@weasel-js/labkit 1.4.0 → 1.4.2

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 (133) hide show
  1. package/README.md +8 -0
  2. package/dist/_dts/{CanvasStackContext-D6M0o8cQ.d.ts → CanvasStackContext-kjILVnPj.d.ts} +1 -1
  3. package/dist/_dts/PrefsForm.d-CgxUequc.d.ts +20 -0
  4. package/dist/_dts/{frac-QS7XzvpG.d.ts → frac-A4R6v4ld.d.ts} +36 -13
  5. package/dist/_dts/{index-B2X21G1c.d.ts → index-CsU9WhjM.d.ts} +90 -30
  6. package/dist/_dts/{types-ChVJJHvk.d.ts → types-BbXpvQa8.d.ts} +20 -1
  7. package/dist/_dts/{types-C1Zw7s5P.d.ts → types-lg4TSCb2.d.ts} +2 -1
  8. package/dist/_dts/{useTrialState-Cdm13fvl.d.ts → useTrialState-DKjqpv20.d.ts} +5 -1
  9. package/dist/_dts/weasel-canvas-FJTFi3ZZ.d.ts +5041 -0
  10. package/dist/canvas/index.d.ts +16 -16
  11. package/dist/canvas/index.js +2 -2
  12. package/dist/chrome/index.d.ts +15 -9
  13. package/dist/chrome/index.js +5 -5
  14. package/dist/{chunk-7VW3S44V.js → chunk-54ZWZ5FQ.js} +908 -301
  15. package/dist/chunk-54ZWZ5FQ.js.map +1 -0
  16. package/dist/{chunk-Y2HK44TG.js → chunk-D5KQ5OY6.js} +3 -3
  17. package/dist/{chunk-Y2HK44TG.js.map → chunk-D5KQ5OY6.js.map} +1 -1
  18. package/dist/{chunk-VHFQKAUL.js → chunk-FJG4PHTL.js} +83 -75
  19. package/dist/chunk-FJG4PHTL.js.map +1 -0
  20. package/dist/{chunk-LN6JDUGB.js → chunk-HXXTULDN.js} +2 -2
  21. package/dist/{chunk-LN6JDUGB.js.map → chunk-HXXTULDN.js.map} +1 -1
  22. package/dist/{chunk-L5WBGUVR.js → chunk-ISSVF5PT.js} +2753 -2654
  23. package/dist/chunk-ISSVF5PT.js.map +1 -0
  24. package/dist/chunk-NSOVI3AZ.js +170 -0
  25. package/dist/chunk-NSOVI3AZ.js.map +1 -0
  26. package/dist/{chunk-YQGQUBKA.js → chunk-TN7YSJVU.js} +62 -60
  27. package/dist/chunk-TN7YSJVU.js.map +1 -0
  28. package/dist/{chunk-4AMN4MMB.js → chunk-UDXOYZEC.js} +53 -39
  29. package/dist/chunk-UDXOYZEC.js.map +1 -0
  30. package/dist/{chunk-LJSIUFYD.js → chunk-ULDW42CR.js} +23 -2
  31. package/dist/chunk-ULDW42CR.js.map +1 -0
  32. package/dist/{chunk-QR5V3AFG.js → chunk-UTOEDPNU.js} +5 -5
  33. package/dist/{chunk-QR5V3AFG.js.map → chunk-UTOEDPNU.js.map} +1 -1
  34. package/dist/{chunk-UD7TEHZT.js → chunk-W2FJR5FF.js} +35 -22
  35. package/dist/chunk-W2FJR5FF.js.map +1 -0
  36. package/dist/{chunk-B5VWJBWM.js → chunk-WS6ZRV75.js} +3 -3
  37. package/dist/{chunk-B5VWJBWM.js.map → chunk-WS6ZRV75.js.map} +1 -1
  38. package/dist/{chunk-W3KSUXXR.js → chunk-XKENZTNE.js} +45 -14
  39. package/dist/chunk-XKENZTNE.js.map +1 -0
  40. package/dist/controls/index.d.ts +4 -3
  41. package/dist/controls/index.js +3 -3
  42. package/dist/dragdrop/index.d.ts +8 -8
  43. package/dist/dragdrop/index.js +2 -2
  44. package/dist/index.d.ts +75 -110
  45. package/dist/index.js +148 -115
  46. package/dist/index.js.map +1 -1
  47. package/dist/job/index.js +1 -1
  48. package/dist/layers/index.d.ts +26 -11
  49. package/dist/layers/index.js +3 -3
  50. package/dist/loupe/index.d.ts +7 -13
  51. package/dist/loupe/index.js +2 -2
  52. package/dist/passthrough/weasel-canvas.d.ts +3 -343
  53. package/dist/passthrough/weasel-canvas.js +1 -1
  54. package/dist/passthrough/weasel-ui.d.ts +123 -3088
  55. package/dist/passthrough/weasel-ui.js +2 -2
  56. package/dist/primitives/index.js +4 -4
  57. package/dist/state/index.d.ts +3 -3
  58. package/dist/state/index.js +2 -2
  59. package/dist/styles.css +30 -3
  60. package/dist/surface/index.js +2 -2
  61. package/dist/ui/layers/index.d.ts +22 -9
  62. package/dist/ui/layers/index.js +2 -2
  63. package/dist/undo/index.d.ts +6 -5
  64. package/package.json +8 -8
  65. package/src/annotations/AnnotationTargets.tsx +6 -1
  66. package/src/annotations/Annotations.overlay.test.tsx +2 -0
  67. package/src/annotations/types.ts +4 -1
  68. package/src/canvas/CanvasStack.tsx +8 -13
  69. package/src/canvas/useOrbit.test.ts +97 -1
  70. package/src/canvas/useOrbit.ts +41 -34
  71. package/src/canvas/usePanZoom.test.ts +106 -1
  72. package/src/canvas/usePanZoom.ts +54 -36
  73. package/src/chrome/ChromeRegions.stories.tsx +42 -1
  74. package/src/chrome/builtins.test.ts +4 -0
  75. package/src/chrome/builtins.tsx +18 -0
  76. package/src/chrome/index.ts +1 -1
  77. package/src/chrome/regions/SidebarRegion.tsx +7 -6
  78. package/src/chrome/regions/TitleBarRegion.test.tsx +64 -0
  79. package/src/chrome/regions/TitleBarRegion.tsx +16 -7
  80. package/src/chrome/regions/ToolbarRegion.test.tsx +14 -0
  81. package/src/chrome/regions/ToolbarRegion.tsx +2 -2
  82. package/src/chrome/regions/ViewportRegion.tsx +2 -2
  83. package/src/chrome/regions/regions.test.tsx +45 -1
  84. package/src/chrome/types.ts +21 -3
  85. package/src/controls/ControlPanel.test.tsx +38 -0
  86. package/src/controls/ControlPanel.tsx +51 -6
  87. package/src/dragdrop/DragDropRuntime.tsx +74 -61
  88. package/src/dragdrop/Palette.tsx +4 -3
  89. package/src/dragdrop/dragDrop.test.tsx +35 -12
  90. package/src/index.ts +2 -1
  91. package/src/instrument/types.ts +4 -5
  92. package/src/job/useJob.ts +1 -1
  93. package/src/lab/Lab.test.tsx +7 -0
  94. package/src/lab/Lab.tsx +2 -2
  95. package/src/lab/LabContext.ts +5 -1
  96. package/src/lab/LabShell.less +17 -2
  97. package/src/lab/Workspace.tsx +1 -1
  98. package/src/layers/AGENTS.md +29 -7
  99. package/src/layers/LayerList.less +16 -0
  100. package/src/layers/LayerList.stories.tsx +66 -0
  101. package/src/layers/LayerList.test.tsx +185 -2
  102. package/src/layers/LayerList.tsx +221 -74
  103. package/src/layers/index.ts +1 -1
  104. package/src/passthrough/weasel-ui.ts +5 -0
  105. package/src/primitives/FloatingPanel.test.tsx +87 -0
  106. package/src/primitives/FloatingPanel.tsx +59 -41
  107. package/src/state/store.test.ts +78 -0
  108. package/src/state/store.ts +27 -0
  109. package/src/state/types.ts +20 -0
  110. package/src/trial/Trial.less +4 -0
  111. package/src/trial/Trial.targets.test.tsx +96 -0
  112. package/src/trial/Trial.test.tsx +171 -14
  113. package/src/trial/Trial.tsx +4 -1
  114. package/src/trial/TrialChrome.tsx +22 -2
  115. package/src/trial/TrialTitleBar.tsx +7 -3
  116. package/src/trial/index.ts +1 -0
  117. package/src/trial/trialOps.test.ts +49 -1
  118. package/src/trial/trialOps.ts +28 -6
  119. package/dist/_dts/DrawCommand-B3bskUsC.d.ts +0 -564
  120. package/dist/_dts/PrefsForm-BkUJZx0A.d.ts +0 -204
  121. package/dist/_dts/fitViewToBounds-dZ2UDB6e.d.ts +0 -21
  122. package/dist/_dts/shapeKinds-Cx_rxwsa.d.ts +0 -87
  123. package/dist/_dts/types-C-gh9Ap-.d.ts +0 -695
  124. package/dist/chunk-4AMN4MMB.js.map +0 -1
  125. package/dist/chunk-7VW3S44V.js.map +0 -1
  126. package/dist/chunk-L5WBGUVR.js.map +0 -1
  127. package/dist/chunk-LJSIUFYD.js.map +0 -1
  128. package/dist/chunk-UD7TEHZT.js.map +0 -1
  129. package/dist/chunk-VHFQKAUL.js.map +0 -1
  130. package/dist/chunk-W3KSUXXR.js.map +0 -1
  131. package/dist/chunk-XCBCZEBO.js +0 -94
  132. package/dist/chunk-XCBCZEBO.js.map +0 -1
  133. package/dist/chunk-YQGQUBKA.js.map +0 -1
