@weasel-js/labkit 1.8.0 → 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.
Files changed (189) hide show
  1. package/README.md +24 -0
  2. package/dist/_dts/{CanvasStackContext-C0fzFsQg.d.ts → CanvasStackContext-B05ZM04l.d.ts} +3 -1
  3. package/dist/_dts/{Stage-Cvwxdnfp.d.ts → Stage-CIJlbjrE.d.ts} +5 -3
  4. package/dist/_dts/{index-DRaswz91.d.ts → index-8geQNQet.d.ts} +83 -11
  5. package/dist/_dts/{index-DEHRoTXK.d.ts → index-DRi3V5sN.d.ts} +5 -3
  6. package/dist/_dts/{useTrialState-CS4TdWPW.d.ts → useTrialState-Ar0AFpCe.d.ts} +94 -87
  7. package/dist/canvas/index.d.ts +4 -4
  8. package/dist/canvas/index.js +2 -2
  9. package/dist/chrome/index.d.ts +2 -2
  10. package/dist/chrome/index.js +7 -7
  11. package/dist/{chunk-YX75W6EK.js → chunk-4RCVWX4M.js} +8 -8
  12. package/dist/chunk-4RCVWX4M.js.map +1 -0
  13. package/dist/{chunk-WIG6XHJ7.js → chunk-6IIKLXBZ.js} +13 -4
  14. package/dist/chunk-6IIKLXBZ.js.map +1 -0
  15. package/dist/{chunk-F4ACIK7Z.js → chunk-6Q6ACJ3H.js} +3 -3
  16. package/dist/{chunk-F4ACIK7Z.js.map → chunk-6Q6ACJ3H.js.map} +1 -1
  17. package/dist/{chunk-PMLZP7RT.js → chunk-7ALJOVGP.js} +5 -9
  18. package/dist/chunk-7ALJOVGP.js.map +1 -0
  19. package/dist/{chunk-XE5HJOPL.js → chunk-7FMZT2WL.js} +3 -3
  20. package/dist/{chunk-XE5HJOPL.js.map → chunk-7FMZT2WL.js.map} +1 -1
  21. package/dist/{chunk-XVUKDSYV.js → chunk-AVOILDN2.js} +2 -2
  22. package/dist/{chunk-XVUKDSYV.js.map → chunk-AVOILDN2.js.map} +1 -1
  23. package/dist/{chunk-2N7UBSS2.js → chunk-J5MDJEOZ.js} +3 -3
  24. package/dist/{chunk-2N7UBSS2.js.map → chunk-J5MDJEOZ.js.map} +1 -1
  25. package/dist/{chunk-NVKBL7ZE.js → chunk-KHB3KRRQ.js} +7 -7
  26. package/dist/chunk-KHB3KRRQ.js.map +1 -0
  27. package/dist/{chunk-XXACAPVU.js → chunk-NHIO2O3O.js} +31 -30
  28. package/dist/chunk-NHIO2O3O.js.map +1 -0
  29. package/dist/{chunk-EESJUSYR.js → chunk-QMAY74TP.js} +56 -5
  30. package/dist/chunk-QMAY74TP.js.map +1 -0
  31. package/dist/{chunk-YDE6XATS.js → chunk-RN7T7OBO.js} +44 -22
  32. package/dist/chunk-RN7T7OBO.js.map +1 -0
  33. package/dist/{chunk-3L4MLLQB.js → chunk-RXO5UEGT.js} +4 -11
  34. package/dist/chunk-RXO5UEGT.js.map +1 -0
  35. package/dist/{chunk-MOTDMMMN.js → chunk-SQX35X5V.js} +3 -3
  36. package/dist/{chunk-MOTDMMMN.js.map → chunk-SQX35X5V.js.map} +1 -1
  37. package/dist/{chunk-J5HJJDLF.js → chunk-T5OEUNCB.js} +7 -2
  38. package/dist/chunk-T5OEUNCB.js.map +1 -0
  39. package/dist/{chunk-RL2LOLNI.js → chunk-UX66USTN.js} +2 -2
  40. package/dist/chunk-UX66USTN.js.map +1 -0
  41. package/dist/{chunk-WURZTJGQ.js → chunk-V4SMGEYY.js} +4858 -4806
  42. package/dist/chunk-V4SMGEYY.js.map +1 -0
  43. package/dist/{chunk-E23Q6A3Y.js → chunk-VCK5T6EP.js} +3 -3
  44. package/dist/{chunk-E23Q6A3Y.js.map → chunk-VCK5T6EP.js.map} +1 -1
  45. package/dist/{chunk-T6DLGEJB.js → chunk-XWR2P6MR.js} +23 -6
  46. package/dist/chunk-XWR2P6MR.js.map +1 -0
  47. package/dist/{chunk-7KAETQSS.js → chunk-YZA73U4A.js} +7 -7
  48. package/dist/chunk-YZA73U4A.js.map +1 -0
  49. package/dist/config/index.d.ts +2 -2
  50. package/dist/config/index.js +2 -2
  51. package/dist/controls/index.js +5 -5
  52. package/dist/dragdrop/index.d.ts +1 -1
  53. package/dist/dragdrop/index.js +2 -2
  54. package/dist/index.d.ts +157 -15
  55. package/dist/index.js +893 -258
  56. package/dist/index.js.map +1 -1
  57. package/dist/layers/index.d.ts +1 -1
  58. package/dist/layers/index.js +3 -3
  59. package/dist/loupe/index.d.ts +175 -27
  60. package/dist/loupe/index.js +547 -141
  61. package/dist/loupe/index.js.map +1 -1
  62. package/dist/overview/index.js +5 -5
  63. package/dist/passthrough/weasel-ui.js +3 -3
  64. package/dist/primitives/index.d.ts +4 -19
  65. package/dist/primitives/index.js +7 -7
  66. package/dist/state/index.d.ts +5 -7
  67. package/dist/state/index.js +5 -5
  68. package/dist/styles.css +173 -38
  69. package/dist/surface/index.d.ts +20 -1
  70. package/dist/surface/index.js +2 -2
  71. package/dist/undo/index.d.ts +18 -7
  72. package/dist/undo/index.js +1 -1
  73. package/package.json +11 -11
  74. package/src/annotations/AnnotationOverlay.abandon.test.tsx +4 -0
  75. package/src/annotations/AnnotationOverlay.tsx +10 -1
  76. package/src/annotations/Annotations.less +2 -0
  77. package/src/annotations/Annotations.overlay.test.tsx +29 -0
  78. package/src/canvas/CanvasStack.test.tsx +35 -0
  79. package/src/canvas/CanvasStack.tsx +12 -1
  80. package/src/canvas/useLayerScheduler.ts +14 -0
  81. package/src/chrome/builtins.test.ts +14 -0
  82. package/src/chrome/builtins.tsx +17 -2
  83. package/src/chrome/regions/StatusRegion.tsx +20 -14
  84. package/src/chrome/regions/regions.test.tsx +28 -0
  85. package/src/chrome/types.ts +8 -0
  86. package/src/clock/clock.browser.test.less +5 -0
  87. package/src/clock/clock.browser.test.tsx +77 -0
  88. package/src/clock/clock.integration.test.tsx +95 -0
  89. package/src/clock/clockRegistry.test.ts +33 -0
  90. package/src/clock/clockRegistry.ts +46 -0
  91. package/src/clock/hooks.ts +44 -0
  92. package/src/clock/index.ts +2 -0
  93. package/src/clock/trialClock.test.ts +265 -0
  94. package/src/clock/trialClock.ts +245 -0
  95. package/src/clock/useClockLoop.ts +45 -0
  96. package/src/config/resolve.test.ts +12 -0
  97. package/src/config/resolve.ts +5 -0
  98. package/src/controls/ControlMatrix.tsx +56 -54
  99. package/src/index.ts +3 -2
  100. package/src/instrument/types.ts +21 -1
  101. package/src/lab/Lab.chrome.test.tsx +8 -1
  102. package/src/lab/Lab.presentation.test.tsx +113 -0
  103. package/src/lab/Lab.surface.test.tsx +20 -9
  104. package/src/lab/Lab.tsx +132 -257
  105. package/src/lab/LabLightbox.browser.test.less +17 -0
  106. package/src/lab/LabLightbox.browser.test.tsx +216 -0
  107. package/src/lab/LabShell.less +10 -3
  108. package/src/lab/LabSurface.tsx +129 -0
  109. package/src/lab/Workspace.stories.tsx +18 -0
  110. package/src/lab/Workspace.surface.test.tsx +4 -0
  111. package/src/lab/Workspace.test.tsx +37 -1
  112. package/src/lab/Workspace.tsx +34 -6
  113. package/src/lab/index.ts +2 -0
  114. package/src/lab/nebula.ts +30 -0
  115. package/src/lab/openLab.test.ts +81 -0
  116. package/src/lab/openLab.ts +119 -0
  117. package/src/lab/presentation.browser.test.less +5 -0
  118. package/src/lab/presentation.browser.test.tsx +119 -0
  119. package/src/lab/presentation.less +64 -0
  120. package/src/lab/presentation.tsx +47 -0
  121. package/src/lab/useFocusPick.ts +43 -0
  122. package/src/lightbox/Lightbox.browser.test.less +14 -0
  123. package/src/lightbox/Lightbox.browser.test.tsx +113 -0
  124. package/src/lightbox/Lightbox.less +128 -0
  125. package/src/lightbox/Lightbox.test.tsx +195 -0
  126. package/src/lightbox/Lightbox.tsx +205 -0
  127. package/src/lightbox/LightboxContext.ts +38 -0
  128. package/src/lightbox/LightboxLayers.tsx +40 -0
  129. package/src/lightbox/index.ts +8 -0
  130. package/src/lightbox/modal.ts +94 -0
  131. package/src/loupe/AGENTS.md +40 -2
  132. package/src/loupe/CanvasLoupe.tsx +5 -4
  133. package/src/loupe/DomLoupe.tsx +7 -5
  134. package/src/loupe/Loupe.less +15 -0
  135. package/src/loupe/LoupeBubble.tsx +35 -13
  136. package/src/loupe/SourceLoupe.browser.test.tsx +204 -0
  137. package/src/loupe/SourceLoupe.tsx +60 -0
  138. package/src/loupe/TrialLoupe.browser.test.tsx +342 -0
  139. package/src/loupe/TrialLoupe.tsx +126 -28
  140. package/src/loupe/canvasLens.ts +20 -17
  141. package/src/loupe/index.ts +26 -2
  142. package/src/loupe/sourceLens.test.ts +65 -0
  143. package/src/loupe/sourceLens.ts +97 -0
  144. package/src/loupe/types.test.ts +6 -0
  145. package/src/loupe/types.ts +109 -7
  146. package/src/loupe/useLoupe.test.tsx +188 -3
  147. package/src/loupe/useLoupe.ts +106 -11
  148. package/src/primitives/index.ts +2 -2
  149. package/src/specimen/Specimen.tsx +0 -7
  150. package/src/state/helpers.test.ts +4 -11
  151. package/src/state/helpers.ts +2 -8
  152. package/src/state/index.ts +0 -2
  153. package/src/state/openLabStore.test.ts +10 -8
  154. package/src/state/openLabStore.ts +1 -1
  155. package/src/state/store.test.ts +2 -2
  156. package/src/state/store.ts +15 -16
  157. package/src/state/types.ts +9 -9
  158. package/src/styles.less +2 -1
  159. package/src/surface/AGENTS.md +13 -0
  160. package/src/surface/index.ts +1 -0
  161. package/src/surface/useSurfaceTile.test.tsx +4 -0
  162. package/src/surface/useSurfaceTile.ts +17 -1
  163. package/src/surface/useTiledSurface.test.tsx +65 -0
  164. package/src/surface/useTiledSurface.ts +68 -1
  165. package/src/trial/Trial.stories.tsx +0 -1
  166. package/src/trial/Trial.test.tsx +40 -3
  167. package/src/trial/Trial.tsx +87 -43
  168. package/src/trial/TrialChrome.tsx +20 -2
  169. package/src/trial/trialOps.test.ts +1 -2
  170. package/src/trial/trialOps.ts +2 -3
  171. package/src/undo/stateOp.ts +21 -0
  172. package/src/undo/undoStack.ts +18 -6
  173. package/dist/chunk-3L4MLLQB.js.map +0 -1
  174. package/dist/chunk-7KAETQSS.js.map +0 -1
  175. package/dist/chunk-EESJUSYR.js.map +0 -1
  176. package/dist/chunk-J5HJJDLF.js.map +0 -1
  177. package/dist/chunk-NVKBL7ZE.js.map +0 -1
  178. package/dist/chunk-PMLZP7RT.js.map +0 -1
  179. package/dist/chunk-RL2LOLNI.js.map +0 -1
  180. package/dist/chunk-T6DLGEJB.js.map +0 -1
  181. package/dist/chunk-WIG6XHJ7.js.map +0 -1
  182. package/dist/chunk-WURZTJGQ.js.map +0 -1
  183. package/dist/chunk-XXACAPVU.js.map +0 -1
  184. package/dist/chunk-YDE6XATS.js.map +0 -1
  185. package/dist/chunk-YX75W6EK.js.map +0 -1
  186. package/src/primitives/StatusBar.less +0 -34
  187. package/src/primitives/StatusBar.stories.tsx +0 -24
  188. package/src/primitives/StatusBar.test.tsx +0 -25
  189. package/src/primitives/StatusBar.tsx +0 -28
