@motion-proto/live-tokens 0.6.2 → 0.8.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 +14 -13
- package/dist-plugin/index.cjs +854 -226
- package/dist-plugin/index.d.cts +2 -1
- package/dist-plugin/index.d.ts +2 -1
- package/dist-plugin/index.js +852 -225
- package/package.json +26 -40
- package/src/{styles → app}/site.css +1 -1
- package/src/{component-editor → editor/component-editor}/BadgeEditor.svelte +8 -82
- package/src/{component-editor → editor/component-editor}/CalloutEditor.svelte +4 -4
- package/src/{component-editor → editor/component-editor}/CardEditor.svelte +28 -76
- package/src/{component-editor → editor/component-editor}/CollapsibleSectionEditor.svelte +37 -30
- package/src/{component-editor → editor/component-editor}/CornerBadgeEditor.svelte +31 -93
- package/src/{component-editor → editor/component-editor}/DialogEditor.svelte +60 -57
- package/src/editor/component-editor/ImageEditor.svelte +30 -0
- package/src/{component-editor → editor/component-editor}/InlineEditActionsEditor.svelte +6 -4
- package/src/editor/component-editor/MenuSelectEditor.svelte +160 -0
- package/src/{component-editor → editor/component-editor}/NotificationEditor.svelte +67 -38
- package/src/{component-editor → editor/component-editor}/ProgressBarEditor.svelte +5 -4
- package/src/{component-editor → editor/component-editor}/RadioButtonEditor.svelte +3 -3
- package/src/editor/component-editor/SectionDividerEditor.svelte +565 -0
- package/src/{component-editor → editor/component-editor}/SegmentedControlEditor.svelte +2 -2
- package/src/{component-editor → editor/component-editor}/StandardButtonsEditor.svelte +29 -21
- package/src/{component-editor → editor/component-editor}/TabBarEditor.svelte +9 -14
- package/src/{component-editor → editor/component-editor}/TableEditor.svelte +9 -18
- package/src/{component-editor → editor/component-editor}/TooltipEditor.svelte +11 -47
- package/src/editor/component-editor/editors.d.ts +10 -0
- package/src/{component-editor → editor/component-editor}/registry.ts +28 -18
- package/src/{component-editor → editor/component-editor}/scaffolding/AngleDial.svelte +54 -15
- package/src/{component-editor → editor/component-editor}/scaffolding/ComponentEditorBase.svelte +3 -51
- package/src/{component-editor → editor/component-editor}/scaffolding/ComponentFileManager.svelte +151 -424
- package/src/{component-editor → editor/component-editor}/scaffolding/ComponentFileMenu.svelte +18 -170
- package/src/{component-editor → editor/component-editor}/scaffolding/ComponentsTab.svelte +2 -2
- package/src/{component-editor → editor/component-editor}/scaffolding/CopyFromMenu.svelte +44 -4
- package/src/{component-editor → editor/component-editor}/scaffolding/FieldsetWrapper.svelte +1 -1
- package/src/{component-editor → editor/component-editor}/scaffolding/LinkageChart.svelte +6 -6
- package/src/{component-editor → editor/component-editor}/scaffolding/LinkedBlock.svelte +6 -12
- package/src/editor/component-editor/scaffolding/NonStylableConfig.svelte +38 -0
- package/src/editor/component-editor/scaffolding/RadialShapePad.svelte +483 -0
- package/src/{component-editor → editor/component-editor}/scaffolding/SaveAsDialog.svelte +66 -12
- package/src/editor/component-editor/scaffolding/ShadowBackdrop.svelte +85 -0
- package/src/editor/component-editor/scaffolding/ShadowBackdropControls.svelte +132 -0
- package/src/editor/component-editor/scaffolding/StateBlock.svelte +345 -0
- package/src/{component-editor → editor/component-editor}/scaffolding/TokenLayout.svelte +17 -12
- package/src/{component-editor → editor/component-editor}/scaffolding/TypeEditor.svelte +13 -1
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +858 -0
- package/src/{component-editor → editor/component-editor}/scaffolding/buildTypeGroupTokens.ts +1 -0
- package/src/{component-editor → editor/component-editor}/scaffolding/editorContext.ts +19 -9
- package/src/{component-editor → editor/component-editor}/scaffolding/linkedBlock.ts +2 -2
- package/src/{component-editor → editor/component-editor}/scaffolding/types.ts +25 -0
- package/src/{lib → editor/core/components}/componentConfigKeys.ts +8 -0
- package/src/{lib → editor/core/components}/componentConfigService.ts +3 -3
- package/src/{lib → editor/core/components}/componentPersist.ts +11 -9
- package/src/editor/core/flashStatus.ts +30 -0
- package/src/{lib → editor/core/fonts}/fontLoader.ts +2 -2
- package/src/{lib → editor/core/fonts}/fontMigration.ts +4 -4
- package/src/{lib → editor/core/fonts}/fontParse.ts +1 -1
- package/src/editor/core/manifests/manifestService.ts +171 -0
- package/src/editor/core/palettes/familySwap.ts +99 -0
- package/src/{lib → editor/core/palettes}/paletteDerivation.ts +71 -2
- package/src/{lib → editor/core/palettes}/tokenRegistry.ts +9 -6
- package/src/editor/core/productionPulse.ts +37 -0
- package/src/{lib → editor/core/routing}/router.ts +1 -1
- package/src/{lib/files/versionedFileResource.ts → editor/core/storage/files/versionedFileResourceClient.ts} +8 -1
- package/src/{lib → editor/core/store}/editorCore.ts +24 -8
- package/src/{lib → editor/core/store}/editorPersistence.ts +3 -3
- package/src/{lib → editor/core/store}/editorRenderer.ts +2 -2
- package/src/{lib → editor/core/store}/editorStore.ts +222 -28
- package/src/{lib → editor/core/store}/editorTypes.ts +56 -13
- package/src/editor/core/store/gradientSource.ts +192 -0
- package/src/editor/core/themes/migrations/2026-05-19-collapsiblesection-drop-frame-surface.ts +28 -0
- package/src/editor/core/themes/migrations/2026-05-19-sectiondivider-rich-gradient.ts +35 -0
- package/src/editor/core/themes/migrations/2026-05-20-sectiondivider-slim-variants.ts +82 -0
- package/src/editor/core/themes/migrations/2026-05-21-sectiondivider-spacing-to-padding.ts +24 -0
- package/src/editor/core/themes/migrations/2026-05-22-sectiondivider-intrinsics-to-css.ts +81 -0
- package/src/{lib → editor/core/themes}/migrations/index.ts +10 -0
- package/src/{lib → editor/core/themes}/slices/columns.ts +2 -2
- package/src/{lib → editor/core/themes}/slices/components.ts +20 -6
- package/src/{lib → editor/core/themes}/slices/fonts.ts +1 -1
- package/src/{lib → editor/core/themes}/slices/gradients.ts +89 -14
- package/src/{lib → editor/core/themes}/slices/overlays.ts +1 -1
- package/src/{lib → editor/core/themes}/slices/palettes.ts +1 -1
- package/src/{lib → editor/core/themes}/slices/shadows.ts +3 -3
- package/src/{lib → editor/core/themes}/themeInit.ts +8 -8
- package/src/{lib → editor/core/themes}/themeService.ts +6 -6
- package/src/{lib → editor/core/themes}/themeTypes.ts +67 -8
- package/src/editor/index.ts +69 -0
- package/src/{lib → editor/overlay}/ColumnsOverlay.svelte +0 -1
- package/src/{lib → editor/overlay}/LiveEditorOverlay.svelte +80 -129
- package/src/{lib → editor/overlay}/columnsOverlay.ts +2 -2
- package/src/{pages → editor/pages}/ComponentEditorPage.svelte +12 -12
- package/src/{pages → editor/pages}/Editor.svelte +4 -4
- package/src/{pages → editor/pages}/EditorShell.svelte +18 -36
- package/src/{styles → editor/styles}/ui-editor.css +43 -22
- package/src/{styles → editor/styles}/ui-form-controls.css +23 -24
- package/src/{ui → editor/ui}/BezierCurveEditor.svelte +119 -68
- package/src/{ui → editor/ui}/ColorEditPanel.svelte +13 -13
- package/src/{ui → editor/ui}/EditorViewSwitcher.svelte +7 -6
- package/src/editor/ui/FileLoadList.svelte +367 -0
- package/src/editor/ui/FilePill.svelte +80 -0
- package/src/editor/ui/FontStackEditor.svelte +499 -0
- package/src/editor/ui/GradientEditor.svelte +690 -0
- package/src/{ui → editor/ui}/GradientStopPicker.svelte +12 -4
- package/src/editor/ui/ManifestFileManager.svelte +438 -0
- package/src/{ui → editor/ui}/PaletteEditor.svelte +180 -673
- package/src/editor/ui/ProjectFontsSection.svelte +638 -0
- package/src/{ui → editor/ui}/SurfacesTab.svelte +3 -3
- package/src/{ui → editor/ui}/TextTab.svelte +3 -3
- package/src/editor/ui/ThemeFileManager.svelte +783 -0
- package/src/{ui → editor/ui}/UICopyPopover.svelte +4 -4
- package/src/{ui → editor/ui}/UIFontFamilySelector.svelte +6 -7
- package/src/{ui → editor/ui}/UIFontSizeSelector.svelte +4 -1
- package/src/editor/ui/UIInfoPopover.svelte +243 -0
- package/src/editor/ui/UILetterSpacingSelector.svelte +65 -0
- package/src/{ui → editor/ui}/UILineHeightSelector.svelte +5 -5
- package/src/{ui → editor/ui}/UILinkToggle.svelte +2 -2
- package/src/{ui → editor/ui}/UIPaddingSelector.svelte +6 -6
- package/src/{ui → editor/ui}/UIPaletteSelector.svelte +57 -30
- package/src/editor/ui/UIPillButton.svelte +168 -0
- package/src/{ui → editor/ui}/UIRadio.svelte +2 -2
- package/src/{ui → editor/ui}/UIRelinkConfirmPopover.svelte +4 -4
- package/src/editor/ui/UISegmentedControl.svelte +114 -0
- package/src/editor/ui/UISquareButton.svelte +172 -0
- package/src/{ui → editor/ui}/UITokenSelector.svelte +14 -11
- package/src/{ui → editor/ui}/UIVariantSelector.svelte +1 -1
- package/src/{ui → editor/ui}/VariablesTab.svelte +46 -17
- package/src/{ui → editor/ui}/palette/GradientStopEditor.svelte +13 -13
- package/src/{ui → editor/ui}/palette/OverridesPanel.svelte +24 -47
- package/src/{ui → editor/ui}/palette/PaletteBase.svelte +11 -8
- package/src/{ui → editor/ui}/palette/paletteEditorState.ts +1 -1
- package/src/editor/ui/palette/paletteMath.ts +275 -0
- package/src/{ui → editor/ui}/sections/ColumnsSection.svelte +137 -18
- package/src/{ui → editor/ui}/sections/GradientsSection.svelte +8 -8
- package/src/{ui → editor/ui}/sections/OverlaysSection.svelte +18 -18
- package/src/{ui → editor/ui}/sections/ShadowsSection.svelte +23 -23
- package/src/{ui → editor/ui}/sections/TokenScaleTable.svelte +3 -3
- package/src/{components → system/components}/Badge.svelte +0 -36
- package/src/{components → system/components}/Button.svelte +2 -2
- package/src/{components → system/components}/Card.svelte +34 -60
- package/src/{components → system/components}/CollapsibleSection.svelte +25 -2
- package/src/{components → system/components}/CornerBadge.svelte +8 -24
- package/src/{components → system/components}/Dialog.svelte +1 -1
- package/src/system/components/FloatingTokenTags.css +275 -0
- package/src/system/components/FloatingTokenTags.svelte +543 -0
- package/src/{components → system/components}/InlineEditActions.svelte +6 -4
- package/src/system/components/MenuSelect.svelte +229 -0
- package/src/{components → system/components}/Notification.svelte +8 -1
- package/src/{components → system/components}/ProgressBar.svelte +29 -11
- package/src/system/components/SectionDivider.svelte +560 -0
- package/src/{components → system/components}/SegmentedControl.svelte +49 -43
- package/src/{components → system/components}/TabBar.svelte +81 -65
- package/src/{components → system/components}/Table.svelte +17 -3
- package/src/{components → system/components}/Tooltip.svelte +6 -4
- package/src/system/styles/CONVENTIONS.md +178 -0
- package/src/system/styles/fonts.css +20 -0
- package/src/system/styles/tokens.css +601 -0
- package/src/system/styles/tokens.generated.css +544 -0
- package/src/component-editor/ImageEditor.svelte +0 -74
- package/src/component-editor/SectionDividerEditor.svelte +0 -265
- package/src/component-editor/scaffolding/DividerEditor.svelte +0 -94
- package/src/component-editor/scaffolding/GradientCard.svelte +0 -296
- package/src/component-editor/scaffolding/NonStylableConfig.svelte +0 -62
- package/src/component-editor/scaffolding/ShadowBackdrop.svelte +0 -37
- package/src/component-editor/scaffolding/ShadowBackdropControls.svelte +0 -61
- package/src/component-editor/scaffolding/StateBlock.svelte +0 -132
- package/src/component-editor/scaffolding/VariantGroup.svelte +0 -310
- package/src/components/SectionDivider.svelte +0 -483
- package/src/data/google-fonts.json +0 -75
- package/src/lib/index.ts +0 -68
- package/src/lib/presetService.ts +0 -214
- package/src/lib/productionPulse.ts +0 -32
- package/src/styles/fonts.css +0 -30
- package/src/styles/tokens.css +0 -1324
- package/src/ui/FontStackEditor.svelte +0 -361
- package/src/ui/GradientEditor.svelte +0 -470
- package/src/ui/PresetFileManager.svelte +0 -1116
- package/src/ui/ProjectFontsSection.svelte +0 -645
- package/src/ui/ThemeFileManager.svelte +0 -1020
- package/src/ui/UnsavedComponentsDialog.svelte +0 -315
- /package/src/{component-editor → editor/component-editor}/index.ts +0 -0
- /package/src/{component-editor → editor/component-editor}/scaffolding/DemoHeader.svelte +0 -0
- /package/src/{component-editor → editor/component-editor}/scaffolding/componentSectionType.ts +0 -0
- /package/src/{component-editor → editor/component-editor}/scaffolding/componentSources.ts +0 -0
- /package/src/{component-editor → editor/component-editor}/scaffolding/defaultSections.ts +0 -0
- /package/src/{component-editor → editor/component-editor}/scaffolding/siblings.ts +0 -0
- /package/src/{lib → editor/core}/cssVarSync.ts +0 -0
- /package/src/{lib → editor/core/palettes}/oklch.ts +0 -0
- /package/src/{lib → editor/core/routing}/navLinkTypes.ts +0 -0
- /package/src/{lib → editor/core/routing}/parentRouteStore.ts +0 -0
- /package/src/{lib → editor/core/storage}/storage.ts +0 -0
- /package/src/{lib → editor/core/store}/editorConfig.ts +0 -0
- /package/src/{lib → editor/core/store}/editorConfigStore.ts +0 -0
- /package/src/{lib → editor/core/store}/editorKeybindings.ts +0 -0
- /package/src/{lib → editor/core/store}/editorViewStore.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-04-24-component-prefix-and-suffix-renames.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-04-24-legacy-keys-and-bg-to-canvas.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-04-27-segmentedcontrol-disabled-flatten.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-05-08-collapsiblesection-frame-and-cleanup.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-05-08-collapsiblesection-variant-namespace.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-05-10-sectiondivider-gradient-stops.ts +0 -0
- /package/src/{lib → editor/core/themes}/migrations/2026-05-13-primary-to-brand.ts +0 -0
- /package/src/{lib → editor/core/themes}/parsers/globalRootBlock.ts +0 -0
- /package/src/{lib → editor/core/themes}/slices/domainVars.ts +0 -0
- /package/src/{lib → editor/overlay}/overlayState.ts +0 -0
- /package/src/{pages → editor/pages}/ComponentEditorPage.svelte.d.ts +0 -0
- /package/src/{pages → editor/pages}/Editor.svelte.d.ts +0 -0
- /package/src/{ui → editor/ui}/Toggle.svelte +0 -0
- /package/src/{ui → editor/ui}/UIDialog.svelte +0 -0
- /package/src/{ui → editor/ui}/UIFontWeightSelector.svelte +0 -0
- /package/src/{ui → editor/ui}/UIOptionItem.svelte +0 -0
- /package/src/{ui → editor/ui}/UIOptionList.svelte +0 -0
- /package/src/{ui → editor/ui}/UIRadioGroup.svelte +0 -0
- /package/src/{lib → editor/ui}/copyPopover.ts +0 -0
- /package/src/{ui → editor/ui}/curveEngine.ts +0 -0
- /package/src/{ui → editor/ui}/index.ts +0 -0
- /package/src/{ui → editor/ui}/keepInViewport.ts +0 -0
- /package/src/{ui → editor/ui}/palette/ScaleCurveEditor.svelte +0 -0
- /package/src/{lib → editor/ui}/scrollSection.ts +0 -0
- /package/src/{ui → editor/ui}/sections/tokenScales.ts +0 -0
- /package/src/{ui → editor/ui}/variantScales.ts +0 -0
- /package/src/{assets → system/assets}/newspaper.webp +0 -0
- /package/src/{assets → system/assets}/offering.webp +0 -0
- /package/src/{components → system/components}/Callout.svelte +0 -0
- /package/src/{components → system/components}/Image.svelte +0 -0
- /package/src/{components → system/components}/RadioButton.svelte +0 -0
- /package/src/{components → system/components}/types.ts +0 -0
- /package/src/{styles → system/styles}/_padding.scss +0 -0
- /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-italic-latin-ext.woff2 +0 -0
- /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-italic-latin.woff2 +0 -0
- /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-roman-latin-ext.woff2 +0 -0
- /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-roman-latin.woff2 +0 -0
- /package/src/{styles → system/styles}/fonts/Manrope/Manrope-latin-ext.woff2 +0 -0
- /package/src/{styles → system/styles}/fonts/Manrope/Manrope-latin.woff2 +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import newspaperBg from '../../../system/assets/newspaper.webp';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
mode?: 'default' | 'image' | 'color';
|
|
8
|
+
/** CSS var name (set by ShadowBackdropControls) the backdrop reads when in color mode. */
|
|
9
|
+
colorVariable?: string;
|
|
10
|
+
/** Padding around the slotted preview content. Set to '0' when the slotted component should cover the full backdrop area (e.g. dialog overlay). */
|
|
11
|
+
padding?: string;
|
|
12
|
+
children?: import('svelte').Snippet;
|
|
13
|
+
/** Optional right-rail snippet rendered inside the backdrop as a fixed-width column. Used for canvas-scoped settings (e.g. Background controls). */
|
|
14
|
+
controls?: import('svelte').Snippet;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let {
|
|
18
|
+
mode = 'default',
|
|
19
|
+
colorVariable,
|
|
20
|
+
padding = '4rem',
|
|
21
|
+
children,
|
|
22
|
+
controls
|
|
23
|
+
}: Props = $props();
|
|
24
|
+
|
|
25
|
+
let backgroundStyle = $derived.by(() => {
|
|
26
|
+
if (mode === 'image') {
|
|
27
|
+
return `background-image: url(${newspaperBg}); background-size: cover; background-position: center; background-repeat: no-repeat;`;
|
|
28
|
+
}
|
|
29
|
+
if (mode === 'color' && colorVariable) {
|
|
30
|
+
return `background: var(${colorVariable}, #1a1a1a);`;
|
|
31
|
+
}
|
|
32
|
+
return `background: var(--ui-surface-lowest); border: 1px solid var(--ui-border-low);`;
|
|
33
|
+
});
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<div class="shadow-backdrop" class:with-controls={!!controls} style={backgroundStyle}>
|
|
37
|
+
<div class="shadow-backdrop-content" style="padding: {padding} {padding} {padding} 1.5rem;">
|
|
38
|
+
{@render children?.()}
|
|
39
|
+
</div>
|
|
40
|
+
{#if controls}
|
|
41
|
+
<div class="shadow-backdrop-controls">
|
|
42
|
+
{@render controls?.()}
|
|
43
|
+
</div>
|
|
44
|
+
{/if}
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
.shadow-backdrop {
|
|
49
|
+
display: grid;
|
|
50
|
+
grid-template-columns: minmax(0, 1fr);
|
|
51
|
+
width: 100%;
|
|
52
|
+
min-width: 0;
|
|
53
|
+
min-height: 12rem;
|
|
54
|
+
border-radius: var(--ui-radius-md);
|
|
55
|
+
box-sizing: border-box;
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.shadow-backdrop.with-controls {
|
|
60
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
61
|
+
grid-template-areas: "preview controls";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.shadow-backdrop-content {
|
|
65
|
+
display: grid;
|
|
66
|
+
align-items: center;
|
|
67
|
+
justify-items: start;
|
|
68
|
+
min-width: 0;
|
|
69
|
+
grid-area: preview;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.shadow-backdrop-controls {
|
|
73
|
+
padding: var(--ui-space-8);
|
|
74
|
+
grid-area: controls;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@container variant-group (max-width: 32rem) {
|
|
78
|
+
.shadow-backdrop.with-controls {
|
|
79
|
+
grid-template-columns: minmax(0, 1fr);
|
|
80
|
+
grid-template-areas:
|
|
81
|
+
"controls"
|
|
82
|
+
"preview";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
</style>
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
import UIPaletteSelector from '../../ui/UIPaletteSelector.svelte';
|
|
4
|
+
import { setCssVar } from '../../core/cssVarSync';
|
|
5
|
+
|
|
6
|
+
type Mode = 'default' | 'image' | 'color';
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
mode?: Mode;
|
|
10
|
+
/** Editor-scoped CSS var the picker writes to (must end with `-surface` to allow gradients). */
|
|
11
|
+
colorVariable: string;
|
|
12
|
+
/** Which modes to expose. Defaults to all three. */
|
|
13
|
+
modes?: ReadonlyArray<Mode>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let { mode = $bindable('default'), colorVariable, modes = ['default', 'image', 'color'] }: Props = $props();
|
|
17
|
+
|
|
18
|
+
const ALL_OPTIONS: ReadonlyArray<{ value: Mode; label: string }> = [
|
|
19
|
+
{ value: 'default', label: 'Default' },
|
|
20
|
+
{ value: 'image', label: 'Image' },
|
|
21
|
+
{ value: 'color', label: 'Color' },
|
|
22
|
+
];
|
|
23
|
+
let options = $derived(ALL_OPTIONS.filter((o) => modes.includes(o.value)));
|
|
24
|
+
|
|
25
|
+
onMount(() => {
|
|
26
|
+
if (!document.documentElement.style.getPropertyValue(colorVariable)) {
|
|
27
|
+
setCssVar(colorVariable, 'var(--surface-canvas)');
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<div class="backdrop-grid" role="radiogroup">
|
|
33
|
+
{#each options as opt (opt.value)}
|
|
34
|
+
<div
|
|
35
|
+
class="backdrop-option"
|
|
36
|
+
class:checked={mode === opt.value}
|
|
37
|
+
role="radio"
|
|
38
|
+
aria-checked={mode === opt.value}
|
|
39
|
+
aria-label={opt.label}
|
|
40
|
+
tabindex={mode === opt.value ? 0 : -1}
|
|
41
|
+
onclick={() => (mode = opt.value)}
|
|
42
|
+
onkeydown={(e) => {
|
|
43
|
+
if (e.key === ' ' || e.key === 'Enter') {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
mode = opt.value;
|
|
46
|
+
}
|
|
47
|
+
}}
|
|
48
|
+
>
|
|
49
|
+
<span class="backdrop-dot" aria-hidden="true"></span>
|
|
50
|
+
{#if opt.value !== 'color'}
|
|
51
|
+
<span>{opt.label}</span>
|
|
52
|
+
{:else}
|
|
53
|
+
<div class="picker-slot">
|
|
54
|
+
<UIPaletteSelector variable={colorVariable} />
|
|
55
|
+
</div>
|
|
56
|
+
{/if}
|
|
57
|
+
</div>
|
|
58
|
+
{/each}
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<style>
|
|
62
|
+
.backdrop-grid {
|
|
63
|
+
display: flex;
|
|
64
|
+
flex-direction: column;
|
|
65
|
+
gap: var(--ui-space-4);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Reserve room for the swatch's absolute-positioned token-name caption so it
|
|
69
|
+
doesn't bleed onto whatever sits below the controls. */
|
|
70
|
+
.backdrop-grid:has(.picker-slot) {
|
|
71
|
+
padding-bottom: var(--ui-space-16);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Each row keeps the same vertical rhythm; the trigger's height defines
|
|
75
|
+
the line, so the radio-only rows match it via min-height. The whole row
|
|
76
|
+
is clickable via the onclick handler — selecting on any pointer hit. */
|
|
77
|
+
.backdrop-option {
|
|
78
|
+
display: flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
gap: var(--ui-space-6);
|
|
81
|
+
min-height: 1.75rem;
|
|
82
|
+
font-size: var(--ui-font-size-sm);
|
|
83
|
+
color: var(--ui-text-tertiary);
|
|
84
|
+
cursor: pointer;
|
|
85
|
+
user-select: none;
|
|
86
|
+
transition: color var(--ui-transition-fast);
|
|
87
|
+
}
|
|
88
|
+
.backdrop-option.checked {
|
|
89
|
+
color: var(--ui-text-primary);
|
|
90
|
+
}
|
|
91
|
+
.backdrop-option:focus-visible {
|
|
92
|
+
outline: 2px solid currentColor;
|
|
93
|
+
outline-offset: 2px;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* Custom radio dot replaces native input so the entire row's onclick
|
|
97
|
+
handler runs without label/input dual-activation quirks. */
|
|
98
|
+
.backdrop-dot {
|
|
99
|
+
flex-shrink: 0;
|
|
100
|
+
width: 12px;
|
|
101
|
+
height: 12px;
|
|
102
|
+
border-radius: 50%;
|
|
103
|
+
border: 1.5px solid currentColor;
|
|
104
|
+
background: transparent;
|
|
105
|
+
opacity: 0.6;
|
|
106
|
+
transition: opacity var(--ui-transition-fast), background var(--ui-transition-fast);
|
|
107
|
+
}
|
|
108
|
+
.backdrop-option.checked .backdrop-dot {
|
|
109
|
+
opacity: 1;
|
|
110
|
+
background:
|
|
111
|
+
radial-gradient(circle, currentColor 0 35%, transparent 38%);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.picker-slot {
|
|
115
|
+
position: relative;
|
|
116
|
+
flex: 1;
|
|
117
|
+
min-width: 0;
|
|
118
|
+
}
|
|
119
|
+
.picker-slot :global(.ui-token-selector) {
|
|
120
|
+
width: 100%;
|
|
121
|
+
}
|
|
122
|
+
/* Hang the token name caption under the swatch trigger so it doesn't
|
|
123
|
+
stretch the row's height. */
|
|
124
|
+
.picker-slot :global(.ui-ts-meta-text) {
|
|
125
|
+
position: absolute;
|
|
126
|
+
top: 100%;
|
|
127
|
+
left: 0;
|
|
128
|
+
margin-top: 2px;
|
|
129
|
+
white-space: nowrap;
|
|
130
|
+
pointer-events: none;
|
|
131
|
+
}
|
|
132
|
+
</style>
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Shared inner block rendered inside a single state in VariantGroup.
|
|
4
|
+
*
|
|
5
|
+
* Both the tabs branch and the list branch of VariantGroup render the same
|
|
6
|
+
* `<TypeEditor>` (when a state has type groups) followed by `<TokenLayout>`,
|
|
7
|
+
* differing only in the surrounding chrome (preview placement, toggles,
|
|
8
|
+
* tab strip). This component owns the duplicated inner block so a per-state
|
|
9
|
+
* control change happens in exactly one place.
|
|
10
|
+
*/
|
|
11
|
+
import type { Snippet } from 'svelte';
|
|
12
|
+
import TokenLayout from './TokenLayout.svelte';
|
|
13
|
+
import TypeEditor from './TypeEditor.svelte';
|
|
14
|
+
import type { Token, TypeGroupConfig } from './types';
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
interface ElementToggle {
|
|
22
|
+
checked: boolean;
|
|
23
|
+
label?: string;
|
|
24
|
+
onchange: (checked: boolean) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface Props {
|
|
28
|
+
/** Tokens for this state, fed to `<TokenLayout>`. */
|
|
29
|
+
tokens: Token[];
|
|
30
|
+
/** Type groups for this state; rendered as a row of `<TypeEditor>` blocks. */
|
|
31
|
+
typeGroups?: TypeGroupConfig[];
|
|
32
|
+
/** Forwarded to TypeEditor and TokenLayout so writes persist through the editor store. */
|
|
33
|
+
component?: string | undefined;
|
|
34
|
+
/** Per-variable rank passed through to TokenLayout for linked-block alignment. */
|
|
35
|
+
linkedOrder?: Map<string, number> | undefined;
|
|
36
|
+
/** Render the token grid with N visual columns. >1 spreads a long property
|
|
37
|
+
list horizontally; only meaningful for state-blocks without typeGroups
|
|
38
|
+
(the two-col flex layout already partitions screen real estate when
|
|
39
|
+
typeGroups are present). */
|
|
40
|
+
columns?: number;
|
|
41
|
+
/** Per-element Show toggle. When provided for an element in element-grouped
|
|
42
|
+
mode, renders a checkbox next to that section's heading. The token rows
|
|
43
|
+
below stay visible regardless — the toggle drives preview visibility,
|
|
44
|
+
not editor visibility. */
|
|
45
|
+
elementToggles?: Record<string, ElementToggle>;
|
|
46
|
+
/** Explicit element ordering. Defaults to first-encounter across tokens
|
|
47
|
+
then typeGroups, which works when structural elements (frame, container)
|
|
48
|
+
come before named typography elements. Pass an explicit order when the
|
|
49
|
+
natural first-encounter wouldn't produce the right reading order. */
|
|
50
|
+
elementOrder?: string[];
|
|
51
|
+
/** Element-keyed snippet rendered between the section heading and the
|
|
52
|
+
section's typography/tokens. Lets callers inject per-element controls
|
|
53
|
+
(e.g. a hairline position dropdown that conceptually belongs in the
|
|
54
|
+
hairline section but isn't a CSS token). */
|
|
55
|
+
elementExtras?: Snippet<[string]>;
|
|
56
|
+
onchange?: () => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let {
|
|
60
|
+
tokens,
|
|
61
|
+
typeGroups = [],
|
|
62
|
+
component = undefined,
|
|
63
|
+
linkedOrder = undefined,
|
|
64
|
+
columns = 1,
|
|
65
|
+
elementToggles = {},
|
|
66
|
+
elementOrder,
|
|
67
|
+
elementExtras,
|
|
68
|
+
onchange,
|
|
69
|
+
}: Props = $props();
|
|
70
|
+
|
|
71
|
+
let hasTypeGroups = $derived(typeGroups.length > 0);
|
|
72
|
+
|
|
73
|
+
/** Element-grouped mode: when 2+ distinct element tags appear across tokens
|
|
74
|
+
and type-groups, partition the panel into labeled subsections (e.g.
|
|
75
|
+
"Frame", "Header", "Body"). Element order = first-encounter across the
|
|
76
|
+
combined tokens + type-groups list. */
|
|
77
|
+
let elementSections = $derived.by(() => {
|
|
78
|
+
const seen = new Set<string>();
|
|
79
|
+
const order: string[] = [];
|
|
80
|
+
if (elementOrder) {
|
|
81
|
+
for (const el of elementOrder) {
|
|
82
|
+
if (!seen.has(el)) { seen.add(el); order.push(el); }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
for (const t of tokens) {
|
|
86
|
+
if (t.element && !seen.has(t.element)) {
|
|
87
|
+
seen.add(t.element);
|
|
88
|
+
order.push(t.element);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
for (const tg of typeGroups) {
|
|
92
|
+
if (tg.element && !seen.has(tg.element)) {
|
|
93
|
+
seen.add(tg.element);
|
|
94
|
+
order.push(tg.element);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (order.length < 2) return null;
|
|
98
|
+
return order.map((el) => ({
|
|
99
|
+
element: el,
|
|
100
|
+
tokens: tokens.filter((t) => t.element === el),
|
|
101
|
+
typeGroups: typeGroups.filter((tg) => tg.element === el),
|
|
102
|
+
}));
|
|
103
|
+
});
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
{#if elementSections}
|
|
107
|
+
<div class="state-controls element-grouped">
|
|
108
|
+
{#each elementSections as section}
|
|
109
|
+
{@const toggle = elementToggles[section.element]}
|
|
110
|
+
<section class="element-section">
|
|
111
|
+
<div class="element-heading-row">
|
|
112
|
+
<h4 class="element-heading">{section.element}</h4>
|
|
113
|
+
{#if toggle}
|
|
114
|
+
<label class="element-show-toggle">
|
|
115
|
+
<input
|
|
116
|
+
type="checkbox"
|
|
117
|
+
checked={toggle.checked}
|
|
118
|
+
onchange={(e) => toggle.onchange((e.currentTarget as HTMLInputElement).checked)}
|
|
119
|
+
/>
|
|
120
|
+
<span>{toggle.label ?? `Show ${section.element}`}</span>
|
|
121
|
+
</label>
|
|
122
|
+
{/if}
|
|
123
|
+
</div>
|
|
124
|
+
{@render elementExtras?.(section.element)}
|
|
125
|
+
{#if section.typeGroups.length > 0}
|
|
126
|
+
<div class="state-type-groups">
|
|
127
|
+
{#each section.typeGroups as tg}
|
|
128
|
+
<TypeEditor
|
|
129
|
+
legend={tg.legend ?? ''}
|
|
130
|
+
colorVariable={tg.colorVariable}
|
|
131
|
+
colorLabel={tg.colorLabel ?? 'text color'}
|
|
132
|
+
familyVariable={tg.familyVariable}
|
|
133
|
+
familyLabel={tg.familyLabel ?? 'font family'}
|
|
134
|
+
sizeVariable={tg.sizeVariable}
|
|
135
|
+
sizeLabel={tg.sizeLabel ?? 'font size'}
|
|
136
|
+
weightVariable={tg.weightVariable}
|
|
137
|
+
weightLabel={tg.weightLabel ?? 'font weight'}
|
|
138
|
+
lineHeightVariable={tg.lineHeightVariable}
|
|
139
|
+
lineHeightLabel={tg.lineHeightLabel ?? 'line height'}
|
|
140
|
+
letterSpacingVariable={tg.letterSpacingVariable}
|
|
141
|
+
letterSpacingLabel={tg.letterSpacingLabel ?? 'letter spacing'}
|
|
142
|
+
outlineWidthVariable={tg.outlineWidthVariable}
|
|
143
|
+
outlineWidthLabel={tg.outlineWidthLabel ?? 'outline thickness'}
|
|
144
|
+
outlineColorVariable={tg.outlineColorVariable}
|
|
145
|
+
outlineColorLabel={tg.outlineColorLabel ?? 'outline color'}
|
|
146
|
+
{component}
|
|
147
|
+
{onchange}
|
|
148
|
+
/>
|
|
149
|
+
{/each}
|
|
150
|
+
</div>
|
|
151
|
+
{/if}
|
|
152
|
+
{#if section.tokens.length > 0}
|
|
153
|
+
<TokenLayout
|
|
154
|
+
title=""
|
|
155
|
+
tokens={section.tokens}
|
|
156
|
+
{component}
|
|
157
|
+
{linkedOrder}
|
|
158
|
+
{columns}
|
|
159
|
+
{onchange}
|
|
160
|
+
/>
|
|
161
|
+
{/if}
|
|
162
|
+
</section>
|
|
163
|
+
{/each}
|
|
164
|
+
</div>
|
|
165
|
+
{:else}
|
|
166
|
+
<div class="state-controls" class:two-col={hasTypeGroups}>
|
|
167
|
+
{#if hasTypeGroups}
|
|
168
|
+
<div class="state-type-groups">
|
|
169
|
+
{#each typeGroups as tg}
|
|
170
|
+
<TypeEditor
|
|
171
|
+
legend={tg.legend ?? 'type'}
|
|
172
|
+
colorVariable={tg.colorVariable}
|
|
173
|
+
colorLabel={tg.colorLabel ?? 'text color'}
|
|
174
|
+
familyVariable={tg.familyVariable}
|
|
175
|
+
familyLabel={tg.familyLabel ?? 'font family'}
|
|
176
|
+
sizeVariable={tg.sizeVariable}
|
|
177
|
+
sizeLabel={tg.sizeLabel ?? 'font size'}
|
|
178
|
+
weightVariable={tg.weightVariable}
|
|
179
|
+
weightLabel={tg.weightLabel ?? 'font weight'}
|
|
180
|
+
lineHeightVariable={tg.lineHeightVariable}
|
|
181
|
+
lineHeightLabel={tg.lineHeightLabel ?? 'line height'}
|
|
182
|
+
letterSpacingVariable={tg.letterSpacingVariable}
|
|
183
|
+
letterSpacingLabel={tg.letterSpacingLabel ?? 'letter spacing'}
|
|
184
|
+
outlineWidthVariable={tg.outlineWidthVariable}
|
|
185
|
+
outlineWidthLabel={tg.outlineWidthLabel ?? 'outline thickness'}
|
|
186
|
+
outlineColorVariable={tg.outlineColorVariable}
|
|
187
|
+
outlineColorLabel={tg.outlineColorLabel ?? 'outline color'}
|
|
188
|
+
{component}
|
|
189
|
+
{onchange}
|
|
190
|
+
/>
|
|
191
|
+
{/each}
|
|
192
|
+
</div>
|
|
193
|
+
{/if}
|
|
194
|
+
<TokenLayout
|
|
195
|
+
title=""
|
|
196
|
+
{tokens}
|
|
197
|
+
{component}
|
|
198
|
+
{linkedOrder}
|
|
199
|
+
{columns}
|
|
200
|
+
{onchange}
|
|
201
|
+
/>
|
|
202
|
+
</div>
|
|
203
|
+
{/if}
|
|
204
|
+
|
|
205
|
+
<style>
|
|
206
|
+
.state-controls {
|
|
207
|
+
display: grid;
|
|
208
|
+
grid-template-columns: 1fr;
|
|
209
|
+
gap: var(--ui-space-12);
|
|
210
|
+
align-items: start;
|
|
211
|
+
margin-top: var(--ui-space-4);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.state-controls.two-col {
|
|
215
|
+
display: flex;
|
|
216
|
+
flex-wrap: wrap;
|
|
217
|
+
gap: var(--ui-space-16) var(--ui-space-16);
|
|
218
|
+
align-items: flex-start;
|
|
219
|
+
justify-content: flex-start;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.state-type-groups {
|
|
223
|
+
display: flex;
|
|
224
|
+
flex-direction: row;
|
|
225
|
+
flex-wrap: wrap;
|
|
226
|
+
gap: var(--ui-space-16);
|
|
227
|
+
align-items: flex-start;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* Inside a state's two-col layout the fieldset frame is redundant with the
|
|
231
|
+
surrounding state card. Flatten the border/padding but keep the legend so
|
|
232
|
+
each block ("title", "body text", …) is identifiable. */
|
|
233
|
+
.state-controls.two-col .state-type-groups :global(.fieldset-wrapper) {
|
|
234
|
+
border: none;
|
|
235
|
+
padding: 0;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.state-controls.two-col .state-type-groups :global(.fieldset-wrapper.active) {
|
|
239
|
+
outline: none;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.state-controls.two-col .state-type-groups :global(.fieldset-legend) {
|
|
243
|
+
padding: 0 var(--ui-space-4) var(--ui-space-4);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/* The general-properties column has no legend of its own; pad it down by
|
|
247
|
+
one legend-line so its first row aligns with the first row of the
|
|
248
|
+
adjacent type-group. */
|
|
249
|
+
.state-controls.two-col > :global(.token-group) {
|
|
250
|
+
padding-top: calc(var(--ui-font-size-xs) + var(--ui-space-4));
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* Element-grouped mode: subsections fan out across available width, each
|
|
254
|
+
labeled by the element it targets (e.g. Frame / Header / Body). Three
|
|
255
|
+
columns at typical editor widths, dropping to two then one as the panel
|
|
256
|
+
narrows — the auto-fit + minmax does the responsive work without media
|
|
257
|
+
queries. `align-items: start` keeps columns of different heights aligned
|
|
258
|
+
to their top edge instead of stretching the shorter ones.
|
|
259
|
+
Within a section the two-col split (typography fieldsets + property grid)
|
|
260
|
+
still applies when the section has both. */
|
|
261
|
+
.state-controls.element-grouped {
|
|
262
|
+
display: grid;
|
|
263
|
+
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
|
|
264
|
+
gap: var(--ui-space-20) var(--ui-space-32);
|
|
265
|
+
align-items: start;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/* Each element section stacks typography fieldset(s) above the property
|
|
269
|
+
grid in a single column, so both share the section's leftmost edge and
|
|
270
|
+
line up with neighbouring sections that have no typography (e.g. Frame). */
|
|
271
|
+
.element-section {
|
|
272
|
+
display: flex;
|
|
273
|
+
flex-direction: column;
|
|
274
|
+
gap: var(--ui-space-8);
|
|
275
|
+
align-items: stretch;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.element-section .state-type-groups {
|
|
279
|
+
display: flex;
|
|
280
|
+
flex-direction: row;
|
|
281
|
+
flex-wrap: wrap;
|
|
282
|
+
gap: var(--ui-space-16);
|
|
283
|
+
align-items: flex-start;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* Type-fieldsets sit chrome-less against the element-section's own
|
|
287
|
+
boundary — the section heading already frames the block, and an extra
|
|
288
|
+
fieldset border would double-line the visual. */
|
|
289
|
+
.element-section .state-type-groups :global(.fieldset-wrapper) {
|
|
290
|
+
border: none;
|
|
291
|
+
padding: 0;
|
|
292
|
+
}
|
|
293
|
+
.element-section .state-type-groups :global(.fieldset-wrapper.active) {
|
|
294
|
+
outline: none;
|
|
295
|
+
}
|
|
296
|
+
.element-section .state-type-groups :global(.fieldset-legend) {
|
|
297
|
+
padding: 0 var(--ui-space-4) var(--ui-space-4);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* TypeEditor's `.type-grid` and TokenLayout's `.token-grid` are independent
|
|
301
|
+
grids stacked inside the same element-section. Each sizes its label
|
|
302
|
+
column from its own `max-content`, so when one grid has long labels
|
|
303
|
+
("letter spacing") and the other has short ones ("padding") their
|
|
304
|
+
dropdowns land at different x positions. Both grids honour
|
|
305
|
+
`--editor-label-col` for their first column track; setting it here pins
|
|
306
|
+
the label column to a shared minimum so short labels pad out and the
|
|
307
|
+
dropdowns line up across the section. The `max-content` upper bound
|
|
308
|
+
still lets exceptionally long labels grow.
|
|
309
|
+
Cascades into the inner grids; @container narrow-width overrides in
|
|
310
|
+
TokenLayout (which redefine `grid-template-columns` wholesale) still
|
|
311
|
+
win when the panel is too tight to honour the wider track. */
|
|
312
|
+
.element-section {
|
|
313
|
+
--editor-label-col: minmax(7.5rem, max-content);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.element-heading-row {
|
|
317
|
+
display: flex;
|
|
318
|
+
align-items: center;
|
|
319
|
+
gap: var(--ui-space-12);
|
|
320
|
+
padding-bottom: var(--ui-space-4);
|
|
321
|
+
border-bottom: 1px solid var(--ui-border-low);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.element-heading {
|
|
325
|
+
margin: 0;
|
|
326
|
+
font-size: var(--ui-font-size-sm);
|
|
327
|
+
font-weight: var(--ui-font-weight-medium);
|
|
328
|
+
color: var(--ui-text-tertiary);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/* Show toggle next to the section heading — drives preview visibility for
|
|
332
|
+
the element. Property rows below stay visible so users can still tune the
|
|
333
|
+
hidden element's tokens. */
|
|
334
|
+
.element-show-toggle {
|
|
335
|
+
display: inline-flex;
|
|
336
|
+
align-items: center;
|
|
337
|
+
gap: var(--ui-space-6);
|
|
338
|
+
font-size: var(--ui-font-size-sm);
|
|
339
|
+
color: var(--ui-text-secondary);
|
|
340
|
+
cursor: pointer;
|
|
341
|
+
user-select: none;
|
|
342
|
+
}
|
|
343
|
+
.element-show-toggle:hover { color: var(--ui-text-primary); }
|
|
344
|
+
.element-show-toggle input { margin: 0; cursor: pointer; }
|
|
345
|
+
</style>
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
getComponentPropertySiblings,
|
|
14
14
|
setComponentAliasLinked,
|
|
15
15
|
clearComponentAliasLinked,
|
|
16
|
-
} from '../../
|
|
16
|
+
} from '../../core/store/editorStore';
|
|
17
17
|
import { getEditorContext } from './editorContext';
|
|
18
18
|
import type { Token } from './types';
|
|
19
19
|
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
{ kind: 'shadow', matches: (v) => v.endsWith('-shadow') || v.startsWith('--shadow-') },
|
|
93
93
|
{ kind: 'padding', matches: (v) => v.endsWith('-padding') || v.endsWith('-margin') },
|
|
94
94
|
{ kind: 'gap', matches: (v) => v.endsWith('-gap') },
|
|
95
|
-
{ kind: 'border-width', matches: (v) => v.endsWith('-border-width') || v.startsWith('--border-width-') },
|
|
95
|
+
{ kind: 'border-width', matches: (v) => v.endsWith('-border-width') || v.endsWith('-accent-width') || v.endsWith('-hairline-thickness') || v.startsWith('--border-width-') },
|
|
96
96
|
{ kind: 'border', matches: (v) => v.endsWith('-border') || v.startsWith('--border-') },
|
|
97
97
|
{ kind: 'surface', matches: (v) => v.endsWith('-surface') || v.startsWith('--surface-') },
|
|
98
98
|
];
|
|
@@ -139,9 +139,11 @@
|
|
|
139
139
|
return sides.some((s) => !!document.documentElement.style.getPropertyValue(`${varName}-${s}`).trim());
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
function categorize(
|
|
143
|
-
const k = rawKind(
|
|
144
|
-
if (k === 'padding' && paddingIsSplit(
|
|
142
|
+
function categorize(token: Token, comp: string | undefined, state: typeof $editorState): Kind {
|
|
143
|
+
const k = rawKind(token.variable);
|
|
144
|
+
if (k === 'padding' && token.splittable !== false && paddingIsSplit(token.variable, comp, state)) {
|
|
145
|
+
return 'padding-split';
|
|
146
|
+
}
|
|
145
147
|
return k;
|
|
146
148
|
}
|
|
147
149
|
|
|
@@ -170,7 +172,7 @@
|
|
|
170
172
|
'divider-height': { component: UIVariantSelector, extra: () => ({ ...DIVIDER_HEIGHT }) },
|
|
171
173
|
'dot-size': { component: UIVariantSelector, extra: () => ({ ...DOT_SIZE }) },
|
|
172
174
|
'radius': { component: UIVariantSelector, extra: () => ({ ...RADIUS }) },
|
|
173
|
-
'padding': { component: UIPaddingSelector, extra: () => ({ mode: 'single' }) },
|
|
175
|
+
'padding': { component: UIPaddingSelector, extra: (t) => ({ mode: 'single', splittable: t.splittable !== false }) },
|
|
174
176
|
/* padding-split is NOT standalone: TokenLayout renders the .token-label
|
|
175
177
|
(e.g. "padding") in col 1 and the wrapper provides the [label][trigger][value]
|
|
176
178
|
subgrid. UIPaddingSelector's sides template fills cols 2-3 of row 1 with
|
|
@@ -217,7 +219,7 @@
|
|
|
217
219
|
})();
|
|
218
220
|
|
|
219
221
|
function buildEntries(list: Token[], order: Map<string, number> | undefined, linked: Set<Kind>, comp: string | undefined, state: typeof $editorState, multiCol: boolean): Entry[] {
|
|
220
|
-
const indexed = list.map((token, i) => ({ e: { kind: categorize(token
|
|
222
|
+
const indexed = list.map((token, i) => ({ e: { kind: categorize(token, comp, state), token }, i }));
|
|
221
223
|
const rank = multiCol ? multiColRank : orderRank;
|
|
222
224
|
indexed.sort((a, b) => {
|
|
223
225
|
if (!multiCol) {
|
|
@@ -385,7 +387,10 @@
|
|
|
385
387
|
--token-selector-w: 8rem;
|
|
386
388
|
--columns: 1;
|
|
387
389
|
display: grid;
|
|
388
|
-
|
|
390
|
+
/* Label column tracks `--editor-label-col` when an ancestor sets one
|
|
391
|
+
(e.g. StateBlock's `.element-section`), so this grid lines up with a
|
|
392
|
+
sibling `.type-grid` whose `max-content` would otherwise differ. */
|
|
393
|
+
grid-template-columns: repeat(var(--columns), var(--editor-label-col, max-content) var(--token-selector-w) 1fr);
|
|
389
394
|
column-gap: var(--ui-space-10);
|
|
390
395
|
row-gap: var(--ui-space-6);
|
|
391
396
|
align-items: center;
|
|
@@ -412,13 +417,13 @@
|
|
|
412
417
|
padding-left: var(--ui-space-20);
|
|
413
418
|
}
|
|
414
419
|
|
|
415
|
-
@container (max-width: 480px) {
|
|
420
|
+
@container variant-group (max-width: 480px) {
|
|
416
421
|
.token-grid { --token-selector-w: 6rem; }
|
|
417
422
|
}
|
|
418
423
|
|
|
419
424
|
/* Narrow multi-col: shrink selector + inter-set gap further before giving
|
|
420
425
|
up the second column. Targets the overlay's typical docked width range. */
|
|
421
|
-
@container (max-width: 640px) {
|
|
426
|
+
@container variant-group (max-width: 640px) {
|
|
422
427
|
.token-grid.multi-col {
|
|
423
428
|
--token-selector-w: 6rem;
|
|
424
429
|
column-gap: var(--ui-space-6);
|
|
@@ -434,7 +439,7 @@
|
|
|
434
439
|
`1fr` so the lone column fills the panel like single-col mode, and the
|
|
435
440
|
inter-set padding is suppressed so wrapped "set 2" rows don't sit
|
|
436
441
|
indented. */
|
|
437
|
-
@container (max-width: 520px) {
|
|
442
|
+
@container variant-group (max-width: 520px) {
|
|
438
443
|
.token-grid.multi-col {
|
|
439
444
|
--columns: 1;
|
|
440
445
|
grid-template-columns: max-content var(--token-selector-w) 1fr;
|
|
@@ -447,7 +452,7 @@
|
|
|
447
452
|
}
|
|
448
453
|
}
|
|
449
454
|
|
|
450
|
-
@container (max-width: 380px) {
|
|
455
|
+
@container variant-group (max-width: 380px) {
|
|
451
456
|
.token-grid {
|
|
452
457
|
grid-template-columns: max-content 1fr;
|
|
453
458
|
column-gap: var(--ui-space-6);
|