@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,5 +1,6 @@
1
- import { P as PlaneMap, S as SnapTarget, M as MoveAdapter } from './types-CHVXGfYm.js';
1
+ import { a as PlaneMap } from './types-7puAuVD2.js';
2
2
  import { Op } from '@weasel-js/history';
3
+ import { S as SnapTarget, M as MoveAdapter } from './types-oFeQ5VjV.js';
3
4
  import { FramedBox, View } from '@weasel-js/geom';
4
5
  import { KitSettingsStore } from '@weasel-js/react';
5
6
  import { ModifierState, ResizeAnchor } from '@weasel-js/routing';
@@ -140,29 +141,15 @@ interface BehaviorEnd {
140
141
  answered: boolean;
141
142
  }
142
143
  /**
143
- * Uniform group transform proposed by a gesture and shaped by behaviors.
144
- * Applied identically to every dragged id so a multi-select gesture cannot
145
- * drift apart. Only `'translate'` is wired end-to-end.
144
+ * The translation a drag proposes and its behaviors shape, applied identically
145
+ * to every dragged id so a multi-select gesture cannot drift apart. Resize and
146
+ * rotate behaviors answer in their own terms (`ResizeMoveResult`,
147
+ * `RotateMoveResult`), not through this.
146
148
  */
147
149
  type GroupTransform = {
148
150
  kind: 'translate';
149
151
  dx: number;
150
152
  dy: number;
151
- } | {
152
- kind: 'scale';
153
- pivot: {
154
- x: number;
155
- y: number;
156
- };
157
- sx: number;
158
- sy: number;
159
- } | {
160
- kind: 'rotate';
161
- pivot: {
162
- x: number;
163
- y: number;
164
- };
165
- angle: number;
166
153
  };
167
154
  /**
168
155
  * Per-frame result a `MoveBehavior.onMove` can return. `snap` announces a
@@ -202,8 +189,8 @@ interface MoveEnd extends BehaviorEnd {
202
189
  };
203
190
  }
204
191
  /** A behavior on a move — shapes the proposed transform during a drag.
205
- * Behaviors receive a `GroupTransform` (currently always `'translate'`) and
206
- * return a `BehaviorResult` shaping it. */
192
+ * Behaviors receive a `GroupTransform` and return a `BehaviorResult` shaping
193
+ * it. */
207
194
  type MoveBehavior<TPose> = ActionBehavior<TPose, GroupTransform, BehaviorResult<TPose>, MoveEnd>;
208
195
 
209
196
  /** Per-frame proposed resize: pose plus the anchor pinning the opposite corner. */
package/dist/clone.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- export { C as CloneBehavior, d as CloneBehaviorResult } from './clone-DZDrfIlU.js';
2
- import './types-CHVXGfYm.js';
3
- import '@weasel-js/history';
1
+ export { C as CloneBehavior, d as CloneBehaviorResult } from './clone-C3e0OTuF.js';
2
+ import './types-7puAuVD2.js';
4
3
  import '@weasel-js/geom';
4
+ import '@weasel-js/history';
5
+ import './types-oFeQ5VjV.js';
5
6
  import './poseDescriptor-DN2yfnq_.js';
6
7
  import '@weasel-js/animator';
7
8
  import '@weasel-js/react';
@@ -1,5 +1,5 @@
1
- import { pathPoseDescriptor } from "./pathPoseDescriptor.js";
2
1
  import { RECT_POSE_DESCRIPTOR } from "./poseDescriptor.js";
2
+ import { pathPoseDescriptor } from "./pathPoseDescriptor.js";
3
3
 
4
4
  //#region src/core/geometry/autoPoseDescriptor.ts
