@weasel-js/labkit 1.4.3 → 1.5.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 (229) hide show
  1. package/README.md +13 -2
  2. package/dist/_dts/{CanvasStackContext-Dde8_1my.d.ts → CanvasStackContext-CqkxkFJW.d.ts} +1 -1
  3. package/dist/_dts/ToggleBar.d-DbHoWKIA.d.ts +116 -0
  4. package/dist/_dts/{frac-B5mB8LsJ.d.ts → frac-8R6UmlvN.d.ts} +256 -33
  5. package/dist/_dts/index-B8uu2ba7.d.ts +237 -0
  6. package/dist/_dts/{index-DelFfeV0.d.ts → index-retnAut7.d.ts} +45 -12
  7. package/dist/_dts/{types-B9_zrHmb.d.ts → types-Ca2LCnPq.d.ts} +65 -2
  8. package/dist/_dts/usePanZoom-nS798rOF.d.ts +160 -0
  9. package/dist/_dts/useTrialState-jcx_TdU6.d.ts +212 -0
  10. package/dist/canvas/index.d.ts +17 -128
  11. package/dist/canvas/index.js +4 -2
  12. package/dist/chrome/index.d.ts +4 -92
  13. package/dist/chrome/index.js +9 -5
  14. package/dist/chunk-67SJLMC7.js +704 -0
  15. package/dist/chunk-67SJLMC7.js.map +1 -0
  16. package/dist/chunk-6ZDGOZQV.js +310 -0
  17. package/dist/chunk-6ZDGOZQV.js.map +1 -0
  18. package/dist/{chunk-QAGAHJKZ.js → chunk-EKIICY6X.js} +111 -25
  19. package/dist/chunk-EKIICY6X.js.map +1 -0
  20. package/dist/{chunk-CTRKTLYZ.js → chunk-H6ZAOWNE.js} +11 -11
  21. package/dist/chunk-H6ZAOWNE.js.map +1 -0
  22. package/dist/{chunk-2RQPGOQF.js → chunk-KJALCDWE.js} +9 -7
  23. package/dist/chunk-KJALCDWE.js.map +1 -0
  24. package/dist/{chunk-ISCOFAUO.js → chunk-MUKOW3TC.js} +3 -3
  25. package/dist/{chunk-ISCOFAUO.js.map → chunk-MUKOW3TC.js.map} +1 -1
  26. package/dist/chunk-NDRYLVOW.js +15 -0
  27. package/dist/chunk-NDRYLVOW.js.map +1 -0
  28. package/dist/{chunk-C42T6DJT.js → chunk-NS64DXMN.js} +226 -159
  29. package/dist/chunk-NS64DXMN.js.map +1 -0
  30. package/dist/{chunk-I6JCVE24.js → chunk-PGETSEDK.js} +135 -13
  31. package/dist/chunk-PGETSEDK.js.map +1 -0
  32. package/dist/{chunk-FQMJUVHJ.js → chunk-QLSV2N3G.js} +32 -37
  33. package/dist/chunk-QLSV2N3G.js.map +1 -0
  34. package/dist/chunk-RWNDDKOH.js +682 -0
  35. package/dist/chunk-RWNDDKOH.js.map +1 -0
  36. package/dist/chunk-S2SHZRD7.js +7681 -0
  37. package/dist/chunk-S2SHZRD7.js.map +1 -0
  38. package/dist/{chunk-ASWKLRKJ.js → chunk-TQBBYTAF.js} +19 -82
  39. package/dist/chunk-TQBBYTAF.js.map +1 -0
  40. package/dist/chunk-UU3NJO6N.js +72 -0
  41. package/dist/chunk-UU3NJO6N.js.map +1 -0
  42. package/dist/chunk-WIG6XHJ7.js +35 -0
  43. package/dist/chunk-WIG6XHJ7.js.map +1 -0
  44. package/dist/{chunk-TJ7QY3OC.js → chunk-ZPH5WTWF.js} +21 -15
  45. package/dist/chunk-ZPH5WTWF.js.map +1 -0
  46. package/dist/config/index.d.ts +232 -0
  47. package/dist/config/index.js +6 -0
  48. package/dist/config/index.js.map +1 -0
  49. package/dist/controls/index.d.ts +2 -3
  50. package/dist/controls/index.js +3 -2
  51. package/dist/dragdrop/index.d.ts +2 -4
  52. package/dist/index.d.ts +123 -348
  53. package/dist/index.js +794 -837
  54. package/dist/index.js.map +1 -1
  55. package/dist/layers/index.d.ts +3 -5
  56. package/dist/layers/index.js +2 -2
  57. package/dist/loupe/index.d.ts +6 -8
  58. package/dist/loupe/index.js +2 -2
  59. package/dist/passthrough/weasel-ui.d.ts +169 -117
  60. package/dist/passthrough/weasel-ui.js +1 -1
  61. package/dist/primitives/index.d.ts +53 -6
  62. package/dist/primitives/index.js +6 -4
  63. package/dist/state/index.d.ts +12 -7
  64. package/dist/state/index.js +16 -13
  65. package/dist/state/index.js.map +1 -1
  66. package/dist/styles.css +163 -62
  67. package/dist/surface/index.d.ts +44 -7
  68. package/dist/surface/index.js +2 -1
  69. package/dist/ui/layers/index.js +1 -1
  70. package/dist/undo/index.d.ts +2 -4
  71. package/package.json +15 -8
  72. package/src/annotations/AnnotationOverlay.tsx +53 -5
  73. package/src/annotations/Annotations.overlay.test.tsx +85 -6
  74. package/src/annotations/drawOne.test.ts +1 -1
  75. package/src/annotations/drawOne.ts +2 -2
  76. package/src/annotations/frac.test.ts +4 -4
  77. package/src/annotations/frac.ts +3 -2
  78. package/src/annotations/index.ts +1 -1
  79. package/src/annotations/paint.test.ts +2 -2
  80. package/src/annotations/paint.ts +1 -1
  81. package/src/annotations/preload.ts +6 -0
  82. package/src/annotations/store.test.ts +18 -0
  83. package/src/annotations/store.ts +7 -6
  84. package/src/annotations/svgNodes.test.ts +2 -2
  85. package/src/annotations/svgNodes.ts +1 -2
  86. package/src/annotations/toolMap.ts +3 -3
  87. package/src/annotations/types.ts +6 -3
  88. package/src/canvas/CameraWheelContext.ts +12 -0
  89. package/src/canvas/CanvasStack.test.tsx +25 -0
  90. package/src/canvas/CanvasStack.tsx +31 -4
  91. package/src/canvas/Stage.less +18 -0
  92. package/src/canvas/Stage.test.tsx +186 -0
  93. package/src/canvas/Stage.tsx +134 -0
  94. package/src/canvas/camera.test.ts +17 -2
  95. package/src/canvas/camera.ts +9 -9
  96. package/src/canvas/index.ts +4 -0
  97. package/src/canvas/usePanZoom.ts +10 -5
  98. package/src/chrome/ChromeRegions.stories.tsx +0 -3
  99. package/src/chrome/LabChrome.tsx +114 -0
  100. package/src/chrome/builtins.tsx +20 -31
  101. package/src/chrome/index.ts +15 -0
  102. package/src/chrome/labRegions.test.tsx +208 -0
  103. package/src/chrome/labTypes.ts +50 -0
  104. package/src/chrome/merge.ts +7 -9
  105. package/src/chrome/regions/PaletteRegion.test.tsx +6 -4
  106. package/src/chrome/regions/PaletteRegion.tsx +21 -9
  107. package/src/chrome/regions/SidebarRegion.tsx +25 -13
  108. package/src/chrome/regions/StatusRegion.tsx +15 -8
  109. package/src/chrome/regions/ToolbarRegion.tsx +30 -16
  110. package/src/chrome/types.ts +47 -20
  111. package/src/config/builder.test.ts +4 -0
  112. package/src/config/builder.ts +16 -10
  113. package/src/config/declarationEmit.fixture.ts +11 -0
  114. package/src/config/declarationEmit.test.ts +51 -0
  115. package/src/config/entry.test.ts +46 -0
  116. package/src/config/index.ts +13 -1
  117. package/src/config/nodeClasses.test.ts +18 -0
  118. package/src/config/types.ts +3 -1
  119. package/src/controls/ControlPanel.test.tsx +16 -0
  120. package/src/controls/ControlPanel.tsx +5 -2
  121. package/src/fake-indexeddb-auto.d.ts +5 -0
  122. package/src/index.test.ts +7 -0
  123. package/src/index.ts +39 -6
  124. package/src/instrument/serializers.test.ts +22 -0
  125. package/src/instrument/serializers.ts +11 -0
  126. package/src/instrument/types.ts +25 -1
  127. package/src/lab/Lab.less +4 -13
  128. package/src/lab/Lab.persist.test.tsx +147 -0
  129. package/src/lab/Lab.stories.tsx +0 -2
  130. package/src/lab/Lab.surface.test.tsx +66 -3
  131. package/src/lab/Lab.test.tsx +91 -17
  132. package/src/lab/Lab.tsx +337 -124
  133. package/src/lab/LabFit.stories.less +18 -0
  134. package/src/lab/LabFit.stories.tsx +219 -0
  135. package/src/lab/LabFullChrome.stories.tsx +0 -3
  136. package/src/lab/LabHeader.test.tsx +40 -9
  137. package/src/lab/LabHeader.tsx +7 -13
  138. package/src/lab/LabPalette.tsx +13 -26
  139. package/src/lab/LabShell.less +49 -12
  140. package/src/lab/LabShell.tsx +14 -2
  141. package/src/lab/LabSwitcher.less +92 -0
  142. package/src/lab/LabSwitcher.test.tsx +96 -0
  143. package/src/lab/LabSwitcher.tsx +112 -0
  144. package/src/lab/Workspace.surface.test.tsx +2 -1
  145. package/src/lab/fitCheck.test.ts +57 -0
  146. package/src/lab/fitCheck.ts +125 -0
  147. package/src/lab/index.ts +2 -0
  148. package/src/loupe/AGENTS.md +1 -1
  149. package/src/loupe/Loupe.less +1 -1
  150. package/src/loupe/canvasLens.ts +1 -1
  151. package/src/loupe/types.ts +1 -1
  152. package/src/loupe/useLoupe.test.tsx +1 -1
  153. package/src/loupe/useLoupe.ts +1 -1
  154. package/src/passthrough/weasel-ui.ts +9 -0
  155. package/src/primitives/FloatingPanel.stories.tsx +13 -1
  156. package/src/primitives/FloatingPanel.test.tsx +47 -16
  157. package/src/primitives/FloatingPanel.tsx +11 -25
  158. package/src/primitives/Split.less +14 -0
  159. package/src/primitives/Split.test.tsx +108 -0
  160. package/src/primitives/Split.tsx +159 -0
  161. package/src/primitives/ZoomControl.tsx +5 -2
  162. package/src/primitives/index.ts +2 -0
  163. package/src/state/Persistence.stories.tsx +75 -0
  164. package/src/state/Persistence.tsx +33 -0
  165. package/src/state/SingletonExperiment.test.tsx +47 -53
  166. package/src/state/SingletonExperiment.tsx +24 -13
  167. package/src/state/adapterContract.ts +116 -0
  168. package/src/state/adapters.test.ts +113 -61
  169. package/src/state/adapters.ts +328 -69
  170. package/src/state/document.test.ts +71 -96
  171. package/src/state/document.ts +66 -52
  172. package/src/state/helpers.test.ts +20 -0
  173. package/src/state/helpers.ts +16 -0
  174. package/src/state/index.ts +8 -0
  175. package/src/state/labRecords.test.ts +105 -0
  176. package/src/state/labRecords.ts +160 -0
  177. package/src/state/openLabStore.test.ts +658 -0
  178. package/src/state/openLabStore.ts +403 -0
  179. package/src/state/records.test.ts +234 -0
  180. package/src/state/records.ts +219 -0
  181. package/src/state/store.test.ts +104 -635
  182. package/src/state/store.ts +117 -158
  183. package/src/state/toolSlot.test.ts +1 -1
  184. package/src/state/types.ts +39 -15
  185. package/src/state/useOpenOnce.ts +68 -0
  186. package/src/state/usePersistedState.test.tsx +125 -0
  187. package/src/state/usePersistedState.ts +66 -0
  188. package/src/state/useTrialState.test.tsx +2 -3
  189. package/src/state/view.test.ts +49 -15
  190. package/src/state/view.ts +18 -1
  191. package/src/styles.less +3 -0
  192. package/src/surface/AGENTS.md +39 -7
  193. package/src/surface/SurfaceContext.ts +26 -3
  194. package/src/surface/index.ts +2 -0
  195. package/src/surface/useSurfaceTile.test.tsx +2 -1
  196. package/src/surface/useSurfaceTile.ts +6 -5
  197. package/src/surface/useTiledSurface.test.tsx +175 -0
  198. package/src/surface/useTiledSurface.ts +54 -5
  199. package/src/theme/Interstellar.stories.tsx +7 -7
  200. package/src/theme/base.less +4 -4
  201. package/src/theme/interstellar.test.ts +1 -1
  202. package/src/theme/interstellar.tokens.json +2 -2
  203. package/src/tools/labTool.ts +11 -0
  204. package/src/trial/Trial.annotations.persist.test.tsx +100 -58
  205. package/src/trial/Trial.annotations.test.tsx +47 -4
  206. package/src/trial/Trial.job.test.tsx +3 -3
  207. package/src/trial/Trial.less +1 -26
  208. package/src/trial/Trial.stories.tsx +1 -2
  209. package/src/trial/Trial.test.tsx +28 -4
  210. package/src/trial/Trial.trialId.test.tsx +23 -1
  211. package/src/trial/Trial.tsx +118 -38
  212. package/src/trial/TrialBody.tsx +17 -141
  213. package/src/trial/TrialChrome.tsx +7 -4
  214. package/src/trial/trialOps.ts +7 -4
  215. package/dist/_dts/types-BP2OCcpg.d.ts +0 -155
  216. package/dist/_dts/types-x92Kfeme.d.ts +0 -62
  217. package/dist/_dts/useTrialState-D6Vb3T-g.d.ts +0 -99
  218. package/dist/chunk-2RQPGOQF.js.map +0 -1
  219. package/dist/chunk-5TROQVQ2.js +0 -547
  220. package/dist/chunk-5TROQVQ2.js.map +0 -1
  221. package/dist/chunk-ASWKLRKJ.js.map +0 -1
  222. package/dist/chunk-C42T6DJT.js.map +0 -1
  223. package/dist/chunk-CTRKTLYZ.js.map +0 -1
  224. package/dist/chunk-FQMJUVHJ.js.map +0 -1
  225. package/dist/chunk-I6JCVE24.js.map +0 -1
  226. package/dist/chunk-MHAGC6VD.js +0 -7320
  227. package/dist/chunk-MHAGC6VD.js.map +0 -1
  228. package/dist/chunk-QAGAHJKZ.js.map +0 -1
  229. package/dist/chunk-TJ7QY3OC.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -1,29 +1,29 @@
