@weasel-js/labkit 1.7.0 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/README.md +3 -3
  2. package/dist/_dts/{CanvasStackContext-D2jnIwfk.d.ts → CanvasStackContext-Cjy6I-Iv.d.ts} +4 -1
  3. package/dist/_dts/{Stage-CCWfQQWM.d.ts → Stage-D6t7o0pF.d.ts} +3 -2
  4. package/dist/_dts/{index-CsYqUHD3.d.ts → index-BTmaRy6a.d.ts} +10 -6
  5. package/dist/_dts/{types-CSm9jgol.d.ts → index-DCMA4Fy1.d.ts} +59 -113
  6. package/dist/_dts/{types-CRPSGFAp.d.ts → types-BUBSIZuV.d.ts} +8 -7
  7. package/dist/_dts/{useTrialState-CTZPgeZ7.d.ts → useTrialState-Bh8bzFgE.d.ts} +1 -1
  8. package/dist/canvas/index.d.ts +8 -6
  9. package/dist/canvas/index.js +6 -6
  10. package/dist/chrome/index.d.ts +7 -5
  11. package/dist/chrome/index.js +10 -9
  12. package/dist/chunk-2ES4W47N.js +8 -0
  13. package/dist/chunk-2ES4W47N.js.map +1 -0
  14. package/dist/{chunk-WPLAANH4.js → chunk-2N7UBSS2.js} +12 -12
  15. package/dist/chunk-2N7UBSS2.js.map +1 -0
  16. package/dist/{chunk-275JRRVD.js → chunk-E23Q6A3Y.js} +232 -37
  17. package/dist/chunk-E23Q6A3Y.js.map +1 -0
  18. package/dist/{chunk-GOZLNM4L.js → chunk-E6NARGU7.js} +5 -5
  19. package/dist/{chunk-GOZLNM4L.js.map → chunk-E6NARGU7.js.map} +1 -1
  20. package/dist/{chunk-IJJUK4FU.js → chunk-EESJUSYR.js} +5 -6
  21. package/dist/chunk-EESJUSYR.js.map +1 -0
  22. package/dist/{chunk-HXXTULDN.js → chunk-EFXRM6XQ.js} +8 -11
  23. package/dist/chunk-EFXRM6XQ.js.map +1 -0
  24. package/dist/chunk-F4ACIK7Z.js +210 -0
  25. package/dist/chunk-F4ACIK7Z.js.map +1 -0
  26. package/dist/{chunk-AWQG7FCC.js → chunk-FG3EXZDV.js} +3 -3
  27. package/dist/{chunk-AWQG7FCC.js.map → chunk-FG3EXZDV.js.map} +1 -1
  28. package/dist/{chunk-YT75VYRD.js → chunk-IBVRMHW5.js} +5 -5
  29. package/dist/{chunk-YT75VYRD.js.map → chunk-IBVRMHW5.js.map} +1 -1
  30. package/dist/{chunk-RWNDDKOH.js → chunk-PMLZP7RT.js} +18 -15
  31. package/dist/chunk-PMLZP7RT.js.map +1 -0
  32. package/dist/{chunk-Y23G2VZL.js → chunk-READTDQX.js} +2 -2
  33. package/dist/chunk-READTDQX.js.map +1 -0
  34. package/dist/{chunk-I5DUQ5HM.js → chunk-RODIY7HI.js} +75 -72
  35. package/dist/chunk-RODIY7HI.js.map +1 -0
  36. package/dist/{chunk-JVBYV6TL.js → chunk-ROGJWDQA.js} +3 -3
  37. package/dist/{chunk-JVBYV6TL.js.map → chunk-ROGJWDQA.js.map} +1 -1
  38. package/dist/{chunk-ZIFPHIWZ.js → chunk-T6DLGEJB.js} +12 -14
  39. package/dist/chunk-T6DLGEJB.js.map +1 -0
  40. package/dist/chunk-U6UQVGFP.js +15583 -0
  41. package/dist/chunk-U6UQVGFP.js.map +1 -0
  42. package/dist/{chunk-24W5VEJW.js → chunk-ULYYNWGP.js} +2 -2
  43. package/dist/{chunk-24W5VEJW.js.map → chunk-ULYYNWGP.js.map} +1 -1
  44. package/dist/{chunk-UNAZSLWE.js → chunk-VYVGVBGY.js} +17 -20
  45. package/dist/chunk-VYVGVBGY.js.map +1 -0
  46. package/dist/chunk-WFALF2X2.js +302 -0
  47. package/dist/chunk-WFALF2X2.js.map +1 -0
  48. package/dist/{chunk-KMJ7RWD3.js → chunk-WLMDTI2Q.js} +3 -3
  49. package/dist/{chunk-KMJ7RWD3.js.map → chunk-WLMDTI2Q.js.map} +1 -1
  50. package/dist/{chunk-T5IBSPAM.js → chunk-WWJDPNZZ.js} +43 -33
  51. package/dist/chunk-WWJDPNZZ.js.map +1 -0
  52. package/dist/{chunk-J7OWWTCW.js → chunk-XE5HJOPL.js} +5 -6
  53. package/dist/chunk-XE5HJOPL.js.map +1 -0
  54. package/dist/{chunk-7BO7HNGF.js → chunk-XRX5S5NT.js} +8 -61
  55. package/dist/chunk-XRX5S5NT.js.map +1 -0
  56. package/dist/chunk-XVUKDSYV.js +38 -0
  57. package/dist/chunk-XVUKDSYV.js.map +1 -0
  58. package/dist/{chunk-FMK7UQ6V.js → chunk-XZDCEMEL.js} +64 -47
  59. package/dist/chunk-XZDCEMEL.js.map +1 -0
  60. package/dist/{chunk-FZ7YFQN7.js → chunk-YCFKW5RX.js} +3 -3
  61. package/dist/chunk-YCFKW5RX.js.map +1 -0
  62. package/dist/{chunk-CQLQPQ4P.js → chunk-ZQIHJXP4.js} +2 -2
  63. package/dist/chunk-ZQIHJXP4.js.map +1 -0
  64. package/dist/config/index.d.ts +18 -10
  65. package/dist/config/index.js +4 -4
  66. package/dist/controls/index.d.ts +58 -9
  67. package/dist/controls/index.js +7 -5
  68. package/dist/dragdrop/index.d.ts +23 -3
  69. package/dist/dragdrop/index.js +4 -3
  70. package/dist/fonts/oswald-tabular-digits.woff2 +0 -0
  71. package/dist/index.d.ts +61 -715
  72. package/dist/index.js +456 -432
  73. package/dist/index.js.map +1 -1
  74. package/dist/job/index.d.ts +8 -0
  75. package/dist/job/index.js +1 -1
  76. package/dist/layers/index.d.ts +6 -5
  77. package/dist/layers/index.js +3 -2
  78. package/dist/loupe/index.d.ts +100 -30
  79. package/dist/loupe/index.js +585 -6
  80. package/dist/loupe/index.js.map +1 -1
  81. package/dist/overview/index.d.ts +4 -2
  82. package/dist/overview/index.js +15 -14
  83. package/dist/overview/index.js.map +1 -1
  84. package/dist/passthrough/weasel-canvas.d.ts +2 -0
  85. package/dist/passthrough/weasel-ui.d.ts +2 -2871
  86. package/dist/passthrough/weasel-ui.js +3 -2
  87. package/dist/primitives/index.d.ts +213 -3
  88. package/dist/primitives/index.js +8 -7
  89. package/dist/state/index.d.ts +7 -5
  90. package/dist/state/index.js +6 -6
  91. package/dist/styles.css +284 -51
  92. package/dist/surface/index.d.ts +10 -2
  93. package/dist/surface/index.js +1 -1
  94. package/dist/undo/index.d.ts +5 -3
  95. package/package.json +11 -11
  96. package/src/annotations/AnnotationOverlay.abandon.test.tsx +143 -0
  97. package/src/annotations/AnnotationOverlay.tsx +50 -31
  98. package/src/annotations/Annotations.overlay.test.tsx +31 -0
  99. package/src/annotations/capture.browser.test.ts +47 -0
  100. package/src/annotations/capture.ts +14 -7
  101. package/src/annotations/drawOne.ts +2 -2
  102. package/src/annotations/frac.test.ts +44 -1
  103. package/src/annotations/frac.ts +46 -18
  104. package/src/annotations/index.ts +1 -0
  105. package/src/annotations/paint.test.ts +74 -33
  106. package/src/annotations/paint.ts +70 -32
  107. package/src/annotations/store.test.ts +212 -2
  108. package/src/annotations/store.ts +130 -27
  109. package/src/annotations/svgNodes.test.ts +22 -10
  110. package/src/annotations/svgNodes.ts +3 -3
  111. package/src/annotations/types.ts +29 -10
  112. package/src/canvas/CameraInput.test.tsx +30 -0
  113. package/src/canvas/CameraInput.tsx +16 -15
  114. package/src/canvas/CanvasStack.tsx +5 -5
  115. package/src/canvas/CanvasStackContext.ts +4 -1
  116. package/src/canvas/Stage.test.tsx +34 -25
  117. package/src/canvas/Stage.tsx +3 -3
  118. package/src/canvas/cameraRegistry.ts +1 -0
  119. package/src/canvas/worldSpec.ts +3 -1
  120. package/src/chrome/builtins.test.ts +7 -6
  121. package/src/chrome/builtins.tsx +5 -1
  122. package/src/chrome/index.ts +1 -1
  123. package/src/chrome/labRegions.test.tsx +37 -26
  124. package/src/chrome/merge.test.ts +5 -0
  125. package/src/chrome/merge.ts +4 -2
  126. package/src/chrome/regions/PaletteRegion.test.tsx +4 -5
  127. package/src/chrome/regions/PaletteRegion.tsx +3 -4
  128. package/src/chrome/regions/ViewportRegion.browser.test.less +6 -0
  129. package/src/chrome/regions/ViewportRegion.browser.test.tsx +38 -0
  130. package/src/chrome/regions/ViewportRegion.less +6 -0
  131. package/src/chrome/regions/ViewportRegion.tsx +10 -4
  132. package/src/chrome/types.ts +4 -2
  133. package/src/config/auto.ts +1 -0
  134. package/src/config/builder.ts +6 -0
  135. package/src/config/types.ts +2 -1
  136. package/src/controls/ControlMatrix.less +245 -0
  137. package/src/controls/ControlMatrix.stories.less +13 -0
  138. package/src/controls/ControlMatrix.stories.tsx +135 -0
  139. package/src/controls/ControlMatrix.test.tsx +206 -0
  140. package/src/controls/ControlMatrix.tsx +446 -0
  141. package/src/controls/ControlPanel.test.tsx +37 -3
  142. package/src/controls/ControlPanel.tsx +16 -5
  143. package/src/controls/index.ts +6 -0
  144. package/src/dragdrop/DragDropRuntime.tsx +22 -13
  145. package/src/dragdrop/DragGhost.tsx +3 -0
  146. package/src/dragdrop/Palette.tsx +2 -0
  147. package/src/dragdrop/dragDrop.test.tsx +34 -33
  148. package/src/index.test.ts +5 -0
  149. package/src/index.ts +7 -1
  150. package/src/instrument/types.ts +0 -6
  151. package/src/job/useJob.ts +14 -9
  152. package/src/lab/Lab.chrome.test.tsx +15 -10
  153. package/src/lab/Lab.nebula.test.tsx +5 -5
  154. package/src/lab/Lab.surface.test.tsx +30 -21
  155. package/src/lab/Lab.test.tsx +75 -74
  156. package/src/lab/Lab.tsx +5 -1
  157. package/src/lab/Lab.undock.test.tsx +15 -10
  158. package/src/lab/LabHeader.test.tsx +15 -14
  159. package/src/lab/LabPalette.test.tsx +12 -7
  160. package/src/lab/LabShell.less +1 -1
  161. package/src/lab/LabSwitcher.browser.test.tsx +27 -0
  162. package/src/lab/LabSwitcher.less +2 -0
  163. package/src/lab/LabZoom.test.tsx +55 -44
  164. package/src/lab/LabZoom.tsx +4 -4
  165. package/src/lab/Workspace.surface.test.tsx +16 -13
  166. package/src/lab/Workspace.test.tsx +32 -27
  167. package/src/lab/Workspace.tsx +48 -52
  168. package/src/loupe/AGENTS.md +28 -15
  169. package/src/loupe/CanvasLoupe.tsx +2 -3
  170. package/src/loupe/DomLoupe.tsx +1 -7
  171. package/src/loupe/Loupe.less +16 -0
  172. package/src/loupe/TrialLoupe.tsx +120 -57
  173. package/src/loupe/index.ts +1 -6
  174. package/src/loupe/types.test.ts +3 -3
  175. package/src/loupe/types.ts +24 -27
  176. package/src/loupe/useLoupe.test.tsx +29 -4
  177. package/src/loupe/useLoupe.ts +20 -17
  178. package/src/overview/OverviewMarks.test.tsx +9 -8
  179. package/src/overview/OverviewMarks.tsx +12 -4
  180. package/src/overview/TrialOverview.test.tsx +18 -17
  181. package/src/overview/TrialOverview.tsx +3 -3
  182. package/src/passthrough/weasel-ui.test.ts +1 -1
  183. package/src/passthrough/weasel-ui.ts +1 -1
  184. package/src/primitives/FloatingPanel.tsx +7 -3
  185. package/src/primitives/FpsMeter.less +1 -2
  186. package/src/primitives/JobProgress.less +1 -1
  187. package/src/primitives/Readout.test.tsx +2 -2
  188. package/src/primitives/ScaleIndicator.less +1 -1
  189. package/src/primitives/Split.tsx +69 -41
  190. package/src/primitives/StatusBar.less +1 -1
  191. package/src/primitives/Toolbar.tsx +3 -3
  192. package/src/primitives/ZoomControl.less +1 -2
  193. package/src/specimen/Specimen.less +1 -0
  194. package/src/specimen/Specimen.tsx +0 -1
  195. package/src/state/undock.ts +3 -0
  196. package/src/state/useOpenOnce.ts +20 -16
  197. package/src/state/view.ts +1 -0
  198. package/src/styles.less +3 -0
  199. package/src/surface/index.ts +1 -1
  200. package/src/surface/useTiledSurface.test.tsx +14 -0
  201. package/src/surface/useTiledSurface.ts +11 -3
  202. package/src/trial/Trial.annotations.persist.test.tsx +20 -9
  203. package/src/trial/Trial.annotations.test.tsx +105 -27
  204. package/src/trial/Trial.canvas.test.tsx +21 -17
  205. package/src/trial/Trial.config.test.tsx +34 -27
  206. package/src/trial/Trial.less +0 -16
  207. package/src/trial/Trial.loupe.test.tsx +51 -25
  208. package/src/trial/Trial.targets.test.tsx +9 -8
  209. package/src/trial/Trial.test.tsx +51 -46
  210. package/src/trial/Trial.trialId.test.tsx +7 -6
  211. package/src/trial/Trial.tsx +74 -62
  212. package/src/trial/TrialChrome.tsx +6 -3
  213. package/src/trial/index.ts +2 -0
  214. package/src/trial/loupeSwitch.ts +15 -0
  215. package/dist/_dts/LayerList.d-DiuEArKq.d.ts +0 -83
  216. package/dist/_dts/PrefsRow.d-TOZ7BgD9.d.ts +0 -79
  217. package/dist/_dts/PropertyPanel.d-D-1paCbE.d.ts +0 -141
  218. package/dist/_dts/Select.d-Bensr_MT.d.ts +0 -579
  219. package/dist/_dts/index-B2Yj5aA0.d.ts +0 -274
  220. package/dist/chunk-275JRRVD.js.map +0 -1
  221. package/dist/chunk-4LJSC7MB.js +0 -143
  222. package/dist/chunk-4LJSC7MB.js.map +0 -1
  223. package/dist/chunk-7BO7HNGF.js.map +0 -1
  224. package/dist/chunk-CQLQPQ4P.js.map +0 -1
  225. package/dist/chunk-FMK7UQ6V.js.map +0 -1
  226. package/dist/chunk-FZ7YFQN7.js.map +0 -1
  227. package/dist/chunk-HXXTULDN.js.map +0 -1
  228. package/dist/chunk-I5DUQ5HM.js.map +0 -1
  229. package/dist/chunk-IJJUK4FU.js.map +0 -1
  230. package/dist/chunk-J7OWWTCW.js.map +0 -1
  231. package/dist/chunk-M7HP3FTK.js +0 -549
  232. package/dist/chunk-M7HP3FTK.js.map +0 -1
  233. package/dist/chunk-MIM5R4ZT.js +0 -14972
  234. package/dist/chunk-MIM5R4ZT.js.map +0 -1
  235. package/dist/chunk-RWNDDKOH.js.map +0 -1
  236. package/dist/chunk-T5IBSPAM.js.map +0 -1
  237. package/dist/chunk-UNAZSLWE.js.map +0 -1
  238. package/dist/chunk-WPLAANH4.js.map +0 -1
  239. package/dist/chunk-Y23G2VZL.js.map +0 -1
  240. package/dist/chunk-ZIFPHIWZ.js.map +0 -1
  241. package/src/primitives/useRovingTabIndex.test.ts +0 -48
  242. package/src/primitives/useRovingTabIndex.ts +0 -88
