@motion-proto/live-tokens 0.3.9 → 0.5.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 +9 -8
- package/src/component-editor/BadgeEditor.svelte +24 -22
- package/src/component-editor/CalloutEditor.svelte +3 -3
- package/src/component-editor/CardEditor.svelte +25 -21
- package/src/component-editor/CollapsibleSectionEditor.svelte +27 -25
- package/src/component-editor/CornerBadgeEditor.svelte +37 -35
- package/src/component-editor/DialogEditor.svelte +26 -24
- package/src/component-editor/ImageEditor.svelte +11 -9
- package/src/component-editor/InlineEditActionsEditor.svelte +17 -15
- package/src/component-editor/NotificationEditor.svelte +32 -30
- package/src/component-editor/ProgressBarEditor.svelte +3 -3
- package/src/component-editor/RadioButtonEditor.svelte +31 -29
- package/src/component-editor/SectionDividerEditor.svelte +30 -28
- package/src/component-editor/SegmentedControlEditor.svelte +29 -25
- package/src/component-editor/StandardButtonsEditor.svelte +42 -38
- package/src/component-editor/TabBarEditor.svelte +20 -18
- package/src/component-editor/TableEditor.svelte +4 -4
- package/src/component-editor/TooltipEditor.svelte +11 -9
- package/src/component-editor/registry.ts +2 -2
- package/src/component-editor/scaffolding/AngleDial.svelte +20 -19
- package/src/component-editor/scaffolding/ComponentEditorBase.svelte +44 -20
- package/src/component-editor/scaffolding/ComponentFileManager.svelte +260 -37
- package/src/component-editor/scaffolding/ComponentFileMenu.svelte +41 -29
- package/src/component-editor/scaffolding/ComponentsTab.svelte +7 -3
- package/src/component-editor/scaffolding/CopyFromMenu.svelte +21 -12
- package/src/component-editor/scaffolding/DemoHeader.svelte +13 -4
- package/src/component-editor/scaffolding/DividerEditor.svelte +27 -14
- package/src/component-editor/scaffolding/FieldsetWrapper.svelte +10 -4
- package/src/component-editor/scaffolding/GradientCard.svelte +25 -20
- package/src/component-editor/scaffolding/LinkageChart.svelte +43 -34
- package/src/component-editor/scaffolding/LinkedBlock.svelte +24 -21
- package/src/component-editor/scaffolding/NonStylableConfig.svelte +6 -1
- package/src/component-editor/scaffolding/SaveAsDialog.svelte +39 -35
- package/src/component-editor/scaffolding/ShadowBackdrop.svelte +21 -9
- package/src/component-editor/scaffolding/ShadowBackdropControls.svelte +8 -3
- package/src/component-editor/scaffolding/StateBlock.svelte +30 -13
- package/src/component-editor/scaffolding/TokenLayout.svelte +46 -30
- package/src/component-editor/scaffolding/TypeEditor.svelte +52 -26
- package/src/component-editor/scaffolding/VariantGroup.svelte +81 -48
- package/src/component-editor/scaffolding/componentSectionType.ts +2 -2
- package/src/components/Badge.svelte +45 -26
- package/src/components/Button.svelte +44 -21
- package/src/components/Callout.svelte +17 -12
- package/src/components/Card.svelte +23 -11
- package/src/components/CollapsibleSection.svelte +56 -27
- package/src/components/CornerBadge.svelte +32 -18
- package/src/components/Dialog.svelte +55 -31
- package/src/components/Image.svelte +14 -5
- package/src/components/InlineEditActions.svelte +22 -10
- package/src/components/Notification.svelte +39 -19
- package/src/components/ProgressBar.svelte +27 -17
- package/src/components/RadioButton.svelte +27 -10
- package/src/components/SectionDivider.svelte +34 -26
- package/src/components/SegmentedControl.svelte +23 -9
- package/src/components/TabBar.svelte +23 -10
- package/src/components/Table.svelte +8 -3
- package/src/components/Tooltip.svelte +15 -5
- package/src/lib/ColumnsOverlay.svelte +3 -3
- package/src/lib/LiveEditorOverlay.svelte +57 -36
- package/src/pages/ComponentEditorPage.svelte +17 -13
- package/src/pages/EditorShell.svelte +24 -20
- package/src/styles/form-controls.css +2 -2
- package/src/styles/tokens.css +59 -81
- package/src/ui/BezierCurveEditor.svelte +59 -43
- package/src/ui/ColorEditPanel.svelte +71 -44
- package/src/ui/EditorViewSwitcher.svelte +9 -5
- package/src/ui/FontStackEditor.svelte +16 -15
- package/src/ui/GradientEditor.svelte +42 -33
- package/src/ui/GradientStopPicker.svelte +18 -29
- package/src/ui/PaletteEditor.svelte +238 -212
- package/src/ui/PresetFileManager.svelte +20 -18
- package/src/ui/ProjectFontsSection.svelte +30 -30
- package/src/ui/SurfacesTab.svelte +3 -3
- package/src/ui/TextTab.svelte +2 -2
- package/src/ui/ThemeFileManager.svelte +38 -35
- package/src/ui/Toggle.svelte +11 -9
- package/src/ui/UICopyPopover.svelte +19 -15
- package/src/ui/UIDialog.svelte +48 -30
- package/src/ui/UIFontFamilySelector.svelte +104 -78
- package/src/ui/UIFontSizeSelector.svelte +38 -20
- package/src/ui/UIFontWeightSelector.svelte +33 -13
- package/src/ui/UILineHeightSelector.svelte +33 -13
- package/src/ui/UILinkToggle.svelte +7 -6
- package/src/ui/UIOptionItem.svelte +21 -7
- package/src/ui/UIOptionList.svelte +9 -3
- package/src/ui/UIPaddingSelector.svelte +108 -82
- package/src/ui/UIPaletteSelector.svelte +186 -161
- package/src/ui/UIRadio.svelte +23 -8
- package/src/ui/UIRadioGroup.svelte +9 -8
- package/src/ui/UIRelinkConfirmPopover.svelte +26 -16
- package/src/ui/UITokenSelector.svelte +112 -68
- package/src/ui/UIVariantSelector.svelte +79 -57
- package/src/ui/VariablesTab.svelte +15 -15
- package/src/ui/palette/GradientStopEditor.svelte +45 -26
- package/src/ui/palette/OverridesPanel.svelte +85 -49
- package/src/ui/palette/PaletteBase.svelte +60 -32
- package/src/ui/palette/ScaleCurveEditor.svelte +25 -10
- package/src/ui/sections/ColumnsSection.svelte +13 -13
- package/src/ui/sections/GradientsSection.svelte +12 -9
- package/src/ui/sections/OverlaysSection.svelte +50 -47
- package/src/ui/sections/ShadowsSection.svelte +110 -104
- package/src/ui/sections/TokenScaleTable.svelte +38 -22
- package/src/ui/sections/tokenScales.ts +2 -2
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { onMount, onDestroy } from 'svelte';
|
|
3
3
|
|
|
4
4
|
type Source = { name: string; label: string; states: string[] };
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
interface Props {
|
|
7
|
+
toState: string;
|
|
8
|
+
variantName: string;
|
|
9
|
+
copySources?: Source[];
|
|
10
|
+
placement?: 'start' | 'end';
|
|
11
|
+
onselect?: (payload: { fromVariant: string; fromState: string }) => void;
|
|
12
|
+
}
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
let {
|
|
15
|
+
toState,
|
|
16
|
+
variantName,
|
|
17
|
+
copySources = [],
|
|
18
|
+
placement = 'start',
|
|
19
|
+
onselect
|
|
20
|
+
}: Props = $props();
|
|
12
21
|
|
|
13
|
-
let open = false;
|
|
14
|
-
let root: HTMLElement;
|
|
22
|
+
let open = $state(false);
|
|
23
|
+
let root: HTMLElement | undefined = $state();
|
|
15
24
|
|
|
16
25
|
function toggle() {
|
|
17
26
|
open = !open;
|
|
@@ -19,7 +28,7 @@
|
|
|
19
28
|
|
|
20
29
|
function pick(fromVariant: string, fromState: string) {
|
|
21
30
|
open = false;
|
|
22
|
-
|
|
31
|
+
onselect?.({ fromVariant, fromState });
|
|
23
32
|
}
|
|
24
33
|
|
|
25
34
|
function handleDocClick(e: MouseEvent) {
|
|
@@ -47,7 +56,7 @@
|
|
|
47
56
|
type="button"
|
|
48
57
|
class="copy-from-btn"
|
|
49
58
|
class:active={open}
|
|
50
|
-
|
|
59
|
+
onclick={toggle}
|
|
51
60
|
title="Copy values from another variant/state"
|
|
52
61
|
>
|
|
53
62
|
<i class="fas fa-clone"></i>
|
|
@@ -63,7 +72,7 @@
|
|
|
63
72
|
type="button"
|
|
64
73
|
class="copy-menu-item"
|
|
65
74
|
disabled={isSelf}
|
|
66
|
-
|
|
75
|
+
onclick={() => pick(src.name, onlyState)}
|
|
67
76
|
role="menuitem"
|
|
68
77
|
>
|
|
69
78
|
<span>{src.label}</span>
|
|
@@ -87,7 +96,7 @@
|
|
|
87
96
|
type="button"
|
|
88
97
|
class="copy-menu-item"
|
|
89
98
|
disabled={isSelf}
|
|
90
|
-
|
|
99
|
+
onclick={() => pick(src.name, fromState)}
|
|
91
100
|
role="menuitem"
|
|
92
101
|
>
|
|
93
102
|
<span>{fromState}</span>
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import ComponentFileManager from './ComponentFileManager.svelte';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
interface Props {
|
|
5
|
+
component: string;
|
|
6
|
+
title: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
resetVariables?: string[] | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let {
|
|
12
|
+
component,
|
|
13
|
+
title,
|
|
14
|
+
description = '',
|
|
15
|
+
resetVariables = null
|
|
16
|
+
}: Props = $props();
|
|
8
17
|
</script>
|
|
9
18
|
|
|
10
19
|
<ComponentFileManager {component} {title} {resetVariables} />
|
|
@@ -6,16 +6,29 @@
|
|
|
6
6
|
import { BORDER_WIDTH, DIVIDER_HEIGHT } from '../../ui/variantScales';
|
|
7
7
|
import FieldsetWrapper from './FieldsetWrapper.svelte';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
colorVariable?: string | undefined;
|
|
12
|
+
colorLabel?: string | undefined;
|
|
13
|
+
widthVariable?: string | undefined;
|
|
14
|
+
widthLabel?: string | undefined;
|
|
15
|
+
heightVariable?: string | undefined;
|
|
16
|
+
heightLabel?: string | undefined;
|
|
17
|
+
/** When set, writes persist through the editor store under this component. */
|
|
18
|
+
component?: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let {
|
|
22
|
+
colorVariable = undefined,
|
|
23
|
+
colorLabel = undefined,
|
|
24
|
+
widthVariable = undefined,
|
|
25
|
+
widthLabel = undefined,
|
|
26
|
+
heightVariable = undefined,
|
|
27
|
+
heightLabel = undefined,
|
|
28
|
+
component = undefined
|
|
29
|
+
}: Props = $props();
|
|
17
30
|
|
|
18
|
-
let heightResolved = '';
|
|
31
|
+
let heightResolved = $state('');
|
|
19
32
|
|
|
20
33
|
function readHeight() {
|
|
21
34
|
if (!heightVariable) {
|
|
@@ -41,26 +54,26 @@
|
|
|
41
54
|
document.removeEventListener(CSS_VAR_CHANGE_EVENT, handleVarChange);
|
|
42
55
|
});
|
|
43
56
|
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
let heightIsZero = $derived(/^0+(?:\.0+)?(px|rem|em|%)?$/.test(heightResolved));
|
|
58
|
+
let siblingDisabled = $derived(heightIsZero);
|
|
46
59
|
</script>
|
|
47
60
|
|
|
48
61
|
<FieldsetWrapper legend="divider">
|
|
49
62
|
{#if colorVariable}
|
|
50
63
|
<div class="entry">
|
|
51
|
-
<UIPaletteSelector variable={colorVariable} {component} disabled={siblingDisabled}
|
|
64
|
+
<UIPaletteSelector variable={colorVariable} {component} disabled={siblingDisabled} onchange={readHeight} />
|
|
52
65
|
<span class="label">{colorLabel ?? ''}</span>
|
|
53
66
|
</div>
|
|
54
67
|
{/if}
|
|
55
68
|
{#if widthVariable}
|
|
56
69
|
<div class="entry">
|
|
57
|
-
<UIVariantSelector variable={widthVariable} {component} disabled={siblingDisabled} {...BORDER_WIDTH}
|
|
70
|
+
<UIVariantSelector variable={widthVariable} {component} disabled={siblingDisabled} {...BORDER_WIDTH} onchange={readHeight} />
|
|
58
71
|
<span class="label">{widthLabel ?? ''}</span>
|
|
59
72
|
</div>
|
|
60
73
|
{/if}
|
|
61
74
|
{#if heightVariable}
|
|
62
75
|
<div class="entry">
|
|
63
|
-
<UIVariantSelector variable={heightVariable} {component} {...DIVIDER_HEIGHT}
|
|
76
|
+
<UIVariantSelector variable={heightVariable} {component} {...DIVIDER_HEIGHT} onchange={readHeight} />
|
|
64
77
|
<span class="label">{heightLabel ?? ''}</span>
|
|
65
78
|
</div>
|
|
66
79
|
{/if}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
legend?: string;
|
|
5
|
+
/** When true, the fieldset is rendered with a strong outline to mark it as the one currently driving the rendered preview. */
|
|
6
|
+
active?: boolean;
|
|
7
|
+
children?: import('svelte').Snippet;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let { legend = '', active = false, children }: Props = $props();
|
|
5
11
|
</script>
|
|
6
12
|
|
|
7
13
|
<fieldset class="fieldset-wrapper" class:active>
|
|
@@ -9,7 +15,7 @@
|
|
|
9
15
|
<legend class="fieldset-legend">{legend}</legend>
|
|
10
16
|
{/if}
|
|
11
17
|
<div class="fieldset-controls">
|
|
12
|
-
|
|
18
|
+
{@render children?.()}
|
|
13
19
|
</div>
|
|
14
20
|
</fieldset>
|
|
15
21
|
|
|
@@ -16,14 +16,19 @@
|
|
|
16
16
|
import UIPaletteSelector from '../../ui/UIPaletteSelector.svelte';
|
|
17
17
|
import AngleDial from './AngleDial.svelte';
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
component: string;
|
|
22
|
+
/** Prefix shared by all 7 token names — e.g. `--sectiondivider-canvas`. */
|
|
23
|
+
prefix: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let { component, prefix }: Props = $props();
|
|
22
27
|
|
|
23
28
|
type StopIndex = 1 | 2 | 3;
|
|
24
29
|
const STOPS: readonly StopIndex[] = [1, 2, 3] as const;
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
let angleVar = $derived(`${prefix}-gradient-angle`);
|
|
27
32
|
function stopColorVar(i: StopIndex): string {
|
|
28
33
|
return `${prefix}-gradient-stop-${i}-color`;
|
|
29
34
|
}
|
|
@@ -52,27 +57,27 @@
|
|
|
52
57
|
return m ? parseFloat(m[1]) : null;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
let angleDeg = $derived(parseNumberFromCss(resolveLiteralWith($tokenRegistry$, angleVar), 'deg') ?? 135);
|
|
61
|
+
let positions = $derived([
|
|
57
62
|
parseNumberFromCss(resolveLiteralWith($tokenRegistry$, stopPositionVar(1)), '%') ?? 0,
|
|
58
63
|
parseNumberFromCss(resolveLiteralWith($tokenRegistry$, stopPositionVar(2)), '%') ?? 50,
|
|
59
64
|
parseNumberFromCss(resolveLiteralWith($tokenRegistry$, stopPositionVar(3)), '%') ?? 100,
|
|
60
|
-
] as [number, number, number];
|
|
65
|
+
] as [number, number, number]);
|
|
61
66
|
|
|
62
67
|
// Reference the per-stop CSS var directly so the cascade fills in the
|
|
63
68
|
// component's CSS defaults when the user hasn't overridden a stop. Reading
|
|
64
69
|
// `aliases[...]` alone would miss defaults (no override → `#888`) even
|
|
65
70
|
// though the component is rendering the color via its own `:root` block.
|
|
66
|
-
|
|
71
|
+
let stopColors = $derived(([1, 2, 3] as StopIndex[]).map((i) => `var(${stopColorVar(i)})`) as [string, string, string]);
|
|
67
72
|
|
|
68
73
|
// Build the live gradient string from current positions + colors so the
|
|
69
74
|
// ribbon reflects edits even mid-drag (before the component re-renders via
|
|
70
75
|
// its own CSS var consumption).
|
|
71
|
-
|
|
76
|
+
let ribbonBg = $derived(`linear-gradient(90deg, ${stopColors
|
|
72
77
|
.map((c, i) => `${c} ${positions[i]}%`)
|
|
73
|
-
.join(', ')})
|
|
78
|
+
.join(', ')})`);
|
|
74
79
|
|
|
75
|
-
let selected: StopIndex = 1;
|
|
80
|
+
let selected: StopIndex = $state(1);
|
|
76
81
|
|
|
77
82
|
function setAngle(deg: number) {
|
|
78
83
|
setComponentAlias(component, angleVar, { kind: 'literal', value: `${Math.round(deg)}deg` });
|
|
@@ -84,11 +89,11 @@
|
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
// ── Position handle drag ────────────────────────────────────────────────
|
|
87
|
-
let barEl: HTMLDivElement;
|
|
88
|
-
let dragIndex: StopIndex | null = null;
|
|
92
|
+
let barEl: HTMLDivElement | undefined = $state();
|
|
93
|
+
let dragIndex: StopIndex | null = $state(null);
|
|
89
94
|
|
|
90
95
|
function pctFromEvent(e: PointerEvent): number {
|
|
91
|
-
const rect = barEl
|
|
96
|
+
const rect = barEl!.getBoundingClientRect();
|
|
92
97
|
const x = e.clientX - rect.left;
|
|
93
98
|
return (x / rect.width) * 100;
|
|
94
99
|
}
|
|
@@ -126,10 +131,10 @@
|
|
|
126
131
|
class:selected={selected === i}
|
|
127
132
|
class:dragging={dragIndex === i}
|
|
128
133
|
style="left: {positions[i - 1]}%; --stop-color: {stopColors[i - 1]};"
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
134
|
+
onpointerdown={(e) => onHandleDown(e, i)}
|
|
135
|
+
onpointermove={onHandleMove}
|
|
136
|
+
onpointerup={onHandleUp}
|
|
137
|
+
onpointercancel={onHandleUp}
|
|
133
138
|
title="Stop {i} ({positions[i - 1]}%)"
|
|
134
139
|
aria-label="Gradient stop {i}"
|
|
135
140
|
>
|
|
@@ -148,7 +153,7 @@
|
|
|
148
153
|
max="100"
|
|
149
154
|
step="0.1"
|
|
150
155
|
value={positions[selected - 1]}
|
|
151
|
-
|
|
156
|
+
onchange={(e) => onPositionInput(selected, e)}
|
|
152
157
|
/>
|
|
153
158
|
<span class="suffix">%</span>
|
|
154
159
|
</label>
|
|
@@ -156,7 +161,7 @@
|
|
|
156
161
|
<UIPaletteSelector variable={stopColorVar(selected)} {component} />
|
|
157
162
|
</div>
|
|
158
163
|
<div class="angle-slot">
|
|
159
|
-
<AngleDial value={angleDeg}
|
|
164
|
+
<AngleDial value={angleDeg} onchange={(d) => setAngle(d.value)} />
|
|
160
165
|
</div>
|
|
161
166
|
</div>
|
|
162
167
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script
|
|
1
|
+
<script module lang="ts">
|
|
2
2
|
type CellStatus = 'linked' | 'broken' | 'absent';
|
|
3
3
|
type RowEntry = { label: string; key: string };
|
|
4
4
|
type Axes =
|
|
@@ -34,37 +34,46 @@
|
|
|
34
34
|
</script>
|
|
35
35
|
|
|
36
36
|
<script lang="ts">
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
/** Caption rendered above the grid. Use to describe the linkage scope
|
|
37
|
+
interface Props {
|
|
38
|
+
contexts?: string[];
|
|
39
|
+
broken?: string[];
|
|
40
|
+
singleAxisLabel?: string;
|
|
41
|
+
/** Caption rendered above the grid. Use to describe the linkage scope
|
|
43
42
|
(e.g. "Links across variants and states"). Defaults to the legacy
|
|
44
43
|
"Linked Properties" label so consumers that don't pass a caption
|
|
45
44
|
keep their existing rendering. */
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
caption?: string;
|
|
46
|
+
/** Currently focused variant (matches a row in 2d / a row label in 1d). When set,
|
|
48
47
|
the matching row is highlighted with the same active style as the variant tab strip. */
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
selectedRow?: string | null;
|
|
49
|
+
/** Currently focused state (matches a column in 2d). The cell at (selectedRow, selectedCol)
|
|
51
50
|
gets an additional accent. Ignored in 1d charts. */
|
|
52
|
-
|
|
51
|
+
selectedCol?: string | null;
|
|
52
|
+
onselect?: (label: string) => void;
|
|
53
|
+
}
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
let {
|
|
56
|
+
contexts = [],
|
|
57
|
+
broken = [],
|
|
58
|
+
singleAxisLabel = '',
|
|
59
|
+
caption = 'Linked Properties',
|
|
60
|
+
selectedRow = null,
|
|
61
|
+
selectedCol = null,
|
|
62
|
+
onselect
|
|
63
|
+
}: Props = $props();
|
|
55
64
|
|
|
56
|
-
|
|
57
|
-
|
|
65
|
+
let axes = $derived(deriveAxes(contexts));
|
|
66
|
+
let status = $derived((() => {
|
|
58
67
|
const brokenSet = new Set(broken);
|
|
59
68
|
const m = new Map<string, CellStatus>();
|
|
60
69
|
for (const c of contexts) m.set(c, brokenSet.has(c) ? 'broken' : 'linked');
|
|
61
70
|
return m;
|
|
62
|
-
})();
|
|
71
|
+
})());
|
|
63
72
|
|
|
64
|
-
let hoveredRow: number = -1;
|
|
73
|
+
let hoveredRow: number = $state(-1);
|
|
65
74
|
|
|
66
75
|
function key2d(r: string, c: string): string { return `${r} ${c}`; }
|
|
67
|
-
function selectRow(label: string) {
|
|
76
|
+
function selectRow(label: string) { onselect?.(label); }
|
|
68
77
|
/** True when this 1d row's key matches focus — either as a bare label
|
|
69
78
|
(`"primary"` matches focusedVariant `"primary"`) or as a compound
|
|
70
79
|
`"variant state"` matching the focused pair. */
|
|
@@ -92,11 +101,11 @@
|
|
|
92
101
|
class="row-h row-target"
|
|
93
102
|
class:hovered={hoveredRow === i}
|
|
94
103
|
class:selected={selectedRow === r}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
104
|
+
onclick={() => selectRow(r)}
|
|
105
|
+
onmouseenter={() => (hoveredRow = i)}
|
|
106
|
+
onmouseleave={() => (hoveredRow = -1)}
|
|
107
|
+
onfocus={() => (hoveredRow = i)}
|
|
108
|
+
onblur={() => (hoveredRow = -1)}
|
|
100
109
|
>{r}</button>
|
|
101
110
|
{#each axes.cols as c (c)}
|
|
102
111
|
{@const st = status.get(key2d(r, c)) ?? 'absent'}
|
|
@@ -108,9 +117,9 @@
|
|
|
108
117
|
class:selected={selectedRow === r && selectedCol === c}
|
|
109
118
|
class:in-selected-row={selectedRow === r && selectedCol !== c}
|
|
110
119
|
aria-label="{r} {c}: {st}"
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
onclick={() => selectRow(r)}
|
|
121
|
+
onmouseenter={() => (hoveredRow = i)}
|
|
122
|
+
onmouseleave={() => (hoveredRow = -1)}
|
|
114
123
|
>
|
|
115
124
|
{#if st === 'linked'}
|
|
116
125
|
<span class="dot" aria-hidden="true"></span>
|
|
@@ -138,11 +147,11 @@
|
|
|
138
147
|
class="row-h row-target"
|
|
139
148
|
class:hovered={hoveredRow === i}
|
|
140
149
|
class:selected={isSel}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
150
|
+
onclick={() => selectRow(r.label)}
|
|
151
|
+
onmouseenter={() => (hoveredRow = i)}
|
|
152
|
+
onmouseleave={() => (hoveredRow = -1)}
|
|
153
|
+
onfocus={() => (hoveredRow = i)}
|
|
154
|
+
onblur={() => (hoveredRow = -1)}
|
|
146
155
|
>{r.label}</button>
|
|
147
156
|
<button
|
|
148
157
|
type="button"
|
|
@@ -151,9 +160,9 @@
|
|
|
151
160
|
class:hovered={hoveredRow === i}
|
|
152
161
|
class:selected={isSel}
|
|
153
162
|
aria-label="{r.label}: {st}"
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
163
|
+
onclick={() => selectRow(r.label)}
|
|
164
|
+
onmouseenter={() => (hoveredRow = i)}
|
|
165
|
+
onmouseleave={() => (hoveredRow = -1)}
|
|
157
166
|
>
|
|
158
167
|
{#if st === 'linked'}
|
|
159
168
|
<span class="dot" aria-hidden="true"></span>
|
|
@@ -13,8 +13,12 @@
|
|
|
13
13
|
const fadeDur = reduceMotion ? 0 : 140;
|
|
14
14
|
const slideDur = reduceMotion ? 0 : 200;
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
interface Props {
|
|
17
|
+
component: string;
|
|
18
|
+
linked: LinkedBlockResult;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let { component, linked }: Props = $props();
|
|
18
22
|
|
|
19
23
|
const editorCtx = getEditorContext();
|
|
20
24
|
const focusedVariant = editorCtx?.focusedVariant;
|
|
@@ -25,9 +29,9 @@
|
|
|
25
29
|
doesn't know if its rows are variants (top-level tab strip) or states (per-VariantGroup
|
|
26
30
|
state tabs), so we set both stores; each consumer adopts the value only if it names
|
|
27
31
|
one of its own tabs. */
|
|
28
|
-
function handleChartSelect(
|
|
29
|
-
editorCtx?.focusedVariant.set(
|
|
30
|
-
editorCtx?.focusedState.set(
|
|
32
|
+
function handleChartSelect(label: string) {
|
|
33
|
+
editorCtx?.focusedVariant.set(label);
|
|
34
|
+
editorCtx?.focusedState.set(label);
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
/** Pick the sibling that backs the cell the user is currently focused on, so the row
|
|
@@ -71,35 +75,35 @@
|
|
|
71
75
|
return `${brokenContexts.length} unlinked`;
|
|
72
76
|
}
|
|
73
77
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
78
|
+
let focusedV = $derived((focusedVariant ? $focusedVariant : null) ?? null);
|
|
79
|
+
let focusedS = $derived((focusedState ? $focusedState : null) ?? null);
|
|
80
|
+
let hoveredVar = $derived((hoveredLinkedVariable ? $hoveredLinkedVariable : null) ?? null);
|
|
77
81
|
|
|
78
82
|
function setHover(variable: string | null) {
|
|
79
83
|
hoveredLinkedVariable?.set(variable);
|
|
80
84
|
}
|
|
81
85
|
|
|
82
86
|
/** One card per LinkedGroup. Stable order = editor-declared order. */
|
|
83
|
-
|
|
87
|
+
let cards = $derived(linked.groups.map((g) => ({
|
|
84
88
|
contexts: g.contexts,
|
|
85
89
|
brokenContexts: g.brokenContexts,
|
|
86
90
|
row: { ...g.token, variable: pickFocusedVariable(g, focusedV, focusedS) },
|
|
87
91
|
caption: captionFor(g.contexts),
|
|
88
92
|
unlinkedText: formatUnlinked(g.brokenContexts),
|
|
89
93
|
isBroken: g.brokenContexts.length > 0,
|
|
90
|
-
}));
|
|
94
|
+
})));
|
|
91
95
|
|
|
92
96
|
/** Section-level summary: count of properties with any broken peers. The
|
|
93
97
|
header tells the user *whether to look*; the per-card text tells them
|
|
94
98
|
*what's broken*. Two layers, two granularities. */
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
let brokenPropertyCount = $derived(cards.filter((c) => c.isBroken).length);
|
|
100
|
+
let hasAnyBroken = $derived(brokenPropertyCount > 0);
|
|
97
101
|
|
|
98
102
|
/** Default closed; the section header's summary count + "in sync / N unlinked"
|
|
99
103
|
text is the at-a-glance signal, so users opt into the matrix only when
|
|
100
104
|
they need it. */
|
|
101
|
-
let sectionToggleOverride: boolean | null = null;
|
|
102
|
-
|
|
105
|
+
let sectionToggleOverride: boolean | null = $state(null);
|
|
106
|
+
let sectionExpanded = $derived(sectionToggleOverride ?? false);
|
|
103
107
|
function toggleSection() {
|
|
104
108
|
sectionToggleOverride = !sectionExpanded;
|
|
105
109
|
}
|
|
@@ -107,7 +111,7 @@
|
|
|
107
111
|
/** Per-card chart expand state, keyed by the card's row variable (which is
|
|
108
112
|
stable per LinkedGroup since pickFocusedVariable runs against the same
|
|
109
113
|
group on every render). */
|
|
110
|
-
let expandedCards: Record<string, boolean> = {};
|
|
114
|
+
let expandedCards: Record<string, boolean> = $state({});
|
|
111
115
|
function toggleCard(variable: string) {
|
|
112
116
|
expandedCards = { ...expandedCards, [variable]: !expandedCards[variable] };
|
|
113
117
|
}
|
|
@@ -120,7 +124,7 @@
|
|
|
120
124
|
class="section-header"
|
|
121
125
|
class:expanded={sectionExpanded}
|
|
122
126
|
aria-expanded={sectionExpanded}
|
|
123
|
-
|
|
127
|
+
onclick={toggleSection}
|
|
124
128
|
>
|
|
125
129
|
<i class="fas fa-chevron-right chevron"></i>
|
|
126
130
|
<span class="section-title">Linked properties</span>
|
|
@@ -144,8 +148,8 @@
|
|
|
144
148
|
class="linked-card"
|
|
145
149
|
class:broken={card.isBroken}
|
|
146
150
|
class:hovered={cardHovered}
|
|
147
|
-
|
|
148
|
-
|
|
151
|
+
onmouseenter={() => setHover(card.row.variable)}
|
|
152
|
+
onmouseleave={() => setHover(null)}
|
|
149
153
|
>
|
|
150
154
|
<h4 class="property-name">{card.row.label}</h4>
|
|
151
155
|
<div class="control-row">
|
|
@@ -154,7 +158,6 @@
|
|
|
154
158
|
{component}
|
|
155
159
|
linkedOrder={linked.linkedOrder}
|
|
156
160
|
isLinkedBlock
|
|
157
|
-
on:change
|
|
158
161
|
/>
|
|
159
162
|
</div>
|
|
160
163
|
<button
|
|
@@ -162,7 +165,7 @@
|
|
|
162
165
|
class="drill-down"
|
|
163
166
|
class:expanded={cardExpanded}
|
|
164
167
|
aria-expanded={cardExpanded}
|
|
165
|
-
|
|
168
|
+
onclick={() => toggleCard(card.row.variable)}
|
|
166
169
|
>
|
|
167
170
|
<i class="fas fa-chevron-right chevron"></i>
|
|
168
171
|
<span class="drill-label">Links</span>
|
|
@@ -181,7 +184,7 @@
|
|
|
181
184
|
caption={card.caption}
|
|
182
185
|
selectedRow={focusedV}
|
|
183
186
|
selectedCol={focusedS}
|
|
184
|
-
|
|
187
|
+
onselect={handleChartSelect}
|
|
185
188
|
/>
|
|
186
189
|
</div>
|
|
187
190
|
{/if}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
children?: import('svelte').Snippet;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
let { children }: Props = $props();
|
|
2
7
|
/** Section that gathers render-time toggles a component accepts as props
|
|
3
8
|
(e.g. dismissible, action buttons, hover shimmer, show icons). */
|
|
4
9
|
</script>
|
|
@@ -9,7 +14,7 @@
|
|
|
9
14
|
<p class="config-description">Component accepts multiple properties that can change its layout. Use these to preview.</p>
|
|
10
15
|
</header>
|
|
11
16
|
<div class="config-controls">
|
|
12
|
-
|
|
17
|
+
{@render children?.()}
|
|
13
18
|
</div>
|
|
14
19
|
</section>
|
|
15
20
|
|