@motion-proto/live-tokens 0.6.2 → 0.7.1
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 +147 -136
- package/dist-plugin/index.d.cts +1 -1
- package/dist-plugin/index.d.ts +1 -1
- package/dist-plugin/index.js +145 -135
- package/package.json +25 -40
- 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 +3 -3
- 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 +64 -37
- package/src/{component-editor → editor/component-editor}/ProgressBarEditor.svelte +5 -4
- package/src/{component-editor → editor/component-editor}/RadioButtonEditor.svelte +3 -3
- package/src/{component-editor → editor/component-editor}/SectionDividerEditor.svelte +57 -84
- package/src/{component-editor → editor/component-editor}/SegmentedControlEditor.svelte +2 -2
- package/src/{component-editor → editor/component-editor}/StandardButtonsEditor.svelte +16 -20
- 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/{component-editor → editor/component-editor}/registry.ts +28 -18
- package/src/{component-editor → editor/component-editor}/scaffolding/AngleDial.svelte +2 -2
- package/src/{component-editor → editor/component-editor}/scaffolding/ComponentEditorBase.svelte +3 -51
- package/src/{component-editor → editor/component-editor}/scaffolding/ComponentFileManager.svelte +144 -416
- 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/DividerEditor.svelte +1 -1
- package/src/{component-editor → editor/component-editor}/scaffolding/FieldsetWrapper.svelte +1 -1
- package/src/{component-editor → editor/component-editor}/scaffolding/GradientCard.svelte +6 -6
- package/src/{component-editor → editor/component-editor}/scaffolding/LinkageChart.svelte +6 -6
- package/src/{component-editor → editor/component-editor}/scaffolding/LinkedBlock.svelte +6 -11
- package/src/editor/component-editor/scaffolding/NonStylableConfig.svelte +38 -0
- package/src/{component-editor → editor/component-editor}/scaffolding/SaveAsDialog.svelte +66 -12
- package/src/editor/component-editor/scaffolding/ShadowBackdrop.svelte +72 -0
- package/src/editor/component-editor/scaffolding/ShadowBackdropControls.svelte +132 -0
- package/src/editor/component-editor/scaffolding/StateBlock.svelte +257 -0
- package/src/{component-editor → editor/component-editor}/scaffolding/TokenLayout.svelte +9 -7
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +644 -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 +14 -0
- package/src/{lib → editor/core/components}/componentConfigService.ts +2 -2
- package/src/{lib → editor/core/components}/componentPersist.ts +5 -5
- 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 +116 -0
- package/src/{lib → editor/core/palettes}/paletteDerivation.ts +2 -2
- package/src/{lib → editor/core/palettes}/tokenRegistry.ts +5 -5
- 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 +17 -17
- package/src/{lib → editor/core/store}/editorTypes.ts +1 -1
- package/src/{lib → editor/core/themes}/slices/columns.ts +2 -2
- package/src/{lib → editor/core/themes}/slices/components.ts +2 -2
- package/src/{lib → editor/core/themes}/slices/fonts.ts +1 -1
- package/src/{lib → editor/core/themes}/slices/gradients.ts +2 -2
- 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 +6 -6
- package/src/{lib → editor/core/themes}/themeService.ts +6 -6
- package/src/{lib → editor/core/themes}/themeTypes.ts +11 -7
- package/src/editor/index.ts +69 -0
- package/src/{lib → editor/overlay}/LiveEditorOverlay.svelte +79 -125
- 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 +41 -21
- package/src/{styles → editor/styles}/ui-form-controls.css +8 -8
- package/src/{ui → editor/ui}/BezierCurveEditor.svelte +8 -8
- package/src/{ui → editor/ui}/ColorEditPanel.svelte +13 -13
- package/src/{ui → editor/ui}/EditorViewSwitcher.svelte +8 -6
- package/src/editor/ui/FileLoadList.svelte +350 -0
- package/src/editor/ui/FilePill.svelte +80 -0
- package/src/{ui → editor/ui}/FontStackEditor.svelte +7 -7
- package/src/{ui → editor/ui}/GradientEditor.svelte +11 -11
- package/src/{ui → editor/ui}/GradientStopPicker.svelte +1 -1
- package/src/editor/ui/ManifestFileManager.svelte +371 -0
- package/src/{ui → editor/ui}/PaletteEditor.svelte +132 -598
- package/src/{ui → editor/ui}/ProjectFontsSection.svelte +102 -144
- package/src/{ui → editor/ui}/SurfacesTab.svelte +3 -3
- package/src/{ui → editor/ui}/TextTab.svelte +3 -3
- package/src/{ui → editor/ui}/ThemeFileManager.svelte +286 -519
- package/src/{ui → editor/ui}/UICopyPopover.svelte +4 -4
- package/src/{ui → editor/ui}/UIFontFamilySelector.svelte +6 -6
- package/src/{ui → editor/ui}/UIFontSizeSelector.svelte +1 -1
- package/src/editor/ui/UIInfoPopover.svelte +244 -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 +26 -26
- package/src/editor/ui/UIPillButton.svelte +138 -0
- package/src/{ui → editor/ui}/UIRadio.svelte +2 -2
- package/src/{ui → editor/ui}/UIRelinkConfirmPopover.svelte +4 -4
- package/src/editor/ui/UISquareButton.svelte +172 -0
- package/src/{ui → editor/ui}/UITokenSelector.svelte +10 -10
- package/src/{ui → editor/ui}/UIVariantSelector.svelte +1 -1
- package/src/{ui → editor/ui}/VariablesTab.svelte +31 -8
- package/src/{ui → editor/ui}/palette/GradientStopEditor.svelte +13 -13
- package/src/{ui → editor/ui}/palette/OverridesPanel.svelte +13 -13
- package/src/{ui → editor/ui}/palette/PaletteBase.svelte +8 -5
- 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 -17
- package/src/{ui → editor/ui}/sections/GradientsSection.svelte +7 -7
- package/src/{ui → editor/ui}/sections/OverlaysSection.svelte +17 -17
- package/src/{ui → editor/ui}/sections/ShadowsSection.svelte +22 -22
- package/src/{ui → editor/ui}/sections/TokenScaleTable.svelte +3 -3
- package/src/{components → system/components}/Badge.svelte +0 -36
- package/src/{components → system/components}/Card.svelte +8 -62
- package/src/{components → system/components}/CornerBadge.svelte +8 -24
- package/src/{components → system/components}/Dialog.svelte +1 -1
- package/src/system/components/FloatingTokenTags.css +256 -0
- package/src/system/components/FloatingTokenTags.svelte +592 -0
- package/src/{components → system/components}/InlineEditActions.svelte +6 -4
- package/src/system/components/MenuSelect.svelte +229 -0
- package/src/{components → system/components}/ProgressBar.svelte +29 -11
- 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/{styles → system/styles}/fonts.css +6 -3
- package/src/{styles → system/styles}/tokens.css +149 -29
- package/src/component-editor/ImageEditor.svelte +0 -74
- 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/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/ui/PresetFileManager.svelte +0 -1116
- package/src/ui/UnsavedComponentsDialog.svelte +0 -315
- /package/src/{styles → app}/site.css +0 -0
- /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/TypeEditor.svelte +0 -0
- /package/src/{component-editor → editor/component-editor}/scaffolding/buildTypeGroupTokens.ts +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/components}/componentConfigKeys.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}/migrations/index.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}/ColumnsOverlay.svelte +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}/Button.svelte +0 -0
- /package/src/{components → system/components}/Callout.svelte +0 -0
- /package/src/{components → system/components}/CollapsibleSection.svelte +0 -0
- /package/src/{components → system/components}/Image.svelte +0 -0
- /package/src/{components → system/components}/Notification.svelte +0 -0
- /package/src/{components → system/components}/RadioButton.svelte +0 -0
- /package/src/{components → system/components}/SectionDivider.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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { run } from 'svelte/legacy';
|
|
3
3
|
|
|
4
|
-
import { sanitizeFileName } from '../../
|
|
4
|
+
import { sanitizeFileName } from '../../core/themes/themeService';
|
|
5
5
|
import UIDialog from '../../ui/UIDialog.svelte';
|
|
6
6
|
|
|
7
7
|
interface Props {
|
|
@@ -11,16 +11,35 @@
|
|
|
11
11
|
currentDisplayName?: string;
|
|
12
12
|
/** Existing files used by the increment helper to find the next available `_NN` suffix.
|
|
13
13
|
* Only `fileName` is read, so this accepts any shape with that field
|
|
14
|
-
* (ComponentConfigMeta,
|
|
14
|
+
* (ComponentConfigMeta, ManifestMeta, …). */
|
|
15
15
|
files?: { fileName: string }[];
|
|
16
16
|
/** Dialog title — defaults to "Save As". Overridable so callers can use
|
|
17
|
-
* context-specific framing (e.g. "Save
|
|
17
|
+
* context-specific framing (e.g. "Save Manifest As"). */
|
|
18
18
|
title?: string;
|
|
19
19
|
/** Placeholder shown in the empty input. */
|
|
20
20
|
placeholder?: string;
|
|
21
21
|
/** Error message shown when the user types the reserved "default" name.
|
|
22
|
-
* Default copy references components;
|
|
22
|
+
* Default copy references components; manifests should override. */
|
|
23
23
|
reservedNameMessage?: string;
|
|
24
|
+
/** Optional one-line explanation rendered above the name input. Use when
|
|
25
|
+
* the dialog opens automatically (e.g. as a recovery prompt) so the user
|
|
26
|
+
* understands what's about to be saved and why the prompt appeared. */
|
|
27
|
+
description?: string;
|
|
28
|
+
/** Seed value to use when branching off the protected `default` file.
|
|
29
|
+
* Without this the dialog falls back to incrementing the default's display
|
|
30
|
+
* name (e.g. "Default Theme_01"), which reads as a derivative of the
|
|
31
|
+
* reserved name. Pass a fresh, neutral suggestion (e.g. "My Theme") so
|
|
32
|
+
* the user's first save isn't named after the slot they can't overwrite. */
|
|
33
|
+
branchFromDefaultName?: string;
|
|
34
|
+
/** Active file's basename. Authoritative source for "are we branching from
|
|
35
|
+
* the protected default?" — the displayName-based check below fails when
|
|
36
|
+
* the default's display name doesn't sanitize to "default" (e.g. themes
|
|
37
|
+
* whose default is named "Default Theme" → "default-theme"). */
|
|
38
|
+
currentFileName?: string;
|
|
39
|
+
/** Display names that already belong to protected/system files. Blocked
|
|
40
|
+
* case-insensitively so a user can't shadow the default by reusing its
|
|
41
|
+
* display label even when the sanitized filename would differ. */
|
|
42
|
+
reservedDisplayNames?: string[];
|
|
24
43
|
onsave?: (payload: { displayName: string; fileName: string }) => void;
|
|
25
44
|
}
|
|
26
45
|
|
|
@@ -31,6 +50,10 @@
|
|
|
31
50
|
title = 'Save As',
|
|
32
51
|
placeholder = 'Config name…',
|
|
33
52
|
reservedNameMessage = 'The name "default" is reserved for the core component definition.',
|
|
53
|
+
description = '',
|
|
54
|
+
branchFromDefaultName = '',
|
|
55
|
+
currentFileName = '',
|
|
56
|
+
reservedDisplayNames = [],
|
|
34
57
|
onsave,
|
|
35
58
|
}: Props = $props();
|
|
36
59
|
|
|
@@ -79,10 +102,27 @@
|
|
|
79
102
|
// ends up focused-and-selected, not the button.
|
|
80
103
|
run(() => {
|
|
81
104
|
if (show) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
105
|
+
const trimmedCurrent = currentDisplayName.trim().toLowerCase();
|
|
106
|
+
const isReservedDisplay = reservedDisplayNames.some(
|
|
107
|
+
(n) => n.trim().toLowerCase() === trimmedCurrent,
|
|
108
|
+
);
|
|
109
|
+
// Three paths funnel into the branch suggestion:
|
|
110
|
+
// 1. Active is the literal `default` file.
|
|
111
|
+
// 2. Current displayName itself sanitizes to "default".
|
|
112
|
+
// 3. Current displayName collides with a reserved label (e.g. a stray
|
|
113
|
+
// user file already named "Default Theme") — re-seeding with their
|
|
114
|
+
// old name would trip the validator on submit.
|
|
115
|
+
const isFromDefault =
|
|
116
|
+
currentFileName === 'default' ||
|
|
117
|
+
sanitizeFileName(currentDisplayName) === 'default' ||
|
|
118
|
+
isReservedDisplay;
|
|
119
|
+
if (isFromDefault) {
|
|
120
|
+
saveAsName = branchFromDefaultName
|
|
121
|
+
? branchFromDefaultName
|
|
122
|
+
: nextIncrementName(currentDisplayName).displayName;
|
|
123
|
+
} else {
|
|
124
|
+
saveAsName = currentDisplayName;
|
|
125
|
+
}
|
|
86
126
|
setTimeout(() => saveAsInput?.select(), 0);
|
|
87
127
|
}
|
|
88
128
|
});
|
|
@@ -92,6 +132,10 @@
|
|
|
92
132
|
if (sanitizeFileName(trimmed) === 'default') {
|
|
93
133
|
return reservedNameMessage;
|
|
94
134
|
}
|
|
135
|
+
const lowered = trimmed.toLowerCase();
|
|
136
|
+
if (reservedDisplayNames.some((n) => n.trim().toLowerCase() === lowered)) {
|
|
137
|
+
return reservedNameMessage;
|
|
138
|
+
}
|
|
95
139
|
return '';
|
|
96
140
|
})());
|
|
97
141
|
</script>
|
|
@@ -106,6 +150,9 @@
|
|
|
106
150
|
width="360px"
|
|
107
151
|
>
|
|
108
152
|
<div class="save-as-dialog">
|
|
153
|
+
{#if description}
|
|
154
|
+
<p class="save-as-description">{description}</p>
|
|
155
|
+
{/if}
|
|
109
156
|
<div class="save-as-row">
|
|
110
157
|
<input
|
|
111
158
|
class="save-as-input"
|
|
@@ -149,7 +196,7 @@
|
|
|
149
196
|
min-width: 0;
|
|
150
197
|
padding: var(--ui-space-8) var(--ui-space-10);
|
|
151
198
|
background: var(--ui-surface-lowest);
|
|
152
|
-
border: 1px solid var(--ui-border-
|
|
199
|
+
border: 1px solid var(--ui-border-low);
|
|
153
200
|
border-radius: var(--ui-radius-md);
|
|
154
201
|
color: var(--ui-text-primary);
|
|
155
202
|
font-size: var(--ui-font-size-md);
|
|
@@ -163,7 +210,7 @@
|
|
|
163
210
|
width: 2.25rem;
|
|
164
211
|
padding: 0;
|
|
165
212
|
background: var(--ui-surface-low);
|
|
166
|
-
border: 1px solid var(--ui-border-
|
|
213
|
+
border: 1px solid var(--ui-border-low);
|
|
167
214
|
border-radius: var(--ui-radius-md);
|
|
168
215
|
color: var(--ui-text-secondary);
|
|
169
216
|
font-size: var(--ui-font-size-md);
|
|
@@ -173,12 +220,12 @@
|
|
|
173
220
|
|
|
174
221
|
.save-as-increment:hover {
|
|
175
222
|
background: var(--ui-surface);
|
|
176
|
-
border-color: var(--ui-border
|
|
223
|
+
border-color: var(--ui-border);
|
|
177
224
|
color: var(--ui-text-primary);
|
|
178
225
|
}
|
|
179
226
|
|
|
180
227
|
.save-as-input:focus {
|
|
181
|
-
border-color: var(--ui-border-
|
|
228
|
+
border-color: var(--ui-border-high);
|
|
182
229
|
}
|
|
183
230
|
|
|
184
231
|
.save-as-input.invalid,
|
|
@@ -195,4 +242,11 @@
|
|
|
195
242
|
font-size: var(--ui-font-size-xs);
|
|
196
243
|
color: var(--ui-highlight);
|
|
197
244
|
}
|
|
245
|
+
|
|
246
|
+
.save-as-description {
|
|
247
|
+
margin: 0;
|
|
248
|
+
font-size: var(--ui-font-size-xs);
|
|
249
|
+
line-height: 1.5;
|
|
250
|
+
color: var(--ui-text-secondary);
|
|
251
|
+
}
|
|
198
252
|
</style>
|
|
@@ -0,0 +1,72 @@
|
|
|
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};">
|
|
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
|
+
}
|
|
62
|
+
|
|
63
|
+
.shadow-backdrop-content {
|
|
64
|
+
display: grid;
|
|
65
|
+
place-items: center;
|
|
66
|
+
min-width: 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.shadow-backdrop-controls {
|
|
70
|
+
padding: var(--ui-space-8);
|
|
71
|
+
}
|
|
72
|
+
</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,257 @@
|
|
|
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 TokenLayout from './TokenLayout.svelte';
|
|
12
|
+
import TypeEditor from './TypeEditor.svelte';
|
|
13
|
+
import type { Token, TypeGroupConfig } from './types';
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
/** Tokens for this state, fed to `<TokenLayout>`. */
|
|
22
|
+
tokens: Token[];
|
|
23
|
+
/** Type groups for this state; rendered as a row of `<TypeEditor>` blocks. */
|
|
24
|
+
typeGroups?: TypeGroupConfig[];
|
|
25
|
+
/** Forwarded to TypeEditor and TokenLayout so writes persist through the editor store. */
|
|
26
|
+
component?: string | undefined;
|
|
27
|
+
/** Per-variable rank passed through to TokenLayout for linked-block alignment. */
|
|
28
|
+
linkedOrder?: Map<string, number> | undefined;
|
|
29
|
+
/** Render the token grid with N visual columns. >1 spreads a long property
|
|
30
|
+
list horizontally; only meaningful for state-blocks without typeGroups
|
|
31
|
+
(the two-col flex layout already partitions screen real estate when
|
|
32
|
+
typeGroups are present). */
|
|
33
|
+
columns?: number;
|
|
34
|
+
onchange?: () => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let {
|
|
38
|
+
tokens,
|
|
39
|
+
typeGroups = [],
|
|
40
|
+
component = undefined,
|
|
41
|
+
linkedOrder = undefined,
|
|
42
|
+
columns = 1,
|
|
43
|
+
onchange,
|
|
44
|
+
}: Props = $props();
|
|
45
|
+
|
|
46
|
+
let hasTypeGroups = $derived(typeGroups.length > 0);
|
|
47
|
+
|
|
48
|
+
/** Element-grouped mode: when 2+ distinct element tags appear across tokens
|
|
49
|
+
and type-groups, partition the panel into labeled subsections (e.g.
|
|
50
|
+
"Frame", "Header", "Body"). Element order = first-encounter across the
|
|
51
|
+
combined tokens + type-groups list. */
|
|
52
|
+
let elementSections = $derived.by(() => {
|
|
53
|
+
const order: string[] = [];
|
|
54
|
+
const seen = new Set<string>();
|
|
55
|
+
for (const t of tokens) {
|
|
56
|
+
if (t.element && !seen.has(t.element)) {
|
|
57
|
+
seen.add(t.element);
|
|
58
|
+
order.push(t.element);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (const tg of typeGroups) {
|
|
62
|
+
if (tg.element && !seen.has(tg.element)) {
|
|
63
|
+
seen.add(tg.element);
|
|
64
|
+
order.push(tg.element);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (order.length < 2) return null;
|
|
68
|
+
return order.map((el) => ({
|
|
69
|
+
element: el,
|
|
70
|
+
tokens: tokens.filter((t) => t.element === el),
|
|
71
|
+
typeGroups: typeGroups.filter((tg) => tg.element === el),
|
|
72
|
+
}));
|
|
73
|
+
});
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
{#if elementSections}
|
|
77
|
+
<div class="state-controls element-grouped">
|
|
78
|
+
{#each elementSections as section}
|
|
79
|
+
<section class="element-section">
|
|
80
|
+
<h4 class="element-heading">{section.element}</h4>
|
|
81
|
+
{#if section.typeGroups.length > 0}
|
|
82
|
+
<div class="state-type-groups">
|
|
83
|
+
{#each section.typeGroups as tg}
|
|
84
|
+
<TypeEditor
|
|
85
|
+
legend={tg.legend ?? 'type'}
|
|
86
|
+
colorVariable={tg.colorVariable}
|
|
87
|
+
colorLabel={tg.colorLabel ?? 'text color'}
|
|
88
|
+
familyVariable={tg.familyVariable}
|
|
89
|
+
familyLabel={tg.familyLabel ?? 'font family'}
|
|
90
|
+
sizeVariable={tg.sizeVariable}
|
|
91
|
+
sizeLabel={tg.sizeLabel ?? 'font size'}
|
|
92
|
+
weightVariable={tg.weightVariable}
|
|
93
|
+
weightLabel={tg.weightLabel ?? 'font weight'}
|
|
94
|
+
lineHeightVariable={tg.lineHeightVariable}
|
|
95
|
+
lineHeightLabel={tg.lineHeightLabel ?? 'line height'}
|
|
96
|
+
outlineWidthVariable={tg.outlineWidthVariable}
|
|
97
|
+
outlineWidthLabel={tg.outlineWidthLabel ?? 'outline thickness'}
|
|
98
|
+
outlineColorVariable={tg.outlineColorVariable}
|
|
99
|
+
outlineColorLabel={tg.outlineColorLabel ?? 'outline color'}
|
|
100
|
+
{component}
|
|
101
|
+
{onchange}
|
|
102
|
+
/>
|
|
103
|
+
{/each}
|
|
104
|
+
</div>
|
|
105
|
+
{/if}
|
|
106
|
+
{#if section.tokens.length > 0}
|
|
107
|
+
<TokenLayout
|
|
108
|
+
title=""
|
|
109
|
+
tokens={section.tokens}
|
|
110
|
+
{component}
|
|
111
|
+
{linkedOrder}
|
|
112
|
+
{columns}
|
|
113
|
+
{onchange}
|
|
114
|
+
/>
|
|
115
|
+
{/if}
|
|
116
|
+
</section>
|
|
117
|
+
{/each}
|
|
118
|
+
</div>
|
|
119
|
+
{:else}
|
|
120
|
+
<div class="state-controls" class:two-col={hasTypeGroups}>
|
|
121
|
+
{#if hasTypeGroups}
|
|
122
|
+
<div class="state-type-groups">
|
|
123
|
+
{#each typeGroups as tg}
|
|
124
|
+
<TypeEditor
|
|
125
|
+
legend={tg.legend ?? 'type'}
|
|
126
|
+
colorVariable={tg.colorVariable}
|
|
127
|
+
colorLabel={tg.colorLabel ?? 'text color'}
|
|
128
|
+
familyVariable={tg.familyVariable}
|
|
129
|
+
familyLabel={tg.familyLabel ?? 'font family'}
|
|
130
|
+
sizeVariable={tg.sizeVariable}
|
|
131
|
+
sizeLabel={tg.sizeLabel ?? 'font size'}
|
|
132
|
+
weightVariable={tg.weightVariable}
|
|
133
|
+
weightLabel={tg.weightLabel ?? 'font weight'}
|
|
134
|
+
lineHeightVariable={tg.lineHeightVariable}
|
|
135
|
+
lineHeightLabel={tg.lineHeightLabel ?? 'line height'}
|
|
136
|
+
outlineWidthVariable={tg.outlineWidthVariable}
|
|
137
|
+
outlineWidthLabel={tg.outlineWidthLabel ?? 'outline thickness'}
|
|
138
|
+
outlineColorVariable={tg.outlineColorVariable}
|
|
139
|
+
outlineColorLabel={tg.outlineColorLabel ?? 'outline color'}
|
|
140
|
+
{component}
|
|
141
|
+
{onchange}
|
|
142
|
+
/>
|
|
143
|
+
{/each}
|
|
144
|
+
</div>
|
|
145
|
+
{/if}
|
|
146
|
+
<TokenLayout
|
|
147
|
+
title=""
|
|
148
|
+
{tokens}
|
|
149
|
+
{component}
|
|
150
|
+
{linkedOrder}
|
|
151
|
+
{columns}
|
|
152
|
+
{onchange}
|
|
153
|
+
/>
|
|
154
|
+
</div>
|
|
155
|
+
{/if}
|
|
156
|
+
|
|
157
|
+
<style>
|
|
158
|
+
.state-controls {
|
|
159
|
+
display: grid;
|
|
160
|
+
grid-template-columns: 1fr;
|
|
161
|
+
gap: var(--ui-space-12);
|
|
162
|
+
align-items: start;
|
|
163
|
+
margin-top: var(--ui-space-4);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.state-controls.two-col {
|
|
167
|
+
display: flex;
|
|
168
|
+
flex-wrap: wrap;
|
|
169
|
+
gap: var(--ui-space-16) var(--ui-space-16);
|
|
170
|
+
align-items: flex-start;
|
|
171
|
+
justify-content: flex-start;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.state-type-groups {
|
|
175
|
+
display: flex;
|
|
176
|
+
flex-direction: row;
|
|
177
|
+
flex-wrap: wrap;
|
|
178
|
+
gap: var(--ui-space-16);
|
|
179
|
+
align-items: flex-start;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* Inside a state's two-col layout the fieldset frame is redundant with the
|
|
183
|
+
surrounding state card. Flatten the border/padding but keep the legend so
|
|
184
|
+
each block ("title", "body text", …) is identifiable. */
|
|
185
|
+
.state-controls.two-col .state-type-groups :global(.fieldset-wrapper) {
|
|
186
|
+
border: none;
|
|
187
|
+
padding: 0;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.state-controls.two-col .state-type-groups :global(.fieldset-wrapper.active) {
|
|
191
|
+
outline: none;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.state-controls.two-col .state-type-groups :global(.fieldset-legend) {
|
|
195
|
+
padding: 0 var(--ui-space-4) var(--ui-space-4);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* The general-properties column has no legend of its own; pad it down by
|
|
199
|
+
one legend-line so its first row aligns with the first row of the
|
|
200
|
+
adjacent type-group. */
|
|
201
|
+
.state-controls.two-col > :global(.token-group) {
|
|
202
|
+
padding-top: calc(var(--ui-font-size-xs) + var(--ui-space-4));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* Element-grouped mode: vertical stack of subsections, each labeled by the
|
|
206
|
+
element it targets (e.g. Frame / Header / Body). Within a section the
|
|
207
|
+
two-col split (typography fieldsets + property grid) still applies when
|
|
208
|
+
the section has both. */
|
|
209
|
+
.state-controls.element-grouped {
|
|
210
|
+
display: flex;
|
|
211
|
+
flex-direction: column;
|
|
212
|
+
gap: var(--ui-space-16);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* Each element section stacks typography fieldset(s) above the property
|
|
216
|
+
grid in a single column, so both share the section's leftmost edge and
|
|
217
|
+
line up with neighbouring sections that have no typography (e.g. Frame). */
|
|
218
|
+
.element-section {
|
|
219
|
+
display: flex;
|
|
220
|
+
flex-direction: column;
|
|
221
|
+
gap: var(--ui-space-8);
|
|
222
|
+
align-items: stretch;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.element-section .state-type-groups {
|
|
226
|
+
display: flex;
|
|
227
|
+
flex-direction: row;
|
|
228
|
+
flex-wrap: wrap;
|
|
229
|
+
gap: var(--ui-space-16);
|
|
230
|
+
align-items: flex-start;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* Type-fieldsets sit chrome-less against the element-section's own
|
|
234
|
+
boundary — the section heading already frames the block, and an extra
|
|
235
|
+
fieldset border would double-line the visual. */
|
|
236
|
+
.element-section .state-type-groups :global(.fieldset-wrapper) {
|
|
237
|
+
border: none;
|
|
238
|
+
padding: 0;
|
|
239
|
+
}
|
|
240
|
+
.element-section .state-type-groups :global(.fieldset-wrapper.active) {
|
|
241
|
+
outline: none;
|
|
242
|
+
}
|
|
243
|
+
.element-section .state-type-groups :global(.fieldset-legend) {
|
|
244
|
+
padding: 0 var(--ui-space-4) var(--ui-space-4);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.element-heading {
|
|
248
|
+
margin: 0;
|
|
249
|
+
font-size: var(--ui-font-size-sm);
|
|
250
|
+
font-weight: var(--ui-font-weight-semibold);
|
|
251
|
+
text-transform: uppercase;
|
|
252
|
+
letter-spacing: 0.04em;
|
|
253
|
+
color: var(--ui-text-tertiary);
|
|
254
|
+
padding-bottom: var(--ui-space-4);
|
|
255
|
+
border-bottom: 1px solid var(--ui-border-low);
|
|
256
|
+
}
|
|
257
|
+
</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.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) {
|