package/README.md CHANGED
@@ -120,6 +120,14 @@ changed draws dashed and reports `isStale`. `meaning.statuses` is the optional
120
120
  vocabulary a mark can be labelled with — a status carries its own color, which
121
121
  the mark on the canvas follows.
122
122
 
123
+ `targets` is declared once per instrument and called once per trial, with the
124
+ asking trial as its third argument: `targets(state, config, trial)`. `trial.id`
125
+ is the id `useTileId` scopes a surface tile under, so a consumer holding its own
126
+ per-trial refs keys them by it and hands back the ones this trial owns; a
127
+ module-level ref like the one above is one ref shared by every trial of the
128
+ instrument, which only shows once a second trial is open. `trial.view` is that
129
+ trial's camera.
130
+
123
131
  Marks live in the trial's record and survive a reload. An instrument that would
124
132
  rather keep them in a format it already owns declares `annotations.storage` with
125
133
  a `load`/`save` pair, and labkit never writes its own slot.
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { RefObject } from 'react';
3
- import { V as ViewTransform, W as WorldFrame } from './frac-QS7XzvpG.js';
3
+ import { V as ViewTransform, W as WorldFrame } from './frac-A4R6v4ld.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. */
@@ -0,0 +1,20 @@
1
+ import { ReactNode } from 'react';
2
+ import { T as ToolPrefLeaf } from './weasel-canvas-FJTFi3ZZ.js';
3
+
4
+ /** What a {@link PrefRenderer} is given for the leaf it is rendering. */
5
+ interface PrefRenderContext {
6
+ /** Dotted path of the leaf within the schema root. */
7
+ path: string;
8
+ /** The schema node. App renderers narrow this to their own kind shape. */
9
+ pref: ToolPrefLeaf;
10
+ /** Current value — `values` at `path`, falling back to `pref.default`. */
11
+ value: unknown;
12
+ setValue: (value: unknown) => void;
13
+ }
14
+ /**
15
+ * Renders the control cell for one preference leaf. Returning `null`
16
+ * collapses the row.
17
+ */
18
+ type PrefRenderer = (ctx: PrefRenderContext) => ReactNode;
19
+
20
+ export type { PrefRenderer as P, PrefRenderContext as a };
@@ -1,8 +1,8 @@
1
1
  import { ComponentType, ReactNode, RefObject } from 'react';
