@weasel-js/labkit 1.7.0 → 1.7.1

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 (208) 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-4KSC7NXL.js +15491 -0
  17. package/dist/chunk-4KSC7NXL.js.map +1 -0
  18. package/dist/{chunk-7BO7HNGF.js → chunk-CEGFXTBD.js} +8 -61
  19. package/dist/chunk-CEGFXTBD.js.map +1 -0
  20. package/dist/{chunk-275JRRVD.js → chunk-E23Q6A3Y.js} +232 -37
  21. package/dist/chunk-E23Q6A3Y.js.map +1 -0
  22. package/dist/{chunk-GOZLNM4L.js → chunk-E6NARGU7.js} +5 -5
  23. package/dist/{chunk-GOZLNM4L.js.map → chunk-E6NARGU7.js.map} +1 -1
  24. package/dist/{chunk-IJJUK4FU.js → chunk-EESJUSYR.js} +5 -6
  25. package/dist/chunk-EESJUSYR.js.map +1 -0
  26. package/dist/{chunk-HXXTULDN.js → chunk-EFXRM6XQ.js} +8 -11
  27. package/dist/chunk-EFXRM6XQ.js.map +1 -0
  28. package/dist/chunk-F4ACIK7Z.js +210 -0
  29. package/dist/chunk-F4ACIK7Z.js.map +1 -0
  30. package/dist/{chunk-FMK7UQ6V.js → chunk-FB4MIZOO.js} +61 -44
  31. package/dist/chunk-FB4MIZOO.js.map +1 -0
  32. package/dist/{chunk-AWQG7FCC.js → chunk-FG3EXZDV.js} +3 -3
  33. package/dist/{chunk-AWQG7FCC.js.map → chunk-FG3EXZDV.js.map} +1 -1
  34. package/dist/{chunk-I5DUQ5HM.js → chunk-GAHELLJT.js} +75 -72
  35. package/dist/chunk-GAHELLJT.js.map +1 -0
  36. package/dist/{chunk-YT75VYRD.js → chunk-IBVRMHW5.js} +5 -5
  37. package/dist/{chunk-YT75VYRD.js.map → chunk-IBVRMHW5.js.map} +1 -1
  38. package/dist/{chunk-T5IBSPAM.js → chunk-JFOJESJF.js} +33 -23
  39. package/dist/chunk-JFOJESJF.js.map +1 -0
  40. package/dist/{chunk-RWNDDKOH.js → chunk-PMLZP7RT.js} +18 -15
  41. package/dist/chunk-PMLZP7RT.js.map +1 -0
  42. package/dist/{chunk-Y23G2VZL.js → chunk-READTDQX.js} +2 -2
  43. package/dist/chunk-READTDQX.js.map +1 -0
  44. package/dist/{chunk-JVBYV6TL.js → chunk-ROGJWDQA.js} +3 -3
  45. package/dist/{chunk-JVBYV6TL.js.map → chunk-ROGJWDQA.js.map} +1 -1
  46. package/dist/{chunk-ZIFPHIWZ.js → chunk-T6DLGEJB.js} +12 -14
  47. package/dist/chunk-T6DLGEJB.js.map +1 -0
  48. package/dist/{chunk-24W5VEJW.js → chunk-ULYYNWGP.js} +2 -2
  49. package/dist/{chunk-24W5VEJW.js.map → chunk-ULYYNWGP.js.map} +1 -1
  50. package/dist/{chunk-UNAZSLWE.js → chunk-VYVGVBGY.js} +17 -20
  51. package/dist/chunk-VYVGVBGY.js.map +1 -0
  52. package/dist/{chunk-KMJ7RWD3.js → chunk-WLMDTI2Q.js} +3 -3
  53. package/dist/{chunk-KMJ7RWD3.js.map → chunk-WLMDTI2Q.js.map} +1 -1
  54. package/dist/{chunk-J7OWWTCW.js → chunk-XE5HJOPL.js} +5 -6
  55. package/dist/chunk-XE5HJOPL.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-FZ7YFQN7.js → chunk-YCFKW5RX.js} +3 -3
  59. package/dist/chunk-YCFKW5RX.js.map +1 -0
  60. package/dist/{chunk-CQLQPQ4P.js → chunk-ZQIHJXP4.js} +2 -2
  61. package/dist/chunk-ZQIHJXP4.js.map +1 -0
  62. package/dist/config/index.d.ts +18 -10
  63. package/dist/config/index.js +4 -4
  64. package/dist/controls/index.d.ts +4 -7
  65. package/dist/controls/index.js +6 -5
  66. package/dist/dragdrop/index.d.ts +23 -3
  67. package/dist/dragdrop/index.js +4 -3
  68. package/dist/fonts/oswald-tabular-digits.woff2 +0 -0
  69. package/dist/index.d.ts +60 -714
  70. package/dist/index.js +357 -334
  71. package/dist/index.js.map +1 -1
  72. package/dist/job/index.d.ts +8 -0
  73. package/dist/job/index.js +1 -1
  74. package/dist/layers/index.d.ts +6 -5
  75. package/dist/layers/index.js +3 -2
  76. package/dist/loupe/index.d.ts +100 -30
  77. package/dist/loupe/index.js +585 -6
  78. package/dist/loupe/index.js.map +1 -1
  79. package/dist/overview/index.d.ts +4 -2
  80. package/dist/overview/index.js +15 -14
  81. package/dist/overview/index.js.map +1 -1
  82. package/dist/passthrough/weasel-canvas.d.ts +2 -0
  83. package/dist/passthrough/weasel-ui.d.ts +2 -2871
  84. package/dist/passthrough/weasel-ui.js +3 -2
  85. package/dist/primitives/index.d.ts +213 -3
  86. package/dist/primitives/index.js +8 -7
  87. package/dist/state/index.d.ts +7 -5
  88. package/dist/state/index.js +6 -6
  89. package/dist/styles.css +60 -44
  90. package/dist/surface/index.d.ts +10 -2
  91. package/dist/surface/index.js +1 -1
  92. package/dist/undo/index.d.ts +5 -3
  93. package/package.json +11 -11
  94. package/src/annotations/AnnotationOverlay.abandon.test.tsx +143 -0
  95. package/src/annotations/AnnotationOverlay.tsx +50 -31
  96. package/src/annotations/Annotations.overlay.test.tsx +31 -0
  97. package/src/annotations/capture.browser.test.ts +41 -0
  98. package/src/annotations/capture.ts +14 -7
  99. package/src/annotations/drawOne.ts +2 -2
  100. package/src/annotations/frac.test.ts +44 -1
  101. package/src/annotations/frac.ts +46 -18
  102. package/src/annotations/index.ts +1 -0
  103. package/src/annotations/paint.test.ts +74 -33
  104. package/src/annotations/paint.ts +70 -32
  105. package/src/annotations/store.test.ts +212 -2
  106. package/src/annotations/store.ts +130 -27
  107. package/src/annotations/svgNodes.test.ts +22 -10
  108. package/src/annotations/svgNodes.ts +3 -3
  109. package/src/annotations/types.ts +29 -10
  110. package/src/canvas/CameraInput.test.tsx +30 -0
  111. package/src/canvas/CameraInput.tsx +16 -15
  112. package/src/canvas/CanvasStack.tsx +5 -5
  113. package/src/canvas/CanvasStackContext.ts +4 -1
  114. package/src/canvas/Stage.tsx +3 -3
  115. package/src/canvas/cameraRegistry.ts +1 -0
  116. package/src/canvas/worldSpec.ts +3 -1
  117. package/src/chrome/builtins.test.ts +7 -6
  118. package/src/chrome/builtins.tsx +5 -1
  119. package/src/chrome/index.ts +1 -1
  120. package/src/chrome/merge.test.ts +5 -0
  121. package/src/chrome/merge.ts +4 -2
  122. package/src/chrome/regions/PaletteRegion.test.tsx +2 -3
  123. package/src/chrome/regions/PaletteRegion.tsx +3 -4
  124. package/src/chrome/regions/ViewportRegion.browser.test.less +6 -0
  125. package/src/chrome/regions/ViewportRegion.browser.test.tsx +38 -0
  126. package/src/chrome/regions/ViewportRegion.less +6 -0
  127. package/src/chrome/regions/ViewportRegion.tsx +10 -4
  128. package/src/chrome/types.ts +4 -2
  129. package/src/config/auto.ts +1 -0
  130. package/src/config/builder.ts +6 -0
  131. package/src/config/types.ts +2 -1
  132. package/src/controls/ControlPanel.test.tsx +37 -3
  133. package/src/controls/ControlPanel.tsx +12 -3
  134. package/src/dragdrop/DragDropRuntime.tsx +22 -13
  135. package/src/dragdrop/DragGhost.tsx +3 -0
  136. package/src/dragdrop/Palette.tsx +2 -0
  137. package/src/index.test.ts +5 -0
  138. package/src/index.ts +1 -1
  139. package/src/instrument/types.ts +0 -6
  140. package/src/job/useJob.ts +14 -9
  141. package/src/lab/Lab.tsx +5 -1
  142. package/src/lab/LabShell.less +1 -0
  143. package/src/lab/LabSwitcher.browser.test.tsx +27 -0
  144. package/src/lab/LabSwitcher.less +2 -0
  145. package/src/lab/LabZoom.tsx +4 -4
  146. package/src/lab/Workspace.tsx +48 -52
  147. package/src/loupe/AGENTS.md +28 -15
  148. package/src/loupe/CanvasLoupe.tsx +2 -3
  149. package/src/loupe/DomLoupe.tsx +1 -7
  150. package/src/loupe/Loupe.less +16 -0
  151. package/src/loupe/TrialLoupe.tsx +120 -57
  152. package/src/loupe/index.ts +1 -6
  153. package/src/loupe/types.test.ts +3 -3
  154. package/src/loupe/types.ts +24 -27
  155. package/src/loupe/useLoupe.test.tsx +29 -4
  156. package/src/loupe/useLoupe.ts +20 -17
  157. package/src/overview/OverviewMarks.tsx +12 -4
  158. package/src/overview/TrialOverview.tsx +3 -3
  159. package/src/passthrough/weasel-ui.test.ts +1 -1
  160. package/src/passthrough/weasel-ui.ts +1 -1
  161. package/src/primitives/FloatingPanel.tsx +7 -3
  162. package/src/primitives/JobProgress.less +1 -0
  163. package/src/primitives/Readout.test.tsx +2 -2
  164. package/src/primitives/Split.tsx +69 -41
  165. package/src/primitives/Toolbar.tsx +3 -3
  166. package/src/primitives/ZoomControl.less +1 -2
  167. package/src/specimen/Specimen.tsx +0 -1
  168. package/src/state/undock.ts +3 -0
  169. package/src/state/useOpenOnce.ts +20 -16
  170. package/src/state/view.ts +1 -0
  171. package/src/surface/index.ts +1 -1
  172. package/src/surface/useTiledSurface.test.tsx +14 -0
  173. package/src/surface/useTiledSurface.ts +11 -3
  174. package/src/trial/Trial.annotations.test.tsx +73 -0
  175. package/src/trial/Trial.less +0 -16
  176. package/src/trial/Trial.loupe.test.tsx +28 -11
  177. package/src/trial/Trial.tsx +74 -62
  178. package/src/trial/TrialChrome.tsx +6 -3
  179. package/src/trial/index.ts +2 -0
  180. package/src/trial/loupeSwitch.ts +15 -0
  181. package/dist/_dts/LayerList.d-DiuEArKq.d.ts +0 -83
  182. package/dist/_dts/PrefsRow.d-TOZ7BgD9.d.ts +0 -79
  183. package/dist/_dts/PropertyPanel.d-D-1paCbE.d.ts +0 -141
  184. package/dist/_dts/Select.d-Bensr_MT.d.ts +0 -579
  185. package/dist/_dts/index-B2Yj5aA0.d.ts +0 -274
  186. package/dist/chunk-275JRRVD.js.map +0 -1
  187. package/dist/chunk-4LJSC7MB.js +0 -143
  188. package/dist/chunk-4LJSC7MB.js.map +0 -1
  189. package/dist/chunk-7BO7HNGF.js.map +0 -1
  190. package/dist/chunk-CQLQPQ4P.js.map +0 -1
  191. package/dist/chunk-FMK7UQ6V.js.map +0 -1
  192. package/dist/chunk-FZ7YFQN7.js.map +0 -1
  193. package/dist/chunk-HXXTULDN.js.map +0 -1
  194. package/dist/chunk-I5DUQ5HM.js.map +0 -1
  195. package/dist/chunk-IJJUK4FU.js.map +0 -1
  196. package/dist/chunk-J7OWWTCW.js.map +0 -1
  197. package/dist/chunk-M7HP3FTK.js +0 -549
  198. package/dist/chunk-M7HP3FTK.js.map +0 -1
  199. package/dist/chunk-MIM5R4ZT.js +0 -14972
  200. package/dist/chunk-MIM5R4ZT.js.map +0 -1
  201. package/dist/chunk-RWNDDKOH.js.map +0 -1
  202. package/dist/chunk-T5IBSPAM.js.map +0 -1
  203. package/dist/chunk-UNAZSLWE.js.map +0 -1
  204. package/dist/chunk-WPLAANH4.js.map +0 -1
  205. package/dist/chunk-Y23G2VZL.js.map +0 -1
  206. package/dist/chunk-ZIFPHIWZ.js.map +0 -1
  207. package/src/primitives/useRovingTabIndex.test.ts +0 -48
  208. package/src/primitives/useRovingTabIndex.ts +0 -88
