@weasel-js/core 1.9.3 → 1.9.4

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 (542) hide show
  1. package/CHANGELOG.md +356 -0
  2. package/README.md +2 -2
  3. package/dist/WeaselProvider.js +5 -5
  4. package/dist/affordances/composeAffordanceLayer.js +10 -20
  5. package/dist/affordances/composeAffordanceLayer.js.map +1 -1
  6. package/dist/affordances/cornerResize.js +25 -17
  7. package/dist/affordances/cornerResize.js.map +1 -1
  8. package/dist/affordances/hitAffordanceRegions.js +27 -20
  9. package/dist/affordances/hitAffordanceRegions.js.map +1 -1
  10. package/dist/affordances/rotationHandle.js +18 -18
  11. package/dist/affordances/rotationHandle.js.map +1 -1
  12. package/dist/animation/behaviors/momentum.js +93 -55
  13. package/dist/animation/behaviors/momentum.js.map +1 -1
  14. package/dist/animation/loop.js +10 -12
  15. package/dist/animation/loop.js.map +1 -1
  16. package/dist/animation/reflow.js +8 -8
  17. package/dist/animation/reflow.js.map +1 -1
  18. package/dist/animation/stagger.js +64 -56
  19. package/dist/animation/stagger.js.map +1 -1
  20. package/dist/animation/timeline/booking.js +62 -54
  21. package/dist/animation/timeline/booking.js.map +1 -1
  22. package/dist/animation/timeline/createTimeline.js +85 -76
  23. package/dist/animation/timeline/createTimeline.js.map +1 -1
  24. package/dist/animation/timeline/sampleTrack.js +13 -5
  25. package/dist/animation/timeline/sampleTrack.js.map +1 -1
  26. package/dist/animation/useAnimator.js +45 -35
  27. package/dist/animation/useAnimator.js.map +1 -1
  28. package/dist/animation/wrappers/animateLifecycle.js +31 -24
  29. package/dist/animation/wrappers/animateLifecycle.js.map +1 -1
  30. package/dist/animation/wrappers/animateOnSetPose.js +28 -26
  31. package/dist/animation/wrappers/animateOnSetPose.js.map +1 -1
  32. package/dist/animation/wrappers/instantPose.js +13 -0
  33. package/dist/animation/wrappers/instantPose.js.map +1 -0
  34. package/dist/{poseDescriptor-D-OH-tu5.d.ts → autoPoseDescriptor-Ct7yqivU.d.ts} +28 -3
  35. package/dist/barrel/chrome.js +16 -0
  36. package/dist/barrel/input.js +19 -0
  37. package/dist/barrel/interactions.js +42 -0
  38. package/dist/barrel/paint.js +18 -0
  39. package/dist/barrel/paths.js +19 -0
  40. package/dist/barrel/renderer.js +20 -0
  41. package/dist/barrel/routing.js +51 -0
  42. package/dist/barrel/text.js +18 -0
  43. package/dist/barrel/viewport.js +52 -0
  44. package/dist/builtins-DPcdghtB.d.ts +1223 -0
  45. package/dist/canvas/Canvas.js +363 -448
  46. package/dist/canvas/Canvas.js.map +1 -1
  47. package/dist/canvas/CanvasView.js +164 -165
  48. package/dist/canvas/CanvasView.js.map +1 -1
  49. package/dist/canvas/CursorCoordsHud.js +37 -32
  50. package/dist/canvas/CursorCoordsHud.js.map +1 -1
  51. package/dist/canvas/DrawCanvas.js +49 -43
  52. package/dist/canvas/DrawCanvas.js.map +1 -1
  53. package/dist/canvas/MinimapCanvas.js +26 -25
  54. package/dist/canvas/MinimapCanvas.js.map +1 -1
  55. package/dist/canvas/NodeShape.js +59 -377
  56. package/dist/canvas/NodeShape.js.map +1 -1
  57. package/dist/canvas/PickHud.js +50 -47
  58. package/dist/canvas/PickHud.js.map +1 -1
  59. package/dist/canvas/SceneCanvas/GestureDispatcherMounter.js +167 -0
  60. package/dist/canvas/SceneCanvas/GestureDispatcherMounter.js.map +1 -0
  61. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +13 -13
  62. package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js +67 -0
  63. package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js.map +1 -0
  64. package/dist/canvas/SceneCanvas/ToolKeybindingsMounter.js +16 -0
  65. package/dist/canvas/SceneCanvas/ToolKeybindingsMounter.js.map +1 -0
  66. package/dist/canvas/SceneCanvas/coordTrace.js +10 -0
  67. package/dist/canvas/SceneCanvas/coordTrace.js.map +1 -0
  68. package/dist/canvas/SceneCanvas/defaultNodeProperties.js +112 -70
  69. package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
  70. package/dist/canvas/SceneCanvas/defaultNodeRouting.js +9 -8
  71. package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
  72. package/dist/canvas/SceneCanvas/features.js +1 -0
  73. package/dist/canvas/SceneCanvas/features.js.map +1 -1
  74. package/dist/canvas/SceneCanvas/isDev.js +12 -0
  75. package/dist/canvas/SceneCanvas/isDev.js.map +1 -0
  76. package/dist/canvas/SceneCanvas/poseGeometry.js +29 -28
  77. package/dist/canvas/SceneCanvas/poseGeometry.js.map +1 -1
  78. package/dist/canvas/SceneCanvas/poseRegistrars.js +13 -0
  79. package/dist/canvas/SceneCanvas/poseRegistrars.js.map +1 -0
  80. package/dist/canvas/SceneCanvas/props.js +38 -0
  81. package/dist/canvas/SceneCanvas/props.js.map +1 -0
  82. package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js +21 -62
  83. package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js.map +1 -1
  84. package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js.map +1 -1
  85. package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js +46 -48
  86. package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js.map +1 -1
  87. package/dist/canvas/SceneCanvas/useSceneSelectTool.js +33 -33
  88. package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
  89. package/dist/canvas/SceneCanvas.js +534 -788
  90. package/dist/canvas/SceneCanvas.js.map +1 -1
  91. package/dist/canvas/SceneViewCanvas.js +45 -43
  92. package/dist/canvas/SceneViewCanvas.js.map +1 -1
  93. package/dist/canvas/buildSceneLayer.js +91 -0
  94. package/dist/canvas/buildSceneLayer.js.map +1 -0
  95. package/dist/canvas/buildSceneTree.js +16 -19
  96. package/dist/canvas/buildSceneTree.js.map +1 -1
  97. package/dist/canvas/canvasRenderer.js +68 -52
  98. package/dist/canvas/canvasRenderer.js.map +1 -1
  99. package/dist/canvas/deps/changes.js +13 -0
  100. package/dist/canvas/deps/changes.js.map +1 -0
  101. package/dist/canvas/deps/editAnchors.js +28 -28
  102. package/dist/canvas/deps/insert.js +119 -91
  103. package/dist/canvas/deps/insert.js.map +1 -1
  104. package/dist/canvas/deps/slice.js +46 -45
  105. package/dist/canvas/deps/slice.js.map +1 -1
  106. package/dist/canvas/deps/textEdit.js +10 -9
  107. package/dist/canvas/deps/textEdit.js.map +1 -1
  108. package/dist/canvas/derivedPath.js +46 -23
  109. package/dist/canvas/derivedPath.js.map +1 -1
  110. package/dist/canvas/getNodeAtPoint.js +7 -7
  111. package/dist/canvas/getNodeAtPoint.js.map +1 -1
  112. package/dist/canvas/hud.module.js +1 -1
  113. package/dist/canvas/hud.module.js.map +1 -1
  114. package/dist/canvas/kitRequirements.js +2 -2
  115. package/dist/canvas/kitRequirements.js.map +1 -1
  116. package/dist/canvas/layerOrder.js +13 -6
  117. package/dist/canvas/layerOrder.js.map +1 -1
  118. package/dist/canvas/minimapMath.js +12 -10
  119. package/dist/canvas/minimapMath.js.map +1 -1
  120. package/dist/canvas/nodeShapes/derivedPainter.js +34 -0
  121. package/dist/canvas/nodeShapes/derivedPainter.js.map +1 -0
  122. package/dist/canvas/nodeShapes/imagePainter.js +87 -0
  123. package/dist/canvas/nodeShapes/imagePainter.js.map +1 -0
  124. package/dist/canvas/nodeShapes/memo.js +9 -0
  125. package/dist/canvas/nodeShapes/memo.js.map +1 -0
  126. package/dist/canvas/nodeShapes/nodePaint.js +57 -0
  127. package/dist/canvas/nodeShapes/nodePaint.js.map +1 -0
  128. package/dist/canvas/nodeShapes/pathPainter.js +38 -0
  129. package/dist/canvas/nodeShapes/pathPainter.js.map +1 -0
  130. package/dist/canvas/nodeShapes/poseBox.js +20 -0
  131. package/dist/canvas/nodeShapes/poseBox.js.map +1 -0
  132. package/dist/canvas/nodeShapes/rectFallbackPainter.js +38 -0
  133. package/dist/canvas/nodeShapes/rectFallbackPainter.js.map +1 -0
  134. package/dist/canvas/nodeShapes/shapePainter.js +72 -0
  135. package/dist/canvas/nodeShapes/shapePainter.js.map +1 -0
  136. package/dist/canvas/nodeShapes/textPainter.js +55 -0
  137. package/dist/canvas/nodeShapes/textPainter.js.map +1 -0
  138. package/dist/canvas/overlayRoleStrokes.js.map +1 -1
  139. package/dist/canvas/paintCull.js +10 -11
  140. package/dist/canvas/paintCull.js.map +1 -1
  141. package/dist/canvas/pickWalk.js +52 -63
  142. package/dist/canvas/pickWalk.js.map +1 -1
  143. package/dist/canvas/poseRotation.js +11 -23
  144. package/dist/canvas/poseRotation.js.map +1 -1
  145. package/dist/canvas/renderDebugSnapshot.js +5 -5
  146. package/dist/canvas/renderSceneToPixels.js +3 -1
  147. package/dist/canvas/renderSceneToPixels.js.map +1 -1
  148. package/dist/canvas/sceneAdapter.js +66 -148
  149. package/dist/canvas/sceneAdapter.js.map +1 -1
  150. package/dist/canvas/sceneClipboard.js +112 -0
  151. package/dist/canvas/sceneClipboard.js.map +1 -0
  152. package/dist/canvas/sceneSlotWiring.js +4 -4
  153. package/dist/canvas/sceneSlotWiring.js.map +1 -1
  154. package/dist/canvas/sceneViewRender.js +39 -40
  155. package/dist/canvas/sceneViewRender.js.map +1 -1
  156. package/dist/canvas/useCanvasRenderer.js +14 -6
  157. package/dist/canvas/useCanvasRenderer.js.map +1 -1
  158. package/dist/canvas/useCanvasView.js +58 -0
  159. package/dist/canvas/useCanvasView.js.map +1 -0
  160. package/dist/canvas/useFrameLoop.js +35 -26
  161. package/dist/canvas/useFrameLoop.js.map +1 -1
  162. package/dist/canvas/useSceneLayerList.js +21 -0
  163. package/dist/canvas/useSceneLayerList.js.map +1 -0
  164. package/dist/clipboard.d.ts +10 -6
  165. package/dist/clone.d.ts +4 -3
  166. package/dist/core/adapters/arrayAdapter.js +48 -39
  167. package/dist/core/adapters/arrayAdapter.js.map +1 -1
  168. package/dist/core/device/index.js +5 -4
  169. package/dist/core/device/useDeviceProfile.js +38 -44
  170. package/dist/core/device/useDeviceProfile.js.map +1 -1
  171. package/dist/core/device/watchDevicePixelRatio.js +17 -0
  172. package/dist/core/device/watchDevicePixelRatio.js.map +1 -0
  173. package/dist/core/fillInPoseFrame.js.map +1 -1
  174. package/dist/core/geometry/poseDescriptor.js +21 -19
  175. package/dist/core/geometry/poseDescriptor.js.map +1 -1
  176. package/dist/core/geometry/poseFrame.js +44 -0
  177. package/dist/core/geometry/poseFrame.js.map +1 -0
  178. package/dist/core/geometry/poseRotation.js.map +1 -1
  179. package/dist/core/geometry/regionHit.js +9 -10
  180. package/dist/core/geometry/regionHit.js.map +1 -1
  181. package/dist/core/geometry/unionBounds.js +31 -29
  182. package/dist/core/geometry/unionBounds.js.map +1 -1
  183. package/dist/core/isPlainObject.js +2 -11
  184. package/dist/core/ops/arrange.js +1 -0
  185. package/dist/core/ops/arrange.js.map +1 -1
  186. package/dist/core/ops/create.js +10 -5
  187. package/dist/core/ops/create.js.map +1 -1
  188. package/dist/core/ops/delete.js +12 -24
  189. package/dist/core/ops/delete.js.map +1 -1
  190. package/dist/core/ops/reorder/index.js +43 -40
  191. package/dist/core/ops/reorder/index.js.map +1 -1
  192. package/dist/core/ops/reorder/setChildOrder.js +34 -0
  193. package/dist/core/ops/reorder/setChildOrder.js.map +1 -0
  194. package/dist/core/paintKinds.js +5 -5
  195. package/dist/core/paintKinds.js.map +1 -1
  196. package/dist/core/scene/NodeProperties.js.map +1 -1
  197. package/dist/core/scene/appliedLog.js +37 -0
  198. package/dist/core/scene/appliedLog.js.map +1 -0
  199. package/dist/core/scene/arrivalWindow.js +101 -0
  200. package/dist/core/scene/arrivalWindow.js.map +1 -0
  201. package/dist/core/scene/derivedPath.js.map +1 -1
  202. package/dist/core/scene/historyFacade.js +84 -0
  203. package/dist/core/scene/historyFacade.js.map +1 -0
  204. package/dist/core/scene/kitOps.js +173 -0
  205. package/dist/core/scene/kitOps.js.map +1 -0
  206. package/dist/core/scene/layerStack.js +38 -0
  207. package/dist/core/scene/layerStack.js.map +1 -0
  208. package/dist/core/scene/lockGuard.js +37 -0
  209. package/dist/core/scene/lockGuard.js.map +1 -0
  210. package/dist/core/scene/nodeFnFields.js +5 -6
  211. package/dist/core/scene/nodeFnFields.js.map +1 -1
  212. package/dist/core/scene/nodeMemo.js +45 -19
  213. package/dist/core/scene/nodeMemo.js.map +1 -1
  214. package/dist/core/scene/nodeStore.js +126 -0
  215. package/dist/core/scene/nodeStore.js.map +1 -0
  216. package/dist/core/scene/pickability.js +6 -0
  217. package/dist/core/scene/pickability.js.map +1 -0
  218. package/dist/core/scene/poseFeed.js +38 -38
  219. package/dist/core/scene/poseFeed.js.map +1 -1
  220. package/dist/core/scene/poseOverrides.js +34 -38
  221. package/dist/core/scene/poseOverrides.js.map +1 -1
  222. package/dist/core/scene/renderOrder.js +84 -0
  223. package/dist/core/scene/renderOrder.js.map +1 -0
  224. package/dist/core/scene/scene.js +289 -866
  225. package/dist/core/scene/scene.js.map +1 -1
  226. package/dist/core/scene/serialization.js +68 -0
  227. package/dist/core/scene/serialization.js.map +1 -0
  228. package/dist/core/scene/treeOrder.js +13 -0
  229. package/dist/core/scene/treeOrder.js.map +1 -0
  230. package/dist/core/scene/types.js.map +1 -1
  231. package/dist/core/viewport/meanScale.js +1 -1
  232. package/dist/core/viewport/meanScale.js.map +1 -1
  233. package/dist/core/viewport/view.js +12 -12
  234. package/dist/core/viewport/view.js.map +1 -1
  235. package/dist/core/viewport/zoomBounds.js +10 -8
  236. package/dist/core/viewport/zoomBounds.js.map +1 -1
  237. package/dist/{cornerHandles-BCrDp_mH.d.ts → cornerHandles-CtCb8a3G.d.ts} +1 -1
  238. package/dist/debug/createDebugOverlayLayer.js +14 -14
  239. package/dist/debug/createDebugOverlayLayer.js.map +1 -1
  240. package/dist/debug/flag.js +2 -41
  241. package/dist/features/chrome-caps/useHoverTracking.js +22 -17
  242. package/dist/features/chrome-caps/useHoverTracking.js.map +1 -1
  243. package/dist/features/focus/gateLayer.js +3 -4
  244. package/dist/features/focus/gateLayer.js.map +1 -1
  245. package/dist/features/images/imageCache.js +19 -9
  246. package/dist/features/images/imageCache.js.map +1 -1
  247. package/dist/features/ingestion/contentHandlers.js +14 -11
  248. package/dist/features/ingestion/contentHandlers.js.map +1 -1
  249. package/dist/features/ingestion/index.js +1 -1
  250. package/dist/features/ingestion/registerKitHandlers.js +7 -7
  251. package/dist/features/ingestion/weaselJsonHandler.js +17 -14
  252. package/dist/features/ingestion/weaselJsonHandler.js.map +1 -1
  253. package/dist/features/meshPaint/lazyKind.js +201 -35
  254. package/dist/features/meshPaint/lazyKind.js.map +1 -1
  255. package/dist/features/meshPaint/meshPaint.js +82 -79
  256. package/dist/features/meshPaint/meshPaint.js.map +1 -1
  257. package/dist/features/minimap/createMinimapContribution.js +42 -42
  258. package/dist/features/minimap/layers.js +44 -62
  259. package/dist/features/minimap/layers.js.map +1 -1
  260. package/dist/features/parallax/createParallaxPlane.js +10 -14
  261. package/dist/features/parallax/createParallaxPlane.js.map +1 -1
  262. package/dist/features/paths/anchorEdits.js +19 -8
  263. package/dist/features/paths/anchorEdits.js.map +1 -1
  264. package/dist/features/paths/anchors.js +31 -26
  265. package/dist/features/paths/anchors.js.map +1 -1
  266. package/dist/features/paths/booleans.js +2 -2
  267. package/dist/features/paths/index.js +13 -11
  268. package/dist/features/paths/markerCommands.js +37 -36
  269. package/dist/features/paths/markerCommands.js.map +1 -1
  270. package/dist/features/paths/pathInWorld.js +19 -19
  271. package/dist/features/paths/pathInWorld.js.map +1 -1
  272. package/dist/features/paths/pathLayer.js.map +1 -1
  273. package/dist/features/paths/strokeToPath.js +40 -0
  274. package/dist/features/paths/strokeToPath.js.map +1 -0
  275. package/dist/features/paths/tessellate/stroke.js.map +1 -1
  276. package/dist/features/patterns/commandPaint.js +18 -0
  277. package/dist/features/patterns/commandPaint.js.map +1 -0
  278. package/dist/features/patterns/index.js +5 -17
  279. package/dist/features/patterns/index.js.map +1 -1
  280. package/dist/features/patterns/rasterizeTile.js +17 -0
  281. package/dist/features/patterns/rasterizeTile.js.map +1 -0
  282. package/dist/features/patterns/resolveSpec.js +52 -44
  283. package/dist/features/patterns/resolveSpec.js.map +1 -1
  284. package/dist/features/poseRun/usePoseRun.js +8 -3
  285. package/dist/features/poseRun/usePoseRun.js.map +1 -1
  286. package/dist/features/selection/SelectionContext.js +5 -0
  287. package/dist/features/selection/SelectionContext.js.map +1 -1
  288. package/dist/features/selection/overlay.js +18 -18
  289. package/dist/features/selection/overlay.js.map +1 -1
  290. package/dist/features/text/domOffsets.js +82 -0
  291. package/dist/features/text/domOffsets.js.map +1 -0
  292. package/dist/features/text/domRuns.js +103 -131
  293. package/dist/features/text/domRuns.js.map +1 -1
  294. package/dist/features/text/hitTest.js +5 -2
  295. package/dist/features/text/hitTest.js.map +1 -1
  296. package/dist/features/text/isTextData.js +8 -0
  297. package/dist/features/text/isTextData.js.map +1 -0
  298. package/dist/features/text/overlayDirection.js +15 -0
  299. package/dist/features/text/overlayDirection.js.map +1 -0
  300. package/dist/features/text/runs/rangeStyle.js +32 -34
  301. package/dist/features/text/runs/rangeStyle.js.map +1 -1
  302. package/dist/features/text/textCommand.js +34 -33
  303. package/dist/features/text/textCommand.js.map +1 -1
  304. package/dist/features/text/textToPath.js +40 -40
  305. package/dist/features/text/textToPath.js.map +1 -1
  306. package/dist/features/text/useSceneTextEdit.js +76 -82
  307. package/dist/features/text/useSceneTextEdit.js.map +1 -1
  308. package/dist/features/text/useTextEdit.js +184 -160
  309. package/dist/features/text/useTextEdit.js.map +1 -1
  310. package/dist/features/tiling/createTiledLayer.js +24 -22
  311. package/dist/features/tiling/createTiledLayer.js.map +1 -1
  312. package/dist/index.d.ts +11033 -7749
  313. package/dist/index.js +316 -309
  314. package/dist/input/keyState.js +42 -43
  315. package/dist/input/keyState.js.map +1 -1
  316. package/dist/input/useKeyModifiers.js +11 -0
  317. package/dist/input/useKeyModifiers.js.map +1 -0
  318. package/dist/interactions/actions/align/align.js +8 -8
  319. package/dist/interactions/actions/clipboard/clipboardOps.js +34 -32
  320. package/dist/interactions/actions/clipboard/clipboardOps.js.map +1 -1
  321. package/dist/interactions/actions/clipboard/materializePaste.js +10 -7
  322. package/dist/interactions/actions/clipboard/materializePaste.js.map +1 -1
  323. package/dist/interactions/actions/clipboard/wireFormat.js.map +1 -1
  324. package/dist/interactions/actions/clone/behaviors/cloneByAltDrag.js.map +1 -1
  325. package/dist/interactions/actions/defaultCommitAdapter.js +20 -18
  326. package/dist/interactions/actions/defaultCommitAdapter.js.map +1 -1
  327. package/dist/interactions/actions/defaults/align.js +9 -10
  328. package/dist/interactions/actions/defaults/align.js.map +1 -1
  329. package/dist/interactions/actions/defaults/anchorEditing.js +59 -81
  330. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  331. package/dist/interactions/actions/defaults/areaSelect.js +35 -38
  332. package/dist/interactions/actions/defaults/areaSelect.js.map +1 -1
  333. package/dist/interactions/actions/defaults/clipboard.js +26 -10
  334. package/dist/interactions/actions/defaults/clipboard.js.map +1 -1
  335. package/dist/interactions/actions/defaults/clone.js +44 -60
  336. package/dist/interactions/actions/defaults/clone.js.map +1 -1
  337. package/dist/interactions/actions/defaults/copySubtree.js +40 -0
  338. package/dist/interactions/actions/defaults/copySubtree.js.map +1 -0
  339. package/dist/interactions/actions/defaults/distribute.js +14 -13
  340. package/dist/interactions/actions/defaults/distribute.js.map +1 -1
  341. package/dist/interactions/actions/defaults/duplicate.js +17 -57
  342. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  343. package/dist/interactions/actions/defaults/editAnchors.js +18 -18
  344. package/dist/interactions/actions/defaults/enterTextEdit.js.map +1 -1
  345. package/dist/interactions/actions/defaults/flip.js +52 -46
  346. package/dist/interactions/actions/defaults/flip.js.map +1 -1
  347. package/dist/interactions/actions/defaults/group.js +43 -48
  348. package/dist/interactions/actions/defaults/group.js.map +1 -1
  349. package/dist/interactions/actions/defaults/ingest.js +35 -33
  350. package/dist/interactions/actions/defaults/ingest.js.map +1 -1
  351. package/dist/interactions/actions/defaults/insert.js +50 -51
  352. package/dist/interactions/actions/defaults/insert.js.map +1 -1
  353. package/dist/interactions/actions/defaults/insertPathAnchor.js +7 -7
  354. package/dist/interactions/actions/defaults/lassoSelect.js +67 -70
  355. package/dist/interactions/actions/defaults/lassoSelect.js.map +1 -1
  356. package/dist/interactions/actions/defaults/move.js +267 -249
  357. package/dist/interactions/actions/defaults/move.js.map +1 -1
  358. package/dist/interactions/actions/defaults/nudge.js +40 -68
  359. package/dist/interactions/actions/defaults/nudge.js.map +1 -1
  360. package/dist/interactions/actions/defaults/nudgeSteps.js +37 -0
  361. package/dist/interactions/actions/defaults/nudgeSteps.js.map +1 -0
  362. package/dist/interactions/actions/defaults/reorder.js +2 -0
  363. package/dist/interactions/actions/defaults/reorder.js.map +1 -1
  364. package/dist/interactions/actions/defaults/resize.js +104 -98
  365. package/dist/interactions/actions/defaults/resize.js.map +1 -1
  366. package/dist/interactions/actions/defaults/rotate.js +111 -110
  367. package/dist/interactions/actions/defaults/rotate.js.map +1 -1
  368. package/dist/interactions/actions/defaults/setFill.js +7 -7
  369. package/dist/interactions/actions/defaults/setFillOpacity.js +4 -4
  370. package/dist/interactions/actions/defaults/setStroke.js +12 -12
  371. package/dist/interactions/actions/defaults/setStrokeOpacity.js +6 -6
  372. package/dist/interactions/actions/defaults/sliceOps.js +19 -19
  373. package/dist/interactions/actions/defaults/viewportDragPan.js +37 -26
  374. package/dist/interactions/actions/defaults/viewportDragPan.js.map +1 -1
  375. package/dist/interactions/actions/edit-anchors/geometry.js +28 -23
  376. package/dist/interactions/actions/edit-anchors/geometry.js.map +1 -1
  377. package/dist/interactions/actions/flip/helpers.js +30 -17
  378. package/dist/interactions/actions/flip/helpers.js.map +1 -1
  379. package/dist/interactions/actions/hitSelection.js +8 -0
  380. package/dist/interactions/actions/hitSelection.js.map +1 -0
  381. package/dist/interactions/actions/lasso-select/behaviors/selectFromLasso.js +14 -18
  382. package/dist/interactions/actions/lasso-select/behaviors/selectFromLasso.js.map +1 -1
  383. package/dist/interactions/actions/move/behaviors/snapBackOrDelete.js +5 -5
  384. package/dist/interactions/actions/move/behaviors/snapBackOrDelete.js.map +1 -1
  385. package/dist/interactions/actions/move/behaviors/snapToContainer.js +32 -21
  386. package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
  387. package/dist/interactions/actions/move/gestureAdapter.js +32 -15
  388. package/dist/interactions/actions/move/gestureAdapter.js.map +1 -1
  389. package/dist/interactions/actions/move/landedDescendants.js +33 -0
  390. package/dist/interactions/actions/move/landedDescendants.js.map +1 -0
  391. package/dist/interactions/actions/outlines/createOutlines.js +18 -18
  392. package/dist/interactions/actions/poseDescriptorDep.js +16 -4
  393. package/dist/interactions/actions/poseDescriptorDep.js.map +1 -1
  394. package/dist/interactions/actions/poseFrame.js +11 -6
  395. package/dist/interactions/actions/poseFrame.js.map +1 -1
  396. package/dist/interactions/actions/previewOverrides.js +5 -5
  397. package/dist/interactions/actions/previewOverrides.js.map +1 -1
  398. package/dist/interactions/actions/selectionSubtree.js +69 -0
  399. package/dist/interactions/actions/selectionSubtree.js.map +1 -0
  400. package/dist/interactions/actions/useStandardActions.js +66 -62
  401. package/dist/interactions/actions/useStandardActions.js.map +1 -1
  402. package/dist/interactions/gestures/dragGesture/dragGesture.js +4 -7
  403. package/dist/interactions/gestures/dragGesture/dragGesture.js.map +1 -1
  404. package/dist/interactions/gestures/dragGesture/dragPointOf.js +23 -0
  405. package/dist/interactions/gestures/dragGesture/dragPointOf.js.map +1 -0
  406. package/dist/interactions/gestures/handleDrag/handleDrag.js +21 -26
  407. package/dist/interactions/gestures/handleDrag/handleDrag.js.map +1 -1
  408. package/dist/interactions/gestures/pointerDrag/pointerDrag.js +8 -6
  409. package/dist/interactions/gestures/pointerDrag/pointerDrag.js.map +1 -1
  410. package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js +8 -4
  411. package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js.map +1 -1
  412. package/dist/{math-Drrw4ewZ.d.ts → math-J-ACHyEg.d.ts} +1 -2
  413. package/dist/math.d.ts +2 -3
  414. package/dist/move.d.ts +12 -11
  415. package/dist/{originProjection-DEklpDc_.d.ts → originProjection-gHnOup4e.d.ts} +1 -1
  416. package/dist/{registerProgram-BMZRDgrh.d.ts → registerProgram-T9S_PfAX.d.ts} +18 -7
  417. package/dist/renderer/DrawCommand.js.map +1 -1
  418. package/dist/renderer/WeaselRenderer.js +75 -73
  419. package/dist/renderer/WeaselRenderer.js.map +1 -1
  420. package/dist/renderer/cache/GLImageCache.js +15 -5
  421. package/dist/renderer/cache/GLImageCache.js.map +1 -1
  422. package/dist/renderer/cache/GLMeshCache.js +23 -23
  423. package/dist/renderer/cache/GLMeshCache.js.map +1 -1
  424. package/dist/renderer/cache/GLTextureCache.js +18 -1
  425. package/dist/renderer/cache/GLTextureCache.js.map +1 -1
  426. package/dist/renderer/cache/cache.js.map +1 -1
  427. package/dist/renderer/cache/markerCommandCache.js.map +1 -1
  428. package/dist/renderer/cache/strokeMeshCache.js.map +1 -1
  429. package/dist/renderer/cullDrawCommands.js +11 -11
  430. package/dist/renderer/draw/batch.js +133 -0
  431. package/dist/renderer/draw/batch.js.map +1 -0
  432. package/dist/renderer/draw/clip.js +89 -0
  433. package/dist/renderer/draw/clip.js.map +1 -0
  434. package/dist/renderer/draw/customShader.js +230 -0
  435. package/dist/renderer/draw/customShader.js.map +1 -0
  436. package/dist/renderer/draw/drawTriangles.js +8 -0
  437. package/dist/renderer/draw/drawTriangles.js.map +1 -0
  438. package/dist/renderer/draw/effects.js +28 -0
  439. package/dist/renderer/draw/effects.js.map +1 -0
  440. package/dist/renderer/draw/flushBatch.js +35 -0
  441. package/dist/renderer/draw/flushBatch.js.map +1 -0
  442. package/dist/renderer/draw/gradient.js +90 -0
  443. package/dist/renderer/draw/gradient.js.map +1 -0
  444. package/dist/renderer/draw/image.js +38 -0
  445. package/dist/renderer/draw/image.js.map +1 -0
  446. package/dist/renderer/draw/mesh.js +16 -0
  447. package/dist/renderer/draw/mesh.js.map +1 -0
  448. package/dist/renderer/draw/paintBind.js +70 -0
  449. package/dist/renderer/draw/paintBind.js.map +1 -0
  450. package/dist/renderer/draw/pathPaint.js +142 -0
  451. package/dist/renderer/draw/pathPaint.js.map +1 -0
  452. package/dist/renderer/draw/scratchPass.js +83 -0
  453. package/dist/renderer/draw/scratchPass.js.map +1 -0
  454. package/dist/renderer/draw/stencil.js +28 -0
  455. package/dist/renderer/draw/stencil.js.map +1 -0
  456. package/dist/renderer/draw/text.js +167 -0
  457. package/dist/renderer/draw/text.js.map +1 -0
  458. package/dist/renderer/draw/uniforms.js +77 -0
  459. package/dist/renderer/draw/uniforms.js.map +1 -0
  460. package/dist/renderer/draw.js +60 -1116
  461. package/dist/renderer/draw.js.map +1 -1
  462. package/dist/renderer/effects/EffectTargets.js +3 -0
  463. package/dist/renderer/effects/EffectTargets.js.map +1 -1
  464. package/dist/renderer/effects/composite.js +7 -5
  465. package/dist/renderer/effects/composite.js.map +1 -1
  466. package/dist/renderer/index.js +18 -17
  467. package/dist/renderer/math/color.js +63 -83
  468. package/dist/renderer/math/color.js.map +1 -1
  469. package/dist/renderer/math/mat3.js +15 -11
  470. package/dist/renderer/math/mat3.js.map +1 -1
  471. package/dist/renderer/math/viewToMat3.js +1 -1
  472. package/dist/renderer/math/viewToMat3.js.map +1 -1
  473. package/dist/renderer/shaders/ShaderProgram.js +13 -13
  474. package/dist/renderer/shaders/ShaderProgram.js.map +1 -1
  475. package/dist/renderer/shaders/glyphPaint.js +3 -3
  476. package/dist/renderer/shaders/glyphPaint.js.map +1 -1
  477. package/dist/renderer/shaders/gradFill.js +2 -1
  478. package/dist/renderer/shaders/gradFill.js.map +1 -1
  479. package/dist/renderer/shaders/pathFill.js +2 -1
  480. package/dist/renderer/shaders/pathFill.js.map +1 -1
  481. package/dist/renderer/shaders/patternFill.js +2 -1
  482. package/dist/renderer/shaders/patternFill.js.map +1 -1
  483. package/dist/renderer/shaders/registerProgram.js.map +1 -1
  484. package/dist/renderer/strokeLengths.js.map +1 -1
  485. package/dist/renderer/textures/registerTexture.js +25 -5
  486. package/dist/renderer/textures/registerTexture.js.map +1 -1
  487. package/dist/renderer.d.ts +16 -15
  488. package/dist/renderer.js +17 -16
  489. package/dist/resize.d.ts +5 -6
  490. package/dist/resize.js +5 -5
  491. package/dist/style.css +1 -1
  492. package/dist/test-hook/install.js +12 -6
  493. package/dist/test-hook/install.js.map +1 -1
  494. package/dist/{test-seams-CuIxe0xY.d.ts → test-seams-DM2B87-g.d.ts} +4 -4
  495. package/dist/test-seams.d.ts +2 -2
  496. package/dist/tools/builtin/ellipse/useEllipseTool.js +1 -0
  497. package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
  498. package/dist/tools/builtin/hand/useHandTool.js +1 -0
  499. package/dist/tools/builtin/hand/useHandTool.js.map +1 -1
  500. package/dist/tools/builtin/lasso/useLassoTool.js +11 -11
  501. package/dist/tools/builtin/lasso/useLassoTool.js.map +1 -1
  502. package/dist/tools/builtin/line/useLineTool.js +1 -0
  503. package/dist/tools/builtin/line/useLineTool.js.map +1 -1
  504. package/dist/tools/builtin/pen/usePenTool.js +153 -103
  505. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  506. package/dist/tools/builtin/pencil/usePencilTool.js +1 -0
  507. package/dist/tools/builtin/pencil/usePencilTool.js.map +1 -1
  508. package/dist/tools/builtin/polygon/usePolygonTool.js +13 -8
  509. package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
  510. package/dist/tools/builtin/rect/useRectTool.js +1 -0
  511. package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
  512. package/dist/tools/builtin/select/selectionContributions.js +24 -23
  513. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  514. package/dist/tools/builtin/select/useSelectTool.js +51 -48
  515. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  516. package/dist/tools/builtin/shared/pointerFollower.js +17 -0
  517. package/dist/tools/builtin/shared/pointerFollower.js.map +1 -0
  518. package/dist/tools/builtin/slice/useSliceTool.js +49 -54
  519. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  520. package/dist/tools/builtin/star/useStarTool.js +22 -16
  521. package/dist/tools/builtin/star/useStarTool.js.map +1 -1
  522. package/dist/tools/builtin/text/useTextTool.js +1 -0
  523. package/dist/tools/builtin/text/useTextTool.js.map +1 -1
  524. package/dist/tools/useKeybindings.js +14 -30
  525. package/dist/tools/useKeybindings.js.map +1 -1
  526. package/dist/{types-B_9g6hMM.d.ts → types-B4iJRHC3.d.ts} +5 -1
  527. package/dist/{types-A37hYkeR.d.ts → types-k-5Oqh-U.d.ts} +31 -7
  528. package/dist/util/color.js +3 -3
  529. package/dist/util/color.js.map +1 -1
  530. package/dist/util/paint.js.map +1 -1
  531. package/dist/version.js +1 -1
  532. package/package.json +20 -18
  533. package/dist/autoPoseDescriptor-vCdt55xm.d.ts +0 -27
  534. package/dist/builtins-C-VgUlWI.d.ts +0 -4514
  535. package/dist/core/isPlainObject.js.map +0 -1
  536. package/dist/debug/flag.js.map +0 -1
  537. package/dist/interactions/actions/defaults/freshNodeId.js +0 -10
  538. package/dist/interactions/actions/defaults/freshNodeId.js.map +0 -1
  539. package/dist/renderer/shaders/imageFill.js +0 -14
  540. package/dist/renderer/shaders/imageFill.js.map +0 -1
  541. package/dist/tools/prefs.js +0 -62
  542. package/dist/tools/prefs.js.map +0 -1