1
+ export { B as Button, a as ButtonProps, b as ButtonSize, c as ButtonVariant, T as ToggleBar, d as ToggleBarItem, e as ToggleBarProps, f as ToggleBarSize, g as ToggleBarVariant } from './_dts/ToggleBar.d-DbHoWKIA.js';
1
2
  export { LayerStack, LayerStackItem, LayerStackProps } from './ui/layers/index.js';
2
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
4
  import * as react from 'react';
4
5
  import { ReactNode } from 'react';
5
- import { P as PropertyMetricProps, a as PropertyListPack } from './_dts/index-DelFfeV0.js';
6
- export { C as CheckboxRow, b as CheckboxRowProps, c as ColorRow, d as ColorRowProps, e as ControlPanel, N as NumberRow, f as NumberRowProps, g as PropertyList, h as PropertyListProps, i as PropertyOption, j as PropertyPanel, k as PropertyPanelProps, l as PropertyRow, m as PropertyRowLayout, n as PropertyRowProps, o as PropertyRowVariant, p as PropertySpan, q as PropertySpanProps, S as SelectRow, r as SelectRowProps, s as SliderRow, t as SliderRowProps, T as TextRow, u as TextRowProps, v as ToggleRow, w as ToggleRowProps } from './_dts/index-DelFfeV0.js';
7
- import { DrawCommand, SceneNode, View, Path, FillStyle, StyledRun, TextStyle, Stroke, BuiltinToolId, ToolPrefLeaf, ToolPrefGroup } from '@weasel-js/core';
8
- import { d as WorldRect, A as AnnotationData, e as AnnotationMeaning, M as MarkScene, C as CaptureSource, f as CaptureOptions, g as CaptureResult, h as AnnotationTarget, i as AnnotationsApi, j as AnnotationsCapability, T as TrialTool, k as AnnotationKind, V as ViewTransform, I as Instrument, l as InstrumentList, m as TrialContribution } from './_dts/frac-B5mB8LsJ.js';
9
- export { n as Annotation, o as AnnotationInit, p as AnnotationPatch, q as AnnotationQuery, r as AnnotationStatus, s as AnnotationStoreOptions, t as AnnotationTargetInfo, u as CanvasCapability, v as CanvasLayer, w as CaptureDeps, x as DEFAULT_FRAME, b as DragDropCapability, D as DragFeedback, F as FracPoint, y as FracRect, H as HitResult, z as IconComponent, L as LOUPE_DEFAULTS, B as LayerCapability, E as LayerDescriptor, G as LoupeCapability, J as LoupeDeclaration, K as LoupeRenderArgs, P as PaletteItem, a as Point, R as RenderContext, N as ResolvedLoupe, S as SerializedAnnotations, O as SidebarSection, Q as StatusReadout, U as SystemEvent, X as ToolCapability, Y as ToolItem, Z as ToolbarItem, _ as TrialChromeContext, $ as TrialRegion, a0 as UndoCapability, a1 as ViewportControl, a2 as ViewportSize, W as WorldFrame, c as WorldSpec, a3 as annotationsFromJSON, a4 as applyCamera, a5 as createAnnotationScene, a6 as createAnnotationStore, a7 as fracContains, a8 as fracIntersects, a9 as fracToWorld, aa as resolveFrame, ab as resolveLoupe, ac as roundFrac, ad as worldToFrac } from './_dts/frac-B5mB8LsJ.js';
10
- import { i as TrialInfo, a as StorageAdapter, h as LabMode, T as TrialRecord, c as SavedSnapshot } from './_dts/types-BP2OCcpg.js';
11
- export { C as CreateLabStoreOptions, L as LabDocument, b as LabStoreState, S as SerializedTrial, d as TrialStateHandle, U as UndoStack, e as UndockedPanel, f as UndockedPanels, g as dockPanel, p as panelKey, u as undockPanel } from './_dts/types-BP2OCcpg.js';
12
- export { CanvasStack, CanvasStackProps, OrbitHandlers, OrbitView, PITCH_LIMIT, PanZoomHandlers, UseOrbitOptions, UsePanZoomOptions, Vec3, ZoomAtOptions, centerOn, clampPitch, orbitAfterDrag, orbitAfterWheel, screenToWorld, useOrbit, usePanZoom, worldToScreen, wrapYaw, zoomAt } from './canvas/index.js';
13
- export { C as CanvasLayerDescriptor, a as CanvasStackContext, b as CanvasStackContextValue, c as CanvasStackSurface } from './_dts/CanvasStackContext-Dde8_1my.js';
14
- export { PaletteRegion, PaletteRegionProps, SidebarRegion, SidebarRegionProps, StatusRegion, StatusRegionProps, TitleBarPlacement, TitleBarRegion, TitleBarRegionProps, ToolbarRegion, ToolbarRegionProps, ViewportRegion, ViewportRegionProps, builtinContributions, mergeContributions, suppressContributions } from './chrome/index.js';
15
- import { b as ConfigNode, A as Annotations, N as NodeOptions, c as ControlRenderer, d as ConfigOption, e as ConfigShape, f as ConfigBranch, B as BranchAnnotations, g as BranchOptions, a as ConfigSchema, I as InferConfig, h as ConfigEntry, R as ResolvedConfig, i as ConfigRule, L as LeafPatch, j as ConfigRuleContext } from './_dts/types-B9_zrHmb.js';
16
- export { k as ConfigOf, C as ConfigPath, E as EntryValue, l as NodeValue, S as SectionSpec, V as ValueAtPath } from './_dts/types-B9_zrHmb.js';
17
- import { C as ConfigField } from './_dts/types-x92Kfeme.js';
18
- export { a as CheckboxField, b as ColorField, c as ConfigFieldBase, d as ConfigFieldType, N as NumberField, S as SelectField, e as SelectOption, f as SliderField, T as TextField } from './_dts/types-x92Kfeme.js';
6
+ import { P as PropertyMetricProps, a as PropertyListPack } from './_dts/index-retnAut7.js';
7
+ export { C as CheckboxRow, b as CheckboxRowProps, c as ColorRow, d as ColorRowProps, e as ControlPanel, N as NumberRow, f as NumberRowProps, g as PropertyList, h as PropertyListProps, i as PropertyOption, j as PropertyPanel, k as PropertyPanelProps, l as PropertyRow, m as PropertyRowLayout, n as PropertyRowProps, o as PropertyRowVariant, p as PropertySpan, q as PropertySpanProps, S as SelectRow, r as SelectRowProps, s as SliderRow, t as SliderRowProps, T as TextRow, u as TextRowProps, v as ToggleRow, w as ToggleRowProps } from './_dts/index-retnAut7.js';
8
+ import { DrawCommand, SceneNode, View, Path, FillStyle, StyledRun, TextStyle, Stroke, BuiltinToolId } from '@weasel-js/core';
9
+ import { t as WorldRect, A as AnnotationData, v as AnnotationMeaning, w as MarkScene, x as CaptureSource, y as CaptureOptions, z as CaptureResult, B as AnnotationTarget, E as AnnotationsApi, F as AnnotationsCapability, G as TrialInfo, H as TrialTool, J as AnnotationKind, k as ViewTransform, K as Instrument, q as InstrumentList, o as LabMode, N as TrialContribution, c as StorageAdapter, T as TrialRecord } from './_dts/frac-8R6UmlvN.js';
10
+ export { O as Annotation, Q as AnnotationInit, R as AnnotationPatch, X as AnnotationQuery, Y as AnnotationStatus, Z as AnnotationStoreOptions, _ as AnnotationTargetInfo, $ as CanvasCapability, a0 as CanvasLayer, a1 as CaptureDeps, a2 as ContributionBase, C as CreateLabStoreOptions, D as DEFAULT_FRAME, n as DragDropCapability, m as DragFeedback, a3 as FracPoint, a4 as FracRect, a5 as HitResult, a6 as IconComponent, a7 as LOUPE_DEFAULTS, L as LabDocument, d as LabStoreState, a8 as LayerCapability, a9 as LayerDescriptor, aa as LoupeCapability, ab as LoupeDeclaration, ac as LoupeRenderArgs, P as PaletteItem, l as Point, ad as RegionContribution, ae as RenderContext, af as ResolvedLoupe, e as SavedSnapshot, ag as SerializedAnnotations, S as SerializedTrial, ah as SidebarSection, ai as SidebarSlotContext, aj as StageCapability, ak as StatusReadout, f as StorageChange, al as SystemEvent, am as ToolCapability, an as ToolItem, ao as ToolSlotContext, ap as ToolbarItem, aq as TrialChromeContext, ar as TrialRegion, g as TrialStateHandle, as as UndoCapability, U as UndoStack, h as UndockedPanel, i as UndockedPanels, at as ViewportControl, V as ViewportSize, W as WorldFrame, a as WorldSpec, au as annotationsFromJSON, b as applyCamera, av as createAnnotationScene, aw as createAnnotationStore, j as dockPanel, ax as fracContains, ay as fracEncloses, az as fracToWorld, p as panelKey, r as resolveFrame, aA as resolveLoupe, aB as roundFrac, u as undockPanel, aC as worldToFrac } from './_dts/frac-8R6UmlvN.js';
11
+ export { C as CanvasStack, a as CanvasStackProps, O as OrbitHandlers, b as OrbitView, P as PITCH_LIMIT, c as PanZoomHandlers, S as Stage, d as StageProps, U as UseOrbitOptions, e as UsePanZoomOptions, V as Vec3, Z as ZoomAtOptions, f as centerOn, g as clampPitch, h as fitStage, o as orbitAfterDrag, i as orbitAfterWheel, s as screenToWorld, u as useOrbit, j as usePanZoom, w as worldToScreen, k as wrapYaw, z as zoomAt } from './_dts/usePanZoom-nS798rOF.js';
12
+ export { C as CanvasLayerDescriptor, a as CanvasStackContext, b as CanvasStackContextValue, c as CanvasStackSurface } from './_dts/CanvasStackContext-CqkxkFJW.js';
13
+ import { L as LabContribution } from './_dts/index-B8uu2ba7.js';
14
+ export { A as AddTrialOptions, a as LabChromeContext, b as LabContext, c as LabContextValue, d as LabFooterRegion, e as LabHeaderRegion, f as LabRegion, g as LabRegionProps, h as LabSidebarRegion, P as PaletteRegion, i as PaletteRegionProps, S as SidebarRegion, j as SidebarRegionProps, k as StatusRegion, l as StatusRegionProps, T as TitleBarPlacement, m as TitleBarRegion, n as TitleBarRegionProps, o as ToolbarRegion, p as ToolbarRegionProps, V as ViewportRegion, q as ViewportRegionProps, r as addTrial, s as builtinContributions, t as cloneTrial, u as closeTrial, v as contributionsIn, w as labContributions, x as mergeContributions, y as reorderTrials, z as resetTrial, B as suppressContributions, C as toolContributions, D as useLabChromeContext, E as useLabContext } from './_dts/index-B8uu2ba7.js';
15
+ export { BaseNode, BooleanNode, ColorNode, CustomNode, EnumNode, GroupNode, NumberNode, StringNode, ValueNode, applyRules, builtinRules, f, fillConfigDefaults, fromConfigFields, hasConfigPath, isConfigBranch, isLeafVisible, resolveConfigSchema, schemaNodeAtPath, titleCase, useConfigSchema, valueAtPath, withValueAtPath } from './config/index.js';
16
+ import { b as ConfigSchema, a as ConfigField, c as ConfigRule, d as ControlRenderer } from './_dts/types-Ca2LCnPq.js';
17
+ export { A as Annotations, B as BranchAnnotations, e as BranchOptions, f as CheckboxField, g as ColorField, h as ConfigBranch, i as ConfigEntry, j as ConfigFieldBase, k as ConfigFieldType, l as ConfigNode, m as ConfigOf, n as ConfigOption, C as ConfigPath, o as ConfigRuleContext, p as ConfigShape, E as EntryValue, I as InferConfig, L as LeafPatch, N as NodeOptions, q as NodeValue, r as NumberField, R as ResolvedConfig, S as SectionSpec, s as SelectField, t as SelectOption, u as SliderField, T as TextField, V as ValueAtPath } from './_dts/types-Ca2LCnPq.js';
19
18
  import { J as JobHandle } from './_dts/types-DJ79Tg5J.js';
