@weasel-js/labkit 1.3.0 → 1.4.0-pre.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 (210) hide show
  1. package/dist/_dts/CanvasStackContext-DtAn_3O-.d.ts +42 -0
  2. package/dist/_dts/DrawCommand-B3bskUsC.d.ts +564 -0
  3. package/dist/_dts/{PrefsForm-BYa6cWnO.d.ts → PrefsForm-BkUJZx0A.d.ts} +4 -1
  4. package/dist/_dts/fitViewToBounds-dZ2UDB6e.d.ts +21 -0
  5. package/dist/_dts/frac-Cp3NivlC.d.ts +728 -0
  6. package/dist/_dts/index-BDVzvRzQ.d.ts +236 -0
  7. package/dist/_dts/shapeKinds-Cx_rxwsa.d.ts +87 -0
  8. package/dist/_dts/{DrawCommand-DBB45NfN.d.ts → types-C-gh9Ap-.d.ts} +1 -582
  9. package/dist/_dts/{types-DCGEcMO_.d.ts → types-D6s4b7if.d.ts} +1 -1
  10. package/dist/_dts/{types-1Sdxy_Pv.d.ts → types-DYMaEvM5.d.ts} +26 -1
  11. package/dist/_dts/{useTrialState-CsGMjhu9.d.ts → useTrialState-gmMvZqPc.d.ts} +7 -2
  12. package/dist/canvas/index.d.ts +43 -25
  13. package/dist/canvas/index.js +5 -4
  14. package/dist/chrome/index.d.ts +9 -6
  15. package/dist/chrome/index.js +6 -6
  16. package/dist/chunk-2AYGEN57.js +32 -0
  17. package/dist/chunk-2AYGEN57.js.map +1 -0
  18. package/dist/{chunk-QRYPXSGP.js → chunk-3P5TTTA7.js} +16 -8
  19. package/dist/chunk-3P5TTTA7.js.map +1 -0
  20. package/dist/{chunk-BDJXIBRZ.js → chunk-3ZELRRBV.js} +44 -27
  21. package/dist/chunk-3ZELRRBV.js.map +1 -0
  22. package/dist/{chunk-LGKRIUSW.js → chunk-4EY67BKJ.js} +32 -7
  23. package/dist/chunk-4EY67BKJ.js.map +1 -0
  24. package/dist/{chunk-3XXPU73K.js → chunk-5TCEVMPI.js} +9 -7
  25. package/dist/chunk-5TCEVMPI.js.map +1 -0
  26. package/dist/{chunk-JDROYQM3.js → chunk-6JMU56CU.js} +130 -131
  27. package/dist/chunk-6JMU56CU.js.map +1 -0
  28. package/dist/{chunk-CPUJ3QXL.js → chunk-CQLQPQ4P.js} +2 -2
  29. package/dist/chunk-CQLQPQ4P.js.map +1 -0
  30. package/dist/chunk-CTRKTLYZ.js +33 -0
  31. package/dist/chunk-CTRKTLYZ.js.map +1 -0
  32. package/dist/chunk-EQIB2PGC.js +458 -0
  33. package/dist/chunk-EQIB2PGC.js.map +1 -0
  34. package/dist/chunk-HEORBLVT.js +7128 -0
  35. package/dist/chunk-HEORBLVT.js.map +1 -0
  36. package/dist/{chunk-BMW4TDP5.js → chunk-JDDIZSLL.js} +3 -3
  37. package/dist/{chunk-BMW4TDP5.js.map → chunk-JDDIZSLL.js.map} +1 -1
  38. package/dist/chunk-LITE5YFB.js +669 -0
  39. package/dist/chunk-LITE5YFB.js.map +1 -0
  40. package/dist/{chunk-QCICIHEO.js → chunk-ROQDRXKW.js} +716 -311
  41. package/dist/chunk-ROQDRXKW.js.map +1 -0
  42. package/dist/{chunk-4TMMVIDM.js → chunk-XJ6N32QP.js} +50 -6
  43. package/dist/chunk-XJ6N32QP.js.map +1 -0
  44. package/dist/{chunk-WTI26YTM.js → chunk-YQJNT4XQ.js} +40 -13
  45. package/dist/chunk-YQJNT4XQ.js.map +1 -0
  46. package/dist/controls/index.d.ts +4 -28
  47. package/dist/controls/index.js +3 -3
  48. package/dist/dragdrop/index.d.ts +9 -5
  49. package/dist/dragdrop/index.js +3 -3
  50. package/dist/index.d.ts +518 -190
  51. package/dist/index.js +1753 -75
  52. package/dist/index.js.map +1 -1
  53. package/dist/layers/index.d.ts +6 -5
  54. package/dist/layers/index.js +3 -3
  55. package/dist/loupe/index.d.ts +187 -0
  56. package/dist/loupe/index.js +7 -0
  57. package/dist/loupe/index.js.map +1 -0
  58. package/dist/passthrough/weasel-canvas.d.ts +3 -1
  59. package/dist/passthrough/weasel-canvas.js +1 -1
  60. package/dist/passthrough/weasel-ui.d.ts +138 -91
  61. package/dist/passthrough/weasel-ui.js +2 -2
  62. package/dist/primitives/index.d.ts +3 -1
  63. package/dist/primitives/index.js +5 -5
  64. package/dist/state/index.d.ts +3 -3
  65. package/dist/state/index.js +2 -2
  66. package/dist/styles.css +229 -1
  67. package/dist/surface/index.d.ts +18 -2
  68. package/dist/surface/index.js +2 -2
  69. package/dist/ui/layers/index.js +2 -2
  70. package/dist/undo/index.d.ts +5 -4
  71. package/package.json +14 -7
  72. package/src/annotations/AnnotationOverlay.tsx +205 -0
  73. package/src/annotations/AnnotationTargets.tsx +37 -0
  74. package/src/annotations/Annotations.less +129 -0
  75. package/src/annotations/Annotations.meaning.test.tsx +111 -0
  76. package/src/annotations/Annotations.overlay.test.tsx +142 -0
  77. package/src/annotations/AnnotationsContext.ts +49 -0
  78. package/src/annotations/ExportMenu.test.tsx +86 -0
  79. package/src/annotations/ExportMenu.tsx +182 -0
  80. package/src/annotations/MarkList.tsx +75 -0
  81. package/src/annotations/capture.test.ts +140 -0
  82. package/src/annotations/capture.ts +237 -0
  83. package/src/annotations/drawOne.test.ts +56 -0
  84. package/src/annotations/drawOne.ts +47 -0
  85. package/src/annotations/frac.test.ts +59 -0
  86. package/src/annotations/frac.ts +66 -0
  87. package/src/annotations/history.test.ts +82 -0
  88. package/src/annotations/history.ts +118 -0
  89. package/src/annotations/index.ts +37 -0
  90. package/src/annotations/paint.test.ts +125 -0
  91. package/src/annotations/paint.ts +130 -0
  92. package/src/annotations/staleness.test.ts +56 -0
  93. package/src/annotations/staleness.ts +41 -0
  94. package/src/annotations/store.test.ts +175 -0
  95. package/src/annotations/store.ts +317 -0
  96. package/src/annotations/svgNodes.test.ts +77 -0
  97. package/src/annotations/svgNodes.ts +74 -0
  98. package/src/annotations/toolMap.test.ts +36 -0
  99. package/src/annotations/toolMap.ts +54 -0
  100. package/src/annotations/types.ts +222 -0
  101. package/src/annotations/view.test.ts +37 -0
  102. package/src/annotations/view.ts +40 -0
  103. package/src/canvas/AGENTS.md +55 -5
  104. package/src/canvas/CanvasStack.test.tsx +27 -1
  105. package/src/canvas/CanvasStack.tsx +29 -4
  106. package/src/canvas/CanvasStackContext.ts +23 -4
  107. package/src/canvas/camera.test.ts +78 -0
  108. package/src/canvas/camera.ts +62 -0
  109. package/src/canvas/canvasCoords.test.ts +26 -0
  110. package/src/canvas/canvasCoords.ts +20 -7
  111. package/src/canvas/index.ts +5 -1
  112. package/src/canvas/useLayerScheduler.ts +7 -3
  113. package/src/canvas/usePanZoom.test.ts +36 -5
  114. package/src/canvas/usePanZoom.ts +20 -15
  115. package/src/canvas/worldSpec.test.ts +63 -0
  116. package/src/canvas/worldSpec.ts +48 -0
  117. package/src/chrome/builtins.test.ts +31 -1
  118. package/src/chrome/builtins.tsx +63 -19
  119. package/src/chrome/regions/PaletteRegion.test.tsx +22 -1
  120. package/src/chrome/regions/PaletteRegion.tsx +4 -0
  121. package/src/chrome/regions/SidebarRegion.tsx +37 -13
  122. package/src/chrome/regions/ToolbarRegion.tsx +2 -1
  123. package/src/chrome/regions/ViewportRegion.tsx +9 -1
  124. package/src/chrome/regions/regions.test.tsx +6 -1
  125. package/src/chrome/types.ts +20 -0
  126. package/src/controls/ControlPanel.test.tsx +38 -0
  127. package/src/controls/ControlPanel.tsx +50 -3
  128. package/src/dragdrop/DragDropRuntime.tsx +8 -2
  129. package/src/dragdrop/dragDrop.test.tsx +29 -2
  130. package/src/index.test.ts +22 -0
  131. package/src/index.ts +87 -2
  132. package/src/instrument/SineWave.smoke.test.tsx +1 -0
  133. package/src/instrument/types.ts +24 -1
  134. package/src/lab/Lab.surface.test.tsx +162 -0
  135. package/src/lab/Lab.tsx +102 -17
  136. package/src/lab/Lab.undock.test.tsx +85 -0
  137. package/src/lab/LabFullChrome.stories.tsx +20 -0
  138. package/src/lab/LabShell.less +11 -0
  139. package/src/lab/Workspace.less +73 -0
  140. package/src/lab/Workspace.surface.test.tsx +2 -0
  141. package/src/lab/Workspace.tsx +97 -8
  142. package/src/lab/index.ts +1 -1
  143. package/src/lab/panelHost.ts +37 -0
  144. package/src/loupe/AGENTS.md +49 -0
  145. package/src/loupe/CanvasLoupe.tsx +83 -0
  146. package/src/loupe/DomLoupe.tsx +62 -0
  147. package/src/loupe/Loupe.less +38 -0
  148. package/src/loupe/LoupeBubble.tsx +32 -0
  149. package/src/loupe/TrialLoupe.tsx +93 -0
  150. package/src/loupe/canvasLens.test.ts +205 -0
  151. package/src/loupe/canvasLens.ts +141 -0
  152. package/src/loupe/index.ts +19 -0
  153. package/src/loupe/types.test.ts +29 -0
  154. package/src/loupe/types.ts +90 -0
  155. package/src/loupe/useHostSize.ts +30 -0
  156. package/src/loupe/useLoupe.test.tsx +197 -0
  157. package/src/loupe/useLoupe.ts +189 -0
  158. package/src/passthrough/weasel-ui.ts +3 -0
  159. package/src/primitives/FloatingPanel.test.tsx +76 -1
  160. package/src/primitives/FloatingPanel.tsx +19 -3
  161. package/src/primitives/ScaleIndicator.test.tsx +7 -2
  162. package/src/primitives/Sidebar.less +18 -0
  163. package/src/primitives/Toolbar.less +8 -0
  164. package/src/primitives/Toolbar.tsx +5 -0
  165. package/src/primitives/useRovingTabIndex.test.ts +21 -0
  166. package/src/primitives/useRovingTabIndex.ts +26 -17
  167. package/src/state/document.test.ts +23 -0
  168. package/src/state/document.ts +14 -2
  169. package/src/state/index.ts +2 -0
  170. package/src/state/store.test.ts +24 -0
  171. package/src/state/store.ts +35 -1
  172. package/src/state/types.ts +11 -0
  173. package/src/state/undock.test.ts +40 -0
  174. package/src/state/undock.ts +39 -0
  175. package/src/styles.less +2 -0
  176. package/src/surface/SurfaceContext.ts +4 -0
  177. package/src/surface/index.ts +8 -3
  178. package/src/surface/useSurfaceTile.test.tsx +2 -0
  179. package/src/surface/useSurfaceTile.ts +7 -1
  180. package/src/surface/useTiledSurface.test.tsx +58 -0
  181. package/src/surface/useTiledSurface.ts +38 -3
  182. package/src/trial/Trial.annotations.persist.test.tsx +166 -0
  183. package/src/trial/Trial.annotations.test.tsx +121 -0
  184. package/src/trial/Trial.canvas.test.tsx +76 -1
  185. package/src/trial/Trial.less +19 -0
  186. package/src/trial/Trial.loupe.test.tsx +128 -0
  187. package/src/trial/Trial.stories.tsx +1 -0
  188. package/src/trial/Trial.test.tsx +12 -0
  189. package/src/trial/Trial.trialId.test.tsx +36 -0
  190. package/src/trial/Trial.tsx +215 -40
  191. package/src/trial/TrialChrome.tsx +35 -0
  192. package/src/trial/UndockedSections.tsx +65 -0
  193. package/src/trial/trialOps.test.ts +21 -0
  194. package/src/trial/trialOps.ts +5 -3
  195. package/dist/_dts/types-BttTIent.d.ts +0 -314
  196. package/dist/chunk-3XXPU73K.js.map +0 -1
  197. package/dist/chunk-4TMMVIDM.js.map +0 -1
  198. package/dist/chunk-6X5RBC6G.js +0 -366
  199. package/dist/chunk-6X5RBC6G.js.map +0 -1
  200. package/dist/chunk-BDJXIBRZ.js.map +0 -1
  201. package/dist/chunk-CPUJ3QXL.js.map +0 -1
  202. package/dist/chunk-JDROYQM3.js.map +0 -1
  203. package/dist/chunk-LGKRIUSW.js.map +0 -1
  204. package/dist/chunk-QCICIHEO.js.map +0 -1
  205. package/dist/chunk-QRYPXSGP.js.map +0 -1
  206. package/dist/chunk-RGT4EJIB.js +0 -6961
  207. package/dist/chunk-RGT4EJIB.js.map +0 -1
  208. package/dist/chunk-T66HU3HX.js +0 -17
  209. package/dist/chunk-T66HU3HX.js.map +0 -1
  210. package/dist/chunk-WTI26YTM.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -2,27 +2,92 @@ export { LayerStack, LayerStackItem, LayerStackProps } from './ui/layers/index.j
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import * as react from 'react';
4
4
  import { ReactNode, WheelEvent, PointerEvent } from 'react';
