uraniyum 1.1.10 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm.js +75 -150
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +75 -150
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/styles.d.ts +2 -5
- package/package.json +1 -1
- package/src/styles.ts +93 -177
package/src/styles.ts
CHANGED
|
@@ -1,242 +1,159 @@
|
|
|
1
1
|
export type CSSValue = string | number | (() => string | number);
|
|
2
2
|
|
|
3
|
-
export interface CSSProperties {
|
|
4
|
-
[key: string]: CSSValue | CSSProperties | undefined;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
3
|
export interface StyleRule {
|
|
8
|
-
[key: string]: CSSValue |
|
|
4
|
+
[key: string]: CSSValue | StyleRule | undefined;
|
|
9
5
|
}
|
|
10
6
|
|
|
11
7
|
export type StylesMap = Record<string, StyleRule>;
|
|
12
8
|
export type ClassNames<T extends StylesMap> = { [K in keyof T]: string };
|
|
13
9
|
|
|
14
|
-
const styleCache = new Map<string, true>();
|
|
15
|
-
const keyframeCache = new Map<string, string>();
|
|
16
10
|
let styleElement: HTMLStyleElement | null = null;
|
|
17
11
|
let styleSheet: CSSStyleSheet | null = null;
|
|
18
12
|
|
|
19
|
-
const ALLOWED_PREFIXES = [
|
|
20
|
-
"root",
|
|
21
|
-
"button",
|
|
22
|
-
"icon",
|
|
23
|
-
"text",
|
|
24
|
-
"container",
|
|
25
|
-
"wrapper",
|
|
26
|
-
"card",
|
|
27
|
-
"header",
|
|
28
|
-
"section",
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
const KEYFRAMES_PREFIX = "@keyframes ";
|
|
32
|
-
|
|
33
13
|
function ensureStyleSheet(): CSSStyleSheet {
|
|
34
14
|
if (!styleSheet) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
document.head.appendChild(styleElement);
|
|
39
|
-
}
|
|
15
|
+
styleElement = document.createElement("style");
|
|
16
|
+
styleElement.id = "styles";
|
|
17
|
+
document.head.appendChild(styleElement);
|
|
40
18
|
styleSheet = styleElement.sheet as CSSStyleSheet;
|
|
41
19
|
}
|
|
42
20
|
return styleSheet;
|
|
43
21
|
}
|
|
44
22
|
|
|
45
|
-
function hashString(str: string): string {
|
|
46
|
-
let hash = 5381;
|
|
47
|
-
for (let i = 0; i < str.length; i++) {
|
|
48
|
-
hash = (hash * 33) ^ str.charCodeAt(i);
|
|
49
|
-
}
|
|
50
|
-
return (hash >>> 0).toString(36);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
23
|
const camelToKebabCache = new Map<string, string>();
|
|
54
24
|
|
|
55
25
|
function camelToKebab(str: string): string {
|
|
56
26
|
const cached = camelToKebabCache.get(str);
|
|
57
27
|
if (cached) return cached;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return result;
|
|
28
|
+
const res = str.replace(/[A-Z]/g, m => "-" + m.toLowerCase());
|
|
29
|
+
camelToKebabCache.set(str, res);
|
|
30
|
+
return res;
|
|
62
31
|
}
|
|
63
32
|
|
|
64
|
-
function
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
for (const key in rule) {
|
|
68
|
-
if (!Object.prototype.hasOwnProperty.call(rule, key)) continue;
|
|
69
|
-
const val = rule[key];
|
|
70
|
-
|
|
71
|
-
if (key.startsWith("@") || typeof val === "object" || val == null) continue;
|
|
72
|
-
|
|
73
|
-
let v: string;
|
|
74
|
-
if (typeof val === "function") v = val.toString();
|
|
75
|
-
else v = String(val);
|
|
76
|
-
|
|
77
|
-
parts.push(`${key}:${v}`);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
parts.sort();
|
|
81
|
-
return hashString(parts.join("|"));
|
|
33
|
+
function resolveValue(v: CSSValue): string | number {
|
|
34
|
+
return typeof v === "function" ? v() : v;
|
|
82
35
|
}
|
|
83
36
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
keyframes: Map<string, string>,
|
|
87
|
-
): string {
|
|
88
|
-
const out: string[] = [];
|
|
37
|
+
const PRECEDENCE_LAYERS = 3;
|
|
38
|
+
let atomicCounter = 0;
|
|
89
39
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (raw == null || typeof raw === "object") continue;
|
|
95
|
-
|
|
96
|
-
let val: string | number =
|
|
97
|
-
typeof raw === "function" ? raw() : (raw as string | number);
|
|
40
|
+
function encode(n: number): string {
|
|
41
|
+
return n.toString(36);
|
|
42
|
+
}
|
|
98
43
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
44
|
+
function makeClassName(layer: number): string {
|
|
45
|
+
// looks like f1phragk
|
|
46
|
+
return `f${layer}${encode(atomicCounter++).padStart(5, "0")}`;
|
|
47
|
+
}
|
|
106
48
|
|
|
107
|
-
|
|
108
|
-
}
|
|
49
|
+
type AtomicSignature = string;
|
|
109
50
|
|
|
110
|
-
|
|
111
|
-
}
|
|
51
|
+
const atomicCache = new Map<AtomicSignature, string[]>();
|
|
112
52
|
|
|
113
|
-
function
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
): string {
|
|
117
|
-
const
|
|
118
|
-
const unique = `${name}-${hash}`;
|
|
53
|
+
function getAtomicClasses(
|
|
54
|
+
selector: string,
|
|
55
|
+
decl: string,
|
|
56
|
+
): string[] {
|
|
57
|
+
const key = `${selector}|${decl}`;
|
|
119
58
|
|
|
120
|
-
const cached =
|
|
59
|
+
const cached = atomicCache.get(key);
|
|
121
60
|
if (cached) return cached;
|
|
122
61
|
|
|
62
|
+
const classes: string[] = [];
|
|
123
63
|
const sheet = ensureStyleSheet();
|
|
124
64
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
65
|
+
for (let layer = 0; layer < PRECEDENCE_LAYERS; layer++) {
|
|
66
|
+
const className = makeClassName(layer);
|
|
67
|
+
classes.push(className);
|
|
68
|
+
|
|
69
|
+
const css =
|
|
70
|
+
selector === "&"
|
|
71
|
+
? `.${className}{${decl}}`
|
|
72
|
+
: selector.replace(/&/g, `.${className}`) + `{${decl}}`;
|
|
131
73
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
keyframeCache.set(unique, unique);
|
|
74
|
+
sheet.insertRule(css, sheet.cssRules.length);
|
|
75
|
+
}
|
|
135
76
|
|
|
136
|
-
|
|
77
|
+
atomicCache.set(key, classes);
|
|
78
|
+
return classes;
|
|
137
79
|
}
|
|
138
80
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const
|
|
81
|
+
type AtomicEntry = {
|
|
82
|
+
classes: string[];
|
|
83
|
+
prop: string;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
function buildAtomicEntries(rule: StyleRule): AtomicEntry[] {
|
|
87
|
+
const entries: AtomicEntry[] = [];
|
|
146
88
|
|
|
147
89
|
for (const key in rule) {
|
|
148
|
-
if (!Object.prototype.hasOwnProperty.call(rule, key)) continue;
|
|
149
90
|
const val = rule[key];
|
|
91
|
+
if (val == null) continue;
|
|
150
92
|
|
|
151
|
-
if (key.startsWith("
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (!val) continue;
|
|
93
|
+
if (key.startsWith(":") && typeof val === "object") {
|
|
94
|
+
for (const prop in val) {
|
|
95
|
+
const v = val[prop];
|
|
96
|
+
if (v == null || typeof v === "object") continue;
|
|
156
97
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
rules.push(`.${className}${key}{${decls}}`);
|
|
98
|
+
const decl = `${camelToKebab(prop)}:${resolveValue(v)}`;
|
|
99
|
+
const classes = getAtomicClasses(`&${key}`, decl);
|
|
100
|
+
entries.push({ classes, prop });
|
|
161
101
|
}
|
|
162
102
|
continue;
|
|
163
103
|
}
|
|
164
104
|
|
|
165
|
-
if (
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
continue;
|
|
105
|
+
if (typeof val !== "object") {
|
|
106
|
+
const decl = `${camelToKebab(key)}:${resolveValue(val)}`;
|
|
107
|
+
const classes = getAtomicClasses("&", decl);
|
|
108
|
+
entries.push({ classes, prop: key });
|
|
171
109
|
}
|
|
110
|
+
}
|
|
172
111
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const decls = stringifyDecls(val ?? {}, keyframes);
|
|
176
|
-
if (decls) {
|
|
177
|
-
rules.push(`${selector}{${decls}}`);
|
|
178
|
-
}
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
112
|
+
return entries;
|
|
113
|
+
}
|
|
181
114
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
115
|
+
export function mergeClasses(
|
|
116
|
+
...inputs: (string | undefined | null | false)[]
|
|
117
|
+
): string {
|
|
118
|
+
const perLayer: string[][] = [];
|
|
187
119
|
|
|
188
|
-
|
|
189
|
-
|
|
120
|
+
for (let i = 0; i < PRECEDENCE_LAYERS; i++) {
|
|
121
|
+
perLayer[i] = [];
|
|
190
122
|
}
|
|
191
123
|
|
|
192
|
-
|
|
124
|
+
inputs.forEach((input, index) => {
|
|
125
|
+
if (typeof input !== "string") return;
|
|
126
|
+
|
|
127
|
+
const layer = Math.min(index, PRECEDENCE_LAYERS - 1);
|
|
128
|
+
|
|
129
|
+
const bucket = perLayer[layer];
|
|
130
|
+
if (!bucket) return;
|
|
131
|
+
|
|
132
|
+
const parts = input.trim().split(/\s+/);
|
|
133
|
+
for (const cls of parts) {
|
|
134
|
+
if (cls) bucket.push(cls);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
return perLayer.flat().join(" ");
|
|
193
139
|
}
|
|
194
140
|
|
|
195
141
|
export function makeStyles<T extends StylesMap>(styles: T) {
|
|
196
142
|
return (): ClassNames<T> => {
|
|
197
|
-
const
|
|
198
|
-
const keyframesMap = new Map<string, string>();
|
|
199
|
-
const sheet = ensureStyleSheet();
|
|
200
|
-
|
|
201
|
-
for (const key in styles) {
|
|
202
|
-
if (!Object.prototype.hasOwnProperty.call(styles, key)) continue;
|
|
203
|
-
if (!key.startsWith(KEYFRAMES_PREFIX)) continue;
|
|
204
|
-
|
|
205
|
-
const name = key.slice(KEYFRAMES_PREFIX.length);
|
|
206
|
-
const frames = styles[key] as unknown as Record<string, any>;
|
|
207
|
-
const unique = registerKeyframes(name, frames);
|
|
208
|
-
keyframesMap.set(name, unique);
|
|
209
|
-
}
|
|
143
|
+
const result = {} as ClassNames<T>;
|
|
210
144
|
|
|
211
145
|
for (const slot in styles) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const rule = styles[slot] as StyleRule;
|
|
216
|
-
const hash = stableHashRule(rule);
|
|
217
|
-
const className = ALLOWED_PREFIXES.includes(slot)
|
|
218
|
-
? `${slot}-${hash}`
|
|
219
|
-
: `css-${hash}`;
|
|
220
|
-
|
|
221
|
-
if (!styleCache.has(className)) {
|
|
222
|
-
const rules = buildRules(className, rule, keyframesMap);
|
|
223
|
-
for (const r of rules) {
|
|
224
|
-
sheet.insertRule(r, sheet.cssRules.length);
|
|
225
|
-
}
|
|
226
|
-
styleCache.set(className, true);
|
|
227
|
-
}
|
|
146
|
+
const rule = (styles[slot] ?? {}) as StyleRule;
|
|
147
|
+
const entries = buildAtomicEntries(rule);
|
|
228
148
|
|
|
229
|
-
(
|
|
149
|
+
const classes = entries.map(e => e.classes[0]).join(" ");
|
|
150
|
+
(result as any)[slot] = classes;
|
|
230
151
|
}
|
|
231
152
|
|
|
232
|
-
return
|
|
153
|
+
return result;
|
|
233
154
|
};
|
|
234
155
|
}
|
|
235
156
|
|
|
236
|
-
export const mergeClasses = (
|
|
237
|
-
...classes: (string | undefined | null | false)[]
|
|
238
|
-
) => classes.filter(Boolean).join(" ");
|
|
239
|
-
|
|
240
157
|
export function mergeStyleSets<T extends StylesMap>(
|
|
241
158
|
...sets: (Partial<T> | undefined)[]
|
|
242
159
|
): ClassNames<T> {
|
|
@@ -245,13 +162,12 @@ export function mergeStyleSets<T extends StylesMap>(
|
|
|
245
162
|
for (const set of sets) {
|
|
246
163
|
if (!set) continue;
|
|
247
164
|
for (const key in set) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
merged[key] = { ...prev, ...cur } as StyleRule;
|
|
165
|
+
merged[key] = {
|
|
166
|
+
...(merged[key] as StyleRule),
|
|
167
|
+
...(set[key] as StyleRule),
|
|
168
|
+
};
|
|
253
169
|
}
|
|
254
170
|
}
|
|
255
171
|
|
|
256
172
|
return makeStyles(merged as T)();
|
|
257
|
-
}
|
|
173
|
+
}
|