@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 +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","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 CommandFill, type CommandStroke } 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?: 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. 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<CommandStroke, 'paint' | 'width'>> & { pad: number } = {\n paint: { fill: 'solid', color: '#f0e0a8' },\n width: 2,\n pad: 1,\n};\nconst DEFAULT_HANDLE_FILL: CommandFill = { fill: 'solid', color: '#d4c4a8' };\nconst DEFAULT_HANDLE_OUTLINE: CommandStroke = {\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?: 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 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: CommandStroke = {\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: CommandFill = 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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"}
@@ -0,0 +1,82 @@
1
+ //#region src/features/text/domOffsets.ts
2
+ var e = /* @__PURE__ */ new Set(["DIV", "P"]);
3
+ function t(t) {
4
+ let n = [], r = (t) => {
5
+ if (t.nodeType === Node.TEXT_NODE) {
6
+ t.data.length > 0 && n.push({ text: t });
7
+ return;
8
+ }
9
+ if (t instanceof Element) {
10
+ if (t.tagName === "BR") {
11
+ n.push({ br: t });
12
+ return;
13
+ }
14
+ e.has(t.tagName) && n.length > 0 && n.push({ block: t });
15
+ for (let e of t.childNodes) r(e);
16
+ }
17
+ };
18
+ for (let e of t.childNodes) r(e);
19
+ return n;
20
+ }
21
+ var n = (e) => Array.prototype.indexOf.call(e.parentNode.childNodes, e);
22
+ function r(e) {
23
+ return "br" in e ? {
24
+ node: e.br.parentNode,
25
+ offset: n(e.br) + 1
26
+ } : {
27
+ node: e.block,
28
+ offset: 0
29
+ };
30
+ }
31
+ function i(e, i) {
32
+ let a = i, o = {
33
+ node: e,
34
+ offset: 0
35
+ }, s = null;
36
+ for (let i of t(e)) {
37
+ if ("text" in i) {
38
+ let e = i.text.data.length;
39
+ if (a <= e) return {
40
+ node: i.text,
41
+ offset: a
42
+ };
43
+ a -= e, o = {
44
+ node: i.text,
45
+ offset: e
46
+ }, s = null;
47
+ continue;
48
+ }
49
+ if (a === 0) return s ?? ("br" in i ? {
50
+ node: i.br.parentNode,
51
+ offset: n(i.br)
52
+ } : r(i));
53
+ --a, o = r(i), s = a === 0 ? o : null;
54
+ }
55
+ return o;
56
+ }
57
+ function a(e, n, i) {
58
+ let a = t(e), o = 0;
59
+ if (n.nodeType === Node.TEXT_NODE) {
60
+ for (let e of a) {
61
+ if (!("text" in e)) {
62
+ o += 1;
63
+ continue;
64
+ }
65
+ if (e.text === n) return o + i;
66
+ o += e.text.data.length;
67
+ }
68
+ return o;
69
+ }
70
+ let s = document.createRange();
71
+ s.setStart(n, Math.max(0, Math.min(i, n.childNodes.length))), s.collapse(!0);
72
+ for (let e of a) if ("text" in e) s.comparePoint(e.text, 0) < 0 && (o += e.text.data.length);
73
+ else {
74
+ let t = r(e);
75
+ s.comparePoint(t.node, t.offset) <= 0 && (o += 1);
76
+ }
77
+ return o;
78
+ }
79
+ //#endregion
80
+ export { e as BLOCK_TAGS, i as charOffsetToDomPosition, a as domPositionToCharOffset, t as overlayPieces };
81
+
82
+ //# sourceMappingURL=domOffsets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domOffsets.js","names":["BLOCK_TAGS","overlayPieces","out","visit","node","child","parent","indexIn","el","afterBreak","piece","charOffsetToDomPosition","remaining","offset","end","pending","len","domPositionToCharOffset","pieces","total","point","past"],"sources":["../../../src/features/text/domOffsets.ts"],"sourcesContent":["/**\n * Character offsets in the edit overlay's DOM, counted the way `domToRuns`\n * reads its text: every text node's characters, plus one newline for each\n * break element a browser or a paste can leave behind.\n */\n\n/** One stretch of the overlay's text, in document order. */\nexport type OverlayPiece =\n | { text: Text }\n /** A newline with no text node of its own: a `<br>`, or the boundary a block opens. */\n | { br: Element }\n | { block: Element };\n\n/** Elements whose boundary reads as a newline. */\nexport const BLOCK_TAGS: ReadonlySet<string> = new Set(['DIV', 'P']);\n\n/**\n * `parent`'s text as pieces. A block (`<div>`, `<p>`) reads as a newline\n * before its contents unless it opens the text, which is how a browser renders\n * the boundary. Both offset walkers below read through here, and `domToRuns`\n * applies the same rule from `BLOCK_TAGS` in its own styled walk.\n */\nexport function overlayPieces(parent: Element): OverlayPiece[] {\n const out: OverlayPiece[] = [];\n const visit = (node: Node): void => {\n if (node.nodeType === Node.TEXT_NODE) {\n if ((node as Text).data.length > 0) out.push({ text: node as Text });\n return;\n }\n if (!(node instanceof Element)) return;\n if (node.tagName === 'BR') { out.push({ br: node }); return; }\n if (BLOCK_TAGS.has(node.tagName) && out.length > 0) out.push({ block: node });\n for (const child of node.childNodes) visit(child);\n };\n for (const child of parent.childNodes) visit(child);\n return out;\n}\n\nconst indexIn = (el: Element): number => Array.prototype.indexOf.call(el.parentNode!.childNodes, el);\n\n/** The DOM position just past a break piece, where the next character goes. */\nfunction afterBreak(piece: { br: Element } | { block: Element }): { node: Node; offset: number } {\n return 'br' in piece\n ? { node: piece.br.parentNode!, offset: indexIn(piece.br) + 1 }\n : { node: piece.block, offset: 0 };\n}\n\n/**\n * The DOM position of plain-text character position `offset`: a text node\n * and an offset into it wherever one holds the position, otherwise an element\n * and a child index (just past a `<br>` that ends the text). Offsets beyond\n * the text clamp to its end. Returns `{ node: parent, offset: 0 }` for an\n * overlay with no text.\n */\nexport function charOffsetToDomPosition(\n parent: HTMLElement,\n offset: number,\n): { node: Node; offset: number } | null {\n let remaining = offset;\n let end: { node: Node; offset: number } = { node: parent, offset: 0 };\n /** Set while the position sits just past a break, with no text met since. */\n let pending: { node: Node; offset: number } | null = null;\n for (const piece of overlayPieces(parent)) {\n if ('text' in piece) {\n const len = piece.text.data.length;\n if (remaining <= len) return { node: piece.text, offset: remaining };\n remaining -= len;\n end = { node: piece.text, offset: len };\n pending = null;\n continue;\n }\n if (remaining === 0) {\n return pending ?? ('br' in piece\n ? { node: piece.br.parentNode!, offset: indexIn(piece.br) }\n : afterBreak(piece));\n }\n remaining -= 1;\n end = afterBreak(piece);\n pending = remaining === 0 ? end : null;\n }\n return end;\n}\n\n/**\n * Inverse of `charOffsetToDomPosition`: the characters that precede the DOM\n * position `(node, offset)`.\n *\n * When `node` is an element the DOM offset indexes *child nodes*, not\n * characters — `(overlay, 0)` is the start of the text and `(overlay,\n * childNodes.length)` its end. That shape is not exotic: `Range.\n * selectNodeContents`, which `useTextEdit` uses for its select-all caret,\n * produces exactly it. So an element position is resolved by counting the\n * pieces that end at or before the boundary point.\n */\nexport function domPositionToCharOffset(\n parent: HTMLElement,\n node: Node,\n offset: number,\n): number {\n const pieces = overlayPieces(parent);\n let total = 0;\n if (node.nodeType === Node.TEXT_NODE) {\n for (const piece of pieces) {\n if (!('text' in piece)) { total += 1; continue; }\n if (piece.text === node) return total + offset;\n total += piece.text.data.length;\n }\n return total;\n }\n const point = document.createRange();\n point.setStart(node, Math.max(0, Math.min(offset, node.childNodes.length)));\n point.collapse(true);\n for (const piece of pieces) {\n if ('text' in piece) {\n // A text node cannot contain the point, so it is wholly before or after.\n if (point.comparePoint(piece.text, 0) < 0) total += piece.text.data.length;\n } else {\n const past = afterBreak(piece);\n if (point.comparePoint(past.node, past.offset) <= 0) total += 1;\n }\n }\n return total;\n}\n"],"mappings":";AAcA,IAAaA,oBAAkC,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC;AAQnE,SAAgBC,EAAc,GAAiC;CAC7D,IAAMC,IAAsB,CAAC,GACvBC,KAAS,MAAqB;EAClC,IAAIC,EAAK,aAAa,KAAK,WAAW;GACpC,AAAKA,EAAc,KAAK,SAAS,KAAGF,EAAI,KAAK,EAAE,MAAME,EAAa,CAAC;GACnE;EACF;EACA,IAAMA,aAAgB,SACtB;OAAIA,EAAK,YAAY,MAAM;IAAE,EAAI,KAAK,EAAE,IAAIA,EAAK,CAAC;IAAG;GAAQ;GAC7D,AAAIJ,EAAW,IAAII,EAAK,OAAO,KAAKF,EAAI,SAAS,KAAGA,EAAI,KAAK,EAAE,OAAOE,EAAK,CAAC;GAC5E,KAAK,IAAMC,KAASD,EAAK,YAAY,EAAMC,CAAK;EAFa;CAG/D;CACA,KAAK,IAAMA,KAASC,EAAO,YAAY,EAAMD,CAAK;CAClD,OAAOH;AACT;AAEA,IAAMK,KAAW,MAAwB,MAAM,UAAU,QAAQ,KAAKC,EAAG,WAAY,YAAYA,CAAE;AAGnG,SAASC,EAAW,GAA6E;CAC/F,OAAO,QAAQC,IACX;EAAE,MAAMA,EAAM,GAAG;EAAa,QAAQH,EAAQG,EAAM,EAAE,IAAI;CAAE,IAC5D;EAAE,MAAMA,EAAM;EAAO,QAAQ;CAAE;AACrC;AASA,SAAgBC,EACd,GACA,GACuC;CACvC,IAAIC,IAAYC,GACZC,IAAsC;EAAE,MAAMR;EAAQ,QAAQ;CAAE,GAEhES,IAAiD;CACrD,KAAK,IAAML,KAAST,EAAcK,CAAM,GAAG;EACzC,IAAI,UAAUI,GAAO;GACnB,IAAMM,IAAMN,EAAM,KAAK,KAAK;GAC5B,IAAIE,KAAaI,GAAK,OAAO;IAAE,MAAMN,EAAM;IAAM,QAAQE;GAAU;GAGnE,AAFA,KAAaI,GACb,IAAM;IAAE,MAAMN,EAAM;IAAM,QAAQM;GAAI,GACtC,IAAU;GACV;EACF;EACA,IAAIJ,MAAc,GAChB,OAAOG,MAAY,QAAQL,IACvB;GAAE,MAAMA,EAAM,GAAG;GAAa,QAAQH,EAAQG,EAAM,EAAE;EAAE,IACxDD,EAAWC,CAAK;EAItB,AAFA,KACA,IAAMD,EAAWC,CAAK,GACtB,IAAUE,MAAc,IAAIE,IAAM;CACpC;CACA,OAAOA;AACT;AAaA,SAAgBG,EACd,GACA,GACA,GACQ;CACR,IAAMC,IAASjB,EAAcK,CAAM,GAC/Ba,IAAQ;CACZ,IAAIf,EAAK,aAAa,KAAK,WAAW;EACpC,KAAK,IAAMM,KAASQ,GAAQ;GAC1B,IAAI,EAAE,UAAUR,IAAQ;IAAE,KAAS;IAAG;GAAU;GAChD,IAAIA,EAAM,SAASN,GAAM,OAAOe,IAAQN;GACxC,KAASH,EAAM,KAAK,KAAK;EAC3B;EACA,OAAOS;CACT;CACA,IAAMC,IAAQ,SAAS,YAAY;CAEnC,AADAA,EAAM,SAAShB,GAAM,KAAK,IAAI,GAAG,KAAK,IAAIS,GAAQT,EAAK,WAAW,MAAM,CAAC,CAAC,GAC1EgB,EAAM,SAAS,EAAI;CACnB,KAAK,IAAMV,KAASQ,GAClB,IAAI,UAAUR,GAER,AAAAU,EAAM,aAAaV,EAAM,MAAM,CAAC,IAAI,MAAG,KAASA,EAAM,KAAK,KAAK;MAC/D;EACL,IAAMW,IAAOZ,EAAWC,CAAK;EAC7B,AAAIU,EAAM,aAAaC,EAAK,MAAMA,EAAK,MAAM,KAAK,MAAG,KAAS;CAChE;CAEF,OAAOF;AACT"}