5
- export { CanvasLayerDescriptor, CanvasStack, CanvasStackContext, CanvasStackContextValue, CanvasStackProps, screenToWorld, worldToScreen } from './canvas/index.js';
5
+ export { C as CheckboxRow, a as CheckboxRowProps, b as ColorRow, c as ColorRowProps, d as ControlPanel, N as NumberRow, e as NumberRowProps, P as PropertyList, f as PropertyListPack, g as PropertyListProps, h as PropertyOption, i as PropertyPanel, j as PropertyPanelProps, k as PropertyRow, l as PropertyRowLayout, m as PropertyRowProps, n as PropertyRowVariant, o as PropertySpan, p as PropertySpanProps, S as SelectRow, q as SelectRowProps, r as SliderRow, s as SliderRowProps, T as TextRow, t as TextRowProps, u as ToggleRow, v as ToggleRowProps } from './_dts/index-BDVzvRzQ.js';
6
+ import { N as Node, P as Path } from './_dts/types-C-gh9Ap-.js';
7
+ import { F as FillStyle, S as Stroke, D as DrawCommand, V as View, T as TextStyle } from './_dts/DrawCommand-B3bskUsC.js';
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-Cp3NivlC.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-Cp3NivlC.js';
10
+ import { B as BuiltinShapeToolId } from './_dts/shapeKinds-Cx_rxwsa.js';
11
+ export { CanvasStack, CanvasStackProps, ZoomAtOptions, centerOn, screenToWorld, worldToScreen, zoomAt } from './canvas/index.js';
12
+ export { C as CanvasLayerDescriptor, a as CanvasStackContext, b as CanvasStackContextValue, c as CanvasStackSurface } from './_dts/CanvasStackContext-DtAn_3O-.js';
6
13
  export { PaletteRegion, PaletteRegionProps, SidebarRegion, SidebarRegionProps, StatusRegion, StatusRegionProps, TitleBarRegion, TitleBarRegionProps, ToolbarRegion, ToolbarRegionProps, ViewportRegion, ViewportRegionProps, builtinContributions, mergeContributions, suppressContributions } from './chrome/index.js';
