@weasel-js/core 1.10.0 → 1.10.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 (327) hide show
  1. package/CHANGELOG.md +168 -0
  2. package/README.md +33 -0
  3. package/dist/affordances/composeAffordanceLayer.js +21 -21
  4. package/dist/affordances/composeAffordanceLayer.js.map +1 -1
  5. package/dist/affordances/hitAffordanceRegions.js +48 -32
  6. package/dist/affordances/hitAffordanceRegions.js.map +1 -1
  7. package/dist/affordances/pathAnchors.js +50 -28
  8. package/dist/affordances/pathAnchors.js.map +1 -1
  9. package/dist/affordances/rotateCursor.js +12 -0
  10. package/dist/affordances/rotateCursor.js.map +1 -0
  11. package/dist/affordances/rotationHandle.js +40 -43
  12. package/dist/affordances/rotationHandle.js.map +1 -1
  13. package/dist/animation/rig/rigNode.js +9 -3
  14. package/dist/animation/rig/rigNode.js.map +1 -1
  15. package/dist/animation/rig/rigSeat.js +46 -13
  16. package/dist/animation/rig/rigSeat.js.map +1 -1
  17. package/dist/animation/rig/skinBinding.js +22 -14
  18. package/dist/animation/rig/skinBinding.js.map +1 -1
  19. package/dist/barrel/canvas.js +29 -28
  20. package/dist/barrel/interactions.js +33 -32
  21. package/dist/barrel/paths.js +11 -10
  22. package/dist/barrel/routing.js +49 -48
  23. package/dist/barrel/scene.js +10 -10
  24. package/dist/barrel/viewport.js +24 -21
  25. package/dist/canvas/Canvas.js +6 -17
  26. package/dist/canvas/Canvas.js.map +1 -1
  27. package/dist/canvas/CanvasView.js +34 -37
  28. package/dist/canvas/CanvasView.js.map +1 -1
  29. package/dist/canvas/CursorCoordsHud.js +3 -3
  30. package/dist/canvas/CursorCoordsHud.js.map +1 -1
  31. package/dist/canvas/DrawCanvas.js +3 -3
  32. package/dist/canvas/DrawCanvas.js.map +1 -1
  33. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +24 -23
  34. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js.map +1 -1
  35. package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js +40 -49
  36. package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js.map +1 -1
  37. package/dist/canvas/SceneCanvas/defaultNodeProperties.js +297 -259
  38. package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
  39. package/dist/canvas/SceneCanvas/features.js +3 -24
  40. package/dist/canvas/SceneCanvas/features.js.map +1 -1
  41. package/dist/canvas/SceneCanvas/insertPreviewCommands.js +97 -0
  42. package/dist/canvas/SceneCanvas/insertPreviewCommands.js.map +1 -0
  43. package/dist/canvas/SceneCanvas/poseGeometry.js.map +1 -1
  44. package/dist/canvas/SceneCanvas/props.js.map +1 -1
  45. package/dist/canvas/SceneCanvas/scenePointQuery.js +50 -0
  46. package/dist/canvas/SceneCanvas/scenePointQuery.js.map +1 -0
  47. package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js +52 -0
  48. package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js.map +1 -0
  49. package/dist/canvas/SceneCanvas/useActionTunings.js +17 -0
  50. package/dist/canvas/SceneCanvas/useActionTunings.js.map +1 -0
  51. package/dist/canvas/SceneCanvas/useCanvasCamera.js +37 -29
  52. package/dist/canvas/SceneCanvas/useCanvasCamera.js.map +1 -1
  53. package/dist/canvas/SceneCanvas/useCanvasDispatcher.js +11 -11
  54. package/dist/canvas/SceneCanvas/useCanvasDispatcher.js.map +1 -1
  55. package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js +45 -109
  56. package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js.map +1 -1
  57. package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js +49 -41
  58. package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js.map +1 -1
  59. package/dist/canvas/SceneCanvas/useSceneSelectTool.js +64 -96
  60. package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
  61. package/dist/canvas/SceneCanvas/worldPointAt.js +3 -4
  62. package/dist/canvas/SceneCanvas/worldPointAt.js.map +1 -1
  63. package/dist/canvas/SceneCanvas.js +77 -80
  64. package/dist/canvas/SceneCanvas.js.map +1 -1
  65. package/dist/canvas/SceneViewCanvas.js +3 -3
  66. package/dist/canvas/SceneViewCanvas.js.map +1 -1
  67. package/dist/canvas/SurfaceCanvas.js +40 -0
  68. package/dist/canvas/SurfaceCanvas.js.map +1 -0
  69. package/dist/canvas/adapterDerivedPath.js +13 -13
  70. package/dist/canvas/adapterDerivedPath.js.map +1 -1
  71. package/dist/canvas/adapterPickSource.js +34 -0
  72. package/dist/canvas/adapterPickSource.js.map +1 -0
  73. package/dist/canvas/affordanceAt.js +1 -1
  74. package/dist/canvas/affordanceAt.js.map +1 -1
  75. package/dist/canvas/buildSceneLayer.js.map +1 -1
  76. package/dist/canvas/buildSceneTree.js +56 -34
  77. package/dist/canvas/buildSceneTree.js.map +1 -1
  78. package/dist/canvas/copiesAbove.js +27 -0
  79. package/dist/canvas/copiesAbove.js.map +1 -0
  80. package/dist/canvas/defaultDrawOne.js +24 -23
  81. package/dist/canvas/defaultDrawOne.js.map +1 -1
  82. package/dist/canvas/deps/editAnchors.js +45 -50
  83. package/dist/canvas/deps/editAnchors.js.map +1 -1
  84. package/dist/canvas/deps/hitTestArea.js +30 -15
  85. package/dist/canvas/deps/hitTestArea.js.map +1 -1
  86. package/dist/canvas/deps/insert.js +134 -100
  87. package/dist/canvas/deps/insert.js.map +1 -1
  88. package/dist/canvas/deps/layout.js +9 -15
  89. package/dist/canvas/deps/layout.js.map +1 -1
  90. package/dist/canvas/derivedPath.js +53 -29
  91. package/dist/canvas/derivedPath.js.map +1 -1
  92. package/dist/canvas/insertPreviewExtent.js +33 -31
  93. package/dist/canvas/insertPreviewExtent.js.map +1 -1
  94. package/dist/canvas/overChildren.js +29 -0
  95. package/dist/canvas/overChildren.js.map +1 -0
  96. package/dist/canvas/paintedCursorLayer.js.map +1 -1
  97. package/dist/canvas/pickReach.js +23 -0
  98. package/dist/canvas/pickReach.js.map +1 -0
  99. package/dist/canvas/pickWalk.js +51 -80
  100. package/dist/canvas/pickWalk.js.map +1 -1
  101. package/dist/canvas/sceneAdapter.js +14 -35
  102. package/dist/canvas/sceneAdapter.js.map +1 -1
  103. package/dist/canvas/sceneSlotWiring.js +11 -10
  104. package/dist/canvas/sceneSlotWiring.js.map +1 -1
  105. package/dist/canvas/sceneViewRender.js +38 -44
  106. package/dist/canvas/sceneViewRender.js.map +1 -1
  107. package/dist/canvas/useCanvasView.js +42 -44
  108. package/dist/canvas/useCanvasView.js.map +1 -1
  109. package/dist/canvas/useSceneAdapter.js +22 -0
  110. package/dist/canvas/useSceneAdapter.js.map +1 -0
  111. package/dist/canvas/useSurfaceInput.js +13 -16
  112. package/dist/canvas/useSurfaceInput.js.map +1 -1
  113. package/dist/canvas/viewRegistry.js +31 -23
  114. package/dist/canvas/viewRegistry.js.map +1 -1
  115. package/dist/canvas/wrapNodeOutput.js +7 -2
  116. package/dist/canvas/wrapNodeOutput.js.map +1 -1
  117. package/dist/clipboard.d.ts +1 -1
  118. package/dist/{clone-2a5hVbBd.d.ts → clone-C0eADtS0.d.ts} +13 -13
  119. package/dist/clone.d.ts +2 -2
  120. package/dist/core/geometry/poseDescriptor.js +49 -23
  121. package/dist/core/geometry/poseDescriptor.js.map +1 -1
  122. package/dist/core/geometry/regionHit.js +2 -2
  123. package/dist/core/geometry/regionHit.js.map +1 -1
  124. package/dist/core/geometry/targetFrame.js.map +1 -1
  125. package/dist/core/layers/children.js +1 -3
  126. package/dist/core/layers/children.js.map +1 -1
  127. package/dist/core/ops/create.js +2 -2
  128. package/dist/core/ops/create.js.map +1 -1
  129. package/dist/core/ops/delete.js +19 -23
  130. package/dist/core/ops/delete.js.map +1 -1
  131. package/dist/core/ops/reorder/index.js +3 -7
  132. package/dist/core/ops/reorder/index.js.map +1 -1
  133. package/dist/core/ops/reorder/setChildOrder.js +2 -4
  134. package/dist/core/ops/reorder/setChildOrder.js.map +1 -1
  135. package/dist/core/ops/reparent.js +0 -1
  136. package/dist/core/ops/reparent.js.map +1 -1
  137. package/dist/core/ops/slot.js +3 -6
  138. package/dist/core/ops/slot.js.map +1 -1
  139. package/dist/core/pages/fitViewToPage.js +15 -0
  140. package/dist/core/pages/fitViewToPage.js.map +1 -0
  141. package/dist/core/pages/pages.js +65 -0
  142. package/dist/core/pages/pages.js.map +1 -0
  143. package/dist/core/pages/pagesLayer.js +27 -0
  144. package/dist/core/pages/pagesLayer.js.map +1 -0
  145. package/dist/core/paint/meshKindLazy.js +2 -2
  146. package/dist/core/paint/meshKindLazy.js.map +1 -1
  147. package/dist/core/scene/NodeProperties.js.map +1 -1
  148. package/dist/core/scene/composeFrame.js.map +1 -1
  149. package/dist/core/scene/composePose.js +58 -20
  150. package/dist/core/scene/composePose.js.map +1 -1
  151. package/dist/core/scene/effectivePose.js +5 -1
  152. package/dist/core/scene/effectivePose.js.map +1 -1
  153. package/dist/core/scene/historyFacade.js +19 -13
  154. package/dist/core/scene/historyFacade.js.map +1 -1
  155. package/dist/core/scene/nodeFnFields.js +7 -0
  156. package/dist/core/scene/nodeFnFields.js.map +1 -1
  157. package/dist/core/scene/outerOps.js +2 -1
  158. package/dist/core/scene/outerOps.js.map +1 -1
  159. package/dist/core/scene/reconcileSpecs.js +1 -1
  160. package/dist/core/scene/reconcileSpecs.js.map +1 -1
  161. package/dist/core/scene/sceneRecording.js +2 -1
  162. package/dist/core/scene/sceneRecording.js.map +1 -1
  163. package/dist/core/scene/types.js.map +1 -1
  164. package/dist/core/viewport/screenSlop.js.map +1 -1
  165. package/dist/core/viewport/useDecayLoop.js +28 -30
  166. package/dist/core/viewport/useDecayLoop.js.map +1 -1
  167. package/dist/core/viewport/useNodeOverlayFrame.js.map +1 -1
  168. package/dist/core/viewport/useViewAnimation.js +70 -69
  169. package/dist/core/viewport/useViewAnimation.js.map +1 -1
  170. package/dist/core/viewport/view.js +8 -5
  171. package/dist/core/viewport/view.js.map +1 -1
  172. package/dist/core/viewport/zoomAt.js +11 -2
  173. package/dist/core/viewport/zoomAt.js.map +1 -1
  174. package/dist/{cornerHandles-BEshc4z3.d.ts → cornerHandles-BSKbyuvQ.d.ts} +1 -1
  175. package/dist/features/paths/editablePath.js +24 -8
  176. package/dist/features/paths/editablePath.js.map +1 -1
  177. package/dist/features/paths/index.js +4 -4
  178. package/dist/features/paths/shapeGenerator.js +89 -0
  179. package/dist/features/paths/shapeGenerator.js.map +1 -0
  180. package/dist/features/paths/usePathEdit.js +13 -13
  181. package/dist/features/poseRun/usePoseRun.js +25 -25
  182. package/dist/features/poseRun/usePoseRun.js.map +1 -1
  183. package/dist/features/text/useSceneTextEdit.js +82 -64
  184. package/dist/features/text/useSceneTextEdit.js.map +1 -1
  185. package/dist/features/viewports/viewResolver.js +28 -24
  186. package/dist/features/viewports/viewResolver.js.map +1 -1
  187. package/dist/icons/SliceIcon.js +24 -0
  188. package/dist/icons/SliceIcon.js.map +1 -0
  189. package/dist/index.d.ts +956 -581
  190. package/dist/index.js +260 -251
  191. package/dist/interactions/actions/align/align.js +9 -9
  192. package/dist/interactions/actions/align/align.js.map +1 -1
  193. package/dist/interactions/actions/booleans/booleans.js +18 -18
  194. package/dist/interactions/actions/booleans/booleans.js.map +1 -1
  195. package/dist/interactions/actions/booleans/operands.js.map +1 -1
  196. package/dist/interactions/actions/clone/action.js +35 -30
  197. package/dist/interactions/actions/clone/action.js.map +1 -1
  198. package/dist/interactions/actions/defaults/anchorEditing.js +56 -59
  199. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  200. package/dist/interactions/actions/defaults/anchorHandles.js +42 -0
  201. package/dist/interactions/actions/defaults/anchorHandles.js.map +1 -0
  202. package/dist/interactions/actions/defaults/anchorJoin.js +92 -0
  203. package/dist/interactions/actions/defaults/anchorJoin.js.map +1 -0
  204. package/dist/interactions/actions/defaults/bendSegment.js +46 -0
  205. package/dist/interactions/actions/defaults/bendSegment.js.map +1 -0
  206. package/dist/interactions/actions/defaults/copySubtree.js +1 -1
  207. package/dist/interactions/actions/defaults/copySubtree.js.map +1 -1
  208. package/dist/interactions/actions/defaults/duplicate.js +32 -17
  209. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  210. package/dist/interactions/actions/defaults/enterPathEdit.js +19 -7
  211. package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
  212. package/dist/interactions/actions/defaults/icons/anchorIcons.js +75 -0
  213. package/dist/interactions/actions/defaults/icons/anchorIcons.js.map +1 -0
  214. package/dist/interactions/actions/defaults/icons/editIcons.js +35 -8
  215. package/dist/interactions/actions/defaults/icons/editIcons.js.map +1 -1
  216. package/dist/interactions/actions/defaults/insertPathAnchor.js +16 -31
  217. package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
  218. package/dist/interactions/actions/defaults/nudge.js +28 -23
  219. package/dist/interactions/actions/defaults/nudge.js.map +1 -1
  220. package/dist/interactions/actions/defaults/pinchZoom.js +29 -29
  221. package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
  222. package/dist/interactions/actions/defaults/segmentUnder.js +22 -0
  223. package/dist/interactions/actions/defaults/segmentUnder.js.map +1 -0
  224. package/dist/interactions/actions/defaults/viewportZoom.js +82 -79
  225. package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
  226. package/dist/interactions/actions/distribute/distribute.js +8 -8
  227. package/dist/interactions/actions/distribute/distribute.js.map +1 -1
  228. package/dist/interactions/actions/edit-anchors/action.js +58 -55
  229. package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
  230. package/dist/interactions/actions/edit-anchors/preview.js +26 -0
  231. package/dist/interactions/actions/edit-anchors/preview.js.map +1 -0
  232. package/dist/interactions/actions/edit-anchors/symmetry.js +11 -0
  233. package/dist/interactions/actions/edit-anchors/symmetry.js.map +1 -0
  234. package/dist/interactions/actions/flip/action.js.map +1 -1
  235. package/dist/interactions/actions/geometryProjection.js.map +1 -1
  236. package/dist/interactions/actions/insert/action.js +37 -30
  237. package/dist/interactions/actions/insert/action.js.map +1 -1
  238. package/dist/interactions/actions/insert/frame.js +9 -2
  239. package/dist/interactions/actions/insert/frame.js.map +1 -1
  240. package/dist/interactions/actions/insert/repositionAction.js +31 -0
  241. package/dist/interactions/actions/insert/repositionAction.js.map +1 -0
  242. package/dist/interactions/actions/lasso-select/action.js +32 -32
  243. package/dist/interactions/actions/move/action.js +29 -25
  244. package/dist/interactions/actions/move/action.js.map +1 -1
  245. package/dist/interactions/actions/move/behaviors/snapToContainer.js +12 -6
  246. package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
  247. package/dist/interactions/actions/move/capture.js +32 -23
  248. package/dist/interactions/actions/move/capture.js.map +1 -1
  249. package/dist/interactions/actions/move/frame.js +2 -14
  250. package/dist/interactions/actions/move/frame.js.map +1 -1
  251. package/dist/interactions/actions/move/session.js +1 -1
  252. package/dist/interactions/actions/move/session.js.map +1 -1
  253. package/dist/interactions/actions/move/translate.js.map +1 -1
  254. package/dist/interactions/actions/outlines/createOutlines.js.map +1 -1
  255. package/dist/interactions/actions/outlines/replaceWithPaths.js +13 -13
  256. package/dist/interactions/actions/outlines/replaceWithPaths.js.map +1 -1
  257. package/dist/interactions/actions/outlines/strokeRegion.js.map +1 -1
  258. package/dist/interactions/actions/pathCommands/cutJoin.js +102 -0
  259. package/dist/interactions/actions/pathCommands/cutJoin.js.map +1 -0
  260. package/dist/interactions/actions/pathCommands/livePathEdit.js +64 -0
  261. package/dist/interactions/actions/pathCommands/livePathEdit.js.map +1 -0
  262. package/dist/interactions/actions/pathCommands/pathNodes.js +99 -0
  263. package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -0
  264. package/dist/interactions/actions/pathCommands/simplifyOffset.js +42 -0
  265. package/dist/interactions/actions/pathCommands/simplifyOffset.js.map +1 -0
  266. package/dist/interactions/actions/resize/action.js +31 -20
  267. package/dist/interactions/actions/resize/action.js.map +1 -1
  268. package/dist/interactions/actions/resize/commit.js.map +1 -1
  269. package/dist/interactions/actions/resize/frame.js +29 -15
  270. package/dist/interactions/actions/resize/frame.js.map +1 -1
  271. package/dist/interactions/actions/resize/replay.js +47 -0
  272. package/dist/interactions/actions/resize/replay.js.map +1 -0
  273. package/dist/interactions/actions/resize/session.js +49 -35
  274. package/dist/interactions/actions/resize/session.js.map +1 -1
  275. package/dist/interactions/actions/resolveOverlays.js +2 -1
  276. package/dist/interactions/actions/resolveOverlays.js.map +1 -1
  277. package/dist/interactions/actions/rotate/action.js +40 -25
  278. package/dist/interactions/actions/rotate/action.js.map +1 -1
  279. package/dist/interactions/actions/rotate/frame.js +1 -1
  280. package/dist/interactions/actions/rotate/frame.js.map +1 -1
  281. package/dist/interactions/actions/rotate/replay.js +22 -0
  282. package/dist/interactions/actions/rotate/replay.js.map +1 -0
  283. package/dist/interactions/actions/rotate/session.js +42 -32
  284. package/dist/interactions/actions/rotate/session.js.map +1 -1
  285. package/dist/interactions/actions/transform-again/action.js +63 -0
  286. package/dist/interactions/actions/transform-again/action.js.map +1 -0
  287. package/dist/interactions/actions/transform-again/memory.js +35 -0
  288. package/dist/interactions/actions/transform-again/memory.js.map +1 -0
  289. package/dist/interactions/actions/useStandardActions.js +101 -83
  290. package/dist/interactions/actions/useStandardActions.js.map +1 -1
  291. package/dist/move.d.ts +4 -4
  292. package/dist/{originProjection-PPT88jZv.d.ts → originProjection-CoNVpITV.d.ts} +1 -1
  293. package/dist/resize.d.ts +3 -3
  294. package/dist/style.css +1 -1
  295. package/dist/tools/builtin/ellipse/useEllipseTool.js +16 -15
  296. package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
  297. package/dist/tools/builtin/line/useLineTool.js +16 -15
  298. package/dist/tools/builtin/line/useLineTool.js.map +1 -1
  299. package/dist/tools/builtin/pen/usePenTool.js +111 -111
  300. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  301. package/dist/tools/builtin/pickTopMostHit.js +11 -14
  302. package/dist/tools/builtin/pickTopMostHit.js.map +1 -1
  303. package/dist/tools/builtin/polygon/usePolygonTool.js +17 -15
  304. package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
  305. package/dist/tools/builtin/rect/useRectTool.js +15 -14
  306. package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
  307. package/dist/tools/builtin/select/adapterPointQuery.js +22 -18
  308. package/dist/tools/builtin/select/adapterPointQuery.js.map +1 -1
  309. package/dist/tools/builtin/select/selectionContributions.js +1 -1
  310. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  311. package/dist/tools/builtin/select/useSelectTool.js +2 -1
  312. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  313. package/dist/tools/builtin/slice/useSliceTool.js +42 -40
  314. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  315. package/dist/tools/builtin/star/useStarTool.js +18 -16
  316. package/dist/tools/builtin/star/useStarTool.js.map +1 -1
  317. package/dist/tools/builtin/text/useTextTool.js +2 -2
  318. package/dist/tools/builtin/text/useTextTool.js.map +1 -1
  319. package/dist/{types-CIKDwlsP.d.ts → types-DBbbCy0i.d.ts} +22 -15
  320. package/dist/version.js +1 -1
  321. package/package.json +22 -22
  322. package/dist/canvas/surface.module.js +0 -6
  323. package/dist/canvas/surface.module.js.map +0 -1
  324. package/dist/canvas/surfaceBox.js +0 -16
  325. package/dist/canvas/surfaceBox.js.map +0 -1
  326. package/dist/layout/arrivals.js +0 -33
  327. package/dist/layout/arrivals.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"action.js","names":["resizeAction","inPlane","begun","beginResize","ctx","hold","session","frame","moveCtx","nextFrame","readers","committed","reason","commitResize","runBehaviorCancel","id","selectionLayer"],"sources":["../../../../src/interactions/actions/resize/action.ts"],"sourcesContent":["import type { Action } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport type { NodeId } from 'core/scene/types';\nimport { closeGesture, runBehaviorCancel } from '../gestureLifecycle';\nimport { inPlane, selectionLayer } from '../planeInput';\nimport { commitResize } from './commit';\nimport { nextFrame } from './frame';\nimport { beginResize, type ResizeFrame } from './session';\n\n/**\n * @experimental\n * Anchor-relative drag resize, committed as one batch on release. It needs\n * `InvocationCtx.drag.affordance` with a `handle:*` kind.\n *\n * The optional `resizePolicy` dep carries the constraints, point snaps, and\n * `expandIds`; absent, the invoker falls back to the kit's default\n * constraints, no snap, and `ids => ids` expansion.\n */\nexport const resizeAction: Action & { requires: string[] } = 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 requires: ['selection', 'scene', 'resizePolicy', 'poseDescriptor', 'applyOps', 'geometryProjection', 'view'],\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 hold = session.scene.overrides.hold();\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(frame.previews);\n },\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n if (reason === 'commit') committed = commitResize(session, frame);\n else runBehaviorCancel(session.constraints, session.gestureCtx);\n } finally {\n closeGesture({ hold, previews: frame.previews, behaviors: session.constraints, ctx: session.gestureCtx, lifecycle: session.lifecycle }, committed);\n }\n },\n previewIds: () => frame.previews.keys(),\n previewPose: (id: string) => frame.previews.get(id as NodeId) ?? null,\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"],"mappings":";;;;;;AAkBA,IAAaA,IAAgDC,EAAQ;CACnE,IAAI;CACJ,OAAO;CAGP,UAAU,EAAE,YAAY,uBAAuB;CAC/C,UAAU;EAAC;EAAa;EAAS;EAAgB;EAAkB;EAAY;EAAsB;CAAM;CAC3G,SAAS;EACP,QAAQ;EACR,MAAM,GAAoB,GAAsB;GAC9C,IAAMC,IAAQC,EAAYC,CAAG;GAC7B,IAAI,CAACF,GAAO,OAAO,CAAC;GACpB,IAAM,EAAE,YAAS,eAAYA,GACvBG,IAAOC,EAAQ,MAAM,UAAU,KAAK,GACtCC,IAAqB,EAAE,0BAAU,IAAI,IAAI,EAAE;GAE/C,OADAD,EAAQ,UAAU,MAAMA,EAAQ,QAA6B,GACtD;IACL,MAAM;IACN,OAAO,GAA8B;KACnC,AAAKE,EAAQ,SACb,IAAQC,EAAUH,GAASI,GAASF,CAAO,GAC3CH,EAAK,IAAIE,EAAM,QAAQ;IACzB;IACA,MAAM,GAAwB,GAAmC;KAC/D,IAAII,IAAY;KAChB,IAAI;MACF,AAAIC,MAAW,WAAU,IAAYC,EAAaP,GAASC,CAAK,IAC3DO,EAAkBR,EAAQ,aAAaA,EAAQ,UAAU;KAChE,UAAU;MACR,EAAa;OAAE;OAAM,UAAUC,EAAM;OAAU,WAAWD,EAAQ;OAAa,KAAKA,EAAQ;OAAY,WAAWA,EAAQ;MAAU,GAAGK,CAAS;KACnJ;IACF;IACA,kBAAkBJ,EAAM,SAAS,KAAK;IACtC,cAAc,MAAeA,EAAM,SAAS,IAAIQ,CAAY,KAAK;GACnE;EACF;CACF;CAMA,eAAe;AACjB,GAAGC,CAAc"}
