@weasel-js/labkit 1.4.1 → 1.4.3
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 +28 -2
- package/dist/_dts/{CanvasStackContext-BIRUVVGH.d.ts → CanvasStackContext-Dde8_1my.d.ts} +1 -1
- package/dist/_dts/{PrefsForm.d-CgxUequc.d.ts → PrefsForm.d-DDHFANkc.d.ts} +1 -1
- package/dist/_dts/{frac-X7mWgd7y.d.ts → frac-B5mB8LsJ.d.ts} +33 -13
- package/dist/_dts/{index-FEa1MudK.d.ts → index-DelFfeV0.d.ts} +99 -31
- package/dist/_dts/types-B9_zrHmb.d.ts +166 -0
- package/dist/_dts/{types-ChVJJHvk.d.ts → types-BP2OCcpg.d.ts} +41 -4
- package/dist/_dts/types-x92Kfeme.d.ts +62 -0
- package/dist/_dts/{useTrialState-Cdm13fvl.d.ts → useTrialState-D6Vb3T-g.d.ts} +11 -7
- package/dist/canvas/index.d.ts +9 -8
- package/dist/canvas/index.js +1 -2
- package/dist/chrome/index.d.ts +16 -9
- package/dist/chrome/index.js +5 -5
- package/dist/{chunk-MSR7EVS6.js → chunk-2RQPGOQF.js} +6 -5
- package/dist/chunk-2RQPGOQF.js.map +1 -0
- package/dist/{chunk-LJSIUFYD.js → chunk-5TROQVQ2.js} +46 -21
- package/dist/chunk-5TROQVQ2.js.map +1 -0
- package/dist/{chunk-53AZ2O2N.js → chunk-ASWKLRKJ.js} +92 -45
- package/dist/chunk-ASWKLRKJ.js.map +1 -0
- package/dist/{chunk-BMQWLKOL.js → chunk-C42T6DJT.js} +94 -83
- package/dist/chunk-C42T6DJT.js.map +1 -0
- package/dist/chunk-E44SU6XS.js +50 -0
- package/dist/chunk-E44SU6XS.js.map +1 -0
- package/dist/{chunk-OFCBEZMU.js → chunk-FQMJUVHJ.js} +3 -3
- package/dist/{chunk-OFCBEZMU.js.map → chunk-FQMJUVHJ.js.map} +1 -1
- package/dist/{chunk-PP7ZWAMV.js → chunk-I6JCVE24.js} +3 -3
- package/dist/chunk-I6JCVE24.js.map +1 -0
- package/dist/chunk-ISCOFAUO.js +170 -0
- package/dist/chunk-ISCOFAUO.js.map +1 -0
- package/dist/chunk-MHAGC6VD.js +7320 -0
- package/dist/chunk-MHAGC6VD.js.map +1 -0
- package/dist/{chunk-7TRFMIWX.js → chunk-QAGAHJKZ.js} +4 -4
- package/dist/{chunk-7TRFMIWX.js.map → chunk-QAGAHJKZ.js.map} +1 -1
- package/dist/{chunk-D7QIPGEB.js → chunk-RS3HRQWU.js} +62 -60
- package/dist/chunk-RS3HRQWU.js.map +1 -0
- package/dist/{chunk-RLOXQZW3.js → chunk-TJ7QY3OC.js} +3 -3
- package/dist/{chunk-RLOXQZW3.js.map → chunk-TJ7QY3OC.js.map} +1 -1
- package/dist/controls/index.d.ts +5 -4
- package/dist/controls/index.js +3 -3
- package/dist/dragdrop/index.d.ts +9 -8
- package/dist/dragdrop/index.js +1 -2
- package/dist/index.d.ts +152 -57
- package/dist/index.js +315 -200
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +27 -11
- package/dist/layers/index.js +2 -3
- package/dist/loupe/index.d.ts +8 -7
- package/dist/loupe/index.js +1 -2
- package/dist/passthrough/weasel-canvas.d.ts +1 -3
- package/dist/passthrough/weasel-canvas.js +1 -1
- package/dist/passthrough/weasel-canvas.js.map +1 -1
- package/dist/passthrough/weasel-ui.d.ts +171 -22
- package/dist/passthrough/weasel-ui.js +1 -2
- package/dist/primitives/index.js +3 -4
- package/dist/state/index.d.ts +6 -3
- package/dist/state/index.js +3 -2
- package/dist/state/index.js.map +1 -1
- package/dist/styles.css +21 -4
- package/dist/surface/index.js +1 -2
- package/dist/ui/layers/index.d.ts +22 -9
- package/dist/ui/layers/index.js +1 -2
- package/dist/undo/index.d.ts +6 -6
- package/package.json +7 -7
- package/src/annotations/AnnotationTargets.tsx +6 -1
- package/src/annotations/Annotations.overlay.test.tsx +2 -0
- package/src/annotations/ExportMenu.test.tsx +16 -0
- package/src/annotations/ExportMenu.tsx +0 -5
- package/src/annotations/types.ts +4 -1
- package/src/canvas/useOrbit.test.ts +7 -3
- package/src/canvas/usePanZoom.test.ts +7 -3
- package/src/chrome/ChromeRegions.stories.tsx +42 -1
- package/src/chrome/builtins.test.ts +4 -0
- package/src/chrome/builtins.tsx +18 -0
- package/src/chrome/index.ts +1 -1
- package/src/chrome/regions/SidebarRegion.tsx +7 -6
- package/src/chrome/regions/TitleBarRegion.test.tsx +64 -0
- package/src/chrome/regions/TitleBarRegion.tsx +16 -7
- package/src/chrome/regions/ToolbarRegion.test.tsx +14 -0
- package/src/chrome/regions/ToolbarRegion.tsx +2 -2
- package/src/chrome/regions/ViewportRegion.tsx +2 -2
- package/src/chrome/regions/regions.test.tsx +45 -1
- package/src/chrome/types.ts +21 -3
- package/src/config/builder.test.ts +56 -2
- package/src/config/builder.ts +73 -13
- package/src/config/index.ts +16 -1
- package/src/config/path.test.ts +109 -0
- package/src/config/path.ts +76 -0
- package/src/config/resolve.test.ts +93 -2
- package/src/config/resolve.ts +72 -29
- package/src/config/types.ts +99 -9
- package/src/config/visible.ts +6 -4
- package/src/controls/ControlPanel.stories.tsx +38 -4
- package/src/controls/ControlPanel.test.tsx +152 -0
- package/src/controls/ControlPanel.tsx +134 -40
- package/src/dragdrop/DragDropRuntime.tsx +74 -61
- package/src/dragdrop/Palette.tsx +4 -3
- package/src/dragdrop/dragDrop.test.tsx +35 -12
- package/src/index.ts +18 -2
- package/src/instrument/serializers.ts +36 -0
- package/src/instrument/types.ts +8 -7
- package/src/lab/Lab.test.tsx +36 -1
- package/src/lab/Lab.tsx +12 -3
- package/src/lab/LabContext.ts +5 -1
- package/src/lab/LabShell.less +17 -2
- package/src/lab/LabShell.test.tsx +8 -0
- package/src/lab/LabShell.tsx +3 -1
- package/src/layers/AGENTS.md +29 -7
- package/src/layers/LayerList.less +16 -0
- package/src/layers/LayerList.stories.tsx +66 -0
- package/src/layers/LayerList.test.tsx +117 -5
- package/src/layers/LayerList.tsx +192 -53
- package/src/layers/index.ts +1 -1
- package/src/passthrough/weasel-ui.ts +5 -0
- package/src/primitives/FloatingPanel.test.tsx +8 -3
- package/src/primitives/ZoomControl.less +6 -2
- package/src/primitives/ZoomControl.tsx +1 -0
- package/src/state/helpers.ts +1 -1
- package/src/state/store.test.ts +233 -1
- package/src/state/store.ts +57 -24
- package/src/state/types.ts +44 -3
- package/src/state/useTrialState.ts +1 -1
- package/src/trial/Trial.config.test.tsx +44 -0
- package/src/trial/Trial.less +4 -0
- package/src/trial/Trial.targets.test.tsx +96 -0
- package/src/trial/Trial.test.tsx +171 -14
- package/src/trial/Trial.tsx +7 -4
- package/src/trial/TrialChrome.tsx +32 -7
- package/src/trial/TrialTitleBar.tsx +7 -3
- package/src/trial/index.ts +1 -0
- package/src/trial/trialOps.test.ts +49 -1
- package/src/trial/trialOps.ts +24 -6
- package/dist/_dts/types-lg4TSCb2.d.ts +0 -164
- package/dist/_dts/weasel-canvas-FJTFi3ZZ.d.ts +0 -5041
- package/dist/chunk-53AZ2O2N.js.map +0 -1
- package/dist/chunk-BMQWLKOL.js.map +0 -1
- package/dist/chunk-D7QIPGEB.js.map +0 -1
- package/dist/chunk-DG2IFMLA.js +0 -29970
- package/dist/chunk-DG2IFMLA.js.map +0 -1
- package/dist/chunk-J6SBFZYT.js +0 -7121
- package/dist/chunk-J6SBFZYT.js.map +0 -1
- package/dist/chunk-LJSIUFYD.js.map +0 -1
- package/dist/chunk-MIT3ISW4.js +0 -100
- package/dist/chunk-MIT3ISW4.js.map +0 -1
- package/dist/chunk-MSR7EVS6.js.map +0 -1
- package/dist/chunk-PP7ZWAMV.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,35 +1,38 @@
|
|
|
1
1
|
import { createEventBus, pushSnapshot, redo, undo } from './chunk-RL2LOLNI.js';
|
|
2
2
|
export { clearUndo, createEventBus, emptyStack, pushSnapshot, redo, undo } from './chunk-RL2LOLNI.js';
|
|
3
|
-
import { useDragDrop, DragOverlay, Palette } from './chunk-
|
|
4
|
-
import { useSurfaceOptional, useSurfaceCanvas, useTileId, useTiledSurface, SurfaceContext, SurfaceCanvasContext } from './chunk-
|
|
5
|
-
export { SurfaceCanvasContext, SurfaceContext, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceCanvas, useSurfaceOptional, useSurfaceTile, useTileId, useTiledSurface } from './chunk-
|
|
3
|
+
import { useDragDrop, DragOverlay, Palette } from './chunk-RS3HRQWU.js';
|
|
4
|
+
import { useSurfaceOptional, useSurfaceCanvas, useTileId, useTiledSurface, SurfaceContext, SurfaceCanvasContext } from './chunk-FQMJUVHJ.js';
|
|
5
|
+
export { SurfaceCanvasContext, SurfaceContext, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceCanvas, useSurfaceOptional, useSurfaceTile, useTileId, useTiledSurface } from './chunk-FQMJUVHJ.js';
|
|
6
6
|
import { useJob } from './chunk-HXXTULDN.js';
|
|
7
7
|
export { useJob } from './chunk-HXXTULDN.js';
|
|
8
|
-
import { ANNOTATION_WEASEL_TOOLS, annotationToolInfo, suppressContributions, mergeContributions, builtinContributions, TitleBarRegion, ToolbarRegion, PaletteRegion, ViewportRegion, SidebarRegion, StatusRegion, AnnotationsContext } from './chunk-
|
|
9
|
-
export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, AnnotationsContext, ExportMenu, MarkList, PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, annotationToolInfo, builtinContributions, mergeContributions, suppressContributions, useAnnotations, useAnnotationsOptional } from './chunk-
|
|
10
|
-
import { JobProgress } from './chunk-
|
|
11
|
-
export { FloatingPanel, JobProgress, Legend, Sidebar } from './chunk-
|
|
12
|
-
export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl } from './chunk-
|
|
13
|
-
import { createLabStore, panelKey, noneAdapter } from './chunk-
|
|
14
|
-
export { CURRENT_DOCUMENT_VERSION, createMemoryAdapter, dockPanel, labDocumentKey, localStorageAdapter, noneAdapter, panelKey, quarantineKey, sessionStorageAdapter, undockPanel, urlHashAdapter, useTrialState } from './chunk-
|
|
8
|
+
import { ANNOTATION_WEASEL_TOOLS, annotationToolInfo, suppressContributions, mergeContributions, builtinContributions, TitleBarRegion, ToolbarRegion, PaletteRegion, ViewportRegion, SidebarRegion, StatusRegion, AnnotationsContext } from './chunk-C42T6DJT.js';
|
|
9
|
+
export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, AnnotationsContext, ExportMenu, MarkList, PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, annotationToolInfo, builtinContributions, mergeContributions, suppressContributions, useAnnotations, useAnnotationsOptional } from './chunk-C42T6DJT.js';
|
|
10
|
+
import { JobProgress } from './chunk-QAGAHJKZ.js';
|
|
11
|
+
export { FloatingPanel, JobProgress, Legend, Sidebar } from './chunk-QAGAHJKZ.js';
|
|
12
|
+
export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl } from './chunk-2RQPGOQF.js';
|
|
13
|
+
import { createLabStore, panelKey, noneAdapter } from './chunk-5TROQVQ2.js';
|
|
14
|
+
export { CURRENT_DOCUMENT_VERSION, createMemoryAdapter, dockPanel, labDocumentKey, localStorageAdapter, noneAdapter, panelKey, quarantineKey, sessionStorageAdapter, undockPanel, urlHashAdapter, useTrialState } from './chunk-5TROQVQ2.js';
|
|
15
15
|
import { LabStoreContext, TrialIdProvider } from './chunk-2YILQ7Y5.js';
|
|
16
16
|
export { LabStoreContext, LabStoreProvider, TrialIdContext, TrialIdProvider, useLabStore, useTrialId } from './chunk-2YILQ7Y5.js';
|
|
17
|
-
import { fromConfigFields } from './chunk-
|
|
18
|
-
export { ControlPanel, fromConfigFields, isLeafVisible } from './chunk-
|
|
19
|
-
import {
|
|
20
|
-
export {
|
|
21
|
-
import {
|
|
22
|
-
export {
|
|
17
|
+
import { fromConfigFields } from './chunk-ASWKLRKJ.js';
|
|
18
|
+
export { ControlPanel, fromConfigFields, isLeafVisible } from './chunk-ASWKLRKJ.js';
|
|
19
|
+
import { hasConfigPath, schemaNodeAtPath, withValueAtPath, fillConfigDefaults } from './chunk-E44SU6XS.js';
|
|
20
|
+
export { fillConfigDefaults, hasConfigPath, schemaNodeAtPath, valueAtPath, withValueAtPath } from './chunk-E44SU6XS.js';
|
|
21
|
+
import { CanvasStack } from './chunk-I6JCVE24.js';
|
|
22
|
+
export { CanvasStack, PITCH_LIMIT, clampPitch, orbitAfterDrag, orbitAfterWheel, useOrbit, usePanZoom, wrapYaw } from './chunk-I6JCVE24.js';
|
|
23
|
+
import { LayerList } from './chunk-ISCOFAUO.js';
|
|
24
|
+
export { LayerList } from './chunk-ISCOFAUO.js';
|
|
23
25
|
import './chunk-SBXNQW4G.js';
|
|
24
|
-
import { E, w, T, C,
|
|
25
|
-
export {
|
|
26
|
-
import { resolveLoupe, TrialLoupe } from './chunk-
|
|
27
|
-
export { CanvasLoupe, DomLoupe, LOUPE_DEFAULTS, LoupeBubble, TrialLoupe, drawCanvasLens, lensCamera, lensSourceRect, resolveLoupe, sampleStack, useLoupe } from './chunk-
|
|
26
|
+
import { E, w, T, C, g, r6 } from './chunk-MHAGC6VD.js';
|
|
27
|
+
export { M2 as CheckboxRow, j2 as ColorRow, y3 as CurveField, R as EffectCard, B as EffectCardList, c3 as LayerStack, P2 as NumberRow, V as PropertyGroup, T2 as PropertyList, w2 as PropertyPanel, D as PropertyRow, E2 as PropertySpan, F as SelectRow, k as SliderRow, L2 as Subpanel, N2 as TextRow, I as ToggleRow } from './chunk-MHAGC6VD.js';
|
|
28
|
+
import { resolveLoupe, TrialLoupe } from './chunk-TJ7QY3OC.js';
|
|
29
|
+
export { CanvasLoupe, DomLoupe, LOUPE_DEFAULTS, LoupeBubble, TrialLoupe, drawCanvasLens, lensCamera, lensSourceRect, resolveLoupe, sampleStack, useLoupe } from './chunk-TJ7QY3OC.js';
|
|
28
30
|
export { centerOn, zoomAt } from './chunk-CTRKTLYZ.js';
|
|
29
31
|
import { applyCamera } from './chunk-2AYGEN57.js';
|
|
30
32
|
export { DEFAULT_FRAME, applyCamera, resolveFrame, screenToWorld, worldToScreen } from './chunk-2AYGEN57.js';
|
|
31
33
|
export { CanvasStackContext } from './chunk-CQLQPQ4P.js';
|
|
32
|
-
import { textCommand, linePath, markerDrawCommands, ellipsePath, rectPath, createScene, asNodeId as asNodeId$1, WeaselProvider, SceneCanvas, sceneFromJSON, PathBuilder, renderSceneToPixels, useActiveToolContext, resolveStrokeWidth, getMarker, getPaintKind, boundsOfPath,
|
|
34
|
+
import { textCommand, linePath, markerDrawCommands, ellipsePath, rectPath, createScene, asNodeId as asNodeId$1, WeaselProvider, SceneCanvas, sceneFromJSON, PathBuilder, renderSceneToPixels, useActiveToolContext, resolveStrokeWidth, getMarker, getPaintKind, boundsOfPath, PATH_M, PATH_L, PATH_C, PATH_Q, PATH_Z, SCRIPT_METRICS } from '@weasel-js/core';
|
|
35
|
+
import { tileGeometry } from '@weasel-js/core/patterns-builtin';
|
|
33
36
|
import { createContext, useState, useRef, useEffect, useContext, useMemo, Children, useLayoutEffect, useCallback, useSyncExternalStore } from 'react';
|
|
34
37
|
import { createPortal } from 'react-dom';
|
|
35
38
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -37,16 +40,15 @@ import { useStore } from 'zustand/react';
|
|
|
37
40
|
import { asNodeId, Store, createNode, stripStrategy, floatingStrategy, gridStrategy } from 'windease';
|
|
38
41
|
import { Provider, StrategyRegistryProvider, Container, DragProvider, useDragHandle } from 'windease/react';
|
|
39
42
|
|
|
40
|
-
// ../svg/dist/index.js
|
|
41
43
|
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
|
42
|
-
function multiply(a,
|
|
44
|
+
function multiply(a, b) {
|
|
43
45
|
return [
|
|
44
|
-
a[0] *
|
|
45
|
-
a[1] *
|
|
46
|
-
a[0] *
|
|
47
|
-
a[1] *
|
|
48
|
-
a[0] *
|
|
49
|
-
a[1] *
|
|
46
|
+
a[0] * b[0] + a[2] * b[1],
|
|
47
|
+
a[1] * b[0] + a[3] * b[1],
|
|
48
|
+
a[0] * b[2] + a[2] * b[3],
|
|
49
|
+
a[1] * b[2] + a[3] * b[3],
|
|
50
|
+
a[0] * b[4] + a[2] * b[5] + a[4],
|
|
51
|
+
a[1] * b[4] + a[3] * b[5] + a[5]
|
|
50
52
|
];
|
|
51
53
|
}
|
|
52
54
|
function isIdentity(m, eps = 1e-9) {
|
|
@@ -108,8 +110,8 @@ function escapeAttr(s) {
|
|
|
108
110
|
}
|
|
109
111
|
function serializePathD(path) {
|
|
110
112
|
if (path.kind === "rect") {
|
|
111
|
-
const { x
|
|
112
|
-
return `M${trimNumber(
|
|
113
|
+
const { x, y: y2, width, height } = path;
|
|
114
|
+
return `M${trimNumber(x)} ${trimNumber(y2)}h${trimNumber(width)}v${trimNumber(height)}h${trimNumber(-width)}Z`;
|
|
113
115
|
}
|
|
114
116
|
const cmds = path.commands;
|
|
115
117
|
const xs = path.coords;
|
|
@@ -395,9 +397,9 @@ function pathXml(node, registry, namespaces) {
|
|
|
395
397
|
attrs.push(`opacity="${trimNumber(node.opacity)}"`);
|
|
396
398
|
}
|
|
397
399
|
if (node.rotation != null && node.rotation !== 0) {
|
|
398
|
-
const
|
|
399
|
-
const cx =
|
|
400
|
-
const cy =
|
|
400
|
+
const b = pathBounds(node.path);
|
|
401
|
+
const cx = b.minX + (b.maxX - b.minX) / 2;
|
|
402
|
+
const cy = b.minY + (b.maxY - b.minY) / 2;
|
|
401
403
|
const deg = node.rotation * 180 / Math.PI;
|
|
402
404
|
attrs.push(`transform="rotate(${trimNumber(deg)} ${trimNumber(cx)} ${trimNumber(cy)})"`);
|
|
403
405
|
}
|
|
@@ -421,17 +423,18 @@ function paintAttrs(paint, name, registry, includeOpacity = true) {
|
|
|
421
423
|
return [`${name}="url(#${id})"`];
|
|
422
424
|
}
|
|
423
425
|
function coreStrokeAttrs(stroke, registry) {
|
|
424
|
-
|
|
426
|
+
const paint = stroke?.paint;
|
|
427
|
+
if (!stroke || !paint) return [];
|
|
425
428
|
const width = resolveStrokeWidth(stroke.width ?? 1, 1);
|
|
426
429
|
if (!(width > 0)) return [];
|
|
427
430
|
const attrs = [];
|
|
428
|
-
if ("color" in
|
|
429
|
-
attrs.push(`stroke="${
|
|
430
|
-
if (
|
|
431
|
-
attrs.push(`stroke-opacity="${trimNumber(
|
|
431
|
+
if ("color" in paint) {
|
|
432
|
+
attrs.push(`stroke="${paint.color}"`);
|
|
433
|
+
if (paint.opacity != null && paint.opacity !== 1) {
|
|
434
|
+
attrs.push(`stroke-opacity="${trimNumber(paint.opacity)}"`);
|
|
432
435
|
}
|
|
433
436
|
} else {
|
|
434
|
-
attrs.push(`stroke="url(#${registry.register(
|
|
437
|
+
attrs.push(`stroke="url(#${registry.register(paint)})"`);
|
|
435
438
|
}
|
|
436
439
|
attrs.push(`stroke-width="${trimNumber(width)}"`);
|
|
437
440
|
if (stroke.cap) attrs.push(`stroke-linecap="${stroke.cap}"`);
|
|
@@ -494,11 +497,11 @@ function computeBounds(nodes) {
|
|
|
494
497
|
n.children.forEach((c2) => visit(c2, childCtm));
|
|
495
498
|
return;
|
|
496
499
|
}
|
|
497
|
-
const
|
|
498
|
-
const local = n.rotation ? rotateAboutCenter(ctm,
|
|
499
|
-
for (const [
|
|
500
|
-
const px = local[0] *
|
|
501
|
-
const py = local[1] *
|
|
500
|
+
const b = n.kind === "text" || n.kind === "image" ? { minX: n.x, minY: n.y, maxX: n.x + n.width, maxY: n.y + n.height } : pathBounds(n.path);
|
|
501
|
+
const local = n.rotation ? rotateAboutCenter(ctm, b, n.rotation) : ctm;
|
|
502
|
+
for (const [x, y2] of corners(b)) {
|
|
503
|
+
const px = local[0] * x + local[2] * y2 + local[4];
|
|
504
|
+
const py = local[1] * x + local[3] * y2 + local[5];
|
|
502
505
|
if (px < minX) minX = px;
|
|
503
506
|
if (py < minY) minY = py;
|
|
504
507
|
if (px > maxX) maxX = px;
|
|
@@ -511,12 +514,12 @@ function computeBounds(nodes) {
|
|
|
511
514
|
}
|
|
512
515
|
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
513
516
|
}
|
|
514
|
-
function corners(
|
|
515
|
-
return [[
|
|
517
|
+
function corners(b) {
|
|
518
|
+
return [[b.minX, b.minY], [b.maxX, b.minY], [b.maxX, b.maxY], [b.minX, b.maxY]];
|
|
516
519
|
}
|
|
517
|
-
function rotateAboutCenter(ctm,
|
|
518
|
-
const cx = (
|
|
519
|
-
const cy = (
|
|
520
|
+
function rotateAboutCenter(ctm, b, angle) {
|
|
521
|
+
const cx = (b.minX + b.maxX) / 2;
|
|
522
|
+
const cy = (b.minY + b.maxY) / 2;
|
|
520
523
|
const c2 = Math.cos(angle);
|
|
521
524
|
const s = Math.sin(angle);
|
|
522
525
|
return multiply(ctm, [c2, s, -s, c2, cx - cx * c2 + cy * s, cy - cx * s - cy * c2]);
|
|
@@ -549,7 +552,9 @@ function textXml(node, registry, namespaces) {
|
|
|
549
552
|
}
|
|
550
553
|
const decoration = textDecorationValue(style?.underline, style?.strikethrough, style?.overline);
|
|
551
554
|
if (decoration) attrs.push(`text-decoration="${decoration}"`);
|
|
552
|
-
if (node.fill) {
|
|
555
|
+
if (node.fill === null) {
|
|
556
|
+
attrs.push('fill="none"');
|
|
557
|
+
} else if (node.fill) {
|
|
553
558
|
if ("color" in node.fill) {
|
|
554
559
|
attrs.push(`fill="${node.fill.color}"`);
|
|
555
560
|
if (node.fill.opacity != null && node.fill.opacity !== 1) {
|
|
@@ -628,34 +633,32 @@ function pathBounds(path) {
|
|
|
628
633
|
maxY: path.y + path.height
|
|
629
634
|
};
|
|
630
635
|
}
|
|
631
|
-
const
|
|
632
|
-
return { minX:
|
|
636
|
+
const b = boundsOfPath(path);
|
|
637
|
+
return { minX: b.x, minY: b.y, maxX: b.x + b.width, maxY: b.y + b.height };
|
|
633
638
|
}
|
|
634
|
-
|
|
635
|
-
// src/annotations/paint.ts
|
|
636
639
|
var MARK_COLOR = "#e5484d";
|
|
637
640
|
var MARK_WIDTH = 2;
|
|
638
641
|
var TEXT_SIZE = 14;
|
|
639
|
-
var toWorld = (
|
|
640
|
-
x:
|
|
641
|
-
y:
|
|
642
|
+
var toWorld = (p, content) => ({
|
|
643
|
+
x: p.x * content.w,
|
|
644
|
+
y: p.y * content.h
|
|
642
645
|
});
|
|
643
646
|
function vertices(m, content) {
|
|
644
647
|
const stored = m.data.points;
|
|
645
|
-
if (stored && stored.length >= 2) return stored.map((
|
|
646
|
-
const { x
|
|
648
|
+
if (stored && stored.length >= 2) return stored.map((p) => toWorld(p, content));
|
|
649
|
+
const { x, y: y2, width, height } = m.pose;
|
|
647
650
|
return [
|
|
648
|
-
{ x
|
|
649
|
-
{ x:
|
|
651
|
+
{ x, y: y2 },
|
|
652
|
+
{ x: x + width, y: y2 + height }
|
|
650
653
|
];
|
|
651
654
|
}
|
|
652
655
|
function polyline(points) {
|
|
653
|
-
const
|
|
656
|
+
const b = new PathBuilder();
|
|
654
657
|
const first = points[0];
|
|
655
658
|
if (!first) return rectPath(0, 0, 0, 0);
|
|
656
|
-
|
|
657
|
-
for (const
|
|
658
|
-
return
|
|
659
|
+
b.moveTo(first.x, first.y);
|
|
660
|
+
for (const p of points.slice(1)) b.lineTo(p.x, p.y);
|
|
661
|
+
return b.build();
|
|
659
662
|
}
|
|
660
663
|
function markCommands(m, content, style = {}) {
|
|
661
664
|
const color = style.color ?? MARK_COLOR;
|
|
@@ -674,13 +677,13 @@ function markCommands(m, content, style = {}) {
|
|
|
674
677
|
case "ellipse":
|
|
675
678
|
return [{ kind: "path", path: ellipsePath(m.pose), stroke }];
|
|
676
679
|
case "line": {
|
|
677
|
-
const [a,
|
|
678
|
-
return [{ kind: "path", path: linePath(a,
|
|
680
|
+
const [a, b] = vertices(m, content);
|
|
681
|
+
return [{ kind: "path", path: linePath(a, b), stroke }];
|
|
679
682
|
}
|
|
680
683
|
case "arrow": {
|
|
681
|
-
const [a,
|
|
684
|
+
const [a, b] = vertices(m, content);
|
|
682
685
|
const marked = { ...stroke, markerEnd: "arrow" };
|
|
683
|
-
const path = linePath(a,
|
|
686
|
+
const path = linePath(a, b);
|
|
684
687
|
return [
|
|
685
688
|
{ kind: "path", path, stroke: marked },
|
|
686
689
|
...markerDrawCommands(path, marked, MARK_WIDTH, void 0)
|
|
@@ -742,8 +745,6 @@ function resolveMarkStyle(data, opts) {
|
|
|
742
745
|
stale: isStale(data.seen, opts.config, opts.positionDependsOn ?? [])
|
|
743
746
|
};
|
|
744
747
|
}
|
|
745
|
-
|
|
746
|
-
// src/annotations/svgNodes.ts
|
|
747
748
|
var NO_PAINT = { kind: "none" };
|
|
748
749
|
function toSvgPaint(paint) {
|
|
749
750
|
if (!paint) return NO_PAINT;
|
|
@@ -799,7 +800,7 @@ function capturePlan(base, format) {
|
|
|
799
800
|
if (format === "svg") return "svg-document";
|
|
800
801
|
return base?.kind === "svg" ? "svg-document" : "raster-stack";
|
|
801
802
|
}
|
|
802
|
-
function nestBaseSvg(markup, w3,
|
|
803
|
+
function nestBaseSvg(markup, w3, h) {
|
|
803
804
|
const doc = new DOMParser().parseFromString(markup, "image/svg+xml");
|
|
804
805
|
const root = doc.documentElement;
|
|
805
806
|
if (doc.getElementsByTagName("parsererror").length > 0 || root.localName !== "svg") {
|
|
@@ -808,16 +809,16 @@ function nestBaseSvg(markup, w3, h2) {
|
|
|
808
809
|
root.setAttribute("x", "0");
|
|
809
810
|
root.setAttribute("y", "0");
|
|
810
811
|
root.setAttribute("width", String(w3));
|
|
811
|
-
root.setAttribute("height", String(
|
|
812
|
+
root.setAttribute("height", String(h));
|
|
812
813
|
return new XMLSerializer().serializeToString(root);
|
|
813
814
|
}
|
|
814
|
-
function embedRasterBase(base, w3,
|
|
815
|
+
function embedRasterBase(base, w3, h, onWarn) {
|
|
815
816
|
const href = base.kind === "canvas" ? base.canvas.toDataURL() : base.kind === "image" ? base.src : "";
|
|
816
817
|
if (base.kind === "image" && !href.startsWith("data:")) {
|
|
817
818
|
onWarn?.(`base image '${href}' is a reference, so this SVG is not self-contained`);
|
|
818
819
|
}
|
|
819
|
-
return serializeSvg([{ kind: "image", href, x: 0, y: 0, width: w3, height:
|
|
820
|
-
viewBox: { x: 0, y: 0, width: w3, height:
|
|
820
|
+
return serializeSvg([{ kind: "image", href, x: 0, y: 0, width: w3, height: h }], {
|
|
821
|
+
viewBox: { x: 0, y: 0, width: w3, height: h }
|
|
821
822
|
});
|
|
822
823
|
}
|
|
823
824
|
function markNodesOf(scene, draw) {
|
|
@@ -833,15 +834,15 @@ function markNodesOf(scene, draw) {
|
|
|
833
834
|
}
|
|
834
835
|
function composeCaptureSvg(args) {
|
|
835
836
|
const { base, scene, draw, scale, onWarn } = args;
|
|
836
|
-
const { w: w3, h
|
|
837
|
-
const baseXml = base === void 0 ? "" : base.kind === "svg" ? nestBaseSvg(base.markup, w3,
|
|
837
|
+
const { w: w3, h } = draw.content;
|
|
838
|
+
const baseXml = base === void 0 ? "" : base.kind === "svg" ? nestBaseSvg(base.markup, w3, h) : embedRasterBase(base, w3, h, onWarn);
|
|
838
839
|
const marksXml = serializeSvg(markNodesOf(scene, draw), {
|
|
839
|
-
viewBox: { x: 0, y: 0, width: w3, height:
|
|
840
|
+
viewBox: { x: 0, y: 0, width: w3, height: h },
|
|
840
841
|
onWarn
|
|
841
842
|
});
|
|
842
843
|
const outW = Math.max(1, Math.round(w3 * scale));
|
|
843
|
-
const outH = Math.max(1, Math.round(
|
|
844
|
-
return `<svg xmlns="${SVG_NS}" width="${outW}" height="${outH}" viewBox="0 0 ${w3} ${
|
|
844
|
+
const outH = Math.max(1, Math.round(h * scale));
|
|
845
|
+
return `<svg xmlns="${SVG_NS}" width="${outW}" height="${outH}" viewBox="0 0 ${w3} ${h}">${baseXml}${marksXml}</svg>`;
|
|
845
846
|
}
|
|
846
847
|
function context2d(width, height) {
|
|
847
848
|
const canvas = document.createElement("canvas");
|
|
@@ -1041,8 +1042,6 @@ function drop(stack, value) {
|
|
|
1041
1042
|
}
|
|
1042
1043
|
}
|
|
1043
1044
|
}
|
|
1044
|
-
|
|
1045
|
-
// src/annotations/store.ts
|
|
1046
1045
|
function createAnnotationScene() {
|
|
1047
1046
|
return createScene({ systemLayers: [{ id: "marks" }] });
|
|
1048
1047
|
}
|
|
@@ -1265,17 +1264,17 @@ function annotationsFromJSON(raw, targets, rest = {}) {
|
|
|
1265
1264
|
}
|
|
1266
1265
|
|
|
1267
1266
|
// src/annotations/view.ts
|
|
1268
|
-
function toWeaselView(
|
|
1269
|
-
return { x:
|
|
1267
|
+
function toWeaselView(v) {
|
|
1268
|
+
return { x: v.pan.x, y: v.pan.y, scale: { x: v.zoom, y: v.zoom } };
|
|
1270
1269
|
}
|
|
1271
|
-
function fromWeaselView(
|
|
1272
|
-
return { zoom:
|
|
1270
|
+
function fromWeaselView(v) {
|
|
1271
|
+
return { zoom: v.scale.x, pan: { x: v.x, y: v.y } };
|
|
1273
1272
|
}
|
|
1274
1273
|
function fitView(content, pane) {
|
|
1275
1274
|
const zoom = content.w > 0 && content.h > 0 ? Math.min(pane.w / content.w, pane.h / content.h) : 1;
|
|
1276
1275
|
return { zoom: Number.isFinite(zoom) && zoom > 0 ? zoom : 1, pan: { x: 0, y: 0 } };
|
|
1277
1276
|
}
|
|
1278
|
-
var sameRect = (a,
|
|
1277
|
+
var sameRect = (a, b) => a !== null && a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h;
|
|
1279
1278
|
function ToolBridge({ toolId }) {
|
|
1280
1279
|
const tools = useActiveToolContext();
|
|
1281
1280
|
const setActive = tools.setActive;
|
|
@@ -1285,9 +1284,9 @@ function ToolBridge({ toolId }) {
|
|
|
1285
1284
|
return null;
|
|
1286
1285
|
}
|
|
1287
1286
|
function pointsOf(extras, content) {
|
|
1288
|
-
const toFrac = (
|
|
1289
|
-
x: content.w === 0 ? 0 :
|
|
1290
|
-
y: content.h === 0 ? 0 :
|
|
1287
|
+
const toFrac = (p) => ({
|
|
1288
|
+
x: content.w === 0 ? 0 : p.x / content.w,
|
|
1289
|
+
y: content.h === 0 ? 0 : p.y / content.h
|
|
1291
1290
|
});
|
|
1292
1291
|
if (extras.kind === "line") {
|
|
1293
1292
|
return [toFrac(extras.a), toFrac(extras.b)];
|
|
@@ -1411,10 +1410,11 @@ function AnnotationTargets({
|
|
|
1411
1410
|
capability,
|
|
1412
1411
|
state,
|
|
1413
1412
|
config,
|
|
1413
|
+
trial,
|
|
1414
1414
|
annotations,
|
|
1415
1415
|
activeToolId
|
|
1416
1416
|
}) {
|
|
1417
|
-
const targets = capability.targets(state, config);
|
|
1417
|
+
const targets = capability.targets(state, config, trial);
|
|
1418
1418
|
return /* @__PURE__ */ jsx(Fragment, { children: targets.map((t) => /* @__PURE__ */ jsx(
|
|
1419
1419
|
AnnotationOverlay,
|
|
1420
1420
|
{
|
|
@@ -1429,6 +1429,9 @@ function AnnotationTargets({
|
|
|
1429
1429
|
}
|
|
1430
1430
|
|
|
1431
1431
|
// src/config/builder.ts
|
|
1432
|
+
function isConfigBranch(entry) {
|
|
1433
|
+
return "children" in entry;
|
|
1434
|
+
}
|
|
1432
1435
|
var BaseNode = class {
|
|
1433
1436
|
constructor(defaultValue, annotations = {}, options = {}) {
|
|
1434
1437
|
this.annotations = annotations;
|
|
@@ -1468,9 +1471,10 @@ var BaseNode = class {
|
|
|
1468
1471
|
pair(pair) {
|
|
1469
1472
|
return this.ann({ pair });
|
|
1470
1473
|
}
|
|
1471
|
-
/** Render under a named section heading.
|
|
1472
|
-
section
|
|
1473
|
-
|
|
1474
|
+
/** Render under a named section heading. `collapsed` opens the section
|
|
1475
|
+
* folded — say it on any one of the section's leaves. */
|
|
1476
|
+
section(label, opts = {}) {
|
|
1477
|
+
return this.opt({ section: { label, ...opts } });
|
|
1474
1478
|
}
|
|
1475
1479
|
/** Show this row only while the predicate holds. Presentational — the value
|
|
1476
1480
|
* stays in config and the instrument still reads it. */
|
|
@@ -1554,6 +1558,45 @@ var CustomNode = class _CustomNode extends BaseNode {
|
|
|
1554
1558
|
return new _CustomNode(this.kind, this.default, annotations, options);
|
|
1555
1559
|
}
|
|
1556
1560
|
};
|
|
1561
|
+
var GroupNode = class _GroupNode {
|
|
1562
|
+
constructor(children, annotations = {}, options = {}) {
|
|
1563
|
+
this.children = children;
|
|
1564
|
+
this.annotations = annotations;
|
|
1565
|
+
this.options = options;
|
|
1566
|
+
}
|
|
1567
|
+
children;
|
|
1568
|
+
annotations;
|
|
1569
|
+
options;
|
|
1570
|
+
with(annotations, options) {
|
|
1571
|
+
return new _GroupNode(this.children, annotations, options);
|
|
1572
|
+
}
|
|
1573
|
+
/** Heading for the group's rows. Defaults to the key, title-cased. */
|
|
1574
|
+
label(name) {
|
|
1575
|
+
return this.with({ ...this.annotations, name }, this.options);
|
|
1576
|
+
}
|
|
1577
|
+
/** Longer help text. Carried on the resolved `PrefGroup`, where weasel-ui's
|
|
1578
|
+
* `PrefsForm` draws it under the heading; `ControlPanel` has no place for
|
|
1579
|
+
* it yet and shows the heading alone. */
|
|
1580
|
+
describe(description) {
|
|
1581
|
+
return this.with({ ...this.annotations, description }, this.options);
|
|
1582
|
+
}
|
|
1583
|
+
/** Render this whole group under a named section heading. */
|
|
1584
|
+
section(label, opts = {}) {
|
|
1585
|
+
return this.with(this.annotations, { ...this.options, section: { label, ...opts } });
|
|
1586
|
+
}
|
|
1587
|
+
/** Show this group only while the predicate holds. Presentational — every
|
|
1588
|
+
* value beneath it stays in config and the instrument still reads it. */
|
|
1589
|
+
showIf(predicate) {
|
|
1590
|
+
return this.with(this.annotations, { ...this.options, showIf: predicate });
|
|
1591
|
+
}
|
|
1592
|
+
};
|
|
1593
|
+
function shapeDefaults(shape) {
|
|
1594
|
+
const out = {};
|
|
1595
|
+
for (const [key, entry] of Object.entries(shape)) {
|
|
1596
|
+
out[key] = isConfigBranch(entry) ? shapeDefaults(entry.children) : entry.default;
|
|
1597
|
+
}
|
|
1598
|
+
return out;
|
|
1599
|
+
}
|
|
1557
1600
|
var expand = (options) => options.map((o) => typeof o === "string" ? { value: o, label: o } : o);
|
|
1558
1601
|
var f = {
|
|
1559
1602
|
number: (def) => new NumberNode(def),
|
|
@@ -1567,18 +1610,15 @@ var f = {
|
|
|
1567
1610
|
/** A leaf with no declared kind: the rule chain decides, which is how a lab
|
|
1568
1611
|
* states a convention like "every `*Color` key is a color picker". */
|
|
1569
1612
|
value: (def) => new ValueNode(def),
|
|
1613
|
+
/** A branch: its children nest under this key, so `grid: f.group({ size })`
|
|
1614
|
+
* puts the value at `config.grid.size` and addresses it as `'grid.size'`.
|
|
1615
|
+
* Groups nest as deeply as the schema wants. */
|
|
1616
|
+
group: (children) => new GroupNode(children),
|
|
1570
1617
|
/** A leaf of a kind a lab supplies the control for, through `controls`. */
|
|
1571
1618
|
custom: (kind, def, validate) => new CustomNode(kind, def, {}, validate ? { validate } : {}),
|
|
1572
|
-
/** Collect leaves into an instrument's config. */
|
|
1619
|
+
/** Collect leaves and groups into an instrument's config. */
|
|
1573
1620
|
schema(nodes) {
|
|
1574
|
-
return {
|
|
1575
|
-
nodes,
|
|
1576
|
-
defaults: () => {
|
|
1577
|
-
const out = {};
|
|
1578
|
-
for (const [key, node] of Object.entries(nodes)) out[key] = node.default;
|
|
1579
|
-
return out;
|
|
1580
|
-
}
|
|
1581
|
-
};
|
|
1621
|
+
return { nodes, defaults: () => shapeDefaults(nodes) };
|
|
1582
1622
|
}
|
|
1583
1623
|
};
|
|
1584
1624
|
|
|
@@ -1610,9 +1650,9 @@ function applyRules(seed, ctx, rules) {
|
|
|
1610
1650
|
for (const rule of rules) {
|
|
1611
1651
|
const patch = rule({ ...ctx, leaf: acc });
|
|
1612
1652
|
if (patch === null) continue;
|
|
1613
|
-
for (const [k2,
|
|
1614
|
-
if (
|
|
1615
|
-
acc[k2] =
|
|
1653
|
+
for (const [k2, v] of Object.entries(patch)) {
|
|
1654
|
+
if (v !== void 0 && acc[k2] === void 0) {
|
|
1655
|
+
acc[k2] = v;
|
|
1616
1656
|
}
|
|
1617
1657
|
}
|
|
1618
1658
|
}
|
|
@@ -1622,40 +1662,59 @@ function applyRules(seed, ctx, rules) {
|
|
|
1622
1662
|
// src/config/resolve.ts
|
|
1623
1663
|
function defined(annotations) {
|
|
1624
1664
|
const out = {};
|
|
1625
|
-
for (const [k2,
|
|
1665
|
+
for (const [k2, v] of Object.entries(annotations)) if (v !== void 0) out[k2] = v;
|
|
1626
1666
|
return out;
|
|
1627
1667
|
}
|
|
1628
1668
|
function resolveConfigSchema(schema, rules = []) {
|
|
1669
|
+
const sink = {
|
|
1670
|
+
sections: [],
|
|
1671
|
+
showIf: /* @__PURE__ */ new Map(),
|
|
1672
|
+
renderers: {},
|
|
1673
|
+
chain: [...rules, ...builtinRules]
|
|
1674
|
+
};
|
|
1675
|
+
const group = resolveShape(schema.nodes, "", "", sink);
|
|
1676
|
+
return { group, sections: sink.sections, showIf: sink.showIf, renderers: sink.renderers };
|
|
1677
|
+
}
|
|
1678
|
+
function resolveShape(shape, at, name, sink) {
|
|
1629
1679
|
const children = {};
|
|
1630
|
-
const
|
|
1631
|
-
const
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
for (const [key, node] of Object.entries(schema.nodes)) {
|
|
1636
|
-
const seed = defined({
|
|
1637
|
-
...node.annotations,
|
|
1638
|
-
...node.kind === null ? {} : { kind: node.kind }
|
|
1639
|
-
});
|
|
1640
|
-
const patch = applyRules(seed, { key, path: key, default: node.default }, chain2);
|
|
1641
|
-
children[key] = { ...patch, default: node.default };
|
|
1642
|
-
const { section, showIf: predicate, render } = node.options;
|
|
1680
|
+
const sections = /* @__PURE__ */ new Map();
|
|
1681
|
+
for (const [key, entry] of Object.entries(shape)) {
|
|
1682
|
+
const path = at === "" ? key : `${at}.${key}`;
|
|
1683
|
+
children[key] = resolveEntry(entry, key, path, sink);
|
|
1684
|
+
const { section, showIf: predicate } = entry.options;
|
|
1643
1685
|
if (section !== void 0) {
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1686
|
+
let spec = sections.get(section.label);
|
|
1687
|
+
if (!spec) {
|
|
1688
|
+
spec = { at, label: section.label, paths: [] };
|
|
1689
|
+
sections.set(section.label, spec);
|
|
1690
|
+
sink.sections.push(spec);
|
|
1691
|
+
}
|
|
1692
|
+
spec.paths.push(path);
|
|
1693
|
+
if (section.collapsed !== void 0) {
|
|
1694
|
+
spec.collapsed = (spec.collapsed ?? false) || section.collapsed;
|
|
1647
1695
|
}
|
|
1648
|
-
sectionPaths.get(section)?.push(key);
|
|
1649
1696
|
}
|
|
1650
|
-
if (predicate) showIf.set(
|
|
1651
|
-
if (render) renderers[
|
|
1697
|
+
if (predicate) sink.showIf.set(path, predicate);
|
|
1698
|
+
if (!isConfigBranch(entry) && entry.options.render) sink.renderers[path] = entry.options.render;
|
|
1699
|
+
}
|
|
1700
|
+
return { name, children };
|
|
1701
|
+
}
|
|
1702
|
+
function resolveEntry(entry, key, path, sink) {
|
|
1703
|
+
if (isConfigBranch(entry)) {
|
|
1704
|
+
const group = resolveShape(
|
|
1705
|
+
entry.children,
|
|
1706
|
+
path,
|
|
1707
|
+
entry.annotations.name ?? titleCase(key),
|
|
1708
|
+
sink
|
|
1709
|
+
);
|
|
1710
|
+
return entry.annotations.description === void 0 ? group : { ...group, description: entry.annotations.description };
|
|
1652
1711
|
}
|
|
1653
|
-
const
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
})
|
|
1658
|
-
return {
|
|
1712
|
+
const seed = defined({
|
|
1713
|
+
...entry.annotations,
|
|
1714
|
+
...entry.kind === null ? {} : { kind: entry.kind }
|
|
1715
|
+
});
|
|
1716
|
+
const patch = applyRules(seed, { key, path, default: entry.default }, sink.chain);
|
|
1717
|
+
return { ...patch, default: entry.default };
|
|
1659
1718
|
}
|
|
1660
1719
|
var LabContext = createContext(null);
|
|
1661
1720
|
function useLabContext() {
|
|
@@ -2303,9 +2362,9 @@ function hexToRgba(hex, alpha) {
|
|
|
2303
2362
|
const body = m[1];
|
|
2304
2363
|
const full = body.length === 3 ? body.replace(/./g, (c2) => c2 + c2) : body;
|
|
2305
2364
|
const r2 = Number.parseInt(full.slice(0, 2), 16);
|
|
2306
|
-
const
|
|
2307
|
-
const
|
|
2308
|
-
return `rgba(${r2}, ${
|
|
2365
|
+
const g2 = Number.parseInt(full.slice(2, 4), 16);
|
|
2366
|
+
const b = Number.parseInt(full.slice(4, 6), 16);
|
|
2367
|
+
return `rgba(${r2}, ${g2}, ${b}, ${alpha})`;
|
|
2309
2368
|
}
|
|
2310
2369
|
var REF = /^\{([^}]+)\}$/;
|
|
2311
2370
|
function refTarget(value) {
|
|
@@ -2443,17 +2502,36 @@ function useThemeOptional() {
|
|
|
2443
2502
|
return useContext(ThemeContext);
|
|
2444
2503
|
}
|
|
2445
2504
|
|
|
2505
|
+
// src/instrument/serializers.ts
|
|
2506
|
+
function configDefaultsOf(instruments) {
|
|
2507
|
+
const out = {};
|
|
2508
|
+
for (const instrument of instruments) out[instrument.name] = () => instrument.defaultConfig();
|
|
2509
|
+
return out;
|
|
2510
|
+
}
|
|
2511
|
+
function serializersOf(instruments) {
|
|
2512
|
+
const out = {};
|
|
2513
|
+
for (const instrument of instruments) {
|
|
2514
|
+
const { name, serialize: serialize2, deserialize } = instrument;
|
|
2515
|
+
if (!serialize2 && !deserialize) continue;
|
|
2516
|
+
out[name] = {
|
|
2517
|
+
...serialize2 ? { serialize: (state) => serialize2(state) } : {},
|
|
2518
|
+
...deserialize ? { deserialize: (data, config) => deserialize(data, config) } : {}
|
|
2519
|
+
};
|
|
2520
|
+
}
|
|
2521
|
+
return out;
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2446
2524
|
// ../theme/dist/index.js
|
|
2447
2525
|
var ALPHA_EXT = "com.weasel.alpha";
|
|
2448
|
-
var isToken = (
|
|
2526
|
+
var isToken = (v) => typeof v === "object" && v !== null && "$value" in v;
|
|
2449
2527
|
function flattenTokens(doc) {
|
|
2450
2528
|
const out = {};
|
|
2451
2529
|
for (const [groupName, group] of Object.entries(doc)) {
|
|
2452
2530
|
if (groupName.startsWith("$")) continue;
|
|
2453
2531
|
if (typeof group !== "object" || group === null) continue;
|
|
2454
|
-
const
|
|
2455
|
-
const groupType =
|
|
2456
|
-
for (const [leaf, node] of Object.entries(
|
|
2532
|
+
const g2 = group;
|
|
2533
|
+
const groupType = g2.$type;
|
|
2534
|
+
for (const [leaf, node] of Object.entries(g2)) {
|
|
2457
2535
|
if (leaf.startsWith("$")) continue;
|
|
2458
2536
|
if (!isToken(node)) continue;
|
|
2459
2537
|
const type = node.$type ?? groupType;
|
|
@@ -2563,11 +2641,11 @@ var interstellarTheme = loadDTCG(interstellar_tokens_default);
|
|
|
2563
2641
|
var DEFAULT_VIEW = { zoom: 1, pan: { x: 0, y: 0 } };
|
|
2564
2642
|
function as2DView(view) {
|
|
2565
2643
|
if (typeof view !== "object" || view === null) return null;
|
|
2566
|
-
const
|
|
2567
|
-
if (typeof
|
|
2568
|
-
if (typeof
|
|
2569
|
-
if (typeof
|
|
2570
|
-
return { zoom:
|
|
2644
|
+
const v = view;
|
|
2645
|
+
if (typeof v.zoom !== "number") return null;
|
|
2646
|
+
if (typeof v.pan !== "object" || v.pan === null) return null;
|
|
2647
|
+
if (typeof v.pan.x !== "number" || typeof v.pan.y !== "number") return null;
|
|
2648
|
+
return { zoom: v.zoom, pan: { x: v.pan.x, y: v.pan.y } };
|
|
2571
2649
|
}
|
|
2572
2650
|
var ZONE_ID = asNodeId("lk-trial-body");
|
|
2573
2651
|
var SIDEBAR_ID = asNodeId("lk-trial-sidebar");
|
|
@@ -2671,18 +2749,20 @@ var TrialDragContext = createContext(null);
|
|
|
2671
2749
|
function useTrialDrag() {
|
|
2672
2750
|
return useContext(TrialDragContext);
|
|
2673
2751
|
}
|
|
2674
|
-
function Draggable({ nodeId, title, children }) {
|
|
2752
|
+
function Draggable({ nodeId, title, lead, children }) {
|
|
2675
2753
|
const handlers = useDragHandle(nodeId);
|
|
2676
2754
|
return /* @__PURE__ */ jsxs("div", { className: "lk-trial__titlebar lk-trial__titlebar--draggable", ...handlers, children: [
|
|
2755
|
+
lead,
|
|
2677
2756
|
/* @__PURE__ */ jsx("span", { className: "lk-trial__title", children: title }),
|
|
2678
2757
|
children
|
|
2679
2758
|
] });
|
|
2680
2759
|
}
|
|
2681
|
-
function TrialTitleBar({ title, children }) {
|
|
2760
|
+
function TrialTitleBar({ title, lead, children }) {
|
|
2682
2761
|
const drag = useTrialDrag();
|
|
2683
2762
|
if (drag)
|
|
2684
|
-
return /* @__PURE__ */ jsx(Draggable, { nodeId: drag.nodeId, title, children });
|
|
2763
|
+
return /* @__PURE__ */ jsx(Draggable, { nodeId: drag.nodeId, title, lead, children });
|
|
2685
2764
|
return /* @__PURE__ */ jsxs("div", { className: "lk-trial__titlebar", children: [
|
|
2765
|
+
lead,
|
|
2686
2766
|
/* @__PURE__ */ jsx("span", { className: "lk-trial__title", children: title }),
|
|
2687
2767
|
children
|
|
2688
2768
|
] });
|
|
@@ -2752,6 +2832,7 @@ function UndockedSections({ trialId, sections, onDock }) {
|
|
|
2752
2832
|
}
|
|
2753
2833
|
var NO_OP = () => {
|
|
2754
2834
|
};
|
|
2835
|
+
var NO_SECTIONS = Object.freeze({});
|
|
2755
2836
|
function TrialChrome({
|
|
2756
2837
|
trialId,
|
|
2757
2838
|
record,
|
|
@@ -2772,17 +2853,21 @@ function TrialChrome({
|
|
|
2772
2853
|
if (!storeCtx) throw new Error("[labkit] TrialChrome requires <LabStoreProvider>");
|
|
2773
2854
|
const updateTrialView = useStore(storeCtx.store, (s) => s.updateTrialView);
|
|
2774
2855
|
const updateTrialSidebarWidth = useStore(storeCtx.store, (s) => s.updateTrialSidebarWidth);
|
|
2856
|
+
const setTrialTitle = useStore(storeCtx.store, (s) => s.setTrialTitle);
|
|
2857
|
+
const setTrialSectionCollapsed = useStore(storeCtx.store, (s) => s.setTrialSectionCollapsed);
|
|
2775
2858
|
const updateTrialConfig = useStore(storeCtx.store, (s) => s.updateTrialConfig);
|
|
2776
2859
|
const updateTrialState = useStore(storeCtx.store, (s) => s.updateTrialState);
|
|
2777
2860
|
const undockPanelAction = useStore(storeCtx.store, (s) => s.undockPanel);
|
|
2778
2861
|
const dockPanelAction = useStore(storeCtx.store, (s) => s.dockPanel);
|
|
2779
2862
|
const undockedPanels = useStore(storeCtx.store, (s) => s.undockedPanels);
|
|
2780
2863
|
const undockedIds = useMemo(
|
|
2781
|
-
() => Object.values(undockedPanels).filter((
|
|
2864
|
+
() => Object.values(undockedPanels).filter((p) => p.trialId === trialId).map((p) => p.sectionId),
|
|
2782
2865
|
[undockedPanels, trialId]
|
|
2783
2866
|
);
|
|
2784
2867
|
const view2d = as2DView(record.view);
|
|
2785
2868
|
const configSchema = useConfigSchema(instrument);
|
|
2869
|
+
const title = record.title ?? record.instrumentName;
|
|
2870
|
+
const collapsedSections = record.collapsedSections ?? NO_SECTIONS;
|
|
2786
2871
|
const ctx = useMemo(() => {
|
|
2787
2872
|
const setZoom = (z) => {
|
|
2788
2873
|
if (!view2d) return;
|
|
@@ -2791,6 +2876,8 @@ function TrialChrome({
|
|
|
2791
2876
|
return {
|
|
2792
2877
|
trialId,
|
|
2793
2878
|
instrumentName: record.instrumentName,
|
|
2879
|
+
title,
|
|
2880
|
+
setTitle: (next) => setTrialTitle(trialId, next),
|
|
2794
2881
|
isLastTrial,
|
|
2795
2882
|
zoom: view2d ? view2d.zoom : null,
|
|
2796
2883
|
setZoom,
|
|
@@ -2803,20 +2890,22 @@ function TrialChrome({
|
|
|
2803
2890
|
configSchema,
|
|
2804
2891
|
configFields: instrument.config ? [] : instrument.configSchema?.() ?? [],
|
|
2805
2892
|
config: record.config,
|
|
2806
|
-
setConfig: (
|
|
2893
|
+
setConfig: (path, value) => {
|
|
2807
2894
|
const prevConfig = record.config;
|
|
2808
|
-
if (process.env.NODE_ENV !== "production" && !(
|
|
2895
|
+
if (process.env.NODE_ENV !== "production" && !hasConfigPath(prevConfig, path) && schemaNodeAtPath(configSchema.group, path) === void 0) {
|
|
2809
2896
|
console.warn(
|
|
2810
|
-
`[labkit] setConfig: unknown
|
|
2897
|
+
`[labkit] setConfig: unknown path "${path}" for instrument "${record.instrumentName}"`
|
|
2811
2898
|
);
|
|
2812
2899
|
}
|
|
2813
|
-
updateTrialConfig(trialId,
|
|
2900
|
+
updateTrialConfig(trialId, path, value);
|
|
2814
2901
|
if (instrument.onConfigChange) {
|
|
2815
|
-
const nextConfig =
|
|
2902
|
+
const nextConfig = withValueAtPath(prevConfig, path, value);
|
|
2816
2903
|
const nextState = instrument.onConfigChange(nextConfig, prevConfig, record.state);
|
|
2817
2904
|
updateTrialState(trialId, nextState);
|
|
2818
2905
|
}
|
|
2819
2906
|
},
|
|
2907
|
+
collapsedSections,
|
|
2908
|
+
setSectionCollapsed: (key, collapsed) => setTrialSectionCollapsed(trialId, key, collapsed),
|
|
2820
2909
|
undockedPanels: undockedIds,
|
|
2821
2910
|
undockPanel: (sectionId, as) => undockPanelAction(trialId, sectionId, as),
|
|
2822
2911
|
dockPanel: (sectionId) => dockPanelAction(trialId, sectionId),
|
|
@@ -2834,6 +2923,7 @@ function TrialChrome({
|
|
|
2834
2923
|
record,
|
|
2835
2924
|
instrument,
|
|
2836
2925
|
lab,
|
|
2926
|
+
title,
|
|
2837
2927
|
isLastTrial,
|
|
2838
2928
|
updateTrialView,
|
|
2839
2929
|
updateTrialConfig,
|
|
@@ -2846,7 +2936,10 @@ function TrialChrome({
|
|
|
2846
2936
|
configSchema,
|
|
2847
2937
|
undockedIds,
|
|
2848
2938
|
undockPanelAction,
|
|
2849
|
-
dockPanelAction
|
|
2939
|
+
dockPanelAction,
|
|
2940
|
+
setTrialTitle,
|
|
2941
|
+
setTrialSectionCollapsed,
|
|
2942
|
+
collapsedSections
|
|
2850
2943
|
]);
|
|
2851
2944
|
const contributions = useMemo(
|
|
2852
2945
|
() => suppressContributions(
|
|
@@ -2877,11 +2970,18 @@ function TrialChrome({
|
|
|
2877
2970
|
"section",
|
|
2878
2971
|
{
|
|
2879
2972
|
className: "lk-trial",
|
|
2880
|
-
"aria-label": `Trial ${
|
|
2973
|
+
"aria-label": `Trial ${title}`,
|
|
2881
2974
|
tabIndex: -1,
|
|
2882
2975
|
onKeyDown: handleKeyDown,
|
|
2883
2976
|
children: [
|
|
2884
|
-
/* @__PURE__ */ jsx(
|
|
2977
|
+
/* @__PURE__ */ jsx(
|
|
2978
|
+
TrialTitleBar,
|
|
2979
|
+
{
|
|
2980
|
+
title,
|
|
2981
|
+
lead: /* @__PURE__ */ jsx(TitleBarRegion, { placement: "lead", contributions: inRegion("titlebar"), ctx }),
|
|
2982
|
+
children: /* @__PURE__ */ jsx(TitleBarRegion, { contributions: inRegion("titlebar"), ctx })
|
|
2983
|
+
}
|
|
2984
|
+
),
|
|
2885
2985
|
/* @__PURE__ */ jsx("div", { className: "lk-trial__toolbar", children: /* @__PURE__ */ jsx(ToolbarRegion, { contributions: inRegion("toolbar"), ctx }) }),
|
|
2886
2986
|
/* @__PURE__ */ jsxs("div", { className: "lk-trial__body", children: [
|
|
2887
2987
|
/* @__PURE__ */ jsx(PaletteRegion, { contributions: inRegion("palette"), ctx }),
|
|
@@ -2978,7 +3078,7 @@ function TrialRuntime({ record, instrument, store, isLast, chrome, suppress }) {
|
|
|
2978
3078
|
const snap = structuredClone(current.state);
|
|
2979
3079
|
updateTrialUndoStack(record.id, (prev) => pushSnapshot(prev, snap, maxDepth));
|
|
2980
3080
|
};
|
|
2981
|
-
const setView = (
|
|
3081
|
+
const setView = (v) => updateTrialView(record.id, v);
|
|
2982
3082
|
const placeView = (size) => {
|
|
2983
3083
|
const declared = instrument.canvas?.initialView;
|
|
2984
3084
|
if (typeof declared !== "function") return;
|
|
@@ -2987,7 +3087,7 @@ function TrialRuntime({ record, instrument, store, isLast, chrome, suppress }) {
|
|
|
2987
3087
|
};
|
|
2988
3088
|
const annotationsCap = instrument.annotations;
|
|
2989
3089
|
const targetsRef = useRef(() => []);
|
|
2990
|
-
targetsRef.current = () => annotationsCap ? annotationsCap.targets(record.state, record.config) : [];
|
|
3090
|
+
targetsRef.current = () => annotationsCap ? annotationsCap.targets(record.state, record.config, { id: record.id, view: record.view }) : [];
|
|
2991
3091
|
const annotationsRef = useRef(null);
|
|
2992
3092
|
const configRef = useRef(record.config);
|
|
2993
3093
|
configRef.current = record.config;
|
|
@@ -3063,11 +3163,11 @@ function TrialRuntime({ record, instrument, store, isLast, chrome, suppress }) {
|
|
|
3063
3163
|
updateTrialState(record.id, next);
|
|
3064
3164
|
bus.emit("state.change");
|
|
3065
3165
|
},
|
|
3066
|
-
setConfig: (
|
|
3067
|
-
const evt = `config.change:${
|
|
3166
|
+
setConfig: (path, value) => {
|
|
3167
|
+
const evt = `config.change:${path}`;
|
|
3068
3168
|
snapshotIfNeeded("config.change");
|
|
3069
3169
|
snapshotIfNeeded(evt);
|
|
3070
|
-
updateTrialConfig(record.id,
|
|
3170
|
+
updateTrialConfig(record.id, path, value);
|
|
3071
3171
|
bus.emit("config.change");
|
|
3072
3172
|
bus.emit(evt);
|
|
3073
3173
|
},
|
|
@@ -3118,11 +3218,11 @@ function TrialRuntime({ record, instrument, store, isLast, chrome, suppress }) {
|
|
|
3118
3218
|
if (declared == null) return null;
|
|
3119
3219
|
return resolveLoupe(typeof declared === "function" ? declared(record.config) : declared);
|
|
3120
3220
|
}, [instrument.loupe, record.config]);
|
|
3121
|
-
const loupeBindings = loupeCap ? { on: loupeOn, toggle: () => setLoupeOn((
|
|
3221
|
+
const loupeBindings = loupeCap ? { on: loupeOn, toggle: () => setLoupeOn((v) => !v) } : void 0;
|
|
3122
3222
|
const canvasLayers = useMemo(() => {
|
|
3123
3223
|
if (!instrument.canvas) return [];
|
|
3124
3224
|
const baseLayers = instrument.canvas.layers;
|
|
3125
|
-
const ordered = layerOrder ? [...baseLayers].sort((a,
|
|
3225
|
+
const ordered = layerOrder ? [...baseLayers].sort((a, b) => layerOrder.indexOf(a.id) - layerOrder.indexOf(b.id)) : baseLayers;
|
|
3126
3226
|
return ordered.map((layer) => ({
|
|
3127
3227
|
id: layer.id,
|
|
3128
3228
|
visible: layerVisibility[layer.id] !== false,
|
|
@@ -3154,8 +3254,8 @@ function TrialRuntime({ record, instrument, store, isLast, chrome, suppress }) {
|
|
|
3154
3254
|
});
|
|
3155
3255
|
const paletteItems = useMemo(() => {
|
|
3156
3256
|
if (!instrument.dragDrop) return [];
|
|
3157
|
-
const
|
|
3158
|
-
return typeof
|
|
3257
|
+
const p = instrument.dragDrop.palette;
|
|
3258
|
+
return typeof p === "function" ? p(record.state, record.config) : p;
|
|
3159
3259
|
}, [instrument.dragDrop, record.state, record.config]);
|
|
3160
3260
|
const layersWithFeedback = useMemo(() => {
|
|
3161
3261
|
if (!dragDropResult.drag?.feedback) return canvasLayers;
|
|
@@ -3269,6 +3369,7 @@ function TrialRuntime({ record, instrument, store, isLast, chrome, suppress }) {
|
|
|
3269
3369
|
capability: annotationsCap,
|
|
3270
3370
|
state: record.state,
|
|
3271
3371
|
config: record.config,
|
|
3372
|
+
trial: { id: record.id, view: record.view },
|
|
3272
3373
|
annotations,
|
|
3273
3374
|
activeToolId: resolvedToolId
|
|
3274
3375
|
}
|
|
@@ -3310,9 +3411,12 @@ function initialView(instrument) {
|
|
|
3310
3411
|
if (typeof declared === "function") return null;
|
|
3311
3412
|
return declared ? structuredClone(declared) : { ...DEFAULT_VIEW2, pan: { ...DEFAULT_VIEW2.pan } };
|
|
3312
3413
|
}
|
|
3313
|
-
function
|
|
3414
|
+
function seedConfig(defaults, seed) {
|
|
3415
|
+
return seed ? fillConfigDefaults(seed, defaults) : defaults;
|
|
3416
|
+
}
|
|
3417
|
+
function addTrial(trials, instruments, instrumentName, options = {}) {
|
|
3314
3418
|
const instrument = findInstrument(instruments, instrumentName);
|
|
3315
|
-
const config = instrument.defaultConfig();
|
|
3419
|
+
const config = seedConfig(instrument.defaultConfig(), options.config);
|
|
3316
3420
|
const state = instrument.initialState(config);
|
|
3317
3421
|
const record = {
|
|
3318
3422
|
id: crypto.randomUUID(),
|
|
@@ -3322,6 +3426,7 @@ function addTrial(trials, instruments, instrumentName) {
|
|
|
3322
3426
|
view: initialView(instrument),
|
|
3323
3427
|
undoStack: { past: [], future: [] }
|
|
3324
3428
|
};
|
|
3429
|
+
if (options.config) record.configSeed = options.config;
|
|
3325
3430
|
return [...trials, record];
|
|
3326
3431
|
}
|
|
3327
3432
|
function cloneTrial(trials, id) {
|
|
@@ -3348,7 +3453,7 @@ function resetTrial(trials, id, instruments) {
|
|
|
3348
3453
|
const current = trials[idx];
|
|
3349
3454
|
if (!current) return trials;
|
|
3350
3455
|
const instrument = findInstrument(instruments, current.instrumentName);
|
|
3351
|
-
const config = instrument.defaultConfig();
|
|
3456
|
+
const config = seedConfig(instrument.defaultConfig(), current.configSeed);
|
|
3352
3457
|
const state = instrument.initialState(config);
|
|
3353
3458
|
const reset = {
|
|
3354
3459
|
...current,
|
|
@@ -3394,7 +3499,7 @@ function LabHeader() {
|
|
|
3394
3499
|
// Held at null so the control stays an "add one" action rather than
|
|
3395
3500
|
// reading as the current instrument.
|
|
3396
3501
|
/* @__PURE__ */ jsx(
|
|
3397
|
-
|
|
3502
|
+
g,
|
|
3398
3503
|
{
|
|
3399
3504
|
className: "lk-lab-header__add-select",
|
|
3400
3505
|
"aria-label": "Add trial",
|
|
@@ -3408,7 +3513,7 @@ function LabHeader() {
|
|
|
3408
3513
|
)
|
|
3409
3514
|
),
|
|
3410
3515
|
/* @__PURE__ */ jsx(
|
|
3411
|
-
|
|
3516
|
+
r6,
|
|
3412
3517
|
{
|
|
3413
3518
|
className: "lk-lab-header__mode",
|
|
3414
3519
|
ariaLabel: "Color mode",
|
|
@@ -3461,14 +3566,18 @@ function useResolvedMode(mode) {
|
|
|
3461
3566
|
function LabShell({ title, children, header, footer, mode = "auto" }) {
|
|
3462
3567
|
const resolved = useResolvedMode(mode);
|
|
3463
3568
|
const outer = useThemeOptional();
|
|
3464
|
-
const shell =
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3569
|
+
const shell = (
|
|
3570
|
+
// Overlays portal here rather than to the themed wrapper above: `.lk-root`
|
|
3571
|
+
// carries the element defaults a lab's bare markup is styled by.
|
|
3572
|
+
/* @__PURE__ */ jsxs("div", { className: "lk-root lk-shell", "data-wzl-portal-host": "", children: [
|
|
3573
|
+
/* @__PURE__ */ jsxs("header", { className: "lk-shell-header", children: [
|
|
3574
|
+
/* @__PURE__ */ jsx("h1", { className: "lk-shell-title", children: title }),
|
|
3575
|
+
header && /* @__PURE__ */ jsx("div", { className: "lk-shell-header-actions", children: header })
|
|
3576
|
+
] }),
|
|
3577
|
+
/* @__PURE__ */ jsx("main", { className: "lk-shell-body", children }),
|
|
3578
|
+
footer && /* @__PURE__ */ jsx("footer", { className: "lk-shell-footer", children: footer })
|
|
3579
|
+
] })
|
|
3580
|
+
);
|
|
3472
3581
|
return outer ? shell : /* @__PURE__ */ jsx(ThemeProvider, { theme: interstellarTheme, mode: resolved, children: shell });
|
|
3473
3582
|
}
|
|
3474
3583
|
var ZONE_ID2 = asNodeId("lk-workspace");
|
|
@@ -3477,11 +3586,11 @@ var FLOAT_ZONE_ID = asNodeId("lk-workspace-floating");
|
|
|
3477
3586
|
var PANEL_KIND = "panel";
|
|
3478
3587
|
var KIND = "trial";
|
|
3479
3588
|
function extentOf(store, id) {
|
|
3480
|
-
const
|
|
3481
|
-
if (!
|
|
3589
|
+
const p = store.getNode(id)?.membership?.placement;
|
|
3590
|
+
if (!p) return null;
|
|
3482
3591
|
const out = {};
|
|
3483
|
-
if (
|
|
3484
|
-
if (
|
|
3592
|
+
if (p.size) out.size = p.size;
|
|
3593
|
+
if (p.span) out.span = p.span;
|
|
3485
3594
|
return Object.keys(out).length > 0 ? out : null;
|
|
3486
3595
|
}
|
|
3487
3596
|
function PanelFrame({ panel, floating = false }) {
|
|
@@ -3502,11 +3611,11 @@ function Workspace({
|
|
|
3502
3611
|
viewport
|
|
3503
3612
|
}) {
|
|
3504
3613
|
const items = Children.toArray(children);
|
|
3505
|
-
const tilePanels = useMemo(() => (panels ?? []).filter((
|
|
3506
|
-
const floatPanels = useMemo(() => (panels ?? []).filter((
|
|
3614
|
+
const tilePanels = useMemo(() => (panels ?? []).filter((p) => p.as === "tile"), [panels]);
|
|
3615
|
+
const floatPanels = useMemo(() => (panels ?? []).filter((p) => p.as === "floating"), [panels]);
|
|
3507
3616
|
const wantedIds = [
|
|
3508
|
-
...items.map((
|
|
3509
|
-
...tilePanels.map((
|
|
3617
|
+
...items.map((_, i) => ids?.[i] ?? `lk-ws-${i}`),
|
|
3618
|
+
...tilePanels.map((p) => `lk-panel-${p.key}`)
|
|
3510
3619
|
];
|
|
3511
3620
|
const idKey = wantedIds.join(",");
|
|
3512
3621
|
const idKeyRef = useRef(null);
|
|
@@ -3583,7 +3692,7 @@ function Workspace({
|
|
|
3583
3692
|
const chrome = useMemo(() => {
|
|
3584
3693
|
const byId = new Map(nodeIds.map((id, i) => [id, items[i]]));
|
|
3585
3694
|
const panelByNode = new Map(
|
|
3586
|
-
tilePanels.map((
|
|
3695
|
+
tilePanels.map((p) => [`lk-panel-${p.key}`, p])
|
|
3587
3696
|
);
|
|
3588
3697
|
return {
|
|
3589
3698
|
[PANEL_KIND]: ({ node }) => {
|
|
@@ -3601,7 +3710,7 @@ function Workspace({
|
|
|
3601
3710
|
}
|
|
3602
3711
|
};
|
|
3603
3712
|
}, [nodeIds, items, reorderable, tilePanels]);
|
|
3604
|
-
const floatingLayer = floatPanels.length === 0 ? null : /* @__PURE__ */ jsx("div", { className: "lk-workspace__floating", children: floatPanels.map((
|
|
3713
|
+
const floatingLayer = floatPanels.length === 0 ? null : /* @__PURE__ */ jsx("div", { className: "lk-workspace__floating", children: floatPanels.map((p) => /* @__PURE__ */ jsx(PanelFrame, { panel: p, floating: true }, p.key)) });
|
|
3605
3714
|
const grid = /* @__PURE__ */ jsx(
|
|
3606
3715
|
Container,
|
|
3607
3716
|
{
|
|
@@ -3624,7 +3733,13 @@ function Workspace({
|
|
|
3624
3733
|
) : reorderable ? /* @__PURE__ */ jsx(DragProvider, { children: grid }) : grid }) });
|
|
3625
3734
|
}
|
|
3626
3735
|
function buildStore(instruments, defaultInstrument, storage, storageKey, initialMode) {
|
|
3627
|
-
const store = createLabStore({
|
|
3736
|
+
const store = createLabStore({
|
|
3737
|
+
storageKey,
|
|
3738
|
+
storage,
|
|
3739
|
+
initialMode,
|
|
3740
|
+
serializers: serializersOf(instruments),
|
|
3741
|
+
configDefaults: configDefaultsOf(instruments)
|
|
3742
|
+
});
|
|
3628
3743
|
if (store.getState().trials.length === 0) {
|
|
3629
3744
|
const seeded = addTrial([], instruments, defaultInstrument);
|
|
3630
3745
|
const record = seeded[0];
|
|
@@ -3644,8 +3759,8 @@ var NEBULA_SLOTS = [
|
|
|
3644
3759
|
];
|
|
3645
3760
|
function buildNebula(colors) {
|
|
3646
3761
|
const blobs = colors.map((c2, i) => {
|
|
3647
|
-
const
|
|
3648
|
-
return `radial-gradient(ellipse ${
|
|
3762
|
+
const p = NEBULA_SLOTS[i % NEBULA_SLOTS.length];
|
|
3763
|
+
return `radial-gradient(ellipse ${p.sx} ${p.sy} at ${p.cx} ${p.cy}, color-mix(in srgb, ${c2} 22%, transparent), transparent ${p.stop})`;
|
|
3649
3764
|
});
|
|
3650
3765
|
blobs.push("radial-gradient(ellipse at center, #0a0a18 0%, #02020a 100%)");
|
|
3651
3766
|
return blobs.join(", ");
|
|
@@ -3697,11 +3812,11 @@ function Lab({
|
|
|
3697
3812
|
const c2 = ownCanvasRef.current;
|
|
3698
3813
|
if (!c2) return;
|
|
3699
3814
|
const w3 = Math.round(frame.size.width * frame.dpr);
|
|
3700
|
-
const
|
|
3701
|
-
if (bufferRef.current.w === w3 && bufferRef.current.h ===
|
|
3702
|
-
bufferRef.current = { w: w3, h
|
|
3815
|
+
const h = Math.round(frame.size.height * frame.dpr);
|
|
3816
|
+
if (bufferRef.current.w === w3 && bufferRef.current.h === h) return;
|
|
3817
|
+
bufferRef.current = { w: w3, h };
|
|
3703
3818
|
c2.width = w3;
|
|
3704
|
-
c2.height =
|
|
3819
|
+
c2.height = h;
|
|
3705
3820
|
c2.style.width = `${frame.size.width}px`;
|
|
3706
3821
|
c2.style.height = `${frame.size.height}px`;
|
|
3707
3822
|
surfaceRef.current?.invalidateAll();
|
|
@@ -3734,8 +3849,8 @@ function Lab({
|
|
|
3734
3849
|
return {
|
|
3735
3850
|
instruments,
|
|
3736
3851
|
trials,
|
|
3737
|
-
addTrial: (instrumentName) => {
|
|
3738
|
-
const next = addTrial(store.getState().trials, instruments, instrumentName);
|
|
3852
|
+
addTrial: (instrumentName, options) => {
|
|
3853
|
+
const next = addTrial(store.getState().trials, instruments, instrumentName, options);
|
|
3739
3854
|
replaceTrials(next);
|
|
3740
3855
|
},
|
|
3741
3856
|
cloneTrial: (id) => {
|
|
@@ -3841,6 +3956,6 @@ function Lab({
|
|
|
3841
3956
|
) }) });
|
|
3842
3957
|
}
|
|
3843
3958
|
|
|
3844
|
-
export { AnnotationOverlay, AnnotationTargets, DEFAULT_VIEW, Lab, LabContext, LabPalette, LabShell, Trial, TrialBody, TrialChrome, Workspace, addTrial, annotationsFromJSON, applyRules, as2DView, builtinRules, capturePlan, captureTarget, cloneTrial, closeTrial, composeCaptureSvg, createAnnotationScene, createAnnotationStore, createMarkDrawOne, defineInstrument, f, fitView, fracContains, fracIntersects, fracToWorld, fromWeaselView, interstellarTheme, isStale, markCommands, markSvgNodes, reorderTrials, resetTrial, resolveConfigSchema, resolveMarkStyle, roundFrac, seenFrom, titleCase, toWeaselView, useConfigSchema, useLabContext, validateConfigSchema, worldToFrac };
|
|
3959
|
+
export { AnnotationOverlay, AnnotationTargets, DEFAULT_VIEW, Lab, LabContext, LabPalette, LabShell, Trial, TrialBody, TrialChrome, Workspace, addTrial, annotationsFromJSON, applyRules, as2DView, builtinRules, capturePlan, captureTarget, cloneTrial, closeTrial, composeCaptureSvg, createAnnotationScene, createAnnotationStore, createMarkDrawOne, defineInstrument, f, fitView, fracContains, fracIntersects, fracToWorld, fromWeaselView, interstellarTheme, isConfigBranch, isStale, markCommands, markSvgNodes, reorderTrials, resetTrial, resolveConfigSchema, resolveMarkStyle, roundFrac, seenFrom, titleCase, toWeaselView, useConfigSchema, useLabContext, validateConfigSchema, worldToFrac };
|
|
3845
3960
|
//# sourceMappingURL=index.js.map
|
|
3846
3961
|
//# sourceMappingURL=index.js.map
|