@weasel-js/labkit 0.7.2 → 1.0.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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -3
  3. package/dist/_dts/{DrawCommand-CEvS5AdV.d.ts → DrawCommand-BwRCZYuo.d.ts} +106 -52
  4. package/dist/_dts/{useExperimentState-eSvpwV_P.d.ts → useExperimentState-CJn2hHzd.d.ts} +6 -4
  5. package/dist/{chunk-SSMHPMDV.js → chunk-53XSBIUK.js} +12 -11
  6. package/dist/chunk-53XSBIUK.js.map +1 -0
  7. package/dist/{chunk-BG6NLMOL.js → chunk-FP5LYDVX.js} +1229 -1227
  8. package/dist/chunk-FP5LYDVX.js.map +1 -0
  9. package/dist/{chunk-ERZQAU4N.js → chunk-HNXVLKBG.js} +3 -3
  10. package/dist/{chunk-ERZQAU4N.js.map → chunk-HNXVLKBG.js.map} +1 -1
  11. package/dist/{chunk-5XDFILHZ.js → chunk-XVBXYKFJ.js} +1675 -670
  12. package/dist/chunk-XVBXYKFJ.js.map +1 -0
  13. package/dist/fonts/inter-latin.woff2 +0 -0
  14. package/dist/fonts/oswald-latin-variable.woff2 +0 -0
  15. package/dist/index.d.ts +37 -13
  16. package/dist/index.js +776 -27
  17. package/dist/index.js.map +1 -1
  18. package/dist/passthrough/weasel-canvas.d.ts +1 -1
  19. package/dist/passthrough/weasel-canvas.js +1 -1
  20. package/dist/passthrough/weasel-ui.d.ts +332 -189
  21. package/dist/passthrough/weasel-ui.js +2 -2
  22. package/dist/state/index.d.ts +2 -2
  23. package/dist/state/index.js +2 -2
  24. package/dist/styles.css +229 -288
  25. package/dist/ui/layers/index.js +3 -3
  26. package/package.json +5 -6
  27. package/src/canvas/CanvasStack.less +1 -1
  28. package/src/controls/ControlPanel.less +12 -12
  29. package/src/dragdrop/DragGhost.less +2 -2
  30. package/src/dragdrop/Palette.less +6 -6
  31. package/src/index.ts +2 -0
  32. package/src/lab/Lab.test.tsx +20 -15
  33. package/src/lab/Lab.tsx +33 -32
  34. package/src/lab/LabContext.ts +3 -3
  35. package/src/lab/LabShell.less +14 -14
  36. package/src/lab/LabShell.test.tsx +7 -20
  37. package/src/lab/LabShell.tsx +22 -13
  38. package/src/lab/WorkspaceGrid.less +1 -1
  39. package/src/lab/WorkspaceGrid.stories.tsx +4 -4
  40. package/src/lab/index.ts +1 -1
  41. package/src/lab/useSystemMode.ts +30 -0
  42. package/src/layers/LayerList.less +9 -9
  43. package/src/primitives/FpsMeter.less +5 -5
  44. package/src/primitives/ScaleIndicator.less +7 -7
  45. package/src/primitives/Sidebar.less +12 -12
  46. package/src/primitives/StatusBar.less +10 -10
  47. package/src/primitives/Toolbar.less +16 -16
  48. package/src/state/store.test.ts +17 -9
  49. package/src/state/store.ts +13 -10
  50. package/src/state/types.ts +5 -2
  51. package/src/theme/Interstellar.stories.less +20 -20
  52. package/src/theme/Interstellar.stories.tsx +44 -59
  53. package/src/theme/base.less +29 -28
  54. package/src/theme/interstellar.test.ts +30 -0
  55. package/src/theme/interstellar.tokens.json +57 -0
  56. package/src/theme/interstellar.ts +9 -0
  57. package/src/ui/layers/LayerStack.less +21 -21
  58. package/src/ui/properties/CurveField.less +5 -5
  59. package/src/ui/properties/EffectCard.tsx +2 -2
  60. package/src/ui/properties/PropertyGroup.less +6 -6
  61. package/src/ui/properties/PropertyPanel.less +70 -70
  62. package/src/ui/properties/SpeechBalloonPanels.stories.tsx +1 -1
  63. package/src/ui/properties/storyLayouts.tsx +1 -1
  64. package/src/workspace/Workspace.less +14 -14
  65. package/src/workspace/Workspace.stories.tsx +2 -2
  66. package/src/workspace/Workspace.test.tsx +2 -2
  67. package/dist/chunk-5XDFILHZ.js.map +0 -1
  68. package/dist/chunk-BG6NLMOL.js.map +0 -1
  69. package/dist/chunk-SSMHPMDV.js.map +0 -1
  70. package/dist/theme-interstellar.css +0 -25
  71. package/dist/theme-light.css +0 -13
  72. package/src/fonts/oswald-latin-variable.woff2 +0 -0
  73. package/src/theme/interstellar.less +0 -34
  74. package/src/theme/light.less +0 -14
  75. package/src/theme/tokens.less +0 -85
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 orochi235
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -43,14 +43,22 @@ function MyLab() {
43
43
  }
44
44
  ```
45
45
 
46
- ## Theme
46
+ ## Theming
47
47
 
48
- Theme follows the OS by default. To force a theme:
48
+ labkit ships one theme, `interstellar` a cosmic dark and a warm parchment
49
+ light — as a value, not a stylesheet:
49
50
 
50
51
  ```tsx
51
- <LabShell title="..." theme="dark">...</LabShell>
52
+ import { interstellarTheme } from '@weasel-js/labkit';
53
+ import { ThemeProvider } from '@weasel-js/theme/react';
54
+
55
+ <ThemeProvider theme={interstellarTheme} mode="dark">…</ThemeProvider>
52
56
  ```
53
57
 
58
+ `<Lab>` and `<LabShell>` do this for you; `mode` is `"auto"` (follow the OS),
59
+ `"light"` or `"dark"`. Only `styles.css` needs importing — the token values
60
+ arrive through the provider.
61
+
54
62
  ## Development
55
63
 
56
64
  ```bash
@@ -172,51 +172,6 @@ interface History {
172
172
  resumeJournal(journal: Journal): void;
173
173
  }
174
174
 
175
- /**
176
- * Pose composition for hierarchical scene graphs.
177
- *
178
- * As of the nesting change, `getPose(id)` on adapters returns the
179
- * **local** pose — relative to the object's direct parent. Anything in the
180
- * kit that needs to draw, hit-test, snap, or otherwise reason about world
181
- * coordinates routes through `composeWorldPose`, which walks the parent
182
- * chain and folds local poses together via a consumer-supplied `compose`.
183
- *
184
- * Pose shape is generic, so the compose strategy is too. For the common
185
- * `{x, y, width, height}` axis-aligned rect, use `composeRectPose` —
186
- * translation only, child dimensions preserved. Custom pose shapes (paths,
187
- * matrix transforms) supply their own.
188
- *
189
- * The inverse — `rebaseLocalPose` — converts a world-space pose into a
190
- * local pose under a target parent. Used when reparenting so the visual
191
- * world position of a child is preserved across the parent change.
192
- */
193
- /**
194
- * Axis-aligned rectangle pose with optional rotation. The canonical pose
195
- * shape used by `composeRectPose` and the `unionBounds` helper. Rotation is
196
- * in radians, pivoted on the unrotated AABB center; absent === 0. Kit-side
197
- * code that consumes rotation already reads `pose.rotation ?? 0`
198
- * (`SceneCanvas.defaultDrawOne`, `rotate/handle.ts`, `pathInWorld.ts`), so
199
- * the slot exists on every default scene whether or not the consumer
200
- * populates it. Defined here in core/transforms so the compose helpers
201
- * don't depend on features.
202
- */
203
- interface RectPose {
204
- x: number;
205
- y: number;
206
- width: number;
207
- height: number;
208
- /** Rotation in radians around the unrotated AABB center. Absent === 0. */
209
- rotation?: number;
210
- }
211
- /** Consumer's pose-composition strategy for hierarchical scenes. `compose`
212
- * folds a child's pose (in parent's frame) up to the next frame; `decompose`
213
- * is its inverse. Default is IDENTITY — an absolute-pose scene where every
214
- * node already stores world coords (parent is grouping-only, no transform). */
215
- interface PoseComposition<TPose> {
216
- compose: (parent: TPose, child: TPose) => TPose;
217
- decompose: (parent: TPose, world: TPose) => TPose;
218
- }
219
-
220
175
  /** Fill rule used by polygon path hit-testing and `ctx.fill()`. */