package/dist/index.js CHANGED
@@ -1,66 +1,67 @@
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-GAHELLJT.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-GAHELLJT.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-FB4MIZOO.js';
17
+ export { JobProgress, Legend, Readout, Split } from './chunk-FB4MIZOO.js';
18
+ import { FloatingPanel } from './chunk-XE5HJOPL.js';
19
+ export { FloatingPanel } from './chunk-XE5HJOPL.js';
20
+ import { Toolbar, StatusBar, ScaleIndicator, ZoomControl } from './chunk-CEGFXTBD.js';
21
+ export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl } from './chunk-CEGFXTBD.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 { ControlPanel, inDialog, summarizeValue } from './chunk-JFOJESJF.js';
28
+ import { useConfigSchema } from './chunk-E6NARGU7.js';
29
+ export { sectionTree, useConfigSchema } from './chunk-E6NARGU7.js';
30
30
  import { useLabContext, LabContext } from './chunk-Z76KEZAX.js';
31
31
  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';
32
+ import { useResolvedConfig } from './chunk-YCFKW5RX.js';
33
+ export { BaseNode, BooleanNode, ColorNode, CustomNode, EnumNode, GroupNode, ListNode, NumberNode, StringNode, ValueNode, applyRules, builtinRules, f, isConfigBranch, resolveConfigSchema, titleCase, useResolvedConfig } from './chunk-YCFKW5RX.js';
34
+ export { fromConfigFields, isLeafVisible } from './chunk-WLMDTI2Q.js';
35
+ import { hasConfigPath, schemaNodeAtPath, applyConfigWrite, resolveAutoConfig, isAuto, isRecord, autoPathsOf, fillConfigDefaults } from './chunk-READTDQX.js';
36
+ export { auto, autoPathsOf, fillConfigDefaults, hasConfigPath, isAuto, resolveAutoConfig, schemaNodeAtPath, valueAtPath, withValueAtPath } from './chunk-READTDQX.js';
37
+ import { CanvasStack, Stage, fitStage } from './chunk-T6DLGEJB.js';
38
+ export { CanvasStack, Stage, fitStage } from './chunk-T6DLGEJB.js';
39
+ export { centerOn, zoomAt } from './chunk-ROGJWDQA.js';
40
+ export { screenToWorld, worldToScreen } from './chunk-FG3EXZDV.js';
41
41
  import { useSurfaceOptional, useSurfaceCanvas, useTileId, SurfaceContext, SurfaceCanvasContext } from './chunk-WIG6XHJ7.js';
42
42
  export { SurfaceCanvasContext, SurfaceContext, useSurface, useSurfaceCanvas, useSurfaceOptional, useSurfaceTile, useTileId } from './chunk-WIG6XHJ7.js';
43
- import { CameraWheelContext, as2DView, CameraRegistryContext, DEFAULT_VIEW, CameraPublishContext, createCameraRegistry, withZoom } from './chunk-UNAZSLWE.js';
44
- export { CameraContext, CameraInput, CameraPublishContext, CameraRegistryContext, CameraScope, DEFAULT_VIEW, as2DView, createCameraRegistry, usePublishCamera } from './chunk-UNAZSLWE.js';
45
- import { applyCamera } from './chunk-24W5VEJW.js';
46
- export { DEFAULT_FRAME, applyCamera, resolveFrame } from './chunk-24W5VEJW.js';
47
- import { CanvasStackContext } from './chunk-CQLQPQ4P.js';
48
- export { CanvasStackContext } from './chunk-CQLQPQ4P.js';
43
+ import { CameraWheelContext, as2DView, CameraRegistryContext, DEFAULT_VIEW, CameraPublishContext, createCameraRegistry, withZoom } from './chunk-VYVGVBGY.js';
44
+ export { CameraContext, CameraInput, CameraPublishContext, CameraRegistryContext, CameraScope, DEFAULT_VIEW, as2DView, createCameraRegistry, usePublishCamera } from './chunk-VYVGVBGY.js';
45
+ import { applyCamera } from './chunk-ULYYNWGP.js';
46
+ export { DEFAULT_FRAME, applyCamera, resolveFrame } from './chunk-ULYYNWGP.js';
47
+ import { CanvasStackContext } from './chunk-ZQIHJXP4.js';
48
+ export { CanvasStackContext } from './chunk-ZQIHJXP4.js';
49
49
  import { LabStoreContext, TrialIdProvider, TrialIdContext } from './chunk-2YILQ7Y5.js';
50
50
  export { LabStoreContext, LabStoreProvider, TrialIdContext, TrialIdProvider, useLabStore, useTrialId } from './chunk-2YILQ7Y5.js';
51
51
  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';
52
+ import { D2, S2, X, U, G, p4, o3, c, Xt, c5, a7, l4, u3, a6, r3, a9, i2, o5, s3, c6, l8, p, f2, u2, y, O2, b4, l9, S, c7, i4, h2, j, k2, oe, se, R, b3, j2, n6, a10, C3, l2, u, v2, d3, j3, r4, n7, r5, i5, p2, f, n8, o4, c4, l7, w, L, n9, j4, be, n2 } from './chunk-4KSC7NXL.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, u2 as Input, l10 as Jog, D2 as LayerList, re as PauseIcon, ne as PlayIcon, z2 as PropertyControl, R as PropertyField, b3 as PropertyGroup, se as PropertyList, oe as PropertyPanel, F2 as PropertyRow, ce as PropertySpan, B as ResetIcon, O2 as Select, ae as StepBackIcon, $ as StepForwardIcon, ie as StopIcon, x2 as Subpanel, a6 as ToggleBar, oe2 as TokenPanel, H2 as inferTokenType, S2 as moveLayers, O3 as refitScale } from './chunk-4KSC7NXL.js';
54
+ import { serializeSvg } from './chunk-E23Q6A3Y.js';
55
+ import './chunk-XVUKDSYV.js';
56
+ 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';
57
+ import { createContext, useState, useRef, useEffect, useInsertionEffect, useCallback, useContext, useMemo, useSyncExternalStore, useLayoutEffect, useId, Children } from 'react';
57
58
  import { flushSync, createPortal } from 'react-dom';
58
59
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
59
60
  import { defineTheme, weaselTheme, colorCount, resolveTheme, colorAt } from '@weasel-js/theme';
60
61
  import { useResolvedColorMode, useThemeOptional, ThemeProvider, ThemeContext } from '@weasel-js/theme/react';
