@weasel-js/core 1.10.0 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +168 -0
- package/README.md +33 -0
- package/dist/affordances/composeAffordanceLayer.js +21 -21
- package/dist/affordances/composeAffordanceLayer.js.map +1 -1
- package/dist/affordances/hitAffordanceRegions.js +48 -32
- package/dist/affordances/hitAffordanceRegions.js.map +1 -1
- package/dist/affordances/pathAnchors.js +50 -28
- package/dist/affordances/pathAnchors.js.map +1 -1
- package/dist/affordances/rotateCursor.js +12 -0
- package/dist/affordances/rotateCursor.js.map +1 -0
- package/dist/affordances/rotationHandle.js +40 -43
- package/dist/affordances/rotationHandle.js.map +1 -1
- package/dist/animation/rig/rigNode.js +9 -3
- package/dist/animation/rig/rigNode.js.map +1 -1
- package/dist/animation/rig/rigSeat.js +46 -13
- package/dist/animation/rig/rigSeat.js.map +1 -1
- package/dist/animation/rig/skinBinding.js +22 -14
- package/dist/animation/rig/skinBinding.js.map +1 -1
- package/dist/barrel/canvas.js +29 -28
- package/dist/barrel/interactions.js +33 -32
- package/dist/barrel/paths.js +11 -10
- package/dist/barrel/routing.js +49 -48
- package/dist/barrel/scene.js +10 -10
- package/dist/barrel/viewport.js +24 -21
- package/dist/canvas/Canvas.js +6 -17
- package/dist/canvas/Canvas.js.map +1 -1
- package/dist/canvas/CanvasView.js +34 -37
- package/dist/canvas/CanvasView.js.map +1 -1
- package/dist/canvas/CursorCoordsHud.js +3 -3
- package/dist/canvas/CursorCoordsHud.js.map +1 -1
- package/dist/canvas/DrawCanvas.js +3 -3
- package/dist/canvas/DrawCanvas.js.map +1 -1
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +24 -23
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js.map +1 -1
- package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js +40 -49
- package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js +297 -259
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
- package/dist/canvas/SceneCanvas/features.js +3 -24
- package/dist/canvas/SceneCanvas/features.js.map +1 -1
- package/dist/canvas/SceneCanvas/insertPreviewCommands.js +97 -0
- package/dist/canvas/SceneCanvas/insertPreviewCommands.js.map +1 -0
- package/dist/canvas/SceneCanvas/poseGeometry.js.map +1 -1
- package/dist/canvas/SceneCanvas/props.js.map +1 -1
- package/dist/canvas/SceneCanvas/scenePointQuery.js +50 -0
- package/dist/canvas/SceneCanvas/scenePointQuery.js.map +1 -0
- package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js +52 -0
- package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js.map +1 -0
- package/dist/canvas/SceneCanvas/useActionTunings.js +17 -0
- package/dist/canvas/SceneCanvas/useActionTunings.js.map +1 -0
- package/dist/canvas/SceneCanvas/useCanvasCamera.js +37 -29
- package/dist/canvas/SceneCanvas/useCanvasCamera.js.map +1 -1
- package/dist/canvas/SceneCanvas/useCanvasDispatcher.js +11 -11
- package/dist/canvas/SceneCanvas/useCanvasDispatcher.js.map +1 -1
- package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js +45 -109
- package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js +49 -41
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js +64 -96
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
- package/dist/canvas/SceneCanvas/worldPointAt.js +3 -4
- package/dist/canvas/SceneCanvas/worldPointAt.js.map +1 -1
- package/dist/canvas/SceneCanvas.js +77 -80
- package/dist/canvas/SceneCanvas.js.map +1 -1
- package/dist/canvas/SceneViewCanvas.js +3 -3
- package/dist/canvas/SceneViewCanvas.js.map +1 -1
- package/dist/canvas/SurfaceCanvas.js +40 -0
- package/dist/canvas/SurfaceCanvas.js.map +1 -0
- package/dist/canvas/adapterDerivedPath.js +13 -13
- package/dist/canvas/adapterDerivedPath.js.map +1 -1
- package/dist/canvas/adapterPickSource.js +34 -0
- package/dist/canvas/adapterPickSource.js.map +1 -0
- package/dist/canvas/affordanceAt.js +1 -1
- package/dist/canvas/affordanceAt.js.map +1 -1
- package/dist/canvas/buildSceneLayer.js.map +1 -1
- package/dist/canvas/buildSceneTree.js +56 -34
- package/dist/canvas/buildSceneTree.js.map +1 -1
- package/dist/canvas/copiesAbove.js +27 -0
- package/dist/canvas/copiesAbove.js.map +1 -0
- package/dist/canvas/defaultDrawOne.js +24 -23
- package/dist/canvas/defaultDrawOne.js.map +1 -1
- package/dist/canvas/deps/editAnchors.js +45 -50
- package/dist/canvas/deps/editAnchors.js.map +1 -1
- package/dist/canvas/deps/hitTestArea.js +30 -15
- package/dist/canvas/deps/hitTestArea.js.map +1 -1
- package/dist/canvas/deps/insert.js +134 -100
- package/dist/canvas/deps/insert.js.map +1 -1
- package/dist/canvas/deps/layout.js +9 -15
- package/dist/canvas/deps/layout.js.map +1 -1
- package/dist/canvas/derivedPath.js +53 -29
- package/dist/canvas/derivedPath.js.map +1 -1
- package/dist/canvas/insertPreviewExtent.js +33 -31
- package/dist/canvas/insertPreviewExtent.js.map +1 -1
- package/dist/canvas/overChildren.js +29 -0
- package/dist/canvas/overChildren.js.map +1 -0
- package/dist/canvas/paintedCursorLayer.js.map +1 -1
- package/dist/canvas/pickReach.js +23 -0
- package/dist/canvas/pickReach.js.map +1 -0
- package/dist/canvas/pickWalk.js +51 -80
- package/dist/canvas/pickWalk.js.map +1 -1
- package/dist/canvas/sceneAdapter.js +14 -35
- package/dist/canvas/sceneAdapter.js.map +1 -1
- package/dist/canvas/sceneSlotWiring.js +11 -10
- package/dist/canvas/sceneSlotWiring.js.map +1 -1
- package/dist/canvas/sceneViewRender.js +38 -44
- package/dist/canvas/sceneViewRender.js.map +1 -1
- package/dist/canvas/useCanvasView.js +42 -44
- package/dist/canvas/useCanvasView.js.map +1 -1
- package/dist/canvas/useSceneAdapter.js +22 -0
- package/dist/canvas/useSceneAdapter.js.map +1 -0
- package/dist/canvas/useSurfaceInput.js +13 -16
- package/dist/canvas/useSurfaceInput.js.map +1 -1
- package/dist/canvas/viewRegistry.js +31 -23
- package/dist/canvas/viewRegistry.js.map +1 -1
- package/dist/canvas/wrapNodeOutput.js +7 -2
- package/dist/canvas/wrapNodeOutput.js.map +1 -1
- package/dist/clipboard.d.ts +1 -1
- package/dist/{clone-2a5hVbBd.d.ts → clone-C0eADtS0.d.ts} +13 -13
- package/dist/clone.d.ts +2 -2
- package/dist/core/geometry/poseDescriptor.js +49 -23
- package/dist/core/geometry/poseDescriptor.js.map +1 -1
- package/dist/core/geometry/regionHit.js +2 -2
- package/dist/core/geometry/regionHit.js.map +1 -1
- package/dist/core/geometry/targetFrame.js.map +1 -1
- package/dist/core/layers/children.js +1 -3
- package/dist/core/layers/children.js.map +1 -1
- package/dist/core/ops/create.js +2 -2
- package/dist/core/ops/create.js.map +1 -1
- package/dist/core/ops/delete.js +19 -23
- package/dist/core/ops/delete.js.map +1 -1
- package/dist/core/ops/reorder/index.js +3 -7
- package/dist/core/ops/reorder/index.js.map +1 -1
- package/dist/core/ops/reorder/setChildOrder.js +2 -4
- package/dist/core/ops/reorder/setChildOrder.js.map +1 -1
- package/dist/core/ops/reparent.js +0 -1
- package/dist/core/ops/reparent.js.map +1 -1
- package/dist/core/ops/slot.js +3 -6
- package/dist/core/ops/slot.js.map +1 -1
- package/dist/core/pages/fitViewToPage.js +15 -0
- package/dist/core/pages/fitViewToPage.js.map +1 -0
- package/dist/core/pages/pages.js +65 -0
- package/dist/core/pages/pages.js.map +1 -0
- package/dist/core/pages/pagesLayer.js +27 -0
- package/dist/core/pages/pagesLayer.js.map +1 -0
- package/dist/core/paint/meshKindLazy.js +2 -2
- package/dist/core/paint/meshKindLazy.js.map +1 -1
- package/dist/core/scene/NodeProperties.js.map +1 -1
- package/dist/core/scene/composeFrame.js.map +1 -1
- package/dist/core/scene/composePose.js +58 -20
- package/dist/core/scene/composePose.js.map +1 -1
- package/dist/core/scene/effectivePose.js +5 -1
- package/dist/core/scene/effectivePose.js.map +1 -1
- package/dist/core/scene/historyFacade.js +19 -13
- package/dist/core/scene/historyFacade.js.map +1 -1
- package/dist/core/scene/nodeFnFields.js +7 -0
- package/dist/core/scene/nodeFnFields.js.map +1 -1
- package/dist/core/scene/outerOps.js +2 -1
- package/dist/core/scene/outerOps.js.map +1 -1
- package/dist/core/scene/reconcileSpecs.js +1 -1
- package/dist/core/scene/reconcileSpecs.js.map +1 -1
- package/dist/core/scene/sceneRecording.js +2 -1
- package/dist/core/scene/sceneRecording.js.map +1 -1
- package/dist/core/scene/types.js.map +1 -1
- package/dist/core/viewport/screenSlop.js.map +1 -1
- package/dist/core/viewport/useDecayLoop.js +28 -30
- package/dist/core/viewport/useDecayLoop.js.map +1 -1
- package/dist/core/viewport/useNodeOverlayFrame.js.map +1 -1
- package/dist/core/viewport/useViewAnimation.js +70 -69
- package/dist/core/viewport/useViewAnimation.js.map +1 -1
- package/dist/core/viewport/view.js +8 -5
- package/dist/core/viewport/view.js.map +1 -1
- package/dist/core/viewport/zoomAt.js +11 -2
- package/dist/core/viewport/zoomAt.js.map +1 -1
- package/dist/{cornerHandles-BEshc4z3.d.ts → cornerHandles-BSKbyuvQ.d.ts} +1 -1
- package/dist/features/paths/editablePath.js +24 -8
- package/dist/features/paths/editablePath.js.map +1 -1
- package/dist/features/paths/index.js +4 -4
- package/dist/features/paths/shapeGenerator.js +89 -0
- package/dist/features/paths/shapeGenerator.js.map +1 -0
- package/dist/features/paths/usePathEdit.js +13 -13
- package/dist/features/poseRun/usePoseRun.js +25 -25
- package/dist/features/poseRun/usePoseRun.js.map +1 -1
- package/dist/features/text/useSceneTextEdit.js +82 -64
- package/dist/features/text/useSceneTextEdit.js.map +1 -1
- package/dist/features/viewports/viewResolver.js +28 -24
- package/dist/features/viewports/viewResolver.js.map +1 -1
- package/dist/icons/SliceIcon.js +24 -0
- package/dist/icons/SliceIcon.js.map +1 -0
- package/dist/index.d.ts +956 -581
- package/dist/index.js +260 -251
- package/dist/interactions/actions/align/align.js +9 -9
- package/dist/interactions/actions/align/align.js.map +1 -1
- package/dist/interactions/actions/booleans/booleans.js +18 -18
- package/dist/interactions/actions/booleans/booleans.js.map +1 -1
- package/dist/interactions/actions/booleans/operands.js.map +1 -1
- package/dist/interactions/actions/clone/action.js +35 -30
- package/dist/interactions/actions/clone/action.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorEditing.js +56 -59
- package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorHandles.js +42 -0
- package/dist/interactions/actions/defaults/anchorHandles.js.map +1 -0
- package/dist/interactions/actions/defaults/anchorJoin.js +92 -0
- package/dist/interactions/actions/defaults/anchorJoin.js.map +1 -0
- package/dist/interactions/actions/defaults/bendSegment.js +46 -0
- package/dist/interactions/actions/defaults/bendSegment.js.map +1 -0
- package/dist/interactions/actions/defaults/copySubtree.js +1 -1
- package/dist/interactions/actions/defaults/copySubtree.js.map +1 -1
- package/dist/interactions/actions/defaults/duplicate.js +32 -17
- package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
- package/dist/interactions/actions/defaults/enterPathEdit.js +19 -7
- package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/icons/anchorIcons.js +75 -0
- package/dist/interactions/actions/defaults/icons/anchorIcons.js.map +1 -0
- package/dist/interactions/actions/defaults/icons/editIcons.js +35 -8
- package/dist/interactions/actions/defaults/icons/editIcons.js.map +1 -1
- package/dist/interactions/actions/defaults/insertPathAnchor.js +16 -31
- package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
- package/dist/interactions/actions/defaults/nudge.js +28 -23
- package/dist/interactions/actions/defaults/nudge.js.map +1 -1
- package/dist/interactions/actions/defaults/pinchZoom.js +29 -29
- package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
- package/dist/interactions/actions/defaults/segmentUnder.js +22 -0
- package/dist/interactions/actions/defaults/segmentUnder.js.map +1 -0
- package/dist/interactions/actions/defaults/viewportZoom.js +82 -79
- package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
- package/dist/interactions/actions/distribute/distribute.js +8 -8
- package/dist/interactions/actions/distribute/distribute.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/action.js +58 -55
- package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/preview.js +26 -0
- package/dist/interactions/actions/edit-anchors/preview.js.map +1 -0
- package/dist/interactions/actions/edit-anchors/symmetry.js +11 -0
- package/dist/interactions/actions/edit-anchors/symmetry.js.map +1 -0
- package/dist/interactions/actions/flip/action.js.map +1 -1
- package/dist/interactions/actions/geometryProjection.js.map +1 -1
- package/dist/interactions/actions/insert/action.js +37 -30
- package/dist/interactions/actions/insert/action.js.map +1 -1
- package/dist/interactions/actions/insert/frame.js +9 -2
- package/dist/interactions/actions/insert/frame.js.map +1 -1
- package/dist/interactions/actions/insert/repositionAction.js +31 -0
- package/dist/interactions/actions/insert/repositionAction.js.map +1 -0
- package/dist/interactions/actions/lasso-select/action.js +32 -32
- package/dist/interactions/actions/move/action.js +29 -25
- package/dist/interactions/actions/move/action.js.map +1 -1
- package/dist/interactions/actions/move/behaviors/snapToContainer.js +12 -6
- package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
- package/dist/interactions/actions/move/capture.js +32 -23
- package/dist/interactions/actions/move/capture.js.map +1 -1
- package/dist/interactions/actions/move/frame.js +2 -14
- package/dist/interactions/actions/move/frame.js.map +1 -1
- package/dist/interactions/actions/move/session.js +1 -1
- package/dist/interactions/actions/move/session.js.map +1 -1
- package/dist/interactions/actions/move/translate.js.map +1 -1
- package/dist/interactions/actions/outlines/createOutlines.js.map +1 -1
- package/dist/interactions/actions/outlines/replaceWithPaths.js +13 -13
- package/dist/interactions/actions/outlines/replaceWithPaths.js.map +1 -1
- package/dist/interactions/actions/outlines/strokeRegion.js.map +1 -1
- package/dist/interactions/actions/pathCommands/cutJoin.js +102 -0
- package/dist/interactions/actions/pathCommands/cutJoin.js.map +1 -0
- package/dist/interactions/actions/pathCommands/livePathEdit.js +64 -0
- package/dist/interactions/actions/pathCommands/livePathEdit.js.map +1 -0
- package/dist/interactions/actions/pathCommands/pathNodes.js +99 -0
- package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -0
- package/dist/interactions/actions/pathCommands/simplifyOffset.js +42 -0
- package/dist/interactions/actions/pathCommands/simplifyOffset.js.map +1 -0
- package/dist/interactions/actions/resize/action.js +31 -20
- package/dist/interactions/actions/resize/action.js.map +1 -1
- package/dist/interactions/actions/resize/commit.js.map +1 -1
- package/dist/interactions/actions/resize/frame.js +29 -15
- package/dist/interactions/actions/resize/frame.js.map +1 -1
- package/dist/interactions/actions/resize/replay.js +47 -0
- package/dist/interactions/actions/resize/replay.js.map +1 -0
- package/dist/interactions/actions/resize/session.js +49 -35
- package/dist/interactions/actions/resize/session.js.map +1 -1
- package/dist/interactions/actions/resolveOverlays.js +2 -1
- package/dist/interactions/actions/resolveOverlays.js.map +1 -1
- package/dist/interactions/actions/rotate/action.js +40 -25
- package/dist/interactions/actions/rotate/action.js.map +1 -1
- package/dist/interactions/actions/rotate/frame.js +1 -1
- package/dist/interactions/actions/rotate/frame.js.map +1 -1
- package/dist/interactions/actions/rotate/replay.js +22 -0
- package/dist/interactions/actions/rotate/replay.js.map +1 -0
- package/dist/interactions/actions/rotate/session.js +42 -32
- package/dist/interactions/actions/rotate/session.js.map +1 -1
- package/dist/interactions/actions/transform-again/action.js +63 -0
- package/dist/interactions/actions/transform-again/action.js.map +1 -0
- package/dist/interactions/actions/transform-again/memory.js +35 -0
- package/dist/interactions/actions/transform-again/memory.js.map +1 -0
- package/dist/interactions/actions/useStandardActions.js +101 -83
- package/dist/interactions/actions/useStandardActions.js.map +1 -1
- package/dist/move.d.ts +4 -4
- package/dist/{originProjection-PPT88jZv.d.ts → originProjection-CoNVpITV.d.ts} +1 -1
- package/dist/resize.d.ts +3 -3
- package/dist/style.css +1 -1
- package/dist/tools/builtin/ellipse/useEllipseTool.js +16 -15
- package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
- package/dist/tools/builtin/line/useLineTool.js +16 -15
- package/dist/tools/builtin/line/useLineTool.js.map +1 -1
- package/dist/tools/builtin/pen/usePenTool.js +111 -111
- package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
- package/dist/tools/builtin/pickTopMostHit.js +11 -14
- package/dist/tools/builtin/pickTopMostHit.js.map +1 -1
- package/dist/tools/builtin/polygon/usePolygonTool.js +17 -15
- package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
- package/dist/tools/builtin/rect/useRectTool.js +15 -14
- package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
- package/dist/tools/builtin/select/adapterPointQuery.js +22 -18
- package/dist/tools/builtin/select/adapterPointQuery.js.map +1 -1
- package/dist/tools/builtin/select/selectionContributions.js +1 -1
- package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
- package/dist/tools/builtin/select/useSelectTool.js +2 -1
- package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
- package/dist/tools/builtin/slice/useSliceTool.js +42 -40
- package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
- package/dist/tools/builtin/star/useStarTool.js +18 -16
- package/dist/tools/builtin/star/useStarTool.js.map +1 -1
- package/dist/tools/builtin/text/useTextTool.js +2 -2
- package/dist/tools/builtin/text/useTextTool.js.map +1 -1
- package/dist/{types-CIKDwlsP.d.ts → types-DBbbCy0i.d.ts} +22 -15
- package/dist/version.js +1 -1
- package/package.json +22 -22
- package/dist/canvas/surface.module.js +0 -6
- package/dist/canvas/surface.module.js.map +0 -1
- package/dist/canvas/surfaceBox.js +0 -16
- package/dist/canvas/surfaceBox.js.map +0 -1
- package/dist/layout/arrivals.js +0 -33
- package/dist/layout/arrivals.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translate.js","names":["translateOps","ops","id","ids","session","node","localDelta","delta","c","m","authored","createTransformOp","translatePoseViaDescriptor","dataOp","geometryDataOp","rootTranslateOps","wanted","roots","unreleasedIds","selected","out","released","cur","claimed"],"sources":["../../../../src/interactions/actions/move/translate.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"translate.js","names":["translateOps","ops","id","ids","session","node","localDelta","delta","c","m","authored","createTransformOp","translatePoseViaDescriptor","dataOp","geometryDataOp","rootTranslateOps","wanted","roots","unreleasedIds","selected","out","released","cur","claimed"],"sources":["../../../../src/interactions/actions/move/translate.ts"],"sourcesContent":["import type { Affine } from '@weasel-js/geom';\nimport { translatePoseViaDescriptor } from 'core/geometry/poseDescriptor';\nimport { createTransformOp } from 'core/ops/transform';\nimport type { Op } from 'core/ops/types';\nimport type { NodeId } from 'core/scene/types';\nimport { geometryDataOp } from '../geometryProjection';\nimport { localDelta } from './delta';\nimport type { MoveSession } from './session';\n\n/** The default translate commit: one transform op per id, plus the data-held\n * geometry op when the `geometryProjection` seam is wired. */\nexport function translateOps(session: MoveSession, ids: Iterable<NodeId>, delta: { dx: number; dy: number }): Op[] {\n const ops: Op[] = [];\n for (const id of ids) {\n if (!session.startPoses.has(id) || session.carried.has(id)) continue;\n const node = session.scene.get(id);\n if (!node) continue;\n const l = localDelta(session, id, delta.dx, delta.dy);\n const c = session.caught.get(id);\n if (c) { l.dx += c.dx; l.dy += c.dy; }\n const m: Affine = [1, 0, 0, 1, l.dx, l.dy];\n // The authored pose, not the captured one: a derived node's captured pose\n // is its derivation, and writing that back would lose the placeholder undo\n // restores.\n const authored = node.pose;\n ops.push(createTransformOp<unknown>({\n id: id as string,\n from: authored,\n to: translatePoseViaDescriptor(authored, l.dx, l.dy, session.descriptorOf(id)),\n label: session.lifecycle.label,\n }));\n if (session.geometryProjection) {\n const dataOp = geometryDataOp(\n session.geometryProjection,\n { id: id as string, data: node.data, pose: authored },\n m,\n session.lifecycle.label,\n );\n if (dataOp) ops.push(dataOp);\n }\n }\n return ops;\n}\n\n/** The default translate commit for the dragged roots among `roots` and the\n * descendants that follow them. Anything else in `roots` is ignored. */\nexport function rootTranslateOps(session: MoveSession, roots: Iterable<string>, delta: { dx: number; dy: number }): Op[] {\n const wanted = new Set<string>(roots);\n const others = new Set<NodeId>(session.ids.filter((id) => !wanted.has(id)));\n return translateOps(session, unreleasedIds(session, others), delta);\n}\n\n/** Selected roots no source layout claimed on release, plus the descendants\n * that follow them — the part of the selection the translate commit owns. */\nexport function unreleasedIds(session: MoveSession, released: Set<NodeId>): NodeId[] {\n const selected = new Set<NodeId>(session.ids);\n const out: NodeId[] = session.ids.filter((id) => !released.has(id));\n for (const id of session.cascadeIds) {\n let cur = session.scene.get(id)?.parent ?? null;\n let claimed = false;\n while (cur) {\n if (released.has(cur)) { claimed = true; break; }\n if (selected.has(cur)) break;\n cur = session.scene.get(cur)?.parent ?? null;\n }\n if (!claimed) out.push(id);\n }\n return out;\n}\n"],"mappings":";;;;;AAWA,SAAgBA,EAAa,GAAsB,GAAuB,GAAyC;CACjH,IAAMC,IAAY,CAAC;CACnB,KAAK,IAAMC,KAAMC,GAAK;EACpB,IAAI,CAACC,EAAQ,WAAW,IAAIF,CAAE,KAAKE,EAAQ,QAAQ,IAAIF,CAAE,GAAG;EAC5D,IAAMG,IAAOD,EAAQ,MAAM,IAAIF,CAAE;EACjC,IAAI,CAACG,GAAM;EACX,IAAM,IAAIC,EAAWF,GAASF,GAAIK,EAAM,IAAIA,EAAM,EAAE,GAC9CC,IAAIJ,EAAQ,OAAO,IAAIF,CAAE;EAC/B,AAAIM,MAAK,EAAE,MAAMA,EAAE,IAAI,EAAE,MAAMA,EAAE;EACjC,IAAMC,IAAY;GAAC;GAAG;GAAG;GAAG;GAAG,EAAE;GAAI,EAAE;EAAE,GAInCC,IAAWL,EAAK;EAOtB,IANAJ,EAAI,KAAKU,EAA2B;GAC9B;GACJ,MAAMD;GACN,IAAIE,EAA2BF,GAAU,EAAE,IAAI,EAAE,IAAIN,EAAQ,aAAaF,CAAE,CAAC;GAC7E,OAAOE,EAAQ,UAAU;EAC3B,CAAC,CAAC,GACEA,EAAQ,oBAAoB;GAC9B,IAAMS,IAASC,EACbV,EAAQ,oBACR;IAAM;IAAc,MAAMC,EAAK;IAAM,MAAMK;GAAS,GACpDD,GACAL,EAAQ,UAAU,KACpB;GACA,AAAIS,KAAQZ,EAAI,KAAKY,CAAM;EAC7B;CACF;CACA,OAAOZ;AACT;AAIA,SAAgBc,EAAiB,GAAsB,GAAyB,GAAyC;CACvH,IAAMC,IAAS,IAAI,IAAYC,CAAK;CAEpC,OAAOjB,EAAaI,GAASc,EAAcd,GAAS,IADjC,IAAYA,EAAQ,IAAI,QAAQ,MAAO,CAACY,EAAO,IAAId,CAAE,CAAC,CACrB,CAAM,GAAGK,CAAK;AACpE;AAIA,SAAgBW,EAAc,GAAsB,GAAiC;CACnF,IAAMC,IAAW,IAAI,IAAYf,EAAQ,GAAG,GACtCgB,IAAgBhB,EAAQ,IAAI,QAAQ,MAAO,CAACiB,EAAS,IAAInB,CAAE,CAAC;CAClE,KAAK,IAAMA,KAAME,EAAQ,YAAY;EACnC,IAAIkB,IAAMlB,EAAQ,MAAM,IAAIF,CAAE,CAAC,EAAE,UAAU,MACvCqB,IAAU;EACd,OAAOD,IAAK;GACV,IAAID,EAAS,IAAIC,CAAG,GAAG;IAAE,IAAU;IAAM;GAAO;GAChD,IAAIH,EAAS,IAAIG,CAAG,GAAG;GACvB,IAAMlB,EAAQ,MAAM,IAAIkB,CAAG,CAAC,EAAE,UAAU;EAC1C;EACA,AAAKC,KAASH,EAAI,KAAKlB,CAAE;CAC3B;CACA,OAAOkB;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createOutlines.js","names":["applyCreateOutlines","sel","adapter","converted","id","text","paths","textToPathsByPaint","err","TextOutlinesError","replaced","replaceWithPaths","c"],"sources":["../../../../src/interactions/actions/outlines/createOutlines.ts"],"sourcesContent":["/**\n * Create Outlines: replace each selected text node with path nodes carrying\n * its glyph outlines, giving up editability for geometry — the destructive\n * conversion every vector editor has. One path per paint the text wears; one\n * undoable batch; the replacement takes the text node's slot, so stacking\n * order is unchanged.\n */\nimport type {
|
|
1
|
+
{"version":3,"file":"createOutlines.js","names":["applyCreateOutlines","sel","adapter","converted","id","text","paths","textToPathsByPaint","err","TextOutlinesError","replaced","replaceWithPaths","c"],"sources":["../../../../src/interactions/actions/outlines/createOutlines.ts"],"sourcesContent":["/**\n * Create Outlines: replace each selected text node with path nodes carrying\n * its glyph outlines, giving up editability for geometry — the destructive\n * conversion every vector editor has. One path per paint the text wears; one\n * undoable batch; the replacement takes the text node's slot, so stacking\n * order is unchanged.\n */\nimport type { Affine, Path, Rect } from '@weasel-js/geom';\nimport type { PathPaint } from 'canvas/nodeShapes/nodePaint';\nimport type { Op } from 'core/ops/types';\nimport type { NodeId } from 'core/scene/types';\nimport { textToPathsByPaint, TextOutlinesError, type TextNodeSource } from '@weasel-js/text';\nimport { replaceWithPaths, type PaintedPath } from './replaceWithPaths';\n\n/** What a path minted by an outline action must carry — see\n * {@link CreateOutlinesAdapter.createPathNode}. */\nexport interface OutlinePathSpec extends PathPaint {\n /** The parent the path goes under: the source's own, or the container\n * minted to hold a source's several paths. */\n parent: string | null;\n}\n\n/** What `applyCreateOutlines` and `applyOutlineStroke` read and write through. */\nexport interface CreateOutlinesAdapter {\n getSelection(): readonly NodeId[] | readonly string[];\n /** The text node behind `id`, or `undefined` for anything else. */\n getTextSource(id: NodeId): TextNodeSource | undefined;\n /**\n * Optional: the world-space path of the path node behind `id`, and the\n * paint it wears. Outline Stroke reads both, and passes over a node that\n * lacks either.\n */\n getWorldPath?(id: NodeId): Path | undefined;\n getPaint?(id: NodeId): PathPaint | undefined;\n /**\n * Optional: the frame the node behind `id` draws its stroke in, as the\n * matrix taking that frame to world (`poseFrameOf`); null or absent for a\n * node drawn straight. Outline Stroke skews and stretches a world-width\n * stroke with it. Without it every stroke is outlined in world.\n */\n getStrokeFrame?(id: NodeId): Affine | null | undefined;\n /**\n * Mint one path node of node `sourceId`'s outlines. `path` is in world\n * space. The node must wear `spec`'s fill and stroke — a text whose runs\n * differ in paint gets one path per paint, and a filled node whose stroke\n * is outlined gets one for the fill and one for the stroke — and sit under\n * `spec.parent`. The kit places it; only the consumer knows its data shape,\n * so anything else of the source's `data` worth keeping is the adapter's to\n * copy: onto this path when it stands alone in the source's slot, onto the\n * container when `createContainerNode` minted one.\n */\n createPathNode(path: Path, sourceId: NodeId, spec: OutlinePathSpec): { id: string };\n /**\n * Mint the container that holds one source's several paths, under `parent`.\n * `bounds` is the world envelope of the paths. The kit puts the container in\n * the source's slot and the paths inside it, back to front. Without this,\n * the paths are laid flat in that slot instead.\n */\n createContainerNode?(sourceId: NodeId, spec: { parent: string | null; bounds: Rect }): { id: string };\n /** Full node for `id`, so undo restores the text node whole. */\n getNode(id: string): { id: string } | undefined | null;\n /** The tree: each path is inserted at its source node's index among its\n * parent's children. */\n getParent(id: string): string | null;\n getChildren(parentId: string | null): string[];\n applyOps?(ops: Op[], label?: string): void;\n setSelection?(ids: NodeId[]): void;\n insertNode?(node: { id: string }, index?: number): void;\n removeNode?(id: string): void;\n}\n\n/** Outcome of {@link applyCreateOutlines}. */\nexport type CreateOutlinesResult =\n /** `resultIds` are what replaced the text nodes at their level — a path,\n * a container, or a run of flat paths each — which is also what is now\n * selected in the text nodes' place. */\n | { kind: 'applied'; resultIds: string[] }\n /** Nothing selected is text with ink. */\n | { kind: 'noop'; reason: 'no-text' }\n /** Some selected text has no outline geometry; nothing was changed. */\n | { kind: 'failed'; reason: 'text-outlines'; error: TextOutlinesError };\n\n/**\n * Convert every text node in the selection to outlines, as one batch labeled\n * \"Create Outlines\". Other selected nodes are left alone and stay selected.\n * All or nothing: if any text node's face cannot supply outlines the scene is\n * untouched and the error comes back in the result.\n */\nexport function applyCreateOutlines(adapter: CreateOutlinesAdapter): CreateOutlinesResult {\n const sel = [...adapter.getSelection()] as NodeId[];\n const converted: { id: NodeId; paths: PaintedPath[] }[] = [];\n try {\n for (const id of sel) {\n const text = adapter.getTextSource(id);\n if (!text) continue;\n const paths = textToPathsByPaint(text.data, text.pose);\n if (paths.length > 0) converted.push({ id, paths });\n }\n } catch (err) {\n if (err instanceof TextOutlinesError) return { kind: 'failed', reason: 'text-outlines', error: err };\n throw err;\n }\n if (converted.length === 0) return { kind: 'noop', reason: 'no-text' };\n\n const replaced = replaceWithPaths(adapter, sel, converted, 'Create Outlines');\n return { kind: 'applied', resultIds: converted.flatMap((c) => replaced.get(c.id)!) };\n}\n"],"mappings":";;;AAwFA,SAAgBA,EAAoB,GAAsD;CACxF,IAAMC,IAAM,CAAC,GAAGC,EAAQ,aAAa,CAAC,GAChCC,IAAoD,CAAC;CAC3D,IAAI;EACF,KAAK,IAAMC,KAAMH,GAAK;GACpB,IAAMI,IAAOH,EAAQ,cAAcE,CAAE;GACrC,IAAI,CAACC,GAAM;GACX,IAAMC,IAAQC,EAAmBF,EAAK,MAAMA,EAAK,IAAI;GACrD,AAAIC,EAAM,SAAS,KAAGH,EAAU,KAAK;IAAE;IAAI;GAAM,CAAC;EACpD;CACF,SAASK,GAAK;EACZ,IAAIA,aAAeC,GAAmB,OAAO;GAAE,MAAM;GAAU,QAAQ;GAAiB,OAAOD;EAAI;EACnG,MAAMA;CACR;CACA,IAAIL,EAAU,WAAW,GAAG,OAAO;EAAE,MAAM;EAAQ,QAAQ;CAAU;CAErE,IAAMO,IAAWC,EAAiBT,GAASD,GAAKE,GAAW,iBAAiB;CAC5E,OAAO;EAAE,MAAM;EAAW,WAAWA,EAAU,SAAS,MAAMO,EAAS,IAAIE,EAAE,EAAE,CAAE;CAAE;AACrF"}
|
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
import { unionBounds as e } from "../../../core/geometry/unionBounds.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { dispatchApplyBatch as t } from "../../../core/applyOps.js";
|
|
3
|
+
import { locateChild as n } from "../../../core/ops/slot.js";
|
|
4
|
+
import { createDeleteOp as r } from "../../../core/ops/delete.js";
|
|
5
|
+
import { createInsertOp as i } from "../../../core/ops/create.js";
|
|
6
6
|
import { createSetSelectionOp as a } from "../../../core/ops/select.js";
|
|
7
7
|
import { boundsOfPath as o } from "@weasel-js/geom";
|
|
8
8
|
//#region src/interactions/actions/outlines/replaceWithPaths.ts
|
|
9
9
|
function s(s, l, u, d) {
|
|
10
10
|
let f = [], p = /* @__PURE__ */ new Map(), m = [...u.map((e) => ({
|
|
11
11
|
...e,
|
|
12
|
-
at:
|
|
12
|
+
at: n(s, e.id)
|
|
13
13
|
}))].sort((e, t) => (t.at?.index ?? -1) - (e.at?.index ?? -1));
|
|
14
|
-
for (let { id: t, paths:
|
|
15
|
-
let l = s.getNode
|
|
14
|
+
for (let { id: t, paths: n, at: a } of m) {
|
|
15
|
+
let l = s.getNode(t) ?? { id: t }, u = a?.index ?? -1, d = a?.parentId ?? s.getParent(t), m = (e, t) => i(u >= 0 ? {
|
|
16
16
|
node: e,
|
|
17
17
|
index: u + t
|
|
18
18
|
} : { node: e });
|
|
19
|
-
f.push(
|
|
19
|
+
f.push(r({
|
|
20
20
|
node: l,
|
|
21
21
|
index: u
|
|
22
22
|
}));
|
|
23
|
-
let h =
|
|
23
|
+
let h = n.length > 1 ? s.createContainerNode?.(t, {
|
|
24
24
|
parent: d,
|
|
25
|
-
bounds: e(
|
|
25
|
+
bounds: e(n.map((e) => o(e.path)))
|
|
26
26
|
}) : void 0;
|
|
27
27
|
if (h) {
|
|
28
28
|
f.push(m(h, 0));
|
|
29
|
-
for (let e of
|
|
29
|
+
for (let e of n) f.push(i({ node: s.createPathNode(e.path, t, c(e, h.id)) }));
|
|
30
30
|
p.set(t, [h.id]);
|
|
31
31
|
} else {
|
|
32
|
-
let e =
|
|
32
|
+
let e = n.map((e) => s.createPathNode(e.path, t, c(e, d)));
|
|
33
33
|
e.forEach((e, t) => f.push(m(e, t))), p.set(t, e.map((e) => e.id));
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
return f.push(a({
|
|
37
37
|
from: [...l],
|
|
38
38
|
to: l.flatMap((e) => p.get(e) ?? [e])
|
|
39
|
-
})),
|
|
39
|
+
})), t(s, f, d), p;
|
|
40
40
|
}
|
|
41
41
|
function c(e, t) {
|
|
42
42
|
return e.stroke === void 0 ? {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replaceWithPaths.js","names":["replaceWithPaths","ops","replaced","order","converted","c","locateChild","adapter","b","a","node","id","index","at","parent","place","createInsertOp","created","i","createDeleteOp","container","paths","unionBounds","boundsOfPath","p","specOf","n","createSetSelectionOp","sel","dispatchApplyBatch","label"],"sources":["../../../../src/interactions/actions/outlines/replaceWithPaths.ts"],"sourcesContent":["import { boundsOfPath, type Path } from '@weasel-js/geom';\nimport type { PathPaint } from 'canvas/nodeShapes/nodePaint';\nimport { createInsertOp } from 'core/ops/create';\nimport { createDeleteOp } from 'core/ops/delete';\nimport { createSetSelectionOp } from 'core/ops/select';\nimport { locateChild } from 'core/ops/slot';\nimport { unionBounds } from 'core/geometry/unionBounds';\nimport type { Op } from 'core/ops/types';\nimport type { NodeId } from 'core/scene/types';\nimport { dispatchApplyBatch } from 'core/applyOps';\nimport type { CreateOutlinesAdapter, OutlinePathSpec } from './createOutlines';\n\n/** A world-space path and the paint it is to wear. */\nexport interface PaintedPath extends PathPaint {\n path: Path;\n}\n\n/**\n * Replace each node in `converted` with its `paths`, back to front, as one\n * batch under `label`: in the node's own slot, inside a container when it has\n * several paths and the adapter mints one. The rest of `sel` stays selected.\n * Answers what took each node's place at its level.\n */\nexport function replaceWithPaths(\n adapter: CreateOutlinesAdapter,\n sel: readonly NodeId[],\n converted: readonly { id: NodeId; paths: readonly PaintedPath[] }[],\n label: string,\n): Map<NodeId, string[]> {\n const ops: Op[] = [];\n const replaced = new Map<NodeId, string[]>();\n // Replacements in the same parent are inserted top slot first, so an\n // earlier one widening the sibling list cannot shift a later one's index.\n const located = converted.map((c) => ({ ...c, at: locateChild(adapter, c.id) }));\n const order = [...located].sort((a, b) => (b.at?.index ?? -1) - (a.at?.index ?? -1));\n for (const { id, paths, at } of order) {\n const node = adapter.getNode
|
|
1
|
+
{"version":3,"file":"replaceWithPaths.js","names":["replaceWithPaths","ops","replaced","order","converted","c","locateChild","adapter","b","a","node","id","index","at","parent","place","createInsertOp","created","i","createDeleteOp","container","paths","unionBounds","boundsOfPath","p","specOf","n","createSetSelectionOp","sel","dispatchApplyBatch","label"],"sources":["../../../../src/interactions/actions/outlines/replaceWithPaths.ts"],"sourcesContent":["import { boundsOfPath, type Path } from '@weasel-js/geom';\nimport type { PathPaint } from 'canvas/nodeShapes/nodePaint';\nimport { createInsertOp } from 'core/ops/create';\nimport { createDeleteOp } from 'core/ops/delete';\nimport { createSetSelectionOp } from 'core/ops/select';\nimport { locateChild } from 'core/ops/slot';\nimport { unionBounds } from 'core/geometry/unionBounds';\nimport type { Op } from 'core/ops/types';\nimport type { NodeId } from 'core/scene/types';\nimport { dispatchApplyBatch } from 'core/applyOps';\nimport type { CreateOutlinesAdapter, OutlinePathSpec } from './createOutlines';\n\n/** A world-space path and the paint it is to wear. */\nexport interface PaintedPath extends PathPaint {\n path: Path;\n}\n\n/**\n * Replace each node in `converted` with its `paths`, back to front, as one\n * batch under `label`: in the node's own slot, inside a container when it has\n * several paths and the adapter mints one. The rest of `sel` stays selected.\n * Answers what took each node's place at its level.\n */\nexport function replaceWithPaths(\n adapter: CreateOutlinesAdapter,\n sel: readonly NodeId[],\n converted: readonly { id: NodeId; paths: readonly PaintedPath[] }[],\n label: string,\n): Map<NodeId, string[]> {\n const ops: Op[] = [];\n const replaced = new Map<NodeId, string[]>();\n // Replacements in the same parent are inserted top slot first, so an\n // earlier one widening the sibling list cannot shift a later one's index.\n const located = converted.map((c) => ({ ...c, at: locateChild(adapter, c.id) }));\n const order = [...located].sort((a, b) => (b.at?.index ?? -1) - (a.at?.index ?? -1));\n for (const { id, paths, at } of order) {\n const node = adapter.getNode(id) ?? { id };\n const index = at?.index ?? -1;\n const parent = at?.parentId ?? adapter.getParent(id);\n const place = (created: { id: string }, i: number) =>\n createInsertOp(index >= 0 ? { node: created, index: index + i } : { node: created });\n ops.push(createDeleteOp({ node, index }));\n\n const container = paths.length > 1\n ? adapter.createContainerNode?.(id, { parent, bounds: unionBounds(paths.map((p) => boundsOfPath(p.path)))! })\n : undefined;\n if (container) {\n ops.push(place(container, 0));\n for (const p of paths) {\n ops.push(createInsertOp({ node: adapter.createPathNode(p.path, id, specOf(p, container.id)) }));\n }\n replaced.set(id, [container.id]);\n } else {\n const created = paths.map((p) => adapter.createPathNode(p.path, id, specOf(p, parent)));\n created.forEach((n, i) => ops.push(place(n, i)));\n replaced.set(id, created.map((n) => n.id));\n }\n }\n ops.push(createSetSelectionOp({\n from: [...sel],\n to: sel.flatMap((id) => (replaced.get(id) ?? [id]) as NodeId[]),\n }));\n dispatchApplyBatch(adapter, ops, label);\n return replaced;\n}\n\nfunction specOf(p: PaintedPath, parent: string | null): OutlinePathSpec {\n return p.stroke !== undefined ? { fill: p.fill, stroke: p.stroke, parent } : { fill: p.fill, parent };\n}\n"],"mappings":";;;;;;;;AAuBA,SAAgBA,EACd,GACA,GACA,GACA,GACuB;CACvB,IAAMC,IAAY,CAAC,GACbC,oBAAW,IAAI,IAAsB,GAIrCC,IAAQ,CAAC,GADCC,EAAU,KAAK,OAAO;EAAE,GAAGC;EAAG,IAAIC,EAAYC,GAASF,EAAE,EAAE;CAAE,EAC3D,CAAO,CAAC,CAAC,MAAM,GAAG,OAAOG,EAAE,IAAI,SAAS,OAAOC,EAAE,IAAI,SAAS,GAAG;CACnF,KAAK,IAAM,EAAE,OAAI,UAAO,WAAQN,GAAO;EACrC,IAAMO,IAAOH,EAAQ,QAAQI,CAAE,KAAK,EAAE,MAAG,GACnCC,IAAQC,GAAI,SAAS,IACrBC,IAASD,GAAI,YAAYN,EAAQ,UAAUI,CAAE,GAC7CI,KAAS,GAAyB,MACtCC,EAAeJ,KAAS,IAAI;GAAE,MAAMK;GAAS,OAAOL,IAAQM;EAAE,IAAI,EAAE,MAAMD,EAAQ,CAAC;EACrF,EAAI,KAAKE,EAAe;GAAE;GAAM;EAAM,CAAC,CAAC;EAExC,IAAMC,IAAYC,EAAM,SAAS,IAC7Bd,EAAQ,sBAAsBI,GAAI;GAAE;GAAQ,QAAQW,EAAYD,EAAM,KAAK,MAAME,EAAaC,EAAE,IAAI,CAAC,CAAC;EAAG,CAAC,IAC1G,KAAA;EACJ,IAAIJ,GAAW;GACb,EAAI,KAAKL,EAAMK,GAAW,CAAC,CAAC;GAC5B,KAAK,IAAMI,KAAKH,GACd,EAAI,KAAKL,EAAe,EAAE,MAAMT,EAAQ,eAAeiB,EAAE,MAAMb,GAAIc,EAAOD,GAAGJ,EAAU,EAAE,CAAC,EAAE,CAAC,CAAC;GAEhG,EAAS,IAAIT,GAAI,CAACS,EAAU,EAAE,CAAC;EACjC,OAAO;GACL,IAAMH,IAAUI,EAAM,KAAK,MAAMd,EAAQ,eAAeiB,EAAE,MAAMb,GAAIc,EAAOD,GAAGV,CAAM,CAAC,CAAC;GAEtF,AADAG,EAAQ,SAAS,GAAG,MAAMhB,EAAI,KAAKc,EAAMW,GAAGR,CAAC,CAAC,CAAC,GAC/ChB,EAAS,IAAIS,GAAIM,EAAQ,KAAK,MAAMS,EAAE,EAAE,CAAC;EAC3C;CACF;CAMA,OALAzB,EAAI,KAAK0B,EAAqB;EAC5B,MAAM,CAAC,GAAGC,CAAG;EACb,IAAIA,EAAI,SAAS,MAAQ1B,EAAS,IAAIS,CAAE,KAAK,CAACA,CAAE,CAAc;CAChE,CAAC,CAAC,GACFkB,EAAmBtB,GAASN,GAAK6B,CAAK,GAC/B5B;AACT;AAEA,SAASuB,EAAO,GAAgB,GAAwC;CACtE,OAAOD,EAAE,WAAW,KAAA,IAAyD;EAAE,MAAMA,EAAE;EAAM;CAAO,IAApE;EAAE,MAAMA,EAAE;EAAM,QAAQA,EAAE;EAAQ;CAAO;AAC3E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strokeRegion.js","names":["strokeRegion","tolerance","flattenTolerance","sx","scale","sy","mean","stroke","strokeToPath","path","frame"],"sources":["../../../../src/interactions/actions/outlines/strokeRegion.ts"],"sourcesContent":["import { strokeToPath } from '@weasel-js/stroke';\nimport type {
|
|
1
|
+
{"version":3,"file":"strokeRegion.js","names":["strokeRegion","tolerance","flattenTolerance","sx","scale","sy","mean","stroke","strokeToPath","path","frame"],"sources":["../../../../src/interactions/actions/outlines/strokeRegion.ts"],"sourcesContent":["import { strokeToPath } from '@weasel-js/stroke';\nimport type { Affine, Path, PolygonPath, Scale2 } from '@weasel-js/geom';\nimport type { Stroke } from '@weasel-js/paint';\n\n/** How Outline Stroke and a Boolean operation counting strokes measure one. */\nexport interface StrokeRegionOptions {\n /** The view scale a `{ px }` width resolves against: one number, or the\n * view's own scale per axis. Default 1. */\n scale?: number | Scale2;\n /** Flatness tolerance for curves, in the units of the frame the stroke is\n * drawn in. */\n flattenTolerance?: number;\n}\n\n/**\n * The region `stroke` covers along the world-space `path`, outlined in the\n * frame the canvas draws it in: the screen for a `{ px }` width, so a view\n * that scales its axes apart thins it on one of them, and otherwise `frame`,\n * the node's own (`poseFrameOf`, to world), which skews and stretches the\n * stroke with the node.\n */\nexport function strokeRegion(\n path: Path,\n stroke: Stroke,\n frame: Affine | null | undefined,\n { scale = 1, flattenTolerance }: StrokeRegionOptions = {},\n): PolygonPath {\n const tolerance = flattenTolerance === undefined ? {} : { flattenTolerance };\n const sx = typeof scale === 'number' ? scale : scale.x;\n const sy = typeof scale === 'number' ? scale : scale.y;\n const mean = Math.sqrt(Math.abs(sx * sy));\n if (typeof stroke.width === 'object') {\n if (Math.abs(sx) === Math.abs(sy)) return strokeToPath(path, stroke, { ...tolerance, scale: mean });\n return strokeToPath(path, stroke, { ...tolerance, frame: [1 / sx, 0, 0, 1 / sy, 0, 0] });\n }\n return strokeToPath(path, stroke, { ...tolerance, scale: mean, ...(frame ? { frame } : {}) });\n}\n"],"mappings":";;AAqBA,SAAgBA,EACd,GACA,GACA,GACA,EAAE,WAAQ,GAAG,wBAA0C,CAAC,GAC3C;CACb,IAAMC,IAAYC,MAAqB,KAAA,IAAY,CAAC,IAAI,EAAE,oBAAiB,GACrEC,IAAK,OAAOC,KAAU,WAAWA,IAAQA,EAAM,GAC/CC,IAAK,OAAOD,KAAU,WAAWA,IAAQA,EAAM,GAC/CE,IAAO,KAAK,KAAK,KAAK,IAAIH,IAAKE,CAAE,CAAC;CAKxC,OAJI,OAAOE,EAAO,SAAU,WACtB,KAAK,IAAIJ,CAAE,MAAM,KAAK,IAAIE,CAAE,IAAUG,EAAaC,GAAMF,GAAQ;EAAE,GAAGN;EAAW,OAAOK;CAAK,CAAC,IAC3FE,EAAaC,GAAMF,GAAQ;EAAE,GAAGN;EAAW,OAAO;GAAC,IAAIE;GAAI;GAAG;GAAG,IAAIE;GAAI;GAAG;EAAC;CAAE,CAAC,IAElFG,EAAaC,GAAMF,GAAQ;EAAE,GAAGN;EAAW,OAAOK;EAAM,GAAII,IAAQ,EAAE,SAAM,IAAI,CAAC;CAAG,CAAC;AAC9F"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { commitOps as e, deleteNode as t, insertAt as n, pathCopy as r, reshapeOps as i, selectedPathNodes as a, slotOf as o } from "./pathNodes.js";
|
|
2
|
+
import { anchorsToPath as s, closestOpenEnds as c, joinSubpathEnds as l, pathToAnchors as u } from "@weasel-js/geom";
|
|
3
|
+
import { ActionDisabledReason as d } from "@weasel-js/routing";
|
|
4
|
+
import { snipPathsAtCrossings as f } from "@weasel-js/geom/booleans";
|
|
5
|
+
//#region src/interactions/actions/pathCommands/cutJoin.ts
|
|
6
|
+
var p = "Cut at Crossings", m = "Join", h = {
|
|
7
|
+
id: "snipAtCrossings",
|
|
8
|
+
label: p,
|
|
9
|
+
group: "path",
|
|
10
|
+
eligible: { capability: "creates-shapes" },
|
|
11
|
+
requires: [
|
|
12
|
+
"selection",
|
|
13
|
+
"scene",
|
|
14
|
+
"applyOps"
|
|
15
|
+
],
|
|
16
|
+
invoker: {
|
|
17
|
+
timing: "immediate",
|
|
18
|
+
run: (i) => {
|
|
19
|
+
let s = i.scene, c = a(i);
|
|
20
|
+
if (!s || c.length < 2) return;
|
|
21
|
+
let l = f(c.map((e) => e.path)), u = c.map((e, t) => ({
|
|
22
|
+
node: e,
|
|
23
|
+
pieces: l[t],
|
|
24
|
+
at: o(s, e.id)
|
|
25
|
+
})).filter((e) => e.pieces !== null).sort((e, t) => t.at - e.at);
|
|
26
|
+
if (u.length === 0) return;
|
|
27
|
+
let d = [], m = /* @__PURE__ */ new Map();
|
|
28
|
+
for (let { node: e, pieces: i, at: a } of u) {
|
|
29
|
+
d.push(t(s, e.node, p));
|
|
30
|
+
let o = i.flatMap((t) => r(s, e.node, t) ?? []);
|
|
31
|
+
o.forEach((e, t) => d.push(n(e, a < 0 ? a : a + t, p))), m.set(e.id, o.map((e) => e.id));
|
|
32
|
+
}
|
|
33
|
+
e(i, d, p);
|
|
34
|
+
let h = i.selection?.get() ?? [];
|
|
35
|
+
i.selection?.set(h.flatMap((e) => m.get(e) ?? [e]));
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
enabled: (e) => a(e).length >= 2 || d.SelectionRequired
|
|
39
|
+
};
|
|
40
|
+
function g(e) {
|
|
41
|
+
if (e.length === 0 || e.length > 2) return null;
|
|
42
|
+
let [t, n = null] = e, r = u(t.path), i = n ? (() => {
|
|
43
|
+
let e = u(n.path);
|
|
44
|
+
return {
|
|
45
|
+
anchors: [...r.anchors, ...e.anchors],
|
|
46
|
+
closed: [...r.closed, ...e.closed]
|
|
47
|
+
};
|
|
48
|
+
})() : r, a = r.anchors.length, o = i.anchors.flatMap((e, t) => !i.closed[t] && e.length >= 2 ? [t] : []), d;
|
|
49
|
+
if (!n && o.length === 1) d = l(i, {
|
|
50
|
+
sub: o[0],
|
|
51
|
+
end: "first"
|
|
52
|
+
}, {
|
|
53
|
+
sub: o[0],
|
|
54
|
+
end: "last"
|
|
55
|
+
});
|
|
56
|
+
else {
|
|
57
|
+
let e = c(i, (e, t) => !n || e.sub < a != t.sub < a);
|
|
58
|
+
d = e !== null && l(i, e[0], e[1]);
|
|
59
|
+
}
|
|
60
|
+
return d ? {
|
|
61
|
+
keep: t,
|
|
62
|
+
drop: n,
|
|
63
|
+
path: s(i.anchors, i.closed, t.path)
|
|
64
|
+
} : null;
|
|
65
|
+
}
|
|
66
|
+
var _ = {
|
|
67
|
+
id: "joinPaths",
|
|
68
|
+
label: m,
|
|
69
|
+
group: "path",
|
|
70
|
+
defaultBinding: {
|
|
71
|
+
kind: "key",
|
|
72
|
+
key: "j",
|
|
73
|
+
mods: { mod: !0 }
|
|
74
|
+
},
|
|
75
|
+
eligible: { capability: "creates-shapes" },
|
|
76
|
+
requires: [
|
|
77
|
+
"selection",
|
|
78
|
+
"scene",
|
|
79
|
+
"applyOps",
|
|
80
|
+
"editAnchors"
|
|
81
|
+
],
|
|
82
|
+
invoker: {
|
|
83
|
+
timing: "immediate",
|
|
84
|
+
run: (n) => {
|
|
85
|
+
let r = n.scene;
|
|
86
|
+
if (n.editAnchors?.editingId) return;
|
|
87
|
+
let o = g(a(n));
|
|
88
|
+
if (!r || !o) return;
|
|
89
|
+
let s = i(o.keep.node, o.path, m);
|
|
90
|
+
o.drop && s.push(t(r, o.drop.node, m)), e(n, s, m), n.selection?.set([o.keep.id]);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
enabled: (e) => {
|
|
94
|
+
if (e?.editAnchors?.editingId) return d.NotApplicable;
|
|
95
|
+
let t = a(e);
|
|
96
|
+
return t.length === 0 ? d.SelectionRequired : g(t) ? !0 : d.NotApplicable;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
//#endregion
|
|
100
|
+
export { _ as joinPathsAction, g as planJoin, h as snipAtCrossingsAction };
|
|
101
|
+
|
|
102
|
+
//# sourceMappingURL=cutJoin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cutJoin.js","names":["CUT_LABEL","JOIN_LABEL","snipAtCrossingsAction","scene","deps","nodes","selectedPathNodes","pieces","snipPathsAtCrossings","n","cut","i","slotOf","node","c","b","a","ops","made","runs","deleteNode","copies","pathCopy","p","insertAt","copy","at","k","selected","id","ActionDisabledReason","planJoin","keep","drop","pathToAnchors","set","fromKeep","open","s","sub","joined","joinSubpathEnds","ends","closestOpenEnds","q","anchorsToPath","joinPathsAction","plan","reshapeOps","commitOps"],"sources":["../../../../src/interactions/actions/pathCommands/cutJoin.ts"],"sourcesContent":["/**\n * Cut at Crossings and Join: the path commands that change how many paths\n * there are.\n */\nimport type { Action, ActionDeps, ImmediateInvoker } from '@weasel-js/routing';\nimport { ActionDisabledReason } from '@weasel-js/routing';\nimport {\n anchorsToPath, closestOpenEnds, joinSubpathEnds, pathToAnchors, type AnchorSet, type PolygonPath,\n} from '@weasel-js/geom';\nimport { snipPathsAtCrossings } from '@weasel-js/geom/booleans';\nimport type { Op } from 'core/ops/types';\nimport {\n commitOps, deleteNode, insertAt, pathCopy, reshapeOps, selectedPathNodes, slotOf, type PathNode,\n} from './pathNodes';\n\nconst CUT_LABEL = 'Cut at Crossings';\nconst JOIN_LABEL = 'Join';\n\n/**\n * @experimental Cut every selected path wherever another selected path\n * crosses it (`snipPathsAtCrossings`): each cut path is replaced, in its\n * slot, by its pieces, which take its paint, and the pieces are selected.\n */\nexport const snipAtCrossingsAction: Action & { requires: string[] } = {\n id: 'snipAtCrossings',\n label: CUT_LABEL,\n group: 'path',\n eligible: { capability: 'creates-shapes' },\n requires: ['selection', 'scene', 'applyOps'],\n invoker: {\n timing: 'immediate',\n run: (deps) => {\n const scene = deps.scene;\n const nodes = selectedPathNodes(deps);\n if (!scene || nodes.length < 2) return;\n const pieces = snipPathsAtCrossings(nodes.map((n) => n.path));\n const cut = nodes\n .map((node, i) => ({ node, pieces: pieces[i], at: slotOf(scene, node.id) }))\n .filter((c): c is { node: PathNode; pieces: PolygonPath[]; at: number } => c.pieces !== null)\n .sort((a, b) => b.at - a.at);\n if (cut.length === 0) return;\n const ops: Op[] = [];\n const made = new Map<string, string[]>();\n for (const { node, pieces: runs, at } of cut) {\n ops.push(deleteNode(scene, node.node, CUT_LABEL));\n const copies = runs.flatMap((p) => pathCopy(scene, node.node, p) ?? []);\n copies.forEach((copy, k) => ops.push(insertAt(copy, at < 0 ? at : at + k, CUT_LABEL)));\n made.set(node.id, copies.map((c) => c.id));\n }\n commitOps(deps, ops, CUT_LABEL);\n const selected = deps.selection?.get() ?? [];\n deps.selection?.set(selected.flatMap((id) => made.get(id) ?? [id]) as never);\n },\n } satisfies ImmediateInvoker,\n enabled: (deps) => (selectedPathNodes(deps).length >= 2 ? true : ActionDisabledReason.SelectionRequired),\n};\n\n/** What Join would do to the selection, or null when it cannot. */\ninterface JoinPlan {\n keep: PathNode;\n drop: PathNode | null;\n path: PolygonPath;\n}\n\n/**\n * One selected path: close its one open subpath, or join the two nearest\n * ends of its open subpaths. Two: join the nearest pair of open ends, one on\n * each, into the first selected, which takes in the second's other subpaths.\n */\nexport function planJoin(nodes: readonly PathNode[]): JoinPlan | null {\n if (nodes.length === 0 || nodes.length > 2) return null;\n const [keep, drop = null] = nodes;\n const a = pathToAnchors(keep.path) as AnchorSet;\n const set: AnchorSet = drop\n ? (() => {\n const b = pathToAnchors(drop.path);\n return { anchors: [...a.anchors, ...b.anchors], closed: [...a.closed, ...b.closed] };\n })()\n : a;\n const fromKeep = a.anchors.length;\n const open = set.anchors.flatMap((sub, s) => (!set.closed[s] && sub.length >= 2 ? [s] : []));\n let joined: boolean;\n if (!drop && open.length === 1) {\n joined = joinSubpathEnds(set, { sub: open[0], end: 'first' }, { sub: open[0], end: 'last' });\n } else {\n const ends = closestOpenEnds(set, (p, q) => !drop || (p.sub < fromKeep) !== (q.sub < fromKeep));\n joined = ends !== null && joinSubpathEnds(set, ends[0], ends[1]);\n }\n if (!joined) return null;\n return { keep, drop, path: anchorsToPath(set.anchors, set.closed, keep.path) };\n}\n\n/**\n * @experimental Join open paths: close a selected path's open end to its\n * start, or connect two selected paths at their nearest open ends into one\n * (`planJoin`). Ends that meet merge into one anchor; ends apart are bridged\n * straight. In path edit, `joinAnchors` joins the two selected anchors\n * instead.\n */\nexport const joinPathsAction: Action & { requires: string[] } = {\n id: 'joinPaths',\n label: JOIN_LABEL,\n group: 'path',\n defaultBinding: { kind: 'key', key: 'j', mods: { mod: true } },\n eligible: { capability: 'creates-shapes' },\n requires: ['selection', 'scene', 'applyOps', 'editAnchors'],\n invoker: {\n timing: 'immediate',\n run: (deps) => {\n const scene = deps.scene;\n if (deps.editAnchors?.editingId) return;\n const plan = planJoin(selectedPathNodes(deps));\n if (!scene || !plan) return;\n const ops = reshapeOps(plan.keep.node, plan.path, JOIN_LABEL);\n if (plan.drop) ops.push(deleteNode(scene, plan.drop.node, JOIN_LABEL));\n commitOps(deps, ops, JOIN_LABEL);\n deps.selection?.set([plan.keep.id] as never);\n },\n } satisfies ImmediateInvoker,\n enabled: (deps?: ActionDeps) => {\n // In path edit Join is the selected anchors' (`joinAnchors`).\n if (deps?.editAnchors?.editingId) return ActionDisabledReason.NotApplicable;\n const nodes = selectedPathNodes(deps);\n if (nodes.length === 0) return ActionDisabledReason.SelectionRequired;\n return planJoin(nodes) ? true : ActionDisabledReason.NotApplicable;\n },\n};\n"],"mappings":";;;;;AAeA,IAAMA,IAAY,oBACZC,IAAa,QAONC,IAAyD;CACpE,IAAI;CACJ,OAAOF;CACP,OAAO;CACP,UAAU,EAAE,YAAY,iBAAiB;CACzC,UAAU;EAAC;EAAa;EAAS;CAAU;CAC3C,SAAS;EACP,QAAQ;EACR,MAAM,MAAS;GACb,IAAMG,IAAQC,EAAK,OACbC,IAAQC,EAAkBF,CAAI;GACpC,IAAI,CAACD,KAASE,EAAM,SAAS,GAAG;GAChC,IAAME,IAASC,EAAqBH,EAAM,KAAK,MAAMI,EAAE,IAAI,CAAC,GACtDC,IAAML,EACT,KAAK,GAAM,OAAO;IAAE;IAAM,QAAQE,EAAOI;IAAI,IAAIC,EAAOT,GAAOU,EAAK,EAAE;GAAE,EAAE,CAAC,CAC3E,QAAQ,MAAkEC,EAAE,WAAW,IAAI,CAAC,CAC5F,MAAM,GAAG,MAAMC,EAAE,KAAKC,EAAE,EAAE;GAC7B,IAAIN,EAAI,WAAW,GAAG;GACtB,IAAMO,IAAY,CAAC,GACbC,oBAAO,IAAI,IAAsB;GACvC,KAAK,IAAM,EAAE,SAAM,QAAQC,GAAM,WAAQT,GAAK;IAC5C,EAAI,KAAKU,EAAWjB,GAAOU,EAAK,MAAMb,CAAS,CAAC;IAChD,IAAMqB,IAASF,EAAK,SAAS,MAAMG,EAASnB,GAAOU,EAAK,MAAMU,CAAC,KAAK,CAAC,CAAC;IAEtE,AADAF,EAAO,SAAS,GAAM,MAAMJ,EAAI,KAAKO,EAASC,GAAMC,IAAK,IAAIA,IAAKA,IAAKC,GAAG3B,CAAS,CAAC,CAAC,GACrFkB,EAAK,IAAIL,EAAK,IAAIQ,EAAO,KAAK,MAAMP,EAAE,EAAE,CAAC;GAC3C;GACA,EAAUV,GAAMa,GAAKjB,CAAS;GAC9B,IAAM4B,IAAWxB,EAAK,WAAW,IAAI,KAAK,CAAC;GAC3C,EAAK,WAAW,IAAIwB,EAAS,SAAS,MAAOV,EAAK,IAAIW,CAAE,KAAK,CAACA,CAAE,CAAC,CAAU;EAC7E;CACF;CACA,UAAU,MAAUvB,EAAkBF,CAAI,CAAC,CAAC,UAAU,KAAW0B,EAAqB;AACxF;AAcA,SAAgBC,EAAS,GAA6C;CACpE,IAAI1B,EAAM,WAAW,KAAKA,EAAM,SAAS,GAAG,OAAO;CACnD,IAAM,CAAC2B,GAAMC,IAAO,QAAQ5B,GACtBW,IAAIkB,EAAcF,EAAK,IAAI,GAC3BG,IAAiBF,WACZ;EACP,IAAMlB,IAAImB,EAAcD,EAAK,IAAI;EACjC,OAAO;GAAE,SAAS,CAAC,GAAGjB,EAAE,SAAS,GAAGD,EAAE,OAAO;GAAG,QAAQ,CAAC,GAAGC,EAAE,QAAQ,GAAGD,EAAE,MAAM;EAAE;CACrF,EAAA,CAAG,IACDC,GACEoB,IAAWpB,EAAE,QAAQ,QACrBqB,IAAOF,EAAI,QAAQ,SAAS,GAAK,MAAO,CAACA,EAAI,OAAOG,MAAMC,EAAI,UAAU,IAAI,CAACD,CAAC,IAAI,CAAC,CAAE,GACvFE;CACJ,IAAI,CAACP,KAAQI,EAAK,WAAW,GAC3B,IAASI,EAAgBN,GAAK;EAAE,KAAKE,EAAK;EAAI,KAAK;CAAQ,GAAG;EAAE,KAAKA,EAAK;EAAI,KAAK;CAAO,CAAC;MACtF;EACL,IAAMK,IAAOC,EAAgBR,IAAM,GAAG,MAAM,CAACF,KAASV,EAAE,MAAMa,KAAeQ,EAAE,MAAMR,CAAS;EAC9F,IAASM,MAAS,QAAQD,EAAgBN,GAAKO,EAAK,IAAIA,EAAK,EAAE;CACjE;CAEA,OADKF,IACE;EAAE;EAAM;EAAM,MAAMK,EAAcV,EAAI,SAASA,EAAI,QAAQH,EAAK,IAAI;CAAE,IADzD;AAEtB;AASA,IAAac,IAAmD;CAC9D,IAAI;CACJ,OAAO7C;CACP,OAAO;CACP,gBAAgB;EAAE,MAAM;EAAO,KAAK;EAAK,MAAM,EAAE,KAAK,GAAK;CAAE;CAC7D,UAAU,EAAE,YAAY,iBAAiB;CACzC,UAAU;EAAC;EAAa;EAAS;EAAY;CAAa;CAC1D,SAAS;EACP,QAAQ;EACR,MAAM,MAAS;GACb,IAAME,IAAQC,EAAK;GACnB,IAAIA,EAAK,aAAa,WAAW;GACjC,IAAM2C,IAAOhB,EAASzB,EAAkBF,CAAI,CAAC;GAC7C,IAAI,CAACD,KAAS,CAAC4C,GAAM;GACrB,IAAM9B,IAAM+B,EAAWD,EAAK,KAAK,MAAMA,EAAK,MAAM9C,CAAU;GAG5D,AAFI8C,EAAK,QAAM9B,EAAI,KAAKG,EAAWjB,GAAO4C,EAAK,KAAK,MAAM9C,CAAU,CAAC,GACrEgD,EAAU7C,GAAMa,GAAKhB,CAAU,GAC/BG,EAAK,WAAW,IAAI,CAAC2C,EAAK,KAAK,EAAE,CAAU;EAC7C;CACF;CACA,UAAU,MAAsB;EAE9B,IAAI3C,GAAM,aAAa,WAAW,OAAO0B,EAAqB;EAC9D,IAAMzB,IAAQC,EAAkBF,CAAI;EAEpC,OADIC,EAAM,WAAW,IAAUyB,EAAqB,oBAC7CC,EAAS1B,CAAK,IAAI,KAAOyB,EAAqB;CACvD;AACF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { commitOps as e, selectedPathNodes as t, withPath as n } from "./pathNodes.js";
|
|
2
|
+
import { ActionDisabledReason as r } from "@weasel-js/routing";
|
|
3
|
+
//#region src/interactions/actions/pathCommands/livePathEdit.ts
|
|
4
|
+
function i(i) {
|
|
5
|
+
return {
|
|
6
|
+
id: i.id,
|
|
7
|
+
label: i.label,
|
|
8
|
+
eligible: { capability: "creates-shapes" },
|
|
9
|
+
requires: [
|
|
10
|
+
"selection",
|
|
11
|
+
"scene",
|
|
12
|
+
"applyOps"
|
|
13
|
+
],
|
|
14
|
+
invoker: {
|
|
15
|
+
timing: "ongoing",
|
|
16
|
+
start(r, a) {
|
|
17
|
+
let o = t(r.deps);
|
|
18
|
+
if (o.length === 0) return {};
|
|
19
|
+
let s = (e) => {
|
|
20
|
+
let t = e?.[i.param];
|
|
21
|
+
return typeof t == "number" && Number.isFinite(t) ? t : null;
|
|
22
|
+
}, c = s(r.params) ?? s(a?.params) ?? i.initial, l = /* @__PURE__ */ new Map(), u = () => {
|
|
23
|
+
l = /* @__PURE__ */ new Map();
|
|
24
|
+
for (let e of o) {
|
|
25
|
+
let t = i.edit(e, c);
|
|
26
|
+
t && l.set(e.id, {
|
|
27
|
+
node: e,
|
|
28
|
+
path: t
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
u();
|
|
33
|
+
let d = (e) => {
|
|
34
|
+
let t = l.get(e);
|
|
35
|
+
return t ? n(t.node.node, t.path) : null;
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
kind: i.id,
|
|
39
|
+
onMove(e) {
|
|
40
|
+
let t = s(e.params);
|
|
41
|
+
t !== null && t !== c && (c = t, u());
|
|
42
|
+
},
|
|
43
|
+
onEnd(t, n) {
|
|
44
|
+
let r = l;
|
|
45
|
+
if (l = /* @__PURE__ */ new Map(), n === "cancel" || r.size === 0) return;
|
|
46
|
+
let a = i.commit(t.deps, r, c);
|
|
47
|
+
e(t.deps, a, i.label);
|
|
48
|
+
let o = i.selectAfter?.(a);
|
|
49
|
+
o && t.deps.selection?.set(o);
|
|
50
|
+
},
|
|
51
|
+
previewIds: () => l.size > 0 ? [...l.keys()] : null,
|
|
52
|
+
previewPose: (e) => d(e)?.pose ?? null,
|
|
53
|
+
previewData: (e) => d(e)?.data ?? null,
|
|
54
|
+
...i.overlaysSource ? { previewHidesSource: !1 } : {}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
enabled: (e) => t(e).length > 0 || r.SelectionRequired
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
export { i as livePathEdit };
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=livePathEdit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"livePathEdit.js","names":["livePathEdit","spec","nodes","selectedPathNodes","ctx","read","v","params","value","opts","current","recompute","node","path","shapeOf","entry","id","withPath","next","moveCtx","done","reason","ops","endCtx","after","deps","ActionDisabledReason"],"sources":["../../../../src/interactions/actions/pathCommands/livePathEdit.ts"],"sourcesContent":["import type { Action, BindingOpts, InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport { ActionDisabledReason } from '@weasel-js/routing';\nimport type { PolygonPath } from '@weasel-js/geom';\nimport type { Op } from 'core/ops/types';\nimport { commitOps, selectedPathNodes, withPath, type AnyNode, type PathNode } from './pathNodes';\n\n/** What one live path command does with its parameter. */\nexport interface LivePathEditSpec {\n id: string;\n label: string;\n /** The param the UI drives, and its value when none is given. */\n param: string;\n initial: number;\n /** The geometry `node` takes at `value`, or null for none. */\n edit(node: PathNode, value: number): PolygonPath | null;\n /** The ops committing `next`, made at `value`, for the edited nodes. */\n commit(deps: InvocationCtx['deps'], next: ReadonlyMap<string, { node: PathNode; path: PolygonPath }>, value: number): Op[];\n /** Ids to select after the commit; the selection stands when absent. */\n selectAfter?(ops: Op[]): string[];\n /** Whether the preview draws over the source, which stays in view. */\n overlaysSource?: boolean;\n}\n\n/**\n * An ongoing action over the selected path nodes driven by one number — a\n * slider's tolerance or distance. `begin` with the param shows the result as\n * a preview; each update recomputes it; committing writes it as one undo\n * entry, and canceling leaves the scene untouched.\n */\nexport function livePathEdit(spec: LivePathEditSpec): Action & { requires: string[] } {\n return {\n id: spec.id,\n label: spec.label,\n eligible: { capability: 'creates-shapes' },\n requires: ['selection', 'scene', 'applyOps'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts?: BindingOpts): OngoingHandle {\n const nodes = selectedPathNodes(ctx.deps);\n if (nodes.length === 0) return {};\n const read = (params: Record<string, unknown> | undefined): number | null => {\n const v = params?.[spec.param];\n return typeof v === 'number' && Number.isFinite(v) ? v : null;\n };\n let value = read(ctx.params) ?? read(opts?.params as Record<string, unknown> | undefined) ?? spec.initial;\n let current = new Map<string, { node: PathNode; path: PolygonPath }>();\n const recompute = () => {\n current = new Map();\n for (const node of nodes) {\n const path = spec.edit(node, value);\n if (path) current.set(node.id, { node, path });\n }\n };\n recompute();\n const shapeOf = (id: string) => {\n const entry = current.get(id);\n return entry ? withPath(entry.node.node as AnyNode, entry.path) : null;\n };\n return {\n kind: spec.id,\n onMove(moveCtx: InvocationCtx): void {\n const next = read(moveCtx.params);\n if (next === null || next === value) return;\n value = next;\n recompute();\n },\n onEnd(endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n const done = current;\n current = new Map();\n if (reason === 'cancel' || done.size === 0) return;\n const ops = spec.commit(endCtx.deps, done, value);\n commitOps(endCtx.deps, ops, spec.label);\n const after = spec.selectAfter?.(ops);\n if (after) endCtx.deps.selection?.set(after as never);\n },\n previewIds: () => (current.size > 0 ? [...current.keys()] : null),\n previewPose: (id: string) => shapeOf(id)?.pose ?? null,\n previewData: (id: string) => shapeOf(id)?.data ?? null,\n ...(spec.overlaysSource ? { previewHidesSource: false } : {}),\n };\n },\n },\n enabled: (deps) => (selectedPathNodes(deps).length > 0 ? true : ActionDisabledReason.SelectionRequired),\n };\n}\n"],"mappings":";;;AA6BA,SAAgBA,EAAa,GAAyD;CACpF,OAAO;EACL,IAAIC,EAAK;EACT,OAAOA,EAAK;EACZ,UAAU,EAAE,YAAY,iBAAiB;EACzC,UAAU;GAAC;GAAa;GAAS;EAAU;EAC3C,SAAS;GACP,QAAQ;GACR,MAAM,GAAoB,GAAmC;IAC3D,IAAMC,IAAQC,EAAkBC,EAAI,IAAI;IACxC,IAAIF,EAAM,WAAW,GAAG,OAAO,CAAC;IAChC,IAAMG,KAAQ,MAA+D;KAC3E,IAAMC,IAAIC,IAASN,EAAK;KACxB,OAAO,OAAOK,KAAM,YAAY,OAAO,SAASA,CAAC,IAAIA,IAAI;IAC3D,GACIE,IAAQH,EAAKD,EAAI,MAAM,KAAKC,EAAKI,GAAM,MAA6C,KAAKR,EAAK,SAC9FS,oBAAU,IAAI,IAAmD,GAC/DC,UAAkB;KACtB,oBAAU,IAAI,IAAI;KAClB,KAAK,IAAMC,KAAQV,GAAO;MACxB,IAAMW,IAAOZ,EAAK,KAAKW,GAAMJ,CAAK;MAClC,AAAIK,KAAMH,EAAQ,IAAIE,EAAK,IAAI;OAAE;OAAM;MAAK,CAAC;KAC/C;IACF;IACA,EAAU;IACV,IAAME,KAAW,MAAe;KAC9B,IAAMC,IAAQL,EAAQ,IAAIM,CAAE;KAC5B,OAAOD,IAAQE,EAASF,EAAM,KAAK,MAAiBA,EAAM,IAAI,IAAI;IACpE;IACA,OAAO;KACL,MAAMd,EAAK;KACX,OAAO,GAA8B;MACnC,IAAMiB,IAAOb,EAAKc,EAAQ,MAAM;MAChC,AAAID,MAAS,QAAQA,MAASV,MAC9B,IAAQU,GACRP,EAAU;KACZ;KACA,MAAM,GAAuB,GAAmC;MAC9D,IAAMS,IAAOV;MAEb,IADA,oBAAU,IAAI,IAAI,GACdW,MAAW,YAAYD,EAAK,SAAS,GAAG;MAC5C,IAAME,IAAMrB,EAAK,OAAOsB,EAAO,MAAMH,GAAMZ,CAAK;MAChD,EAAUe,EAAO,MAAMD,GAAKrB,EAAK,KAAK;MACtC,IAAMuB,IAAQvB,EAAK,cAAcqB,CAAG;MACpC,AAAIE,KAAOD,EAAO,KAAK,WAAW,IAAIC,CAAc;KACtD;KACA,kBAAmBd,EAAQ,OAAO,IAAI,CAAC,GAAGA,EAAQ,KAAK,CAAC,IAAI;KAC5D,cAAc,MAAeI,EAAQE,CAAE,CAAC,EAAE,QAAQ;KAClD,cAAc,MAAeF,EAAQE,CAAE,CAAC,EAAE,QAAQ;KAClD,GAAIf,EAAK,iBAAiB,EAAE,oBAAoB,GAAM,IAAI,CAAC;IAC7D;GACF;EACF;EACA,UAAU,MAAUE,EAAkBsB,CAAI,CAAC,CAAC,SAAS,KAAWC,EAAqB;CACvF;AACF"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { createTransformOp as e } from "../../../core/ops/transform.js";
|
|
2
|
+
import { createSetDataOp as t } from "../../../core/ops/setData.js";
|
|
3
|
+
import { defaultCommitAdapter as n } from "../defaultCommitAdapter.js";
|
|
4
|
+
import { createDeleteOp as r } from "../../../core/ops/delete.js";
|
|
5
|
+
import { createInsertOp as i } from "../../../core/ops/create.js";
|
|
6
|
+
import { resolveEditablePathOf as a, storeEditablePath as o } from "../../../features/paths/editablePath.js";
|
|
7
|
+
import { withoutShapeGenerator as s } from "../../../features/paths/shapeGenerator.js";
|
|
8
|
+
//#region src/interactions/actions/pathCommands/pathNodes.ts
|
|
9
|
+
function c(e) {
|
|
10
|
+
let t = e?.scene, n = e?.selection?.get() ?? [];
|
|
11
|
+
if (!t) return [];
|
|
12
|
+
let r = [];
|
|
13
|
+
for (let e of n) {
|
|
14
|
+
let n = t.get(e);
|
|
15
|
+
if (!n || n.kind !== "leaf") continue;
|
|
16
|
+
let i = a(n);
|
|
17
|
+
i && r.push({
|
|
18
|
+
id: e,
|
|
19
|
+
node: n,
|
|
20
|
+
path: i
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return r;
|
|
24
|
+
}
|
|
25
|
+
function l(e, t) {
|
|
26
|
+
let n = o(e, t);
|
|
27
|
+
if (!n) return null;
|
|
28
|
+
let r = s(n.data);
|
|
29
|
+
if (r && typeof r == "object" && "skin" in r) {
|
|
30
|
+
let { skin: e, ...t } = r;
|
|
31
|
+
return {
|
|
32
|
+
pose: n.pose,
|
|
33
|
+
data: t
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
pose: n.pose,
|
|
38
|
+
data: r
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function u(n, r, i) {
|
|
42
|
+
let a = l(n, r);
|
|
43
|
+
if (!a) return [];
|
|
44
|
+
let o = [];
|
|
45
|
+
return a.pose !== n.pose && o.push(e({
|
|
46
|
+
id: n.id,
|
|
47
|
+
from: n.pose,
|
|
48
|
+
to: a.pose,
|
|
49
|
+
label: i
|
|
50
|
+
})), a.data !== n.data && o.push(t({
|
|
51
|
+
id: n.id,
|
|
52
|
+
from: n.data,
|
|
53
|
+
to: a.data,
|
|
54
|
+
label: i
|
|
55
|
+
})), o;
|
|
56
|
+
}
|
|
57
|
+
function d(e, t, n) {
|
|
58
|
+
let r = l(t, n);
|
|
59
|
+
return r ? {
|
|
60
|
+
...t,
|
|
61
|
+
id: e.mintId(),
|
|
62
|
+
pose: r.pose,
|
|
63
|
+
data: r.data
|
|
64
|
+
} : null;
|
|
65
|
+
}
|
|
66
|
+
function f(e, t) {
|
|
67
|
+
let n = e.get(t)?.parent ?? null;
|
|
68
|
+
return (n === null ? e.roots : e.childrenOf(n)).indexOf(t);
|
|
69
|
+
}
|
|
70
|
+
function p(e, t, n) {
|
|
71
|
+
return i(t >= 0 ? {
|
|
72
|
+
node: e,
|
|
73
|
+
index: t,
|
|
74
|
+
label: n
|
|
75
|
+
} : {
|
|
76
|
+
node: e,
|
|
77
|
+
label: n
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function m(e, t, n) {
|
|
81
|
+
return r({
|
|
82
|
+
node: t,
|
|
83
|
+
index: f(e, t.id),
|
|
84
|
+
label: n
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function h(e, t, r) {
|
|
88
|
+
if (t.length === 0) return;
|
|
89
|
+
if (e.applyOps) {
|
|
90
|
+
e.applyOps(t, r);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
let i = e.scene;
|
|
94
|
+
i && i.applyBatch(t, r, n(i, e.selection?.adapterMethods));
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
export { h as commitOps, m as deleteNode, p as insertAt, d as pathCopy, u as reshapeOps, c as selectedPathNodes, f as slotOf, l as withPath };
|
|
98
|
+
|
|
99
|
+
//# sourceMappingURL=pathNodes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathNodes.js","names":["selectedPathNodes","scene","deps","ids","out","id","node","path","resolveEditablePathOf","withPath","stored","storeEditablePath","worldPath","data","withoutShapeGenerator","_orphaned","rest","reshapeOps","next","ops","createTransformOp","createSetDataOp","pathCopy","slotOf","parent","insertAt","createInsertOp","index","deleteNode","createDeleteOp","commitOps","label","defaultCommitAdapter"],"sources":["../../../../src/interactions/actions/pathCommands/pathNodes.ts"],"sourcesContent":["/**\n * What the path commands share: reading the selected path nodes, and writing\n * new geometry back into a node or into a copy of one. A node's geometry is\n * stored where it already lives (`storeEditablePath`); a skin, whose weights\n * follow anchors the new geometry no longer has, is dropped, and so is a\n * shape generator, which no longer makes it.\n */\nimport type { ActionDeps } from '@weasel-js/routing';\nimport type { PolygonPath } from '@weasel-js/geom';\nimport type { Node, NodeId, Scene } from 'core/scene/types';\nimport type { Op } from 'core/ops/types';\nimport { createTransformOp } from 'core/ops/transform';\nimport { createSetDataOp } from 'core/ops/setData';\nimport { createInsertOp } from 'core/ops/create';\nimport { createDeleteOp } from 'core/ops/delete';\nimport { resolveEditablePathOf, storeEditablePath } from 'features/paths/editablePath';\nimport { withoutShapeGenerator } from 'features/paths/shapeGenerator';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\n\ntype AnyScene = Scene<unknown, string, unknown>;\nexport type AnyNode = Node<unknown, string, unknown>;\n\n/** A selected node with an editable polygon, and that polygon in world space. */\nexport interface PathNode {\n id: NodeId;\n node: AnyNode;\n path: PolygonPath;\n}\n\n/** The selected leaves that hold an editable polygon, in selection order. */\nexport function selectedPathNodes(deps: ActionDeps | undefined): PathNode[] {\n const scene = deps?.scene as AnyScene | undefined;\n const ids = deps?.selection?.get() ?? [];\n if (!scene) return [];\n const out: PathNode[] = [];\n for (const id of ids) {\n const node = scene.get(id as NodeId);\n if (!node || node.kind !== 'leaf') continue;\n const path = resolveEditablePathOf(node);\n if (path) out.push({ id: id as NodeId, node, path });\n }\n return out;\n}\n\n/** `node` storing `worldPath`, or null when it holds no editable polygon. */\nexport function withPath(node: AnyNode, worldPath: PolygonPath): { pose: unknown; data: unknown } | null {\n const stored = storeEditablePath(node, worldPath);\n if (!stored) return null;\n const data = withoutShapeGenerator(stored.data) as { skin?: unknown } | null;\n if (data && typeof data === 'object' && 'skin' in data) {\n const { skin: _orphaned, ...rest } = data;\n void _orphaned;\n return { pose: stored.pose, data: rest };\n }\n return { pose: stored.pose, data };\n}\n\n/** The ops that give `node` the geometry `worldPath`, labeled `label`. */\nexport function reshapeOps(node: AnyNode, worldPath: PolygonPath, label: string): Op[] {\n const next = withPath(node, worldPath);\n if (!next) return [];\n const ops: Op[] = [];\n if (next.pose !== node.pose) ops.push(createTransformOp({ id: node.id, from: node.pose, to: next.pose, label }));\n if (next.data !== node.data) ops.push(createSetDataOp({ id: node.id, from: node.data, to: next.data, label }));\n return ops;\n}\n\n/** A copy of `node` under a fresh id, holding `worldPath`. */\nexport function pathCopy(scene: AnyScene, node: AnyNode, worldPath: PolygonPath): AnyNode | null {\n const next = withPath(node, worldPath);\n if (!next) return null;\n return { ...node, id: scene.mintId(), pose: next.pose, data: next.data } as AnyNode;\n}\n\n/** Where `id` sits among its siblings, back to front. */\nexport function slotOf(scene: AnyScene, id: NodeId): number {\n const parent = scene.get(id)?.parent ?? null;\n const siblings = parent === null ? scene.roots : scene.childrenOf(parent);\n return siblings.indexOf(id);\n}\n\n/** Insert `node` at `index` among its parent's children. */\nexport function insertAt(node: AnyNode, index: number, label: string): Op {\n return createInsertOp(index >= 0 ? { node, index, label } : { node, label });\n}\n\n/** Delete `node`, remembering its slot for undo. */\nexport function deleteNode(scene: AnyScene, node: AnyNode, label: string): Op {\n return createDeleteOp({ node, index: slotOf(scene, node.id), label });\n}\n\n/** Commit `ops` as one undo entry, through the consumer's `applyOps` when\n * there is one. */\nexport function commitOps(deps: ActionDeps, ops: Op[], label: string): void {\n if (ops.length === 0) return;\n if (deps.applyOps) {\n deps.applyOps(ops, label);\n return;\n }\n const scene = deps.scene as AnyScene | undefined;\n if (!scene) return;\n scene.applyBatch(ops, label, defaultCommitAdapter(scene, deps.selection?.adapterMethods));\n}\n"],"mappings":";;;;;;;;AA8BA,SAAgBA,EAAkB,GAA0C;CAC1E,IAAMC,IAAQC,GAAM,OACdC,IAAMD,GAAM,WAAW,IAAI,KAAK,CAAC;CACvC,IAAI,CAACD,GAAO,OAAO,CAAC;CACpB,IAAMG,IAAkB,CAAC;CACzB,KAAK,IAAMC,KAAMF,GAAK;EACpB,IAAMG,IAAOL,EAAM,IAAII,CAAY;EACnC,IAAI,CAACC,KAAQA,EAAK,SAAS,QAAQ;EACnC,IAAMC,IAAOC,EAAsBF,CAAI;EACvC,AAAIC,KAAMH,EAAI,KAAK;GAAM;GAAc;GAAM;EAAK,CAAC;CACrD;CACA,OAAOA;AACT;AAGA,SAAgBK,EAAS,GAAe,GAAiE;CACvG,IAAMC,IAASC,EAAkBL,GAAMM,CAAS;CAChD,IAAI,CAACF,GAAQ,OAAO;CACpB,IAAMG,IAAOC,EAAsBJ,EAAO,IAAI;CAC9C,IAAIG,KAAQ,OAAOA,KAAS,YAAY,UAAUA,GAAM;EACtD,IAAM,EAAE,MAAME,GAAW,GAAGC,MAASH;EAErC,OAAO;GAAE,MAAMH,EAAO;GAAM,MAAMM;EAAK;CACzC;CACA,OAAO;EAAE,MAAMN,EAAO;EAAM;CAAK;AACnC;AAGA,SAAgBO,EAAW,GAAe,GAAwB,GAAqB;CACrF,IAAMC,IAAOT,EAASH,GAAMM,CAAS;CACrC,IAAI,CAACM,GAAM,OAAO,CAAC;CACnB,IAAMC,IAAY,CAAC;CAGnB,OAFID,EAAK,SAASZ,EAAK,QAAMa,EAAI,KAAKC,EAAkB;EAAE,IAAId,EAAK;EAAI,MAAMA,EAAK;EAAM,IAAIY,EAAK;EAAM;CAAM,CAAC,CAAC,GAC3GA,EAAK,SAASZ,EAAK,QAAMa,EAAI,KAAKE,EAAgB;EAAE,IAAIf,EAAK;EAAI,MAAMA,EAAK;EAAM,IAAIY,EAAK;EAAM;CAAM,CAAC,CAAC,GACtGC;AACT;AAGA,SAAgBG,EAAS,GAAiB,GAAe,GAAwC;CAC/F,IAAMJ,IAAOT,EAASH,GAAMM,CAAS;CAErC,OADKM,IACE;EAAE,GAAGZ;EAAM,IAAIL,EAAM,OAAO;EAAG,MAAMiB,EAAK;EAAM,MAAMA,EAAK;CAAK,IADrD;AAEpB;AAGA,SAAgBK,EAAO,GAAiB,GAAoB;CAC1D,IAAMC,IAASvB,EAAM,IAAII,CAAE,CAAC,EAAE,UAAU;CAExC,QADiBmB,MAAW,OAAOvB,EAAM,QAAQA,EAAM,WAAWuB,CAAM,EAAA,CACxD,QAAQnB,CAAE;AAC5B;AAGA,SAAgBoB,EAAS,GAAe,GAAe,GAAmB;CACxE,OAAOC,EAAeC,KAAS,IAAI;EAAE;EAAM;EAAO;CAAM,IAAI;EAAE;EAAM;CAAM,CAAC;AAC7E;AAGA,SAAgBC,EAAW,GAAiB,GAAe,GAAmB;CAC5E,OAAOC,EAAe;EAAE;EAAM,OAAON,EAAOtB,GAAOK,EAAK,EAAE;EAAG;CAAM,CAAC;AACtE;AAIA,SAAgBwB,EAAU,GAAkB,GAAW,GAAqB;CAC1E,IAAIX,EAAI,WAAW,GAAG;CACtB,IAAIjB,EAAK,UAAU;EACjB,EAAK,SAASiB,GAAKY,CAAK;EACxB;CACF;CACA,IAAM9B,IAAQC,EAAK;CACnB,AAAKD,KACLA,EAAM,WAAWkB,GAAKY,GAAOC,EAAqB/B,GAAOC,EAAK,WAAW,cAAc,CAAC;AAC1F"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { insertAt as e, pathCopy as t, reshapeOps as n, slotOf as r } from "./pathNodes.js";
|
|
2
|
+
import { livePathEdit as i } from "./livePathEdit.js";
|
|
3
|
+
import { simplifyPath as a } from "@weasel-js/geom";
|
|
4
|
+
import { offsetPath as o } from "@weasel-js/stroke";
|
|
5
|
+
//#region src/interactions/actions/pathCommands/simplifyOffset.ts
|
|
6
|
+
var s = 1, c = i({
|
|
7
|
+
id: "simplifyPath",
|
|
8
|
+
label: "Simplify",
|
|
9
|
+
param: "tolerance",
|
|
10
|
+
initial: s,
|
|
11
|
+
edit: ({ path: e }, t) => a(e, Math.max(t, 0)),
|
|
12
|
+
commit: (e, t) => [...t.values()].flatMap(({ node: e, path: t }) => n(e.node, t, "Simplify"))
|
|
13
|
+
}), l = i({
|
|
14
|
+
id: "offsetPath",
|
|
15
|
+
label: "Offset Path",
|
|
16
|
+
param: "distance",
|
|
17
|
+
initial: 0,
|
|
18
|
+
overlaysSource: !0,
|
|
19
|
+
edit: ({ path: e }, t) => {
|
|
20
|
+
if (t === 0) return null;
|
|
21
|
+
let n = o(e, t);
|
|
22
|
+
return n.commands.length > 0 ? n : null;
|
|
23
|
+
},
|
|
24
|
+
commit: (n, i, a) => {
|
|
25
|
+
let o = n.scene;
|
|
26
|
+
if (!o) return [];
|
|
27
|
+
let s = [...i.values()].map((e) => ({
|
|
28
|
+
...e,
|
|
29
|
+
at: r(o, e.node.id)
|
|
30
|
+
})).sort((e, t) => t.at - e.at), c = [];
|
|
31
|
+
for (let { node: n, path: r, at: i } of s) {
|
|
32
|
+
let s = t(o, n.node, r);
|
|
33
|
+
s && c.push(e(s, i < 0 || a > 0 ? i : i + 1, "Offset Path"));
|
|
34
|
+
}
|
|
35
|
+
return c;
|
|
36
|
+
},
|
|
37
|
+
selectAfter: (e) => e.map((e) => e.args.node.id)
|
|
38
|
+
});
|
|
39
|
+
//#endregion
|
|
40
|
+
export { s as DEFAULT_SIMPLIFY_TOLERANCE, l as offsetPathAction, c as simplifyPathAction };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=simplifyOffset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simplifyOffset.js","names":["DEFAULT_SIMPLIFY_TOLERANCE","simplifyPathAction","livePathEdit","simplifyPath","path","tolerance","next","reshapeOps","node","offsetPathAction","distance","out","offsetPath","scene","deps","placed","entry","slotOf","b","a","ops","copy","pathCopy","insertAt","at","op"],"sources":["../../../../src/interactions/actions/pathCommands/simplifyOffset.ts"],"sourcesContent":["/**\n * Simplify and Offset Path: the two path commands driven by a number. Both\n * are ongoing actions so a slider can preview them live and commit once —\n * `useOngoingAction('simplifyPath').input({ tolerance })`, then `.commit()`.\n */\nimport { simplifyPath } from '@weasel-js/geom';\nimport { offsetPath } from '@weasel-js/stroke';\nimport type { Op } from 'core/ops/types';\nimport { livePathEdit } from './livePathEdit';\nimport { insertAt, pathCopy, reshapeOps, slotOf } from './pathNodes';\n\n/** Simplify's tolerance when none is given: world units off the original. */\nexport const DEFAULT_SIMPLIFY_TOLERANCE = 1;\n\n/**\n * @experimental Refit each selected path with as few anchors as keep it\n * within `params.tolerance` of where it was (`simplifyPath`).\n */\nexport const simplifyPathAction = livePathEdit({\n id: 'simplifyPath',\n label: 'Simplify',\n param: 'tolerance',\n initial: DEFAULT_SIMPLIFY_TOLERANCE,\n edit: ({ path }, tolerance) => simplifyPath(path, Math.max(tolerance, 0)),\n commit: (_deps, next) => [...next.values()].flatMap(({ node, path }) => reshapeOps(node.node, path, 'Simplify')),\n});\n\n/**\n * @experimental Add, beside each selected path, the outline of the region it\n * fills grown by `params.distance` (shrunk by a negative one), with\n * `params.join` corners (`offsetPath`). A grown outline goes behind its\n * source and a shrunk one in front, so neither hides the other; the new\n * paths are selected.\n */\nexport const offsetPathAction = livePathEdit({\n id: 'offsetPath',\n label: 'Offset Path',\n param: 'distance',\n initial: 0,\n overlaysSource: true,\n edit: ({ path }, distance) => {\n if (distance === 0) return null;\n const out = offsetPath(path, distance);\n return out.commands.length > 0 ? out : null;\n },\n commit: (deps, next, distance) => {\n const scene = deps.scene;\n if (!scene) return [];\n // Top slot first, so an insert cannot shift a later one's index.\n const placed = [...next.values()]\n .map((entry) => ({ ...entry, at: slotOf(scene, entry.node.id) }))\n .sort((a, b) => b.at - a.at);\n const ops: Op[] = [];\n for (const { node, path, at } of placed) {\n const copy = pathCopy(scene, node.node, path);\n if (!copy) continue;\n ops.push(insertAt(copy, at < 0 || distance > 0 ? at : at + 1, 'Offset Path'));\n }\n return ops;\n },\n selectAfter: (ops) => ops.map((op) => (op.args as { node: { id: string } }).node.id),\n});\n"],"mappings":";;;;;AAYA,IAAaA,IAA6B,GAM7BC,IAAqBC,EAAa;CAC7C,IAAI;CACJ,OAAO;CACP,OAAO;CACP,SAASF;CACT,OAAO,EAAE,WAAQ,MAAcG,EAAaC,GAAM,KAAK,IAAIC,GAAW,CAAC,CAAC;CACxE,SAAS,GAAO,MAAS,CAAC,GAAGC,EAAK,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,SAAM,cAAWC,EAAWC,EAAK,MAAMJ,GAAM,UAAU,CAAC;AACjH,CAAC,GASYK,IAAmBP,EAAa;CAC3C,IAAI;CACJ,OAAO;CACP,OAAO;CACP,SAAS;CACT,gBAAgB;CAChB,OAAO,EAAE,WAAQ,MAAa;EAC5B,IAAIQ,MAAa,GAAG,OAAO;EAC3B,IAAMC,IAAMC,EAAWR,GAAMM,CAAQ;EACrC,OAAOC,EAAI,SAAS,SAAS,IAAIA,IAAM;CACzC;CACA,SAAS,GAAM,GAAM,MAAa;EAChC,IAAME,IAAQC,EAAK;EACnB,IAAI,CAACD,GAAO,OAAO,CAAC;EAEpB,IAAME,IAAS,CAAC,GAAGT,EAAK,OAAO,CAAC,CAAC,CAC9B,KAAK,OAAW;GAAE,GAAGU;GAAO,IAAIC,EAAOJ,GAAOG,EAAM,KAAK,EAAE;EAAE,EAAE,CAAC,CAChE,MAAM,GAAG,MAAME,EAAE,KAAKC,EAAE,EAAE,GACvBC,IAAY,CAAC;EACnB,KAAK,IAAM,EAAE,SAAM,SAAM,WAAQL,GAAQ;GACvC,IAAMM,IAAOC,EAAST,GAAOL,EAAK,MAAMJ,CAAI;GAC5C,AAAKiB,KACLD,EAAI,KAAKG,EAASF,GAAMG,IAAK,KAAKd,IAAW,IAAIc,IAAKA,IAAK,GAAG,aAAa,CAAC;EAC9E;EACA,OAAOJ;CACT;CACA,cAAc,MAAQA,EAAI,KAAK,MAAQK,EAAG,KAAkC,KAAK,EAAE;AACrF,CAAC"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { closeGesture as e, runBehaviorCancel as t } from "../gestureLifecycle.js";
|
|
2
2
|
import { inPlane as n, selectionLayer as r } from "../planeInput.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { recordTransform as i } from "../transform-again/memory.js";
|
|
4
|
+
import { commitResize as a } from "./commit.js";
|
|
5
|
+
import { nextFrame as o } from "./frame.js";
|
|
6
|
+
import { beginResize as s } from "./session.js";
|
|
7
|
+
import { unitsOfBox as c } from "./replay.js";
|
|
6
8
|
//#region src/interactions/actions/resize/action.ts
|
|
7
|
-
var
|
|
9
|
+
var l = n({
|
|
8
10
|
id: "resize",
|
|
9
11
|
label: "Resize",
|
|
10
12
|
eligible: { capability: "transforms-selection" },
|
|
@@ -20,36 +22,45 @@ var s = n({
|
|
|
20
22
|
invoker: {
|
|
21
23
|
timing: "ongoing",
|
|
22
24
|
start(n, r) {
|
|
23
|
-
let
|
|
24
|
-
if (!
|
|
25
|
-
let { session:
|
|
26
|
-
return
|
|
25
|
+
let l = s(n);
|
|
26
|
+
if (!l) return {};
|
|
27
|
+
let { session: u, readers: d } = l, f = [...n.deps.selection?.get() ?? []], p = u.scene.overrides.hold(), m = { previews: /* @__PURE__ */ new Map() };
|
|
28
|
+
return u.lifecycle.start(u.writeIds), {
|
|
27
29
|
kind: "resize",
|
|
28
30
|
onMove(e) {
|
|
29
|
-
e.drag && (
|
|
31
|
+
e.drag && (m = o(u, d, e), p.set(m.previews));
|
|
30
32
|
},
|
|
31
33
|
onEnd(n, r) {
|
|
32
|
-
let
|
|
34
|
+
let o = !1;
|
|
33
35
|
try {
|
|
34
|
-
r === "commit"
|
|
36
|
+
if (r === "commit") {
|
|
37
|
+
if (o = a(u, m), o && m.proposed) {
|
|
38
|
+
let e = c(u.box.bounds, m.proposed);
|
|
39
|
+
i(u.scene, {
|
|
40
|
+
kind: "scale",
|
|
41
|
+
to: e,
|
|
42
|
+
anchor: u.box.anchor
|
|
43
|
+
}, f);
|
|
44
|
+
}
|
|
45
|
+
} else t(u.constraints, u.gestureCtx);
|
|
35
46
|
} finally {
|
|
36
47
|
e({
|
|
37
|
-
hold:
|
|
38
|
-
previews:
|
|
39
|
-
behaviors:
|
|
40
|
-
ctx:
|
|
41
|
-
lifecycle:
|
|
42
|
-
},
|
|
48
|
+
hold: p,
|
|
49
|
+
previews: m.previews,
|
|
50
|
+
behaviors: u.constraints,
|
|
51
|
+
ctx: u.gestureCtx,
|
|
52
|
+
lifecycle: u.lifecycle
|
|
53
|
+
}, o);
|
|
43
54
|
}
|
|
44
55
|
},
|
|
45
|
-
previewIds: () =>
|
|
46
|
-
previewPose: (e) =>
|
|
56
|
+
previewIds: () => m.previews.keys(),
|
|
57
|
+
previewPose: (e) => m.previews.get(e) ?? null
|
|
47
58
|
};
|
|
48
59
|
}
|
|
49
60
|
},
|
|
50
61
|
enabled: () => !0
|
|
51
62
|
}, r);
|
|
52
63
|
//#endregion
|
|
53
|
-
export {
|
|
64
|
+
export { l as resizeAction };
|
|
54
65
|
|
|
55
66
|
//# sourceMappingURL=action.js.map
|