From 7140a797cfa4ddf58da2e4482fd1c820cfd8a834 Mon Sep 17 00:00:00 2001 From: Kiro Agent <244629292+kiro-agent@users.noreply.github.com> Date: Fri, 21 Aug 2026 08:22:07 +0000 Subject: [PATCH 1/2] feat(configurator): guard Inherit reset + add glance previews to control gaps Changes panel / value editor: clicking the Inherit tab when an override exists no longer wipes it in one click. It now arms a confirm banner (Cancel / Reset) and only the explicit Reset discards the override; with nothing overridden it stays a harmless no-op. Applies everywhere the value editor is used (Changes, All-tokens, generic token panels). In-panel previews: the right-hand live preview is optional and does not cover every control, so fill the control groups that had no visual: - Effects: text-shadow legibility swatches over a gradient - Typography: letter-spacing, line-height and tabular/proportional numerals - System (Misc): z-index stacking order, icon-size ladder, object-fit, required field marker (+ safe-area 'no preview' note) - Shape (Borders): divider rule sample, field-shape input sample - Layout: live .sf-cluster, .sf-equal and .sf-reel primitives --- .../src/components/inputs/ValueField.svelte | 48 +++++++++++- .../src/components/panels/BordersPanel.svelte | 20 +++++ .../src/components/panels/EffectsPanel.svelte | 14 ++++ .../src/components/panels/LayoutPanel.svelte | 31 ++++++++ .../src/components/panels/MiscPanel.svelte | 77 +++++++++++++++++++ .../components/panels/TypographyPanel.svelte | 34 ++++++++ 6 files changed, 220 insertions(+), 4 deletions(-) diff --git a/configurator/src/components/inputs/ValueField.svelte b/configurator/src/components/inputs/ValueField.svelte index 7e3d81bc..167cf8e4 100644 --- a/configurator/src/components/inputs/ValueField.svelte +++ b/configurator/src/components/inputs/ValueField.svelte @@ -22,10 +22,17 @@ let draft = $state(""); let editing = $state(false); let cancelling = $state(false); - // Reset a user-selected tab when another surface changes this token. + // Switching back to Inherit throws away the override. The tab sits right next + // to Value/Expression and reads like a harmless view switch, so a stray click + // used to silently wipe an edit. When there's an actual override to lose we + // arm this confirm step instead of resetting immediately. + let confirmingInherit = $state(false); + // Reset a user-selected tab (and any pending confirm) when another surface + // changes this token. $effect(() => { overrideValue; manualMode = null; + confirmingInherit = false; }); // Seed the text field from the live value whenever we're not mid-edit. $effect(() => { @@ -41,8 +48,22 @@ } function setMode(m: ValueMode) { + if (m === "inherit") { + // Nothing overridden → already inheriting, so this is a no-op, not a + // destructive reset; just settle on auto-detect. + if (overrideValue === undefined) { manualMode = null; confirmingInherit = false; return; } + // Otherwise require an explicit confirmation before discarding the value. + confirmingInherit = true; + return; + } + confirmingInherit = false; manualMode = m; - if (m === "inherit") { onReset(); manualMode = null; } + } + + function confirmInherit() { + confirmingInherit = false; + manualMode = null; + onReset(); } const TABS: { id: ValueMode; label: string }[] = [ @@ -56,11 +77,12 @@
{#each TABS as t (t.id)} + {@const active = mode === t.id || (t.id === "inherit" && confirmingInherit)}
+ + {#if confirmingInherit} +
+ + Discard this override and inherit {token.value}? + + + +
+ {/if} + {#if mode === "inherit"}
default: {token.value} diff --git a/configurator/src/components/panels/BordersPanel.svelte b/configurator/src/components/panels/BordersPanel.svelte index d7b3e6ec..9daa63d3 100644 --- a/configurator/src/components/panels/BordersPanel.svelte +++ b/configurator/src/components/panels/BordersPanel.svelte @@ -224,6 +224,14 @@ currentRaw={overrides["--sf-divider-gap"]} onRawSet={(v) => onSet("--sf-divider-gap", v)} /> + + +
+

Content above

+
+

Content below

+
@@ -348,6 +356,18 @@ onRawSet={(v) => onSet(t.token, v)} /> {/each} + + +
+ +
{/if} diff --git a/configurator/src/components/panels/EffectsPanel.svelte b/configurator/src/components/panels/EffectsPanel.svelte index 808b867d..ec55de5c 100644 --- a/configurator/src/components/panels/EffectsPanel.svelte +++ b/configurator/src/components/panels/EffectsPanel.svelte @@ -155,6 +155,20 @@ {/each} + + +
+ {#each TEXT_SHADOW_TOKENS as t (t.token)} +
+ Aa + {t.token.replace("--sf-text-shadow-", "")} +
+ {/each} +
diff --git a/configurator/src/components/panels/LayoutPanel.svelte b/configurator/src/components/panels/LayoutPanel.svelte index 86b5ab91..879eb03e 100644 --- a/configurator/src/components/panels/LayoutPanel.svelte +++ b/configurator/src/components/panels/LayoutPanel.svelte @@ -445,6 +445,18 @@ {/if} {/each} + +
+
+ {#each [1.75, 1, 2.25, 1.25] as h, i (i)} + {i + 1} + {/each} +
+
@@ -492,6 +504,13 @@ onReset={() => onReset("--sf-equal-rule-color")} /> + +
+
+

SLASHED flows this text across as many equal columns as fit the box, divided by the column rule. Lower the min column width to pack in more, narrower columns; raise it for fewer, roomier ones. The rule width, style and colour draw the divider.

+
+
@@ -549,6 +568,18 @@ {/if} + +
+
+ {#each [1, 2, 3, 4, 5, 6] as n (n)} +
{n}
+ {/each} +
+
diff --git a/configurator/src/components/panels/MiscPanel.svelte b/configurator/src/components/panels/MiscPanel.svelte index f03008a2..8d10ec75 100644 --- a/configurator/src/components/panels/MiscPanel.svelte +++ b/configurator/src/components/panels/MiscPanel.svelte @@ -53,6 +53,19 @@ function getSizeValue(t: typeof SIZE_TOKENS[0]): number { return parseNum(overrides[t.token]?.replace("rem",""), t.default); } + + const ICON_STEPS = ["xs", "s", "m", "l", "xl", "2xl"]; + + // A deliberately landscape (2:1) sample with a centered ring and a full-bleed + // border, so object-fit differences are unmistakable: cover crops the sides, + // contain letterboxes, fill distorts the circle, none overflows at native px. + const OBJECT_FIT_IMG = `data:image/svg+xml,${encodeURIComponent( + ``, + )}`; + + // Conceptual layering ladder (top rung = highest z). Static preview of the + // *order*, since the numeric values themselves have no standalone visual. + const Z_LADDER = [...Z_INDEX_STEPS].reverse();
@@ -96,6 +109,24 @@ /> {/each}
+ + +
+
Higher rungs paint above lower ones.
+
+ {#each Z_LADDER as z, i (z.token)} +
+ {z.label} + {parseNum(overrides[z.token], z.def)} +
+ {/each} +
+
@@ -310,6 +341,19 @@ onChange={(v) => onSet("--sf-icon-box-pad", `${v}em`)} onReset={() => onReset("--sf-icon-box-pad")} /> + + +
+ {#each ICON_STEPS as s (s)} +
+ + {s} +
+ {/each} +
@@ -350,6 +394,22 @@ {/if} + + +
+
+ Object-fit sample +
+
+ object-fit: {overrides["--sf-object-fit"] ?? "cover"} +
+
@@ -386,6 +446,9 @@ {/each} +

+ No preview — safe-area insets resolve to the physical device (notch / home indicator) at runtime and are 0 on desktop. +

@@ -408,6 +471,20 @@ {/if} + + +
+ +
diff --git a/configurator/src/components/panels/TypographyPanel.svelte b/configurator/src/components/panels/TypographyPanel.svelte index b2f27872..ced8be1e 100644 --- a/configurator/src/components/panels/TypographyPanel.svelte +++ b/configurator/src/components/panels/TypographyPanel.svelte @@ -367,6 +367,16 @@ {/each} + +
+
+ 1,204.05 + 98.10 + 13,760.75 +
+
Optical sizing
@@ -561,6 +571,19 @@
+ +
+ {#each LEADING_TOKENS as t (t.token)} +
+ {t.label} +

+ The quick brown fox jumps over the lazy dog while the rhythm of these lines shifts with the leading. +

+
+ {/each} +
+ {/each} + + +
+ {#each TRACKING_TOKENS as t (t.token)} +
+ {t.label} + Typography +
+ {/each} +
From 2324c13df165929a06fb63ed71bf22ba1c52c2e0 Mon Sep 17 00:00:00 2001 From: Kiro Agent <244629292+kiro-agent@users.noreply.github.com> Date: Fri, 21 Aug 2026 08:35:28 +0000 Subject: [PATCH 2/2] =?UTF-8?q?fix(configurator):=20address=20PR=20review?= =?UTF-8?q?=20=E2=80=94=20z-index=20order,=20stretch=20preview,=20tab=20a1?= =?UTF-8?q?1y?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ValueField: while confirming Inherit, only the Inherit tab is aria-pressed (previously two tabs were marked active). - LayoutPanel: cluster preview items use min-height so align-items:stretch is demonstrable; other alignment modes keep their uneven intrinsic heights. - MiscPanel: z-index preview orders the stack by each rung's current value (override or default) instead of a fixed array, so reordering the numbers reorders the visual stack. --- .../src/components/inputs/ValueField.svelte | 2 +- .../src/components/panels/LayoutPanel.svelte | 2 +- .../src/components/panels/MiscPanel.svelte | 17 +++++++++++------ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/configurator/src/components/inputs/ValueField.svelte b/configurator/src/components/inputs/ValueField.svelte index 167cf8e4..d94c8267 100644 --- a/configurator/src/components/inputs/ValueField.svelte +++ b/configurator/src/components/inputs/ValueField.svelte @@ -77,7 +77,7 @@
{#each TABS as t (t.id)} - {@const active = mode === t.id || (t.id === "inherit" && confirmingInherit)} + {@const active = confirmingInherit ? t.id === "inherit" : mode === t.id}
diff --git a/configurator/src/components/panels/MiscPanel.svelte b/configurator/src/components/panels/MiscPanel.svelte index 8d10ec75..af9e48e8 100644 --- a/configurator/src/components/panels/MiscPanel.svelte +++ b/configurator/src/components/panels/MiscPanel.svelte @@ -63,9 +63,14 @@ ``, )}`; - // Conceptual layering ladder (top rung = highest z). Static preview of the - // *order*, since the numeric values themselves have no standalone visual. - const Z_LADDER = [...Z_INDEX_STEPS].reverse(); + // Layering ladder for the preview: ordered by each rung's *current* value + // (override or default), highest first, so reordering the numbers reorders + // the visual stack instead of showing a fixed hierarchy. + let zLadder = $derived( + Z_INDEX_STEPS + .map((z) => ({ ...z, val: parseNum(overrides[z.token], z.def) })) + .sort((a, b) => b.val - a.val), + );
@@ -116,13 +121,13 @@
Higher rungs paint above lower ones.
- {#each Z_LADDER as z, i (z.token)} + {#each zLadder as z, i (z.token)}
{z.label} - {parseNum(overrides[z.token], z.def)} + {z.val}
{/each}