@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,5 +1,5 @@
|
|
|
1
1
|
import { serialize } from "./serialize.js";
|
|
2
|
-
import { actionBindings, buildDepsFromRequires, evaluateActive, evaluateEnabled, routesForSpec } from "@weasel-js/routing";
|
|
2
|
+
import { actionBindings, buildDepsFromRequires, evaluateActive, evaluateEnabled, overriddenBindings, routesForSpec } from "@weasel-js/routing";
|
|
3
3
|
|
|
4
4
|
//#region src/devtools/registry.ts
|
|
5
5
|
/** What one canvas has registered — its tools, actions, deps and node kinds — as plain data for `get-registry`. */
|
|
@@ -18,7 +18,7 @@ function bindingOf(binding) {
|
|
|
18
18
|
opts: serialize(binding.opts)
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
-
function toolOf(entry, slot) {
|
|
21
|
+
function toolOf(entry, slot, overrides) {
|
|
22
22
|
const p = entry.presentation;
|
|
23
23
|
return {
|
|
24
24
|
id: entry.id,
|
|
@@ -31,7 +31,7 @@ function toolOf(entry, slot) {
|
|
|
31
31
|
hidden: p?.hide === true,
|
|
32
32
|
cursor: serialize(entry.cursor),
|
|
33
33
|
eligibility: serialize(entry.eligibility),
|
|
34
|
-
bindings: (entry.bindings ?? []).map(bindingOf),
|
|
34
|
+
bindings: overriddenBindings(entry.bindings ?? [], entry.id, overrides).map(bindingOf),
|
|
35
35
|
actions: (entry.actions ?? []).map((a) => a.id),
|
|
36
36
|
deps: Object.keys(entry.deps ?? {}),
|
|
37
37
|
hasOverlay: entry.overlay !== void 0
|
|
@@ -71,7 +71,7 @@ function describeRegistry(inputs) {
|
|
|
71
71
|
for (const e of entries) {
|
|
72
72
|
if (seen.has(e.id)) continue;
|
|
73
73
|
seen.add(e.id);
|
|
74
|
-
tools.push(toolOf(e, slot));
|
|
74
|
+
tools.push(toolOf(e, slot, inputs.overrides));
|
|
75
75
|
}
|
|
76
76
|
};
|
|
77
77
|
add(Object.values(inputs.tools.registry), "tool");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","names":[],"sources":["../../src/devtools/registry.ts"],"sourcesContent":["/** What one canvas has registered — its tools, actions, deps and node kinds — as plain data for `get-registry`. */\nimport {\n actionBindings, buildDepsFromRequires, evaluateActive, evaluateEnabled, routesForSpec,\n type Action, type ActionSource, type Contribution, type DepRegistry, type GestureBinding,\n} from '@weasel-js/routing';\nimport type {\n DevtoolsActionEntry, DevtoolsBinding, DevtoolsRegistry, DevtoolsToolEntry,\n} from './protocol';\nimport { serialize } from './serialize';\n\ntype Entry = Contribution<unknown> & { cursor?: unknown };\n\n/** The live registries {@link describeRegistry} reads. */\nexport interface RegistryInputs {\n tools: { registry: Readonly<Record<string, Entry>>; ambient: readonly Entry[] };\n /** The entries a `features` preset brought beside the tools. */\n contributions: readonly Entry[];\n actions: ActionSource | null;\n deps: DepRegistry | null;\n routingKinds: readonly string[];\n}\n\nfunction routesOf(binding: GestureBinding): string[] {\n try {\n return [...routesForSpec(binding.spec)];\n } catch {\n return [];\n }\n}\n\nfunction bindingOf(binding: GestureBinding): DevtoolsBinding {\n return {\n actionId: binding.actionId,\n spec: serialize(binding.spec),\n routes: routesOf(binding),\n opts: serialize(binding.opts),\n };\n}\n\nfunction toolOf(entry: Entry, slot: DevtoolsToolEntry['slot']): DevtoolsToolEntry {\n const p = entry.presentation;\n return {\n id: entry.id,\n slot,\n label: p?.label ?? entry.id,\n icon: p?.icon ?? null,\n group: p?.group ?? null,\n shortcut: p?.shortcut ?? null,\n hotkey: entry.eligibility?.offhand ?? null,\n hidden: p?.hide === true,\n cursor: serialize(entry.cursor),\n eligibility: serialize(entry.eligibility),\n bindings: (entry.bindings ?? []).map(bindingOf),\n actions: (entry.actions ?? []).map((a) => a.id),\n deps: Object.keys(entry.deps ?? {}),\n hasOverlay: entry.overlay !== undefined,\n };\n}\n\nfunction actionOf(action: Action, deps: DepRegistry | null): DevtoolsActionEntry {\n const bag = deps ? buildDepsFromRequires(action, deps) : undefined;\n const enabled = evaluateEnabled(action, bag);\n const rule: unknown = action.eligible;\n return {\n id: action.id,\n label: action.label ?? action.id,\n icon: action.icon ?? null,\n group: action.group ?? null,\n tags: [...(action.tags ?? [])],\n shortcut: action.shortcut ?? null,\n scope: action.scope === 'hotkey' ? 'hotkey' : 'ambient',\n invoker: action.invoker?.timing ?? null,\n requires: [...(action.requires ?? [])],\n variants: (action.variants ?? []).map((v) => ({\n key: v.key, label: v.label, icon: v.icon ?? null, params: serialize(v.params),\n })),\n enabled: enabled.enabled ? true : (enabled.reason ?? 'disabled'),\n active: evaluateActive(action, bag) ?? null,\n hasPreview: action.preview !== undefined,\n // A fluent condition is callable and carries its rule tree on `.rule`.\n eligible: serialize(typeof rule === 'function' ? (rule as { rule?: unknown }).rule : (rule ?? null)),\n bindings: actionBindings(action).map(bindingOf),\n };\n}\n\nexport function describeRegistry(inputs: RegistryInputs): DevtoolsRegistry {\n const seen = new Set<string>();\n const tools: DevtoolsToolEntry[] = [];\n const add = (entries: readonly Entry[], slot: DevtoolsToolEntry['slot']): void => {\n for (const e of entries) {\n if (seen.has(e.id)) continue;\n seen.add(e.id);\n tools.push(toolOf(e, slot));\n }\n };\n add(Object.values(inputs.tools.registry), 'tool');\n add(inputs.tools.ambient, 'ambient');\n add(inputs.contributions, 'contribution');\n return {\n tools,\n actions: (inputs.actions?.list() ?? []).map((a) => actionOf(a, inputs.deps)),\n deps: (inputs.deps?.list?.() ?? []).map((d) => ({ ...d })),\n routingKinds: [...inputs.routingKinds],\n };\n}\n"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"registry.js","names":[],"sources":["../../src/devtools/registry.ts"],"sourcesContent":["/** What one canvas has registered — its tools, actions, deps and node kinds — as plain data for `get-registry`. */\nimport {\n actionBindings, buildDepsFromRequires, evaluateActive, evaluateEnabled, overriddenBindings, routesForSpec,\n type Action, type ActionSource, type Contribution, type DepRegistry, type GestureBinding, type ResolvedBindingOverrides,\n} from '@weasel-js/routing';\nimport type {\n DevtoolsActionEntry, DevtoolsBinding, DevtoolsRegistry, DevtoolsToolEntry,\n} from './protocol';\nimport { serialize } from './serialize';\n\ntype Entry = Contribution<unknown> & { cursor?: unknown };\n\n/** The live registries {@link describeRegistry} reads. */\nexport interface RegistryInputs {\n tools: { registry: Readonly<Record<string, Entry>>; ambient: readonly Entry[] };\n /** The entries a `features` preset brought beside the tools. */\n contributions: readonly Entry[];\n actions: ActionSource | null;\n /** Binding overrides in force, applied to the entries' bindings; `actions`\n * lists its own already overridden. */\n overrides?: ResolvedBindingOverrides;\n deps: DepRegistry | null;\n routingKinds: readonly string[];\n}\n\nfunction routesOf(binding: GestureBinding): string[] {\n try {\n return [...routesForSpec(binding.spec)];\n } catch {\n return [];\n }\n}\n\nfunction bindingOf(binding: GestureBinding): DevtoolsBinding {\n return {\n actionId: binding.actionId,\n spec: serialize(binding.spec),\n routes: routesOf(binding),\n opts: serialize(binding.opts),\n };\n}\n\nfunction toolOf(entry: Entry, slot: DevtoolsToolEntry['slot'], overrides: ResolvedBindingOverrides | undefined): DevtoolsToolEntry {\n const p = entry.presentation;\n return {\n id: entry.id,\n slot,\n label: p?.label ?? entry.id,\n icon: p?.icon ?? null,\n group: p?.group ?? null,\n shortcut: p?.shortcut ?? null,\n hotkey: entry.eligibility?.offhand ?? null,\n hidden: p?.hide === true,\n cursor: serialize(entry.cursor),\n eligibility: serialize(entry.eligibility),\n bindings: overriddenBindings(entry.bindings ?? [], entry.id, overrides).map(bindingOf),\n actions: (entry.actions ?? []).map((a) => a.id),\n deps: Object.keys(entry.deps ?? {}),\n hasOverlay: entry.overlay !== undefined,\n };\n}\n\nfunction actionOf(action: Action, deps: DepRegistry | null): DevtoolsActionEntry {\n const bag = deps ? buildDepsFromRequires(action, deps) : undefined;\n const enabled = evaluateEnabled(action, bag);\n const rule: unknown = action.eligible;\n return {\n id: action.id,\n label: action.label ?? action.id,\n icon: action.icon ?? null,\n group: action.group ?? null,\n tags: [...(action.tags ?? [])],\n shortcut: action.shortcut ?? null,\n scope: action.scope === 'hotkey' ? 'hotkey' : 'ambient',\n invoker: action.invoker?.timing ?? null,\n requires: [...(action.requires ?? [])],\n variants: (action.variants ?? []).map((v) => ({\n key: v.key, label: v.label, icon: v.icon ?? null, params: serialize(v.params),\n })),\n enabled: enabled.enabled ? true : (enabled.reason ?? 'disabled'),\n active: evaluateActive(action, bag) ?? null,\n hasPreview: action.preview !== undefined,\n // A fluent condition is callable and carries its rule tree on `.rule`.\n eligible: serialize(typeof rule === 'function' ? (rule as { rule?: unknown }).rule : (rule ?? null)),\n bindings: actionBindings(action).map(bindingOf),\n };\n}\n\nexport function describeRegistry(inputs: RegistryInputs): DevtoolsRegistry {\n const seen = new Set<string>();\n const tools: DevtoolsToolEntry[] = [];\n const add = (entries: readonly Entry[], slot: DevtoolsToolEntry['slot']): void => {\n for (const e of entries) {\n if (seen.has(e.id)) continue;\n seen.add(e.id);\n tools.push(toolOf(e, slot, inputs.overrides));\n }\n };\n add(Object.values(inputs.tools.registry), 'tool');\n add(inputs.tools.ambient, 'ambient');\n add(inputs.contributions, 'contribution');\n return {\n tools,\n actions: (inputs.actions?.list() ?? []).map((a) => actionOf(a, inputs.deps)),\n deps: (inputs.deps?.list?.() ?? []).map((d) => ({ ...d })),\n routingKinds: [...inputs.routingKinds],\n };\n}\n"],"mappings":";;;;;AAyBA,SAAS,SAAS,SAAmC;CACnD,IAAI;EACF,OAAO,CAAC,GAAG,cAAc,QAAQ,IAAI,CAAC;CACxC,QAAQ;EACN,OAAO,CAAC;CACV;AACF;AAEA,SAAS,UAAU,SAA0C;CAC3D,OAAO;EACL,UAAU,QAAQ;EAClB,MAAM,UAAU,QAAQ,IAAI;EAC5B,QAAQ,SAAS,OAAO;EACxB,MAAM,UAAU,QAAQ,IAAI;CAC9B;AACF;AAEA,SAAS,OAAO,OAAc,MAAiC,WAAoE;CACjI,MAAM,IAAI,MAAM;CAChB,OAAO;EACL,IAAI,MAAM;EACV;EACA,OAAO,GAAG,SAAS,MAAM;EACzB,MAAM,GAAG,QAAQ;EACjB,OAAO,GAAG,SAAS;EACnB,UAAU,GAAG,YAAY;EACzB,QAAQ,MAAM,aAAa,WAAW;EACtC,QAAQ,GAAG,SAAS;EACpB,QAAQ,UAAU,MAAM,MAAM;EAC9B,aAAa,UAAU,MAAM,WAAW;EACxC,UAAU,mBAAmB,MAAM,YAAY,CAAC,GAAG,MAAM,IAAI,SAAS,CAAC,CAAC,IAAI,SAAS;EACrF,UAAU,MAAM,WAAW,CAAC,EAAA,CAAG,KAAK,MAAM,EAAE,EAAE;EAC9C,MAAM,OAAO,KAAK,MAAM,QAAQ,CAAC,CAAC;EAClC,YAAY,MAAM,YAAY;CAChC;AACF;AAEA,SAAS,SAAS,QAAgB,MAA+C;CAC/E,MAAM,MAAM,OAAO,sBAAsB,QAAQ,IAAI,IAAI;CACzD,MAAM,UAAU,gBAAgB,QAAQ,GAAG;CAC3C,MAAM,OAAgB,OAAO;CAC7B,OAAO;EACL,IAAI,OAAO;EACX,OAAO,OAAO,SAAS,OAAO;EAC9B,MAAM,OAAO,QAAQ;EACrB,OAAO,OAAO,SAAS;EACvB,MAAM,CAAC,GAAI,OAAO,QAAQ,CAAC,CAAE;EAC7B,UAAU,OAAO,YAAY;EAC7B,OAAO,OAAO,UAAU,WAAW,WAAW;EAC9C,SAAS,OAAO,SAAS,UAAU;EACnC,UAAU,CAAC,GAAI,OAAO,YAAY,CAAC,CAAE;EACrC,WAAW,OAAO,YAAY,CAAC,EAAA,CAAG,KAAK,OAAO;GAC5C,KAAK,EAAE;GAAK,OAAO,EAAE;GAAO,MAAM,EAAE,QAAQ;GAAM,QAAQ,UAAU,EAAE,MAAM;EAC9E,EAAE;EACF,SAAS,QAAQ,UAAU,OAAQ,QAAQ,UAAU;EACrD,QAAQ,eAAe,QAAQ,GAAG,KAAK;EACvC,YAAY,OAAO,YAAY;EAE/B,UAAU,UAAU,OAAO,SAAS,aAAc,KAA4B,OAAQ,QAAQ,IAAK;EACnG,UAAU,eAAe,MAAM,CAAC,CAAC,IAAI,SAAS;CAChD;AACF;AAEA,SAAgB,iBAAiB,QAA0C;CACzE,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,QAA6B,CAAC;CACpC,MAAM,OAAO,SAA2B,SAA0C;EAChF,KAAK,MAAM,KAAK,SAAS;GACvB,IAAI,KAAK,IAAI,EAAE,EAAE,GAAG;GACpB,KAAK,IAAI,EAAE,EAAE;GACb,MAAM,KAAK,OAAO,GAAG,MAAM,OAAO,SAAS,CAAC;EAC9C;CACF;CACA,IAAI,OAAO,OAAO,OAAO,MAAM,QAAQ,GAAG,MAAM;CAChD,IAAI,OAAO,MAAM,SAAS,SAAS;CACnC,IAAI,OAAO,eAAe,cAAc;CACxC,OAAO;EACL;EACA,UAAU,OAAO,SAAS,KAAK,KAAK,CAAC,EAAA,CAAG,KAAK,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC;EAC3E,OAAO,OAAO,MAAM,OAAO,KAAK,CAAC,EAAA,CAAG,KAAK,OAAO,EAAE,GAAG,EAAE,EAAE;EACzD,cAAc,CAAC,GAAG,OAAO,YAAY;CACvC;AACF"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { e as DebugFeature, a as DebugConfig } from './types-BN9hbdMI.js';
|
|
2
2
|
import { DispatchTrace, TraceRing } from '@weasel-js/routing';
|
|
3
|
-
import { S as Scene } from './types-
|
|
3
|
+
import { S as Scene } from './types-BEdRIhNc.js';
|
|
4
4
|
import '@weasel-js/history';
|
|
5
|
-
import './types-
|
|
5
|
+
import './types-49uYJN3j.js';
|
|
6
6
|
import '@weasel-js/geom';
|
|
7
7
|
import '@weasel-js/quantity';
|
|
8
|
+
import '@weasel-js/paint';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Turn any value into plain data a panel can display. A node's `data` is the
|
|
@@ -134,7 +135,7 @@ type PageMessage = {
|
|
|
134
135
|
/** One child row of the scene tree. `nodeId` absent asks for the top level. */
|
|
135
136
|
interface DevtoolsNodeSummary {
|
|
136
137
|
id: string;
|
|
137
|
-
kind: '
|
|
138
|
+
kind: 'mark' | 'group';
|
|
138
139
|
layer: string;
|
|
139
140
|
childCount: number;
|
|
140
141
|
hidden: boolean;
|
package/dist/devtools.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { DEVTOOLS_ENVELOPE, DEVTOOLS_PROTOCOL, DevtoolsActionEntry, DevtoolsArea, DevtoolsBinding, DevtoolsDepEntry, DevtoolsEnvelope, DevtoolsHistoryOp, DevtoolsHistoryRecord, DevtoolsHistorySlice, DevtoolsNodeDetail, DevtoolsNodeSummary, DevtoolsOverlays, DevtoolsRegistry, DevtoolsRequest, DevtoolsResult, DevtoolsRoot, DevtoolsRootInfo, DevtoolsRootSource, DevtoolsRootState, DevtoolsSchedule, DevtoolsToolEntry, DevtoolsTraceSlice, DevtoolsTransport, PageMessage, PageTransport, PanelMessage, PanelTransport, SerializeLimits, SerializedValue, WeaselDevtoolsHook, createDevtoolsHook, createDevtoolsRoot, createInPageTransports, createWindowPageTransport, createWindowPanelTransport, installDevtoolsHook, isDevtoolsEnvelope, serialize } from './devtools-protocol.js';
|
|
2
2
|
import './types-BN9hbdMI.js';
|
|
3
3
|
import '@weasel-js/routing';
|
|
4
|
-
import './types-
|
|
4
|
+
import './types-BEdRIhNc.js';
|
|
5
5
|
import '@weasel-js/history';
|
|
6
|
-
import './types-
|
|
6
|
+
import './types-49uYJN3j.js';
|
|
7
7
|
import '@weasel-js/geom';
|
|
8
8
|
import '@weasel-js/quantity';
|
|
9
|
+
import '@weasel-js/paint';
|
|
@@ -40,14 +40,16 @@ function measurementsContribution(scene, ms) {
|
|
|
40
40
|
target: { kindOf: onMeasurement },
|
|
41
41
|
mods: MODS_ANY
|
|
42
42
|
},
|
|
43
|
-
actionId: MEASURE_ACTION_IDS.pick
|
|
43
|
+
actionId: MEASURE_ACTION_IDS.pick,
|
|
44
|
+
opts: { id: "weasel-measure.click" }
|
|
44
45
|
}, {
|
|
45
46
|
spec: {
|
|
46
47
|
kind: "drag",
|
|
47
48
|
target: { kindOf: onMeasurement },
|
|
48
49
|
mods: MODS_ANY
|
|
49
50
|
},
|
|
50
|
-
actionId: MEASURE_ACTION_IDS.drag
|
|
51
|
+
actionId: MEASURE_ACTION_IDS.drag,
|
|
52
|
+
opts: { id: "weasel-measure.drag" }
|
|
51
53
|
}]
|
|
52
54
|
};
|
|
53
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"measureContribution.js","names":[],"sources":["../../../src/features/measure/measureContribution.ts"],"sourcesContent":["import { hitPredicate } from '@weasel-js/gestures';\nimport type { Scene } from 'core/scene/types';\nimport type { SurfaceContribution } from 'canvas/surfaceContribution';\nimport type { Measurements } from './measurements';\nimport { measureCommands } from './measureCommands';\nimport { measureDragAction, measurePickAction } from './measureGestures';\nimport { MEASURE_AFFORDANCE_KIND, measurementsLayer } from './measureLayer';\nimport { MEASURE_ACTION_IDS } from './actionIds';\n\nconst onMeasurement = hitPredicate((hit) => (hit as { kind?: string } | null | undefined)?.kind === MEASURE_AFFORDANCE_KIND);\n\nconst MODS_ANY = { shift: 'optional', alt: 'optional', meta: 'optional', ctrl: 'optional' } as const;\n\n/**\n * A scene's measurements on a canvas, whatever tool is active: the layer\n * that shows the picked one and claims presses on measurements, a click on\n * one to pick it and a drag to edit it, and the commands — Move by, Rotate\n * by, Delete, Clear — a readout binds buttons to. Install it with\n * `<SceneCanvas ambient={[…]}>`; `useMeasureTool` adds the measuring itself.\n */\nexport function measurementsContribution(\n scene: Scene<unknown, string, unknown>,\n ms: Measurements,\n): SurfaceContribution {\n const layer = measurementsLayer(scene, ms);\n return {\n id: 'weasel-measure',\n eligibility: { claimed: true },\n attach: (api) => {\n const off = api.registerLayer(layer);\n api.requestRedraw();\n return off;\n },\n actions: [...measureCommands(ms), measurePickAction(ms), measureDragAction(ms)],\n bindings: [\n { spec: { kind: 'click', target: { kindOf: onMeasurement }, mods: MODS_ANY }, actionId: MEASURE_ACTION_IDS.pick },\n { spec: { kind: 'drag', target: { kindOf: onMeasurement }, mods: MODS_ANY }, actionId: MEASURE_ACTION_IDS.drag },\n ],\n };\n}\n"],"mappings":";;;;;;;AASA,IAAM,gBAAgB,cAAc,QAAS,KAA8C,SAAS,uBAAuB;AAE3H,IAAM,WAAW;CAAE,OAAO;CAAY,KAAK;CAAY,MAAM;CAAY,MAAM;AAAW;;;;;;;;AAS1F,SAAgB,yBACd,OACA,IACqB;CACrB,MAAM,QAAQ,kBAAkB,OAAO,EAAE;CACzC,OAAO;EACL,IAAI;EACJ,aAAa,EAAE,SAAS,KAAK;EAC7B,SAAS,QAAQ;GACf,MAAM,MAAM,IAAI,cAAc,KAAK;GACnC,IAAI,cAAc;GAClB,OAAO;EACT;EACA,SAAS;GAAC,GAAG,gBAAgB,EAAE;GAAG,kBAAkB,EAAE;GAAG,kBAAkB,EAAE;EAAC;EAC9E,UAAU,CACR;GAAE,MAAM;IAAE,MAAM;IAAS,QAAQ,EAAE,QAAQ,cAAc;IAAG,MAAM;GAAS;GAAG,UAAU,mBAAmB;
|
|
1
|
+
{"version":3,"file":"measureContribution.js","names":[],"sources":["../../../src/features/measure/measureContribution.ts"],"sourcesContent":["import { hitPredicate } from '@weasel-js/gestures';\nimport type { Scene } from 'core/scene/types';\nimport type { SurfaceContribution } from 'canvas/surfaceContribution';\nimport type { Measurements } from './measurements';\nimport { measureCommands } from './measureCommands';\nimport { measureDragAction, measurePickAction } from './measureGestures';\nimport { MEASURE_AFFORDANCE_KIND, measurementsLayer } from './measureLayer';\nimport { MEASURE_ACTION_IDS } from './actionIds';\n\nconst onMeasurement = hitPredicate((hit) => (hit as { kind?: string } | null | undefined)?.kind === MEASURE_AFFORDANCE_KIND);\n\nconst MODS_ANY = { shift: 'optional', alt: 'optional', meta: 'optional', ctrl: 'optional' } as const;\n\n/**\n * A scene's measurements on a canvas, whatever tool is active: the layer\n * that shows the picked one and claims presses on measurements, a click on\n * one to pick it and a drag to edit it, and the commands — Move by, Rotate\n * by, Delete, Clear — a readout binds buttons to. Install it with\n * `<SceneCanvas ambient={[…]}>`; `useMeasureTool` adds the measuring itself.\n */\nexport function measurementsContribution(\n scene: Scene<unknown, string, unknown>,\n ms: Measurements,\n): SurfaceContribution {\n const layer = measurementsLayer(scene, ms);\n return {\n id: 'weasel-measure',\n eligibility: { claimed: true },\n attach: (api) => {\n const off = api.registerLayer(layer);\n api.requestRedraw();\n return off;\n },\n actions: [...measureCommands(ms), measurePickAction(ms), measureDragAction(ms)],\n bindings: [\n { spec: { kind: 'click', target: { kindOf: onMeasurement }, mods: MODS_ANY }, actionId: MEASURE_ACTION_IDS.pick, opts: { id: 'weasel-measure.click' } },\n { spec: { kind: 'drag', target: { kindOf: onMeasurement }, mods: MODS_ANY }, actionId: MEASURE_ACTION_IDS.drag, opts: { id: 'weasel-measure.drag' } },\n ],\n };\n}\n"],"mappings":";;;;;;;AASA,IAAM,gBAAgB,cAAc,QAAS,KAA8C,SAAS,uBAAuB;AAE3H,IAAM,WAAW;CAAE,OAAO;CAAY,KAAK;CAAY,MAAM;CAAY,MAAM;AAAW;;;;;;;;AAS1F,SAAgB,yBACd,OACA,IACqB;CACrB,MAAM,QAAQ,kBAAkB,OAAO,EAAE;CACzC,OAAO;EACL,IAAI;EACJ,aAAa,EAAE,SAAS,KAAK;EAC7B,SAAS,QAAQ;GACf,MAAM,MAAM,IAAI,cAAc,KAAK;GACnC,IAAI,cAAc;GAClB,OAAO;EACT;EACA,SAAS;GAAC,GAAG,gBAAgB,EAAE;GAAG,kBAAkB,EAAE;GAAG,kBAAkB,EAAE;EAAC;EAC9E,UAAU,CACR;GAAE,MAAM;IAAE,MAAM;IAAS,QAAQ,EAAE,QAAQ,cAAc;IAAG,MAAM;GAAS;GAAG,UAAU,mBAAmB;GAAM,MAAM,EAAE,IAAI,uBAAuB;EAAE,GACtJ;GAAE,MAAM;IAAE,MAAM;IAAQ,QAAQ,EAAE,QAAQ,cAAc;IAAG,MAAM;GAAS;GAAG,UAAU,mBAAmB;GAAM,MAAM,EAAE,IAAI,sBAAsB;EAAE,CACtJ;CACF;AACF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nodesAsShown, shownLookup } from "../../core/scene/nodeAsShown.js";
|
|
1
2
|
import { measureEndsOf } from "./measurement.js";
|
|
2
3
|
import { nodeGates } from "../../core/scene/nodeGates.js";
|
|
3
4
|
import { measureIds } from "./measurements.js";
|
|
@@ -17,9 +18,10 @@ function distanceToSegment(p, a, b) {
|
|
|
17
18
|
*/
|
|
18
19
|
function measureAt(scene, ms, p, tolerance) {
|
|
19
20
|
const gates = nodeGates(scene);
|
|
21
|
+
const shown = shownLookup(scene);
|
|
20
22
|
const ids = measureIds(scene, ms).reverse().filter((id) => !gates.hidden(id) && !gates.locked(id));
|
|
21
23
|
for (const id of ids) {
|
|
22
|
-
const ends = measureEndsOf(
|
|
24
|
+
const ends = measureEndsOf(shown.get(id));
|
|
23
25
|
if (!ends) continue;
|
|
24
26
|
for (const part of ["end", "start"]) if (Math.hypot(p.x - ends[part].x, p.y - ends[part].y) <= tolerance) return {
|
|
25
27
|
id,
|
|
@@ -27,7 +29,7 @@ function measureAt(scene, ms, p, tolerance) {
|
|
|
27
29
|
};
|
|
28
30
|
}
|
|
29
31
|
for (const id of ids) {
|
|
30
|
-
const ends = measureEndsOf(
|
|
32
|
+
const ends = measureEndsOf(shown.get(id));
|
|
31
33
|
if (ends && distanceToSegment(p, ends.start, ends.end) <= tolerance) return {
|
|
32
34
|
id,
|
|
33
35
|
part: "line"
|
|
@@ -46,7 +48,7 @@ function measureEndSource(opts = {}) {
|
|
|
46
48
|
const gates = nodeGates(q.scene);
|
|
47
49
|
const skip = new Set(q.exclude);
|
|
48
50
|
const reach = q.reachWorld(q.reachPx);
|
|
49
|
-
for (const node of q.scene.renderOrderNodes()) {
|
|
51
|
+
for (const node of nodesAsShown(q.scene.overrides, q.scene.renderOrderNodes())) {
|
|
50
52
|
const ends = measureEndsOf(node);
|
|
51
53
|
if (!ends || skip.has(node.id) || gates.hidden(node.id)) continue;
|
|
52
54
|
for (const end of [ends.start, ends.end]) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"measureHit.js","names":[],"sources":["../../../src/features/measure/measureHit.ts"],"sourcesContent":["import type { NodeId, Scene } from 'core/scene/types';\nimport { measureEndsOf, type MeasureEnd, type MeasurePoint } from './measurement';\nimport { measureIds, type Measurements } from './measurements';\nimport { nodeGates } from 'core/scene/nodeGates';\nimport type { SnapSource } from 'features/snap/types';\n\n/** Which part of which measurement lies under a point. */\nexport interface MeasureHit {\n id: NodeId;\n part: MeasureEnd | 'line';\n}\n\n\nfunction distanceToSegment(p: MeasurePoint, a: MeasurePoint, b: MeasurePoint): number {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const len2 = dx * dx + dy * dy;\n const t = len2 === 0 ? 0 : Math.max(0, Math.min(1, ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2));\n return Math.hypot(p.x - (a.x + t * dx), p.y - (a.y + t * dy));\n}\n\n/**\n * The measurement under `p`, newest first: an end within `tolerance` world\n * units of it, else a line within the same distance. A hidden or locked\n * measurement (`nodeGates`) is passed over.\n */\nexport function measureAt(\n scene: Pick<Scene<unknown, string, unknown>, 'renderOrderNodes' | 'get' | 'layers'>,\n ms: Pick<Measurements, 'layer'>,\n p: MeasurePoint,\n tolerance: number,\n): MeasureHit | null {\n const gates = nodeGates(scene);\n const ids = measureIds(scene, ms).reverse().filter((id) => !gates.hidden(id) && !gates.locked(id));\n for (const id of ids) {\n const ends = measureEndsOf(
|
|
1
|
+
{"version":3,"file":"measureHit.js","names":[],"sources":["../../../src/features/measure/measureHit.ts"],"sourcesContent":["import type { NodeId, Scene } from 'core/scene/types';\nimport { measureEndsOf, type MeasureEnd, type MeasurePoint } from './measurement';\nimport { measureIds, type Measurements } from './measurements';\nimport { nodesAsShown, shownLookup } from 'core/scene/nodeAsShown';\nimport { nodeGates } from 'core/scene/nodeGates';\nimport type { SnapSource } from 'features/snap/types';\n\n/** Which part of which measurement lies under a point. */\nexport interface MeasureHit {\n id: NodeId;\n part: MeasureEnd | 'line';\n}\n\n\nfunction distanceToSegment(p: MeasurePoint, a: MeasurePoint, b: MeasurePoint): number {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const len2 = dx * dx + dy * dy;\n const t = len2 === 0 ? 0 : Math.max(0, Math.min(1, ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2));\n return Math.hypot(p.x - (a.x + t * dx), p.y - (a.y + t * dy));\n}\n\n/**\n * The measurement under `p`, newest first: an end within `tolerance` world\n * units of it, else a line within the same distance. A hidden or locked\n * measurement (`nodeGates`) is passed over.\n */\nexport function measureAt(\n scene: Pick<Scene<unknown, string, unknown>, 'renderOrderNodes' | 'get' | 'layers' | 'overrides'>,\n ms: Pick<Measurements, 'layer'>,\n p: MeasurePoint,\n tolerance: number,\n): MeasureHit | null {\n const gates = nodeGates(scene);\n // Hit where the ends are shown: a gesture moving one publishes it as a data override.\n const shown = shownLookup(scene);\n const ids = measureIds(scene, ms).reverse().filter((id) => !gates.hidden(id) && !gates.locked(id));\n for (const id of ids) {\n const ends = measureEndsOf(shown.get(id));\n if (!ends) continue;\n for (const part of ['end', 'start'] as const) {\n if (Math.hypot(p.x - ends[part].x, p.y - ends[part].y) <= tolerance) return { id, part };\n }\n }\n for (const id of ids) {\n const ends = measureEndsOf(shown.get(id));\n if (ends && distanceToSegment(p, ends.start, ends.end) <= tolerance) return { id, part: 'line' };\n }\n return null;\n}\n\n/** Options for `measureEndSource`. */\nexport interface MeasureEndSourceOptions {\n /** Overrides the canvas's reach for measurement ends, in screen px. */\n reachPx?: number;\n}\n\n/** The ends of every shown measurement as snap targets for a pointer probe. */\nexport function measureEndSource(opts: MeasureEndSourceOptions = {}): SnapSource {\n return {\n id: 'measure-ends',\n roles: ['pointer'],\n ...(opts.reachPx !== undefined ? { reachPx: opts.reachPx } : {}),\n *collect(q) {\n if (!q.scene) return;\n const gates = nodeGates(q.scene);\n const skip = new Set(q.exclude);\n const reach = q.reachWorld(q.reachPx);\n for (const node of nodesAsShown(q.scene.overrides, q.scene.renderOrderNodes())) {\n const ends = measureEndsOf(node);\n if (!ends || skip.has(node.id) || gates.hidden(node.id)) continue;\n for (const end of [ends.start, ends.end]) {\n const at = { x: end.x, y: end.y };\n for (const p of q.probes) {\n if (Math.hypot(at.x - p.at.x, at.y - p.at.y) > reach) continue;\n yield { probe: p.id, locus: { at, dirs: [] }, mark: { kind: 'point', at, glyph: 'center' } };\n }\n }\n }\n },\n };\n}\n"],"mappings":";;;;;;AAcA,SAAS,kBAAkB,GAAiB,GAAiB,GAAyB;CACpF,MAAM,KAAK,EAAE,IAAI,EAAE;CACnB,MAAM,KAAK,EAAE,IAAI,EAAE;CACnB,MAAM,OAAO,KAAK,KAAK,KAAK;CAC5B,MAAM,IAAI,SAAS,IAAI,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,MAAM,IAAI,CAAC;CAChG,OAAO,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,IAAI,KAAK,EAAE,KAAK,EAAE,IAAI,IAAI,GAAG;AAC9D;;;;;;AAOA,SAAgB,UACd,OACA,IACA,GACA,WACmB;CACnB,MAAM,QAAQ,UAAU,KAAK;CAE7B,MAAM,QAAQ,YAAY,KAAK;CAC/B,MAAM,MAAM,WAAW,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,OAAO,CAAC,MAAM,OAAO,EAAE,KAAK,CAAC,MAAM,OAAO,EAAE,CAAC;CACjG,KAAK,MAAM,MAAM,KAAK;EACpB,MAAM,OAAO,cAAc,MAAM,IAAI,EAAE,CAAC;EACxC,IAAI,CAAC,MAAM;EACX,KAAK,MAAM,QAAQ,CAAC,OAAO,OAAO,GAChC,IAAI,KAAK,MAAM,EAAE,IAAI,KAAK,KAAK,CAAC,GAAG,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,KAAK,WAAW,OAAO;GAAE;GAAI;EAAK;CAE3F;CACA,KAAK,MAAM,MAAM,KAAK;EACpB,MAAM,OAAO,cAAc,MAAM,IAAI,EAAE,CAAC;EACxC,IAAI,QAAQ,kBAAkB,GAAG,KAAK,OAAO,KAAK,GAAG,KAAK,WAAW,OAAO;GAAE;GAAI,MAAM;EAAO;CACjG;CACA,OAAO;AACT;;AASA,SAAgB,iBAAiB,OAAgC,CAAC,GAAe;CAC/E,OAAO;EACL,IAAI;EACJ,OAAO,CAAC,SAAS;EACjB,GAAI,KAAK,YAAY,SAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;EAC9D,CAAC,QAAQ,GAAG;GACV,IAAI,CAAC,EAAE,OAAO;GACd,MAAM,QAAQ,UAAU,EAAE,KAAK;GAC/B,MAAM,OAAO,IAAI,IAAI,EAAE,OAAO;GAC9B,MAAM,QAAQ,EAAE,WAAW,EAAE,OAAO;GACpC,KAAK,MAAM,QAAQ,aAAa,EAAE,MAAM,WAAW,EAAE,MAAM,iBAAiB,CAAC,GAAG;IAC9E,MAAM,OAAO,cAAc,IAAI;IAC/B,IAAI,CAAC,QAAQ,KAAK,IAAI,KAAK,EAAE,KAAK,MAAM,OAAO,KAAK,EAAE,GAAG;IACzD,KAAK,MAAM,OAAO,CAAC,KAAK,OAAO,KAAK,GAAG,GAAG;KACxC,MAAM,KAAK;MAAE,GAAG,IAAI;MAAG,GAAG,IAAI;KAAE;KAChC,KAAK,MAAM,KAAK,EAAE,QAAQ;MACxB,IAAI,KAAK,MAAM,GAAG,IAAI,EAAE,GAAG,GAAG,GAAG,IAAI,EAAE,GAAG,CAAC,IAAI,OAAO;MACtD,MAAM;OAAE,OAAO,EAAE;OAAI,OAAO;QAAE;QAAI,MAAM,CAAC;OAAE;OAAG,MAAM;QAAE,MAAM;QAAS;QAAI,OAAO;OAAS;MAAE;KAC7F;IACF;GACF;EACF;CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"measurement.js","names":[],"sources":["../../../src/features/measure/measurement.ts"],"sourcesContent":["import type { Node, NodeId, RectPose } from 'core/scene/types';\n\n/** A world-space point. */\nexport interface MeasurePoint { x: number; y: number }\n\n/**\n * The offset from `start` to `end`, in world units. `dx` and `dy` are on the\n * world's own axes, where y grows downward; `angle` reads like a protractor\n * instead, counterclockwise-positive on screen, so a line rising up and to\n * the right at 30° reads +30°. The canvas's own rotations are\n * clockwise-positive: a rotate that follows the line turns by `-angle`.\n */\nexport interface Measurement {\n readonly start: MeasurePoint;\n readonly end: MeasurePoint;\n readonly dx: number;\n readonly dy: number;\n readonly distance: number;\n /** `atan2(-dy, dx)`, in `(-π, π]`. Zero for a zero-length measurement. */\n readonly angle: number;\n}\n\n/** Measure from `start` to `end`. */\nexport function measureBetween(start: MeasurePoint, end: MeasurePoint): Measurement {\n const dx = end.x - start.x;\n const dy = end.y - start.y;\n return {\n start: { x: start.x, y: start.y },\n end: { x: end.x, y: end.y },\n dx,\n dy,\n distance: Math.hypot(dx, dy),\n // `|| 0` drops the sign of a negated zero, which would read a leftward line as -π.\n angle: dx === 0 && dy === 0 ? 0 : Math.atan2(-dy || 0, dx),\n };\n}\n\n/** What a measurement node keeps in `data`: its two ends, in world units. A\n * `label` beside it names the node in a layer list. */\nexport interface MeasureData {\n measure: { start: MeasurePoint; end: MeasurePoint };\n label?: string;\n}\n\n/** Which end of a measurement. */\nexport type MeasureEnd = 'start' | 'end';\n\n\n/** The ends `node` measures between, or null when it is not a measurement. */\nexport function measureEndsOf(node: Pick<Node<unknown, string, unknown>, 'data'> | undefined): MeasureData['measure'] | null {\n const m = (node?.data as Partial<MeasureData> | null | undefined)?.measure;\n if (!m || typeof m !== 'object' || !m.start || !m.end) return null;\n return m;\n}\n\n/** The measurement `node` holds, or null when it is not one. */\nexport function measurementOf(node: Pick<Node<unknown, string, unknown>, 'data'> | undefined): Measurement | null {\n const ends = measureEndsOf(node);\n return ends ? measureBetween(ends.start, ends.end) : null;\n}\n\n/** The box a measurement's pose holds: its two ends' bounds, which is what\n * culling, area queries, and fitting the view read. */\nexport function measurePose(start: MeasurePoint, end: MeasurePoint): RectPose {\n return {\n x: Math.min(start.x, end.x),\n y: Math.min(start.y, end.y),\n width: Math.abs(end.x - start.x),\n height: Math.abs(end.y - start.y),\n };\n}\n\n/** A measurement node on `layer`, ready to insert. */\nexport function measureNode(id: NodeId, layer: string, start: MeasurePoint, end: MeasurePoint): Node<unknown, string, unknown> {\n const data: MeasureData = { measure: { start: { ...start }, end: { ...end } } };\n return { id, kind: '
|
|
1
|
+
{"version":3,"file":"measurement.js","names":[],"sources":["../../../src/features/measure/measurement.ts"],"sourcesContent":["import type { Node, NodeId, RectPose } from 'core/scene/types';\n\n/** A world-space point. */\nexport interface MeasurePoint { x: number; y: number }\n\n/**\n * The offset from `start` to `end`, in world units. `dx` and `dy` are on the\n * world's own axes, where y grows downward; `angle` reads like a protractor\n * instead, counterclockwise-positive on screen, so a line rising up and to\n * the right at 30° reads +30°. The canvas's own rotations are\n * clockwise-positive: a rotate that follows the line turns by `-angle`.\n */\nexport interface Measurement {\n readonly start: MeasurePoint;\n readonly end: MeasurePoint;\n readonly dx: number;\n readonly dy: number;\n readonly distance: number;\n /** `atan2(-dy, dx)`, in `(-π, π]`. Zero for a zero-length measurement. */\n readonly angle: number;\n}\n\n/** Measure from `start` to `end`. */\nexport function measureBetween(start: MeasurePoint, end: MeasurePoint): Measurement {\n const dx = end.x - start.x;\n const dy = end.y - start.y;\n return {\n start: { x: start.x, y: start.y },\n end: { x: end.x, y: end.y },\n dx,\n dy,\n distance: Math.hypot(dx, dy),\n // `|| 0` drops the sign of a negated zero, which would read a leftward line as -π.\n angle: dx === 0 && dy === 0 ? 0 : Math.atan2(-dy || 0, dx),\n };\n}\n\n/** What a measurement node keeps in `data`: its two ends, in world units. A\n * `label` beside it names the node in a layer list. */\nexport interface MeasureData {\n measure: { start: MeasurePoint; end: MeasurePoint };\n label?: string;\n}\n\n/** Which end of a measurement. */\nexport type MeasureEnd = 'start' | 'end';\n\n\n/** The ends `node` measures between, or null when it is not a measurement. */\nexport function measureEndsOf(node: Pick<Node<unknown, string, unknown>, 'data'> | undefined): MeasureData['measure'] | null {\n const m = (node?.data as Partial<MeasureData> | null | undefined)?.measure;\n if (!m || typeof m !== 'object' || !m.start || !m.end) return null;\n return m;\n}\n\n/** The measurement `node` holds, or null when it is not one. */\nexport function measurementOf(node: Pick<Node<unknown, string, unknown>, 'data'> | undefined): Measurement | null {\n const ends = measureEndsOf(node);\n return ends ? measureBetween(ends.start, ends.end) : null;\n}\n\n/** The box a measurement's pose holds: its two ends' bounds, which is what\n * culling, area queries, and fitting the view read. */\nexport function measurePose(start: MeasurePoint, end: MeasurePoint): RectPose {\n return {\n x: Math.min(start.x, end.x),\n y: Math.min(start.y, end.y),\n width: Math.abs(end.x - start.x),\n height: Math.abs(end.y - start.y),\n };\n}\n\n/** A measurement node on `layer`, ready to insert. */\nexport function measureNode(id: NodeId, layer: string, start: MeasurePoint, end: MeasurePoint): Node<unknown, string, unknown> {\n const data: MeasureData = { measure: { start: { ...start }, end: { ...end } } };\n return { id, kind: 'mark', layer, parent: null, pose: measurePose(start, end), data };\n}\n\n/** `node`'s data and pose with its `which` end moved to `to`. */\nexport function withMeasureEnd(\n node: Node<unknown, string, unknown>,\n which: MeasureEnd,\n to: MeasurePoint,\n): { data: MeasureData; pose: RectPose } | null {\n const ends = measureEndsOf(node);\n if (!ends) return null;\n const next = { ...ends, [which]: { x: to.x, y: to.y } };\n const data: MeasureData = { ...(node.data as MeasureData), measure: next };\n return { data, pose: measurePose(next.start, next.end) };\n}\n"],"mappings":";;AAuBA,SAAgB,eAAe,OAAqB,KAAgC;CAClF,MAAM,KAAK,IAAI,IAAI,MAAM;CACzB,MAAM,KAAK,IAAI,IAAI,MAAM;CACzB,OAAO;EACL,OAAO;GAAE,GAAG,MAAM;GAAG,GAAG,MAAM;EAAE;EAChC,KAAK;GAAE,GAAG,IAAI;GAAG,GAAG,IAAI;EAAE;EAC1B;EACA;EACA,UAAU,KAAK,MAAM,IAAI,EAAE;EAE3B,OAAO,OAAO,KAAK,OAAO,IAAI,IAAI,KAAK,MAAM,CAAC,MAAM,GAAG,EAAE;CAC3D;AACF;;AAcA,SAAgB,cAAc,MAA+F;CAC3H,MAAM,KAAK,MAAM,KAAA,EAAkD;CACnE,IAAI,CAAC,KAAK,OAAO,MAAM,YAAY,CAAC,EAAE,SAAS,CAAC,EAAE,KAAK,OAAO;CAC9D,OAAO;AACT;;AAGA,SAAgB,cAAc,MAAoF;CAChH,MAAM,OAAO,cAAc,IAAI;CAC/B,OAAO,OAAO,eAAe,KAAK,OAAO,KAAK,GAAG,IAAI;AACvD;;;AAIA,SAAgB,YAAY,OAAqB,KAA6B;CAC5E,OAAO;EACL,GAAG,KAAK,IAAI,MAAM,GAAG,IAAI,CAAC;EAC1B,GAAG,KAAK,IAAI,MAAM,GAAG,IAAI,CAAC;EAC1B,OAAO,KAAK,IAAI,IAAI,IAAI,MAAM,CAAC;EAC/B,QAAQ,KAAK,IAAI,IAAI,IAAI,MAAM,CAAC;CAClC;AACF;;AAGA,SAAgB,YAAY,IAAY,OAAe,OAAqB,KAAmD;CAC7H,MAAM,OAAoB,EAAE,SAAS;EAAE,OAAO,EAAE,GAAG,MAAM;EAAG,KAAK,EAAE,GAAG,IAAI;CAAE,EAAE;CAC9E,OAAO;EAAE;EAAI,MAAM;EAAQ;EAAO,QAAQ;EAAM,MAAM,YAAY,OAAO,GAAG;EAAG;CAAK;AACtF;;AAGA,SAAgB,eACd,MACA,OACA,IAC8C;CAC9C,MAAM,OAAO,cAAc,IAAI;CAC/B,IAAI,CAAC,MAAM,OAAO;CAClB,MAAM,OAAO;EAAE,GAAG;GAAO,QAAQ;GAAE,GAAG,GAAG;GAAG,GAAG,GAAG;EAAE;CAAE;CAEtD,OAAO;EAAE;GADmB,GAAI,KAAK;GAAsB,SAAS;EAC3D;EAAM,MAAM,YAAY,KAAK,OAAO,KAAK,GAAG;CAAE;AACzD"}
|
|
@@ -4,10 +4,9 @@ import { worldToScreen } from "../../core/viewport/viewTransform.js";
|
|
|
4
4
|
//#region src/features/modes/modeLayers.ts
|
|
5
5
|
var DEFAULT_INTENSITY = .12;
|
|
6
6
|
/**
|
|
7
|
-
* A screen-space layer painting the active mode's `WorkspaceVisual
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* mode switch repaints it.
|
|
7
|
+
* A screen-space layer painting the active mode's `WorkspaceVisual`, or the `fallback`'s in a
|
|
8
|
+
* mode without one: a wash at `intensity`, else that visual's own, bottom-up or top-down when it
|
|
9
|
+
* names a gradient.
|
|
11
10
|
*/
|
|
12
11
|
function workspaceTintLayer(opts) {
|
|
13
12
|
const { registry } = opts;
|
|
@@ -15,11 +14,19 @@ function workspaceTintLayer(opts) {
|
|
|
15
14
|
id: opts.id ?? "mode-tint",
|
|
16
15
|
label: opts.label ?? "Mode tint",
|
|
17
16
|
space: "screen",
|
|
18
|
-
subscribe:
|
|
17
|
+
subscribe: (repaint) => {
|
|
18
|
+
const offMode = registry.subscribe(repaint);
|
|
19
|
+
const offFallback = opts.fallback?.subscribe(repaint);
|
|
20
|
+
return () => {
|
|
21
|
+
offMode();
|
|
22
|
+
offFallback?.();
|
|
23
|
+
};
|
|
24
|
+
},
|
|
19
25
|
draw: (_data, view, dims) => {
|
|
20
|
-
const
|
|
26
|
+
const own = registry.current().workspace;
|
|
27
|
+
const ws = own?.tint && own.tint !== "transparent" ? own : opts.fallback?.visual() ?? void 0;
|
|
21
28
|
const tint = ws?.tint;
|
|
22
|
-
if (!tint || tint === "transparent") return [];
|
|
29
|
+
if (!ws || !tint || tint === "transparent") return [];
|
|
23
30
|
const opacity = opts.intensity ?? ws.intensity ?? DEFAULT_INTENSITY;
|
|
24
31
|
const { width: W, height: H } = dims;
|
|
25
32
|
const strip = (x, y, width, height, from, to) => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modeLayers.js","names":[],"sources":["../../../src/features/modes/modeLayers.ts"],"sourcesContent":["import type { Rect } from '@weasel-js/geom';\nimport type { ModeDecorations, ModeRegistry } from '@weasel-js/modes';\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport type { RenderLayer } from 'core/layers/render';\nimport { viewToTransform } from 'core/viewport/view';\nimport { worldToScreen } from 'core/viewport/viewTransform';\n\n/** Options for {@link workspaceTintLayer}. */\nexport interface WorkspaceTintLayerOptions {\n registry: ModeRegistry;\n /** The page, in world coordinates. When given, the tint covers only the\n * workspace around it, each strip fading toward the page edge if the mode\n * names a gradient. Without it the tint covers the whole canvas. */\n page?: () => Rect | null;\n /** Opacity for every mode's tint, in place of its `workspace.intensity`. */\n intensity?: number;\n id?: string;\n label?: string;\n}\n\nconst DEFAULT_INTENSITY = 0.12;\n\n/**\n * A screen-space layer painting the active mode's `WorkspaceVisual
|
|
1
|
+
{"version":3,"file":"modeLayers.js","names":[],"sources":["../../../src/features/modes/modeLayers.ts"],"sourcesContent":["import type { Rect } from '@weasel-js/geom';\nimport type { ModeDecorations, ModeRegistry, WorkspaceVisual } from '@weasel-js/modes';\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport type { RenderLayer } from 'core/layers/render';\nimport { viewToTransform } from 'core/viewport/view';\nimport { worldToScreen } from 'core/viewport/viewTransform';\n\n/** Options for {@link workspaceTintLayer}. */\nexport interface WorkspaceTintLayerOptions {\n registry: ModeRegistry;\n /** The page, in world coordinates. When given, the tint covers only the\n * workspace around it, each strip fading toward the page edge if the mode\n * names a gradient. Without it the tint covers the whole canvas. */\n page?: () => Rect | null;\n /** Opacity for every mode's tint, in place of its `workspace.intensity`. */\n intensity?: number;\n /** The tint shown in a mode with none of its own, and what announces a change to it. */\n fallback?: { visual: () => WorkspaceVisual | null; subscribe: (fn: () => void) => () => void };\n id?: string;\n label?: string;\n}\n\nconst DEFAULT_INTENSITY = 0.12;\n\n/**\n * A screen-space layer painting the active mode's `WorkspaceVisual`, or the `fallback`'s in a\n * mode without one: a wash at `intensity`, else that visual's own, bottom-up or top-down when it\n * names a gradient.\n */\nexport function workspaceTintLayer(opts: WorkspaceTintLayerOptions): RenderLayer<unknown> {\n const { registry } = opts;\n return {\n id: opts.id ?? 'mode-tint',\n label: opts.label ?? 'Mode tint',\n space: 'screen',\n subscribe: (repaint) => {\n const offMode = registry.subscribe(repaint);\n const offFallback = opts.fallback?.subscribe(repaint);\n return () => { offMode(); offFallback?.(); };\n },\n draw: (_data, view, dims) => {\n const own = registry.current().workspace;\n const ws = own?.tint && own.tint !== 'transparent' ? own : opts.fallback?.visual() ?? undefined;\n const tint = ws?.tint;\n if (!ws || !tint || tint === 'transparent') return [];\n const opacity = opts.intensity ?? ws.intensity ?? DEFAULT_INTENSITY;\n const { width: W, height: H } = dims;\n\n const strip = (\n x: number, y: number, width: number, height: number,\n from: { x: number; y: number }, to: { x: number; y: number },\n ): DrawCommand => ({\n kind: 'path',\n path: { kind: 'rect', x, y, width, height },\n fill: { paint: ws.gradient\n ? { kind: 'linear-gradient', from, to, stops: [{ offset: 0, color: tint }, { offset: 1, color: 'transparent' }], opacity }\n : { kind: 'solid', color: tint, opacity } },\n });\n\n const whole = (): DrawCommand[] => [\n ws.gradient === 'top-down'\n ? strip(0, 0, W, H, { x: 0, y: 0 }, { x: 0, y: H })\n : strip(0, 0, W, H, { x: 0, y: H }, { x: 0, y: 0 }),\n ];\n\n const page = opts.page?.();\n if (!page) return whole();\n\n const t = viewToTransform(view);\n const [sx0, sy0] = worldToScreen(page.x, page.y, t);\n const [sx1, sy1] = worldToScreen(page.x + page.width, page.y + page.height, t);\n const pl = Math.max(0, Math.min(sx0, sx1));\n const pt = Math.max(0, Math.min(sy0, sy1));\n const pr = Math.min(W, Math.max(sx0, sx1));\n const pb = Math.min(H, Math.max(sy0, sy1));\n if (pr <= pl || pb <= pt) {\n return [{ kind: 'path', path: { kind: 'rect', x: 0, y: 0, width: W, height: H }, fill: { paint: { kind: 'solid', color: tint, opacity } } }];\n }\n\n const cmds: DrawCommand[] = [];\n const push = (\n x: number, y: number, w: number, h: number,\n from: { x: number; y: number }, to: { x: number; y: number },\n ): void => { if (w > 0 && h > 0) cmds.push(strip(x, y, w, h, from, to)); };\n push(0, 0, W, pt, { x: 0, y: 0 }, { x: 0, y: pt });\n push(0, pb, W, H - pb, { x: 0, y: H }, { x: 0, y: pb });\n push(0, pt, pl, pb - pt, { x: 0, y: 0 }, { x: pl, y: 0 });\n push(pr, pt, W - pr, pb - pt, { x: W, y: 0 }, { x: pr, y: 0 });\n return cmds;\n },\n };\n}\n\n/** A world-space layer drawing a `ModeDecorations`' active painter. It\n * subscribes to the decorations, so a mode switch or a new painter repaints\n * it. */\nexport function modeDecorationLayer(\n decorations: ModeDecorations,\n opts: { id?: string; label?: string } = {},\n): RenderLayer<unknown> {\n return {\n id: opts.id ?? 'mode-decorations',\n label: opts.label ?? 'Mode decorations',\n subscribe: decorations.subscribe,\n draw: () => decorations.paint() as DrawCommand[],\n };\n}\n"],"mappings":";;;;AAsBA,IAAM,oBAAoB;;;;;;AAO1B,SAAgB,mBAAmB,MAAuD;CACxF,MAAM,EAAE,aAAa;CACrB,OAAO;EACL,IAAI,KAAK,MAAM;EACf,OAAO,KAAK,SAAS;EACrB,OAAO;EACP,YAAY,YAAY;GACtB,MAAM,UAAU,SAAS,UAAU,OAAO;GAC1C,MAAM,cAAc,KAAK,UAAU,UAAU,OAAO;GACpD,aAAa;IAAE,QAAQ;IAAG,cAAc;GAAG;EAC7C;EACA,OAAO,OAAO,MAAM,SAAS;GAC3B,MAAM,MAAM,SAAS,QAAQ,CAAC,CAAC;GAC/B,MAAM,KAAK,KAAK,QAAQ,IAAI,SAAS,gBAAgB,MAAM,KAAK,UAAU,OAAO,KAAK;GACtF,MAAM,OAAO,IAAI;GACjB,IAAI,CAAC,MAAM,CAAC,QAAQ,SAAS,eAAe,OAAO,CAAC;GACpD,MAAM,UAAU,KAAK,aAAa,GAAG,aAAa;GAClD,MAAM,EAAE,OAAO,GAAG,QAAQ,MAAM;GAEhC,MAAM,SACJ,GAAW,GAAW,OAAe,QACrC,MAAgC,QACf;IACjB,MAAM;IACN,MAAM;KAAE,MAAM;KAAQ;KAAG;KAAG;KAAO;IAAO;IAC1C,MAAM,EAAE,OAAO,GAAG,WACd;KAAE,MAAM;KAAmB;KAAM;KAAI,OAAO,CAAC;MAAE,QAAQ;MAAG,OAAO;KAAK,GAAG;MAAE,QAAQ;MAAG,OAAO;KAAc,CAAC;KAAG;IAAQ,IACvH;KAAE,MAAM;KAAS,OAAO;KAAM;IAAQ,EAAE;GAC9C;GAEA,MAAM,cAA6B,CACjC,GAAG,aAAa,aACZ,MAAM,GAAG,GAAG,GAAG,GAAG;IAAE,GAAG;IAAG,GAAG;GAAE,GAAG;IAAE,GAAG;IAAG,GAAG;GAAE,CAAC,IAChD,MAAM,GAAG,GAAG,GAAG,GAAG;IAAE,GAAG;IAAG,GAAG;GAAE,GAAG;IAAE,GAAG;IAAG,GAAG;GAAE,CAAC,CACtD;GAEA,MAAM,OAAO,KAAK,OAAO;GACzB,IAAI,CAAC,MAAM,OAAO,MAAM;GAExB,MAAM,IAAI,gBAAgB,IAAI;GAC9B,MAAM,CAAC,KAAK,OAAO,cAAc,KAAK,GAAG,KAAK,GAAG,CAAC;GAClD,MAAM,CAAC,KAAK,OAAO,cAAc,KAAK,IAAI,KAAK,OAAO,KAAK,IAAI,KAAK,QAAQ,CAAC;GAC7E,MAAM,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC;GACzC,MAAM,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC;GACzC,MAAM,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC;GACzC,MAAM,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC;GACzC,IAAI,MAAM,MAAM,MAAM,IACpB,OAAO,CAAC;IAAE,MAAM;IAAQ,MAAM;KAAE,MAAM;KAAQ,GAAG;KAAG,GAAG;KAAG,OAAO;KAAG,QAAQ;IAAE;IAAG,MAAM,EAAE,OAAO;KAAE,MAAM;KAAS,OAAO;KAAM;IAAQ,EAAE;GAAE,CAAC;GAG7I,MAAM,OAAsB,CAAC;GAC7B,MAAM,QACJ,GAAW,GAAW,GAAW,GACjC,MAAgC,OACvB;IAAE,IAAI,IAAI,KAAK,IAAI,GAAG,KAAK,KAAK,MAAM,GAAG,GAAG,GAAG,GAAG,MAAM,EAAE,CAAC;GAAG;GACzE,KAAK,GAAG,GAAG,GAAG,IAAI;IAAE,GAAG;IAAG,GAAG;GAAE,GAAG;IAAE,GAAG;IAAG,GAAG;GAAG,CAAC;GACjD,KAAK,GAAG,IAAI,GAAG,IAAI,IAAI;IAAE,GAAG;IAAG,GAAG;GAAE,GAAG;IAAE,GAAG;IAAG,GAAG;GAAG,CAAC;GACtD,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI;IAAE,GAAG;IAAG,GAAG;GAAE,GAAG;IAAE,GAAG;IAAI,GAAG;GAAE,CAAC;GACxD,KAAK,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI;IAAE,GAAG;IAAG,GAAG;GAAE,GAAG;IAAE,GAAG;IAAI,GAAG;GAAE,CAAC;GAC7D,OAAO;EACT;CACF;AACF;;;;AAKA,SAAgB,oBACd,aACA,OAAwC,CAAC,GACnB;CACtB,OAAO;EACL,IAAI,KAAK,MAAM;EACf,OAAO,KAAK,SAAS;EACrB,WAAW,YAAY;EACvB,YAAY,YAAY,MAAM;CAChC;AACF"}
|
|
@@ -10,9 +10,9 @@ import { modeLabel } from "@weasel-js/modes";
|
|
|
10
10
|
*
|
|
11
11
|
* The target is the node the dispatcher classified the double-click on (the `hitAt` dep's
|
|
12
12
|
* `doubleClick`, else its hit), the one the binding's `kind:` target matched: a double-click on
|
|
13
|
-
* a grouped member names its outermost group inside
|
|
14
|
-
* included, so a double-click on another node
|
|
15
|
-
* decide what a switch from the current mode means.
|
|
13
|
+
* a grouped member names its outermost group inside the entered group (`<SceneCanvas enteredGroup>`).
|
|
14
|
+
* The action is live in every mode, the target mode included, so a double-click on another node
|
|
15
|
+
* moves a mode onto it; `canEnter` and `enter` decide what a switch from the current mode means.
|
|
16
16
|
*
|
|
17
17
|
* The bindings ride the ambient tier: a tool that claims the double-click itself, the pen
|
|
18
18
|
* finishing a stroke, keeps it.
|
|
@@ -38,12 +38,16 @@ function triggerAction(mode, targets, enter, canEnter) {
|
|
|
38
38
|
if (id === void 0) return null;
|
|
39
39
|
return canEnter?.(mode.id, id) === false ? null : id;
|
|
40
40
|
};
|
|
41
|
+
const id = `mode.${mode.id}.trigger`;
|
|
41
42
|
return {
|
|
42
|
-
id
|
|
43
|
+
id,
|
|
43
44
|
label: `Enter ${modeLabel(mode)}`,
|
|
44
45
|
defaultBinding: targets.map((kind) => ({
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
spec: {
|
|
47
|
+
kind: "doubleClick",
|
|
48
|
+
target: `kind:${kind}`
|
|
49
|
+
},
|
|
50
|
+
opts: { id: `${id}.doubleClick.${kind}` }
|
|
47
51
|
})),
|
|
48
52
|
requires: ["hitAt"],
|
|
49
53
|
enabled: (deps, at) => targetAt(deps, at) !== null ? true : ActionDisabledReason.NotApplicable,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modeTriggers.js","names":[],"sources":["../../../src/features/modes/modeTriggers.ts"],"sourcesContent":["import { modeLabel, type ModeDefinition, type ModeRegistry } from '@weasel-js/modes';\nimport { ActionDisabledReason, type Action, type ActionDeps, type Contribution } from '@weasel-js/routing';\n\n/** What a mode's double-click trigger does. */\nexport interface ModeTriggerHandlers {\n /** Enter mode `id` on the node `targetId`. Without it nothing is bound. */\n enter?: (id: string, targetId: string) => void;\n /**\n * Whether mode `id` can be entered on `targetId` now. Where it says no the double-click falls\n * through to the next binding on it, so a canvas action that already enters the mode on some\n * of those nodes keeps them: `enterPathEdit` on a path with anchors, say. Default yes.\n */\n canEnter?: (id: string, targetId: string) => boolean;\n}\n\n/**\n * The registry's double-click entries as an always-on contribution: for each mode whose\n * `entry.trigger` is `'double-click-target'`, one action bound to a double-click on each routing\n * kind its `entry.targets` names, entering the mode on the node double-clicked. Install it with\n * `<SceneCanvas ambient>`, beside `modeShortcuts`.\n *\n * The target is the node the dispatcher classified the double-click on (the `hitAt` dep's\n * `doubleClick`, else its hit), the one the binding's `kind:` target matched: a double-click on\n * a grouped member names its outermost group inside `<SceneCanvas
|
|
1
|
+
{"version":3,"file":"modeTriggers.js","names":[],"sources":["../../../src/features/modes/modeTriggers.ts"],"sourcesContent":["import { modeLabel, type ModeDefinition, type ModeRegistry } from '@weasel-js/modes';\nimport { ActionDisabledReason, type Action, type ActionDeps, type Contribution } from '@weasel-js/routing';\n\n/** What a mode's double-click trigger does. */\nexport interface ModeTriggerHandlers {\n /** Enter mode `id` on the node `targetId`. Without it nothing is bound. */\n enter?: (id: string, targetId: string) => void;\n /**\n * Whether mode `id` can be entered on `targetId` now. Where it says no the double-click falls\n * through to the next binding on it, so a canvas action that already enters the mode on some\n * of those nodes keeps them: `enterPathEdit` on a path with anchors, say. Default yes.\n */\n canEnter?: (id: string, targetId: string) => boolean;\n}\n\n/**\n * The registry's double-click entries as an always-on contribution: for each mode whose\n * `entry.trigger` is `'double-click-target'`, one action bound to a double-click on each routing\n * kind its `entry.targets` names, entering the mode on the node double-clicked. Install it with\n * `<SceneCanvas ambient>`, beside `modeShortcuts`.\n *\n * The target is the node the dispatcher classified the double-click on (the `hitAt` dep's\n * `doubleClick`, else its hit), the one the binding's `kind:` target matched: a double-click on\n * a grouped member names its outermost group inside the entered group (`<SceneCanvas enteredGroup>`).\n * The action is live in every mode, the target mode included, so a double-click on another node\n * moves a mode onto it; `canEnter` and `enter` decide what a switch from the current mode means.\n *\n * The bindings ride the ambient tier: a tool that claims the double-click itself, the pen\n * finishing a stroke, keeps it.\n */\nexport function modeTriggers(registry: ModeRegistry, handlers: ModeTriggerHandlers): Contribution<never> {\n const actions: Action[] = [];\n const { enter } = handlers;\n if (enter) {\n for (const mode of registry.list()) {\n const targets = mode.entry?.trigger === 'double-click-target' ? mode.entry.targets ?? [] : [];\n if (targets.length > 0) actions.push(triggerAction(mode, targets, enter, handlers.canEnter));\n }\n }\n return { id: 'modes.triggers', eligibility: { always: true }, actions };\n}\n\nfunction triggerAction(\n mode: ModeDefinition,\n targets: readonly string[],\n enter: (id: string, targetId: string) => void,\n canEnter: ModeTriggerHandlers['canEnter'],\n): Action {\n const targetAt = (deps: ActionDeps | undefined, at: { x: number; y: number } | undefined): string | null => {\n if (!at) return null;\n const hit = deps?.hitAt?.(at);\n const id = (hit?.doubleClick ?? hit)?.id;\n if (id === undefined) return null;\n return canEnter?.(mode.id, id) === false ? null : id;\n };\n const id = `mode.${mode.id}.trigger`;\n return {\n id,\n label: `Enter ${modeLabel(mode)}`,\n defaultBinding: targets.map((kind) => ({\n spec: { kind: 'doubleClick' as const, target: `kind:${kind}` as const },\n opts: { id: `${id}.doubleClick.${kind}` },\n })),\n requires: ['hitAt'],\n enabled: (deps, at) => (targetAt(deps, at) !== null ? true : ActionDisabledReason.NotApplicable),\n invoker: {\n timing: 'immediate',\n run: (deps, params) => {\n const x = params?.worldX, y = params?.worldY;\n const id = typeof x === 'number' && typeof y === 'number' ? targetAt(deps, { x, y }) : null;\n if (id !== null) enter(mode.id, id);\n },\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,aAAa,UAAwB,UAAoD;CACvG,MAAM,UAAoB,CAAC;CAC3B,MAAM,EAAE,UAAU;CAClB,IAAI,OACF,KAAK,MAAM,QAAQ,SAAS,KAAK,GAAG;EAClC,MAAM,UAAU,KAAK,OAAO,YAAY,wBAAwB,KAAK,MAAM,WAAW,CAAC,IAAI,CAAC;EAC5F,IAAI,QAAQ,SAAS,GAAG,QAAQ,KAAK,cAAc,MAAM,SAAS,OAAO,SAAS,QAAQ,CAAC;CAC7F;CAEF,OAAO;EAAE,IAAI;EAAkB,aAAa,EAAE,QAAQ,KAAK;EAAG;CAAQ;AACxE;AAEA,SAAS,cACP,MACA,SACA,OACA,UACQ;CACR,MAAM,YAAY,MAA8B,OAA4D;EAC1G,IAAI,CAAC,IAAI,OAAO;EAChB,MAAM,MAAM,MAAM,QAAQ,EAAE;EAC5B,MAAM,MAAM,KAAK,eAAe,IAAA,EAAM;EACtC,IAAI,OAAO,QAAW,OAAO;EAC7B,OAAO,WAAW,KAAK,IAAI,EAAE,MAAM,QAAQ,OAAO;CACpD;CACA,MAAM,KAAK,QAAQ,KAAK,GAAG;CAC3B,OAAO;EACL;EACA,OAAO,SAAS,UAAU,IAAI;EAC9B,gBAAgB,QAAQ,KAAK,UAAU;GACrC,MAAM;IAAE,MAAM;IAAwB,QAAQ,QAAQ;GAAgB;GACtE,MAAM,EAAE,IAAI,GAAG,GAAG,eAAe,OAAO;EAC1C,EAAE;EACF,UAAU,CAAC,OAAO;EAClB,UAAU,MAAM,OAAQ,SAAS,MAAM,EAAE,MAAM,OAAO,OAAO,qBAAqB;EAClF,SAAS;GACP,QAAQ;GACR,MAAM,MAAM,WAAW;IACrB,MAAM,IAAI,QAAQ,QAAQ,IAAI,QAAQ;IACtC,MAAM,KAAK,OAAO,MAAM,YAAY,OAAO,MAAM,WAAW,SAAS,MAAM;KAAE;KAAG;IAAE,CAAC,IAAI;IACvF,IAAI,OAAO,MAAM,MAAM,KAAK,IAAI,EAAE;GACpC;EACF;CACF;AACF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { sourcesOf } from "../../core/scene/dependents.js";
|
|
2
|
+
import { pathEffectOf } from "../../core/scene/pathEffects/derive.js";
|
|
3
|
+
import { isTextData } from "@weasel-js/text";
|
|
4
|
+
|
|
5
|
+
//#region src/features/pathEffects/effectSources.ts
|
|
6
|
+
/**
|
|
7
|
+
* A path effect that hides its sources is edited through itself: its text and
|
|
8
|
+
* its path are reached from the effect node.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* For a path-effect node with `hideSources`, the source an edit of `role`
|
|
12
|
+
* goes to: `'text'`, its first source when that is a text node; `'path'`, the
|
|
13
|
+
* path it lays along — the second source of an along kind, a blend's spine.
|
|
14
|
+
* `null` otherwise. The one answer every edit route asks. It takes a source
|
|
15
|
+
* hidden before the effect was made too: either way the effect is what shows it.
|
|
16
|
+
*/
|
|
17
|
+
function effectSourceFor(scene, id, role) {
|
|
18
|
+
const node = scene.get(id);
|
|
19
|
+
const effect = pathEffectOf(node);
|
|
20
|
+
if (effect === null || effect.hideSources !== true) return null;
|
|
21
|
+
const at = role === "text" ? 0 : effect.kind === "blend" ? 2 : 1;
|
|
22
|
+
const source = sourcesOf(node)[at];
|
|
23
|
+
const found = source === void 0 ? void 0 : scene.get(source);
|
|
24
|
+
if (found === void 0) return null;
|
|
25
|
+
return role === "text" && !isTextData(found.data) ? null : source;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The sources path-effect node `id` holds hidden: with `hideSources`, each of
|
|
29
|
+
* its sources but those it found hidden. Empty for any other node.
|
|
30
|
+
*/
|
|
31
|
+
function sourcesHiddenBy(scene, id) {
|
|
32
|
+
const node = scene.get(id);
|
|
33
|
+
const effect = pathEffectOf(node);
|
|
34
|
+
if (effect?.hideSources !== true) return [];
|
|
35
|
+
const found = effect.foundHidden ?? [];
|
|
36
|
+
return sourcesOf(node).filter((_, at) => !found.includes(at));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The sources a removal of `ids` takes with it: those that a path effect with
|
|
40
|
+
* `hideSources` in the removal hid, and that nothing staying still derives
|
|
41
|
+
* from. A source another effect still reads stays, and so does one shown
|
|
42
|
+
* again since or named in `keep`. Transitive, so an effect's hidden effect
|
|
43
|
+
* takes its own too.
|
|
44
|
+
*/
|
|
45
|
+
function hiddenSourcesTakenWith(scene, ids, keep = /* @__PURE__ */ new Set()) {
|
|
46
|
+
const going = new Set(scene.removalClosure(ids));
|
|
47
|
+
const taken = [];
|
|
48
|
+
const within = (node, root) => {
|
|
49
|
+
for (let at = node; at != null; at = scene.get(at)?.parent) if (at === root) return true;
|
|
50
|
+
return false;
|
|
51
|
+
};
|
|
52
|
+
let grew = true;
|
|
53
|
+
while (grew) {
|
|
54
|
+
grew = false;
|
|
55
|
+
for (const id of [...going]) for (const source of sourcesHiddenBy(scene, id)) {
|
|
56
|
+
if (going.has(source) || keep.has(source) || scene.get(source)?.hidden !== true) continue;
|
|
57
|
+
const closure = scene.removalClosure([source]);
|
|
58
|
+
if (!closure.every((n) => going.has(n) || within(n, source))) continue;
|
|
59
|
+
for (const n of closure) going.add(n);
|
|
60
|
+
taken.push(source);
|
|
61
|
+
grew = true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return taken;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
export { effectSourceFor, hiddenSourcesTakenWith, sourcesHiddenBy };
|
|
69
|
+
//# sourceMappingURL=effectSources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effectSources.js","names":[],"sources":["../../../src/features/pathEffects/effectSources.ts"],"sourcesContent":["/**\n * A path effect that hides its sources is edited through itself: its text and\n * its path are reached from the effect node.\n */\nimport { isTextData } from '@weasel-js/text';\nimport { pathEffectOf } from 'core/scene/pathEffects/derive';\nimport { sourcesOf } from 'core/scene/dependents';\nimport type { NodeId, Scene } from 'core/scene/types';\n\n/**\n * For a path-effect node with `hideSources`, the source an edit of `role`\n * goes to: `'text'`, its first source when that is a text node; `'path'`, the\n * path it lays along — the second source of an along kind, a blend's spine.\n * `null` otherwise. The one answer every edit route asks. It takes a source\n * hidden before the effect was made too: either way the effect is what shows it.\n */\nexport function effectSourceFor<TData, TLayer extends string, TPose>(\n scene: Pick<Scene<TData, TLayer, TPose>, 'get'>,\n id: NodeId,\n role: 'text' | 'path',\n): NodeId | null {\n const node = scene.get(id);\n const effect = pathEffectOf(node);\n if (effect === null || effect.hideSources !== true) return null;\n const at = role === 'text' ? 0 : effect.kind === 'blend' ? 2 : 1;\n const source = sourcesOf(node)[at];\n const found = source === undefined ? undefined : scene.get(source);\n if (found === undefined) return null;\n return role === 'text' && !isTextData(found.data) ? null : source!;\n}\n\n/**\n * The sources path-effect node `id` holds hidden: with `hideSources`, each of\n * its sources but those it found hidden. Empty for any other node.\n */\nexport function sourcesHiddenBy<TData, TLayer extends string, TPose>(\n scene: Pick<Scene<TData, TLayer, TPose>, 'get'>,\n id: NodeId,\n): NodeId[] {\n const node = scene.get(id);\n const effect = pathEffectOf(node);\n if (effect?.hideSources !== true) return [];\n const found = effect.foundHidden ?? [];\n return sourcesOf(node).filter((_, at) => !found.includes(at));\n}\n\n/**\n * The sources a removal of `ids` takes with it: those that a path effect with\n * `hideSources` in the removal hid, and that nothing staying still derives\n * from. A source another effect still reads stays, and so does one shown\n * again since or named in `keep`. Transitive, so an effect's hidden effect\n * takes its own too.\n */\nexport function hiddenSourcesTakenWith<TData, TLayer extends string, TPose>(\n scene: Pick<Scene<TData, TLayer, TPose>, 'get' | 'removalClosure'>,\n ids: readonly NodeId[],\n keep: ReadonlySet<NodeId> = new Set(),\n): NodeId[] {\n const going = new Set<NodeId>(scene.removalClosure(ids));\n const taken: NodeId[] = [];\n const within = (node: NodeId, root: NodeId): boolean => {\n for (let at: NodeId | null | undefined = node; at != null; at = scene.get(at)?.parent) if (at === root) return true;\n return false;\n };\n let grew = true;\n while (grew) {\n grew = false;\n for (const id of [...going]) {\n for (const source of sourcesHiddenBy(scene, id)) {\n if (going.has(source) || keep.has(source) || scene.get(source)?.hidden !== true) continue;\n const closure = scene.removalClosure([source]);\n if (!closure.every((n) => going.has(n) || within(n, source))) continue;\n for (const n of closure) going.add(n);\n taken.push(source);\n grew = true;\n }\n }\n }\n return taken;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,SAAgB,gBACd,OACA,IACA,MACe;CACf,MAAM,OAAO,MAAM,IAAI,EAAE;CACzB,MAAM,SAAS,aAAa,IAAI;CAChC,IAAI,WAAW,QAAQ,OAAO,gBAAgB,MAAM,OAAO;CAC3D,MAAM,KAAK,SAAS,SAAS,IAAI,OAAO,SAAS,UAAU,IAAI;CAC/D,MAAM,SAAS,UAAU,IAAI,CAAC,CAAC;CAC/B,MAAM,QAAQ,WAAW,SAAY,SAAY,MAAM,IAAI,MAAM;CACjE,IAAI,UAAU,QAAW,OAAO;CAChC,OAAO,SAAS,UAAU,CAAC,WAAW,MAAM,IAAI,IAAI,OAAO;AAC7D;;;;;AAMA,SAAgB,gBACd,OACA,IACU;CACV,MAAM,OAAO,MAAM,IAAI,EAAE;CACzB,MAAM,SAAS,aAAa,IAAI;CAChC,IAAI,QAAQ,gBAAgB,MAAM,OAAO,CAAC;CAC1C,MAAM,QAAQ,OAAO,eAAe,CAAC;CACrC,OAAO,UAAU,IAAI,CAAC,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,SAAS,EAAE,CAAC;AAC9D;;;;;;;;AASA,SAAgB,uBACd,OACA,KACA,uBAA4B,IAAI,IAAI,GAC1B;CACV,MAAM,QAAQ,IAAI,IAAY,MAAM,eAAe,GAAG,CAAC;CACvD,MAAM,QAAkB,CAAC;CACzB,MAAM,UAAU,MAAc,SAA0B;EACtD,KAAK,IAAI,KAAgC,MAAM,MAAM,MAAM,KAAK,MAAM,IAAI,EAAE,CAAC,EAAE,QAAQ,IAAI,OAAO,MAAM,OAAO;EAC/G,OAAO;CACT;CACA,IAAI,OAAO;CACX,OAAO,MAAM;EACX,OAAO;EACP,KAAK,MAAM,MAAM,CAAC,GAAG,KAAK,GACxB,KAAK,MAAM,UAAU,gBAAgB,OAAO,EAAE,GAAG;GAC/C,IAAI,MAAM,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,CAAC,EAAE,WAAW,MAAM;GACjF,MAAM,UAAU,MAAM,eAAe,CAAC,MAAM,CAAC;GAC7C,IAAI,CAAC,QAAQ,OAAO,MAAM,MAAM,IAAI,CAAC,KAAK,OAAO,GAAG,MAAM,CAAC,GAAG;GAC9D,KAAK,MAAM,KAAK,SAAS,MAAM,IAAI,CAAC;GACpC,MAAM,KAAK,MAAM;GACjB,OAAO;EACT;CAEJ;CACA,OAAO;AACT"}
|
|
@@ -1,17 +1,33 @@
|
|
|
1
|
+
import { noteFontRead } from "../../core/scene/fontReads.js";
|
|
1
2
|
import { isRectPose } from "../../core/geometry/autoPoseDescriptor.js";
|
|
2
3
|
import { pathPaintOf } from "../../canvas/nodeShapes/nodePaint.js";
|
|
3
4
|
import { findNodeShape } from "../../canvas/NodeShape.js";
|
|
5
|
+
import { textEffectItems } from "./textItems.js";
|
|
4
6
|
import { pathThroughPoseFrame, poseLinearOf } from "@weasel-js/geom";
|
|
7
|
+
import { isTextData } from "@weasel-js/text";
|
|
5
8
|
|
|
6
9
|
//#region src/features/pathEffects/readSource.ts
|
|
7
10
|
/**
|
|
8
11
|
* How the kit's path effects read a source node: its outline from its
|
|
9
12
|
* painter's silhouette, its paint as `kit:path` resolves it.
|
|
10
13
|
*/
|
|
11
|
-
/** `dep` as a path effect's source, or `null` when it has no outline.
|
|
14
|
+
/** `dep` as a path effect's source, or `null` when it has no outline. A text
|
|
15
|
+
* node's source also carries its grapheme clusters as items. */
|
|
12
16
|
function readEffectSource(dep) {
|
|
17
|
+
const data = dep.node.data;
|
|
18
|
+
const text = isTextData(data);
|
|
19
|
+
if (text) noteFontRead();
|
|
20
|
+
const source = readShape(dep);
|
|
21
|
+
const pose = dep.pose;
|
|
22
|
+
if (source === null || !text || !isRectPose(pose)) return source;
|
|
23
|
+
return {
|
|
24
|
+
...source,
|
|
25
|
+
items: () => textEffectItems(data, pose)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function readShape(dep) {
|
|
13
29
|
const data = dep.node.data ?? {};
|
|
14
|
-
const { fill, stroke } = pathPaintOf(data);
|
|
30
|
+
const { fill, stroke } = pathPaintOf(data, dep.inherited);
|
|
15
31
|
const paint = {
|
|
16
32
|
fill,
|
|
17
33
|
stroke: stroke ?? null
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readSource.js","names":[],"sources":["../../../src/features/pathEffects/readSource.ts"],"sourcesContent":["/**\n * How the kit's path effects read a source node: its outline from its\n * painter's silhouette, its paint as `kit:path` resolves it.\n */\nimport { pathThroughPoseFrame, poseLinearOf } from '@weasel-js/geom';\nimport type { Fill, Stroke } from '@weasel-js/paint';\nimport { findNodeShape } from 'canvas/NodeShape';\nimport { isRectPose } from 'core/geometry/autoPoseDescriptor';\nimport type { EffectSource } from 'core/scene/pathEffects/source';\nimport type { DerivedDep } from 'core/scene/types';\nimport { pathPaintOf } from 'canvas/nodeShapes/nodePaint';\n\n/** `dep` as a path effect's source, or `null` when it has no outline. */\nexport function readEffectSource(dep: DerivedDep<unknown>): EffectSource | null {\n const data = (dep.node.data ?? {}) as { fill?: Fill | null; stroke?: Stroke | null };\n const { fill, stroke } = pathPaintOf(data);\n const paint = { fill, stroke: stroke ?? null };\n const shown = dep.path;\n if (shown !== null) return { world: shown, ...paint };\n const local = findNodeShape(dep.node)?.silhouette?.(dep.node, dep.pose) ?? null;\n if (local === null) return null;\n const world = pathThroughPoseFrame(local, dep.pose);\n const pose = dep.pose;\n if (!isRectPose(pose) || poseLinearOf(pose) !== null) return { world, ...paint };\n return {\n world,\n framed: { path: local, cx: pose.x + pose.width / 2, cy: pose.y + pose.height / 2, rotation: pose.rotation ?? 0 },\n ...paint,\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"readSource.js","names":[],"sources":["../../../src/features/pathEffects/readSource.ts"],"sourcesContent":["/**\n * How the kit's path effects read a source node: its outline from its\n * painter's silhouette, its paint as `kit:path` resolves it.\n */\nimport { pathThroughPoseFrame, poseLinearOf, type PathInWorldPose } from '@weasel-js/geom';\nimport type { Fill, Stroke } from '@weasel-js/paint';\nimport { isTextData, type TextOutlineSource } from '@weasel-js/text';\nimport { findNodeShape } from 'canvas/NodeShape';\nimport { isRectPose } from 'core/geometry/autoPoseDescriptor';\nimport { noteFontRead } from 'core/scene/fontReads';\nimport type { EffectSource } from 'core/scene/pathEffects/source';\nimport type { DerivedDep } from 'core/scene/types';\nimport { pathPaintOf } from 'canvas/nodeShapes/nodePaint';\nimport { textEffectItems } from './textItems';\n\n/** `dep` as a path effect's source, or `null` when it has no outline. A text\n * node's source also carries its grapheme clusters as items. */\nexport function readEffectSource(dep: DerivedDep<unknown>): EffectSource | null {\n const data = dep.node.data;\n const text = isTextData(data);\n // A text node's outline is laid out in its face, which may not have landed: without this read, an effect that found\n // no outline while the face loads would never look again.\n if (text) noteFontRead();\n const source = readShape(dep);\n const pose = dep.pose;\n if (source === null || !text || !isRectPose(pose)) return source;\n return { ...source, items: () => textEffectItems(data as TextOutlineSource, pose as PathInWorldPose) };\n}\n\nfunction readShape(dep: DerivedDep<unknown>): EffectSource | null {\n const data = (dep.node.data ?? {}) as { fill?: Fill | null; stroke?: Stroke | null };\n const { fill, stroke } = pathPaintOf(data, dep.inherited);\n const paint = { fill, stroke: stroke ?? null };\n const shown = dep.path;\n if (shown !== null) return { world: shown, ...paint };\n const local = findNodeShape(dep.node)?.silhouette?.(dep.node, dep.pose) ?? null;\n if (local === null) return null;\n const world = pathThroughPoseFrame(local, dep.pose);\n const pose = dep.pose;\n if (!isRectPose(pose) || poseLinearOf(pose) !== null) return { world, ...paint };\n return {\n world,\n framed: { path: local, cx: pose.x + pose.width / 2, cy: pose.y + pose.height / 2, rotation: pose.rotation ?? 0 },\n ...paint,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,SAAgB,iBAAiB,KAA+C;CAC9E,MAAM,OAAO,IAAI,KAAK;CACtB,MAAM,OAAO,WAAW,IAAI;CAG5B,IAAI,MAAM,aAAa;CACvB,MAAM,SAAS,UAAU,GAAG;CAC5B,MAAM,OAAO,IAAI;CACjB,IAAI,WAAW,QAAQ,CAAC,QAAQ,CAAC,WAAW,IAAI,GAAG,OAAO;CAC1D,OAAO;EAAE,GAAG;EAAQ,aAAa,gBAAgB,MAA2B,IAAuB;CAAE;AACvG;AAEA,SAAS,UAAU,KAA+C;CAChE,MAAM,OAAQ,IAAI,KAAK,QAAQ,CAAC;CAChC,MAAM,EAAE,MAAM,WAAW,YAAY,MAAM,IAAI,SAAS;CACxD,MAAM,QAAQ;EAAE;EAAM,QAAQ,UAAU;CAAK;CAC7C,MAAM,QAAQ,IAAI;CAClB,IAAI,UAAU,MAAM,OAAO;EAAE,OAAO;EAAO,GAAG;CAAM;CACpD,MAAM,QAAQ,cAAc,IAAI,IAAI,CAAC,EAAE,aAAa,IAAI,MAAM,IAAI,IAAI,KAAK;CAC3E,IAAI,UAAU,MAAM,OAAO;CAC3B,MAAM,QAAQ,qBAAqB,OAAO,IAAI,IAAI;CAClD,MAAM,OAAO,IAAI;CACjB,IAAI,CAAC,WAAW,IAAI,KAAK,aAAa,IAAI,MAAM,MAAM,OAAO;EAAE;EAAO,GAAG;CAAM;CAC/E,OAAO;EACL;EACA,QAAQ;GAAE,MAAM;GAAO,IAAI,KAAK,IAAI,KAAK,QAAQ;GAAG,IAAI,KAAK,IAAI,KAAK,SAAS;GAAG,UAAU,KAAK,YAAY;EAAE;EAC/G,GAAG;CACL;AACF"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { noteFontRead } from "../../core/scene/fontReads.js";
|
|
2
|
+
import { poseFrameOf, transformPath } from "@weasel-js/geom";
|
|
3
|
+
import { TextOutlinesError, loadTextOutlines, textClusters } from "@weasel-js/text";
|
|
4
|
+
|
|
5
|
+
//#region src/features/pathEffects/textItems.ts
|
|
6
|
+
/**
|
|
7
|
+
* A text node as a path effect's items: its first line's grapheme clusters,
|
|
8
|
+
* each one's outlines in its own frame, sized as the node draws them.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The clusters of `data`'s first line as items, laid in `pose`'s box width.
|
|
12
|
+
* The pose's scale grows them; its rotation and skew are dropped, since the
|
|
13
|
+
* path an effect lays them along decides their turn. `[]` while a face's
|
|
14
|
+
* outlines are loading — the load is started, and the font read is noted so
|
|
15
|
+
* the derivation re-runs once it lands.
|
|
16
|
+
*/
|
|
17
|
+
function textEffectItems(data, pose) {
|
|
18
|
+
noteFontRead();
|
|
19
|
+
let clusters;
|
|
20
|
+
try {
|
|
21
|
+
clusters = textClusters(data, { width: pose.width });
|
|
22
|
+
} catch (err) {
|
|
23
|
+
if (!(err instanceof TextOutlinesError)) throw err;
|
|
24
|
+
loadTextOutlines(data).catch(() => {});
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
const k = scaleOf(pose);
|
|
28
|
+
const grow = k === 1 ? null : [
|
|
29
|
+
k,
|
|
30
|
+
0,
|
|
31
|
+
0,
|
|
32
|
+
k,
|
|
33
|
+
0,
|
|
34
|
+
0
|
|
35
|
+
];
|
|
36
|
+
return clusters.map((c) => ({
|
|
37
|
+
length: c.advance * k,
|
|
38
|
+
middle: c.middle * k,
|
|
39
|
+
parts: c.paths.map((p) => ({
|
|
40
|
+
path: grow === null ? p.path : transformPath(p.path, grow),
|
|
41
|
+
fill: p.fill,
|
|
42
|
+
stroke: p.stroke ?? null
|
|
43
|
+
}))
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
function scaleOf(pose) {
|
|
47
|
+
const m = poseFrameOf(pose);
|
|
48
|
+
return m === null ? 1 : Math.sqrt(Math.abs(m[0] * m[3] - m[1] * m[2]));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//#endregion
|
|
52
|
+
export { textEffectItems };
|
|
53
|
+
//# sourceMappingURL=textItems.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textItems.js","names":[],"sources":["../../../src/features/pathEffects/textItems.ts"],"sourcesContent":["/**\n * A text node as a path effect's items: its first line's grapheme clusters,\n * each one's outlines in its own frame, sized as the node draws them.\n */\nimport { poseFrameOf, transformPath, type Affine, type PathInWorldPose } from '@weasel-js/geom';\nimport {\n loadTextOutlines, textClusters, TextOutlinesError, type TextCluster, type TextOutlineSource,\n} from '@weasel-js/text';\nimport { noteFontRead } from 'core/scene/fontReads';\nimport type { EffectItem } from 'core/scene/pathEffects/source';\n\n/**\n * The clusters of `data`'s first line as items, laid in `pose`'s box width.\n * The pose's scale grows them; its rotation and skew are dropped, since the\n * path an effect lays them along decides their turn. `[]` while a face's\n * outlines are loading — the load is started, and the font read is noted so\n * the derivation re-runs once it lands.\n */\nexport function textEffectItems(data: TextOutlineSource, pose: PathInWorldPose): readonly EffectItem[] {\n noteFontRead();\n let clusters: TextCluster[];\n try {\n clusters = textClusters(data, { width: pose.width });\n } catch (err) {\n if (!(err instanceof TextOutlinesError)) throw err;\n loadTextOutlines(data).catch(() => {});\n return [];\n }\n const k = scaleOf(pose);\n const grow: Affine | null = k === 1 ? null : [k, 0, 0, k, 0, 0];\n return clusters.map((c) => ({\n length: c.advance * k,\n middle: c.middle * k,\n parts: c.paths.map((p) => ({\n path: grow === null ? p.path : transformPath(p.path, grow),\n fill: p.fill,\n stroke: p.stroke ?? null,\n })),\n }));\n}\n\nfunction scaleOf(pose: PathInWorldPose): number {\n const m = poseFrameOf(pose);\n return m === null ? 1 : Math.sqrt(Math.abs(m[0] * m[3] - m[1] * m[2]));\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkBA,SAAgB,gBAAgB,MAAyB,MAA8C;CACrG,aAAa;CACb,IAAI;CACJ,IAAI;EACF,WAAW,aAAa,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC;CACrD,SAAS,KAAK;EACZ,IAAI,EAAE,eAAe,oBAAoB,MAAM;EAC/C,iBAAiB,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC;EACrC,OAAO,CAAC;CACV;CACA,MAAM,IAAI,QAAQ,IAAI;CACtB,MAAM,OAAsB,MAAM,IAAI,OAAO;EAAC;EAAG;EAAG;EAAG;EAAG;EAAG;CAAC;CAC9D,OAAO,SAAS,KAAK,OAAO;EAC1B,QAAQ,EAAE,UAAU;EACpB,QAAQ,EAAE,SAAS;EACnB,OAAO,EAAE,MAAM,KAAK,OAAO;GACzB,MAAM,SAAS,OAAO,EAAE,OAAO,cAAc,EAAE,MAAM,IAAI;GACzD,MAAM,EAAE;GACR,QAAQ,EAAE,UAAU;EACtB,EAAE;CACJ,EAAE;AACJ;AAEA,SAAS,QAAQ,MAA+B;CAC9C,MAAM,IAAI,YAAY,IAAI;CAC1B,OAAO,MAAM,OAAO,IAAI,KAAK,KAAK,KAAK,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;AACvE"}
|