@weasel-js/labkit 1.0.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +6 -6
  2. package/dist/_dts/{DrawCommand-uKHt4Vul.d.ts → DrawCommand-BkZztJsW.d.ts} +3 -1
  3. package/dist/_dts/{index-CFlDPeZh.d.ts → index-iAP6XbH3.d.ts} +17 -7
  4. package/dist/_dts/{useExperimentState-vrttakTt.d.ts → useTrialState-DYe2vUwN.d.ts} +62 -34
  5. package/dist/canvas/index.d.ts +1 -1
  6. package/dist/chunk-3TYUJR7Z.js +488 -0
  7. package/dist/chunk-3TYUJR7Z.js.map +1 -0
  8. package/dist/{chunk-N5KTQKQA.js → chunk-C6GJKPUI.js} +835 -770
  9. package/dist/chunk-C6GJKPUI.js.map +1 -0
  10. package/dist/{chunk-3WPOGKUP.js → chunk-DJLDIRFN.js} +543 -226
  11. package/dist/chunk-DJLDIRFN.js.map +1 -0
  12. package/dist/{chunk-73PXCRCR.js → chunk-NRKWVTVT.js} +6 -6
  13. package/dist/chunk-NRKWVTVT.js.map +1 -0
  14. package/dist/dragdrop/index.d.ts +1 -1
  15. package/dist/index.d.ts +197 -148
  16. package/dist/index.js +275 -161
  17. package/dist/index.js.map +1 -1
  18. package/dist/layers/index.d.ts +2 -2
  19. package/dist/passthrough/weasel-canvas.d.ts +1 -1
  20. package/dist/passthrough/weasel-canvas.js +1 -1
  21. package/dist/passthrough/weasel-ui.d.ts +10 -3
  22. package/dist/passthrough/weasel-ui.js +2 -2
  23. package/dist/state/index.d.ts +14 -14
  24. package/dist/state/index.js +5 -5
  25. package/dist/state/index.js.map +1 -1
  26. package/dist/styles.css +179 -14
  27. package/dist/ui/layers/index.js +3 -3
  28. package/dist/undo/index.d.ts +1 -1
  29. package/package.json +2 -1
  30. package/src/canvas/AGENTS.md +6 -2
  31. package/src/dragdrop/dragDrop.test.tsx +4 -7
  32. package/src/index.test.ts +52 -0
  33. package/src/index.ts +11 -7
  34. package/src/instrument/SineWave.smoke.test.tsx +1 -1
  35. package/src/instrument/capabilityDetector.ts +1 -1
  36. package/src/instrument/types.ts +18 -6
  37. package/src/lab/Lab.less +16 -0
  38. package/src/lab/Lab.stories.tsx +5 -5
  39. package/src/lab/Lab.test.tsx +25 -25
  40. package/src/lab/Lab.tsx +56 -44
  41. package/src/lab/LabContext.ts +12 -11
  42. package/src/lab/LabShell.tsx +1 -1
  43. package/src/lab/Workspace.less +40 -0
  44. package/src/lab/{WorkspaceGrid.stories.tsx → Workspace.stories.tsx} +27 -11
  45. package/src/lab/Workspace.test.tsx +114 -0
  46. package/src/lab/Workspace.tsx +196 -0
  47. package/src/lab/index.ts +2 -4
  48. package/src/layers/AGENTS.md +3 -3
  49. package/src/primitives/Toolbar.stories.tsx +2 -2
  50. package/src/state/SingletonExperiment.test.tsx +8 -8
  51. package/src/state/SingletonExperiment.tsx +9 -9
  52. package/src/state/context.tsx +12 -12
  53. package/src/state/document.test.ts +369 -0
  54. package/src/state/document.ts +194 -0
  55. package/src/state/helpers.test.ts +74 -46
  56. package/src/state/helpers.ts +23 -31
  57. package/src/state/index.ts +16 -8
  58. package/src/state/store.test.ts +440 -40
  59. package/src/state/store.ts +166 -90
  60. package/src/state/types.ts +30 -10
  61. package/src/state/{useExperimentState.test.tsx → useTrialState.test.tsx} +18 -18
  62. package/src/state/useTrialState.ts +29 -0
  63. package/src/styles.less +2 -2
  64. package/src/test-setup.ts +19 -0
  65. package/src/theme/base.less +1 -1
  66. package/src/{workspace → trial}/DefaultSidebar.tsx +3 -3
  67. package/src/{workspace → trial}/DefaultStatusBar.tsx +5 -4
  68. package/src/{workspace → trial}/DefaultToolbar.tsx +9 -8
  69. package/src/trial/Trial.canvas.test.tsx +80 -0
  70. package/src/{workspace/Workspace.less → trial/Trial.less} +1 -1
  71. package/src/{workspace/Workspace.stories.tsx → trial/Trial.stories.tsx} +13 -17
  72. package/src/{workspace/Workspace.test.tsx → trial/Trial.test.tsx} +26 -25
  73. package/src/{workspace/Workspace.tsx → trial/Trial.tsx} +48 -43
  74. package/src/{workspace/WorkspaceChrome.tsx → trial/TrialChrome.tsx} +42 -42
  75. package/src/{workspace → trial}/index.ts +13 -12
  76. package/src/{workspace → trial}/slotTypes.ts +16 -16
  77. package/src/{workspace/workspaceOps.test.ts → trial/trialOps.test.ts} +60 -33
  78. package/src/trial/trialOps.ts +99 -0
  79. package/src/ui/format.test.ts +33 -0
  80. package/src/ui/format.ts +11 -0
  81. package/src/ui/properties/CurveField.tsx +6 -6
  82. package/src/ui/properties/SpeechBalloonPanels.stories.tsx +3 -3
  83. package/dist/chunk-3WPOGKUP.js.map +0 -1
  84. package/dist/chunk-73PXCRCR.js.map +0 -1
  85. package/dist/chunk-N5KTQKQA.js.map +0 -1
  86. package/dist/chunk-T7OKNJTY.js +0 -351
  87. package/dist/chunk-T7OKNJTY.js.map +0 -1
  88. package/src/lab/WorkspaceGrid.less +0 -8
  89. package/src/lab/WorkspaceGrid.test.tsx +0 -40
  90. package/src/lab/WorkspaceGrid.tsx +0 -22
  91. package/src/lab/gridDims.test.ts +0 -35
  92. package/src/lab/gridDims.ts +0 -13
  93. package/src/state/useExperimentState.ts +0 -31
  94. package/src/workspace/workspaceOps.ts +0 -86
