@weasel-js/labkit 1.7.2 → 1.8.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/{CanvasStackContext-Cjy6I-Iv.d.ts → CanvasStackContext-C0fzFsQg.d.ts} +1 -1
- package/dist/_dts/{Stage-D6t7o0pF.d.ts → Stage-Cvwxdnfp.d.ts} +2 -2
- package/dist/_dts/{index-BTmaRy6a.d.ts → index-DEHRoTXK.d.ts} +2 -2
- package/dist/_dts/{index-DCMA4Fy1.d.ts → index-DRaswz91.d.ts} +1 -1
- package/dist/_dts/{types-BUBSIZuV.d.ts → types-DUfQ0isU.d.ts} +5 -1
- package/dist/_dts/{useTrialState-Bh8bzFgE.d.ts → useTrialState-CS4TdWPW.d.ts} +1 -1
- package/dist/canvas/index.d.ts +5 -5
- package/dist/chrome/index.d.ts +3 -3
- package/dist/chrome/index.js +4 -4
- package/dist/{chunk-XRX5S5NT.js → chunk-3L4MLLQB.js} +4 -4
- package/dist/chunk-3L4MLLQB.js.map +1 -0
- package/dist/{chunk-WWJDPNZZ.js → chunk-7KAETQSS.js} +19 -19
- package/dist/chunk-7KAETQSS.js.map +1 -0
- package/dist/{chunk-YCFKW5RX.js → chunk-J5HJJDLF.js} +11 -2
- package/dist/chunk-J5HJJDLF.js.map +1 -0
- package/dist/{chunk-E6NARGU7.js → chunk-MOTDMMMN.js} +3 -3
- package/dist/{chunk-E6NARGU7.js.map → chunk-MOTDMMMN.js.map} +1 -1
- package/dist/{chunk-XZDCEMEL.js → chunk-NVKBL7ZE.js} +3 -3
- package/dist/{chunk-XZDCEMEL.js.map → chunk-NVKBL7ZE.js.map} +1 -1
- package/dist/chunk-WURZTJGQ.js +15756 -0
- package/dist/chunk-WURZTJGQ.js.map +1 -0
- package/dist/{chunk-IBVRMHW5.js → chunk-XXACAPVU.js} +3 -3
- package/dist/{chunk-IBVRMHW5.js.map → chunk-XXACAPVU.js.map} +1 -1
- package/dist/{chunk-RODIY7HI.js → chunk-YDE6XATS.js} +7 -7
- package/dist/{chunk-RODIY7HI.js.map → chunk-YDE6XATS.js.map} +1 -1
- package/dist/{chunk-WFALF2X2.js → chunk-YX75W6EK.js} +53 -16
- package/dist/chunk-YX75W6EK.js.map +1 -0
- package/dist/config/index.d.ts +12 -5
- package/dist/config/index.js +2 -2
- package/dist/controls/index.d.ts +2 -2
- package/dist/controls/index.js +3 -3
- package/dist/dragdrop/index.d.ts +2 -2
- package/dist/index.d.ts +10 -10
- package/dist/index.js +175 -189
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +2 -2
- package/dist/layers/index.js +1 -1
- package/dist/loupe/index.d.ts +1 -1
- package/dist/overview/index.d.ts +1 -1
- package/dist/passthrough/weasel-ui.js +1 -1
- package/dist/primitives/index.js +3 -3
- package/dist/state/index.d.ts +4 -4
- package/dist/state/index.js +3 -3
- package/dist/styles.css +21 -9
- package/dist/undo/index.d.ts +2 -2
- package/package.json +11 -11
- package/src/config/builder.ts +11 -1
- package/src/config/types.ts +5 -1
- package/src/controls/ControlMatrix.less +7 -2
- package/src/controls/ControlMatrix.test.tsx +10 -0
- package/src/controls/ControlMatrix.tsx +58 -8
- package/src/controls/ControlPanel.test.tsx +30 -0
- package/src/styles.less +2 -0
- package/src/theme/interstellar.theme.json +0 -14
- package/dist/chunk-U6UQVGFP.js +0 -15583
- package/dist/chunk-U6UQVGFP.js.map +0 -1
- package/dist/chunk-WFALF2X2.js.map +0 -1
- package/dist/chunk-WWJDPNZZ.js.map +0 -1
- package/dist/chunk-XRX5S5NT.js.map +0 -1
- package/dist/chunk-YCFKW5RX.js.map +0 -1
package/dist/undo/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { at as UndoCapability } from '../_dts/index-
|
|
1
|
+
export { at as UndoCapability } from '../_dts/index-DRaswz91.js';
|
|
2
2
|
import '@weasel-js/ui';
|
|
3
3
|
import '@weasel-js/core';
|
|
4
4
|
import 'react';
|
|
5
5
|
import '@weasel-js/theme';
|
|
6
|
-
import '../_dts/types-
|
|
6
|
+
import '../_dts/types-DUfQ0isU.js';
|
|
7
7
|
import '@weasel-js/quantity';
|
|
8
8
|
import '@weasel-js/geom';
|
|
9
9
|
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
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "React widgets for building self-contained interactive lab pages",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "orochi235",
|
|
@@ -115,18 +115,18 @@
|
|
|
115
115
|
"dev:3d": "LABKIT_EXAMPLE=3d-lab vite"
|
|
116
116
|
},
|
|
117
117
|
"peerDependencies": {
|
|
118
|
-
"@weasel-js/core": "1.
|
|
119
|
-
"@weasel-js/theme": "1.
|
|
118
|
+
"@weasel-js/core": "1.8.0",
|
|
119
|
+
"@weasel-js/theme": "1.8.0",
|
|
120
120
|
"react": "^19.0.0",
|
|
121
121
|
"react-dom": "^19.0.0"
|
|
122
122
|
},
|
|
123
123
|
"dependencies": {
|
|
124
|
-
"@weasel-js/geom": "1.
|
|
125
|
-
"@weasel-js/kernel3d": "1.
|
|
126
|
-
"@weasel-js/loupe": "1.
|
|
127
|
-
"@weasel-js/quantity": "1.
|
|
128
|
-
"@weasel-js/svg": "1.
|
|
129
|
-
"@weasel-js/ui": "1.
|
|
124
|
+
"@weasel-js/geom": "1.8.0",
|
|
125
|
+
"@weasel-js/kernel3d": "1.8.0",
|
|
126
|
+
"@weasel-js/loupe": "1.8.0",
|
|
127
|
+
"@weasel-js/quantity": "1.8.0",
|
|
128
|
+
"@weasel-js/svg": "1.8.0",
|
|
129
|
+
"@weasel-js/ui": "1.8.0",
|
|
130
130
|
"earcut": "3.2.3",
|
|
131
131
|
"polygon-clipping": "^0.15.7",
|
|
132
132
|
"react-aria-components": "^1.5.0",
|
|
@@ -136,8 +136,8 @@
|
|
|
136
136
|
"devDependencies": {
|
|
137
137
|
"@biomejs/biome": "^2.4.12",
|
|
138
138
|
"@testing-library/jest-dom": "^7.0.1",
|
|
139
|
-
"@weasel-js/guides": "1.
|
|
140
|
-
"@weasel-js/modes": "1.
|
|
139
|
+
"@weasel-js/guides": "1.8.0",
|
|
140
|
+
"@weasel-js/modes": "1.8.0",
|
|
141
141
|
"less": "^4.2.0",
|
|
142
142
|
"rollup-plugin-dts": "^6.4.1",
|
|
143
143
|
"tsx": "^4.19.0",
|
package/src/config/builder.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Display } from '@weasel-js/quantity';
|
|
1
|
+
import type { Display, InfinityText } from '@weasel-js/quantity';
|
|
2
2
|
import type { PrefLeaf, PrefNumberUnit } from '@weasel-js/ui';
|
|
3
3
|
import { type Auto, isAuto } from './auto';
|
|
4
4
|
import type {
|
|
@@ -159,6 +159,16 @@ export class NumberNode extends BaseNode<number> {
|
|
|
159
159
|
return this.ann({ unit });
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Make the top of the range mean infinity: the slider's `max` stop stores
|
|
164
|
+
* `Infinity` and reads `word` — `.range(0, 5000).endless('never')`. A value
|
|
165
|
+
* of `Infinity` sits at that stop. `at: 'min'` puts it at the bottom
|
|
166
|
+
* instead, as `-Infinity`; `'both'` does both.
|
|
167
|
+
*/
|
|
168
|
+
endless(word?: InfinityText, at: 'min' | 'max' | 'both' = 'max'): this {
|
|
169
|
+
return this.ann(word === undefined ? { endless: at } : { endless: at, infinity: word });
|
|
170
|
+
}
|
|
171
|
+
|
|
162
172
|
/** Force a slider even without both bounds. */
|
|
163
173
|
slider(): this {
|
|
164
174
|
return this.ann({ control: 'slider' });
|
package/src/config/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Display } from '@weasel-js/quantity';
|
|
1
|
+
import type { Display, InfinityText } from '@weasel-js/quantity';
|
|
2
2
|
import type { PrefGroup, PrefLeaf, PrefNumberUnit, PrefRenderer } from '@weasel-js/ui';
|
|
3
3
|
import type { ReactNode } from 'react';
|
|
4
4
|
|
|
@@ -36,6 +36,10 @@ export interface Annotations {
|
|
|
36
36
|
/** Display-unit conversion for a number stored in a canonical unit — the
|
|
37
37
|
* value, its bounds and its step all convert at the control's edge. */
|
|
38
38
|
unit?: PrefNumberUnit;
|
|
39
|
+
/** Which end of a number's slider stands for infinity. */
|
|
40
|
+
endless?: 'min' | 'max' | 'both';
|
|
41
|
+
/** The word a number's infinity shows as — `'never'`. Default `∞`. */
|
|
42
|
+
infinity?: InfinityText;
|
|
39
43
|
/** A color leaf's value carries alpha (`#rrggbbaa`) and its row edits it. */
|
|
40
44
|
alpha?: boolean;
|
|
41
45
|
control?: string;
|
|
@@ -55,6 +55,8 @@
|
|
|
55
55
|
border: 0;
|
|
56
56
|
border-radius: var(--wzl-radius-sm);
|
|
57
57
|
background: none;
|
|
58
|
+
backdrop-filter: none;
|
|
59
|
+
-webkit-backdrop-filter: none;
|
|
58
60
|
color: inherit;
|
|
59
61
|
font: inherit;
|
|
60
62
|
letter-spacing: var(--wzl-params-label-tracking, var(--wzl-tracking-wide));
|
|
@@ -96,8 +98,8 @@
|
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
// Inherited: the value in effect, but not chosen here.
|
|
99
|
-
.lk-control-matrix__cell.is-inherited
|
|
100
|
-
|
|
101
|
+
.lk-control-matrix__cell.is-inherited {
|
|
102
|
+
.inherited();
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
// Every cell control fills its cell, so the cell is the click target.
|
|
@@ -112,6 +114,9 @@
|
|
|
112
114
|
border: 1px solid transparent;
|
|
113
115
|
border-radius: var(--wzl-radius-sm);
|
|
114
116
|
background: none;
|
|
117
|
+
// labkit's default button blurs its backdrop; dozens of blurred cells make Chrome flicker.
|
|
118
|
+
backdrop-filter: none;
|
|
119
|
+
-webkit-backdrop-filter: none;
|
|
115
120
|
color: inherit;
|
|
116
121
|
font: inherit;
|
|
117
122
|
cursor: pointer;
|
|
@@ -158,6 +158,16 @@ describe('<ControlMatrix>', () => {
|
|
|
158
158
|
expect(setConfig).toHaveBeenCalledWith('looks.window.glow', 0.75);
|
|
159
159
|
});
|
|
160
160
|
|
|
161
|
+
it('lists an enum cell’s options in its popover, with no dropdown inside, and closes on a choice', () => {
|
|
162
|
+
const { setConfig } = setup();
|
|
163
|
+
fireEvent.click(cell('Window Shading'));
|
|
164
|
+
const dialog = screen.getByRole('dialog', { name: 'Window Shading' });
|
|
165
|
+
expect(within(dialog).queryByRole('button', { name: /Shading/ })).toBeNull();
|
|
166
|
+
fireEvent.click(within(dialog).getByRole('radio', { name: 'Soft' }));
|
|
167
|
+
expect(setConfig).toHaveBeenCalledWith('looks.window.shading', 'soft');
|
|
168
|
+
expect(screen.queryByRole('dialog')).toBeNull();
|
|
169
|
+
});
|
|
170
|
+
|
|
161
171
|
it('unpins from the popover with Inherit, disabled while already inherited', () => {
|
|
162
172
|
const { setConfig, unmount } = setup();
|
|
163
173
|
fireEvent.click(cell('Window Glow'));
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
isPrefLeaf,
|
|
6
6
|
type PrefLeaf,
|
|
7
7
|
type PropertyControlProps,
|
|
8
|
+
PropertyField,
|
|
8
9
|
PropertyHelp,
|
|
9
10
|
PropertyList,
|
|
10
11
|
PropertyPanel,
|
|
@@ -211,16 +212,12 @@ export function ControlMatrix({
|
|
|
211
212
|
aria-label={`${nameOf(open.column)} ${open.label}`}
|
|
212
213
|
>
|
|
213
214
|
<PropertyList pack="one-up">
|
|
214
|
-
<
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
resolved={schema}
|
|
215
|
+
<Editor
|
|
216
|
+
open={open}
|
|
217
|
+
schema={schema}
|
|
218
218
|
config={config}
|
|
219
|
-
shown={config}
|
|
220
219
|
setConfig={setConfig}
|
|
221
|
-
|
|
222
|
-
auto={NO_AUTO}
|
|
223
|
-
setRowAuto={noop}
|
|
220
|
+
close={() => setOpen(null)}
|
|
224
221
|
/>
|
|
225
222
|
</PropertyList>
|
|
226
223
|
{clearable(open.leaf) ? (
|
|
@@ -262,6 +259,59 @@ export function ControlMatrix({
|
|
|
262
259
|
);
|
|
263
260
|
}
|
|
264
261
|
|
|
262
|
+
/**
|
|
263
|
+
* The control a cell opens. An enum lists its options outright, as radios: the
|
|
264
|
+
* panel's dropdown would be a second popup opened from inside this one.
|
|
265
|
+
* Choosing one is the whole edit, so it closes the popover.
|
|
266
|
+
*/
|
|
267
|
+
function Editor({
|
|
268
|
+
open,
|
|
269
|
+
schema,
|
|
270
|
+
config,
|
|
271
|
+
setConfig,
|
|
272
|
+
close,
|
|
273
|
+
}: {
|
|
274
|
+
open: OpenCell;
|
|
275
|
+
schema: ResolvedConfig;
|
|
276
|
+
config: Record<string, unknown>;
|
|
277
|
+
setConfig: (path: string, value: unknown) => void;
|
|
278
|
+
close: () => void;
|
|
279
|
+
}) {
|
|
280
|
+
const { path, leaf } = open;
|
|
281
|
+
const field = isBuiltinToolPref(leaf)
|
|
282
|
+
? prefFieldProps(leaf, {
|
|
283
|
+
value: valueAtPath(config, path) ?? leaf.default,
|
|
284
|
+
setValue: (next) => setConfig(path, next),
|
|
285
|
+
})
|
|
286
|
+
: null;
|
|
287
|
+
if (field?.kind === 'enum') {
|
|
288
|
+
return (
|
|
289
|
+
<PropertyField
|
|
290
|
+
{...field}
|
|
291
|
+
label={leaf.name}
|
|
292
|
+
control="radio"
|
|
293
|
+
onChange={(next: Parameters<typeof field.onChange>[0]) => {
|
|
294
|
+
field.onChange(next);
|
|
295
|
+
close();
|
|
296
|
+
}}
|
|
297
|
+
/>
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
return (
|
|
301
|
+
<ControlRow
|
|
302
|
+
path={path}
|
|
303
|
+
leaf={leaf}
|
|
304
|
+
resolved={schema}
|
|
305
|
+
config={config}
|
|
306
|
+
shown={config}
|
|
307
|
+
setConfig={setConfig}
|
|
308
|
+
pack="one-up"
|
|
309
|
+
auto={NO_AUTO}
|
|
310
|
+
setRowAuto={noop}
|
|
311
|
+
/>
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
265
315
|
function ColumnHeader({
|
|
266
316
|
column,
|
|
267
317
|
onClick,
|
|
@@ -1188,3 +1188,33 @@ describe('<ControlPanel> resettable group', () => {
|
|
|
1188
1188
|
]);
|
|
1189
1189
|
});
|
|
1190
1190
|
});
|
|
1191
|
+
|
|
1192
|
+
describe('<ControlPanel> endless number', () => {
|
|
1193
|
+
it('reads its word at the top of the range and writes Infinity there', () => {
|
|
1194
|
+
const schema = resolveConfigSchema(
|
|
1195
|
+
f.schema({ cut: f.number(Infinity).range(0, 5000).step(50).suffix('ms').endless('never') }),
|
|
1196
|
+
[],
|
|
1197
|
+
);
|
|
1198
|
+
const setConfig = vi.fn();
|
|
1199
|
+
function Harness() {
|
|
1200
|
+
const [config, setState] = useState<Record<string, unknown>>({ cut: Infinity });
|
|
1201
|
+
return (
|
|
1202
|
+
<ControlPanel
|
|
1203
|
+
schema={schema}
|
|
1204
|
+
config={config}
|
|
1205
|
+
setConfig={(key: string, value: unknown) => {
|
|
1206
|
+
setConfig(key, value);
|
|
1207
|
+
setState((c) => ({ ...c, [key]: value }));
|
|
1208
|
+
}}
|
|
1209
|
+
/>
|
|
1210
|
+
);
|
|
1211
|
+
}
|
|
1212
|
+
render(<Harness />);
|
|
1213
|
+
expect(screen.getByRole('spinbutton')).toHaveValue('never');
|
|
1214
|
+
expect(screen.queryByText('ms')).toBeNull();
|
|
1215
|
+
fireEvent.change(screen.getByRole('slider'), { target: { value: '4950' } });
|
|
1216
|
+
expect(setConfig).toHaveBeenLastCalledWith('cut', 4950);
|
|
1217
|
+
fireEvent.change(screen.getByRole('slider'), { target: { value: '5000' } });
|
|
1218
|
+
expect(setConfig).toHaveBeenLastCalledWith('cut', Infinity);
|
|
1219
|
+
});
|
|
1220
|
+
});
|
package/src/styles.less
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
@import (css) '@weasel-js/theme/faces.css';
|
|
5
5
|
// The numeric face's one definition, taken as a mixin: `.numeric();`.
|
|
6
6
|
@import (reference, less) '@weasel-js/theme/numeric.module.css';
|
|
7
|
+
// What an inherited value draws in, the same way: `.inherited();`.
|
|
8
|
+
@import (reference, less) '@weasel-js/theme/inherited.module.css';
|
|
7
9
|
@import './theme/base.less';
|
|
8
10
|
@import './lab/Workspace.less';
|
|
9
11
|
@import './lab/LabShell.less';
|
|
@@ -64,20 +64,6 @@
|
|
|
64
64
|
"type": "color"
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
|
-
"fg-muted": {
|
|
68
|
-
"by": "mode",
|
|
69
|
-
"dark": {
|
|
70
|
-
"value": "#a8a8c0",
|
|
71
|
-
"type": "color"
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
"fg-subtle": {
|
|
75
|
-
"by": "mode",
|
|
76
|
-
"dark": {
|
|
77
|
-
"value": "#5a5a78",
|
|
78
|
-
"type": "color"
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
67
|
"accent": {
|
|
82
68
|
"by": "mode",
|
|
83
69
|
"dark": {
|