61
62
  import { useStore } from 'zustand/react';
62
63
  import { Provider, StrategyRegistryProvider, DragProvider, Container, useDragHandle } from 'windease/react';
63
- import { asNodeId, Store, createNode, floatingStrategy, gridStrategy } from 'windease';
64
+ import { asNodeId, createNode, floatingStrategy, gridStrategy, Store } from 'windease';
64
65
  import { Focusable } from 'react-aria-components';
65
66
 
66
67
  // src/annotations/staleness.ts
@@ -68,8 +69,8 @@ function seenFrom(config, keys) {
68
69
  const out = {};
69
70
  if (config === null || typeof config !== "object") return out;
70
71
  const src = config;
71
- for (const k of keys) {
72
- if (k in src) out[k] = src[k];
72
+ for (const k2 of keys) {
73
+ if (k2 in src) out[k2] = src[k2];
73
74
  }
74
75
  return out;
75
76
  }
@@ -77,16 +78,16 @@ function isStale(seen, config, keys) {
77
78
  if (!seen || keys.length === 0) return false;
78
79
  if (config === null || typeof config !== "object") return false;
79
80
  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;
81
+ for (const k2 of keys) {
82
+ if (!(k2 in seen)) continue;
83
+ if (!Object.is(seen[k2], src[k2])) return true;
83
84
  }
84
85
  return false;
85
86
  }
86
87
 
87
88
  // src/annotations/drawOne.ts
88
89
  function createMarkDrawOne(opts) {
89
- return (node, pose) => markCommands({ pose, data: node.data }, opts.content, resolveMarkStyle(node.data, opts));
90
+ return (node, pose, view) => markCommands({ pose, data: node.data }, resolveMarkStyle(node.data, opts), view.scale);
90
91
  }
91
92
  function resolveMarkStyle(data, opts) {
92
93
  return {
@@ -103,7 +104,7 @@ function capturePlan(base, format) {
103
104
  if (format === "svg") return "svg-document";
104
105
  return base?.kind === "svg" ? "svg-document" : "raster-stack";
105
106
  }
106
- function nestBaseSvg(markup, w2, h) {
107
+ function nestBaseSvg(markup, w2, h2) {
107
108
  const doc = new DOMParser().parseFromString(markup, "image/svg+xml");
108
109
  const root = doc.documentElement;
109
110
  if (doc.getElementsByTagName("parsererror").length > 0 || root.localName !== "svg") {
@@ -112,40 +113,40 @@ function nestBaseSvg(markup, w2, h) {
112
113
  root.setAttribute("x", "0");
113
114
  root.setAttribute("y", "0");
114
115
  root.setAttribute("width", String(w2));
115
- root.setAttribute("height", String(h));
116
+ root.setAttribute("height", String(h2));
116
117
  return new XMLSerializer().serializeToString(root);
117
118
  }
118
- function embedRasterBase(base, w2, h, onWarn) {
119
+ function embedRasterBase(base, w2, h2, onWarn) {
119
120
  const href = base.kind === "canvas" ? base.canvas.toDataURL() : base.kind === "image" ? base.src : "";
120
121
  if (base.kind === "image" && !href.startsWith("data:")) {
121
122
  onWarn?.(`base image '${href}' is a reference, so this SVG is not self-contained`);
122
123
  }
123
- return serializeSvg([{ kind: "image", href, x: 0, y: 0, width: w2, height: h }], {
124
- viewBox: { x: 0, y: 0, width: w2, height: h }
124
+ return serializeSvg([{ kind: "image", href, x: 0, y: 0, width: w2, height: h2 }], {
125
+ viewBox: { x: 0, y: 0, width: w2, height: h2 }
125
126
  });
126
127
  }
127
- function markNodesOf(scene, draw) {
128
+ function markNodesOf(scene, draw, scale) {
128
129
  return [...scene.renderOrder()].flatMap((id) => {
129
130
  const node = scene.get(asNodeId$1(String(id)));
130
131
  if (!node) return [];
131
132
  return markSvgNodes(
132
133
  { pose: node.pose, data: node.data },
133
- draw.content,
134
- resolveMarkStyle(node.data, draw)
134
+ resolveMarkStyle(node.data, draw),
135
+ { x: scale, y: scale }
135
136
  );
136
137
  });
137
138
  }
138
139
  function composeCaptureSvg(args) {
139
140
  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 },
141
+ const { w: w2, h: h2 } = draw.content;
142
+ const baseXml = base === void 0 ? "" : base.kind === "svg" ? nestBaseSvg(base.markup, w2, h2) : embedRasterBase(base, w2, h2, onWarn);
143
+ const marksXml = serializeSvg(markNodesOf(scene, draw, scale), {
144
+ viewBox: { x: 0, y: 0, width: w2, height: h2 },
144
145
  onWarn
145
146
  });
146
147
  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>`;
148
+ const outH = Math.max(1, Math.round(h2 * scale));
149
+ return `<svg xmlns="${SVG_NS}" width="${outW}" height="${outH}" viewBox="0 0 ${w2} ${h2}">${baseXml}${marksXml}</svg>`;
149
150
  }
150
151
  function context2d(width, height) {
151
152
  const canvas = document.createElement("canvas");
@@ -195,12 +196,14 @@ async function stackRaster(args) {
195
196
  const ctx = context2d(width, height);
196
197
  if (base?.kind === "image") ctx.drawImage(await loadImage(base.src), 0, 0, width, height);
197
198
  else if (base?.kind === "canvas") ctx.drawImage(base.canvas, 0, 0, width, height);
198
- const raster = renderSceneToPixels({
199
+ const render = {
199
200
  scene,
200
201
  sourceRect: { x: 0, y: 0, width: draw.content.w, height: draw.content.h },
201
202
  scale: { x: scale, y: scale },
202
203
  drawOne: createMarkDrawOne(draw)
203
- });
204
+ };
205
+ await warmRender({ render });
206
+ const raster = renderSceneToPixels(render);
204
207
  const marks = context2d(raster.width, raster.height);
205
208
  marks.putImageData(
206
209
  new ImageData(Uint8ClampedArray.from(raster.data), raster.width, raster.height),
@@ -238,36 +241,6 @@ async function captureTarget(args, opts = {}) {
238
241
  return { target: args.target, blob, format, width, height };
239
242
  }
240
243
 
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
244
  // src/annotations/history.ts
272
245
  var MarkHistory = class {
273
246
  depth = /* @__PURE__ */ new Map();
@@ -349,6 +322,19 @@ function createAnnotationScene() {
349
322
  return createScene({ systemLayers: [{ id: "marks" }] });
350
323
  }
351
324
  var NO_CONTENT = { w: 0, h: 0 };
325
+ function shapeFor(kind, points, frac) {
326
+ if (!points || kind === "point") return void 0;
327
+ return roundPoints(toShape(points, frac));
328
+ }
329
+ function migrateLegacyPoints(raw, content) {
330
+ const nodes = raw.nodes.map((n6) => {
331
+ const { points, ...data } = n6.data;
332
+ if (!points || data.shape) return n6;
333
+ const shape = shapeFor(data.kind, points, worldToFrac(n6.pose, content));
334
+ return { ...n6, data: { ...data, ...shape ? { shape } : {} } };
335
+ });
336
+ return { ...raw, nodes };
337
+ }
352
338
  function splitId(id) {
353
339
  const at = id.lastIndexOf("/");
354
340
  return at <= 0 ? void 0 : { target: id.slice(0, at), node: id.slice(at + 1) };
@@ -361,26 +347,63 @@ function createAnnotationStore(opts) {
361
347
  const notify = () => {
362
348
  for (const fn of subs) fn();
363
349
  };
350
+ let holding = 0;
351
+ let heldDirty = false;
352
+ const hold = (fn) => {
353
+ holding += 1;
354
+ try {
355
+ fn();
356
+ } finally {
357
+ holding -= 1;
358
+ }
359
+ if (holding === 0 && heldDirty) {
360
+ heldDirty = false;
361
+ notify();
362
+ }
363
+ };
364
+ const exclusive = () => (typeof opts.selection === "function" ? opts.selection() : opts.selection) !== "per-target";
365
+ const lastSelection = /* @__PURE__ */ new Map();
366
+ const selectionKey = (scene) => scene.getSelection().map(String).join(" ");
367
+ const clearOthers = (keep) => {
368
+ for (const [target, scene] of scenes) {
369
+ if (target !== keep && scene.getSelection().length > 0) scene.setSelection([]);
370
+ }
371
+ };
372
+ const targetOf = (id) => targets().find((t) => t.id === id);
373
+ const contentOf = (id) => targetOf(id)?.content ?? NO_CONTENT;
364
374
  const sceneFor = (target) => {
365
375
  const known = scenes.get(target);
366
376
  if (known) return known;
367
377
  const raw = restore?.[target];
368
378
  const scene = raw ? sceneFromJSON(
369
- raw,
379
+ migrateLegacyPoints(raw, contentOf(target)),
370
380
  {}
371
381
  ) : createAnnotationScene();
372
382
  scenes.set(target, scene);
373
383
  history.track(target, scene);
384
+ lastSelection.set(target, selectionKey(scene));
374
385
  scene.subscribe(() => {
375
386
  history.observe(target, scene);
376
- notify();
387
+ const selected = selectionKey(scene);
388
+ const newlySelected = selected !== "" && selected !== lastSelection.get(target);
389
+ lastSelection.set(target, selected);
390
+ if (holding > 0) {
391
+ heldDirty = true;
392
+ return;
393
+ }
394
+ if (newlySelected && exclusive()) {
395
+ hold(() => {
396
+ heldDirty = true;
397
+ clearOthers(target);
398
+ });
399
+ } else {
400
+ notify();
401
+ }
377
402
  });
378
403
  return scene;
379
404
  };
380
405
  const historySceneAt = (target) => scenes.get(target);
381
406
  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
407
  const drawOptionsFor = (info) => ({
385
408
  content: info.content,
386
409
  positionDependsOn: info.positionDependsOn,
@@ -390,12 +413,10 @@ function createAnnotationStore(opts) {
390
413
  const project = (target, node) => {
391
414
  const found = scenes.get(target)?.get(asNodeId$1(node));
392
415
  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
- };
416
+ const { shape, ...data } = found.data;
417
+ const frac = roundFrac(worldToFrac(found.pose, contentOf(target)));
418
+ const points = data.kind === "point" ? [{ x: frac.x, y: frac.y }] : shape && roundPoints(fromShape(shape, frac));
419
+ return { ...data, target, id: `${target}/${node}`, frac, ...points ? { points } : {} };
399
420
  };
400
421
  const liveTargets = () => {
401
422
  const declared = targets().map((t) => t.id);
@@ -476,20 +497,24 @@ function createAnnotationStore(opts) {
476
497
  },
477
498
  setSelection(ids) {
478
499
  const wanted = /* @__PURE__ */ new Map();
500
+ const only = exclusive();
479
501
  for (const id of ids) {
480
502
  const found = nodeOf(id);
481
503
  if (!found) continue;
504
+ if (only && wanted.size > 0 && !wanted.has(found.target)) continue;
482
505
  const node = String(found.node.id);
483
506
  const on = wanted.get(found.target);
484
507
  if (!on) wanted.set(found.target, [node]);
485
508
  else if (!on.includes(node)) on.push(node);
486
509
  }
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
- }
510
+ hold(() => {
511
+ for (const [target, scene] of scenes) {
512
+ const next = wanted.get(target) ?? [];
513
+ const now = scene.getSelection();
514
+ if (now.length === next.length && next.every((n6, i5) => String(now[i5]) === n6)) continue;
515
+ scene.setSelection(next.map(asNodeId$1));
516
+ }
517
+ });
493
518
  },
494
519
  subscribe(fn) {
495
520
  subs.add(fn);
@@ -499,10 +524,12 @@ function createAnnotationStore(opts) {
499
524
  },
500
525
  add(init, config) {
501
526
  const target = targetOf(init.target);
527
+ const frac = roundFrac(init.frac);
528
+ const shape = shapeFor(init.kind, init.points, frac);
502
529
  const data = {
503
530
  target: init.target,
504
531
  kind: init.kind,
505
- ...init.points ? { points: init.points } : {},
532
+ ...shape ? { shape } : {},
506
533
  ...init.title !== void 0 ? { title: init.title } : {},
507
534
  ...init.status !== void 0 ? { status: init.status } : {},
508
535
  ...init.tags !== void 0 ? { tags: init.tags } : {},
@@ -512,7 +539,7 @@ function createAnnotationStore(opts) {
512
539
  const node = sceneFor(init.target).add({
513
540
  kind: "leaf",
514
541
  layer: "marks",
515
- pose: fracToWorld(roundFrac(init.frac), target?.content ?? NO_CONTENT),
542
+ pose: fracToWorld(frac, target?.content ?? NO_CONTENT),
516
543
  data
517
544
  });
518
545
  return `${init.target}/${String(node)}`;
@@ -520,14 +547,18 @@ function createAnnotationStore(opts) {
520
547
  update(id, patch) {
521
548
  const found = nodeOf(id);
522
549
  if (!found) return;
523
- const { frac, ...meaning } = patch;
550
+ const { frac: fracPatch, points, ...meaning } = patch;
524
551
  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)));
552
+ const content = contentOf(found.target);
553
+ const frac = fracPatch ?? (points ? boundsOf(points) : null);
554
+ const bounds = roundFrac(frac ?? worldToFrac(found.node.pose, content));
555
+ const shape = points ? shapeFor(found.node.data.kind, points, bounds) : void 0;
556
+ if (Object.keys(meaning).length > 0 || shape) {
557
+ found.scene.update(nid, {
558
+ data: { ...found.node.data, ...meaning, ...shape ? { shape } : {} }
559
+ });
530
560
  }
561
+ if (frac) found.scene.setPose(nid, fracToWorld(bounds, content));
531
562
  },
532
563
  setMeta(id, meta) {
533
564
  const found = nodeOf(id);
@@ -582,17 +613,17 @@ function annotationsFromJSON(raw, targets, rest = {}) {
582
613
  }
583
614
 
584
615
  // 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 } };
616
+ function toWeaselView(v2) {
617
+ return { x: v2.pan.x, y: v2.pan.y, scale: { x: v2.zoom, y: v2.zoom } };
587
618
  }
588
- function fromWeaselView(v) {
589
- return { zoom: v.scale.x, pan: { x: v.x, y: v.y } };
619
+ function fromWeaselView(v2) {
620
+ return { zoom: v2.scale.x, pan: { x: v2.x, y: v2.y } };
590
621
  }
591
622
  function fitView(content, pane) {
592
623
  const zoom = content.w > 0 && content.h > 0 ? Math.min(pane.w / content.w, pane.h / content.h) : 1;
593
624
  return { zoom: Number.isFinite(zoom) && zoom > 0 ? zoom : 1, pan: { x: 0, y: 0 } };
594
625
  }
595
- var sameRect = (a6, b2) => a6 !== null && a6.x === b2.x && a6.y === b2.y && a6.w === b2.w && a6.h === b2.h;
626
+ var sameRect = (a6, b3) => a6 !== null && a6.x === b3.x && a6.y === b3.y && a6.w === b3.w && a6.h === b3.h;
596
627
  function ToolBridge({ toolId }) {
597
628
  const tools = useActiveToolContext();
598
629
  const setActive = tools.setActive;
@@ -601,19 +632,24 @@ function ToolBridge({ toolId }) {
601
632
  }, [toolId, setActive]);
602
633
  return null;
603
634
  }
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
- }
635
+ function verticesOf(extras) {
636
+ if (extras.kind === "line") return [extras.a, extras.b];
612
637
  if (extras.kind === "pencil") {
613
- return extras.samples.map(toFrac);
638
+ const samples = extras.samples;
639
+ return samples.length > 0 ? samples : void 0;
614
640
  }
615
641
  return void 0;
616
642
  }
643
+ function insertedGeometry(extras) {
644
+ const vertices = verticesOf(extras);
645
+ if (!vertices) return void 0;
646
+ const box = boundsOf(vertices);
647
+ if (!box) return void 0;
648
+ return {
649
+ pose: { x: box.x, y: box.y, width: box.w, height: box.h },
650
+ shape: roundPoints(toShape(vertices, box))
651
+ };
652
+ }
617
653
  function AnnotationOverlay({
618
654
  target,
619
655
  scene,
@@ -626,10 +662,9 @@ function AnnotationOverlay({
626
662
  const [rect, setRect] = useState(null);
627
663
  const [input, setInput] = useState(null);
628
664
  const sceneCanvas = useRef(null);
629
- const toolRef = useRef(activeToolId);
630
- toolRef.current = activeToolId;
631
- const configRef = useRef(config);
632
- configRef.current = config;
665
+ useEffect(() => registerNodeShape(POINT_MARK_SHAPE, { priority: "high" }), []);
666
+ const toolRef = useLatest(activeToolId);
667
+ const configRef = useLatest(config);
633
668
  const id = target.id;
634
669
  const tileId = useTileId(id);
635
670
  const lastTile = useRef(null);
@@ -647,9 +682,10 @@ function AnnotationOverlay({
647
682
  [surface, tileId]
648
683
  );
649
684
  const painted = useRef(false);
650
- const canvasRef = useRef(canvas);
651
- if (canvasRef.current !== canvas) painted.current = false;
652
- canvasRef.current = canvas;
685
+ const canvasRef = useLatest(canvas);
686
+ useInsertionEffect(() => {
687
+ painted.current = false;
688
+ }, [canvas]);
653
689
  const unsubscribeFrame = useRef(null);
654
690
  const attachSceneCanvas = useCallback((api) => {
655
691
  sceneCanvas.current = api;
@@ -669,7 +705,7 @@ function AnnotationOverlay({
669
705
  gl.clearColor(0, 0, 0, 0);
670
706
  gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
671
707
  });
672
- }, [surface, tileId]);
708
+ }, [canvasRef, surface, tileId]);
673
709
  const wheelSlot = useContext(CameraWheelContext);
674
710
  useEffect(() => {
675
711
  if (!input || !wheelSlot) return;
@@ -699,14 +735,11 @@ function AnnotationOverlay({
699
735
  const info = annotationToolInfo(toolRef.current);
700
736
  const kind = info?.kind;
701
737
  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 };
738
+ const seen = seenFrom(configRef.current, target.positionDependsOn ?? []);
739
+ const geometry = insertedGeometry(extras);
740
+ if (!geometry) return { data: { target: id, kind, seen } };
741
+ const data = { target: id, kind, shape: geometry.shape, seen };
742
+ return { data, pose: geometry.pose };
710
743
  };
711
744
  }
712
745
  const box = {
@@ -1123,7 +1156,7 @@ function TrialChrome({
1123
1156
  const dockPanelAction = useStore(storeCtx.store, (s2) => s2.dockPanel);
1124
1157
  const undockedPanels = useStore(storeCtx.store, (s2) => s2.undockedPanels);
1125
1158
  const undockedIds = useMemo(
1126
- () => Object.values(undockedPanels).filter((p3) => p3.trialId === trialId).map((p3) => p3.sectionId),
1159
+ () => Object.values(undockedPanels).filter((p4) => p4.trialId === trialId).map((p4) => p4.sectionId),
1127
1160
  [undockedPanels, trialId]
1128
1161
  );
1129
1162
  const view2d = as2DView(record.view);
@@ -1157,6 +1190,7 @@ function TrialChrome({
1157
1190
  canRedo: undoBindings?.canRedo ?? false,
1158
1191
  undo: undoBindings?.undo ?? NO_OP,
1159
1192
  redo: undoBindings?.redo ?? NO_OP,
1193
+ hasLoupe: loupe != null,
1160
1194
  loupeOn: loupe?.on ?? false,
1161
1195
  toggleLoupe: loupe?.toggle ?? NO_OP,
1162
1196
  configSchema,
@@ -1226,7 +1260,8 @@ function TrialChrome({
1226
1260
  [...trialChrome ?? []],
1227
1261
  [...chrome ?? []]
1228
1262
  ),
1229
- suppress ?? []
1263
+ suppress ?? [],
1264
+ TRANSIENT_BUILTINS
1230
1265
  ),
1231
1266
  [instrument, ctx, trialChrome, chrome, suppress, lab.controls]
1232
1267
  );
@@ -1374,7 +1409,6 @@ function TrialRuntime({
1374
1409
  );
1375
1410
  const [pointer] = useState(createPointerStore);
1376
1411
  const canvasContainerRef = useRef(null);
1377
- const loupeHostRef = useRef(null);
1378
1412
  const updateTrialState = useStore(store, (s2) => s2.updateTrialState);
1379
1413
  const updateTrialConfig = useStore(store, (s2) => s2.updateTrialConfig);
1380
1414
  const updateTrialView = useStore(store, (s2) => s2.updateTrialView);
@@ -1391,8 +1425,14 @@ function TrialRuntime({
1391
1425
  const [layerVisibility, setLayerVisibility] = useState({});
1392
1426
  const [layerOrder, setLayerOrder] = useState(null);
1393
1427
  const [loupeOn, setLoupeOn] = useState(false);
1428
+ const [lenses, setLenses] = useState(0);
1429
+ const mountLens = useCallback(() => {
1430
+ setLenses((n6) => n6 + 1);
1431
+ return () => setLenses((n6) => n6 - 1);
1432
+ }, []);
1433
+ const loupeSwitch = useMemo(() => ({ on: loupeOn, mount: mountLens }), [loupeOn, mountLens]);
1394
1434
  const visibleLayers = useMemo(
1395
- () => (instrument.canvas?.layers ?? []).filter((l7) => layerVisibility[l7.id] !== false).map((l7) => l7.id),
1435
+ () => (instrument.canvas?.layers ?? []).filter((l8) => layerVisibility[l8.id] !== false).map((l8) => l8.id),
1396
1436
  [instrument.canvas, layerVisibility]
1397
1437
  );
1398
1438
  const undoCap = instrument.undo;
@@ -1405,7 +1445,7 @@ function TrialRuntime({
1405
1445
  const snap = structuredClone(current.state);
1406
1446
  updateTrialUndoStack(record.id, (prev) => pushSnapshot(prev, snap, maxDepth));
1407
1447
  };
1408
- const setView = (v) => updateTrialView(record.id, v);
1448
+ const setView = (v2) => updateTrialView(record.id, v2);
1409
1449
  const stage = instrument.canvas ? void 0 : instrument.stage;
1410
1450
  const placeView = (size) => {
1411
1451
  const declared = instrument.canvas?.initialView ?? (stage ? stage.initialView ?? ((vp) => fitStage(stage.size, vp)) : void 0);
@@ -1414,29 +1454,48 @@ function TrialRuntime({
1414
1454
  setView(declared(size));
1415
1455
  };
1416
1456
  const annotationsCap = instrument.annotations;
1417
- const targetsRef = useRef(() => []);
1418
- targetsRef.current = () => annotationsCap ? annotationsCap.targets(record.state, config, { id: record.id, view: record.view }) : [];
1457
+ const targetsRef = useLatest(
1458
+ () => annotationsCap ? annotationsCap.targets(record.state, config, { id: record.id, view: record.view }) : []
1459
+ );
1419
1460
  const annotationsRef = useRef(null);
1420
- const configRef = useRef(config);
1421
- configRef.current = config;
1422
- const capRef = useRef(annotationsCap);
1423
- capRef.current = annotationsCap;
1461
+ const configRef = useLatest(config);
1462
+ const capRef = useLatest(annotationsCap);
1424
1463
  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
- });
1464
+ annotationsRef.current = annotationsFromJSON(
1465
+ annotationsCap?.storage ? keptMarks : record.annotations,
1466
+ () => targetsRef.current(),
1467
+ {
1468
+ meaning: () => capRef.current?.meaning,
1469
+ config: () => configRef.current,
1470
+ onCapture: (result) => capRef.current?.onCapture?.(result),
1471
+ selection: () => capRef.current?.selection
1472
+ }
1473
+ );
1431
1474
  }
1432
1475
  const annotations = annotationsRef.current;
1476
+ const inputsCommitted = useRef(/* @__PURE__ */ new Set());
1477
+ useLayoutEffect(() => {
1478
+ for (const fn of inputsCommitted.current) fn();
1479
+ }, [record.state, record.view, config, annotationsCap]);
1480
+ const provided = useMemo(
1481
+ () => ({
1482
+ ...annotations,
1483
+ subscribe: (fn) => {
1484
+ const off = annotations.subscribe(fn);
1485
+ inputsCommitted.current.add(fn);
1486
+ return () => {
1487
+ off();
1488
+ inputsCommitted.current.delete(fn);
1489
+ };
1490
+ }
1491
+ }),
1492
+ [annotations]
1493
+ );
1433
1494
  const saveCap = annotationsCap?.storage;
1434
- const saveRef = useRef(() => {
1435
- });
1436
- saveRef.current = (doc) => {
1495
+ const saveRef = useLatest((doc) => {
1437
1496
  if (saveCap) saveCap.save(doc);
1438
1497
  else updateTrialAnnotations(record.id, doc);
1439
- };
1498
+ });
1440
1499
  const [markMoves, setMarkMoves] = useState({ undo: false, redo: false });
1441
1500
  useEffect(() => {
1442
1501
  if (!annotationsCap) return;
@@ -1469,7 +1528,7 @@ function TrialRuntime({
1469
1528
  if (timer) clearTimeout(timer);
1470
1529
  flush();
1471
1530
  };
1472
- }, [annotations, annotationsCap]);
1531
+ }, [annotations, annotationsCap, saveRef]);
1473
1532
  const declaresTools = instrument.tools != null;
1474
1533
  const labTool = resolveLabTool(labToolId, instruments);
1475
1534
  const resolvedToolId = declaresTools ? record.activeToolId ?? instrument.tools?.initial ?? instrument.tools?.tools[0]?.id ?? null : labTool;
@@ -1545,16 +1604,11 @@ function TrialRuntime({
1545
1604
  if (undoCap) redoState();
1546
1605
  }
1547
1606
  } : 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;
1607
+ const loupeBindings = lenses > 0 ? { on: loupeOn, toggle: () => setLoupeOn((v2) => !v2) } : void 0;
1554
1608
  const canvasLayers = useMemo(() => {
1555
1609
  if (!instrument.canvas) return [];
1556
1610
  const baseLayers = instrument.canvas.layers;
1557
- const ordered = layerOrder ? [...baseLayers].sort((a6, b2) => layerOrder.indexOf(a6.id) - layerOrder.indexOf(b2.id)) : baseLayers;
1611
+ const ordered = layerOrder ? [...baseLayers].sort((a6, b3) => layerOrder.indexOf(a6.id) - layerOrder.indexOf(b3.id)) : baseLayers;
1558
1612
  return ordered.map((layer) => ({
1559
1613
  id: layer.id,
1560
1614
  visible: layerVisibility[layer.id] !== false,
@@ -1566,19 +1620,19 @@ function TrialRuntime({
1566
1620
  }, [instrument.canvas, record.state, config, layerVisibility, layerOrder]);
1567
1621
  const layerDescriptors = useMemo(() => {
1568
1622
  if (!instrument.layers) return [];
1569
- return instrument.layers.ids.map((l7) => typeof l7 === "string" ? { id: l7, label: l7 } : l7);
1623
+ return instrument.layers.ids.map((l8) => typeof l8 === "string" ? { id: l8, label: l8 } : l8);
1570
1624
  }, [instrument.layers]);
1571
1625
  const layerItems = useMemo(() => {
1572
- const ordered = layerOrder ? [...layerDescriptors].sort((a6, b2) => layerOrder.indexOf(a6.id) - layerOrder.indexOf(b2.id)) : layerDescriptors;
1626
+ const ordered = layerOrder ? [...layerDescriptors].sort((a6, b3) => layerOrder.indexOf(a6.id) - layerOrder.indexOf(b3.id)) : layerDescriptors;
1573
1627
  const pinnedLast = [
1574
- ...ordered.filter((l7) => !l7.alwaysOn),
1575
- ...ordered.filter((l7) => l7.alwaysOn)
1628
+ ...ordered.filter((l8) => !l8.alwaysOn),
1629
+ ...ordered.filter((l8) => l8.alwaysOn)
1576
1630
  ];
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
1631
+ return pinnedLast.map((l8) => ({
1632
+ id: l8.id,
1633
+ label: l8.label,
1634
+ locked: l8.alwaysOn === true,
1635
+ visible: l8.alwaysOn === true || layerVisibility[l8.id] !== false
1582
1636
  }));
1583
1637
  }, [layerDescriptors, layerOrder, layerVisibility]);
1584
1638
  const dragDropResult = useDragDrop({
@@ -1599,8 +1653,8 @@ function TrialRuntime({
1599
1653
  });
1600
1654
  const paletteItems = useMemo(() => {
1601
1655
  if (!instrument.dragDrop) return [];
1602
- const p3 = instrument.dragDrop.palette;
1603
- return typeof p3 === "function" ? p3(record.state, config) : p3;
1656
+ const p4 = instrument.dragDrop.palette;
1657
+ return typeof p4 === "function" ? p4(record.state, config) : p4;
1604
1658
  }, [instrument.dragDrop, record.state, config]);
1605
1659
  const layersWithFeedback = useMemo(() => {
1606
1660
  if (!dragDropResult.drag?.feedback) return canvasLayers;
@@ -1626,22 +1680,10 @@ function TrialRuntime({
1626
1680
  }
1627
1681
  ];
1628
1682
  }, [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
1683
  let body;
1642
1684
  if (instrument.canvas) {
1643
1685
  body = /* @__PURE__ */ jsxs("div", { ref: canvasContainerRef, className: "lk-trial__canvas-host", children: [
1644
- /* @__PURE__ */ jsxs(
1686
+ /* @__PURE__ */ jsx(
1645
1687
  CanvasStack,
1646
1688
  {
1647
1689
  layers: layersWithFeedback,
@@ -1651,10 +1693,7 @@ function TrialRuntime({
1651
1693
  onResize: placeView,
1652
1694
  minZoom: instrument.canvas.minZoom,
1653
1695
  maxZoom: instrument.canvas.maxZoom,
1654
- children: [
1655
- instrument.render(renderCtx),
1656
- lens
1657
- ]
1696
+ children: instrument.render(renderCtx)
1658
1697
  }
1659
1698
  ),
1660
1699
  /* @__PURE__ */ jsx(DragOverlay, { drag: dragDropResult.drag })
@@ -1669,19 +1708,10 @@ function TrialRuntime({
1669
1708
  onResize: placeView,
1670
1709
  minZoom: stage.minZoom,
1671
1710
  maxZoom: stage.maxZoom,
1672
- hostRef: loupeHostRef,
1673
- overlay: /* @__PURE__ */ jsxs(Fragment, { children: [
1674
- stage.overlay?.(renderCtx),
1675
- lens
1676
- ] }),
1711
+ overlay: stage.overlay?.(renderCtx),
1677
1712
  children: instrument.render(renderCtx)
1678
1713
  }
1679
1714
  );
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
1715
  } else {
1686
1716
  body = instrument.render(renderCtx);
1687
1717
  }
@@ -1692,11 +1722,11 @@ function TrialRuntime({
1692
1722
  );
1693
1723
  const layerListNode = useMemo(
1694
1724
  () => instrument.layers && layerDescriptors.length > 0 ? /* @__PURE__ */ jsx(
1695
- E3,
1725
+ D2,
1696
1726
  {
1697
1727
  items: layerItems,
1698
1728
  onReorder: (move) => {
1699
- setLayerOrder(x3(layerItems, move).map((l7) => l7.id));
1729
+ setLayerOrder(S2(layerItems, move).map((l8) => l8.id));
1700
1730
  bus.emit("layers.reorder");
1701
1731
  },
1702
1732
  onVisibilityChange: (lid, visible) => {
@@ -1736,8 +1766,8 @@ function TrialRuntime({
1736
1766
  activeToolId: labTool
1737
1767
  }
1738
1768
  ) : 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(
1769
+ 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 }) }) }) });
1770
+ 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
1771
  TrialChrome,
1742
1772
  {
1743
1773
  job: jobCap ? job : void 0,
@@ -1873,11 +1903,11 @@ function reorderTrials(trials, ids) {
1873
1903
  function findOvershoot(bound, items, tolerance = 1) {
1874
1904
  let worst = null;
1875
1905
  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);
1906
+ const y2 = edges.bottom - bound.bottom;
1907
+ const x2 = edges.right - bound.right;
1908
+ const by = Math.max(x2, y2);
1879
1909
  if (by <= tolerance) continue;
1880
- if (!worst || by > worst.by) worst = { item, by, axis: y3 >= x3 ? "y" : "x" };
1910
+ if (!worst || by > worst.by) worst = { item, by, axis: y2 >= x2 ? "y" : "x" };
1881
1911
  }
1882
1912
  return worst;
1883
1913
  }
@@ -1965,7 +1995,7 @@ function LabHeader({ addTrial: addTrial2 = true }) {
1965
1995
  ]
1966
1996
  }
1967
1997
  ) : /* @__PURE__ */ jsx(
1968
- d3,
1998
+ p4,
1969
1999
  {
1970
2000
  "aria-label": "Add trial",
1971
2001
  label: "Add trial\u2026",
@@ -2000,13 +2030,13 @@ function locate(url) {
2000
2030
  function currentPage(path, pages) {
2001
2031
  const here = locate(path);
2002
2032
  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);
2033
+ const routed = pages.findIndex((p4) => {
2034
+ if (!p4.href.includes("#")) return false;
2035
+ const page = locate(p4.href);
2006
2036
  return onDoc(page.doc) && (here.route === page.route || here.route.startsWith(`${page.route}/`));
2007
2037
  });
2008
2038
  if (routed >= 0) return routed;
2009
- return pages.findIndex((p3) => !p3.href.includes("#") && onDoc(locate(p3.href).doc));
2039
+ return pages.findIndex((p4) => !p4.href.includes("#") && onDoc(locate(p4.href).doc));
2010
2040
  }
2011
2041
  function LabSwitcher({ title, pages, path, className }) {
2012
2042
  const [open, setOpen] = useState(false);
@@ -2100,9 +2130,9 @@ var NO_TOOLS = /* @__PURE__ */ new Map();
2100
2130
  var CHANNELS = { contextMenu: false, ingest: false };
2101
2131
  var NO_ELEMENT = { current: null };
2102
2132
  var BASE = makeViewportZoomAction({ min: 1e-9, max: Number.POSITIVE_INFINITY });
2103
- var KEY_BINDINGS = BASE.defaultBinding.filter((b2) => b2.spec.kind === "key");
2133
+ var KEY_BINDINGS = BASE.defaultBinding.filter((b3) => b3.spec.kind === "key");
2104
2134
  function shortcutFor(kind) {
2105
- const spec = KEY_BINDINGS.find((b2) => b2.opts?.params?.kind === kind)?.spec;
2135
+ const spec = KEY_BINDINGS.find((b3) => b3.opts?.params?.kind === kind)?.spec;
2106
2136
  return spec?.key ? n2({ key: spec.key, mod: spec.mods?.mod }) : void 0;
2107
2137
  }
2108
2138
  function forZoom(camera) {
@@ -2133,8 +2163,7 @@ function LabZoomControls() {
2133
2163
  });
2134
2164
  const live = zoom !== null && camera !== null;
2135
2165
  const view = useMemo(() => camera ? forZoom(camera) : null, [camera]);
2136
- const viewRef = useRef(view);
2137
- viewRef.current = live ? view : null;
2166
+ const viewRef = useLatest(live ? view : null);
2138
2167
  useDepSource("view", () => viewRef.current);
2139
2168
  useEffect(() => {
2140
2169
  const action = {
@@ -2143,7 +2172,7 @@ function LabZoomControls() {
2143
2172
  enabled: () => viewRef.current ? true : ActionDisabledReason.NotApplicable
2144
2173
  };
2145
2174
  return registry.register(action);
2146
- }, [registry]);
2175
+ }, [registry, viewRef]);
2147
2176
  useGestureDispatcher({
2148
2177
  canvasRef: NO_ELEMENT,
2149
2178
  actions: registry,
@@ -2204,12 +2233,30 @@ var STRATEGIES = { grid: gridStrategy, floating: floatingStrategy };
2204
2233
  var FLOAT_ZONE_ID = asNodeId("lk-workspace-floating");
2205
2234
  var PANEL_KIND = "panel";
2206
2235
  var KIND = "trial";
2236
+ function createWorkspaceStore(grid) {
2237
+ const store = new Store();
2238
+ store.registerNode(
2239
+ createNode({
2240
+ kind: "zone",
2241
+ id: ZONE_ID,
2242
+ container: { strategyId: "grid", config: grid }
2243
+ })
2244
+ );
2245
+ store.registerNode(
2246
+ createNode({
2247
+ kind: "zone",
2248
+ id: FLOAT_ZONE_ID,
2249
+ container: { strategyId: "floating", config: {} }
2250
+ })
2251
+ );
2252
+ return store;
2253
+ }
2207
2254
  function extentOf(store, id) {
2208
- const p3 = store.getNode(id)?.membership?.placement;
2209
- if (!p3) return null;
2255
+ const p4 = store.getNode(id)?.membership?.placement;
2256
+ if (!p4) return null;
2210
2257
  const out = {};
2211
- if (p3.size) out.size = p3.size;
2212
- if (p3.span) out.span = p3.span;
2258
+ if (p4.size) out.size = p4.size;
2259
+ if (p4.span) out.span = p4.span;
2213
2260
  return Object.keys(out).length > 0 ? out : null;
2214
2261
  }
2215
2262
  function PanelFrame({ panel, floating = false }) {
@@ -2230,43 +2277,18 @@ function Workspace({
2230
2277
  viewport
2231
2278
  }) {
2232
2279
  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;
2280
+ const tilePanels = useMemo(() => (panels ?? []).filter((p4) => p4.as === "tile"), [panels]);
2281
+ const floatPanels = useMemo(() => (panels ?? []).filter((p4) => p4.as === "floating"), [panels]);
2282
+ const idKey = JSON.stringify([
2283
+ ...items.map((_2, i5) => ids?.[i5] ?? `lk-ws-${i5}`),
2284
+ ...tilePanels.map((p4) => `lk-panel-${p4.key}`)
2285
+ ]);
2286
+ const nodeIds = useMemo(() => JSON.parse(idKey).map(asNodeId), [idKey]);
2287
+ const layoutRef = useLatest(layout);
2288
+ const onLayoutChangeRef = useLatest(onLayoutChange);
2251
2289
  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
- }
2290
+ if (storeRef.current === null)
2291
+ storeRef.current = createWorkspaceStore({ resizable, gap, padding });
2270
2292
  const store = storeRef.current;
2271
2293
  const surface = useSurfaceOptional();
2272
2294
  useLayoutEffect(() => {
@@ -2287,7 +2309,7 @@ function Workspace({
2287
2309
  if (saved) store.patchPlacement(id, saved);
2288
2310
  }
2289
2311
  store.setChildOrder(ZONE_ID, [...nodeIds]);
2290
- }, [store, nodeIds]);
2312
+ }, [store, nodeIds, layoutRef]);
2291
2313
  useEffect(() => {
2292
2314
  if (!surface) return;
2293
2315
  surface.invalidateRects();
@@ -2303,7 +2325,7 @@ function Workspace({
2303
2325
  }
2304
2326
  onLayoutChangeRef.current?.(next);
2305
2327
  });
2306
- }, [store, onLayoutChange]);
2328
+ }, [store, onLayoutChange, onLayoutChangeRef]);
2307
2329
  const commitOrder = useCallback(
2308
2330
  (nextIds) => onReorder?.(nextIds.map(String)),
2309
2331
  [onReorder]
@@ -2311,7 +2333,7 @@ function Workspace({
2311
2333
  const chrome = useMemo(() => {
2312
2334
  const byId = new Map(nodeIds.map((id, i5) => [id, items[i5]]));
2313
2335
  const panelByNode = new Map(
2314
- tilePanels.map((p3) => [`lk-panel-${p3.key}`, p3])
2336
+ tilePanels.map((p4) => [`lk-panel-${p4.key}`, p4])
2315
2337
  );
2316
2338
  return {
2317
2339
  [PANEL_KIND]: ({ node }) => {
@@ -2329,7 +2351,7 @@ function Workspace({
2329
2351
  }
2330
2352
  };
2331
2353
  }, [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)) });
2354
+ 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
2355
  const grid = /* @__PURE__ */ jsx(
2334
2356
  Container,
2335
2357
  {
@@ -2425,10 +2447,10 @@ var NEBULA_SLOTS = [
2425
2447
  function buildNebula(list, theme, mode, density) {
2426
2448
  const ctx = { theme, resolved: resolveTheme(theme, { mode, density }) };
2427
2449
  const n6 = colorCount(list, ctx) ?? NEBULA_SLOTS.length;
2428
- const colors = Array.from({ length: n6 }, (_3, i5) => colorAt(list, i5, ctx));
2450
+ const colors = Array.from({ length: n6 }, (_2, i5) => colorAt(list, i5, ctx));
2429
2451
  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})`;
2452
+ const p4 = NEBULA_SLOTS[i5 % NEBULA_SLOTS.length];
2453
+ return `radial-gradient(ellipse ${p4.sx} ${p4.sy} at ${p4.cx} ${p4.cy}, color-mix(in srgb, ${c6} 22%, transparent), transparent ${p4.stop})`;
2432
2454
  });
2433
2455
  blobs.push("radial-gradient(ellipse at center, #0a0a18 0%, #02020a 100%)");
2434
2456
  return blobs.join(", ");
@@ -2558,12 +2580,12 @@ function LabRuntime({
2558
2580
  const canvases = [ownUnderRef.current, ownOverRef.current].filter((c6) => c6 !== null);
2559
2581
  if (canvases.length === 0) return;
2560
2582
  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 };
2583
+ const h2 = Math.round(frame.size.height * frame.dpr);
2584
+ if (bufferRef.current.w !== w2 || bufferRef.current.h !== h2) {
2585
+ bufferRef.current = { w: w2, h: h2 };
2564
2586
  for (const c6 of canvases) {
2565
2587
  c6.width = w2;
2566
- c6.height = h;
2588
+ c6.height = h2;
2567
2589
  c6.style.width = `${frame.size.width}px`;
2568
2590
  c6.style.height = `${frame.size.height}px`;
2569
2591
  }
@@ -2572,7 +2594,9 @@ function LabRuntime({
2572
2594
  }
2573
2595
  }, []);
2574
2596
  const ownSurface = useTiledSurface({ onFrame });
2575
- surfaceRef.current = ownSurface;
2597
+ useInsertionEffect(() => {
2598
+ surfaceRef.current = ownSurface;
2599
+ }, [ownSurface]);
2576
2600
  const [labBody, setLabBody] = useState(null);
2577
2601
  const attachOwnSurface = ownSurface.containerRef;
2578
2602
  const labBodyRef = useCallback(
@@ -2700,8 +2724,8 @@ function LabRuntime({
2700
2724
  store.getState().deleteSnapshot(snapshotId);
2701
2725
  },
2702
2726
  mode: modeValue,
2703
- setMode: (m2) => {
2704
- store.getState().setMode(m2);
2727
+ setMode: (m) => {
2728
+ store.getState().setMode(m);
2705
2729
  },
2706
2730
  configRules,
2707
2731
  controls
@@ -2915,18 +2939,18 @@ function ButtonsAndToggles() {
2915
2939
  /* @__PURE__ */ jsx(Xt, { status: "muted", children: "MUTED" })
2916
2940
  ] }) }),
2917
2941
  /* @__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" })
2942
+ /* @__PURE__ */ jsx(c5, { isSelected: snap, onChange: setSnap, children: "Snap to grid" }),
2943
+ /* @__PURE__ */ jsx(c5, { isIndeterminate: true, children: "Mixed" }),
2944
+ /* @__PURE__ */ jsx(a7, { isSelected: wifi, onChange: setWifi, children: "Wifi" })
2921
2945
  ] }) }),
2922
2946
  /* @__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(u3, { value: "off", children: "Off" }),
2948
+ /* @__PURE__ */ jsx(u3, { value: "grid", children: "Grid" }),
2949
+ /* @__PURE__ */ jsx(u3, { value: "pixel", children: "Pixel" })
2926
2950
  ] }) }),
