@motion-proto/live-tokens 0.9.0 → 0.10.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/README.md +50 -29
- package/dist-plugin/index.cjs +177 -125
- package/dist-plugin/index.d.cts +3 -2
- package/dist-plugin/index.d.ts +3 -2
- package/dist-plugin/index.js +177 -125
- package/package.json +4 -1
- package/src/editor/component-editor/BadgeEditor.svelte +44 -42
- package/src/editor/component-editor/ButtonEditor.svelte +224 -0
- package/src/editor/component-editor/CollapsibleSectionEditor.svelte +1 -7
- package/src/editor/component-editor/CornerBadgeEditor.svelte +44 -34
- package/src/editor/component-editor/ImageLightboxEditor.svelte +58 -0
- package/src/editor/component-editor/InputEditor.svelte +272 -0
- package/src/editor/component-editor/NotificationEditor.svelte +44 -65
- package/src/editor/component-editor/ProgressBarEditor.svelte +71 -87
- package/src/editor/component-editor/SegmentedControlEditor.svelte +98 -37
- package/src/editor/component-editor/SideNavigationEditor.svelte +342 -0
- package/src/editor/component-editor/registry.ts +35 -2
- package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +3 -2
- package/src/editor/component-editor/scaffolding/StateBlock.svelte +9 -10
- package/src/editor/component-editor/scaffolding/TokenLayout.svelte +60 -36
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +38 -1
- package/src/editor/component-editor/scaffolding/buildTypeGroupTokens.ts +1 -1
- package/src/editor/component-editor/scaffolding/siblings.ts +2 -2
- package/src/editor/component-editor/scaffolding/types.ts +2 -1
- package/src/editor/core/components/componentConfigService.ts +7 -6
- package/src/editor/core/manifests/manifestService.ts +5 -4
- package/src/editor/core/storage/apiBase.ts +15 -0
- package/src/editor/core/storage/files/versionedFileResourceClient.ts +1 -1
- package/src/editor/core/themes/migrations/2026-05-24-collapsiblesection-drop-active-state.ts +28 -0
- package/src/editor/core/themes/migrations/2026-05-24-progressbar-collapse-variants.ts +41 -0
- package/src/editor/core/themes/migrations/2026-05-24-promote-state-shared-tokens.ts +59 -0
- package/src/editor/core/themes/migrations/2026-05-24-segmentedcontrol-divider-inset.ts +29 -0
- package/src/editor/core/themes/migrations/2026-05-25-cornerbadge-flatten-variants.ts +46 -0
- package/src/editor/core/themes/migrations/index.ts +10 -0
- package/src/editor/core/themes/themeInit.ts +3 -2
- package/src/editor/core/themes/themeService.ts +3 -2
- package/src/editor/ui/UIEasingSelector.svelte +240 -0
- package/src/editor/ui/variantScales.ts +34 -0
- package/src/system/components/Button.svelte +34 -85
- package/src/system/components/CollapsibleSection.svelte +1 -48
- package/src/system/components/CornerBadge.svelte +72 -138
- package/src/system/components/ImageLightbox.svelte +578 -0
- package/src/system/components/Input.svelte +387 -0
- package/src/system/components/ProgressBar.svelte +62 -258
- package/src/system/components/SegmentedControl.svelte +81 -15
- package/src/system/components/SideNavigation.svelte +777 -0
- package/src/system/styles/tokens.css +43 -0
- package/src/system/styles/tokens.generated.css +4 -183
- package/src/editor/component-editor/StandardButtonsEditor.svelte +0 -190
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { buildTypeGroupTokens, buildTypeGroupShareableContexts } from './scaffolding/buildTypeGroupTokens';
|
|
3
|
+
import type { Token, TypeGroupConfig } from './scaffolding/types';
|
|
4
|
+
|
|
5
|
+
export const component = 'input';
|
|
6
|
+
|
|
7
|
+
// Shape lives under a `field` pseudo-state so it reads as one decision shared by every state.
|
|
8
|
+
// Default/focused/disabled hold the per-state chrome; label/hint/error hold message-row typography.
|
|
9
|
+
// Error also carries the invalid-state border so it sits next to the error text it pairs with.
|
|
10
|
+
const states: Record<string, Token[]> = {
|
|
11
|
+
field: [
|
|
12
|
+
{ label: 'corner radius', groupKey: 'radius', variable: '--input-radius' },
|
|
13
|
+
{ label: 'border width', groupKey: 'border-width', variable: '--input-border-width' },
|
|
14
|
+
{ label: 'padding', variable: '--input-padding', groupKey: 'padding' },
|
|
15
|
+
{ label: 'padding-top', variable: '--input-padding-top', groupKey: 'padding-top', hidden: true },
|
|
16
|
+
{ label: 'padding-right', variable: '--input-padding-right', groupKey: 'padding-right', hidden: true },
|
|
17
|
+
{ label: 'padding-bottom', variable: '--input-padding-bottom', groupKey: 'padding-bottom', hidden: true },
|
|
18
|
+
{ label: 'padding-left', variable: '--input-padding-left', groupKey: 'padding-left', hidden: true },
|
|
19
|
+
{ label: 'message gap', groupKey: 'gap', variable: '--input-gap' },
|
|
20
|
+
],
|
|
21
|
+
default: [
|
|
22
|
+
{ label: 'surface color', groupKey: 'surface', variable: '--input-default-surface' },
|
|
23
|
+
{ label: 'border color', groupKey: 'border', variable: '--input-default-border' },
|
|
24
|
+
{ label: 'placeholder color', groupKey: 'placeholder', variable: '--input-default-placeholder' },
|
|
25
|
+
{ label: 'icon color', groupKey: 'icon', variable: '--input-default-icon' },
|
|
26
|
+
{ label: 'icon size', canBeLinked: true, groupKey: 'icon-size', variable: '--input-default-icon-size' },
|
|
27
|
+
],
|
|
28
|
+
focused: [
|
|
29
|
+
{ label: 'surface color', groupKey: 'surface', variable: '--input-focused-surface' },
|
|
30
|
+
{ label: 'border color', groupKey: 'border', variable: '--input-focused-border' },
|
|
31
|
+
{ label: 'border width', canBeLinked: true, groupKey: 'border-width', variable: '--input-focused-border-width' },
|
|
32
|
+
{ label: 'icon color', groupKey: 'icon', variable: '--input-focused-icon' },
|
|
33
|
+
{ label: 'icon size', canBeLinked: true, groupKey: 'icon-size', variable: '--input-focused-icon-size' },
|
|
34
|
+
],
|
|
35
|
+
disabled: [
|
|
36
|
+
{ label: 'surface color', groupKey: 'surface', variable: '--input-disabled-surface' },
|
|
37
|
+
{ label: 'border color', groupKey: 'border', variable: '--input-disabled-border' },
|
|
38
|
+
{ label: 'icon color', groupKey: 'icon', variable: '--input-disabled-icon' },
|
|
39
|
+
{ label: 'icon size', canBeLinked: true, groupKey: 'icon-size', variable: '--input-disabled-icon-size' },
|
|
40
|
+
],
|
|
41
|
+
label: [],
|
|
42
|
+
hint: [],
|
|
43
|
+
error: [
|
|
44
|
+
{ label: 'border color', groupKey: 'border', variable: '--input-error-border' },
|
|
45
|
+
{ label: 'border width', canBeLinked: true, groupKey: 'border-width', variable: '--input-error-border-width' },
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Per-state input text + standalone label/hint/error message typography.
|
|
50
|
+
// Slot-prefixed groupKeys keep label/hint/error from collapsing into each other.
|
|
51
|
+
const typeGroups: Record<string, TypeGroupConfig[]> = {
|
|
52
|
+
default: [{
|
|
53
|
+
legend: 'input text',
|
|
54
|
+
colorVariable: '--input-default-text',
|
|
55
|
+
familyVariable: '--input-default-text-font-family',
|
|
56
|
+
sizeVariable: '--input-default-text-font-size',
|
|
57
|
+
weightVariable: '--input-default-text-font-weight',
|
|
58
|
+
lineHeightVariable: '--input-default-text-line-height',
|
|
59
|
+
}],
|
|
60
|
+
focused: [{
|
|
61
|
+
legend: 'input text',
|
|
62
|
+
colorVariable: '--input-focused-text',
|
|
63
|
+
familyVariable: '--input-focused-text-font-family',
|
|
64
|
+
sizeVariable: '--input-focused-text-font-size',
|
|
65
|
+
weightVariable: '--input-focused-text-font-weight',
|
|
66
|
+
lineHeightVariable: '--input-focused-text-line-height',
|
|
67
|
+
}],
|
|
68
|
+
disabled: [{
|
|
69
|
+
legend: 'input text',
|
|
70
|
+
colorVariable: '--input-disabled-text',
|
|
71
|
+
familyVariable: '--input-disabled-text-font-family',
|
|
72
|
+
sizeVariable: '--input-disabled-text-font-size',
|
|
73
|
+
weightVariable: '--input-disabled-text-font-weight',
|
|
74
|
+
lineHeightVariable: '--input-disabled-text-line-height',
|
|
75
|
+
}],
|
|
76
|
+
label: [{
|
|
77
|
+
legend: 'label',
|
|
78
|
+
colorVariable: '--input-label',
|
|
79
|
+
familyVariable: '--input-label-font-family',
|
|
80
|
+
sizeVariable: '--input-label-font-size',
|
|
81
|
+
weightVariable: '--input-label-font-weight',
|
|
82
|
+
lineHeightVariable: '--input-label-line-height',
|
|
83
|
+
}],
|
|
84
|
+
hint: [{
|
|
85
|
+
legend: 'hint',
|
|
86
|
+
colorVariable: '--input-hint',
|
|
87
|
+
familyVariable: '--input-hint-font-family',
|
|
88
|
+
sizeVariable: '--input-hint-font-size',
|
|
89
|
+
weightVariable: '--input-hint-font-weight',
|
|
90
|
+
lineHeightVariable: '--input-hint-line-height',
|
|
91
|
+
}],
|
|
92
|
+
error: [{
|
|
93
|
+
legend: 'error',
|
|
94
|
+
colorVariable: '--input-error',
|
|
95
|
+
familyVariable: '--input-error-font-family',
|
|
96
|
+
sizeVariable: '--input-error-font-size',
|
|
97
|
+
weightVariable: '--input-error-font-weight',
|
|
98
|
+
lineHeightVariable: '--input-error-line-height',
|
|
99
|
+
}],
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// Slot-prefixed groupKeys: input text links across default/focused/disabled;
|
|
103
|
+
// label/hint/error each isolate their own typography.
|
|
104
|
+
const inputTextStates = ['default', 'focused', 'disabled'] as const;
|
|
105
|
+
const inputTextTypographyTokens: Token[] = inputTextStates.flatMap((s) => [
|
|
106
|
+
{ label: 'font family', canBeLinked: true, groupKey: 'input-text-font-family', variable: `--input-${s}-text-font-family` },
|
|
107
|
+
{ label: 'font size', canBeLinked: true, groupKey: 'input-text-font-size', variable: `--input-${s}-text-font-size` },
|
|
108
|
+
{ label: 'font weight', canBeLinked: true, groupKey: 'input-text-font-weight', variable: `--input-${s}-text-font-weight` },
|
|
109
|
+
{ label: 'line height', canBeLinked: true, groupKey: 'input-text-line-height', variable: `--input-${s}-text-line-height` },
|
|
110
|
+
]);
|
|
111
|
+
|
|
112
|
+
const messageTypographyTokens: Token[] = (['label', 'hint', 'error'] as const).flatMap((slot) => [
|
|
113
|
+
{ label: 'font family', canBeLinked: true, groupKey: `${slot}-font-family`, variable: `--input-${slot}-font-family` },
|
|
114
|
+
{ label: 'font size', canBeLinked: true, groupKey: `${slot}-font-size`, variable: `--input-${slot}-font-size` },
|
|
115
|
+
{ label: 'font weight', canBeLinked: true, groupKey: `${slot}-font-weight`, variable: `--input-${slot}-font-weight` },
|
|
116
|
+
{ label: 'line height', canBeLinked: true, groupKey: `${slot}-line-height`, variable: `--input-${slot}-line-height` },
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
// colorVariable tokens from buildTypeGroupTokens are derivable but redundant — hand-built typography
|
|
120
|
+
// gives us full control. Use buildTypeGroupShareableContexts for the linkableContexts wiring only.
|
|
121
|
+
// Take the color tokens via buildTypeGroupTokens-equivalent: just enumerate them inline.
|
|
122
|
+
const typographyColorTokens: Token[] = [
|
|
123
|
+
{ label: 'color', groupKey: 'text', variable: '--input-default-text' },
|
|
124
|
+
{ label: 'color', groupKey: 'text', variable: '--input-focused-text' },
|
|
125
|
+
{ label: 'color', groupKey: 'text', variable: '--input-disabled-text' },
|
|
126
|
+
{ label: 'color', groupKey: 'label', variable: '--input-label' },
|
|
127
|
+
{ label: 'color', groupKey: 'hint', variable: '--input-hint' },
|
|
128
|
+
{ label: 'color', groupKey: 'error', variable: '--input-error' },
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
export const allTokens: Token[] = [
|
|
132
|
+
...Object.values(states).flat(),
|
|
133
|
+
...typographyColorTokens,
|
|
134
|
+
...inputTextTypographyTokens,
|
|
135
|
+
...messageTypographyTokens,
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
const linkableContexts = new Map<string, string>([
|
|
139
|
+
...buildTypeGroupShareableContexts(typeGroups),
|
|
140
|
+
['--input-default-icon-size', 'default'],
|
|
141
|
+
['--input-focused-icon-size', 'focused'],
|
|
142
|
+
['--input-disabled-icon-size', 'disabled'],
|
|
143
|
+
['--input-focused-border-width', 'focused'],
|
|
144
|
+
['--input-error-border-width', 'error'],
|
|
145
|
+
]);
|
|
146
|
+
|
|
147
|
+
// Silence unused-import lint without changing behavior; buildTypeGroupTokens stays available
|
|
148
|
+
// for editors that want auto-derived color rows, but we keep ours hand-built for slot-prefixed groupKeys.
|
|
149
|
+
void buildTypeGroupTokens;
|
|
150
|
+
</script>
|
|
151
|
+
|
|
152
|
+
<script lang="ts">
|
|
153
|
+
import Input from '../../system/components/Input.svelte';
|
|
154
|
+
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
155
|
+
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
156
|
+
import { editorState } from '../core/store/editorStore';
|
|
157
|
+
import { computeLinkedBlock, withLinkedDisabled } from './scaffolding/linkedBlock';
|
|
158
|
+
|
|
159
|
+
type InputType = 'text' | 'number' | 'search' | 'password';
|
|
160
|
+
const typeOptions: { value: InputType; label: string }[] = [
|
|
161
|
+
{ value: 'text', label: 'Text' },
|
|
162
|
+
{ value: 'number', label: 'Number' },
|
|
163
|
+
{ value: 'search', label: 'Search' },
|
|
164
|
+
{ value: 'password', label: 'Password' },
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
let previewType: InputType = $state('text');
|
|
168
|
+
let showLabel = $state(true);
|
|
169
|
+
let showHint = $state(true);
|
|
170
|
+
let showError = $state(false);
|
|
171
|
+
|
|
172
|
+
let demoValue = $state('');
|
|
173
|
+
|
|
174
|
+
let placeholderFor = $derived((t: InputType) => {
|
|
175
|
+
switch (t) {
|
|
176
|
+
case 'number': return '0';
|
|
177
|
+
case 'search': return 'Search…';
|
|
178
|
+
case 'password': return 'Enter password';
|
|
179
|
+
default: return 'Type something';
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
let linked = $derived(computeLinkedBlock(component, linkableContexts, allTokens, $editorState));
|
|
184
|
+
|
|
185
|
+
let visibleStates = $derived(Object.fromEntries(
|
|
186
|
+
Object.entries(states).map(([name, list]) => [name, withLinkedDisabled(list, linked.varSet)]),
|
|
187
|
+
) as Record<string, Token[]>);
|
|
188
|
+
</script>
|
|
189
|
+
|
|
190
|
+
<ComponentEditorBase
|
|
191
|
+
{component}
|
|
192
|
+
title="Input"
|
|
193
|
+
description="Single-line text/number/search/password input with optional label, hint, and validation error."
|
|
194
|
+
tokens={allTokens}
|
|
195
|
+
{linked}
|
|
196
|
+
>
|
|
197
|
+
<VariantGroup
|
|
198
|
+
name="input"
|
|
199
|
+
title="Input"
|
|
200
|
+
states={visibleStates}
|
|
201
|
+
{typeGroups}
|
|
202
|
+
{component}
|
|
203
|
+
>
|
|
204
|
+
{#snippet canvasToolbarExtras()}
|
|
205
|
+
<hr class="canvas-toolbar-divider" />
|
|
206
|
+
<label class="toolbar-field">
|
|
207
|
+
<span>Type</span>
|
|
208
|
+
<select class="canvas-toolbar-select" bind:value={previewType}>
|
|
209
|
+
{#each typeOptions as opt}
|
|
210
|
+
<option value={opt.value}>{opt.label}</option>
|
|
211
|
+
{/each}
|
|
212
|
+
</select>
|
|
213
|
+
</label>
|
|
214
|
+
<label class="toolbar-check">
|
|
215
|
+
<input type="checkbox" bind:checked={showLabel} />
|
|
216
|
+
<span>Label</span>
|
|
217
|
+
</label>
|
|
218
|
+
<label class="toolbar-check">
|
|
219
|
+
<input type="checkbox" bind:checked={showHint} />
|
|
220
|
+
<span>Hint</span>
|
|
221
|
+
</label>
|
|
222
|
+
<label class="toolbar-check">
|
|
223
|
+
<input type="checkbox" bind:checked={showError} />
|
|
224
|
+
<span>Error</span>
|
|
225
|
+
</label>
|
|
226
|
+
{/snippet}
|
|
227
|
+
{#snippet children({ activeState })}
|
|
228
|
+
{@const forceFocus = activeState === 'focused'}
|
|
229
|
+
{@const previewDisabled = activeState === 'disabled'}
|
|
230
|
+
{@const previewError = showError || activeState === 'error' ? 'Please enter a valid value.' : ''}
|
|
231
|
+
{@const previewHint = showHint || activeState === 'hint' ? 'Helper text describing the field.' : ''}
|
|
232
|
+
{@const previewLabel = showLabel || activeState === 'label' ? 'Field label' : ''}
|
|
233
|
+
<div class="input-demo-row">
|
|
234
|
+
<Input
|
|
235
|
+
type={previewType}
|
|
236
|
+
bind:value={demoValue}
|
|
237
|
+
placeholder={placeholderFor(previewType)}
|
|
238
|
+
disabled={previewDisabled}
|
|
239
|
+
{forceFocus}
|
|
240
|
+
label={previewLabel}
|
|
241
|
+
hint={previewHint}
|
|
242
|
+
error={previewError}
|
|
243
|
+
/>
|
|
244
|
+
</div>
|
|
245
|
+
{/snippet}
|
|
246
|
+
</VariantGroup>
|
|
247
|
+
</ComponentEditorBase>
|
|
248
|
+
|
|
249
|
+
<style>
|
|
250
|
+
.input-demo-row {
|
|
251
|
+
display: flex;
|
|
252
|
+
width: 100%;
|
|
253
|
+
max-width: 26rem;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.toolbar-check {
|
|
257
|
+
display: inline-flex;
|
|
258
|
+
align-items: center;
|
|
259
|
+
gap: var(--ui-space-6);
|
|
260
|
+
font-size: var(--ui-font-size-sm);
|
|
261
|
+
color: rgba(255, 255, 255, 0.78);
|
|
262
|
+
cursor: pointer;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.toolbar-field {
|
|
266
|
+
display: flex;
|
|
267
|
+
flex-direction: column;
|
|
268
|
+
gap: var(--ui-space-4);
|
|
269
|
+
font-size: var(--ui-font-size-xs);
|
|
270
|
+
color: rgba(255, 255, 255, 0.6);
|
|
271
|
+
}
|
|
272
|
+
</style>
|
|
@@ -1,80 +1,60 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import type { Token, TypeGroupConfig } from './scaffolding/types';
|
|
2
|
+
import type { Token } from './scaffolding/types';
|
|
4
3
|
|
|
5
4
|
export const component = 'notification';
|
|
6
5
|
const variants = ['info', 'success', 'warning', 'danger'] as const;
|
|
7
6
|
type Variant = typeof variants[number];
|
|
8
7
|
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
|
|
8
|
+
// Base part: notification chrome, icon sizing, and both typography stacks.
|
|
9
|
+
// Tagged with `element` so StateBlock partitions the panel into labeled
|
|
10
|
+
// `frame`, `title`, and `body` subsections — the title/body split mirrors the
|
|
11
|
+
// runtime's two type stacks. Section labels mean per-row labels can stay short
|
|
12
|
+
// ('font family', not 'title font family').
|
|
13
|
+
function variantBaseTokens(v: Variant): Token[] {
|
|
14
|
+
return [
|
|
15
|
+
{ label: 'padding', canBeLinked: true, groupKey: 'padding', variable: `--notification-${v}-padding`, element: 'frame' },
|
|
16
|
+
{ label: 'corner radius', canBeLinked: true, groupKey: 'radius', variable: `--notification-${v}-radius`, element: 'frame' },
|
|
17
|
+
{ label: 'border width', canBeLinked: true, groupKey: 'border-width', variable: `--notification-${v}-border-width`, element: 'frame' },
|
|
18
|
+
{ label: 'icon size', canBeLinked: true, groupKey: 'icon-size', variable: `--notification-${v}-icon-size`, element: 'frame' },
|
|
19
|
+
{ label: 'font family', canBeLinked: true, groupKey: 'title-font-family', variable: `--notification-${v}-title-font-family`, element: 'title' },
|
|
20
|
+
{ label: 'font size', canBeLinked: true, groupKey: 'title-font-size', variable: `--notification-${v}-title-font-size`, element: 'title' },
|
|
21
|
+
{ label: 'font weight', canBeLinked: true, groupKey: 'title-font-weight', variable: `--notification-${v}-title-font-weight`, element: 'title' },
|
|
22
|
+
{ label: 'line height', canBeLinked: true, groupKey: 'title-line-height', variable: `--notification-${v}-title-line-height`, element: 'title' },
|
|
23
|
+
{ label: 'font family', canBeLinked: true, groupKey: 'text-font-family', variable: `--notification-${v}-text-font-family`, element: 'body' },
|
|
24
|
+
{ label: 'font size', canBeLinked: true, groupKey: 'text-font-size', variable: `--notification-${v}-text-font-size`, element: 'body' },
|
|
25
|
+
{ label: 'font weight', canBeLinked: true, groupKey: 'text-font-weight', variable: `--notification-${v}-text-font-weight`, element: 'body' },
|
|
26
|
+
{ label: 'line height', canBeLinked: true, groupKey: 'text-line-height', variable: `--notification-${v}-text-line-height`, element: 'body' },
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Colors part: the six shades that distinguish info/success/warning/danger.
|
|
31
|
+
function variantColorTokens(v: Variant): Token[] {
|
|
12
32
|
return [
|
|
13
33
|
{ label: 'surface color', groupKey: 'surface', variable: `--notification-${v}-surface` },
|
|
14
34
|
{ label: 'action surface', groupKey: 'action-surface', variable: `--notification-${v}-action-surface` },
|
|
15
35
|
{ label: 'border color', groupKey: 'border', variable: `--notification-${v}-border` },
|
|
16
|
-
{ label: 'border width', canBeLinked: true, groupKey: 'border-width', variable: `--notification-${v}-border-width` },
|
|
17
|
-
{ label: 'corner radius', canBeLinked: true, groupKey: 'radius', variable: `--notification-${v}-radius` },
|
|
18
|
-
{ label: 'padding', canBeLinked: true, groupKey: 'padding', variable: `--notification-${v}-padding` },
|
|
19
36
|
{ label: 'icon color', groupKey: 'icon', variable: `--notification-${v}-icon` },
|
|
20
|
-
{ label: '
|
|
37
|
+
{ label: 'title color', groupKey: 'title', variable: `--notification-${v}-title` },
|
|
38
|
+
{ label: 'body color', groupKey: 'text', variable: `--notification-${v}-text` },
|
|
21
39
|
];
|
|
22
40
|
}
|
|
23
41
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return [
|
|
27
|
-
{
|
|
28
|
-
legend: 'title',
|
|
29
|
-
colorVariable: `--notification-${v}-title`,
|
|
30
|
-
familyVariable: `--notification-${v}-title-font-family`,
|
|
31
|
-
sizeVariable: `--notification-${v}-title-font-size`,
|
|
32
|
-
weightVariable: `--notification-${v}-title-font-weight`,
|
|
33
|
-
lineHeightVariable: `--notification-${v}-title-line-height`,
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
legend: 'body text',
|
|
37
|
-
colorVariable: `--notification-${v}-text`,
|
|
38
|
-
familyVariable: `--notification-${v}-text-font-family`,
|
|
39
|
-
sizeVariable: `--notification-${v}-text-font-size`,
|
|
40
|
-
weightVariable: `--notification-${v}-text-font-weight`,
|
|
41
|
-
lineHeightVariable: `--notification-${v}-text-line-height`,
|
|
42
|
-
},
|
|
43
|
-
];
|
|
44
|
-
}
|
|
45
|
-
function variantTypeGroupTokens(v: Variant): Token[] {
|
|
46
|
-
return [
|
|
47
|
-
{ label: 'font family', canBeLinked: true, groupKey: 'title-font-family', variable: `--notification-${v}-title-font-family` },
|
|
48
|
-
{ label: 'font size', canBeLinked: true, groupKey: 'title-font-size', variable: `--notification-${v}-title-font-size` },
|
|
49
|
-
{ label: 'font weight', canBeLinked: true, groupKey: 'title-font-weight', variable: `--notification-${v}-title-font-weight` },
|
|
50
|
-
{ label: 'line height', canBeLinked: true, groupKey: 'title-line-height', variable: `--notification-${v}-title-line-height` },
|
|
51
|
-
{ label: 'font family', canBeLinked: true, groupKey: 'text-font-family', variable: `--notification-${v}-text-font-family` },
|
|
52
|
-
{ label: 'font size', canBeLinked: true, groupKey: 'text-font-size', variable: `--notification-${v}-text-font-size` },
|
|
53
|
-
{ label: 'font weight', canBeLinked: true, groupKey: 'text-font-weight', variable: `--notification-${v}-text-font-weight` },
|
|
54
|
-
{ label: 'line height', canBeLinked: true, groupKey: 'text-line-height', variable: `--notification-${v}-text-line-height` },
|
|
55
|
-
];
|
|
42
|
+
function variantStates(v: Variant): Record<string, Token[]> {
|
|
43
|
+
return { base: variantBaseTokens(v), colors: variantColorTokens(v) };
|
|
56
44
|
}
|
|
45
|
+
|
|
57
46
|
export const allTokens: Token[] = variants.flatMap((v) => [
|
|
58
|
-
...
|
|
59
|
-
...
|
|
60
|
-
...variantTypeGroupTokens(v),
|
|
47
|
+
...variantBaseTokens(v),
|
|
48
|
+
...variantColorTokens(v),
|
|
61
49
|
]);
|
|
62
50
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
[`--notification-${v}-title-font-size`, v] as const,
|
|
71
|
-
[`--notification-${v}-title-font-weight`, v] as const,
|
|
72
|
-
[`--notification-${v}-title-line-height`, v] as const,
|
|
73
|
-
[`--notification-${v}-text-font-family`, v] as const,
|
|
74
|
-
[`--notification-${v}-text-font-size`, v] as const,
|
|
75
|
-
[`--notification-${v}-text-font-weight`, v] as const,
|
|
76
|
-
[`--notification-${v}-text-line-height`, v] as const,
|
|
77
|
-
]));
|
|
51
|
+
const linkableContexts = new Map<string, string>(
|
|
52
|
+
variants.flatMap((v) =>
|
|
53
|
+
variantBaseTokens(v)
|
|
54
|
+
.filter((t) => t.canBeLinked)
|
|
55
|
+
.map((t) => [t.variable, `${v} base`] as [string, string]),
|
|
56
|
+
),
|
|
57
|
+
);
|
|
78
58
|
|
|
79
59
|
const BUTTON_VARIANT_OPTIONS = ['none', 'primary', 'secondary', 'outline', 'success', 'danger', 'warning'] as const;
|
|
80
60
|
type ButtonVariantOption = typeof BUTTON_VARIANT_OPTIONS[number];
|
|
@@ -98,7 +78,9 @@
|
|
|
98
78
|
import { buildSiblings } from './scaffolding/siblings';
|
|
99
79
|
|
|
100
80
|
let linked = $derived(computeLinkedBlock(component, linkableContexts, allTokens, $editorState));
|
|
101
|
-
let
|
|
81
|
+
let visibleVariantStates = $derived((v: Variant) => Object.fromEntries(
|
|
82
|
+
Object.entries(variantStates(v)).map(([name, list]) => [name, withLinkedDisabled(list, linked.varSet)]),
|
|
83
|
+
) as Record<string, Token[]>);
|
|
102
84
|
|
|
103
85
|
import type { NotificationActions } from '../../system/components/types';
|
|
104
86
|
|
|
@@ -120,10 +102,9 @@
|
|
|
120
102
|
<VariantGroup
|
|
121
103
|
name={v}
|
|
122
104
|
title={v.charAt(0).toUpperCase() + v.slice(1)}
|
|
123
|
-
states={
|
|
124
|
-
typeGroups={{ [v]: variantTypeGroups(v) }}
|
|
105
|
+
states={visibleVariantStates(v)}
|
|
125
106
|
{component}
|
|
126
|
-
siblings={buildSiblings(variants, v,
|
|
107
|
+
siblings={buildSiblings(variants, v, variantStates)}
|
|
127
108
|
>
|
|
128
109
|
{#snippet canvasToolbarExtras()}
|
|
129
110
|
<hr class="canvas-toolbar-divider" />
|
|
@@ -186,6 +167,4 @@
|
|
|
186
167
|
font-size: var(--ui-font-size-xs);
|
|
187
168
|
color: rgba(255, 255, 255, 0.6);
|
|
188
169
|
}
|
|
189
|
-
|
|
190
170
|
</style>
|
|
191
|
-
|
|
@@ -3,76 +3,72 @@
|
|
|
3
3
|
import type { Token, TypeGroupConfig } from './scaffolding/types';
|
|
4
4
|
|
|
5
5
|
export const component = 'progressbar';
|
|
6
|
-
const variants = ['primary', 'success', 'warning', 'danger', 'info'] as const;
|
|
7
|
-
type Variant = typeof variants[number];
|
|
8
6
|
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
{ label: '
|
|
14
|
-
{ label: 'track
|
|
15
|
-
{ label: 'track border
|
|
16
|
-
{ label: '
|
|
17
|
-
{ label: '
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
// Single-variant component: fill color is a runtime prop on the consumer side,
|
|
8
|
+
// not a per-variant token namespace.
|
|
9
|
+
const states: Record<string, Token[]> = {
|
|
10
|
+
default: [
|
|
11
|
+
{ label: 'fill color', groupKey: 'fill', variable: '--progressbar-fill' },
|
|
12
|
+
{ label: 'track surface color', groupKey: 'surface', variable: '--progressbar-track-surface' },
|
|
13
|
+
{ label: 'track border color', groupKey: 'border', variable: '--progressbar-track-border' },
|
|
14
|
+
{ label: 'track border width', canBeLinked: true, groupKey: 'track-border-width', variable: '--progressbar-track-border-width' },
|
|
15
|
+
{ label: 'corner radius', canBeLinked: true, groupKey: 'radius', variable: '--progressbar-radius' },
|
|
16
|
+
{ label: 'track height', canBeLinked: true, groupKey: 'track-height', variable: '--progressbar-track-height' },
|
|
17
|
+
{ label: 'label gap', groupKey: 'label-gap', variable: '--progressbar-label-gap' },
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return [
|
|
21
|
+
const typeGroups: Record<string, TypeGroupConfig[]> = {
|
|
22
|
+
default: [
|
|
24
23
|
{
|
|
25
24
|
legend: 'label',
|
|
26
|
-
colorVariable:
|
|
27
|
-
familyVariable:
|
|
28
|
-
sizeVariable:
|
|
29
|
-
weightVariable:
|
|
30
|
-
lineHeightVariable:
|
|
25
|
+
colorVariable: '--progressbar-label',
|
|
26
|
+
familyVariable: '--progressbar-label-font-family',
|
|
27
|
+
sizeVariable: '--progressbar-label-font-size',
|
|
28
|
+
weightVariable: '--progressbar-label-font-weight',
|
|
29
|
+
lineHeightVariable: '--progressbar-label-line-height',
|
|
31
30
|
},
|
|
32
31
|
{
|
|
33
32
|
legend: 'value',
|
|
34
|
-
colorVariable:
|
|
35
|
-
familyVariable:
|
|
36
|
-
sizeVariable:
|
|
37
|
-
weightVariable:
|
|
38
|
-
lineHeightVariable:
|
|
33
|
+
colorVariable: '--progressbar-value',
|
|
34
|
+
familyVariable: '--progressbar-value-font-family',
|
|
35
|
+
sizeVariable: '--progressbar-value-font-size',
|
|
36
|
+
weightVariable: '--progressbar-value-font-weight',
|
|
37
|
+
lineHeightVariable: '--progressbar-value-line-height',
|
|
39
38
|
},
|
|
40
|
-
]
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
export const allTokens: Token[] = variants.flatMap((v) => [
|
|
55
|
-
...variantTokens(v),
|
|
56
|
-
...buildTypeGroupColorTokens(variantTypeGroups(v)),
|
|
57
|
-
...variantTypeGroupTokens(v),
|
|
58
|
-
]);
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const typeGroupTokens: Token[] = [
|
|
43
|
+
{ label: 'font family', canBeLinked: true, groupKey: 'label-font-family', variable: '--progressbar-label-font-family' },
|
|
44
|
+
{ label: 'font size', canBeLinked: true, groupKey: 'label-font-size', variable: '--progressbar-label-font-size' },
|
|
45
|
+
{ label: 'font weight', canBeLinked: true, groupKey: 'label-font-weight', variable: '--progressbar-label-font-weight' },
|
|
46
|
+
{ label: 'line height', canBeLinked: true, groupKey: 'label-line-height', variable: '--progressbar-label-line-height' },
|
|
47
|
+
{ label: 'font family', canBeLinked: true, groupKey: 'value-font-family', variable: '--progressbar-value-font-family' },
|
|
48
|
+
{ label: 'font size', canBeLinked: true, groupKey: 'value-font-size', variable: '--progressbar-value-font-size' },
|
|
49
|
+
{ label: 'font weight', canBeLinked: true, groupKey: 'value-font-weight', variable: '--progressbar-value-font-weight' },
|
|
50
|
+
{ label: 'line height', canBeLinked: true, groupKey: 'value-line-height', variable: '--progressbar-value-line-height' },
|
|
51
|
+
];
|
|
59
52
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
[
|
|
63
|
-
[
|
|
64
|
-
[
|
|
65
|
-
[
|
|
66
|
-
[
|
|
67
|
-
[
|
|
68
|
-
[
|
|
69
|
-
[
|
|
70
|
-
[
|
|
71
|
-
[
|
|
72
|
-
|
|
73
|
-
]));
|
|
53
|
+
const linkableContexts = new Map<string, string>([
|
|
54
|
+
['--progressbar-track-border-width', 'progressbar'],
|
|
55
|
+
['--progressbar-radius', 'progressbar'],
|
|
56
|
+
['--progressbar-track-height', 'progressbar'],
|
|
57
|
+
['--progressbar-label-font-family', 'label'],
|
|
58
|
+
['--progressbar-label-font-size', 'label'],
|
|
59
|
+
['--progressbar-label-font-weight', 'label'],
|
|
60
|
+
['--progressbar-label-line-height', 'label'],
|
|
61
|
+
['--progressbar-value-font-family', 'value'],
|
|
62
|
+
['--progressbar-value-font-size', 'value'],
|
|
63
|
+
['--progressbar-value-font-weight', 'value'],
|
|
64
|
+
['--progressbar-value-line-height', 'value'],
|
|
65
|
+
]);
|
|
74
66
|
|
|
75
|
-
const
|
|
67
|
+
export const allTokens: Token[] = [
|
|
68
|
+
...Object.values(states).flat(),
|
|
69
|
+
...buildTypeGroupColorTokens(typeGroups),
|
|
70
|
+
...typeGroupTokens,
|
|
71
|
+
];
|
|
76
72
|
</script>
|
|
77
73
|
|
|
78
74
|
<script lang="ts">
|
|
@@ -81,37 +77,25 @@
|
|
|
81
77
|
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
82
78
|
import { editorState } from '../core/store/editorStore';
|
|
83
79
|
import { computeLinkedBlock, withLinkedDisabled } from './scaffolding/linkedBlock';
|
|
84
|
-
import { buildSiblings } from './scaffolding/siblings';
|
|
85
80
|
|
|
86
81
|
let linked = $derived(computeLinkedBlock(component, linkableContexts, allTokens, $editorState));
|
|
87
|
-
let
|
|
82
|
+
let visibleStates = $derived(Object.fromEntries(
|
|
83
|
+
Object.entries(states).map(([name, list]) => [name, withLinkedDisabled(list, linked.varSet)]),
|
|
84
|
+
) as Record<string, Token[]>);
|
|
88
85
|
</script>
|
|
89
86
|
|
|
90
|
-
<ComponentEditorBase {component} title="Progress Bar" description="Animated progress bar
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
<ProgressBar value={25} label="Getting Started" variant="primary" />
|
|
103
|
-
{:else if v === 'success'}
|
|
104
|
-
<ProgressBar value={100} label="Complete" variant="success" />
|
|
105
|
-
{:else if v === 'warning'}
|
|
106
|
-
<ProgressBar value={75} label="Almost Done" variant="warning" />
|
|
107
|
-
{:else if v === 'danger'}
|
|
108
|
-
<ProgressBar value={33} label="Danger Zone" variant="danger" />
|
|
109
|
-
{:else if v === 'info'}
|
|
110
|
-
<ProgressBar value={50} label="Halfway There" variant="info" />
|
|
111
|
-
{/if}
|
|
112
|
-
</div>
|
|
113
|
-
</VariantGroup>
|
|
114
|
-
{/each}
|
|
87
|
+
<ComponentEditorBase {component} title="Progress Bar" description="Animated progress bar; consumers pass a fill color via the fill prop." tokens={allTokens} {linked}>
|
|
88
|
+
<VariantGroup
|
|
89
|
+
name="progressbar"
|
|
90
|
+
title="Progress Bar"
|
|
91
|
+
states={visibleStates}
|
|
92
|
+
{typeGroups}
|
|
93
|
+
{component}
|
|
94
|
+
>
|
|
95
|
+
<div class="progress-demo-stack">
|
|
96
|
+
<ProgressBar value={75} label="Loading" />
|
|
97
|
+
</div>
|
|
98
|
+
</VariantGroup>
|
|
115
99
|
</ComponentEditorBase>
|
|
116
100
|
|
|
117
101
|
<style>
|