@motion-proto/live-tokens 0.10.0 → 0.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motion-proto/live-tokens",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "type": "module",
5
5
  "description": "Design token editor with live CSS variable editing. Svelte 5 + Vite 6/7.",
6
6
  "keywords": [
@@ -15,6 +15,7 @@
15
15
  { label: 'background blur', canBeLinked: true, groupKey: 'blur', variable: '--card-default-blur', element: 'frame' },
16
16
  { label: 'header color', groupKey: 'surface', variable: '--card-default-header-surface', element: 'header' },
17
17
  { label: 'header padding', canBeLinked: true, groupKey: 'header-padding', variable: '--card-default-header-padding', element: 'header' },
18
+ { label: 'icon gap', canBeLinked: true, groupKey: 'header-gap', variable: '--card-default-header-gap', element: 'header' },
18
19
  { label: 'icon size', canBeLinked: true, groupKey: 'icon-size', variable: '--card-default-icon-size', element: 'header' },
19
20
  { label: 'body padding', canBeLinked: true, groupKey: 'body-padding', variable: '--card-default-body-padding', element: 'body' },
20
21
  ],
@@ -63,6 +64,7 @@
63
64
  ['--card-default-border-width', 'card'],
64
65
  ['--card-default-radius', 'card'],
65
66
  ['--card-default-header-padding', 'card'],
67
+ ['--card-default-header-gap', 'card'],
66
68
  ['--card-default-body-padding', 'card'],
67
69
  ['--card-default-shadow', 'card'],
68
70
  ['--card-default-blur', 'card'],
@@ -53,7 +53,6 @@
53
53
  min-height: 12rem;
54
54
  border-radius: var(--ui-radius-md);
55
55
  box-sizing: border-box;
56
- overflow: hidden;
57
56
  }
58
57
 
59
58
  .shadow-backdrop.with-controls {
@@ -61,12 +60,22 @@
61
60
  grid-template-areas: "preview controls";
62
61
  }
63
62
 
63
+ /* Clip slotted children (e.g. Dialog's full-bleed overlay in padding=0 mode)
64
+ to the backdrop's rounded corners here rather than on the wrapper, so the
65
+ controls cell's dropdowns can escape vertically. The wrapper's image/color
66
+ background is still clipped naturally by its own border-radius. */
64
67
  .shadow-backdrop-content {
65
68
  display: grid;
66
69
  align-items: center;
67
70
  justify-items: start;
68
71
  min-width: 0;
69
72
  grid-area: preview;
73
+ border-radius: var(--ui-radius-md);
74
+ overflow: hidden;
75
+ }
76
+
77
+ .shadow-backdrop.with-controls .shadow-backdrop-content {
78
+ border-radius: var(--ui-radius-md) 0 0 var(--ui-radius-md);
70
79
  }
71
80
 
