@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
|
@@ -0,0 +1,418 @@
|
|
|
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 { PlaygroundMode } from '../lib/compile';
|
|
9
|
+
|
|
10
|
+
export interface Snippet {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly label: string;
|
|
13
|
+
readonly description: string;
|
|
14
|
+
readonly source: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** One playground example with Emotion and Native sources under a shared id. */
|
|
18
|
+
export interface SnippetCatalogEntry {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly label: string;
|
|
21
|
+
readonly description: string;
|
|
22
|
+
readonly source: Record<PlaygroundMode, string>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const cardEmotion = `// Emotion-style authoring. In scope: css, cx, injectGlobal, cn, tokens.
|
|
26
|
+
|
|
27
|
+
const card = css\`
|
|
28
|
+
display: grid;
|
|
29
|
+
gap: \${tokens.space.s};
|
|
30
|
+
padding: \${tokens.space.l};
|
|
31
|
+
border: 1px solid \${tokens.color.border};
|
|
32
|
+
border-radius: \${tokens.radius.m};
|
|
33
|
+
background: \${tokens.color.surface};
|
|
34
|
+
color: \${tokens.color.text};
|
|
35
|
+
font-family: \${tokens.font.sans};
|
|
36
|
+
|
|
37
|
+
& h3 {
|
|
38
|
+
margin: 0;
|
|
39
|
+
color: \${tokens.color.accent};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&:hover {
|
|
43
|
+
border-color: \${tokens.color.accent};
|
|
44
|
+
}
|
|
45
|
+
\`;
|
|
46
|
+
|
|
47
|
+
return \`
|
|
48
|
+
<article class="\${card}">
|
|
49
|
+
<h3>Distillate</h3>
|
|
50
|
+
<p>Edit the styles on the left and watch the output update.</p>
|
|
51
|
+
</article>
|
|
52
|
+
\`;
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
const cardNative = `// Native distillate module. In scope: createStyleModule, rule, media,
|
|
56
|
+
// container, variants, cn, tokens.
|
|
57
|
+
|
|
58
|
+
const styles = createStyleModule('card', ({ css, tokens }) => ({
|
|
59
|
+
root: css\`
|
|
60
|
+
display: grid;
|
|
61
|
+
gap: \${tokens.space.s};
|
|
62
|
+
padding: \${tokens.space.l};
|
|
63
|
+
border: 1px solid \${tokens.color.border};
|
|
64
|
+
border-radius: \${tokens.radius.m};
|
|
65
|
+
background: \${tokens.color.surface};
|
|
66
|
+
color: \${tokens.color.text};
|
|
67
|
+
font-family: \${tokens.font.sans};
|
|
68
|
+
|
|
69
|
+
& h3 {
|
|
70
|
+
margin: 0;
|
|
71
|
+
color: \${tokens.color.accent};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
&:hover {
|
|
75
|
+
border-color: \${tokens.color.accent};
|
|
76
|
+
}
|
|
77
|
+
\`,
|
|
78
|
+
}));
|
|
79
|
+
|
|
80
|
+
return \`
|
|
81
|
+
<article class="\${cn(styles.handles.root)}">
|
|
82
|
+
<h3>Distillate</h3>
|
|
83
|
+
<p>Edit the module on the left and watch the output update.</p>
|
|
84
|
+
</article>
|
|
85
|
+
\`;
|
|
86
|
+
`;
|
|
87
|
+
|
|
88
|
+
const buttonsEmotion = `// Composition + media + a global reset via injectGlobal.
|
|
89
|
+
|
|
90
|
+
injectGlobal\`
|
|
91
|
+
.demo-shell { margin: 0; display: grid; gap: \${tokens.space.m}; }
|
|
92
|
+
\`;
|
|
93
|
+
|
|
94
|
+
const base = css\`
|
|
95
|
+
padding: \${tokens.space.s} \${tokens.space.m};
|
|
96
|
+
border: 0;
|
|
97
|
+
border-radius: \${tokens.radius.s};
|
|
98
|
+
font-family: \${tokens.font.sans};
|
|
99
|
+
cursor: pointer;
|
|
100
|
+
\`;
|
|
101
|
+
|
|
102
|
+
const primary = css\`
|
|
103
|
+
\${base};
|
|
104
|
+
background: \${tokens.color.accent};
|
|
105
|
+
color: white;
|
|
106
|
+
|
|
107
|
+
@media (min-width: 480px) {
|
|
108
|
+
padding: \${tokens.space.m} \${tokens.space.l};
|
|
109
|
+
}
|
|
110
|
+
\`;
|
|
111
|
+
|
|
112
|
+
const subtle = css\`
|
|
113
|
+
\${base};
|
|
114
|
+
background: \${tokens.color.surface};
|
|
115
|
+
color: \${tokens.color.text};
|
|
116
|
+
border: 1px solid \${tokens.color.border};
|
|
117
|
+
\`;
|
|
118
|
+
|
|
119
|
+
return \`
|
|
120
|
+
<div class="demo-shell">
|
|
121
|
+
<button class="\${cx(primary)}">Primary</button>
|
|
122
|
+
<button class="\${cx(subtle)}">Subtle</button>
|
|
123
|
+
</div>
|
|
124
|
+
\`;
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
const buttonsNative = `// Variants stay off always-on collection; naming a handle includes it.
|
|
128
|
+
|
|
129
|
+
const button = createStyleModule('button', ({ css, tokens }) => ({
|
|
130
|
+
root: css\`
|
|
131
|
+
padding: \${tokens.space.s} \${tokens.space.m};
|
|
132
|
+
border: 0;
|
|
133
|
+
border-radius: \${tokens.radius.s};
|
|
134
|
+
font-family: \${tokens.font.sans};
|
|
135
|
+
cursor: pointer;
|
|
136
|
+
\`,
|
|
137
|
+
tone: variants(['primary', 'subtle'] as const, (tone) =>
|
|
138
|
+
tone === 'primary'
|
|
139
|
+
? css\`
|
|
140
|
+
background: \${tokens.color.accent};
|
|
141
|
+
color: white;
|
|
142
|
+
\`
|
|
143
|
+
: css\`
|
|
144
|
+
background: \${tokens.color.surface};
|
|
145
|
+
color: \${tokens.color.text};
|
|
146
|
+
border: 1px solid \${tokens.color.border};
|
|
147
|
+
\`
|
|
148
|
+
),
|
|
149
|
+
}));
|
|
150
|
+
|
|
151
|
+
return \`
|
|
152
|
+
<div style="display: grid; gap: 12px; justify-items: start;">
|
|
153
|
+
<button class="\${cn(button.handles.root, button.handles.tone.primary)}">Primary</button>
|
|
154
|
+
<button class="\${cn(button.handles.root, button.handles.tone.subtle)}">Subtle</button>
|
|
155
|
+
</div>
|
|
156
|
+
\`;
|
|
157
|
+
`;
|
|
158
|
+
|
|
159
|
+
const shakeEmotion = `// Markup names one handle. The stylesheet still contains the rest.
|
|
160
|
+
|
|
161
|
+
const chip = css\`
|
|
162
|
+
display: inline-flex;
|
|
163
|
+
align-items: center;
|
|
164
|
+
padding: \${tokens.space.s} \${tokens.space.m};
|
|
165
|
+
border-radius: \${tokens.radius.s};
|
|
166
|
+
background: \${tokens.color.surface};
|
|
167
|
+
color: \${tokens.color.text};
|
|
168
|
+
font-family: \${tokens.font.sans};
|
|
169
|
+
\`;
|
|
170
|
+
|
|
171
|
+
const calm = css\`
|
|
172
|
+
\${chip};
|
|
173
|
+
box-shadow: none;
|
|
174
|
+
\`;
|
|
175
|
+
|
|
176
|
+
const loud = css\`
|
|
177
|
+
\${chip};
|
|
178
|
+
box-shadow: 0 0 0 2px \${tokens.color.danger};
|
|
179
|
+
\`;
|
|
180
|
+
|
|
181
|
+
return \`
|
|
182
|
+
<span class="\${cx(calm)}">Calm</span>
|
|
183
|
+
\`;
|
|
184
|
+
`;
|
|
185
|
+
|
|
186
|
+
const shakeNative = `// Markup names one variant. The stylesheet still contains the rest.
|
|
187
|
+
|
|
188
|
+
const chip = createStyleModule('chip', ({ css, tokens, vars }) => {
|
|
189
|
+
const look = vars('look', {
|
|
190
|
+
bg: tokens.color.surface,
|
|
191
|
+
fg: tokens.color.text,
|
|
192
|
+
ring: tokens.color.danger,
|
|
193
|
+
});
|
|
194
|
+
return {
|
|
195
|
+
root: css\`
|
|
196
|
+
\${look}
|
|
197
|
+
display: inline-flex;
|
|
198
|
+
align-items: center;
|
|
199
|
+
padding: \${tokens.space.s} \${tokens.space.m};
|
|
200
|
+
border-radius: \${tokens.radius.s};
|
|
201
|
+
background: \${look.bg};
|
|
202
|
+
color: \${look.fg};
|
|
203
|
+
font-family: \${tokens.font.sans};
|
|
204
|
+
\`,
|
|
205
|
+
tone: variants(['calm', 'loud'] as const, (tone) =>
|
|
206
|
+
tone === 'calm'
|
|
207
|
+
? css\`
|
|
208
|
+
box-shadow: none;
|
|
209
|
+
\`
|
|
210
|
+
: css\`
|
|
211
|
+
\${look}
|
|
212
|
+
box-shadow: 0 0 0 2px \${look.ring};
|
|
213
|
+
\`
|
|
214
|
+
),
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
return \`
|
|
219
|
+
<span class="\${cn(chip.handles.root, chip.handles.tone.calm)}">Calm</span>
|
|
220
|
+
\`;
|
|
221
|
+
`;
|
|
222
|
+
|
|
223
|
+
const varsEmotion = `// Emotion has no vars(); compose a second handle to override.
|
|
224
|
+
|
|
225
|
+
const chip = css\`
|
|
226
|
+
display: inline-block;
|
|
227
|
+
padding: \${tokens.space.s} \${tokens.space.m};
|
|
228
|
+
border-radius: \${tokens.radius.s};
|
|
229
|
+
background: \${tokens.color.surface};
|
|
230
|
+
color: \${tokens.color.text};
|
|
231
|
+
font-family: \${tokens.font.sans};
|
|
232
|
+
\`;
|
|
233
|
+
|
|
234
|
+
const accent = css\`
|
|
235
|
+
\${chip};
|
|
236
|
+
background: \${tokens.color.accent};
|
|
237
|
+
color: #fff;
|
|
238
|
+
\`;
|
|
239
|
+
|
|
240
|
+
return \`
|
|
241
|
+
<div style="display: flex; gap: 8px;">
|
|
242
|
+
<span class="\${cx(chip)}">Default</span>
|
|
243
|
+
<span class="\${cx(accent)}">Accent</span>
|
|
244
|
+
</div>
|
|
245
|
+
\`;
|
|
246
|
+
`;
|
|
247
|
+
|
|
248
|
+
const varsNative = `// Module-local vars. \${look} declares defaults; \${look.bg} reads.
|
|
249
|
+
|
|
250
|
+
const chip = createStyleModule('chip', ({ css, tokens, vars }) => {
|
|
251
|
+
const look = vars('look', {
|
|
252
|
+
bg: tokens.color.surface,
|
|
253
|
+
fg: tokens.color.text,
|
|
254
|
+
});
|
|
255
|
+
return {
|
|
256
|
+
root: css\`
|
|
257
|
+
\${look}
|
|
258
|
+
display: inline-block;
|
|
259
|
+
padding: \${tokens.space.s} \${tokens.space.m};
|
|
260
|
+
border-radius: \${tokens.radius.s};
|
|
261
|
+
background: \${look.bg};
|
|
262
|
+
color: \${look.fg};
|
|
263
|
+
font-family: \${tokens.font.sans};
|
|
264
|
+
\`,
|
|
265
|
+
accent: css\`
|
|
266
|
+
\${look.set({ bg: tokens.color.accent, fg: '#fff' })}
|
|
267
|
+
\`,
|
|
268
|
+
};
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
return \`
|
|
272
|
+
<div style="display: flex; gap: 8px;">
|
|
273
|
+
<span class="\${cn(chip.handles.root)}">Default</span>
|
|
274
|
+
<span class="\${cn(chip.handles.root, chip.handles.accent)}">Accent</span>
|
|
275
|
+
</div>
|
|
276
|
+
\`;
|
|
277
|
+
`;
|
|
278
|
+
|
|
279
|
+
const mediaEmotion = `// Nested @media. @container inside css is rejected; Native uses the factory.
|
|
280
|
+
|
|
281
|
+
const band = css\`
|
|
282
|
+
display: flex;
|
|
283
|
+
gap: \${tokens.space.s};
|
|
284
|
+
padding: \${tokens.space.m};
|
|
285
|
+
background: \${tokens.color.surface};
|
|
286
|
+
color: \${tokens.color.text};
|
|
287
|
+
font-family: \${tokens.font.sans};
|
|
288
|
+
|
|
289
|
+
@media (max-width: 600px) {
|
|
290
|
+
flex-direction: column;
|
|
291
|
+
}
|
|
292
|
+
\`;
|
|
293
|
+
|
|
294
|
+
return \`
|
|
295
|
+
<div class="\${cx(band)}">
|
|
296
|
+
<span>One</span>
|
|
297
|
+
<span>Two</span>
|
|
298
|
+
<span>Three</span>
|
|
299
|
+
</div>
|
|
300
|
+
\`;
|
|
301
|
+
`;
|
|
302
|
+
|
|
303
|
+
const mediaNative = `// media(...) and container(...) factories. @container inside css is rejected.
|
|
304
|
+
|
|
305
|
+
const band = createStyleModule('band', ({ css, decls, tokens }) => ({
|
|
306
|
+
root: css\`
|
|
307
|
+
display: flex;
|
|
308
|
+
gap: \${tokens.space.s};
|
|
309
|
+
padding: \${tokens.space.m};
|
|
310
|
+
background: \${tokens.color.surface};
|
|
311
|
+
color: \${tokens.color.text};
|
|
312
|
+
font-family: \${tokens.font.sans};
|
|
313
|
+
container-type: inline-size;
|
|
314
|
+
\`,
|
|
315
|
+
stacked: media('(max-width: 600px)', [
|
|
316
|
+
rule(
|
|
317
|
+
(h) => \`\${h.root}\`,
|
|
318
|
+
decls\`
|
|
319
|
+
flex-direction: column;
|
|
320
|
+
\`
|
|
321
|
+
),
|
|
322
|
+
]),
|
|
323
|
+
wide: container('(min-width: 400px)', [
|
|
324
|
+
rule(
|
|
325
|
+
(h) => \`\${h.root}\`,
|
|
326
|
+
decls\`
|
|
327
|
+
gap: \${tokens.space.l};
|
|
328
|
+
\`
|
|
329
|
+
),
|
|
330
|
+
]),
|
|
331
|
+
}));
|
|
332
|
+
|
|
333
|
+
return \`
|
|
334
|
+
<div class="\${cn(band.handles.root)}">
|
|
335
|
+
<span>One</span>
|
|
336
|
+
<span>Two</span>
|
|
337
|
+
<span>Three</span>
|
|
338
|
+
</div>
|
|
339
|
+
\`;
|
|
340
|
+
`;
|
|
341
|
+
|
|
342
|
+
const asMode = (entry: SnippetCatalogEntry, mode: PlaygroundMode): Snippet => ({
|
|
343
|
+
id: entry.id,
|
|
344
|
+
label: entry.label,
|
|
345
|
+
description: entry.description,
|
|
346
|
+
source: entry.source[mode],
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
/** Shared dropdown catalog. Switching Emotion vs Native keeps the selected id. */
|
|
350
|
+
export const snippetCatalog: readonly SnippetCatalogEntry[] = [
|
|
351
|
+
{
|
|
352
|
+
id: 'card',
|
|
353
|
+
label: 'Card',
|
|
354
|
+
description: 'Nested selectors, tokens, and a hover state.',
|
|
355
|
+
source: { emotion: cardEmotion, native: cardNative },
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
id: 'buttons',
|
|
359
|
+
label: 'Buttons',
|
|
360
|
+
description: 'Primary and subtle actions.',
|
|
361
|
+
source: { emotion: buttonsEmotion, native: buttonsNative },
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
id: 'tree-shake',
|
|
365
|
+
label: 'Tree shake',
|
|
366
|
+
description:
|
|
367
|
+
'One named style versus the full stylesheet; sizes in the CSS pane.',
|
|
368
|
+
source: { emotion: shakeEmotion, native: shakeNative },
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
id: 'local-vars',
|
|
372
|
+
label: 'Local vars',
|
|
373
|
+
description:
|
|
374
|
+
'Default and accent chips. Native uses vars(); Emotion composes an override.',
|
|
375
|
+
source: { emotion: varsEmotion, native: varsNative },
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
id: 'media',
|
|
379
|
+
label: 'Media + container',
|
|
380
|
+
description:
|
|
381
|
+
'Responsive rules. Native uses the factories; Emotion nests @media.',
|
|
382
|
+
source: { emotion: mediaEmotion, native: mediaNative },
|
|
383
|
+
},
|
|
384
|
+
];
|
|
385
|
+
|
|
386
|
+
export const snippets: Record<PlaygroundMode, readonly Snippet[]> = {
|
|
387
|
+
emotion: snippetCatalog.map((entry) => asMode(entry, 'emotion')),
|
|
388
|
+
native: snippetCatalog.map((entry) => asMode(entry, 'native')),
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
export const defaultSnippetSource = (mode: PlaygroundMode): string =>
|
|
392
|
+
snippets[mode]?.[0]?.source ?? '';
|
|
393
|
+
|
|
394
|
+
/** Cross-mode snippet bundle used by the app to initialise and reset editor sources. */
|
|
395
|
+
export interface SnippetBundle {
|
|
396
|
+
readonly id: string;
|
|
397
|
+
readonly source: Record<PlaygroundMode, string>;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const first = snippetCatalog[0];
|
|
401
|
+
|
|
402
|
+
/** Default snippet for initial app state. */
|
|
403
|
+
export const defaultSnippet: SnippetBundle = {
|
|
404
|
+
id: first?.id ?? '',
|
|
405
|
+
source: {
|
|
406
|
+
emotion: first?.source.emotion ?? '',
|
|
407
|
+
native: first?.source.native ?? '',
|
|
408
|
+
},
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
/** Looks up a snippet by shared id; returns both Emotion and Native sources. */
|
|
412
|
+
export const snippetById = (id: string): SnippetBundle | undefined => {
|
|
413
|
+
const found = snippetCatalog.find((item) => item.id === id);
|
|
414
|
+
if (!found) {
|
|
415
|
+
return undefined;
|
|
416
|
+
}
|
|
417
|
+
return { id: found.id, source: { ...found.source } };
|
|
418
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
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 { describe, expect, it } from 'vitest';
|
|
9
|
+
|
|
10
|
+
import { snippets } from '../examples/snippets';
|
|
11
|
+
|
|
12
|
+
import { compilePlayground } from './compile';
|
|
13
|
+
import { createDemoDistillery } from './demo_environment';
|
|
14
|
+
|
|
15
|
+
const expectOk = (result: ReturnType<typeof compilePlayground>) => {
|
|
16
|
+
if (!result.ok) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`expected ok, got ${result.error.stage}: ${result.error.message}`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
describe('compilePlayground', () => {
|
|
25
|
+
it('renders the emotion class into both the preview and the readable CSS', () => {
|
|
26
|
+
const source = 'const c = css`color: red;`;\nreturn c.toString();';
|
|
27
|
+
const result = expectOk(compilePlayground(source, 'emotion'));
|
|
28
|
+
|
|
29
|
+
expect(result.previewHtml).not.toBe('');
|
|
30
|
+
expect(result.readableCss).toContain(`.${result.previewHtml}`);
|
|
31
|
+
expect(result.readableCss).toContain('color:red');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('emits distinct compact and readable class names for the same styles', () => {
|
|
35
|
+
const source = 'const c = css`padding: 16px;`;\nreturn c.toString();';
|
|
36
|
+
const result = expectOk(compilePlayground(source, 'emotion'));
|
|
37
|
+
|
|
38
|
+
expect(result.readableCss).not.toBe('');
|
|
39
|
+
expect(result.compactCss).not.toBe('');
|
|
40
|
+
expect(result.compactCss).not.toEqual(result.readableCss);
|
|
41
|
+
expect(result.compactCss).toContain('padding:16px');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('resolves theme tokens to a var reference and a :host declaration', () => {
|
|
45
|
+
const source =
|
|
46
|
+
'const c = css`color: ${tokens.color.accent};`;\nreturn c.toString();';
|
|
47
|
+
const result = expectOk(compilePlayground(source, 'emotion'));
|
|
48
|
+
|
|
49
|
+
expect(result.readableCss).toContain('var(--dstl-color-accent)');
|
|
50
|
+
expect(result.readableCss).toContain(':host{');
|
|
51
|
+
expect(result.readableCss).toContain('--dstl-color-accent:');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('resolves native module handles via cn into the readable CSS', () => {
|
|
55
|
+
const source = [
|
|
56
|
+
"const m = createStyleModule('demo', ({ css }) => ({",
|
|
57
|
+
' root: css`color: red;`,',
|
|
58
|
+
'}));',
|
|
59
|
+
'return cn(m.handles.root);',
|
|
60
|
+
].join('\n');
|
|
61
|
+
const result = expectOk(compilePlayground(source, 'native'));
|
|
62
|
+
|
|
63
|
+
expect(result.previewHtml).not.toBe('');
|
|
64
|
+
expect(result.readableCss).toContain(`.${result.previewHtml}`);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('reports transform-stage errors for invalid syntax', () => {
|
|
68
|
+
const result = compilePlayground('const = ;', 'emotion');
|
|
69
|
+
expect(result.ok).toBe(false);
|
|
70
|
+
if (!result.ok) {
|
|
71
|
+
expect(result.error.stage).toBe('transform');
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('reports evaluate-stage errors for runtime failures', () => {
|
|
76
|
+
const result = compilePlayground('return missing.value;', 'emotion');
|
|
77
|
+
expect(result.ok).toBe(false);
|
|
78
|
+
if (!result.ok) {
|
|
79
|
+
expect(result.error.stage).toBe('evaluate');
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('compiles every shipped snippet without error', () => {
|
|
84
|
+
for (const mode of ['emotion', 'native'] as const) {
|
|
85
|
+
for (const snippet of snippets[mode]) {
|
|
86
|
+
const result = compilePlayground(snippet.source, mode);
|
|
87
|
+
expect(result.ok, `${mode}/${snippet.id}`).toBe(true);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('omits an uncollected variant from the artifact that the stylesheet keeps', () => {
|
|
93
|
+
for (const mode of ['emotion', 'native'] as const) {
|
|
94
|
+
const snippet = snippets[mode].find((item) => item.id === 'tree-shake');
|
|
95
|
+
expect(snippet, mode).toBeDefined();
|
|
96
|
+
const result = expectOk(compilePlayground(snippet?.source ?? '', mode));
|
|
97
|
+
|
|
98
|
+
expect(result.readableCss).toContain('#C61E25');
|
|
99
|
+
expect(result.artifactCss).not.toContain('#C61E25');
|
|
100
|
+
expect(result.artifactBytes).toBeLessThan(result.stylesheetBytes);
|
|
101
|
+
if (mode === 'native') {
|
|
102
|
+
expect(result.readableCss).toContain('chip-tone-loud');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('collects emotion handles that stringify into the returned markup', () => {
|
|
108
|
+
const source = [
|
|
109
|
+
'const used = css`color: red;`;',
|
|
110
|
+
'const unused = css`color: blue;`;',
|
|
111
|
+
'return `<div class="${used}"></div>`;',
|
|
112
|
+
].join('\n');
|
|
113
|
+
const result = expectOk(compilePlayground(source, 'emotion'));
|
|
114
|
+
|
|
115
|
+
expect(result.readableCss).toContain('color:red');
|
|
116
|
+
expect(result.readableCss).toContain('color:blue');
|
|
117
|
+
expect(result.artifactCss).toContain('color:red');
|
|
118
|
+
expect(result.artifactCss).not.toContain('color:blue');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('assigns compact artifact names after collection completes', () => {
|
|
122
|
+
const source = [
|
|
123
|
+
"const zebra = createStyleModule('zebra', ({ css }) => ({",
|
|
124
|
+
' root: css`color: red;`,',
|
|
125
|
+
'}));',
|
|
126
|
+
"const apple = createStyleModule('apple', ({ css }) => ({",
|
|
127
|
+
' root: css`color: blue;`,',
|
|
128
|
+
'}));',
|
|
129
|
+
'return `<div class="${cn(zebra.handles.root)}"></div><span class="${cn(apple.handles.root)}"></span>`;',
|
|
130
|
+
].join('\n');
|
|
131
|
+
const result = expectOk(compilePlayground(source, 'native'));
|
|
132
|
+
|
|
133
|
+
const distillery = createDemoDistillery();
|
|
134
|
+
const zebra = distillery.createStyleModule('zebra', ({ css }) => ({
|
|
135
|
+
root: css`
|
|
136
|
+
color: red;
|
|
137
|
+
`,
|
|
138
|
+
}));
|
|
139
|
+
const apple = distillery.createStyleModule('apple', ({ css }) => ({
|
|
140
|
+
root: css`
|
|
141
|
+
color: blue;
|
|
142
|
+
`,
|
|
143
|
+
}));
|
|
144
|
+
const collector = distillery.artifactCollector('compact');
|
|
145
|
+
collector.useHandles([zebra.handles.root]);
|
|
146
|
+
collector.useHandles([apple.handles.root]);
|
|
147
|
+
expect(result.artifactCss).toBe(distillery.renderStyles(collector));
|
|
148
|
+
|
|
149
|
+
const early = distillery.artifactCollector('compact');
|
|
150
|
+
early.useHandles([zebra.handles.root]);
|
|
151
|
+
const earlyResolver = early.createResolver();
|
|
152
|
+
early.useHandles([apple.handles.root]);
|
|
153
|
+
expect(() => distillery.renderStyles(early, earlyResolver)).toThrow(
|
|
154
|
+
/No compact class name registered/
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
});
|