@weasel-js/core 1.9.3 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1139) hide show
  1. package/CHANGELOG.md +1106 -0
  2. package/README.md +7 -5
  3. package/dist/WeaselProvider.js +5 -7
  4. package/dist/WeaselProvider.js.map +1 -1
  5. package/dist/affordances/composeAffordanceLayer.js +91 -93
  6. package/dist/affordances/composeAffordanceLayer.js.map +1 -1
  7. package/dist/affordances/cornerResize.js +27 -18
  8. package/dist/affordances/cornerResize.js.map +1 -1
  9. package/dist/affordances/hitAffordanceRegions.js +65 -104
  10. package/dist/affordances/hitAffordanceRegions.js.map +1 -1
  11. package/dist/affordances/pathAnchors.js.map +1 -1
  12. package/dist/affordances/rotationHandle.js +22 -21
  13. package/dist/affordances/rotationHandle.js.map +1 -1
  14. package/dist/animation/behaviors/coast.js +21 -0
  15. package/dist/animation/behaviors/coast.js.map +1 -0
  16. package/dist/animation/behaviors/coastByWrite.js +107 -0
  17. package/dist/animation/behaviors/coastByWrite.js.map +1 -0
  18. package/dist/animation/behaviors/coastOnTargets.js +94 -0
  19. package/dist/animation/behaviors/coastOnTargets.js.map +1 -0
  20. package/dist/animation/behaviors/momentum.js +38 -88
  21. package/dist/animation/behaviors/momentum.js.map +1 -1
  22. package/dist/animation/clipTargets.js +12 -0
  23. package/dist/animation/clipTargets.js.map +1 -0
  24. package/dist/animation/index.js +15 -20
  25. package/dist/animation/poseHelpers.js +112 -33
  26. package/dist/animation/poseHelpers.js.map +1 -1
  27. package/dist/animation/poseTarget.js +115 -0
  28. package/dist/animation/poseTarget.js.map +1 -0
  29. package/dist/animation/reflow.js +113 -83
  30. package/dist/animation/reflow.js.map +1 -1
  31. package/dist/animation/rewind.js +66 -0
  32. package/dist/animation/rewind.js.map +1 -0
  33. package/dist/animation/rig/bindRig.js +85 -53
  34. package/dist/animation/rig/bindRig.js.map +1 -1
  35. package/dist/animation/rig/rigNode.js +93 -0
  36. package/dist/animation/rig/rigNode.js.map +1 -0
  37. package/dist/animation/rig/rigSeat.js +26 -0
  38. package/dist/animation/rig/rigSeat.js.map +1 -0
  39. package/dist/animation/rig/skinBinding.js +56 -0
  40. package/dist/animation/rig/skinBinding.js.map +1 -0
  41. package/dist/animation/rig/useRig.js +31 -16
  42. package/dist/animation/rig/useRig.js.map +1 -1
  43. package/dist/animation/wrappers/animateLifecycle.js +32 -24
  44. package/dist/animation/wrappers/animateLifecycle.js.map +1 -1
  45. package/dist/animation/wrappers/animateOnSetPose.js +31 -29
  46. package/dist/animation/wrappers/animateOnSetPose.js.map +1 -1
  47. package/dist/animation/wrappers/instantPose.js +13 -0
  48. package/dist/animation/wrappers/instantPose.js.map +1 -0
  49. package/dist/animation/writtenPoseTarget.js +33 -0
  50. package/dist/animation/writtenPoseTarget.js.map +1 -0
  51. package/dist/{autoPoseDescriptor-vCdt55xm.d.ts → autoPoseDescriptor-DHg5KqaJ.d.ts} +1 -1
  52. package/dist/barrel/canvas.js +31 -0
  53. package/dist/barrel/chrome.js +16 -0
  54. package/dist/barrel/input.js +18 -0
  55. package/dist/barrel/interactions.js +38 -0
  56. package/dist/barrel/paint.js +11 -0
  57. package/dist/barrel/paths.js +12 -0
  58. package/dist/barrel/renderer.js +14 -0
  59. package/dist/barrel/routing.js +57 -0
  60. package/dist/barrel/scene.js +37 -0
  61. package/dist/barrel/text.js +9 -0
  62. package/dist/barrel/viewport.js +42 -0
  63. package/dist/canvas/Canvas.js +280 -559
  64. package/dist/canvas/Canvas.js.map +1 -1
  65. package/dist/canvas/CanvasView.js +147 -167
  66. package/dist/canvas/CanvasView.js.map +1 -1
  67. package/dist/canvas/CursorCoordsHud.js +53 -49
  68. package/dist/canvas/CursorCoordsHud.js.map +1 -1
  69. package/dist/canvas/DrawCanvas.js +40 -51
  70. package/dist/canvas/DrawCanvas.js.map +1 -1
  71. package/dist/canvas/ModalityHud.js.map +1 -1
  72. package/dist/canvas/NodeShape.js +55 -374
  73. package/dist/canvas/NodeShape.js.map +1 -1
  74. package/dist/canvas/PickHud.js +50 -47
  75. package/dist/canvas/PickHud.js.map +1 -1
  76. package/dist/canvas/SceneCanvas/DevHuds.js +40 -0
  77. package/dist/canvas/SceneCanvas/DevHuds.js.map +1 -0
  78. package/dist/canvas/SceneCanvas/GestureDispatcherMounter.js +126 -0
  79. package/dist/canvas/SceneCanvas/GestureDispatcherMounter.js.map +1 -0
  80. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +27 -31
  81. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js.map +1 -1
  82. package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js +64 -0
  83. package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js.map +1 -0
  84. package/dist/canvas/SceneCanvas/ToolKeybindingsMounter.js +16 -0
  85. package/dist/canvas/SceneCanvas/ToolKeybindingsMounter.js.map +1 -0
  86. package/dist/canvas/SceneCanvas/coordTrace.js +46 -0
  87. package/dist/canvas/SceneCanvas/coordTrace.js.map +1 -0
  88. package/dist/canvas/SceneCanvas/defaultNodeProperties.js +138 -85
  89. package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
  90. package/dist/canvas/SceneCanvas/defaultNodeRouting.js +9 -8
  91. package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
  92. package/dist/canvas/SceneCanvas/dispatcherGestureBounds.js.map +1 -1
  93. package/dist/canvas/SceneCanvas/features.js +74 -43
  94. package/dist/canvas/SceneCanvas/features.js.map +1 -1
  95. package/dist/canvas/SceneCanvas/isDev.js +12 -0
  96. package/dist/canvas/SceneCanvas/isDev.js.map +1 -0
  97. package/dist/canvas/SceneCanvas/poseGeometry.js +31 -34
  98. package/dist/canvas/SceneCanvas/poseGeometry.js.map +1 -1
  99. package/dist/canvas/SceneCanvas/poseRegistrars.js +13 -0
  100. package/dist/canvas/SceneCanvas/poseRegistrars.js.map +1 -0
  101. package/dist/canvas/SceneCanvas/props.js +39 -0
  102. package/dist/canvas/SceneCanvas/props.js.map +1 -0
  103. package/dist/canvas/SceneCanvas/toolRegistry.js +23 -0
  104. package/dist/canvas/SceneCanvas/toolRegistry.js.map +1 -0
  105. package/dist/canvas/SceneCanvas/useActionsPropResolver.js +6 -1
  106. package/dist/canvas/SceneCanvas/useActionsPropResolver.js.map +1 -1
  107. package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js +21 -62
  108. package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js.map +1 -1
  109. package/dist/canvas/SceneCanvas/useBuiltinTools.js +21 -0
  110. package/dist/canvas/SceneCanvas/useBuiltinTools.js.map +1 -0
  111. package/dist/canvas/SceneCanvas/useCanvasCamera.js +38 -0
  112. package/dist/canvas/SceneCanvas/useCanvasCamera.js.map +1 -0
  113. package/dist/canvas/SceneCanvas/useCanvasDispatcher.js +20 -0
  114. package/dist/canvas/SceneCanvas/useCanvasDispatcher.js.map +1 -0
  115. package/dist/canvas/SceneCanvas/useCanvasSelection.js +16 -0
  116. package/dist/canvas/SceneCanvas/useCanvasSelection.js.map +1 -0
  117. package/dist/canvas/SceneCanvas/useCanvasTools.js +67 -0
  118. package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -0
  119. package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js +29 -29
  120. package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js.map +1 -1
  121. package/dist/canvas/SceneCanvas/useHeldModifiers.js +20 -0
  122. package/dist/canvas/SceneCanvas/useHeldModifiers.js.map +1 -0
  123. package/dist/canvas/SceneCanvas/useNodeAtPoint.js +26 -0
  124. package/dist/canvas/SceneCanvas/useNodeAtPoint.js.map +1 -0
  125. package/dist/canvas/SceneCanvas/useNodeKinds.js +26 -0
  126. package/dist/canvas/SceneCanvas/useNodeKinds.js.map +1 -0
  127. package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js +48 -48
  128. package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js.map +1 -1
  129. package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js +47 -0
  130. package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js.map +1 -0
  131. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +66 -0
  132. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -0
  133. package/dist/canvas/SceneCanvas/useSceneChrome.js +59 -0
  134. package/dist/canvas/SceneCanvas/useSceneChrome.js.map +1 -0
  135. package/dist/canvas/SceneCanvas/useSceneRedrawSources.js +23 -0
  136. package/dist/canvas/SceneCanvas/useSceneRedrawSources.js.map +1 -0
  137. package/dist/canvas/SceneCanvas/useSceneSelectTool.js +74 -78
  138. package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
  139. package/dist/canvas/SceneCanvas/useSceneSlotLayers.js +37 -0
  140. package/dist/canvas/SceneCanvas/useSceneSlotLayers.js.map +1 -0
  141. package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js +38 -0
  142. package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js.map +1 -0
  143. package/dist/canvas/SceneCanvas/useViewLayerGate.js +20 -0
  144. package/dist/canvas/SceneCanvas/useViewLayerGate.js.map +1 -0
  145. package/dist/canvas/SceneCanvas/useViewportActions.js +9 -1
  146. package/dist/canvas/SceneCanvas/useViewportActions.js.map +1 -1
  147. package/dist/canvas/SceneCanvas/worldPointAt.js +9 -0
  148. package/dist/canvas/SceneCanvas/worldPointAt.js.map +1 -0
  149. package/dist/canvas/SceneCanvas.js +311 -969
  150. package/dist/canvas/SceneCanvas.js.map +1 -1
  151. package/dist/canvas/SceneViewCanvas.js +42 -46
  152. package/dist/canvas/SceneViewCanvas.js.map +1 -1
  153. package/dist/canvas/adapterDerivedPath.js +26 -0
  154. package/dist/canvas/adapterDerivedPath.js.map +1 -0
  155. package/dist/canvas/affordanceAt.js +11 -1
  156. package/dist/canvas/affordanceAt.js.map +1 -1
  157. package/dist/canvas/buildSceneLayer.js +111 -0
  158. package/dist/canvas/buildSceneLayer.js.map +1 -0
  159. package/dist/canvas/buildSceneTree.js +16 -19
  160. package/dist/canvas/buildSceneTree.js.map +1 -1
  161. package/dist/canvas/canvasRenderer.js +67 -55
  162. package/dist/canvas/canvasRenderer.js.map +1 -1
  163. package/dist/canvas/colorOverrides.js.map +1 -1
  164. package/dist/canvas/defaultDrawOne.js +12 -12
  165. package/dist/canvas/defaultDrawOne.js.map +1 -1
  166. package/dist/canvas/deps/areaSelect.js +4 -4
  167. package/dist/canvas/deps/areaSelect.js.map +1 -1
  168. package/dist/canvas/deps/changes.js +13 -0
  169. package/dist/canvas/deps/changes.js.map +1 -0
  170. package/dist/canvas/deps/debug.js.map +1 -1
  171. package/dist/canvas/deps/editAnchors.js +38 -57
  172. package/dist/canvas/deps/editAnchors.js.map +1 -1
  173. package/dist/canvas/deps/geometryProjection.js.map +1 -1
  174. package/dist/canvas/deps/hitTestArea.js +31 -26
  175. package/dist/canvas/deps/hitTestArea.js.map +1 -1
  176. package/dist/canvas/deps/insert.js +130 -91
  177. package/dist/canvas/deps/insert.js.map +1 -1
  178. package/dist/canvas/deps/lassoSelect.js +5 -5
  179. package/dist/canvas/deps/lassoSelect.js.map +1 -1
  180. package/dist/canvas/deps/poseDescriptor.js +1 -1
  181. package/dist/canvas/deps/poseDescriptor.js.map +1 -1
  182. package/dist/canvas/deps/resizePolicy.js.map +1 -1
  183. package/dist/canvas/deps/slice.js +26 -26
  184. package/dist/canvas/deps/slice.js.map +1 -1
  185. package/dist/canvas/deps/textEdit.js +6 -5
  186. package/dist/canvas/deps/textEdit.js.map +1 -1
  187. package/dist/canvas/deps/view.js.map +1 -1
  188. package/dist/canvas/derivedPath.js +47 -22
  189. package/dist/canvas/derivedPath.js.map +1 -1
  190. package/dist/canvas/drawEnvelope.js +8 -4
  191. package/dist/canvas/drawEnvelope.js.map +1 -1
  192. package/dist/canvas/getNodeAtPoint.js +4 -8
  193. package/dist/canvas/getNodeAtPoint.js.map +1 -1
  194. package/dist/canvas/hud.module.js +1 -1
  195. package/dist/canvas/hud.module.js.map +1 -1
  196. package/dist/canvas/insertPreviewExtent.js.map +1 -1
  197. package/dist/canvas/kitRequirements.js +2 -2
  198. package/dist/canvas/kitRequirements.js.map +1 -1
  199. package/dist/canvas/layerOrder.js +13 -6
  200. package/dist/canvas/layerOrder.js.map +1 -1
  201. package/dist/canvas/layerSlots.js +6 -1
  202. package/dist/canvas/layerSlots.js.map +1 -1
  203. package/dist/canvas/nodeShapes/derivedPainter.js +34 -0
  204. package/dist/canvas/nodeShapes/derivedPainter.js.map +1 -0
  205. package/dist/canvas/nodeShapes/imagePainter.js +87 -0
  206. package/dist/canvas/nodeShapes/imagePainter.js.map +1 -0
  207. package/dist/canvas/nodeShapes/memo.js +9 -0
  208. package/dist/canvas/nodeShapes/memo.js.map +1 -0
  209. package/dist/canvas/nodeShapes/nodePaint.js +68 -0
  210. package/dist/canvas/nodeShapes/nodePaint.js.map +1 -0
  211. package/dist/canvas/nodeShapes/pathPainter.js +39 -0
  212. package/dist/canvas/nodeShapes/pathPainter.js.map +1 -0
  213. package/dist/canvas/nodeShapes/poseBox.js +20 -0
  214. package/dist/canvas/nodeShapes/poseBox.js.map +1 -0
  215. package/dist/canvas/nodeShapes/rectFallbackPainter.js +38 -0
  216. package/dist/canvas/nodeShapes/rectFallbackPainter.js.map +1 -0
  217. package/dist/canvas/nodeShapes/shapePainter.js +72 -0
  218. package/dist/canvas/nodeShapes/shapePainter.js.map +1 -0
  219. package/dist/canvas/nodeShapes/textPainter.js +55 -0
  220. package/dist/canvas/nodeShapes/textPainter.js.map +1 -0
  221. package/dist/canvas/overlayRoleStrokes.js.map +1 -1
  222. package/dist/canvas/paintCull.js +11 -14
  223. package/dist/canvas/paintCull.js.map +1 -1
  224. package/dist/{features/cursor → canvas}/paintedCursorLayer.js +2 -2
  225. package/dist/canvas/paintedCursorLayer.js.map +1 -0
  226. package/dist/canvas/pickWalk.js +59 -68
  227. package/dist/canvas/pickWalk.js.map +1 -1
  228. package/dist/canvas/planeClips.js +18 -19
  229. package/dist/canvas/planeClips.js.map +1 -1
  230. package/dist/canvas/poseCascade.js +41 -0
  231. package/dist/canvas/poseCascade.js.map +1 -0
  232. package/dist/canvas/poseRotation.js +9 -23
  233. package/dist/canvas/poseRotation.js.map +1 -1
  234. package/dist/canvas/rasterReadback.js +22 -0
  235. package/dist/canvas/rasterReadback.js.map +1 -0
  236. package/dist/canvas/renderDebugSnapshot.js +11 -11
  237. package/dist/canvas/renderDebugSnapshot.js.map +1 -1
  238. package/dist/canvas/renderNeeds.js +3 -3
  239. package/dist/canvas/renderNeeds.js.map +1 -1
  240. package/dist/canvas/renderSceneToPixels.js +64 -81
  241. package/dist/canvas/renderSceneToPixels.js.map +1 -1
  242. package/dist/canvas/sceneAdapter.js +68 -214
  243. package/dist/canvas/sceneAdapter.js.map +1 -1
  244. package/dist/canvas/sceneClipboard.js +112 -0
  245. package/dist/canvas/sceneClipboard.js.map +1 -0
  246. package/dist/canvas/sceneLayerPaint.js +4 -4
  247. package/dist/canvas/sceneLayerPaint.js.map +1 -1
  248. package/dist/canvas/sceneSlotWiring.js.map +1 -1
  249. package/dist/canvas/sceneViewRender.js +39 -39
  250. package/dist/canvas/sceneViewRender.js.map +1 -1
  251. package/dist/canvas/slopsDebugLayer.js +4 -4
  252. package/dist/canvas/slopsDebugLayer.js.map +1 -1
  253. package/dist/canvas/surface.module.js +6 -0
  254. package/dist/canvas/surface.module.js.map +1 -0
  255. package/dist/canvas/surfaceBox.js +16 -0
  256. package/dist/canvas/surfaceBox.js.map +1 -0
  257. package/dist/canvas/useCanvasRenderer.js +26 -6
  258. package/dist/canvas/useCanvasRenderer.js.map +1 -1
  259. package/dist/canvas/useCanvasSurface.js +31 -0
  260. package/dist/canvas/useCanvasSurface.js.map +1 -0
  261. package/dist/canvas/useCanvasView.js +67 -0
  262. package/dist/canvas/useCanvasView.js.map +1 -0
  263. package/dist/canvas/useFrameLoop.js +39 -31
  264. package/dist/canvas/useFrameLoop.js.map +1 -1
  265. package/dist/canvas/useHostAnchor.js +35 -33
  266. package/dist/canvas/useHostAnchor.js.map +1 -1
  267. package/dist/canvas/useLateContentRedraw.js +8 -8
  268. package/dist/canvas/useLateContentRedraw.js.map +1 -1
  269. package/dist/canvas/useSceneLayerList.js +11 -0
  270. package/dist/canvas/useSceneLayerList.js.map +1 -0
  271. package/dist/canvas/useSurfaceInput.js +42 -0
  272. package/dist/canvas/useSurfaceInput.js.map +1 -0
  273. package/dist/canvas/useToolCursor.js +29 -0
  274. package/dist/canvas/useToolCursor.js.map +1 -0
  275. package/dist/canvas/useViewHelpers.js +46 -85
  276. package/dist/canvas/useViewHelpers.js.map +1 -1
  277. package/dist/canvas/viewInputs.js.map +1 -1
  278. package/dist/canvas/viewRegistry.js +25 -27
  279. package/dist/canvas/viewRegistry.js.map +1 -1
  280. package/dist/canvas/watchElementMove.js +43 -0
  281. package/dist/canvas/watchElementMove.js.map +1 -0
  282. package/dist/canvas/wrapNodeOutput.js.map +1 -1
  283. package/dist/clipboard.d.ts +16 -19
  284. package/dist/{types-B_9g6hMM.d.ts → clone-2a5hVbBd.d.ts} +123 -74
  285. package/dist/clone.d.ts +4 -7
  286. package/dist/clone.js +0 -2
  287. package/dist/core/device/index.js +5 -4
  288. package/dist/core/device/targets.js.map +1 -1
  289. package/dist/core/device/useDeviceProfile.js +38 -44
  290. package/dist/core/device/useDeviceProfile.js.map +1 -1
  291. package/dist/core/device/watchDevicePixelRatio.js +17 -0
  292. package/dist/core/device/watchDevicePixelRatio.js.map +1 -0
  293. package/dist/{interactions/actions/resize → core/geometry}/autoPoseDescriptor.js +8 -7
  294. package/dist/core/geometry/autoPoseDescriptor.js.map +1 -0
  295. package/dist/core/geometry/pathPoseDescriptor.js +88 -0
  296. package/dist/core/geometry/pathPoseDescriptor.js.map +1 -0
  297. package/dist/core/geometry/poseDescriptor.js +68 -19
  298. package/dist/core/geometry/poseDescriptor.js.map +1 -1
  299. package/dist/core/geometry/regionHit.js +31 -34
  300. package/dist/core/geometry/regionHit.js.map +1 -1
  301. package/dist/core/geometry/targetFrame.js +94 -0
  302. package/dist/core/geometry/targetFrame.js.map +1 -0
  303. package/dist/core/geometry/unionBounds.js +30 -29
  304. package/dist/core/geometry/unionBounds.js.map +1 -1
  305. package/dist/core/isPlainObject.js +2 -11
  306. package/dist/core/layers/backgroundFill.js +31 -0
  307. package/dist/core/layers/backgroundFill.js.map +1 -0
  308. package/dist/{features/groups → core/layers}/children.js +1 -1
  309. package/dist/core/layers/children.js.map +1 -0
  310. package/dist/core/layers/gateLayer.js +13 -0
  311. package/dist/core/layers/gateLayer.js.map +1 -0
  312. package/dist/core/layers/layerGroup.js +40 -0
  313. package/dist/core/layers/layerGroup.js.map +1 -0
  314. package/dist/core/layers/render.js +50 -76
  315. package/dist/core/layers/render.js.map +1 -1
  316. package/dist/core/ops/arrange.js +1 -0
  317. package/dist/core/ops/arrange.js.map +1 -1
  318. package/dist/core/ops/create.js +10 -5
  319. package/dist/core/ops/create.js.map +1 -1
  320. package/dist/core/ops/createHistory.js +9 -9
  321. package/dist/core/ops/createHistory.js.map +1 -1
  322. package/dist/core/ops/delete.js +12 -24
  323. package/dist/core/ops/delete.js.map +1 -1
  324. package/dist/core/ops/reorder/index.js +43 -40
  325. package/dist/core/ops/reorder/index.js.map +1 -1
  326. package/dist/core/ops/reorder/setChildOrder.js +34 -0
  327. package/dist/core/ops/reorder/setChildOrder.js.map +1 -0
  328. package/dist/core/paint/meshKind.js +16 -0
  329. package/dist/core/paint/meshKind.js.map +1 -0
  330. package/dist/{features/meshPaint/lazyKind.js → core/paint/meshKindLazy.js} +282 -105
  331. package/dist/core/paint/meshKindLazy.js.map +1 -0
  332. package/dist/core/paint/paintKindEntry.js +8 -0
  333. package/dist/core/paint/paintKindEntry.js.map +1 -0
  334. package/dist/core/paint/paintKinds.js +144 -0
  335. package/dist/core/paint/paintKinds.js.map +1 -0
  336. package/dist/core/paint/registerMesh.js +7 -0
  337. package/dist/core/paint/registerMesh.js.map +1 -0
  338. package/dist/core/scene/NodeProperties.js.map +1 -1
  339. package/dist/core/scene/NodeRouting.js.map +1 -1
  340. package/dist/core/scene/appliedLog.js +37 -0
  341. package/dist/core/scene/appliedLog.js.map +1 -0
  342. package/dist/core/scene/arrivalWindow.js +102 -0
  343. package/dist/core/scene/arrivalWindow.js.map +1 -0
  344. package/dist/core/scene/boundOps.js +40 -0
  345. package/dist/core/scene/boundOps.js.map +1 -0
  346. package/dist/core/scene/composeFrame.js +9 -6
  347. package/dist/core/scene/composeFrame.js.map +1 -1
  348. package/dist/{features/groups → core/scene}/composePose.js +18 -18
  349. package/dist/core/scene/composePose.js.map +1 -0
  350. package/dist/core/scene/depMemo.js +31 -6
  351. package/dist/core/scene/depMemo.js.map +1 -1
  352. package/dist/core/scene/derivedPath.js +19 -20
  353. package/dist/core/scene/derivedPath.js.map +1 -1
  354. package/dist/core/scene/editMode.js +26 -0
  355. package/dist/core/scene/editMode.js.map +1 -0
  356. package/dist/core/scene/effectivePose.js +38 -39
  357. package/dist/core/scene/effectivePose.js.map +1 -1
  358. package/dist/core/scene/fieldEdits.js +98 -0
  359. package/dist/core/scene/fieldEdits.js.map +1 -0
  360. package/dist/core/scene/historyFacade.js +130 -0
  361. package/dist/core/scene/historyFacade.js.map +1 -0
  362. package/dist/core/scene/historyForm.js +6 -0
  363. package/dist/core/scene/historyForm.js.map +1 -0
  364. package/dist/core/scene/kitOps.js +185 -0
  365. package/dist/core/scene/kitOps.js.map +1 -0
  366. package/dist/core/scene/kitRegistry.js.map +1 -1
  367. package/dist/core/scene/layerStack.js +131 -0
  368. package/dist/core/scene/layerStack.js.map +1 -0
  369. package/dist/core/scene/layoutPass.js +58 -59
  370. package/dist/core/scene/layoutPass.js.map +1 -1
  371. package/dist/core/scene/lockGuard.js +37 -0
  372. package/dist/core/scene/lockGuard.js.map +1 -0
  373. package/dist/{features/groups → core/scene}/nestedHit.js +3 -3
  374. package/dist/core/scene/nestedHit.js.map +1 -0
  375. package/dist/core/scene/nodeFnFields.js +10 -11
  376. package/dist/core/scene/nodeFnFields.js.map +1 -1
  377. package/dist/core/scene/nodeMemo.js +45 -19
  378. package/dist/core/scene/nodeMemo.js.map +1 -1
  379. package/dist/core/scene/nodeStore.js +127 -0
  380. package/dist/core/scene/nodeStore.js.map +1 -0
  381. package/dist/core/scene/notifier.js +37 -0
  382. package/dist/core/scene/notifier.js.map +1 -0
  383. package/dist/core/scene/opTable.js +50 -0
  384. package/dist/core/scene/opTable.js.map +1 -0
  385. package/dist/core/scene/outerOps.js +66 -0
  386. package/dist/core/scene/outerOps.js.map +1 -0
  387. package/dist/core/scene/poseFeed.js +38 -38
  388. package/dist/core/scene/poseFeed.js.map +1 -1
  389. package/dist/core/scene/poseHold.js +39 -0
  390. package/dist/core/scene/poseHold.js.map +1 -0
  391. package/dist/core/scene/poseOverrides.js +44 -40
  392. package/dist/core/scene/poseOverrides.js.map +1 -1
  393. package/dist/core/scene/poseSnapshot.js.map +1 -1
  394. package/dist/core/scene/reconcileSpecs.js +3 -2
  395. package/dist/core/scene/reconcileSpecs.js.map +1 -1
  396. package/dist/core/scene/recorder.js +86 -0
  397. package/dist/core/scene/recorder.js.map +1 -0
  398. package/dist/core/scene/renderOrder.js +84 -0
  399. package/dist/core/scene/renderOrder.js.map +1 -0
  400. package/dist/core/scene/scene.js +80 -1266
  401. package/dist/core/scene/scene.js.map +1 -1
  402. package/dist/core/scene/sceneEdits.js +58 -0
  403. package/dist/core/scene/sceneEdits.js.map +1 -0
  404. package/dist/core/scene/sceneMutators.js +49 -0
  405. package/dist/core/scene/sceneMutators.js.map +1 -0
  406. package/dist/core/scene/scenePoseAdapter.js +16 -0
  407. package/dist/core/scene/scenePoseAdapter.js.map +1 -0
  408. package/dist/core/scene/sceneRecording.js +90 -0
  409. package/dist/core/scene/sceneRecording.js.map +1 -0
  410. package/dist/core/scene/sceneSelection.js +28 -0
  411. package/dist/core/scene/sceneSelection.js.map +1 -0
  412. package/dist/core/scene/sceneState.js +49 -0
  413. package/dist/core/scene/sceneState.js.map +1 -0
  414. package/dist/core/scene/serialization.js +71 -0
  415. package/dist/core/scene/serialization.js.map +1 -0
  416. package/dist/core/scene/staleReplay.js +51 -0
  417. package/dist/core/scene/staleReplay.js.map +1 -0
  418. package/dist/core/scene/statedFields.js +9 -0
  419. package/dist/core/scene/statedFields.js.map +1 -0
  420. package/dist/core/scene/treeEdits.js +127 -0
  421. package/dist/core/scene/treeEdits.js.map +1 -0
  422. package/dist/core/scene/treeOrder.js +13 -0
  423. package/dist/core/scene/treeOrder.js.map +1 -0
  424. package/dist/core/scene/treeReads.js +26 -0
  425. package/dist/core/scene/treeReads.js.map +1 -0
  426. package/dist/core/scene/types.js.map +1 -1
  427. package/dist/{features/groups → core/scene}/unionOfChildren.js +3 -3
  428. package/dist/core/scene/unionOfChildren.js.map +1 -0
  429. package/dist/core/scene/unitScopes.js +13 -0
  430. package/dist/core/scene/unitScopes.js.map +1 -0
  431. package/dist/core/scene/useScene.js.map +1 -1
  432. package/dist/core/selection/readOnlySelection.js +32 -0
  433. package/dist/core/selection/readOnlySelection.js.map +1 -0
  434. package/dist/core/selection/usePublishSceneSelection.js +26 -0
  435. package/dist/core/selection/usePublishSceneSelection.js.map +1 -0
  436. package/dist/core/selection/useSelection.js +34 -25
  437. package/dist/core/selection/useSelection.js.map +1 -1
  438. package/dist/core/shapeKinds.js.map +1 -1
  439. package/dist/core/stylus/stylus.js.map +1 -1
  440. package/dist/core/stylus/usePointerStylus.js.map +1 -1
  441. package/dist/core/usePaintKinds.js +1 -1
  442. package/dist/core/usePaintKinds.js.map +1 -1
  443. package/dist/core/viewport/clientToWorld.js.map +1 -1
  444. package/dist/core/viewport/fitViewToBounds.js.map +1 -1
  445. package/dist/core/viewport/parallax.js.map +1 -1
  446. package/dist/core/viewport/screenSlop.js +11 -11
  447. package/dist/core/viewport/screenSlop.js.map +1 -1
  448. package/dist/core/viewport/useCanvasSize.js.map +1 -1
  449. package/dist/core/viewport/useDecayLoop.js +8 -8
  450. package/dist/core/viewport/useDecayLoop.js.map +1 -1
  451. package/dist/core/viewport/useNodeOverlayFrame.js +84 -0
  452. package/dist/core/viewport/useNodeOverlayFrame.js.map +1 -0
  453. package/dist/core/viewport/useViewAnimation.js +102 -43
  454. package/dist/core/viewport/useViewAnimation.js.map +1 -1
  455. package/dist/core/viewport/view.js +9 -9
  456. package/dist/core/viewport/view.js.map +1 -1
  457. package/dist/core/viewport/wheelHandler.js.map +1 -1
  458. package/dist/core/viewport/zoomBounds.js +10 -8
  459. package/dist/core/viewport/zoomBounds.js.map +1 -1
  460. package/dist/{cornerHandles-BCrDp_mH.d.ts → cornerHandles-BEshc4z3.d.ts} +11 -24
  461. package/dist/debug/createDebugOverlayLayer.js +97 -97
  462. package/dist/debug/createDebugOverlayLayer.js.map +1 -1
  463. package/dist/debug/createDebugSink.js.map +1 -1
  464. package/dist/debug/flag.js +2 -41
  465. package/dist/debug/frameStats.js.map +1 -1
  466. package/dist/debug/useDebugSink.js +52 -0
  467. package/dist/debug/useDebugSink.js.map +1 -0
  468. package/dist/features/chrome-caps/buildChromeCtx.js.map +1 -1
  469. package/dist/features/chrome-caps/conditions.js.map +1 -1
  470. package/dist/features/chrome-caps/defaults.js.map +1 -1
  471. package/dist/features/chrome-caps/resolve.js.map +1 -1
  472. package/dist/features/chrome-caps/useChromeCaps.js +54 -0
  473. package/dist/features/chrome-caps/useChromeCaps.js.map +1 -0
  474. package/dist/features/chrome-caps/useHoverTracking.js +22 -17
  475. package/dist/features/chrome-caps/useHoverTracking.js.map +1 -1
  476. package/dist/features/ingestion/contentHandlers.js +28 -19
  477. package/dist/features/ingestion/contentHandlers.js.map +1 -1
  478. package/dist/features/ingestion/imageHandler.js +21 -24
  479. package/dist/features/ingestion/imageHandler.js.map +1 -1
  480. package/dist/features/ingestion/openFilePicker.js.map +1 -1
  481. package/dist/features/ingestion/placement.js +16 -0
  482. package/dist/features/ingestion/placement.js.map +1 -0
  483. package/dist/features/ingestion/registerKitHandlers.js +7 -7
  484. package/dist/features/ingestion/svgHandler.js +5 -0
  485. package/dist/features/ingestion/svgHandler.js.map +1 -1
  486. package/dist/features/ingestion/textHandler.js +28 -0
  487. package/dist/features/ingestion/textHandler.js.map +1 -0
  488. package/dist/features/ingestion/useCanvasIngestion.js +48 -0
  489. package/dist/features/ingestion/useCanvasIngestion.js.map +1 -0
  490. package/dist/features/ingestion/weaselJsonHandler.js +22 -14
  491. package/dist/features/ingestion/weaselJsonHandler.js.map +1 -1
  492. package/dist/features/longPress/longPressFeedback.js.map +1 -1
  493. package/dist/features/modes/modeLayers.js +7 -7
  494. package/dist/features/modes/modeLayers.js.map +1 -1
  495. package/dist/features/paths/editablePath.js +47 -0
  496. package/dist/features/paths/editablePath.js.map +1 -0
  497. package/dist/features/paths/index.js +9 -14
  498. package/dist/features/paths/pathEditState.js +41 -0
  499. package/dist/features/paths/pathEditState.js.map +1 -0
  500. package/dist/features/paths/pathEditingOverlayLayer.js +36 -38
  501. package/dist/features/paths/pathEditingOverlayLayer.js.map +1 -1
  502. package/dist/features/paths/pathLayer.js +3 -2
  503. package/dist/features/paths/pathLayer.js.map +1 -1
  504. package/dist/features/paths/penPreviewLayer.js +86 -88
  505. package/dist/features/paths/penPreviewLayer.js.map +1 -1
  506. package/dist/features/paths/usePathEdit.js +34 -0
  507. package/dist/features/paths/usePathEdit.js.map +1 -0
  508. package/dist/features/poseRun/usePoseRun.js +44 -52
  509. package/dist/features/poseRun/usePoseRun.js.map +1 -1
  510. package/dist/features/selection/overlay.js +171 -179
  511. package/dist/features/selection/overlay.js.map +1 -1
  512. package/dist/features/text/index.js +6 -0
  513. package/dist/features/text/textLayer.js +1 -1
  514. package/dist/features/text/textLayer.js.map +1 -1
  515. package/dist/features/text/useSceneTextEdit.js +100 -93
  516. package/dist/features/text/useSceneTextEdit.js.map +1 -1
  517. package/dist/features/viewports/viewportLayer.js +25 -36
  518. package/dist/features/viewports/viewportLayer.js.map +1 -1
  519. package/dist/index.d.ts +8473 -9141
  520. package/dist/index.js +269 -307
  521. package/dist/input/keyState.js +38 -39
  522. package/dist/input/keyState.js.map +1 -1
  523. package/dist/input/useKeyModifiers.js +11 -0
  524. package/dist/input/useKeyModifiers.js.map +1 -0
  525. package/dist/interactions/actions/actionShortcuts.js.map +1 -1
  526. package/dist/interactions/actions/{defaults/align.js → align/action.js} +18 -20
  527. package/dist/interactions/actions/align/action.js.map +1 -0
  528. package/dist/interactions/actions/align/align.js +20 -20
  529. package/dist/interactions/actions/align/align.js.map +1 -1
  530. package/dist/interactions/actions/booleans/action.js +65 -0
  531. package/dist/interactions/actions/booleans/action.js.map +1 -0
  532. package/dist/interactions/actions/booleans/booleans.js +69 -78
  533. package/dist/interactions/actions/booleans/booleans.js.map +1 -1
  534. package/dist/interactions/actions/booleans/operands.js +40 -0
  535. package/dist/interactions/actions/booleans/operands.js.map +1 -0
  536. package/dist/interactions/actions/booleans/pieces.js +45 -0
  537. package/dist/interactions/actions/booleans/pieces.js.map +1 -0
  538. package/dist/interactions/actions/booleans/placement.js +24 -0
  539. package/dist/interactions/actions/booleans/placement.js.map +1 -0
  540. package/dist/interactions/actions/booleans/useBooleans.js +11 -9
  541. package/dist/interactions/actions/booleans/useBooleans.js.map +1 -1
  542. package/dist/interactions/actions/booleans/useBooleansAdapter.js.map +1 -1
  543. package/dist/interactions/actions/{defaults/clipboard.js → clipboard/action.js} +31 -15
  544. package/dist/interactions/actions/clipboard/action.js.map +1 -0
  545. package/dist/interactions/actions/clipboard/clipboardOps.js +44 -42
  546. package/dist/interactions/actions/clipboard/clipboardOps.js.map +1 -1
  547. package/dist/interactions/actions/clipboard/materializePaste.js +10 -7
  548. package/dist/interactions/actions/clipboard/materializePaste.js.map +1 -1
  549. package/dist/interactions/actions/clipboard/wireFormat.js.map +1 -1
  550. package/dist/interactions/actions/clone/action.js +98 -0
  551. package/dist/interactions/actions/clone/action.js.map +1 -0
  552. package/dist/interactions/actions/clone/behaviors.js +52 -0
  553. package/dist/interactions/actions/clone/behaviors.js.map +1 -0
  554. package/dist/interactions/actions/defaultCommitAdapter.js +7 -32
  555. package/dist/interactions/actions/defaultCommitAdapter.js.map +1 -1
  556. package/dist/interactions/actions/defaults/anchorEditing.js +60 -84
  557. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  558. package/dist/interactions/actions/defaults/areaSelect.js +35 -38
  559. package/dist/interactions/actions/defaults/areaSelect.js.map +1 -1
  560. package/dist/interactions/actions/defaults/cancelGesture.js.map +1 -1
  561. package/dist/interactions/actions/defaults/clearSelection.js.map +1 -1
  562. package/dist/interactions/actions/defaults/copySubtree.js +40 -0
  563. package/dist/interactions/actions/defaults/copySubtree.js.map +1 -0
  564. package/dist/interactions/actions/defaults/createPaintAction.js.map +1 -1
  565. package/dist/interactions/actions/defaults/delete.js.map +1 -1
  566. package/dist/interactions/actions/defaults/duplicate.js +13 -53
  567. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  568. package/dist/interactions/actions/defaults/enterTextEdit.js.map +1 -1
  569. package/dist/interactions/actions/defaults/group.js +40 -50
  570. package/dist/interactions/actions/defaults/group.js.map +1 -1
  571. package/dist/interactions/actions/defaults/icons/booleanIcons.js +24 -1
  572. package/dist/interactions/actions/defaults/icons/booleanIcons.js.map +1 -1
  573. package/dist/interactions/actions/defaults/icons/outlineIcons.js +39 -1
  574. package/dist/interactions/actions/defaults/icons/outlineIcons.js.map +1 -1
  575. package/dist/interactions/actions/defaults/ingest.js +44 -38
  576. package/dist/interactions/actions/defaults/ingest.js.map +1 -1
  577. package/dist/interactions/actions/defaults/insertPathAnchor.js +11 -12
  578. package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
  579. package/dist/interactions/actions/defaults/nudge.js +40 -69
  580. package/dist/interactions/actions/defaults/nudge.js.map +1 -1
  581. package/dist/interactions/actions/defaults/nudgeSteps.js +37 -0
  582. package/dist/interactions/actions/defaults/nudgeSteps.js.map +1 -0
  583. package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
  584. package/dist/interactions/actions/defaults/reorder.js +2 -0
  585. package/dist/interactions/actions/defaults/reorder.js.map +1 -1
  586. package/dist/interactions/actions/defaults/requiresSelection.js.map +1 -1
  587. package/dist/interactions/actions/defaults/setFill.js +14 -8
  588. package/dist/interactions/actions/defaults/setFill.js.map +1 -1
  589. package/dist/interactions/actions/defaults/setFillOpacity.js +7 -4
  590. package/dist/interactions/actions/defaults/setFillOpacity.js.map +1 -1
  591. package/dist/interactions/actions/defaults/setStroke.js +12 -12
  592. package/dist/interactions/actions/defaults/setStroke.js.map +1 -1
  593. package/dist/interactions/actions/defaults/setStrokeOpacity.js +6 -6
  594. package/dist/interactions/actions/defaults/sliceOps.js +8 -10
  595. package/dist/interactions/actions/defaults/sliceOps.js.map +1 -1
  596. package/dist/interactions/actions/defaults/toolActivate.js.map +1 -1
  597. package/dist/interactions/actions/defaults/toolResetToDefault.js.map +1 -1
  598. package/dist/interactions/actions/defaults/viewportDragPan.js +37 -26
  599. package/dist/interactions/actions/defaults/viewportDragPan.js.map +1 -1
  600. package/dist/interactions/actions/defaults/viewportWheelPan.js.map +1 -1
  601. package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
  602. package/dist/interactions/actions/distribute/action.js +66 -0
  603. package/dist/interactions/actions/distribute/action.js.map +1 -0
  604. package/dist/interactions/actions/distribute/distribute.js +11 -11
  605. package/dist/interactions/actions/distribute/distribute.js.map +1 -1
  606. package/dist/interactions/actions/{defaults/editAnchors.js → edit-anchors/action.js} +7 -9
  607. package/dist/interactions/actions/edit-anchors/action.js.map +1 -0
  608. package/dist/interactions/actions/edit-anchors/geometry.js +30 -27
  609. package/dist/interactions/actions/edit-anchors/geometry.js.map +1 -1
  610. package/dist/interactions/actions/flip/action.js +124 -0
  611. package/dist/interactions/actions/flip/action.js.map +1 -0
  612. package/dist/interactions/actions/flip/helpers.js +30 -17
  613. package/dist/interactions/actions/flip/helpers.js.map +1 -1
  614. package/dist/interactions/actions/gestureFrames.js +18 -0
  615. package/dist/interactions/actions/gestureFrames.js.map +1 -0
  616. package/dist/interactions/actions/gestureLifecycle.js +47 -20
  617. package/dist/interactions/actions/gestureLifecycle.js.map +1 -1
  618. package/dist/interactions/actions/hitSelection.js +8 -0
  619. package/dist/interactions/actions/hitSelection.js.map +1 -0
  620. package/dist/interactions/actions/insert/action.js +72 -0
  621. package/dist/interactions/actions/insert/action.js.map +1 -0
  622. package/dist/interactions/actions/insert/commit.js +28 -0
  623. package/dist/interactions/actions/insert/commit.js.map +1 -0
  624. package/dist/interactions/actions/insert/extras.js +65 -0
  625. package/dist/interactions/actions/insert/extras.js.map +1 -0
  626. package/dist/interactions/actions/insert/frame.js +48 -0
  627. package/dist/interactions/actions/insert/frame.js.map +1 -0
  628. package/dist/interactions/actions/insert/geometry.js +35 -0
  629. package/dist/interactions/actions/insert/geometry.js.map +1 -0
  630. package/dist/interactions/actions/insert/rotateAction.js +21 -0
  631. package/dist/interactions/actions/insert/rotateAction.js.map +1 -0
  632. package/dist/interactions/actions/insert/session.js +59 -0
  633. package/dist/interactions/actions/insert/session.js.map +1 -0
  634. package/dist/interactions/actions/insert/shape.js +34 -0
  635. package/dist/interactions/actions/insert/shape.js.map +1 -0
  636. package/dist/interactions/actions/lasso-select/action.js +143 -0
  637. package/dist/interactions/actions/lasso-select/action.js.map +1 -0
  638. package/dist/interactions/actions/lasso-select/behaviors/selectFromLasso.js +14 -18
  639. package/dist/interactions/actions/lasso-select/behaviors/selectFromLasso.js.map +1 -1
  640. package/dist/interactions/actions/move/action.js +87 -0
  641. package/dist/interactions/actions/move/action.js.map +1 -0
  642. package/dist/interactions/actions/move/behaviors/layoutDrop.js +51 -0
  643. package/dist/interactions/actions/move/behaviors/layoutDrop.js.map +1 -0
  644. package/dist/interactions/actions/move/behaviors/reparentOnDrop.js +15 -0
  645. package/dist/interactions/actions/move/behaviors/reparentOnDrop.js.map +1 -0
  646. package/dist/interactions/actions/move/behaviors/snapBackOrDelete.js +5 -5
  647. package/dist/interactions/actions/move/behaviors/snapBackOrDelete.js.map +1 -1
  648. package/dist/interactions/actions/move/behaviors/snapToContainer.js +39 -27
  649. package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
  650. package/dist/interactions/actions/move/capture.js +99 -0
  651. package/dist/interactions/actions/move/capture.js.map +1 -0
  652. package/dist/interactions/actions/move/commit/index.js +41 -0
  653. package/dist/interactions/actions/move/commit/index.js.map +1 -0
  654. package/dist/interactions/actions/move/commit/layoutDrop.js +44 -0
  655. package/dist/interactions/actions/move/commit/layoutDrop.js.map +1 -0
  656. package/dist/interactions/actions/move/commit/layoutRelease.js +100 -0
  657. package/dist/interactions/actions/move/commit/layoutRelease.js.map +1 -0
  658. package/dist/interactions/actions/move/commit/rebase.js +18 -0
  659. package/dist/interactions/actions/move/commit/rebase.js.map +1 -0
  660. package/dist/interactions/actions/move/commit/reparent.js +65 -0
  661. package/dist/interactions/actions/move/commit/reparent.js.map +1 -0
  662. package/dist/interactions/actions/move/delta.js +51 -0
  663. package/dist/interactions/actions/move/delta.js.map +1 -0
  664. package/dist/interactions/actions/move/frame.js +59 -0
  665. package/dist/interactions/actions/move/frame.js.map +1 -0
  666. package/dist/interactions/actions/move/gestureAdapter.js +22 -30
  667. package/dist/interactions/actions/move/gestureAdapter.js.map +1 -1
  668. package/dist/interactions/actions/move/landedDescendants.js +33 -0
  669. package/dist/interactions/actions/move/landedDescendants.js.map +1 -0
  670. package/dist/interactions/actions/move/layout/container.js +94 -0
  671. package/dist/interactions/actions/move/layout/container.js.map +1 -0
  672. package/dist/interactions/actions/move/layout/dragged.js +58 -0
  673. package/dist/interactions/actions/move/layout/dragged.js.map +1 -0
  674. package/dist/interactions/actions/move/layout/dropPass.js +122 -0
  675. package/dist/interactions/actions/move/layout/dropPass.js.map +1 -0
  676. package/dist/interactions/actions/move/layout/exits.js +38 -0
  677. package/dist/interactions/actions/move/layout/exits.js.map +1 -0
  678. package/dist/interactions/actions/move/layout/glide.js +48 -0
  679. package/dist/interactions/actions/move/layout/glide.js.map +1 -0
  680. package/dist/interactions/actions/move/session.js +63 -0
  681. package/dist/interactions/actions/move/session.js.map +1 -0
  682. package/dist/interactions/actions/move/translate.js +61 -0
  683. package/dist/interactions/actions/move/translate.js.map +1 -0
  684. package/dist/interactions/actions/outlines/createOutlines.js +16 -63
  685. package/dist/interactions/actions/outlines/createOutlines.js.map +1 -1
  686. package/dist/interactions/actions/outlines/createOutlinesAction.js +51 -0
  687. package/dist/interactions/actions/outlines/createOutlinesAction.js.map +1 -0
  688. package/dist/interactions/actions/outlines/outlineStroke.js +72 -0
  689. package/dist/interactions/actions/outlines/outlineStroke.js.map +1 -0
  690. package/dist/interactions/actions/outlines/outlineStrokeAction.js +37 -0
  691. package/dist/interactions/actions/outlines/outlineStrokeAction.js.map +1 -0
  692. package/dist/interactions/actions/outlines/replaceWithPaths.js +54 -0
  693. package/dist/interactions/actions/outlines/replaceWithPaths.js.map +1 -0
  694. package/dist/interactions/actions/outlines/strokeRegion.js +27 -0
  695. package/dist/interactions/actions/outlines/strokeRegion.js.map +1 -0
  696. package/dist/interactions/actions/planeInput.js.map +1 -1
  697. package/dist/interactions/actions/pointerState.js +12 -0
  698. package/dist/interactions/actions/pointerState.js.map +1 -0
  699. package/dist/interactions/actions/poseDescriptorDep.js +16 -4
  700. package/dist/interactions/actions/poseDescriptorDep.js.map +1 -1
  701. package/dist/interactions/actions/poseFrame.js +25 -20
  702. package/dist/interactions/actions/poseFrame.js.map +1 -1
  703. package/dist/interactions/actions/resize/action.js +55 -0
  704. package/dist/interactions/actions/resize/action.js.map +1 -0
  705. package/dist/interactions/actions/resize/behaviors/lockAspect.js.map +1 -1
  706. package/dist/interactions/actions/resize/boxFrame.js +16 -0
  707. package/dist/interactions/actions/resize/boxFrame.js.map +1 -0
  708. package/dist/interactions/actions/resize/capture.js +85 -0
  709. package/dist/interactions/actions/resize/capture.js.map +1 -0
  710. package/dist/interactions/actions/resize/commit.js +69 -0
  711. package/dist/interactions/actions/resize/commit.js.map +1 -0
  712. package/dist/interactions/actions/resize/frame.js +74 -0
  713. package/dist/interactions/actions/resize/frame.js.map +1 -0
  714. package/dist/interactions/actions/resize/pointSnap.js +111 -0
  715. package/dist/interactions/actions/resize/pointSnap.js.map +1 -0
  716. package/dist/interactions/actions/resize/ruleBounds.js +9 -0
  717. package/dist/interactions/actions/resize/ruleBounds.js.map +1 -0
  718. package/dist/interactions/actions/resize/session.js +49 -0
  719. package/dist/interactions/actions/resize/session.js.map +1 -0
  720. package/dist/interactions/actions/resolveOverlays.js.map +1 -1
  721. package/dist/interactions/actions/resolvePreviews.js.map +1 -1
  722. package/dist/interactions/actions/rotate/action.js +56 -0
  723. package/dist/interactions/actions/rotate/action.js.map +1 -0
  724. package/dist/interactions/actions/rotate/behaviors/index.js +7 -0
  725. package/dist/interactions/actions/rotate/behaviors/index.js.map +1 -0
  726. package/dist/interactions/actions/rotate/behaviors/snapRotation.js +12 -0
  727. package/dist/interactions/actions/rotate/behaviors/snapRotation.js.map +1 -0
  728. package/dist/interactions/actions/rotate/commit.js +40 -0
  729. package/dist/interactions/actions/rotate/commit.js.map +1 -0
  730. package/dist/interactions/actions/rotate/frame.js +65 -0
  731. package/dist/interactions/actions/rotate/frame.js.map +1 -0
  732. package/dist/interactions/actions/rotate/handle.js +12 -12
  733. package/dist/interactions/actions/rotate/handle.js.map +1 -1
  734. package/dist/interactions/actions/rotate/session.js +92 -0
  735. package/dist/interactions/actions/rotate/session.js.map +1 -0
  736. package/dist/interactions/actions/selectionSubtree.js +69 -0
  737. package/dist/interactions/actions/selectionSubtree.js.map +1 -0
  738. package/dist/interactions/actions/spatialReference.js.map +1 -1
  739. package/dist/interactions/actions/useStandardActions.js +87 -78
  740. package/dist/interactions/actions/useStandardActions.js.map +1 -1
  741. package/dist/interactions/gestures/dragGesture/dragGesture.js +4 -7
  742. package/dist/interactions/gestures/dragGesture/dragGesture.js.map +1 -1
  743. package/dist/interactions/gestures/dragGesture/dragPointOf.js +23 -0
  744. package/dist/interactions/gestures/dragGesture/dragPointOf.js.map +1 -0
  745. package/dist/interactions/gestures/handleDrag/handleDrag.js +21 -26
  746. package/dist/interactions/gestures/handleDrag/handleDrag.js.map +1 -1
  747. package/dist/interactions/gestures/pointerDrag/pointerDrag.js +62 -41
  748. package/dist/interactions/gestures/pointerDrag/pointerDrag.js.map +1 -1
  749. package/dist/interactions/gestures/shared/originProjection.js +1 -1
  750. package/dist/interactions/gestures/shared/originProjection.js.map +1 -1
  751. package/dist/interactions/gestures/shared/screenTolerance.js +8 -2
  752. package/dist/interactions/gestures/shared/screenTolerance.js.map +1 -1
  753. package/dist/interactions/gestures/shared/snap.js.map +1 -1
  754. package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js +8 -4
  755. package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js.map +1 -1
  756. package/dist/layout/arrivals.js +20 -23
  757. package/dist/layout/arrivals.js.map +1 -1
  758. package/dist/math-CYUjoyyU.d.ts +33 -0
  759. package/dist/math.d.ts +5 -3
  760. package/dist/math.js +6 -6
  761. package/dist/mesh.d.ts +4 -268
  762. package/dist/mesh.js +3 -7
  763. package/dist/move.d.ts +14 -11
  764. package/dist/{originProjection-DEklpDc_.d.ts → originProjection-PPT88jZv.d.ts} +1 -1
  765. package/dist/patterns-builtin.d.ts +1 -118
  766. package/dist/patterns-builtin.js +2 -3
  767. package/dist/{poseDescriptor-D-OH-tu5.d.ts → poseDescriptor-Bqk-11Rl.d.ts} +26 -36
  768. package/dist/renderer.d.ts +1 -91
  769. package/dist/renderer.js +2 -18
  770. package/dist/resize.d.ts +10 -22
  771. package/dist/resize.js +6 -6
  772. package/dist/style.css +1 -1
  773. package/dist/test-hook/install.js +12 -6
  774. package/dist/test-hook/install.js.map +1 -1
  775. package/dist/test-hook/useTestHook.js +22 -0
  776. package/dist/test-hook/useTestHook.js.map +1 -0
  777. package/dist/test-seams-D0pyV3pR.d.ts +149 -0
  778. package/dist/test-seams.d.ts +4 -4
  779. package/dist/test-seams.js +2 -2
  780. package/dist/tools/builtin/bone/boneActions.js +130 -0
  781. package/dist/tools/builtin/bone/boneActions.js.map +1 -0
  782. package/dist/tools/builtin/bone/boneOverlay.js +58 -0
  783. package/dist/tools/builtin/bone/boneOverlay.js.map +1 -0
  784. package/dist/tools/builtin/bone/placedRig.js +24 -0
  785. package/dist/tools/builtin/bone/placedRig.js.map +1 -0
  786. package/dist/tools/builtin/bone/rigEditState.js +21 -0
  787. package/dist/tools/builtin/bone/rigEditState.js.map +1 -0
  788. package/dist/tools/builtin/bone/useBoneTool.js +98 -0
  789. package/dist/tools/builtin/bone/useBoneTool.js.map +1 -0
  790. package/dist/tools/builtin/ellipse/useEllipseTool.js +1 -0
  791. package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
  792. package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
  793. package/dist/tools/builtin/hand/useHandTool.js +1 -0
  794. package/dist/tools/builtin/hand/useHandTool.js.map +1 -1
  795. package/dist/tools/builtin/image/useImageTool.js.map +1 -1
  796. package/dist/tools/builtin/lasso/useLassoTool.js +11 -11
  797. package/dist/tools/builtin/lasso/useLassoTool.js.map +1 -1
  798. package/dist/tools/builtin/line/useLineTool.js +1 -0
  799. package/dist/tools/builtin/line/useLineTool.js.map +1 -1
  800. package/dist/tools/builtin/pen/usePenTool.js +198 -150
  801. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  802. package/dist/tools/builtin/pencil/usePencilTool.js +1 -0
  803. package/dist/tools/builtin/pencil/usePencilTool.js.map +1 -1
  804. package/dist/tools/builtin/pickTopMostHit.js.map +1 -1
  805. package/dist/tools/builtin/polygon/usePolygonTool.js +13 -8
  806. package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
  807. package/dist/tools/builtin/rect/useRectTool.js +1 -0
  808. package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
  809. package/dist/tools/builtin/select/adapterPointQuery.js +36 -0
  810. package/dist/tools/builtin/select/adapterPointQuery.js.map +1 -0
  811. package/dist/tools/builtin/select/selectionContributions.js +25 -24
  812. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  813. package/dist/tools/builtin/select/useSelectTool.js +42 -67
  814. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  815. package/dist/tools/builtin/shared/pointerFollower.js +17 -0
  816. package/dist/tools/builtin/shared/pointerFollower.js.map +1 -0
  817. package/dist/tools/builtin/slice/useSliceTool.js +72 -82
  818. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  819. package/dist/tools/builtin/star/useStarTool.js +22 -16
  820. package/dist/tools/builtin/star/useStarTool.js.map +1 -1
  821. package/dist/tools/builtin/text/useTextTool.js +9 -0
  822. package/dist/tools/builtin/text/useTextTool.js.map +1 -1
  823. package/dist/tools/builtin/weight/useWeightTool.js +77 -0
  824. package/dist/tools/builtin/weight/useWeightTool.js.map +1 -0
  825. package/dist/tools/builtin/weight/weightActions.js +112 -0
  826. package/dist/tools/builtin/weight/weightActions.js.map +1 -0
  827. package/dist/tools/builtin/weight/weightOverlay.js +61 -0
  828. package/dist/tools/builtin/weight/weightOverlay.js.map +1 -0
  829. package/dist/tools/overlayBinding.js.map +1 -1
  830. package/dist/tools/useKeybindings.js +12 -22
  831. package/dist/tools/useKeybindings.js.map +1 -1
  832. package/dist/{types-A37hYkeR.d.ts → types-CIKDwlsP.d.ts} +113 -169
  833. package/dist/util/color.js +3 -3
  834. package/dist/util/color.js.map +1 -1
  835. package/dist/util/paint.js +1 -1
  836. package/dist/util/paint.js.map +1 -1
  837. package/dist/version.js +1 -1
  838. package/package.json +28 -21
  839. package/dist/animation/colorHelpers.js +0 -135
  840. package/dist/animation/colorHelpers.js.map +0 -1
  841. package/dist/animation/colorRegistry.js +0 -37
  842. package/dist/animation/colorRegistry.js.map +0 -1
  843. package/dist/animation/engine/axes.js +0 -36
  844. package/dist/animation/engine/axes.js.map +0 -1
  845. package/dist/animation/engine/codec.js +0 -170
  846. package/dist/animation/engine/codec.js.map +0 -1
  847. package/dist/animation/engine/integrator.js +0 -12
  848. package/dist/animation/engine/integrator.js.map +0 -1
  849. package/dist/animation/loop.js +0 -62
  850. package/dist/animation/loop.js.map +0 -1
  851. package/dist/animation/observe.js +0 -23
  852. package/dist/animation/observe.js.map +0 -1
  853. package/dist/animation/rig/blendPoses.js +0 -43
  854. package/dist/animation/rig/blendPoses.js.map +0 -1
  855. package/dist/animation/rig/mirrorPose.js +0 -19
  856. package/dist/animation/rig/mirrorPose.js.map +0 -1
  857. package/dist/animation/rig/resolveSkeleton.js +0 -33
  858. package/dist/animation/rig/resolveSkeleton.js.map +0 -1
  859. package/dist/animation/rig/solveIk.js +0 -103
  860. package/dist/animation/rig/solveIk.js.map +0 -1
  861. package/dist/animation/rig/types.js +0 -12
  862. package/dist/animation/rig/types.js.map +0 -1
  863. package/dist/animation/slew.js +0 -27
  864. package/dist/animation/slew.js.map +0 -1
  865. package/dist/animation/stagger.js +0 -138
  866. package/dist/animation/stagger.js.map +0 -1
  867. package/dist/animation/timeline/booking.js +0 -106
  868. package/dist/animation/timeline/booking.js.map +0 -1
  869. package/dist/animation/timeline/createTimeline.js +0 -116
  870. package/dist/animation/timeline/createTimeline.js.map +0 -1
  871. package/dist/animation/timeline/sampleTrack.js +0 -71
  872. package/dist/animation/timeline/sampleTrack.js.map +0 -1
  873. package/dist/animation/useAnimator.js +0 -378
  874. package/dist/animation/useAnimator.js.map +0 -1
  875. package/dist/builtins-C-VgUlWI.d.ts +0 -4514
  876. package/dist/canvas/MinimapCanvas.js +0 -139
  877. package/dist/canvas/MinimapCanvas.js.map +0 -1
  878. package/dist/canvas/deps/poseComposition.js +0 -11
  879. package/dist/canvas/deps/poseComposition.js.map +0 -1
  880. package/dist/canvas/minimapMath.js +0 -80
  881. package/dist/canvas/minimapMath.js.map +0 -1
  882. package/dist/canvas/toolPreview.js +0 -39
  883. package/dist/canvas/toolPreview.js.map +0 -1
  884. package/dist/core/adapters/arrayAdapter.js +0 -85
  885. package/dist/core/adapters/arrayAdapter.js.map +0 -1
  886. package/dist/core/adapters/useArrayAdapter.js +0 -13
  887. package/dist/core/adapters/useArrayAdapter.js.map +0 -1
  888. package/dist/core/fillInPoseFrame.js +0 -102
  889. package/dist/core/fillInPoseFrame.js.map +0 -1
  890. package/dist/core/geometry/poseRotation.js +0 -58
  891. package/dist/core/geometry/poseRotation.js.map +0 -1
  892. package/dist/core/gradient.js +0 -136
  893. package/dist/core/gradient.js.map +0 -1
  894. package/dist/core/isPlainObject.js.map +0 -1
  895. package/dist/core/markerInset.js +0 -24
  896. package/dist/core/markerInset.js.map +0 -1
  897. package/dist/core/mixed.js +0 -6
  898. package/dist/core/mixed.js.map +0 -1
  899. package/dist/core/paintKinds.js +0 -156
  900. package/dist/core/paintKinds.js.map +0 -1
  901. package/dist/core/strokeMarkerShapes.js +0 -139
  902. package/dist/core/strokeMarkerShapes.js.map +0 -1
  903. package/dist/core/strokeMarkers.js +0 -28
  904. package/dist/core/strokeMarkers.js.map +0 -1
  905. package/dist/core/viewport/meanScale.js +0 -8
  906. package/dist/core/viewport/meanScale.js.map +0 -1
  907. package/dist/core/viewport/pxExtent.js +0 -42
  908. package/dist/core/viewport/pxExtent.js.map +0 -1
  909. package/dist/debug/flag.js.map +0 -1
  910. package/dist/features/cursor/paintedCursorLayer.js.map +0 -1
  911. package/dist/features/focus/gateLayer.js +0 -14
  912. package/dist/features/focus/gateLayer.js.map +0 -1
  913. package/dist/features/focus/useCanvasFocus.js +0 -29
  914. package/dist/features/focus/useCanvasFocus.js.map +0 -1
  915. package/dist/features/groups/children.js.map +0 -1
  916. package/dist/features/groups/composePose.js.map +0 -1
  917. package/dist/features/groups/nestedHit.js.map +0 -1
  918. package/dist/features/groups/unionOfChildren.js.map +0 -1
  919. package/dist/features/images/imageCache.js +0 -94
  920. package/dist/features/images/imageCache.js.map +0 -1
  921. package/dist/features/ingestion/index.js +0 -8
  922. package/dist/features/meshPaint/bake.js +0 -79
  923. package/dist/features/meshPaint/bake.js.map +0 -1
  924. package/dist/features/meshPaint/bakeCache.js +0 -59
  925. package/dist/features/meshPaint/bakeCache.js.map +0 -1
  926. package/dist/features/meshPaint/handles.js +0 -86
  927. package/dist/features/meshPaint/handles.js.map +0 -1
  928. package/dist/features/meshPaint/lazyKind.js.map +0 -1
  929. package/dist/features/meshPaint/meshPaint.js +0 -236
  930. package/dist/features/meshPaint/meshPaint.js.map +0 -1
  931. package/dist/features/meshPaint/meshShader.js +0 -6
  932. package/dist/features/meshPaint/meshShader.js.map +0 -1
  933. package/dist/features/meshPaint/register.js +0 -7
  934. package/dist/features/meshPaint/register.js.map +0 -1
  935. package/dist/features/meshPaint/surface.js +0 -110
  936. package/dist/features/meshPaint/surface.js.map +0 -1
  937. package/dist/features/minimap/actions.js +0 -53
  938. package/dist/features/minimap/actions.js.map +0 -1
  939. package/dist/features/minimap/createMinimapContribution.js +0 -96
  940. package/dist/features/minimap/createMinimapContribution.js.map +0 -1
  941. package/dist/features/minimap/layers.js +0 -103
  942. package/dist/features/minimap/layers.js.map +0 -1
  943. package/dist/features/overlays/useNodeOverlayFrame.js +0 -103
  944. package/dist/features/overlays/useNodeOverlayFrame.js.map +0 -1
  945. package/dist/features/parallax/createParallaxLayer.js +0 -26
  946. package/dist/features/parallax/createParallaxLayer.js.map +0 -1
  947. package/dist/features/parallax/createParallaxPlane.js +0 -26
  948. package/dist/features/parallax/createParallaxPlane.js.map +0 -1
  949. package/dist/features/paths/anchorEdits.js +0 -156
  950. package/dist/features/paths/anchorEdits.js.map +0 -1
  951. package/dist/features/paths/anchors.js +0 -154
  952. package/dist/features/paths/anchors.js.map +0 -1
  953. package/dist/features/paths/booleans.js +0 -2
  954. package/dist/features/paths/markerCommands.js +0 -148
  955. package/dist/features/paths/markerCommands.js.map +0 -1
  956. package/dist/features/paths/markerSites.js +0 -59
  957. package/dist/features/paths/markerSites.js.map +0 -1
  958. package/dist/features/paths/markers.js +0 -95
  959. package/dist/features/paths/markers.js.map +0 -1
  960. package/dist/features/paths/nearestAnchor.js +0 -36
  961. package/dist/features/paths/nearestAnchor.js.map +0 -1
  962. package/dist/features/paths/pathInWorld.js +0 -41
  963. package/dist/features/paths/pathInWorld.js.map +0 -1
  964. package/dist/features/paths/poseDescriptor.js +0 -39
  965. package/dist/features/paths/poseDescriptor.js.map +0 -1
  966. package/dist/features/paths/tessellate/dash.js +0 -52
  967. package/dist/features/paths/tessellate/dash.js.map +0 -1
  968. package/dist/features/paths/tessellate/insets.js +0 -32
  969. package/dist/features/paths/tessellate/insets.js.map +0 -1
  970. package/dist/features/paths/tessellate/metric.js +0 -72
  971. package/dist/features/paths/tessellate/metric.js.map +0 -1
  972. package/dist/features/paths/tessellate/stroke.js +0 -170
  973. package/dist/features/paths/tessellate/stroke.js.map +0 -1
  974. package/dist/features/paths/tessellate/vertexWidths.js +0 -32
  975. package/dist/features/paths/tessellate/vertexWidths.js.map +0 -1
  976. package/dist/features/patterns/index.js +0 -23
  977. package/dist/features/patterns/index.js.map +0 -1
  978. package/dist/features/patterns/patterns-builtin.js +0 -38
  979. package/dist/features/patterns/patterns-builtin.js.map +0 -1
  980. package/dist/features/patterns/resolveSpec.js +0 -57
  981. package/dist/features/patterns/resolveSpec.js.map +0 -1
  982. package/dist/features/patterns/tileGeometry.js +0 -158
  983. package/dist/features/patterns/tileGeometry.js.map +0 -1
  984. package/dist/features/pointer/PointerContext.js +0 -45
  985. package/dist/features/pointer/PointerContext.js.map +0 -1
  986. package/dist/features/selection/SelectionContext.js +0 -46
  987. package/dist/features/selection/SelectionContext.js.map +0 -1
  988. package/dist/features/simulation/createSimulation.js +0 -61
  989. package/dist/features/simulation/createSimulation.js.map +0 -1
  990. package/dist/features/simulation/types.js +0 -6
  991. package/dist/features/simulation/types.js.map +0 -1
  992. package/dist/features/simulation/useSimulation.js +0 -74
  993. package/dist/features/simulation/useSimulation.js.map +0 -1
  994. package/dist/features/text/domRuns.js +0 -258
  995. package/dist/features/text/domRuns.js.map +0 -1
  996. package/dist/features/text/fitTextPose.js +0 -38
  997. package/dist/features/text/fitTextPose.js.map +0 -1
  998. package/dist/features/text/hitTest.js +0 -45
  999. package/dist/features/text/hitTest.js.map +0 -1
  1000. package/dist/features/text/renderLabel.js +0 -14
  1001. package/dist/features/text/renderLabel.js.map +0 -1
  1002. package/dist/features/text/runs/effectiveRangeStyle.js +0 -66
  1003. package/dist/features/text/runs/effectiveRangeStyle.js.map +0 -1
  1004. package/dist/features/text/runs/flagRange.js +0 -53
  1005. package/dist/features/text/runs/flagRange.js.map +0 -1
  1006. package/dist/features/text/runs/rangeStyle.js +0 -135
  1007. package/dist/features/text/runs/rangeStyle.js.map +0 -1
  1008. package/dist/features/text/textCommand.js +0 -59
  1009. package/dist/features/text/textCommand.js.map +0 -1
  1010. package/dist/features/text/textToPath.js +0 -181
  1011. package/dist/features/text/textToPath.js.map +0 -1
  1012. package/dist/features/text/useTextEdit.js +0 -467
  1013. package/dist/features/text/useTextEdit.js.map +0 -1
  1014. package/dist/features/tiling/createTiledLayer.js +0 -63
  1015. package/dist/features/tiling/createTiledLayer.js.map +0 -1
  1016. package/dist/features/tiling/tiledProject.js +0 -14
  1017. package/dist/features/tiling/tiledProject.js.map +0 -1
  1018. package/dist/interactions/actions/clone/behaviors/cloneByAltDrag.js +0 -26
  1019. package/dist/interactions/actions/clone/behaviors/cloneByAltDrag.js.map +0 -1
  1020. package/dist/interactions/actions/defaults/align.js.map +0 -1
  1021. package/dist/interactions/actions/defaults/booleans.js +0 -52
  1022. package/dist/interactions/actions/defaults/booleans.js.map +0 -1
  1023. package/dist/interactions/actions/defaults/clipboard.js.map +0 -1
  1024. package/dist/interactions/actions/defaults/clone.js +0 -107
  1025. package/dist/interactions/actions/defaults/clone.js.map +0 -1
  1026. package/dist/interactions/actions/defaults/createOutlines.js +0 -47
  1027. package/dist/interactions/actions/defaults/createOutlines.js.map +0 -1
  1028. package/dist/interactions/actions/defaults/distribute.js +0 -66
  1029. package/dist/interactions/actions/defaults/distribute.js.map +0 -1
  1030. package/dist/interactions/actions/defaults/editAnchors.js.map +0 -1
  1031. package/dist/interactions/actions/defaults/flip.js +0 -119
  1032. package/dist/interactions/actions/defaults/flip.js.map +0 -1
  1033. package/dist/interactions/actions/defaults/freshNodeId.js +0 -10
  1034. package/dist/interactions/actions/defaults/freshNodeId.js.map +0 -1
  1035. package/dist/interactions/actions/defaults/insert.js +0 -288
  1036. package/dist/interactions/actions/defaults/insert.js.map +0 -1
  1037. package/dist/interactions/actions/defaults/lassoSelect.js +0 -156
  1038. package/dist/interactions/actions/defaults/lassoSelect.js.map +0 -1
  1039. package/dist/interactions/actions/defaults/move.js +0 -760
  1040. package/dist/interactions/actions/defaults/move.js.map +0 -1
  1041. package/dist/interactions/actions/defaults/resize.js +0 -335
  1042. package/dist/interactions/actions/defaults/resize.js.map +0 -1
  1043. package/dist/interactions/actions/defaults/rotate.js +0 -184
  1044. package/dist/interactions/actions/defaults/rotate.js.map +0 -1
  1045. package/dist/interactions/actions/previewOverrides.js +0 -25
  1046. package/dist/interactions/actions/previewOverrides.js.map +0 -1
  1047. package/dist/interactions/actions/resize/autoPoseDescriptor.js.map +0 -1
  1048. package/dist/math-Drrw4ewZ.d.ts +0 -160
  1049. package/dist/registerProgram-BMZRDgrh.d.ts +0 -197
  1050. package/dist/renderer/DrawCommand.js +0 -6
  1051. package/dist/renderer/DrawCommand.js.map +0 -1
  1052. package/dist/renderer/WeaselRenderer.js +0 -331
  1053. package/dist/renderer/WeaselRenderer.js.map +0 -1
  1054. package/dist/renderer/batchClip.js +0 -46
  1055. package/dist/renderer/batchClip.js.map +0 -1
  1056. package/dist/renderer/cache/GLImageCache.js +0 -64
  1057. package/dist/renderer/cache/GLImageCache.js.map +0 -1
  1058. package/dist/renderer/cache/GLMeshCache.js +0 -102
  1059. package/dist/renderer/cache/GLMeshCache.js.map +0 -1
  1060. package/dist/renderer/cache/GLTextureCache.js +0 -51
  1061. package/dist/renderer/cache/GLTextureCache.js.map +0 -1
  1062. package/dist/renderer/cache/GradientRampAtlas.js +0 -82
  1063. package/dist/renderer/cache/GradientRampAtlas.js.map +0 -1
  1064. package/dist/renderer/cache/cache.js +0 -13
  1065. package/dist/renderer/cache/cache.js.map +0 -1
  1066. package/dist/renderer/cache/markerCommandCache.js +0 -63
  1067. package/dist/renderer/cache/markerCommandCache.js.map +0 -1
  1068. package/dist/renderer/cache/outlineMeshCache.js +0 -15
  1069. package/dist/renderer/cache/outlineMeshCache.js.map +0 -1
  1070. package/dist/renderer/cache/outlineStrokeMeshCache.js +0 -36
  1071. package/dist/renderer/cache/outlineStrokeMeshCache.js.map +0 -1
  1072. package/dist/renderer/cache/strokeMeshCache.js +0 -55
  1073. package/dist/renderer/cache/strokeMeshCache.js.map +0 -1
  1074. package/dist/renderer/cullDrawCommands.js +0 -90
  1075. package/dist/renderer/cullDrawCommands.js.map +0 -1
  1076. package/dist/renderer/draw.js +0 -1135
  1077. package/dist/renderer/draw.js.map +0 -1
  1078. package/dist/renderer/drawBatch.js +0 -198
  1079. package/dist/renderer/drawBatch.js.map +0 -1
  1080. package/dist/renderer/effects/EffectTargets.js +0 -45
  1081. package/dist/renderer/effects/EffectTargets.js.map +0 -1
  1082. package/dist/renderer/effects/builtins.js +0 -31
  1083. package/dist/renderer/effects/builtins.js.map +0 -1
  1084. package/dist/renderer/effects/composite.js +0 -9
  1085. package/dist/renderer/effects/composite.js.map +0 -1
  1086. package/dist/renderer/effects/effectPrelude.js +0 -10
  1087. package/dist/renderer/effects/effectPrelude.js.map +0 -1
  1088. package/dist/renderer/effects/types.js +0 -10
  1089. package/dist/renderer/effects/types.js.map +0 -1
  1090. package/dist/renderer/glyphOutlineMesh.js +0 -67
  1091. package/dist/renderer/glyphOutlineMesh.js.map +0 -1
  1092. package/dist/renderer/index.js +0 -19
  1093. package/dist/renderer/math/color.js +0 -341
  1094. package/dist/renderer/math/color.js.map +0 -1
  1095. package/dist/renderer/math/mat3.js +0 -76
  1096. package/dist/renderer/math/mat3.js.map +0 -1
  1097. package/dist/renderer/math/patternSpace.js +0 -22
  1098. package/dist/renderer/math/patternSpace.js.map +0 -1
  1099. package/dist/renderer/math/viewToMat3.js +0 -19
  1100. package/dist/renderer/math/viewToMat3.js.map +0 -1
  1101. package/dist/renderer/paintResources.js +0 -18
  1102. package/dist/renderer/paintResources.js.map +0 -1
  1103. package/dist/renderer/paintScratch.js +0 -37
  1104. package/dist/renderer/paintScratch.js.map +0 -1
  1105. package/dist/renderer/shaders/ShaderProgram.js +0 -74
  1106. package/dist/renderer/shaders/ShaderProgram.js.map +0 -1
  1107. package/dist/renderer/shaders/batchFill.js +0 -119
  1108. package/dist/renderer/shaders/batchFill.js.map +0 -1
  1109. package/dist/renderer/shaders/customPrelude.js +0 -34
  1110. package/dist/renderer/shaders/customPrelude.js.map +0 -1
  1111. package/dist/renderer/shaders/extractUniformNames.js +0 -184
  1112. package/dist/renderer/shaders/extractUniformNames.js.map +0 -1
  1113. package/dist/renderer/shaders/glyphPaint.js +0 -61
  1114. package/dist/renderer/shaders/glyphPaint.js.map +0 -1
  1115. package/dist/renderer/shaders/gradFill.js +0 -30
  1116. package/dist/renderer/shaders/gradFill.js.map +0 -1
  1117. package/dist/renderer/shaders/imageFill.js +0 -14
  1118. package/dist/renderer/shaders/imageFill.js.map +0 -1
  1119. package/dist/renderer/shaders/pathFill.js +0 -13
  1120. package/dist/renderer/shaders/pathFill.js.map +0 -1
  1121. package/dist/renderer/shaders/patternFill.js +0 -24
  1122. package/dist/renderer/shaders/patternFill.js.map +0 -1
  1123. package/dist/renderer/shaders/registerProgram.js +0 -18
  1124. package/dist/renderer/shaders/registerProgram.js.map +0 -1
  1125. package/dist/renderer/spriteSheet.js +0 -14
  1126. package/dist/renderer/spriteSheet.js.map +0 -1
  1127. package/dist/renderer/state/GroupState.js +0 -77
  1128. package/dist/renderer/state/GroupState.js.map +0 -1
  1129. package/dist/renderer/strokeLengths.js +0 -50
  1130. package/dist/renderer/strokeLengths.js.map +0 -1
  1131. package/dist/renderer/syntheticItalic.js +0 -6
  1132. package/dist/renderer/syntheticItalic.js.map +0 -1
  1133. package/dist/renderer/textures/registerTexture.js +0 -14
  1134. package/dist/renderer/textures/registerTexture.js.map +0 -1
  1135. package/dist/scheduling/useVisibleRaf.js +0 -69
  1136. package/dist/scheduling/useVisibleRaf.js.map +0 -1
  1137. package/dist/test-seams-CuIxe0xY.d.ts +0 -356
  1138. package/dist/tools/prefs.js +0 -62
  1139. package/dist/tools/prefs.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.js","names":["projectBounds","t","viewToTransform","view","sx","sy","worldToScreen","b","leavesOf","isContainer","id","out","visit","kids","getChildren","nid","k","composeSelectionPose","opts","d","AUTO_POSE_DESCRIPTOR","selectionLeaves","resolveLeaf","moved","moveOverlay","resizeOverlay","getStoredPose","leaves","containerResizeLeafPoses","leafBounds","leafId","visualBoundsViaDescriptor","overlayLeaf","u","unionAABB","makeContainerAwareBoundsResolver","oriented","p","getPose","DEFAULT_OUTLINE","DEFAULT_HANDLE_FILL","DEFAULT_HANDLE_OUTLINE","DEFAULT_HANDLE_SIZE","HANDLE_BASE_PX","defaultHandlesOf","resolveOutlineStroke","resolveHandles","rotateAroundMat3","c","theta","s","tx","cx","cy","ty","rectPathFor","outlineCommandsFor","align","stroke","width","resolveStrokeWidth","ids","worldB","resolveBounds","padded","pad","rot","poseRotationOf","r","alignedStrokeRect","q","screenCorners","PATH_M","PATH_L","PATH_Z","rectCorners","w","rotatePoint","x","y","ccx","ccy","normal","nx","a","ny","l","mx","my","n1","i","n2","handleCommandsFor","half","handles","handleAlign","handleWidth","angle","screenAngleOf","hLocal","handlesOf","hWorld","hsx","hsy","center","baseRect","sr","fillCmd","strokeCmd","rotationHandleCommands","rotationHandle","distance","rotation","scx","scy","size","arcRadius","ARC_HALF_ANGLE","arcWidth","cmds","xs","ys","arcCoords","arcPath","headLen","headWidth","arrowHead","len","ux","uy","px","py","tipX","endX","tipY","endY","baseLeftX","baseLeftY","baseRightX","baseRightY","angleA","endAX","endAY","tangentAX","tangentAY","angleB","endBX","endBY","tangentBX","tangentBY","headA","headB","headFill","transform","mat3","buildSelectionLayer","passes","poseBounds","rotationHandleDistance","rotationBadgeOf","chromeState","asChromeState","data","allIds","chromeSelectionIds","suppressed","isVisible","asIsVisible","showOutline","showHandles","showRotation","resolveTargetBounds","MULTI_RESIZE_TARGET_ID","outlineIdsRaw","outlineIds","cmd","DEFAULT_ROTATION_HANDLE_DISTANCE","createSelectionOutlineLayer","createSelectionHandlesLayer","createSelectionOverlayLayer","maybe","state"],"sources":["../../../src/features/selection/overlay.ts"],"sourcesContent":["/**\n * Selection overlay primitives — render layers for drawing selection\n * outlines and corner resize handles in world space.\n *\n * Three pieces:\n * - `composeSelectionPose` resolves the live pose for a selected id by\n * consulting the move overlay first, then the resize overlay, then the\n * stored pose. When `getChildren`/`isContainer` are supplied and the id\n * resolves to a container, the returned pose is the union AABB of all\n * transitive leaf poses (with the same precedence rules applied per leaf).\n * - `createSelectionOutlineLayer` draws the outline rect for each selected\n * id (container ids resolve to a union AABB via `getChildren`/`isContainer`).\n * - `createSelectionHandlesLayer` draws resize-handle rects (default 4\n * corners) for each selected id, with the same container-resolution rules.\n *\n * `createSelectionOverlayLayer` is a thin convenience that returns a single\n * `RenderLayer` whose draw runs the outline pass then the handles pass.\n *\n * **Pose shape:** TPose is generic; callers pass `poseDescriptor` for poses\n * `AUTO_POSE_DESCRIPTOR` can't read. Container ids reduce via `unionAABB`\n * over the projected AABBs.\n */\n\nimport type { DrawCommand } from '../../renderer';\nimport { mat3, type GlMat3 } from '../../renderer';\nimport type { NodeId } from 'core/scene/types';\nimport type { RenderLayer } from 'core/layers/render';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport {\n visualBoundsViaDescriptor,\n type PoseDescriptor,\n} from 'core/geometry/poseDescriptor';\nimport { AUTO_POSE_DESCRIPTOR } from 'interactions/actions/resize/autoPoseDescriptor';\nimport { alignedStrokeRect, type FillStyle, type Stroke } from '@weasel-js/paint';\nimport { resolveStrokeWidth } from 'features/paths/tessellate/stroke';\nimport {\n rotationHandle,\n DEFAULT_ROTATION_HANDLE_DISTANCE,\n} from 'interactions/actions/rotate/handle';\nimport { rectCorners, rotatePoint } from 'interactions/actions/rotate/geometry';\nimport { poseRotationOf } from 'core/geometry/poseRotation';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { ChromeState } from 'core/selection/chromeState';\nimport { MULTI_RESIZE_TARGET_ID } from 'core/selection/selectionTarget';\nimport type { View } from 'core/viewport/view';\nimport { viewToTransform } from 'core/viewport/view';\nimport { worldToScreen } from 'core/viewport/viewTransform';\nimport { screenAngleOf } from 'core/viewport/pxExtent';\nimport { PATH_L, PATH_M, PATH_Z, type PolygonPath } from '@weasel-js/geom';\nimport { HANDLE_BASE_PX } from 'core/device/targets';\n\n/** Project world AABB into screen-space AABB using the active view. */\nfunction projectBounds<B extends Bounds>(b: B, view: View): B {\n const t = viewToTransform(view);\n const [sx, sy] = worldToScreen(b.x, b.y, t);\n return { ...b, x: sx, y: sy, width: b.width * view.scale.x, height: b.height * view.scale.y };\n}\n\n\n/**\n * Transitive leaf ids under `id`. A childless node is a leaf only if it is not\n * itself a container: an empty container contributes no bounds, and its own\n * stored pose is at its most stale when no children are left to have moved it.\n */\nfunction leavesOf(\n id: string,\n getChildren: (id: string) => readonly string[],\n isContainer: (id: string) => boolean,\n): string[] {\n if (!isContainer(id)) return [id];\n const out: string[] = [];\n const visit = (nid: string) => {\n const kids = getChildren(nid);\n if (kids.length === 0) { if (!isContainer(nid)) out.push(nid); return; }\n for (const k of kids) visit(k);\n };\n visit(id);\n return out;\n}\n\n/** Options for `composeSelectionPose`. */\nexport interface ComposeSelectionPoseOpts<TPose> {\n /** Move overlay; when present its `poses` map wins over everything else. */\n moveOverlay?: { poses: Map<string, TPose> } | null;\n /**\n * Resize overlay; consulted only when move overlay does not own the id.\n * For container resize, `leafPoses` (when present) maps each leaf id under\n * the container to its overlay pose. If absent the container falls back to\n * stored leaf poses (defensive — container-resize integration is in flight).\n */\n resizeOverlay?: {\n id: string;\n currentPose: TPose;\n leafPoses?: Map<string, TPose>;\n } | null;\n /** Fallback pose lookup (typically the stored/committed pose). */\n getStoredPose: (id: string) => TPose;\n /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<TPose>;\n /** Walk a container's direct children (e.g. `scene.childrenOf`). With\n * `isContainer`, a selected container resolves to the union AABB of its\n * transitive leaf poses instead of its own stored pose. */\n getChildren?: (id: string) => readonly string[];\n /** True when `id` is a structural container. */\n isContainer?: (id: string) => boolean;\n}\n\n/**\n * Build a pose resolver for a selection. Precedence per id:\n * move overlay > resize overlay > stored. When `getChildren`/`isContainer`\n * are supplied and the id resolves to a container, the resolver returns the\n * union AABB of all transitive leaf poses (each leaf still subject to the\n * precedence rules). Containers with no leaves resolve to `null`.\n */\nexport function composeSelectionPose<TPose>(\n opts: ComposeSelectionPoseOpts<TPose>,\n): (id: string) => TPose | null {\n const { moveOverlay, resizeOverlay, getStoredPose, getChildren, isContainer } = opts;\n const d = (opts.poseDescriptor ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<TPose>;\n\n const selectionLeaves = (id: string): string[] =>\n getChildren && isContainer ? leavesOf(id, getChildren, isContainer) : [id];\n\n const resolveLeaf = (id: string): TPose => {\n const moved = moveOverlay?.poses.get(id);\n if (moved !== undefined) return moved;\n if (resizeOverlay && resizeOverlay.id === id) return resizeOverlay.currentPose;\n return getStoredPose(id);\n };\n\n return (id: string): TPose | null => {\n if (isContainer?.(id)) {\n const leaves = selectionLeaves(id);\n if (leaves.length === 0) return null;\n const containerResizeLeafPoses =\n resizeOverlay && resizeOverlay.id === id ? resizeOverlay.leafPoses : undefined;\n const leafBounds: Bounds[] = [];\n for (const leafId of leaves) {\n const moved = moveOverlay?.poses.get(leafId);\n if (moved !== undefined) {\n leafBounds.push(visualBoundsViaDescriptor(moved, d));\n continue;\n }\n const overlayLeaf = containerResizeLeafPoses?.get(leafId);\n if (overlayLeaf !== undefined) {\n leafBounds.push(visualBoundsViaDescriptor(overlayLeaf, d));\n continue;\n }\n leafBounds.push(visualBoundsViaDescriptor(getStoredPose(leafId), d));\n }\n const u = unionAABB(leafBounds);\n if (u === null) return null;\n return d.fromBounds(u, getStoredPose(leaves[0]!));\n }\n return resolveLeaf(id);\n };\n}\n\n/**\n * Build a pose resolver that handles container ids by computing the union\n * AABB of every leaf's bounds. Non-container ids pass through directly. When\n * `getChildren`/`isContainer` are omitted, every id is treated as a leaf.\n */\nfunction makeContainerAwareBoundsResolver<TPose>(\n getPose: (id: string) => TPose | null,\n d: PoseDescriptor<TPose>,\n getChildren?: (id: string) => readonly string[],\n isContainer?: (id: string) => boolean,\n): (id: string) => Bounds | null {\n const oriented = (p: TPose): Bounds => {\n const b = d.getBounds(p);\n const r = d.getRotation?.(p);\n return r ? { ...b, rotation: r } : b;\n };\n if (getChildren === undefined || isContainer === undefined) {\n return (id: string) => {\n const p = getPose(id);\n return p === null ? null : oriented(p);\n };\n }\n return (id: string): Bounds | null => {\n if (!isContainer(id)) {\n const p = getPose(id);\n return p === null ? null : oriented(p);\n }\n const leaves = leavesOf(id, getChildren, isContainer);\n if (leaves.length === 0) return null;\n const leafBounds: Bounds[] = [];\n for (const leafId of leaves) {\n const p = getPose(leafId);\n if (p !== null) leafBounds.push(visualBoundsViaDescriptor(p, d));\n }\n if (leafBounds.length === 0) return null;\n return unionAABB(leafBounds);\n };\n}\n\n/** Options every selection layer shares. `getSelection` and `getPose` are\n * declared on {@link SelectionOverlayLayerOpts}, which makes both optional —\n * omitted, they come off the draw envelope. */\ninterface SelectionLayerCommon<TPose> {\n /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<TPose>;\n /** Walk a container's direct children (e.g. `scene.childrenOf`). When\n * supplied with `isContainer`, any id that resolves to a container is\n * rendered using the union bounds of all its transitive leaves. */\n getChildren?: (id: string) => readonly string[];\n /** True when `id` is a structural container. */\n isContainer?: (id: string) => boolean;\n}\n\n/** Options for `createSelectionOutlineLayer`. The overlay layer's options\n * minus the handle visuals — the two run the same body. */\nexport type SelectionOutlineLayerOpts<TPose> =\n Omit<SelectionOverlayLayerOpts<TPose>, 'handles' | 'handlesOf' | 'rotationHandle'>;\n\n/** Options for `createSelectionHandlesLayer`. The overlay layer's options\n * minus the outline stroke — the two run the same body. */\nexport type SelectionHandlesLayerOpts<TPose> =\n Omit<SelectionOverlayLayerOpts<TPose>, 'outline'>;\n\n/** Options for `createSelectionOverlayLayer`. */\nexport interface SelectionOverlayLayerOpts<TPose>\n extends SelectionLayerCommon<TPose> {\n /**\n * Which ids to draw chrome for. Omit to take them from the `ChromeState` on\n * the draw envelope, which is what makes one canvas's several views each\n * outline their own selection — the layer is shared, the envelope is not.\n *\n * A multi-selection resolves to the synthetic union id, with the real\n * members going to the outline pass, exactly as the explicit form does.\n */\n getSelection?: () => readonly NodeId[];\n /**\n * Resolve an id to the pose to draw chrome around. Return null to skip an\n * id. Omit to take bounds from the same envelope `getSelection` omitted\n * takes ids from — one cascade, the one the chrome state was built with,\n * rather than a second one here that has to agree with it.\n *\n * Takes `string` rather than `NodeId` because the container-aware resolver\n * walks expanded leaf ids via `getChildren`, which is generic over strings.\n */\n getPose?: (id: string) => TPose | null;\n outline?: Stroke & { pad?: number };\n /** Pass `false` to render outlines only. */\n handles?: SelectionHandleStyle | false;\n handlesOf?: (bounds: Bounds) => { x: number; y: number }[];\n /** Draw a rotate badge above the selection's top edge. `true` places it at\n * the default offset; `distance` sets the offset in screen pixels. Off by\n * default. */\n rotationHandle?:\n | boolean\n | {\n distance?: number;\n };\n /** Optional separate id list for the per-item outline pass. Use this in\n * multi-selection contexts where the handle pass works against a synthetic\n * union id (e.g. `MULTI_RESIZE_TARGET_ID`) but consumers still want to\n * see outlines around each real member. When omitted, the outline pass\n * uses the same `getSelection` ids as the handle pass. */\n getOutlineIds?: () => readonly NodeId[];\n /** Optional set of ids to suppress entirely — both outline and handles\n * are skipped. Used by SceneCanvas to hide the standard selection\n * chrome on the node currently in path-anchor edit mode, where the\n * per-anchor chrome takes over. */\n getSuppressedIds?: () => ReadonlySet<string>;\n}\n\nconst DEFAULT_OUTLINE: Required<Pick<Stroke, 'paint' | 'width'>> & { pad: number } = {\n paint: { fill: 'solid', color: '#f0e0a8' },\n width: 2,\n pad: 1,\n};\nconst DEFAULT_HANDLE_FILL: FillStyle = { fill: 'solid', color: '#d4c4a8' };\nconst DEFAULT_HANDLE_OUTLINE: Stroke = {\n paint: { fill: 'solid', color: '#1a130d' },\n width: 1,\n};\nconst DEFAULT_HANDLE_SIZE = HANDLE_BASE_PX;\n\nfunction defaultHandlesOf(b: Bounds): { x: number; y: number }[] {\n return [\n { x: b.x, y: b.y },\n { x: b.x + b.width, y: b.y },\n { x: b.x, y: b.y + b.height },\n { x: b.x + b.width, y: b.y + b.height },\n ];\n}\n\nfunction resolveOutlineStroke(opts?: Stroke & { pad?: number }): {\n stroke: Stroke;\n pad: number;\n} {\n if (!opts) {\n return {\n stroke: { paint: DEFAULT_OUTLINE.paint, width: DEFAULT_OUTLINE.width },\n pad: DEFAULT_OUTLINE.pad,\n };\n }\n return {\n stroke: {\n paint: opts.paint,\n width: opts.width ?? DEFAULT_OUTLINE.width,\n dash: opts.dash,\n cap: opts.cap,\n join: opts.join,\n align: opts.align,\n },\n pad: opts.pad ?? DEFAULT_OUTLINE.pad,\n };\n}\n\n/** Handle visuals, as a consumer supplies them. */\nexport interface SelectionHandleStyle {\n size?: number;\n fill?: FillStyle;\n outline?: Stroke;\n}\n\ninterface ResolvedHandles {\n size: number;\n fill: FillStyle;\n outline: Stroke;\n}\n\nfunction resolveHandles(opts?: SelectionHandleStyle): ResolvedHandles {\n return {\n size: opts?.size ?? DEFAULT_HANDLE_SIZE,\n fill: opts?.fill ?? DEFAULT_HANDLE_FILL,\n outline: opts?.outline ?? DEFAULT_HANDLE_OUTLINE,\n };\n}\n\n/**\n * GL helper: build the matrix `translate(cx, cy) * rotate(θ) * translate(-cx, -cy)`\n * used to wrap rotated outline / handle commands.\n */\nfunction rotateAroundMat3(cx: number, cy: number, theta: number): GlMat3 {\n const c = Math.cos(theta);\n const s = Math.sin(theta);\n // Composed in column-major (matches mat3 helpers): T(cx,cy) · R(θ) · T(-cx,-cy).\n // After expansion: a=c, b=s, c'=-s, d=c, tx=cx - c*cx + s*cy, ty=cy - s*cx - c*cy.\n const tx = cx - c * cx + s * cy;\n const ty = cy - s * cx - c * cy;\n return new Float32Array([\n c, s, 0,\n -s, c, 0,\n tx, ty, 1,\n ]) as GlMat3;\n}\n\n/** GL helper: emit a closed rect path (kind:'rect'). */\nfunction rectPathFor(x: number, y: number, width: number, height: number): { kind: 'rect'; x: number; y: number; width: number; height: number } {\n return { kind: 'rect', x, y, width, height };\n}\n\n/** GL helper: emit an outline command for one bounds entry. */\nfunction outlineCommandsFor(\n ids: readonly string[],\n resolveBounds: (id: string) => Bounds | null,\n stroke: Stroke,\n pad: number,\n view: View,\n): DrawCommand[] {\n const out: DrawCommand[] = [];\n const align = stroke.align ?? 'center';\n const width = resolveStrokeWidth(stroke.width ?? 1, 1);\n for (const id of ids) {\n const worldB = resolveBounds(id);\n if (!worldB) continue;\n const b = projectBounds(worldB, view);\n const padded = {\n x: b.x - pad,\n y: b.y - pad,\n width: b.width + pad * 2,\n height: b.height + pad * 2,\n };\n const rot = poseRotationOf(worldB);\n if (!rot) {\n const r = alignedStrokeRect(padded, align, width);\n out.push({ kind: 'path', path: rectPathFor(r.x, r.y, r.width, r.height), stroke });\n continue;\n }\n // Turned, the target lands on screen as a parallelogram whenever the zoom\n // is non-uniform, so the outline is traced through its projected corners\n // rather than drawn as a screen rect and turned. `alignedStrokeRect`'s\n // shift is folded into the offset so the ribbon lands where it would.\n const shift = align === 'outer' ? width / 2 : align === 'inner' ? -width / 2 : 0;\n const q = screenCorners(worldB, rot, view, pad + shift);\n out.push({\n kind: 'path',\n path: {\n kind: 'polygon',\n commands: new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L, PATH_Z]),\n coords: new Float32Array([q[0].x, q[0].y, q[1].x, q[1].y, q[2].x, q[2].y, q[3].x, q[3].y]),\n fillRule: 'nonzero',\n },\n stroke: { ...stroke, align: 'center' },\n });\n }\n return out;\n}\n\n/**\n * A turned target's corners on screen, TL/TR/BR/BL, each pushed `pad` screen\n * pixels out from both edges that meet there.\n */\nfunction screenCorners(\n worldB: Bounds,\n rot: { cx: number; cy: number; rotation: number },\n view: View,\n pad: number,\n): { x: number; y: number }[] {\n const t = viewToTransform(view);\n const q = rectCorners(worldB).map((c) => {\n const w = rotatePoint(c.x, c.y, rot.cx, rot.cy, rot.rotation);\n const [x, y] = worldToScreen(w.x, w.y, t);\n return { x, y };\n });\n if (pad === 0) return q;\n const [ccx, ccy] = worldToScreen(rot.cx, rot.cy, t);\n const normal = (a: { x: number; y: number }, b: { x: number; y: number }) => {\n let nx = -(b.y - a.y), ny = b.x - a.x;\n const l = Math.hypot(nx, ny) || 1;\n nx /= l; ny /= l;\n const mx = (a.x + b.x) / 2 - ccx, my = (a.y + b.y) / 2 - ccy;\n return nx * mx + ny * my < 0 ? { x: -nx, y: -ny } : { x: nx, y: ny };\n };\n return q.map((c, i) => {\n const n1 = normal(q[(i + 3) % 4], c);\n const n2 = normal(c, q[(i + 1) % 4]);\n // The point `pad` off both edge lines.\n const k = pad / (1 + n1.x * n2.x + n1.y * n2.y);\n return { x: c.x + (n1.x + n2.x) * k, y: c.y + (n1.y + n2.y) * k };\n });\n}\n\n/** GL helper: emit handle fill+stroke commands for one bounds entry. */\nfunction handleCommandsFor(\n ids: readonly string[],\n resolveBounds: (id: string) => Bounds | null,\n handles: ResolvedHandles,\n handlesOf: (b: Bounds) => { x: number; y: number }[],\n view: View,\n): DrawCommand[] {\n const out: DrawCommand[] = [];\n const half = handles.size / 2;\n const handleAlign = handles.outline.align ?? 'center';\n const handleWidth = resolveStrokeWidth(handles.outline.width ?? 1, 1);\n for (const id of ids) {\n const worldB = resolveBounds(id);\n if (!worldB) continue;\n // Rotation gate + angle from the kit's one convention. Turned in world,\n // then projected: turning the projected point instead lands somewhere else\n // under non-uniform zoom.\n const r = poseRotationOf(worldB);\n const t = viewToTransform(view);\n const angle = r ? screenAngleOf(r.rotation, view.scale) : 0;\n for (const hLocal of handlesOf(worldB)) {\n const hWorld = r ? rotatePoint(hLocal.x, hLocal.y, r.cx, r.cy, r.rotation) : hLocal;\n const [hsx, hsy] = worldToScreen(hWorld.x, hWorld.y, t);\n const center = { x: hsx, y: hsy };\n const baseRect = {\n x: center.x - half,\n y: center.y - half,\n width: handles.size,\n height: handles.size,\n };\n const sr = alignedStrokeRect(baseRect, handleAlign, handleWidth);\n const fillCmd: DrawCommand = {\n kind: 'path',\n path: rectPathFor(baseRect.x, baseRect.y, baseRect.width, baseRect.height),\n fill: handles.fill,\n };\n const strokeCmd: DrawCommand = {\n kind: 'path',\n path: rectPathFor(sr.x, sr.y, sr.width, sr.height),\n stroke: handles.outline,\n };\n if (!r) {\n out.push(fillCmd, strokeCmd);\n } else {\n out.push({\n kind: 'group',\n transform: rotateAroundMat3(center.x, center.y, angle),\n children: [fillCmd, strokeCmd],\n });\n }\n }\n }\n return out;\n}\n\n/** GL helper: emit a curved double-headed arrow indicating bidirectional\n * rotation. The arc opens *toward* the object (apex on top, mouth pointing\n * down) so the affordance reads as a small \"rotate\" badge sitting above\n * the rect. Two arrowheads at the arc endpoints point along the tangent,\n * signaling that rotation goes either direction. */\nfunction rotationHandleCommands(\n worldB: Bounds,\n handles: ResolvedHandles,\n distance: number,\n view: View,\n): DrawCommand[] {\n const hWorld = rotationHandle(worldB, distance, view.scale);\n const rotation = hWorld.angle;\n const t = viewToTransform(view);\n const [scx, scy] = worldToScreen(hWorld.cx, hWorld.cy, t);\n const size = handles.size;\n const arcRadius = size;\n // Arc spans ~240° (from 150° to -30° measured from arc center, going\n // CCW). The arc center is the handle anchor; the arc itself bulges\n // *toward the rect* (downward, since the handle sits above the AABB).\n const ARC_HALF_ANGLE = (Math.PI * 240) / 360 / 2; // 120°\n const N_SEGS = 18;\n const arcWidth = resolveStrokeWidth(handles.outline.width ?? 1, 1) * 1.5;\n const stroke: Stroke = {\n paint: handles.fill,\n width: arcWidth,\n cap: 'round',\n join: 'round',\n };\n // Build the arc as a polyline in handle-local coords. Arc bulges *away*\n // from the rect (upward in canvas space, since the handle sits above the\n // AABB top edge): apex at -y, endpoints at +y near the rect side.\n const cmds: number[] = [PATH_M];\n const xs: number[] = [];\n const ys: number[] = [];\n for (let i = 0; i <= N_SEGS; i++) {\n const t = i / N_SEGS;\n const angle = ARC_HALF_ANGLE - t * ARC_HALF_ANGLE * 2;\n xs.push(arcRadius * Math.sin(angle));\n ys.push(-arcRadius * Math.cos(angle));\n if (i > 0) cmds.push(PATH_L);\n }\n const arcCoords: number[] = [];\n for (let i = 0; i < xs.length; i++) {\n arcCoords.push(xs[i], ys[i]);\n }\n const arcPath: PolygonPath = {\n kind: 'polygon',\n commands: new Uint8Array(cmds),\n coords: new Float32Array(arcCoords),\n fillRule: 'nonzero',\n };\n // Arrowheads: small filled triangles at each endpoint, pointing along\n // the tangent (away from the arc body). Tangent at endpoint = derivative\n // of (sin(angle), cos(angle)) wrt angle = (cos(angle), -sin(angle)).\n // At +ARC_HALF_ANGLE the tangent points \"outward and slightly up\"; at\n // -ARC_HALF_ANGLE the tangent points the other way.\n const headLen = size * 0.6;\n const headWidth = size * 0.4;\n const arrowHead = (endX: number, endY: number, tx: number, ty: number): PolygonPath => {\n // Normalize tangent.\n const len = Math.hypot(tx, ty) || 1;\n const ux = tx / len;\n const uy = ty / len;\n // Perpendicular (rotate tangent 90° CCW).\n const px = -uy;\n const py = ux;\n // Triangle: tip is endX+ux*headLen, base is endX (with +/- headWidth/2 along p).\n const tipX = endX + ux * headLen;\n const tipY = endY + uy * headLen;\n const baseLeftX = endX + px * (headWidth / 2);\n const baseLeftY = endY + py * (headWidth / 2);\n const baseRightX = endX - px * (headWidth / 2);\n const baseRightY = endY - py * (headWidth / 2);\n return {\n kind: 'polygon',\n commands: new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L]),\n coords: new Float32Array([tipX, tipY, baseLeftX, baseLeftY, baseRightX, baseRightY, tipX, tipY]),\n fillRule: 'nonzero',\n };\n };\n // Endpoint A (right side, angle = +ARC_HALF_ANGLE). Arc point:\n // (sin(a)·R, -cos(a)·R). Tangent (d/da) = (cos(a)·R, sin(a)·R) — points\n // outward/down at the right end. Use as \"rotate further clockwise\" arrow.\n const angleA = ARC_HALF_ANGLE;\n const endAX = arcRadius * Math.sin(angleA);\n const endAY = -arcRadius * Math.cos(angleA);\n const tangentAX = Math.cos(angleA);\n const tangentAY = Math.sin(angleA);\n // Endpoint B (left side, angle = -ARC_HALF_ANGLE): tangent in the\n // outward direction is the negation of the above.\n const angleB = -ARC_HALF_ANGLE;\n const endBX = arcRadius * Math.sin(angleB);\n const endBY = -arcRadius * Math.cos(angleB);\n const tangentBX = -Math.cos(angleB);\n const tangentBY = -Math.sin(angleB);\n const headA = arrowHead(endAX, endAY, tangentAX, tangentAY);\n const headB = arrowHead(endBX, endBY, tangentBX, tangentBY);\n const headFill: FillStyle = handles.fill;\n // Build transform: translate(scx, scy) [* rotate(rotation)].\n let transform = mat3.translated(mat3.identity(), scx, scy);\n if (rotation !== 0) {\n const c = Math.cos(rotation);\n const s = Math.sin(rotation);\n const rot = new Float32Array([c, s, 0, -s, c, 0, 0, 0, 1]) as GlMat3;\n transform = mat3.multiply(transform, rot);\n }\n return [\n {\n kind: 'group',\n transform,\n children: [\n { kind: 'path', path: arcPath, stroke },\n { kind: 'path', path: headA, fill: headFill },\n { kind: 'path', path: headB, fill: headFill },\n ],\n },\n ];\n}\n\n/** Which passes a selection layer runs. The three exported factories differ\n * only in this — everything else they do is shared, so a fix to one is a fix\n * to all three. */\ninterface SelectionPasses {\n readonly id: string;\n readonly label: string;\n readonly outline: boolean;\n readonly handles: boolean;\n}\n\nfunction buildSelectionLayer<TPose>(\n opts: SelectionOverlayLayerOpts<TPose>,\n passes: SelectionPasses,\n): RenderLayer<unknown> {\n const { stroke, pad } = resolveOutlineStroke(opts.outline);\n const handlesEnabled = passes.handles && opts.handles !== false;\n const handles = handlesEnabled ? resolveHandles(opts.handles || undefined) : null;\n const handlesOf = opts.handlesOf ?? defaultHandlesOf;\n const d = (opts.poseDescriptor ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<TPose>;\n const getPose = opts.getPose;\n const poseBounds = getPose\n ? makeContainerAwareBoundsResolver(getPose, d, opts.getChildren, opts.isContainer)\n : null;\n const rotationHandleDistance = passes.handles\n ? rotationBadgeOf(opts)?.distancePx ?? null\n : null;\n\n return {\n id: passes.id,\n label: passes.label,\n space: 'screen',\n draw: (data, view) => {\n // The synthetic multi-resize id resolves to `ChromeState.unionBounds`,\n // the single owner of the multi-selection union AABB — the same value\n // the affordance hit-tester (`affordanceAt` / `composeAffordanceLayer`)\n // reads, so painted chrome and its hit region stay in agreement. When\n // no chromeState rides the draw envelope (bare/test callers), fall\n // through to the supplied resolver so they can synthesize it via\n // `getPose`.\n const chromeState = asChromeState(data);\n const allIds = opts.getSelection\n ? opts.getSelection()\n : chromeSelectionIds(chromeState);\n if (allIds.length === 0) return [];\n const suppressed = opts.getSuppressedIds?.();\n const ids = suppressed && suppressed.size > 0\n ? allIds.filter((id) => !suppressed.has(id as unknown as string))\n : allIds;\n if (ids.length === 0) return [];\n // Chrome-caps: gate each of the three passes (outline, resize\n // handles, rotation handle) on its canonical id. When no\n // `getIsVisible` is wired (legacy callers / tests), every pass\n // runs — preserving pre-chrome-caps behavior.\n const isVisible = asIsVisible(data);\n const showOutline = passes.outline && (isVisible ? isVisible('selection.outline') : true);\n const showHandles = isVisible ? isVisible('selection.resize-handles') : true;\n const showRotation = isVisible ? isVisible('selection.rotation-handle') : true;\n\n const resolveBounds = poseBounds ?? ((id: string) => chromeState?.boundsOf(id) ?? null);\n const resolveTargetBounds = (id: string): Bounds | null => {\n if (id === MULTI_RESIZE_TARGET_ID && chromeState?.unionBounds != null) {\n return chromeState.unionBounds;\n }\n return resolveBounds(id);\n };\n\n const out: DrawCommand[] = [];\n if (showOutline) {\n const outlineIdsRaw = opts.getOutlineIds\n ? opts.getOutlineIds()\n : (opts.getSelection ? ids : (chromeState?.selection ?? ids));\n const outlineIds = suppressed && suppressed.size > 0\n ? outlineIdsRaw.filter((id) => !suppressed.has(id as unknown as string))\n : outlineIdsRaw;\n for (const cmd of outlineCommandsFor(outlineIds, resolveTargetBounds, stroke, pad, view)) out.push(cmd);\n }\n if (!handles) return out;\n if (showHandles) {\n for (const cmd of handleCommandsFor(ids, resolveTargetBounds, handles, handlesOf, view)) out.push(cmd);\n }\n if (showRotation && rotationHandleDistance !== null) {\n for (const id of ids) {\n const b = resolveTargetBounds(id);\n if (!b) continue;\n for (const cmd of rotationHandleCommands(b, handles, rotationHandleDistance, view)) {\n out.push(cmd);\n }\n }\n }\n return out;\n },\n };\n}\n\n/** Where the overlay paints its rotate badge and how big it is, in screen\n * pixels, or `null` when it paints none. The badge's grab region and its\n * slops halo read this too, so all three agree on it. */\nexport function rotationBadgeOf(\n opts: Pick<SelectionOverlayLayerOpts<unknown>, 'handles' | 'rotationHandle'>,\n): { distancePx: number; sizePx: number } | null {\n const r = opts.rotationHandle;\n if (!r || opts.handles === false) return null;\n return {\n distancePx: r === true ? DEFAULT_ROTATION_HANDLE_DISTANCE : r.distance ?? DEFAULT_ROTATION_HANDLE_DISTANCE,\n sizePx: resolveHandles(opts.handles || undefined).size,\n };\n}\n/**\n * `RenderLayer` that draws selection outlines only. Stack alongside\n * `createSelectionHandlesLayer` (or use `createSelectionOverlayLayer`, which\n * runs both passes in one layer) when both are wanted.\n */\nexport function createSelectionOutlineLayer<TPose>(\n opts: SelectionOutlineLayerOpts<TPose>,\n): RenderLayer<unknown> {\n return buildSelectionLayer(opts, {\n id: 'selection-outline',\n label: 'Selection outline',\n outline: true,\n handles: false,\n });\n}\n\n/**\n * `RenderLayer` that draws selection handles only. Stack on top of\n * `createSelectionOutlineLayer` (handles render on top of the outline).\n */\nexport function createSelectionHandlesLayer<TPose>(\n opts: SelectionHandlesLayerOpts<TPose>,\n): RenderLayer<unknown> {\n return buildSelectionLayer(opts, {\n id: 'selection-handles',\n label: 'Selection handles',\n outline: false,\n handles: true,\n });\n}\n\n/**\n * Draws outlines then handles in a single layer. Exactly equivalent to\n * stacking `createSelectionOutlineLayer` and `createSelectionHandlesLayer` —\n * all three run the same body. Pass `handles: false` to render outlines only.\n */\nexport function createSelectionOverlayLayer<TPose>(\n opts: SelectionOverlayLayerOpts<TPose>,\n): RenderLayer<unknown> {\n return buildSelectionLayer(opts, {\n id: 'selection-overlay',\n label: 'Selection',\n outline: true,\n handles: true,\n });\n}\n\n/** Pull a chrome-caps visibility predicate off the draw `data` envelope.\n * Returns `null` when the caller passed bare data (no `getIsVisible`\n * thunk) — the layer then renders unconditionally, matching pre-\n * chrome-caps behavior. */\nfunction asIsVisible(data: unknown): ((id: string) => boolean) | null {\n const maybe = data as { getIsVisible?: () => (id: string) => boolean };\n if (typeof maybe?.getIsVisible === 'function') return maybe.getIsVisible();\n return null;\n}\n\n/** The ids the handle pass works against when the layer takes its selection\n * from the envelope: the synthetic union id for a multi-selection, the\n * selection itself otherwise. */\nfunction chromeSelectionIds(state: ChromeState | null): readonly NodeId[] {\n if (!state) return [];\n if (state.multiActive) return [MULTI_RESIZE_TARGET_ID as NodeId];\n return state.selection;\n}\n\n/** Pull live `ChromeState` off the draw `data` envelope (the same channel\n * `composeAffordanceLayer` uses). Returns `null` for bare/test callers that\n * pass plain data with no `getChromeState` thunk — the layer then resolves\n * the multi-union via the supplied `getPose` resolver, preserving pre-\n * chromeState behavior. */\nfunction asChromeState(data: unknown): ChromeState | null {\n const maybe = data as { getChromeState?: () => ChromeState };\n if (typeof maybe?.getChromeState === 'function') return maybe.getChromeState();\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"overlay.js","names":["projectBounds","t","viewToTransform","view","sx","sy","worldToScreen","b","leavesOf","isContainer","id","out","visit","kids","getChildren","nid","k","composeSelectionPose","opts","d","AUTO_POSE_DESCRIPTOR","selectionLeaves","resolveLeaf","moved","moveOverlay","resizeOverlay","getStoredPose","leaves","containerResizeLeafPoses","leafBounds","leafId","visualBoundsViaDescriptor","overlayLeaf","u","unionAABB","makeContainerAwareBoundsResolver","oriented","framedBounds","p","getPose","DEFAULT_OUTLINE","DEFAULT_HANDLE_FILL","DEFAULT_HANDLE_OUTLINE","DEFAULT_HANDLE_SIZE","HANDLE_BASE_PX","defaultHandlesOf","resolveOutlineStroke","resolveHandles","rotateAroundMat3","c","theta","s","tx","cx","cy","ty","rectPathFor","outlineCommandsFor","align","stroke","width","resolveStrokeWidth","ids","worldB","resolveBounds","padded","pad","xf","targetTransformOf","r","alignedStrokeRect","q","screenCorners","PATH_M","PATH_L","PATH_Z","targetCorners","x","y","w","ccx","ccy","normal","nx","a","ny","l","mx","my","n1","i","n2","handleCommandsFor","half","handles","handleAlign","handleWidth","angle","screenAngleOf","angleOf","hLocal","handlesOf","hWorld","localToWorld","hsx","hsy","center","baseRect","sr","fillCmd","strokeCmd","rotationHandleCommands","rotationHandle","distance","rotation","scx","scy","size","arcRadius","ARC_HALF_ANGLE","arcWidth","cmds","xs","ys","arcCoords","arcPath","headLen","headWidth","arrowHead","len","ux","uy","px","py","tipX","endX","tipY","endY","baseLeftX","baseLeftY","baseRightX","baseRightY","angleA","endAX","endAY","tangentAX","tangentAY","angleB","endBX","endBY","tangentBX","tangentBY","headA","headB","transform","mat3","rot","buildSelectionLayer","passes","poseBounds","rotationHandleDistance","rotationBadgeOf","chromeState","asChromeState","data","allIds","chromeSelectionIds","suppressed","isVisible","asIsVisible","showOutline","showHandles","showRotation","resolveTargetBounds","MULTI_RESIZE_TARGET_ID","outlineIdsRaw","outlineIds","cmd","DEFAULT_ROTATION_HANDLE_DISTANCE","createSelectionOutlineLayer","createSelectionHandlesLayer","createSelectionOverlayLayer","maybe","state"],"sources":["../../../src/features/selection/overlay.ts"],"sourcesContent":["/**\n * Selection overlay primitives — render layers for drawing selection\n * outlines and corner resize handles.\n *\n * **Pose shape:** TPose is generic; callers pass `poseDescriptor` for poses\n * `AUTO_POSE_DESCRIPTOR` can't read. Container ids reduce via `unionAABB`\n * over the projected AABBs.\n */\n\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport { mat3, type GlMat3 } from '@weasel-js/renderer';\nimport type { NodeId } from 'core/scene/types';\nimport type { RenderLayer } from 'core/layers/render';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport {\n framedBounds,\n visualBoundsViaDescriptor,\n type PoseDescriptor,\n} from 'core/geometry/poseDescriptor';\nimport { angleOf, localToWorld, targetCorners, targetTransformOf, type TargetTransform } from 'core/geometry/targetFrame';\nimport { AUTO_POSE_DESCRIPTOR } from 'core/geometry/autoPoseDescriptor';\nimport { alignedStrokeRect, type CommandStroke, type CommandFill } from '@weasel-js/paint';\nimport { resolveStrokeWidth } from '@weasel-js/stroke';\nimport {\n rotationHandle,\n DEFAULT_ROTATION_HANDLE_DISTANCE,\n} from 'interactions/actions/rotate/handle';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { ChromeState } from 'core/selection/chromeState';\nimport { MULTI_RESIZE_TARGET_ID } from 'core/selection/selectionTarget';\nimport type { View } from 'core/viewport/view';\nimport { viewToTransform } from 'core/viewport/view';\nimport { worldToScreen } from 'core/viewport/viewTransform';\nimport { screenAngleOf } from '@weasel-js/geom';\nimport { PATH_L, PATH_M, PATH_Z, type PolygonPath } from '@weasel-js/geom';\nimport { HANDLE_BASE_PX } from 'core/device/targets';\n\n/** Project world AABB into screen-space AABB using the active view. */\nfunction projectBounds<B extends Bounds>(b: B, view: View): B {\n const t = viewToTransform(view);\n const [sx, sy] = worldToScreen(b.x, b.y, t);\n return { ...b, x: sx, y: sy, width: b.width * view.scale.x, height: b.height * view.scale.y };\n}\n\n\n/**\n * Transitive leaf ids under `id`. A childless node is a leaf only if it is not\n * itself a container: an empty container contributes no bounds, and its own\n * stored pose is at its most stale when no children are left to have moved it.\n */\nfunction leavesOf(\n id: string,\n getChildren: (id: string) => readonly string[],\n isContainer: (id: string) => boolean,\n): string[] {\n if (!isContainer(id)) return [id];\n const out: string[] = [];\n const visit = (nid: string) => {\n const kids = getChildren(nid);\n if (kids.length === 0) { if (!isContainer(nid)) out.push(nid); return; }\n for (const k of kids) visit(k);\n };\n visit(id);\n return out;\n}\n\n/** Options for `composeSelectionPose`. */\nexport interface ComposeSelectionPoseOpts<TPose> {\n /** Move overlay; when present its `poses` map wins over everything else. */\n moveOverlay?: { poses: Map<string, TPose> } | null;\n /**\n * Resize overlay; consulted only when move overlay does not own the id.\n * For container resize, `leafPoses` (when present) maps each leaf id under\n * the container to its overlay pose. If absent the container falls back to\n * stored leaf poses.\n */\n resizeOverlay?: {\n id: string;\n currentPose: TPose;\n leafPoses?: Map<string, TPose>;\n } | null;\n /** Fallback pose lookup (typically the stored/committed pose). */\n getStoredPose: (id: string) => TPose;\n /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<TPose>;\n /** Walk a container's direct children (e.g. `scene.childrenOf`). With\n * `isContainer`, a selected container resolves to the union AABB of its\n * transitive leaf poses instead of its own stored pose. */\n getChildren?: (id: string) => readonly string[];\n /** True when `id` is a structural container. */\n isContainer?: (id: string) => boolean;\n}\n\n/**\n * Build a pose resolver for a selection. Precedence per id:\n * move overlay > resize overlay > stored. When `getChildren`/`isContainer`\n * are supplied and the id resolves to a container, the resolver returns the\n * union AABB of all transitive leaf poses (each leaf still subject to the\n * precedence rules). Containers with no leaves resolve to `null`.\n */\nexport function composeSelectionPose<TPose>(\n opts: ComposeSelectionPoseOpts<TPose>,\n): (id: string) => TPose | null {\n const { moveOverlay, resizeOverlay, getStoredPose, getChildren, isContainer } = opts;\n const d = (opts.poseDescriptor ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<TPose>;\n\n const selectionLeaves = (id: string): string[] =>\n getChildren && isContainer ? leavesOf(id, getChildren, isContainer) : [id];\n\n const resolveLeaf = (id: string): TPose => {\n const moved = moveOverlay?.poses.get(id);\n if (moved !== undefined) return moved;\n if (resizeOverlay && resizeOverlay.id === id) return resizeOverlay.currentPose;\n return getStoredPose(id);\n };\n\n return (id: string): TPose | null => {\n if (isContainer?.(id)) {\n const leaves = selectionLeaves(id);\n if (leaves.length === 0) return null;\n const containerResizeLeafPoses =\n resizeOverlay && resizeOverlay.id === id ? resizeOverlay.leafPoses : undefined;\n const leafBounds: Bounds[] = [];\n for (const leafId of leaves) {\n const moved = moveOverlay?.poses.get(leafId);\n if (moved !== undefined) {\n leafBounds.push(visualBoundsViaDescriptor(moved, d));\n continue;\n }\n const overlayLeaf = containerResizeLeafPoses?.get(leafId);\n if (overlayLeaf !== undefined) {\n leafBounds.push(visualBoundsViaDescriptor(overlayLeaf, d));\n continue;\n }\n leafBounds.push(visualBoundsViaDescriptor(getStoredPose(leafId), d));\n }\n const u = unionAABB(leafBounds);\n if (u === null) return null;\n return d.fromBounds(u, getStoredPose(leaves[0]!));\n }\n return resolveLeaf(id);\n };\n}\n\n/**\n * Build a pose resolver that handles container ids by computing the union\n * AABB of every leaf's bounds. Non-container ids pass through directly. When\n * `getChildren`/`isContainer` are omitted, every id is treated as a leaf.\n */\nfunction makeContainerAwareBoundsResolver<TPose>(\n getPose: (id: string) => TPose | null,\n d: PoseDescriptor<TPose>,\n getChildren?: (id: string) => readonly string[],\n isContainer?: (id: string) => boolean,\n): (id: string) => Bounds | null {\n const oriented = (p: TPose): Bounds => framedBounds(p, d);\n if (getChildren === undefined || isContainer === undefined) {\n return (id: string) => {\n const p = getPose(id);\n return p === null ? null : oriented(p);\n };\n }\n return (id: string): Bounds | null => {\n if (!isContainer(id)) {\n const p = getPose(id);\n return p === null ? null : oriented(p);\n }\n const leaves = leavesOf(id, getChildren, isContainer);\n if (leaves.length === 0) return null;\n const leafBounds: Bounds[] = [];\n for (const leafId of leaves) {\n const p = getPose(leafId);\n if (p !== null) leafBounds.push(visualBoundsViaDescriptor(p, d));\n }\n if (leafBounds.length === 0) return null;\n return unionAABB(leafBounds);\n };\n}\n\n/** Options every selection layer shares. `getSelection` and `getPose` are\n * declared on {@link SelectionOverlayLayerOpts}, which makes both optional —\n * omitted, they come off the draw envelope. */\ninterface SelectionLayerCommon<TPose> {\n /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<TPose>;\n /** Walk a container's direct children (e.g. `scene.childrenOf`). When\n * supplied with `isContainer`, any id that resolves to a container is\n * rendered using the union bounds of all its transitive leaves. */\n getChildren?: (id: string) => readonly string[];\n /** True when `id` is a structural container. */\n isContainer?: (id: string) => boolean;\n}\n\n/** Options for `createSelectionOutlineLayer`. The overlay layer's options\n * minus the handle visuals — the two run the same body. */\nexport type SelectionOutlineLayerOpts<TPose> =\n Omit<SelectionOverlayLayerOpts<TPose>, 'handles' | 'handlesOf' | 'rotationHandle'>;\n\n/** Options for `createSelectionHandlesLayer`. The overlay layer's options\n * minus the outline stroke — the two run the same body. */\nexport type SelectionHandlesLayerOpts<TPose> =\n Omit<SelectionOverlayLayerOpts<TPose>, 'outline'>;\n\n/** Options for `createSelectionOverlayLayer`. */\nexport interface SelectionOverlayLayerOpts<TPose>\n extends SelectionLayerCommon<TPose> {\n /**\n * Which ids to draw chrome for. Omit to take them from the `ChromeState` on\n * the draw envelope, which is what makes one canvas's several views each\n * outline their own selection — the layer is shared, the envelope is not.\n */\n getSelection?: () => readonly NodeId[];\n /**\n * Resolve an id to the pose to draw chrome around. Return null to skip an\n * id. Omit to take bounds from the same envelope `getSelection` omitted\n * takes ids from.\n *\n * Takes `string` rather than `NodeId` because the container-aware resolver\n * walks expanded leaf ids via `getChildren`, which is generic over strings.\n */\n getPose?: (id: string) => TPose | null;\n outline?: CommandStroke & { pad?: number };\n /** Pass `false` to render outlines only. */\n handles?: SelectionHandleStyle | false;\n handlesOf?: (bounds: Bounds) => { x: number; y: number }[];\n /** Draw a rotate badge above the selection's top edge. `true` places it at\n * the default offset; `distance` sets the offset in screen pixels. Off by\n * default. */\n rotationHandle?:\n | boolean\n | {\n distance?: number;\n };\n /** Optional separate id list for the per-item outline pass, for a\n * multi-selection whose handle pass works against a synthetic union id\n * (e.g. `MULTI_RESIZE_TARGET_ID`) while each real member is outlined.\n * When omitted, the outline pass uses the handle pass's ids. */\n getOutlineIds?: () => readonly NodeId[];\n /** Optional set of ids to suppress entirely — both outline and handles\n * are skipped. */\n getSuppressedIds?: () => ReadonlySet<string>;\n}\n\nconst DEFAULT_OUTLINE: Required<Pick<CommandStroke, 'paint' | 'width'>> & { pad: number } = {\n paint: { kind: 'solid', color: '#f0e0a8' },\n width: 2,\n pad: 1,\n};\nconst DEFAULT_HANDLE_FILL: CommandFill = { paint: { kind: 'solid', color: '#d4c4a8' } };\nconst DEFAULT_HANDLE_OUTLINE: CommandStroke = {\n paint: { kind: 'solid', color: '#1a130d' },\n width: 1,\n};\nconst DEFAULT_HANDLE_SIZE = HANDLE_BASE_PX;\n\nfunction defaultHandlesOf(b: Bounds): { x: number; y: number }[] {\n return [\n { x: b.x, y: b.y },\n { x: b.x + b.width, y: b.y },\n { x: b.x, y: b.y + b.height },\n { x: b.x + b.width, y: b.y + b.height },\n ];\n}\n\nfunction resolveOutlineStroke(opts?: CommandStroke & { pad?: number }): {\n stroke: CommandStroke;\n pad: number;\n} {\n if (!opts) {\n return {\n stroke: { paint: DEFAULT_OUTLINE.paint, width: DEFAULT_OUTLINE.width },\n pad: DEFAULT_OUTLINE.pad,\n };\n }\n return {\n stroke: {\n paint: opts.paint,\n width: opts.width ?? DEFAULT_OUTLINE.width,\n dash: opts.dash,\n cap: opts.cap,\n join: opts.join,\n align: opts.align,\n },\n pad: opts.pad ?? DEFAULT_OUTLINE.pad,\n };\n}\n\n/** Handle visuals, as a consumer supplies them. */\nexport interface SelectionHandleStyle {\n size?: number;\n fill?: CommandFill;\n outline?: CommandStroke;\n}\n\ninterface ResolvedHandles {\n size: number;\n fill: CommandFill;\n outline: CommandStroke;\n}\n\nfunction resolveHandles(opts?: SelectionHandleStyle): ResolvedHandles {\n return {\n size: opts?.size ?? DEFAULT_HANDLE_SIZE,\n fill: opts?.fill ?? DEFAULT_HANDLE_FILL,\n outline: opts?.outline ?? DEFAULT_HANDLE_OUTLINE,\n };\n}\n\n/**\n * GL helper: build the matrix `translate(cx, cy) * rotate(θ) * translate(-cx, -cy)`\n * used to wrap rotated outline / handle commands.\n */\nfunction rotateAroundMat3(cx: number, cy: number, theta: number): GlMat3 {\n const c = Math.cos(theta);\n const s = Math.sin(theta);\n // Composed in column-major (matches mat3 helpers): T(cx,cy) · R(θ) · T(-cx,-cy).\n // After expansion: a=c, b=s, c'=-s, d=c, tx=cx - c*cx + s*cy, ty=cy - s*cx - c*cy.\n const tx = cx - c * cx + s * cy;\n const ty = cy - s * cx - c * cy;\n return new Float32Array([\n c, s, 0,\n -s, c, 0,\n tx, ty, 1,\n ]) as GlMat3;\n}\n\n/** GL helper: emit a closed rect path (kind:'rect'). */\nfunction rectPathFor(x: number, y: number, width: number, height: number): { kind: 'rect'; x: number; y: number; width: number; height: number } {\n return { kind: 'rect', x, y, width, height };\n}\n\n/** GL helper: emit an outline command for one bounds entry. */\nfunction outlineCommandsFor(\n ids: readonly string[],\n resolveBounds: (id: string) => Bounds | null,\n stroke: CommandStroke,\n pad: number,\n view: View,\n): DrawCommand[] {\n const out: DrawCommand[] = [];\n const align = stroke.align ?? 'center';\n const width = resolveStrokeWidth(stroke.width ?? 1, 1);\n for (const id of ids) {\n const worldB = resolveBounds(id);\n if (!worldB) continue;\n const b = projectBounds(worldB, view);\n const padded = {\n x: b.x - pad,\n y: b.y - pad,\n width: b.width + pad * 2,\n height: b.height + pad * 2,\n };\n const xf = targetTransformOf(worldB);\n if (xf.identity) {\n const r = alignedStrokeRect(padded, align, width);\n out.push({ kind: 'path', path: rectPathFor(r.x, r.y, r.width, r.height), stroke });\n continue;\n }\n // Turned or skewed, the target lands on screen as a parallelogram, so the\n // outline is traced through its projected corners. `alignedStrokeRect`'s\n // shift is folded into the offset so the ribbon lands where it would.\n const shift = align === 'outer' ? width / 2 : align === 'inner' ? -width / 2 : 0;\n const q = screenCorners(worldB, xf, view, pad + shift);\n out.push({\n kind: 'path',\n path: {\n kind: 'polygon',\n commands: new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L, PATH_Z]),\n coords: new Float32Array([q[0].x, q[0].y, q[1].x, q[1].y, q[2].x, q[2].y, q[3].x, q[3].y]),\n fillRule: 'nonzero',\n },\n stroke: { ...stroke, align: 'center' },\n });\n }\n return out;\n}\n\n/**\n * A framed target's corners on screen, TL/TR/BR/BL, each pushed `pad` screen\n * pixels out from both edges that meet there.\n */\nfunction screenCorners(\n worldB: Bounds,\n xf: TargetTransform,\n view: View,\n pad: number,\n): { x: number; y: number }[] {\n const t = viewToTransform(view);\n const q = targetCorners(worldB, xf).map((w) => {\n const [x, y] = worldToScreen(w.x, w.y, t);\n return { x, y };\n });\n if (pad === 0) return q;\n const [ccx, ccy] = worldToScreen(worldB.x + worldB.width / 2, worldB.y + worldB.height / 2, t);\n const normal = (a: { x: number; y: number }, b: { x: number; y: number }) => {\n let nx = -(b.y - a.y), ny = b.x - a.x;\n const l = Math.hypot(nx, ny) || 1;\n nx /= l; ny /= l;\n const mx = (a.x + b.x) / 2 - ccx, my = (a.y + b.y) / 2 - ccy;\n return nx * mx + ny * my < 0 ? { x: -nx, y: -ny } : { x: nx, y: ny };\n };\n return q.map((c, i) => {\n const n1 = normal(q[(i + 3) % 4], c);\n const n2 = normal(c, q[(i + 1) % 4]);\n // The point `pad` off both edge lines.\n const k = pad / (1 + n1.x * n2.x + n1.y * n2.y);\n return { x: c.x + (n1.x + n2.x) * k, y: c.y + (n1.y + n2.y) * k };\n });\n}\n\n/** GL helper: emit handle fill+stroke commands for one bounds entry. */\nfunction handleCommandsFor(\n ids: readonly string[],\n resolveBounds: (id: string) => Bounds | null,\n handles: ResolvedHandles,\n handlesOf: (b: Bounds) => { x: number; y: number }[],\n view: View,\n): DrawCommand[] {\n const out: DrawCommand[] = [];\n const half = handles.size / 2;\n const handleAlign = handles.outline.align ?? 'center';\n const handleWidth = resolveStrokeWidth(handles.outline.width ?? 1, 1);\n for (const id of ids) {\n const worldB = resolveBounds(id);\n if (!worldB) continue;\n // Framed in world, then projected: turning the projected point instead\n // lands somewhere else under non-uniform zoom.\n const xf = targetTransformOf(worldB);\n const t = viewToTransform(view);\n const angle = screenAngleOf(angleOf(xf), view.scale);\n for (const hLocal of handlesOf(worldB)) {\n const hWorld = localToWorld(xf, hLocal.x, hLocal.y);\n const [hsx, hsy] = worldToScreen(hWorld.x, hWorld.y, t);\n const center = { x: hsx, y: hsy };\n const baseRect = {\n x: center.x - half,\n y: center.y - half,\n width: handles.size,\n height: handles.size,\n };\n const sr = alignedStrokeRect(baseRect, handleAlign, handleWidth);\n const fillCmd: DrawCommand = {\n kind: 'path',\n path: rectPathFor(baseRect.x, baseRect.y, baseRect.width, baseRect.height),\n fill: handles.fill,\n };\n const strokeCmd: DrawCommand = {\n kind: 'path',\n path: rectPathFor(sr.x, sr.y, sr.width, sr.height),\n stroke: handles.outline,\n };\n if (angle === 0) {\n out.push(fillCmd, strokeCmd);\n } else {\n out.push({\n kind: 'group',\n transform: rotateAroundMat3(center.x, center.y, angle),\n children: [fillCmd, strokeCmd],\n });\n }\n }\n }\n return out;\n}\n\n/** GL helper: emit a curved double-headed arrow, the rotate badge above the\n * rect. The arc opens *toward* the object (apex on top, mouth pointing\n * down), with an arrowhead at each endpoint pointing along the tangent. */\nfunction rotationHandleCommands(\n worldB: Bounds,\n handles: ResolvedHandles,\n distance: number,\n view: View,\n): DrawCommand[] {\n const hWorld = rotationHandle(worldB, distance, view.scale);\n const rotation = hWorld.angle;\n const t = viewToTransform(view);\n const [scx, scy] = worldToScreen(hWorld.cx, hWorld.cy, t);\n const size = handles.size;\n const arcRadius = size;\n const ARC_HALF_ANGLE = (Math.PI * 240) / 360 / 2; // 120°\n const N_SEGS = 18;\n const arcWidth = resolveStrokeWidth(handles.outline.width ?? 1, 1) * 1.5;\n const stroke: CommandStroke = {\n paint: handles.fill.paint,\n width: arcWidth,\n cap: 'round',\n join: 'round',\n };\n // The arc as a polyline in handle-local coords, centered on the handle\n // anchor: apex at -y, endpoints at +y near the rect side.\n const cmds: number[] = [PATH_M];\n const xs: number[] = [];\n const ys: number[] = [];\n for (let i = 0; i <= N_SEGS; i++) {\n const t = i / N_SEGS;\n const angle = ARC_HALF_ANGLE - t * ARC_HALF_ANGLE * 2;\n xs.push(arcRadius * Math.sin(angle));\n ys.push(-arcRadius * Math.cos(angle));\n if (i > 0) cmds.push(PATH_L);\n }\n const arcCoords: number[] = [];\n for (let i = 0; i < xs.length; i++) {\n arcCoords.push(xs[i], ys[i]);\n }\n const arcPath: PolygonPath = {\n kind: 'polygon',\n commands: new Uint8Array(cmds),\n coords: new Float32Array(arcCoords),\n fillRule: 'nonzero',\n };\n // Arrowheads: small filled triangles at each endpoint, pointing along\n // the tangent (away from the arc body).\n const headLen = size * 0.6;\n const headWidth = size * 0.4;\n const arrowHead = (endX: number, endY: number, tx: number, ty: number): PolygonPath => {\n // Normalize tangent.\n const len = Math.hypot(tx, ty) || 1;\n const ux = tx / len;\n const uy = ty / len;\n // Perpendicular (rotate tangent 90° CCW).\n const px = -uy;\n const py = ux;\n // Triangle: tip is endX+ux*headLen, base is endX (with +/- headWidth/2 along p).\n const tipX = endX + ux * headLen;\n const tipY = endY + uy * headLen;\n const baseLeftX = endX + px * (headWidth / 2);\n const baseLeftY = endY + py * (headWidth / 2);\n const baseRightX = endX - px * (headWidth / 2);\n const baseRightY = endY - py * (headWidth / 2);\n return {\n kind: 'polygon',\n commands: new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L]),\n coords: new Float32Array([tipX, tipY, baseLeftX, baseLeftY, baseRightX, baseRightY, tipX, tipY]),\n fillRule: 'nonzero',\n };\n };\n // Endpoint A (right side, angle = +ARC_HALF_ANGLE). Arc point:\n // (sin(a)·R, -cos(a)·R). Tangent (d/da) = (cos(a)·R, sin(a)·R).\n const angleA = ARC_HALF_ANGLE;\n const endAX = arcRadius * Math.sin(angleA);\n const endAY = -arcRadius * Math.cos(angleA);\n const tangentAX = Math.cos(angleA);\n const tangentAY = Math.sin(angleA);\n // Endpoint B (left side, angle = -ARC_HALF_ANGLE): tangent in the\n // outward direction is the negation of the above.\n const angleB = -ARC_HALF_ANGLE;\n const endBX = arcRadius * Math.sin(angleB);\n const endBY = -arcRadius * Math.cos(angleB);\n const tangentBX = -Math.cos(angleB);\n const tangentBY = -Math.sin(angleB);\n const headA = arrowHead(endAX, endAY, tangentAX, tangentAY);\n const headB = arrowHead(endBX, endBY, tangentBX, tangentBY);\n // Build transform: translate(scx, scy) [* rotate(rotation)].\n let transform = mat3.translated(mat3.identity(), scx, scy);\n if (rotation !== 0) {\n const c = Math.cos(rotation);\n const s = Math.sin(rotation);\n const rot = new Float32Array([c, s, 0, -s, c, 0, 0, 0, 1]) as GlMat3;\n transform = mat3.multiply(transform, rot);\n }\n return [\n {\n kind: 'group',\n transform,\n children: [\n { kind: 'path', path: arcPath, stroke },\n { kind: 'path', path: headA, fill: handles.fill },\n { kind: 'path', path: headB, fill: handles.fill },\n ],\n },\n ];\n}\n\n/** Which passes a selection layer runs. The three exported factories differ\n * only in this — everything else they do is shared, so a fix to one is a fix\n * to all three. */\ninterface SelectionPasses {\n readonly id: string;\n readonly label: string;\n readonly outline: boolean;\n readonly handles: boolean;\n}\n\nfunction buildSelectionLayer<TPose>(\n opts: SelectionOverlayLayerOpts<TPose>,\n passes: SelectionPasses,\n): RenderLayer<unknown> {\n const { stroke, pad } = resolveOutlineStroke(opts.outline);\n const handlesEnabled = passes.handles && opts.handles !== false;\n const handles = handlesEnabled ? resolveHandles(opts.handles || undefined) : null;\n const handlesOf = opts.handlesOf ?? defaultHandlesOf;\n const d = (opts.poseDescriptor ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<TPose>;\n const getPose = opts.getPose;\n const poseBounds = getPose\n ? makeContainerAwareBoundsResolver(getPose, d, opts.getChildren, opts.isContainer)\n : null;\n const rotationHandleDistance = passes.handles\n ? rotationBadgeOf(opts)?.distancePx ?? null\n : null;\n\n return {\n id: passes.id,\n label: passes.label,\n space: 'screen',\n draw: (data, view) => {\n // The synthetic multi-resize id resolves to `ChromeState.unionBounds`,\n // the same value the affordance hit-tester reads, so painted chrome\n // and its hit region stay in agreement. With no chromeState on the\n // draw envelope, fall through to the supplied resolver.\n const chromeState = asChromeState(data);\n const allIds = opts.getSelection\n ? opts.getSelection()\n : chromeSelectionIds(chromeState);\n if (allIds.length === 0) return [];\n const suppressed = opts.getSuppressedIds?.();\n const ids = suppressed && suppressed.size > 0\n ? allIds.filter((id) => !suppressed.has(id as unknown as string))\n : allIds;\n if (ids.length === 0) return [];\n // Chrome-caps: gate each pass on its canonical id. When no\n // `getIsVisible` is wired, every pass runs.\n const isVisible = asIsVisible(data);\n const showOutline = passes.outline && (isVisible ? isVisible('selection.outline') : true);\n const showHandles = isVisible ? isVisible('selection.resize-handles') : true;\n const showRotation = isVisible ? isVisible('selection.rotation-handle') : true;\n\n const resolveBounds = poseBounds ?? ((id: string) => chromeState?.boundsOf(id) ?? null);\n const resolveTargetBounds = (id: string): Bounds | null => {\n if (id === MULTI_RESIZE_TARGET_ID && chromeState?.unionBounds != null) {\n return chromeState.unionBounds;\n }\n return resolveBounds(id);\n };\n\n const out: DrawCommand[] = [];\n if (showOutline) {\n const outlineIdsRaw = opts.getOutlineIds\n ? opts.getOutlineIds()\n : (opts.getSelection ? ids : (chromeState?.selection ?? ids));\n const outlineIds = suppressed && suppressed.size > 0\n ? outlineIdsRaw.filter((id) => !suppressed.has(id as unknown as string))\n : outlineIdsRaw;\n for (const cmd of outlineCommandsFor(outlineIds, resolveTargetBounds, stroke, pad, view)) out.push(cmd);\n }\n if (!handles) return out;\n if (showHandles) {\n for (const cmd of handleCommandsFor(ids, resolveTargetBounds, handles, handlesOf, view)) out.push(cmd);\n }\n if (showRotation && rotationHandleDistance !== null) {\n for (const id of ids) {\n const b = resolveTargetBounds(id);\n if (!b) continue;\n for (const cmd of rotationHandleCommands(b, handles, rotationHandleDistance, view)) {\n out.push(cmd);\n }\n }\n }\n return out;\n },\n };\n}\n\n/** Where the overlay paints its rotate badge and how big it is, in screen\n * pixels, or `null` when it paints none. The badge's grab region and its\n * slops halo read this too, so all three agree on it. */\nexport function rotationBadgeOf(\n opts: Pick<SelectionOverlayLayerOpts<unknown>, 'handles' | 'rotationHandle'>,\n): { distancePx: number; sizePx: number } | null {\n const r = opts.rotationHandle;\n if (!r || opts.handles === false) return null;\n return {\n distancePx: r === true ? DEFAULT_ROTATION_HANDLE_DISTANCE : r.distance ?? DEFAULT_ROTATION_HANDLE_DISTANCE,\n sizePx: resolveHandles(opts.handles || undefined).size,\n };\n}\n/**\n * `RenderLayer` that draws selection outlines only. Stack alongside\n * `createSelectionHandlesLayer` (or use `createSelectionOverlayLayer`, which\n * runs both passes in one layer) when both are wanted.\n */\nexport function createSelectionOutlineLayer<TPose>(\n opts: SelectionOutlineLayerOpts<TPose>,\n): RenderLayer<unknown> {\n return buildSelectionLayer(opts, {\n id: 'selection-outline',\n label: 'Selection outline',\n outline: true,\n handles: false,\n });\n}\n\n/**\n * `RenderLayer` that draws selection handles only. Stack on top of\n * `createSelectionOutlineLayer` (handles render on top of the outline).\n */\nexport function createSelectionHandlesLayer<TPose>(\n opts: SelectionHandlesLayerOpts<TPose>,\n): RenderLayer<unknown> {\n return buildSelectionLayer(opts, {\n id: 'selection-handles',\n label: 'Selection handles',\n outline: false,\n handles: true,\n });\n}\n\n/**\n * Draws outlines then handles in a single layer. Exactly equivalent to\n * stacking `createSelectionOutlineLayer` and `createSelectionHandlesLayer` —\n * all three run the same body. Pass `handles: false` to render outlines only.\n */\nexport function createSelectionOverlayLayer<TPose>(\n opts: SelectionOverlayLayerOpts<TPose>,\n): RenderLayer<unknown> {\n return buildSelectionLayer(opts, {\n id: 'selection-overlay',\n label: 'Selection',\n outline: true,\n handles: true,\n });\n}\n\n/** Pull a chrome-caps visibility predicate off the draw `data` envelope.\n * Returns `null` when the caller passed bare data (no `getIsVisible`\n * thunk) — the layer then renders unconditionally. */\nfunction asIsVisible(data: unknown): ((id: string) => boolean) | null {\n const maybe = data as { getIsVisible?: () => (id: string) => boolean };\n if (typeof maybe?.getIsVisible === 'function') return maybe.getIsVisible();\n return null;\n}\n\n/** The ids the handle pass works against when the layer takes its selection\n * from the envelope: the synthetic union id for a multi-selection, the\n * selection itself otherwise. */\nfunction chromeSelectionIds(state: ChromeState | null): readonly NodeId[] {\n if (!state) return [];\n if (state.multiActive) return [MULTI_RESIZE_TARGET_ID as NodeId];\n return state.selection;\n}\n\n/** Pull live `ChromeState` off the draw `data` envelope. Returns `null` for\n * callers that pass plain data with no `getChromeState` thunk — the layer\n * then resolves the multi-union via the supplied `getPose` resolver. */\nfunction asChromeState(data: unknown): ChromeState | null {\n const maybe = data as { getChromeState?: () => ChromeState };\n if (typeof maybe?.getChromeState === 'function') return maybe.getChromeState();\n return null;\n}\n"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { createTextLayer as e } from "./textLayer.js";
2
+ import { useSceneTextEdit as t } from "./useSceneTextEdit.js";
3
+ import { textCommand as n, textCommandFromPose as r, textCommandFromRuns as i } from "@weasel-js/renderer";
4
+ import { TextOutlinesError as a, loadTextOutlines as o, textToPath as s, textToPathsByPaint as c } from "@weasel-js/text";
5
+ import { TEXT_EDIT_FONT_HOLD as l, charOffsetToDomPosition as u, domPositionToCharOffset as d, domToRuns as f, runsToDom as p, useTextEdit as m } from "@weasel-js/text-dom";
6
+ export { l as TEXT_EDIT_FONT_HOLD, a as TextOutlinesError, u as charOffsetToDomPosition, e as createTextLayer, d as domPositionToCharOffset, f as domToRuns, o as loadTextOutlines, p as runsToDom, n as textCommand, r as textCommandFromPose, i as textCommandFromRuns, s as textToPath, c as textToPathsByPaint, t as useSceneTextEdit, m as useTextEdit };
@@ -1,4 +1,4 @@
1
- import { textCommandFromPose as e } from "./textCommand.js";
1
+ import { textCommandFromPose as e } from "@weasel-js/renderer";
2
2
  import { runsToPlainText as t } from "@weasel-js/text";
3
3
  //#region src/features/text/textLayer.ts
4
4
  function n(n) {
@@ -1 +1 @@
1
- {"version":3,"file":"textLayer.js","names":["createTextLayer","opts","scale","view","children","node","getTexts","isHidden","pose","getPose","runsToPlainText","textCmd","textCommandFromPose","clipToBounds"],"sources":["../../../src/features/text/textLayer.ts"],"sourcesContent":["/**\n * Text RenderLayer for text that is not in a scene: one `textCommandFromPose`\n * command per item, the same command the `kit:text` node painter emits, so an\n * item lays out — and wraps, or doesn't, per its style — as a node would.\n *\n * The GL renderer uses MSDF text. The resolved style's `fontFamily` must\n * be registered via `registerFont(family, variant, metricsUrl, atlasUrl)`\n * from the renderer module *before* the GL backend dispatches this layer.\n * Unregistered families render with a warning and no glyphs (see\n * `TextDrawCommand`'s contract).\n */\n\nimport { type DrawCommand } from '../../renderer';\nimport type { TextPose } from '@weasel-js/text';\n\nimport type { RenderLayer } from 'core/layers/render';\nimport { textCommandFromPose } from './textCommand';\nimport { runsToPlainText } from '@weasel-js/text';\n\n\n/** Options for `createTextLayer`. */\nexport interface CreateTextLayerOpts<T> {\n id?: string;\n label?: string;\n getTexts: () => readonly T[];\n getPose: (node: T) => TextPose;\n /** Optional per-node hide hook (e.g., suppress while editing). */\n isHidden?: (node: T) => boolean;\n /** When `true`, each text command is wrapped in a clipped group so any\n * overflow beyond the pose's `(width × height)` is hidden. Default\n * `false` (legacy: text can spill outside the declared bounds). Opt-in\n * so existing consumers who rely on overflow keep working. */\n clipToBounds?: boolean;\n}\n\n/** Build a `RenderLayer` that emits one `TextDrawCommand` per text node. */\nexport function createTextLayer<T>(opts: CreateTextLayerOpts<T>): RenderLayer<unknown> {\n const { id = 'text', label = 'Text', getTexts, getPose, isHidden, clipToBounds = false } = opts;\n return {\n id,\n label,\n draw: (_data, view) => {\n // A world-space layer, so a `{ px }` size in a pose's style resolves\n // against the live camera. Radial in effect — one factor for both axes.\n const scale = (view.scale.x + view.scale.y) / 2;\n const children: DrawCommand[] = [];\n for (const node of getTexts()) {\n if (isHidden?.(node)) continue;\n const pose = getPose(node);\n if (pose.runs && pose.runs.length > 0 && runsToPlainText(pose.runs) !== pose.text) {\n throw new Error(\n `weasel createTextLayer: TextPose invariant violated — ` +\n `runsToPlainText(runs) !== text. Either omit \\`runs\\` or keep it ` +\n `synchronized with \\`text\\`.`,\n );\n }\n const textCmd = textCommandFromPose(pose, scale);\n if (clipToBounds) {\n children.push({\n kind: 'group',\n clip: { kind: 'rect', x: pose.x, y: pose.y, width: pose.width, height: pose.height },\n children: [textCmd],\n });\n } else {\n children.push(textCmd);\n }\n }\n // World-space commands; drawLayers wraps in viewToMat3 automatically.\n return children;\n },\n };\n}\n"],"mappings":";;;AAoCA,SAAgBA,EAAmB,GAAoD;CACrF,IAAM,EAAE,QAAK,QAAQ,WAAQ,QAAQ,aAAU,YAAS,aAAU,kBAAe,OAAUC;CAC3F,OAAO;EACL;EACA;EACA,OAAO,GAAO,MAAS;GAGrB,IAAMC,KAASC,EAAK,MAAM,IAAIA,EAAK,MAAM,KAAK,GACxCC,IAA0B,CAAC;GACjC,KAAK,IAAMC,KAAQC,EAAS,GAAG;IAC7B,IAAIC,IAAWF,CAAI,GAAG;IACtB,IAAMG,IAAOC,EAAQJ,CAAI;IACzB,IAAIG,EAAK,QAAQA,EAAK,KAAK,SAAS,KAAKE,EAAgBF,EAAK,IAAI,MAAMA,EAAK,MAC3E,MAAU,MACR,+IAGF;IAEF,IAAMG,IAAUC,EAAoBJ,GAAMN,CAAK;IAC/C,AAAIW,IACFT,EAAS,KAAK;KACZ,MAAM;KACN,MAAM;MAAE,MAAM;MAAQ,GAAGI,EAAK;MAAG,GAAGA,EAAK;MAAG,OAAOA,EAAK;MAAO,QAAQA,EAAK;KAAO;KACnF,UAAU,CAACG,CAAO;IACpB,CAAC,IAEDP,EAAS,KAAKO,CAAO;GAEzB;GAEA,OAAOP;EACT;CACF;AACF"}
1
+ {"version":3,"file":"textLayer.js","names":["createTextLayer","opts","scale","view","children","node","getTexts","isHidden","pose","getPose","runsToPlainText","textCmd","textCommandFromPose","clipToBounds"],"sources":["../../../src/features/text/textLayer.ts"],"sourcesContent":["/**\n * Text RenderLayer for text that is not in a scene: one `textCommandFromPose`\n * command per item, the same command the `kit:text` node painter emits, so an\n * item lays out — and wraps, or doesn't, per its style — as a node would.\n *\n * The GL renderer uses MSDF text. The resolved style's `fontFamily` must\n * be registered via `registerFont(family, variant, metricsUrl, atlasUrl)`\n * from the renderer module *before* the GL backend dispatches this layer.\n * Unregistered families render with a warning and no glyphs (see\n * `TextDrawCommand`'s contract).\n */\n\nimport { type DrawCommand } from '@weasel-js/renderer';\nimport type { TextPose } from '@weasel-js/text';\n\nimport type { RenderLayer } from 'core/layers/render';\nimport { textCommandFromPose } from '@weasel-js/renderer';\nimport { runsToPlainText } from '@weasel-js/text';\n\n\n/** Options for `createTextLayer`. */\nexport interface CreateTextLayerOpts<T> {\n id?: string;\n label?: string;\n getTexts: () => readonly T[];\n getPose: (node: T) => TextPose;\n /** Optional per-node hide hook (e.g., suppress while editing). */\n isHidden?: (node: T) => boolean;\n /** When `true`, each text command is wrapped in a clipped group so any\n * overflow beyond the pose's `(width × height)` is hidden. Default\n * `false` (legacy: text can spill outside the declared bounds). Opt-in\n * so existing consumers who rely on overflow keep working. */\n clipToBounds?: boolean;\n}\n\n/** Build a `RenderLayer` that emits one `TextDrawCommand` per text node. */\nexport function createTextLayer<T>(opts: CreateTextLayerOpts<T>): RenderLayer<unknown> {\n const { id = 'text', label = 'Text', getTexts, getPose, isHidden, clipToBounds = false } = opts;\n return {\n id,\n label,\n draw: (_data, view) => {\n // A world-space layer, so a `{ px }` size in a pose's style resolves\n // against the live camera. Radial in effect — one factor for both axes.\n const scale = (view.scale.x + view.scale.y) / 2;\n const children: DrawCommand[] = [];\n for (const node of getTexts()) {\n if (isHidden?.(node)) continue;\n const pose = getPose(node);\n if (pose.runs && pose.runs.length > 0 && runsToPlainText(pose.runs) !== pose.text) {\n throw new Error(\n `weasel createTextLayer: TextPose invariant violated — ` +\n `runsToPlainText(runs) !== text. Either omit \\`runs\\` or keep it ` +\n `synchronized with \\`text\\`.`,\n );\n }\n const textCmd = textCommandFromPose(pose, scale);\n if (clipToBounds) {\n children.push({\n kind: 'group',\n clip: { kind: 'rect', x: pose.x, y: pose.y, width: pose.width, height: pose.height },\n children: [textCmd],\n });\n } else {\n children.push(textCmd);\n }\n }\n // World-space commands; drawLayers wraps in viewToMat3 automatically.\n return children;\n },\n };\n}\n"],"mappings":";;;AAoCA,SAAgBA,EAAmB,GAAoD;CACrF,IAAM,EAAE,QAAK,QAAQ,WAAQ,QAAQ,aAAU,YAAS,aAAU,kBAAe,OAAUC;CAC3F,OAAO;EACL;EACA;EACA,OAAO,GAAO,MAAS;GAGrB,IAAMC,KAASC,EAAK,MAAM,IAAIA,EAAK,MAAM,KAAK,GACxCC,IAA0B,CAAC;GACjC,KAAK,IAAMC,KAAQC,EAAS,GAAG;IAC7B,IAAIC,IAAWF,CAAI,GAAG;IACtB,IAAMG,IAAOC,EAAQJ,CAAI;IACzB,IAAIG,EAAK,QAAQA,EAAK,KAAK,SAAS,KAAKE,EAAgBF,EAAK,IAAI,MAAMA,EAAK,MAC3E,MAAU,MACR,+IAGF;IAEF,IAAMG,IAAUC,EAAoBJ,GAAMN,CAAK;IAC/C,AAAIW,IACFT,EAAS,KAAK;KACZ,MAAM;KACN,MAAM;MAAE,MAAM;MAAQ,GAAGI,EAAK;MAAG,GAAGA,EAAK;MAAG,OAAOA,EAAK;MAAO,QAAQA,EAAK;KAAO;KACnF,UAAU,CAACG,CAAO;IACpB,CAAC,IAEDP,EAAS,KAAKO,CAAO;GAEzB;GAEA,OAAOP;EACT;CACF;AACF"}
@@ -1,138 +1,145 @@
1
1
  import { effectivePose as e } from "../../core/scene/effectivePose.js";
2
- import { asNodeId as t } from "../../core/scene/types.js";
3
- import { findMountedCanvas as n } from "../../canvas/mountedCanvases.js";
4
- import { caretIndexAt as r, pointInTextPose as i } from "./hitTest.js";
5
- import { useTextEdit as a } from "./useTextEdit.js";
6
- import { resolveScreenLength as o } from "@weasel-js/paint";
7
- import { useCallback as s, useRef as c } from "react";
2
+ import { targetTransformOf as t, worldToLocal as n } from "../../core/geometry/targetFrame.js";
3
+ import { asNodeId as r } from "../../core/scene/types.js";
4
+ import { findMountedCanvas as i } from "../../canvas/mountedCanvases.js";
5
+ import { poseFrameOf as a } from "@weasel-js/geom";
6
+ import { useCallback as o, useMemo as s, useRef as c } from "react";
8
7
  import { useLatest as l } from "@weasel-js/react";
9
8
  import { clientToCanvas as u } from "@weasel-js/routing";
9
+ import { resolveScreenLength as d } from "@weasel-js/paint";
10
+ import { caretIndexAt as f, isTextData as p, pointInTextPose as m } from "@weasel-js/text";
11
+ import { useTextEdit as h } from "@weasel-js/text-dom";
10
12
  //#region src/features/text/useSceneTextEdit.ts
11
- function d(e) {
13
+ function g(e) {
12
14
  return typeof e == "function" ? e() : e;
13
15
  }
14
- function f(f, p, m = {}) {
15
- let h = l(f), g = l(m), _ = l(p), v = c(null), y = () => {
16
- let e = _.current, t = e ? n(e, v.current) : null;
16
+ function _(a, _, y = {}) {
17
+ let b = l(a), x = l(y), S = l(_), C = c(null), w = () => {
18
+ let e = S.current, t = e ? i(e, C.current) : null;
17
19
  if (!e || !t) return null;
18
- let r = t.element.getBoundingClientRect(), i = e.getBoundingClientRect();
20
+ let n = t.element.getBoundingClientRect(), r = e.getBoundingClientRect();
19
21
  return {
20
22
  canvas: t,
21
23
  box: {
22
- x: r.left - i.left - e.clientLeft + e.scrollLeft,
23
- y: r.top - i.top - e.clientTop + e.scrollTop,
24
- width: r.width,
25
- height: r.height
24
+ x: n.left - r.left - e.clientLeft + e.scrollLeft,
25
+ y: n.top - r.top - e.clientTop + e.scrollTop,
26
+ width: n.width,
27
+ height: n.height
26
28
  }
27
29
  };
28
- }, b = a({
29
- container: p,
30
- isEditorChrome: (e) => g.current.isEditorChrome?.(e) ?? !1,
31
- escape: m.escape,
32
- fontHold: m.fontHold,
30
+ }, T = s(() => ({
31
+ isText: (e) => x.current.isText ? x.current.isText(e) : p(e),
32
+ text: (e) => x.current.getText ? x.current.getText(e) : e.text ?? "",
33
+ style: (e) => x.current.getStyle ? x.current.getStyle(e) : e.style,
34
+ runs: (e) => x.current.getRuns ? x.current.getRuns(e) : e.runs,
35
+ verticalAlign: (e) => x.current.getVerticalAlign ? x.current.getVerticalAlign(e) : e.verticalAlign
36
+ }), [x]), E = h({
37
+ container: _,
38
+ isEditorChrome: (e) => x.current.isEditorChrome?.(e) ?? !1,
39
+ escape: y.escape,
40
+ fontHold: y.fontHold,
33
41
  getText: (e) => {
34
- let n = h.current.get(t(e));
35
- if (!n) return "";
36
- let r = g.current.getText;
37
- return r ? r(n.data) : n.data.text ?? "";
42
+ let t = b.current.get(r(e));
43
+ return t ? T.text(t.data) : "";
38
44
  },
39
45
  getStyle: (e) => {
40
- let n = h.current.get(t(e));
41
- if (!n) return;
42
- let r = g.current.getStyle;
43
- return r ? r(n.data) : n.data.style;
46
+ let t = b.current.get(r(e));
47
+ return t ? T.style(t.data) : void 0;
44
48
  },
45
49
  getPaint: (e) => {
46
- let n = h.current.get(t(e));
47
- if (!n) return;
48
- let r = g.current.getPaint;
49
- return r ? r(n.data) : {
50
- fill: n.data.fill,
51
- stroke: n.data.stroke
50
+ let t = b.current.get(r(e));
51
+ if (!t) return;
52
+ let n = x.current.getPaint;
53
+ return n ? n(t.data) : {
54
+ fill: t.data.fill,
55
+ stroke: t.data.stroke
52
56
  };
53
57
  },
54
- getScreenPose: (n) => {
55
- let r = h.current, i = r.get(t(n));
58
+ getScreenPose: (t) => {
59
+ let n = b.current, i = n.get(r(t));
56
60
  if (!i) return null;
57
- let a = e(r, i), s = g.current.getStyle ? g.current.getStyle(i.data) : i.data.style, c = y(), l = d(g.current.view) ?? c?.canvas.getView(), u = l ? l.scale.x : 1, f = c?.box.x ?? 0, p = c?.box.y ?? 0;
61
+ let a = e(n, i), o = T.style(i.data), s = w(), c = g(x.current.view) ?? s?.canvas.getView(), l = c ? c.scale.x : 1, u = s?.box.x ?? 0, f = s?.box.y ?? 0;
58
62
  return {
59
- x: f + (l ? (a.x - l.x) * l.scale.x : a.x),
60
- y: p + (l ? (a.y - l.y) * l.scale.y : a.y),
63
+ x: u + (c ? (a.x - c.x) * c.scale.x : a.x),
64
+ y: f + (c ? (a.y - c.y) * c.scale.y : a.y),
61
65
  width: a.width,
62
66
  height: a.height,
63
- fontSize: o(s?.fontSize ?? g.current.defaultFontSize ?? 16, u),
64
- zoom: u,
65
- verticalAlign: g.current.getVerticalAlign ? g.current.getVerticalAlign(i.data) : i.data.verticalAlign
67
+ fontSize: d(o?.fontSize ?? x.current.defaultFontSize ?? 16, l),
68
+ zoom: l,
69
+ frame: v(a),
70
+ verticalAlign: T.verticalAlign(i.data)
66
71
  };
67
72
  },
68
- getClipRect: () => y()?.box ?? null,
69
- setText: (e, n) => {
70
- let r = t(e), i = h.current.get(r);
71
- if (!i) return;
72
- let a = g.current.setText, o = a ? a(i.data, n) : {
73
- ...i.data,
74
- text: n
75
- };
76
- h.current.update(r, { data: o });
77
- },
73
+ getClipRect: () => w()?.box ?? null,
78
74
  getRuns: (e) => {
79
- let n = h.current.get(t(e));
80
- if (!n) return;
81
- let r = g.current.getRuns;
82
- return r ? r(n.data) : n.data.runs;
75
+ let t = b.current.get(r(e));
76
+ return t ? T.runs(t.data) : void 0;
83
77
  },
84
- setRuns: (e, n) => {
85
- let r = t(e), i = h.current.get(r);
86
- if (!i) return;
87
- let a = g.current.setRuns, o = a ? a(i.data, n) : {
88
- ...i.data,
89
- runs: n
78
+ commit: (e, { text: t, runs: n, style: i }) => {
79
+ let a = r(e), o = b.current.get(a);
80
+ if (!o) return;
81
+ let { setText: s, setRuns: c, setStyle: l } = x.current, u = s ? s(o.data, t) : {
82
+ ...o.data,
83
+ text: t
90
84
  };
91
- h.current.update(r, { data: o });
92
- },
93
- setStyle: (e, n) => {
94
- let r = t(e), i = h.current.get(r);
95
- if (!i) return;
96
- let a = g.current.setStyle, o = a ? a(i.data, n) : {
97
- ...i.data,
98
- style: n
99
- };
100
- h.current.update(r, { data: o });
85
+ n && (u = c ? c(u, n) : {
86
+ ...u,
87
+ runs: n
88
+ }), i && (u = l ? l(u, i) : {
89
+ ...u,
90
+ style: i
91
+ }), b.current.update(a, { data: u });
101
92
  }
102
- }), x = s((t) => {
103
- let a = t.target instanceof HTMLElement ? t.target : null;
104
- if (!a) return;
105
- let [o, s] = u(a, t.clientX, t.clientY), c = _.current, l = d(g.current.view) ?? (c ? n(c, a)?.getView() : void 0), f = l ? o / l.scale.x + l.x : o, p = l ? s / l.scale.y + l.y : s, m = (e) => g.current.getText ? g.current.getText(e) : e.text ?? "", y = (e) => g.current.getStyle ? g.current.getStyle(e) : e.style, x = (e) => g.current.getRuns ? g.current.getRuns(e) : e.runs, S = (e) => g.current.getVerticalAlign ? g.current.getVerticalAlign(e) : e.verticalAlign, C = h.current.renderOrderNodes();
106
- for (let t = C.length - 1; t >= 0; t--) {
107
- let n = C[t];
108
- if (h.current.isLocked(n.id)) continue;
109
- let o = m(n.data), s = e(h.current, n), c = {
93
+ }), D = o((r) => {
94
+ let a = r.target instanceof HTMLElement ? r.target : null;
95
+ if (!a || a.closest("[contenteditable=\"true\"]")) return;
96
+ let [o, s] = u(a, r.clientX, r.clientY), c = S.current, l = g(x.current.view) ?? (c ? i(c, a)?.getView() : void 0), d = l ? o / l.scale.x + l.x : o, p = l ? s / l.scale.y + l.y : s, h = b.current.renderOrderNodes();
97
+ for (let r = h.length - 1; r >= 0; r--) {
98
+ let i = h[r];
99
+ if (b.current.isLocked(i.id) || !T.isText(i.data)) continue;
100
+ let o = T.text(i.data), s = e(b.current, i), c = n(t(s), d, p);
101
+ if (!c) continue;
102
+ let l = {
110
103
  x: s.x,
111
104
  y: s.y,
112
105
  width: s.width,
113
106
  height: s.height,
114
107
  text: o,
115
- runs: x(n.data),
116
- style: y(n.data),
117
- verticalAlign: S(n.data)
108
+ runs: T.runs(i.data),
109
+ style: T.style(i.data),
110
+ verticalAlign: T.verticalAlign(i.data)
118
111
  };
119
- if (i(f, p, c)) {
120
- v.current = a, b.startEdit(String(n.id), { caret: r(f, p, c) });
112
+ if (m(c.x, c.y, l)) {
113
+ C.current = a, E.startEdit(String(i.id), { caret: f(c.x, c.y, l) });
121
114
  return;
122
115
  }
123
116
  }
124
117
  }, [
125
- b,
126
- _,
127
- g,
128
- h
129
- ]);
118
+ E,
119
+ S,
120
+ x,
121
+ T,
122
+ b
123
+ ]), O = o((e) => {
124
+ let t = b.current.get(r(e));
125
+ return t !== void 0 && T.isText(t.data);
126
+ }, [T, b]);
130
127
  return {
131
- ...b,
132
- onDoubleClick: x
128
+ ...E,
129
+ onDoubleClick: D,
130
+ isTextNode: O
133
131
  };
134
132
  }
133
+ function v(e) {
134
+ let t = a(e);
135
+ return t ? [
136
+ t[0],
137
+ t[1],
138
+ t[2],
139
+ t[3]
140
+ ] : void 0;
141
+ }
135
142
  //#endregion
136
- export { f as useSceneTextEdit };
143
+ export { _ as useSceneTextEdit };
137
144
 
138
145
  //# sourceMappingURL=useSceneTextEdit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSceneTextEdit.js","names":["resolveView","view","useSceneTextEdit","sceneRef","useLatest","scene","optsRef","options","containerRef","container","openedOnRef","useRef","surface","root","canvas","findMountedCanvas","a","b","edit","useTextEdit","el","node","asNodeId","id","get","pose","effectivePose","style","at","zoom","originX","originY","resolveScreenLength","nid","setter","data","text","runs","onDoubleClick","useCallback","e","canvasX","canvasY","clientToCanvas","cx","cy","readText","readStyle","readRuns","readVerticalAlign","order","i","pointInTextPose","caretIndexAt"],"sources":["../../../src/features/text/useSceneTextEdit.ts"],"sourcesContent":["/**\n * `useSceneTextEdit` — scene-aware wrapper around `useTextEdit`.\n *\n * Every consumer that wires `useTextEdit` against a `useScene`-managed\n * scene writes the same callbacks: scene lookups for text / style /\n * runs / screen-pose, and `scene.update(id, { data })` for commits. This\n * helper bakes that wiring in. Consumers pass `scene` + `container` and\n * get back the same `UseTextEditReturn` shape (`startEdit`, `isEditing`,\n * `cancelEdit`, `commit`, `editingId`).\n *\n * Defaults assume the node's `data` carries `text` / `style` / `runs`\n * directly — matches the `useScene({ items })` trivial form where\n * `data === item` for text-shaped items, and matches `TextPose`-shaped\n * data. For custom data shapes, override any of the optional projections\n * (`getText` / `getStyle` / `getRuns` / `setText` / `setRuns` / `setStyle`).\n *\n * Pose component: the helper reads `(x, y, width, height)` straight off\n * the node's pose (typed `RectPose`) and projects that box through the view\n * of the weasel canvas mounted inside `container` — see the `view` option.\n * The overlay is clipped to that canvas's box, where its glyphs are clipped.\n * Consumers with non-rect poses should drop down to raw `useTextEdit` and\n * supply their own `getScreenPose`.\n */\nimport { useCallback, useRef, type MouseEvent } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport { asNodeId } from '../../core/scene/types';\nimport { effectivePose } from '../../core/scene/effectivePose';\nimport type { Scene } from '../../core/scene/types';\nimport type { FillStyle, Stroke } from '@weasel-js/paint';\nimport { resolveScreenLength } from '@weasel-js/paint';\nimport { clientToCanvas } from '@weasel-js/routing';\nimport { findMountedCanvas, type MountedCanvas } from '../../canvas/mountedCanvases';\nimport type { View } from '../../core/viewport/view';\nimport type { RectPose } from 'core/geometry/unionBounds';\nimport { caretIndexAt, pointInTextPose } from './hitTest';\nimport type { StyledRun } from '@weasel-js/text';\nimport type { TextPaint, TextStyle, TextVerticalAlign } from '@weasel-js/text';\nimport { useTextEdit, type TextEditClipRect, type UseTextEditReturn } from './useTextEdit';\n\n/** Shape the default projections expect `data` to satisfy. All fields\n * optional so any object satisfies the constraint — projections fill in\n * the gaps for non-default shapes. */\nexport interface DefaultTextData {\n text?: string;\n style?: TextStyle;\n runs?: readonly StyledRun[];\n fill?: FillStyle | null;\n stroke?: Stroke | null;\n verticalAlign?: TextVerticalAlign;\n}\n\n/** All-optional projections + fontSize fallback. */\nexport interface UseSceneTextEditOptions<TData> {\n /** Read plain text from `data`. Default: `data.text ?? ''`. */\n getText?: (data: TData) => string;\n /** Read style from `data`. Default: `data.style`. */\n getStyle?: (data: TData) => TextStyle | undefined;\n /** Read the node's paint from `data`. Default: `data.fill` / `data.stroke`. */\n getPaint?: (data: TData) => TextPaint | undefined;\n /** Read rich-text runs from `data`. Default: `data.runs`. */\n getRuns?: (data: TData) => readonly StyledRun[] | undefined;\n /** Read the box vertical alignment from `data`. Default: `data.verticalAlign`. */\n getVerticalAlign?: (data: TData) => TextVerticalAlign | undefined;\n /** Produce updated data with new text. Default: `{ ...data, text }`. */\n setText?: (data: TData, text: string) => TData;\n /** Produce updated data with new runs. Default: `{ ...data, runs }`. */\n setRuns?: (data: TData, runs: StyledRun[]) => TData;\n /**\n * Produce updated data with a new node-wide style. Default:\n * `{ ...data, style }`. Written only when a range toggle has to *clear* a\n * flag the node itself sets — the run algebra is additive, so that edit\n * lowers the node flag and raises it on the runs outside the range. See\n * `useTextEdit`'s `setStyle`.\n */\n setStyle?: (data: TData, style: TextStyle) => TData;\n /** Fallback fontSize when `style.fontSize` is unset. Default `16`. */\n defaultFontSize?: number;\n /**\n * The view to project through. Omit it and the view is read live from the\n * weasel canvas mounted inside `container` (the one a double-click landed\n * on, when there are several) — which is all a canvas that pans or zooms\n * needs. With no canvas there, the node's world box is passed through as\n * screen pixels.\n *\n * The overlay is positioned at the node's projected origin and CSS-scaled\n * by the view, so every typographic metric on it — including the\n * `fontSize` / `letterSpacing` a *run* carries — stays in world units and\n * scales together.\n *\n * The overlay takes a single scale factor, so a non-uniform view scale is\n * represented by its `scale.x`; text under `scale.x !== scale.y` will not\n * match the canvas.\n *\n * Pass one to project through a camera other than the canvas's own. A\n * thunk is re-read on every projection; a plain `View` is the value from\n * the render that supplied it.\n */\n view?: View | (() => View);\n /**\n * Forwarded to `useTextEdit`: is `el` part of the editor's own chrome?\n * Focus moving into it does not end the edit. Wire it to whatever renders\n * the character controls.\n */\n isEditorChrome?: (el: Element) => boolean;\n /** Forwarded to `useTextEdit`: what Escape does to the edit. */\n escape?: 'cancel' | 'commit';\n /** Forwarded to `useTextEdit`: how long an edit waits for its face. */\n fontHold?: number;\n}\n\nfunction resolveView(view: View | (() => View) | undefined): View | undefined {\n return typeof view === 'function' ? view() : view;\n}\n\n/** Return shape extends `UseTextEditReturn` with an `onDoubleClick`\n * binding for the canvas container. Double-clicking inside a text\n * node enters edit mode with the caret seeded at the clicked glyph. */\nexport interface UseSceneTextEditReturn extends UseTextEditReturn {\n /** Bind to the element wrapping `<SceneCanvas>` (the same element\n * passed as `container`, or any ancestor that receives the dblclick\n * bubble). The handler looks up the canvas via `e.target`, hits the\n * top-most text node under the cursor via `pointInTextPose`, resolves\n * a caret offset via `caretIndexAt`, and starts edit on that node. */\n onDoubleClick: (e: MouseEvent<HTMLElement>) => void;\n}\n\n/** Wire double-click-to-edit text on a scene: mounts a DOM editing overlay\n * over the node being edited and writes the result back as an undoable op. */\nexport function useSceneTextEdit<\n TData extends DefaultTextData,\n TLayer extends string,\n TPose extends RectPose = RectPose,\n>(\n scene: Scene<TData, TLayer, TPose>,\n container: HTMLElement | null,\n options: UseSceneTextEditOptions<TData> = {},\n): UseSceneTextEditReturn {\n // Stash scene + options in refs so the useTextEdit callbacks always see\n // the current values without re-binding (the underlying hook also reads\n // its options through a ref, so any re-creation would be churn).\n const sceneRef = useLatest(scene);\n const optsRef = useLatest(options);\n const containerRef = useLatest(container);\n // The last double-click's target, so the overlay projects through the\n // canvas the edit was opened on.\n const openedOnRef = useRef<EventTarget | null>(null);\n\n // The canvas's box in container pixels is both the origin its view projects\n // from and the region its glyphs are clipped to.\n const surface = (): { canvas: MountedCanvas; box: TextEditClipRect } | null => {\n const root = containerRef.current;\n const canvas = root ? findMountedCanvas(root, openedOnRef.current) : null;\n if (!root || !canvas) return null;\n const a = canvas.element.getBoundingClientRect();\n const b = root.getBoundingClientRect();\n return {\n canvas,\n box: {\n x: a.left - b.left - root.clientLeft + root.scrollLeft,\n y: a.top - b.top - root.clientTop + root.scrollTop,\n width: a.width,\n height: a.height,\n },\n };\n };\n\n const edit = useTextEdit({\n container,\n isEditorChrome: (el) => optsRef.current.isEditorChrome?.(el) ?? false,\n escape: options.escape,\n fontHold: options.fontHold,\n getText: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n if (!node) return '';\n const get = optsRef.current.getText;\n return get ? get(node.data) : (node.data.text ?? '');\n },\n getStyle: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n if (!node) return undefined;\n const get = optsRef.current.getStyle;\n return get ? get(node.data) : node.data.style;\n },\n getPaint: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n if (!node) return undefined;\n const get = optsRef.current.getPaint;\n return get ? get(node.data) : { fill: node.data.fill, stroke: node.data.stroke };\n },\n getScreenPose: (id) => {\n const scene = sceneRef.current;\n const node = scene.get(asNodeId(id));\n if (!node) return null;\n const pose = effectivePose(scene, node);\n const style = optsRef.current.getStyle\n ? optsRef.current.getStyle(node.data)\n : node.data.style;\n const at = surface();\n const view = resolveView(optsRef.current.view) ?? at?.canvas.getView();\n const zoom = view ? view.scale.x : 1;\n const originX = at?.box.x ?? 0;\n const originY = at?.box.y ?? 0;\n // Only the origin is projected. Width, height and font size stay in\n // world units and reach the screen through the overlay's own\n // `scale(zoom)` — see `TextEditScreenPose.zoom`.\n return {\n x: originX + (view ? (pose.x - view.x) * view.scale.x : pose.x),\n y: originY + (view ? (pose.y - view.y) * view.scale.y : pose.y),\n width: pose.width,\n height: pose.height,\n // Against `zoom`, the same factor the overlay scales back up by, so a\n // `{ px }` size arrives on screen at the pixel count it names.\n fontSize: resolveScreenLength(\n style?.fontSize ?? optsRef.current.defaultFontSize ?? 16,\n zoom,\n ),\n zoom,\n verticalAlign: optsRef.current.getVerticalAlign\n ? optsRef.current.getVerticalAlign(node.data)\n : node.data.verticalAlign,\n };\n },\n getClipRect: () => surface()?.box ?? null,\n setText: (id, text) => {\n const nid = asNodeId(id);\n const node = sceneRef.current.get(nid);\n if (!node) return;\n const setter = optsRef.current.setText;\n const data = setter ? setter(node.data, text) : { ...node.data, text };\n sceneRef.current.update(nid, { data });\n },\n getRuns: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n if (!node) return undefined;\n const get = optsRef.current.getRuns;\n return get ? get(node.data) : node.data.runs;\n },\n setRuns: (id, runs) => {\n const nid = asNodeId(id);\n const node = sceneRef.current.get(nid);\n if (!node) return;\n const setter = optsRef.current.setRuns;\n const data = setter ? setter(node.data, runs) : { ...node.data, runs };\n sceneRef.current.update(nid, { data });\n },\n setStyle: (id, style) => {\n const nid = asNodeId(id);\n const node = sceneRef.current.get(nid);\n if (!node) return;\n const setter = optsRef.current.setStyle;\n const data = setter ? setter(node.data, style) : { ...node.data, style };\n sceneRef.current.update(nid, { data });\n },\n });\n\n const onDoubleClick = useCallback((e: MouseEvent<HTMLElement>) => {\n // The dblclick bubbles from the canvas up to any wrapping container; the\n // element it started on is what the click coordinates are relative to.\n const canvas = e.target instanceof HTMLElement ? e.target : null;\n if (!canvas) return;\n\n // `pointInTextPose` and `caretIndexAt` both work in world units, so the\n // canvas-space click has to be un-projected before either sees it.\n const [canvasX, canvasY] = clientToCanvas(canvas, e.clientX, e.clientY);\n const root = containerRef.current;\n const view = resolveView(optsRef.current.view)\n ?? (root ? findMountedCanvas(root, canvas)?.getView() : undefined);\n const cx = view ? canvasX / view.scale.x + view.x : canvasX;\n const cy = view ? canvasY / view.scale.y + view.y : canvasY;\n const readText = (data: TData): string =>\n optsRef.current.getText ? optsRef.current.getText(data) : (data.text ?? '');\n const readStyle = (data: TData): TextStyle | undefined =>\n optsRef.current.getStyle ? optsRef.current.getStyle(data) : data.style;\n const readRuns = (data: TData): readonly StyledRun[] | undefined =>\n optsRef.current.getRuns ? optsRef.current.getRuns(data) : data.runs;\n const readVerticalAlign = (data: TData): TextVerticalAlign | undefined =>\n optsRef.current.getVerticalAlign ? optsRef.current.getVerticalAlign(data) : data.verticalAlign;\n\n // Top-most-first hit test: renderOrder() is back-to-front, so iterate\n // in reverse and break on the first hit.\n const order = sceneRef.current.renderOrderNodes();\n for (let i = order.length - 1; i >= 0; i--) {\n const node = order[i];\n if (sceneRef.current.isLocked(node.id)) continue;\n const text = readText(node.data);\n const at = effectivePose(sceneRef.current, node);\n const pose = {\n x: at.x,\n y: at.y,\n width: at.width,\n height: at.height,\n text,\n runs: readRuns(node.data) as StyledRun[] | undefined,\n style: readStyle(node.data),\n verticalAlign: readVerticalAlign(node.data),\n };\n if (!pointInTextPose(cx, cy, pose)) continue;\n\n openedOnRef.current = canvas;\n edit.startEdit(String(node.id), { caret: caretIndexAt(cx, cy, pose) });\n return;\n }\n }, [edit, containerRef, optsRef, sceneRef]);\n\n return { ...edit, onDoubleClick };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useSceneTextEdit.js","names":["resolveView","view","useSceneTextEdit","sceneRef","useLatest","scene","optsRef","options","containerRef","container","openedOnRef","useRef","surface","root","canvas","findMountedCanvas","a","b","read","useMemo","data","isTextData","edit","useTextEdit","el","node","asNodeId","id","get","pose","effectivePose","style","at","zoom","originX","originY","resolveScreenLength","frameLinearOf","nid","setText","text","runs","setRuns","setStyle","onDoubleClick","useCallback","e","canvasX","canvasY","clientToCanvas","cx","cy","order","i","p","worldToLocal","targetTransformOf","pointInTextPose","caretIndexAt","isTextNode","m","poseFrameOf"],"sources":["../../../src/features/text/useSceneTextEdit.ts"],"sourcesContent":["/**\n * `useSceneTextEdit` — scene-aware wrapper around `useTextEdit`: scene\n * lookups for text / style / runs / screen-pose, and\n * `scene.update(id, { data })` for commits.\n *\n * Defaults assume the node's `data` carries `text` / `style` / `runs`\n * directly. For custom data shapes, override any of the optional projections.\n * Consumers with non-rect poses should drop down to raw `useTextEdit` and\n * supply their own `getScreenPose`.\n */\nimport { useCallback, useMemo, useRef, type MouseEvent } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport { asNodeId } from '../../core/scene/types';\nimport { effectivePose } from '../../core/scene/effectivePose';\nimport type { Scene } from '../../core/scene/types';\nimport type { Stroke, Fill } from '@weasel-js/paint';\nimport { resolveScreenLength } from '@weasel-js/paint';\nimport { clientToCanvas } from '@weasel-js/routing';\nimport { findMountedCanvas, type MountedCanvas } from '../../canvas/mountedCanvases';\nimport type { View } from '../../core/viewport/view';\nimport type { RectPose } from 'core/geometry/unionBounds';\nimport { targetTransformOf, worldToLocal } from 'core/geometry/targetFrame';\nimport { poseFrameOf } from '@weasel-js/geom';\nimport { caretIndexAt, pointInTextPose, isTextData, type StyledRun, type TextPaint, type TextStyle, type TextVerticalAlign } from '@weasel-js/text';\nimport { useTextEdit, type TextEditClipRect, type TextEditScreenPose, type UseTextEditReturn } from '@weasel-js/text-dom';\n\n/** Shape the default projections expect `data` to satisfy. All fields\n * optional so any object satisfies the constraint — projections fill in\n * the gaps for non-default shapes. */\nexport interface DefaultTextData {\n text?: string;\n style?: TextStyle;\n runs?: readonly StyledRun[];\n fill?: Fill | null;\n stroke?: Stroke | null;\n verticalAlign?: TextVerticalAlign;\n}\n\n/** All-optional projections + fontSize fallback. */\nexport interface UseSceneTextEditOptions<TData> {\n /**\n * Is this node text? A double-click opens an edit only on a node that\n * answers yes, and passes through any other to the text under it. Default:\n * `isTextData`, the test `inferredNodeRouting` classifies a text node by. Pass one when `getText` reads some other shape.\n */\n isText?: (data: TData) => boolean;\n /** Read plain text from `data`. Default: `data.text ?? ''`. */\n getText?: (data: TData) => string;\n /** Read style from `data`. Default: `data.style`. */\n getStyle?: (data: TData) => TextStyle | undefined;\n /** Read the node's paint from `data`. Default: `data.fill` / `data.stroke`. */\n getPaint?: (data: TData) => TextPaint | undefined;\n /** Read rich-text runs from `data`. Default: `data.runs`. */\n getRuns?: (data: TData) => readonly StyledRun[] | undefined;\n /** Read the box vertical alignment from `data`. Default: `data.verticalAlign`. */\n getVerticalAlign?: (data: TData) => TextVerticalAlign | undefined;\n /** Produce updated data with new text. Default: `{ ...data, text }`. */\n setText?: (data: TData, text: string) => TData;\n /** Produce updated data with new runs. Default: `{ ...data, runs }`. */\n setRuns?: (data: TData, runs: StyledRun[]) => TData;\n /**\n * Produce updated data with a new node-wide style. Default:\n * `{ ...data, style }`. Written only when a range toggle has to *clear* a\n * flag the node itself sets — the run algebra is additive, so that edit\n * lowers the node flag and raises it on the runs outside the range. See\n * `useTextEdit`'s `setStyle`.\n *\n * An edit's text, runs, and style are folded through these three and\n * written as one `scene.update`, so a commit is one undo step.\n */\n setStyle?: (data: TData, style: TextStyle) => TData;\n /** Fallback fontSize when `style.fontSize` is unset. Default `16`. */\n defaultFontSize?: number;\n /**\n * The view to project through. Omit it and the view is read live from the\n * weasel canvas mounted inside `container` (the one a double-click landed\n * on, when there are several). With no canvas there, the node's world box\n * is passed through as screen pixels.\n *\n * The overlay takes a single scale factor, so a non-uniform view scale is\n * represented by its `scale.x`; text under `scale.x !== scale.y` will not\n * match the canvas.\n *\n * A thunk is re-read on every projection; a plain `View` is the value from\n * the render that supplied it.\n */\n view?: View | (() => View);\n /**\n * Forwarded to `useTextEdit`: is `el` part of the editor's own chrome?\n * Focus moving into it does not end the edit. Wire it to whatever renders\n * the character controls.\n */\n isEditorChrome?: (el: Element) => boolean;\n /** Forwarded to `useTextEdit`: what Escape does to the edit. */\n escape?: 'cancel' | 'commit';\n /** Forwarded to `useTextEdit`: how long an edit waits for its face. */\n fontHold?: number;\n}\n\nfunction resolveView(view: View | (() => View) | undefined): View | undefined {\n return typeof view === 'function' ? view() : view;\n}\n\n/** Return shape extends `UseTextEditReturn` with an `onDoubleClick`\n * binding for the canvas container. Double-clicking inside a text\n * node enters edit mode with the caret seeded at the clicked glyph. */\nexport interface UseSceneTextEditReturn extends UseTextEditReturn {\n /** Bind to the element wrapping `<SceneCanvas>` (the same element\n * passed as `container`, or any ancestor that receives the dblclick\n * bubble). Starts an edit on the top-most text node under the cursor. */\n onDoubleClick: (e: MouseEvent<HTMLElement>) => void;\n /** The `isText` option asked of the node with this id: what\n * `TextEditDep.isTextNode` wants, so both ways into an edit agree. */\n isTextNode: (id: string) => boolean;\n}\n\n/** Wire double-click-to-edit text on a scene: mounts a DOM editing overlay\n * over the node being edited and writes the result back as an undoable op. */\nexport function useSceneTextEdit<\n TData extends DefaultTextData,\n TLayer extends string,\n TPose extends RectPose = RectPose,\n>(\n scene: Scene<TData, TLayer, TPose>,\n container: HTMLElement | null,\n options: UseSceneTextEditOptions<TData> = {},\n): UseSceneTextEditReturn {\n // Refs, so the useTextEdit callbacks always see the current values\n // without re-binding.\n const sceneRef = useLatest(scene);\n const optsRef = useLatest(options);\n const containerRef = useLatest(container);\n // The last double-click's target, so the overlay projects through the\n // canvas the edit was opened on.\n const openedOnRef = useRef<EventTarget | null>(null);\n\n // The canvas's box in container pixels is both the origin its view projects\n // from and the region its glyphs are clipped to.\n const surface = (): { canvas: MountedCanvas; box: TextEditClipRect } | null => {\n const root = containerRef.current;\n const canvas = root ? findMountedCanvas(root, openedOnRef.current) : null;\n if (!root || !canvas) return null;\n const a = canvas.element.getBoundingClientRect();\n const b = root.getBoundingClientRect();\n return {\n canvas,\n box: {\n x: a.left - b.left - root.clientLeft + root.scrollLeft,\n y: a.top - b.top - root.clientTop + root.scrollTop,\n width: a.width,\n height: a.height,\n },\n };\n };\n\n const read = useMemo(() => ({\n isText: (data: TData): boolean =>\n optsRef.current.isText ? optsRef.current.isText(data) : isTextData(data),\n text: (data: TData): string =>\n optsRef.current.getText ? optsRef.current.getText(data) : (data.text ?? ''),\n style: (data: TData): TextStyle | undefined =>\n optsRef.current.getStyle ? optsRef.current.getStyle(data) : data.style,\n runs: (data: TData): readonly StyledRun[] | undefined =>\n optsRef.current.getRuns ? optsRef.current.getRuns(data) : data.runs,\n verticalAlign: (data: TData): TextVerticalAlign | undefined =>\n optsRef.current.getVerticalAlign ? optsRef.current.getVerticalAlign(data) : data.verticalAlign,\n }), [optsRef]);\n\n const edit = useTextEdit({\n container,\n isEditorChrome: (el) => optsRef.current.isEditorChrome?.(el) ?? false,\n escape: options.escape,\n fontHold: options.fontHold,\n getText: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.text(node.data) : '';\n },\n getStyle: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.style(node.data) : undefined;\n },\n getPaint: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n if (!node) return undefined;\n const get = optsRef.current.getPaint;\n return get ? get(node.data) : { fill: node.data.fill, stroke: node.data.stroke };\n },\n getScreenPose: (id) => {\n const scene = sceneRef.current;\n const node = scene.get(asNodeId(id));\n if (!node) return null;\n const pose = effectivePose(scene, node);\n const style = read.style(node.data);\n const at = surface();\n const view = resolveView(optsRef.current.view) ?? at?.canvas.getView();\n const zoom = view ? view.scale.x : 1;\n const originX = at?.box.x ?? 0;\n const originY = at?.box.y ?? 0;\n // Only the origin is projected. Width, height and font size stay in\n // world units and reach the screen through the overlay's own\n // `scale(zoom)` — see `TextEditScreenPose.zoom`.\n return {\n x: originX + (view ? (pose.x - view.x) * view.scale.x : pose.x),\n y: originY + (view ? (pose.y - view.y) * view.scale.y : pose.y),\n width: pose.width,\n height: pose.height,\n // Against `zoom`, the same factor the overlay scales back up by, so a\n // `{ px }` size arrives on screen at the pixel count it names.\n fontSize: resolveScreenLength(\n style?.fontSize ?? optsRef.current.defaultFontSize ?? 16,\n zoom,\n ),\n zoom,\n frame: frameLinearOf(pose),\n verticalAlign: read.verticalAlign(node.data),\n };\n },\n getClipRect: () => surface()?.box ?? null,\n getRuns: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.runs(node.data) : undefined;\n },\n commit: (id, { text, runs, style }) => {\n const nid = asNodeId(id);\n const node = sceneRef.current.get(nid);\n if (!node) return;\n const { setText, setRuns, setStyle } = optsRef.current;\n let data = setText ? setText(node.data, text) : { ...node.data, text };\n if (runs) data = setRuns ? setRuns(data, runs) : { ...data, runs };\n if (style) data = setStyle ? setStyle(data, style) : { ...data, style };\n sceneRef.current.update(nid, { data });\n },\n });\n\n const onDoubleClick = useCallback((e: MouseEvent<HTMLElement>) => {\n // The dblclick bubbles from the canvas up to any wrapping container; the\n // element it started on is what the click coordinates are relative to.\n const canvas = e.target instanceof HTMLElement ? e.target : null;\n if (!canvas) return;\n // Inside the editor a double-click selects a word, and its target is a run\n // span whose box the click would be measured against as if it were a canvas.\n if (canvas.closest('[contenteditable=\"true\"]')) return;\n\n // `pointInTextPose` and `caretIndexAt` work in the node's own box: the click\n // is un-projected here, then taken back through the frame the node is drawn in.\n const [canvasX, canvasY] = clientToCanvas(canvas, e.clientX, e.clientY);\n const root = containerRef.current;\n const view = resolveView(optsRef.current.view)\n ?? (root ? findMountedCanvas(root, canvas)?.getView() : undefined);\n const cx = view ? canvasX / view.scale.x + view.x : canvasX;\n const cy = view ? canvasY / view.scale.y + view.y : canvasY;\n // Top-most-first hit test: renderOrder() is back-to-front, so iterate\n // in reverse and break on the first hit.\n const order = sceneRef.current.renderOrderNodes();\n for (let i = order.length - 1; i >= 0; i--) {\n const node = order[i];\n if (sceneRef.current.isLocked(node.id)) continue;\n if (!read.isText(node.data)) continue;\n const text = read.text(node.data);\n const at = effectivePose(sceneRef.current, node);\n const p = worldToLocal(targetTransformOf(at), cx, cy);\n if (!p) continue;\n const pose = {\n x: at.x, y: at.y, width: at.width, height: at.height,\n text,\n runs: read.runs(node.data) as StyledRun[] | undefined,\n style: read.style(node.data),\n verticalAlign: read.verticalAlign(node.data),\n };\n if (!pointInTextPose(p.x, p.y, pose)) continue;\n\n openedOnRef.current = canvas;\n edit.startEdit(String(node.id), { caret: caretIndexAt(p.x, p.y, pose) });\n return;\n }\n }, [edit, containerRef, optsRef, read, sceneRef]);\n\n const isTextNode = useCallback((id: string): boolean => {\n const node = sceneRef.current.get(asNodeId(id));\n return node !== undefined && read.isText(node.data);\n }, [read, sceneRef]);\n\n return { ...edit, onDoubleClick, isTextNode };\n}\n\n/** The linear part of the frame `pose` is drawn in, as the overlay takes it. */\nfunction frameLinearOf(pose: unknown): TextEditScreenPose['frame'] {\n const m = poseFrameOf(pose);\n return m ? [m[0], m[1], m[2], m[3]] : undefined;\n}\n"],"mappings":"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"}