package/dist/index.js CHANGED
@@ -1,66 +1,68 @@
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';
1
+ import { LoupeSwitchContext } from './chunk-2ES4W47N.js';
2
+ export { LoupeSwitchContext } from './chunk-2ES4W47N.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-WPLAANH4.js';
6
- import { useTiledSurface } from './chunk-IJJUK4FU.js';
7
- export { composeRects, rectsEqual, toDeviceRect, useTiledSurface } from './chunk-IJJUK4FU.js';
8
- import { useJob } from './chunk-HXXTULDN.js';
9
- export { useJob } from './chunk-HXXTULDN.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';
5
+ import { useDragDrop, DragOverlay, Palette } from './chunk-2N7UBSS2.js';
6
+ import { useTiledSurface } from './chunk-EESJUSYR.js';
7
+ export { composeRects, toDeviceRect, useTiledSurface } from './chunk-EESJUSYR.js';
8
+ import { useJob } from './chunk-EFXRM6XQ.js';
9
+ export { useJob } from './chunk-EFXRM6XQ.js';
10
+ import { markCommands, boundsOf, roundFrac, worldToFrac, fracToWorld, fracEncloses, fracContains, POINT_MARK_SHAPE, roundPoints, fromShape, markSvgNodes, toShape } from './chunk-F4ACIK7Z.js';
11
+ export { fracContains, fracEncloses, fracToWorld, markCommands, markSvgNodes, roundFrac, worldToFrac } from './chunk-F4ACIK7Z.js';
12
+ import { ANNOTATION_WEASEL_TOOLS, annotationToolInfo, suppressContributions, mergeContributions, builtinContributions, TRANSIENT_BUILTINS, TitleBarRegion, ToolbarRegion, PaletteRegion, ViewportRegion, SidebarRegion, StatusRegion, resolveLabTool, useLabChromeContext, labContributions, labAnnotationTools, LabHeaderRegion, LabFooterRegion, LabAsideRegion, LabSidebarRegion } from './chunk-RODIY7HI.js';
13
+ export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, ExportMenu, LabAsideRegion, LabFooterRegion, LabHeaderRegion, LabSidebarRegion, MarkList, PaletteRegion, SidebarRegion, StatusRegion, TRANSIENT_BUILTINS, TitleBarRegion, ToolbarRegion, ViewportRegion, annotationToolInfo, builtinContributions, contributionsIn, labContributions, mergeContributions, suppressContributions, toolContributions, useLabChromeContext } from './chunk-RODIY7HI.js';
14
14
  import { AnnotationsContext } from './chunk-3RY6WL5T.js';
15
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';
16
+ import { Split, JobProgress, Legend } from './chunk-XZDCEMEL.js';
17
+ export { JobProgress, Legend, Readout, Split } from './chunk-XZDCEMEL.js';
18
+ import { FloatingPanel } from './chunk-XE5HJOPL.js';
19
+ export { FloatingPanel } from './chunk-XE5HJOPL.js';
20
+ import { Toolbar, StatusBar, ScaleIndicator, ZoomControl } from './chunk-XRX5S5NT.js';
21
+ export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl } from './chunk-XRX5S5NT.js';
22
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';
25
- import { newId, useWarnIgnoredChange, useOpenOnce, PersistenceContext, createRecordCache, noneAdapter, defaultStorage, usePersistedState } from './chunk-RWNDDKOH.js';
26
- export { Persistence, createIndexedDbAdapter, createMemoryAdapter, indexedDbAdapter, localStorageAdapter, noneAdapter, sessionStorageAdapter, urlHashAdapter, usePersistedState } from './chunk-RWNDDKOH.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';
23
+ import { unruledConfigSchema, createLabStore, openLabStore, panelKey } from './chunk-IBVRMHW5.js';
24
+ export { CURRENT_DOCUMENT_VERSION, dockPanel, labDocumentKey, openLabStore, panelKey, quarantineKey, undockPanel, useTrialState } from './chunk-IBVRMHW5.js';
25
+ import { newId, useWarnIgnoredChange, useOpenOnce, PersistenceContext, createRecordCache, noneAdapter, defaultStorage, usePersistedState } from './chunk-PMLZP7RT.js';
26
+ export { Persistence, createIndexedDbAdapter, createMemoryAdapter, indexedDbAdapter, localStorageAdapter, noneAdapter, sessionStorageAdapter, urlHashAdapter, usePersistedState } from './chunk-PMLZP7RT.js';
27
+ export { ControlMatrix } from './chunk-WFALF2X2.js';
28
+ export { ControlPanel, inDialog, summarizeValue } from './chunk-WWJDPNZZ.js';
29
+ import { useConfigSchema } from './chunk-E6NARGU7.js';
30
+ export { sectionTree, useConfigSchema } from './chunk-E6NARGU7.js';
30
31
  import { useLabContext, LabContext } from './chunk-Z76KEZAX.js';
31
32
  export { LabContext, useLabContext } from './chunk-Z76KEZAX.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';
33
+ import { useResolvedConfig } from './chunk-YCFKW5RX.js';
34
+ export { BaseNode, BooleanNode, ColorNode, CustomNode, EnumNode, GroupNode, ListNode, NumberNode, StringNode, ValueNode, applyRules, builtinRules, f, isConfigBranch, resolveConfigSchema, titleCase, useResolvedConfig } from './chunk-YCFKW5RX.js';
35
+ export { fromConfigFields, isLeafVisible } from './chunk-WLMDTI2Q.js';
36
+ import { hasConfigPath, schemaNodeAtPath, applyConfigWrite, resolveAutoConfig, isAuto, isRecord, autoPathsOf, fillConfigDefaults } from './chunk-READTDQX.js';
37
+ export { auto, autoPathsOf, fillConfigDefaults, hasConfigPath, isAuto, resolveAutoConfig, schemaNodeAtPath, valueAtPath, withValueAtPath } from './chunk-READTDQX.js';
38
+ import { CanvasStack, Stage, fitStage } from './chunk-T6DLGEJB.js';
39
+ export { CanvasStack, Stage, fitStage } from './chunk-T6DLGEJB.js';
40
+ export { centerOn, zoomAt } from './chunk-ROGJWDQA.js';
41
+ export { screenToWorld, worldToScreen } from './chunk-FG3EXZDV.js';
41
42
  import { useSurfaceOptional, useSurfaceCanvas, useTileId, SurfaceContext, SurfaceCanvasContext } from './chunk-WIG6XHJ7.js';
42
43
  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';
47
- import { CanvasStackContext } from './chunk-CQLQPQ4P.js';
48
- export { CanvasStackContext } from './chunk-CQLQPQ4P.js';
44
+ import { CameraWheelContext, as2DView, CameraRegistryContext, DEFAULT_VIEW, CameraPublishContext, createCameraRegistry, withZoom } from './chunk-VYVGVBGY.js';
45
+ export { CameraContext, CameraInput, CameraPublishContext, CameraRegistryContext, CameraScope, DEFAULT_VIEW, as2DView, createCameraRegistry, usePublishCamera } from './chunk-VYVGVBGY.js';
46
+ import { applyCamera } from './chunk-ULYYNWGP.js';
47
+ export { DEFAULT_FRAME, applyCamera, resolveFrame } from './chunk-ULYYNWGP.js';
48
+ import { CanvasStackContext } from './chunk-ZQIHJXP4.js';
49
+ export { CanvasStackContext } from './chunk-ZQIHJXP4.js';
49
50
  import { LabStoreContext, TrialIdProvider, TrialIdContext } from './chunk-2YILQ7Y5.js';
50
51
  export { LabStoreContext, LabStoreProvider, TrialIdContext, TrialIdProvider, useLabStore, useTrialId } from './chunk-2YILQ7Y5.js';
51
52
  import './chunk-2RVCB2PT.js';
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';
53
+ import { D2, S2, X, U, G, p4, o3, c, Xt, c6, a6, l5, u3, a5, r3, a8, i3, o5, s4, c7, l9, p, f2, u2, y, O2, b4, l10, S, c8, i4, h2, j, k2, ae2, oe, de, b3, j2, n6, a9, C3, l3, u, v2, d3, j3, r4, n7, r5, i5, p2, f, n8, o4, c5, l8, w, L, n9, j4, xe2, n2 } from './chunk-U6UQVGFP.js';
54
+ export { c as Button, V as CloseIcon, xe as CollapseIcon, _ as CurveField, s as DetailList, c2 as DetailRow, Se as ExpandIcon, l as Icon, u2 as Input, l11 as Jog, D2 as LayerList, re as PauseIcon, ne as PlayIcon, fe2 as PropertyControl, de as PropertyField, b3 as PropertyGroup, oe as PropertyList, ae2 as PropertyPanel, L2 as PropertyRow, se as PropertySpan, B as ResetIcon, O2 as Select, ae as StepBackIcon, $ as StepForwardIcon, ie as StopIcon, x2 as Subpanel, a5 as ToggleBar, oe2 as TokenPanel, H2 as inferTokenType, S2 as moveLayers, O3 as refitScale } from './chunk-U6UQVGFP.js';
55
+ import { serializeSvg } from './chunk-E23Q6A3Y.js';
56
+ import './chunk-XVUKDSYV.js';
57
+ import { makeViewportZoomAction, createScene, asNodeId as asNodeId$1, registerNodeShape, useLatest, WeaselProvider, SceneCanvas, createPointerStore, PointerContextProvider, DepRegistryProvider, ActionsProvider, ActiveToolContextProvider, useActionsRegistry, useDepSource, ActionDisabledReason, useGestureDispatcher, sceneFromJSON, warmRender, renderSceneToPixels, useActiveToolContext } from '@weasel-js/core';
58
+ import { createContext, useState, useRef, useEffect, useInsertionEffect, useCallback, useContext, useMemo, useSyncExternalStore, useLayoutEffect, useId, Children } from 'react';
57
59
  import { flushSync, createPortal } from 'react-dom';
58
60
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
59
61
  import { defineTheme, weaselTheme, colorCount, resolveTheme, colorAt } from '@weasel-js/theme';
60
62
  import { useResolvedColorMode, useThemeOptional, ThemeProvider, ThemeContext } from '@weasel-js/theme/react';
61
63
  import { useStore } from 'zustand/react';
62
64
  import { Provider, StrategyRegistryProvider, DragProvider, Container, useDragHandle } from 'windease/react';
63
- import { asNodeId, Store, createNode, floatingStrategy, gridStrategy } from 'windease';
65
+ import { asNodeId, createNode, floatingStrategy, gridStrategy, Store } from 'windease';
64
66
  import { Focusable } from 'react-aria-components';
65
67
 
66
68
  // src/annotations/staleness.ts
