@weasel-js/labkit 1.2.0 → 1.3.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/dist/_dts/{DrawCommand-C_XboUpz.d.ts → DrawCommand-DBB45NfN.d.ts} +196 -52
- package/dist/_dts/PrefsForm-BYa6cWnO.d.ts +201 -0
- package/dist/_dts/types-1Sdxy_Pv.d.ts +90 -0
- package/dist/_dts/types-BttTIent.d.ts +314 -0
- package/dist/_dts/types-DCGEcMO_.d.ts +162 -0
- package/dist/_dts/{useTrialState-BMNIx3Cy.d.ts → useTrialState-CsGMjhu9.d.ts} +5 -87
- package/dist/canvas/index.d.ts +7 -3
- package/dist/canvas/index.js +3 -1
- package/dist/chrome/index.d.ts +86 -0
- package/dist/chrome/index.js +9 -0
- package/dist/chrome/index.js.map +1 -0
- package/dist/chunk-3XXPU73K.js +138 -0
- package/dist/chunk-3XXPU73K.js.map +1 -0
- package/dist/{chunk-VUU5UXHE.js → chunk-4TMMVIDM.js} +8 -5
- package/dist/chunk-4TMMVIDM.js.map +1 -0
- package/dist/chunk-6X5RBC6G.js +366 -0
- package/dist/chunk-6X5RBC6G.js.map +1 -0
- package/dist/{chunk-574LJAV4.js → chunk-BDJXIBRZ.js} +33 -35
- package/dist/chunk-BDJXIBRZ.js.map +1 -0
- package/dist/{chunk-SFL7NFKN.js → chunk-BMW4TDP5.js} +15 -7
- package/dist/chunk-BMW4TDP5.js.map +1 -0
- package/dist/chunk-JDROYQM3.js +266 -0
- package/dist/chunk-JDROYQM3.js.map +1 -0
- package/dist/{chunk-THBG7FQZ.js → chunk-LGKRIUSW.js} +15 -12
- package/dist/chunk-LGKRIUSW.js.map +1 -0
- package/dist/{chunk-BOHF3PQO.js → chunk-QCICIHEO.js} +8129 -5196
- package/dist/chunk-QCICIHEO.js.map +1 -0
- package/dist/chunk-QRYPXSGP.js +212 -0
- package/dist/chunk-QRYPXSGP.js.map +1 -0
- package/dist/chunk-RGT4EJIB.js +6961 -0
- package/dist/chunk-RGT4EJIB.js.map +1 -0
- package/dist/chunk-SBXNQW4G.js +3 -0
- package/dist/chunk-SBXNQW4G.js.map +1 -0
- package/dist/chunk-T66HU3HX.js +17 -0
- package/dist/chunk-T66HU3HX.js.map +1 -0
- package/dist/chunk-WTI26YTM.js +266 -0
- package/dist/chunk-WTI26YTM.js.map +1 -0
- package/dist/controls/index.d.ts +19 -5
- package/dist/controls/index.js +3 -1
- package/dist/dragdrop/index.d.ts +46 -3
- package/dist/dragdrop/index.js +3 -1
- package/dist/index.d.ts +735 -565
- package/dist/index.js +661 -1019
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +5 -3
- package/dist/layers/index.js +4 -1
- package/dist/passthrough/weasel-canvas.d.ts +69 -13
- package/dist/passthrough/weasel-canvas.js +1 -1
- package/dist/passthrough/weasel-ui.d.ts +3811 -3671
- package/dist/passthrough/weasel-ui.js +3 -2
- package/dist/primitives/index.d.ts +102 -8
- package/dist/primitives/index.js +5 -1
- package/dist/state/index.d.ts +3 -2
- package/dist/state/index.js +2 -2
- package/dist/styles.css +490 -803
- package/dist/surface/index.js +2 -1
- package/dist/ui/layers/index.d.ts +8 -2
- package/dist/ui/layers/index.js +2 -3
- package/dist/undo/index.d.ts +4 -2
- package/package.json +16 -7
- package/src/canvas/AGENTS.md +4 -0
- package/src/canvas/CanvasStack.tsx +6 -2
- package/src/canvas/useLayerScheduler.ts +22 -15
- package/src/canvas/usePanZoom.test.ts +80 -0
- package/src/canvas/usePanZoom.ts +16 -2
- package/src/chrome/ChromeRegions.stories.tsx +106 -0
- package/src/chrome/builtins.test.ts +153 -0
- package/src/chrome/builtins.tsx +205 -0
- package/src/chrome/index.ts +25 -0
- package/src/chrome/merge.test.ts +51 -0
- package/src/chrome/merge.ts +52 -0
- package/src/chrome/regions/PaletteRegion.less +14 -0
- package/src/chrome/regions/PaletteRegion.test.tsx +36 -0
- package/src/chrome/regions/PaletteRegion.tsx +41 -0
- package/src/chrome/regions/SidebarRegion.tsx +56 -0
- package/src/chrome/regions/StatusRegion.tsx +31 -0
- package/src/chrome/regions/TitleBarRegion.tsx +41 -0
- package/src/chrome/regions/ToolbarRegion.test.tsx +82 -0
- package/src/chrome/regions/ToolbarRegion.tsx +71 -0
- package/src/chrome/regions/ViewportRegion.less +42 -0
- package/src/chrome/regions/ViewportRegion.tsx +37 -0
- package/src/chrome/regions/regions.test.tsx +81 -0
- package/src/chrome/types.ts +127 -0
- package/src/config/builder.test.ts +93 -0
- package/src/config/builder.ts +220 -0
- package/src/config/fromConfigField.test.ts +93 -0
- package/src/config/fromConfigField.ts +74 -0
- package/src/config/index.ts +22 -0
- package/src/config/resolve.test.ts +119 -0
- package/src/config/resolve.ts +67 -0
- package/src/config/rules.ts +68 -0
- package/src/config/types.ts +108 -0
- package/src/config/useConfigSchema.ts +30 -0
- package/src/config/visible.ts +20 -0
- package/src/controls/ControlPanel.less +4 -58
- package/src/controls/ControlPanel.stories.tsx +125 -0
- package/src/controls/ControlPanel.test.tsx +245 -10
- package/src/controls/ControlPanel.tsx +236 -203
- package/src/dragdrop/DragDropRuntime.tsx +36 -18
- package/src/dragdrop/DragGhost.less +1 -1
- package/src/dragdrop/Palette.less +1 -1
- package/src/dragdrop/index.ts +11 -0
- package/src/index.ts +74 -5
- package/src/instrument/SineWave.smoke.test.tsx +8 -1
- package/src/instrument/defineInstrument.test.ts +38 -1
- package/src/instrument/defineInstrument.ts +31 -4
- package/src/instrument/index.ts +1 -0
- package/src/instrument/types.ts +27 -4
- package/src/instrument/validateConfigSchema.test.ts +13 -3
- package/src/instrument/validateConfigSchema.ts +7 -10
- package/src/lab/Lab.chrome.test.tsx +65 -0
- package/src/lab/Lab.tsx +58 -15
- package/src/lab/LabContext.ts +6 -0
- package/src/lab/LabFullChrome.stories.tsx +308 -0
- package/src/lab/LabHeader.test.tsx +42 -0
- package/src/lab/LabHeader.tsx +57 -0
- package/src/lab/LabPalette.test.tsx +35 -0
- package/src/lab/LabPalette.tsx +34 -0
- package/src/lab/LabShell.less +50 -3
- package/src/lab/Workspace.less +1 -30
- package/src/lab/Workspace.test.tsx +20 -10
- package/src/lab/Workspace.tsx +5 -8
- package/src/lab/index.ts +3 -1
- package/src/layers/AGENTS.md +1 -1
- package/src/layers/LayerList.less +31 -7
- package/src/layers/LayerList.tsx +17 -4
- package/src/passthrough/weasel-ui.ts +28 -0
- package/src/primitives/FloatingPanel.less +28 -0
- package/src/primitives/FloatingPanel.stories.tsx +46 -0
- package/src/primitives/FloatingPanel.test.tsx +240 -0
- package/src/primitives/FloatingPanel.tsx +190 -0
- package/src/primitives/FpsMeter.test.tsx +44 -0
- package/src/primitives/FpsMeter.tsx +20 -9
- package/src/primitives/JobProgress.less +69 -0
- package/src/primitives/JobProgress.stories.tsx +48 -0
- package/src/primitives/JobProgress.tsx +65 -0
- package/src/primitives/Legend.less +47 -0
- package/src/primitives/Legend.stories.tsx +32 -0
- package/src/primitives/Legend.test.tsx +57 -0
- package/src/primitives/Legend.tsx +40 -0
- package/src/primitives/Sidebar.less +32 -2
- package/src/primitives/StatusBar.less +7 -0
- package/src/primitives/StatusBar.tsx +10 -3
- package/src/primitives/Toolbar.less +50 -3
- package/src/primitives/Toolbar.test.tsx +67 -1
- package/src/primitives/Toolbar.tsx +72 -6
- package/src/primitives/ZoomControl.less +31 -0
- package/src/primitives/ZoomControl.tsx +76 -0
- package/src/primitives/floating.entry.test.tsx +14 -0
- package/src/primitives/index.ts +10 -2
- package/src/primitives/useRovingTabIndex.test.ts +27 -0
- package/src/primitives/useRovingTabIndex.ts +79 -0
- package/src/state/store.ts +11 -3
- package/src/state/toolSlot.test.ts +36 -0
- package/src/state/types.ts +4 -0
- package/src/styles.less +6 -4
- package/src/surface/useTiledSurface.ts +14 -10
- package/src/test-setup.ts +26 -0
- package/src/theme/Interstellar.stories.tsx +1 -1
- package/src/theme/base.less +19 -2
- package/src/theme/interstellar.tokens.json +6 -2
- package/src/tools/types.ts +24 -0
- package/src/trial/Trial.config.test.tsx +108 -0
- package/src/trial/Trial.job.test.tsx +13 -15
- package/src/trial/Trial.less +115 -10
- package/src/trial/Trial.stories.tsx +1 -0
- package/src/trial/Trial.test.tsx +67 -96
- package/src/trial/Trial.tsx +80 -39
- package/src/trial/TrialChrome.tsx +99 -80
- package/src/trial/TrialDragContext.ts +10 -0
- package/src/trial/TrialTitleBar.tsx +41 -0
- package/src/trial/index.ts +1 -15
- package/src/trial/trialChrome.borders.test.ts +38 -0
- package/src/ui/layers/index.ts +5 -1
- package/dist/_dts/index-JFAYj5Tv.d.ts +0 -144
- package/dist/_dts/types-x92Kfeme.d.ts +0 -62
- package/dist/chunk-574LJAV4.js.map +0 -1
- package/dist/chunk-5R2ATYPJ.js +0 -201
- package/dist/chunk-5R2ATYPJ.js.map +0 -1
- package/dist/chunk-73KA7WBO.js +0 -5992
- package/dist/chunk-73KA7WBO.js.map +0 -1
- package/dist/chunk-BOHF3PQO.js.map +0 -1
- package/dist/chunk-G5TJVQQT.js +0 -161
- package/dist/chunk-G5TJVQQT.js.map +0 -1
- package/dist/chunk-PMAU3SEE.js +0 -126
- package/dist/chunk-PMAU3SEE.js.map +0 -1
- package/dist/chunk-SFL7NFKN.js.map +0 -1
- package/dist/chunk-THBG7FQZ.js.map +0 -1
- package/dist/chunk-VUU5UXHE.js.map +0 -1
- package/src/instrument/capabilityDetector.test.ts +0 -64
- package/src/instrument/capabilityDetector.ts +0 -20
- package/src/trial/DefaultSidebar.tsx +0 -29
- package/src/trial/DefaultStatusBar.tsx +0 -19
- package/src/trial/DefaultToolbar.tsx +0 -92
- package/src/trial/slotTypes.ts +0 -54
- package/src/ui/format.test.ts +0 -33
- package/src/ui/format.ts +0 -30
- package/src/ui/layers/LayerStack.less +0 -143
- package/src/ui/layers/LayerStack.stories.tsx +0 -45
- package/src/ui/layers/LayerStack.test.tsx +0 -170
- package/src/ui/layers/LayerStack.tsx +0 -220
- package/src/ui/properties/CheckboxRow.stories.tsx +0 -27
- package/src/ui/properties/ColorRow.stories.tsx +0 -106
- package/src/ui/properties/CurveField.less +0 -48
- package/src/ui/properties/CurveField.stories.tsx +0 -20
- package/src/ui/properties/CurveField.test.tsx +0 -127
- package/src/ui/properties/CurveField.tsx +0 -184
- package/src/ui/properties/EffectCard.tsx +0 -324
- package/src/ui/properties/Gallery.stories.tsx +0 -178
- package/src/ui/properties/NumberRow.stories.tsx +0 -65
- package/src/ui/properties/PropertyGroup.less +0 -50
- package/src/ui/properties/PropertyGroup.stories.tsx +0 -34
- package/src/ui/properties/PropertyGroup.test.tsx +0 -33
- package/src/ui/properties/PropertyGroup.tsx +0 -45
- package/src/ui/properties/PropertyList.stories.tsx +0 -83
- package/src/ui/properties/PropertyPanel.less +0 -592
- package/src/ui/properties/PropertyPanel.stories.tsx +0 -190
- package/src/ui/properties/PropertyPanel.test.tsx +0 -193
- package/src/ui/properties/PropertyPanel.tsx +0 -469
- package/src/ui/properties/PropertyRow.stories.tsx +0 -53
- package/src/ui/properties/SelectRow.stories.tsx +0 -58
- package/src/ui/properties/SliderRow.stories.tsx +0 -74
- package/src/ui/properties/SpeechBalloonPanels.stories.tsx +0 -396
- package/src/ui/properties/TextRow.stories.tsx +0 -62
- package/src/ui/properties/ToggleRow.stories.tsx +0 -57
- package/src/ui/properties/index.ts +0 -39
- package/src/ui/properties/storyLayouts.tsx +0 -36
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
CheckboxRow,
|
|
5
|
-
ColorRow,
|
|
6
|
-
NumberRow,
|
|
7
|
-
PropertyList,
|
|
8
|
-
type PropertyListPack,
|
|
9
|
-
PropertyPanel,
|
|
10
|
-
PropertyRow,
|
|
11
|
-
SelectRow,
|
|
12
|
-
SliderRow,
|
|
13
|
-
TextRow,
|
|
14
|
-
ToggleRow,
|
|
15
|
-
} from './PropertyPanel';
|
|
16
|
-
|
|
17
|
-
// Args common to most stories — exposed as Storybook controls so the
|
|
18
|
-
// title, pack mode, and container width can be tweaked live.
|
|
19
|
-
interface DemoArgs {
|
|
20
|
-
title: string;
|
|
21
|
-
pack: PropertyListPack;
|
|
22
|
-
width: number;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const meta: Meta<DemoArgs> = {
|
|
26
|
-
title: 'labkit/UI/Properties/PropertyPanel',
|
|
27
|
-
argTypes: {
|
|
28
|
-
title: { control: 'text' },
|
|
29
|
-
pack: {
|
|
30
|
-
control: 'inline-radio',
|
|
31
|
-
options: ['auto-color', 'pairs'] satisfies PropertyListPack[],
|
|
32
|
-
description:
|
|
33
|
-
"PropertyList packing. 'auto-color' (default) spans non-color rows full-width; 'pairs' packs every row two-per-row.",
|
|
34
|
-
},
|
|
35
|
-
width: { control: { type: 'number', min: 200, max: 600, step: 10 } },
|
|
36
|
-
},
|
|
37
|
-
args: {
|
|
38
|
-
title: 'Shape',
|
|
39
|
-
pack: 'auto-color',
|
|
40
|
-
width: 320,
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
export default meta;
|
|
44
|
-
|
|
45
|
-
type Story = StoryObj<DemoArgs>;
|
|
46
|
-
|
|
47
|
-
function Demo({ title, pack, width }: DemoArgs) {
|
|
48
|
-
const [opacity, setOpacity] = useState(0.65);
|
|
49
|
-
const [radius, setRadius] = useState(12);
|
|
50
|
-
const [fill, setFill] = useState('#b08adb');
|
|
51
|
-
const [stroke, setStroke] = useState('#1a1428');
|
|
52
|
-
const [label, setLabel] = useState('Untitled');
|
|
53
|
-
const [visible, setVisible] = useState(true);
|
|
54
|
-
|
|
55
|
-
return (
|
|
56
|
-
<div style={{ width }}>
|
|
57
|
-
<PropertyPanel title={title}>
|
|
58
|
-
<PropertyList pack={pack}>
|
|
59
|
-
<SliderRow
|
|
60
|
-
label="Opacity"
|
|
61
|
-
value={opacity}
|
|
62
|
-
min={0}
|
|
63
|
-
max={1}
|
|
64
|
-
step={0.01}
|
|
65
|
-
onChange={setOpacity}
|
|
66
|
-
format={(v) => v.toFixed(2)}
|
|
67
|
-
/>
|
|
68
|
-
<SliderRow
|
|
69
|
-
label="Radius"
|
|
70
|
-
value={radius}
|
|
71
|
-
min={0}
|
|
72
|
-
max={64}
|
|
73
|
-
step={1}
|
|
74
|
-
onChange={setRadius}
|
|
75
|
-
unit="px"
|
|
76
|
-
/>
|
|
77
|
-
<ColorRow label="Fill" value={fill} onChange={setFill} />
|
|
78
|
-
<ColorRow label="Stroke" value={stroke} onChange={setStroke} />
|
|
79
|
-
<TextRow label="Label" value={label} onChange={setLabel} />
|
|
80
|
-
<CheckboxRow label="Visible" value={visible} onChange={setVisible} />
|
|
81
|
-
</PropertyList>
|
|
82
|
-
</PropertyPanel>
|
|
83
|
-
</div>
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export const Default: Story = {
|
|
88
|
-
render: (args) => <Demo {...args} />,
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
export const NoTitle: Story = {
|
|
92
|
-
args: { title: '' },
|
|
93
|
-
render: ({ title, width }) => (
|
|
94
|
-
<div style={{ width }}>
|
|
95
|
-
<PropertyPanel title={title || undefined}>
|
|
96
|
-
<PropertyList>
|
|
97
|
-
<SliderRow label="Just a slider" value={50} min={0} max={100} onChange={() => {}} />
|
|
98
|
-
</PropertyList>
|
|
99
|
-
</PropertyPanel>
|
|
100
|
-
</div>
|
|
101
|
-
),
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
function AllRowsDemo({ title, pack, width }: DemoArgs) {
|
|
105
|
-
const [opacity, setOpacity] = useState(0.65);
|
|
106
|
-
const [count, setCount] = useState(8);
|
|
107
|
-
const [fill, setFill] = useState('#b08adb');
|
|
108
|
-
const [stroke, setStroke] = useState('#1a1428');
|
|
109
|
-
const [name, setName] = useState('Untitled');
|
|
110
|
-
const [visible, setVisible] = useState(true);
|
|
111
|
-
const [mode, setMode] = useState<'fill' | 'stroke' | 'both'>('both');
|
|
112
|
-
const [align, setAlign] = useState<'left' | 'center' | 'right'>('center');
|
|
113
|
-
|
|
114
|
-
return (
|
|
115
|
-
<div style={{ width }}>
|
|
116
|
-
<PropertyPanel title={title}>
|
|
117
|
-
<PropertyList pack={pack}>
|
|
118
|
-
<SliderRow
|
|
119
|
-
label="Opacity"
|
|
120
|
-
value={opacity}
|
|
121
|
-
min={0}
|
|
122
|
-
max={1}
|
|
123
|
-
step={0.01}
|
|
124
|
-
onChange={setOpacity}
|
|
125
|
-
format={(v) => v.toFixed(2)}
|
|
126
|
-
/>
|
|
127
|
-
<NumberRow label="Count" value={count} onChange={setCount} min={0} max={100} step={1} />
|
|
128
|
-
<ColorRow label="Fill" value={fill} onChange={setFill} />
|
|
129
|
-
<ColorRow label="Stroke" value={stroke} onChange={setStroke} />
|
|
130
|
-
<TextRow label="Name" value={name} onChange={setName} />
|
|
131
|
-
<SelectRow
|
|
132
|
-
label="Mode"
|
|
133
|
-
value={mode}
|
|
134
|
-
onChange={setMode}
|
|
135
|
-
options={[
|
|
136
|
-
{ value: 'fill', label: 'Fill only' },
|
|
137
|
-
{ value: 'stroke', label: 'Stroke only' },
|
|
138
|
-
{ value: 'both', label: 'Fill + stroke' },
|
|
139
|
-
]}
|
|
140
|
-
/>
|
|
141
|
-
<ToggleRow
|
|
142
|
-
label="Align"
|
|
143
|
-
value={align}
|
|
144
|
-
onChange={setAlign}
|
|
145
|
-
options={[
|
|
146
|
-
{ value: 'left', label: 'L' },
|
|
147
|
-
{ value: 'center', label: 'C' },
|
|
148
|
-
{ value: 'right', label: 'R' },
|
|
149
|
-
]}
|
|
150
|
-
/>
|
|
151
|
-
<CheckboxRow label="Visible" value={visible} onChange={setVisible} />
|
|
152
|
-
</PropertyList>
|
|
153
|
-
</PropertyPanel>
|
|
154
|
-
</div>
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export const AllRows: Story = {
|
|
159
|
-
args: { title: 'Everything' },
|
|
160
|
-
render: (args) => <AllRowsDemo {...args} />,
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
export const CustomPropertyRow: Story = {
|
|
164
|
-
args: { title: 'Custom row' },
|
|
165
|
-
render: ({ title, pack, width }) => (
|
|
166
|
-
<div style={{ width }}>
|
|
167
|
-
<PropertyPanel title={title}>
|
|
168
|
-
<PropertyList pack={pack}>
|
|
169
|
-
<PropertyRow label="Anything" readout="custom">
|
|
170
|
-
<button type="button">click me</button>
|
|
171
|
-
</PropertyRow>
|
|
172
|
-
</PropertyList>
|
|
173
|
-
</PropertyPanel>
|
|
174
|
-
</div>
|
|
175
|
-
),
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
export const ListWithoutChrome: Story = {
|
|
179
|
-
// No title — this story explicitly demonstrates rendering without the panel chrome.
|
|
180
|
-
argTypes: { title: { table: { disable: true } } },
|
|
181
|
-
render: ({ pack, width }) => (
|
|
182
|
-
<div style={{ width }}>
|
|
183
|
-
<PropertyList pack={pack}>
|
|
184
|
-
<SliderRow label="Bare" value={50} min={0} max={100} onChange={() => {}} />
|
|
185
|
-
<ColorRow label="Color A" value="#b08adb" onChange={() => {}} />
|
|
186
|
-
<ColorRow label="Color B" value="#1a1428" onChange={() => {}} />
|
|
187
|
-
</PropertyList>
|
|
188
|
-
</div>
|
|
189
|
-
),
|
|
190
|
-
};
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { fireEvent, render, screen } from '@testing-library/react';
|
|
2
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import {
|
|
4
|
-
CheckboxRow,
|
|
5
|
-
ColorRow,
|
|
6
|
-
NumberRow,
|
|
7
|
-
PropertyList,
|
|
8
|
-
PropertyPanel,
|
|
9
|
-
PropertyRow,
|
|
10
|
-
SelectRow,
|
|
11
|
-
SliderRow,
|
|
12
|
-
TextRow,
|
|
13
|
-
ToggleRow,
|
|
14
|
-
} from './PropertyPanel';
|
|
15
|
-
|
|
16
|
-
describe('PropertyPanel', () => {
|
|
17
|
-
it('renders title and children', () => {
|
|
18
|
-
render(
|
|
19
|
-
<PropertyPanel title="Shape">
|
|
20
|
-
<PropertyRow label="A">
|
|
21
|
-
<input type="text" defaultValue="x" />
|
|
22
|
-
</PropertyRow>
|
|
23
|
-
</PropertyPanel>,
|
|
24
|
-
);
|
|
25
|
-
expect(screen.getByRole('heading', { name: 'Shape' })).toBeInTheDocument();
|
|
26
|
-
expect(screen.getByText('A')).toBeInTheDocument();
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('omits the heading when no title is given', () => {
|
|
30
|
-
const { container } = render(
|
|
31
|
-
<PropertyPanel>
|
|
32
|
-
<PropertyRow label="A">
|
|
33
|
-
<input type="text" defaultValue="x" />
|
|
34
|
-
</PropertyRow>
|
|
35
|
-
</PropertyPanel>,
|
|
36
|
-
);
|
|
37
|
-
expect(container.querySelector('.lk-property-panel__title')).toBeNull();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('renders children directly (no implicit grid)', () => {
|
|
41
|
-
const { container } = render(
|
|
42
|
-
<PropertyPanel>
|
|
43
|
-
<span>raw child</span>
|
|
44
|
-
</PropertyPanel>,
|
|
45
|
-
);
|
|
46
|
-
expect(container.querySelector('.lk-property-list')).toBeNull();
|
|
47
|
-
expect(screen.getByText('raw child')).toBeInTheDocument();
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
describe('PropertyList', () => {
|
|
52
|
-
it('renders a grid container', () => {
|
|
53
|
-
const { container } = render(
|
|
54
|
-
<PropertyList>
|
|
55
|
-
<PropertyRow label="A">
|
|
56
|
-
<input type="text" defaultValue="x" />
|
|
57
|
-
</PropertyRow>
|
|
58
|
-
</PropertyList>,
|
|
59
|
-
);
|
|
60
|
-
expect(container.querySelector('.lk-property-list')).not.toBeNull();
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
describe('PropertyRow', () => {
|
|
65
|
-
it('renders label and optional readout', () => {
|
|
66
|
-
render(
|
|
67
|
-
<PropertyRow label="Opacity" readout="0.65">
|
|
68
|
-
<input type="range" defaultValue={50} />
|
|
69
|
-
</PropertyRow>,
|
|
70
|
-
);
|
|
71
|
-
expect(screen.getByText('Opacity')).toBeInTheDocument();
|
|
72
|
-
expect(screen.getByText('0.65')).toBeInTheDocument();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('applies variant class', () => {
|
|
76
|
-
const { container } = render(
|
|
77
|
-
<PropertyRow label="L" variant="color">
|
|
78
|
-
<input type="color" defaultValue="#fff" />
|
|
79
|
-
</PropertyRow>,
|
|
80
|
-
);
|
|
81
|
-
expect(container.querySelector('.lk-property-row--color')).not.toBeNull();
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
describe('SliderRow', () => {
|
|
86
|
-
it('emits numeric value on change', () => {
|
|
87
|
-
const onChange = vi.fn();
|
|
88
|
-
render(<SliderRow label="Op" value={10} min={0} max={100} onChange={onChange} />);
|
|
89
|
-
fireEvent.change(screen.getByRole('slider'), { target: { value: '42' } });
|
|
90
|
-
expect(onChange).toHaveBeenCalledWith(42);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('formats the readout when format is supplied', () => {
|
|
94
|
-
render(
|
|
95
|
-
<SliderRow
|
|
96
|
-
label="Op"
|
|
97
|
-
value={0.5}
|
|
98
|
-
min={0}
|
|
99
|
-
max={1}
|
|
100
|
-
step={0.01}
|
|
101
|
-
onChange={() => {}}
|
|
102
|
-
format={(v) => v.toFixed(2)}
|
|
103
|
-
/>,
|
|
104
|
-
);
|
|
105
|
-
expect(screen.getByDisplayValue('0.50')).toBeInTheDocument();
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
describe('ColorRow', () => {
|
|
110
|
-
it('emits the new hex on change', () => {
|
|
111
|
-
const onChange = vi.fn();
|
|
112
|
-
const { container } = render(<ColorRow label="Fill" value="#ffffff" onChange={onChange} />);
|
|
113
|
-
const input = container.querySelector('input[type="color"]') as HTMLInputElement;
|
|
114
|
-
fireEvent.change(input, { target: { value: '#aa3300' } });
|
|
115
|
-
expect(onChange).toHaveBeenCalledWith('#aa3300');
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
describe('CheckboxRow', () => {
|
|
120
|
-
it('toggles the boolean', () => {
|
|
121
|
-
const onChange = vi.fn();
|
|
122
|
-
render(<CheckboxRow label="Visible" value={false} onChange={onChange} />);
|
|
123
|
-
fireEvent.click(screen.getByRole('checkbox'));
|
|
124
|
-
expect(onChange).toHaveBeenCalledWith(true);
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
describe('TextRow', () => {
|
|
129
|
-
it('emits the new text on change', () => {
|
|
130
|
-
const onChange = vi.fn();
|
|
131
|
-
render(<TextRow label="Name" value="foo" onChange={onChange} />);
|
|
132
|
-
fireEvent.change(screen.getByDisplayValue('foo'), { target: { value: 'bar' } });
|
|
133
|
-
expect(onChange).toHaveBeenCalledWith('bar');
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
describe('NumberRow', () => {
|
|
138
|
-
it('emits a number on change', () => {
|
|
139
|
-
const onChange = vi.fn();
|
|
140
|
-
render(<NumberRow label="N" value={1} onChange={onChange} />);
|
|
141
|
-
fireEvent.change(screen.getByRole('spinbutton'), { target: { value: '42' } });
|
|
142
|
-
expect(onChange).toHaveBeenCalledWith(42);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('ignores non-finite values', () => {
|
|
146
|
-
const onChange = vi.fn();
|
|
147
|
-
render(<NumberRow label="N" value={1} onChange={onChange} />);
|
|
148
|
-
fireEvent.change(screen.getByRole('spinbutton'), { target: { value: 'abc' } });
|
|
149
|
-
expect(onChange).not.toHaveBeenCalled();
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
describe('SelectRow', () => {
|
|
154
|
-
it('emits the selected option', () => {
|
|
155
|
-
const onChange = vi.fn();
|
|
156
|
-
render(
|
|
157
|
-
<SelectRow
|
|
158
|
-
label="Mode"
|
|
159
|
-
value="a"
|
|
160
|
-
options={[
|
|
161
|
-
{ value: 'a', label: 'A' },
|
|
162
|
-
{ value: 'b', label: 'B' },
|
|
163
|
-
]}
|
|
164
|
-
onChange={onChange}
|
|
165
|
-
/>,
|
|
166
|
-
);
|
|
167
|
-
fireEvent.change(screen.getByRole('combobox'), { target: { value: 'b' } });
|
|
168
|
-
expect(onChange).toHaveBeenCalledWith('b');
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
describe('ToggleRow', () => {
|
|
173
|
-
it('marks the active option aria-pressed and emits on click', () => {
|
|
174
|
-
const onChange = vi.fn();
|
|
175
|
-
render(
|
|
176
|
-
<ToggleRow
|
|
177
|
-
label="Align"
|
|
178
|
-
value="left"
|
|
179
|
-
options={[
|
|
180
|
-
{ value: 'left', label: 'L' },
|
|
181
|
-
{ value: 'right', label: 'R' },
|
|
182
|
-
]}
|
|
183
|
-
onChange={onChange}
|
|
184
|
-
/>,
|
|
185
|
-
);
|
|
186
|
-
const left = screen.getByText('L');
|
|
187
|
-
const right = screen.getByText('R');
|
|
188
|
-
expect(left).toHaveAttribute('aria-pressed', 'true');
|
|
189
|
-
expect(right).toHaveAttribute('aria-pressed', 'false');
|
|
190
|
-
fireEvent.click(right);
|
|
191
|
-
expect(onChange).toHaveBeenCalledWith('right');
|
|
192
|
-
});
|
|
193
|
-
});
|