@weasel-js/core 1.10.0 → 1.10.1
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.
- package/CHANGELOG.md +168 -0
- package/README.md +33 -0
- package/dist/affordances/composeAffordanceLayer.js +21 -21
- package/dist/affordances/composeAffordanceLayer.js.map +1 -1
- package/dist/affordances/hitAffordanceRegions.js +48 -32
- package/dist/affordances/hitAffordanceRegions.js.map +1 -1
- package/dist/affordances/pathAnchors.js +50 -28
- package/dist/affordances/pathAnchors.js.map +1 -1
- package/dist/affordances/rotateCursor.js +12 -0
- package/dist/affordances/rotateCursor.js.map +1 -0
- package/dist/affordances/rotationHandle.js +40 -43
- package/dist/affordances/rotationHandle.js.map +1 -1
- package/dist/animation/rig/rigNode.js +9 -3
- package/dist/animation/rig/rigNode.js.map +1 -1
- package/dist/animation/rig/rigSeat.js +46 -13
- package/dist/animation/rig/rigSeat.js.map +1 -1
- package/dist/animation/rig/skinBinding.js +22 -14
- package/dist/animation/rig/skinBinding.js.map +1 -1
- package/dist/barrel/canvas.js +29 -28
- package/dist/barrel/interactions.js +33 -32
- package/dist/barrel/paths.js +11 -10
- package/dist/barrel/routing.js +49 -48
- package/dist/barrel/scene.js +10 -10
- package/dist/barrel/viewport.js +24 -21
- package/dist/canvas/Canvas.js +6 -17
- package/dist/canvas/Canvas.js.map +1 -1
- package/dist/canvas/CanvasView.js +34 -37
- package/dist/canvas/CanvasView.js.map +1 -1
- package/dist/canvas/CursorCoordsHud.js +3 -3
- package/dist/canvas/CursorCoordsHud.js.map +1 -1
- package/dist/canvas/DrawCanvas.js +3 -3
- package/dist/canvas/DrawCanvas.js.map +1 -1
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +24 -23
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js.map +1 -1
- package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js +40 -49
- package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js +297 -259
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
- package/dist/canvas/SceneCanvas/features.js +3 -24
- package/dist/canvas/SceneCanvas/features.js.map +1 -1
- package/dist/canvas/SceneCanvas/insertPreviewCommands.js +97 -0
- package/dist/canvas/SceneCanvas/insertPreviewCommands.js.map +1 -0
- package/dist/canvas/SceneCanvas/poseGeometry.js.map +1 -1
- package/dist/canvas/SceneCanvas/props.js.map +1 -1
- package/dist/canvas/SceneCanvas/scenePointQuery.js +50 -0
- package/dist/canvas/SceneCanvas/scenePointQuery.js.map +1 -0
- package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js +52 -0
- package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js.map +1 -0
- package/dist/canvas/SceneCanvas/useActionTunings.js +17 -0
- package/dist/canvas/SceneCanvas/useActionTunings.js.map +1 -0
- package/dist/canvas/SceneCanvas/useCanvasCamera.js +37 -29
- package/dist/canvas/SceneCanvas/useCanvasCamera.js.map +1 -1
- package/dist/canvas/SceneCanvas/useCanvasDispatcher.js +11 -11
- package/dist/canvas/SceneCanvas/useCanvasDispatcher.js.map +1 -1
- package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js +45 -109
- package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js +49 -41
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js +64 -96
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
- package/dist/canvas/SceneCanvas/worldPointAt.js +3 -4
- package/dist/canvas/SceneCanvas/worldPointAt.js.map +1 -1
- package/dist/canvas/SceneCanvas.js +77 -80
- package/dist/canvas/SceneCanvas.js.map +1 -1
- package/dist/canvas/SceneViewCanvas.js +3 -3
- package/dist/canvas/SceneViewCanvas.js.map +1 -1
- package/dist/canvas/SurfaceCanvas.js +40 -0
- package/dist/canvas/SurfaceCanvas.js.map +1 -0
- package/dist/canvas/adapterDerivedPath.js +13 -13
- package/dist/canvas/adapterDerivedPath.js.map +1 -1
- package/dist/canvas/adapterPickSource.js +34 -0
- package/dist/canvas/adapterPickSource.js.map +1 -0
- package/dist/canvas/affordanceAt.js +1 -1
- package/dist/canvas/affordanceAt.js.map +1 -1
- package/dist/canvas/buildSceneLayer.js.map +1 -1
- package/dist/canvas/buildSceneTree.js +56 -34
- package/dist/canvas/buildSceneTree.js.map +1 -1
- package/dist/canvas/copiesAbove.js +27 -0
- package/dist/canvas/copiesAbove.js.map +1 -0
- package/dist/canvas/defaultDrawOne.js +24 -23
- package/dist/canvas/defaultDrawOne.js.map +1 -1
- package/dist/canvas/deps/editAnchors.js +45 -50
- package/dist/canvas/deps/editAnchors.js.map +1 -1
- package/dist/canvas/deps/hitTestArea.js +30 -15
- package/dist/canvas/deps/hitTestArea.js.map +1 -1
- package/dist/canvas/deps/insert.js +134 -100
- package/dist/canvas/deps/insert.js.map +1 -1
- package/dist/canvas/deps/layout.js +9 -15
- package/dist/canvas/deps/layout.js.map +1 -1
- package/dist/canvas/derivedPath.js +53 -29
- package/dist/canvas/derivedPath.js.map +1 -1
- package/dist/canvas/insertPreviewExtent.js +33 -31
- package/dist/canvas/insertPreviewExtent.js.map +1 -1
- package/dist/canvas/overChildren.js +29 -0
- package/dist/canvas/overChildren.js.map +1 -0
- package/dist/canvas/paintedCursorLayer.js.map +1 -1
- package/dist/canvas/pickReach.js +23 -0
- package/dist/canvas/pickReach.js.map +1 -0
- package/dist/canvas/pickWalk.js +51 -80
- package/dist/canvas/pickWalk.js.map +1 -1
- package/dist/canvas/sceneAdapter.js +14 -35
- package/dist/canvas/sceneAdapter.js.map +1 -1
- package/dist/canvas/sceneSlotWiring.js +11 -10
- package/dist/canvas/sceneSlotWiring.js.map +1 -1
- package/dist/canvas/sceneViewRender.js +38 -44
- package/dist/canvas/sceneViewRender.js.map +1 -1
- package/dist/canvas/useCanvasView.js +42 -44
- package/dist/canvas/useCanvasView.js.map +1 -1
- package/dist/canvas/useSceneAdapter.js +22 -0
- package/dist/canvas/useSceneAdapter.js.map +1 -0
- package/dist/canvas/useSurfaceInput.js +13 -16
- package/dist/canvas/useSurfaceInput.js.map +1 -1
- package/dist/canvas/viewRegistry.js +31 -23
- package/dist/canvas/viewRegistry.js.map +1 -1
- package/dist/canvas/wrapNodeOutput.js +7 -2
- package/dist/canvas/wrapNodeOutput.js.map +1 -1
- package/dist/clipboard.d.ts +1 -1
- package/dist/{clone-2a5hVbBd.d.ts → clone-C0eADtS0.d.ts} +13 -13
- package/dist/clone.d.ts +2 -2
- package/dist/core/geometry/poseDescriptor.js +49 -23
- package/dist/core/geometry/poseDescriptor.js.map +1 -1
- package/dist/core/geometry/regionHit.js +2 -2
- package/dist/core/geometry/regionHit.js.map +1 -1
- package/dist/core/geometry/targetFrame.js.map +1 -1
- package/dist/core/layers/children.js +1 -3
- package/dist/core/layers/children.js.map +1 -1
- package/dist/core/ops/create.js +2 -2
- package/dist/core/ops/create.js.map +1 -1
- package/dist/core/ops/delete.js +19 -23
- package/dist/core/ops/delete.js.map +1 -1
- package/dist/core/ops/reorder/index.js +3 -7
- package/dist/core/ops/reorder/index.js.map +1 -1
- package/dist/core/ops/reorder/setChildOrder.js +2 -4
- package/dist/core/ops/reorder/setChildOrder.js.map +1 -1
- package/dist/core/ops/reparent.js +0 -1
- package/dist/core/ops/reparent.js.map +1 -1
- package/dist/core/ops/slot.js +3 -6
- package/dist/core/ops/slot.js.map +1 -1
- package/dist/core/pages/fitViewToPage.js +15 -0
- package/dist/core/pages/fitViewToPage.js.map +1 -0
- package/dist/core/pages/pages.js +65 -0
- package/dist/core/pages/pages.js.map +1 -0
- package/dist/core/pages/pagesLayer.js +27 -0
- package/dist/core/pages/pagesLayer.js.map +1 -0
- package/dist/core/paint/meshKindLazy.js +2 -2
- package/dist/core/paint/meshKindLazy.js.map +1 -1
- package/dist/core/scene/NodeProperties.js.map +1 -1
- package/dist/core/scene/composeFrame.js.map +1 -1
- package/dist/core/scene/composePose.js +58 -20
- package/dist/core/scene/composePose.js.map +1 -1
- package/dist/core/scene/effectivePose.js +5 -1
- package/dist/core/scene/effectivePose.js.map +1 -1
- package/dist/core/scene/historyFacade.js +19 -13
- package/dist/core/scene/historyFacade.js.map +1 -1
- package/dist/core/scene/nodeFnFields.js +7 -0
- package/dist/core/scene/nodeFnFields.js.map +1 -1
- package/dist/core/scene/outerOps.js +2 -1
- package/dist/core/scene/outerOps.js.map +1 -1
- package/dist/core/scene/reconcileSpecs.js +1 -1
- package/dist/core/scene/reconcileSpecs.js.map +1 -1
- package/dist/core/scene/sceneRecording.js +2 -1
- package/dist/core/scene/sceneRecording.js.map +1 -1
- package/dist/core/scene/types.js.map +1 -1
- package/dist/core/viewport/screenSlop.js.map +1 -1
- package/dist/core/viewport/useDecayLoop.js +28 -30
- package/dist/core/viewport/useDecayLoop.js.map +1 -1
- package/dist/core/viewport/useNodeOverlayFrame.js.map +1 -1
- package/dist/core/viewport/useViewAnimation.js +70 -69
- package/dist/core/viewport/useViewAnimation.js.map +1 -1
- package/dist/core/viewport/view.js +8 -5
- package/dist/core/viewport/view.js.map +1 -1
- package/dist/core/viewport/zoomAt.js +11 -2
- package/dist/core/viewport/zoomAt.js.map +1 -1
- package/dist/{cornerHandles-BEshc4z3.d.ts → cornerHandles-BSKbyuvQ.d.ts} +1 -1
- package/dist/features/paths/editablePath.js +24 -8
- package/dist/features/paths/editablePath.js.map +1 -1
- package/dist/features/paths/index.js +4 -4
- package/dist/features/paths/shapeGenerator.js +89 -0
- package/dist/features/paths/shapeGenerator.js.map +1 -0
- package/dist/features/paths/usePathEdit.js +13 -13
- package/dist/features/poseRun/usePoseRun.js +25 -25
- package/dist/features/poseRun/usePoseRun.js.map +1 -1
- package/dist/features/text/useSceneTextEdit.js +82 -64
- package/dist/features/text/useSceneTextEdit.js.map +1 -1
- package/dist/features/viewports/viewResolver.js +28 -24
- package/dist/features/viewports/viewResolver.js.map +1 -1
- package/dist/icons/SliceIcon.js +24 -0
- package/dist/icons/SliceIcon.js.map +1 -0
- package/dist/index.d.ts +956 -581
- package/dist/index.js +260 -251
- package/dist/interactions/actions/align/align.js +9 -9
- package/dist/interactions/actions/align/align.js.map +1 -1
- package/dist/interactions/actions/booleans/booleans.js +18 -18
- package/dist/interactions/actions/booleans/booleans.js.map +1 -1
- package/dist/interactions/actions/booleans/operands.js.map +1 -1
- package/dist/interactions/actions/clone/action.js +35 -30
- package/dist/interactions/actions/clone/action.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorEditing.js +56 -59
- package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorHandles.js +42 -0
- package/dist/interactions/actions/defaults/anchorHandles.js.map +1 -0
- package/dist/interactions/actions/defaults/anchorJoin.js +92 -0
- package/dist/interactions/actions/defaults/anchorJoin.js.map +1 -0
- package/dist/interactions/actions/defaults/bendSegment.js +46 -0
- package/dist/interactions/actions/defaults/bendSegment.js.map +1 -0
- package/dist/interactions/actions/defaults/copySubtree.js +1 -1
- package/dist/interactions/actions/defaults/copySubtree.js.map +1 -1
- package/dist/interactions/actions/defaults/duplicate.js +32 -17
- package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
- package/dist/interactions/actions/defaults/enterPathEdit.js +19 -7
- package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/icons/anchorIcons.js +75 -0
- package/dist/interactions/actions/defaults/icons/anchorIcons.js.map +1 -0
- package/dist/interactions/actions/defaults/icons/editIcons.js +35 -8
- package/dist/interactions/actions/defaults/icons/editIcons.js.map +1 -1
- package/dist/interactions/actions/defaults/insertPathAnchor.js +16 -31
- package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
- package/dist/interactions/actions/defaults/nudge.js +28 -23
- package/dist/interactions/actions/defaults/nudge.js.map +1 -1
- package/dist/interactions/actions/defaults/pinchZoom.js +29 -29
- package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
- package/dist/interactions/actions/defaults/segmentUnder.js +22 -0
- package/dist/interactions/actions/defaults/segmentUnder.js.map +1 -0
- package/dist/interactions/actions/defaults/viewportZoom.js +82 -79
- package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
- package/dist/interactions/actions/distribute/distribute.js +8 -8
- package/dist/interactions/actions/distribute/distribute.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/action.js +58 -55
- package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/preview.js +26 -0
- package/dist/interactions/actions/edit-anchors/preview.js.map +1 -0
- package/dist/interactions/actions/edit-anchors/symmetry.js +11 -0
- package/dist/interactions/actions/edit-anchors/symmetry.js.map +1 -0
- package/dist/interactions/actions/flip/action.js.map +1 -1
- package/dist/interactions/actions/geometryProjection.js.map +1 -1
- package/dist/interactions/actions/insert/action.js +37 -30
- package/dist/interactions/actions/insert/action.js.map +1 -1
- package/dist/interactions/actions/insert/frame.js +9 -2
- package/dist/interactions/actions/insert/frame.js.map +1 -1
- package/dist/interactions/actions/insert/repositionAction.js +31 -0
- package/dist/interactions/actions/insert/repositionAction.js.map +1 -0
- package/dist/interactions/actions/lasso-select/action.js +32 -32
- package/dist/interactions/actions/move/action.js +29 -25
- package/dist/interactions/actions/move/action.js.map +1 -1
- package/dist/interactions/actions/move/behaviors/snapToContainer.js +12 -6
- package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
- package/dist/interactions/actions/move/capture.js +32 -23
- package/dist/interactions/actions/move/capture.js.map +1 -1
- package/dist/interactions/actions/move/frame.js +2 -14
- package/dist/interactions/actions/move/frame.js.map +1 -1
- package/dist/interactions/actions/move/session.js +1 -1
- package/dist/interactions/actions/move/session.js.map +1 -1
- package/dist/interactions/actions/move/translate.js.map +1 -1
- package/dist/interactions/actions/outlines/createOutlines.js.map +1 -1
- package/dist/interactions/actions/outlines/replaceWithPaths.js +13 -13
- package/dist/interactions/actions/outlines/replaceWithPaths.js.map +1 -1
- package/dist/interactions/actions/outlines/strokeRegion.js.map +1 -1
- package/dist/interactions/actions/pathCommands/cutJoin.js +102 -0
- package/dist/interactions/actions/pathCommands/cutJoin.js.map +1 -0
- package/dist/interactions/actions/pathCommands/livePathEdit.js +64 -0
- package/dist/interactions/actions/pathCommands/livePathEdit.js.map +1 -0
- package/dist/interactions/actions/pathCommands/pathNodes.js +99 -0
- package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -0
- package/dist/interactions/actions/pathCommands/simplifyOffset.js +42 -0
- package/dist/interactions/actions/pathCommands/simplifyOffset.js.map +1 -0
- package/dist/interactions/actions/resize/action.js +31 -20
- package/dist/interactions/actions/resize/action.js.map +1 -1
- package/dist/interactions/actions/resize/commit.js.map +1 -1
- package/dist/interactions/actions/resize/frame.js +29 -15
- package/dist/interactions/actions/resize/frame.js.map +1 -1
- package/dist/interactions/actions/resize/replay.js +47 -0
- package/dist/interactions/actions/resize/replay.js.map +1 -0
- package/dist/interactions/actions/resize/session.js +49 -35
- package/dist/interactions/actions/resize/session.js.map +1 -1
- package/dist/interactions/actions/resolveOverlays.js +2 -1
- package/dist/interactions/actions/resolveOverlays.js.map +1 -1
- package/dist/interactions/actions/rotate/action.js +40 -25
- package/dist/interactions/actions/rotate/action.js.map +1 -1
- package/dist/interactions/actions/rotate/frame.js +1 -1
- package/dist/interactions/actions/rotate/frame.js.map +1 -1
- package/dist/interactions/actions/rotate/replay.js +22 -0
- package/dist/interactions/actions/rotate/replay.js.map +1 -0
- package/dist/interactions/actions/rotate/session.js +42 -32
- package/dist/interactions/actions/rotate/session.js.map +1 -1
- package/dist/interactions/actions/transform-again/action.js +63 -0
- package/dist/interactions/actions/transform-again/action.js.map +1 -0
- package/dist/interactions/actions/transform-again/memory.js +35 -0
- package/dist/interactions/actions/transform-again/memory.js.map +1 -0
- package/dist/interactions/actions/useStandardActions.js +101 -83
- package/dist/interactions/actions/useStandardActions.js.map +1 -1
- package/dist/move.d.ts +4 -4
- package/dist/{originProjection-PPT88jZv.d.ts → originProjection-CoNVpITV.d.ts} +1 -1
- package/dist/resize.d.ts +3 -3
- package/dist/style.css +1 -1
- package/dist/tools/builtin/ellipse/useEllipseTool.js +16 -15
- package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
- package/dist/tools/builtin/line/useLineTool.js +16 -15
- package/dist/tools/builtin/line/useLineTool.js.map +1 -1
- package/dist/tools/builtin/pen/usePenTool.js +111 -111
- package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
- package/dist/tools/builtin/pickTopMostHit.js +11 -14
- package/dist/tools/builtin/pickTopMostHit.js.map +1 -1
- package/dist/tools/builtin/polygon/usePolygonTool.js +17 -15
- package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
- package/dist/tools/builtin/rect/useRectTool.js +15 -14
- package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
- package/dist/tools/builtin/select/adapterPointQuery.js +22 -18
- package/dist/tools/builtin/select/adapterPointQuery.js.map +1 -1
- package/dist/tools/builtin/select/selectionContributions.js +1 -1
- package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
- package/dist/tools/builtin/select/useSelectTool.js +2 -1
- package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
- package/dist/tools/builtin/slice/useSliceTool.js +42 -40
- package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
- package/dist/tools/builtin/star/useStarTool.js +18 -16
- package/dist/tools/builtin/star/useStarTool.js.map +1 -1
- package/dist/tools/builtin/text/useTextTool.js +2 -2
- package/dist/tools/builtin/text/useTextTool.js.map +1 -1
- package/dist/{types-CIKDwlsP.d.ts → types-DBbbCy0i.d.ts} +22 -15
- package/dist/version.js +1 -1
- package/package.json +22 -22
- package/dist/canvas/surface.module.js +0 -6
- package/dist/canvas/surface.module.js.map +0 -1
- package/dist/canvas/surfaceBox.js +0 -16
- package/dist/canvas/surfaceBox.js.map +0 -1
- package/dist/layout/arrivals.js +0 -33
- package/dist/layout/arrivals.js.map +0 -1
|
@@ -1,58 +1,96 @@
|
|
|
1
1
|
import { IDENTITY_POSE_COMPOSITION as e, composeWorldPose as t, composesFrames as n, frameAtOrAbove as r, rebaseLocalPose as i } from "./composeFrame.js";
|
|
2
|
+
import { applyToPoint as a, multiply as o, poseFrameInverseOf as s, poseFrameOf as c, poseLinearOf as l, rotate as u } from "@weasel-js/geom";
|
|
2
3
|
//#region src/core/scene/composePose.ts
|
|
3
|
-
function
|
|
4
|
+
function d(e, t) {
|
|
4
5
|
return {
|
|
5
6
|
...t,
|
|
6
7
|
x: e.x + t.x,
|
|
7
8
|
y: e.y + t.y
|
|
8
9
|
};
|
|
9
10
|
}
|
|
10
|
-
function
|
|
11
|
+
function f(e, t, n) {
|
|
11
12
|
return {
|
|
12
13
|
...e,
|
|
13
14
|
x: e.x + t,
|
|
14
15
|
y: e.y + n
|
|
15
16
|
};
|
|
16
17
|
}
|
|
17
|
-
function
|
|
18
|
+
function p(e, t) {
|
|
18
19
|
return {
|
|
19
20
|
...t,
|
|
20
21
|
x: t.x - e.x,
|
|
21
22
|
y: t.y - e.y
|
|
22
23
|
};
|
|
23
24
|
}
|
|
24
|
-
function
|
|
25
|
+
function m(e, t, n) {
|
|
26
|
+
let [r, i, a, s] = o(u(-t), n), c = Math.abs(r - 1) < 1e-12 && Math.abs(i) < 1e-12 && Math.abs(a) < 1e-12 && Math.abs(s - 1) < 1e-12, l = {
|
|
27
|
+
...e,
|
|
28
|
+
rotation: t
|
|
29
|
+
};
|
|
30
|
+
return c ? delete l.transform : l.transform = [
|
|
31
|
+
r,
|
|
32
|
+
i,
|
|
33
|
+
a,
|
|
34
|
+
s
|
|
35
|
+
], l;
|
|
36
|
+
}
|
|
37
|
+
function h(e, t, n) {
|
|
38
|
+
return {
|
|
39
|
+
...e,
|
|
40
|
+
x: t - e.width / 2,
|
|
41
|
+
y: n - e.height / 2
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
var g = [
|
|
45
|
+
1,
|
|
46
|
+
0,
|
|
47
|
+
0,
|
|
48
|
+
1,
|
|
49
|
+
0,
|
|
50
|
+
0
|
|
51
|
+
];
|
|
52
|
+
function _(e, t, n, r, i) {
|
|
25
53
|
let a = Math.cos(n), o = Math.sin(n);
|
|
26
54
|
return [e + (r - e) * a - (i - t) * o, t + (r - e) * o + (i - t) * a];
|
|
27
55
|
}
|
|
28
|
-
function
|
|
29
|
-
let n = e.rotation ?? 0,
|
|
56
|
+
function v(e, t) {
|
|
57
|
+
let n = e.rotation ?? 0, r = l(e) && c(e);
|
|
58
|
+
if (r) {
|
|
59
|
+
let [i, s] = a(r, e.x + t.x + t.width / 2, e.y + t.y + t.height / 2), l = o(r, c(t) ?? g);
|
|
60
|
+
return m(h(t, i, s), (t.rotation ?? 0) + n, l);
|
|
61
|
+
}
|
|
62
|
+
let [i, s] = _(e.x + e.width / 2, e.y + e.height / 2, n, e.x + t.x + t.width / 2, e.y + t.y + t.height / 2);
|
|
30
63
|
return {
|
|
31
64
|
...t,
|
|
32
|
-
x:
|
|
33
|
-
y:
|
|
65
|
+
x: i - t.width / 2,
|
|
66
|
+
y: s - t.height / 2,
|
|
34
67
|
rotation: (t.rotation ?? 0) + n
|
|
35
68
|
};
|
|
36
69
|
}
|
|
37
|
-
function
|
|
38
|
-
let n = e.rotation ?? 0,
|
|
70
|
+
function y(e, t) {
|
|
71
|
+
let n = e.rotation ?? 0, r = l(e) && s(e);
|
|
72
|
+
if (r) {
|
|
73
|
+
let [i, s] = a(r, t.x + t.width / 2, t.y + t.height / 2), l = o(r, c(t) ?? g);
|
|
74
|
+
return m(h(t, i - e.x, s - e.y), (t.rotation ?? 0) - n, l);
|
|
75
|
+
}
|
|
76
|
+
let [i, u] = _(e.x + e.width / 2, e.y + e.height / 2, -n, t.x + t.width / 2, t.y + t.height / 2);
|
|
39
77
|
return {
|
|
40
78
|
...t,
|
|
41
|
-
x:
|
|
42
|
-
y:
|
|
79
|
+
x: i - e.x - t.width / 2,
|
|
80
|
+
y: u - e.y - t.height / 2,
|
|
43
81
|
rotation: (t.rotation ?? 0) - n
|
|
44
82
|
};
|
|
45
83
|
}
|
|
46
|
-
var
|
|
47
|
-
compose:
|
|
48
|
-
decompose:
|
|
84
|
+
var b = {
|
|
85
|
+
compose: d,
|
|
86
|
+
decompose: p,
|
|
49
87
|
closure: "translation"
|
|
50
|
-
},
|
|
51
|
-
compose:
|
|
52
|
-
decompose:
|
|
88
|
+
}, x = {
|
|
89
|
+
compose: v,
|
|
90
|
+
decompose: y,
|
|
53
91
|
closure: "rigid"
|
|
54
92
|
};
|
|
55
|
-
function
|
|
93
|
+
function S(e, n) {
|
|
56
94
|
return (r) => {
|
|
57
95
|
try {
|
|
58
96
|
return t(e, r, n);
|
|
@@ -62,6 +100,6 @@ function p(e, n) {
|
|
|
62
100
|
};
|
|
63
101
|
}
|
|
64
102
|
//#endregion
|
|
65
|
-
export { e as IDENTITY_POSE_COMPOSITION,
|
|
103
|
+
export { e as IDENTITY_POSE_COMPOSITION, b as RECT_POSE_COMPOSITION, x as RIGID_POSE_COMPOSITION, d as composeRectPose, v as composeRigidPose, t as composeWorldPose, n as composesFrames, p as decomposeRectPose, y as decomposeRigidPose, r as frameAtOrAbove, i as rebaseLocalPose, f as translateRectPose, S as worldPoseLookup };
|
|
66
104
|
|
|
67
105
|
//# sourceMappingURL=composePose.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composePose.js","names":["composeRectPose","child","parent","translateRectPose","pose","dx","dy","decomposeRectPose","world","
|
|
1
|
+
{"version":3,"file":"composePose.js","names":["composeRectPose","child","parent","translateRectPose","pose","dx","dy","decomposeRectPose","world","withLinear","a","b","c","d","multiply","rotate","rotation","linear","plain","next","centeredAt","cx","cy","NO_FRAME","turn","r","s","x","y","composeRigidPose","pr","frame","poseLinearOf","poseFrameOf","applyToPoint","wcx","wcy","decomposeRigidPose","back","poseFrameInverseOf","ux","uy","RECT_POSE_COMPOSITION","RIGID_POSE_COMPOSITION","worldPoseLookup","composeWorldPose","adapter","id","compose","IDENTITY_POSE_COMPOSITION","composesFrames","frameAtOrAbove","rebaseLocalPose"],"sources":["../../../src/core/scene/composePose.ts"],"sourcesContent":["/**\n * Pose composition for hierarchical scene graphs.\n *\n * `getPose(id)` on adapters returns the **local** pose — relative to the\n * object's direct parent. Anything in the kit that needs world coordinates\n * routes through `composeWorldPose`, which folds local poses together via a\n * consumer-supplied `compose`.\n */\n\nimport { applyToPoint, multiply, poseFrameInverseOf, poseFrameOf, poseLinearOf, rotate, type Affine } from '@weasel-js/geom';\nimport type { RectPose } from 'core/scene/types';\nexport type { RectPose };\n\nimport {\n IDENTITY_POSE_COMPOSITION,\n composesFrames,\n composeWorldPose,\n frameAtOrAbove,\n rebaseLocalPose,\n type PoseAdapter,\n type PoseClosure,\n type PoseComposition,\n} from 'core/scene/composeFrame';\nexport { IDENTITY_POSE_COMPOSITION, composesFrames, composeWorldPose, frameAtOrAbove, rebaseLocalPose };\nexport type { PoseAdapter, PoseClosure, PoseComposition };\n\n/**\n * `compose` for axis-aligned rectangles under a translation-only hierarchy.\n * Adds translation; every other field is taken from the child unchanged.\n */\nexport function composeRectPose<TPose extends RectPose>(parent: TPose, child: TPose): TPose {\n return {\n ...child,\n x: parent.x + child.x,\n y: parent.y + child.y,\n };\n}\n\n/** Translate a `RectPose`-shaped pose by `(dx, dy)`; other fields are preserved. */\nexport function translateRectPose<TPose extends RectPose>(pose: TPose, dx: number, dy: number): TPose {\n return { ...pose, x: pose.x + dx, y: pose.y + dy };\n}\n\n/** Inverse of `composeRectPose` — subtracts parent translation. */\nexport function decomposeRectPose<TPose extends RectPose>(parent: TPose, world: TPose): TPose {\n return {\n ...world,\n x: world.x - parent.x,\n y: world.y - parent.y,\n };\n}\n\n/** `pose` with the linear part `linear` held as `rotation` and whatever is\n * left over as `transform`, which is dropped when nothing is. */\nfunction withLinear<TPose extends RectPose>(pose: TPose, rotation: number, linear: Affine): TPose {\n const [a, b, c, d] = multiply(rotate(-rotation), linear);\n const plain = Math.abs(a - 1) < 1e-12 && Math.abs(b) < 1e-12 && Math.abs(c) < 1e-12 && Math.abs(d - 1) < 1e-12;\n const next: RectPose = { ...pose, rotation };\n if (plain) delete next.transform;\n else next.transform = [a, b, c, d];\n return next as TPose;\n}\n\n/** `pose` moved so its box center is at `(cx, cy)`. */\nfunction centeredAt<TPose extends RectPose>(pose: TPose, cx: number, cy: number): TPose {\n return { ...pose, x: cx - pose.width / 2, y: cy - pose.height / 2 };\n}\n\nconst NO_FRAME: Affine = [1, 0, 0, 1, 0, 0];\n\n/** Turn `(x, y)` about `(cx, cy)` by `r` radians. */\nfunction turn(cx: number, cy: number, r: number, x: number, y: number): [number, number] {\n const c = Math.cos(r);\n const s = Math.sin(r);\n return [cx + (x - cx) * c - (y - cy) * s, cy + (x - cx) * s + (y - cy) * c];\n}\n\n/**\n * `compose` for a container whose pose defines a **frame**: the child's local\n * pose is offset into the parent's unrotated box, then the whole thing is\n * turned about the parent's center. Rotations add; the child keeps its size.\n *\n * Reduces to `composeRectPose` when the parent is upright. A parent's\n * `transform` composes too, and what the child's box and rotation cannot hold\n * of the result lands in the child's own `transform`.\n */\nexport function composeRigidPose<TPose extends RectPose>(parent: TPose, child: TPose): TPose {\n const pr = parent.rotation ?? 0;\n const frame = poseLinearOf(parent) && poseFrameOf(parent);\n if (frame) {\n const [cx, cy] = applyToPoint(frame, parent.x + child.x + child.width / 2, parent.y + child.y + child.height / 2);\n const linear = multiply(frame, poseFrameOf(child) ?? NO_FRAME);\n return withLinear(centeredAt(child, cx, cy), (child.rotation ?? 0) + pr, linear);\n }\n const [wcx, wcy] = turn(\n parent.x + parent.width / 2,\n parent.y + parent.height / 2,\n pr,\n parent.x + child.x + child.width / 2,\n parent.y + child.y + child.height / 2,\n );\n return {\n ...child,\n x: wcx - child.width / 2,\n y: wcy - child.height / 2,\n rotation: (child.rotation ?? 0) + pr,\n };\n}\n\n/** Inverse of `composeRigidPose` — un-turns about the parent's center, then\n * subtracts the parent's offset. */\nexport function decomposeRigidPose<TPose extends RectPose>(parent: TPose, world: TPose): TPose {\n const pr = parent.rotation ?? 0;\n // A singular transform has no inverse: the container draws nothing, and the turn alone is undone.\n const back = poseLinearOf(parent) && poseFrameInverseOf(parent);\n if (back) {\n const [ux, uy] = applyToPoint(back, world.x + world.width / 2, world.y + world.height / 2);\n const linear = multiply(back, poseFrameOf(world) ?? NO_FRAME);\n return withLinear(centeredAt(world, ux - parent.x, uy - parent.y), (world.rotation ?? 0) - pr, linear);\n }\n const [ux, uy] = turn(\n parent.x + parent.width / 2,\n parent.y + parent.height / 2,\n -pr,\n world.x + world.width / 2,\n world.y + world.height / 2,\n );\n return {\n ...world,\n x: ux - parent.x - world.width / 2,\n y: uy - parent.y - world.height / 2,\n rotation: (world.rotation ?? 0) - pr,\n };\n}\n\n/** Translation-only composition over `RectPose`. What a scene wants when a\n * container groups its children but never turns them. */\nexport const RECT_POSE_COMPOSITION: PoseComposition<RectPose> = {\n compose: composeRectPose,\n decompose: decomposeRectPose,\n closure: 'translation',\n};\n\n/** Composition over `RectPose` where a container's pose is a frame: rotating\n * the container rotates its contents. */\nexport const RIGID_POSE_COMPOSITION: PoseComposition<RectPose> = {\n compose: composeRigidPose,\n decompose: decomposeRigidPose,\n closure: 'rigid',\n};\n\n/**\n * Build a `(id) => world pose | null` callback over a `PoseAdapter`, for\n * RenderLayers that take a `getPose` callback.\n *\n * Returns `null` when `adapter.getPose` or `adapter.getParent` throws — the\n * common case is an id removed mid-render between selection state and the\n * next paint. Layers should treat `null` as \"skip this id.\"\n */\nexport function worldPoseLookup<TPose>(\n adapter: PoseAdapter<TPose>,\n compose: (parent: TPose, child: TPose) => TPose,\n): (id: string) => TPose | null {\n return (id: string) => {\n try {\n return composeWorldPose(adapter, id, compose);\n } catch {\n return null;\n }\n };\n}\n"],"mappings":"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"}
|
|
@@ -47,10 +47,14 @@ var g = class {
|
|
|
47
47
|
reading;
|
|
48
48
|
node;
|
|
49
49
|
pose;
|
|
50
|
+
shown;
|
|
50
51
|
constructor(e, t, n) {
|
|
51
|
-
this.source = e, this.posed = t, this.reading = n, this.node = t
|
|
52
|
+
this.source = e, this.posed = t, this.reading = n, this.node = t;
|
|
53
|
+
let r = n === "effective" ? e.overrides.read(t.id) : void 0;
|
|
54
|
+
this.shown = r?.path, this.pose = r?.pose ?? f(e, t, n) ?? t.pose;
|
|
52
55
|
}
|
|
53
56
|
get path() {
|
|
57
|
+
if (this.shown !== void 0) return this.shown;
|
|
54
58
|
let { source: e, reading: t } = this;
|
|
55
59
|
return o(this.posed, (n) => h(e, n, t), (t) => e.childrenOf(t), c[t]);
|
|
56
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effectivePose.js","names":["POSE_SLOT","PATH_SLOT","resolving","cycleHits","derivedPose","derivedPoseIn","source","node","derive","ids","dependencyIdsOf","hitsBefore","depOf","depIn","id","reading","computed","record","nodeMemo","run","emptyDepRecord","sameDeps","dropPoseKeyedMemoSlots","deriveRecorded","into","deps","handed","derivedDepOf","SceneDep","posed","poseIn","resolveDerivedPath","depId","override","documentPose","effectivePose","definesFrame"],"sources":["../../../src/core/scene/effectivePose.ts"],"sourcesContent":["/**\n * `effectivePose` — the pose to draw, pick and measure a node at.\n *\n * Three answers, in order: the ephemeral override a gesture published, the\n * pose the node derives from its dependencies, or the pose the document\n * stores. A reader of `node.pose` disagrees with the render about where a\n * dragged or derived node is.\n */\nimport { deriveRecorded, emptyDepRecord, sameDeps, type DepRecord } from './depMemo';\nimport { dependencyIdsOf } from './dependents';\nimport { resolveDerivedPath } from './derivedPath';\nimport { dropPoseKeyedMemoSlots, nodeMemo } from './nodeMemo';\nimport type { Path } from '@weasel-js/geom';\nimport type { DerivedDep, DerivePathFn, DerivePoseFn, Node, NodeId, PoseOverrides } from './types';\n\n/**\n * Which pose a resolution answers: `effective` honors overrides all the way\n * down the dependency chain, `document` ignores them all the way down. Each\n * reading memoizes in its own slots — the memo key is the node and its\n * authored pose, which is the same for both.\n */\ntype Reading = 'effective' | 'document';\n\nconst POSE_SLOT: Record<Reading, string> = {\n effective: 'kit:derivedPose',\n document: 'kit:derivedPose:document',\n};\nconst PATH_SLOT: Record<Reading, string | undefined> = {\n effective: undefined,\n document: 'kit:derivedPath:document',\n};\n\n/** The subset of a node this module reads. Structural so a `Node` satisfies\n * it without importing the full generic shape. */\nexport interface PosedNode<TPose> {\n id: NodeId;\n kind?: 'leaf' | 'container';\n pose: TPose;\n /** Read only by the memo, which keys on its reference alongside the pose. */\n data?: unknown;\n dependsOn?: readonly NodeId[] | 'children';\n derivePose?: DerivePoseFn<TPose>;\n /** Read only when something asks a dependency for its `path`. */\n derivePath?: DerivePathFn<TPose>;\n}\n\n/** What resolving a pose needs: the overrides, and enough of the scene to\n * reach a node's dependencies. A `Scene` satisfies it. */\nexport interface PoseSource<TPose> {\n readonly overrides: Pick<PoseOverrides<TPose>, 'read'>;\n get(id: NodeId): PosedNode<TPose> | undefined;\n childrenOf(id: NodeId): readonly NodeId[];\n}\n\n/** A cached derived pose, with what it was derived from. */\ninterface PoseMemo<TPose> extends DepRecord<TPose> {\n value: TPose | null;\n}\n\n/** Ids whose derivation is on the stack. A dependency graph is meant to be\n * acyclic and `dependsOn` is unvalidated, so a cycle resolves to the authored\n * pose at whichever node closes it rather than overflowing the stack. */\nconst resolving = new Set<NodeId>();\n\n/** Bumped each time the guard above fires. A derivation that closed a cycle\n * answered from a fallback rather than from its dependencies, so its value is\n * an artifact of which node was asked first and must not be cached. */\nlet cycleHits = 0;\n\n/**\n * The pose `node` computes from its dependencies, or `null` when it derives\n * nothing — it has no `derivePose`, nothing to derive from, or its\n * `derivePose` returned `null`.\n *\n * A dependency is read through {@link effectivePose}, so a group of groups\n * resolves bottom-up and a dragged dependency's override reaches the\n * derivation the same frame it is published.\n */\nexport function derivedPose<TPose>(\n source: PoseSource<TPose>,\n node: PosedNode<TPose>,\n): TPose | null {\n return derivedPoseIn(source, node, 'effective');\n}\n\nfunction derivedPoseIn<TPose>(\n source: PoseSource<TPose>,\n node: PosedNode<TPose>,\n reading: Reading,\n): TPose | null {\n const derive = node.derivePose;\n if (derive === undefined) return null;\n const ids = dependencyIdsOf(node, source.childrenOf);\n if (ids.length === 0) return null;\n if (resolving.has(node.id)) {\n cycleHits++;\n return null;\n }\n resolving.add(node.id);\n const hitsBefore = cycleHits;\n try {\n const depOf = (id: NodeId) => depIn(source, id, reading);\n // Keyed on the authored pose, which only sees a change someone pushed, so\n // the record also carries what the derivation read and re-checks it by\n // value on a hit — see `depMemo.ts`.\n let computed = false;\n const record = nodeMemo<PoseMemo<TPose>>(node, POSE_SLOT[reading], node.pose, () => {\n computed = true;\n return run(node, derive, ids.map(depOf), { ...emptyDepRecord<TPose>(), value: null });\n });\n // Mutating the record in place is what updates the memo slot, which holds\n // this object.\n if (!computed && !sameDeps(record, ids, depOf)) {\n run(node, derive, ids.map(depOf), record);\n }\n if (cycleHits !== hitsBefore) dropPoseKeyedMemoSlots(node);\n return record.value;\n } finally {\n resolving.delete(node.id);\n }\n}\n\n/** Run `derivePose` against `deps` and record what it was run against. */\nfunction run<TPose>(\n node: PosedNode<TPose>,\n derive: NonNullable<PosedNode<TPose>['derivePose']>,\n deps: readonly (DerivedDep<TPose> | undefined)[],\n into: PoseMemo<TPose>,\n): PoseMemo<TPose> {\n into.value = deriveRecorded(into, deps, (handed) => derive(node as never, handed));\n return into;\n}\n\n/**\n * `id` as a derivation sees it: the node, the pose it is painted at, and the\n * path it derives.\n *\n * The pose is resolved eagerly — every derivation reads it — and the path\n * lazily, because most do not and resolving a route costs a router run. Both\n * resolve *through* this function, so a dependency that is itself derived is\n * resolved before it is read.\n */\nexport function derivedDepOf<TPose>(\n source: PoseSource<TPose>,\n id: NodeId,\n): DerivedDep<TPose> | undefined {\n return depIn(source, id, 'effective');\n}\n\nfunction depIn<TPose>(\n source: PoseSource<TPose>,\n id: NodeId,\n reading: Reading,\n): DerivedDep<TPose> | undefined {\n const node = source.get(id);\n if (node === undefined) return undefined;\n return new SceneDep(source, node, reading);\n}\n\n/**\n * A class rather than an object literal with a `get path()`: one of these is\n * built per dependency per derived node per frame, and an own accessor costs\n * an order of magnitude more to define than a prototype one does to inherit.\n */\nclass SceneDep<TPose> implements DerivedDep<TPose> {\n readonly node: Node<unknown, string, TPose>;\n readonly pose: TPose;\n\n constructor(\n private readonly source: PoseSource<TPose>,\n private readonly posed: PosedNode<TPose>,\n private readonly reading: Reading,\n ) {\n this.node = posed as unknown as Node<unknown, string, TPose>;\n this.pose = poseIn(source, posed, reading);\n }\n\n get path(): Path | null {\n const { source, reading } = this;\n return resolveDerivedPath(\n this.posed,\n (depId) => depIn(source, depId, reading),\n (depId) => source.childrenOf(depId),\n PATH_SLOT[reading],\n );\n }\n}\n\nfunction poseIn<TPose>(\n source: PoseSource<TPose>,\n node: PosedNode<TPose>,\n reading: Reading,\n): TPose {\n if (reading === 'effective') {\n const override = source.overrides.read(node.id)?.pose;\n if (override !== undefined) return override;\n }\n return derivedPoseIn(source, node, reading) ?? node.pose;\n}\n\n/**\n * The pose the *document* says `node` is at: derived when it derives, else\n * authored. `effectivePose` minus the override step, at every link of the\n * dependency chain — a derived node's document pose holds still while\n * something it derives from is being dragged.\n *\n * For a reader that must not see an in-flight gesture, such as an action\n * capturing the `from` of a transform op.\n */\nexport function documentPose<TPose>(\n source: PoseSource<TPose>,\n node: PosedNode<TPose>,\n): TPose {\n return poseIn(source, node, 'document');\n}\n\n/**\n * The pose to draw, pick and measure `node` at. Every pose a reader acts on\n * comes from here.\n */\nexport function effectivePose<TPose>(\n source: PoseSource<TPose>,\n node: PosedNode<TPose>,\n): TPose {\n return poseIn(source, node, 'effective');\n}\n\n/**\n * Whether `node`'s pose is a frame its children are expressed in, under a\n * composing strategy.\n *\n * A container that derives its pose from its children cannot be one: moving\n * the frame to cover the children would move the children, and a `RectPose`\n * frame's origin is its corner, so no envelope leaves them in place. Such a\n * container is an envelope instead — its children are stored in its own\n * frame — and the composition fold passes over it.\n */\nexport function definesFrame(node: { dependsOn?: unknown; derivePose?: unknown }): boolean {\n return !(node.dependsOn === 'children' && node.derivePose !== undefined);\n}\n"],"mappings":";;;;;AAuBA,IAAMA,IAAqC;CACzC,WAAW;CACX,UAAU;AACZ,GACMC,IAAiD;CACrD,WAAW,KAAA;CACX,UAAU;AACZ,GAgCMC,oBAAY,IAAI,IAAY,GAK9BC,IAAY;AAWhB,SAAgBC,EACd,GACA,GACc;CACd,OAAOC,EAAcC,GAAQC,GAAM,WAAW;AAChD;AAEA,SAASF,EACP,GACA,GACA,GACc;CACd,IAAMG,IAASD,EAAK;CACpB,IAAIC,MAAW,KAAA,GAAW,OAAO;CACjC,IAAMC,IAAMC,EAAgBH,GAAMD,EAAO,UAAU;CACnD,IAAIG,EAAI,WAAW,GAAG,OAAO;CAC7B,IAAIP,EAAU,IAAIK,EAAK,EAAE,GAEvB,OADA,KACO;CAET,EAAU,IAAIA,EAAK,EAAE;CACrB,IAAMI,IAAaR;CACnB,IAAI;EACF,IAAMS,KAAS,MAAeC,EAAMP,GAAQQ,GAAIC,CAAO,GAInDC,IAAW,IACTC,IAASC,EAA0BX,GAAMP,EAAUe,IAAUR,EAAK,aACtE,IAAW,IACJY,EAAIZ,GAAMC,GAAQC,EAAI,IAAIG,CAAK,GAAG;GAAE,GAAGQ,EAAsB;GAAG,OAAO;EAAK,CAAC,EACrF;EAOD,OAJI,CAACJ,KAAY,CAACK,EAASJ,GAAQR,GAAKG,CAAK,KAC3CO,EAAIZ,GAAMC,GAAQC,EAAI,IAAIG,CAAK,GAAGK,CAAM,GAEtCd,MAAcQ,KAAYW,EAAuBf,CAAI,GAClDU,EAAO;CAChB,UAAU;EACR,EAAU,OAAOV,EAAK,EAAE;CAC1B;AACF;AAGA,SAASY,EACP,GACA,GACA,GACA,GACiB;CAEjB,OADA,EAAK,QAAQI,EAAeC,GAAMC,IAAO,MAAWjB,EAAOD,GAAemB,CAAM,CAAC,GAC1EF;AACT;AAWA,SAAgBG,EACd,GACA,GAC+B;CAC/B,OAAOd,EAAMP,GAAQQ,GAAI,WAAW;AACtC;AAEA,SAASD,EACP,GACA,GACA,GAC+B;CAC/B,IAAMN,IAAOD,EAAO,IAAIQ,CAAE;CAC1B,IAAIP,MAAS,KAAA,GACb,OAAO,IAAIqB,EAAStB,GAAQC,GAAMQ,CAAO;AAC3C;AAOA,IAAMa,IAAN,MAAmD;CAK9B;CACA;CACA;CANnB;CACA;CAEA,YACE,GACA,GACA,GACA;EAEA,AALiB,KAAA,SAAAtB,GACA,KAAA,QAAAuB,GACA,KAAA,UAAAd,GAEjB,KAAK,OAAOc,GACZ,KAAK,OAAOC,EAAOxB,GAAQuB,GAAOd,CAAO;CAC3C;CAEA,IAAI,OAAoB;EACtB,IAAM,EAAE,WAAQ,eAAY;EAC5B,OAAOgB,EACL,KAAK,QACJ,MAAUlB,EAAMP,GAAQ0B,GAAOjB,CAAO,IACtC,MAAUT,EAAO,WAAW0B,CAAK,GAClC/B,EAAUc,EACZ;CACF;AACF;AAEA,SAASe,EACP,GACA,GACA,GACO;CACP,IAAIf,MAAY,aAAa;EAC3B,IAAMkB,IAAW3B,EAAO,UAAU,KAAKC,EAAK,EAAE,CAAC,EAAE;EACjD,IAAI0B,MAAa,KAAA,GAAW,OAAOA;CACrC;CACA,OAAO5B,EAAcC,GAAQC,GAAMQ,CAAO,KAAKR,EAAK;AACtD;AAWA,SAAgB2B,EACd,GACA,GACO;CACP,OAAOJ,EAAOxB,GAAQC,GAAM,UAAU;AACxC;AAMA,SAAgB4B,EACd,GACA,GACO;CACP,OAAOL,EAAOxB,GAAQC,GAAM,WAAW;AACzC;AAYA,SAAgB6B,EAAa,GAA8D;CACzF,OAAS7B,EAAK,cAAc,cAAcA,EAAK,eAAe,KAAA;AAChE"}
|
|
1
|
+
{"version":3,"file":"effectivePose.js","names":["POSE_SLOT","PATH_SLOT","resolving","cycleHits","derivedPose","derivedPoseIn","source","node","derive","ids","dependencyIdsOf","hitsBefore","depOf","depIn","id","reading","computed","record","nodeMemo","run","emptyDepRecord","sameDeps","dropPoseKeyedMemoSlots","deriveRecorded","into","deps","handed","derivedDepOf","SceneDep","posed","override","resolveDerivedPath","depId","poseIn","documentPose","effectivePose","definesFrame"],"sources":["../../../src/core/scene/effectivePose.ts"],"sourcesContent":["/**\n * `effectivePose` — the pose to draw, pick and measure a node at.\n *\n * Three answers, in order: the ephemeral override a gesture published, the\n * pose the node derives from its dependencies, or the pose the document\n * stores. A reader of `node.pose` disagrees with the render about where a\n * dragged or derived node is.\n */\nimport { deriveRecorded, emptyDepRecord, sameDeps, type DepRecord } from './depMemo';\nimport { dependencyIdsOf } from './dependents';\nimport { resolveDerivedPath } from './derivedPath';\nimport { dropPoseKeyedMemoSlots, nodeMemo } from './nodeMemo';\nimport type { Path } from '@weasel-js/geom';\nimport type { DerivedDep, DerivePathFn, DerivePoseFn, Node, NodeId, PoseOverrides } from './types';\n\n/**\n * Which pose a resolution answers: `effective` honors overrides all the way\n * down the dependency chain, `document` ignores them all the way down. Each\n * reading memoizes in its own slots — the memo key is the node and its\n * authored pose, which is the same for both.\n */\ntype Reading = 'effective' | 'document';\n\nconst POSE_SLOT: Record<Reading, string> = {\n effective: 'kit:derivedPose',\n document: 'kit:derivedPose:document',\n};\nconst PATH_SLOT: Record<Reading, string | undefined> = {\n effective: undefined,\n document: 'kit:derivedPath:document',\n};\n\n/** The subset of a node this module reads. Structural so a `Node` satisfies\n * it without importing the full generic shape. */\nexport interface PosedNode<TPose> {\n id: NodeId;\n kind?: 'leaf' | 'container';\n pose: TPose;\n /** Read only by the memo, which keys on its reference alongside the pose. */\n data?: unknown;\n dependsOn?: readonly NodeId[] | 'children';\n derivePose?: DerivePoseFn<TPose>;\n /** Read only when something asks a dependency for its `path`. */\n derivePath?: DerivePathFn<TPose>;\n}\n\n/** What resolving a pose needs: the overrides, and enough of the scene to\n * reach a node's dependencies. A `Scene` satisfies it. */\nexport interface PoseSource<TPose> {\n readonly overrides: Pick<PoseOverrides<TPose>, 'read'>;\n get(id: NodeId): PosedNode<TPose> | undefined;\n childrenOf(id: NodeId): readonly NodeId[];\n}\n\n/** A cached derived pose, with what it was derived from. */\ninterface PoseMemo<TPose> extends DepRecord<TPose> {\n value: TPose | null;\n}\n\n/** Ids whose derivation is on the stack. A dependency graph is meant to be\n * acyclic and `dependsOn` is unvalidated, so a cycle resolves to the authored\n * pose at whichever node closes it rather than overflowing the stack. */\nconst resolving = new Set<NodeId>();\n\n/** Bumped each time the guard above fires. A derivation that closed a cycle\n * answered from a fallback rather than from its dependencies, so its value is\n * an artifact of which node was asked first and must not be cached. */\nlet cycleHits = 0;\n\n/**\n * The pose `node` computes from its dependencies, or `null` when it derives\n * nothing — it has no `derivePose`, nothing to derive from, or its\n * `derivePose` returned `null`.\n *\n * A dependency is read through {@link effectivePose}, so a group of groups\n * resolves bottom-up and a dragged dependency's override reaches the\n * derivation the same frame it is published.\n */\nexport function derivedPose<TPose>(\n source: PoseSource<TPose>,\n node: PosedNode<TPose>,\n): TPose | null {\n return derivedPoseIn(source, node, 'effective');\n}\n\nfunction derivedPoseIn<TPose>(\n source: PoseSource<TPose>,\n node: PosedNode<TPose>,\n reading: Reading,\n): TPose | null {\n const derive = node.derivePose;\n if (derive === undefined) return null;\n const ids = dependencyIdsOf(node, source.childrenOf);\n if (ids.length === 0) return null;\n if (resolving.has(node.id)) {\n cycleHits++;\n return null;\n }\n resolving.add(node.id);\n const hitsBefore = cycleHits;\n try {\n const depOf = (id: NodeId) => depIn(source, id, reading);\n // Keyed on the authored pose, which only sees a change someone pushed, so\n // the record also carries what the derivation read and re-checks it by\n // value on a hit — see `depMemo.ts`.\n let computed = false;\n const record = nodeMemo<PoseMemo<TPose>>(node, POSE_SLOT[reading], node.pose, () => {\n computed = true;\n return run(node, derive, ids.map(depOf), { ...emptyDepRecord<TPose>(), value: null });\n });\n // Mutating the record in place is what updates the memo slot, which holds\n // this object.\n if (!computed && !sameDeps(record, ids, depOf)) {\n run(node, derive, ids.map(depOf), record);\n }\n if (cycleHits !== hitsBefore) dropPoseKeyedMemoSlots(node);\n return record.value;\n } finally {\n resolving.delete(node.id);\n }\n}\n\n/** Run `derivePose` against `deps` and record what it was run against. */\nfunction run<TPose>(\n node: PosedNode<TPose>,\n derive: NonNullable<PosedNode<TPose>['derivePose']>,\n deps: readonly (DerivedDep<TPose> | undefined)[],\n into: PoseMemo<TPose>,\n): PoseMemo<TPose> {\n into.value = deriveRecorded(into, deps, (handed) => derive(node as never, handed));\n return into;\n}\n\n/**\n * `id` as a derivation sees it: the node, the pose it is painted at, and the\n * path it derives.\n *\n * The pose is resolved eagerly — every derivation reads it — and the path\n * lazily, because most do not and resolving a route costs a router run. Both\n * resolve *through* this function, so a dependency that is itself derived is\n * resolved before it is read.\n */\nexport function derivedDepOf<TPose>(\n source: PoseSource<TPose>,\n id: NodeId,\n): DerivedDep<TPose> | undefined {\n return depIn(source, id, 'effective');\n}\n\nfunction depIn<TPose>(\n source: PoseSource<TPose>,\n id: NodeId,\n reading: Reading,\n): DerivedDep<TPose> | undefined {\n const node = source.get(id);\n if (node === undefined) return undefined;\n return new SceneDep(source, node, reading);\n}\n\n/**\n * A class rather than an object literal with a `get path()`: one of these is\n * built per dependency per derived node per frame, and an own accessor costs\n * an order of magnitude more to define than a prototype one does to inherit.\n */\nclass SceneDep<TPose> implements DerivedDep<TPose> {\n readonly node: Node<unknown, string, TPose>;\n readonly pose: TPose;\n private readonly shown: Path | undefined;\n\n constructor(\n private readonly source: PoseSource<TPose>,\n private readonly posed: PosedNode<TPose>,\n private readonly reading: Reading,\n ) {\n this.node = posed as unknown as Node<unknown, string, TPose>;\n const override = reading === 'effective' ? source.overrides.read(posed.id) : undefined;\n this.shown = override?.path;\n this.pose = override?.pose ?? derivedPoseIn(source, posed, reading) ?? posed.pose;\n }\n\n get path(): Path | null {\n if (this.shown !== undefined) return this.shown;\n const { source, reading } = this;\n return resolveDerivedPath(\n this.posed,\n (depId) => depIn(source, depId, reading),\n (depId) => source.childrenOf(depId),\n PATH_SLOT[reading],\n );\n }\n}\n\nfunction poseIn<TPose>(\n source: PoseSource<TPose>,\n node: PosedNode<TPose>,\n reading: Reading,\n): TPose {\n if (reading === 'effective') {\n const override = source.overrides.read(node.id)?.pose;\n if (override !== undefined) return override;\n }\n return derivedPoseIn(source, node, reading) ?? node.pose;\n}\n\n/**\n * The pose the *document* says `node` is at: derived when it derives, else\n * authored. `effectivePose` minus the override step, at every link of the\n * dependency chain — a derived node's document pose holds still while\n * something it derives from is being dragged.\n *\n * For a reader that must not see an in-flight gesture, such as an action\n * capturing the `from` of a transform op.\n */\nexport function documentPose<TPose>(\n source: PoseSource<TPose>,\n node: PosedNode<TPose>,\n): TPose {\n return poseIn(source, node, 'document');\n}\n\n/**\n * The pose to draw, pick and measure `node` at. Every pose a reader acts on\n * comes from here.\n */\nexport function effectivePose<TPose>(\n source: PoseSource<TPose>,\n node: PosedNode<TPose>,\n): TPose {\n return poseIn(source, node, 'effective');\n}\n\n/**\n * Whether `node`'s pose is a frame its children are expressed in, under a\n * composing strategy.\n *\n * A container that derives its pose from its children cannot be one: moving\n * the frame to cover the children would move the children, and a `RectPose`\n * frame's origin is its corner, so no envelope leaves them in place. Such a\n * container is an envelope instead — its children are stored in its own\n * frame — and the composition fold passes over it.\n */\nexport function definesFrame(node: { dependsOn?: unknown; derivePose?: unknown }): boolean {\n return !(node.dependsOn === 'children' && node.derivePose !== undefined);\n}\n"],"mappings":"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"}
|
|
@@ -38,11 +38,17 @@ function r(r) {
|
|
|
38
38
|
function u(e, t) {
|
|
39
39
|
return e() ? (a(t), o(), !0) : !1;
|
|
40
40
|
}
|
|
41
|
-
let d = {
|
|
42
|
-
undo
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
let d = () => r.activeJournal() ?? i, f = {
|
|
42
|
+
undo() {
|
|
43
|
+
let e = r.activeJournal();
|
|
44
|
+
return e ? e.canUndo() ? (e.undo(), !0) : !1 : u(() => i.canUndo(), () => i.undo());
|
|
45
|
+
},
|
|
46
|
+
redo() {
|
|
47
|
+
let e = r.activeJournal();
|
|
48
|
+
return e ? e.canRedo() ? (e.redo(), !0) : !1 : u(() => i.canRedo(), () => i.redo());
|
|
49
|
+
},
|
|
50
|
+
canUndo: () => d().canUndo(),
|
|
51
|
+
canRedo: () => d().canRedo(),
|
|
46
52
|
historyEntries() {
|
|
47
53
|
let { undo: e, redo: t } = i.entries();
|
|
48
54
|
return [...e, ...t].map((e) => ({
|
|
@@ -80,13 +86,13 @@ function r(r) {
|
|
|
80
86
|
});
|
|
81
87
|
},
|
|
82
88
|
undo: () => {
|
|
83
|
-
|
|
89
|
+
f.undo();
|
|
84
90
|
},
|
|
85
91
|
redo: () => {
|
|
86
|
-
|
|
92
|
+
f.redo();
|
|
87
93
|
},
|
|
88
94
|
goto: (e) => {
|
|
89
|
-
|
|
95
|
+
f.jumpToHistoryIndex(e);
|
|
90
96
|
},
|
|
91
97
|
clear() {
|
|
92
98
|
i.clear(), o();
|
|
@@ -100,9 +106,9 @@ function r(r) {
|
|
|
100
106
|
switchBranch(e) {
|
|
101
107
|
i.switchBranch(e), o();
|
|
102
108
|
},
|
|
103
|
-
restore:
|
|
104
|
-
canUndo:
|
|
105
|
-
canRedo:
|
|
109
|
+
restore: f.restoreHistory,
|
|
110
|
+
canUndo: f.canUndo,
|
|
111
|
+
canRedo: f.canRedo,
|
|
106
112
|
undoDepth: () => i.undoDepth(),
|
|
107
113
|
redoDepth: () => i.redoDepth(),
|
|
108
114
|
entries: () => i.entries(),
|
|
@@ -111,7 +117,7 @@ function r(r) {
|
|
|
111
117
|
branches: () => i.branches(),
|
|
112
118
|
getVersion: () => i.getVersion(),
|
|
113
119
|
subscribe: (e) => i.subscribe(e),
|
|
114
|
-
serialize:
|
|
120
|
+
serialize: f.serializeHistory,
|
|
115
121
|
allForwardOps: () => i.allForwardOps(),
|
|
116
122
|
seal: () => i.seal(),
|
|
117
123
|
currentEntryId: () => i.currentEntryId(),
|
|
@@ -121,7 +127,7 @@ function r(r) {
|
|
|
121
127
|
},
|
|
122
128
|
resumeJournal: (e) => i.resumeJournal(l.get(e) ?? e)
|
|
123
129
|
},
|
|
124
|
-
methods:
|
|
130
|
+
methods: f
|
|
125
131
|
};
|
|
126
132
|
}
|
|
127
133
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"historyFacade.js","names":["wrapJournal","env","raw","ops","all","label","notify","replay","listener","createSceneHistory","rawJournals","step","can","run","methods","engine","undo","redo","total","target","index","SCENE_HISTORY_FORM","snapshot","refuseUntracked","runArrivalEdit","op","n","opts","t","id","i","wrapped","journal"],"sources":["../../../src/core/scene/historyFacade.ts"],"sourcesContent":["/**\n * `scene.history`: the `History` the kit's `undo`/`redo` actions resolve\n * their `history` dep to, and the handle a mode machine opens journals\n * against.\n *\n * Handing out the engine directly would let an action-driven undo replay ops\n * with scene-side recording still armed and without bumping the scene's\n * version, so every member that mutates routes through the scene's own\n * wrappers and one `notify()`; reads forward to the engine.\n */\nimport type { History, Journal } from '@weasel-js/history';\nimport type { Op } from 'core/ops/types';\nimport { dwarn } from 'debug/flag';\nimport { SCENE_HISTORY_FORM, type SerializedSceneHistory } from './historyForm';\nimport type { Scene } from './types';\n\n/** What the facade needs from the scene it fronts. */\nexport interface SceneHistoryEnv {\n /** The scene's own undo/redo engine. */\n engine: History;\n /** Run a step that applies ops through an engine: all-or-nothing, with\n * scene-side recording suppressed. */\n applying(step: () => void): void;\n /** An op as the engine applies it: its entry records the kit ops it\n * caused. */\n causing(op: Op): Op;\n /** Run a step that replays recorded ops: an undo, a redo, a cancel. */\n replay(step: () => void): void;\n notify(): void;\n refuseUntracked(verb: string): void;\n /** Run an op-driven edit with its arrivals settled into the same batch. */\n runArrivalEdit(ops: Op[], run: (ops: Op[]) => void): void;\n}\n\n/** The scene's own spellings of its history, which answer what a caller\n * outside the engine's vocabulary asks: whether a step moved anything. */\nexport type SceneHistoryMethods = Pick<\n Scene<unknown, string, unknown>,\n | 'undo' | 'redo' | 'canUndo' | 'canRedo' | 'historyEntries' | 'historyIndex'\n | 'jumpToHistoryIndex' | 'serializeHistory' | 'restoreHistory'\n>;\n\n/** A journal drives adapter mutation itself, so its applies and undos\n * re-enter scene mutation methods the way the facade's do. */\nfunction wrapJournal(raw: Journal, env: SceneHistoryEnv): Journal {\n const { replay, notify } = env;\n return {\n targetId: raw.targetId,\n forkedAtEntryId: raw.forkedAtEntryId,\n applyBatch(ops, label) {\n env.runArrivalEdit(ops, (all) => {\n env.applying(() => raw.applyBatch(all.map(env.causing), label));\n notify();\n });\n },\n undo() {\n replay(() => raw.undo());\n notify();\n },\n redo() {\n replay(() => raw.redo());\n notify();\n },\n canUndo: () => raw.canUndo(),\n canRedo: () => raw.canRedo(),\n entries: () => raw.entries(),\n seal: () => raw.seal(),\n getVersion: () => raw.getVersion(),\n subscribe: (listener) => raw.subscribe(listener),\n commit(label) {\n // Flushes the session's net ops to the parent stack — no apply, but\n // the parent's undo depth changes and listeners read that.\n raw.commit(label);\n notify();\n },\n cancel() {\n replay(() => raw.cancel());\n notify();\n },\n suspend: () => raw.suspend(),\n isActive: () => raw.isActive(),\n };\n}\n\nexport function createSceneHistory(env: SceneHistoryEnv): { history: History; methods: SceneHistoryMethods } {\n const { engine, replay, notify, refuseUntracked, runArrivalEdit } = env;\n\n /** Wrapped journal → the engine's own, for `resumeJournal`: the engine keys\n * resumability off journal identity, which a wrapper would not match. */\n const rawJournals = new WeakMap<Journal, Journal>();\n\n function step(can: () => boolean, run: () => void): boolean {\n if (!can()) return false;\n replay(run);\n notify();\n return true;\n }\n\n const methods: SceneHistoryMethods = {\n undo: () => step(() => engine.canUndo(), () => engine.undo()),\n redo: () => step(() => engine.canRedo(), () => engine.redo()),\n canUndo: () => engine.canUndo(),\n canRedo: () => engine.canRedo(),\n historyEntries() {\n const { undo, redo } = engine.entries();\n // entries().redo is already chronological: the next redo comes first.\n return [...undo, ...redo].map((e) => ({ id: String(e.id), label: e.label }));\n },\n historyIndex: () => engine.undoDepth(),\n jumpToHistoryIndex(index) {\n const total = engine.undoDepth() + engine.redoDepth();\n const target = Math.max(0, Math.min(total, index));\n return step(() => target !== engine.undoDepth(), () => engine.goto(target));\n },\n serializeHistory: () => ({ ...engine.serialize(), form: SCENE_HISTORY_FORM }),\n restoreHistory(snapshot) {\n if ((snapshot as Partial<SerializedSceneHistory>).form !== SCENE_HISTORY_FORM) {\n dwarn('scene', 'restoreHistory: snapshot is not in the current recorded form — dropped');\n return;\n }\n // Only the stacks are rebuilt: no op applies.\n engine.restore(snapshot);\n notify();\n },\n };\n\n const history: History = {\n // Mutating: applied ops re-enter the scene's own mutation methods.\n apply(op, label) {\n refuseUntracked('history.apply');\n runArrivalEdit([op], (all) => {\n const run = () => (all.length === 1\n ? engine.apply(env.causing(op), label)\n : engine.applyOps(all.map(env.causing), label ?? op.label ?? ''));\n env.applying(run);\n notify();\n });\n },\n applyOps(ops, label) {\n refuseUntracked('history.applyOps');\n runArrivalEdit(ops, (all) => {\n env.applying(() => engine.applyOps(all.map(env.causing), label));\n notify();\n });\n },\n undo: () => { methods.undo(); },\n redo: () => { methods.redo(); },\n goto: (n) => { methods.jumpToHistoryIndex(n); },\n // Stack-only: nothing applies, but what `canUndo()` answers changes.\n clear() {\n engine.clear();\n notify();\n },\n recordEntry(ops, label, opts) {\n engine.recordEntry(ops, label, opts);\n notify();\n },\n prune(t) {\n engine.prune(t);\n notify();\n },\n switchBranch(id) {\n engine.switchBranch(id);\n notify();\n },\n restore: methods.restoreHistory,\n // Reads forward to the engine, `version` included: it counts history\n // operations, where the scene's counts every mutation.\n canUndo: methods.canUndo,\n canRedo: methods.canRedo,\n undoDepth: () => engine.undoDepth(),\n redoDepth: () => engine.redoDepth(),\n entries: () => engine.entries(),\n timestampAt: (i) => engine.timestampAt(i),\n depthAt: (t) => engine.depthAt(t),\n branches: () => engine.branches(),\n getVersion: () => engine.getVersion(),\n subscribe: (listener) => engine.subscribe(listener),\n serialize: methods.serializeHistory,\n allForwardOps: () => engine.allForwardOps(),\n seal: () => engine.seal(),\n currentEntryId: () => engine.currentEntryId(),\n beginJournal(opts) {\n const raw = engine.beginJournal(opts);\n const wrapped = wrapJournal(raw, env);\n rawJournals.set(wrapped, raw);\n return wrapped;\n },\n resumeJournal: (journal) => engine.resumeJournal(rawJournals.get(journal) ?? journal),\n };\n return { history, methods };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"historyFacade.js","names":["wrapJournal","env","raw","ops","all","label","notify","replay","listener","createSceneHistory","rawJournals","step","can","run","stack","engine","methods","j","undo","redo","total","target","index","SCENE_HISTORY_FORM","snapshot","refuseUntracked","runArrivalEdit","op","n","opts","t","id","i","wrapped","journal"],"sources":["../../../src/core/scene/historyFacade.ts"],"sourcesContent":["/**\n * `scene.history`: the `History` the kit's `undo`/`redo` actions resolve\n * their `history` dep to, and the handle a mode machine opens journals\n * against.\n *\n * Handing out the engine directly would let an action-driven undo replay ops\n * with scene-side recording still armed and without bumping the scene's\n * version, so every member that mutates routes through the scene's own\n * wrappers and one `notify()`; reads forward to the engine.\n */\nimport type { History, Journal } from '@weasel-js/history';\nimport type { Op } from 'core/ops/types';\nimport { dwarn } from 'debug/flag';\nimport { SCENE_HISTORY_FORM, type SerializedSceneHistory } from './historyForm';\nimport type { Scene } from './types';\n\n/** What the facade needs from the scene it fronts. */\nexport interface SceneHistoryEnv {\n /** The scene's own undo/redo engine. */\n engine: History;\n /** Run a step that applies ops through an engine: all-or-nothing, with\n * scene-side recording suppressed. */\n applying(step: () => void): void;\n /** An op as the engine applies it: its entry records the kit ops it\n * caused. */\n causing(op: Op): Op;\n /** Run a step that replays recorded ops: an undo, a redo, a cancel. */\n replay(step: () => void): void;\n notify(): void;\n refuseUntracked(verb: string): void;\n /** Run an op-driven edit with its arrivals settled into the same batch. */\n runArrivalEdit(ops: Op[], run: (ops: Op[]) => void): void;\n /** The journal `applyBatch` writes to now, or null. Undo and redo step it\n * instead of the engine, so they take back the edits that went there. */\n activeJournal(): Journal | null;\n}\n\n/** The scene's own spellings of its history, which answer what a caller\n * outside the engine's vocabulary asks: whether a step moved anything. */\nexport type SceneHistoryMethods = Pick<\n Scene<unknown, string, unknown>,\n | 'undo' | 'redo' | 'canUndo' | 'canRedo' | 'historyEntries' | 'historyIndex'\n | 'jumpToHistoryIndex' | 'serializeHistory' | 'restoreHistory'\n>;\n\n/** A journal drives adapter mutation itself, so its applies and undos\n * re-enter scene mutation methods the way the facade's do. */\nfunction wrapJournal(raw: Journal, env: SceneHistoryEnv): Journal {\n const { replay, notify } = env;\n return {\n targetId: raw.targetId,\n forkedAtEntryId: raw.forkedAtEntryId,\n applyBatch(ops, label) {\n env.runArrivalEdit(ops, (all) => {\n env.applying(() => raw.applyBatch(all.map(env.causing), label));\n notify();\n });\n },\n undo() {\n replay(() => raw.undo());\n notify();\n },\n redo() {\n replay(() => raw.redo());\n notify();\n },\n canUndo: () => raw.canUndo(),\n canRedo: () => raw.canRedo(),\n entries: () => raw.entries(),\n seal: () => raw.seal(),\n getVersion: () => raw.getVersion(),\n subscribe: (listener) => raw.subscribe(listener),\n commit(label) {\n // Flushes the session's net ops to the parent stack — no apply, but\n // the parent's undo depth changes and listeners read that.\n raw.commit(label);\n notify();\n },\n cancel() {\n replay(() => raw.cancel());\n notify();\n },\n suspend: () => raw.suspend(),\n isActive: () => raw.isActive(),\n };\n}\n\nexport function createSceneHistory(env: SceneHistoryEnv): { history: History; methods: SceneHistoryMethods } {\n const { engine, replay, notify, refuseUntracked, runArrivalEdit } = env;\n\n /** Wrapped journal → the engine's own, for `resumeJournal`: the engine keys\n * resumability off journal identity, which a wrapper would not match. */\n const rawJournals = new WeakMap<Journal, Journal>();\n\n function step(can: () => boolean, run: () => void): boolean {\n if (!can()) return false;\n replay(run);\n notify();\n return true;\n }\n\n /** What undo and redo step: the open journal, else the engine. */\n const stack = (): Pick<History, 'canUndo' | 'canRedo' | 'undo' | 'redo'> => env.activeJournal() ?? engine;\n\n const methods: SceneHistoryMethods = {\n undo() {\n const j = env.activeJournal();\n if (j) { if (!j.canUndo()) return false; j.undo(); return true; }\n return step(() => engine.canUndo(), () => engine.undo());\n },\n redo() {\n const j = env.activeJournal();\n if (j) { if (!j.canRedo()) return false; j.redo(); return true; }\n return step(() => engine.canRedo(), () => engine.redo());\n },\n canUndo: () => stack().canUndo(),\n canRedo: () => stack().canRedo(),\n historyEntries() {\n const { undo, redo } = engine.entries();\n // entries().redo is already chronological: the next redo comes first.\n return [...undo, ...redo].map((e) => ({ id: String(e.id), label: e.label }));\n },\n historyIndex: () => engine.undoDepth(),\n jumpToHistoryIndex(index) {\n const total = engine.undoDepth() + engine.redoDepth();\n const target = Math.max(0, Math.min(total, index));\n return step(() => target !== engine.undoDepth(), () => engine.goto(target));\n },\n serializeHistory: () => ({ ...engine.serialize(), form: SCENE_HISTORY_FORM }),\n restoreHistory(snapshot) {\n if ((snapshot as Partial<SerializedSceneHistory>).form !== SCENE_HISTORY_FORM) {\n dwarn('scene', 'restoreHistory: snapshot is not in the current recorded form — dropped');\n return;\n }\n // Only the stacks are rebuilt: no op applies.\n engine.restore(snapshot);\n notify();\n },\n };\n\n const history: History = {\n // Mutating: applied ops re-enter the scene's own mutation methods.\n apply(op, label) {\n refuseUntracked('history.apply');\n runArrivalEdit([op], (all) => {\n const run = () => (all.length === 1\n ? engine.apply(env.causing(op), label)\n : engine.applyOps(all.map(env.causing), label ?? op.label ?? ''));\n env.applying(run);\n notify();\n });\n },\n applyOps(ops, label) {\n refuseUntracked('history.applyOps');\n runArrivalEdit(ops, (all) => {\n env.applying(() => engine.applyOps(all.map(env.causing), label));\n notify();\n });\n },\n undo: () => { methods.undo(); },\n redo: () => { methods.redo(); },\n goto: (n) => { methods.jumpToHistoryIndex(n); },\n // Stack-only: nothing applies, but what `canUndo()` answers changes.\n clear() {\n engine.clear();\n notify();\n },\n recordEntry(ops, label, opts) {\n engine.recordEntry(ops, label, opts);\n notify();\n },\n prune(t) {\n engine.prune(t);\n notify();\n },\n switchBranch(id) {\n engine.switchBranch(id);\n notify();\n },\n restore: methods.restoreHistory,\n // Reads forward to the engine, `version` included: it counts history\n // operations, where the scene's counts every mutation.\n canUndo: methods.canUndo,\n canRedo: methods.canRedo,\n undoDepth: () => engine.undoDepth(),\n redoDepth: () => engine.redoDepth(),\n entries: () => engine.entries(),\n timestampAt: (i) => engine.timestampAt(i),\n depthAt: (t) => engine.depthAt(t),\n branches: () => engine.branches(),\n getVersion: () => engine.getVersion(),\n subscribe: (listener) => engine.subscribe(listener),\n serialize: methods.serializeHistory,\n allForwardOps: () => engine.allForwardOps(),\n seal: () => engine.seal(),\n currentEntryId: () => engine.currentEntryId(),\n beginJournal(opts) {\n const raw = engine.beginJournal(opts);\n const wrapped = wrapJournal(raw, env);\n rawJournals.set(wrapped, raw);\n return wrapped;\n },\n resumeJournal: (journal) => engine.resumeJournal(rawJournals.get(journal) ?? journal),\n };\n return { history, methods };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodeFnFields.js","names":["NODE_FN_FIELDS","createNodeFnFields","table","registry","spec","reverse","key","fn","applies","node","onWrite","restoreFn","field","site","fnKeysOf","out","fields","which","fnFieldsOfNode","src"],"sources":["../../../src/core/scene/nodeFnFields.ts"],"sourcesContent":["/**\n * The registry-keyed function fields a node can carry, as a table.\n *\n * These fields are live functions on a node, and a function travels through\n * neither a serializable op payload nor a JSON snapshot. Each one therefore\n * needs the same things: a function→key reverse map, a name in the op\n * payload, a name in the snapshot, and a registry lookup on restore.\n */\nimport type { NodeId, SceneRegistry } from './types';\n\n/** A node's function field, opaque here: the table moves these around by\n * reference and never calls one. A container's `layout` is an object rather\n * than a function, and rides the same table for the same reason. */\nexport type NodeFn = ((...args: never[]) => unknown) | object;\n\n/** A node as this module reads it — a bag with the function fields on it. */\nexport type FnBearingNode = { id: NodeId; kind: 'leaf' | 'container' } & {\n [K in NodeFnFieldName]?: NodeFn;\n};\n\nexport type NodeFnFieldName = 'clipFromPose' | 'derivePath' | 'derivePose' | 'layout';\n\nexport interface NodeFnFieldSpec {\n /** The field's name on `Node` — and, deliberately, its name in\n * `SceneRegistry` too, so one string indexes both. */\n readonly field: NodeFnFieldName;\n /** Its key in the `kit:add` and `kit:remove` op payloads. `clipFromPose`'s\n * is the short one because a persisted history already carries that name. */\n readonly opKey: string;\n /** Its key in a `SerializedNode`. */\n readonly jsonKey: string;\n /** True for a field only a `ContainerNode` can carry. */\n readonly containersOnly: boolean;\n /** What a node loses when its key is not in the registry, for the warning. */\n readonly lost: string;\n}\n\nexport const NODE_FN_FIELDS: readonly NodeFnFieldSpec[] = [\n {\n field: 'clipFromPose',\n opKey: 'clipKey',\n jsonKey: 'clipFromPoseKey',\n containersOnly: true,\n lost: 'clip',\n },\n {\n field: 'derivePath',\n opKey: 'derivePathKey',\n jsonKey: 'derivePathKey',\n containersOnly: false,\n lost: 'derived path',\n },\n {\n field: 'derivePose',\n opKey: 'derivePoseKey',\n jsonKey: 'derivePoseKey',\n containersOnly: false,\n lost: 'derived pose',\n },\n {\n field: 'layout',\n opKey: 'layoutKey',\n jsonKey: 'layoutKey',\n containersOnly: true,\n lost: 'layout',\n },\n];\n\n/** One field's per-scene state. */\nexport interface NodeFnField {\n readonly spec: NodeFnFieldSpec;\n /** `fn → registry key`, for writing a payload or a snapshot. */\n keyOf(fn: NodeFn): string | undefined;\n /** `registry key → fn`, for restoring one. */\n fnOf(key: string): NodeFn | undefined;\n /** The function on `node`, or `undefined` — including when the field is\n * container-only and `node` is a leaf. */\n read(node: FnBearingNode): NodeFn | undefined;\n /** Attach `fn` to `node`, ignoring a container-only field on a leaf. */\n write(node: FnBearingNode, fn: NodeFn): void;\n}\n\nexport function createNodeFnFields<TPose>(\n registry: SceneRegistry<TPose>,\n /** Called after a field is written onto a node it applies to. */\n onWrite?: (field: NodeFnFieldName, node: FnBearingNode) => void,\n): readonly NodeFnField[] {\n return NODE_FN_FIELDS.map((spec) => {\n const table = registry[spec.field] as Readonly<Record<string, NodeFn>> | undefined;\n const reverse = new Map<NodeFn, string>();\n if (table) for (const [key, fn] of Object.entries(table)) reverse.set(fn, key);\n const applies = (node: FnBearingNode): boolean =>\n !spec.containersOnly || node.kind === 'container';\n return {\n spec,\n keyOf: (fn) => reverse.get(fn),\n fnOf: (key) => table?.[key],\n read: (node) => (applies(node) ? node[spec.field] : undefined),\n write: (node, fn) => {\n if (!applies(node)) return;\n node[spec.field] = fn;\n onWrite?.(spec.field, node);\n },\n };\n });\n}\n\n/**\n * Attach the function `key` names to `node`. Warns and leaves the field\n * unset when the key is not in this scene's registry — a snapshot outliving\n * the code that registered its functions must still load.\n */\nexport function restoreFn(\n field: NodeFnField,\n node: FnBearingNode,\n key: string,\n site: string,\n warn: (channel: string, message: string) => void,\n): void {\n const fn = field.fnOf(key);\n if (fn === undefined) {\n warn(\n 'scene',\n `${site}: ${field.spec.opKey} \"${key}\" not in this scene's registry — node \"${node.id}\" ` +\n `restored without its ${field.spec.lost}. Register a function with this key in the ` +\n `registry option to restore it.`,\n );\n return;\n }\n field.write(node, fn);\n}\n\n/** The `{ clipKey?, derivePathKey?, … }` an op payload or a snapshot carries\n * for `node`. Empty when the node has no keyed function on it. */\nexport function fnKeysOf(\n fields: readonly NodeFnField[],\n node: FnBearingNode,\n which: 'opKey' | 'jsonKey',\n onUnregistered?: (field: NodeFnField) => never,\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const field of fields) {\n const fn = field.read(node);\n if (fn === undefined) continue;\n const key = field.keyOf(fn);\n if (key === undefined) {\n onUnregistered?.(field);\n continue;\n }\n out[field.spec[which]] = key;\n }\n return out;\n}\n\n/**\n * The function fields to carry from a live node into an `AddNodeSpec`. An\n * insert that drops them brings an edge back as a static path that never\n * follows its endpoints again, and a clipped container back with nothing\n * clipped.\n */\nexport function fnFieldsOfNode<T extends { kind: 'leaf' | 'container' }>(\n node: T,\n): Partial<Pick<T, Extract<NodeFnFieldName, keyof T>>> {\n const src = node as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const spec of NODE_FN_FIELDS) {\n if (spec.containersOnly && node.kind !== 'container') continue;\n const fn = src[spec.field];\n if (fn !== undefined) out[spec.field] = fn;\n }\n return out as Partial<Pick<T, Extract<NodeFnFieldName, keyof T>>>;\n}\n"],"mappings":";AAqCA,IAAaA,IAA6C;CACxD;EACE,OAAO;EACP,OAAO;EACP,SAAS;EACT,gBAAgB;EAChB,MAAM;CACR;CACA;EACE,OAAO;EACP,OAAO;EACP,SAAS;EACT,gBAAgB;EAChB,MAAM;CACR;CACA;EACE,OAAO;EACP,OAAO;EACP,SAAS;EACT,gBAAgB;EAChB,MAAM;CACR;CACA;EACE,OAAO;EACP,OAAO;EACP,SAAS;EACT,gBAAgB;EAChB,MAAM;CACR;AACF;AAgBA,SAAgBC,EACd,GAEA,GACwB;CACxB,OAAOD,EAAe,KAAK,MAAS;EAClC,IAAME,IAAQC,EAASC,EAAK,QACtBC,oBAAU,IAAI,IAAoB;EACxC,IAAIH,GAAO,KAAK,IAAM,CAACI,GAAKC,MAAO,OAAO,QAAQL,CAAK,GAAG,EAAQ,IAAIK,GAAID,CAAG;EAC7E,IAAME,KAAW,MACf,CAACJ,EAAK,kBAAkBK,EAAK,SAAS;EACxC,OAAO;GACL;GACA,QAAQ,MAAOJ,EAAQ,IAAIE,CAAE;GAC7B,OAAO,MAAQL,IAAQI;GACvB,OAAO,MAAUE,EAAQC,CAAI,IAAIA,EAAKL,EAAK,SAAS,KAAA;GACpD,QAAQ,GAAM,MAAO;IACnB,AAAKI,EAAQC,CAAI,MACjB,EAAKL,EAAK,SAASG,GACnBG,IAAUN,EAAK,OAAOK,CAAI;GAC5B;EACF;CACF,CAAC;AACH;AAOA,SAAgBE,EACd,GACA,GACA,GACA,GACA,GACM;CACN,IAAMJ,IAAKK,EAAM,KAAKN,CAAG;CACzB,IAAIC,MAAO,KAAA,GAAW;EACpB,EACE,SACA,GAAGM,EAAK,IAAID,EAAM,KAAK,MAAM,IAAIN,EAAI,yCAAyCG,EAAK,GAAG,yBAC5DG,EAAM,KAAK,KAAK,0EAE5C;EACA;CACF;CACA,EAAM,MAAMH,GAAMF,CAAE;AACtB;AAIA,SAAgBO,EACd,GACA,GACA,GACA,GACwB;CACxB,IAAMC,IAA8B,CAAC;CACrC,KAAK,IAAMH,KAASI,GAAQ;EAC1B,IAAMT,IAAKK,EAAM,KAAKH,CAAI;EAC1B,IAAIF,MAAO,KAAA,GAAW;EACtB,IAAMD,IAAMM,EAAM,MAAML,CAAE;EAC1B,IAAID,MAAQ,KAAA,GAAW;GACrB,IAAiBM,CAAK;GACtB;EACF;EACA,EAAIA,EAAM,KAAKK,MAAUX;CAC3B;CACA,OAAOS;AACT;AAQA,SAAgBG,EACd,GACqD;CACrD,IAAMC,IAAMV,GACNM,IAA+B,CAAC;CACtC,KAAK,IAAMX,KAAQJ,GAAgB;EACjC,IAAII,EAAK,kBAAkBK,EAAK,SAAS,aAAa;EACtD,IAAMF,IAAKY,EAAIf,EAAK;EACpB,AAAIG,MAAO,KAAA,MAAW,EAAIH,EAAK,SAASG;CAC1C;CACA,OAAOQ;AACT"}
|
|
1
|
+
{"version":3,"file":"nodeFnFields.js","names":["NODE_FN_FIELDS","createNodeFnFields","table","registry","spec","reverse","key","fn","applies","node","onWrite","restoreFn","field","site","fnKeysOf","out","fields","which","fnFieldsOfNode","src"],"sources":["../../../src/core/scene/nodeFnFields.ts"],"sourcesContent":["/**\n * The registry-keyed function fields a node can carry, as a table.\n *\n * These fields are live functions on a node, and a function travels through\n * neither a serializable op payload nor a JSON snapshot. Each one therefore\n * needs the same things: a function→key reverse map, a name in the op\n * payload, a name in the snapshot, and a registry lookup on restore.\n */\nimport type { NodeId, SceneRegistry } from './types';\n\n/** A node's function field, opaque here: the table moves these around by\n * reference and never calls one. A container's `layout` is an object rather\n * than a function, and rides the same table for the same reason. */\nexport type NodeFn = ((...args: never[]) => unknown) | object;\n\n/** A node as this module reads it — a bag with the function fields on it. */\nexport type FnBearingNode = { id: NodeId; kind: 'leaf' | 'container' } & {\n [K in NodeFnFieldName]?: NodeFn;\n};\n\nexport type NodeFnFieldName = 'clipFromPose' | 'copiesFromPose' | 'derivePath' | 'derivePose' | 'layout';\n\nexport interface NodeFnFieldSpec {\n /** The field's name on `Node` — and, deliberately, its name in\n * `SceneRegistry` too, so one string indexes both. */\n readonly field: NodeFnFieldName;\n /** Its key in the `kit:add` and `kit:remove` op payloads. `clipFromPose`'s\n * is the short one because a persisted history already carries that name. */\n readonly opKey: string;\n /** Its key in a `SerializedNode`. */\n readonly jsonKey: string;\n /** True for a field only a `ContainerNode` can carry. */\n readonly containersOnly: boolean;\n /** What a node loses when its key is not in the registry, for the warning. */\n readonly lost: string;\n}\n\nexport const NODE_FN_FIELDS: readonly NodeFnFieldSpec[] = [\n {\n field: 'clipFromPose',\n opKey: 'clipKey',\n jsonKey: 'clipFromPoseKey',\n containersOnly: true,\n lost: 'clip',\n },\n {\n field: 'copiesFromPose',\n opKey: 'copiesKey',\n jsonKey: 'copiesFromPoseKey',\n containersOnly: true,\n lost: 'copies',\n },\n {\n field: 'derivePath',\n opKey: 'derivePathKey',\n jsonKey: 'derivePathKey',\n containersOnly: false,\n lost: 'derived path',\n },\n {\n field: 'derivePose',\n opKey: 'derivePoseKey',\n jsonKey: 'derivePoseKey',\n containersOnly: false,\n lost: 'derived pose',\n },\n {\n field: 'layout',\n opKey: 'layoutKey',\n jsonKey: 'layoutKey',\n containersOnly: true,\n lost: 'layout',\n },\n];\n\n/** One field's per-scene state. */\nexport interface NodeFnField {\n readonly spec: NodeFnFieldSpec;\n /** `fn → registry key`, for writing a payload or a snapshot. */\n keyOf(fn: NodeFn): string | undefined;\n /** `registry key → fn`, for restoring one. */\n fnOf(key: string): NodeFn | undefined;\n /** The function on `node`, or `undefined` — including when the field is\n * container-only and `node` is a leaf. */\n read(node: FnBearingNode): NodeFn | undefined;\n /** Attach `fn` to `node`, ignoring a container-only field on a leaf. */\n write(node: FnBearingNode, fn: NodeFn): void;\n}\n\nexport function createNodeFnFields<TPose>(\n registry: SceneRegistry<TPose>,\n /** Called after a field is written onto a node it applies to. */\n onWrite?: (field: NodeFnFieldName, node: FnBearingNode) => void,\n): readonly NodeFnField[] {\n return NODE_FN_FIELDS.map((spec) => {\n const table = registry[spec.field] as Readonly<Record<string, NodeFn>> | undefined;\n const reverse = new Map<NodeFn, string>();\n if (table) for (const [key, fn] of Object.entries(table)) reverse.set(fn, key);\n const applies = (node: FnBearingNode): boolean =>\n !spec.containersOnly || node.kind === 'container';\n return {\n spec,\n keyOf: (fn) => reverse.get(fn),\n fnOf: (key) => table?.[key],\n read: (node) => (applies(node) ? node[spec.field] : undefined),\n write: (node, fn) => {\n if (!applies(node)) return;\n node[spec.field] = fn;\n onWrite?.(spec.field, node);\n },\n };\n });\n}\n\n/**\n * Attach the function `key` names to `node`. Warns and leaves the field\n * unset when the key is not in this scene's registry — a snapshot outliving\n * the code that registered its functions must still load.\n */\nexport function restoreFn(\n field: NodeFnField,\n node: FnBearingNode,\n key: string,\n site: string,\n warn: (channel: string, message: string) => void,\n): void {\n const fn = field.fnOf(key);\n if (fn === undefined) {\n warn(\n 'scene',\n `${site}: ${field.spec.opKey} \"${key}\" not in this scene's registry — node \"${node.id}\" ` +\n `restored without its ${field.spec.lost}. Register a function with this key in the ` +\n `registry option to restore it.`,\n );\n return;\n }\n field.write(node, fn);\n}\n\n/** The `{ clipKey?, derivePathKey?, … }` an op payload or a snapshot carries\n * for `node`. Empty when the node has no keyed function on it. */\nexport function fnKeysOf(\n fields: readonly NodeFnField[],\n node: FnBearingNode,\n which: 'opKey' | 'jsonKey',\n onUnregistered?: (field: NodeFnField) => never,\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const field of fields) {\n const fn = field.read(node);\n if (fn === undefined) continue;\n const key = field.keyOf(fn);\n if (key === undefined) {\n onUnregistered?.(field);\n continue;\n }\n out[field.spec[which]] = key;\n }\n return out;\n}\n\n/**\n * The function fields to carry from a live node into an `AddNodeSpec`. An\n * insert that drops them brings an edge back as a static path that never\n * follows its endpoints again, and a clipped container back with nothing\n * clipped.\n */\nexport function fnFieldsOfNode<T extends { kind: 'leaf' | 'container' }>(\n node: T,\n): Partial<Pick<T, Extract<NodeFnFieldName, keyof T>>> {\n const src = node as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const spec of NODE_FN_FIELDS) {\n if (spec.containersOnly && node.kind !== 'container') continue;\n const fn = src[spec.field];\n if (fn !== undefined) out[spec.field] = fn;\n }\n return out as Partial<Pick<T, Extract<NodeFnFieldName, keyof T>>>;\n}\n"],"mappings":";AAqCA,IAAaA,IAA6C;CACxD;EACE,OAAO;EACP,OAAO;EACP,SAAS;EACT,gBAAgB;EAChB,MAAM;CACR;CACA;EACE,OAAO;EACP,OAAO;EACP,SAAS;EACT,gBAAgB;EAChB,MAAM;CACR;CACA;EACE,OAAO;EACP,OAAO;EACP,SAAS;EACT,gBAAgB;EAChB,MAAM;CACR;CACA;EACE,OAAO;EACP,OAAO;EACP,SAAS;EACT,gBAAgB;EAChB,MAAM;CACR;CACA;EACE,OAAO;EACP,OAAO;EACP,SAAS;EACT,gBAAgB;EAChB,MAAM;CACR;AACF;AAgBA,SAAgBC,EACd,GAEA,GACwB;CACxB,OAAOD,EAAe,KAAK,MAAS;EAClC,IAAME,IAAQC,EAASC,EAAK,QACtBC,oBAAU,IAAI,IAAoB;EACxC,IAAIH,GAAO,KAAK,IAAM,CAACI,GAAKC,MAAO,OAAO,QAAQL,CAAK,GAAG,EAAQ,IAAIK,GAAID,CAAG;EAC7E,IAAME,KAAW,MACf,CAACJ,EAAK,kBAAkBK,EAAK,SAAS;EACxC,OAAO;GACL;GACA,QAAQ,MAAOJ,EAAQ,IAAIE,CAAE;GAC7B,OAAO,MAAQL,IAAQI;GACvB,OAAO,MAAUE,EAAQC,CAAI,IAAIA,EAAKL,EAAK,SAAS,KAAA;GACpD,QAAQ,GAAM,MAAO;IACnB,AAAKI,EAAQC,CAAI,MACjB,EAAKL,EAAK,SAASG,GACnBG,IAAUN,EAAK,OAAOK,CAAI;GAC5B;EACF;CACF,CAAC;AACH;AAOA,SAAgBE,EACd,GACA,GACA,GACA,GACA,GACM;CACN,IAAMJ,IAAKK,EAAM,KAAKN,CAAG;CACzB,IAAIC,MAAO,KAAA,GAAW;EACpB,EACE,SACA,GAAGM,EAAK,IAAID,EAAM,KAAK,MAAM,IAAIN,EAAI,yCAAyCG,EAAK,GAAG,yBAC5DG,EAAM,KAAK,KAAK,0EAE5C;EACA;CACF;CACA,EAAM,MAAMH,GAAMF,CAAE;AACtB;AAIA,SAAgBO,EACd,GACA,GACA,GACA,GACwB;CACxB,IAAMC,IAA8B,CAAC;CACrC,KAAK,IAAMH,KAASI,GAAQ;EAC1B,IAAMT,IAAKK,EAAM,KAAKH,CAAI;EAC1B,IAAIF,MAAO,KAAA,GAAW;EACtB,IAAMD,IAAMM,EAAM,MAAML,CAAE;EAC1B,IAAID,MAAQ,KAAA,GAAW;GACrB,IAAiBM,CAAK;GACtB;EACF;EACA,EAAIA,EAAM,KAAKK,MAAUX;CAC3B;CACA,OAAOS;AACT;AAQA,SAAgBG,EACd,GACqD;CACrD,IAAMC,IAAMV,GACNM,IAA+B,CAAC;CACtC,KAAK,IAAMX,KAAQJ,GAAgB;EACjC,IAAII,EAAK,kBAAkBK,EAAK,SAAS,aAAa;EACtD,IAAMF,IAAKY,EAAIf,EAAK;EACpB,AAAIG,MAAO,KAAA,MAAW,EAAIH,EAAK,SAASG;CAC1C;CACA,OAAOQ;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outerOps.js","names":["rebuildGlobalOp","keyed","key","outerKey","kit","createOuterOps","historyAdapter","activeJournal","env","causing","op","caused","given","adapter","ops","result","own","name","args","rebuilt","rebuildOp","bindOpToHistoryAdapter","journal","bound","bindOpToAdapter","label","engine","fn"],"sources":["../../../src/core/scene/outerOps.ts"],"sourcesContent":["/**\n * Ops built outside the scene and handed to `applyBatch` or `scene.history`.\n *\n * An undo entry holds the scene's own ops, so an outer op is recorded as the\n * kit ops it caused. One that wrote no scene state is recorded as itself, and\n * needs an adapter to replay through: the one it was applied with, or after a\n * reload the one `setHistoryAdapter` supplies.\n */\nimport type { History, Journal } from '@weasel-js/history';\nimport type { Op } from 'core/ops/types';\nimport { rebuildOp as rebuildGlobalOp } from 'core/ops/registry';\nimport { bindOpToAdapter, bindOpToHistoryAdapter } from './boundOps';\nimport type { Recorder } from './recorder';\n\n/** What the outer ops need from the scene they are applied to. */\nexport interface OuterOpsEnv {\n /** The scene's own op for a kind it has registered, or `null`. */\n own(name: string, args: unknown): Op | null;\n /** The scene's recorder, built after this is. */\n recorder(): Pick<Recorder, 'capturing' | 'joins' | 'join'>;\n /** Run a step that applies ops through a history engine: all-or-nothing,\n * unrecorded by the scene, with subscribers called once after. */\n driving(step: () => void): void;\n /** Where `applyBatch` looks for an open journal until an accessor is set. */\n getActiveJournal: (() => Journal | null) | null;\n}\n\nexport interface OuterOps {\n /** The op a restored history names: the scene's own, or an outer op bound\n * to the adapter `setHistoryAdapter` supplies. `null` when nothing knows\n * the name, and the engine places its no-op placeholder. */\n rebuild(name: string, args: unknown): Op | null;\n /** `op` as an engine applies it: its entry records the kit ops it caused,\n * or the op itself when it caused none. */\n causing(op: Op): Op;\n /** Apply `ops` against `adapter` as one entry: part of the open `batch`\n * when there is one, else on the active journal, else on `engine`. */\n apply(engine: History, ops: Op[], label: string, adapter: unknown): void;\n setHistoryAdapter(fn: (() => unknown) | null): void;\n setActiveJournalAccessor(fn: (() => Journal | null) | null): void;\n}\n\n/** A kit op under the key of the outer op that caused it, so two edits merge\n * when their outer ops would have. */\nfunction keyed(kit: Op, outerKey: string | undefined): Op {\n const key = outerKey === undefined || kit.coalesceKey === undefined ? undefined : `${outerKey}>${kit.coalesceKey}`;\n return { name: kit.name, args: kit.args, coalesceKey: key, apply: kit.apply, invert: kit.invert };\n}\n\nexport function createOuterOps(env: OuterOpsEnv): OuterOps {\n let historyAdapter: (() => unknown) | null = null;\n let activeJournal = env.getActiveJournal;\n\n function causing(op: Op, given: Op = op): Op {\n if (op.caused) return op;\n let caused: Op[] = [given];\n return {\n get name() { return op.name; },\n get args() { return op.args; },\n label: op.label,\n // Read when asked: an arrange op has no key until it has applied.\n get coalesceKey() { return op.coalesceKey; },\n elideNoop: op.elideNoop,\n apply(adapter) {\n const { result, ops } = env.recorder().capturing(() => given.apply(adapter));\n if (ops.length > 0) caused = ops.map((kit) => keyed(kit, op.coalesceKey));\n return result;\n },\n caused: () => caused,\n invert: () => given.invert(),\n };\n }\n\n return {\n rebuild(name, args) {\n const own = env.own(name, args);\n if (own !== null) return own;\n const rebuilt = rebuildGlobalOp(name, args);\n return rebuilt === null ? null : bindOpToHistoryAdapter(rebuilt, () => historyAdapter);\n },\n causing: (op) => causing(op),\n apply(engine, ops, label, adapter) {\n if (env.recorder().joins()) return env.recorder().join(ops, adapter);\n const journal = activeJournal?.() ?? null;\n env.driving(() => {\n // Neither engine was built with an adapter, so an op is bound to\n // this call's before either applies or stores it.\n const bound = ops.map((op) => causing(op, bindOpToAdapter(op, adapter)));\n if (journal) journal.applyBatch(bound, label);\n else engine.applyOps(bound, label);\n });\n },\n setHistoryAdapter(fn) {\n historyAdapter = fn;\n },\n setActiveJournalAccessor(fn) {\n activeJournal = fn;\n },\n };\n}\n"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"outerOps.js","names":["rebuildGlobalOp","keyed","key","outerKey","kit","createOuterOps","historyAdapter","activeJournal","env","causing","op","caused","given","adapter","ops","result","own","name","args","rebuilt","rebuildOp","bindOpToHistoryAdapter","journal","bound","bindOpToAdapter","label","engine","fn"],"sources":["../../../src/core/scene/outerOps.ts"],"sourcesContent":["/**\n * Ops built outside the scene and handed to `applyBatch` or `scene.history`.\n *\n * An undo entry holds the scene's own ops, so an outer op is recorded as the\n * kit ops it caused. One that wrote no scene state is recorded as itself, and\n * needs an adapter to replay through: the one it was applied with, or after a\n * reload the one `setHistoryAdapter` supplies.\n */\nimport type { History, Journal } from '@weasel-js/history';\nimport type { Op } from 'core/ops/types';\nimport { rebuildOp as rebuildGlobalOp } from 'core/ops/registry';\nimport { bindOpToAdapter, bindOpToHistoryAdapter } from './boundOps';\nimport type { Recorder } from './recorder';\n\n/** What the outer ops need from the scene they are applied to. */\nexport interface OuterOpsEnv {\n /** The scene's own op for a kind it has registered, or `null`. */\n own(name: string, args: unknown): Op | null;\n /** The scene's recorder, built after this is. */\n recorder(): Pick<Recorder, 'capturing' | 'joins' | 'join'>;\n /** Run a step that applies ops through a history engine: all-or-nothing,\n * unrecorded by the scene, with subscribers called once after. */\n driving(step: () => void): void;\n /** Where `applyBatch` looks for an open journal until an accessor is set. */\n getActiveJournal: (() => Journal | null) | null;\n}\n\nexport interface OuterOps {\n /** The op a restored history names: the scene's own, or an outer op bound\n * to the adapter `setHistoryAdapter` supplies. `null` when nothing knows\n * the name, and the engine places its no-op placeholder. */\n rebuild(name: string, args: unknown): Op | null;\n /** `op` as an engine applies it: its entry records the kit ops it caused,\n * or the op itself when it caused none. */\n causing(op: Op): Op;\n /** Apply `ops` against `adapter` as one entry: part of the open `batch`\n * when there is one, else on the active journal, else on `engine`. */\n apply(engine: History, ops: Op[], label: string, adapter: unknown): void;\n setHistoryAdapter(fn: (() => unknown) | null): void;\n setActiveJournalAccessor(fn: (() => Journal | null) | null): void;\n /** The journal edits go to now, or null for the scene's own history. */\n activeJournal(): Journal | null;\n}\n\n/** A kit op under the key of the outer op that caused it, so two edits merge\n * when their outer ops would have. */\nfunction keyed(kit: Op, outerKey: string | undefined): Op {\n const key = outerKey === undefined || kit.coalesceKey === undefined ? undefined : `${outerKey}>${kit.coalesceKey}`;\n return { name: kit.name, args: kit.args, coalesceKey: key, apply: kit.apply, invert: kit.invert };\n}\n\nexport function createOuterOps(env: OuterOpsEnv): OuterOps {\n let historyAdapter: (() => unknown) | null = null;\n let activeJournal = env.getActiveJournal;\n\n function causing(op: Op, given: Op = op): Op {\n if (op.caused) return op;\n let caused: Op[] = [given];\n return {\n get name() { return op.name; },\n get args() { return op.args; },\n label: op.label,\n // Read when asked: an arrange op has no key until it has applied.\n get coalesceKey() { return op.coalesceKey; },\n elideNoop: op.elideNoop,\n apply(adapter) {\n const { result, ops } = env.recorder().capturing(() => given.apply(adapter));\n if (ops.length > 0) caused = ops.map((kit) => keyed(kit, op.coalesceKey));\n return result;\n },\n caused: () => caused,\n invert: () => given.invert(),\n };\n }\n\n return {\n rebuild(name, args) {\n const own = env.own(name, args);\n if (own !== null) return own;\n const rebuilt = rebuildGlobalOp(name, args);\n return rebuilt === null ? null : bindOpToHistoryAdapter(rebuilt, () => historyAdapter);\n },\n causing: (op) => causing(op),\n apply(engine, ops, label, adapter) {\n if (env.recorder().joins()) return env.recorder().join(ops, adapter);\n const journal = activeJournal?.() ?? null;\n env.driving(() => {\n // Neither engine was built with an adapter, so an op is bound to\n // this call's before either applies or stores it.\n const bound = ops.map((op) => causing(op, bindOpToAdapter(op, adapter)));\n if (journal) journal.applyBatch(bound, label);\n else engine.applyOps(bound, label);\n });\n },\n setHistoryAdapter(fn) {\n historyAdapter = fn;\n },\n setActiveJournalAccessor(fn) {\n activeJournal = fn;\n },\n activeJournal: () => activeJournal?.() ?? null,\n };\n}\n"],"mappings":";;;AA8CA,SAASC,EAAM,GAAS,GAAkC;CACxD,IAAMC,IAAMC,MAAa,KAAA,KAAaC,EAAI,gBAAgB,KAAA,IAAY,KAAA,IAAY,GAAGD,EAAS,GAAGC,EAAI;CACrG,OAAO;EAAE,MAAMA,EAAI;EAAM,MAAMA,EAAI;EAAM,aAAaF;EAAK,OAAOE,EAAI;EAAO,QAAQA,EAAI;CAAO;AAClG;AAEA,SAAgBC,EAAe,GAA4B;CACzD,IAAIC,IAAyC,MACzCC,IAAgBC,EAAI;CAExB,SAASC,EAAQ,GAAQ,IAAYC,GAAQ;EAC3C,IAAIA,EAAG,QAAQ,OAAOA;EACtB,IAAIC,IAAe,CAACC,CAAK;EACzB,OAAO;GACL,IAAI,OAAO;IAAE,OAAOF,EAAG;GAAM;GAC7B,IAAI,OAAO;IAAE,OAAOA,EAAG;GAAM;GAC7B,OAAOA,EAAG;GAEV,IAAI,cAAc;IAAE,OAAOA,EAAG;GAAa;GAC3C,WAAWA,EAAG;GACd,MAAM,GAAS;IACb,IAAM,EAAE,WAAQ,WAAQF,EAAI,SAAS,CAAC,CAAC,gBAAgBI,EAAM,MAAMC,CAAO,CAAC;IAE3E,OADIC,EAAI,SAAS,MAAG,IAASA,EAAI,KAAK,MAAQb,EAAMG,GAAKM,EAAG,WAAW,CAAC,IACjEK;GACT;GACA,cAAcJ;GACd,cAAcC,EAAM,OAAO;EAC7B;CACF;CAEA,OAAO;EACL,QAAQ,GAAM,GAAM;GAClB,IAAMI,IAAMR,EAAI,IAAIS,GAAMC,CAAI;GAC9B,IAAIF,MAAQ,MAAM,OAAOA;GACzB,IAAMG,IAAUnB,EAAgBiB,GAAMC,CAAI;GAC1C,OAAOC,MAAY,OAAO,OAAOE,EAAuBF,SAAeb,CAAc;EACvF;EACA,UAAU,MAAOG,EAAQC,CAAE;EAC3B,MAAM,GAAQ,GAAK,GAAO,GAAS;GACjC,IAAIF,EAAI,SAAS,CAAC,CAAC,MAAM,GAAG,OAAOA,EAAI,SAAS,CAAC,CAAC,KAAKM,GAAKD,CAAO;GACnE,IAAMS,IAAUf,IAAgB,KAAK;GACrC,EAAI,cAAc;IAGhB,IAAMgB,IAAQT,EAAI,KAAK,MAAOL,EAAQC,GAAIc,EAAgBd,GAAIG,CAAO,CAAC,CAAC;IACvE,AAAIS,IAASA,EAAQ,WAAWC,GAAOE,CAAK,IACvCC,EAAO,SAASH,GAAOE,CAAK;GACnC,CAAC;EACH;EACA,kBAAkB,GAAI;GACpB,IAAiBE;EACnB;EACA,yBAAyB,GAAI;GAC3B,IAAgBA;EAClB;EACA,qBAAqBpB,IAAgB,KAAK;CAC5C;AACF"}
|
|
@@ -31,7 +31,7 @@ function n(e) {
|
|
|
31
31
|
return t;
|
|
32
32
|
}
|
|
33
33
|
function r(e, t) {
|
|
34
|
-
return e.kind !== t.kind || e.pickable !== t.pickable || e.derivePath !== t.derivePath || e.derivePose !== t.derivePose || e.clipFromPose !== t.clipFromPose || e.layout !== t.layout;
|
|
34
|
+
return e.kind !== t.kind || e.pickable !== t.pickable || e.derivePath !== t.derivePath || e.derivePose !== t.derivePose || e.clipFromPose !== t.clipFromPose || e.copiesFromPose !== t.copiesFromPose || e.layout !== t.layout;
|
|
35
35
|
}
|
|
36
36
|
function i(t, n) {
|
|
37
37
|
if (Object.is(t, n)) return !0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconcileSpecs.js","names":["reconcileSpecs","prevById","byId","prev","nextById","next","gone","id","before","after","needsReplace","removing","scene","removed","selected","spec","parent","same","out","specs","a","b","v","i","isPlainObject","ka","k"],"sources":["../../../src/core/scene/reconcileSpecs.ts"],"sourcesContent":["import { isPlainObject } from '../isPlainObject';\nimport type { AddNodeSpec, NodeId, Scene } from './types';\n\n/**\n * Bring `scene` from `prev` to `next`: add what `next` gained, remove what it\n * lost, and write only the fields that changed between the two.\n *\n * The diff is spec against spec, not spec against scene, so whatever the scene\n * did since `prev` — a node dragged, an edge authored by a gesture — survives\n * unless `next` changes that same field. The writes are untracked: syncing to\n * outside data is not an undo step.\n *\n * Every spec needs an `id`, and `next` must be in an order `createScene` would\n * accept — parents and dependencies before what names them. A node whose\n * `kind` or derive functions change is removed and added again, along with\n * everything its removal takes with it, and stays selected if it was.\n */\nexport function reconcileSpecs<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n prev: readonly AddNodeSpec<TData, TLayer, TPose>[],\n next: readonly AddNodeSpec<TData, TLayer, TPose>[],\n): void {\n const prevById = byId(prev);\n const nextById = byId(next);\n const gone: NodeId[] = [];\n for (const [id, before] of prevById) {\n const after = nextById.get(id);\n if (after === undefined || needsReplace(before, after)) gone.push(id);\n }\n const removing = scene.removalClosure(gone.filter((id) => scene.get(id) !== undefined));\n const removed = new Set(removing);\n\n // A replaced node is the same node to whoever selected it.\n const selected = scene.getSelection();\n\n scene.untracked(() => {\n scene.removeMany(removing);\n for (const spec of next) {\n const id = spec.id!;\n const before = prevById.get(id);\n if (scene.get(id) === undefined || before === undefined || removed.has(id)) {\n scene.add(spec);\n continue;\n }\n const parent = spec.parent ?? null;\n if (parent !== (before.parent ?? null)) scene.move(id, parent);\n if (spec.layer !== before.layer) scene.setLayer(id, spec.layer);\n if (!same(spec.data, before.data)) scene.update(id, { data: spec.data });\n if (!same(spec.dependsOn, before.dependsOn)) scene.setDependsOn(id, spec.dependsOn);\n if (spec.kind === 'container' && !same(spec.units, before.units)) scene.setUnits(id, spec.units ?? null);\n if (!same(spec.pose, before.pose)) scene.setPose(id, spec.pose);\n }\n if (selected.some((id) => removed.has(id))) {\n scene.setSelection(selected.filter((id) => scene.get(id) !== undefined));\n }\n });\n}\n\nfunction byId<T extends { id?: NodeId }>(specs: readonly T[]): Map<NodeId, T> {\n const out = new Map<NodeId, T>();\n for (const spec of specs) {\n if (spec.id === undefined) throw new Error('reconcileSpecs: every spec needs an id');\n if (out.has(spec.id)) throw new Error(`reconcileSpecs: id \"${spec.id}\" appears more than once`);\n out.set(spec.id, spec);\n }\n return out;\n}\n\nfunction needsReplace<TData, TLayer extends string, TPose>(\n a: AddNodeSpec<TData, TLayer, TPose>,\n b: AddNodeSpec<TData, TLayer, TPose>,\n): boolean {\n return a.kind !== b.kind\n || a.pickable !== b.pickable\n || a.derivePath !== b.derivePath\n || a.derivePose !== b.derivePose\n || a.clipFromPose !== b.clipFromPose\n || a.layout !== b.layout;\n}\n\n/** Structural equality over plain objects and arrays; anything else by identity. */\nfunction same(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((v, i) => same(v, b[i]));\n }\n if (isPlainObject(a) && isPlainObject(b)) {\n const ka = Object.keys(a);\n return ka.length === Object.keys(b).length && ka.every((k) => k in b && same(a[k], b[k]));\n }\n return false;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"reconcileSpecs.js","names":["reconcileSpecs","prevById","byId","prev","nextById","next","gone","id","before","after","needsReplace","removing","scene","removed","selected","spec","parent","same","out","specs","a","b","v","i","isPlainObject","ka","k"],"sources":["../../../src/core/scene/reconcileSpecs.ts"],"sourcesContent":["import { isPlainObject } from '../isPlainObject';\nimport type { AddNodeSpec, NodeId, Scene } from './types';\n\n/**\n * Bring `scene` from `prev` to `next`: add what `next` gained, remove what it\n * lost, and write only the fields that changed between the two.\n *\n * The diff is spec against spec, not spec against scene, so whatever the scene\n * did since `prev` — a node dragged, an edge authored by a gesture — survives\n * unless `next` changes that same field. The writes are untracked: syncing to\n * outside data is not an undo step.\n *\n * Every spec needs an `id`, and `next` must be in an order `createScene` would\n * accept — parents and dependencies before what names them. A node whose\n * `kind` or derive functions change is removed and added again, along with\n * everything its removal takes with it, and stays selected if it was.\n */\nexport function reconcileSpecs<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n prev: readonly AddNodeSpec<TData, TLayer, TPose>[],\n next: readonly AddNodeSpec<TData, TLayer, TPose>[],\n): void {\n const prevById = byId(prev);\n const nextById = byId(next);\n const gone: NodeId[] = [];\n for (const [id, before] of prevById) {\n const after = nextById.get(id);\n if (after === undefined || needsReplace(before, after)) gone.push(id);\n }\n const removing = scene.removalClosure(gone.filter((id) => scene.get(id) !== undefined));\n const removed = new Set(removing);\n\n // A replaced node is the same node to whoever selected it.\n const selected = scene.getSelection();\n\n scene.untracked(() => {\n scene.removeMany(removing);\n for (const spec of next) {\n const id = spec.id!;\n const before = prevById.get(id);\n if (scene.get(id) === undefined || before === undefined || removed.has(id)) {\n scene.add(spec);\n continue;\n }\n const parent = spec.parent ?? null;\n if (parent !== (before.parent ?? null)) scene.move(id, parent);\n if (spec.layer !== before.layer) scene.setLayer(id, spec.layer);\n if (!same(spec.data, before.data)) scene.update(id, { data: spec.data });\n if (!same(spec.dependsOn, before.dependsOn)) scene.setDependsOn(id, spec.dependsOn);\n if (spec.kind === 'container' && !same(spec.units, before.units)) scene.setUnits(id, spec.units ?? null);\n if (!same(spec.pose, before.pose)) scene.setPose(id, spec.pose);\n }\n if (selected.some((id) => removed.has(id))) {\n scene.setSelection(selected.filter((id) => scene.get(id) !== undefined));\n }\n });\n}\n\nfunction byId<T extends { id?: NodeId }>(specs: readonly T[]): Map<NodeId, T> {\n const out = new Map<NodeId, T>();\n for (const spec of specs) {\n if (spec.id === undefined) throw new Error('reconcileSpecs: every spec needs an id');\n if (out.has(spec.id)) throw new Error(`reconcileSpecs: id \"${spec.id}\" appears more than once`);\n out.set(spec.id, spec);\n }\n return out;\n}\n\nfunction needsReplace<TData, TLayer extends string, TPose>(\n a: AddNodeSpec<TData, TLayer, TPose>,\n b: AddNodeSpec<TData, TLayer, TPose>,\n): boolean {\n return a.kind !== b.kind\n || a.pickable !== b.pickable\n || a.derivePath !== b.derivePath\n || a.derivePose !== b.derivePose\n || a.clipFromPose !== b.clipFromPose\n || a.copiesFromPose !== b.copiesFromPose\n || a.layout !== b.layout;\n}\n\n/** Structural equality over plain objects and arrays; anything else by identity. */\nfunction same(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((v, i) => same(v, b[i]));\n }\n if (isPlainObject(a) && isPlainObject(b)) {\n const ka = Object.keys(a);\n return ka.length === Object.keys(b).length && ka.every((k) => k in b && same(a[k], b[k]));\n }\n return false;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sceneRecording.js","names":["createSceneRecording","env","notifier","ops","createOpTable","mode","replay","step","notify","stale","logApplied","kind","payload","reverted","outer","createOuterOps","name","args","recorder","atomically","config","engine","createHistory","selection","ids","log","createAppliedLog","createRecorder","lifted","engineDriven","refuseUntracked","verb","createSceneHistory","arrivals","handler","op","batch","all","label","adapter","methods"],"sources":["../../../src/core/scene/sceneRecording.ts"],"sourcesContent":["/**\n * How a scene's edits reach its undo stack: the op table, the log that takes\n * back an edit refused partway, the engine, and the recorder between them.\n */\nimport type { Journal } from '@weasel-js/history';\nimport { createHistory } from 'core/ops/createHistory';\nimport { createAppliedLog } from './appliedLog';\nimport type { ArrivalWindow } from './arrivalWindow';\nimport type { EditMode } from './editMode';\nimport { createSceneHistory, type SceneHistoryMethods } from './historyFacade';\nimport type { Notifier } from './notifier';\nimport { createOpTable, type OpTable } from './opTable';\nimport { createOuterOps } from './outerOps';\nimport { createRecorder, type Recorder, type RecorderEnv } from './recorder';\nimport type { SceneSelection } from './sceneSelection';\nimport type { StaleReplay } from './staleReplay';\nimport type { NodeId, RegisteredOp, Scene } from './types';\n\nexport interface SceneRecordingEnv {\n notifier: Notifier;\n mode: EditMode;\n stale: StaleReplay;\n /** Run with the lock guard lifted. */\n lifted<T>(fn: () => T): T;\n selection: Pick<SceneSelection, 'get' | 'set' | 'replace'>;\n arrivals: RecorderEnv['arrivals'] & Pick<ArrivalWindow<unknown>, 'runEdit'>;\n writePose(id: string, pose: unknown): void;\n config: {\n getActiveJournal?: (() => Journal | null) | undefined;\n coalesceWindowMs?: number | undefined;\n historyLimit?: number | undefined;\n };\n}\n\nexport interface SceneRecording {\n ops: Pick<OpTable, 'register' | 'run'>;\n recorder: Recorder;\n clearHistory(): void;\n methods: SceneHistoryMethods & Pick<\n Scene<unknown, string, unknown>,\n | 'registerOp' | 'recordOp' | 'applyBatch' | 'history' | 'batch' | 'untracked'\n | 'setActiveJournalAccessor' | 'setHistoryAdapter'\n >;\n}\n\nexport function createSceneRecording(env: SceneRecordingEnv): SceneRecording {\n const { notifier, mode, stale, lifted, selection, arrivals, config } = env;\n const { notify } = notifier;\n\n const ops = createOpTable({\n driven: mode.open,\n replayAlone: (step) => { replay(step); notify(); },\n skips: stale.skips,\n // Only a replay is logged: a first apply is recorded by the entry it\n // creates, and reverting it would leave that entry describing nothing.\n applied: (kind, payload, reverted) => { if (!mode.records()) logApplied(kind, payload, reverted); },\n });\n\n const outer = createOuterOps({\n own: (name, args) => (ops.handlers.has(name) ? ops.op(name, args) : null),\n recorder: () => recorder,\n // Deferred rather than muted, so a throwing op cannot strand subscribers\n // after earlier ops in the batch already mutated state.\n driving: (step) => notifier.deferred(() => mode.during('engine', () => atomically(step, () => true))),\n getActiveJournal: config.getActiveJournal ?? null,\n });\n\n // The scene's undo/redo engine. Its recorded ops close over their payloads,\n // so the engine's adapter argument is unused.\n const engine = createHistory(undefined, {\n selection: { get: selection.get, set: (ids) => selection.set(ids as readonly NodeId[]) },\n ...(config.coalesceWindowMs !== undefined ? { coalesceWindowMs: config.coalesceWindowMs } : {}),\n ...(config.historyLimit !== undefined ? { historyLimit: config.historyLimit } : {}),\n rebuildOp: outer.rebuild,\n });\n\n const log = createAppliedLog({\n registered: ops.handlers,\n lifted,\n getSelection: selection.get,\n setSelection: selection.replace,\n notify,\n });\n const { atomically, logApplied } = log;\n\n const recorder = createRecorder({\n notifier,\n mode,\n engine,\n runOp: ops.run,\n makeOp: ops.op,\n log,\n arrivals,\n selection: selection.get,\n writePose: env.writePose,\n });\n const { record, engineDriven } = recorder;\n\n /** Run an engine step that replays recorded ops — undo, redo, goto, a\n * journal stepping. The engine inverts whole ops when one throws; this\n * also reverts the scene writes of the op that threw partway. */\n function replay(step: () => void): void {\n atomically(() => lifted(() => stale.during(() => engineDriven(step))), () => true);\n }\n\n function refuseUntracked(verb: string): void {\n if (mode.untracked()) throw new Error(`Scene: cannot ${verb} inside untracked() — it records`);\n }\n\n const { history, methods } = createSceneHistory({\n engine,\n applying: (step) => atomically(() => engineDriven(step), () => true),\n causing: outer.causing,\n replay,\n notify,\n refuseUntracked,\n runArrivalEdit: arrivals.runEdit,\n });\n\n return {\n ops,\n recorder,\n clearHistory: () => engine.clear(),\n methods: {\n registerOp(kind, handler) {\n if (kind.startsWith('kit:')) {\n throw new Error(`Scene: op kind \"${kind}\" is reserved (kit:* prefix)`);\n }\n ops.register(kind, handler as RegisteredOp<unknown>);\n },\n recordOp(op) {\n record(op.kind, op.payload, op.kind);\n },\n applyBatch(batch, label, adapter) {\n refuseUntracked('applyBatch');\n return arrivals.runEdit(batch, (all) => outer.apply(engine, all, label, adapter));\n },\n history,\n ...methods,\n batch: recorder.batch,\n untracked: recorder.untracked,\n setActiveJournalAccessor: outer.setActiveJournalAccessor,\n setHistoryAdapter: outer.setHistoryAdapter,\n },\n };\n}\n"],"mappings":";;;;;;;AA6CA,SAAgBA,EAAqB,GAAwC;CAC3E,IAAM,EAAE,aAAU,SAAM,UAAO,WAAQ,cAAW,aAAU,cAAWC,GACjE,EAAE,cAAWC,GAEbC,IAAMC,EAAc;EACxB,QAAQC,EAAK;EACb,cAAc,MAAS;GAAgB,AAAdC,EAAOC,CAAI,GAAGC,EAAO;EAAG;EACjD,OAAOC,EAAM;EAGb,UAAU,GAAM,GAAS,MAAa;GAAE,AAAKJ,EAAK,QAAQ,KAAGK,EAAWC,GAAMC,GAASC,CAAQ;EAAG;CACpG,CAAC,GAEKC,IAAQC,EAAe;EAC3B,MAAM,GAAM,MAAUZ,EAAI,SAAS,IAAIa,CAAI,IAAIb,EAAI,GAAGa,GAAMC,CAAI,IAAI;EACpE,gBAAgBC;EAGhB,UAAU,MAAShB,EAAS,eAAeG,EAAK,OAAO,gBAAgBc,EAAWZ,SAAY,EAAI,CAAC,CAAC;EACpG,kBAAkBa,EAAO,oBAAoB;CAC/C,CAAC,GAIKC,IAASC,EAAc,KAAA,GAAW;EACtC,WAAW;GAAE,KAAKC,EAAU;GAAK,MAAM,MAAQA,EAAU,IAAIC,CAAwB;EAAE;EACvF,GAAIJ,EAAO,qBAAqB,KAAA,IAA4D,CAAC,IAAjD,EAAE,kBAAkBA,EAAO,iBAAiB;EACxF,GAAIA,EAAO,iBAAiB,KAAA,IAAoD,CAAC,IAAzC,EAAE,cAAcA,EAAO,aAAa;EAC5E,WAAWN,EAAM;CACnB,CAAC,GAEKW,IAAMC,EAAiB;EAC3B,YAAYvB,EAAI;EAChB;EACA,cAAcoB,EAAU;EACxB,cAAcA,EAAU;EACxB;CACF,CAAC,GACK,EAAE,eAAY,kBAAeE,GAE7BP,IAAWS,EAAe;EAC9B;EACA;EACA;EACA,OAAOxB,EAAI;EACX,QAAQA,EAAI;EACZ;EACA;EACA,WAAWoB,EAAU;EACrB,WAAWtB,EAAI;CACjB,CAAC,GACK,EAAE,WAAQ,oBAAiBiB;CAKjC,SAASZ,EAAO,GAAwB;EACtC,QAAiBsB,QAAanB,EAAM,aAAaoB,EAAatB,CAAI,CAAC,CAAC,SAAS,EAAI;CACnF;CAEA,SAASuB,EAAgB,GAAoB;EAC3C,IAAIzB,EAAK,UAAU,GAAG,MAAU,MAAM,iBAAiB0B,EAAK,iCAAiC;CAC/F;CAEA,IAAM,EAAE,YAAS,eAAYC,EAAmB;EAC9C;EACA,WAAW,MAASb,QAAiBU,EAAatB,CAAI,SAAS,EAAI;EACnE,SAASO,EAAM;EACf;EACA;EACA;EACA,gBAAgBmB,EAAS;
|
|
1
|
+
{"version":3,"file":"sceneRecording.js","names":["createSceneRecording","env","notifier","ops","createOpTable","mode","replay","step","notify","stale","logApplied","kind","payload","reverted","outer","createOuterOps","name","args","recorder","atomically","config","engine","createHistory","selection","ids","log","createAppliedLog","createRecorder","lifted","engineDriven","refuseUntracked","verb","createSceneHistory","arrivals","handler","op","batch","all","label","adapter","methods"],"sources":["../../../src/core/scene/sceneRecording.ts"],"sourcesContent":["/**\n * How a scene's edits reach its undo stack: the op table, the log that takes\n * back an edit refused partway, the engine, and the recorder between them.\n */\nimport type { Journal } from '@weasel-js/history';\nimport { createHistory } from 'core/ops/createHistory';\nimport { createAppliedLog } from './appliedLog';\nimport type { ArrivalWindow } from './arrivalWindow';\nimport type { EditMode } from './editMode';\nimport { createSceneHistory, type SceneHistoryMethods } from './historyFacade';\nimport type { Notifier } from './notifier';\nimport { createOpTable, type OpTable } from './opTable';\nimport { createOuterOps } from './outerOps';\nimport { createRecorder, type Recorder, type RecorderEnv } from './recorder';\nimport type { SceneSelection } from './sceneSelection';\nimport type { StaleReplay } from './staleReplay';\nimport type { NodeId, RegisteredOp, Scene } from './types';\n\nexport interface SceneRecordingEnv {\n notifier: Notifier;\n mode: EditMode;\n stale: StaleReplay;\n /** Run with the lock guard lifted. */\n lifted<T>(fn: () => T): T;\n selection: Pick<SceneSelection, 'get' | 'set' | 'replace'>;\n arrivals: RecorderEnv['arrivals'] & Pick<ArrivalWindow<unknown>, 'runEdit'>;\n writePose(id: string, pose: unknown): void;\n config: {\n getActiveJournal?: (() => Journal | null) | undefined;\n coalesceWindowMs?: number | undefined;\n historyLimit?: number | undefined;\n };\n}\n\nexport interface SceneRecording {\n ops: Pick<OpTable, 'register' | 'run'>;\n recorder: Recorder;\n clearHistory(): void;\n methods: SceneHistoryMethods & Pick<\n Scene<unknown, string, unknown>,\n | 'registerOp' | 'recordOp' | 'applyBatch' | 'history' | 'batch' | 'untracked'\n | 'setActiveJournalAccessor' | 'setHistoryAdapter'\n >;\n}\n\nexport function createSceneRecording(env: SceneRecordingEnv): SceneRecording {\n const { notifier, mode, stale, lifted, selection, arrivals, config } = env;\n const { notify } = notifier;\n\n const ops = createOpTable({\n driven: mode.open,\n replayAlone: (step) => { replay(step); notify(); },\n skips: stale.skips,\n // Only a replay is logged: a first apply is recorded by the entry it\n // creates, and reverting it would leave that entry describing nothing.\n applied: (kind, payload, reverted) => { if (!mode.records()) logApplied(kind, payload, reverted); },\n });\n\n const outer = createOuterOps({\n own: (name, args) => (ops.handlers.has(name) ? ops.op(name, args) : null),\n recorder: () => recorder,\n // Deferred rather than muted, so a throwing op cannot strand subscribers\n // after earlier ops in the batch already mutated state.\n driving: (step) => notifier.deferred(() => mode.during('engine', () => atomically(step, () => true))),\n getActiveJournal: config.getActiveJournal ?? null,\n });\n\n // The scene's undo/redo engine. Its recorded ops close over their payloads,\n // so the engine's adapter argument is unused.\n const engine = createHistory(undefined, {\n selection: { get: selection.get, set: (ids) => selection.set(ids as readonly NodeId[]) },\n ...(config.coalesceWindowMs !== undefined ? { coalesceWindowMs: config.coalesceWindowMs } : {}),\n ...(config.historyLimit !== undefined ? { historyLimit: config.historyLimit } : {}),\n rebuildOp: outer.rebuild,\n });\n\n const log = createAppliedLog({\n registered: ops.handlers,\n lifted,\n getSelection: selection.get,\n setSelection: selection.replace,\n notify,\n });\n const { atomically, logApplied } = log;\n\n const recorder = createRecorder({\n notifier,\n mode,\n engine,\n runOp: ops.run,\n makeOp: ops.op,\n log,\n arrivals,\n selection: selection.get,\n writePose: env.writePose,\n });\n const { record, engineDriven } = recorder;\n\n /** Run an engine step that replays recorded ops — undo, redo, goto, a\n * journal stepping. The engine inverts whole ops when one throws; this\n * also reverts the scene writes of the op that threw partway. */\n function replay(step: () => void): void {\n atomically(() => lifted(() => stale.during(() => engineDriven(step))), () => true);\n }\n\n function refuseUntracked(verb: string): void {\n if (mode.untracked()) throw new Error(`Scene: cannot ${verb} inside untracked() — it records`);\n }\n\n const { history, methods } = createSceneHistory({\n engine,\n applying: (step) => atomically(() => engineDriven(step), () => true),\n causing: outer.causing,\n replay,\n notify,\n refuseUntracked,\n runArrivalEdit: arrivals.runEdit,\n activeJournal: outer.activeJournal,\n });\n\n return {\n ops,\n recorder,\n clearHistory: () => engine.clear(),\n methods: {\n registerOp(kind, handler) {\n if (kind.startsWith('kit:')) {\n throw new Error(`Scene: op kind \"${kind}\" is reserved (kit:* prefix)`);\n }\n ops.register(kind, handler as RegisteredOp<unknown>);\n },\n recordOp(op) {\n record(op.kind, op.payload, op.kind);\n },\n applyBatch(batch, label, adapter) {\n refuseUntracked('applyBatch');\n return arrivals.runEdit(batch, (all) => outer.apply(engine, all, label, adapter));\n },\n history,\n ...methods,\n batch: recorder.batch,\n untracked: recorder.untracked,\n setActiveJournalAccessor: outer.setActiveJournalAccessor,\n setHistoryAdapter: outer.setHistoryAdapter,\n },\n };\n}\n"],"mappings":";;;;;;;AA6CA,SAAgBA,EAAqB,GAAwC;CAC3E,IAAM,EAAE,aAAU,SAAM,UAAO,WAAQ,cAAW,aAAU,cAAWC,GACjE,EAAE,cAAWC,GAEbC,IAAMC,EAAc;EACxB,QAAQC,EAAK;EACb,cAAc,MAAS;GAAgB,AAAdC,EAAOC,CAAI,GAAGC,EAAO;EAAG;EACjD,OAAOC,EAAM;EAGb,UAAU,GAAM,GAAS,MAAa;GAAE,AAAKJ,EAAK,QAAQ,KAAGK,EAAWC,GAAMC,GAASC,CAAQ;EAAG;CACpG,CAAC,GAEKC,IAAQC,EAAe;EAC3B,MAAM,GAAM,MAAUZ,EAAI,SAAS,IAAIa,CAAI,IAAIb,EAAI,GAAGa,GAAMC,CAAI,IAAI;EACpE,gBAAgBC;EAGhB,UAAU,MAAShB,EAAS,eAAeG,EAAK,OAAO,gBAAgBc,EAAWZ,SAAY,EAAI,CAAC,CAAC;EACpG,kBAAkBa,EAAO,oBAAoB;CAC/C,CAAC,GAIKC,IAASC,EAAc,KAAA,GAAW;EACtC,WAAW;GAAE,KAAKC,EAAU;GAAK,MAAM,MAAQA,EAAU,IAAIC,CAAwB;EAAE;EACvF,GAAIJ,EAAO,qBAAqB,KAAA,IAA4D,CAAC,IAAjD,EAAE,kBAAkBA,EAAO,iBAAiB;EACxF,GAAIA,EAAO,iBAAiB,KAAA,IAAoD,CAAC,IAAzC,EAAE,cAAcA,EAAO,aAAa;EAC5E,WAAWN,EAAM;CACnB,CAAC,GAEKW,IAAMC,EAAiB;EAC3B,YAAYvB,EAAI;EAChB;EACA,cAAcoB,EAAU;EACxB,cAAcA,EAAU;EACxB;CACF,CAAC,GACK,EAAE,eAAY,kBAAeE,GAE7BP,IAAWS,EAAe;EAC9B;EACA;EACA;EACA,OAAOxB,EAAI;EACX,QAAQA,EAAI;EACZ;EACA;EACA,WAAWoB,EAAU;EACrB,WAAWtB,EAAI;CACjB,CAAC,GACK,EAAE,WAAQ,oBAAiBiB;CAKjC,SAASZ,EAAO,GAAwB;EACtC,QAAiBsB,QAAanB,EAAM,aAAaoB,EAAatB,CAAI,CAAC,CAAC,SAAS,EAAI;CACnF;CAEA,SAASuB,EAAgB,GAAoB;EAC3C,IAAIzB,EAAK,UAAU,GAAG,MAAU,MAAM,iBAAiB0B,EAAK,iCAAiC;CAC/F;CAEA,IAAM,EAAE,YAAS,eAAYC,EAAmB;EAC9C;EACA,WAAW,MAASb,QAAiBU,EAAatB,CAAI,SAAS,EAAI;EACnE,SAASO,EAAM;EACf;EACA;EACA;EACA,gBAAgBmB,EAAS;EACzB,eAAenB,EAAM;CACvB,CAAC;CAED,OAAO;EACL;EACA;EACA,oBAAoBO,EAAO,MAAM;EACjC,SAAS;GACP,WAAW,GAAM,GAAS;IACxB,IAAIV,EAAK,WAAW,MAAM,GACxB,MAAU,MAAM,mBAAmBA,EAAK,6BAA6B;IAEvE,EAAI,SAASA,GAAMuB,CAAgC;GACrD;GACA,SAAS,GAAI;IACX,EAAOC,EAAG,MAAMA,EAAG,SAASA,EAAG,IAAI;GACrC;GACA,WAAW,GAAO,GAAO,GAAS;IAEhC,OADAL,EAAgB,YAAY,GACrBG,EAAS,QAAQG,IAAQ,MAAQtB,EAAM,MAAMO,GAAQgB,GAAKC,GAAOC,CAAO,CAAC;GAClF;GACA;GACA,GAAGC;GACH,OAAOtB,EAAS;GAChB,WAAWA,EAAS;GACpB,0BAA0BJ,EAAM;GAChC,mBAAmBA,EAAM;EAC3B;CACF;AACF"}
|