@weasel-js/labkit 1.4.4 → 1.5.1
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/README.md +54 -6
- package/dist/_dts/{CanvasStackContext-kTEZvEgE.d.ts → CanvasStackContext-CJNMS6mz.d.ts} +1 -1
- package/dist/_dts/{PrefsForm.d-DDHFANkc.d.ts → PrefsForm.d-DPy9I8It.d.ts} +4 -0
- package/dist/_dts/Select.d-Gwr8fLpK.d.ts +453 -0
- package/dist/_dts/{frac-z7ker2Vx.d.ts → frac-B4okC2lX.d.ts} +291 -31
- package/dist/_dts/{index-Blv9uQzu.d.ts → index-BNdz-tNd.d.ts} +105 -17
- package/dist/_dts/index-CSJoj4LC.d.ts +248 -0
- package/dist/_dts/{types-B9_zrHmb.d.ts → types-DzoNY1pO.d.ts} +91 -4
- package/dist/_dts/usePanZoom-Pzf9f2jh.d.ts +160 -0
- package/dist/_dts/useTrialState-uLlmaccn.d.ts +212 -0
- package/dist/canvas/index.d.ts +18 -129
- package/dist/canvas/index.js +4 -2
- package/dist/chrome/index.d.ts +5 -93
- package/dist/chrome/index.js +10 -6
- package/dist/chunk-7PFH3CNM.js +150 -0
- package/dist/chunk-7PFH3CNM.js.map +1 -0
- package/dist/{chunk-I6JCVE24.js → chunk-CEIUBPPW.js} +143 -17
- package/dist/chunk-CEIUBPPW.js.map +1 -0
- package/dist/chunk-EH7UEQV7.js +590 -0
- package/dist/chunk-EH7UEQV7.js.map +1 -0
- package/dist/{chunk-MOM3GOVY.js → chunk-EHGVROVV.js} +125 -27
- package/dist/chunk-EHGVROVV.js.map +1 -0
- package/dist/{chunk-TJ7QY3OC.js → chunk-ERFMC6WU.js} +160 -78
- package/dist/chunk-ERFMC6WU.js.map +1 -0
- package/dist/{chunk-CTRKTLYZ.js → chunk-H6ZAOWNE.js} +11 -11
- package/dist/chunk-H6ZAOWNE.js.map +1 -0
- package/dist/{chunk-64ZCN3DA.js → chunk-IHUVQ3TX.js} +250 -160
- package/dist/chunk-IHUVQ3TX.js.map +1 -0
- package/dist/{chunk-FQMJUVHJ.js → chunk-IJJUK4FU.js} +53 -46
- package/dist/chunk-IJJUK4FU.js.map +1 -0
- package/dist/chunk-IXTQI7JX.js +737 -0
- package/dist/chunk-IXTQI7JX.js.map +1 -0
- package/dist/{chunk-BKFVHKJH.js → chunk-MDVTK5U3.js} +4 -4
- package/dist/{chunk-BKFVHKJH.js.map → chunk-MDVTK5U3.js.map} +1 -1
- package/dist/chunk-PHK4W562.js +72 -0
- package/dist/chunk-PHK4W562.js.map +1 -0
- package/dist/chunk-PJ7WEQBJ.js +18 -0
- package/dist/chunk-PJ7WEQBJ.js.map +1 -0
- package/dist/chunk-RWNDDKOH.js +682 -0
- package/dist/chunk-RWNDDKOH.js.map +1 -0
- package/dist/chunk-T3EC2DXD.js +12628 -0
- package/dist/chunk-T3EC2DXD.js.map +1 -0
- package/dist/{chunk-SMHP6XZ4.js → chunk-UN4U4P63.js} +10 -8
- package/dist/chunk-UN4U4P63.js.map +1 -0
- package/dist/chunk-WIG6XHJ7.js +35 -0
- package/dist/chunk-WIG6XHJ7.js.map +1 -0
- package/dist/chunk-Z76KEZAX.js +15 -0
- package/dist/chunk-Z76KEZAX.js.map +1 -0
- package/dist/chunk-ZDHY47EV.js +363 -0
- package/dist/chunk-ZDHY47EV.js.map +1 -0
- package/dist/config/index.d.ts +276 -0
- package/dist/config/index.js +8 -0
- package/dist/config/index.js.map +1 -0
- package/dist/controls/index.d.ts +3 -4
- package/dist/controls/index.js +4 -3
- package/dist/dragdrop/index.d.ts +3 -5
- package/dist/index.d.ts +266 -413
- package/dist/index.js +1775 -2251
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +4 -6
- package/dist/layers/index.js +2 -2
- package/dist/loupe/index.d.ts +69 -20
- package/dist/loupe/index.js +2 -2
- package/dist/passthrough/weasel-ui.d.ts +175 -309
- package/dist/passthrough/weasel-ui.js +1 -1
- package/dist/primitives/index.d.ts +55 -6
- package/dist/primitives/index.js +6 -4
- package/dist/state/index.d.ts +13 -8
- package/dist/state/index.js +18 -13
- package/dist/state/index.js.map +1 -1
- package/dist/styles.css +223 -76
- package/dist/surface/index.d.ts +44 -7
- package/dist/surface/index.js +2 -1
- package/dist/ui/layers/index.js +1 -1
- package/dist/undo/index.d.ts +3 -5
- package/package.json +15 -8
- package/src/annotations/AnnotationOverlay.tsx +56 -5
- package/src/annotations/Annotations.less +4 -0
- package/src/annotations/Annotations.overlay.test.tsx +105 -6
- package/src/annotations/drawOne.test.ts +1 -1
- package/src/annotations/drawOne.ts +2 -2
- package/src/annotations/paint.test.ts +2 -2
- package/src/annotations/paint.ts +1 -1
- package/src/annotations/preload.ts +6 -0
- package/src/annotations/store.test.ts +18 -0
- package/src/annotations/store.ts +5 -4
- package/src/annotations/svgNodes.test.ts +2 -2
- package/src/annotations/svgNodes.ts +1 -0
- package/src/annotations/toolMap.test.ts +9 -5
- package/src/annotations/toolMap.ts +6 -3
- package/src/annotations/types.ts +6 -3
- package/src/canvas/CameraWheelContext.ts +12 -0
- package/src/canvas/CanvasStack.stories.tsx +1 -1
- package/src/canvas/CanvasStack.test.tsx +25 -0
- package/src/canvas/CanvasStack.tsx +31 -4
- package/src/canvas/Stage.less +18 -0
- package/src/canvas/Stage.test.tsx +186 -0
- package/src/canvas/Stage.tsx +134 -0
- package/src/canvas/camera.test.ts +17 -2
- package/src/canvas/camera.ts +9 -9
- package/src/canvas/index.ts +4 -0
- package/src/canvas/usePanZoom.test.ts +28 -0
- package/src/canvas/usePanZoom.ts +21 -9
- package/src/chrome/ChromeRegions.stories.tsx +1 -4
- package/src/chrome/LabChrome.tsx +130 -0
- package/src/chrome/builtins.test.ts +1 -0
- package/src/chrome/builtins.tsx +21 -31
- package/src/chrome/index.ts +16 -0
- package/src/chrome/labRegions.test.tsx +208 -0
- package/src/chrome/labTypes.ts +50 -0
- package/src/chrome/merge.ts +7 -9
- package/src/chrome/regions/PaletteRegion.test.tsx +6 -4
- package/src/chrome/regions/PaletteRegion.tsx +16 -9
- package/src/chrome/regions/SidebarRegion.stories.tsx +44 -0
- package/src/chrome/regions/SidebarRegion.tsx +25 -13
- package/src/chrome/regions/StatusRegion.tsx +15 -8
- package/src/chrome/regions/ToolbarRegion.tsx +34 -16
- package/src/chrome/types.ts +50 -20
- package/src/config/auto.test.ts +12 -0
- package/src/config/auto.ts +15 -0
- package/src/config/autoConfig.test.ts +107 -0
- package/src/config/autoConfig.ts +153 -0
- package/src/config/builder.test.ts +42 -0
- package/src/config/builder.ts +68 -17
- package/src/config/declarationEmit.fixture.ts +11 -0
- package/src/config/declarationEmit.test.ts +51 -0
- package/src/config/entry.test.ts +46 -0
- package/src/config/index.ts +16 -1
- package/src/config/nodeClasses.test.ts +18 -0
- package/src/config/path.ts +7 -2
- package/src/config/resolve.test.ts +25 -0
- package/src/config/resolve.ts +17 -1
- package/src/config/types.ts +34 -2
- package/src/config/useResolvedConfig.ts +26 -0
- package/src/controls/AutoControls.stories.tsx +88 -0
- package/src/controls/ControlPanel.stories.tsx +42 -1
- package/src/controls/ControlPanel.test.tsx +530 -4
- package/src/controls/ControlPanel.tsx +562 -82
- package/src/fake-indexeddb-auto.d.ts +5 -0
- package/src/index.test.ts +7 -0
- package/src/index.ts +66 -5
- package/src/instrument/serializers.test.ts +22 -0
- package/src/instrument/serializers.ts +40 -1
- package/src/instrument/types.ts +25 -1
- package/src/lab/Lab.chrome.test.tsx +16 -0
- package/src/lab/Lab.less +4 -13
- package/src/lab/Lab.persist.test.tsx +147 -0
- package/src/lab/Lab.stories.tsx +1 -3
- package/src/lab/Lab.surface.test.tsx +71 -3
- package/src/lab/Lab.test.tsx +168 -16
- package/src/lab/Lab.tsx +434 -129
- package/src/lab/LabContext.ts +8 -0
- package/src/lab/LabFit.stories.less +18 -0
- package/src/lab/LabFit.stories.tsx +219 -0
- package/src/lab/LabFullChrome.stories.tsx +1 -4
- package/src/lab/LabHeader.test.tsx +40 -9
- package/src/lab/LabHeader.tsx +7 -14
- package/src/lab/LabPalette.tsx +13 -26
- package/src/lab/LabRoot.test.tsx +56 -0
- package/src/lab/LabRoot.tsx +47 -0
- package/src/lab/LabShell.less +73 -15
- package/src/lab/LabShell.stories.tsx +50 -1
- package/src/lab/LabShell.tsx +18 -27
- package/src/lab/LabSwitcher.less +18 -11
- package/src/lab/LabSwitcher.test.tsx +14 -9
- package/src/lab/LabSwitcher.tsx +8 -4
- package/src/lab/Workspace.less +1 -1
- package/src/lab/Workspace.stories.tsx +1 -1
- package/src/lab/Workspace.surface.test.tsx +1 -0
- package/src/lab/fitCheck.test.ts +57 -0
- package/src/lab/fitCheck.ts +125 -0
- package/src/lab/index.ts +2 -0
- package/src/layers/LayerList.stories.tsx +1 -1
- package/src/loupe/AGENTS.md +17 -5
- package/src/loupe/Loupe.less +1 -1
- package/src/loupe/LoupeGestures.tsx +67 -0
- package/src/loupe/TrialLoupe.tsx +43 -28
- package/src/loupe/canvasLens.ts +1 -1
- package/src/loupe/index.ts +4 -0
- package/src/loupe/loupeActions.ts +98 -0
- package/src/loupe/types.ts +1 -1
- package/src/loupe/useLoupe.test.tsx +60 -3
- package/src/loupe/useLoupe.ts +29 -49
- package/src/passthrough/weasel-ui.ts +9 -0
- package/src/primitives/FloatingPanel.stories.tsx +14 -2
- package/src/primitives/FloatingPanel.test.tsx +47 -16
- package/src/primitives/FloatingPanel.tsx +11 -25
- package/src/primitives/FpsMeter.stories.tsx +1 -1
- package/src/primitives/JobProgress.stories.tsx +1 -1
- package/src/primitives/Legend.stories.tsx +1 -1
- package/src/primitives/ScaleIndicator.stories.tsx +1 -1
- package/src/primitives/Sidebar.less +7 -0
- package/src/primitives/Sidebar.stories.tsx +1 -1
- package/src/primitives/Split.less +14 -0
- package/src/primitives/Split.test.tsx +133 -0
- package/src/primitives/Split.tsx +175 -0
- package/src/primitives/StatusBar.stories.tsx +1 -1
- package/src/primitives/Toolbar.stories.tsx +1 -1
- package/src/primitives/ZoomControl.tsx +5 -2
- package/src/primitives/index.ts +2 -0
- package/src/specimen/Specimen.less +95 -0
- package/src/specimen/Specimen.stories.tsx +13 -0
- package/src/specimen/Specimen.test.tsx +13 -0
- package/src/specimen/Specimen.tsx +888 -0
- package/src/state/Persistence.stories.tsx +75 -0
- package/src/state/Persistence.tsx +33 -0
- package/src/state/SingletonExperiment.test.tsx +47 -53
- package/src/state/SingletonExperiment.tsx +24 -13
- package/src/state/adapterContract.ts +116 -0
- package/src/state/adapters.test.ts +113 -61
- package/src/state/adapters.ts +328 -69
- package/src/state/document.test.ts +71 -96
- package/src/state/document.ts +66 -52
- package/src/state/helpers.test.ts +1 -1
- package/src/state/index.ts +8 -0
- package/src/state/labRecords.test.ts +105 -0
- package/src/state/labRecords.ts +160 -0
- package/src/state/openLabStore.test.ts +658 -0
- package/src/state/openLabStore.ts +403 -0
- package/src/state/records.test.ts +234 -0
- package/src/state/records.ts +219 -0
- package/src/state/store.test.ts +169 -635
- package/src/state/store.ts +146 -163
- package/src/state/toolSlot.test.ts +1 -1
- package/src/state/types.ts +65 -17
- package/src/state/useOpenOnce.ts +68 -0
- package/src/state/usePersistedState.test.tsx +125 -0
- package/src/state/usePersistedState.ts +66 -0
- package/src/state/useTrialState.test.tsx +87 -3
- package/src/state/useTrialState.ts +9 -1
- package/src/state/view.test.ts +49 -15
- package/src/state/view.ts +18 -1
- package/src/styles.less +3 -0
- package/src/surface/AGENTS.md +39 -7
- package/src/surface/SurfaceContext.ts +26 -3
- package/src/surface/index.ts +2 -0
- package/src/surface/useSurfaceTile.test.tsx +1 -0
- package/src/surface/useSurfaceTile.ts +6 -5
- package/src/surface/useTiledSurface.test.tsx +231 -1
- package/src/surface/useTiledSurface.ts +76 -15
- package/src/theme/Interstellar.stories.tsx +9 -9
- package/src/theme/interstellar.test.ts +17 -6
- package/src/theme/interstellar.theme.json +180 -0
- package/src/theme/interstellar.ts +8 -5
- package/src/tools/labTool.ts +11 -0
- package/src/trial/Trial.annotations.persist.test.tsx +100 -58
- package/src/trial/Trial.annotations.test.tsx +59 -7
- package/src/trial/Trial.canvas.test.tsx +32 -0
- package/src/trial/Trial.config.test.tsx +75 -2
- package/src/trial/Trial.job.test.tsx +3 -3
- package/src/trial/Trial.less +5 -26
- package/src/trial/Trial.stories.tsx +5 -3
- package/src/trial/Trial.test.tsx +31 -4
- package/src/trial/Trial.trialId.test.tsx +23 -1
- package/src/trial/Trial.tsx +139 -52
- package/src/trial/TrialBody.tsx +17 -141
- package/src/trial/TrialChrome.tsx +24 -7
- package/src/trial/trialOps.test.ts +101 -1
- package/src/trial/trialOps.ts +67 -7
- package/dist/_dts/types-BP2OCcpg.d.ts +0 -155
- package/dist/_dts/types-x92Kfeme.d.ts +0 -62
- package/dist/_dts/useTrialState-D6Vb3T-g.d.ts +0 -99
- package/dist/chunk-2P6PP5N4.js +0 -553
- package/dist/chunk-2P6PP5N4.js.map +0 -1
- package/dist/chunk-64ZCN3DA.js.map +0 -1
- package/dist/chunk-CTRKTLYZ.js.map +0 -1
- package/dist/chunk-E44SU6XS.js +0 -50
- package/dist/chunk-E44SU6XS.js.map +0 -1
- package/dist/chunk-FQMJUVHJ.js.map +0 -1
- package/dist/chunk-I6JCVE24.js.map +0 -1
- package/dist/chunk-MOM3GOVY.js.map +0 -1
- package/dist/chunk-SMHP6XZ4.js.map +0 -1
- package/dist/chunk-TJ7QY3OC.js.map +0 -1
- package/dist/chunk-U3IYHIAE.js +0 -343
- package/dist/chunk-U3IYHIAE.js.map +0 -1
- package/dist/chunk-W3ECWC2K.js +0 -7335
- package/dist/chunk-W3ECWC2K.js.map +0 -1
- package/src/theme/interstellar.tokens.json +0 -61
package/src/config/types.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
PrefGroup,
|
|
3
|
+
PrefLeaf,
|
|
4
|
+
PrefNumberFormat,
|
|
5
|
+
PrefNumberUnit,
|
|
6
|
+
PrefRenderer,
|
|
7
|
+
} from '@weasel-js/ui';
|
|
2
8
|
|
|
3
9
|
/**
|
|
4
10
|
* Renders the control cell for one config leaf. Identical to weasel-ui's
|
|
@@ -25,6 +31,13 @@ export interface Annotations {
|
|
|
25
31
|
max?: number;
|
|
26
32
|
step?: number;
|
|
27
33
|
suffix?: string;
|
|
34
|
+
/** How a number's value is shown. `compact` abbreviates from a thousand up. */
|
|
35
|
+
format?: PrefNumberFormat;
|
|
36
|
+
/** Display-unit conversion for a number stored in a canonical unit — the
|
|
37
|
+
* value, its bounds and its step all convert at the control's edge. */
|
|
38
|
+
unit?: PrefNumberUnit;
|
|
39
|
+
/** A color leaf's value carries alpha (`#rrggbbaa`) and its row edits it. */
|
|
40
|
+
alpha?: boolean;
|
|
28
41
|
control?: string;
|
|
29
42
|
options?: readonly ConfigOption[];
|
|
30
43
|
placeholder?: string;
|
|
@@ -74,6 +87,10 @@ export interface SectionSpec {
|
|
|
74
87
|
* whether or not it was given a panel-wide `collapse`; a fold the reader
|
|
75
88
|
* has since toggled outranks it. */
|
|
76
89
|
collapsed?: boolean;
|
|
90
|
+
/** Where the section's rows put their labels, over the panel's `layout`. */
|
|
91
|
+
layout?: 'block' | 'inline';
|
|
92
|
+
/** How the section packs its rows, over the panel's `pack`. */
|
|
93
|
+
pack?: 'auto' | 'pairs' | 'one-up';
|
|
77
94
|
}
|
|
78
95
|
|
|
79
96
|
/** A schema resolved against a set of rules: the vocabulary weasel-ui renders,
|
|
@@ -95,12 +112,27 @@ export interface ResolvedConfig {
|
|
|
95
112
|
export interface SectionOption {
|
|
96
113
|
label: string;
|
|
97
114
|
collapsed?: boolean;
|
|
115
|
+
/** Where the section's rows put their labels, over the panel's `layout`. */
|
|
116
|
+
layout?: 'block' | 'inline';
|
|
117
|
+
/** How the section packs its rows, over the panel's `pack`. */
|
|
118
|
+
pack?: 'auto' | 'pairs' | 'one-up';
|
|
98
119
|
}
|
|
99
120
|
|
|
100
121
|
/** Per-node extras that do not belong on a `PrefLeaf`. */
|
|
101
122
|
export interface NodeOptions extends BranchOptions {
|
|
102
123
|
render?: ControlRenderer;
|
|
103
|
-
|
|
124
|
+
/** Errors for this leaf under `config`, the instrument's whole config. */
|
|
125
|
+
validate?: (leaf: PrefLeaf, config: Record<string, unknown>) => string[];
|
|
126
|
+
/** Computes this leaf's value while it is auto. Attaching one is what lets
|
|
127
|
+
* the ghosted control draw a real value and keeps the instrument off
|
|
128
|
+
* `?? compute()`. */
|
|
129
|
+
autoResolve?: (config: Record<string, unknown>) => unknown;
|
|
130
|
+
/** The leaf starts auto rather than pinned at its default. Set by
|
|
131
|
+
* `.initial(auto)`. */
|
|
132
|
+
unpinned?: boolean;
|
|
133
|
+
/** The leaf can never be auto: the row takes no pin dot and ignores the
|
|
134
|
+
* gesture. For a value the instrument cannot receive as `undefined`. */
|
|
135
|
+
manual?: boolean;
|
|
104
136
|
}
|
|
105
137
|
|
|
106
138
|
/** What a branch can say about itself, beyond its children. */
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { resolveAutoConfig } from './autoConfig';
|
|
3
|
+
import type { ResolvedConfig } from './types';
|
|
4
|
+
|
|
5
|
+
const NONE: ReadonlySet<string> = new Set();
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The config an instrument reads: the stored one with every unpinned path
|
|
9
|
+
* resolved. The single place resolution happens, so `Trial` and
|
|
10
|
+
* `useTrialState` cannot disagree about what an instrument is looking at.
|
|
11
|
+
*/
|
|
12
|
+
export function useResolvedConfig<TC>(
|
|
13
|
+
schema: ResolvedConfig | undefined,
|
|
14
|
+
config: TC,
|
|
15
|
+
autoPaths: readonly string[] | undefined,
|
|
16
|
+
): { config: TC; auto: ReadonlySet<string> } {
|
|
17
|
+
const auto = useMemo(
|
|
18
|
+
() => (autoPaths && autoPaths.length > 0 ? new Set(autoPaths) : NONE),
|
|
19
|
+
[autoPaths],
|
|
20
|
+
);
|
|
21
|
+
const resolvedConfig = useMemo(
|
|
22
|
+
() => (schema ? resolveAutoConfig(schema, config, auto) : config),
|
|
23
|
+
[schema, config, auto],
|
|
24
|
+
);
|
|
25
|
+
return { config: resolvedConfig, auto };
|
|
26
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@weasel-js/forge';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { applyConfigWrite } from '../config/autoConfig';
|
|
4
|
+
import { f } from '../config/builder';
|
|
5
|
+
import { resolveConfigSchema } from '../config/resolve';
|
|
6
|
+
import { ControlPanel } from './ControlPanel';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The ghosting and the muted accent are CSS, and jsdom resolves neither
|
|
10
|
+
* `var()` nor `color-mix()`. This story is the only place they can be checked.
|
|
11
|
+
*/
|
|
12
|
+
const meta: Meta<typeof ControlPanel> = {
|
|
13
|
+
title: 'labkit/Controls/AutoControls',
|
|
14
|
+
component: ControlPanel,
|
|
15
|
+
parameters: { layout: 'padded' },
|
|
16
|
+
};
|
|
17
|
+
export default meta;
|
|
18
|
+
|
|
19
|
+
type Story = StoryObj<typeof ControlPanel>;
|
|
20
|
+
|
|
21
|
+
const schema = f.schema({
|
|
22
|
+
width: f.number(432).range(64, 1024).label('Width'),
|
|
23
|
+
gap: f
|
|
24
|
+
.number(12)
|
|
25
|
+
.range(0, 48)
|
|
26
|
+
.suffix('px')
|
|
27
|
+
.auto((c) => Math.round((c.width as number) / 24))
|
|
28
|
+
.label('Gap'),
|
|
29
|
+
cols: f.number(3).range(1, 12).label('Columns'),
|
|
30
|
+
wave: f.enum('sine', ['sine', 'square', 'triangle']).label('Wave'),
|
|
31
|
+
mode: f.enum('fit', ['fit', 'fill']).radio().label('Mode'),
|
|
32
|
+
showGrid: f.boolean(true).label('Show grid'),
|
|
33
|
+
title: f.string('My experiment').placeholder('Title…').label('Title'),
|
|
34
|
+
tint: f.color('#3a86ff').label('Tint'),
|
|
35
|
+
seed: f.number(1).range(0, 99).manual().label('Seed'),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const resolved = resolveConfigSchema(schema, []);
|
|
39
|
+
|
|
40
|
+
/** Every path the panel will draw ghosted, except the `.manual()` one. */
|
|
41
|
+
const EVERY_AUTO = ['gap', 'cols', 'wave', 'mode', 'showGrid', 'title', 'tint'];
|
|
42
|
+
|
|
43
|
+
function Panel({ start }: { start: readonly string[] }) {
|
|
44
|
+
const [state, setState] = useState(() => ({
|
|
45
|
+
config: schema.defaults() as Record<string, unknown>,
|
|
46
|
+
autoPaths: start,
|
|
47
|
+
}));
|
|
48
|
+
return (
|
|
49
|
+
<ControlPanel
|
|
50
|
+
schema={resolved}
|
|
51
|
+
config={state.config}
|
|
52
|
+
auto={new Set(state.autoPaths)}
|
|
53
|
+
setConfig={(path, value) =>
|
|
54
|
+
setState((prev) => applyConfigWrite(prev.config, prev.autoPaths, path, value))
|
|
55
|
+
}
|
|
56
|
+
/>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function Pair() {
|
|
61
|
+
return (
|
|
62
|
+
<div style={{ display: 'flex', gap: 32, alignItems: 'flex-start' }}>
|
|
63
|
+
<div style={{ flex: '1 1 0', minWidth: 0 }}>
|
|
64
|
+
<h3>Pinned</h3>
|
|
65
|
+
<Panel start={[]} />
|
|
66
|
+
</div>
|
|
67
|
+
<div style={{ flex: '1 1 0', minWidth: 0 }}>
|
|
68
|
+
<h3>Auto</h3>
|
|
69
|
+
<Panel start={EVERY_AUTO} />
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Both states of every row kind, side by side. What to look at: an auto row's
|
|
77
|
+
* control keeps no accent color, its readout reads `auto · 18 px` rather than a
|
|
78
|
+
* number, and the pin dot appears only under the pointer — except on an auto
|
|
79
|
+
* row, where it stays. `Seed` is `.manual()` and takes no dot at all.
|
|
80
|
+
*/
|
|
81
|
+
export const BothStates: Story = {
|
|
82
|
+
render: () => <Pair />,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/** One panel to shift-click around in: the handle must not move as it toggles. */
|
|
86
|
+
export const Interactive: Story = {
|
|
87
|
+
render: () => <Panel start={['gap']} />,
|
|
88
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ANGLE_RADIANS, prefUnit } from '@weasel-js/core';
|
|
2
|
+
import type { Meta, StoryObj } from '@weasel-js/forge';
|
|
2
3
|
import { PropertyRow } from '@weasel-js/ui';
|
|
3
4
|
import { useState } from 'react';
|
|
4
5
|
import { f } from '../config/builder';
|
|
@@ -234,3 +235,43 @@ export const Nested: Story = {
|
|
|
234
235
|
);
|
|
235
236
|
},
|
|
236
237
|
};
|
|
238
|
+
|
|
239
|
+
const degrees = prefUnit(ANGLE_RADIANS, 'deg', { precision: 1 });
|
|
240
|
+
|
|
241
|
+
const presentation = f.schema({
|
|
242
|
+
x: f.number(120).label('X').pair('Offset'),
|
|
243
|
+
y: f.number(-40).label('Y').pair('Offset'),
|
|
244
|
+
spin: f
|
|
245
|
+
.number(Math.PI / 4)
|
|
246
|
+
.range(0, Math.PI * 2)
|
|
247
|
+
.unit(degrees)
|
|
248
|
+
.label('Rotation'),
|
|
249
|
+
nudge: f
|
|
250
|
+
.number(Math.PI / 180)
|
|
251
|
+
.input()
|
|
252
|
+
.unit(degrees)
|
|
253
|
+
.label('Nudge'),
|
|
254
|
+
tint: f.color('#3a86ffcc').alpha().label('Tint'),
|
|
255
|
+
opaque: f.color('#3a86ff').label('Grid'),
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
/** The three presentation fields a leaf can declare: `pair` puts `X` and `Y`
|
|
259
|
+
* on one row the pair names, `unit` stores radians and edits degrees, and
|
|
260
|
+
* `alpha` gives the swatch an opacity track and stores `#rrggbbaa`. The dump
|
|
261
|
+
* shows what each control actually wrote. */
|
|
262
|
+
export const Presentation: Story = {
|
|
263
|
+
render: () => {
|
|
264
|
+
const schema = resolveConfigSchema(presentation, []);
|
|
265
|
+
const [config, setConfig] = useState<Record<string, unknown>>(presentation.defaults());
|
|
266
|
+
return (
|
|
267
|
+
<>
|
|
268
|
+
<ControlPanel
|
|
269
|
+
schema={schema}
|
|
270
|
+
config={config}
|
|
271
|
+
setConfig={(path, value) => setConfig((prev) => withValueAtPath(prev, path, value))}
|
|
272
|
+
/>
|
|
273
|
+
<pre>{JSON.stringify(config, null, 2)}</pre>
|
|
274
|
+
</>
|
|
275
|
+
);
|
|
276
|
+
},
|
|
277
|
+
};
|