@@ -1,19 +1,20 @@
1
1
  import { effectivePose as e } from "../../core/scene/effectivePose.js";
2
2
  import { asNodeId as t } from "../../core/scene/types.js";
3
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";
8
- import { useLatest as l } from "@weasel-js/react";
9
- import { clientToCanvas as u } from "@weasel-js/routing";
4
+ import { isTextData as r } from "./isTextData.js";
5
+ import { caretIndexAt as i, pointInTextPose as a } from "./hitTest.js";
6
+ import { useTextEdit as o } from "./useTextEdit.js";
7
+ import { resolveScreenLength as s } from "@weasel-js/paint";
8
+ import { useCallback as c, useMemo as l, useRef as u } from "react";
9
+ import { useLatest as d } from "@weasel-js/react";
10
+ import { clientToCanvas as f } from "@weasel-js/routing";
10
11
  //#region src/features/text/useSceneTextEdit.ts
11
- function d(e) {
12
+ function p(e) {
12
13
  return typeof e == "function" ? e() : e;
13
14
  }
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;
15
+ function m(m, h, g = {}) {
16
+ let _ = d(m), v = d(g), y = d(h), b = u(null), x = () => {
17
+ let e = y.current, t = e ? n(e, b.current) : null;
17
18
  if (!e || !t) return null;
18
19
  let r = t.element.getBoundingClientRect(), i = e.getBoundingClientRect();
19
20
  return {
@@ -25,114 +26,107 @@ function f(f, p, m = {}) {
25
26
  height: r.height
26
27
  }
27
28
  };
28
- }, b = a({
29
- container: p,
30
- isEditorChrome: (e) => g.current.isEditorChrome?.(e) ?? !1,
31
- escape: m.escape,
32
- fontHold: m.fontHold,
29
+ }, S = l(() => ({
30
+ isText: (e) => v.current.isText ? v.current.isText(e) : r(e),
31
+ text: (e) => v.current.getText ? v.current.getText(e) : e.text ?? "",
32
+ style: (e) => v.current.getStyle ? v.current.getStyle(e) : e.style,
33
+ runs: (e) => v.current.getRuns ? v.current.getRuns(e) : e.runs,
34
+ verticalAlign: (e) => v.current.getVerticalAlign ? v.current.getVerticalAlign(e) : e.verticalAlign
35
+ }), [v]), C = o({
36
+ container: h,
37
+ isEditorChrome: (e) => v.current.isEditorChrome?.(e) ?? !1,
38
+ escape: g.escape,
39
+ fontHold: g.fontHold,
33
40
  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 ?? "";
41
+ let n = _.current.get(t(e));
42
+ return n ? S.text(n.data) : "";
38
43
  },
39
44
  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;
45
+ let n = _.current.get(t(e));
46
+ return n ? S.style(n.data) : void 0;
44
47
  },
45
48
  getPaint: (e) => {
46
- let n = h.current.get(t(e));
49
+ let n = _.current.get(t(e));
47
50
  if (!n) return;
48
- let r = g.current.getPaint;
51
+ let r = v.current.getPaint;
49
52
  return r ? r(n.data) : {
50
53
  fill: n.data.fill,
51
54
  stroke: n.data.stroke
52
55
  };
53
56
  },
54
57
  getScreenPose: (n) => {
55
- let r = h.current, i = r.get(t(n));
58
+ let r = _.current, i = r.get(t(n));
56
59
  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;
60
+ let a = e(r, i), o = S.style(i.data), c = x(), l = p(v.current.view) ?? c?.canvas.getView(), u = l ? l.scale.x : 1, d = c?.box.x ?? 0, f = c?.box.y ?? 0;
58
61
  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),
62
+ x: d + (l ? (a.x - l.x) * l.scale.x : a.x),
63
+ y: f + (l ? (a.y - l.y) * l.scale.y : a.y),
61
64
  width: a.width,
62
65
  height: a.height,
63
- fontSize: o(s?.fontSize ?? g.current.defaultFontSize ?? 16, u),
66
+ fontSize: s(o?.fontSize ?? v.current.defaultFontSize ?? 16, u),
64
67
  zoom: u,
65
- verticalAlign: g.current.getVerticalAlign ? g.current.getVerticalAlign(i.data) : i.data.verticalAlign
66
- };
67
- },
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
68
+ verticalAlign: S.verticalAlign(i.data)
75
69
  };
