@weasel-js/core 1.13.0 → 1.14.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 (741) hide show
  1. package/CHANGELOG.md +326 -0
  2. package/README.md +8 -12
  3. package/dist/affordances/hitAffordanceRegions.js +1 -1
  4. package/dist/affordances/hitAffordanceRegions.js.map +1 -1
  5. package/dist/affordances/pathAnchors.js.map +1 -1
  6. package/dist/animation/clipTargets.js +1 -1
  7. package/dist/animation/clipTargets.js.map +1 -1
  8. package/dist/animation/poseTarget.js +5 -32
  9. package/dist/animation/poseTarget.js.map +1 -1
  10. package/dist/{autoPoseDescriptor-CZ1eXbzY.d.ts → autoPoseDescriptor-C25QVb0W.d.ts} +1 -1
  11. package/dist/barrel/canvas.js +8 -8
  12. package/dist/barrel/chrome.js +9 -9
  13. package/dist/barrel/input.js +1 -1
  14. package/dist/barrel/interactions.js +3 -3
  15. package/dist/barrel/paint.js +2 -2
  16. package/dist/barrel/paths.js +19 -17
  17. package/dist/barrel/renderer.js +11 -7
  18. package/dist/barrel/routing.js +4 -1
  19. package/dist/barrel/scene.js +16 -12
  20. package/dist/barrel/text.js +5 -5
  21. package/dist/barrel/viewport.js +8 -8
  22. package/dist/canvas/Canvas.js +2 -2
  23. package/dist/canvas/Canvas.js.map +1 -1
  24. package/dist/canvas/CanvasView.js +20 -14
  25. package/dist/canvas/CanvasView.js.map +1 -1
  26. package/dist/canvas/GestureReason.js +64 -0
  27. package/dist/canvas/GestureReason.js.map +1 -0
  28. package/dist/canvas/GestureReason.module.js +7 -0
  29. package/dist/canvas/GestureReason.module.js.map +1 -0
  30. package/dist/canvas/LeanSceneCanvas.js +3 -1
  31. package/dist/canvas/LeanSceneCanvas.js.map +1 -1
  32. package/dist/canvas/NodeShape.js +2 -0
  33. package/dist/canvas/NodeShape.js.map +1 -1
  34. package/dist/canvas/PickHud.js +7 -3
  35. package/dist/canvas/PickHud.js.map +1 -1
  36. package/dist/canvas/SceneCanvas/CanvasKitProviders.js +1 -1
  37. package/dist/canvas/SceneCanvas/CanvasKitProviders.js.map +1 -1
  38. package/dist/canvas/SceneCanvas/DevHuds.js +2 -2
  39. package/dist/canvas/SceneCanvas/DevHuds.js.map +1 -1
  40. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +4 -2
  41. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js.map +1 -1
  42. package/dist/canvas/SceneCanvas/SceneCanvasInput.js +3 -1
  43. package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
  44. package/dist/canvas/SceneCanvas/brushOverlay.js.map +1 -1
  45. package/dist/canvas/SceneCanvas/builtinToolSets.js +17 -9
  46. package/dist/canvas/SceneCanvas/builtinToolSets.js.map +1 -1
  47. package/dist/canvas/SceneCanvas/canvasPassThrough.js +2 -1
  48. package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
  49. package/dist/canvas/SceneCanvas/defaultNodeProperties.js +75 -19
  50. package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
  51. package/dist/canvas/SceneCanvas/defaultNodeRouting.js +7 -1
  52. package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
  53. package/dist/canvas/SceneCanvas/defaultTextEditor.js +108 -0
  54. package/dist/canvas/SceneCanvas/defaultTextEditor.js.map +1 -0
  55. package/dist/canvas/SceneCanvas/describePresets.js +47 -0
  56. package/dist/canvas/SceneCanvas/describePresets.js.map +1 -0
  57. package/dist/canvas/SceneCanvas/features.js +57 -16
  58. package/dist/canvas/SceneCanvas/features.js.map +1 -1
  59. package/dist/canvas/SceneCanvas/mergeLayers.js +10 -1
  60. package/dist/canvas/SceneCanvas/mergeLayers.js.map +1 -1
  61. package/dist/canvas/SceneCanvas/namedPresets.js +52 -24
  62. package/dist/canvas/SceneCanvas/namedPresets.js.map +1 -1
  63. package/dist/canvas/SceneCanvas/presets/arrange.js +35 -10
  64. package/dist/canvas/SceneCanvas/presets/arrange.js.map +1 -1
  65. package/dist/canvas/SceneCanvas/presets/baseline.js +9 -0
  66. package/dist/canvas/SceneCanvas/presets/baseline.js.map +1 -0
  67. package/dist/canvas/SceneCanvas/presets/chrome.js.map +1 -1
  68. package/dist/canvas/SceneCanvas/presets/composites.js +43 -0
  69. package/dist/canvas/SceneCanvas/presets/composites.js.map +1 -0
  70. package/dist/canvas/SceneCanvas/presets/edit.js +79 -26
  71. package/dist/canvas/SceneCanvas/presets/edit.js.map +1 -1
  72. package/dist/canvas/SceneCanvas/presets/ingest.js +1 -0
  73. package/dist/canvas/SceneCanvas/presets/ingest.js.map +1 -1
  74. package/dist/canvas/SceneCanvas/presets/paths.js +58 -16
  75. package/dist/canvas/SceneCanvas/presets/paths.js.map +1 -1
  76. package/dist/canvas/SceneCanvas/presets/select.js +4 -2
  77. package/dist/canvas/SceneCanvas/presets/select.js.map +1 -1
  78. package/dist/canvas/SceneCanvas/presets/tools.js +24 -0
  79. package/dist/canvas/SceneCanvas/presets/tools.js.map +1 -0
  80. package/dist/canvas/SceneCanvas/presets/transform.js +4 -0
  81. package/dist/canvas/SceneCanvas/presets/transform.js.map +1 -1
  82. package/dist/canvas/SceneCanvas/presets/view.js +3 -1
  83. package/dist/canvas/SceneCanvas/presets/view.js.map +1 -1
  84. package/dist/canvas/SceneCanvas/props.js.map +1 -1
  85. package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js +1 -1
  86. package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js.map +1 -1
  87. package/dist/canvas/SceneCanvas/toolRegistry.js +5 -4
  88. package/dist/canvas/SceneCanvas/toolRegistry.js.map +1 -1
  89. package/dist/canvas/SceneCanvas/useCanvasTools.js +26 -10
  90. package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
  91. package/dist/canvas/SceneCanvas/useContributionRoles.js +15 -2
  92. package/dist/canvas/SceneCanvas/useContributionRoles.js.map +1 -1
  93. package/dist/canvas/SceneCanvas/useDepartureGhostLayer.js +5 -4
  94. package/dist/canvas/SceneCanvas/useDepartureGhostLayer.js.map +1 -1
  95. package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js +1 -1
  96. package/dist/canvas/SceneCanvas/useNodeAtPoint.js.map +1 -1
  97. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +9 -8
  98. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
  99. package/dist/canvas/SceneCanvas/useSceneCanvasPathEdit.js +2 -2
  100. package/dist/canvas/SceneCanvas/useSceneCanvasPathEdit.js.map +1 -1
  101. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +4 -1
  102. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
  103. package/dist/canvas/SceneCanvas/useSceneChrome.js +7 -4
  104. package/dist/canvas/SceneCanvas/useSceneChrome.js.map +1 -1
  105. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js +9 -9
  106. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js.map +1 -1
  107. package/dist/canvas/SceneCanvas/useScenePicking.js +4 -7
  108. package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
  109. package/dist/canvas/SceneCanvas/useSceneRedrawSources.js +2 -1
  110. package/dist/canvas/SceneCanvas/useSceneRedrawSources.js.map +1 -1
  111. package/dist/canvas/SceneCanvas/useSceneSelectTool.js +6 -6
  112. package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
  113. package/dist/canvas/SceneCanvas/useSceneStandardActions.js +2 -2
  114. package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
  115. package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js +1 -1
  116. package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js.map +1 -1
  117. package/dist/canvas/SceneCanvas/useSurfaceViewInputs.js.map +1 -1
  118. package/dist/canvas/SceneCanvas/useToolKeybindings.js +2 -2
  119. package/dist/canvas/SceneCanvas/useToolKeybindings.js.map +1 -1
  120. package/dist/canvas/SceneCanvas/useViewportActions.js +5 -2
  121. package/dist/canvas/SceneCanvas/useViewportActions.js.map +1 -1
  122. package/dist/canvas/SceneCanvas/worldPointAt.js.map +1 -1
  123. package/dist/canvas/SceneCanvas.js +22 -11
  124. package/dist/canvas/SceneCanvas.js.map +1 -1
  125. package/dist/canvas/SceneViewCanvas.js +1 -0
  126. package/dist/canvas/SceneViewCanvas.js.map +1 -1
  127. package/dist/canvas/ViewMarker.js.map +1 -1
  128. package/dist/canvas/accentColor.js +14 -1
  129. package/dist/canvas/accentColor.js.map +1 -1
  130. package/dist/canvas/affordanceAt.js +2 -2
  131. package/dist/canvas/affordanceAt.js.map +1 -1
  132. package/dist/canvas/buildSceneTree.js +5 -3
  133. package/dist/canvas/buildSceneTree.js.map +1 -1
  134. package/dist/canvas/deps/editAnchors.js +4 -4
  135. package/dist/canvas/deps/editAnchors.js.map +1 -1
  136. package/dist/canvas/deps/enteredGroup.js +14 -5
  137. package/dist/canvas/deps/enteredGroup.js.map +1 -1
  138. package/dist/canvas/deps/ingestion.js +5 -1
  139. package/dist/canvas/deps/ingestion.js.map +1 -1
  140. package/dist/canvas/deps/insert.js.map +1 -1
  141. package/dist/canvas/deps/insertSite.js +5 -3
  142. package/dist/canvas/deps/insertSite.js.map +1 -1
  143. package/dist/canvas/deps/nodeAtPoint.js +1 -12
  144. package/dist/canvas/deps/nodeAtPoint.js.map +1 -1
  145. package/dist/canvas/deps/pathEditCommits.js +3 -3
  146. package/dist/canvas/deps/pathEditCommits.js.map +1 -1
  147. package/dist/canvas/deps/slice.js +16 -2
  148. package/dist/canvas/deps/slice.js.map +1 -1
  149. package/dist/canvas/deps/snap.js +5 -5
  150. package/dist/canvas/deps/snap.js.map +1 -1
  151. package/dist/canvas/deps/textEdit.js +5 -6
  152. package/dist/canvas/deps/textEdit.js.map +1 -1
  153. package/dist/canvas/derivedPath.js +8 -3
  154. package/dist/canvas/derivedPath.js.map +1 -1
  155. package/dist/canvas/getNodeAtPoint.js +2 -2
  156. package/dist/canvas/getNodeAtPoint.js.map +1 -1
  157. package/dist/canvas/insertPreviewExtent.js.map +1 -1
  158. package/dist/canvas/layerSlots.js.map +1 -1
  159. package/dist/canvas/nodeShapes/measurePainter.js +1 -1
  160. package/dist/canvas/nodeShapes/measurePainter.js.map +1 -1
  161. package/dist/canvas/nodeShapes/strokedBounds.js +5 -3
  162. package/dist/canvas/nodeShapes/strokedBounds.js.map +1 -1
  163. package/dist/canvas/overlayRoleStrokes.js +6 -0
  164. package/dist/canvas/overlayRoleStrokes.js.map +1 -1
  165. package/dist/canvas/pickIndex/scenePickIndex.js +10 -12
  166. package/dist/canvas/pickIndex/scenePickIndex.js.map +1 -1
  167. package/dist/canvas/sceneAdapter.js +10 -19
  168. package/dist/canvas/sceneAdapter.js.map +1 -1
  169. package/dist/canvas/sceneClipboard.js +17 -4
  170. package/dist/canvas/sceneClipboard.js.map +1 -1
  171. package/dist/canvas/sceneViewRender.js +3 -2
  172. package/dist/canvas/sceneViewRender.js.map +1 -1
  173. package/dist/canvas/surfaceContribution.js.map +1 -1
  174. package/dist/canvas/useCanvasPaint.js +10 -4
  175. package/dist/canvas/useCanvasPaint.js.map +1 -1
  176. package/dist/canvas/useHitObserver.js +1 -1
  177. package/dist/canvas/useHitObserver.js.map +1 -1
  178. package/dist/canvas/useViewAim.js +1 -1
  179. package/dist/canvas/useViewAim.js.map +1 -1
  180. package/dist/canvas/useViewHelpers.js +8 -5
  181. package/dist/canvas/useViewHelpers.js.map +1 -1
  182. package/dist/canvas/useViewNesting.js +39 -12
  183. package/dist/canvas/useViewNesting.js.map +1 -1
  184. package/dist/canvas/viewInputs.js.map +1 -1
  185. package/dist/canvas/viewMarkers.js +2 -2
  186. package/dist/canvas/viewMarkers.js.map +1 -1
  187. package/dist/canvas/viewRegistry.js +2 -2
  188. package/dist/canvas/viewRegistry.js.map +1 -1
  189. package/dist/canvas/viewSnap.js +67 -0
  190. package/dist/canvas/viewSnap.js.map +1 -0
  191. package/dist/clipboard.d.ts +6 -12
  192. package/dist/{clone-qb2e1F5p.d.ts → clone-Bz4iqGfE.d.ts} +10 -5
  193. package/dist/clone.d.ts +5 -5
  194. package/dist/core/geometry/booleanOfPaths.js +23 -0
  195. package/dist/core/geometry/booleanOfPaths.js.map +1 -0
  196. package/dist/core/geometry/pathPoseDescriptor.js +12 -9
  197. package/dist/core/geometry/pathPoseDescriptor.js.map +1 -1
  198. package/dist/core/geometry/poseDescriptor.js +12 -3
  199. package/dist/core/geometry/poseDescriptor.js.map +1 -1
  200. package/dist/core/geometry/targetFrame.js +2 -13
  201. package/dist/core/geometry/targetFrame.js.map +1 -1
  202. package/dist/core/layers/render.js +2 -1
  203. package/dist/core/layers/render.js.map +1 -1
  204. package/dist/core/layers/retain.js +5 -3
  205. package/dist/core/layers/retain.js.map +1 -1
  206. package/dist/core/ops/setPath.js +3 -0
  207. package/dist/core/ops/setPath.js.map +1 -1
  208. package/dist/core/paint/meshKindLazy.js.map +1 -1
  209. package/dist/core/paint/paintKindEntry.js.map +1 -1
  210. package/dist/core/paint/paintKinds.js +8 -1
  211. package/dist/core/paint/paintKinds.js.map +1 -1
  212. package/dist/core/scene/NodeProperties.js.map +1 -1
  213. package/dist/core/scene/NodeRouting.js.map +1 -1
  214. package/dist/core/scene/booleanGroup.js +33 -0
  215. package/dist/core/scene/booleanGroup.js.map +1 -0
  216. package/dist/core/scene/booleanOfChildren.js +53 -0
  217. package/dist/core/scene/booleanOfChildren.js.map +1 -0
  218. package/dist/core/scene/carryDescendants.js +18 -6
  219. package/dist/core/scene/carryDescendants.js.map +1 -1
  220. package/dist/core/scene/composeFrame.js +42 -5
  221. package/dist/core/scene/composeFrame.js.map +1 -1
  222. package/dist/core/scene/composePose.js +35 -16
  223. package/dist/core/scene/composePose.js.map +1 -1
  224. package/dist/core/scene/depMemo.js +36 -18
  225. package/dist/core/scene/depMemo.js.map +1 -1
  226. package/dist/core/scene/derivedParts.js +2 -23
  227. package/dist/core/scene/derivedParts.js.map +1 -1
  228. package/dist/core/scene/effectivePose.js +10 -0
  229. package/dist/core/scene/effectivePose.js.map +1 -1
  230. package/dist/core/scene/historyForm.js +5 -4
  231. package/dist/core/scene/historyForm.js.map +1 -1
  232. package/dist/core/scene/kitOps.js +5 -71
  233. package/dist/core/scene/kitOps.js.map +1 -1
  234. package/dist/core/scene/kitRegistry.js +5 -0
  235. package/dist/core/scene/kitRegistry.js.map +1 -1
  236. package/dist/core/scene/layerOps.js +82 -0
  237. package/dist/core/scene/layerOps.js.map +1 -0
  238. package/dist/core/scene/layoutPass.js +14 -12
  239. package/dist/core/scene/layoutPass.js.map +1 -1
  240. package/dist/core/scene/lockGuard.js +9 -3
  241. package/dist/core/scene/lockGuard.js.map +1 -1
  242. package/dist/core/scene/nestedHit.js +5 -5
  243. package/dist/core/scene/nestedHit.js.map +1 -1
  244. package/dist/core/scene/nodeFlags.js +8 -2
  245. package/dist/core/scene/nodeFlags.js.map +1 -1
  246. package/dist/core/scene/nodeGates.js +31 -2
  247. package/dist/core/scene/nodeGates.js.map +1 -1
  248. package/dist/core/scene/pathEffects/effects.js +22 -3
  249. package/dist/core/scene/pathEffects/effects.js.map +1 -1
  250. package/dist/core/scene/pathEffects/textAlong.js +16 -3
  251. package/dist/core/scene/pathEffects/textAlong.js.map +1 -1
  252. package/dist/core/scene/pathEffects/textAlongBands.js +65 -0
  253. package/dist/core/scene/pathEffects/textAlongBands.js.map +1 -0
  254. package/dist/core/scene/reconcileSpecs.js +1 -1
  255. package/dist/core/scene/reconcileSpecs.js.map +1 -1
  256. package/dist/core/scene/scene.js +11 -5
  257. package/dist/core/scene/scene.js.map +1 -1
  258. package/dist/core/scene/sceneEdits.js +5 -2
  259. package/dist/core/scene/sceneEdits.js.map +1 -1
  260. package/dist/core/scene/scenePoseAdapter.js +10 -1
  261. package/dist/core/scene/scenePoseAdapter.js.map +1 -1
  262. package/dist/core/scene/scrollOffsets.js +93 -0
  263. package/dist/core/scene/scrollOffsets.js.map +1 -0
  264. package/dist/core/scene/serialization.js +15 -5
  265. package/dist/core/scene/serialization.js.map +1 -1
  266. package/dist/core/scene/statedFields.js +2 -1
  267. package/dist/core/scene/statedFields.js.map +1 -1
  268. package/dist/core/scene/strategyView.js +35 -0
  269. package/dist/core/scene/strategyView.js.map +1 -0
  270. package/dist/core/scene/types.js.map +1 -1
  271. package/dist/core/scene/useScene.js +2 -0
  272. package/dist/core/scene/useScene.js.map +1 -1
  273. package/dist/core/scene/worldSave.js +87 -0
  274. package/dist/core/scene/worldSave.js.map +1 -0
  275. package/dist/core/selection/selectionTarget.js +1 -1
  276. package/dist/core/selection/selectionTarget.js.map +1 -1
  277. package/dist/{cornerHandles-CNCb7aTY.d.ts → cornerHandles-DpmQM_z5.d.ts} +1 -1
  278. package/dist/{depSchema-CpIQzKWQ.d.ts → depSchema-C3BwxitB.d.ts} +119 -99
  279. package/dist/devtools-protocol.d.ts +2 -2
  280. package/dist/devtools.d.ts +2 -2
  281. package/dist/{features → domains}/chrome-caps/buildChromeCtx.js +1 -1
  282. package/dist/domains/chrome-caps/buildChromeCtx.js.map +1 -0
  283. package/dist/{features → domains}/chrome-caps/conditions.js +1 -1
  284. package/dist/domains/chrome-caps/conditions.js.map +1 -0
  285. package/dist/{features → domains}/chrome-caps/defaults.js +1 -1
  286. package/dist/domains/chrome-caps/defaults.js.map +1 -0
  287. package/dist/{features → domains}/chrome-caps/resolve.js +1 -1
  288. package/dist/domains/chrome-caps/resolve.js.map +1 -0
  289. package/dist/{features → domains}/chrome-caps/useChromeCaps.js +1 -1
  290. package/dist/domains/chrome-caps/useChromeCaps.js.map +1 -0
  291. package/dist/{features → domains}/chrome-caps/useHoverTracking.js +1 -1
  292. package/dist/domains/chrome-caps/useHoverTracking.js.map +1 -0
  293. package/dist/{features → domains}/ingestion/contentHandlers.js +20 -3
  294. package/dist/domains/ingestion/contentHandlers.js.map +1 -0
  295. package/dist/domains/ingestion/ghost.js +56 -0
  296. package/dist/domains/ingestion/ghost.js.map +1 -0
  297. package/dist/{features → domains}/ingestion/imageHandler.js +1 -1
  298. package/dist/domains/ingestion/imageHandler.js.map +1 -0
  299. package/dist/domains/ingestion/kitHandlers.js +22 -0
  300. package/dist/domains/ingestion/kitHandlers.js.map +1 -0
  301. package/dist/{features → domains}/ingestion/openFilePicker.js +1 -1
  302. package/dist/domains/ingestion/openFilePicker.js.map +1 -0
  303. package/dist/{features → domains}/ingestion/placement.js +1 -1
  304. package/dist/domains/ingestion/placement.js.map +1 -0
  305. package/dist/{features → domains}/ingestion/svgHandler.js +1 -1
  306. package/dist/domains/ingestion/svgHandler.js.map +1 -0
  307. package/dist/{features → domains}/ingestion/textHandler.js +9 -7
  308. package/dist/domains/ingestion/textHandler.js.map +1 -0
  309. package/dist/{features → domains}/ingestion/useCanvasIngestion.js +13 -15
  310. package/dist/domains/ingestion/useCanvasIngestion.js.map +1 -0
  311. package/dist/{features → domains}/ingestion/weaselJsonHandler.js +1 -1
  312. package/dist/domains/ingestion/weaselJsonHandler.js.map +1 -0
  313. package/dist/{features → domains}/longPress/longPressFeedback.js +1 -1
  314. package/dist/domains/longPress/longPressFeedback.js.map +1 -0
  315. package/dist/{features → domains}/measure/actionIds.js +1 -1
  316. package/dist/domains/measure/actionIds.js.map +1 -0
  317. package/dist/{features → domains}/measure/measureCommands.js +1 -1
  318. package/dist/domains/measure/measureCommands.js.map +1 -0
  319. package/dist/{features → domains}/measure/measureContribution.js +1 -1
  320. package/dist/domains/measure/measureContribution.js.map +1 -0
  321. package/dist/{features → domains}/measure/measureEdits.js +1 -1
  322. package/dist/domains/measure/measureEdits.js.map +1 -0
  323. package/dist/{features → domains}/measure/measureGestures.js +4 -7
  324. package/dist/domains/measure/measureGestures.js.map +1 -0
  325. package/dist/{features → domains}/measure/measureHit.js +1 -1
  326. package/dist/domains/measure/measureHit.js.map +1 -0
  327. package/dist/{features → domains}/measure/measureLayer.js +1 -1
  328. package/dist/domains/measure/measureLayer.js.map +1 -0
  329. package/dist/{features → domains}/measure/measurement.js +1 -1
  330. package/dist/domains/measure/measurement.js.map +1 -0
  331. package/dist/{features → domains}/measure/measurements.js +2 -2
  332. package/dist/domains/measure/measurements.js.map +1 -0
  333. package/dist/{features → domains}/modes/modeLayers.js +1 -1
  334. package/dist/domains/modes/modeLayers.js.map +1 -0
  335. package/dist/{features → domains}/modes/modeTriggers.js +3 -6
  336. package/dist/domains/modes/modeTriggers.js.map +1 -0
  337. package/dist/{features → domains}/pathEffects/effectSources.js +1 -1
  338. package/dist/domains/pathEffects/effectSources.js.map +1 -0
  339. package/dist/{features → domains}/pathEffects/index.js +1 -1
  340. package/dist/domains/pathEffects/index.js.map +1 -0
  341. package/dist/{features → domains}/pathEffects/readSource.js +1 -1
  342. package/dist/domains/pathEffects/readSource.js.map +1 -0
  343. package/dist/{features → domains}/pathEffects/textItems.js +11 -2
  344. package/dist/domains/pathEffects/textItems.js.map +1 -0
  345. package/dist/{features → domains}/pathEffects/useEffectSourcesLayer.js +1 -1
  346. package/dist/domains/pathEffects/useEffectSourcesLayer.js.map +1 -0
  347. package/dist/{features → domains}/paths/anchorData.js +1 -1
  348. package/dist/domains/paths/anchorData.js.map +1 -0
  349. package/dist/{features → domains}/paths/anchorMarkers.js +9 -7
  350. package/dist/domains/paths/anchorMarkers.js.map +1 -0
  351. package/dist/{features → domains}/paths/editablePath.js +1 -1
  352. package/dist/domains/paths/editablePath.js.map +1 -0
  353. package/dist/{features → domains}/paths/index.js +3 -3
  354. package/dist/{features → domains}/paths/originProjection.js +1 -1
  355. package/dist/domains/paths/originProjection.js.map +1 -0
  356. package/dist/{features → domains}/paths/pathEditExtension.js +1 -1
  357. package/dist/domains/paths/pathEditExtension.js.map +1 -0
  358. package/dist/{features → domains}/paths/pathEditState.js +1 -1
  359. package/dist/domains/paths/pathEditState.js.map +1 -0
  360. package/dist/{features → domains}/paths/pathEditingOverlayLayer.js +1 -1
  361. package/dist/domains/paths/pathEditingOverlayLayer.js.map +1 -0
  362. package/dist/{features → domains}/paths/pathLayer.js +1 -1
  363. package/dist/domains/paths/pathLayer.js.map +1 -0
  364. package/dist/{features → domains}/paths/pathRepresentation.js +1 -1
  365. package/dist/domains/paths/pathRepresentation.js.map +1 -0
  366. package/dist/{features → domains}/paths/pathSnap/glyphs.js +1 -1
  367. package/dist/domains/paths/pathSnap/glyphs.js.map +1 -0
  368. package/dist/{features → domains}/paths/pathSnap/pathSnapSource.js +1 -1
  369. package/dist/domains/paths/pathSnap/pathSnapSource.js.map +1 -0
  370. package/dist/{features → domains}/paths/pathSnap/sceneIndex.js +1 -1
  371. package/dist/domains/paths/pathSnap/sceneIndex.js.map +1 -0
  372. package/dist/{features → domains}/paths/pathSnap/snapGeometry.js +3 -2
  373. package/dist/domains/paths/pathSnap/snapGeometry.js.map +1 -0
  374. package/dist/{features → domains}/paths/penPreviewLayer.js +1 -1
  375. package/dist/domains/paths/penPreviewLayer.js.map +1 -0
  376. package/dist/{features → domains}/paths/shapeGenerator.js +6 -4
  377. package/dist/domains/paths/shapeGenerator.js.map +1 -0
  378. package/dist/{features → domains}/paths/strokeOutline.js +1 -1
  379. package/dist/domains/paths/strokeOutline.js.map +1 -0
  380. package/dist/{features → domains}/paths/useAnchorFields.js +1 -1
  381. package/dist/domains/paths/useAnchorFields.js.map +1 -0
  382. package/dist/{features → domains}/paths/usePathEdit.js +1 -1
  383. package/dist/domains/paths/usePathEdit.js.map +1 -0
  384. package/dist/{features → domains}/poseRun/usePoseRun.js +1 -1
  385. package/dist/domains/poseRun/usePoseRun.js.map +1 -0
  386. package/dist/{features → domains}/selection/enteredGroupFrame.js +49 -10
  387. package/dist/domains/selection/enteredGroupFrame.js.map +1 -0
  388. package/dist/{features → domains}/selection/enteredGroupScope.js +1 -1
  389. package/dist/domains/selection/enteredGroupScope.js.map +1 -0
  390. package/dist/domains/selection/enteredOperands.js +29 -0
  391. package/dist/domains/selection/enteredOperands.js.map +1 -0
  392. package/dist/{features → domains}/selection/handleCommands.js +1 -1
  393. package/dist/domains/selection/handleCommands.js.map +1 -0
  394. package/dist/{features → domains}/selection/overlay.js +1 -1
  395. package/dist/domains/selection/overlay.js.map +1 -0
  396. package/dist/{features → domains}/selection/selectionPose.js +1 -1
  397. package/dist/domains/selection/selectionPose.js.map +1 -0
  398. package/dist/{features → domains}/snap/angle2d.js +1 -1
  399. package/dist/domains/snap/angle2d.js.map +1 -0
  400. package/dist/{features → domains}/snap/debugCandidates.js +1 -1
  401. package/dist/domains/snap/debugCandidates.js.map +1 -0
  402. package/dist/{features → domains}/snap/gather.js +1 -1
  403. package/dist/domains/snap/gather.js.map +1 -0
  404. package/dist/{features → domains}/snap/inputSubspace.js +1 -1
  405. package/dist/domains/snap/inputSubspace.js.map +1 -0
  406. package/dist/{features → domains}/snap/lazySession.js +1 -1
  407. package/dist/domains/snap/lazySession.js.map +1 -0
  408. package/dist/{features → domains}/snap/marks.js +1 -1
  409. package/dist/domains/snap/marks.js.map +1 -0
  410. package/dist/{features → domains}/snap/outcomeStore.js +1 -1
  411. package/dist/domains/snap/outcomeStore.js.map +1 -0
  412. package/dist/{features → domains}/snap/pointSnap.js +1 -1
  413. package/dist/domains/snap/pointSnap.js.map +1 -0
  414. package/dist/{features → domains}/snap/probes2d.js +1 -1
  415. package/dist/domains/snap/probes2d.js.map +1 -0
  416. package/dist/{features → domains}/snap/readoutDraw.js +1 -1
  417. package/dist/domains/snap/readoutDraw.js.map +1 -0
  418. package/dist/{features → domains}/snap/readoutLayer.js +1 -1
  419. package/dist/domains/snap/readoutLayer.js.map +1 -0
  420. package/dist/{features → domains}/snap/registry.js +1 -1
  421. package/dist/domains/snap/registry.js.map +1 -0
  422. package/dist/{features → domains}/snap/resizeBox.js +1 -1
  423. package/dist/domains/snap/resizeBox.js.map +1 -0
  424. package/dist/{features → domains}/snap/roles.js +1 -1
  425. package/dist/domains/snap/roles.js.map +1 -0
  426. package/dist/{features → domains}/snap/rotationSource.js +1 -1
  427. package/dist/domains/snap/rotationSource.js.map +1 -0
  428. package/dist/{features → domains}/snap/sceneReads.js +24 -3
  429. package/dist/domains/snap/sceneReads.js.map +1 -0
  430. package/dist/{features → domains}/snap/sceneSession2d.js +3 -2
  431. package/dist/domains/snap/sceneSession2d.js.map +1 -0
  432. package/dist/{features → domains}/snap/screen.js +1 -1
  433. package/dist/domains/snap/screen.js.map +1 -0
  434. package/dist/{features → domains}/snap/session2d.js +3 -2
  435. package/dist/domains/snap/session2d.js.map +1 -0
  436. package/dist/{features → domains}/snap/spanSnap.js +1 -1
  437. package/dist/domains/snap/spanSnap.js.map +1 -0
  438. package/dist/{features → domains}/snap/stepAngles.js +1 -1
  439. package/dist/domains/snap/stepAngles.js.map +1 -0
  440. package/dist/{features → domains}/text/editingDrawOne.js +4 -4
  441. package/dist/domains/text/editingDrawOne.js.map +1 -0
  442. package/dist/domains/text/hostTextEditors.js +24 -0
  443. package/dist/domains/text/hostTextEditors.js.map +1 -0
  444. package/dist/{features → domains}/text/index.js +1 -1
  445. package/dist/{features → domains}/text/sceneTextDrafts.js +1 -1
  446. package/dist/domains/text/sceneTextDrafts.js.map +1 -0
  447. package/dist/{features → domains}/text/textHitAt.js +18 -2
  448. package/dist/domains/text/textHitAt.js.map +1 -0
  449. package/dist/{features → domains}/text/textLayer.js +1 -1
  450. package/dist/domains/text/textLayer.js.map +1 -0
  451. package/dist/{features → domains}/text/useSceneTextEdit.js +11 -3
  452. package/dist/domains/text/useSceneTextEdit.js.map +1 -0
  453. package/dist/{features → domains}/viewports/aim.js +1 -1
  454. package/dist/domains/viewports/aim.js.map +1 -0
  455. package/dist/{features → domains}/viewports/viewMarker.js +23 -5
  456. package/dist/domains/viewports/viewMarker.js.map +1 -0
  457. package/dist/{features → domains}/viewports/viewMarkerDrag.js +3 -3
  458. package/dist/domains/viewports/viewMarkerDrag.js.map +1 -0
  459. package/dist/{features → domains}/viewports/viewResolver.js +1 -1
  460. package/dist/domains/viewports/viewResolver.js.map +1 -0
  461. package/dist/{features → domains}/viewports/viewportLayer.js +1 -1
  462. package/dist/domains/viewports/viewportLayer.js.map +1 -0
  463. package/dist/icons.table.js +1 -1
  464. package/dist/icons.table.js.map +1 -1
  465. package/dist/icons.table.json +106 -6
  466. package/dist/index.d.ts +1441 -1050
  467. package/dist/index.js +90 -77
  468. package/dist/interactions/actions/admitsChild.js +6 -2
  469. package/dist/interactions/actions/admitsChild.js.map +1 -1
  470. package/dist/interactions/actions/align/align.js +1 -4
  471. package/dist/interactions/actions/align/align.js.map +1 -1
  472. package/dist/interactions/actions/booleans/booleanGroupAction.js +66 -0
  473. package/dist/interactions/actions/booleans/booleanGroupAction.js.map +1 -0
  474. package/dist/interactions/actions/booleans/keymap.js +52 -0
  475. package/dist/interactions/actions/booleans/keymap.js.map +1 -0
  476. package/dist/interactions/actions/booleans/operands.js +1 -1
  477. package/dist/interactions/actions/booleans/pieces.js +4 -11
  478. package/dist/interactions/actions/booleans/pieces.js.map +1 -1
  479. package/dist/interactions/actions/clipboard/action.js +3 -7
  480. package/dist/interactions/actions/clipboard/action.js.map +1 -1
  481. package/dist/interactions/actions/clipboard/clipboardOps.js +1 -1
  482. package/dist/interactions/actions/clipboard/clipboardOps.js.map +1 -1
  483. package/dist/interactions/actions/clipboard/materializePaste.js.map +1 -1
  484. package/dist/interactions/actions/defaults/anchorEditing.js +6 -6
  485. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  486. package/dist/interactions/actions/defaults/bendSegment.js +1 -1
  487. package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
  488. package/dist/interactions/actions/defaults/containerScroll.js +170 -0
  489. package/dist/interactions/actions/defaults/containerScroll.js.map +1 -0
  490. package/dist/interactions/actions/defaults/contextMenu.js +2 -5
  491. package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
  492. package/dist/interactions/actions/defaults/delete.js +1 -1
  493. package/dist/interactions/actions/defaults/delete.js.map +1 -1
  494. package/dist/interactions/actions/defaults/duplicate.js +1 -3
  495. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  496. package/dist/interactions/actions/defaults/enterGroup.js +7 -12
  497. package/dist/interactions/actions/defaults/enterGroup.js.map +1 -1
  498. package/dist/interactions/actions/defaults/enterPathEdit.js +4 -8
  499. package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
  500. package/dist/interactions/actions/defaults/group.js +12 -24
  501. package/dist/interactions/actions/defaults/group.js.map +1 -1
  502. package/dist/interactions/actions/defaults/ingest.js +18 -10
  503. package/dist/interactions/actions/defaults/ingest.js.map +1 -1
  504. package/dist/interactions/actions/defaults/insertPathAnchor.js +3 -3
  505. package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
  506. package/dist/interactions/actions/defaults/nudgeSteps.js +3 -21
  507. package/dist/interactions/actions/defaults/nudgeSteps.js.map +1 -1
  508. package/dist/interactions/actions/defaults/pathEditMarks.js.map +1 -1
  509. package/dist/interactions/actions/defaults/selectDeep.js +2 -2
  510. package/dist/interactions/actions/defaults/selectDeep.js.map +1 -1
  511. package/dist/interactions/actions/distribute/distribute.js.map +1 -1
  512. package/dist/interactions/actions/dropVerdict.js +9 -0
  513. package/dist/interactions/actions/dropVerdict.js.map +1 -0
  514. package/dist/interactions/actions/edit-anchors/action.js +2 -2
  515. package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
  516. package/dist/interactions/actions/edit-anchors/extensionDrags.js.map +1 -1
  517. package/dist/interactions/actions/edit-anchors/geometry.js +8 -6
  518. package/dist/interactions/actions/edit-anchors/geometry.js.map +1 -1
  519. package/dist/interactions/actions/edit-anchors/handleDrag.js.map +1 -1
  520. package/dist/interactions/actions/edit-anchors/preview.js +1 -1
  521. package/dist/interactions/actions/edit-anchors/preview.js.map +1 -1
  522. package/dist/interactions/actions/flip/action.js +3 -2
  523. package/dist/interactions/actions/flip/action.js.map +1 -1
  524. package/dist/interactions/actions/geometryProjection.js +8 -3
  525. package/dist/interactions/actions/geometryProjection.js.map +1 -1
  526. package/dist/interactions/actions/gestureFrames.js +1 -0
  527. package/dist/interactions/actions/gestureFrames.js.map +1 -1
  528. package/dist/interactions/actions/insert/action.js +6 -2
  529. package/dist/interactions/actions/insert/action.js.map +1 -1
  530. package/dist/interactions/actions/insert/frame.js +1 -1
  531. package/dist/interactions/actions/insert/frame.js.map +1 -1
  532. package/dist/interactions/actions/insert/placeAction.js +6 -8
  533. package/dist/interactions/actions/insert/placeAction.js.map +1 -1
  534. package/dist/interactions/actions/insert/session.js +2 -2
  535. package/dist/interactions/actions/insert/session.js.map +1 -1
  536. package/dist/interactions/actions/move/action.js +6 -15
  537. package/dist/interactions/actions/move/action.js.map +1 -1
  538. package/dist/interactions/actions/move/behaviors/layoutDrop.js +12 -2
  539. package/dist/interactions/actions/move/behaviors/layoutDrop.js.map +1 -1
  540. package/dist/interactions/actions/move/behaviors/reparentOnDrop.js +29 -10
  541. package/dist/interactions/actions/move/behaviors/reparentOnDrop.js.map +1 -1
  542. package/dist/interactions/actions/move/behaviors/snapToContainer.js +42 -6
  543. package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
  544. package/dist/interactions/actions/move/capture.js +4 -8
  545. package/dist/interactions/actions/move/capture.js.map +1 -1
  546. package/dist/interactions/actions/move/commit/index.js.map +1 -1
  547. package/dist/interactions/actions/move/commit/layoutDrop.js +4 -3
  548. package/dist/interactions/actions/move/commit/layoutDrop.js.map +1 -1
  549. package/dist/interactions/actions/move/commit/layoutRelease.js +15 -9
  550. package/dist/interactions/actions/move/commit/layoutRelease.js.map +1 -1
  551. package/dist/interactions/actions/move/commit/reparent.js +19 -13
  552. package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
  553. package/dist/interactions/actions/move/delta.js +51 -5
  554. package/dist/interactions/actions/move/delta.js.map +1 -1
  555. package/dist/interactions/actions/move/frame.js +8 -4
  556. package/dist/interactions/actions/move/frame.js.map +1 -1
  557. package/dist/interactions/actions/move/layout/container.js +19 -9
  558. package/dist/interactions/actions/move/layout/container.js.map +1 -1
  559. package/dist/interactions/actions/move/layout/dragged.js +2 -2
  560. package/dist/interactions/actions/move/layout/dragged.js.map +1 -1
  561. package/dist/interactions/actions/move/layout/dropPass.js +36 -18
  562. package/dist/interactions/actions/move/layout/dropPass.js.map +1 -1
  563. package/dist/interactions/actions/move/layout/exits.js +2 -2
  564. package/dist/interactions/actions/move/layout/exits.js.map +1 -1
  565. package/dist/interactions/actions/move/layout/glide.js +5 -5
  566. package/dist/interactions/actions/move/layout/glide.js.map +1 -1
  567. package/dist/interactions/actions/move/layout/view.js +55 -0
  568. package/dist/interactions/actions/move/layout/view.js.map +1 -0
  569. package/dist/interactions/actions/move/refusal.js +52 -0
  570. package/dist/interactions/actions/move/refusal.js.map +1 -0
  571. package/dist/interactions/actions/move/session.js +9 -8
  572. package/dist/interactions/actions/move/session.js.map +1 -1
  573. package/dist/interactions/actions/move/translate.js +10 -4
  574. package/dist/interactions/actions/move/translate.js.map +1 -1
  575. package/dist/interactions/actions/moveNodes.js +21 -5
  576. package/dist/interactions/actions/moveNodes.js.map +1 -1
  577. package/dist/interactions/actions/pathCommands/pathNodes.js +3 -3
  578. package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -1
  579. package/dist/interactions/actions/planeInput.js +14 -13
  580. package/dist/interactions/actions/planeInput.js.map +1 -1
  581. package/dist/interactions/actions/poseFrame.js +21 -8
  582. package/dist/interactions/actions/poseFrame.js.map +1 -1
  583. package/dist/interactions/actions/resize/action.js +1 -1
  584. package/dist/interactions/actions/resize/action.js.map +1 -1
  585. package/dist/interactions/actions/resize/aspect.js +1 -1
  586. package/dist/interactions/actions/resize/aspect.js.map +1 -1
  587. package/dist/interactions/actions/resize/commit.js +10 -1
  588. package/dist/interactions/actions/resize/commit.js.map +1 -1
  589. package/dist/interactions/actions/resize/frame.js +3 -2
  590. package/dist/interactions/actions/resize/frame.js.map +1 -1
  591. package/dist/interactions/actions/resize/held.js +44 -0
  592. package/dist/interactions/actions/resize/held.js.map +1 -0
  593. package/dist/interactions/actions/resize/session.js +3 -1
  594. package/dist/interactions/actions/resize/session.js.map +1 -1
  595. package/dist/interactions/actions/resolveOverlays.js +9 -0
  596. package/dist/interactions/actions/resolveOverlays.js.map +1 -1
  597. package/dist/interactions/actions/resolvePreviews.js +23 -7
  598. package/dist/interactions/actions/resolvePreviews.js.map +1 -1
  599. package/dist/interactions/actions/rotate/action.js +1 -1
  600. package/dist/interactions/actions/rotate/action.js.map +1 -1
  601. package/dist/interactions/actions/rotate/frame.js +1 -1
  602. package/dist/interactions/actions/rotate/frame.js.map +1 -1
  603. package/dist/interactions/actions/rotate/session.js +2 -2
  604. package/dist/interactions/actions/rotate/session.js.map +1 -1
  605. package/dist/interactions/actions/selectionSubtree.js +2 -4
  606. package/dist/interactions/actions/selectionSubtree.js.map +1 -1
  607. package/dist/interactions/actions/spatialReference.js +4 -9
  608. package/dist/interactions/actions/spatialReference.js.map +1 -1
  609. package/dist/interactions/gestures/dragRadial/dragRadial.js.map +1 -1
  610. package/dist/interactions/gestures/dragRect/dragRect.js.map +1 -1
  611. package/dist/kitSettingsSchema.js +2 -2
  612. package/dist/kitSettingsSchema.js.map +1 -1
  613. package/dist/{math-C_elShP_.d.ts → math-B_unOnF4.d.ts} +2 -2
  614. package/dist/math.d.ts +3 -3
  615. package/dist/move.d.ts +6 -6
  616. package/dist/{options-ClEm3SEl.d.ts → options-DAjkhbcs.d.ts} +5 -5
  617. package/dist/{poseDescriptor-DN2yfnq_.d.ts → poseDescriptor-CvSxVhCd.d.ts} +17 -4
  618. package/dist/resize.d.ts +6 -6
  619. package/dist/style.css +14 -0
  620. package/dist/test-seams.d.ts +11 -15
  621. package/dist/test-seams.js +1 -1
  622. package/dist/tools/builtin/eyedropper/useEyedropperTool.js +3 -6
  623. package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
  624. package/dist/tools/builtin/line/useLineTool.js.map +1 -1
  625. package/dist/tools/builtin/measure/useMeasureTool.js +2 -2
  626. package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
  627. package/dist/tools/builtin/pen/penHandle.js +2 -2
  628. package/dist/tools/builtin/pen/penHandle.js.map +1 -1
  629. package/dist/tools/builtin/pen/usePenTool.js +13 -19
  630. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  631. package/dist/tools/builtin/polygon/usePolygonTool.js +1 -1
  632. package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
  633. package/dist/tools/builtin/select/groupEntry.js +1 -1
  634. package/dist/tools/builtin/select/groupEntry.js.map +1 -1
  635. package/dist/tools/builtin/select/selectionContributions.js +1 -1
  636. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  637. package/dist/tools/builtin/select/useSelectTool.js +7 -7
  638. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  639. package/dist/tools/builtin/slice/useSliceTool.js +5 -8
  640. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  641. package/dist/tools/builtin/star/useStarTool.js +1 -1
  642. package/dist/tools/builtin/star/useStarTool.js.map +1 -1
  643. package/dist/tools/index.js +2 -1
  644. package/dist/{types-49uYJN3j.d.ts → types-A_sNJYRd.d.ts} +8 -0
  645. package/dist/{types-BEdRIhNc.d.ts → types-DW14eu9B.d.ts} +131 -36
  646. package/dist/{types-p2alu-R1.d.ts → types-VCtfchp-.d.ts} +4 -6
  647. package/dist/util/color.js +12 -14
  648. package/dist/util/color.js.map +1 -1
  649. package/dist/version.js +1 -1
  650. package/package.json +25 -24
  651. package/dist/canvas/poseCascade.js +0 -65
  652. package/dist/canvas/poseCascade.js.map +0 -1
  653. package/dist/features/chrome-caps/buildChromeCtx.js.map +0 -1
  654. package/dist/features/chrome-caps/conditions.js.map +0 -1
  655. package/dist/features/chrome-caps/defaults.js.map +0 -1
  656. package/dist/features/chrome-caps/resolve.js.map +0 -1
  657. package/dist/features/chrome-caps/useChromeCaps.js.map +0 -1
  658. package/dist/features/chrome-caps/useHoverTracking.js.map +0 -1
  659. package/dist/features/ingestion/contentHandlers.js.map +0 -1
  660. package/dist/features/ingestion/imageHandler.js.map +0 -1
  661. package/dist/features/ingestion/openFilePicker.js.map +0 -1
  662. package/dist/features/ingestion/placement.js.map +0 -1
  663. package/dist/features/ingestion/registerKitHandlers.js +0 -43
  664. package/dist/features/ingestion/registerKitHandlers.js.map +0 -1
  665. package/dist/features/ingestion/svgHandler.js.map +0 -1
  666. package/dist/features/ingestion/textHandler.js.map +0 -1
  667. package/dist/features/ingestion/useCanvasIngestion.js.map +0 -1
  668. package/dist/features/ingestion/weaselJsonHandler.js.map +0 -1
  669. package/dist/features/longPress/longPressFeedback.js.map +0 -1
  670. package/dist/features/measure/actionIds.js.map +0 -1
  671. package/dist/features/measure/measureCommands.js.map +0 -1
  672. package/dist/features/measure/measureContribution.js.map +0 -1
  673. package/dist/features/measure/measureEdits.js.map +0 -1
  674. package/dist/features/measure/measureGestures.js.map +0 -1
  675. package/dist/features/measure/measureHit.js.map +0 -1
  676. package/dist/features/measure/measureLayer.js.map +0 -1
  677. package/dist/features/measure/measurement.js.map +0 -1
  678. package/dist/features/measure/measurements.js.map +0 -1
  679. package/dist/features/modes/modeLayers.js.map +0 -1
  680. package/dist/features/modes/modeTriggers.js.map +0 -1
  681. package/dist/features/pathEffects/effectSources.js.map +0 -1
  682. package/dist/features/pathEffects/index.js.map +0 -1
  683. package/dist/features/pathEffects/readSource.js.map +0 -1
  684. package/dist/features/pathEffects/textItems.js.map +0 -1
  685. package/dist/features/pathEffects/useEffectSourcesLayer.js.map +0 -1
  686. package/dist/features/paths/anchorData.js.map +0 -1
  687. package/dist/features/paths/anchorMarkers.js.map +0 -1
  688. package/dist/features/paths/editablePath.js.map +0 -1
  689. package/dist/features/paths/originProjection.js.map +0 -1
  690. package/dist/features/paths/pathEditExtension.js.map +0 -1
  691. package/dist/features/paths/pathEditState.js.map +0 -1
  692. package/dist/features/paths/pathEditingOverlayLayer.js.map +0 -1
  693. package/dist/features/paths/pathLayer.js.map +0 -1
  694. package/dist/features/paths/pathRepresentation.js.map +0 -1
  695. package/dist/features/paths/pathSnap/glyphs.js.map +0 -1
  696. package/dist/features/paths/pathSnap/pathSnapSource.js.map +0 -1
  697. package/dist/features/paths/pathSnap/sceneIndex.js.map +0 -1
  698. package/dist/features/paths/pathSnap/snapGeometry.js.map +0 -1
  699. package/dist/features/paths/penPreviewLayer.js.map +0 -1
  700. package/dist/features/paths/shapeGenerator.js.map +0 -1
  701. package/dist/features/paths/strokeOutline.js.map +0 -1
  702. package/dist/features/paths/useAnchorFields.js.map +0 -1
  703. package/dist/features/paths/usePathEdit.js.map +0 -1
  704. package/dist/features/poseRun/usePoseRun.js.map +0 -1
  705. package/dist/features/selection/enteredGroupFrame.js.map +0 -1
  706. package/dist/features/selection/enteredGroupScope.js.map +0 -1
  707. package/dist/features/selection/handleCommands.js.map +0 -1
  708. package/dist/features/selection/overlay.js.map +0 -1
  709. package/dist/features/selection/selectionPose.js.map +0 -1
  710. package/dist/features/snap/angle2d.js.map +0 -1
  711. package/dist/features/snap/debugCandidates.js.map +0 -1
  712. package/dist/features/snap/gather.js.map +0 -1
  713. package/dist/features/snap/inputSubspace.js.map +0 -1
  714. package/dist/features/snap/lazySession.js.map +0 -1
  715. package/dist/features/snap/marks.js.map +0 -1
  716. package/dist/features/snap/outcomeStore.js.map +0 -1
  717. package/dist/features/snap/pointSnap.js.map +0 -1
  718. package/dist/features/snap/probes2d.js.map +0 -1
  719. package/dist/features/snap/readoutDraw.js.map +0 -1
  720. package/dist/features/snap/readoutLayer.js.map +0 -1
  721. package/dist/features/snap/registry.js.map +0 -1
  722. package/dist/features/snap/resizeBox.js.map +0 -1
  723. package/dist/features/snap/roles.js.map +0 -1
  724. package/dist/features/snap/rotationSource.js.map +0 -1
  725. package/dist/features/snap/sceneReads.js.map +0 -1
  726. package/dist/features/snap/sceneSession2d.js.map +0 -1
  727. package/dist/features/snap/screen.js.map +0 -1
  728. package/dist/features/snap/session2d.js.map +0 -1
  729. package/dist/features/snap/spanSnap.js.map +0 -1
  730. package/dist/features/snap/stepAngles.js.map +0 -1
  731. package/dist/features/text/editingDrawOne.js.map +0 -1
  732. package/dist/features/text/sceneTextDrafts.js.map +0 -1
  733. package/dist/features/text/textHitAt.js.map +0 -1
  734. package/dist/features/text/textLayer.js.map +0 -1
  735. package/dist/features/text/useSceneTextEdit.js.map +0 -1
  736. package/dist/features/viewports/aim.js.map +0 -1
  737. package/dist/features/viewports/viewMarker.js.map +0 -1
  738. package/dist/features/viewports/viewMarkerDrag.js.map +0 -1
  739. package/dist/features/viewports/viewResolver.js.map +0 -1
  740. package/dist/features/viewports/viewportLayer.js.map +0 -1
  741. /package/dist/{features → domains}/chrome-caps/index.js +0 -0