@@ -1,5 +1,5 @@
1
- import { c as LayerDescriptor } from '../_dts/index-CFlDPeZh.js';
2
- export { L as LayerCapability } from '../_dts/index-CFlDPeZh.js';
1
+ import { d as LayerDescriptor } from '../_dts/index-iAP6XbH3.js';
2
+ export { L as LayerCapability } from '../_dts/index-iAP6XbH3.js';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
  import 'react';
5
5
  import '../_dts/types-x92Kfeme.js';
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { Ref } from 'react';
3
- import { N as Node, V as View, D as DrawCommand, S as Scene, B as Bounds, a as ViewportDims, P as PathDrawCommand } from '../_dts/DrawCommand-uKHt4Vul.js';
3
+ import { N as Node, V as View, D as DrawCommand, S as Scene, B as Bounds, a as ViewportDims, P as PathDrawCommand } from '../_dts/DrawCommand-BkZztJsW.js';
4
4
 
5
5
  /**
6
6
  * `renderSceneToCanvas` — substrate for detached, read-only scene views
@@ -1,3 +1,3 @@
1
- export { FALLBACK_FIT_VIEW, MinimapCanvas, SceneViewCanvas, buildSceneViewCommands, computeFitView2 as computeFitView, computeIndicatorCommand, renderSceneToCanvas } from '../chunk-3WPOGKUP.js';
1
+ export { FALLBACK_FIT_VIEW, MinimapCanvas, SceneViewCanvas, buildSceneViewCommands, computeFitView2 as computeFitView, computeIndicatorCommand, renderSceneToCanvas } from '../chunk-DJLDIRFN.js';
2
2
  //# sourceMappingURL=weasel-canvas.js.map
3
3
  //# sourceMappingURL=weasel-canvas.js.map
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { ReactNode, CSSProperties, ButtonHTMLAttributes, ReactElement, MutableRefObject, KeyboardEvent, PointerEvent as PointerEvent$1, RefCallback, RefObject } from 'react';
4
- import { V as View, D as DrawCommand, O as Op, b as NodeId, c as Path, S as Scene, H as History, B as Bounds } from '../_dts/DrawCommand-uKHt4Vul.js';
4
+ import { V as View, D as DrawCommand, O as Op, b as NodeId, c as Path, S as Scene, H as History, B as Bounds } from '../_dts/DrawCommand-BkZztJsW.js';
5
5
  import { TextFieldProps, ValidationResult, CheckboxProps as CheckboxProps$1, SwitchProps as SwitchProps$1, TabProps as TabProps$1, TabListProps as TabListProps$1, TabPanelProps as TabPanelProps$1, TabsProps as TabsProps$1, RadioProps as RadioProps$1, RadioGroupProps as RadioGroupProps$1, NumberFieldProps as NumberFieldProps$1, SelectProps as SelectProps$1, ListBoxItemProps, ComboBoxProps as ComboBoxProps$1, SliderProps as SliderProps$1, ModalOverlayProps, DialogProps as DialogProps$1 } from 'react-aria-components';
6
6
 
7
7
  /**
@@ -1082,6 +1082,10 @@ type TrackCtx = {
1082
1082
  * `onInput` fires continuously through a drag; `onChange` fires once when it
1083
1083
  * ends and is the one to write to history.
1084
1084
  *
1085
+ * `stops` are attractors: a drag that passes within a few pixels of one lands
1086
+ * on it, and the arrow keys move stop to stop. `step` still quantizes the
1087
+ * values between them.
1088
+ *
1085
1089
  * `constraint: 'ordered'` keeps thumbs from crossing each other. Supplying
1086
1090
  * `onAddThumb` makes a click on empty track create a thumb, and supplying
1087
1091
  * `onRemoveThumb` lets a right-click or a drag off the track remove one —
@@ -1095,6 +1099,7 @@ type SliderProps<T extends Thumb = Thumb> = {
1095
1099
  min: number;
1096
1100
  max: number;
1097
1101
  step?: number;
1102
+ stops?: number[];
1098
1103
  constraint?: 'free' | 'ordered';
1099
1104
  onAddThumb?: (atValue: number) => T | null;
1100
1105
  onRemoveThumb?: (index: number) => boolean;
@@ -1676,8 +1681,10 @@ interface InsertAdapter<TNode extends {
1676
1681
  dx: number;
1677
1682
  dy: number;
1678
1683
  };
1679
- /** Mutator wired by `insertNode`-using ops (kit-side InsertOp). */
1680
- insertNode(node: TNode): void;
1684
+ /** Mutator wired by `insertNode`-using ops (kit-side InsertOp). `index`
1685
+ * carries the z-position a delete captured, so undo restores paint order;
1686
+ * see `SceneAdapter.insertNode`. */
1687
+ insertNode(node: TNode, index?: number): void;
1681
1688
  /** Mutator wired by `setSelection` ops batched alongside paste. */
