@weasel-js/core 1.13.0-rc.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (745) hide show
  1. package/CHANGELOG.md +408 -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 +17 -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/buildSceneLayer.js +1 -1
  133. package/dist/canvas/buildSceneLayer.js.map +1 -1
  134. package/dist/canvas/buildSceneTree.js +5 -3
  135. package/dist/canvas/buildSceneTree.js.map +1 -1
  136. package/dist/canvas/canvasRenderer.js +6 -2
  137. package/dist/canvas/canvasRenderer.js.map +1 -1
  138. package/dist/canvas/deps/editAnchors.js +4 -4
  139. package/dist/canvas/deps/editAnchors.js.map +1 -1
  140. package/dist/canvas/deps/enteredGroup.js +14 -5
  141. package/dist/canvas/deps/enteredGroup.js.map +1 -1
  142. package/dist/canvas/deps/ingestion.js +5 -1
  143. package/dist/canvas/deps/ingestion.js.map +1 -1
  144. package/dist/canvas/deps/insert.js.map +1 -1
  145. package/dist/canvas/deps/insertSite.js +5 -3
  146. package/dist/canvas/deps/insertSite.js.map +1 -1
  147. package/dist/canvas/deps/nodeAtPoint.js +1 -12
  148. package/dist/canvas/deps/nodeAtPoint.js.map +1 -1
  149. package/dist/canvas/deps/pathEditCommits.js +3 -3
  150. package/dist/canvas/deps/pathEditCommits.js.map +1 -1
  151. package/dist/canvas/deps/slice.js +16 -2
  152. package/dist/canvas/deps/slice.js.map +1 -1
  153. package/dist/canvas/deps/snap.js +5 -5
  154. package/dist/canvas/deps/snap.js.map +1 -1
  155. package/dist/canvas/deps/textEdit.js +5 -6
  156. package/dist/canvas/deps/textEdit.js.map +1 -1
  157. package/dist/canvas/derivedPath.js +8 -3
  158. package/dist/canvas/derivedPath.js.map +1 -1
  159. package/dist/canvas/getNodeAtPoint.js +2 -2
  160. package/dist/canvas/getNodeAtPoint.js.map +1 -1
  161. package/dist/canvas/insertPreviewExtent.js.map +1 -1
  162. package/dist/canvas/layerSlots.js.map +1 -1
  163. package/dist/canvas/nodeShapes/measurePainter.js +1 -1
  164. package/dist/canvas/nodeShapes/measurePainter.js.map +1 -1
  165. package/dist/canvas/nodeShapes/strokedBounds.js +5 -3
  166. package/dist/canvas/nodeShapes/strokedBounds.js.map +1 -1
  167. package/dist/canvas/overlayRoleStrokes.js +6 -0
  168. package/dist/canvas/overlayRoleStrokes.js.map +1 -1
  169. package/dist/canvas/pickIndex/scenePickIndex.js +10 -12
  170. package/dist/canvas/pickIndex/scenePickIndex.js.map +1 -1
  171. package/dist/canvas/sceneAdapter.js +10 -19
  172. package/dist/canvas/sceneAdapter.js.map +1 -1
  173. package/dist/canvas/sceneClipboard.js +17 -4
  174. package/dist/canvas/sceneClipboard.js.map +1 -1
  175. package/dist/canvas/sceneViewRender.js +7 -5
  176. package/dist/canvas/sceneViewRender.js.map +1 -1
  177. package/dist/canvas/surfaceContribution.js.map +1 -1
  178. package/dist/canvas/useCanvasPaint.js +12 -4
  179. package/dist/canvas/useCanvasPaint.js.map +1 -1
  180. package/dist/canvas/useHitObserver.js +1 -1
  181. package/dist/canvas/useHitObserver.js.map +1 -1
  182. package/dist/canvas/useViewAim.js +1 -1
  183. package/dist/canvas/useViewAim.js.map +1 -1
  184. package/dist/canvas/useViewHelpers.js +8 -5
  185. package/dist/canvas/useViewHelpers.js.map +1 -1
  186. package/dist/canvas/useViewNesting.js +39 -12
  187. package/dist/canvas/useViewNesting.js.map +1 -1
  188. package/dist/canvas/viewInputs.js.map +1 -1
  189. package/dist/canvas/viewMarkers.js +2 -2
  190. package/dist/canvas/viewMarkers.js.map +1 -1
  191. package/dist/canvas/viewRegistry.js +2 -2
  192. package/dist/canvas/viewRegistry.js.map +1 -1
  193. package/dist/canvas/viewSnap.js +67 -0
  194. package/dist/canvas/viewSnap.js.map +1 -0
  195. package/dist/clipboard.d.ts +6 -12
  196. package/dist/{clone-qb2e1F5p.d.ts → clone-Bz4iqGfE.d.ts} +10 -5
  197. package/dist/clone.d.ts +5 -5
  198. package/dist/core/geometry/booleanOfPaths.js +23 -0
  199. package/dist/core/geometry/booleanOfPaths.js.map +1 -0
  200. package/dist/core/geometry/pathPoseDescriptor.js +12 -9
  201. package/dist/core/geometry/pathPoseDescriptor.js.map +1 -1
  202. package/dist/core/geometry/poseDescriptor.js +12 -3
  203. package/dist/core/geometry/poseDescriptor.js.map +1 -1
  204. package/dist/core/geometry/targetFrame.js +2 -13
  205. package/dist/core/geometry/targetFrame.js.map +1 -1
  206. package/dist/core/layers/render.js +2 -1
  207. package/dist/core/layers/render.js.map +1 -1
  208. package/dist/core/layers/retain.js +5 -3
  209. package/dist/core/layers/retain.js.map +1 -1
  210. package/dist/core/ops/setPath.js +3 -0
  211. package/dist/core/ops/setPath.js.map +1 -1
  212. package/dist/core/paint/meshKindLazy.js.map +1 -1
  213. package/dist/core/paint/paintKindEntry.js.map +1 -1
  214. package/dist/core/paint/paintKinds.js +8 -1
  215. package/dist/core/paint/paintKinds.js.map +1 -1
  216. package/dist/core/scene/NodeProperties.js.map +1 -1
  217. package/dist/core/scene/NodeRouting.js.map +1 -1
  218. package/dist/core/scene/booleanGroup.js +33 -0
  219. package/dist/core/scene/booleanGroup.js.map +1 -0
  220. package/dist/core/scene/booleanOfChildren.js +53 -0
  221. package/dist/core/scene/booleanOfChildren.js.map +1 -0
  222. package/dist/core/scene/carryDescendants.js +18 -6
  223. package/dist/core/scene/carryDescendants.js.map +1 -1
  224. package/dist/core/scene/composeFrame.js +42 -5
  225. package/dist/core/scene/composeFrame.js.map +1 -1
  226. package/dist/core/scene/composePose.js +35 -16
  227. package/dist/core/scene/composePose.js.map +1 -1
  228. package/dist/core/scene/depMemo.js +36 -18
  229. package/dist/core/scene/depMemo.js.map +1 -1
  230. package/dist/core/scene/derivedParts.js +2 -23
  231. package/dist/core/scene/derivedParts.js.map +1 -1
  232. package/dist/core/scene/effectivePose.js +10 -0
  233. package/dist/core/scene/effectivePose.js.map +1 -1
  234. package/dist/core/scene/historyForm.js +5 -4
  235. package/dist/core/scene/historyForm.js.map +1 -1
  236. package/dist/core/scene/kitOps.js +5 -71
  237. package/dist/core/scene/kitOps.js.map +1 -1
  238. package/dist/core/scene/kitRegistry.js +5 -0
  239. package/dist/core/scene/kitRegistry.js.map +1 -1
  240. package/dist/core/scene/layerOps.js +82 -0
  241. package/dist/core/scene/layerOps.js.map +1 -0
  242. package/dist/core/scene/layoutPass.js +14 -12
  243. package/dist/core/scene/layoutPass.js.map +1 -1
  244. package/dist/core/scene/lockGuard.js +9 -3
  245. package/dist/core/scene/lockGuard.js.map +1 -1
  246. package/dist/core/scene/nestedHit.js +5 -5
  247. package/dist/core/scene/nestedHit.js.map +1 -1
  248. package/dist/core/scene/nodeFlags.js +8 -2
  249. package/dist/core/scene/nodeFlags.js.map +1 -1
  250. package/dist/core/scene/nodeGates.js +31 -2
  251. package/dist/core/scene/nodeGates.js.map +1 -1
  252. package/dist/core/scene/pathEffects/effects.js +22 -3
  253. package/dist/core/scene/pathEffects/effects.js.map +1 -1
  254. package/dist/core/scene/pathEffects/textAlong.js +16 -3
  255. package/dist/core/scene/pathEffects/textAlong.js.map +1 -1
  256. package/dist/core/scene/pathEffects/textAlongBands.js +65 -0
  257. package/dist/core/scene/pathEffects/textAlongBands.js.map +1 -0
  258. package/dist/core/scene/reconcileSpecs.js +1 -1
  259. package/dist/core/scene/reconcileSpecs.js.map +1 -1
  260. package/dist/core/scene/scene.js +11 -5
  261. package/dist/core/scene/scene.js.map +1 -1
  262. package/dist/core/scene/sceneEdits.js +5 -2
  263. package/dist/core/scene/sceneEdits.js.map +1 -1
  264. package/dist/core/scene/scenePoseAdapter.js +10 -1
  265. package/dist/core/scene/scenePoseAdapter.js.map +1 -1
  266. package/dist/core/scene/scrollOffsets.js +93 -0
  267. package/dist/core/scene/scrollOffsets.js.map +1 -0
  268. package/dist/core/scene/serialization.js +15 -5
  269. package/dist/core/scene/serialization.js.map +1 -1
  270. package/dist/core/scene/statedFields.js +2 -1
  271. package/dist/core/scene/statedFields.js.map +1 -1
  272. package/dist/core/scene/strategyView.js +35 -0
  273. package/dist/core/scene/strategyView.js.map +1 -0
  274. package/dist/core/scene/types.js.map +1 -1
  275. package/dist/core/scene/useScene.js +2 -0
  276. package/dist/core/scene/useScene.js.map +1 -1
  277. package/dist/core/scene/worldSave.js +87 -0
  278. package/dist/core/scene/worldSave.js.map +1 -0
  279. package/dist/core/selection/selectionTarget.js +1 -1
  280. package/dist/core/selection/selectionTarget.js.map +1 -1
  281. package/dist/{cornerHandles-CNCb7aTY.d.ts → cornerHandles-DpmQM_z5.d.ts} +1 -1
  282. package/dist/{depSchema-B1RS-IJx.d.ts → depSchema-C3BwxitB.d.ts} +130 -104
  283. package/dist/devtools-protocol.d.ts +2 -2
  284. package/dist/devtools.d.ts +2 -2
  285. package/dist/{features → domains}/chrome-caps/buildChromeCtx.js +1 -1
  286. package/dist/domains/chrome-caps/buildChromeCtx.js.map +1 -0
  287. package/dist/{features → domains}/chrome-caps/conditions.js +1 -1
  288. package/dist/domains/chrome-caps/conditions.js.map +1 -0
  289. package/dist/{features → domains}/chrome-caps/defaults.js +1 -1
  290. package/dist/domains/chrome-caps/defaults.js.map +1 -0
  291. package/dist/{features → domains}/chrome-caps/resolve.js +1 -1
  292. package/dist/domains/chrome-caps/resolve.js.map +1 -0
  293. package/dist/{features → domains}/chrome-caps/useChromeCaps.js +1 -1
  294. package/dist/domains/chrome-caps/useChromeCaps.js.map +1 -0
  295. package/dist/{features → domains}/chrome-caps/useHoverTracking.js +1 -1
  296. package/dist/domains/chrome-caps/useHoverTracking.js.map +1 -0
  297. package/dist/{features → domains}/ingestion/contentHandlers.js +20 -3
  298. package/dist/domains/ingestion/contentHandlers.js.map +1 -0
  299. package/dist/domains/ingestion/ghost.js +56 -0
  300. package/dist/domains/ingestion/ghost.js.map +1 -0
  301. package/dist/{features → domains}/ingestion/imageHandler.js +1 -1
  302. package/dist/domains/ingestion/imageHandler.js.map +1 -0
  303. package/dist/domains/ingestion/kitHandlers.js +22 -0
  304. package/dist/domains/ingestion/kitHandlers.js.map +1 -0
  305. package/dist/{features → domains}/ingestion/openFilePicker.js +1 -1
  306. package/dist/domains/ingestion/openFilePicker.js.map +1 -0
  307. package/dist/{features → domains}/ingestion/placement.js +1 -1
  308. package/dist/domains/ingestion/placement.js.map +1 -0
  309. package/dist/{features → domains}/ingestion/svgHandler.js +1 -1
  310. package/dist/domains/ingestion/svgHandler.js.map +1 -0
  311. package/dist/{features → domains}/ingestion/textHandler.js +9 -7
  312. package/dist/domains/ingestion/textHandler.js.map +1 -0
  313. package/dist/{features → domains}/ingestion/useCanvasIngestion.js +13 -15
  314. package/dist/domains/ingestion/useCanvasIngestion.js.map +1 -0
  315. package/dist/{features → domains}/ingestion/weaselJsonHandler.js +1 -1
  316. package/dist/domains/ingestion/weaselJsonHandler.js.map +1 -0
  317. package/dist/{features → domains}/longPress/longPressFeedback.js +1 -1
  318. package/dist/domains/longPress/longPressFeedback.js.map +1 -0
  319. package/dist/{features → domains}/measure/actionIds.js +1 -1
  320. package/dist/domains/measure/actionIds.js.map +1 -0
  321. package/dist/{features → domains}/measure/measureCommands.js +1 -1
  322. package/dist/domains/measure/measureCommands.js.map +1 -0
  323. package/dist/{features → domains}/measure/measureContribution.js +1 -1
  324. package/dist/domains/measure/measureContribution.js.map +1 -0
  325. package/dist/{features → domains}/measure/measureEdits.js +1 -1
  326. package/dist/domains/measure/measureEdits.js.map +1 -0
  327. package/dist/{features → domains}/measure/measureGestures.js +4 -7
  328. package/dist/domains/measure/measureGestures.js.map +1 -0
  329. package/dist/{features → domains}/measure/measureHit.js +1 -1
  330. package/dist/domains/measure/measureHit.js.map +1 -0
  331. package/dist/{features → domains}/measure/measureLayer.js +1 -1
  332. package/dist/domains/measure/measureLayer.js.map +1 -0
  333. package/dist/{features → domains}/measure/measurement.js +1 -1
  334. package/dist/domains/measure/measurement.js.map +1 -0
  335. package/dist/{features → domains}/measure/measurements.js +2 -2
  336. package/dist/domains/measure/measurements.js.map +1 -0
  337. package/dist/{features → domains}/modes/modeLayers.js +1 -1
  338. package/dist/domains/modes/modeLayers.js.map +1 -0
  339. package/dist/{features → domains}/modes/modeTriggers.js +3 -6
  340. package/dist/domains/modes/modeTriggers.js.map +1 -0
  341. package/dist/{features → domains}/pathEffects/effectSources.js +1 -1
  342. package/dist/domains/pathEffects/effectSources.js.map +1 -0
  343. package/dist/{features → domains}/pathEffects/index.js +1 -1
  344. package/dist/domains/pathEffects/index.js.map +1 -0
  345. package/dist/{features → domains}/pathEffects/readSource.js +1 -1
  346. package/dist/domains/pathEffects/readSource.js.map +1 -0
  347. package/dist/{features → domains}/pathEffects/textItems.js +11 -2
  348. package/dist/domains/pathEffects/textItems.js.map +1 -0
  349. package/dist/{features → domains}/pathEffects/useEffectSourcesLayer.js +1 -1
  350. package/dist/domains/pathEffects/useEffectSourcesLayer.js.map +1 -0
  351. package/dist/{features → domains}/paths/anchorData.js +1 -1
  352. package/dist/domains/paths/anchorData.js.map +1 -0
  353. package/dist/{features → domains}/paths/anchorMarkers.js +9 -7
  354. package/dist/domains/paths/anchorMarkers.js.map +1 -0
  355. package/dist/{features → domains}/paths/editablePath.js +1 -1
  356. package/dist/domains/paths/editablePath.js.map +1 -0
  357. package/dist/{features → domains}/paths/index.js +3 -3
  358. package/dist/{features → domains}/paths/originProjection.js +1 -1
  359. package/dist/domains/paths/originProjection.js.map +1 -0
  360. package/dist/{features → domains}/paths/pathEditExtension.js +1 -1
  361. package/dist/domains/paths/pathEditExtension.js.map +1 -0
  362. package/dist/{features → domains}/paths/pathEditState.js +1 -1
  363. package/dist/domains/paths/pathEditState.js.map +1 -0
  364. package/dist/{features → domains}/paths/pathEditingOverlayLayer.js +1 -1
  365. package/dist/domains/paths/pathEditingOverlayLayer.js.map +1 -0
  366. package/dist/{features → domains}/paths/pathLayer.js +1 -1
  367. package/dist/domains/paths/pathLayer.js.map +1 -0
  368. package/dist/{features → domains}/paths/pathRepresentation.js +1 -1
  369. package/dist/domains/paths/pathRepresentation.js.map +1 -0
  370. package/dist/{features → domains}/paths/pathSnap/glyphs.js +1 -1
  371. package/dist/domains/paths/pathSnap/glyphs.js.map +1 -0
  372. package/dist/{features → domains}/paths/pathSnap/pathSnapSource.js +1 -1
  373. package/dist/domains/paths/pathSnap/pathSnapSource.js.map +1 -0
  374. package/dist/{features → domains}/paths/pathSnap/sceneIndex.js +1 -1
  375. package/dist/domains/paths/pathSnap/sceneIndex.js.map +1 -0
  376. package/dist/{features → domains}/paths/pathSnap/snapGeometry.js +3 -2
  377. package/dist/domains/paths/pathSnap/snapGeometry.js.map +1 -0
  378. package/dist/{features → domains}/paths/penPreviewLayer.js +1 -1
  379. package/dist/domains/paths/penPreviewLayer.js.map +1 -0
  380. package/dist/{features → domains}/paths/shapeGenerator.js +6 -4
  381. package/dist/domains/paths/shapeGenerator.js.map +1 -0
  382. package/dist/{features → domains}/paths/strokeOutline.js +1 -1
  383. package/dist/domains/paths/strokeOutline.js.map +1 -0
  384. package/dist/{features → domains}/paths/useAnchorFields.js +1 -1
  385. package/dist/domains/paths/useAnchorFields.js.map +1 -0
  386. package/dist/{features → domains}/paths/usePathEdit.js +1 -1
  387. package/dist/domains/paths/usePathEdit.js.map +1 -0
  388. package/dist/{features → domains}/poseRun/usePoseRun.js +1 -1
  389. package/dist/domains/poseRun/usePoseRun.js.map +1 -0
  390. package/dist/{features → domains}/selection/enteredGroupFrame.js +49 -10
  391. package/dist/domains/selection/enteredGroupFrame.js.map +1 -0
  392. package/dist/{features → domains}/selection/enteredGroupScope.js +1 -1
  393. package/dist/domains/selection/enteredGroupScope.js.map +1 -0
  394. package/dist/domains/selection/enteredOperands.js +29 -0
  395. package/dist/domains/selection/enteredOperands.js.map +1 -0
  396. package/dist/{features → domains}/selection/handleCommands.js +1 -1
  397. package/dist/domains/selection/handleCommands.js.map +1 -0
  398. package/dist/{features → domains}/selection/overlay.js +1 -1
  399. package/dist/domains/selection/overlay.js.map +1 -0
  400. package/dist/{features → domains}/selection/selectionPose.js +1 -1
  401. package/dist/domains/selection/selectionPose.js.map +1 -0
  402. package/dist/{features → domains}/snap/angle2d.js +1 -1
  403. package/dist/domains/snap/angle2d.js.map +1 -0
  404. package/dist/{features → domains}/snap/debugCandidates.js +1 -1
  405. package/dist/domains/snap/debugCandidates.js.map +1 -0
  406. package/dist/{features → domains}/snap/gather.js +1 -1
  407. package/dist/domains/snap/gather.js.map +1 -0
  408. package/dist/{features → domains}/snap/inputSubspace.js +1 -1
  409. package/dist/domains/snap/inputSubspace.js.map +1 -0
  410. package/dist/{features → domains}/snap/lazySession.js +1 -1
  411. package/dist/domains/snap/lazySession.js.map +1 -0
  412. package/dist/{features → domains}/snap/marks.js +1 -1
  413. package/dist/domains/snap/marks.js.map +1 -0
  414. package/dist/{features → domains}/snap/outcomeStore.js +1 -1
  415. package/dist/domains/snap/outcomeStore.js.map +1 -0
  416. package/dist/{features → domains}/snap/pointSnap.js +1 -1
  417. package/dist/domains/snap/pointSnap.js.map +1 -0
  418. package/dist/{features → domains}/snap/probes2d.js +1 -1
  419. package/dist/domains/snap/probes2d.js.map +1 -0
  420. package/dist/{features → domains}/snap/readoutDraw.js +1 -1
  421. package/dist/domains/snap/readoutDraw.js.map +1 -0
  422. package/dist/{features → domains}/snap/readoutLayer.js +1 -1
  423. package/dist/domains/snap/readoutLayer.js.map +1 -0
  424. package/dist/{features → domains}/snap/registry.js +1 -1
  425. package/dist/domains/snap/registry.js.map +1 -0
  426. package/dist/{features → domains}/snap/resizeBox.js +1 -1
  427. package/dist/domains/snap/resizeBox.js.map +1 -0
  428. package/dist/{features → domains}/snap/roles.js +1 -1
  429. package/dist/domains/snap/roles.js.map +1 -0
  430. package/dist/{features → domains}/snap/rotationSource.js +1 -1
  431. package/dist/domains/snap/rotationSource.js.map +1 -0
  432. package/dist/{features → domains}/snap/sceneReads.js +24 -3
  433. package/dist/domains/snap/sceneReads.js.map +1 -0
  434. package/dist/{features → domains}/snap/sceneSession2d.js +3 -2
  435. package/dist/domains/snap/sceneSession2d.js.map +1 -0
  436. package/dist/{features → domains}/snap/screen.js +1 -1
  437. package/dist/domains/snap/screen.js.map +1 -0
  438. package/dist/{features → domains}/snap/session2d.js +3 -2
  439. package/dist/domains/snap/session2d.js.map +1 -0
  440. package/dist/{features → domains}/snap/spanSnap.js +1 -1
  441. package/dist/domains/snap/spanSnap.js.map +1 -0
  442. package/dist/{features → domains}/snap/stepAngles.js +1 -1
  443. package/dist/domains/snap/stepAngles.js.map +1 -0
  444. package/dist/{features → domains}/text/editingDrawOne.js +4 -4
  445. package/dist/domains/text/editingDrawOne.js.map +1 -0
  446. package/dist/domains/text/hostTextEditors.js +24 -0
  447. package/dist/domains/text/hostTextEditors.js.map +1 -0
  448. package/dist/{features → domains}/text/index.js +1 -1
  449. package/dist/{features → domains}/text/sceneTextDrafts.js +1 -1
  450. package/dist/domains/text/sceneTextDrafts.js.map +1 -0
  451. package/dist/{features → domains}/text/textHitAt.js +18 -2
  452. package/dist/domains/text/textHitAt.js.map +1 -0
  453. package/dist/{features → domains}/text/textLayer.js +1 -1
  454. package/dist/domains/text/textLayer.js.map +1 -0
  455. package/dist/{features → domains}/text/useSceneTextEdit.js +11 -3
  456. package/dist/domains/text/useSceneTextEdit.js.map +1 -0
  457. package/dist/{features → domains}/viewports/aim.js +1 -1
  458. package/dist/domains/viewports/aim.js.map +1 -0
  459. package/dist/{features → domains}/viewports/viewMarker.js +23 -5
  460. package/dist/domains/viewports/viewMarker.js.map +1 -0
  461. package/dist/{features → domains}/viewports/viewMarkerDrag.js +3 -3
  462. package/dist/domains/viewports/viewMarkerDrag.js.map +1 -0
  463. package/dist/{features → domains}/viewports/viewResolver.js +1 -1
  464. package/dist/domains/viewports/viewResolver.js.map +1 -0
  465. package/dist/{features → domains}/viewports/viewportLayer.js +3 -2
  466. package/dist/domains/viewports/viewportLayer.js.map +1 -0
  467. package/dist/icons.table.js +1 -1
  468. package/dist/icons.table.js.map +1 -1
  469. package/dist/icons.table.json +106 -6
  470. package/dist/index.d.ts +1445 -1053
  471. package/dist/index.js +90 -77
  472. package/dist/interactions/actions/admitsChild.js +6 -2
  473. package/dist/interactions/actions/admitsChild.js.map +1 -1
  474. package/dist/interactions/actions/align/align.js +1 -4
  475. package/dist/interactions/actions/align/align.js.map +1 -1
  476. package/dist/interactions/actions/booleans/booleanGroupAction.js +66 -0
  477. package/dist/interactions/actions/booleans/booleanGroupAction.js.map +1 -0
  478. package/dist/interactions/actions/booleans/keymap.js +52 -0
  479. package/dist/interactions/actions/booleans/keymap.js.map +1 -0
  480. package/dist/interactions/actions/booleans/operands.js +1 -1
  481. package/dist/interactions/actions/booleans/pieces.js +4 -11
  482. package/dist/interactions/actions/booleans/pieces.js.map +1 -1
  483. package/dist/interactions/actions/clipboard/action.js +3 -7
  484. package/dist/interactions/actions/clipboard/action.js.map +1 -1
  485. package/dist/interactions/actions/clipboard/clipboardOps.js +1 -1
  486. package/dist/interactions/actions/clipboard/clipboardOps.js.map +1 -1
  487. package/dist/interactions/actions/clipboard/materializePaste.js.map +1 -1
  488. package/dist/interactions/actions/defaults/anchorEditing.js +6 -6
  489. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  490. package/dist/interactions/actions/defaults/bendSegment.js +1 -1
  491. package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
  492. package/dist/interactions/actions/defaults/containerScroll.js +170 -0
  493. package/dist/interactions/actions/defaults/containerScroll.js.map +1 -0
  494. package/dist/interactions/actions/defaults/contextMenu.js +2 -5
  495. package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
  496. package/dist/interactions/actions/defaults/delete.js +1 -1
  497. package/dist/interactions/actions/defaults/delete.js.map +1 -1
  498. package/dist/interactions/actions/defaults/duplicate.js +1 -3
  499. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  500. package/dist/interactions/actions/defaults/enterGroup.js +7 -12
  501. package/dist/interactions/actions/defaults/enterGroup.js.map +1 -1
  502. package/dist/interactions/actions/defaults/enterPathEdit.js +4 -8
  503. package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
  504. package/dist/interactions/actions/defaults/group.js +12 -24
  505. package/dist/interactions/actions/defaults/group.js.map +1 -1
  506. package/dist/interactions/actions/defaults/ingest.js +18 -10
  507. package/dist/interactions/actions/defaults/ingest.js.map +1 -1
  508. package/dist/interactions/actions/defaults/insertPathAnchor.js +3 -3
  509. package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
  510. package/dist/interactions/actions/defaults/nudgeSteps.js +3 -21
  511. package/dist/interactions/actions/defaults/nudgeSteps.js.map +1 -1
  512. package/dist/interactions/actions/defaults/pathEditMarks.js.map +1 -1
  513. package/dist/interactions/actions/defaults/selectDeep.js +2 -2
  514. package/dist/interactions/actions/defaults/selectDeep.js.map +1 -1
  515. package/dist/interactions/actions/distribute/distribute.js.map +1 -1
  516. package/dist/interactions/actions/dropVerdict.js +9 -0
  517. package/dist/interactions/actions/dropVerdict.js.map +1 -0
  518. package/dist/interactions/actions/edit-anchors/action.js +2 -2
  519. package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
  520. package/dist/interactions/actions/edit-anchors/extensionDrags.js.map +1 -1
  521. package/dist/interactions/actions/edit-anchors/geometry.js +8 -6
  522. package/dist/interactions/actions/edit-anchors/geometry.js.map +1 -1
  523. package/dist/interactions/actions/edit-anchors/handleDrag.js.map +1 -1
  524. package/dist/interactions/actions/edit-anchors/preview.js +1 -1
  525. package/dist/interactions/actions/edit-anchors/preview.js.map +1 -1
  526. package/dist/interactions/actions/flip/action.js +3 -2
  527. package/dist/interactions/actions/flip/action.js.map +1 -1
  528. package/dist/interactions/actions/geometryProjection.js +8 -3
  529. package/dist/interactions/actions/geometryProjection.js.map +1 -1
  530. package/dist/interactions/actions/gestureFrames.js +1 -0
  531. package/dist/interactions/actions/gestureFrames.js.map +1 -1
  532. package/dist/interactions/actions/insert/action.js +6 -2
  533. package/dist/interactions/actions/insert/action.js.map +1 -1
  534. package/dist/interactions/actions/insert/frame.js +1 -1
  535. package/dist/interactions/actions/insert/frame.js.map +1 -1
  536. package/dist/interactions/actions/insert/placeAction.js +6 -8
  537. package/dist/interactions/actions/insert/placeAction.js.map +1 -1
  538. package/dist/interactions/actions/insert/session.js +2 -2
  539. package/dist/interactions/actions/insert/session.js.map +1 -1
  540. package/dist/interactions/actions/move/action.js +6 -15
  541. package/dist/interactions/actions/move/action.js.map +1 -1
  542. package/dist/interactions/actions/move/behaviors/layoutDrop.js +12 -2
  543. package/dist/interactions/actions/move/behaviors/layoutDrop.js.map +1 -1
  544. package/dist/interactions/actions/move/behaviors/reparentOnDrop.js +29 -10
  545. package/dist/interactions/actions/move/behaviors/reparentOnDrop.js.map +1 -1
  546. package/dist/interactions/actions/move/behaviors/snapToContainer.js +42 -6
  547. package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
  548. package/dist/interactions/actions/move/capture.js +4 -8
  549. package/dist/interactions/actions/move/capture.js.map +1 -1
  550. package/dist/interactions/actions/move/commit/index.js.map +1 -1
  551. package/dist/interactions/actions/move/commit/layoutDrop.js +4 -3
  552. package/dist/interactions/actions/move/commit/layoutDrop.js.map +1 -1
  553. package/dist/interactions/actions/move/commit/layoutRelease.js +15 -9
  554. package/dist/interactions/actions/move/commit/layoutRelease.js.map +1 -1
  555. package/dist/interactions/actions/move/commit/reparent.js +19 -13
  556. package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
  557. package/dist/interactions/actions/move/delta.js +51 -5
  558. package/dist/interactions/actions/move/delta.js.map +1 -1
  559. package/dist/interactions/actions/move/frame.js +8 -4
  560. package/dist/interactions/actions/move/frame.js.map +1 -1
  561. package/dist/interactions/actions/move/layout/container.js +19 -9
  562. package/dist/interactions/actions/move/layout/container.js.map +1 -1
  563. package/dist/interactions/actions/move/layout/dragged.js +2 -2
  564. package/dist/interactions/actions/move/layout/dragged.js.map +1 -1
  565. package/dist/interactions/actions/move/layout/dropPass.js +36 -18
  566. package/dist/interactions/actions/move/layout/dropPass.js.map +1 -1
  567. package/dist/interactions/actions/move/layout/exits.js +2 -2
  568. package/dist/interactions/actions/move/layout/exits.js.map +1 -1
  569. package/dist/interactions/actions/move/layout/glide.js +5 -5
  570. package/dist/interactions/actions/move/layout/glide.js.map +1 -1
  571. package/dist/interactions/actions/move/layout/view.js +55 -0
  572. package/dist/interactions/actions/move/layout/view.js.map +1 -0
  573. package/dist/interactions/actions/move/refusal.js +52 -0
  574. package/dist/interactions/actions/move/refusal.js.map +1 -0
  575. package/dist/interactions/actions/move/session.js +9 -8
  576. package/dist/interactions/actions/move/session.js.map +1 -1
  577. package/dist/interactions/actions/move/translate.js +10 -4
  578. package/dist/interactions/actions/move/translate.js.map +1 -1
  579. package/dist/interactions/actions/moveNodes.js +21 -5
  580. package/dist/interactions/actions/moveNodes.js.map +1 -1
  581. package/dist/interactions/actions/pathCommands/pathNodes.js +3 -3
  582. package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -1
  583. package/dist/interactions/actions/planeInput.js +14 -13
  584. package/dist/interactions/actions/planeInput.js.map +1 -1
  585. package/dist/interactions/actions/poseFrame.js +21 -8
  586. package/dist/interactions/actions/poseFrame.js.map +1 -1
  587. package/dist/interactions/actions/resize/action.js +1 -1
  588. package/dist/interactions/actions/resize/action.js.map +1 -1
  589. package/dist/interactions/actions/resize/aspect.js +1 -1
  590. package/dist/interactions/actions/resize/aspect.js.map +1 -1
  591. package/dist/interactions/actions/resize/commit.js +10 -1
  592. package/dist/interactions/actions/resize/commit.js.map +1 -1
  593. package/dist/interactions/actions/resize/frame.js +3 -2
  594. package/dist/interactions/actions/resize/frame.js.map +1 -1
  595. package/dist/interactions/actions/resize/held.js +44 -0
  596. package/dist/interactions/actions/resize/held.js.map +1 -0
  597. package/dist/interactions/actions/resize/session.js +3 -1
  598. package/dist/interactions/actions/resize/session.js.map +1 -1
  599. package/dist/interactions/actions/resolveOverlays.js +9 -0
  600. package/dist/interactions/actions/resolveOverlays.js.map +1 -1
  601. package/dist/interactions/actions/resolvePreviews.js +23 -7
  602. package/dist/interactions/actions/resolvePreviews.js.map +1 -1
  603. package/dist/interactions/actions/rotate/action.js +1 -1
  604. package/dist/interactions/actions/rotate/action.js.map +1 -1
  605. package/dist/interactions/actions/rotate/frame.js +1 -1
  606. package/dist/interactions/actions/rotate/frame.js.map +1 -1
  607. package/dist/interactions/actions/rotate/session.js +2 -2
  608. package/dist/interactions/actions/rotate/session.js.map +1 -1
  609. package/dist/interactions/actions/selectionSubtree.js +2 -4
  610. package/dist/interactions/actions/selectionSubtree.js.map +1 -1
  611. package/dist/interactions/actions/spatialReference.js +4 -9
  612. package/dist/interactions/actions/spatialReference.js.map +1 -1
  613. package/dist/interactions/gestures/dragRadial/dragRadial.js.map +1 -1
  614. package/dist/interactions/gestures/dragRect/dragRect.js.map +1 -1
  615. package/dist/kitSettingsSchema.js +2 -2
  616. package/dist/kitSettingsSchema.js.map +1 -1
  617. package/dist/{math-C_elShP_.d.ts → math-B_unOnF4.d.ts} +2 -2
  618. package/dist/math.d.ts +3 -3
  619. package/dist/move.d.ts +6 -6
  620. package/dist/{options-ClEm3SEl.d.ts → options-DAjkhbcs.d.ts} +5 -5
  621. package/dist/{poseDescriptor-DN2yfnq_.d.ts → poseDescriptor-CvSxVhCd.d.ts} +17 -4
  622. package/dist/resize.d.ts +6 -6
  623. package/dist/style.css +14 -0
  624. package/dist/test-seams.d.ts +11 -15
  625. package/dist/test-seams.js +1 -1
  626. package/dist/tools/builtin/eyedropper/useEyedropperTool.js +3 -6
  627. package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
  628. package/dist/tools/builtin/line/useLineTool.js.map +1 -1
  629. package/dist/tools/builtin/measure/useMeasureTool.js +2 -2
  630. package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
  631. package/dist/tools/builtin/pen/penHandle.js +2 -2
  632. package/dist/tools/builtin/pen/penHandle.js.map +1 -1
  633. package/dist/tools/builtin/pen/usePenTool.js +13 -19
  634. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  635. package/dist/tools/builtin/polygon/usePolygonTool.js +1 -1
  636. package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
  637. package/dist/tools/builtin/select/groupEntry.js +1 -1
  638. package/dist/tools/builtin/select/groupEntry.js.map +1 -1
  639. package/dist/tools/builtin/select/selectionContributions.js +1 -1
  640. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  641. package/dist/tools/builtin/select/useSelectTool.js +7 -7
  642. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  643. package/dist/tools/builtin/slice/useSliceTool.js +5 -8
  644. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  645. package/dist/tools/builtin/star/useStarTool.js +1 -1
  646. package/dist/tools/builtin/star/useStarTool.js.map +1 -1
  647. package/dist/tools/index.js +2 -1
  648. package/dist/{types-49uYJN3j.d.ts → types-A_sNJYRd.d.ts} +8 -0
  649. package/dist/{types-BEdRIhNc.d.ts → types-DW14eu9B.d.ts} +131 -36
  650. package/dist/{types-p2alu-R1.d.ts → types-VCtfchp-.d.ts} +4 -6
  651. package/dist/util/color.js +12 -14
  652. package/dist/util/color.js.map +1 -1
  653. package/dist/version.js +1 -1
  654. package/package.json +25 -24
  655. package/dist/canvas/poseCascade.js +0 -65
  656. package/dist/canvas/poseCascade.js.map +0 -1
  657. package/dist/features/chrome-caps/buildChromeCtx.js.map +0 -1
  658. package/dist/features/chrome-caps/conditions.js.map +0 -1
  659. package/dist/features/chrome-caps/defaults.js.map +0 -1
  660. package/dist/features/chrome-caps/resolve.js.map +0 -1
  661. package/dist/features/chrome-caps/useChromeCaps.js.map +0 -1
  662. package/dist/features/chrome-caps/useHoverTracking.js.map +0 -1
  663. package/dist/features/ingestion/contentHandlers.js.map +0 -1
  664. package/dist/features/ingestion/imageHandler.js.map +0 -1
  665. package/dist/features/ingestion/openFilePicker.js.map +0 -1
  666. package/dist/features/ingestion/placement.js.map +0 -1
  667. package/dist/features/ingestion/registerKitHandlers.js +0 -43
  668. package/dist/features/ingestion/registerKitHandlers.js.map +0 -1
  669. package/dist/features/ingestion/svgHandler.js.map +0 -1
  670. package/dist/features/ingestion/textHandler.js.map +0 -1
  671. package/dist/features/ingestion/useCanvasIngestion.js.map +0 -1
  672. package/dist/features/ingestion/weaselJsonHandler.js.map +0 -1
  673. package/dist/features/longPress/longPressFeedback.js.map +0 -1
  674. package/dist/features/measure/actionIds.js.map +0 -1
  675. package/dist/features/measure/measureCommands.js.map +0 -1
  676. package/dist/features/measure/measureContribution.js.map +0 -1
  677. package/dist/features/measure/measureEdits.js.map +0 -1
  678. package/dist/features/measure/measureGestures.js.map +0 -1
  679. package/dist/features/measure/measureHit.js.map +0 -1
  680. package/dist/features/measure/measureLayer.js.map +0 -1
  681. package/dist/features/measure/measurement.js.map +0 -1
  682. package/dist/features/measure/measurements.js.map +0 -1
  683. package/dist/features/modes/modeLayers.js.map +0 -1
  684. package/dist/features/modes/modeTriggers.js.map +0 -1
  685. package/dist/features/pathEffects/effectSources.js.map +0 -1
  686. package/dist/features/pathEffects/index.js.map +0 -1
  687. package/dist/features/pathEffects/readSource.js.map +0 -1
  688. package/dist/features/pathEffects/textItems.js.map +0 -1
  689. package/dist/features/pathEffects/useEffectSourcesLayer.js.map +0 -1
  690. package/dist/features/paths/anchorData.js.map +0 -1
  691. package/dist/features/paths/anchorMarkers.js.map +0 -1
  692. package/dist/features/paths/editablePath.js.map +0 -1
  693. package/dist/features/paths/originProjection.js.map +0 -1
  694. package/dist/features/paths/pathEditExtension.js.map +0 -1
  695. package/dist/features/paths/pathEditState.js.map +0 -1
  696. package/dist/features/paths/pathEditingOverlayLayer.js.map +0 -1
  697. package/dist/features/paths/pathLayer.js.map +0 -1
  698. package/dist/features/paths/pathRepresentation.js.map +0 -1
  699. package/dist/features/paths/pathSnap/glyphs.js.map +0 -1
  700. package/dist/features/paths/pathSnap/pathSnapSource.js.map +0 -1
  701. package/dist/features/paths/pathSnap/sceneIndex.js.map +0 -1
  702. package/dist/features/paths/pathSnap/snapGeometry.js.map +0 -1
  703. package/dist/features/paths/penPreviewLayer.js.map +0 -1
  704. package/dist/features/paths/shapeGenerator.js.map +0 -1
  705. package/dist/features/paths/strokeOutline.js.map +0 -1
  706. package/dist/features/paths/useAnchorFields.js.map +0 -1
  707. package/dist/features/paths/usePathEdit.js.map +0 -1
  708. package/dist/features/poseRun/usePoseRun.js.map +0 -1
  709. package/dist/features/selection/enteredGroupFrame.js.map +0 -1
  710. package/dist/features/selection/enteredGroupScope.js.map +0 -1
  711. package/dist/features/selection/handleCommands.js.map +0 -1
  712. package/dist/features/selection/overlay.js.map +0 -1
  713. package/dist/features/selection/selectionPose.js.map +0 -1
  714. package/dist/features/snap/angle2d.js.map +0 -1
  715. package/dist/features/snap/debugCandidates.js.map +0 -1
  716. package/dist/features/snap/gather.js.map +0 -1
  717. package/dist/features/snap/inputSubspace.js.map +0 -1
  718. package/dist/features/snap/lazySession.js.map +0 -1
  719. package/dist/features/snap/marks.js.map +0 -1
  720. package/dist/features/snap/outcomeStore.js.map +0 -1
  721. package/dist/features/snap/pointSnap.js.map +0 -1
  722. package/dist/features/snap/probes2d.js.map +0 -1
  723. package/dist/features/snap/readoutDraw.js.map +0 -1
  724. package/dist/features/snap/readoutLayer.js.map +0 -1
  725. package/dist/features/snap/registry.js.map +0 -1
  726. package/dist/features/snap/resizeBox.js.map +0 -1
  727. package/dist/features/snap/roles.js.map +0 -1
  728. package/dist/features/snap/rotationSource.js.map +0 -1
  729. package/dist/features/snap/sceneReads.js.map +0 -1
  730. package/dist/features/snap/sceneSession2d.js.map +0 -1
  731. package/dist/features/snap/screen.js.map +0 -1
  732. package/dist/features/snap/session2d.js.map +0 -1
  733. package/dist/features/snap/spanSnap.js.map +0 -1
  734. package/dist/features/snap/stepAngles.js.map +0 -1
  735. package/dist/features/text/editingDrawOne.js.map +0 -1
  736. package/dist/features/text/sceneTextDrafts.js.map +0 -1
  737. package/dist/features/text/textHitAt.js.map +0 -1
  738. package/dist/features/text/textLayer.js.map +0 -1
  739. package/dist/features/text/useSceneTextEdit.js.map +0 -1
  740. package/dist/features/viewports/aim.js.map +0 -1
  741. package/dist/features/viewports/viewMarker.js.map +0 -1
  742. package/dist/features/viewports/viewMarkerDrag.js.map +0 -1
  743. package/dist/features/viewports/viewResolver.js.map +0 -1
  744. package/dist/features/viewports/viewportLayer.js.map +0 -1
  745. /package/dist/{features → domains}/chrome-caps/index.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"insert.js","names":["e"],"sources":["../../../src/canvas/deps/insert.ts"],"sourcesContent":["/**\n * `useInsertDepSource` — wires the `insert` dep consumed by `insertAction`.\n *\n * `line`, `polygon`, `star`, and `pencil` receive the drag AABB from the insertAction invoker,\n * but `extras` may carry richer geometry (endpoints, center+radius+rotation, point trail).\n * `insertPreviewExtent` resolves the two into the node's real extent — the same resolution the\n * live preview and the reported gesture bounds use.\n */\nimport { useRef } from 'react';\nimport { useDepRegistry, useDepSource } from '@weasel-js/routing/react';\nimport { useLatest } from '@weasel-js/react';\nimport type { InsertDep, InsertExtras, InsertLive } from 'interactions/actions/depSchema';\nimport { insertSite } from './insertSite';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport type { Op } from 'core/ops/types';\nimport { createInsertOp } from 'core/ops/create';\nimport {\n rectPath,\n ellipsePath,\n regularPolygonPath,\n starPath,\n linePath,\n polygonFromPoints,\n schneiderFit,\n type PathFillRule,\n type PolygonPath,\n} from '@weasel-js/geom';\nimport { insertPreviewExtent } from '../insertPreviewExtent';\nimport type { ShapeGenerator } from 'features/paths/shapeGenerator';\nimport type { Stroke, Fill } from '@weasel-js/paint';\nimport { DEFAULT_TEXT_FILL } from '@weasel-js/text';\nimport { cycleFill, solid, strokeOf } from '../../util/paint';\nimport { stickyData, type StickyStyle } from '../../tools/builtin/sticky/stickyNode';\nimport { minSizeOf } from 'core/scene/minSize';\n\ninterface OpsApplier {\n applyOps(ops: Op[], label?: string): void;\n}\n\n/**\n * Consumer-supplied node factory for one insert `kind`. Given the drag AABB\n * and the tool's `extras`, returns the node's `data` (in the consumer's own\n * data shape) plus an optional `pose` override — the dep supplies id, layer,\n * and the undoable insert op. Return `null` to reject the insert.\n *\n * A factory registered for a kit kind (`rect`, `line`, …) fully replaces the\n * kit's default `{ path, fill }` factory for that kind; a factory for a novel\n * kind adds support the kit doesn't ship (e.g. `text`). To change only the\n * paint of a kit shape, pass an {@link InsertPaint}. See\n * `SceneCanvas`'s `insertNodeFactories` prop.\n */\nexport type InsertNodeFactory = (\n bounds: { x: number; y: number; width: number; height: number },\n extras: InsertExtras,\n) => { data: unknown; pose?: unknown } | null;\n\n/**\n * The paint a kit-built shape is inserted with. `kind` is the shape being\n * built and `seq` counts this canvas's inserts from 1. A key left out stays\n * off the node, which paints none of it, the same as `null`. A pencil\n * trail too short to fit is built as a rect and asks as one. A line and an\n * open pen path are inserted unfilled: a fill given to either is dropped.\n * `fillRule` is the rule a path that carries one is built with, where the\n * kit's own is nonzero; a rect or an ellipse has none to set.\n *\n * It paints only the shapes the kit builds: an `InsertNodeFactory` owns its\n * node's whole `data`. See `SceneCanvas`'s `insertPaint` prop.\n */\nexport type InsertPaint = (kind: string, seq: number) => {\n fill?: Fill | null;\n stroke?: Stroke | null;\n fillRule?: PathFillRule;\n};\n\nfunction paintKeys({ fill, stroke }: ReturnType<InsertPaint>): { fill?: Fill | null; stroke?: Stroke | null } {\n return { ...(fill !== undefined ? { fill } : {}), ...(stroke !== undefined ? { stroke } : {}) };\n}\n\nfunction withFillRule(data: unknown, rule: PathFillRule | undefined): unknown {\n const path = (data as { path?: object } | undefined)?.path;\n if (rule === undefined || path === undefined || !('fillRule' in path)) return data;\n return { ...(data as object), path: { ...path, fillRule: rule } };\n}\n\n/** The default {@link InsertPaint}: the next color of the kit palette, as a\n * fill on a closed shape, a fill and a stroke on a pen path, and a stroke\n * alone on a line or a pencil trail. */\nexport const paletteInsertPaint: InsertPaint = (kind, seq) => {\n const color = cycleFill(seq);\n if (kind === 'line' || kind === 'pencil') return { stroke: strokeOf(color, 2) };\n if (kind === 'path') return { fill: { paint: solid(color) }, stroke: strokeOf(color, 2) };\n return { fill: { paint: solid(color) } };\n};\n\n/** The kit's default data for a kind drawn as a box, or `null` for a kind it has none for. */\nfunction boxKindData(\n kind: string,\n bounds: { x: number; y: number; width: number; height: number },\n extras: InsertExtras,\n painted: (as?: string) => ReturnType<typeof paintKeys>,\n): unknown {\n switch (kind) {\n case 'rect':\n // The rect path lives at the origin and the pose carries position:\n // `pathInPoseFrame` rebases a rect path onto the pose box, so don't\n // double-count the position.\n return { path: rectPath(0, 0, bounds.width, bounds.height), ...painted() };\n case 'ellipse':\n return { path: ellipsePath(bounds), ...painted() };\n case 'path': {\n const e = extras as { path: PolygonPath; closed: boolean; data?: Readonly<Record<string, unknown>> };\n return { ...e.data, path: e.path, ...painted(), ...(e.closed ? {} : { fill: null }) };\n }\n case 'text': {\n // The built-in text tool drags an empty text box you then type into, so\n // `extras` carries no content. The kit:text painter matches on\n // `data.text != null` and applies style defaults at render time.\n const e = extras as Partial<{ text: string }>;\n return { text: e.text ?? '', fill: DEFAULT_TEXT_FILL };\n }\n case 'sticky':\n return stickyData(extras as StickyStyle & { text?: string });\n case 'image': {\n // The bitmap is loaded + cached by `imageCache` keyed on `src`;\n // only the (serializable) `src` lives on the node.\n const e = extras as Partial<{ src: string; opacity: number }>;\n return { image: { src: e.src ?? '', ...(e.opacity !== undefined ? { opacity: e.opacity } : {}) } };\n }\n default:\n return null;\n }\n}\n\nexport function useInsertDepSource(\n scene: Scene<unknown, string, unknown>,\n adapter: OpsApplier,\n factories?: Record<string, InsertNodeFactory>,\n paint: InsertPaint = paletteInsertPaint,\n): void {\n const sceneRef = useLatest(scene);\n const adapterRef = useLatest(adapter);\n const factoriesRef = useLatest(factories);\n const paintRef = useLatest(paint);\n const registry = useDepRegistry();\n const insertSeqRef = useRef(0);\n const liveRef = useRef<InsertLive>({ gesture: null });\n useDepSource('insertLive', () => liveRef.current);\n\n useDepSource('insert', (): InsertDep => {\n const sc = sceneRef.current;\n const ad = adapterRef.current;\n\n const site = () => insertSite(sc, registry.get('insertInto')?.get(), registry.get('canDropInto'));\n const build: NonNullable<InsertDep['build']> = (bounds, extras) => {\n const kind = extras.kind;\n const { parent, layer, local } = site();\n const seq = ++insertSeqRef.current;\n const id = sc.mintId();\n let asked: ReturnType<InsertPaint> | undefined;\n const painted = (as: string = kind) => paintKeys(asked = paintRef.current(as, seq));\n\n // The nascent node's extent — drag AABB reconciled with whatever\n // richer geometry `extras` carries.\n const extent = insertPreviewExtent({ shape: kind, bounds, extras });\n const pose: unknown = extent.bounds;\n\n // Consumer factory wins over the kit default for this kind. It owns the node's\n // data + optional pose; the dep still supplies id/layer/op.\n const factory = factoriesRef.current?.[kind];\n if (factory) {\n const built = factory(bounds, extras);\n if (built === null) return null;\n return {\n id,\n ops: [createInsertOp({ node: { id, kind: 'mark', layer, parent, pose: local(built.pose ?? pose), data: built.data } as unknown as { id: string }, label: `Insert ${kind}` })],\n };\n }\n\n const geom = extent.geometry;\n let data: unknown;\n\n switch (geom.kind) {\n case 'line':\n data = { path: linePath(geom.a, geom.b), ...painted(), fill: null };\n break;\n case 'polygon':\n data = {\n path: regularPolygonPath(geom.center, geom.radius, geom.sides, geom.rotation),\n generator: { kind: 'polygon', sides: geom.sides, rotation: geom.rotation } satisfies ShapeGenerator,\n ...painted(),\n };\n break;\n case 'star':\n data = {\n path: starPath(geom.center, geom.outerRadius, geom.points, geom.innerRadius, geom.rotation),\n generator: {\n kind: 'star',\n points: geom.points,\n innerRadiusRatio: geom.outerRadius === 0 ? 0.5 : geom.innerRadius / geom.outerRadius,\n rotation: geom.rotation,\n } satisfies ShapeGenerator,\n ...painted(),\n };\n break;\n case 'pencil': {\n const samples = geom.samples as { x: number; y: number }[];\n if (samples.length >= 4) {\n data = { path: schneiderFit(samples, 2.0), ...painted() };\n } else if (samples.length >= 2) {\n data = { path: polygonFromPoints(samples), ...painted() };\n } else {\n data = { path: rectPath(0, 0, extent.bounds.width, extent.bounds.height), ...painted('rect') };\n }\n break;\n }\n case 'box':\n data = boxKindData(kind, extent.bounds, extras, painted);\n if (data === null) {\n console.warn(`weasel insertDep: no factory for kind=\"${kind}\". Skipping insert.`);\n return null;\n }\n break;\n }\n\n data = withFillRule(data, asked?.fillRule);\n const min = minSizeOf(extras);\n if (min) data = { ...(data as object), minSize: min };\n return {\n id,\n ops: [createInsertOp({ node: { id, kind: 'mark', layer, parent, pose: local(pose), data } as unknown as { id: string }, label: `Insert ${kind}` })],\n };\n };\n return {\n layer: () => site().layer,\n build,\n commit(bounds, extras, ends): NodeId | null {\n const built = build(bounds, extras, ends);\n if (built === null) return null;\n ad.applyOps(built.ops, `Insert ${extras.kind}`);\n return built.id;\n },\n };\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"insert.js","names":["e"],"sources":["../../../src/canvas/deps/insert.ts"],"sourcesContent":["/**\n * `useInsertDepSource` — wires the `insert` dep consumed by `insertAction`.\n *\n * `line`, `polygon`, `star`, and `pencil` receive the drag AABB from the insertAction invoker,\n * but `extras` may carry richer geometry (endpoints, center+radius+rotation, point trail).\n * `insertPreviewExtent` resolves the two into the node's real extent — the same resolution the\n * live preview and the reported gesture bounds use.\n */\nimport { useRef } from 'react';\nimport { useDepRegistry, useDepSource } from '@weasel-js/routing/react';\nimport { useLatest } from '@weasel-js/react';\nimport type { InsertDep, InsertExtras, InsertLive } from 'interactions/actions/depSchema';\nimport { insertSite } from './insertSite';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport type { Op } from 'core/ops/types';\nimport { createInsertOp } from 'core/ops/create';\nimport {\n rectPath,\n ellipsePath,\n regularPolygonPath,\n starPath,\n linePath,\n polygonFromPoints,\n schneiderFit,\n type PathFillRule,\n type PolygonPath,\n} from '@weasel-js/geom';\nimport { insertPreviewExtent } from '../insertPreviewExtent';\nimport type { ShapeGenerator } from 'domains/paths/shapeGenerator';\nimport type { Stroke, Fill } from '@weasel-js/paint';\nimport { DEFAULT_TEXT_FILL } from '@weasel-js/text';\nimport { cycleFill, solid, strokeOf } from '../../util/paint';\nimport { stickyData, type StickyStyle } from '../../tools/builtin/sticky/stickyNode';\nimport { minSizeOf } from 'core/scene/minSize';\n\ninterface OpsApplier {\n applyOps(ops: Op[], label?: string): void;\n}\n\n/**\n * Consumer-supplied node factory for one insert `kind`. Given the drag AABB\n * and the tool's `extras`, returns the node's `data` (in the consumer's own\n * data shape) plus an optional `pose` override — the dep supplies id, layer,\n * and the undoable insert op. Return `null` to reject the insert.\n *\n * A factory registered for a kit kind (`rect`, `line`, …) fully replaces the\n * kit's default `{ path, fill }` factory for that kind; a factory for a novel\n * kind adds support the kit doesn't ship (e.g. `text`). To change only the\n * paint of a kit shape, pass an {@link InsertPaint}. See\n * `SceneCanvas`'s `insertNodeFactories` prop.\n */\nexport type InsertNodeFactory = (\n bounds: { x: number; y: number; width: number; height: number },\n extras: InsertExtras,\n) => { data: unknown; pose?: unknown } | null;\n\n/**\n * The paint a kit-built shape is inserted with. `kind` is the shape being\n * built and `seq` counts this canvas's inserts from 1. A key left out stays\n * off the node, which paints none of it, the same as `null`. A pencil\n * trail too short to fit is built as a rect and asks as one. A line and an\n * open pen path are inserted unfilled: a fill given to either is dropped.\n * `fillRule` is the rule a path that carries one is built with, where the\n * kit's own is nonzero; a rect or an ellipse has none to set.\n *\n * It paints only the shapes the kit builds: an `InsertNodeFactory` owns its\n * node's whole `data`. See `SceneCanvas`'s `insertPaint` prop.\n */\nexport type InsertPaint = (kind: string, seq: number) => {\n fill?: Fill | null;\n stroke?: Stroke | null;\n fillRule?: PathFillRule;\n};\n\nfunction paintKeys({ fill, stroke }: ReturnType<InsertPaint>): { fill?: Fill | null; stroke?: Stroke | null } {\n return { ...(fill !== undefined ? { fill } : {}), ...(stroke !== undefined ? { stroke } : {}) };\n}\n\nfunction withFillRule(data: unknown, rule: PathFillRule | undefined): unknown {\n const path = (data as { path?: object } | undefined)?.path;\n if (rule === undefined || path === undefined || !('fillRule' in path)) return data;\n return { ...(data as object), path: { ...path, fillRule: rule } };\n}\n\n/** The default {@link InsertPaint}: the next color of the kit palette, as a\n * fill on a closed shape, a fill and a stroke on a pen path, and a stroke\n * alone on a line or a pencil trail. */\nexport const paletteInsertPaint: InsertPaint = (kind, seq) => {\n const color = cycleFill(seq);\n if (kind === 'line' || kind === 'pencil') return { stroke: strokeOf(color, 2) };\n if (kind === 'path') return { fill: { paint: solid(color) }, stroke: strokeOf(color, 2) };\n return { fill: { paint: solid(color) } };\n};\n\n/** The kit's default data for a kind drawn as a box, or `null` for a kind it has none for. */\nfunction boxKindData(\n kind: string,\n bounds: { x: number; y: number; width: number; height: number },\n extras: InsertExtras,\n painted: (as?: string) => ReturnType<typeof paintKeys>,\n): unknown {\n switch (kind) {\n case 'rect':\n // The rect path lives at the origin and the pose carries position:\n // `pathInPoseFrame` rebases a rect path onto the pose box, so don't\n // double-count the position.\n return { path: rectPath(0, 0, bounds.width, bounds.height), ...painted() };\n case 'ellipse':\n return { path: ellipsePath(bounds), ...painted() };\n case 'path': {\n const e = extras as { path: PolygonPath; closed: boolean; data?: Readonly<Record<string, unknown>> };\n return { ...e.data, path: e.path, ...painted(), ...(e.closed ? {} : { fill: null }) };\n }\n case 'text': {\n // The built-in text tool drags an empty text box you then type into, so\n // `extras` carries no content. The kit:text painter matches on\n // `data.text != null` and applies style defaults at render time.\n const e = extras as Partial<{ text: string }>;\n return { text: e.text ?? '', fill: DEFAULT_TEXT_FILL };\n }\n case 'sticky':\n return stickyData(extras as StickyStyle & { text?: string });\n case 'image': {\n // The bitmap is loaded + cached by `imageCache` keyed on `src`;\n // only the (serializable) `src` lives on the node.\n const e = extras as Partial<{ src: string; opacity: number }>;\n return { image: { src: e.src ?? '', ...(e.opacity !== undefined ? { opacity: e.opacity } : {}) } };\n }\n default:\n return null;\n }\n}\n\nexport function useInsertDepSource(\n scene: Scene<unknown, string, unknown>,\n adapter: OpsApplier,\n factories?: Record<string, InsertNodeFactory>,\n paint: InsertPaint = paletteInsertPaint,\n): void {\n const sceneRef = useLatest(scene);\n const adapterRef = useLatest(adapter);\n const factoriesRef = useLatest(factories);\n const paintRef = useLatest(paint);\n const registry = useDepRegistry();\n const insertSeqRef = useRef(0);\n const liveRef = useRef<InsertLive>({ gesture: null });\n useDepSource('insertLive', () => liveRef.current);\n\n useDepSource('insert', (): InsertDep => {\n const sc = sceneRef.current;\n const ad = adapterRef.current;\n\n const site = () => insertSite(sc, registry.get('insertInto')?.get(), registry.get('canDropInto'));\n const build: NonNullable<InsertDep['build']> = (bounds, extras) => {\n const kind = extras.kind;\n const { parent, layer, local } = site();\n const seq = ++insertSeqRef.current;\n const id = sc.mintId();\n let asked: ReturnType<InsertPaint> | undefined;\n const painted = (as: string = kind) => paintKeys(asked = paintRef.current(as, seq));\n\n // The nascent node's extent — drag AABB reconciled with whatever\n // richer geometry `extras` carries.\n const extent = insertPreviewExtent({ shape: kind, bounds, extras });\n const pose: unknown = extent.bounds;\n\n // Consumer factory wins over the kit default for this kind. It owns the node's\n // data + optional pose; the dep still supplies id/layer/op.\n const factory = factoriesRef.current?.[kind];\n if (factory) {\n const built = factory(bounds, extras);\n if (built === null) return null;\n return {\n id,\n ops: [createInsertOp({ node: { id, kind: 'mark', layer, parent, pose: local(built.pose ?? pose), data: built.data } as unknown as { id: string }, label: `Insert ${kind}` })],\n };\n }\n\n const geom = extent.geometry;\n let data: unknown;\n\n switch (geom.kind) {\n case 'line':\n data = { path: linePath(geom.a, geom.b), ...painted(), fill: null };\n break;\n case 'polygon':\n data = {\n path: regularPolygonPath(geom.center, geom.radius, geom.sides, geom.rotation),\n generator: { kind: 'polygon', sides: geom.sides, rotation: geom.rotation } satisfies ShapeGenerator,\n ...painted(),\n };\n break;\n case 'star':\n data = {\n path: starPath(geom.center, geom.outerRadius, geom.points, geom.innerRadius, geom.rotation),\n generator: {\n kind: 'star',\n points: geom.points,\n innerRadiusRatio: geom.outerRadius === 0 ? 0.5 : geom.innerRadius / geom.outerRadius,\n rotation: geom.rotation,\n } satisfies ShapeGenerator,\n ...painted(),\n };\n break;\n case 'pencil': {\n const samples = geom.samples as { x: number; y: number }[];\n if (samples.length >= 4) {\n data = { path: schneiderFit(samples, 2.0), ...painted() };\n } else if (samples.length >= 2) {\n data = { path: polygonFromPoints(samples), ...painted() };\n } else {\n data = { path: rectPath(0, 0, extent.bounds.width, extent.bounds.height), ...painted('rect') };\n }\n break;\n }\n case 'box':\n data = boxKindData(kind, extent.bounds, extras, painted);\n if (data === null) {\n console.warn(`weasel insertDep: no factory for kind=\"${kind}\". Skipping insert.`);\n return null;\n }\n break;\n }\n\n data = withFillRule(data, asked?.fillRule);\n const min = minSizeOf(extras);\n if (min) data = { ...(data as object), minSize: min };\n return {\n id,\n ops: [createInsertOp({ node: { id, kind: 'mark', layer, parent, pose: local(pose), data } as unknown as { id: string }, label: `Insert ${kind}` })],\n };\n };\n return {\n layer: () => site().layer,\n build,\n commit(bounds, extras, ends): NodeId | null {\n const built = build(bounds, extras, ends);\n if (built === null) return null;\n ad.applyOps(built.ops, `Insert ${extras.kind}`);\n return built.id;\n },\n };\n });\n}\n"],"mappings":"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"}
@@ -1,11 +1,13 @@
1
- import { composeWorldPose, composesFrames } from "../../core/scene/composeFrame.js";
1
+ import { composeChildFrame, composesFrames } from "../../core/scene/composeFrame.js";
2
2
  import { definesFrame } from "../../core/scene/effectivePose.js";
3
+ import { viewPoseAdapter } from "../../core/scene/scrollOffsets.js";
3
4
  import { insertParent } from "../../interactions/actions/insert/parent.js";
4
5
 
5
6
  //#region src/canvas/deps/insertSite.ts
6
7
  /**
7
8
  * Where an insert lands: the container the `insertInto` dep names, on that container's
8
9
  * layer, with the pose made local to it when the scene composes frames —
10
+ * through its scroll offset, since the world pose is where the view shows it —
9
11
  * or the top of the tree, on the first layer, when it names no container.
10
12
  */
11
13
  function insertSite(sc, into, canDropInto) {
@@ -22,11 +24,11 @@ function insertSite(sc, into, canDropInto) {
22
24
  layer: parent.layer,
23
25
  local: (p) => p
24
26
  };
25
- const frame = composeWorldPose({
27
+ const frame = composeChildFrame(viewPoseAdapter(sc, {
26
28
  getPose: (id) => sc.get(id).pose,
27
29
  getParent: (id) => sc.get(id)?.parent ?? null,
28
30
  definesFrame: (id) => definesFrame(sc.get(id) ?? {})
29
- }, parent.id, composition.compose);
31
+ }), parent.id, composition.compose);
30
32
  return {
31
33
  parent: parent.id,
32
34
  layer: parent.layer,
@@ -1 +1 @@
1
- {"version":3,"file":"insertSite.js","names":[],"sources":["../../../src/canvas/deps/insertSite.ts"],"sourcesContent":["import type { Scene, NodeId } from 'core/scene/types';\nimport type { CanDropIntoDep } from 'interactions/actions/layoutDeps';\nimport { insertParent } from 'interactions/actions/insert/parent';\nimport { composesFrames, composeWorldPose } from 'core/scene/composeFrame';\nimport { definesFrame } from 'core/scene/effectivePose';\n\n/** Where a new node lands: its parent, its layer, and how a world pose becomes its stored one. */\nexport interface InsertSite {\n parent: NodeId | null;\n layer: string;\n local: (world: unknown) => unknown;\n}\n\n/**\n * Where an insert lands: the container the `insertInto` dep names, on that container's\n * layer, with the pose made local to it when the scene composes frames —\n * or the top of the tree, on the first layer, when it names no container.\n */\nexport function insertSite(\n sc: Pick<Scene<unknown, string, unknown>, 'get' | 'layers' | 'composition'>,\n into: string | null | undefined,\n canDropInto?: CanDropIntoDep,\n): InsertSite {\n const parentId = insertParent(sc, into, canDropInto);\n if (parentId === null) {\n return { parent: null, layer: (sc.layers[0]?.id ?? 'default') as string, local: (p) => p };\n }\n const parent = sc.get(parentId)!;\n const composition = sc.composition;\n if (composition === undefined || !composesFrames(composition)) {\n return { parent: parent.id, layer: parent.layer, local: (p) => p };\n }\n const frame = composeWorldPose({\n getPose: (id) => sc.get(id as NodeId)!.pose,\n getParent: (id) => sc.get(id as NodeId)?.parent ?? null,\n definesFrame: (id) => definesFrame(sc.get(id as NodeId) ?? {}),\n }, parent.id, composition.compose);\n return { parent: parent.id, layer: parent.layer, local: (p) => composition.decompose(frame, p) };\n}\n"],"mappings":";;;;;;;;;;AAkBA,SAAgB,WACd,IACA,MACA,aACY;CACZ,MAAM,WAAW,aAAa,IAAI,MAAM,WAAW;CACnD,IAAI,aAAa,MACf,OAAO;EAAE,QAAQ;EAAM,OAAQ,GAAG,OAAO,EAAE,EAAE,MAAM;EAAsB,QAAQ,MAAM;CAAE;CAE3F,MAAM,SAAS,GAAG,IAAI,QAAQ;CAC9B,MAAM,cAAc,GAAG;CACvB,IAAI,gBAAgB,UAAa,CAAC,eAAe,WAAW,GAC1D,OAAO;EAAE,QAAQ,OAAO;EAAI,OAAO,OAAO;EAAO,QAAQ,MAAM;CAAE;CAEnE,MAAM,QAAQ,iBAAiB;EAC7B,UAAU,OAAO,GAAG,IAAI,EAAY,CAAC,CAAE;EACvC,YAAY,OAAO,GAAG,IAAI,EAAY,CAAC,EAAE,UAAU;EACnD,eAAe,OAAO,aAAa,GAAG,IAAI,EAAY,KAAK,CAAC,CAAC;CAC/D,GAAG,OAAO,IAAI,YAAY,OAAO;CACjC,OAAO;EAAE,QAAQ,OAAO;EAAI,OAAO,OAAO;EAAO,QAAQ,MAAM,YAAY,UAAU,OAAO,CAAC;CAAE;AACjG"}
1
+ {"version":3,"file":"insertSite.js","names":[],"sources":["../../../src/canvas/deps/insertSite.ts"],"sourcesContent":["import type { Scene, NodeId } from 'core/scene/types';\nimport type { CanDropIntoDep } from 'interactions/actions/layoutDeps';\nimport { insertParent } from 'interactions/actions/insert/parent';\nimport { composeChildFrame, composesFrames, type PoseAdapter } from 'core/scene/composeFrame';\nimport { viewPoseAdapter } from 'core/scene/scrollOffsets';\nimport { definesFrame } from 'core/scene/effectivePose';\n\n/** Where a new node lands: its parent, its layer, and how a world pose becomes its stored one. */\nexport interface InsertSite {\n parent: NodeId | null;\n layer: string;\n local: (world: unknown) => unknown;\n}\n\n/**\n * Where an insert lands: the container the `insertInto` dep names, on that container's\n * layer, with the pose made local to it when the scene composes frames —\n * through its scroll offset, since the world pose is where the view shows it —\n * or the top of the tree, on the first layer, when it names no container.\n */\nexport function insertSite(\n sc: Pick<Scene<unknown, string, unknown>, 'get' | 'layers' | 'composition'> & Partial<Pick<Scene<unknown, string, unknown>, 'scroll'>>,\n into: string | null | undefined,\n canDropInto?: CanDropIntoDep,\n): InsertSite {\n const parentId = insertParent(sc, into, canDropInto);\n if (parentId === null) {\n return { parent: null, layer: (sc.layers[0]?.id ?? 'default') as string, local: (p) => p };\n }\n const parent = sc.get(parentId)!;\n const composition = sc.composition;\n if (composition === undefined || !composesFrames(composition)) {\n return { parent: parent.id, layer: parent.layer, local: (p) => p };\n }\n const frame = composeChildFrame(viewPoseAdapter(sc, {\n getPose: (id) => sc.get(id as NodeId)!.pose,\n getParent: (id) => sc.get(id as NodeId)?.parent ?? null,\n definesFrame: (id) => definesFrame(sc.get(id as NodeId) ?? {}),\n } as PoseAdapter<unknown>), parent.id, composition.compose);\n return { parent: parent.id, layer: parent.layer, local: (p) => composition.decompose(frame, p) };\n}\n"],"mappings":";;;;;;;;;;;;AAoBA,SAAgB,WACd,IACA,MACA,aACY;CACZ,MAAM,WAAW,aAAa,IAAI,MAAM,WAAW;CACnD,IAAI,aAAa,MACf,OAAO;EAAE,QAAQ;EAAM,OAAQ,GAAG,OAAO,EAAE,EAAE,MAAM;EAAsB,QAAQ,MAAM;CAAE;CAE3F,MAAM,SAAS,GAAG,IAAI,QAAQ;CAC9B,MAAM,cAAc,GAAG;CACvB,IAAI,gBAAgB,UAAa,CAAC,eAAe,WAAW,GAC1D,OAAO;EAAE,QAAQ,OAAO;EAAI,OAAO,OAAO;EAAO,QAAQ,MAAM;CAAE;CAEnE,MAAM,QAAQ,kBAAkB,gBAAgB,IAAI;EAClD,UAAU,OAAO,GAAG,IAAI,EAAY,CAAC,CAAE;EACvC,YAAY,OAAO,GAAG,IAAI,EAAY,CAAC,EAAE,UAAU;EACnD,eAAe,OAAO,aAAa,GAAG,IAAI,EAAY,KAAK,CAAC,CAAC;CAC/D,CAAyB,GAAG,OAAO,IAAI,YAAY,OAAO;CAC1D,OAAO;EAAE,QAAQ,OAAO;EAAI,OAAO,OAAO;EAAO,QAAQ,MAAM,YAAY,UAAU,OAAO,CAAC;CAAE;AACjG"}
@@ -3,22 +3,11 @@ import { useLatest } from "@weasel-js/react";
3
3
  import { useDepSource } from "@weasel-js/routing/react";
4
4
 
5
5
  //#region src/canvas/deps/nodeAtPoint.ts
6
- /**
7
- * `useNodeAtPointDepSource` — wires the `nodeAtPoint` dep consumed by
8
- * `moveAction` (reparent-on-drop) and any other action needing a
9
- * single-best pick. Delegates to `<SceneCanvas>`'s `pickEvery` (the
10
- * back-to-front pose-walking picker) so consumer-supplied geometry
11
- * overrides are honored automatically.
12
- *
13
- * The exclude set is consulted front-to-back: the dep returns the
14
- * topmost id that isn't in `exclude`, which lets callers ignore the
15
- * node(s) they're currently manipulating without separate plumbing.
16
- */
17
6
  function useNodeAtPointDepSource(pickEvery) {
18
7
  const pickRef = useLatest(pickEvery);
19
8
  useDepSource("nodeAtPoint", () => {
20
9
  return (point, exclude) => {
21
- const ids = pickRef.current(point.x, point.y);
10
+ const ids = pickRef.current(point);
22
11
  if (ids.length === 0) return null;
23
12
  if (!exclude) return asNodeId(ids[ids.length - 1]);
24
13
  const ex = exclude instanceof Set ? exclude : new Set(exclude);
@@ -1 +1 @@
1
- {"version":3,"file":"nodeAtPoint.js","names":[],"sources":["../../../src/canvas/deps/nodeAtPoint.ts"],"sourcesContent":["/**\n * `useNodeAtPointDepSource` — wires the `nodeAtPoint` dep consumed by\n * `moveAction` (reparent-on-drop) and any other action needing a\n * single-best pick. Delegates to `<SceneCanvas>`'s `pickEvery` (the\n * back-to-front pose-walking picker) so consumer-supplied geometry\n * overrides are honored automatically.\n *\n * The exclude set is consulted front-to-back: the dep returns the\n * topmost id that isn't in `exclude`, which lets callers ignore the\n * node(s) they're currently manipulating without separate plumbing.\n */\nimport { useDepSource } from '@weasel-js/routing/react';\nimport { useLatest } from '@weasel-js/react';\nimport type { NodeAtPointDep } from 'interactions/actions/depSchema';\nimport { asNodeId } from 'core/scene/types';\n\nexport function useNodeAtPointDepSource(\n pickEvery: (worldX: number, worldY: number) => string[],\n): void {\n const pickRef = useLatest(pickEvery);\n\n useDepSource('nodeAtPoint', (): NodeAtPointDep => {\n return (point, exclude) => {\n const ids = pickRef.current(point.x, point.y);\n if (ids.length === 0) return null;\n if (!exclude) {\n // `pickEvery` returns back-to-front; topmost is the last entry.\n return asNodeId(ids[ids.length - 1]);\n }\n const ex = exclude instanceof Set ? exclude : new Set(exclude);\n for (let i = ids.length - 1; i >= 0; i--) {\n if (!ex.has(asNodeId(ids[i]))) return asNodeId(ids[i]);\n }\n return null;\n };\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,SAAgB,wBACd,WACM;CACN,MAAM,UAAU,UAAU,SAAS;CAEnC,aAAa,qBAAqC;EAChD,QAAQ,OAAO,YAAY;GACzB,MAAM,MAAM,QAAQ,QAAQ,MAAM,GAAG,MAAM,CAAC;GAC5C,IAAI,IAAI,WAAW,GAAG,OAAO;GAC7B,IAAI,CAAC,SAEH,OAAO,SAAS,IAAI,IAAI,SAAS,EAAE;GAErC,MAAM,KAAK,mBAAmB,MAAM,UAAU,IAAI,IAAI,OAAO;GAC7D,KAAK,IAAI,IAAI,IAAI,SAAS,GAAG,KAAK,GAAG,KACnC,IAAI,CAAC,GAAG,IAAI,SAAS,IAAI,EAAE,CAAC,GAAG,OAAO,SAAS,IAAI,EAAE;GAEvD,OAAO;EACT;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"nodeAtPoint.js","names":[],"sources":["../../../src/canvas/deps/nodeAtPoint.ts"],"sourcesContent":["/**\n * `useNodeAtPointDepSource` — wires the `nodeAtPoint` dep consumed by\n * `moveAction` (reparent-on-drop) and any other action needing a\n * single-best pick. Delegates to `<SceneCanvas>`'s `pickEvery` (the\n * back-to-front pose-walking picker) so consumer-supplied geometry\n * overrides are honored automatically.\n *\n * The exclude set is consulted front-to-back: the dep returns the\n * topmost id that isn't in `exclude`, which lets callers ignore the\n * node(s) they're currently manipulating without separate plumbing.\n */\nimport type { WorldPoint } from '@weasel-js/routing';\nimport { useDepSource } from '@weasel-js/routing/react';\nimport { useLatest } from '@weasel-js/react';\nimport type { NodeAtPointDep } from 'interactions/actions/depSchema';\nimport { asNodeId } from 'core/scene/types';\n\nexport function useNodeAtPointDepSource(\n pickEvery: (world: WorldPoint) => string[],\n): void {\n const pickRef = useLatest(pickEvery);\n\n useDepSource('nodeAtPoint', (): NodeAtPointDep => {\n return (point, exclude) => {\n const ids = pickRef.current(point);\n if (ids.length === 0) return null;\n if (!exclude) {\n // `pickEvery` returns back-to-front; topmost is the last entry.\n return asNodeId(ids[ids.length - 1]);\n }\n const ex = exclude instanceof Set ? exclude : new Set(exclude);\n for (let i = ids.length - 1; i >= 0; i--) {\n if (!ex.has(asNodeId(ids[i]))) return asNodeId(ids[i]);\n }\n return null;\n };\n });\n}\n"],"mappings":";;;;;AAiBA,SAAgB,wBACd,WACM;CACN,MAAM,UAAU,UAAU,SAAS;CAEnC,aAAa,qBAAqC;EAChD,QAAQ,OAAO,YAAY;GACzB,MAAM,MAAM,QAAQ,QAAQ,KAAK;GACjC,IAAI,IAAI,WAAW,GAAG,OAAO;GAC7B,IAAI,CAAC,SAEH,OAAO,SAAS,IAAI,IAAI,SAAS,EAAE;GAErC,MAAM,KAAK,mBAAmB,MAAM,UAAU,IAAI,IAAI,OAAO;GAC7D,KAAK,IAAI,IAAI,IAAI,SAAS,GAAG,KAAK,GAAG,KACnC,IAAI,CAAC,GAAG,IAAI,SAAS,IAAI,EAAE,CAAC,GAAG,OAAO,SAAS,IAAI,EAAE;GAEvD,OAAO;EACT;CACF,CAAC;AACH"}
@@ -2,9 +2,9 @@ import { sceneDependentsOf } from "../../core/scene/dependents.js";
2
2
  import { createTransformOp } from "../../core/ops/transform.js";
3
3
  import { createSetDataOp } from "../../core/ops/setData.js";
4
4
  import { createDeleteOp } from "../../core/ops/delete.js";
5
- import { pathEditPathOf, storeEditablePath } from "../../features/paths/editablePath.js";
6
- import { withoutShapeGenerator } from "../../features/paths/shapeGenerator.js";
7
- import { withoutGeometryBoundData } from "../../features/paths/pathEditExtension.js";
5
+ import { pathEditPathOf, storeEditablePath } from "../../domains/paths/editablePath.js";
6
+ import { withoutShapeGenerator } from "../../domains/paths/shapeGenerator.js";
7
+ import { withoutGeometryBoundData } from "../../domains/paths/pathEditExtension.js";
8
8
  import { writtenBy } from "../../core/ops/writtenBy.js";
9
9
 
10
10
  //#region src/canvas/deps/pathEditCommits.ts
@@ -1 +1 @@
1
- {"version":3,"file":"pathEditCommits.js","names":[],"sources":["../../../src/canvas/deps/pathEditCommits.ts"],"sourcesContent":["/**\n * What the `editAnchors` dep commits: an edit finished by every path-edit\n * extension, the other nodes the extensions change with it, and the same for\n * a whole-node transform's batch.\n */\nimport type { PointOrigin, PolygonPath } from '@weasel-js/geom';\nimport type { Op } from 'core/ops/types';\nimport { createTransformOp } from 'core/ops/transform';\nimport { createSetDataOp } from 'core/ops/setData';\nimport { createDeleteOp } from 'core/ops/delete';\nimport { writtenBy } from 'core/ops/writtenBy';\nimport type { TransformFollower, TransformPreviewNode } from 'interactions/actions/transformFinish';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport { sceneDependentsOf } from 'core/scene/dependents';\nimport { pathEditPathOf, storeEditablePath } from 'features/paths/editablePath';\nimport { withoutShapeGenerator } from 'features/paths/shapeGenerator';\nimport {\n withoutGeometryBoundData, type PathEditExtension, type PathEditFinishCtx, type PathEditOther, type PathTransformFinishCtx,\n} from 'features/paths/pathEditExtension';\n\ntype AnyScene = Scene<unknown, string, unknown>;\nexport type EditableNode = { pose: unknown; data: unknown };\n\n/** What {@link finishEdit} answers: the edited path, the data set beside it, and the other nodes it changes, by id. */\nexport interface Finished {\n path: PolygonPath;\n data: Record<string, unknown> | null;\n others: Map<string, PathEditOther>;\n}\n\n/** The scene as an extension's `finishEdit` reads it. */\nexport function finishCtx(sc: AnyScene, id: string, extensions: readonly PathEditExtension[]): PathEditFinishCtx {\n return {\n id,\n node(nid) {\n const node = sc.get(nid as NodeId);\n return node ? { pose: node.pose, data: node.data, dependsOn: node.dependsOn } : null;\n },\n path: (nid) => pathEditPathOf(sc.get(nid as NodeId) as EditableNode | undefined, extensions),\n dependents: (nid) => sceneDependentsOf(sc, nid as NodeId),\n };\n}\n\n/** `o` laid over what `others` already holds for its node. */\nfunction addOther(others: Map<string, PathEditOther>, o: PathEditOther): void {\n const had = others.get(o.id);\n others.set(o.id, {\n id: o.id,\n path: o.path ?? had?.path,\n data: o.data || had?.data ? { ...had?.data, ...o.data } : undefined,\n remove: o.remove || had?.remove,\n });\n}\n\n/** `worldPath` finished by each of `extensions` in turn, the data they set\n * beside it, and the other nodes they change; null when one cannot finish it. */\nexport function finishEdit(\n extensions: readonly PathEditExtension[],\n node: EditableNode,\n worldPath: PolygonPath,\n origins: readonly (PointOrigin | null)[] | undefined,\n ctx: PathEditFinishCtx,\n): Finished | null {\n let path = worldPath;\n let data: Record<string, unknown> | null = null;\n const others = new Map<string, PathEditOther>();\n for (const ext of extensions) {\n if (!ext.finishEdit) continue;\n const done = ext.finishEdit(node, path, origins, ctx);\n if (!done) return null;\n path = done.path;\n if (done.data) data = { ...(data ?? {}), ...done.data };\n for (const o of done.others ?? []) addOther(others, o);\n }\n return { path, data, others };\n}\n\n/** The ops that commit `others`, each from its node as committed. */\nexport function otherOps(\n sc: AnyScene,\n others: ReadonlyMap<string, PathEditOther>,\n label: string,\n extensions: readonly PathEditExtension[],\n): Op[] {\n return [...others.values()].flatMap((o) => {\n const node = sc.get(o.id as NodeId) as EditableNode | undefined;\n if (!node) return [];\n if (o.remove) return [createDeleteOp({ node: sc.get(o.id as NodeId)!, label })];\n if (o.path) return reshapeOps(o.id, node, o.path, label, o.data ?? null, extensions);\n return o.data ? [createSetDataOp({ id: o.id, from: node.data, to: { ...(node.data as object), ...o.data }, label })] : [];\n });\n}\n\n/** The ops that store `worldPath` where `node` keeps its polygon, with `patch` laid over its data. */\nexport function reshapeOps(\n id: string,\n node: EditableNode,\n worldPath: PolygonPath,\n label: string,\n patch: Record<string, unknown> | null,\n extensions: readonly PathEditExtension[],\n): Op[] {\n const next = storeEditablePath(node, worldPath, extensions);\n if (!next) return [];\n const reshape = createTransformOp({ id, from: node.pose, to: next.pose, label });\n // A path edited by hand is no longer what its generator or warp makes: it becomes plain geometry.\n // Its skin and constraints stay, renumbered by the caller's patch where it has one, and the\n // form it was drawn from as storing it left it.\n const data = withoutGeometryBoundData(\n next.data === node.data ? node.data : withoutShapeGenerator(next.data), ['skin', 'constraints', 'representation'],\n );\n if (data === node.data && !patch) return [reshape];\n return [reshape, createSetDataOp({ id, from: node.data, to: { ...(data as object), ...patch }, label })];\n}\n\n/** The other nodes `extensions` change along with a transform that leaves the nodes in `after` as given; null when one refuses it. */\nfunction transformOthers(\n sc: AnyScene,\n extensions: readonly PathEditExtension[],\n after: ReadonlyMap<string, EditableNode>,\n): Map<string, PathEditOther> | null {\n const others = new Map<string, PathEditOther>();\n const finishing = extensions.filter((e) => e.finishTransform);\n if (finishing.length === 0 || after.size === 0) return others;\n const nodeAfter = (id: string) => {\n const node = sc.get(id as NodeId);\n if (!node) return null;\n const written = after.get(id);\n return { pose: written?.pose ?? node.pose, data: written?.data ?? node.data, dependsOn: node.dependsOn };\n };\n const ctx: PathTransformFinishCtx = {\n ids: [...after.keys()],\n node: nodeAfter,\n path: (id) => pathEditPathOf(nodeAfter(id) ?? undefined, extensions),\n before: (id) => pathEditPathOf(sc.get(id as NodeId) as EditableNode | undefined, extensions),\n dependents: (id) => sceneDependentsOf(sc, id as NodeId),\n };\n for (const ext of finishing) {\n const done = ext.finishTransform!(ctx);\n if (!done) return null;\n for (const o of done) if (!after.has(o.id)) addOther(others, o);\n }\n return others;\n}\n\n/** `ops`, a whole-node transform's batch, with the ops `extensions` add for the other nodes it changes; null when one refuses it. */\nexport function transformOps(\n sc: AnyScene,\n extensions: readonly PathEditExtension[],\n ops: readonly Op[],\n label: string,\n): Op[] | null {\n const after = extensions.some((e) => e.finishTransform) ? writtenBy(sc, ops) : null;\n if (!after || after.size === 0) return [...ops];\n const others = transformOthers(sc, extensions, after);\n return others && [...ops, ...otherOps(sc, others, label, extensions)];\n}\n\n/**\n * The other nodes `extensions` change along with a transform frame that\n * poses the nodes in `poses` as given, each as it would be stored — what\n * {@link transformOps} would commit for that frame, read the same way. Empty\n * when nothing changes with it, or an extension refuses it.\n */\nexport function transformPreview(\n sc: AnyScene,\n extensions: readonly PathEditExtension[],\n poses: ReadonlyMap<string, unknown>,\n): TransformPreviewNode[] {\n if (poses.size === 0 || !extensions.some((e) => e.finishTransform)) return [];\n const after = new Map<string, EditableNode>();\n for (const [id, pose] of poses) {\n const node = sc.get(id as NodeId);\n if (node) after.set(id, { pose, data: node.data });\n }\n const others = transformOthers(sc, extensions, after);\n return [...(others?.values() ?? [])].flatMap((o) => {\n const node = sc.get(o.id as NodeId) as EditableNode | undefined;\n const stored = node && o.path && !o.remove ? storeEditablePath(node, o.path, extensions) : null;\n if (!node || !stored) return [];\n return [stored.data === node.data ? { id: o.id, pose: stored.pose } : { id: o.id, pose: stored.pose, data: stored.data }];\n });\n}\n\n/** The transform follower `extensions` make: each one's `finishTransform`, as\n * {@link transformOps} and {@link transformPreview} read it. Null when none\n * has one, so a transform runs no follower for them. */\nexport function pathEditFollower(sc: AnyScene, extensions: readonly PathEditExtension[]): TransformFollower | null {\n if (!extensions.some((e) => e.finishTransform)) return null;\n return {\n finish: (ops, label) => transformOps(sc, extensions, ops, label),\n preview: (poses) => transformPreview(sc, extensions, poses),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pathEditCommits.js","names":[],"sources":["../../../src/canvas/deps/pathEditCommits.ts"],"sourcesContent":["/**\n * What the `editAnchors` dep commits: an edit finished by every path-edit\n * extension, the other nodes the extensions change with it, and the same for\n * a whole-node transform's batch.\n */\nimport type { PointOrigin, PolygonPath } from '@weasel-js/geom';\nimport type { Op } from 'core/ops/types';\nimport { createTransformOp } from 'core/ops/transform';\nimport { createSetDataOp } from 'core/ops/setData';\nimport { createDeleteOp } from 'core/ops/delete';\nimport { writtenBy } from 'core/ops/writtenBy';\nimport type { TransformFollower, TransformPreviewNode } from 'interactions/actions/transformFinish';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport { sceneDependentsOf } from 'core/scene/dependents';\nimport { pathEditPathOf, storeEditablePath } from 'domains/paths/editablePath';\nimport { withoutShapeGenerator } from 'domains/paths/shapeGenerator';\nimport {\n withoutGeometryBoundData, type PathEditExtension, type PathEditFinishCtx, type PathEditOther, type PathTransformFinishCtx,\n} from 'domains/paths/pathEditExtension';\n\ntype AnyScene = Scene<unknown, string, unknown>;\nexport type EditableNode = { pose: unknown; data: unknown };\n\n/** What {@link finishEdit} answers: the edited path, the data set beside it, and the other nodes it changes, by id. */\nexport interface Finished {\n path: PolygonPath;\n data: Record<string, unknown> | null;\n others: Map<string, PathEditOther>;\n}\n\n/** The scene as an extension's `finishEdit` reads it. */\nexport function finishCtx(sc: AnyScene, id: string, extensions: readonly PathEditExtension[]): PathEditFinishCtx {\n return {\n id,\n node(nid) {\n const node = sc.get(nid as NodeId);\n return node ? { pose: node.pose, data: node.data, dependsOn: node.dependsOn } : null;\n },\n path: (nid) => pathEditPathOf(sc.get(nid as NodeId) as EditableNode | undefined, extensions),\n dependents: (nid) => sceneDependentsOf(sc, nid as NodeId),\n };\n}\n\n/** `o` laid over what `others` already holds for its node. */\nfunction addOther(others: Map<string, PathEditOther>, o: PathEditOther): void {\n const had = others.get(o.id);\n others.set(o.id, {\n id: o.id,\n path: o.path ?? had?.path,\n data: o.data || had?.data ? { ...had?.data, ...o.data } : undefined,\n remove: o.remove || had?.remove,\n });\n}\n\n/** `worldPath` finished by each of `extensions` in turn, the data they set\n * beside it, and the other nodes they change; null when one cannot finish it. */\nexport function finishEdit(\n extensions: readonly PathEditExtension[],\n node: EditableNode,\n worldPath: PolygonPath,\n origins: readonly (PointOrigin | null)[] | undefined,\n ctx: PathEditFinishCtx,\n): Finished | null {\n let path = worldPath;\n let data: Record<string, unknown> | null = null;\n const others = new Map<string, PathEditOther>();\n for (const ext of extensions) {\n if (!ext.finishEdit) continue;\n const done = ext.finishEdit(node, path, origins, ctx);\n if (!done) return null;\n path = done.path;\n if (done.data) data = { ...(data ?? {}), ...done.data };\n for (const o of done.others ?? []) addOther(others, o);\n }\n return { path, data, others };\n}\n\n/** The ops that commit `others`, each from its node as committed. */\nexport function otherOps(\n sc: AnyScene,\n others: ReadonlyMap<string, PathEditOther>,\n label: string,\n extensions: readonly PathEditExtension[],\n): Op[] {\n return [...others.values()].flatMap((o) => {\n const node = sc.get(o.id as NodeId) as EditableNode | undefined;\n if (!node) return [];\n if (o.remove) return [createDeleteOp({ node: sc.get(o.id as NodeId)!, label })];\n if (o.path) return reshapeOps(o.id, node, o.path, label, o.data ?? null, extensions);\n return o.data ? [createSetDataOp({ id: o.id, from: node.data, to: { ...(node.data as object), ...o.data }, label })] : [];\n });\n}\n\n/** The ops that store `worldPath` where `node` keeps its polygon, with `patch` laid over its data. */\nexport function reshapeOps(\n id: string,\n node: EditableNode,\n worldPath: PolygonPath,\n label: string,\n patch: Record<string, unknown> | null,\n extensions: readonly PathEditExtension[],\n): Op[] {\n const next = storeEditablePath(node, worldPath, extensions);\n if (!next) return [];\n const reshape = createTransformOp({ id, from: node.pose, to: next.pose, label });\n // A path edited by hand is no longer what its generator or warp makes: it becomes plain geometry.\n // Its skin and constraints stay, renumbered by the caller's patch where it has one, and the\n // form it was drawn from as storing it left it.\n const data = withoutGeometryBoundData(\n next.data === node.data ? node.data : withoutShapeGenerator(next.data), ['skin', 'constraints', 'representation'],\n );\n if (data === node.data && !patch) return [reshape];\n return [reshape, createSetDataOp({ id, from: node.data, to: { ...(data as object), ...patch }, label })];\n}\n\n/** The other nodes `extensions` change along with a transform that leaves the nodes in `after` as given; null when one refuses it. */\nfunction transformOthers(\n sc: AnyScene,\n extensions: readonly PathEditExtension[],\n after: ReadonlyMap<string, EditableNode>,\n): Map<string, PathEditOther> | null {\n const others = new Map<string, PathEditOther>();\n const finishing = extensions.filter((e) => e.finishTransform);\n if (finishing.length === 0 || after.size === 0) return others;\n const nodeAfter = (id: string) => {\n const node = sc.get(id as NodeId);\n if (!node) return null;\n const written = after.get(id);\n return { pose: written?.pose ?? node.pose, data: written?.data ?? node.data, dependsOn: node.dependsOn };\n };\n const ctx: PathTransformFinishCtx = {\n ids: [...after.keys()],\n node: nodeAfter,\n path: (id) => pathEditPathOf(nodeAfter(id) ?? undefined, extensions),\n before: (id) => pathEditPathOf(sc.get(id as NodeId) as EditableNode | undefined, extensions),\n dependents: (id) => sceneDependentsOf(sc, id as NodeId),\n };\n for (const ext of finishing) {\n const done = ext.finishTransform!(ctx);\n if (!done) return null;\n for (const o of done) if (!after.has(o.id)) addOther(others, o);\n }\n return others;\n}\n\n/** `ops`, a whole-node transform's batch, with the ops `extensions` add for the other nodes it changes; null when one refuses it. */\nexport function transformOps(\n sc: AnyScene,\n extensions: readonly PathEditExtension[],\n ops: readonly Op[],\n label: string,\n): Op[] | null {\n const after = extensions.some((e) => e.finishTransform) ? writtenBy(sc, ops) : null;\n if (!after || after.size === 0) return [...ops];\n const others = transformOthers(sc, extensions, after);\n return others && [...ops, ...otherOps(sc, others, label, extensions)];\n}\n\n/**\n * The other nodes `extensions` change along with a transform frame that\n * poses the nodes in `poses` as given, each as it would be stored — what\n * {@link transformOps} would commit for that frame, read the same way. Empty\n * when nothing changes with it, or an extension refuses it.\n */\nexport function transformPreview(\n sc: AnyScene,\n extensions: readonly PathEditExtension[],\n poses: ReadonlyMap<string, unknown>,\n): TransformPreviewNode[] {\n if (poses.size === 0 || !extensions.some((e) => e.finishTransform)) return [];\n const after = new Map<string, EditableNode>();\n for (const [id, pose] of poses) {\n const node = sc.get(id as NodeId);\n if (node) after.set(id, { pose, data: node.data });\n }\n const others = transformOthers(sc, extensions, after);\n return [...(others?.values() ?? [])].flatMap((o) => {\n const node = sc.get(o.id as NodeId) as EditableNode | undefined;\n const stored = node && o.path && !o.remove ? storeEditablePath(node, o.path, extensions) : null;\n if (!node || !stored) return [];\n return [stored.data === node.data ? { id: o.id, pose: stored.pose } : { id: o.id, pose: stored.pose, data: stored.data }];\n });\n}\n\n/** The transform follower `extensions` make: each one's `finishTransform`, as\n * {@link transformOps} and {@link transformPreview} read it. Null when none\n * has one, so a transform runs no follower for them. */\nexport function pathEditFollower(sc: AnyScene, extensions: readonly PathEditExtension[]): TransformFollower | null {\n if (!extensions.some((e) => e.finishTransform)) return null;\n return {\n finish: (ops, label) => transformOps(sc, extensions, ops, label),\n preview: (poses) => transformPreview(sc, extensions, poses),\n };\n}\n"],"mappings":"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"}
@@ -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"}