221
176
  type PathFillRule = 'nonzero' | 'evenodd';
222
177
  /**
@@ -246,6 +201,23 @@ interface RectPath {
246
201
  /** Canonical path shape — either an axis-aligned rect (fast path) or a polygon command stream. */
247
202
  type Path = PolygonPath | RectPath;
248
203
 
204
+ /**
205
+ * Axis-aligned rectangle pose with optional rotation. The canonical pose
206
+ * shape used by `composeRectPose` and the `unionBounds` helper. Rotation is
207
+ * in radians, pivoted on the unrotated AABB center; absent === 0. Kit-side
208
+ * code that consumes rotation already reads `pose.rotation ?? 0`
209
+ * (`SceneCanvas.defaultDrawOne`, `rotate/handle.ts`, `pathInWorld.ts`), so
210
+ * the slot exists on every default scene whether or not the consumer
211
+ * populates it.
212
+ */
213
+ interface RectPose {
214
+ x: number;
215
+ y: number;
216
+ width: number;
217
+ height: number;
218
+ /** Rotation in radians around the unrotated AABB center. Absent === 0. */
219
+ rotation?: number;
220
+ }
249
221
  /**
250
222
  * # SceneNode — the thing in the scene
251
223
  *
@@ -631,11 +603,18 @@ interface TextureHandle {
631
603
  * equivalent to `{ fill: 'solid', color: '#abc' }`. Pattern paints must set
632
604
  * `fill: 'pattern'` explicitly.
633
605
  *
634
- * The `'pattern'` variant's payload is a `TextureHandle` (registered via
635
- * `registerTexture()`). The kit-level factory `createTilePattern` (and the
636
- * `patterns-builtin` catalog: `hatch`, `crosshatch`, `dots`, `chunks`)
637
- * produces these handles by rendering a tile to an `OffscreenCanvas` and
638
- * registering the resulting `ImageBitmap` as a GL texture.
606
+ * The `'pattern'` variant's payload is either a `TilePatternSpec` plain
607
+ * data naming one of the built-in tiles, which survives serialization — or a
608
+ * `TextureHandle` for a tile the consumer built itself via
609
+ * `createTilePattern()`. A handle is a session-scoped registry key, so a
610
+ * paint carrying one cannot be persisted or exported; prefer the spec.
611
+ *
612
+ * `units` on a pattern names the space the tile's origin and scale live in,
613
+ * not the space of any geometry (a pattern has none). Under `'bounds'` the
614
+ * tile anchors to the painted node's box, so the pattern travels with the
615
+ * node and a resize reveals more tiles rather than stretching them;
616
+ * `fillInPoseFrame` resolves that to a `'local'` paint with an explicit
617
+ * `origin` before the renderer sees it.
639
618
  */