5
5
  /** True for Path-shaped poses (`{kind: 'polygon' | 'rect'}`). Useful for
@@ -0,0 +1,37 @@
1
+ import { registerOpFactory } from "./registry.js";
2
+
3
+ //#region src/core/ops/setDependsOn.ts
4
+ /** Op: set what a derived node's geometry derives from, inverting back to
5
+ * `from`. */
6
+ function createSetDependsOnOp(args) {
7
+ const { id, from, to, label, coalesceKey } = args;
8
+ return {
9
+ name: "setDependsOn",
10
+ args: {
11
+ id,
12
+ from,
13
+ to,
14
+ label,
15
+ coalesceKey
16
+ },
17
+ label,
18
+ coalesceKey,
19
+ apply(adapter) {
20
+ adapter.setDependsOn(id, to);
21
+ },
22
+ invert() {
23
+ return createSetDependsOnOp({
24
+ id,
25
+ from: to,
26
+ to: from,
27
+ label,
28
+ coalesceKey
29
+ });
30
+ }
31
+ };
32
+ }
33
+ registerOpFactory("setDependsOn", (args) => createSetDependsOnOp(args));
34
+
35
+ //#endregion
36
+ export { createSetDependsOnOp };
37
+ //# sourceMappingURL=setDependsOn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setDependsOn.js","names":[],"sources":["../../../src/core/ops/setDependsOn.ts"],"sourcesContent":["import type { Op } from './types';\nimport { registerOpFactory } from './registry';\n\ntype DependsOn = readonly string[] | 'children' | undefined;\n\ninterface SetDependsOnAdapter {\n setDependsOn(id: string, dependsOn: DependsOn): void;\n}\n\n/** Arguments to {@link createSetDependsOnOp}: retarget node `id`'s derivation\n * from the sources `from` to `to`. `undefined` is no derivation. */\nexport interface SetDependsOnArgs {\n id: string;\n from: DependsOn;\n to: DependsOn;\n label?: string;\n coalesceKey?: string;\n}\n\n/** Op: set what a derived node's geometry derives from, inverting back to\n * `from`. */\nexport function createSetDependsOnOp(args: SetDependsOnArgs): Op {\n const { id, from, to, label, coalesceKey } = args;\n return {\n name: 'setDependsOn',\n args: { id, from, to, label, coalesceKey },\n label,\n coalesceKey,\n apply(adapter) {\n (adapter as SetDependsOnAdapter).setDependsOn(id, to);\n },\n invert() {\n return createSetDependsOnOp({ id, from: to, to: from, label, coalesceKey });\n },\n };\n}\n\nregisterOpFactory<SetDependsOnArgs>('setDependsOn', (args) => createSetDependsOnOp(args));\n"],"mappings":";;;;;AAqBA,SAAgB,qBAAqB,MAA4B;CAC/D,MAAM,EAAE,IAAI,MAAM,IAAI,OAAO,gBAAgB;CAC7C,OAAO;EACL,MAAM;EACN,MAAM;GAAE;GAAI;GAAM;GAAI;GAAO;EAAY;EACzC;EACA;EACA,MAAM,SAAS;GACb,QAAiC,aAAa,IAAI,EAAE;EACtD;EACA,SAAS;GACP,OAAO,qBAAqB;IAAE;IAAI,MAAM;IAAI,IAAI;IAAM;IAAO;GAAY,CAAC;EAC5E;CACF;AACF;AAEA,kBAAoC,iBAAiB,SAAS,qBAAqB,IAAI,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { sceneMutators } from "../scene/sceneMutators.js";
2
+
3
+ //#region src/core/ops/writtenBy.ts
4
+ /**
5
+ * The pose and data `ops` leave each node they write, by id, read by applying
6
+ * them to a recorder rather than the scene; null when one cannot be read that
7
+ * way. A node only re-parented, re-layered, inserted, or removed is not in it.
8
+ */
9
+ function writtenBy(sc, ops) {
10
+ const after = /* @__PURE__ */ new Map();
11
+ const current = (id) => {
12
+ const node = after.get(id) ?? sc.get(id);
13
+ return node ? {
14
+ pose: node.pose,
15
+ data: node.data
16
+ } : null;
17
+ };
18
+ const write = (id, field, value) => {
19
+ const node = current(id);
20
+ if (node) after.set(id, {
21
+ ...node,
22
+ [field]: value
23
+ });
24
+ };
25
+ const reads = sceneMutators(sc);
26
+ const noop = () => {};
27
+ const recorder = {
28
+ ...reads,
29
+ setPose: (id, pose) => write(id, "pose", pose),
30
+ setData: (id, data) => write(id, "data", data),
31
+ setParent: noop,
32
+ setChildOrder: noop,
33
+ setLayer: noop,
34
+ setDependsOn: noop,
35
+ setLayout: noop,
36
+ setHidden: noop,
37
+ setLocked: noop,
38
+ removeNode: noop,
39
+ insertNode: noop,
40
+ getSelection: () => [...sc.getSelection()],
41
+ setSelection: noop
42
+ };
43
+ try {
44
+ for (const op of ops) op.apply(recorder);
45
+ } catch {
46
+ return null;
47
+ }
48
+ return after;
49
+ }
50
+
51
+ //#endregion
52
+ export { writtenBy };
53
+ //# sourceMappingURL=writtenBy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writtenBy.js","names":[],"sources":["../../../src/core/ops/writtenBy.ts"],"sourcesContent":["import { sceneMutators } from '../scene/sceneMutators';\nimport type { NodeId, Scene } from '../scene/types';\nimport type { Op } from './types';\n\n/** A node's pose and data, as a batch of ops leaves them. */\nexport interface WrittenNode {\n pose: unknown;\n data: unknown;\n}\n\n/**\n * The pose and data `ops` leave each node they write, by id, read by applying\n * them to a recorder rather than the scene; null when one cannot be read that\n * way. A node only re-parented, re-layered, inserted, or removed is not in it.\n */\nexport function writtenBy(sc: Scene<unknown, string, unknown>, ops: readonly Op[]): Map<string, WrittenNode> | null {\n const after = new Map<string, WrittenNode>();\n const current = (id: string): WrittenNode | null => {\n const node = after.get(id) ?? sc.get(id as NodeId);\n return node ? { pose: node.pose, data: node.data } : null;\n };\n const write = (id: string, field: keyof WrittenNode, value: unknown) => {\n const node = current(id);\n if (node) after.set(id, { ...node, [field]: value });\n };\n const reads = sceneMutators(sc);\n const noop = () => {};\n const recorder = {\n ...reads,\n setPose: (id: string, pose: unknown) => write(id, 'pose', pose),\n setData: (id: string, data: unknown) => write(id, 'data', data),\n setParent: noop, setChildOrder: noop, setLayer: noop, setDependsOn: noop, setLayout: noop,\n setHidden: noop, setLocked: noop, removeNode: noop, insertNode: noop,\n getSelection: (): string[] => [...sc.getSelection()],\n setSelection: noop,\n };\n try {\n for (const op of ops) op.apply(recorder);\n } catch {\n return null;\n }\n return after;\n}\n"],"mappings":";;;;;;;;AAeA,SAAgB,UAAU,IAAqC,KAAqD;CAClH,MAAM,wBAAQ,IAAI,IAAyB;CAC3C,MAAM,WAAW,OAAmC;EAClD,MAAM,OAAO,MAAM,IAAI,EAAE,KAAK,GAAG,IAAI,EAAY;EACjD,OAAO,OAAO;GAAE,MAAM,KAAK;GAAM,MAAM,KAAK;EAAK,IAAI;CACvD;CACA,MAAM,SAAS,IAAY,OAA0B,UAAmB;EACtE,MAAM,OAAO,QAAQ,EAAE;EACvB,IAAI,MAAM,MAAM,IAAI,IAAI;GAAE,GAAG;IAAO,QAAQ;EAAM,CAAC;CACrD;CACA,MAAM,QAAQ,cAAc,EAAE;CAC9B,MAAM,aAAa,CAAC;CACpB,MAAM,WAAW;EACf,GAAG;EACH,UAAU,IAAY,SAAkB,MAAM,IAAI,QAAQ,IAAI;EAC9D,UAAU,IAAY,SAAkB,MAAM,IAAI,QAAQ,IAAI;EAC9D,WAAW;EAAM,eAAe;EAAM,UAAU;EAAM,cAAc;EAAM,WAAW;EACrF,WAAW;EAAM,WAAW;EAAM,YAAY;EAAM,YAAY;EAChE,oBAA8B,CAAC,GAAG,GAAG,aAAa,CAAC;EACnD,cAAc;CAChB;CACA,IAAI;EACF,KAAK,MAAM,MAAM,KAAK,GAAG,MAAM,QAAQ;CACzC,QAAQ;EACN,OAAO;CACT;CACA,OAAO;AACT"}
@@ -1,4 +1,5 @@
1
1
  import { fitViewToBounds } from "../viewport/fitViewToBounds.js";
2
+ import { pageOfBounds } from "./pages.js";
2
3
 
3
4
  //#region src/core/pages/fitViewToPage.ts
4
5
  /** The view that shows one placed page whole: `fitViewToBounds` on its rect. */
@@ -11,7 +12,17 @@ function fitViewToPage(page, viewportDims, currentView, options) {
11
12
  height
12
13
  }, viewportDims, currentView, options);
13
14
  }
15
+ /** The page the view shows most of: the one overlapping the visible world rect most, or `null` when none shows. */
16
+ function pageInView(pages, view, viewportDims) {
17
+ const visible = {
18
+ x: view.x,
19
+ y: view.y,
20
+ width: viewportDims.width / view.scale.x,
21
+ height: viewportDims.height / view.scale.y
22
+ };
23
+ return pageOfBounds(pages, visible);
24
+ }
14
25
 
15
26
  //#endregion