7
- import { I as Instrument, c as InstrumentList, T as TrialContribution, d as TrialTool, V as ViewTransform } from './_dts/types-BttTIent.js';
8
- export { C as CanvasCapability, e as CanvasLayer, b as DragDropCapability, D as DragFeedback, H as HitResult, f as IconComponent, L as LayerCapability, g as LayerDescriptor, P as PaletteItem, a as Point, R as RenderContext, S as SidebarSection, h as StatusReadout, i as SystemEvent, j as ToolCapability, k as ToolItem, l as ToolbarItem, m as TrialChromeContext, n as TrialRegion, U as UndoCapability, o as ViewportControl } from './_dts/types-BttTIent.js';
9
- import { T as ToolPrefLeaf } from './_dts/PrefsForm-BYa6cWnO.js';
10
- import { b as ConfigNode, A as Annotations, N as NodeOptions, c as ControlRenderer, d as ConfigOption, a as ConfigSchema, I as InferConfig, C as ConfigField, R as ResolvedConfig, e as ConfigRule, L as LeafPatch, f as ConfigRuleContext } from './_dts/types-DCGEcMO_.js';
11
- export { g as CheckboxField, h as ColorField, i as ConfigFieldBase, j as ConfigFieldType, k as ConfigOf, l as NodeValue, m as NumberField, S as SectionSpec, n as SelectField, o as SelectOption, p as SliderField, T as TextField } from './_dts/types-DCGEcMO_.js';
12
- export { ControlPanel } from './controls/index.js';
14
+ import { T as ToolPrefLeaf } from './_dts/PrefsForm-BkUJZx0A.js';
15
+ import { b as ConfigNode, A as Annotations, N as NodeOptions, c as ControlRenderer, d as ConfigOption, a as ConfigSchema, I as InferConfig, C as ConfigField, R as ResolvedConfig, e as ConfigRule, L as LeafPatch, f as ConfigRuleContext } from './_dts/types-D6s4b7if.js';
16
+ export { g as CheckboxField, h as ColorField, i as ConfigFieldBase, j as ConfigFieldType, k as ConfigOf, l as NodeValue, m as NumberField, S as SectionSpec, n as SelectField, o as SelectOption, p as SliderField, T as TextField } from './_dts/types-D6s4b7if.js';
13
17
  import { J as JobHandle } from './_dts/types-DJ79Tg5J.js';
14
18
  export { a as JobCapability, b as JobEvent, c as JobFailure, d as JobStatus } from './_dts/types-DJ79Tg5J.js';
15
19
  export { UseJobOptions, useJob } from './job/index.js';
16
- import { a as StorageAdapter, e as LabMode, T as TrialRecord, c as SavedSnapshot } from './_dts/types-1Sdxy_Pv.js';
17
- export { C as CreateLabStoreOptions, L as LabDocument, b as LabStoreState, S as SerializedTrial, d as TrialStateHandle, U as UndoStack } from './_dts/types-1Sdxy_Pv.js';
20
+ import { a as StorageAdapter, h as LabMode, T as TrialRecord, c as SavedSnapshot } from './_dts/types-DYMaEvM5.js';
21
+ 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-DYMaEvM5.js';
18
22
  export { LayerList, LayerListProps } from './layers/index.js';
23
+ export { CanvasLoupe, CanvasLoupeProps, DomLoupe, DomLoupeProps, LensCamera, LoupeBubble, LoupeBubbleProps, LoupeState, SourceRect, TrialLoupe, TrialLoupeProps, UseLoupeOptions, drawCanvasLens, lensCamera, lensSourceRect, sampleStack, useLoupe } from './loupe/index.js';
19
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';
20
- 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-CsGMjhu9.js';
21
- export { Box, Rect, SurfaceContext, SurfaceFrame, SurfaceHandle, UseTiledSurfaceOptions, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceOptional, useSurfaceTile, useTiledSurface } from './surface/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-gmMvZqPc.js';
26
+ export { Box, Rect, SurfaceCanvasContext, SurfaceContext, SurfaceFrame, SurfaceHandle, TilePainter, UseTiledSurfaceOptions, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceCanvas, useSurfaceOptional, useSurfaceTile, useTiledSurface } from './surface/index.js';
22
27
  export { EventBus, EventListener, clearUndo, createEventBus, emptyStack, pushSnapshot, redo, undo } from './undo/index.js';
23
28
  import 'windease';
24
29
  import 'zustand/vanilla';
25
30
 
31
+ /**
32
+ * Canonical inline-styling primitive for text nodes. A node's text is
33
+ * either a plain `string` (treated as a single-run, default-styled fragment)
34
+ * or `StyledRun[]` for rich content. `toRuns` is the funnel that normalizes
35
+ * either form into the array shape used by the renderer.
36
+ *
37
+ * Every field except `text` is optional; missing fields fall back to the
38
+ * node-level `TextStyle`. `bold`/`italic` are toggles; richer weight axes
39
+ * (300/500/900) are out of scope for slice 1.
40
+ */
41
+
42
+ /** A span of text with its own styling, as authored. Fields left absent
43
+ * inherit from the node's text style — this is the difference between a run
44
+ * and a fully resolved one. */
45
+ interface StyledRun {
46
+ text: string;
47
+ bold?: boolean;
48
+ italic?: boolean;
49
+ fontFamily?: string;
50
+ fontSize?: number;
51
+ fill?: FillStyle;
52
+ /** Outline over this run's glyphs. Overrides the node's own `data.stroke`;
53
+ * absent inherits it. Only painted on the outline tier. */
54
+ stroke?: Stroke;
55
+ letterSpacing?: number;
56
+ underline?: boolean;
57
+ strikethrough?: boolean;
58
+ /** Draw a rule above this run's ascent. Additive over the node style. */
59
+ overline?: boolean;
60
+ /**
61
+ * Set this run as a superscript or subscript — a raised or lowered baseline
62
+ * and a smaller size together, which is the pair `<sup>` and `<sub>` imply.
63
+ *
64
+ * A preset over the two primitives below, not a third mechanism: it supplies
65
+ * a `baselineShift` and a `fontScale`, and naming either of those directly
66
+ * overrides that half while leaving the other alone. The numbers are in
67
+ * {@link SCRIPT_METRICS}.
68
+ */
69
+ script?: 'super' | 'sub';
70
+ /**
71
+ * Raise (positive) or lower (negative) this run off the line's shared
72
+ * baseline, in ems of the *inherited* font size — so a run's rise does not
73
+ * shrink along with the run when `fontScale` also applies.
74
+ */
75
+ baselineShift?: number;
76
+ /**
77
+ * Multiplier on the inherited font size. The relative counterpart to
78
+ * `fontSize`, which pins an absolute size and wins over this when both are
79
+ * present.
80
+ */
81
+ fontScale?: number;
82
+ }
83
+
84
+ /** Built-in tool ids that aren't shape tools — the ones with no entry in
85
+ * the `core/shapeKinds` table. */
86
+ declare const NON_SHAPE_BUILTIN_TOOLS: readonly ["select", "rotate", "hand"];
87
+ /** Built-in tool ids SceneCanvas knows how to mount when no `tools` prop
88
+ * is supplied. Pass a subset via `defaultTools` to slim the registered set. */
89
+ type BuiltinToolId = (typeof NON_SHAPE_BUILTIN_TOOLS)[number] | BuiltinShapeToolId;
90
+
26
91
  /** An annotation drawn over a curve plot: a shaded band across a range of x,
27
92
  * or a vertical line at one x. */