72
81
  .shadow-backdrop-controls {
@@ -19,7 +19,6 @@ import {
19
19
  columnsToVars,
20
20
  columnsEqualsDefault,
21
21
  overlaysToVars,
22
- overlaysEqualsDefault,
23
22
  shadowsToVars,
24
23
  gradientsToVars,
25
24
  componentsToVars,
@@ -30,9 +29,7 @@ export function deriveCssVars(state: EditorState): Record<string, string> {
30
29
  if (!columnsEqualsDefault(state.columns)) {
31
30
  Object.assign(out, columnsToVars(state.columns));
32
31
  }
33
- if (!overlaysEqualsDefault(state.overlays)) {
34
- Object.assign(out, overlaysToVars(state.overlays));
35
- }
32
+ Object.assign(out, overlaysToVars(state.overlays));
36
33
  if (state.shadows.tokens.length > 0) {
37
34
  Object.assign(out, shadowsToVars(state.shadows));
38
35
  }
@@ -51,7 +51,6 @@ import {
51
51
  import {
52
52
  loadOverlaysFromVars,
53
53
  makeDefaultOverlaysState,
54
- overlaysEqualsDefault,
55
54
  overlaysToVars,
56
55
  } from '../themes/slices/overlays';
57
56
  import {
@@ -133,14 +132,13 @@ export {
133
132
 
134
133
  export {
135
134
  overlaysToVars,
136
- overlaysEqualsDefault,
137
135
  OVERLAY_VAR_NAMES,
138
136
  applyOverlayVarsToState,
139
137
  makeDefaultOverlaysState,
140
- overlayTokenToRgba,
141
- parseRgba,
142
- RGBA_RE,
143
- HEX_RE,
138
+ makeDefaultOverlayTokens,
139
+ makeDefaultHoverTokens,
140
+ overlayTokenToCss,
141
+ parseOverlayCss,
144
142
  } from '../themes/slices/overlays';
145
143
 
146
144
  export {
@@ -548,9 +546,7 @@ export function toTheme(state: EditorState, meta: { name: string }): Theme {
548
546
  if (!columnsEqualsDefault(state.columns)) {
549
547
  Object.assign(cssVariables, columnsToVars(state.columns));
550
548
  }
551
- if (!overlaysEqualsDefault(state.overlays)) {
552
- Object.assign(cssVariables, overlaysToVars(state.overlays));
553
- }
549
+ Object.assign(cssVariables, overlaysToVars(state.overlays));
554
550
  if (state.shadows.tokens.length > 0) {
555
551
  Object.assign(cssVariables, shadowsToVars(state.shadows));
556
552
  }
@@ -21,19 +21,13 @@ export interface ShadowOverrideFlags {
21
21
  distance: boolean; blur: boolean; size: boolean;
22
22
  }
23
23
 
24
+ /** Overlay stop: an aliased color token + an opacity. Emits as
25
+ * `color-mix(in srgb, var(<alias>) <opacity%>, transparent)`. */
24
26
  export interface OverlayToken {
25
- variable: string; label: string;
26
- r: number; g: number; b: number; opacity: number;
27
- }
28
-
29
- export interface OverlayChannelGlobals {
30
- hue: number; saturation: number; lightness: number;
31
- opacityMin: number; opacityMax: number;
32
- }
33
-
34
- export interface OverlayGlobals {
35
- overlay: OverlayChannelGlobals;
36
- hover: OverlayChannelGlobals;
27
+ variable: string;
28
+ label: string;
29
+ alias: string;
30
+ opacity: number;
37
31
  }
38
32
 
39
33
  export interface ColumnsState {
@@ -134,7 +128,6 @@ export interface EditorState {
134
128
  overlays: {
135
129
  tokens: OverlayToken[];
136
130
  hoverTokens: OverlayToken[];
137
- globals: OverlayGlobals;
138
131
  };
139
132
  columns: ColumnsState;
140
133
  components: Record<string, ComponentSlice>;
@@ -1,26 +1,6 @@
1
1
  import type { Migration } from './index';
2
2
 
3
- /**
4
- * 2026-05-13: rename the `primary` color family to `brand`.
5
- *
6
- * The word "primary" was overloaded — both a color-family slot (alongside
7
- * info/success/danger/etc.) AND the top of the neutral text-emphasis ramp
8
- * (`--text-primary` / `--text-secondary` / `--text-tertiary`). Tokens like
9
- * `--text-primary-color` only existed because `--text-primary` was already
10
- * taken by neutral. Renaming the family to `brand` dissolves the collision:
11
- *
12
- * --color-primary-{step} → --color-brand-{step}
13
- * --surface-primary[-step] → --surface-brand[-step]
14
- * --border-primary[-step] → --border-brand[-step]
15
- * --text-primary-color → --text-brand
16
- * --text-primary-{step} → --text-brand-{step} (step in secondary|tertiary|muted|disabled)
17
- *
18
- * The neutral text ramp (`--text-primary`, `--text-secondary`, …) is **left
19
- * untouched** — it's a different namespace that just happens to share the
20
- * word. The match list below enumerates the brand-family names explicitly so
21
- * a substring-on-`primary` mistake can't clobber neutral text or unrelated
22
- * tokens like `--button-primary-*` (component variant, not family).
23
- */
3
+ // Match list is explicit so the neutral `--text-primary` ramp (different namespace) isn't clobbered.
24
4
 
25
5
  const PALETTE_STEPS = ['100','200','300','400','500','600','700','800','850','900','950'] as const;
26
6
  const SURFACE_SUFFIXES = ['lowest','lower','low','high','higher','highest'] as const;
@@ -43,7 +23,6 @@ function renameToken(name: string): string {
43
23
  return RENAME_MAP[name] ?? name;
44
24
  }
45
25
 
46
- /** Rewrite keys only — used for theme cssVariables (values are hex). */
47
26
  function renameKeys(rawVars: Record<string, string>): Record<string, string> {
48
27
  const out: Record<string, string> = {};
49
28
  for (const [k, v] of Object.entries(rawVars)) {
@@ -52,7 +31,6 @@ function renameKeys(rawVars: Record<string, string>): Record<string, string> {
52
31
  return out;
53
32
  }
54
33
 
55
- /** Rewrite both keys and values — used for component-config aliases. */
56
34
  function renameKeysAndValues(rawVars: Record<string, string>): Record<string, string> {
57
35
  const out: Record<string, string> = {};
58
36
  for (const [k, v] of Object.entries(rawVars)) {
@@ -77,12 +55,7 @@ export const componentMigration_2026_05_13_primaryToBrand: Migration = {
77
55
  apply: renameKeysAndValues,
78
56
  };
79
57
 
80
- /**
81
- * Helper for loadFromFile: rename `theme.editorConfigs.Primary` → `Brand`.
82
- * Lives here (with the rest of the rename) instead of in the migration
83
- * framework because the framework's contract is `Record<string, string>` —
84
- * editorConfigs is a structured palette-config map and can't pass through it.
85
- */
58
+ // Lives outside the migration framework because its contract is Record<string, string>; editorConfigs is structured.
86
59
  export function renamePrimaryPaletteKey<T>(editorConfigs: Record<string, T>): Record<string, T> {
87
60
  if (!('Primary' in editorConfigs) || 'Brand' in editorConfigs) return editorConfigs;
88
61
  const { Primary, ...rest } = editorConfigs;
@@ -0,0 +1,46 @@
1
+ import type { Migration } from './index';
2
+
3
+ /**
4
+ * Overlay scale trim (2026-05-26): `--overlay-lowest`, `--overlay-lower`,
5
+ * `--overlay-higher`, and `--overlay-highest` were retired. The kept stops
6
+ * are `--overlay-low`, `--overlay`, and `--overlay-high`. Theme files
7
+ * stripped of the dropped keys; component configs whose aliases referenced
8
+ * a dropped stop rebind to the nearest survivor.
9
+ */
10
+ const DROPPED_TO_KEPT: Record<string, string> = {
11
+ '--overlay-lowest': '--overlay-low',
12
+ '--overlay-lower': '--overlay-low',
13
+ '--overlay-higher': '--overlay-high',
14
+ '--overlay-highest': '--overlay-high',
15
+ };
16
+
17
+ export const themeMigration_2026_05_26_dropOverlayExtraStops: Migration = {
18
+ id: '2026-05-26-drop-overlay-extra-stops-theme',
19
+ fromVersion: 2,
20
+ toVersion: 3,
21
+ appliesTo: 'theme',
22
+ apply(rawVars) {
23
+ const out: Record<string, string> = {};
24
+ for (const [key, value] of Object.entries(rawVars)) {
25
+ if (key in DROPPED_TO_KEPT) continue;
26
+ out[key] = value;
27
+ }
28
+ return out;
29
+ },
30
+ };
31
+
32
+ export const componentMigration_2026_05_26_dropOverlayExtraStops: Migration = {
33
+ id: '2026-05-26-drop-overlay-extra-stops-component',
34
+ fromVersion: 16,
35
+ toVersion: 17,
36
+ appliesTo: 'component-config',
37
+ apply(rawVars) {
38
+ const out: Record<string, string> = {};
39
+ for (const [key, value] of Object.entries(rawVars)) {
40
+ // Alias values are bare token names like "--overlay-higher" — rebind
41
+ // those to the nearest kept stop. Literal CSS values are left alone.
42
+ out[key] = DROPPED_TO_KEPT[value] ?? value;
43
+ }
44
+ return out;
45
+ },
46
+ };
@@ -50,6 +50,10 @@ import { componentMigration_2026_05_24_promoteStateSharedTokens } from './2026-0
50
50
  import { componentMigration_2026_05_24_progressbarCollapseVariants } from './2026-05-24-progressbar-collapse-variants';
51
51
  import { componentMigration_2026_05_24_collapsiblesectionDropActiveState } from './2026-05-24-collapsiblesection-drop-active-state';
52
52
  import { componentMigration_2026_05_25_cornerbadgeFlattenVariants } from './2026-05-25-cornerbadge-flatten-variants';
53
+ import {
54
+ themeMigration_2026_05_26_dropOverlayExtraStops,
55
+ componentMigration_2026_05_26_dropOverlayExtraStops,
56
+ } from './2026-05-26-drop-overlay-extra-stops';
53
57
 
54
58
  /**
55
59
  * Registered migrations. Order in this array does not matter — the runner
@@ -74,6 +78,8 @@ export const MIGRATIONS: Migration[] = [
74
78
  componentMigration_2026_05_24_progressbarCollapseVariants,
75
79
  componentMigration_2026_05_24_collapsiblesectionDropActiveState,
76
80
  componentMigration_2026_05_25_cornerbadgeFlattenVariants,
81
+ themeMigration_2026_05_26_dropOverlayExtraStops,
82
+ componentMigration_2026_05_26_dropOverlayExtraStops,
77
83
  ];
78
84
 
79
85
  function countFor(kind: 'theme' | 'component-config'): number {
@@ -1,28 +1,28 @@
1
1
  /**
2
- * Overlays slice — overlay + hover RGBA tokens. Defaults are editor-defined
3
- * (mirror what `VariablesTab` historically initialised into local let state)
4
- * and diverge from tokens.css by design: the editor starts with a neutral
5
- * palette and tokens.css continues to win until first edit.
2
+ * Overlays slice — overlay + hover stops, each stored as `{alias, opacity}`.
3
+ * Emits as `color-mix(in srgb, var(<alias>) <pct>%, transparent)` so the
4
+ * overlay tints automatically follow the aliased source token (a brand-color
5
+ * shift propagates without re-editing every overlay).
6
+ *
7
+ * Defaults diverge from tokens.css by design: the editor starts from a
8
+ * neutral alias and tokens.css continues to win until first edit (see
9
+ * `overlaysEqualsDefault`).
6
10
  */
7
11
  import type { EditorState, OverlayToken } from '../../store/editorTypes';
8
12
 
9
13
  export function makeDefaultOverlayTokens(): OverlayToken[] {
10
14
  return [
11
- { variable: '--overlay-lowest', label: 'Lowest', r: 0, g: 0, b: 0, opacity: 0.05 },
12
- { variable: '--overlay-lower', label: 'Lower', r: 0, g: 0, b: 0, opacity: 0.1 },
13
- { variable: '--overlay-low', label: 'Low', r: 0, g: 0, b: 0, opacity: 0.2 },
14
- { variable: '--overlay', label: 'Base', r: 0, g: 0, b: 0, opacity: 0.3 },
15
- { variable: '--overlay-high', label: 'High', r: 0, g: 0, b: 0, opacity: 0.5 },
16
- { variable: '--overlay-higher', label: 'Higher', r: 0, g: 0, b: 0, opacity: 0.7 },
17
- { variable: '--overlay-highest',label: 'Highest',r: 0, g: 0, b: 0, opacity: 0.95 },
15
+ { variable: '--overlay-low', label: 'Low', alias: '--surface-neutral-lowest', opacity: 0.38 },
16
+ { variable: '--overlay', label: 'Base', alias: '--surface-neutral-lowest', opacity: 0.51 },
17
+ { variable: '--overlay-high', label: 'High', alias: '--surface-neutral-lowest', opacity: 0.64 },
18
18
  ];
19
19
  }
20
20
 
21
21
  export function makeDefaultHoverTokens(): OverlayToken[] {
22
22
  return [
23
- { variable: '--hover-low', label: 'Low', r: 255, g: 255, b: 255, opacity: 0.05 },
24
- { variable: '--hover', label: 'Base', r: 255, g: 255, b: 255, opacity: 0.1 },
25
- { variable: '--hover-high', label: 'High', r: 255, g: 255, b: 255, opacity: 0.15 },
23
+ { variable: '--hover-low', label: 'Low', alias: '--text-primary', opacity: 0.05 },
24
+ { variable: '--hover', label: 'Base', alias: '--text-primary', opacity: 0.1 },
25
+ { variable: '--hover-high', label: 'High', alias: '--text-primary', opacity: 0.15 },
26
26
  ];
27
27
  }
28
28
 
@@ -30,88 +30,52 @@ export function makeDefaultOverlaysState(): EditorState['overlays'] {
30
30
  return {
31
31
  tokens: makeDefaultOverlayTokens(),
32
32
  hoverTokens: makeDefaultHoverTokens(),
33
- globals: {
34
- overlay: { hue: 0, saturation: 0, lightness: 0, opacityMin: 0.05, opacityMax: 0.95 },
35
- hover: { hue: 0, saturation: 0, lightness: 100, opacityMin: 0.05, opacityMax: 0.15 },
36
- },
37
33
  };
38
34
  }
39
35
 
40
36
  export const OVERLAY_VAR_NAMES = [
41
- '--overlay-lowest', '--overlay-lower', '--overlay-low', '--overlay',
42
- '--overlay-high', '--overlay-higher', '--overlay-highest',
37
+ '--overlay-low', '--overlay', '--overlay-high',
43
38
  '--hover-low', '--hover', '--hover-high',
44
39
  ] as const;
45
40
 
46
- // Accepts rgb(), rgba(), and #rrggbb[aa] — themes saved by the editor
47
- // always use rgba(), but loading hand-written files shouldn't break.
48
- export const RGBA_RE = /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+)\s*)?\)/i;
49
- export const HEX_RE = /^#([0-9a-f]{6})([0-9a-f]{2})?$/i;
41
+ export function overlayTokenToCss(t: OverlayToken): string {
42
+ const pct = Math.round(t.opacity * 100);
43
+ if (pct >= 100) return `var(${t.alias})`;
44
+ return `color-mix(in srgb, var(${t.alias}) ${pct}%, transparent)`;
45
+ }
46
+
47
+ const COLOR_MIX_RE = /^color-mix\(in srgb,\s*var\((--[a-z0-9-]+)\)\s+(\d+)%,\s*transparent\)$/i;
48
+ const PLAIN_VAR_RE = /^var\((--[a-z0-9-]+)\)$/i;
50
49
 
51
- export function parseRgba(raw: string): { r: number; g: number; b: number; opacity: number } | null {
50
+ export function parseOverlayCss(raw: string): { alias: string; opacity: number } | null {
52
51
  const s = raw.trim();
53
- const m = s.match(RGBA_RE);
54
- if (m) {
55
- const r = parseInt(m[1], 10);
56
- const g = parseInt(m[2], 10);
57
- const b = parseInt(m[3], 10);
58
- const a = m[4] !== undefined ? parseFloat(m[4]) : 1;
59
- if (![r, g, b].every((n) => Number.isFinite(n) && n >= 0 && n <= 255)) return null;
60
- return { r, g, b, opacity: Number.isFinite(a) ? a : 1 };
61
- }
62
- const h = s.match(HEX_RE);
63
- if (h) {
64
- const hex = h[1];
65
- const alpha = h[2] !== undefined ? parseInt(h[2], 16) / 255 : 1;
66
- return {
67
- r: parseInt(hex.slice(0, 2), 16),
68
- g: parseInt(hex.slice(2, 4), 16),
69
- b: parseInt(hex.slice(4, 6), 16),
70
- opacity: Math.round(alpha * 100) / 100,
71
- };
52
+ const mix = s.match(COLOR_MIX_RE);
53
+ if (mix) {
54
+ const pct = parseInt(mix[2], 10);
55
+ if (!Number.isFinite(pct)) return null;
56
+ return { alias: mix[1], opacity: Math.max(0, Math.min(100, pct)) / 100 };
72
57
  }
58
+ const plain = s.match(PLAIN_VAR_RE);
59
+ if (plain) return { alias: plain[1], opacity: 1 };
73
60
  return null;
74
61
  }
75
62
 
76
- export function overlayTokenToRgba(t: OverlayToken): string {
77
- return `rgba(${t.r}, ${t.g}, ${t.b}, ${t.opacity})`;
78
- }
79
-
80
63
  export function overlaysToVars(o: EditorState['overlays']): Record<string, string> {
81
64
  const out: Record<string, string> = {};
82
- for (const t of o.tokens) out[t.variable] = overlayTokenToRgba(t);
83
- for (const t of o.hoverTokens) out[t.variable] = overlayTokenToRgba(t);
65
+ for (const t of o.tokens) out[t.variable] = overlayTokenToCss(t);
66
+ for (const t of o.hoverTokens) out[t.variable] = overlayTokenToCss(t);
84
67
  return out;
85
68
  }
86
69
 
87
- function tokensEqualDefault(tokens: OverlayToken[], defaults: OverlayToken[]): boolean {
88
- if (tokens.length !== defaults.length) return false;
89
- for (let i = 0; i < tokens.length; i++) {
90
- const a = tokens[i]; const b = defaults[i];
91
- if (a.variable !== b.variable || a.r !== b.r || a.g !== b.g || a.b !== b.b || a.opacity !== b.opacity) return false;
92
- }
93
- return true;
94
- }
95
-
96
- /**
97
- * Same pattern as columns: only emit overlay CSS vars once state diverges
98
- * from the editor defaults. tokens.css owns the rgba values until the
99
- * user touches any overlay control (or loads a theme that already
100
- * contains overrides).
101
- */
102
- export function overlaysEqualsDefault(o: EditorState['overlays']): boolean {
103
- return tokensEqualDefault(o.tokens, makeDefaultOverlayTokens())
104
- && tokensEqualDefault(o.hoverTokens, makeDefaultHoverTokens());
105
- }
106
-
107
70
  export function applyOverlayVarsToState(overlays: EditorState['overlays'], vars: Record<string, string>): void {
108
71
  const applyTo = (list: OverlayToken[]) => {
109
72
  for (const t of list) {
110
73
  const raw = vars[t.variable];
111
74
  if (!raw) continue;
112
- const parsed = parseRgba(raw);
75
+ const parsed = parseOverlayCss(raw);
113
76
  if (!parsed) continue;
114
- t.r = parsed.r; t.g = parsed.g; t.b = parsed.b; t.opacity = parsed.opacity;
77
+ t.alias = parsed.alias;
78
+ t.opacity = parsed.opacity;
115
79
  }
116
80
  };
117
81
  applyTo(overlays.tokens);
@@ -120,13 +84,18 @@ export function applyOverlayVarsToState(overlays: EditorState['overlays'], vars:
120
84
 
121
85
  /**
122
86
  * Loader: route overlay/hover entries from a freshly-loaded theme's vars
123
- * bag into `next.overlays` and remove them from the bag. Mutates `next`
124
- * and `rawVars` in place.
87
+ * bag into `next.overlays` and remove them from the bag but only when the
88
+ * value parses as the new format (color-mix / plain var). Legacy rgba values
89
+ * pass through to the cssVars bag so the DOM still paints them; the user's
90
+ * next edit in the picker promotes them to the typed slice.
125
91
  */
126
92
  export function loadOverlaysFromVars(
127
93
  next: EditorState,
128
94
  rawVars: Record<string, string>,
129
95
  ): void {
130
96
  applyOverlayVarsToState(next.overlays, rawVars);
131
- for (const name of OVERLAY_VAR_NAMES) delete rawVars[name];
97
+ for (const name of OVERLAY_VAR_NAMES) {
98
+ const raw = rawVars[name];
99
+ if (raw && parseOverlayCss(raw) !== null) delete rawVars[name];
100
+ }
132
101
  }
@@ -31,13 +31,9 @@
31
31
  {
32
32
  title: 'Overlays',
33
33
  swatches: [
34
- { name: 'Lowest', variable: '--overlay-lowest', description: 'Barely visible tint' },
35
- { name: 'Lower', variable: '--overlay-lower', description: 'Very subtle overlay' },
36
- { name: 'Low', variable: '--overlay-low', description: 'Light overlay' },
37
- { name: 'Overlay', variable: '--overlay', description: 'Standard overlay' },
38
- { name: 'High', variable: '--overlay-high', description: 'Heavy overlay' },
39
- { name: 'Higher', variable: '--overlay-higher', description: 'Modal backdrop' },
40
- { name: 'Highest', variable: '--overlay-highest', description: 'Nearly opaque' }
34
+ { name: 'Low', variable: '--overlay-low', description: 'Light backdrop / pressed wash' },
35
+ { name: 'Overlay', variable: '--overlay', description: 'Standard backdrop' },
36
+ { name: 'High', variable: '--overlay-high', description: 'Strong backdrop' }
41
37
  ]
42
38
  },
43
39
  {
@@ -18,7 +18,7 @@
18
18
  unlinkComponentProperty,
19
19
  relinkComponentProperty,
20
20
  } from '../core/store/editorStore';
21
- import UIRelinkConfirmPopover from './UIRelinkConfirmPopover.svelte';
21
+ import UIRelinkConfirmDialog from './UIRelinkConfirmDialog.svelte';
22
22
  import UILinkToggle from './UILinkToggle.svelte';
23
23
 
24
24
  interface Props {
@@ -383,7 +383,7 @@
383
383
  <div class="link-toggle-wrap">
384
384
  <UILinkToggle linked={isLinkedParent} ontoggle={toggleLinkPaddingGroup} />
385
385
  {#if relinkOpen && component}
386
- <UIRelinkConfirmPopover
386
+ <UIRelinkConfirmDialog
387
387
  candidates={relinkCandidates}
388
388
  initialVariable={variable}
389
389
  prefixToStrip={`--${component}-`}