@weasel-js/core 1.11.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (586) hide show
  1. package/CHANGELOG.md +611 -0
  2. package/README.md +1 -1
  3. package/dist/WeaselProvider.js +1 -1
  4. package/dist/affordances/pathAnchors.js +10 -6
  5. package/dist/affordances/pathAnchors.js.map +1 -1
  6. package/dist/animation/index.js +3 -3
  7. package/dist/animation/rig/bindRig.js +1 -1
  8. package/dist/animation/rig/rigNode.js.map +1 -1
  9. package/dist/barrel/canvas.js +9 -3
  10. package/dist/barrel/interactions.js +5 -4
  11. package/dist/barrel/paint.js +4 -4
  12. package/dist/barrel/paths.js +10 -6
  13. package/dist/barrel/renderer.js +5 -3
  14. package/dist/barrel/routing.js +7 -12
  15. package/dist/barrel/scene.js +9 -5
  16. package/dist/barrel/text.js +2 -2
  17. package/dist/barrel/viewport.js +9 -4
  18. package/dist/canvas/Canvas.js +5 -2
  19. package/dist/canvas/Canvas.js.map +1 -1
  20. package/dist/canvas/CanvasView.js +23 -34
  21. package/dist/canvas/CanvasView.js.map +1 -1
  22. package/dist/canvas/ModalityHud.js +1 -1
  23. package/dist/canvas/NodeShape.js +4 -1
  24. package/dist/canvas/NodeShape.js.map +1 -1
  25. package/dist/canvas/SceneCanvas/ActionsProviderIfRoot.js +1 -1
  26. package/dist/canvas/SceneCanvas/DepRegistryProviderIfRoot.js +1 -1
  27. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +1 -1
  28. package/dist/canvas/SceneCanvas/SceneCanvasInput.js +17 -3
  29. package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
  30. package/dist/canvas/SceneCanvas/SurfaceDeclarations.js +23 -0
  31. package/dist/canvas/SceneCanvas/SurfaceDeclarations.js.map +1 -0
  32. package/dist/canvas/SceneCanvas/builtinToolSets.js +30 -0
  33. package/dist/canvas/SceneCanvas/builtinToolSets.js.map +1 -0
  34. package/dist/canvas/SceneCanvas/canvasPassThrough.js +2 -0
  35. package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
  36. package/dist/canvas/SceneCanvas/coordTrace.js +5 -16
  37. package/dist/canvas/SceneCanvas/coordTrace.js.map +1 -1
  38. package/dist/canvas/SceneCanvas/defaultNodeProperties.js +5 -0
  39. package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
  40. package/dist/canvas/SceneCanvas/features.js +45 -5
  41. package/dist/canvas/SceneCanvas/features.js.map +1 -1
  42. package/dist/canvas/SceneCanvas/props.js +1 -11
  43. package/dist/canvas/SceneCanvas/props.js.map +1 -1
  44. package/dist/canvas/SceneCanvas/scenePointQuery.js +7 -3
  45. package/dist/canvas/SceneCanvas/scenePointQuery.js.map +1 -1
  46. package/dist/canvas/SceneCanvas/toolRegistry.js +8 -4
  47. package/dist/canvas/SceneCanvas/toolRegistry.js.map +1 -1
  48. package/dist/canvas/SceneCanvas/useActionTunings.js +6 -1
  49. package/dist/canvas/SceneCanvas/useActionTunings.js.map +1 -1
  50. package/dist/canvas/SceneCanvas/useActionsPropResolver.js +1 -11
  51. package/dist/canvas/SceneCanvas/useActionsPropResolver.js.map +1 -1
  52. package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js.map +1 -1
  53. package/dist/canvas/SceneCanvas/useBuiltinTools.js +2 -9
  54. package/dist/canvas/SceneCanvas/useBuiltinTools.js.map +1 -1
  55. package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js +94 -0
  56. package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js.map +1 -0
  57. package/dist/canvas/SceneCanvas/useCanvasSelection.js +7 -2
  58. package/dist/canvas/SceneCanvas/useCanvasSelection.js.map +1 -1
  59. package/dist/canvas/SceneCanvas/useCanvasTools.js +15 -10
  60. package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
  61. package/dist/canvas/SceneCanvas/useNodeKinds.js +1 -1
  62. package/dist/canvas/SceneCanvas/useNodeKinds.js.map +1 -1
  63. package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js +9 -3
  64. package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js.map +1 -1
  65. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +23 -4
  66. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
  67. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +2 -3
  68. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
  69. package/dist/canvas/SceneCanvas/useSceneChrome.js +6 -7
  70. package/dist/canvas/SceneCanvas/useSceneChrome.js.map +1 -1
  71. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js +24 -7
  72. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js.map +1 -1
  73. package/dist/canvas/SceneCanvas/useScenePicking.js +2 -3
  74. package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
  75. package/dist/canvas/SceneCanvas/useSceneSelectTool.js +2 -1
  76. package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
  77. package/dist/canvas/SceneCanvas/useSceneStandardActions.js +5 -5
  78. package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
  79. package/dist/canvas/SceneCanvas.js +27 -24
  80. package/dist/canvas/SceneCanvas.js.map +1 -1
  81. package/dist/canvas/SurfaceCanvas.js +5 -22
  82. package/dist/canvas/SurfaceCanvas.js.map +1 -1
  83. package/dist/canvas/ViewMarker.js +35 -0
  84. package/dist/canvas/ViewMarker.js.map +1 -0
  85. package/dist/canvas/canvasRenderer.js +9 -5
  86. package/dist/canvas/canvasRenderer.js.map +1 -1
  87. package/dist/canvas/contextAttributes.js +14 -0
  88. package/dist/canvas/contextAttributes.js.map +1 -0
  89. package/dist/canvas/defaultDrawOne.js +2 -0
  90. package/dist/canvas/defaultDrawOne.js.map +1 -1
  91. package/dist/canvas/deps/booleans.js +2 -1
  92. package/dist/canvas/deps/booleans.js.map +1 -1
  93. package/dist/canvas/deps/editAnchors.js +9 -113
  94. package/dist/canvas/deps/editAnchors.js.map +1 -1
  95. package/dist/canvas/deps/hitTestArea.js +2 -2
  96. package/dist/canvas/deps/hitTestArea.js.map +1 -1
  97. package/dist/canvas/deps/insert.js +10 -4
  98. package/dist/canvas/deps/insert.js.map +1 -1
  99. package/dist/canvas/deps/pathEditCommits.js +189 -0
  100. package/dist/canvas/deps/pathEditCommits.js.map +1 -0
  101. package/dist/canvas/deps/snap.js +12 -9
  102. package/dist/canvas/deps/snap.js.map +1 -1
  103. package/dist/canvas/deps/transformFollowers.js +20 -0
  104. package/dist/canvas/deps/transformFollowers.js.map +1 -0
  105. package/dist/canvas/derivedPath.js +20 -1
  106. package/dist/canvas/derivedPath.js.map +1 -1
  107. package/dist/canvas/drawnBounds.js +38 -4
  108. package/dist/canvas/drawnBounds.js.map +1 -1
  109. package/dist/canvas/inheritedPaints.js +44 -0
  110. package/dist/canvas/inheritedPaints.js.map +1 -0
  111. package/dist/canvas/nodeShapes/derivedPainter.js +23 -16
  112. package/dist/canvas/nodeShapes/derivedPainter.js.map +1 -1
  113. package/dist/canvas/nodeShapes/nodePaint.js +13 -34
  114. package/dist/canvas/nodeShapes/nodePaint.js.map +1 -1
  115. package/dist/canvas/nodeShapes/pathPainter.js +12 -10
  116. package/dist/canvas/nodeShapes/pathPainter.js.map +1 -1
  117. package/dist/canvas/nodeShapes/rectFallbackPainter.js +4 -5
  118. package/dist/canvas/nodeShapes/rectFallbackPainter.js.map +1 -1
  119. package/dist/canvas/nodeShapes/shapePainter.js +12 -11
  120. package/dist/canvas/nodeShapes/shapePainter.js.map +1 -1
  121. package/dist/canvas/nodeShapes/textPainter.js +13 -12
  122. package/dist/canvas/nodeShapes/textPainter.js.map +1 -1
  123. package/dist/canvas/overlayRoleStrokes.js +12 -0
  124. package/dist/canvas/overlayRoleStrokes.js.map +1 -1
  125. package/dist/canvas/pathOverlay.js +27 -7
  126. package/dist/canvas/pathOverlay.js.map +1 -1
  127. package/dist/canvas/pickReach.js +3 -3
  128. package/dist/canvas/pickReach.js.map +1 -1
  129. package/dist/canvas/pickWalk.js +3 -1
  130. package/dist/canvas/pickWalk.js.map +1 -1
  131. package/dist/canvas/renderDebugSnapshot.js +1 -0
  132. package/dist/canvas/renderDebugSnapshot.js.map +1 -1
  133. package/dist/canvas/renderSceneToPixels.js +7 -6
  134. package/dist/canvas/renderSceneToPixels.js.map +1 -1
  135. package/dist/canvas/sceneAdapter.js.map +1 -1
  136. package/dist/canvas/sceneSlotWiring.js +2 -1
  137. package/dist/canvas/sceneSlotWiring.js.map +1 -1
  138. package/dist/canvas/sceneViewRender.js +2 -1
  139. package/dist/canvas/sceneViewRender.js.map +1 -1
  140. package/dist/canvas/surfaceContribution.js +12 -8
  141. package/dist/canvas/surfaceContribution.js.map +1 -1
  142. package/dist/canvas/useCanvasPaint.js +2 -1
  143. package/dist/canvas/useCanvasPaint.js.map +1 -1
  144. package/dist/canvas/useCanvasView.js +4 -2
  145. package/dist/canvas/useCanvasView.js.map +1 -1
  146. package/dist/canvas/useInFlightBounds.js +52 -0
  147. package/dist/canvas/useInFlightBounds.js.map +1 -0
  148. package/dist/canvas/useLayerStack.js +6 -2
  149. package/dist/canvas/useLayerStack.js.map +1 -1
  150. package/dist/canvas/useViewAim.js +121 -0
  151. package/dist/canvas/useViewAim.js.map +1 -0
  152. package/dist/canvas/useViewHelpers.js +7 -9
  153. package/dist/canvas/useViewHelpers.js.map +1 -1
  154. package/dist/canvas/useViewNesting.js +3 -2
  155. package/dist/canvas/useViewNesting.js.map +1 -1
  156. package/dist/canvas/useViewRegistrySurface.js +4 -2
  157. package/dist/canvas/useViewRegistrySurface.js.map +1 -1
  158. package/dist/canvas/viewMarkers.js +63 -0
  159. package/dist/canvas/viewMarkers.js.map +1 -0
  160. package/dist/canvas/viewRegistry.js +27 -1
  161. package/dist/canvas/viewRegistry.js.map +1 -1
  162. package/dist/clipboard.d.ts +3 -2
  163. package/dist/{clone-DZDrfIlU.d.ts → clone-C3e0OTuF.d.ts} +8 -21
  164. package/dist/clone.d.ts +4 -3
  165. package/dist/core/geometry/autoPoseDescriptor.js +1 -1
  166. package/dist/core/ops/setDependsOn.js +37 -0
  167. package/dist/core/ops/setDependsOn.js.map +1 -0
  168. package/dist/core/ops/writtenBy.js +53 -0
  169. package/dist/core/ops/writtenBy.js.map +1 -0
  170. package/dist/core/pages/fitViewToPage.js +12 -1
  171. package/dist/core/pages/fitViewToPage.js.map +1 -1
  172. package/dist/core/pages/pageEdits.js +163 -0
  173. package/dist/core/pages/pageEdits.js.map +1 -0
  174. package/dist/core/pages/pages.js +30 -1
  175. package/dist/core/pages/pages.js.map +1 -1
  176. package/dist/core/paint/meshKindLazy.js +59 -2
  177. package/dist/core/paint/meshKindLazy.js.map +1 -1
  178. package/dist/core/scene/NodeRouting.js +8 -3
  179. package/dist/core/scene/NodeRouting.js.map +1 -1
  180. package/dist/core/scene/arrivalWindow.js.map +1 -1
  181. package/dist/core/scene/carryDescendants.js +51 -0
  182. package/dist/core/scene/carryDescendants.js.map +1 -0
  183. package/dist/core/scene/clipNothing.js +13 -0
  184. package/dist/core/scene/clipNothing.js.map +1 -0
  185. package/dist/core/scene/depMemo.js +11 -3
  186. package/dist/core/scene/depMemo.js.map +1 -1
  187. package/dist/core/scene/dependents.js +7 -1
  188. package/dist/core/scene/dependents.js.map +1 -1
  189. package/dist/core/scene/derivedParts.js +10 -11
  190. package/dist/core/scene/derivedParts.js.map +1 -1
  191. package/dist/core/scene/docValues.js +57 -0
  192. package/dist/core/scene/docValues.js.map +1 -0
  193. package/dist/core/scene/editPass.js +111 -0
  194. package/dist/core/scene/editPass.js.map +1 -0
  195. package/dist/core/scene/effectivePose.js +13 -2
  196. package/dist/core/scene/effectivePose.js.map +1 -1
  197. package/dist/core/scene/fieldEdits.js +4 -1
  198. package/dist/core/scene/fieldEdits.js.map +1 -1
  199. package/dist/core/scene/fontReads.js +37 -0
  200. package/dist/core/scene/fontReads.js.map +1 -0
  201. package/dist/core/scene/historyFacade.js +1 -0
  202. package/dist/core/scene/historyFacade.js.map +1 -1
  203. package/dist/core/scene/inheritedPaint.js +75 -0
  204. package/dist/core/scene/inheritedPaint.js.map +1 -0
  205. package/dist/core/scene/kitRegistry.js +5 -0
  206. package/dist/core/scene/kitRegistry.js.map +1 -1
  207. package/dist/core/scene/layoutPass.js +28 -3
  208. package/dist/core/scene/layoutPass.js.map +1 -1
  209. package/dist/core/scene/nodeMemo.js +15 -7
  210. package/dist/core/scene/nodeMemo.js.map +1 -1
  211. package/dist/core/scene/pathEffects/blend.js.map +1 -1
  212. package/dist/core/scene/pathEffects/derive.js +7 -2
  213. package/dist/core/scene/pathEffects/derive.js.map +1 -1
  214. package/dist/core/scene/pathEffects/effects.js +3 -1
  215. package/dist/core/scene/pathEffects/effects.js.map +1 -1
  216. package/dist/core/scene/pathEffects/textAlong.js +95 -0
  217. package/dist/core/scene/pathEffects/textAlong.js.map +1 -0
  218. package/dist/core/scene/recorder.js +28 -19
  219. package/dist/core/scene/recorder.js.map +1 -1
  220. package/dist/core/scene/scene.js +15 -9
  221. package/dist/core/scene/scene.js.map +1 -1
  222. package/dist/core/scene/sceneChanges.js +13 -0
  223. package/dist/core/scene/sceneChanges.js.map +1 -0
  224. package/dist/core/scene/sceneEdits.js +8 -1
  225. package/dist/core/scene/sceneEdits.js.map +1 -1
  226. package/dist/core/scene/sceneMutators.js +1 -0
  227. package/dist/core/scene/sceneMutators.js.map +1 -1
  228. package/dist/core/scene/sceneRecording.js +20 -3
  229. package/dist/core/scene/sceneRecording.js.map +1 -1
  230. package/dist/core/scene/sceneSelection.js +4 -1
  231. package/dist/core/scene/sceneSelection.js.map +1 -1
  232. package/dist/core/scene/sceneState.js +11 -5
  233. package/dist/core/scene/sceneState.js.map +1 -1
  234. package/dist/core/scene/serialization.js +5 -3
  235. package/dist/core/scene/serialization.js.map +1 -1
  236. package/dist/core/scene/types.js.map +1 -1
  237. package/dist/core/scene/unitScopes.js +19 -1
  238. package/dist/core/scene/unitScopes.js.map +1 -1
  239. package/dist/core/selection/usePublishSceneSelection.js +6 -12
  240. package/dist/core/selection/usePublishSceneSelection.js.map +1 -1
  241. package/dist/core/shapeKinds.js +25 -11
  242. package/dist/core/shapeKinds.js.map +1 -1
  243. package/dist/{cornerHandles-Camw_yeu.d.ts → cornerHandles-p8fDIAKt.d.ts} +3 -2
  244. package/dist/debug/createDebugOverlayLayer.js +16 -111
  245. package/dist/debug/createDebugOverlayLayer.js.map +1 -1
  246. package/dist/debug/createDebugSink.js +2 -1
  247. package/dist/debug/createDebugSink.js.map +1 -1
  248. package/dist/debug/defaultTheme.js +4 -2
  249. package/dist/debug/defaultTheme.js.map +1 -1
  250. package/dist/debug/features.js +17 -0
  251. package/dist/debug/features.js.map +1 -0
  252. package/dist/debug/overlayPanels.js +117 -0
  253. package/dist/debug/overlayPanels.js.map +1 -0
  254. package/dist/debug/parseDebugFlags.js +4 -13
  255. package/dist/debug/parseDebugFlags.js.map +1 -1
  256. package/dist/{depSchema-Cgfu_G9s.d.ts → depSchema-mG19aEdD.d.ts} +174 -904
  257. package/dist/devtools/handlers.js +112 -0
  258. package/dist/devtools/handlers.js.map +1 -0
  259. package/dist/devtools/history.js +71 -0
  260. package/dist/devtools/history.js.map +1 -0
  261. package/dist/devtools/hook.js +74 -0
  262. package/dist/devtools/hook.js.map +1 -0
  263. package/dist/devtools/label.js +25 -0
  264. package/dist/devtools/label.js.map +1 -0
  265. package/dist/devtools/notices.js +58 -0
  266. package/dist/devtools/notices.js.map +1 -0
  267. package/dist/devtools/protocol.js +7 -0
  268. package/dist/devtools/protocol.js.map +1 -0
  269. package/dist/devtools/registry.js +90 -0
  270. package/dist/devtools/registry.js.map +1 -0
  271. package/dist/devtools/root.js +80 -0
  272. package/dist/devtools/root.js.map +1 -0
  273. package/dist/devtools/serialize.js +86 -0
  274. package/dist/devtools/serialize.js.map +1 -0
  275. package/dist/devtools/session.js +111 -0
  276. package/dist/devtools/session.js.map +1 -0
  277. package/dist/devtools/transport.js +67 -0
  278. package/dist/devtools/transport.js.map +1 -0
  279. package/dist/devtools/useDevtoolsRoot.js +81 -0
  280. package/dist/devtools/useDevtoolsRoot.js.map +1 -0
  281. package/dist/devtools-protocol.d.ts +435 -0
  282. package/dist/devtools-protocol.js +7 -0
  283. package/dist/devtools.d.ts +8 -0
  284. package/dist/devtools.js +12 -0
  285. package/dist/devtools.js.map +1 -0
  286. package/dist/features/chrome-caps/useHoverTracking.js +16 -10
  287. package/dist/features/chrome-caps/useHoverTracking.js.map +1 -1
  288. package/dist/features/ingestion/contentHandlers.js +25 -2
  289. package/dist/features/ingestion/contentHandlers.js.map +1 -1
  290. package/dist/features/measure/measureCommands.js +7 -5
  291. package/dist/features/measure/measureCommands.js.map +1 -1
  292. package/dist/features/measure/measureContribution.js +4 -2
  293. package/dist/features/measure/measureContribution.js.map +1 -1
  294. package/dist/features/modes/modeTriggers.js +7 -3
  295. package/dist/features/modes/modeTriggers.js.map +1 -1
  296. package/dist/features/pathEffects/effectSources.js +60 -0
  297. package/dist/features/pathEffects/effectSources.js.map +1 -0
  298. package/dist/features/pathEffects/readSource.js +17 -1
  299. package/dist/features/pathEffects/readSource.js.map +1 -1
  300. package/dist/features/pathEffects/textItems.js +53 -0
  301. package/dist/features/pathEffects/textItems.js.map +1 -0
  302. package/dist/features/pathEffects/useEffectSourcesLayer.js +57 -0
  303. package/dist/features/pathEffects/useEffectSourcesLayer.js.map +1 -0
  304. package/dist/features/paths/index.js +2 -2
  305. package/dist/features/paths/pathEditExtension.js.map +1 -1
  306. package/dist/features/paths/pathEditState.js +5 -2
  307. package/dist/features/paths/pathEditState.js.map +1 -1
  308. package/dist/features/paths/pathSnap/pathSnapSource.js +5 -5
  309. package/dist/features/paths/pathSnap/pathSnapSource.js.map +1 -1
  310. package/dist/features/paths/pathSnap/sceneIndex.js +10 -3
  311. package/dist/features/paths/pathSnap/sceneIndex.js.map +1 -1
  312. package/dist/features/selection/selectionPose.js +4 -1
  313. package/dist/features/selection/selectionPose.js.map +1 -1
  314. package/dist/features/snap/gather.js +9 -1
  315. package/dist/features/snap/gather.js.map +1 -1
  316. package/dist/features/snap/lazySession.js +17 -0
  317. package/dist/features/snap/lazySession.js.map +1 -0
  318. package/dist/features/snap/marks.js.map +1 -1
  319. package/dist/features/snap/probes2d.js +27 -19
  320. package/dist/features/snap/probes2d.js.map +1 -1
  321. package/dist/features/snap/readoutLayer.js.map +1 -1
  322. package/dist/features/snap/roles.js +2 -1
  323. package/dist/features/snap/roles.js.map +1 -1
  324. package/dist/features/snap/rotationSource.js +25 -8
  325. package/dist/features/snap/rotationSource.js.map +1 -1
  326. package/dist/features/snap/sceneSession2d.js +6 -4
  327. package/dist/features/snap/sceneSession2d.js.map +1 -1
  328. package/dist/features/snap/session2d.js +37 -23
  329. package/dist/features/snap/session2d.js.map +1 -1
  330. package/dist/features/snap/spanSnap.js +5 -2
  331. package/dist/features/snap/spanSnap.js.map +1 -1
  332. package/dist/features/text/sceneTextDrafts.js +65 -0
  333. package/dist/features/text/sceneTextDrafts.js.map +1 -0
  334. package/dist/features/text/textHitAt.js +31 -2
  335. package/dist/features/text/textHitAt.js.map +1 -1
  336. package/dist/features/text/useSceneTextEdit.js +22 -18
  337. package/dist/features/text/useSceneTextEdit.js.map +1 -1
  338. package/dist/features/viewports/aim.js +105 -0
  339. package/dist/features/viewports/aim.js.map +1 -0
  340. package/dist/features/viewports/viewMarker.js +82 -0
  341. package/dist/features/viewports/viewMarker.js.map +1 -0
  342. package/dist/features/viewports/viewMarkerDrag.js +55 -0
  343. package/dist/features/viewports/viewMarkerDrag.js.map +1 -0
  344. package/dist/icons.table.js +1 -1
  345. package/dist/icons.table.js.map +1 -1
  346. package/dist/icons.table.json +0 -10
  347. package/dist/index.d.ts +1198 -894
  348. package/dist/index.js +55 -38
  349. package/dist/interactions/actions/align/action.js +6 -4
  350. package/dist/interactions/actions/align/action.js.map +1 -1
  351. package/dist/interactions/actions/align/align.js.map +1 -1
  352. package/dist/interactions/actions/booleans/action.js +7 -1
  353. package/dist/interactions/actions/booleans/action.js.map +1 -1
  354. package/dist/interactions/actions/booleans/booleans.js +2 -1
  355. package/dist/interactions/actions/booleans/booleans.js.map +1 -1
  356. package/dist/interactions/actions/booleans/operands.js +6 -5
  357. package/dist/interactions/actions/booleans/operands.js.map +1 -1
  358. package/dist/interactions/actions/clipboard/action.js +27 -17
  359. package/dist/interactions/actions/clipboard/action.js.map +1 -1
  360. package/dist/interactions/actions/clone/action.js +1 -1
  361. package/dist/interactions/actions/clone/behaviors.js +4 -4
  362. package/dist/interactions/actions/clone/behaviors.js.map +1 -1
  363. package/dist/interactions/actions/defaults/anchorEditing.js +44 -23
  364. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  365. package/dist/interactions/actions/defaults/anchorJoin.js +12 -6
  366. package/dist/interactions/actions/defaults/anchorJoin.js.map +1 -1
  367. package/dist/interactions/actions/defaults/bendSegment.js +8 -5
  368. package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
  369. package/dist/interactions/actions/defaults/cancelGesture.js +11 -8
  370. package/dist/interactions/actions/defaults/cancelGesture.js.map +1 -1
  371. package/dist/interactions/actions/defaults/contextMenu.js +17 -8
  372. package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
  373. package/dist/interactions/actions/defaults/createPaintAction.js +2 -2
  374. package/dist/interactions/actions/defaults/createPaintAction.js.map +1 -1
  375. package/dist/interactions/actions/defaults/delete.js +64 -41
  376. package/dist/interactions/actions/defaults/delete.js.map +1 -1
  377. package/dist/interactions/actions/defaults/duplicate.js +12 -9
  378. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  379. package/dist/interactions/actions/defaults/enterPathEdit.js +19 -9
  380. package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
  381. package/dist/interactions/actions/defaults/escape.js +11 -8
  382. package/dist/interactions/actions/defaults/escape.js.map +1 -1
  383. package/dist/interactions/actions/defaults/exitPathEdit.js +7 -4
  384. package/dist/interactions/actions/defaults/exitPathEdit.js.map +1 -1
  385. package/dist/interactions/actions/defaults/group.js +21 -15
  386. package/dist/interactions/actions/defaults/group.js.map +1 -1
  387. package/dist/interactions/actions/defaults/ingest.js +17 -9
  388. package/dist/interactions/actions/defaults/ingest.js.map +1 -1
  389. package/dist/interactions/actions/defaults/insertPathAnchor.js +7 -4
  390. package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
  391. package/dist/interactions/actions/defaults/nudge.js +21 -40
  392. package/dist/interactions/actions/defaults/nudge.js.map +1 -1
  393. package/dist/interactions/actions/defaults/pathEditTools.js +11 -8
  394. package/dist/interactions/actions/defaults/pathEditTools.js.map +1 -1
  395. package/dist/interactions/actions/defaults/pinchZoom.js +7 -4
  396. package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
  397. package/dist/interactions/actions/defaults/reorder.js +24 -6
  398. package/dist/interactions/actions/defaults/reorder.js.map +1 -1
  399. package/dist/interactions/actions/defaults/selectAll.js +8 -5
  400. package/dist/interactions/actions/defaults/selectAll.js.map +1 -1
  401. package/dist/interactions/actions/defaults/setFill.js +7 -3
  402. package/dist/interactions/actions/defaults/setFill.js.map +1 -1
  403. package/dist/interactions/actions/defaults/setFillOpacity.js +1 -1
  404. package/dist/interactions/actions/defaults/setStroke.js +12 -11
  405. package/dist/interactions/actions/defaults/setStroke.js.map +1 -1
  406. package/dist/interactions/actions/defaults/setStrokeOpacity.js +1 -1
  407. package/dist/interactions/actions/defaults/toolActivate.js +7 -1
  408. package/dist/interactions/actions/defaults/toolActivate.js.map +1 -1
  409. package/dist/interactions/actions/defaults/toolResetToDefault.js +7 -4
  410. package/dist/interactions/actions/defaults/toolResetToDefault.js.map +1 -1
  411. package/dist/interactions/actions/defaults/undoRedo.js +19 -13
  412. package/dist/interactions/actions/defaults/undoRedo.js.map +1 -1
  413. package/dist/interactions/actions/defaults/viewportWheelPan.js +16 -7
  414. package/dist/interactions/actions/defaults/viewportWheelPan.js.map +1 -1
  415. package/dist/interactions/actions/defaults/viewportZoom.js +24 -6
  416. package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
  417. package/dist/interactions/actions/distribute/action.js +6 -4
  418. package/dist/interactions/actions/distribute/action.js.map +1 -1
  419. package/dist/interactions/actions/drawnBoxes.js +2 -1
  420. package/dist/interactions/actions/drawnBoxes.js.map +1 -1
  421. package/dist/interactions/actions/edit-anchors/action.js +10 -10
  422. package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
  423. package/dist/interactions/actions/edit-anchors/preview.js +41 -8
  424. package/dist/interactions/actions/edit-anchors/preview.js.map +1 -1
  425. package/dist/interactions/actions/flip/action.js +14 -6
  426. package/dist/interactions/actions/flip/action.js.map +1 -1
  427. package/dist/interactions/actions/gestureLifecycle.js +5 -2
  428. package/dist/interactions/actions/gestureLifecycle.js.map +1 -1
  429. package/dist/interactions/actions/insert/action.js +1 -2
  430. package/dist/interactions/actions/insert/action.js.map +1 -1
  431. package/dist/interactions/actions/insert/commit.js +1 -1
  432. package/dist/interactions/actions/insert/parent.js +11 -0
  433. package/dist/interactions/actions/insert/parent.js.map +1 -0
  434. package/dist/interactions/actions/insert/placeAction.js +7 -2
  435. package/dist/interactions/actions/insert/placeAction.js.map +1 -1
  436. package/dist/interactions/actions/insert/repositionAction.js +2 -1
  437. package/dist/interactions/actions/insert/repositionAction.js.map +1 -1
  438. package/dist/interactions/actions/insert/session.js +5 -1
  439. package/dist/interactions/actions/insert/session.js.map +1 -1
  440. package/dist/interactions/actions/move/action.js +15 -8
  441. package/dist/interactions/actions/move/action.js.map +1 -1
  442. package/dist/interactions/actions/move/behaviors/layoutDrop.js +0 -1
  443. package/dist/interactions/actions/move/behaviors/layoutDrop.js.map +1 -1
  444. package/dist/interactions/actions/move/behaviors/snapToContainer.js +1 -1
  445. package/dist/interactions/actions/move/capture.js +1 -1
  446. package/dist/interactions/actions/move/commit/index.js +0 -2
  447. package/dist/interactions/actions/move/commit/index.js.map +1 -1
  448. package/dist/interactions/actions/move/commit/layoutDrop.js +2 -2
  449. package/dist/interactions/actions/move/commit/layoutRelease.js +2 -2
  450. package/dist/interactions/actions/move/commit/reparent.js +11 -5
  451. package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
  452. package/dist/interactions/actions/move/frame.js +4 -10
  453. package/dist/interactions/actions/move/frame.js.map +1 -1
  454. package/dist/interactions/actions/move/landedDescendants.js +20 -17
  455. package/dist/interactions/actions/move/landedDescendants.js.map +1 -1
  456. package/dist/interactions/actions/move/layout/container.js +2 -1
  457. package/dist/interactions/actions/move/layout/container.js.map +1 -1
  458. package/dist/interactions/actions/move/layout/dragged.js +1 -1
  459. package/dist/interactions/actions/move/layout/dropPass.js +18 -1
  460. package/dist/interactions/actions/move/layout/dropPass.js.map +1 -1
  461. package/dist/interactions/actions/move/layout/exits.js +5 -5
  462. package/dist/interactions/actions/move/layout/exits.js.map +1 -1
  463. package/dist/interactions/actions/move/session.js +14 -3
  464. package/dist/interactions/actions/move/session.js.map +1 -1
  465. package/dist/interactions/actions/move/translate.js +8 -37
  466. package/dist/interactions/actions/move/translate.js.map +1 -1
  467. package/dist/interactions/actions/moveNodes.js +87 -0
  468. package/dist/interactions/actions/moveNodes.js.map +1 -0
  469. package/dist/interactions/actions/outlines/createOutlinesAction.js +8 -5
  470. package/dist/interactions/actions/outlines/createOutlinesAction.js.map +1 -1
  471. package/dist/interactions/actions/outlines/outlineStroke.js +5 -3
  472. package/dist/interactions/actions/outlines/outlineStroke.js.map +1 -1
  473. package/dist/interactions/actions/pathCommands/cutJoin.js +8 -5
  474. package/dist/interactions/actions/pathCommands/cutJoin.js.map +1 -1
  475. package/dist/interactions/actions/planeInput.js.map +1 -1
  476. package/dist/interactions/actions/resize/action.js +83 -72
  477. package/dist/interactions/actions/resize/action.js.map +1 -1
  478. package/dist/interactions/actions/resize/commit.js +2 -1
  479. package/dist/interactions/actions/resize/commit.js.map +1 -1
  480. package/dist/interactions/actions/resize/cornerHandles.js +2 -1
  481. package/dist/interactions/actions/resize/cornerHandles.js.map +1 -1
  482. package/dist/interactions/actions/resize/session.js +2 -0
  483. package/dist/interactions/actions/resize/session.js.map +1 -1
  484. package/dist/interactions/actions/resolvePreviews.js +3 -3
  485. package/dist/interactions/actions/resolvePreviews.js.map +1 -1
  486. package/dist/interactions/actions/rotate/action.js +7 -4
  487. package/dist/interactions/actions/rotate/action.js.map +1 -1
  488. package/dist/interactions/actions/rotate/commit.js +2 -1
  489. package/dist/interactions/actions/rotate/commit.js.map +1 -1
  490. package/dist/interactions/actions/rotate/session.js +2 -0
  491. package/dist/interactions/actions/rotate/session.js.map +1 -1
  492. package/dist/interactions/actions/selectionSubtree.js +25 -9
  493. package/dist/interactions/actions/selectionSubtree.js.map +1 -1
  494. package/dist/interactions/actions/testUtils.js.map +1 -1
  495. package/dist/interactions/actions/transform-again/action.js +13 -11
  496. package/dist/interactions/actions/transform-again/action.js.map +1 -1
  497. package/dist/interactions/actions/transformFinish.js +106 -0
  498. package/dist/interactions/actions/transformFinish.js.map +1 -0
  499. package/dist/json.d.ts +4 -0
  500. package/dist/json.js +3 -0
  501. package/dist/kitSettingsSchema.js +8 -5
  502. package/dist/kitSettingsSchema.js.map +1 -1
  503. package/dist/{math-CrJULaZI.d.ts → math-B56zxVs5.d.ts} +10 -1
  504. package/dist/math.d.ts +1 -1
  505. package/dist/math.js +2 -1
  506. package/dist/move.d.ts +5 -4
  507. package/dist/{options-p9GZMXbY.d.ts → options-DBxEryYq.d.ts} +1 -1
  508. package/dist/resize.d.ts +4 -3
  509. package/dist/routing.d.ts +1 -1
  510. package/dist/routing.js +2 -2
  511. package/dist/test-hook/createTestHook.js +1 -1
  512. package/dist/test-hook/createTestHook.js.map +1 -1
  513. package/dist/test-hook/useTestHook.js +2 -1
  514. package/dist/test-hook/useTestHook.js.map +1 -1
  515. package/dist/test-seams.d.ts +9 -5
  516. package/dist/tools/builtin/ellipse/useEllipseTool.js +1 -0
  517. package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
  518. package/dist/tools/builtin/eyedropper/useEyedropperTool.js +2 -1
  519. package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
  520. package/dist/tools/builtin/hand/dragPanContribution.js +4 -1
  521. package/dist/tools/builtin/hand/dragPanContribution.js.map +1 -1
  522. package/dist/tools/builtin/hand/useHandTool.js +7 -4
  523. package/dist/tools/builtin/hand/useHandTool.js.map +1 -1
  524. package/dist/tools/builtin/image/useImageTool.js +1 -0
  525. package/dist/tools/builtin/image/useImageTool.js.map +1 -1
  526. package/dist/tools/builtin/lasso/useLassoTool.js +1 -0
  527. package/dist/tools/builtin/lasso/useLassoTool.js.map +1 -1
  528. package/dist/tools/builtin/line/useLineTool.js +1 -0
  529. package/dist/tools/builtin/line/useLineTool.js.map +1 -1
  530. package/dist/tools/builtin/measure/useMeasureTool.js +12 -5
  531. package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
  532. package/dist/tools/builtin/pen/penHandle.js +3 -5
  533. package/dist/tools/builtin/pen/penHandle.js.map +1 -1
  534. package/dist/tools/builtin/pen/usePenTool.js +14 -6
  535. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  536. package/dist/tools/builtin/pencil/usePencilTool.js +1 -0
  537. package/dist/tools/builtin/pencil/usePencilTool.js.map +1 -1
  538. package/dist/tools/builtin/polygon/usePolygonTool.js +13 -4
  539. package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
  540. package/dist/tools/builtin/rect/useRectTool.js +1 -0
  541. package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
  542. package/dist/tools/builtin/select/adapterPointQuery.js +3 -2
  543. package/dist/tools/builtin/select/adapterPointQuery.js.map +1 -1
  544. package/dist/tools/builtin/select/pressDecision.js +32 -0
  545. package/dist/tools/builtin/select/pressDecision.js.map +1 -0
  546. package/dist/tools/builtin/select/selectionContributions.js +22 -13
  547. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  548. package/dist/tools/builtin/select/useSelectTool.js +13 -10
  549. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  550. package/dist/tools/builtin/slice/useSliceTool.js +22 -8
  551. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  552. package/dist/tools/builtin/star/useStarTool.js +13 -4
  553. package/dist/tools/builtin/star/useStarTool.js.map +1 -1
  554. package/dist/tools/builtin/sticky/stickyNode.js +4 -1
  555. package/dist/tools/builtin/sticky/stickyNode.js.map +1 -1
  556. package/dist/tools/builtin/sticky/useStickyTool.js +10 -5
  557. package/dist/tools/builtin/sticky/useStickyTool.js.map +1 -1
  558. package/dist/tools/builtin/text/useTextTool.js +3 -1
  559. package/dist/tools/builtin/text/useTextTool.js.map +1 -1
  560. package/dist/tools/index.js +26 -0
  561. package/dist/{types-CHVXGfYm.d.ts → types-7puAuVD2.d.ts} +3 -262
  562. package/dist/types-BN9hbdMI.d.ts +184 -0
  563. package/dist/types-CniVctmk.d.ts +949 -0
  564. package/dist/types-oFeQ5VjV.d.ts +264 -0
  565. package/dist/util/paint.js +1 -3
  566. package/dist/util/paint.js.map +1 -1
  567. package/dist/version.js +1 -1
  568. package/package.json +39 -25
  569. package/dist/canvas/SceneCanvas/useBuiltinRigTools.js +0 -65
  570. package/dist/canvas/SceneCanvas/useBuiltinRigTools.js.map +0 -1
  571. package/dist/tools/builtin/bone/boneActions.js +0 -156
  572. package/dist/tools/builtin/bone/boneActions.js.map +0 -1
  573. package/dist/tools/builtin/bone/boneOverlay.js +0 -71
  574. package/dist/tools/builtin/bone/boneOverlay.js.map +0 -1
  575. package/dist/tools/builtin/bone/placedRig.js +0 -28
  576. package/dist/tools/builtin/bone/placedRig.js.map +0 -1
  577. package/dist/tools/builtin/bone/rigEditState.js +0 -30
  578. package/dist/tools/builtin/bone/rigEditState.js.map +0 -1
  579. package/dist/tools/builtin/bone/useBoneTool.js +0 -125
  580. package/dist/tools/builtin/bone/useBoneTool.js.map +0 -1
  581. package/dist/tools/builtin/weight/useWeightTool.js +0 -101
  582. package/dist/tools/builtin/weight/useWeightTool.js.map +0 -1
  583. package/dist/tools/builtin/weight/weightActions.js +0 -140
  584. package/dist/tools/builtin/weight/weightActions.js.map +0 -1
  585. package/dist/tools/builtin/weight/weightOverlay.js +0 -78
  586. package/dist/tools/builtin/weight/weightOverlay.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"arrivalWindow.js","names":[],"sources":["../../../src/core/scene/arrivalWindow.ts"],"sourcesContent":["/**\n * The scene's arrival window: what a live edit did to containers, collected\n * while it runs and handed to a layout handler before it closes.\n *\n * The window is open while a live edit is collecting the nodes that joined a\n * container, the ones that left one, and every container whose children or\n * size it changed; whoever opened the window settles it before the edit\n * closes. Undo, redo and journal replays never open it: they restore an\n * arrangement that was already decided.\n */\nimport { createEmitter } from '@weasel-js/registry';\nimport type { Op } from 'core/ops/types';\nimport { createArrangeOp, type ArrangedPose } from 'core/ops/arrange';\nimport { SceneArrivalRefused } from './arrivals';\nimport type { LayoutMove, Node, NodeId, SceneArrivalHandler } from './types';\n\n/** What the window needs from the scene it serves. */\nexport interface ArrivalWindowEnv<TData, TLayer extends string, TPose> {\n nodes: Map<NodeId, Node<TData, TLayer, TPose>>;\n /** The pass over the scene's declared layouts, which settles arrivals once\n * a container has declared one. An installed handler takes its place. */\n layoutPass: SceneArrivalHandler<TPose>;\n /** Whether a bare scene call would record an edit of its own right now:\n * no batch is open and no history engine is driving. */\n recordsBareEdits(): boolean;\n /** Write one arranged pose. Bound into the arrange op, since not every\n * adapter an edit is applied through can write poses. */\n writePose(id: string, pose: unknown): void;\n}\n\nexport interface ArrivalWindow<TPose> {\n /** A container was given a layout: from here on the scene has arrivals to\n * settle even with no handler installed. */\n layoutDeclared(): void;\n /** Install the handler that settles arrivals. Returns its remover. */\n setHandler(handler: SceneArrivalHandler<TPose>): () => void;\n /** Hear the poses each live edit's settle wrote, after the edit lands. */\n onReflow(listener: (moves: readonly LayoutMove<TPose>[]) => void): () => void;\n noteArrival(id: NodeId, parent: NodeId | null, from: NodeId | null): void;\n noteDeparture(id: NodeId, from: NodeId | null, to: NodeId | null): void;\n /** A container's child set or order changed, or it changed size. */\n noteChange(id: NodeId | null): void;\n /** Whether a bare scene call has to run as a batch of its own, so the\n * layout pass it triggers lands in its undo step. */\n bareLayoutEdit(): boolean;\n /** Open the window when a handler wants one — or `always`, for an edit that\n * may give the scene its first layout partway through — and no enclosing\n * edit holds it already; true when this caller now owns it. */\n open(always?: boolean): boolean;\n /** Close the window and ask the handler what the arrivals get. Throws\n * `SceneArrivalRefused` when it refuses, which reverts the edit. */\n settle(): ArrangedPose[];\n /** Report what the settled edit wrote, now that it has landed. */\n emitReflow(): void;\n /** Close the window with nothing settled or reported: its owner's edit is\n * over, however it ended. */\n abandon(): void;\n /** Run an op-driven edit that may carry arrivals: a refusal reverts it and\n * is swallowed, the way a drop onto a full container is — nothing lands.\n * Returns whether the edit landed. */\n runEdit(ops: Op[], run: (ops: Op[]) => void): boolean;\n}\n\n/** Of the ids noted per container, those the landed edit bears out: still\n * under it when `joined`, gone from it otherwise. A container that is itself\n * gone is left out. */\nfunction heldMoves(\n nodes: ReadonlyMap<NodeId, { parent: NodeId | null }>,\n noted: ReadonlyMap<NodeId, NodeId[]>,\n joined: boolean,\n): Map<NodeId, NodeId[]> {\n const out = new Map<NodeId, NodeId[]>();\n for (const [parent, ids] of noted) {\n const held = ids.filter((id) => (nodes.get(id)?.parent === parent) === joined);\n if (held.length > 0 && nodes.has(parent)) out.set(parent, held);\n }\n return out;\n}\n\nexport function createArrivalWindow<TData, TLayer extends string, TPose>(\n env: ArrivalWindowEnv<TData, TLayer, TPose>,\n): ArrivalWindow<TPose> {\n const { nodes } = env;\n let installed: SceneArrivalHandler<TPose> | null = null;\n let hasLayouts = false;\n let arrivals: Map<NodeId, NodeId[]> | null = null;\n let departures = new Map<NodeId, NodeId[]>();\n let changed = new Set<NodeId>();\n /** What the last settle wrote, reported to `onReflow` once its edit lands. */\n let reflowDue: LayoutMove<TPose>[] | null = null;\n const reflowListeners = createEmitter<[moves: readonly LayoutMove<TPose>[]]>();\n\n const activeHandler = (): SceneArrivalHandler<TPose> | null => installed ?? (hasLayouts ? env.layoutPass : null);\n\n function open(always = false): boolean {\n if (arrivals !== null || (!always && activeHandler() === null)) return false;\n arrivals = new Map();\n departures = new Map();\n changed = new Set();\n reflowDue = null;\n return true;\n }\n\n function emitReflow(): void {\n const moves = reflowDue;\n reflowDue = null;\n if (moves === null || moves.length === 0) return;\n reflowListeners.emit(moves);\n }\n\n function settle(): ArrangedPose[] {\n const pending = arrivals;\n arrivals = null;\n const handler = activeHandler();\n if (pending === null || handler === null) return [];\n // Only what is still there once the edit's other mutations have landed.\n const landed = heldMoves(nodes, pending, true);\n // Only what is gone from the container once the edit has landed: a child\n // that left and came back did not depart.\n const left = heldMoves(nodes, departures, false);\n departures = new Map();\n const touched = new Set([...changed].filter((id) => nodes.get(id)?.kind === 'container'));\n if (landed.size === 0 && touched.size === 0) return [];\n const poses = handler(landed, touched, left);\n if (poses === null) throw new SceneArrivalRefused(landed);\n const out: ArrangedPose[] = [];\n for (const [id, to] of poses) {\n const node = nodes.get(id);\n if (node) out.push({ id, from: node.pose, to });\n }\n reflowDue = out as LayoutMove<TPose>[];\n return out;\n }\n\n function abandon(): void {\n arrivals = null;\n reflowDue = null;\n }\n\n /** `ops` plus the op that settles their arrivals, when this call owns the\n * window; `ops` unchanged otherwise. Opened even on a scene with no layout\n * yet: an edit's op list is fixed before it runs, and any op in it may give\n * the scene its first. The arrange op that settles nothing elides itself. */\n function withArrivalOps(ops: Op[]): { ops: Op[]; owned: boolean } {\n if (!open(true)) return { ops, owned: false };\n return { ops: [...ops, createArrangeOp({}, settle, env.writePose)], owned: true };\n }\n\n return {\n layoutDeclared: () => { hasLayouts = true; },\n setHandler(handler) {\n installed = handler;\n return () => {\n if (installed === handler) installed = null;\n };\n },\n onReflow: reflowListeners.subscribe,\n noteArrival(id, parent, from) {\n if (arrivals === null || parent === null || parent === from) return;\n changed.add(parent);\n const list = arrivals.get(parent);\n if (list === undefined) arrivals.set(parent, [id]);\n else if (!list.includes(id)) list.push(id);\n },\n noteDeparture(id, from, to) {\n if (arrivals === null || from === null || from === to) return;\n changed.add(from);\n // One that joined earlier in this edit was never there to leave.\n if (arrivals.get(from)?.includes(id)) return;\n const list = departures.get(from);\n if (list === undefined) departures.set(from, [id]);\n else if (!list.includes(id)) list.push(id);\n },\n noteChange(id) {\n if (arrivals !== null && id !== null) changed.add(id);\n },\n bareLayoutEdit: () => activeHandler() !== null && arrivals === null && env.recordsBareEdits(),\n open,\n settle,\n emitReflow,\n abandon,\n runEdit(ops, run) {\n const { ops: all, owned } = withArrivalOps(ops);\n // An edit inside another's window leaves a refusal to the one that owns\n // it, which reverts the whole edit and answers for it.\n if (!owned) return run(all), true;\n try {\n run(all);\n emitReflow();\n return true;\n } catch (err) {\n if (!(err instanceof SceneArrivalRefused)) throw err;\n return false;\n } finally {\n abandon();\n }\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"arrivalWindow.js","names":[],"sources":["../../../src/core/scene/arrivalWindow.ts"],"sourcesContent":["/**\n * The scene's arrival window: what a live edit did to containers, collected\n * while it runs and handed to a layout handler before it closes.\n *\n * The window is open while a live edit is collecting the nodes that joined a\n * container, the ones that left one, and every container whose children or\n * size it changed; whoever opened the window settles it before the edit\n * closes. Undo, redo and journal replays never open it: they restore an\n * arrangement that was already decided.\n */\nimport { createEmitter } from '@weasel-js/registry';\nimport type { Op } from 'core/ops/types';\nimport { createArrangeOp, type ArrangedPose } from 'core/ops/arrange';\nimport { SceneArrivalRefused } from './arrivals';\nimport type { LayoutMove, Node, NodeId, SceneArrivalHandler } from './types';\n\n/** What the window needs from the scene it serves. */\nexport interface ArrivalWindowEnv<TData, TLayer extends string, TPose> {\n nodes: Map<NodeId, Node<TData, TLayer, TPose>>;\n /** The pass over the scene's declared layouts, which settles arrivals once\n * a container has declared one. An installed handler takes its place. */\n layoutPass: SceneArrivalHandler<TPose>;\n /** Whether a bare scene call would record an edit of its own right now:\n * no batch is open and no history engine is driving. */\n recordsBareEdits(): boolean;\n /** Write one arranged pose. Bound into the arrange op, since not every\n * adapter an edit is applied through can write poses. */\n writePose(id: string, pose: unknown): void;\n}\n\nexport interface ArrivalWindow<TPose> {\n /** A container was given a layout: from here on the scene has arrivals to\n * settle even with no handler installed. */\n layoutDeclared(): void;\n /** Install the handler that settles arrivals. Returns its remover. */\n setHandler(handler: SceneArrivalHandler<TPose>): () => void;\n /** Hear the poses each live edit's settle wrote, after the edit lands. */\n onReflow(listener: (moves: readonly LayoutMove<TPose>[]) => void): () => void;\n noteArrival(id: NodeId, parent: NodeId | null, from: NodeId | null): void;\n noteDeparture(id: NodeId, from: NodeId | null, to: NodeId | null): void;\n /** A container's child set or order changed, it changed size, or a child was posed. */\n noteChange(id: NodeId | null): void;\n /** Whether a bare scene call has to run as a batch of its own, so the\n * layout pass it triggers lands in its undo step. */\n bareLayoutEdit(): boolean;\n /** Open the window when a handler wants one — or `always`, for an edit that\n * may give the scene its first layout partway through — and no enclosing\n * edit holds it already; true when this caller now owns it. */\n open(always?: boolean): boolean;\n /** Close the window and ask the handler what the arrivals get. Throws\n * `SceneArrivalRefused` when it refuses, which reverts the edit. */\n settle(): ArrangedPose[];\n /** Report what the settled edit wrote, now that it has landed. */\n emitReflow(): void;\n /** Close the window with nothing settled or reported: its owner's edit is\n * over, however it ended. */\n abandon(): void;\n /** Run an op-driven edit that may carry arrivals: a refusal reverts it and\n * is swallowed, the way a drop onto a full container is — nothing lands.\n * Returns whether the edit landed. */\n runEdit(ops: Op[], run: (ops: Op[]) => void): boolean;\n}\n\n/** Of the ids noted per container, those the landed edit bears out: still\n * under it when `joined`, gone from it otherwise. A container that is itself\n * gone is left out. */\nfunction heldMoves(\n nodes: ReadonlyMap<NodeId, { parent: NodeId | null }>,\n noted: ReadonlyMap<NodeId, NodeId[]>,\n joined: boolean,\n): Map<NodeId, NodeId[]> {\n const out = new Map<NodeId, NodeId[]>();\n for (const [parent, ids] of noted) {\n const held = ids.filter((id) => (nodes.get(id)?.parent === parent) === joined);\n if (held.length > 0 && nodes.has(parent)) out.set(parent, held);\n }\n return out;\n}\n\nexport function createArrivalWindow<TData, TLayer extends string, TPose>(\n env: ArrivalWindowEnv<TData, TLayer, TPose>,\n): ArrivalWindow<TPose> {\n const { nodes } = env;\n let installed: SceneArrivalHandler<TPose> | null = null;\n let hasLayouts = false;\n let arrivals: Map<NodeId, NodeId[]> | null = null;\n let departures = new Map<NodeId, NodeId[]>();\n let changed = new Set<NodeId>();\n /** What the last settle wrote, reported to `onReflow` once its edit lands. */\n let reflowDue: LayoutMove<TPose>[] | null = null;\n const reflowListeners = createEmitter<[moves: readonly LayoutMove<TPose>[]]>();\n\n const activeHandler = (): SceneArrivalHandler<TPose> | null => installed ?? (hasLayouts ? env.layoutPass : null);\n\n function open(always = false): boolean {\n if (arrivals !== null || (!always && activeHandler() === null)) return false;\n arrivals = new Map();\n departures = new Map();\n changed = new Set();\n reflowDue = null;\n return true;\n }\n\n function emitReflow(): void {\n const moves = reflowDue;\n reflowDue = null;\n if (moves === null || moves.length === 0) return;\n reflowListeners.emit(moves);\n }\n\n function settle(): ArrangedPose[] {\n const pending = arrivals;\n arrivals = null;\n const handler = activeHandler();\n if (pending === null || handler === null) return [];\n // Only what is still there once the edit's other mutations have landed.\n const landed = heldMoves(nodes, pending, true);\n // Only what is gone from the container once the edit has landed: a child\n // that left and came back did not depart.\n const left = heldMoves(nodes, departures, false);\n departures = new Map();\n const touched = new Set([...changed].filter((id) => nodes.get(id)?.kind === 'container'));\n if (landed.size === 0 && touched.size === 0) return [];\n const poses = handler(landed, touched, left);\n if (poses === null) throw new SceneArrivalRefused(landed);\n const out: ArrangedPose[] = [];\n for (const [id, to] of poses) {\n const node = nodes.get(id);\n if (node) out.push({ id, from: node.pose, to });\n }\n reflowDue = out as LayoutMove<TPose>[];\n return out;\n }\n\n function abandon(): void {\n arrivals = null;\n reflowDue = null;\n }\n\n /** `ops` plus the op that settles their arrivals, when this call owns the\n * window; `ops` unchanged otherwise. Opened even on a scene with no layout\n * yet: an edit's op list is fixed before it runs, and any op in it may give\n * the scene its first. The arrange op that settles nothing elides itself. */\n function withArrivalOps(ops: Op[]): { ops: Op[]; owned: boolean } {\n if (!open(true)) return { ops, owned: false };\n return { ops: [...ops, createArrangeOp({}, settle, env.writePose)], owned: true };\n }\n\n return {\n layoutDeclared: () => { hasLayouts = true; },\n setHandler(handler) {\n installed = handler;\n return () => {\n if (installed === handler) installed = null;\n };\n },\n onReflow: reflowListeners.subscribe,\n noteArrival(id, parent, from) {\n if (arrivals === null || parent === null || parent === from) return;\n changed.add(parent);\n const list = arrivals.get(parent);\n if (list === undefined) arrivals.set(parent, [id]);\n else if (!list.includes(id)) list.push(id);\n },\n noteDeparture(id, from, to) {\n if (arrivals === null || from === null || from === to) return;\n changed.add(from);\n // One that joined earlier in this edit was never there to leave.\n if (arrivals.get(from)?.includes(id)) return;\n const list = departures.get(from);\n if (list === undefined) departures.set(from, [id]);\n else if (!list.includes(id)) list.push(id);\n },\n noteChange(id) {\n if (arrivals !== null && id !== null) changed.add(id);\n },\n bareLayoutEdit: () => activeHandler() !== null && arrivals === null && env.recordsBareEdits(),\n open,\n settle,\n emitReflow,\n abandon,\n runEdit(ops, run) {\n const { ops: all, owned } = withArrivalOps(ops);\n // An edit inside another's window leaves a refusal to the one that owns\n // it, which reverts the whole edit and answers for it.\n if (!owned) return run(all), true;\n try {\n run(all);\n emitReflow();\n return true;\n } catch (err) {\n if (!(err instanceof SceneArrivalRefused)) throw err;\n return false;\n } finally {\n abandon();\n }\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { composeWorldPose, composesFrames, frameAtOrAbove, rebaseLocalPose } from "./composeFrame.js";
2
+ import { scenePoseAdapter } from "./scenePoseAdapter.js";
3
+
4
+ //#region src/core/scene/carryDescendants.ts
5
+ /**
6
+ * Bringing a node's descendants along when something writes the node's pose
7
+ * and nothing writes theirs: a layout restacking a container, a drop landing
8
+ * one, a page move. Under absolute poses a descendant stores its own world
9
+ * pose, so it stays behind unless it is written too.
10
+ */
11
+ /** A {@link CarrySource} over a scene's document poses. */
12
+ function sceneCarrySource(scene) {
13
+ return {
14
+ childrenOf: (id) => scene.childrenOf(id),
15
+ poses: scenePoseAdapter(scene),
16
+ composition: scene.composition
17
+ };
18
+ }
19
+ /**
20
+ * The stored poses that bring `root`'s descendants along with it: each one's
21
+ * world pose put through `translate`, rebased into the frame it is stored in.
22
+ * A descendant stored in the frame of `root` or of a node under it is left
23
+ * out, since that frame carries it, and so is one `translate` answers null
24
+ * for. A descendant `moving` names is moving on its own: it and everything
25
+ * under it are left to whoever moves it.
26
+ */
27
+ function carriedDescendants(source, root, translate, moving = () => false) {
28
+ const { poses, composition } = source;
29
+ const framed = composesFrames(composition);
30
+ const under = /* @__PURE__ */ new Set([root]);
31
+ const out = /* @__PURE__ */ new Map();
32
+ const walk = (at) => {
33
+ for (const id of source.childrenOf(at)) {
34
+ if (moving(id)) continue;
35
+ under.add(id);
36
+ const parent = poses.getParent(id);
37
+ const frame = framed ? frameAtOrAbove(poses, parent) : null;
38
+ if (frame === null || !under.has(frame)) {
39
+ const world = translate(composeWorldPose(poses, id, composition.compose), id);
40
+ if (world !== null) out.set(id, rebaseLocalPose(poses, world, parent, composition.compose, composition.decompose));
41
+ }
42
+ walk(id);
43
+ }
44
+ };
45
+ walk(root);
46
+ return out;
47
+ }
48
+
49
+ //#endregion
50
+ export { carriedDescendants, sceneCarrySource };
51
+ //# sourceMappingURL=carryDescendants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"carryDescendants.js","names":[],"sources":["../../../src/core/scene/carryDescendants.ts"],"sourcesContent":["/**\n * Bringing a node's descendants along when something writes the node's pose\n * and nothing writes theirs: a layout restacking a container, a drop landing\n * one, a page move. Under absolute poses a descendant stores its own world\n * pose, so it stays behind unless it is written too.\n */\nimport { composeWorldPose, composesFrames, frameAtOrAbove, rebaseLocalPose, type PoseAdapter, type PoseComposition } from './composeFrame';\nimport { scenePoseAdapter } from './scenePoseAdapter';\nimport type { NodeId, Scene } from './types';\n\n/** What carrying reads: the tree, every stored pose, and how poses compose. */\nexport interface CarrySource<TPose> {\n childrenOf(id: NodeId): readonly NodeId[];\n poses: PoseAdapter<TPose>;\n composition: PoseComposition<TPose>;\n}\n\n/** A {@link CarrySource} over a scene's document poses. */\nexport function sceneCarrySource(scene: Scene<unknown, string, unknown>): CarrySource<unknown> {\n return {\n childrenOf: (id) => scene.childrenOf(id),\n poses: scenePoseAdapter(scene),\n composition: scene.composition,\n };\n}\n\n/**\n * The stored poses that bring `root`'s descendants along with it: each one's\n * world pose put through `translate`, rebased into the frame it is stored in.\n * A descendant stored in the frame of `root` or of a node under it is left\n * out, since that frame carries it, and so is one `translate` answers null\n * for. A descendant `moving` names is moving on its own: it and everything\n * under it are left to whoever moves it.\n */\nexport function carriedDescendants<TPose>(\n source: CarrySource<TPose>,\n root: NodeId,\n translate: (world: TPose, id: NodeId) => TPose | null,\n moving: (id: NodeId) => boolean = () => false,\n): Map<NodeId, TPose> {\n const { poses, composition } = source;\n const framed = composesFrames(composition);\n const under = new Set<NodeId>([root]);\n const out = new Map<NodeId, TPose>();\n const walk = (at: NodeId): void => {\n for (const id of source.childrenOf(at)) {\n if (moving(id)) continue;\n under.add(id);\n const parent = poses.getParent(id);\n const frame = framed ? frameAtOrAbove(poses, parent) : null;\n if (frame === null || !under.has(frame as NodeId)) {\n const world = translate(composeWorldPose(poses, id, composition.compose), id);\n if (world !== null) out.set(id, rebaseLocalPose(poses, world, parent, composition.compose, composition.decompose));\n }\n walk(id);\n }\n };\n walk(root);\n return out;\n}\n"],"mappings":";;;;;;;;;;;AAkBA,SAAgB,iBAAiB,OAA8D;CAC7F,OAAO;EACL,aAAa,OAAO,MAAM,WAAW,EAAE;EACvC,OAAO,iBAAiB,KAAK;EAC7B,aAAa,MAAM;CACrB;AACF;;;;;;;;;AAUA,SAAgB,mBACd,QACA,MACA,WACA,eAAwC,OACpB;CACpB,MAAM,EAAE,OAAO,gBAAgB;CAC/B,MAAM,SAAS,eAAe,WAAW;CACzC,MAAM,wBAAQ,IAAI,IAAY,CAAC,IAAI,CAAC;CACpC,MAAM,sBAAM,IAAI,IAAmB;CACnC,MAAM,QAAQ,OAAqB;EACjC,KAAK,MAAM,MAAM,OAAO,WAAW,EAAE,GAAG;GACtC,IAAI,OAAO,EAAE,GAAG;GAChB,MAAM,IAAI,EAAE;GACZ,MAAM,SAAS,MAAM,UAAU,EAAE;GACjC,MAAM,QAAQ,SAAS,eAAe,OAAO,MAAM,IAAI;GACvD,IAAI,UAAU,QAAQ,CAAC,MAAM,IAAI,KAAe,GAAG;IACjD,MAAM,QAAQ,UAAU,iBAAiB,OAAO,IAAI,YAAY,OAAO,GAAG,EAAE;IAC5E,IAAI,UAAU,MAAM,IAAI,IAAI,IAAI,gBAAgB,OAAO,OAAO,QAAQ,YAAY,SAAS,YAAY,SAAS,CAAC;GACnH;GACA,KAAK,EAAE;EACT;CACF;CACA,KAAK,IAAI;CACT,OAAO;AACT"}
@@ -0,0 +1,13 @@
1
+ //#region src/core/scene/clipNothing.ts
2
+ /** Registry key for {@link clipNothing}; every scene's registry carries it. */
3
+ var CLIP_NOTHING = "kit:clipNothing";
4
+ /**
5
+ * A container's `clipFromPose` that clips nothing, for a container whose
6
+ * children may draw outside it. A container without one clips its children to
7
+ * its painter's silhouette.
8
+ */
9
+ var clipNothing = () => null;
10
+
11
+ //#endregion
12
+ export { CLIP_NOTHING, clipNothing };
13
+ //# sourceMappingURL=clipNothing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clipNothing.js","names":[],"sources":["../../../src/core/scene/clipNothing.ts"],"sourcesContent":["/** Registry key for {@link clipNothing}; every scene's registry carries it. */\nexport const CLIP_NOTHING = 'kit:clipNothing';\n\n/**\n * A container's `clipFromPose` that clips nothing, for a container whose\n * children may draw outside it. A container without one clips its children to\n * its painter's silhouette.\n */\nexport const clipNothing = (): null => null;\n"],"mappings":";;AACA,IAAa,eAAe;;;;;;AAO5B,IAAa,oBAA0B"}
@@ -1,3 +1,4 @@
1
+ import { fontGeneration, noteFontRead, withFontReads } from "./fontReads.js";
1
2
  import { samePoseValue, snapshotPose } from "./poseSnapshot.js";
2
3
 
3
4
  //#region src/core/scene/depMemo.ts
@@ -7,7 +8,8 @@ function emptyDepRecord() {
7
8
  poses: [],
8
9
  data: [],
9
10
  layers: [],
10
- paths: []
11
+ paths: [],
12
+ faces: null
11
13
  };
12
14
  }
13
15
  /** A dependency as the derivation is handed it, noting a read of its path. A
@@ -37,20 +39,25 @@ function deriveRecorded(into, deps, derive) {
37
39
  into.data.length = 0;
38
40
  into.layers.length = 0;
39
41
  into.paths.length = 0;
40
- return derive(deps.map((dep, i) => {
42
+ const handed = deps.map((dep, i) => {
41
43
  into.nodes.push(dep?.node);
42
44
  into.poses.push(dep === void 0 ? void 0 : snapshotPose(dep.pose));
43
45
  into.data.push(dep?.node.data);
44
46
  into.layers.push(dep?.node.layer);
45
47
  into.paths.push(void 0);
46
48
  return dep === void 0 ? void 0 : new RecordedDep(dep, into.paths, i);
47
- }));
49
+ });
50
+ const generation = fontGeneration();
51
+ const { value, fonts } = withFontReads(() => derive(handed));
52
+ into.faces = fonts ? generation : null;
53
+ return value;
48
54
  }
49
55
  /** Whether the dependencies still resolve to what the record was taken from.
50
56
  * Resolves them one at a time rather than taking an array: this is the hit
51
57
  * path, and it walks every derived node's every dependency on every frame. */
52
58
  function sameDeps(record, ids, depOf) {
53
59
  if (record.nodes.length !== ids.length) return false;
60
+ if (record.faces !== null && record.faces !== fontGeneration()) return false;
54
61
  for (let i = 0; i < ids.length; i++) {
55
62
  const dep = depOf(ids[i]);
56
63
  if (record.nodes[i] !== (dep === void 0 ? void 0 : dep.node)) return false;
@@ -60,6 +67,7 @@ function sameDeps(record, ids, depOf) {
60
67
  const path = record.paths[i];
61
68
  if (path !== void 0 && path !== dep.path) return false;
62
69
  }
70
+ if (record.faces !== null) noteFontRead();
63
71
  return true;
64
72
  }
65
73
 
@@ -1 +1 @@
1
- {"version":3,"file":"depMemo.js","names":[],"sources":["../../../src/core/scene/depMemo.ts"],"sourcesContent":["/**\n * What a memoized derivation was derived *from*, so a hit can re-check it.\n *\n * A derivation keyed on the deriving node's own authored pose only notices a\n * change someone pushed. A dependency that changed with nothing pushed behind\n * it — an ancestor's frame moving, a removal, a dependency appearing, a lookup\n * answering nodes no scene edits — is invisible to that key. Recording what\n * the derivation was handed and comparing it on the hit path is what notices\n * it without a trigger.\n *\n * What is recorded is what a derivation may read of a dependency: its node (an\n * identity), its pose (by value), its `data` (a reference, which every edit\n * replaces), its `layer`, and its path where the derivation read it. Anything\n * else on the node — its parent, its children — still needs a push.\n */\nimport type { Path } from '@weasel-js/geom';\nimport { samePoseValue, snapshotPose } from './poseSnapshot';\nimport type { DerivedDep, Node, NodeId } from './types';\n\n/** Each dependency's node — an identity, so a restored clone is a different\n * one — with a copy of the pose it resolved to, its `data` and `layer`, and\n * the path it answered, `undefined` where the derivation never asked. */\nexport interface DepRecord<TPose> {\n nodes: (object | undefined)[];\n poses: (TPose | undefined)[];\n data: unknown[];\n layers: (string | undefined)[];\n paths: (Path | null | undefined)[];\n}\n\nexport function emptyDepRecord<TPose>(): DepRecord<TPose> {\n return { nodes: [], poses: [], data: [], layers: [], paths: [] };\n}\n\n/** A dependency as the derivation is handed it, noting a read of its path. A\n * class for the reason `SceneDep` is one: a prototype accessor is cheap. */\nclass RecordedDep<TPose> implements DerivedDep<TPose> {\n readonly node: Node<unknown, string, TPose>;\n readonly pose: TPose;\n\n constructor(\n private readonly dep: DerivedDep<TPose>,\n private readonly paths: (Path | null | undefined)[],\n private readonly index: number,\n ) {\n this.node = dep.node;\n this.pose = dep.pose;\n }\n\n get path(): Path | null {\n return (this.paths[this.index] = this.dep.path);\n }\n}\n\n/** Run `derive` against `deps`, recording in place what it was run against.\n * Mutating the record is what updates the memo slot, which holds this object. */\nexport function deriveRecorded<TPose, T>(\n into: DepRecord<TPose>,\n deps: readonly (DerivedDep<TPose> | undefined)[],\n derive: (deps: readonly (DerivedDep<TPose> | undefined)[]) => T,\n): T {\n into.nodes.length = 0;\n into.poses.length = 0;\n into.data.length = 0;\n into.layers.length = 0;\n into.paths.length = 0;\n const handed = deps.map((dep, i) => {\n into.nodes.push(dep?.node);\n into.poses.push(dep === undefined ? undefined : snapshotPose(dep.pose));\n into.data.push(dep?.node.data);\n into.layers.push(dep?.node.layer);\n into.paths.push(undefined);\n return dep === undefined ? undefined : new RecordedDep(dep, into.paths, i);\n });\n return derive(handed);\n}\n\n/** Whether the dependencies still resolve to what the record was taken from.\n * Resolves them one at a time rather than taking an array: this is the hit\n * path, and it walks every derived node's every dependency on every frame. */\nexport function sameDeps<TPose>(\n record: DepRecord<TPose>,\n ids: readonly NodeId[],\n depOf: (id: NodeId) => DerivedDep<TPose> | undefined,\n): boolean {\n if (record.nodes.length !== ids.length) return false;\n for (let i = 0; i < ids.length; i++) {\n const dep = depOf(ids[i]);\n if (record.nodes[i] !== (dep === undefined ? undefined : dep.node)) return false;\n if (dep === undefined) continue;\n if (record.data[i] !== dep.node.data || record.layers[i] !== dep.node.layer) return false;\n if (!samePoseValue(record.poses[i], dep.pose)) return false;\n const path = record.paths[i];\n if (path !== undefined && path !== dep.path) return false;\n }\n return true;\n}\n"],"mappings":";;;AA8BA,SAAgB,iBAA0C;CACxD,OAAO;EAAE,OAAO,CAAC;EAAG,OAAO,CAAC;EAAG,MAAM,CAAC;EAAG,QAAQ,CAAC;EAAG,OAAO,CAAC;CAAE;AACjE;;;AAIA,IAAM,cAAN,MAAsD;CAKjC;CACA;CACA;CANnB;CACA;CAEA,YACE,KACA,OACA,OACA;EAHiB,KAAA,MAAA;EACA,KAAA,QAAA;EACA,KAAA,QAAA;EAEjB,KAAK,OAAO,IAAI;EAChB,KAAK,OAAO,IAAI;CAClB;CAEA,IAAI,OAAoB;EACtB,OAAQ,KAAK,MAAM,KAAK,SAAS,KAAK,IAAI;CAC5C;AACF;;;AAIA,SAAgB,eACd,MACA,MACA,QACG;CACH,KAAK,MAAM,SAAS;CACpB,KAAK,MAAM,SAAS;CACpB,KAAK,KAAK,SAAS;CACnB,KAAK,OAAO,SAAS;CACrB,KAAK,MAAM,SAAS;CASpB,OAAO,OARQ,KAAK,KAAK,KAAK,MAAM;EAClC,KAAK,MAAM,KAAK,KAAK,IAAI;EACzB,KAAK,MAAM,KAAK,QAAQ,SAAY,SAAY,aAAa,IAAI,IAAI,CAAC;EACtE,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI;EAC7B,KAAK,OAAO,KAAK,KAAK,KAAK,KAAK;EAChC,KAAK,MAAM,KAAK,MAAS;EACzB,OAAO,QAAQ,SAAY,SAAY,IAAI,YAAY,KAAK,KAAK,OAAO,CAAC;CAC3E,CACc,CAAM;AACtB;;;;AAKA,SAAgB,SACd,QACA,KACA,OACS;CACT,IAAI,OAAO,MAAM,WAAW,IAAI,QAAQ,OAAO;CAC/C,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;EACnC,MAAM,MAAM,MAAM,IAAI,EAAE;EACxB,IAAI,OAAO,MAAM,QAAQ,QAAQ,SAAY,SAAY,IAAI,OAAO,OAAO;EAC3E,IAAI,QAAQ,QAAW;EACvB,IAAI,OAAO,KAAK,OAAO,IAAI,KAAK,QAAQ,OAAO,OAAO,OAAO,IAAI,KAAK,OAAO,OAAO;EACpF,IAAI,CAAC,cAAc,OAAO,MAAM,IAAI,IAAI,IAAI,GAAG,OAAO;EACtD,MAAM,OAAO,OAAO,MAAM;EAC1B,IAAI,SAAS,UAAa,SAAS,IAAI,MAAM,OAAO;CACtD;CACA,OAAO;AACT"}
1
+ {"version":3,"file":"depMemo.js","names":[],"sources":["../../../src/core/scene/depMemo.ts"],"sourcesContent":["/**\n * What a memoized derivation was derived *from*, so a hit can re-check it.\n *\n * A derivation keyed on the deriving node's own authored pose only notices a\n * change someone pushed. A dependency that changed with nothing pushed behind\n * it — an ancestor's frame moving, a removal, a dependency appearing, a lookup\n * answering nodes no scene edits — is invisible to that key. Recording what\n * the derivation was handed and comparing it on the hit path is what notices\n * it without a trigger.\n *\n * What is recorded is what a derivation may read of a dependency: its node (an\n * identity), its pose (by value), its `data` (a reference, which every edit\n * replaces), its `layer`, and its path where the derivation read it. Anything\n * else on the node — its parent, its children — still needs a push. A\n * derivation that read glyph outlines also records the face generation, since\n * a face landing changes its result with nothing in the scene changed.\n */\nimport type { Path } from '@weasel-js/geom';\nimport { fontGeneration, noteFontRead, withFontReads } from './fontReads';\nimport { samePoseValue, snapshotPose } from './poseSnapshot';\nimport type { DerivedDep, Node, NodeId } from './types';\n\n/** Each dependency's node — an identity, so a restored clone is a different\n * one — with a copy of the pose it resolved to, its `data` and `layer`, and\n * the path it answered, `undefined` where the derivation never asked. */\nexport interface DepRecord<TPose> {\n nodes: (object | undefined)[];\n poses: (TPose | undefined)[];\n data: unknown[];\n layers: (string | undefined)[];\n paths: (Path | null | undefined)[];\n /** The face generation it was derived under, or `null` when it read no\n * glyph outlines. */\n faces: number | null;\n}\n\nexport function emptyDepRecord<TPose>(): DepRecord<TPose> {\n return { nodes: [], poses: [], data: [], layers: [], paths: [], faces: null };\n}\n\n/** A dependency as the derivation is handed it, noting a read of its path. A\n * class for the reason `SceneDep` is one: a prototype accessor is cheap. */\nclass RecordedDep<TPose> implements DerivedDep<TPose> {\n readonly node: Node<unknown, string, TPose>;\n readonly pose: TPose;\n\n constructor(\n private readonly dep: DerivedDep<TPose>,\n private readonly paths: (Path | null | undefined)[],\n private readonly index: number,\n ) {\n this.node = dep.node;\n this.pose = dep.pose;\n }\n\n get path(): Path | null {\n return (this.paths[this.index] = this.dep.path);\n }\n}\n\n/** Run `derive` against `deps`, recording in place what it was run against.\n * Mutating the record is what updates the memo slot, which holds this object. */\nexport function deriveRecorded<TPose, T>(\n into: DepRecord<TPose>,\n deps: readonly (DerivedDep<TPose> | undefined)[],\n derive: (deps: readonly (DerivedDep<TPose> | undefined)[]) => T,\n): T {\n into.nodes.length = 0;\n into.poses.length = 0;\n into.data.length = 0;\n into.layers.length = 0;\n into.paths.length = 0;\n const handed = deps.map((dep, i) => {\n into.nodes.push(dep?.node);\n into.poses.push(dep === undefined ? undefined : snapshotPose(dep.pose));\n into.data.push(dep?.node.data);\n into.layers.push(dep?.node.layer);\n into.paths.push(undefined);\n return dep === undefined ? undefined : new RecordedDep(dep, into.paths, i);\n });\n const generation = fontGeneration();\n const { value, fonts } = withFontReads(() => derive(handed));\n into.faces = fonts ? generation : null;\n return value;\n}\n\n/** Whether the dependencies still resolve to what the record was taken from.\n * Resolves them one at a time rather than taking an array: this is the hit\n * path, and it walks every derived node's every dependency on every frame. */\nexport function sameDeps<TPose>(\n record: DepRecord<TPose>,\n ids: readonly NodeId[],\n depOf: (id: NodeId) => DerivedDep<TPose> | undefined,\n): boolean {\n if (record.nodes.length !== ids.length) return false;\n if (record.faces !== null && record.faces !== fontGeneration()) return false;\n for (let i = 0; i < ids.length; i++) {\n const dep = depOf(ids[i]);\n if (record.nodes[i] !== (dep === undefined ? undefined : dep.node)) return false;\n if (dep === undefined) continue;\n if (record.data[i] !== dep.node.data || record.layers[i] !== dep.node.layer) return false;\n if (!samePoseValue(record.poses[i], dep.pose)) return false;\n const path = record.paths[i];\n if (path !== undefined && path !== dep.path) return false;\n }\n // A hit is still a read, for any derivation enclosing this one.\n if (record.faces !== null) noteFontRead();\n return true;\n}\n"],"mappings":";;;;AAoCA,SAAgB,iBAA0C;CACxD,OAAO;EAAE,OAAO,CAAC;EAAG,OAAO,CAAC;EAAG,MAAM,CAAC;EAAG,QAAQ,CAAC;EAAG,OAAO,CAAC;EAAG,OAAO;CAAK;AAC9E;;;AAIA,IAAM,cAAN,MAAsD;CAKjC;CACA;CACA;CANnB;CACA;CAEA,YACE,KACA,OACA,OACA;EAHiB,KAAA,MAAA;EACA,KAAA,QAAA;EACA,KAAA,QAAA;EAEjB,KAAK,OAAO,IAAI;EAChB,KAAK,OAAO,IAAI;CAClB;CAEA,IAAI,OAAoB;EACtB,OAAQ,KAAK,MAAM,KAAK,SAAS,KAAK,IAAI;CAC5C;AACF;;;AAIA,SAAgB,eACd,MACA,MACA,QACG;CACH,KAAK,MAAM,SAAS;CACpB,KAAK,MAAM,SAAS;CACpB,KAAK,KAAK,SAAS;CACnB,KAAK,OAAO,SAAS;CACrB,KAAK,MAAM,SAAS;CACpB,MAAM,SAAS,KAAK,KAAK,KAAK,MAAM;EAClC,KAAK,MAAM,KAAK,KAAK,IAAI;EACzB,KAAK,MAAM,KAAK,QAAQ,SAAY,SAAY,aAAa,IAAI,IAAI,CAAC;EACtE,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI;EAC7B,KAAK,OAAO,KAAK,KAAK,KAAK,KAAK;EAChC,KAAK,MAAM,KAAK,MAAS;EACzB,OAAO,QAAQ,SAAY,SAAY,IAAI,YAAY,KAAK,KAAK,OAAO,CAAC;CAC3E,CAAC;CACD,MAAM,aAAa,eAAe;CAClC,MAAM,EAAE,OAAO,UAAU,oBAAoB,OAAO,MAAM,CAAC;CAC3D,KAAK,QAAQ,QAAQ,aAAa;CAClC,OAAO;AACT;;;;AAKA,SAAgB,SACd,QACA,KACA,OACS;CACT,IAAI,OAAO,MAAM,WAAW,IAAI,QAAQ,OAAO;CAC/C,IAAI,OAAO,UAAU,QAAQ,OAAO,UAAU,eAAe,GAAG,OAAO;CACvE,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;EACnC,MAAM,MAAM,MAAM,IAAI,EAAE;EACxB,IAAI,OAAO,MAAM,QAAQ,QAAQ,SAAY,SAAY,IAAI,OAAO,OAAO;EAC3E,IAAI,QAAQ,QAAW;EACvB,IAAI,OAAO,KAAK,OAAO,IAAI,KAAK,QAAQ,OAAO,OAAO,OAAO,IAAI,KAAK,OAAO,OAAO;EACpF,IAAI,CAAC,cAAc,OAAO,MAAM,IAAI,IAAI,IAAI,GAAG,OAAO;EACtD,MAAM,OAAO,OAAO,MAAM;EAC1B,IAAI,SAAS,UAAa,SAAS,IAAI,MAAM,OAAO;CACtD;CAEA,IAAI,OAAO,UAAU,MAAM,aAAa;CACxC,OAAO;AACT"}
@@ -1,5 +1,11 @@
1
1
  //#region src/core/scene/dependents.ts
2
2
  var NONE = Object.freeze([]);
3
+ /** The nodes in `scene` that list `id` in their `dependsOn`, directly or through others, less any inside `id`'s own
4
+ * subtree. */
5
+ function sceneDependentsOf(scene, id) {
6
+ if (!scene.get(id)) return NONE;
7
+ return scene.removalClosure([id]).filter((d) => d !== id && !scene.ancestorsOf(d).includes(id));
8
+ }
3
9
  /**
4
10
  * The nodes `node`'s geometry derives from: the ids it named, or its own
5
11
  * children when it named `'children'`.
@@ -90,5 +96,5 @@ function sameDependsOn(a, b) {
90
96
  }
91
97
 
92
98
  //#endregion
93
- export { createDependentsIndex, dependencyIdsOf, sameDependsOn };
99
+ export { createDependentsIndex, dependencyIdsOf, sameDependsOn, sceneDependentsOf };
94
100
  //# sourceMappingURL=dependents.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dependents.js","names":[],"sources":["../../../src/core/scene/dependents.ts"],"sourcesContent":["/**\n * Which nodes must recompute when a given node's pose changes — the reverse\n * index, plus {@link dependencyIdsOf}, the forward read it is built from.\n */\nimport type { NodeId } from './types';\n\nconst NONE: readonly NodeId[] = Object.freeze([]);\n\n/**\n * The nodes `node`'s geometry derives from: the ids it named, or its own\n * children when it named `'children'`.\n *\n * The `'children'` form is deliberately absent from the reverse index — a\n * container is not a dependent of the children it hugs, or deleting one child\n * would cascade the whole group away. Its invalidation is the ancestor walk in\n * `scene.ts` instead.\n */\nexport function dependencyIdsOf(\n node: { id: NodeId; dependsOn?: readonly NodeId[] | 'children' },\n childrenOf: (id: NodeId) => readonly NodeId[],\n): readonly NodeId[] {\n const deps = node.dependsOn;\n if (deps === undefined) return NONE;\n return deps === 'children' ? childrenOf(node.id) : deps;\n}\n\nexport interface DependentsIndex {\n add(id: NodeId, deps: readonly NodeId[]): void;\n /** Forget what `id` declared. Deliberately not symmetric: who depends on\n * `id` is those nodes' declaration, not `id`'s, and outlives its removal. */\n remove(id: NodeId): void;\n /** Forget every registration. */\n clear(): void;\n /** True when nothing derives from anything. */\n isEmpty(): boolean;\n dependentsOf(id: NodeId): Iterable<NodeId>;\n /** Nodes that derive from `id` directly or through a chain. Excludes `id`\n * itself unless a cycle leads back to it. */\n transitiveDependentsOf(id: NodeId): Iterable<NodeId>;\n}\n\nexport function createDependentsIndex(): DependentsIndex {\n /** dependency -> nodes deriving from it */\n const forward = new Map<NodeId, Set<NodeId>>();\n /** dependent -> the dependencies it registered against */\n const reverse = new Map<NodeId, readonly NodeId[]>();\n\n /** Drop `id`'s registrations against its current dependencies. Shared by\n * `add` (which re-registers after) and `remove` (which does not). */\n function detachOwnDeps(id: NodeId): void {\n const old = reverse.get(id);\n if (old === undefined) return;\n for (const dep of old) {\n const set = forward.get(dep);\n if (set === undefined) continue;\n set.delete(id);\n if (set.size === 0) forward.delete(dep);\n }\n reverse.delete(id);\n }\n\n return {\n add(id, deps) {\n detachOwnDeps(id);\n if (deps.length === 0) return;\n reverse.set(id, [...deps]);\n for (const dep of deps) {\n let set = forward.get(dep);\n if (set === undefined) { set = new Set(); forward.set(dep, set); }\n set.add(id);\n }\n },\n\n remove(id) {\n detachOwnDeps(id);\n },\n\n clear() {\n forward.clear();\n reverse.clear();\n },\n\n isEmpty() {\n return forward.size === 0;\n },\n\n dependentsOf(id) {\n const set = forward.get(id);\n return set === undefined ? NONE : [...set];\n },\n\n transitiveDependentsOf(id) {\n // Runs per node per frame; the miss must not allocate.\n const direct = forward.get(id);\n if (direct === undefined) return NONE;\n const out = new Set<NodeId>();\n const stack: NodeId[] = [...direct];\n while (stack.length > 0) {\n const next = stack.pop()!;\n if (out.has(next)) continue; // also what stops a cycle\n out.add(next);\n for (const d of forward.get(next) ?? []) stack.push(d);\n }\n return out;\n },\n };\n}\n\n/**\n * Whether two `dependsOn` values name the same thing, so a retarget to what a\n * node already declares can be elided. Order is part of it: a router reads its\n * ends positionally, and swapping them reverses the edge.\n */\nexport function sameDependsOn(\n a: readonly NodeId[] | 'children' | undefined,\n b: readonly NodeId[] | 'children' | undefined,\n): boolean {\n if (a === b) return true;\n if (a === undefined || b === undefined) return false;\n if (a === 'children' || b === 'children') return false;\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n"],"mappings":";AAMA,IAAM,OAA0B,OAAO,OAAO,CAAC,CAAC;;;;;;;;;;AAWhD,SAAgB,gBACd,MACA,YACmB;CACnB,MAAM,OAAO,KAAK;CAClB,IAAI,SAAS,QAAW,OAAO;CAC/B,OAAO,SAAS,aAAa,WAAW,KAAK,EAAE,IAAI;AACrD;AAiBA,SAAgB,wBAAyC;;CAEvD,MAAM,0BAAU,IAAI,IAAyB;;CAE7C,MAAM,0BAAU,IAAI,IAA+B;;;CAInD,SAAS,cAAc,IAAkB;EACvC,MAAM,MAAM,QAAQ,IAAI,EAAE;EAC1B,IAAI,QAAQ,QAAW;EACvB,KAAK,MAAM,OAAO,KAAK;GACrB,MAAM,MAAM,QAAQ,IAAI,GAAG;GAC3B,IAAI,QAAQ,QAAW;GACvB,IAAI,OAAO,EAAE;GACb,IAAI,IAAI,SAAS,GAAG,QAAQ,OAAO,GAAG;EACxC;EACA,QAAQ,OAAO,EAAE;CACnB;CAEA,OAAO;EACL,IAAI,IAAI,MAAM;GACZ,cAAc,EAAE;GAChB,IAAI,KAAK,WAAW,GAAG;GACvB,QAAQ,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC;GACzB,KAAK,MAAM,OAAO,MAAM;IACtB,IAAI,MAAM,QAAQ,IAAI,GAAG;IACzB,IAAI,QAAQ,QAAW;KAAE,sBAAM,IAAI,IAAI;KAAG,QAAQ,IAAI,KAAK,GAAG;IAAG;IACjE,IAAI,IAAI,EAAE;GACZ;EACF;EAEA,OAAO,IAAI;GACT,cAAc,EAAE;EAClB;EAEA,QAAQ;GACN,QAAQ,MAAM;GACd,QAAQ,MAAM;EAChB;EAEA,UAAU;GACR,OAAO,QAAQ,SAAS;EAC1B;EAEA,aAAa,IAAI;GACf,MAAM,MAAM,QAAQ,IAAI,EAAE;GAC1B,OAAO,QAAQ,SAAY,OAAO,CAAC,GAAG,GAAG;EAC3C;EAEA,uBAAuB,IAAI;GAEzB,MAAM,SAAS,QAAQ,IAAI,EAAE;GAC7B,IAAI,WAAW,QAAW,OAAO;GACjC,MAAM,sBAAM,IAAI,IAAY;GAC5B,MAAM,QAAkB,CAAC,GAAG,MAAM;GAClC,OAAO,MAAM,SAAS,GAAG;IACvB,MAAM,OAAO,MAAM,IAAI;IACvB,IAAI,IAAI,IAAI,IAAI,GAAG;IACnB,IAAI,IAAI,IAAI;IACZ,KAAK,MAAM,KAAK,QAAQ,IAAI,IAAI,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC;GACvD;GACA,OAAO;EACT;CACF;AACF;;;;;;AAOA,SAAgB,cACd,GACA,GACS;CACT,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,MAAM,UAAa,MAAM,QAAW,OAAO;CAC/C,IAAI,MAAM,cAAc,MAAM,YAAY,OAAO;CACjD,IAAI,EAAE,WAAW,EAAE,QAAQ,OAAO;CAClC,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK,IAAI,EAAE,OAAO,EAAE,IAAI,OAAO;CAC7D,OAAO;AACT"}
1
+ {"version":3,"file":"dependents.js","names":[],"sources":["../../../src/core/scene/dependents.ts"],"sourcesContent":["/**\n * Which nodes must recompute when a given node's pose changes — the reverse\n * index, plus {@link dependencyIdsOf}, the forward read it is built from.\n */\nimport type { NodeId, Scene } from './types';\n\nconst NONE: readonly NodeId[] = Object.freeze([]);\n\n/** The nodes in `scene` that list `id` in their `dependsOn`, directly or through others, less any inside `id`'s own\n * subtree. */\nexport function sceneDependentsOf<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n id: NodeId,\n): readonly NodeId[] {\n if (!scene.get(id)) return NONE;\n return scene.removalClosure([id]).filter((d) => d !== id && !scene.ancestorsOf(d).includes(id));\n}\n\n/**\n * The nodes `node`'s geometry derives from: the ids it named, or its own\n * children when it named `'children'`.\n *\n * The `'children'` form is deliberately absent from the reverse index — a\n * container is not a dependent of the children it hugs, or deleting one child\n * would cascade the whole group away. Its invalidation is the ancestor walk in\n * `scene.ts` instead.\n */\nexport function dependencyIdsOf(\n node: { id: NodeId; dependsOn?: readonly NodeId[] | 'children' },\n childrenOf: (id: NodeId) => readonly NodeId[],\n): readonly NodeId[] {\n const deps = node.dependsOn;\n if (deps === undefined) return NONE;\n return deps === 'children' ? childrenOf(node.id) : deps;\n}\n\nexport interface DependentsIndex {\n add(id: NodeId, deps: readonly NodeId[]): void;\n /** Forget what `id` declared. Deliberately not symmetric: who depends on\n * `id` is those nodes' declaration, not `id`'s, and outlives its removal. */\n remove(id: NodeId): void;\n /** Forget every registration. */\n clear(): void;\n /** True when nothing derives from anything. */\n isEmpty(): boolean;\n dependentsOf(id: NodeId): Iterable<NodeId>;\n /** Nodes that derive from `id` directly or through a chain. Excludes `id`\n * itself unless a cycle leads back to it. */\n transitiveDependentsOf(id: NodeId): Iterable<NodeId>;\n}\n\nexport function createDependentsIndex(): DependentsIndex {\n /** dependency -> nodes deriving from it */\n const forward = new Map<NodeId, Set<NodeId>>();\n /** dependent -> the dependencies it registered against */\n const reverse = new Map<NodeId, readonly NodeId[]>();\n\n /** Drop `id`'s registrations against its current dependencies. Shared by\n * `add` (which re-registers after) and `remove` (which does not). */\n function detachOwnDeps(id: NodeId): void {\n const old = reverse.get(id);\n if (old === undefined) return;\n for (const dep of old) {\n const set = forward.get(dep);\n if (set === undefined) continue;\n set.delete(id);\n if (set.size === 0) forward.delete(dep);\n }\n reverse.delete(id);\n }\n\n return {\n add(id, deps) {\n detachOwnDeps(id);\n if (deps.length === 0) return;\n reverse.set(id, [...deps]);\n for (const dep of deps) {\n let set = forward.get(dep);\n if (set === undefined) { set = new Set(); forward.set(dep, set); }\n set.add(id);\n }\n },\n\n remove(id) {\n detachOwnDeps(id);\n },\n\n clear() {\n forward.clear();\n reverse.clear();\n },\n\n isEmpty() {\n return forward.size === 0;\n },\n\n dependentsOf(id) {\n const set = forward.get(id);\n return set === undefined ? NONE : [...set];\n },\n\n transitiveDependentsOf(id) {\n // Runs per node per frame; the miss must not allocate.\n const direct = forward.get(id);\n if (direct === undefined) return NONE;\n const out = new Set<NodeId>();\n const stack: NodeId[] = [...direct];\n while (stack.length > 0) {\n const next = stack.pop()!;\n if (out.has(next)) continue; // also what stops a cycle\n out.add(next);\n for (const d of forward.get(next) ?? []) stack.push(d);\n }\n return out;\n },\n };\n}\n\n/**\n * Whether two `dependsOn` values name the same thing, so a retarget to what a\n * node already declares can be elided. Order is part of it: a router reads its\n * ends positionally, and swapping them reverses the edge.\n */\nexport function sameDependsOn(\n a: readonly NodeId[] | 'children' | undefined,\n b: readonly NodeId[] | 'children' | undefined,\n): boolean {\n if (a === b) return true;\n if (a === undefined || b === undefined) return false;\n if (a === 'children' || b === 'children') return false;\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n"],"mappings":";AAMA,IAAM,OAA0B,OAAO,OAAO,CAAC,CAAC;;;AAIhD,SAAgB,kBACd,OACA,IACmB;CACnB,IAAI,CAAC,MAAM,IAAI,EAAE,GAAG,OAAO;CAC3B,OAAO,MAAM,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,MAAM,MAAM,MAAM,CAAC,MAAM,YAAY,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;AAChG;;;;;;;;;;AAWA,SAAgB,gBACd,MACA,YACmB;CACnB,MAAM,OAAO,KAAK;CAClB,IAAI,SAAS,QAAW,OAAO;CAC/B,OAAO,SAAS,aAAa,WAAW,KAAK,EAAE,IAAI;AACrD;AAiBA,SAAgB,wBAAyC;;CAEvD,MAAM,0BAAU,IAAI,IAAyB;;CAE7C,MAAM,0BAAU,IAAI,IAA+B;;;CAInD,SAAS,cAAc,IAAkB;EACvC,MAAM,MAAM,QAAQ,IAAI,EAAE;EAC1B,IAAI,QAAQ,QAAW;EACvB,KAAK,MAAM,OAAO,KAAK;GACrB,MAAM,MAAM,QAAQ,IAAI,GAAG;GAC3B,IAAI,QAAQ,QAAW;GACvB,IAAI,OAAO,EAAE;GACb,IAAI,IAAI,SAAS,GAAG,QAAQ,OAAO,GAAG;EACxC;EACA,QAAQ,OAAO,EAAE;CACnB;CAEA,OAAO;EACL,IAAI,IAAI,MAAM;GACZ,cAAc,EAAE;GAChB,IAAI,KAAK,WAAW,GAAG;GACvB,QAAQ,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC;GACzB,KAAK,MAAM,OAAO,MAAM;IACtB,IAAI,MAAM,QAAQ,IAAI,GAAG;IACzB,IAAI,QAAQ,QAAW;KAAE,sBAAM,IAAI,IAAI;KAAG,QAAQ,IAAI,KAAK,GAAG;IAAG;IACjE,IAAI,IAAI,EAAE;GACZ;EACF;EAEA,OAAO,IAAI;GACT,cAAc,EAAE;EAClB;EAEA,QAAQ;GACN,QAAQ,MAAM;GACd,QAAQ,MAAM;EAChB;EAEA,UAAU;GACR,OAAO,QAAQ,SAAS;EAC1B;EAEA,aAAa,IAAI;GACf,MAAM,MAAM,QAAQ,IAAI,EAAE;GAC1B,OAAO,QAAQ,SAAY,OAAO,CAAC,GAAG,GAAG;EAC3C;EAEA,uBAAuB,IAAI;GAEzB,MAAM,SAAS,QAAQ,IAAI,EAAE;GAC7B,IAAI,WAAW,QAAW,OAAO;GACjC,MAAM,sBAAM,IAAI,IAAY;GAC5B,MAAM,QAAkB,CAAC,GAAG,MAAM;GAClC,OAAO,MAAM,SAAS,GAAG;IACvB,MAAM,OAAO,MAAM,IAAI;IACvB,IAAI,IAAI,IAAI,IAAI,GAAG;IACnB,IAAI,IAAI,IAAI;IACZ,KAAK,MAAM,KAAK,QAAQ,IAAI,IAAI,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC;GACvD;GACA,OAAO;EACT;CACF;AACF;;;;;;AAOA,SAAgB,cACd,GACA,GACS;CACT,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,MAAM,UAAa,MAAM,QAAW,OAAO;CAC/C,IAAI,MAAM,cAAc,MAAM,YAAY,OAAO;CACjD,IAAI,EAAE,WAAW,EAAE,QAAQ,OAAO;CAClC,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK,IAAI,EAAE,OAAO,EAAE,IAAI,OAAO;CAC7D,OAAO;AACT"}
@@ -1,16 +1,15 @@
1
1
  import { cubicContoursToPath, pathToCubicContours } from "@weasel-js/geom";
2
+ import { resolveFill, resolveStroke } from "@weasel-js/paint";
2
3
 
3
4
  //#region src/core/scene/derivedParts.ts
4
- /**
5
- * A derived path that paints in several parts, each with its own fill and
6
- * stroke: the steps of a blend, the copies of a repeat.
7
- *
8
- * A derivation returns one `Path`, which is what picking, bounds and every
9
- * reader of `DerivedDep.path` see. {@link pathFromParts} makes that path out
10
- * of the parts and remembers the parts against it, so the derived-node
11
- * painter, handed the path, can paint each part as itself. The parts live as
12
- * long as the path does — in the derivation's memo.
13
- */
5
+ /** What `part` paints, its `INHERIT` taken from `own`, the deriving node's
6
+ * data — whose own `INHERIT` takes `inherited`, its container's. */
7
+ function resolvePartPaint(part, own, inherited) {
8
+ return {
9
+ fill: resolveFill(part.fill, resolveFill(own?.fill, inherited?.fill)),
10
+ stroke: resolveStroke(part.stroke, resolveStroke(own?.stroke, inherited?.stroke))
11
+ };
12
+ }
14
13
  var PARTS = /* @__PURE__ */ new WeakMap();
15
14
  /**
16
15
  * One path holding every part's outline, with the parts remembered against
@@ -54,5 +53,5 @@ function concatPaths(paths) {
54
53
  }
55
54
 
56
55
  //#endregion
57
- export { derivedPartsOf, pathFromParts };
56
+ export { derivedPartsOf, pathFromParts, resolvePartPaint };
58
57
  //# sourceMappingURL=derivedParts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"derivedParts.js","names":[],"sources":["../../../src/core/scene/derivedParts.ts"],"sourcesContent":["/**\n * A derived path that paints in several parts, each with its own fill and\n * stroke: the steps of a blend, the copies of a repeat.\n *\n * A derivation returns one `Path`, which is what picking, bounds and every\n * reader of `DerivedDep.path` see. {@link pathFromParts} makes that path out\n * of the parts and remembers the parts against it, so the derived-node\n * painter, handed the path, can paint each part as itself. The parts live as\n * long as the path does — in the derivation's memo.\n */\nimport { pathToCubicContours, cubicContoursToPath, type Path, type PolygonPath } from '@weasel-js/geom';\nimport type { Fill, Stroke } from '@weasel-js/paint';\n\n/** One painted piece of a derived path. */\nexport interface DerivedPart {\n path: Path;\n /** The part's fill. Absent, the node's own `data.fill` paints it; `null`\n * paints none. */\n fill?: Fill | null;\n /** The part's stroke, on the same terms as `fill`. */\n stroke?: Stroke | null;\n}\n\nconst PARTS = new WeakMap<Path, readonly DerivedPart[]>();\n\n/**\n * One path holding every part's outline, with the parts remembered against\n * it for the painter. Return it from a `derivePath`. `null` for no parts.\n */\nexport function pathFromParts(parts: readonly DerivedPart[]): Path | null {\n if (parts.length === 0) return null;\n const whole = parts.length === 1 ? parts[0]!.path : concatPaths(parts.map((p) => p.path));\n // A one-part path is the part's own, which another reader may hold; the\n // painter must not mistake that path for a painted one elsewhere.\n const key = whole === parts[0]!.path ? { ...whole } as Path : whole;\n PARTS.set(key, parts);\n return key;\n}\n\n/** The parts `path` was made from by {@link pathFromParts}, or `undefined`\n * for any other path. */\nexport function derivedPartsOf(path: Path | null | undefined): readonly DerivedPart[] | undefined {\n return path == null ? undefined : PARTS.get(path);\n}\n\nfunction concatPaths(paths: readonly Path[]): PolygonPath {\n const polys = paths.map((p) => (p.kind === 'rect' ? cubicContoursToPath(pathToCubicContours(p)) : p));\n let commands = 0;\n let coords = 0;\n for (const p of polys) {\n commands += p.commands.length;\n coords += p.coords.length;\n }\n const out: PolygonPath = {\n kind: 'polygon',\n commands: new Uint8Array(commands),\n coords: new Float32Array(coords),\n fillRule: 'nonzero',\n };\n let ci = 0;\n let xi = 0;\n for (const p of polys) {\n out.commands.set(p.commands, ci);\n out.coords.set(p.coords, xi);\n ci += p.commands.length;\n xi += p.coords.length;\n }\n return out;\n}\n"],"mappings":";;;;;;;;;;;;;AAuBA,IAAM,wBAAQ,IAAI,QAAsC;;;;;AAMxD,SAAgB,cAAc,OAA4C;CACxE,IAAI,MAAM,WAAW,GAAG,OAAO;CAC/B,MAAM,QAAQ,MAAM,WAAW,IAAI,MAAM,EAAE,CAAE,OAAO,YAAY,MAAM,KAAK,MAAM,EAAE,IAAI,CAAC;CAGxF,MAAM,MAAM,UAAU,MAAM,EAAE,CAAE,OAAO,EAAE,GAAG,MAAM,IAAY;CAC9D,MAAM,IAAI,KAAK,KAAK;CACpB,OAAO;AACT;;;AAIA,SAAgB,eAAe,MAAmE;CAChG,OAAO,QAAQ,OAAO,SAAY,MAAM,IAAI,IAAI;AAClD;AAEA,SAAS,YAAY,OAAqC;CACxD,MAAM,QAAQ,MAAM,KAAK,MAAO,EAAE,SAAS,SAAS,oBAAoB,oBAAoB,CAAC,CAAC,IAAI,CAAE;CACpG,IAAI,WAAW;CACf,IAAI,SAAS;CACb,KAAK,MAAM,KAAK,OAAO;EACrB,YAAY,EAAE,SAAS;EACvB,UAAU,EAAE,OAAO;CACrB;CACA,MAAM,MAAmB;EACvB,MAAM;EACN,UAAU,IAAI,WAAW,QAAQ;EACjC,QAAQ,IAAI,aAAa,MAAM;EAC/B,UAAU;CACZ;CACA,IAAI,KAAK;CACT,IAAI,KAAK;CACT,KAAK,MAAM,KAAK,OAAO;EACrB,IAAI,SAAS,IAAI,EAAE,UAAU,EAAE;EAC/B,IAAI,OAAO,IAAI,EAAE,QAAQ,EAAE;EAC3B,MAAM,EAAE,SAAS;EACjB,MAAM,EAAE,OAAO;CACjB;CACA,OAAO;AACT"}
1
+ {"version":3,"file":"derivedParts.js","names":[],"sources":["../../../src/core/scene/derivedParts.ts"],"sourcesContent":["/**\n * A derived path that paints in several parts, each with its own fill and\n * stroke: the steps of a blend, the copies of a repeat.\n *\n * A derivation returns one `Path`, which is what picking, bounds and every\n * reader of `DerivedDep.path` see. {@link pathFromParts} makes that path out\n * of the parts and remembers the parts against it, so the derived-node\n * painter, handed the path, can paint each part as itself. The parts live as\n * long as the path does — in the derivation's memo.\n */\nimport type { InheritedPaint } from './inheritedPaint';\nimport { pathToCubicContours, cubicContoursToPath, type Path, type PolygonPath } from '@weasel-js/geom';\nimport {\n resolveFill, resolveStroke, type Fill, type Inherit, type PaintedFill, type PaintedStroke, type Stroke,\n} from '@weasel-js/paint';\n\n/** One painted piece of a derived path. */\nexport interface DerivedPart {\n path: Path;\n /** The part's fill, read as a node's is: absent paints none, and\n * `INHERIT` takes the node's own `data.fill`. */\n fill?: Fill | Inherit | null;\n /** The part's stroke, on the same terms as `fill`. */\n stroke?: Stroke | Inherit | null;\n}\n\n/** What `part` paints, its `INHERIT` taken from `own`, the deriving node's\n * data — whose own `INHERIT` takes `inherited`, its container's. */\nexport function resolvePartPaint(\n part: DerivedPart,\n own: { fill?: Fill | Inherit | null; stroke?: Stroke | Inherit | null } | null | undefined,\n inherited?: InheritedPaint,\n): { fill: PaintedFill | null; stroke: PaintedStroke | null } {\n return {\n fill: resolveFill(part.fill, resolveFill(own?.fill, inherited?.fill)),\n stroke: resolveStroke(part.stroke, resolveStroke(own?.stroke, inherited?.stroke)),\n };\n}\n\nconst PARTS = new WeakMap<Path, readonly DerivedPart[]>();\n\n/**\n * One path holding every part's outline, with the parts remembered against\n * it for the painter. Return it from a `derivePath`. `null` for no parts.\n */\nexport function pathFromParts(parts: readonly DerivedPart[]): Path | null {\n if (parts.length === 0) return null;\n const whole = parts.length === 1 ? parts[0]!.path : concatPaths(parts.map((p) => p.path));\n // A one-part path is the part's own, which another reader may hold; the\n // painter must not mistake that path for a painted one elsewhere.\n const key = whole === parts[0]!.path ? { ...whole } as Path : whole;\n PARTS.set(key, parts);\n return key;\n}\n\n/** The parts `path` was made from by {@link pathFromParts}, or `undefined`\n * for any other path. */\nexport function derivedPartsOf(path: Path | null | undefined): readonly DerivedPart[] | undefined {\n return path == null ? undefined : PARTS.get(path);\n}\n\nfunction concatPaths(paths: readonly Path[]): PolygonPath {\n const polys = paths.map((p) => (p.kind === 'rect' ? cubicContoursToPath(pathToCubicContours(p)) : p));\n let commands = 0;\n let coords = 0;\n for (const p of polys) {\n commands += p.commands.length;\n coords += p.coords.length;\n }\n const out: PolygonPath = {\n kind: 'polygon',\n commands: new Uint8Array(commands),\n coords: new Float32Array(coords),\n fillRule: 'nonzero',\n };\n let ci = 0;\n let xi = 0;\n for (const p of polys) {\n out.commands.set(p.commands, ci);\n out.coords.set(p.coords, xi);\n ci += p.commands.length;\n xi += p.coords.length;\n }\n return out;\n}\n"],"mappings":";;;;;;AA4BA,SAAgB,iBACd,MACA,KACA,WAC4D;CAC5D,OAAO;EACL,MAAM,YAAY,KAAK,MAAM,YAAY,KAAK,MAAM,WAAW,IAAI,CAAC;EACpE,QAAQ,cAAc,KAAK,QAAQ,cAAc,KAAK,QAAQ,WAAW,MAAM,CAAC;CAClF;AACF;AAEA,IAAM,wBAAQ,IAAI,QAAsC;;;;;AAMxD,SAAgB,cAAc,OAA4C;CACxE,IAAI,MAAM,WAAW,GAAG,OAAO;CAC/B,MAAM,QAAQ,MAAM,WAAW,IAAI,MAAM,EAAE,CAAE,OAAO,YAAY,MAAM,KAAK,MAAM,EAAE,IAAI,CAAC;CAGxF,MAAM,MAAM,UAAU,MAAM,EAAE,CAAE,OAAO,EAAE,GAAG,MAAM,IAAY;CAC9D,MAAM,IAAI,KAAK,KAAK;CACpB,OAAO;AACT;;;AAIA,SAAgB,eAAe,MAAmE;CAChG,OAAO,QAAQ,OAAO,SAAY,MAAM,IAAI,IAAI;AAClD;AAEA,SAAS,YAAY,OAAqC;CACxD,MAAM,QAAQ,MAAM,KAAK,MAAO,EAAE,SAAS,SAAS,oBAAoB,oBAAoB,CAAC,CAAC,IAAI,CAAE;CACpG,IAAI,WAAW;CACf,IAAI,SAAS;CACb,KAAK,MAAM,KAAK,OAAO;EACrB,YAAY,EAAE,SAAS;EACvB,UAAU,EAAE,OAAO;CACrB;CACA,MAAM,MAAmB;EACvB,MAAM;EACN,UAAU,IAAI,WAAW,QAAQ;EACjC,QAAQ,IAAI,aAAa,MAAM;EAC/B,UAAU;CACZ;CACA,IAAI,KAAK;CACT,IAAI,KAAK;CACT,KAAK,MAAM,KAAK,OAAO;EACrB,IAAI,SAAS,IAAI,EAAE,UAAU,EAAE;EAC/B,IAAI,OAAO,IAAI,EAAE,QAAQ,EAAE;EAC3B,MAAM,EAAE,SAAS;EACjB,MAAM,EAAE,OAAO;CACjB;CACA,OAAO;AACT"}
@@ -0,0 +1,57 @@
1
+ import { deepEqual } from "@weasel-js/registry";
2
+
3
+ //#region src/core/scene/docValues.ts
4
+ /**
5
+ * Document state that is not a node — a document's pages, its theme — held as
6
+ * named JSON values beside the tree, saved in its snapshot and undone with it.
7
+ */
8
+ var SET_DOC = "kit:setDoc";
9
+ function write(values, key, to) {
10
+ if (to === void 0) values.delete(key);
11
+ else values.set(key, to);
12
+ }
13
+ /** The snapshot side of a scene's document values, kept in `values`. */
14
+ function createDocStore(values) {
15
+ return {
16
+ /** The values as a snapshot holds them, or `undefined` when there are none. */
17
+ toJSON() {
18
+ return values.size === 0 ? void 0 : Object.fromEntries(values);
19
+ },
20
+ /** Replace every value, outside history. */
21
+ reset(next) {
22
+ values.clear();
23
+ for (const [key, value] of Object.entries(next ?? {})) write(values, key, value);
24
+ }
25
+ };
26
+ }
27
+ /** Register `kit:setDoc` and answer with the `SceneDoc` that records it. */
28
+ function createSceneDoc(env) {
29
+ const { values } = env;
30
+ env.register(SET_DOC, {
31
+ apply: (p) => {
32
+ const { key, to } = p;
33
+ write(values, key, to);
34
+ },
35
+ revert: (p) => {
36
+ const { key, from } = p;
37
+ write(values, key, from);
38
+ }
39
+ });
40
+ return {
41
+ get: (key) => values.get(key),
42
+ set(key, to) {
43
+ const from = values.get(key);
44
+ if (deepEqual(from, to)) return;
45
+ env.record(SET_DOC, {
46
+ key,
47
+ from,
48
+ to
49
+ }, "setDoc");
50
+ },
51
+ keys: () => [...values.keys()]
52
+ };
53
+ }
54
+
55
+ //#endregion
56
+ export { createDocStore, createSceneDoc };
57
+ //# sourceMappingURL=docValues.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docValues.js","names":[],"sources":["../../../src/core/scene/docValues.ts"],"sourcesContent":["/**\n * Document state that is not a node — a document's pages, its theme — held as\n * named JSON values beside the tree, saved in its snapshot and undone with it.\n */\nimport { deepEqual } from '@weasel-js/registry';\nimport type { RegisteredOp } from './types';\n\n/**\n * A scene's document values. Keys are namespaced by their owner\n * (`core:pages`, `diagram:theme`); values are JSON, and are not to be mutated\n * once set. A `set` is a scene edit: undoable, part of an enclosing `batch`,\n * skipped when the value is deep-equal to the current one, and heard by\n * `subscribe`. Setting `undefined` removes the key.\n */\nexport interface SceneDoc {\n get<T = unknown>(key: string): T | undefined;\n set(key: string, value: unknown): void;\n keys(): readonly string[];\n}\n\n/** The part of `Scene` that carries its document values. */\nexport interface SceneDocValues {\n readonly doc: SceneDoc;\n}\n\n/** A snapshot's document values. */\nexport type SerializedDoc = Readonly<Record<string, unknown>>;\n\n/** `undefined` on either side means the key is absent there. */\ninterface SetDocPayload { key: string; from?: unknown; to?: unknown }\n\nconst SET_DOC = 'kit:setDoc';\n\nfunction write(values: Map<string, unknown>, key: string, to: unknown): void {\n if (to === undefined) values.delete(key);\n else values.set(key, to);\n}\n\n/** The snapshot side of a scene's document values, kept in `values`. */\nexport function createDocStore(values: Map<string, unknown>) {\n return {\n /** The values as a snapshot holds them, or `undefined` when there are none. */\n toJSON(): SerializedDoc | undefined {\n return values.size === 0 ? undefined : Object.fromEntries(values);\n },\n /** Replace every value, outside history. */\n reset(next: SerializedDoc | undefined): void {\n values.clear();\n for (const [key, value] of Object.entries(next ?? {})) write(values, key, value);\n },\n };\n}\n\nexport interface SceneDocEnv {\n values: Map<string, unknown>;\n register(kind: string, handler: RegisteredOp<unknown>): void;\n record(kind: string, payload: unknown, label: string): void;\n}\n\n/** Register `kit:setDoc` and answer with the `SceneDoc` that records it. */\nexport function createSceneDoc(env: SceneDocEnv): SceneDoc {\n const { values } = env;\n env.register(SET_DOC, {\n apply: (p) => { const { key, to } = p as SetDocPayload; write(values, key, to); },\n revert: (p) => { const { key, from } = p as SetDocPayload; write(values, key, from); },\n });\n return {\n get: <T>(key: string) => values.get(key) as T | undefined,\n set(key, to) {\n const from = values.get(key);\n if (deepEqual(from, to)) return;\n env.record(SET_DOC, { key, from, to } satisfies SetDocPayload, 'setDoc');\n },\n keys: () => [...values.keys()],\n };\n}\n"],"mappings":";;;;;;;AA+BA,IAAM,UAAU;AAEhB,SAAS,MAAM,QAA8B,KAAa,IAAmB;CAC3E,IAAI,OAAO,QAAW,OAAO,OAAO,GAAG;MAClC,OAAO,IAAI,KAAK,EAAE;AACzB;;AAGA,SAAgB,eAAe,QAA8B;CAC3D,OAAO;;EAEL,SAAoC;GAClC,OAAO,OAAO,SAAS,IAAI,SAAY,OAAO,YAAY,MAAM;EAClE;;EAEA,MAAM,MAAuC;GAC3C,OAAO,MAAM;GACb,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,CAAC,CAAC,GAAG,MAAM,QAAQ,KAAK,KAAK;EACjF;CACF;AACF;;AASA,SAAgB,eAAe,KAA4B;CACzD,MAAM,EAAE,WAAW;CACnB,IAAI,SAAS,SAAS;EACpB,QAAQ,MAAM;GAAE,MAAM,EAAE,KAAK,OAAO;GAAoB,MAAM,QAAQ,KAAK,EAAE;EAAG;EAChF,SAAS,MAAM;GAAE,MAAM,EAAE,KAAK,SAAS;GAAoB,MAAM,QAAQ,KAAK,IAAI;EAAG;CACvF,CAAC;CACD,OAAO;EACL,MAAS,QAAgB,OAAO,IAAI,GAAG;EACvC,IAAI,KAAK,IAAI;GACX,MAAM,OAAO,OAAO,IAAI,GAAG;GAC3B,IAAI,UAAU,MAAM,EAAE,GAAG;GACzB,IAAI,OAAO,SAAS;IAAE;IAAK;IAAM;GAAG,GAA2B,QAAQ;EACzE;EACA,YAAY,CAAC,GAAG,OAAO,KAAK,CAAC;CAC/B;AACF"}
@@ -0,0 +1,111 @@
1
+ //#region src/core/scene/editPass.ts
2
+ var emptyCollecting = () => ({
3
+ added: /* @__PURE__ */ new Set(),
4
+ removed: /* @__PURE__ */ new Set(),
5
+ posed: /* @__PURE__ */ new Set(),
6
+ reparented: /* @__PURE__ */ new Set(),
7
+ dataChanged: /* @__PURE__ */ new Set(),
8
+ docChanged: /* @__PURE__ */ new Set()
9
+ });
10
+ var snapshot = (c) => ({
11
+ added: new Set(c.added),
12
+ removed: new Set(c.removed),
13
+ posed: new Set(c.posed),
14
+ reparented: new Set(c.reparented),
15
+ dataChanged: new Set(c.dataChanged),
16
+ docChanged: new Set(c.docChanged)
17
+ });
18
+ var NOOP = {
19
+ name: "editPass",
20
+ args: {},
21
+ elideNoop: true,
22
+ apply: () => "noop",
23
+ invert: () => NOOP
24
+ };
25
+ /** Note one kit op's ids into `into`. */
26
+ function noteInto(into, kind, payload) {
27
+ const p = payload;
28
+ switch (kind) {
29
+ case "kit:add":
30
+ into.added.add(p.id);
31
+ break;
32
+ case "kit:remove":
33
+ for (const n of p.nodes ?? []) into.removed.add(n.id);
34
+ break;
35
+ case "kit:setPose":
36
+ into.posed.add(p.id);
37
+ break;
38
+ case "kit:setData":
39
+ into.dataChanged.add(p.id);
40
+ break;
41
+ case "kit:setDoc":
42
+ into.docChanged.add(p.key);
43
+ break;
44
+ case "kit:move": if (p.fromParent !== p.toParent) into.reparented.add(p.id);
45
+ }
46
+ }
47
+ function createEditPasses(env) {
48
+ /** Sorted by order; equal orders keep the order they were added in. */
49
+ const passes = [];
50
+ let collecting = null;
51
+ function run() {
52
+ const summary = collecting;
53
+ if (summary === null) return 0;
54
+ let applied = 0;
55
+ try {
56
+ for (const { pass } of [...passes]) {
57
+ const ops = pass(snapshot(summary));
58
+ if (ops === null) continue;
59
+ const adapter = env.adapter();
60
+ for (const op of ops) {
61
+ op.apply(adapter);
62
+ applied++;
63
+ }
64
+ }
65
+ } finally {
66
+ collecting = null;
67
+ }
68
+ return applied;
69
+ }
70
+ return {
71
+ add(pass, opts) {
72
+ const entry = {
73
+ pass,
74
+ order: opts?.order ?? 0
75
+ };
76
+ const at = passes.findIndex((p) => p.order > entry.order);
77
+ passes.splice(at < 0 ? passes.length : at, 0, entry);
78
+ return () => {
79
+ const i = passes.indexOf(entry);
80
+ if (i >= 0) passes.splice(i, 1);
81
+ };
82
+ },
83
+ any: () => passes.length > 0,
84
+ open() {
85
+ if (collecting !== null || passes.length === 0) return false;
86
+ collecting = emptyCollecting();
87
+ return true;
88
+ },
89
+ note(kind, payload) {
90
+ if (collecting !== null && !env.untracked()) noteInto(collecting, kind, payload);
91
+ },
92
+ run,
93
+ abandon() {
94
+ collecting = null;
95
+ },
96
+ op() {
97
+ return {
98
+ name: "editPass",
99
+ args: {},
100
+ label: "Edit pass",
101
+ elideNoop: true,
102
+ apply: () => run() > 0 ? void 0 : "noop",
103
+ invert: () => NOOP
104
+ };
105
+ }
106
+ };
107
+ }
108
+
109
+ //#endregion
110
+ export { createEditPasses };
111
+ //# sourceMappingURL=editPass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editPass.js","names":[],"sources":["../../../src/core/scene/editPass.ts"],"sourcesContent":["/**\n * Scene edit passes: functions that hear what a live edit did, once its own\n * mutations and the arrival handler have run, and answer with ops that join\n * the same undo entry.\n *\n * Passes run by ascending order, and each hears the edit's own changes plus\n * every write the passes before it made. A pass still runs once per edit, so\n * none re-triggers itself or another. Undo, redo, and history replays never\n * run passes: they restore an edit whose passes already ran.\n */\nimport type { Op } from 'core/ops/types';\nimport type { NodeId } from './types';\n\n/** What one live edit did to the scene's nodes, by id. */\nexport interface SceneEditSummary {\n added: ReadonlySet<NodeId>;\n removed: ReadonlySet<NodeId>;\n posed: ReadonlySet<NodeId>;\n /** Nodes that changed parent. A reorder among siblings is not here. */\n reparented: ReadonlySet<NodeId>;\n dataChanged: ReadonlySet<NodeId>;\n /** The document-value keys (`scene.doc`) set. */\n docChanged: ReadonlySet<string>;\n}\n\n/** Where a pass runs among the others. */\nexport interface SceneEditPassOptions {\n /** Passes run by ascending order, ties in the order they were added.\n * Default 0. */\n order?: number;\n}\n\n/** A scene edit pass: the ops `summary`'s edit also makes, or null for none. */\nexport type SceneEditPass = (summary: SceneEditSummary) => readonly Op[] | null;\n\n/** The scene's edit-pass member. */\nexport interface SceneEditPasses {\n /** Add a pass that hears each live edit once its own mutations and the\n * arrival handler have run, and answers with ops that join the same undo\n * entry. A bare scene call runs as an edit of its own while any pass is\n * added. A pass hears what the passes ordered before it wrote, never what\n * it or a later one writes, and undo, redo, and history replays never run\n * it. Returns the pass's remover. */\n addEditPass(pass: SceneEditPass, opts?: SceneEditPassOptions): () => void;\n}\n\n/** What the passes need from the scene they serve. */\nexport interface EditPassEnv {\n /** The adapter a pass's ops apply through. */\n adapter(): unknown;\n /** Whether an edit made now is untracked, and so not summarized. */\n untracked(): boolean;\n}\n\nexport interface EditPasses {\n /** Add a pass after every one of its order or lower. Returns its remover. */\n add(pass: SceneEditPass, opts?: SceneEditPassOptions): () => void;\n /** Whether any pass is installed. */\n any(): boolean;\n /** Start summarizing an edit when a pass is installed and no enclosing edit\n * is summarizing already; true when this caller now owns the summary. */\n open(): boolean;\n /** Note what a live kit op is about to write. */\n note(kind: string, payload: unknown): void;\n /** Run every pass in order, each over the summary as it stands at its\n * turn, applying its ops into that summary; then close it. Answers how\n * many ops applied. */\n run(): number;\n /** Close the summary with nothing run. */\n abandon(): void;\n /** An op that runs the passes when it first applies, for the end of an\n * op-driven edit whose summary the caller owns. */\n op(): Op;\n}\n\ninterface Collecting {\n added: Set<NodeId>;\n removed: Set<NodeId>;\n posed: Set<NodeId>;\n reparented: Set<NodeId>;\n dataChanged: Set<NodeId>;\n docChanged: Set<string>;\n}\n\nconst emptyCollecting = (): Collecting => ({\n added: new Set(), removed: new Set(), posed: new Set(), reparented: new Set(), dataChanged: new Set(), docChanged: new Set(),\n});\n\nconst snapshot = (c: Collecting): SceneEditSummary => ({\n added: new Set(c.added),\n removed: new Set(c.removed),\n posed: new Set(c.posed),\n reparented: new Set(c.reparented),\n dataChanged: new Set(c.dataChanged),\n docChanged: new Set(c.docChanged),\n});\n\nconst NOOP: Op = { name: 'editPass', args: {}, elideNoop: true, apply: () => 'noop', invert: () => NOOP };\n\n/** Note one kit op's ids into `into`. */\nfunction noteInto(into: Collecting, kind: string, payload: unknown): void {\n const p = payload as { id?: NodeId; key?: string; nodes?: readonly { id: NodeId }[]; fromParent?: NodeId | null; toParent?: NodeId | null };\n switch (kind) {\n case 'kit:add': into.added.add(p.id!); break;\n case 'kit:remove': for (const n of p.nodes ?? []) into.removed.add(n.id); break;\n case 'kit:setPose': into.posed.add(p.id!); break;\n case 'kit:setData': into.dataChanged.add(p.id!); break;\n case 'kit:setDoc': into.docChanged.add(p.key!); break;\n case 'kit:move': if (p.fromParent !== p.toParent) into.reparented.add(p.id!); break;\n default: break;\n }\n}\n\nexport function createEditPasses(env: EditPassEnv): EditPasses {\n /** Sorted by order; equal orders keep the order they were added in. */\n const passes: { pass: SceneEditPass; order: number }[] = [];\n let collecting: Collecting | null = null;\n\n function run(): number {\n const summary = collecting;\n if (summary === null) return 0;\n let applied = 0;\n try {\n for (const { pass } of [...passes]) {\n const ops = pass(snapshot(summary));\n if (ops === null) continue;\n const adapter = env.adapter();\n for (const op of ops) {\n op.apply(adapter);\n applied++;\n }\n }\n } finally {\n collecting = null;\n }\n return applied;\n }\n\n return {\n add(pass, opts) {\n const entry = { pass, order: opts?.order ?? 0 };\n const at = passes.findIndex((p) => p.order > entry.order);\n passes.splice(at < 0 ? passes.length : at, 0, entry);\n return () => {\n const i = passes.indexOf(entry);\n if (i >= 0) passes.splice(i, 1);\n };\n },\n any: () => passes.length > 0,\n open() {\n if (collecting !== null || passes.length === 0) return false;\n collecting = emptyCollecting();\n return true;\n },\n note(kind, payload) {\n if (collecting !== null && !env.untracked()) noteInto(collecting, kind, payload);\n },\n run,\n abandon() {\n collecting = null;\n },\n op() {\n return {\n name: 'editPass',\n args: {},\n label: 'Edit pass',\n elideNoop: true,\n apply: () => (run() > 0 ? undefined : 'noop'),\n invert: () => NOOP,\n };\n },\n };\n}\n"],"mappings":";AAoFA,IAAM,yBAAqC;CACzC,uBAAO,IAAI,IAAI;CAAG,yBAAS,IAAI,IAAI;CAAG,uBAAO,IAAI,IAAI;CAAG,4BAAY,IAAI,IAAI;CAAG,6BAAa,IAAI,IAAI;CAAG,4BAAY,IAAI,IAAI;AAC7H;AAEA,IAAM,YAAY,OAAqC;CACrD,OAAO,IAAI,IAAI,EAAE,KAAK;CACtB,SAAS,IAAI,IAAI,EAAE,OAAO;CAC1B,OAAO,IAAI,IAAI,EAAE,KAAK;CACtB,YAAY,IAAI,IAAI,EAAE,UAAU;CAChC,aAAa,IAAI,IAAI,EAAE,WAAW;CAClC,YAAY,IAAI,IAAI,EAAE,UAAU;AAClC;AAEA,IAAM,OAAW;CAAE,MAAM;CAAY,MAAM,CAAC;CAAG,WAAW;CAAM,aAAa;CAAQ,cAAc;AAAK;;AAGxG,SAAS,SAAS,MAAkB,MAAc,SAAwB;CACxE,MAAM,IAAI;CACV,QAAQ,MAAR;EACE,KAAK;GAAW,KAAK,MAAM,IAAI,EAAE,EAAG;GAAG;EACvC,KAAK;GAAc,KAAK,MAAM,KAAK,EAAE,SAAS,CAAC,GAAG,KAAK,QAAQ,IAAI,EAAE,EAAE;GAAG;EAC1E,KAAK;GAAe,KAAK,MAAM,IAAI,EAAE,EAAG;GAAG;EAC3C,KAAK;GAAe,KAAK,YAAY,IAAI,EAAE,EAAG;GAAG;EACjD,KAAK;GAAc,KAAK,WAAW,IAAI,EAAE,GAAI;GAAG;EAChD,KAAK,YAAY,IAAI,EAAE,eAAe,EAAE,UAAU,KAAK,WAAW,IAAI,EAAE,EAAG;CAE7E;AACF;AAEA,SAAgB,iBAAiB,KAA8B;;CAE7D,MAAM,SAAmD,CAAC;CAC1D,IAAI,aAAgC;CAEpC,SAAS,MAAc;EACrB,MAAM,UAAU;EAChB,IAAI,YAAY,MAAM,OAAO;EAC7B,IAAI,UAAU;EACd,IAAI;GACF,KAAK,MAAM,EAAE,UAAU,CAAC,GAAG,MAAM,GAAG;IAClC,MAAM,MAAM,KAAK,SAAS,OAAO,CAAC;IAClC,IAAI,QAAQ,MAAM;IAClB,MAAM,UAAU,IAAI,QAAQ;IAC5B,KAAK,MAAM,MAAM,KAAK;KACpB,GAAG,MAAM,OAAO;KAChB;IACF;GACF;EACF,UAAU;GACR,aAAa;EACf;EACA,OAAO;CACT;CAEA,OAAO;EACL,IAAI,MAAM,MAAM;GACd,MAAM,QAAQ;IAAE;IAAM,OAAO,MAAM,SAAS;GAAE;GAC9C,MAAM,KAAK,OAAO,WAAW,MAAM,EAAE,QAAQ,MAAM,KAAK;GACxD,OAAO,OAAO,KAAK,IAAI,OAAO,SAAS,IAAI,GAAG,KAAK;GACnD,aAAa;IACX,MAAM,IAAI,OAAO,QAAQ,KAAK;IAC9B,IAAI,KAAK,GAAG,OAAO,OAAO,GAAG,CAAC;GAChC;EACF;EACA,WAAW,OAAO,SAAS;EAC3B,OAAO;GACL,IAAI,eAAe,QAAQ,OAAO,WAAW,GAAG,OAAO;GACvD,aAAa,gBAAgB;GAC7B,OAAO;EACT;EACA,KAAK,MAAM,SAAS;GAClB,IAAI,eAAe,QAAQ,CAAC,IAAI,UAAU,GAAG,SAAS,YAAY,MAAM,OAAO;EACjF;EACA;EACA,UAAU;GACR,aAAa;EACf;EACA,KAAK;GACH,OAAO;IACL,MAAM;IACN,MAAM,CAAC;IACP,OAAO;IACP,WAAW;IACX,aAAc,IAAI,IAAI,IAAI,SAAY;IACtC,cAAc;GAChB;EACF;CACF;AACF"}
@@ -86,6 +86,12 @@ function run(node, derive, deps, into) {
86
86
  function derivedDepOf(source, id, reader) {
87
87
  return reader === void 0 ? depIn(source, id, "effective") : depsAsRead(source, reader, "effective")(id);
88
88
  }
89
+ /** `id` as {@link derivedDepOf} answers it, but at the pose and path the
90
+ * document holds: no override anywhere down its dependencies counts. For a
91
+ * reader that must not see an in-flight gesture, such as an edit pass. */
92
+ function documentDepOf(source, id) {
93
+ return depIn(source, id, "document");
94
+ }
89
95
  /** `(id) => that dependency as `reader`'s derivation is handed it`: its pose
90
96
  * in `reader`'s frame where the scene composes frames. A `'children'`
91
97
  * dependent shares its children's frame, so it reads them as they are. */
@@ -189,9 +195,14 @@ function effectivePose(source, node) {
189
195
  * frame — and the composition fold passes over it.
190
196
  */
191
197
  function definesFrame(node) {
192
- return !(node.dependsOn === "children" && node.derivePose !== void 0);
198
+ return !isEnvelope(node);
199
+ }
200
+ /** Whether `node` derives its pose from its children: a group that is its
201
+ * members, so moving them moves it. */
202
+ function isEnvelope(node) {
203
+ return node.dependsOn === "children" && node.derivePose !== void 0;
193
204
  }
194
205
 
195
206
  //#endregion
196
- export { definesFrame, derivedDepOf, derivedPose, documentPose, effectivePose };
207
+ export { definesFrame, derivedDepOf, derivedPose, documentDepOf, documentPose, effectivePose, isEnvelope };
197
208
  //# sourceMappingURL=effectivePose.js.map