16
- export { fitViewToPage };
27
+ export { fitViewToPage, pageInView };
17
28
  //# sourceMappingURL=fitViewToPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fitViewToPage.js","names":[],"sources":["../../../src/core/pages/fitViewToPage.ts"],"sourcesContent":["import {\n fitViewToBounds,\n type FitViewToBoundsOptions,\n type ViewportDims,\n} from '../viewport/fitViewToBounds';\nimport type { View } from '../viewport/view';\nimport type { PlacedPage } from './pages';\n\n/** The view that shows one placed page whole: `fitViewToBounds` on its rect. */\nexport function fitViewToPage(\n page: PlacedPage,\n viewportDims: ViewportDims,\n currentView: View,\n options?: FitViewToBoundsOptions,\n): View {\n const { x, y, width, height } = page;\n return fitViewToBounds({ x, y, width, height }, viewportDims, currentView, options);\n}\n"],"mappings":";;;;AASA,SAAgB,cACd,MACA,cACA,aACA,SACM;CACN,MAAM,EAAE,GAAG,GAAG,OAAO,WAAW;CAChC,OAAO,gBAAgB;EAAE;EAAG;EAAG;EAAO;CAAO,GAAG,cAAc,aAAa,OAAO;AACpF"}
1
+ {"version":3,"file":"fitViewToPage.js","names":[],"sources":["../../../src/core/pages/fitViewToPage.ts"],"sourcesContent":["import {\n fitViewToBounds,\n type FitViewToBoundsOptions,\n type ViewportDims,\n} from '../viewport/fitViewToBounds';\nimport type { View } from '../viewport/view';\nimport { pageOfBounds, type PlacedPage } from './pages';\n\n/** The view that shows one placed page whole: `fitViewToBounds` on its rect. */\nexport function fitViewToPage(\n page: PlacedPage,\n viewportDims: ViewportDims,\n currentView: View,\n options?: FitViewToBoundsOptions,\n): View {\n const { x, y, width, height } = page;\n return fitViewToBounds({ x, y, width, height }, viewportDims, currentView, options);\n}\n\n/** The page the view shows most of: the one overlapping the visible world rect most, or `null` when none shows. */\nexport function pageInView(\n pages: readonly PlacedPage[],\n view: View,\n viewportDims: ViewportDims,\n): PlacedPage | null {\n const visible = { x: view.x, y: view.y, width: viewportDims.width / view.scale.x, height: viewportDims.height / view.scale.y };\n return pageOfBounds(pages, visible);\n}\n"],"mappings":";;;;;AASA,SAAgB,cACd,MACA,cACA,aACA,SACM;CACN,MAAM,EAAE,GAAG,GAAG,OAAO,WAAW;CAChC,OAAO,gBAAgB;EAAE;EAAG;EAAG;EAAO;CAAO,GAAG,cAAc,aAAa,OAAO;AACpF;;AAGA,SAAgB,WACd,OACA,MACA,cACmB;CACnB,MAAM,UAAU;EAAE,GAAG,KAAK;EAAG,GAAG,KAAK;EAAG,OAAO,aAAa,QAAQ,KAAK,MAAM;EAAG,QAAQ,aAAa,SAAS,KAAK,MAAM;CAAE;CAC7H,OAAO,aAAa,OAAO,OAAO;AACpC"}
@@ -0,0 +1,163 @@
1
+ import { effectivePose, isEnvelope } from "../scene/effectivePose.js";
2
+ import { layoutPages, pageOfBounds } from "./pages.js";
3
+ import { RECT_POSE_DESCRIPTOR, poseDescriptorForNode, translatePoseViaDescriptor } from "../geometry/poseDescriptor.js";
4
+ import { carriedDescendants, sceneCarrySource } from "../scene/carryDescendants.js";
5
+
6
+ //#region src/core/pages/pageEdits.ts
7
+ /**
8
+ * A document's pages as a scene document value, and the edits that change
9
+ * them. Each edit moves the nodes on a page by however far the page itself
10
+ * moved, so what is on a page stays where it is on that page.
11
+ */
12
+ /** The scene document value key a page list lives under (`scene.doc`). */
13
+ var PAGES_DOC_KEY = "core:pages";
14
+ var asAny = (scene) => scene;
15
+ /** The scene's pages doc, or `null` when it has none. */
16
+ function pagesOf(scene) {
17
+ return scene.doc.get(PAGES_DOC_KEY) ?? null;
18
+ }
19
+ /** The scene's pages, placed in world space; empty when it has no pages doc. */
20
+ function placedPagesOf(scene) {
21
+ const doc = pagesOf(scene);
22
+ return doc ? layoutPages(doc.pages, doc.layout) : [];
23
+ }
24
+ /** An id none of `pages` has: `page-1`, `page-2`, and so on. */
25
+ function nextPageId(pages) {
26
+ const taken = new Set(pages.map((p) => p.id));
27
+ let n = 1;
28
+ while (taken.has(`page-${n}`)) n++;
29
+ return `page-${n}`;
30
+ }
31
+ /** Whether `id` draws from other nodes and goes wherever they go. */
32
+ function followsOthers(scene, id) {
33
+ const deps = scene.get(id)?.dependsOn;
34
+ return Array.isArray(deps) && deps.length > 0;
35
+ }
36
+ /**
37
+ * The root nodes on each placed page, by page id: each root belongs to the
38
+ * page its bounds overlap most (`pageOfBounds`). A root in the gaps belongs to
39
+ * none, and one that derives from other nodes is left out, since it follows
40
+ * them.
41
+ */
42
+ function pageMembers(scene, placed, descriptor = RECT_POSE_DESCRIPTOR) {
43
+ const s = asAny(scene);
44
+ const out = new Map(placed.map((p) => [p.id, []]));
45
+ for (const id of s.roots) {
46
+ const node = s.get(id);
47
+ if (!node || followsOthers(s, id)) continue;
48
+ const bounds = poseDescriptorForNode(descriptor, node).getBounds(effectivePose(s, node));
49
+ const page = pageOfBounds(placed, bounds);
50
+ if (page) out.get(page.id).push(id);
51
+ }
52
+ return out;
53
+ }
54
+ function derivesPose(scene, id) {
55
+ const node = scene.get(id);
56
+ return node !== void 0 && isEnvelope(node);
57
+ }
58
+ /** The stored poses that move root `id` and what it carries by `dx`, `dy`: the
59
+ * root, unless its pose derives from its children (then each child moves in
60
+ * its place), and the descendants it carries, less whatever derives its pose. */
61
+ function pageMoveWrites(scene, id, dx, dy, descriptor, out) {
62
+ const node = scene.get(id);
63
+ if (!node || followsOthers(scene, id)) return;
64
+ if (derivesPose(scene, id)) {
65
+ for (const child of scene.childrenOf(id)) pageMoveWrites(scene, child, dx, dy, descriptor, out);
66
+ return;
67
+ }
68
+ const move = (pose, at) => translatePoseViaDescriptor(pose, dx, dy, poseDescriptorForNode(descriptor, scene.get(at)));
69
+ out.push({
70
+ id,
71
+ pose: move(node.pose, id)
72
+ });
73
+ const carried = carriedDescendants(sceneCarrySource(scene), id, (world, at) => followsOthers(scene, at) || derivesPose(scene, at) ? null : move(world, at));
74
+ for (const [at, pose] of carried) out.push({
75
+ id: at,
76
+ pose
77
+ });
78
+ }
79
+ /**
80
+ * Replace the scene's pages doc with `next`, moving each page's members by
81
+ * the change in their page's place, all as one undo entry labeled `label`.
82
+ * Members of a page `next` drops are left where they are; `removePage` deletes
83
+ * them first.
84
+ */
85
+ function setPages(scene, next, label, options = {}) {
86
+ const s = asAny(scene);
87
+ const descriptor = options.descriptor ?? RECT_POSE_DESCRIPTOR;
88
+ const before = placedPagesOf(s);
89
+ const after = new Map(layoutPages(next.pages, next.layout).map((p) => [p.id, p]));
90
+ const members = pageMembers(s, before, descriptor);
91
+ const writes = [];
92
+ for (const page of before) {
93
+ const to = after.get(page.id);
94
+ if (!to) continue;
95
+ const dx = to.x - page.x;
96
+ const dy = to.y - page.y;
97
+ if (dx === 0 && dy === 0) continue;
98
+ for (const root of members.get(page.id) ?? []) pageMoveWrites(s, root, dx, dy, descriptor, writes);
99
+ }
100
+ s.batch(label, () => {
101
+ for (const { id, pose } of writes) s.setPose(id, pose);
102
+ s.doc.set(PAGES_DOC_KEY, next);
103
+ });
104
+ }
105
+ function edit(scene, fallback, options, change) {
106
+ const doc = pagesOf(scene) ?? { pages: [] };
107
+ setPages(scene, {
108
+ ...doc,
109
+ pages: change([...doc.pages])
110
+ }, options.label ?? fallback, options);
111
+ }
112
+ /** Insert `page` at `index`, by default after the last page. */
113
+ function addPage(scene, page, options = {}) {
114
+ edit(scene, "Add page", options, (pages) => {
115
+ pages.splice(options.index ?? pages.length, 0, page);
116
+ return pages;
117
+ });
118
+ }
119
+ /** Delete page `id`, what is on it, and every node that derives from that, as one entry. */
120
+ function removePage(scene, id, options = {}) {
121
+ const label = options.label ?? "Delete page";
122
+ const members = pageMembers(scene, placedPagesOf(scene), options.descriptor).get(id) ?? [];
123
+ scene.batch(label, () => {
124
+ if (members.length > 0) scene.removeMany(members);
125
+ edit(scene, label, {
126
+ ...options,
127
+ label
128
+ }, (pages) => pages.filter((p) => p.id !== id));
129
+ });
130
+ }
131
+ /** Move page `id` to `index` in the page order. */
132
+ function movePage(scene, id, index, options = {}) {
133
+ edit(scene, "Move page", options, (pages) => {
134
+ const at = pages.findIndex((p) => p.id === id);
135
+ if (at < 0) return pages;
136
+ const [page] = pages.splice(at, 1);
137
+ pages.splice(Math.max(0, Math.min(index, pages.length)), 0, page);
138
+ return pages;
139
+ });
140
+ }
141
+ /** Give page `id` a new size. Its members keep their places on it; the pages after it shift. */
142
+ function resizePage(scene, id, size, options = {}) {
143
+ edit(scene, "Resize page", options, (pages) => pages.map((p) => p.id === id ? {
144
+ ...p,
145
+ width: size.width,
146
+ height: size.height
147
+ } : p));
148
+ }
149
+ /** Rename page `id`; an empty name removes it. */
150
+ function renamePage(scene, id, name, options = {}) {
151
+ edit(scene, "Rename page", options, (pages) => pages.map((p) => {
152
+ if (p.id !== id) return p;
153
+ const { name: _old, ...rest } = p;
154
+ return name === "" ? rest : {
155
+ ...rest,
156
+ name
157
+ };
158
+ }));
159
+ }
160
+
161
+ //#endregion
162
+ export { PAGES_DOC_KEY, addPage, movePage, nextPageId, pageMembers, pagesOf, placedPagesOf, removePage, renamePage, resizePage, setPages };
163
+ //# sourceMappingURL=pageEdits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pageEdits.js","names":[],"sources":["../../../src/core/pages/pageEdits.ts"],"sourcesContent":["/**\n * A document's pages as a scene document value, and the edits that change\n * them. Each edit moves the nodes on a page by however far the page itself\n * moved, so what is on a page stays where it is on that page.\n */\nimport {\n RECT_POSE_DESCRIPTOR, poseDescriptorForNode, translatePoseViaDescriptor, type PoseDescriptor,\n} from '../geometry/poseDescriptor';\nimport { carriedDescendants, sceneCarrySource } from '../scene/carryDescendants';\nimport { effectivePose, isEnvelope } from '../scene/effectivePose';\nimport type { NodeId, Scene } from '../scene/types';\nimport { layoutPages, pageOfBounds, type Page, type PageLayoutOptions, type PlacedPage } from './pages';\n\n/** The document value under {@link PAGES_DOC_KEY}: the pages in order, and how they are laid out. */\nexport interface PagesDoc {\n readonly pages: readonly Page[];\n readonly layout?: PageLayoutOptions;\n}\n\n/** The scene document value key a page list lives under (`scene.doc`). */\nexport const PAGES_DOC_KEY = 'core:pages';\n\n/** Options every page edit takes. */\nexport interface PageEditOptions {\n /** The undo entry's label. */\n label?: string;\n /** How node poses are measured and moved. Default: poses are rects. */\n descriptor?: PoseDescriptor<unknown>;\n}\n\ntype AnyScene = Scene<unknown, string, unknown>;\nconst asAny = <TData, TLayer extends string, TPose>(scene: Scene<TData, TLayer, TPose>) =>\n scene as unknown as AnyScene;\n\n/** The scene's pages doc, or `null` when it has none. */\nexport function pagesOf<TData, TLayer extends string, TPose>(scene: Scene<TData, TLayer, TPose>): PagesDoc | null {\n return scene.doc.get<PagesDoc>(PAGES_DOC_KEY) ?? null;\n}\n\n/** The scene's pages, placed in world space; empty when it has no pages doc. */\nexport function placedPagesOf<TData, TLayer extends string, TPose>(scene: Scene<TData, TLayer, TPose>): PlacedPage[] {\n const doc = pagesOf(scene);\n return doc ? layoutPages(doc.pages, doc.layout) : [];\n}\n\n/** An id none of `pages` has: `page-1`, `page-2`, and so on. */\nexport function nextPageId(pages: readonly Page[]): string {\n const taken = new Set(pages.map((p) => p.id));\n let n = 1;\n while (taken.has(`page-${n}`)) n++;\n return `page-${n}`;\n}\n\n/** Whether `id` draws from other nodes and goes wherever they go. */\nfunction followsOthers(scene: AnyScene, id: NodeId): boolean {\n const deps = scene.get(id)?.dependsOn;\n return Array.isArray(deps) && deps.length > 0;\n}\n\n/**\n * The root nodes on each placed page, by page id: each root belongs to the\n * page its bounds overlap most (`pageOfBounds`). A root in the gaps belongs to\n * none, and one that derives from other nodes is left out, since it follows\n * them.\n */\nexport function pageMembers<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n placed: readonly PlacedPage[],\n descriptor: PoseDescriptor<unknown> = RECT_POSE_DESCRIPTOR as PoseDescriptor<unknown>,\n): Map<string, NodeId[]> {\n const s = asAny(scene);\n const out = new Map<string, NodeId[]>(placed.map((p) => [p.id, []]));\n for (const id of s.roots) {\n const node = s.get(id);\n if (!node || followsOthers(s, id)) continue;\n const bounds = poseDescriptorForNode(descriptor, node).getBounds(effectivePose(s, node));\n const page = pageOfBounds(placed, bounds);\n if (page) out.get(page.id)!.push(id);\n }\n return out;\n}\n\nfunction derivesPose(scene: AnyScene, id: NodeId): boolean {\n const node = scene.get(id);\n return node !== undefined && isEnvelope(node);\n}\n\n/** The stored poses that move root `id` and what it carries by `dx`, `dy`: the\n * root, unless its pose derives from its children (then each child moves in\n * its place), and the descendants it carries, less whatever derives its pose. */\nfunction pageMoveWrites(\n scene: AnyScene,\n id: NodeId,\n dx: number,\n dy: number,\n descriptor: PoseDescriptor<unknown>,\n out: { id: NodeId; pose: unknown }[],\n): void {\n const node = scene.get(id);\n if (!node || followsOthers(scene, id)) return;\n if (derivesPose(scene, id)) {\n for (const child of scene.childrenOf(id)) pageMoveWrites(scene, child, dx, dy, descriptor, out);\n return;\n }\n const move = (pose: unknown, at: NodeId) => translatePoseViaDescriptor(pose, dx, dy, poseDescriptorForNode(descriptor, scene.get(at)!));\n out.push({ id, pose: move(node.pose, id) });\n const carried = carriedDescendants(sceneCarrySource(scene), id, (world, at) => (\n followsOthers(scene, at) || derivesPose(scene, at) ? null : move(world, at)\n ));\n for (const [at, pose] of carried) out.push({ id: at, pose });\n}\n\n/**\n * Replace the scene's pages doc with `next`, moving each page's members by\n * the change in their page's place, all as one undo entry labeled `label`.\n * Members of a page `next` drops are left where they are; `removePage` deletes\n * them first.\n */\nexport function setPages<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n next: PagesDoc,\n label: string,\n options: Pick<PageEditOptions, 'descriptor'> = {},\n): void {\n const s = asAny(scene);\n const descriptor = options.descriptor ?? (RECT_POSE_DESCRIPTOR as PoseDescriptor<unknown>);\n const before = placedPagesOf(s);\n const after = new Map(layoutPages(next.pages, next.layout).map((p) => [p.id, p]));\n const members = pageMembers(s, before, descriptor);\n const writes: { id: NodeId; pose: unknown }[] = [];\n for (const page of before) {\n const to = after.get(page.id);\n if (!to) continue;\n const dx = to.x - page.x;\n const dy = to.y - page.y;\n if (dx === 0 && dy === 0) continue;\n for (const root of members.get(page.id) ?? []) pageMoveWrites(s, root, dx, dy, descriptor, writes);\n }\n s.batch(label, () => {\n for (const { id, pose } of writes) s.setPose(id, pose);\n s.doc.set(PAGES_DOC_KEY, next);\n });\n}\n\nfunction edit<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n fallback: string,\n options: PageEditOptions,\n change: (pages: Page[]) => Page[],\n): void {\n const doc = pagesOf(scene) ?? { pages: [] };\n setPages(scene, { ...doc, pages: change([...doc.pages]) }, options.label ?? fallback, options);\n}\n\n/** Insert `page` at `index`, by default after the last page. */\nexport function addPage<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n page: Page,\n options: PageEditOptions & { index?: number } = {},\n): void {\n edit(scene, 'Add page', options, (pages) => {\n pages.splice(options.index ?? pages.length, 0, page);\n return pages;\n });\n}\n\n/** Delete page `id`, what is on it, and every node that derives from that, as one entry. */\nexport function removePage<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n id: string,\n options: PageEditOptions = {},\n): void {\n const label = options.label ?? 'Delete page';\n const members = pageMembers(scene, placedPagesOf(scene), options.descriptor).get(id) ?? [];\n scene.batch(label, () => {\n if (members.length > 0) scene.removeMany(members);\n edit(scene, label, { ...options, label }, (pages) => pages.filter((p) => p.id !== id));\n });\n}\n\n/** Move page `id` to `index` in the page order. */\nexport function movePage<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n id: string,\n index: number,\n options: PageEditOptions = {},\n): void {\n edit(scene, 'Move page', options, (pages) => {\n const at = pages.findIndex((p) => p.id === id);\n if (at < 0) return pages;\n const [page] = pages.splice(at, 1);\n pages.splice(Math.max(0, Math.min(index, pages.length)), 0, page!);\n return pages;\n });\n}\n\n/** Give page `id` a new size. Its members keep their places on it; the pages after it shift. */\nexport function resizePage<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n id: string,\n size: { readonly width: number; readonly height: number },\n options: PageEditOptions = {},\n): void {\n edit(scene, 'Resize page', options, (pages) =>\n pages.map((p) => (p.id === id ? { ...p, width: size.width, height: size.height } : p)));\n}\n\n/** Rename page `id`; an empty name removes it. */\nexport function renamePage<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n id: string,\n name: string,\n options: PageEditOptions = {},\n): void {\n edit(scene, 'Rename page', options, (pages) => pages.map((p) => {\n if (p.id !== id) return p;\n const { name: _old, ...rest } = p;\n return name === '' ? rest : { ...rest, name };\n }));\n}\n"],"mappings":"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"}
@@ -33,6 +33,10 @@ function layoutPages(pages, options = {}) {
33
33
  return placed;
34
34
  });