@@ -1,10 +1,11 @@
1
1
  import { documentOf } from "../../core/scene/documentOf.js";
2
2
  import { poseDescriptorForNode } from "../../core/geometry/poseDescriptor.js";
3
3
  import { AUTO_POSE_DESCRIPTOR } from "../../core/geometry/autoPoseDescriptor.js";
4
+ import { indexedCandidates } from "../pickIndex/scenePickIndex.js";
4
5
  import { scenePoseFrame } from "../../interactions/actions/poseFrame.js";
5
6
  import { drawnPose, leafPath, storePiece } from "./pathLeaf.js";
6
7
  import { computeSliceOps } from "../../interactions/actions/defaults/sliceOps.js";
7
- import { pathInWorld } from "@weasel-js/geom";
8
+ import { boundsOfCoords, pathInWorld } from "@weasel-js/geom";
8
9
  import { useLatest } from "@weasel-js/react";
9
10
  import { useDepSource } from "@weasel-js/routing/react";
10
11
 
@@ -45,7 +46,8 @@ function useSliceDepSource(scene, selection, adapter, poseDescriptor) {
45
46
  const descriptor = descriptorRef.current ?? AUTO_POSE_DESCRIPTOR;
46
47
  const leaves = [];
47
48
  const drawnAt = /* @__PURE__ */ new Map();
48
- for (const node of sc.renderOrderNodes()) {
49
+ const nodes = candidatesUnder(sc, descriptor, cut) ?? sc.renderOrderNodes();
50
+ for (const node of nodes) {
49
51
  if (sc.isHidden(node.id)) continue;
50
52
  const path = leafPath(sc, node);
51
53
  if (!path) continue;
@@ -77,6 +79,18 @@ function useSliceDepSource(scene, selection, adapter, poseDescriptor) {
77
79
  if (nextSelection) sel.set(nextSelection);
78
80
  } }));
