@weasel-js/labkit 1.7.3 → 1.8.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 +24 -0
- package/dist/_dts/{CanvasStackContext-Cjy6I-Iv.d.ts → CanvasStackContext-B05ZM04l.d.ts} +3 -1
- package/dist/_dts/{Stage-D6t7o0pF.d.ts → Stage-CIJlbjrE.d.ts} +5 -3
- package/dist/_dts/{index-DCMA4Fy1.d.ts → index-8geQNQet.d.ts} +84 -12
- package/dist/_dts/{index-BTmaRy6a.d.ts → index-DRi3V5sN.d.ts} +6 -4
- package/dist/_dts/{types-BUBSIZuV.d.ts → types-DUfQ0isU.d.ts} +5 -1
- package/dist/_dts/{useTrialState-Bh8bzFgE.d.ts → useTrialState-Ar0AFpCe.d.ts} +94 -87
- package/dist/canvas/index.d.ts +5 -5
- package/dist/canvas/index.js +2 -2
- package/dist/chrome/index.d.ts +3 -3
- package/dist/chrome/index.js +7 -7
- package/dist/{chunk-HBGH344L.js → chunk-4RCVWX4M.js} +55 -18
- package/dist/chunk-4RCVWX4M.js.map +1 -0
- package/dist/{chunk-WIG6XHJ7.js → chunk-6IIKLXBZ.js} +13 -4
- package/dist/chunk-6IIKLXBZ.js.map +1 -0
- package/dist/{chunk-F4ACIK7Z.js → chunk-6Q6ACJ3H.js} +3 -3
- package/dist/{chunk-F4ACIK7Z.js.map → chunk-6Q6ACJ3H.js.map} +1 -1
- package/dist/{chunk-PMLZP7RT.js → chunk-7ALJOVGP.js} +5 -9
- package/dist/chunk-7ALJOVGP.js.map +1 -0
- package/dist/{chunk-XE5HJOPL.js → chunk-7FMZT2WL.js} +3 -3
- package/dist/{chunk-XE5HJOPL.js.map → chunk-7FMZT2WL.js.map} +1 -1
- package/dist/{chunk-XVUKDSYV.js → chunk-AVOILDN2.js} +2 -2
- package/dist/{chunk-XVUKDSYV.js.map → chunk-AVOILDN2.js.map} +1 -1
- package/dist/{chunk-2N7UBSS2.js → chunk-J5MDJEOZ.js} +3 -3
- package/dist/{chunk-2N7UBSS2.js.map → chunk-J5MDJEOZ.js.map} +1 -1
- package/dist/{chunk-LPGBC63T.js → chunk-KHB3KRRQ.js} +7 -7
- package/dist/chunk-KHB3KRRQ.js.map +1 -0
- package/dist/{chunk-IBVRMHW5.js → chunk-NHIO2O3O.js} +31 -30
- package/dist/chunk-NHIO2O3O.js.map +1 -0
- package/dist/{chunk-EESJUSYR.js → chunk-QMAY74TP.js} +56 -5
- package/dist/chunk-QMAY74TP.js.map +1 -0
- package/dist/{chunk-4X44DMRS.js → chunk-RN7T7OBO.js} +46 -24
- package/dist/chunk-RN7T7OBO.js.map +1 -0
- package/dist/{chunk-4TJ34FXA.js → chunk-RXO5UEGT.js} +5 -12
- package/dist/chunk-RXO5UEGT.js.map +1 -0
- package/dist/{chunk-E6NARGU7.js → chunk-SQX35X5V.js} +3 -3
- package/dist/{chunk-E6NARGU7.js.map → chunk-SQX35X5V.js.map} +1 -1
- package/dist/{chunk-YCFKW5RX.js → chunk-T5OEUNCB.js} +16 -2
- package/dist/chunk-T5OEUNCB.js.map +1 -0
- package/dist/{chunk-RL2LOLNI.js → chunk-UX66USTN.js} +2 -2
- package/dist/chunk-UX66USTN.js.map +1 -0
- package/dist/{chunk-IRMPZIYU.js → chunk-V4SMGEYY.js} +6732 -6507
- package/dist/chunk-V4SMGEYY.js.map +1 -0
- package/dist/{chunk-E23Q6A3Y.js → chunk-VCK5T6EP.js} +3 -3
- package/dist/{chunk-E23Q6A3Y.js.map → chunk-VCK5T6EP.js.map} +1 -1
- package/dist/{chunk-T6DLGEJB.js → chunk-XWR2P6MR.js} +23 -6
- package/dist/chunk-XWR2P6MR.js.map +1 -0
- package/dist/{chunk-XSJJTXNA.js → chunk-YZA73U4A.js} +19 -19
- package/dist/chunk-YZA73U4A.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 +5 -5
- package/dist/dragdrop/index.d.ts +2 -2
- package/dist/dragdrop/index.js +2 -2
- package/dist/index.d.ts +158 -16
- package/dist/index.js +1036 -415
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +2 -2
- package/dist/layers/index.js +3 -3
- package/dist/loupe/index.d.ts +176 -28
- package/dist/loupe/index.js +547 -141
- package/dist/loupe/index.js.map +1 -1
- package/dist/overview/index.d.ts +1 -1
- package/dist/overview/index.js +5 -5
- package/dist/passthrough/weasel-ui.js +3 -3
- package/dist/primitives/index.d.ts +4 -19
- package/dist/primitives/index.js +7 -7
- package/dist/state/index.d.ts +6 -8
- package/dist/state/index.js +5 -5
- package/dist/styles.css +181 -44
- package/dist/surface/index.d.ts +20 -1
- package/dist/surface/index.js +2 -2
- package/dist/undo/index.d.ts +19 -8
- package/dist/undo/index.js +1 -1
- package/package.json +11 -11
- package/src/annotations/AnnotationOverlay.abandon.test.tsx +4 -0
- package/src/annotations/AnnotationOverlay.tsx +10 -1
- package/src/annotations/Annotations.less +2 -0
- package/src/annotations/Annotations.overlay.test.tsx +29 -0
- package/src/canvas/CanvasStack.test.tsx +35 -0
- package/src/canvas/CanvasStack.tsx +12 -1
- package/src/canvas/useLayerScheduler.ts +14 -0
- package/src/chrome/builtins.test.ts +14 -0
- package/src/chrome/builtins.tsx +17 -2
- package/src/chrome/regions/StatusRegion.tsx +20 -14
- package/src/chrome/regions/regions.test.tsx +28 -0
- package/src/chrome/types.ts +8 -0
- package/src/clock/clock.browser.test.less +5 -0
- package/src/clock/clock.browser.test.tsx +77 -0
- package/src/clock/clock.integration.test.tsx +95 -0
- package/src/clock/clockRegistry.test.ts +33 -0
- package/src/clock/clockRegistry.ts +46 -0
- package/src/clock/hooks.ts +44 -0
- package/src/clock/index.ts +2 -0
- package/src/clock/trialClock.test.ts +265 -0
- package/src/clock/trialClock.ts +245 -0
- package/src/clock/useClockLoop.ts +45 -0
- package/src/config/builder.ts +11 -1
- package/src/config/resolve.test.ts +12 -0
- package/src/config/resolve.ts +5 -0
- package/src/config/types.ts +5 -1
- package/src/controls/ControlMatrix.test.tsx +10 -0
- package/src/controls/ControlMatrix.tsx +110 -58
- package/src/controls/ControlPanel.test.tsx +30 -0
- package/src/index.ts +3 -2
- package/src/instrument/types.ts +21 -1
- package/src/lab/Lab.chrome.test.tsx +8 -1
- package/src/lab/Lab.presentation.test.tsx +113 -0
- package/src/lab/Lab.surface.test.tsx +20 -9
- package/src/lab/Lab.tsx +132 -257
- package/src/lab/LabLightbox.browser.test.less +17 -0
- package/src/lab/LabLightbox.browser.test.tsx +216 -0
- package/src/lab/LabShell.less +10 -3
- package/src/lab/LabSurface.tsx +129 -0
- package/src/lab/Workspace.stories.tsx +18 -0
- package/src/lab/Workspace.surface.test.tsx +4 -0
- package/src/lab/Workspace.test.tsx +37 -1
- package/src/lab/Workspace.tsx +34 -6
- package/src/lab/index.ts +2 -0
- package/src/lab/nebula.ts +30 -0
- package/src/lab/openLab.test.ts +81 -0
- package/src/lab/openLab.ts +119 -0
- package/src/lab/presentation.browser.test.less +5 -0
- package/src/lab/presentation.browser.test.tsx +119 -0
- package/src/lab/presentation.less +64 -0
- package/src/lab/presentation.tsx +47 -0
- package/src/lab/useFocusPick.ts +43 -0
- package/src/lightbox/Lightbox.browser.test.less +14 -0
- package/src/lightbox/Lightbox.browser.test.tsx +113 -0
- package/src/lightbox/Lightbox.less +128 -0
- package/src/lightbox/Lightbox.test.tsx +195 -0
- package/src/lightbox/Lightbox.tsx +205 -0
- package/src/lightbox/LightboxContext.ts +38 -0
- package/src/lightbox/LightboxLayers.tsx +40 -0
- package/src/lightbox/index.ts +8 -0
- package/src/lightbox/modal.ts +94 -0
- package/src/loupe/AGENTS.md +40 -2
- package/src/loupe/CanvasLoupe.tsx +5 -4
- package/src/loupe/DomLoupe.tsx +7 -5
- package/src/loupe/Loupe.less +15 -0
- package/src/loupe/LoupeBubble.tsx +35 -13
- package/src/loupe/SourceLoupe.browser.test.tsx +204 -0
- package/src/loupe/SourceLoupe.tsx +60 -0
- package/src/loupe/TrialLoupe.browser.test.tsx +342 -0
- package/src/loupe/TrialLoupe.tsx +126 -28
- package/src/loupe/canvasLens.ts +20 -17
- package/src/loupe/index.ts +26 -2
- package/src/loupe/sourceLens.test.ts +65 -0
- package/src/loupe/sourceLens.ts +97 -0
- package/src/loupe/types.test.ts +6 -0
- package/src/loupe/types.ts +109 -7
- package/src/loupe/useLoupe.test.tsx +188 -3
- package/src/loupe/useLoupe.ts +106 -11
- package/src/primitives/index.ts +2 -2
- package/src/specimen/Specimen.tsx +0 -7
- package/src/state/helpers.test.ts +4 -11
- package/src/state/helpers.ts +2 -8
- package/src/state/index.ts +0 -2
- package/src/state/openLabStore.test.ts +10 -8
- package/src/state/openLabStore.ts +1 -1
- package/src/state/store.test.ts +2 -2
- package/src/state/store.ts +15 -16
- package/src/state/types.ts +9 -9
- package/src/styles.less +2 -1
- package/src/surface/AGENTS.md +13 -0
- package/src/surface/index.ts +1 -0
- package/src/surface/useSurfaceTile.test.tsx +4 -0
- package/src/surface/useSurfaceTile.ts +17 -1
- package/src/surface/useTiledSurface.test.tsx +65 -0
- package/src/surface/useTiledSurface.ts +68 -1
- package/src/theme/interstellar.theme.json +0 -14
- package/src/trial/Trial.stories.tsx +0 -1
- package/src/trial/Trial.test.tsx +40 -3
- package/src/trial/Trial.tsx +87 -43
- package/src/trial/TrialChrome.tsx +20 -2
- package/src/trial/trialOps.test.ts +1 -2
- package/src/trial/trialOps.ts +2 -3
- package/src/undo/stateOp.ts +21 -0
- package/src/undo/undoStack.ts +18 -6
- package/dist/chunk-4TJ34FXA.js.map +0 -1
- package/dist/chunk-4X44DMRS.js.map +0 -1
- package/dist/chunk-EESJUSYR.js.map +0 -1
- package/dist/chunk-HBGH344L.js.map +0 -1
- package/dist/chunk-IBVRMHW5.js.map +0 -1
- package/dist/chunk-IRMPZIYU.js.map +0 -1
- package/dist/chunk-LPGBC63T.js.map +0 -1
- package/dist/chunk-PMLZP7RT.js.map +0 -1
- package/dist/chunk-RL2LOLNI.js.map +0 -1
- package/dist/chunk-T6DLGEJB.js.map +0 -1
- package/dist/chunk-WIG6XHJ7.js.map +0 -1
- package/dist/chunk-XSJJTXNA.js.map +0 -1
- package/dist/chunk-YCFKW5RX.js.map +0 -1
- package/src/primitives/StatusBar.less +0 -34
- package/src/primitives/StatusBar.stories.tsx +0 -24
- package/src/primitives/StatusBar.test.tsx +0 -25
- package/src/primitives/StatusBar.tsx +0 -28
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useSurfaceOptional } from './chunk-
|
|
1
|
+
import { useSurfaceOptional } from './chunk-6IIKLXBZ.js';
|
|
2
2
|
import { CameraContext, pointerElsewhere, STAGE_VIEW_ID, normalize2DView, useCameraView, CameraScope, CameraInput } from './chunk-VYVGVBGY.js';
|
|
3
3
|
import { resolveFrame, DEFAULT_FRAME } from './chunk-ULYYNWGP.js';
|
|
4
4
|
import { CanvasStackContext } from './chunk-ZQIHJXP4.js';
|
|
@@ -53,7 +53,8 @@ function useLayerScheduler({
|
|
|
53
53
|
frame = DEFAULT_FRAME,
|
|
54
54
|
canvasRefs,
|
|
55
55
|
size,
|
|
56
|
-
host
|
|
56
|
+
host,
|
|
57
|
+
ticks
|
|
57
58
|
}) {
|
|
58
59
|
const dirty = useRef(/* @__PURE__ */ new Set());
|
|
59
60
|
const lastRenderRef = useRef(/* @__PURE__ */ new Map());
|
|
@@ -98,6 +99,13 @@ function useLayerScheduler({
|
|
|
98
99
|
useEffect(() => {
|
|
99
100
|
if (dirty.current.size > 0) frameLoop.request();
|
|
100
101
|
});
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (!ticks || !layers.some((l) => l.timed)) return;
|
|
104
|
+
return ticks(() => {
|
|
105
|
+
for (const layer of layers) if (layer.timed) dirty.current.add(layer.id);
|
|
106
|
+
frameLoop.request();
|
|
107
|
+
});
|
|
108
|
+
}, [ticks, layers, frameLoop]);
|
|
101
109
|
}
|
|
102
110
|
function CanvasStack({
|
|
103
111
|
layers,
|
|
@@ -112,7 +120,8 @@ function CanvasStack({
|
|
|
112
120
|
onResize,
|
|
113
121
|
onHitTest,
|
|
114
122
|
children,
|
|
115
|
-
yoke
|
|
123
|
+
yoke,
|
|
124
|
+
ticks
|
|
116
125
|
}) {
|
|
117
126
|
const view = normalize2DView(viewProp);
|
|
118
127
|
const containerRef = useRef(null);
|
|
@@ -159,7 +168,15 @@ function CanvasStack({
|
|
|
159
168
|
() => ({ view: camera, frame, element: () => containerRef.current }),
|
|
160
169
|
[camera, frame]
|
|
161
170
|
);
|
|
162
|
-
useLayerScheduler({
|
|
171
|
+
useLayerScheduler({
|
|
172
|
+
layers,
|
|
173
|
+
view,
|
|
174
|
+
frame,
|
|
175
|
+
canvasRefs: canvasMap,
|
|
176
|
+
size,
|
|
177
|
+
host: containerRef,
|
|
178
|
+
ticks
|
|
179
|
+
});
|
|
163
180
|
const ctxValue = useMemo(
|
|
164
181
|
() => ({
|
|
165
182
|
view,
|
|
@@ -296,5 +313,5 @@ function Stage({
|
|
|
296
313
|
}
|
|
297
314
|
|
|
298
315
|
export { CanvasStack, LinkedCursor, Stage, fitStage };
|
|
299
|
-
//# sourceMappingURL=chunk-
|
|
300
|
-
//# sourceMappingURL=chunk-
|
|
316
|
+
//# sourceMappingURL=chunk-XWR2P6MR.js.map
|
|
317
|
+
//# sourceMappingURL=chunk-XWR2P6MR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/canvas/LinkedCursor.tsx","../src/canvas/useLayerScheduler.ts","../src/canvas/CanvasStack.tsx","../src/canvas/Stage.tsx"],"names":["useRef","useEffect","jsx","jsxs","useMemo","useLatest"],"mappings":";;;;;;;;AAKA,IAAM,IAAA,GAAO,CAAC,MAAA,EAAQ,OAAA,EAAS,MAAM,MAAM,CAAA;AAOpC,SAAS,YAAA,GAAe;AAC7B,EAAA,MAAM,MAAA,GAAS,WAAW,aAAa,CAAA;AACvC,EAAA,MAAM,UAAU,kBAAA,EAAmB;AACnC,EAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,EAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,OAAA,EAAS,aAAA,EAAe,OAAO,KAAK,CAAA;AACnE,EAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AAGnB,EAAA,MAAM,CAAA,GAAI,MAAA,CAAO,IAAA,CAAK,GAAA,EAAI;AAC1B,EAAA,MAAM,KAAK,KAAA,CAAM,CAAA,GAAI,CAAA,CAAE,CAAA,IAAK,EAAE,KAAA,CAAM,CAAA;AACpC,EAAA,MAAM,CAAA,GAAA,CAAK,MAAM,CAAA,GAAI,MAAA,CAAO,MAAM,IAAA,GAAO,CAAA,CAAE,CAAA,IAAK,CAAA,CAAE,KAAA,CAAM,CAAA;AACxD,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,KAAS,cAAA,CAAe,CAAA,EAAG,GAAG,CAAC,CAAA;AAC7C,EAAA,MAAM,OAAO,IAAA,CAAK,GAAA,CAAI,CAAC,IAAA,EAAM,OAAO,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,CAAK,CAAC,CAAA,EAAG,GAAA,EAAK,IAAA,CAAK,CAAC,GAAE,CAAE,CAAA;AAC1E,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,kBAAA,EAAmB,eAAY,MAAA,EAC3C,QAAA,EAAA;AAAA,IAAA,IAAA,CAAK,GAAA;AAAA,MAAI,CAAC,EAAE,IAAA,EAAM,IAAA,EAAM,CAAA,OACvB,CAAA,mBACE,GAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UAEC,SAAA,EAAU,wBAAA;AAAA,UACV,GAAG,CAAA,CAAE,CAAA;AAAA,UACL,GAAG,CAAA,CAAE,CAAA;AAAA,UACL,OAAO,CAAA,CAAE,CAAA;AAAA,UACT,QAAQ,CAAA,CAAE;AAAA,SAAA;AAAA,QALL,QAAQ,IAAI,CAAA;AAAA,OAMnB,GACE;AAAA,KACN;AAAA,IACC,IAAA,CAAK,GAAA;AAAA,MAAI,CAAC,EAAE,IAAA,EAAM,GAAA,EAAK,CAAA,OACtB,CAAA,mBACE,GAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UAEC,SAAA,EAAU,uBAAA;AAAA,UACV,GAAG,CAAA,CAAE,CAAA;AAAA,UACL,GAAG,CAAA,CAAE,CAAA;AAAA,UACL,OAAO,CAAA,CAAE,CAAA;AAAA,UACT,QAAQ,CAAA,CAAE;AAAA,SAAA;AAAA,QALL,OAAO,IAAI,CAAA;AAAA,OAMlB,GACE;AAAA;AACN,GAAA,EACF,CAAA;AAEJ;ACvBO,SAAS,iBAAA,CAAkB;AAAA,EAChC,MAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA,GAAQ,aAAA;AAAA,EACR,UAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,EAA2B;AACzB,EAAA,MAAM,KAAA,GAAQ,MAAA,iBAAoB,IAAI,GAAA,EAAK,CAAA;AAC3C,EAAA,MAAM,aAAA,GAAgB,MAAA,iBAAqD,IAAI,GAAA,EAAK,CAAA;AAEpF,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,MAAA,MAAM,IAAA,GAAO,aAAA,CAAc,OAAA,CAAQ,GAAA,CAAI,MAAM,EAAE,CAAA;AAC/C,MAAA,IAAI,SAAS,KAAA,CAAM,MAAA,QAAc,OAAA,CAAQ,GAAA,CAAI,MAAM,EAAE,CAAA;AACrD,MAAA,aAAA,CAAc,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,EAAA,EAAI,MAAM,MAAM,CAAA;AAAA,IAClD;AACA,IAAA,KAAA,MAAW,MAAM,CAAC,GAAG,cAAc,OAAA,CAAQ,IAAA,EAAM,CAAA,EAAG;AAClD,MAAA,IAAI,CAAC,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAA,EAAG,aAAA,CAAc,OAAA,CAAQ,MAAA,CAAO,EAAE,CAAA;AAAA,IACvE;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAGX,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,KAAA,MAAW,SAAS,MAAA,EAAQ,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,MAAM,EAAE,CAAA;AAAA,EACxD,GAAG,CAAC,IAAA,EAAM,KAAA,EAAO,IAAA,EAAM,MAAM,CAAC,CAAA;AAK9B,EAAA,MAAM,SAAA,GAAY,aAAA;AAAA,IAChB,MAAM;AACJ,MAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,IAAA,KAAS,CAAA,EAAG;AAC9B,MAAA,MAAM,MAAM,UAAA,CAAW,OAAA;AACvB,MAAA,IAAI,CAAC,GAAA,EAAK;AACR,QAAA,KAAA,CAAM,QAAQ,KAAA,EAAM;AACpB,QAAA;AAAA,MACF;AACA,MAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,QAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,EAAE,CAAA,EAAG;AAClC,QAAA,IAAI,CAAC,MAAM,OAAA,EAAS;AACpB,QAAA,MAAM,MAAA,GAAS,GAAA,CAAI,GAAA,CAAI,KAAA,CAAM,EAAE,CAAA;AAC/B,QAAA,IAAI,CAAC,MAAA,EAAQ;AACb,QAAA,MAAM,GAAA,GAAM,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AAClC,QAAA,IAAI,CAAC,GAAA,EAAK;AACV,QAAA,GAAA,CAAI,IAAA,EAAK;AACT,QAAA,GAAA,CAAI,YAAA,CAAa,KAAK,GAAA,EAAK,CAAA,EAAG,GAAG,IAAA,CAAK,GAAA,EAAK,GAAG,CAAC,CAAA;AAC/C,QAAA,GAAA,CAAI,UAAU,CAAA,EAAG,CAAA,EAAG,IAAA,CAAK,KAAA,EAAO,KAAK,MAAM,CAAA;AAC3C,QAAA,KAAA,CAAM,MAAA,CAAO,GAAA,EAAK,IAAA,EAAM,KAAK,CAAA;AAC7B,QAAA,GAAA,CAAI,OAAA,EAAQ;AAAA,MACd;AACA,MAAA,KAAA,CAAM,QAAQ,KAAA,EAAM;AAAA,IACtB,CAAA;AAAA,IACA,EAAE,QAAQ,IAAA;AAAK,GACjB;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,IAAA,GAAO,CAAA,YAAa,OAAA,EAAQ;AAAA,EAChD,CAAC,CAAA;AAED,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,SAAS,CAAC,MAAA,CAAO,KAAK,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,CAAA,EAAG;AAC5C,IAAA,OAAO,MAAM,MAAM;AACjB,MAAA,KAAA,MAAW,KAAA,IAAS,QAAQ,IAAI,KAAA,CAAM,OAAO,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,EAAE,CAAA;AACvE,MAAA,SAAA,CAAU,OAAA,EAAQ;AAAA,IACpB,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,KAAA,EAAO,MAAA,EAAQ,SAAS,CAAC,CAAA;AAC/B;AC1DO,SAAS,WAAA,CAAY;AAAA,EAC1B,MAAA;AAAA,EACA,IAAA,EAAM,QAAA;AAAA,EACN,YAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA,GAAQ,MAAA;AAAA,EACR,MAAA,GAAS,MAAA;AAAA,EACT,SAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,EAAqB;AACnB,EAAA,MAAM,IAAA,GAAO,gBAAgB,QAAQ,CAAA;AACrC,EAAA,MAAM,YAAA,GAAeA,OAA8B,IAAI,CAAA;AACvD,EAAA,MAAM,SAAA,GAAYA,MAAAA,iBAAuC,IAAI,GAAA,EAAK,CAAA;AAClE,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,QAAA,CAAS,EAAE,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,EAAG,GAAA,EAAK,CAAA,EAAG,CAAA;AAEhE,EAAA,MAAM,YAAA,GAAe,CAAC,EAAA,EAAY,EAAA,KAAuC;AACvE,IAAA,IAAI,EAAA,EAAI,SAAA,CAAU,OAAA,CAAQ,GAAA,CAAI,IAAI,EAAE,CAAA;AAAA,SAC/B,SAAA,CAAU,OAAA,CAAQ,MAAA,CAAO,EAAE,CAAA;AAAA,EAClC,CAAA;AAEA,EAAAC,UAAU,MAAM;AACd,IAAA,MAAM,KAAK,YAAA,CAAa,OAAA;AACxB,IAAA,IAAI,CAAC,EAAA,EAAI;AACT,IAAA,MAAM,SAAS,MAAM;AACnB,MAAA,MAAM,IAAA,GAAO,GAAG,qBAAA,EAAsB;AACtC,MAAA,MAAM,GAAA,GAAM,OAAO,gBAAA,IAAoB,CAAA;AACvC,MAAA,OAAA,CAAQ,CAAC,IAAA,KAAS;AAChB,QAAA,IAAI,IAAA,CAAK,KAAA,KAAU,IAAA,CAAK,KAAA,IAAS,IAAA,CAAK,WAAW,IAAA,CAAK,MAAA,IAAU,IAAA,CAAK,GAAA,KAAQ,GAAA,EAAK;AAChF,UAAA,OAAO,IAAA;AAAA,QACT;AACA,QAAA,OAAO,EAAE,KAAA,EAAO,IAAA,CAAK,OAAO,MAAA,EAAQ,IAAA,CAAK,QAAQ,GAAA,EAAI;AAAA,MACvD,CAAC,CAAA;AAAA,IACH,CAAA;AACA,IAAA,MAAA,EAAO;AACP,IAAA,IAAI,OAAO,mBAAmB,WAAA,EAAa;AAC3C,IAAA,MAAM,EAAA,GAAK,IAAI,cAAA,CAAe,MAAM,CAAA;AACpC,IAAA,EAAA,CAAG,QAAQ,EAAE,CAAA;AACb,IAAA,OAAO,MAAM,GAAG,UAAA,EAAW;AAAA,EAC7B,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,WAAA,GAAc,UAAU,QAAQ,CAAA;AACtC,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,IAAA,CAAK,KAAA,KAAU,CAAA,IAAK,IAAA,CAAK,WAAW,CAAA,EAAG;AAC3C,IAAA,WAAA,CAAY,OAAA,GAAU,EAAE,KAAA,EAAO,IAAA,CAAK,OAAO,MAAA,EAAQ,IAAA,CAAK,QAAQ,CAAA;AAAA,EAClE,GAAG,CAAC,IAAA,CAAK,OAAO,IAAA,CAAK,MAAA,EAAQ,WAAW,CAAC,CAAA;AAEzC,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,MAAM,YAAA,CAAa,SAAA,EAAW,IAAI,CAAA,EAAG,CAAC,SAAA,EAAW,IAAI,CAAC,CAAA;AAE5E,EAAA,MAAM,SAAS,aAAA,CAAc;AAAA,IAC3B,IAAA,EAAM,QAAA;AAAA,IACN,YAAA;AAAA,IACA,KAAA;AAAA,IACA,OAAA,EAAS,YAAA;AAAA,IACT,OAAA;AAAA,IACA;AAAA,GACD,CAAA;AACD,EAAA,MAAM,SAAA,GAAY,OAAA;AAAA,IAChB,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAO,OAAA,EAAS,MAAM,aAAa,OAAA,EAAQ,CAAA;AAAA,IAClE,CAAC,QAAQ,KAAK;AAAA,GAChB;AACA,EAAA,iBAAA,CAAkB;AAAA,IAChB,MAAA;AAAA,IACA,IAAA;AAAA,IACA,KAAA;AAAA,IACA,UAAA,EAAY,SAAA;AAAA,IACZ,IAAA;AAAA,IACA,IAAA,EAAM,YAAA;AAAA,IACN;AAAA,GACD,CAAA;AAED,EAAA,MAAM,QAAA,GAAW,OAAA;AAAA,IACf,OAAO;AAAA,MACL,IAAA;AAAA,MACA,KAAA;AAAA,MACA,OAAA,EAAS,EAAE,OAAA,EAAS,YAAA,EAAc,MAAM,QAAA,EAAU,SAAA,EAAW,QAAQ,SAAA;AAAU,KACjF,CAAA;AAAA,IACA,CAAC,IAAA,EAAM,KAAA,EAAO,IAAA,EAAM,QAAQ,SAAS;AAAA,GACvC;AAEA,EAAA,MAAM,cAAA,GAAgC,EAAE,KAAA,EAAO,MAAA,EAAO;AACtD,EAAA,MAAM,QAAA,GAAW;AAAA,IACf,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,MAAM,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,IACpD,MAAA,EAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,MAAM,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,GAAG,CAAC;AAAA,GACxD;AACA,EAAA,MAAM,SAAA,GAA2B;AAAA,IAC/B,OAAO,IAAA,CAAK,KAAA;AAAA,IACZ,QAAQ,IAAA,CAAK;AAAA,GACf;AAEA,EAAA,uBACEC,GAAAA,CAAC,WAAA,EAAA,EAAY,IAAA,EACX,QAAA,kBAAAA,IAAC,aAAA,CAAc,QAAA,EAAd,EAAuB,KAAA,EAAO,WAC7B,QAAA,kBAAAC,IAAAA,CAAC,mBAAmB,QAAA,EAAnB,EAA4B,OAAO,QAAA,EAClC,QAAA,EAAA;AAAA,oBAAAD,IAAC,WAAA,EAAA,EAAY,OAAA,EAAS,cAAc,MAAA,EAAgB,KAAA,EAAc,OAAO,SAAA,EAAW,CAAA;AAAA,oBACpFC,IAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,YAAA;AAAA,QACL,SAAA,EAAW,SAAA,GAAY,CAAA,gBAAA,EAAmB,SAAS,CAAA,CAAA,GAAK,iBAAA;AAAA,QACxD,KAAA,EAAO,cAAA;AAAA,QAEN,QAAA,EAAA;AAAA,UAAA,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,qBACXD,GAAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cAEC,KAAK,CAAC,EAAA,KAAO,YAAA,CAAa,KAAA,CAAM,IAAI,EAAE,CAAA;AAAA,cACtC,SAAA,EAAU,yBAAA;AAAA,cACV,OAAO,QAAA,CAAS,KAAA;AAAA,cAChB,QAAQ,QAAA,CAAS,MAAA;AAAA,cACjB,KAAA,EAAO,EAAE,GAAG,SAAA,EAAW,SAAS,KAAA,CAAM,OAAA,GAAU,UAAU,MAAA;AAAO,aAAA;AAAA,YAL5D,KAAA,CAAM;AAAA,WAOd,CAAA;AAAA,0BACDA,IAAC,YAAA,EAAA,EAAa,CAAA;AAAA,0BACdA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4BAA4B,QAAA,EAAS;AAAA;AAAA;AAAA;AACtD,GAAA,EACF,GACF,CAAA,EACF,CAAA;AAEJ;AChIO,SAAS,QAAA,CAAS,MAAoB,QAAA,EAAuC;AAClF,EAAA,IAAI,EAAE,IAAA,CAAK,KAAA,GAAQ,CAAA,IAAK,IAAA,CAAK,MAAA,GAAS,CAAA,IAAK,QAAA,CAAS,KAAA,GAAQ,CAAA,IAAK,QAAA,CAAS,MAAA,GAAS,CAAA,CAAA,EAAI;AACrF,IAAA,OAAO,EAAE,MAAM,CAAA,EAAG,GAAA,EAAK,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAE,EAAE;AAAA,EACxC;AACA,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,QAAA,CAAS,KAAA,GAAQ,IAAA,CAAK,KAAA,EAAO,QAAA,CAAS,MAAA,GAAS,IAAA,CAAK,MAAM,CAAA;AACnF,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,GAAA,EAAK;AAAA,MACH,CAAA,EAAA,CAAI,QAAA,CAAS,KAAA,GAAQ,IAAA,CAAK,QAAQ,IAAA,IAAQ,CAAA;AAAA,MAC1C,CAAA,EAAA,CAAI,QAAA,CAAS,MAAA,GAAS,IAAA,CAAK,SAAS,IAAA,IAAQ;AAAA;AAC9C,GACF;AACF;AASO,SAAS,KAAA,CAAM;AAAA,EACpB,IAAA;AAAA,EACA,IAAA,EAAM,QAAA;AAAA,EACN,YAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAAe;AACb,EAAA,MAAM,IAAA,GAAO,gBAAgB,QAAQ,CAAA;AACrC,EAAA,MAAM,IAAA,GAAOF,OAA8B,IAAI,CAAA;AAC/C,EAAA,MAAM,UAAU,kBAAA,EAAmB;AACnC,EAAA,MAAM,SAAS,aAAA,CAAc;AAAA,IAC3B,IAAA,EAAM,QAAA;AAAA,IACN,YAAA;AAAA,IACA,KAAA,EAAO,aAAA;AAAA,IACP,OAAA,EAAS,IAAA;AAAA,IACT,OAAA;AAAA,IACA;AAAA,GACD,CAAA;AACD,EAAA,MAAM,SAAA,GAAYI,OAAAA;AAAA,IAChB,OAAO;AAAA,MACL,IAAA,EAAM,MAAA;AAAA,MACN,KAAA,EAAO,aAAA;AAAA,MACP,OAAA,EAAS,MAAM,IAAA,CAAK,OAAA;AAAA,MACpB,OAAA,EAAS,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO,MAAA,EAAQ,IAAA,CAAK,MAAA;AAAO,KAChE,CAAA;AAAA,IACA,CAAC,MAAA,EAAQ,IAAA,CAAK,KAAA,EAAO,KAAK,MAAM;AAAA,GAClC;AAEA,EAAA,MAAM,WAAA,GAAcC,UAAU,QAAQ,CAAA;AACtC,EAAAJ,UAAU,MAAM;AACd,IAAA,MAAM,KAAK,IAAA,CAAK,OAAA;AAChB,IAAA,IAAI,CAAC,EAAA,EAAI;AACT,IAAA,MAAM,UAAU,MAAM;AACpB,MAAA,MAAM,IAAA,GAAO,GAAG,qBAAA,EAAsB;AACtC,MAAA,IAAI,IAAA,CAAK,KAAA,GAAQ,CAAA,IAAK,IAAA,CAAK,SAAS,CAAA,EAAG;AACrC,QAAA,WAAA,CAAY,OAAA,GAAU,EAAE,KAAA,EAAO,IAAA,CAAK,OAAO,MAAA,EAAQ,IAAA,CAAK,QAAQ,CAAA;AAAA,MAClE;AAAA,IACF,CAAA;AACA,IAAA,OAAA,EAAQ;AACR,IAAA,IAAI,OAAO,mBAAmB,WAAA,EAAa;AAC3C,IAAA,MAAM,EAAA,GAAK,IAAI,cAAA,CAAe,OAAO,CAAA;AACrC,IAAA,EAAA,CAAG,QAAQ,EAAE,CAAA;AACb,IAAA,OAAO,MAAM,GAAG,UAAA,EAAW;AAAA,EAC7B,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAKhB,EAAAA,UAAU,MAAM;AACd,IAAA,OAAA,EAAS,eAAA,EAAgB;AAAA,EAC3B,CAAA,EAAG,CAAC,OAAA,EAAS,IAAA,CAAK,IAAA,EAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAC,CAAC,CAAA;AAK/C,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,CAAC,cAAwB,GAAG,CAAA,EAAG,IAAA,CAAK,IAAI,CAAC,CAAA,EAAA,CAAA;AAAA,IACzC,CAAC,cAAwB,GAAG,CAAA,EAAG,IAAA,CAAK,IAAI,CAAC,CAAA,EAAA,CAAA;AAAA,IACzC,CAAC,iBAA2B,GAAG,MAAA,CAAO,KAAK,IAAI,CAAA;AAAA,IAC/C,CAAC,cAAwB,GAAG,CAAA,EAAG,KAAK,KAAK,CAAA,EAAA,CAAA;AAAA,IACzC,CAAC,cAAwB,GAAG,CAAA,EAAG,KAAK,MAAM,CAAA,EAAA;AAAA,GAC5C;AAEA,EAAA,uBACEC,GAAAA,CAAC,WAAA,EAAA,EAAY,IAAA,EACX,QAAA,kBAAAC,KAAC,aAAA,CAAc,QAAA,EAAd,EAAuB,KAAA,EAAO,SAAA,EAC7B,QAAA,EAAA;AAAA,oBAAAD,IAAC,WAAA,EAAA,EAAY,OAAA,EAAS,IAAA,EAAM,MAAA,EAAgB,OAAO,aAAA,EAAe,CAAA;AAAA,oBAClEC,IAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,CAAC,EAAA,KAAO;AACX,UAAA,IAAA,CAAK,OAAA,GAAU,EAAA;AACf,UAAA,IAAI,OAAA,UAAiB,OAAA,GAAU,EAAA;AAAA,QACjC,CAAA;AAAA,QACA,SAAA,EAAU,UAAA;AAAA,QAEV,QAAA,EAAA;AAAA,0BAAAD,IAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mBAAA,EAAoB,KAAA,EAAO,YACvC,QAAA,EACH,CAAA;AAAA,0BACAA,IAAC,YAAA,EAAA,EAAa,CAAA;AAAA,UACb;AAAA;AAAA;AAAA;AACH,GAAA,EACF,CAAA,EACF,CAAA;AAEJ","file":"chunk-XWR2P6MR.js","sourcesContent":["import { crosshairRects, usePointerPosition } from '@weasel-js/core';\nimport { useContext } from 'react';\nimport { CameraContext, pointerElsewhere, STAGE_VIEW_ID } from './CameraInput';\n\n/** `crosshairRects` returns its four arms in this order. */\nconst ARMS = ['left', 'right', 'up', 'down'] as const;\n\n/**\n * The other side of a linked cursor: a crosshair on the camera's own element\n * wherever the shared pointer is over some other view — an overview, say. The\n * same crosshair core paints on a weasel canvas.\n */\nexport function LinkedCursor() {\n const camera = useContext(CameraContext);\n const pointer = usePointerPosition();\n if (!camera) return null;\n const local = pointerElsewhere(pointer, STAGE_VIEW_ID, camera.frame);\n if (!local) return null;\n // `pointerElsewhere` hands back the instrument's world; the camera works\n // frame-local, and the map is its own inverse.\n const v = camera.view.get();\n const x = (local.x - v.x) * v.scale.x;\n const y = (local.y * camera.frame.yDir - v.y) * v.scale.y;\n const { halo, bars } = crosshairRects(x, y, 1);\n const arms = ARMS.map((name, i) => ({ name, halo: halo[i], bar: bars[i] }));\n return (\n <svg className=\"lk-linked-cursor\" aria-hidden=\"true\">\n {arms.map(({ name, halo: r }) =>\n r ? (\n <rect\n key={`halo-${name}`}\n className=\"lk-linked-cursor__halo\"\n x={r.x}\n y={r.y}\n width={r.w}\n height={r.h}\n />\n ) : null,\n )}\n {arms.map(({ name, bar: r }) =>\n r ? (\n <rect\n key={`bar-${name}`}\n className=\"lk-linked-cursor__bar\"\n x={r.x}\n y={r.y}\n width={r.w}\n height={r.h}\n />\n ) : null,\n )}\n </svg>\n );\n}\n","import { useVisibleRaf } from '@weasel-js/core';\nimport { type RefObject, useEffect, useRef } from 'react';\nimport type { ViewTransform } from '../instrument/types';\nimport { DEFAULT_FRAME, type WorldFrame } from './worldSpec';\n\n/** One layer of a canvas stack: its id, whether it is currently shown, and how\n * it paints itself. */\nexport interface CanvasLayerDescriptor {\n id: string;\n visible: boolean;\n /** Repaint on every `ticks` frame, not only when `render` or the view change. */\n timed?: boolean;\n render: (ctx: CanvasRenderingContext2D, view: ViewTransform, frame: WorldFrame) => void;\n}\n\ninterface SchedulerOptions {\n layers: CanvasLayerDescriptor[];\n view: ViewTransform;\n /** The instrument's coordinate system, resolved against `size`. */\n frame?: WorldFrame;\n canvasRefs: RefObject<Map<string, HTMLCanvasElement>>;\n size: { width: number; height: number; dpr: number };\n /** The element the stack occupies. Given one, the scheduler also stops while\n * the stack sits outside the viewport. */\n host?: RefObject<Element | null>;\n /** Subscribes to frames — a trial clock's — after each of which every timed\n * layer repaints. Returns the unsubscribe. */\n ticks?: (fn: () => void) => () => void;\n}\n\nexport function useLayerScheduler({\n layers,\n view,\n frame = DEFAULT_FRAME,\n canvasRefs,\n size,\n host,\n ticks,\n}: SchedulerOptions): void {\n const dirty = useRef<Set<string>>(new Set());\n const lastRenderRef = useRef<Map<string, CanvasLayerDescriptor['render']>>(new Map());\n\n useEffect(() => {\n for (const layer of layers) {\n const prev = lastRenderRef.current.get(layer.id);\n if (prev !== layer.render) dirty.current.add(layer.id);\n lastRenderRef.current.set(layer.id, layer.render);\n }\n for (const id of [...lastRenderRef.current.keys()]) {\n if (!layers.find((l) => l.id === id)) lastRenderRef.current.delete(id);\n }\n }, [layers]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: re-mark dirty when view or size changes\n useEffect(() => {\n for (const layer of layers) dirty.current.add(layer.id);\n }, [view, frame, size, layers]);\n\n // Painting only what is dirty is not the same as doing nothing: a hidden tab\n // still commits React updates, and the effect above marks every layer dirty\n // on any view or size change. The gate is what actually stops the work.\n const frameLoop = useVisibleRaf(\n () => {\n if (dirty.current.size === 0) return;\n const map = canvasRefs.current;\n if (!map) {\n dirty.current.clear();\n return;\n }\n for (const layer of layers) {\n if (!dirty.current.has(layer.id)) continue;\n if (!layer.visible) continue;\n const canvas = map.get(layer.id);\n if (!canvas) continue;\n const ctx = canvas.getContext('2d');\n if (!ctx) continue;\n ctx.save();\n ctx.setTransform(size.dpr, 0, 0, size.dpr, 0, 0);\n ctx.clearRect(0, 0, size.width, size.height);\n layer.render(ctx, view, frame);\n ctx.restore();\n }\n dirty.current.clear();\n },\n { target: host },\n );\n\n useEffect(() => {\n if (dirty.current.size > 0) frameLoop.request();\n });\n\n useEffect(() => {\n if (!ticks || !layers.some((l) => l.timed)) return;\n return ticks(() => {\n for (const layer of layers) if (layer.timed) dirty.current.add(layer.id);\n frameLoop.request();\n });\n }, [ticks, layers, frameLoop]);\n}\n","import type { Yoke } from '@weasel-js/core';\nimport { useLatest } from '@weasel-js/core';\nimport { type CSSProperties, type ReactNode, useEffect, useMemo, useRef, useState } from 'react';\nimport type { Point, ViewTransform } from '../instrument/types';\nimport { normalize2DView } from '../state/view';\nimport { CameraContext, CameraInput, CameraScope, useCameraView } from './CameraInput';\nimport { CanvasStackContext } from './CanvasStackContext';\nimport { LinkedCursor } from './LinkedCursor';\nimport { type CanvasLayerDescriptor, useLayerScheduler } from './useLayerScheduler';\nimport { resolveFrame, type ViewportSize, type WorldSpec } from './worldSpec';\n\n/** Props for `<CanvasStack>`. */\nexport interface CanvasStackProps {\n layers: CanvasLayerDescriptor[];\n view: ViewTransform;\n onViewChange: (v: ViewTransform) => void;\n /** The instrument's coordinate system. Omitted, world (0,0) sits at the\n * element's top-left with y running down. */\n worldSpec?: WorldSpec;\n minZoom?: number;\n maxZoom?: number;\n width?: number | string;\n height?: number | string;\n className?: string;\n /** Fired whenever the stack is measured, so a consumer can place a view that\n * only makes sense in terms of the viewport. */\n onResize?: (size: ViewportSize) => void;\n onHitTest?: (worldPos: Point) => void;\n children?: ReactNode;\n /** A yoke to join, from `useYoke()`: cameras on one yoke share their tool\n * and gesture in flight. Omitted, this one keeps its own. */\n yoke?: Yoke;\n /** Frames after each of which every `timed` layer repaints — a trial clock's. */\n ticks?: (fn: () => void) => () => void;\n}\n\n/** Stacks one `<canvas>` per layer and drives them from a shared view, so a\n * layer that changes rarely is not redrawn with one that changes every frame.\n * Handles sizing and device pixel ratio; pan and zoom route through weasel's\n * gesture dispatcher (`<CameraInput>`). */\nexport function CanvasStack({\n layers,\n view: viewProp,\n onViewChange,\n worldSpec,\n minZoom,\n maxZoom,\n width = '100%',\n height = '100%',\n className,\n onResize,\n onHitTest,\n children,\n yoke,\n ticks,\n}: CanvasStackProps) {\n const view = normalize2DView(viewProp);\n const containerRef = useRef<HTMLDivElement | null>(null);\n const canvasMap = useRef<Map<string, HTMLCanvasElement>>(new Map());\n const [size, setSize] = useState({ width: 0, height: 0, dpr: 1 });\n\n const setCanvasRef = (id: string, el: HTMLCanvasElement | null): void => {\n if (el) canvasMap.current.set(id, el);\n else canvasMap.current.delete(id);\n };\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const update = () => {\n const rect = el.getBoundingClientRect();\n const dpr = window.devicePixelRatio ?? 1;\n setSize((prev) => {\n if (prev.width === rect.width && prev.height === rect.height && prev.dpr === dpr) {\n return prev;\n }\n return { width: rect.width, height: rect.height, dpr };\n });\n };\n update();\n if (typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(update);\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n const onResizeRef = useLatest(onResize);\n useEffect(() => {\n if (size.width === 0 && size.height === 0) return;\n onResizeRef.current?.({ width: size.width, height: size.height });\n }, [size.width, size.height, onResizeRef]);\n\n const frame = useMemo(() => resolveFrame(worldSpec, size), [worldSpec, size]);\n\n const camera = useCameraView({\n view: viewProp,\n onViewChange,\n frame,\n hostRef: containerRef,\n minZoom,\n maxZoom,\n });\n const cameraCtx = useMemo(\n () => ({ view: camera, frame, element: () => containerRef.current }),\n [camera, frame],\n );\n useLayerScheduler({\n layers,\n view,\n frame,\n canvasRefs: canvasMap,\n size,\n host: containerRef,\n ticks,\n });\n\n const ctxValue = useMemo(\n () => ({\n view,\n frame,\n surface: { element: containerRef, size, canvases: canvasMap, layers, worldSpec },\n }),\n [view, frame, size, layers, worldSpec],\n );\n\n const containerStyle: CSSProperties = { width, height };\n const canvasPx = {\n width: Math.max(0, Math.round(size.width * size.dpr)),\n height: Math.max(0, Math.round(size.height * size.dpr)),\n };\n const canvasCss: CSSProperties = {\n width: size.width,\n height: size.height,\n };\n\n return (\n <CameraScope yoke={yoke}>\n <CameraContext.Provider value={cameraCtx}>\n <CanvasStackContext.Provider value={ctxValue}>\n <CameraInput hostRef={containerRef} camera={camera} frame={frame} onTap={onHitTest} />\n <div\n ref={containerRef}\n className={className ? `lk-canvas-stack ${className}` : 'lk-canvas-stack'}\n style={containerStyle}\n >\n {layers.map((layer) => (\n <canvas\n key={layer.id}\n ref={(el) => setCanvasRef(layer.id, el)}\n className=\"lk-canvas-stack__canvas\"\n width={canvasPx.width}\n height={canvasPx.height}\n style={{ ...canvasCss, display: layer.visible ? 'block' : 'none' }}\n />\n ))}\n <LinkedCursor />\n <div className=\"lk-canvas-stack__overlay\">{children}</div>\n </div>\n </CanvasStackContext.Provider>\n </CameraContext.Provider>\n </CameraScope>\n );\n}\n","import type { Yoke } from '@weasel-js/core';\nimport { useLatest } from '@weasel-js/core';\nimport { type CSSProperties, type ReactNode, useEffect, useMemo, useRef } from 'react';\nimport type { ViewTransform } from '../instrument/types';\nimport { normalize2DView } from '../state/view';\nimport { useSurfaceOptional } from '../surface/useSurfaceTile';\nimport { CameraContext, CameraInput, CameraScope, useCameraView } from './CameraInput';\nimport { LinkedCursor } from './LinkedCursor';\nimport { DEFAULT_FRAME, type ViewportSize } from './worldSpec';\n\n/** Props for `<Stage>`. */\nexport interface StageProps {\n /** The content's own size in CSS pixels, at zoom 1. */\n size: ViewportSize;\n view: ViewTransform;\n onViewChange: (v: ViewTransform) => void;\n minZoom?: number;\n maxZoom?: number;\n /** Fired whenever the stage's viewport is measured at a non-zero size. */\n onResize?: (viewport: ViewportSize) => void;\n /** Handed the viewport element, for a consumer tracking the pointer over it. */\n hostRef?: { current: HTMLDivElement | null };\n /** Drawn over the content in viewport pixels, outside the camera. */\n overlay?: ReactNode;\n children?: ReactNode;\n /** A yoke to join, from `useYoke()`: cameras on one yoke share their tool\n * and gesture in flight. Omitted, this one keeps its own. */\n yoke?: Yoke;\n}\n\n/**\n * The camera a stage opens at: the content centered in its viewport, shrunk to\n * fit if it has to be and never enlarged past its own size.\n */\nexport function fitStage(size: ViewportSize, viewport: ViewportSize): ViewTransform {\n if (!(size.width > 0 && size.height > 0 && viewport.width > 0 && viewport.height > 0)) {\n return { zoom: 1, pan: { x: 0, y: 0 } };\n }\n const zoom = Math.min(1, viewport.width / size.width, viewport.height / size.height);\n return {\n zoom,\n pan: {\n x: (viewport.width - size.width * zoom) / 2,\n y: (viewport.height - size.height * zoom) / 2,\n },\n };\n}\n\n/**\n * DOM content of a fixed size, panned and zoomed by a camera — what\n * `<CanvasStack>` is for layers drawn to a canvas. Pan and zoom route through\n * weasel's gesture dispatcher (`<CameraInput>`). The content is laid out at\n * its own size and transformed, so everything inside keeps its layout and a\n * measurement of any element in it reports where it is actually drawn.\n */\nexport function Stage({\n size,\n view: viewProp,\n onViewChange,\n minZoom,\n maxZoom,\n onResize,\n hostRef,\n overlay,\n children,\n yoke,\n}: StageProps) {\n const view = normalize2DView(viewProp);\n const host = useRef<HTMLDivElement | null>(null);\n const surface = useSurfaceOptional();\n const camera = useCameraView({\n view: viewProp,\n onViewChange,\n frame: DEFAULT_FRAME,\n hostRef: host,\n minZoom,\n maxZoom,\n });\n const cameraCtx = useMemo(\n () => ({\n view: camera,\n frame: DEFAULT_FRAME,\n element: () => host.current,\n content: { x: 0, y: 0, width: size.width, height: size.height },\n }),\n [camera, size.width, size.height],\n );\n\n const onResizeRef = useLatest(onResize);\n useEffect(() => {\n const el = host.current;\n if (!el) return;\n const measure = () => {\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) {\n onResizeRef.current?.({ width: rect.width, height: rect.height });\n }\n };\n measure();\n if (typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, [onResizeRef]);\n\n // A transform moves every tile inside the content without resizing anything,\n // and a ResizeObserver reports only resizes.\n // biome-ignore lint/correctness/useExhaustiveDependencies: the camera is the trigger, not an input — the effect re-measures whenever it moves.\n useEffect(() => {\n surface?.invalidateRects();\n }, [surface, view.zoom, view.pan.x, view.pan.y]);\n\n // The camera changes every frame of a pan, and a transform has nowhere to\n // live but the element's own style: set as custom properties the stylesheet\n // reads.\n const cameraVars = {\n ['--lk-stage-x' as string]: `${view.pan.x}px`,\n ['--lk-stage-y' as string]: `${view.pan.y}px`,\n ['--lk-stage-zoom' as string]: String(view.zoom),\n ['--lk-stage-w' as string]: `${size.width}px`,\n ['--lk-stage-h' as string]: `${size.height}px`,\n } as CSSProperties;\n\n return (\n <CameraScope yoke={yoke}>\n <CameraContext.Provider value={cameraCtx}>\n <CameraInput hostRef={host} camera={camera} frame={DEFAULT_FRAME} />\n <div\n ref={(el) => {\n host.current = el;\n if (hostRef) hostRef.current = el;\n }}\n className=\"lk-stage\"\n >\n <div className=\"lk-stage__content\" style={cameraVars}>\n {children}\n </div>\n <LinkedCursor />\n {overlay}\n </div>\n </CameraContext.Provider>\n </CameraScope>\n );\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fromConfigFields, isLeafVisible } from './chunk-WLMDTI2Q.js';
|
|
2
2
|
import { resolveAutoConfig, valueAtPath, schemaNodeAtPath, auto } from './chunk-READTDQX.js';
|
|
3
|
-
import { v,
|
|
3
|
+
import { v, le, ce2, l6, ye, v2, L2, b3, d3, c, B, be } from './chunk-V4SMGEYY.js';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import { isBuiltinToolPref, toHex8, withAlpha01, getAlpha01 } from '@weasel-js/core';
|
|
6
6
|
import { useMemo, useState, useRef, useEffect, Fragment as Fragment$1 } from 'react';
|
|
@@ -42,7 +42,7 @@ var NO_AUTO = /* @__PURE__ */ new Set();
|
|
|
42
42
|
function leavesUnder(group, at) {
|
|
43
43
|
return Object.entries(group.children).flatMap(([key, child]) => {
|
|
44
44
|
const path = at === "" ? key : `${at}.${key}`;
|
|
45
|
-
return
|
|
45
|
+
return d3(child) ? [[path, child.default]] : leavesUnder(child, path);
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
function ResetGroup({
|
|
@@ -52,7 +52,7 @@ function ResetGroup({
|
|
|
52
52
|
setConfig
|
|
53
53
|
}) {
|
|
54
54
|
const changed = leavesUnder(group, path).filter(
|
|
55
|
-
([p,
|
|
55
|
+
([p, d2]) => !Object.is(valueAtPath(config, p), d2)
|
|
56
56
|
);
|
|
57
57
|
return /* @__PURE__ */ jsx(
|
|
58
58
|
c,
|
|
@@ -64,7 +64,7 @@ function ResetGroup({
|
|
|
64
64
|
tooltip: `Reset ${group.name} to defaults`,
|
|
65
65
|
disabled: changed.length === 0,
|
|
66
66
|
onClick: () => {
|
|
67
|
-
for (const [p,
|
|
67
|
+
for (const [p, d2] of changed) setConfig(p, d2);
|
|
68
68
|
},
|
|
69
69
|
children: /* @__PURE__ */ jsx(B, {})
|
|
70
70
|
}
|
|
@@ -124,7 +124,7 @@ function ControlPanel({
|
|
|
124
124
|
const found = schemaNodeAtPath(resolved.group, path);
|
|
125
125
|
if (!found) return null;
|
|
126
126
|
if (!isLeafVisible(resolved, path, config, showHidden)) return null;
|
|
127
|
-
if (
|
|
127
|
+
if (d3(found)) {
|
|
128
128
|
return /* @__PURE__ */ jsx(
|
|
129
129
|
ControlRow,
|
|
130
130
|
{
|
|
@@ -167,7 +167,7 @@ function ControlPanel({
|
|
|
167
167
|
};
|
|
168
168
|
const pairable = (path) => {
|
|
169
169
|
const found = schemaNodeAtPath(resolved.group, path);
|
|
170
|
-
if (!found || !
|
|
170
|
+
if (!found || !d3(found)) return void 0;
|
|
171
171
|
const pair = extra(found, "pair");
|
|
172
172
|
if (pair === void 0) return void 0;
|
|
173
173
|
if (!isLeafVisible(resolved, path, config, showHidden))
|
|
@@ -237,7 +237,7 @@ function ControlPanel({
|
|
|
237
237
|
] });
|
|
238
238
|
};
|
|
239
239
|
const list = /* @__PURE__ */ jsx(
|
|
240
|
-
|
|
240
|
+
le,
|
|
241
241
|
{
|
|
242
242
|
pack: gridPack,
|
|
243
243
|
density,
|
|
@@ -247,7 +247,7 @@ function ControlPanel({
|
|
|
247
247
|
}
|
|
248
248
|
);
|
|
249
249
|
if (title === void 0 && stance === void 0 && tone === void 0) return list;
|
|
250
|
-
return /* @__PURE__ */ jsx(
|
|
250
|
+
return /* @__PURE__ */ jsx(ce2, { title, stance, tone, density, children: list });
|
|
251
251
|
}
|
|
252
252
|
function sectionKey(section) {
|
|
253
253
|
return section.at === "" ? section.label : `${section.at}.${section.label}`;
|
|
@@ -319,16 +319,16 @@ function ControlRow({
|
|
|
319
319
|
case "string":
|
|
320
320
|
return /* @__PURE__ */ jsx(DebouncedTextRow, { leaf, field, span: wide, ...row });
|
|
321
321
|
case "number":
|
|
322
|
-
return /* @__PURE__ */ jsx(
|
|
322
|
+
return /* @__PURE__ */ jsx(ye, { ...field, ...row, span: field.control === "slider" && wide });
|
|
323
323
|
case "enum":
|
|
324
|
-
return /* @__PURE__ */ jsx(
|
|
324
|
+
return /* @__PURE__ */ jsx(ye, { ...field, ...row, span: field.control === "toggle" && wide });
|
|
325
325
|
default:
|
|
326
|
-
return /* @__PURE__ */ jsx(
|
|
326
|
+
return /* @__PURE__ */ jsx(ye, { ...field, ...row });
|
|
327
327
|
}
|
|
328
328
|
}
|
|
329
329
|
function labField(leaf, value, write) {
|
|
330
330
|
if (!isBuiltinToolPref(leaf) || leaf.kind === "paint" || leaf.kind === "object") return null;
|
|
331
|
-
const field =
|
|
331
|
+
const field = v2(leaf, { value, setValue: write });
|
|
332
332
|
if (field === null) return null;
|
|
333
333
|
switch (field.kind) {
|
|
334
334
|
case "number":
|
|
@@ -378,7 +378,7 @@ function DebouncedTextRow({
|
|
|
378
378
|
field.onChange,
|
|
379
379
|
extra(leaf, "debounceMs") ?? 150
|
|
380
380
|
);
|
|
381
|
-
return /* @__PURE__ */ jsx(
|
|
381
|
+
return /* @__PURE__ */ jsx(ye, { ...field, ...row, value: text.local, onChange: text.type });
|
|
382
382
|
}
|
|
383
383
|
function PairedRow({
|
|
384
384
|
label,
|
|
@@ -419,13 +419,13 @@ function PairCell({
|
|
|
419
419
|
if (field === null) return null;
|
|
420
420
|
switch (field.kind) {
|
|
421
421
|
case "string":
|
|
422
|
-
return /* @__PURE__ */ jsx(
|
|
422
|
+
return /* @__PURE__ */ jsx(be, { ...field, name: leaf.name, value: text.local, onChange: text.type });
|
|
423
423
|
case "number":
|
|
424
|
-
return /* @__PURE__ */ jsx(
|
|
424
|
+
return /* @__PURE__ */ jsx(be, { ...field, name: leaf.name, control: "input", unit: void 0 });
|
|
425
425
|
case "color": {
|
|
426
426
|
const stored = typeof value === "string" ? toHex8(value) : "#000000";
|
|
427
427
|
return /* @__PURE__ */ jsx(
|
|
428
|
-
|
|
428
|
+
be,
|
|
429
429
|
{
|
|
430
430
|
...field,
|
|
431
431
|
name: leaf.name,
|
|
@@ -435,7 +435,7 @@ function PairCell({
|
|
|
435
435
|
);
|
|
436
436
|
}
|
|
437
437
|
default:
|
|
438
|
-
return /* @__PURE__ */ jsx(
|
|
438
|
+
return /* @__PURE__ */ jsx(be, { ...field, name: leaf.name });
|
|
439
439
|
}
|
|
440
440
|
}
|
|
441
441
|
function useDebouncedText(value, write, debounceMs) {
|
|
@@ -470,5 +470,5 @@ function useDebouncedText(value, write, debounceMs) {
|
|
|
470
470
|
}
|
|
471
471
|
|
|
472
472
|
export { ControlPanel, ControlRow, inDialog, summarizeValue };
|
|
473
|
-
//# sourceMappingURL=chunk-
|
|
474
|
-
//# sourceMappingURL=chunk-
|
|
473
|
+
//# sourceMappingURL=chunk-YZA73U4A.js.map
|
|
474
|
+
//# sourceMappingURL=chunk-YZA73U4A.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/controls/inDialog.tsx","../src/controls/ControlPanel.tsx"],"names":["auto","d","jsx","Fragment","b","ce","value","l","v","L"],"mappings":"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","file":"chunk-YZA73U4A.js","sourcesContent":["import { DialogRow } from '@weasel-js/ui';\nimport type { ControlRenderer, InDialogOptions } from '../config/types';\n\nexport type { InDialogOptions };\n\n/** The one-line summary a dialog row shows when it is given none. */\nexport function summarizeValue(value: unknown): string {\n if (Array.isArray(value)) return value.length === 0 ? 'None' : value.join(', ');\n if (value === undefined || value === null || value === '') return 'None';\n return typeof value === 'object' ? JSON.stringify(value) : String(value);\n}\n\n/**\n * Moves a control into a modal: the row becomes a button showing a summary of\n * the value, and the button opens a dialog whose body is `body`, handed the\n * same context a row renderer gets. For a leaf whose editor will never fit a\n * sidebar row.\n */\nexport function inDialog(body: ControlRenderer, opts: InDialogOptions = {}): ControlRenderer {\n const summary = opts.summary ?? summarizeValue;\n return (ctx) => {\n const { pref, value, auto, setAuto } = ctx;\n const manual = (pref as { manual?: boolean }).manual === true;\n return (\n <DialogRow\n label={pref.name}\n description={pref.description}\n summary={summary(value)}\n title={opts.title}\n readout={auto ? 'auto' : undefined}\n auto={auto}\n onAutoChange={manual ? undefined : setAuto}\n >\n {() => body(ctx)}\n </DialogRow>\n );\n };\n}\n","import { getAlpha01, isBuiltinToolPref, toHex8, withAlpha01 } from '@weasel-js/core';\nimport {\n Button,\n DialogRow,\n isPrefLeaf,\n ListEditor,\n type PrefGroup,\n type PrefLeaf,\n type PropertyAlign,\n PropertyControl,\n type PropertyControlProps,\n type PropertyDensity,\n PropertyField,\n PropertyGroup,\n PropertyList,\n type PropertyListPack,\n PropertyPanel,\n PropertyRow,\n type PropertyRowLayout,\n prefFieldProps,\n ResetIcon,\n type StanceProps,\n} from '@weasel-js/ui';\nimport { Fragment, type ReactNode, useEffect, useMemo, useRef, useState } from 'react';\nimport { auto as autoValue } from '../config/auto';\nimport { resolveAutoConfig } from '../config/autoConfig';\nimport { fromConfigFields } from '../config/fromConfigField';\nimport { schemaNodeAtPath, valueAtPath } from '../config/path';\nimport type { ControlRenderer, ResolvedConfig, SectionSpec } from '../config/types';\nimport { isLeafVisible } from '../config/visible';\nimport { inDialog, summarizeValue } from './inDialog';\nimport type { ConfigField } from './types';\n\n/** How a panel packs its rows into the two-column property grid.\n * - `'auto'`: narrow controls (numbers, checkboxes, dropdowns, colors) sit\n * two per row; the ones that need the width — text, sliders, segmented\n * toggles — span it.\n * - `'pairs'`: every row pairs. A control that needs the full width says so\n * itself, with `<PropertyRow span>`.\n * - `'one-up'`: one control per row, colors excepted.\n */\nexport type ControlPack = 'auto' | 'pairs' | 'one-up';\n\n/** How the rows under one heading are laid out: the panel's, or a section's own. */\ninterface Rows {\n pack: ControlPack;\n layout: PropertyRowLayout | undefined;\n grid: PropertyListPack;\n}\n\nconst gridOf = (pack: ControlPack): PropertyListPack =>\n pack === 'one-up' ? 'auto-color' : 'pairs';\n\nfunction sectionRows(section: SectionSpec, rows: Rows): Rows {\n return {\n pack: section.pack ?? rows.pack,\n layout: section.layout ?? rows.layout,\n grid: section.pack ? gridOf(section.pack) : rows.grid,\n };\n}\n\nexport interface ControlPanelProps<TC extends Record<string, unknown>> extends StanceProps {\n /** The instrument's resolved config schema. */\n schema?: ResolvedConfig;\n /** @deprecated Pass `schema`. A field list is adapted into one internally. */\n fields?: ConfigField[];\n config: TC;\n /** Writes one value. The path is dotted for a leaf inside an `f.group`, and\n * the bare key for one at the root. */\n setConfig: (path: string, value: unknown) => void;\n /**\n * Control overrides and app-defined kinds, PrefsForm-style. Keys are config\n * paths (checked first) or leaf kinds. A renderer returning `null` collapses\n * the row; entries override the built-in rows on collision.\n */\n renderers?: Record<string, ControlRenderer>;\n /** How rows pack into the two-column grid. Defaults to `'pairs'`. */\n pack?: ControlPack;\n /**\n * Where a row's label sits relative to its control. Unset takes each row's\n * own orientation — `block` (label above, which is what leaves a paired row\n * room for its value) for most, `inline` for colors and checkboxes.\n */\n layout?: PropertyRowLayout;\n /** Room the rows get. Passed straight to the property list. */\n density?: PropertyDensity;\n /** Cross-axis alignment of an inline row's label and control. */\n align?: PropertyAlign;\n /**\n * Fold each section away behind a twisty, starting `'open'` or `'closed'`.\n * Unset draws the heading alone, as the panel always has — unless a section\n * in the schema declares how it opens, which makes that section foldable on\n * its own and outranks this for that one section.\n */\n collapse?: 'open' | 'closed';\n /**\n * Which sections are folded, keyed as `onCollapse` reports them. Given, the\n * panel keeps no state of its own: every toggle arrives at `onCollapse`\n * instead, which is where a lab that remembers a trial's sections writes\n * them.\n */\n collapsed?: Readonly<Record<string, boolean>>;\n /** A fold moved. The key is a section's label — prefixed by its group's\n * dotted path when the section sits inside one — or a group's own path. */\n onCollapse?: (key: string, collapsed: boolean) => void;\n /** Dotted paths currently unpinned. A row in this set hides its control and\n * reads out `auto`, and clicking its label writes the sentinel back through\n * `setConfig`. Omitted, the panel keeps the set itself: the labels still\n * toggle and the sentinel never reaches `setConfig`, which would otherwise\n * store it as the row's value. */\n auto?: ReadonlySet<string>;\n /** Draw leaves marked `hidden`. */\n showHidden?: boolean;\n /** Heads the panel. With `title`, `stance` or `tone` given, the rows sit in a\n * `<PropertyPanel>` carrying them; with none, they are the bare list. */\n title?: ReactNode;\n className?: string;\n}\n\nconst NO_AUTO: ReadonlySet<string> = new Set();\n\n/** Every leaf beneath a group, as its dotted path and its default. */\nfunction leavesUnder(group: PrefGroup, at: string): [string, unknown][] {\n return Object.entries(group.children).flatMap(([key, child]) => {\n const path = at === '' ? key : `${at}.${key}`;\n return isPrefLeaf(child)\n ? [[path, child.default] as [string, unknown]]\n : leavesUnder(child, path);\n });\n}\n\n/** The heading button of a `.resettable()` group: writes each changed leaf's\n * default, and is disabled while nothing has changed. */\nfunction ResetGroup({\n group,\n path,\n config,\n setConfig,\n}: {\n group: PrefGroup;\n path: string;\n config: Record<string, unknown>;\n setConfig: (path: string, value: unknown) => void;\n}) {\n const changed = leavesUnder(group, path).filter(\n ([p, d]) => !Object.is(valueAtPath(config, p), d),\n );\n return (\n <Button\n iconOnly\n variant=\"ghost\"\n size=\"sm\"\n ariaLabel={`Reset ${group.name}`}\n tooltip={`Reset ${group.name} to defaults`}\n disabled={changed.length === 0}\n onClick={() => {\n for (const [p, d] of changed) setConfig(p, d);\n }}\n >\n <ResetIcon />\n </Button>\n );\n}\n\n/** Render an instrument's config schema as a stack of controls, each writing\n * back through `setConfig`. Built on the property rows, so a lab's controls\n * are the same aligned, themed rows the rest of the kit uses. */\nexport function ControlPanel<TC extends Record<string, unknown>>({\n schema,\n fields,\n config,\n setConfig,\n renderers,\n pack = 'pairs',\n layout,\n density,\n align,\n collapse,\n collapsed,\n onCollapse,\n auto: given,\n showHidden = false,\n title,\n stance,\n tone,\n className,\n}: ControlPanelProps<TC>) {\n const resolved = useMemo(() => schema ?? fromConfigFields(fields ?? []), [schema, fields]);\n\n // An owner that tracks the set decides what a dot means; one that does not\n // gets a panel that decides for itself, because the alternative is handing it\n // a sentinel it would write into the config as though it were a value.\n const [ownAuto, setOwnAuto] = useState<ReadonlySet<string>>(NO_AUTO);\n const auto = given ?? ownAuto;\n const setRowAuto = (path: string, next: boolean, value: unknown): void => {\n if (given) {\n setConfig(path, next ? autoValue : value);\n return;\n }\n setOwnAuto((prev) => {\n const now = new Set(prev);\n if (next) now.add(path);\n else now.delete(path);\n return now;\n });\n // Pinning keeps whatever the row was showing, the same value the controlled\n // path writes back.\n if (!next) setConfig(path, value);\n };\n\n // What the instrument is reading. A row draws and reports from this rather\n // than calling its own resolver against the raw config, which would disagree\n // with the instrument whenever a resolver depends on another auto path.\n const shown = useMemo(\n () => (auto && auto.size > 0 ? resolveAutoConfig(resolved, config, auto) : config),\n [resolved, config, auto],\n );\n\n const gridPack = gridOf(pack);\n // A section that declares how it opens is foldable whether or not the lab\n // asked for folds — there is nothing else for the declaration to mean.\n const folds =\n collapse !== undefined ||\n collapsed !== undefined ||\n onCollapse !== undefined ||\n resolved.sections.some((s) => s.collapsed !== undefined);\n const startsFolded = collapse === 'closed';\n\n const fold = (key: string, declared?: boolean, grid: PropertyListPack = gridPack) => ({\n pack: grid,\n collapsible: folds,\n defaultCollapsed: declared ?? startsFolded,\n collapsed: collapsed ? (collapsed[key] ?? declared ?? startsFolded) : undefined,\n onCollapsedChange: onCollapse ? (next: boolean) => onCollapse(key, next) : undefined,\n });\n\n /** One node, which is either a group to recurse into or a row to draw. */\n const node = (path: string, rows: Rows): ReactNode => {\n const found = schemaNodeAtPath(resolved.group, path);\n if (!found) return null;\n if (!isLeafVisible(resolved, path, config as Record<string, unknown>, showHidden)) return null;\n if (isPrefLeaf(found)) {\n return (\n <ControlRow\n key={path}\n path={path}\n leaf={found}\n resolved={resolved}\n config={config}\n shown={shown}\n setConfig={setConfig}\n renderers={renderers}\n pack={rows.pack}\n layout={rows.layout}\n auto={auto}\n setRowAuto={setRowAuto}\n />\n );\n }\n // A group with no name organizes without heading it — core's rule for an\n // empty `PrefGroup.name` — so it contributes its rows and no chrome.\n if (found.name === '') return <Fragment key={path}>{body(found, path, rows)}</Fragment>;\n return (\n <PropertyGroup\n key={path}\n title={found.name}\n description={found.description}\n // A nested group is a block of rows, not a control: half of a\n // two-column grid leaves it laying its own rows out inside a cell,\n // which overlaps them.\n span\n actions={\n resolved.resettable?.has(path) ? (\n <ResetGroup\n group={found}\n path={path}\n config={config as Record<string, unknown>}\n setConfig={setConfig}\n />\n ) : undefined\n }\n {...fold(path, undefined, rows.grid)}\n >\n {body(found, path, rows)}\n </PropertyGroup>\n );\n };\n\n /**\n * The leaf at `path` if it may share a row with its neighbours: `pair` is\n * presentational, so a leaf whose control the lab draws itself, or one whose\n * control needs the whole row, keeps its own row instead.\n */\n const pairable = (path: string): { leaf: PrefLeaf; pair: string } | undefined => {\n const found = schemaNodeAtPath(resolved.group, path);\n if (!found || !isPrefLeaf(found)) return undefined;\n const pair = extra<string>(found, 'pair');\n if (pair === undefined) return undefined;\n if (!isLeafVisible(resolved, path, config as Record<string, unknown>, showHidden))\n return undefined;\n if (\n renderers?.[path] ??\n resolved.renderers[path] ??\n resolved.dialogs[path] ??\n renderers?.[found.kind]\n )\n return undefined;\n if (!isBuiltinToolPref(found)) return undefined;\n if (found.kind === 'paint' || found.kind === 'object' || isSliderLeaf(found)) return undefined;\n return { leaf: found, pair };\n };\n\n /** A run of sibling paths as rows, merging each run of adjacent leaves\n * sharing a `pair` id into one row named by the pair. */\n const rowsFor = (paths: readonly string[], rows: Rows): ReactNode[] => {\n const out: ReactNode[] = [];\n for (let i = 0; i < paths.length; ) {\n const head = pairable(paths[i]);\n if (!head) {\n out.push(node(paths[i], rows));\n i += 1;\n continue;\n }\n const { pair } = head;\n const cells = [{ path: paths[i], leaf: head.leaf }];\n let j = i + 1;\n for (; j < paths.length; j += 1) {\n const next = pairable(paths[j]);\n if (!next || next.pair !== pair) break;\n cells.push({ path: paths[j], leaf: next.leaf });\n }\n out.push(\n <PairedRow\n key={paths[i]}\n label={pair}\n cells={cells}\n shown={shown}\n setConfig={setConfig}\n layout={rows.layout}\n // A segmented cell carries every choice at once, so a pair holding\n // one needs the whole row the way a segmented row of its own does.\n span={cells.some(({ leaf }) => extra<string>(leaf, 'control') === 'radio')}\n />,\n );\n i = j;\n }\n return out;\n };\n\n /** One group's children: its loose nodes, then its sections. */\n const body = (group: PrefGroup, at: string, rows: Rows): ReactNode => {\n const sections = resolved.sections.filter((s) => s.at === at);\n const sectioned = new Set(sections.flatMap((s) => s.paths));\n const paths = Object.keys(group.children).map((key) => (at === '' ? key : `${at}.${key}`));\n return (\n <>\n {rowsFor(\n paths.filter((p) => !sectioned.has(p)),\n rows,\n )}\n {sections.map((section) => {\n const inner = sectionRows(section, rows);\n return (\n <PropertyGroup\n key={sectionKey(section)}\n title={section.label}\n {...fold(sectionKey(section), section.collapsed, inner.grid)}\n >\n {rowsFor(section.paths, inner)}\n </PropertyGroup>\n );\n })}\n </>\n );\n };\n\n const list = (\n <PropertyList\n pack={gridPack}\n density={density}\n align={align}\n className={className ? `lk-control-panel ${className}` : 'lk-control-panel'}\n >\n {body(resolved.group, '', { pack, layout, grid: gridPack })}\n </PropertyList>\n );\n if (title === undefined && stance === undefined && tone === undefined) return list;\n return (\n <PropertyPanel title={title} stance={stance} tone={tone} density={density}>\n {list}\n </PropertyPanel>\n );\n}\n\n/** How a section is keyed for folding: its label at the root, and its group's\n * path in front of it anywhere else, so two groups may both have an\n * `Advanced`. */\nfunction sectionKey(section: SectionSpec): string {\n return section.at === '' ? section.label : `${section.at}.${section.label}`;\n}\n\nexport interface ControlRowProps<TC extends Record<string, unknown>> {\n path: string;\n leaf: PrefLeaf;\n resolved: ResolvedConfig;\n config: TC;\n /** `config` with every auto path resolved -- what the instrument reads. */\n shown: TC;\n setConfig: (path: string, value: unknown) => void;\n renderers?: Record<string, ControlRenderer>;\n pack: ControlPack;\n layout?: PropertyRowLayout;\n auto?: ReadonlySet<string>;\n setRowAuto: (path: string, next: boolean, value: unknown) => void;\n}\n\n/** Whether this leaf draws as a slider, mirroring the condition the `number`\n * arm below branches on. A slider is the one control whose value cannot be\n * read off the control itself. */\nfunction isSliderLeaf(leaf: PrefLeaf): boolean {\n return (\n leaf.kind === 'number' &&\n extra<string>(leaf, 'control') === 'slider' &&\n extra<number>(leaf, 'min') !== undefined &&\n extra<number>(leaf, 'max') !== undefined\n );\n}\n\n/** Reads a labkit-only extra off a leaf. `PrefLeaf` has no field for these,\n * and extra keys survive the resolve pass at runtime. */\nfunction extra<T>(leaf: PrefLeaf, key: string): T | undefined {\n return (leaf as unknown as Record<string, T | undefined>)[key];\n}\n\n/** One leaf's row, as the panel draws it. Shared with `ControlMatrix`, whose\n * popover edits one cell with exactly this row. */\nexport function ControlRow<TC extends Record<string, unknown>>({\n path,\n leaf,\n resolved,\n config,\n shown,\n setConfig,\n renderers,\n pack,\n layout,\n auto,\n setRowAuto,\n}: ControlRowProps<TC>) {\n const write = (value: unknown): void => setConfig(path, value);\n const fallback = extra<unknown>(leaf, 'default');\n const pinned = valueAtPath(config, path) ?? fallback;\n\n const isAutoRow = auto?.has(path) ?? false;\n const canAuto = !extra<boolean>(leaf, 'manual');\n // Read out of the resolved config rather than re-running this leaf's own\n // resolver, so the row reports the value the instrument actually got — the\n // two diverge as soon as a resolver reads another auto path.\n const resolvedValue = isAutoRow ? valueAtPath(shown, path) : undefined;\n // An auto row draws what the resolver decided, not the value underneath it —\n // a handle sitting at the pinned number while the readout says something else\n // reads as a rendering bug. Pinning then keeps what you were looking at.\n const value = resolvedValue ?? pinned;\n const setAuto = (next: boolean): void => setRowAuto(path, next, value);\n const onAutoChange = canAuto ? setAuto : undefined;\n // An auto row hides its control, so the word is all the row has to say.\n const autoReadout = isAutoRow ? 'auto' : undefined;\n const autoProps = { auto: isAutoRow, onAutoChange };\n\n // Most specific wins, and within a tier the lab's entry beats the\n // instrument's: controls[path] -> node .render/.dialog -> controls[kind] -> built-in.\n const dialog = resolved.dialogs[path];\n const custom =\n renderers?.[path] ??\n resolved.renderers[path] ??\n (dialog ? inDialog(dialog.body, dialog) : undefined) ??\n renderers?.[leaf.kind];\n // A custom row places itself like any other; one that needs the full width\n // says so with `<PropertyRow span>`, which is the same opt-out a built-in has.\n if (custom) return custom({ path, pref: leaf, value, setValue: write, auto: isAutoRow, setAuto });\n\n const label = leaf.name;\n const description = leaf.description;\n // `auto` gives the whole width to the controls that read badly at half of a\n // sidebar's: free text, a slider track, a segmented toggle. `pairs` doesn't.\n const wide = pack === 'auto';\n const row = { label, description, layout, readout: autoReadout, ...autoProps };\n\n if (leaf.kind === 'list') {\n const entries = Array.isArray(value) ? (value as string[]) : [];\n return (\n <DialogRow\n label={label}\n summary={summarizeValue(entries)}\n readout={autoReadout}\n layout={layout}\n description={description}\n {...autoProps}\n >\n {() => (\n <ListEditor\n aria-label={label}\n value={entries}\n onChange={write}\n placeholder={extra<string>(leaf, 'placeholder')}\n />\n )}\n </DialogRow>\n );\n }\n\n const field = labField(leaf, value, write);\n if (field === null)\n return <UnwiredRow label={label} kind={leaf.kind} description={description} />;\n switch (field.kind) {\n case 'string':\n return <DebouncedTextRow leaf={leaf} field={field} span={wide} {...row} />;\n case 'number':\n return <PropertyField {...field} {...row} span={field.control === 'slider' && wide} />;\n case 'enum':\n return <PropertyField {...field} {...row} span={field.control === 'toggle' && wide} />;\n default:\n return <PropertyField {...field} {...row} />;\n }\n}\n\n/**\n * A leaf as the field it draws, with the labkit-only extras `prefFieldProps`\n * knows nothing of. `null` for a kind the panel declines: a paint, which a\n * hex swatch would flatten to a solid, and an object, which a flat row would\n * write one field of. Override with `render` to edit either.\n */\nfunction labField(\n leaf: PrefLeaf,\n value: unknown,\n write: (value: unknown) => void,\n): PropertyControlProps | null {\n if (!isBuiltinToolPref(leaf) || leaf.kind === 'paint' || leaf.kind === 'object') return null;\n const field = prefFieldProps(leaf, { value, setValue: write });\n if (field === null) return null;\n switch (field.kind) {\n case 'number':\n // `prefFieldProps` clamps what it stores, so an instrument is never\n // handed a value outside the range it asked for.\n return {\n ...field,\n control: isSliderLeaf(leaf) ? 'slider' : 'input',\n unit: extra<string>(leaf, 'suffix') ?? field.unit,\n };\n case 'boolean':\n return {\n ...field,\n control: extra<string>(leaf, 'control') === 'switch' ? 'switch' : 'checkbox',\n };\n case 'enum':\n // `.radio()` asks for every option at once, as segments.\n return {\n ...field,\n control: extra<string>(leaf, 'control') === 'radio' ? 'toggle' : 'select',\n };\n case 'string':\n return {\n ...field,\n placeholder: extra<string>(leaf, 'placeholder'),\n maxLength: extra<number>(leaf, 'maxLength'),\n };\n default:\n return field;\n }\n}\n\n/** A leaf this panel has no control for is named rather than dropped: a silent\n * gap reads as \"this control does not exist\". */\nfunction UnwiredRow({\n label,\n kind,\n description,\n}: {\n label: string;\n kind: string;\n description?: string;\n}) {\n return (\n <PropertyRow label={label} description={description}>\n <span className=\"lk-control-panel__unknown\">no control for “{kind}”</span>\n </PropertyRow>\n );\n}\n\n/** A text row whose writes are debounced — see {@link useDebouncedText}. */\nfunction DebouncedTextRow({\n leaf,\n field,\n ...row\n}: {\n leaf: PrefLeaf;\n field: PropertyControlProps & { kind: 'string' };\n label: string;\n layout?: PropertyRowLayout;\n span?: boolean;\n description?: string;\n readout?: ReactNode;\n auto?: boolean;\n onAutoChange?: (next: boolean) => void;\n}) {\n const text = useDebouncedText(\n field.value ?? '',\n field.onChange,\n extra<number>(leaf, 'debounceMs') ?? 150,\n );\n return <PropertyField {...field} {...row} value={text.local} onChange={text.type} />;\n}\n\n/** One cell of a paired row, with its path and the leaf it draws. */\ninterface PairCellSpec {\n path: string;\n leaf: PrefLeaf;\n}\n\n/**\n * Leaves sharing a `pair` id, side by side on one row the pair names — the\n * compact `X` / `Y` idiom `SelectionPanel` draws for the same annotation.\n *\n * The cells are bare controls: a row holds one label column, so each leaf's\n * own name stays with its control as the accessible name and its description\n * as a title. For the same reason the row's label does not toggle auto — it\n * names one path, and this row has several.\n */\nfunction PairedRow<TC extends Record<string, unknown>>({\n label,\n cells,\n shown,\n setConfig,\n layout,\n span,\n}: {\n label: string;\n cells: readonly PairCellSpec[];\n shown: TC;\n setConfig: (path: string, value: unknown) => void;\n layout?: PropertyRowLayout;\n span?: boolean;\n}) {\n return (\n <PropertyRow group span={span} label={label} layout={layout}>\n {cells.map(({ path, leaf }) => (\n // The row is named by the pair, so a cell that shares it says which\n // knob it is — without a caption a paired switch reads only to a\n // screen reader. A cell whose leaf is deliberately unnamed keeps none.\n <span key={path} className=\"lk-pair-cell\" title={leaf.description || undefined}>\n {leaf.name ? <span className=\"lk-pair-label\">{leaf.name}</span> : null}\n <PairCell\n leaf={leaf}\n value={valueAtPath(shown, path) ?? extra<unknown>(leaf, 'default')}\n write={(value) => setConfig(path, value)}\n />\n </span>\n ))}\n </PropertyRow>\n );\n}\n\n/** The control a paired cell holds, without the row chrome a whole row of its\n * own would bring. */\nfunction PairCell({\n leaf,\n value,\n write,\n}: {\n leaf: PrefLeaf;\n value: unknown;\n write: (value: unknown) => void;\n}) {\n const text = useDebouncedText(\n typeof value === 'string' ? value : '',\n write,\n extra<number>(leaf, 'debounceMs') ?? 150,\n );\n const field = labField(leaf, value, write);\n // Unreachable for null: `pairable` admits only kinds with a field.\n if (field === null) return null;\n switch (field.kind) {\n case 'string':\n return (\n <PropertyControl {...field} name={leaf.name} value={text.local} onChange={text.type} />\n );\n case 'number':\n // The pair names the row, so a cell has no room for a unit.\n return <PropertyControl {...field} name={leaf.name} control=\"input\" unit={undefined} />;\n case 'color': {\n // The alpha track needs a row of its own to sit under, so a paired\n // swatch edits the color and carries the stored alpha through untouched.\n const stored = typeof value === 'string' ? toHex8(value) : '#000000';\n return (\n <PropertyControl\n {...field}\n name={leaf.name}\n alpha={undefined}\n onChange={(rgb: string) =>\n write(field.alpha ? withAlpha01(rgb, getAlpha01(stored)) : rgb)\n }\n />\n );\n }\n default:\n return <PropertyControl {...field} name={leaf.name} />;\n }\n}\n\n/**\n * Live text held locally between debounced commits, so typing does not re-run\n * the instrument on every keystroke. Locally controlled between commits, which\n * means it has to notice the value changing underneath it.\n */\nfunction useDebouncedText(\n value: string,\n write: (value: string) => void,\n debounceMs: number,\n): { local: string; type: (next: string) => void } {\n const [local, setLocal] = useState(value);\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const lastExternal = useRef(value);\n\n useEffect(() => {\n if (value !== lastExternal.current) {\n lastExternal.current = value;\n setLocal(value);\n }\n }, [value]);\n\n useEffect(\n () => () => {\n if (timer.current) clearTimeout(timer.current);\n },\n [],\n );\n\n return {\n local,\n type: (next) => {\n setLocal(next);\n if (timer.current) clearTimeout(timer.current);\n const commit = () => {\n lastExternal.current = next;\n write(next);\n };\n if (debounceMs === 0) commit();\n else timer.current = setTimeout(commit, debounceMs);\n },\n };\n}\n"]}
|
package/dist/config/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { a4 as Auto } from '../_dts/index-
|
|
1
|
+
import { a4 as Auto } from '../_dts/index-8geQNQet.js';
|
|
2
2
|
import { Instrument } from '../index.js';
|
|
3
|
-
export {
|
|
4
|
-
import { R as ResolvedConfig, k as ConfigNode, A as Annotations, N as NodeOptions, S as SectionOption, c as ControlRenderer, I as InDialogOptions, m as ConfigOption, p as ConfigShape, g as ConfigBranch, B as BranchAnnotations, d as BranchOptions, C as ConfigSchema, q as InferConfig, h as ConfigEntry, b as ConfigRule, L as LeafPatch, o as ConfigRuleContext } from '../_dts/types-
|
|
3
|
+
export { ax as auto, aD as isAuto } from '../_dts/index-8geQNQet.js';
|
|
4
|
+
import { R as ResolvedConfig, k as ConfigNode, A as Annotations, N as NodeOptions, S as SectionOption, c as ControlRenderer, I as InDialogOptions, m as ConfigOption, p as ConfigShape, g as ConfigBranch, B as BranchAnnotations, d as BranchOptions, C as ConfigSchema, q as InferConfig, h as ConfigEntry, b as ConfigRule, L as LeafPatch, o as ConfigRuleContext } from '../_dts/types-DUfQ0isU.js';
|
|
5
5
|
import { ConfigField } from '../controls/index.js';
|
|
6
|
-
export { l as ConfigOf, n as ConfigPath, D as DialogSpec, E as EntryValue, r as NodeValue, t as SectionSpec, V as ValueAtPath } from '../_dts/types-
|
|
7
|
-
import { Display } from '@weasel-js/quantity';
|
|
6
|
+
export { l as ConfigOf, n as ConfigPath, D as DialogSpec, E as EntryValue, r as NodeValue, t as SectionSpec, V as ValueAtPath } from '../_dts/types-DUfQ0isU.js';
|
|
7
|
+
import { Display, InfinityText } from '@weasel-js/quantity';
|
|
8
8
|
import { PrefNumberUnit, PrefLeaf, PrefGroup } from '@weasel-js/ui';
|
|
9
9
|
import '@weasel-js/core';
|
|
10
10
|
import 'react';
|
|
@@ -94,6 +94,13 @@ declare class NumberNode extends BaseNode<number> {
|
|
|
94
94
|
* `UnitSystem`.
|
|
95
95
|
*/
|
|
96
96
|
unit(unit: PrefNumberUnit): this;
|
|
97
|
+
/**
|
|
98
|
+
* Make the top of the range mean infinity: the slider's `max` stop stores
|
|
99
|
+
* `Infinity` and reads `word` — `.range(0, 5000).endless('never')`. A value
|
|
100
|
+
* of `Infinity` sits at that stop. `at: 'min'` puts it at the bottom
|
|
101
|
+
* instead, as `-Infinity`; `'both'` does both.
|
|
102
|
+
*/
|
|
103
|
+
endless(word?: InfinityText, at?: 'min' | 'max' | 'both'): this;
|
|
97
104
|
/** Force a slider even without both bounds. */
|
|
98
105
|
slider(): this;
|
|
99
106
|
/** Force a typed input even when both bounds are set. */
|
package/dist/config/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { sectionTree, useConfigSchema } from '../chunk-
|
|
1
|
+
export { sectionTree, useConfigSchema } from '../chunk-SQX35X5V.js';
|
|
2
2
|
import '../chunk-Z76KEZAX.js';
|
|
3
|
-
export { BaseNode, BooleanNode, ColorNode, CustomNode, EnumNode, GroupNode, ListNode, NumberNode, StringNode, ValueNode, applyRules, builtinRules, f, isConfigBranch, resolveConfigSchema, titleCase, useResolvedConfig } from '../chunk-
|
|
3
|
+
export { BaseNode, BooleanNode, ColorNode, CustomNode, EnumNode, GroupNode, ListNode, NumberNode, StringNode, ValueNode, applyRules, builtinRules, f, isConfigBranch, resolveConfigSchema, titleCase, useResolvedConfig } from '../chunk-T5OEUNCB.js';
|
|
4
4
|
export { fromConfigFields, isLeafVisible } from '../chunk-WLMDTI2Q.js';
|
|
5
5
|
export { auto, autoPathsOf, fillConfigDefaults, hasConfigPath, isAuto, resolveAutoConfig, schemaNodeAtPath, valueAtPath, withValueAtPath } from '../chunk-READTDQX.js';
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
package/dist/controls/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { StanceProps, PropertyRowLayout, PropertyDensity, PropertyAlign } from '@weasel-js/ui';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { ReactNode, ReactElement } from 'react';
|
|
4
|
-
import { a as ConfigField, I as InDialogOptions } from '../_dts/types-
|
|
4
|
+
import { a as ConfigField, I as InDialogOptions } from '../_dts/types-DUfQ0isU.js';
|
|
5
5
|
import { ResolvedConfig, ControlRenderer } from '../config/index.js';
|
|
6
|
-
export { e as CheckboxField, f as ColorField, j as ConfigFieldType, s as NumberField, u as SelectField, v as SelectOption, w as SliderField, T as TextField } from '../_dts/types-
|
|
6
|
+
export { e as CheckboxField, f as ColorField, j as ConfigFieldType, s as NumberField, u as SelectField, v as SelectOption, w as SliderField, T as TextField } from '../_dts/types-DUfQ0isU.js';
|
|
7
7
|
import '@weasel-js/quantity';
|
|
8
8
|
|
|
9
9
|
/** One column of a {@link ControlMatrix}: a config group, every one the same shape. */
|
package/dist/controls/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { ControlMatrix } from '../chunk-
|
|
2
|
-
export { ControlPanel, inDialog, summarizeValue } from '../chunk-
|
|
1
|
+
export { ControlMatrix } from '../chunk-4RCVWX4M.js';
|
|
2
|
+
export { ControlPanel, inDialog, summarizeValue } from '../chunk-YZA73U4A.js';
|
|
3
3
|
import '../chunk-WLMDTI2Q.js';
|
|
4
4
|
import '../chunk-READTDQX.js';
|
|
5
|
-
import '../chunk-
|
|
6
|
-
import '../chunk-
|
|
7
|
-
import '../chunk-
|
|
5
|
+
import '../chunk-V4SMGEYY.js';
|
|
6
|
+
import '../chunk-VCK5T6EP.js';
|
|
7
|
+
import '../chunk-AVOILDN2.js';
|
|
8
8
|
//# sourceMappingURL=index.js.map
|
|
9
9
|
//# sourceMappingURL=index.js.map
|
package/dist/dragdrop/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { k as PaletteItem, l as DragFeedback, m as DragDropCapability } from '../_dts/index-8geQNQet.js';
|
|
2
2
|
import { WorldSpec } from '../canvas/index.js';
|
|
3
3
|
import { Point, ViewTransform } from '../index.js';
|
|
4
4
|
import * as react from 'react';
|
|
@@ -6,7 +6,7 @@ import { RefObject, PointerEvent, ReactPortal } from 'react';
|
|
|
6
6
|
import '@weasel-js/ui';
|
|
7
7
|
import '@weasel-js/core';
|
|
8
8
|
import '@weasel-js/theme';
|
|
9
|
-
import '../_dts/types-
|
|
9
|
+
import '../_dts/types-DUfQ0isU.js';
|
|
10
10
|
import '@weasel-js/quantity';
|
|
11
11
|
import '@weasel-js/geom';
|
|
12
12
|
import '../_dts/types-DJ79Tg5J.js';
|
package/dist/dragdrop/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { DragGhost, DragOverlay, Palette, useDragDrop } from '../chunk-
|
|
1
|
+
export { DragGhost, DragOverlay, Palette, useDragDrop } from '../chunk-J5MDJEOZ.js';
|
|
2
2
|
import '../chunk-FG3EXZDV.js';
|
|
3
3
|
import '../chunk-ULYYNWGP.js';
|
|
4
|
-
import '../chunk-
|
|
4
|
+
import '../chunk-AVOILDN2.js';
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
|
6
6
|
//# sourceMappingURL=index.js.map
|