76
- h.current.update(r, { data: o });
77
70
  },
71
+ getClipRect: () => x()?.box ?? null,
78
72
  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;
83
- },
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
90
- };
91
- h.current.update(r, { data: o });
73
+ let n = _.current.get(t(e));
74
+ return n ? S.runs(n.data) : void 0;
92
75
  },
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
76
+ commit: (e, { text: n, runs: r, style: i }) => {
77
+ let a = t(e), o = _.current.get(a);
78
+ if (!o) return;
79
+ let { setText: s, setRuns: c, setStyle: l } = v.current, u = s ? s(o.data, n) : {
80
+ ...o.data,
81
+ text: n
99
82
  };
100
- h.current.update(r, { data: o });
83
+ r && (u = c ? c(u, r) : {
84
+ ...u,
85
+ runs: r
86
+ }), i && (u = l ? l(u, i) : {
87
+ ...u,
88
+ style: i
89
+ }), _.current.update(a, { data: u });
101
90
  }
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 = {
91
+ }), w = c((t) => {
92
+ let r = t.target instanceof HTMLElement ? t.target : null;
93
+ if (!r || r.closest("[contenteditable=\"true\"]")) return;
94
+ let [o, s] = f(r, t.clientX, t.clientY), c = y.current, l = p(v.current.view) ?? (c ? n(c, r)?.getView() : void 0), u = l ? o / l.scale.x + l.x : o, d = l ? s / l.scale.y + l.y : s, m = _.current.renderOrderNodes();
95
+ for (let t = m.length - 1; t >= 0; t--) {
96
+ let n = m[t];
97
+ if (_.current.isLocked(n.id) || !S.isText(n.data)) continue;
98
+ let o = S.text(n.data), s = e(_.current, n), c = {
110
99
  x: s.x,
111
100
  y: s.y,
112
101
  width: s.width,
113
102
  height: s.height,
114
103
  text: o,
115
- runs: x(n.data),
116
- style: y(n.data),
117
- verticalAlign: S(n.data)
104
+ runs: S.runs(n.data),
105
+ style: S.style(n.data),
106
+ verticalAlign: S.verticalAlign(n.data)
118
107
  };
119
- if (i(f, p, c)) {
120
- v.current = a, b.startEdit(String(n.id), { caret: r(f, p, c) });
108
+ if (a(u, d, c)) {
109
+ b.current = r, C.startEdit(String(n.id), { caret: i(u, d, c) });
121
110
  return;
122
111
  }
123
112
  }
124
113
  }, [
125
- b,
126
- _,
127
- g,
128
- h
129
- ]);
114
+ C,
115
+ y,
116
+ v,
117
+ S,
118
+ _
119
+ ]), T = c((e) => {
120
+ let n = _.current.get(t(e));
121
+ return n !== void 0 && S.isText(n.data);
122
+ }, [S, _]);
130
123
  return {
131
- ...b,
132
- onDoubleClick: x
124
+ ...C,
125
+ onDoubleClick: w,
126
+ isTextNode: T
133
127
  };
134
128
  }
135
129
  //#endregion
136
- export { f as useSceneTextEdit };
130
+ export { m as useSceneTextEdit };
137
131
 
138
132
  //# 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","nid","setText","text","runs","setRuns","setStyle","onDoubleClick","useCallback","e","canvasX","canvasY","clientToCanvas","cx","cy","order","i","pointInTextPose","caretIndexAt","isTextNode"],"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, 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 { 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 { isTextData } from './isTextData';\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 /**\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) — 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 /** 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 // 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 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 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` 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 // 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 pose = {\n x: at.x,\n y: at.y,\n width: at.width,\n 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(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, 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"],"mappings":"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"}