35
35
  }
36
+ /** The name page `index` of the page order shows: its own, else "Page" and its place. */
37
+ function pageName(page, index) {
38
+ return page.name ?? `Page ${index + 1}`;
39
+ }
36
40
  /** The page under a world point, or `null` between and outside them. A point on an edge is on the page. */
37
41
  function pageAt(pages, point) {
38
42
  return pageOfBounds(pages, {
@@ -64,6 +68,31 @@ function pageOfBounds(pages, bounds) {
64
68
  }
65
69
  return best;
66
70
  }
71
+ function gap(page, b) {
72
+ const dx = Math.max(page.x - (b.x + b.width), b.x - (page.x + page.width), 0);
73
+ const dy = Math.max(page.y - (b.y + b.height), b.y - (page.y + page.height), 0);
74
+ return Math.hypot(dx, dy);
75
+ }
76
+ /**
77
+ * The page a world-space box is held by: the one it is on (`pageOfBounds`),
78
+ * else the one nearest it by the box-to-box gap, the earlier of two equally
79
+ * near. `null` only with no pages. Used where every object must land on some
80
+ * page, such as an export; `pageOfBounds` stays the rule for what is on one.
81
+ */
82
+ function pageHolding(pages, bounds) {
83
+ const on = pageOfBounds(pages, bounds);
84
+ if (on !== null) return on;
85
+ let best = null;
86
+ let least = Infinity;
87
+ for (const page of pages) {
88
+ const d = gap(page, bounds);
89
+ if (d < least) {
90
+ best = page;
91
+ least = d;
92
+ }
93
+ }
94
+ return best;
95
+ }
67
96
  /**
68
97
  * The page `step` places along the page order from the one with id `current`:
69
98
  * the next slide is `1`, the one before is `-1`. `null` past either end, unless
@@ -92,5 +121,5 @@ function pagesBounds(pages) {
92
121
  }
93
122
 
94
123
  //#endregion
95
- export { adjacentPage, layoutPages, pageAt, pageOfBounds, pagesBounds };
124
+ export { adjacentPage, layoutPages, pageAt, pageHolding, pageName, pageOfBounds, pagesBounds };
96
125
  //# sourceMappingURL=pages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pages.js","names":[],"sources":["../../../src/core/pages/pages.ts"],"sourcesContent":["import type { Bounds } from '@weasel-js/routing';\n\n/** One page of a document: a sheet of a fixed size, in world units. */\nexport interface Page {\n readonly id: string;\n readonly name?: string;\n readonly width: number;\n readonly height: number;\n}\n\n/** A page and where it sits in world space. */\nexport interface PlacedPage extends Page {\n readonly x: number;\n readonly y: number;\n /** Its place in the document's page order. */\n readonly index: number;\n}\n\n/** Options for {@link layoutPages}. */\nexport interface PageLayoutOptions {\n /** Which way the pages run. Default `'row'`. */\n direction?: 'row' | 'column';\n /** World units between neighbors. Default 40. */\n gap?: number;\n /** Where a page sits across the run, against the largest page. Default `'start'`. */\n align?: 'start' | 'center' | 'end';\n /** Where the first page's run starts. Default the world origin. */\n origin?: { readonly x: number; readonly y: number };\n}\n\nconst ALIGN = { start: 0, center: 0.5, end: 1 } as const;\n\n/**\n * Place a document's pages in one world space, in order, so a single scene,\n * view, and history serve all of them. With the defaults the first page's\n * top-left corner is the world origin, where a one-page document's page is.\n * Throws on two pages with one id.\n */\nexport function layoutPages(pages: readonly Page[], options: PageLayoutOptions = {}): PlacedPage[] {\n const { direction = 'row', gap = 40, align = 'start', origin = { x: 0, y: 0 } } = options;\n const row = direction === 'row';\n const across = Math.max(0, ...pages.map((p) => (row ? p.height : p.width)));\n const seen = new Set<string>();\n let along = 0;\n return pages.map((page, index) => {\n if (seen.has(page.id)) throw new Error(`layoutPages: two pages have the id \"${page.id}\"`);\n seen.add(page.id);\n const offset = (across - (row ? page.height : page.width)) * ALIGN[align];\n const placed = {\n ...page,\n x: origin.x + (row ? along : offset),\n y: origin.y + (row ? offset : along),\n index,\n };\n along += (row ? page.width : page.height) + gap;\n return placed;\n });\n}\n\n/** The page under a world point, or `null` between and outside them. A point on an edge is on the page. */\nexport function pageAt(\n pages: readonly PlacedPage[],\n point: { readonly x: number; readonly y: number },\n): PlacedPage | null {\n return pageOfBounds(pages, { x: point.x, y: point.y, width: 0, height: 0 });\n}\n\nfunction overlap(page: PlacedPage, b: Bounds): number | null {\n const w = Math.min(page.x + page.width, b.x + b.width) - Math.max(page.x, b.x);\n const h = Math.min(page.y + page.height, b.y + b.height) - Math.max(page.y, b.y);\n return w < 0 || h < 0 ? null : w * h;\n}\n\n/**\n * The page a world-space box belongs to: the one it overlaps most, the earlier\n * of two it overlaps equally, and `null` when it touches none. This is the\n * rule that says which page an object is on.\n */\nexport function pageOfBounds(pages: readonly PlacedPage[], bounds: Bounds): PlacedPage | null {\n let best: PlacedPage | null = null;\n let most = -1;\n for (const page of pages) {\n const area = overlap(page, bounds);\n if (area !== null && area > most) {\n best = page;\n most = area;\n }\n }\n return best;\n}\n\n/**\n * The page `step` places along the page order from the one with id `current`:\n * the next slide is `1`, the one before is `-1`. `null` past either end, unless\n * `wrap`. With no current page in the list, a step forward starts at the first\n * page and a step back at the last.\n */\nexport function adjacentPage(\n pages: readonly PlacedPage[],\n current: string | null,\n step: number,\n options: { wrap?: boolean } = {},\n): PlacedPage | null {\n const n = pages.length;\n if (n === 0) return null;\n const at = pages.findIndex((p) => p.id === current);\n if (at < 0) return pages[step < 0 ? n - 1 : 0] ?? null;\n const to = at + step;\n return pages[options.wrap ? ((to % n) + n) % n : to] ?? null;\n}\n\n/** The box around every page, or `null` for a document with none. */\nexport function pagesBounds(pages: readonly PlacedPage[]): Bounds | null {\n if (pages.length === 0) return null;\n const x = Math.min(...pages.map((p) => p.x));\n const y = Math.min(...pages.map((p) => p.y));\n return {\n x,\n y,\n width: Math.max(...pages.map((p) => p.x + p.width)) - x,\n height: Math.max(...pages.map((p) => p.y + p.height)) - y,\n };\n}\n"],"mappings":";AA8BA,IAAM,QAAQ;CAAE,OAAO;CAAG,QAAQ;CAAK,KAAK;AAAE;;;;;;;AAQ9C,SAAgB,YAAY,OAAwB,UAA6B,CAAC,GAAiB;CACjG,MAAM,EAAE,YAAY,OAAO,MAAM,IAAI,QAAQ,SAAS,SAAS;EAAE,GAAG;EAAG,GAAG;CAAE,MAAM;CAClF,MAAM,MAAM,cAAc;CAC1B,MAAM,SAAS,KAAK,IAAI,GAAG,GAAG,MAAM,KAAK,MAAO,MAAM,EAAE,SAAS,EAAE,KAAM,CAAC;CAC1E,MAAM,uBAAO,IAAI,IAAY;CAC7B,IAAI,QAAQ;CACZ,OAAO,MAAM,KAAK,MAAM,UAAU;EAChC,IAAI,KAAK,IAAI,KAAK,EAAE,GAAG,MAAM,IAAI,MAAM,uCAAuC,KAAK,GAAG,EAAE;EACxF,KAAK,IAAI,KAAK,EAAE;EAChB,MAAM,UAAU,UAAU,MAAM,KAAK,SAAS,KAAK,UAAU,MAAM;EACnE,MAAM,SAAS;GACb,GAAG;GACH,GAAG,OAAO,KAAK,MAAM,QAAQ;GAC7B,GAAG,OAAO,KAAK,MAAM,SAAS;GAC9B;EACF;EACA,UAAU,MAAM,KAAK,QAAQ,KAAK,UAAU;EAC5C,OAAO;CACT,CAAC;AACH;;AAGA,SAAgB,OACd,OACA,OACmB;CACnB,OAAO,aAAa,OAAO;EAAE,GAAG,MAAM;EAAG,GAAG,MAAM;EAAG,OAAO;EAAG,QAAQ;CAAE,CAAC;AAC5E;AAEA,SAAS,QAAQ,MAAkB,GAA0B;CAC3D,MAAM,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI,KAAK,IAAI,KAAK,GAAG,EAAE,CAAC;CAC7E,MAAM,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,QAAQ,EAAE,IAAI,EAAE,MAAM,IAAI,KAAK,IAAI,KAAK,GAAG,EAAE,CAAC;CAC/E,OAAO,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI;AACrC;;;;;;AAOA,SAAgB,aAAa,OAA8B,QAAmC;CAC5F,IAAI,OAA0B;CAC9B,IAAI,OAAO;CACX,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,OAAO,QAAQ,MAAM,MAAM;EACjC,IAAI,SAAS,QAAQ,OAAO,MAAM;GAChC,OAAO;GACP,OAAO;EACT;CACF;CACA,OAAO;AACT;;;;;;;AAQA,SAAgB,aACd,OACA,SACA,MACA,UAA8B,CAAC,GACZ;CACnB,MAAM,IAAI,MAAM;CAChB,IAAI,MAAM,GAAG,OAAO;CACpB,MAAM,KAAK,MAAM,WAAW,MAAM,EAAE,OAAO,OAAO;CAClD,IAAI,KAAK,GAAG,OAAO,MAAM,OAAO,IAAI,IAAI,IAAI,MAAM;CAClD,MAAM,KAAK,KAAK;CAChB,OAAO,MAAM,QAAQ,QAAS,KAAK,IAAK,KAAK,IAAI,OAAO;AAC1D;;AAGA,SAAgB,YAAY,OAA6C;CACvE,IAAI,MAAM,WAAW,GAAG,OAAO;CAC/B,MAAM,IAAI,KAAK,IAAI,GAAG,MAAM,KAAK,MAAM,EAAE,CAAC,CAAC;CAC3C,MAAM,IAAI,KAAK,IAAI,GAAG,MAAM,KAAK,MAAM,EAAE,CAAC,CAAC;CAC3C,OAAO;EACL;EACA;EACA,OAAO,KAAK,IAAI,GAAG,MAAM,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI;EACtD,QAAQ,KAAK,IAAI,GAAG,MAAM,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI;CAC1D;AACF"}
1
+ {"version":3,"file":"pages.js","names":[],"sources":["../../../src/core/pages/pages.ts"],"sourcesContent":["import type { Bounds } from '@weasel-js/routing';\n\n/** One page of a document: a sheet of a fixed size, in world units. */\nexport interface Page {\n readonly id: string;\n readonly name?: string;\n readonly width: number;\n readonly height: number;\n}\n\n/** A page and where it sits in world space. */\nexport interface PlacedPage extends Page {\n readonly x: number;\n readonly y: number;\n /** Its place in the document's page order. */\n readonly index: number;\n}\n\n/** Options for {@link layoutPages}. */\nexport interface PageLayoutOptions {\n /** Which way the pages run. Default `'row'`. */\n direction?: 'row' | 'column';\n /** World units between neighbors. Default 40. */\n gap?: number;\n /** Where a page sits across the run, against the largest page. Default `'start'`. */\n align?: 'start' | 'center' | 'end';\n /** Where the first page's run starts. Default the world origin. */\n origin?: { readonly x: number; readonly y: number };\n}\n\nconst ALIGN = { start: 0, center: 0.5, end: 1 } as const;\n\n/**\n * Place a document's pages in one world space, in order, so a single scene,\n * view, and history serve all of them. With the defaults the first page's\n * top-left corner is the world origin, where a one-page document's page is.\n * Throws on two pages with one id.\n */\nexport function layoutPages(pages: readonly Page[], options: PageLayoutOptions = {}): PlacedPage[] {\n const { direction = 'row', gap = 40, align = 'start', origin = { x: 0, y: 0 } } = options;\n const row = direction === 'row';\n const across = Math.max(0, ...pages.map((p) => (row ? p.height : p.width)));\n const seen = new Set<string>();\n let along = 0;\n return pages.map((page, index) => {\n if (seen.has(page.id)) throw new Error(`layoutPages: two pages have the id \"${page.id}\"`);\n seen.add(page.id);\n const offset = (across - (row ? page.height : page.width)) * ALIGN[align];\n const placed = {\n ...page,\n x: origin.x + (row ? along : offset),\n y: origin.y + (row ? offset : along),\n index,\n };\n along += (row ? page.width : page.height) + gap;\n return placed;\n });\n}\n\n/** The name page `index` of the page order shows: its own, else \"Page\" and its place. */\nexport function pageName(page: { readonly name?: string | undefined }, index: number): string {\n return page.name ?? `Page ${index + 1}`;\n}\n\n/** The page under a world point, or `null` between and outside them. A point on an edge is on the page. */\nexport function pageAt(\n pages: readonly PlacedPage[],\n point: { readonly x: number; readonly y: number },\n): PlacedPage | null {\n return pageOfBounds(pages, { x: point.x, y: point.y, width: 0, height: 0 });\n}\n\nfunction overlap(page: PlacedPage, b: Bounds): number | null {\n const w = Math.min(page.x + page.width, b.x + b.width) - Math.max(page.x, b.x);\n const h = Math.min(page.y + page.height, b.y + b.height) - Math.max(page.y, b.y);\n return w < 0 || h < 0 ? null : w * h;\n}\n\n/**\n * The page a world-space box belongs to: the one it overlaps most, the earlier\n * of two it overlaps equally, and `null` when it touches none. This is the\n * rule that says which page an object is on.\n */\nexport function pageOfBounds(pages: readonly PlacedPage[], bounds: Bounds): PlacedPage | null {\n let best: PlacedPage | null = null;\n let most = -1;\n for (const page of pages) {\n const area = overlap(page, bounds);\n if (area !== null && area > most) {\n best = page;\n most = area;\n }\n }\n return best;\n}\n\nfunction gap(page: PlacedPage, b: Bounds): number {\n const dx = Math.max(page.x - (b.x + b.width), b.x - (page.x + page.width), 0);\n const dy = Math.max(page.y - (b.y + b.height), b.y - (page.y + page.height), 0);\n return Math.hypot(dx, dy);\n}\n\n/**\n * The page a world-space box is held by: the one it is on (`pageOfBounds`),\n * else the one nearest it by the box-to-box gap, the earlier of two equally\n * near. `null` only with no pages. Used where every object must land on some\n * page, such as an export; `pageOfBounds` stays the rule for what is on one.\n */\nexport function pageHolding(pages: readonly PlacedPage[], bounds: Bounds): PlacedPage | null {\n const on = pageOfBounds(pages, bounds);\n if (on !== null) return on;\n let best: PlacedPage | null = null;\n let least = Infinity;\n for (const page of pages) {\n const d = gap(page, bounds);\n if (d < least) {\n best = page;\n least = d;\n }\n }\n return best;\n}\n\n/**\n * The page `step` places along the page order from the one with id `current`:\n * the next slide is `1`, the one before is `-1`. `null` past either end, unless\n * `wrap`. With no current page in the list, a step forward starts at the first\n * page and a step back at the last.\n */\nexport function adjacentPage(\n pages: readonly PlacedPage[],\n current: string | null,\n step: number,\n options: { wrap?: boolean } = {},\n): PlacedPage | null {\n const n = pages.length;\n if (n === 0) return null;\n const at = pages.findIndex((p) => p.id === current);\n if (at < 0) return pages[step < 0 ? n - 1 : 0] ?? null;\n const to = at + step;\n return pages[options.wrap ? ((to % n) + n) % n : to] ?? null;\n}\n\n/** The box around every page, or `null` for a document with none. */\nexport function pagesBounds(pages: readonly PlacedPage[]): Bounds | null {\n if (pages.length === 0) return null;\n const x = Math.min(...pages.map((p) => p.x));\n const y = Math.min(...pages.map((p) => p.y));\n return {\n x,\n y,\n width: Math.max(...pages.map((p) => p.x + p.width)) - x,\n height: Math.max(...pages.map((p) => p.y + p.height)) - y,\n };\n}\n"],"mappings":"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"}
@@ -202,6 +202,12 @@ function lerpColorArray(from, to, t, space = "rgb") {
202
202
  }
203
203
  return out;
204
204
  }
205
+ /** Linear-light channel to sRGB encoding (0..1). Unclamped. */
206
+ function linearToSrgb(c) {
207
+ const a = Math.abs(c);
208
+ const v = a <= .0031308 ? a * 12.92 : 1.055 * Math.pow(a, 1 / 2.4) - .055;
209
+ return c < 0 ? -v : v;
210
+ }
205
211
  /** HSL to sRGB. Hue in degrees, saturation, lightness and output all 0..1. */
206
212
  function hslToSrgb(h, s, l) {
207
213
  if (s === 0) return [
@@ -240,8 +246,9 @@ function hueToChannel(p, q, t) {
240
246
  * unitless in the modern syntax); same alpha rules and separator rules
241
247
  * as `rgb()`
242
248
  * - The 148 CSS named colors plus `transparent`
249
+ * - `color(srgb …)` and `color(srgb-linear …)`; `oklab()` and `oklch()`, clamped into sRGB
243
250
  *
244
- * Not supported: `oklch()`, `lab()`, `color()`, `currentColor`, system
251
+ * Not supported: `lab()`, `lch()`, other `color()` spaces, `currentColor`, system
245
252
  * colors. Throws on anything unrecognized.
246
253
  *
247
254
  * Results are cached by input-string identity. Callers MUST treat the
@@ -271,6 +278,14 @@ function parseColorUncached(input) {
271
278
  const parsed = parseHslFunction(lower);
272
279
  if (parsed) return parsed;
273
280
  }
281
+ if (lower.startsWith("color(")) {
282
+ const parsed = parseColorFunction(lower);
283
+ if (parsed) return parsed;
284
+ }
285
+ if (lower.startsWith("ok")) {
286
+ const parsed = parseOkFunction(lower);
287
+ if (parsed) return parsed;
288
+ }
274
289
  throw new Error(`parseColor: unrecognized color "${input}"`);
275
290
  }
276
291
  const RESOLVE_COLOR_CACHE_CAP = 1024;
@@ -399,7 +414,49 @@ function parseHslFunction(s) {
399
414
  parseAlpha(channels.alpha)
400
415
  ];
401
416
  }
402
- /** Parse a hue token: `<number>`, `<number>deg`, `<number>rad`, `<number>grad`, `<number>turn`. Returns degrees 0..360 (modulo). */
417
+ /** `color(srgb …)` or `color(srgb-linear …)`, channels as numbers 0..1 or percents. */
418
+ function parseColorFunction(s) {
419
+ const body = unwrapFn(s, "color");
420
+ const space = body?.match(/^(srgb-linear|srgb)\s+/);
421
+ if (!body || !space || body.includes(",")) return null;
422
+ const channels = splitChannels(body.slice(space[0].length));
423
+ if (!channels) return null;
424
+ const rgb = channels.rgb.map((tok) => parseChannel(tok, 1));
425
+ if (rgb.some((c) => c === null)) return null;
426
+ const [r, g, b] = space[1] === "srgb" ? rgb : rgb.map((c) => linearToSrgb(c));
427
+ return [
428
+ clamp01(r),
429
+ clamp01(g),
430
+ clamp01(b),
431
+ parseAlpha(channels.alpha)
432
+ ];
433
+ }
434
+ /** `oklab(L a b)` or `oklch(L C h)`, clamped into sRGB. L is 0..1 or a percent; a, b and C are numbers. */
435
+ function parseOkFunction(s) {
436
+ const lch = unwrapFn(s, "oklch");
437
+ const body = lch ?? unwrapFn(s, "oklab");
438
+ if (body === null || body.includes(",")) return null;
439
+ const channels = splitChannels(body);
440
+ if (!channels) return null;
441
+ const L = parsePercentOrNumber(channels.rgb[0]);
442
+ const second = Number(channels.rgb[1]);
443
+ if (L === null || !Number.isFinite(second)) return null;
444
+ let A = second;
445
+ let B = Number(channels.rgb[2]);
446
+ if (lch !== null) {
447
+ const h = parseHue(channels.rgb[2]);
448
+ if (h === null) return null;
449
+ [, A, B] = oklchToOklab(L, second, h * (Math.PI / 180));
450
+ } else if (!Number.isFinite(B)) return null;
451
+ const [r, g, b] = oklabToLinearSrgb(L, A, B).map((c) => clamp01(linearToSrgb(c)));
452
+ return [
453
+ r,
454
+ g,
455
+ b,
456
+ parseAlpha(channels.alpha)
457
+ ];
458
+ }
459
+ /** Parse a hue token:`<number>`, `<number>deg`, `<number>rad`, `<number>grad`, `<number>turn`. Returns degrees 0..360 (modulo). */
403
460
  function parseHue(tok) {
404
461
  let n;
405
462
  if (tok.endsWith("deg")) n = Number(tok.slice(0, -3));