20
19
  export { a as JobCapability, b as JobEvent, c as JobFailure, d as JobStatus } from './_dts/types-DJ79Tg5J.js';
21
20
  export { UseJobOptions, useJob } from './job/index.js';
22
21
  export { LayerList, LayerListProps, LayerTreeNode } from './layers/index.js';
23
22
  export { CanvasLoupe, CanvasLoupeProps, DomLoupe, DomLoupeProps, LensCamera, LoupeBubble, LoupeBubbleProps, LoupeState, SourceRect, TrialLoupe, TrialLoupeProps, UseLoupeOptions, drawCanvasLens, lensCamera, lensSourceRect, sampleStack, useLoupe } from './loupe/index.js';
24
- export { FloatingPanel, FloatingPanelProps, FpsMeter, JobProgress, JobProgressProps, Legend, LegendEntry, LegendMark, LegendProps, ScaleIndicator, ScaleIndicatorProps, Sidebar, SidebarProps, StatusBar, StatusBarProps, StatusBarSectionProps, Toolbar, ToolbarButtonProps, ToolbarGroupProps, ToolbarProps, ZoomControl, ZoomControlProps } from './primitives/index.js';
25
- export { C as CURRENT_DOCUMENT_VERSION, b as LabStoreContext, c as LabStoreProvider, T as TrialIdContext, d as TrialIdProvider, f as createMemoryAdapter, l as labDocumentKey, g as localStorageAdapter, n as noneAdapter, q as quarantineKey, s as sessionStorageAdapter, u as urlHashAdapter, h as useLabStore, i as useTrialId, j as useTrialState } from './_dts/useTrialState-D6Vb3T-g.js';
26
- export { Box, Rect, SurfaceCanvasContext, SurfaceContext, SurfaceFrame, SurfaceHandle, TilePainter, UseTiledSurfaceOptions, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceCanvas, useSurfaceOptional, useSurfaceTile, useTileId, useTiledSurface } from './surface/index.js';
23
+ import { SplitProps } from './primitives/index.js';
24
+ export { FloatingPanel, FloatingPanelProps, FpsMeter, JobProgress, JobProgressProps, Legend, LegendEntry, LegendMark, LegendProps, ScaleIndicator, ScaleIndicatorProps, Sidebar, SidebarProps, Split, StatusBar, StatusBarProps, StatusBarSectionProps, Toolbar, ToolbarButtonProps, ToolbarGroupProps, ToolbarProps, ZoomControl, ZoomControlProps } from './primitives/index.js';
25
+ export { C as CURRENT_DOCUMENT_VERSION, I as IndexedDbAdapterOptions, b as LabStoreContext, c as LabStoreProvider, O as OpenLabStoreOptions, d as OpenedLabStore, P as PersistedStateOptions, e as Persistence, f as PersistenceProps, R as RecordCache, g as RecordChange, T as TrialIdContext, h as TrialIdProvider, i as createIndexedDbAdapter, k as createMemoryAdapter, l as indexedDbAdapter, m as labDocumentKey, n as localStorageAdapter, o as noneAdapter, p as openLabStore, q as quarantineKey, s as sessionStorageAdapter, u as urlHashAdapter, r as useLabStore, t as usePersistedState, v as useTrialId, w as useTrialState } from './_dts/useTrialState-jcx_TdU6.js';
26
+ export { Box, Rect, SurfaceCanvasContext, SurfaceCanvases, SurfaceClear, SurfaceContext, SurfaceFrame, SurfaceHandle, SurfaceLayer, TilePainter, UseTiledSurfaceOptions, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceCanvas, useSurfaceOptional, useSurfaceTile, useTileId, useTiledSurface } from './surface/index.js';
27
27
  export { EventBus, EventListener, clearUndo, createEventBus, emptyStack, pushSnapshot, redo, undo } from './undo/index.js';