package/README.md CHANGED
@@ -74,6 +74,20 @@ names another substrate: `localStorageAdapter`, `sessionStorageAdapter`,
74
74
  `urlHashAdapter`, or your own `StorageAdapter` over a server. The lab renders
75
75
  `fallback` while it loads. Leave `storageKey` off and nothing persists.
76
76
 
77
+ ### Presenting a lab
78
+
79
+ `<Lab present>` shows one trial and nothing else — no lab chrome, no trial
80
+ chrome, a transparent ground — for embedding a lab as a figure. `?present` in
81
+ the page's URL does the same, so one build serves both the lab and its embed.
82
+ `seed={{ instrument, config, state, view }}` says what that trial opens on. A
83
+ stored lab presents from records of its own (`storageKey` + `':present'`), so
84
+ an embed never shows a visitor their last session in the full lab or writes
85
+ into it; changing the seed reopens the trial on it for returning visitors.
86
+
87
+ Inside any lab, `usePresentation()` gives `{ active, enter, exit }`: `enter`
88
+ presents the focused trial and Escape returns. Nothing unmounts either way, so
89
+ a canvas keeps its context and a clock its place.
90
+
77
91
  A widget's own state persists the same way through `usePersistedState(name,
78
92
  initial)`, which is `useState` whose value survives a reload — kept per trial
79
93
  inside one, and plain `useState` wherever no `<Lab>` or `<Persistence>` is
@@ -279,6 +293,16 @@ import { LabShell, Workspace } from '@weasel-js/labkit';
279
293
  </LabShell>;
280
294
  ```