1
+ {"version":3,"file":"action.js","names":["resizeAction","inPlane","begun","beginResize","ctx","subject","hold","session","frame","moveCtx","nextFrame","readers","committed","reason","commitResize","to","unitsOfBox","id","selectionLayer"],"sources":["../../../../src/interactions/actions/resize/action.ts"],"sourcesContent":["import type { Action } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport type { NodeId } from 'core/scene/types';\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';\n\n/**\n * @experimental\n * Anchor-relative drag resize, committed as one batch on release. It needs\n * `InvocationCtx.drag.affordance` with a `handle:*` kind.\n *\n * The optional `resizePolicy` dep carries the constraints, point snaps, and\n * `expandIds`; absent, the invoker falls back to the kit's default\n * constraints, no snap, and `ids => ids` expansion.\n */\nexport const resizeAction: Action & { requires: string[] } = 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 requires: ['selection', 'scene', 'resizePolicy', 'poseDescriptor', 'applyOps', 'geometryProjection', 'view'],\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 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(frame.previews);\n },\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n 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 closeGesture({ hold, previews: frame.previews, behaviors: session.constraints, ctx: session.gestureCtx, lifecycle: session.lifecycle }, committed);\n }\n },\n previewIds: () => frame.previews.keys(),\n previewPose: (id: string) => frame.previews.get(id as NodeId) ?? null,\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"],"mappings":";;;;;;;;AAoBA,IAAaA,IAAgDC,EAAQ;CACnE,IAAI;CACJ,OAAO;CAGP,UAAU,EAAE,YAAY,uBAAuB;CAC/C,UAAU;EAAC;EAAa;EAAS;EAAgB;EAAkB;EAAY;EAAsB;CAAM;CAC3G,SAAS;EACP,QAAQ;EACR,MAAM,GAAoB,GAAsB;GAC9C,IAAMC,IAAQC,EAAYC,CAAG;GAC7B,IAAI,CAACF,GAAO,OAAO,CAAC;GACpB,IAAM,EAAE,YAAS,eAAYA,GACvBG,IAAU,CAAC,GAAID,EAAI,KAAK,WAAW,IAAI,KAAK,CAAC,CAAE,GAC/CE,IAAOC,EAAQ,MAAM,UAAU,KAAK,GACtCC,IAAqB,EAAE,0BAAU,IAAI,IAAI,EAAE;GAE/C,OADAD,EAAQ,UAAU,MAAMA,EAAQ,QAA6B,GACtD;IACL,MAAM;IACN,OAAO,GAA8B;KACnC,AAAKE,EAAQ,SACb,IAAQC,EAAUH,GAASI,GAASF,CAAO,GAC3CH,EAAK,IAAIE,EAAM,QAAQ;IACzB;IACA,MAAM,GAAwB,GAAmC;KAC/D,IAAII,IAAY;KAChB,IAAI;MACF,IAAIC,MAAW,UAEb;WADA,IAAYC,EAAaP,GAASC,CAAK,GACnCI,KAAaJ,EAAM,UAAU;QAC/B,IAAMO,IAAKC,EAAWT,EAAQ,IAAI,QAAQC,EAAM,QAAQ;QACxD,EAAgBD,EAAQ,OAAO;SAAE,MAAM;SAAS;SAAI,QAAQA,EAAQ,IAAI;QAAO,GAAGF,CAAO;OAC3F;aACK,EAAkBE,EAAQ,aAAaA,EAAQ,UAAU;KAClE,UAAU;MACR,EAAa;OAAE;OAAM,UAAUC,EAAM;OAAU,WAAWD,EAAQ;OAAa,KAAKA,EAAQ;OAAY,WAAWA,EAAQ;MAAU,GAAGK,CAAS;KACnJ;IACF;IACA,kBAAkBJ,EAAM,SAAS,KAAK;IACtC,cAAc,MAAeA,EAAM,SAAS,IAAIS,CAAY,KAAK;GACnE;EACF;CACF;CAMA,eAAe;AACjB,GAAGC,CAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"commit.js","names":["projectedGeometry","sb","g","from","db","next","m","boxToBox","dataOp","geometryDataOp","projection","node","label","nb","resizeOps","ops","id","leaves","previews","to","projected","createTransformOp","commitResize","session","target","defaultCommitAdapter","r","reduceBehaviorEnd","commitGestureOps","lifecycle","frame"],"sources":["../../../../src/interactions/actions/resize/commit.ts"],"sourcesContent":["import { boxToBox, type Mat3 } 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: Mat3 = 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 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,SAASA,EACP,GACA,GACA,GACA,GACA,GACA,GACsC;CACtC,IAAMC,IAAKC,EAAE,UAAUC,CAAI,GACrBC,IAAKF,EAAE,UAAUG,CAAI,GACrBC,IAAUC,EACdN,EAAG,GAAGA,EAAG,GAAGA,EAAG,OAAOA,EAAG,QACzBG,EAAG,GAAGA,EAAG,GAAGA,EAAG,OAAOA,EAAG,MAC3B,GACMI,IAASC,EAAeC,GAAY;EAAE,IAAIC,EAAK;EAAI,MAAMA,EAAK;EAAM,MAAMR;CAAK,GAAGG,GAAGM,CAAK;CAChG,IAAI,CAACJ,GAAQ,OAAO;CAOpB,IAAI,EAAEJ,EAAG,QAAQ,KAAKA,EAAG,SAAS,IAAI,OAAO;EAAE;EAAQ,MAAMC;CAAK;CAClE,IAAMQ,IAAK;EACT,GAAGT;EACH,GAAGA,EAAG,QAAQ,IAAIA,EAAG,IAAIA,EAAG,QAAQA,EAAG;EACvC,GAAGA,EAAG,SAAS,IAAIA,EAAG,IAAIA,EAAG,SAASA,EAAG;EACzC,OAAO,KAAK,IAAIA,EAAG,KAAK;EACxB,QAAQ,KAAK,IAAIA,EAAG,MAAM;CAC5B;CACA,OAAO;EAAE;EAAQ,MAAMF,EAAE,YAAYG,GAAMD,GAAIS,CAAE;CAAE;AACrD;AAKA,SAAgBC,EACd,GACA,GACA,GACM;CACN,IAAMC,IAAY,CAAC;CACnB,KAAK,IAAMC,KAAMC,EAAO,UAAU;EAChC,IAAMZ,IAAOa,EAAS,IAAIF,CAAE;EAC5B,IAAIX,MAAS,KAAA,GAAW;EACxB,IAAMF,IAAOc,EAAO,WAAW,IAAID,CAAE;EACrC,IAAIb,MAAS,KAAA,GAAW;EACxB,IAAIgB,IAAcd,GACZM,IAAOM,EAAO,qBAAqBA,EAAO,MAAM,IAAID,CAAE,IAAI,KAAA;EAChE,IAAIC,EAAO,sBAAsBN,GAAM;GACrC,IAAMS,IAAYpB,EAChBiB,EAAO,oBAAoBA,EAAO,WAAWD,CAAE,GAAG;IAAM;IAAc,MAAML,EAAK;GAAK,GAAGR,GAAME,GAAMO,CACvG;GACA,AAAIQ,MACFL,EAAI,KAAKK,EAAU,MAAM,GACzB,IAAKA,EAAU;EAEnB;EACA,EAAI,KAAKC,EAA2B;GAAM;GAAc;GAAM;GAAI;EAAM,CAAC,CAAC;CAC5E;CACA,OAAON;AACT;AAIA,SAAgBO,EAAa,GAAwB,GAA6B;CAChF,IAAM,EAAE,iBAAcC,GAChBC,IAAS;EACb,OAAOD,EAAQ;EACf,UAAUA,EAAQ;EAClB,SAASE,EAAqBF,EAAQ,OAAOA,EAAQ,gBAAgB;CACvE,GACMG,IAAIC,EAAkBJ,EAAQ,aAAaA,EAAQ,UAAU;CACnE,IAAIG,MAAM,MAAM,OAAO;CACvB,IAAIA,MAAM,KAAA,GAAW,OAAOE,EAAiBJ,GAAQK,GAAWH,CAAC;CAEjE,IAAII,EAAM,SAAS,SAAS,GAAG,OAAO;CACtC,IAAMf,IAAMD,EAAUS,GAASO,EAAM,UAAUD,EAAU,KAAK;CAE9D,OADId,EAAI,WAAW,KACZa,EAAiBJ,GAAQK,GAAWd,CAAG;AAChD"}
1
+ {"version":3,"file":"commit.js","names":["projectedGeometry","sb","g","from","db","next","m","boxToBox","dataOp","geometryDataOp","projection","node","label","nb","resizeOps","ops","id","leaves","previews","to","projected","createTransformOp","commitResize","session","target","defaultCommitAdapter","r","reduceBehaviorEnd","commitGestureOps","lifecycle","frame"],"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 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,SAASA,EACP,GACA,GACA,GACA,GACA,GACA,GACsC;CACtC,IAAMC,IAAKC,EAAE,UAAUC,CAAI,GACrBC,IAAKF,EAAE,UAAUG,CAAI,GACrBC,IAAYC,EAChBN,EAAG,GAAGA,EAAG,GAAGA,EAAG,OAAOA,EAAG,QACzBG,EAAG,GAAGA,EAAG,GAAGA,EAAG,OAAOA,EAAG,MAC3B,GACMI,IAASC,EAAeC,GAAY;EAAE,IAAIC,EAAK;EAAI,MAAMA,EAAK;EAAM,MAAMR;CAAK,GAAGG,GAAGM,CAAK;CAChG,IAAI,CAACJ,GAAQ,OAAO;CAOpB,IAAI,EAAEJ,EAAG,QAAQ,KAAKA,EAAG,SAAS,IAAI,OAAO;EAAE;EAAQ,MAAMC;CAAK;CAClE,IAAMQ,IAAK;EACT,GAAGT;EACH,GAAGA,EAAG,QAAQ,IAAIA,EAAG,IAAIA,EAAG,QAAQA,EAAG;EACvC,GAAGA,EAAG,SAAS,IAAIA,EAAG,IAAIA,EAAG,SAASA,EAAG;EACzC,OAAO,KAAK,IAAIA,EAAG,KAAK;EACxB,QAAQ,KAAK,IAAIA,EAAG,MAAM;CAC5B;CACA,OAAO;EAAE;EAAQ,MAAMF,EAAE,YAAYG,GAAMD,GAAIS,CAAE;CAAE;AACrD;AAKA,SAAgBC,EACd,GACA,GACA,GACM;CACN,IAAMC,IAAY,CAAC;CACnB,KAAK,IAAMC,KAAMC,EAAO,UAAU;EAChC,IAAMZ,IAAOa,EAAS,IAAIF,CAAE;EAC5B,IAAIX,MAAS,KAAA,GAAW;EACxB,IAAMF,IAAOc,EAAO,WAAW,IAAID,CAAE;EACrC,IAAIb,MAAS,KAAA,GAAW;EACxB,IAAIgB,IAAcd,GACZM,IAAOM,EAAO,qBAAqBA,EAAO,MAAM,IAAID,CAAE,IAAI,KAAA;EAChE,IAAIC,EAAO,sBAAsBN,GAAM;GACrC,IAAMS,IAAYpB,EAChBiB,EAAO,oBAAoBA,EAAO,WAAWD,CAAE,GAAG;IAAM;IAAc,MAAML,EAAK;GAAK,GAAGR,GAAME,GAAMO,CACvG;GACA,AAAIQ,MACFL,EAAI,KAAKK,EAAU,MAAM,GACzB,IAAKA,EAAU;EAEnB;EACA,EAAI,KAAKC,EAA2B;GAAM;GAAc;GAAM;GAAI;EAAM,CAAC,CAAC;CAC5E;CACA,OAAON;AACT;AAIA,SAAgBO,EAAa,GAAwB,GAA6B;CAChF,IAAM,EAAE,iBAAcC,GAChBC,IAAS;EACb,OAAOD,EAAQ;EACf,UAAUA,EAAQ;EAClB,SAASE,EAAqBF,EAAQ,OAAOA,EAAQ,gBAAgB;CACvE,GACMG,IAAIC,EAAkBJ,EAAQ,aAAaA,EAAQ,UAAU;CACnE,IAAIG,MAAM,MAAM,OAAO;CACvB,IAAIA,MAAM,KAAA,GAAW,OAAOE,EAAiBJ,GAAQK,GAAWH,CAAC;CAEjE,IAAII,EAAM,SAAS,SAAS,GAAG,OAAO;CACtC,IAAMf,IAAMD,EAAUS,GAASO,EAAM,UAAUD,EAAU,KAAK;CAE9D,OADId,EAAI,WAAW,KACZa,EAAiBJ,GAAQK,GAAWd,CAAG;AAChD"}
@@ -6,7 +6,7 @@ import { pointerStateOf as s } from "../pointerState.js";
6
6
  import { boxFrame as c } from "./boxFrame.js";
7
7
  import { boundsForRules as l } from "./ruleBounds.js";
8
8
  import { snapPose as u } from "./pointSnap.js";
9
- import { poseRotationOf as d } from "@weasel-js/geom";
9
+ import { poseFrameOf as d } from "@weasel-js/geom";
10
10
  //#region src/interactions/actions/resize/frame.ts
11
11
  function f(e, t, n, i, a) {
12
12
  let { x: o, y: s } = r(a, n, i) ?? {
@@ -49,26 +49,40 @@ function g(e, t, n) {
49
49
  let r = e.scene.get(t)?.layer;
50
50
  return e.poseFrame.local(t, a(e.geometryOf(t), n, r === void 0 ? null : o(e.view, r)));
51
51
  }
52
- function _(e, t, n) {
53
- let r = n.drag.current, { box: i, gestureCtx: a } = e;
54
- a.modifiers = { ...n.modifiers }, a.pointer = s(r, n), a.view = t.view(), a.plane = t.plane();
55
- let o = p(e.constraints, a, i.anchor, f(i.bounds, i.anchor, r.x - e.startWorld.x, r.y - e.startWorld.y, c(i, i.bounds))), d = /* @__PURE__ */ new Map(), _ = (t) => {
56
- let n = e.startWorlds.get(t);
57
- if (n !== void 0) return m(e.geometryOf(t), n, i.bounds, o, e.sharedBox);
52
+ function _(e, t, n = (e, t) => t) {
53
+ let { box: r } = e, i = /* @__PURE__ */ new Map(), a = (n) => {
54
+ let i = e.startWorlds.get(n);
55
+ if (i !== void 0) return m(e.geometryOf(n), i, r.bounds, t, e.sharedBox);
58
56
  };
59
57
  if (e.sharedBox) {
60
58
  for (let t of e.writeIds) {
61
- let n = _(t);
62
- n !== void 0 && d.set(t, g(e, t, n));
59
+ let n = a(t);
60
+ n !== void 0 && i.set(t, g(e, t, n));
63
61
  }
64
- return { previews: d };
62
+ return { previews: i };
65
63
  }
66
- let v = e.writeIds[0], y = e.geometryOf(v), b = _(v);
67
- if (b === void 0) return { previews: d };
68
- let x = u(e.pointSnap, y, h(y, b, i, o), i, i.anchor, a.modifiers, a.plane ?? null);
69
- return d.set(v, g(e, v, x)), a.current = /* @__PURE__ */ new Map([[v, l(y, x)]]), { previews: d };
64
+ let o = e.writeIds[0], s = e.geometryOf(o), c = a(o);
65
+ if (c === void 0) return { previews: i };
66
+ let l = n(s, h(s, c, r, t));
67
+ return i.set(o, g(e, o, l)), {
68
+ previews: i,
69
+ lone: {
70
+ id: o,
71
+ g: s,
72
+ world: l
73
+ }
74
+ };
75
+ }
76
+ function v(e, t, n) {
77
+ let r = n.drag.current, { box: i, gestureCtx: a } = e;
78
+ a.modifiers = { ...n.modifiers }, a.pointer = s(r, n), a.view = t.view(), a.plane = t.plane();
79
+ let o = p(e.constraints, a, i.anchor, f(i.bounds, i.anchor, r.x - e.startWorld.x, r.y - e.startWorld.y, c(i, i.bounds))), { previews: d, lone: m } = _(e, o, (t, n) => u(e.pointSnap, t, n, i, i.anchor, a.modifiers, a.plane ?? null));
80
+ return m && (a.current = /* @__PURE__ */ new Map([[m.id, l(m.g, m.world)]])), {
81
+ previews: d,
82
+ proposed: o
83
+ };
70
84
  }
71
85
  //#endregion
72
- export { _ as nextFrame };
86
+ export { v as nextFrame, _ as posesInBox };
73
87
 
74
88
  //# sourceMappingURL=frame.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"frame.js","names":["computeProposedBounds","dx","dy","worldDeltaToLocal","frame","worldDx","worldDy","nx","ob","ny","nw","nh","anchor","constrain","bounds","proposed","b","constraints","r","gctx","leafPose","sharedBox","poseRotationOf","start","remapRotatedLeaf","src","dst","g","pinFixedCorner","boxFrame","box","pose","newFixedLocal","fixedCornerOf","newFixedWorld","localToWorld","translatePoseViaDescriptor","storedPose","layer","place","id","carryPose","world","planeOf","nextFrame","at","moveCtx","session","pointerStateOf","readers","previews","worldOf","next","remapped","snapPose","boundsForRules"],"sources":["../../../../src/interactions/actions/resize/frame.ts"],"sourcesContent":["import { poseRotationOf } 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 } from './cornerHandles';\nimport { remapRotatedLeaf, translatePoseViaDescriptor, type PoseDescriptor } from './geometry';\nimport { snapPose } from './pointSnap';\nimport { boundsForRules } from './ruleBounds';\nimport { boxFrame } from './boxFrame';\nimport type { ResizeBox, ResizeFrame, ResizeSession } from './session';\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 let nx = ob.x;\n let ny = ob.y;\n let nw = ob.width;\n let nh = ob.height;\n if (anchor.x === 'min') {\n nw = ob.width + dx;\n } else if (anchor.x === 'max') {\n nx = ob.x + dx;\n nw = ob.width - dx;\n }\n if (anchor.y === 'min') {\n nh = ob.height + dy;\n } else if (anchor.y === 'max') {\n ny = ob.y + dy;\n nh = ob.height - dy;\n }\n return { x: nx, y: ny, width: nw, height: nh };\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 rotated 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 && poseRotationOf(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/** One move's previews: the box as the drag and the constraints leave it,\n * and every write id's stored pose inside it. A lone target also gets the\n * rotated-resize pin and the point snaps, which a shared box, resized in the\n * AABB frame, does not. `moveCtx` must carry a drag. */\nexport function nextFrame(session: ResizeSession, readers: GestureReaders, moveCtx: InvocationCtx): ResizeFrame {\n const at = moveCtx.drag!.current;\n const { box, gestureCtx: gctx } = session;\n gctx.modifiers = { ...moveCtx.modifiers };\n gctx.pointer = pointerStateOf(at, moveCtx);\n gctx.view = readers.view();\n gctx.plane = readers.plane();\n\n const proposed = constrain(\n session.constraints,\n gctx,\n box.anchor,\n computeProposedBounds(box.bounds, box.anchor, at.x - session.startWorld.x, at.y - session.startWorld.y, boxFrame(box, box.bounds)),\n );\n\n const previews = new Map<NodeId, unknown>();\n const worldOf = (id: NodeId): unknown => {\n const start = session.startWorlds.get(id);\n if (start === undefined) return undefined;\n return leafPose(session.geometryOf(id), start, box.bounds, proposed, session.sharedBox);\n };\n\n if (session.sharedBox) {\n for (const id of session.writeIds) {\n const next = worldOf(id);\n if (next === undefined) continue;\n previews.set(id, storedPose(session, id, next));\n }\n return { previews };\n }\n\n const id = session.writeIds[0];\n const g = session.geometryOf(id);\n const remapped = worldOf(id);\n if (remapped === undefined) return { previews };\n const world = snapPose(\n session.pointSnap,\n g,\n pinFixedCorner(g, remapped, box, proposed),\n box,\n box.anchor,\n gctx.modifiers,\n gctx.plane ?? null,\n );\n previews.set(id, storedPose(session, id, world));\n gctx.current = new Map<string, Bounds>([[id as string, boundsForRules(g, world)]]);\n return { previews };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"frame.js","names":["computeProposedBounds","dx","dy","worldDeltaToLocal","frame","worldDx","worldDy","nx","ob","ny","nw","nh","anchor","constrain","bounds","proposed","b","constraints","r","gctx","leafPose","sharedBox","poseFrameOf","start","remapRotatedLeaf","src","dst","g","pinFixedCorner","boxFrame","box","pose","newFixedLocal","fixedCornerOf","newFixedWorld","localToWorld","translatePoseViaDescriptor","storedPose","layer","place","id","carryPose","world","planeOf","posesInBox","previews","worldOf","next","remapped","snap","nextFrame","at","moveCtx","session","pointerStateOf","readers","snapPose","lone","boundsForRules"],"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 } from './cornerHandles';\nimport { remapRotatedLeaf, translatePoseViaDescriptor, type PoseDescriptor } from './geometry';\nimport { snapPose } from './pointSnap';\nimport { boundsForRules } from './ruleBounds';\nimport { boxFrame } from './boxFrame';\nimport type { ResizeBox, ResizeFrame, ResizeSession } from './session';\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 let nx = ob.x;\n let ny = ob.y;\n let nw = ob.width;\n let nh = ob.height;\n if (anchor.x === 'min') {\n nw = ob.width + dx;\n } else if (anchor.x === 'max') {\n nx = ob.x + dx;\n nw = ob.width - dx;\n }\n if (anchor.y === 'min') {\n nh = ob.height + dy;\n } else if (anchor.y === 'max') {\n ny = ob.y + dy;\n nh = ob.height - dy;\n }\n return { x: nx, y: ny, width: nw, height: nh };\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 `proposed`. A lone target is also pinned at the fixed corner and run\n * through `snap`, and comes back with its world pose. */\nexport function posesInBox(\n place: Pick<ResizeSession, 'scene' | 'poseFrame' | 'view' | 'geometryOf' | 'writeIds' | 'startWorlds' | 'box' | 'sharedBox'>,\n proposed: Bounds,\n snap: (g: PoseDescriptor<unknown>, world: unknown) => unknown = (_g, world) => world,\n): { previews: Map<NodeId, unknown>; lone?: { id: NodeId; g: PoseDescriptor<unknown>; world: unknown } } {\n const { box } = place;\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 };\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 };\n const world = snap(g, pinFixedCorner(g, remapped, box, proposed));\n previews.set(id, storedPose(place, id, world));\n return { previews, lone: { id, g, world } };\n}\n\n/** One move's previews: the box as the drag and the constraints leave it,\n * and every write id's stored pose inside it. A lone target also gets the\n * rotated-resize pin and the point snaps, which a shared box, resized in the\n * AABB frame, does not. `moveCtx` must carry a drag. */\nexport function nextFrame(session: ResizeSession, readers: GestureReaders, moveCtx: InvocationCtx): ResizeFrame {\n const at = moveCtx.drag!.current;\n const { box, gestureCtx: gctx } = session;\n gctx.modifiers = { ...moveCtx.modifiers };\n gctx.pointer = pointerStateOf(at, moveCtx);\n gctx.view = readers.view();\n gctx.plane = readers.plane();\n\n const proposed = constrain(\n session.constraints,\n gctx,\n box.anchor,\n computeProposedBounds(box.bounds, box.anchor, at.x - session.startWorld.x, at.y - session.startWorld.y, boxFrame(box, box.bounds)),\n );\n\n const { previews, lone } = posesInBox(session, proposed, (g, world) => snapPose(\n session.pointSnap, g, world, box, box.anchor, gctx.modifiers, gctx.plane ?? null,\n ));\n if (lone) gctx.current = new Map<string, Bounds>([[lone.id as string, boundsForRules(lone.g, lone.world)]]);\n return { previews, proposed };\n}\n"],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import { resizeOps as e } from "./commit.js";
2
+ import { posesInBox as t } from "./frame.js";
3
+ import { captureResize as n } from "./session.js";
4
+ //#region src/interactions/actions/resize/replay.ts
5
+ function r(e, t) {
6
+ return {
7
+ x: e.x + t.x * e.width,
8
+ y: e.y + t.y * e.height,
9
+ width: t.width * e.width,
10
+ height: t.height * e.height
11
+ };
12
+ }
13
+ function i(e, t) {
14
+ let n = e.width === 0 ? {
15
+ x: 0,
16
+ width: 1
17
+ } : {
18
+ x: (t.x - e.x) / e.width,
19
+ width: t.width / e.width
20
+ }, r = e.height === 0 ? {
21
+ y: 0,
22
+ height: 1
23
+ } : {
24
+ y: (t.y - e.y) / e.height,
25
+ height: t.height / e.height
26
+ };
27
+ return {
28
+ x: n.x,
29
+ y: r.y,
30
+ width: n.width,
31
+ height: r.height
32
+ };
33
+ }
34
+ function a(i, a, o, s, c, l) {
35
+ if (a.length === 0) return [];
36
+ let u = n(i, a, o, c);
37
+ if (!u) return [];
38
+ let { place: d } = u, { previews: f } = t(d, r(d.box.bounds, s));
39
+ return e({
40
+ ...d,
41
+ geometryProjection: c.geometryProjection
42
+ }, f, l);
43
+ }
44
+ //#endregion
45
+ export { r as boxInUnits, a as resizeSelectionOps, i as unitsOfBox };
46
+
47
+ //# sourceMappingURL=replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.js","names":["boxInUnits","from","to","unitsOfBox","ux","uy","resizeSelectionOps","selected","captured","captureResize","scene","anchor","deps","posesInBox","place","units","resizeOps","previews","label"],"sources":["../../../../src/interactions/actions/resize/replay.ts"],"sourcesContent":["import type { ActionDeps, ResizeAnchor } from '@weasel-js/routing';\nimport type { Op } from 'core/ops/types';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { resizeOps } from './commit';\nimport { posesInBox } from './frame';\nimport { captureResize } from './session';\n\n/** `to`, given in units of `from` (`{ x: 0, y: 0, width: 1, height: 1 }` is\n * `from` itself), in `from`'s own coordinates. */\nexport function boxInUnits(from: Bounds, to: Bounds): Bounds {\n return {\n x: from.x + to.x * from.width,\n y: from.y + to.y * from.height,\n width: to.width * from.width,\n height: to.height * from.height,\n };\n}\n\n/** `to` in units of `from`: the inverse of `boxInUnits`. A zero extent\n * reads as unscaled on that axis. */\nexport function unitsOfBox(from: Bounds, to: Bounds): Bounds {\n const ux = from.width === 0 ? { x: 0, width: 1 } : { x: (to.x - from.x) / from.width, width: to.width / from.width };\n const uy = from.height === 0 ? { y: 0, height: 1 } : { y: (to.y - from.y) / from.height, height: to.height / from.height };\n return { x: ux.x, y: uy.y, width: ux.width, height: uy.height };\n}\n\n/** The ops that resize `selected` the way a handle drag would, taking the box\n * it would resize to `units` of itself. The resize policy's expansion\n * applies; its constraints and point snaps, which shape a pointer, do not. */\nexport function resizeSelectionOps(\n scene: Scene<unknown, string, unknown>,\n selected: readonly string[],\n anchor: ResizeAnchor,\n units: Bounds,\n deps: Pick<ActionDeps, 'poseDescriptor' | 'resizePolicy' | 'view' | 'geometryProjection'>,\n label: string,\n): Op[] {\n if (selected.length === 0) return [];\n const captured = captureResize(scene, selected as NodeId[], anchor, deps);\n if (!captured) return [];\n const { place } = captured;\n const { previews } = posesInBox(place, boxInUnits(place.box.bounds, units));\n return resizeOps({ ...place, geometryProjection: deps.geometryProjection }, previews, label);\n}\n"],"mappings":";;;;AAUA,SAAgBA,EAAW,GAAc,GAAoB;CAC3D,OAAO;EACL,GAAGC,EAAK,IAAIC,EAAG,IAAID,EAAK;EACxB,GAAGA,EAAK,IAAIC,EAAG,IAAID,EAAK;EACxB,OAAOC,EAAG,QAAQD,EAAK;EACvB,QAAQC,EAAG,SAASD,EAAK;CAC3B;AACF;AAIA,SAAgBE,EAAW,GAAc,GAAoB;CAC3D,IAAMC,IAAKH,EAAK,UAAU,IAAI;EAAE,GAAG;EAAG,OAAO;CAAE,IAAI;EAAE,IAAIC,EAAG,IAAID,EAAK,KAAKA,EAAK;EAAO,OAAOC,EAAG,QAAQD,EAAK;CAAM,GAC7GI,IAAKJ,EAAK,WAAW,IAAI;EAAE,GAAG;EAAG,QAAQ;CAAE,IAAI;EAAE,IAAIC,EAAG,IAAID,EAAK,KAAKA,EAAK;EAAQ,QAAQC,EAAG,SAASD,EAAK;CAAO;CACzH,OAAO;EAAE,GAAGG,EAAG;EAAG,GAAGC,EAAG;EAAG,OAAOD,EAAG;EAAO,QAAQC,EAAG;CAAO;AAChE;AAKA,SAAgBC,EACd,GACA,GACA,GACA,GACA,GACA,GACM;CACN,IAAIC,EAAS,WAAW,GAAG,OAAO,CAAC;CACnC,IAAMC,IAAWC,EAAcC,GAAOH,GAAsBI,GAAQC,CAAI;CACxE,IAAI,CAACJ,GAAU,OAAO,CAAC;CACvB,IAAM,EAAE,aAAUA,GACZ,EAAE,gBAAaK,EAAWC,GAAOd,EAAWc,EAAM,IAAI,QAAQC,CAAK,CAAC;CAC1E,OAAOC,EAAU;EAAE,GAAGF;EAAO,oBAAoBF,EAAK;CAAmB,GAAGK,GAAUC,CAAK;AAC7F"}
@@ -4,46 +4,60 @@ import { nodeDescriptors as n, poseDescriptorOf as r } from "../poseDescriptorDe
4
4
  import { scenePoseFrame as i } from "../poseFrame.js";
5
5
  import { buildGestureContext as a, captureBox as o, captureStarts as s, captureTargets as c, resolvePolicy as l } from "./capture.js";
6
6
  //#region src/interactions/actions/resize/session.ts
7
- function u(u) {
8
- let d = u.deps.selection, f = u.deps.scene;
9
- if (!d || !f) return null;
10
- let p = d.get();
11
- if (p.length === 0) return null;
12
- let m = u.drag?.affordance?.anchor;
13
- if (!m) return null;
14
- let h = r(u.deps.poseDescriptor), g = u.deps.resizePolicy, { constraints: _, pointSnap: v, expandIds: y } = l(g), b = n(f, h), x = c(f, p, y);
15
- if (!x) return null;
16
- let { writeIds: S, isGroupPath: C } = x, w = i(f), T = u.deps.view, E = s(f, S, b, w, T);
17
- if (E.startPoses.size === 0) return null;
18
- let { box: D, ruleOrigin: O } = o(E, S, C, m, h, b), k = {
19
- x: u.drag?.start.x ?? 0,
20
- y: u.drag?.start.y ?? 0
21
- }, A = t(u.deps), j = a(u, p, O, k, A);
22
- for (let e of _) e.onStart?.(j);
7
+ function u(e, t, a, u) {
8
+ let d = r(u.poseDescriptor), f = u.resizePolicy, { constraints: p, pointSnap: m, expandIds: h } = l(f), g = n(e, d), _ = c(e, t, h);
9
+ if (!_) return null;
10
+ let { writeIds: v, isGroupPath: y } = _, b = i(e), x = u.view, S = s(e, v, g, b, x);
11
+ if (S.startPoses.size === 0) return null;
12
+ let { box: C, ruleOrigin: w } = o(S, v, y, a, d, g);
13
+ return {
14
+ place: {
15
+ scene: e,
16
+ writeIds: v,
17
+ sharedBox: y || v.length > 1,
18
+ box: C,
19
+ startPoses: S.startPoses,
20
+ startWorlds: S.startWorlds,
21
+ geometryOf: g,
22
+ poseFrame: b,
23
+ view: x
24
+ },
25
+ ruleOrigin: w,
26
+ policy: f,
27
+ constraints: p,
28
+ pointSnap: m
29
+ };
30
+ }
31
+ function d(n) {
32
+ let r = n.deps.selection, i = n.deps.scene;
33
+ if (!r || !i) return null;
34
+ let o = r.get();
35
+ if (o.length === 0) return null;
36
+ let s = n.drag?.affordance?.anchor;
37
+ if (!s) return null;
38
+ let c = u(i, o, s, n.deps);
39
+ if (!c) return null;
40
+ let { place: l, ruleOrigin: d, policy: f, constraints: p, pointSnap: m } = c, h = {
41
+ x: n.drag?.start.x ?? 0,
42
+ y: n.drag?.start.y ?? 0
43
+ }, g = t(n.deps), _ = a(n, o, d, h, g);
44
+ for (let e of p) e.onStart?.(_);
23
45
  return {
24
46
  session: {
25
- scene: f,
26
- writeIds: S,
27
- sharedBox: C || S.length > 1,
28
- box: D,
29
- startPoses: E.startPoses,
30
- startWorlds: E.startWorlds,
31
- startWorld: k,
32
- geometryOf: b,
33
- poseFrame: w,
34
- view: T,
35
- constraints: _,
36
- pointSnap: v,
37
- gestureCtx: j,
38
- applyOps: u.deps.applyOps,
39
- geometryProjection: u.deps.geometryProjection,
40
- selectionMethods: d.adapterMethods,
41
- lifecycle: e(g, "Resize", _)
47
+ ...l,
48
+ startWorld: h,
49
+ constraints: p,
50
+ pointSnap: m,
51
+ gestureCtx: _,
52
+ applyOps: n.deps.applyOps,
53
+ geometryProjection: n.deps.geometryProjection,
54
+ selectionMethods: r.adapterMethods,
55
+ lifecycle: e(f, "Resize", p)
42
56
  },
43
- readers: A
57
+ readers: g
44
58
  };
45
59
  }
46
60
  //#endregion
47
- export { u as beginResize };
61
+ export { d as beginResize, u as captureResize };
48
62
 
49
63
  //# sourceMappingURL=session.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","names":["beginResize","selection","ctx","scene","ids","anchor","geometry","poseDescriptorOf","policy","resolvePolicy","geometryOf","nodeDescriptors","targets","captureTargets","expandIds","poseFrame","scenePoseFrame","view","starts","captureStarts","writeIds","captureBox","isGroupPath","startWorld","readers","gestureReaders","gestureCtx","buildGestureContext","ruleOrigin","b","constraints","readGestureLifecycle"],"sources":["../../../../src/interactions/actions/resize/session.ts"],"sourcesContent":["import type { PoseLinear } from '@weasel-js/geom';\nimport type { InvocationCtx } from '@weasel-js/routing';\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, PointSnapBehavior, 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';\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}\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 readonly constraints: readonly BoundsConstraint<Bounds>[];\n readonly pointSnap: readonly PointSnapBehavior<Bounds>[];\n /** Reused across the drag; constraints mutate its `scratch`. */\n readonly gestureCtx: GestureContext<Bounds>;\n readonly applyOps?: (ops: Op[], label: string) => void;\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}\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}\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 geometry = poseDescriptorOf(ctx.deps.poseDescriptor);\n const policy = ctx.deps.resizePolicy;\n const { constraints, pointSnap, 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 = ctx.deps.view;\n const starts = captureStarts(scene, writeIds, geometryOf, poseFrame, view);\n if (starts.startPoses.size === 0) return null;\n\n const { box, ruleOrigin } = captureBox(starts, writeIds, isGroupPath, anchor, geometry, geometryOf);\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 scene,\n writeIds,\n sharedBox: isGroupPath || writeIds.length > 1,\n box,\n startPoses: starts.startPoses,\n startWorlds: starts.startWorlds,\n startWorld,\n geometryOf,\n poseFrame,\n view,\n constraints,\n pointSnap,\n gestureCtx,\n applyOps: ctx.deps.applyOps,\n geometryProjection: ctx.deps.geometryProjection,\n selectionMethods: selection.adapterMethods,\n lifecycle: readGestureLifecycle(policy, 'Resize', constraints),\n };\n return { session, readers };\n}\n"],"mappings":";;;;;;AAuEA,SAAgBA,EACd,GAC4D;CAC5D,IAAMC,IAAYC,EAAI,KAAK,WACrBC,IAAQD,EAAI,KAAK;CACvB,IAAI,CAACD,KAAa,CAACE,GAAO,OAAO;CAEjC,IAAMC,IAAMH,EAAU,IAAI;CAC1B,IAAIG,EAAI,WAAW,GAAG,OAAO;CAE7B,IAAMC,IAASH,EAAI,MAAM,YAAY;CACrC,IAAI,CAACG,GAAQ,OAAO;CAEpB,IAAMC,IAAWC,EAAiBL,EAAI,KAAK,cAAc,GACnDM,IAASN,EAAI,KAAK,cAClB,EAAE,gBAAa,cAAW,iBAAcO,EAAcD,CAAM,GAC5DE,IAAaC,EAAgBR,GAAOG,CAAQ,GAE5CM,IAAUC,EAAeV,GAAOC,GAAKU,CAAS;CACpD,IAAI,CAACF,GAAS,OAAO;CACrB,IAAM,EAAE,aAAU,mBAAgBA,GAK5BG,IAAYC,EAAeb,CAAK,GAChCc,IAAOf,EAAI,KAAK,MAChBgB,IAASC,EAAchB,GAAOiB,GAAUV,GAAYK,GAAWE,CAAI;CACzE,IAAIC,EAAO,WAAW,SAAS,GAAG,OAAO;CAEzC,IAAM,EAAE,QAAK,kBAAeG,EAAWH,GAAQE,GAAUE,GAAajB,GAAQC,GAAUI,CAAU,GAC5Fa,IAAa;EAAE,GAAGrB,EAAI,MAAM,MAAM,KAAK;EAAG,GAAGA,EAAI,MAAM,MAAM,KAAK;CAAE,GACpEsB,IAAUC,EAAevB,EAAI,IAAI,GACjCwB,IAAaC,EAAoBzB,GAAKE,GAAKwB,GAAYL,GAAYC,CAAO;CAChF,KAAK,IAAMK,KAAKC,GAAa,EAAE,UAAUJ,CAAU;CAqBnD,OAAO;EAAE,SAAA;GAlBP;GACA;GACA,WAAWJ,KAAeF,EAAS,SAAS;GAC5C;GACA,YAAYF,EAAO;GACnB,aAAaA,EAAO;GACpB;GACA;GACA;GACA;GACA;GACA;GACA;GACA,UAAUhB,EAAI,KAAK;GACnB,oBAAoBA,EAAI,KAAK;GAC7B,kBAAkBD,EAAU;GAC5B,WAAW8B,EAAqBvB,GAAQ,UAAUsB,CAAW;EAEtD;EAAS;CAAQ;AAC5B"}
1
+ {"version":3,"file":"session.js","names":["captureResize","geometry","poseDescriptorOf","deps","policy","resolvePolicy","geometryOf","nodeDescriptors","scene","targets","captureTargets","ids","expandIds","poseFrame","scenePoseFrame","view","starts","captureStarts","writeIds","captureBox","isGroupPath","anchor","beginResize","selection","ctx","captured","startWorld","readers","gestureReaders","gestureCtx","buildGestureContext","ruleOrigin","b","constraints","place","readGestureLifecycle"],"sources":["../../../../src/interactions/actions/resize/session.ts"],"sourcesContent":["import type { PoseLinear } from '@weasel-js/geom';\nimport type { ActionDeps, InvocationCtx } from '@weasel-js/routing';\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, PointSnapBehavior, 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';\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}\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 readonly constraints: readonly BoundsConstraint<Bounds>[];\n readonly pointSnap: readonly PointSnapBehavior<Bounds>[];\n /** Reused across the drag; constraints mutate its `scratch`. */\n readonly gestureCtx: GestureContext<Bounds>;\n readonly applyOps?: (ops: Op[], label: string) => void;\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}\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'\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'>,\n): {\n place: ResizePlace;\n ruleOrigin: Bounds;\n policy: ActionDeps['resizePolicy'];\n constraints: BoundsConstraint<Bounds>[];\n pointSnap: PointSnapBehavior<Bounds>[];\n} | null {\n const geometry = poseDescriptorOf(deps.poseDescriptor);\n const policy = deps.resizePolicy;\n const { constraints, pointSnap, 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 starts = captureStarts(scene, writeIds, geometryOf, poseFrame, view);\n if (starts.startPoses.size === 0) return null;\n\n const { box, ruleOrigin } = captureBox(starts, writeIds, isGroupPath, anchor, geometry, geometryOf);\n return {\n place: {\n scene,\n writeIds,\n sharedBox: isGroupPath || writeIds.length > 1,\n box,\n startPoses: starts.startPoses,\n startWorlds: starts.startWorlds,\n geometryOf,\n poseFrame,\n view,\n },\n ruleOrigin,\n policy,\n constraints,\n pointSnap,\n };\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, pointSnap } = 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 pointSnap,\n gestureCtx,\n applyOps: ctx.deps.applyOps,\n geometryProjection: ctx.deps.geometryProjection,\n selectionMethods: selection.adapterMethods,\n lifecycle: readGestureLifecycle(policy, 'Resize', constraints),\n };\n return { session, readers };\n}\n"],"mappings":";;;;;;AA+EA,SAAgBA,EACd,GACA,GACA,GACA,GAOO;CACP,IAAMC,IAAWC,EAAiBC,EAAK,cAAc,GAC/CC,IAASD,EAAK,cACd,EAAE,gBAAa,cAAW,iBAAcE,EAAcD,CAAM,GAC5DE,IAAaC,EAAgBC,GAAOP,CAAQ,GAE5CQ,IAAUC,EAAeF,GAAOG,GAAKC,CAAS;CACpD,IAAI,CAACH,GAAS,OAAO;CACrB,IAAM,EAAE,aAAU,mBAAgBA,GAK5BI,IAAYC,EAAeN,CAAK,GAChCO,IAAOZ,EAAK,MACZa,IAASC,EAAcT,GAAOU,GAAUZ,GAAYO,GAAWE,CAAI;CACzE,IAAIC,EAAO,WAAW,SAAS,GAAG,OAAO;CAEzC,IAAM,EAAE,QAAK,kBAAeG,EAAWH,GAAQE,GAAUE,GAAaC,GAAQpB,GAAUK,CAAU;CAClG,OAAO;EACL,OAAO;GACL;GACA;GACA,WAAWc,KAAeF,EAAS,SAAS;GAC5C;GACA,YAAYF,EAAO;GACnB,aAAaA,EAAO;GACpB;GACA;GACA;EACF;EACA;EACA;EACA;EACA;CACF;AACF;AAKA,SAAgBM,EACd,GAC4D;CAC5D,IAAMC,IAAYC,EAAI,KAAK,WACrBhB,IAAQgB,EAAI,KAAK;CACvB,IAAI,CAACD,KAAa,CAACf,GAAO,OAAO;CAEjC,IAAMG,IAAMY,EAAU,IAAI;CAC1B,IAAIZ,EAAI,WAAW,GAAG,OAAO;CAE7B,IAAMU,IAASG,EAAI,MAAM,YAAY;CACrC,IAAI,CAACH,GAAQ,OAAO;CAEpB,IAAMI,IAAWzB,EAAcQ,GAAOG,GAAKU,GAAQG,EAAI,IAAI;CAC3D,IAAI,CAACC,GAAU,OAAO;CACtB,IAAM,EAAE,UAAO,eAAY,WAAQ,gBAAa,iBAAcA,GACxDC,IAAa;EAAE,GAAGF,EAAI,MAAM,MAAM,KAAK;EAAG,GAAGA,EAAI,MAAM,MAAM,KAAK;CAAE,GACpEG,IAAUC,EAAeJ,EAAI,IAAI,GACjCK,IAAaC,EAAoBN,GAAKb,GAAKoB,GAAYL,GAAYC,CAAO;CAChF,KAAK,IAAMK,KAAKC,GAAa,EAAE,UAAUJ,CAAU;CAanD,OAAO;EAAE,SAAA;GAVP,GAAGK;GACH;GACA;GACA;GACA;GACA,UAAUV,EAAI,KAAK;GACnB,oBAAoBA,EAAI,KAAK;GAC7B,kBAAkBD,EAAU;GAC5B,WAAWY,EAAqB/B,GAAQ,UAAU6B,CAAW;EAEtD;EAAS;CAAQ;AAC5B"}
@@ -39,7 +39,8 @@ function t(t) {
39
39
  bounds: t,
40
40
  geometry: i,
41
41
  extras: r.extras,
42
- ...r.anchorPoint && r.shape !== "pencil" ? { anchorPoint: r.anchorPoint } : {}
42
+ ...r.anchorPoint && r.shape !== "pencil" ? { anchorPoint: r.anchorPoint } : {},
43
+ ...r.copies ? { copies: r.copies } : {}
43
44
  });
44
45
  break;
45
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"resolveOverlays.js","names":["resolveOverlays","out","ov","overlays","x","y","width","height","insertPreviewExtent","bounds","geometry"],"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\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 /** 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/** 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 });\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 }\n }\n return out;\n}\n"],"mappings":";;AAwFA,SAAgBA,EAAgB,GAAuD;CACrF,IAAMC,IAAyB,CAAC;CAChC,KAAK,IAAMC,KAAMC,GACf,QAAQD,EAAG,MAAX;EACE,KAAK,WAAW;GACd,IAAME,IAAI,KAAK,IAAIF,EAAG,MAAM,GAAGA,EAAG,QAAQ,CAAC,GACrCG,IAAI,KAAK,IAAIH,EAAG,MAAM,GAAGA,EAAG,QAAQ,CAAC,GACrCI,IAAQ,KAAK,IAAIJ,EAAG,QAAQ,IAAIA,EAAG,MAAM,CAAC,GAC1CK,IAAS,KAAK,IAAIL,EAAG,QAAQ,IAAIA,EAAG,MAAM,CAAC;GACjD,IAAII,MAAU,KAAKC,MAAW,GAAG;GACjC,EAAI,KAAK;IACP,MAAM;IACN,cAAc;IACd,QAAQ;KAAE;KAAG;KAAG;KAAO;IAAO;IAC9B,WAAWL,EAAG;GAChB,CAAC;GACD;EACF;EACA,KAAK;GACH,IAAIA,EAAG,SAAS,SAAS,GAAG;GAC5B,EAAI,KAAK;IACP,MAAM;IACN,cAAc;IACd,UAAUA,EAAG;IACb,SAASA,EAAG;IACZ,WAAWA,EAAG;GAChB,CAAC;GACD;EAEF,KAAK,iBAAiB;GACpB,IAAM,EAAE,WAAQ,gBAAaM,EAAoBN,CAAE;GAInD,IADIO,EAAO,UAAU,KAAKA,EAAO,WAAW,KAAKP,EAAG,UAAU,YAC1DQ,EAAS,SAAS,YAAYA,EAAS,QAAQ,SAAS,GAAG;GAC/D,EAAI,KAAK;IACP,MAAM;IACN,cAAc;IAGd,OAAOR,EAAG;IACV;IACA;IACA,QAAQA,EAAG;IACX,GAAIA,EAAG,eAAeA,EAAG,UAAU,WAAW,EAAE,aAAaA,EAAG,YAAY,IAAI,CAAC;GACnF,CAAC;GACD;EACF;EACA,KAAK;GACH,IAAIA,EAAG,OAAO,SAAS,GAAG;GAC1B,EAAI,KAAK;IACP,MAAM;IACN,cAAc;IACd,QAAQA,EAAG;IACX,MAAMA,EAAG,QAAQ;GACnB,CAAC;CAGL;CAEF,OAAOD;AACT"}
1
+ {"version":3,"file":"resolveOverlays.js","names":["resolveOverlays","out","ov","overlays","x","y","width","height","insertPreviewExtent","bounds","geometry"],"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\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/** 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 }\n }\n return out;\n}\n"],"mappings":";;AA0FA,SAAgBA,EAAgB,GAAuD;CACrF,IAAMC,IAAyB,CAAC;CAChC,KAAK,IAAMC,KAAMC,GACf,QAAQD,EAAG,MAAX;EACE,KAAK,WAAW;GACd,IAAME,IAAI,KAAK,IAAIF,EAAG,MAAM,GAAGA,EAAG,QAAQ,CAAC,GACrCG,IAAI,KAAK,IAAIH,EAAG,MAAM,GAAGA,EAAG,QAAQ,CAAC,GACrCI,IAAQ,KAAK,IAAIJ,EAAG,QAAQ,IAAIA,EAAG,MAAM,CAAC,GAC1CK,IAAS,KAAK,IAAIL,EAAG,QAAQ,IAAIA,EAAG,MAAM,CAAC;GACjD,IAAII,MAAU,KAAKC,MAAW,GAAG;GACjC,EAAI,KAAK;IACP,MAAM;IACN,cAAc;IACd,QAAQ;KAAE;KAAG;KAAG;KAAO;IAAO;IAC9B,WAAWL,EAAG;GAChB,CAAC;GACD;EACF;EACA,KAAK;GACH,IAAIA,EAAG,SAAS,SAAS,GAAG;GAC5B,EAAI,KAAK;IACP,MAAM;IACN,cAAc;IACd,UAAUA,EAAG;IACb,SAASA,EAAG;IACZ,WAAWA,EAAG;GAChB,CAAC;GACD;EAEF,KAAK,iBAAiB;GACpB,IAAM,EAAE,WAAQ,gBAAaM,EAAoBN,CAAE;GAInD,IADIO,EAAO,UAAU,KAAKA,EAAO,WAAW,KAAKP,EAAG,UAAU,YAC1DQ,EAAS,SAAS,YAAYA,EAAS,QAAQ,SAAS,GAAG;GAC/D,EAAI,KAAK;IACP,MAAM;IACN,cAAc;IAGd,OAAOR,EAAG;IACV;IACA;IACA,QAAQA,EAAG;IACX,GAAIA,EAAG,eAAeA,EAAG,UAAU,WAAW,EAAE,aAAaA,EAAG,YAAY,IAAI,CAAC;IACjF,GAAIA,EAAG,SAAS,EAAE,QAAQA,EAAG,OAAO,IAAI,CAAC;GAC3C,CAAC;GACD;EACF;EACA,KAAK;GACH,IAAIA,EAAG,OAAO,SAAS,GAAG;GAC1B,EAAI,KAAK;IACP,MAAM;IACN,cAAc;IACd,QAAQA,EAAG;IACX,MAAMA,EAAG,QAAQ;GACnB,CAAC;CAGL;CAEF,OAAOD;AACT"}
@@ -1,10 +1,12 @@
1
- import { closeGesture as e, runBehaviorCancel as t } from "../gestureLifecycle.js";
2
- import { inPlane as n, selectionLayer as r } from "../planeInput.js";
3
- import { nextFrame as i } from "./frame.js";
4
- import { commitRotate as a } from "./commit.js";
5
- import { beginRotate as o } from "./session.js";
1
+ import { rotateCursorAt as e } from "../../../affordances/rotateCursor.js";
2
+ import { closeGesture as t, runBehaviorCancel as n } from "../gestureLifecycle.js";
3
+ import { inPlane as r, selectionLayer as i } from "../planeInput.js";
4
+ import { recordTransform as a } from "../transform-again/memory.js";
5
+ import { nextFrame as o } from "./frame.js";
6
+ import { commitRotate as s } from "./commit.js";
7
+ import { beginRotate as c } from "./session.js";
6
8
  //#region src/interactions/actions/rotate/action.ts
7
- var s = n({
9
+ var l = r({
8
10
  id: "rotate",
9
11
  label: "Rotate",
10
12
  eligible: { capability: "transforms-selection" },
@@ -17,40 +19,53 @@ var s = n({
17
19
  ],
18
20
  invoker: {
19
21
  timing: "ongoing",
20
- start(n, r) {
21
- let s = o(n, r);
22
- if (!s) return {};
23
- let { session: c, readers: l } = s, u = c.scene.overrides.hold(), d = {
22
+ start(r, i) {
23
+ let l = c(r, i);
24
+ if (!l) return {};
25
+ let { session: u, readers: d } = l, f = [...r.deps.selection?.get() ?? []], p = u.scene.overrides.hold(), m = {
24
26
  delta: 0,
25
27
  previews: /* @__PURE__ */ new Map()
26
- };
27
- return c.lifecycle.start(c.gestureCtx.draggedIds), {
28
+ }, h = r.world;
29
+ return u.lifecycle.start(u.gestureCtx.draggedIds), {
28
30
  kind: "rotate",
31
+ cursor: () => {
32
+ let t = r.deps.view?.get().scale;
33
+ return t ? e(u.turn.pivot, h, t) : void 0;
34
+ },
29
35
  onMove(e) {
30
- d = i(c, l, e), u.set(d.previews);
36
+ h = e.world, m = o(u, d, e), p.set(m.previews);
31
37
  },
32
- onEnd(n, r) {
38
+ onEnd(e, r) {
33
39
  let i = !1;
34
40
  try {
35
- r === "commit" ? i = a(c, d) : t(c.behaviors, c.gestureCtx);
41
+ if (r === "commit") {
42
+ if (i = s(u, m), i) {
43
+ let e = u.ids.length > 1 && !u.turn.useUnionPivot ? "each" : "union";
44
+ a(u.scene, {
45
+ kind: "rotate",
46
+ angle: m.delta,
47
+ pivot: e
48
+ }, f);
49
+ }
50
+ } else n(u.behaviors, u.gestureCtx);
36
51
  } finally {
37
- e({
38
- hold: u,
39
- previews: d.previews,
40
- behaviors: c.behaviors,
41
- ctx: c.gestureCtx,
42
- lifecycle: c.lifecycle
52
+ t({
53
+ hold: p,
54
+ previews: m.previews,
55
+ behaviors: u.behaviors,
56
+ ctx: u.gestureCtx,
57
+ lifecycle: u.lifecycle
43
58
  }, i);
44
59
  }
45
60
  },
46
- previewIds: () => d.previews.keys(),
47
- previewPose: (e) => d.previews.get(e) ?? null
61
+ previewIds: () => m.previews.keys(),
62
+ previewPose: (e) => m.previews.get(e) ?? null
48
63
  };
49
64
  }
50
65
  },
51
66
  enabled: () => !0
52
- }, r);
67
+ }, i);
53
68
  //#endregion
54
- export { s as rotateAction };
69
+ export { l as rotateAction };
55
70
 
56
71
  //# sourceMappingURL=action.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"action.js","names":["rotateAction","inPlane","begun","beginRotate","ctx","opts","hold","session","frame","nextFrame","readers","moveCtx","committed","reason","commitRotate","runBehaviorCancel","id","selectionLayer"],"sources":["../../../../src/interactions/actions/rotate/action.ts"],"sourcesContent":["import type { Action } from '@weasel-js/routing';\nimport type { BindingOpts, InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport type { NodeId } from 'core/scene/types';\nimport { closeGesture, runBehaviorCancel } from '../gestureLifecycle';\nimport { inPlane, selectionLayer } from '../planeInput';\nimport { commitRotate } from './commit';\nimport { nextFrame } from './frame';\nimport { beginRotate, type RotateFrame } from './session';\n\n/**\n * @experimental\n * Pointer-driven rotation of the selection, committed as one undo entry.\n *\n * A pose whose descriptor has no `withRotation`, or reports\n * `supportsRotation` false, is left alone. Behaviors (`opts.behaviors`) see\n * the first rotated node's turned pose; a pose one returns from `onMove` sets\n * the rotation for the whole selection.\n */\nexport const rotateAction: Action & { requires: string[] } = inPlane({\n id: 'rotate',\n label: 'Rotate',\n // No default binding: a bare `{ kind: 'drag' }` makes any drag no active\n // tool claimed rotate a non-empty selection. The rotation handle binds it\n // (`selectionRotateBindings`).\n eligible: { capability: 'transforms-selection' },\n requires: ['selection', 'scene', 'applyOps', 'poseDescriptor', 'view'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts?: BindingOpts): OngoingHandle {\n const begun = beginRotate(ctx, opts);\n if (!begun) return {};\n const { session, readers } = begun;\n const hold = session.scene.overrides.hold();\n let frame: RotateFrame = { delta: 0, previews: new Map() };\n session.lifecycle.start(session.gestureCtx.draggedIds);\n return {\n kind: 'rotate',\n onMove(moveCtx: InvocationCtx): void {\n frame = nextFrame(session, readers, moveCtx);\n hold.set(frame.previews);\n },\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n if (reason === 'commit') committed = commitRotate(session, frame);\n else runBehaviorCancel(session.behaviors, session.gestureCtx);\n } finally {\n closeGesture({ hold, previews: frame.previews, behaviors: session.behaviors, ctx: session.gestureCtx, lifecycle: session.lifecycle }, committed);\n }\n },\n previewIds: () => frame.previews.keys(),\n previewPose: (id: string) => frame.previews.get(id as NodeId) ?? null,\n };\n },\n },\n enabled: () => true,\n}, selectionLayer);\n"],"mappings":";;;;;;AAkBA,IAAaA,IAAgDC,EAAQ;CACnE,IAAI;CACJ,OAAO;CAIP,UAAU,EAAE,YAAY,uBAAuB;CAC/C,UAAU;EAAC;EAAa;EAAS;EAAY;EAAkB;CAAM;CACrE,SAAS;EACP,QAAQ;EACR,MAAM,GAAoB,GAAmC;GAC3D,IAAMC,IAAQC,EAAYC,GAAKC,CAAI;GACnC,IAAI,CAACH,GAAO,OAAO,CAAC;GACpB,IAAM,EAAE,YAAS,eAAYA,GACvBI,IAAOC,EAAQ,MAAM,UAAU,KAAK,GACtCC,IAAqB;IAAE,OAAO;IAAG,0BAAU,IAAI,IAAI;GAAE;GAEzD,OADAD,EAAQ,UAAU,MAAMA,EAAQ,WAAW,UAAU,GAC9C;IACL,MAAM;IACN,OAAO,GAA8B;KAEnC,AADA,IAAQE,EAAUF,GAASG,GAASC,CAAO,GAC3CL,EAAK,IAAIE,EAAM,QAAQ;IACzB;IACA,MAAM,GAAwB,GAAmC;KAC/D,IAAII,IAAY;KAChB,IAAI;MACF,AAAIC,MAAW,WAAU,IAAYC,EAAaP,GAASC,CAAK,IAC3DO,EAAkBR,EAAQ,WAAWA,EAAQ,UAAU;KAC9D,UAAU;MACR,EAAa;OAAE;OAAM,UAAUC,EAAM;OAAU,WAAWD,EAAQ;OAAW,KAAKA,EAAQ;OAAY,WAAWA,EAAQ;MAAU,GAAGK,CAAS;KACjJ;IACF;IACA,kBAAkBJ,EAAM,SAAS,KAAK;IACtC,cAAc,MAAeA,EAAM,SAAS,IAAIQ,CAAY,KAAK;GACnE;EACF;CACF;CACA,eAAe;AACjB,GAAGC,CAAc"}
1
+ {"version":3,"file":"action.js","names":["rotateAction","inPlane","begun","beginRotate","ctx","opts","subject","hold","session","frame","pointer","scale","rotateCursorAt","moveCtx","nextFrame","readers","committed","reason","commitRotate","pivot","id","selectionLayer"],"sources":["../../../../src/interactions/actions/rotate/action.ts"],"sourcesContent":["import type { Action } from '@weasel-js/routing';\nimport type { BindingOpts, InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport type { NodeId } from 'core/scene/types';\nimport { closeGesture, runBehaviorCancel } from '../gestureLifecycle';\nimport { inPlane, selectionLayer } from '../planeInput';\nimport { rotateCursorAt } from 'affordances/rotateCursor';\nimport { commitRotate } from './commit';\nimport { nextFrame } from './frame';\nimport { beginRotate, type RotateFrame } from './session';\nimport { recordTransform } from '../transform-again/memory';\n\n/**\n * @experimental\n * Pointer-driven rotation of the selection, committed as one undo entry.\n *\n * A pose whose descriptor has no `withRotation`, or reports\n * `supportsRotation` false, is left alone. Behaviors (`opts.behaviors`) see\n * the first rotated node's turned pose; a pose one returns from `onMove` sets\n * the rotation for the whole selection.\n */\nexport const rotateAction: Action & { requires: string[] } = inPlane({\n id: 'rotate',\n label: 'Rotate',\n // No default binding: a bare `{ kind: 'drag' }` makes any drag no active\n // tool claimed rotate a non-empty selection. The rotation handle binds it\n // (`selectionRotateBindings`).\n eligible: { capability: 'transforms-selection' },\n requires: ['selection', 'scene', 'applyOps', 'poseDescriptor', 'view'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts?: BindingOpts): OngoingHandle {\n const begun = beginRotate(ctx, opts);\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 let frame: RotateFrame = { delta: 0, previews: new Map() };\n let pointer = ctx.world;\n session.lifecycle.start(session.gestureCtx.draggedIds);\n return {\n kind: 'rotate',\n cursor: () => {\n const scale = ctx.deps.view?.get().scale;\n return scale ? rotateCursorAt(session.turn.pivot, pointer, scale) : undefined;\n },\n onMove(moveCtx: InvocationCtx): void {\n pointer = moveCtx.world;\n frame = nextFrame(session, readers, moveCtx);\n hold.set(frame.previews);\n },\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n if (reason === 'commit') {\n committed = commitRotate(session, frame);\n if (committed) {\n const pivot = session.ids.length > 1 && !session.turn.useUnionPivot ? 'each' : 'union';\n recordTransform(session.scene, { kind: 'rotate', angle: frame.delta, pivot }, subject);\n }\n } else runBehaviorCancel(session.behaviors, session.gestureCtx);\n } finally {\n closeGesture({ hold, previews: frame.previews, behaviors: session.behaviors, ctx: session.gestureCtx, lifecycle: session.lifecycle }, committed);\n }\n },\n previewIds: () => frame.previews.keys(),\n previewPose: (id: string) => frame.previews.get(id as NodeId) ?? null,\n };\n },\n },\n enabled: () => true,\n}, selectionLayer);\n"],"mappings":";;;;;;;;AAoBA,IAAaA,IAAgDC,EAAQ;CACnE,IAAI;CACJ,OAAO;CAIP,UAAU,EAAE,YAAY,uBAAuB;CAC/C,UAAU;EAAC;EAAa;EAAS;EAAY;EAAkB;CAAM;CACrE,SAAS;EACP,QAAQ;EACR,MAAM,GAAoB,GAAmC;GAC3D,IAAMC,IAAQC,EAAYC,GAAKC,CAAI;GACnC,IAAI,CAACH,GAAO,OAAO,CAAC;GACpB,IAAM,EAAE,YAAS,eAAYA,GACvBI,IAAU,CAAC,GAAIF,EAAI,KAAK,WAAW,IAAI,KAAK,CAAC,CAAE,GAC/CG,IAAOC,EAAQ,MAAM,UAAU,KAAK,GACtCC,IAAqB;IAAE,OAAO;IAAG,0BAAU,IAAI,IAAI;GAAE,GACrDC,IAAUN,EAAI;GAElB,OADAI,EAAQ,UAAU,MAAMA,EAAQ,WAAW,UAAU,GAC9C;IACL,MAAM;IACN,cAAc;KACZ,IAAMG,IAAQP,EAAI,KAAK,MAAM,IAAI,CAAC,CAAC;KACnC,OAAOO,IAAQC,EAAeJ,EAAQ,KAAK,OAAOE,GAASC,CAAK,IAAI,KAAA;IACtE;IACA,OAAO,GAA8B;KAGnC,AAFA,IAAUE,EAAQ,OAClB,IAAQC,EAAUN,GAASO,GAASF,CAAO,GAC3CN,EAAK,IAAIE,EAAM,QAAQ;IACzB;IACA,MAAM,GAAwB,GAAmC;KAC/D,IAAIO,IAAY;KAChB,IAAI;MACF,IAAIC,MAAW,UAEb;WADA,IAAYC,EAAaV,GAASC,CAAK,GACnCO,GAAW;QACb,IAAMG,IAAQX,EAAQ,IAAI,SAAS,KAAK,CAACA,EAAQ,KAAK,gBAAgB,SAAS;QAC/E,EAAgBA,EAAQ,OAAO;SAAE,MAAM;SAAU,OAAOC,EAAM;SAAO;QAAM,GAAGH,CAAO;OACvF;aACK,EAAkBE,EAAQ,WAAWA,EAAQ,UAAU;KAChE,UAAU;MACR,EAAa;OAAE;OAAM,UAAUC,EAAM;OAAU,WAAWD,EAAQ;OAAW,KAAKA,EAAQ;OAAY,WAAWA,EAAQ;MAAU,GAAGQ,CAAS;KACjJ;IACF;IACA,kBAAkBP,EAAM,SAAS,KAAK;IACtC,cAAc,MAAeA,EAAM,SAAS,IAAIW,CAAY,KAAK;GACnE;EACF;CACF;CACA,eAAe;AACjB,GAAGC,CAAc"}
@@ -60,6 +60,6 @@ function l(e, t, n) {
60
60
  };
61
61
  }
62
62
  //#endregion
63
- export { l as nextFrame, o as syncGestureCurrent, a as turnedWorlds };
63
+ export { l as nextFrame, c as storedPreviews, o as syncGestureCurrent, a as turnedWorlds };
64
64
 
65
65
  //# sourceMappingURL=frame.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"frame.js","names":["turnPose","rotated","d","origin","delta","pivot","cos","sin","ox","oy","nx","ny","translatePoseViaDescriptor","turnedWorlds","out","turn","id","syncGestureCurrent","turned","pose","shapeDelta","moveCtx","pointerStateOf","readers","primary","originRotation","raw","proposed","gctx","b","behaviors","r","rotation","storedPreviews","previews","session","layer","own","planeOf","carryPose","nextFrame"],"sources":["../../../../src/interactions/actions/rotate/frame.ts"],"sourcesContent":["import type { InvocationCtx } from '@weasel-js/routing';\nimport { pointerStateOf } from '../pointerState';\nimport type { NodeId } from 'core/scene/types';\nimport type { GestureReaders } from '../../gestures/shared/screenTolerance';\nimport type { GestureContext, RotateBehavior, RotateProposed } from '../../gestures/types';\nimport { carryPose, planeOf } from '../planeInput';\nimport { translatePoseViaDescriptor, type PoseDescriptor } from '../resize/geometry';\nimport type { RotateFrame, RotateSession, Turn, TurnOrigin } from './session';\n\n/** `origin` turned by `delta` radians, its center orbiting `pivot` when one\n * is given. */\nfunction turnPose(\n d: PoseDescriptor<unknown>,\n origin: TurnOrigin,\n delta: number,\n pivot: { x: number; y: number } | null,\n): unknown {\n const rotated = d.withRotation!(origin.world, origin.rotation + delta);\n if (!pivot) return rotated;\n const cos = Math.cos(delta);\n const sin = Math.sin(delta);\n const ox = origin.center.x - pivot.x;\n const oy = origin.center.y - pivot.y;\n const nx = pivot.x + ox * cos - oy * sin;\n const ny = pivot.y + ox * sin + oy * cos;\n return translatePoseViaDescriptor(rotated, nx - origin.center.x, ny - origin.center.y, d);\n}\n\n/** Each rotated node's world pose turned by `delta`. */\nexport function turnedWorlds(turn: Turn, delta: number): Map<NodeId, unknown> {\n const out = new Map<NodeId, unknown>();\n const pivot = turn.useUnionPivot ? turn.pivot : null;\n for (const [id, origin] of turn.origins) {\n out.set(id, turnPose(turn.descriptorOf(id), origin, delta, pivot));\n }\n return out;\n}\n\n/** Write the poses a turn by `delta` gives into `gctx.current`. */\nexport function syncGestureCurrent(\n gctx: GestureContext<unknown>,\n turn: Turn,\n delta: number,\n): Map<NodeId, unknown> {\n const turned = turnedWorlds(turn, delta);\n for (const [id, pose] of turned) gctx.current.set(id as string, pose);\n return turned;\n}\n\n/** The pointer's delta as the behaviors reshape it. */\nfunction shapeDelta(\n turn: Turn,\n behaviors: readonly RotateBehavior<unknown>[],\n gctx: GestureContext<unknown>,\n readers: GestureReaders,\n moveCtx: InvocationCtx,\n raw: number,\n): number {\n gctx.modifiers = { ...moveCtx.modifiers };\n gctx.pointer = pointerStateOf(moveCtx.world, moveCtx);\n gctx.view = readers.view();\n gctx.plane = readers.plane();\n const primary = turn.origins.keys().next().value as NodeId;\n const originRotation = turn.origins.get(primary)?.rotation ?? 0;\n let delta = raw;\n let proposed: RotateProposed<unknown> = {\n pose: syncGestureCurrent(gctx, turn, raw).get(primary),\n rotation: originRotation + raw,\n };\n for (const b of behaviors) {\n const r = b.onMove?.(gctx, proposed);\n if (!r) continue;\n if (r.rotation !== undefined) {\n delta = r.rotation - originRotation;\n proposed = { pose: syncGestureCurrent(gctx, turn, delta).get(primary), rotation: r.rotation };\n continue;\n }\n if (r.pose === undefined) continue;\n const rotation = turn.descriptorOf(primary).getRotation?.(r.pose) ?? 0;\n delta = rotation - originRotation;\n proposed = { pose: r.pose, rotation };\n }\n return delta;\n}\n\n/** Every rotated id's stored pose under a turn by `delta`; none at zero. */\nfunction storedPreviews(\n session: Pick<RotateSession, 'scene' | 'turn' | 'poseFrame' | 'view'>,\n delta: number,\n): Map<NodeId, unknown> {\n const previews = new Map<NodeId, unknown>();\n if (delta === 0) return previews;\n for (const [id, turned] of turnedWorlds(session.turn, delta)) {\n const layer = session.scene.get(id)?.layer;\n const own = layer === undefined ? null : planeOf(session.view, layer);\n previews.set(id, session.poseFrame.local(id, carryPose(session.turn.descriptorOf(id), turned, own)));\n }\n return previews;\n}\n\n/** One move's delta and previews: the pointer's angle since press as the\n * behaviors shaped it, and every rotated id's stored pose under it. */\nexport function nextFrame(session: RotateSession, readers: GestureReaders, moveCtx: InvocationCtx): RotateFrame {\n const { pivot } = session.turn;\n const pointerAngle = Math.atan2(moveCtx.world.y - pivot.y, moveCtx.world.x - pivot.x);\n const raw = pointerAngle - session.startPointerAngle;\n const delta = session.behaviors.length > 0\n ? shapeDelta(session.turn, session.behaviors, session.gestureCtx, readers, moveCtx, raw)\n : raw;\n return { delta, previews: storedPreviews(session, delta) };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"frame.js","names":["turnPose","rotated","d","origin","delta","pivot","cos","sin","ox","oy","nx","ny","translatePoseViaDescriptor","turnedWorlds","out","turn","id","syncGestureCurrent","turned","pose","shapeDelta","moveCtx","pointerStateOf","readers","primary","originRotation","raw","proposed","gctx","b","behaviors","r","rotation","storedPreviews","previews","session","layer","own","planeOf","carryPose","nextFrame"],"sources":["../../../../src/interactions/actions/rotate/frame.ts"],"sourcesContent":["import type { InvocationCtx } from '@weasel-js/routing';\nimport { pointerStateOf } from '../pointerState';\nimport type { NodeId } from 'core/scene/types';\nimport type { GestureReaders } from '../../gestures/shared/screenTolerance';\nimport type { GestureContext, RotateBehavior, RotateProposed } from '../../gestures/types';\nimport { carryPose, planeOf } from '../planeInput';\nimport { translatePoseViaDescriptor, type PoseDescriptor } from '../resize/geometry';\nimport type { RotateFrame, RotateSession, Turn, TurnOrigin } from './session';\n\n/** `origin` turned by `delta` radians, its center orbiting `pivot` when one\n * is given. */\nfunction turnPose(\n d: PoseDescriptor<unknown>,\n origin: TurnOrigin,\n delta: number,\n pivot: { x: number; y: number } | null,\n): unknown {\n const rotated = d.withRotation!(origin.world, origin.rotation + delta);\n if (!pivot) return rotated;\n const cos = Math.cos(delta);\n const sin = Math.sin(delta);\n const ox = origin.center.x - pivot.x;\n const oy = origin.center.y - pivot.y;\n const nx = pivot.x + ox * cos - oy * sin;\n const ny = pivot.y + ox * sin + oy * cos;\n return translatePoseViaDescriptor(rotated, nx - origin.center.x, ny - origin.center.y, d);\n}\n\n/** Each rotated node's world pose turned by `delta`. */\nexport function turnedWorlds(turn: Turn, delta: number): Map<NodeId, unknown> {\n const out = new Map<NodeId, unknown>();\n const pivot = turn.useUnionPivot ? turn.pivot : null;\n for (const [id, origin] of turn.origins) {\n out.set(id, turnPose(turn.descriptorOf(id), origin, delta, pivot));\n }\n return out;\n}\n\n/** Write the poses a turn by `delta` gives into `gctx.current`. */\nexport function syncGestureCurrent(\n gctx: GestureContext<unknown>,\n turn: Turn,\n delta: number,\n): Map<NodeId, unknown> {\n const turned = turnedWorlds(turn, delta);\n for (const [id, pose] of turned) gctx.current.set(id as string, pose);\n return turned;\n}\n\n/** The pointer's delta as the behaviors reshape it. */\nfunction shapeDelta(\n turn: Turn,\n behaviors: readonly RotateBehavior<unknown>[],\n gctx: GestureContext<unknown>,\n readers: GestureReaders,\n moveCtx: InvocationCtx,\n raw: number,\n): number {\n gctx.modifiers = { ...moveCtx.modifiers };\n gctx.pointer = pointerStateOf(moveCtx.world, moveCtx);\n gctx.view = readers.view();\n gctx.plane = readers.plane();\n const primary = turn.origins.keys().next().value as NodeId;\n const originRotation = turn.origins.get(primary)?.rotation ?? 0;\n let delta = raw;\n let proposed: RotateProposed<unknown> = {\n pose: syncGestureCurrent(gctx, turn, raw).get(primary),\n rotation: originRotation + raw,\n };\n for (const b of behaviors) {\n const r = b.onMove?.(gctx, proposed);\n if (!r) continue;\n if (r.rotation !== undefined) {\n delta = r.rotation - originRotation;\n proposed = { pose: syncGestureCurrent(gctx, turn, delta).get(primary), rotation: r.rotation };\n continue;\n }\n if (r.pose === undefined) continue;\n const rotation = turn.descriptorOf(primary).getRotation?.(r.pose) ?? 0;\n delta = rotation - originRotation;\n proposed = { pose: r.pose, rotation };\n }\n return delta;\n}\n\n/** Every rotated id's stored pose under a turn by `delta`; none at zero. */\nexport function storedPreviews(\n session: Pick<RotateSession, 'scene' | 'turn' | 'poseFrame' | 'view'>,\n delta: number,\n): Map<NodeId, unknown> {\n const previews = new Map<NodeId, unknown>();\n if (delta === 0) return previews;\n for (const [id, turned] of turnedWorlds(session.turn, delta)) {\n const layer = session.scene.get(id)?.layer;\n const own = layer === undefined ? null : planeOf(session.view, layer);\n previews.set(id, session.poseFrame.local(id, carryPose(session.turn.descriptorOf(id), turned, own)));\n }\n return previews;\n}\n\n/** One move's delta and previews: the pointer's angle since press as the\n * behaviors shaped it, and every rotated id's stored pose under it. */\nexport function nextFrame(session: RotateSession, readers: GestureReaders, moveCtx: InvocationCtx): RotateFrame {\n const { pivot } = session.turn;\n const pointerAngle = Math.atan2(moveCtx.world.y - pivot.y, moveCtx.world.x - pivot.x);\n const raw = pointerAngle - session.startPointerAngle;\n const delta = session.behaviors.length > 0\n ? shapeDelta(session.turn, session.behaviors, session.gestureCtx, readers, moveCtx, raw)\n : raw;\n return { delta, previews: storedPreviews(session, delta) };\n}\n"],"mappings":"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"}