640
619
  type FillStyle = {
641
620
  fill?: 'solid';
@@ -643,7 +622,12 @@ type FillStyle = {
643
622
  opacity?: number;
644
623
  } | {
645
624
  fill: 'pattern';
646
- pattern: TextureHandle;
625
+ pattern: TextureHandle | TilePatternSpec;
626
+ units?: GradientUnits;
627
+ origin?: {
628
+ x: number;
629
+ y: number;
630
+ };
647
631
  opacity?: number;
648
632
  } | {
649
633
  fill: 'linear-gradient';
@@ -656,6 +640,7 @@ type FillStyle = {
656
640
  y: number;
657
641
  };
658
642
  stops: GradStop[];
643
+ units?: GradientUnits;
659
644
  opacity?: number;
660
645
  } | {
661
646
  fill: 'radial-gradient';
@@ -665,6 +650,7 @@ type FillStyle = {
665
650
  };
666
651
  radius: number;
667
652
  stops: GradStop[];
653
+ units?: GradientUnits;
668
654
  opacity?: number;
669
655
  } | {
670
656
  fill: 'conic-gradient';
@@ -674,8 +660,56 @@ type FillStyle = {
674
660
  };
675
661
  angle: number;
676
662
  stops: GradStop[];
663
+ units?: GradientUnits;
677
664
  opacity?: number;
678
665
  };
666
+ /**
667
+ * Which coordinate space a gradient's geometry (`from`/`to`, `center`,
668
+ * `radius`) is expressed in. SVG's `gradientUnits`, plus an option for
669
+ * paints that are themselves viewport furniture.
670
+ *
671
+ * - `'bounds'`: fractions of the painted node's bounding box, `0..1` on each
672
+ * axis — SVG `objectBoundingBox`. Resolved by the node painter, before the
673
+ * renderer sees it, so the paint follows the node through moves, resizes
674
+ * and rotation. What a gradient on a scene node wants.
675
+ * - `'local'`: the coordinate space the geometry was handed to the renderer
676
+ * in — the enclosing group's frame. For draw commands a consumer builds
677
+ * itself, where "the coordinates I just wrote" is the useful frame.
678
+ * - `'world'`: scene coordinates. The paint stays put under pan and zoom
679
+ * while the geometry moves through it. SVG `userSpaceOnUse`. Requires the
680
+ * renderer to have been handed a view matrix; falls back to `'screen'`
681
+ * when it has not.
682
+ * - `'screen'`: CSS pixels of the drawing surface. For overlays and
683
+ * viewport-fixed washes that should not move with the content at all.
684
+ *
685
+ * Defaults to `'screen'`, which is the behavior every gradient had before
686
+ * this field existed.
687
+ */
688
+ type GradientUnits = 'bounds' | 'local' | 'world' | 'screen';
689
+ /**
690
+ * A built-in tile, described as plain data. The serializable half of the
691
+ * pattern paint: `resolvePatternSpec()` turns one into a `TextureHandle`
692
+ * at paint time, memoized so identical specs share a texture.
693
+ *
694
+ * `size` is the tile's edge length, and doubles as its extent in paint
695
+ * space — a bigger `size` rasterizes a bigger tile rather than magnifying
696
+ * a small one, which is why there is no separate scale field.
697
+ */
698
+ interface TilePatternSpec {
699
+ tile: 'hatch' | 'crosshatch' | 'dots' | 'chunks';
700
+ color: string;
701
+ /** `chunks` only — omit for a transparent tile background. */
702
+ bg?: string;
703
+ size?: number;
704
+ /** `hatch` / `crosshatch`. */
705
+ lineWidth?: number;
706
+ /** `dots`. */
707
+ radius?: number;
708
+ /** `chunks`. */
709
+ density?: number;
710
+ chunkSize?: number;
711
+ seed?: number;
712
+ }
679
713
  /** A single color stop within a gradient. `offset` is in 0..1. */
680
714
  interface GradStop {
681
715
  offset: number;
@@ -791,6 +825,19 @@ interface TextStyle {
791
825
  underline?: boolean;
792
826
  /** Default `false`. */
793
827
  strikethrough?: boolean;
828
+ /**
829
+ * Outline painted over the glyph fill. Omitted (the default) means no
830
+ * outline — there is no such thing as a default text stroke.
831
+ *
832
+ * Only glyphs on the outline tier are stroked: above
833
+ * `textOutlineMinScreenSize` a glyph is a real `PolygonPath`, so it gets
834
+ * the ordinary tessellated ribbon with real joins, caps and miters, in any
835
+ * paint. Below it a glyph is a sampled distance field with no geometry to
836
+ * stroke, and it renders unstroked rather than approximated. `width` is in
837
+ * world units, like every other stroke in the kit — it does not scale with
838
+ * `fontSize`.
839
+ */
840
+ stroke?: Stroke;
794
841
  }
795
842
 
796
843
  /**
@@ -818,6 +865,9 @@ interface ResolvedRun {
818
865
  fontWeight: number;
819
866
  fontStyle: 'normal' | 'italic';
820
867
  fill: FillStyle;
868
+ /** Outline over this run's glyphs, or absent for none. Painted only on the
869
+ * outline tier — a distance field has no geometry to stroke. */
870
+ stroke?: Stroke;
821
871
  /** Extra advance added after each glyph of this run, in world units. */
822
872
  letterSpacing: number;
823
873
  /** Draw a rule below this run's baseline. Additive over the node style. */
@@ -944,6 +994,10 @@ interface ImageDrawCommand {
944
994
  w: number;
945
995
  h: number;
946
996
  opacity?: number;
997
+ /** Magnification filter. `'linear'` (default) smooths; `'nearest'` shows
998
+ * device pixels as hard squares — required by anything magnifying a
999
+ * framebuffer readback, where blur destroys the point of the readback. */
1000
+ sampling?: 'linear' | 'nearest';
947
1001
  }
948
1002
  /**
949
1003
  * Custom shader draw command. The renderer generates a quad over `bounds`
@@ -968,4 +1022,4 @@ interface ShaderDrawCommand {
968
1022
  };
969
1023
  }
970
1024
 
971
- export type { Bounds as B, DrawCommand as D, History as H, Node as N, Op as O, PathDrawCommand as P, Scene as S, View as V, ViewportDims as a, NodeId as b, Path as c, PoseComposition as d };
1025
+ export type { Bounds as B, DrawCommand as D, History as H, Node as N, Op as O, PathDrawCommand as P, Scene as S, View as V, ViewportDims as a, NodeId as b, Path as c };
@@ -29,10 +29,12 @@ interface SavedSnapshot {
29
29
  state: unknown;
30
30
  savedAt: number;
31
31
  }
32
+ /** `auto` follows the OS; the other two are an explicit choice. */
33
+ type LabMode = 'auto' | 'light' | 'dark';
32
34
  interface LabStoreState {
33
35
  workspaces: WorkspaceRecord[];
34
36
  savedSnapshots: SavedSnapshot[];
35
- theme: 'light' | 'interstellar' | 'auto';
37
+ mode: LabMode;
36
38
  }
37
39
  interface StorageAdapter {
38
40
  read(key: string): string | null;
@@ -48,7 +50,7 @@ interface ExperimentStateHandle<TS, TC> {
48
50
  interface CreateLabStoreOptions {
49
51
  storageKey: string;
50
52
  storage: StorageAdapter;
51
- initialTheme?: 'light' | 'interstellar' | 'auto';
53
+ initialMode?: LabMode;
52
54
  }
53
55
  type InstrumentSerializers = Record<string, {
54
56
  serialize?: (state: unknown) => unknown;
@@ -73,7 +75,7 @@ interface LabStoreActions {
73
75
  loadSnapshot: (snapshotId: string, workspaceId: string) => void;
74
76
  deleteSnapshot: (snapshotId: string) => void;
75
77
  listSnapshots: (workspaceId?: string) => SavedSnapshot[];
76
- setTheme: (theme: 'light' | 'interstellar' | 'auto') => void;
78
+ setMode: (mode: LabMode) => void;
77
79
  }
78
80
  type LabStore = StoreApi<LabStoreState & LabStoreActions> & {
79
81
  registerSerializers: (s: InstrumentSerializers) => void;
@@ -99,4 +101,4 @@ declare function useWorkspaceId(): string;
99
101
  declare function useExperimentState<TS = unknown, TC = unknown>(): ExperimentStateHandle<TS, TC>;
100
102
 
101
103
  export { LabStoreContext as b, LabStoreProvider as c, WorkspaceIdContext as f, WorkspaceIdProvider as g, createLabStore as h, createMemoryAdapter as i, useExperimentState as j, useLabStore as k, localStorageAdapter as l, useWorkspaceId as m, noneAdapter as n, sessionStorageAdapter as s, urlHashAdapter as u };
102
- export type { CreateLabStoreOptions as C, ExperimentStateHandle as E, InstrumentSerializers as I, LabStore as L, StorageAdapter as S, UndoStack as U, WorkspaceRecord as W, LabStoreActions as a, LabStoreState as d, SavedSnapshot as e };
104
+ export type { CreateLabStoreOptions as C, ExperimentStateHandle as E, InstrumentSerializers as I, LabStore as L, StorageAdapter as S, UndoStack as U, WorkspaceRecord as W, LabStoreActions as a, LabStoreState as d, SavedSnapshot as e, LabMode as o };
@@ -183,17 +183,18 @@ function createLabStore(options) {
183
183
  hydratedSnapshots = [];
184
184
  }
185
185
  }
186
- const themeRaw = options.storage.read(labStorageKey(options.storageKey, "theme"));
187
- let hydratedTheme;
188
- if (themeRaw === "light" || themeRaw === "interstellar" || themeRaw === "auto") {
189
- hydratedTheme = themeRaw;
186
+ const modeRaw = options.storage.read(labStorageKey(options.storageKey, "theme"));
187
+ const stored = modeRaw === "interstellar" ? "dark" : modeRaw;
188
+ let hydratedMode;
189
+ if (stored === "light" || stored === "dark" || stored === "auto") {
190
+ hydratedMode = stored;
190
191
  } else {
191
- hydratedTheme = options.initialTheme ?? "auto";
192
+ hydratedMode = options.initialMode ?? "auto";
192
193
  }
193
194
  const store = createStore()((set, get) => ({
194
195
  workspaces: hydratedWorkspaces,
195
196
  savedSnapshots: hydratedSnapshots,
196
- theme: hydratedTheme,
197
+ mode: hydratedMode,
197
198
  addWorkspace: (record) => {
198
199
  set((s) => ({
199
200
  workspaces: [...s.workspaces, { ...record, undoStack: emptyUndoStack() }]
@@ -300,8 +301,8 @@ function createLabStore(options) {
300
301
  const filtered = workspaceId ? all.filter((sn) => sn.workspaceId === workspaceId) : all;
301
302
  return [...filtered].sort((a, b) => b.savedAt - a.savedAt);
302
303
  },
303
- setTheme: (theme) => {
304
- set({ theme });
304
+ setMode: (mode) => {
305
+ set({ mode });
305
306
  scheduleFlush();
306
307
  }
307
308
  }));
@@ -317,7 +318,7 @@ function createLabStore(options) {
317
318
  labStorageKey(options.storageKey, "saves"),
318
319
  JSON.stringify(s.savedSnapshots)
319
320
  );
320
- options.storage.write(labStorageKey(options.storageKey, "theme"), s.theme);
321
+ options.storage.write(labStorageKey(options.storageKey, "theme"), s.mode);
321
322
  flushTimer = null;
322
323
  }, 300);
323
324
  }
@@ -346,5 +347,5 @@ function useExperimentState() {
346
347
  }
347
348
 
348
349
  export { LabStoreContext, LabStoreProvider, WorkspaceIdContext, WorkspaceIdProvider, createLabStore, createMemoryAdapter, decodeUrlHash, deserializeWorkspaces, emptyUndoStack, encodeUrlHash, labStorageKey, localStorageAdapter, noneAdapter, serializeWorkspaces, sessionStorageAdapter, urlHashAdapter, useExperimentState, useLabStore, useWorkspaceId };
349
- //# sourceMappingURL=chunk-SSMHPMDV.js.map
350
- //# sourceMappingURL=chunk-SSMHPMDV.js.map
350
+ //# sourceMappingURL=chunk-53XSBIUK.js.map
351
+ //# sourceMappingURL=chunk-53XSBIUK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/state/helpers.ts","../src/state/adapters.ts","../src/state/context.tsx","../src/state/store.ts","../src/state/useExperimentState.ts"],"names":["useContext","useStore"],"mappings":";;;;;;AAEO,SAAS,aAAA,CACd,YACA,MAAA,EACQ;AACR,EAAA,OAAO,CAAA,GAAA,EAAM,UAAU,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AACnC;AAEO,SAAS,cAAc,KAAA,EAAuB;AACnD,EAAA,OAAO,IAAA,CAAK,kBAAA,CAAmB,KAAK,CAAC,CAAA;AACvC;AAEO,SAAS,cAAc,IAAA,EAA6B;AACzD,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,IAAI;AACF,IAAA,OAAO,kBAAA,CAAmB,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,EACtC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEO,SAAS,cAAA,GAA4B;AAC1C,EAAA,OAAO,EAAE,IAAA,EAAM,EAAC,EAAG,MAAA,EAAQ,EAAC,EAAE;AAChC;AAIO,SAAS,mBAAA,CACd,YACA,WAAA,EACQ;AACR,EAAA,MAAM,OAAA,GAA8B,WAAW,GAAA,CAAI,CAAC,EAAE,SAAA,EAAW,KAAA,EAAO,GAAG,CAAA,EAAE,KAAM;AACjF,IAAA,MAAM,CAAA,GAAI,WAAA,CAAY,CAAA,CAAE,cAAc,CAAA;AACtC,IAAA,OAAO;AAAA,MACL,GAAG,CAAA;AAAA,MACH,KAAA,EAAO,GAAG,SAAA,GAAY,CAAA,CAAE,UAAU,CAAA,CAAE,KAAK,IAAI,CAAA,CAAE;AAAA,KACjD;AAAA,EACF,CAAC,CAAA;AACD,EAAA,OAAO,IAAA,CAAK,UAAU,OAAO,CAAA;AAC/B;AAEO,SAAS,qBAAA,CACd,KACA,aAAA,EACmB;AACnB,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC9B,IAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM;AACxB,MAAA,MAAM,CAAA,GAAI,aAAA,CAAc,CAAA,CAAE,cAAc,CAAA;AACxC,MAAA,OAAO;AAAA,QACL,GAAG,CAAA;AAAA,QACH,KAAA,EAAO,GAAG,WAAA,GAAc,CAAA,CAAE,YAAY,CAAA,CAAE,KAAK,IAAI,CAAA,CAAE,KAAA;AAAA,QACnD,WAAW,cAAA;AAAe,OAC5B;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAA,CAAA,MAAQ;AACN,IAAA,OAAA,CAAQ,KAAK,uEAAuE,CAAA;AACpF,IAAA,OAAO,EAAC;AAAA,EACV;AACF;;;ACzDO,IAAM,mBAAA,GAAsC;AAAA,EACjD,IAAA,EAAM,CAAC,GAAA,KAAQ;AACb,IAAA,IAAI;AACF,MAAA,OAAO,YAAA,CAAa,QAAQ,GAAG,CAAA;AAAA,IACjC,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF,CAAA;AAAA,EACA,KAAA,EAAO,CAAC,GAAA,EAAK,KAAA,KAAU;AACrB,IAAA,IAAI;AACF,MAAA,YAAA,CAAa,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,IACjC,SAAS,CAAA,EAAG;AACV,MAAA,OAAA,CAAQ,IAAA,CAAK,uCAAuC,CAAC,CAAA;AAAA,IACvD;AAAA,EACF,CAAA;AAAA,EACA,MAAA,EAAQ,CAAC,GAAA,KAAQ;AACf,IAAA,IAAI;AACF,MAAA,YAAA,CAAa,WAAW,GAAG,CAAA;AAAA,IAC7B,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACF;AAEO,IAAM,qBAAA,GAAwC;AAAA,EACnD,IAAA,EAAM,CAAC,GAAA,KAAQ;AACb,IAAA,IAAI;AACF,MAAA,OAAO,cAAA,CAAe,QAAQ,GAAG,CAAA;AAAA,IACnC,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF,CAAA;AAAA,EACA,KAAA,EAAO,CAAC,GAAA,EAAK,KAAA,KAAU;AACrB,IAAA,IAAI;AACF,MAAA,cAAA,CAAe,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,IACnC,SAAS,CAAA,EAAG;AACV,MAAA,OAAA,CAAQ,IAAA,CAAK,yCAAyC,CAAC,CAAA;AAAA,IACzD;AAAA,EACF,CAAA;AAAA,EACA,MAAA,EAAQ,CAAC,GAAA,KAAQ;AACf,IAAA,IAAI;AACF,MAAA,cAAA,CAAe,WAAW,GAAG,CAAA;AAAA,IAC/B,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACF;AAEA,IAAM,cAAA,GAAiB,OAAO,MAAA,KAAW,WAAA;AAEzC,SAAS,WAAA,GAAsC;AAC7C,EAAA,IAAI,CAAC,cAAA,EAAgB,OAAO,EAAC;AAC7B,EAAA,MAAM,GAAA,GAAM,cAAc,MAAA,CAAO,QAAA,CAAS,KAAK,OAAA,CAAQ,IAAA,EAAM,EAAE,CAAC,CAAA;AAChE,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,EAAC;AAClB,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,EACvB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AAEA,SAAS,aAAa,GAAA,EAAmC;AACvD,EAAA,IAAI,CAAC,cAAA,EAAgB;AACrB,EAAA,MAAM,OAAA,GAAU,aAAA,CAAc,IAAA,CAAK,SAAA,CAAU,GAAG,CAAC,CAAA;AACjD,EAAA,MAAA,CAAO,QAAQ,YAAA,CAAa,IAAA,EAAM,EAAA,EAAI,CAAA,CAAA,EAAI,OAAO,CAAA,CAAE,CAAA;AACrD;AAEO,IAAM,cAAA,GAAiC;AAAA,EAC5C,MAAM,CAAC,GAAA,KAAQ,WAAA,EAAY,CAAE,GAAG,CAAA,IAAK,IAAA;AAAA,EACrC,KAAA,EAAO,CAAC,GAAA,EAAK,KAAA,KAAU;AACrB,IAAA,MAAM,MAAM,WAAA,EAAY;AACxB,IAAA,GAAA,CAAI,GAAG,CAAA,GAAI,KAAA;AACX,IAAA,YAAA,CAAa,GAAG,CAAA;AAAA,EAClB,CAAA;AAAA,EACA,MAAA,EAAQ,CAAC,GAAA,KAAQ;AACf,IAAA,MAAM,MAAM,WAAA,EAAY;AACxB,IAAA,OAAO,IAAI,GAAG,CAAA;AACd,IAAA,YAAA,CAAa,GAAG,CAAA;AAAA,EAClB;AACF;AAEO,SAAS,mBAAA,GAAsC;AACpD,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAoB;AACtC,EAAA,OAAO;AAAA,IACL,MAAM,CAAC,GAAA,KAAQ,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA,IAAK,IAAA;AAAA,IACjC,KAAA,EAAO,CAAC,GAAA,EAAK,KAAA,KAAU;AACrB,MAAA,KAAA,CAAM,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,IACtB,CAAA;AAAA,IACA,MAAA,EAAQ,CAAC,GAAA,KAAQ;AACf,MAAA,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,IAClB;AAAA,GACF;AACF;AAEO,IAAM,WAAA,GAA8B;AAAA,EACzC,MAAM,MAAM,IAAA;AAAA,EACZ,OAAO,MAAM;AAAA,EAAC,CAAA;AAAA,EACd,QAAQ,MAAM;AAAA,EAAC;AACjB;AC9FO,IAAM,eAAA,GAAkB,cAA2B,IAAI;AAEvD,SAAS,gBAAA,CAAiB;AAAA,EAC/B,KAAA;AAAA,EACA;AACF,CAAA,EAGiB;AACf,EAAA,uBAAO,GAAA,CAAC,gBAAgB,QAAA,EAAhB,EAAyB,OAAO,EAAE,KAAA,IAAU,QAAA,EAAS,CAAA;AAC/D;AAEO,SAAS,WAAA,GAAgE;AAC9E,EAAA,MAAM,GAAA,GAAM,WAAW,eAAe,CAAA;AACtC,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,MAAM,6DAA6D,CAAA;AACvF,EAAA,OAAO,QAAA,CAAS,IAAI,KAAK,CAAA;AAC3B;AAEO,IAAM,kBAAA,GAAqB,cAA6B,IAAI;AAE5D,SAAS,mBAAA,CAAoB;AAAA,EAClC,WAAA;AAAA,EACA;AACF,CAAA,EAGiB;AACf,EAAA,2BAAQ,kBAAA,CAAmB,QAAA,EAAnB,EAA4B,KAAA,EAAO,aAAc,QAAA,EAAS,CAAA;AACpE;AAEO,SAAS,cAAA,GAAyB;AACvC,EAAA,MAAM,EAAA,GAAK,WAAW,kBAAkB,CAAA;AACxC,EAAA,IAAI,CAAC,EAAA,EAAI,MAAM,IAAI,MAAM,mEAAmE,CAAA;AAC5F,EAAA,OAAO,EAAA;AACT;ACDO,SAAS,eAAe,OAAA,EAA0C;AACvE,EAAA,IAAI,cAAqC,EAAC;AAC1C,EAAA,IAAI,UAAA,GAAmD,IAAA;AAEvD,EAAA,MAAM,aAAA,GAAgB,QAAQ,OAAA,CAAQ,IAAA,CAAK,cAAc,OAAA,CAAQ,UAAA,EAAY,YAAY,CAAC,CAAA;AAC1F,EAAA,IAAI,qBAAwC,EAAC;AAC7C,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,kBAAA,GAAqB,qBAAA,CAAsB,eAAe,WAAW,CAAA;AAAA,EACvE;AAEA,EAAA,MAAM,QAAA,GAAW,QAAQ,OAAA,CAAQ,IAAA,CAAK,cAAc,OAAA,CAAQ,UAAA,EAAY,OAAO,CAAC,CAAA;AAChF,EAAA,IAAI,oBAAqC,EAAC;AAC1C,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,IAAI;AACF,MAAA,iBAAA,GAAoB,IAAA,CAAK,MAAM,QAAQ,CAAA;AAAA,IACzC,CAAA,CAAA,MAAQ;AACN,MAAA,OAAA,CAAQ,KAAK,0DAA0D,CAAA;AACvE,MAAA,iBAAA,GAAoB,EAAC;AAAA,IACvB;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,CAAQ,IAAA,CAAK,cAAc,OAAA,CAAQ,UAAA,EAAY,OAAO,CAAC,CAAA;AAE/E,EAAA,MAAM,MAAA,GAAS,OAAA,KAAY,cAAA,GAAiB,MAAA,GAAS,OAAA;AACrD,EAAA,IAAI,YAAA;AACJ,EAAA,IAAI,MAAA,KAAW,OAAA,IAAW,MAAA,KAAW,MAAA,IAAU,WAAW,MAAA,EAAQ;AAChE,IAAA,YAAA,GAAe,MAAA;AAAA,EACjB,CAAA,MAAO;AACL,IAAA,YAAA,GAAe,QAAQ,WAAA,IAAe,MAAA;AAAA,EACxC;AAEA,EAAA,MAAM,KAAA,GAAQ,WAAA,EAA6C,CAAE,CAAC,KAAK,GAAA,MAAS;AAAA,IAC1E,UAAA,EAAY,kBAAA;AAAA,IACZ,cAAA,EAAgB,iBAAA;AAAA,IAChB,IAAA,EAAM,YAAA;AAAA,IAEN,YAAA,EAAc,CAAC,MAAA,KAAW;AACxB,MAAA,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QACV,UAAA,EAAY,CAAC,GAAG,CAAA,CAAE,UAAA,EAAY,EAAE,GAAG,MAAA,EAAQ,SAAA,EAAW,cAAA,EAAe,EAAG;AAAA,OAC1E,CAAE,CAAA;AACF,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAAA,IAEA,eAAA,EAAiB,CAAC,EAAA,KAAO;AACvB,MAAA,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,UAAA,EAAY,CAAA,CAAE,UAAA,CAAW,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,GAAE,CAAE,CAAA;AACpE,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAAA,IAEA,oBAAA,EAAsB,CAAC,EAAA,EAAI,IAAA,KAAS;AAClC,MAAA,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QACV,UAAA,EAAY,CAAA,CAAE,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,KAAM;AAClC,UAAA,IAAI,CAAA,CAAE,EAAA,KAAO,EAAA,EAAI,OAAO,CAAA;AACxB,UAAA,MAAM,YACJ,OAAO,IAAA,KAAS,aAAc,IAAA,CAAoC,CAAA,CAAE,KAAK,CAAA,GAAI,IAAA;AAC/E,UAAA,OAAO,EAAE,GAAG,CAAA,EAAG,KAAA,EAAO,SAAA,EAAU;AAAA,QAClC,CAAC;AAAA,OACH,CAAE,CAAA;AACF,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAAA,IAEA,qBAAA,EAAuB,CAAC,EAAA,EAAI,GAAA,EAAK,KAAA,KAAU;AACzC,MAAA,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QACV,UAAA,EAAY,CAAA,CAAE,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,KAAM;AAClC,UAAA,IAAI,CAAA,CAAE,EAAA,KAAO,EAAA,EAAI,OAAO,CAAA;AACxB,UAAA,OAAO;AAAA,YACL,GAAG,CAAA;AAAA,YACH,MAAA,EAAQ,EAAE,GAAI,CAAA,CAAE,QAAoC,CAAC,GAAa,GAAG,KAAA;AAAM,WAC7E;AAAA,QACF,CAAC;AAAA,OACH,CAAE,CAAA;AACF,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAAA,IAEA,mBAAA,EAAqB,CAAC,EAAA,EAAI,IAAA,KAAS;AACjC,MAAA,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QACV,UAAA,EAAY,CAAA,CAAE,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,EAAA,GAAK,EAAE,GAAG,CAAA,EAAG,IAAA,KAAS,CAAE;AAAA,OACxE,CAAE,CAAA;AACF,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAAA,IAEA,wBAAA,EAA0B,CAAC,EAAA,EAAI,IAAA,KAAS;AACtC,MAAA,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QACV,UAAA,EAAY,CAAA,CAAE,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,KAAM;AAClC,UAAA,IAAI,CAAA,CAAE,EAAA,KAAO,EAAA,EAAI,OAAO,CAAA;AACxB,UAAA,MAAM,SAAA,GACJ,OAAO,IAAA,KAAS,UAAA,GACX,IAAA;AAAA,YACC,CAAA,CAAE;AAAA,WACJ,GACA,IAAA;AACN,UAAA,OAAO,EAAE,GAAG,CAAA,EAAG,SAAA,EAAU;AAAA,QAC3B,CAAC;AAAA,OACH,CAAE,CAAA;AAAA,IACJ,CAAA;AAAA,IAEA,sBAAA,EAAwB,CAAC,EAAA,EAAI,cAAA,KAAmB;AAC9C,MAAA,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QACV,UAAA,EAAY,CAAA,CAAE,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,EAAA,GAAK,EAAE,GAAG,CAAA,EAAG,cAAA,KAAmB,CAAE;AAAA,OAClF,CAAE,CAAA;AACF,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAAA,IAEA,YAAA,EAAc,CAAC,WAAA,EAAa,IAAA,KAAS;AACnC,MAAA,MAAM,SAAA,GAAY,KAAI,CAAE,UAAA,CAAW,KAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,WAAW,CAAA;AACnE,MAAA,IAAI,CAAC,SAAA,EAAW;AAChB,MAAA,MAAM,GAAA,GAAM,WAAA,CAAY,SAAA,CAAU,cAAc,CAAA;AAChD,MAAA,MAAM,eAAA,GAAkB,GAAA,EAAK,SAAA,GACzB,GAAA,CAAI,SAAA,CAAU,UAAU,KAAK,CAAA,GAC7B,eAAA,CAAgB,SAAA,CAAU,KAAK,CAAA;AACnC,MAAA,MAAM,YAAA,GAAe,eAAA,CAAgB,SAAA,CAAU,MAAM,CAAA;AACrD,MAAA,MAAM,MAAA,GAAS,GAAA,EAAI,CAAE,cAAA,CAAe,OAAO,CAAC,CAAA,EAAG,EAAA,KAAQ,EAAA,CAAG,OAAA,GAAU,CAAA,GAAI,EAAA,CAAG,OAAA,GAAU,GAAI,CAAC,CAAA;AAC1F,MAAA,MAAM,UAAU,IAAA,CAAK,GAAA,CAAI,KAAK,GAAA,EAAI,EAAG,SAAS,CAAC,CAAA;AAC/C,MAAA,MAAM,QAAA,GAA0B;AAAA,QAC9B,EAAA,EAAI,OAAO,UAAA,EAAW;AAAA,QACtB,IAAA;AAAA,QACA,WAAA;AAAA,QACA,gBAAgB,SAAA,CAAU,cAAA;AAAA,QAC1B,MAAA,EAAQ,YAAA;AAAA,QACR,KAAA,EAAO,eAAA;AAAA,QACP;AAAA,OACF;AACA,MAAA,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,cAAA,EAAgB,CAAC,GAAG,CAAA,CAAE,cAAA,EAAgB,QAAQ,CAAA,EAAE,CAAE,CAAA;AAChE,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAAA,IAEA,YAAA,EAAc,CAAC,UAAA,EAAY,WAAA,KAAgB;AACzC,MAAA,MAAM,QAAA,GAAW,KAAI,CAAE,cAAA,CAAe,KAAK,CAAC,EAAA,KAAO,EAAA,CAAG,EAAA,KAAO,UAAU,CAAA;AACvE,MAAA,IAAI,CAAC,QAAA,EAAU;AACf,MAAA,MAAM,SAAA,GAAY,KAAI,CAAE,UAAA,CAAW,KAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,WAAW,CAAA;AACnE,MAAA,IAAI,CAAC,SAAA,EAAW;AAChB,MAAA,IAAI,QAAA,CAAS,cAAA,KAAmB,SAAA,CAAU,cAAA,EAAgB;AACxD,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN,CAAA,qDAAA,EAAwD,QAAA,CAAS,cAAc,CAAA,YAAA,EAAe,UAAU,cAAc,CAAA,mBAAA;AAAA,SACxH;AACA,QAAA;AAAA,MACF;AACA,MAAA,MAAM,GAAA,GAAM,WAAA,CAAY,QAAA,CAAS,cAAc,CAAA;AAC/C,MAAA,MAAM,aAAA,GAAgB,KAAK,WAAA,GAAc,GAAA,CAAI,YAAY,QAAA,CAAS,KAAK,IAAI,QAAA,CAAS,KAAA;AACpF,MAAA,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QACV,UAAA,EAAY,EAAE,UAAA,CAAW,GAAA;AAAA,UAAI,CAAC,CAAA,KAC5B,CAAA,CAAE,EAAA,KAAO,WAAA,GAAc,EAAE,GAAG,CAAA,EAAG,KAAA,EAAO,aAAA,EAAe,MAAA,EAAQ,QAAA,CAAS,QAAO,GAAI;AAAA;AACnF,OACF,CAAE,CAAA;AACF,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAAA,IAEA,cAAA,EAAgB,CAAC,UAAA,KAAe;AAC9B,MAAA,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QACV,cAAA,EAAgB,EAAE,cAAA,CAAe,MAAA,CAAO,CAAC,EAAA,KAAO,EAAA,CAAG,OAAO,UAAU;AAAA,OACtE,CAAE,CAAA;AACF,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAAA,IAEA,aAAA,EAAe,CAAC,WAAA,KAAgB;AAC9B,MAAA,MAAM,GAAA,GAAM,KAAI,CAAE,cAAA;AAClB,MAAA,MAAM,QAAA,GAAW,cAAc,GAAA,CAAI,MAAA,CAAO,CAAC,EAAA,KAAO,EAAA,CAAG,WAAA,KAAgB,WAAW,CAAA,GAAI,GAAA;AACpF,MAAA,OAAO,CAAC,GAAG,QAAQ,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,OAAA,GAAU,CAAA,CAAE,OAAO,CAAA;AAAA,IAC3D,CAAA;AAAA,IAEA,OAAA,EAAS,CAAC,IAAA,KAAS;AACjB,MAAA,GAAA,CAAI,EAAE,MAAM,CAAA;AACZ,MAAA,aAAA,EAAc;AAAA,IAChB;AAAA,GACF,CAAE,CAAA;AAEF,EAAA,SAAS,aAAA,GAAsB;AAC7B,IAAA,IAAI,UAAA,eAAyB,UAAU,CAAA;AACvC,IAAA,UAAA,GAAa,WAAW,MAAM;AAC5B,MAAA,MAAM,CAAA,GAAI,MAAM,QAAA,EAAS;AACzB,MAAA,OAAA,CAAQ,OAAA,CAAQ,KAAA;AAAA,QACd,aAAA,CAAc,OAAA,CAAQ,UAAA,EAAY,YAAY,CAAA;AAAA,QAC9C,mBAAA,CAAoB,CAAA,CAAE,UAAA,EAAY,WAAW;AAAA,OAC/C;AACA,MAAA,OAAA,CAAQ,OAAA,CAAQ,KAAA;AAAA,QACd,aAAA,CAAc,OAAA,CAAQ,UAAA,EAAY,OAAO,CAAA;AAAA,QACzC,IAAA,CAAK,SAAA,CAAU,CAAA,CAAE,cAAc;AAAA,OACjC;AACA,MAAA,OAAA,CAAQ,OAAA,CAAQ,MAAM,aAAA,CAAc,OAAA,CAAQ,YAAY,OAAO,CAAA,EAAG,EAAE,IAAI,CAAA;AACxE,MAAA,UAAA,GAAa,IAAA;AAAA,IACf,GAAG,GAAG,CAAA;AAAA,EACR;AAEA,EAAA,OAAO,MAAA,CAAO,OAAO,KAAA,EAAO;AAAA,IAC1B,oBAAoB,CAAA,EAA0B;AAC5C,MAAA,WAAA,GAAc,CAAA;AAAA,IAChB;AAAA,GACD,CAAA;AACH;AC9NO,SAAS,kBAAA,GAAgF;AAC9F,EAAA,MAAM,GAAA,GAAMA,WAAW,eAAe,CAAA;AACtC,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,MAAM,oEAAoE,CAAA;AAE9F,EAAA,MAAM,WAAA,GAAcA,WAAW,kBAAkB,CAAA;AACjD,EAAA,IAAI,CAAC,WAAA;AACH,IAAA,MAAM,IAAI,MAAM,uEAAuE,CAAA;AAEzF,EAAA,MAAM,MAAA,GAASC,QAAAA,CAAS,GAAA,CAAI,KAAA,EAAO,CAAC,CAAA,KAAM,CAAA,CAAE,UAAA,CAAW,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,WAAW,CAAC,CAAA;AAExF,EAAA,IAAI,CAAC,MAAA,EAAQ,MAAM,IAAI,KAAA,CAAM,CAAA,qCAAA,EAAwC,WAAW,CAAA,CAAA,CAAG,CAAA;AAEnF,EAAA,MAAM,uBAAuBA,QAAAA,CAAS,GAAA,CAAI,OAAO,CAAC,CAAA,KAAM,EAAE,oBAAoB,CAAA;AAC9E,EAAA,MAAM,wBAAwBA,QAAAA,CAAS,GAAA,CAAI,OAAO,CAAC,CAAA,KAAM,EAAE,qBAAqB,CAAA;AAEhF,EAAA,OAAO;AAAA,IACL,OAAO,MAAA,CAAO,KAAA;AAAA,IACd,QAAQ,MAAA,CAAO,MAAA;AAAA,IACf,QAAA,EAAU,CAAC,IAAA,KACT,oBAAA,CAAqB,aAAa,IAAkD,CAAA;AAAA,IACtF,WAAW,CAAC,GAAA,EAAK,UAAU,qBAAA,CAAsB,WAAA,EAAa,KAAc,KAAc;AAAA,GAC5F;AACF","file":"chunk-53XSBIUK.js","sourcesContent":["import type { InstrumentSerializers, UndoStack, WorkspaceRecord } from './types';\n\nexport function labStorageKey(\n storageKey: string,\n bucket: 'workspaces' | 'saves' | 'theme',\n): string {\n return `lk:${storageKey}:${bucket}`;\n}\n\nexport function encodeUrlHash(value: string): string {\n return btoa(encodeURIComponent(value));\n}\n\nexport function decodeUrlHash(hash: string): string | null {\n if (!hash) return null;\n try {\n return decodeURIComponent(atob(hash));\n } catch {\n return null;\n }\n}\n\nexport function emptyUndoStack(): UndoStack {\n return { past: [], future: [] };\n}\n\ntype SerializedRecord = Omit<WorkspaceRecord, 'undoStack'>;\n\nexport function serializeWorkspaces(\n workspaces: WorkspaceRecord[],\n serializers: InstrumentSerializers,\n): string {\n const records: SerializedRecord[] = workspaces.map(({ undoStack: _undo, ...w }) => {\n const s = serializers[w.instrumentName];\n return {\n ...w,\n state: s?.serialize ? s.serialize(w.state) : w.state,\n };\n });\n return JSON.stringify(records);\n}\n\nexport function deserializeWorkspaces(\n raw: string,\n deserializers: InstrumentSerializers,\n): WorkspaceRecord[] {\n try {\n const records = JSON.parse(raw) as SerializedRecord[];\n return records.map((r) => {\n const d = deserializers[r.instrumentName];\n return {\n ...r,\n state: d?.deserialize ? d.deserialize(r.state) : r.state,\n undoStack: emptyUndoStack(),\n };\n });\n } catch {\n console.warn('[labkit] deserializeWorkspaces: failed to parse, returning empty list');\n return [];\n }\n}\n","import { decodeUrlHash, encodeUrlHash } from './helpers';\nimport type { StorageAdapter } from './types';\n\nexport const localStorageAdapter: StorageAdapter = {\n read: (key) => {\n try {\n return localStorage.getItem(key);\n } catch {\n return null;\n }\n },\n write: (key, value) => {\n try {\n localStorage.setItem(key, value);\n } catch (e) {\n console.warn('[labkit] localStorage write failed:', e);\n }\n },\n delete: (key) => {\n try {\n localStorage.removeItem(key);\n } catch {\n /* ignore */\n }\n },\n};\n\nexport const sessionStorageAdapter: StorageAdapter = {\n read: (key) => {\n try {\n return sessionStorage.getItem(key);\n } catch {\n return null;\n }\n },\n write: (key, value) => {\n try {\n sessionStorage.setItem(key, value);\n } catch (e) {\n console.warn('[labkit] sessionStorage write failed:', e);\n }\n },\n delete: (key) => {\n try {\n sessionStorage.removeItem(key);\n } catch {\n /* ignore */\n }\n },\n};\n\nconst URL_HASH_GUARD = typeof window !== 'undefined';\n\nfunction readHashMap(): Record<string, string> {\n if (!URL_HASH_GUARD) return {};\n const raw = decodeUrlHash(window.location.hash.replace(/^#/, ''));\n if (!raw) return {};\n try {\n return JSON.parse(raw) as Record<string, string>;\n } catch {\n return {};\n }\n}\n\nfunction writeHashMap(map: Record<string, string>): void {\n if (!URL_HASH_GUARD) return;\n const encoded = encodeUrlHash(JSON.stringify(map));\n window.history.replaceState(null, '', `#${encoded}`);\n}\n\nexport const urlHashAdapter: StorageAdapter = {\n read: (key) => readHashMap()[key] ?? null,\n write: (key, value) => {\n const map = readHashMap();\n map[key] = value;\n writeHashMap(map);\n },\n delete: (key) => {\n const map = readHashMap();\n delete map[key];\n writeHashMap(map);\n },\n};\n\nexport function createMemoryAdapter(): StorageAdapter {\n const store = new Map<string, string>();\n return {\n read: (key) => store.get(key) ?? null,\n write: (key, value) => {\n store.set(key, value);\n },\n delete: (key) => {\n store.delete(key);\n },\n };\n}\n\nexport const noneAdapter: StorageAdapter = {\n read: () => null,\n write: () => {},\n delete: () => {},\n};\n","import { createContext, type ReactElement, type ReactNode, useContext } from 'react';\nimport { useStore } from 'zustand/react';\nimport type { LabStore } from './store';\nimport type { LabStoreState } from './types';\n\ntype LabStoreCtx = { store: LabStore } | null;\n\nexport const LabStoreContext = createContext<LabStoreCtx>(null);\n\nexport function LabStoreProvider({\n store,\n children,\n}: {\n store: LabStore;\n children: ReactNode;\n}): ReactElement {\n return <LabStoreContext.Provider value={{ store }}>{children}</LabStoreContext.Provider>;\n}\n\nexport function useLabStore(): LabStoreState & ReturnType<LabStore['getState']> {\n const ctx = useContext(LabStoreContext);\n if (!ctx) throw new Error('[labkit] useLabStore must be used inside <LabStoreProvider>');\n return useStore(ctx.store);\n}\n\nexport const WorkspaceIdContext = createContext<string | null>(null);\n\nexport function WorkspaceIdProvider({\n workspaceId,\n children,\n}: {\n workspaceId: string;\n children: ReactNode;\n}): ReactElement {\n return <WorkspaceIdContext.Provider value={workspaceId}>{children}</WorkspaceIdContext.Provider>;\n}\n\nexport function useWorkspaceId(): string {\n const id = useContext(WorkspaceIdContext);\n if (!id) throw new Error('[labkit] useWorkspaceId must be used inside <WorkspaceIdProvider>');\n return id;\n}\n","import { createStore, type StoreApi } from 'zustand/vanilla';\nimport {\n deserializeWorkspaces,\n emptyUndoStack,\n labStorageKey,\n serializeWorkspaces,\n} from './helpers';\nimport type {\n CreateLabStoreOptions,\n InstrumentSerializers,\n LabMode,\n LabStoreState,\n SavedSnapshot,\n WorkspaceRecord,\n} from './types';\n\nexport interface LabStoreActions {\n addWorkspace: (record: Omit<WorkspaceRecord, 'undoStack'>) => void;\n removeWorkspace: (id: string) => void;\n updateWorkspaceState: <TS>(id: string, next: TS | ((prev: TS) => TS)) => void;\n updateWorkspaceConfig: <TC>(id: string, key: keyof TC, value: TC[keyof TC]) => void;\n updateWorkspaceView: (id: string, view: WorkspaceRecord['view']) => void;\n updateWorkspaceUndoStack: (\n id: string,\n next:\n | WorkspaceRecord['undoStack']\n | ((prev: WorkspaceRecord['undoStack']) => WorkspaceRecord['undoStack']),\n ) => void;\n setWorkspaceInstrument: (id: string, instrumentName: string) => void;\n saveSnapshot: (workspaceId: string, name: string) => void;\n loadSnapshot: (snapshotId: string, workspaceId: string) => void;\n deleteSnapshot: (snapshotId: string) => void;\n listSnapshots: (workspaceId?: string) => SavedSnapshot[];\n setMode: (mode: LabMode) => void;\n}\n\nexport type LabStore = StoreApi<LabStoreState & LabStoreActions> & {\n registerSerializers: (s: InstrumentSerializers) => void;\n};\n\nexport function createLabStore(options: CreateLabStoreOptions): LabStore {\n let serializers: InstrumentSerializers = {};\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n const workspacesRaw = options.storage.read(labStorageKey(options.storageKey, 'workspaces'));\n let hydratedWorkspaces: WorkspaceRecord[] = [];\n if (workspacesRaw) {\n hydratedWorkspaces = deserializeWorkspaces(workspacesRaw, serializers);\n }\n\n const savesRaw = options.storage.read(labStorageKey(options.storageKey, 'saves'));\n let hydratedSnapshots: SavedSnapshot[] = [];\n if (savesRaw) {\n try {\n hydratedSnapshots = JSON.parse(savesRaw) as SavedSnapshot[];\n } catch {\n console.warn('[labkit] failed to parse saved snapshots, starting empty');\n hydratedSnapshots = [];\n }\n }\n\n const modeRaw = options.storage.read(labStorageKey(options.storageKey, 'theme'));\n // `interstellar` was the dark mode's name back when it was a theme.\n const stored = modeRaw === 'interstellar' ? 'dark' : modeRaw;\n let hydratedMode: LabMode;\n if (stored === 'light' || stored === 'dark' || stored === 'auto') {\n hydratedMode = stored;\n } else {\n hydratedMode = options.initialMode ?? 'auto';\n }\n\n const store = createStore<LabStoreState & LabStoreActions>()((set, get) => ({\n workspaces: hydratedWorkspaces,\n savedSnapshots: hydratedSnapshots,\n mode: hydratedMode,\n\n addWorkspace: (record) => {\n set((s) => ({\n workspaces: [...s.workspaces, { ...record, undoStack: emptyUndoStack() }],\n }));\n scheduleFlush();\n },\n\n removeWorkspace: (id) => {\n set((s) => ({ workspaces: s.workspaces.filter((w) => w.id !== id) }));\n scheduleFlush();\n },\n\n updateWorkspaceState: (id, next) => {\n set((s) => ({\n workspaces: s.workspaces.map((w) => {\n if (w.id !== id) return w;\n const nextState =\n typeof next === 'function' ? (next as (prev: unknown) => unknown)(w.state) : next;\n return { ...w, state: nextState };\n }),\n }));\n scheduleFlush();\n },\n\n updateWorkspaceConfig: (id, key, value) => {\n set((s) => ({\n workspaces: s.workspaces.map((w) => {\n if (w.id !== id) return w;\n return {\n ...w,\n config: { ...(w.config as Record<string, unknown>), [key as string]: value },\n };\n }),\n }));\n scheduleFlush();\n },\n\n updateWorkspaceView: (id, view) => {\n set((s) => ({\n workspaces: s.workspaces.map((w) => (w.id === id ? { ...w, view } : w)),\n }));\n scheduleFlush();\n },\n\n updateWorkspaceUndoStack: (id, next) => {\n set((s) => ({\n workspaces: s.workspaces.map((w) => {\n if (w.id !== id) return w;\n const undoStack =\n typeof next === 'function'\n ? (next as (prev: WorkspaceRecord['undoStack']) => WorkspaceRecord['undoStack'])(\n w.undoStack,\n )\n : next;\n return { ...w, undoStack };\n }),\n }));\n },\n\n setWorkspaceInstrument: (id, instrumentName) => {\n set((s) => ({\n workspaces: s.workspaces.map((w) => (w.id === id ? { ...w, instrumentName } : w)),\n }));\n scheduleFlush();\n },\n\n saveSnapshot: (workspaceId, name) => {\n const workspace = get().workspaces.find((w) => w.id === workspaceId);\n if (!workspace) return;\n const reg = serializers[workspace.instrumentName];\n const serializedState = reg?.serialize\n ? reg.serialize(workspace.state)\n : structuredClone(workspace.state);\n const clonedConfig = structuredClone(workspace.config);\n const lastAt = get().savedSnapshots.reduce((m, sn) => (sn.savedAt > m ? sn.savedAt : m), 0);\n const savedAt = Math.max(Date.now(), lastAt + 1);\n const snapshot: SavedSnapshot = {\n id: crypto.randomUUID(),\n name,\n workspaceId,\n instrumentName: workspace.instrumentName,\n config: clonedConfig,\n state: serializedState,\n savedAt,\n };\n set((s) => ({ savedSnapshots: [...s.savedSnapshots, snapshot] }));\n scheduleFlush();\n },\n\n loadSnapshot: (snapshotId, workspaceId) => {\n const snapshot = get().savedSnapshots.find((sn) => sn.id === snapshotId);\n if (!snapshot) return;\n const workspace = get().workspaces.find((w) => w.id === workspaceId);\n if (!workspace) return;\n if (snapshot.instrumentName !== workspace.instrumentName) {\n console.warn(\n `[labkit] loadSnapshot: instrument mismatch (snapshot=${snapshot.instrumentName}, workspace=${workspace.instrumentName}); refusing to load`,\n );\n return;\n }\n const reg = serializers[snapshot.instrumentName];\n const restoredState = reg?.deserialize ? reg.deserialize(snapshot.state) : snapshot.state;\n set((s) => ({\n workspaces: s.workspaces.map((w) =>\n w.id === workspaceId ? { ...w, state: restoredState, config: snapshot.config } : w,\n ),\n }));\n scheduleFlush();\n },\n\n deleteSnapshot: (snapshotId) => {\n set((s) => ({\n savedSnapshots: s.savedSnapshots.filter((sn) => sn.id !== snapshotId),\n }));\n scheduleFlush();\n },\n\n listSnapshots: (workspaceId) => {\n const all = get().savedSnapshots;\n const filtered = workspaceId ? all.filter((sn) => sn.workspaceId === workspaceId) : all;\n return [...filtered].sort((a, b) => b.savedAt - a.savedAt);\n },\n\n setMode: (mode) => {\n set({ mode });\n scheduleFlush();\n },\n }));\n\n function scheduleFlush(): void {\n if (flushTimer) clearTimeout(flushTimer);\n flushTimer = setTimeout(() => {\n const s = store.getState();\n options.storage.write(\n labStorageKey(options.storageKey, 'workspaces'),\n serializeWorkspaces(s.workspaces, serializers),\n );\n options.storage.write(\n labStorageKey(options.storageKey, 'saves'),\n JSON.stringify(s.savedSnapshots),\n );\n options.storage.write(labStorageKey(options.storageKey, 'theme'), s.mode);\n flushTimer = null;\n }, 300);\n }\n\n return Object.assign(store, {\n registerSerializers(s: InstrumentSerializers) {\n serializers = s;\n },\n });\n}\n","import { useContext } from 'react';\nimport { useStore } from 'zustand/react';\nimport { LabStoreContext, WorkspaceIdContext } from './context';\nimport type { ExperimentStateHandle } from './types';\n\nexport function useExperimentState<TS = unknown, TC = unknown>(): ExperimentStateHandle<TS, TC> {\n const ctx = useContext(LabStoreContext);\n if (!ctx) throw new Error('[labkit] useExperimentState must be used inside <LabStoreProvider>');\n\n const workspaceId = useContext(WorkspaceIdContext);\n if (!workspaceId)\n throw new Error('[labkit] useExperimentState must be used inside <WorkspaceIdProvider>');\n\n const record = useStore(ctx.store, (s) => s.workspaces.find((w) => w.id === workspaceId));\n\n if (!record) throw new Error(`[labkit] No workspace found with id \"${workspaceId}\"`);\n\n const updateWorkspaceState = useStore(ctx.store, (s) => s.updateWorkspaceState);\n const updateWorkspaceConfig = useStore(ctx.store, (s) => s.updateWorkspaceConfig);\n\n return {\n state: record.state as TS,\n config: record.config as TC,\n setState: (next) =>\n updateWorkspaceState(workspaceId, next as Parameters<typeof updateWorkspaceState>[1]),\n setConfig: (key, value) => updateWorkspaceConfig(workspaceId, key as never, value as never),\n };\n}\n"]}