@weasel-js/labkit 1.6.0 → 1.7.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 (222) hide show
  1. package/dist/_dts/{CanvasStackContext-DQgcH1ny.d.ts → CanvasStackContext-D2jnIwfk.d.ts} +1 -1
  2. package/dist/_dts/FloatingPanel-7j0IcXwz.d.ts +30 -0
  3. package/dist/_dts/{LayerList.d-2c9yup5Y.d.ts → LayerList.d-DiuEArKq.d.ts} +4 -4
  4. package/dist/_dts/PrefsRow.d-TOZ7BgD9.d.ts +79 -0
  5. package/dist/_dts/PropertyPanel.d-D-1paCbE.d.ts +141 -0
  6. package/dist/_dts/{Select.d-BchGMC2Y.d.ts → Select.d-Bensr_MT.d.ts} +15 -6
  7. package/dist/_dts/Stage-CCWfQQWM.d.ts +202 -0
  8. package/dist/_dts/index-B2Yj5aA0.d.ts +274 -0
  9. package/dist/_dts/{index-B0--8PEM.d.ts → index-CsYqUHD3.d.ts} +12 -13
  10. package/dist/_dts/{types-B7y8hX1D.d.ts → types-CRPSGFAp.d.ts} +33 -5
  11. package/dist/_dts/{frac-DTRq7Xpb.d.ts → types-CSm9jgol.d.ts} +700 -650
  12. package/dist/_dts/{useTrialState-CP4jfuKl.d.ts → useTrialState-CTZPgeZ7.d.ts} +2 -3
  13. package/dist/canvas/index.d.ts +40 -8
  14. package/dist/canvas/index.js +5 -3
  15. package/dist/chrome/index.d.ts +5 -6
  16. package/dist/chrome/index.js +9 -7
  17. package/dist/chunk-24W5VEJW.js +18 -0
  18. package/dist/chunk-24W5VEJW.js.map +1 -0
  19. package/dist/chunk-275JRRVD.js +728 -0
  20. package/dist/chunk-275JRRVD.js.map +1 -0
  21. package/dist/chunk-3RY6WL5T.js +38 -0
  22. package/dist/chunk-3RY6WL5T.js.map +1 -0
  23. package/dist/chunk-4LJSC7MB.js +143 -0
  24. package/dist/chunk-4LJSC7MB.js.map +1 -0
  25. package/dist/{chunk-3FI7Y4R4.js → chunk-7BO7HNGF.js} +5 -5
  26. package/dist/{chunk-3FI7Y4R4.js.map → chunk-7BO7HNGF.js.map} +1 -1
  27. package/dist/chunk-AWQG7FCC.js +19 -0
  28. package/dist/chunk-AWQG7FCC.js.map +1 -0
  29. package/dist/chunk-CZZPXUOU.js +3 -0
  30. package/dist/{chunk-SBXNQW4G.js.map → chunk-CZZPXUOU.js.map} +1 -1
  31. package/dist/{chunk-ZORVNOKX.js → chunk-FMK7UQ6V.js} +24 -145
  32. package/dist/chunk-FMK7UQ6V.js.map +1 -0
  33. package/dist/{chunk-BVL7Y574.js → chunk-FZ7YFQN7.js} +26 -10
  34. package/dist/chunk-FZ7YFQN7.js.map +1 -0
  35. package/dist/{chunk-USO6TERP.js → chunk-GOZLNM4L.js} +11 -9
  36. package/dist/chunk-GOZLNM4L.js.map +1 -0
  37. package/dist/{chunk-H5VIV7MQ.js → chunk-I5DUQ5HM.js} +88 -82
  38. package/dist/chunk-I5DUQ5HM.js.map +1 -0
  39. package/dist/chunk-J7OWWTCW.js +143 -0
  40. package/dist/chunk-J7OWWTCW.js.map +1 -0
  41. package/dist/{chunk-H6ZAOWNE.js → chunk-JVBYV6TL.js} +3 -3
  42. package/dist/{chunk-H6ZAOWNE.js.map → chunk-JVBYV6TL.js.map} +1 -1
  43. package/dist/{chunk-VQ47KWD5.js → chunk-KMJ7RWD3.js} +18 -7
  44. package/dist/chunk-KMJ7RWD3.js.map +1 -0
  45. package/dist/{chunk-ERFMC6WU.js → chunk-M7HP3FTK.js} +20 -11
  46. package/dist/chunk-M7HP3FTK.js.map +1 -0
  47. package/dist/chunk-MIM5R4ZT.js +14972 -0
  48. package/dist/chunk-MIM5R4ZT.js.map +1 -0
  49. package/dist/{chunk-HFRE4QQV.js → chunk-T5IBSPAM.js} +96 -32
  50. package/dist/chunk-T5IBSPAM.js.map +1 -0
  51. package/dist/chunk-UNAZSLWE.js +294 -0
  52. package/dist/chunk-UNAZSLWE.js.map +1 -0
  53. package/dist/{chunk-RS3HRQWU.js → chunk-WPLAANH4.js} +4 -3
  54. package/dist/chunk-WPLAANH4.js.map +1 -0
  55. package/dist/{chunk-AWH3SRPW.js → chunk-Y23G2VZL.js} +5 -37
  56. package/dist/chunk-Y23G2VZL.js.map +1 -0
  57. package/dist/{chunk-MOLIUNVH.js → chunk-YT75VYRD.js} +4 -4
  58. package/dist/{chunk-MOLIUNVH.js.map → chunk-YT75VYRD.js.map} +1 -1
  59. package/dist/chunk-ZIFPHIWZ.js +302 -0
  60. package/dist/chunk-ZIFPHIWZ.js.map +1 -0
  61. package/dist/config/index.d.ts +48 -40
  62. package/dist/config/index.js +4 -5
  63. package/dist/controls/index.d.ts +91 -7
  64. package/dist/controls/index.js +5 -4
  65. package/dist/dragdrop/index.d.ts +9 -7
  66. package/dist/dragdrop/index.js +3 -2
  67. package/dist/index.d.ts +294 -82
  68. package/dist/index.js +425 -402
  69. package/dist/index.js.map +1 -1
  70. package/dist/layers/index.d.ts +4 -5
  71. package/dist/layers/index.js +2 -1
  72. package/dist/loupe/index.d.ts +20 -17
  73. package/dist/loupe/index.js +5 -3
  74. package/dist/overview/index.d.ts +56 -0
  75. package/dist/overview/index.js +289 -0
  76. package/dist/overview/index.js.map +1 -0
  77. package/dist/passthrough/weasel-ui.d.ts +239 -69
  78. package/dist/passthrough/weasel-ui.js +3 -2
  79. package/dist/primitives/index.d.ts +5 -204
  80. package/dist/primitives/index.js +6 -4
  81. package/dist/state/index.d.ts +8 -8
  82. package/dist/state/index.js +4 -5
  83. package/dist/state/index.js.map +1 -1
  84. package/dist/styles.css +152 -82
  85. package/dist/undo/index.d.ts +4 -4
  86. package/package.json +17 -12
  87. package/src/annotations/AnnotationOverlay.tsx +2 -2
  88. package/src/annotations/Annotations.less +0 -10
  89. package/src/annotations/MarkList.tsx +4 -8
  90. package/src/annotations/index.ts +1 -0
  91. package/src/annotations/paint.test.ts +3 -14
  92. package/src/annotations/paint.ts +3 -19
  93. package/src/annotations/store.test.ts +26 -0
  94. package/src/annotations/store.ts +25 -6
  95. package/src/annotations/svgNodes.test.ts +6 -9
  96. package/src/annotations/svgNodes.ts +3 -3
  97. package/src/annotations/toolMap.test.ts +37 -2
  98. package/src/annotations/toolMap.ts +13 -0
  99. package/src/annotations/types.ts +27 -0
  100. package/src/canvas/AGENTS.md +9 -10
  101. package/src/canvas/CameraInput.test.tsx +136 -0
  102. package/src/canvas/CameraInput.tsx +322 -0
  103. package/src/canvas/CanvasStack.tsx +47 -58
  104. package/src/canvas/LinkedCursor.less +16 -0
  105. package/src/canvas/LinkedCursor.tsx +54 -0
  106. package/src/canvas/Stage.test.tsx +33 -4
  107. package/src/canvas/Stage.tsx +47 -37
  108. package/src/canvas/cameraRegistry.test.ts +55 -0
  109. package/src/canvas/cameraRegistry.ts +86 -0
  110. package/src/canvas/cameraView.test.ts +60 -0
  111. package/src/canvas/cameraView.ts +61 -0
  112. package/src/canvas/cameraZoom.test.ts +46 -0
  113. package/src/canvas/cameraZoom.ts +24 -0
  114. package/src/canvas/index.ts +23 -2
  115. package/src/canvas/sharedScope.test.tsx +94 -0
  116. package/src/chrome/ChromeRegions.stories.tsx +1 -0
  117. package/src/chrome/regions/PaletteRegion.less +0 -7
  118. package/src/chrome/regions/SidebarRegion.less +12 -2
  119. package/src/chrome/regions/SidebarRegion.test.tsx +9 -2
  120. package/src/config/builder.test.ts +2 -1
  121. package/src/config/builder.ts +15 -8
  122. package/src/config/entry.test.ts +3 -1
  123. package/src/config/fromConfigField.test.ts +14 -0
  124. package/src/config/fromConfigField.ts +19 -4
  125. package/src/config/index.ts +4 -1
  126. package/src/config/path.ts +2 -5
  127. package/src/config/resolve.ts +15 -1
  128. package/src/config/sectionTree.test.ts +12 -6
  129. package/src/config/sectionTree.ts +15 -5
  130. package/src/config/types.ts +34 -9
  131. package/src/controls/ControlPanel.less +1 -1
  132. package/src/controls/ControlPanel.stories.tsx +3 -2
  133. package/src/controls/ControlPanel.test.tsx +76 -13
  134. package/src/controls/ControlPanel.tsx +80 -11
  135. package/src/controls/inDialog.test.tsx +18 -0
  136. package/src/controls/inDialog.tsx +2 -10
  137. package/src/index.test.ts +1 -1
  138. package/src/index.ts +23 -5
  139. package/src/instrument/SineWave.smoke.test.tsx +2 -0
  140. package/src/instrument/types.ts +10 -1
  141. package/src/lab/Lab.nebula.test.tsx +11 -2
  142. package/src/lab/Lab.test.tsx +3 -1
  143. package/src/lab/Lab.tsx +87 -76
  144. package/src/lab/{LabFit.stories.less → LabFit.browser.test.less} +1 -1
  145. package/src/lab/{LabFit.stories.tsx → LabFit.browser.test.tsx} +41 -63
  146. package/src/lab/LabFullChrome.stories.tsx +1 -0
  147. package/src/lab/LabHeader.test.tsx +24 -14
  148. package/src/lab/LabHeader.tsx +11 -12
  149. package/src/lab/LabShell.less +8 -17
  150. package/src/lab/LabSwitcher.less +6 -6
  151. package/src/lab/LabZoom.test.tsx +223 -0
  152. package/src/lab/LabZoom.tsx +170 -0
  153. package/src/lab/index.ts +1 -0
  154. package/src/loupe/AGENTS.md +7 -6
  155. package/src/loupe/LoupeGestures.tsx +15 -10
  156. package/src/loupe/TrialLoupe.tsx +5 -5
  157. package/src/loupe/index.ts +1 -0
  158. package/src/loupe/loupeActions.ts +6 -2
  159. package/src/overview/AGENTS.md +38 -0
  160. package/src/overview/OverviewMarks.test.tsx +100 -0
  161. package/src/overview/OverviewMarks.tsx +93 -0
  162. package/src/overview/TrialOverview.less +53 -0
  163. package/src/overview/TrialOverview.stories.tsx +50 -0
  164. package/src/overview/TrialOverview.test.tsx +116 -0
  165. package/src/overview/TrialOverview.tsx +376 -0
  166. package/src/overview/index.ts +2 -0
  167. package/src/passthrough/weasel-ui.test.ts +2 -0
  168. package/src/passthrough/weasel-ui.ts +23 -4
  169. package/src/primitives/FloatingPanel.test.tsx +11 -0
  170. package/src/primitives/FloatingPanel.tsx +2 -5
  171. package/src/primitives/JobProgress.less +1 -1
  172. package/src/primitives/Legend.stories.tsx +1 -0
  173. package/src/primitives/Readout.browser.test.tsx +137 -0
  174. package/src/primitives/Readout.less +12 -0
  175. package/src/primitives/Readout.stories.tsx +58 -0
  176. package/src/primitives/Readout.test.tsx +93 -0
  177. package/src/primitives/Readout.tsx +56 -0
  178. package/src/primitives/index.ts +2 -0
  179. package/src/specimen/Specimen.stories.tsx +1 -0
  180. package/src/specimen/Specimen.tsx +21 -4
  181. package/src/state/Persistence.browser.test.tsx +47 -0
  182. package/src/state/labRecords.test.ts +4 -1
  183. package/src/state/store.test.ts +9 -5
  184. package/src/state/usePersistedState.test.tsx +1 -1
  185. package/src/state/useTrialState.test.tsx +1 -1
  186. package/src/styles.less +3 -0
  187. package/src/theme/Interstellar.stories.tsx +4 -6
  188. package/src/theme/base.less +21 -47
  189. package/src/theme/interstellar.test.ts +1 -1
  190. package/src/theme/interstellar.theme.json +10 -3
  191. package/src/tools/labTool.ts +6 -2
  192. package/src/trial/Trial.annotations.test.tsx +16 -0
  193. package/src/trial/Trial.less +0 -13
  194. package/src/trial/Trial.loupe.test.tsx +73 -1
  195. package/src/trial/Trial.stories.tsx +2 -0
  196. package/src/trial/Trial.tsx +23 -1
  197. package/src/trial/TrialChrome.tsx +21 -3
  198. package/src/trial/trialOps.test.ts +4 -4
  199. package/dist/_dts/PrefsRow.d-DFpPIeIC.d.ts +0 -39
  200. package/dist/_dts/inDialog-D5ZKGjiD.d.ts +0 -23
  201. package/dist/_dts/index-DINmCuLA.d.ts +0 -453
  202. package/dist/_dts/number.d-OeQYQoUO.d.ts +0 -28
  203. package/dist/_dts/usePanZoom-Bq73pwFe.d.ts +0 -117
  204. package/dist/chunk-2AYGEN57.js +0 -32
  205. package/dist/chunk-2AYGEN57.js.map +0 -1
  206. package/dist/chunk-AWH3SRPW.js.map +0 -1
  207. package/dist/chunk-BVL7Y574.js.map +0 -1
  208. package/dist/chunk-ERFMC6WU.js.map +0 -1
  209. package/dist/chunk-H5VIV7MQ.js.map +0 -1
  210. package/dist/chunk-HFRE4QQV.js.map +0 -1
  211. package/dist/chunk-RS3HRQWU.js.map +0 -1
  212. package/dist/chunk-SBXNQW4G.js +0 -3
  213. package/dist/chunk-TT5C5S6R.js +0 -368
  214. package/dist/chunk-TT5C5S6R.js.map +0 -1
  215. package/dist/chunk-USO6TERP.js.map +0 -1
  216. package/dist/chunk-VQ47KWD5.js.map +0 -1
  217. package/dist/chunk-WUJXJC5O.js +0 -14568
  218. package/dist/chunk-WUJXJC5O.js.map +0 -1
  219. package/dist/chunk-ZORVNOKX.js.map +0 -1
  220. package/src/canvas/usePanZoom.test.ts +0 -244
  221. package/src/canvas/usePanZoom.ts +0 -147
  222. package/src/state/Persistence.stories.tsx +0 -75