79
81
  }
82
+ /** The nodes whose boxes the cut's bounds reach, or null when the pick index cannot say. */
83
+ function candidatesUnder(scene, descriptor, cut) {
84
+ const b = boundsOfCoords(cut.flatMap((p) => [p.x, p.y]));
85
+ if (b === null) return null;
86
+ const broad = { box: {
87
+ x: b[0],
88
+ y: b[1],
89
+ width: b[2] - b[0],
90
+ height: b[3] - b[1]
91
+ } };
92
+ return indexedCandidates(scene, descriptor, () => broad);
93
+ }
80
94
  function siblingIndex(scene, node) {
81
95
  return (node.parent == null ? scene.roots : scene.childrenOf(node.parent)).indexOf(node.id);
82
96
  }
@@ -1 +1 @@
1
- {"version":3,"file":"slice.js","names":[],"sources":["../../../src/canvas/deps/slice.ts"],"sourcesContent":["/**\n * The `slice` dep `sliceAction` and `useSliceTool` commit their cuts through.\n *\n * `<SceneCanvas>` publishes `useSliceDepSource` over its own scene. A consumer\n * replaces it with `useSliceDep` (or `useDepSource('slice', …)`) from under\n * the canvas; the newest registration wins, and a canvas child registers\n * after the canvas's own.\n */\nimport { useDepSource } from '@weasel-js/routing/react';\nimport { useLatest } from '@weasel-js/react';\nimport type { SliceDep } from 'interactions/actions/depSchema';\nimport type { Scene, NodeId, Node } from 'core/scene/types';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport type { Op } from 'core/ops/types';\nimport { AUTO_POSE_DESCRIPTOR } from 'core/geometry/autoPoseDescriptor';\nimport { poseDescriptorForNode, type PoseDescriptor } from 'core/geometry/poseDescriptor';\nimport { pathInWorld } from '@weasel-js/geom';\nimport { drawnPose, leafPath, storePiece, type DrawnPose } from './pathLeaf';\nimport { scenePoseFrame } from 'interactions/actions/poseFrame';\nimport { documentOf } from 'core/scene/documentOf';\nimport { computeSliceOps, type SliceLeaf } from 'interactions/actions/defaults/sliceOps';\n\n/** Publish how a slice (knife cut) is performed, so the `slice` action can\n * run against the consumer's geometry. */\nexport function useSliceDep(dep: SliceDep): void {\n const depRef = useLatest(dep);\n\n useDepSource('slice', (): SliceDep => depRef.current);\n}\n\n/** What the `slice` dep writes its batch through. An adapter satisfies it. */\nexport interface OpsApplier {\n applyOps(ops: Op[], label?: string): void;\n}\n\n/**\n * The kit `slice` dep: cut every leaf the cut crosses and swap it for its\n * pieces in one undoable batch.\n *\n * A leaf is cut when its `data.path` is a `Path` and `poseDescriptor` can read\n * its world pose as a box and a rotation; a leaf on a locked layer, or one\n * whose geometry derives from other nodes, is passed over. A piece keeps the\n * source's rotation in its pose when the descriptor can write one\n * (`withRotation`), and has the rotation baked into its path otherwise. The\n * pieces of a selected leaf take its place in the selection.\n */\nexport function useSliceDepSource(\n scene: Scene<unknown, string, unknown>,\n selection: SelectionApi,\n adapter: OpsApplier,\n poseDescriptor?: PoseDescriptor<unknown>,\n): void {\n const sceneRef = useLatest(scene);\n const selectionRef = useLatest(selection);\n const adapterRef = useLatest(adapter);\n const descriptorRef = useLatest(poseDescriptor);\n\n useDepSource('slice', (): SliceDep => ({\n commit(cut) {\n // A commit cuts what the document holds, not what an open gesture or edit is showing.\n const sc = documentOf(sceneRef.current);\n const frame = scenePoseFrame(sc);\n const descriptor = descriptorRef.current ?? AUTO_POSE_DESCRIPTOR;\n const leaves: SliceLeaf<Node<unknown, string, unknown>>[] = [];\n const drawnAt = new Map<string, DrawnPose>();\n for (const node of sc.renderOrderNodes()) {\n if (sc.isHidden(node.id)) continue;\n const path = leafPath(sc, node);\n if (!path) continue;\n const drawn = drawnPose(poseDescriptorForNode(descriptor, node), frame.world(node.id));\n if (!drawn) continue;\n drawnAt.set(node.id, drawn);\n leaves.push({ node, index: siblingIndex(sc, node), worldPath: pathInWorld(path, drawn.box) });\n }\n\n const sel = selectionRef.current;\n const { ops, nextSelection } = computeSliceOps({\n leaves,\n cut,\n nextId: () => sc.mintId(),\n selection: sel.get(),\n placePiece: (leaf, piece) => {\n const stored = storePiece(drawnAt.get(leaf.node.id)!, piece);\n return { pose: frame.local(leaf.node.id, stored.pose), path: stored.path };\n },\n });\n if (ops.length === 0) return;\n adapterRef.current.applyOps(ops, 'Slice');\n if (nextSelection) sel.set(nextSelection as NodeId[]);\n },\n }));\n}\n\nfunction siblingIndex(scene: Scene<unknown, string, unknown>, node: Node<unknown, string, unknown>): number {\n const siblings = node.parent == null ? scene.roots : scene.childrenOf(node.parent);\n return siblings.indexOf(node.id);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,YAAY,KAAqB;CAC/C,MAAM,SAAS,UAAU,GAAG;CAE5B,aAAa,eAAyB,OAAO,OAAO;AACtD;;;;;;;;;;;;AAkBA,SAAgB,kBACd,OACA,WACA,SACA,gBACM;CACN,MAAM,WAAW,UAAU,KAAK;CAChC,MAAM,eAAe,UAAU,SAAS;CACxC,MAAM,aAAa,UAAU,OAAO;CACpC,MAAM,gBAAgB,UAAU,cAAc;CAE9C,aAAa,gBAA0B,EACrC,OAAO,KAAK;EAEV,MAAM,KAAK,WAAW,SAAS,OAAO;EACtC,MAAM,QAAQ,eAAe,EAAE;EAC/B,MAAM,aAAa,cAAc,WAAW;EAC5C,MAAM,SAAsD,CAAC;EAC7D,MAAM,0BAAU,IAAI,IAAuB;EAC3C,KAAK,MAAM,QAAQ,GAAG,iBAAiB,GAAG;GACxC,IAAI,GAAG,SAAS,KAAK,EAAE,GAAG;GAC1B,MAAM,OAAO,SAAS,IAAI,IAAI;GAC9B,IAAI,CAAC,MAAM;GACX,MAAM,QAAQ,UAAU,sBAAsB,YAAY,IAAI,GAAG,MAAM,MAAM,KAAK,EAAE,CAAC;GACrF,IAAI,CAAC,OAAO;GACZ,QAAQ,IAAI,KAAK,IAAI,KAAK;GAC1B,OAAO,KAAK;IAAE;IAAM,OAAO,aAAa,IAAI,IAAI;IAAG,WAAW,YAAY,MAAM,MAAM,GAAG;GAAE,CAAC;EAC9F;EAEA,MAAM,MAAM,aAAa;EACzB,MAAM,EAAE,KAAK,kBAAkB,gBAAgB;GAC7C;GACA;GACA,cAAc,GAAG,OAAO;GACxB,WAAW,IAAI,IAAI;GACnB,aAAa,MAAM,UAAU;IAC3B,MAAM,SAAS,WAAW,QAAQ,IAAI,KAAK,KAAK,EAAE,GAAI,KAAK;IAC3D,OAAO;KAAE,MAAM,MAAM,MAAM,KAAK,KAAK,IAAI,OAAO,IAAI;KAAG,MAAM,OAAO;IAAK;GAC3E;EACF,CAAC;EACD,IAAI,IAAI,WAAW,GAAG;EACtB,WAAW,QAAQ,SAAS,KAAK,OAAO;EACxC,IAAI,eAAe,IAAI,IAAI,aAAyB;CACtD,EACF,EAAE;AACJ;AAEA,SAAS,aAAa,OAAwC,MAA8C;CAE1G,QADiB,KAAK,UAAU,OAAO,MAAM,QAAQ,MAAM,WAAW,KAAK,MAAM,EAC1E,CAAS,QAAQ,KAAK,EAAE;AACjC"}
1
+ {"version":3,"file":"slice.js","names":[],"sources":["../../../src/canvas/deps/slice.ts"],"sourcesContent":["/**\n * The `slice` dep `sliceAction` and `useSliceTool` commit their cuts through.\n *\n * `<SceneCanvas>` publishes `useSliceDepSource` over its own scene. A consumer\n * replaces it with `useSliceDep` (or `useDepSource('slice', …)`) from under\n * the canvas; the newest registration wins, and a canvas child registers\n * after the canvas's own.\n */\nimport { useDepSource } from '@weasel-js/routing/react';\nimport { useLatest } from '@weasel-js/react';\nimport type { SliceDep } from 'interactions/actions/depSchema';\nimport type { Scene, NodeId, Node } from 'core/scene/types';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport type { Op } from 'core/ops/types';\nimport { AUTO_POSE_DESCRIPTOR } from 'core/geometry/autoPoseDescriptor';\nimport { poseDescriptorForNode, type PoseDescriptor } from 'core/geometry/poseDescriptor';\nimport { boundsOfCoords, pathInWorld } from '@weasel-js/geom';\nimport { drawnPose, leafPath, storePiece, type DrawnPose } from './pathLeaf';\nimport { scenePoseFrame } from 'interactions/actions/poseFrame';\nimport { documentOf } from 'core/scene/documentOf';\nimport { computeSliceOps, type SliceLeaf } from 'interactions/actions/defaults/sliceOps';\nimport { indexedCandidates } from 'canvas/pickIndex/scenePickIndex';\n\n/** Publish how a slice (knife cut) is performed, so the `slice` action can\n * run against the consumer's geometry. */\nexport function useSliceDep(dep: SliceDep): void {\n const depRef = useLatest(dep);\n\n useDepSource('slice', (): SliceDep => depRef.current);\n}\n\n/** What the `slice` dep writes its batch through. An adapter satisfies it. */\nexport interface OpsApplier {\n applyOps(ops: Op[], label?: string): void;\n}\n\n/**\n * The kit `slice` dep: cut every leaf the cut crosses and swap it for its\n * pieces in one undoable batch.\n *\n * A leaf is cut when its `data.path` is a `Path` and `poseDescriptor` can read\n * its world pose as a box and a rotation; a leaf on a locked layer, or one\n * whose geometry derives from other nodes, is passed over. A piece keeps the\n * source's rotation in its pose when the descriptor can write one\n * (`withRotation`), and has the rotation baked into its path otherwise. The\n * pieces of a selected leaf take its place in the selection.\n */\nexport function useSliceDepSource(\n scene: Scene<unknown, string, unknown>,\n selection: SelectionApi,\n adapter: OpsApplier,\n poseDescriptor?: PoseDescriptor<unknown>,\n): void {\n const sceneRef = useLatest(scene);\n const selectionRef = useLatest(selection);\n const adapterRef = useLatest(adapter);\n const descriptorRef = useLatest(poseDescriptor);\n\n useDepSource('slice', (): SliceDep => ({\n commit(cut) {\n // A commit cuts what the document holds, not what an open gesture or edit is showing.\n const sc = documentOf(sceneRef.current);\n const frame = scenePoseFrame(sc);\n const descriptor = descriptorRef.current ?? AUTO_POSE_DESCRIPTOR;\n const leaves: SliceLeaf<Node<unknown, string, unknown>>[] = [];\n const drawnAt = new Map<string, DrawnPose>();\n const nodes = (candidatesUnder(sc, descriptor, cut) ?? sc.renderOrderNodes()) as readonly Node<unknown, string, unknown>[];\n for (const node of nodes) {\n if (sc.isHidden(node.id)) continue;\n const path = leafPath(sc, node);\n if (!path) continue;\n const drawn = drawnPose(poseDescriptorForNode(descriptor, node), frame.world(node.id));\n if (!drawn) continue;\n drawnAt.set(node.id, drawn);\n leaves.push({ node, index: siblingIndex(sc, node), worldPath: pathInWorld(path, drawn.box) });\n }\n\n const sel = selectionRef.current;\n const { ops, nextSelection } = computeSliceOps({\n leaves,\n cut,\n nextId: () => sc.mintId(),\n selection: sel.get(),\n placePiece: (leaf, piece) => {\n const stored = storePiece(drawnAt.get(leaf.node.id)!, piece);\n return { pose: frame.local(leaf.node.id, stored.pose), path: stored.path };\n },\n });\n if (ops.length === 0) return;\n adapterRef.current.applyOps(ops, 'Slice');\n if (nextSelection) sel.set(nextSelection as NodeId[]);\n },\n }));\n}\n\n/** The nodes whose boxes the cut's bounds reach, or null when the pick index cannot say. */\nfunction candidatesUnder(\n scene: Scene<unknown, string, unknown>,\n descriptor: PoseDescriptor<unknown>,\n cut: ReadonlyArray<{ x: number; y: number }>,\n): readonly unknown[] | null {\n const b = boundsOfCoords(cut.flatMap((p) => [p.x, p.y]));\n if (b === null) return null;\n const broad = { box: { x: b[0], y: b[1], width: b[2] - b[0], height: b[3] - b[1] } };\n return indexedCandidates(scene, descriptor, () => broad);\n}\n\nfunction siblingIndex(scene: Scene<unknown, string, unknown>, node: Node<unknown, string, unknown>): number {\n const siblings = node.parent == null ? scene.roots : scene.childrenOf(node.parent);\n return siblings.indexOf(node.id);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,YAAY,KAAqB;CAC/C,MAAM,SAAS,UAAU,GAAG;CAE5B,aAAa,eAAyB,OAAO,OAAO;AACtD;;;;;;;;;;;;AAkBA,SAAgB,kBACd,OACA,WACA,SACA,gBACM;CACN,MAAM,WAAW,UAAU,KAAK;CAChC,MAAM,eAAe,UAAU,SAAS;CACxC,MAAM,aAAa,UAAU,OAAO;CACpC,MAAM,gBAAgB,UAAU,cAAc;CAE9C,aAAa,gBAA0B,EACrC,OAAO,KAAK;EAEV,MAAM,KAAK,WAAW,SAAS,OAAO;EACtC,MAAM,QAAQ,eAAe,EAAE;EAC/B,MAAM,aAAa,cAAc,WAAW;EAC5C,MAAM,SAAsD,CAAC;EAC7D,MAAM,0BAAU,IAAI,IAAuB;EAC3C,MAAM,QAAS,gBAAgB,IAAI,YAAY,GAAG,KAAK,GAAG,iBAAiB;EAC3E,KAAK,MAAM,QAAQ,OAAO;GACxB,IAAI,GAAG,SAAS,KAAK,EAAE,GAAG;GAC1B,MAAM,OAAO,SAAS,IAAI,IAAI;GAC9B,IAAI,CAAC,MAAM;GACX,MAAM,QAAQ,UAAU,sBAAsB,YAAY,IAAI,GAAG,MAAM,MAAM,KAAK,EAAE,CAAC;GACrF,IAAI,CAAC,OAAO;GACZ,QAAQ,IAAI,KAAK,IAAI,KAAK;GAC1B,OAAO,KAAK;IAAE;IAAM,OAAO,aAAa,IAAI,IAAI;IAAG,WAAW,YAAY,MAAM,MAAM,GAAG;GAAE,CAAC;EAC9F;EAEA,MAAM,MAAM,aAAa;EACzB,MAAM,EAAE,KAAK,kBAAkB,gBAAgB;GAC7C;GACA;GACA,cAAc,GAAG,OAAO;GACxB,WAAW,IAAI,IAAI;GACnB,aAAa,MAAM,UAAU;IAC3B,MAAM,SAAS,WAAW,QAAQ,IAAI,KAAK,KAAK,EAAE,GAAI,KAAK;IAC3D,OAAO;KAAE,MAAM,MAAM,MAAM,KAAK,KAAK,IAAI,OAAO,IAAI;KAAG,MAAM,OAAO;IAAK;GAC3E;EACF,CAAC;EACD,IAAI,IAAI,WAAW,GAAG;EACtB,WAAW,QAAQ,SAAS,KAAK,OAAO;EACxC,IAAI,eAAe,IAAI,IAAI,aAAyB;CACtD,EACF,EAAE;AACJ;;AAGA,SAAS,gBACP,OACA,YACA,KAC2B;CAC3B,MAAM,IAAI,eAAe,IAAI,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;CACvD,IAAI,MAAM,MAAM,OAAO;CACvB,MAAM,QAAQ,EAAE,KAAK;EAAE,GAAG,EAAE;EAAI,GAAG,EAAE;EAAI,OAAO,EAAE,KAAK,EAAE;EAAI,QAAQ,EAAE,KAAK,EAAE;CAAG,EAAE;CACnF,OAAO,kBAAkB,OAAO,kBAAkB,KAAK;AACzD;AAEA,SAAS,aAAa,OAAwC,MAA8C;CAE1G,QADiB,KAAK,UAAU,OAAO,MAAM,QAAQ,MAAM,WAAW,KAAK,MAAM,EAC1E,CAAS,QAAQ,KAAK,EAAE;AACjC"}
@@ -1,8 +1,8 @@
1
- import { assertSnapSourceIds, snapSourcesFor } from "../../features/snap/gather.js";
2
- import { DEFAULT_SNAP_PX } from "../../features/snap/session2d.js";
3
- import { ownGeometryAt, pathSnapSource } from "../../features/paths/pathSnap/pathSnapSource.js";
4
- import { sceneSession2d } from "../../features/snap/sceneSession2d.js";
5
- import { rotationSnapSource } from "../../features/snap/rotationSource.js";
1
+ import { assertSnapSourceIds, snapSourcesFor } from "../../domains/snap/gather.js";
2
+ import { DEFAULT_SNAP_PX } from "../../domains/snap/session2d.js";
3
+ import { ownGeometryAt, pathSnapSource } from "../../domains/paths/pathSnap/pathSnapSource.js";
4
+ import { sceneSession2d } from "../../domains/snap/sceneSession2d.js";
5
+ import { rotationSnapSource } from "../../domains/snap/rotationSource.js";
6
6
  import { useKitSettings, useLatest } from "@weasel-js/react";
7
7
  import { useDepSource } from "@weasel-js/routing/react";
8
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"snap.js","names":[],"sources":["../../../src/canvas/deps/snap.ts"],"sourcesContent":["/**\n * `useSnapDepSource` — wires the `snap` dep whose `begin` every snapping\n * gesture runs: a session over the snap sources `session` names, writing its\n * marks to the outcome store this hook returns.\n */\nimport { useDepSource } from '@weasel-js/routing/react';\nimport { useKitSettings, useLatest } from '@weasel-js/react';\nimport type { DebugSink } from '@weasel-js/routing';\nimport type { SnapDep } from 'interactions/actions/snapDep';\nimport { ownGeometryAt } from 'features/paths/pathSnap/pathSnapSource';\nimport type { View } from 'core/viewport/view';\nimport type { Scene } from 'core/scene/types';\nimport type { DrawnBoxes } from 'interactions/actions/drawnBoxes';\nimport type { PoseDescriptor } from 'interactions/actions/resize/geometry';\nimport type { OriginProjection } from 'interactions/gestures/shared/originProjection';\nimport type { SnapOutcomeStore } from 'features/snap/outcomeStore';\nimport type { SnapSourceRegistry } from 'features/snap/registry';\nimport { assertSnapSourceIds, snapSourcesFor } from 'features/snap/gather';\nimport { sceneSession2d } from 'features/snap/sceneSession2d';\nimport { DEFAULT_SNAP_PX } from 'features/snap/session2d';\nimport type { SnapReadoutDep } from 'features/snap/readoutDep';\nimport { rotationSnapSource } from 'features/snap/rotationSource';\nimport { pathSnapSource } from 'features/paths/pathSnap/pathSnapSource';\nimport type { SnapSource } from 'features/snap/types';\n\ntype Point = { x: number; y: number };\n\n/** What `begin` reads: the scene its probes come from and the sources it asks. */\nexport interface SnapSessionSources {\n scene: Scene<unknown, string, unknown>;\n /** The boxes the subject is drawn with, read when a session begins. */\n boxes: () => DrawnBoxes;\n /** `<SceneCanvas snap.sources>`, then the presets' `snapSources`. */\n sources: readonly SnapSource[];\n /** Sources `useSnapSource` adds, after `sources`. */\n registry?: SnapSourceRegistry;\n /** Ids of the canvas's default sources to leave out. */\n omit?: readonly string[];\n /** Overrides the kit setting `targets.snapPx`. */\n reachPx?: number;\n /** How a node's rotation is read, for angle targets. */\n poseDescriptor?: PoseDescriptor<unknown>;\n /** How a pose's origin is read, for the `origin` probe. */\n originProjection?: OriginProjection<unknown>;\n /** The canvas's debug sink, read when a session begins: each frame's\n * candidates are recorded into it. */\n debug?: () => DebugSink | null | undefined;\n}\n\n/** The sources every canvas asks after its own, unless `omit` names one:\n * quarter turns and other nodes' angles for a rotate, and other nodes'\n * anchors for a point gesture, under `pathSnapSource`'s own id, so a\n * consumer's `pathSnapSource()` takes its place. */\nconst DEFAULT_SNAP_SOURCES: readonly SnapSource[] = [\n rotationSnapSource(),\n { ...pathSnapSource({ only: ['anchor'] }), gestures: ['point'] },\n];\n\n/** `listed`, which must not repeat an id, then each default whose id is\n * neither listed nor in `omit`. */\nfunction withDefaults(listed: readonly SnapSource[], omit: readonly string[] = []): SnapSource[] {\n assertSnapSourceIds(listed);\n const taken = new Set([...listed.map((s) => s.id), ...omit]);\n return [...listed, ...DEFAULT_SNAP_SOURCES.filter((s) => !taken.has(s.id))];\n}\n\nexport function useSnapDepSource(\n viewRef: React.RefObject<View | null>,\n session: SnapSessionSources,\n /** The canvas's outcome store, which its readout layer draws. */\n store: SnapOutcomeStore,\n): SnapOutcomeStore {\n const sessionRef = useLatest(session);\n const kitSettings = useKitSettings();\n useDepSource('snapReadout', (): SnapReadoutDep => ({ store }));\n\n useDepSource('snap', (): SnapDep => ({\n begin: (req) => {\n const s = sessionRef.current;\n const view = viewRef.current;\n const omit = new Set(req.omit);\n const sources = [\n ...withDefaults([...s.sources, ...(s.registry?.list() ?? [])], s.omit).filter((src) => !omit.has(src.id)),\n ...(req.sources ?? []),\n ];\n assertSnapSourceIds(sources);\n const wantsGeometry = snapSourcesFor(sources, req.gesture).some((src) => src.roles.includes('geometry'));\n const debug = s.debug?.() ?? undefined;\n const reachPx = s.reachPx ?? kitSettings.get('targets.snapPx') ?? DEFAULT_SNAP_PX;\n return sceneSession2d({\n req,\n scene: s.scene,\n boxes: s.boxes(),\n sources,\n ...(wantsGeometry ? { geometryAt: (press: Point, ids: readonly string[]) => ownGeometryAt(s.scene, press, ids, view?.scale ?? { x: 1, y: 1 }, reachPx) } : {}),\n view: () => viewRef.current,\n reachPx,\n ...(s.poseDescriptor ? { poseDescriptor: s.poseDescriptor } : {}),\n ...(s.originProjection ? { originProjection: s.originProjection } : {}),\n ...(debug ? { debug } : {}),\n store,\n });\n },\n }));\n return store;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqDA,IAAM,uBAA8C,CAClD,mBAAmB,GACnB;CAAE,GAAG,eAAe,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;CAAG,UAAU,CAAC,OAAO;AAAE,CACjE;;;AAIA,SAAS,aAAa,QAA+B,OAA0B,CAAC,GAAiB;CAC/F,oBAAoB,MAAM;CAC1B,MAAM,wBAAQ,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,MAAM,EAAE,EAAE,GAAG,GAAG,IAAI,CAAC;CAC3D,OAAO,CAAC,GAAG,QAAQ,GAAG,qBAAqB,QAAQ,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC;AAC5E;AAEA,SAAgB,iBACd,SACA,SAEA,OACkB;CAClB,MAAM,aAAa,UAAU,OAAO;CACpC,MAAM,cAAc,eAAe;CACnC,aAAa,sBAAsC,EAAE,MAAM,EAAE;CAE7D,aAAa,eAAwB,EACnC,QAAQ,QAAQ;EACd,MAAM,IAAI,WAAW;EACrB,MAAM,OAAO,QAAQ;EACrB,MAAM,OAAO,IAAI,IAAI,IAAI,IAAI;EAC7B,MAAM,UAAU,CACd,GAAG,aAAa,CAAC,GAAG,EAAE,SAAS,GAAI,EAAE,UAAU,KAAK,KAAK,CAAC,CAAE,GAAG,EAAE,IAAI,CAAC,CAAC,QAAQ,QAAQ,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC,GACxG,GAAI,IAAI,WAAW,CAAC,CACtB;EACA,oBAAoB,OAAO;EAC3B,MAAM,gBAAgB,eAAe,SAAS,IAAI,OAAO,CAAC,CAAC,MAAM,QAAQ,IAAI,MAAM,SAAS,UAAU,CAAC;EACvG,MAAM,QAAQ,EAAE,QAAQ,KAAK;EAC7B,MAAM,UAAU,EAAE,WAAW,YAAY,IAAI,gBAAgB,KAAK;EAClE,OAAO,eAAe;GACpB;GACA,OAAO,EAAE;GACT,OAAO,EAAE,MAAM;GACf;GACA,GAAI,gBAAgB,EAAE,aAAa,OAAc,QAA2B,cAAc,EAAE,OAAO,OAAO,KAAK,MAAM,SAAS;IAAE,GAAG;IAAG,GAAG;GAAE,GAAG,OAAO,EAAE,IAAI,CAAC;GAC5J,YAAY,QAAQ;GACpB;GACA,GAAI,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,IAAI,CAAC;GAC/D,GAAI,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,iBAAiB,IAAI,CAAC;GACrE,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;GACzB;EACF,CAAC;CACH,EACF,EAAE;CACF,OAAO;AACT"}
1
+ {"version":3,"file":"snap.js","names":[],"sources":["../../../src/canvas/deps/snap.ts"],"sourcesContent":["/**\n * `useSnapDepSource` — wires the `snap` dep whose `begin` every snapping\n * gesture runs: a session over the snap sources `session` names, writing its\n * marks to the outcome store this hook returns.\n */\nimport { useDepSource } from '@weasel-js/routing/react';\nimport { useKitSettings, useLatest } from '@weasel-js/react';\nimport type { DebugSink, WorldPoint } from '@weasel-js/routing';\nimport type { SnapDep } from 'interactions/actions/snapDep';\nimport { ownGeometryAt } from 'domains/paths/pathSnap/pathSnapSource';\nimport type { View } from 'core/viewport/view';\nimport type { Scene } from 'core/scene/types';\nimport type { DrawnBoxes } from 'interactions/actions/drawnBoxes';\nimport type { PoseDescriptor } from 'interactions/actions/resize/geometry';\nimport type { OriginProjection } from 'interactions/gestures/shared/originProjection';\nimport type { SnapOutcomeStore } from 'domains/snap/outcomeStore';\nimport type { SnapSourceRegistry } from 'domains/snap/registry';\nimport { assertSnapSourceIds, snapSourcesFor } from 'domains/snap/gather';\nimport { sceneSession2d } from 'domains/snap/sceneSession2d';\nimport { DEFAULT_SNAP_PX } from 'domains/snap/session2d';\nimport type { SnapReadoutDep } from 'domains/snap/readoutDep';\nimport { rotationSnapSource } from 'domains/snap/rotationSource';\nimport { pathSnapSource } from 'domains/paths/pathSnap/pathSnapSource';\nimport type { SnapSource } from 'domains/snap/types';\n\n/** What `begin` reads: the scene its probes come from and the sources it asks. */\nexport interface SnapSessionSources {\n scene: Scene<unknown, string, unknown>;\n /** The boxes the subject is drawn with, read when a session begins. */\n boxes: () => DrawnBoxes;\n /** `<SceneCanvas snap.sources>`, then the presets' `snapSources`. */\n sources: readonly SnapSource[];\n /** Sources `useSnapSource` adds, after `sources`. */\n registry?: SnapSourceRegistry;\n /** Ids of the canvas's default sources to leave out. */\n omit?: readonly string[];\n /** Overrides the kit setting `targets.snapPx`. */\n reachPx?: number;\n /** How a node's rotation is read, for angle targets. */\n poseDescriptor?: PoseDescriptor<unknown>;\n /** How a pose's origin is read, for the `origin` probe. */\n originProjection?: OriginProjection<unknown>;\n /** The canvas's debug sink, read when a session begins: each frame's\n * candidates are recorded into it. */\n debug?: () => DebugSink | null | undefined;\n}\n\n/** The sources every canvas asks after its own, unless `omit` names one:\n * quarter turns and other nodes' angles for a rotate, and other nodes'\n * anchors for a point gesture, under `pathSnapSource`'s own id, so a\n * consumer's `pathSnapSource()` takes its place. */\nconst DEFAULT_SNAP_SOURCES: readonly SnapSource[] = [\n rotationSnapSource(),\n { ...pathSnapSource({ only: ['anchor'] }), gestures: ['point'] },\n];\n\n/** `listed`, which must not repeat an id, then each default whose id is\n * neither listed nor in `omit`. */\nfunction withDefaults(listed: readonly SnapSource[], omit: readonly string[] = []): SnapSource[] {\n assertSnapSourceIds(listed);\n const taken = new Set([...listed.map((s) => s.id), ...omit]);\n return [...listed, ...DEFAULT_SNAP_SOURCES.filter((s) => !taken.has(s.id))];\n}\n\nexport function useSnapDepSource(\n viewRef: React.RefObject<View | null>,\n session: SnapSessionSources,\n /** The canvas's outcome store, which its readout layer draws. */\n store: SnapOutcomeStore,\n): SnapOutcomeStore {\n const sessionRef = useLatest(session);\n const kitSettings = useKitSettings();\n useDepSource('snapReadout', (): SnapReadoutDep => ({ store }));\n\n useDepSource('snap', (): SnapDep => ({\n begin: (req) => {\n const s = sessionRef.current;\n const view = viewRef.current;\n const omit = new Set(req.omit);\n const sources = [\n ...withDefaults([...s.sources, ...(s.registry?.list() ?? [])], s.omit).filter((src) => !omit.has(src.id)),\n ...(req.sources ?? []),\n ];\n assertSnapSourceIds(sources);\n const wantsGeometry = snapSourcesFor(sources, req.gesture).some((src) => src.roles.includes('geometry'));\n const debug = s.debug?.() ?? undefined;\n const reachPx = s.reachPx ?? kitSettings.get('targets.snapPx') ?? DEFAULT_SNAP_PX;\n return sceneSession2d({\n req,\n scene: s.scene,\n boxes: s.boxes(),\n sources,\n ...(wantsGeometry ? { geometryAt: (press: WorldPoint, ids: readonly string[]) => ownGeometryAt(s.scene, press, ids, view?.scale ?? { x: 1, y: 1 }, reachPx) } : {}),\n view: () => viewRef.current,\n reachPx,\n ...(s.poseDescriptor ? { poseDescriptor: s.poseDescriptor } : {}),\n ...(s.originProjection ? { originProjection: s.originProjection } : {}),\n ...(debug ? { debug } : {}),\n store,\n });\n },\n }));\n return store;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmDA,IAAM,uBAA8C,CAClD,mBAAmB,GACnB;CAAE,GAAG,eAAe,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;CAAG,UAAU,CAAC,OAAO;AAAE,CACjE;;;AAIA,SAAS,aAAa,QAA+B,OAA0B,CAAC,GAAiB;CAC/F,oBAAoB,MAAM;CAC1B,MAAM,wBAAQ,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,MAAM,EAAE,EAAE,GAAG,GAAG,IAAI,CAAC;CAC3D,OAAO,CAAC,GAAG,QAAQ,GAAG,qBAAqB,QAAQ,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC;AAC5E;AAEA,SAAgB,iBACd,SACA,SAEA,OACkB;CAClB,MAAM,aAAa,UAAU,OAAO;CACpC,MAAM,cAAc,eAAe;CACnC,aAAa,sBAAsC,EAAE,MAAM,EAAE;CAE7D,aAAa,eAAwB,EACnC,QAAQ,QAAQ;EACd,MAAM,IAAI,WAAW;EACrB,MAAM,OAAO,QAAQ;EACrB,MAAM,OAAO,IAAI,IAAI,IAAI,IAAI;EAC7B,MAAM,UAAU,CACd,GAAG,aAAa,CAAC,GAAG,EAAE,SAAS,GAAI,EAAE,UAAU,KAAK,KAAK,CAAC,CAAE,GAAG,EAAE,IAAI,CAAC,CAAC,QAAQ,QAAQ,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC,GACxG,GAAI,IAAI,WAAW,CAAC,CACtB;EACA,oBAAoB,OAAO;EAC3B,MAAM,gBAAgB,eAAe,SAAS,IAAI,OAAO,CAAC,CAAC,MAAM,QAAQ,IAAI,MAAM,SAAS,UAAU,CAAC;EACvG,MAAM,QAAQ,EAAE,QAAQ,KAAK;EAC7B,MAAM,UAAU,EAAE,WAAW,YAAY,IAAI,gBAAgB,KAAK;EAClE,OAAO,eAAe;GACpB;GACA,OAAO,EAAE;GACT,OAAO,EAAE,MAAM;GACf;GACA,GAAI,gBAAgB,EAAE,aAAa,OAAmB,QAA2B,cAAc,EAAE,OAAO,OAAO,KAAK,MAAM,SAAS;IAAE,GAAG;IAAG,GAAG;GAAE,GAAG,OAAO,EAAE,IAAI,CAAC;GACjK,YAAY,QAAQ;GACpB;GACA,GAAI,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,IAAI,CAAC;GAC/D,GAAI,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,iBAAiB,IAAI,CAAC;GACrE,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;GACzB;EACF,CAAC;CACH,EACF,EAAE;CACF,OAAO;AACT"}
@@ -4,11 +4,10 @@ import { useDepSource } from "@weasel-js/routing/react";
4
4
 
5
5
  //#region src/canvas/deps/textEdit.ts
6
6
  /**
7
- * `useTextEditDepSource` — wires the `textEdit` dep consumed by
8
- * `enterTextEditAction`. Kit-default implementation is a no-op stub for
9
- * `startEdit` plus an `isTextNode` that asks `isTextData`. Consumers wanting real text editing override the
10
- * dep via their own `useDepSource('textEdit', ...)` sourced from a
11
- * `useSceneTextEdit` instance.
7
+ * `useTextEditDepSource` — the `textEdit` dep `enterTextEditAction` reads when
8
+ * no editor answers it: a `startEdit` that does nothing, and an `isTextNode`
9
+ * that asks `isTextData`. `<SceneCanvas>`'s own editor registers over it
10
+ * (`SceneCanvas/defaultTextEditor.tsx`), and so does a host's.
12
11
  */
13
12
  function useTextEditDepSource(scene) {
14
13
  const sceneRef = useLatest(scene);
@@ -16,7 +15,7 @@ function useTextEditDepSource(scene) {
16
15
  const sc = sceneRef.current;
17
16
  return {
18
17
  startEdit(_id, _opts) {
19
- if (isDev()) console.warn("weasel textEditDep: startEdit called but no useTextEdit hook is mounted in SceneCanvas. Override the \"textEdit\" dep via useDepSource(\"textEdit\", ...) to enable in-place text editing.");
18
+ if (isDev()) console.warn("weasel textEditDep: startEdit called but this canvas has no text editor: it was given textEditor={false}, or a host useSceneTextEdit holds it without publishing the \"textEdit\" dep. Publish it with useDepSource(\"textEdit\", ...) from inside <SceneCanvas>.");
20
19
  },
21
20
  isTextNode(id) {
22
21
  return isTextData(sc.get(id)?.data);
@@ -1 +1 @@
1
- {"version":3,"file":"textEdit.js","names":[],"sources":["../../../src/canvas/deps/textEdit.ts"],"sourcesContent":["/**\n * `useTextEditDepSource` — wires the `textEdit` dep consumed by\n * `enterTextEditAction`. Kit-default implementation is a no-op stub for\n * `startEdit` plus an `isTextNode` that asks `isTextData`. Consumers wanting real text editing override the\n * dep via their own `useDepSource('textEdit', ...)` sourced from a\n * `useSceneTextEdit` instance.\n */\nimport { useDepSource } from '@weasel-js/routing/react';\nimport { useLatest, isDev } from '@weasel-js/react';\nimport type { TextEditDep } from 'interactions/actions/depSchema';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport { isTextData } from '@weasel-js/text';\n\nexport function useTextEditDepSource(\n scene: Scene<unknown, string, unknown>,\n): void {\n const sceneRef = useLatest(scene);\n\n useDepSource('textEdit', (): TextEditDep => {\n const sc = sceneRef.current;\n return {\n startEdit(_id: string, _opts?: { caret?: number | 'all' }) {\n if (isDev()) {\n console.warn(\n 'weasel textEditDep: startEdit called but no useTextEdit hook is mounted in SceneCanvas. ' +\n 'Override the \"textEdit\" dep via useDepSource(\"textEdit\", ...) to enable in-place text editing.',\n );\n }\n },\n isTextNode(id: string) {\n return isTextData(sc.get(id as NodeId)?.data);\n },\n };\n });\n}\n"],"mappings":";;;;;;;;;;;;AAaA,SAAgB,qBACd,OACM;CACN,MAAM,WAAW,UAAU,KAAK;CAEhC,aAAa,kBAA+B;EAC1C,MAAM,KAAK,SAAS;EACpB,OAAO;GACL,UAAU,KAAa,OAAoC;IACzD,IAAI,MAAM,GACR,QAAQ,KACN,4LAEF;GAEJ;GACA,WAAW,IAAY;IACrB,OAAO,WAAW,GAAG,IAAI,EAAY,CAAC,EAAE,IAAI;GAC9C;EACF;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"textEdit.js","names":[],"sources":["../../../src/canvas/deps/textEdit.ts"],"sourcesContent":["/**\n * `useTextEditDepSource` — the `textEdit` dep `enterTextEditAction` reads when\n * no editor answers it: a `startEdit` that does nothing, and an `isTextNode`\n * that asks `isTextData`. `<SceneCanvas>`'s own editor registers over it\n * (`SceneCanvas/defaultTextEditor.tsx`), and so does a host's.\n */\nimport { useDepSource } from '@weasel-js/routing/react';\nimport { useLatest, isDev } from '@weasel-js/react';\nimport type { TextEditDep } from 'interactions/actions/depSchema';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport { isTextData } from '@weasel-js/text';\n\nexport function useTextEditDepSource(\n scene: Scene<unknown, string, unknown>,\n): void {\n const sceneRef = useLatest(scene);\n\n useDepSource('textEdit', (): TextEditDep => {\n const sc = sceneRef.current;\n return {\n startEdit(_id: string, _opts?: { caret?: number | 'all' }) {\n if (isDev()) {\n console.warn(\n 'weasel textEditDep: startEdit called but this canvas has no text editor: it was given ' +\n 'textEditor={false}, or a host useSceneTextEdit holds it without publishing the \"textEdit\" dep. ' +\n 'Publish it with useDepSource(\"textEdit\", ...) from inside <SceneCanvas>.',\n );\n }\n },\n isTextNode(id: string) {\n return isTextData(sc.get(id as NodeId)?.data);\n },\n };\n });\n}\n"],"mappings":";;;;;;;;;;;AAYA,SAAgB,qBACd,OACM;CACN,MAAM,WAAW,UAAU,KAAK;CAEhC,aAAa,kBAA+B;EAC1C,MAAM,KAAK,SAAS;EACpB,OAAO;GACL,UAAU,KAAa,OAAoC;IACzD,IAAI,MAAM,GACR,QAAQ,KACN,mQAGF;GAEJ;GACA,WAAW,IAAY;IACrB,OAAO,WAAW,GAAG,IAAI,EAAY,CAAC,EAAE,IAAI;GAC9C;EACF;CACF,CAAC;AACH"}
@@ -5,6 +5,7 @@ import { resolveDerivedPath } from "../core/scene/derivedPath.js";
5
5
  import { inheritedPaintIn } from "../core/scene/inheritedPaint.js";
6
6
  import { nodeAsShown, shownLookup } from "../core/scene/nodeAsShown.js";
7
7
  import { definesFrame, derivedDepOf, effectivePose } from "../core/scene/effectivePose.js";
8
+ import { viewPoseAdapter } from "../core/scene/scrollOffsets.js";
8
9
  import { asNodeId } from "../core/scene/types.js";
9
10
  import { multiply, poseFrameInverseOf, poseFrameOf } from "@weasel-js/geom";
10
11
 
@@ -41,12 +42,13 @@ function sceneOverridePathOf(scene, toPose) {
41
42
  /**
42
43
  * `(node) => the pose it is painted at`: the slot's `toPose` of the node as the scene shows
43
44
  * it if it has one, else the scene's effective pose, folded through the parent chain when
44
- * the scene's composition makes a stored pose local to its container.
45
+ * the scene's composition makes a stored pose local to its container, and through each
46
+ * container's scroll offset.
45
47
  */
46
48
  function scenePaintedPoseOf(scene, toPose) {
47
49
  const local = toPose ? sceneShownToPose(scene, toPose) : (node) => effectivePose(scene, node);
48
50
  if (!composesFrames(scene.composition)) return local;
49
- const chain = {
51
+ const chain = viewPoseAdapter(scene, {
50
52
  getPose: (id) => {
51
53
  const n = scene.get(asNodeId(id));
52
54
  return n ? local(n) : void 0;
@@ -56,7 +58,7 @@ function scenePaintedPoseOf(scene, toPose) {
56
58
  const n = scene.get(asNodeId(id));
57
59
  return n === void 0 || definesFrame(n);
58
60
  }
59
- };
61
+ });
60
62
  return (node) => composeWorldPose(chain, node.id, scene.composition.compose);
61
63
  }
62
64
  /**
@@ -104,6 +106,9 @@ var SlotDep = class {
104
106
  get inherited() {
105
107
  return inheritedPaintIn(this.ctx.scene, this.node);
106
108
  }
109
+ get children() {
110
+ return this.ctx.childrenOf(this.node.id).map(this.ctx.lookup);
111
+ }
107
112
  };
108
113
  /** Whether something outside `node`'s data says what path it shows: it derives one, or a
109
114
  * pose override carries one. The gate both scene walks check before resolving a path. */
@@ -1 +1 @@
1
- {"version":3,"file":"derivedPath.js","names":[],"sources":["../../src/canvas/derivedPath.ts"],"sourcesContent":["/**\n * The render walk's half of derived paths: resolving one against a scene, and\n * handing it to the painter.\n *\n * The resolver itself lives in `core/scene/derivedPath.ts`, beside\n * `derivedPose` — a *pose* can derive from a dependency's path, so\n * `effectivePose` has to be able to reach it.\n */\nimport type { DerivedDep, Node, NodeId, Scene } from 'core/scene/types';\nimport { multiply, poseFrameInverseOf, poseFrameOf, type Path } from '@weasel-js/geom';\nimport { asNodeId } from 'core/scene/types';\nimport { definesFrame, derivedDepOf, effectivePose } from 'core/scene/effectivePose';\nimport { composesFrames, composeWorldPose, type PoseAdapter } from 'core/scene/composeFrame';\nimport { resolveDerivedPath } from 'core/scene/derivedPath';\nimport { inheritedPaintIn, type InheritedPaint } from 'core/scene/inheritedPaint';\nimport { createNodeMemoScope, type NodeMemoScope } from 'core/scene/nodeMemo';\nimport { carryBoxPath, carryPathBy, pathAsPainted } from 'core/scene/depFrame';\nimport type { SceneViewDrawOne } from './NodeShape';\nimport type { DrawnBoundsScene } from './drawnBounds';\nimport { nodeAsShown, shownLookup } from 'core/scene/nodeAsShown';\n\nexport { resolveDerivedPath } from 'core/scene/derivedPath';\n\ntype ToPose<TData, TLayer extends string, TPose> = (node: Node<TData, TLayer, TPose>) => TPose;\n\n/** `node` as the scene shows it, its `pose` an override's or a derived one and its `data` an\n * override's: the stored node itself where they agree. */\nfunction shownNode<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n stored: Node<TData, TLayer, TPose>,\n): Node<TData, TLayer, TPose> {\n const node = nodeAsShown(scene.overrides, stored);\n const pose = effectivePose(scene, stored);\n return pose === node.pose ? node : { ...node, pose };\n}\n\n/** A slot's `toPose`, handed each node as the scene shows it, so a view drawn through one\n * shows a drag in flight and a rig's motion as every other view does. */\nexport function sceneShownToPose<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose: ToPose<TData, TLayer, TPose>,\n): ToPose<TData, TLayer, TPose> {\n return (node) => toPose(shownNode(scene, node));\n}\n\n/**\n * `(node) => the path its pose override shows it by`, in the frame the reader paints in: as\n * the override has it, or under a `toPose` carried from the box the scene shows the node at\n * to the box `toPose` answers.\n */\nfunction sceneOverridePathOf<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: ToPose<TData, TLayer, TPose>,\n): (node: Node<TData, TLayer, TPose>) => Path | undefined {\n if (toPose === undefined) return (node) => scene.overrides.read(node.id)?.path;\n return (node) => {\n const path = scene.overrides.read(node.id)?.path;\n if (path === undefined) return undefined;\n const shown = shownNode(scene, node);\n return carryBoxPath(path, shown.pose, toPose(shown));\n };\n}\n\n/**\n * `(node) => the pose it is painted at`: the slot's `toPose` of the node as the scene shows\n * it if it has one, else the scene's effective pose, folded through the parent chain when\n * the scene's composition makes a stored pose local to its container.\n */\nexport function scenePaintedPoseOf<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): (node: Node<TData, TLayer, TPose>) => TPose {\n const local = toPose\n ? sceneShownToPose(scene, toPose)\n : (node: Node<TData, TLayer, TPose>) => effectivePose(scene, node);\n if (!composesFrames(scene.composition)) return local;\n const chain: PoseAdapter<TPose> = {\n getPose: (id) => {\n const n = scene.get(asNodeId(id));\n return n ? local(n) : (undefined as unknown as TPose);\n },\n getParent: (id) => scene.get(asNodeId(id))?.parent ?? null,\n definesFrame: (id) => {\n const n = scene.get(asNodeId(id));\n return n === undefined || definesFrame(n);\n },\n };\n return (node) => composeWorldPose(chain, node.id, scene.composition.compose);\n}\n\n/**\n * `(id) => that node, the pose it is painted at, and the path it derives` —\n * resolved against the scene, so a dependency that is itself derived resolves\n * before it is read.\n *\n * A derived edge is drawn from these coordinates and must meet the nodes it\n * connects, so this reads the pose each one is painted at: see\n * {@link scenePaintedPoseOf}.\n */\nexport function sceneDepLookup<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): (id: NodeId) => DerivedDep<TPose> | undefined {\n const slot = memoSlotFor(toPose, composesFrames(scene.composition));\n if (slot === undefined) return (id) => derivedDepOf(scene, id);\n const ctx: SlotLookup<TPose> = {\n at: scenePaintedPoseOf(scene, toPose) as (node: unknown) => TPose,\n local: (toPose\n ? sceneShownToPose(scene, toPose)\n : (node: Node<TData, TLayer, TPose>) => effectivePose(scene, node)) as (node: unknown) => TPose,\n slot,\n shown: sceneOverridePathOf(scene, toPose) as (node: unknown) => Path | undefined,\n childrenOf: (id: NodeId) => scene.childrenOf(id),\n scene: shownLookup(scene) as never,\n lookup: (id: NodeId) => {\n const node = scene.get(id);\n return node === undefined ? undefined : new SlotDep(nodeAsShown(scene.overrides, node), ctx);\n },\n };\n return ctx.lookup;\n}\n\ninterface SlotLookup<TPose> {\n at: (node: unknown) => TPose;\n /** The pose the node is shown at in its own frame: the box its override path is drawn in. */\n local: (node: unknown) => TPose;\n slot: string | NodeMemoScope;\n /** The path a pose override shows a node by, where it has one. */\n shown: (node: unknown) => Path | undefined;\n childrenOf: (id: NodeId) => readonly NodeId[];\n lookup: (id: NodeId) => DerivedDep<TPose> | undefined;\n /** Where a node's `'inherit'` paint is looked up. */\n scene: { get(id: NodeId): Node<unknown, string, TPose> | undefined };\n}\n\n/** A class, not an object literal with a `get path()` — see `SceneDep` in\n * `core/scene/effectivePose.ts` for why. */\nclass SlotDep<TPose> implements DerivedDep<TPose> {\n readonly node: Node<unknown, string, TPose>;\n readonly pose: TPose;\n\n constructor(posed: unknown, private readonly ctx: SlotLookup<TPose>) {\n this.node = posed as Node<unknown, string, TPose>;\n this.pose = ctx.at(posed);\n }\n\n get path(): Path | null {\n const shown = this.ctx.shown(this.node);\n if (shown !== undefined) return pathAsPainted(shown, this.ctx.local(this.node), this.pose);\n return resolveDerivedPath(\n this.node as never, this.ctx.lookup, this.ctx.childrenOf, this.ctx.slot,\n );\n }\n\n get inherited(): InheritedPaint | undefined {\n return inheritedPaintIn(this.ctx.scene, this.node);\n }\n}\n\n/** Whether something outside `node`'s data says what path it shows: it derives one, or a\n * pose override carries one. The gate both scene walks check before resolving a path. */\nexport function showsComputedPath<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n node: { id: NodeId; dependsOn?: readonly NodeId[] | 'children' },\n): boolean {\n return node.dependsOn !== undefined || scene.overrides.read(node.id)?.path !== undefined;\n}\n\n/**\n * `(node) => the path it shows in place of its data's`: a pose override's `path`, else the\n * one it derives, read through {@link sceneDepLookup}. A reader painting through a `toPose`\n * is answered the override's path carried into the box its `toPose` answers.\n */\nexport function sceneDerivedPathOf<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): (node: Node<TData, TLayer, TPose>) => Path | null {\n const depOf = sceneDepLookup(scene, toPose);\n const slot = memoSlotFor(toPose, composesFrames(scene.composition));\n const childrenOf = (id: NodeId): readonly NodeId[] => scene.childrenOf(id);\n const derived = (node: Node<TData, TLayer, TPose>): Path | null =>\n resolveDerivedPath(node, depOf, childrenOf, slot);\n const overridePathOf = sceneOverridePathOf(scene, toPose);\n return (node) => overridePathOf(node) ?? derived(node);\n}\n\nconst toPoseScopes = new WeakMap<object, { local?: NodeMemoScope; world?: NodeMemoScope }>();\n\n/** Where one way of reading poses memoizes its paths, or `undefined` for the\n * scene's own slot: two readers painting one scene at different poses must\n * not serve each other's paths. Every reader composing stored poses shares a\n * slot; a `toPose` gets a scope that is collected with the function. */\nfunction memoSlotFor(\n toPose: object | undefined,\n composes: boolean,\n): string | NodeMemoScope | undefined {\n const frame = composes ? 'world' : 'local';\n if (toPose === undefined) return frame === 'world' ? 'kit:derivedPath:world' : undefined;\n let scopes = toPoseScopes.get(toPose);\n if (scopes === undefined) {\n scopes = {};\n toPoseScopes.set(toPose, scopes);\n }\n return (scopes[frame] ??= createNodeMemoScope());\n}\n\n/**\n * Wrap a `drawOne` so a node that derives its geometry, or whose pose override\n * carries a path, arrives at the painter with the resolved path. The painter has no scene handle and so cannot read\n * the dependencies' poses itself; both scene walks wrap here instead.\n *\n * A node that derives nothing passes the caller's `ctx` through untouched —\n * this runs per node per frame, and an added `{ derivedPath: null }` would be\n * an allocation per node for a field no painter reads.\n */\nexport function withDerivedPaths<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): SceneViewDrawOne<TData, TLayer, TPose> {\n const derivedPathOf = sceneDerivedPathOf(scene, toPose);\n const ownPoseOf = composesFrames(scene.composition)\n ? (toPose ? sceneShownToPose(scene, toPose) : (node: Node<TData, TLayer, TPose>) => effectivePose(scene, node))\n : null;\n return (node, pose, view, ctx) => {\n if (!showsComputedPath(scene, node)) return drawOne(node, pose, view, ctx);\n let path = derivedPathOf(node);\n if (path !== null && ownPoseOf !== null && scene.overrides.read(node.id)?.path === undefined) {\n path = withoutInheritedFrame(path, pose, ownPoseOf(node));\n }\n return drawOne(node, pose, view, { ...ctx, derivedPath: path });\n };\n}\n\n/**\n * A derived path is drawn from its dependencies' painted poses, so it is already where it\n * shows; but the pose rotation the walk wraps every node in is `painted`'s, which carries its\n * containers' turns as well as its own. Carried back through what the containers add, the\n * wrap turns it by its own frame alone, as it does a root's.\n */\nfunction withoutInheritedFrame(path: Path, painted: unknown, own: unknown): Path {\n const undo = poseFrameInverseOf(painted);\n if (undo === null) return path;\n const box = painted as { x: number; y: number; width: number; height: number };\n const o = own as { rotation?: number; transform?: unknown } | null;\n const redo = poseFrameOf({ x: box.x, y: box.y, width: box.width, height: box.height, rotation: o?.rotation, transform: o?.transform });\n return carryPathBy(path, redo === null ? undo : multiply(undo, redo));\n}\n\nconst drawnScenes = new WeakMap<object, DrawnBoundsScene>();\n\n/** `scene` read as `drawnBoundsOf` reads one, each node that shows a computed\n * path answering it. One object per scene, so it can key a memo. */\nexport function drawnBoundsScene<TData, TLayer extends string, TPose>(scene: Scene<TData, TLayer, TPose>): DrawnBoundsScene {\n let held = drawnScenes.get(scene);\n if (held === undefined) {\n const pathOf = sceneDerivedPathOf(scene);\n const shown = shownLookup(scene);\n held = {\n get: (id) => shown.get(id) as never,\n childrenOf: (id) => scene.childrenOf(id),\n derivedPathOf: (id) => {\n const node = scene.get(id);\n return node !== undefined && showsComputedPath(scene, node) ? pathOf(node) : null;\n },\n };\n drawnScenes.set(scene, held);\n }\n return held;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"derivedPath.js","names":[],"sources":["../../src/canvas/derivedPath.ts"],"sourcesContent":["/**\n * The render walk's half of derived paths: resolving one against a scene, and\n * handing it to the painter.\n *\n * The resolver itself lives in `core/scene/derivedPath.ts`, beside\n * `derivedPose` — a *pose* can derive from a dependency's path, so\n * `effectivePose` has to be able to reach it.\n */\nimport type { DerivedDep, Node, NodeId, Scene } from 'core/scene/types';\nimport { multiply, poseFrameInverseOf, poseFrameOf, type Path } from '@weasel-js/geom';\nimport { asNodeId } from 'core/scene/types';\nimport { definesFrame, derivedDepOf, effectivePose } from 'core/scene/effectivePose';\nimport { composesFrames, composeWorldPose, type PoseAdapter } from 'core/scene/composeFrame';\nimport { viewPoseAdapter } from 'core/scene/scrollOffsets';\nimport { resolveDerivedPath } from 'core/scene/derivedPath';\nimport { inheritedPaintIn, type InheritedPaint } from 'core/scene/inheritedPaint';\nimport { createNodeMemoScope, type NodeMemoScope } from 'core/scene/nodeMemo';\nimport { carryBoxPath, carryPathBy, pathAsPainted } from 'core/scene/depFrame';\nimport type { SceneViewDrawOne } from './NodeShape';\nimport type { DrawnBoundsScene } from './drawnBounds';\nimport { nodeAsShown, shownLookup } from 'core/scene/nodeAsShown';\n\nexport { resolveDerivedPath } from 'core/scene/derivedPath';\n\ntype ToPose<TData, TLayer extends string, TPose> = (node: Node<TData, TLayer, TPose>) => TPose;\n\n/** `node` as the scene shows it, its `pose` an override's or a derived one and its `data` an\n * override's: the stored node itself where they agree. */\nfunction shownNode<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n stored: Node<TData, TLayer, TPose>,\n): Node<TData, TLayer, TPose> {\n const node = nodeAsShown(scene.overrides, stored);\n const pose = effectivePose(scene, stored);\n return pose === node.pose ? node : { ...node, pose };\n}\n\n/** A slot's `toPose`, handed each node as the scene shows it, so a view drawn through one\n * shows a drag in flight and a rig's motion as every other view does. */\nexport function sceneShownToPose<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose: ToPose<TData, TLayer, TPose>,\n): ToPose<TData, TLayer, TPose> {\n return (node) => toPose(shownNode(scene, node));\n}\n\n/**\n * `(node) => the path its pose override shows it by`, in the frame the reader paints in: as\n * the override has it, or under a `toPose` carried from the box the scene shows the node at\n * to the box `toPose` answers.\n */\nfunction sceneOverridePathOf<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: ToPose<TData, TLayer, TPose>,\n): (node: Node<TData, TLayer, TPose>) => Path | undefined {\n if (toPose === undefined) return (node) => scene.overrides.read(node.id)?.path;\n return (node) => {\n const path = scene.overrides.read(node.id)?.path;\n if (path === undefined) return undefined;\n const shown = shownNode(scene, node);\n return carryBoxPath(path, shown.pose, toPose(shown));\n };\n}\n\n/**\n * `(node) => the pose it is painted at`: the slot's `toPose` of the node as the scene shows\n * it if it has one, else the scene's effective pose, folded through the parent chain when\n * the scene's composition makes a stored pose local to its container, and through each\n * container's scroll offset.\n */\nexport function scenePaintedPoseOf<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): (node: Node<TData, TLayer, TPose>) => TPose {\n const local = toPose\n ? sceneShownToPose(scene, toPose)\n : (node: Node<TData, TLayer, TPose>) => effectivePose(scene, node);\n if (!composesFrames(scene.composition)) return local;\n const chain: PoseAdapter<TPose> = viewPoseAdapter(scene, {\n getPose: (id) => {\n const n = scene.get(asNodeId(id));\n return n ? local(n) : (undefined as unknown as TPose);\n },\n getParent: (id) => scene.get(asNodeId(id))?.parent ?? null,\n definesFrame: (id) => {\n const n = scene.get(asNodeId(id));\n return n === undefined || definesFrame(n);\n },\n } as PoseAdapter<TPose>);\n return (node) => composeWorldPose(chain, node.id, scene.composition.compose);\n}\n\n/**\n * `(id) => that node, the pose it is painted at, and the path it derives` —\n * resolved against the scene, so a dependency that is itself derived resolves\n * before it is read.\n *\n * A derived edge is drawn from these coordinates and must meet the nodes it\n * connects, so this reads the pose each one is painted at: see\n * {@link scenePaintedPoseOf}.\n */\nexport function sceneDepLookup<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): (id: NodeId) => DerivedDep<TPose> | undefined {\n const slot = memoSlotFor(toPose, composesFrames(scene.composition));\n if (slot === undefined) return (id) => derivedDepOf(scene, id);\n const ctx: SlotLookup<TPose> = {\n at: scenePaintedPoseOf(scene, toPose) as (node: unknown) => TPose,\n local: (toPose\n ? sceneShownToPose(scene, toPose)\n : (node: Node<TData, TLayer, TPose>) => effectivePose(scene, node)) as (node: unknown) => TPose,\n slot,\n shown: sceneOverridePathOf(scene, toPose) as (node: unknown) => Path | undefined,\n childrenOf: (id: NodeId) => scene.childrenOf(id),\n scene: shownLookup(scene) as never,\n lookup: (id: NodeId) => {\n const node = scene.get(id);\n return node === undefined ? undefined : new SlotDep(nodeAsShown(scene.overrides, node), ctx);\n },\n };\n return ctx.lookup;\n}\n\ninterface SlotLookup<TPose> {\n at: (node: unknown) => TPose;\n /** The pose the node is shown at in its own frame: the box its override path is drawn in. */\n local: (node: unknown) => TPose;\n slot: string | NodeMemoScope;\n /** The path a pose override shows a node by, where it has one. */\n shown: (node: unknown) => Path | undefined;\n childrenOf: (id: NodeId) => readonly NodeId[];\n lookup: (id: NodeId) => DerivedDep<TPose> | undefined;\n /** Where a node's `'inherit'` paint is looked up. */\n scene: { get(id: NodeId): Node<unknown, string, TPose> | undefined };\n}\n\n/** A class, not an object literal with a `get path()` — see `SceneDep` in\n * `core/scene/effectivePose.ts` for why. */\nclass SlotDep<TPose> implements DerivedDep<TPose> {\n readonly node: Node<unknown, string, TPose>;\n readonly pose: TPose;\n\n constructor(posed: unknown, private readonly ctx: SlotLookup<TPose>) {\n this.node = posed as Node<unknown, string, TPose>;\n this.pose = ctx.at(posed);\n }\n\n get path(): Path | null {\n const shown = this.ctx.shown(this.node);\n if (shown !== undefined) return pathAsPainted(shown, this.ctx.local(this.node), this.pose);\n return resolveDerivedPath(\n this.node as never, this.ctx.lookup, this.ctx.childrenOf, this.ctx.slot,\n );\n }\n\n get inherited(): InheritedPaint | undefined {\n return inheritedPaintIn(this.ctx.scene, this.node);\n }\n\n // Every pose this lookup answers is the painted one, so a child needs no rebase.\n get children(): readonly (DerivedDep<TPose> | undefined)[] {\n return this.ctx.childrenOf(this.node.id).map(this.ctx.lookup);\n }\n}\n\n/** Whether something outside `node`'s data says what path it shows: it derives one, or a\n * pose override carries one. The gate both scene walks check before resolving a path. */\nexport function showsComputedPath<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n node: { id: NodeId; dependsOn?: readonly NodeId[] | 'children' },\n): boolean {\n return node.dependsOn !== undefined || scene.overrides.read(node.id)?.path !== undefined;\n}\n\n/**\n * `(node) => the path it shows in place of its data's`: a pose override's `path`, else the\n * one it derives, read through {@link sceneDepLookup}. A reader painting through a `toPose`\n * is answered the override's path carried into the box its `toPose` answers.\n */\nexport function sceneDerivedPathOf<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): (node: Node<TData, TLayer, TPose>) => Path | null {\n const depOf = sceneDepLookup(scene, toPose);\n const slot = memoSlotFor(toPose, composesFrames(scene.composition));\n const childrenOf = (id: NodeId): readonly NodeId[] => scene.childrenOf(id);\n const derived = (node: Node<TData, TLayer, TPose>): Path | null =>\n resolveDerivedPath(node, depOf, childrenOf, slot);\n const overridePathOf = sceneOverridePathOf(scene, toPose);\n return (node) => overridePathOf(node) ?? derived(node);\n}\n\nconst toPoseScopes = new WeakMap<object, { local?: NodeMemoScope; world?: NodeMemoScope }>();\n\n/** Where one way of reading poses memoizes its paths, or `undefined` for the\n * scene's own slot: two readers painting one scene at different poses must\n * not serve each other's paths. Every reader composing stored poses shares a\n * slot; a `toPose` gets a scope that is collected with the function. */\nfunction memoSlotFor(\n toPose: object | undefined,\n composes: boolean,\n): string | NodeMemoScope | undefined {\n const frame = composes ? 'world' : 'local';\n if (toPose === undefined) return frame === 'world' ? 'kit:derivedPath:world' : undefined;\n let scopes = toPoseScopes.get(toPose);\n if (scopes === undefined) {\n scopes = {};\n toPoseScopes.set(toPose, scopes);\n }\n return (scopes[frame] ??= createNodeMemoScope());\n}\n\n/**\n * Wrap a `drawOne` so a node that derives its geometry, or whose pose override\n * carries a path, arrives at the painter with the resolved path. The painter has no scene handle and so cannot read\n * the dependencies' poses itself; both scene walks wrap here instead.\n *\n * A node that derives nothing passes the caller's `ctx` through untouched —\n * this runs per node per frame, and an added `{ derivedPath: null }` would be\n * an allocation per node for a field no painter reads.\n */\nexport function withDerivedPaths<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): SceneViewDrawOne<TData, TLayer, TPose> {\n const derivedPathOf = sceneDerivedPathOf(scene, toPose);\n const ownPoseOf = composesFrames(scene.composition)\n ? (toPose ? sceneShownToPose(scene, toPose) : (node: Node<TData, TLayer, TPose>) => effectivePose(scene, node))\n : null;\n return (node, pose, view, ctx) => {\n if (!showsComputedPath(scene, node)) return drawOne(node, pose, view, ctx);\n let path = derivedPathOf(node);\n if (path !== null && ownPoseOf !== null && scene.overrides.read(node.id)?.path === undefined) {\n path = withoutInheritedFrame(path, pose, ownPoseOf(node));\n }\n return drawOne(node, pose, view, { ...ctx, derivedPath: path });\n };\n}\n\n/**\n * A derived path is drawn from its dependencies' painted poses, so it is already where it\n * shows; but the pose rotation the walk wraps every node in is `painted`'s, which carries its\n * containers' turns as well as its own. Carried back through what the containers add, the\n * wrap turns it by its own frame alone, as it does a root's.\n */\nfunction withoutInheritedFrame(path: Path, painted: unknown, own: unknown): Path {\n const undo = poseFrameInverseOf(painted);\n if (undo === null) return path;\n const box = painted as { x: number; y: number; width: number; height: number };\n const o = own as { rotation?: number; transform?: unknown } | null;\n const redo = poseFrameOf({ x: box.x, y: box.y, width: box.width, height: box.height, rotation: o?.rotation, transform: o?.transform });\n return carryPathBy(path, redo === null ? undo : multiply(undo, redo));\n}\n\nconst drawnScenes = new WeakMap<object, DrawnBoundsScene>();\n\n/** `scene` read as `drawnBoundsOf` reads one, each node that shows a computed\n * path answering it. One object per scene, so it can key a memo. */\nexport function drawnBoundsScene<TData, TLayer extends string, TPose>(scene: Scene<TData, TLayer, TPose>): DrawnBoundsScene {\n let held = drawnScenes.get(scene);\n if (held === undefined) {\n const pathOf = sceneDerivedPathOf(scene);\n const shown = shownLookup(scene);\n held = {\n get: (id) => shown.get(id) as never,\n childrenOf: (id) => scene.childrenOf(id),\n derivedPathOf: (id) => {\n const node = scene.get(id);\n return node !== undefined && showsComputedPath(scene, node) ? pathOf(node) : null;\n },\n };\n drawnScenes.set(scene, held);\n }\n return held;\n}\n"],"mappings":"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"}
@@ -2,8 +2,8 @@
2
2
  /** The node a single-hit picker names under a world point, with its kind:
3
3
  * `'unknown'` when `nodeResolver` is absent or returns null. */
4
4
  function makeGetNodeAtPoint(pickBest, nodeResolver) {
5
- return (wx, wy, view) => {
6
- const id = pickBest(wx, wy, view);
5
+ return (world, view) => {
6
+ const id = pickBest(world, view);
7
7
  if (id == null) return null;
8
8
  return {
9
9
  id,
@@ -1 +1 @@
1
- {"version":3,"file":"getNodeAtPoint.js","names":[],"sources":["../../src/canvas/getNodeAtPoint.ts"],"sourcesContent":["import type { PickView } from './SceneCanvas/useSceneSelectTool';\n\n/** The hit record returned by a `getNodeAtPoint` function. */\nexport interface NodeAtPointHit {\n id: string;\n kind: string;\n}\n\n/** Resolves a node's routing kind. */\nexport type NodeResolver = (id: string) => { kind: string } | null;\n\n/** The node a single-hit picker names under a world point, with its kind:\n * `'unknown'` when `nodeResolver` is absent or returns null. */\nexport function makeGetNodeAtPoint(\n pickBest: (wx: number, wy: number, view?: PickView | null) => string | null,\n nodeResolver?: NodeResolver,\n): (wx: number, wy: number, view?: PickView | null) => NodeAtPointHit | null {\n return (wx: number, wy: number, view?: PickView | null): NodeAtPointHit | null => {\n const id = pickBest(wx, wy, view);\n if (id == null) return null;\n\n return { id, kind: nodeResolver?.(id)?.kind ?? 'unknown' };\n };\n}\n"],"mappings":";;;AAaA,SAAgB,mBACd,UACA,cAC2E;CAC3E,QAAQ,IAAY,IAAY,SAAkD;EAChF,MAAM,KAAK,SAAS,IAAI,IAAI,IAAI;EAChC,IAAI,MAAM,MAAM,OAAO;EAEvB,OAAO;GAAE;GAAI,MAAM,eAAe,EAAE,CAAC,EAAE,QAAQ;EAAU;CAC3D;AACF"}
1
+ {"version":3,"file":"getNodeAtPoint.js","names":[],"sources":["../../src/canvas/getNodeAtPoint.ts"],"sourcesContent":["import type { PickView } from './SceneCanvas/useSceneSelectTool';\nimport type { WorldPoint } from '@weasel-js/routing';\n\n/** The hit record returned by a `getNodeAtPoint` function. */\nexport interface NodeAtPointHit {\n id: string;\n kind: string;\n}\n\n/** Resolves a node's routing kind. */\nexport type NodeResolver = (id: string) => { kind: string } | null;\n\n/** The node a single-hit picker names under a world point, with its kind:\n * `'unknown'` when `nodeResolver` is absent or returns null. */\nexport function makeGetNodeAtPoint(\n pickBest: (world: WorldPoint, view?: PickView | null) => string | null,\n nodeResolver?: NodeResolver,\n): (world: WorldPoint, view?: PickView | null) => NodeAtPointHit | null {\n return (world: WorldPoint, view?: PickView | null): NodeAtPointHit | null => {\n const id = pickBest(world, view);\n if (id == null) return null;\n\n return { id, kind: nodeResolver?.(id)?.kind ?? 'unknown' };\n };\n}\n"],"mappings":";;;AAcA,SAAgB,mBACd,UACA,cACsE;CACtE,QAAQ,OAAmB,SAAkD;EAC3E,MAAM,KAAK,SAAS,OAAO,IAAI;EAC/B,IAAI,MAAM,MAAM,OAAO;EAEvB,OAAO;GAAE;GAAI,MAAM,eAAe,EAAE,CAAC,EAAE,QAAQ;EAAU;CAC3D;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"insertPreviewExtent.js","names":[],"sources":["../../src/canvas/insertPreviewExtent.ts"],"sourcesContent":["/**\n * The one answer to \"how big is the thing this in-flight insert is making\",\n * shared by the preview paint, the commit, and the gesture's reported bounds.\n *\n * The drag AABB alone is NOT the answer. `insertAction` hands over an\n * `extras` payload that can carry richer geometry than the drag rect, and\n * where it does, that geometry is the shape: a pencil that loops back to its\n * start produces a zero-area drag rect around a trail that swept the page.\n */\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { OngoingOverlay } from '@weasel-js/routing';\nimport { boundsOfPath, regularPolygonPath, starPath, type Path } from '@weasel-js/geom';\n\ntype Point = { x: number; y: number };\n\n/** The fields of an `insertPreview` overlay this needs. `canvas/deps/insert`\n * passes the equivalent from its own `(bounds, extras)` commit arguments. */\nexport interface InsertPreviewLike {\n shape: string;\n bounds: { x: number; y: number; width: number; height: number };\n extras: unknown;\n}\n\n/** Resolved preview geometry, in the terms the path builders take. */\nexport type InsertPreviewGeometry =\n | { kind: 'box' }\n | { kind: 'line'; a: Point; b: Point }\n | { kind: 'polygon'; center: Point; radius: number; sides: number; rotation: number }\n | {\n kind: 'star';\n center: Point;\n outerRadius: number;\n innerRadius: number;\n points: number;\n rotation: number;\n }\n | { kind: 'pencil'; samples: ReadonlyArray<Point> };\n\n/** An in-flight insert's shape, resolved from its drag rect and `extras`. */\nexport interface InsertPreviewExtent {\n /** The insert kind, verbatim from the caller. */\n shape: string;\n /** World-space AABB of `geometry` — the extent. */\n bounds: Bounds;\n geometry: InsertPreviewGeometry;\n}\n\n/** The `insertPreview` member of `OngoingOverlay`, which `insertAction` publishes during a drag-to-insert. */\nexport type InsertPreviewOverlay = Extract<OngoingOverlay, { kind: 'insertPreview' }>;\n\n/** Resolve an in-flight insert's geometry and world AABB. Uses the geometry in\n * `extras` where the shape carries it; an unknown shape falls back to its drag rect. */\nexport function insertPreviewExtent(ov: InsertPreviewLike): InsertPreviewExtent {\n const b = ov.bounds;\n const box = { x: b.x, y: b.y, width: b.width, height: b.height };\n\n switch (ov.shape) {\n case 'line': {\n const e = ov.extras as Partial<{ a: Point; b: Point }>;\n const a = e.a ?? { x: b.x, y: b.y };\n const b2 = e.b ?? { x: b.x + b.width, y: b.y + b.height };\n return { shape: ov.shape, bounds: aabbOf([a, b2]) ?? box, geometry: { kind: 'line', a, b: b2 } };\n }\n case 'polygon': {\n const e = ov.extras as Partial<{\n sides: number; rotation: number; center: Point; radius: number;\n }>;\n const center = e.center ?? { x: b.x + b.width / 2, y: b.y + b.height / 2 };\n const radius = e.radius ?? Math.min(b.width, b.height) / 2;\n const sides = Math.max(3, Math.floor(e.sides ?? 6));\n const rotation = e.rotation ?? 0;\n return {\n shape: ov.shape,\n bounds: boxOf(regularPolygonPath(center, radius, sides, rotation)),\n geometry: { kind: 'polygon', center, radius, sides, rotation },\n };\n }\n case 'star': {\n const e = ov.extras as Partial<{\n points: number; innerRadiusRatio: number; rotation: number;\n center: Point; outerRadius: number;\n }>;\n const center = e.center ?? { x: b.x + b.width / 2, y: b.y + b.height / 2 };\n const outerRadius = e.outerRadius ?? Math.min(b.width, b.height) / 2;\n const innerRadius = outerRadius * (e.innerRadiusRatio ?? 0.5);\n const points = Math.max(3, Math.floor(e.points ?? 5));\n const rotation = e.rotation ?? 0;\n return {\n shape: ov.shape,\n bounds: boxOf(starPath(center, outerRadius, points, innerRadius, rotation)),\n geometry: { kind: 'star', center, outerRadius, innerRadius, points, rotation },\n };\n }\n case 'pencil': {\n const e = ov.extras as Partial<{ samples: ReadonlyArray<Point> }>;\n const samples = e.samples ?? [];\n return {\n shape: ov.shape,\n bounds: aabbOf(samples) ?? box,\n geometry: { kind: 'pencil', samples },\n };\n }\n default:\n return { shape: ov.shape, bounds: box, geometry: { kind: 'box' } };\n }\n}\n\n/** A radial shape's extent is the box of the shape it makes, as the commit stores it. */\nfunction boxOf(path: Path): Bounds {\n const { x, y, width, height } = boundsOfPath(path);\n return { x, y, width, height };\n}\n\nfunction aabbOf(pts: ReadonlyArray<Point>): Bounds | null {\n if (pts.length === 0) return null;\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const p of pts) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n"],"mappings":";;;;;AAoDA,SAAgB,oBAAoB,IAA4C;CAC9E,MAAM,IAAI,GAAG;CACb,MAAM,MAAM;EAAE,GAAG,EAAE;EAAG,GAAG,EAAE;EAAG,OAAO,EAAE;EAAO,QAAQ,EAAE;CAAO;CAE/D,QAAQ,GAAG,OAAX;EACE,KAAK,QAAQ;GACX,MAAM,IAAI,GAAG;GACb,MAAM,IAAI,EAAE,KAAK;IAAE,GAAG,EAAE;IAAG,GAAG,EAAE;GAAE;GAClC,MAAM,KAAK,EAAE,KAAK;IAAE,GAAG,EAAE,IAAI,EAAE;IAAO,GAAG,EAAE,IAAI,EAAE;GAAO;GACxD,OAAO;IAAE,OAAO,GAAG;IAAO,QAAQ,OAAO,CAAC,GAAG,EAAE,CAAC,KAAK;IAAK,UAAU;KAAE,MAAM;KAAQ;KAAG,GAAG;IAAG;GAAE;EACjG;EACA,KAAK,WAAW;GACd,MAAM,IAAI,GAAG;GAGb,MAAM,SAAS,EAAE,UAAU;IAAE,GAAG,EAAE,IAAI,EAAE,QAAQ;IAAG,GAAG,EAAE,IAAI,EAAE,SAAS;GAAE;GACzE,MAAM,SAAS,EAAE,UAAU,KAAK,IAAI,EAAE,OAAO,EAAE,MAAM,IAAI;GACzD,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,EAAE,SAAS,CAAC,CAAC;GAClD,MAAM,WAAW,EAAE,YAAY;GAC/B,OAAO;IACL,OAAO,GAAG;IACV,QAAQ,MAAM,mBAAmB,QAAQ,QAAQ,OAAO,QAAQ,CAAC;IACjE,UAAU;KAAE,MAAM;KAAW;KAAQ;KAAQ;KAAO;IAAS;GAC/D;EACF;EACA,KAAK,QAAQ;GACX,MAAM,IAAI,GAAG;GAIb,MAAM,SAAS,EAAE,UAAU;IAAE,GAAG,EAAE,IAAI,EAAE,QAAQ;IAAG,GAAG,EAAE,IAAI,EAAE,SAAS;GAAE;GACzE,MAAM,cAAc,EAAE,eAAe,KAAK,IAAI,EAAE,OAAO,EAAE,MAAM,IAAI;GACnE,MAAM,cAAc,eAAe,EAAE,oBAAoB;GACzD,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM,EAAE,UAAU,CAAC,CAAC;GACpD,MAAM,WAAW,EAAE,YAAY;GAC/B,OAAO;IACL,OAAO,GAAG;IACV,QAAQ,MAAM,SAAS,QAAQ,aAAa,QAAQ,aAAa,QAAQ,CAAC;IAC1E,UAAU;KAAE,MAAM;KAAQ;KAAQ;KAAa;KAAa;KAAQ;IAAS;GAC/E;EACF;EACA,KAAK,UAAU;GAEb,MAAM,UADI,GAAG,OACK,WAAW,CAAC;GAC9B,OAAO;IACL,OAAO,GAAG;IACV,QAAQ,OAAO,OAAO,KAAK;IAC3B,UAAU;KAAE,MAAM;KAAU;IAAQ;GACtC;EACF;EACA,SACE,OAAO;GAAE,OAAO,GAAG;GAAO,QAAQ;GAAK,UAAU,EAAE,MAAM,MAAM;EAAE;CACrE;AACF;;AAGA,SAAS,MAAM,MAAoB;CACjC,MAAM,EAAE,GAAG,GAAG,OAAO,WAAW,aAAa,IAAI;CACjD,OAAO;EAAE;EAAG;EAAG;EAAO;CAAO;AAC/B;AAEA,SAAS,OAAO,KAA0C;CACxD,IAAI,IAAI,WAAW,GAAG,OAAO;CAC7B,IAAI,OAAO,UAAU,OAAO,UAAU,OAAO,WAAW,OAAO;CAC/D,KAAK,MAAM,KAAK,KAAK;EACnB,IAAI,EAAE,IAAI,MAAM,OAAO,EAAE;EACzB,IAAI,EAAE,IAAI,MAAM,OAAO,EAAE;EACzB,IAAI,EAAE,IAAI,MAAM,OAAO,EAAE;EACzB,IAAI,EAAE,IAAI,MAAM,OAAO,EAAE;CAC3B;CACA,OAAO;EAAE,GAAG;EAAM,GAAG;EAAM,OAAO,OAAO;EAAM,QAAQ,OAAO;CAAK;AACrE"}
1
+ {"version":3,"file":"insertPreviewExtent.js","names":[],"sources":["../../src/canvas/insertPreviewExtent.ts"],"sourcesContent":["/**\n * The one answer to \"how big is the thing this in-flight insert is making\",\n * shared by the preview paint, the commit, and the gesture's reported bounds.\n *\n * The drag AABB alone is NOT the answer. `insertAction` hands over an\n * `extras` payload that can carry richer geometry than the drag rect, and\n * where it does, that geometry is the shape: a pencil that loops back to its\n * start produces a zero-area drag rect around a trail that swept the page.\n */\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { OngoingOverlay } from '@weasel-js/routing';\nimport { boundsOfPath, regularPolygonPath, starPath, type Path, type Point } from '@weasel-js/geom';\n\n/** The fields of an `insertPreview` overlay this needs. `canvas/deps/insert`\n * passes the equivalent from its own `(bounds, extras)` commit arguments. */\nexport interface InsertPreviewLike {\n shape: string;\n bounds: { x: number; y: number; width: number; height: number };\n extras: unknown;\n}\n\n/** Resolved preview geometry, in the terms the path builders take. */\nexport type InsertPreviewGeometry =\n | { kind: 'box' }\n | { kind: 'line'; a: Point; b: Point }\n | { kind: 'polygon'; center: Point; radius: number; sides: number; rotation: number }\n | {\n kind: 'star';\n center: Point;\n outerRadius: number;\n innerRadius: number;\n points: number;\n rotation: number;\n }\n | { kind: 'pencil'; samples: ReadonlyArray<Point> };\n\n/** An in-flight insert's shape, resolved from its drag rect and `extras`. */\nexport interface InsertPreviewExtent {\n /** The insert kind, verbatim from the caller. */\n shape: string;\n /** World-space AABB of `geometry` — the extent. */\n bounds: Bounds;\n geometry: InsertPreviewGeometry;\n}\n\n/** The `insertPreview` member of `OngoingOverlay`, which `insertAction` publishes during a drag-to-insert. */\nexport type InsertPreviewOverlay = Extract<OngoingOverlay, { kind: 'insertPreview' }>;\n\n/** Resolve an in-flight insert's geometry and world AABB. Uses the geometry in\n * `extras` where the shape carries it; an unknown shape falls back to its drag rect. */\nexport function insertPreviewExtent(ov: InsertPreviewLike): InsertPreviewExtent {\n const b = ov.bounds;\n const box = { x: b.x, y: b.y, width: b.width, height: b.height };\n\n switch (ov.shape) {\n case 'line': {\n const e = ov.extras as Partial<{ a: Point; b: Point }>;\n const a = e.a ?? { x: b.x, y: b.y };\n const b2 = e.b ?? { x: b.x + b.width, y: b.y + b.height };\n return { shape: ov.shape, bounds: aabbOf([a, b2]) ?? box, geometry: { kind: 'line', a, b: b2 } };\n }\n case 'polygon': {\n const e = ov.extras as Partial<{\n sides: number; rotation: number; center: Point; radius: number;\n }>;\n const center = e.center ?? { x: b.x + b.width / 2, y: b.y + b.height / 2 };\n const radius = e.radius ?? Math.min(b.width, b.height) / 2;\n const sides = Math.max(3, Math.floor(e.sides ?? 6));\n const rotation = e.rotation ?? 0;\n return {\n shape: ov.shape,\n bounds: boxOf(regularPolygonPath(center, radius, sides, rotation)),\n geometry: { kind: 'polygon', center, radius, sides, rotation },\n };\n }\n case 'star': {\n const e = ov.extras as Partial<{\n points: number; innerRadiusRatio: number; rotation: number;\n center: Point; outerRadius: number;\n }>;\n const center = e.center ?? { x: b.x + b.width / 2, y: b.y + b.height / 2 };\n const outerRadius = e.outerRadius ?? Math.min(b.width, b.height) / 2;\n const innerRadius = outerRadius * (e.innerRadiusRatio ?? 0.5);\n const points = Math.max(3, Math.floor(e.points ?? 5));\n const rotation = e.rotation ?? 0;\n return {\n shape: ov.shape,\n bounds: boxOf(starPath(center, outerRadius, points, innerRadius, rotation)),\n geometry: { kind: 'star', center, outerRadius, innerRadius, points, rotation },\n };\n }\n case 'pencil': {\n const e = ov.extras as Partial<{ samples: ReadonlyArray<Point> }>;\n const samples = e.samples ?? [];\n return {\n shape: ov.shape,\n bounds: aabbOf(samples) ?? box,\n geometry: { kind: 'pencil', samples },\n };\n }\n default:\n return { shape: ov.shape, bounds: box, geometry: { kind: 'box' } };\n }\n}\n\n/** A radial shape's extent is the box of the shape it makes, as the commit stores it. */\nfunction boxOf(path: Path): Bounds {\n const { x, y, width, height } = boundsOfPath(path);\n return { x, y, width, height };\n}\n\nfunction aabbOf(pts: ReadonlyArray<Point>): Bounds | null {\n if (pts.length === 0) return null;\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const p of pts) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n"],"mappings":";;;;;AAkDA,SAAgB,oBAAoB,IAA4C;CAC9E,MAAM,IAAI,GAAG;CACb,MAAM,MAAM;EAAE,GAAG,EAAE;EAAG,GAAG,EAAE;EAAG,OAAO,EAAE;EAAO,QAAQ,EAAE;CAAO;CAE/D,QAAQ,GAAG,OAAX;EACE,KAAK,QAAQ;GACX,MAAM,IAAI,GAAG;GACb,MAAM,IAAI,EAAE,KAAK;IAAE,GAAG,EAAE;IAAG,GAAG,EAAE;GAAE;GAClC,MAAM,KAAK,EAAE,KAAK;IAAE,GAAG,EAAE,IAAI,EAAE;IAAO,GAAG,EAAE,IAAI,EAAE;GAAO;GACxD,OAAO;IAAE,OAAO,GAAG;IAAO,QAAQ,OAAO,CAAC,GAAG,EAAE,CAAC,KAAK;IAAK,UAAU;KAAE,MAAM;KAAQ;KAAG,GAAG;IAAG;GAAE;EACjG;EACA,KAAK,WAAW;GACd,MAAM,IAAI,GAAG;GAGb,MAAM,SAAS,EAAE,UAAU;IAAE,GAAG,EAAE,IAAI,EAAE,QAAQ;IAAG,GAAG,EAAE,IAAI,EAAE,SAAS;GAAE;GACzE,MAAM,SAAS,EAAE,UAAU,KAAK,IAAI,EAAE,OAAO,EAAE,MAAM,IAAI;GACzD,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,EAAE,SAAS,CAAC,CAAC;GAClD,MAAM,WAAW,EAAE,YAAY;GAC/B,OAAO;IACL,OAAO,GAAG;IACV,QAAQ,MAAM,mBAAmB,QAAQ,QAAQ,OAAO,QAAQ,CAAC;IACjE,UAAU;KAAE,MAAM;KAAW;KAAQ;KAAQ;KAAO;IAAS;GAC/D;EACF;EACA,KAAK,QAAQ;GACX,MAAM,IAAI,GAAG;GAIb,MAAM,SAAS,EAAE,UAAU;IAAE,GAAG,EAAE,IAAI,EAAE,QAAQ;IAAG,GAAG,EAAE,IAAI,EAAE,SAAS;GAAE;GACzE,MAAM,cAAc,EAAE,eAAe,KAAK,IAAI,EAAE,OAAO,EAAE,MAAM,IAAI;GACnE,MAAM,cAAc,eAAe,EAAE,oBAAoB;GACzD,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM,EAAE,UAAU,CAAC,CAAC;GACpD,MAAM,WAAW,EAAE,YAAY;GAC/B,OAAO;IACL,OAAO,GAAG;IACV,QAAQ,MAAM,SAAS,QAAQ,aAAa,QAAQ,aAAa,QAAQ,CAAC;IAC1E,UAAU;KAAE,MAAM;KAAQ;KAAQ;KAAa;KAAa;KAAQ;IAAS;GAC/E;EACF;EACA,KAAK,UAAU;GAEb,MAAM,UADI,GAAG,OACK,WAAW,CAAC;GAC9B,OAAO;IACL,OAAO,GAAG;IACV,QAAQ,OAAO,OAAO,KAAK;IAC3B,UAAU;KAAE,MAAM;KAAU;IAAQ;GACtC;EACF;EACA,SACE,OAAO;GAAE,OAAO,GAAG;GAAO,QAAQ;GAAK,UAAU,EAAE,MAAM,MAAM;EAAE;CACrE;AACF;;AAGA,SAAS,MAAM,MAAoB;CACjC,MAAM,EAAE,GAAG,GAAG,OAAO,WAAW,aAAa,IAAI;CACjD,OAAO;EAAE;EAAG;EAAG;EAAO;CAAO;AAC/B;AAEA,SAAS,OAAO,KAA0C;CACxD,IAAI,IAAI,WAAW,GAAG,OAAO;CAC7B,IAAI,OAAO,UAAU,OAAO,UAAU,OAAO,WAAW,OAAO;CAC/D,KAAK,MAAM,KAAK,KAAK;EACnB,IAAI,EAAE,IAAI,MAAM,OAAO,EAAE;EACzB,IAAI,EAAE,IAAI,MAAM,OAAO,EAAE;EACzB,IAAI,EAAE,IAAI,MAAM,OAAO,EAAE;EACzB,IAAI,EAAE,IAAI,MAAM,OAAO,EAAE;CAC3B;CACA,OAAO;EAAE,GAAG;EAAM,GAAG;EAAM,OAAO,OAAO;EAAM,QAAQ,OAAO;CAAK;AACrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"layerSlots.js","names":[],"sources":["../../src/canvas/layerSlots.ts"],"sourcesContent":["import type { RenderLayer } from '../core/layers/render';\nimport type { SelectionOverlayLayerOpts } from 'features/selection/overlay';\nimport type { SceneSlotConfig } from './buildSceneLayer';\nimport type { PathEditingOverlayStyle } from 'features/paths/pathEditingOverlayLayer';\n\n/** Standard slot names — render in this canonical order.\n * `cellHighlight` is not an anchor for custom layers: it sits between the\n * grid and the scene, so anchor to one of those. */\n/** @internal */\nexport const STANDARD_SLOTS = [\n 'grid',\n 'cellHighlight',\n 'scene',\n 'selectionOverlay',\n] as const;\n\n/** Names of the slots `<Canvas>` supports out of the box (excluding the implicit cell-highlight overlay). */\nexport type StandardSlotName = Exclude<(typeof STANDARD_SLOTS)[number], 'cellHighlight'>;\n\n/** Custom layer entry — any key not in `STANDARD_SLOTS`. The presence of\n * `.layer` discriminates this from a slot config. */\nexport interface CustomLayerEntry {\n layer: RenderLayer<unknown>;\n /** Insert immediately after the named standard slot or another custom-layer key. */\n after?: StandardSlotName | (string & {});\n /** Insert immediately before the named standard slot or another custom-layer key. */\n before?: StandardSlotName | (string & {});\n}\n\nexport function isCustomEntry(v: unknown): v is CustomLayerEntry {\n return !!v && typeof v === 'object' && 'layer' in (v as Record<string, unknown>);\n}\n\n/** Selection-overlay slot config — passed through to `createSelectionOverlayLayer`,\n * minus the `getSelection`/`getPose` the canvas wires automatically and the\n * `resizeHandles` it takes from the hit-test, so the two cannot disagree. */\nexport type SelectionOverlaySlotConfig<TPose> = Omit<\n SelectionOverlayLayerOpts<TPose>,\n 'getSelection' | 'getPose' | 'resizeHandles'\n> & {\n /** Override the auto-wired pose lookup (overlay-aware → adapter fallback). */\n poseById?: (id: string) => TPose | null;\n};\n\n/** Path-edit overlay slot config: how `<SceneCanvas>` draws the chrome of the\n * path whose anchors are being edited. */\nexport interface PathEditingOverlaySlotConfig {\n /** Anchor and handle marker overrides. */\n style?: PathEditingOverlayStyle;\n}\n\n/** Per-slot config union. The key narrows it in practice. */\nexport type StandardSlotConfig<TNode extends { id: string }, TPose> =\n | SceneSlotConfig<TNode, TPose>\n | SelectionOverlaySlotConfig<TPose>\n | PathEditingOverlaySlotConfig;\n\n/** What may fill one of the canvas's named layer slots: a config the canvas\n * builds the layer from, a pre-built layer, or `null` to leave the slot\n * empty. */\nexport type LayerSlotValue<TNode extends { id: string }, TPose> =\n | StandardSlotConfig<TNode, TPose>\n | CustomLayerEntry\n | null;\n\n/** The canvas's render stack, as named slots. The standard slots (grid,\n * scene, selection overlay, cell highlight) fix where a layer sits in the\n * stack; scene and selection overlay can be configured, and every one can be\n * given a layer of your own or switched off. Further keys add custom layers.\n * `TSceneSlot` is what the scene slot accepts: `<SceneCanvas>` takes a\n * partial config and fills the rest from its defaults. */\nexport type LayersMap<\n TNode extends { id: string },\n TPose,\n TSceneSlot = SceneSlotConfig<TNode, TPose>,\n> = {\n /** Grid slot, beneath the scene. Takes a pre-built layer (`{ layer }`) —\n * e.g. `createGridLayer` from `@weasel-js/guides` — or `null`. */\n grid?: CustomLayerEntry | null;\n /** Scene slot: the config `<SceneCanvas>` builds its layers from, a\n * pre-built layer that paints the scene in their place, or `null`. A\n * pre-built layer gets no ghost of a node in flight, which needs `drawOne`. */\n scene?: TSceneSlot | CustomLayerEntry | null;\n /** Selection-overlay slot: the config `<SceneCanvas>` builds the layer\n * from, a pre-built layer that paints in its place, or `null` for no\n * selection chrome. */\n selectionOverlay?: SelectionOverlaySlotConfig<TPose> | CustomLayerEntry | null;\n /** Cell-highlight overlay slot, drawn immediately after the grid. Takes a\n * pre-built layer (`{ layer }`) — e.g. `createCellHighlightLayer` from\n * `@weasel-js/guides` — or `null`. */\n cellHighlight?: CustomLayerEntry | null;\n /** `<SceneCanvas>`'s anchor-editing overlay, above the selection overlay:\n * the config it builds the layer from, a pre-built layer, or `null`. */\n pathEditingOverlay?: PathEditingOverlaySlotConfig | CustomLayerEntry | null;\n} & {\n [customKey: string]: LayerSlotValue<TNode, TPose> | TSceneSlot | undefined;\n};\n\n/** The scene slot once built: its canvas layers, bottom first. Each `key` is\n * an anchor a custom layer can name (`scene`, or `scene:<layerId>`). */\nexport interface SceneSlotLayers {\n layers: ReadonlyArray<{ key: string; layer: RenderLayer<unknown> }>;\n}\n\n/** What `<Canvas>` composes: a {@link LayersMap} with every slot already a\n * layer. `<SceneCanvas>` builds one from its `layers` prop. */\nexport type CanvasLayers = {\n grid?: CustomLayerEntry | null;\n cellHighlight?: CustomLayerEntry | null;\n scene?: SceneSlotLayers | null;\n selectionOverlay?: CustomLayerEntry | null;\n} & {\n [customKey: string]: CustomLayerEntry | SceneSlotLayers | null | undefined;\n};\n\n/** The layers of `map` that are already built, in its key order: each\n * `{ layer }` entry and each `null`. A slot config is left out, for whoever\n * builds it to put back. */\nexport function builtLayersOf(map: Record<string, unknown>): Record<string, CustomLayerEntry | null> {\n const out: Record<string, CustomLayerEntry | null> = {};\n for (const [key, value] of Object.entries(map)) {\n if (value === null || isCustomEntry(value)) out[key] = value;\n }\n return out;\n}\n"],"mappings":";;;;;AASA,IAAa,iBAAiB;CAC5B;CACA;CACA;CACA;AACF;AAeA,SAAgB,cAAc,GAAmC;CAC/D,OAAO,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,WAAY;AACrD;;;;AAuFA,SAAgB,cAAc,KAAuE;CACnG,MAAM,MAA+C,CAAC;CACtD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAC3C,IAAI,UAAU,QAAQ,cAAc,KAAK,GAAG,IAAI,OAAO;CAEzD,OAAO;AACT"}
1
+ {"version":3,"file":"layerSlots.js","names":[],"sources":["../../src/canvas/layerSlots.ts"],"sourcesContent":["import type { RenderLayer } from '../core/layers/render';\nimport type { SelectionOverlayLayerOpts } from 'domains/selection/overlay';\nimport type { SceneSlotConfig } from './buildSceneLayer';\nimport type { PathEditingOverlayStyle } from 'domains/paths/pathEditingOverlayLayer';\n\n/** Standard slot names — render in this canonical order.\n * `cellHighlight` is not an anchor for custom layers: it sits between the\n * grid and the scene, so anchor to one of those. */\n/** @internal */\nexport const STANDARD_SLOTS = [\n 'grid',\n 'cellHighlight',\n 'scene',\n 'selectionOverlay',\n] as const;\n\n/** Names of the slots `<Canvas>` supports out of the box (excluding the implicit cell-highlight overlay). */\nexport type StandardSlotName = Exclude<(typeof STANDARD_SLOTS)[number], 'cellHighlight'>;\n\n/** Custom layer entry — any key not in `STANDARD_SLOTS`. The presence of\n * `.layer` discriminates this from a slot config. */\nexport interface CustomLayerEntry {\n layer: RenderLayer<unknown>;\n /** Insert immediately after the named standard slot or another custom-layer key. */\n after?: StandardSlotName | (string & {});\n /** Insert immediately before the named standard slot or another custom-layer key. */\n before?: StandardSlotName | (string & {});\n}\n\nexport function isCustomEntry(v: unknown): v is CustomLayerEntry {\n return !!v && typeof v === 'object' && 'layer' in (v as Record<string, unknown>);\n}\n\n/** Selection-overlay slot config — passed through to `createSelectionOverlayLayer`,\n * minus the `getSelection`/`getPose` the canvas wires automatically and the\n * `resizeHandles` it takes from the hit-test, so the two cannot disagree. */\nexport type SelectionOverlaySlotConfig<TPose> = Omit<\n SelectionOverlayLayerOpts<TPose>,\n 'getSelection' | 'getPose' | 'resizeHandles'\n> & {\n /** Override the auto-wired pose lookup (overlay-aware → adapter fallback). */\n poseById?: (id: string) => TPose | null;\n};\n\n/** Path-edit overlay slot config: how `<SceneCanvas>` draws the chrome of the\n * path whose anchors are being edited. */\nexport interface PathEditingOverlaySlotConfig {\n /** Anchor and handle marker overrides. */\n style?: PathEditingOverlayStyle;\n}\n\n/** Per-slot config union. The key narrows it in practice. */\nexport type StandardSlotConfig<TNode extends { id: string }, TPose> =\n | SceneSlotConfig<TNode, TPose>\n | SelectionOverlaySlotConfig<TPose>\n | PathEditingOverlaySlotConfig;\n\n/** What may fill one of the canvas's named layer slots: a config the canvas\n * builds the layer from, a pre-built layer, or `null` to leave the slot\n * empty. */\nexport type LayerSlotValue<TNode extends { id: string }, TPose> =\n | StandardSlotConfig<TNode, TPose>\n | CustomLayerEntry\n | null;\n\n/** The canvas's render stack, as named slots. The standard slots (grid,\n * scene, selection overlay, cell highlight) fix where a layer sits in the\n * stack; scene and selection overlay can be configured, and every one can be\n * given a layer of your own or switched off. Further keys add custom layers.\n * `TSceneSlot` is what the scene slot accepts: `<SceneCanvas>` takes a\n * partial config and fills the rest from its defaults. */\nexport type LayersMap<\n TNode extends { id: string },\n TPose,\n TSceneSlot = SceneSlotConfig<TNode, TPose>,\n> = {\n /** Grid slot, beneath the scene. Takes a pre-built layer (`{ layer }`) —\n * e.g. `createGridLayer` from `@weasel-js/guides` — or `null`. */\n grid?: CustomLayerEntry | null;\n /** Scene slot: the config `<SceneCanvas>` builds its layers from, a\n * pre-built layer that paints the scene in their place, or `null`. A\n * pre-built layer gets no ghost of a node in flight, which needs `drawOne`. */\n scene?: TSceneSlot | CustomLayerEntry | null;\n /** Selection-overlay slot: the config `<SceneCanvas>` builds the layer\n * from, a pre-built layer that paints in its place, or `null` for no\n * selection chrome. */\n selectionOverlay?: SelectionOverlaySlotConfig<TPose> | CustomLayerEntry | null;\n /** Cell-highlight overlay slot, drawn immediately after the grid. Takes a\n * pre-built layer (`{ layer }`) — e.g. `createCellHighlightLayer` from\n * `@weasel-js/guides` — or `null`. */\n cellHighlight?: CustomLayerEntry | null;\n /** `<SceneCanvas>`'s anchor-editing overlay, above the selection overlay:\n * the config it builds the layer from, a pre-built layer, or `null`. */\n pathEditingOverlay?: PathEditingOverlaySlotConfig | CustomLayerEntry | null;\n} & {\n [customKey: string]: LayerSlotValue<TNode, TPose> | TSceneSlot | undefined;\n};\n\n/** The scene slot once built: its canvas layers, bottom first. Each `key` is\n * an anchor a custom layer can name (`scene`, or `scene:<layerId>`). */\nexport interface SceneSlotLayers {\n layers: ReadonlyArray<{ key: string; layer: RenderLayer<unknown> }>;\n}\n\n/** What `<Canvas>` composes: a {@link LayersMap} with every slot already a\n * layer. `<SceneCanvas>` builds one from its `layers` prop. */\nexport type CanvasLayers = {\n grid?: CustomLayerEntry | null;\n cellHighlight?: CustomLayerEntry | null;\n scene?: SceneSlotLayers | null;\n selectionOverlay?: CustomLayerEntry | null;\n} & {\n [customKey: string]: CustomLayerEntry | SceneSlotLayers | null | undefined;\n};\n\n/** The layers of `map` that are already built, in its key order: each\n * `{ layer }` entry and each `null`. A slot config is left out, for whoever\n * builds it to put back. */\nexport function builtLayersOf(map: Record<string, unknown>): Record<string, CustomLayerEntry | null> {\n const out: Record<string, CustomLayerEntry | null> = {};\n for (const [key, value] of Object.entries(map)) {\n if (value === null || isCustomEntry(value)) out[key] = value;\n }\n return out;\n}\n"],"mappings":";;;;;AASA,IAAa,iBAAiB;CAC5B;CACA;CACA;CACA;AACF;AAeA,SAAgB,cAAc,GAAmC;CAC/D,OAAO,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,WAAY;AACrD;;;;AAuFA,SAAgB,cAAc,KAAuE;CACnG,MAAM,MAA+C,CAAC;CACtD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAC3C,IAAI,UAAU,QAAQ,cAAc,KAAK,GAAG,IAAI,OAAO;CAEzD,OAAO;AACT"}
@@ -1,6 +1,6 @@
1
1
  import { paintsPose } from "./poseBox.js";
2
2
  import { OVERLAY_ROLE_STROKES } from "../overlayRoleStrokes.js";
3
- import { measureEndsOf } from "../../features/measure/measurement.js";
3
+ import { measureEndsOf } from "../../domains/measure/measurement.js";
4
4
  import { polylineFromPoints } from "@weasel-js/geom";
5
5
 
6
6
  //#region src/canvas/nodeShapes/measurePainter.ts
@@ -1 +1 @@
1
- {"version":3,"file":"measurePainter.js","names":[],"sources":["../../../src/canvas/nodeShapes/measurePainter.ts"],"sourcesContent":["import { polylineFromPoints } from '@weasel-js/geom';\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport type { NodeShapeEntry } from 'canvas/NodeShape';\nimport { OVERLAY_ROLE_STROKES } from 'canvas/overlayRoleStrokes';\nimport { measureEndsOf, type MeasurePoint } from 'features/measure/measurement';\nimport { paintsPose } from './poseBox';\n\n/** Screen-px half-length of the tick across each end of a measurement. */\nexport const MEASURE_TICK_PX = 5;\n\n/**\n * A measurement's line and a tick across each end, as the measure painter\n * and the measurements layer draw it. `perPx` is world units per screen pixel, so the\n * line and its ticks keep their screen size at any zoom.\n */\nexport function measureCommands(start: MeasurePoint, end: MeasurePoint, perPx: number): DrawCommand[] {\n const stroke = { ...OVERLAY_ROLE_STROKES['measure'], width: { px: 1 } };\n const len = Math.hypot(end.x - start.x, end.y - start.y);\n // The ticks run across the line; with no length yet they stand upright.\n const nx = len > 0 ? -(end.y - start.y) / len : 0;\n const ny = len > 0 ? (end.x - start.x) / len : 1;\n const half = MEASURE_TICK_PX * perPx;\n const tick = (p: MeasurePoint): DrawCommand => ({\n kind: 'path',\n path: polylineFromPoints([{ x: p.x - nx * half, y: p.y - ny * half }, { x: p.x + nx * half, y: p.y + ny * half }]),\n stroke,\n });\n const out: DrawCommand[] = [tick(start), tick(end)];\n if (len > 0) out.unshift({ kind: 'path', path: polylineFromPoints([start, end]), stroke });\n return out;\n}\n\n/** Paints a measurement node — `data.measure`, in world units — in the\n * canvas's measure color. It has no silhouette: a measurement is not content\n * to pick. */\nexport const MEASURE_PAINTER: NodeShapeEntry = {\n id: 'kit:measure',\n matches: (node) => paintsPose(node.pose) && measureEndsOf(node) !== null,\n paint: (node, _pose, ctx) => {\n const ends = measureEndsOf(node);\n if (!ends) return [];\n const dpr = globalThis.devicePixelRatio || 1;\n return measureCommands(ends.start, ends.end, dpr / (ctx?.pixelScale ?? dpr));\n },\n};\n"],"mappings":";;;;;;;AAQA,IAAa,kBAAkB;;;;;;AAO/B,SAAgB,gBAAgB,OAAqB,KAAmB,OAA8B;CACpG,MAAM,SAAS;EAAE,GAAG,qBAAqB;EAAY,OAAO,EAAE,IAAI,EAAE;CAAE;CACtE,MAAM,MAAM,KAAK,MAAM,IAAI,IAAI,MAAM,GAAG,IAAI,IAAI,MAAM,CAAC;CAEvD,MAAM,KAAK,MAAM,IAAI,EAAE,IAAI,IAAI,MAAM,KAAK,MAAM;CAChD,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM;CAC/C,MAAM,OAAO,kBAAkB;CAC/B,MAAM,QAAQ,OAAkC;EAC9C,MAAM;EACN,MAAM,mBAAmB,CAAC;GAAE,GAAG,EAAE,IAAI,KAAK;GAAM,GAAG,EAAE,IAAI,KAAK;EAAK,GAAG;GAAE,GAAG,EAAE,IAAI,KAAK;GAAM,GAAG,EAAE,IAAI,KAAK;EAAK,CAAC,CAAC;EACjH;CACF;CACA,MAAM,MAAqB,CAAC,KAAK,KAAK,GAAG,KAAK,GAAG,CAAC;CAClD,IAAI,MAAM,GAAG,IAAI,QAAQ;EAAE,MAAM;EAAQ,MAAM,mBAAmB,CAAC,OAAO,GAAG,CAAC;EAAG;CAAO,CAAC;CACzF,OAAO;AACT;;;;AAKA,IAAa,kBAAkC;CAC7C,IAAI;CACJ,UAAU,SAAS,WAAW,KAAK,IAAI,KAAK,cAAc,IAAI,MAAM;CACpE,QAAQ,MAAM,OAAO,QAAQ;EAC3B,MAAM,OAAO,cAAc,IAAI;EAC/B,IAAI,CAAC,MAAM,OAAO,CAAC;EACnB,MAAM,MAAM,WAAW,oBAAoB;EAC3C,OAAO,gBAAgB,KAAK,OAAO,KAAK,KAAK,OAAO,KAAK,cAAc,IAAI;CAC7E;AACF"}
1
+ {"version":3,"file":"measurePainter.js","names":[],"sources":["../../../src/canvas/nodeShapes/measurePainter.ts"],"sourcesContent":["import { polylineFromPoints } from '@weasel-js/geom';\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport type { NodeShapeEntry } from 'canvas/NodeShape';\nimport { OVERLAY_ROLE_STROKES } from 'canvas/overlayRoleStrokes';\nimport { measureEndsOf, type MeasurePoint } from 'domains/measure/measurement';\nimport { paintsPose } from './poseBox';\n\n/** Screen-px half-length of the tick across each end of a measurement. */\nexport const MEASURE_TICK_PX = 5;\n\n/**\n * A measurement's line and a tick across each end, as the measure painter\n * and the measurements layer draw it. `perPx` is world units per screen pixel, so the\n * line and its ticks keep their screen size at any zoom.\n */\nexport function measureCommands(start: MeasurePoint, end: MeasurePoint, perPx: number): DrawCommand[] {\n const stroke = { ...OVERLAY_ROLE_STROKES['measure'], width: { px: 1 } };\n const len = Math.hypot(end.x - start.x, end.y - start.y);\n // The ticks run across the line; with no length yet they stand upright.\n const nx = len > 0 ? -(end.y - start.y) / len : 0;\n const ny = len > 0 ? (end.x - start.x) / len : 1;\n const half = MEASURE_TICK_PX * perPx;\n const tick = (p: MeasurePoint): DrawCommand => ({\n kind: 'path',\n path: polylineFromPoints([{ x: p.x - nx * half, y: p.y - ny * half }, { x: p.x + nx * half, y: p.y + ny * half }]),\n stroke,\n });\n const out: DrawCommand[] = [tick(start), tick(end)];\n if (len > 0) out.unshift({ kind: 'path', path: polylineFromPoints([start, end]), stroke });\n return out;\n}\n\n/** Paints a measurement node — `data.measure`, in world units — in the\n * canvas's measure color. It has no silhouette: a measurement is not content\n * to pick. */\nexport const MEASURE_PAINTER: NodeShapeEntry = {\n id: 'kit:measure',\n matches: (node) => paintsPose(node.pose) && measureEndsOf(node) !== null,\n paint: (node, _pose, ctx) => {\n const ends = measureEndsOf(node);\n if (!ends) return [];\n const dpr = globalThis.devicePixelRatio || 1;\n return measureCommands(ends.start, ends.end, dpr / (ctx?.pixelScale ?? dpr));\n },\n};\n"],"mappings":";;;;;;;AAQA,IAAa,kBAAkB;;;;;;AAO/B,SAAgB,gBAAgB,OAAqB,KAAmB,OAA8B;CACpG,MAAM,SAAS;EAAE,GAAG,qBAAqB;EAAY,OAAO,EAAE,IAAI,EAAE;CAAE;CACtE,MAAM,MAAM,KAAK,MAAM,IAAI,IAAI,MAAM,GAAG,IAAI,IAAI,MAAM,CAAC;CAEvD,MAAM,KAAK,MAAM,IAAI,EAAE,IAAI,IAAI,MAAM,KAAK,MAAM;CAChD,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM;CAC/C,MAAM,OAAO,kBAAkB;CAC/B,MAAM,QAAQ,OAAkC;EAC9C,MAAM;EACN,MAAM,mBAAmB,CAAC;GAAE,GAAG,EAAE,IAAI,KAAK;GAAM,GAAG,EAAE,IAAI,KAAK;EAAK,GAAG;GAAE,GAAG,EAAE,IAAI,KAAK;GAAM,GAAG,EAAE,IAAI,KAAK;EAAK,CAAC,CAAC;EACjH;CACF;CACA,MAAM,MAAqB,CAAC,KAAK,KAAK,GAAG,KAAK,GAAG,CAAC;CAClD,IAAI,MAAM,GAAG,IAAI,QAAQ;EAAE,MAAM;EAAQ,MAAM,mBAAmB,CAAC,OAAO,GAAG,CAAC;EAAG;CAAO,CAAC;CACzF,OAAO;AACT;;;;AAKA,IAAa,kBAAkC;CAC7C,IAAI;CACJ,UAAU,SAAS,WAAW,KAAK,IAAI,KAAK,cAAc,IAAI,MAAM;CACpE,QAAQ,MAAM,OAAO,QAAQ;EAC3B,MAAM,OAAO,cAAc,IAAI;EAC/B,IAAI,CAAC,MAAM,OAAO,CAAC;EACnB,MAAM,MAAM,WAAW,oBAAoB;EAC3C,OAAO,gBAAgB,KAAK,OAAO,KAAK,KAAK,OAAO,KAAK,cAAc,IAAI;CAC7E;AACF"}
@@ -25,7 +25,7 @@ function strokedBounds(path, stroke, scale, screen) {
25
25
  if (align !== "inner") {
26
26
  const k = align === "outer" ? 2 : 1;
27
27
  const insets = strokeInsets(sized, width);
28
- const v = tessellateStroke(path, {
28
+ const mesh = tessellateStroke(path, {
29
29
  ...sized,
30
30
  width: width * k,
31
31
  align: "center",
@@ -34,8 +34,10 @@ function strokedBounds(path, stroke, scale, screen) {
34
34
  startInset: insetIn(insets.start, spaces.start, spaces.ribbon),
35
35
  endInset: insetIn(insets.end, spaces.end, spaces.ribbon),
36
36
  ...spaces.ribbon ? { metric: spaces.ribbon.metric } : {}
37
- }).vertices;
38
- for (let i = 0; i + 1 < v.length; i += 2) box.add(v[i], v[i + 1], 0);
37
+ });
38
+ const v = mesh.vertices;
39
+ const ox = mesh.origin?.x ?? 0, oy = mesh.origin?.y ?? 0;
40
+ for (let i = 0; i + 1 < v.length; i += 2) box.add(v[i] + ox, v[i + 1] + oy, 0);
39
41
  }
40
42
  for (const { entry, path: head, size } of markerHeads(path, sized, width, void 0, spaces)) {
41
43
  const b = boundsOfPath(head);
@@ -1 +1 @@
1
- {"version":3,"file":"strokedBounds.js","names":[],"sources":["../../../src/canvas/nodeShapes/strokedBounds.ts"],"sourcesContent":["import { boundsOfPath, type Path } from '@weasel-js/geom';\nimport { scaleVertexWidth, type Stroke } from '@weasel-js/paint';\nimport {\n markerHeads, resolveStrokeWidth, strokeInsets, tessellateStroke,\n type InsetLength, type ScreenSpace, type StrokeSpaces,\n} from '@weasel-js/stroke';\nimport { resolveStrokeLengths, type GlMat3, type StrokedPathCommand } from '@weasel-js/renderer';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { nodeMemo } from 'core/scene/nodeMemo';\nimport type { NodeInkCtx } from 'canvas/NodeShape';\nimport { strokeOutsetPerAxis } from './nodePaint';\n\n/**\n * The box `stroke` covers along `path`, from the ribbon the renderer draws:\n * joins, caps, dashes, and per-vertex widths as tessellated, and marker heads.\n * An inner stroke stays inside the path, and an outer one reaches as far out as\n * a centered stroke twice as wide. `null` when the stroke paints nothing.\n *\n * With `screen` (see `NodeInkCtx.screen`), each screen-sized part is built the\n * way the renderer builds it under that map, so a `{ px }` stroke is exact in\n * every direction; without, it is resolved at `scale`.\n */\nexport function strokedBounds(path: Path, stroke: Stroke, scale: number, screen?: ScreenMap): Bounds | null {\n const { sized, spaces } = screen ? onScreen(path, stroke, screen) : atScale(stroke, scale);\n const width = resolveStrokeWidth(sized.width ?? 1, 1);\n if (!(width > 0)) return null;\n const box = new Box();\n const align = stroke.align ?? 'center';\n if (align !== 'inner') {\n const k = align === 'outer' ? 2 : 1;\n const insets = strokeInsets(sized, width);\n const mesh = tessellateStroke(\n path,\n { ...sized, width: width * k, align: 'center', vertexWidths: stroke.vertexWidths?.map((w) => scaleVertexWidth(w, k)) },\n {\n startInset: insetIn(insets.start, spaces.start, spaces.ribbon),\n endInset: insetIn(insets.end, spaces.end, spaces.ribbon),\n ...(spaces.ribbon ? { metric: spaces.ribbon.metric } : {}),\n },\n );\n const v = mesh.vertices;\n for (let i = 0; i + 1 < v.length; i += 2) box.add(v[i]!, v[i + 1]!, 0);\n }\n for (const { entry, path: head, size } of markerHeads(path, sized, width, undefined, spaces)) {\n const b = boundsOfPath(head);\n const pad = entry.outline ? (entry.outline.width * size) / 2 : 0;\n box.add(b.x, b.y, pad);\n box.add(b.x + b.width, b.y + b.height, pad);\n }\n return box.bounds();\n}\n\n/** `[a, b, c, d]`: a frame's linear map to screen pixels. */\nexport type ScreenMap = readonly [number, number, number, number];\n\nfunction atScale(stroke: Stroke, scale: number): { sized: Stroke; spaces: StrokeSpaces } {\n return { sized: { ...stroke, width: resolveStrokeWidth(stroke.width ?? 1, scale) }, spaces: {} };\n}\n\nfunction onScreen(path: Path, stroke: Stroke, [a, b, c, d]: ScreenMap): { sized: Stroke; spaces: StrokeSpaces } {\n const transform = new Float32Array([a, b, 0, c, d, 0, 0, 0, 1]) as GlMat3;\n const { cmd, spaces } = resolveStrokeLengths(transform, { kind: 'path', path, stroke } as StrokedPathCommand);\n return { sized: cmd.stroke as Stroke, spaces };\n}\n\n/** `length`, measured in `head`'s space, as the tessellator reads it. */\nfunction insetIn(length: number, head: ScreenSpace | undefined, ribbon: ScreenSpace | undefined): InsetLength {\n return head?.metric === ribbon?.metric ? length : { length, metric: head?.metric ?? null };\n}\n\nclass Box {\n private x0 = Infinity;\n private y0 = Infinity;\n private x1 = -Infinity;\n private y1 = -Infinity;\n add(x: number, y: number, pad: number): void {\n this.x0 = Math.min(this.x0, x - pad);\n this.y0 = Math.min(this.y0, y - pad);\n this.x1 = Math.max(this.x1, x + pad);\n this.y1 = Math.max(this.y1, y + pad);\n }\n bounds(): Bounds | null {\n return this.x0 === Infinity ? null : { x: this.x0, y: this.y0, width: this.x1 - this.x0, height: this.y1 - this.y0 };\n }\n}\n\nconst DRAWN_SLOT = 'shape:drawn';\n\ninterface DrawnRecord {\n width: number;\n height: number;\n scale: number;\n screen: ScreenMap | undefined;\n /** Relative to the pose's top-left, so a move reuses it. */\n box: Bounds | null;\n}\n\n/** The pose box grown by a uniform stroke outset: exact for a rect or an\n * ellipse, whose stroke reaches the same distance past the box on every side. */\nexport function outsetPoseBox(pose: Bounds, stroke: Stroke | null, ctx: NodeInkCtx | undefined): Bounds {\n const box = normalized(pose);\n if (!stroke) return box;\n const r = strokeOutsetPerAxis(stroke, ctx);\n return { x: box.x - r.x, y: box.y - r.y, width: box.width + 2 * r.x, height: box.height + 2 * r.y };\n}\n\n/**\n * The pose box together with what `stroke` covers along `pathAt(pose)`,\n * memoized per node on the pose's size and the view scale: a drag that only\n * moves the node does not stroke it again.\n */\nexport function strokedPoseBox(\n node: { data?: unknown },\n pose: Bounds,\n stroke: Stroke | null,\n ctx: NodeInkCtx | undefined,\n pathAt: (pose: Bounds) => Path,\n): Bounds {\n const box = normalized(pose);\n if (stroke === null) return box;\n const scale = ctx?.scale ?? 1;\n const screen = ctx?.screen;\n const held = nodeMemo(node, DRAWN_SLOT, undefined, (): DrawnRecord => ({ width: NaN, height: NaN, scale: NaN, screen: undefined, box: null }));\n if (held.width !== pose.width || held.height !== pose.height || held.scale !== scale || !sameMap(held.screen, screen)) {\n const at = { x: 0, y: 0, width: pose.width, height: pose.height };\n held.width = pose.width;\n held.height = pose.height;\n held.scale = scale;\n held.screen = screen;\n held.box = strokedBounds(pathAt(at), stroke, scale, screen);\n }\n if (held.box === null) return box;\n const x0 = Math.min(box.x, pose.x + held.box.x);\n const y0 = Math.min(box.y, pose.y + held.box.y);\n const x1 = Math.max(box.x + box.width, pose.x + held.box.x + held.box.width);\n const y1 = Math.max(box.y + box.height, pose.y + held.box.y + held.box.height);\n return { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };\n}\n\nfunction sameMap(m: ScreenMap | undefined, n: ScreenMap | undefined): boolean {\n if (m === n) return true;\n return !!m && !!n && m[0] === n[0] && m[1] === n[1] && m[2] === n[2] && m[3] === n[3];\n}\n\nfunction normalized(pose: Bounds): Bounds {\n return {\n x: Math.min(pose.x, pose.x + pose.width),\n y: Math.min(pose.y, pose.y + pose.height),\n width: Math.abs(pose.width),\n height: Math.abs(pose.height),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"strokedBounds.js","names":[],"sources":["../../../src/canvas/nodeShapes/strokedBounds.ts"],"sourcesContent":["import { boundsOfPath, type Path } from '@weasel-js/geom';\nimport { scaleVertexWidth, type Stroke } from '@weasel-js/paint';\nimport {\n markerHeads, resolveStrokeWidth, strokeInsets, tessellateStroke,\n type InsetLength, type ScreenSpace, type StrokeSpaces,\n} from '@weasel-js/stroke';\nimport { resolveStrokeLengths, type GlMat3, type StrokedPathCommand } from '@weasel-js/renderer';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { nodeMemo } from 'core/scene/nodeMemo';\nimport type { NodeInkCtx } from 'canvas/NodeShape';\nimport { strokeOutsetPerAxis } from './nodePaint';\n\n/**\n * The box `stroke` covers along `path`, from the ribbon the renderer draws:\n * joins, caps, dashes, and per-vertex widths as tessellated, and marker heads.\n * An inner stroke stays inside the path, and an outer one reaches as far out as\n * a centered stroke twice as wide. `null` when the stroke paints nothing.\n *\n * With `screen` (see `NodeInkCtx.screen`), each screen-sized part is built the\n * way the renderer builds it under that map, so a `{ px }` stroke is exact in\n * every direction; without, it is resolved at `scale`.\n */\nexport function strokedBounds(path: Path, stroke: Stroke, scale: number, screen?: ScreenMap): Bounds | null {\n const { sized, spaces } = screen ? onScreen(path, stroke, screen) : atScale(stroke, scale);\n const width = resolveStrokeWidth(sized.width ?? 1, 1);\n if (!(width > 0)) return null;\n const box = new Box();\n const align = stroke.align ?? 'center';\n if (align !== 'inner') {\n const k = align === 'outer' ? 2 : 1;\n const insets = strokeInsets(sized, width);\n const mesh = tessellateStroke(\n path,\n { ...sized, width: width * k, align: 'center', vertexWidths: stroke.vertexWidths?.map((w) => scaleVertexWidth(w, k)) },\n {\n startInset: insetIn(insets.start, spaces.start, spaces.ribbon),\n endInset: insetIn(insets.end, spaces.end, spaces.ribbon),\n ...(spaces.ribbon ? { metric: spaces.ribbon.metric } : {}),\n },\n );\n const v = mesh.vertices;\n const ox = mesh.origin?.x ?? 0, oy = mesh.origin?.y ?? 0;\n for (let i = 0; i + 1 < v.length; i += 2) box.add(v[i]! + ox, v[i + 1]! + oy, 0);\n }\n for (const { entry, path: head, size } of markerHeads(path, sized, width, undefined, spaces)) {\n const b = boundsOfPath(head);\n const pad = entry.outline ? (entry.outline.width * size) / 2 : 0;\n box.add(b.x, b.y, pad);\n box.add(b.x + b.width, b.y + b.height, pad);\n }\n return box.bounds();\n}\n\n/** `[a, b, c, d]`: a frame's linear map to screen pixels. */\nexport type ScreenMap = readonly [number, number, number, number];\n\nfunction atScale(stroke: Stroke, scale: number): { sized: Stroke; spaces: StrokeSpaces } {\n return { sized: { ...stroke, width: resolveStrokeWidth(stroke.width ?? 1, scale) }, spaces: {} };\n}\n\nfunction onScreen(path: Path, stroke: Stroke, [a, b, c, d]: ScreenMap): { sized: Stroke; spaces: StrokeSpaces } {\n const transform = new Float32Array([a, b, 0, c, d, 0, 0, 0, 1]) as GlMat3;\n const { cmd, spaces } = resolveStrokeLengths(transform, { kind: 'path', path, stroke } as StrokedPathCommand);\n return { sized: cmd.stroke as Stroke, spaces };\n}\n\n/** `length`, measured in `head`'s space, as the tessellator reads it. */\nfunction insetIn(length: number, head: ScreenSpace | undefined, ribbon: ScreenSpace | undefined): InsetLength {\n return head?.metric === ribbon?.metric ? length : { length, metric: head?.metric ?? null };\n}\n\nclass Box {\n private x0 = Infinity;\n private y0 = Infinity;\n private x1 = -Infinity;\n private y1 = -Infinity;\n add(x: number, y: number, pad: number): void {\n this.x0 = Math.min(this.x0, x - pad);\n this.y0 = Math.min(this.y0, y - pad);\n this.x1 = Math.max(this.x1, x + pad);\n this.y1 = Math.max(this.y1, y + pad);\n }\n bounds(): Bounds | null {\n return this.x0 === Infinity ? null : { x: this.x0, y: this.y0, width: this.x1 - this.x0, height: this.y1 - this.y0 };\n }\n}\n\nconst DRAWN_SLOT = 'shape:drawn';\n\ninterface DrawnRecord {\n width: number;\n height: number;\n scale: number;\n screen: ScreenMap | undefined;\n /** Relative to the pose's top-left, so a move reuses it. */\n box: Bounds | null;\n}\n\n/** The pose box grown by a uniform stroke outset: exact for a rect or an\n * ellipse, whose stroke reaches the same distance past the box on every side. */\nexport function outsetPoseBox(pose: Bounds, stroke: Stroke | null, ctx: NodeInkCtx | undefined): Bounds {\n const box = normalized(pose);\n if (!stroke) return box;\n const r = strokeOutsetPerAxis(stroke, ctx);\n return { x: box.x - r.x, y: box.y - r.y, width: box.width + 2 * r.x, height: box.height + 2 * r.y };\n}\n\n/**\n * The pose box together with what `stroke` covers along `pathAt(pose)`,\n * memoized per node on the pose's size and the view scale: a drag that only\n * moves the node does not stroke it again.\n */\nexport function strokedPoseBox(\n node: { data?: unknown },\n pose: Bounds,\n stroke: Stroke | null,\n ctx: NodeInkCtx | undefined,\n pathAt: (pose: Bounds) => Path,\n): Bounds {\n const box = normalized(pose);\n if (stroke === null) return box;\n const scale = ctx?.scale ?? 1;\n const screen = ctx?.screen;\n const held = nodeMemo(node, DRAWN_SLOT, undefined, (): DrawnRecord => ({ width: NaN, height: NaN, scale: NaN, screen: undefined, box: null }));\n if (held.width !== pose.width || held.height !== pose.height || held.scale !== scale || !sameMap(held.screen, screen)) {\n const at = { x: 0, y: 0, width: pose.width, height: pose.height };\n held.width = pose.width;\n held.height = pose.height;\n held.scale = scale;\n held.screen = screen;\n held.box = strokedBounds(pathAt(at), stroke, scale, screen);\n }\n if (held.box === null) return box;\n const x0 = Math.min(box.x, pose.x + held.box.x);\n const y0 = Math.min(box.y, pose.y + held.box.y);\n const x1 = Math.max(box.x + box.width, pose.x + held.box.x + held.box.width);\n const y1 = Math.max(box.y + box.height, pose.y + held.box.y + held.box.height);\n return { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };\n}\n\nfunction sameMap(m: ScreenMap | undefined, n: ScreenMap | undefined): boolean {\n if (m === n) return true;\n return !!m && !!n && m[0] === n[0] && m[1] === n[1] && m[2] === n[2] && m[3] === n[3];\n}\n\nfunction normalized(pose: Bounds): Bounds {\n return {\n x: Math.min(pose.x, pose.x + pose.width),\n y: Math.min(pose.y, pose.y + pose.height),\n width: Math.abs(pose.width),\n height: Math.abs(pose.height),\n };\n}\n"],"mappings":"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"}
@@ -27,6 +27,12 @@ var OVERLAY_ROLE_STROKES = {
27
27
  paint: { color: "#d9480f" },
28
28
  width: 1.5
29
29
  },
30
+ /** What a dragged item would be dropped on. */
31
+ target: {
32
+ paint: { color: "#1f8fff" },
33
+ width: 1.5,
34
+ dash: [5, 3]
35
+ },
30
36
  /** Where a dragged item would land. */
31
37
  insert: {
32
38
  paint: { color: "#1f8fff" },
@@ -1 +1 @@
1
- {"version":3,"file":"overlayRoleStrokes.js","names":[],"sources":["../../src/canvas/overlayRoleStrokes.ts"],"sourcesContent":["import type { CommandPaint, CommandStroke } from '@weasel-js/paint';\n\n/** How each `polyline` overlay role reads. An action publishes the run and\n * the word; this table is the whole of the paint, for the dispatcher overlay\n * and for any tool previewing the same kind of run between gestures. */\nexport const OVERLAY_ROLE_STROKES: Readonly<Record<string, CommandStroke & { paint: CommandPaint }>> = {\n cut: { paint: { color: '#e23b3b' }, width: 1, dash: [6, 4] },\n connector: { paint: { color: '#7ba7c7' }, width: 2, dash: [4, 4] },\n falloff: { paint: { color: 'rgba(52, 120, 246, 0.28)' }, width: 10, cap: 'round', join: 'round' },\n measure: { paint: { color: '#1f8fff' }, width: 1 },\n lock: { paint: { color: '#d9480f' }, width: 1.5 },\n /** Where a dragged item would land. */\n insert: { paint: { color: '#1f8fff' }, width: 3, cap: 'round' },\n /** Where a dragged item is over but cannot land. */\n refused: { paint: { color: '#ff5d5d' }, width: 3, cap: 'round' },\n};\n"],"mappings":";;;;AAKA,IAAa,uBAA0F;CACrG,KAAK;EAAE,OAAO,EAAE,OAAO,UAAU;EAAG,OAAO;EAAG,MAAM,CAAC,GAAG,CAAC;CAAE;CAC3D,WAAW;EAAE,OAAO,EAAE,OAAO,UAAU;EAAG,OAAO;EAAG,MAAM,CAAC,GAAG,CAAC;CAAE;CACjE,SAAS;EAAE,OAAO,EAAE,OAAO,2BAA2B;EAAG,OAAO;EAAI,KAAK;EAAS,MAAM;CAAQ;CAChG,SAAS;EAAE,OAAO,EAAE,OAAO,UAAU;EAAG,OAAO;CAAE;CACjD,MAAM;EAAE,OAAO,EAAE,OAAO,UAAU;EAAG,OAAO;CAAI;;CAEhD,QAAQ;EAAE,OAAO,EAAE,OAAO,UAAU;EAAG,OAAO;EAAG,KAAK;CAAQ;;CAE9D,SAAS;EAAE,OAAO,EAAE,OAAO,UAAU;EAAG,OAAO;EAAG,KAAK;CAAQ;AACjE"}
1
+ {"version":3,"file":"overlayRoleStrokes.js","names":[],"sources":["../../src/canvas/overlayRoleStrokes.ts"],"sourcesContent":["import type { CommandPaint, CommandStroke } from '@weasel-js/paint';\n\n/** How each `polyline` overlay role reads. An action publishes the run and\n * the word; this table is the whole of the paint, for the dispatcher overlay\n * and for any tool previewing the same kind of run between gestures. */\nexport const OVERLAY_ROLE_STROKES: Readonly<Record<string, CommandStroke & { paint: CommandPaint }>> = {\n cut: { paint: { color: '#e23b3b' }, width: 1, dash: [6, 4] },\n connector: { paint: { color: '#7ba7c7' }, width: 2, dash: [4, 4] },\n falloff: { paint: { color: 'rgba(52, 120, 246, 0.28)' }, width: 10, cap: 'round', join: 'round' },\n measure: { paint: { color: '#1f8fff' }, width: 1 },\n lock: { paint: { color: '#d9480f' }, width: 1.5 },\n /** What a dragged item would be dropped on. */\n target: { paint: { color: '#1f8fff' }, width: 1.5, dash: [5, 3] },\n /** Where a dragged item would land. */\n insert: { paint: { color: '#1f8fff' }, width: 3, cap: 'round' },\n /** Where a dragged item is over but cannot land. */\n refused: { paint: { color: '#ff5d5d' }, width: 3, cap: 'round' },\n};\n"],"mappings":";;;;AAKA,IAAa,uBAA0F;CACrG,KAAK;EAAE,OAAO,EAAE,OAAO,UAAU;EAAG,OAAO;EAAG,MAAM,CAAC,GAAG,CAAC;CAAE;CAC3D,WAAW;EAAE,OAAO,EAAE,OAAO,UAAU;EAAG,OAAO;EAAG,MAAM,CAAC,GAAG,CAAC;CAAE;CACjE,SAAS;EAAE,OAAO,EAAE,OAAO,2BAA2B;EAAG,OAAO;EAAI,KAAK;EAAS,MAAM;CAAQ;CAChG,SAAS;EAAE,OAAO,EAAE,OAAO,UAAU;EAAG,OAAO;CAAE;CACjD,MAAM;EAAE,OAAO,EAAE,OAAO,UAAU;EAAG,OAAO;CAAI;;CAEhD,QAAQ;EAAE,OAAO,EAAE,OAAO,UAAU;EAAG,OAAO;EAAK,MAAM,CAAC,GAAG,CAAC;CAAE;;CAEhE,QAAQ;EAAE,OAAO,EAAE,OAAO,UAAU;EAAG,OAAO;EAAG,KAAK;CAAQ;;CAE9D,SAAS;EAAE,OAAO,EAAE,OAAO,UAAU;EAAG,OAAO;EAAG,KAAK;CAAQ;AACjE"}
@@ -6,7 +6,7 @@ import { scenePaintedPoseOf } from "../derivedPath.js";
6
6
  import { sceneParentsOf, sceneShownPathOf } from "../scenePickReads.js";
7
7
  import { nodeBroadBox } from "./nodeBroadBox.js";
8
8
  import { markerGeneration } from "@weasel-js/stroke";
9
- import { createBvh } from "@weasel-js/geom/nd";
9
+ import { createBvh, createSettledCache } from "@weasel-js/geom/nd";
10
10
 
11
11
  //#region src/canvas/pickIndex/scenePickIndex.ts
12
12
  /**
@@ -169,25 +169,23 @@ function current(scene, descriptor) {
169
169
  getNodeShapes();
170
170
  const version = scene.getVersion();
171
171
  const overrides = scene.overrides.getGeneration();
172
+ const scrolled = scene.scroll?.getGeneration() ?? 0;
172
173
  const memo = nodeMemoGeneration();
173
174
  const markers = markerGeneration();
174
175
  let perScene = CACHE.get(scene);
175
176
  if (perScene === void 0) CACHE.set(scene, perScene = /* @__PURE__ */ new WeakMap());
176
- const hit = perScene.get(descriptor);
177
+ let cache = perScene.get(descriptor);
178
+ if (cache === void 0) perScene.set(descriptor, cache = createSettledCache());
177
179
  const order = nodesAsShown(scene.overrides, scene.renderOrderNodes());
178
- if (hit && hit.version === version && hit.overrides === overrides && hit.memo === memo && hit.markers === markers) {
179
- if (hit.index === null) hit.index = build(scene, descriptor, order);
180
- else hit.index.rankBy(order);
181
- return hit.index;
182
- }
183
- perScene.set(descriptor, {
180
+ const index = cache.read([
184
181
  version,
185
182
  overrides,
183
+ scrolled,
186
184
  memo,
187
- markers,
188
- index: null
189
- });
190
- return null;
185
+ markers
186
+ ], () => build(scene, descriptor, order));
187
+ index?.rankBy(order);
188
+ return index;
191
189
  }
192
190
  /** What `PickSource.candidates` answers for a scene source with an index. */
193
191
  function indexedCandidates(scene, descriptor, broadFor) {