2
- import { R as ResolvedConfig, C as ConfigField, a as ConfigSchema } from './types-C1Zw7s5P.js';
3
- import { c as SavedSnapshot } from './types-ChVJJHvk.js';
2
+ import { R as ResolvedConfig, C as ConfigField, a as ConfigSchema } from './types-lg4TSCb2.js';
3
+ import { c as SavedSnapshot, i as TrialInfo } from './types-BbXpvQa8.js';
4
4
  import { J as JobHandle, a as JobCapability } from './types-DJ79Tg5J.js';
5
- import { S as Scene } from './types-C-gh9Ap-.js';
5
+ import { S as Scene } from './weasel-canvas-FJTFi3ZZ.js';
6
6
 
7
7
  /** How an instrument's world sits on the canvas, independent of the camera.
8
8
  * The defaults reproduce the convention labkit shipped before this existed:
@@ -53,7 +53,10 @@ interface ToolbarItem {
53
53
  pressed?: boolean;
54
54
  /** Render the label beside the glyph rather than only in the tooltip. */
55
55
  showLabel?: boolean;
56
- onActivate: () => void;
56
+ /** Handed the trial's chrome context, so a contribution declared from the
57
+ * lab can reach `ctx.saveSnapshot()` and the rest without the `render`
58
+ * escape. A zero-argument handler stays valid. */
59
+ onActivate: (ctx: TrialChromeContext) => void;
57
60
  }
58
61
  /** A selectable tool in the palette region. */
