elit 3.5.6 → 3.5.7
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/Cargo.toml +1 -1
- package/README.md +1 -1
- package/desktop/build.rs +83 -0
- package/desktop/icon.rs +106 -0
- package/desktop/lib.rs +2 -0
- package/desktop/main.rs +235 -0
- package/desktop/native_main.rs +128 -0
- package/desktop/native_renderer/action_widgets.rs +184 -0
- package/desktop/native_renderer/app_models.rs +171 -0
- package/desktop/native_renderer/app_runtime.rs +140 -0
- package/desktop/native_renderer/container_rendering.rs +610 -0
- package/desktop/native_renderer/content_widgets.rs +634 -0
- package/desktop/native_renderer/css_models.rs +371 -0
- package/desktop/native_renderer/embedded_surfaces.rs +414 -0
- package/desktop/native_renderer/form_controls.rs +516 -0
- package/desktop/native_renderer/interaction_dispatch.rs +89 -0
- package/desktop/native_renderer/runtime_support.rs +135 -0
- package/desktop/native_renderer/utilities.rs +495 -0
- package/desktop/native_renderer/vector_drawing.rs +491 -0
- package/desktop/native_renderer.rs +4122 -0
- package/desktop/runtime/external.rs +422 -0
- package/desktop/runtime/mod.rs +67 -0
- package/desktop/runtime/quickjs.rs +106 -0
- package/desktop/window.rs +383 -0
- package/package.json +6 -3
- package/dist/build.d.mts +0 -20
- package/dist/chokidar.d.mts +0 -134
- package/dist/cli.d.mts +0 -81
- package/dist/config.d.mts +0 -254
- package/dist/coverage.d.mts +0 -85
- package/dist/database.d.mts +0 -52
- package/dist/desktop.d.mts +0 -68
- package/dist/dom.d.mts +0 -87
- package/dist/el.d.mts +0 -208
- package/dist/fs.d.mts +0 -255
- package/dist/hmr.d.mts +0 -38
- package/dist/http.d.mts +0 -169
- package/dist/https.d.mts +0 -108
- package/dist/index.d.mts +0 -13
- package/dist/mime-types.d.mts +0 -48
- package/dist/native.d.mts +0 -136
- package/dist/path.d.mts +0 -163
- package/dist/router.d.mts +0 -49
- package/dist/runtime.d.mts +0 -97
- package/dist/server-D0Dp4R5z.d.mts +0 -449
- package/dist/server.d.mts +0 -7
- package/dist/state.d.mts +0 -117
- package/dist/style.d.mts +0 -232
- package/dist/test-reporter.d.mts +0 -77
- package/dist/test-runtime.d.mts +0 -122
- package/dist/test.d.mts +0 -39
- package/dist/types.d.mts +0 -586
- package/dist/universal.d.mts +0 -21
- package/dist/ws.d.mts +0 -200
- package/dist/wss.d.mts +0 -108
- package/src/build.ts +0 -362
- package/src/chokidar.ts +0 -427
- package/src/cli.ts +0 -1162
- package/src/config.ts +0 -509
- package/src/coverage.ts +0 -1479
- package/src/database.ts +0 -1410
- package/src/desktop-auto-render.ts +0 -317
- package/src/desktop-cli.ts +0 -1533
- package/src/desktop.ts +0 -99
- package/src/dev-build.ts +0 -340
- package/src/dom.ts +0 -901
- package/src/el.ts +0 -183
- package/src/fs.ts +0 -609
- package/src/hmr.ts +0 -149
- package/src/http.ts +0 -856
- package/src/https.ts +0 -411
- package/src/index.ts +0 -16
- package/src/mime-types.ts +0 -222
- package/src/mobile-cli.ts +0 -2313
- package/src/native-background.ts +0 -444
- package/src/native-border.ts +0 -343
- package/src/native-canvas.ts +0 -260
- package/src/native-cli.ts +0 -414
- package/src/native-color.ts +0 -904
- package/src/native-estimation.ts +0 -194
- package/src/native-grid.ts +0 -590
- package/src/native-interaction.ts +0 -1289
- package/src/native-layout.ts +0 -568
- package/src/native-link.ts +0 -76
- package/src/native-render-support.ts +0 -361
- package/src/native-spacing.ts +0 -231
- package/src/native-state.ts +0 -318
- package/src/native-strings.ts +0 -46
- package/src/native-transform.ts +0 -120
- package/src/native-types.ts +0 -439
- package/src/native-typography.ts +0 -254
- package/src/native-units.ts +0 -441
- package/src/native-vector.ts +0 -910
- package/src/native.ts +0 -5606
- package/src/path.ts +0 -493
- package/src/pm-cli.ts +0 -2498
- package/src/preview-build.ts +0 -294
- package/src/render-context.ts +0 -138
- package/src/router.ts +0 -260
- package/src/runtime.ts +0 -97
- package/src/server.ts +0 -2294
- package/src/state.ts +0 -556
- package/src/style.ts +0 -1790
- package/src/test-globals.d.ts +0 -184
- package/src/test-reporter.ts +0 -609
- package/src/test-runtime.ts +0 -1359
- package/src/test.ts +0 -368
- package/src/types.ts +0 -381
- package/src/universal.ts +0 -81
- package/src/wapk-cli.ts +0 -3213
- package/src/workspace-package.ts +0 -102
- package/src/ws.ts +0 -648
- package/src/wss.ts +0 -241
package/src/style.ts
DELETED
|
@@ -1,1790 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Elit - CreateStyle CSS Generation System
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export interface CSSVariable {
|
|
6
|
-
name: string;
|
|
7
|
-
value: string;
|
|
8
|
-
toString(): string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface CSSRule {
|
|
12
|
-
selector: string;
|
|
13
|
-
styles: Record<string, string | number>;
|
|
14
|
-
nested?: CSSRule[];
|
|
15
|
-
type: 'tag' | 'class' | 'id' | 'pseudo-class' | 'pseudo-element' | 'name' | 'custom' | 'media' | 'attribute';
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface MediaRule {
|
|
19
|
-
type: string;
|
|
20
|
-
condition: string;
|
|
21
|
-
rules: CSSRule[];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface KeyframeStep {
|
|
25
|
-
step: string | number;
|
|
26
|
-
styles: Record<string, string | number>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface Keyframes {
|
|
30
|
-
name: string;
|
|
31
|
-
steps: KeyframeStep[];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface FontFace {
|
|
35
|
-
fontFamily: string;
|
|
36
|
-
src: string;
|
|
37
|
-
fontWeight?: string | number;
|
|
38
|
-
fontStyle?: string;
|
|
39
|
-
fontDisplay?: string;
|
|
40
|
-
unicodeRange?: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface ContainerRule {
|
|
44
|
-
name?: string;
|
|
45
|
-
condition: string;
|
|
46
|
-
rules: CSSRule[];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface SupportsRule {
|
|
50
|
-
condition: string;
|
|
51
|
-
rules: CSSRule[];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface LayerRule {
|
|
55
|
-
name: string;
|
|
56
|
-
rules: CSSRule[];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export interface StyleSelectorTarget {
|
|
60
|
-
tagName?: string;
|
|
61
|
-
classNames?: string[];
|
|
62
|
-
attributes?: Record<string, string | number | boolean>;
|
|
63
|
-
pseudoStates?: string[];
|
|
64
|
-
previousSiblings?: StyleSelectorTarget[];
|
|
65
|
-
nextSiblings?: StyleSelectorTarget[];
|
|
66
|
-
children?: StyleSelectorTarget[];
|
|
67
|
-
childIndex?: number;
|
|
68
|
-
siblingCount?: number;
|
|
69
|
-
sameTypeIndex?: number;
|
|
70
|
-
sameTypeCount?: number;
|
|
71
|
-
containerNames?: string[];
|
|
72
|
-
containerWidth?: number;
|
|
73
|
-
isContainer?: boolean;
|
|
74
|
-
isScopeReference?: boolean;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface NativeStyleResolveOptions {
|
|
78
|
-
viewportWidth?: number;
|
|
79
|
-
viewportHeight?: number;
|
|
80
|
-
colorScheme?: 'light' | 'dark';
|
|
81
|
-
reducedMotion?: boolean;
|
|
82
|
-
mediaType?: 'screen' | 'print' | 'all';
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
type ParsedSelectorCombinator = 'descendant' | 'child' | 'adjacent-sibling' | 'general-sibling';
|
|
86
|
-
|
|
87
|
-
interface ParsedAttributeSelector {
|
|
88
|
-
name: string;
|
|
89
|
-
operator?: '=' | '~=' | '^=' | '$=' | '*=';
|
|
90
|
-
value?: string;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
interface ParsedSimpleSelector {
|
|
94
|
-
tagName?: string;
|
|
95
|
-
idName?: string;
|
|
96
|
-
classNames: string[];
|
|
97
|
-
attributes: ParsedAttributeSelector[];
|
|
98
|
-
pseudoClasses: string[];
|
|
99
|
-
combinator?: ParsedSelectorCombinator;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
interface ParsedSelectorCursor {
|
|
103
|
-
target: StyleSelectorTarget;
|
|
104
|
-
ancestorIndex: number;
|
|
105
|
-
previousSiblings: StyleSelectorTarget[];
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
interface CreateStyleStore {
|
|
109
|
-
variables: CSSVariable[];
|
|
110
|
-
rules: CSSRule[];
|
|
111
|
-
mediaRules: MediaRule[];
|
|
112
|
-
keyframes: Keyframes[];
|
|
113
|
-
fontFaces: FontFace[];
|
|
114
|
-
imports: string[];
|
|
115
|
-
containerRules: ContainerRule[];
|
|
116
|
-
supportsRules: SupportsRule[];
|
|
117
|
-
layerRules: LayerRule[];
|
|
118
|
-
layerOrder: string[];
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const ELIT_SHARED_STYLE_STORE_KEY = '__elitSharedStyleStore__';
|
|
122
|
-
|
|
123
|
-
function createStyleStore(): CreateStyleStore {
|
|
124
|
-
return {
|
|
125
|
-
variables: [],
|
|
126
|
-
rules: [],
|
|
127
|
-
mediaRules: [],
|
|
128
|
-
keyframes: [],
|
|
129
|
-
fontFaces: [],
|
|
130
|
-
imports: [],
|
|
131
|
-
containerRules: [],
|
|
132
|
-
supportsRules: [],
|
|
133
|
-
layerRules: [],
|
|
134
|
-
layerOrder: [],
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function getSharedStyleStore(): CreateStyleStore {
|
|
139
|
-
const globalScope = globalThis as typeof globalThis & { [ELIT_SHARED_STYLE_STORE_KEY]?: CreateStyleStore };
|
|
140
|
-
if (!globalScope[ELIT_SHARED_STYLE_STORE_KEY]) {
|
|
141
|
-
globalScope[ELIT_SHARED_STYLE_STORE_KEY] = createStyleStore();
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return globalScope[ELIT_SHARED_STYLE_STORE_KEY]!;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export class CreateStyle {
|
|
148
|
-
private variables: CSSVariable[] = [];
|
|
149
|
-
private rules: CSSRule[] = [];
|
|
150
|
-
private mediaRules: MediaRule[] = [];
|
|
151
|
-
private keyframes: Keyframes[] = [];
|
|
152
|
-
private fontFaces: FontFace[] = [];
|
|
153
|
-
private imports: string[] = [];
|
|
154
|
-
private containerRules: ContainerRule[] = [];
|
|
155
|
-
private supportsRules: SupportsRule[] = [];
|
|
156
|
-
private layerRules: LayerRule[] = [];
|
|
157
|
-
private _layerOrder: string[] = [];
|
|
158
|
-
private parsedSelectorChainCache = new Map<string, ParsedSimpleSelector[][]>();
|
|
159
|
-
private nativeTargetNormalizationCache?: WeakMap<StyleSelectorTarget, StyleSelectorTarget>;
|
|
160
|
-
|
|
161
|
-
constructor(store?: CreateStyleStore) {
|
|
162
|
-
if (!store) {
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
this.variables = store.variables;
|
|
167
|
-
this.rules = store.rules;
|
|
168
|
-
this.mediaRules = store.mediaRules;
|
|
169
|
-
this.keyframes = store.keyframes;
|
|
170
|
-
this.fontFaces = store.fontFaces;
|
|
171
|
-
this.imports = store.imports;
|
|
172
|
-
this.containerRules = store.containerRules;
|
|
173
|
-
this.supportsRules = store.supportsRules;
|
|
174
|
-
this.layerRules = store.layerRules;
|
|
175
|
-
this._layerOrder = store.layerOrder;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// CSS Variables
|
|
179
|
-
addVar(name: string, value: string): CSSVariable {
|
|
180
|
-
const cssVar: CSSVariable = {
|
|
181
|
-
name: name.startsWith('--') ? name : `--${name}`,
|
|
182
|
-
value,
|
|
183
|
-
toString() { return `var(${this.name})`; }
|
|
184
|
-
};
|
|
185
|
-
this.variables.push(cssVar);
|
|
186
|
-
return cssVar;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
var(variable: CSSVariable | string, fallback?: string): string {
|
|
190
|
-
const varName = typeof variable === 'string'
|
|
191
|
-
? (variable.startsWith('--') ? variable : `--${variable}`)
|
|
192
|
-
: variable.name;
|
|
193
|
-
return fallback ? `var(${varName}, ${fallback})` : `var(${varName})`;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Basic Selectors
|
|
197
|
-
addTag(tag: string, styles: Record<string, string | number>): CSSRule {
|
|
198
|
-
const rule: CSSRule = { selector: tag, styles, type: 'tag' };
|
|
199
|
-
this.rules.push(rule);
|
|
200
|
-
return rule;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
addClass(name: string, styles: Record<string, string | number>): CSSRule {
|
|
204
|
-
const selector = name.startsWith('.') ? name : `.${name}`;
|
|
205
|
-
const rule: CSSRule = { selector, styles, type: 'class' };
|
|
206
|
-
this.rules.push(rule);
|
|
207
|
-
return rule;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
addId(name: string, styles: Record<string, string | number>): CSSRule {
|
|
211
|
-
const selector = name.startsWith('#') ? name : `#${name}`;
|
|
212
|
-
const rule: CSSRule = { selector, styles, type: 'id' };
|
|
213
|
-
this.rules.push(rule);
|
|
214
|
-
return rule;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Pseudo Selectors
|
|
218
|
-
addPseudoClass(pseudo: string, styles: Record<string, string | number>, baseSelector?: string): CSSRule {
|
|
219
|
-
const pseudoClass = pseudo.startsWith(':') ? pseudo : `:${pseudo}`;
|
|
220
|
-
const selector = baseSelector ? `${baseSelector}${pseudoClass}` : pseudoClass;
|
|
221
|
-
const rule: CSSRule = { selector, styles, type: 'pseudo-class' };
|
|
222
|
-
this.rules.push(rule);
|
|
223
|
-
return rule;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
addPseudoElement(pseudo: string, styles: Record<string, string | number>, baseSelector?: string): CSSRule {
|
|
227
|
-
const pseudoElement = pseudo.startsWith('::') ? pseudo : `::${pseudo}`;
|
|
228
|
-
const selector = baseSelector ? `${baseSelector}${pseudoElement}` : pseudoElement;
|
|
229
|
-
const rule: CSSRule = { selector, styles, type: 'pseudo-element' };
|
|
230
|
-
this.rules.push(rule);
|
|
231
|
-
return rule;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Attribute Selectors
|
|
235
|
-
addAttribute(attr: string, styles: Record<string, string | number>, baseSelector?: string): CSSRule {
|
|
236
|
-
const attrSelector = attr.startsWith('[') ? attr : `[${attr}]`;
|
|
237
|
-
const selector = baseSelector ? `${baseSelector}${attrSelector}` : attrSelector;
|
|
238
|
-
const rule: CSSRule = { selector, styles, type: 'attribute' };
|
|
239
|
-
this.rules.push(rule);
|
|
240
|
-
return rule;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
attrEquals(attr: string, value: string, styles: Record<string, string | number>, baseSelector?: string): CSSRule {
|
|
244
|
-
return this.addAttribute(`${attr}="${value}"`, styles, baseSelector);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
attrContainsWord(attr: string, value: string, styles: Record<string, string | number>, baseSelector?: string): CSSRule {
|
|
248
|
-
return this.addAttribute(`${attr}~="${value}"`, styles, baseSelector);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
attrStartsWith(attr: string, value: string, styles: Record<string, string | number>, baseSelector?: string): CSSRule {
|
|
252
|
-
return this.addAttribute(`${attr}^="${value}"`, styles, baseSelector);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
attrEndsWith(attr: string, value: string, styles: Record<string, string | number>, baseSelector?: string): CSSRule {
|
|
256
|
-
return this.addAttribute(`${attr}$="${value}"`, styles, baseSelector);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
attrContains(attr: string, value: string, styles: Record<string, string | number>, baseSelector?: string): CSSRule {
|
|
260
|
-
return this.addAttribute(`${attr}*="${value}"`, styles, baseSelector);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Combinator Selectors
|
|
264
|
-
descendant(ancestor: string, descendant: string, styles: Record<string, string | number>): CSSRule {
|
|
265
|
-
return this.createAndAddRule(`${ancestor} ${descendant}`, styles);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
child(parent: string, childSel: string, styles: Record<string, string | number>): CSSRule {
|
|
269
|
-
return this.createAndAddRule(`${parent} > ${childSel}`, styles);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
adjacentSibling(element: string, sibling: string, styles: Record<string, string | number>): CSSRule {
|
|
273
|
-
return this.createAndAddRule(`${element} + ${sibling}`, styles);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
generalSibling(element: string, sibling: string, styles: Record<string, string | number>): CSSRule {
|
|
277
|
-
return this.createAndAddRule(`${element} ~ ${sibling}`, styles);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
multiple(selectors: string[], styles: Record<string, string | number>): CSSRule {
|
|
281
|
-
return this.createAndAddRule(selectors.join(', '), styles);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Nesting (BEM-style)
|
|
285
|
-
addName(name: string, styles: Record<string, string | number>): CSSRule {
|
|
286
|
-
const selector = name.startsWith('--') ? `&${name}` : `&--${name}`;
|
|
287
|
-
const rule: CSSRule = { selector, styles, type: 'name' };
|
|
288
|
-
return rule;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
nesting(parentRule: CSSRule, ...childRules: CSSRule[]): CSSRule {
|
|
292
|
-
parentRule.nested = childRules;
|
|
293
|
-
return parentRule;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// @keyframes - Animations
|
|
297
|
-
keyframe(name: string, steps: Record<string | number, Record<string, string | number>>): Keyframes {
|
|
298
|
-
const keyframeSteps: KeyframeStep[] = Object.entries(steps).map(([step, styles]) => ({
|
|
299
|
-
step: step === 'from' ? 'from' : step === 'to' ? 'to' : `${step}%`,
|
|
300
|
-
styles
|
|
301
|
-
}));
|
|
302
|
-
const kf: Keyframes = { name, steps: keyframeSteps };
|
|
303
|
-
this.keyframes.push(kf);
|
|
304
|
-
return kf;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
keyframeFromTo(name: string, from: Record<string, string | number>, to: Record<string, string | number>): Keyframes {
|
|
308
|
-
return this.keyframe(name, { from, to });
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// @font-face - Custom Fonts
|
|
312
|
-
fontFace(options: FontFace): FontFace {
|
|
313
|
-
this.fontFaces.push(options);
|
|
314
|
-
return options;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// @import - Import Stylesheets
|
|
318
|
-
import(url: string, mediaQuery?: string): string {
|
|
319
|
-
const importRule = mediaQuery ? `@import url("${url}") ${mediaQuery};` : `@import url("${url}");`;
|
|
320
|
-
this.imports.push(importRule);
|
|
321
|
-
return importRule;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// @media - Media Queries
|
|
325
|
-
media(type: string, condition: string, rules: Record<string, Record<string, string | number>>): MediaRule {
|
|
326
|
-
const mediaRule: MediaRule = { type, condition, rules: this.rulesToCSSRules(rules) };
|
|
327
|
-
this.mediaRules.push(mediaRule);
|
|
328
|
-
return mediaRule;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
mediaScreen(condition: string, rules: Record<string, Record<string, string | number>>): MediaRule {
|
|
332
|
-
return this.media('screen', condition, rules);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
mediaPrint(rules: Record<string, Record<string, string | number>>): MediaRule {
|
|
336
|
-
return this.media('print', '', rules);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
mediaMinWidth(minWidth: string, rules: Record<string, Record<string, string | number>>): MediaRule {
|
|
340
|
-
return this.media('screen', `min-width: ${minWidth}`, rules);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
mediaMaxWidth(maxWidth: string, rules: Record<string, Record<string, string | number>>): MediaRule {
|
|
344
|
-
return this.media('screen', `max-width: ${maxWidth}`, rules);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
mediaDark(rules: Record<string, Record<string, string | number>>): MediaRule {
|
|
348
|
-
const mediaRule: MediaRule = { type: '', condition: 'prefers-color-scheme: dark', rules: this.rulesToCSSRules(rules) };
|
|
349
|
-
this.mediaRules.push(mediaRule);
|
|
350
|
-
return mediaRule;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
mediaLight(rules: Record<string, Record<string, string | number>>): MediaRule {
|
|
354
|
-
const mediaRule: MediaRule = { type: '', condition: 'prefers-color-scheme: light', rules: this.rulesToCSSRules(rules) };
|
|
355
|
-
this.mediaRules.push(mediaRule);
|
|
356
|
-
return mediaRule;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
mediaReducedMotion(rules: Record<string, Record<string, string | number>>): MediaRule {
|
|
360
|
-
const mediaRule: MediaRule = { type: '', condition: 'prefers-reduced-motion: reduce', rules: this.rulesToCSSRules(rules) };
|
|
361
|
-
this.mediaRules.push(mediaRule);
|
|
362
|
-
return mediaRule;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// @container - Container Queries
|
|
366
|
-
container(condition: string, rules: Record<string, Record<string, string | number>>, name?: string): ContainerRule {
|
|
367
|
-
const containerRule: ContainerRule = { name, condition, rules: this.rulesToCSSRules(rules) };
|
|
368
|
-
this.containerRules.push(containerRule);
|
|
369
|
-
return containerRule;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
addContainer(name: string, styles: Record<string, string | number>): CSSRule {
|
|
373
|
-
const containerStyles = { ...styles, containerName: name };
|
|
374
|
-
return this.addClass(name, containerStyles);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// @supports - Feature Queries
|
|
378
|
-
supports(condition: string, rules: Record<string, Record<string, string | number>>): SupportsRule {
|
|
379
|
-
const supportsRule: SupportsRule = { condition, rules: this.rulesToCSSRules(rules) };
|
|
380
|
-
this.supportsRules.push(supportsRule);
|
|
381
|
-
return supportsRule;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// @layer - Cascade Layers
|
|
385
|
-
layerOrder(...layers: string[]): void {
|
|
386
|
-
this._layerOrder = layers;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
layer(name: string, rules: Record<string, Record<string, string | number>>): LayerRule {
|
|
390
|
-
const layerRule: LayerRule = { name, rules: this.rulesToCSSRules(rules) };
|
|
391
|
-
this.layerRules.push(layerRule);
|
|
392
|
-
return layerRule;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// Custom Rules
|
|
396
|
-
add(rules: Record<string, Record<string, string | number>>): CSSRule[] {
|
|
397
|
-
const cssRules: CSSRule[] = Object.entries(rules).map(([selector, styles]) => {
|
|
398
|
-
const rule: CSSRule = { selector, styles, type: 'custom' };
|
|
399
|
-
this.rules.push(rule);
|
|
400
|
-
return rule;
|
|
401
|
-
});
|
|
402
|
-
return cssRules;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
important(value: string | number): string {
|
|
406
|
-
return `${value} !important`;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
getVariables(): Record<string, string> {
|
|
410
|
-
return Object.fromEntries(this.variables.map((variable) => [variable.name, variable.value]));
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
private resolveVariableReferences(value: string, variables: Record<string, string>): string {
|
|
414
|
-
let resolved = value;
|
|
415
|
-
|
|
416
|
-
for (let index = 0; index < 8; index++) {
|
|
417
|
-
let replaced = false;
|
|
418
|
-
resolved = resolved.replace(/var\(\s*(--[\w-]+)\s*(?:,\s*([^\)]+))?\)/g, (match, name: string, fallback?: string) => {
|
|
419
|
-
const variableValue = variables[name];
|
|
420
|
-
if (variableValue !== undefined) {
|
|
421
|
-
replaced = true;
|
|
422
|
-
return variableValue;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
if (fallback !== undefined) {
|
|
426
|
-
replaced = true;
|
|
427
|
-
return fallback.trim();
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
return match;
|
|
431
|
-
});
|
|
432
|
-
|
|
433
|
-
if (!replaced) {
|
|
434
|
-
break;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
return resolved.replace(/\s*!important\s*$/i, '').trim();
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
private normalizeTargetIdentity(target: StyleSelectorTarget): StyleSelectorTarget {
|
|
442
|
-
return {
|
|
443
|
-
tagName: typeof target.tagName === 'string' && target.tagName.trim()
|
|
444
|
-
? target.tagName.trim().toLowerCase()
|
|
445
|
-
: undefined,
|
|
446
|
-
classNames: Array.isArray(target.classNames)
|
|
447
|
-
? target.classNames.map((className) => className.trim()).filter(Boolean)
|
|
448
|
-
: [],
|
|
449
|
-
attributes: target.attributes
|
|
450
|
-
? Object.fromEntries(
|
|
451
|
-
Object.entries(target.attributes)
|
|
452
|
-
.filter(([, value]) => value !== undefined && value !== null && value !== false)
|
|
453
|
-
.map(([name, value]) => [name.toLowerCase(), String(value)])
|
|
454
|
-
)
|
|
455
|
-
: {},
|
|
456
|
-
pseudoStates: Array.isArray(target.pseudoStates)
|
|
457
|
-
? [...new Set(target.pseudoStates.map((pseudoState) => pseudoState.trim().toLowerCase()).filter(Boolean))]
|
|
458
|
-
: [],
|
|
459
|
-
childIndex: typeof target.childIndex === 'number' && Number.isFinite(target.childIndex)
|
|
460
|
-
? target.childIndex
|
|
461
|
-
: undefined,
|
|
462
|
-
siblingCount: typeof target.siblingCount === 'number' && Number.isFinite(target.siblingCount)
|
|
463
|
-
? target.siblingCount
|
|
464
|
-
: undefined,
|
|
465
|
-
sameTypeIndex: typeof target.sameTypeIndex === 'number' && Number.isFinite(target.sameTypeIndex)
|
|
466
|
-
? target.sameTypeIndex
|
|
467
|
-
: undefined,
|
|
468
|
-
sameTypeCount: typeof target.sameTypeCount === 'number' && Number.isFinite(target.sameTypeCount)
|
|
469
|
-
? target.sameTypeCount
|
|
470
|
-
: undefined,
|
|
471
|
-
containerNames: Array.isArray(target.containerNames)
|
|
472
|
-
? [...new Set(target.containerNames.map((containerName) => containerName.trim().toLowerCase()).filter(Boolean))]
|
|
473
|
-
: [],
|
|
474
|
-
containerWidth: typeof target.containerWidth === 'number' && Number.isFinite(target.containerWidth)
|
|
475
|
-
? target.containerWidth
|
|
476
|
-
: undefined,
|
|
477
|
-
isContainer: target.isContainer === true,
|
|
478
|
-
isScopeReference: target.isScopeReference === true,
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
private normalizeTarget(target: StyleSelectorTarget): StyleSelectorTarget {
|
|
483
|
-
const cached = this.nativeTargetNormalizationCache?.get(target);
|
|
484
|
-
if (cached) {
|
|
485
|
-
return cached;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
const normalized: StyleSelectorTarget = {
|
|
489
|
-
...this.normalizeTargetIdentity(target),
|
|
490
|
-
previousSiblings: [],
|
|
491
|
-
nextSiblings: [],
|
|
492
|
-
children: [],
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
this.nativeTargetNormalizationCache?.set(target, normalized);
|
|
496
|
-
|
|
497
|
-
normalized.previousSiblings = Array.isArray(target.previousSiblings)
|
|
498
|
-
? target.previousSiblings.map((sibling) => this.normalizeTarget(sibling))
|
|
499
|
-
: [];
|
|
500
|
-
normalized.nextSiblings = Array.isArray(target.nextSiblings)
|
|
501
|
-
? target.nextSiblings.map((sibling) => this.normalizeTarget(sibling))
|
|
502
|
-
: [];
|
|
503
|
-
normalized.children = Array.isArray(target.children)
|
|
504
|
-
? target.children.map((child) => this.normalizeTarget(child))
|
|
505
|
-
: [];
|
|
506
|
-
|
|
507
|
-
return normalized;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
private withNativeTargetNormalizationCache<T>(callback: () => T): T {
|
|
511
|
-
const previousCache = this.nativeTargetNormalizationCache;
|
|
512
|
-
this.nativeTargetNormalizationCache = new WeakMap();
|
|
513
|
-
|
|
514
|
-
try {
|
|
515
|
-
return callback();
|
|
516
|
-
} finally {
|
|
517
|
-
this.nativeTargetNormalizationCache = previousCache;
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
private splitConditionalClauses(value: string, operator: 'and' | 'or'): string[] {
|
|
522
|
-
const clauses: string[] = [];
|
|
523
|
-
let token = '';
|
|
524
|
-
let depth = 0;
|
|
525
|
-
|
|
526
|
-
for (let index = 0; index < value.length; index++) {
|
|
527
|
-
const char = value[index];
|
|
528
|
-
if (char === '(') {
|
|
529
|
-
depth += 1;
|
|
530
|
-
} else if (char === ')' && depth > 0) {
|
|
531
|
-
depth -= 1;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
const operatorToken = ` ${operator} `;
|
|
535
|
-
if (depth === 0 && value.slice(index, index + operatorToken.length).toLowerCase() === operatorToken) {
|
|
536
|
-
const trimmed = token.trim();
|
|
537
|
-
if (trimmed) {
|
|
538
|
-
clauses.push(trimmed);
|
|
539
|
-
}
|
|
540
|
-
token = '';
|
|
541
|
-
index += operatorToken.length - 1;
|
|
542
|
-
continue;
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
token += char;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
const trailing = token.trim();
|
|
549
|
-
if (trailing) {
|
|
550
|
-
clauses.push(trailing);
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
return clauses;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
private splitSelectorList(value: string): string[] {
|
|
557
|
-
const selectors: string[] = [];
|
|
558
|
-
let token = '';
|
|
559
|
-
let attributeDepth = 0;
|
|
560
|
-
let parenthesisDepth = 0;
|
|
561
|
-
let quoted: '"' | '\'' | undefined;
|
|
562
|
-
|
|
563
|
-
for (let index = 0; index < value.length; index++) {
|
|
564
|
-
const char = value[index];
|
|
565
|
-
|
|
566
|
-
if (quoted) {
|
|
567
|
-
token += char;
|
|
568
|
-
if (char === quoted && value[index - 1] !== '\\') {
|
|
569
|
-
quoted = undefined;
|
|
570
|
-
}
|
|
571
|
-
continue;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
if (char === '"' || char === '\'') {
|
|
575
|
-
quoted = char;
|
|
576
|
-
token += char;
|
|
577
|
-
continue;
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
if (char === '[') {
|
|
581
|
-
attributeDepth += 1;
|
|
582
|
-
token += char;
|
|
583
|
-
continue;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
if (char === ']' && attributeDepth > 0) {
|
|
587
|
-
attributeDepth -= 1;
|
|
588
|
-
token += char;
|
|
589
|
-
continue;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
if (attributeDepth === 0 && char === '(') {
|
|
593
|
-
parenthesisDepth += 1;
|
|
594
|
-
token += char;
|
|
595
|
-
continue;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
if (attributeDepth === 0 && char === ')' && parenthesisDepth > 0) {
|
|
599
|
-
parenthesisDepth -= 1;
|
|
600
|
-
token += char;
|
|
601
|
-
continue;
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
if (attributeDepth === 0 && parenthesisDepth === 0 && char === ',') {
|
|
605
|
-
const trimmed = token.trim();
|
|
606
|
-
if (trimmed) {
|
|
607
|
-
selectors.push(trimmed);
|
|
608
|
-
}
|
|
609
|
-
token = '';
|
|
610
|
-
continue;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
token += char;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
const trailing = token.trim();
|
|
617
|
-
if (trailing) {
|
|
618
|
-
selectors.push(trailing);
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
return selectors;
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
private parsePseudoSelectorToken(token: string, startIndex: number): { value: string; nextIndex: number } | undefined {
|
|
625
|
-
if (token[startIndex] !== ':' || token[startIndex + 1] === ':') {
|
|
626
|
-
return undefined;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
let cursor = startIndex + 1;
|
|
630
|
-
const nameMatch = token.slice(cursor).match(/^([_a-zA-Z][-_a-zA-Z0-9]*)/);
|
|
631
|
-
if (!nameMatch) {
|
|
632
|
-
return undefined;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
const pseudoName = nameMatch[1].toLowerCase();
|
|
636
|
-
cursor += nameMatch[0].length;
|
|
637
|
-
|
|
638
|
-
if (token[cursor] !== '(') {
|
|
639
|
-
return { value: pseudoName, nextIndex: cursor };
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
const argumentStart = cursor + 1;
|
|
643
|
-
let attributeDepth = 0;
|
|
644
|
-
let parenthesisDepth = 1;
|
|
645
|
-
let quoted: '"' | '\'' | undefined;
|
|
646
|
-
cursor += 1;
|
|
647
|
-
|
|
648
|
-
while (cursor < token.length) {
|
|
649
|
-
const char = token[cursor];
|
|
650
|
-
|
|
651
|
-
if (quoted) {
|
|
652
|
-
if (char === quoted && token[cursor - 1] !== '\\') {
|
|
653
|
-
quoted = undefined;
|
|
654
|
-
}
|
|
655
|
-
cursor += 1;
|
|
656
|
-
continue;
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
if (char === '"' || char === '\'') {
|
|
660
|
-
quoted = char;
|
|
661
|
-
cursor += 1;
|
|
662
|
-
continue;
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
if (char === '[') {
|
|
666
|
-
attributeDepth += 1;
|
|
667
|
-
cursor += 1;
|
|
668
|
-
continue;
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
if (char === ']' && attributeDepth > 0) {
|
|
672
|
-
attributeDepth -= 1;
|
|
673
|
-
cursor += 1;
|
|
674
|
-
continue;
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
if (attributeDepth === 0 && char === '(') {
|
|
678
|
-
parenthesisDepth += 1;
|
|
679
|
-
cursor += 1;
|
|
680
|
-
continue;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
if (attributeDepth === 0 && char === ')') {
|
|
684
|
-
parenthesisDepth -= 1;
|
|
685
|
-
if (parenthesisDepth === 0) {
|
|
686
|
-
const pseudoArgument = token.slice(argumentStart, cursor).trim();
|
|
687
|
-
return {
|
|
688
|
-
value: pseudoArgument.length > 0
|
|
689
|
-
? `${pseudoName}(${pseudoArgument})`
|
|
690
|
-
: `${pseudoName}()`,
|
|
691
|
-
nextIndex: cursor + 1,
|
|
692
|
-
};
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
cursor += 1;
|
|
696
|
-
continue;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
cursor += 1;
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
return undefined;
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
private matchesSupportsDeclaration(property: string, value: string): boolean {
|
|
706
|
-
const normalizedProperty = property.trim().toLowerCase();
|
|
707
|
-
const normalizedValue = value.trim().toLowerCase();
|
|
708
|
-
const supportedProperties = new Set([
|
|
709
|
-
'align-items',
|
|
710
|
-
'background',
|
|
711
|
-
'background-color',
|
|
712
|
-
'backdrop-filter',
|
|
713
|
-
'border',
|
|
714
|
-
'border-radius',
|
|
715
|
-
'box-shadow',
|
|
716
|
-
'color',
|
|
717
|
-
'column-gap',
|
|
718
|
-
'container-name',
|
|
719
|
-
'container-type',
|
|
720
|
-
'display',
|
|
721
|
-
'flex',
|
|
722
|
-
'flex-direction',
|
|
723
|
-
'flex-grow',
|
|
724
|
-
'flex-wrap',
|
|
725
|
-
'font-family',
|
|
726
|
-
'font-size',
|
|
727
|
-
'font-weight',
|
|
728
|
-
'gap',
|
|
729
|
-
'grid-template-columns',
|
|
730
|
-
'height',
|
|
731
|
-
'justify-content',
|
|
732
|
-
'letter-spacing',
|
|
733
|
-
'line-height',
|
|
734
|
-
'margin',
|
|
735
|
-
'margin-bottom',
|
|
736
|
-
'margin-left',
|
|
737
|
-
'margin-right',
|
|
738
|
-
'margin-top',
|
|
739
|
-
'max-height',
|
|
740
|
-
'max-width',
|
|
741
|
-
'min-height',
|
|
742
|
-
'min-width',
|
|
743
|
-
'padding',
|
|
744
|
-
'padding-bottom',
|
|
745
|
-
'padding-end',
|
|
746
|
-
'padding-horizontal',
|
|
747
|
-
'padding-left',
|
|
748
|
-
'padding-right',
|
|
749
|
-
'padding-start',
|
|
750
|
-
'padding-top',
|
|
751
|
-
'padding-vertical',
|
|
752
|
-
'row-gap',
|
|
753
|
-
'text-align',
|
|
754
|
-
'text-decoration',
|
|
755
|
-
'text-transform',
|
|
756
|
-
'width',
|
|
757
|
-
]);
|
|
758
|
-
|
|
759
|
-
if (!supportedProperties.has(normalizedProperty)) {
|
|
760
|
-
return false;
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
if (normalizedProperty === 'display') {
|
|
764
|
-
return new Set(['block', 'flex', 'grid', 'inline', 'inline-block', 'inline-flex', 'inline-grid']).has(normalizedValue);
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
if (normalizedProperty === 'backdrop-filter') {
|
|
768
|
-
return /blur\(/.test(normalizedValue);
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
if (normalizedProperty === 'container-type') {
|
|
772
|
-
return new Set(['inline-size', 'size']).has(normalizedValue);
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
return true;
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
private matchesSupportsCondition(condition: string): boolean {
|
|
779
|
-
const normalized = condition.trim().replace(/^\(+|\)+$/g, '').trim();
|
|
780
|
-
if (!normalized) {
|
|
781
|
-
return true;
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
if (normalized.toLowerCase().startsWith('not ')) {
|
|
785
|
-
return !this.matchesSupportsCondition(normalized.slice(4));
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
const orClauses = this.splitConditionalClauses(normalized, 'or');
|
|
789
|
-
if (orClauses.length > 1) {
|
|
790
|
-
return orClauses.some((clause) => this.matchesSupportsCondition(clause));
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
const andClauses = this.splitConditionalClauses(normalized, 'and');
|
|
794
|
-
if (andClauses.length > 1) {
|
|
795
|
-
return andClauses.every((clause) => this.matchesSupportsCondition(clause));
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
const declarationMatch = normalized.match(/^([a-z-]+)\s*:\s*(.+)$/i);
|
|
799
|
-
if (!declarationMatch) {
|
|
800
|
-
return false;
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
return this.matchesSupportsDeclaration(declarationMatch[1], declarationMatch[2]);
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
private findMatchingContainerTarget(ancestors: StyleSelectorTarget[], name?: string): StyleSelectorTarget | undefined {
|
|
807
|
-
const normalizedName = typeof name === 'string' && name.trim()
|
|
808
|
-
? name.trim().toLowerCase()
|
|
809
|
-
: undefined;
|
|
810
|
-
|
|
811
|
-
for (let index = ancestors.length - 1; index >= 0; index--) {
|
|
812
|
-
const ancestor = ancestors[index];
|
|
813
|
-
if (!ancestor?.isContainer || ancestor.containerWidth === undefined) {
|
|
814
|
-
continue;
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
if (!normalizedName) {
|
|
818
|
-
return ancestor;
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
if ((ancestor.containerNames ?? []).includes(normalizedName)) {
|
|
822
|
-
return ancestor;
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
return undefined;
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
private matchesContainerCondition(condition: string, containerWidth: number): boolean {
|
|
830
|
-
const normalized = condition.trim().replace(/^\(+|\)+$/g, '').trim().toLowerCase();
|
|
831
|
-
if (!normalized) {
|
|
832
|
-
return true;
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
if (normalized.startsWith('not ')) {
|
|
836
|
-
return !this.matchesContainerCondition(normalized.slice(4), containerWidth);
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
const orClauses = this.splitConditionalClauses(normalized, 'or');
|
|
840
|
-
if (orClauses.length > 1) {
|
|
841
|
-
return orClauses.some((clause) => this.matchesContainerCondition(clause, containerWidth));
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
const andClauses = this.splitConditionalClauses(normalized, 'and');
|
|
845
|
-
if (andClauses.length > 1) {
|
|
846
|
-
return andClauses.every((clause) => this.matchesContainerCondition(clause, containerWidth));
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
if (normalized.startsWith('min-width:')) {
|
|
850
|
-
const minWidth = this.parseMediaLength(normalized.slice('min-width:'.length));
|
|
851
|
-
return minWidth !== undefined && containerWidth >= minWidth;
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
if (normalized.startsWith('max-width:')) {
|
|
855
|
-
const maxWidth = this.parseMediaLength(normalized.slice('max-width:'.length));
|
|
856
|
-
return maxWidth !== undefined && containerWidth <= maxWidth;
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
return false;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
private parseSimpleSelectorToken(token: string): ParsedSimpleSelector | undefined {
|
|
863
|
-
const trimmed = token.trim();
|
|
864
|
-
if (!trimmed || /[*&]/.test(trimmed)) {
|
|
865
|
-
return undefined;
|
|
866
|
-
}
|
|
867
|
-
let cursor = 0;
|
|
868
|
-
let tagName: string | undefined;
|
|
869
|
-
let idName: string | undefined;
|
|
870
|
-
const classNames: string[] = [];
|
|
871
|
-
const attributes: ParsedAttributeSelector[] = [];
|
|
872
|
-
const pseudoClasses: string[] = [];
|
|
873
|
-
|
|
874
|
-
const tagMatch = trimmed.slice(cursor).match(/^([_a-zA-Z][-_a-zA-Z0-9]*)/);
|
|
875
|
-
if (tagMatch) {
|
|
876
|
-
tagName = tagMatch[1].toLowerCase();
|
|
877
|
-
cursor += tagMatch[0].length;
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
while (cursor < trimmed.length) {
|
|
881
|
-
const char = trimmed[cursor];
|
|
882
|
-
if (char === '.') {
|
|
883
|
-
const classMatch = trimmed.slice(cursor).match(/^\.([_a-zA-Z][-_a-zA-Z0-9]*)/);
|
|
884
|
-
if (!classMatch) {
|
|
885
|
-
return undefined;
|
|
886
|
-
}
|
|
887
|
-
classNames.push(classMatch[1]);
|
|
888
|
-
cursor += classMatch[0].length;
|
|
889
|
-
continue;
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
if (char === '#') {
|
|
893
|
-
const idMatch = trimmed.slice(cursor).match(/^#([_a-zA-Z][-_a-zA-Z0-9]*)/);
|
|
894
|
-
if (!idMatch || idName) {
|
|
895
|
-
return undefined;
|
|
896
|
-
}
|
|
897
|
-
idName = idMatch[1];
|
|
898
|
-
cursor += idMatch[0].length;
|
|
899
|
-
continue;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
if (char === '[') {
|
|
903
|
-
const endIndex = trimmed.indexOf(']', cursor + 1);
|
|
904
|
-
if (endIndex === -1) {
|
|
905
|
-
return undefined;
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
const rawAttribute = trimmed.slice(cursor + 1, endIndex).trim();
|
|
909
|
-
const attrMatch = rawAttribute.match(/^([_a-zA-Z][-_a-zA-Z0-9]*)(?:\s*(=|~=|\^=|\$=|\*=)\s*(?:"([^"]*)"|'([^']*)'|([^\s"']+)))?$/);
|
|
910
|
-
if (!attrMatch) {
|
|
911
|
-
return undefined;
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
attributes.push({
|
|
915
|
-
name: attrMatch[1].toLowerCase(),
|
|
916
|
-
operator: attrMatch[2] as ParsedAttributeSelector['operator'] | undefined,
|
|
917
|
-
value: attrMatch[3] ?? attrMatch[4] ?? attrMatch[5],
|
|
918
|
-
});
|
|
919
|
-
cursor = endIndex + 1;
|
|
920
|
-
continue;
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
if (char === ':') {
|
|
924
|
-
const pseudoToken = this.parsePseudoSelectorToken(trimmed, cursor);
|
|
925
|
-
if (!pseudoToken) {
|
|
926
|
-
return undefined;
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
pseudoClasses.push(pseudoToken.value);
|
|
930
|
-
cursor = pseudoToken.nextIndex;
|
|
931
|
-
continue;
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
return undefined;
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
if (!tagName && !idName && classNames.length === 0 && attributes.length === 0 && pseudoClasses.length === 0) {
|
|
938
|
-
return undefined;
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
return { tagName, idName, classNames, attributes, pseudoClasses };
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
private extractSupportedSelectorChains(selector: string): ParsedSimpleSelector[][] {
|
|
945
|
-
const cached = this.parsedSelectorChainCache.get(selector);
|
|
946
|
-
if (cached) {
|
|
947
|
-
return cached;
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
const parsedChains = this.splitSelectorList(selector)
|
|
951
|
-
.map((segment) => segment.trim())
|
|
952
|
-
.map((segment) => {
|
|
953
|
-
const chain: ParsedSimpleSelector[] = [];
|
|
954
|
-
let token = '';
|
|
955
|
-
let combinator: ParsedSelectorCombinator = 'descendant';
|
|
956
|
-
let invalid = false;
|
|
957
|
-
let attributeDepth = 0;
|
|
958
|
-
let parenthesisDepth = 0;
|
|
959
|
-
let quoted: '"' | '\'' | undefined;
|
|
960
|
-
|
|
961
|
-
const flushToken = (): void => {
|
|
962
|
-
const trimmedToken = token.trim();
|
|
963
|
-
token = '';
|
|
964
|
-
if (!trimmedToken || invalid) {
|
|
965
|
-
return;
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
const parsed = this.parseSimpleSelectorToken(trimmedToken);
|
|
969
|
-
if (!parsed) {
|
|
970
|
-
invalid = true;
|
|
971
|
-
return;
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
if (chain.length > 0) {
|
|
975
|
-
parsed.combinator = combinator;
|
|
976
|
-
}
|
|
977
|
-
chain.push(parsed);
|
|
978
|
-
combinator = 'descendant';
|
|
979
|
-
};
|
|
980
|
-
|
|
981
|
-
for (let index = 0; index < segment.length; index++) {
|
|
982
|
-
const char = segment[index];
|
|
983
|
-
if (quoted) {
|
|
984
|
-
token += char;
|
|
985
|
-
if (char === quoted && segment[index - 1] !== '\\') {
|
|
986
|
-
quoted = undefined;
|
|
987
|
-
}
|
|
988
|
-
continue;
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
if (char === '"' || char === '\'') {
|
|
992
|
-
quoted = char;
|
|
993
|
-
token += char;
|
|
994
|
-
continue;
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
if (char === '[') {
|
|
998
|
-
attributeDepth += 1;
|
|
999
|
-
token += char;
|
|
1000
|
-
continue;
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
if (char === ']') {
|
|
1004
|
-
if (attributeDepth > 0) {
|
|
1005
|
-
attributeDepth -= 1;
|
|
1006
|
-
}
|
|
1007
|
-
token += char;
|
|
1008
|
-
continue;
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
if (attributeDepth === 0 && char === '(') {
|
|
1012
|
-
parenthesisDepth += 1;
|
|
1013
|
-
token += char;
|
|
1014
|
-
continue;
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
if (attributeDepth === 0 && char === ')' && parenthesisDepth > 0) {
|
|
1018
|
-
parenthesisDepth -= 1;
|
|
1019
|
-
token += char;
|
|
1020
|
-
continue;
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
if (attributeDepth === 0 && parenthesisDepth === 0 && (char === '>' || char === '+' || char === '~')) {
|
|
1024
|
-
flushToken();
|
|
1025
|
-
if (invalid) break;
|
|
1026
|
-
combinator = char === '>'
|
|
1027
|
-
? 'child'
|
|
1028
|
-
: char === '+'
|
|
1029
|
-
? 'adjacent-sibling'
|
|
1030
|
-
: 'general-sibling';
|
|
1031
|
-
continue;
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
if (attributeDepth === 0 && parenthesisDepth === 0 && /\s/.test(char)) {
|
|
1035
|
-
flushToken();
|
|
1036
|
-
if (invalid) break;
|
|
1037
|
-
continue;
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
token += char;
|
|
1041
|
-
}
|
|
1042
|
-
flushToken();
|
|
1043
|
-
|
|
1044
|
-
if (invalid || chain.length === 0) {
|
|
1045
|
-
return undefined;
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
return chain.some((part) => Boolean(part.tagName) || Boolean(part.idName) || part.classNames.length > 0 || part.attributes.length > 0 || part.pseudoClasses.length > 0)
|
|
1049
|
-
? chain
|
|
1050
|
-
: undefined;
|
|
1051
|
-
})
|
|
1052
|
-
.filter((segment): segment is ParsedSimpleSelector[] => Array.isArray(segment) && segment.length > 0);
|
|
1053
|
-
|
|
1054
|
-
this.parsedSelectorChainCache.set(selector, parsedChains);
|
|
1055
|
-
return parsedChains;
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
private matchesAttributeSelector(targetValue: string | undefined, selector: ParsedAttributeSelector): boolean {
|
|
1059
|
-
if (selector.operator === undefined) {
|
|
1060
|
-
return targetValue !== undefined;
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
if (targetValue === undefined || selector.value === undefined) {
|
|
1064
|
-
return false;
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
switch (selector.operator) {
|
|
1068
|
-
case '=':
|
|
1069
|
-
return targetValue === selector.value;
|
|
1070
|
-
case '~=':
|
|
1071
|
-
return targetValue.split(/\s+/).includes(selector.value);
|
|
1072
|
-
case '^=':
|
|
1073
|
-
return targetValue.startsWith(selector.value);
|
|
1074
|
-
case '$=':
|
|
1075
|
-
return targetValue.endsWith(selector.value);
|
|
1076
|
-
case '*=':
|
|
1077
|
-
return targetValue.includes(selector.value);
|
|
1078
|
-
default:
|
|
1079
|
-
return false;
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
private matchesSelectorPart(target: StyleSelectorTarget, selector: ParsedSimpleSelector): boolean {
|
|
1084
|
-
if (selector.tagName && target.tagName !== selector.tagName) {
|
|
1085
|
-
return false;
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
const attributes = target.attributes as Record<string, string> | undefined;
|
|
1089
|
-
if (selector.idName && attributes?.id !== selector.idName) {
|
|
1090
|
-
return false;
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
const classSet = new Set(target.classNames ?? []);
|
|
1094
|
-
if (!selector.classNames.every((className) => classSet.has(className))) {
|
|
1095
|
-
return false;
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
if (!selector.attributes.every((attribute) => this.matchesAttributeSelector(attributes?.[attribute.name], attribute))) {
|
|
1099
|
-
return false;
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
return selector.pseudoClasses.every((pseudoClass) => this.matchesPseudoClass(target, pseudoClass));
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1105
|
-
private matchesPseudoClass(target: StyleSelectorTarget, pseudoClass: string): boolean {
|
|
1106
|
-
const rawPseudoClass = pseudoClass.trim();
|
|
1107
|
-
const normalized = rawPseudoClass.toLowerCase();
|
|
1108
|
-
const pseudoStates = new Set((target.pseudoStates ?? []).map((state) => state.trim().toLowerCase()));
|
|
1109
|
-
if (pseudoStates.has(normalized)) {
|
|
1110
|
-
return true;
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
const functionalMatch = rawPseudoClass.match(/^([_a-zA-Z][-_a-zA-Z0-9]*)(?:\((.*)\))?$/);
|
|
1114
|
-
const pseudoName = functionalMatch?.[1] ?? normalized;
|
|
1115
|
-
const pseudoArgument = functionalMatch?.[2]?.trim();
|
|
1116
|
-
const attributes = target.attributes as Record<string, string> | undefined;
|
|
1117
|
-
switch (pseudoName) {
|
|
1118
|
-
case 'scope':
|
|
1119
|
-
return target.isScopeReference === true;
|
|
1120
|
-
case 'checked':
|
|
1121
|
-
return attributes?.checked !== undefined && attributes.checked !== 'false';
|
|
1122
|
-
case 'disabled':
|
|
1123
|
-
return attributes?.disabled !== undefined && attributes.disabled !== 'false';
|
|
1124
|
-
case 'selected':
|
|
1125
|
-
return (attributes?.selected !== undefined && attributes.selected !== 'false') || attributes?.['aria-current'] !== undefined;
|
|
1126
|
-
case 'first-child':
|
|
1127
|
-
return target.childIndex === 1;
|
|
1128
|
-
case 'last-child':
|
|
1129
|
-
return target.childIndex !== undefined
|
|
1130
|
-
&& target.siblingCount !== undefined
|
|
1131
|
-
&& target.childIndex === target.siblingCount;
|
|
1132
|
-
case 'only-child':
|
|
1133
|
-
return target.childIndex !== undefined
|
|
1134
|
-
&& target.siblingCount !== undefined
|
|
1135
|
-
&& target.siblingCount === 1;
|
|
1136
|
-
case 'first-of-type':
|
|
1137
|
-
return target.sameTypeIndex === 1;
|
|
1138
|
-
case 'last-of-type':
|
|
1139
|
-
return target.sameTypeIndex !== undefined
|
|
1140
|
-
&& target.sameTypeCount !== undefined
|
|
1141
|
-
&& target.sameTypeIndex === target.sameTypeCount;
|
|
1142
|
-
case 'only-of-type':
|
|
1143
|
-
return target.sameTypeIndex !== undefined
|
|
1144
|
-
&& target.sameTypeCount !== undefined
|
|
1145
|
-
&& target.sameTypeCount === 1;
|
|
1146
|
-
case 'nth-child':
|
|
1147
|
-
return target.childIndex !== undefined
|
|
1148
|
-
&& typeof pseudoArgument === 'string'
|
|
1149
|
-
&& this.matchesNthChildExpression(pseudoArgument, target.childIndex);
|
|
1150
|
-
case 'nth-last-child':
|
|
1151
|
-
return target.childIndex !== undefined
|
|
1152
|
-
&& target.siblingCount !== undefined
|
|
1153
|
-
&& typeof pseudoArgument === 'string'
|
|
1154
|
-
&& this.matchesNthChildExpression(pseudoArgument, target.siblingCount - target.childIndex + 1);
|
|
1155
|
-
case 'nth-of-type':
|
|
1156
|
-
return target.sameTypeIndex !== undefined
|
|
1157
|
-
&& typeof pseudoArgument === 'string'
|
|
1158
|
-
&& this.matchesNthChildExpression(pseudoArgument, target.sameTypeIndex);
|
|
1159
|
-
case 'nth-last-of-type':
|
|
1160
|
-
return target.sameTypeIndex !== undefined
|
|
1161
|
-
&& target.sameTypeCount !== undefined
|
|
1162
|
-
&& typeof pseudoArgument === 'string'
|
|
1163
|
-
&& this.matchesNthChildExpression(pseudoArgument, target.sameTypeCount - target.sameTypeIndex + 1);
|
|
1164
|
-
case 'has':
|
|
1165
|
-
return typeof pseudoArgument === 'string'
|
|
1166
|
-
&& this.matchesHasPseudoClass(target, pseudoArgument);
|
|
1167
|
-
case 'not': {
|
|
1168
|
-
if (!pseudoArgument) {
|
|
1169
|
-
return false;
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
|
-
const selectorArguments = this.splitSelectorList(pseudoArgument);
|
|
1173
|
-
if (selectorArguments.length === 0) {
|
|
1174
|
-
return false;
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
const parsedSelectors: ParsedSimpleSelector[] = [];
|
|
1178
|
-
for (const selectorArgument of selectorArguments) {
|
|
1179
|
-
const parsedSelector = this.parseSimpleSelectorToken(selectorArgument);
|
|
1180
|
-
if (!parsedSelector) {
|
|
1181
|
-
return false;
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
parsedSelectors.push(parsedSelector);
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
return parsedSelectors.every((selectorPart) => !this.matchesSelectorPart(target, selectorPart));
|
|
1188
|
-
}
|
|
1189
|
-
default:
|
|
1190
|
-
return false;
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
private matchesNthChildExpression(expression: string, childIndex: number): boolean {
|
|
1195
|
-
const normalized = expression.trim().toLowerCase().replace(/\s+/g, '');
|
|
1196
|
-
if (!normalized) {
|
|
1197
|
-
return false;
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
if (normalized === 'odd') {
|
|
1201
|
-
return childIndex % 2 === 1;
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
if (normalized === 'even') {
|
|
1205
|
-
return childIndex % 2 === 0;
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
if (/^[+-]?\d+$/.test(normalized)) {
|
|
1209
|
-
return childIndex === Number(normalized);
|
|
1210
|
-
}
|
|
1211
|
-
|
|
1212
|
-
const patternMatch = normalized.match(/^([+-]?\d*)n(?:([+-]?\d+))?$/);
|
|
1213
|
-
if (!patternMatch) {
|
|
1214
|
-
return false;
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
const coefficientToken = patternMatch[1];
|
|
1218
|
-
const offsetToken = patternMatch[2];
|
|
1219
|
-
const coefficient = coefficientToken === '' || coefficientToken === '+'
|
|
1220
|
-
? 1
|
|
1221
|
-
: coefficientToken === '-'
|
|
1222
|
-
? -1
|
|
1223
|
-
: Number(coefficientToken);
|
|
1224
|
-
const offset = offsetToken !== undefined ? Number(offsetToken) : 0;
|
|
1225
|
-
|
|
1226
|
-
if (!Number.isFinite(coefficient) || !Number.isFinite(offset)) {
|
|
1227
|
-
return false;
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
if (coefficient === 0) {
|
|
1231
|
-
return childIndex === offset;
|
|
1232
|
-
}
|
|
1233
|
-
|
|
1234
|
-
const delta = childIndex - offset;
|
|
1235
|
-
const step = Math.abs(coefficient);
|
|
1236
|
-
if (delta % step !== 0) {
|
|
1237
|
-
return false;
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
const n = delta / coefficient;
|
|
1241
|
-
return Number.isInteger(n) && n >= 0;
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
private matchesHasPseudoClass(target: StyleSelectorTarget, pseudoArgument: string): boolean {
|
|
1245
|
-
const selectorArguments = this.splitSelectorList(pseudoArgument);
|
|
1246
|
-
if (selectorArguments.length === 0) {
|
|
1247
|
-
return false;
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
return selectorArguments.some((selectorArgument) => this.matchesRelativeHasSelector(target, selectorArgument));
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
private matchesRelativeHasSelector(target: StyleSelectorTarget, selectorArgument: string): boolean {
|
|
1254
|
-
const trimmedSelector = selectorArgument.trim();
|
|
1255
|
-
if (!trimmedSelector) {
|
|
1256
|
-
return false;
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
const scopeRelativeSelector = this.toHasScopeRelativeSelector(trimmedSelector);
|
|
1260
|
-
if (!scopeRelativeSelector) {
|
|
1261
|
-
return false;
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
|
-
const selectorChains = this.extractSupportedSelectorChains(scopeRelativeSelector);
|
|
1265
|
-
if (selectorChains.length === 0) {
|
|
1266
|
-
return false;
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
const scopeTarget = this.normalizeTarget({ ...target, isScopeReference: true });
|
|
1270
|
-
if (trimmedSelector.startsWith('+') || trimmedSelector.startsWith('~')) {
|
|
1271
|
-
const scopedSiblings = this.buildScopedFollowingSiblingTargets(scopeTarget, target.nextSiblings ?? []);
|
|
1272
|
-
return selectorChains.some((selectorChain) =>
|
|
1273
|
-
scopedSiblings.some((sibling) => this.matchesSelectorChainInSubtree(sibling, [], selectorChain))
|
|
1274
|
-
);
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
return selectorChains.some((selectorChain) =>
|
|
1278
|
-
(target.children ?? []).some((child) => this.matchesSelectorChainInSubtree(child, [scopeTarget], selectorChain))
|
|
1279
|
-
);
|
|
1280
|
-
}
|
|
1281
|
-
|
|
1282
|
-
private toHasScopeRelativeSelector(selectorArgument: string): string | undefined {
|
|
1283
|
-
const trimmedSelector = selectorArgument.trim();
|
|
1284
|
-
if (!trimmedSelector) {
|
|
1285
|
-
return undefined;
|
|
1286
|
-
}
|
|
1287
|
-
|
|
1288
|
-
return trimmedSelector.startsWith('>') || trimmedSelector.startsWith('+') || trimmedSelector.startsWith('~')
|
|
1289
|
-
? `:scope${trimmedSelector}`
|
|
1290
|
-
: `:scope ${trimmedSelector}`;
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
private buildScopedFollowingSiblingTargets(
|
|
1294
|
-
scopeTarget: StyleSelectorTarget,
|
|
1295
|
-
nextSiblings: StyleSelectorTarget[],
|
|
1296
|
-
): StyleSelectorTarget[] {
|
|
1297
|
-
const scopedSiblings: StyleSelectorTarget[] = [];
|
|
1298
|
-
|
|
1299
|
-
for (const sibling of nextSiblings) {
|
|
1300
|
-
const scopedSibling = this.normalizeTarget({
|
|
1301
|
-
...sibling,
|
|
1302
|
-
previousSiblings: [scopeTarget, ...scopedSiblings],
|
|
1303
|
-
});
|
|
1304
|
-
scopedSiblings.push(scopedSibling);
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
return scopedSiblings;
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
private matchesSelectorChainInSubtree(
|
|
1311
|
-
target: StyleSelectorTarget,
|
|
1312
|
-
ancestors: StyleSelectorTarget[],
|
|
1313
|
-
chain: ParsedSimpleSelector[],
|
|
1314
|
-
): boolean {
|
|
1315
|
-
if (this.matchesSelectorChain(target, ancestors, chain)) {
|
|
1316
|
-
return true;
|
|
1317
|
-
}
|
|
1318
|
-
|
|
1319
|
-
const nextAncestors = [...ancestors, target];
|
|
1320
|
-
return (target.children ?? []).some((child) => this.matchesSelectorChainInSubtree(child, nextAncestors, chain));
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
private matchesSelectorChain(
|
|
1324
|
-
target: StyleSelectorTarget,
|
|
1325
|
-
ancestors: StyleSelectorTarget[],
|
|
1326
|
-
chain: ParsedSimpleSelector[],
|
|
1327
|
-
): boolean {
|
|
1328
|
-
const initialCursor: ParsedSelectorCursor = {
|
|
1329
|
-
target,
|
|
1330
|
-
ancestorIndex: ancestors.length - 1,
|
|
1331
|
-
previousSiblings: Array.isArray(target.previousSiblings) ? target.previousSiblings : [],
|
|
1332
|
-
};
|
|
1333
|
-
|
|
1334
|
-
return this.matchesSelectorChainFromCursor(chain, chain.length - 1, ancestors, initialCursor);
|
|
1335
|
-
}
|
|
1336
|
-
|
|
1337
|
-
private getAncestorCursor(ancestors: StyleSelectorTarget[], ancestorIndex: number): ParsedSelectorCursor | undefined {
|
|
1338
|
-
if (ancestorIndex < 0 || ancestorIndex >= ancestors.length) {
|
|
1339
|
-
return undefined;
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1342
|
-
const ancestor = ancestors[ancestorIndex];
|
|
1343
|
-
return {
|
|
1344
|
-
target: ancestor,
|
|
1345
|
-
ancestorIndex: ancestorIndex - 1,
|
|
1346
|
-
previousSiblings: Array.isArray(ancestor.previousSiblings) ? ancestor.previousSiblings : [],
|
|
1347
|
-
};
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
private matchesSelectorChainFromCursor(
|
|
1351
|
-
chain: ParsedSimpleSelector[],
|
|
1352
|
-
chainIndex: number,
|
|
1353
|
-
ancestors: StyleSelectorTarget[],
|
|
1354
|
-
cursor: ParsedSelectorCursor,
|
|
1355
|
-
): boolean {
|
|
1356
|
-
if (!this.matchesSelectorPart(cursor.target, chain[chainIndex])) {
|
|
1357
|
-
return false;
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
if (chainIndex === 0) {
|
|
1361
|
-
return true;
|
|
1362
|
-
}
|
|
1363
|
-
|
|
1364
|
-
const combinator = chain[chainIndex].combinator ?? 'descendant';
|
|
1365
|
-
switch (combinator) {
|
|
1366
|
-
case 'child': {
|
|
1367
|
-
const parentCursor = this.getAncestorCursor(ancestors, cursor.ancestorIndex);
|
|
1368
|
-
return parentCursor
|
|
1369
|
-
? this.matchesSelectorChainFromCursor(chain, chainIndex - 1, ancestors, parentCursor)
|
|
1370
|
-
: false;
|
|
1371
|
-
}
|
|
1372
|
-
case 'adjacent-sibling': {
|
|
1373
|
-
const siblingIndex = cursor.previousSiblings.length - 1;
|
|
1374
|
-
if (siblingIndex < 0) {
|
|
1375
|
-
return false;
|
|
1376
|
-
}
|
|
1377
|
-
|
|
1378
|
-
return this.matchesSelectorChainFromCursor(chain, chainIndex - 1, ancestors, {
|
|
1379
|
-
target: cursor.previousSiblings[siblingIndex],
|
|
1380
|
-
ancestorIndex: cursor.ancestorIndex,
|
|
1381
|
-
previousSiblings: cursor.previousSiblings.slice(0, siblingIndex),
|
|
1382
|
-
});
|
|
1383
|
-
}
|
|
1384
|
-
case 'general-sibling': {
|
|
1385
|
-
for (let siblingIndex = cursor.previousSiblings.length - 1; siblingIndex >= 0; siblingIndex--) {
|
|
1386
|
-
if (this.matchesSelectorChainFromCursor(chain, chainIndex - 1, ancestors, {
|
|
1387
|
-
target: cursor.previousSiblings[siblingIndex],
|
|
1388
|
-
ancestorIndex: cursor.ancestorIndex,
|
|
1389
|
-
previousSiblings: cursor.previousSiblings.slice(0, siblingIndex),
|
|
1390
|
-
})) {
|
|
1391
|
-
return true;
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
return false;
|
|
1396
|
-
}
|
|
1397
|
-
case 'descendant':
|
|
1398
|
-
default: {
|
|
1399
|
-
for (let ancestorIndex = cursor.ancestorIndex; ancestorIndex >= 0; ancestorIndex--) {
|
|
1400
|
-
const ancestorCursor = this.getAncestorCursor(ancestors, ancestorIndex);
|
|
1401
|
-
if (ancestorCursor && this.matchesSelectorChainFromCursor(chain, chainIndex - 1, ancestors, ancestorCursor)) {
|
|
1402
|
-
return true;
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
return false;
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
private parseMediaLength(value: string): number | undefined {
|
|
1412
|
-
const match = value.trim().match(/^(-?\d+(?:\.\d+)?)(px|rem|em)?$/i);
|
|
1413
|
-
if (!match) {
|
|
1414
|
-
return undefined;
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
|
-
const numericValue = Number(match[1]);
|
|
1418
|
-
const unit = (match[2] ?? 'px').toLowerCase();
|
|
1419
|
-
if (unit === 'rem' || unit === 'em') {
|
|
1420
|
-
return numericValue * 16;
|
|
1421
|
-
}
|
|
1422
|
-
|
|
1423
|
-
return numericValue;
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
|
-
private matchesMediaCondition(condition: string, options: NativeStyleResolveOptions): boolean {
|
|
1427
|
-
const normalized = condition.trim().replace(/^\(+|\)+$/g, '').trim().toLowerCase();
|
|
1428
|
-
if (!normalized) {
|
|
1429
|
-
return true;
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
if (normalized.startsWith('min-width:')) {
|
|
1433
|
-
const minWidth = this.parseMediaLength(normalized.slice('min-width:'.length));
|
|
1434
|
-
return minWidth !== undefined && options.viewportWidth !== undefined && options.viewportWidth >= minWidth;
|
|
1435
|
-
}
|
|
1436
|
-
|
|
1437
|
-
if (normalized.startsWith('max-width:')) {
|
|
1438
|
-
const maxWidth = this.parseMediaLength(normalized.slice('max-width:'.length));
|
|
1439
|
-
return maxWidth !== undefined && options.viewportWidth !== undefined && options.viewportWidth <= maxWidth;
|
|
1440
|
-
}
|
|
1441
|
-
|
|
1442
|
-
if (normalized === 'prefers-color-scheme: dark') {
|
|
1443
|
-
return options.colorScheme === 'dark';
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
if (normalized === 'prefers-color-scheme: light') {
|
|
1447
|
-
return (options.colorScheme ?? 'light') === 'light';
|
|
1448
|
-
}
|
|
1449
|
-
|
|
1450
|
-
if (normalized === 'prefers-reduced-motion: reduce') {
|
|
1451
|
-
return options.reducedMotion === true;
|
|
1452
|
-
}
|
|
1453
|
-
|
|
1454
|
-
return false;
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
private matchesMediaRule(rule: MediaRule, options: NativeStyleResolveOptions): boolean {
|
|
1458
|
-
const mediaType = options.mediaType ?? 'screen';
|
|
1459
|
-
if (rule.type && rule.type !== mediaType && rule.type !== 'all') {
|
|
1460
|
-
return false;
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
|
-
if (!rule.condition.trim()) {
|
|
1464
|
-
return true;
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
|
-
return rule.condition
|
|
1468
|
-
.split(/\band\b/i)
|
|
1469
|
-
.map((part) => part.trim())
|
|
1470
|
-
.filter(Boolean)
|
|
1471
|
-
.every((part) => this.matchesMediaCondition(part, options));
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
private getOrderedLayerNames(): string[] {
|
|
1475
|
-
const orderedLayerNames: string[] = [];
|
|
1476
|
-
|
|
1477
|
-
for (const layerName of this._layerOrder) {
|
|
1478
|
-
const normalizedName = layerName.trim();
|
|
1479
|
-
if (normalizedName && !orderedLayerNames.includes(normalizedName)) {
|
|
1480
|
-
orderedLayerNames.push(normalizedName);
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
for (const layerRule of this.layerRules) {
|
|
1485
|
-
const normalizedName = layerRule.name.trim();
|
|
1486
|
-
if (normalizedName && !orderedLayerNames.includes(normalizedName)) {
|
|
1487
|
-
orderedLayerNames.push(normalizedName);
|
|
1488
|
-
}
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
return orderedLayerNames;
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
resolveNativeStyles(
|
|
1495
|
-
target: StyleSelectorTarget,
|
|
1496
|
-
ancestors: StyleSelectorTarget[] = [],
|
|
1497
|
-
options: NativeStyleResolveOptions = {},
|
|
1498
|
-
): Record<string, string | number> {
|
|
1499
|
-
return this.withNativeTargetNormalizationCache(() => {
|
|
1500
|
-
const normalizedTarget = this.normalizeTarget(target);
|
|
1501
|
-
if (!normalizedTarget.tagName && (!normalizedTarget.classNames || normalizedTarget.classNames.length === 0)) {
|
|
1502
|
-
return {};
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
const normalizedAncestors = ancestors.map((ancestor) => this.normalizeTarget(ancestor));
|
|
1506
|
-
const variables = this.getVariables();
|
|
1507
|
-
const resolved: Record<string, string | number> = {};
|
|
1508
|
-
|
|
1509
|
-
const applyRules = (rules: CSSRule[]): void => {
|
|
1510
|
-
for (const rule of rules) {
|
|
1511
|
-
const selectorChains = this.extractSupportedSelectorChains(rule.selector);
|
|
1512
|
-
if (selectorChains.length === 0) {
|
|
1513
|
-
continue;
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
const matches = selectorChains.some((selectorChain) => this.matchesSelectorChain(normalizedTarget, normalizedAncestors, selectorChain));
|
|
1517
|
-
if (!matches) {
|
|
1518
|
-
continue;
|
|
1519
|
-
}
|
|
1520
|
-
|
|
1521
|
-
for (const [property, value] of Object.entries(rule.styles)) {
|
|
1522
|
-
resolved[property] = typeof value === 'string'
|
|
1523
|
-
? this.resolveVariableReferences(value, variables)
|
|
1524
|
-
: value;
|
|
1525
|
-
}
|
|
1526
|
-
}
|
|
1527
|
-
}
|
|
1528
|
-
|
|
1529
|
-
for (const layerName of this.getOrderedLayerNames()) {
|
|
1530
|
-
for (const layerRule of this.layerRules) {
|
|
1531
|
-
if (layerRule.name.trim() === layerName) {
|
|
1532
|
-
applyRules(layerRule.rules);
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
}
|
|
1536
|
-
|
|
1537
|
-
applyRules(this.rules);
|
|
1538
|
-
|
|
1539
|
-
for (const supportsRule of this.supportsRules) {
|
|
1540
|
-
if (this.matchesSupportsCondition(supportsRule.condition)) {
|
|
1541
|
-
applyRules(supportsRule.rules);
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
|
|
1545
|
-
for (const containerRule of this.containerRules) {
|
|
1546
|
-
const matchingContainer = this.findMatchingContainerTarget(normalizedAncestors, containerRule.name);
|
|
1547
|
-
if (matchingContainer && this.matchesContainerCondition(containerRule.condition, matchingContainer.containerWidth!)) {
|
|
1548
|
-
applyRules(containerRule.rules);
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
|
|
1552
|
-
for (const mediaRule of this.mediaRules) {
|
|
1553
|
-
if (this.matchesMediaRule(mediaRule, options)) {
|
|
1554
|
-
applyRules(mediaRule.rules);
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
|
-
return resolved;
|
|
1559
|
-
});
|
|
1560
|
-
}
|
|
1561
|
-
|
|
1562
|
-
resolveClassStyles(classNames: string[]): Record<string, string | number> {
|
|
1563
|
-
return this.resolveNativeStyles({ classNames });
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
// Utility Methods
|
|
1567
|
-
private toKebabCase(str: string): string {
|
|
1568
|
-
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
|
1569
|
-
}
|
|
1570
|
-
|
|
1571
|
-
// Helper: Create and add rule (eliminates duplication in combinator selectors)
|
|
1572
|
-
private createAndAddRule(selector: string, styles: Record<string, string | number>, type: CSSRule['type'] = 'custom'): CSSRule {
|
|
1573
|
-
const rule: CSSRule = { selector, styles, type };
|
|
1574
|
-
this.rules.push(rule);
|
|
1575
|
-
return rule;
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
// Helper: Convert rules object to CSSRule array (eliminates duplication in media/container/supports/layer)
|
|
1579
|
-
private rulesToCSSRules(rules: Record<string, Record<string, string | number>>): CSSRule[] {
|
|
1580
|
-
return Object.entries(rules).map(([selector, styles]) => ({
|
|
1581
|
-
selector,
|
|
1582
|
-
styles,
|
|
1583
|
-
type: 'custom' as const
|
|
1584
|
-
}));
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
// Helper: Render rules with indentation (eliminates duplication in render methods)
|
|
1588
|
-
private renderRulesWithIndent(rules: CSSRule[], indent: string = ' '): string {
|
|
1589
|
-
return rules.map(rule => this.renderRule(rule, indent)).join('\n');
|
|
1590
|
-
}
|
|
1591
|
-
|
|
1592
|
-
private stylesToString(styles: Record<string, string | number>, indent: string = ' '): string {
|
|
1593
|
-
return Object.entries(styles)
|
|
1594
|
-
.map(([prop, value]) => {
|
|
1595
|
-
const cssValue = typeof value === 'object' && value !== null && 'name' in value
|
|
1596
|
-
? `var(${(value as CSSVariable).name})`
|
|
1597
|
-
: value;
|
|
1598
|
-
return `${indent}${this.toKebabCase(prop)}: ${cssValue};`;
|
|
1599
|
-
})
|
|
1600
|
-
.join('\n');
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
|
-
private renderRule(rule: CSSRule, indent: string = ''): string {
|
|
1604
|
-
let css = `${indent}${rule.selector} {\n${this.stylesToString(rule.styles, indent + ' ')}\n`;
|
|
1605
|
-
|
|
1606
|
-
if (rule.nested && rule.nested.length > 0) {
|
|
1607
|
-
for (const nestedRule of rule.nested) {
|
|
1608
|
-
const nestedSelector = nestedRule.selector.startsWith('&')
|
|
1609
|
-
? nestedRule.selector.replace(/&/g, rule.selector)
|
|
1610
|
-
: `${rule.selector} ${nestedRule.selector}`;
|
|
1611
|
-
css += `\n${indent}${nestedSelector} {\n${this.stylesToString(nestedRule.styles, indent + ' ')}\n${indent}}\n`;
|
|
1612
|
-
}
|
|
1613
|
-
}
|
|
1614
|
-
|
|
1615
|
-
css += `${indent}}`;
|
|
1616
|
-
return css;
|
|
1617
|
-
}
|
|
1618
|
-
|
|
1619
|
-
private renderMediaRule(media: MediaRule): string {
|
|
1620
|
-
const condition = media.type && media.condition
|
|
1621
|
-
? `${media.type} and (${media.condition})`
|
|
1622
|
-
: media.type
|
|
1623
|
-
? media.type
|
|
1624
|
-
: `(${media.condition})`;
|
|
1625
|
-
return `@media ${condition} {\n${this.renderRulesWithIndent(media.rules)}\n}`;
|
|
1626
|
-
}
|
|
1627
|
-
|
|
1628
|
-
private renderKeyframes(kf: Keyframes): string {
|
|
1629
|
-
let css = `@keyframes ${kf.name} {\n`;
|
|
1630
|
-
for (const step of kf.steps) {
|
|
1631
|
-
css += ` ${step.step} {\n${this.stylesToString(step.styles, ' ')}\n }\n`;
|
|
1632
|
-
}
|
|
1633
|
-
css += '}';
|
|
1634
|
-
return css;
|
|
1635
|
-
}
|
|
1636
|
-
|
|
1637
|
-
private renderFontFace(ff: FontFace): string {
|
|
1638
|
-
let css = '@font-face {\n';
|
|
1639
|
-
css += ` font-family: "${ff.fontFamily}";\n`;
|
|
1640
|
-
css += ` src: ${ff.src};\n`;
|
|
1641
|
-
if (ff.fontWeight) css += ` font-weight: ${ff.fontWeight};\n`;
|
|
1642
|
-
if (ff.fontStyle) css += ` font-style: ${ff.fontStyle};\n`;
|
|
1643
|
-
if (ff.fontDisplay) css += ` font-display: ${ff.fontDisplay};\n`;
|
|
1644
|
-
if (ff.unicodeRange) css += ` unicode-range: ${ff.unicodeRange};\n`;
|
|
1645
|
-
css += '}';
|
|
1646
|
-
return css;
|
|
1647
|
-
}
|
|
1648
|
-
|
|
1649
|
-
private renderContainerRule(container: ContainerRule): string {
|
|
1650
|
-
const nameStr = container.name ? `${container.name} ` : '';
|
|
1651
|
-
return `@container ${nameStr}(${container.condition}) {\n${this.renderRulesWithIndent(container.rules)}\n}`;
|
|
1652
|
-
}
|
|
1653
|
-
|
|
1654
|
-
private renderSupportsRule(supports: SupportsRule): string {
|
|
1655
|
-
return `@supports (${supports.condition}) {\n${this.renderRulesWithIndent(supports.rules)}\n}`;
|
|
1656
|
-
}
|
|
1657
|
-
|
|
1658
|
-
private renderLayerRule(layer: LayerRule): string {
|
|
1659
|
-
return `@layer ${layer.name} {\n${this.renderRulesWithIndent(layer.rules)}\n}`;
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
// Render Output
|
|
1663
|
-
render(...additionalRules: (CSSRule | CSSRule[] | MediaRule | Keyframes | ContainerRule | SupportsRule | LayerRule | undefined | null)[]): string {
|
|
1664
|
-
const parts: string[] = [];
|
|
1665
|
-
|
|
1666
|
-
if (this.imports.length > 0) {
|
|
1667
|
-
parts.push(this.imports.join('\n'));
|
|
1668
|
-
}
|
|
1669
|
-
|
|
1670
|
-
if (this._layerOrder.length > 0) {
|
|
1671
|
-
parts.push(`@layer ${this._layerOrder.join(', ')};`);
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
if (this.variables.length > 0) {
|
|
1675
|
-
const varDeclarations = this.variables
|
|
1676
|
-
.map(v => ` ${v.name}: ${v.value};`)
|
|
1677
|
-
.join('\n');
|
|
1678
|
-
parts.push(`:root {\n${varDeclarations}\n}`);
|
|
1679
|
-
}
|
|
1680
|
-
|
|
1681
|
-
for (const ff of this.fontFaces) {
|
|
1682
|
-
parts.push(this.renderFontFace(ff));
|
|
1683
|
-
}
|
|
1684
|
-
|
|
1685
|
-
for (const kf of this.keyframes) {
|
|
1686
|
-
parts.push(this.renderKeyframes(kf));
|
|
1687
|
-
}
|
|
1688
|
-
|
|
1689
|
-
const allRules: CSSRule[] = [...this.rules];
|
|
1690
|
-
const allMediaRules: MediaRule[] = [...this.mediaRules];
|
|
1691
|
-
const allKeyframes: Keyframes[] = [];
|
|
1692
|
-
const allContainerRules: ContainerRule[] = [...this.containerRules];
|
|
1693
|
-
const allSupportsRules: SupportsRule[] = [...this.supportsRules];
|
|
1694
|
-
const allLayerRules: LayerRule[] = [...this.layerRules];
|
|
1695
|
-
|
|
1696
|
-
for (const item of additionalRules) {
|
|
1697
|
-
if (!item) continue;
|
|
1698
|
-
if (Array.isArray(item)) {
|
|
1699
|
-
allRules.push(...item);
|
|
1700
|
-
} else if ('condition' in item && 'rules' in item && !('name' in item && 'steps' in item)) {
|
|
1701
|
-
if ('type' in item) {
|
|
1702
|
-
allMediaRules.push(item as MediaRule);
|
|
1703
|
-
} else if ('name' in item && typeof (item as any).name === 'string') {
|
|
1704
|
-
allContainerRules.push(item as ContainerRule);
|
|
1705
|
-
} else {
|
|
1706
|
-
allSupportsRules.push(item as SupportsRule);
|
|
1707
|
-
}
|
|
1708
|
-
} else if ('name' in item && 'steps' in item) {
|
|
1709
|
-
allKeyframes.push(item as Keyframes);
|
|
1710
|
-
} else if ('name' in item && 'rules' in item) {
|
|
1711
|
-
allLayerRules.push(item as LayerRule);
|
|
1712
|
-
} else {
|
|
1713
|
-
allRules.push(item as CSSRule);
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1716
|
-
|
|
1717
|
-
for (const kf of allKeyframes) {
|
|
1718
|
-
parts.push(this.renderKeyframes(kf));
|
|
1719
|
-
}
|
|
1720
|
-
|
|
1721
|
-
for (const layer of allLayerRules) {
|
|
1722
|
-
parts.push(this.renderLayerRule(layer));
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
for (const rule of allRules) {
|
|
1726
|
-
parts.push(this.renderRule(rule));
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
|
-
for (const supports of allSupportsRules) {
|
|
1730
|
-
parts.push(this.renderSupportsRule(supports));
|
|
1731
|
-
}
|
|
1732
|
-
|
|
1733
|
-
for (const container of allContainerRules) {
|
|
1734
|
-
parts.push(this.renderContainerRule(container));
|
|
1735
|
-
}
|
|
1736
|
-
|
|
1737
|
-
for (const media of allMediaRules) {
|
|
1738
|
-
parts.push(this.renderMediaRule(media));
|
|
1739
|
-
}
|
|
1740
|
-
|
|
1741
|
-
return parts.join('\n\n');
|
|
1742
|
-
}
|
|
1743
|
-
|
|
1744
|
-
inject(styleId?: string): HTMLStyleElement {
|
|
1745
|
-
const css = this.render();
|
|
1746
|
-
const style = document.createElement('style');
|
|
1747
|
-
if (styleId) style.id = styleId;
|
|
1748
|
-
style.textContent = css;
|
|
1749
|
-
document.head.appendChild(style);
|
|
1750
|
-
return style;
|
|
1751
|
-
}
|
|
1752
|
-
|
|
1753
|
-
clear(): void {
|
|
1754
|
-
this.variables.length = 0;
|
|
1755
|
-
this.rules.length = 0;
|
|
1756
|
-
this.mediaRules.length = 0;
|
|
1757
|
-
this.keyframes.length = 0;
|
|
1758
|
-
this.fontFaces.length = 0;
|
|
1759
|
-
this.imports.length = 0;
|
|
1760
|
-
this.containerRules.length = 0;
|
|
1761
|
-
this.supportsRules.length = 0;
|
|
1762
|
-
this.layerRules.length = 0;
|
|
1763
|
-
this._layerOrder.length = 0;
|
|
1764
|
-
}
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
export const styles = new CreateStyle(getSharedStyleStore());
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
export const {
|
|
1771
|
-
addVar, var: getVar,
|
|
1772
|
-
addTag, addClass, addId,
|
|
1773
|
-
addPseudoClass, addPseudoElement, addAttribute, attrEquals, attrContainsWord, attrStartsWith, attrEndsWith, attrContains,
|
|
1774
|
-
descendant, child: childStyle, adjacentSibling, generalSibling, multiple: multipleStyle,
|
|
1775
|
-
addName, nesting,
|
|
1776
|
-
keyframe, keyframeFromTo,
|
|
1777
|
-
fontFace,
|
|
1778
|
-
import: importStyle,
|
|
1779
|
-
media: mediaStyle,
|
|
1780
|
-
mediaScreen, mediaPrint, mediaMinWidth, mediaMaxWidth, mediaDark, mediaLight, mediaReducedMotion,
|
|
1781
|
-
container, addContainer,
|
|
1782
|
-
supports: supportsStyle,
|
|
1783
|
-
layerOrder, layer,
|
|
1784
|
-
add: addStyle, important,
|
|
1785
|
-
getVariables: getStyleVariables,
|
|
1786
|
-
resolveClassStyles,
|
|
1787
|
-
render: renderStyle, inject: injectStyle, clear: clearStyle
|
|
1788
|
-
} = styles;
|
|
1789
|
-
|
|
1790
|
-
export default styles;
|