@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
package/dist/index.js
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
import { LoupeSwitchContext } from './chunk-2ES4W47N.js';
|
|
2
2
|
export { LoupeSwitchContext } from './chunk-2ES4W47N.js';
|
|
3
|
-
import { createEventBus
|
|
4
|
-
export { clearUndo, createEventBus, emptyStack, pushSnapshot, redo, undo } from './chunk-
|
|
5
|
-
import { useDragDrop, DragOverlay, Palette } from './chunk-
|
|
6
|
-
import { useTiledSurface } from './chunk-
|
|
7
|
-
export { composeRects, toDeviceRect, useTiledSurface } from './chunk-
|
|
3
|
+
import { createEventBus } from './chunk-UX66USTN.js';
|
|
4
|
+
export { clearUndo, createEventBus, emptyStack, pushSnapshot, redo, undo } from './chunk-UX66USTN.js';
|
|
5
|
+
import { useDragDrop, DragOverlay, Palette } from './chunk-J5MDJEOZ.js';
|
|
6
|
+
import { useTiledSurface } from './chunk-QMAY74TP.js';
|
|
7
|
+
export { composeRects, toDeviceRect, useTiledSurface } from './chunk-QMAY74TP.js';
|
|
8
8
|
import { useJob } from './chunk-EFXRM6XQ.js';
|
|
9
9
|
export { useJob } from './chunk-EFXRM6XQ.js';
|
|
10
|
-
import { markCommands, boundsOf, roundFrac, worldToFrac, fracToWorld, fracEncloses, fracContains, POINT_MARK_SHAPE, roundPoints, fromShape, markSvgNodes, toShape } from './chunk-
|
|
11
|
-
export { fracContains, fracEncloses, fracToWorld, markCommands, markSvgNodes, roundFrac, worldToFrac } from './chunk-
|
|
12
|
-
import { ANNOTATION_WEASEL_TOOLS, annotationToolInfo, suppressContributions, mergeContributions, builtinContributions, TRANSIENT_BUILTINS, TitleBarRegion, ToolbarRegion, PaletteRegion, ViewportRegion, SidebarRegion, StatusRegion, resolveLabTool, useLabChromeContext, labContributions, labAnnotationTools, LabHeaderRegion, LabFooterRegion, LabAsideRegion, LabSidebarRegion } from './chunk-
|
|
13
|
-
export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, ExportMenu, LabAsideRegion, LabFooterRegion, LabHeaderRegion, LabSidebarRegion, MarkList, PaletteRegion, SidebarRegion, StatusRegion, TRANSIENT_BUILTINS, TitleBarRegion, ToolbarRegion, ViewportRegion, annotationToolInfo, builtinContributions, contributionsIn, labContributions, mergeContributions, suppressContributions, toolContributions, useLabChromeContext } from './chunk-
|
|
10
|
+
import { markCommands, boundsOf, roundFrac, worldToFrac, fracToWorld, fracEncloses, fracContains, POINT_MARK_SHAPE, roundPoints, fromShape, markSvgNodes, toShape } from './chunk-6Q6ACJ3H.js';
|
|
11
|
+
export { fracContains, fracEncloses, fracToWorld, markCommands, markSvgNodes, roundFrac, worldToFrac } from './chunk-6Q6ACJ3H.js';
|
|
12
|
+
import { ANNOTATION_WEASEL_TOOLS, annotationToolInfo, suppressContributions, mergeContributions, builtinContributions, TRANSIENT_BUILTINS, TitleBarRegion, ToolbarRegion, PaletteRegion, ViewportRegion, SidebarRegion, StatusRegion, resolveLabTool, useLabChromeContext, labContributions, labAnnotationTools, LabHeaderRegion, LabFooterRegion, LabAsideRegion, LabSidebarRegion } from './chunk-RN7T7OBO.js';
|
|
13
|
+
export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, ExportMenu, LabAsideRegion, LabFooterRegion, LabHeaderRegion, LabSidebarRegion, MarkList, PaletteRegion, SidebarRegion, StatusRegion, TRANSIENT_BUILTINS, TitleBarRegion, ToolbarRegion, ViewportRegion, annotationToolInfo, builtinContributions, contributionsIn, labContributions, mergeContributions, suppressContributions, toolContributions, useLabChromeContext } from './chunk-RN7T7OBO.js';
|
|
14
14
|
import { AnnotationsContext } from './chunk-3RY6WL5T.js';
|
|
15
15
|
export { AnnotationsContext, useAnnotations, useAnnotationsOptional } from './chunk-3RY6WL5T.js';
|
|
16
|
-
import { Split, JobProgress, Legend } from './chunk-
|
|
17
|
-
export { JobProgress, Legend, Readout, Split } from './chunk-
|
|
18
|
-
import { FloatingPanel } from './chunk-
|
|
19
|
-
export { FloatingPanel } from './chunk-
|
|
20
|
-
import { Toolbar,
|
|
21
|
-
export { FpsMeter, ScaleIndicator,
|
|
16
|
+
import { Split, JobProgress, Legend } from './chunk-KHB3KRRQ.js';
|
|
17
|
+
export { JobProgress, Legend, Readout, Split } from './chunk-KHB3KRRQ.js';
|
|
18
|
+
import { FloatingPanel } from './chunk-7FMZT2WL.js';
|
|
19
|
+
export { FloatingPanel } from './chunk-7FMZT2WL.js';
|
|
20
|
+
import { Toolbar, ScaleIndicator, ZoomControl } from './chunk-RXO5UEGT.js';
|
|
21
|
+
export { FpsMeter, ScaleIndicator, Toolbar, ZoomControl } from './chunk-RXO5UEGT.js';
|
|
22
22
|
import './chunk-CZZPXUOU.js';
|
|
23
|
-
import { unruledConfigSchema, createLabStore, openLabStore, panelKey } from './chunk-
|
|
24
|
-
export { CURRENT_DOCUMENT_VERSION, dockPanel, labDocumentKey, openLabStore, panelKey, quarantineKey, undockPanel, useTrialState } from './chunk-
|
|
25
|
-
import { newId, useWarnIgnoredChange, useOpenOnce, PersistenceContext, createRecordCache, noneAdapter, defaultStorage, usePersistedState } from './chunk-
|
|
26
|
-
export { Persistence, createIndexedDbAdapter, createMemoryAdapter, indexedDbAdapter, localStorageAdapter, noneAdapter, sessionStorageAdapter, urlHashAdapter, usePersistedState } from './chunk-
|
|
27
|
-
export { ControlMatrix } from './chunk-
|
|
28
|
-
export { ControlPanel, inDialog, summarizeValue } from './chunk-
|
|
29
|
-
import { useConfigSchema } from './chunk-
|
|
30
|
-
export { sectionTree, useConfigSchema } from './chunk-
|
|
31
|
-
import {
|
|
23
|
+
import { unruledConfigSchema, createLabStore, openLabStore, panelKey } from './chunk-NHIO2O3O.js';
|
|
24
|
+
export { CURRENT_DOCUMENT_VERSION, dockPanel, labDocumentKey, openLabStore, panelKey, quarantineKey, undockPanel, useTrialState } from './chunk-NHIO2O3O.js';
|
|
25
|
+
import { valueRecord, newId, useWarnIgnoredChange, useOpenOnce, PersistenceContext, createRecordCache, noneAdapter, defaultStorage, usePersistedState } from './chunk-7ALJOVGP.js';
|
|
26
|
+
export { Persistence, createIndexedDbAdapter, createMemoryAdapter, indexedDbAdapter, localStorageAdapter, noneAdapter, sessionStorageAdapter, urlHashAdapter, usePersistedState } from './chunk-7ALJOVGP.js';
|
|
27
|
+
export { ControlMatrix } from './chunk-4RCVWX4M.js';
|
|
28
|
+
export { ControlPanel, inDialog, summarizeValue } from './chunk-YZA73U4A.js';
|
|
29
|
+
import { useConfigSchema } from './chunk-SQX35X5V.js';
|
|
30
|
+
export { sectionTree, useConfigSchema } from './chunk-SQX35X5V.js';
|
|
31
|
+
import { LabContext, useLabContext } from './chunk-Z76KEZAX.js';
|
|
32
32
|
export { LabContext, useLabContext } from './chunk-Z76KEZAX.js';
|
|
33
|
-
import { useResolvedConfig } from './chunk-
|
|
34
|
-
export { BaseNode, BooleanNode, ColorNode, CustomNode, EnumNode, GroupNode, ListNode, NumberNode, StringNode, ValueNode, applyRules, builtinRules, f, isConfigBranch, resolveConfigSchema, titleCase, useResolvedConfig } from './chunk-
|
|
33
|
+
import { useResolvedConfig } from './chunk-T5OEUNCB.js';
|
|
34
|
+
export { BaseNode, BooleanNode, ColorNode, CustomNode, EnumNode, GroupNode, ListNode, NumberNode, StringNode, ValueNode, applyRules, builtinRules, f, isConfigBranch, resolveConfigSchema, titleCase, useResolvedConfig } from './chunk-T5OEUNCB.js';
|
|
35
35
|
export { fromConfigFields, isLeafVisible } from './chunk-WLMDTI2Q.js';
|
|
36
36
|
import { hasConfigPath, schemaNodeAtPath, applyConfigWrite, resolveAutoConfig, isAuto, isRecord, autoPathsOf, fillConfigDefaults } from './chunk-READTDQX.js';
|
|
37
37
|
export { auto, autoPathsOf, fillConfigDefaults, hasConfigPath, isAuto, resolveAutoConfig, schemaNodeAtPath, valueAtPath, withValueAtPath } from './chunk-READTDQX.js';
|
|
38
|
-
import { CanvasStack, Stage, fitStage } from './chunk-
|
|
39
|
-
export { CanvasStack, Stage, fitStage } from './chunk-
|
|
38
|
+
import { CanvasStack, Stage, fitStage } from './chunk-XWR2P6MR.js';
|
|
39
|
+
export { CanvasStack, Stage, fitStage } from './chunk-XWR2P6MR.js';
|
|
40
40
|
export { centerOn, zoomAt } from './chunk-ROGJWDQA.js';
|
|
41
41
|
export { screenToWorld, worldToScreen } from './chunk-FG3EXZDV.js';
|
|
42
|
-
import { useSurfaceOptional, useSurfaceCanvas, useTileId, SurfaceContext, SurfaceCanvasContext } from './chunk-
|
|
43
|
-
export { SurfaceCanvasContext, SurfaceContext, useSurface, useSurfaceCanvas, useSurfaceOptional, useSurfaceTile, useTileId } from './chunk-
|
|
42
|
+
import { useSurfaceOptional, useSurfaceCanvas, useTileId, useTileInScope, SurfaceContext, SurfaceCanvasContext } from './chunk-6IIKLXBZ.js';
|
|
43
|
+
export { SurfaceCanvasContext, SurfaceContext, useSurface, useSurfaceCanvas, useSurfaceOptional, useSurfaceTile, useTileId, useTileInScope } from './chunk-6IIKLXBZ.js';
|
|
44
44
|
import { CameraWheelContext, as2DView, CameraRegistryContext, DEFAULT_VIEW, CameraPublishContext, createCameraRegistry, withZoom } from './chunk-VYVGVBGY.js';
|
|
45
45
|
export { CameraContext, CameraInput, CameraPublishContext, CameraRegistryContext, CameraScope, DEFAULT_VIEW, as2DView, createCameraRegistry, usePublishCamera } from './chunk-VYVGVBGY.js';
|
|
46
46
|
import { applyCamera } from './chunk-ULYYNWGP.js';
|
|
@@ -50,12 +50,12 @@ export { CanvasStackContext } from './chunk-ZQIHJXP4.js';
|
|
|
50
50
|
import { LabStoreContext, TrialIdProvider, TrialIdContext } from './chunk-2YILQ7Y5.js';
|
|
51
51
|
export { LabStoreContext, LabStoreProvider, TrialIdContext, TrialIdProvider, useLabStore, useTrialId } from './chunk-2YILQ7Y5.js';
|
|
52
52
|
import './chunk-2RVCB2PT.js';
|
|
53
|
-
import {
|
|
54
|
-
export { c as Button, V as CloseIcon,
|
|
55
|
-
import { serializeSvg } from './chunk-
|
|
56
|
-
import './chunk-
|
|
57
|
-
import { makeViewportZoomAction, createScene, asNodeId as asNodeId$1, registerNodeShape, useLatest, WeaselProvider, SceneCanvas, createPointerStore, PointerContextProvider, DepRegistryProvider, ActionsProvider, ActiveToolContextProvider, useActionsRegistry, useDepSource, ActionDisabledReason, useGestureDispatcher, sceneFromJSON, warmRender, renderSceneToPixels, useActiveToolContext } from '@weasel-js/core';
|
|
58
|
-
import { createContext, useState, useRef, useEffect, useInsertionEffect, useCallback, useContext,
|
|
53
|
+
import { A2, T, Z, U, V, de, G, p6, o3, c, Xt, c4, a5, l5, u3, s3, r3, a7, i3, o5, s5, c5, l8, p, f3, u2, y, O2, b4, l9, w2, c6, i4, h2, j, k2, ce2, le, ye, b3, j2, n6, a8, C3, l3, u, v3, d2, j3, r4, n7, r5, i5, p2, f2, n8, o4, p4, l7, w, L, n9, j4, xe, n2 } from './chunk-V4SMGEYY.js';
|
|
54
|
+
export { c as Button, V as CloseIcon, we as CollapseIcon, _ as CurveField, s as DetailList, c2 as DetailRow, Te as ExpandIcon, l as Icon, u2 as Input, l10 as Jog, A2 as LayerList, oe as PauseIcon, ae as PlayIcon, be as PropertyControl, ye as PropertyField, b3 as PropertyGroup, le as PropertyList, ce2 as PropertyPanel, L2 as PropertyRow, ue as PropertySpan, B as ResetIcon, O2 as Select, n7 as StatusBar, r5 as StatusBarItem, i5 as StatusBarSpacer, ce as StepBackIcon, $ as StepForwardIcon, se as StopIcon, x2 as Subpanel, s3 as ToggleBar, oe2 as TokenPanel, H2 as inferTokenType, T as moveLayers, O3 as refitScale } from './chunk-V4SMGEYY.js';
|
|
55
|
+
import { serializeSvg } from './chunk-VCK5T6EP.js';
|
|
56
|
+
import './chunk-AVOILDN2.js';
|
|
57
|
+
import { makeViewportZoomAction, createScene, asNodeId as asNodeId$1, registerNodeShape, useLatest, WeaselProvider, SceneCanvas, createPointerStore, PointerContextProvider, DepRegistryProvider, ActionsProvider, ActiveToolContextProvider, useActionsRegistry, useDepSource, ActionDisabledReason, useGestureDispatcher, sceneFromJSON, warmRender, renderSceneToPixels, useActiveToolContext, createHistory, useVisibleRaf, stableStringify } from '@weasel-js/core';
|
|
58
|
+
import { createContext, useState, useRef, useEffect, useInsertionEffect, useCallback, useContext, useSyncExternalStore, useReducer, useLayoutEffect, useMemo, useId, Children } from 'react';
|
|
59
59
|
import { flushSync, createPortal } from 'react-dom';
|
|
60
60
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
61
61
|
import { defineTheme, weaselTheme, colorCount, resolveTheme, colorAt } from '@weasel-js/theme';
|
|
@@ -92,7 +92,7 @@ function createMarkDrawOne(opts) {
|
|
|
92
92
|
}
|
|
93
93
|
function resolveMarkStyle(data, opts) {
|
|
94
94
|
return {
|
|
95
|
-
color: opts.meaning?.statuses?.find((
|
|
95
|
+
color: opts.meaning?.statuses?.find((s4) => s4.id === data.status)?.color,
|
|
96
96
|
// Read off the node rather than through the store's `isStale`, which
|
|
97
97
|
// wants a projected Annotation this path does not have.
|
|
98
98
|
stale: isStale(data.seen, opts.config, opts.positionDependsOn ?? [])
|
|
@@ -105,7 +105,7 @@ function capturePlan(base, format) {
|
|
|
105
105
|
if (format === "svg") return "svg-document";
|
|
106
106
|
return base?.kind === "svg" ? "svg-document" : "raster-stack";
|
|
107
107
|
}
|
|
108
|
-
function nestBaseSvg(markup,
|
|
108
|
+
function nestBaseSvg(markup, w3, h2) {
|
|
109
109
|
const doc = new DOMParser().parseFromString(markup, "image/svg+xml");
|
|
110
110
|
const root = doc.documentElement;
|
|
111
111
|
if (doc.getElementsByTagName("parsererror").length > 0 || root.localName !== "svg") {
|
|
@@ -113,17 +113,17 @@ function nestBaseSvg(markup, w2, h2) {
|
|
|
113
113
|
}
|
|
114
114
|
root.setAttribute("x", "0");
|
|
115
115
|
root.setAttribute("y", "0");
|
|
116
|
-
root.setAttribute("width", String(
|
|
116
|
+
root.setAttribute("width", String(w3));
|
|
117
117
|
root.setAttribute("height", String(h2));
|
|
118
118
|
return new XMLSerializer().serializeToString(root);
|
|
119
119
|
}
|
|
120
|
-
function embedRasterBase(base,
|
|
120
|
+
function embedRasterBase(base, w3, h2, onWarn) {
|
|
121
121
|
const href = base.kind === "canvas" ? base.canvas.toDataURL() : base.kind === "image" ? base.src : "";
|
|
122
122
|
if (base.kind === "image" && !href.startsWith("data:")) {
|
|
123
123
|
onWarn?.(`base image '${href}' is a reference, so this SVG is not self-contained`);
|
|
124
124
|
}
|
|
125
|
-
return serializeSvg([{ kind: "image", href, x: 0, y: 0, width:
|
|
126
|
-
viewBox: { x: 0, y: 0, width:
|
|
125
|
+
return serializeSvg([{ kind: "image", href, x: 0, y: 0, width: w3, height: h2 }], {
|
|
126
|
+
viewBox: { x: 0, y: 0, width: w3, height: h2 }
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
129
|
function markNodesOf(scene, draw, scale) {
|
|
@@ -139,15 +139,15 @@ function markNodesOf(scene, draw, scale) {
|
|
|
139
139
|
}
|
|
140
140
|
function composeCaptureSvg(args) {
|
|
141
141
|
const { base, scene, draw, scale, onWarn } = args;
|
|
142
|
-
const { w:
|
|
143
|
-
const baseXml = base === void 0 ? "" : base.kind === "svg" ? nestBaseSvg(base.markup,
|
|
142
|
+
const { w: w3, h: h2 } = draw.content;
|
|
143
|
+
const baseXml = base === void 0 ? "" : base.kind === "svg" ? nestBaseSvg(base.markup, w3, h2) : embedRasterBase(base, w3, h2, onWarn);
|
|
144
144
|
const marksXml = serializeSvg(markNodesOf(scene, draw, scale), {
|
|
145
|
-
viewBox: { x: 0, y: 0, width:
|
|
145
|
+
viewBox: { x: 0, y: 0, width: w3, height: h2 },
|
|
146
146
|
onWarn
|
|
147
147
|
});
|
|
148
|
-
const outW = Math.max(1, Math.round(
|
|
148
|
+
const outW = Math.max(1, Math.round(w3 * scale));
|
|
149
149
|
const outH = Math.max(1, Math.round(h2 * scale));
|
|
150
|
-
return `<svg xmlns="${SVG_NS}" width="${outW}" height="${outH}" viewBox="0 0 ${
|
|
150
|
+
return `<svg xmlns="${SVG_NS}" width="${outW}" height="${outH}" viewBox="0 0 ${w3} ${h2}">${baseXml}${marksXml}</svg>`;
|
|
151
151
|
}
|
|
152
152
|
function context2d(width, height) {
|
|
153
153
|
const canvas = document.createElement("canvas");
|
|
@@ -283,13 +283,13 @@ var MarkHistory = class {
|
|
|
283
283
|
return null;
|
|
284
284
|
}
|
|
285
285
|
canUndo(at) {
|
|
286
|
-
return this.next(this.undoable, (
|
|
286
|
+
return this.next(this.undoable, (s4) => s4.canUndo(), at) !== null;
|
|
287
287
|
}
|
|
288
288
|
canRedo(at) {
|
|
289
|
-
return this.next(this.redoable, (
|
|
289
|
+
return this.next(this.redoable, (s4) => s4.canRedo(), at) !== null;
|
|
290
290
|
}
|
|
291
291
|
undo(at) {
|
|
292
|
-
const target = this.next(this.undoable, (
|
|
292
|
+
const target = this.next(this.undoable, (s4) => s4.canUndo(), at);
|
|
293
293
|
const scene = target === null ? void 0 : at(target);
|
|
294
294
|
if (!scene) return false;
|
|
295
295
|
this.replaying = "undo";
|
|
@@ -300,7 +300,7 @@ var MarkHistory = class {
|
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
302
|
redo(at) {
|
|
303
|
-
const target = this.next(this.redoable, (
|
|
303
|
+
const target = this.next(this.redoable, (s4) => s4.canRedo(), at);
|
|
304
304
|
const scene = target === null ? void 0 : at(target);
|
|
305
305
|
if (!scene) return false;
|
|
306
306
|
this.replaying = "redo";
|
|
@@ -429,21 +429,21 @@ function createAnnotationStore(opts) {
|
|
|
429
429
|
if (!scene) return [];
|
|
430
430
|
const out = [];
|
|
431
431
|
for (const id of scene.renderOrder()) {
|
|
432
|
-
const
|
|
433
|
-
if (
|
|
432
|
+
const a4 = project(target, String(id));
|
|
433
|
+
if (a4) out.push(a4);
|
|
434
434
|
}
|
|
435
435
|
return out;
|
|
436
436
|
};
|
|
437
437
|
const all = () => liveTargets().flatMap(marksOn);
|
|
438
|
-
const matches = (
|
|
439
|
-
if (q.target !== void 0 &&
|
|
440
|
-
if (q.kind !== void 0 &&
|
|
441
|
-
if (q.status !== void 0 &&
|
|
438
|
+
const matches = (a4, q) => {
|
|
439
|
+
if (q.target !== void 0 && a4.target !== q.target) return false;
|
|
440
|
+
if (q.kind !== void 0 && a4.kind !== q.kind) return false;
|
|
441
|
+
if (q.status !== void 0 && a4.status !== q.status) return false;
|
|
442
442
|
if (q.tags !== void 0) {
|
|
443
|
-
const have =
|
|
443
|
+
const have = a4.tags ?? [];
|
|
444
444
|
for (const t of q.tags) if (!have.includes(t)) return false;
|
|
445
445
|
}
|
|
446
|
-
if (q.where && !q.where(
|
|
446
|
+
if (q.where && !q.where(a4)) return false;
|
|
447
447
|
return true;
|
|
448
448
|
};
|
|
449
449
|
const nodeOf = (id) => {
|
|
@@ -461,17 +461,17 @@ function createAnnotationStore(opts) {
|
|
|
461
461
|
return parts ? project(parts.target, parts.node) : void 0;
|
|
462
462
|
},
|
|
463
463
|
query(q) {
|
|
464
|
-
return q ? all().filter((
|
|
464
|
+
return q ? all().filter((a4) => matches(a4, q)) : all();
|
|
465
465
|
},
|
|
466
466
|
hitTest(target, pt, tol = 0) {
|
|
467
|
-
return marksOn(target).filter((
|
|
467
|
+
return marksOn(target).filter((a4) => fracContains(a4.frac, pt, tol)).reverse();
|
|
468
468
|
},
|
|
469
469
|
within(target, box) {
|
|
470
|
-
return marksOn(target).filter((
|
|
470
|
+
return marksOn(target).filter((a4) => fracEncloses(box, a4.frac));
|
|
471
471
|
},
|
|
472
|
-
isStale(
|
|
473
|
-
const keys = targetOf(
|
|
474
|
-
return isStale(
|
|
472
|
+
isStale(a4, config) {
|
|
473
|
+
const keys = targetOf(a4.target)?.positionDependsOn ?? [];
|
|
474
|
+
return isStale(a4.seen, config, keys);
|
|
475
475
|
},
|
|
476
476
|
canUndo() {
|
|
477
477
|
return history.canUndo(historySceneAt);
|
|
@@ -624,7 +624,7 @@ function fitView(content, pane) {
|
|
|
624
624
|
const zoom = content.w > 0 && content.h > 0 ? Math.min(pane.w / content.w, pane.h / content.h) : 1;
|
|
625
625
|
return { zoom: Number.isFinite(zoom) && zoom > 0 ? zoom : 1, pan: { x: 0, y: 0 } };
|
|
626
626
|
}
|
|
627
|
-
var sameRect = (
|
|
627
|
+
var sameRect = (a4, b3) => a4 !== null && a4.x === b3.x && a4.y === b3.y && a4.w === b3.w && a4.h === b3.h;
|
|
628
628
|
function ToolBridge({ toolId }) {
|
|
629
629
|
const tools = useActiveToolContext();
|
|
630
630
|
const setActive = tools.setActive;
|
|
@@ -668,6 +668,7 @@ function AnnotationOverlay({
|
|
|
668
668
|
const configRef = useLatest(config);
|
|
669
669
|
const id = target.id;
|
|
670
670
|
const tileId = useTileId(id);
|
|
671
|
+
const inScope = useTileInScope(tileId);
|
|
671
672
|
const lastTile = useRef(null);
|
|
672
673
|
useEffect(() => {
|
|
673
674
|
const el = target.ref.current ?? null;
|
|
@@ -758,6 +759,7 @@ function AnnotationOverlay({
|
|
|
758
759
|
className: "lk-annotate__input",
|
|
759
760
|
"data-annotation-target": id,
|
|
760
761
|
"data-idle": annotationToolInfo(activeToolId) ? void 0 : "",
|
|
762
|
+
hidden: !inScope,
|
|
761
763
|
role: "application",
|
|
762
764
|
"aria-label": `Annotations on ${id}`,
|
|
763
765
|
tabIndex: 0,
|
|
@@ -811,6 +813,62 @@ function AnnotationTargets({
|
|
|
811
813
|
t.id
|
|
812
814
|
)) });
|
|
813
815
|
}
|
|
816
|
+
function createClockRegistry() {
|
|
817
|
+
const handles = /* @__PURE__ */ new Map();
|
|
818
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
819
|
+
const notify = () => {
|
|
820
|
+
for (const l8 of [...listeners]) l8();
|
|
821
|
+
};
|
|
822
|
+
return {
|
|
823
|
+
register(trialId, handle) {
|
|
824
|
+
handles.set(trialId, handle);
|
|
825
|
+
notify();
|
|
826
|
+
return () => {
|
|
827
|
+
if (handles.get(trialId) !== handle) return;
|
|
828
|
+
handles.delete(trialId);
|
|
829
|
+
notify();
|
|
830
|
+
};
|
|
831
|
+
},
|
|
832
|
+
get: (trialId) => handles.get(trialId) ?? null,
|
|
833
|
+
all: () => handles.values(),
|
|
834
|
+
subscribe(listener) {
|
|
835
|
+
listeners.add(listener);
|
|
836
|
+
return () => {
|
|
837
|
+
listeners.delete(listener);
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
var ClockRegistryContext = createContext(null);
|
|
843
|
+
var TrialClockContext = createContext(null);
|
|
844
|
+
|
|
845
|
+
// src/clock/hooks.ts
|
|
846
|
+
var NO_SUBSCRIBE = () => () => {
|
|
847
|
+
};
|
|
848
|
+
function useTrialClock(trialId) {
|
|
849
|
+
const registry = useContext(ClockRegistryContext);
|
|
850
|
+
const own = useContext(TrialClockContext);
|
|
851
|
+
const lab = useContext(LabContext);
|
|
852
|
+
useSyncExternalStore(registry?.subscribe ?? NO_SUBSCRIBE, () => registry ? resolve() : own);
|
|
853
|
+
function resolve() {
|
|
854
|
+
if (trialId !== void 0) return registry?.get(trialId) ?? null;
|
|
855
|
+
if (own) return own;
|
|
856
|
+
const focused = lab?.focusedTrialId;
|
|
857
|
+
return focused ? registry?.get(focused) ?? null : null;
|
|
858
|
+
}
|
|
859
|
+
const clock = resolve()?.clock ?? null;
|
|
860
|
+
const [, bump] = useReducer((n6) => n6 + 1, 0);
|
|
861
|
+
useEffect(() => clock?.subscribe(bump), [clock]);
|
|
862
|
+
return clock;
|
|
863
|
+
}
|
|
864
|
+
function useClockFrame(fn) {
|
|
865
|
+
const handle = useContext(TrialClockContext);
|
|
866
|
+
const latest = useLatest(fn);
|
|
867
|
+
useEffect(
|
|
868
|
+
() => handle?.onFrame((elapsed, pass) => latest.current(elapsed, pass)),
|
|
869
|
+
[handle, latest]
|
|
870
|
+
);
|
|
871
|
+
}
|
|
814
872
|
|
|
815
873
|
// src/instrument/defineInstrument.ts
|
|
816
874
|
function defineInstrument(spec) {
|
|
@@ -870,6 +928,41 @@ function validateConfigSchema(fields) {
|
|
|
870
928
|
return { valid: errors.length === 0, errors };
|
|
871
929
|
}
|
|
872
930
|
var AnnotationPreloadContext = createContext(null);
|
|
931
|
+
function useClockLoop(registry) {
|
|
932
|
+
const loop = useVisibleRaf(
|
|
933
|
+
(timestamp) => {
|
|
934
|
+
let live = false;
|
|
935
|
+
for (const { clock } of registry.all()) {
|
|
936
|
+
if (clock.inert) continue;
|
|
937
|
+
clock.sync(timestamp);
|
|
938
|
+
if (!clock.inert) live = true;
|
|
939
|
+
}
|
|
940
|
+
if (live) loop.request();
|
|
941
|
+
},
|
|
942
|
+
{
|
|
943
|
+
onResume: () => {
|
|
944
|
+
for (const { clock } of registry.all()) clock.rebase();
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
);
|
|
948
|
+
useEffect(() => {
|
|
949
|
+
let unwakes = [];
|
|
950
|
+
const attach = () => {
|
|
951
|
+
for (const off2 of unwakes) off2();
|
|
952
|
+
unwakes = [];
|
|
953
|
+
for (const { clock } of registry.all()) {
|
|
954
|
+
unwakes.push(clock.onWake(() => loop.request()));
|
|
955
|
+
if (!clock.inert) loop.request();
|
|
956
|
+
}
|
|
957
|
+
};
|
|
958
|
+
attach();
|
|
959
|
+
const off = registry.subscribe(attach);
|
|
960
|
+
return () => {
|
|
961
|
+
off();
|
|
962
|
+
for (const unwake of unwakes) unwake();
|
|
963
|
+
};
|
|
964
|
+
}, [registry, loop]);
|
|
965
|
+
}
|
|
873
966
|
|
|
874
967
|
// src/theme/interstellar.theme.json
|
|
875
968
|
var interstellar_theme_default = {
|
|
@@ -938,20 +1031,6 @@ var interstellar_theme_default = {
|
|
|
938
1031
|
type: "color"
|
|
939
1032
|
}
|
|
940
1033
|
},
|
|
941
|
-
"fg-muted": {
|
|
942
|
-
by: "mode",
|
|
943
|
-
dark: {
|
|
944
|
-
value: "#a8a8c0",
|
|
945
|
-
type: "color"
|
|
946
|
-
}
|
|
947
|
-
},
|
|
948
|
-
"fg-subtle": {
|
|
949
|
-
by: "mode",
|
|
950
|
-
dark: {
|
|
951
|
-
value: "#5a5a78",
|
|
952
|
-
type: "color"
|
|
953
|
-
}
|
|
954
|
-
},
|
|
955
1034
|
accent: {
|
|
956
1035
|
by: "mode",
|
|
957
1036
|
dark: {
|
|
@@ -1010,6 +1089,180 @@ var interstellarTheme = defineTheme({
|
|
|
1010
1089
|
extends: weaselTheme
|
|
1011
1090
|
});
|
|
1012
1091
|
|
|
1092
|
+
// src/clock/trialClock.ts
|
|
1093
|
+
var passesOf = (loop) => loop === true ? Number.POSITIVE_INFINITY : loop === false ? 1 : Math.max(1, loop);
|
|
1094
|
+
var checkRate = (rate, seekable) => {
|
|
1095
|
+
if (!Number.isFinite(rate)) throw new RangeError(`labkit: a clock's rate is finite, not ${rate}`);
|
|
1096
|
+
if (rate < 0 && !seekable)
|
|
1097
|
+
throw new RangeError("labkit: a clock that is not seekable cannot run backward");
|
|
1098
|
+
};
|
|
1099
|
+
function createTrialClock(spec, start) {
|
|
1100
|
+
const duration = spec.duration ?? Number.POSITIVE_INFINITY;
|
|
1101
|
+
const seekable = spec.seekable ?? true;
|
|
1102
|
+
const openRate = spec.rate ?? 0;
|
|
1103
|
+
checkRate(openRate, seekable);
|
|
1104
|
+
let loop = spec.loop ?? false;
|
|
1105
|
+
let span = duration * passesOf(loop);
|
|
1106
|
+
let rate = start ? start.rate : openRate;
|
|
1107
|
+
let elapsed = start ? Math.min(Math.max(0, start.elapsed), span) : 0;
|
|
1108
|
+
let ramp = null;
|
|
1109
|
+
let last = Number.NaN;
|
|
1110
|
+
let changed = false;
|
|
1111
|
+
let slept = false;
|
|
1112
|
+
let wakeFired = false;
|
|
1113
|
+
const wakes = /* @__PURE__ */ new Set();
|
|
1114
|
+
const subs = /* @__PURE__ */ new Set();
|
|
1115
|
+
const frames = /* @__PURE__ */ new Set();
|
|
1116
|
+
const isInert = () => rate === 0 && ramp === null && !changed;
|
|
1117
|
+
const notify = () => {
|
|
1118
|
+
for (const fn of [...subs]) fn();
|
|
1119
|
+
};
|
|
1120
|
+
const change = () => {
|
|
1121
|
+
changed = true;
|
|
1122
|
+
if (wakeFired) return;
|
|
1123
|
+
wakeFired = true;
|
|
1124
|
+
for (const fn of [...wakes]) fn();
|
|
1125
|
+
};
|
|
1126
|
+
const passAt = () => duration > 0 && Number.isFinite(duration) ? elapsed >= span ? passesOf(loop) - 1 : Math.floor(elapsed / duration) : 0;
|
|
1127
|
+
const phaseAt = () => duration > 0 && Number.isFinite(duration) ? elapsed >= span ? 1 : elapsed % duration / duration : 0;
|
|
1128
|
+
const advance = (dt) => {
|
|
1129
|
+
if (!ramp) return rate * dt;
|
|
1130
|
+
if (dt >= ramp.left) {
|
|
1131
|
+
const area2 = (rate + ramp.to) / 2 * ramp.left + ramp.to * (dt - ramp.left);
|
|
1132
|
+
rate = ramp.to;
|
|
1133
|
+
ramp = null;
|
|
1134
|
+
notify();
|
|
1135
|
+
return area2;
|
|
1136
|
+
}
|
|
1137
|
+
const next = rate + (ramp.to - rate) * dt / ramp.left;
|
|
1138
|
+
const area = (rate + next) / 2 * dt;
|
|
1139
|
+
rate = next;
|
|
1140
|
+
ramp.left -= dt;
|
|
1141
|
+
return area;
|
|
1142
|
+
};
|
|
1143
|
+
const clock = {
|
|
1144
|
+
get elapsed() {
|
|
1145
|
+
return elapsed;
|
|
1146
|
+
},
|
|
1147
|
+
get pass() {
|
|
1148
|
+
return passAt();
|
|
1149
|
+
},
|
|
1150
|
+
get phase() {
|
|
1151
|
+
return phaseAt();
|
|
1152
|
+
},
|
|
1153
|
+
get rate() {
|
|
1154
|
+
return rate;
|
|
1155
|
+
},
|
|
1156
|
+
set rate(next) {
|
|
1157
|
+
checkRate(next, seekable);
|
|
1158
|
+
rate = next;
|
|
1159
|
+
ramp = null;
|
|
1160
|
+
change();
|
|
1161
|
+
notify();
|
|
1162
|
+
},
|
|
1163
|
+
get loop() {
|
|
1164
|
+
return loop;
|
|
1165
|
+
},
|
|
1166
|
+
set loop(next) {
|
|
1167
|
+
loop = next;
|
|
1168
|
+
span = duration * passesOf(loop);
|
|
1169
|
+
elapsed = Math.min(elapsed, span);
|
|
1170
|
+
change();
|
|
1171
|
+
notify();
|
|
1172
|
+
},
|
|
1173
|
+
ramp(to, over) {
|
|
1174
|
+
checkRate(to, seekable);
|
|
1175
|
+
if (!(over > 0)) {
|
|
1176
|
+
clock.rate = to;
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
1179
|
+
ramp = { to, left: over };
|
|
1180
|
+
change();
|
|
1181
|
+
notify();
|
|
1182
|
+
},
|
|
1183
|
+
seek(target) {
|
|
1184
|
+
if (!seekable) throw new Error("labkit: this clock is not seekable");
|
|
1185
|
+
elapsed = Math.min(Math.max(0, target), span);
|
|
1186
|
+
change();
|
|
1187
|
+
notify();
|
|
1188
|
+
},
|
|
1189
|
+
sync(timestamp) {
|
|
1190
|
+
const wasChanged = changed;
|
|
1191
|
+
const before = elapsed;
|
|
1192
|
+
if (!Number.isNaN(last) && !slept) {
|
|
1193
|
+
elapsed += advance(Math.max(0, timestamp - last));
|
|
1194
|
+
if (elapsed >= span && rate > 0) {
|
|
1195
|
+
elapsed = span;
|
|
1196
|
+
rate = 0;
|
|
1197
|
+
ramp = null;
|
|
1198
|
+
notify();
|
|
1199
|
+
} else if (elapsed <= 0 && rate < 0) {
|
|
1200
|
+
elapsed = 0;
|
|
1201
|
+
rate = 0;
|
|
1202
|
+
ramp = null;
|
|
1203
|
+
notify();
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
last = timestamp;
|
|
1207
|
+
changed = false;
|
|
1208
|
+
wakeFired = false;
|
|
1209
|
+
slept = isInert();
|
|
1210
|
+
if (elapsed !== before || wasChanged) {
|
|
1211
|
+
const pass = passAt();
|
|
1212
|
+
for (const fn of [...frames]) fn(elapsed, pass);
|
|
1213
|
+
}
|
|
1214
|
+
},
|
|
1215
|
+
rebase() {
|
|
1216
|
+
last = Number.NaN;
|
|
1217
|
+
},
|
|
1218
|
+
get inert() {
|
|
1219
|
+
return isInert();
|
|
1220
|
+
},
|
|
1221
|
+
onWake(fn) {
|
|
1222
|
+
wakes.add(fn);
|
|
1223
|
+
return () => {
|
|
1224
|
+
wakes.delete(fn);
|
|
1225
|
+
};
|
|
1226
|
+
},
|
|
1227
|
+
subscribe(fn) {
|
|
1228
|
+
subs.add(fn);
|
|
1229
|
+
return () => {
|
|
1230
|
+
subs.delete(fn);
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
};
|
|
1234
|
+
return {
|
|
1235
|
+
clock,
|
|
1236
|
+
reset() {
|
|
1237
|
+
elapsed = 0;
|
|
1238
|
+
rate = openRate;
|
|
1239
|
+
ramp = null;
|
|
1240
|
+
change();
|
|
1241
|
+
notify();
|
|
1242
|
+
},
|
|
1243
|
+
onFrame(fn) {
|
|
1244
|
+
frames.add(fn);
|
|
1245
|
+
return () => {
|
|
1246
|
+
frames.delete(fn);
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
// src/undo/stateOp.ts
|
|
1253
|
+
function stateOp(before, read, write) {
|
|
1254
|
+
let after;
|
|
1255
|
+
const forward = {
|
|
1256
|
+
label: "state",
|
|
1257
|
+
apply: () => write(structuredClone(after)),
|
|
1258
|
+
invert: () => {
|
|
1259
|
+
after = structuredClone(read());
|
|
1260
|
+
return { label: "state", apply: () => write(structuredClone(before)), invert: () => forward };
|
|
1261
|
+
}
|
|
1262
|
+
};
|
|
1263
|
+
return forward;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1013
1266
|
// src/canvas/cameraZoom.ts
|
|
1014
1267
|
function atScale(view, scale, at) {
|
|
1015
1268
|
return {
|
|
@@ -1027,6 +1280,36 @@ function zoomCameraTo(camera, zoom) {
|
|
|
1027
1280
|
const scale = Math.min(max, Math.max(min, zoom));
|
|
1028
1281
|
camera.set(atScale(camera.get(), scale, viewMiddle(camera)));
|
|
1029
1282
|
}
|
|
1283
|
+
var PresentationContext = createContext(null);
|
|
1284
|
+
function usePresentation() {
|
|
1285
|
+
const value = useContext(PresentationContext);
|
|
1286
|
+
if (!value) throw new Error("[labkit] usePresentation() must be called inside <Lab>");
|
|
1287
|
+
return value;
|
|
1288
|
+
}
|
|
1289
|
+
function usePresentedTrial(trialId) {
|
|
1290
|
+
const presented = useContext(PresentationContext)?.trialId === trialId;
|
|
1291
|
+
const surface = useSurfaceOptional();
|
|
1292
|
+
const [el, ref] = useState(null);
|
|
1293
|
+
useLayoutEffect(() => {
|
|
1294
|
+
if (!presented || !el || !surface) return;
|
|
1295
|
+
surface.scope(el);
|
|
1296
|
+
return () => surface.scope(null);
|
|
1297
|
+
}, [presented, el, surface]);
|
|
1298
|
+
return { presented, ref };
|
|
1299
|
+
}
|
|
1300
|
+
function hasPresentParam() {
|
|
1301
|
+
return typeof location !== "undefined" && new URLSearchParams(location.search).has("present");
|
|
1302
|
+
}
|
|
1303
|
+
var LightboxContext = createContext(null);
|
|
1304
|
+
function useLightbox() {
|
|
1305
|
+
return useContext(LightboxContext);
|
|
1306
|
+
}
|
|
1307
|
+
function useLightboxControl() {
|
|
1308
|
+
const ctx = useContext(LightboxContext);
|
|
1309
|
+
const claim = ctx?.claimControl;
|
|
1310
|
+
useLayoutEffect(() => claim?.(), [claim]);
|
|
1311
|
+
return ctx;
|
|
1312
|
+
}
|
|
1030
1313
|
function TrialBody({ sidebar, children, contentClassName, ...rest }) {
|
|
1031
1314
|
return /* @__PURE__ */ jsx(
|
|
1032
1315
|
Split,
|
|
@@ -1123,7 +1406,7 @@ function Portalled({
|
|
|
1123
1406
|
}
|
|
1124
1407
|
function UndockedSections({ trialId, sections, onDock }) {
|
|
1125
1408
|
if (sections.length === 0) return null;
|
|
1126
|
-
return /* @__PURE__ */ jsx(Fragment, { children: sections.map((
|
|
1409
|
+
return /* @__PURE__ */ jsx(Fragment, { children: sections.map((c6) => /* @__PURE__ */ jsx(Portalled, { trialId, contribution: c6, onDock }, c6.id)) });
|
|
1127
1410
|
}
|
|
1128
1411
|
var NO_OP = () => {
|
|
1129
1412
|
};
|
|
@@ -1145,19 +1428,20 @@ function TrialChrome({
|
|
|
1145
1428
|
children
|
|
1146
1429
|
}) {
|
|
1147
1430
|
const lab = useLabContext();
|
|
1431
|
+
const { presented, ref: presentedRef } = usePresentedTrial(trialId);
|
|
1148
1432
|
const storeCtx = useContext(LabStoreContext);
|
|
1149
1433
|
if (!storeCtx) throw new Error("[labkit] TrialChrome requires <LabStoreProvider>");
|
|
1150
|
-
const updateTrialView = useStore(storeCtx.store, (
|
|
1151
|
-
const updateTrialSidebarWidth = useStore(storeCtx.store, (
|
|
1152
|
-
const setTrialTitle = useStore(storeCtx.store, (
|
|
1153
|
-
const setTrialSectionCollapsed = useStore(storeCtx.store, (
|
|
1154
|
-
const updateTrialConfig = useStore(storeCtx.store, (
|
|
1155
|
-
const updateTrialState = useStore(storeCtx.store, (
|
|
1156
|
-
const undockPanelAction = useStore(storeCtx.store, (
|
|
1157
|
-
const dockPanelAction = useStore(storeCtx.store, (
|
|
1158
|
-
const undockedPanels = useStore(storeCtx.store, (
|
|
1434
|
+
const updateTrialView = useStore(storeCtx.store, (s4) => s4.updateTrialView);
|
|
1435
|
+
const updateTrialSidebarWidth = useStore(storeCtx.store, (s4) => s4.updateTrialSidebarWidth);
|
|
1436
|
+
const setTrialTitle = useStore(storeCtx.store, (s4) => s4.setTrialTitle);
|
|
1437
|
+
const setTrialSectionCollapsed = useStore(storeCtx.store, (s4) => s4.setTrialSectionCollapsed);
|
|
1438
|
+
const updateTrialConfig = useStore(storeCtx.store, (s4) => s4.updateTrialConfig);
|
|
1439
|
+
const updateTrialState = useStore(storeCtx.store, (s4) => s4.updateTrialState);
|
|
1440
|
+
const undockPanelAction = useStore(storeCtx.store, (s4) => s4.undockPanel);
|
|
1441
|
+
const dockPanelAction = useStore(storeCtx.store, (s4) => s4.dockPanel);
|
|
1442
|
+
const undockedPanels = useStore(storeCtx.store, (s4) => s4.undockedPanels);
|
|
1159
1443
|
const undockedIds = useMemo(
|
|
1160
|
-
() => Object.values(undockedPanels).filter((
|
|
1444
|
+
() => Object.values(undockedPanels).filter((p5) => p5.trialId === trialId).map((p5) => p5.sectionId),
|
|
1161
1445
|
[undockedPanels, trialId]
|
|
1162
1446
|
);
|
|
1163
1447
|
const view2d = as2DView(record.view);
|
|
@@ -1174,6 +1458,7 @@ function TrialChrome({
|
|
|
1174
1458
|
cameras?.subscribe ?? noSubscribe,
|
|
1175
1459
|
() => cameras?.get(trialId) ?? null
|
|
1176
1460
|
);
|
|
1461
|
+
const lightbox = useLightboxControl();
|
|
1177
1462
|
const ctx = useMemo(() => {
|
|
1178
1463
|
const setZoom = (z) => {
|
|
1179
1464
|
if (camera) zoomCameraTo(camera, z);
|
|
@@ -1194,6 +1479,9 @@ function TrialChrome({
|
|
|
1194
1479
|
hasLoupe: loupe != null,
|
|
1195
1480
|
loupeOn: loupe?.on ?? false,
|
|
1196
1481
|
toggleLoupe: loupe?.toggle ?? NO_OP,
|
|
1482
|
+
canExpand: lightbox != null,
|
|
1483
|
+
expanded: lightbox?.expanded ?? false,
|
|
1484
|
+
toggleExpanded: lightbox?.toggle ?? NO_OP,
|
|
1197
1485
|
configSchema,
|
|
1198
1486
|
configFields: instrument.config ? [] : instrument.configSchema?.() ?? [],
|
|
1199
1487
|
config: record.config,
|
|
@@ -1218,7 +1506,7 @@ function TrialChrome({
|
|
|
1218
1506
|
undockedPanels: undockedIds,
|
|
1219
1507
|
undockPanel: (sectionId, as) => undockPanelAction(trialId, sectionId, as),
|
|
1220
1508
|
dockPanel: (sectionId) => dockPanelAction(trialId, sectionId),
|
|
1221
|
-
savedSnapshots: lab.savedSnapshots.filter((
|
|
1509
|
+
savedSnapshots: lab.savedSnapshots.filter((s4) => s4.trialId === trialId),
|
|
1222
1510
|
saveSnapshot: (name) => lab.saveSnapshot(trialId, name),
|
|
1223
1511
|
loadSnapshot: (snapshotId) => lab.loadSnapshot(trialId, snapshotId),
|
|
1224
1512
|
clone: () => lab.cloneTrial(trialId),
|
|
@@ -1239,6 +1527,7 @@ function TrialChrome({
|
|
|
1239
1527
|
updateTrialState,
|
|
1240
1528
|
undoBindings,
|
|
1241
1529
|
loupe,
|
|
1530
|
+
lightbox,
|
|
1242
1531
|
view2d,
|
|
1243
1532
|
activeToolId,
|
|
1244
1533
|
setActiveTool,
|
|
@@ -1266,10 +1555,10 @@ function TrialChrome({
|
|
|
1266
1555
|
),
|
|
1267
1556
|
[instrument, ctx, trialChrome, chrome, suppress, lab.controls]
|
|
1268
1557
|
);
|
|
1269
|
-
const inRegion = (region) => contributions.filter((
|
|
1558
|
+
const inRegion = (region) => contributions.filter((c6) => c6.region === region);
|
|
1270
1559
|
const handleKeyDown = (e) => {
|
|
1271
1560
|
const mod = e.metaKey || e.ctrlKey;
|
|
1272
|
-
if (!mod) return;
|
|
1561
|
+
if (!mod || presented) return;
|
|
1273
1562
|
if (e.key === "z" || e.key === "Z") {
|
|
1274
1563
|
e.preventDefault();
|
|
1275
1564
|
if (e.shiftKey) ctx.redo();
|
|
@@ -1282,9 +1571,11 @@ function TrialChrome({
|
|
|
1282
1571
|
return /* @__PURE__ */ jsxs(
|
|
1283
1572
|
"section",
|
|
1284
1573
|
{
|
|
1574
|
+
ref: presentedRef,
|
|
1285
1575
|
className: "lk-trial",
|
|
1286
1576
|
"data-trial-id": trialId,
|
|
1287
1577
|
"data-focused": lab.trials.length > 1 && lab.focusedTrialId === trialId ? "true" : void 0,
|
|
1578
|
+
"data-lk-presented": presented ? "" : void 0,
|
|
1288
1579
|
"aria-label": `Trial ${title}`,
|
|
1289
1580
|
tabIndex: -1,
|
|
1290
1581
|
onKeyDown: handleKeyDown,
|
|
@@ -1304,15 +1595,18 @@ function TrialChrome({
|
|
|
1304
1595
|
TrialBody,
|
|
1305
1596
|
{
|
|
1306
1597
|
width: record.sidebarWidth,
|
|
1307
|
-
onWidthChange: (
|
|
1308
|
-
contentClassName:
|
|
1598
|
+
onWidthChange: (w3) => updateTrialSidebarWidth(trialId, w3),
|
|
1599
|
+
contentClassName: [
|
|
1600
|
+
instrument.canvas || instrument.stage ? "lk-trial__content--flush" : "",
|
|
1601
|
+
presented ? "lk-trial__stage" : ""
|
|
1602
|
+
].filter(Boolean).join(" ") || void 0,
|
|
1309
1603
|
sidebar: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1310
1604
|
/* @__PURE__ */ jsx(SidebarRegion, { contributions: inRegion("sidebar"), ctx }),
|
|
1311
1605
|
/* @__PURE__ */ jsx(
|
|
1312
1606
|
UndockedSections,
|
|
1313
1607
|
{
|
|
1314
1608
|
trialId,
|
|
1315
|
-
sections: inRegion("sidebar").filter((
|
|
1609
|
+
sections: inRegion("sidebar").filter((c6) => undockedIds.includes(c6.id)),
|
|
1316
1610
|
onDock: ctx.dockPanel
|
|
1317
1611
|
}
|
|
1318
1612
|
)
|
|
@@ -1336,8 +1630,8 @@ function Trial({ id, chrome, suppress }) {
|
|
|
1336
1630
|
const lab = useLabContext();
|
|
1337
1631
|
const storeCtx = useContext(LabStoreContext);
|
|
1338
1632
|
if (!storeCtx) throw new Error("[labkit] <Trial> requires <LabStoreProvider>");
|
|
1339
|
-
const instruments = useStore(storeCtx.store, (
|
|
1340
|
-
const record = useStore(storeCtx.store, (
|
|
1633
|
+
const instruments = useStore(storeCtx.store, (s4) => s4.instruments) ?? lab.instruments;
|
|
1634
|
+
const record = useStore(storeCtx.store, (s4) => s4.trials.find((w3) => w3.id === id));
|
|
1341
1635
|
const instrument = record ? instruments.find((i4) => i4.name === record.instrumentName) : void 0;
|
|
1342
1636
|
const kept = useKeptMarks(instrument?.annotations?.storage, id);
|
|
1343
1637
|
if (!record) {
|
|
@@ -1410,14 +1704,15 @@ function TrialRuntime({
|
|
|
1410
1704
|
);
|
|
1411
1705
|
const [pointer] = useState(createPointerStore);
|
|
1412
1706
|
const canvasContainerRef = useRef(null);
|
|
1413
|
-
const updateTrialState = useStore(store, (
|
|
1414
|
-
const updateTrialConfig = useStore(store, (
|
|
1415
|
-
const updateTrialView = useStore(store, (
|
|
1416
|
-
const
|
|
1417
|
-
const
|
|
1418
|
-
const
|
|
1419
|
-
const
|
|
1420
|
-
const
|
|
1707
|
+
const updateTrialState = useStore(store, (s4) => s4.updateTrialState);
|
|
1708
|
+
const updateTrialConfig = useStore(store, (s4) => s4.updateTrialConfig);
|
|
1709
|
+
const updateTrialView = useStore(store, (s4) => s4.updateTrialView);
|
|
1710
|
+
const setTrialHistory = useStore(store, (s4) => s4.setTrialHistory);
|
|
1711
|
+
const updateTrialClock = useStore(store, (s4) => s4.updateTrialClock);
|
|
1712
|
+
const updateTrialAnnotations = useStore(store, (s4) => s4.updateTrialAnnotations);
|
|
1713
|
+
const labToolId = useStore(store, (s4) => s4.activeToolId);
|
|
1714
|
+
const setLabTool = useStore(store, (s4) => s4.setLabTool);
|
|
1715
|
+
const setTrialTool = useStore(store, (s4) => s4.setTrialTool);
|
|
1421
1716
|
const schema = useConfigSchema(instrument);
|
|
1422
1717
|
const { config } = useResolvedConfig(schema, record.config, record.auto);
|
|
1423
1718
|
const busRef = useRef(null);
|
|
@@ -1436,15 +1731,40 @@ function TrialRuntime({
|
|
|
1436
1731
|
() => (instrument.canvas?.layers ?? []).filter((l8) => layerVisibility[l8.id] !== false).map((l8) => l8.id),
|
|
1437
1732
|
[instrument.canvas, layerVisibility]
|
|
1438
1733
|
);
|
|
1734
|
+
const [clockHandle] = useState(
|
|
1735
|
+
() => instrument.clock ? createTrialClock(instrument.clock, record.clock) : null
|
|
1736
|
+
);
|
|
1737
|
+
const clocks = useContext(ClockRegistryContext);
|
|
1738
|
+
useEffect(() => {
|
|
1739
|
+
if (!clockHandle || !clocks) return;
|
|
1740
|
+
return clocks.register(record.id, clockHandle);
|
|
1741
|
+
}, [clocks, clockHandle, record.id]);
|
|
1742
|
+
useEffect(() => {
|
|
1743
|
+
if (!clockHandle) return;
|
|
1744
|
+
const { clock } = clockHandle;
|
|
1745
|
+
return clock.subscribe(
|
|
1746
|
+
() => updateTrialClock(record.id, { elapsed: clock.elapsed, rate: clock.rate })
|
|
1747
|
+
);
|
|
1748
|
+
}, [clockHandle, record.id, updateTrialClock]);
|
|
1749
|
+
const ticks = useMemo(
|
|
1750
|
+
() => clockHandle ? (fn) => clockHandle.onFrame(() => fn()) : void 0,
|
|
1751
|
+
[clockHandle]
|
|
1752
|
+
);
|
|
1439
1753
|
const undoCap = instrument.undo;
|
|
1440
1754
|
const undoEvents = useMemo(() => new Set(undoCap?.snapshotOn ?? ["state.change"]), [undoCap]);
|
|
1441
1755
|
const maxDepth = undoCap?.maxDepth ?? 50;
|
|
1442
1756
|
const snapshotIfNeeded = (event) => {
|
|
1443
1757
|
if (!undoCap || !undoEvents.has(event)) return;
|
|
1444
|
-
const current = store.getState().trials.find((
|
|
1758
|
+
const current = store.getState().trials.find((w3) => w3.id === record.id);
|
|
1445
1759
|
if (!current) return;
|
|
1446
|
-
|
|
1447
|
-
|
|
1760
|
+
let history = current.history;
|
|
1761
|
+
if (!history) {
|
|
1762
|
+
history = createHistory(null, { historyLimit: maxDepth });
|
|
1763
|
+
setTrialHistory(record.id, history);
|
|
1764
|
+
}
|
|
1765
|
+
const read = () => store.getState().trials.find((w3) => w3.id === record.id)?.state;
|
|
1766
|
+
const write = (state) => updateTrialState(record.id, state);
|
|
1767
|
+
history.recordEntry([stateOp(structuredClone(current.state), read, write)], event);
|
|
1448
1768
|
};
|
|
1449
1769
|
const setView = (v2) => updateTrialView(record.id, v2);
|
|
1450
1770
|
const stage = instrument.canvas ? void 0 : instrument.stage;
|
|
@@ -1573,7 +1893,8 @@ function TrialRuntime({
|
|
|
1573
1893
|
},
|
|
1574
1894
|
activeToolId: resolvedToolId,
|
|
1575
1895
|
visibleLayers,
|
|
1576
|
-
pointer
|
|
1896
|
+
pointer,
|
|
1897
|
+
...clockHandle ? { clock: clockHandle.clock } : {}
|
|
1577
1898
|
},
|
|
1578
1899
|
emit: (event) => {
|
|
1579
1900
|
snapshotIfNeeded(event);
|
|
@@ -1581,50 +1902,48 @@ function TrialRuntime({
|
|
|
1581
1902
|
},
|
|
1582
1903
|
job: jobCap ? job : void 0
|
|
1583
1904
|
};
|
|
1584
|
-
const
|
|
1585
|
-
const result = undo(record.undoStack, structuredClone(record.state));
|
|
1586
|
-
if (!result) return;
|
|
1587
|
-
updateTrialState(record.id, result.snapshot);
|
|
1588
|
-
updateTrialUndoStack(record.id, result.stack);
|
|
1589
|
-
};
|
|
1590
|
-
const redoState = () => {
|
|
1591
|
-
const result = redo(record.undoStack, structuredClone(record.state));
|
|
1592
|
-
if (!result) return;
|
|
1593
|
-
updateTrialState(record.id, result.snapshot);
|
|
1594
|
-
updateTrialUndoStack(record.id, result.stack);
|
|
1595
|
-
};
|
|
1905
|
+
const stateHistory = useHistoryVersion(record.history);
|
|
1596
1906
|
const undoBindings = undoCap || annotationsCap ? {
|
|
1597
|
-
canUndo: markMoves.undo || (undoCap ?
|
|
1598
|
-
canRedo: markMoves.redo || (undoCap ?
|
|
1907
|
+
canUndo: markMoves.undo || (undoCap ? stateHistory?.canUndo() ?? false : false),
|
|
1908
|
+
canRedo: markMoves.redo || (undoCap ? stateHistory?.canRedo() ?? false : false),
|
|
1599
1909
|
undo: () => {
|
|
1600
1910
|
if (annotationsCap && annotations.undo()) return;
|
|
1601
|
-
if (undoCap)
|
|
1911
|
+
if (undoCap) stateHistory?.undo();
|
|
1602
1912
|
},
|
|
1603
1913
|
redo: () => {
|
|
1604
1914
|
if (annotationsCap && annotations.redo()) return;
|
|
1605
|
-
if (undoCap)
|
|
1915
|
+
if (undoCap) stateHistory?.redo();
|
|
1606
1916
|
}
|
|
1607
1917
|
} : void 0;
|
|
1608
1918
|
const loupeBindings = lenses > 0 ? { on: loupeOn, toggle: () => setLoupeOn((v2) => !v2) } : void 0;
|
|
1609
1919
|
const canvasLayers = useMemo(() => {
|
|
1610
1920
|
if (!instrument.canvas) return [];
|
|
1611
1921
|
const baseLayers = instrument.canvas.layers;
|
|
1612
|
-
const ordered = layerOrder ? [...baseLayers].sort((
|
|
1922
|
+
const ordered = layerOrder ? [...baseLayers].sort((a4, b3) => layerOrder.indexOf(a4.id) - layerOrder.indexOf(b3.id)) : baseLayers;
|
|
1923
|
+
const clock = clockHandle?.clock;
|
|
1613
1924
|
return ordered.map((layer) => ({
|
|
1614
1925
|
id: layer.id,
|
|
1615
1926
|
visible: layerVisibility[layer.id] !== false,
|
|
1927
|
+
timed: layer.timed === true,
|
|
1616
1928
|
render: (ctx, view, frame) => {
|
|
1617
1929
|
applyCamera(ctx, view, frame);
|
|
1618
|
-
layer.draw(ctx, {
|
|
1930
|
+
layer.draw(ctx, {
|
|
1931
|
+
state: record.state,
|
|
1932
|
+
config,
|
|
1933
|
+
zoom: view.zoom,
|
|
1934
|
+
elapsed: clock?.elapsed ?? 0,
|
|
1935
|
+
pass: clock?.pass ?? 0,
|
|
1936
|
+
phase: clock?.phase ?? 0
|
|
1937
|
+
});
|
|
1619
1938
|
}
|
|
1620
1939
|
}));
|
|
1621
|
-
}, [instrument.canvas, record.state, config, layerVisibility, layerOrder]);
|
|
1940
|
+
}, [instrument.canvas, record.state, config, layerVisibility, layerOrder, clockHandle]);
|
|
1622
1941
|
const layerDescriptors = useMemo(() => {
|
|
1623
1942
|
if (!instrument.layers) return [];
|
|
1624
1943
|
return instrument.layers.ids.map((l8) => typeof l8 === "string" ? { id: l8, label: l8 } : l8);
|
|
1625
1944
|
}, [instrument.layers]);
|
|
1626
1945
|
const layerItems = useMemo(() => {
|
|
1627
|
-
const ordered = layerOrder ? [...layerDescriptors].sort((
|
|
1946
|
+
const ordered = layerOrder ? [...layerDescriptors].sort((a4, b3) => layerOrder.indexOf(a4.id) - layerOrder.indexOf(b3.id)) : layerDescriptors;
|
|
1628
1947
|
const pinnedLast = [
|
|
1629
1948
|
...ordered.filter((l8) => !l8.alwaysOn),
|
|
1630
1949
|
...ordered.filter((l8) => l8.alwaysOn)
|
|
@@ -1637,7 +1956,7 @@ function TrialRuntime({
|
|
|
1637
1956
|
}));
|
|
1638
1957
|
}, [layerDescriptors, layerOrder, layerVisibility]);
|
|
1639
1958
|
const dragDropResult = useDragDrop({
|
|
1640
|
-
capability: instrument.dragDrop ?? { palette: [], onDrop: (_p, _i,
|
|
1959
|
+
capability: instrument.dragDrop ?? { palette: [], onDrop: (_p, _i, s4) => s4 },
|
|
1641
1960
|
canvasContainerRef,
|
|
1642
1961
|
view: view2d ?? DEFAULT_VIEW,
|
|
1643
1962
|
worldSpec: instrument.canvas?.worldSpec,
|
|
@@ -1654,8 +1973,8 @@ function TrialRuntime({
|
|
|
1654
1973
|
});
|
|
1655
1974
|
const paletteItems = useMemo(() => {
|
|
1656
1975
|
if (!instrument.dragDrop) return [];
|
|
1657
|
-
const
|
|
1658
|
-
return typeof
|
|
1976
|
+
const p5 = instrument.dragDrop.palette;
|
|
1977
|
+
return typeof p5 === "function" ? p5(record.state, config) : p5;
|
|
1659
1978
|
}, [instrument.dragDrop, record.state, config]);
|
|
1660
1979
|
const layersWithFeedback = useMemo(() => {
|
|
1661
1980
|
if (!dragDropResult.drag?.feedback) return canvasLayers;
|
|
@@ -1694,6 +2013,7 @@ function TrialRuntime({
|
|
|
1694
2013
|
onResize: placeView,
|
|
1695
2014
|
minZoom: instrument.canvas.minZoom,
|
|
1696
2015
|
maxZoom: instrument.canvas.maxZoom,
|
|
2016
|
+
ticks,
|
|
1697
2017
|
children: instrument.render(renderCtx)
|
|
1698
2018
|
}
|
|
1699
2019
|
),
|
|
@@ -1723,11 +2043,11 @@ function TrialRuntime({
|
|
|
1723
2043
|
);
|
|
1724
2044
|
const layerListNode = useMemo(
|
|
1725
2045
|
() => instrument.layers && layerDescriptors.length > 0 ? /* @__PURE__ */ jsx(
|
|
1726
|
-
|
|
2046
|
+
A2,
|
|
1727
2047
|
{
|
|
1728
2048
|
items: layerItems,
|
|
1729
2049
|
onReorder: (move) => {
|
|
1730
|
-
setLayerOrder(
|
|
2050
|
+
setLayerOrder(T(layerItems, move).map((l8) => l8.id));
|
|
1731
2051
|
bus.emit("layers.reorder");
|
|
1732
2052
|
},
|
|
1733
2053
|
onVisibilityChange: (lid, visible) => {
|
|
@@ -1768,7 +2088,7 @@ function TrialRuntime({
|
|
|
1768
2088
|
}
|
|
1769
2089
|
) : null;
|
|
1770
2090
|
const scopedBody = /* @__PURE__ */ jsx(WeaselProvider, { isolate: true, children: /* @__PURE__ */ jsx(PointerContextProvider, { store: pointer, children: /* @__PURE__ */ jsx(CameraPublishContext.Provider, { value: publishCamera, children: /* @__PURE__ */ jsx(LoupeSwitchContext.Provider, { value: loupeSwitch, children: body }) }) }) });
|
|
1771
|
-
return /* @__PURE__ */ jsx(TrialIdProvider, { trialId: record.id, children: /* @__PURE__ */ jsx(AnnotationsContext.Provider, { value: annotationsCap ? provided : null, children: /* @__PURE__ */ jsx(CameraWheelContext.Provider, { value: wheelSlot, children: /* @__PURE__ */ jsxs(
|
|
2091
|
+
return /* @__PURE__ */ jsx(TrialIdProvider, { trialId: record.id, children: /* @__PURE__ */ jsx(TrialClockContext.Provider, { value: clockHandle, children: /* @__PURE__ */ jsx(AnnotationsContext.Provider, { value: annotationsCap ? provided : null, children: /* @__PURE__ */ jsx(CameraWheelContext.Provider, { value: wheelSlot, children: /* @__PURE__ */ jsxs(
|
|
1772
2092
|
TrialChrome,
|
|
1773
2093
|
{
|
|
1774
2094
|
job: jobCap ? job : void 0,
|
|
@@ -1788,7 +2108,13 @@ function TrialRuntime({
|
|
|
1788
2108
|
annotationOverlays
|
|
1789
2109
|
]
|
|
1790
2110
|
}
|
|
1791
|
-
) }) }) });
|
|
2111
|
+
) }) }) }) });
|
|
2112
|
+
}
|
|
2113
|
+
var NO_SUBSCRIBE2 = () => () => {
|
|
2114
|
+
};
|
|
2115
|
+
function useHistoryVersion(history) {
|
|
2116
|
+
useSyncExternalStore(history?.subscribe ?? NO_SUBSCRIBE2, () => history?.getVersion() ?? 0);
|
|
2117
|
+
return history;
|
|
1792
2118
|
}
|
|
1793
2119
|
|
|
1794
2120
|
// src/trial/trialOps.ts
|
|
@@ -1841,8 +2167,7 @@ function addTrial(trials, instruments, instrumentName, options = {}) {
|
|
|
1841
2167
|
instrumentName,
|
|
1842
2168
|
config,
|
|
1843
2169
|
state,
|
|
1844
|
-
view: initialView(instrument)
|
|
1845
|
-
undoStack: { past: [], future: [] }
|
|
2170
|
+
view: initialView(instrument)
|
|
1846
2171
|
};
|
|
1847
2172
|
if (options.config) record.configSeed = seeded.config;
|
|
1848
2173
|
if (seeded.autoPaths.length > 0) record.autoSeed = seeded.autoPaths;
|
|
@@ -1850,26 +2175,26 @@ function addTrial(trials, instruments, instrumentName, options = {}) {
|
|
|
1850
2175
|
return [...trials, record];
|
|
1851
2176
|
}
|
|
1852
2177
|
function cloneTrial(trials, id) {
|
|
1853
|
-
const sourceIdx = trials.findIndex((
|
|
2178
|
+
const sourceIdx = trials.findIndex((w3) => w3.id === id);
|
|
1854
2179
|
const source = trials[sourceIdx];
|
|
1855
2180
|
if (!source) return trials;
|
|
2181
|
+
const { history: _history, ...rest } = source;
|
|
1856
2182
|
const clone = {
|
|
1857
|
-
...
|
|
2183
|
+
...rest,
|
|
1858
2184
|
id: newId(),
|
|
1859
2185
|
config: structuredClone(source.config),
|
|
1860
2186
|
state: structuredClone(source.state),
|
|
1861
|
-
view: structuredClone(source.view)
|
|
1862
|
-
undoStack: { past: [], future: [] }
|
|
2187
|
+
view: structuredClone(source.view)
|
|
1863
2188
|
};
|
|
1864
2189
|
return [...trials.slice(0, sourceIdx + 1), clone, ...trials.slice(sourceIdx + 1)];
|
|
1865
2190
|
}
|
|
1866
2191
|
function closeTrial(trials, id) {
|
|
1867
2192
|
if (trials.length <= 1) return trials;
|
|
1868
|
-
const next = trials.filter((
|
|
2193
|
+
const next = trials.filter((w3) => w3.id !== id);
|
|
1869
2194
|
return next.length === trials.length ? trials : next;
|
|
1870
2195
|
}
|
|
1871
2196
|
function resetTrial(trials, id, instruments) {
|
|
1872
|
-
const idx = trials.findIndex((
|
|
2197
|
+
const idx = trials.findIndex((w3) => w3.id === id);
|
|
1873
2198
|
const current = trials[idx];
|
|
1874
2199
|
if (!current) return trials;
|
|
1875
2200
|
const instrument = findInstrument(instruments, current.instrumentName);
|
|
@@ -1887,7 +2212,7 @@ function resetTrial(trials, id, instruments) {
|
|
|
1887
2212
|
return [...trials.slice(0, idx), reset, ...trials.slice(idx + 1)];
|
|
1888
2213
|
}
|
|
1889
2214
|
function swapTrial(trials, instruments, id, instrumentName, options = {}) {
|
|
1890
|
-
const idx = trials.findIndex((
|
|
2215
|
+
const idx = trials.findIndex((w3) => w3.id === id);
|
|
1891
2216
|
const current = trials[idx];
|
|
1892
2217
|
if (!current) return trials;
|
|
1893
2218
|
const [record] = addTrial([], instruments, instrumentName, options);
|
|
@@ -1895,10 +2220,10 @@ function swapTrial(trials, instruments, id, instrumentName, options = {}) {
|
|
|
1895
2220
|
return [...trials.slice(0, idx), record, ...trials.slice(idx + 1)];
|
|
1896
2221
|
}
|
|
1897
2222
|
function reorderTrials(trials, ids) {
|
|
1898
|
-
const byId = new Map(trials.map((
|
|
1899
|
-
const named = ids.map((id) => byId.get(id)).filter((
|
|
1900
|
-
const seen = new Set(named.map((
|
|
1901
|
-
const rest = trials.filter((
|
|
2223
|
+
const byId = new Map(trials.map((w3) => [w3.id, w3]));
|
|
2224
|
+
const named = ids.map((id) => byId.get(id)).filter((w3) => w3 !== void 0);
|
|
2225
|
+
const seen = new Set(named.map((w3) => w3.id));
|
|
2226
|
+
const rest = trials.filter((w3) => !seen.has(w3.id));
|
|
1902
2227
|
return [...named, ...rest];
|
|
1903
2228
|
}
|
|
1904
2229
|
function findOvershoot(bound, items, tolerance = 1) {
|
|
@@ -1913,7 +2238,7 @@ function findOvershoot(bound, items, tolerance = 1) {
|
|
|
1913
2238
|
return worst;
|
|
1914
2239
|
}
|
|
1915
2240
|
function tagAndClasses(el) {
|
|
1916
|
-
return el.tagName.toLowerCase() + [...el.classList].map((
|
|
2241
|
+
return el.tagName.toLowerCase() + [...el.classList].map((c6) => `.${c6}`).join("");
|
|
1917
2242
|
}
|
|
1918
2243
|
function describeElement(el) {
|
|
1919
2244
|
if (el.classList.length > 0) return tagAndClasses(el);
|
|
@@ -1996,7 +2321,7 @@ function LabHeader({ addTrial: addTrial2 = true }) {
|
|
|
1996
2321
|
]
|
|
1997
2322
|
}
|
|
1998
2323
|
) : /* @__PURE__ */ jsx(
|
|
1999
|
-
|
|
2324
|
+
p6,
|
|
2000
2325
|
{
|
|
2001
2326
|
"aria-label": "Add trial",
|
|
2002
2327
|
label: "Add trial\u2026",
|
|
@@ -2012,7 +2337,7 @@ function LabThemeSwitcher() {
|
|
|
2012
2337
|
function LabPalette({ tools, contributions }) {
|
|
2013
2338
|
const ctx = useLabChromeContext();
|
|
2014
2339
|
const all = labContributions(tools, contributions);
|
|
2015
|
-
return /* @__PURE__ */ jsx(PaletteRegion, { contributions: all.filter((
|
|
2340
|
+
return /* @__PURE__ */ jsx(PaletteRegion, { contributions: all.filter((c6) => c6.region === "palette"), ctx });
|
|
2016
2341
|
}
|
|
2017
2342
|
function LabRoot({ children, mode = "auto", className }) {
|
|
2018
2343
|
const resolved = useResolvedColorMode(mode);
|
|
@@ -2031,13 +2356,13 @@ function locate(url) {
|
|
|
2031
2356
|
function currentPage(path, pages) {
|
|
2032
2357
|
const here = locate(path);
|
|
2033
2358
|
const onDoc = (doc) => here.doc.endsWith(doc);
|
|
2034
|
-
const routed = pages.findIndex((
|
|
2035
|
-
if (!
|
|
2036
|
-
const page = locate(
|
|
2359
|
+
const routed = pages.findIndex((p5) => {
|
|
2360
|
+
if (!p5.href.includes("#")) return false;
|
|
2361
|
+
const page = locate(p5.href);
|
|
2037
2362
|
return onDoc(page.doc) && (here.route === page.route || here.route.startsWith(`${page.route}/`));
|
|
2038
2363
|
});
|
|
2039
2364
|
if (routed >= 0) return routed;
|
|
2040
|
-
return pages.findIndex((
|
|
2365
|
+
return pages.findIndex((p5) => !p5.href.includes("#") && onDoc(locate(p5.href).doc));
|
|
2041
2366
|
}
|
|
2042
2367
|
function LabSwitcher({ title, pages, path, className }) {
|
|
2043
2368
|
const [open, setOpen] = useState(false);
|
|
@@ -2126,6 +2451,91 @@ function LabShell({
|
|
|
2126
2451
|
footer && /* @__PURE__ */ jsx("footer", { className: "lk-shell-footer", children: footer })
|
|
2127
2452
|
] });
|
|
2128
2453
|
}
|
|
2454
|
+
var NONE = { below: [], above: [] };
|
|
2455
|
+
var LightboxLayersContext = createContext(NONE);
|
|
2456
|
+
function LightboxLayers({ below, above, children }) {
|
|
2457
|
+
const value = useMemo(
|
|
2458
|
+
() => ({ below: below ?? NONE.below, above: above ?? NONE.above }),
|
|
2459
|
+
[below, above]
|
|
2460
|
+
);
|
|
2461
|
+
return /* @__PURE__ */ jsx(LightboxLayersContext.Provider, { value, children });
|
|
2462
|
+
}
|
|
2463
|
+
function useLightboxLayers() {
|
|
2464
|
+
return useContext(LightboxLayersContext);
|
|
2465
|
+
}
|
|
2466
|
+
function LabSurface({ bodyRef, children }) {
|
|
2467
|
+
const outerSurface = useSurfaceOptional();
|
|
2468
|
+
const outerOver = useSurfaceCanvas("over");
|
|
2469
|
+
const outerUnder = useSurfaceCanvas("under");
|
|
2470
|
+
const [ownOver, setOwnOver] = useState(null);
|
|
2471
|
+
const [ownUnder, setOwnUnder] = useState(null);
|
|
2472
|
+
const [underLayer, setUnderLayer] = useState(null);
|
|
2473
|
+
const [overLayer, setOverLayer] = useState(null);
|
|
2474
|
+
const ownOverRef = useRef(null);
|
|
2475
|
+
const ownUnderRef = useRef(null);
|
|
2476
|
+
const bufferRef = useRef({ w: 0, h: 0 });
|
|
2477
|
+
const surfaceRef = useRef(null);
|
|
2478
|
+
const onFrame = useCallback((frame) => {
|
|
2479
|
+
const canvases2 = [ownUnderRef.current, ownOverRef.current].filter((c6) => c6 !== null);
|
|
2480
|
+
if (canvases2.length === 0) return;
|
|
2481
|
+
const w3 = Math.round(frame.size.width * frame.dpr);
|
|
2482
|
+
const h2 = Math.round(frame.size.height * frame.dpr);
|
|
2483
|
+
if (bufferRef.current.w !== w3 || bufferRef.current.h !== h2) {
|
|
2484
|
+
bufferRef.current = { w: w3, h: h2 };
|
|
2485
|
+
for (const c6 of canvases2) {
|
|
2486
|
+
c6.width = w3;
|
|
2487
|
+
c6.height = h2;
|
|
2488
|
+
c6.style.width = `${frame.size.width}px`;
|
|
2489
|
+
c6.style.height = `${frame.size.height}px`;
|
|
2490
|
+
}
|
|
2491
|
+
surfaceRef.current?.invalidateAll();
|
|
2492
|
+
return;
|
|
2493
|
+
}
|
|
2494
|
+
}, []);
|
|
2495
|
+
const ownSurface = useTiledSurface({ onFrame });
|
|
2496
|
+
useInsertionEffect(() => {
|
|
2497
|
+
surfaceRef.current = ownSurface;
|
|
2498
|
+
}, [ownSurface]);
|
|
2499
|
+
const attachOwnSurface = ownSurface.containerRef;
|
|
2500
|
+
const overLayerRef = useCallback(
|
|
2501
|
+
(el) => {
|
|
2502
|
+
setOverLayer(el);
|
|
2503
|
+
attachOwnSurface(el);
|
|
2504
|
+
},
|
|
2505
|
+
[attachOwnSurface]
|
|
2506
|
+
);
|
|
2507
|
+
const surface = outerSurface ?? ownSurface;
|
|
2508
|
+
const canvases = useMemo(
|
|
2509
|
+
() => outerSurface ? { over: outerOver, under: outerUnder } : { over: ownOver, under: ownUnder },
|
|
2510
|
+
[outerSurface, outerOver, outerUnder, ownOver, ownUnder]
|
|
2511
|
+
);
|
|
2512
|
+
const below = useMemo(() => [underLayer], [underLayer]);
|
|
2513
|
+
const above = useMemo(() => [overLayer], [overLayer]);
|
|
2514
|
+
const body = /* @__PURE__ */ jsxs("div", { className: "lk-lab__body", ref: bodyRef, children: [
|
|
2515
|
+
outerSurface ? null : /* @__PURE__ */ jsx("div", { className: "lk-lab__layer lk-lab__layer--under", ref: setUnderLayer, children: /* @__PURE__ */ jsx(
|
|
2516
|
+
"canvas",
|
|
2517
|
+
{
|
|
2518
|
+
className: "lk-lab__surface",
|
|
2519
|
+
ref: (el) => {
|
|
2520
|
+
ownUnderRef.current = el;
|
|
2521
|
+
setOwnUnder(el);
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
) }),
|
|
2525
|
+
children,
|
|
2526
|
+
outerSurface ? null : /* @__PURE__ */ jsx("div", { className: "lk-lab__layer lk-lab__layer--over", ref: overLayerRef, children: /* @__PURE__ */ jsx(
|
|
2527
|
+
"canvas",
|
|
2528
|
+
{
|
|
2529
|
+
className: "lk-lab__surface",
|
|
2530
|
+
ref: (el) => {
|
|
2531
|
+
ownOverRef.current = el;
|
|
2532
|
+
setOwnOver(el);
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
) })
|
|
2536
|
+
] });
|
|
2537
|
+
return /* @__PURE__ */ jsx(SurfaceContext.Provider, { value: surface, children: /* @__PURE__ */ jsx(SurfaceCanvasContext.Provider, { value: canvases, children: /* @__PURE__ */ jsx(LightboxLayers, { below, above, children: body }) }) });
|
|
2538
|
+
}
|
|
2129
2539
|
var ZOOM_ID = "viewport.zoom";
|
|
2130
2540
|
var NO_TOOLS = /* @__PURE__ */ new Map();
|
|
2131
2541
|
var CHANNELS = { contextMenu: false, ingest: false };
|
|
@@ -2158,8 +2568,8 @@ function LabZoomControls() {
|
|
|
2158
2568
|
cameras?.subscribe ?? noSubscribe2,
|
|
2159
2569
|
() => cameras && focusedTrialId ? cameras.get(focusedTrialId) : null
|
|
2160
2570
|
);
|
|
2161
|
-
const zoom = useStore(storeCtx.store, (
|
|
2162
|
-
const record =
|
|
2571
|
+
const zoom = useStore(storeCtx.store, (s4) => {
|
|
2572
|
+
const record = s4.trials.find((t) => t.id === focusedTrialId);
|
|
2163
2573
|
return as2DView(record?.view)?.zoom ?? null;
|
|
2164
2574
|
});
|
|
2165
2575
|
const live = zoom !== null && camera !== null;
|
|
@@ -2201,7 +2611,7 @@ function LabZoomControls() {
|
|
|
2201
2611
|
title: hint("Zoom out", "out"),
|
|
2202
2612
|
disabled: !canOut,
|
|
2203
2613
|
onClick: run("out"),
|
|
2204
|
-
children: /* @__PURE__ */ jsx(
|
|
2614
|
+
children: /* @__PURE__ */ jsx(Z, { size: 16 })
|
|
2205
2615
|
}
|
|
2206
2616
|
),
|
|
2207
2617
|
/* @__PURE__ */ jsx(
|
|
@@ -2229,6 +2639,311 @@ function LabZoomControls() {
|
|
|
2229
2639
|
}
|
|
2230
2640
|
var noSubscribe2 = () => () => {
|
|
2231
2641
|
};
|
|
2642
|
+
var NEBULA_SLOTS = [
|
|
2643
|
+
{ cx: "18%", cy: "30%", sx: "60%", sy: "80%", stop: "70%" },
|
|
2644
|
+
{ cx: "78%", cy: "70%", sx: "55%", sy: "90%", stop: "65%" },
|
|
2645
|
+
{ cx: "50%", cy: "50%", sx: "50%", sy: "70%", stop: "75%" },
|
|
2646
|
+
{ cx: "12%", cy: "82%", sx: "50%", sy: "70%", stop: "70%" },
|
|
2647
|
+
{ cx: "85%", cy: "18%", sx: "55%", sy: "80%", stop: "70%" }
|
|
2648
|
+
];
|
|
2649
|
+
function buildNebula(list, theme, mode, density) {
|
|
2650
|
+
const ctx = { theme, resolved: resolveTheme(theme, { mode, density }) };
|
|
2651
|
+
const n6 = colorCount(list, ctx) ?? NEBULA_SLOTS.length;
|
|
2652
|
+
const colors = Array.from({ length: n6 }, (_2, i4) => colorAt(list, i4, ctx));
|
|
2653
|
+
const blobs = colors.map((c6, i4) => {
|
|
2654
|
+
const p5 = NEBULA_SLOTS[i4 % NEBULA_SLOTS.length];
|
|
2655
|
+
return `radial-gradient(ellipse ${p5.sx} ${p5.sy} at ${p5.cx} ${p5.cy}, color-mix(in srgb, ${c6} 22%, transparent), transparent ${p5.stop})`;
|
|
2656
|
+
});
|
|
2657
|
+
blobs.push("radial-gradient(ellipse at center, #0a0a18 0%, #02020a 100%)");
|
|
2658
|
+
return blobs.join(", ");
|
|
2659
|
+
}
|
|
2660
|
+
function presentStorageKey(storageKey) {
|
|
2661
|
+
return `${storageKey}:present`;
|
|
2662
|
+
}
|
|
2663
|
+
var SEED_RECORD = valueRecord(null, "lk-present-seed");
|
|
2664
|
+
function seedPresentedTrial(store, records, { instruments, defaultInstrument }, seed) {
|
|
2665
|
+
const instrument = seed.instrument ?? defaultInstrument;
|
|
2666
|
+
const fingerprint = stableStringify({ ...seed, instrument });
|
|
2667
|
+
const trials = store.getState().trials;
|
|
2668
|
+
if (trials.length > 0 && records.get(SEED_RECORD) === fingerprint) return;
|
|
2669
|
+
const record = addTrial([], instruments, instrument, { config: seed.config })[0];
|
|
2670
|
+
if (!record) return;
|
|
2671
|
+
store.setState({ trials: [] });
|
|
2672
|
+
store.getState().addTrial({
|
|
2673
|
+
...record,
|
|
2674
|
+
..."state" in seed ? { state: seed.state } : {},
|
|
2675
|
+
..."view" in seed ? { view: seed.view } : {}
|
|
2676
|
+
});
|
|
2677
|
+
records.set(SEED_RECORD, fingerprint);
|
|
2678
|
+
}
|
|
2679
|
+
function seedDefaultTrial(store, instruments, defaultInstrument) {
|
|
2680
|
+
if (store.getState().trials.length > 0) return;
|
|
2681
|
+
const record = addTrial([], instruments, defaultInstrument)[0];
|
|
2682
|
+
if (!record) return;
|
|
2683
|
+
store.getState().addTrial(record);
|
|
2684
|
+
}
|
|
2685
|
+
function openUnstoredLab(options, seed) {
|
|
2686
|
+
const { instruments, defaultInstrument, mode } = options;
|
|
2687
|
+
const store = createLabStore({ initialMode: mode ?? "auto", instruments });
|
|
2688
|
+
const records = createRecordCache({ storage: noneAdapter, prefix: "", writable: false });
|
|
2689
|
+
if (seed) seedPresentedTrial(store, records, options, seed);
|
|
2690
|
+
else seedDefaultTrial(store, instruments, defaultInstrument);
|
|
2691
|
+
return { store, records, close: () => records.close(), marks: /* @__PURE__ */ new Map() };
|
|
2692
|
+
}
|
|
2693
|
+
async function openStoredLab(options, storageKey, storage, seed) {
|
|
2694
|
+
const { instruments, defaultInstrument, mode } = options;
|
|
2695
|
+
const opened = await openLabStore({
|
|
2696
|
+
storageKey,
|
|
2697
|
+
storage: storage ?? await defaultStorage(),
|
|
2698
|
+
initialMode: mode ?? "auto",
|
|
2699
|
+
instruments
|
|
2700
|
+
});
|
|
2701
|
+
if (seed) seedPresentedTrial(opened.store, opened.records, options, seed);
|
|
2702
|
+
else seedDefaultTrial(opened.store, instruments, defaultInstrument);
|
|
2703
|
+
const marks = /* @__PURE__ */ new Map();
|
|
2704
|
+
await Promise.all(
|
|
2705
|
+
opened.store.getState().trials.map(async (trial) => {
|
|
2706
|
+
const kept = instruments.find((i4) => i4.name === trial.instrumentName)?.annotations?.storage;
|
|
2707
|
+
if (!kept) return;
|
|
2708
|
+
try {
|
|
2709
|
+
marks.set(trial.id, await kept.load());
|
|
2710
|
+
} catch (error) {
|
|
2711
|
+
console.warn(`[labkit] could not load the marks of trial "${trial.id}"`, error);
|
|
2712
|
+
marks.set(trial.id, null);
|
|
2713
|
+
}
|
|
2714
|
+
})
|
|
2715
|
+
);
|
|
2716
|
+
return { ...opened, marks };
|
|
2717
|
+
}
|
|
2718
|
+
function useFocusPick(labBody, store, pick) {
|
|
2719
|
+
useEffect(() => {
|
|
2720
|
+
if (!labBody) return;
|
|
2721
|
+
const pickFrom = (node) => {
|
|
2722
|
+
const owned = new Set(store.getState().trials.map((t) => t.id));
|
|
2723
|
+
const nearest = (from) => from?.closest(".lk-trial[data-trial-id]") ?? null;
|
|
2724
|
+
let trial = typeof node?.closest === "function" ? nearest(node) : null;
|
|
2725
|
+
while (trial && !owned.has(trial.dataset.trialId ?? "")) trial = nearest(trial.parentElement);
|
|
2726
|
+
if (trial?.dataset.trialId) pick(trial.dataset.trialId);
|
|
2727
|
+
};
|
|
2728
|
+
const onInput = (event) => pickFrom(event.target);
|
|
2729
|
+
let pending;
|
|
2730
|
+
const doc = labBody.ownerDocument;
|
|
2731
|
+
const win = doc.defaultView;
|
|
2732
|
+
const onBlur = () => {
|
|
2733
|
+
clearTimeout(pending);
|
|
2734
|
+
pending = setTimeout(() => pickFrom(doc.activeElement), 0);
|
|
2735
|
+
};
|
|
2736
|
+
labBody.addEventListener("pointerdown", onInput, true);
|
|
2737
|
+
labBody.addEventListener("focusin", onInput, true);
|
|
2738
|
+
win?.addEventListener("blur", onBlur);
|
|
2739
|
+
return () => {
|
|
2740
|
+
clearTimeout(pending);
|
|
2741
|
+
labBody.removeEventListener("pointerdown", onInput, true);
|
|
2742
|
+
labBody.removeEventListener("focusin", onInput, true);
|
|
2743
|
+
win?.removeEventListener("blur", onBlur);
|
|
2744
|
+
};
|
|
2745
|
+
}, [labBody, store, pick]);
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
// src/lightbox/modal.ts
|
|
2749
|
+
var OWN_DOUBLE_CLICK = [
|
|
2750
|
+
"button",
|
|
2751
|
+
"a[href]",
|
|
2752
|
+
"input",
|
|
2753
|
+
"select",
|
|
2754
|
+
"textarea",
|
|
2755
|
+
"label",
|
|
2756
|
+
"summary",
|
|
2757
|
+
'[contenteditable]:not([contenteditable="false"])',
|
|
2758
|
+
'[role="button"]',
|
|
2759
|
+
'[role="checkbox"]',
|
|
2760
|
+
'[role="combobox"]',
|
|
2761
|
+
'[role="link"]',
|
|
2762
|
+
'[role="menuitem"]',
|
|
2763
|
+
'[role="option"]',
|
|
2764
|
+
'[role="radio"]',
|
|
2765
|
+
'[role="separator"]',
|
|
2766
|
+
'[role="slider"]',
|
|
2767
|
+
'[role="spinbutton"]',
|
|
2768
|
+
'[role="switch"]',
|
|
2769
|
+
'[role="tab"]',
|
|
2770
|
+
'[role="textbox"]',
|
|
2771
|
+
"[data-lk-lightbox-ignore]"
|
|
2772
|
+
].join(",");
|
|
2773
|
+
function opensLightbox(event, root) {
|
|
2774
|
+
if (event.defaultPrevented) return false;
|
|
2775
|
+
const target = event.target;
|
|
2776
|
+
if (!(target instanceof Element)) return true;
|
|
2777
|
+
const owner = target.closest(OWN_DOUBLE_CLICK);
|
|
2778
|
+
return owner === null || !root.contains(owner);
|
|
2779
|
+
}
|
|
2780
|
+
function inertOutside(keep) {
|
|
2781
|
+
const path = /* @__PURE__ */ new Set();
|
|
2782
|
+
for (const el of keep) {
|
|
2783
|
+
for (let node = el; node && node !== document.body; node = node.parentElement) {
|
|
2784
|
+
path.add(node);
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
const marked = [];
|
|
2788
|
+
for (const node of path) {
|
|
2789
|
+
const parent = node.parentElement;
|
|
2790
|
+
if (!parent) continue;
|
|
2791
|
+
for (const sibling of Array.from(parent.children)) {
|
|
2792
|
+
if (path.has(sibling) || sibling.hasAttribute("inert")) continue;
|
|
2793
|
+
sibling.setAttribute("inert", "");
|
|
2794
|
+
marked.push(sibling);
|
|
2795
|
+
}
|
|
2796
|
+
}
|
|
2797
|
+
return () => {
|
|
2798
|
+
for (const sibling of marked) sibling.removeAttribute("inert");
|
|
2799
|
+
};
|
|
2800
|
+
}
|
|
2801
|
+
function liftStack(stack, self) {
|
|
2802
|
+
if (typeof self.showPopover !== "function") return () => {
|
|
2803
|
+
};
|
|
2804
|
+
stack.forEach((el, i4) => {
|
|
2805
|
+
el.setAttribute("popover", "manual");
|
|
2806
|
+
if (el !== self) el.setAttribute("data-lk-lightbox-layer", "");
|
|
2807
|
+
if (i4 === 0) el.setAttribute("data-lk-lightbox-scrim", "");
|
|
2808
|
+
el.showPopover();
|
|
2809
|
+
});
|
|
2810
|
+
return () => {
|
|
2811
|
+
for (const el of [...stack].reverse()) {
|
|
2812
|
+
if (el.matches(":popover-open")) el.hidePopover();
|
|
2813
|
+
el.removeAttribute("popover");
|
|
2814
|
+
el.removeAttribute("data-lk-lightbox-layer");
|
|
2815
|
+
el.removeAttribute("data-lk-lightbox-scrim");
|
|
2816
|
+
}
|
|
2817
|
+
};
|
|
2818
|
+
}
|
|
2819
|
+
function dialogProps(label) {
|
|
2820
|
+
return {
|
|
2821
|
+
role: "dialog",
|
|
2822
|
+
"aria-modal": true,
|
|
2823
|
+
"aria-label": label,
|
|
2824
|
+
"data-wzl-portal-host": ""
|
|
2825
|
+
};
|
|
2826
|
+
}
|
|
2827
|
+
function Lightbox({
|
|
2828
|
+
children,
|
|
2829
|
+
label = "Expanded view",
|
|
2830
|
+
disabled = false,
|
|
2831
|
+
expandOnDoubleClick = false,
|
|
2832
|
+
expanded: expandedProp,
|
|
2833
|
+
onExpandedChange,
|
|
2834
|
+
className
|
|
2835
|
+
}) {
|
|
2836
|
+
const [own, setOwn] = useState(false);
|
|
2837
|
+
const expanded = !disabled && (expandedProp ?? own);
|
|
2838
|
+
const onChangeRef = useLatest(onExpandedChange);
|
|
2839
|
+
const expandedRef = useLatest(expanded);
|
|
2840
|
+
const rootRef = useRef(null);
|
|
2841
|
+
const closeRef = useRef(null);
|
|
2842
|
+
const [claims, setClaims] = useState(0);
|
|
2843
|
+
const layers = useLightboxLayers();
|
|
2844
|
+
const surface = useSurfaceOptional();
|
|
2845
|
+
const set = useCallback(
|
|
2846
|
+
(next) => {
|
|
2847
|
+
if (next === expandedRef.current) return;
|
|
2848
|
+
setOwn(next);
|
|
2849
|
+
onChangeRef.current?.(next);
|
|
2850
|
+
},
|
|
2851
|
+
[expandedRef, onChangeRef]
|
|
2852
|
+
);
|
|
2853
|
+
const ctx = useMemo(
|
|
2854
|
+
() => disabled ? null : {
|
|
2855
|
+
expanded,
|
|
2856
|
+
open: () => set(true),
|
|
2857
|
+
close: () => set(false),
|
|
2858
|
+
toggle: () => set(!expandedRef.current),
|
|
2859
|
+
claimControl: () => {
|
|
2860
|
+
setClaims((n6) => n6 + 1);
|
|
2861
|
+
return () => setClaims((n6) => n6 - 1);
|
|
2862
|
+
}
|
|
2863
|
+
},
|
|
2864
|
+
[disabled, expanded, set, expandedRef]
|
|
2865
|
+
);
|
|
2866
|
+
useLayoutEffect(() => {
|
|
2867
|
+
const el = rootRef.current;
|
|
2868
|
+
if (!expanded || !el) return;
|
|
2869
|
+
const returnTo = document.activeElement;
|
|
2870
|
+
const stack = [...layers.below, el, ...layers.above].filter(
|
|
2871
|
+
(layer) => layer !== null
|
|
2872
|
+
);
|
|
2873
|
+
const unlift = liftStack(stack, el);
|
|
2874
|
+
const release = inertOutside(stack);
|
|
2875
|
+
surface?.scope(el);
|
|
2876
|
+
closeRef.current?.focus({ preventScroll: true });
|
|
2877
|
+
return () => {
|
|
2878
|
+
surface?.scope(null);
|
|
2879
|
+
release();
|
|
2880
|
+
unlift();
|
|
2881
|
+
if (returnTo?.isConnected) returnTo.focus({ preventScroll: true });
|
|
2882
|
+
};
|
|
2883
|
+
}, [expanded, layers, surface]);
|
|
2884
|
+
useEffect(() => {
|
|
2885
|
+
if (!expanded) return;
|
|
2886
|
+
const onKey = (e) => {
|
|
2887
|
+
if (e.key !== "Escape" || e.defaultPrevented) return;
|
|
2888
|
+
e.preventDefault();
|
|
2889
|
+
set(false);
|
|
2890
|
+
};
|
|
2891
|
+
document.addEventListener("keydown", onKey);
|
|
2892
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
2893
|
+
}, [expanded, set]);
|
|
2894
|
+
const onDoubleClick = (e) => {
|
|
2895
|
+
if (disabled || !expandOnDoubleClick || !opensLightbox(e, e.currentTarget)) return;
|
|
2896
|
+
e.preventDefault();
|
|
2897
|
+
set(!expanded);
|
|
2898
|
+
};
|
|
2899
|
+
const onClick = (e) => {
|
|
2900
|
+
if (expanded && e.target === e.currentTarget) set(false);
|
|
2901
|
+
};
|
|
2902
|
+
const classes = ["lk-lightbox"];
|
|
2903
|
+
if (expanded) classes.push("lk-lightbox--expanded");
|
|
2904
|
+
if (className) classes.push(className);
|
|
2905
|
+
let control = null;
|
|
2906
|
+
if (expanded) {
|
|
2907
|
+
control = /* @__PURE__ */ jsx(
|
|
2908
|
+
"button",
|
|
2909
|
+
{
|
|
2910
|
+
ref: closeRef,
|
|
2911
|
+
type: "button",
|
|
2912
|
+
className: "lk-lightbox__button lk-lightbox__close",
|
|
2913
|
+
"aria-label": "Close expanded view",
|
|
2914
|
+
title: "Close (Esc)",
|
|
2915
|
+
onClick: () => set(false),
|
|
2916
|
+
children: /* @__PURE__ */ jsx(V, { size: 16 })
|
|
2917
|
+
}
|
|
2918
|
+
);
|
|
2919
|
+
} else if (!disabled && claims === 0) {
|
|
2920
|
+
control = /* @__PURE__ */ jsx(
|
|
2921
|
+
"button",
|
|
2922
|
+
{
|
|
2923
|
+
type: "button",
|
|
2924
|
+
className: "lk-lightbox__button lk-lightbox__open",
|
|
2925
|
+
"aria-label": "Expand",
|
|
2926
|
+
title: "Expand",
|
|
2927
|
+
onClick: () => set(true),
|
|
2928
|
+
children: /* @__PURE__ */ jsx(de, { size: 16 })
|
|
2929
|
+
}
|
|
2930
|
+
);
|
|
2931
|
+
}
|
|
2932
|
+
return /* @__PURE__ */ jsx(LightboxContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxs(
|
|
2933
|
+
"div",
|
|
2934
|
+
{
|
|
2935
|
+
ref: rootRef,
|
|
2936
|
+
className: classes.join(" "),
|
|
2937
|
+
...expanded ? dialogProps(label) : null,
|
|
2938
|
+
onDoubleClick,
|
|
2939
|
+
onClick,
|
|
2940
|
+
children: [
|
|
2941
|
+
/* @__PURE__ */ jsx("div", { className: "lk-lightbox__frame", children }),
|
|
2942
|
+
control
|
|
2943
|
+
]
|
|
2944
|
+
}
|
|
2945
|
+
) });
|
|
2946
|
+
}
|
|
2232
2947
|
var ZONE_ID = asNodeId("lk-workspace");
|
|
2233
2948
|
var STRATEGIES = { grid: gridStrategy, floating: floatingStrategy };
|
|
2234
2949
|
var FLOAT_ZONE_ID = asNodeId("lk-workspace-floating");
|
|
@@ -2253,11 +2968,11 @@ function createWorkspaceStore(grid) {
|
|
|
2253
2968
|
return store;
|
|
2254
2969
|
}
|
|
2255
2970
|
function extentOf(store, id) {
|
|
2256
|
-
const
|
|
2257
|
-
if (!
|
|
2971
|
+
const p5 = store.getNode(id)?.membership?.placement;
|
|
2972
|
+
if (!p5) return null;
|
|
2258
2973
|
const out = {};
|
|
2259
|
-
if (
|
|
2260
|
-
if (
|
|
2974
|
+
if (p5.size) out.size = p5.size;
|
|
2975
|
+
if (p5.span) out.span = p5.span;
|
|
2261
2976
|
return Object.keys(out).length > 0 ? out : null;
|
|
2262
2977
|
}
|
|
2263
2978
|
function PanelFrame({ panel, floating = false }) {
|
|
@@ -2275,14 +2990,16 @@ function Workspace({
|
|
|
2275
2990
|
onLayoutChange,
|
|
2276
2991
|
gap = 12,
|
|
2277
2992
|
padding = 0,
|
|
2278
|
-
viewport
|
|
2993
|
+
viewport,
|
|
2994
|
+
lightbox = true,
|
|
2995
|
+
expandOnDoubleClick = false
|
|
2279
2996
|
}) {
|
|
2280
2997
|
const items = Children.toArray(children);
|
|
2281
|
-
const tilePanels = useMemo(() => (panels ?? []).filter((
|
|
2282
|
-
const floatPanels = useMemo(() => (panels ?? []).filter((
|
|
2998
|
+
const tilePanels = useMemo(() => (panels ?? []).filter((p5) => p5.as === "tile"), [panels]);
|
|
2999
|
+
const floatPanels = useMemo(() => (panels ?? []).filter((p5) => p5.as === "floating"), [panels]);
|
|
2283
3000
|
const idKey = JSON.stringify([
|
|
2284
3001
|
...items.map((_2, i4) => ids?.[i4] ?? `lk-ws-${i4}`),
|
|
2285
|
-
...tilePanels.map((
|
|
3002
|
+
...tilePanels.map((p5) => `lk-panel-${p5.key}`)
|
|
2286
3003
|
]);
|
|
2287
3004
|
const nodeIds = useMemo(() => JSON.parse(idKey).map(asNodeId), [idKey]);
|
|
2288
3005
|
const layoutRef = useLatest(layout);
|
|
@@ -2332,9 +3049,11 @@ function Workspace({
|
|
|
2332
3049
|
[onReorder]
|
|
2333
3050
|
);
|
|
2334
3051
|
const chrome = useMemo(() => {
|
|
3052
|
+
const lightboxFor = typeof lightbox === "function" ? lightbox : () => lightbox;
|
|
3053
|
+
const doubleClickFor = typeof expandOnDoubleClick === "function" ? expandOnDoubleClick : () => expandOnDoubleClick;
|
|
2335
3054
|
const byId = new Map(nodeIds.map((id, i4) => [id, items[i4]]));
|
|
2336
3055
|
const panelByNode = new Map(
|
|
2337
|
-
tilePanels.map((
|
|
3056
|
+
tilePanels.map((p5) => [`lk-panel-${p5.key}`, p5])
|
|
2338
3057
|
);
|
|
2339
3058
|
return {
|
|
2340
3059
|
[PANEL_KIND]: ({ node }) => {
|
|
@@ -2343,16 +3062,29 @@ function Workspace({
|
|
|
2343
3062
|
return /* @__PURE__ */ jsx(PanelFrame, { panel });
|
|
2344
3063
|
},
|
|
2345
3064
|
[KIND]: ({ node }) => {
|
|
2346
|
-
const
|
|
2347
|
-
|
|
3065
|
+
const id = String(node.id);
|
|
3066
|
+
const tile = (
|
|
3067
|
+
// `disabled` rather than leaving the wrapper out, so turning the
|
|
3068
|
+
// lightbox off cannot remount the tile.
|
|
3069
|
+
/* @__PURE__ */ jsx(
|
|
3070
|
+
Lightbox,
|
|
3071
|
+
{
|
|
3072
|
+
className: "lk-trial-tile",
|
|
3073
|
+
disabled: !lightboxFor(id),
|
|
3074
|
+
expandOnDoubleClick: doubleClickFor(id),
|
|
3075
|
+
children: byId.get(node.id) ?? null
|
|
3076
|
+
}
|
|
3077
|
+
)
|
|
3078
|
+
);
|
|
3079
|
+
if (!reorderable) return tile;
|
|
2348
3080
|
return (
|
|
2349
3081
|
// No grip strip: the trial's own title bar is the drag surface.
|
|
2350
|
-
/* @__PURE__ */ jsx(TrialDragContext.Provider, { value: { nodeId: node.id }, children:
|
|
3082
|
+
/* @__PURE__ */ jsx(TrialDragContext.Provider, { value: { nodeId: node.id }, children: tile })
|
|
2351
3083
|
);
|
|
2352
3084
|
}
|
|
2353
3085
|
};
|
|
2354
|
-
}, [nodeIds, items, reorderable, tilePanels]);
|
|
2355
|
-
const floatingLayer = floatPanels.length === 0 ? null : /* @__PURE__ */ jsx("div", { className: "lk-workspace__floating", children: floatPanels.map((
|
|
3086
|
+
}, [nodeIds, items, reorderable, tilePanels, lightbox, expandOnDoubleClick]);
|
|
3087
|
+
const floatingLayer = floatPanels.length === 0 ? null : /* @__PURE__ */ jsx("div", { className: "lk-workspace__floating", children: floatPanels.map((p5) => /* @__PURE__ */ jsx(PanelFrame, { panel: p5, floating: true }, p5.key)) });
|
|
2356
3088
|
const grid = /* @__PURE__ */ jsx(
|
|
2357
3089
|
Container,
|
|
2358
3090
|
{
|
|
@@ -2374,42 +3106,6 @@ function Workspace({
|
|
|
2374
3106
|
] })
|
|
2375
3107
|
) : reorderable ? /* @__PURE__ */ jsx(DragProvider, { children: grid }) : grid }) });
|
|
2376
3108
|
}
|
|
2377
|
-
function seedDefaultTrial(store, instruments, defaultInstrument) {
|
|
2378
|
-
if (store.getState().trials.length > 0) return;
|
|
2379
|
-
const record = addTrial([], instruments, defaultInstrument)[0];
|
|
2380
|
-
if (!record) return;
|
|
2381
|
-
const { undoStack: _undoStack, ...rest } = record;
|
|
2382
|
-
store.getState().addTrial(rest);
|
|
2383
|
-
}
|
|
2384
|
-
function openUnstoredLab({ instruments, defaultInstrument, mode }) {
|
|
2385
|
-
const store = createLabStore({ initialMode: mode ?? "auto", instruments });
|
|
2386
|
-
seedDefaultTrial(store, instruments, defaultInstrument);
|
|
2387
|
-
const records = createRecordCache({ storage: noneAdapter, prefix: "", writable: false });
|
|
2388
|
-
return { store, records, close: () => records.close(), marks: /* @__PURE__ */ new Map() };
|
|
2389
|
-
}
|
|
2390
|
-
async function openStoredLab({ instruments, defaultInstrument, mode }, storageKey, storage) {
|
|
2391
|
-
const opened = await openLabStore({
|
|
2392
|
-
storageKey,
|
|
2393
|
-
storage: storage ?? await defaultStorage(),
|
|
2394
|
-
initialMode: mode ?? "auto",
|
|
2395
|
-
instruments
|
|
2396
|
-
});
|
|
2397
|
-
seedDefaultTrial(opened.store, instruments, defaultInstrument);
|
|
2398
|
-
const marks = /* @__PURE__ */ new Map();
|
|
2399
|
-
await Promise.all(
|
|
2400
|
-
opened.store.getState().trials.map(async (trial) => {
|
|
2401
|
-
const kept = instruments.find((i4) => i4.name === trial.instrumentName)?.annotations?.storage;
|
|
2402
|
-
if (!kept) return;
|
|
2403
|
-
try {
|
|
2404
|
-
marks.set(trial.id, await kept.load());
|
|
2405
|
-
} catch (error) {
|
|
2406
|
-
console.warn(`[labkit] could not load the marks of trial "${trial.id}"`, error);
|
|
2407
|
-
marks.set(trial.id, null);
|
|
2408
|
-
}
|
|
2409
|
-
})
|
|
2410
|
-
);
|
|
2411
|
-
return { ...opened, marks };
|
|
2412
|
-
}
|
|
2413
3109
|
function LabFallback({
|
|
2414
3110
|
title,
|
|
2415
3111
|
mode,
|
|
@@ -2438,24 +3134,6 @@ function LabFallback({
|
|
|
2438
3134
|
}
|
|
2439
3135
|
);
|
|
2440
3136
|
}
|
|
2441
|
-
var NEBULA_SLOTS = [
|
|
2442
|
-
{ cx: "18%", cy: "30%", sx: "60%", sy: "80%", stop: "70%" },
|
|
2443
|
-
{ cx: "78%", cy: "70%", sx: "55%", sy: "90%", stop: "65%" },
|
|
2444
|
-
{ cx: "50%", cy: "50%", sx: "50%", sy: "70%", stop: "75%" },
|
|
2445
|
-
{ cx: "12%", cy: "82%", sx: "50%", sy: "70%", stop: "70%" },
|
|
2446
|
-
{ cx: "85%", cy: "18%", sx: "55%", sy: "80%", stop: "70%" }
|
|
2447
|
-
];
|
|
2448
|
-
function buildNebula(list, theme, mode, density) {
|
|
2449
|
-
const ctx = { theme, resolved: resolveTheme(theme, { mode, density }) };
|
|
2450
|
-
const n6 = colorCount(list, ctx) ?? NEBULA_SLOTS.length;
|
|
2451
|
-
const colors = Array.from({ length: n6 }, (_2, i4) => colorAt(list, i4, ctx));
|
|
2452
|
-
const blobs = colors.map((c7, i4) => {
|
|
2453
|
-
const p4 = NEBULA_SLOTS[i4 % NEBULA_SLOTS.length];
|
|
2454
|
-
return `radial-gradient(ellipse ${p4.sx} ${p4.sy} at ${p4.cx} ${p4.cy}, color-mix(in srgb, ${c7} 22%, transparent), transparent ${p4.stop})`;
|
|
2455
|
-
});
|
|
2456
|
-
blobs.push("radial-gradient(ellipse at center, #0a0a18 0%, #02020a 100%)");
|
|
2457
|
-
return blobs.join(", ");
|
|
2458
|
-
}
|
|
2459
3137
|
function LabPanes({
|
|
2460
3138
|
contributions,
|
|
2461
3139
|
children
|
|
@@ -2471,7 +3149,7 @@ function LabPanes({
|
|
|
2471
3149
|
void 0,
|
|
2472
3150
|
{ scope: "lab" }
|
|
2473
3151
|
);
|
|
2474
|
-
const main = contributions.some((
|
|
3152
|
+
const main = contributions.some((c6) => c6.region === "aside") ? /* @__PURE__ */ jsx(
|
|
2475
3153
|
Split,
|
|
2476
3154
|
{
|
|
2477
3155
|
className: "lk-lab__panes",
|
|
@@ -2481,15 +3159,15 @@ function LabPanes({
|
|
|
2481
3159
|
label: "Lab aside",
|
|
2482
3160
|
defaultWidth: 320,
|
|
2483
3161
|
width: asideWidth,
|
|
2484
|
-
onWidthChange: (
|
|
2485
|
-
setAsideWidth(
|
|
3162
|
+
onWidthChange: (w3) => {
|
|
3163
|
+
setAsideWidth(w3);
|
|
2486
3164
|
surface?.invalidateRects();
|
|
2487
3165
|
},
|
|
2488
3166
|
sidebar: /* @__PURE__ */ jsx(LabAsideRegion, { contributions }),
|
|
2489
3167
|
children
|
|
2490
3168
|
}
|
|
2491
3169
|
) : children;
|
|
2492
|
-
if (!contributions.some((
|
|
3170
|
+
if (!contributions.some((c6) => c6.region === "sidebar")) return main;
|
|
2493
3171
|
return /* @__PURE__ */ jsx(
|
|
2494
3172
|
Split,
|
|
2495
3173
|
{
|
|
@@ -2499,8 +3177,8 @@ function LabPanes({
|
|
|
2499
3177
|
label: "Lab sidebar",
|
|
2500
3178
|
defaultWidth: 260,
|
|
2501
3179
|
width: sidebarWidth,
|
|
2502
|
-
onWidthChange: (
|
|
2503
|
-
setSidebarWidth(
|
|
3180
|
+
onWidthChange: (w3) => {
|
|
3181
|
+
setSidebarWidth(w3);
|
|
2504
3182
|
surface?.invalidateRects();
|
|
2505
3183
|
},
|
|
2506
3184
|
sidebar: /* @__PURE__ */ jsx(LabSidebarRegion, { contributions }),
|
|
@@ -2512,13 +3190,21 @@ function Lab(props) {
|
|
|
2512
3190
|
if (process.env.NODE_ENV !== "production" && props.instruments.length === 0) {
|
|
2513
3191
|
throw new Error("[labkit] <Lab> requires a non-empty `instruments` array");
|
|
2514
3192
|
}
|
|
2515
|
-
const { storageKey, storage } = props;
|
|
2516
|
-
useWarnIgnoredChange("<Lab>", { storageKey, storage });
|
|
2517
|
-
const
|
|
2518
|
-
|
|
2519
|
-
|
|
3193
|
+
const { storageKey, storage, present } = props;
|
|
3194
|
+
useWarnIgnoredChange("<Lab>", { storageKey, storage, present });
|
|
3195
|
+
const [startsPresenting] = useState(() => present === true || hasPresentParam());
|
|
3196
|
+
if (process.env.NODE_ENV !== "production" && props.seed && !startsPresenting) {
|
|
3197
|
+
warnSeedIgnored();
|
|
3198
|
+
}
|
|
3199
|
+
const opened = useOpenOnce(() => {
|
|
3200
|
+
const seed = startsPresenting ? props.seed ?? {} : void 0;
|
|
3201
|
+
if (storageKey === void 0) return openUnstoredLab(props, seed);
|
|
3202
|
+
const key = startsPresenting ? presentStorageKey(storageKey) : storageKey;
|
|
3203
|
+
return openStoredLab(props, key, storage, seed);
|
|
3204
|
+
});
|
|
2520
3205
|
if (!opened) {
|
|
2521
3206
|
if (props.fallback !== void 0) return props.fallback;
|
|
3207
|
+
if (startsPresenting) return null;
|
|
2522
3208
|
return /* @__PURE__ */ jsx(
|
|
2523
3209
|
LabFallback,
|
|
2524
3210
|
{
|
|
@@ -2531,7 +3217,13 @@ function Lab(props) {
|
|
|
2531
3217
|
}
|
|
2532
3218
|
);
|
|
2533
3219
|
}
|
|
2534
|
-
return /* @__PURE__ */ jsx(LabRuntime, { ...props, opened });
|
|
3220
|
+
return /* @__PURE__ */ jsx(LabRuntime, { ...props, opened, startsPresenting });
|
|
3221
|
+
}
|
|
3222
|
+
var seedWarned = false;
|
|
3223
|
+
function warnSeedIgnored() {
|
|
3224
|
+
if (seedWarned) return;
|
|
3225
|
+
seedWarned = true;
|
|
3226
|
+
console.warn("[labkit] <Lab> reads `seed` only when it starts presenting; it is ignored here");
|
|
2535
3227
|
}
|
|
2536
3228
|
function LabRuntime({
|
|
2537
3229
|
instruments,
|
|
@@ -2546,100 +3238,58 @@ function LabRuntime({
|
|
|
2546
3238
|
chrome,
|
|
2547
3239
|
labChrome,
|
|
2548
3240
|
suppress,
|
|
3241
|
+
expandOnDoubleClick = false,
|
|
2549
3242
|
addTrial: addTrial2,
|
|
2550
3243
|
zoom = true,
|
|
2551
3244
|
tools,
|
|
2552
3245
|
configRules,
|
|
2553
3246
|
controls,
|
|
2554
3247
|
children,
|
|
2555
|
-
opened
|
|
3248
|
+
opened,
|
|
3249
|
+
startsPresenting
|
|
2556
3250
|
}) {
|
|
2557
3251
|
const { store } = opened;
|
|
2558
3252
|
useLayoutEffect(() => {
|
|
2559
3253
|
store.getState().setInstruments(instruments);
|
|
2560
3254
|
}, [instruments, store]);
|
|
2561
|
-
const trials = useStore(store, (
|
|
3255
|
+
const trials = useStore(store, (s4) => s4.trials);
|
|
2562
3256
|
const [cameras] = useState(createCameraRegistry);
|
|
3257
|
+
const [clocks] = useState(createClockRegistry);
|
|
3258
|
+
useClockLoop(clocks);
|
|
2563
3259
|
const [focusPick, setFocusPick] = useState(null);
|
|
2564
3260
|
const focusedTrialId = trials.some((t) => t.id === focusPick) ? focusPick : trials[0]?.id ?? null;
|
|
2565
|
-
const
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
const
|
|
3261
|
+
const [presentedBy, setPresentedBy] = useState(
|
|
3262
|
+
startsPresenting ? "mount" : null
|
|
3263
|
+
);
|
|
3264
|
+
const presenting = presentedBy !== null;
|
|
3265
|
+
const presentation = useMemo(
|
|
3266
|
+
() => ({
|
|
3267
|
+
active: presenting,
|
|
3268
|
+
enter: () => setPresentedBy((by) => by ?? "enter"),
|
|
3269
|
+
exit: () => setPresentedBy(null),
|
|
3270
|
+
trialId: presenting ? focusedTrialId : null
|
|
3271
|
+
}),
|
|
3272
|
+
[presenting, focusedTrialId]
|
|
3273
|
+
);
|
|
3274
|
+
const savedSnapshots = useStore(store, (s4) => s4.savedSnapshots);
|
|
3275
|
+
const modeValue = useStore(store, (s4) => s4.mode);
|
|
3276
|
+
const layout = useStore(store, (s4) => s4.layout);
|
|
3277
|
+
const undockedPanels = useStore(store, (s4) => s4.undockedPanels);
|
|
2569
3278
|
const panelHostsRef = useRef(null);
|
|
2570
3279
|
if (panelHostsRef.current === null) panelHostsRef.current = createPanelHostRegistry();
|
|
2571
|
-
const outerSurface = useSurfaceOptional();
|
|
2572
|
-
const outerOver = useSurfaceCanvas("over");
|
|
2573
|
-
const outerUnder = useSurfaceCanvas("under");
|
|
2574
|
-
const [ownOver, setOwnOver] = useState(null);
|
|
2575
|
-
const [ownUnder, setOwnUnder] = useState(null);
|
|
2576
|
-
const ownOverRef = useRef(null);
|
|
2577
|
-
const ownUnderRef = useRef(null);
|
|
2578
|
-
const bufferRef = useRef({ w: 0, h: 0 });
|
|
2579
|
-
const surfaceRef = useRef(null);
|
|
2580
|
-
const onFrame = useCallback((frame) => {
|
|
2581
|
-
const canvases = [ownUnderRef.current, ownOverRef.current].filter((c7) => c7 !== null);
|
|
2582
|
-
if (canvases.length === 0) return;
|
|
2583
|
-
const w2 = Math.round(frame.size.width * frame.dpr);
|
|
2584
|
-
const h2 = Math.round(frame.size.height * frame.dpr);
|
|
2585
|
-
if (bufferRef.current.w !== w2 || bufferRef.current.h !== h2) {
|
|
2586
|
-
bufferRef.current = { w: w2, h: h2 };
|
|
2587
|
-
for (const c7 of canvases) {
|
|
2588
|
-
c7.width = w2;
|
|
2589
|
-
c7.height = h2;
|
|
2590
|
-
c7.style.width = `${frame.size.width}px`;
|
|
2591
|
-
c7.style.height = `${frame.size.height}px`;
|
|
2592
|
-
}
|
|
2593
|
-
surfaceRef.current?.invalidateAll();
|
|
2594
|
-
return;
|
|
2595
|
-
}
|
|
2596
|
-
}, []);
|
|
2597
|
-
const ownSurface = useTiledSurface({ onFrame });
|
|
2598
|
-
useInsertionEffect(() => {
|
|
2599
|
-
surfaceRef.current = ownSurface;
|
|
2600
|
-
}, [ownSurface]);
|
|
2601
3280
|
const [labBody, setLabBody] = useState(null);
|
|
2602
|
-
const attachOwnSurface = ownSurface.containerRef;
|
|
2603
|
-
const labBodyRef = useCallback(
|
|
2604
|
-
(el) => {
|
|
2605
|
-
setLabBody(el);
|
|
2606
|
-
if (!outerSurface) attachOwnSurface(el);
|
|
2607
|
-
},
|
|
2608
|
-
[outerSurface, attachOwnSurface]
|
|
2609
|
-
);
|
|
2610
3281
|
useLabFitWarning(labBody);
|
|
3282
|
+
useFocusPick(labBody, store, setFocusPick);
|
|
2611
3283
|
useEffect(() => {
|
|
2612
|
-
if (!labBody) return;
|
|
2613
|
-
const pick = (node) => {
|
|
2614
|
-
const owned = new Set(store.getState().trials.map((t) => t.id));
|
|
2615
|
-
const nearest = (from) => from?.closest(".lk-trial[data-trial-id]") ?? null;
|
|
2616
|
-
let trial = typeof node?.closest === "function" ? nearest(node) : null;
|
|
2617
|
-
while (trial && !owned.has(trial.dataset.trialId ?? "")) trial = nearest(trial.parentElement);
|
|
2618
|
-
if (trial?.dataset.trialId) setFocusPick(trial.dataset.trialId);
|
|
2619
|
-
};
|
|
2620
|
-
const onInput = (event) => pick(event.target);
|
|
2621
|
-
let pending;
|
|
3284
|
+
if (presentedBy !== "enter" || !labBody) return;
|
|
2622
3285
|
const doc = labBody.ownerDocument;
|
|
2623
|
-
const
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
pending = setTimeout(() => pick(doc.activeElement), 0);
|
|
2627
|
-
};
|
|
2628
|
-
labBody.addEventListener("pointerdown", onInput, true);
|
|
2629
|
-
labBody.addEventListener("focusin", onInput, true);
|
|
2630
|
-
win?.addEventListener("blur", onBlur);
|
|
2631
|
-
return () => {
|
|
2632
|
-
clearTimeout(pending);
|
|
2633
|
-
labBody.removeEventListener("pointerdown", onInput, true);
|
|
2634
|
-
labBody.removeEventListener("focusin", onInput, true);
|
|
2635
|
-
win?.removeEventListener("blur", onBlur);
|
|
3286
|
+
const onKeyDown = (event) => {
|
|
3287
|
+
if (event.key !== "Escape" || event.defaultPrevented) return;
|
|
3288
|
+
setPresentedBy(null);
|
|
2636
3289
|
};
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
() => outerSurface ? { over: outerOver, under: outerUnder } : { over: ownOver, under: ownUnder },
|
|
2641
|
-
[outerSurface, outerOver, outerUnder, ownOver, ownUnder]
|
|
2642
|
-
);
|
|
3290
|
+
doc.addEventListener("keydown", onKeyDown);
|
|
3291
|
+
return () => doc.removeEventListener("keydown", onKeyDown);
|
|
3292
|
+
}, [presentedBy, labBody]);
|
|
2643
3293
|
const workspacePanels = useMemo(
|
|
2644
3294
|
() => Object.entries(undockedPanels).map(([key, panel]) => ({
|
|
2645
3295
|
key,
|
|
@@ -2654,8 +3304,8 @@ function LabRuntime({
|
|
|
2654
3304
|
() => labContributions([...annotationTools, ...tools ?? []], labChrome),
|
|
2655
3305
|
[annotationTools, tools, labChrome]
|
|
2656
3306
|
);
|
|
2657
|
-
const hasFooterChrome = labChromeAll.some((
|
|
2658
|
-
const hasPaneChrome = labChromeAll.some((
|
|
3307
|
+
const hasFooterChrome = labChromeAll.some((c6) => c6.region === "footer");
|
|
3308
|
+
const hasPaneChrome = labChromeAll.some((c6) => c6.region === "sidebar" || c6.region === "aside");
|
|
2659
3309
|
useEffect(() => {
|
|
2660
3310
|
if (mode && mode !== store.getState().mode) {
|
|
2661
3311
|
store.getState().setMode(mode);
|
|
@@ -2663,14 +3313,14 @@ function LabRuntime({
|
|
|
2663
3313
|
}, [mode, store]);
|
|
2664
3314
|
const contextValue = useMemo(() => {
|
|
2665
3315
|
const replaceTrials = (next) => {
|
|
2666
|
-
const currentById = new Map(store.getState().trials.map((
|
|
2667
|
-
const merged = next.map((
|
|
3316
|
+
const currentById = new Map(store.getState().trials.map((w3) => [w3.id, w3]));
|
|
3317
|
+
const merged = next.map((w3) => currentById.get(w3.id) ?? w3);
|
|
2668
3318
|
store.setState({ trials: merged });
|
|
2669
3319
|
};
|
|
2670
3320
|
const replaceAndFocusAdded = (next) => {
|
|
2671
|
-
const before = new Set(store.getState().trials.map((
|
|
3321
|
+
const before = new Set(store.getState().trials.map((w3) => w3.id));
|
|
2672
3322
|
replaceTrials(next);
|
|
2673
|
-
const added = next.find((
|
|
3323
|
+
const added = next.find((w3) => !before.has(w3.id));
|
|
2674
3324
|
if (added) setFocusPick(added.id);
|
|
2675
3325
|
};
|
|
2676
3326
|
return {
|
|
@@ -2695,7 +3345,7 @@ function LabRuntime({
|
|
|
2695
3345
|
const current = store.getState();
|
|
2696
3346
|
const next = swapTrial(current.trials, instruments, id, instrumentName, options);
|
|
2697
3347
|
if (next === current.trials) return;
|
|
2698
|
-
const record = next[current.trials.findIndex((
|
|
3348
|
+
const record = next[current.trials.findIndex((w3) => w3.id === id)];
|
|
2699
3349
|
const { [id]: extent, ...layoutRest } = current.layout;
|
|
2700
3350
|
if (extent) current.setLayout({ ...layoutRest, [record.id]: extent });
|
|
2701
3351
|
replaceTrials(next);
|
|
@@ -2705,17 +3355,18 @@ function LabRuntime({
|
|
|
2705
3355
|
focusTrial: (id) => setFocusPick(id),
|
|
2706
3356
|
resetTrial: (id) => {
|
|
2707
3357
|
const next = resetTrial(store.getState().trials, id, instruments);
|
|
2708
|
-
const record = next.find((
|
|
3358
|
+
const record = next.find((w3) => w3.id === id);
|
|
2709
3359
|
if (!record) return;
|
|
2710
|
-
store.setState((
|
|
2711
|
-
trials:
|
|
2712
|
-
(
|
|
3360
|
+
store.setState((s4) => ({
|
|
3361
|
+
trials: s4.trials.map(
|
|
3362
|
+
(w3) => w3.id === id ? { ...w3, config: record.config, state: record.state, view: record.view } : w3
|
|
2713
3363
|
)
|
|
2714
3364
|
}));
|
|
3365
|
+
clocks.get(id)?.reset();
|
|
2715
3366
|
},
|
|
2716
3367
|
savedSnapshots,
|
|
2717
3368
|
saveSnapshot: (trialId, name) => {
|
|
2718
|
-
const taken = store.getState().savedSnapshots.filter((
|
|
3369
|
+
const taken = store.getState().savedSnapshots.filter((s4) => s4.trialId === trialId).length;
|
|
2719
3370
|
store.getState().saveSnapshot(trialId, name ?? `Snapshot ${taken + 1}`);
|
|
2720
3371
|
},
|
|
2721
3372
|
loadSnapshot: (trialId, snapshotId) => {
|
|
@@ -2732,6 +3383,7 @@ function LabRuntime({
|
|
|
2732
3383
|
controls
|
|
2733
3384
|
};
|
|
2734
3385
|
}, [
|
|
3386
|
+
clocks,
|
|
2735
3387
|
instruments,
|
|
2736
3388
|
trials,
|
|
2737
3389
|
focusedTrialId,
|
|
@@ -2753,21 +3405,25 @@ function LabRuntime({
|
|
|
2753
3405
|
Workspace,
|
|
2754
3406
|
{
|
|
2755
3407
|
panels: workspacePanels,
|
|
2756
|
-
ids: trials.map((
|
|
3408
|
+
ids: trials.map((w3) => w3.id),
|
|
2757
3409
|
resizable: true,
|
|
2758
3410
|
reorderable: true,
|
|
2759
3411
|
onReorder: (ids) => contextValue.reorderTrials(ids),
|
|
2760
3412
|
layout,
|
|
2761
3413
|
onLayoutChange: (next) => store.getState().setLayout(next),
|
|
2762
|
-
|
|
3414
|
+
expandOnDoubleClick: typeof expandOnDoubleClick === "function" ? (id) => {
|
|
3415
|
+
const trial = trials.find((t) => t.id === id);
|
|
3416
|
+
return trial ? expandOnDoubleClick(trial) : false;
|
|
3417
|
+
} : expandOnDoubleClick,
|
|
3418
|
+
children: trials.map((w3) => /* @__PURE__ */ jsx(Trial, { id: w3.id, chrome, suppress }, w3.id))
|
|
2763
3419
|
}
|
|
2764
3420
|
);
|
|
2765
|
-
return /* @__PURE__ */ jsx(LabStoreContext.Provider, { value: { store }, children: /* @__PURE__ */ jsx(PersistenceContext.Provider, { value: opened.records, children: /* @__PURE__ */ jsx(AnnotationPreloadContext.Provider, { value: opened.marks, children: /* @__PURE__ */ jsx(LabContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(CameraRegistryContext.Provider, { value: cameras, children: /* @__PURE__ */ jsx(
|
|
3421
|
+
return /* @__PURE__ */ jsx(LabStoreContext.Provider, { value: { store }, children: /* @__PURE__ */ jsx(PersistenceContext.Provider, { value: opened.records, children: /* @__PURE__ */ jsx(AnnotationPreloadContext.Provider, { value: opened.marks, children: /* @__PURE__ */ jsx(LabContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(PresentationContext.Provider, { value: presentation, children: /* @__PURE__ */ jsx(CameraRegistryContext.Provider, { value: cameras, children: /* @__PURE__ */ jsx(ClockRegistryContext.Provider, { value: clocks, children: /* @__PURE__ */ jsx(
|
|
2766
3422
|
ThemeProvider,
|
|
2767
3423
|
{
|
|
2768
3424
|
theme,
|
|
2769
3425
|
selection: { mode: resolvedMode, density: density ?? "comfortable" },
|
|
2770
|
-
className: "lk-lab",
|
|
3426
|
+
className: presenting ? "lk-lab lk-lab--present" : "lk-lab",
|
|
2771
3427
|
style: backdropStyle,
|
|
2772
3428
|
children: /* @__PURE__ */ jsx(
|
|
2773
3429
|
LabShell,
|
|
@@ -2782,53 +3438,22 @@ function LabRuntime({
|
|
|
2782
3438
|
] }) : footer,
|
|
2783
3439
|
header: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2784
3440
|
/* @__PURE__ */ jsx(LabHeader, { ...addTrial2 !== void 0 ? { addTrial: addTrial2 } : {} }),
|
|
2785
|
-
zoom ? /* @__PURE__ */ jsx(LabZoom, {}) : null,
|
|
3441
|
+
zoom && !presenting ? /* @__PURE__ */ jsx(LabZoom, {}) : null,
|
|
2786
3442
|
children,
|
|
2787
3443
|
/* @__PURE__ */ jsx(LabHeaderRegion, { contributions: labChromeAll }),
|
|
2788
3444
|
/* @__PURE__ */ jsx(LabThemeSwitcher, {})
|
|
2789
3445
|
] }),
|
|
2790
|
-
children: /* @__PURE__ */ jsx(PanelHostContext.Provider, { value: panelHostsRef.current, children: /* @__PURE__ */ jsx(
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2798
|
-
/* @__PURE__ */ jsx(
|
|
2799
|
-
"canvas",
|
|
2800
|
-
{
|
|
2801
|
-
className: "lk-lab__surface lk-lab__surface--under",
|
|
2802
|
-
ref: (el) => {
|
|
2803
|
-
ownUnderRef.current = el;
|
|
2804
|
-
setOwnUnder(el);
|
|
2805
|
-
}
|
|
2806
|
-
}
|
|
2807
|
-
),
|
|
2808
|
-
/* @__PURE__ */ jsx(
|
|
2809
|
-
"canvas",
|
|
2810
|
-
{
|
|
2811
|
-
className: "lk-lab__surface lk-lab__surface--over",
|
|
2812
|
-
ref: (el) => {
|
|
2813
|
-
ownOverRef.current = el;
|
|
2814
|
-
setOwnOver(el);
|
|
2815
|
-
}
|
|
2816
|
-
}
|
|
2817
|
-
)
|
|
2818
|
-
] })
|
|
2819
|
-
),
|
|
2820
|
-
hasPaneChrome ? /* @__PURE__ */ jsxs(LabPanes, { contributions: labChromeAll, children: [
|
|
2821
|
-
/* @__PURE__ */ jsx(LabPalette, { contributions: labChromeAll }),
|
|
2822
|
-
workspace
|
|
2823
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2824
|
-
/* @__PURE__ */ jsx(LabPalette, { contributions: labChromeAll }),
|
|
2825
|
-
workspace
|
|
2826
|
-
] })
|
|
2827
|
-
] }) }) }) })
|
|
3446
|
+
children: /* @__PURE__ */ jsx(PanelHostContext.Provider, { value: panelHostsRef.current, children: /* @__PURE__ */ jsx(LabSurface, { bodyRef: setLabBody, children: hasPaneChrome ? /* @__PURE__ */ jsxs(LabPanes, { contributions: labChromeAll, children: [
|
|
3447
|
+
/* @__PURE__ */ jsx(LabPalette, { contributions: labChromeAll }),
|
|
3448
|
+
workspace
|
|
3449
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3450
|
+
/* @__PURE__ */ jsx(LabPalette, { contributions: labChromeAll }),
|
|
3451
|
+
workspace
|
|
3452
|
+
] }) }) })
|
|
2828
3453
|
}
|
|
2829
3454
|
)
|
|
2830
3455
|
}
|
|
2831
|
-
) }) }) }) }) });
|
|
3456
|
+
) }) }) }) }) }) }) });
|
|
2832
3457
|
}
|
|
2833
3458
|
function LabBoundary({ children }) {
|
|
2834
3459
|
return /* @__PURE__ */ jsx(LabStoreContext.Provider, { value: null, children: /* @__PURE__ */ jsx(PersistenceContext.Provider, { value: null, children: /* @__PURE__ */ jsx(AnnotationPreloadContext.Provider, { value: null, children: /* @__PURE__ */ jsx(LabContext.Provider, { value: null, children: /* @__PURE__ */ jsx(PanelHostContext.Provider, { value: null, children: /* @__PURE__ */ jsx(SurfaceContext.Provider, { value: null, children: /* @__PURE__ */ jsx(SurfaceCanvasContext.Provider, { value: { over: null, under: null }, children: /* @__PURE__ */ jsx(TrialIdContext.Provider, { value: null, children: /* @__PURE__ */ jsx(AnnotationsContext.Provider, { value: null, children: /* @__PURE__ */ jsx(CameraWheelContext.Provider, { value: null, children: /* @__PURE__ */ jsx(CanvasStackContext.Provider, { value: null, children: /* @__PURE__ */ jsx(TrialDragContext.Provider, { value: null, children: /* @__PURE__ */ jsx(ThemeContext.Provider, { value: null, children }) }) }) }) }) }) }) }) }) }) }) }) });
|
|
@@ -2940,9 +3565,9 @@ function ButtonsAndToggles() {
|
|
|
2940
3565
|
/* @__PURE__ */ jsx(Xt, { status: "muted", children: "MUTED" })
|
|
2941
3566
|
] }) }),
|
|
2942
3567
|
/* @__PURE__ */ jsx(Cell, { label: "Checkbox, Switch", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
|
|
2943
|
-
/* @__PURE__ */ jsx(
|
|
2944
|
-
/* @__PURE__ */ jsx(
|
|
2945
|
-
/* @__PURE__ */ jsx(
|
|
3568
|
+
/* @__PURE__ */ jsx(c4, { isSelected: snap, onChange: setSnap, children: "Snap to grid" }),
|
|
3569
|
+
/* @__PURE__ */ jsx(c4, { isIndeterminate: true, children: "Mixed" }),
|
|
3570
|
+
/* @__PURE__ */ jsx(a5, { isSelected: wifi, onChange: setWifi, children: "Wifi" })
|
|
2946
3571
|
] }) }),
|
|
2947
3572
|
/* @__PURE__ */ jsx(Cell, { label: "RadioGroup", children: /* @__PURE__ */ jsxs(l5, { label: "Snap mode", orientation: "horizontal", defaultValue: "grid", children: [
|
|
2948
3573
|
/* @__PURE__ */ jsx(u3, { value: "off", children: "Off" }),
|
|
@@ -2951,7 +3576,7 @@ function ButtonsAndToggles() {
|
|
|
2951
3576
|
] }) }),
|
|
2952
3577
|
/* @__PURE__ */ jsxs(Cell, { label: "ToggleBar", children: [
|
|
2953
3578
|
/* @__PURE__ */ jsx(
|
|
2954
|
-
|
|
3579
|
+
s3,
|
|
2955
3580
|
{
|
|
2956
3581
|
ariaLabel: "Align",
|
|
2957
3582
|
value: align,
|
|
@@ -2964,7 +3589,7 @@ function ButtonsAndToggles() {
|
|
|
2964
3589
|
}
|
|
2965
3590
|
),
|
|
2966
3591
|
/* @__PURE__ */ jsx(
|
|
2967
|
-
|
|
3592
|
+
s3,
|
|
2968
3593
|
{
|
|
2969
3594
|
ariaLabel: "Align, flat",
|
|
2970
3595
|
variant: "flat",
|
|
@@ -2990,7 +3615,7 @@ function ButtonsAndToggles() {
|
|
|
2990
3615
|
}
|
|
2991
3616
|
),
|
|
2992
3617
|
/* @__PURE__ */ jsx(
|
|
2993
|
-
|
|
3618
|
+
a7,
|
|
2994
3619
|
{
|
|
2995
3620
|
items: [
|
|
2996
3621
|
{ value: "undo", label: "Undo", onAction: () => {
|
|
@@ -3003,7 +3628,7 @@ function ButtonsAndToggles() {
|
|
|
3003
3628
|
] }) }),
|
|
3004
3629
|
/* @__PURE__ */ jsx(Cell, { label: "MenuButton, Disclosure", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
|
|
3005
3630
|
/* @__PURE__ */ jsx(
|
|
3006
|
-
|
|
3631
|
+
p6,
|
|
3007
3632
|
{
|
|
3008
3633
|
label: "Add trial\u2026",
|
|
3009
3634
|
onAction: () => {
|
|
@@ -3017,19 +3642,19 @@ function ButtonsAndToggles() {
|
|
|
3017
3642
|
/* @__PURE__ */ jsx(i3, { open, onToggle: () => setOpen((o4) => !o4), label: "Shapes" })
|
|
3018
3643
|
] }) }),
|
|
3019
3644
|
/* @__PURE__ */ jsx(Cell, { label: "Tabs", children: /* @__PURE__ */ jsxs(o5, { children: [
|
|
3020
|
-
/* @__PURE__ */ jsxs(
|
|
3021
|
-
/* @__PURE__ */ jsx(
|
|
3022
|
-
/* @__PURE__ */ jsx(
|
|
3023
|
-
/* @__PURE__ */ jsx(
|
|
3645
|
+
/* @__PURE__ */ jsxs(s5, { "aria-label": "Sections", children: [
|
|
3646
|
+
/* @__PURE__ */ jsx(c5, { id: "props", children: "Props" }),
|
|
3647
|
+
/* @__PURE__ */ jsx(c5, { id: "events", children: "Events" }),
|
|
3648
|
+
/* @__PURE__ */ jsx(c5, { id: "snapshot", children: "Snapshot" })
|
|
3024
3649
|
] }),
|
|
3025
|
-
/* @__PURE__ */ jsx(
|
|
3026
|
-
/* @__PURE__ */ jsx(
|
|
3027
|
-
/* @__PURE__ */ jsx(
|
|
3650
|
+
/* @__PURE__ */ jsx(l8, { id: "props", children: "Props panel." }),
|
|
3651
|
+
/* @__PURE__ */ jsx(l8, { id: "events", children: "Events panel." }),
|
|
3652
|
+
/* @__PURE__ */ jsx(l8, { id: "snapshot", children: "Snapshot panel." })
|
|
3028
3653
|
] }) }),
|
|
3029
3654
|
/* @__PURE__ */ jsx(Cell, { label: "Keycaps", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
|
|
3030
3655
|
/* @__PURE__ */ jsx(p, { keys: [{ label: "\u2318" }, { label: "\u21E7" }, { label: "K" }], separator: "+" }),
|
|
3031
|
-
/* @__PURE__ */ jsx(
|
|
3032
|
-
/* @__PURE__ */ jsx(
|
|
3656
|
+
/* @__PURE__ */ jsx(f3, { label: "K" }),
|
|
3657
|
+
/* @__PURE__ */ jsx(f3, { label: "\u2325", variant: "minimal" })
|
|
3033
3658
|
] }) })
|
|
3034
3659
|
] });
|
|
3035
3660
|
}
|
|
@@ -3089,9 +3714,9 @@ function FieldsAndPickers() {
|
|
|
3089
3714
|
)
|
|
3090
3715
|
] }),
|
|
3091
3716
|
/* @__PURE__ */ jsxs(Cell, { label: "RangeSlider, Slider", children: [
|
|
3092
|
-
/* @__PURE__ */ jsx(
|
|
3717
|
+
/* @__PURE__ */ jsx(l9, { label: "Range", defaultValue: [20, 80], minValue: 0, maxValue: 100 }),
|
|
3093
3718
|
/* @__PURE__ */ jsx(
|
|
3094
|
-
|
|
3719
|
+
l9,
|
|
3095
3720
|
{
|
|
3096
3721
|
label: "Opacity",
|
|
3097
3722
|
defaultValue: 75,
|
|
@@ -3101,7 +3726,7 @@ function FieldsAndPickers() {
|
|
|
3101
3726
|
}
|
|
3102
3727
|
),
|
|
3103
3728
|
/* @__PURE__ */ jsx(
|
|
3104
|
-
|
|
3729
|
+
w2,
|
|
3105
3730
|
{
|
|
3106
3731
|
ariaLabel: "Pair",
|
|
3107
3732
|
min: 0,
|
|
@@ -3116,7 +3741,7 @@ function FieldsAndPickers() {
|
|
|
3116
3741
|
] }),
|
|
3117
3742
|
/* @__PURE__ */ jsxs(Cell, { label: "DetentSlider, InlineRange", children: [
|
|
3118
3743
|
/* @__PURE__ */ jsx(
|
|
3119
|
-
|
|
3744
|
+
c6,
|
|
3120
3745
|
{
|
|
3121
3746
|
items: [0.25, 0.5, 1, 2, 4],
|
|
3122
3747
|
value: rate,
|
|
@@ -3171,9 +3796,9 @@ function PanelsAndRows() {
|
|
|
3171
3796
|
]);
|
|
3172
3797
|
const [panelCollapsed, setPanelCollapsed] = useState(false);
|
|
3173
3798
|
return /* @__PURE__ */ jsxs(Section, { title: "Panels & property rows", children: [
|
|
3174
|
-
/* @__PURE__ */ jsx(Cell, { label: "PropertyPanel", children: /* @__PURE__ */ jsx(
|
|
3799
|
+
/* @__PURE__ */ jsx(Cell, { label: "PropertyPanel", children: /* @__PURE__ */ jsx(ce2, { title: "Shape", children: /* @__PURE__ */ jsxs(le, { children: [
|
|
3175
3800
|
/* @__PURE__ */ jsx(
|
|
3176
|
-
|
|
3801
|
+
ye,
|
|
3177
3802
|
{
|
|
3178
3803
|
kind: "number",
|
|
3179
3804
|
control: "slider",
|
|
@@ -3186,7 +3811,7 @@ function PanelsAndRows() {
|
|
|
3186
3811
|
}
|
|
3187
3812
|
),
|
|
3188
3813
|
/* @__PURE__ */ jsx(
|
|
3189
|
-
|
|
3814
|
+
ye,
|
|
3190
3815
|
{
|
|
3191
3816
|
kind: "number",
|
|
3192
3817
|
control: "slider",
|
|
@@ -3199,7 +3824,7 @@ function PanelsAndRows() {
|
|
|
3199
3824
|
}
|
|
3200
3825
|
),
|
|
3201
3826
|
/* @__PURE__ */ jsx(
|
|
3202
|
-
|
|
3827
|
+
ye,
|
|
3203
3828
|
{
|
|
3204
3829
|
kind: "color",
|
|
3205
3830
|
label: "Fill",
|
|
@@ -3209,9 +3834,9 @@ function PanelsAndRows() {
|
|
|
3209
3834
|
onAlphaChange: setAlpha
|
|
3210
3835
|
}
|
|
3211
3836
|
),
|
|
3212
|
-
/* @__PURE__ */ jsx(
|
|
3837
|
+
/* @__PURE__ */ jsx(ye, { kind: "color", label: "Stroke", value: stroke, onChange: setStroke }),
|
|
3213
3838
|
/* @__PURE__ */ jsx(
|
|
3214
|
-
|
|
3839
|
+
ye,
|
|
3215
3840
|
{
|
|
3216
3841
|
kind: "number",
|
|
3217
3842
|
label: "Count",
|
|
@@ -3223,7 +3848,7 @@ function PanelsAndRows() {
|
|
|
3223
3848
|
}
|
|
3224
3849
|
),
|
|
3225
3850
|
/* @__PURE__ */ jsx(
|
|
3226
|
-
|
|
3851
|
+
ye,
|
|
3227
3852
|
{
|
|
3228
3853
|
kind: "enum",
|
|
3229
3854
|
label: "Line cap",
|
|
@@ -3236,7 +3861,7 @@ function PanelsAndRows() {
|
|
|
3236
3861
|
}
|
|
3237
3862
|
),
|
|
3238
3863
|
/* @__PURE__ */ jsx(
|
|
3239
|
-
|
|
3864
|
+
ye,
|
|
3240
3865
|
{
|
|
3241
3866
|
kind: "enum",
|
|
3242
3867
|
control: "toggle",
|
|
@@ -3250,10 +3875,10 @@ function PanelsAndRows() {
|
|
|
3250
3875
|
]
|
|
3251
3876
|
}
|
|
3252
3877
|
),
|
|
3253
|
-
/* @__PURE__ */ jsx(
|
|
3254
|
-
/* @__PURE__ */ jsx(
|
|
3878
|
+
/* @__PURE__ */ jsx(ye, { kind: "string", label: "Label", value: label, onChange: setLabel }),
|
|
3879
|
+
/* @__PURE__ */ jsx(ye, { kind: "boolean", label: "Visible", value: visible, onChange: setVisible }),
|
|
3255
3880
|
/* @__PURE__ */ jsx(b3, { title: "Bevel", defaultCollapsed: true, children: /* @__PURE__ */ jsx(
|
|
3256
|
-
|
|
3881
|
+
ye,
|
|
3257
3882
|
{
|
|
3258
3883
|
kind: "number",
|
|
3259
3884
|
control: "slider",
|
|
@@ -3276,10 +3901,10 @@ function PanelsAndRows() {
|
|
|
3276
3901
|
}
|
|
3277
3902
|
) }),
|
|
3278
3903
|
/* @__PURE__ */ jsx(Cell, { label: "LayerList", children: /* @__PURE__ */ jsx(
|
|
3279
|
-
|
|
3904
|
+
A2,
|
|
3280
3905
|
{
|
|
3281
3906
|
items: layers,
|
|
3282
|
-
onReorder: (move) => setLayers(
|
|
3907
|
+
onReorder: (move) => setLayers(T(layers, move)),
|
|
3283
3908
|
renderBody: (item) => /* @__PURE__ */ jsxs("div", { children: [
|
|
3284
3909
|
"settings for ",
|
|
3285
3910
|
item.label
|
|
@@ -3287,7 +3912,7 @@ function PanelsAndRows() {
|
|
|
3287
3912
|
}
|
|
3288
3913
|
) }),
|
|
3289
3914
|
/* @__PURE__ */ jsx(Cell, { label: "Sidebar, SidebarPanel", children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__box", children: /* @__PURE__ */ jsx(n6, { side: "right", ariaLabel: "Specimen sidebar", children: /* @__PURE__ */ jsx(
|
|
3290
|
-
|
|
3915
|
+
a8,
|
|
3291
3916
|
{
|
|
3292
3917
|
title: "Selection",
|
|
3293
3918
|
collapsed: panelCollapsed,
|
|
@@ -3312,7 +3937,7 @@ function OverlaysAndFeedback() {
|
|
|
3312
3937
|
] }),
|
|
3313
3938
|
/* @__PURE__ */ jsx("button", { type: "button", ref: calloutAnchor, onClick: () => setCalloutOpen(true), children: "Callout" }),
|
|
3314
3939
|
/* @__PURE__ */ jsx(
|
|
3315
|
-
|
|
3940
|
+
v3,
|
|
3316
3941
|
{
|
|
3317
3942
|
triggerRef: calloutAnchor,
|
|
3318
3943
|
isOpen: calloutOpen,
|
|
@@ -3324,7 +3949,7 @@ function OverlaysAndFeedback() {
|
|
|
3324
3949
|
),
|
|
3325
3950
|
/* @__PURE__ */ jsx(c, { onClick: () => setDialogOpen(true), children: "Dialog" }),
|
|
3326
3951
|
/* @__PURE__ */ jsx(
|
|
3327
|
-
|
|
3952
|
+
d2,
|
|
3328
3953
|
{
|
|
3329
3954
|
isOpen: dialogOpen,
|
|
3330
3955
|
onOpenChange: setDialogOpen,
|
|
@@ -3376,7 +4001,7 @@ function ListsAndData() {
|
|
|
3376
4001
|
}
|
|
3377
4002
|
) }),
|
|
3378
4003
|
/* @__PURE__ */ jsx(Cell, { label: "DataGrid", children: /* @__PURE__ */ jsx(
|
|
3379
|
-
|
|
4004
|
+
f2,
|
|
3380
4005
|
{
|
|
3381
4006
|
rows: [
|
|
3382
4007
|
{ id: "1", name: "accent", count: 3 },
|
|
@@ -3407,14 +4032,14 @@ function ToolChrome() {
|
|
|
3407
4032
|
},
|
|
3408
4033
|
id
|
|
3409
4034
|
)) }) }),
|
|
3410
|
-
/* @__PURE__ */ jsx(Cell, { label: "ToolOptionsBar", children: /* @__PURE__ */ jsxs(
|
|
4035
|
+
/* @__PURE__ */ jsx(Cell, { label: "ToolOptionsBar", children: /* @__PURE__ */ jsxs(p4, { label: "Text", children: [
|
|
3411
4036
|
/* @__PURE__ */ jsx(c, { size: "sm", variant: "ghost", iconOnly: true, ariaLabel: "Bold", children: "B" }),
|
|
3412
4037
|
/* @__PURE__ */ jsx(c, { size: "sm", variant: "ghost", iconOnly: true, ariaLabel: "Italic", children: "I" })
|
|
3413
4038
|
] }) }),
|
|
3414
4039
|
/* @__PURE__ */ jsx(Cell, { label: "ResizeHandle", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__box", children: [
|
|
3415
4040
|
/* @__PURE__ */ jsx("div", { className: "lk-specimen__box-main", children: "content" }),
|
|
3416
4041
|
/* @__PURE__ */ jsx(
|
|
3417
|
-
|
|
4042
|
+
l7,
|
|
3418
4043
|
{
|
|
3419
4044
|
value: paneWidth,
|
|
3420
4045
|
min: 100,
|
|
@@ -3538,7 +4163,7 @@ function EditorsAndPlots() {
|
|
|
3538
4163
|
}
|
|
3539
4164
|
) }),
|
|
3540
4165
|
/* @__PURE__ */ jsx(Cell, { label: "Timeline", wide: true, children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__timeline", children: /* @__PURE__ */ jsx(
|
|
3541
|
-
|
|
4166
|
+
xe,
|
|
3542
4167
|
{
|
|
3543
4168
|
tracks,
|
|
3544
4169
|
duration: 2e3,
|
|
@@ -3563,10 +4188,6 @@ function LabChrome() {
|
|
|
3563
4188
|
/* @__PURE__ */ jsx(Toolbar.Group, { end: true, children: /* @__PURE__ */ jsx(Toolbar.Button, { onClick: () => {
|
|
3564
4189
|
}, children: "Save" }) })
|
|
3565
4190
|
] }) }),
|
|
3566
|
-
/* @__PURE__ */ jsx(Cell, { label: "StatusBar", children: /* @__PURE__ */ jsxs(StatusBar, { children: [
|
|
3567
|
-
/* @__PURE__ */ jsx(StatusBar.Section, { children: "Items: 12" }),
|
|
3568
|
-
/* @__PURE__ */ jsx(StatusBar.Section, { children: "Zoom: 100%" })
|
|
3569
|
-
] }) }),
|
|
3570
4191
|
/* @__PURE__ */ jsxs(Cell, { label: "Legend, JobProgress", children: [
|
|
3571
4192
|
/* @__PURE__ */ jsx(Legend, { entries: LEGEND }),
|
|
3572
4193
|
/* @__PURE__ */ jsx(JobProgress, { job: JOB })
|
|
@@ -3601,6 +4222,6 @@ function Specimen({ className }) {
|
|
|
3601
4222
|
] });
|
|
3602
4223
|
}
|
|
3603
4224
|
|
|
3604
|
-
export { AnnotationOverlay, AnnotationTargets, Lab, LabBoundary, LabPalette, LabRoot, LabShell, LabSwitcher, LabZoom, SPECIMEN_SECTIONS, Specimen, Trial, TrialBody, TrialChrome, Workspace, addTrial, annotationsFromJSON, capturePlan, captureTarget, cloneTrial, closeTrial, composeCaptureSvg, createAnnotationScene, createAnnotationStore, createMarkDrawOne, currentPage, defineInstrument, fitView, fromWeaselView, interstellarTheme, isStale, reorderTrials, resetTrial, resolveMarkStyle, seenFrom, toWeaselView, validateConfigSchema };
|
|
4225
|
+
export { AnnotationOverlay, AnnotationTargets, Lab, LabBoundary, LabPalette, LabRoot, LabShell, LabSwitcher, LabZoom, Lightbox, LightboxLayers, SPECIMEN_SECTIONS, Specimen, Trial, TrialBody, TrialChrome, Workspace, addTrial, annotationsFromJSON, capturePlan, captureTarget, cloneTrial, closeTrial, composeCaptureSvg, createAnnotationScene, createAnnotationStore, createMarkDrawOne, currentPage, defineInstrument, fitView, fromWeaselView, interstellarTheme, isStale, reorderTrials, resetTrial, resolveMarkStyle, seenFrom, toWeaselView, useClockFrame, useLightbox, useLightboxControl, useLightboxLayers, usePresentation, useTrialClock, validateConfigSchema };
|
|
3605
4226
|
//# sourceMappingURL=index.js.map
|
|
3606
4227
|
//# sourceMappingURL=index.js.map
|