@motion-proto/live-tokens 0.1.1 → 0.3.2
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 +168 -21
- package/dist-plugin/index.cjs +823 -336
- package/dist-plugin/index.d.cts +9 -7
- package/dist-plugin/index.d.ts +9 -7
- package/dist-plugin/index.js +822 -335
- package/package.json +46 -20
- package/src/assets/newspaper.webp +0 -0
- package/src/assets/offering.webp +0 -0
- package/src/component-editor/BadgeEditor.svelte +170 -0
- package/src/component-editor/CalloutEditor.svelte +103 -0
- package/src/component-editor/CardEditor.svelte +184 -0
- package/src/component-editor/CollapsibleSectionEditor.svelte +167 -0
- package/src/component-editor/CornerBadgeEditor.svelte +207 -0
- package/src/component-editor/DialogEditor.svelte +172 -0
- package/src/component-editor/ImageEditor.svelte +72 -0
- package/src/component-editor/InlineEditActionsEditor.svelte +83 -0
- package/src/component-editor/NotificationEditor.svelte +160 -0
- package/src/component-editor/ProgressBarEditor.svelte +124 -0
- package/src/component-editor/RadioButtonEditor.svelte +140 -0
- package/src/component-editor/SectionDividerEditor.svelte +263 -0
- package/src/component-editor/SegmentedControlEditor.svelte +154 -0
- package/src/component-editor/StandardButtonsEditor.svelte +178 -0
- package/src/component-editor/TabBarEditor.svelte +137 -0
- package/src/component-editor/TableEditor.svelte +128 -0
- package/src/component-editor/TooltipEditor.svelte +122 -0
- package/src/component-editor/editorTokens.test.ts +93 -0
- package/src/component-editor/groupKeySlots.test.ts +67 -0
- package/src/component-editor/groupKeySnapshot.test.ts +52 -0
- package/src/component-editor/index.ts +5 -0
- package/src/component-editor/registry.ts +246 -0
- package/src/component-editor/scaffolding/AngleDial.svelte +185 -0
- package/src/component-editor/scaffolding/ComponentEditorBase.svelte +96 -0
- package/src/component-editor/scaffolding/ComponentFileManager.svelte +682 -0
- package/src/component-editor/scaffolding/ComponentFileMenu.svelte +312 -0
- package/src/component-editor/scaffolding/ComponentsTab.svelte +69 -0
- package/src/component-editor/scaffolding/CopyFromMenu.svelte +246 -0
- package/src/component-editor/scaffolding/DemoHeader.svelte +21 -0
- package/src/component-editor/scaffolding/DividerEditor.svelte +81 -0
- package/src/component-editor/scaffolding/FieldsetWrapper.svelte +46 -0
- package/src/component-editor/scaffolding/GradientCard.svelte +291 -0
- package/src/component-editor/scaffolding/LinkageChart.svelte +297 -0
- package/src/component-editor/scaffolding/LinkedBlock.svelte +418 -0
- package/src/component-editor/scaffolding/NonStylableConfig.svelte +57 -0
- package/src/component-editor/scaffolding/SaveAsDialog.svelte +177 -0
- package/src/component-editor/scaffolding/ShadowBackdrop.svelte +25 -0
- package/src/component-editor/scaffolding/ShadowBackdropControls.svelte +56 -0
- package/src/component-editor/scaffolding/StateBlock.svelte +115 -0
- package/src/component-editor/scaffolding/TokenLayout.svelte +511 -0
- package/src/component-editor/scaffolding/TypeEditor.svelte +82 -0
- package/src/component-editor/scaffolding/VariantGroup.svelte +277 -0
- package/src/component-editor/scaffolding/buildTypeGroupTokens.ts +97 -0
- package/src/component-editor/scaffolding/componentSectionType.ts +8 -0
- package/src/component-editor/scaffolding/componentSources.ts +9 -0
- package/src/component-editor/scaffolding/defaultSections.ts +16 -0
- package/src/component-editor/scaffolding/editorContext.ts +44 -0
- package/src/component-editor/scaffolding/linkedBlock.ts +226 -0
- package/src/component-editor/scaffolding/siblings.ts +33 -0
- package/src/component-editor/scaffolding/types.ts +39 -0
- package/src/components/Badge.svelte +231 -42
- package/src/components/Button.svelte +324 -124
- package/src/components/Callout.svelte +145 -0
- package/src/components/Card.svelte +123 -25
- package/src/components/CollapsibleSection.svelte +213 -35
- package/src/components/CornerBadge.svelte +224 -0
- package/src/components/Dialog.svelte +137 -114
- package/src/components/Image.svelte +43 -0
- package/src/components/InlineEditActions.svelte +74 -14
- package/src/components/Notification.svelte +184 -163
- package/src/components/ProgressBar.svelte +216 -22
- package/src/components/RadioButton.svelte +110 -40
- package/src/components/SectionDivider.svelte +428 -74
- package/src/components/SegmentedControl.svelte +203 -0
- package/src/components/TabBar.svelte +146 -21
- package/src/components/Table.svelte +102 -0
- package/src/components/Tooltip.svelte +45 -19
- package/src/components/types.ts +51 -0
- package/src/data/google-fonts.json +75 -0
- package/src/lib/ColumnsOverlay.svelte +20 -7
- package/src/lib/LiveEditorOverlay.svelte +257 -78
- package/src/lib/columnsOverlay.ts +21 -17
- package/src/lib/componentConfig.test.ts +204 -0
- package/src/lib/componentConfigKeys.ts +19 -0
- package/src/lib/componentConfigService.ts +88 -0
- package/src/lib/copyPopover.ts +30 -0
- package/src/lib/cssVarSync.ts +59 -7
- package/src/lib/editorConfigStore.ts +0 -10
- package/src/lib/editorCore.ts +402 -0
- package/src/lib/editorKeybindings.ts +52 -0
- package/src/lib/editorPersistence.ts +106 -0
- package/src/lib/editorRenderer.ts +74 -0
- package/src/lib/editorStore.test.ts +328 -0
- package/src/lib/editorStore.ts +412 -0
- package/src/lib/editorTypes.ts +100 -0
- package/src/lib/editorViewStore.ts +55 -0
- package/src/lib/files/versionedFileResource.ts +140 -0
- package/src/lib/fontLoader.ts +130 -0
- package/src/lib/fontMigration.ts +140 -0
- package/src/lib/fontParse.ts +168 -0
- package/src/lib/index.ts +48 -30
- package/src/lib/lazyConfig.test.ts +54 -0
- package/src/lib/migrations/2026-04-24-component-prefix-and-suffix-renames.ts +64 -0
- package/src/lib/migrations/2026-04-24-legacy-keys-and-bg-to-canvas.ts +71 -0
- package/src/lib/migrations/2026-04-27-segmentedcontrol-disabled-flatten.ts +43 -0
- package/src/lib/migrations/2026-05-08-collapsiblesection-frame-and-cleanup.ts +68 -0
- package/src/lib/migrations/2026-05-08-collapsiblesection-variant-namespace.ts +35 -0
- package/src/lib/migrations/2026-05-10-sectiondivider-gradient-stops.ts +50 -0
- package/src/lib/migrations/2026-05-13-primary-to-brand.ts +90 -0
- package/src/lib/migrations/index.ts +93 -0
- package/src/lib/migrations/migrations.test.ts +341 -0
- package/src/lib/navLinkTypes.ts +1 -0
- package/src/lib/overlayState.ts +3 -0
- package/src/lib/paletteDerivation.ts +300 -0
- package/src/lib/parentRouteStore.ts +42 -0
- package/src/lib/parsers/globalRootBlock.ts +32 -0
- package/src/lib/presetService.ts +94 -0
- package/src/lib/router.ts +42 -10
- package/src/lib/scrollSection.ts +45 -0
- package/src/lib/slices/columns.ts +59 -0
- package/src/lib/slices/components.ts +362 -0
- package/src/lib/slices/domainVars.ts +15 -0
- package/src/lib/slices/fonts.ts +30 -0
- package/src/lib/slices/gradients.ts +153 -0
- package/src/lib/slices/overlays.ts +132 -0
- package/src/lib/slices/palettes.ts +26 -0
- package/src/lib/slices/shadows.ts +123 -0
- package/src/lib/storage.ts +88 -0
- package/src/lib/themeInit.ts +74 -0
- package/src/lib/themeService.ts +101 -0
- package/src/lib/themeTypes.ts +146 -0
- package/src/lib/tokenRegistry.ts +148 -0
- package/src/pages/ComponentEditorPage.svelte +384 -0
- package/src/pages/ComponentEditorPage.svelte.d.ts +2 -0
- package/src/pages/Editor.svelte +98 -0
- package/src/pages/Editor.svelte.d.ts +2 -0
- package/src/pages/EditorShell.svelte +348 -0
- package/src/styles/_padding.scss +34 -0
- package/src/styles/fonts/Fraunces/Fraunces-italic-latin-ext.woff2 +0 -0
- package/src/styles/fonts/Fraunces/Fraunces-italic-latin.woff2 +0 -0
- package/src/styles/fonts/Fraunces/Fraunces-roman-latin-ext.woff2 +0 -0
- package/src/styles/fonts/Fraunces/Fraunces-roman-latin.woff2 +0 -0
- package/src/styles/fonts/Manrope/Manrope-latin-ext.woff2 +0 -0
- package/src/styles/fonts/Manrope/Manrope-latin.woff2 +0 -0
- package/src/styles/fonts.css +22 -10
- package/src/styles/form-controls.css +14 -16
- package/src/styles/tokens.css +1322 -0
- package/src/styles/ui-editor.css +126 -0
- package/src/{showcase → ui}/BezierCurveEditor.svelte +14 -14
- package/src/{showcase → ui}/ColorEditPanel.svelte +42 -36
- package/src/ui/EditorViewSwitcher.svelte +180 -0
- package/src/ui/FontStackEditor.svelte +360 -0
- package/src/ui/GradientEditor.svelte +461 -0
- package/src/ui/GradientStopPicker.svelte +74 -0
- package/src/ui/PaletteEditor.svelte +1590 -0
- package/src/ui/PaletteEditor.test.ts +108 -0
- package/src/ui/PresetFileManager.svelte +567 -0
- package/src/ui/ProjectFontsSection.svelte +645 -0
- package/src/{showcase → ui}/SurfacesTab.svelte +39 -39
- package/src/{showcase → ui}/TextTab.svelte +27 -27
- package/src/{showcase/TokenFileManager.svelte → ui/ThemeFileManager.svelte} +196 -112
- package/src/ui/Toggle.svelte +108 -0
- package/src/ui/UICopyPopover.svelte +78 -0
- package/src/{showcase/EditorDialog.svelte → ui/UIDialog.svelte} +66 -25
- package/src/ui/UIFontFamilySelector.svelte +309 -0
- package/src/ui/UIFontSizeSelector.svelte +165 -0
- package/src/ui/UIFontWeightSelector.svelte +52 -0
- package/src/ui/UILineHeightSelector.svelte +47 -0
- package/src/ui/UILinkToggle.svelte +60 -0
- package/src/ui/UIOptionItem.svelte +74 -0
- package/src/ui/UIOptionList.svelte +27 -0
- package/src/ui/UIPaddingSelector.svelte +661 -0
- package/src/ui/UIPaletteSelector.svelte +1084 -0
- package/src/ui/UIRadio.svelte +72 -0
- package/src/ui/UIRadioGroup.svelte +59 -0
- package/src/ui/UIRelinkConfirmPopover.svelte +235 -0
- package/src/ui/UITokenSelector.svelte +509 -0
- package/src/ui/UIVariantSelector.svelte +145 -0
- package/src/ui/VariablesTab.svelte +252 -0
- package/src/ui/index.ts +31 -0
- package/src/ui/keepInViewport.ts +84 -0
- package/src/ui/palette/GradientStopEditor.svelte +482 -0
- package/src/ui/palette/OverridesPanel.svelte +526 -0
- package/src/ui/palette/PaletteBase.svelte +165 -0
- package/src/ui/palette/ScaleCurveEditor.svelte +38 -0
- package/src/ui/palette/paletteEditorState.ts +89 -0
- package/src/ui/sections/ColumnsSection.svelte +273 -0
- package/src/ui/sections/GradientsSection.svelte +147 -0
- package/src/ui/sections/OverlaysSection.svelte +670 -0
- package/src/ui/sections/ShadowsSection.svelte +1250 -0
- package/src/ui/sections/TokenScaleTable.svelte +332 -0
- package/src/ui/sections/tokenScales.ts +81 -0
- package/src/ui/variantScales.ts +108 -0
- package/src/components/DetailNav.svelte +0 -78
- package/src/components/Toggle.svelte +0 -86
- package/src/lib/tokenInit.ts +0 -29
- package/src/lib/tokenService.ts +0 -144
- package/src/lib/tokenTypes.ts +0 -45
- package/src/pages/Admin.svelte +0 -100
- package/src/pages/ShowcasePage.svelte +0 -144
- package/src/showcase/BackupBrowser.svelte +0 -617
- package/src/showcase/ComponentsTab.svelte +0 -105
- package/src/showcase/PaletteEditor.svelte +0 -2579
- package/src/showcase/PaletteSelector.svelte +0 -627
- package/src/showcase/TokenMap.svelte +0 -54
- package/src/showcase/VariablesTab.svelte +0 -2655
- package/src/showcase/VisualsTab.svelte +0 -231
- package/src/showcase/demos/BadgeDemo.svelte +0 -56
- package/src/showcase/demos/CardDemo.svelte +0 -50
- package/src/showcase/demos/ChoiceButtonsDemo.svelte +0 -192
- package/src/showcase/demos/CollapsibleSectionDemo.svelte +0 -54
- package/src/showcase/demos/DialogDemo.svelte +0 -42
- package/src/showcase/demos/InlineEditActionsDemo.svelte +0 -25
- package/src/showcase/demos/NotificationDemo.svelte +0 -147
- package/src/showcase/demos/ProgressBarDemo.svelte +0 -54
- package/src/showcase/demos/RadioButtonDemo.svelte +0 -56
- package/src/showcase/demos/SectionDividerDemo.svelte +0 -77
- package/src/showcase/demos/StandardButtonsDemo.svelte +0 -455
- package/src/showcase/demos/TabBarDemo.svelte +0 -58
- package/src/showcase/demos/TooltipDemo.svelte +0 -52
- package/src/showcase/editor.css +0 -93
- package/src/showcase/index.ts +0 -17
- package/src/styles/fonts/Domine/Domine-VariableFont_wght.ttf +0 -0
- package/src/styles/fonts/Domine/OFL.txt +0 -97
- package/src/styles/fonts/Domine/README.txt +0 -66
- /package/src/{showcase → ui}/curveEngine.ts +0 -0
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount, onDestroy, createEventDispatcher } from 'svelte';
|
|
3
|
+
import { setCssVar, removeCssVar, CSS_VAR_CHANGE_EVENT } from '../lib/cssVarSync';
|
|
4
|
+
import type { CssVarRef } from '../lib/editorTypes';
|
|
5
|
+
import {
|
|
6
|
+
editorState,
|
|
7
|
+
setComponentAlias,
|
|
8
|
+
clearComponentAlias,
|
|
9
|
+
setComponentAliasLinked,
|
|
10
|
+
clearComponentAliasLinked,
|
|
11
|
+
isComponentPropertyLinked,
|
|
12
|
+
unlinkComponentProperty,
|
|
13
|
+
relinkComponentProperty,
|
|
14
|
+
getComponentPropertySiblings,
|
|
15
|
+
} from '../lib/editorStore';
|
|
16
|
+
import UILinkToggle from './UILinkToggle.svelte';
|
|
17
|
+
import UIRelinkConfirmPopover from './UIRelinkConfirmPopover.svelte';
|
|
18
|
+
import { keepInViewport } from './keepInViewport';
|
|
19
|
+
|
|
20
|
+
const dispatch = createEventDispatcher<{
|
|
21
|
+
change: void;
|
|
22
|
+
reset: void;
|
|
23
|
+
open: void;
|
|
24
|
+
close: void;
|
|
25
|
+
'var-change': void;
|
|
26
|
+
}>();
|
|
27
|
+
|
|
28
|
+
export let variable: string;
|
|
29
|
+
/** When set, writes persist through the editor store under this component. */
|
|
30
|
+
export let component: string | undefined = undefined;
|
|
31
|
+
/** When true, render a link toggle that lets the user share this value across all sibling variants. */
|
|
32
|
+
export let canBeLinked: boolean = false;
|
|
33
|
+
/** Minimum width of the dropdown panel. */
|
|
34
|
+
export let dropdownMinWidth: string = '14rem';
|
|
35
|
+
/** Max width of the dropdown panel (useful for grids). */
|
|
36
|
+
export let dropdownMaxWidth: string = '';
|
|
37
|
+
/** When true, the default dropdown header (variable name + reset) is omitted. */
|
|
38
|
+
export let hideDefaultHeader: boolean = false;
|
|
39
|
+
/** When true, the trigger becomes non-interactive and visually dimmed. */
|
|
40
|
+
export let disabled: boolean = false;
|
|
41
|
+
/** When true, the trigger opens normally but the dropdown's selection area is
|
|
42
|
+
* dimmed and non-interactive. The lock toggle in the header stays active so
|
|
43
|
+
* the user can re-engage editing by re-linking. Used by the linked block to
|
|
44
|
+
* make the row openable even when currently unshared. */
|
|
45
|
+
export let selectionsLocked: boolean = false;
|
|
46
|
+
|
|
47
|
+
let open = false;
|
|
48
|
+
let container: HTMLElement;
|
|
49
|
+
let relinkOpen = false;
|
|
50
|
+
let relinkCandidates: { variable: string; alias: string }[] = [];
|
|
51
|
+
|
|
52
|
+
$: isLinkedFromData = canBeLinked && component && $editorState
|
|
53
|
+
? isComponentPropertyLinked(component, variable)
|
|
54
|
+
: false;
|
|
55
|
+
$: isLinkedDisplay = canBeLinked && !!component && isLinkedFromData;
|
|
56
|
+
$: peerCount = canBeLinked && component && $editorState
|
|
57
|
+
? getComponentPropertySiblings(component, variable).length
|
|
58
|
+
: 0;
|
|
59
|
+
$: hasSiblings = peerCount >= 2;
|
|
60
|
+
$: showLinkToggle = canBeLinked && !!component && hasSiblings;
|
|
61
|
+
|
|
62
|
+
/** Persist a semantic CSS-var reference (or clear it when null). */
|
|
63
|
+
export function writeOverride(semanticName: string | null): void {
|
|
64
|
+
if (component) {
|
|
65
|
+
const useLinked = isLinkedDisplay;
|
|
66
|
+
if (semanticName) {
|
|
67
|
+
// Mirror splitAliasesAndConfig: a `--…` reference becomes a token
|
|
68
|
+
// (rendered as `var(name)`); anything else (color-mix expressions,
|
|
69
|
+
// `transparent`, gradient tokens already wrapped) is a literal whose
|
|
70
|
+
// value is emitted as-is. Storing complex CSS as a token would render
|
|
71
|
+
// `var(color-mix(...))`, which is invalid and breaks the preview.
|
|
72
|
+
const ref: CssVarRef = semanticName.startsWith('--')
|
|
73
|
+
? { kind: 'token', name: semanticName }
|
|
74
|
+
: { kind: 'literal', value: semanticName };
|
|
75
|
+
if (useLinked) setComponentAliasLinked(component, variable, ref);
|
|
76
|
+
else setComponentAlias(component, variable, ref);
|
|
77
|
+
} else {
|
|
78
|
+
if (useLinked) clearComponentAliasLinked(component, variable);
|
|
79
|
+
else clearComponentAlias(component, variable);
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (semanticName) {
|
|
84
|
+
setCssVar(variable, semanticName.startsWith('--') ? `var(${semanticName})` : semanticName);
|
|
85
|
+
} else {
|
|
86
|
+
removeCssVar(variable);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function close() {
|
|
91
|
+
if (!open) return;
|
|
92
|
+
open = false;
|
|
93
|
+
dispatch('close');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function toggle() {
|
|
97
|
+
if (disabled) return;
|
|
98
|
+
open = !open;
|
|
99
|
+
dispatch(open ? 'open' : 'close');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
$: if (disabled && open) close();
|
|
103
|
+
|
|
104
|
+
function toggleLinked() {
|
|
105
|
+
if (!canBeLinked || !component) return;
|
|
106
|
+
if (isLinkedDisplay) {
|
|
107
|
+
unlinkComponentProperty(component, variable);
|
|
108
|
+
dispatch('change');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const slice = $editorState.components[component];
|
|
112
|
+
if (!slice) return;
|
|
113
|
+
const siblings = getComponentPropertySiblings(component, variable);
|
|
114
|
+
if (siblings.length < 2) return;
|
|
115
|
+
|
|
116
|
+
// Re-linking this property: figure out the value to adopt by inspecting the
|
|
117
|
+
// siblings *currently linked* (those not in `unlinked`, excluding the target).
|
|
118
|
+
// The target itself is rejoining, so its own value isn't a candidate unless
|
|
119
|
+
// every other sibling has also detached.
|
|
120
|
+
const linkedSiblings = siblings.filter(
|
|
121
|
+
(v) => v !== variable && !slice.unlinked?.includes(v),
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
if (linkedSiblings.length === 0) {
|
|
125
|
+
// No remaining linked siblings — promote this property's current value.
|
|
126
|
+
const currentValue = slice.aliases[variable];
|
|
127
|
+
if (currentValue) {
|
|
128
|
+
setComponentAliasLinked(component, variable, currentValue);
|
|
129
|
+
dispatch('change');
|
|
130
|
+
}
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const candidates = linkedSiblings.map((v) => {
|
|
135
|
+
const ref = slice.aliases[v];
|
|
136
|
+
const alias = ref?.kind === 'token' ? ref.name : '';
|
|
137
|
+
return { variable: v, alias };
|
|
138
|
+
});
|
|
139
|
+
const definedCandidates = candidates.filter((c) => c.alias);
|
|
140
|
+
const distinctValues = new Set(definedCandidates.map((c) => c.alias));
|
|
141
|
+
|
|
142
|
+
if (distinctValues.size <= 1) {
|
|
143
|
+
// ≤1 explicit alias among peers: adopt it; if none of them have one,
|
|
144
|
+
// promote this property's current value so the lock takes effect even
|
|
145
|
+
// when peers are still at their declared defaults. If no alias exists
|
|
146
|
+
// anywhere in the group, rejoin as pure metadata (the group is linked
|
|
147
|
+
// at its upstream default and there's nothing to write).
|
|
148
|
+
const adoptRef = definedCandidates.length > 0
|
|
149
|
+
? slice.aliases[definedCandidates[0].variable]
|
|
150
|
+
: slice.aliases[variable];
|
|
151
|
+
if (adoptRef) setComponentAliasLinked(component, variable, adoptRef);
|
|
152
|
+
else relinkComponentProperty(component, variable);
|
|
153
|
+
dispatch('change');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
relinkCandidates = candidates;
|
|
158
|
+
relinkOpen = true;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function handleRelinkConfirm(e: CustomEvent<{ alias: string }>) {
|
|
162
|
+
if (!component) return;
|
|
163
|
+
setComponentAliasLinked(component, variable, { kind: 'token', name: e.detail.alias });
|
|
164
|
+
dispatch('change');
|
|
165
|
+
relinkOpen = false;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function handleRelinkCancel() {
|
|
169
|
+
relinkOpen = false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function handleReset() {
|
|
173
|
+
// Order matters: notify children of reset first so they can clear local
|
|
174
|
+
// state, THEN clear the override. writeOverride fires CSS_VAR_CHANGE_EVENT
|
|
175
|
+
// synchronously, which triggers `var-change` on children — that's where
|
|
176
|
+
// each selector should re-derive its display state from the new default.
|
|
177
|
+
//
|
|
178
|
+
// Linked properties: writeOverride(null) routes through
|
|
179
|
+
// `clearComponentAliasLinked`, which clears the shared override on every
|
|
180
|
+
// linked peer. That's the natural meaning of "clear" on a linked group —
|
|
181
|
+
// peers all return to the upstream default together, the link stays.
|
|
182
|
+
// Per-peer resets while preserving the link are impossible by definition
|
|
183
|
+
// (linked = peers share one value); a "reset just this one" intent is
|
|
184
|
+
// really "unlink, then reset," which the user does in two visible steps.
|
|
185
|
+
dispatch('reset');
|
|
186
|
+
writeOverride(null);
|
|
187
|
+
close();
|
|
188
|
+
dispatch('change');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function handleClickOutside(e: MouseEvent) {
|
|
192
|
+
if (container && !container.contains(e.target as Node)) {
|
|
193
|
+
close();
|
|
194
|
+
relinkOpen = false;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function handleVarChange(e: Event) {
|
|
199
|
+
const detail = (e as CustomEvent<{ name: string }>).detail;
|
|
200
|
+
if (detail?.name === variable) dispatch('var-change');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
onMount(() => {
|
|
204
|
+
document.addEventListener('click', handleClickOutside, true);
|
|
205
|
+
document.addEventListener(CSS_VAR_CHANGE_EVENT, handleVarChange);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
onDestroy(() => {
|
|
209
|
+
document.removeEventListener('click', handleClickOutside, true);
|
|
210
|
+
document.removeEventListener(CSS_VAR_CHANGE_EVENT, handleVarChange);
|
|
211
|
+
});
|
|
212
|
+
</script>
|
|
213
|
+
|
|
214
|
+
<div class="ui-token-selector" class:disabled bind:this={container}>
|
|
215
|
+
<div class="ui-ts-trigger-wrap">
|
|
216
|
+
<button
|
|
217
|
+
class="ui-ts-trigger"
|
|
218
|
+
class:linked={isLinkedDisplay}
|
|
219
|
+
class:unlinked={showLinkToggle && !isLinkedDisplay}
|
|
220
|
+
on:click={toggle}
|
|
221
|
+
{disabled}
|
|
222
|
+
>
|
|
223
|
+
<div class="ui-ts-content">
|
|
224
|
+
{#if $$slots['trigger-preview']}
|
|
225
|
+
<div class="ui-ts-preview">
|
|
226
|
+
<slot name="trigger-preview" />
|
|
227
|
+
</div>
|
|
228
|
+
{/if}
|
|
229
|
+
<div class="ui-ts-text">
|
|
230
|
+
<slot name="trigger-text">
|
|
231
|
+
{#if $$slots['trigger-title']}
|
|
232
|
+
<span class="ui-ts-category"><slot name="trigger-title" /></span>
|
|
233
|
+
{/if}
|
|
234
|
+
</slot>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
<i class="fas fa-chevron-down ui-ts-chevron" class:open></i>
|
|
238
|
+
</button>
|
|
239
|
+
|
|
240
|
+
{#if relinkOpen && component}
|
|
241
|
+
<UIRelinkConfirmPopover
|
|
242
|
+
candidates={relinkCandidates}
|
|
243
|
+
initialVariable={variable}
|
|
244
|
+
prefixToStrip={`--${component}-`}
|
|
245
|
+
on:confirm={handleRelinkConfirm}
|
|
246
|
+
on:cancel={handleRelinkCancel}
|
|
247
|
+
/>
|
|
248
|
+
{/if}
|
|
249
|
+
|
|
250
|
+
{#if open}
|
|
251
|
+
<div
|
|
252
|
+
class="ui-ts-dropdown"
|
|
253
|
+
style="min-width: {dropdownMinWidth};{dropdownMaxWidth ? ` max-width: ${dropdownMaxWidth};` : ''}"
|
|
254
|
+
use:keepInViewport
|
|
255
|
+
>
|
|
256
|
+
{#if !hideDefaultHeader}
|
|
257
|
+
<slot name="header">
|
|
258
|
+
<div class="ui-ts-header">
|
|
259
|
+
{#if showLinkToggle}
|
|
260
|
+
<UILinkToggle linked={isLinkedDisplay} on:toggle={toggleLinked} />
|
|
261
|
+
{/if}
|
|
262
|
+
<button
|
|
263
|
+
type="button"
|
|
264
|
+
class="ui-ts-reset"
|
|
265
|
+
on:click={handleReset}
|
|
266
|
+
disabled={selectionsLocked}
|
|
267
|
+
title={selectionsLocked ? 'Unlock to reset' : 'Reset to default'}
|
|
268
|
+
>
|
|
269
|
+
<i class="fas fa-undo" aria-hidden="true"></i>
|
|
270
|
+
<span>Reset</span>
|
|
271
|
+
</button>
|
|
272
|
+
</div>
|
|
273
|
+
</slot>
|
|
274
|
+
{/if}
|
|
275
|
+
<div class="ui-ts-selections" class:locked={selectionsLocked}>
|
|
276
|
+
<slot name="subheader" />
|
|
277
|
+
<slot {close} {handleReset} />
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
{/if}
|
|
281
|
+
</div>
|
|
282
|
+
|
|
283
|
+
{#if $$slots['trigger-meta']}
|
|
284
|
+
<span class="ui-ts-meta-text"><slot name="trigger-meta" /></span>
|
|
285
|
+
{/if}
|
|
286
|
+
</div>
|
|
287
|
+
|
|
288
|
+
<style>
|
|
289
|
+
/* Subgrid spanning the parent's trigger + meta columns. */
|
|
290
|
+
.ui-token-selector {
|
|
291
|
+
display: grid;
|
|
292
|
+
grid-template-columns: subgrid;
|
|
293
|
+
grid-column: span 2;
|
|
294
|
+
align-items: stretch;
|
|
295
|
+
column-gap: var(--ui-space-8);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.ui-ts-trigger-wrap {
|
|
299
|
+
position: relative;
|
|
300
|
+
min-width: 0;
|
|
301
|
+
justify-self: stretch;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.ui-token-selector.disabled {
|
|
305
|
+
opacity: 0.4;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.ui-token-selector.disabled .ui-ts-trigger {
|
|
309
|
+
cursor: not-allowed;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.ui-token-selector.disabled .ui-ts-trigger:hover {
|
|
313
|
+
border-color: var(--ui-border-default);
|
|
314
|
+
background: var(--ui-surface-low);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.ui-ts-trigger {
|
|
318
|
+
display: flex;
|
|
319
|
+
align-items: center;
|
|
320
|
+
gap: var(--ui-space-6);
|
|
321
|
+
padding: var(--ui-space-2) var(--ui-space-8);
|
|
322
|
+
background: var(--ui-surface-low);
|
|
323
|
+
border: 1px solid var(--ui-border-default);
|
|
324
|
+
border-radius: var(--ui-radius-md);
|
|
325
|
+
cursor: pointer;
|
|
326
|
+
transition: all var(--ui-transition-fast);
|
|
327
|
+
min-height: 1.75rem;
|
|
328
|
+
width: 100%;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.ui-ts-content {
|
|
332
|
+
display: flex;
|
|
333
|
+
flex: 1;
|
|
334
|
+
min-width: 0;
|
|
335
|
+
align-items: center;
|
|
336
|
+
justify-content: flex-start;
|
|
337
|
+
gap: var(--ui-space-6);
|
|
338
|
+
overflow: hidden;
|
|
339
|
+
align-self: stretch;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.ui-ts-text {
|
|
343
|
+
display: flex;
|
|
344
|
+
flex-direction: column;
|
|
345
|
+
gap: 1px;
|
|
346
|
+
flex: 0 1 auto;
|
|
347
|
+
text-align: left;
|
|
348
|
+
align-items: flex-start;
|
|
349
|
+
min-width: 0;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.ui-ts-text:has(.ui-ts-category:empty) {
|
|
353
|
+
display: none;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.ui-ts-category {
|
|
357
|
+
font-size: var(--ui-font-size-sm);
|
|
358
|
+
color: var(--ui-text-primary);
|
|
359
|
+
font-weight: var(--ui-font-weight-medium);
|
|
360
|
+
text-align: left;
|
|
361
|
+
width: 100%;
|
|
362
|
+
white-space: nowrap;
|
|
363
|
+
overflow: hidden;
|
|
364
|
+
text-overflow: ellipsis;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.ui-ts-trigger:hover {
|
|
368
|
+
border-color: var(--ui-border-strong);
|
|
369
|
+
background: var(--ui-surface-high);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/* Link-state pop-bar. The wrap already has `position: relative` (so the
|
|
373
|
+
dropdown can anchor). The bar is a `::before` anchored at the wrap's
|
|
374
|
+
left edge — same column position regardless of state, so a stack of
|
|
375
|
+
mixed linked/unlinked rows shares one continuous link-state column.
|
|
376
|
+
Linked rows: bar is teal, full size, sitting flush against the trigger.
|
|
377
|
+
Unlinked rows: bar shrinks to a smaller amber tick and the trigger is
|
|
378
|
+
indented (`padding-left` on the wrap) so the bar sits clear of it. */
|
|
379
|
+
.ui-ts-trigger-wrap {
|
|
380
|
+
transition: padding-left 320ms cubic-bezier(0.5, 1.6, 0.5, 1);
|
|
381
|
+
}
|
|
382
|
+
.ui-ts-trigger-wrap:has(> .ui-ts-trigger.linked, > .ui-ts-trigger.unlinked)::before {
|
|
383
|
+
content: "";
|
|
384
|
+
position: absolute;
|
|
385
|
+
top: 50%;
|
|
386
|
+
left: 0;
|
|
387
|
+
width: 4px;
|
|
388
|
+
height: 1.75rem;
|
|
389
|
+
border-radius: var(--ui-radius-md) 0 0 var(--ui-radius-md);
|
|
390
|
+
background: var(--ui-text-primary);
|
|
391
|
+
transform: translateY(-50%);
|
|
392
|
+
pointer-events: none;
|
|
393
|
+
transition:
|
|
394
|
+
width 220ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
395
|
+
height 220ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
396
|
+
border-radius 220ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
397
|
+
background-color 220ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
398
|
+
}
|
|
399
|
+
.ui-ts-trigger-wrap:has(> .ui-ts-trigger.unlinked) {
|
|
400
|
+
padding-left: 0.5rem;
|
|
401
|
+
}
|
|
402
|
+
.ui-ts-trigger-wrap:has(> .ui-ts-trigger.unlinked)::before {
|
|
403
|
+
background: var(--ui-link-broken);
|
|
404
|
+
width: 2px;
|
|
405
|
+
height: 0.875rem;
|
|
406
|
+
border-radius: 1px;
|
|
407
|
+
}
|
|
408
|
+
/* Keep the dropdown's left edge aligned with the (indented) trigger rather
|
|
409
|
+
than the column anchor, so an open dropdown doesn't bleed left of its
|
|
410
|
+
associated control. */
|
|
411
|
+
.ui-ts-trigger-wrap:has(> .ui-ts-trigger.unlinked) > .ui-ts-dropdown {
|
|
412
|
+
left: 0.5rem;
|
|
413
|
+
}
|
|
414
|
+
@media (prefers-reduced-motion: reduce) {
|
|
415
|
+
.ui-ts-trigger-wrap,
|
|
416
|
+
.ui-ts-trigger-wrap::before { transition: none; }
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.ui-ts-preview {
|
|
420
|
+
flex: 1;
|
|
421
|
+
align-self: stretch;
|
|
422
|
+
flex-shrink: 0;
|
|
423
|
+
display: flex;
|
|
424
|
+
align-items: center;
|
|
425
|
+
justify-content: center;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.ui-ts-preview:empty {
|
|
429
|
+
display: none;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.ui-ts-meta-text {
|
|
433
|
+
align-self: center;
|
|
434
|
+
color: var(--ui-text-tertiary);
|
|
435
|
+
font-family: var(--ui-font-mono);
|
|
436
|
+
font-size: var(--ui-font-size-sm);
|
|
437
|
+
overflow: hidden;
|
|
438
|
+
text-overflow: ellipsis;
|
|
439
|
+
white-space: nowrap;
|
|
440
|
+
min-width: 0;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.ui-ts-chevron {
|
|
444
|
+
font-size: 0.625rem;
|
|
445
|
+
color: var(--ui-text-secondary);
|
|
446
|
+
transition: transform var(--ui-transition-fast);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.ui-ts-chevron.open {
|
|
450
|
+
transform: rotate(180deg);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.ui-ts-dropdown {
|
|
454
|
+
position: absolute;
|
|
455
|
+
top: calc(100% + var(--ui-space-4));
|
|
456
|
+
left: 0;
|
|
457
|
+
background: var(--ui-surface-higher);
|
|
458
|
+
border: 1px solid var(--ui-border-medium);
|
|
459
|
+
border-radius: var(--ui-radius-md);
|
|
460
|
+
box-shadow: var(--ui-shadow-lg);
|
|
461
|
+
z-index: 10;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.ui-ts-header {
|
|
465
|
+
display: flex;
|
|
466
|
+
align-items: center;
|
|
467
|
+
justify-content: flex-end;
|
|
468
|
+
gap: var(--ui-space-6);
|
|
469
|
+
padding: var(--ui-space-6) var(--ui-space-8);
|
|
470
|
+
border-bottom: 1px solid var(--ui-border-faint);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.ui-ts-reset {
|
|
474
|
+
display: inline-flex;
|
|
475
|
+
align-items: center;
|
|
476
|
+
gap: var(--ui-space-6);
|
|
477
|
+
height: 1.5rem;
|
|
478
|
+
padding: var(--ui-space-2) var(--ui-space-8);
|
|
479
|
+
background: none;
|
|
480
|
+
border: 1px solid var(--ui-border-default);
|
|
481
|
+
border-radius: var(--ui-radius-sm);
|
|
482
|
+
color: var(--ui-text-secondary);
|
|
483
|
+
font-family: inherit;
|
|
484
|
+
font-size: var(--ui-font-size-sm);
|
|
485
|
+
cursor: pointer;
|
|
486
|
+
flex-shrink: 0;
|
|
487
|
+
transition: all var(--ui-transition-fast);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.ui-ts-reset i {
|
|
491
|
+
font-size: 0.625rem;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.ui-ts-reset:hover:not(:disabled) {
|
|
495
|
+
background: var(--ui-hover);
|
|
496
|
+
border-color: var(--ui-border-strong);
|
|
497
|
+
color: var(--ui-text-primary);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.ui-ts-reset:disabled {
|
|
501
|
+
opacity: 0.4;
|
|
502
|
+
cursor: not-allowed;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.ui-ts-selections.locked {
|
|
506
|
+
opacity: 0.4;
|
|
507
|
+
pointer-events: none;
|
|
508
|
+
}
|
|
509
|
+
</style>
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<script lang="ts" generics="T extends { key: string; label?: string; value?: string }">
|
|
2
|
+
import { createEventDispatcher } from 'svelte';
|
|
3
|
+
import { resolveAliasChain } from '../lib/tokenRegistry';
|
|
4
|
+
import UITokenSelector from './UITokenSelector.svelte';
|
|
5
|
+
import UIOptionList from './UIOptionList.svelte';
|
|
6
|
+
import UIOptionItem from './UIOptionItem.svelte';
|
|
7
|
+
|
|
8
|
+
const dispatch = createEventDispatcher<{
|
|
9
|
+
change: void;
|
|
10
|
+
}>();
|
|
11
|
+
|
|
12
|
+
export let variable: string;
|
|
13
|
+
export let component: string | undefined = undefined;
|
|
14
|
+
export let canBeLinked: boolean = false;
|
|
15
|
+
export let disabled: boolean = false;
|
|
16
|
+
export let selectionsLocked: boolean = false;
|
|
17
|
+
export let dropdownMinWidth: string = '12rem';
|
|
18
|
+
export let dropdownMaxWidth: string = '';
|
|
19
|
+
/** Forwarded to UIOptionList — when set, options render in a linked-column grid. */
|
|
20
|
+
export let dropdownGridColumns: string = '';
|
|
21
|
+
/** CSS var prefix that, joined with an option `key`, forms the target var (e.g. `--font-weight-`). */
|
|
22
|
+
export let varPrefix: string;
|
|
23
|
+
/** Selectable options. Each must have a unique `key`. */
|
|
24
|
+
export let options: ReadonlyArray<T>;
|
|
25
|
+
|
|
26
|
+
let selector: UITokenSelector;
|
|
27
|
+
let chosenKey: string | null = null;
|
|
28
|
+
let currentValue: string = '';
|
|
29
|
+
|
|
30
|
+
$: validKeys = new Set(options.map((o) => o.key));
|
|
31
|
+
$: refMatcher = (() => {
|
|
32
|
+
const escaped = varPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
33
|
+
return new RegExp(`var\\((${escaped}[^)\\s]+)\\)`);
|
|
34
|
+
})();
|
|
35
|
+
|
|
36
|
+
function parseRef(value: string): string | null {
|
|
37
|
+
const m = value.match(refMatcher);
|
|
38
|
+
if (!m) return null;
|
|
39
|
+
const key = m[1].slice(varPrefix.length);
|
|
40
|
+
return validKeys.has(key) ? key : null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function readResolved() {
|
|
44
|
+
currentValue = getComputedStyle(document.documentElement).getPropertyValue(variable).trim();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function initFromCurrent() {
|
|
48
|
+
readResolved();
|
|
49
|
+
const raw = document.documentElement.style.getPropertyValue(variable).trim();
|
|
50
|
+
if (raw) {
|
|
51
|
+
const key = parseRef(raw);
|
|
52
|
+
if (key) {
|
|
53
|
+
chosenKey = key;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const alias of resolveAliasChain(variable)) {
|
|
58
|
+
const key = parseRef(`var(${alias})`);
|
|
59
|
+
if (key) {
|
|
60
|
+
chosenKey = key;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Last-ditch fallback: match the resolved value against an option's `value`
|
|
65
|
+
// (lets us highlight a variant even when the default is a literal, not an alias).
|
|
66
|
+
const matchedByValue = options.find((o) => o.value !== undefined && o.value === currentValue);
|
|
67
|
+
chosenKey = matchedByValue ? matchedByValue.key : null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function handleReset() {
|
|
71
|
+
chosenKey = null;
|
|
72
|
+
readResolved();
|
|
73
|
+
dispatch('change');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function selectKey(key: string, close: () => void) {
|
|
77
|
+
const target = `${varPrefix}${key}`;
|
|
78
|
+
if (target === variable) {
|
|
79
|
+
selector.writeOverride(null);
|
|
80
|
+
chosenKey = null;
|
|
81
|
+
} else {
|
|
82
|
+
selector.writeOverride(target);
|
|
83
|
+
chosenKey = key;
|
|
84
|
+
}
|
|
85
|
+
readResolved();
|
|
86
|
+
close();
|
|
87
|
+
dispatch('change');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Re-derive `chosenKey` when the bound `variable` changes (e.g. when a
|
|
91
|
+
// VariantGroup tabs view reuses the same selector across states). Without
|
|
92
|
+
// this, prop swaps leave the trigger label stale.
|
|
93
|
+
let lastSeenVariable: string | null = null;
|
|
94
|
+
$: if (variable !== lastSeenVariable) {
|
|
95
|
+
lastSeenVariable = variable;
|
|
96
|
+
initFromCurrent();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
$: activeOption = (options.find((o) => o.key === chosenKey) ?? null) as T | null;
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<UITokenSelector
|
|
103
|
+
bind:this={selector}
|
|
104
|
+
{variable}
|
|
105
|
+
{component}
|
|
106
|
+
{canBeLinked}
|
|
107
|
+
{disabled}
|
|
108
|
+
{selectionsLocked}
|
|
109
|
+
{dropdownMinWidth}
|
|
110
|
+
{dropdownMaxWidth}
|
|
111
|
+
on:reset={handleReset}
|
|
112
|
+
on:var-change={initFromCurrent}
|
|
113
|
+
>
|
|
114
|
+
<svelte:fragment slot="trigger-title">
|
|
115
|
+
<slot name="trigger-title" {activeOption}>{activeOption?.label ?? ''}</slot>
|
|
116
|
+
</svelte:fragment>
|
|
117
|
+
<svelte:fragment slot="trigger-meta">
|
|
118
|
+
<slot name="trigger-meta" {currentValue} {activeOption}>{currentValue || '—'}</slot>
|
|
119
|
+
</svelte:fragment>
|
|
120
|
+
|
|
121
|
+
<svelte:fragment let:close>
|
|
122
|
+
<UIOptionList gridColumns={dropdownGridColumns}>
|
|
123
|
+
{#each options as opt (opt.key)}
|
|
124
|
+
<slot
|
|
125
|
+
name="option"
|
|
126
|
+
{opt}
|
|
127
|
+
active={chosenKey === opt.key}
|
|
128
|
+
select={() => selectKey(opt.key, close)}
|
|
129
|
+
>
|
|
130
|
+
{#if opt.value !== undefined}
|
|
131
|
+
<UIOptionItem active={chosenKey === opt.key} on:click={() => selectKey(opt.key, close)}>
|
|
132
|
+
<svelte:fragment slot="label">{opt.label ?? ''}</svelte:fragment>
|
|
133
|
+
<svelte:fragment slot="meta">{opt.value}</svelte:fragment>
|
|
134
|
+
</UIOptionItem>
|
|
135
|
+
{:else}
|
|
136
|
+
<UIOptionItem active={chosenKey === opt.key} on:click={() => selectKey(opt.key, close)}>
|
|
137
|
+
<svelte:fragment slot="label">{opt.label ?? ''}</svelte:fragment>
|
|
138
|
+
</UIOptionItem>
|
|
139
|
+
{/if}
|
|
140
|
+
</slot>
|
|
141
|
+
{/each}
|
|
142
|
+
<slot name="extras" {close} />
|
|
143
|
+
</UIOptionList>
|
|
144
|
+
</svelte:fragment>
|
|
145
|
+
</UITokenSelector>
|