@weasel-js/core 1.11.1 → 1.13.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +275 -0
- package/dist/WeaselProvider.js +1 -1
- package/dist/affordances/pathAnchors.js +10 -6
- package/dist/affordances/pathAnchors.js.map +1 -1
- package/dist/animation/poseTarget.js +46 -15
- package/dist/animation/poseTarget.js.map +1 -1
- package/dist/animation/poseTransition.js +3 -3
- package/dist/animation/poseTransition.js.map +1 -1
- package/dist/animation/reflow.js +3 -6
- package/dist/animation/reflow.js.map +1 -1
- package/dist/animation/rig/bindRig.js +2 -2
- package/dist/animation/rig/bindRig.js.map +1 -1
- package/dist/animation/rig/skinBinding.js +2 -2
- package/dist/animation/rig/skinBinding.js.map +1 -1
- package/dist/barrel/canvas.js +5 -1
- package/dist/barrel/chrome.js +3 -1
- package/dist/barrel/paint.js +4 -4
- package/dist/barrel/paths.js +9 -4
- package/dist/barrel/renderer.js +3 -2
- package/dist/barrel/routing.js +4 -4
- package/dist/barrel/scene.js +7 -1
- package/dist/barrel/text.js +2 -2
- package/dist/barrel/viewport.js +6 -2
- package/dist/canvas/Canvas.js +2 -1
- package/dist/canvas/Canvas.js.map +1 -1
- package/dist/canvas/CanvasView.js +23 -34
- package/dist/canvas/CanvasView.js.map +1 -1
- package/dist/canvas/ModalityHud.js +1 -1
- package/dist/canvas/NodeShape.js +5 -1
- package/dist/canvas/NodeShape.js.map +1 -1
- package/dist/canvas/SceneCanvas/ActionsProviderIfRoot.js +1 -1
- package/dist/canvas/SceneCanvas/DepRegistryProviderIfRoot.js +1 -1
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +1 -1
- package/dist/canvas/SceneCanvas/SceneCanvasInput.js +2 -0
- package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
- package/dist/canvas/SceneCanvas/SurfaceDeclarations.js +23 -0
- package/dist/canvas/SceneCanvas/SurfaceDeclarations.js.map +1 -0
- package/dist/canvas/SceneCanvas/canvasPassThrough.js +2 -1
- package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js +2 -2
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
- package/dist/canvas/SceneCanvas/props.js.map +1 -1
- package/dist/canvas/SceneCanvas/scenePointQuery.js +27 -5
- package/dist/canvas/SceneCanvas/scenePointQuery.js.map +1 -1
- package/dist/canvas/SceneCanvas/useActionTunings.js +6 -1
- package/dist/canvas/SceneCanvas/useActionTunings.js.map +1 -1
- package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js +1 -0
- package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js.map +1 -1
- package/dist/canvas/SceneCanvas/useCanvasTools.js +10 -2
- package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js +25 -19
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js +9 -3
- package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +17 -2
- package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +2 -0
- package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js +19 -4
- package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js.map +1 -1
- package/dist/canvas/SceneCanvas/useScenePicking.js +31 -6
- package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js +4 -5
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneStandardActions.js +7 -4
- package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
- package/dist/canvas/SceneCanvas.js +30 -12
- package/dist/canvas/SceneCanvas.js.map +1 -1
- package/dist/canvas/ViewMarker.js +35 -0
- package/dist/canvas/ViewMarker.js.map +1 -0
- package/dist/canvas/accentColor.js +26 -3
- package/dist/canvas/accentColor.js.map +1 -1
- package/dist/canvas/buildSceneTree.js +14 -20
- package/dist/canvas/buildSceneTree.js.map +1 -1
- package/dist/canvas/copiesAbove.js +1 -1
- package/dist/canvas/copiesAbove.js.map +1 -1
- package/dist/canvas/defaultDrawOne.js +11 -6
- package/dist/canvas/defaultDrawOne.js.map +1 -1
- package/dist/canvas/deps/areaSelect.js +5 -2
- package/dist/canvas/deps/areaSelect.js.map +1 -1
- package/dist/canvas/deps/booleans.js +3 -2
- package/dist/canvas/deps/booleans.js.map +1 -1
- package/dist/canvas/deps/enteredGroup.js +81 -0
- package/dist/canvas/deps/enteredGroup.js.map +1 -0
- package/dist/canvas/deps/hitTestArea.js +28 -16
- package/dist/canvas/deps/hitTestArea.js.map +1 -1
- package/dist/canvas/deps/insert.js +10 -38
- package/dist/canvas/deps/insert.js.map +1 -1
- package/dist/canvas/deps/insertSite.js +39 -0
- package/dist/canvas/deps/insertSite.js.map +1 -0
- package/dist/canvas/deps/lassoSelect.js +6 -3
- package/dist/canvas/deps/lassoSelect.js.map +1 -1
- package/dist/canvas/deps/pathEditCommits.js +3 -7
- package/dist/canvas/deps/pathEditCommits.js.map +1 -1
- package/dist/canvas/deps/pathLeaf.js +1 -1
- package/dist/canvas/deps/pathLeaf.js.map +1 -1
- package/dist/canvas/deps/slice.js +2 -1
- package/dist/canvas/deps/slice.js.map +1 -1
- package/dist/canvas/derivedPath.js +14 -6
- package/dist/canvas/derivedPath.js.map +1 -1
- package/dist/canvas/doubleClickTarget.js +9 -11
- package/dist/canvas/doubleClickTarget.js.map +1 -1
- package/dist/canvas/drawnBounds.js +26 -9
- package/dist/canvas/drawnBounds.js.map +1 -1
- package/dist/canvas/inheritedPaints.js +55 -0
- package/dist/canvas/inheritedPaints.js.map +1 -0
- package/dist/canvas/nodeShapes/derivedPainter.js +15 -16
- package/dist/canvas/nodeShapes/derivedPainter.js.map +1 -1
- package/dist/canvas/nodeShapes/nodePaint.js +7 -34
- package/dist/canvas/nodeShapes/nodePaint.js.map +1 -1
- package/dist/canvas/nodeShapes/pathPainter.js +7 -7
- package/dist/canvas/nodeShapes/pathPainter.js.map +1 -1
- package/dist/canvas/nodeShapes/rectFallbackPainter.js +4 -5
- package/dist/canvas/nodeShapes/rectFallbackPainter.js.map +1 -1
- package/dist/canvas/nodeShapes/shapePainter.js +9 -9
- package/dist/canvas/nodeShapes/shapePainter.js.map +1 -1
- package/dist/canvas/nodeShapes/textPainter.js +13 -12
- package/dist/canvas/nodeShapes/textPainter.js.map +1 -1
- package/dist/canvas/ownClip.js +24 -0
- package/dist/canvas/ownClip.js.map +1 -0
- package/dist/canvas/paintCull.js.map +1 -1
- package/dist/canvas/pickIndex/nodeBroadBox.js +86 -0
- package/dist/canvas/pickIndex/nodeBroadBox.js.map +1 -0
- package/dist/canvas/pickIndex/scenePickIndex.js +208 -0
- package/dist/canvas/pickIndex/scenePickIndex.js.map +1 -0
- package/dist/canvas/pickReach.js +3 -3
- package/dist/canvas/pickReach.js.map +1 -1
- package/dist/canvas/pickWalk.js +17 -91
- package/dist/canvas/pickWalk.js.map +1 -1
- package/dist/canvas/poseCascade.js +1 -1
- package/dist/canvas/poseCascade.js.map +1 -1
- package/dist/canvas/publishPreviews.js +97 -0
- package/dist/canvas/publishPreviews.js.map +1 -0
- package/dist/canvas/renderSceneToPixels.js +1 -1
- package/dist/canvas/renderSceneToPixels.js.map +1 -1
- package/dist/canvas/sceneAdapter.js +7 -5
- package/dist/canvas/sceneAdapter.js.map +1 -1
- package/dist/canvas/sceneClipboard.js +17 -10
- package/dist/canvas/sceneClipboard.js.map +1 -1
- package/dist/canvas/scenePickReads.js +37 -0
- package/dist/canvas/scenePickReads.js.map +1 -0
- package/dist/canvas/scenePickSource.js +74 -0
- package/dist/canvas/scenePickSource.js.map +1 -0
- package/dist/canvas/sceneSlotWiring.js +9 -3
- package/dist/canvas/sceneSlotWiring.js.map +1 -1
- package/dist/canvas/sceneViewRender.js +9 -4
- package/dist/canvas/sceneViewRender.js.map +1 -1
- package/dist/canvas/shownNodes.js +15 -0
- package/dist/canvas/shownNodes.js.map +1 -0
- package/dist/canvas/surfaceContribution.js +12 -8
- package/dist/canvas/surfaceContribution.js.map +1 -1
- package/dist/canvas/useCanvasView.js +4 -2
- package/dist/canvas/useCanvasView.js.map +1 -1
- package/dist/canvas/useLayerStack.js +6 -2
- package/dist/canvas/useLayerStack.js.map +1 -1
- package/dist/canvas/useSceneAdapter.js +5 -3
- package/dist/canvas/useSceneAdapter.js.map +1 -1
- package/dist/canvas/useViewAim.js +121 -0
- package/dist/canvas/useViewAim.js.map +1 -0
- package/dist/canvas/useViewNesting.js +3 -2
- package/dist/canvas/useViewNesting.js.map +1 -1
- package/dist/canvas/useViewRegistrySurface.js +4 -2
- package/dist/canvas/useViewRegistrySurface.js.map +1 -1
- package/dist/canvas/viewMarkers.js +63 -0
- package/dist/canvas/viewMarkers.js.map +1 -0
- package/dist/canvas/viewRegistry.js +27 -1
- package/dist/canvas/viewRegistry.js.map +1 -1
- package/dist/clipboard.d.ts +2 -2
- package/dist/{clone-C3e0OTuF.d.ts → clone-qb2e1F5p.d.ts} +2 -2
- package/dist/clone.d.ts +3 -3
- package/dist/core/isPlainObject.js +2 -2
- package/dist/core/layers/layerGroup.js.map +1 -1
- package/dist/core/pages/pageEdits.js +2 -3
- package/dist/core/pages/pageEdits.js.map +1 -1
- package/dist/core/paint/meshKindLazy.js +59 -2
- package/dist/core/paint/meshKindLazy.js.map +1 -1
- package/dist/core/scene/NodeRouting.js.map +1 -1
- package/dist/core/scene/arrivalWindow.js +1 -1
- package/dist/core/scene/arrivalWindow.js.map +1 -1
- package/dist/core/scene/clipNothing.js +10 -0
- package/dist/core/scene/clipNothing.js.map +1 -0
- package/dist/core/scene/declaredFieldSetters.js +44 -0
- package/dist/core/scene/declaredFieldSetters.js.map +1 -0
- package/dist/core/scene/depMemo.js +14 -3
- package/dist/core/scene/depMemo.js.map +1 -1
- package/dist/core/scene/dependents.js +9 -1
- package/dist/core/scene/dependents.js.map +1 -1
- package/dist/core/scene/derivedParts.js +10 -11
- package/dist/core/scene/derivedParts.js.map +1 -1
- package/dist/core/scene/documentOf.js +43 -0
- package/dist/core/scene/documentOf.js.map +1 -0
- package/dist/core/scene/effectivePose.js +44 -15
- package/dist/core/scene/effectivePose.js.map +1 -1
- package/dist/core/scene/fieldEdits.js +17 -14
- package/dist/core/scene/fieldEdits.js.map +1 -1
- package/dist/core/scene/fontReads.js +37 -0
- package/dist/core/scene/fontReads.js.map +1 -0
- package/dist/core/scene/historyForm.js +4 -4
- package/dist/core/scene/historyForm.js.map +1 -1
- package/dist/core/scene/inheritedPaint.js +97 -0
- package/dist/core/scene/inheritedPaint.js.map +1 -0
- package/dist/core/scene/kitOps.js +3 -23
- package/dist/core/scene/kitOps.js.map +1 -1
- package/dist/core/scene/kitRegistry.js +5 -0
- package/dist/core/scene/kitRegistry.js.map +1 -1
- package/dist/core/scene/layoutPass.js +1 -2
- package/dist/core/scene/layoutPass.js.map +1 -1
- package/dist/core/scene/nodeAsShown.js +72 -0
- package/dist/core/scene/nodeAsShown.js.map +1 -0
- package/dist/core/scene/nodeFnFields.js +2 -10
- package/dist/core/scene/nodeFnFields.js.map +1 -1
- package/dist/core/scene/nodeMemo.js +21 -8
- package/dist/core/scene/nodeMemo.js.map +1 -1
- package/dist/core/scene/nodeStore.js +2 -4
- package/dist/core/scene/nodeStore.js.map +1 -1
- package/dist/core/scene/pathEffects/blend.js.map +1 -1
- package/dist/core/scene/pathEffects/derive.js +10 -4
- package/dist/core/scene/pathEffects/derive.js.map +1 -1
- package/dist/core/scene/pathEffects/effects.js +3 -1
- package/dist/core/scene/pathEffects/effects.js.map +1 -1
- package/dist/core/scene/pathEffects/foundHidden.js +35 -0
- package/dist/core/scene/pathEffects/foundHidden.js.map +1 -0
- package/dist/core/scene/pathEffects/textAlong.js +95 -0
- package/dist/core/scene/pathEffects/textAlong.js.map +1 -0
- package/dist/core/scene/plyStacks.js +89 -0
- package/dist/core/scene/plyStacks.js.map +1 -0
- package/dist/core/scene/poseHold.js +42 -24
- package/dist/core/scene/poseHold.js.map +1 -1
- package/dist/core/scene/poseOverrides.js +35 -38
- package/dist/core/scene/poseOverrides.js.map +1 -1
- package/dist/core/scene/posePlies.js +59 -0
- package/dist/core/scene/posePlies.js.map +1 -0
- package/dist/core/scene/reconcileSpecs.js +6 -15
- package/dist/core/scene/reconcileSpecs.js.map +1 -1
- package/dist/core/scene/renderOrder.js +10 -4
- package/dist/core/scene/renderOrder.js.map +1 -1
- package/dist/core/scene/sameValue.js +17 -0
- package/dist/core/scene/sameValue.js.map +1 -0
- package/dist/core/scene/scene.js +3 -3
- package/dist/core/scene/scene.js.map +1 -1
- package/dist/core/scene/sceneEdits.js +8 -0
- package/dist/core/scene/sceneEdits.js.map +1 -1
- package/dist/core/scene/sceneState.js +1 -2
- package/dist/core/scene/sceneState.js.map +1 -1
- package/dist/core/scene/serialization.js +45 -9
- package/dist/core/scene/serialization.js.map +1 -1
- package/dist/core/scene/staleReplay.js +5 -2
- package/dist/core/scene/staleReplay.js.map +1 -1
- package/dist/core/scene/statedFields.js +4 -2
- package/dist/core/scene/statedFields.js.map +1 -1
- package/dist/core/scene/treeEdits.js +2 -4
- package/dist/core/scene/treeEdits.js.map +1 -1
- package/dist/core/scene/treeOrder.js +3 -1
- package/dist/core/scene/treeOrder.js.map +1 -1
- package/dist/core/scene/treeReads.js +1 -2
- package/dist/core/scene/treeReads.js.map +1 -1
- package/dist/core/scene/treeShape.js +13 -0
- package/dist/core/scene/treeShape.js.map +1 -0
- package/dist/core/scene/types.js.map +1 -1
- package/dist/core/scene/useScene.js +1 -1
- package/dist/core/scene/useScene.js.map +1 -1
- package/dist/{cornerHandles-BHuoMs1o.d.ts → cornerHandles-CNCb7aTY.d.ts} +3 -2
- package/dist/{depSchema-BpZNOv7q.d.ts → depSchema-B1RS-IJx.d.ts} +39 -18
- package/dist/devtools/handlers.js +1 -1
- package/dist/devtools/handlers.js.map +1 -1
- package/dist/devtools/protocol.js.map +1 -1
- package/dist/devtools/registry.js +4 -4
- package/dist/devtools/registry.js.map +1 -1
- package/dist/devtools-protocol.d.ts +4 -3
- package/dist/devtools.d.ts +3 -2
- package/dist/features/measure/measureContribution.js +4 -2
- package/dist/features/measure/measureContribution.js.map +1 -1
- package/dist/features/measure/measureHit.js +5 -3
- package/dist/features/measure/measureHit.js.map +1 -1
- package/dist/features/measure/measurement.js +1 -1
- package/dist/features/measure/measurement.js.map +1 -1
- package/dist/features/modes/modeLayers.js +14 -7
- package/dist/features/modes/modeLayers.js.map +1 -1
- package/dist/features/modes/modeTriggers.js +10 -6
- package/dist/features/modes/modeTriggers.js.map +1 -1
- package/dist/features/pathEffects/effectSources.js +69 -0
- package/dist/features/pathEffects/effectSources.js.map +1 -0
- package/dist/features/pathEffects/readSource.js +18 -2
- package/dist/features/pathEffects/readSource.js.map +1 -1
- package/dist/features/pathEffects/textItems.js +53 -0
- package/dist/features/pathEffects/textItems.js.map +1 -0
- package/dist/features/pathEffects/useEffectSourcesLayer.js +53 -0
- package/dist/features/pathEffects/useEffectSourcesLayer.js.map +1 -0
- package/dist/features/paths/editablePath.js +1 -1
- package/dist/features/paths/editablePath.js.map +1 -1
- package/dist/features/paths/pathEditState.js +5 -2
- package/dist/features/paths/pathEditState.js.map +1 -1
- package/dist/features/paths/pathSnap/sceneIndex.js +1 -1
- package/dist/features/paths/pathSnap/sceneIndex.js.map +1 -1
- package/dist/features/selection/enteredGroupFrame.js +65 -0
- package/dist/features/selection/enteredGroupFrame.js.map +1 -0
- package/dist/features/selection/enteredGroupScope.js +44 -0
- package/dist/features/selection/enteredGroupScope.js.map +1 -0
- package/dist/features/text/sceneTextDrafts.js +64 -0
- package/dist/features/text/sceneTextDrafts.js.map +1 -0
- package/dist/features/text/textHitAt.js +34 -3
- package/dist/features/text/textHitAt.js.map +1 -1
- package/dist/features/text/useSceneTextEdit.js +23 -19
- package/dist/features/text/useSceneTextEdit.js.map +1 -1
- package/dist/features/viewports/aim.js +105 -0
- package/dist/features/viewports/aim.js.map +1 -0
- package/dist/features/viewports/viewMarker.js +82 -0
- package/dist/features/viewports/viewMarker.js.map +1 -0
- package/dist/features/viewports/viewMarkerDrag.js +55 -0
- package/dist/features/viewports/viewMarkerDrag.js.map +1 -0
- package/dist/index.d.ts +709 -258
- package/dist/index.js +33 -12
- package/dist/interactions/actions/admitsChild.js +11 -0
- package/dist/interactions/actions/admitsChild.js.map +1 -0
- package/dist/interactions/actions/booleans/booleans.js +2 -1
- package/dist/interactions/actions/booleans/booleans.js.map +1 -1
- package/dist/interactions/actions/booleans/operands.js +6 -5
- package/dist/interactions/actions/booleans/operands.js.map +1 -1
- package/dist/interactions/actions/clipboard/action.js +27 -17
- package/dist/interactions/actions/clipboard/action.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorEditing.js +44 -23
- package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorJoin.js +12 -6
- package/dist/interactions/actions/defaults/anchorJoin.js.map +1 -1
- package/dist/interactions/actions/defaults/bendSegment.js +7 -4
- package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
- package/dist/interactions/actions/defaults/cancelGesture.js +11 -8
- package/dist/interactions/actions/defaults/cancelGesture.js.map +1 -1
- package/dist/interactions/actions/defaults/contextMenu.js +33 -11
- package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
- package/dist/interactions/actions/defaults/createPaintAction.js +5 -2
- package/dist/interactions/actions/defaults/createPaintAction.js.map +1 -1
- package/dist/interactions/actions/defaults/delete.js +28 -14
- package/dist/interactions/actions/defaults/delete.js.map +1 -1
- package/dist/interactions/actions/defaults/duplicate.js +11 -8
- package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
- package/dist/interactions/actions/defaults/enterGroup.js +88 -0
- package/dist/interactions/actions/defaults/enterGroup.js.map +1 -0
- package/dist/interactions/actions/defaults/enterPathEdit.js +20 -10
- package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/enterTextEdit.js +1 -1
- package/dist/interactions/actions/defaults/enterTextEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/escape.js +11 -8
- package/dist/interactions/actions/defaults/escape.js.map +1 -1
- package/dist/interactions/actions/defaults/exitPathEdit.js +7 -4
- package/dist/interactions/actions/defaults/exitPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/group.js +26 -20
- package/dist/interactions/actions/defaults/group.js.map +1 -1
- package/dist/interactions/actions/defaults/ingest.js +10 -4
- package/dist/interactions/actions/defaults/ingest.js.map +1 -1
- package/dist/interactions/actions/defaults/insertPathAnchor.js +7 -4
- package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
- package/dist/interactions/actions/defaults/nudge.js +8 -2
- package/dist/interactions/actions/defaults/nudge.js.map +1 -1
- package/dist/interactions/actions/defaults/pathEditTools.js +11 -8
- package/dist/interactions/actions/defaults/pathEditTools.js.map +1 -1
- package/dist/interactions/actions/defaults/pinchZoom.js +7 -4
- package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
- package/dist/interactions/actions/defaults/reorder.js +24 -6
- package/dist/interactions/actions/defaults/reorder.js.map +1 -1
- package/dist/interactions/actions/defaults/selectAll.js +15 -8
- package/dist/interactions/actions/defaults/selectAll.js.map +1 -1
- package/dist/interactions/actions/defaults/selectDeep.js +35 -0
- package/dist/interactions/actions/defaults/selectDeep.js.map +1 -0
- package/dist/interactions/actions/defaults/setFill.js +7 -3
- package/dist/interactions/actions/defaults/setFill.js.map +1 -1
- package/dist/interactions/actions/defaults/setFillOpacity.js +1 -1
- package/dist/interactions/actions/defaults/setStroke.js +12 -11
- package/dist/interactions/actions/defaults/setStroke.js.map +1 -1
- package/dist/interactions/actions/defaults/setStrokeOpacity.js +1 -1
- package/dist/interactions/actions/defaults/toolActivate.js +7 -1
- package/dist/interactions/actions/defaults/toolActivate.js.map +1 -1
- package/dist/interactions/actions/defaults/toolResetToDefault.js +7 -4
- package/dist/interactions/actions/defaults/toolResetToDefault.js.map +1 -1
- package/dist/interactions/actions/defaults/undoRedo.js +19 -13
- package/dist/interactions/actions/defaults/undoRedo.js.map +1 -1
- package/dist/interactions/actions/defaults/viewportWheelPan.js +16 -7
- package/dist/interactions/actions/defaults/viewportWheelPan.js.map +1 -1
- package/dist/interactions/actions/defaults/viewportZoom.js +24 -6
- package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
- package/dist/interactions/actions/drawnBoxes.js +2 -1
- package/dist/interactions/actions/drawnBoxes.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/action.js +7 -4
- package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
- package/dist/interactions/actions/flip/action.js +8 -2
- package/dist/interactions/actions/flip/action.js.map +1 -1
- package/dist/interactions/actions/insert/action.js +1 -0
- package/dist/interactions/actions/insert/action.js.map +1 -1
- package/dist/interactions/actions/insert/parent.js +7 -5
- package/dist/interactions/actions/insert/parent.js.map +1 -1
- package/dist/interactions/actions/insert/placeAction.js +3 -2
- package/dist/interactions/actions/insert/placeAction.js.map +1 -1
- package/dist/interactions/actions/insert/repositionAction.js +2 -1
- package/dist/interactions/actions/insert/repositionAction.js.map +1 -1
- package/dist/interactions/actions/insert/session.js +2 -2
- package/dist/interactions/actions/insert/session.js.map +1 -1
- package/dist/interactions/actions/move/action.js +7 -4
- package/dist/interactions/actions/move/action.js.map +1 -1
- package/dist/interactions/actions/move/commit/reparent.js +1 -1
- package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
- package/dist/interactions/actions/move/gestureAdapter.js +6 -7
- package/dist/interactions/actions/move/gestureAdapter.js.map +1 -1
- package/dist/interactions/actions/move/layout/exits.js +1 -1
- package/dist/interactions/actions/move/layout/exits.js.map +1 -1
- package/dist/interactions/actions/move/session.js +4 -4
- package/dist/interactions/actions/move/session.js.map +1 -1
- package/dist/interactions/actions/outlines/createOutlinesAction.js +8 -5
- package/dist/interactions/actions/outlines/createOutlinesAction.js.map +1 -1
- package/dist/interactions/actions/outlines/outlineStroke.js +5 -3
- package/dist/interactions/actions/outlines/outlineStroke.js.map +1 -1
- package/dist/interactions/actions/pathCommands/cutJoin.js +8 -5
- package/dist/interactions/actions/pathCommands/cutJoin.js.map +1 -1
- package/dist/interactions/actions/pathCommands/pathNodes.js +14 -5
- package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -1
- package/dist/interactions/actions/resize/cornerHandles.js +2 -1
- package/dist/interactions/actions/resize/cornerHandles.js.map +1 -1
- package/dist/interactions/actions/selectionSubtree.js +12 -7
- package/dist/interactions/actions/selectionSubtree.js.map +1 -1
- package/dist/interactions/actions/transform-again/action.js +8 -5
- package/dist/interactions/actions/transform-again/action.js.map +1 -1
- package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js +14 -2
- package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js.map +1 -1
- package/dist/json.d.ts +4 -0
- package/dist/json.js +3 -0
- package/dist/kitSettingsSchema.js +8 -1
- package/dist/kitSettingsSchema.js.map +1 -1
- package/dist/{math-CrJULaZI.d.ts → math-C_elShP_.d.ts} +7 -1
- package/dist/math.d.ts +1 -1
- package/dist/math.js +2 -1
- package/dist/move.d.ts +4 -4
- package/dist/{options-DBxEryYq.d.ts → options-ClEm3SEl.d.ts} +1 -1
- package/dist/resize.d.ts +4 -4
- package/dist/test-seams.d.ts +6 -6
- package/dist/tools/builtin/ellipse/useEllipseTool.js +1 -0
- package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
- package/dist/tools/builtin/eyedropper/useEyedropperTool.js +2 -1
- package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
- package/dist/tools/builtin/hand/dragPanContribution.js +4 -1
- package/dist/tools/builtin/hand/dragPanContribution.js.map +1 -1
- package/dist/tools/builtin/hand/useHandTool.js +7 -4
- package/dist/tools/builtin/hand/useHandTool.js.map +1 -1
- package/dist/tools/builtin/image/useImageTool.js +1 -0
- package/dist/tools/builtin/image/useImageTool.js.map +1 -1
- package/dist/tools/builtin/lasso/useLassoTool.js +1 -0
- package/dist/tools/builtin/lasso/useLassoTool.js.map +1 -1
- package/dist/tools/builtin/line/useLineTool.js +1 -0
- package/dist/tools/builtin/line/useLineTool.js.map +1 -1
- package/dist/tools/builtin/measure/useMeasureTool.js +12 -5
- package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
- package/dist/tools/builtin/pen/usePenTool.js +14 -6
- package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
- package/dist/tools/builtin/pencil/usePencilTool.js +1 -0
- package/dist/tools/builtin/pencil/usePencilTool.js.map +1 -1
- package/dist/tools/builtin/polygon/usePolygonTool.js +13 -4
- package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
- package/dist/tools/builtin/pressTarget.js +22 -0
- package/dist/tools/builtin/pressTarget.js.map +1 -0
- package/dist/tools/builtin/rect/useRectTool.js +1 -0
- package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
- package/dist/tools/builtin/select/adapterPointQuery.js +6 -5
- package/dist/tools/builtin/select/adapterPointQuery.js.map +1 -1
- package/dist/tools/builtin/select/collapseDeferred.js +40 -0
- package/dist/tools/builtin/select/collapseDeferred.js.map +1 -0
- package/dist/tools/builtin/select/groupEntry.js +82 -0
- package/dist/tools/builtin/select/groupEntry.js.map +1 -0
- package/dist/tools/builtin/select/pressDecision.js +32 -0
- package/dist/tools/builtin/select/pressDecision.js.map +1 -0
- package/dist/tools/builtin/select/selectionContributions.js +22 -13
- package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
- package/dist/tools/builtin/select/useSelectTool.js +74 -55
- package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
- package/dist/tools/builtin/slice/useSliceTool.js +22 -8
- package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
- package/dist/tools/builtin/star/useStarTool.js +13 -4
- package/dist/tools/builtin/star/useStarTool.js.map +1 -1
- package/dist/tools/builtin/sticky/stickyNode.js +4 -1
- package/dist/tools/builtin/sticky/stickyNode.js.map +1 -1
- package/dist/tools/builtin/sticky/useStickyTool.js +10 -5
- package/dist/tools/builtin/sticky/useStickyTool.js.map +1 -1
- package/dist/tools/builtin/text/useTextTool.js +3 -1
- package/dist/tools/builtin/text/useTextTool.js.map +1 -1
- package/dist/{types-7puAuVD2.d.ts → types-49uYJN3j.d.ts} +1 -1
- package/dist/{types-CniVctmk.d.ts → types-BEdRIhNc.d.ts} +272 -109
- package/dist/{types-oFeQ5VjV.d.ts → types-p2alu-R1.d.ts} +1 -1
- package/dist/util/paint.js +1 -3
- package/dist/util/paint.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +29 -25
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arrivalWindow.js","names":[],"sources":["../../../src/core/scene/arrivalWindow.ts"],"sourcesContent":["/**\n * The scene's arrival window: what a live edit did to containers, collected\n * while it runs and handed to a layout handler before it closes.\n *\n * The window is open while a live edit is collecting the nodes that joined a\n * container, the ones that left one, and every container whose children or\n * size it changed; whoever opened the window settles it before the edit\n * closes. Undo, redo and journal replays never open it: they restore an\n * arrangement that was already decided.\n */\nimport { createEmitter } from '@weasel-js/registry';\nimport type { Op } from 'core/ops/types';\nimport { createArrangeOp, type ArrangedPose } from 'core/ops/arrange';\nimport { SceneArrivalRefused } from './arrivals';\nimport type { LayoutMove, Node, NodeId, SceneArrivalHandler } from './types';\n\n/** What the window needs from the scene it serves. */\nexport interface ArrivalWindowEnv<TData, TLayer extends string, TPose> {\n nodes: Map<NodeId, Node<TData, TLayer, TPose>>;\n /** The pass over the scene's declared layouts, which settles arrivals once\n * a container has declared one. An installed handler takes its place. */\n layoutPass: SceneArrivalHandler<TPose>;\n /** Whether a bare scene call would record an edit of its own right now:\n * no batch is open and no history engine is driving. */\n recordsBareEdits(): boolean;\n /** Write one arranged pose. Bound into the arrange op, since not every\n * adapter an edit is applied through can write poses. */\n writePose(id: string, pose: unknown): void;\n}\n\nexport interface ArrivalWindow<TPose> {\n /** A container was given a layout: from here on the scene has arrivals to\n * settle even with no handler installed. */\n layoutDeclared(): void;\n /** Install the handler that settles arrivals. Returns its remover. */\n setHandler(handler: SceneArrivalHandler<TPose>): () => void;\n /** Hear the poses each live edit's settle wrote, after the edit lands. */\n onReflow(listener: (moves: readonly LayoutMove<TPose>[]) => void): () => void;\n noteArrival(id: NodeId, parent: NodeId | null, from: NodeId | null): void;\n noteDeparture(id: NodeId, from: NodeId | null, to: NodeId | null): void;\n /** A container's child set or order changed, it changed size, or a child was posed. */\n noteChange(id: NodeId | null): void;\n /** Whether a bare scene call has to run as a batch of its own, so the\n * layout pass it triggers lands in its undo step. */\n bareLayoutEdit(): boolean;\n /** Open the window when a handler wants one — or `always`, for an edit that\n * may give the scene its first layout partway through — and no enclosing\n * edit holds it already; true when this caller now owns it. */\n open(always?: boolean): boolean;\n /** Close the window and ask the handler what the arrivals get. Throws\n * `SceneArrivalRefused` when it refuses, which reverts the edit. */\n settle(): ArrangedPose[];\n /** Report what the settled edit wrote, now that it has landed. */\n emitReflow(): void;\n /** Close the window with nothing settled or reported: its owner's edit is\n * over, however it ended. */\n abandon(): void;\n /** Run an op-driven edit that may carry arrivals: a refusal reverts it and\n * is swallowed, the way a drop onto a full container is — nothing lands.\n * Returns whether the edit landed. */\n runEdit(ops: Op[], run: (ops: Op[]) => void): boolean;\n}\n\n/** Of the ids noted per container, those the landed edit bears out: still\n * under it when `joined`, gone from it otherwise. A container that is itself\n * gone is left out. */\nfunction heldMoves(\n nodes: ReadonlyMap<NodeId, { parent: NodeId | null }>,\n noted: ReadonlyMap<NodeId, NodeId[]>,\n joined: boolean,\n): Map<NodeId, NodeId[]> {\n const out = new Map<NodeId, NodeId[]>();\n for (const [parent, ids] of noted) {\n const held = ids.filter((id) => (nodes.get(id)?.parent === parent) === joined);\n if (held.length > 0 && nodes.has(parent)) out.set(parent, held);\n }\n return out;\n}\n\nexport function createArrivalWindow<TData, TLayer extends string, TPose>(\n env: ArrivalWindowEnv<TData, TLayer, TPose>,\n): ArrivalWindow<TPose> {\n const { nodes } = env;\n let installed: SceneArrivalHandler<TPose> | null = null;\n let hasLayouts = false;\n let arrivals: Map<NodeId, NodeId[]> | null = null;\n let departures = new Map<NodeId, NodeId[]>();\n let changed = new Set<NodeId>();\n /** What the last settle wrote, reported to `onReflow` once its edit lands. */\n let reflowDue: LayoutMove<TPose>[] | null = null;\n const reflowListeners = createEmitter<[moves: readonly LayoutMove<TPose>[]]>();\n\n const activeHandler = (): SceneArrivalHandler<TPose> | null => installed ?? (hasLayouts ? env.layoutPass : null);\n\n function open(always = false): boolean {\n if (arrivals !== null || (!always && activeHandler() === null)) return false;\n arrivals = new Map();\n departures = new Map();\n changed = new Set();\n reflowDue = null;\n return true;\n }\n\n function emitReflow(): void {\n const moves = reflowDue;\n reflowDue = null;\n if (moves === null || moves.length === 0) return;\n reflowListeners.emit(moves);\n }\n\n function settle(): ArrangedPose[] {\n const pending = arrivals;\n arrivals = null;\n const handler = activeHandler();\n if (pending === null || handler === null) return [];\n // Only what is still there once the edit's other mutations have landed.\n const landed = heldMoves(nodes, pending, true);\n // Only what is gone from the container once the edit has landed: a child\n // that left and came back did not depart.\n const left = heldMoves(nodes, departures, false);\n departures = new Map();\n const touched = new Set([...changed].filter((id) => nodes.get(id)?.kind === 'container'));\n if (landed.size === 0 && touched.size === 0) return [];\n const poses = handler(landed, touched, left);\n if (poses === null) throw new SceneArrivalRefused(landed);\n const out: ArrangedPose[] = [];\n for (const [id, to] of poses) {\n const node = nodes.get(id);\n if (node) out.push({ id, from: node.pose, to });\n }\n reflowDue = out as LayoutMove<TPose>[];\n return out;\n }\n\n function abandon(): void {\n arrivals = null;\n reflowDue = null;\n }\n\n /** `ops` plus the op that settles their arrivals, when this call owns the\n * window; `ops` unchanged otherwise. Opened even on a scene with no layout\n * yet: an edit's op list is fixed before it runs, and any op in it may give\n * the scene its first. The arrange op that settles nothing elides itself. */\n function withArrivalOps(ops: Op[]): { ops: Op[]; owned: boolean } {\n if (!open(true)) return { ops, owned: false };\n return { ops: [...ops, createArrangeOp({}, settle, env.writePose)], owned: true };\n }\n\n return {\n layoutDeclared: () => { hasLayouts = true; },\n setHandler(handler) {\n installed = handler;\n return () => {\n if (installed === handler) installed = null;\n };\n },\n onReflow: reflowListeners.subscribe,\n noteArrival(id, parent, from) {\n if (arrivals === null || parent === null || parent === from) return;\n changed.add(parent);\n const list = arrivals.get(parent);\n if (list === undefined) arrivals.set(parent, [id]);\n else if (!list.includes(id)) list.push(id);\n },\n noteDeparture(id, from, to) {\n if (arrivals === null || from === null || from === to) return;\n changed.add(from);\n // One that joined earlier in this edit was never there to leave.\n if (arrivals.get(from)?.includes(id)) return;\n const list = departures.get(from);\n if (list === undefined) departures.set(from, [id]);\n else if (!list.includes(id)) list.push(id);\n },\n noteChange(id) {\n if (arrivals !== null && id !== null) changed.add(id);\n },\n bareLayoutEdit: () => activeHandler() !== null && arrivals === null && env.recordsBareEdits(),\n open,\n settle,\n emitReflow,\n abandon,\n runEdit(ops, run) {\n const { ops: all, owned } = withArrivalOps(ops);\n // An edit inside another's window leaves a refusal to the one that owns\n // it, which reverts the whole edit and answers for it.\n if (!owned) return run(all), true;\n try {\n run(all);\n emitReflow();\n return true;\n } catch (err) {\n if (!(err instanceof SceneArrivalRefused)) throw err;\n return false;\n } finally {\n abandon();\n }\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"arrivalWindow.js","names":[],"sources":["../../../src/core/scene/arrivalWindow.ts"],"sourcesContent":["/**\n * The scene's arrival window: what a live edit did to containers, collected\n * while it runs and handed to a layout handler before it closes.\n *\n * The window is open while a live edit is collecting the nodes that joined a\n * container, the ones that left one, and every container whose children or\n * size it changed; whoever opened the window settles it before the edit\n * closes. Undo, redo and journal replays never open it: they restore an\n * arrangement that was already decided.\n */\nimport { createEmitter } from '@weasel-js/registry';\nimport type { Op } from 'core/ops/types';\nimport { createArrangeOp, type ArrangedPose } from 'core/ops/arrange';\nimport { SceneArrivalRefused } from './arrivals';\nimport type { LayoutMove, Node, NodeId, SceneArrivalHandler } from './types';\n\n/** What the window needs from the scene it serves. */\nexport interface ArrivalWindowEnv<TData, TLayer extends string, TPose> {\n nodes: Map<NodeId, Node<TData, TLayer, TPose>>;\n /** The pass over the scene's declared layouts, which settles arrivals once\n * a container has declared one. An installed handler takes its place. */\n layoutPass: SceneArrivalHandler<TPose>;\n /** Whether a bare scene call would record an edit of its own right now:\n * no batch is open and no history engine is driving. */\n recordsBareEdits(): boolean;\n /** Write one arranged pose. Bound into the arrange op, since not every\n * adapter an edit is applied through can write poses. */\n writePose(id: string, pose: unknown): void;\n}\n\nexport interface ArrivalWindow<TPose> {\n /** A container was given a layout: from here on the scene has arrivals to\n * settle even with no handler installed. */\n layoutDeclared(): void;\n /** Install the handler that settles arrivals. Returns its remover. */\n setHandler(handler: SceneArrivalHandler<TPose>): () => void;\n /** Hear the poses each live edit's settle wrote, after the edit lands. */\n onReflow(listener: (moves: readonly LayoutMove<TPose>[]) => void): () => void;\n noteArrival(id: NodeId, parent: NodeId | null, from: NodeId | null): void;\n noteDeparture(id: NodeId, from: NodeId | null, to: NodeId | null): void;\n /** A container's child set or order changed, it changed size, or a child was posed. */\n noteChange(id: NodeId | null): void;\n /** Whether a bare scene call has to run as a batch of its own, so the\n * layout pass it triggers lands in its undo step. */\n bareLayoutEdit(): boolean;\n /** Open the window when a handler wants one — or `always`, for an edit that\n * may give the scene its first layout partway through — and no enclosing\n * edit holds it already; true when this caller now owns it. */\n open(always?: boolean): boolean;\n /** Close the window and ask the handler what the arrivals get. Throws\n * `SceneArrivalRefused` when it refuses, which reverts the edit. */\n settle(): ArrangedPose[];\n /** Report what the settled edit wrote, now that it has landed. */\n emitReflow(): void;\n /** Close the window with nothing settled or reported: its owner's edit is\n * over, however it ended. */\n abandon(): void;\n /** Run an op-driven edit that may carry arrivals: a refusal reverts it and\n * is swallowed, the way a drop onto a full container is — nothing lands.\n * Returns whether the edit landed. */\n runEdit(ops: Op[], run: (ops: Op[]) => void): boolean;\n}\n\n/** Of the ids noted per container, those the landed edit bears out: still\n * under it when `joined`, gone from it otherwise. A container that is itself\n * gone is left out. */\nfunction heldMoves(\n nodes: ReadonlyMap<NodeId, { parent: NodeId | null }>,\n noted: ReadonlyMap<NodeId, NodeId[]>,\n joined: boolean,\n): Map<NodeId, NodeId[]> {\n const out = new Map<NodeId, NodeId[]>();\n for (const [parent, ids] of noted) {\n const held = ids.filter((id) => (nodes.get(id)?.parent === parent) === joined);\n if (held.length > 0 && nodes.has(parent)) out.set(parent, held);\n }\n return out;\n}\n\nexport function createArrivalWindow<TData, TLayer extends string, TPose>(\n env: ArrivalWindowEnv<TData, TLayer, TPose>,\n): ArrivalWindow<TPose> {\n const { nodes } = env;\n let installed: SceneArrivalHandler<TPose> | null = null;\n let hasLayouts = false;\n let arrivals: Map<NodeId, NodeId[]> | null = null;\n let departures = new Map<NodeId, NodeId[]>();\n let changed = new Set<NodeId>();\n /** What the last settle wrote, reported to `onReflow` once its edit lands. */\n let reflowDue: LayoutMove<TPose>[] | null = null;\n const reflowListeners = createEmitter<[moves: readonly LayoutMove<TPose>[]]>();\n\n const activeHandler = (): SceneArrivalHandler<TPose> | null => installed ?? (hasLayouts ? env.layoutPass : null);\n\n function open(always = false): boolean {\n if (arrivals !== null || (!always && activeHandler() === null)) return false;\n arrivals = new Map();\n departures = new Map();\n changed = new Set();\n reflowDue = null;\n return true;\n }\n\n function emitReflow(): void {\n const moves = reflowDue;\n reflowDue = null;\n if (moves === null || moves.length === 0) return;\n reflowListeners.emit(moves);\n }\n\n function settle(): ArrangedPose[] {\n const pending = arrivals;\n arrivals = null;\n const handler = activeHandler();\n if (pending === null || handler === null) return [];\n // Only what is still there once the edit's other mutations have landed.\n const landed = heldMoves(nodes, pending, true);\n // Only what is gone from the container once the edit has landed: a child\n // that left and came back did not depart.\n const left = heldMoves(nodes, departures, false);\n departures = new Map();\n const touched = new Set([...changed].filter((id) => nodes.has(id)));\n if (landed.size === 0 && touched.size === 0) return [];\n const poses = handler(landed, touched, left);\n if (poses === null) throw new SceneArrivalRefused(landed);\n const out: ArrangedPose[] = [];\n for (const [id, to] of poses) {\n const node = nodes.get(id);\n if (node) out.push({ id, from: node.pose, to });\n }\n reflowDue = out as LayoutMove<TPose>[];\n return out;\n }\n\n function abandon(): void {\n arrivals = null;\n reflowDue = null;\n }\n\n /** `ops` plus the op that settles their arrivals, when this call owns the\n * window; `ops` unchanged otherwise. Opened even on a scene with no layout\n * yet: an edit's op list is fixed before it runs, and any op in it may give\n * the scene its first. The arrange op that settles nothing elides itself. */\n function withArrivalOps(ops: Op[]): { ops: Op[]; owned: boolean } {\n if (!open(true)) return { ops, owned: false };\n return { ops: [...ops, createArrangeOp({}, settle, env.writePose)], owned: true };\n }\n\n return {\n layoutDeclared: () => { hasLayouts = true; },\n setHandler(handler) {\n installed = handler;\n return () => {\n if (installed === handler) installed = null;\n };\n },\n onReflow: reflowListeners.subscribe,\n noteArrival(id, parent, from) {\n if (arrivals === null || parent === null || parent === from) return;\n changed.add(parent);\n const list = arrivals.get(parent);\n if (list === undefined) arrivals.set(parent, [id]);\n else if (!list.includes(id)) list.push(id);\n },\n noteDeparture(id, from, to) {\n if (arrivals === null || from === null || from === to) return;\n changed.add(from);\n // One that joined earlier in this edit was never there to leave.\n if (arrivals.get(from)?.includes(id)) return;\n const list = departures.get(from);\n if (list === undefined) departures.set(from, [id]);\n else if (!list.includes(id)) list.push(id);\n },\n noteChange(id) {\n if (arrivals !== null && id !== null) changed.add(id);\n },\n bareLayoutEdit: () => activeHandler() !== null && arrivals === null && env.recordsBareEdits(),\n open,\n settle,\n emitReflow,\n abandon,\n runEdit(ops, run) {\n const { ops: all, owned } = withArrivalOps(ops);\n // An edit inside another's window leaves a refusal to the one that owns\n // it, which reverts the whole edit and answers for it.\n if (!owned) return run(all), true;\n try {\n run(all);\n emitReflow();\n return true;\n } catch (err) {\n if (!(err instanceof SceneArrivalRefused)) throw err;\n return false;\n } finally {\n abandon();\n }\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/core/scene/clipNothing.ts
|
|
2
|
+
/** Registry key for {@link clipNothing}; every scene's registry carries it. */
|
|
3
|
+
var CLIP_NOTHING = "kit:clipNothing";
|
|
4
|
+
/** A `clipFromPose` that clips nothing, registered in every scene so a save
|
|
5
|
+
* naming {@link CLIP_NOTHING} loads. */
|
|
6
|
+
var clipNothing = () => null;
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
export { CLIP_NOTHING, clipNothing };
|
|
10
|
+
//# sourceMappingURL=clipNothing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipNothing.js","names":[],"sources":["../../../src/core/scene/clipNothing.ts"],"sourcesContent":["/** Registry key for {@link clipNothing}; every scene's registry carries it. */\nexport const CLIP_NOTHING = 'kit:clipNothing';\n\n/** A `clipFromPose` that clips nothing, registered in every scene so a save\n * naming {@link CLIP_NOTHING} loads. */\nexport const clipNothing = (): null => null;\n"],"mappings":";;AACA,IAAa,eAAe;;;AAI5B,IAAa,oBAA0B"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { sameValue } from "./sameValue.js";
|
|
2
|
+
|
|
3
|
+
//#region src/core/scene/declaredFieldSetters.ts
|
|
4
|
+
/** Stored only while declared, so a snapshot of a node declaring none carries neither. */
|
|
5
|
+
function write(node, field, to) {
|
|
6
|
+
if (to === void 0) delete node[field];
|
|
7
|
+
else node[field] = to;
|
|
8
|
+
}
|
|
9
|
+
var KIND = {
|
|
10
|
+
units: "kit:setUnits",
|
|
11
|
+
clip: "kit:setClip"
|
|
12
|
+
};
|
|
13
|
+
/** Register `kit:setUnits` and `kit:setClip`, and answer with the scene
|
|
14
|
+
* methods that record them. */
|
|
15
|
+
function createDeclaredFieldSetters(env) {
|
|
16
|
+
for (const field of ["units", "clip"]) env.register(KIND[field], {
|
|
17
|
+
apply: (p) => {
|
|
18
|
+
const { id, to } = p;
|
|
19
|
+
write(env.requireNode(id), field, to);
|
|
20
|
+
},
|
|
21
|
+
revert: (p) => {
|
|
22
|
+
const { id, from } = p;
|
|
23
|
+
write(env.requireNode(id), field, from);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
const set = (field, label, verb) => (id, to) => {
|
|
27
|
+
const from = env.requireNode(id)[field];
|
|
28
|
+
env.refuse(id, verb);
|
|
29
|
+
if (sameValue(from, to ?? void 0)) return;
|
|
30
|
+
env.record(KIND[field], {
|
|
31
|
+
id,
|
|
32
|
+
from,
|
|
33
|
+
to: to ?? void 0
|
|
34
|
+
}, label);
|
|
35
|
+
};
|
|
36
|
+
return {
|
|
37
|
+
setUnits: set("units", "setUnits", "set the units of"),
|
|
38
|
+
setClip: set("clip", "setClip", "set the clip of")
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
export { createDeclaredFieldSetters };
|
|
44
|
+
//# sourceMappingURL=declaredFieldSetters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declaredFieldSetters.js","names":[],"sources":["../../../src/core/scene/declaredFieldSetters.ts"],"sourcesContent":["/**\n * What a node declares for its children — the unit scope they are shown in and\n * the clip they are drawn in: the kit ops that write each, and the scene\n * methods that record them.\n */\nimport type { UnitScope } from '@weasel-js/quantity';\nimport type { LockGuard } from './lockGuard';\nimport { sameValue } from './sameValue';\nimport type { Node, NodeClip, NodeId, RegisteredOp } from './types';\n\n/** The scene methods that write a node's declared `units` and `clip`, each one undo step. */\nexport interface SceneDeclaredFieldSetters {\n /** Declare the unit scope of container `id`, or clear it with `null`. */\n setUnits(id: NodeId, units: UnitScope | null): void;\n /** Declare the clip `id` draws its children in (see `SceneNode.clip`), or clear it with `null`. */\n setClip(id: NodeId, clip: NodeClip | null): void;\n}\n\n/** What `createDeclaredFieldSetters` needs from the scene it is built into. */\nexport interface DeclaredFieldSettersEnv<TData, TLayer extends string, TPose> {\n register(kind: string, handler: RegisteredOp<unknown>): void;\n requireNode(id: NodeId): Node<TData, TLayer, TPose>;\n refuse: LockGuard<TLayer>['refuse'];\n record(kind: string, payload: unknown, label: string): void;\n}\n\ntype Declared = { units?: UnitScope; clip?: NodeClip };\ntype Field = keyof Declared;\ninterface DeclaredPayload { id: NodeId; from?: unknown; to?: unknown }\n\n/** Stored only while declared, so a snapshot of a node declaring none carries neither. */\nfunction write(node: Declared, field: Field, to: unknown): void {\n if (to === undefined) delete node[field];\n else (node as Record<Field, unknown>)[field] = to;\n}\n\nconst KIND: Record<Field, string> = { units: 'kit:setUnits', clip: 'kit:setClip' };\n\n/** Register `kit:setUnits` and `kit:setClip`, and answer with the scene\n * methods that record them. */\nexport function createDeclaredFieldSetters<TData, TLayer extends string, TPose>(\n env: DeclaredFieldSettersEnv<TData, TLayer, TPose>,\n): SceneDeclaredFieldSetters {\n for (const field of ['units', 'clip'] as const) {\n env.register(KIND[field], {\n apply: (p) => { const { id, to } = p as DeclaredPayload; write(env.requireNode(id), field, to); },\n revert: (p) => { const { id, from } = p as DeclaredPayload; write(env.requireNode(id), field, from); },\n });\n }\n\n const set = (field: Field, label: string, verb: string) => (id: NodeId, to: unknown): void => {\n const from = (env.requireNode(id) as Declared)[field];\n env.refuse(id, verb);\n if (sameValue(from, to ?? undefined)) return;\n env.record(KIND[field], { id, from, to: to ?? undefined } satisfies DeclaredPayload, label);\n };\n\n return {\n setUnits: set('units', 'setUnits', 'set the units of'),\n setClip: set('clip', 'setClip', 'set the clip of'),\n };\n}\n"],"mappings":";;;;AA+BA,SAAS,MAAM,MAAgB,OAAc,IAAmB;CAC9D,IAAI,OAAO,QAAW,OAAO,KAAK;MAC7B,KAAiC,SAAS;AACjD;AAEA,IAAM,OAA8B;CAAE,OAAO;CAAgB,MAAM;AAAc;;;AAIjF,SAAgB,2BACd,KAC2B;CAC3B,KAAK,MAAM,SAAS,CAAC,SAAS,MAAM,GAClC,IAAI,SAAS,KAAK,QAAQ;EACxB,QAAQ,MAAM;GAAE,MAAM,EAAE,IAAI,OAAO;GAAsB,MAAM,IAAI,YAAY,EAAE,GAAG,OAAO,EAAE;EAAG;EAChG,SAAS,MAAM;GAAE,MAAM,EAAE,IAAI,SAAS;GAAsB,MAAM,IAAI,YAAY,EAAE,GAAG,OAAO,IAAI;EAAG;CACvG,CAAC;CAGH,MAAM,OAAO,OAAc,OAAe,UAAkB,IAAY,OAAsB;EAC5F,MAAM,OAAQ,IAAI,YAAY,EAAE,CAAC,CAAc;EAC/C,IAAI,OAAO,IAAI,IAAI;EACnB,IAAI,UAAU,MAAM,MAAM,MAAS,GAAG;EACtC,IAAI,OAAO,KAAK,QAAQ;GAAE;GAAI;GAAM,IAAI,MAAM;EAAU,GAA6B,KAAK;CAC5F;CAEA,OAAO;EACL,UAAU,IAAI,SAAS,YAAY,kBAAkB;EACrD,SAAS,IAAI,QAAQ,WAAW,iBAAiB;CACnD;AACF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { fontGeneration, noteFontRead, withFontReads } from "./fontReads.js";
|
|
1
2
|
import { samePoseValue, snapshotPose } from "./poseSnapshot.js";
|
|
2
3
|
|
|
3
4
|
//#region src/core/scene/depMemo.ts
|
|
@@ -7,7 +8,8 @@ function emptyDepRecord() {
|
|
|
7
8
|
poses: [],
|
|
8
9
|
data: [],
|
|
9
10
|
layers: [],
|
|
10
|
-
paths: []
|
|
11
|
+
paths: [],
|
|
12
|
+
faces: null
|
|
11
13
|
};
|
|
12
14
|
}
|
|
13
15
|
/** A dependency as the derivation is handed it, noting a read of its path. A
|
|
@@ -28,6 +30,9 @@ var RecordedDep = class {
|
|
|
28
30
|
get path() {
|
|
29
31
|
return this.paths[this.index] = this.dep.path;
|
|
30
32
|
}
|
|
33
|
+
get inherited() {
|
|
34
|
+
return this.dep.inherited;
|
|
35
|
+
}
|
|
31
36
|
};
|
|
32
37
|
/** Run `derive` against `deps`, recording in place what it was run against.
|
|
33
38
|
* Mutating the record is what updates the memo slot, which holds this object. */
|
|
@@ -37,20 +42,25 @@ function deriveRecorded(into, deps, derive) {
|
|
|
37
42
|
into.data.length = 0;
|
|
38
43
|
into.layers.length = 0;
|
|
39
44
|
into.paths.length = 0;
|
|
40
|
-
|
|
45
|
+
const handed = deps.map((dep, i) => {
|
|
41
46
|
into.nodes.push(dep?.node);
|
|
42
47
|
into.poses.push(dep === void 0 ? void 0 : snapshotPose(dep.pose));
|
|
43
48
|
into.data.push(dep?.node.data);
|
|
44
49
|
into.layers.push(dep?.node.layer);
|
|
45
50
|
into.paths.push(void 0);
|
|
46
51
|
return dep === void 0 ? void 0 : new RecordedDep(dep, into.paths, i);
|
|
47
|
-
})
|
|
52
|
+
});
|
|
53
|
+
const generation = fontGeneration();
|
|
54
|
+
const { value, fonts } = withFontReads(() => derive(handed));
|
|
55
|
+
into.faces = fonts ? generation : null;
|
|
56
|
+
return value;
|
|
48
57
|
}
|
|
49
58
|
/** Whether the dependencies still resolve to what the record was taken from.
|
|
50
59
|
* Resolves them one at a time rather than taking an array: this is the hit
|
|
51
60
|
* path, and it walks every derived node's every dependency on every frame. */
|
|
52
61
|
function sameDeps(record, ids, depOf) {
|
|
53
62
|
if (record.nodes.length !== ids.length) return false;
|
|
63
|
+
if (record.faces !== null && record.faces !== fontGeneration()) return false;
|
|
54
64
|
for (let i = 0; i < ids.length; i++) {
|
|
55
65
|
const dep = depOf(ids[i]);
|
|
56
66
|
if (record.nodes[i] !== (dep === void 0 ? void 0 : dep.node)) return false;
|
|
@@ -60,6 +70,7 @@ function sameDeps(record, ids, depOf) {
|
|
|
60
70
|
const path = record.paths[i];
|
|
61
71
|
if (path !== void 0 && path !== dep.path) return false;
|
|
62
72
|
}
|
|
73
|
+
if (record.faces !== null) noteFontRead();
|
|
63
74
|
return true;
|
|
64
75
|
}
|
|
65
76
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"depMemo.js","names":[],"sources":["../../../src/core/scene/depMemo.ts"],"sourcesContent":["/**\n * What a memoized derivation was derived *from*, so a hit can re-check it.\n *\n * A derivation keyed on the deriving node's own authored pose only notices a\n * change someone pushed. A dependency that changed with nothing pushed behind\n * it — an ancestor's frame moving, a removal, a dependency appearing, a lookup\n * answering nodes no scene edits — is invisible to that key. Recording what\n * the derivation was handed and comparing it on the hit path is what notices\n * it without a trigger.\n *\n * What is recorded is what a derivation may read of a dependency: its node (an\n * identity), its pose (by value), its `data` (a reference, which every edit\n * replaces), its `layer`, and its path where the derivation read it. Anything\n * else on the node — its parent, its children — still needs a push.\n */\nimport type { Path } from '@weasel-js/geom';\nimport { samePoseValue, snapshotPose } from './poseSnapshot';\nimport type { DerivedDep, Node, NodeId } from './types';\n\n/** Each dependency's node — an identity, so a restored clone is a different\n * one — with a copy of the pose it resolved to, its `data` and `layer`, and\n * the path it answered, `undefined` where the derivation never asked. */\nexport interface DepRecord<TPose> {\n nodes: (object | undefined)[];\n poses: (TPose | undefined)[];\n data: unknown[];\n layers: (string | undefined)[];\n paths: (Path | null | undefined)[];\n}\n\nexport function emptyDepRecord<TPose>(): DepRecord<TPose> {\n return { nodes: [], poses: [], data: [], layers: [], paths: [] };\n}\n\n/** A dependency as the derivation is handed it, noting a read of its path. A\n * class for the reason `SceneDep` is one: a prototype accessor is cheap. */\nclass RecordedDep<TPose> implements DerivedDep<TPose> {\n readonly node: Node<unknown, string, TPose>;\n readonly pose: TPose;\n\n constructor(\n private readonly dep: DerivedDep<TPose>,\n private readonly paths: (Path | null | undefined)[],\n private readonly index: number,\n ) {\n this.node = dep.node;\n this.pose = dep.pose;\n }\n\n get path(): Path | null {\n return (this.paths[this.index] = this.dep.path);\n }\n}\n\n/** Run `derive` against `deps`, recording in place what it was run against.\n * Mutating the record is what updates the memo slot, which holds this object. */\nexport function deriveRecorded<TPose, T>(\n into: DepRecord<TPose>,\n deps: readonly (DerivedDep<TPose> | undefined)[],\n derive: (deps: readonly (DerivedDep<TPose> | undefined)[]) => T,\n): T {\n into.nodes.length = 0;\n into.poses.length = 0;\n into.data.length = 0;\n into.layers.length = 0;\n into.paths.length = 0;\n const handed = deps.map((dep, i) => {\n into.nodes.push(dep?.node);\n into.poses.push(dep === undefined ? undefined : snapshotPose(dep.pose));\n into.data.push(dep?.node.data);\n into.layers.push(dep?.node.layer);\n into.paths.push(undefined);\n return dep === undefined ? undefined : new RecordedDep(dep, into.paths, i);\n });\n
|
|
1
|
+
{"version":3,"file":"depMemo.js","names":[],"sources":["../../../src/core/scene/depMemo.ts"],"sourcesContent":["/**\n * What a memoized derivation was derived *from*, so a hit can re-check it.\n *\n * A derivation keyed on the deriving node's own authored pose only notices a\n * change someone pushed. A dependency that changed with nothing pushed behind\n * it — an ancestor's frame moving, a removal, a dependency appearing, a lookup\n * answering nodes no scene edits — is invisible to that key. Recording what\n * the derivation was handed and comparing it on the hit path is what notices\n * it without a trigger.\n *\n * What is recorded is what a derivation may read of a dependency: its node (an\n * identity), its pose (by value), its `data` (a reference, which every edit\n * replaces), its `layer`, and its path where the derivation read it. Anything\n * else on the node — its parent, its children — still needs a push. A\n * derivation that read glyph outlines also records the face generation, since\n * a face landing changes its result with nothing in the scene changed.\n */\nimport type { Path } from '@weasel-js/geom';\nimport type { InheritedPaint } from './inheritedPaint';\nimport { fontGeneration, noteFontRead, withFontReads } from './fontReads';\nimport { samePoseValue, snapshotPose } from './poseSnapshot';\nimport type { DerivedDep, Node, NodeId } from './types';\n\n/** Each dependency's node — an identity, so a restored clone is a different\n * one — with a copy of the pose it resolved to, its `data` and `layer`, and\n * the path it answered, `undefined` where the derivation never asked. */\nexport interface DepRecord<TPose> {\n nodes: (object | undefined)[];\n poses: (TPose | undefined)[];\n data: unknown[];\n layers: (string | undefined)[];\n paths: (Path | null | undefined)[];\n /** The face generation it was derived under, or `null` when it read no\n * glyph outlines. */\n faces: number | null;\n}\n\nexport function emptyDepRecord<TPose>(): DepRecord<TPose> {\n return { nodes: [], poses: [], data: [], layers: [], paths: [], faces: null };\n}\n\n/** A dependency as the derivation is handed it, noting a read of its path. A\n * class for the reason `SceneDep` is one: a prototype accessor is cheap. */\nclass RecordedDep<TPose> implements DerivedDep<TPose> {\n readonly node: Node<unknown, string, TPose>;\n readonly pose: TPose;\n\n constructor(\n private readonly dep: DerivedDep<TPose>,\n private readonly paths: (Path | null | undefined)[],\n private readonly index: number,\n ) {\n this.node = dep.node;\n this.pose = dep.pose;\n }\n\n get path(): Path | null {\n return (this.paths[this.index] = this.dep.path);\n }\n\n get inherited(): InheritedPaint | undefined {\n return this.dep.inherited;\n }\n}\n\n/** Run `derive` against `deps`, recording in place what it was run against.\n * Mutating the record is what updates the memo slot, which holds this object. */\nexport function deriveRecorded<TPose, T>(\n into: DepRecord<TPose>,\n deps: readonly (DerivedDep<TPose> | undefined)[],\n derive: (deps: readonly (DerivedDep<TPose> | undefined)[]) => T,\n): T {\n into.nodes.length = 0;\n into.poses.length = 0;\n into.data.length = 0;\n into.layers.length = 0;\n into.paths.length = 0;\n const handed = deps.map((dep, i) => {\n into.nodes.push(dep?.node);\n into.poses.push(dep === undefined ? undefined : snapshotPose(dep.pose));\n into.data.push(dep?.node.data);\n into.layers.push(dep?.node.layer);\n into.paths.push(undefined);\n return dep === undefined ? undefined : new RecordedDep(dep, into.paths, i);\n });\n const generation = fontGeneration();\n const { value, fonts } = withFontReads(() => derive(handed));\n into.faces = fonts ? generation : null;\n return value;\n}\n\n/** Whether the dependencies still resolve to what the record was taken from.\n * Resolves them one at a time rather than taking an array: this is the hit\n * path, and it walks every derived node's every dependency on every frame. */\nexport function sameDeps<TPose>(\n record: DepRecord<TPose>,\n ids: readonly NodeId[],\n depOf: (id: NodeId) => DerivedDep<TPose> | undefined,\n): boolean {\n if (record.nodes.length !== ids.length) return false;\n if (record.faces !== null && record.faces !== fontGeneration()) return false;\n for (let i = 0; i < ids.length; i++) {\n const dep = depOf(ids[i]);\n if (record.nodes[i] !== (dep === undefined ? undefined : dep.node)) return false;\n if (dep === undefined) continue;\n if (record.data[i] !== dep.node.data || record.layers[i] !== dep.node.layer) return false;\n if (!samePoseValue(record.poses[i], dep.pose)) return false;\n const path = record.paths[i];\n if (path !== undefined && path !== dep.path) return false;\n }\n // A hit is still a read, for any derivation enclosing this one.\n if (record.faces !== null) noteFontRead();\n return true;\n}\n"],"mappings":";;;;AAqCA,SAAgB,iBAA0C;CACxD,OAAO;EAAE,OAAO,CAAC;EAAG,OAAO,CAAC;EAAG,MAAM,CAAC;EAAG,QAAQ,CAAC;EAAG,OAAO,CAAC;EAAG,OAAO;CAAK;AAC9E;;;AAIA,IAAM,cAAN,MAAsD;CAKjC;CACA;CACA;CANnB;CACA;CAEA,YACE,KACA,OACA,OACA;EAHiB,KAAA,MAAA;EACA,KAAA,QAAA;EACA,KAAA,QAAA;EAEjB,KAAK,OAAO,IAAI;EAChB,KAAK,OAAO,IAAI;CAClB;CAEA,IAAI,OAAoB;EACtB,OAAQ,KAAK,MAAM,KAAK,SAAS,KAAK,IAAI;CAC5C;CAEA,IAAI,YAAwC;EAC1C,OAAO,KAAK,IAAI;CAClB;AACF;;;AAIA,SAAgB,eACd,MACA,MACA,QACG;CACH,KAAK,MAAM,SAAS;CACpB,KAAK,MAAM,SAAS;CACpB,KAAK,KAAK,SAAS;CACnB,KAAK,OAAO,SAAS;CACrB,KAAK,MAAM,SAAS;CACpB,MAAM,SAAS,KAAK,KAAK,KAAK,MAAM;EAClC,KAAK,MAAM,KAAK,KAAK,IAAI;EACzB,KAAK,MAAM,KAAK,QAAQ,SAAY,SAAY,aAAa,IAAI,IAAI,CAAC;EACtE,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI;EAC7B,KAAK,OAAO,KAAK,KAAK,KAAK,KAAK;EAChC,KAAK,MAAM,KAAK,MAAS;EACzB,OAAO,QAAQ,SAAY,SAAY,IAAI,YAAY,KAAK,KAAK,OAAO,CAAC;CAC3E,CAAC;CACD,MAAM,aAAa,eAAe;CAClC,MAAM,EAAE,OAAO,UAAU,oBAAoB,OAAO,MAAM,CAAC;CAC3D,KAAK,QAAQ,QAAQ,aAAa;CAClC,OAAO;AACT;;;;AAKA,SAAgB,SACd,QACA,KACA,OACS;CACT,IAAI,OAAO,MAAM,WAAW,IAAI,QAAQ,OAAO;CAC/C,IAAI,OAAO,UAAU,QAAQ,OAAO,UAAU,eAAe,GAAG,OAAO;CACvE,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;EACnC,MAAM,MAAM,MAAM,IAAI,EAAE;EACxB,IAAI,OAAO,MAAM,QAAQ,QAAQ,SAAY,SAAY,IAAI,OAAO,OAAO;EAC3E,IAAI,QAAQ,QAAW;EACvB,IAAI,OAAO,KAAK,OAAO,IAAI,KAAK,QAAQ,OAAO,OAAO,OAAO,IAAI,KAAK,OAAO,OAAO;EACpF,IAAI,CAAC,cAAc,OAAO,MAAM,IAAI,IAAI,IAAI,GAAG,OAAO;EACtD,MAAM,OAAO,OAAO,MAAM;EAC1B,IAAI,SAAS,UAAa,SAAS,IAAI,MAAM,OAAO;CACtD;CAEA,IAAI,OAAO,UAAU,MAAM,aAAa;CACxC,OAAO;AACT"}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
//#region src/core/scene/dependents.ts
|
|
2
2
|
var NONE = Object.freeze([]);
|
|
3
|
+
/** The nodes in `scene` that list `id` in their `dependsOn`, directly or through others, less any inside `id`'s own
|
|
4
|
+
* subtree. */
|
|
5
|
+
function sceneDependentsOf(scene, id) {
|
|
6
|
+
if (!scene.get(id)) return NONE;
|
|
7
|
+
return scene.removalClosure([id]).filter((d) => d !== id && !scene.ancestorsOf(d).includes(id));
|
|
8
|
+
}
|
|
9
|
+
/** The ids `node` names in its `dependsOn`, in order: none for a node naming `'children'` or nothing. */
|
|
10
|
+
var sourcesOf = (node) => Array.isArray(node?.dependsOn) ? node.dependsOn : NONE;
|
|
3
11
|
/**
|
|
4
12
|
* The nodes `node`'s geometry derives from: the ids it named, or its own
|
|
5
13
|
* children when it named `'children'`.
|
|
@@ -90,5 +98,5 @@ function sameDependsOn(a, b) {
|
|
|
90
98
|
}
|
|
91
99
|
|
|
92
100
|
//#endregion
|
|
93
|
-
export { createDependentsIndex, dependencyIdsOf, sameDependsOn };
|
|
101
|
+
export { createDependentsIndex, dependencyIdsOf, sameDependsOn, sceneDependentsOf, sourcesOf };
|
|
94
102
|
//# sourceMappingURL=dependents.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dependents.js","names":[],"sources":["../../../src/core/scene/dependents.ts"],"sourcesContent":["/**\n * Which nodes must recompute when a given node's pose changes — the reverse\n * index, plus {@link dependencyIdsOf}, the forward read it is built from.\n */\nimport type { NodeId } from './types';\n\nconst NONE: readonly NodeId[] = Object.freeze([]);\n\n/**\n * The nodes `node`'s geometry derives from: the ids it named, or its own\n * children when it named `'children'`.\n *\n * The `'children'` form is deliberately absent from the reverse index — a\n * container is not a dependent of the children it hugs, or deleting one child\n * would cascade the whole group away. Its invalidation is the ancestor walk in\n * `scene.ts` instead.\n */\nexport function dependencyIdsOf(\n node: { id: NodeId; dependsOn?: readonly NodeId[] | 'children' },\n childrenOf: (id: NodeId) => readonly NodeId[],\n): readonly NodeId[] {\n const deps = node.dependsOn;\n if (deps === undefined) return NONE;\n return deps === 'children' ? childrenOf(node.id) : deps;\n}\n\nexport interface DependentsIndex {\n add(id: NodeId, deps: readonly NodeId[]): void;\n /** Forget what `id` declared. Deliberately not symmetric: who depends on\n * `id` is those nodes' declaration, not `id`'s, and outlives its removal. */\n remove(id: NodeId): void;\n /** Forget every registration. */\n clear(): void;\n /** True when nothing derives from anything. */\n isEmpty(): boolean;\n dependentsOf(id: NodeId): Iterable<NodeId>;\n /** Nodes that derive from `id` directly or through a chain. Excludes `id`\n * itself unless a cycle leads back to it. */\n transitiveDependentsOf(id: NodeId): Iterable<NodeId>;\n}\n\nexport function createDependentsIndex(): DependentsIndex {\n /** dependency -> nodes deriving from it */\n const forward = new Map<NodeId, Set<NodeId>>();\n /** dependent -> the dependencies it registered against */\n const reverse = new Map<NodeId, readonly NodeId[]>();\n\n /** Drop `id`'s registrations against its current dependencies. Shared by\n * `add` (which re-registers after) and `remove` (which does not). */\n function detachOwnDeps(id: NodeId): void {\n const old = reverse.get(id);\n if (old === undefined) return;\n for (const dep of old) {\n const set = forward.get(dep);\n if (set === undefined) continue;\n set.delete(id);\n if (set.size === 0) forward.delete(dep);\n }\n reverse.delete(id);\n }\n\n return {\n add(id, deps) {\n detachOwnDeps(id);\n if (deps.length === 0) return;\n reverse.set(id, [...deps]);\n for (const dep of deps) {\n let set = forward.get(dep);\n if (set === undefined) { set = new Set(); forward.set(dep, set); }\n set.add(id);\n }\n },\n\n remove(id) {\n detachOwnDeps(id);\n },\n\n clear() {\n forward.clear();\n reverse.clear();\n },\n\n isEmpty() {\n return forward.size === 0;\n },\n\n dependentsOf(id) {\n const set = forward.get(id);\n return set === undefined ? NONE : [...set];\n },\n\n transitiveDependentsOf(id) {\n // Runs per node per frame; the miss must not allocate.\n const direct = forward.get(id);\n if (direct === undefined) return NONE;\n const out = new Set<NodeId>();\n const stack: NodeId[] = [...direct];\n while (stack.length > 0) {\n const next = stack.pop()!;\n if (out.has(next)) continue; // also what stops a cycle\n out.add(next);\n for (const d of forward.get(next) ?? []) stack.push(d);\n }\n return out;\n },\n };\n}\n\n/**\n * Whether two `dependsOn` values name the same thing, so a retarget to what a\n * node already declares can be elided. Order is part of it: a router reads its\n * ends positionally, and swapping them reverses the edge.\n */\nexport function sameDependsOn(\n a: readonly NodeId[] | 'children' | undefined,\n b: readonly NodeId[] | 'children' | undefined,\n): boolean {\n if (a === b) return true;\n if (a === undefined || b === undefined) return false;\n if (a === 'children' || b === 'children') return false;\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n"],"mappings":";AAMA,IAAM,OAA0B,OAAO,OAAO,CAAC,CAAC;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"dependents.js","names":[],"sources":["../../../src/core/scene/dependents.ts"],"sourcesContent":["/**\n * Which nodes must recompute when a given node's pose changes — the reverse\n * index, plus {@link dependencyIdsOf}, the forward read it is built from.\n */\nimport type { NodeId, Scene } from './types';\n\nconst NONE: readonly NodeId[] = Object.freeze([]);\n\n/** The nodes in `scene` that list `id` in their `dependsOn`, directly or through others, less any inside `id`'s own\n * subtree. */\nexport function sceneDependentsOf<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n id: NodeId,\n): readonly NodeId[] {\n if (!scene.get(id)) return NONE;\n return scene.removalClosure([id]).filter((d) => d !== id && !scene.ancestorsOf(d).includes(id));\n}\n\n/** The ids `node` names in its `dependsOn`, in order: none for a node naming `'children'` or nothing. */\nexport const sourcesOf = (node: { dependsOn?: unknown } | undefined): readonly NodeId[] =>\n (Array.isArray(node?.dependsOn) ? node.dependsOn as readonly NodeId[] : NONE);\n\n/**\n * The nodes `node`'s geometry derives from: the ids it named, or its own\n * children when it named `'children'`.\n *\n * The `'children'` form is deliberately absent from the reverse index — a\n * container is not a dependent of the children it hugs, or deleting one child\n * would cascade the whole group away. Its invalidation is the ancestor walk in\n * `scene.ts` instead.\n */\nexport function dependencyIdsOf(\n node: { id: NodeId; dependsOn?: readonly NodeId[] | 'children' },\n childrenOf: (id: NodeId) => readonly NodeId[],\n): readonly NodeId[] {\n const deps = node.dependsOn;\n if (deps === undefined) return NONE;\n return deps === 'children' ? childrenOf(node.id) : deps;\n}\n\nexport interface DependentsIndex {\n add(id: NodeId, deps: readonly NodeId[]): void;\n /** Forget what `id` declared. Deliberately not symmetric: who depends on\n * `id` is those nodes' declaration, not `id`'s, and outlives its removal. */\n remove(id: NodeId): void;\n /** Forget every registration. */\n clear(): void;\n /** True when nothing derives from anything. */\n isEmpty(): boolean;\n dependentsOf(id: NodeId): Iterable<NodeId>;\n /** Nodes that derive from `id` directly or through a chain. Excludes `id`\n * itself unless a cycle leads back to it. */\n transitiveDependentsOf(id: NodeId): Iterable<NodeId>;\n}\n\nexport function createDependentsIndex(): DependentsIndex {\n /** dependency -> nodes deriving from it */\n const forward = new Map<NodeId, Set<NodeId>>();\n /** dependent -> the dependencies it registered against */\n const reverse = new Map<NodeId, readonly NodeId[]>();\n\n /** Drop `id`'s registrations against its current dependencies. Shared by\n * `add` (which re-registers after) and `remove` (which does not). */\n function detachOwnDeps(id: NodeId): void {\n const old = reverse.get(id);\n if (old === undefined) return;\n for (const dep of old) {\n const set = forward.get(dep);\n if (set === undefined) continue;\n set.delete(id);\n if (set.size === 0) forward.delete(dep);\n }\n reverse.delete(id);\n }\n\n return {\n add(id, deps) {\n detachOwnDeps(id);\n if (deps.length === 0) return;\n reverse.set(id, [...deps]);\n for (const dep of deps) {\n let set = forward.get(dep);\n if (set === undefined) { set = new Set(); forward.set(dep, set); }\n set.add(id);\n }\n },\n\n remove(id) {\n detachOwnDeps(id);\n },\n\n clear() {\n forward.clear();\n reverse.clear();\n },\n\n isEmpty() {\n return forward.size === 0;\n },\n\n dependentsOf(id) {\n const set = forward.get(id);\n return set === undefined ? NONE : [...set];\n },\n\n transitiveDependentsOf(id) {\n // Runs per node per frame; the miss must not allocate.\n const direct = forward.get(id);\n if (direct === undefined) return NONE;\n const out = new Set<NodeId>();\n const stack: NodeId[] = [...direct];\n while (stack.length > 0) {\n const next = stack.pop()!;\n if (out.has(next)) continue; // also what stops a cycle\n out.add(next);\n for (const d of forward.get(next) ?? []) stack.push(d);\n }\n return out;\n },\n };\n}\n\n/**\n * Whether two `dependsOn` values name the same thing, so a retarget to what a\n * node already declares can be elided. Order is part of it: a router reads its\n * ends positionally, and swapping them reverses the edge.\n */\nexport function sameDependsOn(\n a: readonly NodeId[] | 'children' | undefined,\n b: readonly NodeId[] | 'children' | undefined,\n): boolean {\n if (a === b) return true;\n if (a === undefined || b === undefined) return false;\n if (a === 'children' || b === 'children') return false;\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n"],"mappings":";AAMA,IAAM,OAA0B,OAAO,OAAO,CAAC,CAAC;;;AAIhD,SAAgB,kBACd,OACA,IACmB;CACnB,IAAI,CAAC,MAAM,IAAI,EAAE,GAAG,OAAO;CAC3B,OAAO,MAAM,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,MAAM,MAAM,MAAM,CAAC,MAAM,YAAY,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;AAChG;;AAGA,IAAa,aAAa,SACvB,MAAM,QAAQ,MAAM,SAAS,IAAI,KAAK,YAAiC;;;;;;;;;;AAW1E,SAAgB,gBACd,MACA,YACmB;CACnB,MAAM,OAAO,KAAK;CAClB,IAAI,SAAS,QAAW,OAAO;CAC/B,OAAO,SAAS,aAAa,WAAW,KAAK,EAAE,IAAI;AACrD;AAiBA,SAAgB,wBAAyC;;CAEvD,MAAM,0BAAU,IAAI,IAAyB;;CAE7C,MAAM,0BAAU,IAAI,IAA+B;;;CAInD,SAAS,cAAc,IAAkB;EACvC,MAAM,MAAM,QAAQ,IAAI,EAAE;EAC1B,IAAI,QAAQ,QAAW;EACvB,KAAK,MAAM,OAAO,KAAK;GACrB,MAAM,MAAM,QAAQ,IAAI,GAAG;GAC3B,IAAI,QAAQ,QAAW;GACvB,IAAI,OAAO,EAAE;GACb,IAAI,IAAI,SAAS,GAAG,QAAQ,OAAO,GAAG;EACxC;EACA,QAAQ,OAAO,EAAE;CACnB;CAEA,OAAO;EACL,IAAI,IAAI,MAAM;GACZ,cAAc,EAAE;GAChB,IAAI,KAAK,WAAW,GAAG;GACvB,QAAQ,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC;GACzB,KAAK,MAAM,OAAO,MAAM;IACtB,IAAI,MAAM,QAAQ,IAAI,GAAG;IACzB,IAAI,QAAQ,QAAW;KAAE,sBAAM,IAAI,IAAI;KAAG,QAAQ,IAAI,KAAK,GAAG;IAAG;IACjE,IAAI,IAAI,EAAE;GACZ;EACF;EAEA,OAAO,IAAI;GACT,cAAc,EAAE;EAClB;EAEA,QAAQ;GACN,QAAQ,MAAM;GACd,QAAQ,MAAM;EAChB;EAEA,UAAU;GACR,OAAO,QAAQ,SAAS;EAC1B;EAEA,aAAa,IAAI;GACf,MAAM,MAAM,QAAQ,IAAI,EAAE;GAC1B,OAAO,QAAQ,SAAY,OAAO,CAAC,GAAG,GAAG;EAC3C;EAEA,uBAAuB,IAAI;GAEzB,MAAM,SAAS,QAAQ,IAAI,EAAE;GAC7B,IAAI,WAAW,QAAW,OAAO;GACjC,MAAM,sBAAM,IAAI,IAAY;GAC5B,MAAM,QAAkB,CAAC,GAAG,MAAM;GAClC,OAAO,MAAM,SAAS,GAAG;IACvB,MAAM,OAAO,MAAM,IAAI;IACvB,IAAI,IAAI,IAAI,IAAI,GAAG;IACnB,IAAI,IAAI,IAAI;IACZ,KAAK,MAAM,KAAK,QAAQ,IAAI,IAAI,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC;GACvD;GACA,OAAO;EACT;CACF;AACF;;;;;;AAOA,SAAgB,cACd,GACA,GACS;CACT,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,MAAM,UAAa,MAAM,QAAW,OAAO;CAC/C,IAAI,MAAM,cAAc,MAAM,YAAY,OAAO;CACjD,IAAI,EAAE,WAAW,EAAE,QAAQ,OAAO;CAClC,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK,IAAI,EAAE,OAAO,EAAE,IAAI,OAAO;CAC7D,OAAO;AACT"}
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { cubicContoursToPath, pathToCubicContours } from "@weasel-js/geom";
|
|
2
|
+
import { resolveFill, resolveStroke } from "@weasel-js/paint";
|
|
2
3
|
|
|
3
4
|
//#region src/core/scene/derivedParts.ts
|
|
4
|
-
/**
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* long as the path does — in the derivation's memo.
|
|
13
|
-
*/
|
|
5
|
+
/** What `part` paints, its `INHERIT` taken from `own`, the deriving node's
|
|
6
|
+
* data — whose own `INHERIT` takes `inherited`, its container's. */
|
|
7
|
+
function resolvePartPaint(part, own, inherited) {
|
|
8
|
+
return {
|
|
9
|
+
fill: resolveFill(part.fill, resolveFill(own?.fill, inherited?.fill)),
|
|
10
|
+
stroke: resolveStroke(part.stroke, resolveStroke(own?.stroke, inherited?.stroke))
|
|
11
|
+
};
|
|
12
|
+
}
|
|
14
13
|
var PARTS = /* @__PURE__ */ new WeakMap();
|
|
15
14
|
/**
|
|
16
15
|
* One path holding every part's outline, with the parts remembered against
|
|
@@ -54,5 +53,5 @@ function concatPaths(paths) {
|
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
//#endregion
|
|
57
|
-
export { derivedPartsOf, pathFromParts };
|
|
56
|
+
export { derivedPartsOf, pathFromParts, resolvePartPaint };
|
|
58
57
|
//# sourceMappingURL=derivedParts.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derivedParts.js","names":[],"sources":["../../../src/core/scene/derivedParts.ts"],"sourcesContent":["/**\n * A derived path that paints in several parts, each with its own fill and\n * stroke: the steps of a blend, the copies of a repeat.\n *\n * A derivation returns one `Path`, which is what picking, bounds and every\n * reader of `DerivedDep.path` see. {@link pathFromParts} makes that path out\n * of the parts and remembers the parts against it, so the derived-node\n * painter, handed the path, can paint each part as itself. The parts live as\n * long as the path does — in the derivation's memo.\n */\nimport { pathToCubicContours, cubicContoursToPath, type Path, type PolygonPath } from '@weasel-js/geom';\nimport type
|
|
1
|
+
{"version":3,"file":"derivedParts.js","names":[],"sources":["../../../src/core/scene/derivedParts.ts"],"sourcesContent":["/**\n * A derived path that paints in several parts, each with its own fill and\n * stroke: the steps of a blend, the copies of a repeat.\n *\n * A derivation returns one `Path`, which is what picking, bounds and every\n * reader of `DerivedDep.path` see. {@link pathFromParts} makes that path out\n * of the parts and remembers the parts against it, so the derived-node\n * painter, handed the path, can paint each part as itself. The parts live as\n * long as the path does — in the derivation's memo.\n */\nimport type { InheritedPaint } from './inheritedPaint';\nimport { pathToCubicContours, cubicContoursToPath, type Path, type PolygonPath } from '@weasel-js/geom';\nimport {\n resolveFill, resolveStroke, type Fill, type Inherit, type PaintedFill, type PaintedStroke, type Stroke,\n} from '@weasel-js/paint';\n\n/** One painted piece of a derived path. */\nexport interface DerivedPart {\n path: Path;\n /** The part's fill, read as a node's is: absent paints none, and\n * `INHERIT` takes the node's own `data.fill`. */\n fill?: Fill | Inherit | null;\n /** The part's stroke, on the same terms as `fill`. */\n stroke?: Stroke | Inherit | null;\n}\n\n/** What `part` paints, its `INHERIT` taken from `own`, the deriving node's\n * data — whose own `INHERIT` takes `inherited`, its container's. */\nexport function resolvePartPaint(\n part: DerivedPart,\n own: { fill?: Fill | Inherit | null; stroke?: Stroke | Inherit | null } | null | undefined,\n inherited?: InheritedPaint,\n): { fill: PaintedFill | null; stroke: PaintedStroke | null } {\n return {\n fill: resolveFill(part.fill, resolveFill(own?.fill, inherited?.fill)),\n stroke: resolveStroke(part.stroke, resolveStroke(own?.stroke, inherited?.stroke)),\n };\n}\n\nconst PARTS = new WeakMap<Path, readonly DerivedPart[]>();\n\n/**\n * One path holding every part's outline, with the parts remembered against\n * it for the painter. Return it from a `derivePath`. `null` for no parts.\n */\nexport function pathFromParts(parts: readonly DerivedPart[]): Path | null {\n if (parts.length === 0) return null;\n const whole = parts.length === 1 ? parts[0]!.path : concatPaths(parts.map((p) => p.path));\n // A one-part path is the part's own, which another reader may hold; the\n // painter must not mistake that path for a painted one elsewhere.\n const key = whole === parts[0]!.path ? { ...whole } as Path : whole;\n PARTS.set(key, parts);\n return key;\n}\n\n/** The parts `path` was made from by {@link pathFromParts}, or `undefined`\n * for any other path. */\nexport function derivedPartsOf(path: Path | null | undefined): readonly DerivedPart[] | undefined {\n return path == null ? undefined : PARTS.get(path);\n}\n\nfunction concatPaths(paths: readonly Path[]): PolygonPath {\n const polys = paths.map((p) => (p.kind === 'rect' ? cubicContoursToPath(pathToCubicContours(p)) : p));\n let commands = 0;\n let coords = 0;\n for (const p of polys) {\n commands += p.commands.length;\n coords += p.coords.length;\n }\n const out: PolygonPath = {\n kind: 'polygon',\n commands: new Uint8Array(commands),\n coords: new Float32Array(coords),\n fillRule: 'nonzero',\n };\n let ci = 0;\n let xi = 0;\n for (const p of polys) {\n out.commands.set(p.commands, ci);\n out.coords.set(p.coords, xi);\n ci += p.commands.length;\n xi += p.coords.length;\n }\n return out;\n}\n"],"mappings":";;;;;;AA4BA,SAAgB,iBACd,MACA,KACA,WAC4D;CAC5D,OAAO;EACL,MAAM,YAAY,KAAK,MAAM,YAAY,KAAK,MAAM,WAAW,IAAI,CAAC;EACpE,QAAQ,cAAc,KAAK,QAAQ,cAAc,KAAK,QAAQ,WAAW,MAAM,CAAC;CAClF;AACF;AAEA,IAAM,wBAAQ,IAAI,QAAsC;;;;;AAMxD,SAAgB,cAAc,OAA4C;CACxE,IAAI,MAAM,WAAW,GAAG,OAAO;CAC/B,MAAM,QAAQ,MAAM,WAAW,IAAI,MAAM,EAAE,CAAE,OAAO,YAAY,MAAM,KAAK,MAAM,EAAE,IAAI,CAAC;CAGxF,MAAM,MAAM,UAAU,MAAM,EAAE,CAAE,OAAO,EAAE,GAAG,MAAM,IAAY;CAC9D,MAAM,IAAI,KAAK,KAAK;CACpB,OAAO;AACT;;;AAIA,SAAgB,eAAe,MAAmE;CAChG,OAAO,QAAQ,OAAO,SAAY,MAAM,IAAI,IAAI;AAClD;AAEA,SAAS,YAAY,OAAqC;CACxD,MAAM,QAAQ,MAAM,KAAK,MAAO,EAAE,SAAS,SAAS,oBAAoB,oBAAoB,CAAC,CAAC,IAAI,CAAE;CACpG,IAAI,WAAW;CACf,IAAI,SAAS;CACb,KAAK,MAAM,KAAK,OAAO;EACrB,YAAY,EAAE,SAAS;EACvB,UAAU,EAAE,OAAO;CACrB;CACA,MAAM,MAAmB;EACvB,MAAM;EACN,UAAU,IAAI,WAAW,QAAQ;EACjC,QAAQ,IAAI,aAAa,MAAM;EAC/B,UAAU;CACZ;CACA,IAAI,KAAK;CACT,IAAI,KAAK;CACT,KAAK,MAAM,KAAK,OAAO;EACrB,IAAI,SAAS,IAAI,EAAE,UAAU,EAAE;EAC/B,IAAI,OAAO,IAAI,EAAE,QAAQ,EAAE;EAC3B,MAAM,EAAE,SAAS;EACjB,MAAM,EAAE,OAAO;CACjB;CACA,OAAO;AACT"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//#region src/core/scene/documentOf.ts
|
|
2
|
+
var refuse = () => {
|
|
3
|
+
throw new Error("documentOf: the document reading holds no overrides; write them to the scene");
|
|
4
|
+
};
|
|
5
|
+
/** The empty table a document reading answers with. */
|
|
6
|
+
var DOCUMENT_OVERRIDES = Object.freeze({
|
|
7
|
+
set: refuse,
|
|
8
|
+
get: () => void 0,
|
|
9
|
+
read: (_id) => void 0,
|
|
10
|
+
has: () => false,
|
|
11
|
+
ids: () => [],
|
|
12
|
+
clear: refuse,
|
|
13
|
+
clearAll: refuse,
|
|
14
|
+
commit: refuse,
|
|
15
|
+
subscribe: () => () => {},
|
|
16
|
+
getGeneration: () => 0,
|
|
17
|
+
hold: () => refuse()
|
|
18
|
+
});
|
|
19
|
+
var views = /* @__PURE__ */ new WeakMap();
|
|
20
|
+
/**
|
|
21
|
+
* `source` read as its document holds it: the same object in every respect but
|
|
22
|
+
* its `overrides`, which are empty, so no pose, path or data override reaches
|
|
23
|
+
* anything handed it. One view per source, so memos keyed on it hit. The
|
|
24
|
+
* readers it is handed to memoize the document reading apart from the shown
|
|
25
|
+
* one, as `documentPose` and `documentDepOf` do.
|
|
26
|
+
*/
|
|
27
|
+
function documentOf(source) {
|
|
28
|
+
if (isDocument(source)) return source;
|
|
29
|
+
let view = views.get(source);
|
|
30
|
+
if (view === void 0) {
|
|
31
|
+
view = Object.create(source, { overrides: { value: DOCUMENT_OVERRIDES } });
|
|
32
|
+
views.set(source, view);
|
|
33
|
+
}
|
|
34
|
+
return view;
|
|
35
|
+
}
|
|
36
|
+
/** Whether `source` is a {@link documentOf} view. */
|
|
37
|
+
function isDocument(source) {
|
|
38
|
+
return source.overrides === DOCUMENT_OVERRIDES;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
export { documentOf, isDocument };
|
|
43
|
+
//# sourceMappingURL=documentOf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documentOf.js","names":[],"sources":["../../../src/core/scene/documentOf.ts"],"sourcesContent":["/**\n * `documentOf` — a scene read as its document holds it.\n *\n * Commands and exports act on the document: Expand bakes what an effect's\n * sources store, an SVG save writes it, Align measures it. Handed the scene\n * itself, every reader they reach — `effectivePose`, `derivedDepOf`, the\n * canvas's derived paths and drawn bounds — would bake in whatever a gesture or\n * an open text edit is showing. Handed `documentOf(scene)`, each of them reads\n * the document, because the view it is handed holds no overrides.\n */\nimport type { NodeId, PoseHold, PoseOverride, PoseOverrides } from './types';\n\nconst refuse = (): never => {\n throw new Error('documentOf: the document reading holds no overrides; write them to the scene');\n};\n\n/** The empty table a document reading answers with. */\nconst DOCUMENT_OVERRIDES: PoseOverrides<never, never> = Object.freeze({\n set: refuse,\n get: (): undefined => undefined,\n read: (_id: NodeId): PoseOverride<never, never> | undefined => undefined,\n has: () => false,\n ids: () => [],\n clear: refuse,\n clearAll: refuse,\n commit: refuse,\n subscribe: () => () => {},\n getGeneration: () => 0,\n hold: (): PoseHold<never, never> => refuse(),\n});\n\nconst views = new WeakMap<object, object>();\n\n/**\n * `source` read as its document holds it: the same object in every respect but\n * its `overrides`, which are empty, so no pose, path or data override reaches\n * anything handed it. One view per source, so memos keyed on it hit. The\n * readers it is handed to memoize the document reading apart from the shown\n * one, as `documentPose` and `documentDepOf` do.\n */\nexport function documentOf<TSource extends { readonly overrides: unknown }>(source: TSource): TSource {\n if (isDocument(source)) return source;\n let view = views.get(source);\n if (view === undefined) {\n view = Object.create(source, { overrides: { value: DOCUMENT_OVERRIDES } }) as object;\n views.set(source, view);\n }\n return view as TSource;\n}\n\n/** Whether `source` is a {@link documentOf} view. */\nexport function isDocument(source: { readonly overrides: unknown }): boolean {\n return source.overrides === DOCUMENT_OVERRIDES;\n}\n"],"mappings":";AAYA,IAAM,eAAsB;CAC1B,MAAM,IAAI,MAAM,8EAA8E;AAChG;;AAGA,IAAM,qBAAkD,OAAO,OAAO;CACpE,KAAK;CACL,WAAsB;CACtB,OAAO,QAAwD;CAC/D,WAAW;CACX,WAAW,CAAC;CACZ,OAAO;CACP,UAAU;CACV,QAAQ;CACR,uBAAuB,CAAC;CACxB,qBAAqB;CACrB,YAAoC,OAAO;AAC7C,CAAC;AAED,IAAM,wBAAQ,IAAI,QAAwB;;;;;;;;AAS1C,SAAgB,WAA4D,QAA0B;CACpG,IAAI,WAAW,MAAM,GAAG,OAAO;CAC/B,IAAI,OAAO,MAAM,IAAI,MAAM;CAC3B,IAAI,SAAS,QAAW;EACtB,OAAO,OAAO,OAAO,QAAQ,EAAE,WAAW,EAAE,OAAO,mBAAmB,EAAE,CAAC;EACzE,MAAM,IAAI,QAAQ,IAAI;CACxB;CACA,OAAO;AACT;;AAGA,SAAgB,WAAW,QAAkD;CAC3E,OAAO,OAAO,cAAc;AAC9B"}
|
|
@@ -3,6 +3,9 @@ import { carryDepPath, depFrameRebase, pathAsPainted } from "./depFrame.js";
|
|
|
3
3
|
import { dependencyIdsOf } from "./dependents.js";
|
|
4
4
|
import { dropPoseKeyedMemoSlots, nodeMemo } from "./nodeMemo.js";
|
|
5
5
|
import { resolveDerivedPath } from "./derivedPath.js";
|
|
6
|
+
import { inheritedPaintIn } from "./inheritedPaint.js";
|
|
7
|
+
import { isDocument } from "./documentOf.js";
|
|
8
|
+
import { nodeAsShown, shownLookup } from "./nodeAsShown.js";
|
|
6
9
|
|
|
7
10
|
//#region src/core/scene/effectivePose.ts
|
|
8
11
|
/**
|
|
@@ -39,9 +42,14 @@ var cycleHits = 0;
|
|
|
39
42
|
* derivation the same frame it is published.
|
|
40
43
|
*/
|
|
41
44
|
function derivedPose(source, node) {
|
|
42
|
-
return derivedPoseIn(source, node,
|
|
45
|
+
return derivedPoseIn(source, node, readingOf(source));
|
|
43
46
|
}
|
|
44
|
-
|
|
47
|
+
/** How `source` is read: as its document holds it when it is a `documentOf` view. */
|
|
48
|
+
function readingOf(source) {
|
|
49
|
+
return isDocument(source) ? "document" : "effective";
|
|
50
|
+
}
|
|
51
|
+
function derivedPoseIn(source, stored, reading) {
|
|
52
|
+
const node = shownIn(source, stored, reading);
|
|
45
53
|
const derive = node.derivePose;
|
|
46
54
|
if (derive === void 0) return null;
|
|
47
55
|
const ids = dependencyIdsOf(node, source.childrenOf);
|
|
@@ -84,13 +92,15 @@ function run(node, derive, deps, into) {
|
|
|
84
92
|
* resolved before it is read.
|
|
85
93
|
*/
|
|
86
94
|
function derivedDepOf(source, id, reader) {
|
|
87
|
-
|
|
95
|
+
const reading = readingOf(source);
|
|
96
|
+
return reader === void 0 ? depIn(source, id, reading) : depsAsRead(source, reader, reading)(id);
|
|
88
97
|
}
|
|
89
|
-
/** `id` as {@link derivedDepOf} answers it, but at the pose and
|
|
90
|
-
* document holds: no override anywhere down its dependencies counts.
|
|
91
|
-
*
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
/** `id` as {@link derivedDepOf} answers it, but at the pose, path and data the
|
|
99
|
+
* document holds: no override anywhere down its dependencies counts. The same
|
|
100
|
+
* reading as `derivedDepOf(documentOf(source), …)`, for a reader that must not
|
|
101
|
+
* see an in-flight gesture or an open edit, such as an edit pass. */
|
|
102
|
+
function documentDepOf(source, id, reader) {
|
|
103
|
+
return reader === void 0 ? depIn(source, id, "document") : depsAsRead(source, reader, "document")(id);
|
|
94
104
|
}
|
|
95
105
|
/** `(id) => that dependency as `reader`'s derivation is handed it`: its pose
|
|
96
106
|
* in `reader`'s frame where the scene composes frames. A `'children'`
|
|
@@ -125,6 +135,9 @@ var RebasedDep = class {
|
|
|
125
135
|
const path = this.dep.path;
|
|
126
136
|
return path === null ? null : carryDepPath(path, this.dep.pose, this.pose);
|
|
127
137
|
}
|
|
138
|
+
get inherited() {
|
|
139
|
+
return this.dep.inherited;
|
|
140
|
+
}
|
|
128
141
|
};
|
|
129
142
|
function depIn(source, id, reading) {
|
|
130
143
|
const node = source.get(id);
|
|
@@ -138,15 +151,16 @@ function depIn(source, id, reading) {
|
|
|
138
151
|
*/
|
|
139
152
|
var SceneDep = class {
|
|
140
153
|
source;
|
|
141
|
-
posed;
|
|
142
154
|
reading;
|
|
143
155
|
node;
|
|
144
156
|
pose;
|
|
145
157
|
shown;
|
|
146
|
-
|
|
158
|
+
posed;
|
|
159
|
+
constructor(source, stored, reading) {
|
|
147
160
|
this.source = source;
|
|
148
|
-
this.posed = posed;
|
|
149
161
|
this.reading = reading;
|
|
162
|
+
const posed = shownIn(source, stored, reading);
|
|
163
|
+
this.posed = posed;
|
|
150
164
|
this.node = posed;
|
|
151
165
|
const override = reading === "effective" ? source.overrides.read(posed.id) : void 0;
|
|
152
166
|
this.shown = override?.path;
|
|
@@ -157,7 +171,16 @@ var SceneDep = class {
|
|
|
157
171
|
const { source, reading } = this;
|
|
158
172
|
return resolveDerivedPath(this.posed, depsAsRead(source, this.posed, reading), (depId) => source.childrenOf(depId), PATH_SLOT[reading]);
|
|
159
173
|
}
|
|
174
|
+
get inherited() {
|
|
175
|
+
const { source, reading } = this;
|
|
176
|
+
return inheritedPaintIn(reading === "effective" ? shownLookup(source) : source, this.posed);
|
|
177
|
+
}
|
|
160
178
|
};
|
|
179
|
+
/** `node` as `reading` reads it: with the data an override shows it with in the effective
|
|
180
|
+
* reading, as stored in the document one. */
|
|
181
|
+
function shownIn(source, node, reading) {
|
|
182
|
+
return reading === "effective" ? nodeAsShown(source.overrides, node) : node;
|
|
183
|
+
}
|
|
161
184
|
function poseIn(source, node, reading) {
|
|
162
185
|
if (reading === "effective") {
|
|
163
186
|
const override = source.overrides.read(node.id)?.pose;
|
|
@@ -172,7 +195,8 @@ function poseIn(source, node, reading) {
|
|
|
172
195
|
* something it derives from is being dragged.
|
|
173
196
|
*
|
|
174
197
|
* For a reader that must not see an in-flight gesture, such as an action
|
|
175
|
-
* capturing the `from` of a transform op.
|
|
198
|
+
* capturing the `from` of a transform op. The same reading as
|
|
199
|
+
* `effectivePose(documentOf(source), node)`.
|
|
176
200
|
*/
|
|
177
201
|
function documentPose(source, node) {
|
|
178
202
|
return poseIn(source, node, "document");
|
|
@@ -182,7 +206,7 @@ function documentPose(source, node) {
|
|
|
182
206
|
* comes from here.
|
|
183
207
|
*/
|
|
184
208
|
function effectivePose(source, node) {
|
|
185
|
-
return poseIn(source, node,
|
|
209
|
+
return poseIn(source, node, readingOf(source));
|
|
186
210
|
}
|
|
187
211
|
/**
|
|
188
212
|
* Whether `node`'s pose is a frame its children are expressed in, under a
|
|
@@ -195,9 +219,14 @@ function effectivePose(source, node) {
|
|
|
195
219
|
* frame — and the composition fold passes over it.
|
|
196
220
|
*/
|
|
197
221
|
function definesFrame(node) {
|
|
198
|
-
return !(node
|
|
222
|
+
return !isEnvelope(node);
|
|
223
|
+
}
|
|
224
|
+
/** Whether `node` derives its pose from its children: a group that is its
|
|
225
|
+
* members, so moving them moves it. */
|
|
226
|
+
function isEnvelope(node) {
|
|
227
|
+
return node.dependsOn === "children" && node.derivePose !== void 0;
|
|
199
228
|
}
|
|
200
229
|
|
|
201
230
|
//#endregion
|
|
202
|
-
export { definesFrame, derivedDepOf, derivedPose, documentDepOf, documentPose, effectivePose };
|
|
231
|
+
export { definesFrame, derivedDepOf, derivedPose, documentDepOf, documentPose, effectivePose, isEnvelope };
|
|
203
232
|
//# sourceMappingURL=effectivePose.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effectivePose.js","names":[],"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 type { PoseComposition } from './composeFrame';\nimport { carryDepPath, depFrameRebase, pathAsPainted } from './depFrame';\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 /** Read under a composing strategy, to find the frame its pose is in. */\n parent?: NodeId | null;\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 /** When it composes frames, a derivation reads each dependency in the\n * frame of the node deriving. */\n readonly composition?: PoseComposition<TPose>;\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 = depsAsRead(source, node, 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 reader?: PosedNode<TPose>,\n): DerivedDep<TPose> | undefined {\n return reader === undefined ? depIn(source, id, 'effective') : depsAsRead(source, reader, 'effective')(id);\n}\n\n/** `id` as {@link derivedDepOf} answers it, but at the pose and path the\n * document holds: no override anywhere down its dependencies counts. For a\n * reader that must not see an in-flight gesture, such as an edit pass. */\nexport function documentDepOf<TPose>(source: PoseSource<TPose>, id: NodeId): DerivedDep<TPose> | undefined {\n return depIn(source, id, 'document');\n}\n\n/** `(id) => that dependency as `reader`'s derivation is handed it`: its pose\n * in `reader`'s frame where the scene composes frames. A `'children'`\n * dependent shares its children's frame, so it reads them as they are. */\nfunction depsAsRead<TPose>(\n source: PoseSource<TPose>,\n reader: PosedNode<TPose>,\n reading: Reading,\n): (id: NodeId) => DerivedDep<TPose> | undefined {\n const plain = (id: NodeId) => depIn(source, id, reading);\n if (reader.dependsOn === 'children') return plain;\n const rebase = depFrameRebase(\n source.composition,\n reader,\n (id) => source.get(id),\n (id) => poseIn(source, source.get(id)!, reading),\n (id) => {\n const n = source.get(id);\n return n === undefined || definesFrame(n);\n },\n );\n if (rebase === null) return plain;\n return (id) => {\n const dep = plain(id);\n if (dep === undefined) return undefined;\n const pose = rebase(id, dep.pose);\n return pose === dep.pose ? dep : new RebasedDep(dep, pose);\n };\n}\n\n/** A dependency read from another frame: its pose rebased, and its path\n * carried by the same frame change when asked for. */\nclass RebasedDep<TPose> implements DerivedDep<TPose> {\n readonly node: Node<unknown, string, TPose>;\n\n constructor(private readonly dep: DerivedDep<TPose>, readonly pose: TPose) {\n this.node = dep.node;\n }\n\n get path(): Path | null {\n const path = this.dep.path;\n return path === null ? null : carryDepPath(path, this.dep.pose, this.pose);\n }\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 pathAsPainted(this.shown, this.pose, this.pose);\n const { source, reading } = this;\n return resolveDerivedPath(\n this.posed,\n depsAsRead(source, this.posed, 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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"}
|
|
1
|
+
{"version":3,"file":"effectivePose.js","names":[],"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 type { PoseComposition } from './composeFrame';\nimport { carryDepPath, depFrameRebase, pathAsPainted } from './depFrame';\nimport { dependencyIdsOf } from './dependents';\nimport { resolveDerivedPath } from './derivedPath';\nimport { inheritedPaintIn, type InheritedPaint } from './inheritedPaint';\nimport { isDocument } from './documentOf';\nimport { nodeAsShown, shownLookup } from './nodeAsShown';\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. A\n * `documentOf` view is read as `document` by every entry point. 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?: 'mark' | 'group';\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 /** Read under a composing strategy, to find the frame its pose is in. */\n parent?: NodeId | null;\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 /** When it composes frames, a derivation reads each dependency in the\n * frame of the node deriving. */\n readonly composition?: PoseComposition<TPose>;\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, readingOf(source));\n}\n\n/** How `source` is read: as its document holds it when it is a `documentOf` view. */\nfunction readingOf(source: PoseSource<unknown>): Reading {\n return isDocument(source) ? 'document' : 'effective';\n}\n\nfunction derivedPoseIn<TPose>(\n source: PoseSource<TPose>,\n stored: PosedNode<TPose>,\n reading: Reading,\n): TPose | null {\n const node = shownIn(source, stored, reading);\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 = depsAsRead(source, node, 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 reader?: PosedNode<TPose>,\n): DerivedDep<TPose> | undefined {\n const reading = readingOf(source);\n return reader === undefined ? depIn(source, id, reading) : depsAsRead(source, reader, reading)(id);\n}\n\n/** `id` as {@link derivedDepOf} answers it, but at the pose, path and data the\n * document holds: no override anywhere down its dependencies counts. The same\n * reading as `derivedDepOf(documentOf(source), …)`, for a reader that must not\n * see an in-flight gesture or an open edit, such as an edit pass. */\nexport function documentDepOf<TPose>(\n source: PoseSource<TPose>,\n id: NodeId,\n reader?: PosedNode<TPose>,\n): DerivedDep<TPose> | undefined {\n return reader === undefined ? depIn(source, id, 'document') : depsAsRead(source, reader, 'document')(id);\n}\n\n/** `(id) => that dependency as `reader`'s derivation is handed it`: its pose\n * in `reader`'s frame where the scene composes frames. A `'children'`\n * dependent shares its children's frame, so it reads them as they are. */\nfunction depsAsRead<TPose>(\n source: PoseSource<TPose>,\n reader: PosedNode<TPose>,\n reading: Reading,\n): (id: NodeId) => DerivedDep<TPose> | undefined {\n const plain = (id: NodeId) => depIn(source, id, reading);\n if (reader.dependsOn === 'children') return plain;\n const rebase = depFrameRebase(\n source.composition,\n reader,\n (id) => source.get(id),\n (id) => poseIn(source, source.get(id)!, reading),\n (id) => {\n const n = source.get(id);\n return n === undefined || definesFrame(n);\n },\n );\n if (rebase === null) return plain;\n return (id) => {\n const dep = plain(id);\n if (dep === undefined) return undefined;\n const pose = rebase(id, dep.pose);\n return pose === dep.pose ? dep : new RebasedDep(dep, pose);\n };\n}\n\n/** A dependency read from another frame: its pose rebased, and its path\n * carried by the same frame change when asked for. */\nclass RebasedDep<TPose> implements DerivedDep<TPose> {\n readonly node: Node<unknown, string, TPose>;\n\n constructor(private readonly dep: DerivedDep<TPose>, readonly pose: TPose) {\n this.node = dep.node;\n }\n\n get path(): Path | null {\n const path = this.dep.path;\n return path === null ? null : carryDepPath(path, this.dep.pose, this.pose);\n }\n\n get inherited(): InheritedPaint | undefined {\n return this.dep.inherited;\n }\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 private readonly posed: PosedNode<TPose>;\n\n constructor(\n private readonly source: PoseSource<TPose>,\n stored: PosedNode<TPose>,\n private readonly reading: Reading,\n ) {\n const posed = shownIn(source, stored, reading);\n this.posed = posed;\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 pathAsPainted(this.shown, this.pose, this.pose);\n const { source, reading } = this;\n return resolveDerivedPath(\n this.posed,\n depsAsRead(source, this.posed, reading),\n (depId) => source.childrenOf(depId),\n PATH_SLOT[reading],\n );\n }\n\n get inherited(): InheritedPaint | undefined {\n const { source, reading } = this;\n return inheritedPaintIn(reading === 'effective' ? shownLookup(source) : source, this.posed);\n }\n}\n\n/** `node` as `reading` reads it: with the data an override shows it with in the effective\n * reading, as stored in the document one. */\nfunction shownIn<TPose>(source: PoseSource<TPose>, node: PosedNode<TPose>, reading: Reading): PosedNode<TPose> {\n return reading === 'effective' ? nodeAsShown(source.overrides, node) : node;\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. The same reading as\n * `effectivePose(documentOf(source), node)`.\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, readingOf(source));\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 !isEnvelope(node);\n}\n\n/** Whether `node` derives its pose from its children: a group that is its\n * members, so moving them moves it. */\nexport function isEnvelope(node: { dependsOn?: unknown; derivePose?: unknown }): boolean {\n return node.dependsOn === 'children' && node.derivePose !== undefined;\n}\n"],"mappings":"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"}
|