2927
2951
  /* @__PURE__ */ jsxs(Cell, { label: "ToggleBar", children: [
2928
2952
  /* @__PURE__ */ jsx(
2929
- a7,
2953
+ a6,
2930
2954
  {
2931
2955
  ariaLabel: "Align",
2932
2956
  value: align,
@@ -2939,7 +2963,7 @@ function ButtonsAndToggles() {
2939
2963
  }
2940
2964
  ),
2941
2965
  /* @__PURE__ */ jsx(
2942
- a7,
2966
+ a6,
2943
2967
  {
2944
2968
  ariaLabel: "Align, flat",
2945
2969
  variant: "flat",
@@ -2965,7 +2989,7 @@ function ButtonsAndToggles() {
2965
2989
  }
2966
2990
  ),
2967
2991
  /* @__PURE__ */ jsx(
2968
- a10,
2992
+ a9,
2969
2993
  {
2970
2994
  items: [
2971
2995
  { value: "undo", label: "Undo", onAction: () => {
@@ -2978,7 +3002,7 @@ function ButtonsAndToggles() {
2978
3002
  ] }) }),
2979
3003
  /* @__PURE__ */ jsx(Cell, { label: "MenuButton, Disclosure", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
2980
3004
  /* @__PURE__ */ jsx(
2981
- d3,
3005
+ p4,
2982
3006
  {
2983
3007
  label: "Add trial\u2026",
2984
3008
  onAction: () => {
@@ -2989,17 +3013,17 @@ function ButtonsAndToggles() {
2989
3013
  ]
2990
3014
  }
2991
3015
  ),
2992
- /* @__PURE__ */ jsx(i2, { open, onToggle: () => setOpen((o5) => !o5), label: "Shapes" })
3016
+ /* @__PURE__ */ jsx(i2, { open, onToggle: () => setOpen((o4) => !o4), label: "Shapes" })
2993
3017
  ] }) }),
2994
- /* @__PURE__ */ jsx(Cell, { label: "Tabs", children: /* @__PURE__ */ jsxs(o6, { children: [
2995
- /* @__PURE__ */ jsxs(s4, { "aria-label": "Sections", children: [
3018
+ /* @__PURE__ */ jsx(Cell, { label: "Tabs", children: /* @__PURE__ */ jsxs(o5, { children: [
3019
+ /* @__PURE__ */ jsxs(s3, { "aria-label": "Sections", children: [
2996
3020
  /* @__PURE__ */ jsx(c6, { id: "props", children: "Props" }),
2997
3021
  /* @__PURE__ */ jsx(c6, { id: "events", children: "Events" }),
2998
3022
  /* @__PURE__ */ jsx(c6, { id: "snapshot", children: "Snapshot" })
2999
3023
  ] }),
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." })
3024
+ /* @__PURE__ */ jsx(l8, { id: "props", children: "Props panel." }),
3025
+ /* @__PURE__ */ jsx(l8, { id: "events", children: "Events panel." }),
3026
+ /* @__PURE__ */ jsx(l8, { id: "snapshot", children: "Snapshot panel." })
3003
3027
  ] }) }),
3004
3028
  /* @__PURE__ */ jsx(Cell, { label: "Keycaps", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
3005
3029
  /* @__PURE__ */ jsx(p, { keys: [{ label: "\u2318" }, { label: "\u21E7" }, { label: "K" }], separator: "+" }),
@@ -3025,9 +3049,9 @@ function FieldsAndPickers() {
3025
3049
  const [paint, setPaint] = useState({ fill: "solid", color: "#b08adb" });
3026
3050
  return /* @__PURE__ */ jsxs(Section, { title: "Fields & pickers", children: [
3027
3051
  /* @__PURE__ */ jsxs(Cell, { label: "Input", children: [
3028
- /* @__PURE__ */ jsx(u3, { label: "Name", placeholder: "e.g. Pico" }),
3052
+ /* @__PURE__ */ jsx(u2, { label: "Name", placeholder: "e.g. Pico" }),
3029
3053
  /* @__PURE__ */ jsx(
3030
- u3,
3054
+ u2,
3031
3055
  {
3032
3056
  label: "Size",
3033
3057
  leadingAdornment: /* @__PURE__ */ jsx("span", { children: "W" }),
@@ -3035,12 +3059,12 @@ function FieldsAndPickers() {
3035
3059
  defaultValue: "120"
3036
3060
  }
3037
3061
  ),
3038
- /* @__PURE__ */ jsx(u3, { label: "Required", isInvalid: true, errorMessage: "Name is required." })
3062
+ /* @__PURE__ */ jsx(u2, { label: "Required", isInvalid: true, errorMessage: "Name is required." })
3039
3063
  ] }),
3040
3064
  /* @__PURE__ */ jsxs(Cell, { label: "NumberField, Select, ComboBox", children: [
3041
3065
  /* @__PURE__ */ jsx(y, { label: "Opacity", minValue: 0, maxValue: 100, step: 5, defaultValue: 80 }),
3042
3066
  /* @__PURE__ */ jsx(
3043
- E2,
3067
+ O2,
3044
3068
  {
3045
3069
  label: "Color",
3046
3070
  defaultSelectedKey: "g",
@@ -3052,7 +3076,7 @@ function FieldsAndPickers() {
3052
3076
  }
3053
3077
  ),
3054
3078
  /* @__PURE__ */ jsx(
3055
- y2,
3079
+ b4,
3056
3080
  {
3057
3081
  label: "Filter",
3058
3082
  placeholder: "Type to filter\u2026",
@@ -3064,15 +3088,15 @@ function FieldsAndPickers() {
3064
3088
  )
3065
3089
  ] }),
3066
3090
  /* @__PURE__ */ jsxs(Cell, { label: "RangeSlider, Slider", children: [
3067
- /* @__PURE__ */ jsx(l7, { label: "Range", defaultValue: [20, 80], minValue: 0, maxValue: 100 }),
3091
+ /* @__PURE__ */ jsx(l9, { label: "Range", defaultValue: [20, 80], minValue: 0, maxValue: 100 }),
3068
3092
  /* @__PURE__ */ jsx(
3069
- l7,
3093
+ l9,
3070
3094
  {
3071
3095
  label: "Opacity",
3072
3096
  defaultValue: 75,
3073
3097
  minValue: 0,
3074
3098
  maxValue: 100,
3075
- formatOutput: (v) => `${v}%`
3099
+ formatOutput: (v2) => `${v2}%`
3076
3100
  }
3077
3101
  ),
3078
3102
  /* @__PURE__ */ jsx(
@@ -3113,11 +3137,11 @@ function FieldsAndPickers() {
3113
3137
  )
3114
3138
  ] }),
3115
3139
  /* @__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 })
3140
+ /* @__PURE__ */ jsx(h2, { value: color, alpha: true, onInput: setColor, onChange: setColor, "aria-label": "Color" }),
3141
+ /* @__PURE__ */ jsx(j, { value: gradient, onInput: setGradient, onChange: setGradient, kindSwitch: true })
3118
3142
  ] }),
3119
3143
  /* @__PURE__ */ jsx(Cell, { label: "PaintInput", children: /* @__PURE__ */ jsx(
3120
- T,
3144
+ k2,
3121
3145
  {
3122
3146
  value: paint,
3123
3147
  onInput: setPaint,
@@ -3146,7 +3170,7 @@ function PanelsAndRows() {
3146
3170
  ]);
3147
3171
  const [panelCollapsed, setPanelCollapsed] = useState(false);
3148
3172
  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: [
3173
+ /* @__PURE__ */ jsx(Cell, { label: "PropertyPanel", children: /* @__PURE__ */ jsx(oe, { title: "Shape", children: /* @__PURE__ */ jsxs(se, { children: [
3150
3174
  /* @__PURE__ */ jsx(
3151
3175
  R,
3152
3176
  {
@@ -3227,7 +3251,7 @@ function PanelsAndRows() {
3227
3251
  ),
3228
3252
  /* @__PURE__ */ jsx(R, { kind: "string", label: "Label", value: label, onChange: setLabel }),
3229
3253
  /* @__PURE__ */ jsx(R, { kind: "boolean", label: "Visible", value: visible, onChange: setVisible }),
3230
- /* @__PURE__ */ jsx(b2, { title: "Bevel", defaultCollapsed: true, children: /* @__PURE__ */ jsx(
3254
+ /* @__PURE__ */ jsx(b3, { title: "Bevel", defaultCollapsed: true, children: /* @__PURE__ */ jsx(
3231
3255
  R,
3232
3256
  {
3233
3257
  kind: "number",
@@ -3243,7 +3267,7 @@ function PanelsAndRows() {
3243
3267
  ) })
3244
3268
  ] }) }) }),
3245
3269
  /* @__PURE__ */ jsx(Cell, { label: "PrefsForm", children: /* @__PURE__ */ jsx(
3246
- j,
3270
+ j2,
3247
3271
  {
3248
3272
  schema: PREFS,
3249
3273
  values: prefs,
@@ -3251,10 +3275,10 @@ function PanelsAndRows() {
3251
3275
  }
3252
3276
  ) }),
3253
3277
  /* @__PURE__ */ jsx(Cell, { label: "LayerList", children: /* @__PURE__ */ jsx(
3254
- E3,
3278
+ D2,
3255
3279
  {
3256
3280
  items: layers,
3257
- onReorder: (move) => setLayers(x3(layers, move)),
3281
+ onReorder: (move) => setLayers(S2(layers, move)),
3258
3282
  renderBody: (item) => /* @__PURE__ */ jsxs("div", { children: [
3259
3283
  "settings for ",
3260
3284
  item.label
@@ -3262,11 +3286,11 @@ function PanelsAndRows() {
3262
3286
  }
3263
3287
  ) }),
3264
3288
  /* @__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,
3289
+ a10,
3266
3290
  {
3267
3291
  title: "Selection",
3268
3292
  collapsed: panelCollapsed,
3269
- onToggleCollapse: () => setPanelCollapsed((v) => !v),
3293
+ onToggleCollapse: () => setPanelCollapsed((v2) => !v2),
3270
3294
  onHide: () => {
3271
3295
  },
3272
3296
  children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__pad", children: "2 items selected" })
@@ -3278,7 +3302,7 @@ function OverlaysAndFeedback() {
3278
3302
  const calloutAnchor = useRef(null);
3279
3303
  const [calloutOpen, setCalloutOpen] = useState(false);
3280
3304
  const [dialogOpen, setDialogOpen] = useState(false);
3281
- const toasts = useMemo(() => m3(), []);
3305
+ const toasts = useMemo(() => C3(), []);
3282
3306
  return /* @__PURE__ */ jsxs(Section, { title: "Overlays & feedback", children: [
3283
3307
  /* @__PURE__ */ jsx(Cell, { label: "Tooltip, Callout, Dialog, Toast", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
3284
3308
  /* @__PURE__ */ jsxs(l2, { children: [
@@ -3287,7 +3311,7 @@ function OverlaysAndFeedback() {
3287
3311
  ] }),
3288
3312
  /* @__PURE__ */ jsx("button", { type: "button", ref: calloutAnchor, onClick: () => setCalloutOpen(true), children: "Callout" }),
3289
3313
  /* @__PURE__ */ jsx(
3290
- _2,
3314
+ v2,
3291
3315
  {
3292
3316
  triggerRef: calloutAnchor,
3293
3317
  isOpen: calloutOpen,
@@ -3299,7 +3323,7 @@ function OverlaysAndFeedback() {
3299
3323
  ),
3300
3324
  /* @__PURE__ */ jsx(c, { onClick: () => setDialogOpen(true), children: "Dialog" }),
3301
3325
  /* @__PURE__ */ jsx(
3302
- d2,
3326
+ d3,
3303
3327
  {
3304
3328
  isOpen: dialogOpen,
3305
3329
  onOpenChange: setDialogOpen,
@@ -3315,7 +3339,7 @@ function OverlaysAndFeedback() {
3315
3339
  children: "Toast"
3316
3340
  }
3317
3341
  ),
3318
- /* @__PURE__ */ jsx(S3, { queue: toasts, placement: "bottom-right" })
3342
+ /* @__PURE__ */ jsx(j3, { queue: toasts, placement: "bottom-right" })
3319
3343
  ] }) }),
3320
3344
  /* @__PURE__ */ jsx(Cell, { label: "Powerline", children: /* @__PURE__ */ jsx(
3321
3345
  r4,
@@ -3378,7 +3402,6 @@ function ToolChrome() {
3378
3402
  label: id,
3379
3403
  shortcut: id.slice(0, 1).toUpperCase(),
3380
3404
  active: tool === id,
3381
- tabbable: tool === id,
3382
3405
  onClick: () => setTool(id)
3383
3406
  },
3384
3407
  id
@@ -3390,7 +3413,7 @@ function ToolChrome() {
3390
3413
  /* @__PURE__ */ jsx(Cell, { label: "ResizeHandle", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__box", children: [
3391
3414
  /* @__PURE__ */ jsx("div", { className: "lk-specimen__box-main", children: "content" }),
3392
3415
  /* @__PURE__ */ jsx(
3393
- c5,
3416
+ l7,
3394
3417
  {
3395
3418
  value: paneWidth,
3396
3419
  min: 100,
@@ -3499,7 +3522,7 @@ function EditorsAndPlots() {
3499
3522
  }
3500
3523
  ) }),
3501
3524
  /* @__PURE__ */ jsx(Cell, { label: "BandEditor", wide: true, children: /* @__PURE__ */ jsx(
3502
- j2,
3525
+ j4,
3503
3526
  {
3504
3527
  min: 1 / 64,
3505
3528
  max: 1 / 2,
@@ -3509,12 +3532,12 @@ function EditorsAndPlots() {
3509
3532
  onChange: setBands,
3510
3533
  selectedIndex: band,
3511
3534
  onSelect: setBand,
3512
- renderBand: (b2) => b2.data.name,
3535
+ renderBand: (b3) => b3.data.name,
3513
3536
  ticks: [1 / 24, 1 / 12, 1 / 6].map((at) => ({ at, label: `1/${Math.round(1 / at)}` }))
3514
3537
  }
3515
3538
  ) }),
3516
3539
  /* @__PURE__ */ jsx(Cell, { label: "Timeline", wide: true, children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__timeline", children: /* @__PURE__ */ jsx(
3517
- ye,
3540
+ be,
3518
3541
  {
3519
3542
  tracks,
3520
3543
  duration: 2e3,
@@ -3577,6 +3600,6 @@ function Specimen({ className }) {
3577
3600
  ] });
3578
3601
  }
3579
3602
 
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 };
3603
+ 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
3604
  //# sourceMappingURL=index.js.map
3582
3605
  //# sourceMappingURL=index.js.map