@motion-proto/live-tokens 0.67.1 → 0.69.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/.claude/skills/live-tokens-build-page/SKILL.md +16 -5
- package/.claude/skills/live-tokens-create-component/SKILL.md +43 -8
- package/.claude/skills/live-tokens-create-component/references/token-naming.md +30 -1
- package/.claude/skills/live-tokens-fix-findings/SKILL.md +131 -0
- package/.claude/skills/live-tokens-pick-component/SKILL.md +2 -1
- package/CHANGELOG.md +239 -0
- package/README.md +11 -4
- package/bin/check-component.mjs +367 -63
- package/bin/check-page.mjs +409 -0
- package/bin/cli.mjs +57 -8
- package/bin/generate-theme.mjs +5 -4
- package/bin/lib/cssValues.mjs +50 -0
- package/bin/lib/findings.mjs +106 -0
- package/bin/lib/tokenVocabulary.mjs +213 -0
- package/dist-plugin/adjust/index.cjs +174 -23
- package/dist-plugin/adjust/index.d.cts +1 -1
- package/dist-plugin/adjust/index.d.ts +1 -1
- package/dist-plugin/adjust/index.js +68 -23
- package/dist-plugin/{chunk-J2JT4UEA.js → chunk-2YNERPXY.js} +26 -26
- package/dist-plugin/{chunk-NE6N66EE.js → chunk-GPIBU44G.js} +107 -1
- package/dist-plugin/{chunk-ZHPX7ZYQ.js → chunk-RFVYPNRO.js} +39 -1
- package/dist-plugin/{dataPaths-DZUzVv8H.d.ts → dataPaths-bJTCEO4H.d.cts} +1 -1
- package/dist-plugin/{dataPaths-DZUzVv8H.d.cts → dataPaths-bJTCEO4H.d.ts} +1 -1
- package/dist-plugin/fontPairing/index.d.cts +1 -1
- package/dist-plugin/fontPairing/index.d.ts +1 -1
- package/dist-plugin/generateColorsAndType/index.cjs +107 -1
- package/dist-plugin/generateColorsAndType/index.d.cts +1 -1
- package/dist-plugin/generateColorsAndType/index.d.ts +1 -1
- package/dist-plugin/generateColorsAndType/index.js +1 -1
- package/dist-plugin/index.cjs +173 -29
- package/dist-plugin/index.d.cts +1 -1
- package/dist-plugin/index.d.ts +1 -1
- package/dist-plugin/index.js +7 -7
- package/dist-plugin/migrateData/index.cjs +132 -26
- package/dist-plugin/migrateData/index.d.cts +1 -1
- package/dist-plugin/migrateData/index.d.ts +1 -1
- package/dist-plugin/migrateData/index.js +2 -2
- package/dist-plugin/tokensCssMigrations/index.cjs +39 -1
- package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
- package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
- package/dist-plugin/tokensCssMigrations/index.js +1 -1
- package/package.json +6 -5
- package/src/app/site.css +4 -4
- package/src/editor/bootstrap.ts +6 -6
- package/src/editor/component-editor/ButtonEditor.svelte +71 -4
- package/src/editor/component-editor/CardEditor.svelte +6 -6
- package/src/editor/component-editor/DialogEditor.svelte +3 -3
- package/src/editor/component-editor/IconButtonEditor.svelte +68 -3
- package/src/editor/component-editor/ImageEditor.svelte +8 -8
- package/src/editor/component-editor/ImageLightboxEditor.svelte +13 -2
- package/src/editor/component-editor/MenuSelectEditor.svelte +63 -3
- package/src/editor/component-editor/SegmentedControlEditor.svelte +63 -3
- package/src/editor/component-editor/SideNavigationEditor.svelte +67 -3
- package/src/editor/component-editor/SliderEditor.svelte +186 -0
- package/src/editor/component-editor/TabBarEditor.svelte +63 -3
- package/src/editor/component-editor/registry.ts +10 -0
- package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +4 -4
- package/src/editor/core/components/aliasKinds.ts +51 -28
- package/src/editor/core/fonts/fontLoader.ts +2 -2
- package/src/editor/core/preview/{lookPreview.ts → themePreview.ts} +27 -27
- package/src/editor/core/productionPulse.ts +3 -3
- package/src/editor/core/sketch/index.ts +52 -44
- package/src/editor/core/sketch/maskField.ts +9 -9
- package/src/editor/core/sketch/sketchLayer.ts +25 -9
- package/src/editor/core/sketch/sketchRegistry.ts +34 -34
- package/src/editor/core/sketch/sketchStore.ts +98 -83
- package/src/editor/core/sketch/sketchStyleService.ts +4 -4
- package/src/editor/core/sketch/sketchStyles.ts +28 -28
- package/src/editor/core/store/editorPersistence.ts +44 -1
- package/src/editor/core/store/editorRenderer.ts +2 -2
- package/src/editor/core/store/editorStore.ts +18 -18
- package/src/editor/core/store/editorTypes.ts +7 -6
- package/src/editor/core/themes/colorsAndTypeService.ts +1 -1
- package/src/editor/core/themes/loadRows.ts +8 -8
- package/src/editor/core/themes/migrations/2026-09-01-gate-suffix-enabled.ts +31 -0
- package/src/editor/core/themes/migrations/2026-09-01-scrim-rename.ts +52 -0
- package/src/editor/core/themes/migrations/2026-09-01-tabbar-active-tint.ts +27 -0
- package/src/editor/core/themes/migrations/2026-09-01-tint-rename.ts +42 -0
- package/src/editor/core/themes/migrations/index.ts +16 -0
- package/src/editor/core/themes/slices/domainVars.ts +2 -2
- package/src/editor/core/themes/slices/washes.ts +107 -0
- package/src/editor/core/themes/themeDocumentSync.ts +2 -2
- package/src/editor/core/themes/themeInit.ts +2 -2
- package/src/editor/core/themes/themeService.ts +17 -17
- package/src/editor/core/themes/{lookSummary.ts → themeSummary.ts} +9 -9
- package/src/editor/core/themes/themeTypes.ts +10 -6
- package/src/editor/docs/content/editing-tokens.md +5 -3
- package/src/editor/docs/content/getting-started.md +1 -1
- package/src/editor/docs/content/sketch-mode.md +22 -17
- package/src/editor/docs/content/themes-workflow.md +11 -11
- package/src/editor/docs/content/where-themes-live.md +6 -6
- package/src/editor/docs/content.generated.ts +5 -5
- package/src/editor/index.ts +2 -2
- package/src/editor/pages/EditorShell.svelte +1 -1
- package/src/editor/ui/SurfacesTab.svelte +3 -3
- package/src/editor/ui/ThemePanel.svelte +52 -52
- package/src/editor/ui/UITokenSelector.svelte +1 -0
- package/src/editor/ui/VariablesTab.svelte +2 -2
- package/src/editor/ui/sections/{OverlaysSection.svelte → WashesSection.svelte} +44 -43
- package/src/editor/ui/sketch/SketchPreview.svelte +2 -2
- package/src/editor/ui/sketch/SketchTab.svelte +64 -38
- package/src/live-tokens/data/colors-and-type/autumn.json +6 -6
- package/src/live-tokens/data/colors-and-type/default.json +6 -6
- package/src/live-tokens/data/colors-and-type/halloween.json +6 -6
- package/src/live-tokens/data/colors-and-type/midnight-study.json +6 -6
- package/src/live-tokens/data/colors-and-type/ocean.json +6 -6
- package/src/live-tokens/data/colors-and-type/royal-velvet.json +6 -6
- package/src/live-tokens/data/colors-and-type/sketchy.json +6 -6
- package/src/live-tokens/data/colors-and-type/spring-meadow.json +6 -6
- package/src/live-tokens/data/colors-and-type/sunset.json +6 -6
- package/src/live-tokens/data/sketch-styles/dry.json +5 -5
- package/src/live-tokens/data/sketch-styles/hatched.json +9 -9
- package/src/live-tokens/data/themes/autumn.json +82 -14
- package/src/live-tokens/data/themes/halloween.json +82 -14
- package/src/live-tokens/data/themes/midnight-study.json +82 -14
- package/src/live-tokens/data/themes/ocean.json +82 -14
- package/src/live-tokens/data/themes/royal-velvet.json +82 -14
- package/src/live-tokens/data/themes/sketchy.json +82 -14
- package/src/live-tokens/data/themes/spring-meadow.json +82 -14
- package/src/live-tokens/data/themes/sunset.json +82 -14
- package/src/live-tokens/data/tokens.generated.css +6 -6
- package/src/system/backdrop/backdrop.ts +1 -1
- package/src/system/components/Button.svelte +28 -10
- package/src/system/components/Card.svelte +6 -6
- package/src/system/components/Dialog.svelte +3 -3
- package/src/system/components/IconButton.svelte +23 -7
- package/src/system/components/Image.svelte +6 -6
- package/src/system/components/MenuSelect.svelte +17 -1
- package/src/system/components/SectionDivider.svelte +1 -1
- package/src/system/components/SegmentedControl.svelte +20 -2
- package/src/system/components/SideNavigation.svelte +22 -2
- package/src/system/components/Slider.svelte +348 -0
- package/src/system/components/TabBar.svelte +20 -2
- package/src/system/styles/CONVENTIONS.md +2 -2
- package/src/system/styles/tokens.css +12 -4
- package/template/package.json +3 -2
- package/template/src/pages/Home.svelte +1 -1
- package/src/editor/core/themes/slices/overlays.ts +0 -101
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
2
|
import { buildTypeGroupTokens, buildTypeGroupShareableContexts } from './scaffolding/buildTypeGroupTokens';
|
|
3
|
-
import type { Token, TypeGroupConfig } from './scaffolding/types';
|
|
3
|
+
import type { Token, TypeGroupConfig, IntrinsicSpec } from './scaffolding/types';
|
|
4
4
|
|
|
5
5
|
export const component = 'segmentedcontrol';
|
|
6
6
|
|
|
@@ -123,14 +123,55 @@
|
|
|
123
123
|
const linkableContexts = new Map<string, string>(
|
|
124
124
|
buildTypeGroupShareableContexts(typeGroups),
|
|
125
125
|
);
|
|
126
|
+
|
|
127
|
+
// The hover tint is off unless a project turns it on: the gate holds a
|
|
128
|
+
// transparent layer, a no-op, until it holds the tint itself.
|
|
129
|
+
export const intrinsics: IntrinsicSpec[] = [
|
|
130
|
+
{
|
|
131
|
+
key: 'hover-tint',
|
|
132
|
+
variants: ['default'],
|
|
133
|
+
variable: () => '--segmentedcontrol-hover-tint-enabled',
|
|
134
|
+
values: ['var(--color-transparent)', 'var(--segmentedcontrol-hover-tint)'],
|
|
135
|
+
default: { default: 'var(--color-transparent)' },
|
|
136
|
+
},
|
|
137
|
+
];
|
|
126
138
|
</script>
|
|
127
139
|
|
|
128
140
|
<script lang="ts">
|
|
129
141
|
import SegmentedControl from '../../system/components/SegmentedControl.svelte';
|
|
130
142
|
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
131
143
|
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
132
|
-
import { editorState } from '../core/store/editorStore';
|
|
144
|
+
import { editorState, setComponentAlias, clearComponentAlias } from '../core/store/editorStore';
|
|
133
145
|
import { computeLinkedBlock, withLinkedDisabled } from './scaffolding/linkedBlock';
|
|
146
|
+
import Toggle from '../ui/Toggle.svelte';
|
|
147
|
+
import UIPaletteSelector from '../ui/UIPaletteSelector.svelte';
|
|
148
|
+
|
|
149
|
+
// One switch. Turning the tint on also stands each hover surface down to its
|
|
150
|
+
// own base, so hover is the tint alone rather than a swap wearing a wash.
|
|
151
|
+
// Written as aliases rather than gated in CSS: a component token's value is
|
|
152
|
+
// substituted at :root, so it can never name a per-variant private var.
|
|
153
|
+
// Off clears the overrides, returning each surface to its shipped default.
|
|
154
|
+
const HOVER_SWAPS: readonly (readonly [hover: string, base: string])[] = [
|
|
155
|
+
['--segmentedcontrol-option-hover-surface', '--color-transparent'],
|
|
156
|
+
];
|
|
157
|
+
const TINT_ON = 'var(--segmentedcontrol-hover-tint)';
|
|
158
|
+
const TINT_OFF = 'var(--color-transparent)';
|
|
159
|
+
|
|
160
|
+
let tintOn = $derived.by(() => {
|
|
161
|
+
const ref = $editorState.components.segmentedcontrol?.aliases['--segmentedcontrol-hover-tint-enabled'];
|
|
162
|
+
return (ref?.kind === 'literal' ? ref.value : TINT_OFF) === TINT_ON;
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
function setTintOn(checked: boolean) {
|
|
166
|
+
setComponentAlias('segmentedcontrol', '--segmentedcontrol-hover-tint-enabled', {
|
|
167
|
+
kind: 'literal',
|
|
168
|
+
value: checked ? TINT_ON : TINT_OFF,
|
|
169
|
+
});
|
|
170
|
+
for (const [hover, base] of HOVER_SWAPS) {
|
|
171
|
+
if (checked) setComponentAlias('segmentedcontrol', hover, { kind: 'token', name: base });
|
|
172
|
+
else clearComponentAlias('segmentedcontrol', hover);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
134
175
|
|
|
135
176
|
type Segment = { value: string; label: string; icon?: string; disabled?: boolean };
|
|
136
177
|
const segments: Segment[] = [
|
|
@@ -148,7 +189,12 @@
|
|
|
148
189
|
let activeTypeGroups = $derived(previewSize === 'small' ? emptyTypeGroups : typeGroups);
|
|
149
190
|
|
|
150
191
|
let visibleStates = $derived(Object.fromEntries(
|
|
151
|
-
Object.entries(activeStates).map(([name, list]) => [
|
|
192
|
+
Object.entries(activeStates).map(([name, list]) => [
|
|
193
|
+
name,
|
|
194
|
+
withLinkedDisabled(list, linked.varSet).map((t) =>
|
|
195
|
+
tintOn && t.variable.endsWith('-hover-surface') ? { ...t, disabled: true } : t,
|
|
196
|
+
),
|
|
197
|
+
]),
|
|
152
198
|
) as Record<string, Token[]>);
|
|
153
199
|
</script>
|
|
154
200
|
|
|
@@ -160,6 +206,20 @@
|
|
|
160
206
|
typeGroups={activeTypeGroups}
|
|
161
207
|
{component}
|
|
162
208
|
>
|
|
209
|
+
{#snippet extraPropertyRows(stateName)}
|
|
210
|
+
{#if stateName === 'hover option'}
|
|
211
|
+
<div class="property-row" data-token-variables="--segmentedcontrol-hover-tint-enabled">
|
|
212
|
+
<span class="property-label">tint layer</span>
|
|
213
|
+
<Toggle checked={tintOn} onchange={setTintOn} />
|
|
214
|
+
</div>
|
|
215
|
+
{#if tintOn}
|
|
216
|
+
<div class="property-row">
|
|
217
|
+
<span class="property-label">tint color</span>
|
|
218
|
+
<UIPaletteSelector variable="--segmentedcontrol-hover-tint" {component} showNone={false} />
|
|
219
|
+
</div>
|
|
220
|
+
{/if}
|
|
221
|
+
{/if}
|
|
222
|
+
{/snippet}
|
|
163
223
|
{#snippet previewActions()}
|
|
164
224
|
<label>
|
|
165
225
|
<span>Size</span>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
2
|
import { buildTypeGroupColorTokens } from './scaffolding/buildTypeGroupTokens';
|
|
3
|
-
import type { Token, TypeGroupConfig } from './scaffolding/types';
|
|
3
|
+
import type { Token, TypeGroupConfig, IntrinsicSpec } from './scaffolding/types';
|
|
4
4
|
|
|
5
5
|
export const component = 'sidenavigation';
|
|
6
6
|
|
|
@@ -259,14 +259,59 @@
|
|
|
259
259
|
['--sidenavigation-panel-padding', 'panel'],
|
|
260
260
|
['--sidenavigation-title-label-border-width', 'title block'],
|
|
261
261
|
]);
|
|
262
|
+
|
|
263
|
+
// The hover tint is off unless a project turns it on: the gate holds a
|
|
264
|
+
// transparent layer, a no-op, until it holds the tint itself.
|
|
265
|
+
export const intrinsics: IntrinsicSpec[] = [
|
|
266
|
+
{
|
|
267
|
+
key: 'hover-tint',
|
|
268
|
+
variants: ['default'],
|
|
269
|
+
variable: () => '--sidenavigation-hover-tint-enabled',
|
|
270
|
+
values: ['var(--color-transparent)', 'var(--sidenavigation-hover-tint)'],
|
|
271
|
+
default: { default: 'var(--color-transparent)' },
|
|
272
|
+
},
|
|
273
|
+
];
|
|
262
274
|
</script>
|
|
263
275
|
|
|
264
276
|
<script lang="ts">
|
|
265
277
|
import SideNavigation, { type SideNavSection, type SideNavFooter } from '../../system/components/SideNavigation.svelte';
|
|
266
278
|
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
267
279
|
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
268
|
-
import { editorState } from '../core/store/editorStore';
|
|
280
|
+
import { editorState, setComponentAlias, clearComponentAlias } from '../core/store/editorStore';
|
|
269
281
|
import { computeLinkedBlock, withLinkedDisabled } from './scaffolding/linkedBlock';
|
|
282
|
+
import Toggle from '../ui/Toggle.svelte';
|
|
283
|
+
import UIPaletteSelector from '../ui/UIPaletteSelector.svelte';
|
|
284
|
+
|
|
285
|
+
// One switch. Turning the tint on also stands each hover surface down to its
|
|
286
|
+
// own base, so hover is the tint alone rather than a swap wearing a wash.
|
|
287
|
+
// Written as aliases rather than gated in CSS: a component token's value is
|
|
288
|
+
// substituted at :root, so it can never name a per-variant private var.
|
|
289
|
+
// Off clears the overrides, returning each surface to its shipped default.
|
|
290
|
+
const HOVER_SWAPS: readonly (readonly [hover: string, base: string])[] = [
|
|
291
|
+
['--sidenavigation-title-hover-surface', '--sidenavigation-title-default-surface'],
|
|
292
|
+
['--sidenavigation-toggle-hover-surface', '--sidenavigation-toggle-default-surface'],
|
|
293
|
+
['--sidenavigation-section-hover-surface', '--sidenavigation-section-default-surface'],
|
|
294
|
+
['--sidenavigation-item-hover-surface', '--sidenavigation-item-default-surface'],
|
|
295
|
+
['--sidenavigation-footer-hover-surface', '--sidenavigation-footer-default-surface'],
|
|
296
|
+
];
|
|
297
|
+
const TINT_ON = 'var(--sidenavigation-hover-tint)';
|
|
298
|
+
const TINT_OFF = 'var(--color-transparent)';
|
|
299
|
+
|
|
300
|
+
let tintOn = $derived.by(() => {
|
|
301
|
+
const ref = $editorState.components.sidenavigation?.aliases['--sidenavigation-hover-tint-enabled'];
|
|
302
|
+
return (ref?.kind === 'literal' ? ref.value : TINT_OFF) === TINT_ON;
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
function setTintOn(checked: boolean) {
|
|
306
|
+
setComponentAlias('sidenavigation', '--sidenavigation-hover-tint-enabled', {
|
|
307
|
+
kind: 'literal',
|
|
308
|
+
value: checked ? TINT_ON : TINT_OFF,
|
|
309
|
+
});
|
|
310
|
+
for (const [hover, base] of HOVER_SWAPS) {
|
|
311
|
+
if (checked) setComponentAlias('sidenavigation', hover, { kind: 'token', name: base });
|
|
312
|
+
else clearComponentAlias('sidenavigation', hover);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
270
315
|
|
|
271
316
|
const demoSections: SideNavSection[] = [
|
|
272
317
|
{
|
|
@@ -296,7 +341,12 @@
|
|
|
296
341
|
let previewOpen = $state(true);
|
|
297
342
|
|
|
298
343
|
let visibleStates = $derived(Object.fromEntries(
|
|
299
|
-
Object.entries(states).map(([name, list]) => [
|
|
344
|
+
Object.entries(states).map(([name, list]) => [
|
|
345
|
+
name,
|
|
346
|
+
withLinkedDisabled(list, linked.varSet).map((t) =>
|
|
347
|
+
tintOn && t.variable.endsWith('-hover-surface') ? { ...t, disabled: true } : t,
|
|
348
|
+
),
|
|
349
|
+
]),
|
|
300
350
|
) as Record<string, Token[]>);
|
|
301
351
|
|
|
302
352
|
// Map the active part/state to the demo's force-hover / force-active hooks
|
|
@@ -331,6 +381,20 @@
|
|
|
331
381
|
{component}
|
|
332
382
|
selectorLabel="Part"
|
|
333
383
|
>
|
|
384
|
+
{#snippet extraPropertyRows(stateName)}
|
|
385
|
+
{#if stateName.endsWith(' / Hover')}
|
|
386
|
+
<div class="property-row" data-token-variables="--sidenavigation-hover-tint-enabled">
|
|
387
|
+
<span class="property-label">tint layer</span>
|
|
388
|
+
<Toggle checked={tintOn} onchange={setTintOn} />
|
|
389
|
+
</div>
|
|
390
|
+
{#if tintOn}
|
|
391
|
+
<div class="property-row">
|
|
392
|
+
<span class="property-label">tint color</span>
|
|
393
|
+
<UIPaletteSelector variable="--sidenavigation-hover-tint" {component} showNone={false} />
|
|
394
|
+
</div>
|
|
395
|
+
{/if}
|
|
396
|
+
{/if}
|
|
397
|
+
{/snippet}
|
|
334
398
|
{#snippet children({ activeState })}
|
|
335
399
|
{@const { forceHoverPart, forceActivePart } = deriveForce(activeState)}
|
|
336
400
|
<div class="sn-preview-frame">
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { buildTypeGroupColorTokens } from './scaffolding/buildTypeGroupTokens';
|
|
3
|
+
import type { Token, TypeGroupConfig } from './scaffolding/types';
|
|
4
|
+
import { sliderVariants } from '../../system/components/Slider.svelte';
|
|
5
|
+
|
|
6
|
+
export const component = 'slider';
|
|
7
|
+
const variants = sliderVariants;
|
|
8
|
+
type Variant = typeof variants[number];
|
|
9
|
+
|
|
10
|
+
// Geometry and colour are identical across the two variants by default, so
|
|
11
|
+
// every row is linkable: an edit to the single slider's track moves the range
|
|
12
|
+
// slider's track until a user unlinks them on purpose.
|
|
13
|
+
function variantDefaultTokens(v: Variant): Token[] {
|
|
14
|
+
return [
|
|
15
|
+
{ label: 'surface', element: 'track', canBeLinked: true, groupKey: 'track-surface', variable: `--slider-${v}-track-surface` },
|
|
16
|
+
{ label: 'border', element: 'track', canBeLinked: true, groupKey: 'track-border', variable: `--slider-${v}-track-border` },
|
|
17
|
+
{ label: 'border width', element: 'track', canBeLinked: true, groupKey: 'track-border-width', variable: `--slider-${v}-track-border-width` },
|
|
18
|
+
{ label: 'height', element: 'track', canBeLinked: true, groupKey: 'track-height', variable: `--slider-${v}-track-height` },
|
|
19
|
+
{ label: 'corner radius', element: 'track', canBeLinked: true, groupKey: 'track-radius', variable: `--slider-${v}-track-radius` },
|
|
20
|
+
{ label: 'color', element: 'fill', canBeLinked: true, groupKey: 'fill', variable: `--slider-${v}-fill` },
|
|
21
|
+
{ label: 'surface', element: 'thumb', canBeLinked: true, groupKey: 'thumb-surface', variable: `--slider-${v}-thumb-surface` },
|
|
22
|
+
{ label: 'border', element: 'thumb', canBeLinked: true, groupKey: 'thumb-border', variable: `--slider-${v}-thumb-border` },
|
|
23
|
+
{ label: 'border width', element: 'thumb', canBeLinked: true, groupKey: 'thumb-border-width', variable: `--slider-${v}-thumb-border-width` },
|
|
24
|
+
{ label: 'size', element: 'thumb', canBeLinked: true, groupKey: 'thumb-size', variable: `--slider-${v}-thumb-size` },
|
|
25
|
+
{ label: 'corner radius', element: 'thumb', canBeLinked: true, groupKey: 'thumb-radius', variable: `--slider-${v}-thumb-radius` },
|
|
26
|
+
{ label: 'shadow', element: 'thumb', canBeLinked: true, groupKey: 'thumb-shadow', variable: `--slider-${v}-thumb-shadow` },
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function variantHoverTokens(v: Variant): Token[] {
|
|
31
|
+
return [
|
|
32
|
+
{ label: 'thumb surface', canBeLinked: true, groupKey: 'hover-thumb-surface', variable: `--slider-${v}-hover-thumb-surface` },
|
|
33
|
+
{ label: 'thumb border', canBeLinked: true, groupKey: 'hover-thumb-border', variable: `--slider-${v}-hover-thumb-border` },
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function variantDisabledTokens(v: Variant): Token[] {
|
|
38
|
+
return [
|
|
39
|
+
{ label: 'track surface', canBeLinked: true, groupKey: 'disabled-track-surface', variable: `--slider-${v}-disabled-track-surface` },
|
|
40
|
+
{ label: 'fill color', canBeLinked: true, groupKey: 'disabled-fill', variable: `--slider-${v}-disabled-fill` },
|
|
41
|
+
{ label: 'thumb surface', canBeLinked: true, groupKey: 'disabled-thumb-surface', variable: `--slider-${v}-disabled-thumb-surface` },
|
|
42
|
+
{ label: 'thumb border', canBeLinked: true, groupKey: 'disabled-thumb-border', variable: `--slider-${v}-disabled-thumb-border` },
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// The label and its gap are shared by both variants, so their rows render
|
|
47
|
+
// once, under the single variant beside the type groups.
|
|
48
|
+
const labelGapToken: Token = { label: 'label gap', element: 'label', groupKey: 'label-gap', variable: '--slider-label-gap' };
|
|
49
|
+
|
|
50
|
+
function variantStates(v: Variant): Record<string, Token[]> {
|
|
51
|
+
return {
|
|
52
|
+
default: v === 'single' ? [...variantDefaultTokens(v), labelGapToken] : variantDefaultTokens(v),
|
|
53
|
+
hover: variantHoverTokens(v),
|
|
54
|
+
disabled: variantDisabledTokens(v),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// The label and value readout are shared by both variants, so they live in
|
|
59
|
+
// one type group outside the per-variant states.
|
|
60
|
+
const typeGroups: Record<string, TypeGroupConfig[]> = {
|
|
61
|
+
default: [
|
|
62
|
+
{
|
|
63
|
+
legend: '',
|
|
64
|
+
element: 'label',
|
|
65
|
+
colorVariable: '--slider-label',
|
|
66
|
+
familyVariable: '--slider-label-font-family',
|
|
67
|
+
sizeVariable: '--slider-label-font-size',
|
|
68
|
+
weightVariable: '--slider-label-font-weight',
|
|
69
|
+
lineHeightVariable: '--slider-label-line-height',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
legend: '',
|
|
73
|
+
element: 'value',
|
|
74
|
+
colorVariable: '--slider-value',
|
|
75
|
+
familyVariable: '--slider-value-font-family',
|
|
76
|
+
sizeVariable: '--slider-value-font-size',
|
|
77
|
+
weightVariable: '--slider-value-font-weight',
|
|
78
|
+
lineHeightVariable: '--slider-value-line-height',
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const typeGroupTokens: Token[] = [
|
|
84
|
+
{ label: 'font family', canBeLinked: true, groupKey: 'label-font-family', variable: '--slider-label-font-family' },
|
|
85
|
+
{ label: 'font size', canBeLinked: true, groupKey: 'label-font-size', variable: '--slider-label-font-size' },
|
|
86
|
+
{ label: 'font weight', canBeLinked: true, groupKey: 'label-font-weight', variable: '--slider-label-font-weight' },
|
|
87
|
+
{ label: 'line height', canBeLinked: true, groupKey: 'label-line-height', variable: '--slider-label-line-height' },
|
|
88
|
+
{ label: 'font family', canBeLinked: true, groupKey: 'value-font-family', variable: '--slider-value-font-family' },
|
|
89
|
+
{ label: 'font size', canBeLinked: true, groupKey: 'value-font-size', variable: '--slider-value-font-size' },
|
|
90
|
+
{ label: 'font weight', canBeLinked: true, groupKey: 'value-font-weight', variable: '--slider-value-font-weight' },
|
|
91
|
+
{ label: 'line height', canBeLinked: true, groupKey: 'value-line-height', variable: '--slider-value-line-height' },
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
export const allTokens: Token[] = [
|
|
95
|
+
...variants.flatMap((v) => Object.values(variantStates(v)).flat()),
|
|
96
|
+
...buildTypeGroupColorTokens(typeGroups, { component }),
|
|
97
|
+
...typeGroupTokens,
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
const linkableContexts = new Map<string, string>([
|
|
101
|
+
...variants.flatMap((v) =>
|
|
102
|
+
Object.entries(variantStates(v)).flatMap(([state, list]) =>
|
|
103
|
+
list.filter((t) => t.canBeLinked).map((t) => [t.variable, `${v} ${state}`] as [string, string]),
|
|
104
|
+
),
|
|
105
|
+
),
|
|
106
|
+
...typeGroupTokens
|
|
107
|
+
.filter((t) => t.canBeLinked)
|
|
108
|
+
.map((t) => [t.variable, t.variable.includes('-label-') ? 'label' : 'value'] as [string, string]),
|
|
109
|
+
]);
|
|
110
|
+
|
|
111
|
+
const variantOptions = variants.map((v) => ({ value: v, label: v.charAt(0).toUpperCase() + v.slice(1) }));
|
|
112
|
+
</script>
|
|
113
|
+
|
|
114
|
+
<script lang="ts">
|
|
115
|
+
import Slider from '../../system/components/Slider.svelte';
|
|
116
|
+
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
117
|
+
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
118
|
+
import { editorState } from '../core/store/editorStore';
|
|
119
|
+
import { computeLinkedBlock, withLinkedDisabled } from './scaffolding/linkedBlock';
|
|
120
|
+
import { buildSiblings } from './scaffolding/siblings';
|
|
121
|
+
|
|
122
|
+
let linked = $derived(computeLinkedBlock(component, linkableContexts, allTokens, $editorState));
|
|
123
|
+
let visibleVariantStates = $derived((v: Variant) => Object.fromEntries(
|
|
124
|
+
Object.entries(variantStates(v)).map(([name, list]) => [name, withLinkedDisabled(list, linked.varSet)]),
|
|
125
|
+
) as Record<string, Token[]>);
|
|
126
|
+
|
|
127
|
+
let value = $state(40);
|
|
128
|
+
let low = $state(20);
|
|
129
|
+
let high = $state(70);
|
|
130
|
+
|
|
131
|
+
function previewProps(activeState: string) {
|
|
132
|
+
return {
|
|
133
|
+
disabled: activeState === 'disabled',
|
|
134
|
+
forceClass: activeState === 'hover' ? 'force-hover' : '',
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
</script>
|
|
138
|
+
|
|
139
|
+
<ComponentEditorBase
|
|
140
|
+
{component}
|
|
141
|
+
title="Slider"
|
|
142
|
+
description="A number chosen by position on a track. Single moves one thumb to a value; range moves two thumbs to a low and a high bound."
|
|
143
|
+
tokens={allTokens}
|
|
144
|
+
{linked}
|
|
145
|
+
variants={variantOptions}
|
|
146
|
+
>
|
|
147
|
+
{#each variants as v}
|
|
148
|
+
<VariantGroup
|
|
149
|
+
name={v}
|
|
150
|
+
title={v.charAt(0).toUpperCase() + v.slice(1)}
|
|
151
|
+
states={visibleVariantStates(v)}
|
|
152
|
+
typeGroups={v === 'single' ? typeGroups : undefined}
|
|
153
|
+
{component}
|
|
154
|
+
siblings={buildSiblings(variants, v, variantStates)}
|
|
155
|
+
>
|
|
156
|
+
{#snippet children({ activeState })}
|
|
157
|
+
{@const p = previewProps(activeState)}
|
|
158
|
+
<div class="slider-demo-stack">
|
|
159
|
+
{#if v === 'range'}
|
|
160
|
+
<Slider
|
|
161
|
+
variant="range"
|
|
162
|
+
label="Price"
|
|
163
|
+
{low}
|
|
164
|
+
{high}
|
|
165
|
+
disabled={p.disabled}
|
|
166
|
+
class={p.forceClass}
|
|
167
|
+
onrangechange={(l, h) => { low = l; high = h; }}
|
|
168
|
+
/>
|
|
169
|
+
{:else}
|
|
170
|
+
<Slider label="Volume" {value} disabled={p.disabled} class={p.forceClass} onchange={(n) => (value = n)} />
|
|
171
|
+
{/if}
|
|
172
|
+
</div>
|
|
173
|
+
{/snippet}
|
|
174
|
+
</VariantGroup>
|
|
175
|
+
{/each}
|
|
176
|
+
</ComponentEditorBase>
|
|
177
|
+
|
|
178
|
+
<style>
|
|
179
|
+
.slider-demo-stack {
|
|
180
|
+
display: flex;
|
|
181
|
+
flex-direction: column;
|
|
182
|
+
gap: var(--space-12);
|
|
183
|
+
width: 100%;
|
|
184
|
+
max-width: 32rem;
|
|
185
|
+
}
|
|
186
|
+
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
2
|
import { buildTypeGroupColorTokens } from './scaffolding/buildTypeGroupTokens';
|
|
3
|
-
import type { Token, TypeGroupConfig } from './scaffolding/types';
|
|
3
|
+
import type { Token, TypeGroupConfig, IntrinsicSpec } from './scaffolding/types';
|
|
4
4
|
|
|
5
5
|
export const component = 'tabbar';
|
|
6
6
|
|
|
@@ -81,14 +81,55 @@
|
|
|
81
81
|
[`--tabbar-${s}-text-line-height`, `${s} tab`] as const,
|
|
82
82
|
]),
|
|
83
83
|
]);
|
|
84
|
+
|
|
85
|
+
// The hover tint is off unless a project turns it on: the gate holds a
|
|
86
|
+
// transparent layer, a no-op, until it holds the tint itself.
|
|
87
|
+
export const intrinsics: IntrinsicSpec[] = [
|
|
88
|
+
{
|
|
89
|
+
key: 'hover-tint',
|
|
90
|
+
variants: ['default'],
|
|
91
|
+
variable: () => '--tabbar-hover-tint-enabled',
|
|
92
|
+
values: ['var(--color-transparent)', 'var(--tabbar-hover-tint)'],
|
|
93
|
+
default: { default: 'var(--color-transparent)' },
|
|
94
|
+
},
|
|
95
|
+
];
|
|
84
96
|
</script>
|
|
85
97
|
|
|
86
98
|
<script lang="ts">
|
|
87
99
|
import TabBar from '../../system/components/TabBar.svelte';
|
|
88
100
|
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
89
101
|
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
90
|
-
import { editorState } from '../core/store/editorStore';
|
|
102
|
+
import { editorState, setComponentAlias, clearComponentAlias } from '../core/store/editorStore';
|
|
91
103
|
import { computeLinkedBlock, withLinkedDisabled } from './scaffolding/linkedBlock';
|
|
104
|
+
import Toggle from '../ui/Toggle.svelte';
|
|
105
|
+
import UIPaletteSelector from '../ui/UIPaletteSelector.svelte';
|
|
106
|
+
|
|
107
|
+
// One switch. Turning the tint on also stands each hover surface down to its
|
|
108
|
+
// own base, so hover is the tint alone rather than a swap wearing a wash.
|
|
109
|
+
// Written as aliases rather than gated in CSS: a component token's value is
|
|
110
|
+
// substituted at :root, so it can never name a per-variant private var.
|
|
111
|
+
// Off clears the overrides, returning each surface to its shipped default.
|
|
112
|
+
const HOVER_SWAPS: readonly (readonly [hover: string, base: string])[] = [
|
|
113
|
+
['--tabbar-hover-surface', '--tabbar-default-surface'],
|
|
114
|
+
];
|
|
115
|
+
const TINT_ON = 'var(--tabbar-hover-tint)';
|
|
116
|
+
const TINT_OFF = 'var(--color-transparent)';
|
|
117
|
+
|
|
118
|
+
let tintOn = $derived.by(() => {
|
|
119
|
+
const ref = $editorState.components.tabbar?.aliases['--tabbar-hover-tint-enabled'];
|
|
120
|
+
return (ref?.kind === 'literal' ? ref.value : TINT_OFF) === TINT_ON;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
function setTintOn(checked: boolean) {
|
|
124
|
+
setComponentAlias('tabbar', '--tabbar-hover-tint-enabled', {
|
|
125
|
+
kind: 'literal',
|
|
126
|
+
value: checked ? TINT_ON : TINT_OFF,
|
|
127
|
+
});
|
|
128
|
+
for (const [hover, base] of HOVER_SWAPS) {
|
|
129
|
+
if (checked) setComponentAlias('tabbar', hover, { kind: 'token', name: base });
|
|
130
|
+
else clearComponentAlias('tabbar', hover);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
92
133
|
|
|
93
134
|
let selectedDemoTab = $state('overview');
|
|
94
135
|
const demoTabs = [
|
|
@@ -101,7 +142,12 @@
|
|
|
101
142
|
let linked = $derived(computeLinkedBlock(component, linkableContexts, allTokens, $editorState));
|
|
102
143
|
|
|
103
144
|
let visibleStates = $derived(Object.fromEntries(
|
|
104
|
-
Object.entries(states).map(([name, list]) => [
|
|
145
|
+
Object.entries(states).map(([name, list]) => [
|
|
146
|
+
name,
|
|
147
|
+
withLinkedDisabled(list, linked.varSet).map((t) =>
|
|
148
|
+
tintOn && t.variable.endsWith('-hover-surface') ? { ...t, disabled: true } : t,
|
|
149
|
+
),
|
|
150
|
+
]),
|
|
105
151
|
) as Record<string, Token[]>);
|
|
106
152
|
</script>
|
|
107
153
|
|
|
@@ -114,6 +160,20 @@
|
|
|
114
160
|
{component}
|
|
115
161
|
|
|
116
162
|
>
|
|
163
|
+
{#snippet extraPropertyRows(stateName)}
|
|
164
|
+
{#if stateName === 'hover tab'}
|
|
165
|
+
<div class="property-row" data-token-variables="--tabbar-hover-tint-enabled">
|
|
166
|
+
<span class="property-label">tint layer</span>
|
|
167
|
+
<Toggle checked={tintOn} onchange={setTintOn} />
|
|
168
|
+
</div>
|
|
169
|
+
{#if tintOn}
|
|
170
|
+
<div class="property-row">
|
|
171
|
+
<span class="property-label">tint color</span>
|
|
172
|
+
<UIPaletteSelector variable="--tabbar-hover-tint" {component} showNone={false} />
|
|
173
|
+
</div>
|
|
174
|
+
{/if}
|
|
175
|
+
{/if}
|
|
176
|
+
{/snippet}
|
|
117
177
|
{#snippet children({ activeState })}
|
|
118
178
|
{@const forceClass = activeState === 'hover tab' ? 'force-hover' : ''}
|
|
119
179
|
<TabBar tabs={demoTabs} selectedTab={selectedDemoTab} class={forceClass} on:tabChange={(e) => (selectedDemoTab = e.detail)} />
|
|
@@ -19,6 +19,7 @@ import MenuSelectEditor, { allTokens as menuSelectTokens } from './MenuSelectEdi
|
|
|
19
19
|
import NotificationEditor, { allTokens as notificationTokens } from './NotificationEditor.svelte';
|
|
20
20
|
import PanelEditor, { allTokens as panelTokens } from './PanelEditor.svelte';
|
|
21
21
|
import ProgressBarEditor, { allTokens as progressBarTokens } from './ProgressBarEditor.svelte';
|
|
22
|
+
import SliderEditor, { allTokens as sliderTokens } from './SliderEditor.svelte';
|
|
22
23
|
import RadioButtonEditor, { allTokens as radioButtonTokens } from './RadioButtonEditor.svelte';
|
|
23
24
|
import SectionDividerEditor, { allTokens as sectionDividerTokens, intrinsics as sectionDividerIntrinsics } from './SectionDividerEditor.svelte';
|
|
24
25
|
import SegmentedControlEditor, { allTokens as segmentedControlTokens } from './SegmentedControlEditor.svelte';
|
|
@@ -320,6 +321,15 @@ const builtInRegistry: Readonly<Record<BuiltInComponentId, RegistryEntry>> = Obj
|
|
|
320
321
|
schema: progressBarTokens,
|
|
321
322
|
origin: 'system',
|
|
322
323
|
},
|
|
324
|
+
slider: {
|
|
325
|
+
id: 'slider',
|
|
326
|
+
label: 'Slider',
|
|
327
|
+
icon: 'fas fa-sliders',
|
|
328
|
+
sourceFile: 'src/system/components/Slider.svelte',
|
|
329
|
+
editorComponent: SliderEditor,
|
|
330
|
+
schema: sliderTokens,
|
|
331
|
+
origin: 'system',
|
|
332
|
+
},
|
|
323
333
|
});
|
|
324
334
|
|
|
325
335
|
/** Mutable map of consumer-registered components, populated by `registerComponent()`. */
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
productionTheme,
|
|
30
30
|
} from '../../core/productionPulse';
|
|
31
31
|
import {
|
|
32
|
-
|
|
32
|
+
adoptTheme,
|
|
33
33
|
getActiveTheme,
|
|
34
34
|
getProductionTheme,
|
|
35
35
|
listThemes,
|
|
@@ -239,7 +239,7 @@
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
/**
|
|
242
|
-
* Adopt ships the whole
|
|
242
|
+
* Adopt ships the whole theme, because production is one saved theme: flush
|
|
243
243
|
* this component, save the open theme, publish it. The protected Default
|
|
244
244
|
* theme cannot record what shipped, so it prompts for a theme name first and
|
|
245
245
|
* retries.
|
|
@@ -261,7 +261,7 @@
|
|
|
261
261
|
try {
|
|
262
262
|
if (wasDirty) await persist();
|
|
263
263
|
await saveActiveTheme();
|
|
264
|
-
await
|
|
264
|
+
await adoptTheme();
|
|
265
265
|
await refreshProduction();
|
|
266
266
|
bumpProductionRevision();
|
|
267
267
|
adoptFeedback = wasDirty
|
|
@@ -401,7 +401,7 @@
|
|
|
401
401
|
</UISquareButton>
|
|
402
402
|
<UIInfoPopover title="Component Configuration" ariaLabel="About Save and Adopt">
|
|
403
403
|
<p>
|
|
404
|
-
<strong>Save</strong> keeps your edits in the theme you have open. The theme carries a copy of every component you changed, so the
|
|
404
|
+
<strong>Save</strong> keeps your edits in the theme you have open. The theme carries a copy of every component you changed, so the theme travels as one file.
|
|
405
405
|
</p>
|
|
406
406
|
<p>
|
|
407
407
|
<strong>Save As</strong> writes the component's settings to a file of their own, ready to load into any theme.
|
|
@@ -21,36 +21,59 @@ export type TokenKind =
|
|
|
21
21
|
| 'easing'
|
|
22
22
|
| 'text-color';
|
|
23
23
|
|
|
24
|
-
/** Suffix
|
|
25
|
-
editor's selector layout
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
{ kind: '
|
|
40
|
-
{ kind: '
|
|
41
|
-
{ kind: '
|
|
42
|
-
{ kind: '
|
|
43
|
-
{ kind: '
|
|
44
|
-
|
|
45
|
-
{ kind: '
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
{ kind: '
|
|
49
|
-
{ kind: '
|
|
50
|
-
{ kind: '
|
|
51
|
-
{ kind: '
|
|
24
|
+
/** Suffix and prefix data mapped to kinds — the one source of truth for the
|
|
25
|
+
editor's selector layout, the `adjust` CLI, and `check-component`'s naming
|
|
26
|
+
rule, so the three cannot drift. `bin/check-component.mjs` reads the
|
|
27
|
+
`suffix:` arrays out of this file, which is why they are plain literals.
|
|
28
|
+
|
|
29
|
+
Order matters: `-text` must run before `-border`/`-surface`, and
|
|
30
|
+
`-accent-width` before `-accent`, because the first match wins. A variable
|
|
31
|
+
matching nothing falls through to `text-color` (a palette picker), but that
|
|
32
|
+
fall-through is a smell — `check-component` rejects an unrecognised suffix,
|
|
33
|
+
so add the name here rather than letting it drift. */
|
|
34
|
+
export const KIND_RULES: ReadonlyArray<{
|
|
35
|
+
kind: TokenKind;
|
|
36
|
+
suffix?: readonly string[];
|
|
37
|
+
prefix?: readonly string[];
|
|
38
|
+
}> = [
|
|
39
|
+
{ kind: 'font-family', suffix: ['-font-family'] },
|
|
40
|
+
{ kind: 'font-weight', suffix: ['-font-weight'] },
|
|
41
|
+
{ kind: 'font-size', suffix: ['-font-size', '-icon-size', '-thumb-size'] },
|
|
42
|
+
{ kind: 'line-height', suffix: ['-line-height'] },
|
|
43
|
+
{ kind: 'letter-spacing', suffix: ['-letter-spacing'] },
|
|
44
|
+
// Element-named colour roles: the property *is* the element it paints.
|
|
45
|
+
{ kind: 'text-color', suffix: ['-text', '-label', '-icon', '-title', '-body', '-eyebrow',
|
|
46
|
+
'-description', '-hint', '-error', '-placeholder', '-value'],
|
|
47
|
+
prefix: ['--text-'] },
|
|
48
|
+
{ kind: 'radius', suffix: ['-radius'], prefix: ['--radius-'] },
|
|
49
|
+
{ kind: 'divider-width', suffix: ['-divider-width', '-divider-thickness'] },
|
|
50
|
+
{ kind: 'divider-height', suffix: ['-divider-height', '-track-height'] },
|
|
51
|
+
{ kind: 'divider-inset', suffix: ['-divider-inset', '-inset'] },
|
|
52
|
+
{ kind: 'dot-size', suffix: ['-dot-size'] },
|
|
53
|
+
{ kind: 'blur', suffix: ['-blur'], prefix: ['--blur-'] },
|
|
54
|
+
{ kind: 'scale', suffix: ['-scale'], prefix: ['--scale-'] },
|
|
55
|
+
{ kind: 'shadow', suffix: ['-shadow'], prefix: ['--shadow-'] },
|
|
56
|
+
{ kind: 'padding', suffix: ['-padding', '-margin'] },
|
|
57
|
+
{ kind: 'gap', suffix: ['-gap'] },
|
|
58
|
+
{ kind: 'duration', suffix: ['-duration'], prefix: ['--duration-'] },
|
|
59
|
+
{ kind: 'easing', suffix: ['-easing'], prefix: ['--ease-'] },
|
|
60
|
+
{ kind: 'border-width', suffix: ['-border-width', '-accent-width', '-hairline-thickness', '-thickness'],
|
|
61
|
+
prefix: ['--border-width-'] },
|
|
62
|
+
{ kind: 'border', suffix: ['-border'], prefix: ['--border-'] },
|
|
63
|
+
// Fills. A tint is a wash over a surface, so it takes the surface picker: the
|
|
64
|
+
// full palette with an alpha, not just the tint stops it defaults to.
|
|
65
|
+
{ kind: 'surface', suffix: ['-surface', '-fill', '-divider', '-background', '-indicator',
|
|
66
|
+
'-thumb', '-accent', '-color', '-tint', '-opacity',
|
|
67
|
+
'-width', '-height', '-size'],
|
|
68
|
+
prefix: ['--surface-', '--tint', '--color-'] },
|
|
52
69
|
];
|
|
53
70
|
|
|
71
|
+
export const KIND_PATTERNS: ReadonlyArray<{ kind: TokenKind; matches: (v: string) => boolean }> =
|
|
72
|
+
KIND_RULES.map(({ kind, suffix = [], prefix = [] }) => ({
|
|
73
|
+
kind,
|
|
74
|
+
matches: (v: string) => suffix.some((s) => v.endsWith(s)) || prefix.some((p) => v.startsWith(p)),
|
|
75
|
+
}));
|
|
76
|
+
|
|
54
77
|
export function rawKind(variable: string): TokenKind {
|
|
55
78
|
for (const { kind, matches } of KIND_PATTERNS) {
|
|
56
79
|
if (matches(variable)) return kind;
|