package/dist/index.js CHANGED
@@ -1,49 +1,59 @@
1
- import { resolveLoupe, TrialLoupe } from './chunk-ERFMC6WU.js';
2
- export { CanvasLoupe, DomLoupe, LOUPE_DEFAULTS, LOUPE_MAGNIFY_ID, LOUPE_PEEK_ID, LoupeBubble, LoupeGestures, TrialLoupe, createLoupeActions, drawCanvasLens, lensCamera, lensSourceRect, resolveLoupe, sampleStack, useLoupe } from './chunk-ERFMC6WU.js';
1
+ import { resolveLoupe, TrialLoupe } from './chunk-M7HP3FTK.js';
2
+ export { CanvasLoupe, DomLoupe, LOUPE_DEFAULTS, LOUPE_MAGNIFY_ID, LOUPE_PEEK_ID, LoupeBubble, LoupeGestures, TrialLoupe, createLoupeActions, drawCanvasLens, lensCamera, lensSourceRect, resolveLoupe, sampleStack, useLoupe } from './chunk-M7HP3FTK.js';
3
3
  import { createEventBus, pushSnapshot, redo, undo } from './chunk-RL2LOLNI.js';
4
4
  export { clearUndo, createEventBus, emptyStack, pushSnapshot, redo, undo } from './chunk-RL2LOLNI.js';
5
- import { useDragDrop, DragOverlay, Palette } from './chunk-RS3HRQWU.js';
5
+ import { useDragDrop, DragOverlay, Palette } from './chunk-WPLAANH4.js';
6
6
  import { useTiledSurface } from './chunk-IJJUK4FU.js';
7
7
  export { composeRects, rectsEqual, toDeviceRect, useTiledSurface } from './chunk-IJJUK4FU.js';
8
8
  import { useJob } from './chunk-HXXTULDN.js';
9
9
  export { useJob } from './chunk-HXXTULDN.js';
10
- import { suppressContributions, mergeContributions, builtinContributions, TitleBarRegion, ToolbarRegion, PaletteRegion, ViewportRegion, SidebarRegion, StatusRegion, resolveLabTool, AnnotationsContext, useLabChromeContext, labContributions, LabHeaderRegion, LabFooterRegion, LabAsideRegion, LabSidebarRegion } from './chunk-H5VIV7MQ.js';
11
- export { AnnotationsContext, ExportMenu, LabAsideRegion, LabFooterRegion, LabHeaderRegion, LabSidebarRegion, MarkList, PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, builtinContributions, contributionsIn, labContributions, mergeContributions, suppressContributions, toolContributions, useAnnotations, useAnnotationsOptional, useLabChromeContext } from './chunk-H5VIV7MQ.js';
12
- import { Split, JobProgress, Legend, FloatingPanel } from './chunk-ZORVNOKX.js';
13
- export { FloatingPanel, JobProgress, Legend, Split } from './chunk-ZORVNOKX.js';
14
- import { Toolbar, StatusBar, ScaleIndicator, ZoomControl } from './chunk-3FI7Y4R4.js';
15
- export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl } from './chunk-3FI7Y4R4.js';
16
- import './chunk-SBXNQW4G.js';
17
- import { unruledConfigSchema, createLabStore, openLabStore, panelKey } from './chunk-MOLIUNVH.js';
18
- export { CURRENT_DOCUMENT_VERSION, dockPanel, labDocumentKey, openLabStore, panelKey, quarantineKey, undockPanel, useTrialState } from './chunk-MOLIUNVH.js';
10
+ import { markCommands, markSvgNodes } from './chunk-4LJSC7MB.js';
11
+ export { markCommands, markSvgNodes } from './chunk-4LJSC7MB.js';
12
+ import { ANNOTATION_WEASEL_TOOLS, annotationToolInfo, suppressContributions, mergeContributions, builtinContributions, TitleBarRegion, ToolbarRegion, PaletteRegion, ViewportRegion, SidebarRegion, StatusRegion, resolveLabTool, useLabChromeContext, labContributions, labAnnotationTools, LabHeaderRegion, LabFooterRegion, LabAsideRegion, LabSidebarRegion } from './chunk-I5DUQ5HM.js';
13
+ export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, ExportMenu, LabAsideRegion, LabFooterRegion, LabHeaderRegion, LabSidebarRegion, MarkList, PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, annotationToolInfo, builtinContributions, contributionsIn, labContributions, mergeContributions, suppressContributions, toolContributions, useLabChromeContext } from './chunk-I5DUQ5HM.js';
14
+ import { AnnotationsContext } from './chunk-3RY6WL5T.js';
15
+ export { AnnotationsContext, useAnnotations, useAnnotationsOptional } from './chunk-3RY6WL5T.js';
16
+ import { Split, JobProgress, Legend } from './chunk-FMK7UQ6V.js';
17
+ export { JobProgress, Legend, Readout, Split } from './chunk-FMK7UQ6V.js';
18
+ import { FloatingPanel } from './chunk-J7OWWTCW.js';
19
+ export { FloatingPanel } from './chunk-J7OWWTCW.js';
20
+ import { Toolbar, StatusBar, ScaleIndicator, ZoomControl } from './chunk-7BO7HNGF.js';
21
+ export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl } from './chunk-7BO7HNGF.js';
22
+ import './chunk-CZZPXUOU.js';
23
+ import { unruledConfigSchema, createLabStore, openLabStore, panelKey } from './chunk-YT75VYRD.js';
24
+ export { CURRENT_DOCUMENT_VERSION, dockPanel, labDocumentKey, openLabStore, panelKey, quarantineKey, undockPanel, useTrialState } from './chunk-YT75VYRD.js';
19
25
  import { newId, useWarnIgnoredChange, useOpenOnce, PersistenceContext, createRecordCache, noneAdapter, defaultStorage, usePersistedState } from './chunk-RWNDDKOH.js';
20
26
  export { Persistence, createIndexedDbAdapter, createMemoryAdapter, indexedDbAdapter, localStorageAdapter, noneAdapter, sessionStorageAdapter, urlHashAdapter, usePersistedState } from './chunk-RWNDDKOH.js';
21
- export { ControlPanel } from './chunk-HFRE4QQV.js';
22
- import { useConfigSchema } from './chunk-USO6TERP.js';
23
- export { sectionTree, useConfigSchema } from './chunk-USO6TERP.js';
27
+ export { ControlPanel, inDialog, summarizeValue } from './chunk-T5IBSPAM.js';
28
+ import { useConfigSchema } from './chunk-GOZLNM4L.js';
29
+ export { sectionTree, useConfigSchema } from './chunk-GOZLNM4L.js';
24
30
  import { useLabContext, LabContext } from './chunk-Z76KEZAX.js';
25
31
  export { LabContext, useLabContext } from './chunk-Z76KEZAX.js';
26
- import { useResolvedConfig } from './chunk-BVL7Y574.js';
27
- export { BaseNode, BooleanNode, ColorNode, CustomNode, EnumNode, GroupNode, ListNode, NumberNode, StringNode, ValueNode, applyRules, builtinRules, f, isConfigBranch, resolveConfigSchema, titleCase, useResolvedConfig } from './chunk-BVL7Y574.js';
28
- export { fromConfigFields, isLeafVisible } from './chunk-VQ47KWD5.js';
29
- import { hasConfigPath, schemaNodeAtPath, applyConfigWrite, resolveAutoConfig, isAuto, isRecord, autoPathsOf, fillConfigDefaults } from './chunk-AWH3SRPW.js';
30
- export { auto, autoPathsOf, fillConfigDefaults, hasConfigPath, inDialog, isAuto, resolveAutoConfig, schemaNodeAtPath, summarizeValue, valueAtPath, withValueAtPath } from './chunk-AWH3SRPW.js';
31
- import { CameraWheelContext, as2DView, DEFAULT_VIEW, CanvasStack, Stage, withZoom, fitStage } from './chunk-TT5C5S6R.js';
32
- export { CanvasStack, DEFAULT_VIEW, Stage, as2DView, fitStage, usePanZoom } from './chunk-TT5C5S6R.js';
33
- export { centerOn, zoomAt } from './chunk-H6ZAOWNE.js';
34
- import { applyCamera } from './chunk-2AYGEN57.js';
35
- export { DEFAULT_FRAME, applyCamera, resolveFrame, screenToWorld, worldToScreen } from './chunk-2AYGEN57.js';
32
+ import { useResolvedConfig } from './chunk-FZ7YFQN7.js';
33
+ export { BaseNode, BooleanNode, ColorNode, CustomNode, EnumNode, GroupNode, ListNode, NumberNode, StringNode, ValueNode, applyRules, builtinRules, f, isConfigBranch, resolveConfigSchema, titleCase, useResolvedConfig } from './chunk-FZ7YFQN7.js';
34
+ export { fromConfigFields, isLeafVisible } from './chunk-KMJ7RWD3.js';
35
+ import { hasConfigPath, schemaNodeAtPath, applyConfigWrite, resolveAutoConfig, isAuto, isRecord, autoPathsOf, fillConfigDefaults } from './chunk-Y23G2VZL.js';
36
+ export { auto, autoPathsOf, fillConfigDefaults, hasConfigPath, isAuto, resolveAutoConfig, schemaNodeAtPath, valueAtPath, withValueAtPath } from './chunk-Y23G2VZL.js';
37
+ import { CanvasStack, Stage, fitStage } from './chunk-ZIFPHIWZ.js';
38
+ export { CanvasStack, Stage, fitStage } from './chunk-ZIFPHIWZ.js';
39
+ export { centerOn, zoomAt } from './chunk-JVBYV6TL.js';
40
+ export { screenToWorld, worldToScreen } from './chunk-AWQG7FCC.js';
36
41
  import { useSurfaceOptional, useSurfaceCanvas, useTileId, SurfaceContext, SurfaceCanvasContext } from './chunk-WIG6XHJ7.js';
37
42
  export { SurfaceCanvasContext, SurfaceContext, useSurface, useSurfaceCanvas, useSurfaceOptional, useSurfaceTile, useTileId } from './chunk-WIG6XHJ7.js';
43
+ import { CameraWheelContext, as2DView, CameraRegistryContext, DEFAULT_VIEW, CameraPublishContext, createCameraRegistry, withZoom } from './chunk-UNAZSLWE.js';
44
+ export { CameraContext, CameraInput, CameraPublishContext, CameraRegistryContext, CameraScope, DEFAULT_VIEW, as2DView, createCameraRegistry, usePublishCamera } from './chunk-UNAZSLWE.js';
45
+ import { applyCamera } from './chunk-24W5VEJW.js';
46
+ export { DEFAULT_FRAME, applyCamera, resolveFrame } from './chunk-24W5VEJW.js';
38
47
  import { CanvasStackContext } from './chunk-CQLQPQ4P.js';
39
48
  export { CanvasStackContext } from './chunk-CQLQPQ4P.js';
40
49
  import { LabStoreContext, TrialIdProvider, TrialIdContext } from './chunk-2YILQ7Y5.js';
41
50
  export { LabStoreContext, LabStoreProvider, TrialIdContext, TrialIdProvider, useLabStore, useTrialId } from './chunk-2YILQ7Y5.js';
42
51
  import './chunk-2RVCB2PT.js';