281
295
 
296
+ Every tile has an expand button in its corner that shows it large over the
297
+ page; Escape, a click in the margin, or the close button puts it back. The tile
298
+ is lifted into the browser's top layer rather than remounted, so a WebGL
299
+ context inside it keeps running and only sees its box grow. A double-click
300
+ opens it too where you ask for that — `expandOnDoubleClick={(id) => id ===
301
+ 'output'}` for an image tile. Turn the lightbox off with `lightbox={false}`, or
302
+ per tile with `lightbox={(id) => …}`; the same behavior is available outside a
303
+ workspace as `<Lightbox>`. In a `<Lab>` every trial has the toggle in its title
304
+ bar, and its shared-surface pixels — annotation marks, a 3D view — come along.
305
+
282
306
  `<Toolbar>`, `<Sidebar>`, `<StatusBar>`, `<FpsMeter>`, `<ScaleIndicator>`,
283
307
  `<Legend>`, `<FloatingPanel>`, `<ZoomControl>` and the `@weasel-js/ui` property
284
308
  rows re-exported from the root are all usable this way. `<Trial>` is not: it
@@ -1,12 +1,14 @@
1
1
  import * as react from 'react';
2
2
  import { RefObject } from 'react';
3
- import { a as ViewTransform, W as WorldFrame, b as WorldSpec } from './index-DRaswz91.js';
3
+ import { a as ViewTransform, W as WorldFrame, b as WorldSpec } from './index-8geQNQet.js';
4
4
 
5
5
  /** One layer of a canvas stack: its id, whether it is currently shown, and how
6
6
  * it paints itself. */
7
7
  interface CanvasLayerDescriptor {
8
8
  id: string;
9
9
  visible: boolean;
10
+ /** Repaint on every `ticks` frame, not only when `render` or the view change. */
11
+ timed?: boolean;
10
12
  render: (ctx: CanvasRenderingContext2D, view: ViewTransform, frame: WorldFrame) => void;
11
13
  }
12
14
 
@@ -1,8 +1,8 @@
1
1
  import * as react from 'react';
2
2
  import { RefObject, ReactNode } from 'react';
3
3
  import { ViewApi, Yoke } from '@weasel-js/core';
4
- import { W as WorldFrame, P as Point, a as ViewTransform, b as WorldSpec, V as ViewportSize } from './index-DRaswz91.js';
5
- import { C as CanvasLayerDescriptor } from './CanvasStackContext-C0fzFsQg.js';
4
+ import { W as WorldFrame, P as Point, a as ViewTransform, b as WorldSpec, V as ViewportSize } from './index-8geQNQet.js';
5
+ import { C as CanvasLayerDescriptor } from './CanvasStackContext-B05ZM04l.js';
6
6
 
7
7
  /** The view id the stage publishes its pointer under. */
8
8
  declare const STAGE_VIEW_ID = "stage";
@@ -102,12 +102,14 @@ interface CanvasStackProps {
102
102
  /** A yoke to join, from `useYoke()`: cameras on one yoke share their tool
103
103
  * and gesture in flight. Omitted, this one keeps its own. */
104
104
  yoke?: Yoke;
105
+ /** Frames after each of which every `timed` layer repaints — a trial clock's. */
106
+ ticks?: (fn: () => void) => () => void;
105
107
  }
106
108
  /** Stacks one `<canvas>` per layer and drives them from a shared view, so a
107
109
  * layer that changes rarely is not redrawn with one that changes every frame.
108
110
  * Handles sizing and device pixel ratio; pan and zoom route through weasel's
109
111
  * gesture dispatcher (`<CameraInput>`). */
110
- declare function CanvasStack({ layers, view: viewProp, onViewChange, worldSpec, minZoom, maxZoom, width, height, className, onResize, onHitTest, children, yoke, }: CanvasStackProps): react.JSX.Element;
112
+ declare function CanvasStack({ layers, view: viewProp, onViewChange, worldSpec, minZoom, maxZoom, width, height, className, onResize, onHitTest, children, yoke, ticks, }: CanvasStackProps): react.JSX.Element;
111
113
 
112
114
  /** Bounds and coordinate system a {@link zoomAt} works in. */