1682
1689
  setSelection(ids: string[]): void;
1683
1690
  /** Optional: see SceneAdapter.applyOps. */
@@ -1,4 +1,4 @@
1
- export { m as ActionBar, r3 as ActionsBar, Ft as Badge, a as Button, o3 as Checkbox, p4 as ComboBox, m2 as ComboBoxItem, F as CurveEditor, l as DataGrid, c2 as Dialog, qe as EDGE_PROFILES, n as Field, u2 as Input, s2 as KeyCap, c as KeySequence, a2 as MINUS_SIGN, f3 as NumberField, r2 as OptionsBar, _ as Plot2D, n4 as PointPlotter, r4 as Powerline, u3 as Radio, l2 as RadioGroup, l3 as RangeSlider, p3 as Select, h as SelectItem, n2 as Sidebar, o4 as SidebarPanel, f2 as Slider, a4 as Switch, c3 as Tab, s3 as TabList, l4 as TabPanel, o6 as Tabs, r as ToggleBar, o5 as ToolButton, n3 as ToolGroup, _2 as ToolPalette, He as chromaAt, u as detectPlatform, p as dlog, r5 as fieldClasses, o2 as formatNumber, d2 as formatShortcut, u4 as formatShortcutParts, o as inferKeycapKind, f as isDebugEnabled, e as keyGlyph, p2 as keySpecFromKey, d as keySpecsFromMods, Ve as oklchToHex, p5 as paintGradientTrack, s as useReorderDragList, a3 as useRovingTabIndex } from '../chunk-N5KTQKQA.js';
2
- import '../chunk-3WPOGKUP.js';
1
+ export { m as ActionBar, r3 as ActionsBar, Ft as Badge, a as Button, o3 as Checkbox, p4 as ComboBox, m2 as ComboBoxItem, F as CurveEditor, u as DataGrid, c3 as Dialog, qe as EDGE_PROFILES, n as Field, u3 as Input, s as KeyCap, c2 as KeySequence, o2 as MINUS_SIGN, f2 as NumberField, r2 as OptionsBar, _ as Plot2D, n4 as PointPlotter, r4 as Powerline, u4 as Radio, l as RadioGroup, l2 as RangeSlider, p3 as Select, h as SelectItem, n2 as Sidebar, o4 as SidebarPanel, v as Slider, a3 as Switch, c4 as Tab, s3 as TabList, l3 as TabPanel, o6 as Tabs, r as ToggleBar, o5 as ToolButton, n3 as ToolGroup, _2 as ToolPalette, He as chromaAt, u2 as detectPlatform, p as dlog, r5 as fieldClasses, s2 as formatNumber, d2 as formatShortcut, u5 as formatShortcutParts, o as inferKeycapKind, f as isDebugEnabled, e as keyGlyph, p2 as keySpecFromKey, d as keySpecsFromMods, Ve as oklchToHex, p5 as paintGradientTrack, c as useReorderDragList, a2 as useRovingTabIndex } from '../chunk-C6GJKPUI.js';
2
+ import '../chunk-DJLDIRFN.js';
3
3
  //# sourceMappingURL=weasel-ui.js.map