@@ -68,8 +70,8 @@ function seenFrom(config, keys) {
68
70
  const out = {};
69
71
  if (config === null || typeof config !== "object") return out;
70
72
  const src = config;
71
- for (const k of keys) {
72
- if (k in src) out[k] = src[k];
73
+ for (const k2 of keys) {
74
+ if (k2 in src) out[k2] = src[k2];
73
75
  }
74
76
  return out;
75
77
  }
@@ -77,20 +79,20 @@ function isStale(seen, config, keys) {
77
79
  if (!seen || keys.length === 0) return false;
78
80
  if (config === null || typeof config !== "object") return false;
79
81
  const src = config;
80
- for (const k of keys) {
81
- if (!(k in seen)) continue;
82
- if (!Object.is(seen[k], src[k])) return true;
82
+ for (const k2 of keys) {
83
+ if (!(k2 in seen)) continue;
84
+ if (!Object.is(seen[k2], src[k2])) return true;
83
85
  }
84
86
  return false;
85
87
  }
86
88
 
87
89
  // src/annotations/drawOne.ts
88
90
  function createMarkDrawOne(opts) {
89
- return (node, pose) => markCommands({ pose, data: node.data }, opts.content, resolveMarkStyle(node.data, opts));
91
+ return (node, pose, view) => markCommands({ pose, data: node.data }, resolveMarkStyle(node.data, opts), view.scale);
90
92
  }
91
93
  function resolveMarkStyle(data, opts) {
92
94
  return {
93
- color: opts.meaning?.statuses?.find((s2) => s2.id === data.status)?.color,
95
+ color: opts.meaning?.statuses?.find((s3) => s3.id === data.status)?.color,
94
96
  // Read off the node rather than through the store's `isStale`, which
95
97
  // wants a projected Annotation this path does not have.
96
98
  stale: isStale(data.seen, opts.config, opts.positionDependsOn ?? [])
@@ -103,7 +105,7 @@ function capturePlan(base, format) {
103
105
  if (format === "svg") return "svg-document";
104
106
  return base?.kind === "svg" ? "svg-document" : "raster-stack";
105
107
  }
106
- function nestBaseSvg(markup, w2, h) {
108
+ function nestBaseSvg(markup, w2, h2) {
107
109
  const doc = new DOMParser().parseFromString(markup, "image/svg+xml");
108
110
  const root = doc.documentElement;
109
111
  if (doc.getElementsByTagName("parsererror").length > 0 || root.localName !== "svg") {
@@ -112,40 +114,40 @@ function nestBaseSvg(markup, w2, h) {
112
114
  root.setAttribute("x", "0");
113
115
  root.setAttribute("y", "0");
114
116
  root.setAttribute("width", String(w2));
115
- root.setAttribute("height", String(h));
117
+ root.setAttribute("height", String(h2));
116
118
  return new XMLSerializer().serializeToString(root);
117
119
  }
118
- function embedRasterBase(base, w2, h, onWarn) {
120
+ function embedRasterBase(base, w2, h2, onWarn) {
119
121
  const href = base.kind === "canvas" ? base.canvas.toDataURL() : base.kind === "image" ? base.src : "";
120
122
  if (base.kind === "image" && !href.startsWith("data:")) {
121
123
  onWarn?.(`base image '${href}' is a reference, so this SVG is not self-contained`);
122
124
  }
123
- return serializeSvg([{ kind: "image", href, x: 0, y: 0, width: w2, height: h }], {
124
- viewBox: { x: 0, y: 0, width: w2, height: h }
125
+ return serializeSvg([{ kind: "image", href, x: 0, y: 0, width: w2, height: h2 }], {
126
+ viewBox: { x: 0, y: 0, width: w2, height: h2 }
125
127
  });
126
128
  }
127
- function markNodesOf(scene, draw) {
129
+ function markNodesOf(scene, draw, scale) {
128
130
  return [...scene.renderOrder()].flatMap((id) => {
129
131
  const node = scene.get(asNodeId$1(String(id)));
130
132
  if (!node) return [];
131
133
  return markSvgNodes(
132
134
  { pose: node.pose, data: node.data },
133
- draw.content,
134
- resolveMarkStyle(node.data, draw)
135
+ resolveMarkStyle(node.data, draw),
136
+ { x: scale, y: scale }
135
137
  );
136
138
  });
137
139
  }
138
140
  function composeCaptureSvg(args) {
139
141
  const { base, scene, draw, scale, onWarn } = args;
140
- const { w: w2, h } = draw.content;
141
- const baseXml = base === void 0 ? "" : base.kind === "svg" ? nestBaseSvg(base.markup, w2, h) : embedRasterBase(base, w2, h, onWarn);
142
- const marksXml = serializeSvg(markNodesOf(scene, draw), {
143
- viewBox: { x: 0, y: 0, width: w2, height: h },
142
+ const { w: w2, h: h2 } = draw.content;
143
+ const baseXml = base === void 0 ? "" : base.kind === "svg" ? nestBaseSvg(base.markup, w2, h2) : embedRasterBase(base, w2, h2, onWarn);
144
+ const marksXml = serializeSvg(markNodesOf(scene, draw, scale), {
145
+ viewBox: { x: 0, y: 0, width: w2, height: h2 },
144
146
  onWarn
145
147
  });
146
148
  const outW = Math.max(1, Math.round(w2 * scale));
147
- const outH = Math.max(1, Math.round(h * scale));
148
- return `<svg xmlns="${SVG_NS}" width="${outW}" height="${outH}" viewBox="0 0 ${w2} ${h}">${baseXml}${marksXml}</svg>`;
149
+ const outH = Math.max(1, Math.round(h2 * scale));
150
+ return `<svg xmlns="${SVG_NS}" width="${outW}" height="${outH}" viewBox="0 0 ${w2} ${h2}">${baseXml}${marksXml}</svg>`;
149
151
  }
150
152
  function context2d(width, height) {
151
153
  const canvas = document.createElement("canvas");
@@ -195,12 +197,14 @@ async function stackRaster(args) {
195
197
  const ctx = context2d(width, height);
196
198
  if (base?.kind === "image") ctx.drawImage(await loadImage(base.src), 0, 0, width, height);
197
199
  else if (base?.kind === "canvas") ctx.drawImage(base.canvas, 0, 0, width, height);
198
- const raster = renderSceneToPixels({
200
+ const render = {
199
201
  scene,
200
202
  sourceRect: { x: 0, y: 0, width: draw.content.w, height: draw.content.h },
201
203
  scale: { x: scale, y: scale },
202
204
  drawOne: createMarkDrawOne(draw)
203
- });
205
+ };
206
+ await warmRender({ render });
207
+ const raster = renderSceneToPixels(render);
204
208
  const marks = context2d(raster.width, raster.height);
205
209
  marks.putImageData(
206
210
  new ImageData(Uint8ClampedArray.from(raster.data), raster.width, raster.height),
@@ -238,36 +242,6 @@ async function captureTarget(args, opts = {}) {
238
242
  return { target: args.target, blob, format, width, height };
239
243
  }
240
244
 
241
- // src/annotations/frac.ts
242
- function fracToWorld(f5, content) {
243
- return {
244
- x: f5.x * content.w,
245
- y: f5.y * content.h,
246
- width: f5.w * content.w,
247
- height: f5.h * content.h
248
- };
249
- }
250
- function worldToFrac(r4, content) {
251
- const sx = content.w === 0 ? 0 : 1 / content.w;
252
- const sy = content.h === 0 ? 0 : 1 / content.h;
253
- return { x: r4.x * sx, y: r4.y * sy, w: r4.width * sx, h: r4.height * sy };
254
- }
255
- var DP = 1e4;
256
- function roundFrac(f5) {
257
- return {
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
262
- };
263
- }
264
- function fracContains(box, pt, tol = 0) {
265
- return pt.x >= box.x - tol && pt.x <= box.x + box.w + tol && pt.y >= box.y - tol && pt.y <= box.y + box.h + tol;
266
- }
267
- function fracEncloses(outer, inner) {
268
- return inner.x >= outer.x && inner.y >= outer.y && inner.x + inner.w <= outer.x + outer.w && inner.y + inner.h <= outer.y + outer.h;
269
- }
270
-
271
245
  // src/annotations/history.ts
272
246
  var MarkHistory = class {
273
247
  depth = /* @__PURE__ */ new Map();
@@ -300,8 +274,8 @@ var MarkHistory = class {
300
274
  /** The target `undo` would act on, skipping any whose scene has nothing
301
275
  * left — a scene can drop entries this ordering still lists. */
302
276
  next(stack, can, at) {
303
- for (let i5 = stack.length - 1; i5 >= 0; i5--) {
304
- const target = stack[i5];
277
+ for (let i4 = stack.length - 1; i4 >= 0; i4--) {
278
+ const target = stack[i4];
305
279
  if (target === void 0) continue;
306
280
  const scene = at(target);
307
281
  if (scene && can(scene)) return target;
@@ -309,13 +283,13 @@ var MarkHistory = class {
309
283
  return null;
310
284
  }
311
285
  canUndo(at) {
312
- return this.next(this.undoable, (s2) => s2.canUndo(), at) !== null;
286
+ return this.next(this.undoable, (s3) => s3.canUndo(), at) !== null;
313
287
  }
314
288
  canRedo(at) {
315
- return this.next(this.redoable, (s2) => s2.canRedo(), at) !== null;
289
+ return this.next(this.redoable, (s3) => s3.canRedo(), at) !== null;
316
290
  }
317
291
  undo(at) {
318
- const target = this.next(this.undoable, (s2) => s2.canUndo(), at);
292
+ const target = this.next(this.undoable, (s3) => s3.canUndo(), at);
319
293
  const scene = target === null ? void 0 : at(target);
320
294
  if (!scene) return false;
321
295
  this.replaying = "undo";
@@ -326,7 +300,7 @@ var MarkHistory = class {
326
300
  }
327
301
  }
328
302
  redo(at) {
329
- const target = this.next(this.redoable, (s2) => s2.canRedo(), at);
303
+ const target = this.next(this.redoable, (s3) => s3.canRedo(), at);
330
304
  const scene = target === null ? void 0 : at(target);
331
305
  if (!scene) return false;
332
306
  this.replaying = "redo";
@@ -338,9 +312,9 @@ var MarkHistory = class {
338
312
  }
339
313
  };
340
314
  function drop(stack, value) {
341
- for (let i5 = stack.length - 1; i5 >= 0; i5--) {
342
- if (stack[i5] === value) {
343
- stack.splice(i5, 1);
315
+ for (let i4 = stack.length - 1; i4 >= 0; i4--) {
316
+ if (stack[i4] === value) {
317
+ stack.splice(i4, 1);
344
318
  return;
345
319
  }
346
320
  }
@@ -349,6 +323,19 @@ function createAnnotationScene() {
349
323
  return createScene({ systemLayers: [{ id: "marks" }] });
350
324
  }
351
325
  var NO_CONTENT = { w: 0, h: 0 };
326
+ function shapeFor(kind, points, frac) {
327
+ if (!points || kind === "point") return void 0;
328
+ return roundPoints(toShape(points, frac));
329
+ }
330
+ function migrateLegacyPoints(raw, content) {
331
+ const nodes = raw.nodes.map((n6) => {
332
+ const { points, ...data } = n6.data;
333
+ if (!points || data.shape) return n6;
334
+ const shape = shapeFor(data.kind, points, worldToFrac(n6.pose, content));
335
+ return { ...n6, data: { ...data, ...shape ? { shape } : {} } };
336
+ });
337
+ return { ...raw, nodes };
338
+ }
352
339
  function splitId(id) {
353
340
  const at = id.lastIndexOf("/");
354
341
  return at <= 0 ? void 0 : { target: id.slice(0, at), node: id.slice(at + 1) };
@@ -361,26 +348,63 @@ function createAnnotationStore(opts) {
361
348
  const notify = () => {
362
349
  for (const fn of subs) fn();
363
350
  };
351
+ let holding = 0;
352
+ let heldDirty = false;
353
+ const hold = (fn) => {
354
+ holding += 1;
355
+ try {
356
+ fn();
357
+ } finally {
358
+ holding -= 1;
359
+ }
360
+ if (holding === 0 && heldDirty) {
361
+ heldDirty = false;
362
+ notify();
363
+ }
364
+ };
365
+ const exclusive = () => (typeof opts.selection === "function" ? opts.selection() : opts.selection) !== "per-target";
366
+ const lastSelection = /* @__PURE__ */ new Map();
367
+ const selectionKey = (scene) => scene.getSelection().map(String).join(" ");
368
+ const clearOthers = (keep) => {
369
+ for (const [target, scene] of scenes) {
370
+ if (target !== keep && scene.getSelection().length > 0) scene.setSelection([]);
371
+ }
372
+ };
373
+ const targetOf = (id) => targets().find((t) => t.id === id);
374
+ const contentOf = (id) => targetOf(id)?.content ?? NO_CONTENT;
364
375
  const sceneFor = (target) => {
365
376
  const known = scenes.get(target);
366
377
  if (known) return known;
367
378
  const raw = restore?.[target];
368
379
  const scene = raw ? sceneFromJSON(
369
- raw,
380
+ migrateLegacyPoints(raw, contentOf(target)),
370
381
  {}
371
382
  ) : createAnnotationScene();
372
383
  scenes.set(target, scene);
373
384
  history.track(target, scene);
385
+ lastSelection.set(target, selectionKey(scene));
374
386
  scene.subscribe(() => {
375
387
  history.observe(target, scene);
376
- notify();
388
+ const selected = selectionKey(scene);
389
+ const newlySelected = selected !== "" && selected !== lastSelection.get(target);
390
+ lastSelection.set(target, selected);
391
+ if (holding > 0) {
392
+ heldDirty = true;
393
+ return;
394
+ }
395
+ if (newlySelected && exclusive()) {
396
+ hold(() => {
397
+ heldDirty = true;
398
+ clearOthers(target);
399
+ });
400
+ } else {
401
+ notify();
402
+ }
377
403
  });
378
404
  return scene;
379
405
  };
380
406
  const historySceneAt = (target) => scenes.get(target);
381
407
  for (const target of Object.keys(restore ?? {})) sceneFor(target);
382
- const targetOf = (id) => targets().find((t) => t.id === id);
383
- const contentOf = (id) => targetOf(id)?.content ?? NO_CONTENT;
384
408
  const drawOptionsFor = (info) => ({
385
409
  content: info.content,
386
410
  positionDependsOn: info.positionDependsOn,
@@ -390,12 +414,10 @@ function createAnnotationStore(opts) {
390
414
  const project = (target, node) => {
391
415
  const found = scenes.get(target)?.get(asNodeId$1(node));
392
416
  if (!found) return void 0;
393
- return {
394
- ...found.data,
395
- target,
396
- id: `${target}/${node}`,
397
- frac: roundFrac(worldToFrac(found.pose, contentOf(target)))
398
- };
417
+ const { shape, ...data } = found.data;
418
+ const frac = roundFrac(worldToFrac(found.pose, contentOf(target)));
419
+ const points = data.kind === "point" ? [{ x: frac.x, y: frac.y }] : shape && roundPoints(fromShape(shape, frac));
420
+ return { ...data, target, id: `${target}/${node}`, frac, ...points ? { points } : {} };
399
421
  };
400
422
  const liveTargets = () => {
401
423
  const declared = targets().map((t) => t.id);
@@ -407,21 +429,21 @@ function createAnnotationStore(opts) {
407
429
  if (!scene) return [];
408
430
  const out = [];
409
431
  for (const id of scene.renderOrder()) {
410
- const a6 = project(target, String(id));
411
- if (a6) out.push(a6);
432
+ const a5 = project(target, String(id));
433
+ if (a5) out.push(a5);
412
434
  }
413
435
  return out;
414
436
  };
415
437
  const all = () => liveTargets().flatMap(marksOn);
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;
438
+ const matches = (a5, q) => {
439
+ if (q.target !== void 0 && a5.target !== q.target) return false;
440
+ if (q.kind !== void 0 && a5.kind !== q.kind) return false;
441
+ if (q.status !== void 0 && a5.status !== q.status) return false;
420
442
  if (q.tags !== void 0) {
421
- const have = a6.tags ?? [];
443
+ const have = a5.tags ?? [];
422
444
  for (const t of q.tags) if (!have.includes(t)) return false;
423
445
  }
424
- if (q.where && !q.where(a6)) return false;
446
+ if (q.where && !q.where(a5)) return false;
425
447
  return true;
426
448
  };
427
449
  const nodeOf = (id) => {
@@ -439,17 +461,17 @@ function createAnnotationStore(opts) {
439
461
  return parts ? project(parts.target, parts.node) : void 0;
440
462
  },
441
463
  query(q) {
442
- return q ? all().filter((a6) => matches(a6, q)) : all();
464
+ return q ? all().filter((a5) => matches(a5, q)) : all();
443
465
  },
444
466
  hitTest(target, pt, tol = 0) {
445
- return marksOn(target).filter((a6) => fracContains(a6.frac, pt, tol)).reverse();
467
+ return marksOn(target).filter((a5) => fracContains(a5.frac, pt, tol)).reverse();
446
468
  },
447
469
  within(target, box) {
448
- return marksOn(target).filter((a6) => fracEncloses(box, a6.frac));
470
+ return marksOn(target).filter((a5) => fracEncloses(box, a5.frac));
449
471
  },
450
- isStale(a6, config) {
451
- const keys = targetOf(a6.target)?.positionDependsOn ?? [];
452
- return isStale(a6.seen, config, keys);
472
+ isStale(a5, config) {
473
+ const keys = targetOf(a5.target)?.positionDependsOn ?? [];
474
+ return isStale(a5.seen, config, keys);
453
475
  },
454
476
  canUndo() {
455
477
  return history.canUndo(historySceneAt);
@@ -476,20 +498,24 @@ function createAnnotationStore(opts) {
476
498
  },
477
499
  setSelection(ids) {
478
500
  const wanted = /* @__PURE__ */ new Map();
501
+ const only = exclusive();
479
502
  for (const id of ids) {
480
503
  const found = nodeOf(id);
481
504
  if (!found) continue;
505
+ if (only && wanted.size > 0 && !wanted.has(found.target)) continue;
482
506
  const node = String(found.node.id);
483
507
  const on = wanted.get(found.target);
484
508
  if (!on) wanted.set(found.target, [node]);
485
509
  else if (!on.includes(node)) on.push(node);
486
510
  }
487
- for (const [target, scene] of scenes) {
488
- const next = wanted.get(target) ?? [];
489
- const now = scene.getSelection();
490
- if (now.length === next.length && next.every((n6, i5) => String(now[i5]) === n6)) continue;
491
- scene.setSelection(next.map(asNodeId$1));
492
- }
511
+ hold(() => {
512
+ for (const [target, scene] of scenes) {
513
+ const next = wanted.get(target) ?? [];
514
+ const now = scene.getSelection();
515
+ if (now.length === next.length && next.every((n6, i4) => String(now[i4]) === n6)) continue;
516
+ scene.setSelection(next.map(asNodeId$1));
517
+ }
518
+ });
493
519
  },
494
520
  subscribe(fn) {
495
521
  subs.add(fn);
@@ -499,10 +525,12 @@ function createAnnotationStore(opts) {
499
525
  },
500
526
  add(init, config) {
501
527
  const target = targetOf(init.target);
528
+ const frac = roundFrac(init.frac);
529
+ const shape = shapeFor(init.kind, init.points, frac);
502
530
  const data = {
503
531
  target: init.target,
504
532
  kind: init.kind,
505
- ...init.points ? { points: init.points } : {},
533
+ ...shape ? { shape } : {},
506
534
  ...init.title !== void 0 ? { title: init.title } : {},
507
535
  ...init.status !== void 0 ? { status: init.status } : {},
508
536
  ...init.tags !== void 0 ? { tags: init.tags } : {},
@@ -512,7 +540,7 @@ function createAnnotationStore(opts) {
512
540
  const node = sceneFor(init.target).add({
513
541
  kind: "leaf",
514
542
  layer: "marks",
515
- pose: fracToWorld(roundFrac(init.frac), target?.content ?? NO_CONTENT),
543
+ pose: fracToWorld(frac, target?.content ?? NO_CONTENT),
516
544
  data
517
545
  });
518
546
  return `${init.target}/${String(node)}`;
@@ -520,14 +548,18 @@ function createAnnotationStore(opts) {
520
548
  update(id, patch) {
521
549
  const found = nodeOf(id);
522
550
  if (!found) return;
523
- const { frac, ...meaning } = patch;
551
+ const { frac: fracPatch, points, ...meaning } = patch;
524
552
  const nid = asNodeId$1(found.node.id);
525
- if (Object.keys(meaning).length > 0) {
526
- found.scene.update(nid, { data: { ...found.node.data, ...meaning } });
527
- }
528
- if (frac) {
529
- found.scene.setPose(nid, fracToWorld(roundFrac(frac), contentOf(found.target)));
553
+ const content = contentOf(found.target);
554
+ const frac = fracPatch ?? (points ? boundsOf(points) : null);
555
+ const bounds = roundFrac(frac ?? worldToFrac(found.node.pose, content));
556
+ const shape = points ? shapeFor(found.node.data.kind, points, bounds) : void 0;
557
+ if (Object.keys(meaning).length > 0 || shape) {
558
+ found.scene.update(nid, {
559
+ data: { ...found.node.data, ...meaning, ...shape ? { shape } : {} }
560
+ });
530
561
  }
562
+ if (frac) found.scene.setPose(nid, fracToWorld(bounds, content));
531
563
  },
532
564
  setMeta(id, meta) {
533
565
  const found = nodeOf(id);
@@ -582,17 +614,17 @@ function annotationsFromJSON(raw, targets, rest = {}) {
582
614
  }
583
615
 
584
616
  // src/annotations/view.ts
585
- function toWeaselView(v) {
586
- return { x: v.pan.x, y: v.pan.y, scale: { x: v.zoom, y: v.zoom } };
617
+ function toWeaselView(v2) {
618
+ return { x: v2.pan.x, y: v2.pan.y, scale: { x: v2.zoom, y: v2.zoom } };
587
619
  }
588
- function fromWeaselView(v) {
589
- return { zoom: v.scale.x, pan: { x: v.x, y: v.y } };
620
+ function fromWeaselView(v2) {
621
+ return { zoom: v2.scale.x, pan: { x: v2.x, y: v2.y } };
590
622
  }
591
623
  function fitView(content, pane) {
592
624
  const zoom = content.w > 0 && content.h > 0 ? Math.min(pane.w / content.w, pane.h / content.h) : 1;
593
625
  return { zoom: Number.isFinite(zoom) && zoom > 0 ? zoom : 1, pan: { x: 0, y: 0 } };
594
626
  }
595
- var sameRect = (a6, b2) => a6 !== null && a6.x === b2.x && a6.y === b2.y && a6.w === b2.w && a6.h === b2.h;
627
+ var sameRect = (a5, b3) => a5 !== null && a5.x === b3.x && a5.y === b3.y && a5.w === b3.w && a5.h === b3.h;
596
628
  function ToolBridge({ toolId }) {
597
629
  const tools = useActiveToolContext();
598
630
  const setActive = tools.setActive;
@@ -601,19 +633,24 @@ function ToolBridge({ toolId }) {
601
633
  }, [toolId, setActive]);
602
634
  return null;
603
635
  }
604
- function pointsOf(extras, content) {
605
- const toFrac = (p3) => ({
606
- x: content.w === 0 ? 0 : p3.x / content.w,
607
- y: content.h === 0 ? 0 : p3.y / content.h
608
- });
609
- if (extras.kind === "line") {
610
- return [toFrac(extras.a), toFrac(extras.b)];
611
- }
636
+ function verticesOf(extras) {
637
+ if (extras.kind === "line") return [extras.a, extras.b];
612
638
  if (extras.kind === "pencil") {
613
- return extras.samples.map(toFrac);
639
+ const samples = extras.samples;
640
+ return samples.length > 0 ? samples : void 0;
614
641
  }
615
642
  return void 0;
616
643
  }
644
+ function insertedGeometry(extras) {
645
+ const vertices = verticesOf(extras);
646
+ if (!vertices) return void 0;
647
+ const box = boundsOf(vertices);
648
+ if (!box) return void 0;
649
+ return {
650
+ pose: { x: box.x, y: box.y, width: box.w, height: box.h },
651
+ shape: roundPoints(toShape(vertices, box))
652
+ };
653
+ }
617
654
  function AnnotationOverlay({
618
655
  target,
619
656
  scene,
@@ -626,10 +663,9 @@ function AnnotationOverlay({
626
663
  const [rect, setRect] = useState(null);
627
664
  const [input, setInput] = useState(null);
628
665
  const sceneCanvas = useRef(null);
629
- const toolRef = useRef(activeToolId);
630
- toolRef.current = activeToolId;
631
- const configRef = useRef(config);
632
- configRef.current = config;
666
+ useEffect(() => registerNodeShape(POINT_MARK_SHAPE, { priority: "high" }), []);
667
+ const toolRef = useLatest(activeToolId);
668
+ const configRef = useLatest(config);
633
669
  const id = target.id;
634
670
  const tileId = useTileId(id);
635
671
  const lastTile = useRef(null);
@@ -647,9 +683,10 @@ function AnnotationOverlay({
647
683
  [surface, tileId]
648
684
  );
649
685
  const painted = useRef(false);
650
- const canvasRef = useRef(canvas);
651
- if (canvasRef.current !== canvas) painted.current = false;
652
- canvasRef.current = canvas;
686
+ const canvasRef = useLatest(canvas);
687
+ useInsertionEffect(() => {
688
+ painted.current = false;
689
+ }, [canvas]);
653
690
  const unsubscribeFrame = useRef(null);
654
691
  const attachSceneCanvas = useCallback((api) => {
655
692
  sceneCanvas.current = api;
@@ -669,7 +706,7 @@ function AnnotationOverlay({
669
706
  gl.clearColor(0, 0, 0, 0);
670
707
  gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
671
708
  });
672
- }, [surface, tileId]);
709
+ }, [canvasRef, surface, tileId]);
673
710
  const wheelSlot = useContext(CameraWheelContext);
674
711
  useEffect(() => {
675
712
  if (!input || !wheelSlot) return;
@@ -699,14 +736,11 @@ function AnnotationOverlay({
699
736
  const info = annotationToolInfo(toolRef.current);
700
737
  const kind = info?.kind;
701
738
  if (!kind) return null;
702
- const points = pointsOf(extras, target.content);
703
- const data = {
704
- target: id,
705
- kind,
706
- ...points ? { points } : {},
707
- seen: seenFrom(configRef.current, target.positionDependsOn ?? [])
708
- };
709
- return { data };
739
+ const seen = seenFrom(configRef.current, target.positionDependsOn ?? []);
740
+ const geometry = insertedGeometry(extras);
741
+ if (!geometry) return { data: { target: id, kind, seen } };
742
+ const data = { target: id, kind, shape: geometry.shape, seen };
743
+ return { data, pose: geometry.pose };
710
744
  };
711
745
  }
712
746
  const box = {
@@ -1089,7 +1123,7 @@ function Portalled({
1089
1123
  }
1090
1124
  function UndockedSections({ trialId, sections, onDock }) {
1091
1125
  if (sections.length === 0) return null;
1092
- return /* @__PURE__ */ jsx(Fragment, { children: sections.map((c6) => /* @__PURE__ */ jsx(Portalled, { trialId, contribution: c6, onDock }, c6.id)) });
1126
+ return /* @__PURE__ */ jsx(Fragment, { children: sections.map((c7) => /* @__PURE__ */ jsx(Portalled, { trialId, contribution: c7, onDock }, c7.id)) });
1093
1127
  }
1094
1128
  var NO_OP = () => {
1095
1129
  };
@@ -1113,17 +1147,17 @@ function TrialChrome({
1113
1147
  const lab = useLabContext();
1114
1148
  const storeCtx = useContext(LabStoreContext);
1115
1149
  if (!storeCtx) throw new Error("[labkit] TrialChrome requires <LabStoreProvider>");
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);
1150
+ const updateTrialView = useStore(storeCtx.store, (s3) => s3.updateTrialView);
1151
+ const updateTrialSidebarWidth = useStore(storeCtx.store, (s3) => s3.updateTrialSidebarWidth);
1152
+ const setTrialTitle = useStore(storeCtx.store, (s3) => s3.setTrialTitle);
1153
+ const setTrialSectionCollapsed = useStore(storeCtx.store, (s3) => s3.setTrialSectionCollapsed);
1154
+ const updateTrialConfig = useStore(storeCtx.store, (s3) => s3.updateTrialConfig);
1155
+ const updateTrialState = useStore(storeCtx.store, (s3) => s3.updateTrialState);
1156
+ const undockPanelAction = useStore(storeCtx.store, (s3) => s3.undockPanel);
1157
+ const dockPanelAction = useStore(storeCtx.store, (s3) => s3.dockPanel);
1158
+ const undockedPanels = useStore(storeCtx.store, (s3) => s3.undockedPanels);
1125
1159
  const undockedIds = useMemo(
1126
- () => Object.values(undockedPanels).filter((p3) => p3.trialId === trialId).map((p3) => p3.sectionId),
1160
+ () => Object.values(undockedPanels).filter((p4) => p4.trialId === trialId).map((p4) => p4.sectionId),
1127
1161
  [undockedPanels, trialId]
1128
1162
  );
1129
1163
  const view2d = as2DView(record.view);
@@ -1141,9 +1175,9 @@ function TrialChrome({
1141
1175
  () => cameras?.get(trialId) ?? null
1142
1176
  );
1143
1177
  const ctx = useMemo(() => {
1144
- const setZoom = (z2) => {
1145
- if (camera) zoomCameraTo(camera, z2);
1146
- else if (view2d) updateTrialView(trialId, withZoom(view2d, z2));
1178
+ const setZoom = (z) => {
1179
+ if (camera) zoomCameraTo(camera, z);
1180
+ else if (view2d) updateTrialView(trialId, withZoom(view2d, z));
1147
1181
  };
1148
1182
  return {
1149
1183
  trialId,
@@ -1157,6 +1191,7 @@ function TrialChrome({
1157
1191
  canRedo: undoBindings?.canRedo ?? false,
1158
1192
  undo: undoBindings?.undo ?? NO_OP,
1159
1193
  redo: undoBindings?.redo ?? NO_OP,
1194
+ hasLoupe: loupe != null,
1160
1195
  loupeOn: loupe?.on ?? false,
1161
1196
  toggleLoupe: loupe?.toggle ?? NO_OP,
1162
1197
  configSchema,
@@ -1183,7 +1218,7 @@ function TrialChrome({
1183
1218
  undockedPanels: undockedIds,
1184
1219
  undockPanel: (sectionId, as) => undockPanelAction(trialId, sectionId, as),
1185
1220
  dockPanel: (sectionId) => dockPanelAction(trialId, sectionId),
1186
- savedSnapshots: lab.savedSnapshots.filter((s2) => s2.trialId === trialId),
1221
+ savedSnapshots: lab.savedSnapshots.filter((s3) => s3.trialId === trialId),
1187
1222
  saveSnapshot: (name) => lab.saveSnapshot(trialId, name),
1188
1223
  loadSnapshot: (snapshotId) => lab.loadSnapshot(trialId, snapshotId),
1189
1224
  clone: () => lab.cloneTrial(trialId),
@@ -1226,11 +1261,12 @@ function TrialChrome({
1226
1261
  [...trialChrome ?? []],
1227
1262
  [...chrome ?? []]
1228
1263
  ),
1229
- suppress ?? []
1264
+ suppress ?? [],
1265
+ TRANSIENT_BUILTINS
1230
1266
  ),
1231
1267
  [instrument, ctx, trialChrome, chrome, suppress, lab.controls]
1232
1268
  );
1233
- const inRegion = (region) => contributions.filter((c6) => c6.region === region);
1269
+ const inRegion = (region) => contributions.filter((c7) => c7.region === region);
1234
1270
  const handleKeyDown = (e) => {
1235
1271
  const mod = e.metaKey || e.ctrlKey;
1236
1272
  if (!mod) return;
@@ -1276,7 +1312,7 @@ function TrialChrome({
1276
1312
  UndockedSections,
1277
1313
  {
1278
1314
  trialId,
1279
- sections: inRegion("sidebar").filter((c6) => undockedIds.includes(c6.id)),
1315
+ sections: inRegion("sidebar").filter((c7) => undockedIds.includes(c7.id)),
1280
1316
  onDock: ctx.dockPanel
1281
1317
  }
1282
1318
  )
@@ -1300,9 +1336,9 @@ function Trial({ id, chrome, suppress }) {
1300
1336
  const lab = useLabContext();
1301
1337
  const storeCtx = useContext(LabStoreContext);
1302
1338
  if (!storeCtx) throw new Error("[labkit] <Trial> requires <LabStoreProvider>");
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));
1305
- const instrument = record ? instruments.find((i5) => i5.name === record.instrumentName) : void 0;
1339
+ const instruments = useStore(storeCtx.store, (s3) => s3.instruments) ?? lab.instruments;
1340
+ const record = useStore(storeCtx.store, (s3) => s3.trials.find((w2) => w2.id === id));
1341
+ const instrument = record ? instruments.find((i4) => i4.name === record.instrumentName) : void 0;
1306
1342
  const kept = useKeptMarks(instrument?.annotations?.storage, id);
1307
1343
  if (!record) {
1308
1344
  return /* @__PURE__ */ jsxs("div", { className: "lk-trial lk-trial--unknown", children: [
@@ -1374,15 +1410,14 @@ function TrialRuntime({
1374
1410
  );
1375
1411
  const [pointer] = useState(createPointerStore);
1376
1412
  const canvasContainerRef = useRef(null);
1377
- const loupeHostRef = useRef(null);
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);
1413
+ const updateTrialState = useStore(store, (s3) => s3.updateTrialState);
1414
+ const updateTrialConfig = useStore(store, (s3) => s3.updateTrialConfig);
1415
+ const updateTrialView = useStore(store, (s3) => s3.updateTrialView);
1416
+ const updateTrialUndoStack = useStore(store, (s3) => s3.updateTrialUndoStack);
1417
+ const updateTrialAnnotations = useStore(store, (s3) => s3.updateTrialAnnotations);
1418
+ const labToolId = useStore(store, (s3) => s3.activeToolId);
1419
+ const setLabTool = useStore(store, (s3) => s3.setLabTool);
1420
+ const setTrialTool = useStore(store, (s3) => s3.setTrialTool);
1386
1421
  const schema = useConfigSchema(instrument);
1387
1422
  const { config } = useResolvedConfig(schema, record.config, record.auto);
1388
1423
  const busRef = useRef(null);
@@ -1391,8 +1426,14 @@ function TrialRuntime({
1391
1426
  const [layerVisibility, setLayerVisibility] = useState({});
1392
1427
  const [layerOrder, setLayerOrder] = useState(null);
1393
1428
  const [loupeOn, setLoupeOn] = useState(false);
1429
+ const [lenses, setLenses] = useState(0);
1430
+ const mountLens = useCallback(() => {
1431
+ setLenses((n6) => n6 + 1);
1432
+ return () => setLenses((n6) => n6 - 1);
1433
+ }, []);
1434
+ const loupeSwitch = useMemo(() => ({ on: loupeOn, mount: mountLens }), [loupeOn, mountLens]);
1394
1435
  const visibleLayers = useMemo(
1395
- () => (instrument.canvas?.layers ?? []).filter((l7) => layerVisibility[l7.id] !== false).map((l7) => l7.id),
1436
+ () => (instrument.canvas?.layers ?? []).filter((l8) => layerVisibility[l8.id] !== false).map((l8) => l8.id),
1396
1437
  [instrument.canvas, layerVisibility]
1397
1438
  );
1398
1439
  const undoCap = instrument.undo;
@@ -1405,7 +1446,7 @@ function TrialRuntime({
1405
1446
  const snap = structuredClone(current.state);
1406
1447
  updateTrialUndoStack(record.id, (prev) => pushSnapshot(prev, snap, maxDepth));
1407
1448
  };
1408
- const setView = (v) => updateTrialView(record.id, v);
1449
+ const setView = (v2) => updateTrialView(record.id, v2);
1409
1450
  const stage = instrument.canvas ? void 0 : instrument.stage;
1410
1451
  const placeView = (size) => {
1411
1452
  const declared = instrument.canvas?.initialView ?? (stage ? stage.initialView ?? ((vp) => fitStage(stage.size, vp)) : void 0);
@@ -1414,29 +1455,48 @@ function TrialRuntime({
1414
1455
  setView(declared(size));
1415
1456
  };
1416
1457
  const annotationsCap = instrument.annotations;
1417
- const targetsRef = useRef(() => []);
1418
- targetsRef.current = () => annotationsCap ? annotationsCap.targets(record.state, config, { id: record.id, view: record.view }) : [];
1458
+ const targetsRef = useLatest(
1459
+ () => annotationsCap ? annotationsCap.targets(record.state, config, { id: record.id, view: record.view }) : []
1460
+ );
1419
1461
  const annotationsRef = useRef(null);
1420
- const configRef = useRef(config);
1421
- configRef.current = config;
1422
- const capRef = useRef(annotationsCap);
1423
- capRef.current = annotationsCap;
1462
+ const configRef = useLatest(config);
1463
+ const capRef = useLatest(annotationsCap);
1424
1464
  if (annotationsRef.current === null) {
1425
- const kept = annotationsCap?.storage ? keptMarks : record.annotations;
1426
- annotationsRef.current = annotationsFromJSON(kept, () => targetsRef.current(), {
1427
- meaning: () => capRef.current?.meaning,
1428
- config: () => configRef.current,
1429
- onCapture: (result) => capRef.current?.onCapture?.(result)
1430
- });
1465
+ annotationsRef.current = annotationsFromJSON(
1466
+ annotationsCap?.storage ? keptMarks : record.annotations,
1467
+ () => targetsRef.current(),
1468
+ {
1469
+ meaning: () => capRef.current?.meaning,
1470
+ config: () => configRef.current,
1471
+ onCapture: (result) => capRef.current?.onCapture?.(result),
1472
+ selection: () => capRef.current?.selection
1473
+ }
1474
+ );
1431
1475
  }
1432
1476
  const annotations = annotationsRef.current;
1477
+ const inputsCommitted = useRef(/* @__PURE__ */ new Set());
1478
+ useLayoutEffect(() => {
1479
+ for (const fn of inputsCommitted.current) fn();
1480
+ }, [record.state, record.view, config, annotationsCap]);
1481
+ const provided = useMemo(
1482
+ () => ({
1483
+ ...annotations,
1484
+ subscribe: (fn) => {
1485
+ const off = annotations.subscribe(fn);
1486
+ inputsCommitted.current.add(fn);
1487
+ return () => {
1488
+ off();
1489
+ inputsCommitted.current.delete(fn);
1490
+ };
1491
+ }
1492
+ }),
1493
+ [annotations]
1494
+ );
1433
1495
  const saveCap = annotationsCap?.storage;
1434
- const saveRef = useRef(() => {
1435
- });
1436
- saveRef.current = (doc) => {
1496
+ const saveRef = useLatest((doc) => {
1437
1497
  if (saveCap) saveCap.save(doc);
1438
1498
  else updateTrialAnnotations(record.id, doc);
1439
- };
1499
+ });
1440
1500
  const [markMoves, setMarkMoves] = useState({ undo: false, redo: false });
1441
1501
  useEffect(() => {
1442
1502
  if (!annotationsCap) return;
@@ -1469,7 +1529,7 @@ function TrialRuntime({
1469
1529
  if (timer) clearTimeout(timer);
1470
1530
  flush();
1471
1531
  };
1472
- }, [annotations, annotationsCap]);
1532
+ }, [annotations, annotationsCap, saveRef]);
1473
1533
  const declaresTools = instrument.tools != null;
1474
1534
  const labTool = resolveLabTool(labToolId, instruments);
1475
1535
  const resolvedToolId = declaresTools ? record.activeToolId ?? instrument.tools?.initial ?? instrument.tools?.tools[0]?.id ?? null : labTool;
@@ -1507,9 +1567,9 @@ function TrialRuntime({
1507
1567
  view: record.view,
1508
1568
  setView,
1509
1569
  zoom: view2d?.zoom ?? 1,
1510
- setZoom: (z2) => {
1570
+ setZoom: (z) => {
1511
1571
  if (!view2d) return;
1512
- updateTrialView(record.id, withZoom(view2d, z2));
1572
+ updateTrialView(record.id, withZoom(view2d, z));
1513
1573
  },
1514
1574
  activeToolId: resolvedToolId,
1515
1575
  visibleLayers,
@@ -1545,16 +1605,11 @@ function TrialRuntime({
1545
1605
  if (undoCap) redoState();
1546
1606
  }
1547
1607
  } : void 0;
1548
- const loupeCap = useMemo(() => {
1549
- const declared = instrument.loupe;
1550
- if (declared == null) return null;
1551
- return resolveLoupe(typeof declared === "function" ? declared(config) : declared);
1552
- }, [instrument.loupe, config]);
1553
- const loupeBindings = loupeCap ? { on: loupeOn, toggle: () => setLoupeOn((v) => !v) } : void 0;
1608
+ const loupeBindings = lenses > 0 ? { on: loupeOn, toggle: () => setLoupeOn((v2) => !v2) } : void 0;
1554
1609
  const canvasLayers = useMemo(() => {
1555
1610
  if (!instrument.canvas) return [];
1556
1611
  const baseLayers = instrument.canvas.layers;
1557
- const ordered = layerOrder ? [...baseLayers].sort((a6, b2) => layerOrder.indexOf(a6.id) - layerOrder.indexOf(b2.id)) : baseLayers;
1612
+ const ordered = layerOrder ? [...baseLayers].sort((a5, b3) => layerOrder.indexOf(a5.id) - layerOrder.indexOf(b3.id)) : baseLayers;
1558
1613
  return ordered.map((layer) => ({
1559
1614
  id: layer.id,
1560
1615
  visible: layerVisibility[layer.id] !== false,
@@ -1566,23 +1621,23 @@ function TrialRuntime({
1566
1621
  }, [instrument.canvas, record.state, config, layerVisibility, layerOrder]);
1567
1622
  const layerDescriptors = useMemo(() => {
1568
1623
  if (!instrument.layers) return [];
1569
- return instrument.layers.ids.map((l7) => typeof l7 === "string" ? { id: l7, label: l7 } : l7);
1624
+ return instrument.layers.ids.map((l8) => typeof l8 === "string" ? { id: l8, label: l8 } : l8);
1570
1625
  }, [instrument.layers]);
1571
1626
  const layerItems = useMemo(() => {
1572
- const ordered = layerOrder ? [...layerDescriptors].sort((a6, b2) => layerOrder.indexOf(a6.id) - layerOrder.indexOf(b2.id)) : layerDescriptors;
1627
+ const ordered = layerOrder ? [...layerDescriptors].sort((a5, b3) => layerOrder.indexOf(a5.id) - layerOrder.indexOf(b3.id)) : layerDescriptors;
1573
1628
  const pinnedLast = [
1574
- ...ordered.filter((l7) => !l7.alwaysOn),
1575
- ...ordered.filter((l7) => l7.alwaysOn)
1629
+ ...ordered.filter((l8) => !l8.alwaysOn),
1630
+ ...ordered.filter((l8) => l8.alwaysOn)
1576
1631
  ];
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
1632
+ return pinnedLast.map((l8) => ({
1633
+ id: l8.id,
1634
+ label: l8.label,
1635
+ locked: l8.alwaysOn === true,
1636
+ visible: l8.alwaysOn === true || layerVisibility[l8.id] !== false
1582
1637
  }));
1583
1638
  }, [layerDescriptors, layerOrder, layerVisibility]);
1584
1639
  const dragDropResult = useDragDrop({
1585
- capability: instrument.dragDrop ?? { palette: [], onDrop: (_p, _i, s2) => s2 },
1640
+ capability: instrument.dragDrop ?? { palette: [], onDrop: (_p, _i, s3) => s3 },
1586
1641
  canvasContainerRef,
1587
1642
  view: view2d ?? DEFAULT_VIEW,
1588
1643
  worldSpec: instrument.canvas?.worldSpec,
@@ -1599,8 +1654,8 @@ function TrialRuntime({
1599
1654
  });
1600
1655
  const paletteItems = useMemo(() => {
1601
1656
  if (!instrument.dragDrop) return [];
1602
- const p3 = instrument.dragDrop.palette;
1603
- return typeof p3 === "function" ? p3(record.state, config) : p3;
1657
+ const p4 = instrument.dragDrop.palette;
1658
+ return typeof p4 === "function" ? p4(record.state, config) : p4;
1604
1659
  }, [instrument.dragDrop, record.state, config]);
1605
1660
  const layersWithFeedback = useMemo(() => {
1606
1661
  if (!dragDropResult.drag?.feedback) return canvasLayers;
@@ -1626,22 +1681,10 @@ function TrialRuntime({
1626
1681
  }
1627
1682
  ];
1628
1683
  }, [canvasLayers, dragDropResult.drag]);
1629
- const lens = loupeCap ? /* @__PURE__ */ jsx(
1630
- TrialLoupe,
1631
- {
1632
- capability: loupeCap,
1633
- enabled: loupeOn,
1634
- state: record.state,
1635
- config,
1636
- view: view2d ?? DEFAULT_VIEW,
1637
- worldSpec: instrument.canvas?.worldSpec,
1638
- hostRef: loupeHostRef
1639
- }
1640
- ) : null;
1641
1684
  let body;
1642
1685
  if (instrument.canvas) {
1643
1686
  body = /* @__PURE__ */ jsxs("div", { ref: canvasContainerRef, className: "lk-trial__canvas-host", children: [
1644
- /* @__PURE__ */ jsxs(
1687
+ /* @__PURE__ */ jsx(
1645
1688
  CanvasStack,
1646
1689
  {
1647
1690
  layers: layersWithFeedback,
@@ -1651,10 +1694,7 @@ function TrialRuntime({
1651
1694
  onResize: placeView,
1652
1695
  minZoom: instrument.canvas.minZoom,
1653
1696
  maxZoom: instrument.canvas.maxZoom,
1654
- children: [
1655
- instrument.render(renderCtx),
1656
- lens
1657
- ]
1697
+ children: instrument.render(renderCtx)
1658
1698
  }
1659
1699
  ),
1660
1700
  /* @__PURE__ */ jsx(DragOverlay, { drag: dragDropResult.drag })
@@ -1669,19 +1709,10 @@ function TrialRuntime({
1669
1709
  onResize: placeView,
1670
1710
  minZoom: stage.minZoom,
1671
1711
  maxZoom: stage.maxZoom,
1672
- hostRef: loupeHostRef,
1673
- overlay: /* @__PURE__ */ jsxs(Fragment, { children: [
1674
- stage.overlay?.(renderCtx),
1675
- lens
1676
- ] }),
1712
+ overlay: stage.overlay?.(renderCtx),
1677
1713
  children: instrument.render(renderCtx)
1678
1714
  }
1679
1715
  );
1680
- } else if (lens) {
1681
- body = /* @__PURE__ */ jsxs("div", { ref: loupeHostRef, className: "lk-trial__loupe-host", children: [
1682
- instrument.render(renderCtx),
1683
- lens
1684
- ] });
1685
1716
  } else {
1686
1717
  body = instrument.render(renderCtx);
1687
1718
  }
@@ -1692,11 +1723,11 @@ function TrialRuntime({
1692
1723
  );
1693
1724
  const layerListNode = useMemo(
1694
1725
  () => instrument.layers && layerDescriptors.length > 0 ? /* @__PURE__ */ jsx(
1695
- E3,
1726
+ D2,
1696
1727
  {
1697
1728
  items: layerItems,
1698
1729
  onReorder: (move) => {
1699
- setLayerOrder(x3(layerItems, move).map((l7) => l7.id));
1730
+ setLayerOrder(S2(layerItems, move).map((l8) => l8.id));
1700
1731
  bus.emit("layers.reorder");
1701
1732
  },
1702
1733
  onVisibilityChange: (lid, visible) => {
@@ -1736,8 +1767,8 @@ function TrialRuntime({
1736
1767
  activeToolId: labTool
1737
1768
  }
1738
1769
  ) : null;
1739
- const scopedBody = /* @__PURE__ */ jsx(WeaselProvider, { isolate: true, children: /* @__PURE__ */ jsx(PointerContextProvider, { store: pointer, children: /* @__PURE__ */ jsx(CameraPublishContext.Provider, { value: publishCamera, children: body }) }) });
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(
1770
+ const scopedBody = /* @__PURE__ */ jsx(WeaselProvider, { isolate: true, children: /* @__PURE__ */ jsx(PointerContextProvider, { store: pointer, children: /* @__PURE__ */ jsx(CameraPublishContext.Provider, { value: publishCamera, children: /* @__PURE__ */ jsx(LoupeSwitchContext.Provider, { value: loupeSwitch, children: body }) }) }) });
1771
+ return /* @__PURE__ */ jsx(TrialIdProvider, { trialId: record.id, children: /* @__PURE__ */ jsx(AnnotationsContext.Provider, { value: annotationsCap ? provided : null, children: /* @__PURE__ */ jsx(CameraWheelContext.Provider, { value: wheelSlot, children: /* @__PURE__ */ jsxs(
1741
1772
  TrialChrome,
1742
1773
  {
1743
1774
  job: jobCap ? job : void 0,
@@ -1763,7 +1794,7 @@ function TrialRuntime({
1763
1794
  // src/trial/trialOps.ts
1764
1795
  var DEFAULT_VIEW2 = { zoom: 1, pan: { x: 0, y: 0 } };
1765
1796
  function findInstrument(instruments, name) {
1766
- const found = instruments.find((i5) => i5.name === name);
1797
+ const found = instruments.find((i4) => i4.name === name);
1767
1798
  if (!found) {
1768
1799
  throw new Error(`[labkit] Unknown instrument: "${name}"`);
1769
1800
  }
@@ -1873,16 +1904,16 @@ function reorderTrials(trials, ids) {
1873
1904
  function findOvershoot(bound, items, tolerance = 1) {
1874
1905
  let worst = null;
1875
1906
  for (const { item, edges } of items) {
1876
- const y3 = edges.bottom - bound.bottom;
1877
- const x3 = edges.right - bound.right;
1878
- const by = Math.max(x3, y3);
1907
+ const y2 = edges.bottom - bound.bottom;
1908
+ const x2 = edges.right - bound.right;
1909
+ const by = Math.max(x2, y2);
1879
1910
  if (by <= tolerance) continue;
1880
- if (!worst || by > worst.by) worst = { item, by, axis: y3 >= x3 ? "y" : "x" };
1911
+ if (!worst || by > worst.by) worst = { item, by, axis: y2 >= x2 ? "y" : "x" };
1881
1912
  }
1882
1913
  return worst;
1883
1914
  }
1884
1915
  function tagAndClasses(el) {
1885
- return el.tagName.toLowerCase() + [...el.classList].map((c6) => `.${c6}`).join("");
1916
+ return el.tagName.toLowerCase() + [...el.classList].map((c7) => `.${c7}`).join("");
1886
1917
  }
1887
1918
  function describeElement(el) {
1888
1919
  if (el.classList.length > 0) return tagAndClasses(el);
@@ -1965,11 +1996,11 @@ function LabHeader({ addTrial: addTrial2 = true }) {
1965
1996
  ]
1966
1997
  }
1967
1998
  ) : /* @__PURE__ */ jsx(
1968
- d3,
1999
+ p4,
1969
2000
  {
1970
2001
  "aria-label": "Add trial",
1971
2002
  label: "Add trial\u2026",
1972
- items: lab.instruments.map((i5) => ({ value: i5.name, label: i5.title ?? i5.name })),
2003
+ items: lab.instruments.map((i4) => ({ value: i4.name, label: i4.title ?? i4.name })),
1973
2004
  onAction: (name) => lab.addTrial(name)
1974
2005
  }
1975
2006
  ) });
@@ -1981,7 +2012,7 @@ function LabThemeSwitcher() {
1981
2012
  function LabPalette({ tools, contributions }) {
1982
2013
  const ctx = useLabChromeContext();
1983
2014
  const all = labContributions(tools, contributions);
1984
- return /* @__PURE__ */ jsx(PaletteRegion, { contributions: all.filter((c6) => c6.region === "palette"), ctx });
2015
+ return /* @__PURE__ */ jsx(PaletteRegion, { contributions: all.filter((c7) => c7.region === "palette"), ctx });
1985
2016
  }
1986
2017
  function LabRoot({ children, mode = "auto", className }) {
1987
2018
  const resolved = useResolvedColorMode(mode);
@@ -2000,13 +2031,13 @@ function locate(url) {
2000
2031
  function currentPage(path, pages) {
2001
2032
  const here = locate(path);
2002
2033
  const onDoc = (doc) => here.doc.endsWith(doc);
2003
- const routed = pages.findIndex((p3) => {
2004
- if (!p3.href.includes("#")) return false;
2005
- const page = locate(p3.href);
2034
+ const routed = pages.findIndex((p4) => {
2035
+ if (!p4.href.includes("#")) return false;
2036
+ const page = locate(p4.href);
2006
2037
  return onDoc(page.doc) && (here.route === page.route || here.route.startsWith(`${page.route}/`));
2007
2038
  });
2008
2039
  if (routed >= 0) return routed;
2009
- return pages.findIndex((p3) => !p3.href.includes("#") && onDoc(locate(p3.href).doc));
2040
+ return pages.findIndex((p4) => !p4.href.includes("#") && onDoc(locate(p4.href).doc));
2010
2041
  }
2011
2042
  function LabSwitcher({ title, pages, path, className }) {
2012
2043
  const [open, setOpen] = useState(false);
@@ -2054,13 +2085,13 @@ function LabSwitcher({ title, pages, path, className }) {
2054
2085
  ]
2055
2086
  }
2056
2087
  ) }),
2057
- open && /* @__PURE__ */ jsx("div", { className: "lk-switcher-menu", id: menuId, role: "menu", children: pages.map((page, i5) => /* @__PURE__ */ jsx(
2088
+ open && /* @__PURE__ */ jsx("div", { className: "lk-switcher-menu", id: menuId, role: "menu", children: pages.map((page, i4) => /* @__PURE__ */ jsx(
2058
2089
  "a",
2059
2090
  {
2060
2091
  href: page.href,
2061
2092
  role: "menuitem",
2062
2093
  className: "lk-switcher-item",
2063
- "aria-current": i5 === here ? "page" : void 0,
2094
+ "aria-current": i4 === here ? "page" : void 0,
2064
2095
  onClick: close,
2065
2096
  children: page.label
2066
2097
  },
@@ -2100,9 +2131,9 @@ var NO_TOOLS = /* @__PURE__ */ new Map();
2100
2131
  var CHANNELS = { contextMenu: false, ingest: false };
2101
2132
  var NO_ELEMENT = { current: null };
2102
2133
  var BASE = makeViewportZoomAction({ min: 1e-9, max: Number.POSITIVE_INFINITY });
2103
- var KEY_BINDINGS = BASE.defaultBinding.filter((b2) => b2.spec.kind === "key");
2134
+ var KEY_BINDINGS = BASE.defaultBinding.filter((b3) => b3.spec.kind === "key");
2104
2135
  function shortcutFor(kind) {
2105
- const spec = KEY_BINDINGS.find((b2) => b2.opts?.params?.kind === kind)?.spec;
2136
+ const spec = KEY_BINDINGS.find((b3) => b3.opts?.params?.kind === kind)?.spec;
2106
2137
  return spec?.key ? n2({ key: spec.key, mod: spec.mods?.mod }) : void 0;
2107
2138
  }
2108
2139
  function forZoom(camera) {
@@ -2127,14 +2158,13 @@ function LabZoomControls() {
2127
2158
  cameras?.subscribe ?? noSubscribe2,
2128
2159
  () => cameras && focusedTrialId ? cameras.get(focusedTrialId) : null
2129
2160
  );
2130
- const zoom = useStore(storeCtx.store, (s2) => {
2131
- const record = s2.trials.find((t) => t.id === focusedTrialId);
2161
+ const zoom = useStore(storeCtx.store, (s3) => {
2162
+ const record = s3.trials.find((t) => t.id === focusedTrialId);
2132
2163
  return as2DView(record?.view)?.zoom ?? null;
2133
2164
  });
2134
2165
  const live = zoom !== null && camera !== null;
2135
2166
  const view = useMemo(() => camera ? forZoom(camera) : null, [camera]);
2136
- const viewRef = useRef(view);
2137
- viewRef.current = live ? view : null;
2167
+ const viewRef = useLatest(live ? view : null);
2138
2168
  useDepSource("view", () => viewRef.current);
2139
2169
  useEffect(() => {
2140
2170
  const action = {
@@ -2143,7 +2173,7 @@ function LabZoomControls() {
2143
2173
  enabled: () => viewRef.current ? true : ActionDisabledReason.NotApplicable
2144
2174
  };
2145
2175
  return registry.register(action);
2146
- }, [registry]);
2176
+ }, [registry, viewRef]);
2147
2177
  useGestureDispatcher({
2148
2178
  canvasRef: NO_ELEMENT,
2149
2179
  actions: registry,
@@ -2204,12 +2234,30 @@ var STRATEGIES = { grid: gridStrategy, floating: floatingStrategy };
2204
2234
  var FLOAT_ZONE_ID = asNodeId("lk-workspace-floating");
2205
2235
  var PANEL_KIND = "panel";
2206
2236
  var KIND = "trial";
2237
+ function createWorkspaceStore(grid) {
2238
+ const store = new Store();
2239
+ store.registerNode(
2240
+ createNode({
2241
+ kind: "zone",
2242
+ id: ZONE_ID,
2243
+ container: { strategyId: "grid", config: grid }
2244
+ })
2245
+ );
2246
+ store.registerNode(
2247
+ createNode({
2248
+ kind: "zone",
2249
+ id: FLOAT_ZONE_ID,
2250
+ container: { strategyId: "floating", config: {} }
2251
+ })
2252
+ );
2253
+ return store;
2254
+ }
2207
2255
  function extentOf(store, id) {
2208
- const p3 = store.getNode(id)?.membership?.placement;
2209
- if (!p3) return null;
2256
+ const p4 = store.getNode(id)?.membership?.placement;
2257
+ if (!p4) return null;
2210
2258
  const out = {};
2211
- if (p3.size) out.size = p3.size;
2212
- if (p3.span) out.span = p3.span;
2259
+ if (p4.size) out.size = p4.size;
2260
+ if (p4.span) out.span = p4.span;
2213
2261
  return Object.keys(out).length > 0 ? out : null;
2214
2262
  }
2215
2263
  function PanelFrame({ panel, floating = false }) {
@@ -2230,43 +2278,18 @@ function Workspace({
2230
2278
  viewport
2231
2279
  }) {
2232
2280
  const items = Children.toArray(children);
2233
- const tilePanels = useMemo(() => (panels ?? []).filter((p3) => p3.as === "tile"), [panels]);
2234
- const floatPanels = useMemo(() => (panels ?? []).filter((p3) => p3.as === "floating"), [panels]);
2235
- const wantedIds = [
2236
- ...items.map((_3, i5) => ids?.[i5] ?? `lk-ws-${i5}`),
2237
- ...tilePanels.map((p3) => `lk-panel-${p3.key}`)
2238
- ];
2239
- const idKey = wantedIds.join(",");
2240
- const idKeyRef = useRef(null);
2241
- const nodeIdsRef = useRef([]);
2242
- if (idKeyRef.current !== idKey) {
2243
- idKeyRef.current = idKey;
2244
- nodeIdsRef.current = wantedIds.map(asNodeId);
2245
- }
2246
- const nodeIds = nodeIdsRef.current;
2247
- const layoutRef = useRef(layout);
2248
- layoutRef.current = layout;
2249
- const onLayoutChangeRef = useRef(onLayoutChange);
2250
- onLayoutChangeRef.current = onLayoutChange;
2281
+ const tilePanels = useMemo(() => (panels ?? []).filter((p4) => p4.as === "tile"), [panels]);
2282
+ const floatPanels = useMemo(() => (panels ?? []).filter((p4) => p4.as === "floating"), [panels]);
2283
+ const idKey = JSON.stringify([
2284
+ ...items.map((_2, i4) => ids?.[i4] ?? `lk-ws-${i4}`),
2285
+ ...tilePanels.map((p4) => `lk-panel-${p4.key}`)
2286
+ ]);
2287
+ const nodeIds = useMemo(() => JSON.parse(idKey).map(asNodeId), [idKey]);
2288
+ const layoutRef = useLatest(layout);
2289
+ const onLayoutChangeRef = useLatest(onLayoutChange);
2251
2290
  const storeRef = useRef(null);
2252
- if (storeRef.current === null) {
2253
- const store2 = new Store();
2254
- store2.registerNode(
2255
- createNode({
2256
- kind: "zone",
2257
- id: ZONE_ID,
2258
- container: { strategyId: "grid", config: { resizable, gap, padding } }
2259
- })
2260
- );
2261
- store2.registerNode(
2262
- createNode({
2263
- kind: "zone",
2264
- id: FLOAT_ZONE_ID,
2265
- container: { strategyId: "floating", config: {} }
2266
- })
2267
- );
2268
- storeRef.current = store2;
2269
- }
2291
+ if (storeRef.current === null)
2292
+ storeRef.current = createWorkspaceStore({ resizable, gap, padding });
2270
2293
  const store = storeRef.current;
2271
2294
  const surface = useSurfaceOptional();
2272
2295
  useLayoutEffect(() => {
@@ -2287,7 +2310,7 @@ function Workspace({
2287
2310
  if (saved) store.patchPlacement(id, saved);
2288
2311
  }
2289
2312
  store.setChildOrder(ZONE_ID, [...nodeIds]);
2290
- }, [store, nodeIds]);
2313
+ }, [store, nodeIds, layoutRef]);
2291
2314
  useEffect(() => {
2292
2315
  if (!surface) return;
2293
2316
  surface.invalidateRects();
@@ -2303,15 +2326,15 @@ function Workspace({
2303
2326
  }
2304
2327
  onLayoutChangeRef.current?.(next);
2305
2328
  });
2306
- }, [store, onLayoutChange]);
2329
+ }, [store, onLayoutChange, onLayoutChangeRef]);
2307
2330
  const commitOrder = useCallback(
2308
2331
  (nextIds) => onReorder?.(nextIds.map(String)),
2309
2332
  [onReorder]
2310
2333
  );
2311
2334
  const chrome = useMemo(() => {
2312
- const byId = new Map(nodeIds.map((id, i5) => [id, items[i5]]));
2335
+ const byId = new Map(nodeIds.map((id, i4) => [id, items[i4]]));
2313
2336
  const panelByNode = new Map(
2314
- tilePanels.map((p3) => [`lk-panel-${p3.key}`, p3])
2337
+ tilePanels.map((p4) => [`lk-panel-${p4.key}`, p4])
2315
2338
  );
2316
2339
  return {
2317
2340
  [PANEL_KIND]: ({ node }) => {
@@ -2329,7 +2352,7 @@ function Workspace({
2329
2352
  }
2330
2353
  };
2331
2354
  }, [nodeIds, items, reorderable, tilePanels]);
2332
- const floatingLayer = floatPanels.length === 0 ? null : /* @__PURE__ */ jsx("div", { className: "lk-workspace__floating", children: floatPanels.map((p3) => /* @__PURE__ */ jsx(PanelFrame, { panel: p3, floating: true }, p3.key)) });
2355
+ const floatingLayer = floatPanels.length === 0 ? null : /* @__PURE__ */ jsx("div", { className: "lk-workspace__floating", children: floatPanels.map((p4) => /* @__PURE__ */ jsx(PanelFrame, { panel: p4, floating: true }, p4.key)) });
2333
2356
  const grid = /* @__PURE__ */ jsx(
2334
2357
  Container,
2335
2358
  {
@@ -2375,7 +2398,7 @@ async function openStoredLab({ instruments, defaultInstrument, mode }, storageKe
2375
2398
  const marks = /* @__PURE__ */ new Map();
2376
2399
  await Promise.all(
2377
2400
  opened.store.getState().trials.map(async (trial) => {
2378
- const kept = instruments.find((i5) => i5.name === trial.instrumentName)?.annotations?.storage;
2401
+ const kept = instruments.find((i4) => i4.name === trial.instrumentName)?.annotations?.storage;
2379
2402
  if (!kept) return;
2380
2403
  try {
2381
2404
  marks.set(trial.id, await kept.load());
@@ -2425,10 +2448,10 @@ var NEBULA_SLOTS = [
2425
2448
  function buildNebula(list, theme, mode, density) {
2426
2449
  const ctx = { theme, resolved: resolveTheme(theme, { mode, density }) };
2427
2450
  const n6 = colorCount(list, ctx) ?? NEBULA_SLOTS.length;
2428
- const colors = Array.from({ length: n6 }, (_3, i5) => colorAt(list, i5, ctx));
2429
- const blobs = colors.map((c6, i5) => {
2430
- const p3 = NEBULA_SLOTS[i5 % NEBULA_SLOTS.length];
2431
- return `radial-gradient(ellipse ${p3.sx} ${p3.sy} at ${p3.cx} ${p3.cy}, color-mix(in srgb, ${c6} 22%, transparent), transparent ${p3.stop})`;
2451
+ const colors = Array.from({ length: n6 }, (_2, i4) => colorAt(list, i4, ctx));
2452
+ const blobs = colors.map((c7, i4) => {
2453
+ const p4 = NEBULA_SLOTS[i4 % NEBULA_SLOTS.length];
2454
+ return `radial-gradient(ellipse ${p4.sx} ${p4.sy} at ${p4.cx} ${p4.cy}, color-mix(in srgb, ${c7} 22%, transparent), transparent ${p4.stop})`;
2432
2455
  });
2433
2456
  blobs.push("radial-gradient(ellipse at center, #0a0a18 0%, #02020a 100%)");
2434
2457
  return blobs.join(", ");
@@ -2448,7 +2471,7 @@ function LabPanes({
2448
2471
  void 0,
2449
2472
  { scope: "lab" }
2450
2473
  );
2451
- const main = contributions.some((c6) => c6.region === "aside") ? /* @__PURE__ */ jsx(
2474
+ const main = contributions.some((c7) => c7.region === "aside") ? /* @__PURE__ */ jsx(
2452
2475
  Split,
2453
2476
  {
2454
2477
  className: "lk-lab__panes",
@@ -2466,7 +2489,7 @@ function LabPanes({
2466
2489
  children
2467
2490
  }
2468
2491
  ) : children;
2469
- if (!contributions.some((c6) => c6.region === "sidebar")) return main;
2492
+ if (!contributions.some((c7) => c7.region === "sidebar")) return main;
2470
2493
  return /* @__PURE__ */ jsx(
2471
2494
  Split,
2472
2495
  {
@@ -2535,14 +2558,14 @@ function LabRuntime({
2535
2558
  useLayoutEffect(() => {
2536
2559
  store.getState().setInstruments(instruments);
2537
2560
  }, [instruments, store]);
2538
- const trials = useStore(store, (s2) => s2.trials);
2561
+ const trials = useStore(store, (s3) => s3.trials);
2539
2562
  const [cameras] = useState(createCameraRegistry);
2540
2563
  const [focusPick, setFocusPick] = useState(null);
2541
2564
  const focusedTrialId = trials.some((t) => t.id === focusPick) ? focusPick : trials[0]?.id ?? null;
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);
2565
+ const savedSnapshots = useStore(store, (s3) => s3.savedSnapshots);
2566
+ const modeValue = useStore(store, (s3) => s3.mode);
2567
+ const layout = useStore(store, (s3) => s3.layout);
2568
+ const undockedPanels = useStore(store, (s3) => s3.undockedPanels);
2546
2569
  const panelHostsRef = useRef(null);
2547
2570
  if (panelHostsRef.current === null) panelHostsRef.current = createPanelHostRegistry();
2548
2571
  const outerSurface = useSurfaceOptional();
@@ -2555,24 +2578,26 @@ function LabRuntime({
2555
2578
  const bufferRef = useRef({ w: 0, h: 0 });
2556
2579
  const surfaceRef = useRef(null);
2557
2580
  const onFrame = useCallback((frame) => {
2558
- const canvases = [ownUnderRef.current, ownOverRef.current].filter((c6) => c6 !== null);
2581
+ const canvases = [ownUnderRef.current, ownOverRef.current].filter((c7) => c7 !== null);
2559
2582
  if (canvases.length === 0) return;
2560
2583
  const w2 = Math.round(frame.size.width * frame.dpr);
2561
- const h = Math.round(frame.size.height * frame.dpr);
2562
- if (bufferRef.current.w !== w2 || bufferRef.current.h !== h) {
2563
- bufferRef.current = { w: w2, h };
2564
- for (const c6 of canvases) {
2565
- c6.width = w2;
2566
- c6.height = h;
2567
- c6.style.width = `${frame.size.width}px`;
2568
- c6.style.height = `${frame.size.height}px`;
2584
+ const h2 = Math.round(frame.size.height * frame.dpr);
2585
+ if (bufferRef.current.w !== w2 || bufferRef.current.h !== h2) {
2586
+ bufferRef.current = { w: w2, h: h2 };
2587
+ for (const c7 of canvases) {
2588
+ c7.width = w2;
2589
+ c7.height = h2;
2590
+ c7.style.width = `${frame.size.width}px`;
2591
+ c7.style.height = `${frame.size.height}px`;
2569
2592
  }
2570
2593
  surfaceRef.current?.invalidateAll();
2571
2594
  return;
2572
2595
  }
2573
2596
  }, []);
2574
2597
  const ownSurface = useTiledSurface({ onFrame });
2575
- surfaceRef.current = ownSurface;
2598
+ useInsertionEffect(() => {
2599
+ surfaceRef.current = ownSurface;
2600
+ }, [ownSurface]);
2576
2601
  const [labBody, setLabBody] = useState(null);
2577
2602
  const attachOwnSurface = ownSurface.containerRef;
2578
2603
  const labBodyRef = useCallback(
@@ -2629,8 +2654,8 @@ function LabRuntime({
2629
2654
  () => labContributions([...annotationTools, ...tools ?? []], labChrome),
2630
2655
  [annotationTools, tools, labChrome]
2631
2656
  );
2632
- const hasFooterChrome = labChromeAll.some((c6) => c6.region === "footer");
2633
- const hasPaneChrome = labChromeAll.some((c6) => c6.region === "sidebar" || c6.region === "aside");
2657
+ const hasFooterChrome = labChromeAll.some((c7) => c7.region === "footer");
2658
+ const hasPaneChrome = labChromeAll.some((c7) => c7.region === "sidebar" || c7.region === "aside");
2634
2659
  useEffect(() => {
2635
2660
  if (mode && mode !== store.getState().mode) {
2636
2661
  store.getState().setMode(mode);
@@ -2682,15 +2707,15 @@ function LabRuntime({
2682
2707
  const next = resetTrial(store.getState().trials, id, instruments);
2683
2708
  const record = next.find((w2) => w2.id === id);
2684
2709
  if (!record) return;
2685
- store.setState((s2) => ({
2686
- trials: s2.trials.map(
2710
+ store.setState((s3) => ({
2711
+ trials: s3.trials.map(
2687
2712
  (w2) => w2.id === id ? { ...w2, config: record.config, state: record.state, view: record.view } : w2
2688
2713
  )
2689
2714
  }));
2690
2715
  },
2691
2716
  savedSnapshots,
2692
2717
  saveSnapshot: (trialId, name) => {
2693
- const taken = store.getState().savedSnapshots.filter((s2) => s2.trialId === trialId).length;
2718
+ const taken = store.getState().savedSnapshots.filter((s3) => s3.trialId === trialId).length;
2694
2719
  store.getState().saveSnapshot(trialId, name ?? `Snapshot ${taken + 1}`);
2695
2720
  },
2696
2721
  loadSnapshot: (trialId, snapshotId) => {
@@ -2700,8 +2725,8 @@ function LabRuntime({
2700
2725
  store.getState().deleteSnapshot(snapshotId);
2701
2726
  },
2702
2727
  mode: modeValue,
2703
- setMode: (m2) => {
2704
- store.getState().setMode(m2);
2728
+ setMode: (m) => {
2729
+ store.getState().setMode(m);
2705
2730
  },
2706
2731
  configRules,
2707
2732
  controls
@@ -2915,18 +2940,18 @@ function ButtonsAndToggles() {
2915
2940
  /* @__PURE__ */ jsx(Xt, { status: "muted", children: "MUTED" })
2916
2941
  ] }) }),
2917
2942
  /* @__PURE__ */ jsx(Cell, { label: "Checkbox, Switch", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
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" })
2943
+ /* @__PURE__ */ jsx(c6, { isSelected: snap, onChange: setSnap, children: "Snap to grid" }),
2944
+ /* @__PURE__ */ jsx(c6, { isIndeterminate: true, children: "Mixed" }),
2945
+ /* @__PURE__ */ jsx(a6, { isSelected: wifi, onChange: setWifi, children: "Wifi" })
2921
2946
  ] }) }),
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" })
2947
+ /* @__PURE__ */ jsx(Cell, { label: "RadioGroup", children: /* @__PURE__ */ jsxs(l5, { label: "Snap mode", orientation: "horizontal", defaultValue: "grid", children: [
2948
+ /* @__PURE__ */ jsx(u3, { value: "off", children: "Off" }),
2949
+ /* @__PURE__ */ jsx(u3, { value: "grid", children: "Grid" }),
2950
+ /* @__PURE__ */ jsx(u3, { value: "pixel", children: "Pixel" })
2926
2951
  ] }) }),
2927
2952
  /* @__PURE__ */ jsxs(Cell, { label: "ToggleBar", children: [
2928
2953
  /* @__PURE__ */ jsx(
2929
- a7,
2954
+ a5,
2930
2955
  {
2931
2956
  ariaLabel: "Align",
2932
2957
  value: align,
@@ -2939,7 +2964,7 @@ function ButtonsAndToggles() {
2939
2964
  }
2940
2965
  ),
2941
2966
  /* @__PURE__ */ jsx(
2942
- a7,
2967
+ a5,
2943
2968
  {
2944
2969
  ariaLabel: "Align, flat",
2945
2970
  variant: "flat",
@@ -2965,7 +2990,7 @@ function ButtonsAndToggles() {
2965
2990
  }
2966
2991
  ),
2967
2992
  /* @__PURE__ */ jsx(
2968
- a10,
2993
+ a8,
2969
2994
  {
2970
2995
  items: [
2971
2996
  { value: "undo", label: "Undo", onAction: () => {
@@ -2978,7 +3003,7 @@ function ButtonsAndToggles() {
2978
3003
  ] }) }),
2979
3004
  /* @__PURE__ */ jsx(Cell, { label: "MenuButton, Disclosure", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
2980
3005
  /* @__PURE__ */ jsx(
2981
- d3,
3006
+ p4,
2982
3007
  {
2983
3008
  label: "Add trial\u2026",
2984
3009
  onAction: () => {
@@ -2989,17 +3014,17 @@ function ButtonsAndToggles() {
2989
3014
  ]
2990
3015
  }
2991
3016
  ),
2992
- /* @__PURE__ */ jsx(i2, { open, onToggle: () => setOpen((o5) => !o5), label: "Shapes" })
3017
+ /* @__PURE__ */ jsx(i3, { open, onToggle: () => setOpen((o4) => !o4), label: "Shapes" })
2993
3018
  ] }) }),
2994
- /* @__PURE__ */ jsx(Cell, { label: "Tabs", children: /* @__PURE__ */ jsxs(o6, { children: [
3019
+ /* @__PURE__ */ jsx(Cell, { label: "Tabs", children: /* @__PURE__ */ jsxs(o5, { children: [
2995
3020
  /* @__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" })
3021
+ /* @__PURE__ */ jsx(c7, { id: "props", children: "Props" }),
3022
+ /* @__PURE__ */ jsx(c7, { id: "events", children: "Events" }),
3023
+ /* @__PURE__ */ jsx(c7, { id: "snapshot", children: "Snapshot" })
2999
3024
  ] }),
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." })
3025
+ /* @__PURE__ */ jsx(l9, { id: "props", children: "Props panel." }),
3026
+ /* @__PURE__ */ jsx(l9, { id: "events", children: "Events panel." }),
3027
+ /* @__PURE__ */ jsx(l9, { id: "snapshot", children: "Snapshot panel." })
3003
3028
  ] }) }),
3004
3029
  /* @__PURE__ */ jsx(Cell, { label: "Keycaps", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
3005
3030
  /* @__PURE__ */ jsx(p, { keys: [{ label: "\u2318" }, { label: "\u21E7" }, { label: "K" }], separator: "+" }),
@@ -3025,9 +3050,9 @@ function FieldsAndPickers() {
3025
3050
  const [paint, setPaint] = useState({ fill: "solid", color: "#b08adb" });
3026
3051
  return /* @__PURE__ */ jsxs(Section, { title: "Fields & pickers", children: [
3027
3052
  /* @__PURE__ */ jsxs(Cell, { label: "Input", children: [
3028
- /* @__PURE__ */ jsx(u3, { label: "Name", placeholder: "e.g. Pico" }),
3053
+ /* @__PURE__ */ jsx(u2, { label: "Name", placeholder: "e.g. Pico" }),
3029
3054
  /* @__PURE__ */ jsx(
3030
- u3,
3055
+ u2,
3031
3056
  {
3032
3057
  label: "Size",
3033
3058
  leadingAdornment: /* @__PURE__ */ jsx("span", { children: "W" }),
@@ -3035,12 +3060,12 @@ function FieldsAndPickers() {
3035
3060
  defaultValue: "120"
3036
3061
  }
3037
3062
  ),
3038
- /* @__PURE__ */ jsx(u3, { label: "Required", isInvalid: true, errorMessage: "Name is required." })
3063
+ /* @__PURE__ */ jsx(u2, { label: "Required", isInvalid: true, errorMessage: "Name is required." })
3039
3064
  ] }),
3040
3065
  /* @__PURE__ */ jsxs(Cell, { label: "NumberField, Select, ComboBox", children: [
3041
3066
  /* @__PURE__ */ jsx(y, { label: "Opacity", minValue: 0, maxValue: 100, step: 5, defaultValue: 80 }),
3042
3067
  /* @__PURE__ */ jsx(
3043
- E2,
3068
+ O2,
3044
3069
  {
3045
3070
  label: "Color",
3046
3071
  defaultSelectedKey: "g",
@@ -3052,7 +3077,7 @@ function FieldsAndPickers() {
3052
3077
  }
3053
3078
  ),
3054
3079
  /* @__PURE__ */ jsx(
3055
- y2,
3080
+ b4,
3056
3081
  {
3057
3082
  label: "Filter",
3058
3083
  placeholder: "Type to filter\u2026",
@@ -3064,15 +3089,15 @@ function FieldsAndPickers() {
3064
3089
  )
3065
3090
  ] }),
3066
3091
  /* @__PURE__ */ jsxs(Cell, { label: "RangeSlider, Slider", children: [
3067
- /* @__PURE__ */ jsx(l7, { label: "Range", defaultValue: [20, 80], minValue: 0, maxValue: 100 }),
3092
+ /* @__PURE__ */ jsx(l10, { label: "Range", defaultValue: [20, 80], minValue: 0, maxValue: 100 }),
3068
3093
  /* @__PURE__ */ jsx(
3069
- l7,
3094
+ l10,
3070
3095
  {
3071
3096
  label: "Opacity",
3072
3097
  defaultValue: 75,
3073
3098
  minValue: 0,
3074
3099
  maxValue: 100,
3075
- formatOutput: (v) => `${v}%`
3100
+ formatOutput: (v2) => `${v2}%`
3076
3101
  }
3077
3102
  ),
3078
3103
  /* @__PURE__ */ jsx(
@@ -3091,7 +3116,7 @@ function FieldsAndPickers() {
3091
3116
  ] }),
3092
3117
  /* @__PURE__ */ jsxs(Cell, { label: "DetentSlider, InlineRange", children: [
3093
3118
  /* @__PURE__ */ jsx(
3094
- c7,
3119
+ c8,
3095
3120
  {
3096
3121
  items: [0.25, 0.5, 1, 2, 4],
3097
3122
  value: rate,
@@ -3113,11 +3138,11 @@ function FieldsAndPickers() {
3113
3138
  )
3114
3139
  ] }),
3115
3140
  /* @__PURE__ */ jsxs(Cell, { label: "ColorField, GradientEditor", children: [
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 })
3141
+ /* @__PURE__ */ jsx(h2, { value: color, alpha: true, onInput: setColor, onChange: setColor, "aria-label": "Color" }),
3142
+ /* @__PURE__ */ jsx(j, { value: gradient, onInput: setGradient, onChange: setGradient, kindSwitch: true })
3118
3143
  ] }),
3119
3144
  /* @__PURE__ */ jsx(Cell, { label: "PaintInput", children: /* @__PURE__ */ jsx(
3120
- T,
3145
+ k2,
3121
3146
  {
3122
3147
  value: paint,
3123
3148
  onInput: setPaint,
@@ -3146,9 +3171,9 @@ function PanelsAndRows() {
3146
3171
  ]);
3147
3172
  const [panelCollapsed, setPanelCollapsed] = useState(false);
3148
3173
  return /* @__PURE__ */ jsxs(Section, { title: "Panels & property rows", children: [
3149
- /* @__PURE__ */ jsx(Cell, { label: "PropertyPanel", children: /* @__PURE__ */ jsx(re2, { title: "Shape", children: /* @__PURE__ */ jsxs(ie2, { children: [
3174
+ /* @__PURE__ */ jsx(Cell, { label: "PropertyPanel", children: /* @__PURE__ */ jsx(ae2, { title: "Shape", children: /* @__PURE__ */ jsxs(oe, { children: [
3150
3175
  /* @__PURE__ */ jsx(
3151
- R,
3176
+ de,
3152
3177
  {
3153
3178
  kind: "number",
3154
3179
  control: "slider",
@@ -3161,7 +3186,7 @@ function PanelsAndRows() {
3161
3186
  }
3162
3187
  ),
3163
3188
  /* @__PURE__ */ jsx(
3164
- R,
3189
+ de,
3165
3190
  {
3166
3191
  kind: "number",
3167
3192
  control: "slider",
@@ -3174,7 +3199,7 @@ function PanelsAndRows() {
3174
3199
  }
3175
3200
  ),
3176
3201
  /* @__PURE__ */ jsx(
3177
- R,
3202
+ de,
3178
3203
  {
3179
3204
  kind: "color",
3180
3205
  label: "Fill",
@@ -3184,9 +3209,9 @@ function PanelsAndRows() {
3184
3209
  onAlphaChange: setAlpha
3185
3210
  }
3186
3211
  ),
3187
- /* @__PURE__ */ jsx(R, { kind: "color", label: "Stroke", value: stroke, onChange: setStroke }),
3212
+ /* @__PURE__ */ jsx(de, { kind: "color", label: "Stroke", value: stroke, onChange: setStroke }),
3188
3213
  /* @__PURE__ */ jsx(
3189
- R,
3214
+ de,
3190
3215
  {
3191
3216
  kind: "number",
3192
3217
  label: "Count",
@@ -3198,7 +3223,7 @@ function PanelsAndRows() {
3198
3223
  }
3199
3224
  ),
3200
3225
  /* @__PURE__ */ jsx(
3201
- R,
3226
+ de,
3202
3227
  {
3203
3228
  kind: "enum",
3204
3229
  label: "Line cap",
@@ -3211,7 +3236,7 @@ function PanelsAndRows() {
3211
3236
  }
3212
3237
  ),
3213
3238
  /* @__PURE__ */ jsx(
3214
- R,
3239
+ de,
3215
3240
  {
3216
3241
  kind: "enum",
3217
3242
  control: "toggle",
@@ -3225,10 +3250,10 @@ function PanelsAndRows() {
3225
3250
  ]
3226
3251
  }
3227
3252
  ),
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,
3253
+ /* @__PURE__ */ jsx(de, { kind: "string", label: "Label", value: label, onChange: setLabel }),
3254
+ /* @__PURE__ */ jsx(de, { kind: "boolean", label: "Visible", value: visible, onChange: setVisible }),
3255
+ /* @__PURE__ */ jsx(b3, { title: "Bevel", defaultCollapsed: true, children: /* @__PURE__ */ jsx(
3256
+ de,
3232
3257
  {
3233
3258
  kind: "number",
3234
3259
  control: "slider",
@@ -3243,7 +3268,7 @@ function PanelsAndRows() {
3243
3268
  ) })
3244
3269
  ] }) }) }),
3245
3270
  /* @__PURE__ */ jsx(Cell, { label: "PrefsForm", children: /* @__PURE__ */ jsx(
3246
- j,
3271
+ j2,
3247
3272
  {
3248
3273
  schema: PREFS,
3249
3274
  values: prefs,
@@ -3251,10 +3276,10 @@ function PanelsAndRows() {
3251
3276
  }
3252
3277
  ) }),
3253
3278
  /* @__PURE__ */ jsx(Cell, { label: "LayerList", children: /* @__PURE__ */ jsx(
3254
- E3,
3279
+ D2,
3255
3280
  {
3256
3281
  items: layers,
3257
- onReorder: (move) => setLayers(x3(layers, move)),
3282
+ onReorder: (move) => setLayers(S2(layers, move)),
3258
3283
  renderBody: (item) => /* @__PURE__ */ jsxs("div", { children: [
3259
3284
  "settings for ",
3260
3285
  item.label
@@ -3262,11 +3287,11 @@ function PanelsAndRows() {
3262
3287
  }
3263
3288
  ) }),
3264
3289
  /* @__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(
3265
- a11,
3290
+ a9,
3266
3291
  {
3267
3292
  title: "Selection",
3268
3293
  collapsed: panelCollapsed,
3269
- onToggleCollapse: () => setPanelCollapsed((v) => !v),
3294
+ onToggleCollapse: () => setPanelCollapsed((v2) => !v2),
3270
3295
  onHide: () => {
3271
3296
  },
3272
3297
  children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__pad", children: "2 items selected" })
@@ -3278,16 +3303,16 @@ function OverlaysAndFeedback() {
3278
3303
  const calloutAnchor = useRef(null);
3279
3304
  const [calloutOpen, setCalloutOpen] = useState(false);
3280
3305
  const [dialogOpen, setDialogOpen] = useState(false);
3281
- const toasts = useMemo(() => m3(), []);
3306
+ const toasts = useMemo(() => C3(), []);
3282
3307
  return /* @__PURE__ */ jsxs(Section, { title: "Overlays & feedback", children: [
3283
3308
  /* @__PURE__ */ jsx(Cell, { label: "Tooltip, Callout, Dialog, Toast", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
3284
- /* @__PURE__ */ jsxs(l2, { children: [
3309
+ /* @__PURE__ */ jsxs(l3, { children: [
3285
3310
  /* @__PURE__ */ jsx(Focusable, { children: /* @__PURE__ */ jsx("button", { type: "button", children: "Hover me" }) }),
3286
3311
  /* @__PURE__ */ jsx(u, { placement: "bottom", children: "Duplicates the selected layer" })
3287
3312
  ] }),
3288
3313
  /* @__PURE__ */ jsx("button", { type: "button", ref: calloutAnchor, onClick: () => setCalloutOpen(true), children: "Callout" }),
3289
3314
  /* @__PURE__ */ jsx(
3290
- _2,
3315
+ v2,
3291
3316
  {
3292
3317
  triggerRef: calloutAnchor,
3293
3318
  isOpen: calloutOpen,
@@ -3299,7 +3324,7 @@ function OverlaysAndFeedback() {
3299
3324
  ),
3300
3325
  /* @__PURE__ */ jsx(c, { onClick: () => setDialogOpen(true), children: "Dialog" }),
3301
3326
  /* @__PURE__ */ jsx(
3302
- d2,
3327
+ d3,
3303
3328
  {
3304
3329
  isOpen: dialogOpen,
3305
3330
  onOpenChange: setDialogOpen,
@@ -3315,7 +3340,7 @@ function OverlaysAndFeedback() {
3315
3340
  children: "Toast"
3316
3341
  }
3317
3342
  ),
3318
- /* @__PURE__ */ jsx(S3, { queue: toasts, placement: "bottom-right" })
3343
+ /* @__PURE__ */ jsx(j3, { queue: toasts, placement: "bottom-right" })
3319
3344
  ] }) }),
3320
3345
  /* @__PURE__ */ jsx(Cell, { label: "Powerline", children: /* @__PURE__ */ jsx(
3321
3346
  r4,
@@ -3378,19 +3403,18 @@ function ToolChrome() {
3378
3403
  label: id,
3379
3404
  shortcut: id.slice(0, 1).toUpperCase(),
3380
3405
  active: tool === id,
3381
- tabbable: tool === id,
3382
3406
  onClick: () => setTool(id)
3383
3407
  },
3384
3408
  id
3385
3409
  )) }) }),
3386
- /* @__PURE__ */ jsx(Cell, { label: "ToolOptionsBar", children: /* @__PURE__ */ jsxs(c4, { label: "Text", children: [
3410
+ /* @__PURE__ */ jsx(Cell, { label: "ToolOptionsBar", children: /* @__PURE__ */ jsxs(c5, { label: "Text", children: [
3387
3411
  /* @__PURE__ */ jsx(c, { size: "sm", variant: "ghost", iconOnly: true, ariaLabel: "Bold", children: "B" }),
3388
3412
  /* @__PURE__ */ jsx(c, { size: "sm", variant: "ghost", iconOnly: true, ariaLabel: "Italic", children: "I" })
3389
3413
  ] }) }),
3390
3414
  /* @__PURE__ */ jsx(Cell, { label: "ResizeHandle", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__box", children: [
3391
3415
  /* @__PURE__ */ jsx("div", { className: "lk-specimen__box-main", children: "content" }),
3392
3416
  /* @__PURE__ */ jsx(
3393
- c5,
3417
+ l8,
3394
3418
  {
3395
3419
  value: paneWidth,
3396
3420
  min: 100,
@@ -3499,7 +3523,7 @@ function EditorsAndPlots() {
3499
3523
  }
3500
3524
  ) }),
3501
3525
  /* @__PURE__ */ jsx(Cell, { label: "BandEditor", wide: true, children: /* @__PURE__ */ jsx(
3502
- j2,
3526
+ j4,
3503
3527
  {
3504
3528
  min: 1 / 64,
3505
3529
  max: 1 / 2,
@@ -3509,12 +3533,12 @@ function EditorsAndPlots() {
3509
3533
  onChange: setBands,
3510
3534
  selectedIndex: band,
3511
3535
  onSelect: setBand,
3512
- renderBand: (b2) => b2.data.name,
3536
+ renderBand: (b3) => b3.data.name,
3513
3537
  ticks: [1 / 24, 1 / 12, 1 / 6].map((at) => ({ at, label: `1/${Math.round(1 / at)}` }))
3514
3538
  }
3515
3539
  ) }),
3516
3540
  /* @__PURE__ */ jsx(Cell, { label: "Timeline", wide: true, children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__timeline", children: /* @__PURE__ */ jsx(
3517
- ye,
3541
+ xe2,
3518
3542
  {
3519
3543
  tracks,
3520
3544
  duration: 2e3,
@@ -3577,6 +3601,6 @@ function Specimen({ className }) {
3577
3601
  ] });
3578
3602
  }
3579
3603
 
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 };
3604
+ 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, fromWeaselView, interstellarTheme, isStale, reorderTrials, resetTrial, resolveMarkStyle, seenFrom, toWeaselView, validateConfigSchema };
3581
3605
  //# sourceMappingURL=index.js.map
3582
3606
  //# sourceMappingURL=index.js.map