43
- import { y, I, A, T, i2, P, m, H, serializeSvg, D, S2, oe, d2, s3, c, Ht, o2, a6, l5, u5, a5, r3, a7, i3, o4, s6, c5, l7, p, f2, u4, g, T2, y2, l8, b, c6, i4, l4, C, S, ae, oe2, B, b2, A2, n6, s5, m4, l2, u, g2, u3, S4, r4, n7, r5, i5, p2, f, n8, o3, c3, c4, w, L, n9, k, $2 } from './chunk-WUJXJC5O.js';
44
- export { c as Button, re as CloseIcon, Pe as CollapseIcon, _ as CurveField, Fe as ExpandIcon, l as Icon, u4 as Input, l9 as Jog, D as LayerList, ge as PauseIcon, he as PlayIcon, V as PropertyControl, B as PropertyField, b2 as PropertyGroup, oe2 as PropertyList, ae as PropertyPanel, L3 as PropertyRow, se as PropertySpan, Z as ResetIcon, T2 as Select, ve as StepBackIcon, $ as StepForwardIcon, _e as StopIcon, x as Subpanel, a5 as ToggleBar, oe3 as TokenPanel, H2 as inferTokenType, S2 as moveLayers, O as refitScale } from './chunk-WUJXJC5O.js';
45
- import { textCommand, ellipsePath, linePath, markerDrawCommands, rectPath, createScene, asNodeId as asNodeId$1, WeaselProvider, SceneCanvas, sceneFromJSON, PathBuilder, renderSceneToPixels, useActiveToolContext } from '@weasel-js/core';
46
- import { createContext, useState, useRef, useEffect, useCallback, useContext, useMemo, useId, Children, useLayoutEffect, useSyncExternalStore } from 'react';
52
+ import { E3, x3, X, U, G, d3, o3, c, Xt, o5, a8, l4, u4, a7, r3, a10, i2, o6, s4, c6, l6, p, f2, u3, y, E2, y2, l7, S, c7, i4, f3, D, T, re2, ie2, R, b2, j, n6, a11, m3, l2, u, _2, d2, S3, r4, n7, r5, i5, p2, f, n8, o4, c4, c5, w, L, n9, j2, ye, n2 } from './chunk-MIM5R4ZT.js';
53
+ export { c as Button, V as CloseIcon, xe as CollapseIcon, _ as CurveField, i3 as DetailList, a4 as DetailRow, Se as ExpandIcon, l as Icon, u3 as Input, l8 as Jog, E3 as LayerList, re as PauseIcon, ne as PlayIcon, z2 as PropertyControl, R as PropertyField, b2 as PropertyGroup, ie2 as PropertyList, re2 as PropertyPanel, I as PropertyRow, ae2 as PropertySpan, B as ResetIcon, E2 as Select, ae as StepBackIcon, $ as StepForwardIcon, ie as StopIcon, x2 as Subpanel, a7 as ToggleBar, oe as TokenPanel, H2 as inferTokenType, x3 as moveLayers, O2 as refitScale } from './chunk-MIM5R4ZT.js';
54
+ import { serializeSvg } from './chunk-275JRRVD.js';
55
+ import { makeViewportZoomAction, createScene, asNodeId as asNodeId$1, WeaselProvider, SceneCanvas, createPointerStore, PointerContextProvider, DepRegistryProvider, ActionsProvider, ActiveToolContextProvider, useActionsRegistry, useDepSource, ActionDisabledReason, useGestureDispatcher, sceneFromJSON, renderSceneToPixels, useActiveToolContext } from '@weasel-js/core';
56
+ import { createContext, useState, useRef, useEffect, useCallback, useContext, useMemo, useSyncExternalStore, useId, Children, useLayoutEffect } from 'react';
47
57
  import { flushSync, createPortal } from 'react-dom';
48
58
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
49
59
  import { defineTheme, weaselTheme, colorCount, resolveTheme, colorAt } from '@weasel-js/theme';