4
4
  //# sourceMappingURL=weasel-ui.js.map
@@ -1,12 +1,12 @@
1
- import { I as InstrumentSerializers, W as WorkspaceRecord, U as UndoStack, S as StorageAdapter } from '../_dts/useExperimentState-vrttakTt.js';
2
- export { C as CreateLabStoreOptions, E as ExperimentStateHandle, L as LabStore, a as LabStoreActions, b as LabStoreContext, c as LabStoreProvider, d as LabStoreState, e as SavedSnapshot, f as WorkspaceIdContext, g as WorkspaceIdProvider, h as createLabStore, i as createMemoryAdapter, l as localStorageAdapter, n as noneAdapter, s as sessionStorageAdapter, u as urlHashAdapter, j as useExperimentState, k as useLabStore, m as useWorkspaceId } from '../_dts/useExperimentState-vrttakTt.js';
1
+ import { S as SerializedTrial, I as InstrumentSerializers, T as TrialRecord, U as UndoStack, a as StorageAdapter } from '../_dts/useTrialState-DYe2vUwN.js';
2
+ export { C as CURRENT_DOCUMENT_VERSION, b as CreateLabStoreOptions, L as LabDocument, c as LabStore, d as LabStoreActions, e as LabStoreContext, f as LabStoreProvider, g as LabStoreState, M as Migration, h as SavedSnapshot, i as TrialIdContext, j as TrialIdProvider, k as TrialStateHandle, l as createLabStore, m as createMemoryAdapter, n as labDocumentKey, o as localStorageAdapter, p as noneAdapter, q as quarantineKey, s as sessionStorageAdapter, u as urlHashAdapter, r as useLabStore, t as useTrialId, v as useTrialState } from '../_dts/useTrialState-DYe2vUwN.js';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
  import { ReactNode } from 'react';
5
5
  import 'zustand/vanilla';
6
6
 
7
- /** The storage key a lab writes one of its three buckets under. Namespaced by
7
+ /** The storage key a lab writes one of its buckets under. Namespaced by
8
8
  * `storageKey` so two labs sharing an origin do not collide. */
9
- declare function labStorageKey(storageKey: string, bucket: 'workspaces' | 'saves' | 'theme'): string;
9
+ declare function labStorageKey(storageKey: string, bucket: 'workspaces' | 'saves' | 'theme' | 'layout'): string;
10
10
  /** Encode a string for the URL fragment. */
11
11
  declare function encodeUrlHash(value: string): string;
12
12
  /** Decode a URL fragment written by `encodeUrlHash`, or `null` if it is
@@ -14,19 +14,19 @@ declare function encodeUrlHash(value: string): string;
14
14
  declare function decodeUrlHash(hash: string): string | null;
15
15
  /** A fresh, empty undo history. */