59
62
  interface ToolItem {
@@ -65,7 +68,7 @@ interface ToolItem {
65
68
  /** A titled block in the sidebar. */
66
69
  interface SidebarSection {
67
70
  title: string;
68
- /** Starts collapsed. The open/closed state itself is the region's. */
71
+ /** Starts collapsed, until the trial remembers a fold of its own. */
69
72
  defaultCollapsed?: boolean;
70
73
  /** Offer the tear-out control. On by default; a section that only makes
71
74
  * sense beside its trial sets this false. */
@@ -79,7 +82,8 @@ interface ViewportControl {
79
82
  icon: IconComponent;
80
83
  label: string;
81
84
  disabled?: boolean;
82
- onActivate: () => void;
85
+ /** Handed the trial's chrome context, as `ToolbarItem.onActivate` is. */
86
+ onActivate: (ctx: TrialChromeContext) => void;
83
87
  }
84
88
  /** A readout in the status bar. */
85
89
  interface StatusReadout {
@@ -139,6 +143,12 @@ type TrialContribution = (ContributionBase & {
139
143
  interface TrialChromeContext {
140
144
  trialId: string;
141
145
  instrumentName: string;
146
+ /** What the title bar reads, which is the instrument's name until something
147
+ * calls `setTitle`. */
148
+ title: string;
149
+ /** Retitle this trial; `null` restores the instrument name. Persisted with
150
+ * the trial, so a title survives a reload. */
151
+ setTitle: (title: string | null) => void;
142
152
  isLastTrial: boolean;
143
153
  /** Null when the trial holds a view that is not the 2D one. */
144
154
  zoom: number | null;
@@ -159,6 +169,13 @@ interface TrialChromeContext {
159
169
  configFields: ConfigField[];
160
170
  config: unknown;
161
171
  setConfig: (key: string, value: unknown) => void;
172
+ /** Which of this trial's collapsible sections are folded. A sidebar
173
+ * section's key is its contribution id; a section *inside* a contribution —
174
+ * a control panel's property group — is keyed `<contribution id>/<label>`.
175
+ * A section absent here is at its own default. Persisted with the trial. */
176
+ collapsedSections: Readonly<Record<string, boolean>>;
177
+ /** Fold or unfold one section, keyed as `collapsedSections` is. */
178
+ setSectionCollapsed: (key: string, collapsed: boolean) => void;
162
179
  /** Section ids this trial currently has torn out of its sidebar. */
163
180
  undockedPanels: readonly string[];
164
181
  /** Tear a sidebar section out into the workspace. */
@@ -177,6 +194,12 @@ interface TrialChromeContext {
177
194
  setActiveTool: (id: string) => void;
178
195
  }
179
196
 
197
+ /** A point on the magnified surface, in its own CSS pixels. */
198
+ interface LoupePoint {
199
+ x: number;
200
+ y: number;
201
+ }
202
+
180
203
  /** How a loupe magnifies. `'vector'` re-renders the source through a zoomed-in
181
204
  * view, so content stays sharp at any factor; `'pixel'` blows up the actual
182
205
  * pixels the surface presented. */
@@ -277,11 +300,9 @@ interface RenderContext<TS = unknown, TC = unknown> {
277
300
  config: TC;
278
301
  setState: (next: TS | ((prev: TS) => TS)) => void;
279
302
  setConfig: (key: keyof TC, value: unknown) => void;
280
- trial: {
281
- id: string;
282
- /** The trial's view, in whatever shape this instrument chose. labkit persists
283
- * it and restores it on Reset without ever reading into it. */
284
- view: unknown;
303
+ /** labkit persists `view` and restores it on Reset without ever reading
304
+ * into it. */
305
+ trial: TrialInfo & {
285
306
  setView: (next: unknown) => void;
286
307
  /** 2D convenience over `view`. Reads 1 and writes nothing when the trial holds
287
308
  * a view that is not the 2D one. */
@@ -635,7 +656,9 @@ interface AnnotationStorage {
635
656
  /** Declares that an instrument accepts marks: which regions take them,
636
657
  * optionally what a mark is allowed to mean, and optionally where they live. */
637
658
  interface AnnotationsCapability<TS = unknown, TC = unknown> {
638
- targets: (state: TS, config: TC) => readonly AnnotationTarget[];
659
+ /** `trial` is which trial is asking: a declaration made once per instrument
660
+ * is called once per trial, and its targets are that trial's own. */
661
+ targets: (state: TS, config: TC, trial: TrialInfo) => readonly AnnotationTarget[];
639
662
  meaning?: AnnotationMeaning;
640
663
  storage?: AnnotationStorage;
641
664
  /** Fires after every finished export, labkit's own chrome included. A
@@ -732,4 +755,4 @@ declare function fracContains(box: FracRect, pt: FracPoint, tol?: number): boole
732
755
  declare function fracIntersects(outer: FracRect, inner: FracRect): boolean;
733
756
 
734
757
  export { LOUPE_DEFAULTS as L, annotationsFromJSON as a3, applyCamera as a4, createAnnotationScene as a5, createAnnotationStore as a6, fracContains as a7, fracIntersects as a8, fracToWorld as a9, resolveFrame as aa, resolveLoupe as ab, roundFrac as ac, worldToFrac as ad, DEFAULT_FRAME as x };
735
- export type { TrialRegion as $, AnnotationData as A, LayerCapability as B, CaptureSource as C, DragFeedback as D, LayerDescriptor as E, FracPoint as F, LoupeCapability as G, HitResult as H, Instrument as I, LoupeDeclaration as J, LoupeRenderArgs as K, MarkScene as M, ResolvedLoupe as N, SidebarSection as O, PaletteItem as P, StatusReadout as Q, RenderContext as R, SerializedAnnotations as S, TrialTool as T, SystemEvent as U, ViewTransform as V, WorldFrame as W, ToolCapability as X, ToolItem as Y, ToolbarItem as Z, TrialChromeContext as _, Point as a, UndoCapability as a0, ViewportControl as a1, ViewportSize as a2, LoupeMode as ae, DragDropCapability as b, WorldSpec as c, WorldRect as d, AnnotationMeaning as e, CaptureOptions as f, CaptureResult as g, AnnotationTarget as h, AnnotationsApi as i, AnnotationsCapability as j, AnnotationKind as k, InstrumentList as l, TrialContribution as m, Annotation as n, AnnotationInit as o, AnnotationPatch as p, AnnotationQuery as q, AnnotationStatus as r, AnnotationStoreOptions as s, AnnotationTargetInfo as t, CanvasCapability as u, CanvasLayer as v, CaptureDeps as w, FracRect as y, IconComponent as z };
758
+ export type { TrialRegion as $, AnnotationData as A, LayerCapability as B, CaptureSource as C, DragFeedback as D, LayerDescriptor as E, FracPoint as F, LoupeCapability as G, HitResult as H, Instrument as I, LoupeDeclaration as J, LoupeRenderArgs as K, MarkScene as M, ResolvedLoupe as N, SidebarSection as O, PaletteItem as P, StatusReadout as Q, RenderContext as R, SerializedAnnotations as S, TrialTool as T, SystemEvent as U, ViewTransform as V, WorldFrame as W, ToolCapability as X, ToolItem as Y, ToolbarItem as Z, TrialChromeContext as _, Point as a, UndoCapability as a0, ViewportControl as a1, ViewportSize as a2, LoupePoint as ae, LoupeMode as af, DragDropCapability as b, WorldSpec as c, WorldRect as d, AnnotationMeaning as e, CaptureOptions as f, CaptureResult as g, AnnotationTarget as h, AnnotationsApi as i, AnnotationsCapability as j, AnnotationKind as k, InstrumentList as l, TrialContribution as m, Annotation as n, AnnotationInit as o, AnnotationPatch as p, AnnotationQuery as q, AnnotationStatus as r, AnnotationStoreOptions as s, AnnotationTargetInfo as t, CanvasCapability as u, CanvasLayer as v, CaptureDeps as w, FracRect as y, IconComponent as z };
@@ -1,20 +1,44 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { R as ResolvedConfig, C as ConfigField, c as ControlRenderer } from './types-C1Zw7s5P.js';
3
+ import { R as ResolvedConfig, C as ConfigField, c as ControlRenderer } from './types-lg4TSCb2.js';
4
4
 
5
+ /**
6
+ * How much room a container gives its rows — gaps, padding, and field height,
7
+ * moved together. Set on any container in the family; it reaches every
8
+ * descendant, so an inner group can differ from the panel around it.
9
+ */
10
+ type PropertyDensity = 'tight' | 'normal' | 'roomy';
11
+ /** Where an inline row's label and control sit on the row's cross axis. Set on
12
+ * a container to line a whole column of them up. */
13
+ type PropertyAlign = 'start' | 'center' | 'end' | 'baseline';
14
+ /** Metric props every container in the family takes. Both reach descendants,
15
+ * so the nearest container that states one wins. */
16
+ interface PropertyMetricProps {
17
+ /** Room the rows get. Unset inherits from an outer container, else `normal`. */
18
+ density?: PropertyDensity;
19
+ /**
20
+ * Cross-axis alignment of an inline row's label and control. `baseline` sits
21
+ * the control on the label's first-line baseline, which is what lines a
22
+ * column of swatches up against labels of different heights. Unset keeps each
23
+ * variant's own alignment — a color row centers its label and swatch and
24
+ * sinks the pair to the row's bottom edge, which keeps a paired alpha track
25
+ * level with its neighbour.
26
+ */
27
+ align?: PropertyAlign;
28
+ }
5
29
  /** Props for `<PropertyPanel>`. */
6
- interface PropertyPanelProps {
30
+ interface PropertyPanelProps extends PropertyMetricProps {
7
31
  title?: ReactNode;
8
32
  children: ReactNode;
9
33
  className?: string;
10
34
  }
11
35
  /** A titled panel holding property rows — the sidebar container the rest of
12
36
  * this module's components fill. */
13
- declare function PropertyPanel({ title, children, className }: PropertyPanelProps): react_jsx_runtime.JSX.Element;
37
+ declare function PropertyPanel({ title, children, className, density, align, }: PropertyPanelProps): react_jsx_runtime.JSX.Element;
14
38
  /** How a property list packs its rows into two columns. */
15
- type PropertyListPack = 'auto-color' | 'pairs';
39
+ type PropertyListPack = 'auto-color' | 'pairs' | 'one-up';
16
40
  /** Props for `<PropertyList>`. */
17
- interface PropertyListProps {
41
+ interface PropertyListProps extends PropertyMetricProps {
18
42
  children: ReactNode;
19
43
  className?: string;
20
44
  /**
@@ -24,6 +48,8 @@ interface PropertyListProps {
24
48
  * - `'pairs'`: every row auto-places into the 2-column grid two-per-row.
25
49
  * Headers and subpanels still span the full width; wrap any other
26
50
  * full-width child in `<PropertySpan>`. Right for dense effect bodies.
51
+ * - `'one-up'`: every row spans the full width, color rows included. Right
52
+ * for a palette — a column of swatches read as a group.
27
53
  */
28
54
  pack?: PropertyListPack;
29
55
  }
@@ -31,7 +57,7 @@ interface PropertyListProps {
31
57
  * Grid container for PropertyRows. Use standalone for chrome-less layouts, or
32
58
  * nest inside <PropertyPanel/> for the standard glass card.
33
59
  */
34
- declare function PropertyList({ children, className, pack }: PropertyListProps): react_jsx_runtime.JSX.Element;
60
+ declare function PropertyList({ children, className, pack, density, align, }: PropertyListProps): react_jsx_runtime.JSX.Element;
35
61
  /** Props for `<PropertySpan>`. */
36
62
  interface PropertySpanProps {
37
63
  children: ReactNode;
@@ -49,7 +75,7 @@ type PropertyRowVariant = 'default' | 'color' | 'checkbox';
49
75
  /** Whether a row's label sits above its control or beside it. */
50
76
  type PropertyRowLayout = 'block' | 'inline';
51
77
  /** Props for `<PropertyRow>`. */
52
- interface PropertyRowProps {
78
+ interface PropertyRowProps extends PropertyMetricProps {
53
79
  label: ReactNode;
54
80
  /** Right-aligned readout shown next to the label (e.g. current value). */
55
81
  readout?: ReactNode;
@@ -60,9 +86,9 @@ interface PropertyRowProps {
60
86
  description?: string;
61
87
  variant?: PropertyRowVariant;
62
88
  /**
63
- * Label position relative to the control. "block" (default) stacks
64
- * label above control; "inline" places the label to the left.
65
- * Color and checkbox variants are always inline by their own nature.
89
+ * Label position relative to the control. Unset takes the variant's own
90
+ * orientation: `block` — label above control — for the default variant, and
91
+ * `inline` for the color and checkbox variants, which read as a row.
66
92
  */
67
93
  layout?: PropertyRowLayout;
68
94
  /**
@@ -77,15 +103,26 @@ interface PropertyRowProps {
77
103
  }
78
104
  /** The label-plus-control frame every typed row below is built from. Use it
79
105
  * directly for a control this module does not cover. */
80
- declare function PropertyRow({ label, readout, description, variant, layout, span, children, htmlFor, className, }: PropertyRowProps): react_jsx_runtime.JSX.Element;
106
+ declare function PropertyRow({ label, readout, description, variant, layout, span, children, htmlFor, className, density, align, }: PropertyRowProps): react_jsx_runtime.JSX.Element;
81
107
  /** Props for `<SliderRow>`. */
82
- interface SliderRowProps {
108
+ interface SliderRowProps extends PropertyMetricProps {
83
109
  label: ReactNode;
84
110
  value: number;
85
111
  min: number;
86
112
  max: number;
87
113
  step?: number;
114
+ /**
115
+ * The committed value. Given `onInput` as well, it fires once a drag ends
116
+ * or a typed readout is accepted; on its own it fires on every move, which
117
+ * is what a row with one callback has always done.
118
+ */
88
119
  onChange: (next: number) => void;
120
+ /**
121
+ * The live value, fired continuously through a drag. Pass it alongside
122
+ * `onChange` when the write is expensive — cheap state here, the costly
123
+ * work there. Mirrors `<Slider>`'s `onInput` / `onChange` pair.
124
+ */
125
+ onInput?: (next: number) => void;
89
126
  /** Override how the value is rendered next to the label. Defaults to `value.toString()`. */
90
127
  format?: (value: number) => ReactNode;
91
128
  /**
@@ -101,9 +138,9 @@ interface SliderRowProps {
101
138
  }
102
139
  /** A bounded number edited by dragging, with a live readout whose precision
103
140
  * follows `step`. */
104
- declare function SliderRow({ label, value, min, max, step, onChange, format, unit, layout, description, span, }: SliderRowProps): react_jsx_runtime.JSX.Element;
141
+ declare function SliderRow({ label, value, min, max, step, onChange, onInput, format, unit, layout, description, span, density, align, }: SliderRowProps): react_jsx_runtime.JSX.Element;
105
142
  /** Props for `<ColorRow>`. */
106
- interface ColorRowProps {
143
+ interface ColorRowProps extends PropertyMetricProps {
107
144
  label: ReactNode;
108
145
  value: string;
109
146
  onChange: (next: string) => void;
@@ -115,25 +152,29 @@ interface ColorRowProps {
115
152
  * Use when the color's consumer drops alpha so the affordance reads dead.
116
153
  */
117
154
  alphaDisabled?: boolean;
155
+ /** Label beside the swatch (default) or above it. */
156
+ layout?: PropertyRowLayout;
118
157
  description?: string;
119
158
  /** Take the full width of the enclosing grid — see `<PropertyRow span>`. */
120
159
  span?: boolean;
121
160
  }
122
161
  /** A color swatch, optionally with an alpha slider beneath it. */
123
- declare function ColorRow({ label, value, onChange, alpha, onAlphaChange, alphaDisabled, description, span, }: ColorRowProps): react_jsx_runtime.JSX.Element;
162
+ declare function ColorRow({ label, value, onChange, alpha, onAlphaChange, alphaDisabled, layout, description, span, density, align, }: ColorRowProps): react_jsx_runtime.JSX.Element;
124
163
  /** Props for `<CheckboxRow>`. */
125
- interface CheckboxRowProps {
164
+ interface CheckboxRowProps extends PropertyMetricProps {
126
165
  label: ReactNode;
127
166
  value: boolean;
128
167
  onChange: (next: boolean) => void;
168
+ /** Label beside the box (default) or above it. */
169
+ layout?: PropertyRowLayout;
129
170
  description?: string;
130
171
  /** Take the full width of the enclosing grid — see `<PropertyRow span>`. */
131
172
  span?: boolean;
132
173
  }
133
174
  /** A boolean checkbox. */
134
- declare function CheckboxRow({ label, value, onChange, span, description }: CheckboxRowProps): react_jsx_runtime.JSX.Element;
175
+ declare function CheckboxRow({ label, value, onChange, layout, span, description, density, align, }: CheckboxRowProps): react_jsx_runtime.JSX.Element;
135
176
  /** Props for `<TextRow>`. */
136
- interface TextRowProps {
177
+ interface TextRowProps extends PropertyMetricProps {
137
178
  label: ReactNode;
138
179
  value: string;
139
180
  onChange: (next: string) => void;
@@ -145,9 +186,9 @@ interface TextRowProps {
145
186
  span?: boolean;
146
187
  }
147
188
  /** A single-line text input. */
148
- declare function TextRow({ label, value, onChange, placeholder, maxLength, layout, description, span, }: TextRowProps): react_jsx_runtime.JSX.Element;
189
+ declare function TextRow({ label, value, onChange, placeholder, maxLength, layout, description, span, density, align, }: TextRowProps): react_jsx_runtime.JSX.Element;
149
190
  /** Props for `<NumberRow>`. */
150
- interface NumberRowProps {
191
+ interface NumberRowProps extends PropertyMetricProps {
151
192
  label: ReactNode;
152
193
  value: number;
153
194
  onChange: (next: number) => void;
@@ -168,13 +209,13 @@ interface NumberRowProps {
168
209
  }
169
210
  /** A number typed directly. Reach for `<SliderRow>` when the range matters
170
211
  * more than the exact value. */
171
- declare function NumberRow({ label, value, onChange, min, max, step, placeholder, unit, layout, description, span, }: NumberRowProps): react_jsx_runtime.JSX.Element;
212
+ declare function NumberRow({ label, value, onChange, min, max, step, placeholder, unit, layout, description, span, density, align, }: NumberRowProps): react_jsx_runtime.JSX.Element;
172
213
  interface PropertyOption<T extends string> {
173
214
  value: T;
174
215
  label: ReactNode;
175
216
  }
176
217
  /** Props for `<SelectRow>`. */
177
- interface SelectRowProps<T extends string> {
218
+ interface SelectRowProps<T extends string> extends PropertyMetricProps {
178
219
  label: ReactNode;
179
220
  value: T;
180
221
  options: ReadonlyArray<PropertyOption<T>>;
@@ -186,9 +227,9 @@ interface SelectRowProps<T extends string> {
186
227
  }
187
228
  /** A dropdown over a fixed set of choices. Prefer `<ToggleRow>` when there
188
229
  * are only two or three and they should all stay visible. */
189
- declare function SelectRow<T extends string>({ label, value, options, onChange, layout, description, span, }: SelectRowProps<T>): react_jsx_runtime.JSX.Element;
230
+ declare function SelectRow<T extends string>({ label, value, options, onChange, layout, description, span, density, align, }: SelectRowProps<T>): react_jsx_runtime.JSX.Element;
190
231
  /** Props for `<ToggleRow>`. */
191
- interface ToggleRowProps<T extends string> {
232
+ interface ToggleRowProps<T extends string> extends PropertyMetricProps {
192
233
  label: ReactNode;
193
234
  value: T;
194
235
  options: ReadonlyArray<PropertyOption<T>>;
@@ -200,7 +241,7 @@ interface ToggleRowProps<T extends string> {
200
241
  }
201
242
  /** A segmented control: the same choice as a select, with every option
202
243
  * visible at once. */
203
- declare function ToggleRow<T extends string>({ label, value, options, onChange, layout, description, span, }: ToggleRowProps<T>): react_jsx_runtime.JSX.Element;
244
+ declare function ToggleRow<T extends string>({ label, value, options, onChange, layout, description, span, density, align, }: ToggleRowProps<T>): react_jsx_runtime.JSX.Element;
204
245
 
205
246
  /** How a panel packs its rows into the two-column property grid.
206
247
  * - `'auto'`: narrow controls (numbers, checkboxes, dropdowns, colours) sit
@@ -226,9 +267,28 @@ interface ControlPanelProps<TC extends Record<string, unknown>> {
226
267
  renderers?: Record<string, ControlRenderer>;
227
268
  /** How rows pack into the two-column grid. Defaults to `'pairs'`. */
228
269
  pack?: ControlPack;
229
- /** Where a row's label sits relative to its control. Defaults to `'block'`
230
- * — above it, which is what leaves a paired row room for its value. */
270
+ /**
271
+ * Where a row's label sits relative to its control. Unset takes each row's
272
+ * own orientation — `block` (label above, which is what leaves a paired row
273
+ * room for its value) for most, `inline` for colors and checkboxes.
274
+ */
231
275
  layout?: PropertyRowLayout;
276
+ /** Room the rows get. Passed straight to the property list. */
277
+ density?: PropertyDensity;
278
+ /** Cross-axis alignment of an inline row's label and control. */
279
+ align?: PropertyAlign;
280
+ /**
281
+ * Fold each section away behind a twisty, starting `'open'` or `'closed'`.
282
+ * Unset draws the heading alone, as the panel always has.
283
+ */
284
+ collapse?: 'open' | 'closed';
285
+ /**
286
+ * Which sections are folded, keyed by section label. Given, the panel keeps
287
+ * no state of its own: every toggle arrives at `onCollapse` instead, which
288
+ * is where a lab that remembers a trial's sections writes them.
289
+ */
290
+ collapsed?: Readonly<Record<string, boolean>>;
291
+ onCollapse?: (label: string, collapsed: boolean) => void;
232
292
  /** Draw leaves marked `hidden`. */
233
293
  showHidden?: boolean;
234
294
  className?: string;
@@ -236,7 +296,7 @@ interface ControlPanelProps<TC extends Record<string, unknown>> {
236
296
  /** Render an instrument's config schema as a stack of controls, each writing
237
297
  * back through `setConfig`. Built on the property rows, so a lab's controls
238
298
  * are the same aligned, themed rows the rest of the kit uses. */
239
- declare function ControlPanel<TC extends Record<string, unknown>>({ schema, fields, config, setConfig, renderers, pack, layout, showHidden, className, }: ControlPanelProps<TC>): react_jsx_runtime.JSX.Element;
299
+ declare function ControlPanel<TC extends Record<string, unknown>>({ schema, fields, config, setConfig, renderers, pack, layout, density, align, collapse, collapsed, onCollapse, showHidden, className, }: ControlPanelProps<TC>): react_jsx_runtime.JSX.Element;
240
300
 
241
- export { CheckboxRow as C, NumberRow as N, PropertyList as P, SelectRow as S, TextRow as T, ColorRow as b, ControlPanel as d, PropertyPanel as i, PropertyRow as k, PropertySpan as o, SliderRow as r, ToggleRow as u };
242
- export type { CheckboxRowProps as a, ColorRowProps as c, NumberRowProps as e, PropertyListPack as f, PropertyListProps as g, PropertyOption as h, PropertyPanelProps as j, PropertyRowLayout as l, PropertyRowProps as m, PropertyRowVariant as n, PropertySpanProps as p, SelectRowProps as q, SliderRowProps as s, TextRowProps as t, ToggleRowProps as v };
301
+ export { CheckboxRow as C, NumberRow as N, SelectRow as S, TextRow as T, ColorRow as c, ControlPanel as e, PropertyList as g, PropertyPanel as j, PropertyRow as l, PropertySpan as p, SliderRow as s, ToggleRow as v };
302
+ export type { PropertyMetricProps as P, PropertyListPack as a, CheckboxRowProps as b, ColorRowProps as d, NumberRowProps as f, PropertyListProps as h, PropertyOption as i, PropertyPanelProps as k, PropertyRowLayout as m, PropertyRowProps as n, PropertyRowVariant as o, PropertySpanProps as q, SelectRowProps as r, SliderRowProps as t, TextRowProps as u, ToggleRowProps as w };
@@ -18,6 +18,14 @@ interface UndoStack {
18
18
  past: unknown[];
19
19
  future: unknown[];
20
20
  }
21
+ /** The trial a per-trial call is coming from. `id` is the id `useTileId`
22
+ * scopes a surface tile under, so a consumer keying its own per-trial
23
+ * registry and labkit's tiles agree on the key. */
24
+ interface TrialInfo<TV = unknown> {
25
+ id: string;
26
+ /** The trial's view, in whatever shape the instrument keeps it. */
27
+ view: TV;
28
+ }
21
29
  /** One trial as the store holds it: which instrument it runs, that
22
30
  * instrument's config and state, the camera, and the undo history. */
23
31
  interface TrialRecord<TS = unknown, TC = unknown, TV = unknown> {
@@ -28,11 +36,22 @@ interface TrialRecord<TS = unknown, TC = unknown, TV = unknown> {
28
36
  /** Opaque to labkit: persisted, restored on Reset and handed to the instrument,
29
37
  * but never read into. A 3D lab puts an orbit here and keeps all three. */
30
38
  view: TV;
39
+ /** The config `addTrial` opened this trial on, overlaid on the instrument's
40
+ * defaults. Kept so Reset restores the trial's own subject rather than the
41
+ * bare defaults. */
42
+ configSeed?: Partial<TC>;
31
43
  /** This trial's own tool slot. Undefined means it reads the lab's. */
32
44
  activeToolId?: string | null;
33
45
  /** The extent the trial's sidebar was last dragged to, in pixels. Undefined
34
46
  * until someone moves the seam. */
35
47
  sidebarWidth?: number;
48
+ /** What the title bar reads. Undefined — the state a trial opens in, and the
49
+ * one `setTitle(null)` returns it to — means the instrument's name. */
50
+ title?: string | null;
51
+ /** Which of the trial's collapsible sections are folded, keyed as
52
+ * `TrialChromeContext.collapsedSections` describes. A key that is absent
53
+ * takes the section's own default. */
54
+ collapsedSections?: Record<string, boolean>;
36
55
  /** The marks on this trial's annotation targets, as `AnnotationsApi.toJSON`
37
56
  * wrote them. Opaque here, and absent for a trial whose instrument declares
38
57
  * no `annotations` — or declares its own `storage`. Not in `state`, which
@@ -115,4 +134,4 @@ interface LabDocument {
115
134
  type Migration = (doc: Record<string, unknown>) => Record<string, unknown>;
116
135
 
117
136
  export { dockPanel as g, panelKey as p, undockPanel as u };
118
- export type { CreateLabStoreOptions as C, InstrumentSerializers as I, LabDocument as L, Migration as M, SerializedTrial as S, TrialRecord as T, UndoStack as U, StorageAdapter as a, LabStoreState as b, SavedSnapshot as c, TrialStateHandle as d, UndockedPanel as e, UndockedPanels as f, LabMode as h };
137
+ export type { CreateLabStoreOptions as C, InstrumentSerializers as I, LabDocument as L, Migration as M, SerializedTrial as S, TrialRecord as T, UndoStack as U, StorageAdapter as a, LabStoreState as b, SavedSnapshot as c, TrialStateHandle as d, UndockedPanel as e, UndockedPanels as f, LabMode as h, TrialInfo as i };
@@ -1,4 +1,5 @@
1
- import { P as PrefRenderer, T as ToolPrefLeaf, a as ToolPrefGroup } from './PrefsForm-BkUJZx0A.js';
1
+ import { T as ToolPrefLeaf, a as ToolPrefGroup } from './weasel-canvas-FJTFi3ZZ.js';
2
+ import { P as PrefRenderer } from './PrefsForm.d-CgxUequc.js';
2
3
 
3
4
  /**
4
5
  * Renders the control cell for one config leaf. Identical to weasel-ui's
@@ -1,4 +1,4 @@
1
- import { a as StorageAdapter, b as LabStoreState, T as TrialRecord, c as SavedSnapshot, h as LabMode, e as UndockedPanel, I as InstrumentSerializers, C as CreateLabStoreOptions, d as TrialStateHandle } from './types-ChVJJHvk.js';
1
+ import { a as StorageAdapter, b as LabStoreState, T as TrialRecord, c as SavedSnapshot, h as LabMode, e as UndockedPanel, I as InstrumentSerializers, C as CreateLabStoreOptions, d as TrialStateHandle } from './types-BbXpvQa8.js';
2
2
  import * as react from 'react';
3
3
  import { ReactNode, ReactElement } from 'react';
4
4
  import { StoreApi } from 'zustand/vanilla';
@@ -26,6 +26,10 @@ interface LabStoreActions {
26
26
  updateTrialConfig: <TC>(id: string, key: keyof TC, value: TC[keyof TC]) => void;
27
27
  updateTrialView: (id: string, view: unknown) => void;
28
28
  updateTrialSidebarWidth: (id: string, width: number) => void;
29
+ /** Retitle a trial. `null` returns it to its instrument's name. */
30
+ setTrialTitle: (id: string, title: string | null) => void;
31
+ /** Fold or unfold one of a trial's sections. */
32
+ setTrialSectionCollapsed: (id: string, key: string, collapsed: boolean) => void;
29
33
  updateTrialAnnotations: (id: string, doc: unknown) => void;
30
34
  updateTrialUndoStack: (id: string, next: TrialRecord['undoStack'] | ((prev: TrialRecord['undoStack']) => TrialRecord['undoStack'])) => void;
31
35
  setTrialInstrument: (id: string, instrumentName: string) => void;