@elastic/distillate 0.0.0 → 0.1.0
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/LICENSE.txt +93 -0
- package/NOTICE.txt +30 -0
- package/README.md +142 -0
- package/THIRD_PARTY_LICENSES.md +768 -0
- package/dist/cjs/collector.js +420 -0
- package/dist/cjs/collector.js.map +1 -0
- package/dist/cjs/css_scan.js +186 -0
- package/dist/cjs/css_scan.js.map +1 -0
- package/dist/cjs/dom_sink.js +40 -0
- package/dist/cjs/dom_sink.js.map +1 -0
- package/dist/cjs/emotion.js +189 -0
- package/dist/cjs/emotion.js.map +1 -0
- package/dist/cjs/engine.js +79 -0
- package/dist/cjs/engine.js.map +1 -0
- package/dist/cjs/environment.js +9 -0
- package/dist/cjs/environment.js.map +1 -0
- package/dist/cjs/hash.js +86 -0
- package/dist/cjs/hash.js.map +1 -0
- package/dist/cjs/idents.js +23 -0
- package/dist/cjs/idents.js.map +1 -0
- package/dist/cjs/index.js +42 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/instance.js +34 -0
- package/dist/cjs/instance.js.map +1 -0
- package/dist/cjs/local_vars.js +100 -0
- package/dist/cjs/local_vars.js.map +1 -0
- package/dist/cjs/minify.js +77 -0
- package/dist/cjs/minify.js.map +1 -0
- package/dist/cjs/names.js +77 -0
- package/dist/cjs/names.js.map +1 -0
- package/dist/cjs/nesting.js +406 -0
- package/dist/cjs/nesting.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/runtime.js +257 -0
- package/dist/cjs/runtime.js.map +1 -0
- package/dist/cjs/styles/authoring.js +169 -0
- package/dist/cjs/styles/authoring.js.map +1 -0
- package/dist/cjs/styles/declarations.js +139 -0
- package/dist/cjs/styles/declarations.js.map +1 -0
- package/dist/cjs/styles/index.js +32 -0
- package/dist/cjs/styles/index.js.map +1 -0
- package/dist/cjs/styles/module.js +233 -0
- package/dist/cjs/styles/module.js.map +1 -0
- package/dist/cjs/styles/registry.js +187 -0
- package/dist/cjs/styles/registry.js.map +1 -0
- package/dist/cjs/styles/types.js +9 -0
- package/dist/cjs/styles/types.js.map +1 -0
- package/dist/cjs/testing.js +37 -0
- package/dist/cjs/testing.js.map +1 -0
- package/dist/cjs/theme.js +249 -0
- package/dist/cjs/theme.js.map +1 -0
- package/dist/cjs/tokens/contextual_var.js +39 -0
- package/dist/cjs/tokens/contextual_var.js.map +1 -0
- package/dist/cjs/tokens/index.js +24 -0
- package/dist/cjs/tokens/index.js.map +1 -0
- package/dist/cjs/tokens/kind.js +14 -0
- package/dist/cjs/tokens/kind.js.map +1 -0
- package/dist/cjs/tokens/light_dark.js +42 -0
- package/dist/cjs/tokens/light_dark.js.map +1 -0
- package/dist/cjs/tokens/scale_token.js +28 -0
- package/dist/cjs/tokens/scale_token.js.map +1 -0
- package/dist/cjs/tokens/theme_token.js +28 -0
- package/dist/cjs/tokens/theme_token.js.map +1 -0
- package/dist/cjs/var_invariant.js +115 -0
- package/dist/cjs/var_invariant.js.map +1 -0
- package/dist/collector.d.ts +84 -0
- package/dist/collector.d.ts.map +1 -0
- package/dist/collector.js +416 -0
- package/dist/collector.js.map +1 -0
- package/dist/css_scan.d.ts +57 -0
- package/dist/css_scan.d.ts.map +1 -0
- package/dist/css_scan.js +180 -0
- package/dist/css_scan.js.map +1 -0
- package/dist/dom_sink.d.ts +27 -0
- package/dist/dom_sink.d.ts.map +1 -0
- package/dist/dom_sink.js +36 -0
- package/dist/dom_sink.js.map +1 -0
- package/dist/emotion.d.ts +47 -0
- package/dist/emotion.d.ts.map +1 -0
- package/dist/emotion.js +184 -0
- package/dist/emotion.js.map +1 -0
- package/dist/engine.d.ts +41 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +75 -0
- package/dist/engine.js.map +1 -0
- package/dist/environment.d.ts +43 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +8 -0
- package/dist/environment.js.map +1 -0
- package/dist/hash.d.ts +2 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +82 -0
- package/dist/hash.js.map +1 -0
- package/dist/idents.d.ts +9 -0
- package/dist/idents.d.ts.map +1 -0
- package/dist/idents.js +19 -0
- package/dist/idents.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/instance.d.ts +16 -0
- package/dist/instance.d.ts.map +1 -0
- package/dist/instance.js +30 -0
- package/dist/instance.js.map +1 -0
- package/dist/local_vars.d.ts +75 -0
- package/dist/local_vars.d.ts.map +1 -0
- package/dist/local_vars.js +92 -0
- package/dist/local_vars.js.map +1 -0
- package/dist/minify.d.ts +11 -0
- package/dist/minify.d.ts.map +1 -0
- package/dist/minify.js +73 -0
- package/dist/minify.js.map +1 -0
- package/dist/names.d.ts +39 -0
- package/dist/names.d.ts.map +1 -0
- package/dist/names.js +70 -0
- package/dist/names.js.map +1 -0
- package/dist/nesting.d.ts +59 -0
- package/dist/nesting.d.ts.map +1 -0
- package/dist/nesting.js +400 -0
- package/dist/nesting.js.map +1 -0
- package/dist/runtime.d.ts +36 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +252 -0
- package/dist/runtime.js.map +1 -0
- package/dist/styles/authoring.d.ts +59 -0
- package/dist/styles/authoring.d.ts.map +1 -0
- package/dist/styles/authoring.js +155 -0
- package/dist/styles/authoring.js.map +1 -0
- package/dist/styles/declarations.d.ts +10 -0
- package/dist/styles/declarations.d.ts.map +1 -0
- package/dist/styles/declarations.js +132 -0
- package/dist/styles/declarations.js.map +1 -0
- package/dist/styles/index.d.ts +7 -0
- package/dist/styles/index.d.ts.map +1 -0
- package/dist/styles/index.js +12 -0
- package/dist/styles/index.js.map +1 -0
- package/dist/styles/module.d.ts +5 -0
- package/dist/styles/module.d.ts.map +1 -0
- package/dist/styles/module.js +229 -0
- package/dist/styles/module.js.map +1 -0
- package/dist/styles/registry.d.ts +48 -0
- package/dist/styles/registry.d.ts.map +1 -0
- package/dist/styles/registry.js +182 -0
- package/dist/styles/registry.js.map +1 -0
- package/dist/styles/types.d.ts +211 -0
- package/dist/styles/types.d.ts.map +1 -0
- package/dist/styles/types.js +8 -0
- package/dist/styles/types.js.map +1 -0
- package/dist/testing.d.ts +10 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +31 -0
- package/dist/testing.js.map +1 -0
- package/dist/theme.d.ts +85 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +240 -0
- package/dist/theme.js.map +1 -0
- package/dist/tokens/contextual_var.d.ts +35 -0
- package/dist/tokens/contextual_var.d.ts.map +1 -0
- package/dist/tokens/contextual_var.js +33 -0
- package/dist/tokens/contextual_var.js.map +1 -0
- package/dist/tokens/index.d.ts +5 -0
- package/dist/tokens/index.d.ts.map +1 -0
- package/dist/tokens/index.js +11 -0
- package/dist/tokens/index.js.map +1 -0
- package/dist/tokens/kind.d.ts +2 -0
- package/dist/tokens/kind.d.ts.map +1 -0
- package/dist/tokens/kind.js +10 -0
- package/dist/tokens/kind.js.map +1 -0
- package/dist/tokens/light_dark.d.ts +20 -0
- package/dist/tokens/light_dark.d.ts.map +1 -0
- package/dist/tokens/light_dark.js +37 -0
- package/dist/tokens/light_dark.js.map +1 -0
- package/dist/tokens/scale_token.d.ts +20 -0
- package/dist/tokens/scale_token.d.ts.map +1 -0
- package/dist/tokens/scale_token.js +23 -0
- package/dist/tokens/scale_token.js.map +1 -0
- package/dist/tokens/theme_token.d.ts +20 -0
- package/dist/tokens/theme_token.d.ts.map +1 -0
- package/dist/tokens/theme_token.js +23 -0
- package/dist/tokens/theme_token.js.map +1 -0
- package/dist/var_invariant.d.ts +25 -0
- package/dist/var_invariant.d.ts.map +1 -0
- package/dist/var_invariant.js +108 -0
- package/dist/var_invariant.js.map +1 -0
- package/docs/concepts/authoring.md +115 -0
- package/docs/concepts/collection.md +66 -0
- package/docs/concepts/distillery.md +47 -0
- package/docs/concepts/index.md +18 -0
- package/docs/concepts/naming-and-output.md +123 -0
- package/docs/concepts/ordering.md +61 -0
- package/docs/concepts/single-copy.md +103 -0
- package/docs/concepts/tokens.md +99 -0
- package/docs/docset.yml +53 -0
- package/docs/examples/01-stylesheet.ts +20 -0
- package/docs/examples/02-artifact.ts +26 -0
- package/docs/examples/03-variants.ts +40 -0
- package/docs/examples/04-emotion.ts +33 -0
- package/docs/examples/05-var-invariant.ts +31 -0
- package/docs/examples/06-payload.ts +85 -0
- package/docs/examples/fixture.ts +22 -0
- package/docs/getting-started/index.md +14 -0
- package/docs/getting-started/installation.md +30 -0
- package/docs/getting-started/quick-start.md +61 -0
- package/docs/getting-started/your-first-stylesheet.md +57 -0
- package/docs/guides/compact-artifacts.md +87 -0
- package/docs/guides/emotion-migration.md +60 -0
- package/docs/guides/index.md +17 -0
- package/docs/guides/name-collisions.md +37 -0
- package/docs/guides/non-css-surfaces.md +73 -0
- package/docs/guides/react-renderer.md +158 -0
- package/docs/guides/theming.md +107 -0
- package/docs/guides/var-invariant.md +24 -0
- package/docs/guides/vs-emotion.md +61 -0
- package/docs/index.md +73 -0
- package/docs/logo.svg +7 -0
- package/docs/playground/index.html +12 -0
- package/docs/playground/package.json +23 -0
- package/docs/playground/src/app/app.tsx +109 -0
- package/docs/playground/src/app/css_panel.tsx +119 -0
- package/docs/playground/src/app/editor_panel.tsx +87 -0
- package/docs/playground/src/app/index.ts +8 -0
- package/docs/playground/src/app/monaco_css_editor.tsx +84 -0
- package/docs/playground/src/app/monaco_source_editor.tsx +132 -0
- package/docs/playground/src/app/preview_panel.tsx +99 -0
- package/docs/playground/src/app/tokens_panel.tsx +117 -0
- package/docs/playground/src/app/types.ts +10 -0
- package/docs/playground/src/examples/snippets.test.ts +28 -0
- package/docs/playground/src/examples/snippets.ts +418 -0
- package/docs/playground/src/lib/compile.test.ts +157 -0
- package/docs/playground/src/lib/compile.ts +242 -0
- package/docs/playground/src/lib/demo_environment.test.ts +123 -0
- package/docs/playground/src/lib/demo_environment.ts +140 -0
- package/docs/playground/src/lib/editor_lib.test.ts +39 -0
- package/docs/playground/src/lib/editor_lib.ts +142 -0
- package/docs/playground/src/lib/format_css.test.ts +41 -0
- package/docs/playground/src/lib/format_css.ts +71 -0
- package/docs/playground/src/main.tsx +25 -0
- package/docs/playground/src/setup/chrome.test.ts +47 -0
- package/docs/playground/src/setup/chrome.ts +365 -0
- package/docs/playground/src/setup/monaco_env.ts +64 -0
- package/docs/playground/tsconfig.json +22 -0
- package/docs/playground/vite.config.ts +37 -0
- package/docs/playground/vitest.config.ts +35 -0
- package/docs/playground.md +28 -0
- package/docs/reference/api/emotion.md +372 -0
- package/docs/reference/api/index-1.md +2180 -0
- package/docs/reference/api/index.md +9 -0
- package/docs/reference/api/testing.md +92 -0
- package/docs/reference/api.md +12 -0
- package/docs/reference/entry-points.md +125 -0
- package/docs/reference/environment.md +60 -0
- package/docs/reference/index.md +11 -0
- package/docs/reference/okf-map.md +92 -0
- package/package.json +127 -4
- package/src/collector.ts +526 -0
- package/src/css_scan.ts +263 -0
- package/src/dom_sink.ts +65 -0
- package/src/emotion.ts +311 -0
- package/src/engine.ts +191 -0
- package/src/environment.ts +56 -0
- package/src/hash.ts +111 -0
- package/src/idents.ts +21 -0
- package/src/index.ts +93 -0
- package/src/instance.ts +49 -0
- package/src/local_vars.ts +220 -0
- package/src/minify.ts +87 -0
- package/src/names.ts +129 -0
- package/src/nesting.ts +596 -0
- package/src/runtime.ts +428 -0
- package/src/styles/authoring.ts +244 -0
- package/src/styles/declarations.ts +172 -0
- package/src/styles/index.ts +58 -0
- package/src/styles/module.ts +396 -0
- package/src/styles/registry.ts +261 -0
- package/src/styles/types.ts +283 -0
- package/src/testing.ts +48 -0
- package/src/theme.ts +454 -0
- package/src/tokens/contextual_var.ts +72 -0
- package/src/tokens/index.ts +17 -0
- package/src/tokens/kind.ts +13 -0
- package/src/tokens/light_dark.ts +58 -0
- package/src/tokens/scale_token.ts +41 -0
- package/src/tokens/theme_token.ts +42 -0
- package/src/var_invariant.ts +147 -0
package/src/runtime.ts
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
3
|
+
* or more contributor license agreements. Licensed under the Elastic License
|
|
4
|
+
* 2.0; you may not use this file except in compliance with the Elastic License
|
|
5
|
+
* 2.0.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { StylesCollector } from './collector';
|
|
9
|
+
import { isBlankCss, isOpaque, scanCss } from './css_scan';
|
|
10
|
+
import type { DistilleryEnvironment, ThemeVarDefinition } from './environment';
|
|
11
|
+
import {
|
|
12
|
+
isLocalVarDefaultMarker,
|
|
13
|
+
isLocalVarOverrideMarker,
|
|
14
|
+
type LocalVarDefaultMarker,
|
|
15
|
+
type LocalVarOverrideMarker,
|
|
16
|
+
} from './local_vars';
|
|
17
|
+
import { minifyCss } from './minify';
|
|
18
|
+
import { cssVarName, type StyleNameResolver } from './names';
|
|
19
|
+
import type {
|
|
20
|
+
Declarations,
|
|
21
|
+
DeclarationSegment,
|
|
22
|
+
StyleHandle,
|
|
23
|
+
StyleRule,
|
|
24
|
+
StyleSelectorResolver,
|
|
25
|
+
} from './styles';
|
|
26
|
+
import {
|
|
27
|
+
requireThemeVariation,
|
|
28
|
+
type ResolvedThemeVariation,
|
|
29
|
+
serializedThemeValue,
|
|
30
|
+
} from './theme';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Emits collected CSS: theme block, then entries, minified.
|
|
34
|
+
*
|
|
35
|
+
* @param environment Theme vars, prefix, and scope for this render.
|
|
36
|
+
* @param collector Reachable entries and deps.
|
|
37
|
+
* @param resolver Defaults to `collector.createResolver()`.
|
|
38
|
+
*/
|
|
39
|
+
export const renderStyles = (
|
|
40
|
+
environment: DistilleryEnvironment<unknown>,
|
|
41
|
+
collector: StylesCollector,
|
|
42
|
+
resolver: StyleNameResolver = collector.createResolver(),
|
|
43
|
+
options: RenderStylesOptions = {}
|
|
44
|
+
): string => {
|
|
45
|
+
const ctx: RenderContext = { environment, collector, resolver, options };
|
|
46
|
+
const bodyFragments = collector.collectedEntries.map((entry) => {
|
|
47
|
+
if (entry.kind === 'handle') {
|
|
48
|
+
return renderHandle(entry, ctx);
|
|
49
|
+
}
|
|
50
|
+
if (entry.kind === 'rule') {
|
|
51
|
+
return renderRule(entry, ctx);
|
|
52
|
+
}
|
|
53
|
+
const inner = entry.rules
|
|
54
|
+
.map((rule) => renderRule(rule, ctx))
|
|
55
|
+
.filter((fragment) => fragment.length > 0);
|
|
56
|
+
return inner.length > 0
|
|
57
|
+
? `@${entry.atRule ?? 'media'} ${entry.query}{${inner.join('')}}`
|
|
58
|
+
: '';
|
|
59
|
+
});
|
|
60
|
+
const bodyCss = bodyFragments.join('');
|
|
61
|
+
const fragments = [renderThemeVars(ctx), bodyCss];
|
|
62
|
+
|
|
63
|
+
return minifyCss(fragments.join(''));
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/** Per-render variation selection, scheme flatten, alternate blocks, and value overrides. */
|
|
67
|
+
export interface RenderStylesOptions {
|
|
68
|
+
/** Flatten this declared variation into `themeScope`. Default is the base. A media variation does not replace the primary block; it wraps its diffs in `@media`. */
|
|
69
|
+
flatten?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Emit one scheme's literal instead of `light-dark(...)`.
|
|
72
|
+
*
|
|
73
|
+
* For a target with no color scheme to resolve the function against — an image or PDF backend, email HTML, an older browser.
|
|
74
|
+
*/
|
|
75
|
+
scheme?: 'light' | 'dark';
|
|
76
|
+
/** Extra blocks for runtime switching. Each entry emits only the variation's diff. */
|
|
77
|
+
alternates?: readonly ThemeAlternate[];
|
|
78
|
+
/** Override a theme token's emitted value. */
|
|
79
|
+
themeValueOverrides?: Partial<Record<string, string>>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** One runtime-switched variation. `selector` is required unless the variation declares `media`. */
|
|
83
|
+
export interface ThemeAlternate {
|
|
84
|
+
/** Name passed in `DistilleryOptions.variations`. */
|
|
85
|
+
readonly variation: string;
|
|
86
|
+
/** Consuming page selector, composed with `themeScope`. */
|
|
87
|
+
readonly selector?: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface RenderContext {
|
|
91
|
+
/** Environment supplying theme vars, prefix, and scope. */
|
|
92
|
+
environment: DistilleryEnvironment<unknown>;
|
|
93
|
+
/** Reachable entries and deps for this render. */
|
|
94
|
+
collector: StylesCollector;
|
|
95
|
+
/** Class and CSS-var name resolver for this render. */
|
|
96
|
+
resolver: StyleNameResolver;
|
|
97
|
+
/** Per-render theme value overrides. */
|
|
98
|
+
options: RenderStylesOptions;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const renderThemeVars = (ctx: RenderContext): string => {
|
|
102
|
+
const { environment, options } = ctx;
|
|
103
|
+
const selected = options.flatten
|
|
104
|
+
? themeVariation(environment, options.flatten)
|
|
105
|
+
: undefined;
|
|
106
|
+
const primaryVars =
|
|
107
|
+
selected && !selected.media ? selected.themeVars : environment.themeVars;
|
|
108
|
+
const blocks = [renderVarBlock(ctx, environment.themeScope, primaryVars)];
|
|
109
|
+
if (selected?.media) {
|
|
110
|
+
blocks.push(
|
|
111
|
+
wrapMedia(
|
|
112
|
+
selected.media,
|
|
113
|
+
renderVarBlock(ctx, environment.themeScope, selected.diffs)
|
|
114
|
+
)
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
for (const alternate of options.alternates ?? []) {
|
|
118
|
+
blocks.push(renderAlternate(ctx, alternate));
|
|
119
|
+
}
|
|
120
|
+
return blocks.join('');
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const renderAlternate = (
|
|
124
|
+
ctx: RenderContext,
|
|
125
|
+
alternate: ThemeAlternate
|
|
126
|
+
): string => {
|
|
127
|
+
const resolved = themeVariation(ctx.environment, alternate.variation);
|
|
128
|
+
const selector = alternate.selector
|
|
129
|
+
? composeThemeSelector(ctx.environment.themeScope, alternate.selector)
|
|
130
|
+
: resolved.media
|
|
131
|
+
? ctx.environment.themeScope
|
|
132
|
+
: undefined;
|
|
133
|
+
if (!selector) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`Alternate variation "${alternate.variation}" needs a selector (media-conditioned variations may omit one).`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
const block = renderVarBlock(ctx, selector, resolved.diffs);
|
|
139
|
+
return resolved.media ? wrapMedia(resolved.media, block) : block;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const themeVariation = (
|
|
143
|
+
environment: DistilleryEnvironment<unknown>,
|
|
144
|
+
name: string
|
|
145
|
+
): ResolvedThemeVariation =>
|
|
146
|
+
requireThemeVariation(environment.variations, name);
|
|
147
|
+
|
|
148
|
+
const renderVarBlock = (
|
|
149
|
+
ctx: RenderContext,
|
|
150
|
+
selector: string,
|
|
151
|
+
vars: Readonly<Record<string, ThemeVarDefinition>>
|
|
152
|
+
): string => {
|
|
153
|
+
const declarations = [...ctx.collector.collectedThemeDeps]
|
|
154
|
+
.sort()
|
|
155
|
+
.flatMap((path) => {
|
|
156
|
+
const definition = vars[path];
|
|
157
|
+
if (!definition) {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
return [
|
|
161
|
+
`${ctx.resolver.cssVar(path)}:${formatThemeValue(
|
|
162
|
+
definition,
|
|
163
|
+
ctx.options.themeValueOverrides?.[path],
|
|
164
|
+
ctx.options.scheme
|
|
165
|
+
)}`,
|
|
166
|
+
];
|
|
167
|
+
});
|
|
168
|
+
return declarations.length > 0
|
|
169
|
+
? `${selector}{${declarations.join(';')}}`
|
|
170
|
+
: '';
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const wrapMedia = (query: string, block: string): string =>
|
|
174
|
+
block.length > 0 ? `@media ${query}{${block}}` : '';
|
|
175
|
+
|
|
176
|
+
/** Composes `themeScope` with a per-render alternate selector. */
|
|
177
|
+
export const composeThemeSelector = (
|
|
178
|
+
themeScope: string,
|
|
179
|
+
selector: string
|
|
180
|
+
): string => {
|
|
181
|
+
const scope = themeScope.trim();
|
|
182
|
+
const extra = selector.trim();
|
|
183
|
+
if (extra.length === 0) {
|
|
184
|
+
throw new Error('Alternate selector must be non-empty.');
|
|
185
|
+
}
|
|
186
|
+
if (scope === ':host') {
|
|
187
|
+
return extra.startsWith(':host') ? extra : `:host(${extra})`;
|
|
188
|
+
}
|
|
189
|
+
if (/^[.#[:]/.test(extra)) {
|
|
190
|
+
return `${scope}${extra}`;
|
|
191
|
+
}
|
|
192
|
+
return `${scope} ${extra}`;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const formatThemeValue = (
|
|
196
|
+
definition: ThemeVarDefinition,
|
|
197
|
+
override: string | undefined,
|
|
198
|
+
scheme: 'light' | 'dark' | undefined
|
|
199
|
+
): string =>
|
|
200
|
+
override ?? (scheme ? definition[scheme] : serializedThemeValue(definition));
|
|
201
|
+
|
|
202
|
+
const renderHandle = (handle: StyleHandle, ctx: RenderContext): string => {
|
|
203
|
+
const body = renderDeclarations(handle.declarations, { handle }, ctx);
|
|
204
|
+
if (isBlankCss(body)) {
|
|
205
|
+
return '';
|
|
206
|
+
}
|
|
207
|
+
const className = ctx.resolver.className(handle.key, handle.readableName);
|
|
208
|
+
return `.${className}{${body}}`;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const renderRule = (rule: StyleRule, ctx: RenderContext): string => {
|
|
212
|
+
// Rules don't have a host handle for per-handle reachability — default
|
|
213
|
+
// markers in a rule's declaration emit every listed key. In practice
|
|
214
|
+
// authors place default markers on handle declarations; this branch keeps
|
|
215
|
+
// the runtime well-defined if a rule ever does carry one.
|
|
216
|
+
const body = renderDeclarations(rule.declarations, {}, ctx);
|
|
217
|
+
if (isBlankCss(body)) {
|
|
218
|
+
return '';
|
|
219
|
+
}
|
|
220
|
+
const selector = rule.selector(createSelectorResolver(rule, ctx));
|
|
221
|
+
return `${selector}{${body}}`;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/** Host for default-marker emission: a handle enables per-handle reachability. */
|
|
225
|
+
interface DeclarationHostContext {
|
|
226
|
+
/** Host handle whose refs narrow default-marker keys. Omitted for rules. */
|
|
227
|
+
handle?: StyleHandle;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const renderDeclarations = (
|
|
231
|
+
declarations: Declarations,
|
|
232
|
+
host: DeclarationHostContext,
|
|
233
|
+
ctx: RenderContext
|
|
234
|
+
): string => {
|
|
235
|
+
const out: string[] = [];
|
|
236
|
+
for (const segment of declarations.css) {
|
|
237
|
+
out.push(renderSegment(segment, host, ctx));
|
|
238
|
+
}
|
|
239
|
+
return out.join('');
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const renderSegment = (
|
|
243
|
+
segment: DeclarationSegment,
|
|
244
|
+
host: DeclarationHostContext,
|
|
245
|
+
ctx: RenderContext
|
|
246
|
+
): string => {
|
|
247
|
+
if (typeof segment === 'string') {
|
|
248
|
+
return resolveStringSegment(segment, ctx);
|
|
249
|
+
}
|
|
250
|
+
if (isLocalVarDefaultMarker(segment)) {
|
|
251
|
+
return renderDefaultMarker(segment, host, ctx);
|
|
252
|
+
}
|
|
253
|
+
if (isLocalVarOverrideMarker(segment)) {
|
|
254
|
+
return renderOverrideMarker(segment, ctx);
|
|
255
|
+
}
|
|
256
|
+
return '';
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const renderDefaultMarker = (
|
|
260
|
+
marker: LocalVarDefaultMarker,
|
|
261
|
+
host: DeclarationHostContext,
|
|
262
|
+
ctx: RenderContext
|
|
263
|
+
): string => {
|
|
264
|
+
const reachable = host.handle
|
|
265
|
+
? ctx.collector.reachableDefaults(host.handle, marker.groupPath)
|
|
266
|
+
: null;
|
|
267
|
+
const declarations: string[] = [];
|
|
268
|
+
for (const { key, path, value } of marker.defaults) {
|
|
269
|
+
if (reachable && !reachable.has(key)) {
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
const stringified = stringifyMarkerValue(value);
|
|
273
|
+
const resolvedValue = resolveStringSegment(stringified, ctx);
|
|
274
|
+
const propIdentifier = ctx.resolver.cssVar(path);
|
|
275
|
+
declarations.push(`${propIdentifier}:${resolvedValue}`);
|
|
276
|
+
}
|
|
277
|
+
return declarations.length > 0 ? `${declarations.join(';')};` : '';
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const renderOverrideMarker = (
|
|
281
|
+
marker: LocalVarOverrideMarker,
|
|
282
|
+
ctx: RenderContext
|
|
283
|
+
): string => {
|
|
284
|
+
const declarations: string[] = [];
|
|
285
|
+
for (const { path, value } of marker.overrides) {
|
|
286
|
+
const stringified = stringifyMarkerValue(value);
|
|
287
|
+
const resolvedValue = resolveStringSegment(stringified, ctx);
|
|
288
|
+
const propIdentifier = ctx.resolver.cssVar(path);
|
|
289
|
+
declarations.push(`${propIdentifier}:${resolvedValue}`);
|
|
290
|
+
}
|
|
291
|
+
return declarations.length > 0 ? `${declarations.join(';')};` : '';
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const stringifyMarkerValue = (value: unknown): string => {
|
|
295
|
+
if (typeof value === 'string') {
|
|
296
|
+
return value;
|
|
297
|
+
}
|
|
298
|
+
if (typeof value === 'number') {
|
|
299
|
+
return String(value);
|
|
300
|
+
}
|
|
301
|
+
if (
|
|
302
|
+
value !== null &&
|
|
303
|
+
typeof value === 'object' &&
|
|
304
|
+
typeof (value as { toString?: () => string }).toString === 'function' &&
|
|
305
|
+
(value as { toString: () => string }).toString !== Object.prototype.toString
|
|
306
|
+
) {
|
|
307
|
+
return (value as { toString: () => string }).toString();
|
|
308
|
+
}
|
|
309
|
+
throw new Error(
|
|
310
|
+
`t.vars(...) value must be a string, number, theme token, contextual var, scale token, or local var ref; received ${describeValue(value)}.`
|
|
311
|
+
);
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const describeValue = (value: unknown): string => {
|
|
315
|
+
if (value === null) {
|
|
316
|
+
return 'null';
|
|
317
|
+
}
|
|
318
|
+
if (value === undefined) {
|
|
319
|
+
return 'undefined';
|
|
320
|
+
}
|
|
321
|
+
if (typeof value === 'object') {
|
|
322
|
+
return '[object Object]';
|
|
323
|
+
}
|
|
324
|
+
return `${typeof value}`;
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const createSelectorResolver = (
|
|
328
|
+
rule: StyleRule,
|
|
329
|
+
ctx: RenderContext
|
|
330
|
+
): StyleSelectorResolver => {
|
|
331
|
+
const { resolver } = ctx;
|
|
332
|
+
const selectorResolver = ((handle: StyleHandle) =>
|
|
333
|
+
resolver.className(
|
|
334
|
+
handle.key,
|
|
335
|
+
handle.readableName
|
|
336
|
+
)) as StyleSelectorResolver;
|
|
337
|
+
const module = ctx.collector.registry.module(rule.moduleName);
|
|
338
|
+
for (const handle of module?.handleList ?? []) {
|
|
339
|
+
defineSelectorAlias(selectorResolver, handle.localName, handle, resolver);
|
|
340
|
+
const leafName = handle.localName.split('/').at(-1);
|
|
341
|
+
if (leafName && leafName !== handle.localName) {
|
|
342
|
+
defineSelectorAlias(selectorResolver, leafName, handle, resolver);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return selectorResolver;
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
const defineSelectorAlias = (
|
|
349
|
+
selectorResolver: StyleSelectorResolver,
|
|
350
|
+
name: string,
|
|
351
|
+
handle: StyleHandle,
|
|
352
|
+
resolver: StyleNameResolver
|
|
353
|
+
): void => {
|
|
354
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(name) || name in selectorResolver) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
Object.defineProperty(selectorResolver, name, {
|
|
358
|
+
configurable: true,
|
|
359
|
+
enumerable: true,
|
|
360
|
+
get: () => `.${resolver.className(handle.key, handle.readableName)}`,
|
|
361
|
+
});
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
const resolveStringSegment = (cssText: string, ctx: RenderContext): string => {
|
|
365
|
+
return scanCss(cssText)
|
|
366
|
+
.map((span) =>
|
|
367
|
+
isOpaque(span) ? span.text : resolveCodeSpan(span.text, ctx)
|
|
368
|
+
)
|
|
369
|
+
.join('');
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
const resolveCodeSpan = (cssText: string, ctx: RenderContext): string => {
|
|
373
|
+
let result = cssText;
|
|
374
|
+
const paths = new Set<string>([
|
|
375
|
+
...Object.keys(ctx.environment.themeVars),
|
|
376
|
+
...(ctx.environment.sharedVars ?? []),
|
|
377
|
+
...ctx.collector.collectedVarDeps,
|
|
378
|
+
]);
|
|
379
|
+
for (const path of paths) {
|
|
380
|
+
result = substituteReadableVar(result, path, ctx);
|
|
381
|
+
}
|
|
382
|
+
return result;
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const substituteReadableVar = (
|
|
386
|
+
cssText: string,
|
|
387
|
+
path: string,
|
|
388
|
+
ctx: RenderContext
|
|
389
|
+
): string => {
|
|
390
|
+
const readableName = cssVarName(ctx.environment.prefix, path);
|
|
391
|
+
const readableRef = `var(${readableName})`;
|
|
392
|
+
let result = cssText;
|
|
393
|
+
if (result.includes(readableRef)) {
|
|
394
|
+
result = replaceAll(result, readableRef, ctx.resolver.cssVarRef(path));
|
|
395
|
+
}
|
|
396
|
+
if (containsCssIdentifier(result, readableName)) {
|
|
397
|
+
result = replaceCssIdentifier(
|
|
398
|
+
result,
|
|
399
|
+
readableName,
|
|
400
|
+
ctx.resolver.cssVar(path)
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
return result;
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
const replaceAll = (
|
|
407
|
+
value: string,
|
|
408
|
+
search: string,
|
|
409
|
+
replacement: string
|
|
410
|
+
): string => value.split(search).join(replacement);
|
|
411
|
+
|
|
412
|
+
const replaceCssIdentifier = (
|
|
413
|
+
value: string,
|
|
414
|
+
search: string,
|
|
415
|
+
replacement: string
|
|
416
|
+
): string =>
|
|
417
|
+
// Authored and generated CSS only contains valid custom property identifiers.
|
|
418
|
+
// Since every searched token starts with "--", the trailing boundary is enough.
|
|
419
|
+
value.replace(
|
|
420
|
+
new RegExp(`${escapeRegExp(search)}(?![_a-zA-Z0-9-])`, 'g'),
|
|
421
|
+
replacement
|
|
422
|
+
);
|
|
423
|
+
|
|
424
|
+
const containsCssIdentifier = (value: string, search: string): boolean =>
|
|
425
|
+
new RegExp(`${escapeRegExp(search)}(?![_a-zA-Z0-9-])`).test(value);
|
|
426
|
+
|
|
427
|
+
const escapeRegExp = (value: string): string =>
|
|
428
|
+
value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
3
|
+
* or more contributor license agreements. Licensed under the Elastic License
|
|
4
|
+
* 2.0; you may not use this file except in compliance with the Elastic License
|
|
5
|
+
* 2.0.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
type FlattenedTemplate,
|
|
10
|
+
flattenTemplate,
|
|
11
|
+
hasNestedSyntax,
|
|
12
|
+
type SelectorAlternative,
|
|
13
|
+
} from '../nesting';
|
|
14
|
+
|
|
15
|
+
import { buildDeclarations } from './declarations';
|
|
16
|
+
import type {
|
|
17
|
+
Declarations,
|
|
18
|
+
PendingStyleHandle,
|
|
19
|
+
RuleOptions,
|
|
20
|
+
StyleHandle,
|
|
21
|
+
StyleMedia,
|
|
22
|
+
StyleRule,
|
|
23
|
+
StyleSelectorResolver,
|
|
24
|
+
StylesObject,
|
|
25
|
+
} from './types';
|
|
26
|
+
|
|
27
|
+
/** Shared empty `dependsOn` until module construction fills the real set. */
|
|
28
|
+
export const EMPTY_DEPS: ReadonlySet<string> = new Set();
|
|
29
|
+
|
|
30
|
+
/** Declaration-block template. Interpolations stringify; local-var markers stay until render. */
|
|
31
|
+
export const decls = (
|
|
32
|
+
strings: TemplateStringsArray,
|
|
33
|
+
...values: readonly unknown[]
|
|
34
|
+
): Declarations => buildDeclarations(strings, values);
|
|
35
|
+
|
|
36
|
+
/** Handle template. Nested `&` / `@media` flatten into sibling rules. */
|
|
37
|
+
export const css = (
|
|
38
|
+
strings: TemplateStringsArray,
|
|
39
|
+
...values: readonly unknown[]
|
|
40
|
+
): PendingStyleHandle => {
|
|
41
|
+
if (!hasNestedSyntax(strings)) {
|
|
42
|
+
return {
|
|
43
|
+
kind: 'pending-handle',
|
|
44
|
+
declarations: buildDeclarations(strings, values),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return pendingHandleFromFlattened(
|
|
48
|
+
flattenTemplate(strings, values, { mode: 'self' })
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** Builds a pending handle (plus nested sibling descriptors) from a flattened template. */
|
|
53
|
+
export const pendingHandleFromFlattened = (
|
|
54
|
+
flat: FlattenedTemplate
|
|
55
|
+
): PendingStyleHandle => {
|
|
56
|
+
const selfSlice = flat.self ?? { strings: [''], values: [] };
|
|
57
|
+
return {
|
|
58
|
+
kind: 'pending-handle',
|
|
59
|
+
declarations: buildDeclarations(selfSlice.strings, selfSlice.values),
|
|
60
|
+
nested: flat.nested.map((entry) => {
|
|
61
|
+
if (entry.kind === 'rule') {
|
|
62
|
+
return {
|
|
63
|
+
kind: 'nested-rule',
|
|
64
|
+
alternatives: entry.alternatives,
|
|
65
|
+
declarations: buildDeclarations(
|
|
66
|
+
entry.slice.strings,
|
|
67
|
+
entry.slice.values
|
|
68
|
+
),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
kind: 'nested-media',
|
|
73
|
+
query: entry.query,
|
|
74
|
+
...(entry.self
|
|
75
|
+
? { self: buildDeclarations(entry.self.strings, entry.self.values) }
|
|
76
|
+
: {}),
|
|
77
|
+
rules: entry.rules.map((rule) => ({
|
|
78
|
+
kind: 'nested-rule',
|
|
79
|
+
alternatives: rule.alternatives,
|
|
80
|
+
declarations: buildDeclarations(
|
|
81
|
+
rule.slice.strings,
|
|
82
|
+
rule.slice.values
|
|
83
|
+
),
|
|
84
|
+
})),
|
|
85
|
+
};
|
|
86
|
+
}),
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Selector plus declarations. `dependsOn` is filled when the module is constructed.
|
|
92
|
+
*
|
|
93
|
+
* @param selector Factory receiving a {@link StyleSelectorResolver}; uses `&` and handle aliases.
|
|
94
|
+
* @param declarations CSS properties for this rule.
|
|
95
|
+
* @param options `auto` controls whether the rule self-collects when its handle dependencies are met.
|
|
96
|
+
*/
|
|
97
|
+
export const rule = (
|
|
98
|
+
selector: (h: StyleSelectorResolver) => string,
|
|
99
|
+
declarations: Declarations,
|
|
100
|
+
options: RuleOptions = {}
|
|
101
|
+
): StyleRule => ({
|
|
102
|
+
kind: 'rule',
|
|
103
|
+
moduleName: '',
|
|
104
|
+
key: '',
|
|
105
|
+
selector,
|
|
106
|
+
declarations,
|
|
107
|
+
// `dependsOn` is computed in `assignEntries` once the module's handles are
|
|
108
|
+
// known. Authors construct rules outside that scope, so the placeholder is
|
|
109
|
+
// an empty set until `assignEntries` rewrites the entry.
|
|
110
|
+
dependsOn: EMPTY_DEPS,
|
|
111
|
+
auto: options.auto ?? true,
|
|
112
|
+
variant: false,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* `@media` block wrapping rules.
|
|
117
|
+
*
|
|
118
|
+
* @param query Media query string (e.g. `(min-width: 600px)`).
|
|
119
|
+
* @param rules Inner rules scoped to this block.
|
|
120
|
+
*/
|
|
121
|
+
export const media = (
|
|
122
|
+
query: string,
|
|
123
|
+
rules: readonly StyleRule[]
|
|
124
|
+
): StyleMedia => ({
|
|
125
|
+
kind: 'media',
|
|
126
|
+
atRule: 'media',
|
|
127
|
+
key: '',
|
|
128
|
+
moduleName: '',
|
|
129
|
+
query,
|
|
130
|
+
rules,
|
|
131
|
+
variant: false,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* `@container` block. `kind` stays `'media'` so emission rank matches {@link media}.
|
|
136
|
+
*
|
|
137
|
+
* @param query Container query string (e.g. `(min-width: 400px)`).
|
|
138
|
+
* @param rules Inner rules scoped to this block.
|
|
139
|
+
*/
|
|
140
|
+
export const container = (
|
|
141
|
+
query: string,
|
|
142
|
+
rules: readonly StyleRule[]
|
|
143
|
+
): StyleMedia => ({
|
|
144
|
+
kind: 'media',
|
|
145
|
+
atRule: 'container',
|
|
146
|
+
key: '',
|
|
147
|
+
moduleName: '',
|
|
148
|
+
query,
|
|
149
|
+
rules,
|
|
150
|
+
variant: false,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const variantMarkers = new WeakSet<object>();
|
|
154
|
+
|
|
155
|
+
export const isVariantMarked = (value: unknown): boolean =>
|
|
156
|
+
Boolean(value && typeof value === 'object' && variantMarkers.has(value));
|
|
157
|
+
|
|
158
|
+
const markVariant = (value: unknown): void => {
|
|
159
|
+
if (!value || typeof value !== 'object') {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
variantMarkers.add(value);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Builds a record keyed by `domain`. No CSS-collection side effect.
|
|
167
|
+
*
|
|
168
|
+
* @param domain All valid keys (e.g. `['primary', 'secondary']`).
|
|
169
|
+
* @param factory Called once per key.
|
|
170
|
+
*/
|
|
171
|
+
export const mapDomain = <TKey extends string, TValue>(
|
|
172
|
+
domain: readonly TKey[],
|
|
173
|
+
factory: (value: TKey) => TValue
|
|
174
|
+
): Record<TKey, TValue> =>
|
|
175
|
+
Object.fromEntries(domain.map((key) => [key, factory(key)])) as Record<
|
|
176
|
+
TKey,
|
|
177
|
+
TValue
|
|
178
|
+
>;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Builds a record of styles keyed by `domain`. Each value is marked `variant` so {@link index.StylesCollector#use | StylesCollector.use} skips it.
|
|
182
|
+
*
|
|
183
|
+
* @param domain All valid variant keys (e.g. `['primary', 'secondary']`).
|
|
184
|
+
* @param factory Called once per key; returns the handle or nested style object for that variant.
|
|
185
|
+
*/
|
|
186
|
+
export const variants = <TKey extends string, TValue>(
|
|
187
|
+
domain: readonly TKey[],
|
|
188
|
+
factory: (value: TKey) => TValue
|
|
189
|
+
): Record<TKey, TValue> => {
|
|
190
|
+
const record = mapDomain(domain, factory);
|
|
191
|
+
for (const value of Object.values(record)) {
|
|
192
|
+
markVariant(value);
|
|
193
|
+
}
|
|
194
|
+
return record;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Resolves handles through the collector's class-name resolver.
|
|
199
|
+
*
|
|
200
|
+
* @param context Object exposing `resolveClassName` (e.g. a React render context).
|
|
201
|
+
* @param handles One or more handles to resolve and join.
|
|
202
|
+
*/
|
|
203
|
+
export const combineClassNames = (
|
|
204
|
+
context: { resolveClassName: (...handles: StyleHandle[]) => string },
|
|
205
|
+
...handles: readonly StyleHandle[]
|
|
206
|
+
): string => context.resolveClassName(...handles);
|
|
207
|
+
|
|
208
|
+
const composeAbsoluteSelector =
|
|
209
|
+
(alternatives: readonly SelectorAlternative[]) =>
|
|
210
|
+
(h: StyleSelectorResolver): string =>
|
|
211
|
+
alternatives
|
|
212
|
+
.map((parts) =>
|
|
213
|
+
parts
|
|
214
|
+
.map((part) => (typeof part === 'string' ? part : `.${h(part)}`))
|
|
215
|
+
.join('')
|
|
216
|
+
)
|
|
217
|
+
.join(',');
|
|
218
|
+
|
|
219
|
+
/** Authored `rule()`/`media()` entries from a global-mode flattened template. */
|
|
220
|
+
export const globalStylesFromFlattened = (
|
|
221
|
+
flat: FlattenedTemplate
|
|
222
|
+
): StylesObject => {
|
|
223
|
+
const styles: Record<string, StyleRule | StyleMedia> = {};
|
|
224
|
+
flat.nested.forEach((entry, index) => {
|
|
225
|
+
const localKey = `g${String(index).padStart(3, '0')}`;
|
|
226
|
+
if (entry.kind === 'rule') {
|
|
227
|
+
styles[localKey] = rule(
|
|
228
|
+
composeAbsoluteSelector(entry.alternatives),
|
|
229
|
+
buildDeclarations(entry.slice.strings, entry.slice.values)
|
|
230
|
+
);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
styles[localKey] = media(
|
|
234
|
+
entry.query,
|
|
235
|
+
entry.rules.map((nested) =>
|
|
236
|
+
rule(
|
|
237
|
+
composeAbsoluteSelector(nested.alternatives),
|
|
238
|
+
buildDeclarations(nested.slice.strings, nested.slice.values)
|
|
239
|
+
)
|
|
240
|
+
)
|
|
241
|
+
);
|
|
242
|
+
});
|
|
243
|
+
return styles;
|
|
244
|
+
};
|