@weasel-js/labkit 1.3.0-pre.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/{index-DgcNdEdh.d.ts → types-BttTIent.d.ts} +2 -2
- package/dist/_dts/{types-AHlQxBNN.d.ts → types-DCGEcMO_.d.ts} +1 -1
- package/dist/canvas/index.d.ts +2 -2
- package/dist/canvas/index.js +3 -2
- package/dist/chrome/index.d.ts +3 -3
- package/dist/chrome/index.js +6 -5
- package/dist/chunk-3XXPU73K.js +138 -0
- package/dist/chunk-3XXPU73K.js.map +1 -0
- package/dist/{chunk-PO6L3NSH.js → chunk-6X5RBC6G.js} +17 -17
- package/dist/chunk-6X5RBC6G.js.map +1 -0
- package/dist/{chunk-NS54R52R.js → chunk-BDJXIBRZ.js} +5 -17
- package/dist/chunk-BDJXIBRZ.js.map +1 -0
- package/dist/{chunk-V7PRSIRQ.js → chunk-BMW4TDP5.js} +4 -4
- package/dist/chunk-BMW4TDP5.js.map +1 -0
- package/dist/{chunk-O7NVSCLN.js → chunk-JDROYQM3.js} +8 -8
- package/dist/chunk-JDROYQM3.js.map +1 -0
- package/dist/{chunk-HFDVGF4X.js → chunk-LGKRIUSW.js} +3 -3
- package/dist/{chunk-HFDVGF4X.js.map → chunk-LGKRIUSW.js.map} +1 -1
- package/dist/{chunk-Z6HJ5FEM.js → chunk-QCICIHEO.js} +19 -7
- package/dist/{chunk-Z6HJ5FEM.js.map → chunk-QCICIHEO.js.map} +1 -1
- package/dist/{chunk-RVNN4CHQ.js → chunk-QRYPXSGP.js} +5 -5
- package/dist/{chunk-RVNN4CHQ.js.map → chunk-QRYPXSGP.js.map} +1 -1
- 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 +2 -2
- package/dist/controls/index.js +3 -3
- package/dist/dragdrop/index.d.ts +44 -3
- package/dist/dragdrop/index.js +3 -1
- package/dist/index.d.ts +571 -541
- package/dist/index.js +69 -541
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +3 -3
- package/dist/layers/index.js +4 -2
- package/dist/passthrough/weasel-canvas.js +1 -1
- package/dist/passthrough/weasel-ui.d.ts +15 -2
- package/dist/passthrough/weasel-ui.js +3 -2
- package/dist/primitives/index.js +5 -4
- package/dist/styles.css +1 -703
- package/dist/surface/index.js +2 -2
- package/dist/ui/layers/index.d.ts +8 -2
- package/dist/ui/layers/index.js +2 -4
- package/dist/undo/index.d.ts +2 -2
- package/package.json +5 -5
- package/src/config/builder.test.ts +7 -1
- package/src/config/builder.ts +1 -5
- package/src/config/resolve.test.ts +1 -2
- package/src/controls/ControlPanel.stories.tsx +41 -2
- package/src/controls/ControlPanel.test.tsx +31 -9
- package/src/controls/ControlPanel.tsx +56 -22
- package/src/dragdrop/index.ts +11 -0
- package/src/index.ts +49 -2
- package/src/lab/index.ts +1 -1
- package/src/layers/AGENTS.md +1 -1
- package/src/layers/LayerList.tsx +1 -1
- package/src/passthrough/weasel-ui.ts +22 -17
- package/src/styles.less +0 -4
- package/src/theme/Interstellar.stories.tsx +1 -1
- package/src/trial/Trial.config.test.tsx +3 -8
- package/src/ui/layers/index.ts +5 -1
- package/dist/chunk-NS54R52R.js.map +0 -1
- package/dist/chunk-O2BULFHX.js +0 -152
- package/dist/chunk-O2BULFHX.js.map +0 -1
- package/dist/chunk-O7NVSCLN.js.map +0 -1
- package/dist/chunk-PO6L3NSH.js.map +0 -1
- package/dist/chunk-PQJ5B2U2.js +0 -27
- package/dist/chunk-PQJ5B2U2.js.map +0 -1
- package/dist/chunk-TLGRYALP.js +0 -6151
- package/dist/chunk-TLGRYALP.js.map +0 -1
- package/dist/chunk-V7PRSIRQ.js.map +0 -1
- package/dist/chunk-ZZAYVX4X.js +0 -505
- package/dist/chunk-ZZAYVX4X.js.map +0 -1
- package/src/primitives/DragHandleGlyph.tsx +0 -29
- 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 -208
- 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 -606
- 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 -398
- 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
package/dist/surface/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { SurfaceContext, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceOptional, useSurfaceTile, useTiledSurface } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
1
|
+
export { SurfaceContext, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceOptional, useSurfaceTile, useTiledSurface } from '../chunk-LGKRIUSW.js';
|
|
2
|
+
import '../chunk-QCICIHEO.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -14,7 +14,9 @@ interface LayerStackItem {
|
|
|
14
14
|
* can switch mode/shape without expanding. */
|
|
15
15
|
primaryValue?: string;
|
|
16
16
|
primaryOptions?: string[];
|
|
17
|
-
/** Accent CSS color used as the left border / index-badge fill.
|
|
17
|
+
/** Accent CSS color used as the left border / index-badge fill. Sets
|
|
18
|
+
* --wzl-layer-stack-accent on the card, which re-binds --wzl-accent
|
|
19
|
+
* for everything inside it. */
|
|
18
20
|
accent?: string;
|
|
19
21
|
/** Optional badge text rendered before the primary control
|
|
20
22
|
* (e.g. tail index "1", "2", "3"). When omitted a drag handle
|
|
@@ -38,10 +40,14 @@ interface LayerStackProps {
|
|
|
38
40
|
/** Hide the title + palette row (used when an outer wrap renders its
|
|
39
41
|
* own head — see speech-balloons Tails panel). */
|
|
40
42
|
hideHead?: boolean;
|
|
43
|
+
/** Appended to the root element's class list. The module's own class names
|
|
44
|
+
* are hashed, so this is the supported way to reach the stack from a
|
|
45
|
+
* consumer stylesheet. */
|
|
46
|
+
className?: string;
|
|
41
47
|
}
|
|
42
48
|
/** A drag-reorderable stack of expandable cards, with a palette in the header
|
|
43
49
|
* for adding more. The body of each card is the caller's to render. */
|
|
44
|
-
declare function LayerStack({ title, items, paletteKinds, onAdd, onRemove, onReorder, onPrimaryChange, renderBody, hideHead, }: LayerStackProps): react_jsx_runtime.JSX.Element;
|
|
50
|
+
declare function LayerStack({ className, title, items, paletteKinds, onAdd, onRemove, onReorder, onPrimaryChange, renderBody, hideHead, }: LayerStackProps): react_jsx_runtime.JSX.Element;
|
|
45
51
|
|
|
46
52
|
export { LayerStack };
|
|
47
53
|
export type { LayerStackItem, LayerStackProps };
|
package/dist/ui/layers/index.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
export { LayerStack } from '../../chunk-
|
|
2
|
-
import '../../chunk-
|
|
3
|
-
import '../../chunk-Z6HJ5FEM.js';
|
|
4
|
-
import '../../chunk-PQJ5B2U2.js';
|
|
1
|
+
export { c3 as LayerStack } from '../../chunk-RGT4EJIB.js';
|
|
2
|
+
import '../../chunk-QCICIHEO.js';
|
|
5
3
|
//# sourceMappingURL=index.js.map
|
|
6
4
|
//# sourceMappingURL=index.js.map
|
package/dist/undo/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { U as UndoCapability } from '../_dts/
|
|
1
|
+
export { U as UndoCapability } from '../_dts/types-BttTIent.js';
|
|
2
2
|
import 'react';
|
|
3
|
-
import '../_dts/types-
|
|
3
|
+
import '../_dts/types-DCGEcMO_.js';
|
|
4
4
|
import '../_dts/PrefsForm-BYa6cWnO.js';
|
|
5
5
|
import '../_dts/types-1Sdxy_Pv.js';
|
|
6
6
|
import '../_dts/types-DJ79Tg5J.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weasel-js/labkit",
|
|
3
|
-
"version": "1.3.0
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "React widgets for building self-contained interactive lab pages",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "orochi235",
|
|
@@ -109,9 +109,9 @@
|
|
|
109
109
|
"react-dom": "^19.0.0"
|
|
110
110
|
},
|
|
111
111
|
"dependencies": {
|
|
112
|
-
"@weasel-js/core": "1.3.0
|
|
113
|
-
"@weasel-js/theme": "1.3.0
|
|
114
|
-
"@weasel-js/ui": "1.3.0
|
|
112
|
+
"@weasel-js/core": "1.3.0",
|
|
113
|
+
"@weasel-js/theme": "1.3.0",
|
|
114
|
+
"@weasel-js/ui": "1.3.0",
|
|
115
115
|
"earcut": "2.2.4",
|
|
116
116
|
"polygon-clipping": "^0.15.7",
|
|
117
117
|
"react-aria-components": "^1.5.0",
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
"@biomejs/biome": "^2.4.12",
|
|
123
123
|
"@rollup/plugin-alias": "^6.0.0",
|
|
124
124
|
"@testing-library/jest-dom": "^6.6.0",
|
|
125
|
-
"@weasel-js/modes": "1.3.0
|
|
125
|
+
"@weasel-js/modes": "1.3.0",
|
|
126
126
|
"less": "^4.2.0",
|
|
127
127
|
"rollup-plugin-dts": "^6.4.1",
|
|
128
128
|
"tsx": "^4.19.0",
|
|
@@ -20,7 +20,13 @@ describe('builder', () => {
|
|
|
20
20
|
it('keeps the subclass across a chain, so kind-specific methods survive', () => {
|
|
21
21
|
const n = f.number(20).label('A').range(5, 80).describe('help').step(5);
|
|
22
22
|
expect(n.kind).toBe('number');
|
|
23
|
-
expect(n.annotations).toMatchObject({
|
|
23
|
+
expect(n.annotations).toMatchObject({
|
|
24
|
+
name: 'A',
|
|
25
|
+
description: 'help',
|
|
26
|
+
min: 5,
|
|
27
|
+
max: 80,
|
|
28
|
+
step: 5,
|
|
29
|
+
});
|
|
24
30
|
});
|
|
25
31
|
|
|
26
32
|
it('keeps a custom node kind across a chain', () => {
|
package/src/config/builder.ts
CHANGED
|
@@ -29,11 +29,7 @@ abstract class BaseNode<T> implements ConfigNode<T> {
|
|
|
29
29
|
/** Clone into the same subclass. Subclasses with extra constructor
|
|
30
30
|
* arguments override this. */
|
|
31
31
|
protected with(annotations: Annotations, options: NodeOptions): this {
|
|
32
|
-
const Ctor = this.constructor as new (
|
|
33
|
-
d: T,
|
|
34
|
-
a: Annotations,
|
|
35
|
-
o: NodeOptions,
|
|
36
|
-
) => this;
|
|
32
|
+
const Ctor = this.constructor as new (d: T, a: Annotations, o: NodeOptions) => this;
|
|
37
33
|
return new Ctor(this.default, annotations, options);
|
|
38
34
|
}
|
|
39
35
|
|
|
@@ -54,8 +54,7 @@ describe('resolveConfigSchema', () => {
|
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
it('a consumer rule claims an f.value kind before the built-in', () => {
|
|
57
|
-
const colorByName: ConfigRule = (ctx) =>
|
|
58
|
-
ctx.key.endsWith('Color') ? { kind: 'color' } : null;
|
|
57
|
+
const colorByName: ConfigRule = (ctx) => (ctx.key.endsWith('Color') ? { kind: 'color' } : null);
|
|
59
58
|
const r = resolveConfigSchema(f.schema({ tintColor: f.value('#fff') }), [colorByName]);
|
|
60
59
|
expect(leafAt(r, 'tintColor').kind).toBe('color');
|
|
61
60
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import { PropertyRow } from '@weasel-js/ui';
|
|
2
3
|
import { useState } from 'react';
|
|
3
4
|
import { f } from '../config/builder';
|
|
4
5
|
import { resolveConfigSchema } from '../config/resolve';
|
|
5
6
|
import type { ConfigRule, ControlRenderer } from '../config/types';
|
|
6
|
-
import { PropertyRow } from '../ui/properties/PropertyPanel';
|
|
7
7
|
import { ControlPanel } from './ControlPanel';
|
|
8
8
|
import type { ConfigField } from './types';
|
|
9
9
|
|
|
@@ -141,9 +141,48 @@ export const CustomControl: Story = {
|
|
|
141
141
|
),
|
|
142
142
|
};
|
|
143
143
|
|
|
144
|
+
const described = f.schema({
|
|
145
|
+
frequency: f
|
|
146
|
+
.number(2)
|
|
147
|
+
.range(0.1, 10)
|
|
148
|
+
.step(0.1)
|
|
149
|
+
.describe('Cycles per second the oscillator runs at.'),
|
|
150
|
+
amplitude: f.number(0.5).range(0, 1).step(0.05),
|
|
151
|
+
showGrid: f.boolean(true).describe('Draw the alignment grid behind the plot.'),
|
|
152
|
+
wave: f
|
|
153
|
+
.enum('sine', [
|
|
154
|
+
{ value: 'sine', label: 'Sine' },
|
|
155
|
+
{ value: 'square', label: 'Square' },
|
|
156
|
+
])
|
|
157
|
+
.describe('Waveform the generator emits.'),
|
|
158
|
+
title: f.string('My experiment'),
|
|
159
|
+
tint: f.color('#3a86ff').describe('Plot line color.'),
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
/** A leaf with a `describe(...)` gets an \u24d8 beside its label whose tooltip
|
|
163
|
+
* carries the text; leaves without one stay bare. */
|
|
164
|
+
export const Described: Story = {
|
|
165
|
+
render: () => {
|
|
166
|
+
const schema = resolveConfigSchema(described, []);
|
|
167
|
+
const [config, setConfig] = useState<Record<string, unknown>>(described.defaults());
|
|
168
|
+
return (
|
|
169
|
+
<ControlPanel
|
|
170
|
+
schema={schema}
|
|
171
|
+
config={config}
|
|
172
|
+
setConfig={(key, value) => setConfig((prev) => ({ ...prev, [key as string]: value }))}
|
|
173
|
+
/>
|
|
174
|
+
);
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
|
|
144
178
|
const conditional = f.schema({
|
|
145
179
|
showGrid: f.boolean(true),
|
|
146
|
-
cellSize: f
|
|
180
|
+
cellSize: f
|
|
181
|
+
.number(20)
|
|
182
|
+
.range(5, 80)
|
|
183
|
+
.step(5)
|
|
184
|
+
.label('Grid spacing')
|
|
185
|
+
.showIf((c) => c.showGrid === true),
|
|
147
186
|
});
|
|
148
187
|
|
|
149
188
|
/** `showIf` hides the row while the value stays in config. Toggle the
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { fireEvent, render, screen } from '@testing-library/react';
|
|
2
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
3
2
|
import { TOOL_PREF_KINDS, type ToolPrefKind } from '@weasel-js/core';
|
|
4
3
|
import type { PrefLeaf } from '@weasel-js/ui';
|
|
5
|
-
import
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
6
5
|
import { f } from '../config/builder';
|
|
7
6
|
import { resolveConfigSchema } from '../config/resolve';
|
|
7
|
+
import type { ResolvedConfig } from '../config/types';
|
|
8
8
|
import { ControlPanel } from './ControlPanel';
|
|
9
9
|
import type { ConfigField } from './types';
|
|
10
10
|
|
|
@@ -188,6 +188,21 @@ describe('<ControlPanel> schema', () => {
|
|
|
188
188
|
render(<ControlPanel schema={schema} config={{}} setConfig={vi.fn()} />);
|
|
189
189
|
expect(screen.getByLabelText('Tint')).toHaveValue('#123456');
|
|
190
190
|
});
|
|
191
|
+
|
|
192
|
+
it('hangs a described leaf\u2019s description off a help affordance, and leaves an undescribed leaf bare', () => {
|
|
193
|
+
const schema = resolveConfigSchema(
|
|
194
|
+
f.schema({
|
|
195
|
+
showGrid: f.boolean(true).describe('Draw the alignment grid.'),
|
|
196
|
+
snap: f.boolean(true),
|
|
197
|
+
}),
|
|
198
|
+
[],
|
|
199
|
+
);
|
|
200
|
+
render(
|
|
201
|
+
<ControlPanel schema={schema} config={{ showGrid: true, snap: true }} setConfig={vi.fn()} />,
|
|
202
|
+
);
|
|
203
|
+
expect(screen.getByRole('button', { name: 'About Show grid' })).toBeInTheDocument();
|
|
204
|
+
expect(screen.getAllByRole('button', { name: /^About / })).toHaveLength(1);
|
|
205
|
+
});
|
|
191
206
|
});
|
|
192
207
|
|
|
193
208
|
describe('<ControlPanel> renderers', () => {
|
|
@@ -205,7 +220,7 @@ describe('<ControlPanel> renderers', () => {
|
|
|
205
220
|
expect(screen.queryByText('by-kind')).not.toBeInTheDocument();
|
|
206
221
|
});
|
|
207
222
|
|
|
208
|
-
it(
|
|
223
|
+
it("a lab renderer for the path beats the node's own .render", () => {
|
|
209
224
|
const schema = resolveConfigSchema(
|
|
210
225
|
f.schema({ tint: f.color('#ffffff').render(() => <span>by-node</span>) }),
|
|
211
226
|
[],
|
|
@@ -252,7 +267,7 @@ describe('<ControlPanel> renderers', () => {
|
|
|
252
267
|
|
|
253
268
|
it('a renderer returning null collapses the row', () => {
|
|
254
269
|
const schema = resolveConfigSchema(f.schema({ tint: f.color('#ffffff') }), []);
|
|
255
|
-
|
|
270
|
+
render(
|
|
256
271
|
<ControlPanel
|
|
257
272
|
schema={schema}
|
|
258
273
|
config={{ tint: '#ffffff' }}
|
|
@@ -260,7 +275,7 @@ describe('<ControlPanel> renderers', () => {
|
|
|
260
275
|
renderers={{ color: () => null }}
|
|
261
276
|
/>,
|
|
262
277
|
);
|
|
263
|
-
expect(
|
|
278
|
+
expect(screen.queryByText('Tint')).toBeNull();
|
|
264
279
|
});
|
|
265
280
|
});
|
|
266
281
|
|
|
@@ -274,7 +289,11 @@ describe('<ControlPanel> visibility and sections', () => {
|
|
|
274
289
|
[],
|
|
275
290
|
);
|
|
276
291
|
const { rerender } = render(
|
|
277
|
-
<ControlPanel
|
|
292
|
+
<ControlPanel
|
|
293
|
+
schema={schema}
|
|
294
|
+
config={{ showGrid: true, cellSize: 20 }}
|
|
295
|
+
setConfig={vi.fn()}
|
|
296
|
+
/>,
|
|
278
297
|
);
|
|
279
298
|
expect(screen.getByLabelText('Cell size')).toBeInTheDocument();
|
|
280
299
|
rerender(
|
|
@@ -302,11 +321,11 @@ describe('<ControlPanel> visibility and sections', () => {
|
|
|
302
321
|
f.schema({ showGrid: f.boolean(true), seed: f.number(0).section('Advanced') }),
|
|
303
322
|
[],
|
|
304
323
|
);
|
|
305
|
-
|
|
324
|
+
render(
|
|
306
325
|
<ControlPanel schema={schema} config={{ showGrid: true, seed: 0 }} setConfig={vi.fn()} />,
|
|
307
326
|
);
|
|
308
327
|
expect(screen.getByText('Advanced')).toBeInTheDocument();
|
|
309
|
-
const group =
|
|
328
|
+
const group = screen.getByRole('heading', { name: 'Advanced' }).parentElement;
|
|
310
329
|
expect(group).not.toBeNull();
|
|
311
330
|
expect(group?.textContent).toContain('Seed');
|
|
312
331
|
expect(group?.textContent).not.toContain('Show grid');
|
|
@@ -335,7 +354,10 @@ describe('<ControlPanel> built-in kind coverage', () => {
|
|
|
335
354
|
schema={schemaWith(
|
|
336
355
|
{ kind: 'paint', name: 'Fill', description: '', default: null },
|
|
337
356
|
{
|
|
338
|
-
kind: 'object',
|
|
357
|
+
kind: 'object',
|
|
358
|
+
name: 'Stroke',
|
|
359
|
+
description: '',
|
|
360
|
+
default: {},
|
|
339
361
|
children: { width: { kind: 'number', name: 'Width', description: '', default: 1 } },
|
|
340
362
|
},
|
|
341
363
|
)}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { isBuiltinToolPref } from '@weasel-js/core';
|
|
2
|
-
import type { PrefLeaf } from '@weasel-js/ui';
|
|
3
|
-
import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react';
|
|
4
|
-
import { fromConfigFields } from '../config/fromConfigField';
|
|
5
|
-
import type { ControlRenderer, ResolvedConfig } from '../config/types';
|
|
6
|
-
import { isLeafVisible } from '../config/visible';
|
|
7
|
-
import { PropertyGroup } from '../ui/properties/PropertyGroup';
|
|
8
2
|
import {
|
|
9
3
|
CheckboxRow,
|
|
10
4
|
ColorRow,
|
|
11
5
|
NumberRow,
|
|
6
|
+
type PrefLeaf,
|
|
7
|
+
PropertyGroup,
|
|
12
8
|
PropertyList,
|
|
13
9
|
PropertyRow,
|
|
14
10
|
SelectRow,
|
|
11
|
+
SliderRow,
|
|
15
12
|
TextRow,
|
|
16
13
|
ToggleRow,
|
|
17
|
-
|
|
18
|
-
} from '
|
|
14
|
+
} from '@weasel-js/ui';
|
|
15
|
+
import { type ReactNode, useEffect, useMemo, useRef, useState } from 'react';
|
|
16
|
+
import { fromConfigFields } from '../config/fromConfigField';
|
|
17
|
+
import type { ControlRenderer, ResolvedConfig } from '../config/types';
|
|
18
|
+
import { isLeafVisible } from '../config/visible';
|
|
19
19
|
import type { ConfigField } from './types';
|
|
20
20
|
|
|
21
21
|
export interface ControlPanelProps<TC extends Record<string, unknown>> {
|
|
@@ -48,10 +48,7 @@ export function ControlPanel<TC extends Record<string, unknown>>({
|
|
|
48
48
|
showHidden = false,
|
|
49
49
|
className,
|
|
50
50
|
}: ControlPanelProps<TC>) {
|
|
51
|
-
const resolved = useMemo(
|
|
52
|
-
() => schema ?? fromConfigFields(fields ?? []),
|
|
53
|
-
[schema, fields],
|
|
54
|
-
);
|
|
51
|
+
const resolved = useMemo(() => schema ?? fromConfigFields(fields ?? []), [schema, fields]);
|
|
55
52
|
|
|
56
53
|
const paths = Object.keys(resolved.group.children);
|
|
57
54
|
const sectioned = new Set(resolved.sections.flatMap((s) => s.paths));
|
|
@@ -114,14 +111,15 @@ function ControlRow<TC extends Record<string, unknown>>({
|
|
|
114
111
|
|
|
115
112
|
// Most specific wins, and within a tier the lab's entry beats the
|
|
116
113
|
// instrument's: controls[path] -> node .render -> controls[kind] -> built-in.
|
|
117
|
-
const custom =
|
|
118
|
-
renderers?.[path] ?? resolved.renderers[path] ?? renderers?.[leaf.kind];
|
|
114
|
+
const custom = renderers?.[path] ?? resolved.renderers[path] ?? renderers?.[leaf.kind];
|
|
119
115
|
if (custom) return custom({ path, pref: leaf, value, setValue: write });
|
|
120
116
|
|
|
121
117
|
const label = leaf.name;
|
|
118
|
+
const description = leaf.description;
|
|
122
119
|
const read = <T,>(): T => value as T;
|
|
123
120
|
|
|
124
|
-
if (!isBuiltinToolPref(leaf))
|
|
121
|
+
if (!isBuiltinToolPref(leaf))
|
|
122
|
+
return <UnwiredRow label={label} kind={leaf.kind} description={description} />;
|
|
125
123
|
|
|
126
124
|
switch (leaf.kind) {
|
|
127
125
|
case 'number': {
|
|
@@ -137,6 +135,7 @@ function ControlRow<TC extends Record<string, unknown>>({
|
|
|
137
135
|
max={max}
|
|
138
136
|
step={step}
|
|
139
137
|
onChange={write}
|
|
138
|
+
description={description}
|
|
140
139
|
/>
|
|
141
140
|
);
|
|
142
141
|
}
|
|
@@ -153,28 +152,52 @@ function ControlRow<TC extends Record<string, unknown>>({
|
|
|
153
152
|
max={max}
|
|
154
153
|
step={step}
|
|
155
154
|
onChange={(n) => write(Math.min(hi, Math.max(lo, n)))}
|
|
155
|
+
description={description}
|
|
156
156
|
/>
|
|
157
157
|
);
|
|
158
158
|
}
|
|
159
159
|
case 'boolean':
|
|
160
|
-
return
|
|
160
|
+
return (
|
|
161
|
+
<CheckboxRow
|
|
162
|
+
label={label}
|
|
163
|
+
value={read<boolean>()}
|
|
164
|
+
onChange={write}
|
|
165
|
+
description={description}
|
|
166
|
+
/>
|
|
167
|
+
);
|
|
161
168
|
case 'enum': {
|
|
162
169
|
const options = extra<readonly { value: string; label: string }[]>(leaf, 'options') ?? [];
|
|
163
170
|
const Row = extra<string>(leaf, 'control') === 'radio' ? ToggleRow : SelectRow;
|
|
164
171
|
return (
|
|
165
|
-
<Row
|
|
172
|
+
<Row
|
|
173
|
+
label={label}
|
|
174
|
+
value={read<string>()}
|
|
175
|
+
options={options}
|
|
176
|
+
onChange={write}
|
|
177
|
+
description={description}
|
|
178
|
+
/>
|
|
166
179
|
);
|
|
167
180
|
}
|
|
168
181
|
case 'string':
|
|
169
|
-
return
|
|
182
|
+
return (
|
|
183
|
+
<DebouncedTextRow
|
|
184
|
+
leaf={leaf}
|
|
185
|
+
label={label}
|
|
186
|
+
value={read<string>()}
|
|
187
|
+
write={write}
|
|
188
|
+
description={description}
|
|
189
|
+
/>
|
|
190
|
+
);
|
|
170
191
|
case 'color':
|
|
171
|
-
return
|
|
192
|
+
return (
|
|
193
|
+
<ColorRow label={label} value={read<string>()} onChange={write} description={description} />
|
|
194
|
+
);
|
|
172
195
|
case 'paint':
|
|
173
196
|
case 'object':
|
|
174
197
|
// Declined: a hex swatch would write a solid over a gradient, and a flat
|
|
175
198
|
// row would write one field into a half-built object. Override with
|
|
176
199
|
// `render` to edit either.
|
|
177
|
-
return <UnwiredRow label={label} kind={leaf.kind} />;
|
|
200
|
+
return <UnwiredRow label={label} kind={leaf.kind} description={description} />;
|
|
178
201
|
default: {
|
|
179
202
|
// Not reachable while every built-in kind has an arm — and a new kind
|
|
180
203
|
// that lacks one is a compile error here, never a blank row.
|
|
@@ -188,9 +211,17 @@ function ControlRow<TC extends Record<string, unknown>>({
|
|
|
188
211
|
|
|
189
212
|
/** A leaf this panel has no control for is named rather than dropped: a silent
|
|
190
213
|
* gap reads as "this control does not exist". */
|
|
191
|
-
function UnwiredRow({
|
|
214
|
+
function UnwiredRow({
|
|
215
|
+
label,
|
|
216
|
+
kind,
|
|
217
|
+
description,
|
|
218
|
+
}: {
|
|
219
|
+
label: string;
|
|
220
|
+
kind: string;
|
|
221
|
+
description?: string;
|
|
222
|
+
}) {
|
|
192
223
|
return (
|
|
193
|
-
<PropertyRow label={label}>
|
|
224
|
+
<PropertyRow label={label} description={description}>
|
|
194
225
|
<span className="lk-control-panel__unknown">no control for “{kind}”</span>
|
|
195
226
|
</PropertyRow>
|
|
196
227
|
);
|
|
@@ -204,11 +235,13 @@ function DebouncedTextRow({
|
|
|
204
235
|
label,
|
|
205
236
|
value,
|
|
206
237
|
write,
|
|
238
|
+
description,
|
|
207
239
|
}: {
|
|
208
240
|
leaf: PrefLeaf;
|
|
209
241
|
label: string;
|
|
210
242
|
value: string;
|
|
211
243
|
write: (value: unknown) => void;
|
|
244
|
+
description?: string;
|
|
212
245
|
}) {
|
|
213
246
|
const debounceMs = extra<number>(leaf, 'debounceMs') ?? 150;
|
|
214
247
|
const [local, setLocal] = useState(value);
|
|
@@ -232,6 +265,7 @@ function DebouncedTextRow({
|
|
|
232
265
|
return (
|
|
233
266
|
<TextRow
|
|
234
267
|
label={label}
|
|
268
|
+
description={description}
|
|
235
269
|
value={local}
|
|
236
270
|
placeholder={extra<string>(leaf, 'placeholder')}
|
|
237
271
|
maxLength={extra<number>(leaf, 'maxLength')}
|
package/src/dragdrop/index.ts
CHANGED
|
@@ -1 +1,12 @@
|
|
|
1
1
|
export type { DragDropCapability, DragFeedback, PaletteItem } from '../instrument/types';
|
|
2
|
+
export type {
|
|
3
|
+
DragOverlayProps,
|
|
4
|
+
DragState,
|
|
5
|
+
UseDragDropArgs,
|
|
6
|
+
UseDragDropResult,
|
|
7
|
+
} from './DragDropRuntime';
|
|
8
|
+
export { DragOverlay, useDragDrop } from './DragDropRuntime';
|
|
9
|
+
export type { DragGhostProps } from './DragGhost';
|
|
10
|
+
export { DragGhost } from './DragGhost';
|
|
11
|
+
export type { PaletteProps } from './Palette';
|
|
12
|
+
export { Palette } from './Palette';
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,52 @@
|
|
|
1
|
+
// The property-panel family and LayerStack live in `@weasel-js/ui` now; labkit
|
|
2
|
+
// re-exports them so existing `@weasel-js/labkit` imports keep resolving. Named,
|
|
3
|
+
// not `export *` — a star re-export of an external package emits no binding in
|
|
4
|
+
// the bundle.
|
|
5
|
+
export type {
|
|
6
|
+
CheckboxRowProps,
|
|
7
|
+
ColorRowProps,
|
|
8
|
+
CurveFieldProps,
|
|
9
|
+
CurveMark,
|
|
10
|
+
EffectCardListItem,
|
|
11
|
+
EffectCardListProps,
|
|
12
|
+
EffectCardProps,
|
|
13
|
+
LayerStackItem,
|
|
14
|
+
LayerStackProps,
|
|
15
|
+
NumberRowProps,
|
|
16
|
+
PropertyGroupProps,
|
|
17
|
+
PropertyListPack,
|
|
18
|
+
PropertyListProps,
|
|
19
|
+
PropertyOption,
|
|
20
|
+
PropertyPanelProps,
|
|
21
|
+
PropertyRowLayout,
|
|
22
|
+
PropertyRowProps,
|
|
23
|
+
PropertyRowVariant,
|
|
24
|
+
PropertySpanProps,
|
|
25
|
+
SelectRowProps,
|
|
26
|
+
SliderRowProps,
|
|
27
|
+
SubpanelProps,
|
|
28
|
+
TextRowProps,
|
|
29
|
+
ToggleRowProps,
|
|
30
|
+
} from '@weasel-js/ui';
|
|
31
|
+
export {
|
|
32
|
+
CheckboxRow,
|
|
33
|
+
ColorRow,
|
|
34
|
+
CurveField,
|
|
35
|
+
EffectCard,
|
|
36
|
+
EffectCardList,
|
|
37
|
+
LayerStack,
|
|
38
|
+
NumberRow,
|
|
39
|
+
PropertyGroup,
|
|
40
|
+
PropertyList,
|
|
41
|
+
PropertyPanel,
|
|
42
|
+
PropertyRow,
|
|
43
|
+
PropertySpan,
|
|
44
|
+
SelectRow,
|
|
45
|
+
SliderRow,
|
|
46
|
+
Subpanel,
|
|
47
|
+
TextRow,
|
|
48
|
+
ToggleRow,
|
|
49
|
+
} from '@weasel-js/ui';
|
|
1
50
|
export type { CanvasLayerDescriptor, CanvasStackContextValue, CanvasStackProps } from './canvas';
|
|
2
51
|
export { CanvasStack, CanvasStackContext, screenToWorld, worldToScreen } from './canvas';
|
|
3
52
|
export type { OrbitHandlers, OrbitView, UseOrbitOptions, Vec3 } from './canvas/useOrbit';
|
|
@@ -105,7 +154,5 @@ export * from './surface';
|
|
|
105
154
|
export { interstellarTheme } from './theme/interstellar';
|
|
106
155
|
export type { ToolCapability, TrialTool } from './tools/types';
|
|
107
156
|
export * from './trial';
|
|
108
|
-
export * from './ui/layers';
|
|
109
|
-
export * from './ui/properties';
|
|
110
157
|
export type { EventBus, EventListener } from './undo';
|
|
111
158
|
export { clearUndo, createEventBus, emptyStack, pushSnapshot, redo, undo } from './undo';
|
package/src/lab/index.ts
CHANGED
|
@@ -6,5 +6,5 @@ export type { LabPaletteProps } from './LabPalette';
|
|
|
6
6
|
export { LabPalette } from './LabPalette';
|
|
7
7
|
export type { LabShellProps } from './LabShell';
|
|
8
8
|
export { LabShell } from './LabShell';
|
|
9
|
-
export type { WorkspaceProps } from './Workspace';
|
|
9
|
+
export type { TrialLayout, WorkspaceProps } from './Workspace';
|
|
10
10
|
export { Workspace } from './Workspace';
|
package/src/layers/AGENTS.md
CHANGED
|
@@ -46,7 +46,7 @@ This is intended for legend/HUD layers that should never be toggled off. Visibil
|
|
|
46
46
|
|
|
47
47
|
## Drag handle customization
|
|
48
48
|
|
|
49
|
-
The drag handle is a button with class `lk-layer-list__handle` holding `<DragHandleGlyph
|
|
49
|
+
The drag handle is a button with class `lk-layer-list__handle` holding `<DragHandleGlyph>` (from `@weasel-js/ui`), the same grip `LayerStack` uses. Its padding is transparent and cancelled by an equal negative margin, so the grab target is larger than the drawn dots without widening the row. Row pitch — height plus row gap — is measured from the DOM when a drag starts, so restyling the row does not skew drag distance. It used to be a hardcoded `28`, which had already drifted from the rendered height by the time it was found.
|
|
50
50
|
|
|
51
51
|
Pointer capture is acquired on `pointerdown` and released on `pointerup`, so dragging works across the document without requiring window-level listeners.
|
|
52
52
|
|
package/src/layers/LayerList.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type PointerEvent, useRef, useState } from 'react';
|
|
2
2
|
import type { LayerDescriptor } from '../instrument/types';
|
|
3
|
-
import { DragHandleGlyph } from '../
|
|
3
|
+
import { DragHandleGlyph } from '../passthrough/weasel-ui';
|
|
4
4
|
|
|
5
5
|
/** Props for `<LayerList>`. */
|
|
6
6
|
export interface LayerListProps {
|
|
@@ -24,6 +24,7 @@ export {
|
|
|
24
24
|
type BadgeVariant,
|
|
25
25
|
type BoundsCtx,
|
|
26
26
|
type BuiltInEdgeName,
|
|
27
|
+
type BuiltinPref,
|
|
27
28
|
Button,
|
|
28
29
|
type ButtonProps,
|
|
29
30
|
type ButtonSize,
|
|
@@ -47,6 +48,8 @@ export {
|
|
|
47
48
|
type DataGridProps,
|
|
48
49
|
Dialog,
|
|
49
50
|
type DialogProps,
|
|
51
|
+
DragHandleGlyph,
|
|
52
|
+
type DragHandleGlyphProps,
|
|
50
53
|
detectPlatform,
|
|
51
54
|
dlog,
|
|
52
55
|
EDGE_PROFILES,
|
|
@@ -68,6 +71,7 @@ export {
|
|
|
68
71
|
type InterpolationMode,
|
|
69
72
|
inferKeycapKind,
|
|
70
73
|
isDebugEnabled,
|
|
74
|
+
isPrefLeaf,
|
|
71
75
|
KeyCap,
|
|
72
76
|
type KeyCapProps,
|
|
73
77
|
type KeyCapVariant,
|
|
@@ -79,6 +83,9 @@ export {
|
|
|
79
83
|
keySpecFromKey,
|
|
80
84
|
keySpecsFromMods,
|
|
81
85
|
type LayerListItem,
|
|
86
|
+
LayerStack,
|
|
87
|
+
type LayerStackItem,
|
|
88
|
+
type LayerStackProps,
|
|
82
89
|
type LogicalMod,
|
|
83
90
|
type LogicalModSpec,
|
|
84
91
|
MINUS_SIGN,
|
|
@@ -100,22 +107,6 @@ export {
|
|
|
100
107
|
Powerline,
|
|
101
108
|
type PowerlineProps,
|
|
102
109
|
type PowerlineSegment,
|
|
103
|
-
paintGradientTrack,
|
|
104
|
-
Radio,
|
|
105
|
-
RadioGroup,
|
|
106
|
-
type RadioGroupProps,
|
|
107
|
-
type RadioProps,
|
|
108
|
-
RangeSlider,
|
|
109
|
-
type RangeSliderProps,
|
|
110
|
-
type ReorderDragHandlers,
|
|
111
|
-
type ReorderDragState,
|
|
112
|
-
type RovingItem,
|
|
113
|
-
type RovingTabIndex,
|
|
114
|
-
Select,
|
|
115
|
-
SelectItem,
|
|
116
|
-
type SelectItemProps,
|
|
117
|
-
type BuiltinPref,
|
|
118
|
-
isPrefLeaf,
|
|
119
110
|
type PrefBoolean,
|
|
120
111
|
type PrefBooleanControl,
|
|
121
112
|
type PrefColor,
|
|
@@ -135,8 +126,21 @@ export {
|
|
|
135
126
|
type PrefRenderer,
|
|
136
127
|
type PrefString,
|
|
137
128
|
type PrefStringControl,
|
|
129
|
+
paintGradientTrack,
|
|
138
130
|
prefValueAtPath,
|
|
139
|
-
|
|
131
|
+
Radio,
|
|
132
|
+
RadioGroup,
|
|
133
|
+
type RadioGroupProps,
|
|
134
|
+
type RadioProps,
|
|
135
|
+
RangeSlider,
|
|
136
|
+
type RangeSliderProps,
|
|
137
|
+
type ReorderDragHandlers,
|
|
138
|
+
type ReorderDragState,
|
|
139
|
+
type RovingItem,
|
|
140
|
+
type RovingTabIndex,
|
|
141
|
+
Select,
|
|
142
|
+
SelectItem,
|
|
143
|
+
type SelectItemProps,
|
|
140
144
|
type SelectOption,
|
|
141
145
|
type SelectProps,
|
|
142
146
|
Sidebar,
|
|
@@ -174,4 +178,5 @@ export {
|
|
|
174
178
|
type UseRovingTabIndexOptions,
|
|
175
179
|
useReorderDragList,
|
|
176
180
|
useRovingTabIndex,
|
|
181
|
+
visiblePrefSubtree,
|
|
177
182
|
} from '@weasel-js/ui';
|
package/src/styles.less
CHANGED
|
@@ -20,7 +20,3 @@
|
|
|
20
20
|
@import './layers/LayerList.less';
|
|
21
21
|
@import './dragdrop/Palette.less';
|
|
22
22
|
@import './dragdrop/DragGhost.less';
|
|
23
|
-
@import './ui/properties/PropertyPanel.less';
|
|
24
|
-
@import './ui/properties/PropertyGroup.less';
|
|
25
|
-
@import './ui/properties/CurveField.less';
|
|
26
|
-
@import './ui/layers/LayerStack.less';
|