113
115
  interface ZoomAtOptions {
@@ -1,5 +1,5 @@
1
1
  import { StanceProps } from '@weasel-js/ui';
2
- import { View, DrawCommand, Scene, PointerContextValue } from '@weasel-js/core';
2
+ import { History, View, DrawCommand, Scene, PointerContextValue } from '@weasel-js/core';
3
3
  import { RefObject, ComponentType, ReactNode } from 'react';
4
4
  import { ColorModePreference } from '@weasel-js/theme';
5
5
  import { R as ResolvedConfig, n as ConfigPath, V as ValueAtPath, a as ConfigField, C as ConfigSchema } from './types-DUfQ0isU.js';
@@ -36,12 +36,6 @@ declare function undockPanel(panels: UndockedPanels, trialId: string, sectionId:
36
36
  * owns, which is what closing a trial wants. */
37
37
  declare function dockPanel(panels: UndockedPanels, trialId: string, sectionId?: string): UndockedPanels;
38
38
 
39
- /** A trial's undo history, as snapshots of its state either side of the
40
- * present. */
41
- interface UndoStack {
42
- past: unknown[];
43
- future: unknown[];
44
- }
45
39
  /** The trial a per-trial call is coming from. `id` is the id `useTileId`
46
40
  * scopes a surface tile under, so a consumer keying its own per-trial
47
41
  * registry and labkit's tiles agree on the key. */
@@ -90,7 +84,16 @@ interface TrialRecord<TS = unknown, TC = unknown, TV = unknown> {
90
84
  * no `annotations` — or declares its own `storage`. Not in `state`, which
91
85
  * belongs to the instrument and is typed as such. */
92
86
  annotations?: unknown;
93
- undoStack: UndoStack;
87
+ /** This trial's undo history over `state`, made by the trial on its first
88
+ * snapshot. Session-only: absent on a new, cloned, swapped or reloaded
89
+ * trial, which is how each starts with an empty history. */
90
+ history?: History;
91
+ /** Where the trial's clock stood at its last rate or seek change, for a
92
+ * trial whose instrument declares `clock`. */
93
+ clock?: {
94
+ elapsed: number;
95
+ rate: number;
96
+ };
94
97
  }
95
98
  /** A named, saved copy of a trial's config and state, restorable into any
96
99
  * trial running the same instrument. */
@@ -206,7 +209,7 @@ type InstrumentSerializers = Record<string, {
206
209
  } | undefined>;
207
210
  /** A trial as it is persisted: everything but the undo history, which is
208
211
  * session-only. */
209
- type SerializedTrial = Omit<TrialRecord, 'undoStack'>;
212
+ type SerializedTrial = Omit<TrialRecord, 'history'>;
210
213
  /** Everything a lab persists, under one key, at a known version. */
211
214
  interface LabDocument {
212
215
  version: number;
@@ -776,6 +779,13 @@ interface TrialChromeContext extends ToolSlotContext, SidebarSlotContext {
776
779
  /** Whether the trial's loupe is turned on. */
777
780
  loupeOn: boolean;
778
781
  toggleLoupe: () => void;
782
+ /** Whether the trial sits in a `<Lightbox>` — every `<Workspace>` tile does
783
+ * unless the workspace turned it off. The expand toggle is offered only
784
+ * while it does. */
785
+ canExpand: boolean;
786
+ /** Whether the trial is showing in its lightbox. */
787
+ expanded: boolean;
788
+ toggleExpanded: () => void;
779
789
  /** The instrument's controls, resolved against the lab's rules. Always
780
790
  * populated: a legacy `configSchema()` is adapted into the same shape. */
781
791
  configSchema: ResolvedConfig;
@@ -808,6 +818,56 @@ interface TrialChromeContext extends ToolSlotContext, SidebarSlotContext {
808
818
  close: () => void;
809
819
  }
810
820
 
821
+ /**
822
+ * What an instrument declares to get a clock: how long a pass runs, how many
823
+ * passes, and how it opens. Shaped like a blits voice spec.
824
+ */
825
+ interface ClockCapability {
826
+ /** ms per pass. Omitted, the run never ends. */
827
+ duration?: number;
828
+ /** Passes: `true` endless, `false` one, `n` that many. Default `false`. */
829
+ loop?: boolean | number;
830
+ /** The rate it opens at; `0`, the default, opens paused. */
831
+ rate?: number;
832
+ /** `false` for an instrument whose state is built up by running, so time can
833
+ * only move by running: no seek and no negative rate. Default `true`. */
834
+ seekable?: boolean;
835
+ }
836
+ /**
837
+ * A trial's time. A position (`elapsed`) moved by a signed `rate`, synced by
838
+ * the lab's frame loop once a frame. Named after blits' owner handle and
839
+ * `Ticked`, so a blits ticker can drive one and blits voices can play under it.
840
+ */
841
+ interface TrialClock {
842
+ /** ms the trial has played, rate applied, counted across passes. */
843
+ readonly elapsed: number;
844
+ /** Which pass `elapsed` falls in, 0 first; the last once the run is over. */
845
+ readonly pass: number;
846
+ /** How far through its pass, 0 to 1; 1 once the run is over. 0 with no duration. */
847
+ readonly phase: number;
848
+ /** Signed: 0 pauses and a negative rate plays backward. A write changes speed
849
+ * at once and replaces any ramp. */
850
+ rate: number;
851
+ /** Passes, as `ClockCapability.loop`. */
852
+ loop: boolean | number;
853
+ /** Move `rate` to `to` linearly over `over` real ms; position stays continuous. */
854
+ ramp(to: number, over: number): void;
855
+ /** Move to `elapsed` ms from the start, clamped to the run. Never runs state
856
+ * forward to meet it. Throws on a clock that is not seekable. */
857
+ seek(elapsed: number): void;
858
+ /** The frame loop reports the time, once a frame. */
859
+ sync(timestamp: number): void;
860
+ /** The time between now and the next sync does not count. */
861
+ rebase(): void;
862
+ /** Another frame would change nothing: paused, no ramp, nothing changed since
863
+ * the last sync. */
864
+ readonly inert: boolean;
865
+ /** Called when a change needs frames again, once until the next sync. */
866
+ onWake(fn: () => void): () => void;
867
+ /** Called on a rate, seek or loop change, and when the run ends; never per frame. */
868
+ subscribe(fn: () => void): () => void;
869
+ }
870
+
811
871
  /**
812
872
  * A tool a trial can be in. labkit's own — core's `ToolsApi` carries hotkey
813
873
  * slots, ambient tools, eligibility tiers and canvas overlay layers, all bound
@@ -862,6 +922,8 @@ interface RenderContext<TS = unknown, TC = unknown> {
862
922
  * reading it works over either view.
863
923
  */
864
924
  pointer: PointerContextValue;
925
+ /** The trial's clock, present when the instrument declares `clock`. */
926
+ clock?: TrialClock;
865
927
  };
866
928
  emit: (event: string) => void;
867
929
  /** Present only when the instrument declares a `job`. */
@@ -874,10 +936,17 @@ interface RenderContext<TS = unknown, TC = unknown> {
874
936
  * set `ctx.lineWidth = 1 / zoom` to keep a hairline hairline. */
875
937
  interface CanvasLayer<TS = unknown, TC = unknown> {
876
938
  id: string;
939
+ /** Redraw every frame the trial's clock moves, not only when state, config
940
+ * or the view change. For a layer that reads `elapsed`, `pass` or `phase`. */
941
+ timed?: boolean;
877
942
  draw: (ctx: CanvasRenderingContext2D, args: {
878
943
  state: TS;
879
944
  config: TC;
880
945
  zoom: number;
946
+ /** The trial clock's, as `TrialClock` has them; 0 with no clock. */
947
+ elapsed: number;
948
+ pass: number;
949
+ phase: number;
881
950
  }) => void;
882
951
  }
883
952
  /** Declares that an instrument draws to a canvas: its layers, and where the
@@ -1023,6 +1092,9 @@ interface Instrument<TS = unknown, TC = unknown, TItem = unknown> {
1023
1092
  annotations?: AnnotationsCapability<TS, TC>;
1024
1093
  /** Chrome this instrument contributes beyond what its capabilities imply. */
1025
1094
  chrome?: TrialContribution[];
1095
+ /** Gives the trial a clock: playback time that layers, renderers and chrome
1096
+ * read and drive. */
1097
+ clock?: ClockCapability;
1026
1098
  /** Work too slow to do during a render. The runtime starts it, aborts it on
1027
1099
  * unmount and on a `key` change, and renders progress into the trial. */
1028
1100
  job?: JobCapability<TS, TC, TItem>;
@@ -1032,5 +1104,5 @@ interface Instrument<TS = unknown, TC = unknown, TItem = unknown> {
1032
1104
  * an `Instrument<unknown, unknown>[]`; it is contained to this alias. */
1033
1105
  type InstrumentList = readonly Instrument<any, any, any>[];
1034
1106
 
1035
- export { DEFAULT_FRAME as D, fracEncloses as aA, fracToWorld as aB, isAuto as aC, markCommands as aD, roundFrac as aE, worldToFrac as aF, annotationsFromJSON as av, auto as aw, createAnnotationScene as ax, createAnnotationStore as ay, fracContains as az, dockPanel as j, applyCamera as k, panelKey as p, resolveFrame as r, undockPanel as u };
1036
- export type { AnnotationSelectionMode as $, AnnotationMeaning as A, CaptureResult as B, CreateLabStoreOptions as C, PaintableMark as E, AnnotationTarget as F, AnnotationsApi as G, AnnotationsCapability as H, InstrumentSerializers as I, TrialInfo as J, TrialTool as K, LabDocument as L, Migration as M, AnnotationKind as N, Instrument as O, Point as P, LabDensity as Q, TrialContribution as R, SerializedTrial as S, TrialRecord as T, UndoStack as U, ViewportSize as V, WorldFrame as W, Annotation as X, AnnotationInit as Y, AnnotationPatch as Z, AnnotationQuery as _, ViewTransform as a, AnnotationStatus as a0, AnnotationStoreOptions as a1, AnnotationTargetInfo as a2, AnnotationToolId as a3, Auto as a4, CanvasCapability as a5, CanvasLayer as a6, CaptureDeps as a7, ContributionBase as a8, FracPoint as a9, FracRect as aa, HitResult as ab, IconComponent as ac, LayerCapability as ad, LayerDescriptor as ae, RegionContribution as af, RenderContext as ag, SerializedAnnotations as ah, SidebarSection as ai, SidebarSlotContext as aj, StageCapability as ak, StatusReadout as al, SystemEvent as am, ToolCapability as an, ToolItem as ao, ToolSlotContext as ap, ToolbarItem as aq, TrialChromeContext as ar, TrialRegion as as, UndoCapability as at, ViewportControl as au, WorldSpec as b, StorageAdapter as c, LabStoreState as d, SavedSnapshot as e, StorageChange as f, TrialStateHandle as g, UndockedPanel as h, UndockedPanels as i, PaletteItem as l, DragFeedback as m, DragDropCapability as n, LabMode as o, InstrumentList as q, InstrumentHooks as s, AnnotationData as t, WorldRect as v, MarkStyle as w, MarkScene as x, CaptureSource as y, CaptureOptions as z };
1107
+ export { DEFAULT_FRAME as D, fracContains as aA, fracEncloses as aB, fracToWorld as aC, isAuto as aD, markCommands as aE, roundFrac as aF, worldToFrac as aG, annotationsFromJSON as aw, auto as ax, createAnnotationScene as ay, createAnnotationStore as az, dockPanel as i, applyCamera as j, panelKey as p, resolveFrame as r, undockPanel as u };
1108
+ export type { AnnotationSelectionMode as $, AnnotationMeaning as A, PaintableMark as B, CreateLabStoreOptions as C, AnnotationTarget as E, AnnotationsApi as F, AnnotationsCapability as G, TrialInfo as H, InstrumentSerializers as I, TrialTool as J, AnnotationKind as K, LabDocument as L, Migration as M, TrialClock as N, Instrument as O, Point as P, LabDensity as Q, TrialContribution as R, SerializedTrial as S, TrialRecord as T, UndockedPanel as U, ViewportSize as V, WorldFrame as W, Annotation as X, AnnotationInit as Y, AnnotationPatch as Z, AnnotationQuery as _, ViewTransform as a, AnnotationStatus as a0, AnnotationStoreOptions as a1, AnnotationTargetInfo as a2, AnnotationToolId as a3, Auto as a4, CanvasCapability as a5, CanvasLayer as a6, CaptureDeps as a7, ClockCapability as a8, ContributionBase as a9, FracPoint as aa, FracRect as ab, HitResult as ac, IconComponent as ad, LayerCapability as ae, LayerDescriptor as af, RegionContribution as ag, RenderContext as ah, SerializedAnnotations as ai, SidebarSection as aj, SidebarSlotContext as ak, StageCapability as al, StatusReadout as am, SystemEvent as an, ToolCapability as ao, ToolItem as ap, ToolSlotContext as aq, ToolbarItem as ar, TrialChromeContext as as, TrialRegion as at, UndoCapability as au, ViewportControl as av, WorldSpec as b, StorageAdapter as c, LabStoreState as d, SavedSnapshot as e, StorageChange as f, TrialStateHandle as g, UndockedPanels as h, PaletteItem as k, DragFeedback as l, DragDropCapability as m, LabMode as n, InstrumentList as o, InstrumentHooks as q, AnnotationData as s, WorldRect as t, MarkStyle as v, MarkScene as w, CaptureSource as x, CaptureOptions as y, CaptureResult as z };
@@ -1,10 +1,11 @@
1
1
  import { c as ControlRenderer, b as ConfigRule } from './types-DUfQ0isU.js';
2
- import { O as Instrument, ar as TrialChromeContext, R as TrialContribution, T as TrialRecord, q as InstrumentList, e as SavedSnapshot, o as LabMode, ap as ToolSlotContext, a8 as ContributionBase, aq as ToolbarItem, ao as ToolItem, ai as SidebarSection, al as StatusReadout, K as TrialTool, af as RegionContribution, aj as SidebarSlotContext } from './index-DRaswz91.js';
2
+ import { O as Instrument, as as TrialChromeContext, R as TrialContribution, T as TrialRecord, o as InstrumentList, e as SavedSnapshot, n as LabMode, aq as ToolSlotContext, a9 as ContributionBase, ar as ToolbarItem, ap as ToolItem, aj as SidebarSection, am as StatusReadout, J as TrialTool, ag as RegionContribution, ak as SidebarSlotContext } from './index-8geQNQet.js';
3
3
  import * as react from 'react';
4
4
  import { ReactNode } from 'react';
5
5
 
6
6
  /** Built-in ids contributed only while runtime state says so — the loupe
7
- * toggle appears once a lens mounts, after the trial's first render. */
7
+ * toggle appears once a lens mounts, after the trial's first render, and the
8
+ * expand toggle only inside a lightbox. */
8
9
  declare const TRANSIENT_BUILTINS: ReadonlySet<string>;
9
10
  /**
10
11
  * The contributions a trial gets from what its instrument declared. This is
@@ -208,7 +209,8 @@ interface StatusRegionProps<TCtx = TrialChromeContext> {
208
209
  /** Which region's readouts to lay out; the lab's footer is `footer`. */
209
210
  region?: string;
210
211
  }
211
- /** Lays a bar's readouts out. */
212
+ /** Lays a bar's readouts out. The first one marked `end`, and every one after
213
+ * it, sits at the far end. */
212
214
  declare function StatusRegion<TCtx = TrialChromeContext>({ contributions, ctx, region, }: StatusRegionProps<TCtx>): react.JSX.Element | null;
213
215
 
214
216
  /** Which end of the title bar a `<TitleBarRegion>` lays out: `'lead'` renders
@@ -1,42 +1,47 @@
1
- import { c as StorageAdapter, d as LabStoreState, T as TrialRecord, e as SavedSnapshot, o as LabMode, h as UndockedPanel, q as InstrumentList, s as InstrumentHooks, C as CreateLabStoreOptions, g as TrialStateHandle } from './index-DRaswz91.js';
1
+ import { d as LabStoreState, T as TrialRecord, e as SavedSnapshot, n as LabMode, U as UndockedPanel, o as InstrumentList, q as InstrumentHooks, C as CreateLabStoreOptions, c as StorageAdapter, g as TrialStateHandle } from './index-8geQNQet.js';
2
2
  import * as react from 'react';
3
3
  import { ReactNode, ReactElement, Dispatch, SetStateAction } from 'react';
4
+ import { History } from '@weasel-js/core';
4
5
  import { StoreApi } from 'zustand/vanilla';
5
6
 
6
- /** Persist to `localStorage`, one JSON value per record. Survives a reload and
7
- * reaches other tabs through the `storage` event. */
8
- declare const localStorageAdapter: StorageAdapter;
9
- /** Persist to `sessionStorage` — survives a reload but not a new tab. */
10
- declare const sessionStorageAdapter: StorageAdapter;
11
- /** Persist into the URL fragment, so the page's link carries its state and can
12
- * be shared or bookmarked. Changes to the fragment made elsewhere — a pasted
13
- * link, back and forward — arrive through `hashchange`. */
14
- declare const urlHashAdapter: StorageAdapter;
15
- /** An in-memory store, discarded on reload. Values are copied in and out, as a
16
- * real substrate would. Adapters built over one shared `backing` hear each
17
- * other's writes — two tabs, for a test. */
18
- declare function createMemoryAdapter(backing?: Map<string, unknown>): StorageAdapter;
19
- /** Persists nothing and reads back nothing. */
20
- declare const noneAdapter: StorageAdapter;
21
- /** Options for `createIndexedDbAdapter`. */
22
- interface IndexedDbAdapterOptions {
23
- /** Default `'labkit'`. */
24
- database?: string;
25
- /** Default `'records'`. One object store per database: a store added to a
26
- * database that already exists is not created. */
27
- store?: string;
7
+ /** One record changing, as a cache listener hears it. `value` is `undefined`
8
+ * for a delete. `local` changes were made through this cache; `remote` ones
9
+ * came from another writer. */
10
+ interface RecordChange {
11
+ name: string;
12
+ value: unknown;
13
+ origin: 'local' | 'remote';
14
+ }
15
+ /**
16
+ * Every record under one prefix, held in memory: the only thing that talks to
17
+ * a `StorageAdapter`. Names are keys with the prefix removed.
18
+ *
19
+ * Writes land in memory at once and reach storage on a debounce. The newest
20
+ * write to a record wins: another writer's change to a record with a write
21
+ * still queued here is ignored, since the queued write lands after it.
22
+ */
23
+ interface RecordCache {
24
+ readonly prefix: string;
25
+ /** False once writing is off — the records could not be read, or were
26
+ * written by a newer labkit — so nothing here can overwrite them. */
27
+ readonly writable: boolean;
28
+ has(name: string): boolean;
29
+ get(name: string): unknown;
30
+ /** Every record whose name starts with `namePrefix`. */
31
+ entries(namePrefix?: string): [string, unknown][];
32
+ set(name: string, value: unknown): void;
33
+ delete(name: string): void;
34
+ subscribe(listener: (changes: RecordChange[]) => void): () => void;
35
+ /** Send queued writes now. */
36
+ flush(): Promise<void>;
37
+ /** Send queued writes and stop hearing other writers. */
38
+ close(): Promise<void>;
28
39
  }
29
- /** Persist to IndexedDB, which stores structured-clone values natively — typed
30
- * arrays, `Map`s, `Blob`s — and holds far more than localStorage. Other tabs
31
- * hear writes through a `BroadcastChannel`. The database opens on first use. */
32
- declare function createIndexedDbAdapter({ database, store, }?: IndexedDbAdapterOptions): StorageAdapter;
33
- /** IndexedDB under the default database and store. */
34
- declare const indexedDbAdapter: StorageAdapter;
35
40
 
36
41
  /** Every mutation a lab store supports: managing trials, saving and
37
42
  * restoring snapshots, and setting the color mode. */
38
43
  interface LabStoreActions {
39
- addTrial: (record: Omit<TrialRecord, 'undoStack'>) => void;
44
+ addTrial: (record: Omit<TrialRecord, 'history'>) => void;
40
45
  removeTrial: (id: string) => void;
41
46
  updateTrialState: <TS>(id: string, next: TS | ((prev: TS) => TS)) => void;
42
47
  /** Write one config value. `path` is dotted for a value nested under an
@@ -49,7 +54,13 @@ interface LabStoreActions {
49
54
  /** Fold or unfold one of a trial's sections. */
50
55
  setTrialSectionCollapsed: (id: string, key: string, collapsed: boolean) => void;
51
56
  updateTrialAnnotations: (id: string, doc: unknown) => void;
52
- updateTrialUndoStack: (id: string, next: TrialRecord['undoStack'] | ((prev: TrialRecord['undoStack']) => TrialRecord['undoStack'])) => void;
57
+ /** Give a trial the undo history it made on its first snapshot. */
58
+ setTrialHistory: (id: string, history: History) => void;
59
+ /** Record where a trial's clock stands. */
60
+ updateTrialClock: (id: string, clock: {
61
+ elapsed: number;
62
+ rate: number;
63
+ }) => void;
53
64
  setTrialInstrument: (id: string, instrumentName: string) => void;
54
65
  saveSnapshot: (trialId: string, name: string) => void;
55
66
  loadSnapshot: (snapshotId: string, trialId: string) => void;
@@ -78,6 +89,58 @@ type LabStore = StoreApi<LabStoreState & LabStoreActions>;
78
89
  * it. */
79
90
  declare function createLabStore(options?: CreateLabStoreOptions): LabStore;
80
91
 
92
+ /** Options for `openLabStore`. `storageKey` names the lab, so two labs on one
93
+ * origin keep separate records. */
94
+ interface OpenLabStoreOptions extends Omit<CreateLabStoreOptions, 'initial'> {
95
+ storageKey: string;
96
+ storage: StorageAdapter;
97
+ }
98
+ /** A lab store bound to its records. */
99
+ interface OpenedLabStore {
100
+ store: LabStore;
101
+ /** Every record of the lab, `usePersistedState` values included. */
102
+ records: RecordCache;
103
+ /** Send queued writes and stop hearing other writers. */
104
+ close(): Promise<void>;
105
+ }
106
+ /**
107
+ * Read a stored lab and return a store bound to it: every change to the store
108
+ * is written as the records it touched, and another writer's records are
109
+ * applied back into the store. A lab stored before records existed is folded
110
+ * forward on the way in.
111
+ */
112
+ declare function openLabStore(options: OpenLabStoreOptions): Promise<OpenedLabStore>;
113
+
114
+ /** Persist to `localStorage`, one JSON value per record. Survives a reload and
115
+ * reaches other tabs through the `storage` event. */
116
+ declare const localStorageAdapter: StorageAdapter;
117
+ /** Persist to `sessionStorage` — survives a reload but not a new tab. */
118
+ declare const sessionStorageAdapter: StorageAdapter;
119
+ /** Persist into the URL fragment, so the page's link carries its state and can
120
+ * be shared or bookmarked. Changes to the fragment made elsewhere — a pasted
121
+ * link, back and forward — arrive through `hashchange`. */
122
+ declare const urlHashAdapter: StorageAdapter;
123
+ /** An in-memory store, discarded on reload. Values are copied in and out, as a
124
+ * real substrate would. Adapters built over one shared `backing` hear each
125
+ * other's writes — two tabs, for a test. */
126
+ declare function createMemoryAdapter(backing?: Map<string, unknown>): StorageAdapter;
127
+ /** Persists nothing and reads back nothing. */
128
+ declare const noneAdapter: StorageAdapter;
129
+ /** Options for `createIndexedDbAdapter`. */
130
+ interface IndexedDbAdapterOptions {
131
+ /** Default `'labkit'`. */
132
+ database?: string;
133
+ /** Default `'records'`. One object store per database: a store added to a
134
+ * database that already exists is not created. */
135
+ store?: string;
136
+ }
137
+ /** Persist to IndexedDB, which stores structured-clone values natively — typed
138
+ * arrays, `Map`s, `Blob`s — and holds far more than localStorage. Other tabs
139
+ * hear writes through a `BroadcastChannel`. The database opens on first use. */
140
+ declare function createIndexedDbAdapter({ database, store, }?: IndexedDbAdapterOptions): StorageAdapter;
141
+ /** IndexedDB under the default database and store. */
142
+ declare const indexedDbAdapter: StorageAdapter;
143
+
81
144
  type LabStoreCtx = {
82
145
  store: LabStore;
83
146
  } | null;
@@ -112,62 +175,6 @@ declare function labDocumentKey(storageKey: string): string;
112
175
  * loses state loudly rather than silently. */
113
176
  declare function quarantineKey(storageKey: string): string;
114
177
 
115
- /** One record changing, as a cache listener hears it. `value` is `undefined`
116
- * for a delete. `local` changes were made through this cache; `remote` ones
117
- * came from another writer. */
118
- interface RecordChange {
119
- name: string;
120
- value: unknown;
121
- origin: 'local' | 'remote';
122
- }
123
- /**
124
- * Every record under one prefix, held in memory: the only thing that talks to
125
- * a `StorageAdapter`. Names are keys with the prefix removed.
126
- *
127
- * Writes land in memory at once and reach storage on a debounce. The newest
128
- * write to a record wins: another writer's change to a record with a write
129
- * still queued here is ignored, since the queued write lands after it.
130
- */
131
- interface RecordCache {
132
- readonly prefix: string;
133
- /** False once writing is off — the records could not be read, or were
134
- * written by a newer labkit — so nothing here can overwrite them. */
135
- readonly writable: boolean;
136
- has(name: string): boolean;
137
- get(name: string): unknown;
138
- /** Every record whose name starts with `namePrefix`. */
139
- entries(namePrefix?: string): [string, unknown][];
140
- set(name: string, value: unknown): void;
141
- delete(name: string): void;
142
- subscribe(listener: (changes: RecordChange[]) => void): () => void;
143
- /** Send queued writes now. */
144
- flush(): Promise<void>;
145
- /** Send queued writes and stop hearing other writers. */
146
- close(): Promise<void>;
147
- }
148
-
149
- /** Options for `openLabStore`. `storageKey` names the lab, so two labs on one
150
- * origin keep separate records. */
151
- interface OpenLabStoreOptions extends Omit<CreateLabStoreOptions, 'initial'> {
152
- storageKey: string;
153
- storage: StorageAdapter;
154
- }
155
- /** A lab store bound to its records. */
156
- interface OpenedLabStore {
157
- store: LabStore;
158
- /** Every record of the lab, `usePersistedState` values included. */
159
- records: RecordCache;
160
- /** Send queued writes and stop hearing other writers. */
161
- close(): Promise<void>;
162
- }
163
- /**
164
- * Read a stored lab and return a store bound to it: every change to the store
165
- * is written as the records it touched, and another writer's records are
166
- * applied back into the store. A lab stored before records existed is folded
167
- * forward on the way in.
168
- */
169
- declare function openLabStore(options: OpenLabStoreOptions): Promise<OpenedLabStore>;
170
-
171
178
  /** Props for `<Persistence>`. */
172
179
  interface PersistenceProps {
173
180
  /** Names the records, as `<Lab storageKey>` does. A lab and a
@@ -1,10 +1,10 @@
1
- export { C as CameraContext, a as CameraContextValue, b as CameraInput, c as CameraInputProps, d as CameraPublishContext, e as CameraRegistry, f as CameraRegistryContext, g as CameraScope, h as CameraView, i as CameraViewOptions, j as CanvasStack, k as CanvasStackProps, S as STAGE_VIEW_ID, l as Stage, m as StageProps, Z as ZoomAtOptions, n as ZoomRange, o as centerOn, p as createCameraRegistry, q as fitStage, s as screenToWorld, u as useCameraView, r as usePublishCamera, w as worldToScreen, z as zoomAt } from '../_dts/Stage-Cvwxdnfp.js';
1
+ export { C as CameraContext, a as CameraContextValue, b as CameraInput, c as CameraInputProps, d as CameraPublishContext, e as CameraRegistry, f as CameraRegistryContext, g as CameraScope, h as CameraView, i as CameraViewOptions, j as CanvasStack, k as CanvasStackProps, S as STAGE_VIEW_ID, l as Stage, m as StageProps, Z as ZoomAtOptions, n as ZoomRange, o as centerOn, p as createCameraRegistry, q as fitStage, s as screenToWorld, u as useCameraView, r as usePublishCamera, w as worldToScreen, z as zoomAt } from '../_dts/Stage-CIJlbjrE.js';
2
2
  import * as react from 'react';
3
- export { C as CanvasLayerDescriptor, a as CanvasStackContext, b as CanvasStackContextValue, c as CanvasStackSurface } from '../_dts/CanvasStackContext-C0fzFsQg.js';
3
+ export { C as CanvasLayerDescriptor, a as CanvasStackContext, b as CanvasStackContextValue, c as CanvasStackSurface } from '../_dts/CanvasStackContext-B05ZM04l.js';
4
4
  import { View } from '@weasel-js/core';
5
- import { W as WorldFrame } from '../_dts/index-DRaswz91.js';
5
+ import { W as WorldFrame } from '../_dts/index-8geQNQet.js';
6
6
  import { Point, ViewTransform } from '../index.js';
7
- export { D as DEFAULT_FRAME, V as ViewportSize, b as WorldSpec, k as applyCamera, r as resolveFrame } from '../_dts/index-DRaswz91.js';
7
+ export { D as DEFAULT_FRAME, V as ViewportSize, b as WorldSpec, j as applyCamera, r as resolveFrame } from '../_dts/index-8geQNQet.js';
8
8
  import '@weasel-js/ui';
9
9
  import '@weasel-js/theme';
10
10
  import '../_dts/types-DUfQ0isU.js';
@@ -1,7 +1,7 @@
1
- export { CanvasStack, LinkedCursor, Stage, fitStage } from '../chunk-T6DLGEJB.js';
1
+ export { CanvasStack, LinkedCursor, Stage, fitStage } from '../chunk-XWR2P6MR.js';
2
2
  export { centerOn, zoomAt } from '../chunk-ROGJWDQA.js';
3
3
  export { screenToWorld, worldToScreen } from '../chunk-FG3EXZDV.js';
4
- import '../chunk-WIG6XHJ7.js';
4
+ import '../chunk-6IIKLXBZ.js';
5
5
  export { CameraContext, CameraInput, CameraPublishContext, CameraRegistryContext, CameraScope, CameraWheelContext, STAGE_VIEW_ID, clampZoomAbout, createCameraRegistry, frameLocalToWorld, fromCameraView, toCameraView, useCameraView, usePublishCamera } from '../chunk-VYVGVBGY.js';
6
6
  export { DEFAULT_FRAME, applyCamera, resolveFrame } from '../chunk-ULYYNWGP.js';
7
7
  export { CanvasStackContext } from '../chunk-ZQIHJXP4.js';
@@ -1,5 +1,5 @@
1
- export { a as LabAsideRegion, b as LabChromeContext, L as LabContribution, e as LabFooterRegion, f as LabHeaderRegion, g as LabRegion, h as LabRegionProps, i as LabSidebarRegion, P as PaletteRegion, j as PaletteRegionProps, S as SidebarRegion, k as SidebarRegionProps, l as StatusRegion, m as StatusRegionProps, T as TRANSIENT_BUILTINS, n as TitleBarPlacement, o as TitleBarRegion, p as TitleBarRegionProps, q as ToolbarRegion, r as ToolbarRegionProps, V as ViewportRegion, s as ViewportRegionProps, u as builtinContributions, x as contributionsIn, y as labContributions, z as mergeContributions, D as suppressContributions, E as toolContributions, F as useLabChromeContext } from '../_dts/index-DEHRoTXK.js';
2
- export { a8 as ContributionBase, ac as IconComponent, af as RegionContribution, ai as SidebarSection, aj as SidebarSlotContext, al as StatusReadout, ao as ToolItem, ap as ToolSlotContext, aq as ToolbarItem, ar as TrialChromeContext, R as TrialContribution, as as TrialRegion, au as ViewportControl } from '../_dts/index-DRaswz91.js';
1
+ export { a as LabAsideRegion, b as LabChromeContext, L as LabContribution, e as LabFooterRegion, f as LabHeaderRegion, g as LabRegion, h as LabRegionProps, i as LabSidebarRegion, P as PaletteRegion, j as PaletteRegionProps, S as SidebarRegion, k as SidebarRegionProps, l as StatusRegion, m as StatusRegionProps, T as TRANSIENT_BUILTINS, n as TitleBarPlacement, o as TitleBarRegion, p as TitleBarRegionProps, q as ToolbarRegion, r as ToolbarRegionProps, V as ViewportRegion, s as ViewportRegionProps, u as builtinContributions, x as contributionsIn, y as labContributions, z as mergeContributions, D as suppressContributions, E as toolContributions, F as useLabChromeContext } from '../_dts/index-DRi3V5sN.js';
2
+ export { a9 as ContributionBase, ad as IconComponent, ag as RegionContribution, aj as SidebarSection, ak as SidebarSlotContext, am as StatusReadout, ap as ToolItem, aq as ToolSlotContext, ar as ToolbarItem, as as TrialChromeContext, R as TrialContribution, at as TrialRegion, av as ViewportControl } from '../_dts/index-8geQNQet.js';
3
3
  import '../_dts/types-DUfQ0isU.js';
4
4
  import '@weasel-js/quantity';
5
5
  import '@weasel-js/ui';
@@ -1,16 +1,16 @@
1
- export { LabAsideRegion, LabFooterRegion, LabHeaderRegion, LabSidebarRegion, PaletteRegion, SidebarRegion, StatusRegion, TRANSIENT_BUILTINS, TitleBarRegion, ToolbarRegion, ViewportRegion, builtinContributions, contributionsIn, labContributions, mergeContributions, suppressContributions, toolContributions, useLabChromeContext } from '../chunk-YDE6XATS.js';
1
+ export { LabAsideRegion, LabFooterRegion, LabHeaderRegion, LabSidebarRegion, PaletteRegion, SidebarRegion, StatusRegion, TRANSIENT_BUILTINS, TitleBarRegion, ToolbarRegion, ViewportRegion, builtinContributions, contributionsIn, labContributions, mergeContributions, suppressContributions, toolContributions, useLabChromeContext } from '../chunk-RN7T7OBO.js';
2
2
  import '../chunk-3RY6WL5T.js';
3
- import '../chunk-3L4MLLQB.js';
3
+ import '../chunk-RXO5UEGT.js';
4
4
  import '../chunk-CZZPXUOU.js';
5
- import '../chunk-PMLZP7RT.js';
6
- import '../chunk-7KAETQSS.js';
5
+ import '../chunk-7ALJOVGP.js';
6
+ import '../chunk-YZA73U4A.js';
7
7
  import '../chunk-Z76KEZAX.js';
8
8
  import '../chunk-WLMDTI2Q.js';
9
9
  import '../chunk-READTDQX.js';
10
10
  import '../chunk-ZQIHJXP4.js';
11
11
  import '../chunk-2YILQ7Y5.js';
12
- import '../chunk-WURZTJGQ.js';
13
- import '../chunk-E23Q6A3Y.js';
14
- import '../chunk-XVUKDSYV.js';
12
+ import '../chunk-V4SMGEYY.js';
13
+ import '../chunk-VCK5T6EP.js';
14
+ import '../chunk-AVOILDN2.js';
15
15
  //# sourceMappingURL=index.js.map
16
16
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
- import { ControlRow, summarizeValue } from './chunk-7KAETQSS.js';
1
+ import { ControlRow, summarizeValue } from './chunk-YZA73U4A.js';
2
2
  import { valueAtPath, auto, schemaNodeAtPath } from './chunk-READTDQX.js';
3
- import { l2, R, le, c, ce, v2, ye, l3, i2, u, d4 } from './chunk-WURZTJGQ.js';
3
+ import { l2, R, le, c, ce2, v2, ye, l3, i2, u, d3 } from './chunk-V4SMGEYY.js';
4
4
  import { isBuiltinToolPref, toHex8, withAlpha01, getAlpha01 } from '@weasel-js/core';
5
5
  import { useState, useRef } from 'react';
6
6
  import { Popover, Dialog } from 'react-aria-components';
@@ -28,10 +28,10 @@ function ControlMatrix({
28
28
  const hintFor = inheritHint ?? ((_) => fallback ? `from ${nameOf(fallback)}` : "");
29
29
  const [open, setOpen] = useState(null);
30
30
  const triggerRef = useRef(null);
31
- const { anchor, portalProps } = l2();
31
+ const { anchor, portalProps, ready } = l2();
32
32
  const leafAt = (path) => {
33
33
  const node = schemaNodeAtPath(schema.group, path);
34
- return node && d4(node) ? node : void 0;
34
+ return node && d3(node) ? node : void 0;
35
35
  };
36
36
  const rowSpecs = rows.map((row) => {
37
37
  const leaves = columns.map((column) => leafAt(`${column.key}.${row.key}`));
@@ -92,7 +92,7 @@ function ControlMatrix({
92
92
  })
93
93
  ] }, row.key)) })
94
94
  ] }),
95
- /* @__PURE__ */ jsx(
95
+ ready && /* @__PURE__ */ jsx(
96
96
  Popover,
97
97
  {
98
98
  triggerRef,
@@ -148,7 +148,7 @@ function ControlMatrix({
148
148
  )
149
149
  ] });
150
150
  if (title === void 0 && stance === void 0 && tone === void 0) return table;
151
- return /* @__PURE__ */ jsx(ce, { title, stance, tone, children: table });
151
+ return /* @__PURE__ */ jsx(ce2, { title, stance, tone, children: table });
152
152
  }
153
153
  function Editor({
154
154
  open,
@@ -335,5 +335,5 @@ function Cell({
335
335
  }
336
336
 
337
337
  export { ControlMatrix };
338
- //# sourceMappingURL=chunk-YX75W6EK.js.map
339
- //# sourceMappingURL=chunk-YX75W6EK.js.map
338
+ //# sourceMappingURL=chunk-4RCVWX4M.js.map
339
+ //# sourceMappingURL=chunk-4RCVWX4M.js.map