16
16
  declare function emptyUndoStack(): UndoStack;
17
- /** Serialize workspaces for storage, running each instrument's own serializer
17
+ /** Serialize trials for storage, running each instrument's own serializer
18
18
  * over its state. Undo history is deliberately dropped — it does not survive
19
19
  * a reload. */
20
- declare function serializeWorkspaces(workspaces: WorkspaceRecord[], serializers: InstrumentSerializers): string;
21
- /** Rebuild workspaces from storage, running each instrument's deserializer
20
+ declare function serializeTrials(trials: TrialRecord[], serializers: InstrumentSerializers): SerializedTrial[];
21
+ /** Rebuild trials from storage, running each instrument's deserializer
22
22
  * over its state and starting each with an empty undo history. Returns an
23
23
  * empty list rather than throwing on malformed input. */
24
- declare function deserializeWorkspaces(raw: string, deserializers: InstrumentSerializers): WorkspaceRecord[];
24
+ declare function deserializeTrials(records: SerializedTrial[], deserializers: InstrumentSerializers): TrialRecord[];
25
25
 
26
26
  /** Props for `<SingletonExperimentProvider>`. */
27
27
  interface SingletonExperimentProviderProps<TS, TC> {
28
- /** Stable id for the synthetic workspace; also doubles as the
29
- * WorkspaceIdContext value. */
28
+ /** Stable id for the synthetic trial; also doubles as the
29
+ * TrialIdContext value. */
30
30
  id: string;
31
31
  initialConfig: TC;
32
32
  initialState: TS;
@@ -35,12 +35,12 @@ interface SingletonExperimentProviderProps<TS, TC> {
35
35
  children: ReactNode;
36
36
  }
37
37
  /**
38
- * One-workspace `<Lab>` substitute for single-screen experiments. Mounts
39
- * a `LabStoreProvider` + `WorkspaceIdProvider` with one synthetic
40
- * workspace, so `useExperimentState` works without going through the
38
+ * One-trial `<Lab>` substitute for single-screen experiments. Mounts
39
+ * a `LabStoreProvider` + `TrialIdProvider` with one synthetic
40
+ * trial, so `useTrialState` works without going through the
41
41
  * full `<Lab instruments={...}>` runtime.
42
42
  */
43
43
  declare function SingletonExperimentProvider<TS, TC>({ id, initialConfig, initialState, storage, storageKey, children, }: SingletonExperimentProviderProps<TS, TC>): react_jsx_runtime.JSX.Element;
44
44
 
45
- export { InstrumentSerializers, SingletonExperimentProvider, StorageAdapter, UndoStack, WorkspaceRecord, decodeUrlHash, deserializeWorkspaces, emptyUndoStack, encodeUrlHash, labStorageKey, serializeWorkspaces };
45
+ export { InstrumentSerializers, SerializedTrial, SingletonExperimentProvider, StorageAdapter, TrialRecord, UndoStack, decodeUrlHash, deserializeTrials, emptyUndoStack, encodeUrlHash, labStorageKey, serializeTrials };
46
46
  export type { SingletonExperimentProviderProps };
@@ -1,5 +1,5 @@
1
- import { createLabStore, LabStoreProvider, WorkspaceIdProvider } from '../chunk-T7OKNJTY.js';
2
- export { LabStoreContext, LabStoreProvider, WorkspaceIdContext, WorkspaceIdProvider, createLabStore, createMemoryAdapter, decodeUrlHash, deserializeWorkspaces, emptyUndoStack, encodeUrlHash, labStorageKey, localStorageAdapter, noneAdapter, serializeWorkspaces, sessionStorageAdapter, urlHashAdapter, useExperimentState, useLabStore, useWorkspaceId } from '../chunk-T7OKNJTY.js';
1
+ import { createLabStore, LabStoreProvider, TrialIdProvider } from '../chunk-3TYUJR7Z.js';
2
+ export { CURRENT_DOCUMENT_VERSION, LabStoreContext, LabStoreProvider, TrialIdContext, TrialIdProvider, createLabStore, createMemoryAdapter, decodeUrlHash, deserializeTrials, emptyUndoStack, encodeUrlHash, labDocumentKey, labStorageKey, localStorageAdapter, noneAdapter, quarantineKey, serializeTrials, sessionStorageAdapter, urlHashAdapter, useLabStore, useTrialId, useTrialState } from '../chunk-3TYUJR7Z.js';
3
3
  import { useRef } from 'react';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
 
@@ -15,8 +15,8 @@ function SingletonExperimentProvider({
15
15
  const storeRef = useRef(null);
16
16
  if (storeRef.current === null) {
17
17
  const store = createLabStore({ storageKey, storage });
18
- if (!store.getState().workspaces.some((w) => w.id === id)) {
19
- store.getState().addWorkspace({
18
+ if (!store.getState().trials.some((w) => w.id === id)) {
19
+ store.getState().addTrial({
20
20
  id,
21
21
  instrumentName: SINGLETON_INSTRUMENT,
22
22
  config: initialConfig,
@@ -26,7 +26,7 @@ function SingletonExperimentProvider({
26
26
  }
27
27
  storeRef.current = store;
28
28
  }
29
- return /* @__PURE__ */ jsx(LabStoreProvider, { store: storeRef.current, children: /* @__PURE__ */ jsx(WorkspaceIdProvider, { workspaceId: id, children }) });
29
+ return /* @__PURE__ */ jsx(LabStoreProvider, { store: storeRef.current, children: /* @__PURE__ */ jsx(TrialIdProvider, { trialId: id, children }) });
30
30
  }
31
31
 
32
32
  export { SingletonExperimentProvider };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/state/SingletonExperiment.tsx"],"names":[],"mappings":";;;;;AAKA,IAAM,oBAAA,GAAuB,eAAA;AAoBtB,SAAS,2BAAA,CAAoC;AAAA,EAClD,EAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAAA,EAA6C;AAC3C,EAAA,MAAM,QAAA,GAAW,OAAwB,IAAI,CAAA;AAC7C,EAAA,IAAI,QAAA,CAAS,YAAY,IAAA,EAAM;AAC7B,IAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,EAAE,UAAA,EAAY,SAAS,CAAA;AACpD,IAAA,IAAI,CAAC,KAAA,CAAM,QAAA,EAAS,CAAE,UAAA,CAAW,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAA,EAAG;AACzD,MAAA,KAAA,CAAM,QAAA,GAAW,YAAA,CAAa;AAAA,QAC5B,EAAA;AAAA,QACA,cAAA,EAAgB,oBAAA;AAAA,QAChB,MAAA,EAAQ,aAAA;AAAA,QACR,KAAA,EAAO,YAAA;AAAA,QACP,IAAA,EAAM,EAAE,IAAA,EAAM,CAAA,EAAG,GAAA,EAAK,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAE;AAAE,OACtC,CAAA;AAAA,IACH;AACA,IAAA,QAAA,CAAS,OAAA,GAAU,KAAA;AAAA,EACrB;AACA,EAAA,uBACE,GAAA,CAAC,gBAAA,EAAA,EAAiB,KAAA,EAAO,QAAA,CAAS,OAAA,EAChC,8BAAC,mBAAA,EAAA,EAAoB,WAAA,EAAa,EAAA,EAAK,QAAA,EAAS,CAAA,EAClD,CAAA;AAEJ","file":"index.js","sourcesContent":["import { type ReactNode, useRef } from 'react';\nimport { LabStoreProvider, WorkspaceIdProvider } from './context';\nimport { createLabStore, type LabStore } from './store';\nimport type { StorageAdapter } from './types';\n\nconst SINGLETON_INSTRUMENT = '__singleton__';\n\n/** Props for `<SingletonExperimentProvider>`. */\nexport interface SingletonExperimentProviderProps<TS, TC> {\n /** Stable id for the synthetic workspace; also doubles as the\n * WorkspaceIdContext value. */\n id: string;\n initialConfig: TC;\n initialState: TS;\n storage: StorageAdapter;\n storageKey: string;\n children: ReactNode;\n}\n\n/**\n * One-workspace `<Lab>` substitute for single-screen experiments. Mounts\n * a `LabStoreProvider` + `WorkspaceIdProvider` with one synthetic\n * workspace, so `useExperimentState` works without going through the\n * full `<Lab instruments={...}>` runtime.\n */\nexport function SingletonExperimentProvider<TS, TC>({\n id,\n initialConfig,\n initialState,\n storage,\n storageKey,\n children,\n}: SingletonExperimentProviderProps<TS, TC>) {\n const storeRef = useRef<LabStore | null>(null);\n if (storeRef.current === null) {\n const store = createLabStore({ storageKey, storage });\n if (!store.getState().workspaces.some((w) => w.id === id)) {\n store.getState().addWorkspace({\n id,\n instrumentName: SINGLETON_INSTRUMENT,\n config: initialConfig,\n state: initialState,\n view: { zoom: 1, pan: { x: 0, y: 0 } },\n });\n }\n storeRef.current = store;\n }\n return (\n <LabStoreProvider store={storeRef.current}>\n <WorkspaceIdProvider workspaceId={id}>{children}</WorkspaceIdProvider>\n </LabStoreProvider>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../src/state/SingletonExperiment.tsx"],"names":[],"mappings":";;;;;AAKA,IAAM,oBAAA,GAAuB,eAAA;AAoBtB,SAAS,2BAAA,CAAoC;AAAA,EAClD,EAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAAA,EAA6C;AAC3C,EAAA,MAAM,QAAA,GAAW,OAAwB,IAAI,CAAA;AAC7C,EAAA,IAAI,QAAA,CAAS,YAAY,IAAA,EAAM;AAC7B,IAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,EAAE,UAAA,EAAY,SAAS,CAAA;AACpD,IAAA,IAAI,CAAC,KAAA,CAAM,QAAA,EAAS,CAAE,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAA,EAAG;AACrD,MAAA,KAAA,CAAM,QAAA,GAAW,QAAA,CAAS;AAAA,QACxB,EAAA;AAAA,QACA,cAAA,EAAgB,oBAAA;AAAA,QAChB,MAAA,EAAQ,aAAA;AAAA,QACR,KAAA,EAAO,YAAA;AAAA,QACP,IAAA,EAAM,EAAE,IAAA,EAAM,CAAA,EAAG,GAAA,EAAK,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAE;AAAE,OACtC,CAAA;AAAA,IACH;AACA,IAAA,QAAA,CAAS,OAAA,GAAU,KAAA;AAAA,EACrB;AACA,EAAA,uBACE,GAAA,CAAC,gBAAA,EAAA,EAAiB,KAAA,EAAO,QAAA,CAAS,OAAA,EAChC,8BAAC,eAAA,EAAA,EAAgB,OAAA,EAAS,EAAA,EAAK,QAAA,EAAS,CAAA,EAC1C,CAAA;AAEJ","file":"index.js","sourcesContent":["import { type ReactNode, useRef } from 'react';\nimport { LabStoreProvider, TrialIdProvider } from './context';\nimport { createLabStore, type LabStore } from './store';\nimport type { StorageAdapter } from './types';\n\nconst SINGLETON_INSTRUMENT = '__singleton__';\n\n/** Props for `<SingletonExperimentProvider>`. */\nexport interface SingletonExperimentProviderProps<TS, TC> {\n /** Stable id for the synthetic trial; also doubles as the\n * TrialIdContext value. */\n id: string;\n initialConfig: TC;\n initialState: TS;\n storage: StorageAdapter;\n storageKey: string;\n children: ReactNode;\n}\n\n/**\n * One-trial `<Lab>` substitute for single-screen experiments. Mounts\n * a `LabStoreProvider` + `TrialIdProvider` with one synthetic\n * trial, so `useTrialState` works without going through the\n * full `<Lab instruments={...}>` runtime.\n */\nexport function SingletonExperimentProvider<TS, TC>({\n id,\n initialConfig,\n initialState,\n storage,\n storageKey,\n children,\n}: SingletonExperimentProviderProps<TS, TC>) {\n const storeRef = useRef<LabStore | null>(null);\n if (storeRef.current === null) {\n const store = createLabStore({ storageKey, storage });\n if (!store.getState().trials.some((w) => w.id === id)) {\n store.getState().addTrial({\n id,\n instrumentName: SINGLETON_INSTRUMENT,\n config: initialConfig,\n state: initialState,\n view: { zoom: 1, pan: { x: 0, y: 0 } },\n });\n }\n storeRef.current = store;\n }\n return (\n <LabStoreProvider store={storeRef.current}>\n <TrialIdProvider trialId={id}>{children}</TrialIdProvider>\n </LabStoreProvider>\n );\n}\n"]}