@@ -53,101 +63,13 @@ import { Provider, StrategyRegistryProvider, DragProvider, Container, useDragHan
53
63
  import { asNodeId, Store, createNode, floatingStrategy, gridStrategy } from 'windease';
54
64
  import { Focusable } from 'react-aria-components';
55
65
 
56
- var MARK_COLOR = "#e5484d";
57
- var MARK_WIDTH = 2;
58
- var TEXT_SIZE = 14;
59
- var POINT_RADIUS = 4;
60
- var toWorld = (p3, content) => ({
61
- x: p3.x * content.w,
62
- y: p3.y * content.h
63
- });
64
- function vertices(m3, content) {
65
- const stored = m3.data.points;
66
- if (stored && stored.length >= 2) return stored.map((p3) => toWorld(p3, content));
67
- const { x: x2, y: y3, width, height } = m3.pose;
68
- return [
69
- { x: x2, y: y3 },
70
- { x: x2 + width, y: y3 + height }
71
- ];
72
- }
73
- function polyline(points) {
74
- const b3 = new PathBuilder();
75
- const first = points[0];
76
- if (!first) return rectPath(0, 0, 0, 0);
77
- b3.moveTo(first.x, first.y);
78
- for (const p3 of points.slice(1)) b3.lineTo(p3.x, p3.y);
79
- return b3.build();
80
- }
81
- function markCommands(m3, content, style = {}) {
82
- const color = style.color ?? MARK_COLOR;
83
- const stroke = {
84
- paint: { color },
85
- width: MARK_WIDTH,
86
- cap: "round",
87
- join: "round",
88
- ...style.stale ? { dash: [6, 4] } : {}
89
- };
90
- switch (m3.data.kind) {
91
- case "rect":
92
- return [
93
- { kind: "path", path: rectPath(m3.pose.x, m3.pose.y, m3.pose.width, m3.pose.height), stroke }
94
- ];
95
- case "ellipse":
96
- return [{ kind: "path", path: ellipsePath(m3.pose), stroke }];
97
- case "line": {
98
- const [a4, b3] = vertices(m3, content);
99
- return [{ kind: "path", path: linePath(a4, b3), stroke }];
100
- }
101
- case "arrow": {
102
- const [a4, b3] = vertices(m3, content);
103
- const marked = { ...stroke, markerEnd: "arrow" };
104
- const path = linePath(a4, b3);
105
- return [
106
- { kind: "path", path, stroke: marked },
107
- ...markerDrawCommands(path, marked, MARK_WIDTH, void 0)
108
- ];
109
- }
110
- case "stroke":
111
- return [{ kind: "path", path: polyline(vertices(m3, content)), stroke }];
112
- case "point": {
113
- const stored = m3.data.points?.[0];
114
- const c6 = stored ? toWorld(stored, content) : { x: m3.pose.x, y: m3.pose.y };
115
- const ring = {
116
- x: c6.x - POINT_RADIUS,
117
- y: c6.y - POINT_RADIUS,
118
- width: 2 * POINT_RADIUS,
119
- height: 2 * POINT_RADIUS
120
- };
121
- return [{ kind: "path", path: ellipsePath(ring), stroke }];
122
- }
123
- case "text": {
124
- const text = m3.data.title;
125
- if (!text) return [];
126
- return [
127
- textCommand(
128
- m3.pose.x,
129
- m3.pose.y,
130
- text,
131
- { fontSize: TEXT_SIZE },
132
- void 0,
133
- void 0,
134
- void 0,
135
- {
136
- fill: { color }
137
- }
138
- )
139
- ];
140
- }
141
- }
142
- }
143
-
144
66
  // src/annotations/staleness.ts
145
67
  function seenFrom(config, keys) {
146
68
  const out = {};
147
69
  if (config === null || typeof config !== "object") return out;
148
70
  const src = config;
149
- for (const k2 of keys) {
150
- if (k2 in src) out[k2] = src[k2];
71
+ for (const k of keys) {
72
+ if (k in src) out[k] = src[k];
151
73
  }
152
74
  return out;
153
75
  }
@@ -155,9 +77,9 @@ function isStale(seen, config, keys) {
155
77
  if (!seen || keys.length === 0) return false;
156
78
  if (config === null || typeof config !== "object") return false;
157
79
  const src = config;
158
- for (const k2 of keys) {
159
- if (!(k2 in seen)) continue;
160
- if (!Object.is(seen[k2], src[k2])) return true;
80
+ for (const k of keys) {
81
+ if (!(k in seen)) continue;
82
+ if (!Object.is(seen[k], src[k])) return true;
161
83
  }
162
84
  return false;
163
85
  }
@@ -168,64 +90,13 @@ function createMarkDrawOne(opts) {
168
90
  }
169
91
  function resolveMarkStyle(data, opts) {
170
92
  return {
171
- color: opts.meaning?.statuses?.find((s4) => s4.id === data.status)?.color,
93
+ color: opts.meaning?.statuses?.find((s2) => s2.id === data.status)?.color,
172
94
  // Read off the node rather than through the store's `isStale`, which
173
95
  // wants a projected Annotation this path does not have.
174
96
  stale: isStale(data.seen, opts.config, opts.positionDependsOn ?? [])
175
97
  };
176
98
  }
177
99
 
178
- // src/annotations/svgNodes.ts
179
- var NO_PAINT = { kind: "none" };
180
- function toSvgPaint(paint) {
181
- if (!paint) return NO_PAINT;
182
- if ("color" in paint && typeof paint.color === "string") {
183
- return {
184
- kind: "solid",
185
- color: paint.color,
186
- ...paint.opacity != null ? { opacity: paint.opacity } : {}
187
- };
188
- }
189
- return { kind: "gradient", paint };
190
- }
191
- function toSvgStroke(stroke) {
192
- return {
193
- paint: toSvgPaint(stroke.paint),
194
- width: stroke.width ?? 1,
195
- ...stroke.cap ? { cap: stroke.cap } : {},
196
- ...stroke.join ? { join: stroke.join } : {},
197
- ...stroke.dash ? { dash: [...stroke.dash] } : {},
198
- ...stroke.miterLimit != null ? { miterLimit: stroke.miterLimit } : {},
199
- ...stroke.align ? { align: stroke.align } : {}
200
- };
201
- }
202
- function toSvgNode(cmd, m3) {
203
- if (cmd.kind === "path") {
204
- return {
205
- kind: "path",
206
- path: cmd.path,
207
- fill: toSvgPaint(cmd.fill),
208
- ...cmd.stroke ? { stroke: toSvgStroke(cmd.stroke) } : {}
209
- };
210
- }
211
- if (cmd.kind === "text") {
212
- return {
213
- kind: "text",
214
- x: cmd.x,
215
- y: cmd.y,
216
- width: m3.pose.width,
217
- height: m3.pose.height,
218
- text: cmd.runs.map((run) => run.text).join(""),
219
- style: cmd.style,
220
- ...cmd.runs[0]?.fill ? { fill: cmd.runs[0].fill } : {}
221
- };
222
- }
223
- throw new Error(`[labkit] a mark drew a '${cmd.kind}' command, which has no vector form`);
224
- }
225
- function markSvgNodes(m3, content, style = {}) {
226
- return markCommands(m3, content, style).map((cmd) => toSvgNode(cmd, m3));
227
- }
228
-
229
100
  // src/annotations/capture.ts
230
101
  var SVG_NS = "http://www.w3.org/2000/svg";
231
102
  function capturePlan(base, format) {
@@ -368,12 +239,12 @@ async function captureTarget(args, opts = {}) {
368
239
  }
369
240
 
370
241
  // src/annotations/frac.ts
371
- function fracToWorld(f4, content) {
242
+ function fracToWorld(f5, content) {
372
243
  return {
373
- x: f4.x * content.w,
374
- y: f4.y * content.h,
375
- width: f4.w * content.w,
376
- height: f4.h * content.h
244
+ x: f5.x * content.w,
245
+ y: f5.y * content.h,
246
+ width: f5.w * content.w,
247
+ height: f5.h * content.h
377
248
  };
378
249
  }
379
250
  function worldToFrac(r4, content) {
@@ -382,12 +253,12 @@ function worldToFrac(r4, content) {
382
253
  return { x: r4.x * sx, y: r4.y * sy, w: r4.width * sx, h: r4.height * sy };
383
254
  }
384
255
  var DP = 1e4;
385
- function roundFrac(f4) {
256
+ function roundFrac(f5) {
386
257
  return {
387
- x: Math.round(f4.x * DP) / DP,
388
- y: Math.round(f4.y * DP) / DP,
389
- w: Math.round(f4.w * DP) / DP,
390
- h: Math.round(f4.h * DP) / DP
258
+ x: Math.round(f5.x * DP) / DP,
259
+ y: Math.round(f5.y * DP) / DP,
260
+ w: Math.round(f5.w * DP) / DP,
261
+ h: Math.round(f5.h * DP) / DP
391
262
  };
392
263
  }
393
264
  function fracContains(box, pt, tol = 0) {
@@ -438,13 +309,13 @@ var MarkHistory = class {
438
309
  return null;
439
310
  }
440
311
  canUndo(at) {
441
- return this.next(this.undoable, (s4) => s4.canUndo(), at) !== null;
312
+ return this.next(this.undoable, (s2) => s2.canUndo(), at) !== null;
442
313
  }
443
314
  canRedo(at) {
444
- return this.next(this.redoable, (s4) => s4.canRedo(), at) !== null;
315
+ return this.next(this.redoable, (s2) => s2.canRedo(), at) !== null;
445
316
  }
446
317
  undo(at) {
447
- const target = this.next(this.undoable, (s4) => s4.canUndo(), at);
318
+ const target = this.next(this.undoable, (s2) => s2.canUndo(), at);
448
319
  const scene = target === null ? void 0 : at(target);
449
320
  if (!scene) return false;
450
321
  this.replaying = "undo";
@@ -455,7 +326,7 @@ var MarkHistory = class {
455
326
  }
456
327
  }
457
328
  redo(at) {
458
- const target = this.next(this.redoable, (s4) => s4.canRedo(), at);
329
+ const target = this.next(this.redoable, (s2) => s2.canRedo(), at);
459
330
  const scene = target === null ? void 0 : at(target);
460
331
  if (!scene) return false;
461
332
  this.replaying = "redo";
@@ -510,6 +381,12 @@ function createAnnotationStore(opts) {
510
381
  for (const target of Object.keys(restore ?? {})) sceneFor(target);
511
382
  const targetOf = (id) => targets().find((t) => t.id === id);
512
383
  const contentOf = (id) => targetOf(id)?.content ?? NO_CONTENT;
384
+ const drawOptionsFor = (info) => ({
385
+ content: info.content,
386
+ positionDependsOn: info.positionDependsOn,
387
+ config: opts.config?.(),
388
+ meaning: typeof opts.meaning === "function" ? opts.meaning() : opts.meaning
389
+ });
513
390
  const project = (target, node) => {
514
391
  const found = scenes.get(target)?.get(asNodeId$1(node));
515
392
  if (!found) return void 0;
@@ -530,21 +407,21 @@ function createAnnotationStore(opts) {
530
407
  if (!scene) return [];
531
408
  const out = [];
532
409
  for (const id of scene.renderOrder()) {
533
- const a4 = project(target, String(id));
534
- if (a4) out.push(a4);
410
+ const a6 = project(target, String(id));
411
+ if (a6) out.push(a6);
535
412
  }
536
413
  return out;
537
414
  };
538
415
  const all = () => liveTargets().flatMap(marksOn);
539
- const matches = (a4, q) => {
540
- if (q.target !== void 0 && a4.target !== q.target) return false;
541
- if (q.kind !== void 0 && a4.kind !== q.kind) return false;
542
- if (q.status !== void 0 && a4.status !== q.status) return false;
416
+ const matches = (a6, q) => {
417
+ if (q.target !== void 0 && a6.target !== q.target) return false;
418
+ if (q.kind !== void 0 && a6.kind !== q.kind) return false;
419
+ if (q.status !== void 0 && a6.status !== q.status) return false;
543
420
  if (q.tags !== void 0) {
544
- const have = a4.tags ?? [];
421
+ const have = a6.tags ?? [];
545
422
  for (const t of q.tags) if (!have.includes(t)) return false;
546
423
  }
547
- if (q.where && !q.where(a4)) return false;
424
+ if (q.where && !q.where(a6)) return false;
548
425
  return true;
549
426
  };
550
427
  const nodeOf = (id) => {
@@ -562,17 +439,17 @@ function createAnnotationStore(opts) {
562
439
  return parts ? project(parts.target, parts.node) : void 0;
563
440
  },
564
441
  query(q) {
565
- return q ? all().filter((a4) => matches(a4, q)) : all();
442
+ return q ? all().filter((a6) => matches(a6, q)) : all();
566
443
  },
567
444
  hitTest(target, pt, tol = 0) {
568
- return marksOn(target).filter((a4) => fracContains(a4.frac, pt, tol)).reverse();
445
+ return marksOn(target).filter((a6) => fracContains(a6.frac, pt, tol)).reverse();
569
446
  },
570
447
  within(target, box) {
571
- return marksOn(target).filter((a4) => fracEncloses(box, a4.frac));
448
+ return marksOn(target).filter((a6) => fracEncloses(box, a6.frac));
572
449
  },
573
- isStale(a4, config) {
574
- const keys = targetOf(a4.target)?.positionDependsOn ?? [];
575
- return isStale(a4.seen, config, keys);
450
+ isStale(a6, config) {
451
+ const keys = targetOf(a6.target)?.positionDependsOn ?? [];
452
+ return isStale(a6.seen, config, keys);
576
453
  },
577
454
  canUndo() {
578
455
  return history.canUndo(historySceneAt);
@@ -610,7 +487,7 @@ function createAnnotationStore(opts) {
610
487
  for (const [target, scene] of scenes) {
611
488
  const next = wanted.get(target) ?? [];
612
489
  const now = scene.getSelection();
613
- if (now.length === next.length && next.every((n5, i5) => String(now[i5]) === n5)) continue;
490
+ if (now.length === next.length && next.every((n6, i5) => String(now[i5]) === n6)) continue;
614
491
  scene.setSelection(next.map(asNodeId$1));
615
492
  }
616
493
  },
@@ -661,6 +538,20 @@ function createAnnotationStore(opts) {
661
538
  const found = nodeOf(id);
662
539
  if (found) found.scene.remove(asNodeId$1(found.node.id));
663
540
  },
541
+ paintedMarks(target) {
542
+ const info = targetOf(target);
543
+ const scene = scenes.get(target);
544
+ if (!info || !scene) return [];
545
+ const draw = drawOptionsFor(info);
546
+ return [...scene.renderOrder()].flatMap((id) => {
547
+ const node = scene.get(asNodeId$1(String(id)));
548
+ if (!node) return [];
549
+ const data = node.data;
550
+ return [
551
+ { mark: { pose: node.pose, data }, style: resolveMarkStyle(data, draw) }
552
+ ];
553
+ });
554
+ },
664
555
  async capture(target, captureOpts) {
665
556
  const info = targetOf(target);
666
557
  if (!info) throw new Error(`[labkit] no annotation target called '${target}'`);
@@ -668,12 +559,7 @@ function createAnnotationStore(opts) {
668
559
  {
669
560
  target,
670
561
  scene: sceneFor(target),
671
- draw: {
672
- content: info.content,
673
- positionDependsOn: info.positionDependsOn,
674
- config: opts.config?.(),
675
- meaning: typeof opts.meaning === "function" ? opts.meaning() : opts.meaning
676
- },
562
+ draw: drawOptionsFor(info),
677
563
  base: info.base,
678
564
  onWarn: (message) => console.warn(`[labkit] capture: ${message}`)
679
565
  },
@@ -695,34 +581,6 @@ function annotationsFromJSON(raw, targets, rest = {}) {
695
581
  return createAnnotationStore({ targets, restore: doc.scenes, ...rest });
696
582
  }
697
583
 
698
- // src/annotations/toolMap.ts
699
- var TOOLS = {
700
- select: { weaselTool: "select" },
701
- stroke: { weaselTool: "pencil", kind: "stroke" },
702
- line: { weaselTool: "line", kind: "line" },
703
- arrow: { weaselTool: "line", kind: "arrow" },
704
- rect: { weaselTool: "rect", kind: "rect" },
705
- ellipse: { weaselTool: "ellipse", kind: "ellipse" },
706
- text: { weaselTool: "text", kind: "text" }
707
- };
708
- var ANNOTATION_TOOLS = [
709
- // Not in `TOOLS`: an id the map does not carry is what leaves the overlay idle.
710
- { id: "pointer", label: "Interact", icon: y, group: "annotate" },
711
- { id: "select", label: "Select", icon: I, group: "annotate" },
712
- { id: "stroke", label: "Freehand", icon: A, group: "annotate" },
713
- { id: "line", label: "Line", icon: T, group: "annotate" },
714
- { id: "arrow", label: "Arrow", icon: i2, group: "annotate" },
715
- { id: "rect", label: "Rectangle", icon: P, group: "annotate" },
716
- { id: "ellipse", label: "Ellipse", icon: m, group: "annotate" },
717
- { id: "text", label: "Text", icon: H, group: "annotate" }
718
- ];
719
- function annotationToolInfo(id) {
720
- return id === null ? void 0 : TOOLS[id];
721
- }
722
- var ANNOTATION_WEASEL_TOOLS = [
723
- ...new Set(Object.values(TOOLS).map((t) => t.weaselTool))
724
- ];
725
-
726
584
  // src/annotations/view.ts
727
585
  function toWeaselView(v) {
728
586
  return { x: v.pan.x, y: v.pan.y, scale: { x: v.zoom, y: v.zoom } };
@@ -734,7 +592,7 @@ function fitView(content, pane) {
734
592
  const zoom = content.w > 0 && content.h > 0 ? Math.min(pane.w / content.w, pane.h / content.h) : 1;
735
593
  return { zoom: Number.isFinite(zoom) && zoom > 0 ? zoom : 1, pan: { x: 0, y: 0 } };
736
594
  }
737
- var sameRect = (a4, b3) => a4 !== null && a4.x === b3.x && a4.y === b3.y && a4.w === b3.w && a4.h === b3.h;
595
+ var sameRect = (a6, b2) => a6 !== null && a6.x === b2.x && a6.y === b2.y && a6.w === b2.w && a6.h === b2.h;
738
596
  function ToolBridge({ toolId }) {
739
597
  const tools = useActiveToolContext();
740
598
  const setActive = tools.setActive;
@@ -873,13 +731,13 @@ function AnnotationOverlay({
873
731
  }
874
732
  ),
875
733
  canvas && input ? (
876
- // One scope per pane: a shared <ActionsProvider> lets only the newest
877
- // canvas under it respond to input, and the rest go silently dead.
734
+ // Isolated so each pane keeps its own selection and tool.
878
735
  /* @__PURE__ */ jsxs(WeaselProvider, { isolate: true, children: [
879
736
  /* @__PURE__ */ jsx(ToolBridge, { toolId: annotationToolInfo(activeToolId)?.weaselTool ?? "select" }),
880
737
  /* @__PURE__ */ jsx(
881
738
  SceneCanvas,
882
739
  {
740
+ features: ["pick", "move", "transform", "edit"],
883
741
  ref: attachSceneCanvas,
884
742
  scene,
885
743
  width: rect.w,
@@ -1063,21 +921,28 @@ var interstellar_theme_default = {
1063
921
  accent: {
1064
922
  by: "mode",
1065
923
  dark: {
1066
- value: "#b08adb",
924
+ value: "#4f46e5",
1067
925
  type: "color"
1068
926
  }
1069
927
  },
1070
928
  "accent-hover": {
1071
929
  by: "mode",
1072
930
  dark: {
1073
- value: "#c6a3ee",
931
+ value: "#6d5dfc",
932
+ type: "color"
933
+ }
934
+ },
935
+ "accent-strong": {
936
+ by: "mode",
937
+ dark: {
938
+ value: "#7474fe",
1074
939
  type: "color"
1075
940
  }
1076
941
  },
1077
942
  "focus-ring": {
1078
943
  by: "mode",
1079
944
  dark: {
1080
- value: "rgba(176, 138, 219, 0.45)",
945
+ value: "rgba(116, 116, 254, 0.5)",
1081
946
  type: "color"
1082
947
  }
1083
948
  },
@@ -1110,6 +975,24 @@ var interstellarTheme = defineTheme({
1110
975
  ...interstellar_theme_default,
1111
976
  extends: weaselTheme
1112
977
  });
978
+
979
+ // src/canvas/cameraZoom.ts
980
+ function atScale(view, scale, at) {
981
+ return {
982
+ x: view.x + at.x / view.scale.x - at.x / scale,
983
+ y: view.y + at.y / view.scale.y - at.y / scale,
984
+ scale: { x: scale, y: scale }
985
+ };
986
+ }
987
+ function viewMiddle(camera) {
988
+ const size = camera.hostSize?.();
989
+ return size ? { x: size.width / 2, y: size.height / 2 } : { x: 0, y: 0 };
990
+ }
991
+ function zoomCameraTo(camera, zoom) {
992
+ const { min, max } = camera.zoomRange();
993
+ const scale = Math.min(max, Math.max(min, zoom));
994
+ camera.set(atScale(camera.get(), scale, viewMiddle(camera)));
995
+ }
1113
996
  function TrialBody({ sidebar, children, contentClassName, ...rest }) {
1114
997
  return /* @__PURE__ */ jsx(
1115
998
  Split,
@@ -1211,6 +1094,7 @@ function UndockedSections({ trialId, sections, onDock }) {
1211
1094
  var NO_OP = () => {
1212
1095
  };
1213
1096
  var NO_SECTIONS = Object.freeze({});
1097
+ var noSubscribe = () => NO_OP;
1214
1098
  function TrialChrome({
1215
1099
  trialId,
1216
1100
  record,
@@ -1229,15 +1113,15 @@ function TrialChrome({
1229
1113
  const lab = useLabContext();
1230
1114
  const storeCtx = useContext(LabStoreContext);
1231
1115
  if (!storeCtx) throw new Error("[labkit] TrialChrome requires <LabStoreProvider>");
1232
- const updateTrialView = useStore(storeCtx.store, (s4) => s4.updateTrialView);
1233
- const updateTrialSidebarWidth = useStore(storeCtx.store, (s4) => s4.updateTrialSidebarWidth);
1234
- const setTrialTitle = useStore(storeCtx.store, (s4) => s4.setTrialTitle);
1235
- const setTrialSectionCollapsed = useStore(storeCtx.store, (s4) => s4.setTrialSectionCollapsed);
1236
- const updateTrialConfig = useStore(storeCtx.store, (s4) => s4.updateTrialConfig);
1237
- const updateTrialState = useStore(storeCtx.store, (s4) => s4.updateTrialState);
1238
- const undockPanelAction = useStore(storeCtx.store, (s4) => s4.undockPanel);
1239
- const dockPanelAction = useStore(storeCtx.store, (s4) => s4.dockPanel);
1240
- const undockedPanels = useStore(storeCtx.store, (s4) => s4.undockedPanels);
1116
+ const updateTrialView = useStore(storeCtx.store, (s2) => s2.updateTrialView);
1117
+ const updateTrialSidebarWidth = useStore(storeCtx.store, (s2) => s2.updateTrialSidebarWidth);
1118
+ const setTrialTitle = useStore(storeCtx.store, (s2) => s2.setTrialTitle);
1119
+ const setTrialSectionCollapsed = useStore(storeCtx.store, (s2) => s2.setTrialSectionCollapsed);
1120
+ const updateTrialConfig = useStore(storeCtx.store, (s2) => s2.updateTrialConfig);
1121
+ const updateTrialState = useStore(storeCtx.store, (s2) => s2.updateTrialState);
1122
+ const undockPanelAction = useStore(storeCtx.store, (s2) => s2.undockPanel);
1123
+ const dockPanelAction = useStore(storeCtx.store, (s2) => s2.dockPanel);
1124
+ const undockedPanels = useStore(storeCtx.store, (s2) => s2.undockedPanels);
1241
1125
  const undockedIds = useMemo(
1242
1126
  () => Object.values(undockedPanels).filter((p3) => p3.trialId === trialId).map((p3) => p3.sectionId),
1243
1127
  [undockedPanels, trialId]
@@ -1251,10 +1135,15 @@ function TrialChrome({
1251
1135
  );
1252
1136
  const title = record.title ?? instrument.title ?? instrument.name;
1253
1137
  const collapsedSections = record.collapsedSections ?? NO_SECTIONS;
1138
+ const cameras = useContext(CameraRegistryContext);
1139
+ const camera = useSyncExternalStore(
1140
+ cameras?.subscribe ?? noSubscribe,
1141
+ () => cameras?.get(trialId) ?? null
1142
+ );
1254
1143
  const ctx = useMemo(() => {
1255
- const setZoom = (z) => {
1256
- if (!view2d) return;
1257
- updateTrialView(trialId, withZoom(view2d, z));
1144
+ const setZoom = (z2) => {
1145
+ if (camera) zoomCameraTo(camera, z2);
1146
+ else if (view2d) updateTrialView(trialId, withZoom(view2d, z2));
1258
1147
  };
1259
1148
  return {
1260
1149
  trialId,
@@ -1294,7 +1183,7 @@ function TrialChrome({
1294
1183
  undockedPanels: undockedIds,
1295
1184
  undockPanel: (sectionId, as) => undockPanelAction(trialId, sectionId, as),
1296
1185
  dockPanel: (sectionId) => dockPanelAction(trialId, sectionId),
1297
- savedSnapshots: lab.savedSnapshots.filter((s4) => s4.trialId === trialId),
1186
+ savedSnapshots: lab.savedSnapshots.filter((s2) => s2.trialId === trialId),
1298
1187
  saveSnapshot: (name) => lab.saveSnapshot(trialId, name),
1299
1188
  loadSnapshot: (snapshotId) => lab.loadSnapshot(trialId, snapshotId),
1300
1189
  clone: () => lab.cloneTrial(trialId),
@@ -1326,7 +1215,8 @@ function TrialChrome({
1326
1215
  dockPanelAction,
1327
1216
  setTrialTitle,
1328
1217
  setTrialSectionCollapsed,
1329
- collapsedSections
1218
+ collapsedSections,
1219
+ camera
1330
1220
  ]);
1331
1221
  const contributions = useMemo(
1332
1222
  () => suppressContributions(
@@ -1410,8 +1300,8 @@ function Trial({ id, chrome, suppress }) {
1410
1300
  const lab = useLabContext();
1411
1301
  const storeCtx = useContext(LabStoreContext);
1412
1302
  if (!storeCtx) throw new Error("[labkit] <Trial> requires <LabStoreProvider>");
1413
- const instruments = useStore(storeCtx.store, (s4) => s4.instruments) ?? lab.instruments;
1414
- const record = useStore(storeCtx.store, (s4) => s4.trials.find((w2) => w2.id === id));
1303
+ const instruments = useStore(storeCtx.store, (s2) => s2.instruments) ?? lab.instruments;
1304
+ const record = useStore(storeCtx.store, (s2) => s2.trials.find((w2) => w2.id === id));
1415
1305
  const instrument = record ? instruments.find((i5) => i5.name === record.instrumentName) : void 0;
1416
1306
  const kept = useKeptMarks(instrument?.annotations?.storage, id);
1417
1307
  if (!record) {
@@ -1476,16 +1366,23 @@ function TrialRuntime({
1476
1366
  suppress
1477
1367
  }) {
1478
1368
  const wheelSlot = useRef(null);
1369
+ const cameras = useContext(CameraRegistryContext);
1370
+ const trialId = record.id;
1371
+ const publishCamera = useMemo(
1372
+ () => cameras ? (camera) => cameras.register(trialId, camera) : null,
1373
+ [cameras, trialId]
1374
+ );
1375
+ const [pointer] = useState(createPointerStore);
1479
1376
  const canvasContainerRef = useRef(null);
1480
1377
  const loupeHostRef = useRef(null);
1481
- const updateTrialState = useStore(store, (s4) => s4.updateTrialState);
1482
- const updateTrialConfig = useStore(store, (s4) => s4.updateTrialConfig);
1483
- const updateTrialView = useStore(store, (s4) => s4.updateTrialView);
1484
- const updateTrialUndoStack = useStore(store, (s4) => s4.updateTrialUndoStack);
1485
- const updateTrialAnnotations = useStore(store, (s4) => s4.updateTrialAnnotations);
1486
- const labToolId = useStore(store, (s4) => s4.activeToolId);
1487
- const setLabTool = useStore(store, (s4) => s4.setLabTool);
1488
- const setTrialTool = useStore(store, (s4) => s4.setTrialTool);
1378
+ const updateTrialState = useStore(store, (s2) => s2.updateTrialState);
1379
+ const updateTrialConfig = useStore(store, (s2) => s2.updateTrialConfig);
1380
+ const updateTrialView = useStore(store, (s2) => s2.updateTrialView);
1381
+ const updateTrialUndoStack = useStore(store, (s2) => s2.updateTrialUndoStack);
1382
+ const updateTrialAnnotations = useStore(store, (s2) => s2.updateTrialAnnotations);
1383
+ const labToolId = useStore(store, (s2) => s2.activeToolId);
1384
+ const setLabTool = useStore(store, (s2) => s2.setLabTool);
1385
+ const setTrialTool = useStore(store, (s2) => s2.setTrialTool);
1489
1386
  const schema = useConfigSchema(instrument);
1490
1387
  const { config } = useResolvedConfig(schema, record.config, record.auto);
1491
1388
  const busRef = useRef(null);
@@ -1495,7 +1392,7 @@ function TrialRuntime({
1495
1392
  const [layerOrder, setLayerOrder] = useState(null);
1496
1393
  const [loupeOn, setLoupeOn] = useState(false);
1497
1394
  const visibleLayers = useMemo(
1498
- () => (instrument.canvas?.layers ?? []).filter((l8) => layerVisibility[l8.id] !== false).map((l8) => l8.id),
1395
+ () => (instrument.canvas?.layers ?? []).filter((l7) => layerVisibility[l7.id] !== false).map((l7) => l7.id),
1499
1396
  [instrument.canvas, layerVisibility]
1500
1397
  );
1501
1398
  const undoCap = instrument.undo;
@@ -1610,12 +1507,13 @@ function TrialRuntime({
1610
1507
  view: record.view,
1611
1508
  setView,
1612
1509
  zoom: view2d?.zoom ?? 1,
1613
- setZoom: (z) => {
1510
+ setZoom: (z2) => {
1614
1511
  if (!view2d) return;
1615
- updateTrialView(record.id, withZoom(view2d, z));
1512
+ updateTrialView(record.id, withZoom(view2d, z2));
1616
1513
  },
1617
1514
  activeToolId: resolvedToolId,
1618
- visibleLayers
1515
+ visibleLayers,
1516
+ pointer
1619
1517
  },
1620
1518
  emit: (event) => {
1621
1519
  snapshotIfNeeded(event);
@@ -1656,7 +1554,7 @@ function TrialRuntime({
1656
1554
  const canvasLayers = useMemo(() => {
1657
1555
  if (!instrument.canvas) return [];
1658
1556
  const baseLayers = instrument.canvas.layers;
1659
- const ordered = layerOrder ? [...baseLayers].sort((a4, b3) => layerOrder.indexOf(a4.id) - layerOrder.indexOf(b3.id)) : baseLayers;
1557
+ const ordered = layerOrder ? [...baseLayers].sort((a6, b2) => layerOrder.indexOf(a6.id) - layerOrder.indexOf(b2.id)) : baseLayers;
1660
1558
  return ordered.map((layer) => ({
1661
1559
  id: layer.id,
1662
1560
  visible: layerVisibility[layer.id] !== false,
@@ -1668,23 +1566,23 @@ function TrialRuntime({
1668
1566
  }, [instrument.canvas, record.state, config, layerVisibility, layerOrder]);
1669
1567
  const layerDescriptors = useMemo(() => {
1670
1568
  if (!instrument.layers) return [];
1671
- return instrument.layers.ids.map((l8) => typeof l8 === "string" ? { id: l8, label: l8 } : l8);
1569
+ return instrument.layers.ids.map((l7) => typeof l7 === "string" ? { id: l7, label: l7 } : l7);
1672
1570
  }, [instrument.layers]);
1673
1571
  const layerItems = useMemo(() => {
1674
- const ordered = layerOrder ? [...layerDescriptors].sort((a4, b3) => layerOrder.indexOf(a4.id) - layerOrder.indexOf(b3.id)) : layerDescriptors;
1572
+ const ordered = layerOrder ? [...layerDescriptors].sort((a6, b2) => layerOrder.indexOf(a6.id) - layerOrder.indexOf(b2.id)) : layerDescriptors;
1675
1573
  const pinnedLast = [
1676
- ...ordered.filter((l8) => !l8.alwaysOn),
1677
- ...ordered.filter((l8) => l8.alwaysOn)
1574
+ ...ordered.filter((l7) => !l7.alwaysOn),
1575
+ ...ordered.filter((l7) => l7.alwaysOn)
1678
1576
  ];
1679
- return pinnedLast.map((l8) => ({
1680
- id: l8.id,
1681
- label: l8.label,
1682
- locked: l8.alwaysOn === true,
1683
- visible: l8.alwaysOn === true || layerVisibility[l8.id] !== false
1577
+ return pinnedLast.map((l7) => ({
1578
+ id: l7.id,
1579
+ label: l7.label,
1580
+ locked: l7.alwaysOn === true,
1581
+ visible: l7.alwaysOn === true || layerVisibility[l7.id] !== false
1684
1582
  }));
1685
1583
  }, [layerDescriptors, layerOrder, layerVisibility]);
1686
1584
  const dragDropResult = useDragDrop({
1687
- capability: instrument.dragDrop ?? { palette: [], onDrop: (_p, _i, s4) => s4 },
1585
+ capability: instrument.dragDrop ?? { palette: [], onDrop: (_p, _i, s2) => s2 },
1688
1586
  canvasContainerRef,
1689
1587
  view: view2d ?? DEFAULT_VIEW,
1690
1588
  worldSpec: instrument.canvas?.worldSpec,
@@ -1794,11 +1692,11 @@ function TrialRuntime({
1794
1692
  );
1795
1693
  const layerListNode = useMemo(
1796
1694
  () => instrument.layers && layerDescriptors.length > 0 ? /* @__PURE__ */ jsx(
1797
- D,
1695
+ E3,
1798
1696
  {
1799
1697
  items: layerItems,
1800
1698
  onReorder: (move) => {
1801
- setLayerOrder(S2(layerItems, move).map((l8) => l8.id));
1699
+ setLayerOrder(x3(layerItems, move).map((l7) => l7.id));
1802
1700
  bus.emit("layers.reorder");
1803
1701
  },
1804
1702
  onVisibilityChange: (lid, visible) => {
@@ -1838,6 +1736,7 @@ function TrialRuntime({
1838
1736
  activeToolId: labTool
1839
1737
  }
1840
1738
  ) : null;
1739
+ const scopedBody = /* @__PURE__ */ jsx(WeaselProvider, { isolate: true, children: /* @__PURE__ */ jsx(PointerContextProvider, { store: pointer, children: /* @__PURE__ */ jsx(CameraPublishContext.Provider, { value: publishCamera, children: body }) }) });
1841
1740
  return /* @__PURE__ */ jsx(TrialIdProvider, { trialId: record.id, children: /* @__PURE__ */ jsx(AnnotationsContext.Provider, { value: annotationsCap ? annotations : null, children: /* @__PURE__ */ jsx(CameraWheelContext.Provider, { value: wheelSlot, children: /* @__PURE__ */ jsxs(
1842
1741
  TrialChrome,
1843
1742
  {
@@ -1854,7 +1753,7 @@ function TrialRuntime({
1854
1753
  activeToolId: resolvedToolId,
1855
1754
  setActiveTool,
1856
1755
  children: [
1857
- body,
1756
+ scopedBody,
1858
1757
  annotationOverlays
1859
1758
  ]
1860
1759
  }
@@ -1975,10 +1874,10 @@ function findOvershoot(bound, items, tolerance = 1) {
1975
1874
  let worst = null;
1976
1875
  for (const { item, edges } of items) {
1977
1876
  const y3 = edges.bottom - bound.bottom;
1978
- const x2 = edges.right - bound.right;
1979
- const by = Math.max(x2, y3);
1877
+ const x3 = edges.right - bound.right;
1878
+ const by = Math.max(x3, y3);
1980
1879
  if (by <= tolerance) continue;
1981
- if (!worst || by > worst.by) worst = { item, by, axis: y3 >= x2 ? "y" : "x" };
1880
+ if (!worst || by > worst.by) worst = { item, by, axis: y3 >= x3 ? "y" : "x" };
1982
1881
  }
1983
1882
  return worst;
1984
1883
  }
@@ -2054,37 +1953,30 @@ function useLabFitWarning(labBody) {
2054
1953
  function LabHeader({ addTrial: addTrial2 = true }) {
2055
1954
  const lab = useLabContext();
2056
1955
  const only = lab.instruments.length === 1 ? lab.instruments[0] : null;
2057
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2058
- !addTrial2 ? null : only ? /* @__PURE__ */ jsxs(
2059
- "button",
2060
- {
2061
- type: "button",
2062
- className: "lk-lab-header__add",
2063
- onClick: () => lab.addTrial(only.name),
2064
- children: [
2065
- /* @__PURE__ */ jsx(oe, { size: 16 }),
2066
- /* @__PURE__ */ jsx("span", { children: "Add trial" })
2067
- ]
2068
- }
2069
- ) : /* @__PURE__ */ jsx(
2070
- d2,
2071
- {
2072
- "aria-label": "Add trial",
2073
- label: "Add trial\u2026",
2074
- items: lab.instruments.map((i5) => ({ value: i5.name, label: i5.title ?? i5.name })),
2075
- onAction: (name) => lab.addTrial(name)
2076
- }
2077
- ),
2078
- /* @__PURE__ */ jsx(
2079
- s3,
2080
- {
2081
- className: "lk-lab-header__mode",
2082
- variant: "flat",
2083
- value: lab.mode,
2084
- onChange: lab.setMode
2085
- }
2086
- )
2087
- ] });
1956
+ return /* @__PURE__ */ jsx(Fragment, { children: !addTrial2 ? null : only ? /* @__PURE__ */ jsxs(
1957
+ "button",
1958
+ {
1959
+ type: "button",
1960
+ className: "lk-lab-header__add",
1961
+ onClick: () => lab.addTrial(only.name),
1962
+ children: [
1963
+ /* @__PURE__ */ jsx(G, { size: 16 }),
1964
+ /* @__PURE__ */ jsx("span", { children: "Add trial" })
1965
+ ]
1966
+ }
1967
+ ) : /* @__PURE__ */ jsx(
1968
+ d3,
1969
+ {
1970
+ "aria-label": "Add trial",
1971
+ label: "Add trial\u2026",
1972
+ items: lab.instruments.map((i5) => ({ value: i5.name, label: i5.title ?? i5.name })),
1973
+ onAction: (name) => lab.addTrial(name)
1974
+ }
1975
+ ) });
1976
+ }
1977
+ function LabThemeSwitcher() {
1978
+ const lab = useLabContext();
1979
+ return /* @__PURE__ */ jsx(o3, { value: lab.mode, onChange: lab.setMode });
2088
1980
  }
2089
1981
  function LabPalette({ tools, contributions }) {
2090
1982
  const ctx = useLabChromeContext();
@@ -2203,6 +2095,110 @@ function LabShell({
2203
2095
  footer && /* @__PURE__ */ jsx("footer", { className: "lk-shell-footer", children: footer })
2204
2096
  ] });
2205
2097
  }
2098
+ var ZOOM_ID = "viewport.zoom";
2099
+ var NO_TOOLS = /* @__PURE__ */ new Map();
2100
+ var CHANNELS = { contextMenu: false, ingest: false };
2101
+ var NO_ELEMENT = { current: null };
2102
+ var BASE = makeViewportZoomAction({ min: 1e-9, max: Number.POSITIVE_INFINITY });
2103
+ var KEY_BINDINGS = BASE.defaultBinding.filter((b2) => b2.spec.kind === "key");
2104
+ function shortcutFor(kind) {
2105
+ const spec = KEY_BINDINGS.find((b2) => b2.opts?.params?.kind === kind)?.spec;
2106
+ return spec?.key ? n2({ key: spec.key, mod: spec.mods?.mod }) : void 0;
2107
+ }
2108
+ function forZoom(camera) {
2109
+ return {
2110
+ get: camera.get,
2111
+ set: camera.set,
2112
+ hostSize: camera.hostSize,
2113
+ recenter: () => atScale(camera.get(), 1, viewMiddle(camera))
2114
+ };
2115
+ }
2116
+ var percent = new Intl.NumberFormat(void 0, { style: "percent", maximumFractionDigits: 0 });
2117
+ function LabZoom() {
2118
+ return /* @__PURE__ */ jsx(DepRegistryProvider, { children: /* @__PURE__ */ jsx(ActionsProvider, { children: /* @__PURE__ */ jsx(ActiveToolContextProvider, { children: /* @__PURE__ */ jsx(LabZoomControls, {}) }) }) });
2119
+ }
2120
+ function LabZoomControls() {
2121
+ const registry = useActionsRegistry();
2122
+ const { focusedTrialId } = useLabContext();
2123
+ const cameras = useContext(CameraRegistryContext);
2124
+ const storeCtx = useContext(LabStoreContext);
2125
+ if (!storeCtx) throw new Error("[labkit] <LabZoom> requires <LabStoreProvider>");
2126
+ const camera = useSyncExternalStore(
2127
+ cameras?.subscribe ?? noSubscribe2,
2128
+ () => cameras && focusedTrialId ? cameras.get(focusedTrialId) : null
2129
+ );
2130
+ const zoom = useStore(storeCtx.store, (s2) => {
2131
+ const record = s2.trials.find((t) => t.id === focusedTrialId);
2132
+ return as2DView(record?.view)?.zoom ?? null;
2133
+ });
2134
+ const live = zoom !== null && camera !== null;
2135
+ const view = useMemo(() => camera ? forZoom(camera) : null, [camera]);
2136
+ const viewRef = useRef(view);
2137
+ viewRef.current = live ? view : null;
2138
+ useDepSource("view", () => viewRef.current);
2139
+ useEffect(() => {
2140
+ const action = {
2141
+ ...BASE,
2142
+ defaultBinding: KEY_BINDINGS,
2143
+ enabled: () => viewRef.current ? true : ActionDisabledReason.NotApplicable
2144
+ };
2145
+ return registry.register(action);
2146
+ }, [registry]);
2147
+ useGestureDispatcher({
2148
+ canvasRef: NO_ELEMENT,
2149
+ actions: registry,
2150
+ entriesById: NO_TOOLS,
2151
+ channels: CHANNELS,
2152
+ keyboard: "first"
2153
+ });
2154
+ const range = camera?.zoomRange();
2155
+ const canIn = zoom !== null && range !== void 0 && zoom < range.max * (1 - 1e-9);
2156
+ const canOut = zoom !== null && range !== void 0 && zoom > range.min * (1 + 1e-9);
2157
+ const run = (kind) => () => {
2158
+ registry.trigger(ZOOM_ID, { kind });
2159
+ };
2160
+ const hint = (label, kind) => {
2161
+ const keys = shortcutFor(kind);
2162
+ return keys ? `${label} (${keys})` : label;
2163
+ };
2164
+ const shown = live && zoom !== null ? percent.format(zoom) : null;
2165
+ return /* @__PURE__ */ jsx(Toolbar, { "aria-label": "Zoom", children: /* @__PURE__ */ jsxs(Toolbar.Group, { "aria-label": "Zoom", children: [
2166
+ /* @__PURE__ */ jsx(
2167
+ Toolbar.Button,
2168
+ {
2169
+ iconOnly: true,
2170
+ "aria-label": "Zoom out",
2171
+ title: hint("Zoom out", "out"),
2172
+ disabled: !canOut,
2173
+ onClick: run("out"),
2174
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
2175
+ }
2176
+ ),
2177
+ /* @__PURE__ */ jsx(
2178
+ Toolbar.Button,
2179
+ {
2180
+ "aria-label": shown ? `Zoom ${shown} \u2014 reset to actual size` : "Zoom unavailable",
2181
+ title: live ? hint("Actual size", "reset") : "This trial has no camera",
2182
+ disabled: !live,
2183
+ onClick: run("reset"),
2184
+ children: /* @__PURE__ */ jsx("span", { className: "lk-lab-zoom__readout", children: shown ?? "\u2013" })
2185
+ }
2186
+ ),
2187
+ /* @__PURE__ */ jsx(
2188
+ Toolbar.Button,
2189
+ {
2190
+ iconOnly: true,
2191
+ "aria-label": "Zoom in",
2192
+ title: hint("Zoom in", "in"),
2193
+ disabled: !canIn,
2194
+ onClick: run("in"),
2195
+ children: /* @__PURE__ */ jsx(U, { size: 16 })
2196
+ }
2197
+ )
2198
+ ] }) });
2199
+ }
2200
+ var noSubscribe2 = () => () => {
2201
+ };
2206
2202
  var ZONE_ID = asNodeId("lk-workspace");
2207
2203
  var STRATEGIES = { grid: gridStrategy, floating: floatingStrategy };
2208
2204
  var FLOAT_ZONE_ID = asNodeId("lk-workspace-floating");
@@ -2237,7 +2233,7 @@ function Workspace({
2237
2233
  const tilePanels = useMemo(() => (panels ?? []).filter((p3) => p3.as === "tile"), [panels]);
2238
2234
  const floatPanels = useMemo(() => (panels ?? []).filter((p3) => p3.as === "floating"), [panels]);
2239
2235
  const wantedIds = [
2240
- ...items.map((_2, i5) => ids?.[i5] ?? `lk-ws-${i5}`),
2236
+ ...items.map((_3, i5) => ids?.[i5] ?? `lk-ws-${i5}`),
2241
2237
  ...tilePanels.map((p3) => `lk-panel-${p3.key}`)
2242
2238
  ];
2243
2239
  const idKey = wantedIds.join(",");
@@ -2428,8 +2424,8 @@ var NEBULA_SLOTS = [
2428
2424
  ];
2429
2425
  function buildNebula(list, theme, mode, density) {
2430
2426
  const ctx = { theme, resolved: resolveTheme(theme, { mode, density }) };
2431
- const n5 = colorCount(list, ctx) ?? NEBULA_SLOTS.length;
2432
- const colors = Array.from({ length: n5 }, (_2, i5) => colorAt(list, i5, ctx));
2427
+ const n6 = colorCount(list, ctx) ?? NEBULA_SLOTS.length;
2428
+ const colors = Array.from({ length: n6 }, (_3, i5) => colorAt(list, i5, ctx));
2433
2429
  const blobs = colors.map((c6, i5) => {
2434
2430
  const p3 = NEBULA_SLOTS[i5 % NEBULA_SLOTS.length];
2435
2431
  return `radial-gradient(ellipse ${p3.sx} ${p3.sy} at ${p3.cx} ${p3.cy}, color-mix(in srgb, ${c6} 22%, transparent), transparent ${p3.stop})`;
@@ -2528,6 +2524,7 @@ function LabRuntime({
2528
2524
  labChrome,
2529
2525
  suppress,
2530
2526
  addTrial: addTrial2,
2527
+ zoom = true,
2531
2528
  tools,
2532
2529
  configRules,
2533
2530
  controls,
@@ -2538,13 +2535,14 @@ function LabRuntime({
2538
2535
  useLayoutEffect(() => {
2539
2536
  store.getState().setInstruments(instruments);
2540
2537
  }, [instruments, store]);
2541
- const trials = useStore(store, (s4) => s4.trials);
2538
+ const trials = useStore(store, (s2) => s2.trials);
2539
+ const [cameras] = useState(createCameraRegistry);
2542
2540
  const [focusPick, setFocusPick] = useState(null);
2543
2541
  const focusedTrialId = trials.some((t) => t.id === focusPick) ? focusPick : trials[0]?.id ?? null;
2544
- const savedSnapshots = useStore(store, (s4) => s4.savedSnapshots);
2545
- const modeValue = useStore(store, (s4) => s4.mode);
2546
- const layout = useStore(store, (s4) => s4.layout);
2547
- const undockedPanels = useStore(store, (s4) => s4.undockedPanels);
2542
+ const savedSnapshots = useStore(store, (s2) => s2.savedSnapshots);
2543
+ const modeValue = useStore(store, (s2) => s2.mode);
2544
+ const layout = useStore(store, (s2) => s2.layout);
2545
+ const undockedPanels = useStore(store, (s2) => s2.undockedPanels);
2548
2546
  const panelHostsRef = useRef(null);
2549
2547
  if (panelHostsRef.current === null) panelHostsRef.current = createPanelHostRegistry();
2550
2548
  const outerSurface = useSurfaceOptional();
@@ -2626,10 +2624,10 @@ function LabRuntime({
2626
2624
  [undockedPanels]
2627
2625
  );
2628
2626
  const resolvedMode = useResolvedColorMode(modeValue);
2629
- const annotates = instruments.some((i5) => i5.annotations != null);
2627
+ const annotationTools = useMemo(() => labAnnotationTools(instruments), [instruments]);
2630
2628
  const labChromeAll = useMemo(
2631
- () => labContributions([...annotates ? ANNOTATION_TOOLS : [], ...tools ?? []], labChrome),
2632
- [annotates, tools, labChrome]
2629
+ () => labContributions([...annotationTools, ...tools ?? []], labChrome),
2630
+ [annotationTools, tools, labChrome]
2633
2631
  );
2634
2632
  const hasFooterChrome = labChromeAll.some((c6) => c6.region === "footer");
2635
2633
  const hasPaneChrome = labChromeAll.some((c6) => c6.region === "sidebar" || c6.region === "aside");
@@ -2684,15 +2682,15 @@ function LabRuntime({
2684
2682
  const next = resetTrial(store.getState().trials, id, instruments);
2685
2683
  const record = next.find((w2) => w2.id === id);
2686
2684
  if (!record) return;
2687
- store.setState((s4) => ({
2688
- trials: s4.trials.map(
2685
+ store.setState((s2) => ({
2686
+ trials: s2.trials.map(
2689
2687
  (w2) => w2.id === id ? { ...w2, config: record.config, state: record.state, view: record.view } : w2
2690
2688
  )
2691
2689
  }));
2692
2690
  },
2693
2691
  savedSnapshots,
2694
2692
  saveSnapshot: (trialId, name) => {
2695
- const taken = store.getState().savedSnapshots.filter((s4) => s4.trialId === trialId).length;
2693
+ const taken = store.getState().savedSnapshots.filter((s2) => s2.trialId === trialId).length;
2696
2694
  store.getState().saveSnapshot(trialId, name ?? `Snapshot ${taken + 1}`);
2697
2695
  },
2698
2696
  loadSnapshot: (trialId, snapshotId) => {
@@ -2702,8 +2700,8 @@ function LabRuntime({
2702
2700
  store.getState().deleteSnapshot(snapshotId);
2703
2701
  },
2704
2702
  mode: modeValue,
2705
- setMode: (m3) => {
2706
- store.getState().setMode(m3);
2703
+ setMode: (m2) => {
2704
+ store.getState().setMode(m2);
2707
2705
  },
2708
2706
  configRules,
2709
2707
  controls
@@ -2739,7 +2737,7 @@ function LabRuntime({
2739
2737
  children: trials.map((w2) => /* @__PURE__ */ jsx(Trial, { id: w2.id, chrome, suppress }, w2.id))
2740
2738
  }
2741
2739
  );
2742
- return /* @__PURE__ */ jsx(LabStoreContext.Provider, { value: { store }, children: /* @__PURE__ */ jsx(PersistenceContext.Provider, { value: opened.records, children: /* @__PURE__ */ jsx(AnnotationPreloadContext.Provider, { value: opened.marks, children: /* @__PURE__ */ jsx(LabContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
2740
+ return /* @__PURE__ */ jsx(LabStoreContext.Provider, { value: { store }, children: /* @__PURE__ */ jsx(PersistenceContext.Provider, { value: opened.records, children: /* @__PURE__ */ jsx(AnnotationPreloadContext.Provider, { value: opened.marks, children: /* @__PURE__ */ jsx(LabContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(CameraRegistryContext.Provider, { value: cameras, children: /* @__PURE__ */ jsx(
2743
2741
  ThemeProvider,
2744
2742
  {
2745
2743
  theme,
@@ -2759,8 +2757,10 @@ function LabRuntime({
2759
2757
  ] }) : footer,
2760
2758
  header: /* @__PURE__ */ jsxs(Fragment, { children: [
2761
2759
  /* @__PURE__ */ jsx(LabHeader, { ...addTrial2 !== void 0 ? { addTrial: addTrial2 } : {} }),
2760
+ zoom ? /* @__PURE__ */ jsx(LabZoom, {}) : null,
2762
2761
  children,
2763
- /* @__PURE__ */ jsx(LabHeaderRegion, { contributions: labChromeAll })
2762
+ /* @__PURE__ */ jsx(LabHeaderRegion, { contributions: labChromeAll }),
2763
+ /* @__PURE__ */ jsx(LabThemeSwitcher, {})
2764
2764
  ] }),
2765
2765
  children: /* @__PURE__ */ jsx(PanelHostContext.Provider, { value: panelHostsRef.current, children: /* @__PURE__ */ jsx(SurfaceContext.Provider, { value: surface, children: /* @__PURE__ */ jsx(SurfaceCanvasContext.Provider, { value: surfaceCanvases, children: /* @__PURE__ */ jsxs("div", { className: "lk-lab__body", ref: labBodyRef, children: [
2766
2766
  outerSurface ? null : (
@@ -2803,7 +2803,7 @@ function LabRuntime({
2803
2803
  }
2804
2804
  )
2805
2805
  }
2806
- ) }) }) }) });
2806
+ ) }) }) }) }) });
2807
2807
  }
2808
2808
  function LabBoundary({ children }) {
2809
2809
  return /* @__PURE__ */ jsx(LabStoreContext.Provider, { value: null, children: /* @__PURE__ */ jsx(PersistenceContext.Provider, { value: null, children: /* @__PURE__ */ jsx(AnnotationPreloadContext.Provider, { value: null, children: /* @__PURE__ */ jsx(LabContext.Provider, { value: null, children: /* @__PURE__ */ jsx(PanelHostContext.Provider, { value: null, children: /* @__PURE__ */ jsx(SurfaceContext.Provider, { value: null, children: /* @__PURE__ */ jsx(SurfaceCanvasContext.Provider, { value: { over: null, under: null }, children: /* @__PURE__ */ jsx(TrialIdContext.Provider, { value: null, children: /* @__PURE__ */ jsx(AnnotationsContext.Provider, { value: null, children: /* @__PURE__ */ jsx(CameraWheelContext.Provider, { value: null, children: /* @__PURE__ */ jsx(CanvasStackContext.Provider, { value: null, children: /* @__PURE__ */ jsx(TrialDragContext.Provider, { value: null, children: /* @__PURE__ */ jsx(ThemeContext.Provider, { value: null, children }) }) }) }) }) }) }) }) }) }) }) }) });
@@ -2908,25 +2908,25 @@ function ButtonsAndToggles() {
2908
2908
  /* @__PURE__ */ jsx(c, { variant: "secondary", iconOnly: true, ariaLabel: "Add", children: /* @__PURE__ */ jsx(Dot, {}) })
2909
2909
  ] }) }),
2910
2910
  /* @__PURE__ */ jsx(Cell, { label: "Badge", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
2911
- /* @__PURE__ */ jsx(Ht, { shape: "pill", status: "accent", variant: "outline", size: "sm", children: "ACCENT" }),
2912
- /* @__PURE__ */ jsx(Ht, { status: "info", variant: "subtle", children: "INFO" }),
2913
- /* @__PURE__ */ jsx(Ht, { status: "warn", variant: "solid", children: "WARN" }),
2914
- /* @__PURE__ */ jsx(Ht, { status: "danger", variant: "solid", children: "DANGER" }),
2915
- /* @__PURE__ */ jsx(Ht, { status: "muted", children: "MUTED" })
2911
+ /* @__PURE__ */ jsx(Xt, { shape: "pill", status: "accent", variant: "outline", size: "sm", children: "ACCENT" }),
2912
+ /* @__PURE__ */ jsx(Xt, { status: "info", variant: "subtle", children: "INFO" }),
2913
+ /* @__PURE__ */ jsx(Xt, { status: "warn", variant: "solid", children: "WARN" }),
2914
+ /* @__PURE__ */ jsx(Xt, { status: "danger", variant: "solid", children: "DANGER" }),
2915
+ /* @__PURE__ */ jsx(Xt, { status: "muted", children: "MUTED" })
2916
2916
  ] }) }),
2917
2917
  /* @__PURE__ */ jsx(Cell, { label: "Checkbox, Switch", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
2918
- /* @__PURE__ */ jsx(o2, { isSelected: snap, onChange: setSnap, children: "Snap to grid" }),
2919
- /* @__PURE__ */ jsx(o2, { isIndeterminate: true, children: "Mixed" }),
2920
- /* @__PURE__ */ jsx(a6, { isSelected: wifi, onChange: setWifi, children: "Wifi" })
2918
+ /* @__PURE__ */ jsx(o5, { isSelected: snap, onChange: setSnap, children: "Snap to grid" }),
2919
+ /* @__PURE__ */ jsx(o5, { isIndeterminate: true, children: "Mixed" }),
2920
+ /* @__PURE__ */ jsx(a8, { isSelected: wifi, onChange: setWifi, children: "Wifi" })
2921
2921
  ] }) }),
2922
- /* @__PURE__ */ jsx(Cell, { label: "RadioGroup", children: /* @__PURE__ */ jsxs(l5, { label: "Snap mode", orientation: "horizontal", defaultValue: "grid", children: [
2923
- /* @__PURE__ */ jsx(u5, { value: "off", children: "Off" }),
2924
- /* @__PURE__ */ jsx(u5, { value: "grid", children: "Grid" }),
2925
- /* @__PURE__ */ jsx(u5, { value: "pixel", children: "Pixel" })
2922
+ /* @__PURE__ */ jsx(Cell, { label: "RadioGroup", children: /* @__PURE__ */ jsxs(l4, { label: "Snap mode", orientation: "horizontal", defaultValue: "grid", children: [
2923
+ /* @__PURE__ */ jsx(u4, { value: "off", children: "Off" }),
2924
+ /* @__PURE__ */ jsx(u4, { value: "grid", children: "Grid" }),
2925
+ /* @__PURE__ */ jsx(u4, { value: "pixel", children: "Pixel" })
2926
2926
  ] }) }),
2927
2927
  /* @__PURE__ */ jsxs(Cell, { label: "ToggleBar", children: [
2928
2928
  /* @__PURE__ */ jsx(
2929
- a5,
2929
+ a7,
2930
2930
  {
2931
2931
  ariaLabel: "Align",
2932
2932
  value: align,
@@ -2939,7 +2939,7 @@ function ButtonsAndToggles() {
2939
2939
  }
2940
2940
  ),
2941
2941
  /* @__PURE__ */ jsx(
2942
- a5,
2942
+ a7,
2943
2943
  {
2944
2944
  ariaLabel: "Align, flat",
2945
2945
  variant: "flat",
@@ -2965,7 +2965,7 @@ function ButtonsAndToggles() {
2965
2965
  }
2966
2966
  ),
2967
2967
  /* @__PURE__ */ jsx(
2968
- a7,
2968
+ a10,
2969
2969
  {
2970
2970
  items: [
2971
2971
  { value: "undo", label: "Undo", onAction: () => {
@@ -2978,7 +2978,7 @@ function ButtonsAndToggles() {
2978
2978
  ] }) }),
2979
2979
  /* @__PURE__ */ jsx(Cell, { label: "MenuButton, Disclosure", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
2980
2980
  /* @__PURE__ */ jsx(
2981
- d2,
2981
+ d3,
2982
2982
  {
2983
2983
  label: "Add trial\u2026",
2984
2984
  onAction: () => {
@@ -2989,17 +2989,17 @@ function ButtonsAndToggles() {
2989
2989
  ]
2990
2990
  }
2991
2991
  ),
2992
- /* @__PURE__ */ jsx(i3, { open, onToggle: () => setOpen((o4) => !o4), label: "Shapes" })
2992
+ /* @__PURE__ */ jsx(i2, { open, onToggle: () => setOpen((o5) => !o5), label: "Shapes" })
2993
2993
  ] }) }),
2994
- /* @__PURE__ */ jsx(Cell, { label: "Tabs", children: /* @__PURE__ */ jsxs(o4, { children: [
2995
- /* @__PURE__ */ jsxs(s6, { "aria-label": "Sections", children: [
2996
- /* @__PURE__ */ jsx(c5, { id: "props", children: "Props" }),
2997
- /* @__PURE__ */ jsx(c5, { id: "events", children: "Events" }),
2998
- /* @__PURE__ */ jsx(c5, { id: "snapshot", children: "Snapshot" })
2994
+ /* @__PURE__ */ jsx(Cell, { label: "Tabs", children: /* @__PURE__ */ jsxs(o6, { children: [
2995
+ /* @__PURE__ */ jsxs(s4, { "aria-label": "Sections", children: [
2996
+ /* @__PURE__ */ jsx(c6, { id: "props", children: "Props" }),
2997
+ /* @__PURE__ */ jsx(c6, { id: "events", children: "Events" }),
2998
+ /* @__PURE__ */ jsx(c6, { id: "snapshot", children: "Snapshot" })
2999
2999
  ] }),
3000
- /* @__PURE__ */ jsx(l7, { id: "props", children: "Props panel." }),
3001
- /* @__PURE__ */ jsx(l7, { id: "events", children: "Events panel." }),
3002
- /* @__PURE__ */ jsx(l7, { id: "snapshot", children: "Snapshot panel." })
3000
+ /* @__PURE__ */ jsx(l6, { id: "props", children: "Props panel." }),
3001
+ /* @__PURE__ */ jsx(l6, { id: "events", children: "Events panel." }),
3002
+ /* @__PURE__ */ jsx(l6, { id: "snapshot", children: "Snapshot panel." })
3003
3003
  ] }) }),
3004
3004
  /* @__PURE__ */ jsx(Cell, { label: "Keycaps", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
3005
3005
  /* @__PURE__ */ jsx(p, { keys: [{ label: "\u2318" }, { label: "\u21E7" }, { label: "K" }], separator: "+" }),
@@ -3025,9 +3025,9 @@ function FieldsAndPickers() {
3025
3025
  const [paint, setPaint] = useState({ fill: "solid", color: "#b08adb" });
3026
3026
  return /* @__PURE__ */ jsxs(Section, { title: "Fields & pickers", children: [
3027
3027
  /* @__PURE__ */ jsxs(Cell, { label: "Input", children: [
3028
- /* @__PURE__ */ jsx(u4, { label: "Name", placeholder: "e.g. Pico" }),
3028
+ /* @__PURE__ */ jsx(u3, { label: "Name", placeholder: "e.g. Pico" }),
3029
3029
  /* @__PURE__ */ jsx(
3030
- u4,
3030
+ u3,
3031
3031
  {
3032
3032
  label: "Size",
3033
3033
  leadingAdornment: /* @__PURE__ */ jsx("span", { children: "W" }),
@@ -3035,12 +3035,12 @@ function FieldsAndPickers() {
3035
3035
  defaultValue: "120"
3036
3036
  }
3037
3037
  ),
3038
- /* @__PURE__ */ jsx(u4, { label: "Required", isInvalid: true, errorMessage: "Name is required." })
3038
+ /* @__PURE__ */ jsx(u3, { label: "Required", isInvalid: true, errorMessage: "Name is required." })
3039
3039
  ] }),
3040
3040
  /* @__PURE__ */ jsxs(Cell, { label: "NumberField, Select, ComboBox", children: [
3041
- /* @__PURE__ */ jsx(g, { label: "Opacity", minValue: 0, maxValue: 100, step: 5, defaultValue: 80 }),
3041
+ /* @__PURE__ */ jsx(y, { label: "Opacity", minValue: 0, maxValue: 100, step: 5, defaultValue: 80 }),
3042
3042
  /* @__PURE__ */ jsx(
3043
- T2,
3043
+ E2,
3044
3044
  {
3045
3045
  label: "Color",
3046
3046
  defaultSelectedKey: "g",
@@ -3064,9 +3064,9 @@ function FieldsAndPickers() {
3064
3064
  )
3065
3065
  ] }),
3066
3066
  /* @__PURE__ */ jsxs(Cell, { label: "RangeSlider, Slider", children: [
3067
- /* @__PURE__ */ jsx(l8, { label: "Range", defaultValue: [20, 80], minValue: 0, maxValue: 100 }),
3067
+ /* @__PURE__ */ jsx(l7, { label: "Range", defaultValue: [20, 80], minValue: 0, maxValue: 100 }),
3068
3068
  /* @__PURE__ */ jsx(
3069
- l8,
3069
+ l7,
3070
3070
  {
3071
3071
  label: "Opacity",
3072
3072
  defaultValue: 75,
@@ -3076,7 +3076,7 @@ function FieldsAndPickers() {
3076
3076
  }
3077
3077
  ),
3078
3078
  /* @__PURE__ */ jsx(
3079
- b,
3079
+ S,
3080
3080
  {
3081
3081
  ariaLabel: "Pair",
3082
3082
  min: 0,
@@ -3091,7 +3091,7 @@ function FieldsAndPickers() {
3091
3091
  ] }),
3092
3092
  /* @__PURE__ */ jsxs(Cell, { label: "DetentSlider, InlineRange", children: [
3093
3093
  /* @__PURE__ */ jsx(
3094
- c6,
3094
+ c7,
3095
3095
  {
3096
3096
  items: [0.25, 0.5, 1, 2, 4],
3097
3097
  value: rate,
@@ -3113,11 +3113,11 @@ function FieldsAndPickers() {
3113
3113
  )
3114
3114
  ] }),
3115
3115
  /* @__PURE__ */ jsxs(Cell, { label: "ColorField, GradientEditor", children: [
3116
- /* @__PURE__ */ jsx(l4, { value: color, alpha: true, onInput: setColor, onChange: setColor, "aria-label": "Color" }),
3117
- /* @__PURE__ */ jsx(C, { value: gradient, onInput: setGradient, onChange: setGradient, kindSwitch: true })
3116
+ /* @__PURE__ */ jsx(f3, { value: color, alpha: true, onInput: setColor, onChange: setColor, "aria-label": "Color" }),
3117
+ /* @__PURE__ */ jsx(D, { value: gradient, onInput: setGradient, onChange: setGradient, kindSwitch: true })
3118
3118
  ] }),
3119
3119
  /* @__PURE__ */ jsx(Cell, { label: "PaintInput", children: /* @__PURE__ */ jsx(
3120
- S,
3120
+ T,
3121
3121
  {
3122
3122
  value: paint,
3123
3123
  onInput: setPaint,
@@ -3146,9 +3146,9 @@ function PanelsAndRows() {
3146
3146
  ]);
3147
3147
  const [panelCollapsed, setPanelCollapsed] = useState(false);
3148
3148
  return /* @__PURE__ */ jsxs(Section, { title: "Panels & property rows", children: [
3149
- /* @__PURE__ */ jsx(Cell, { label: "PropertyPanel", children: /* @__PURE__ */ jsx(ae, { title: "Shape", children: /* @__PURE__ */ jsxs(oe2, { children: [
3149
+ /* @__PURE__ */ jsx(Cell, { label: "PropertyPanel", children: /* @__PURE__ */ jsx(re2, { title: "Shape", children: /* @__PURE__ */ jsxs(ie2, { children: [
3150
3150
  /* @__PURE__ */ jsx(
3151
- B,
3151
+ R,
3152
3152
  {
3153
3153
  kind: "number",
3154
3154
  control: "slider",
@@ -3161,7 +3161,7 @@ function PanelsAndRows() {
3161
3161
  }
3162
3162
  ),
3163
3163
  /* @__PURE__ */ jsx(
3164
- B,
3164
+ R,
3165
3165
  {
3166
3166
  kind: "number",
3167
3167
  control: "slider",
@@ -3174,7 +3174,7 @@ function PanelsAndRows() {
3174
3174
  }
3175
3175
  ),
3176
3176
  /* @__PURE__ */ jsx(
3177
- B,
3177
+ R,
3178
3178
  {
3179
3179
  kind: "color",
3180
3180
  label: "Fill",
@@ -3184,10 +3184,21 @@ function PanelsAndRows() {
3184
3184
  onAlphaChange: setAlpha
3185
3185
  }
3186
3186
  ),
3187
- /* @__PURE__ */ jsx(B, { kind: "color", label: "Stroke", value: stroke, onChange: setStroke }),
3188
- /* @__PURE__ */ jsx(B, { kind: "number", label: "Count", value: count, min: 0, max: 100, step: 1, onChange: setCount }),
3187
+ /* @__PURE__ */ jsx(R, { kind: "color", label: "Stroke", value: stroke, onChange: setStroke }),
3188
+ /* @__PURE__ */ jsx(
3189
+ R,
3190
+ {
3191
+ kind: "number",
3192
+ label: "Count",
3193
+ value: count,
3194
+ min: 0,
3195
+ max: 100,
3196
+ step: 1,
3197
+ onChange: setCount
3198
+ }
3199
+ ),
3189
3200
  /* @__PURE__ */ jsx(
3190
- B,
3201
+ R,
3191
3202
  {
3192
3203
  kind: "enum",
3193
3204
  label: "Line cap",
@@ -3200,7 +3211,7 @@ function PanelsAndRows() {
3200
3211
  }
3201
3212
  ),
3202
3213
  /* @__PURE__ */ jsx(
3203
- B,
3214
+ R,
3204
3215
  {
3205
3216
  kind: "enum",
3206
3217
  control: "toggle",
@@ -3214,13 +3225,25 @@ function PanelsAndRows() {
3214
3225
  ]
3215
3226
  }
3216
3227
  ),
3217
- /* @__PURE__ */ jsx(B, { kind: "string", label: "Label", value: label, onChange: setLabel }),
3218
- /* @__PURE__ */ jsx(B, { kind: "boolean", label: "Visible", value: visible, onChange: setVisible }),
3219
- /* @__PURE__ */ jsx(b2, { title: "Bevel", defaultCollapsed: true, children: /* @__PURE__ */ jsx(B, { kind: "number", control: "slider", label: "Rings", value: 32, min: 4, max: 96, step: 1, onChange: () => {
3220
- } }) })
3228
+ /* @__PURE__ */ jsx(R, { kind: "string", label: "Label", value: label, onChange: setLabel }),
3229
+ /* @__PURE__ */ jsx(R, { kind: "boolean", label: "Visible", value: visible, onChange: setVisible }),
3230
+ /* @__PURE__ */ jsx(b2, { title: "Bevel", defaultCollapsed: true, children: /* @__PURE__ */ jsx(
3231
+ R,
3232
+ {
3233
+ kind: "number",
3234
+ control: "slider",
3235
+ label: "Rings",
3236
+ value: 32,
3237
+ min: 4,
3238
+ max: 96,
3239
+ step: 1,
3240
+ onChange: () => {
3241
+ }
3242
+ }
3243
+ ) })
3221
3244
  ] }) }) }),
3222
3245
  /* @__PURE__ */ jsx(Cell, { label: "PrefsForm", children: /* @__PURE__ */ jsx(
3223
- A2,
3246
+ j,
3224
3247
  {
3225
3248
  schema: PREFS,
3226
3249
  values: prefs,
@@ -3228,10 +3251,10 @@ function PanelsAndRows() {
3228
3251
  }
3229
3252
  ) }),
3230
3253
  /* @__PURE__ */ jsx(Cell, { label: "LayerList", children: /* @__PURE__ */ jsx(
3231
- D,
3254
+ E3,
3232
3255
  {
3233
3256
  items: layers,
3234
- onReorder: (move) => setLayers(S2(layers, move)),
3257
+ onReorder: (move) => setLayers(x3(layers, move)),
3235
3258
  renderBody: (item) => /* @__PURE__ */ jsxs("div", { children: [
3236
3259
  "settings for ",
3237
3260
  item.label
@@ -3239,7 +3262,7 @@ function PanelsAndRows() {
3239
3262
  }
3240
3263
  ) }),
3241
3264
  /* @__PURE__ */ jsx(Cell, { label: "Sidebar, SidebarPanel", children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__box", children: /* @__PURE__ */ jsx(n6, { side: "right", ariaLabel: "Specimen sidebar", children: /* @__PURE__ */ jsx(
3242
- s5,
3265
+ a11,
3243
3266
  {
3244
3267
  title: "Selection",
3245
3268
  collapsed: panelCollapsed,
@@ -3255,7 +3278,7 @@ function OverlaysAndFeedback() {
3255
3278
  const calloutAnchor = useRef(null);
3256
3279
  const [calloutOpen, setCalloutOpen] = useState(false);
3257
3280
  const [dialogOpen, setDialogOpen] = useState(false);
3258
- const toasts = useMemo(() => m4(), []);
3281
+ const toasts = useMemo(() => m3(), []);
3259
3282
  return /* @__PURE__ */ jsxs(Section, { title: "Overlays & feedback", children: [
3260
3283
  /* @__PURE__ */ jsx(Cell, { label: "Tooltip, Callout, Dialog, Toast", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
3261
3284
  /* @__PURE__ */ jsxs(l2, { children: [
@@ -3264,7 +3287,7 @@ function OverlaysAndFeedback() {
3264
3287
  ] }),
3265
3288
  /* @__PURE__ */ jsx("button", { type: "button", ref: calloutAnchor, onClick: () => setCalloutOpen(true), children: "Callout" }),
3266
3289
  /* @__PURE__ */ jsx(
3267
- g2,
3290
+ _2,
3268
3291
  {
3269
3292
  triggerRef: calloutAnchor,
3270
3293
  isOpen: calloutOpen,
@@ -3276,7 +3299,7 @@ function OverlaysAndFeedback() {
3276
3299
  ),
3277
3300
  /* @__PURE__ */ jsx(c, { onClick: () => setDialogOpen(true), children: "Dialog" }),
3278
3301
  /* @__PURE__ */ jsx(
3279
- u3,
3302
+ d2,
3280
3303
  {
3281
3304
  isOpen: dialogOpen,
3282
3305
  onOpenChange: setDialogOpen,
@@ -3292,7 +3315,7 @@ function OverlaysAndFeedback() {
3292
3315
  children: "Toast"
3293
3316
  }
3294
3317
  ),
3295
- /* @__PURE__ */ jsx(S4, { queue: toasts, placement: "bottom-right" })
3318
+ /* @__PURE__ */ jsx(S3, { queue: toasts, placement: "bottom-right" })
3296
3319
  ] }) }),
3297
3320
  /* @__PURE__ */ jsx(Cell, { label: "Powerline", children: /* @__PURE__ */ jsx(
3298
3321
  r4,
@@ -3349,7 +3372,7 @@ function ToolChrome() {
3349
3372
  const [paneWidth, setPaneWidth] = useState(160);
3350
3373
  return /* @__PURE__ */ jsxs(Section, { title: "Tool chrome", children: [
3351
3374
  /* @__PURE__ */ jsx(Cell, { label: "ToolGroup, ToolButton", children: /* @__PURE__ */ jsx(n8, { orientation: "horizontal", ariaLabel: "Tools", children: ["select", "rect", "ellipse"].map((id) => /* @__PURE__ */ jsx(
3352
- o3,
3375
+ o4,
3353
3376
  {
3354
3377
  icon: /* @__PURE__ */ jsx(Dot, {}),
3355
3378
  label: id,
@@ -3360,14 +3383,14 @@ function ToolChrome() {
3360
3383
  },
3361
3384
  id
3362
3385
  )) }) }),
3363
- /* @__PURE__ */ jsx(Cell, { label: "ToolOptionsBar", children: /* @__PURE__ */ jsxs(c3, { label: "Text", children: [
3386
+ /* @__PURE__ */ jsx(Cell, { label: "ToolOptionsBar", children: /* @__PURE__ */ jsxs(c4, { label: "Text", children: [
3364
3387
  /* @__PURE__ */ jsx(c, { size: "sm", variant: "ghost", iconOnly: true, ariaLabel: "Bold", children: "B" }),
3365
3388
  /* @__PURE__ */ jsx(c, { size: "sm", variant: "ghost", iconOnly: true, ariaLabel: "Italic", children: "I" })
3366
3389
  ] }) }),
3367
3390
  /* @__PURE__ */ jsx(Cell, { label: "ResizeHandle", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__box", children: [
3368
3391
  /* @__PURE__ */ jsx("div", { className: "lk-specimen__box-main", children: "content" }),
3369
3392
  /* @__PURE__ */ jsx(
3370
- c4,
3393
+ c5,
3371
3394
  {
3372
3395
  value: paneWidth,
3373
3396
  min: 100,
@@ -3476,7 +3499,7 @@ function EditorsAndPlots() {
3476
3499
  }
3477
3500
  ) }),
3478
3501
  /* @__PURE__ */ jsx(Cell, { label: "BandEditor", wide: true, children: /* @__PURE__ */ jsx(
3479
- k,
3502
+ j2,
3480
3503
  {
3481
3504
  min: 1 / 64,
3482
3505
  max: 1 / 2,
@@ -3486,12 +3509,12 @@ function EditorsAndPlots() {
3486
3509
  onChange: setBands,
3487
3510
  selectedIndex: band,
3488
3511
  onSelect: setBand,
3489
- renderBand: (b3) => b3.data.name,
3512
+ renderBand: (b2) => b2.data.name,
3490
3513
  ticks: [1 / 24, 1 / 12, 1 / 6].map((at) => ({ at, label: `1/${Math.round(1 / at)}` }))
3491
3514
  }
3492
3515
  ) }),
3493
3516
  /* @__PURE__ */ jsx(Cell, { label: "Timeline", wide: true, children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__timeline", children: /* @__PURE__ */ jsx(
3494
- $2,
3517
+ ye,
3495
3518
  {
3496
3519
  tracks,
3497
3520
  duration: 2e3,
@@ -3554,6 +3577,6 @@ function Specimen({ className }) {
3554
3577
  ] });
3555
3578
  }
3556
3579
 
3557
- export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, AnnotationOverlay, AnnotationTargets, Lab, LabBoundary, LabPalette, LabRoot, LabShell, LabSwitcher, SPECIMEN_SECTIONS, Specimen, Trial, TrialBody, TrialChrome, Workspace, addTrial, annotationToolInfo, annotationsFromJSON, capturePlan, captureTarget, cloneTrial, closeTrial, composeCaptureSvg, createAnnotationScene, createAnnotationStore, createMarkDrawOne, currentPage, defineInstrument, fitView, fracContains, fracEncloses, fracToWorld, fromWeaselView, interstellarTheme, isStale, markCommands, markSvgNodes, reorderTrials, resetTrial, resolveMarkStyle, roundFrac, seenFrom, toWeaselView, validateConfigSchema, worldToFrac };
3580
+ export { AnnotationOverlay, AnnotationTargets, Lab, LabBoundary, LabPalette, LabRoot, LabShell, LabSwitcher, LabZoom, SPECIMEN_SECTIONS, Specimen, Trial, TrialBody, TrialChrome, Workspace, addTrial, annotationsFromJSON, capturePlan, captureTarget, cloneTrial, closeTrial, composeCaptureSvg, createAnnotationScene, createAnnotationStore, createMarkDrawOne, currentPage, defineInstrument, fitView, fracContains, fracEncloses, fracToWorld, fromWeaselView, interstellarTheme, isStale, reorderTrials, resetTrial, resolveMarkStyle, roundFrac, seenFrom, toWeaselView, validateConfigSchema, worldToFrac };
3558
3581
  //# sourceMappingURL=index.js.map
3559
3582
  //# sourceMappingURL=index.js.map