28
28
  import './_dts/PrefsForm.d-DDHFANkc.js';
29
29
  import 'windease';
@@ -177,7 +177,7 @@ interface PaintableMark {
177
177
  /** How a mark is drawn, as opposed to where. Resolved by the overlay from the
178
178
  * instrument's vocabulary and the mark's own staleness. */
179
179
  interface MarkStyle {
180
- /** The status's colour, or the default. */
180
+ /** The status's color, or the default. */
181
181
  color?: string;
182
182
  /** A mark whose stored position no longer describes the picture. Drawn
183
183
  * dashed rather than hidden: it still describes *something*, and dropping
@@ -207,14 +207,14 @@ interface MarkDrawOptions {
207
207
  positionDependsOn?: readonly string[];
208
208
  /** The trial's config at the time of the draw. */
209
209
  config: unknown;
210
- /** The instrument's vocabulary, for a status's colour. */
210
+ /** The instrument's vocabulary, for a status's color. */
211
211
  meaning?: AnnotationMeaning;
212
212
  }
213
213
  /**
214
214
  * How one mark is drawn — shared by the pane on screen and by an export.
215
215
  *
216
216
  * One function rather than two call sites building their own, because an
217
- * export that resolves a status colour or a stale dash differently from the
217
+ * export that resolves a status color or a stale dash differently from the
218
218
  * screen produces a picture nobody was looking at.
219
219
  */
220
220
  declare function createMarkDrawOne(opts: MarkDrawOptions): (node: SceneNode<AnnotationData, 'marks', WorldRect>, pose: WorldRect, view: View) => DrawCommand[];
@@ -377,7 +377,12 @@ type SvgPaint = {
377
377
  /** Stroke description: a paint plus structural line parameters. */
378
378
  interface SvgStroke {
379
379
  paint: SvgPaint;
380
- width: number;
380
+ /** World units, or `{ px }` for a width that holds its rendered thickness
381
+ * however the document is scaled — SVG's `vector-effect="non-scaling-stroke"`,
382
+ * and the same unit system as the kit's `Stroke.width`. */
383
+ width: number | {
384
+ px: number;
385
+ };
381
386
  opacity?: number;
382
387
  /** `stroke-linecap`. Default per SVG spec is `'butt'`. */
383
388
  cap?: 'butt' | 'round' | 'square';
@@ -440,9 +445,12 @@ interface SvgGroupNode {
440
445
  * `dominant-baseline="text-before-edge"` so `y` is the top of the text
441
446
  * box, plus `data-weasel-width` / `data-weasel-height` so weasel's
442
447
  * explicit box dimensions round-trip losslessly. External SVG text
443
- * (lacking the data-* attrs) imports with estimated dimensions —
444
- * {@link UNBOUNDED_TEXT_WIDTH} and
448
+ * (lacking the data-* attrs) imports with the width the kit's text layout
449
+ * measures — an em-based estimate when no registered font can — and
445
450
  * `height = fontSize * lineHeight * (lineCount || 1)`.
451
+ *
452
+ * `x` here is always the box's left edge. In the SVG it is the
453
+ * `text-anchor` point, and the parser and serializer convert between them.
446
454
  */
447
455
  interface SvgTextNode {
448
456
  kind: 'text';
@@ -525,7 +533,7 @@ interface AnnotationOverlayProps {
525
533
  config: unknown;
526
534
  /** The trial's resolved tool slot. */
527
535
  activeToolId: string | null;
528
- /** The instrument's vocabulary, for a status's colour. */
536
+ /** The instrument's vocabulary, for a status's color. */
529
537
  meaning?: AnnotationMeaning;
530
538
  }
531
539
  /**
@@ -570,9 +578,9 @@ interface AnnotationToolInfo {
570
578
  weaselTool: BuiltinToolId;
571
579
  kind?: AnnotationKind;
572
580
  }
573
- /** The palette an instrument gets for declaring `annotations`. Ids share the
574
- * trial's contribution namespace with `instrument.tools`, and one tool slot
575
- * holds whichever is active. */
581
+ /** The tools a lab's rail gets when any instrument declares `annotations`.
582
+ * Ids share the lab's contribution namespace with its own `tools`, and the
583
+ * lab's tool slot holds whichever is active. */
576
584
  declare const ANNOTATION_TOOLS: readonly TrialTool[];
577
585
  /** What `id` drives, or undefined for a tool that is not one of these. */
578
586
  declare function annotationToolInfo(id: string | null): AnnotationToolInfo | undefined;
@@ -605,226 +613,6 @@ declare function fromWeaselView(v: View): ViewTransform;
605
613
  */
606
614
  declare function fitView(content: ContentSize, pane: PaneSize): ViewTransform;
607
615
 
608
- /** Whether a schema entry is a branch rather than a leaf. */
609
- declare function isConfigBranch(entry: ConfigEntry): entry is ConfigBranch;
610
- /** Shared chaining surface. Every method clones, so a node can be reused as a
611
- * base for several leaves without one bleeding into the next. */
612
- declare abstract class BaseNode<T> implements ConfigNode<T> {
613
- readonly annotations: Readonly<Annotations>;
614
- readonly options: Readonly<NodeOptions>;
615
- abstract readonly kind: string | null;
616
- readonly default: T;
617
- constructor(defaultValue: T, annotations?: Readonly<Annotations>, options?: Readonly<NodeOptions>);
618
- /** Clone into the same subclass. Subclasses with extra constructor
619
- * arguments override this. */
620
- protected with(annotations: Annotations, options: NodeOptions): this;
621
- protected ann(patch: Annotations): this;
622
- protected opt(patch: NodeOptions): this;
623
- /** Human-readable label. Defaults to the key, title-cased. */
624
- label(name: string): this;
625
- /** Longer help text, surfaced as a tooltip on the row label. */
626
- describe(description: string): this;
627
- /** Omit from the panel unless it is asked to show hidden leaves. */
628
- hidden(): this;
629
- /** Pair with a sibling sharing this id, side-by-side on one row. */
630
- pair(pair: string): this;
631
- /** Render under a named section heading. `collapsed` opens the section
632
- * folded — say it on any one of the section's leaves. */
633
- section(label: string, opts?: {
634
- collapsed?: boolean;
635
- }): this;
636
- /** Show this row only while the predicate holds. Presentational — the value
637
- * stays in config and the instrument still reads it. */
638
- showIf(predicate: (config: Record<string, unknown>) => boolean): this;
639
- /** Draw this one row yourself, keeping the kind, default and validation. */
640
- render(renderer: ControlRenderer): this;
641
- }
642
- declare class NumberNode extends BaseNode<number> {
643
- readonly kind = "number";
644
- /** Bound the value. A number with both bounds renders as a slider. */
645
- range(min: number, max: number): this;
646
- step(step: number): this;
647
- /** A display suffix for the value — `'px'`, `'ms'`, `'°'`. Presentation only:
648
- * it is never parsed, and the stored value stays a plain number. */
649
- suffix(suffix: string): this;
650
- /** Force a slider even without both bounds. */
651
- slider(): this;
652
- /** Force a typed input even when both bounds are set. */
653
- input(): this;
654
- }
655
- declare class BooleanNode extends BaseNode<boolean> {
656
- readonly kind = "boolean";
657
- /** Ask for a switch. `ControlPanel` still draws a checkbox; weasel-ui's
658
- * `PrefsForm` honors the distinction. */
659
- toggle(): this;
660
- }
661
- declare class StringNode extends BaseNode<string> {
662
- readonly kind = "string";
663
- placeholder(placeholder: string): this;
664
- maxLength(maxLength: number): this;
665
- /** Milliseconds to debounce live writes. 0 commits every keystroke. */
666
- debounce(debounceMs: number): this;
667
- }
668
- declare class ColorNode extends BaseNode<string> {
669
- readonly kind = "color";
670
- }
671
- declare class EnumNode<T extends string> extends BaseNode<T> {
672
- readonly kind = "enum";
673
- /** Render as a segmented control rather than a select. */
674
- radio(): this;
675
- /** Relabel the choices. Named `labels` rather than `options` because
676
- * `options` is the node's own extras bag. */
677
- labels(options: readonly ConfigOption[]): this;
678
- }
679
- /** A leaf whose kind the rule chain decides. */
680
- declare class ValueNode<T> extends BaseNode<T> {
681
- readonly kind: null;
682
- }
683
- /** A leaf of a kind labkit does not ship a row for. */
684
- declare class CustomNode<T> extends BaseNode<T> {
685
- readonly kind: string;
686
- constructor(kind: string, defaultValue: T, annotations?: Readonly<Annotations>, options?: Readonly<NodeOptions>);
687
- protected with(annotations: Annotations, options: NodeOptions): this;
688
- }
689
- /**
690
- * A branch of the schema: its children nest under its key, so a leaf inside
691
- * one is read and written at a dotted path. Distinct from `.section()`, which
692
- * puts a heading over sibling leaves and leaves their paths alone.
693
- */
694
- declare class GroupNode<S extends ConfigShape> implements ConfigBranch<S> {
695
- readonly children: S;
696
- readonly annotations: Readonly<BranchAnnotations>;
697
- readonly options: Readonly<BranchOptions>;
698
- constructor(children: S, annotations?: Readonly<BranchAnnotations>, options?: Readonly<BranchOptions>);
699
- private with;
700
- /** Heading for the group's rows. Defaults to the key, title-cased. */
701
- label(name: string): GroupNode<S>;
702
- /** Longer help text. Carried on the resolved `PrefGroup`, where weasel-ui's
703
- * `PrefsForm` draws it under the heading; `ControlPanel` has no place for
704
- * it yet and shows the heading alone. */
705
- describe(description: string): GroupNode<S>;
706
- /** Render this whole group under a named section heading. */
707
- section(label: string, opts?: {
708
- collapsed?: boolean;
709
- }): GroupNode<S>;
710
- /** Show this group only while the predicate holds. Presentational — every
711
- * value beneath it stays in config and the instrument still reads it. */
712
- showIf(predicate: (config: Record<string, unknown>) => boolean): GroupNode<S>;
713
- }
714
- /**
715
- * Builds an instrument's config: the values, their types, and how each is
716
- * edited, in one declaration.
717
- *
718
- * ```ts
719
- * const config = f.schema({
720
- * showGrid: f.boolean(true),
721
- * cellSize: f.number(20).range(5, 80).step(5).label('Grid spacing'),
722
- * // Nested: read and written at `grid.color`.
723
- * grid: f.group({ color: f.color('#ffffff') }),
724
- * })
725
- * ```
726
- */
727
- declare const f: {
728
- number: (def: number) => NumberNode;
729
- boolean: (def: boolean) => BooleanNode;
730
- string: (def: string) => StringNode;
731
- color: (def: string) => ColorNode;
732
- /** A fixed set of choices. The default's literal type flows into the config
733
- * type, so `f.enum('fast', ['fast', 'accurate'])` gives
734
- * `'fast' | 'accurate'` with no `as const`. */
735
- enum: <const T extends string>(def: T, options: readonly T[] | readonly ConfigOption[]) => EnumNode<T>;
736
- /** A leaf with no declared kind: the rule chain decides, which is how a lab
737
- * states a convention like "every `*Color` key is a color picker". */
738
- value: <T>(def: T) => ValueNode<T>;
739
- /** A branch: its children nest under this key, so `grid: f.group({ size })`
740
- * puts the value at `config.grid.size` and addresses it as `'grid.size'`.
741
- * Groups nest as deeply as the schema wants. */
742
- group: <const S extends ConfigShape>(children: S) => GroupNode<S>;
743
- /** A leaf of a kind a lab supplies the control for, through `controls`. */
744
- custom: <T>(kind: string, def: T, validate?: (leaf: ToolPrefLeaf) => string[]) => CustomNode<T>;
745
- /** Collect leaves and groups into an instrument's config. */
746
- schema<S extends ConfigShape>(nodes: S): ConfigSchema<InferConfig<S>>;
747
- };
748
-
749
- /**
750
- * Adapt a legacy `configSchema(): ConfigField[]` into the resolved shape, so
751
- * both instrument paths reach one renderer.
752
- *
753
- * Rules do not run here: a hand-written `ConfigField` already states its label
754
- * and control, which is everything the rule chain would have inferred.
755
- */
756
- declare function fromConfigFields(fields: readonly ConfigField[]): ResolvedConfig;
757
-
758
- /** The value at a dotted path. `undefined` when a segment is missing or the
759
- * walk hits something that is not a record. */
760
- declare function valueAtPath(config: unknown, path: string): unknown;
761
- /** Whether a dotted path is actually present, which a `undefined` value is
762
- * not enough to tell you. */
763
- declare function hasConfigPath(config: unknown, path: string): boolean;
764
- /** A copy of `config` with `value` written at a dotted path. Every record on
765
- * the way down is copied and the input is left alone; a missing — or
766
- * non-record — intermediate is replaced with the branch the path implies. */
767
- declare function withValueAtPath<T>(config: T, path: string, value: unknown): T;
768
- /**
769
- * `stored` with every gap filled from `defaults`, down the whole tree.
770
- *
771
- * This is how a config written before its schema grew a branch still loads:
772
- * the branch arrives at its defaults instead of `undefined`, and a key the
773
- * defaults no longer mention is kept rather than dropped, so nothing is lost
774
- * to a schema change the author has not finished making.
775
- */
776
- declare function fillConfigDefaults<T>(stored: unknown, defaults: T): T;
777
- /** A node in a resolved schema tree, by dotted path. Structural rather than
778
- * `isPrefLeaf` so this stays free of a runtime import. */
779
- declare function schemaNodeAtPath(group: ToolPrefGroup, path: string): ToolPrefLeaf | ToolPrefGroup | undefined;
780
-
781
- /**
782
- * Resolve a schema into the vocabulary weasel-ui renders, running each leaf
783
- * through the consumer's rules and then labkit's own.
784
- *
785
- * The group mirrors the schema's own nesting: an `f.group` becomes a nested
786
- * `PrefGroup`, so a leaf's dotted path within the tree is the path its value
787
- * is written at, and both `ControlPanel` and `PrefsForm` address it
788
- * identically.
789
- */
790
- declare function resolveConfigSchema<TC>(schema: ConfigSchema<TC>, rules?: readonly ConfigRule[]): ResolvedConfig;
791
-
792
- /** `cellSize` -> `Cell size`. Splits camelCase without shattering acronyms. */
793
- declare function titleCase(key: string): string;
794
- /**
795
- * labkit's own inference, expressed in the same vocabulary a consumer
796
- * extends. Runs after the consumer's rules, so a lab always wins.
797
- *
798
- * If one of these ever needs something a `ConfigRule` cannot express, the
799
- * seam is too weak — that is the point of writing them this way.
800
- */
801
- declare const builtinRules: readonly ConfigRule[];
802
- /**
803
- * Fold a rule chain into one leaf patch. Gap-filling: a property already
804
- * settled is never overwritten, so the accumulator seeded with the author's
805
- * annotations beats every rule, and earlier rules beat later ones.
806
- */
807
- declare function applyRules(seed: LeafPatch, ctx: Omit<ConfigRuleContext, 'leaf'>, rules: readonly ConfigRule[]): LeafPatch;
808
-
809
- /**
810
- * An instrument's controls, resolved against the surrounding lab's rules.
811
- *
812
- * Resolution cannot happen in `defineInstrument` — rules are lab-scoped and
813
- * that runs at module load — so it happens here, at render. Both instrument
814
- * paths land in the same shape, so callers never branch on which was used.
815
- */
816
- declare function useConfigSchema(instrument: Instrument<any, any, any>): ResolvedConfig;
817
-
818
- /**
819
- * Whether the row at a dotted path should be drawn right now. A group answers
820
- * for its whole subtree — hiding one hides everything under it.
821
- *
822
- * `hidden` is the node's own static flag; `showIf` is the schema's predicate
823
- * over the live config. Both are presentational — a hidden leaf keeps its
824
- * value and the instrument still reads it.
825
- */
826
- declare function isLeafVisible(resolved: ResolvedConfig, path: string, config: Record<string, unknown>, showHidden?: boolean): boolean;
827
-
828
616
  /** An instrument as it is written: either the legacy `defaultConfig` (plus an
829
617
  * optional `configSchema`), or a `config` schema that supplies both. */
830
618
  type InstrumentSpec<TS, TC, TItem = unknown> = Instrument<TS, TC, TItem> | (Omit<Instrument<TS, TC, TItem>, 'defaultConfig'> & {
@@ -863,13 +651,50 @@ interface ValidationResult {
863
651
  * a field simply has no constraints to check here. */
864
652
  declare function validateConfigSchema(fields: ConfigField[]): ValidationResult;
865
653
 
866
- /** Props for `<Lab>`. */
867
- interface LabProps {
654
+ /** One page in a project's set of labs. */
655
+ interface LabPage {
656
+ /** The page's own URL, and how the switcher knows which page is open. */
657
+ href: string;
658
+ label: string;
659
+ }
660
+ /** Props for `<LabSwitcher>`. */
661
+ interface LabSwitcherProps {
662
+ /** The open page's title, shown as the control's own label. */
663
+ title: string;
664
+ pages: readonly LabPage[];
665
+ /** Defaults to the current location. Pass it in tests, or to render a
666
+ * switcher for a page other than the one being viewed. */
667
+ path?: string;
668
+ className?: string;
669
+ }
670
+ /** Which of `pages` a path is on, or -1.
671
+ *
672
+ * Matched on the end of the path so a query string, a trailing slash or a
673
+ * leftover `.html` cannot lose it: a project whose dev server maps `/stats`
674
+ * to `stats.html` serves both spellings, and a bookmark from before the URLs
675
+ * lost their extension still resolves to the same page. */
676
+ declare function currentPage(path: string, pages: readonly LabPage[]): number;
677
+ /** A project's lab title, doubling as the way to reach its other labs.
678
+ *
679
+ * The menu holds real anchors, not a `<select>` and not buttons. These are
680
+ * separate documents, so an `href` is what gets middle-click, cmd-click and
681
+ * the back button for free; a select fires a change event and can do none of
682
+ * the three. The trigger is a button because it opens something rather than
683
+ * going anywhere.
684
+ *
685
+ * Pages accumulate -- a project grows a wall, a dashboard, an ingest page, a
686
+ * bench -- and a tab strip is the layout that stops working first. */
687
+ declare function LabSwitcher({ title, pages, path, className }: LabSwitcherProps): react_jsx_runtime.JSX.Element;
688
+
689
+ interface LabBaseProps {
690
+ /** May change while mounted. An instrument that is a different object from
691
+ * the last render counts as replaced and its open trials' configs are
692
+ * refilled, so hoist or memoize the list. */
868
693
  instruments: InstrumentList;
869
694
  defaultInstrument: string;
870
- storage?: StorageAdapter | null;
871
- storageKey?: string;
872
695
  mode?: LabMode;
696
+ /** Rendered while a stored lab loads. Default: the lab's empty shell. */
697
+ fallback?: ReactNode;
873
698
  /**
874
699
  * Optional list of CSS colors used to compose the interstellar theme's
875
700
  * cosmic backdrop. Each color becomes one radial-gradient blob on the
@@ -878,12 +703,27 @@ interface LabProps {
878
703
  */
879
704
  nebula?: readonly string[];
880
705
  title?: string;
706
+ /** The project's other labs. Given two or more, the title becomes the way to
707
+ * reach them — the same switcher `<LabShell>` renders, so a lab reached from
708
+ * one is not a dead end. */
709
+ pages?: readonly LabPage[];
710
+ /** The path the switcher marks as open. Defaults to the current location. */
711
+ path?: string;
881
712
  /** Rendered in the shell's footer, below the workspace. */
882
713
  footer?: ReactNode;
883
714
  /** Contributions added to every trial's chrome, after the instrument's own. */
884
715
  chrome?: readonly TrialContribution[];
716
+ /** Contributions to the lab's own chrome — its header bar, its sidebar, its
717
+ * tool rail and its footer — rather than to every trial's. Rendered after
718
+ * `children` and `footer`, which stay the way a lab drops arbitrary content
719
+ * into those same two boxes. Going from no sidebar contributions to some
720
+ * remounts the workspace and every trial, dropping unpersisted trial state. */
721
+ labChrome?: readonly LabContribution[];
885
722
  /** Built-in contribution ids to drop. Throws on an id that is not there. */
886
723
  suppress?: readonly string[];
724
+ /** Offer the header's add-trial control. Default `true`; a lab that opens
725
+ * trials some other way passes `false`. */
726
+ addTrial?: boolean;
887
727
  /** Tools offered lab-wide. A trial whose instrument declares none of its own
888
728
  * reflects and writes this slot. */
889
729
  tools?: readonly TrialTool[];
@@ -896,75 +736,31 @@ interface LabProps {
896
736
  controls?: Record<string, ControlRenderer>;
897
737
  children?: ReactNode;
898
738
  }
899
- /** The lab runtime: creates the store, provides it, and renders one trial
739
+ /** Props for `<Lab>`. With a `storageKey` the lab persists — to IndexedDB
740
+ * unless `storage` names another substrate — and both are read once, at
741
+ * mount. Without one, nothing persists. */
742
+ type LabProps = LabBaseProps & ({
743
+ storageKey?: undefined;
744
+ storage?: undefined;
745
+ } | {
746
+ storageKey: string;
747
+ storage?: StorageAdapter;
748
+ });
749
+ /** The lab runtime: opens the store, provides it, and renders one trial
900
750
  * per record in a grid. Each trial runs one of `instruments`. */
901
- declare function Lab({ instruments, defaultInstrument, storage, storageKey, mode, nebula, title, footer, chrome, suppress, tools, configRules, controls, children, }: LabProps): react_jsx_runtime.JSX.Element;
902
-
903
- /** What a trial opens on beyond its instrument's own defaults. */
904
- interface AddTrialOptions<TC = Record<string, unknown>> {
905
- /** Overlaid on `defaultConfig()` before `initialState` reads it, so a trial
906
- * opened on a subject is running that subject from its first frame. Keys
907
- * whose value is `undefined` are left to the default. */
908
- config?: Partial<TC>;
909
- }
910
- /** Append a new trial running `instrumentName`, at that instrument's default
911
- * config — with `options.config` written over it — and the initial state
912
- * that config produces. */
913
- declare function addTrial(trials: TrialRecord[], instruments: InstrumentList, instrumentName: string, options?: AddTrialOptions): TrialRecord[];
914
- /** Insert a deep copy of a trial directly after it. The copy starts with
915
- * an empty undo history — the original's is not shared. */
916
- declare function cloneTrial(trials: TrialRecord[], id: string): TrialRecord[];
917
- /** Remove a trial, unless it is the last one — a lab always has at least
918
- * one. */
919
- declare function closeTrial(trials: TrialRecord[], id: string): TrialRecord[];
920
- /** Return a trial to what it opened on — its instrument's defaults under the
921
- * seed `addTrial` was given — keeping its id and its place in the list. */
922
- declare function resetTrial(trials: TrialRecord[], id: string, instruments: InstrumentList): TrialRecord[];
923
- /**
924
- * Reorder to match `ids`. Ids the list doesn't mention keep their relative
925
- * order at the end, and ids it names that no longer exist are dropped — a
926
- * reorder that raced a close should not resurrect the closed trial.
927
- */
928
- declare function reorderTrials(trials: TrialRecord[], ids: readonly string[]): TrialRecord[];
929
-
930
- /** Lab-wide state and commands: the available instruments, the open
931
- * trials and the operations over them, saved snapshots, and the color
932
- * mode. */
933
- interface LabContextValue {
934
- instruments: InstrumentList;
935
- trials: TrialRecord[];
936
- /** Open a trial running `instrumentName`. `options.config` is written over
937
- * that instrument's defaults, which is where a trial opened on a subject
938
- * says which subject. */
939
- addTrial: (instrumentName: string, options?: AddTrialOptions) => void;
940
- cloneTrial: (id: string) => void;
941
- closeTrial: (id: string) => void;
942
- resetTrial: (id: string) => void;
943
- reorderTrials: (ids: readonly string[]) => void;
944
- savedSnapshots: SavedSnapshot[];
945
- saveSnapshot: (trialId: string, name?: string) => void;
946
- loadSnapshot: (trialId: string, snapshotId: string) => void;
947
- deleteSnapshot: (snapshotId: string) => void;
948
- mode: LabMode;
949
- setMode: (m: LabMode) => void;
950
- /** Lab-wide rules run over every instrument's config leaves, before
951
- * labkit's own inference. */
952
- configRules?: readonly ConfigRule[];
953
- /** Lab-wide control overrides, keyed by config path or by leaf kind. */
954
- controls?: Record<string, ControlRenderer>;
955
- }
956
- /** Context carrying the surrounding lab. Prefer `useLabContext`. */
957
- declare const LabContext: react.Context<LabContextValue | null>;
958
- /** The surrounding lab. Throws outside a `<Lab>`. */
959
- declare function useLabContext(): LabContextValue;
751
+ declare function Lab(props: LabProps): react_jsx_runtime.JSX.Element;
960
752
 
961
753
  /** Props for `<LabPalette>`. */
962
754
  interface LabPaletteProps {
963
- tools: readonly TrialTool[];
755
+ /** Tools offered lab-wide. Shorthand for one `palette` contribution each. */
756
+ tools?: readonly TrialTool[];
757
+ /** The lab's contributions; the `palette` ones are laid out here. */
758
+ contributions?: readonly LabContribution[];
964
759
  }
965
- /** The lab's tool strip. Writes the lab's tool slot, which every trial whose
966
- * instrument declares no tools of its own resolves to. */
967
- declare function LabPalette({ tools }: LabPaletteProps): react_jsx_runtime.JSX.Element;
760
+ /** The lab's tool rail. Writes the lab's tool slot, which every trial whose
761
+ * instrument declares no tools of its own resolves to. Renders nothing when
762
+ * the lab contributes no tool rail. */
763
+ declare function LabPalette({ tools, contributions }: LabPaletteProps): react_jsx_runtime.JSX.Element;
968
764
 
969
765
  /** Props for `<LabShell>`. */
970
766
  interface LabShellProps {
@@ -976,11 +772,17 @@ interface LabShellProps {
976
772
  footer?: ReactNode;
977
773
  /** Color mode. "auto" (default) follows prefers-color-scheme. */
978
774
  mode?: LabMode;
775
+ /** The project's other labs. Given two or more, the title becomes the way
776
+ * to reach them; given none, it stays a plain heading. */
777
+ pages?: readonly LabPage[];
778
+ /** The path the switcher reads to mark the open page. Defaults to the
779
+ * current location. */
780
+ path?: string;
979
781
  }
980
782
  /** Page frame for a lab: a titled header, a body, and an optional footer,
981
783
  * themed for the resolved color mode. Presentational only — use `<Lab>` when
982
784
  * the trial runtime is wanted too. */
983
- declare function LabShell({ title, children, header, footer, mode }: LabShellProps): react_jsx_runtime.JSX.Element;
785
+ declare function LabShell({ title, children, header, footer, mode, pages, path }: LabShellProps): react_jsx_runtime.JSX.Element;
984
786
 
985
787
  /** A tile's persisted extent, keyed by the id its caller gave it. Grid resizes
986
788
  * write `span`; `size` is here because a strategy swap would write that. */
@@ -1103,7 +905,7 @@ interface TrialProps {
1103
905
  declare function Trial({ id, chrome, suppress }: TrialProps): react_jsx_runtime.JSX.Element;
1104
906
 
1105
907
  /** Props for `<TrialBody>`. */
1106
- interface TrialBodyProps {
908
+ interface TrialBodyProps extends Omit<SplitProps, 'sidebar' | 'children' | 'className' | 'sidebarClassName' | 'label'> {
1107
909
  /** The sidebar region's sections. */
1108
910
  sidebar: ReactNode;
1109
911
  /** The instrument's own output. */
@@ -1111,36 +913,9 @@ interface TrialBodyProps {
1111
913
  /** Extra class on the content pane — `Trial` marks a canvas instrument's
1112
914
  * well flush. */
1113
915
  contentClassName?: string;
1114
- /** The sidebar's current extent in pixels. Omit for an unpersisted lab: the
1115
- * seam still works, its result just does not outlive the mount. */
1116
- width?: number;
1117
- /** Where the sidebar starts before anyone drags it. */
1118
- defaultWidth?: number;
1119
- minWidth?: number;
1120
- maxWidth?: number;
1121
- /** How little the instrument may be squeezed to. Reported as the seam's
1122
- * reachable maximum, so the drag stops there rather than clamping silently. */
1123
- contentMinWidth?: number;
1124
- /** Fires through the drag, not on release: the pane is already there. */
1125
- onWidthChange?: (width: number) => void;
1126
- /**
1127
- * Fixed extent. Omit in an app — the strip measures its own box. Supply it
1128
- * where nothing measures, notably jsdom, or both panes lay out at zero.
1129
- */
1130
- viewport?: {
1131
- w: number;
1132
- h: number;
1133
- };
1134
916
  }
1135
- /**
1136
- * A trial's sidebar and content as a two-pane strip with a draggable seam.
1137
- *
1138
- * The seam is `stripStrategy`'s own resize affordance, so it arrives as a
1139
- * `role="separator"` carrying the reachable range, operable by pointer and by
1140
- * arrows / Home / End, and clamped against the content pane's floor rather
1141
- * than against the sidebar's alone.
1142
- */
1143
- declare function TrialBody({ sidebar, children, contentClassName, width, defaultWidth, minWidth, maxWidth, contentMinWidth, onWidthChange, viewport, }: TrialBodyProps): react_jsx_runtime.JSX.Element;
917
+ /** A trial's sidebar and content as a `Split`, wearing the trial's classes. */
918
+ declare function TrialBody({ sidebar, children, contentClassName, ...rest }: TrialBodyProps): react_jsx_runtime.JSX.Element;
1144
919
 
1145
920
  /** The trial's loupe as its chrome sees it: a switch and its position. */
1146
921
  interface LoupeBindings {
@@ -1183,5 +958,5 @@ interface TrialChromeProps {
1183
958
  * each region its slice. */
1184
959
  declare function TrialChrome({ trialId, record, instrument, isLastTrial, undoBindings, job, loupe, trialChrome, chrome, suppress, activeToolId, setActiveTool, children, }: TrialChromeProps): react_jsx_runtime.JSX.Element;
1185
960
 
1186
- export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, AnnotationData, AnnotationKind, AnnotationMeaning, AnnotationOverlay, AnnotationTarget, AnnotationTargets, Annotations, AnnotationsApi, AnnotationsCapability, AnnotationsContext, BranchAnnotations, BranchOptions, CaptureOptions, CaptureResult, CaptureSource, ConfigBranch, ConfigEntry, ConfigField, ConfigNode, ConfigOption, ConfigRule, ConfigRuleContext, ConfigSchema, ConfigShape, ControlRenderer, CurveField, DEFAULT_VIEW, EffectCard, EffectCardList, ExportMenu, InferConfig, Instrument, InstrumentList, JobHandle, Lab, LabContext, LabMode, LabPalette, LabShell, LeafPatch, MarkList, MarkScene, NodeOptions, PropertyGroup, PropertyListPack, ResolvedConfig, SavedSnapshot, StorageAdapter, Subpanel, Trial, TrialBody, TrialChrome, TrialContribution, TrialInfo, TrialRecord, TrialTool, ViewTransform, Workspace, WorldRect, addTrial, annotationToolInfo, applyRules, as2DView, builtinRules, capturePlan, captureTarget, cloneTrial, closeTrial, composeCaptureSvg, createMarkDrawOne, defineInstrument, f, fillConfigDefaults, fitView, fromConfigFields, fromWeaselView, hasConfigPath, interstellarTheme, isConfigBranch, isLeafVisible, isStale, markCommands, markSvgNodes, reorderTrials, resetTrial, resolveConfigSchema, resolveMarkStyle, schemaNodeAtPath, seenFrom, titleCase, toWeaselView, useAnnotations, useAnnotationsOptional, useConfigSchema, useLabContext, validateConfigSchema, valueAtPath, withValueAtPath };
1187
- export type { AddTrialOptions, AnnotationOverlayProps, AnnotationTargetsProps, AnnotationToolInfo, CaptureArgs, CapturePlan, ComposeSvgArgs, ContentSize, CurveFieldProps, CurveMark, EffectCardListItem, EffectCardListProps, EffectCardProps, InstrumentSpec, LabContextValue, LabPaletteProps, LabProps, LabShellProps, MarkDrawOptions, MarkListProps, MarkStyle, PaintableMark, PaneSize, PanelDescriptor, PropertyGroupProps, SubpanelProps, TrialBodyProps, TrialChromeProps, TrialLayout, TrialProps, UndoBindings, ValidationResult, ViewTransform2D, WorkspaceProps };
961
+ export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, AnnotationData, AnnotationKind, AnnotationMeaning, AnnotationOverlay, AnnotationTarget, AnnotationTargets, AnnotationsApi, AnnotationsCapability, AnnotationsContext, CaptureOptions, CaptureResult, CaptureSource, ConfigField, ConfigRule, ConfigSchema, ControlRenderer, CurveField, DEFAULT_VIEW, EffectCard, EffectCardList, ExportMenu, Instrument, InstrumentList, JobHandle, Lab, LabContribution, LabMode, LabPalette, LabShell, LabSwitcher, MarkList, MarkScene, PropertyGroup, PropertyListPack, SplitProps, StorageAdapter, Subpanel, Trial, TrialBody, TrialChrome, TrialContribution, TrialInfo, TrialRecord, TrialTool, ViewTransform, Workspace, WorldRect, annotationToolInfo, as2DView, capturePlan, captureTarget, composeCaptureSvg, createMarkDrawOne, currentPage, defineInstrument, fitView, fromWeaselView, interstellarTheme, isStale, markCommands, markSvgNodes, resolveMarkStyle, seenFrom, toWeaselView, useAnnotations, useAnnotationsOptional, validateConfigSchema };
962
+ export type { AnnotationOverlayProps, AnnotationTargetsProps, AnnotationToolInfo, CaptureArgs, CapturePlan, ComposeSvgArgs, ContentSize, CurveFieldProps, CurveMark, EffectCardListItem, EffectCardListProps, EffectCardProps, InstrumentSpec, LabPage, LabPaletteProps, LabProps, LabShellProps, LabSwitcherProps, MarkDrawOptions, MarkListProps, MarkStyle, PaintableMark, PaneSize, PanelDescriptor, PropertyGroupProps, SubpanelProps, TrialBodyProps, TrialChromeProps, TrialLayout, TrialProps, UndoBindings, ValidationResult, ViewTransform2D, WorkspaceProps };