28
93
  type CurveMark = {
@@ -150,185 +215,435 @@ interface PropertyGroupProps {
150
215
  */
151
216
  declare function PropertyGroup({ title, hidden, children, className, pack, }: PropertyGroupProps): react_jsx_runtime.JSX.Element | null;
152
217
 
153
- /** Props for `<PropertyPanel>`. */
154
- interface PropertyPanelProps {
155
- title?: ReactNode;
156
- children: ReactNode;
157
- className?: string;
218
+ /** The subset of a mark's scene node this needs: where it is, and what it is. */
219
+ interface PaintableMark {
220
+ pose: WorldRect;
221
+ data: AnnotationData;
158
222
  }
159
- /** A titled panel holding property rows — the sidebar container the rest of
160
- * this module's components fill. */
161
- declare function PropertyPanel({ title, children, className }: PropertyPanelProps): react_jsx_runtime.JSX.Element;
162
- /** How a property list packs its rows into two columns. */
163
- type PropertyListPack = 'auto-color' | 'pairs';
164
- /** Props for `<PropertyList>`. */
165
- interface PropertyListProps {
166
- children: ReactNode;
167
- className?: string;
168
- /**
169
- * How rows pack into the 2-column grid.
170
- * - `'auto-color'` (default): only color rows pair side-by-side; everything
171
- * else spans the full width. Right for sparse top-level panels.
172
- * - `'pairs'`: every row auto-places into the 2-column grid two-per-row.
173
- * Headers and subpanels still span the full width; wrap any other
174
- * full-width child in `<PropertySpan>`. Right for dense effect bodies.
175
- */
176
- pack?: PropertyListPack;
223
+ /** How a mark is drawn, as opposed to where. Resolved by the overlay from the
224
+ * instrument's vocabulary and the mark's own staleness. */
225
+ interface MarkStyle {
226
+ /** The status's colour, or the default. */
227
+ color?: string;
228
+ /** A mark whose stored position no longer describes the picture. Drawn
229
+ * dashed rather than hidden: it still describes *something*, and dropping
230
+ * it would lose it. */
231
+ stale?: boolean;
177
232
  }
178
233
  /**
179
- * Grid container for PropertyRows. Use standalone for chrome-less layouts, or
180
- * nest inside <PropertyPanel/> for the standard glass card.
234
+ * What one mark draws, in its target's world.
235
+ *
236
+ * Pure: a node and the target's content box in, draw commands out. Geometry
237
+ * that a bounding box cannot describe — a line's ends, a stroke's path — comes
238
+ * from `data.points`, which is in fractions like the bounds.
181
239
  */
182
- declare function PropertyList({ children, className, pack }: PropertyListProps): react_jsx_runtime.JSX.Element;
183
- /** Props for `<PropertySpan>`. */
184
- interface PropertySpanProps {
185
- children: ReactNode;
186
- className?: string;
240
+ declare function markCommands(m: PaintableMark, content: {
241
+ w: number;
242
+ h: number;
243
+ }, style?: MarkStyle): DrawCommand[];
244
+
245
+ /** What resolving a mark's appearance needs beyond the mark itself. */
246
+ interface MarkDrawOptions {
247
+ /** The target's content box — the world a mark's geometry is in. */
248
+ content: {
249
+ w: number;
250
+ h: number;
251
+ };
252
+ /** The target's `positionDependsOn`, for staleness. */
253
+ positionDependsOn?: readonly string[];
254
+ /** The trial's config at the time of the draw. */
255
+ config: unknown;
256
+ /** The instrument's vocabulary, for a status's colour. */
257
+ meaning?: AnnotationMeaning;
187
258
  }
188
259
  /**
189
- * Wrapper that makes an arbitrary child span both columns of a
190
- * `<PropertyList pack="pairs">`, a `<PropertyGroup pack="pairs">` body, or a
191
- * `<Subpanel>`. `<PropertyRow span>` covers the row case; this covers
192
- * everything else a consumer puts in the grid.
193
- */
194
- declare function PropertySpan({ children, className }: PropertySpanProps): react_jsx_runtime.JSX.Element;
195
- /** Which control shape a row holds, which decides its intrinsic layout. */
196
- type PropertyRowVariant = 'default' | 'color' | 'checkbox';
197
- /** Whether a row's label sits above its control or beside it. */
198
- type PropertyRowLayout = 'block' | 'inline';
199
- /** Props for `<PropertyRow>`. */
200
- interface PropertyRowProps {
201
- label: ReactNode;
202
- /** Right-aligned readout shown next to the label (e.g. current value). */
203
- readout?: ReactNode;
204
- /**
205
- * Help text for the row, shown in a tooltip off an ⓘ affordance beside the
206
- * label. Empty or absent renders no affordance.
207
- */
208
- description?: string;
209
- variant?: PropertyRowVariant;
210
- /**
211
- * Label position relative to the control. "block" (default) stacks
212
- * label above control; "inline" places the label to the left.
213
- * Color and checkbox variants are always inline by their own nature.
214
- */
215
- layout?: PropertyRowLayout;
216
- /**
217
- * Take the full width of the enclosing grid. Only has an effect inside a
218
- * `<PropertyList pack="pairs">` or a `<Subpanel>`; elsewhere rows are already
219
- * full width.
220
- */
221
- span?: boolean;
222
- children: ReactNode;
223
- htmlFor?: string;
224
- className?: string;
260
+ * How one mark is drawn — shared by the pane on screen and by an export.
261
+ *
262
+ * One function rather than two call sites building their own, because an
263
+ * export that resolves a status colour or a stale dash differently from the
264
+ * screen produces a picture nobody was looking at.
265
+ */
266
+ declare function createMarkDrawOne(opts: MarkDrawOptions): (node: Node<AnnotationData, 'marks', WorldRect>, pose: WorldRect, view: View) => DrawCommand[];
267
+ /** How a mark looks, as opposed to where it is. Separate from the callback
268
+ * above because an SVG export resolves the same appearance without ever
269
+ * building a draw command. */
270
+ declare function resolveMarkStyle(data: AnnotationData, opts: MarkDrawOptions): MarkStyle;
271
+
272
+ /** Which of the two composition routes an export takes. */
273
+ type CapturePlan = 'svg-document' | 'raster-stack';
274
+ /**
275
+ * Vector all the way through, or both sides rasterized and stacked.
276
+ *
277
+ * An SVG base is the only one that nests: the marks serialize beside the
278
+ * artifact's own markup and the whole document rasterizes once at the end. A
279
+ * raster base, or none at all, takes the renderer's own path instead — which
280
+ * is also what draws marks onto transparency for a target that declares no
281
+ * base.
282
+ */
283
+ declare function capturePlan(base: CaptureSource | undefined, format: 'png' | 'svg'): CapturePlan;
284
+ interface ComposeSvgArgs {
285
+ base?: CaptureSource;
286
+ scene: MarkScene;
287
+ draw: MarkDrawOptions;
288
+ scale: number;
289
+ onWarn?: (message: string) => void;
225
290
  }
226
- /** The label-plus-control frame every typed row below is built from. Use it
227
- * directly for a control this module does not cover. */
228
- declare function PropertyRow({ label, readout, description, variant, layout, span, children, htmlFor, className, }: PropertyRowProps): react_jsx_runtime.JSX.Element;
229
- /** Props for `<SliderRow>`. */
230
- interface SliderRowProps {
231
- label: ReactNode;
232
- value: number;
233
- min: number;
234
- max: number;
235
- step?: number;
236
- onChange: (next: number) => void;
237
- /** Override how the value is rendered next to the label. Defaults to `value.toString()`. */
238
- format?: (value: number) => ReactNode;
291
+ /**
292
+ * The base and the marks in one SVG document.
293
+ *
294
+ * The outer `viewBox` is the content box, so marks — which are already in it —
295
+ * need no transform, and `width`/`height` carry the export scale. Both halves
296
+ * nest as child `<svg>` elements, which each establish their own viewport and
297
+ * so keep their own `viewBox` maths out of this function.
298
+ */
299
+ declare function composeCaptureSvg(args: ComposeSvgArgs): string;
300
+ /** What a capture needs about the target it is exporting. */
301
+ interface CaptureArgs {
302
+ target: string;
303
+ scene: MarkScene;
304
+ draw: MarkDrawOptions;
305
+ base?: () => CaptureSource | Promise<CaptureSource>;
306
+ onWarn?: (message: string) => void;
307
+ }
308
+ /** Export one target's picture with its marks on it. */
309
+ declare function captureTarget(args: CaptureArgs, opts?: CaptureOptions): Promise<CaptureResult>;
310
+
311
+ /**
312
+ * Export a target's picture with its marks on it.
313
+ *
314
+ * A panel rather than a button because a mark belongs to a target: with more
315
+ * than one pane, "export" on its own does not say what.
316
+ *
317
+ * Reads the store through the hook the way `<MarkList>` does — the chrome
318
+ * context carries no instrument state and is not the route to it.
319
+ */
320
+ declare function ExportMenu(): react_jsx_runtime.JSX.Element | null;
321
+
322
+ /** Props for `<MarkList>`. */
323
+ interface MarkListProps {
324
+ /** The instrument's vocabulary. Omitted, rows carry no status control —
325
+ * a host that declared none owns what a mark means. */
326
+ meaning?: AnnotationMeaning;
327
+ /** The live config, for answering staleness. */
328
+ config: unknown;
329
+ }
330
+ /** Every mark on this trial's targets: what it says, and whether it still
331
+ * describes the picture under it.
332
+ *
333
+ * Reads the store through the hook, which re-renders on every mutation — so a
334
+ * mark drawn on a pane appears here without anything wiring the two. */
335
+ declare function MarkList({ meaning, config }: MarkListProps): react_jsx_runtime.JSX.Element;
336
+
337
+ /**
338
+ * Whether a stored mark still describes the picture the current config
339
+ * produces. A target names the config keys its positions depend on; labkit
340
+ * snapshots and compares them without knowing what any of them mean.
341
+ */
342
+ /** The values of `keys` in `config`, for storing beside a new mark. Keys the
343
+ * config does not carry are omitted rather than stored as undefined, so the
344
+ * snapshot says what was known rather than what was asked. */
345
+ declare function seenFrom(config: unknown, keys: readonly string[]): Record<string, unknown>;
346
+ /**
347
+ * Whether the picture moved under the mark.
348
+ *
349
+ * Only keys present in `seen` are compared. A mark filed before its target
350
+ * declared a new dependency must not go stale retroactively: nothing can know
351
+ * what that key was at the time, and guessing would grey out every old mark
352
+ * the first time a target grows a key.
353
+ */
354
+ declare function isStale(seen: Readonly<Record<string, unknown>> | undefined, config: unknown, keys: readonly string[]): boolean;
355
+
356
+ /**
357
+ * Public types for `@weasel-js/svg`. The package exposes a flat,
358
+ * discriminated-union node model (`SvgNode`) that mirrors the SVG element
359
+ * tree but uses weasel-native leaf data (`Path`, `FillStyle`) for geometry and
360
+ * paint.
361
+ *
362
+ * Parsing collapses every `transform="..."` onto its descendants' geometry,
363
+ * so the `SvgNode` tree returned from `parseSvg` never has a non-identity
364
+ * group transform. Consumers may still construct groups with explicit
365
+ * transforms before serializing, in which case the serializer emits a
366
+ * single `matrix(a b c d e f)` on the `<g>`.
367
+ */
368
+
369
+ /**
370
+ * Opaque pass-through bag for namespaced XML content.
371
+ *
372
+ * weasel-svg does not interpret the contents — it only ensures that any
373
+ * attributes or child elements in a *declared* XML namespace round-trip
374
+ * losslessly through parse → serialize. Consumers (e.g. an app-specific
375
+ * bridge layer) hang their domain semantics off this structure.
376
+ *
377
+ * Keyed by namespace prefix (the prefix is a write-time choice; the URI
378
+ * is the canonical identifier and is supplied via `ParseOptions.namespaces`
379
+ * / `SerializeOptions.namespaces`).
380
+ */
381
+ interface NamespaceMeta {
382
+ [prefix: string]: {
383
+ /** Local-name → string-value map for attributes in this namespace. */
384
+ attrs?: Record<string, string>;
385
+ /**
386
+ * Child elements in this namespace, keyed by local name. Each entry
387
+ * is an array because a namespace can host multiple sibling elements
388
+ * with the same tag (e.g. `<wd:layer/><wd:layer/>`).
389
+ */
390
+ elements?: Record<string, NamespacedElement[]>;
391
+ };
392
+ }
393
+ /** Opaque structured representation of a namespaced element. */
394
+ interface NamespacedElement {
395
+ /** Attribute local-name → string-value. */
396
+ attrs: Record<string, string>;
397
+ /** Text content, when the element contains only text (no child elements). */
398
+ text?: string;
399
+ /** Nested namespaced children, keyed by local name (recursive). */
400
+ children?: Record<string, NamespacedElement[]>;
401
+ }
402
+ /**
403
+ * 2x3 affine matrix in column-major form (SVG's `matrix(a b c d e f)`
404
+ * order). Maps `[x', y'] = [a*x + c*y + e, b*x + d*y + f]`.
405
+ */
406
+ type Matrix = readonly [number, number, number, number, number, number];
407
+ /**
408
+ * FillStyle description in the SVG sense — either explicit `none`, a solid
409
+ * color, or a reference to a weasel-native gradient `FillStyle`. Solid colors
410
+ * are normalized to `#rrggbb` strings; opacity is carried separately so
411
+ * `fill-opacity` and `stroke-opacity` round-trip cleanly.
412
+ */
413
+ type SvgPaint = {
414
+ kind: 'none';
415
+ } | {
416
+ kind: 'solid';
417
+ color: string;
418
+ opacity?: number;
419
+ } | {
420
+ kind: 'gradient';
421
+ paint: FillStyle;
422
+ };
423
+ /** Stroke description: a paint plus structural line parameters. */
424
+ interface SvgStroke {
425
+ paint: SvgPaint;
426
+ width: number;
427
+ opacity?: number;
428
+ /** `stroke-linecap`. Default per SVG spec is `'butt'`. */
429
+ cap?: 'butt' | 'round' | 'square';
430
+ /** `stroke-linejoin`. Default per SVG spec is `'miter'`. SVG's `arcs` / `miter-clip` map to `'miter'` with a warning. */
431
+ join?: 'miter' | 'round' | 'bevel';
432
+ /** `stroke-dasharray` as a flat number array. Odd-length inputs are doubled per SVG spec. */
433
+ dash?: number[];
239
434
  /**
240
- * Optional suffix rendered next to the readout. A string becomes a
241
- * baseline-aligned dim "word" unit (e.g. "px"); pass JSX like `<sup>°</sup>`
242
- * to get the browser's native super positioning for symbol units.
435
+ * `stroke-miterlimit`. SVG's default is 4. Weasel's renderer defaults to
436
+ * 10 (Canvas2D) when unset, so parsed strokes without an explicit
437
+ * attribute may render with longer miters than the source SVG intended.
243
438
  */
244
- unit?: ReactNode;
245
- layout?: PropertyRowLayout;
246
- description?: string;
247
- }
248
- /** A bounded number edited by dragging, with a live readout whose precision
249
- * follows `step`. */
250
- declare function SliderRow({ label, value, min, max, step, onChange, format, unit, layout, description, }: SliderRowProps): react_jsx_runtime.JSX.Element;
251
- /** Props for `<ColorRow>`. */
252
- interface ColorRowProps {
253
- label: ReactNode;
254
- value: string;
255
- onChange: (next: string) => void;
256
- /** 0..1 alpha. When provided, a translucent slider renders beneath the swatch. */
257
- alpha?: number;
258
- onAlphaChange?: (next: number) => void;
439
+ miterLimit?: number;
440
+ /** `marker-start` / `marker-mid` / `marker-end`, as the bare `url(#id)` key. */
441
+ markerStart?: string;
442
+ markerMid?: string;
443
+ markerEnd?: string;
444
+ }
445
+ /**
446
+ * Leaf node: a path geometry plus fill/stroke. All other v1 shapes
447
+ * (`<rect>`, `<ellipse>`, etc.) are lowered to this representation on
448
+ * parse — `<rect>` uses weasel's `RectPath` fast-path subtype when
449
+ * possible, everything else becomes a `PolygonPath`.
450
+ */
451
+ interface SvgPathNode {
452
+ kind: 'path';
453
+ path: Path;
454
+ fill: SvgPaint;
455
+ stroke?: SvgStroke;
456
+ /** Element-level opacity (`opacity="..."`), 0..1. */
457
+ opacity?: number;
458
+ /** Element-level rotation in **radians**, pivoting around the AABB
459
+ * center of the underlying `path` geometry. Emitted as SVG
460
+ * `transform="rotate(angleDegrees cx cy)"`. */
461
+ rotation?: number;
462
+ /** Opaque per-element bag for declared namespaces. See `NamespaceMeta`. */
463
+ meta?: NamespaceMeta;
464
+ }
465
+ /**
466
+ * Group node: an SVG `<g>`. On parse, `transform` is always omitted (any
467
+ * `transform` attribute is collapsed onto descendants' geometry). On
468
+ * serialize, a non-identity `transform` is emitted as
469
+ * `matrix(a b c d e f)`.
470
+ */
471
+ interface SvgGroupNode {
472
+ kind: 'group';
473
+ children: SvgNode[];
474
+ transform?: Matrix;
475
+ opacity?: number;
476
+ /** Opaque per-element bag for declared namespaces. See `NamespaceMeta`. */
477
+ meta?: NamespaceMeta;
478
+ }
479
+ /**
480
+ * Text leaf node. Mirrors the kit's `TextPose` shape — a bounding box plus
481
+ * text content, optional rich-text `runs` (per-range styling), and an
482
+ * optional `TextStyle` for the node-wide defaults.
483
+ *
484
+ * Note on SVG text geometry: native `<text>` flows from a baseline; it
485
+ * doesn't have width/height attributes. The serializer emits
486
+ * `dominant-baseline="text-before-edge"` so `y` is the top of the text
487
+ * box, plus `data-weasel-width` / `data-weasel-height` so weasel's
488
+ * explicit box dimensions round-trip losslessly. External SVG text
489
+ * (lacking the data-* attrs) imports with estimated dimensions —
490
+ * {@link UNBOUNDED_TEXT_WIDTH} and
491
+ * `height = fontSize * lineHeight * (lineCount || 1)`.
492
+ */
493
+ interface SvgTextNode {
494
+ kind: 'text';
495
+ x: number;
496
+ y: number;
497
+ width: number;
498
+ height: number;
499
+ /** Plain text. When `runs` is set, `runsToPlainText(runs)` must equal `text`. */
500
+ text: string;
501
+ /** Optional per-range styling — same shape as `TextPose.runs`. */
502
+ runs?: StyledRun[];
503
+ /** Node-wide typography. Defaults applied at render time via `resolveTextStyle`. */
504
+ style?: TextStyle;
259
505
  /**
260
- * Render the alpha track as inert (dimmed, no thumb, not-allowed cursor).
261
- * Use when the color's consumer drops alpha so the affordance reads dead.
506
+ * Node-wide glyph paint, the `FillStyle` / `Stroke` a kit text node holds
507
+ * in `data.fill` / `data.stroke`. Not `SvgPaint`, which is the path
508
+ * nodes' shape — a text paint reaches the renderer through the runs, and
509
+ * `StyledRun.fill` / `.stroke` override these per range.
262
510
  */
263
- alphaDisabled?: boolean;
264
- description?: string;
265
- }
266
- /** A color swatch, optionally with an alpha slider beneath it. */
267
- declare function ColorRow({ label, value, onChange, alpha, onAlphaChange, alphaDisabled, description, }: ColorRowProps): react_jsx_runtime.JSX.Element;
268
- /** Props for `<CheckboxRow>`. */
269
- interface CheckboxRowProps {
270
- label: ReactNode;
271
- value: boolean;
272
- onChange: (next: boolean) => void;
273
- description?: string;
274
- }
275
- /** A boolean checkbox. */
276
- declare function CheckboxRow({ label, value, onChange, description }: CheckboxRowProps): react_jsx_runtime.JSX.Element;
277
- /** Props for `<TextRow>`. */
278
- interface TextRowProps {
279
- label: ReactNode;
280
- value: string;
281
- onChange: (next: string) => void;
282
- placeholder?: string;
283
- maxLength?: number;
284
- layout?: PropertyRowLayout;
285
- description?: string;
286
- }
287
- /** A single-line text input. */
288
- declare function TextRow({ label, value, onChange, placeholder, maxLength, layout, description, }: TextRowProps): react_jsx_runtime.JSX.Element;
289
- /** Props for `<NumberRow>`. */
290
- interface NumberRowProps {
291
- label: ReactNode;
292
- value: number;
293
- onChange: (next: number) => void;
294
- min?: number;
295
- max?: number;
296
- step?: number;
297
- placeholder?: string;
298
- layout?: PropertyRowLayout;
299
- description?: string;
300
- }
301
- /** A number typed directly. Reach for `<SliderRow>` when the range matters
302
- * more than the exact value. */
303
- declare function NumberRow({ label, value, onChange, min, max, step, placeholder, layout, description, }: NumberRowProps): react_jsx_runtime.JSX.Element;
304
- interface PropertyOption<T extends string> {
305
- value: T;
306
- label: ReactNode;
307
- }
308
- /** Props for `<SelectRow>`. */
309
- interface SelectRowProps<T extends string> {
310
- label: ReactNode;
311
- value: T;
312
- options: ReadonlyArray<PropertyOption<T>>;
313
- onChange: (next: T) => void;
314
- layout?: PropertyRowLayout;
315
- description?: string;
316
- }
317
- /** A dropdown over a fixed set of choices. Prefer `<ToggleRow>` when there
318
- * are only two or three and they should all stay visible. */
319
- declare function SelectRow<T extends string>({ label, value, options, onChange, layout, description, }: SelectRowProps<T>): react_jsx_runtime.JSX.Element;
320
- /** Props for `<ToggleRow>`. */
321
- interface ToggleRowProps<T extends string> {
322
- label: ReactNode;
323
- value: T;
324
- options: ReadonlyArray<PropertyOption<T>>;
325
- onChange: (next: T) => void;
326
- layout?: PropertyRowLayout;
327
- description?: string;
328
- }
329
- /** A segmented control: the same choice as a select, with every option
330
- * visible at once. */
331
- declare function ToggleRow<T extends string>({ label, value, options, onChange, layout, description, }: ToggleRowProps<T>): react_jsx_runtime.JSX.Element;
511
+ fill?: FillStyle;
512
+ stroke?: Stroke;
513
+ /** Element-level opacity (`opacity="..."`), 0..1. */
514
+ opacity?: number;
515
+ /** Element-level rotation in **radians**, pivoting around the unrotated
516
+ * AABB center `(x + width/2, y + height/2)`. Emitted as SVG
517
+ * `transform="rotate(angleDegrees cx cy)"`. */
518
+ rotation?: number;
519
+ /** Opaque per-element bag for declared namespaces. See `NamespaceMeta`. */
520
+ meta?: NamespaceMeta;
521
+ }
522
+ /**
523
+ * Raster-image leaf — an SVG `<image>`. `href` is the element's `href` (or
524
+ * legacy `xlink:href`) verbatim: an external URL or a `data:` URI. The
525
+ * package neither fetches nor decodes it, so an external URL round-trips as
526
+ * a reference and only resolves when something downstream loads it.
527
+ *
528
+ * SVG's `preserveAspectRatio` is not modeled; the box is taken literally.
529
+ */
530
+ interface SvgImageNode {
531
+ kind: 'image';
532
+ href: string;
533
+ x: number;
534
+ y: number;
535
+ width: number;
536
+ height: number;
537
+ /** Element-level opacity (`opacity="..."`), 0..1. */
538
+ opacity?: number;
539
+ /** Element-level rotation in **radians**, pivoting around the unrotated
540
+ * AABB center `(x + width/2, y + height/2)`. Emitted as SVG
541
+ * `transform="rotate(angleDegrees cx cy)"`. */
542
+ rotation?: number;
543
+ /** Opaque per-element bag for declared namespaces. See `NamespaceMeta`. */
544
+ meta?: NamespaceMeta;
545
+ }
546
+ /** Discriminated-union node — the leaf of the public tree. */
547
+ type SvgNode = SvgPathNode | SvgGroupNode | SvgTextNode | SvgImageNode;
548
+
549
+ /**
550
+ * One mark as SVG nodes, converted from the very commands the pane paints.
551
+ *
552
+ * Deliberately not a second switch over `data.kind`: geometry has one source,
553
+ * and this is a translation of it. `serializeSvg` turns the result into a
554
+ * document.
555
+ */
556
+ declare function markSvgNodes(m: PaintableMark, content: {
557
+ w: number;
558
+ h: number;
559
+ }, style?: MarkStyle): SvgNode[];
560
+
561
+ /** Props for `<AnnotationOverlay>`. */
562
+ interface AnnotationOverlayProps {
563
+ target: AnnotationTarget;
564
+ /** The trial's mark scene — shared by every target; a mark's own `target`
565
+ * field is what separates them. */
566
+ scene: MarkScene;
567
+ /** Snapshotted onto each new mark, so staleness can be answered later. */
568
+ config: unknown;
569
+ /** The trial's resolved tool slot. */
570
+ activeToolId: string | null;
571
+ /** The instrument's vocabulary, for a status's colour. */
572
+ meaning?: AnnotationMeaning;
573
+ }
574
+ /**
575
+ * One target's drawing surface: a transparent box over the target's element
576
+ * taking the input, and a `<SceneCanvas>` painting into the lab's shared
577
+ * buffer at that box's rect.
578
+ *
579
+ * The box is portalled into the surface container because that is what tile
580
+ * rects are measured against; positioning it among the instrument's own DOM
581
+ * would put it in whatever positioning context happened to be there.
582
+ */
583
+ declare function AnnotationOverlay({ target, scene, config, activeToolId, meaning, }: AnnotationOverlayProps): react.ReactPortal | null;
584
+
585
+ /** Null in a trial whose instrument declares no `annotations`. */
586
+ declare const AnnotationsContext: react.Context<AnnotationsApi | null>;
587
+ /** The marks on this trial's targets. Reached through a hook rather than the
588
+ * chrome context, which carries no instrument state — a sidebar panel listing
589
+ * marks pulls it the way `useTrialState()` does. Throws outside a trial whose
590
+ * instrument declares the capability. */
591
+ declare function useAnnotations(): AnnotationsApi;
592
+ /** The marks on this trial's targets, or null. For chrome that renders in
593
+ * every trial and does something else where there are none. */
594
+ declare function useAnnotationsOptional(): AnnotationsApi | null;
595
+
596
+ /** Props for `<AnnotationTargets>`. */
597
+ interface AnnotationTargetsProps {
598
+ capability: AnnotationsCapability;
599
+ state: unknown;
600
+ config: unknown;
601
+ annotations: AnnotationsApi;
602
+ activeToolId: string | null;
603
+ }
604
+ /** One overlay per region the instrument said accepts marks. */
605
+ declare function AnnotationTargets({ capability, state, config, annotations, activeToolId, }: AnnotationTargetsProps): react_jsx_runtime.JSX.Element;
606
+
607
+ /** Which weasel tool an annotation tool drives, and what kind of mark that
608
+ * makes. `select` makes none. */
609
+ interface AnnotationToolInfo {
610
+ weaselTool: BuiltinToolId;
611
+ kind?: AnnotationKind;
612
+ }
613
+ /** The palette an instrument gets for declaring `annotations`. Ids share the
614
+ * trial's contribution namespace with `instrument.tools`, and one tool slot
615
+ * holds whichever is active. */
616
+ declare const ANNOTATION_TOOLS: readonly TrialTool[];
617
+ /** What `id` drives, or undefined for a tool that is not one of these. */
618
+ declare function annotationToolInfo(id: string | null): AnnotationToolInfo | undefined;
619
+ /** Every weasel tool the overlay has to mount for this palette to work. */
620
+ declare const ANNOTATION_WEASEL_TOOLS: readonly BuiltinToolId[];
621
+
622
+ /** A target's world in CSS pixels: the box its fractions are fractions of. */
623
+ interface ContentSize {
624
+ w: number;
625
+ h: number;
626
+ }
627
+ /** A target's drawn box on the surface, in CSS pixels. */
628
+ interface PaneSize {
629
+ w: number;
630
+ h: number;
631
+ }
632
+ /** labkit's camera in weasel's shape. Zoom is uniform, so it lands on both
633
+ * scale axes; pan is weasel's translation unchanged. */
634
+ declare function toWeaselView(v: ViewTransform): View;
635
+ /** The inverse. A weasel view with unequal axis scales collapses to its x —
636
+ * labkit's camera has one zoom and cannot hold the other. */
637
+ declare function fromWeaselView(v: View): ViewTransform;
638
+ /**
639
+ * The camera a target with none of its own draws through: its content box
640
+ * scaled to fit the box it is drawn in, anchored at the origin.
641
+ *
642
+ * The spec calls the camera "a plain scale" at zoom 1; zoom 1 is only right
643
+ * when the pane happens to be the content's size, and a mark drawn on a
644
+ * scaled-down pane otherwise lands outside it.
645
+ */
646
+ declare function fitView(content: ContentSize, pane: PaneSize): ViewTransform;
332
647
 
333
648
  /** A point in the space the instrument works in. */
334
649
  interface Vec3 {
@@ -695,6 +1010,11 @@ interface WorkspaceProps {
695
1010
  onLayoutChange?: (layout: TrialLayout) => void;
696
1011
  gap?: number;
697
1012
  padding?: number;
1013
+ /** Undocked sidebar panels to render alongside the trials. A `'tile'` panel
1014
+ * joins the grid as a peer of the trials; a `'floating'` one goes into the
1015
+ * floating zone above it. The body is portalled in by the trial that owns
1016
+ * it, so all this renders is the frame and the host. */
1017
+ panels?: readonly PanelDescriptor[];
698
1018
  /**
699
1019
  * Fixed tiling extent. Omit in an app — the grid measures its own box. Supply
700
1020
  * it where nothing measures, notably jsdom: at a zero measurement the grid
@@ -705,14 +1025,14 @@ interface WorkspaceProps {
705
1025
  h: number;
706
1026
  };
707
1027
  }
708
- /**
709
- * Auto-balanced tiling of trials, `ceil(sqrt(n))` columns wide.
710
- *
711
- * Tiles are absolutely positioned at the rects `gridStrategy` computes, not
712
- * laid out by CSS — `windease/styles.css` (folded into
713
- * `@weasel-js/labkit/styles.css`) carries the rules that positioning depends on.
714
- */
715
- declare function Workspace({ children, ids, resizable, reorderable, onReorder, layout, onLayoutChange, gap, padding, viewport, }: WorkspaceProps): react_jsx_runtime.JSX.Element;
1028
+ /** One undocked panel, as the workspace needs to know it. */
1029
+ interface PanelDescriptor {
1030
+ /** Stable key; also the portal host key the owning trial writes into. */
1031
+ key: string;
1032
+ title: string;
1033
+ as: 'tile' | 'floating';
1034
+ }
1035
+ declare function Workspace({ children, ids, panels, resizable, reorderable, onReorder, layout, onLayoutChange, gap, padding, viewport, }: WorkspaceProps): react_jsx_runtime.JSX.Element;
716
1036
 
717
1037
  /** The 2D view labkit has always shipped, and what a trial gets when it names no
718
1038
  * other. Re-exported under its own name so a consumer can say which it means. */
@@ -773,6 +1093,11 @@ interface TrialProps {
773
1093
  * instrument, and mounts the instrument inside the trial chrome. */
774
1094
  declare function Trial({ id, chrome, suppress }: TrialProps): react_jsx_runtime.JSX.Element;
775
1095
 
1096
+ /** The trial's loupe as its chrome sees it: a switch and its position. */
1097
+ interface LoupeBindings {
1098
+ on: boolean;
1099
+ toggle: () => void;
1100
+ }
776
1101
  interface UndoBindings {
777
1102
  canUndo: boolean;
778
1103
  canRedo: boolean;
@@ -788,6 +1113,9 @@ interface TrialChromeProps {
788
1113
  undoBindings?: UndoBindings;
789
1114
  /** Supplied when the instrument declares a `job`. */
790
1115
  job?: JobHandle;
1116
+ /** Supplied when the instrument declares a `loupe`. The lens itself is the
1117
+ * trial's to mount; the chrome only offers the switch. */
1118
+ loupe?: LoupeBindings;
791
1119
  /** Contributions the trial runtime itself adds — the drag palette and the
792
1120
  * layer list, which depend on runtime state the instrument cannot reach. */
793
1121
  trialChrome?: readonly TrialContribution[];
@@ -804,7 +1132,7 @@ interface TrialChromeProps {
804
1132
  /** The frame around a running instrument. Builds one chrome context, assembles
805
1133
  * the contributions the instrument, the runtime and the lab declare, and hands
806
1134
  * each region its slice. */
807
- declare function TrialChrome({ trialId, record, instrument, isLastTrial, undoBindings, job, trialChrome, chrome, suppress, activeToolId, setActiveTool, children, }: TrialChromeProps): react_jsx_runtime.JSX.Element;
1135
+ declare function TrialChrome({ trialId, record, instrument, isLastTrial, undoBindings, job, loupe, trialChrome, chrome, suppress, activeToolId, setActiveTool, children, }: TrialChromeProps): react_jsx_runtime.JSX.Element;
808
1136
 
809
1137
  /** Append a new trial running `instrumentName`, at that instrument's
810
1138
  * default config and initial state. */
@@ -825,5 +1153,5 @@ declare function resetTrial(trials: TrialRecord[], id: string, instruments: Inst
825
1153
  */
826
1154
  declare function reorderTrials(trials: TrialRecord[], ids: readonly string[]): TrialRecord[];
827
1155
 
828
- export { Annotations, CheckboxRow, ColorRow, ConfigField, ConfigNode, ConfigOption, ConfigRule, ConfigRuleContext, ConfigSchema, ControlRenderer, CurveField, DEFAULT_VIEW, EffectCard, EffectCardList, InferConfig, Instrument, InstrumentList, JobHandle, Lab, LabContext, LabMode, LabPalette, LabShell, LeafPatch, NodeOptions, NumberRow, PITCH_LIMIT, PropertyGroup, PropertyList, PropertyPanel, PropertyRow, PropertySpan, ResolvedConfig, SavedSnapshot, SelectRow, SliderRow, StorageAdapter, Subpanel, TextRow, ToggleRow, Trial, TrialChrome, TrialContribution, TrialRecord, TrialTool, ViewTransform, Workspace, addTrial, applyRules, as2DView, builtinRules, clampPitch, cloneTrial, closeTrial, defineInstrument, f, fromConfigFields, interstellarTheme, isLeafVisible, orbitAfterDrag, orbitAfterWheel, reorderTrials, resetTrial, resolveConfigSchema, titleCase, useConfigSchema, useLabContext, useOrbit, validateConfigSchema, wrapYaw };
829
- export type { CheckboxRowProps, ColorRowProps, CurveFieldProps, CurveMark, EffectCardListItem, EffectCardListProps, EffectCardProps, InstrumentSpec, LabContextValue, LabPaletteProps, LabProps, LabShellProps, NumberRowProps, OrbitHandlers, OrbitView, PropertyGroupProps, PropertyListPack, PropertyListProps, PropertyOption, PropertyPanelProps, PropertyRowLayout, PropertyRowProps, PropertyRowVariant, PropertySpanProps, SelectRowProps, SliderRowProps, SubpanelProps, TextRowProps, ToggleRowProps, TrialChromeProps, TrialLayout, TrialProps, UndoBindings, UseOrbitOptions, ValidationResult, Vec3, ViewTransform2D, WorkspaceProps };
1156
+ export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, AnnotationData, AnnotationKind, AnnotationMeaning, AnnotationOverlay, AnnotationTarget, AnnotationTargets, Annotations, AnnotationsApi, AnnotationsCapability, AnnotationsContext, CaptureOptions, CaptureResult, CaptureSource, ConfigField, ConfigNode, ConfigOption, ConfigRule, ConfigRuleContext, ConfigSchema, ControlRenderer, CurveField, DEFAULT_VIEW, EffectCard, EffectCardList, ExportMenu, InferConfig, Instrument, InstrumentList, JobHandle, Lab, LabContext, LabMode, LabPalette, LabShell, LeafPatch, MarkList, MarkScene, NodeOptions, PITCH_LIMIT, PropertyGroup, ResolvedConfig, SavedSnapshot, StorageAdapter, Subpanel, Trial, TrialChrome, TrialContribution, TrialRecord, TrialTool, ViewTransform, Workspace, WorldRect, addTrial, annotationToolInfo, applyRules, as2DView, builtinRules, capturePlan, captureTarget, clampPitch, cloneTrial, closeTrial, composeCaptureSvg, createMarkDrawOne, defineInstrument, f, fitView, fromConfigFields, fromWeaselView, interstellarTheme, isLeafVisible, isStale, markCommands, markSvgNodes, orbitAfterDrag, orbitAfterWheel, reorderTrials, resetTrial, resolveConfigSchema, resolveMarkStyle, seenFrom, titleCase, toWeaselView, useAnnotations, useAnnotationsOptional, useConfigSchema, useLabContext, useOrbit, validateConfigSchema, wrapYaw };
1157
+ export type { AnnotationOverlayProps, AnnotationTargetsProps, AnnotationToolInfo, CaptureArgs, CapturePlan, ComposeSvgArgs, ContentSize, CurveFieldProps, CurveMark, EffectCardListItem, EffectCardListProps, EffectCardProps, InstrumentSpec, LabContextValue, LabPaletteProps, LabProps, LabShellProps, MarkDrawOptions, MarkListProps, MarkStyle, OrbitHandlers, OrbitView, PaintableMark, PaneSize, PanelDescriptor, PropertyGroupProps, SubpanelProps, TrialChromeProps, TrialLayout, TrialProps, UndoBindings, UseOrbitOptions, ValidationResult, Vec3, ViewTransform2D, WorkspaceProps };