-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Expand file tree
/
Copy pathruntime.ts
More file actions
110 lines (98 loc) · 4.13 KB
/
Copy pathruntime.ts
File metadata and controls
110 lines (98 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
* Copyright 2024 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import {StyleString} from './types';
// import {RuntimeStyleFunction, RenderProps} from './types';
// taken from: https://stackoverflow.com/questions/51603250/typescript-3-parameter-list-intersection-type/51604379#51604379
// type ArgTypes<T> = T extends (props: infer V) => any ? NullToObject<V> : never;
// type NullToObject<T> = T extends (null | undefined) ? {} : T;
// type BoxedTupleTypes<T extends any[]> = { [P in keyof T]: [ArgTypes<T[P]>] }[Exclude<keyof T, keyof any[]>];
// type BoxedReturnTypes<T extends any[]> = { [P in keyof T]: [InferReturn<T[P]>] }[Exclude<keyof T, keyof any[]>];
// type UnboxIntersection<T> = T extends { 0: infer U } ? U : never;
// type Arg<X, R> = RuntimeStyleFunction<X, R> | null | undefined;
// type NoInfer<T> = [T, void][T extends any ? 0 : 1];
// type InferReturn<T> = T extends (props: any) => infer R ? NullToObject<R> : never;
// type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
// type InferReturnType<T extends any[]> = UnboxIntersection<UnionToIntersection<BoxedReturnTypes<T>>>;
// Two overloads:
// 1. If a render props type is expected based on the return type, forward that type to all arguments.
// 2. Otherwise, infer the return type based on the arguments.
// export function merge<R extends RenderProps<string> = never, X = {}>(...args: Arg<NoInfer<X>, NoInfer<R>>[]): RuntimeStyleFunction<X, R>;
// export function merge<T extends Arg<any, any>[]>(...args: T): RuntimeStyleFunction<InferReturnType<T>, UnboxIntersection<UnionToIntersection<BoxedTupleTypes<T>>>>;
// export function merge(...args: any[]): RuntimeStyleFunction<any, any> {
// return (props) => {
// return mergeStyles(...args.map(f => typeof f === 'function' ? f(props) : null));
// };
// }
export function mergeStyles(...styles: (StyleString | null | undefined)[]): StyleString {
let definedStyles = styles.filter(Boolean) as StyleString[];
if (definedStyles.length === 1) {
let first = definedStyles[0];
if (typeof first !== 'string') {
// static macro has a toString method so that we generate the style macro map for the entry
// it's automatically called in other places, but for our merging, we have to call it ourselves
return (first as StyleString).toString() as StyleString;
}
return first;
}
let map = new Map<string, string>();
for (let style of definedStyles) {
// must call toString here for the static macro
for (let [k, v] of parse(style.toString())) {
map.set(k, v);
}
}
let res = '';
for (let value of map.values()) {
res += value;
}
return res as StyleString;
}
function parse(s: string) {
let properties = new Map<string, string>();
let i = 0;
while (i < s.length) {
while (i < s.length && s[i] === ' ') {
i++;
}
let start = i;
readValue(); // property index
// read conditions (up to the last segment)
let condition = i;
while (i < s.length && s[i] !== ' ') {
readValue();
}
let property = s.slice(start, condition);
properties.set(property, (properties.get(property) || '') + ' ' + s.slice(start, i));
}
function readValue() {
if (s[i] === '-') {
// the beginning and end of arbitrary values are marked with -
while (i < s.length && s[i] !== ' ') {
i++;
if (s[i] === '-') {
i++;
break;
}
}
} else {
while (i < s.length) {
if (s[i] === '_') {
i++;
} else {
i++;
break;
}
}
}
}
return properties;
}