@weasel-js/core 1.13.0 → 1.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (741) hide show
  1. package/CHANGELOG.md +326 -0
  2. package/README.md +8 -12
  3. package/dist/affordances/hitAffordanceRegions.js +1 -1
  4. package/dist/affordances/hitAffordanceRegions.js.map +1 -1
  5. package/dist/affordances/pathAnchors.js.map +1 -1
  6. package/dist/animation/clipTargets.js +1 -1
  7. package/dist/animation/clipTargets.js.map +1 -1
  8. package/dist/animation/poseTarget.js +5 -32
  9. package/dist/animation/poseTarget.js.map +1 -1
  10. package/dist/{autoPoseDescriptor-CZ1eXbzY.d.ts → autoPoseDescriptor-C25QVb0W.d.ts} +1 -1
  11. package/dist/barrel/canvas.js +8 -8
  12. package/dist/barrel/chrome.js +9 -9
  13. package/dist/barrel/input.js +1 -1
  14. package/dist/barrel/interactions.js +3 -3
  15. package/dist/barrel/paint.js +2 -2
  16. package/dist/barrel/paths.js +19 -17
  17. package/dist/barrel/renderer.js +11 -7
  18. package/dist/barrel/routing.js +4 -1
  19. package/dist/barrel/scene.js +16 -12
  20. package/dist/barrel/text.js +5 -5
  21. package/dist/barrel/viewport.js +8 -8
  22. package/dist/canvas/Canvas.js +2 -2
  23. package/dist/canvas/Canvas.js.map +1 -1
  24. package/dist/canvas/CanvasView.js +20 -14
  25. package/dist/canvas/CanvasView.js.map +1 -1
  26. package/dist/canvas/GestureReason.js +64 -0
  27. package/dist/canvas/GestureReason.js.map +1 -0
  28. package/dist/canvas/GestureReason.module.js +7 -0
  29. package/dist/canvas/GestureReason.module.js.map +1 -0
  30. package/dist/canvas/LeanSceneCanvas.js +3 -1
  31. package/dist/canvas/LeanSceneCanvas.js.map +1 -1
  32. package/dist/canvas/NodeShape.js +2 -0
  33. package/dist/canvas/NodeShape.js.map +1 -1
  34. package/dist/canvas/PickHud.js +7 -3
  35. package/dist/canvas/PickHud.js.map +1 -1
  36. package/dist/canvas/SceneCanvas/CanvasKitProviders.js +1 -1
  37. package/dist/canvas/SceneCanvas/CanvasKitProviders.js.map +1 -1
  38. package/dist/canvas/SceneCanvas/DevHuds.js +2 -2
  39. package/dist/canvas/SceneCanvas/DevHuds.js.map +1 -1
  40. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +4 -2
  41. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js.map +1 -1
  42. package/dist/canvas/SceneCanvas/SceneCanvasInput.js +3 -1
  43. package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
  44. package/dist/canvas/SceneCanvas/brushOverlay.js.map +1 -1
  45. package/dist/canvas/SceneCanvas/builtinToolSets.js +17 -9
  46. package/dist/canvas/SceneCanvas/builtinToolSets.js.map +1 -1
  47. package/dist/canvas/SceneCanvas/canvasPassThrough.js +2 -1
  48. package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
  49. package/dist/canvas/SceneCanvas/defaultNodeProperties.js +75 -19
  50. package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
  51. package/dist/canvas/SceneCanvas/defaultNodeRouting.js +7 -1
  52. package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
  53. package/dist/canvas/SceneCanvas/defaultTextEditor.js +108 -0
  54. package/dist/canvas/SceneCanvas/defaultTextEditor.js.map +1 -0
  55. package/dist/canvas/SceneCanvas/describePresets.js +47 -0
  56. package/dist/canvas/SceneCanvas/describePresets.js.map +1 -0
  57. package/dist/canvas/SceneCanvas/features.js +57 -16
  58. package/dist/canvas/SceneCanvas/features.js.map +1 -1
  59. package/dist/canvas/SceneCanvas/mergeLayers.js +10 -1
  60. package/dist/canvas/SceneCanvas/mergeLayers.js.map +1 -1
  61. package/dist/canvas/SceneCanvas/namedPresets.js +52 -24
  62. package/dist/canvas/SceneCanvas/namedPresets.js.map +1 -1
  63. package/dist/canvas/SceneCanvas/presets/arrange.js +35 -10
  64. package/dist/canvas/SceneCanvas/presets/arrange.js.map +1 -1
  65. package/dist/canvas/SceneCanvas/presets/baseline.js +9 -0
  66. package/dist/canvas/SceneCanvas/presets/baseline.js.map +1 -0
  67. package/dist/canvas/SceneCanvas/presets/chrome.js.map +1 -1
  68. package/dist/canvas/SceneCanvas/presets/composites.js +43 -0
  69. package/dist/canvas/SceneCanvas/presets/composites.js.map +1 -0
  70. package/dist/canvas/SceneCanvas/presets/edit.js +79 -26
  71. package/dist/canvas/SceneCanvas/presets/edit.js.map +1 -1
  72. package/dist/canvas/SceneCanvas/presets/ingest.js +1 -0
  73. package/dist/canvas/SceneCanvas/presets/ingest.js.map +1 -1
  74. package/dist/canvas/SceneCanvas/presets/paths.js +58 -16
  75. package/dist/canvas/SceneCanvas/presets/paths.js.map +1 -1
  76. package/dist/canvas/SceneCanvas/presets/select.js +4 -2
  77. package/dist/canvas/SceneCanvas/presets/select.js.map +1 -1
  78. package/dist/canvas/SceneCanvas/presets/tools.js +24 -0
  79. package/dist/canvas/SceneCanvas/presets/tools.js.map +1 -0
  80. package/dist/canvas/SceneCanvas/presets/transform.js +4 -0
  81. package/dist/canvas/SceneCanvas/presets/transform.js.map +1 -1
  82. package/dist/canvas/SceneCanvas/presets/view.js +3 -1
  83. package/dist/canvas/SceneCanvas/presets/view.js.map +1 -1
  84. package/dist/canvas/SceneCanvas/props.js.map +1 -1
  85. package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js +1 -1
  86. package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js.map +1 -1
  87. package/dist/canvas/SceneCanvas/toolRegistry.js +5 -4
  88. package/dist/canvas/SceneCanvas/toolRegistry.js.map +1 -1
  89. package/dist/canvas/SceneCanvas/useCanvasTools.js +26 -10
  90. package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
  91. package/dist/canvas/SceneCanvas/useContributionRoles.js +15 -2
  92. package/dist/canvas/SceneCanvas/useContributionRoles.js.map +1 -1
  93. package/dist/canvas/SceneCanvas/useDepartureGhostLayer.js +5 -4
  94. package/dist/canvas/SceneCanvas/useDepartureGhostLayer.js.map +1 -1
  95. package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js +1 -1
  96. package/dist/canvas/SceneCanvas/useNodeAtPoint.js.map +1 -1
  97. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +9 -8
  98. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
  99. package/dist/canvas/SceneCanvas/useSceneCanvasPathEdit.js +2 -2
  100. package/dist/canvas/SceneCanvas/useSceneCanvasPathEdit.js.map +1 -1
  101. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +4 -1
  102. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
  103. package/dist/canvas/SceneCanvas/useSceneChrome.js +7 -4
  104. package/dist/canvas/SceneCanvas/useSceneChrome.js.map +1 -1
  105. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js +9 -9
  106. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js.map +1 -1
  107. package/dist/canvas/SceneCanvas/useScenePicking.js +4 -7
  108. package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
  109. package/dist/canvas/SceneCanvas/useSceneRedrawSources.js +2 -1
  110. package/dist/canvas/SceneCanvas/useSceneRedrawSources.js.map +1 -1
  111. package/dist/canvas/SceneCanvas/useSceneSelectTool.js +6 -6
  112. package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
  113. package/dist/canvas/SceneCanvas/useSceneStandardActions.js +2 -2
  114. package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
  115. package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js +1 -1
  116. package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js.map +1 -1
  117. package/dist/canvas/SceneCanvas/useSurfaceViewInputs.js.map +1 -1
  118. package/dist/canvas/SceneCanvas/useToolKeybindings.js +2 -2
  119. package/dist/canvas/SceneCanvas/useToolKeybindings.js.map +1 -1
  120. package/dist/canvas/SceneCanvas/useViewportActions.js +5 -2
  121. package/dist/canvas/SceneCanvas/useViewportActions.js.map +1 -1
  122. package/dist/canvas/SceneCanvas/worldPointAt.js.map +1 -1
  123. package/dist/canvas/SceneCanvas.js +22 -11
  124. package/dist/canvas/SceneCanvas.js.map +1 -1
  125. package/dist/canvas/SceneViewCanvas.js +1 -0
  126. package/dist/canvas/SceneViewCanvas.js.map +1 -1
  127. package/dist/canvas/ViewMarker.js.map +1 -1
  128. package/dist/canvas/accentColor.js +14 -1
  129. package/dist/canvas/accentColor.js.map +1 -1
  130. package/dist/canvas/affordanceAt.js +2 -2
  131. package/dist/canvas/affordanceAt.js.map +1 -1
  132. package/dist/canvas/buildSceneTree.js +5 -3
  133. package/dist/canvas/buildSceneTree.js.map +1 -1
  134. package/dist/canvas/deps/editAnchors.js +4 -4
  135. package/dist/canvas/deps/editAnchors.js.map +1 -1
  136. package/dist/canvas/deps/enteredGroup.js +14 -5
  137. package/dist/canvas/deps/enteredGroup.js.map +1 -1
  138. package/dist/canvas/deps/ingestion.js +5 -1
  139. package/dist/canvas/deps/ingestion.js.map +1 -1
  140. package/dist/canvas/deps/insert.js.map +1 -1
  141. package/dist/canvas/deps/insertSite.js +5 -3
  142. package/dist/canvas/deps/insertSite.js.map +1 -1
  143. package/dist/canvas/deps/nodeAtPoint.js +1 -12
  144. package/dist/canvas/deps/nodeAtPoint.js.map +1 -1
  145. package/dist/canvas/deps/pathEditCommits.js +3 -3
  146. package/dist/canvas/deps/pathEditCommits.js.map +1 -1
  147. package/dist/canvas/deps/slice.js +16 -2
  148. package/dist/canvas/deps/slice.js.map +1 -1
  149. package/dist/canvas/deps/snap.js +5 -5
  150. package/dist/canvas/deps/snap.js.map +1 -1
  151. package/dist/canvas/deps/textEdit.js +5 -6
  152. package/dist/canvas/deps/textEdit.js.map +1 -1
  153. package/dist/canvas/derivedPath.js +8 -3
  154. package/dist/canvas/derivedPath.js.map +1 -1
  155. package/dist/canvas/getNodeAtPoint.js +2 -2
  156. package/dist/canvas/getNodeAtPoint.js.map +1 -1
  157. package/dist/canvas/insertPreviewExtent.js.map +1 -1
  158. package/dist/canvas/layerSlots.js.map +1 -1
  159. package/dist/canvas/nodeShapes/measurePainter.js +1 -1
  160. package/dist/canvas/nodeShapes/measurePainter.js.map +1 -1
  161. package/dist/canvas/nodeShapes/strokedBounds.js +5 -3
  162. package/dist/canvas/nodeShapes/strokedBounds.js.map +1 -1
  163. package/dist/canvas/overlayRoleStrokes.js +6 -0
  164. package/dist/canvas/overlayRoleStrokes.js.map +1 -1
  165. package/dist/canvas/pickIndex/scenePickIndex.js +10 -12
  166. package/dist/canvas/pickIndex/scenePickIndex.js.map +1 -1
  167. package/dist/canvas/sceneAdapter.js +10 -19
  168. package/dist/canvas/sceneAdapter.js.map +1 -1
  169. package/dist/canvas/sceneClipboard.js +17 -4
  170. package/dist/canvas/sceneClipboard.js.map +1 -1
  171. package/dist/canvas/sceneViewRender.js +3 -2
  172. package/dist/canvas/sceneViewRender.js.map +1 -1
  173. package/dist/canvas/surfaceContribution.js.map +1 -1
  174. package/dist/canvas/useCanvasPaint.js +10 -4
  175. package/dist/canvas/useCanvasPaint.js.map +1 -1
  176. package/dist/canvas/useHitObserver.js +1 -1
  177. package/dist/canvas/useHitObserver.js.map +1 -1
  178. package/dist/canvas/useViewAim.js +1 -1
  179. package/dist/canvas/useViewAim.js.map +1 -1
  180. package/dist/canvas/useViewHelpers.js +8 -5
  181. package/dist/canvas/useViewHelpers.js.map +1 -1
  182. package/dist/canvas/useViewNesting.js +39 -12
  183. package/dist/canvas/useViewNesting.js.map +1 -1
  184. package/dist/canvas/viewInputs.js.map +1 -1
  185. package/dist/canvas/viewMarkers.js +2 -2
  186. package/dist/canvas/viewMarkers.js.map +1 -1
  187. package/dist/canvas/viewRegistry.js +2 -2
  188. package/dist/canvas/viewRegistry.js.map +1 -1
  189. package/dist/canvas/viewSnap.js +67 -0
  190. package/dist/canvas/viewSnap.js.map +1 -0
  191. package/dist/clipboard.d.ts +6 -12
  192. package/dist/{clone-qb2e1F5p.d.ts → clone-Bz4iqGfE.d.ts} +10 -5
  193. package/dist/clone.d.ts +5 -5
  194. package/dist/core/geometry/booleanOfPaths.js +23 -0
  195. package/dist/core/geometry/booleanOfPaths.js.map +1 -0
  196. package/dist/core/geometry/pathPoseDescriptor.js +12 -9
  197. package/dist/core/geometry/pathPoseDescriptor.js.map +1 -1
  198. package/dist/core/geometry/poseDescriptor.js +12 -3
  199. package/dist/core/geometry/poseDescriptor.js.map +1 -1
  200. package/dist/core/geometry/targetFrame.js +2 -13
  201. package/dist/core/geometry/targetFrame.js.map +1 -1
  202. package/dist/core/layers/render.js +2 -1
  203. package/dist/core/layers/render.js.map +1 -1
  204. package/dist/core/layers/retain.js +5 -3
  205. package/dist/core/layers/retain.js.map +1 -1
  206. package/dist/core/ops/setPath.js +3 -0
  207. package/dist/core/ops/setPath.js.map +1 -1
  208. package/dist/core/paint/meshKindLazy.js.map +1 -1
  209. package/dist/core/paint/paintKindEntry.js.map +1 -1
  210. package/dist/core/paint/paintKinds.js +8 -1
  211. package/dist/core/paint/paintKinds.js.map +1 -1
  212. package/dist/core/scene/NodeProperties.js.map +1 -1
  213. package/dist/core/scene/NodeRouting.js.map +1 -1
  214. package/dist/core/scene/booleanGroup.js +33 -0
  215. package/dist/core/scene/booleanGroup.js.map +1 -0
  216. package/dist/core/scene/booleanOfChildren.js +53 -0
  217. package/dist/core/scene/booleanOfChildren.js.map +1 -0
  218. package/dist/core/scene/carryDescendants.js +18 -6
  219. package/dist/core/scene/carryDescendants.js.map +1 -1
  220. package/dist/core/scene/composeFrame.js +42 -5
  221. package/dist/core/scene/composeFrame.js.map +1 -1
  222. package/dist/core/scene/composePose.js +35 -16
  223. package/dist/core/scene/composePose.js.map +1 -1
  224. package/dist/core/scene/depMemo.js +36 -18
  225. package/dist/core/scene/depMemo.js.map +1 -1
  226. package/dist/core/scene/derivedParts.js +2 -23
  227. package/dist/core/scene/derivedParts.js.map +1 -1
  228. package/dist/core/scene/effectivePose.js +10 -0
  229. package/dist/core/scene/effectivePose.js.map +1 -1
  230. package/dist/core/scene/historyForm.js +5 -4
  231. package/dist/core/scene/historyForm.js.map +1 -1
  232. package/dist/core/scene/kitOps.js +5 -71
  233. package/dist/core/scene/kitOps.js.map +1 -1
  234. package/dist/core/scene/kitRegistry.js +5 -0
  235. package/dist/core/scene/kitRegistry.js.map +1 -1
  236. package/dist/core/scene/layerOps.js +82 -0
  237. package/dist/core/scene/layerOps.js.map +1 -0
  238. package/dist/core/scene/layoutPass.js +14 -12
  239. package/dist/core/scene/layoutPass.js.map +1 -1
  240. package/dist/core/scene/lockGuard.js +9 -3
  241. package/dist/core/scene/lockGuard.js.map +1 -1
  242. package/dist/core/scene/nestedHit.js +5 -5
  243. package/dist/core/scene/nestedHit.js.map +1 -1
  244. package/dist/core/scene/nodeFlags.js +8 -2
  245. package/dist/core/scene/nodeFlags.js.map +1 -1
  246. package/dist/core/scene/nodeGates.js +31 -2
  247. package/dist/core/scene/nodeGates.js.map +1 -1
  248. package/dist/core/scene/pathEffects/effects.js +22 -3
  249. package/dist/core/scene/pathEffects/effects.js.map +1 -1
  250. package/dist/core/scene/pathEffects/textAlong.js +16 -3
  251. package/dist/core/scene/pathEffects/textAlong.js.map +1 -1
  252. package/dist/core/scene/pathEffects/textAlongBands.js +65 -0
  253. package/dist/core/scene/pathEffects/textAlongBands.js.map +1 -0
  254. package/dist/core/scene/reconcileSpecs.js +1 -1
  255. package/dist/core/scene/reconcileSpecs.js.map +1 -1
  256. package/dist/core/scene/scene.js +11 -5
  257. package/dist/core/scene/scene.js.map +1 -1
  258. package/dist/core/scene/sceneEdits.js +5 -2
  259. package/dist/core/scene/sceneEdits.js.map +1 -1
  260. package/dist/core/scene/scenePoseAdapter.js +10 -1
  261. package/dist/core/scene/scenePoseAdapter.js.map +1 -1
  262. package/dist/core/scene/scrollOffsets.js +93 -0
  263. package/dist/core/scene/scrollOffsets.js.map +1 -0
  264. package/dist/core/scene/serialization.js +15 -5
  265. package/dist/core/scene/serialization.js.map +1 -1
  266. package/dist/core/scene/statedFields.js +2 -1
  267. package/dist/core/scene/statedFields.js.map +1 -1
  268. package/dist/core/scene/strategyView.js +35 -0
  269. package/dist/core/scene/strategyView.js.map +1 -0
  270. package/dist/core/scene/types.js.map +1 -1
  271. package/dist/core/scene/useScene.js +2 -0
  272. package/dist/core/scene/useScene.js.map +1 -1
  273. package/dist/core/scene/worldSave.js +87 -0
  274. package/dist/core/scene/worldSave.js.map +1 -0
  275. package/dist/core/selection/selectionTarget.js +1 -1
  276. package/dist/core/selection/selectionTarget.js.map +1 -1
  277. package/dist/{cornerHandles-CNCb7aTY.d.ts → cornerHandles-DpmQM_z5.d.ts} +1 -1
  278. package/dist/{depSchema-CpIQzKWQ.d.ts → depSchema-C3BwxitB.d.ts} +119 -99
  279. package/dist/devtools-protocol.d.ts +2 -2
  280. package/dist/devtools.d.ts +2 -2
  281. package/dist/{features → domains}/chrome-caps/buildChromeCtx.js +1 -1
  282. package/dist/domains/chrome-caps/buildChromeCtx.js.map +1 -0
  283. package/dist/{features → domains}/chrome-caps/conditions.js +1 -1
  284. package/dist/domains/chrome-caps/conditions.js.map +1 -0
  285. package/dist/{features → domains}/chrome-caps/defaults.js +1 -1
  286. package/dist/domains/chrome-caps/defaults.js.map +1 -0
  287. package/dist/{features → domains}/chrome-caps/resolve.js +1 -1
  288. package/dist/domains/chrome-caps/resolve.js.map +1 -0
  289. package/dist/{features → domains}/chrome-caps/useChromeCaps.js +1 -1
  290. package/dist/domains/chrome-caps/useChromeCaps.js.map +1 -0
  291. package/dist/{features → domains}/chrome-caps/useHoverTracking.js +1 -1
  292. package/dist/domains/chrome-caps/useHoverTracking.js.map +1 -0
  293. package/dist/{features → domains}/ingestion/contentHandlers.js +20 -3
  294. package/dist/domains/ingestion/contentHandlers.js.map +1 -0
  295. package/dist/domains/ingestion/ghost.js +56 -0
  296. package/dist/domains/ingestion/ghost.js.map +1 -0
  297. package/dist/{features → domains}/ingestion/imageHandler.js +1 -1
  298. package/dist/domains/ingestion/imageHandler.js.map +1 -0
  299. package/dist/domains/ingestion/kitHandlers.js +22 -0
  300. package/dist/domains/ingestion/kitHandlers.js.map +1 -0
  301. package/dist/{features → domains}/ingestion/openFilePicker.js +1 -1
  302. package/dist/domains/ingestion/openFilePicker.js.map +1 -0
  303. package/dist/{features → domains}/ingestion/placement.js +1 -1
  304. package/dist/domains/ingestion/placement.js.map +1 -0
  305. package/dist/{features → domains}/ingestion/svgHandler.js +1 -1
  306. package/dist/domains/ingestion/svgHandler.js.map +1 -0
  307. package/dist/{features → domains}/ingestion/textHandler.js +9 -7
  308. package/dist/domains/ingestion/textHandler.js.map +1 -0
  309. package/dist/{features → domains}/ingestion/useCanvasIngestion.js +13 -15
  310. package/dist/domains/ingestion/useCanvasIngestion.js.map +1 -0
  311. package/dist/{features → domains}/ingestion/weaselJsonHandler.js +1 -1
  312. package/dist/domains/ingestion/weaselJsonHandler.js.map +1 -0
  313. package/dist/{features → domains}/longPress/longPressFeedback.js +1 -1
  314. package/dist/domains/longPress/longPressFeedback.js.map +1 -0
  315. package/dist/{features → domains}/measure/actionIds.js +1 -1
  316. package/dist/domains/measure/actionIds.js.map +1 -0
  317. package/dist/{features → domains}/measure/measureCommands.js +1 -1
  318. package/dist/domains/measure/measureCommands.js.map +1 -0
  319. package/dist/{features → domains}/measure/measureContribution.js +1 -1
  320. package/dist/domains/measure/measureContribution.js.map +1 -0
  321. package/dist/{features → domains}/measure/measureEdits.js +1 -1
  322. package/dist/domains/measure/measureEdits.js.map +1 -0
  323. package/dist/{features → domains}/measure/measureGestures.js +4 -7
  324. package/dist/domains/measure/measureGestures.js.map +1 -0
  325. package/dist/{features → domains}/measure/measureHit.js +1 -1
  326. package/dist/domains/measure/measureHit.js.map +1 -0
  327. package/dist/{features → domains}/measure/measureLayer.js +1 -1
  328. package/dist/domains/measure/measureLayer.js.map +1 -0
  329. package/dist/{features → domains}/measure/measurement.js +1 -1
  330. package/dist/domains/measure/measurement.js.map +1 -0
  331. package/dist/{features → domains}/measure/measurements.js +2 -2
  332. package/dist/domains/measure/measurements.js.map +1 -0
  333. package/dist/{features → domains}/modes/modeLayers.js +1 -1
  334. package/dist/domains/modes/modeLayers.js.map +1 -0
  335. package/dist/{features → domains}/modes/modeTriggers.js +3 -6
  336. package/dist/domains/modes/modeTriggers.js.map +1 -0
  337. package/dist/{features → domains}/pathEffects/effectSources.js +1 -1
  338. package/dist/domains/pathEffects/effectSources.js.map +1 -0
  339. package/dist/{features → domains}/pathEffects/index.js +1 -1
  340. package/dist/domains/pathEffects/index.js.map +1 -0
  341. package/dist/{features → domains}/pathEffects/readSource.js +1 -1
  342. package/dist/domains/pathEffects/readSource.js.map +1 -0
  343. package/dist/{features → domains}/pathEffects/textItems.js +11 -2
  344. package/dist/domains/pathEffects/textItems.js.map +1 -0
  345. package/dist/{features → domains}/pathEffects/useEffectSourcesLayer.js +1 -1
  346. package/dist/domains/pathEffects/useEffectSourcesLayer.js.map +1 -0
  347. package/dist/{features → domains}/paths/anchorData.js +1 -1
  348. package/dist/domains/paths/anchorData.js.map +1 -0
  349. package/dist/{features → domains}/paths/anchorMarkers.js +9 -7
  350. package/dist/domains/paths/anchorMarkers.js.map +1 -0
  351. package/dist/{features → domains}/paths/editablePath.js +1 -1
  352. package/dist/domains/paths/editablePath.js.map +1 -0
  353. package/dist/{features → domains}/paths/index.js +3 -3
  354. package/dist/{features → domains}/paths/originProjection.js +1 -1
  355. package/dist/domains/paths/originProjection.js.map +1 -0
  356. package/dist/{features → domains}/paths/pathEditExtension.js +1 -1
  357. package/dist/domains/paths/pathEditExtension.js.map +1 -0
  358. package/dist/{features → domains}/paths/pathEditState.js +1 -1
  359. package/dist/domains/paths/pathEditState.js.map +1 -0
  360. package/dist/{features → domains}/paths/pathEditingOverlayLayer.js +1 -1
  361. package/dist/domains/paths/pathEditingOverlayLayer.js.map +1 -0
  362. package/dist/{features → domains}/paths/pathLayer.js +1 -1
  363. package/dist/domains/paths/pathLayer.js.map +1 -0
  364. package/dist/{features → domains}/paths/pathRepresentation.js +1 -1
  365. package/dist/domains/paths/pathRepresentation.js.map +1 -0
  366. package/dist/{features → domains}/paths/pathSnap/glyphs.js +1 -1
  367. package/dist/domains/paths/pathSnap/glyphs.js.map +1 -0
  368. package/dist/{features → domains}/paths/pathSnap/pathSnapSource.js +1 -1
  369. package/dist/domains/paths/pathSnap/pathSnapSource.js.map +1 -0
  370. package/dist/{features → domains}/paths/pathSnap/sceneIndex.js +1 -1
  371. package/dist/domains/paths/pathSnap/sceneIndex.js.map +1 -0
  372. package/dist/{features → domains}/paths/pathSnap/snapGeometry.js +3 -2
  373. package/dist/domains/paths/pathSnap/snapGeometry.js.map +1 -0
  374. package/dist/{features → domains}/paths/penPreviewLayer.js +1 -1
  375. package/dist/domains/paths/penPreviewLayer.js.map +1 -0
  376. package/dist/{features → domains}/paths/shapeGenerator.js +6 -4
  377. package/dist/domains/paths/shapeGenerator.js.map +1 -0
  378. package/dist/{features → domains}/paths/strokeOutline.js +1 -1
  379. package/dist/domains/paths/strokeOutline.js.map +1 -0
  380. package/dist/{features → domains}/paths/useAnchorFields.js +1 -1
  381. package/dist/domains/paths/useAnchorFields.js.map +1 -0
  382. package/dist/{features → domains}/paths/usePathEdit.js +1 -1
  383. package/dist/domains/paths/usePathEdit.js.map +1 -0
  384. package/dist/{features → domains}/poseRun/usePoseRun.js +1 -1
  385. package/dist/domains/poseRun/usePoseRun.js.map +1 -0
  386. package/dist/{features → domains}/selection/enteredGroupFrame.js +49 -10
  387. package/dist/domains/selection/enteredGroupFrame.js.map +1 -0
  388. package/dist/{features → domains}/selection/enteredGroupScope.js +1 -1
  389. package/dist/domains/selection/enteredGroupScope.js.map +1 -0
  390. package/dist/domains/selection/enteredOperands.js +29 -0
  391. package/dist/domains/selection/enteredOperands.js.map +1 -0
  392. package/dist/{features → domains}/selection/handleCommands.js +1 -1
  393. package/dist/domains/selection/handleCommands.js.map +1 -0
  394. package/dist/{features → domains}/selection/overlay.js +1 -1
  395. package/dist/domains/selection/overlay.js.map +1 -0
  396. package/dist/{features → domains}/selection/selectionPose.js +1 -1
  397. package/dist/domains/selection/selectionPose.js.map +1 -0
  398. package/dist/{features → domains}/snap/angle2d.js +1 -1
  399. package/dist/domains/snap/angle2d.js.map +1 -0
  400. package/dist/{features → domains}/snap/debugCandidates.js +1 -1
  401. package/dist/domains/snap/debugCandidates.js.map +1 -0
  402. package/dist/{features → domains}/snap/gather.js +1 -1
  403. package/dist/domains/snap/gather.js.map +1 -0
  404. package/dist/{features → domains}/snap/inputSubspace.js +1 -1
  405. package/dist/domains/snap/inputSubspace.js.map +1 -0
  406. package/dist/{features → domains}/snap/lazySession.js +1 -1
  407. package/dist/domains/snap/lazySession.js.map +1 -0
  408. package/dist/{features → domains}/snap/marks.js +1 -1
  409. package/dist/domains/snap/marks.js.map +1 -0
  410. package/dist/{features → domains}/snap/outcomeStore.js +1 -1
  411. package/dist/domains/snap/outcomeStore.js.map +1 -0
  412. package/dist/{features → domains}/snap/pointSnap.js +1 -1
  413. package/dist/domains/snap/pointSnap.js.map +1 -0
  414. package/dist/{features → domains}/snap/probes2d.js +1 -1
  415. package/dist/domains/snap/probes2d.js.map +1 -0
  416. package/dist/{features → domains}/snap/readoutDraw.js +1 -1
  417. package/dist/domains/snap/readoutDraw.js.map +1 -0
  418. package/dist/{features → domains}/snap/readoutLayer.js +1 -1
  419. package/dist/domains/snap/readoutLayer.js.map +1 -0
  420. package/dist/{features → domains}/snap/registry.js +1 -1
  421. package/dist/domains/snap/registry.js.map +1 -0
  422. package/dist/{features → domains}/snap/resizeBox.js +1 -1
  423. package/dist/domains/snap/resizeBox.js.map +1 -0
  424. package/dist/{features → domains}/snap/roles.js +1 -1
  425. package/dist/domains/snap/roles.js.map +1 -0
  426. package/dist/{features → domains}/snap/rotationSource.js +1 -1
  427. package/dist/domains/snap/rotationSource.js.map +1 -0
  428. package/dist/{features → domains}/snap/sceneReads.js +24 -3
  429. package/dist/domains/snap/sceneReads.js.map +1 -0
  430. package/dist/{features → domains}/snap/sceneSession2d.js +3 -2
  431. package/dist/domains/snap/sceneSession2d.js.map +1 -0
  432. package/dist/{features → domains}/snap/screen.js +1 -1
  433. package/dist/domains/snap/screen.js.map +1 -0
  434. package/dist/{features → domains}/snap/session2d.js +3 -2
  435. package/dist/domains/snap/session2d.js.map +1 -0
  436. package/dist/{features → domains}/snap/spanSnap.js +1 -1
  437. package/dist/domains/snap/spanSnap.js.map +1 -0
  438. package/dist/{features → domains}/snap/stepAngles.js +1 -1
  439. package/dist/domains/snap/stepAngles.js.map +1 -0
  440. package/dist/{features → domains}/text/editingDrawOne.js +4 -4
  441. package/dist/domains/text/editingDrawOne.js.map +1 -0
  442. package/dist/domains/text/hostTextEditors.js +24 -0
  443. package/dist/domains/text/hostTextEditors.js.map +1 -0
  444. package/dist/{features → domains}/text/index.js +1 -1
  445. package/dist/{features → domains}/text/sceneTextDrafts.js +1 -1
  446. package/dist/domains/text/sceneTextDrafts.js.map +1 -0
  447. package/dist/{features → domains}/text/textHitAt.js +18 -2
  448. package/dist/domains/text/textHitAt.js.map +1 -0
  449. package/dist/{features → domains}/text/textLayer.js +1 -1
  450. package/dist/domains/text/textLayer.js.map +1 -0
  451. package/dist/{features → domains}/text/useSceneTextEdit.js +11 -3
  452. package/dist/domains/text/useSceneTextEdit.js.map +1 -0
  453. package/dist/{features → domains}/viewports/aim.js +1 -1
  454. package/dist/domains/viewports/aim.js.map +1 -0
  455. package/dist/{features → domains}/viewports/viewMarker.js +23 -5
  456. package/dist/domains/viewports/viewMarker.js.map +1 -0
  457. package/dist/{features → domains}/viewports/viewMarkerDrag.js +3 -3
  458. package/dist/domains/viewports/viewMarkerDrag.js.map +1 -0
  459. package/dist/{features → domains}/viewports/viewResolver.js +1 -1
  460. package/dist/domains/viewports/viewResolver.js.map +1 -0
  461. package/dist/{features → domains}/viewports/viewportLayer.js +1 -1
  462. package/dist/domains/viewports/viewportLayer.js.map +1 -0
  463. package/dist/icons.table.js +1 -1
  464. package/dist/icons.table.js.map +1 -1
  465. package/dist/icons.table.json +106 -6
  466. package/dist/index.d.ts +1441 -1050
  467. package/dist/index.js +90 -77
  468. package/dist/interactions/actions/admitsChild.js +6 -2
  469. package/dist/interactions/actions/admitsChild.js.map +1 -1
  470. package/dist/interactions/actions/align/align.js +1 -4
  471. package/dist/interactions/actions/align/align.js.map +1 -1
  472. package/dist/interactions/actions/booleans/booleanGroupAction.js +66 -0
  473. package/dist/interactions/actions/booleans/booleanGroupAction.js.map +1 -0
  474. package/dist/interactions/actions/booleans/keymap.js +52 -0
  475. package/dist/interactions/actions/booleans/keymap.js.map +1 -0
  476. package/dist/interactions/actions/booleans/operands.js +1 -1
  477. package/dist/interactions/actions/booleans/pieces.js +4 -11
  478. package/dist/interactions/actions/booleans/pieces.js.map +1 -1
  479. package/dist/interactions/actions/clipboard/action.js +3 -7
  480. package/dist/interactions/actions/clipboard/action.js.map +1 -1
  481. package/dist/interactions/actions/clipboard/clipboardOps.js +1 -1
  482. package/dist/interactions/actions/clipboard/clipboardOps.js.map +1 -1
  483. package/dist/interactions/actions/clipboard/materializePaste.js.map +1 -1
  484. package/dist/interactions/actions/defaults/anchorEditing.js +6 -6
  485. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  486. package/dist/interactions/actions/defaults/bendSegment.js +1 -1
  487. package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
  488. package/dist/interactions/actions/defaults/containerScroll.js +170 -0
  489. package/dist/interactions/actions/defaults/containerScroll.js.map +1 -0
  490. package/dist/interactions/actions/defaults/contextMenu.js +2 -5
  491. package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
  492. package/dist/interactions/actions/defaults/delete.js +1 -1
  493. package/dist/interactions/actions/defaults/delete.js.map +1 -1
  494. package/dist/interactions/actions/defaults/duplicate.js +1 -3
  495. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  496. package/dist/interactions/actions/defaults/enterGroup.js +7 -12
  497. package/dist/interactions/actions/defaults/enterGroup.js.map +1 -1
  498. package/dist/interactions/actions/defaults/enterPathEdit.js +4 -8
  499. package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
  500. package/dist/interactions/actions/defaults/group.js +12 -24
  501. package/dist/interactions/actions/defaults/group.js.map +1 -1
  502. package/dist/interactions/actions/defaults/ingest.js +18 -10
  503. package/dist/interactions/actions/defaults/ingest.js.map +1 -1
  504. package/dist/interactions/actions/defaults/insertPathAnchor.js +3 -3
  505. package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
  506. package/dist/interactions/actions/defaults/nudgeSteps.js +3 -21
  507. package/dist/interactions/actions/defaults/nudgeSteps.js.map +1 -1
  508. package/dist/interactions/actions/defaults/pathEditMarks.js.map +1 -1
  509. package/dist/interactions/actions/defaults/selectDeep.js +2 -2
  510. package/dist/interactions/actions/defaults/selectDeep.js.map +1 -1
  511. package/dist/interactions/actions/distribute/distribute.js.map +1 -1
  512. package/dist/interactions/actions/dropVerdict.js +9 -0
  513. package/dist/interactions/actions/dropVerdict.js.map +1 -0
  514. package/dist/interactions/actions/edit-anchors/action.js +2 -2
  515. package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
  516. package/dist/interactions/actions/edit-anchors/extensionDrags.js.map +1 -1
  517. package/dist/interactions/actions/edit-anchors/geometry.js +8 -6
  518. package/dist/interactions/actions/edit-anchors/geometry.js.map +1 -1
  519. package/dist/interactions/actions/edit-anchors/handleDrag.js.map +1 -1
  520. package/dist/interactions/actions/edit-anchors/preview.js +1 -1
  521. package/dist/interactions/actions/edit-anchors/preview.js.map +1 -1
  522. package/dist/interactions/actions/flip/action.js +3 -2
  523. package/dist/interactions/actions/flip/action.js.map +1 -1
  524. package/dist/interactions/actions/geometryProjection.js +8 -3
  525. package/dist/interactions/actions/geometryProjection.js.map +1 -1
  526. package/dist/interactions/actions/gestureFrames.js +1 -0
  527. package/dist/interactions/actions/gestureFrames.js.map +1 -1
  528. package/dist/interactions/actions/insert/action.js +6 -2
  529. package/dist/interactions/actions/insert/action.js.map +1 -1
  530. package/dist/interactions/actions/insert/frame.js +1 -1
  531. package/dist/interactions/actions/insert/frame.js.map +1 -1
  532. package/dist/interactions/actions/insert/placeAction.js +6 -8
  533. package/dist/interactions/actions/insert/placeAction.js.map +1 -1
  534. package/dist/interactions/actions/insert/session.js +2 -2
  535. package/dist/interactions/actions/insert/session.js.map +1 -1
  536. package/dist/interactions/actions/move/action.js +6 -15
  537. package/dist/interactions/actions/move/action.js.map +1 -1
  538. package/dist/interactions/actions/move/behaviors/layoutDrop.js +12 -2
  539. package/dist/interactions/actions/move/behaviors/layoutDrop.js.map +1 -1
  540. package/dist/interactions/actions/move/behaviors/reparentOnDrop.js +29 -10
  541. package/dist/interactions/actions/move/behaviors/reparentOnDrop.js.map +1 -1
  542. package/dist/interactions/actions/move/behaviors/snapToContainer.js +42 -6
  543. package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
  544. package/dist/interactions/actions/move/capture.js +4 -8
  545. package/dist/interactions/actions/move/capture.js.map +1 -1
  546. package/dist/interactions/actions/move/commit/index.js.map +1 -1
  547. package/dist/interactions/actions/move/commit/layoutDrop.js +4 -3
  548. package/dist/interactions/actions/move/commit/layoutDrop.js.map +1 -1
  549. package/dist/interactions/actions/move/commit/layoutRelease.js +15 -9
  550. package/dist/interactions/actions/move/commit/layoutRelease.js.map +1 -1
  551. package/dist/interactions/actions/move/commit/reparent.js +19 -13
  552. package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
  553. package/dist/interactions/actions/move/delta.js +51 -5
  554. package/dist/interactions/actions/move/delta.js.map +1 -1
  555. package/dist/interactions/actions/move/frame.js +8 -4
  556. package/dist/interactions/actions/move/frame.js.map +1 -1
  557. package/dist/interactions/actions/move/layout/container.js +19 -9
  558. package/dist/interactions/actions/move/layout/container.js.map +1 -1
  559. package/dist/interactions/actions/move/layout/dragged.js +2 -2
  560. package/dist/interactions/actions/move/layout/dragged.js.map +1 -1
  561. package/dist/interactions/actions/move/layout/dropPass.js +36 -18
  562. package/dist/interactions/actions/move/layout/dropPass.js.map +1 -1
  563. package/dist/interactions/actions/move/layout/exits.js +2 -2
  564. package/dist/interactions/actions/move/layout/exits.js.map +1 -1
  565. package/dist/interactions/actions/move/layout/glide.js +5 -5
  566. package/dist/interactions/actions/move/layout/glide.js.map +1 -1
  567. package/dist/interactions/actions/move/layout/view.js +55 -0
  568. package/dist/interactions/actions/move/layout/view.js.map +1 -0
  569. package/dist/interactions/actions/move/refusal.js +52 -0
  570. package/dist/interactions/actions/move/refusal.js.map +1 -0
  571. package/dist/interactions/actions/move/session.js +9 -8
  572. package/dist/interactions/actions/move/session.js.map +1 -1
  573. package/dist/interactions/actions/move/translate.js +10 -4
  574. package/dist/interactions/actions/move/translate.js.map +1 -1
  575. package/dist/interactions/actions/moveNodes.js +21 -5
  576. package/dist/interactions/actions/moveNodes.js.map +1 -1
  577. package/dist/interactions/actions/pathCommands/pathNodes.js +3 -3
  578. package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -1
  579. package/dist/interactions/actions/planeInput.js +14 -13
  580. package/dist/interactions/actions/planeInput.js.map +1 -1
  581. package/dist/interactions/actions/poseFrame.js +21 -8
  582. package/dist/interactions/actions/poseFrame.js.map +1 -1
  583. package/dist/interactions/actions/resize/action.js +1 -1
  584. package/dist/interactions/actions/resize/action.js.map +1 -1
  585. package/dist/interactions/actions/resize/aspect.js +1 -1
  586. package/dist/interactions/actions/resize/aspect.js.map +1 -1
  587. package/dist/interactions/actions/resize/commit.js +10 -1
  588. package/dist/interactions/actions/resize/commit.js.map +1 -1
  589. package/dist/interactions/actions/resize/frame.js +3 -2
  590. package/dist/interactions/actions/resize/frame.js.map +1 -1
  591. package/dist/interactions/actions/resize/held.js +44 -0
  592. package/dist/interactions/actions/resize/held.js.map +1 -0
  593. package/dist/interactions/actions/resize/session.js +3 -1
  594. package/dist/interactions/actions/resize/session.js.map +1 -1
  595. package/dist/interactions/actions/resolveOverlays.js +9 -0
  596. package/dist/interactions/actions/resolveOverlays.js.map +1 -1
  597. package/dist/interactions/actions/resolvePreviews.js +23 -7
  598. package/dist/interactions/actions/resolvePreviews.js.map +1 -1
  599. package/dist/interactions/actions/rotate/action.js +1 -1
  600. package/dist/interactions/actions/rotate/action.js.map +1 -1
  601. package/dist/interactions/actions/rotate/frame.js +1 -1
  602. package/dist/interactions/actions/rotate/frame.js.map +1 -1
  603. package/dist/interactions/actions/rotate/session.js +2 -2
  604. package/dist/interactions/actions/rotate/session.js.map +1 -1
  605. package/dist/interactions/actions/selectionSubtree.js +2 -4
  606. package/dist/interactions/actions/selectionSubtree.js.map +1 -1
  607. package/dist/interactions/actions/spatialReference.js +4 -9
  608. package/dist/interactions/actions/spatialReference.js.map +1 -1
  609. package/dist/interactions/gestures/dragRadial/dragRadial.js.map +1 -1
  610. package/dist/interactions/gestures/dragRect/dragRect.js.map +1 -1
  611. package/dist/kitSettingsSchema.js +2 -2
  612. package/dist/kitSettingsSchema.js.map +1 -1
  613. package/dist/{math-C_elShP_.d.ts → math-B_unOnF4.d.ts} +2 -2
  614. package/dist/math.d.ts +3 -3
  615. package/dist/move.d.ts +6 -6
  616. package/dist/{options-ClEm3SEl.d.ts → options-DAjkhbcs.d.ts} +5 -5
  617. package/dist/{poseDescriptor-DN2yfnq_.d.ts → poseDescriptor-CvSxVhCd.d.ts} +17 -4
  618. package/dist/resize.d.ts +6 -6
  619. package/dist/style.css +14 -0
  620. package/dist/test-seams.d.ts +11 -15
  621. package/dist/test-seams.js +1 -1
  622. package/dist/tools/builtin/eyedropper/useEyedropperTool.js +3 -6
  623. package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
  624. package/dist/tools/builtin/line/useLineTool.js.map +1 -1
  625. package/dist/tools/builtin/measure/useMeasureTool.js +2 -2
  626. package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
  627. package/dist/tools/builtin/pen/penHandle.js +2 -2
  628. package/dist/tools/builtin/pen/penHandle.js.map +1 -1
  629. package/dist/tools/builtin/pen/usePenTool.js +13 -19
  630. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  631. package/dist/tools/builtin/polygon/usePolygonTool.js +1 -1
  632. package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
  633. package/dist/tools/builtin/select/groupEntry.js +1 -1
  634. package/dist/tools/builtin/select/groupEntry.js.map +1 -1
  635. package/dist/tools/builtin/select/selectionContributions.js +1 -1
  636. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  637. package/dist/tools/builtin/select/useSelectTool.js +7 -7
  638. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  639. package/dist/tools/builtin/slice/useSliceTool.js +5 -8
  640. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  641. package/dist/tools/builtin/star/useStarTool.js +1 -1
  642. package/dist/tools/builtin/star/useStarTool.js.map +1 -1
  643. package/dist/tools/index.js +2 -1
  644. package/dist/{types-49uYJN3j.d.ts → types-A_sNJYRd.d.ts} +8 -0
  645. package/dist/{types-BEdRIhNc.d.ts → types-DW14eu9B.d.ts} +131 -36
  646. package/dist/{types-p2alu-R1.d.ts → types-VCtfchp-.d.ts} +4 -6
  647. package/dist/util/color.js +12 -14
  648. package/dist/util/color.js.map +1 -1
  649. package/dist/version.js +1 -1
  650. package/package.json +25 -24
  651. package/dist/canvas/poseCascade.js +0 -65
  652. package/dist/canvas/poseCascade.js.map +0 -1
  653. package/dist/features/chrome-caps/buildChromeCtx.js.map +0 -1
  654. package/dist/features/chrome-caps/conditions.js.map +0 -1
  655. package/dist/features/chrome-caps/defaults.js.map +0 -1
  656. package/dist/features/chrome-caps/resolve.js.map +0 -1
  657. package/dist/features/chrome-caps/useChromeCaps.js.map +0 -1
  658. package/dist/features/chrome-caps/useHoverTracking.js.map +0 -1
  659. package/dist/features/ingestion/contentHandlers.js.map +0 -1
  660. package/dist/features/ingestion/imageHandler.js.map +0 -1
  661. package/dist/features/ingestion/openFilePicker.js.map +0 -1
  662. package/dist/features/ingestion/placement.js.map +0 -1
  663. package/dist/features/ingestion/registerKitHandlers.js +0 -43
  664. package/dist/features/ingestion/registerKitHandlers.js.map +0 -1
  665. package/dist/features/ingestion/svgHandler.js.map +0 -1
  666. package/dist/features/ingestion/textHandler.js.map +0 -1
  667. package/dist/features/ingestion/useCanvasIngestion.js.map +0 -1
  668. package/dist/features/ingestion/weaselJsonHandler.js.map +0 -1
  669. package/dist/features/longPress/longPressFeedback.js.map +0 -1
  670. package/dist/features/measure/actionIds.js.map +0 -1
  671. package/dist/features/measure/measureCommands.js.map +0 -1
  672. package/dist/features/measure/measureContribution.js.map +0 -1
  673. package/dist/features/measure/measureEdits.js.map +0 -1
  674. package/dist/features/measure/measureGestures.js.map +0 -1
  675. package/dist/features/measure/measureHit.js.map +0 -1
  676. package/dist/features/measure/measureLayer.js.map +0 -1
  677. package/dist/features/measure/measurement.js.map +0 -1
  678. package/dist/features/measure/measurements.js.map +0 -1
  679. package/dist/features/modes/modeLayers.js.map +0 -1
  680. package/dist/features/modes/modeTriggers.js.map +0 -1
  681. package/dist/features/pathEffects/effectSources.js.map +0 -1
  682. package/dist/features/pathEffects/index.js.map +0 -1
  683. package/dist/features/pathEffects/readSource.js.map +0 -1
  684. package/dist/features/pathEffects/textItems.js.map +0 -1
  685. package/dist/features/pathEffects/useEffectSourcesLayer.js.map +0 -1
  686. package/dist/features/paths/anchorData.js.map +0 -1
  687. package/dist/features/paths/anchorMarkers.js.map +0 -1
  688. package/dist/features/paths/editablePath.js.map +0 -1
  689. package/dist/features/paths/originProjection.js.map +0 -1
  690. package/dist/features/paths/pathEditExtension.js.map +0 -1
  691. package/dist/features/paths/pathEditState.js.map +0 -1
  692. package/dist/features/paths/pathEditingOverlayLayer.js.map +0 -1
  693. package/dist/features/paths/pathLayer.js.map +0 -1
  694. package/dist/features/paths/pathRepresentation.js.map +0 -1
  695. package/dist/features/paths/pathSnap/glyphs.js.map +0 -1
  696. package/dist/features/paths/pathSnap/pathSnapSource.js.map +0 -1
  697. package/dist/features/paths/pathSnap/sceneIndex.js.map +0 -1
  698. package/dist/features/paths/pathSnap/snapGeometry.js.map +0 -1
  699. package/dist/features/paths/penPreviewLayer.js.map +0 -1
  700. package/dist/features/paths/shapeGenerator.js.map +0 -1
  701. package/dist/features/paths/strokeOutline.js.map +0 -1
  702. package/dist/features/paths/useAnchorFields.js.map +0 -1
  703. package/dist/features/paths/usePathEdit.js.map +0 -1
  704. package/dist/features/poseRun/usePoseRun.js.map +0 -1
  705. package/dist/features/selection/enteredGroupFrame.js.map +0 -1
  706. package/dist/features/selection/enteredGroupScope.js.map +0 -1
  707. package/dist/features/selection/handleCommands.js.map +0 -1
  708. package/dist/features/selection/overlay.js.map +0 -1
  709. package/dist/features/selection/selectionPose.js.map +0 -1
  710. package/dist/features/snap/angle2d.js.map +0 -1
  711. package/dist/features/snap/debugCandidates.js.map +0 -1
  712. package/dist/features/snap/gather.js.map +0 -1
  713. package/dist/features/snap/inputSubspace.js.map +0 -1
  714. package/dist/features/snap/lazySession.js.map +0 -1
  715. package/dist/features/snap/marks.js.map +0 -1
  716. package/dist/features/snap/outcomeStore.js.map +0 -1
  717. package/dist/features/snap/pointSnap.js.map +0 -1
  718. package/dist/features/snap/probes2d.js.map +0 -1
  719. package/dist/features/snap/readoutDraw.js.map +0 -1
  720. package/dist/features/snap/readoutLayer.js.map +0 -1
  721. package/dist/features/snap/registry.js.map +0 -1
  722. package/dist/features/snap/resizeBox.js.map +0 -1
  723. package/dist/features/snap/roles.js.map +0 -1
  724. package/dist/features/snap/rotationSource.js.map +0 -1
  725. package/dist/features/snap/sceneReads.js.map +0 -1
  726. package/dist/features/snap/sceneSession2d.js.map +0 -1
  727. package/dist/features/snap/screen.js.map +0 -1
  728. package/dist/features/snap/session2d.js.map +0 -1
  729. package/dist/features/snap/spanSnap.js.map +0 -1
  730. package/dist/features/snap/stepAngles.js.map +0 -1
  731. package/dist/features/text/editingDrawOne.js.map +0 -1
  732. package/dist/features/text/sceneTextDrafts.js.map +0 -1
  733. package/dist/features/text/textHitAt.js.map +0 -1
  734. package/dist/features/text/textLayer.js.map +0 -1
  735. package/dist/features/text/useSceneTextEdit.js.map +0 -1
  736. package/dist/features/viewports/aim.js.map +0 -1
  737. package/dist/features/viewports/viewMarker.js.map +0 -1
  738. package/dist/features/viewports/viewMarkerDrag.js.map +0 -1
  739. package/dist/features/viewports/viewResolver.js.map +0 -1
  740. package/dist/features/viewports/viewportLayer.js.map +0 -1
  741. /package/dist/{features → domains}/chrome-caps/index.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"planeInput.js","names":[],"sources":["../../../src/interactions/actions/planeInput.ts"],"sourcesContent":["/**\n * Editing a node on a parallax plane.\n *\n * The dispatcher hands every action the camera's world. A node on a layer\n * carrying `parallax` stores its pose in its plane's world, which the camera's\n * reaches through a `PlaneMap` that changes with the camera. An editing action\n * pairs the pointer with the pose it edits, so the two have to be in one world.\n *\n * `inPlane` wraps an action so its input is carried into the plane of the\n * layer it edits before the action reads it, and the chrome it publishes back\n * comes out in the camera's world. A dep that answers in world points\n * (`nodeAtPoint`, `snap`) keeps speaking the camera's world, and the seam\n * converts at its boundary.\n *\n * A selection can span planes. The edit is measured in one of them, and a\n * node on another is carried into it as the gesture starts and back out\n * through `planeOf` as it is now.\n *\n * The map is read afresh on every call: a camera panning under a held drag, or\n * a plane whose factors are being animated, moves the node with the pointer.\n */\nimport type {\n Action, ActionDeps, AffordanceHit, BindingOpts, DragSample, InvocationCtx, OngoingHandle,\n OngoingOverlay,\n} from '@weasel-js/routing';\nimport type { Scene } from 'core/scene/types';\nimport { asNodeId } from 'core/scene/types';\nimport {\n deriveParallaxView, fromPlane, planeMap, planeToPlane, rectFromPlane, rectToPlane, toPlane,\n type ParallaxOpts, type PlaneMap,\n} from 'core/viewport/parallax';\nimport type { View } from 'core/viewport/view';\nimport type { PoseDescriptor } from 'core/geometry/poseDescriptor';\nimport type { NodeAtPointDep, SnapDep, ViewApi } from './depSchema';\nimport type { SnapBegin } from './snapDep';\n\ntype Point = { x: number; y: number };\n\n/** Which scene layer an invocation edits, read once as it starts. `undefined`\n * means none: the action runs in the camera's world. */\nexport type EditedLayerOf = (deps: ActionDeps, affordance?: AffordanceHit) => string | undefined;\n\nconst layerOfNode = (deps: ActionDeps, id: string | null | undefined): string | undefined =>\n (id ? deps.scene?.get(asNodeId(id))?.layer : undefined);\n\n/** The layer of the node a selection edit acts on: the affordance's target\n * when the drag grabbed one, the first selected node otherwise. A selection\n * spanning planes is edited in that one node's plane. */\nexport const selectionLayer: EditedLayerOf = (deps, affordance) => {\n const selection = deps.selection;\n for (const id of [...(affordance?.targetIds ?? []), ...(selection?.get() ?? [])]) {\n const layer = layerOfNode(deps, id);\n if (layer !== undefined) return layer;\n }\n return undefined;\n};\n\n/** The layer the `insert` dep will put a new node on. */\nexport const insertLayer: EditedLayerOf = (deps) =>\n deps.insert?.layer?.();\n\n/** The layer of the path in anchor-edit mode. */\nexport const editingLayer: EditedLayerOf = (deps) =>\n layerOfNode(deps, deps.editAnchors?.editingId);\n\n/** How the world an invocation edits in maps into the world `layer`'s nodes\n * are stored in, read now. Null when they are the same world. */\nexport function planeOf(view: unknown, layer: string): PlaneMap | null {\n return (view as ViewApi | undefined)?.planeOf?.(layer) ?? null;\n}\n\n/** `m` run backwards; null stays null. */\nexport function invertPlane(m: PlaneMap | null): PlaneMap | null {\n return m && planeToPlane(m, null);\n}\n\n/** `pose` carried through `m`. The map is axis-aligned, so remapping the\n * pose's bounds carries it exactly when the map scales both axes alike. */\nexport function carryPose<P>(d: PoseDescriptor<P>, pose: P, m: PlaneMap | null): P {\n if (m === null) return pose;\n const b = d.getBounds(pose);\n return d.remapBounds(pose, b, rectToPlane(m, b));\n}\n\n/** `action`, with its input carried into the plane of the layer `layerOf`\n * names. An action in a scene with no `parallax` layer, or invoked with no\n * scene or view to read a plane from, runs exactly as it would unwrapped.\n *\n * An immediate action's world point is `params.worldX` / `params.worldY`,\n * the dispatcher's convention for a click; it is carried when present. */\nexport function inPlane<A extends Action>(action: A, layerOf: EditedLayerOf): A {\n const inner = action.invoker;\n if (!inner) return action;\n const declared = action.requires ?? [];\n const requires = [...new Set([...declared, 'scene', 'selection', 'view'])];\n if (inner.timing === 'immediate') {\n return {\n ...action,\n requires,\n invoker: {\n timing: 'immediate',\n run(deps: ActionDeps, params?: Record<string, unknown>): void {\n const plane = livePlane(deps, layerOf(deps), declared, null);\n if (plane === null) return inner.run(deps, params);\n const wx = params?.['worldX'];\n const wy = params?.['worldY'];\n const at = typeof wx === 'number' && typeof wy === 'number'\n ? toPlane(plane.map(), { x: wx, y: wy })\n : null;\n inner.run(plane.deps, at ? { ...params, worldX: at.x, worldY: at.y } : params);\n },\n },\n } as A;\n }\n return {\n ...action,\n requires,\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts?: BindingOpts): OngoingHandle {\n const plane = livePlane(\n ctx.deps, layerOf(ctx.deps, ctx.drag?.affordance), declared, ctx.drag?.start ?? null,\n );\n if (plane === null) return inner.start(ctx, opts);\n return planeHandle(inner.start(plane.carry(ctx), opts), plane);\n },\n },\n } as A;\n}\n\ninterface LivePlane {\n map(): PlaneMap;\n /** The invocation's deps, speaking the plane's world. */\n deps: ActionDeps;\n /** `ctx` in the plane's world. */\n carry(ctx: InvocationCtx): InvocationCtx;\n}\n\nfunction livePlane(\n bag: ActionDeps,\n layer: string | undefined,\n /** What the wrapped action declared. The dispatcher's dev deps bag throws\n * on any other read, so the seam converts only the deps it can see. */\n declared: readonly string[],\n /** The drag's press point in the camera's world, when there is a drag. */\n pressedAt: Point | null,\n): LivePlane | null {\n const scene = bag.scene as Scene<unknown, string, unknown> | undefined;\n const viewApi = bag.view as ViewApi | undefined;\n if (layer === undefined || !scene || !viewApi) return null;\n if (!scene.layers.some((l) => l.parallax !== undefined)) return null;\n const parallaxOf = (id: string): ParallaxOpts | undefined => scene.layers.find((l) => l.id === id)?.parallax;\n const parallax = (): ParallaxOpts | undefined => parallaxOf(layer);\n\n const IDENTITY: PlaneMap = { scale: { x: 1, y: 1 }, offset: { x: 0, y: 0 } };\n const map = (): PlaneMap => {\n const p = parallax();\n return p ? planeMap(viewApi.get(), p) : IDENTITY;\n };\n\n // A screen-pixel tolerance, and anything else an action reads off the\n // camera, has to be read at the plane's scale.\n const planeView = Object.defineProperties(Object.create(viewApi), {\n get: {\n value: (): View => {\n const p = parallax();\n const camera = viewApi.get();\n return p ? deriveParallaxView(camera, p) : camera;\n },\n },\n plane: { value: map },\n planeOf: {\n value: (id: string): PlaneMap | null => {\n const edited = parallax();\n const own = parallaxOf(id);\n const camera = viewApi.get();\n return planeToPlane(edited ? planeMap(camera, edited) : null, own ? planeMap(camera, own) : null);\n },\n },\n }) as ViewApi;\n\n // Over the dispatcher's bag rather than a copy of it, so every other read\n // still goes through whatever checks the bag makes.\n const deps = Object.create(bag) as typeof bag;\n const override = (name: string, value: unknown) =>\n Object.defineProperty(deps, name, { value, enumerable: true });\n override('view', planeView);\n const nodeAtPoint = declared.includes('nodeAtPoint')\n ? bag.nodeAtPoint as NodeAtPointDep | undefined\n : undefined;\n if (nodeAtPoint) {\n override('nodeAtPoint', ((p, exclude) => nodeAtPoint(fromPlane(map(), p), exclude)) as NodeAtPointDep);\n }\n const snap = declared.includes('snap') ? bag.snap as SnapDep | undefined : undefined;\n if (snap) {\n // A session runs in the plane; a target the camera draws, a grid or a\n // ruler guide, is carried into it.\n override('snap', { begin: (req: SnapBegin) => snap.begin({ ...req, plane: map }) } satisfies SnapDep);\n }\n\n // The drag's origin, fixed in the plane at the moment it was pressed,\n // whatever the camera does after.\n const start0 = pressedAt ? toPlane(map(), pressedAt) : null;\n const trail = trailCarrier();\n\n return {\n map,\n deps,\n carry(c) {\n const m = map();\n const out: InvocationCtx = { ...c, world: toPlane(m, c.world) };\n if (c.drag) {\n const start = start0 ?? toPlane(m, c.drag.start);\n const current = toPlane(m, c.drag.current);\n const aff = c.drag.affordance;\n out.drag = {\n ...c.drag,\n start,\n current,\n delta: { x: current.x - start.x, y: current.y - start.y },\n ...(c.drag.points ? { points: trail(c.drag.points, m) } : {}),\n ...(aff?.fixedPoint ? { affordance: { ...aff, fixedPoint: toPlane(m, aff.fixedPoint) } } : {}),\n };\n }\n // The dispatcher hands `onMove` no deps; only `start` has any to carry.\n if (c.deps) out.deps = deps;\n return out;\n },\n };\n}\n\n/** The drag trail in the plane. The dispatcher grows its trail in place, so\n * only the samples added since the last call are mapped — unless the map\n * moved, when every sample is. */\nfunction trailCarrier(): (points: DragSample[], m: PlaneMap) => DragSample[] {\n let src: DragSample[] | null = null;\n let lastMap: PlaneMap | null = null;\n let out: DragSample[] = [];\n return (points, m) => {\n const same = lastMap !== null\n && lastMap.scale.x === m.scale.x && lastMap.scale.y === m.scale.y\n && lastMap.offset.x === m.offset.x && lastMap.offset.y === m.offset.y;\n if (points !== src || !same || points.length < out.length) {\n src = points;\n out = [];\n }\n lastMap = m;\n for (let i = out.length; i < points.length; i++) {\n out.push({ ...points[i], ...toPlane(m, points[i]) });\n }\n // A copy, so a snapshot taken on `onEnd` is not the live accumulator.\n return out.slice();\n };\n}\n\nfunction planeHandle(handle: OngoingHandle, plane: LivePlane): OngoingHandle {\n const out: OngoingHandle = { ...handle };\n if (handle.onMove) out.onMove = (c) => handle.onMove!(plane.carry(c));\n if (handle.onEnd) out.onEnd = (c, reason) => handle.onEnd!(plane.carry(c), reason);\n if (handle.onWheel) out.onWheel = (c) => handle.onWheel!(plane.carry(c));\n if (handle.overlay) {\n out.overlay = () => {\n const ov = handle.overlay!();\n if (!ov) return ov;\n const m = plane.map();\n return Array.isArray(ov)\n ? (ov as readonly OngoingOverlay[]).map((o) => overlayFromPlane(o, m))\n : overlayFromPlane(ov as OngoingOverlay, m);\n };\n }\n return out;\n}\n\n/** An overlay drawn in the plane, in the camera's world: what every painter\n * reads an overlay as. */\nfunction overlayFromPlane(ov: OngoingOverlay, m: PlaneMap): OngoingOverlay {\n const pt = (p: Point) => fromPlane(m, p);\n switch (ov.kind) {\n case 'marquee':\n return { ...ov, start: pt(ov.start), current: pt(ov.current) };\n case 'lasso':\n return { ...ov, vertices: ov.vertices.map(pt), current: pt(ov.current) };\n case 'polyline':\n case 'brush':\n return { ...ov, points: ov.points.map(pt) };\n case 'insertPreview':\n return {\n ...ov,\n bounds: rectFromPlane(m, ov.bounds),\n extras: insertExtrasFromPlane(ov.extras, m),\n ...(ov.anchorPoint ? { anchorPoint: pt(ov.anchorPoint) } : {}),\n };\n }\n}\n\n/** The geometry the kit's insert kinds carry in `extras`, in the camera's\n * world. A consumer kind's extras are opaque, and pass through. */\nfunction insertExtrasFromPlane(extras: unknown, m: PlaneMap): unknown {\n if (extras === null || typeof extras !== 'object') return extras;\n const e = extras as Record<string, unknown>;\n const pt = (p: unknown) => fromPlane(m, p as Point);\n // Radial kinds inscribe in a square, so one scale carries a radius.\n const r = (v: unknown) => (typeof v === 'number' ? v / ((m.scale.x + m.scale.y) / 2) : v);\n const out: Record<string, unknown> = { ...e };\n if (e['a'] && e['b']) { out['a'] = pt(e['a']); out['b'] = pt(e['b']); }\n if (e['center']) out['center'] = pt(e['center']);\n if ('radius' in e) out['radius'] = r(e['radius']);\n if ('outerRadius' in e) out['outerRadius'] = r(e['outerRadius']);\n if (Array.isArray(e['samples'])) {\n out['samples'] = (e['samples'] as DragSample[]).map((s) => ({ ...s, ...pt(s) }));\n }\n return out;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"planeInput.js","names":[],"sources":["../../../src/interactions/actions/planeInput.ts"],"sourcesContent":["/**\n * Editing a node on a parallax plane.\n *\n * The dispatcher hands every action the camera's world. A node on a layer\n * carrying `parallax` stores its pose in its plane's world, which the camera's\n * reaches through a `PlaneMap` that changes with the camera. An editing action\n * pairs the pointer with the pose it edits, so the two have to be in one world.\n *\n * `inPlane` wraps an action so its input is carried into the plane of the\n * layer it edits before the action reads it, and the chrome it publishes back\n * comes out in the camera's world. A dep that answers in world points\n * (`nodeAtPoint`, `snap`) keeps speaking the camera's world, and the seam\n * converts at its boundary.\n *\n * A selection can span planes. The edit is measured in one of them, and a\n * node on another is carried into it as the gesture starts and back out\n * through `planeOf` as it is now.\n *\n * The map is read afresh on every call: a camera panning under a held drag, or\n * a plane whose factors are being animated, moves the node with the pointer.\n */\nimport type {\n Action, ActionDeps, AffordanceHit, BindingOpts, DragSample, InvocationCtx, OngoingHandle,\n OngoingOverlay, WorldPoint,\n} from '@weasel-js/routing';\nimport type { Scene } from 'core/scene/types';\nimport { asNodeId } from 'core/scene/types';\nimport {\n deriveParallaxView, fromPlane, planeMap, planeToPlane, rectFromPlane, rectToPlane, toPlane,\n type ParallaxOpts, type PlaneMap,\n} from 'core/viewport/parallax';\nimport type { View } from 'core/viewport/view';\nimport type { PoseDescriptor } from 'core/geometry/poseDescriptor';\nimport type { NodeAtPointDep, SnapDep, ViewApi } from './depSchema';\nimport type { SnapBegin } from './snapDep';\nimport type { Point } from '@weasel-js/geom';\nimport type { ImmediateParams } from '@weasel-js/routing';\n\n/** Which scene layer an invocation edits, read once as it starts. `undefined`\n * means none: the action runs in the camera's world. */\nexport type EditedLayerOf = (deps: ActionDeps, affordance?: AffordanceHit) => string | undefined;\n\nconst layerOfNode = (deps: ActionDeps, id: string | null | undefined): string | undefined =>\n (id ? deps.scene?.get(asNodeId(id))?.layer : undefined);\n\n/** The layer of the node a selection edit acts on: the affordance's target\n * when the drag grabbed one, the first selected node otherwise. A selection\n * spanning planes is edited in that one node's plane. */\nexport const selectionLayer: EditedLayerOf = (deps, affordance) => {\n const selection = deps.selection;\n for (const id of [...(affordance?.targetIds ?? []), ...(selection?.get() ?? [])]) {\n const layer = layerOfNode(deps, id);\n if (layer !== undefined) return layer;\n }\n return undefined;\n};\n\n/** The layer the `insert` dep will put a new node on. */\nexport const insertLayer: EditedLayerOf = (deps) =>\n deps.insert?.layer?.();\n\n/** The layer of the path in anchor-edit mode. */\nexport const editingLayer: EditedLayerOf = (deps) =>\n layerOfNode(deps, deps.editAnchors?.editingId);\n\n/** How the world an invocation edits in maps into the world `layer`'s nodes\n * are stored in, read now. Null when they are the same world. */\nexport function planeOf(view: unknown, layer: string): PlaneMap | null {\n return (view as ViewApi | undefined)?.planeOf?.(layer) ?? null;\n}\n\n/** `m` run backwards; null stays null. */\nexport function invertPlane(m: PlaneMap | null): PlaneMap | null {\n return m && planeToPlane(m, null);\n}\n\n/** `pose` carried through `m`. The map is axis-aligned, so remapping the\n * pose's bounds carries it exactly when the map scales both axes alike. */\nexport function carryPose<P>(d: PoseDescriptor<P>, pose: P, m: PlaneMap | null): P {\n if (m === null) return pose;\n const b = d.getBounds(pose);\n return d.remapBounds(pose, b, rectToPlane(m, b));\n}\n\n/** `action`, with its input carried into the plane of the layer `layerOf`\n * names. An action in a scene with no `parallax` layer, or invoked with no\n * scene or view to read a plane from, runs exactly as it would unwrapped.\n *\n * An immediate action's points are its params' `world` and `press`; each\n * is carried when present. */\nexport function inPlane<A extends Action>(action: A, layerOf: EditedLayerOf): A {\n const inner = action.invoker;\n if (!inner) return action;\n const declared = action.requires ?? [];\n const requires = [...new Set([...declared, 'scene', 'selection', 'view'])];\n if (inner.timing === 'immediate') {\n return {\n ...action,\n requires,\n invoker: {\n timing: 'immediate',\n run(deps: ActionDeps, params?: Record<string, unknown>): void | 'pass' {\n const plane = livePlane(deps, layerOf(deps), declared, null);\n if (plane === null) return inner.run(deps, params);\n const { world, press } = (params ?? {}) as ImmediateParams;\n if (!world && !press) return inner.run(plane.deps, params);\n const m = plane.map();\n return inner.run(plane.deps, {\n ...params,\n ...(world ? { world: toPlane(m, world) } : {}),\n ...(press ? { press: toPlane(m, press) } : {}),\n });\n },\n },\n } as A;\n }\n return {\n ...action,\n requires,\n invoker: {\n ...inner,\n start(ctx: InvocationCtx, opts?: BindingOpts): OngoingHandle {\n const plane = livePlane(\n ctx.deps, layerOf(ctx.deps, ctx.drag?.affordance), declared, ctx.drag?.start ?? null,\n );\n if (plane === null) return inner.start(ctx, opts);\n return planeHandle(inner.start(plane.carry(ctx), opts), plane);\n },\n },\n } as A;\n}\n\ninterface LivePlane {\n map(): PlaneMap;\n /** The invocation's deps, speaking the plane's world. */\n deps: ActionDeps;\n /** `ctx` in the plane's world. */\n carry(ctx: InvocationCtx): InvocationCtx;\n}\n\nfunction livePlane(\n bag: ActionDeps,\n layer: string | undefined,\n /** What the wrapped action declared. The dispatcher's dev deps bag throws\n * on any other read, so the seam converts only the deps it can see. */\n declared: readonly string[],\n /** The drag's press point in the camera's world, when there is a drag. */\n pressedAt: WorldPoint | null,\n): LivePlane | null {\n const scene = bag.scene as Scene<unknown, string, unknown> | undefined;\n const viewApi = bag.view as ViewApi | undefined;\n if (layer === undefined || !scene || !viewApi) return null;\n if (!scene.layers.some((l) => l.parallax !== undefined)) return null;\n const parallaxOf = (id: string): ParallaxOpts | undefined => scene.layers.find((l) => l.id === id)?.parallax;\n const parallax = (): ParallaxOpts | undefined => parallaxOf(layer);\n\n const IDENTITY: PlaneMap = { scale: { x: 1, y: 1 }, offset: { x: 0, y: 0 } };\n const map = (): PlaneMap => {\n const p = parallax();\n return p ? planeMap(viewApi.get(), p) : IDENTITY;\n };\n\n // A screen-pixel tolerance, and anything else an action reads off the\n // camera, has to be read at the plane's scale.\n const planeView = Object.defineProperties(Object.create(viewApi), {\n get: {\n value: (): View => {\n const p = parallax();\n const camera = viewApi.get();\n return p ? deriveParallaxView(camera, p) : camera;\n },\n },\n plane: { value: map },\n planeOf: {\n value: (id: string): PlaneMap | null => {\n const edited = parallax();\n const own = parallaxOf(id);\n const camera = viewApi.get();\n return planeToPlane(edited ? planeMap(camera, edited) : null, own ? planeMap(camera, own) : null);\n },\n },\n }) as ViewApi;\n\n // Over the dispatcher's bag rather than a copy of it, so every other read\n // still goes through whatever checks the bag makes.\n const deps = Object.create(bag) as typeof bag;\n const override = (name: string, value: unknown) =>\n Object.defineProperty(deps, name, { value, enumerable: true });\n override('view', planeView);\n const nodeAtPoint = declared.includes('nodeAtPoint')\n ? bag.nodeAtPoint as NodeAtPointDep | undefined\n : undefined;\n if (nodeAtPoint) {\n override('nodeAtPoint', ((p, exclude) => nodeAtPoint(fromPlane(map(), p), exclude)) as NodeAtPointDep);\n }\n const snap = declared.includes('snap') ? bag.snap as SnapDep | undefined : undefined;\n if (snap) {\n // A session runs in the plane; a target the camera draws, a grid or a\n // ruler guide, is carried into it.\n override('snap', { begin: (req: SnapBegin) => snap.begin({ ...req, plane: map }) } satisfies SnapDep);\n }\n\n // The drag's origin, fixed in the plane at the moment it was pressed,\n // whatever the camera does after.\n const start0 = pressedAt ? toPlane(map(), pressedAt) : null;\n const trail = trailCarrier();\n\n return {\n map,\n deps,\n carry(c) {\n const m = map();\n const out: InvocationCtx = { ...c, world: toPlane(m, c.world) };\n if (c.drag) {\n const start = start0 ?? toPlane(m, c.drag.start);\n const current = toPlane(m, c.drag.current);\n const aff = c.drag.affordance;\n out.drag = {\n ...c.drag,\n start,\n current,\n delta: { x: current.x - start.x, y: current.y - start.y },\n ...(c.drag.points ? { points: trail(c.drag.points, m) } : {}),\n ...(aff?.fixedPoint ? { affordance: { ...aff, fixedPoint: toPlane(m, aff.fixedPoint) } } : {}),\n };\n }\n // The dispatcher hands `onMove` no deps; only `start` has any to carry.\n if (c.deps) out.deps = deps;\n return out;\n },\n };\n}\n\n/** The drag trail in the plane. The dispatcher grows its trail in place, so\n * only the samples added since the last call are mapped — unless the map\n * moved, when every sample is. */\nfunction trailCarrier(): (points: DragSample[], m: PlaneMap) => DragSample[] {\n let src: DragSample[] | null = null;\n let lastMap: PlaneMap | null = null;\n let out: DragSample[] = [];\n return (points, m) => {\n const same = lastMap !== null\n && lastMap.scale.x === m.scale.x && lastMap.scale.y === m.scale.y\n && lastMap.offset.x === m.offset.x && lastMap.offset.y === m.offset.y;\n if (points !== src || !same || points.length < out.length) {\n src = points;\n out = [];\n }\n lastMap = m;\n for (let i = out.length; i < points.length; i++) {\n out.push({ ...points[i], ...toPlane(m, points[i]) });\n }\n // A copy, so a snapshot taken on `onEnd` is not the live accumulator.\n return out.slice();\n };\n}\n\nfunction planeHandle(handle: OngoingHandle, plane: LivePlane): OngoingHandle {\n const out: OngoingHandle = { ...handle };\n if (handle.onMove) out.onMove = (c) => handle.onMove!(plane.carry(c));\n if (handle.onEnd) out.onEnd = (c, reason) => handle.onEnd!(plane.carry(c), reason);\n if (handle.onWheel) out.onWheel = (c) => handle.onWheel!(plane.carry(c));\n if (handle.overlay) {\n out.overlay = () => {\n const ov = handle.overlay!();\n if (!ov) return ov;\n const m = plane.map();\n return Array.isArray(ov)\n ? (ov as readonly OngoingOverlay[]).map((o) => overlayFromPlane(o, m))\n : overlayFromPlane(ov as OngoingOverlay, m);\n };\n }\n return out;\n}\n\n/** An overlay drawn in the plane, in the camera's world: what every painter\n * reads an overlay as. */\nfunction overlayFromPlane(ov: OngoingOverlay, m: PlaneMap): OngoingOverlay {\n const pt = (p: Point) => fromPlane(m, p);\n switch (ov.kind) {\n case 'marquee':\n return { ...ov, start: pt(ov.start), current: pt(ov.current) };\n case 'lasso':\n return { ...ov, vertices: ov.vertices.map(pt), current: pt(ov.current) };\n case 'polyline':\n case 'brush':\n return { ...ov, points: ov.points.map(pt) };\n case 'reason':\n return { ...ov, at: pt(ov.at) };\n case 'insertPreview':\n return {\n ...ov,\n bounds: rectFromPlane(m, ov.bounds),\n extras: insertExtrasFromPlane(ov.extras, m),\n ...(ov.anchorPoint ? { anchorPoint: pt(ov.anchorPoint) } : {}),\n };\n }\n}\n\n/** The geometry the kit's insert kinds carry in `extras`, in the camera's\n * world. A consumer kind's extras are opaque, and pass through. */\nfunction insertExtrasFromPlane(extras: unknown, m: PlaneMap): unknown {\n if (extras === null || typeof extras !== 'object') return extras;\n const e = extras as Record<string, unknown>;\n const pt = (p: unknown) => fromPlane(m, p as Point);\n // Radial kinds inscribe in a square, so one scale carries a radius.\n const r = (v: unknown) => (typeof v === 'number' ? v / ((m.scale.x + m.scale.y) / 2) : v);\n const out: Record<string, unknown> = { ...e };\n if (e['a'] && e['b']) { out['a'] = pt(e['a']); out['b'] = pt(e['b']); }\n if (e['center']) out['center'] = pt(e['center']);\n if ('radius' in e) out['radius'] = r(e['radius']);\n if ('outerRadius' in e) out['outerRadius'] = r(e['outerRadius']);\n if (Array.isArray(e['samples'])) {\n out['samples'] = (e['samples'] as DragSample[]).map((s) => ({ ...s, ...pt(s) }));\n }\n return out;\n}\n"],"mappings":"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"}
@@ -1,6 +1,8 @@
1
- import { composeWorldPose, frameAtOrAbove, rebaseLocalPose } from "../../core/scene/composeFrame.js";
1
+ import { childFrameAt, composeChildFrame, composeWorldPose, frameAtOrAbove, rebaseLocalPose } from "../../core/scene/composeFrame.js";
2
2
  import { definesFrame, effectivePose } from "../../core/scene/effectivePose.js";
3
+ import { viewPoseAdapter } from "../../core/scene/scrollOffsets.js";
3
4
  import { asNodeId } from "../../core/scene/types.js";
5
+ import { boxFrameOf } from "@weasel-js/geom";
4
6
 
5
7
  //#region src/interactions/actions/poseFrame.ts
6
8
  /**
@@ -12,8 +14,11 @@ import { asNodeId } from "../../core/scene/types.js";
12
14
  * world and writes world looks right for one gesture and drifts on the next,
13
15
  * because the stored pose is then read in the parent's frame again.
14
16
  *
15
- * Under `IDENTITY_POSE_COMPOSITION`, the default, local and world are the same
16
- * value. `core/scene/frameFixture.ts` is the scene where they differ.
17
+ * Under `IDENTITY_POSE_COMPOSITION` local and world are the same value.
18
+ *
19
+ * A scene-backed frame reads world as the view shows it, a scrolled
20
+ * container's content moved by its offset, and writes back through the same
21
+ * fold, so a pose an action stores is the content position.
17
22
  */
18
23
  /** Pair the two directions over an arbitrary pose adapter. */
19
24
  function poseFrame(adapter, pc) {
@@ -26,18 +31,19 @@ function poseFrame(adapter, pc) {
26
31
  },
27
32
  parentWorld: (id) => {
28
33
  const frame = frameAtOrAbove(adapter, adapter.getParent(id));
29
- return frame === null ? null : composeWorldPose(adapter, frame, pc.compose);
34
+ return frame === null ? null : composeChildFrame(adapter, frame, pc.compose);
30
35
  },
36
+ childFrame: (id, world) => childFrameAt(adapter, id, world),
31
37
  local: (id, worldPose) => rebaseLocalPose(adapter, worldPose, adapter.getParent(id), pc.compose, pc.decompose),
32
38
  localUnder: (parentId, worldPose) => rebaseLocalPose(adapter, worldPose, parentId, pc.compose, pc.decompose)
33
39
  };
34
40
  }
35
41
  /** The `poseFrame` a scene-backed action works in, over the scene's own
36
- * composition. Under IDENTITY every method is a no-op. */
42
+ * composition, read and written through the view's scrolled frames. */
37
43
  function scenePoseFrame(scene) {
38
44
  const pc = scene.composition;
39
45
  const source = scene;
40
- return poseFrame({
46
+ return poseFrame(viewPoseAdapter(scene, {
41
47
  getPose: (id) => {
42
48
  const node = scene.get(id);
43
49
  return node === void 0 ? {
@@ -52,9 +58,16 @@ function scenePoseFrame(scene) {
52
58
  const node = scene.get(id);
53
59
  return node === void 0 || definesFrame(node);
54
60
  }
55
- }, pc);
61
+ }), pc);
62
+ }
63
+ /** Each node's box frame in world, `boxFrameOf` its world pose: where a
64
+ * container's children are laid out, and its own grid runs. `null` for a
65
+ * node missing from `scene` or whose pose is not a box. */
66
+ function sceneBoxFrames(scene) {
67
+ const frame = scenePoseFrame(scene);
68
+ return (id) => scene.get(id) === void 0 ? null : boxFrameOf(frame.world(id));
56
69
  }
57
70
 
58
71
  //#endregion
59
- export { poseFrame, scenePoseFrame };
72
+ export { poseFrame, sceneBoxFrames, scenePoseFrame };
60
73
  //# sourceMappingURL=poseFrame.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"poseFrame.js","names":[],"sources":["../../../src/interactions/actions/poseFrame.ts"],"sourcesContent":["/**\n * World reads and local writes, paired, for the default actions.\n *\n * A container's pose defines a frame, so a node's stored pose is expressed in\n * its parent's. The geometry an action reasons about is world; every pose it\n * writes back through `setPose` or a pose op is local. An action that reads\n * world and writes world looks right for one gesture and drifts on the next,\n * because the stored pose is then read in the parent's frame again.\n *\n * Under `IDENTITY_POSE_COMPOSITION`, the default, local and world are the same\n * value. `core/scene/frameFixture.ts` is the scene where they differ.\n */\nimport { definesFrame, effectivePose, type PoseSource } from 'core/scene/effectivePose';\nimport { asNodeId, type NodeId, type Scene } from 'core/scene/types';\nimport {\n composeWorldPose,\n frameAtOrAbove,\n rebaseLocalPose,\n type PoseAdapter,\n type PoseComposition,\n} from 'core/scene/composePose';\n\n/** The two directions an action needs, over one composition strategy. */\nexport interface PoseFrame<TPose> {\n /** The strategy in force. `closure` says what it can express exactly. */\n readonly pc: PoseComposition<TPose>;\n /** `id`'s pose in world coordinates, honoring an in-flight gesture override. */\n world(id: NodeId): TPose;\n /** The node whose frame `id` is stored in, or `null` for the root frame. */\n frame(id: NodeId): NodeId | null;\n /** World pose of the frame `id` is stored in, or `null` for the root frame. */\n parentWorld(id: NodeId): TPose | null;\n /** `worldPose` expressed in `id`'s own parent frame — what `setPose` stores. */\n local(id: NodeId, worldPose: TPose): TPose;\n /** `worldPose` expressed under `parentId`'s frame. For a node about to be\n * reparented, whose current parent is not the frame it will be stored in. */\n localUnder(parentId: NodeId | null, worldPose: TPose): TPose;\n}\n\n/** Pair the two directions over an arbitrary pose adapter. */\nexport function poseFrame<TPose>(\n adapter: PoseAdapter<TPose>,\n pc: PoseComposition<TPose>,\n): PoseFrame<TPose> {\n return {\n pc,\n world: (id) => composeWorldPose(adapter, id as string, pc.compose),\n frame: (id) => {\n const frame = frameAtOrAbove(adapter, adapter.getParent(id as string));\n return frame === null ? null : asNodeId(frame);\n },\n parentWorld: (id) => {\n const frame = frameAtOrAbove(adapter, adapter.getParent(id as string));\n return frame === null ? null : composeWorldPose(adapter, frame, pc.compose);\n },\n local: (id, worldPose) =>\n rebaseLocalPose(adapter, worldPose, adapter.getParent(id as string), pc.compose, pc.decompose),\n localUnder: (parentId, worldPose) =>\n rebaseLocalPose(adapter, worldPose, parentId as string | null, pc.compose, pc.decompose),\n };\n}\n\n/** The `poseFrame` a scene-backed action works in, over the scene's own\n * composition. Under IDENTITY every method is a no-op. */\nexport function scenePoseFrame(scene: Scene<unknown, string, unknown>): PoseFrame<unknown> {\n const pc = scene.composition;\n const source = scene as unknown as PoseSource<unknown>;\n const adapter: PoseAdapter<unknown> = {\n getPose: (id) => {\n const node = scene.get(id as NodeId);\n return node === undefined ? { x: 0, y: 0, width: 0, height: 0 } : effectivePose(source, node);\n },\n getParent: (id) => scene.get(id as NodeId)?.parent ?? null,\n definesFrame: (id) => {\n const node = scene.get(id as NodeId);\n return node === undefined || definesFrame(node);\n },\n };\n return poseFrame(adapter, pc);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAwCA,SAAgB,UACd,SACA,IACkB;CAClB,OAAO;EACL;EACA,QAAQ,OAAO,iBAAiB,SAAS,IAAc,GAAG,OAAO;EACjE,QAAQ,OAAO;GACb,MAAM,QAAQ,eAAe,SAAS,QAAQ,UAAU,EAAY,CAAC;GACrE,OAAO,UAAU,OAAO,OAAO,SAAS,KAAK;EAC/C;EACA,cAAc,OAAO;GACnB,MAAM,QAAQ,eAAe,SAAS,QAAQ,UAAU,EAAY,CAAC;GACrE,OAAO,UAAU,OAAO,OAAO,iBAAiB,SAAS,OAAO,GAAG,OAAO;EAC5E;EACA,QAAQ,IAAI,cACV,gBAAgB,SAAS,WAAW,QAAQ,UAAU,EAAY,GAAG,GAAG,SAAS,GAAG,SAAS;EAC/F,aAAa,UAAU,cACrB,gBAAgB,SAAS,WAAW,UAA2B,GAAG,SAAS,GAAG,SAAS;CAC3F;AACF;;;AAIA,SAAgB,eAAe,OAA4D;CACzF,MAAM,KAAK,MAAM;CACjB,MAAM,SAAS;CAYf,OAAO,UAAU;EAVf,UAAU,OAAO;GACf,MAAM,OAAO,MAAM,IAAI,EAAY;GACnC,OAAO,SAAS,SAAY;IAAE,GAAG;IAAG,GAAG;IAAG,OAAO;IAAG,QAAQ;GAAE,IAAI,cAAc,QAAQ,IAAI;EAC9F;EACA,YAAY,OAAO,MAAM,IAAI,EAAY,CAAC,EAAE,UAAU;EACtD,eAAe,OAAO;GACpB,MAAM,OAAO,MAAM,IAAI,EAAY;GACnC,OAAO,SAAS,UAAa,aAAa,IAAI;EAChD;CAEe,GAAS,EAAE;AAC9B"}
1
+ {"version":3,"file":"poseFrame.js","names":[],"sources":["../../../src/interactions/actions/poseFrame.ts"],"sourcesContent":["/**\n * World reads and local writes, paired, for the default actions.\n *\n * A container's pose defines a frame, so a node's stored pose is expressed in\n * its parent's. The geometry an action reasons about is world; every pose it\n * writes back through `setPose` or a pose op is local. An action that reads\n * world and writes world looks right for one gesture and drifts on the next,\n * because the stored pose is then read in the parent's frame again.\n *\n * Under `IDENTITY_POSE_COMPOSITION` local and world are the same value.\n *\n * A scene-backed frame reads world as the view shows it, a scrolled\n * container's content moved by its offset, and writes back through the same\n * fold, so a pose an action stores is the content position.\n */\nimport { boxFrameOf, type Affine } from '@weasel-js/geom';\nimport { definesFrame, effectivePose, type PoseSource } from 'core/scene/effectivePose';\nimport { asNodeId, type NodeId, type Scene } from 'core/scene/types';\nimport { viewPoseAdapter } from 'core/scene/scrollOffsets';\nimport {\n childFrameAt,\n composeChildFrame,\n composeWorldPose,\n frameAtOrAbove,\n rebaseLocalPose,\n type PoseAdapter,\n type PoseComposition,\n} from 'core/scene/composePose';\n\n/** The two directions an action needs, over one composition strategy. */\nexport interface PoseFrame<TPose> {\n /** The strategy in force. `closure` says what it can express exactly. */\n readonly pc: PoseComposition<TPose>;\n /** `id`'s pose in world coordinates, honoring an in-flight gesture override. */\n world(id: NodeId): TPose;\n /** The node whose frame `id` is stored in, or `null` for the root frame. */\n frame(id: NodeId): NodeId | null;\n /** World pose of the frame `id` is stored in, or `null` for the root frame:\n * the container's `childFrame`, scrolled where the view scrolls it. */\n parentWorld(id: NodeId): TPose | null;\n /** The frame `id` gives its children when its own pose folds to `world`. */\n childFrame(id: NodeId, world: TPose): TPose;\n /** `worldPose` expressed in `id`'s own parent frame — what `setPose` stores. */\n local(id: NodeId, worldPose: TPose): TPose;\n /** `worldPose` expressed under `parentId`'s frame. For a node about to be\n * reparented, whose current parent is not the frame it will be stored in. */\n localUnder(parentId: NodeId | null, worldPose: TPose): TPose;\n}\n\n/** Pair the two directions over an arbitrary pose adapter. */\nexport function poseFrame<TPose>(\n adapter: PoseAdapter<TPose>,\n pc: PoseComposition<TPose>,\n): PoseFrame<TPose> {\n return {\n pc,\n world: (id) => composeWorldPose(adapter, id as string, pc.compose),\n frame: (id) => {\n const frame = frameAtOrAbove(adapter, adapter.getParent(id as string));\n return frame === null ? null : asNodeId(frame);\n },\n parentWorld: (id) => {\n const frame = frameAtOrAbove(adapter, adapter.getParent(id as string));\n return frame === null ? null : composeChildFrame(adapter, frame, pc.compose);\n },\n childFrame: (id, world) => childFrameAt(adapter, id as string, world),\n local: (id, worldPose) =>\n rebaseLocalPose(adapter, worldPose, adapter.getParent(id as string), pc.compose, pc.decompose),\n localUnder: (parentId, worldPose) =>\n rebaseLocalPose(adapter, worldPose, parentId as string | null, pc.compose, pc.decompose),\n };\n}\n\n/** The `poseFrame` a scene-backed action works in, over the scene's own\n * composition, read and written through the view's scrolled frames. */\nexport function scenePoseFrame(scene: Scene<unknown, string, unknown>): PoseFrame<unknown> {\n const pc = scene.composition;\n const source = scene as unknown as PoseSource<unknown>;\n const adapter: PoseAdapter<unknown> = viewPoseAdapter(scene, {\n getPose: (id) => {\n const node = scene.get(id as NodeId);\n return node === undefined ? { x: 0, y: 0, width: 0, height: 0 } : effectivePose(source, node);\n },\n getParent: (id) => scene.get(id as NodeId)?.parent ?? null,\n definesFrame: (id) => {\n const node = scene.get(id as NodeId);\n return node === undefined || definesFrame(node);\n },\n } as PoseAdapter<unknown>);\n return poseFrame(adapter, pc);\n}\n\n/** Each node's box frame in world, `boxFrameOf` its world pose: where a\n * container's children are laid out, and its own grid runs. `null` for a\n * node missing from `scene` or whose pose is not a box. */\nexport function sceneBoxFrames(scene: Scene<unknown, string, unknown>): (id: string) => Affine | null {\n const frame = scenePoseFrame(scene);\n return (id) => (scene.get(id as NodeId) === undefined ? null : boxFrameOf(frame.world(id as NodeId)));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAkDA,SAAgB,UACd,SACA,IACkB;CAClB,OAAO;EACL;EACA,QAAQ,OAAO,iBAAiB,SAAS,IAAc,GAAG,OAAO;EACjE,QAAQ,OAAO;GACb,MAAM,QAAQ,eAAe,SAAS,QAAQ,UAAU,EAAY,CAAC;GACrE,OAAO,UAAU,OAAO,OAAO,SAAS,KAAK;EAC/C;EACA,cAAc,OAAO;GACnB,MAAM,QAAQ,eAAe,SAAS,QAAQ,UAAU,EAAY,CAAC;GACrE,OAAO,UAAU,OAAO,OAAO,kBAAkB,SAAS,OAAO,GAAG,OAAO;EAC7E;EACA,aAAa,IAAI,UAAU,aAAa,SAAS,IAAc,KAAK;EACpE,QAAQ,IAAI,cACV,gBAAgB,SAAS,WAAW,QAAQ,UAAU,EAAY,GAAG,GAAG,SAAS,GAAG,SAAS;EAC/F,aAAa,UAAU,cACrB,gBAAgB,SAAS,WAAW,UAA2B,GAAG,SAAS,GAAG,SAAS;CAC3F;AACF;;;AAIA,SAAgB,eAAe,OAA4D;CACzF,MAAM,KAAK,MAAM;CACjB,MAAM,SAAS;CAYf,OAAO,UAX+B,gBAAgB,OAAO;EAC3D,UAAU,OAAO;GACf,MAAM,OAAO,MAAM,IAAI,EAAY;GACnC,OAAO,SAAS,SAAY;IAAE,GAAG;IAAG,GAAG;IAAG,OAAO;IAAG,QAAQ;GAAE,IAAI,cAAc,QAAQ,IAAI;EAC9F;EACA,YAAY,OAAO,MAAM,IAAI,EAAY,CAAC,EAAE,UAAU;EACtD,eAAe,OAAO;GACpB,MAAM,OAAO,MAAM,IAAI,EAAY;GACnC,OAAO,SAAS,UAAa,aAAa,IAAI;EAChD;CACF,CACiB,GAAS,EAAE;AAC9B;;;;AAKA,SAAgB,eAAe,OAAuE;CACpG,MAAM,QAAQ,eAAe,KAAK;CAClC,QAAQ,OAAQ,MAAM,IAAI,EAAY,MAAM,SAAY,OAAO,WAAW,MAAM,MAAM,EAAY,CAAC;AACrG"}
@@ -1,7 +1,7 @@
1
1
  import { transformPreview } from "../transformFinish.js";
2
2
  import { closeGesture, runBehaviorCancel } from "../gestureLifecycle.js";
3
3
  import { inPlane, selectionLayer } from "../planeInput.js";
4
- import { SNAP_ROLES } from "../../../features/snap/roles.js";
4
+ import { SNAP_ROLES } from "../../../domains/snap/roles.js";
5
5
  import { recordTransform } from "../transform-again/memory.js";
6
6
  import { commitResize } from "./commit.js";
7
7
  import { nextFrame } from "./frame.js";
@@ -1 +1 @@
1
- {"version":3,"file":"action.js","names":[],"sources":["../../../../src/interactions/actions/resize/action.ts"],"sourcesContent":["import type { Action, ActionDeps } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport type { NodeId } from 'core/scene/types';\nimport { transformPreview } from '../transformFinish';\nimport { closeGesture, runBehaviorCancel } from '../gestureLifecycle';\nimport { inPlane, selectionLayer } from '../planeInput';\nimport { commitResize } from './commit';\nimport { nextFrame } from './frame';\nimport { beginResize, type ResizeFrame } from './session';\nimport { unitsOfBox } from './replay';\nimport { recordTransform } from '../transform-again/memory';\nimport { SNAP_ROLES } from 'features/snap/roles';\n\n/** Options for {@link createResizeAction}. */\nexport interface ResizeActionOptions {\n /** Runs in place of the scene commit, handed each resized node's pose at\n * release, so a host keeping the geometry as data can store it. The scene\n * is left as it was, and no undo entry is made; the constraints' `onEnd`\n * answers are not asked for. */\n commit?: (poses: ReadonlyMap<NodeId, unknown>, deps: ActionDeps) => void;\n}\n\n/**\n * Anchor-relative drag resize, committed as one batch on release. It needs\n * `InvocationCtx.drag.affordance` with a `handle:*` kind.\n *\n * The dragged corner or edge snaps through the `snap` dep's session before\n * the box is resized, held to the handle's axis, and to the box's diagonal\n * while `snap.constrain` (Shift) is held. The optional `resizePolicy` dep\n * carries the constraints, point snaps, and `expandIds`; absent, the invoker\n * runs no constraints and `ids => ids` expansion.\n */\nexport function createResizeAction(opts: ResizeActionOptions = {}): Action & { requires: string[] } {\n const { commit } = opts;\n return inPlane({\n id: 'resize',\n label: 'Resize',\n // No default binding: a bare `{ kind: 'drag' }` claims every drag at ambient\n // scope. The resize handles bind it (`selectionResizeBindings`).\n eligible: { capability: 'transforms-selection' },\n modifierRoles: SNAP_ROLES,\n requires: [\n 'selection', 'scene', 'resizePolicy', 'poseDescriptor', 'applyOps', 'geometryProjection', 'view',\n 'boundsIncludeStroke', 'kitSettings', 'snap', 'transformFollowers',\n ],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, _opts): OngoingHandle {\n const begun = beginResize(ctx);\n if (!begun) return {};\n const { session, readers } = begun;\n const subject = [...(ctx.deps.selection?.get() ?? [])] as string[];\n const hold = session.scene.overrides.hold();\n const preview = transformPreview(ctx.deps, session.scene, () => frame.previews);\n let frame: ResizeFrame = { previews: new Map() };\n session.lifecycle.start(session.writeIds as readonly string[]);\n return {\n kind: 'resize',\n onMove(moveCtx: InvocationCtx): void {\n if (!moveCtx.drag) return;\n frame = nextFrame(session, readers, moveCtx);\n hold.set(preview.poses());\n },\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n if (reason === 'commit' && commit !== undefined) {\n committed = frame.previews.size > 0;\n if (committed) commit(new Map(frame.previews), ctx.deps);\n } else if (reason === 'commit') {\n committed = commitResize(session, frame);\n if (committed && frame.proposed) {\n const to = unitsOfBox(session.box.bounds, frame.proposed);\n recordTransform(session.scene, { kind: 'scale', to, anchor: session.box.anchor }, subject);\n }\n } else runBehaviorCancel(session.constraints, session.gestureCtx);\n } finally {\n session.snap.end();\n closeGesture({ hold, previews: frame.previews, behaviors: session.constraints, ctx: session.gestureCtx, lifecycle: session.lifecycle }, committed);\n }\n },\n previewIds: preview.previewIds,\n previewData: preview.previewData,\n };\n },\n },\n /**\n * Always enabled: the dispatcher treats anything `!== true` as \"skip and\n * try the next match\", so a disabled reason here makes the resize binding\n * silently lose to lower-specificity matches (e.g. ambient `insertAction`).\n */\n enabled: () => true,\n }, selectionLayer);\n}\n\n/** The resize that commits to the scene. */\nexport const resizeAction = createResizeAction();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,mBAAmB,OAA4B,CAAC,GAAoC;CAClG,MAAM,EAAE,WAAW;CACnB,OAAO,QAAQ;EACb,IAAI;EACJ,OAAO;EAGP,UAAU,EAAE,YAAY,uBAAuB;EAC/C,eAAe;EACf,UAAU;GACR;GAAa;GAAS;GAAgB;GAAkB;GAAY;GAAsB;GAC1F;GAAuB;GAAe;GAAQ;EAChD;EACA,SAAS;GACP,QAAQ;GACR,MAAM,KAAoB,OAAsB;IAC9C,MAAM,QAAQ,YAAY,GAAG;IAC7B,IAAI,CAAC,OAAO,OAAO,CAAC;IACpB,MAAM,EAAE,SAAS,YAAY;IAC7B,MAAM,UAAU,CAAC,GAAI,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,CAAE;IACrD,MAAM,OAAO,QAAQ,MAAM,UAAU,KAAK;IAC1C,MAAM,UAAU,iBAAiB,IAAI,MAAM,QAAQ,aAAa,MAAM,QAAQ;IAC9E,IAAI,QAAqB,EAAE,0BAAU,IAAI,IAAI,EAAE;IAC/C,QAAQ,UAAU,MAAM,QAAQ,QAA6B;IAC7D,OAAO;KACL,MAAM;KACN,OAAO,SAA8B;MACnC,IAAI,CAAC,QAAQ,MAAM;MACnB,QAAQ,UAAU,SAAS,SAAS,OAAO;MAC3C,KAAK,IAAI,QAAQ,MAAM,CAAC;KAC1B;KACA,MAAM,SAAwB,QAAmC;MAC/D,IAAI,YAAY;MAChB,IAAI;OACF,IAAI,WAAW,YAAY,WAAW,QAAW;QAC/C,YAAY,MAAM,SAAS,OAAO;QAClC,IAAI,WAAW,OAAO,IAAI,IAAI,MAAM,QAAQ,GAAG,IAAI,IAAI;OACzD,OAAO,IAAI,WAAW,UAAU;QAC9B,YAAY,aAAa,SAAS,KAAK;QACvC,IAAI,aAAa,MAAM,UAAU;SAC/B,MAAM,KAAK,WAAW,QAAQ,IAAI,QAAQ,MAAM,QAAQ;SACxD,gBAAgB,QAAQ,OAAO;UAAE,MAAM;UAAS;UAAI,QAAQ,QAAQ,IAAI;SAAO,GAAG,OAAO;QAC3F;OACF,OAAO,kBAAkB,QAAQ,aAAa,QAAQ,UAAU;MAClE,UAAU;OACR,QAAQ,KAAK,IAAI;OACjB,aAAa;QAAE;QAAM,UAAU,MAAM;QAAU,WAAW,QAAQ;QAAa,KAAK,QAAQ;QAAY,WAAW,QAAQ;OAAU,GAAG,SAAS;MACnJ;KACF;KACA,YAAY,QAAQ;KACpB,aAAa,QAAQ;IACvB;GACF;EACF;;;;;;EAMA,eAAe;CACjB,GAAG,cAAc;AACnB;;AAGA,IAAa,eAAe,mBAAmB"}
1
+ {"version":3,"file":"action.js","names":[],"sources":["../../../../src/interactions/actions/resize/action.ts"],"sourcesContent":["import type { Action, ActionDeps } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport type { NodeId } from 'core/scene/types';\nimport { transformPreview } from '../transformFinish';\nimport { closeGesture, runBehaviorCancel } from '../gestureLifecycle';\nimport { inPlane, selectionLayer } from '../planeInput';\nimport { commitResize } from './commit';\nimport { nextFrame } from './frame';\nimport { beginResize, type ResizeFrame } from './session';\nimport { unitsOfBox } from './replay';\nimport { recordTransform } from '../transform-again/memory';\nimport { SNAP_ROLES } from 'domains/snap/roles';\n\n/** Options for {@link createResizeAction}. */\nexport interface ResizeActionOptions {\n /** Runs in place of the scene commit, handed each resized node's pose at\n * release, so a host keeping the geometry as data can store it. The scene\n * is left as it was, and no undo entry is made; the constraints' `onEnd`\n * answers are not asked for. */\n commit?: (poses: ReadonlyMap<NodeId, unknown>, deps: ActionDeps) => void;\n}\n\n/**\n * Anchor-relative drag resize, committed as one batch on release. It needs\n * `InvocationCtx.drag.affordance` with a `handle:*` kind.\n *\n * The dragged corner or edge snaps through the `snap` dep's session before\n * the box is resized, held to the handle's axis, and to the box's diagonal\n * while `snap.constrain` (Shift) is held. The optional `resizePolicy` dep\n * carries the constraints, point snaps, and `expandIds`; absent, the invoker\n * runs no constraints and `ids => ids` expansion.\n */\nexport function createResizeAction(opts: ResizeActionOptions = {}): Action & { requires: string[] } {\n const { commit } = opts;\n return inPlane({\n id: 'resize',\n label: 'Resize',\n // No default binding: a bare `{ kind: 'drag' }` claims every drag at ambient\n // scope. The resize handles bind it (`selectionResizeBindings`).\n eligible: { capability: 'transforms-selection' },\n modifierRoles: SNAP_ROLES,\n requires: [\n 'selection', 'scene', 'resizePolicy', 'poseDescriptor', 'applyOps', 'geometryProjection', 'view',\n 'boundsIncludeStroke', 'kitSettings', 'snap', 'transformFollowers',\n ],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, _opts): OngoingHandle {\n const begun = beginResize(ctx);\n if (!begun) return {};\n const { session, readers } = begun;\n const subject = [...(ctx.deps.selection?.get() ?? [])] as string[];\n const hold = session.scene.overrides.hold();\n const preview = transformPreview(ctx.deps, session.scene, () => frame.previews);\n let frame: ResizeFrame = { previews: new Map() };\n session.lifecycle.start(session.writeIds as readonly string[]);\n return {\n kind: 'resize',\n onMove(moveCtx: InvocationCtx): void {\n if (!moveCtx.drag) return;\n frame = nextFrame(session, readers, moveCtx);\n hold.set(preview.poses());\n },\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n if (reason === 'commit' && commit !== undefined) {\n committed = frame.previews.size > 0;\n if (committed) commit(new Map(frame.previews), ctx.deps);\n } else if (reason === 'commit') {\n committed = commitResize(session, frame);\n if (committed && frame.proposed) {\n const to = unitsOfBox(session.box.bounds, frame.proposed);\n recordTransform(session.scene, { kind: 'scale', to, anchor: session.box.anchor }, subject);\n }\n } else runBehaviorCancel(session.constraints, session.gestureCtx);\n } finally {\n session.snap.end();\n closeGesture({ hold, previews: frame.previews, behaviors: session.constraints, ctx: session.gestureCtx, lifecycle: session.lifecycle }, committed);\n }\n },\n previewIds: preview.previewIds,\n previewData: preview.previewData,\n };\n },\n },\n /**\n * Always enabled: the dispatcher treats anything `!== true` as \"skip and\n * try the next match\", so a disabled reason here makes the resize binding\n * silently lose to lower-specificity matches (e.g. ambient `insertAction`).\n */\n enabled: () => true,\n }, selectionLayer);\n}\n\n/** The resize that commits to the scene. */\nexport const resizeAction = createResizeAction();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,mBAAmB,OAA4B,CAAC,GAAoC;CAClG,MAAM,EAAE,WAAW;CACnB,OAAO,QAAQ;EACb,IAAI;EACJ,OAAO;EAGP,UAAU,EAAE,YAAY,uBAAuB;EAC/C,eAAe;EACf,UAAU;GACR;GAAa;GAAS;GAAgB;GAAkB;GAAY;GAAsB;GAC1F;GAAuB;GAAe;GAAQ;EAChD;EACA,SAAS;GACP,QAAQ;GACR,MAAM,KAAoB,OAAsB;IAC9C,MAAM,QAAQ,YAAY,GAAG;IAC7B,IAAI,CAAC,OAAO,OAAO,CAAC;IACpB,MAAM,EAAE,SAAS,YAAY;IAC7B,MAAM,UAAU,CAAC,GAAI,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,CAAE;IACrD,MAAM,OAAO,QAAQ,MAAM,UAAU,KAAK;IAC1C,MAAM,UAAU,iBAAiB,IAAI,MAAM,QAAQ,aAAa,MAAM,QAAQ;IAC9E,IAAI,QAAqB,EAAE,0BAAU,IAAI,IAAI,EAAE;IAC/C,QAAQ,UAAU,MAAM,QAAQ,QAA6B;IAC7D,OAAO;KACL,MAAM;KACN,OAAO,SAA8B;MACnC,IAAI,CAAC,QAAQ,MAAM;MACnB,QAAQ,UAAU,SAAS,SAAS,OAAO;MAC3C,KAAK,IAAI,QAAQ,MAAM,CAAC;KAC1B;KACA,MAAM,SAAwB,QAAmC;MAC/D,IAAI,YAAY;MAChB,IAAI;OACF,IAAI,WAAW,YAAY,WAAW,QAAW;QAC/C,YAAY,MAAM,SAAS,OAAO;QAClC,IAAI,WAAW,OAAO,IAAI,IAAI,MAAM,QAAQ,GAAG,IAAI,IAAI;OACzD,OAAO,IAAI,WAAW,UAAU;QAC9B,YAAY,aAAa,SAAS,KAAK;QACvC,IAAI,aAAa,MAAM,UAAU;SAC/B,MAAM,KAAK,WAAW,QAAQ,IAAI,QAAQ,MAAM,QAAQ;SACxD,gBAAgB,QAAQ,OAAO;UAAE,MAAM;UAAS;UAAI,QAAQ,QAAQ,IAAI;SAAO,GAAG,OAAO;QAC3F;OACF,OAAO,kBAAkB,QAAQ,aAAa,QAAQ,UAAU;MAClE,UAAU;OACR,QAAQ,KAAK,IAAI;OACjB,aAAa;QAAE;QAAM,UAAU,MAAM;QAAU,WAAW,QAAQ;QAAa,KAAK,QAAQ;QAAY,WAAW,QAAQ;OAAU,GAAG,SAAS;MACnJ;KACF;KACA,YAAY,QAAQ;KACpB,aAAa,QAAQ;IACvB;GACF;EACF;;;;;;EAMA,eAAe;CACjB,GAAG,cAAc;AACnB;;AAGA,IAAa,eAAe,mBAAmB"}
@@ -1,4 +1,4 @@
1
- import { EPS } from "../../../features/snap/resizeBox.js";
1
+ import { EPS } from "../../../domains/snap/resizeBox.js";
2
2
 
3
3
  //#region src/interactions/actions/resize/aspect.ts
4
4
  /** `b` with the axis an edge handle leaves free scaled to keep `origin`'s
@@ -1 +1 @@
1
- {"version":3,"file":"aspect.js","names":[],"sources":["../../../../src/interactions/actions/resize/aspect.ts"],"sourcesContent":["import type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { EPS } from 'features/snap/resizeBox';\nimport type { ResizeAnchor } from '../../gestures/types';\n\n/** `b` with the axis an edge handle leaves free scaled to keep `origin`'s\n * aspect, centered on `origin`. A corner comes back unchanged: `onDiagonal`\n * already put its pointer on the diagonal. */\nexport function edgeAspect(b: Bounds, origin: Bounds, anchor: ResizeAnchor): Bounds {\n if ((anchor.x === 'free') === (anchor.y === 'free') || origin.width === 0 || origin.height === 0) return b;\n const ratio = origin.width / origin.height;\n if (anchor.x === 'free') {\n const width = Math.abs(b.height * ratio);\n return { ...b, x: origin.x + origin.width / 2 - width / 2, width };\n }\n const height = Math.abs(b.width / ratio);\n return { ...b, y: origin.y + origin.height / 2 - height / 2, height };\n}\n\n/** A corner drag's `local` delta put on the diagonal of `drawn`, scaled by\n * whichever axis it grows the box more on relative to its size, so the\n * corner keeps up with the cursor on that axis. Null for an edge handle or\n * a box with no area. */\nexport function onDiagonal(local: { x: number; y: number }, drawn: Bounds, anchor: ResizeAnchor): { x: number; y: number } | null {\n if (anchor.x === 'free' || anchor.y === 'free' || Math.abs(drawn.width) < EPS || Math.abs(drawn.height) < EPS) return null;\n const dx = anchor.x === 'min' ? drawn.width : -drawn.width;\n const dy = anchor.y === 'min' ? drawn.height : -drawn.height;\n const sx = local.x / dx;\n const sy = local.y / dy;\n const s = Math.abs(sx) >= Math.abs(sy) ? sx : sy;\n return { x: s * dx, y: s * dy };\n}\n"],"mappings":";;;;;;AAOA,SAAgB,WAAW,GAAW,QAAgB,QAA8B;CAClF,IAAK,OAAO,MAAM,YAAa,OAAO,MAAM,WAAW,OAAO,UAAU,KAAK,OAAO,WAAW,GAAG,OAAO;CACzG,MAAM,QAAQ,OAAO,QAAQ,OAAO;CACpC,IAAI,OAAO,MAAM,QAAQ;EACvB,MAAM,QAAQ,KAAK,IAAI,EAAE,SAAS,KAAK;EACvC,OAAO;GAAE,GAAG;GAAG,GAAG,OAAO,IAAI,OAAO,QAAQ,IAAI,QAAQ;GAAG;EAAM;CACnE;CACA,MAAM,SAAS,KAAK,IAAI,EAAE,QAAQ,KAAK;CACvC,OAAO;EAAE,GAAG;EAAG,GAAG,OAAO,IAAI,OAAO,SAAS,IAAI,SAAS;EAAG;CAAO;AACtE;;;;;AAMA,SAAgB,WAAW,OAAiC,OAAe,QAAuD;CAChI,IAAI,OAAO,MAAM,UAAU,OAAO,MAAM,UAAU,KAAK,IAAI,MAAM,KAAK,IAAI,OAAO,KAAK,IAAI,MAAM,MAAM,IAAI,KAAK,OAAO;CACtH,MAAM,KAAK,OAAO,MAAM,QAAQ,MAAM,QAAQ,CAAC,MAAM;CACrD,MAAM,KAAK,OAAO,MAAM,QAAQ,MAAM,SAAS,CAAC,MAAM;CACtD,MAAM,KAAK,MAAM,IAAI;CACrB,MAAM,KAAK,MAAM,IAAI;CACrB,MAAM,IAAI,KAAK,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,IAAI,KAAK;CAC9C,OAAO;EAAE,GAAG,IAAI;EAAI,GAAG,IAAI;CAAG;AAChC"}
1
+ {"version":3,"file":"aspect.js","names":[],"sources":["../../../../src/interactions/actions/resize/aspect.ts"],"sourcesContent":["import type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { EPS } from 'domains/snap/resizeBox';\nimport type { ResizeAnchor } from '../../gestures/types';\n\n/** `b` with the axis an edge handle leaves free scaled to keep `origin`'s\n * aspect, centered on `origin`. A corner comes back unchanged: `onDiagonal`\n * already put its pointer on the diagonal. */\nexport function edgeAspect(b: Bounds, origin: Bounds, anchor: ResizeAnchor): Bounds {\n if ((anchor.x === 'free') === (anchor.y === 'free') || origin.width === 0 || origin.height === 0) return b;\n const ratio = origin.width / origin.height;\n if (anchor.x === 'free') {\n const width = Math.abs(b.height * ratio);\n return { ...b, x: origin.x + origin.width / 2 - width / 2, width };\n }\n const height = Math.abs(b.width / ratio);\n return { ...b, y: origin.y + origin.height / 2 - height / 2, height };\n}\n\n/** A corner drag's `local` delta put on the diagonal of `drawn`, scaled by\n * whichever axis it grows the box more on relative to its size, so the\n * corner keeps up with the cursor on that axis. Null for an edge handle or\n * a box with no area. */\nexport function onDiagonal(local: { x: number; y: number }, drawn: Bounds, anchor: ResizeAnchor): { x: number; y: number } | null {\n if (anchor.x === 'free' || anchor.y === 'free' || Math.abs(drawn.width) < EPS || Math.abs(drawn.height) < EPS) return null;\n const dx = anchor.x === 'min' ? drawn.width : -drawn.width;\n const dy = anchor.y === 'min' ? drawn.height : -drawn.height;\n const sx = local.x / dx;\n const sy = local.y / dy;\n const s = Math.abs(sx) >= Math.abs(sy) ? sx : sy;\n return { x: s * dx, y: s * dy };\n}\n"],"mappings":";;;;;;AAOA,SAAgB,WAAW,GAAW,QAAgB,QAA8B;CAClF,IAAK,OAAO,MAAM,YAAa,OAAO,MAAM,WAAW,OAAO,UAAU,KAAK,OAAO,WAAW,GAAG,OAAO;CACzG,MAAM,QAAQ,OAAO,QAAQ,OAAO;CACpC,IAAI,OAAO,MAAM,QAAQ;EACvB,MAAM,QAAQ,KAAK,IAAI,EAAE,SAAS,KAAK;EACvC,OAAO;GAAE,GAAG;GAAG,GAAG,OAAO,IAAI,OAAO,QAAQ,IAAI,QAAQ;GAAG;EAAM;CACnE;CACA,MAAM,SAAS,KAAK,IAAI,EAAE,QAAQ,KAAK;CACvC,OAAO;EAAE,GAAG;EAAG,GAAG,OAAO,IAAI,OAAO,SAAS,IAAI,SAAS;EAAG;CAAO;AACtE;;;;;AAMA,SAAgB,WAAW,OAAiC,OAAe,QAAuD;CAChI,IAAI,OAAO,MAAM,UAAU,OAAO,MAAM,UAAU,KAAK,IAAI,MAAM,KAAK,IAAI,OAAO,KAAK,IAAI,MAAM,MAAM,IAAI,KAAK,OAAO;CACtH,MAAM,KAAK,OAAO,MAAM,QAAQ,MAAM,QAAQ,CAAC,MAAM;CACrD,MAAM,KAAK,OAAO,MAAM,QAAQ,MAAM,SAAS,CAAC,MAAM;CACtD,MAAM,KAAK,MAAM,IAAI;CACrB,MAAM,KAAK,MAAM,IAAI;CACrB,MAAM,IAAI,KAAK,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,IAAI,KAAK;CAC9C,OAAO;EAAE,GAAG,IAAI;EAAI,GAAG,IAAI;CAAG;AAChC"}
@@ -16,7 +16,7 @@ function projectedGeometry(projection, g, node, from, next, label) {
16
16
  id: node.id,
17
17
  data: node.data,
18
18
  pose: from
19
- }, m, label);
19
+ }, m, next, label);
20
20
  if (!dataOp) return null;
21
21
  if (!(db.width < 0 || db.height < 0)) return {
22
22
  dataOp,
@@ -39,6 +39,15 @@ function projectedGeometry(projection, g, node, from, next, label) {
39
39
  * answers for the node. */
40
40
  function resizeOps(leaves, previews, label) {
41
41
  const ops = [];
42
+ for (const [id, h] of leaves.held ?? []) {
43
+ const to = previews.get(id);
44
+ if (to !== void 0) ops.push(createTransformOp({
45
+ id,
46
+ from: h.from,
47
+ to,
48
+ label
49
+ }));
50
+ }
42
51
  for (const id of leaves.writeIds) {
43
52
  const next = previews.get(id);
44
53
  if (next === void 0) continue;
@@ -1 +1 @@
1
- {"version":3,"file":"commit.js","names":[],"sources":["../../../../src/interactions/actions/resize/commit.ts"],"sourcesContent":["import { boxToBox, type Affine } from '@weasel-js/geom';\nimport type { Op } from 'core/ops/types';\nimport { createTransformOp } from 'core/ops/transform';\nimport type { NodeId } from 'core/scene/types';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport { geometryDataOp, type GeometryProjection } from '../geometryProjection';\nimport { commitGestureOps, reduceBehaviorEnd } from '../gestureLifecycle';\nimport type { PoseDescriptor } from './geometry';\nimport type { ResizeFrame, ResizeSession } from './session';\n\n/** The op mapping a leaf's data-held geometry by the box→box affine its pose\n * underwent, and the pose to commit beside it. Null when the projection\n * leaves this node's data alone. */\nfunction projectedGeometry(\n projection: GeometryProjection,\n g: PoseDescriptor<unknown>,\n node: { id: string; data: unknown },\n from: unknown,\n next: unknown,\n label: string,\n): { dataOp: Op; pose: unknown } | null {\n const sb = g.getBounds(from);\n const db = g.getBounds(next);\n const m: Affine = boxToBox(\n sb.x, sb.y, sb.width, sb.height,\n db.x, db.y, db.width, db.height,\n );\n const dataOp = geometryDataOp(projection, { id: node.id, data: node.data, pose: from }, m, label);\n if (!dataOp) return null;\n // The data absorbed the affine — including any mirror from a\n // drag past the opposite edge — so the pose must commit as a\n // normalized AABB. Leaving signed extents on the pose makes\n // the node unhittable (hit-testing assumes normalized boxes).\n // Without the seam the signed pose is kept: a bare-AABB pose\n // is the only carrier of the flip there.\n if (!(db.width < 0 || db.height < 0)) return { dataOp, pose: next };\n const nb = {\n ...db,\n x: db.width < 0 ? db.x + db.width : db.x,\n y: db.height < 0 ? db.y + db.height : db.y,\n width: Math.abs(db.width),\n height: Math.abs(db.height),\n };\n return { dataOp, pose: g.remapBounds(next, db, nb) };\n}\n\n/** One transform op per write id, `from` the pose stored at press and `to`\n * its preview, each preceded by its data op when the geometry projection\n * answers for the node. */\nexport function resizeOps(\n leaves: Pick<ResizeSession, 'scene' | 'writeIds' | 'startPoses' | 'geometryOf' | 'geometryProjection'>,\n previews: ReadonlyMap<NodeId, unknown>,\n label: string,\n): Op[] {\n const ops: Op[] = [];\n for (const id of leaves.writeIds) {\n const next = previews.get(id);\n if (next === undefined) continue;\n const from = leaves.startPoses.get(id);\n if (from === undefined) continue;\n let to: unknown = next;\n const node = leaves.geometryProjection ? leaves.scene.get(id) : undefined;\n if (leaves.geometryProjection && node) {\n const projected = projectedGeometry(\n leaves.geometryProjection, leaves.geometryOf(id), { id: id as string, data: node.data }, from, next, label,\n );\n if (projected) {\n ops.push(projected.dataOp);\n to = projected.pose;\n }\n }\n ops.push(createTransformOp<unknown>({ id: id as string, from, to, label }));\n }\n return ops;\n}\n\n/** Commit the drag as one batch, so one undo entry. Returns whether anything\n * reached the document. */\nexport function commitResize(session: ResizeSession, frame: ResizeFrame): boolean {\n const { lifecycle } = session;\n const target = {\n scene: session.scene,\n applyOps: session.applyOps,\n finish: session.finish,\n adapter: defaultCommitAdapter(session.scene, session.selectionMethods),\n };\n const r = reduceBehaviorEnd(session.constraints, session.gestureCtx);\n if (r === null) return false;\n if (r !== undefined) return commitGestureOps(target, lifecycle, r);\n\n if (frame.previews.size === 0) return false;\n const ops = resizeOps(session, frame.previews, lifecycle.label);\n if (ops.length === 0) return false;\n return commitGestureOps(target, lifecycle, ops);\n}\n"],"mappings":";;;;;;;;;;AAaA,SAAS,kBACP,YACA,GACA,MACA,MACA,MACA,OACsC;CACtC,MAAM,KAAK,EAAE,UAAU,IAAI;CAC3B,MAAM,KAAK,EAAE,UAAU,IAAI;CAC3B,MAAM,IAAY,SAChB,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,QACzB,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,MAC3B;CACA,MAAM,SAAS,eAAe,YAAY;EAAE,IAAI,KAAK;EAAI,MAAM,KAAK;EAAM,MAAM;CAAK,GAAG,GAAG,KAAK;CAChG,IAAI,CAAC,QAAQ,OAAO;CAOpB,IAAI,EAAE,GAAG,QAAQ,KAAK,GAAG,SAAS,IAAI,OAAO;EAAE;EAAQ,MAAM;CAAK;CAClE,MAAM,KAAK;EACT,GAAG;EACH,GAAG,GAAG,QAAQ,IAAI,GAAG,IAAI,GAAG,QAAQ,GAAG;EACvC,GAAG,GAAG,SAAS,IAAI,GAAG,IAAI,GAAG,SAAS,GAAG;EACzC,OAAO,KAAK,IAAI,GAAG,KAAK;EACxB,QAAQ,KAAK,IAAI,GAAG,MAAM;CAC5B;CACA,OAAO;EAAE;EAAQ,MAAM,EAAE,YAAY,MAAM,IAAI,EAAE;CAAE;AACrD;;;;AAKA,SAAgB,UACd,QACA,UACA,OACM;CACN,MAAM,MAAY,CAAC;CACnB,KAAK,MAAM,MAAM,OAAO,UAAU;EAChC,MAAM,OAAO,SAAS,IAAI,EAAE;EAC5B,IAAI,SAAS,QAAW;EACxB,MAAM,OAAO,OAAO,WAAW,IAAI,EAAE;EACrC,IAAI,SAAS,QAAW;EACxB,IAAI,KAAc;EAClB,MAAM,OAAO,OAAO,qBAAqB,OAAO,MAAM,IAAI,EAAE,IAAI;EAChE,IAAI,OAAO,sBAAsB,MAAM;GACrC,MAAM,YAAY,kBAChB,OAAO,oBAAoB,OAAO,WAAW,EAAE,GAAG;IAAM;IAAc,MAAM,KAAK;GAAK,GAAG,MAAM,MAAM,KACvG;GACA,IAAI,WAAW;IACb,IAAI,KAAK,UAAU,MAAM;IACzB,KAAK,UAAU;GACjB;EACF;EACA,IAAI,KAAK,kBAA2B;GAAM;GAAc;GAAM;GAAI;EAAM,CAAC,CAAC;CAC5E;CACA,OAAO;AACT;;;AAIA,SAAgB,aAAa,SAAwB,OAA6B;CAChF,MAAM,EAAE,cAAc;CACtB,MAAM,SAAS;EACb,OAAO,QAAQ;EACf,UAAU,QAAQ;EAClB,QAAQ,QAAQ;EAChB,SAAS,qBAAqB,QAAQ,OAAO,QAAQ,gBAAgB;CACvE;CACA,MAAM,IAAI,kBAAkB,QAAQ,aAAa,QAAQ,UAAU;CACnE,IAAI,MAAM,MAAM,OAAO;CACvB,IAAI,MAAM,QAAW,OAAO,iBAAiB,QAAQ,WAAW,CAAC;CAEjE,IAAI,MAAM,SAAS,SAAS,GAAG,OAAO;CACtC,MAAM,MAAM,UAAU,SAAS,MAAM,UAAU,UAAU,KAAK;CAC9D,IAAI,IAAI,WAAW,GAAG,OAAO;CAC7B,OAAO,iBAAiB,QAAQ,WAAW,GAAG;AAChD"}
1
+ {"version":3,"file":"commit.js","names":[],"sources":["../../../../src/interactions/actions/resize/commit.ts"],"sourcesContent":["import { boxToBox, type Affine } from '@weasel-js/geom';\nimport type { Op } from 'core/ops/types';\nimport { createTransformOp } from 'core/ops/transform';\nimport type { NodeId } from 'core/scene/types';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport { geometryDataOp, type GeometryProjection } from '../geometryProjection';\nimport { commitGestureOps, reduceBehaviorEnd } from '../gestureLifecycle';\nimport type { PoseDescriptor } from './geometry';\nimport type { ResizeFrame, ResizeSession } from './session';\n\n/** The op mapping a leaf's data-held geometry by the box→box affine its pose\n * underwent, and the pose to commit beside it. Null when the projection\n * leaves this node's data alone. */\nfunction projectedGeometry(\n projection: GeometryProjection,\n g: PoseDescriptor<unknown>,\n node: { id: string; data: unknown },\n from: unknown,\n next: unknown,\n label: string,\n): { dataOp: Op; pose: unknown } | null {\n const sb = g.getBounds(from);\n const db = g.getBounds(next);\n const m: Affine = boxToBox(\n sb.x, sb.y, sb.width, sb.height,\n db.x, db.y, db.width, db.height,\n );\n const dataOp = geometryDataOp(projection, { id: node.id, data: node.data, pose: from }, m, next, label);\n if (!dataOp) return null;\n // The data absorbed the affine — including any mirror from a\n // drag past the opposite edge — so the pose must commit as a\n // normalized AABB. Leaving signed extents on the pose makes\n // the node unhittable (hit-testing assumes normalized boxes).\n // Without the seam the signed pose is kept: a bare-AABB pose\n // is the only carrier of the flip there.\n if (!(db.width < 0 || db.height < 0)) return { dataOp, pose: next };\n const nb = {\n ...db,\n x: db.width < 0 ? db.x + db.width : db.x,\n y: db.height < 0 ? db.y + db.height : db.y,\n width: Math.abs(db.width),\n height: Math.abs(db.height),\n };\n return { dataOp, pose: g.remapBounds(next, db, nb) };\n}\n\n/** One transform op per write id, `from` the pose stored at press and `to`\n * its preview, each preceded by its data op when the geometry projection\n * answers for the node. */\nexport function resizeOps(\n leaves: Pick<ResizeSession, 'scene' | 'writeIds' | 'startPoses' | 'geometryOf' | 'geometryProjection'> & Partial<Pick<ResizeSession, 'held'>>,\n previews: ReadonlyMap<NodeId, unknown>,\n label: string,\n): Op[] {\n const ops: Op[] = [];\n for (const [id, h] of leaves.held ?? []) {\n const to = previews.get(id);\n if (to !== undefined) ops.push(createTransformOp<unknown>({ id: id as string, from: h.from, to, label }));\n }\n for (const id of leaves.writeIds) {\n const next = previews.get(id);\n if (next === undefined) continue;\n const from = leaves.startPoses.get(id);\n if (from === undefined) continue;\n let to: unknown = next;\n const node = leaves.geometryProjection ? leaves.scene.get(id) : undefined;\n if (leaves.geometryProjection && node) {\n const projected = projectedGeometry(\n leaves.geometryProjection, leaves.geometryOf(id), { id: id as string, data: node.data }, from, next, label,\n );\n if (projected) {\n ops.push(projected.dataOp);\n to = projected.pose;\n }\n }\n ops.push(createTransformOp<unknown>({ id: id as string, from, to, label }));\n }\n return ops;\n}\n\n/** Commit the drag as one batch, so one undo entry. Returns whether anything\n * reached the document. */\nexport function commitResize(session: ResizeSession, frame: ResizeFrame): boolean {\n const { lifecycle } = session;\n const target = {\n scene: session.scene,\n applyOps: session.applyOps,\n finish: session.finish,\n adapter: defaultCommitAdapter(session.scene, session.selectionMethods),\n };\n const r = reduceBehaviorEnd(session.constraints, session.gestureCtx);\n if (r === null) return false;\n if (r !== undefined) return commitGestureOps(target, lifecycle, r);\n\n if (frame.previews.size === 0) return false;\n const ops = resizeOps(session, frame.previews, lifecycle.label);\n if (ops.length === 0) return false;\n return commitGestureOps(target, lifecycle, ops);\n}\n"],"mappings":";;;;;;;;;;AAaA,SAAS,kBACP,YACA,GACA,MACA,MACA,MACA,OACsC;CACtC,MAAM,KAAK,EAAE,UAAU,IAAI;CAC3B,MAAM,KAAK,EAAE,UAAU,IAAI;CAC3B,MAAM,IAAY,SAChB,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,QACzB,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,MAC3B;CACA,MAAM,SAAS,eAAe,YAAY;EAAE,IAAI,KAAK;EAAI,MAAM,KAAK;EAAM,MAAM;CAAK,GAAG,GAAG,MAAM,KAAK;CACtG,IAAI,CAAC,QAAQ,OAAO;CAOpB,IAAI,EAAE,GAAG,QAAQ,KAAK,GAAG,SAAS,IAAI,OAAO;EAAE;EAAQ,MAAM;CAAK;CAClE,MAAM,KAAK;EACT,GAAG;EACH,GAAG,GAAG,QAAQ,IAAI,GAAG,IAAI,GAAG,QAAQ,GAAG;EACvC,GAAG,GAAG,SAAS,IAAI,GAAG,IAAI,GAAG,SAAS,GAAG;EACzC,OAAO,KAAK,IAAI,GAAG,KAAK;EACxB,QAAQ,KAAK,IAAI,GAAG,MAAM;CAC5B;CACA,OAAO;EAAE;EAAQ,MAAM,EAAE,YAAY,MAAM,IAAI,EAAE;CAAE;AACrD;;;;AAKA,SAAgB,UACd,QACA,UACA,OACM;CACN,MAAM,MAAY,CAAC;CACnB,KAAK,MAAM,CAAC,IAAI,MAAM,OAAO,QAAQ,CAAC,GAAG;EACvC,MAAM,KAAK,SAAS,IAAI,EAAE;EAC1B,IAAI,OAAO,QAAW,IAAI,KAAK,kBAA2B;GAAM;GAAc,MAAM,EAAE;GAAM;GAAI;EAAM,CAAC,CAAC;CAC1G;CACA,KAAK,MAAM,MAAM,OAAO,UAAU;EAChC,MAAM,OAAO,SAAS,IAAI,EAAE;EAC5B,IAAI,SAAS,QAAW;EACxB,MAAM,OAAO,OAAO,WAAW,IAAI,EAAE;EACrC,IAAI,SAAS,QAAW;EACxB,IAAI,KAAc;EAClB,MAAM,OAAO,OAAO,qBAAqB,OAAO,MAAM,IAAI,EAAE,IAAI;EAChE,IAAI,OAAO,sBAAsB,MAAM;GACrC,MAAM,YAAY,kBAChB,OAAO,oBAAoB,OAAO,WAAW,EAAE,GAAG;IAAM;IAAc,MAAM,KAAK;GAAK,GAAG,MAAM,MAAM,KACvG;GACA,IAAI,WAAW;IACb,IAAI,KAAK,UAAU,MAAM;IACzB,KAAK,UAAU;GACjB;EACF;EACA,IAAI,KAAK,kBAA2B;GAAM;GAAc;GAAM;GAAI;EAAM,CAAC,CAAC;CAC5E;CACA,OAAO;AACT;;;AAIA,SAAgB,aAAa,SAAwB,OAA6B;CAChF,MAAM,EAAE,cAAc;CACtB,MAAM,SAAS;EACb,OAAO,QAAQ;EACf,UAAU,QAAQ;EAClB,QAAQ,QAAQ;EAChB,SAAS,qBAAqB,QAAQ,OAAO,QAAQ,gBAAgB;CACvE;CACA,MAAM,IAAI,kBAAkB,QAAQ,aAAa,QAAQ,UAAU;CACnE,IAAI,MAAM,MAAM,OAAO;CACvB,IAAI,MAAM,QAAW,OAAO,iBAAiB,QAAQ,WAAW,CAAC;CAEjE,IAAI,MAAM,SAAS,SAAS,GAAG,OAAO;CACtC,MAAM,MAAM,UAAU,SAAS,MAAM,UAAU,UAAU,KAAK;CAC9D,IAAI,IAAI,WAAW,GAAG,OAAO;CAC7B,OAAO,iBAAiB,QAAQ,WAAW,GAAG;AAChD"}
@@ -4,7 +4,8 @@ import { insetBox, outsetBox } from "../../../core/geometry/inkExtents.js";
4
4
  import { fixedCornerOf, movedEdges } from "./cornerHandles.js";
5
5
  import { carryPose, planeOf } from "../planeInput.js";
6
6
  import { pointerStateOf } from "../pointerState.js";
7
- import { snapMods } from "../../../features/snap/roles.js";
7
+ import { snapMods } from "../../../domains/snap/roles.js";
8
+ import { holdInPlace } from "./held.js";
8
9
  import { boundsForRules } from "./ruleBounds.js";
9
10
  import { boxFrame } from "./boxFrame.js";
10
11
  import { clampToMinSize } from "./behaviors/clampMinSize.js";
@@ -145,7 +146,7 @@ function nextFrame(session, readers, moveCtx) {
145
146
  const { previews, proposed, lone } = posesInBox(session, insetBox(constrain(session.constraints, gctx, box.anchor, shaped), box.extents));
146
147
  if (lone) gctx.current = /* @__PURE__ */ new Map([[lone.id, outsetBox(boundsForRules(lone.g, lone.world), box.extents)]]);
147
148
  return {
148
- previews,
149
+ previews: holdInPlace(previews, session.held, session.poseFrame),
149
150
  proposed
150
151
  };
151
152
  }
@@ -1 +1 @@
1
- {"version":3,"file":"frame.js","names":[],"sources":["../../../../src/interactions/actions/resize/frame.ts"],"sourcesContent":["import { poseFrameOf } from '@weasel-js/geom';\nimport type { InvocationCtx } from '@weasel-js/routing';\nimport { pointerStateOf } from '../pointerState';\nimport { localToWorld, worldDeltaToLocal, type TargetTransform } from 'core/geometry/targetFrame';\nimport type { NodeId } from 'core/scene/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { GestureReaders } from '../../gestures/shared/screenTolerance';\nimport type { BoundsConstraint, GestureContext, ResizeAnchor, RotatedPose } from '../../gestures/types';\nimport { carryPose, planeOf } from '../planeInput';\nimport { fixedCornerOf, movedEdges } from './cornerHandles';\nimport { remapRotatedLeaf, translatePoseViaDescriptor, type PoseDescriptor } from './geometry';\nimport { boundsForRules } from './ruleBounds';\nimport { boxFrame } from './boxFrame';\nimport { insetBox, outsetBox } from 'core/geometry/inkExtents';\nimport type { ResizeBox, ResizeFrame, ResizeSession } from './session';\nimport { clampToMinSize } from './behaviors/clampMinSize';\nimport { edgeAspect, onDiagonal } from './aspect';\nimport { snapMods } from 'features/snap/roles';\n\n/** `ob` with the edges `anchor` leaves free moved by the drag delta, which is\n * taken into the axes of the frame the box is drawn in first. A frame nothing\n * maps back through moves no edge. */\nfunction computeProposedBounds(\n ob: Bounds,\n anchor: ResizeAnchor,\n worldDx: number,\n worldDy: number,\n frame: TargetTransform,\n): Bounds {\n const { x: dx, y: dy } = worldDeltaToLocal(frame, worldDx, worldDy) ?? { x: 0, y: 0 };\n return movedEdges(ob, anchor, dx, dy);\n}\n\n/** `proposed` as the constraints rewrite it, each seeing the one before's. */\nfunction constrain(\n constraints: readonly BoundsConstraint<Bounds>[],\n gctx: GestureContext<Bounds>,\n anchor: ResizeAnchor,\n proposed: Bounds,\n): Bounds {\n let bounds = proposed;\n for (const b of constraints) {\n const r = b.onMove?.(gctx, { pose: bounds, anchor });\n if (!r) continue;\n if (r.pose !== undefined) {\n bounds = { x: r.pose.x, y: r.pose.y, width: r.pose.width, height: r.pose.height };\n }\n }\n return bounds;\n}\n\n/** One write id's world pose with the box taken from `src` to `dst`.\n *\n * A turned or skewed leaf resized with others needs its own frame: `src`/`dst`\n * are world-frame there, unlike the lone path where the drag delta\n * was already projected into the leaf's frame, so the naive affine\n * scales the wrong pair of extents. See `remapRotatedLeaf`. */\nfunction leafPose(\n g: PoseDescriptor<unknown>,\n start: unknown,\n src: Bounds,\n dst: Bounds,\n sharedBox: boolean,\n): unknown {\n if (sharedBox && poseFrameOf(start) !== null) {\n return remapRotatedLeaf(start as RotatedPose, src, dst);\n }\n return g.remapBounds(start, src, dst);\n}\n\n/** `pose` shifted so the corner opposite the dragged one stays where the\n * press found it, which resizing a box whose frame is about its center moves. */\nfunction pinFixedCorner(\n g: PoseDescriptor<unknown>,\n pose: unknown,\n box: Pick<ResizeBox, 'anchor' | 'rotation' | 'transform' | 'fixedWorld'>,\n proposed: Bounds,\n): unknown {\n const frame = boxFrame(box, proposed);\n if (frame.identity) return pose;\n const newFixedLocal = fixedCornerOf(proposed, box.anchor);\n const newFixedWorld = localToWorld(frame, newFixedLocal.x, newFixedLocal.y);\n return translatePoseViaDescriptor(\n pose,\n box.fixedWorld.x - newFixedWorld.x,\n box.fixedWorld.y - newFixedWorld.y,\n g,\n );\n}\n\n/** A world result for `id`, as stored. */\nfunction storedPose(\n place: Pick<ResizeSession, 'scene' | 'poseFrame' | 'view' | 'geometryOf'>,\n id: NodeId,\n world: unknown,\n): unknown {\n const layer = place.scene.get(id)?.layer;\n return place.poseFrame.local(\n id,\n carryPose(place.geometryOf(id), world, layer === undefined ? null : planeOf(place.view, layer)),\n );\n}\n\n/** Every write id's stored pose with the box taken from where the press found\n * it to `asked`, held to the place's minimum. A lone target is also pinned at\n * the fixed corner, and comes back with its world pose. `proposed` is the box\n * they were put in. */\nexport function posesInBox(\n place: Pick<ResizeSession, 'scene' | 'poseFrame' | 'view' | 'geometryOf' | 'writeIds' | 'startWorlds' | 'box' | 'sharedBox' | 'minimum'>,\n asked: Bounds,\n): { previews: Map<NodeId, unknown>; proposed: Bounds; lone?: { id: NodeId; g: PoseDescriptor<unknown>; world: unknown } } {\n const { box } = place;\n const proposed = (place.minimum && clampToMinSize(asked, box.anchor, place.minimum)) ?? asked;\n const previews = new Map<NodeId, unknown>();\n const worldOf = (id: NodeId): unknown => {\n const start = place.startWorlds.get(id);\n if (start === undefined) return undefined;\n return leafPose(place.geometryOf(id), start, box.bounds, proposed, place.sharedBox);\n };\n\n if (place.sharedBox) {\n for (const id of place.writeIds) {\n const next = worldOf(id);\n if (next === undefined) continue;\n previews.set(id, storedPose(place, id, next));\n }\n return { previews, proposed };\n }\n\n const id = place.writeIds[0];\n const g = place.geometryOf(id);\n const remapped = worldOf(id);\n if (remapped === undefined) return { previews, proposed };\n const world = pinFixedCorner(g, remapped, box, proposed);\n previews.set(id, storedPose(place, id, world));\n return { previews, proposed, lone: { id, g, world } };\n}\n\n/** The pointer put on the box's diagonal, for an aspect-locked corner: the\n * session's input subspace then leaves it where it is, and a target still\n * lands it where the diagonal meets the target. */\nfunction aspectPointer(session: ResizeSession, frame: TargetTransform, drawn: Bounds, raw: { x: number; y: number }): { x: number; y: number } {\n const { startWorld: o, box } = session;\n const local = worldDeltaToLocal(frame, raw.x - o.x, raw.y - o.y);\n const d = local && onDiagonal(local, drawn, box.anchor);\n if (!d) return raw;\n const zero = localToWorld(frame, 0, 0);\n const w = localToWorld(frame, d.x, d.y);\n return { x: o.x + w.x - zero.x, y: o.y + w.y - zero.y };\n}\n\n/** One move's previews: the box as the snapped drag and the constraints\n * leave it, and every write id's stored pose inside it. A lone target also\n * gets the rotated-resize pin; a shared box, resized in the AABB frame, does\n * not.\n * `moveCtx` must carry a drag. */\nexport function nextFrame(session: ResizeSession, readers: GestureReaders, moveCtx: InvocationCtx): ResizeFrame {\n const raw = moveCtx.drag!.current;\n const { box, gestureCtx: gctx } = session;\n gctx.modifiers = { ...moveCtx.modifiers };\n gctx.pointer = pointerStateOf(raw, moveCtx);\n gctx.view = readers.view();\n gctx.plane = readers.plane();\n\n const mods = snapMods(moveCtx);\n const frame = boxFrame(box, box.bounds);\n const drawnStart = outsetBox(box.bounds, box.extents);\n const pointer = mods.constrain ? aspectPointer(session, frame, drawnStart, raw) : raw;\n const snapped = session.snap.at(pointer, mods);\n const at = snapped.point;\n // The constraints see the box as drawn; the stroke keeps its width, so the\n // extents come back off what they leave.\n const moved = computeProposedBounds(box.bounds, box.anchor, at.x - session.startWorld.x, at.y - session.startWorld.y, frame);\n const drawn = outsetBox(moved, box.extents);\n const shaped = mods.constrain ? edgeAspect(drawn, drawnStart, box.anchor) : drawn;\n const constrained = insetBox(constrain(session.constraints, gctx, box.anchor, shaped), box.extents);\n\n const { previews, proposed, lone } = posesInBox(session, constrained);\n if (lone) gctx.current = new Map<string, Bounds>([[lone.id as string, outsetBox(boundsForRules(lone.g, lone.world), box.extents)]]);\n return { previews, proposed };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"frame.js","names":[],"sources":["../../../../src/interactions/actions/resize/frame.ts"],"sourcesContent":["import { poseFrameOf } from '@weasel-js/geom';\nimport { holdInPlace } from './held';\nimport type { InvocationCtx } from '@weasel-js/routing';\nimport { pointerStateOf } from '../pointerState';\nimport { localToWorld, worldDeltaToLocal, type TargetTransform } from 'core/geometry/targetFrame';\nimport type { NodeId } from 'core/scene/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { GestureReaders } from '../../gestures/shared/screenTolerance';\nimport type { BoundsConstraint, GestureContext, ResizeAnchor, RotatedPose } from '../../gestures/types';\nimport { carryPose, planeOf } from '../planeInput';\nimport { fixedCornerOf, movedEdges } from './cornerHandles';\nimport { remapRotatedLeaf, translatePoseViaDescriptor, type PoseDescriptor } from './geometry';\nimport { boundsForRules } from './ruleBounds';\nimport { boxFrame } from './boxFrame';\nimport { insetBox, outsetBox } from 'core/geometry/inkExtents';\nimport type { ResizeBox, ResizeFrame, ResizeSession } from './session';\nimport { clampToMinSize } from './behaviors/clampMinSize';\nimport { edgeAspect, onDiagonal } from './aspect';\nimport { snapMods } from 'domains/snap/roles';\n\n/** `ob` with the edges `anchor` leaves free moved by the drag delta, which is\n * taken into the axes of the frame the box is drawn in first. A frame nothing\n * maps back through moves no edge. */\nfunction computeProposedBounds(\n ob: Bounds,\n anchor: ResizeAnchor,\n worldDx: number,\n worldDy: number,\n frame: TargetTransform,\n): Bounds {\n const { x: dx, y: dy } = worldDeltaToLocal(frame, worldDx, worldDy) ?? { x: 0, y: 0 };\n return movedEdges(ob, anchor, dx, dy);\n}\n\n/** `proposed` as the constraints rewrite it, each seeing the one before's. */\nfunction constrain(\n constraints: readonly BoundsConstraint<Bounds>[],\n gctx: GestureContext<Bounds>,\n anchor: ResizeAnchor,\n proposed: Bounds,\n): Bounds {\n let bounds = proposed;\n for (const b of constraints) {\n const r = b.onMove?.(gctx, { pose: bounds, anchor });\n if (!r) continue;\n if (r.pose !== undefined) {\n bounds = { x: r.pose.x, y: r.pose.y, width: r.pose.width, height: r.pose.height };\n }\n }\n return bounds;\n}\n\n/** One write id's world pose with the box taken from `src` to `dst`.\n *\n * A turned or skewed leaf resized with others needs its own frame: `src`/`dst`\n * are world-frame there, unlike the lone path where the drag delta\n * was already projected into the leaf's frame, so the naive affine\n * scales the wrong pair of extents. See `remapRotatedLeaf`. */\nfunction leafPose(\n g: PoseDescriptor<unknown>,\n start: unknown,\n src: Bounds,\n dst: Bounds,\n sharedBox: boolean,\n): unknown {\n if (sharedBox && poseFrameOf(start) !== null) {\n return remapRotatedLeaf(start as RotatedPose, src, dst);\n }\n return g.remapBounds(start, src, dst);\n}\n\n/** `pose` shifted so the corner opposite the dragged one stays where the\n * press found it, which resizing a box whose frame is about its center moves. */\nfunction pinFixedCorner(\n g: PoseDescriptor<unknown>,\n pose: unknown,\n box: Pick<ResizeBox, 'anchor' | 'rotation' | 'transform' | 'fixedWorld'>,\n proposed: Bounds,\n): unknown {\n const frame = boxFrame(box, proposed);\n if (frame.identity) return pose;\n const newFixedLocal = fixedCornerOf(proposed, box.anchor);\n const newFixedWorld = localToWorld(frame, newFixedLocal.x, newFixedLocal.y);\n return translatePoseViaDescriptor(\n pose,\n box.fixedWorld.x - newFixedWorld.x,\n box.fixedWorld.y - newFixedWorld.y,\n g,\n );\n}\n\n/** A world result for `id`, as stored. */\nfunction storedPose(\n place: Pick<ResizeSession, 'scene' | 'poseFrame' | 'view' | 'geometryOf'>,\n id: NodeId,\n world: unknown,\n): unknown {\n const layer = place.scene.get(id)?.layer;\n return place.poseFrame.local(\n id,\n carryPose(place.geometryOf(id), world, layer === undefined ? null : planeOf(place.view, layer)),\n );\n}\n\n/** Every write id's stored pose with the box taken from where the press found\n * it to `asked`, held to the place's minimum. A lone target is also pinned at\n * the fixed corner, and comes back with its world pose. `proposed` is the box\n * they were put in. */\nexport function posesInBox(\n place: Pick<ResizeSession, 'scene' | 'poseFrame' | 'view' | 'geometryOf' | 'writeIds' | 'startWorlds' | 'box' | 'sharedBox' | 'minimum'>,\n asked: Bounds,\n): { previews: Map<NodeId, unknown>; proposed: Bounds; lone?: { id: NodeId; g: PoseDescriptor<unknown>; world: unknown } } {\n const { box } = place;\n const proposed = (place.minimum && clampToMinSize(asked, box.anchor, place.minimum)) ?? asked;\n const previews = new Map<NodeId, unknown>();\n const worldOf = (id: NodeId): unknown => {\n const start = place.startWorlds.get(id);\n if (start === undefined) return undefined;\n return leafPose(place.geometryOf(id), start, box.bounds, proposed, place.sharedBox);\n };\n\n if (place.sharedBox) {\n for (const id of place.writeIds) {\n const next = worldOf(id);\n if (next === undefined) continue;\n previews.set(id, storedPose(place, id, next));\n }\n return { previews, proposed };\n }\n\n const id = place.writeIds[0];\n const g = place.geometryOf(id);\n const remapped = worldOf(id);\n if (remapped === undefined) return { previews, proposed };\n const world = pinFixedCorner(g, remapped, box, proposed);\n previews.set(id, storedPose(place, id, world));\n return { previews, proposed, lone: { id, g, world } };\n}\n\n/** The pointer put on the box's diagonal, for an aspect-locked corner: the\n * session's input subspace then leaves it where it is, and a target still\n * lands it where the diagonal meets the target. */\nfunction aspectPointer(session: ResizeSession, frame: TargetTransform, drawn: Bounds, raw: { x: number; y: number }): { x: number; y: number } {\n const { startWorld: o, box } = session;\n const local = worldDeltaToLocal(frame, raw.x - o.x, raw.y - o.y);\n const d = local && onDiagonal(local, drawn, box.anchor);\n if (!d) return raw;\n const zero = localToWorld(frame, 0, 0);\n const w = localToWorld(frame, d.x, d.y);\n return { x: o.x + w.x - zero.x, y: o.y + w.y - zero.y };\n}\n\n/** One move's previews: the box as the snapped drag and the constraints\n * leave it, and every write id's stored pose inside it. A lone target also\n * gets the rotated-resize pin; a shared box, resized in the AABB frame, does\n * not.\n * `moveCtx` must carry a drag. */\nexport function nextFrame(session: ResizeSession, readers: GestureReaders, moveCtx: InvocationCtx): ResizeFrame {\n const raw = moveCtx.drag!.current;\n const { box, gestureCtx: gctx } = session;\n gctx.modifiers = { ...moveCtx.modifiers };\n gctx.pointer = pointerStateOf(raw, moveCtx);\n gctx.view = readers.view();\n gctx.plane = readers.plane();\n\n const mods = snapMods(moveCtx);\n const frame = boxFrame(box, box.bounds);\n const drawnStart = outsetBox(box.bounds, box.extents);\n const pointer = mods.constrain ? aspectPointer(session, frame, drawnStart, raw) : raw;\n const snapped = session.snap.at(pointer, mods);\n const at = snapped.point;\n // The constraints see the box as drawn; the stroke keeps its width, so the\n // extents come back off what they leave.\n const moved = computeProposedBounds(box.bounds, box.anchor, at.x - session.startWorld.x, at.y - session.startWorld.y, frame);\n const drawn = outsetBox(moved, box.extents);\n const shaped = mods.constrain ? edgeAspect(drawn, drawnStart, box.anchor) : drawn;\n const constrained = insetBox(constrain(session.constraints, gctx, box.anchor, shaped), box.extents);\n\n const { previews, proposed, lone } = posesInBox(session, constrained);\n if (lone) gctx.current = new Map<string, Bounds>([[lone.id as string, outsetBox(boundsForRules(lone.g, lone.world), box.extents)]]);\n return { previews: holdInPlace(previews, session.held, session.poseFrame), proposed };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAuBA,SAAS,sBACP,IACA,QACA,SACA,SACA,OACQ;CACR,MAAM,EAAE,GAAG,IAAI,GAAG,OAAO,kBAAkB,OAAO,SAAS,OAAO,KAAK;EAAE,GAAG;EAAG,GAAG;CAAE;CACpF,OAAO,WAAW,IAAI,QAAQ,IAAI,EAAE;AACtC;;AAGA,SAAS,UACP,aACA,MACA,QACA,UACQ;CACR,IAAI,SAAS;CACb,KAAK,MAAM,KAAK,aAAa;EAC3B,MAAM,IAAI,EAAE,SAAS,MAAM;GAAE,MAAM;GAAQ;EAAO,CAAC;EACnD,IAAI,CAAC,GAAG;EACR,IAAI,EAAE,SAAS,QACb,SAAS;GAAE,GAAG,EAAE,KAAK;GAAG,GAAG,EAAE,KAAK;GAAG,OAAO,EAAE,KAAK;GAAO,QAAQ,EAAE,KAAK;EAAO;CAEpF;CACA,OAAO;AACT;;;;;;;AAQA,SAAS,SACP,GACA,OACA,KACA,KACA,WACS;CACT,IAAI,aAAa,YAAY,KAAK,MAAM,MACtC,OAAO,iBAAiB,OAAsB,KAAK,GAAG;CAExD,OAAO,EAAE,YAAY,OAAO,KAAK,GAAG;AACtC;;;AAIA,SAAS,eACP,GACA,MACA,KACA,UACS;CACT,MAAM,QAAQ,SAAS,KAAK,QAAQ;CACpC,IAAI,MAAM,UAAU,OAAO;CAC3B,MAAM,gBAAgB,cAAc,UAAU,IAAI,MAAM;CACxD,MAAM,gBAAgB,aAAa,OAAO,cAAc,GAAG,cAAc,CAAC;CAC1E,OAAO,2BACL,MACA,IAAI,WAAW,IAAI,cAAc,GACjC,IAAI,WAAW,IAAI,cAAc,GACjC,CACF;AACF;;AAGA,SAAS,WACP,OACA,IACA,OACS;CACT,MAAM,QAAQ,MAAM,MAAM,IAAI,EAAE,CAAC,EAAE;CACnC,OAAO,MAAM,UAAU,MACrB,IACA,UAAU,MAAM,WAAW,EAAE,GAAG,OAAO,UAAU,SAAY,OAAO,QAAQ,MAAM,MAAM,KAAK,CAAC,CAChG;AACF;;;;;AAMA,SAAgB,WACd,OACA,OACyH;CACzH,MAAM,EAAE,QAAQ;CAChB,MAAM,YAAY,MAAM,WAAW,eAAe,OAAO,IAAI,QAAQ,MAAM,OAAO,MAAM;CACxF,MAAM,2BAAW,IAAI,IAAqB;CAC1C,MAAM,WAAW,OAAwB;EACvC,MAAM,QAAQ,MAAM,YAAY,IAAI,EAAE;EACtC,IAAI,UAAU,QAAW,OAAO;EAChC,OAAO,SAAS,MAAM,WAAW,EAAE,GAAG,OAAO,IAAI,QAAQ,UAAU,MAAM,SAAS;CACpF;CAEA,IAAI,MAAM,WAAW;EACnB,KAAK,MAAM,MAAM,MAAM,UAAU;GAC/B,MAAM,OAAO,QAAQ,EAAE;GACvB,IAAI,SAAS,QAAW;GACxB,SAAS,IAAI,IAAI,WAAW,OAAO,IAAI,IAAI,CAAC;EAC9C;EACA,OAAO;GAAE;GAAU;EAAS;CAC9B;CAEA,MAAM,KAAK,MAAM,SAAS;CAC1B,MAAM,IAAI,MAAM,WAAW,EAAE;CAC7B,MAAM,WAAW,QAAQ,EAAE;CAC3B,IAAI,aAAa,QAAW,OAAO;EAAE;EAAU;CAAS;CACxD,MAAM,QAAQ,eAAe,GAAG,UAAU,KAAK,QAAQ;CACvD,SAAS,IAAI,IAAI,WAAW,OAAO,IAAI,KAAK,CAAC;CAC7C,OAAO;EAAE;EAAU;EAAU,MAAM;GAAE;GAAI;GAAG;EAAM;CAAE;AACtD;;;;AAKA,SAAS,cAAc,SAAwB,OAAwB,OAAe,KAAyD;CAC7I,MAAM,EAAE,YAAY,GAAG,QAAQ;CAC/B,MAAM,QAAQ,kBAAkB,OAAO,IAAI,IAAI,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC;CAC/D,MAAM,IAAI,SAAS,WAAW,OAAO,OAAO,IAAI,MAAM;CACtD,IAAI,CAAC,GAAG,OAAO;CACf,MAAM,OAAO,aAAa,OAAO,GAAG,CAAC;CACrC,MAAM,IAAI,aAAa,OAAO,EAAE,GAAG,EAAE,CAAC;CACtC,OAAO;EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,KAAK;EAAG,GAAG,EAAE,IAAI,EAAE,IAAI,KAAK;CAAE;AACxD;;;;;;AAOA,SAAgB,UAAU,SAAwB,SAAyB,SAAqC;CAC9G,MAAM,MAAM,QAAQ,KAAM;CAC1B,MAAM,EAAE,KAAK,YAAY,SAAS;CAClC,KAAK,YAAY,EAAE,GAAG,QAAQ,UAAU;CACxC,KAAK,UAAU,eAAe,KAAK,OAAO;CAC1C,KAAK,OAAO,QAAQ,KAAK;CACzB,KAAK,QAAQ,QAAQ,MAAM;CAE3B,MAAM,OAAO,SAAS,OAAO;CAC7B,MAAM,QAAQ,SAAS,KAAK,IAAI,MAAM;CACtC,MAAM,aAAa,UAAU,IAAI,QAAQ,IAAI,OAAO;CACpD,MAAM,UAAU,KAAK,YAAY,cAAc,SAAS,OAAO,YAAY,GAAG,IAAI;CAElF,MAAM,KADU,QAAQ,KAAK,GAAG,SAAS,IAC9B,CAAA,CAAQ;CAGnB,MAAM,QAAQ,sBAAsB,IAAI,QAAQ,IAAI,QAAQ,GAAG,IAAI,QAAQ,WAAW,GAAG,GAAG,IAAI,QAAQ,WAAW,GAAG,KAAK;CAC3H,MAAM,QAAQ,UAAU,OAAO,IAAI,OAAO;CAC1C,MAAM,SAAS,KAAK,YAAY,WAAW,OAAO,YAAY,IAAI,MAAM,IAAI;CAG5E,MAAM,EAAE,UAAU,UAAU,SAAS,WAAW,SAF5B,SAAS,UAAU,QAAQ,aAAa,MAAM,IAAI,QAAQ,MAAM,GAAG,IAAI,OAElC,CAAW;CACpE,IAAI,MAAM,KAAK,0BAAU,IAAI,IAAoB,CAAC,CAAC,KAAK,IAAc,UAAU,eAAe,KAAK,GAAG,KAAK,KAAK,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC;CAClI,OAAO;EAAE,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,SAAS;EAAG;CAAS;AACtF"}
@@ -0,0 +1,44 @@
1
+ import { definesFrame } from "../../../core/scene/effectivePose.js";
2
+ import { heldInFrame } from "../../../core/scene/carryDescendants.js";
3
+
4
+ //#region src/interactions/actions/resize/held.ts
5
+ /**
6
+ * What a resized frame holds: a resize changes the box, not where the
7
+ * contents draw, so each node stored in a written frame and not written
8
+ * itself is re-expressed in the frame's new pose.
9
+ */
10
+ /** The nodes stored in a frame among `writeIds` that the resize does not write. */
11
+ function captureHeld(scene, writeIds, poseFrame) {
12
+ const held = /* @__PURE__ */ new Map();
13
+ if (poseFrame.pc.closure === "identity") return held;
14
+ const writing = new Set(writeIds);
15
+ for (const frame of writeIds) {
16
+ const node = scene.get(frame);
17
+ if (!node || !definesFrame(node)) continue;
18
+ for (const id of heldInFrame(scene, frame)) {
19
+ if (writing.has(id) || held.has(id)) continue;
20
+ held.set(id, {
21
+ frame,
22
+ world: poseFrame.world(id),
23
+ from: scene.get(id).pose
24
+ });
25
+ }
26
+ }
27
+ return held;
28
+ }
29
+ /** `previews` with each held node posed in its frame's previewed pose, so it
30
+ * stays where it drew. */
31
+ function holdInPlace(previews, held, poseFrame) {
32
+ const { compose, decompose } = poseFrame.pc;
33
+ for (const [id, h] of held) {
34
+ const stored = previews.get(h.frame);
35
+ if (stored === void 0) continue;
36
+ const above = poseFrame.parentWorld(h.frame);
37
+ previews.set(id, decompose(poseFrame.childFrame(h.frame, above === null ? stored : compose(above, stored)), h.world));
38
+ }
39
+ return previews;
40
+ }
41
+
42
+ //#endregion
43
+ export { captureHeld, holdInPlace };
44
+ //# sourceMappingURL=held.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"held.js","names":[],"sources":["../../../../src/interactions/actions/resize/held.ts"],"sourcesContent":["/**\n * What a resized frame holds: a resize changes the box, not where the\n * contents draw, so each node stored in a written frame and not written\n * itself is re-expressed in the frame's new pose.\n */\nimport { heldInFrame } from 'core/scene/carryDescendants';\nimport { definesFrame } from 'core/scene/effectivePose';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport type { PoseFrame } from '../poseFrame';\n\n/** A node held in place: the frame it is stored in, where it draws, and its\n * stored pose at press. */\nexport interface HeldNode {\n readonly frame: NodeId;\n readonly world: unknown;\n readonly from: unknown;\n}\n\n/** The nodes stored in a frame among `writeIds` that the resize does not write. */\nexport function captureHeld(\n scene: Scene<unknown, string, unknown>,\n writeIds: readonly NodeId[],\n poseFrame: PoseFrame<unknown>,\n): Map<NodeId, HeldNode> {\n const held = new Map<NodeId, HeldNode>();\n if (poseFrame.pc.closure === 'identity') return held;\n const writing = new Set(writeIds);\n for (const frame of writeIds) {\n const node = scene.get(frame);\n if (!node || !definesFrame(node)) continue;\n for (const id of heldInFrame(scene, frame)) {\n if (writing.has(id) || held.has(id)) continue;\n held.set(id, { frame, world: poseFrame.world(id), from: scene.get(id)!.pose });\n }\n }\n return held;\n}\n\n/** `previews` with each held node posed in its frame's previewed pose, so it\n * stays where it drew. */\nexport function holdInPlace(\n previews: Map<NodeId, unknown>,\n held: ReadonlyMap<NodeId, HeldNode>,\n poseFrame: PoseFrame<unknown>,\n): Map<NodeId, unknown> {\n const { compose, decompose } = poseFrame.pc;\n for (const [id, h] of held) {\n const stored = previews.get(h.frame);\n if (stored === undefined) continue;\n const above = poseFrame.parentWorld(h.frame);\n previews.set(id, decompose(poseFrame.childFrame(h.frame, above === null ? stored : compose(above, stored)), h.world));\n }\n return previews;\n}\n"],"mappings":";;;;;;;;;;AAmBA,SAAgB,YACd,OACA,UACA,WACuB;CACvB,MAAM,uBAAO,IAAI,IAAsB;CACvC,IAAI,UAAU,GAAG,YAAY,YAAY,OAAO;CAChD,MAAM,UAAU,IAAI,IAAI,QAAQ;CAChC,KAAK,MAAM,SAAS,UAAU;EAC5B,MAAM,OAAO,MAAM,IAAI,KAAK;EAC5B,IAAI,CAAC,QAAQ,CAAC,aAAa,IAAI,GAAG;EAClC,KAAK,MAAM,MAAM,YAAY,OAAO,KAAK,GAAG;GAC1C,IAAI,QAAQ,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,GAAG;GACrC,KAAK,IAAI,IAAI;IAAE;IAAO,OAAO,UAAU,MAAM,EAAE;IAAG,MAAM,MAAM,IAAI,EAAE,CAAC,CAAE;GAAK,CAAC;EAC/E;CACF;CACA,OAAO;AACT;;;AAIA,SAAgB,YACd,UACA,MACA,WACsB;CACtB,MAAM,EAAE,SAAS,cAAc,UAAU;CACzC,KAAK,MAAM,CAAC,IAAI,MAAM,MAAM;EAC1B,MAAM,SAAS,SAAS,IAAI,EAAE,KAAK;EACnC,IAAI,WAAW,QAAW;EAC1B,MAAM,QAAQ,UAAU,YAAY,EAAE,KAAK;EAC3C,SAAS,IAAI,IAAI,UAAU,UAAU,WAAW,EAAE,OAAO,UAAU,OAAO,SAAS,QAAQ,OAAO,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC;CACtH;CACA,OAAO;AACT"}
@@ -6,10 +6,11 @@ import { transformFinisher } from "../transformFinish.js";
6
6
  import { readGestureLifecycle } from "../gestureLifecycle.js";
7
7
  import { gestureReaders } from "../../gestures/shared/screenTolerance.js";
8
8
  import { drawnBoxes } from "../drawnBoxes.js";
9
+ import { captureHeld } from "./held.js";
9
10
  import { boxFrame } from "./boxFrame.js";
10
11
  import { buildGestureContext, captureBox, captureStarts, captureTargets, resolvePolicy } from "./capture.js";
11
12
  import { boxMinimum } from "./minimum.js";
12
- import { inputSession } from "../../../features/snap/session2d.js";
13
+ import { inputSession } from "../../../domains/snap/session2d.js";
13
14
 
14
15
  //#region src/interactions/actions/resize/session.ts
15
16
  /** Capture what resizing `ids` from `anchor` acts on. Null when nothing it
@@ -42,6 +43,7 @@ function captureResize(scene, ids, anchor, deps) {
42
43
  box,
43
44
  startPoses: starts.startPoses,
44
45
  startWorlds: starts.startWorlds,
46
+ held: captureHeld(scene, written, poseFrame),
45
47
  geometryOf,
46
48
  poseFrame,
47
49
  view
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","names":[],"sources":["../../../../src/interactions/actions/resize/session.ts"],"sourcesContent":["import type { PoseLinear } from '@weasel-js/geom';\nimport type { ActionDeps, InvocationCtx } from '@weasel-js/routing';\nimport { transformFinisher, type TransformFinisher } from '../transformFinish';\nimport type { Op } from 'core/ops/types';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { gestureReaders, type GestureReaders } from '../../gestures/shared/screenTolerance';\nimport type { BoundsConstraint, GestureContext, ResizeAnchor } from '../../gestures/types';\nimport type { GeometryProjection } from '../geometryProjection';\nimport { readGestureLifecycle, type GestureLifecycle } from '../gestureLifecycle';\nimport { nodeDescriptors, poseDescriptorOf } from '../poseDescriptorDep';\nimport { scenePoseFrame, type PoseFrame } from '../poseFrame';\nimport { buildGestureContext, captureBox, captureStarts, captureTargets, resolvePolicy } from './capture';\nimport type { PoseDescriptor } from './geometry';\nimport type { InkExtents } from 'core/geometry/inkExtents';\nimport { drawnBoxes } from '../drawnBoxes';\nimport type { MinSize } from 'core/scene/minSize';\nimport { boxMinimum } from './minimum';\nimport { boxFrame } from './boxFrame';\nimport { localToWorld } from 'core/geometry/targetFrame';\nimport { outsetBox } from 'core/geometry/inkExtents';\nimport type { SnapBegin, SnapSession } from '../snapDep';\nimport { inputSession } from 'features/snap/session2d';\n\n/** The box the drag resizes, as the press found it. */\nexport interface ResizeBox {\n /** The union for a group or a multi-selection, a lone target's own bounds\n * otherwise. The `src` rect every write id is remapped from. */\n readonly bounds: Bounds;\n readonly anchor: ResizeAnchor;\n /** A lone target's rotation; 0 for a group. */\n readonly rotation: number;\n /** A lone target's `transform`; none for a group. */\n readonly transform?: PoseLinear;\n /** World position of the corner opposite the dragged one, which a resize\n * in a turned or skewed frame pins. */\n readonly fixedWorld: { x: number; y: number };\n /** How far the ink reaches past `bounds` in its own frame. The handles sit\n * on `bounds` grown by it, and the constraints see that box; the stroke\n * does not scale, so the same extents come off whatever box they return. */\n readonly extents: InkExtents;\n}\n\n/** What a resize captured at press. Nothing here changes during the drag. */\nexport interface ResizeSession {\n readonly scene: Scene<unknown, string, unknown>;\n /** The ids the gesture writes: the leaf set for a group, else the selection. */\n readonly writeIds: readonly NodeId[];\n /** Whether `box` stands for several write ids, each remapped inside it,\n * rather than being a lone target's own. */\n readonly sharedBox: boolean;\n readonly box: ResizeBox;\n /** Start poses as stored: the `from` of each op. */\n readonly startPoses: ReadonlyMap<NodeId, unknown>;\n /** Start poses in world, the frame the anchor math and the drag share. */\n readonly startWorlds: ReadonlyMap<NodeId, unknown>;\n /** Where the pointer pressed. */\n readonly startWorld: { x: number; y: number };\n readonly geometryOf: (id: NodeId) => PoseDescriptor<unknown>;\n /** World reads and local writes over the scene's composition strategy. */\n readonly poseFrame: PoseFrame<unknown>;\n readonly view: unknown;\n /** The smallest `box` may be resized to, from the written nodes' own\n * minimums: a floor under every constraint. `null` for none. */\n readonly minimum: MinSize | null;\n readonly constraints: readonly BoundsConstraint<Bounds>[];\n /** Reused across the drag; constraints mutate its `scratch`. */\n readonly gestureCtx: GestureContext<Bounds>;\n readonly applyOps?: (ops: Op[], label: string) => void;\n /** Finishes the committed batch with the other nodes that change with it. */\n readonly finish?: TransformFinisher;\n /** When present, the commit maps each leaf's data-held geometry by the\n * affine its pose underwent. */\n readonly geometryProjection?: GeometryProjection;\n readonly selectionMethods: SelectionApi['adapterMethods'] | undefined;\n /** Label, history, and callbacks from the `resizePolicy` dep. */\n readonly lifecycle: GestureLifecycle;\n /** The drag's snapping: the `snap` dep's session, else one that only holds\n * the handle to its axis and Shift to the aspect. */\n readonly snap: SnapSession;\n}\n\n/** What one `onMove` produced. Replaced, not mutated, by the next. */\nexport interface ResizeFrame {\n /** Stored-frame pose of every write id the move reached. */\n readonly previews: Map<NodeId, unknown>;\n /** The box the move resized `ResizeBox.bounds` to; absent before the first move. */\n readonly proposed?: Bounds;\n}\n\n/** The part of a resize that a box alone decides: what it writes, the box\n * they share, and where each starts. */\nexport type ResizePlace = Pick<\n ResizeSession,\n 'scene' | 'writeIds' | 'sharedBox' | 'box' | 'startPoses' | 'startWorlds' | 'geometryOf' | 'poseFrame' | 'view' | 'minimum'\n>;\n\n/** Capture what resizing `ids` from `anchor` acts on. Null when nothing it\n * would write exists. */\nexport function captureResize(\n scene: Scene<unknown, string, unknown>,\n ids: readonly NodeId[],\n anchor: ResizeAnchor,\n deps: Pick<ActionDeps, 'poseDescriptor' | 'resizePolicy' | 'view' | 'boundsIncludeStroke'>,\n): {\n place: ResizePlace;\n ruleOrigin: Bounds;\n policy: ActionDeps['resizePolicy'];\n constraints: BoundsConstraint<Bounds>[];\n} | null {\n const geometry = poseDescriptorOf(deps.poseDescriptor);\n const policy = deps.resizePolicy;\n const { constraints, expandIds } = resolvePolicy(policy);\n const geometryOf = nodeDescriptors(scene, geometry);\n\n const targets = captureTargets(scene, ids, expandIds);\n if (!targets) return null;\n const { writeIds, isGroupPath } = targets;\n\n // The drag delta is world, so the anchor math runs on world poses — carried\n // into the plane the edit is measured in — and each result is carried back\n // to its node's plane and stored in the node's own parent frame.\n const poseFrame = scenePoseFrame(scene);\n const view = deps.view;\n const boxes = drawnBoxes({ ...deps, scene }, poseFrame);\n const starts = captureStarts(scene, writeIds, geometryOf, poseFrame, view, boxes);\n if (starts.startPoses.size === 0) return null;\n\n const { box, ruleOrigin } = captureBox(starts, writeIds, isGroupPath, anchor, geometry, geometryOf);\n const sharedBox = isGroupPath || writeIds.length > 1;\n const written = writeIds.filter((id) => starts.startPoses.has(id));\n return {\n place: {\n scene,\n writeIds,\n sharedBox,\n minimum: boxMinimum(scene, written, starts.leafBounds, starts.startWorlds, box.bounds, sharedBox),\n box,\n startPoses: starts.startPoses,\n startWorlds: starts.startWorlds,\n geometryOf,\n poseFrame,\n view,\n },\n ruleOrigin,\n policy,\n constraints,\n };\n}\n\n/** The drag's snap session, over the box as drawn in its own frame. */\nfunction beginSnap(ctx: InvocationCtx, ids: readonly NodeId[], press: { x: number; y: number }, box: ResizeBox): SnapSession {\n const frame = boxFrame(box, box.bounds);\n const req: SnapBegin = {\n gesture: 'resize',\n ids,\n press,\n handle: box.anchor,\n constrain: 'aspect',\n box: { bounds: outsetBox(box.bounds, box.extents), toWorld: (p) => localToWorld(frame, p.x, p.y) },\n };\n return ctx.deps.snap?.begin(req) ?? inputSession(req);\n}\n\n/** Capture a resize at press. Null when nothing is selected, the press is not\n * on a resize handle, or nothing it would write exists. Runs each\n * constraint's `onStart`. */\nexport function beginResize(\n ctx: InvocationCtx,\n): { session: ResizeSession; readers: GestureReaders } | null {\n const selection = ctx.deps.selection;\n const scene = ctx.deps.scene;\n if (!selection || !scene) return null;\n\n const ids = selection.get() as NodeId[];\n if (ids.length === 0) return null;\n\n const anchor = ctx.drag?.affordance?.anchor;\n if (!anchor) return null;\n\n const captured = captureResize(scene, ids, anchor, ctx.deps);\n if (!captured) return null;\n const { place, ruleOrigin, policy, constraints } = captured;\n const startWorld = { x: ctx.drag?.start.x ?? 0, y: ctx.drag?.start.y ?? 0 };\n const readers = gestureReaders(ctx.deps);\n const gestureCtx = buildGestureContext(ctx, ids, ruleOrigin, startWorld, readers);\n for (const b of constraints) b.onStart?.(gestureCtx);\n\n const session: ResizeSession = {\n ...place,\n startWorld,\n constraints,\n gestureCtx,\n applyOps: ctx.deps.applyOps,\n finish: transformFinisher(ctx.deps),\n geometryProjection: ctx.deps.geometryProjection,\n selectionMethods: selection.adapterMethods,\n lifecycle: readGestureLifecycle(policy, 'Resize', constraints),\n snap: beginSnap(ctx, ids, startWorld, place.box),\n };\n return { session, readers };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAoGA,SAAgB,cACd,OACA,KACA,QACA,MAMO;CACP,MAAM,WAAW,iBAAiB,KAAK,cAAc;CACrD,MAAM,SAAS,KAAK;CACpB,MAAM,EAAE,aAAa,cAAc,cAAc,MAAM;CACvD,MAAM,aAAa,gBAAgB,OAAO,QAAQ;CAElD,MAAM,UAAU,eAAe,OAAO,KAAK,SAAS;CACpD,IAAI,CAAC,SAAS,OAAO;CACrB,MAAM,EAAE,UAAU,gBAAgB;CAKlC,MAAM,YAAY,eAAe,KAAK;CACtC,MAAM,OAAO,KAAK;CAClB,MAAM,QAAQ,WAAW;EAAE,GAAG;EAAM;CAAM,GAAG,SAAS;CACtD,MAAM,SAAS,cAAc,OAAO,UAAU,YAAY,WAAW,MAAM,KAAK;CAChF,IAAI,OAAO,WAAW,SAAS,GAAG,OAAO;CAEzC,MAAM,EAAE,KAAK,eAAe,WAAW,QAAQ,UAAU,aAAa,QAAQ,UAAU,UAAU;CAClG,MAAM,YAAY,eAAe,SAAS,SAAS;CACnD,MAAM,UAAU,SAAS,QAAQ,OAAO,OAAO,WAAW,IAAI,EAAE,CAAC;CACjE,OAAO;EACL,OAAO;GACL;GACA;GACA;GACA,SAAS,WAAW,OAAO,SAAS,OAAO,YAAY,OAAO,aAAa,IAAI,QAAQ,SAAS;GAChG;GACA,YAAY,OAAO;GACnB,aAAa,OAAO;GACpB;GACA;GACA;EACF;EACA;EACA;EACA;CACF;AACF;;AAGA,SAAS,UAAU,KAAoB,KAAwB,OAAiC,KAA6B;CAC3H,MAAM,QAAQ,SAAS,KAAK,IAAI,MAAM;CACtC,MAAM,MAAiB;EACrB,SAAS;EACT;EACA;EACA,QAAQ,IAAI;EACZ,WAAW;EACX,KAAK;GAAE,QAAQ,UAAU,IAAI,QAAQ,IAAI,OAAO;GAAG,UAAU,MAAM,aAAa,OAAO,EAAE,GAAG,EAAE,CAAC;EAAE;CACnG;CACA,OAAO,IAAI,KAAK,MAAM,MAAM,GAAG,KAAK,aAAa,GAAG;AACtD;;;;AAKA,SAAgB,YACd,KAC4D;CAC5D,MAAM,YAAY,IAAI,KAAK;CAC3B,MAAM,QAAQ,IAAI,KAAK;CACvB,IAAI,CAAC,aAAa,CAAC,OAAO,OAAO;CAEjC,MAAM,MAAM,UAAU,IAAI;CAC1B,IAAI,IAAI,WAAW,GAAG,OAAO;CAE7B,MAAM,SAAS,IAAI,MAAM,YAAY;CACrC,IAAI,CAAC,QAAQ,OAAO;CAEpB,MAAM,WAAW,cAAc,OAAO,KAAK,QAAQ,IAAI,IAAI;CAC3D,IAAI,CAAC,UAAU,OAAO;CACtB,MAAM,EAAE,OAAO,YAAY,QAAQ,gBAAgB;CACnD,MAAM,aAAa;EAAE,GAAG,IAAI,MAAM,MAAM,KAAK;EAAG,GAAG,IAAI,MAAM,MAAM,KAAK;CAAE;CAC1E,MAAM,UAAU,eAAe,IAAI,IAAI;CACvC,MAAM,aAAa,oBAAoB,KAAK,KAAK,YAAY,YAAY,OAAO;CAChF,KAAK,MAAM,KAAK,aAAa,EAAE,UAAU,UAAU;CAcnD,OAAO;EAAE;GAXP,GAAG;GACH;GACA;GACA;GACA,UAAU,IAAI,KAAK;GACnB,QAAQ,kBAAkB,IAAI,IAAI;GAClC,oBAAoB,IAAI,KAAK;GAC7B,kBAAkB,UAAU;GAC5B,WAAW,qBAAqB,QAAQ,UAAU,WAAW;GAC7D,MAAM,UAAU,KAAK,KAAK,YAAY,MAAM,GAAG;EAExC;EAAS;CAAQ;AAC5B"}
1
+ {"version":3,"file":"session.js","names":[],"sources":["../../../../src/interactions/actions/resize/session.ts"],"sourcesContent":["import type { PoseLinear } from '@weasel-js/geom';\nimport type { ActionDeps, InvocationCtx } from '@weasel-js/routing';\nimport { transformFinisher, type TransformFinisher } from '../transformFinish';\nimport type { Op } from 'core/ops/types';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { gestureReaders, type GestureReaders } from '../../gestures/shared/screenTolerance';\nimport type { BoundsConstraint, GestureContext, ResizeAnchor } from '../../gestures/types';\nimport type { GeometryProjection } from '../geometryProjection';\nimport { readGestureLifecycle, type GestureLifecycle } from '../gestureLifecycle';\nimport { nodeDescriptors, poseDescriptorOf } from '../poseDescriptorDep';\nimport { scenePoseFrame, type PoseFrame } from '../poseFrame';\nimport { buildGestureContext, captureBox, captureStarts, captureTargets, resolvePolicy } from './capture';\nimport type { PoseDescriptor } from './geometry';\nimport type { InkExtents } from 'core/geometry/inkExtents';\nimport { drawnBoxes } from '../drawnBoxes';\nimport type { MinSize } from 'core/scene/minSize';\nimport { boxMinimum } from './minimum';\nimport { boxFrame } from './boxFrame';\nimport { captureHeld, type HeldNode } from './held';\nimport { localToWorld } from 'core/geometry/targetFrame';\nimport { outsetBox } from 'core/geometry/inkExtents';\nimport type { SnapBegin, SnapSession } from '../snapDep';\nimport { inputSession } from 'domains/snap/session2d';\n\n/** The box the drag resizes, as the press found it. */\nexport interface ResizeBox {\n /** The union for a group or a multi-selection, a lone target's own bounds\n * otherwise. The `src` rect every write id is remapped from. */\n readonly bounds: Bounds;\n readonly anchor: ResizeAnchor;\n /** A lone target's rotation; 0 for a group. */\n readonly rotation: number;\n /** A lone target's `transform`; none for a group. */\n readonly transform?: PoseLinear;\n /** World position of the corner opposite the dragged one, which a resize\n * in a turned or skewed frame pins. */\n readonly fixedWorld: { x: number; y: number };\n /** How far the ink reaches past `bounds` in its own frame. The handles sit\n * on `bounds` grown by it, and the constraints see that box; the stroke\n * does not scale, so the same extents come off whatever box they return. */\n readonly extents: InkExtents;\n}\n\n/** What a resize captured at press. Nothing here changes during the drag. */\nexport interface ResizeSession {\n readonly scene: Scene<unknown, string, unknown>;\n /** The ids the gesture writes: the leaf set for a group, else the selection. */\n readonly writeIds: readonly NodeId[];\n /** Whether `box` stands for several write ids, each remapped inside it,\n * rather than being a lone target's own. */\n readonly sharedBox: boolean;\n readonly box: ResizeBox;\n /** Start poses as stored: the `from` of each op. */\n readonly startPoses: ReadonlyMap<NodeId, unknown>;\n /** Start poses in world, the frame the anchor math and the drag share. */\n readonly startWorlds: ReadonlyMap<NodeId, unknown>;\n /** What the written frames hold that the resize leaves where it draws. */\n readonly held: ReadonlyMap<NodeId, HeldNode>;\n /** Where the pointer pressed. */\n readonly startWorld: { x: number; y: number };\n readonly geometryOf: (id: NodeId) => PoseDescriptor<unknown>;\n /** World reads and local writes over the scene's composition strategy. */\n readonly poseFrame: PoseFrame<unknown>;\n readonly view: unknown;\n /** The smallest `box` may be resized to, from the written nodes' own\n * minimums: a floor under every constraint. `null` for none. */\n readonly minimum: MinSize | null;\n readonly constraints: readonly BoundsConstraint<Bounds>[];\n /** Reused across the drag; constraints mutate its `scratch`. */\n readonly gestureCtx: GestureContext<Bounds>;\n readonly applyOps?: (ops: Op[], label: string) => void;\n /** Finishes the committed batch with the other nodes that change with it. */\n readonly finish?: TransformFinisher;\n /** When present, the commit maps each leaf's data-held geometry by the\n * affine its pose underwent. */\n readonly geometryProjection?: GeometryProjection;\n readonly selectionMethods: SelectionApi['adapterMethods'] | undefined;\n /** Label, history, and callbacks from the `resizePolicy` dep. */\n readonly lifecycle: GestureLifecycle;\n /** The drag's snapping: the `snap` dep's session, else one that only holds\n * the handle to its axis and Shift to the aspect. */\n readonly snap: SnapSession;\n}\n\n/** What one `onMove` produced. Replaced, not mutated, by the next. */\nexport interface ResizeFrame {\n /** Stored-frame pose of every write id the move reached. */\n readonly previews: Map<NodeId, unknown>;\n /** The box the move resized `ResizeBox.bounds` to; absent before the first move. */\n readonly proposed?: Bounds;\n}\n\n/** The part of a resize that a box alone decides: what it writes, the box\n * they share, and where each starts. */\nexport type ResizePlace = Pick<\n ResizeSession,\n 'scene' | 'writeIds' | 'sharedBox' | 'box' | 'startPoses' | 'startWorlds' | 'held' | 'geometryOf' | 'poseFrame' | 'view' | 'minimum'\n>;\n\n/** Capture what resizing `ids` from `anchor` acts on. Null when nothing it\n * would write exists. */\nexport function captureResize(\n scene: Scene<unknown, string, unknown>,\n ids: readonly NodeId[],\n anchor: ResizeAnchor,\n deps: Pick<ActionDeps, 'poseDescriptor' | 'resizePolicy' | 'view' | 'boundsIncludeStroke'>,\n): {\n place: ResizePlace;\n ruleOrigin: Bounds;\n policy: ActionDeps['resizePolicy'];\n constraints: BoundsConstraint<Bounds>[];\n} | null {\n const geometry = poseDescriptorOf(deps.poseDescriptor);\n const policy = deps.resizePolicy;\n const { constraints, expandIds } = resolvePolicy(policy);\n const geometryOf = nodeDescriptors(scene, geometry);\n\n const targets = captureTargets(scene, ids, expandIds);\n if (!targets) return null;\n const { writeIds, isGroupPath } = targets;\n\n // The drag delta is world, so the anchor math runs on world poses — carried\n // into the plane the edit is measured in — and each result is carried back\n // to its node's plane and stored in the node's own parent frame.\n const poseFrame = scenePoseFrame(scene);\n const view = deps.view;\n const boxes = drawnBoxes({ ...deps, scene }, poseFrame);\n const starts = captureStarts(scene, writeIds, geometryOf, poseFrame, view, boxes);\n if (starts.startPoses.size === 0) return null;\n\n const { box, ruleOrigin } = captureBox(starts, writeIds, isGroupPath, anchor, geometry, geometryOf);\n const sharedBox = isGroupPath || writeIds.length > 1;\n const written = writeIds.filter((id) => starts.startPoses.has(id));\n return {\n place: {\n scene,\n writeIds,\n sharedBox,\n minimum: boxMinimum(scene, written, starts.leafBounds, starts.startWorlds, box.bounds, sharedBox),\n box,\n startPoses: starts.startPoses,\n startWorlds: starts.startWorlds,\n held: captureHeld(scene, written, poseFrame),\n geometryOf,\n poseFrame,\n view,\n },\n ruleOrigin,\n policy,\n constraints,\n };\n}\n\n/** The drag's snap session, over the box as drawn in its own frame. */\nfunction beginSnap(ctx: InvocationCtx, ids: readonly NodeId[], press: { x: number; y: number }, box: ResizeBox): SnapSession {\n const frame = boxFrame(box, box.bounds);\n const req: SnapBegin = {\n gesture: 'resize',\n ids,\n press,\n handle: box.anchor,\n constrain: 'aspect',\n box: { bounds: outsetBox(box.bounds, box.extents), toWorld: (p) => localToWorld(frame, p.x, p.y) },\n };\n return ctx.deps.snap?.begin(req) ?? inputSession(req);\n}\n\n/** Capture a resize at press. Null when nothing is selected, the press is not\n * on a resize handle, or nothing it would write exists. Runs each\n * constraint's `onStart`. */\nexport function beginResize(\n ctx: InvocationCtx,\n): { session: ResizeSession; readers: GestureReaders } | null {\n const selection = ctx.deps.selection;\n const scene = ctx.deps.scene;\n if (!selection || !scene) return null;\n\n const ids = selection.get() as NodeId[];\n if (ids.length === 0) return null;\n\n const anchor = ctx.drag?.affordance?.anchor;\n if (!anchor) return null;\n\n const captured = captureResize(scene, ids, anchor, ctx.deps);\n if (!captured) return null;\n const { place, ruleOrigin, policy, constraints } = captured;\n const startWorld = { x: ctx.drag?.start.x ?? 0, y: ctx.drag?.start.y ?? 0 };\n const readers = gestureReaders(ctx.deps);\n const gestureCtx = buildGestureContext(ctx, ids, ruleOrigin, startWorld, readers);\n for (const b of constraints) b.onStart?.(gestureCtx);\n\n const session: ResizeSession = {\n ...place,\n startWorld,\n constraints,\n gestureCtx,\n applyOps: ctx.deps.applyOps,\n finish: transformFinisher(ctx.deps),\n geometryProjection: ctx.deps.geometryProjection,\n selectionMethods: selection.adapterMethods,\n lifecycle: readGestureLifecycle(policy, 'Resize', constraints),\n snap: beginSnap(ctx, ids, startWorld, place.box),\n };\n return { session, readers };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAuGA,SAAgB,cACd,OACA,KACA,QACA,MAMO;CACP,MAAM,WAAW,iBAAiB,KAAK,cAAc;CACrD,MAAM,SAAS,KAAK;CACpB,MAAM,EAAE,aAAa,cAAc,cAAc,MAAM;CACvD,MAAM,aAAa,gBAAgB,OAAO,QAAQ;CAElD,MAAM,UAAU,eAAe,OAAO,KAAK,SAAS;CACpD,IAAI,CAAC,SAAS,OAAO;CACrB,MAAM,EAAE,UAAU,gBAAgB;CAKlC,MAAM,YAAY,eAAe,KAAK;CACtC,MAAM,OAAO,KAAK;CAClB,MAAM,QAAQ,WAAW;EAAE,GAAG;EAAM;CAAM,GAAG,SAAS;CACtD,MAAM,SAAS,cAAc,OAAO,UAAU,YAAY,WAAW,MAAM,KAAK;CAChF,IAAI,OAAO,WAAW,SAAS,GAAG,OAAO;CAEzC,MAAM,EAAE,KAAK,eAAe,WAAW,QAAQ,UAAU,aAAa,QAAQ,UAAU,UAAU;CAClG,MAAM,YAAY,eAAe,SAAS,SAAS;CACnD,MAAM,UAAU,SAAS,QAAQ,OAAO,OAAO,WAAW,IAAI,EAAE,CAAC;CACjE,OAAO;EACL,OAAO;GACL;GACA;GACA;GACA,SAAS,WAAW,OAAO,SAAS,OAAO,YAAY,OAAO,aAAa,IAAI,QAAQ,SAAS;GAChG;GACA,YAAY,OAAO;GACnB,aAAa,OAAO;GACpB,MAAM,YAAY,OAAO,SAAS,SAAS;GAC3C;GACA;GACA;EACF;EACA;EACA;EACA;CACF;AACF;;AAGA,SAAS,UAAU,KAAoB,KAAwB,OAAiC,KAA6B;CAC3H,MAAM,QAAQ,SAAS,KAAK,IAAI,MAAM;CACtC,MAAM,MAAiB;EACrB,SAAS;EACT;EACA;EACA,QAAQ,IAAI;EACZ,WAAW;EACX,KAAK;GAAE,QAAQ,UAAU,IAAI,QAAQ,IAAI,OAAO;GAAG,UAAU,MAAM,aAAa,OAAO,EAAE,GAAG,EAAE,CAAC;EAAE;CACnG;CACA,OAAO,IAAI,KAAK,MAAM,MAAM,GAAG,KAAK,aAAa,GAAG;AACtD;;;;AAKA,SAAgB,YACd,KAC4D;CAC5D,MAAM,YAAY,IAAI,KAAK;CAC3B,MAAM,QAAQ,IAAI,KAAK;CACvB,IAAI,CAAC,aAAa,CAAC,OAAO,OAAO;CAEjC,MAAM,MAAM,UAAU,IAAI;CAC1B,IAAI,IAAI,WAAW,GAAG,OAAO;CAE7B,MAAM,SAAS,IAAI,MAAM,YAAY;CACrC,IAAI,CAAC,QAAQ,OAAO;CAEpB,MAAM,WAAW,cAAc,OAAO,KAAK,QAAQ,IAAI,IAAI;CAC3D,IAAI,CAAC,UAAU,OAAO;CACtB,MAAM,EAAE,OAAO,YAAY,QAAQ,gBAAgB;CACnD,MAAM,aAAa;EAAE,GAAG,IAAI,MAAM,MAAM,KAAK;EAAG,GAAG,IAAI,MAAM,MAAM,KAAK;CAAE;CAC1E,MAAM,UAAU,eAAe,IAAI,IAAI;CACvC,MAAM,aAAa,oBAAoB,KAAK,KAAK,YAAY,YAAY,OAAO;CAChF,KAAK,MAAM,KAAK,aAAa,EAAE,UAAU,UAAU;CAcnD,OAAO;EAAE;GAXP,GAAG;GACH;GACA;GACA;GACA,UAAU,IAAI,KAAK;GACnB,QAAQ,kBAAkB,IAAI,IAAI;GAClC,oBAAoB,IAAI,KAAK;GAC7B,kBAAkB,UAAU;GAC5B,WAAW,qBAAqB,QAAQ,UAAU,WAAW;GAC7D,MAAM,UAAU,KAAK,KAAK,YAAY,MAAM,GAAG;EAExC;EAAS;CAAQ;AAC5B"}
@@ -67,6 +67,15 @@ function resolveOverlays(overlays) {
67
67
  points: ov.points,
68
68
  radiusPx: ov.radiusPx
69
69
  });
70
+ break;
71
+ case "reason":
72
+ if (ov.text === "") break;
73
+ out.push({
74
+ kind: "reason",
75
+ visibilityId: "action.reason",
76
+ at: ov.at,
77
+ text: ov.text
78
+ });
70
79
  }
71
80
  return out;
72
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"resolveOverlays.js","names":[],"sources":["../../../src/interactions/actions/resolveOverlays.ts"],"sourcesContent":["/**\n * What an in-flight gesture is proposing to paint *beside* the scene, resolved\n * to geometry.\n *\n * The sibling of `resolvePreviews`: that one answers for the ghosts of scene\n * nodes a gesture is displacing, this one for the chrome a gesture draws that\n * is no node at all — a marquee rect, a lasso trail, the outline of a shape\n * being dragged out.\n *\n * What stays out, as in `resolvePreviews`: no view, no screen projection, no\n * `DrawCommand`, no style, no React, no dispatcher. World coordinates only.\n */\n\nimport type { InsertPreviewGeometry } from '../../canvas/insertPreviewExtent';\nimport { insertPreviewExtent } from '../../canvas/insertPreviewExtent';\nimport type { Bounds } from '../../core/viewport/fitViewToBounds';\nimport type { KitInsertShape } from '../../core/shapeKinds';\nimport type { OngoingOverlay, OverlayRole } from '@weasel-js/routing';\n\ntype Point = { x: number; y: number };\n\n/**\n * The chrome-caps id a surface consults before painting each variant. The\n * gating itself is the painter's — two views of one surface may disagree about\n * whether to show an in-flight marquee — but the id is not something a caller\n * should have to guess.\n */\nexport type OverlayVisibilityId =\n | 'action.marquee'\n | 'action.lasso'\n | 'action.insert-preview'\n | 'action.polyline'\n | 'action.brush';\n\n/**\n * One in-flight overlay, in world coordinates.\n *\n * Every degenerate overlay is already gone: a marquee of zero size, a lasso\n * under two vertices, a zero-area insert of anything but a pencil, a pencil\n * under two samples, a run of fewer than two points. Whatever is in this list\n * is worth painting.\n */\nexport type ResolvedOverlay =\n | {\n kind: 'marquee';\n visibilityId: 'action.marquee';\n /** The drag normalized: `start`/`current` in either order, one AABB. */\n bounds: Bounds;\n /** Additive intent. Core's 2D layer paints the same rect either way. */\n shiftHeld: boolean;\n }\n | {\n kind: 'lasso';\n visibilityId: 'action.lasso';\n /** The trail so far, at least two long. The region it encloses is the\n * trail closed back to its first vertex. */\n vertices: ReadonlyArray<Point>;\n /** Live pointer position — the trail's last vertex until it advances. */\n current: Point;\n shiftHeld: boolean;\n }\n | {\n kind: 'insertPreview';\n visibilityId: 'action.insert-preview';\n shape: KitInsertShape;\n /** Extent of `geometry`, which for a radial or freehand shape is not the\n * drag rect. See `insertPreviewExtent`. */\n bounds: Bounds;\n geometry: InsertPreviewGeometry;\n /** The drag's anchor — a growth axis to mark. Absent for a pencil, which\n * has none. */\n anchorPoint?: Point;\n /** World affines the shape will also be drawn under, as the action gave them. */\n copies?: readonly (readonly [number, number, number, number, number, number])[];\n /** The action's per-shape payload, verbatim. Carries what geometry\n * cannot: an image insert's `src`, say. */\n extras: unknown;\n }\n | {\n kind: 'polyline';\n visibilityId: 'action.polyline';\n /** The run, at least two long, open — the last point does not join the\n * first. A closed sweep is a `lasso`. */\n points: ReadonlyArray<Point>;\n /** What the run is, for a painter choosing a style. Never defaulted\n * away: `'chrome'` when the action named none. A role the painter has\n * no style for is drawn as plain chrome, not dropped. */\n role: OverlayRole;\n }\n | {\n kind: 'brush';\n visibilityId: 'action.brush';\n /** The brush's path, at least one point; the last is where it is now. */\n points: ReadonlyArray<Point>;\n /** On screen: a painter draws it at this size at every zoom. */\n radiusPx: number;\n };\n\n/** The overlays worth painting, in the order the handles published them. */\nexport function resolveOverlays(overlays: Iterable<OngoingOverlay>): ResolvedOverlay[] {\n const out: ResolvedOverlay[] = [];\n for (const ov of overlays) {\n switch (ov.kind) {\n case 'marquee': {\n const x = Math.min(ov.start.x, ov.current.x);\n const y = Math.min(ov.start.y, ov.current.y);\n const width = Math.abs(ov.current.x - ov.start.x);\n const height = Math.abs(ov.current.y - ov.start.y);\n if (width === 0 && height === 0) break;\n out.push({\n kind: 'marquee',\n visibilityId: 'action.marquee',\n bounds: { x, y, width, height },\n shiftHeld: ov.shiftHeld,\n });\n break;\n }\n case 'lasso': {\n if (ov.vertices.length < 2) break;\n out.push({\n kind: 'lasso',\n visibilityId: 'action.lasso',\n vertices: ov.vertices,\n current: ov.current,\n shiftHeld: ov.shiftHeld,\n });\n break;\n }\n case 'insertPreview': {\n const { bounds, geometry } = insertPreviewExtent(ov);\n // A pencil can be meaningful at zero AABB — a closed loop, a\n // sub-threshold gesture — where every other shape cannot.\n if (bounds.width === 0 && bounds.height === 0 && ov.shape !== 'pencil') break;\n if (geometry.kind === 'pencil' && geometry.samples.length < 2) break;\n out.push({\n kind: 'insertPreview',\n visibilityId: 'action.insert-preview',\n // Routing types the insert shape as an open string; a\n // consumer-defined kind is legal there.\n shape: ov.shape as KitInsertShape,\n bounds,\n geometry,\n extras: ov.extras,\n ...(ov.anchorPoint && ov.shape !== 'pencil' ? { anchorPoint: ov.anchorPoint } : {}),\n ...(ov.copies ? { copies: ov.copies } : {}),\n });\n break;\n }\n case 'polyline': {\n if (ov.points.length < 2) break;\n out.push({\n kind: 'polyline',\n visibilityId: 'action.polyline',\n points: ov.points,\n role: ov.role ?? 'chrome',\n });\n break;\n }\n case 'brush': {\n if (ov.points.length === 0 || !(ov.radiusPx > 0)) break;\n out.push({ kind: 'brush', visibilityId: 'action.brush', points: ov.points, radiusPx: ov.radiusPx });\n break;\n }\n }\n }\n return out;\n}\n"],"mappings":";;;;AAmGA,SAAgB,gBAAgB,UAAuD;CACrF,MAAM,MAAyB,CAAC;CAChC,KAAK,MAAM,MAAM,UACf,QAAQ,GAAG,MAAX;EACE,KAAK,WAAW;GACd,MAAM,IAAI,KAAK,IAAI,GAAG,MAAM,GAAG,GAAG,QAAQ,CAAC;GAC3C,MAAM,IAAI,KAAK,IAAI,GAAG,MAAM,GAAG,GAAG,QAAQ,CAAC;GAC3C,MAAM,QAAQ,KAAK,IAAI,GAAG,QAAQ,IAAI,GAAG,MAAM,CAAC;GAChD,MAAM,SAAS,KAAK,IAAI,GAAG,QAAQ,IAAI,GAAG,MAAM,CAAC;GACjD,IAAI,UAAU,KAAK,WAAW,GAAG;GACjC,IAAI,KAAK;IACP,MAAM;IACN,cAAc;IACd,QAAQ;KAAE;KAAG;KAAG;KAAO;IAAO;IAC9B,WAAW,GAAG;GAChB,CAAC;GACD;EACF;EACA,KAAK;GACH,IAAI,GAAG,SAAS,SAAS,GAAG;GAC5B,IAAI,KAAK;IACP,MAAM;IACN,cAAc;IACd,UAAU,GAAG;IACb,SAAS,GAAG;IACZ,WAAW,GAAG;GAChB,CAAC;GACD;EAEF,KAAK,iBAAiB;GACpB,MAAM,EAAE,QAAQ,aAAa,oBAAoB,EAAE;GAGnD,IAAI,OAAO,UAAU,KAAK,OAAO,WAAW,KAAK,GAAG,UAAU,UAAU;GACxE,IAAI,SAAS,SAAS,YAAY,SAAS,QAAQ,SAAS,GAAG;GAC/D,IAAI,KAAK;IACP,MAAM;IACN,cAAc;IAGd,OAAO,GAAG;IACV;IACA;IACA,QAAQ,GAAG;IACX,GAAI,GAAG,eAAe,GAAG,UAAU,WAAW,EAAE,aAAa,GAAG,YAAY,IAAI,CAAC;IACjF,GAAI,GAAG,SAAS,EAAE,QAAQ,GAAG,OAAO,IAAI,CAAC;GAC3C,CAAC;GACD;EACF;EACA,KAAK;GACH,IAAI,GAAG,OAAO,SAAS,GAAG;GAC1B,IAAI,KAAK;IACP,MAAM;IACN,cAAc;IACd,QAAQ,GAAG;IACX,MAAM,GAAG,QAAQ;GACnB,CAAC;GACD;EAEF,KAAK;GACH,IAAI,GAAG,OAAO,WAAW,KAAK,EAAE,GAAG,WAAW,IAAI;GAClD,IAAI,KAAK;IAAE,MAAM;IAAS,cAAc;IAAgB,QAAQ,GAAG;IAAQ,UAAU,GAAG;GAAS,CAAC;CAGtG;CAEF,OAAO;AACT"}
1
+ {"version":3,"file":"resolveOverlays.js","names":[],"sources":["../../../src/interactions/actions/resolveOverlays.ts"],"sourcesContent":["/**\n * What an in-flight gesture is proposing to paint *beside* the scene, resolved\n * to geometry.\n *\n * The sibling of `resolvePreviews`: that one answers for the ghosts of scene\n * nodes a gesture is displacing, this one for the chrome a gesture draws that\n * is no node at all — a marquee rect, a lasso trail, the outline of a shape\n * being dragged out.\n *\n * What stays out, as in `resolvePreviews`: no view, no screen projection, no\n * `DrawCommand`, no style, no React, no dispatcher. World coordinates only.\n */\n\nimport type { InsertPreviewGeometry } from '../../canvas/insertPreviewExtent';\nimport { insertPreviewExtent } from '../../canvas/insertPreviewExtent';\nimport type { Bounds } from '../../core/viewport/fitViewToBounds';\nimport type { KitInsertShape } from '../../core/shapeKinds';\nimport type { OngoingOverlay, OverlayRole } from '@weasel-js/routing';\nimport type { Point } from '@weasel-js/geom';\n\n/**\n * The chrome-caps id a surface consults before painting each variant. The\n * gating itself is the painter's — two views of one surface may disagree about\n * whether to show an in-flight marquee — but the id is not something a caller\n * should have to guess.\n */\nexport type OverlayVisibilityId =\n | 'action.marquee'\n | 'action.lasso'\n | 'action.insert-preview'\n | 'action.polyline'\n | 'action.brush'\n | 'action.reason';\n\n/**\n * One in-flight overlay, in world coordinates.\n *\n * Every degenerate overlay is already gone: a marquee of zero size, a lasso\n * under two vertices, a zero-area insert of anything but a pencil, a pencil\n * under two samples, a run of fewer than two points. Whatever is in this list\n * is worth painting.\n */\nexport type ResolvedOverlay =\n | {\n kind: 'marquee';\n visibilityId: 'action.marquee';\n /** The drag normalized: `start`/`current` in either order, one AABB. */\n bounds: Bounds;\n /** Additive intent. Core's 2D layer paints the same rect either way. */\n shiftHeld: boolean;\n }\n | {\n kind: 'lasso';\n visibilityId: 'action.lasso';\n /** The trail so far, at least two long. The region it encloses is the\n * trail closed back to its first vertex. */\n vertices: ReadonlyArray<Point>;\n /** Live pointer position — the trail's last vertex until it advances. */\n current: Point;\n shiftHeld: boolean;\n }\n | {\n kind: 'insertPreview';\n visibilityId: 'action.insert-preview';\n shape: KitInsertShape;\n /** Extent of `geometry`, which for a radial or freehand shape is not the\n * drag rect. See `insertPreviewExtent`. */\n bounds: Bounds;\n geometry: InsertPreviewGeometry;\n /** The drag's anchor — a growth axis to mark. Absent for a pencil, which\n * has none. */\n anchorPoint?: Point;\n /** World affines the shape will also be drawn under, as the action gave them. */\n copies?: readonly (readonly [number, number, number, number, number, number])[];\n /** The action's per-shape payload, verbatim. Carries what geometry\n * cannot: an image insert's `src`, say. */\n extras: unknown;\n }\n | {\n kind: 'polyline';\n visibilityId: 'action.polyline';\n /** The run, at least two long, open — the last point does not join the\n * first. A closed sweep is a `lasso`. */\n points: ReadonlyArray<Point>;\n /** What the run is, for a painter choosing a style. Never defaulted\n * away: `'chrome'` when the action named none. A role the painter has\n * no style for is drawn as plain chrome, not dropped. */\n role: OverlayRole;\n }\n | {\n kind: 'brush';\n visibilityId: 'action.brush';\n /** The brush's path, at least one point; the last is where it is now. */\n points: ReadonlyArray<Point>;\n /** On screen: a painter draws it at this size at every zoom. */\n radiusPx: number;\n }\n | {\n kind: 'reason';\n visibilityId: 'action.reason';\n /** The pointer, which a painter shows `text` beside. */\n at: Point;\n text: string;\n };\n\n/** The overlays worth painting, in the order the handles published them. */\nexport function resolveOverlays(overlays: Iterable<OngoingOverlay>): ResolvedOverlay[] {\n const out: ResolvedOverlay[] = [];\n for (const ov of overlays) {\n switch (ov.kind) {\n case 'marquee': {\n const x = Math.min(ov.start.x, ov.current.x);\n const y = Math.min(ov.start.y, ov.current.y);\n const width = Math.abs(ov.current.x - ov.start.x);\n const height = Math.abs(ov.current.y - ov.start.y);\n if (width === 0 && height === 0) break;\n out.push({\n kind: 'marquee',\n visibilityId: 'action.marquee',\n bounds: { x, y, width, height },\n shiftHeld: ov.shiftHeld,\n });\n break;\n }\n case 'lasso': {\n if (ov.vertices.length < 2) break;\n out.push({\n kind: 'lasso',\n visibilityId: 'action.lasso',\n vertices: ov.vertices,\n current: ov.current,\n shiftHeld: ov.shiftHeld,\n });\n break;\n }\n case 'insertPreview': {\n const { bounds, geometry } = insertPreviewExtent(ov);\n // A pencil can be meaningful at zero AABB — a closed loop, a\n // sub-threshold gesture — where every other shape cannot.\n if (bounds.width === 0 && bounds.height === 0 && ov.shape !== 'pencil') break;\n if (geometry.kind === 'pencil' && geometry.samples.length < 2) break;\n out.push({\n kind: 'insertPreview',\n visibilityId: 'action.insert-preview',\n // Routing types the insert shape as an open string; a\n // consumer-defined kind is legal there.\n shape: ov.shape as KitInsertShape,\n bounds,\n geometry,\n extras: ov.extras,\n ...(ov.anchorPoint && ov.shape !== 'pencil' ? { anchorPoint: ov.anchorPoint } : {}),\n ...(ov.copies ? { copies: ov.copies } : {}),\n });\n break;\n }\n case 'polyline': {\n if (ov.points.length < 2) break;\n out.push({\n kind: 'polyline',\n visibilityId: 'action.polyline',\n points: ov.points,\n role: ov.role ?? 'chrome',\n });\n break;\n }\n case 'brush': {\n if (ov.points.length === 0 || !(ov.radiusPx > 0)) break;\n out.push({ kind: 'brush', visibilityId: 'action.brush', points: ov.points, radiusPx: ov.radiusPx });\n break;\n }\n case 'reason': {\n if (ov.text === '') break;\n out.push({ kind: 'reason', visibilityId: 'action.reason', at: ov.at, text: ov.text });\n break;\n }\n }\n }\n return out;\n}\n"],"mappings":";;;;AA0GA,SAAgB,gBAAgB,UAAuD;CACrF,MAAM,MAAyB,CAAC;CAChC,KAAK,MAAM,MAAM,UACf,QAAQ,GAAG,MAAX;EACE,KAAK,WAAW;GACd,MAAM,IAAI,KAAK,IAAI,GAAG,MAAM,GAAG,GAAG,QAAQ,CAAC;GAC3C,MAAM,IAAI,KAAK,IAAI,GAAG,MAAM,GAAG,GAAG,QAAQ,CAAC;GAC3C,MAAM,QAAQ,KAAK,IAAI,GAAG,QAAQ,IAAI,GAAG,MAAM,CAAC;GAChD,MAAM,SAAS,KAAK,IAAI,GAAG,QAAQ,IAAI,GAAG,MAAM,CAAC;GACjD,IAAI,UAAU,KAAK,WAAW,GAAG;GACjC,IAAI,KAAK;IACP,MAAM;IACN,cAAc;IACd,QAAQ;KAAE;KAAG;KAAG;KAAO;IAAO;IAC9B,WAAW,GAAG;GAChB,CAAC;GACD;EACF;EACA,KAAK;GACH,IAAI,GAAG,SAAS,SAAS,GAAG;GAC5B,IAAI,KAAK;IACP,MAAM;IACN,cAAc;IACd,UAAU,GAAG;IACb,SAAS,GAAG;IACZ,WAAW,GAAG;GAChB,CAAC;GACD;EAEF,KAAK,iBAAiB;GACpB,MAAM,EAAE,QAAQ,aAAa,oBAAoB,EAAE;GAGnD,IAAI,OAAO,UAAU,KAAK,OAAO,WAAW,KAAK,GAAG,UAAU,UAAU;GACxE,IAAI,SAAS,SAAS,YAAY,SAAS,QAAQ,SAAS,GAAG;GAC/D,IAAI,KAAK;IACP,MAAM;IACN,cAAc;IAGd,OAAO,GAAG;IACV;IACA;IACA,QAAQ,GAAG;IACX,GAAI,GAAG,eAAe,GAAG,UAAU,WAAW,EAAE,aAAa,GAAG,YAAY,IAAI,CAAC;IACjF,GAAI,GAAG,SAAS,EAAE,QAAQ,GAAG,OAAO,IAAI,CAAC;GAC3C,CAAC;GACD;EACF;EACA,KAAK;GACH,IAAI,GAAG,OAAO,SAAS,GAAG;GAC1B,IAAI,KAAK;IACP,MAAM;IACN,cAAc;IACd,QAAQ,GAAG;IACX,MAAM,GAAG,QAAQ;GACnB,CAAC;GACD;EAEF,KAAK;GACH,IAAI,GAAG,OAAO,WAAW,KAAK,EAAE,GAAG,WAAW,IAAI;GAClD,IAAI,KAAK;IAAE,MAAM;IAAS,cAAc;IAAgB,QAAQ,GAAG;IAAQ,UAAU,GAAG;GAAS,CAAC;GAClG;EAEF,KAAK;GACH,IAAI,GAAG,SAAS,IAAI;GACpB,IAAI,KAAK;IAAE,MAAM;IAAU,cAAc;IAAiB,IAAI,GAAG;IAAI,MAAM,GAAG;GAAK,CAAC;CAGxF;CAEF,OAAO;AACT"}