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.
Files changed (113) hide show
  1. package/Cargo.toml +1 -1
  2. package/README.md +1 -1
  3. package/desktop/build.rs +83 -0
  4. package/desktop/icon.rs +106 -0
  5. package/desktop/lib.rs +2 -0
  6. package/desktop/main.rs +235 -0
  7. package/desktop/native_main.rs +128 -0
  8. package/desktop/native_renderer/action_widgets.rs +184 -0
  9. package/desktop/native_renderer/app_models.rs +171 -0
  10. package/desktop/native_renderer/app_runtime.rs +140 -0
  11. package/desktop/native_renderer/container_rendering.rs +610 -0
  12. package/desktop/native_renderer/content_widgets.rs +634 -0
  13. package/desktop/native_renderer/css_models.rs +371 -0
  14. package/desktop/native_renderer/embedded_surfaces.rs +414 -0
  15. package/desktop/native_renderer/form_controls.rs +516 -0
  16. package/desktop/native_renderer/interaction_dispatch.rs +89 -0
  17. package/desktop/native_renderer/runtime_support.rs +135 -0
  18. package/desktop/native_renderer/utilities.rs +495 -0
  19. package/desktop/native_renderer/vector_drawing.rs +491 -0
  20. package/desktop/native_renderer.rs +4122 -0
  21. package/desktop/runtime/external.rs +422 -0
  22. package/desktop/runtime/mod.rs +67 -0
  23. package/desktop/runtime/quickjs.rs +106 -0
  24. package/desktop/window.rs +383 -0
  25. package/package.json +6 -3
  26. package/dist/build.d.mts +0 -20
  27. package/dist/chokidar.d.mts +0 -134
  28. package/dist/cli.d.mts +0 -81
  29. package/dist/config.d.mts +0 -254
  30. package/dist/coverage.d.mts +0 -85
  31. package/dist/database.d.mts +0 -52
  32. package/dist/desktop.d.mts +0 -68
  33. package/dist/dom.d.mts +0 -87
  34. package/dist/el.d.mts +0 -208
  35. package/dist/fs.d.mts +0 -255
  36. package/dist/hmr.d.mts +0 -38
  37. package/dist/http.d.mts +0 -169
  38. package/dist/https.d.mts +0 -108
  39. package/dist/index.d.mts +0 -13
  40. package/dist/mime-types.d.mts +0 -48
  41. package/dist/native.d.mts +0 -136
  42. package/dist/path.d.mts +0 -163
  43. package/dist/router.d.mts +0 -49
  44. package/dist/runtime.d.mts +0 -97
  45. package/dist/server-D0Dp4R5z.d.mts +0 -449
  46. package/dist/server.d.mts +0 -7
  47. package/dist/state.d.mts +0 -117
  48. package/dist/style.d.mts +0 -232
  49. package/dist/test-reporter.d.mts +0 -77
  50. package/dist/test-runtime.d.mts +0 -122
  51. package/dist/test.d.mts +0 -39
  52. package/dist/types.d.mts +0 -586
  53. package/dist/universal.d.mts +0 -21
  54. package/dist/ws.d.mts +0 -200
  55. package/dist/wss.d.mts +0 -108
  56. package/src/build.ts +0 -362
  57. package/src/chokidar.ts +0 -427
  58. package/src/cli.ts +0 -1162
  59. package/src/config.ts +0 -509
  60. package/src/coverage.ts +0 -1479
  61. package/src/database.ts +0 -1410
  62. package/src/desktop-auto-render.ts +0 -317
  63. package/src/desktop-cli.ts +0 -1533
  64. package/src/desktop.ts +0 -99
  65. package/src/dev-build.ts +0 -340
  66. package/src/dom.ts +0 -901
  67. package/src/el.ts +0 -183
  68. package/src/fs.ts +0 -609
  69. package/src/hmr.ts +0 -149
  70. package/src/http.ts +0 -856
  71. package/src/https.ts +0 -411
  72. package/src/index.ts +0 -16
  73. package/src/mime-types.ts +0 -222
  74. package/src/mobile-cli.ts +0 -2313
  75. package/src/native-background.ts +0 -444
  76. package/src/native-border.ts +0 -343
  77. package/src/native-canvas.ts +0 -260
  78. package/src/native-cli.ts +0 -414
  79. package/src/native-color.ts +0 -904
  80. package/src/native-estimation.ts +0 -194
  81. package/src/native-grid.ts +0 -590
  82. package/src/native-interaction.ts +0 -1289
  83. package/src/native-layout.ts +0 -568
  84. package/src/native-link.ts +0 -76
  85. package/src/native-render-support.ts +0 -361
  86. package/src/native-spacing.ts +0 -231
  87. package/src/native-state.ts +0 -318
  88. package/src/native-strings.ts +0 -46
  89. package/src/native-transform.ts +0 -120
  90. package/src/native-types.ts +0 -439
  91. package/src/native-typography.ts +0 -254
  92. package/src/native-units.ts +0 -441
  93. package/src/native-vector.ts +0 -910
  94. package/src/native.ts +0 -5606
  95. package/src/path.ts +0 -493
  96. package/src/pm-cli.ts +0 -2498
  97. package/src/preview-build.ts +0 -294
  98. package/src/render-context.ts +0 -138
  99. package/src/router.ts +0 -260
  100. package/src/runtime.ts +0 -97
  101. package/src/server.ts +0 -2294
  102. package/src/state.ts +0 -556
  103. package/src/style.ts +0 -1790
  104. package/src/test-globals.d.ts +0 -184
  105. package/src/test-reporter.ts +0 -609
  106. package/src/test-runtime.ts +0 -1359
  107. package/src/test.ts +0 -368
  108. package/src/types.ts +0 -381
  109. package/src/universal.ts +0 -81
  110. package/src/wapk-cli.ts +0 -3213
  111. package/src/workspace-package.ts +0 -102
  112. package/src/ws.ts +0 -648
  113. 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;