@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,167 @@
|
|
|
1
|
+
<script context="module" lang="ts">
|
|
2
|
+
import { buildTypeGroupColorTokens } from './scaffolding/buildTypeGroupTokens';
|
|
3
|
+
import type { Token, TypeGroupConfig } from './scaffolding/types';
|
|
4
|
+
|
|
5
|
+
export const component = 'collapsiblesection';
|
|
6
|
+
|
|
7
|
+
const VARIANTS = ['chromeless', 'divider', 'container'] as const;
|
|
8
|
+
type Variant = typeof VARIANTS[number];
|
|
9
|
+
const HEADER_STATES = ['default', 'hover', 'active'] as const;
|
|
10
|
+
type HeaderState = typeof HEADER_STATES[number];
|
|
11
|
+
|
|
12
|
+
function capitalize(s: string): string {
|
|
13
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const VARIANT_LABELS: Record<Variant, string> = {
|
|
17
|
+
chromeless: 'Chromeless',
|
|
18
|
+
divider: 'With Divider',
|
|
19
|
+
container: 'Container',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Header tokens per variant. Chromeless has no chrome; divider exposes the
|
|
23
|
+
// bottom-border (the divider line) per state; container's outer chrome lives
|
|
24
|
+
// in `frame` so the header strip itself just owns surface + padding + text.
|
|
25
|
+
function headerStateTokens(v: Variant, s: HeaderState): Token[] {
|
|
26
|
+
const p = `--collapsiblesection-${v}-${s}`;
|
|
27
|
+
const base: Token[] = [
|
|
28
|
+
{ label: 'surface color', groupKey: 'surface', variable: `${p}-surface` },
|
|
29
|
+
{ label: 'padding', canBeLinked: true, groupKey: 'padding', variable: `${p}-padding` },
|
|
30
|
+
{ label: 'icon color', groupKey: 'icon', variable: `${p}-icon` },
|
|
31
|
+
{ label: 'icon size', canBeLinked: true, groupKey: 'font-size', variable: `${p}-icon-size` },
|
|
32
|
+
];
|
|
33
|
+
if (v === 'divider') {
|
|
34
|
+
base.splice(1, 0,
|
|
35
|
+
{ label: 'divider color', groupKey: 'border', variable: `${p}-border` },
|
|
36
|
+
{ label: 'divider width', canBeLinked: true, groupKey: 'border-width', variable: `${p}-border-width` },
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return base;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Container has a single Frame ruleset for the always-on outer chrome.
|
|
43
|
+
const frameTokens: Token[] = [
|
|
44
|
+
{ label: 'surface color', groupKey: 'surface', variable: '--collapsiblesection-container-frame-surface' },
|
|
45
|
+
{ label: 'border color', groupKey: 'border', variable: '--collapsiblesection-container-frame-border' },
|
|
46
|
+
{ label: 'border width', canBeLinked: true, groupKey: 'border-width', variable: '--collapsiblesection-container-frame-border-width' },
|
|
47
|
+
{ label: 'corner radius', canBeLinked: true, groupKey: 'radius', variable: '--collapsiblesection-container-frame-radius' },
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
// Expanded panel: chromeless/divider only own padding; container also paints
|
|
51
|
+
// its own surface so the content area can read distinct from the header strip.
|
|
52
|
+
function expandedTokens(v: Variant): Token[] {
|
|
53
|
+
const p = `--collapsiblesection-${v}-expanded`;
|
|
54
|
+
const tokens: Token[] = [];
|
|
55
|
+
if (v === 'container') tokens.push({ label: 'surface color', groupKey: 'surface', variable: `${p}-surface` });
|
|
56
|
+
tokens.push({ label: 'padding', canBeLinked: true, groupKey: 'padding', variable: `${p}-padding` });
|
|
57
|
+
return tokens;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Single per-variant state map: frame (container only), default/hover/active,
|
|
61
|
+
// expanded. State-tab strip inside the VariantGroup walks this sequence so the
|
|
62
|
+
// user moves through the whole variant from one tabbed surface.
|
|
63
|
+
function variantStates(v: Variant): Record<string, Token[]> {
|
|
64
|
+
const out: Record<string, Token[]> = {};
|
|
65
|
+
if (v === 'container') out.frame = frameTokens;
|
|
66
|
+
for (const s of HEADER_STATES) out[s] = headerStateTokens(v, s);
|
|
67
|
+
out.expanded = expandedTokens(v);
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Label typography only attaches to header states; frame and expanded don't
|
|
72
|
+
// own text. VariantGroup tolerates a partial map.
|
|
73
|
+
function variantTypeGroups(v: Variant): Record<string, TypeGroupConfig[]> {
|
|
74
|
+
return Object.fromEntries(HEADER_STATES.map((s) => [s, [{
|
|
75
|
+
legend: 'label',
|
|
76
|
+
colorVariable: `--collapsiblesection-${v}-${s}-label`,
|
|
77
|
+
familyVariable: `--collapsiblesection-${v}-${s}-label-font-family`,
|
|
78
|
+
sizeVariable: `--collapsiblesection-${v}-${s}-label-font-size`,
|
|
79
|
+
weightVariable: `--collapsiblesection-${v}-${s}-label-font-weight`,
|
|
80
|
+
lineHeightVariable: `--collapsiblesection-${v}-${s}-label-line-height`,
|
|
81
|
+
}]]));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const headerTypeGroupTokens: Token[] = VARIANTS.flatMap((v) => HEADER_STATES.flatMap((s) => [
|
|
85
|
+
{ label: 'font family', canBeLinked: true, groupKey: 'font-family', variable: `--collapsiblesection-${v}-${s}-label-font-family` },
|
|
86
|
+
{ label: 'font size', canBeLinked: true, groupKey: 'font-size', variable: `--collapsiblesection-${v}-${s}-label-font-size` },
|
|
87
|
+
{ label: 'font weight', canBeLinked: true, groupKey: 'font-weight', variable: `--collapsiblesection-${v}-${s}-label-font-weight` },
|
|
88
|
+
{ label: 'line height', canBeLinked: true, groupKey: 'line-height', variable: `--collapsiblesection-${v}-${s}-label-line-height` },
|
|
89
|
+
]));
|
|
90
|
+
|
|
91
|
+
export const allTokens: Token[] = [
|
|
92
|
+
...VARIANTS.flatMap((v) => Object.values(variantStates(v)).flat()),
|
|
93
|
+
...VARIANTS.flatMap((v) => buildTypeGroupColorTokens(variantTypeGroups(v))),
|
|
94
|
+
...headerTypeGroupTokens,
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
const linkableContexts = new Map<string, string>([
|
|
98
|
+
...VARIANTS.flatMap((v) => HEADER_STATES.flatMap((s) => {
|
|
99
|
+
const base: Array<[string, string]> = [
|
|
100
|
+
[`--collapsiblesection-${v}-${s}-padding`, `${v} ${s}`],
|
|
101
|
+
[`--collapsiblesection-${v}-${s}-icon-size`, `${v} ${s}`],
|
|
102
|
+
[`--collapsiblesection-${v}-${s}-label-font-family`, `${v} ${s}`],
|
|
103
|
+
[`--collapsiblesection-${v}-${s}-label-font-size`, `${v} ${s}`],
|
|
104
|
+
[`--collapsiblesection-${v}-${s}-label-font-weight`, `${v} ${s}`],
|
|
105
|
+
[`--collapsiblesection-${v}-${s}-label-line-height`, `${v} ${s}`],
|
|
106
|
+
];
|
|
107
|
+
if (v === 'divider') base.push([`--collapsiblesection-divider-${s}-border-width`, `divider ${s}`]);
|
|
108
|
+
return base;
|
|
109
|
+
})),
|
|
110
|
+
['--collapsiblesection-container-frame-border-width', 'container frame'],
|
|
111
|
+
['--collapsiblesection-container-frame-radius', 'container frame'],
|
|
112
|
+
...VARIANTS.flatMap((v) => [
|
|
113
|
+
[`--collapsiblesection-${v}-expanded-padding`, `${v} expanded`] as [string, string],
|
|
114
|
+
]),
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
const variantOptions = VARIANTS.map((v) => ({ value: v, label: VARIANT_LABELS[v] }));
|
|
118
|
+
</script>
|
|
119
|
+
|
|
120
|
+
<script lang="ts">
|
|
121
|
+
import CollapsibleSection from '../components/CollapsibleSection.svelte';
|
|
122
|
+
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
123
|
+
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
124
|
+
import { buildSiblings } from './scaffolding/siblings';
|
|
125
|
+
import { editorState } from '../lib/editorStore';
|
|
126
|
+
import { computeLinkedBlock, withLinkedDisabled } from './scaffolding/linkedBlock';
|
|
127
|
+
|
|
128
|
+
$: linked = computeLinkedBlock(component, linkableContexts, allTokens, $editorState);
|
|
129
|
+
|
|
130
|
+
$: visibleVariantStates = (v: Variant) => Object.fromEntries(
|
|
131
|
+
Object.entries(variantStates(v)).map(([name, list]) => [name, withLinkedDisabled(list, linked.varSet)]),
|
|
132
|
+
) as Record<string, Token[]>;
|
|
133
|
+
</script>
|
|
134
|
+
|
|
135
|
+
<ComponentEditorBase {component} title="Collapsible Section" description="Expandable section with chevron toggle. Variants: chromeless, divider, container. Import from <code>components/CollapsibleSection.svelte</code>" tokens={allTokens} {linked} variants={variantOptions}>
|
|
136
|
+
{#each VARIANTS as v}
|
|
137
|
+
<VariantGroup
|
|
138
|
+
name={v}
|
|
139
|
+
title={VARIANT_LABELS[v]}
|
|
140
|
+
states={visibleVariantStates(v)}
|
|
141
|
+
typeGroups={variantTypeGroups(v)}
|
|
142
|
+
{component}
|
|
143
|
+
siblings={buildSiblings(VARIANTS, v, variantStates, variantTypeGroups)}
|
|
144
|
+
let:activeState
|
|
145
|
+
>
|
|
146
|
+
{@const isExpanded = activeState === 'expanded'}
|
|
147
|
+
{@const isFrame = activeState === 'frame'}
|
|
148
|
+
{@const forceClass = activeState === 'hover' ? 'force-hover' : ''}
|
|
149
|
+
{@const forceActive = activeState === 'active'}
|
|
150
|
+
<CollapsibleSection
|
|
151
|
+
variant={v}
|
|
152
|
+
label="Click to expand"
|
|
153
|
+
expanded={isExpanded}
|
|
154
|
+
active={forceActive}
|
|
155
|
+
class={forceClass}
|
|
156
|
+
>
|
|
157
|
+
<p style="margin: 0; color: var(--text-secondary);">
|
|
158
|
+
{#if isFrame}
|
|
159
|
+
(Frame) — outer chrome only; expand the section to see content area styling.
|
|
160
|
+
{:else}
|
|
161
|
+
This content is revealed when the section is expanded. Any content can go here.
|
|
162
|
+
{/if}
|
|
163
|
+
</p>
|
|
164
|
+
</CollapsibleSection>
|
|
165
|
+
</VariantGroup>
|
|
166
|
+
{/each}
|
|
167
|
+
</ComponentEditorBase>
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
<script context="module" lang="ts">
|
|
2
|
+
import type { Token } from './scaffolding/types';
|
|
3
|
+
import { badgeVariants } from '../components/Badge.svelte';
|
|
4
|
+
|
|
5
|
+
export const component = 'cornerbadge';
|
|
6
|
+
|
|
7
|
+
// One state per Badge variant. Each variant carries the same five tokens, and
|
|
8
|
+
// every token has a role-specific groupKey so the LinkedBlock groups
|
|
9
|
+
// "outer-radius" across variants (not against inner/h-axis/v-axis). Changing
|
|
10
|
+
// a variant's outer corner radius propagates to the same role on every other
|
|
11
|
+
// variant when linked; roles within a variant stay independent.
|
|
12
|
+
function variantTokens(v: typeof badgeVariants[number]): Token[] {
|
|
13
|
+
return [
|
|
14
|
+
{ label: 'offset from corner', canBeLinked: true, groupKey: 'margin', variable: `--corner-badge-${v}-margin` },
|
|
15
|
+
{ label: 'outer corner radius', canBeLinked: true, groupKey: 'outer-radius', variable: `--corner-badge-${v}-outer-radius` },
|
|
16
|
+
{ label: 'inner corner radius', canBeLinked: true, groupKey: 'inner-radius', variable: `--corner-badge-${v}-inner-radius` },
|
|
17
|
+
{ label: 'horizontal-axis radius', canBeLinked: true, groupKey: 'h-axis-radius', variable: `--corner-badge-${v}-h-axis-radius` },
|
|
18
|
+
{ label: 'vertical-axis radius', canBeLinked: true, groupKey: 'v-axis-radius', variable: `--corner-badge-${v}-v-axis-radius` },
|
|
19
|
+
{ label: 'padding', canBeLinked: true, groupKey: 'padding', variable: `--corner-badge-${v}-padding` },
|
|
20
|
+
// Per-side overrides written by the UIPaddingSelector when the user splits
|
|
21
|
+
// padding. Declared (hidden) so the schema sees them as siblings across
|
|
22
|
+
// variants — `padding-top` on primary links to `padding-top` on accent, etc.
|
|
23
|
+
// The themed-padding mixin in CornerBadge.svelte reads them via
|
|
24
|
+
// `var(--corner-badge-${v}-padding-top, fallback)`; no `:root` default is
|
|
25
|
+
// needed (test skips `hidden: true` tokens by design — see editorTokens.test.ts).
|
|
26
|
+
{ label: 'padding-top', canBeLinked: true, groupKey: 'padding-top', variable: `--corner-badge-${v}-padding-top`, hidden: true },
|
|
27
|
+
{ label: 'padding-right', canBeLinked: true, groupKey: 'padding-right', variable: `--corner-badge-${v}-padding-right`, hidden: true },
|
|
28
|
+
{ label: 'padding-bottom', canBeLinked: true, groupKey: 'padding-bottom', variable: `--corner-badge-${v}-padding-bottom`, hidden: true },
|
|
29
|
+
{ label: 'padding-left', canBeLinked: true, groupKey: 'padding-left', variable: `--corner-badge-${v}-padding-left`, hidden: true },
|
|
30
|
+
{ label: 'font family', canBeLinked: true, groupKey: 'text-font-family', variable: `--corner-badge-${v}-text-font-family` },
|
|
31
|
+
{ label: 'font size', canBeLinked: true, groupKey: 'text-font-size', variable: `--corner-badge-${v}-text-font-size` },
|
|
32
|
+
{ label: 'font weight', canBeLinked: true, groupKey: 'text-font-weight', variable: `--corner-badge-${v}-text-font-weight` },
|
|
33
|
+
{ label: 'line height', canBeLinked: true, groupKey: 'text-line-height', variable: `--corner-badge-${v}-text-line-height` },
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
const states: Record<string, Token[]> = Object.fromEntries(
|
|
37
|
+
badgeVariants.map((v) => [v, variantTokens(v)]),
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
export const allTokens: Token[] = Object.values(states).flat();
|
|
41
|
+
|
|
42
|
+
// Every linkable variable across variants — the LinkedBlock uses this to detect
|
|
43
|
+
// when ≥2 variants currently agree on an alias for the same groupKey. Variant
|
|
44
|
+
// name is the context label so the chart rows mirror the variant tab strip.
|
|
45
|
+
const linkableContexts = new Map<string, string>(
|
|
46
|
+
badgeVariants.flatMap((v) =>
|
|
47
|
+
variantTokens(v)
|
|
48
|
+
.filter((t) => t.canBeLinked)
|
|
49
|
+
.map((t) => [t.variable, v] as [string, string]),
|
|
50
|
+
),
|
|
51
|
+
);
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<script lang="ts">
|
|
55
|
+
import { onMount } from 'svelte';
|
|
56
|
+
import CornerBadge, { type CornerAnchor } from '../components/CornerBadge.svelte';
|
|
57
|
+
import type { BadgeVariant } from '../components/Badge.svelte';
|
|
58
|
+
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
59
|
+
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
60
|
+
import ShadowBackdrop from './scaffolding/ShadowBackdrop.svelte';
|
|
61
|
+
import UIRadioGroup from '../ui/UIRadioGroup.svelte';
|
|
62
|
+
import UIPaletteSelector from '../ui/UIPaletteSelector.svelte';
|
|
63
|
+
import { setCssVar } from '../lib/cssVarSync';
|
|
64
|
+
import { editorState } from '../lib/editorStore';
|
|
65
|
+
import { computeLinkedBlock, withLinkedDisabled } from './scaffolding/linkedBlock';
|
|
66
|
+
import demoImageUrl from '../assets/newspaper.webp';
|
|
67
|
+
|
|
68
|
+
$: linked = computeLinkedBlock(component, linkableContexts, allTokens, $editorState);
|
|
69
|
+
$: visibleStates = Object.fromEntries(
|
|
70
|
+
badgeVariants.map((v) => [v, withLinkedDisabled(variantTokens(v), linked.varSet)]),
|
|
71
|
+
) as Record<string, Token[]>;
|
|
72
|
+
|
|
73
|
+
const bgVar = '--backdrop-cornerbadge-surface';
|
|
74
|
+
|
|
75
|
+
onMount(() => {
|
|
76
|
+
if (!document.documentElement.style.getPropertyValue(bgVar)) {
|
|
77
|
+
setCssVar(bgVar, 'var(--surface-canvas)');
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
let anchor: CornerAnchor = 'bottom-right';
|
|
82
|
+
const anchorGrid: ReadonlyArray<{ value: CornerAnchor; icon: string; label: string }> = [
|
|
83
|
+
{ value: 'top-left', icon: 'fas fa-arrow-up-left', label: 'Top left' },
|
|
84
|
+
{ value: 'top-right', icon: 'fas fa-arrow-up-right', label: 'Top right' },
|
|
85
|
+
{ value: 'bottom-left', icon: 'fas fa-arrow-down-left', label: 'Bottom left' },
|
|
86
|
+
{ value: 'bottom-right', icon: 'fas fa-arrow-down-right', label: 'Bottom right' },
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
let variant: BadgeVariant = 'accent';
|
|
90
|
+
const variantOptions = badgeVariants.map((v) => ({ value: v, label: v.charAt(0).toUpperCase() + v.slice(1) }));
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<ComponentEditorBase {component} title="Corner Badge" description="Badge pinned flush to a corner of a positioned ancestor. Composes <code>Badge</code>; adds offset + inner-radius tokens. Import from <code>components/CornerBadge.svelte</code>" tokens={allTokens} {linked}>
|
|
94
|
+
<svelte:fragment slot="config">
|
|
95
|
+
<label class="backdrop-config">
|
|
96
|
+
<span>Sample background</span>
|
|
97
|
+
<div class="picker-slot">
|
|
98
|
+
<UIPaletteSelector variable={bgVar} />
|
|
99
|
+
</div>
|
|
100
|
+
</label>
|
|
101
|
+
<div class="control-row">
|
|
102
|
+
<span>Anchor</span>
|
|
103
|
+
<div class="anchor-grid" role="radiogroup" aria-label="Corner badge anchor">
|
|
104
|
+
{#each anchorGrid as opt (opt.value)}
|
|
105
|
+
<button
|
|
106
|
+
type="button"
|
|
107
|
+
class="anchor-btn"
|
|
108
|
+
class:checked={anchor === opt.value}
|
|
109
|
+
role="radio"
|
|
110
|
+
aria-checked={anchor === opt.value}
|
|
111
|
+
aria-label={opt.label}
|
|
112
|
+
title={opt.label}
|
|
113
|
+
on:click={() => (anchor = opt.value)}
|
|
114
|
+
>
|
|
115
|
+
<i class={opt.icon} aria-hidden="true"></i>
|
|
116
|
+
</button>
|
|
117
|
+
{/each}
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="control-row">
|
|
121
|
+
<span>Variant</span>
|
|
122
|
+
<UIRadioGroup bind:value={variant} name="corner-badge-variant" options={variantOptions} />
|
|
123
|
+
</div>
|
|
124
|
+
</svelte:fragment>
|
|
125
|
+
<VariantGroup name="cornerbadge" title="Corner Badge" states={visibleStates} {component}>
|
|
126
|
+
<ShadowBackdrop mode="color" colorVariable={bgVar}>
|
|
127
|
+
<div class="corner-stage-wrap">
|
|
128
|
+
<div class="corner-stage">
|
|
129
|
+
<img src={demoImageUrl} alt="" class="corner-stage-image" />
|
|
130
|
+
<CornerBadge {variant} {anchor}>{variant.charAt(0).toUpperCase() + variant.slice(1)}</CornerBadge>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
</ShadowBackdrop>
|
|
134
|
+
</VariantGroup>
|
|
135
|
+
</ComponentEditorBase>
|
|
136
|
+
|
|
137
|
+
<style>
|
|
138
|
+
/* Center the stage in the backdrop so the smaller surface doesn't stretch full-width. */
|
|
139
|
+
.corner-stage-wrap {
|
|
140
|
+
display: grid;
|
|
141
|
+
place-items: center;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* Anchor parent for the preview — gives CornerBadge a positioned ancestor so it
|
|
145
|
+
actually pins to a corner, and a visible surface so offset/radius are observable. */
|
|
146
|
+
/* No overflow:hidden here — the badge needs to be able to extend past the stage
|
|
147
|
+
(e.g. when the offset is 0 or negative). Rounded corners live on the image. */
|
|
148
|
+
.corner-stage {
|
|
149
|
+
position: relative;
|
|
150
|
+
width: 380px;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.corner-stage-image {
|
|
154
|
+
display: block;
|
|
155
|
+
width: 100%;
|
|
156
|
+
height: auto;
|
|
157
|
+
border-radius: var(--ui-radius-md);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.control-row {
|
|
161
|
+
display: inline-flex;
|
|
162
|
+
align-items: center;
|
|
163
|
+
gap: var(--ui-space-8);
|
|
164
|
+
font-size: var(--ui-font-size-sm);
|
|
165
|
+
color: var(--ui-text-secondary);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.backdrop-config {
|
|
169
|
+
display: inline-flex;
|
|
170
|
+
align-items: center;
|
|
171
|
+
gap: var(--ui-space-8);
|
|
172
|
+
}
|
|
173
|
+
.picker-slot {
|
|
174
|
+
min-width: 8rem;
|
|
175
|
+
}
|
|
176
|
+
.picker-slot :global(.ui-token-selector) {
|
|
177
|
+
width: 100%;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.anchor-grid {
|
|
181
|
+
display: grid;
|
|
182
|
+
grid-template-columns: repeat(2, 1.5rem);
|
|
183
|
+
grid-template-rows: repeat(2, 1.5rem);
|
|
184
|
+
gap: 2px;
|
|
185
|
+
}
|
|
186
|
+
.anchor-btn {
|
|
187
|
+
display: grid;
|
|
188
|
+
place-items: center;
|
|
189
|
+
padding: 0;
|
|
190
|
+
border: 1px solid var(--ui-border-subtle, rgba(255, 255, 255, 0.1));
|
|
191
|
+
border-radius: var(--ui-radius-sm);
|
|
192
|
+
background: transparent;
|
|
193
|
+
color: var(--ui-text-tertiary);
|
|
194
|
+
cursor: pointer;
|
|
195
|
+
font-size: 0.7rem;
|
|
196
|
+
line-height: 1;
|
|
197
|
+
transition: background var(--ui-transition-fast), color var(--ui-transition-fast), border-color var(--ui-transition-fast);
|
|
198
|
+
}
|
|
199
|
+
.anchor-btn:hover {
|
|
200
|
+
color: var(--ui-text-primary);
|
|
201
|
+
}
|
|
202
|
+
.anchor-btn.checked {
|
|
203
|
+
background: var(--ui-surface-active, rgba(255, 255, 255, 0.12));
|
|
204
|
+
color: var(--ui-text-primary);
|
|
205
|
+
border-color: var(--ui-border-strong, rgba(255, 255, 255, 0.25));
|
|
206
|
+
}
|
|
207
|
+
</style>
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
<script context="module" lang="ts">
|
|
2
|
+
import { buildTypeGroupColorTokens } from './scaffolding/buildTypeGroupTokens';
|
|
3
|
+
import type { Token, TypeGroupConfig } from './scaffolding/types';
|
|
4
|
+
|
|
5
|
+
export const component = 'dialog';
|
|
6
|
+
|
|
7
|
+
const BUTTON_VARIANTS = ['primary', 'secondary', 'outline', 'success', 'danger', 'warning'] as const;
|
|
8
|
+
type ButtonVariant = typeof BUTTON_VARIANTS[number];
|
|
9
|
+
|
|
10
|
+
const CONFIRM_VAR = '--dialog-confirm-variant';
|
|
11
|
+
const CANCEL_VAR = '--dialog-cancel-variant';
|
|
12
|
+
const DEFAULT_CONFIRM: ButtonVariant = 'primary';
|
|
13
|
+
const DEFAULT_CANCEL: ButtonVariant = 'outline';
|
|
14
|
+
|
|
15
|
+
// Frame-level tokens (the dialog box itself + overlay + header + body + footer + close icon).
|
|
16
|
+
// Button styling lives in Button.svelte — the dialog only owns its own chrome.
|
|
17
|
+
const frameStates: Record<string, Token[]> = {
|
|
18
|
+
overlay: [
|
|
19
|
+
{ label: 'backdrop color', groupKey: 'surface', variable: '--dialog-overlay-surface' },
|
|
20
|
+
],
|
|
21
|
+
dialog: [
|
|
22
|
+
{ label: 'surface color', variable: '--dialog-surface' },
|
|
23
|
+
{ label: 'border color', variable: '--dialog-border' },
|
|
24
|
+
{ label: 'border width', groupKey: 'width', variable: '--dialog-border-width' },
|
|
25
|
+
{ label: 'corner radius', variable: '--dialog-radius' },
|
|
26
|
+
{ label: 'dialog shadow', variable: '--dialog-shadow' },
|
|
27
|
+
{ label: 'background blur', variable: '--dialog-blur' },
|
|
28
|
+
],
|
|
29
|
+
header: [
|
|
30
|
+
{ label: 'surface color', groupKey: 'surface', variable: '--dialog-header-surface' },
|
|
31
|
+
{ label: 'border color', groupKey: 'border', variable: '--dialog-header-border' },
|
|
32
|
+
{ label: 'border width', groupKey: 'width', variable: '--dialog-header-border-width' },
|
|
33
|
+
{ label: 'padding', groupKey: 'padding', variable: '--dialog-header-padding' },
|
|
34
|
+
{ label: 'close icon color', groupKey: 'icon', variable: '--dialog-close-icon' },
|
|
35
|
+
{ label: 'close icon size', groupKey: 'size', variable: '--dialog-close-icon-size' },
|
|
36
|
+
],
|
|
37
|
+
body: [
|
|
38
|
+
{ label: 'padding', groupKey: 'padding', variable: '--dialog-body-padding' },
|
|
39
|
+
],
|
|
40
|
+
footer: [
|
|
41
|
+
{ label: 'border color', groupKey: 'border', variable: '--dialog-footer-border' },
|
|
42
|
+
{ label: 'border width', groupKey: 'width', variable: '--dialog-footer-border-width' },
|
|
43
|
+
{ label: 'padding', groupKey: 'padding', variable: '--dialog-footer-padding' },
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const frameTypeGroups: Record<string, TypeGroupConfig[]> = {
|
|
48
|
+
header: [{
|
|
49
|
+
legend: 'title',
|
|
50
|
+
colorVariable: '--dialog-title',
|
|
51
|
+
familyVariable: '--dialog-title-font-family',
|
|
52
|
+
sizeVariable: '--dialog-title-font-size',
|
|
53
|
+
weightVariable: '--dialog-title-font-weight',
|
|
54
|
+
lineHeightVariable: '--dialog-title-line-height',
|
|
55
|
+
}],
|
|
56
|
+
body: [{
|
|
57
|
+
legend: 'body text',
|
|
58
|
+
colorVariable: '--dialog-body',
|
|
59
|
+
familyVariable: '--dialog-body-font-family',
|
|
60
|
+
sizeVariable: '--dialog-body-font-size',
|
|
61
|
+
weightVariable: '--dialog-body-font-weight',
|
|
62
|
+
lineHeightVariable: '--dialog-body-line-height',
|
|
63
|
+
}],
|
|
64
|
+
};
|
|
65
|
+
// Slot-prefixed groupKeys keep title and body typography independent.
|
|
66
|
+
// Sharing a groupKey would phantom-link the two slots in the schema without
|
|
67
|
+
// surfacing the link in the LinkedBlock.
|
|
68
|
+
const frameTypeGroupTokens: Token[] = [
|
|
69
|
+
{ label: 'font family', groupKey: 'title-font-family', variable: '--dialog-title-font-family' },
|
|
70
|
+
{ label: 'font size', groupKey: 'title-font-size', variable: '--dialog-title-font-size' },
|
|
71
|
+
{ label: 'font weight', groupKey: 'title-font-weight', variable: '--dialog-title-font-weight' },
|
|
72
|
+
{ label: 'line height', groupKey: 'title-line-height', variable: '--dialog-title-line-height' },
|
|
73
|
+
{ label: 'font family', groupKey: 'body-font-family', variable: '--dialog-body-font-family' },
|
|
74
|
+
{ label: 'font size', groupKey: 'body-font-size', variable: '--dialog-body-font-size' },
|
|
75
|
+
{ label: 'font weight', groupKey: 'body-font-weight', variable: '--dialog-body-font-weight' },
|
|
76
|
+
{ label: 'line height', groupKey: 'body-line-height', variable: '--dialog-body-line-height' },
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
export const allTokens: Token[] = [
|
|
80
|
+
...Object.values(frameStates).flat(),
|
|
81
|
+
...buildTypeGroupColorTokens(frameTypeGroups),
|
|
82
|
+
...frameTypeGroupTokens,
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
function variantLabel(v: ButtonVariant): string {
|
|
86
|
+
return v.charAt(0).toUpperCase() + v.slice(1);
|
|
87
|
+
}
|
|
88
|
+
</script>
|
|
89
|
+
|
|
90
|
+
<script lang="ts">
|
|
91
|
+
import Dialog from '../components/Dialog.svelte';
|
|
92
|
+
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
93
|
+
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
94
|
+
import { editorState, setComponentConfig } from '../lib/editorStore';
|
|
95
|
+
import ShadowBackdrop from './scaffolding/ShadowBackdrop.svelte';
|
|
96
|
+
import ShadowBackdropControls from './scaffolding/ShadowBackdropControls.svelte';
|
|
97
|
+
|
|
98
|
+
$: config = $editorState.components.dialog?.config ?? {};
|
|
99
|
+
$: confirmVariant = (BUTTON_VARIANTS.includes(config[CONFIRM_VAR] as ButtonVariant) ? config[CONFIRM_VAR] : DEFAULT_CONFIRM) as ButtonVariant;
|
|
100
|
+
$: cancelVariant = (BUTTON_VARIANTS.includes(config[CANCEL_VAR] as ButtonVariant) ? config[CANCEL_VAR] : DEFAULT_CANCEL) as ButtonVariant;
|
|
101
|
+
|
|
102
|
+
function setConfirmVariant(e: Event) {
|
|
103
|
+
const v = (e.target as HTMLSelectElement).value;
|
|
104
|
+
setComponentConfig(component, CONFIRM_VAR, v);
|
|
105
|
+
}
|
|
106
|
+
function setCancelVariant(e: Event) {
|
|
107
|
+
const v = (e.target as HTMLSelectElement).value;
|
|
108
|
+
setComponentConfig(component, CANCEL_VAR, v);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let bgMode: 'image' | 'color' = 'image';
|
|
112
|
+
const bgVar = '--backdrop-dialog-surface';
|
|
113
|
+
</script>
|
|
114
|
+
|
|
115
|
+
<ComponentEditorBase {component} title="Dialog" description="Modal dialog with focus management and slide-in animation. Import from <code>components/Dialog.svelte</code>" tokens={allTokens}>
|
|
116
|
+
<svelte:fragment slot="config">
|
|
117
|
+
<label>
|
|
118
|
+
<span>Cancel button (left)</span>
|
|
119
|
+
<select class="form-select" value={cancelVariant} on:change={setCancelVariant}>
|
|
120
|
+
{#each BUTTON_VARIANTS as v}
|
|
121
|
+
<option value={v}>{variantLabel(v)}</option>
|
|
122
|
+
{/each}
|
|
123
|
+
</select>
|
|
124
|
+
</label>
|
|
125
|
+
<label>
|
|
126
|
+
<span>Confirm button (right)</span>
|
|
127
|
+
<select class="form-select" value={confirmVariant} on:change={setConfirmVariant}>
|
|
128
|
+
{#each BUTTON_VARIANTS as v}
|
|
129
|
+
<option value={v}>{variantLabel(v)}</option>
|
|
130
|
+
{/each}
|
|
131
|
+
</select>
|
|
132
|
+
</label>
|
|
133
|
+
<ShadowBackdropControls bind:mode={bgMode} colorVariable={bgVar} />
|
|
134
|
+
</svelte:fragment>
|
|
135
|
+
<div class="dialog-preview">
|
|
136
|
+
<ShadowBackdrop mode={bgMode} colorVariable={bgVar} padding="0">
|
|
137
|
+
<Dialog
|
|
138
|
+
show
|
|
139
|
+
inline
|
|
140
|
+
title="Sample Dialog"
|
|
141
|
+
confirm={{ label: 'Save', onClick: () => {} }}
|
|
142
|
+
cancel={{ label: 'Cancel', onClick: () => {} }}
|
|
143
|
+
>
|
|
144
|
+
<p style="margin: 0;">This is the dialog body content. It supports any slotted content including forms, lists, or other components.</p>
|
|
145
|
+
</Dialog>
|
|
146
|
+
</ShadowBackdrop>
|
|
147
|
+
</div>
|
|
148
|
+
<VariantGroup name="dialog" title="Dialog" states={frameStates} typeGroups={frameTypeGroups} {component} />
|
|
149
|
+
</ComponentEditorBase>
|
|
150
|
+
|
|
151
|
+
<style>
|
|
152
|
+
.dialog-preview {
|
|
153
|
+
display: flex;
|
|
154
|
+
justify-content: center;
|
|
155
|
+
align-items: center;
|
|
156
|
+
width: 100%;
|
|
157
|
+
min-width: 0;
|
|
158
|
+
}
|
|
159
|
+
.dialog-preview :global(.shadow-backdrop) {
|
|
160
|
+
display: flex;
|
|
161
|
+
justify-content: center;
|
|
162
|
+
align-items: center;
|
|
163
|
+
width: 100%;
|
|
164
|
+
min-width: 0;
|
|
165
|
+
}
|
|
166
|
+
.dialog-preview :global(.dialog-backdrop.inline) {
|
|
167
|
+
width: auto;
|
|
168
|
+
box-sizing: border-box;
|
|
169
|
+
padding: clamp(24px, 6vw, 128px);
|
|
170
|
+
}
|
|
171
|
+
</style>
|
|
172
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<script context="module" lang="ts">
|
|
2
|
+
import type { Token } from './scaffolding/types';
|
|
3
|
+
|
|
4
|
+
export const component = 'image';
|
|
5
|
+
|
|
6
|
+
// Single object: image frame.
|
|
7
|
+
const states: Record<string, Token[]> = {
|
|
8
|
+
image: [
|
|
9
|
+
{ label: 'border color', groupKey: 'border', variable: '--image-default-border' },
|
|
10
|
+
{ label: 'border width', groupKey: 'width', variable: '--image-default-border-width' },
|
|
11
|
+
{ label: 'corner radius', groupKey: 'radius', variable: '--image-default-radius' },
|
|
12
|
+
{ label: 'image shadow', groupKey: 'shadow', variable: '--image-default-shadow' },
|
|
13
|
+
],
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const allTokens: Token[] = Object.values(states).flat();
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<script lang="ts">
|
|
20
|
+
import { onMount } from 'svelte';
|
|
21
|
+
import Image from '../components/Image.svelte';
|
|
22
|
+
import VariantGroup from './scaffolding/VariantGroup.svelte';
|
|
23
|
+
import ComponentEditorBase from './scaffolding/ComponentEditorBase.svelte';
|
|
24
|
+
import demoImageUrl from '../assets/offering.webp';
|
|
25
|
+
import ShadowBackdrop from './scaffolding/ShadowBackdrop.svelte';
|
|
26
|
+
import UIPaletteSelector from '../ui/UIPaletteSelector.svelte';
|
|
27
|
+
import { setCssVar } from '../lib/cssVarSync';
|
|
28
|
+
|
|
29
|
+
const bgVar = '--backdrop-image-surface';
|
|
30
|
+
|
|
31
|
+
onMount(() => {
|
|
32
|
+
if (!document.documentElement.style.getPropertyValue(bgVar)) {
|
|
33
|
+
setCssVar(bgVar, 'var(--surface-canvas)');
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<ComponentEditorBase {component} title="Image" description="Framed image with rounded corners, border, and shadow. Import from <code>components/Image.svelte</code>" tokens={allTokens}>
|
|
39
|
+
<svelte:fragment slot="config">
|
|
40
|
+
<label class="backdrop-config">
|
|
41
|
+
<span>Sample background</span>
|
|
42
|
+
<div class="picker-slot">
|
|
43
|
+
<UIPaletteSelector variable={bgVar} />
|
|
44
|
+
</div>
|
|
45
|
+
</label>
|
|
46
|
+
</svelte:fragment>
|
|
47
|
+
<VariantGroup name="image" title="Image" {states} {component}>
|
|
48
|
+
<ShadowBackdrop mode="color" colorVariable={bgVar}>
|
|
49
|
+
<div class="image-demo-grid">
|
|
50
|
+
<Image src={demoImageUrl} alt="Demo" variant="banner" />
|
|
51
|
+
</div>
|
|
52
|
+
</ShadowBackdrop>
|
|
53
|
+
</VariantGroup>
|
|
54
|
+
</ComponentEditorBase>
|
|
55
|
+
|
|
56
|
+
<style>
|
|
57
|
+
.image-demo-grid {
|
|
58
|
+
display: grid;
|
|
59
|
+
place-items: center;
|
|
60
|
+
}
|
|
61
|
+
.backdrop-config {
|
|
62
|
+
display: inline-flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
gap: var(--ui-space-8);
|
|
65
|
+
}
|
|
66
|
+
.picker-slot {
|
|
67
|
+
min-width: 8rem;
|
|
68
|
+
}
|
|
69
|
+
.picker-slot :global(.ui-token-selector) {
|
|
70
|
+
width: 100%;
|
|
71
|
+
}
|
|
72
|
+
</style>
|