@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,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { targetTransformOf as e, worldToLocal as t } from "../../core/geometry/targetFrame.js";
|
|
2
|
+
import { asNodeId as n } from "../../core/scene/types.js";
|
|
3
|
+
import { scenePaintedPoseOf as r } from "../../canvas/derivedPath.js";
|
|
4
4
|
import { findMountedCanvas as i } from "../../canvas/mountedCanvases.js";
|
|
5
5
|
import { poseFrameOf as a } from "@weasel-js/geom";
|
|
6
6
|
import { useCallback as o, useMemo as s, useRef as c } from "react";
|
|
@@ -13,8 +13,17 @@ import { useTextEdit as h } from "@weasel-js/text-dom";
|
|
|
13
13
|
function g(e) {
|
|
14
14
|
return typeof e == "function" ? e() : e;
|
|
15
15
|
}
|
|
16
|
-
function _(
|
|
17
|
-
|
|
16
|
+
function _(e) {
|
|
17
|
+
return {
|
|
18
|
+
isText: (t) => e.current.isText ? e.current.isText(t) : p(t),
|
|
19
|
+
text: (t) => e.current.getText ? e.current.getText(t) : t.text ?? "",
|
|
20
|
+
style: (t) => e.current.getStyle ? e.current.getStyle(t) : t.style,
|
|
21
|
+
runs: (t) => e.current.getRuns ? e.current.getRuns(t) : t.runs,
|
|
22
|
+
verticalAlign: (t) => e.current.getVerticalAlign ? e.current.getVerticalAlign(t) : t.verticalAlign
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function v(a, p, v = {}) {
|
|
26
|
+
let b = l(a), x = l(v), S = l(p), C = c(null), w = () => {
|
|
18
27
|
let e = S.current, t = e ? i(e, C.current) : null;
|
|
19
28
|
if (!e || !t) return null;
|
|
20
29
|
let n = t.element.getBoundingClientRect(), r = e.getBoundingClientRect();
|
|
@@ -27,90 +36,81 @@ function _(a, _, y = {}) {
|
|
|
27
36
|
height: n.height
|
|
28
37
|
}
|
|
29
38
|
};
|
|
30
|
-
}, T = s(() => ({
|
|
31
|
-
|
|
32
|
-
text: (e) => x.current.getText ? x.current.getText(e) : e.text ?? "",
|
|
33
|
-
style: (e) => x.current.getStyle ? x.current.getStyle(e) : e.style,
|
|
34
|
-
runs: (e) => x.current.getRuns ? x.current.getRuns(e) : e.runs,
|
|
35
|
-
verticalAlign: (e) => x.current.getVerticalAlign ? x.current.getVerticalAlign(e) : e.verticalAlign
|
|
36
|
-
}), [x]), E = h({
|
|
37
|
-
container: _,
|
|
39
|
+
}, T = s(() => _(x), [x]), E = h({
|
|
40
|
+
container: p,
|
|
38
41
|
isEditorChrome: (e) => x.current.isEditorChrome?.(e) ?? !1,
|
|
39
|
-
escape:
|
|
40
|
-
fontHold:
|
|
42
|
+
escape: v.escape,
|
|
43
|
+
fontHold: v.fontHold,
|
|
44
|
+
onStart: (e) => x.current.onStart?.(e),
|
|
45
|
+
onEnd: (e) => x.current.onEnd?.(e),
|
|
41
46
|
getText: (e) => {
|
|
42
|
-
let t = b.current.get(
|
|
47
|
+
let t = b.current.get(n(e));
|
|
43
48
|
return t ? T.text(t.data) : "";
|
|
44
49
|
},
|
|
45
50
|
getStyle: (e) => {
|
|
46
|
-
let t = b.current.get(
|
|
51
|
+
let t = b.current.get(n(e));
|
|
47
52
|
return t ? T.style(t.data) : void 0;
|
|
48
53
|
},
|
|
49
54
|
getPaint: (e) => {
|
|
50
|
-
let t = b.current.get(
|
|
55
|
+
let t = b.current.get(n(e));
|
|
51
56
|
if (!t) return;
|
|
52
|
-
let
|
|
53
|
-
return
|
|
57
|
+
let r = x.current.getPaint;
|
|
58
|
+
return r ? r(t.data) : {
|
|
54
59
|
fill: t.data.fill,
|
|
55
60
|
stroke: t.data.stroke
|
|
56
61
|
};
|
|
57
62
|
},
|
|
58
|
-
getScreenPose: (
|
|
59
|
-
let
|
|
63
|
+
getScreenPose: (e) => {
|
|
64
|
+
let t = b.current, i = t.get(n(e));
|
|
60
65
|
if (!i) return null;
|
|
61
|
-
let a =
|
|
66
|
+
let a = r(t)(i), o = T.style(i.data), s = w(), c = y(a, g(x.current.view) ?? s?.canvas.getView(), s?.box);
|
|
62
67
|
return {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
width: a.width,
|
|
66
|
-
height: a.height,
|
|
67
|
-
fontSize: d(o?.fontSize ?? x.current.defaultFontSize ?? 16, l),
|
|
68
|
-
zoom: l,
|
|
69
|
-
frame: v(a),
|
|
68
|
+
...c,
|
|
69
|
+
fontSize: d(o?.fontSize ?? x.current.defaultFontSize ?? 16, c.zoom),
|
|
70
70
|
verticalAlign: T.verticalAlign(i.data)
|
|
71
71
|
};
|
|
72
72
|
},
|
|
73
73
|
getClipRect: () => w()?.box ?? null,
|
|
74
74
|
getRuns: (e) => {
|
|
75
|
-
let t = b.current.get(
|
|
75
|
+
let t = b.current.get(n(e));
|
|
76
76
|
return t ? T.runs(t.data) : void 0;
|
|
77
77
|
},
|
|
78
|
-
commit: (e, { text: t, runs:
|
|
79
|
-
let a =
|
|
78
|
+
commit: (e, { text: t, runs: r, style: i }) => {
|
|
79
|
+
let a = n(e), o = b.current.get(a);
|
|
80
80
|
if (!o) return;
|
|
81
81
|
let { setText: s, setRuns: c, setStyle: l } = x.current, u = s ? s(o.data, t) : {
|
|
82
82
|
...o.data,
|
|
83
83
|
text: t
|
|
84
84
|
};
|
|
85
|
-
|
|
85
|
+
r && (u = c ? c(u, r) : {
|
|
86
86
|
...u,
|
|
87
|
-
runs:
|
|
87
|
+
runs: r
|
|
88
88
|
}), i && (u = l ? l(u, i) : {
|
|
89
89
|
...u,
|
|
90
90
|
style: i
|
|
91
91
|
}), b.current.update(a, { data: u });
|
|
92
92
|
}
|
|
93
|
-
}), D = o((
|
|
94
|
-
let a =
|
|
93
|
+
}), D = o((n) => {
|
|
94
|
+
let a = n.target instanceof HTMLElement ? n.target : null;
|
|
95
95
|
if (!a || a.closest("[contenteditable=\"true\"]")) return;
|
|
96
|
-
let [o, s] = u(a,
|
|
97
|
-
for (let
|
|
98
|
-
let
|
|
99
|
-
if (b.current.isLocked(
|
|
100
|
-
let
|
|
101
|
-
if (!
|
|
102
|
-
let
|
|
103
|
-
x:
|
|
104
|
-
y:
|
|
105
|
-
width:
|
|
106
|
-
height:
|
|
107
|
-
text:
|
|
108
|
-
runs: T.runs(
|
|
109
|
-
style: T.style(
|
|
110
|
-
verticalAlign: T.verticalAlign(
|
|
96
|
+
let [o, s] = u(a, n.clientX, n.clientY), c = S.current, l = g(x.current.view) ?? (c ? i(c, a)?.getView() : void 0), d = l ? o / l.scale.x + l.x : o, p = l ? s / l.scale.y + l.y : s, h = b.current.renderOrderNodes(), _ = r(b.current);
|
|
97
|
+
for (let n = h.length - 1; n >= 0; n--) {
|
|
98
|
+
let r = h[n];
|
|
99
|
+
if (b.current.isLocked(r.id) || !T.isText(r.data)) continue;
|
|
100
|
+
let i = T.text(r.data), o = _(r), s = t(e(o), d, p);
|
|
101
|
+
if (!s) continue;
|
|
102
|
+
let c = {
|
|
103
|
+
x: o.x,
|
|
104
|
+
y: o.y,
|
|
105
|
+
width: o.width,
|
|
106
|
+
height: o.height,
|
|
107
|
+
text: i,
|
|
108
|
+
runs: T.runs(r.data),
|
|
109
|
+
style: T.style(r.data),
|
|
110
|
+
verticalAlign: T.verticalAlign(r.data)
|
|
111
111
|
};
|
|
112
|
-
if (m(
|
|
113
|
-
C.current = a, E.startEdit(String(
|
|
112
|
+
if (m(s.x, s.y, c)) {
|
|
113
|
+
C.current = a, E.startEdit(String(r.id), { caret: f(s.x, s.y, c) });
|
|
114
114
|
return;
|
|
115
115
|
}
|
|
116
116
|
}
|
|
@@ -121,7 +121,7 @@ function _(a, _, y = {}) {
|
|
|
121
121
|
T,
|
|
122
122
|
b
|
|
123
123
|
]), O = o((e) => {
|
|
124
|
-
let t = b.current.get(
|
|
124
|
+
let t = b.current.get(n(e));
|
|
125
125
|
return t !== void 0 && T.isText(t.data);
|
|
126
126
|
}, [T, b]);
|
|
127
127
|
return {
|
|
@@ -130,16 +130,34 @@ function _(a, _, y = {}) {
|
|
|
130
130
|
isTextNode: O
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
|
-
function
|
|
134
|
-
let t = a(e);
|
|
135
|
-
return
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
133
|
+
function y(e, t, n) {
|
|
134
|
+
let r = t ? t.scale.x : 1, i = t ? t.scale.y : 1, a = (n?.x ?? 0) + (e.x + e.width / 2 - (t?.x ?? 0)) * r, o = (n?.y ?? 0) + (e.y + e.height / 2 - (t?.y ?? 0)) * i;
|
|
135
|
+
return {
|
|
136
|
+
x: a - e.width * r / 2,
|
|
137
|
+
y: o - e.height * r / 2,
|
|
138
|
+
width: e.width,
|
|
139
|
+
height: e.height,
|
|
140
|
+
zoom: r,
|
|
141
|
+
frame: b(e, i / r)
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function b(e, t) {
|
|
145
|
+
let n = a(e);
|
|
146
|
+
if (!n && t === 1) return;
|
|
147
|
+
let [r, i, o, s] = n ?? [
|
|
148
|
+
1,
|
|
149
|
+
0,
|
|
150
|
+
0,
|
|
151
|
+
1
|
|
152
|
+
];
|
|
153
|
+
return [
|
|
154
|
+
r,
|
|
155
|
+
i * t,
|
|
156
|
+
o,
|
|
157
|
+
s * t
|
|
158
|
+
];
|
|
141
159
|
}
|
|
142
160
|
//#endregion
|
|
143
|
-
export {
|
|
161
|
+
export { v as useSceneTextEdit };
|
|
144
162
|
|
|
145
163
|
//# sourceMappingURL=useSceneTextEdit.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSceneTextEdit.js","names":["resolveView","view","useSceneTextEdit","sceneRef","useLatest","scene","optsRef","options","containerRef","container","openedOnRef","useRef","surface","root","canvas","findMountedCanvas","a","b","read","useMemo","data","isTextData","edit","useTextEdit","el","node","asNodeId","id","get","pose","effectivePose","style","at","zoom","originX","originY","resolveScreenLength","frameLinearOf","nid","setText","text","runs","setRuns","setStyle","onDoubleClick","useCallback","e","canvasX","canvasY","clientToCanvas","cx","cy","order","i","p","worldToLocal","targetTransformOf","pointInTextPose","caretIndexAt","isTextNode","m","poseFrameOf"],"sources":["../../../src/features/text/useSceneTextEdit.ts"],"sourcesContent":["/**\n * `useSceneTextEdit` — scene-aware wrapper around `useTextEdit`: scene\n * lookups for text / style / runs / screen-pose, and\n * `scene.update(id, { data })` for commits.\n *\n * Defaults assume the node's `data` carries `text` / `style` / `runs`\n * directly. For custom data shapes, override any of the optional projections.\n * Consumers with non-rect poses should drop down to raw `useTextEdit` and\n * supply their own `getScreenPose`.\n */\nimport { useCallback, useMemo, useRef, type MouseEvent } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport { asNodeId } from '../../core/scene/types';\nimport { effectivePose } from '../../core/scene/effectivePose';\nimport type { Scene } from '../../core/scene/types';\nimport type { Stroke, Fill } from '@weasel-js/paint';\nimport { resolveScreenLength } from '@weasel-js/paint';\nimport { clientToCanvas } from '@weasel-js/routing';\nimport { findMountedCanvas, type MountedCanvas } from '../../canvas/mountedCanvases';\nimport type { View } from '../../core/viewport/view';\nimport type { RectPose } from 'core/geometry/unionBounds';\nimport { targetTransformOf, worldToLocal } from 'core/geometry/targetFrame';\nimport { poseFrameOf } from '@weasel-js/geom';\nimport { caretIndexAt, pointInTextPose, isTextData, type StyledRun, type TextPaint, type TextStyle, type TextVerticalAlign } from '@weasel-js/text';\nimport { useTextEdit, type TextEditClipRect, type TextEditScreenPose, type UseTextEditReturn } from '@weasel-js/text-dom';\n\n/** Shape the default projections expect `data` to satisfy. All fields\n * optional so any object satisfies the constraint — projections fill in\n * the gaps for non-default shapes. */\nexport interface DefaultTextData {\n text?: string;\n style?: TextStyle;\n runs?: readonly StyledRun[];\n fill?: Fill | null;\n stroke?: Stroke | null;\n verticalAlign?: TextVerticalAlign;\n}\n\n/** All-optional projections + fontSize fallback. */\nexport interface UseSceneTextEditOptions<TData> {\n /**\n * Is this node text? A double-click opens an edit only on a node that\n * answers yes, and passes through any other to the text under it. Default:\n * `isTextData`, the test `inferredNodeRouting` classifies a text node by. Pass one when `getText` reads some other shape.\n */\n isText?: (data: TData) => boolean;\n /** Read plain text from `data`. Default: `data.text ?? ''`. */\n getText?: (data: TData) => string;\n /** Read style from `data`. Default: `data.style`. */\n getStyle?: (data: TData) => TextStyle | undefined;\n /** Read the node's paint from `data`. Default: `data.fill` / `data.stroke`. */\n getPaint?: (data: TData) => TextPaint | undefined;\n /** Read rich-text runs from `data`. Default: `data.runs`. */\n getRuns?: (data: TData) => readonly StyledRun[] | undefined;\n /** Read the box vertical alignment from `data`. Default: `data.verticalAlign`. */\n getVerticalAlign?: (data: TData) => TextVerticalAlign | undefined;\n /** Produce updated data with new text. Default: `{ ...data, text }`. */\n setText?: (data: TData, text: string) => TData;\n /** Produce updated data with new runs. Default: `{ ...data, runs }`. */\n setRuns?: (data: TData, runs: StyledRun[]) => TData;\n /**\n * Produce updated data with a new node-wide style. Default:\n * `{ ...data, style }`. Written only when a range toggle has to *clear* a\n * flag the node itself sets — the run algebra is additive, so that edit\n * lowers the node flag and raises it on the runs outside the range. See\n * `useTextEdit`'s `setStyle`.\n *\n * An edit's text, runs, and style are folded through these three and\n * written as one `scene.update`, so a commit is one undo step.\n */\n setStyle?: (data: TData, style: TextStyle) => TData;\n /** Fallback fontSize when `style.fontSize` is unset. Default `16`. */\n defaultFontSize?: number;\n /**\n * The view to project through. Omit it and the view is read live from the\n * weasel canvas mounted inside `container` (the one a double-click landed\n * on, when there are several). With no canvas there, the node's world box\n * is passed through as screen pixels.\n *\n * The overlay takes a single scale factor, so a non-uniform view scale is\n * represented by its `scale.x`; text under `scale.x !== scale.y` will not\n * match the canvas.\n *\n * A thunk is re-read on every projection; a plain `View` is the value from\n * the render that supplied it.\n */\n view?: View | (() => View);\n /**\n * Forwarded to `useTextEdit`: is `el` part of the editor's own chrome?\n * Focus moving into it does not end the edit. Wire it to whatever renders\n * the character controls.\n */\n isEditorChrome?: (el: Element) => boolean;\n /** Forwarded to `useTextEdit`: what Escape does to the edit. */\n escape?: 'cancel' | 'commit';\n /** Forwarded to `useTextEdit`: how long an edit waits for its face. */\n fontHold?: number;\n}\n\nfunction resolveView(view: View | (() => View) | undefined): View | undefined {\n return typeof view === 'function' ? view() : view;\n}\n\n/** Return shape extends `UseTextEditReturn` with an `onDoubleClick`\n * binding for the canvas container. Double-clicking inside a text\n * node enters edit mode with the caret seeded at the clicked glyph. */\nexport interface UseSceneTextEditReturn extends UseTextEditReturn {\n /** Bind to the element wrapping `<SceneCanvas>` (the same element\n * passed as `container`, or any ancestor that receives the dblclick\n * bubble). Starts an edit on the top-most text node under the cursor. */\n onDoubleClick: (e: MouseEvent<HTMLElement>) => void;\n /** The `isText` option asked of the node with this id: what\n * `TextEditDep.isTextNode` wants, so both ways into an edit agree. */\n isTextNode: (id: string) => boolean;\n}\n\n/** Wire double-click-to-edit text on a scene: mounts a DOM editing overlay\n * over the node being edited and writes the result back as an undoable op. */\nexport function useSceneTextEdit<\n TData extends DefaultTextData,\n TLayer extends string,\n TPose extends RectPose = RectPose,\n>(\n scene: Scene<TData, TLayer, TPose>,\n container: HTMLElement | null,\n options: UseSceneTextEditOptions<TData> = {},\n): UseSceneTextEditReturn {\n // Refs, so the useTextEdit callbacks always see the current values\n // without re-binding.\n const sceneRef = useLatest(scene);\n const optsRef = useLatest(options);\n const containerRef = useLatest(container);\n // The last double-click's target, so the overlay projects through the\n // canvas the edit was opened on.\n const openedOnRef = useRef<EventTarget | null>(null);\n\n // The canvas's box in container pixels is both the origin its view projects\n // from and the region its glyphs are clipped to.\n const surface = (): { canvas: MountedCanvas; box: TextEditClipRect } | null => {\n const root = containerRef.current;\n const canvas = root ? findMountedCanvas(root, openedOnRef.current) : null;\n if (!root || !canvas) return null;\n const a = canvas.element.getBoundingClientRect();\n const b = root.getBoundingClientRect();\n return {\n canvas,\n box: {\n x: a.left - b.left - root.clientLeft + root.scrollLeft,\n y: a.top - b.top - root.clientTop + root.scrollTop,\n width: a.width,\n height: a.height,\n },\n };\n };\n\n const read = useMemo(() => ({\n isText: (data: TData): boolean =>\n optsRef.current.isText ? optsRef.current.isText(data) : isTextData(data),\n text: (data: TData): string =>\n optsRef.current.getText ? optsRef.current.getText(data) : (data.text ?? ''),\n style: (data: TData): TextStyle | undefined =>\n optsRef.current.getStyle ? optsRef.current.getStyle(data) : data.style,\n runs: (data: TData): readonly StyledRun[] | undefined =>\n optsRef.current.getRuns ? optsRef.current.getRuns(data) : data.runs,\n verticalAlign: (data: TData): TextVerticalAlign | undefined =>\n optsRef.current.getVerticalAlign ? optsRef.current.getVerticalAlign(data) : data.verticalAlign,\n }), [optsRef]);\n\n const edit = useTextEdit({\n container,\n isEditorChrome: (el) => optsRef.current.isEditorChrome?.(el) ?? false,\n escape: options.escape,\n fontHold: options.fontHold,\n getText: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.text(node.data) : '';\n },\n getStyle: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.style(node.data) : undefined;\n },\n getPaint: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n if (!node) return undefined;\n const get = optsRef.current.getPaint;\n return get ? get(node.data) : { fill: node.data.fill, stroke: node.data.stroke };\n },\n getScreenPose: (id) => {\n const scene = sceneRef.current;\n const node = scene.get(asNodeId(id));\n if (!node) return null;\n const pose = effectivePose(scene, node);\n const style = read.style(node.data);\n const at = surface();\n const view = resolveView(optsRef.current.view) ?? at?.canvas.getView();\n const zoom = view ? view.scale.x : 1;\n const originX = at?.box.x ?? 0;\n const originY = at?.box.y ?? 0;\n // Only the origin is projected. Width, height and font size stay in\n // world units and reach the screen through the overlay's own\n // `scale(zoom)` — see `TextEditScreenPose.zoom`.\n return {\n x: originX + (view ? (pose.x - view.x) * view.scale.x : pose.x),\n y: originY + (view ? (pose.y - view.y) * view.scale.y : pose.y),\n width: pose.width,\n height: pose.height,\n // Against `zoom`, the same factor the overlay scales back up by, so a\n // `{ px }` size arrives on screen at the pixel count it names.\n fontSize: resolveScreenLength(\n style?.fontSize ?? optsRef.current.defaultFontSize ?? 16,\n zoom,\n ),\n zoom,\n frame: frameLinearOf(pose),\n verticalAlign: read.verticalAlign(node.data),\n };\n },\n getClipRect: () => surface()?.box ?? null,\n getRuns: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.runs(node.data) : undefined;\n },\n commit: (id, { text, runs, style }) => {\n const nid = asNodeId(id);\n const node = sceneRef.current.get(nid);\n if (!node) return;\n const { setText, setRuns, setStyle } = optsRef.current;\n let data = setText ? setText(node.data, text) : { ...node.data, text };\n if (runs) data = setRuns ? setRuns(data, runs) : { ...data, runs };\n if (style) data = setStyle ? setStyle(data, style) : { ...data, style };\n sceneRef.current.update(nid, { data });\n },\n });\n\n const onDoubleClick = useCallback((e: MouseEvent<HTMLElement>) => {\n // The dblclick bubbles from the canvas up to any wrapping container; the\n // element it started on is what the click coordinates are relative to.\n const canvas = e.target instanceof HTMLElement ? e.target : null;\n if (!canvas) return;\n // Inside the editor a double-click selects a word, and its target is a run\n // span whose box the click would be measured against as if it were a canvas.\n if (canvas.closest('[contenteditable=\"true\"]')) return;\n\n // `pointInTextPose` and `caretIndexAt` work in the node's own box: the click\n // is un-projected here, then taken back through the frame the node is drawn in.\n const [canvasX, canvasY] = clientToCanvas(canvas, e.clientX, e.clientY);\n const root = containerRef.current;\n const view = resolveView(optsRef.current.view)\n ?? (root ? findMountedCanvas(root, canvas)?.getView() : undefined);\n const cx = view ? canvasX / view.scale.x + view.x : canvasX;\n const cy = view ? canvasY / view.scale.y + view.y : canvasY;\n // Top-most-first hit test: renderOrder() is back-to-front, so iterate\n // in reverse and break on the first hit.\n const order = sceneRef.current.renderOrderNodes();\n for (let i = order.length - 1; i >= 0; i--) {\n const node = order[i];\n if (sceneRef.current.isLocked(node.id)) continue;\n if (!read.isText(node.data)) continue;\n const text = read.text(node.data);\n const at = effectivePose(sceneRef.current, node);\n const p = worldToLocal(targetTransformOf(at), cx, cy);\n if (!p) continue;\n const pose = {\n x: at.x, y: at.y, width: at.width, height: at.height,\n text,\n runs: read.runs(node.data) as StyledRun[] | undefined,\n style: read.style(node.data),\n verticalAlign: read.verticalAlign(node.data),\n };\n if (!pointInTextPose(p.x, p.y, pose)) continue;\n\n openedOnRef.current = canvas;\n edit.startEdit(String(node.id), { caret: caretIndexAt(p.x, p.y, pose) });\n return;\n }\n }, [edit, containerRef, optsRef, read, sceneRef]);\n\n const isTextNode = useCallback((id: string): boolean => {\n const node = sceneRef.current.get(asNodeId(id));\n return node !== undefined && read.isText(node.data);\n }, [read, sceneRef]);\n\n return { ...edit, onDoubleClick, isTextNode };\n}\n\n/** The linear part of the frame `pose` is drawn in, as the overlay takes it. */\nfunction frameLinearOf(pose: unknown): TextEditScreenPose['frame'] {\n const m = poseFrameOf(pose);\n return m ? [m[0], m[1], m[2], m[3]] : undefined;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useSceneTextEdit.js","names":["resolveView","view","projectionsOf","opts","data","isTextData","useSceneTextEdit","sceneRef","useLatest","scene","optsRef","options","containerRef","container","openedOnRef","useRef","surface","root","canvas","findMountedCanvas","a","b","read","useMemo","edit","useTextEdit","el","id","node","asNodeId","get","pose","scenePaintedPoseOf","style","at","box","screenBoxOf","resolveScreenLength","nid","setText","text","runs","setRuns","setStyle","onDoubleClick","useCallback","e","canvasX","canvasY","clientToCanvas","cx","cy","order","paintedPoseOf","i","p","worldToLocal","targetTransformOf","pointInTextPose","caretIndexAt","isTextNode","zoom","zoomY","origin","frameLinearOf","m","poseFrameOf","stretch","c","d"],"sources":["../../../src/features/text/useSceneTextEdit.ts"],"sourcesContent":["/**\n * `useSceneTextEdit` — scene-aware wrapper around `useTextEdit`: scene\n * lookups for text / style / runs / screen-pose, and\n * `scene.update(id, { data })` for commits. The overlay and a double-click\n * both read the pose a node is painted at, so text inside a container whose\n * pose is a frame is edited where it is drawn.\n *\n * Defaults assume the node's `data` carries `text` / `style` / `runs`\n * directly. For custom data shapes, override any of the optional projections.\n * Consumers with non-rect poses should drop down to raw `useTextEdit` and\n * supply their own `getScreenPose`.\n */\nimport { useCallback, useMemo, useRef, type MouseEvent } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport { asNodeId } from '../../core/scene/types';\nimport { scenePaintedPoseOf } from '../../canvas/derivedPath';\nimport type { Scene } from '../../core/scene/types';\nimport type { Stroke, Fill } from '@weasel-js/paint';\nimport { resolveScreenLength } from '@weasel-js/paint';\nimport { clientToCanvas } from '@weasel-js/routing';\nimport { findMountedCanvas, type MountedCanvas } from '../../canvas/mountedCanvases';\nimport type { View } from '../../core/viewport/view';\nimport type { RectPose } from 'core/geometry/unionBounds';\nimport { targetTransformOf, worldToLocal } from 'core/geometry/targetFrame';\nimport { poseFrameOf } from '@weasel-js/geom';\nimport { caretIndexAt, pointInTextPose, isTextData, type StyledRun, type TextPaint, type TextStyle, type TextVerticalAlign } from '@weasel-js/text';\nimport { useTextEdit, type TextEditClipRect, type TextEditScreenPose, type UseTextEditReturn } from '@weasel-js/text-dom';\n\n/** Shape the default projections expect `data` to satisfy. All fields\n * optional so any object satisfies the constraint — projections fill in\n * the gaps for non-default shapes. */\nexport interface DefaultTextData {\n text?: string;\n style?: TextStyle;\n runs?: readonly StyledRun[];\n fill?: Fill | null;\n stroke?: Stroke | null;\n verticalAlign?: TextVerticalAlign;\n}\n\n/** All-optional projections + fontSize fallback. */\nexport interface UseSceneTextEditOptions<TData> {\n /**\n * Is this node text? A double-click opens an edit only on a node that\n * answers yes, and passes through any other to the text under it. Default:\n * `isTextData`, the test `inferredNodeRouting` classifies a text node by. Pass one when `getText` reads some other shape.\n */\n isText?: (data: TData) => boolean;\n /** Read plain text from `data`. Default: `data.text ?? ''`. */\n getText?: (data: TData) => string;\n /** Read style from `data`. Default: `data.style`. */\n getStyle?: (data: TData) => TextStyle | undefined;\n /** Read the node's paint from `data`. Default: `data.fill` / `data.stroke`. */\n getPaint?: (data: TData) => TextPaint | undefined;\n /** Read rich-text runs from `data`. Default: `data.runs`. */\n getRuns?: (data: TData) => readonly StyledRun[] | undefined;\n /** Read the box vertical alignment from `data`. Default: `data.verticalAlign`. */\n getVerticalAlign?: (data: TData) => TextVerticalAlign | undefined;\n /** Produce updated data with new text. Default: `{ ...data, text }`. */\n setText?: (data: TData, text: string) => TData;\n /** Produce updated data with new runs. Default: `{ ...data, runs }`. */\n setRuns?: (data: TData, runs: StyledRun[]) => TData;\n /**\n * Produce updated data with a new node-wide style. Default:\n * `{ ...data, style }`. Written only when a range toggle has to *clear* a\n * flag the node itself sets — the run algebra is additive, so that edit\n * lowers the node flag and raises it on the runs outside the range. See\n * `useTextEdit`'s `setStyle`.\n *\n * An edit's text, runs, and style are folded through these three and\n * written as one `scene.update`, so a commit is one undo step.\n */\n setStyle?: (data: TData, style: TextStyle) => TData;\n /** Fallback fontSize when `style.fontSize` is unset. Default `16`. */\n defaultFontSize?: number;\n /**\n * The view to project through. Omit it and the view is read live from the\n * weasel canvas mounted inside `container` (the one a double-click landed\n * on, when there are several). With no canvas there, the node's world box\n * is passed through as screen pixels.\n *\n * A thunk is re-read on every projection; a plain `View` is the value from\n * the render that supplied it.\n */\n view?: View | (() => View);\n /**\n * Forwarded to `useTextEdit`: is `el` part of the editor's own chrome?\n * Focus moving into it does not end the edit. Wire it to whatever renders\n * the character controls.\n */\n isEditorChrome?: (el: Element) => boolean;\n /** Forwarded to `useTextEdit`: what Escape does to the edit. */\n escape?: 'cancel' | 'commit';\n /** Forwarded to `useTextEdit`: how long an edit waits for its face. */\n fontHold?: number;\n /** Forwarded to `useTextEdit`: called as an edit of the node `id` opens,\n * whichever way it was started. */\n onStart?: (id: string) => void;\n /** Forwarded to `useTextEdit`: called as the edit of `id` closes, after\n * any commit has been written to the scene. */\n onEnd?: (id: string) => void;\n}\n\nfunction resolveView(view: View | (() => View) | undefined): View | undefined {\n return typeof view === 'function' ? view() : view;\n}\n\n/** Return shape extends `UseTextEditReturn` with an `onDoubleClick`\n * binding for the canvas container. Double-clicking inside a text\n * node enters edit mode with the caret seeded at the clicked glyph. */\nexport interface UseSceneTextEditReturn extends UseTextEditReturn {\n /** Bind to the element wrapping `<SceneCanvas>` (the same element\n * passed as `container`, or any ancestor that receives the dblclick\n * bubble). Starts an edit on the top-most text node under the cursor. */\n onDoubleClick: (e: MouseEvent<HTMLElement>) => void;\n /** The `isText` option asked of the node with this id: what\n * `TextEditDep.isTextNode` wants, so both ways into an edit agree. */\n isTextNode: (id: string) => boolean;\n}\n\n/** How each field is read from a node's `data`: the option's projection, else the default shape. */\nfunction projectionsOf<TData extends DefaultTextData>(opts: { readonly current: UseSceneTextEditOptions<TData> }) {\n return {\n isText: (data: TData): boolean =>\n opts.current.isText ? opts.current.isText(data) : isTextData(data),\n text: (data: TData): string =>\n opts.current.getText ? opts.current.getText(data) : (data.text ?? ''),\n style: (data: TData): TextStyle | undefined =>\n opts.current.getStyle ? opts.current.getStyle(data) : data.style,\n runs: (data: TData): readonly StyledRun[] | undefined =>\n opts.current.getRuns ? opts.current.getRuns(data) : data.runs,\n verticalAlign: (data: TData): TextVerticalAlign | undefined =>\n opts.current.getVerticalAlign ? opts.current.getVerticalAlign(data) : data.verticalAlign,\n };\n}\n\n/** Wire double-click-to-edit text on a scene: mounts a DOM editing overlay\n * over the node being edited and writes the result back as an undoable op. */\nexport function useSceneTextEdit<\n TData extends DefaultTextData,\n TLayer extends string,\n TPose extends RectPose = RectPose,\n>(\n scene: Scene<TData, TLayer, TPose>,\n container: HTMLElement | null,\n options: UseSceneTextEditOptions<TData> = {},\n): UseSceneTextEditReturn {\n // Refs, so the useTextEdit callbacks always see the current values\n // without re-binding.\n const sceneRef = useLatest(scene);\n const optsRef = useLatest(options);\n const containerRef = useLatest(container);\n // The last double-click's target, so the overlay projects through the\n // canvas the edit was opened on.\n const openedOnRef = useRef<EventTarget | null>(null);\n\n // The canvas's box in container pixels is both the origin its view projects\n // from and the region its glyphs are clipped to.\n const surface = (): { canvas: MountedCanvas; box: TextEditClipRect } | null => {\n const root = containerRef.current;\n const canvas = root ? findMountedCanvas(root, openedOnRef.current) : null;\n if (!root || !canvas) return null;\n const a = canvas.element.getBoundingClientRect();\n const b = root.getBoundingClientRect();\n return {\n canvas,\n box: {\n x: a.left - b.left - root.clientLeft + root.scrollLeft,\n y: a.top - b.top - root.clientTop + root.scrollTop,\n width: a.width,\n height: a.height,\n },\n };\n };\n\n const read = useMemo(() => projectionsOf(optsRef), [optsRef]);\n\n const edit = useTextEdit({\n container,\n isEditorChrome: (el) => optsRef.current.isEditorChrome?.(el) ?? false,\n escape: options.escape,\n fontHold: options.fontHold,\n onStart: (id) => optsRef.current.onStart?.(id),\n onEnd: (id) => optsRef.current.onEnd?.(id),\n getText: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.text(node.data) : '';\n },\n getStyle: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.style(node.data) : undefined;\n },\n getPaint: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n if (!node) return undefined;\n const get = optsRef.current.getPaint;\n return get ? get(node.data) : { fill: node.data.fill, stroke: node.data.stroke };\n },\n getScreenPose: (id) => {\n const scene = sceneRef.current;\n const node = scene.get(asNodeId(id));\n if (!node) return null;\n const pose = scenePaintedPoseOf(scene)(node);\n const style = read.style(node.data);\n const at = surface();\n const view = resolveView(optsRef.current.view) ?? at?.canvas.getView();\n const box = screenBoxOf(pose, view, at?.box);\n return {\n ...box,\n // Against `zoom`, the same factor the overlay scales back up by, so a\n // `{ px }` size arrives on screen at the pixel count it names.\n fontSize: resolveScreenLength(\n style?.fontSize ?? optsRef.current.defaultFontSize ?? 16,\n box.zoom,\n ),\n verticalAlign: read.verticalAlign(node.data),\n };\n },\n getClipRect: () => surface()?.box ?? null,\n getRuns: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.runs(node.data) : undefined;\n },\n commit: (id, { text, runs, style }) => {\n const nid = asNodeId(id);\n const node = sceneRef.current.get(nid);\n if (!node) return;\n const { setText, setRuns, setStyle } = optsRef.current;\n let data = setText ? setText(node.data, text) : { ...node.data, text };\n if (runs) data = setRuns ? setRuns(data, runs) : { ...data, runs };\n if (style) data = setStyle ? setStyle(data, style) : { ...data, style };\n sceneRef.current.update(nid, { data });\n },\n });\n\n const onDoubleClick = useCallback((e: MouseEvent<HTMLElement>) => {\n // The dblclick bubbles from the canvas up to any wrapping container; the\n // element it started on is what the click coordinates are relative to.\n const canvas = e.target instanceof HTMLElement ? e.target : null;\n if (!canvas) return;\n // Inside the editor a double-click selects a word, and its target is a run\n // span whose box the click would be measured against as if it were a canvas.\n if (canvas.closest('[contenteditable=\"true\"]')) return;\n\n // `pointInTextPose` and `caretIndexAt` work in the node's own box: the click\n // is un-projected here, then taken back through the frame the node is drawn in.\n const [canvasX, canvasY] = clientToCanvas(canvas, e.clientX, e.clientY);\n const root = containerRef.current;\n const view = resolveView(optsRef.current.view)\n ?? (root ? findMountedCanvas(root, canvas)?.getView() : undefined);\n const cx = view ? canvasX / view.scale.x + view.x : canvasX;\n const cy = view ? canvasY / view.scale.y + view.y : canvasY;\n // Top-most-first hit test: renderOrder() is back-to-front, so iterate\n // in reverse and break on the first hit.\n const order = sceneRef.current.renderOrderNodes();\n const paintedPoseOf = scenePaintedPoseOf(sceneRef.current);\n for (let i = order.length - 1; i >= 0; i--) {\n const node = order[i];\n if (sceneRef.current.isLocked(node.id)) continue;\n if (!read.isText(node.data)) continue;\n const text = read.text(node.data);\n const at = paintedPoseOf(node);\n const p = worldToLocal(targetTransformOf(at), cx, cy);\n if (!p) continue;\n const pose = {\n x: at.x, y: at.y, width: at.width, height: at.height,\n text,\n runs: read.runs(node.data) as StyledRun[] | undefined,\n style: read.style(node.data),\n verticalAlign: read.verticalAlign(node.data),\n };\n if (!pointInTextPose(p.x, p.y, pose)) continue;\n\n openedOnRef.current = canvas;\n edit.startEdit(String(node.id), { caret: caretIndexAt(p.x, p.y, pose) });\n return;\n }\n }, [edit, containerRef, optsRef, read, sceneRef]);\n\n const isTextNode = useCallback((id: string): boolean => {\n const node = sceneRef.current.get(asNodeId(id));\n return node !== undefined && read.isText(node.data);\n }, [read, sceneRef]);\n\n return { ...edit, onDoubleClick, isTextNode };\n}\n\n/**\n * `pose`'s box as the overlay takes it, `origin` being the canvas's corner in\n * container pixels. Only the box center is projected, since the overlay's\n * frame is about it. Width and height stay in world units and reach the\n * screen through the overlay's own `scale(zoom)` — see\n * `TextEditScreenPose.zoom`.\n */\nfunction screenBoxOf(\n pose: RectPose,\n view: View | undefined,\n origin: { x: number; y: number } | undefined,\n): Pick<TextEditScreenPose, 'x' | 'y' | 'width' | 'height' | 'frame'> & { zoom: number } {\n const zoom = view ? view.scale.x : 1;\n const zoomY = view ? view.scale.y : 1;\n const cx = (origin?.x ?? 0) + (pose.x + pose.width / 2 - (view?.x ?? 0)) * zoom;\n const cy = (origin?.y ?? 0) + (pose.y + pose.height / 2 - (view?.y ?? 0)) * zoomY;\n return {\n x: cx - (pose.width * zoom) / 2,\n y: cy - (pose.height * zoom) / 2,\n width: pose.width,\n height: pose.height,\n zoom,\n frame: frameLinearOf(pose, zoomY / zoom),\n };\n}\n\n/** The linear part of the frame `pose` is drawn in, as the overlay takes it.\n * `stretch` is the view's y scale over its x scale: the overlay scales both\n * axes by the x scale, so the frame carries what is left of y. */\nfunction frameLinearOf(pose: unknown, stretch: number): TextEditScreenPose['frame'] {\n const m = poseFrameOf(pose);\n if (!m && stretch === 1) return undefined;\n const [a, b, c, d] = m ?? [1, 0, 0, 1];\n return [a, b * stretch, c, d * stretch];\n}\n"],"mappings":"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"}
|
|
@@ -1,49 +1,53 @@
|
|
|
1
1
|
//#region src/features/viewports/viewResolver.ts
|
|
2
2
|
function e(e) {
|
|
3
|
-
let { views: t, root: n,
|
|
4
|
-
|
|
3
|
+
let { views: t, root: n, toLocal: r, occluded: i } = e, a = /* @__PURE__ */ new Map(), o = (e, t, n) => ({
|
|
4
|
+
x: (e.x - t.x) / n.scale.x + n.x,
|
|
5
|
+
y: (e.y - t.y) / n.scale.y + n.y
|
|
6
|
+
});
|
|
7
|
+
function s(e) {
|
|
8
|
+
let t = n();
|
|
5
9
|
return {
|
|
6
10
|
id: null,
|
|
7
|
-
view:
|
|
8
|
-
|
|
11
|
+
view: t,
|
|
12
|
+
world: o(e, {
|
|
13
|
+
x: 0,
|
|
14
|
+
y: 0
|
|
15
|
+
}, t)
|
|
9
16
|
};
|
|
10
17
|
}
|
|
11
|
-
function
|
|
12
|
-
let t = r();
|
|
18
|
+
function c(e, t) {
|
|
13
19
|
return {
|
|
14
20
|
id: e.id,
|
|
15
21
|
view: e.view,
|
|
16
|
-
|
|
17
|
-
left: t.left + e.rect.x,
|
|
18
|
-
top: t.top + e.rect.y
|
|
19
|
-
}
|
|
22
|
+
world: o(t, e.rect, e.view)
|
|
20
23
|
};
|
|
21
24
|
}
|
|
22
|
-
function
|
|
23
|
-
let
|
|
24
|
-
for (let
|
|
25
|
-
let { rect:
|
|
26
|
-
if (
|
|
25
|
+
function l({ x: e, y: n }) {
|
|
26
|
+
let r = t();
|
|
27
|
+
for (let t = r.length - 1; t >= 0; t--) {
|
|
28
|
+
let { rect: a } = r[t];
|
|
29
|
+
if (e >= a.x && e < a.x + a.w && n >= a.y && n < a.y + a.h) return i?.(e, n) ? void 0 : r[t];
|
|
27
30
|
}
|
|
28
31
|
}
|
|
29
|
-
function
|
|
30
|
-
let
|
|
31
|
-
return
|
|
32
|
+
function u(e) {
|
|
33
|
+
let t = l(e);
|
|
34
|
+
return t ? c(t, e) : s(e);
|
|
32
35
|
}
|
|
33
36
|
return {
|
|
34
37
|
begin(e, t, n) {
|
|
35
|
-
let
|
|
36
|
-
return a.set(e,
|
|
38
|
+
let i = u(r(t, n));
|
|
39
|
+
return a.set(e, i.id), i;
|
|
37
40
|
},
|
|
38
|
-
at(e, n,
|
|
41
|
+
at(e, n, i) {
|
|
42
|
+
let o = r(n, i);
|
|
39
43
|
if (e !== null && a.has(e)) {
|
|
40
44
|
let n = a.get(e);
|
|
41
|
-
if (n === null) return o
|
|
45
|
+
if (n === null) return s(o);
|
|
42
46
|
let r = t().find((e) => e.id === n);
|
|
43
|
-
if (r) return
|
|
47
|
+
if (r) return c(r, o);
|
|
44
48
|
a.delete(e);
|
|
45
49
|
}
|
|
46
|
-
return
|
|
50
|
+
return u(o);
|
|
47
51
|
},
|
|
48
52
|
end(e) {
|
|
49
53
|
a.delete(e);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewResolver.js","names":["createViewResolver","opts","pinned","
|
|
1
|
+
{"version":3,"file":"viewResolver.js","names":["createViewResolver","opts","pinned","worldOf","at","from","view","rootTarget","root","target","v","hit","list","views","i","x","rect","y","occluded","fresh","t","toLocal","clientX","clientY","pointerId","id","c"],"sources":["../../../src/features/viewports/viewResolver.ts"],"sourcesContent":["import type { View } from 'core/viewport/view';\n\n/**\n * @experimental\n *\n * A view the resolver can route input to: a camera and the rect it paints\n * into, in canvas CSS-pixel space. A viewport node supplies one of these per\n * frame; so could any other per-view surface.\n */\nexport interface ResolvableView {\n id: string;\n view: View;\n rect: { x: number; y: number; w: number; h: number };\n}\n\n/**\n * @experimental\n *\n * The view an input event belongs to. `id` is `null` for the root view —\n * the whole canvas, when no viewport contains the point.\n */\nexport interface ViewTarget {\n id: string | null;\n view: View;\n /** The point asked about, in that view's world. */\n world: { x: number; y: number };\n}\n\n/**\n * @experimental\n *\n * Routes client points to views, and holds a captured pointer on the view its\n * gesture started in.\n *\n * Stickiness is the point. A drag that leaves its view's rect — over a\n * neighbouring view, or off the canvas — must keep reporting coordinates in\n * the space it began in, or a marquee crossing a panel edge silently starts\n * measuring against the wrong camera.\n */\nexport interface ViewResolver {\n /** Resolve and pin `pointerId`. Call on pointerdown. */\n begin(pointerId: number, clientX: number, clientY: number): ViewTarget;\n /**\n * The view for a point. A pinned `pointerId` gets its pinned view, looked\n * up fresh so a rect that moved mid-gesture is honored. Pass `null` for\n * input with no pointer to capture — wheel, hover, keys.\n */\n at(pointerId: number | null, clientX: number, clientY: number): ViewTarget;\n /** Release `pointerId`. Call on pointerup and pointercancel. */\n end(pointerId: number): void;\n /** Release every pin. */\n clear(): void;\n}\n\n/**\n * @experimental\n *\n * Options for `createViewResolver`. Each field is a function called afresh on\n * every query, so views and the canvas may move between events.\n */\nexport interface CreateViewResolverOpts {\n /** Candidate views in paint order — the last one containing a point wins. */\n views: () => readonly ResolvableView[];\n /** The camera for points no view claims. */\n root: () => View;\n /** A client point in the canvas's own CSS pixels, from its top-left. */\n toLocal: (clientX: number, clientY: number) => { x: number; y: number };\n /**\n * Whether something painted over every view claims a canvas-local point —\n * chrome on the surface's own frame. Such a point resolves to the root even\n * inside a view's rect. Asked only where a view would otherwise win.\n */\n occluded?: (x: number, y: number) => boolean;\n}\n\n/** @experimental Build a `ViewResolver` over `opts.views`, falling back to `opts.root`. */\nexport function createViewResolver(opts: CreateViewResolverOpts): ViewResolver {\n const { views, root, toLocal, occluded } = opts;\n const pinned = new Map<number, string | null>();\n\n type Local = { x: number; y: number };\n /** `at`, a canvas point `from` its surface's top-left, through `view`. */\n const worldOf = (at: Local, from: Local, view: View): Local => ({\n x: (at.x - from.x) / view.scale.x + view.x,\n y: (at.y - from.y) / view.scale.y + view.y,\n });\n\n function rootTarget(at: Local): ViewTarget {\n const view = root();\n return { id: null, view, world: worldOf(at, { x: 0, y: 0 }, view) };\n }\n\n function target(v: ResolvableView, at: Local): ViewTarget {\n return { id: v.id, view: v.view, world: worldOf(at, v.rect, v.view) };\n }\n\n /** Right and bottom edges are exclusive, so neighbouring views never both\n * claim a pixel. */\n function hit({ x, y }: Local): ResolvableView | undefined {\n const list = views();\n for (let i = list.length - 1; i >= 0; i--) {\n const { rect } = list[i]!;\n if (x >= rect.x && x < rect.x + rect.w && y >= rect.y && y < rect.y + rect.h) {\n return occluded?.(x, y) ? undefined : list[i];\n }\n }\n return undefined;\n }\n\n function fresh(at: Local): ViewTarget {\n const v = hit(at);\n return v ? target(v, at) : rootTarget(at);\n }\n\n return {\n begin(pointerId, clientX, clientY) {\n const t = fresh(toLocal(clientX, clientY));\n pinned.set(pointerId, t.id);\n return t;\n },\n at(pointerId, clientX, clientY) {\n const at = toLocal(clientX, clientY);\n if (pointerId !== null && pinned.has(pointerId)) {\n const id = pinned.get(pointerId)!;\n if (id === null) return rootTarget(at);\n const v = views().find((c) => c.id === id);\n if (v) return target(v, at);\n pinned.delete(pointerId);\n }\n return fresh(at);\n },\n end(pointerId) {\n pinned.delete(pointerId);\n },\n clear() {\n pinned.clear();\n },\n };\n}\n"],"mappings":";AA4EA,SAAgBA,EAAmB,GAA4C;CAC7E,IAAM,EAAE,UAAO,SAAM,YAAS,gBAAaC,GACrCC,oBAAS,IAAI,IAA2B,GAIxCC,KAAW,GAAW,GAAa,OAAuB;EAC9D,IAAIC,EAAG,IAAIC,EAAK,KAAKC,EAAK,MAAM,IAAIA,EAAK;EACzC,IAAIF,EAAG,IAAIC,EAAK,KAAKC,EAAK,MAAM,IAAIA,EAAK;CAC3C;CAEA,SAASC,EAAW,GAAuB;EACzC,IAAMD,IAAOE,EAAK;EAClB,OAAO;GAAE,IAAI;GAAM;GAAM,OAAOL,EAAQC,GAAI;IAAE,GAAG;IAAG,GAAG;GAAE,GAAGE,CAAI;EAAE;CACpE;CAEA,SAASG,EAAO,GAAmB,GAAuB;EACxD,OAAO;GAAE,IAAIC,EAAE;GAAI,MAAMA,EAAE;GAAM,OAAOP,EAAQC,GAAIM,EAAE,MAAMA,EAAE,IAAI;EAAE;CACtE;CAIA,SAASC,EAAI,EAAE,MAAG,QAAwC;EACxD,IAAMC,IAAOC,EAAM;EACnB,KAAK,IAAIC,IAAIF,EAAK,SAAS,GAAGE,KAAK,GAAG,KAAK;GACzC,IAAM,EAAE,YAASF,EAAKE;GACtB,IAAIC,KAAKC,EAAK,KAAKD,IAAIC,EAAK,IAAIA,EAAK,KAAKC,KAAKD,EAAK,KAAKC,IAAID,EAAK,IAAIA,EAAK,GACzE,OAAOE,IAAWH,GAAGE,CAAC,IAAI,KAAA,IAAYL,EAAKE;EAE/C;CAEF;CAEA,SAASK,EAAM,GAAuB;EACpC,IAAMT,IAAIC,EAAIP,CAAE;EAChB,OAAOM,IAAID,EAAOC,GAAGN,CAAE,IAAIG,EAAWH,CAAE;CAC1C;CAEA,OAAO;EACL,MAAM,GAAW,GAAS,GAAS;GACjC,IAAMgB,IAAID,EAAME,EAAQC,GAASC,CAAO,CAAC;GAEzC,OADArB,EAAO,IAAIsB,GAAWJ,EAAE,EAAE,GACnBA;EACT;EACA,GAAG,GAAW,GAAS,GAAS;GAC9B,IAAMhB,IAAKiB,EAAQC,GAASC,CAAO;GACnC,IAAIC,MAAc,QAAQtB,EAAO,IAAIsB,CAAS,GAAG;IAC/C,IAAMC,IAAKvB,EAAO,IAAIsB,CAAS;IAC/B,IAAIC,MAAO,MAAM,OAAOlB,EAAWH,CAAE;IACrC,IAAMM,IAAIG,EAAM,CAAC,CAAC,MAAM,MAAMa,EAAE,OAAOD,CAAE;IACzC,IAAIf,GAAG,OAAOD,EAAOC,GAAGN,CAAE;IAC1B,EAAO,OAAOoB,CAAS;GACzB;GACA,OAAOL,EAAMf,CAAE;EACjB;EACA,IAAI,GAAW;GACb,EAAO,OAAOoB,CAAS;EACzB;EACA,QAAQ;GACN,EAAO,MAAM;EACf;CACF;AACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ICON_SVG_BASE as e } from "./_base.js";
|
|
2
|
+
import { jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
3
|
+
//#region src/icons/SliceIcon.tsx
|
|
4
|
+
function r({ className: r, size: i = 20 }) {
|
|
5
|
+
return /* @__PURE__ */ n("svg", {
|
|
6
|
+
...e,
|
|
7
|
+
className: r,
|
|
8
|
+
width: i,
|
|
9
|
+
height: i,
|
|
10
|
+
children: [/* @__PURE__ */ t("path", {
|
|
11
|
+
d: "M 8.5 10.5 L 14.5 4.5 L 16.5 6.5 L 10.5 12.5",
|
|
12
|
+
strokeLinejoin: "round",
|
|
13
|
+
strokeLinecap: "round"
|
|
14
|
+
}), /* @__PURE__ */ t("path", {
|
|
15
|
+
d: "M 8.5 10.5 L 3.5 15.5 L 10.5 12.5 Z",
|
|
16
|
+
fill: "currentColor",
|
|
17
|
+
strokeLinejoin: "round"
|
|
18
|
+
})]
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { r as default };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=SliceIcon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SliceIcon.js","names":["SliceIcon","ICON_SVG_BASE","size"],"sources":["../../src/icons/SliceIcon.tsx"],"sourcesContent":["import { ICON_SVG_BASE } from './_base';\nimport type { IconProps } from './types';\n\n/** Knife — an outlined handle on the diagonal with a filled blade whose\n * spine continues the handle's upper edge to the tip at lower-left. Used\n * for `useSliceTool`. */\nexport default function SliceIcon({ className, size = 20 }: IconProps) {\n return (\n <svg\n {...ICON_SVG_BASE}\n className={className}\n width={size}\n height={size}\n >\n {/* Handle, open where the blade seats */}\n <path d=\"M 8.5 10.5 L 14.5 4.5 L 16.5 6.5 L 10.5 12.5\" strokeLinejoin=\"round\" strokeLinecap=\"round\" />\n {/* Blade */}\n <path d=\"M 8.5 10.5 L 3.5 15.5 L 10.5 12.5 Z\" fill=\"currentColor\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n"],"mappings":";;;AAMA,SAAwBA,EAAU,EAAE,cAAW,UAAO,MAAiB;CACrE,OACE,kBAAC,OAAD;EACE,GAAIC;EACO;EACX,OAAOC;EACP,QAAQA;EAJV,UAAA,CAOE,kBAAC,QAAD;GAAM,GAAE;GAA+C,gBAAe;GAAQ,eAAc;EAAS,CAAA,GAErG,kBAAC,QAAD;GAAM,GAAE;GAAsC,MAAK;GAAe,gBAAe;EAAS,CAAA,CACvF;;AAET"}
|