@weasel-js/core 1.9.3 → 1.9.4
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 +356 -0
- package/README.md +2 -2
- package/dist/WeaselProvider.js +5 -5
- package/dist/affordances/composeAffordanceLayer.js +10 -20
- package/dist/affordances/composeAffordanceLayer.js.map +1 -1
- package/dist/affordances/cornerResize.js +25 -17
- package/dist/affordances/cornerResize.js.map +1 -1
- package/dist/affordances/hitAffordanceRegions.js +27 -20
- package/dist/affordances/hitAffordanceRegions.js.map +1 -1
- package/dist/affordances/rotationHandle.js +18 -18
- package/dist/affordances/rotationHandle.js.map +1 -1
- package/dist/animation/behaviors/momentum.js +93 -55
- package/dist/animation/behaviors/momentum.js.map +1 -1
- package/dist/animation/loop.js +10 -12
- package/dist/animation/loop.js.map +1 -1
- package/dist/animation/reflow.js +8 -8
- package/dist/animation/reflow.js.map +1 -1
- package/dist/animation/stagger.js +64 -56
- package/dist/animation/stagger.js.map +1 -1
- package/dist/animation/timeline/booking.js +62 -54
- package/dist/animation/timeline/booking.js.map +1 -1
- package/dist/animation/timeline/createTimeline.js +85 -76
- package/dist/animation/timeline/createTimeline.js.map +1 -1
- package/dist/animation/timeline/sampleTrack.js +13 -5
- package/dist/animation/timeline/sampleTrack.js.map +1 -1
- package/dist/animation/useAnimator.js +45 -35
- package/dist/animation/useAnimator.js.map +1 -1
- package/dist/animation/wrappers/animateLifecycle.js +31 -24
- package/dist/animation/wrappers/animateLifecycle.js.map +1 -1
- package/dist/animation/wrappers/animateOnSetPose.js +28 -26
- package/dist/animation/wrappers/animateOnSetPose.js.map +1 -1
- package/dist/animation/wrappers/instantPose.js +13 -0
- package/dist/animation/wrappers/instantPose.js.map +1 -0
- package/dist/{poseDescriptor-D-OH-tu5.d.ts → autoPoseDescriptor-Ct7yqivU.d.ts} +28 -3
- package/dist/barrel/chrome.js +16 -0
- package/dist/barrel/input.js +19 -0
- package/dist/barrel/interactions.js +42 -0
- package/dist/barrel/paint.js +18 -0
- package/dist/barrel/paths.js +19 -0
- package/dist/barrel/renderer.js +20 -0
- package/dist/barrel/routing.js +51 -0
- package/dist/barrel/text.js +18 -0
- package/dist/barrel/viewport.js +52 -0
- package/dist/builtins-DPcdghtB.d.ts +1223 -0
- package/dist/canvas/Canvas.js +363 -448
- package/dist/canvas/Canvas.js.map +1 -1
- package/dist/canvas/CanvasView.js +164 -165
- package/dist/canvas/CanvasView.js.map +1 -1
- package/dist/canvas/CursorCoordsHud.js +37 -32
- package/dist/canvas/CursorCoordsHud.js.map +1 -1
- package/dist/canvas/DrawCanvas.js +49 -43
- package/dist/canvas/DrawCanvas.js.map +1 -1
- package/dist/canvas/MinimapCanvas.js +26 -25
- package/dist/canvas/MinimapCanvas.js.map +1 -1
- package/dist/canvas/NodeShape.js +59 -377
- package/dist/canvas/NodeShape.js.map +1 -1
- package/dist/canvas/PickHud.js +50 -47
- package/dist/canvas/PickHud.js.map +1 -1
- package/dist/canvas/SceneCanvas/GestureDispatcherMounter.js +167 -0
- package/dist/canvas/SceneCanvas/GestureDispatcherMounter.js.map +1 -0
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +13 -13
- package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js +67 -0
- package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js.map +1 -0
- package/dist/canvas/SceneCanvas/ToolKeybindingsMounter.js +16 -0
- package/dist/canvas/SceneCanvas/ToolKeybindingsMounter.js.map +1 -0
- package/dist/canvas/SceneCanvas/coordTrace.js +10 -0
- package/dist/canvas/SceneCanvas/coordTrace.js.map +1 -0
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js +112 -70
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js +9 -8
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
- package/dist/canvas/SceneCanvas/features.js +1 -0
- package/dist/canvas/SceneCanvas/features.js.map +1 -1
- package/dist/canvas/SceneCanvas/isDev.js +12 -0
- package/dist/canvas/SceneCanvas/isDev.js.map +1 -0
- package/dist/canvas/SceneCanvas/poseGeometry.js +29 -28
- package/dist/canvas/SceneCanvas/poseGeometry.js.map +1 -1
- package/dist/canvas/SceneCanvas/poseRegistrars.js +13 -0
- package/dist/canvas/SceneCanvas/poseRegistrars.js.map +1 -0
- package/dist/canvas/SceneCanvas/props.js +38 -0
- package/dist/canvas/SceneCanvas/props.js.map +1 -0
- package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js +21 -62
- package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js +46 -48
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js +33 -33
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
- package/dist/canvas/SceneCanvas.js +534 -788
- package/dist/canvas/SceneCanvas.js.map +1 -1
- package/dist/canvas/SceneViewCanvas.js +45 -43
- package/dist/canvas/SceneViewCanvas.js.map +1 -1
- package/dist/canvas/buildSceneLayer.js +91 -0
- package/dist/canvas/buildSceneLayer.js.map +1 -0
- package/dist/canvas/buildSceneTree.js +16 -19
- package/dist/canvas/buildSceneTree.js.map +1 -1
- package/dist/canvas/canvasRenderer.js +68 -52
- package/dist/canvas/canvasRenderer.js.map +1 -1
- package/dist/canvas/deps/changes.js +13 -0
- package/dist/canvas/deps/changes.js.map +1 -0
- package/dist/canvas/deps/editAnchors.js +28 -28
- package/dist/canvas/deps/insert.js +119 -91
- package/dist/canvas/deps/insert.js.map +1 -1
- package/dist/canvas/deps/slice.js +46 -45
- package/dist/canvas/deps/slice.js.map +1 -1
- package/dist/canvas/deps/textEdit.js +10 -9
- package/dist/canvas/deps/textEdit.js.map +1 -1
- package/dist/canvas/derivedPath.js +46 -23
- package/dist/canvas/derivedPath.js.map +1 -1
- package/dist/canvas/getNodeAtPoint.js +7 -7
- package/dist/canvas/getNodeAtPoint.js.map +1 -1
- package/dist/canvas/hud.module.js +1 -1
- package/dist/canvas/hud.module.js.map +1 -1
- package/dist/canvas/kitRequirements.js +2 -2
- package/dist/canvas/kitRequirements.js.map +1 -1
- package/dist/canvas/layerOrder.js +13 -6
- package/dist/canvas/layerOrder.js.map +1 -1
- package/dist/canvas/minimapMath.js +12 -10
- package/dist/canvas/minimapMath.js.map +1 -1
- package/dist/canvas/nodeShapes/derivedPainter.js +34 -0
- package/dist/canvas/nodeShapes/derivedPainter.js.map +1 -0
- package/dist/canvas/nodeShapes/imagePainter.js +87 -0
- package/dist/canvas/nodeShapes/imagePainter.js.map +1 -0
- package/dist/canvas/nodeShapes/memo.js +9 -0
- package/dist/canvas/nodeShapes/memo.js.map +1 -0
- package/dist/canvas/nodeShapes/nodePaint.js +57 -0
- package/dist/canvas/nodeShapes/nodePaint.js.map +1 -0
- package/dist/canvas/nodeShapes/pathPainter.js +38 -0
- package/dist/canvas/nodeShapes/pathPainter.js.map +1 -0
- package/dist/canvas/nodeShapes/poseBox.js +20 -0
- package/dist/canvas/nodeShapes/poseBox.js.map +1 -0
- package/dist/canvas/nodeShapes/rectFallbackPainter.js +38 -0
- package/dist/canvas/nodeShapes/rectFallbackPainter.js.map +1 -0
- package/dist/canvas/nodeShapes/shapePainter.js +72 -0
- package/dist/canvas/nodeShapes/shapePainter.js.map +1 -0
- package/dist/canvas/nodeShapes/textPainter.js +55 -0
- package/dist/canvas/nodeShapes/textPainter.js.map +1 -0
- package/dist/canvas/overlayRoleStrokes.js.map +1 -1
- package/dist/canvas/paintCull.js +10 -11
- package/dist/canvas/paintCull.js.map +1 -1
- package/dist/canvas/pickWalk.js +52 -63
- package/dist/canvas/pickWalk.js.map +1 -1
- package/dist/canvas/poseRotation.js +11 -23
- package/dist/canvas/poseRotation.js.map +1 -1
- package/dist/canvas/renderDebugSnapshot.js +5 -5
- package/dist/canvas/renderSceneToPixels.js +3 -1
- package/dist/canvas/renderSceneToPixels.js.map +1 -1
- package/dist/canvas/sceneAdapter.js +66 -148
- package/dist/canvas/sceneAdapter.js.map +1 -1
- package/dist/canvas/sceneClipboard.js +112 -0
- package/dist/canvas/sceneClipboard.js.map +1 -0
- package/dist/canvas/sceneSlotWiring.js +4 -4
- package/dist/canvas/sceneSlotWiring.js.map +1 -1
- package/dist/canvas/sceneViewRender.js +39 -40
- package/dist/canvas/sceneViewRender.js.map +1 -1
- package/dist/canvas/useCanvasRenderer.js +14 -6
- package/dist/canvas/useCanvasRenderer.js.map +1 -1
- package/dist/canvas/useCanvasView.js +58 -0
- package/dist/canvas/useCanvasView.js.map +1 -0
- package/dist/canvas/useFrameLoop.js +35 -26
- package/dist/canvas/useFrameLoop.js.map +1 -1
- package/dist/canvas/useSceneLayerList.js +21 -0
- package/dist/canvas/useSceneLayerList.js.map +1 -0
- package/dist/clipboard.d.ts +10 -6
- package/dist/clone.d.ts +4 -3
- package/dist/core/adapters/arrayAdapter.js +48 -39
- package/dist/core/adapters/arrayAdapter.js.map +1 -1
- package/dist/core/device/index.js +5 -4
- package/dist/core/device/useDeviceProfile.js +38 -44
- package/dist/core/device/useDeviceProfile.js.map +1 -1
- package/dist/core/device/watchDevicePixelRatio.js +17 -0
- package/dist/core/device/watchDevicePixelRatio.js.map +1 -0
- package/dist/core/fillInPoseFrame.js.map +1 -1
- package/dist/core/geometry/poseDescriptor.js +21 -19
- package/dist/core/geometry/poseDescriptor.js.map +1 -1
- package/dist/core/geometry/poseFrame.js +44 -0
- package/dist/core/geometry/poseFrame.js.map +1 -0
- package/dist/core/geometry/poseRotation.js.map +1 -1
- package/dist/core/geometry/regionHit.js +9 -10
- package/dist/core/geometry/regionHit.js.map +1 -1
- package/dist/core/geometry/unionBounds.js +31 -29
- package/dist/core/geometry/unionBounds.js.map +1 -1
- package/dist/core/isPlainObject.js +2 -11
- package/dist/core/ops/arrange.js +1 -0
- package/dist/core/ops/arrange.js.map +1 -1
- package/dist/core/ops/create.js +10 -5
- package/dist/core/ops/create.js.map +1 -1
- package/dist/core/ops/delete.js +12 -24
- package/dist/core/ops/delete.js.map +1 -1
- package/dist/core/ops/reorder/index.js +43 -40
- package/dist/core/ops/reorder/index.js.map +1 -1
- package/dist/core/ops/reorder/setChildOrder.js +34 -0
- package/dist/core/ops/reorder/setChildOrder.js.map +1 -0
- package/dist/core/paintKinds.js +5 -5
- package/dist/core/paintKinds.js.map +1 -1
- package/dist/core/scene/NodeProperties.js.map +1 -1
- package/dist/core/scene/appliedLog.js +37 -0
- package/dist/core/scene/appliedLog.js.map +1 -0
- package/dist/core/scene/arrivalWindow.js +101 -0
- package/dist/core/scene/arrivalWindow.js.map +1 -0
- package/dist/core/scene/derivedPath.js.map +1 -1
- package/dist/core/scene/historyFacade.js +84 -0
- package/dist/core/scene/historyFacade.js.map +1 -0
- package/dist/core/scene/kitOps.js +173 -0
- package/dist/core/scene/kitOps.js.map +1 -0
- package/dist/core/scene/layerStack.js +38 -0
- package/dist/core/scene/layerStack.js.map +1 -0
- package/dist/core/scene/lockGuard.js +37 -0
- package/dist/core/scene/lockGuard.js.map +1 -0
- package/dist/core/scene/nodeFnFields.js +5 -6
- package/dist/core/scene/nodeFnFields.js.map +1 -1
- package/dist/core/scene/nodeMemo.js +45 -19
- package/dist/core/scene/nodeMemo.js.map +1 -1
- package/dist/core/scene/nodeStore.js +126 -0
- package/dist/core/scene/nodeStore.js.map +1 -0
- package/dist/core/scene/pickability.js +6 -0
- package/dist/core/scene/pickability.js.map +1 -0
- package/dist/core/scene/poseFeed.js +38 -38
- package/dist/core/scene/poseFeed.js.map +1 -1
- package/dist/core/scene/poseOverrides.js +34 -38
- package/dist/core/scene/poseOverrides.js.map +1 -1
- package/dist/core/scene/renderOrder.js +84 -0
- package/dist/core/scene/renderOrder.js.map +1 -0
- package/dist/core/scene/scene.js +289 -866
- package/dist/core/scene/scene.js.map +1 -1
- package/dist/core/scene/serialization.js +68 -0
- package/dist/core/scene/serialization.js.map +1 -0
- package/dist/core/scene/treeOrder.js +13 -0
- package/dist/core/scene/treeOrder.js.map +1 -0
- package/dist/core/scene/types.js.map +1 -1
- package/dist/core/viewport/meanScale.js +1 -1
- package/dist/core/viewport/meanScale.js.map +1 -1
- package/dist/core/viewport/view.js +12 -12
- package/dist/core/viewport/view.js.map +1 -1
- package/dist/core/viewport/zoomBounds.js +10 -8
- package/dist/core/viewport/zoomBounds.js.map +1 -1
- package/dist/{cornerHandles-BCrDp_mH.d.ts → cornerHandles-CtCb8a3G.d.ts} +1 -1
- package/dist/debug/createDebugOverlayLayer.js +14 -14
- package/dist/debug/createDebugOverlayLayer.js.map +1 -1
- package/dist/debug/flag.js +2 -41
- package/dist/features/chrome-caps/useHoverTracking.js +22 -17
- package/dist/features/chrome-caps/useHoverTracking.js.map +1 -1
- package/dist/features/focus/gateLayer.js +3 -4
- package/dist/features/focus/gateLayer.js.map +1 -1
- package/dist/features/images/imageCache.js +19 -9
- package/dist/features/images/imageCache.js.map +1 -1
- package/dist/features/ingestion/contentHandlers.js +14 -11
- package/dist/features/ingestion/contentHandlers.js.map +1 -1
- package/dist/features/ingestion/index.js +1 -1
- package/dist/features/ingestion/registerKitHandlers.js +7 -7
- package/dist/features/ingestion/weaselJsonHandler.js +17 -14
- package/dist/features/ingestion/weaselJsonHandler.js.map +1 -1
- package/dist/features/meshPaint/lazyKind.js +201 -35
- package/dist/features/meshPaint/lazyKind.js.map +1 -1
- package/dist/features/meshPaint/meshPaint.js +82 -79
- package/dist/features/meshPaint/meshPaint.js.map +1 -1
- package/dist/features/minimap/createMinimapContribution.js +42 -42
- package/dist/features/minimap/layers.js +44 -62
- package/dist/features/minimap/layers.js.map +1 -1
- package/dist/features/parallax/createParallaxPlane.js +10 -14
- package/dist/features/parallax/createParallaxPlane.js.map +1 -1
- package/dist/features/paths/anchorEdits.js +19 -8
- package/dist/features/paths/anchorEdits.js.map +1 -1
- package/dist/features/paths/anchors.js +31 -26
- package/dist/features/paths/anchors.js.map +1 -1
- package/dist/features/paths/booleans.js +2 -2
- package/dist/features/paths/index.js +13 -11
- package/dist/features/paths/markerCommands.js +37 -36
- package/dist/features/paths/markerCommands.js.map +1 -1
- package/dist/features/paths/pathInWorld.js +19 -19
- package/dist/features/paths/pathInWorld.js.map +1 -1
- package/dist/features/paths/pathLayer.js.map +1 -1
- package/dist/features/paths/strokeToPath.js +40 -0
- package/dist/features/paths/strokeToPath.js.map +1 -0
- package/dist/features/paths/tessellate/stroke.js.map +1 -1
- package/dist/features/patterns/commandPaint.js +18 -0
- package/dist/features/patterns/commandPaint.js.map +1 -0
- package/dist/features/patterns/index.js +5 -17
- package/dist/features/patterns/index.js.map +1 -1
- package/dist/features/patterns/rasterizeTile.js +17 -0
- package/dist/features/patterns/rasterizeTile.js.map +1 -0
- package/dist/features/patterns/resolveSpec.js +52 -44
- package/dist/features/patterns/resolveSpec.js.map +1 -1
- package/dist/features/poseRun/usePoseRun.js +8 -3
- package/dist/features/poseRun/usePoseRun.js.map +1 -1
- package/dist/features/selection/SelectionContext.js +5 -0
- package/dist/features/selection/SelectionContext.js.map +1 -1
- package/dist/features/selection/overlay.js +18 -18
- package/dist/features/selection/overlay.js.map +1 -1
- package/dist/features/text/domOffsets.js +82 -0
- package/dist/features/text/domOffsets.js.map +1 -0
- package/dist/features/text/domRuns.js +103 -131
- package/dist/features/text/domRuns.js.map +1 -1
- package/dist/features/text/hitTest.js +5 -2
- package/dist/features/text/hitTest.js.map +1 -1
- package/dist/features/text/isTextData.js +8 -0
- package/dist/features/text/isTextData.js.map +1 -0
- package/dist/features/text/overlayDirection.js +15 -0
- package/dist/features/text/overlayDirection.js.map +1 -0
- package/dist/features/text/runs/rangeStyle.js +32 -34
- package/dist/features/text/runs/rangeStyle.js.map +1 -1
- package/dist/features/text/textCommand.js +34 -33
- package/dist/features/text/textCommand.js.map +1 -1
- package/dist/features/text/textToPath.js +40 -40
- package/dist/features/text/textToPath.js.map +1 -1
- package/dist/features/text/useSceneTextEdit.js +76 -82
- package/dist/features/text/useSceneTextEdit.js.map +1 -1
- package/dist/features/text/useTextEdit.js +184 -160
- package/dist/features/text/useTextEdit.js.map +1 -1
- package/dist/features/tiling/createTiledLayer.js +24 -22
- package/dist/features/tiling/createTiledLayer.js.map +1 -1
- package/dist/index.d.ts +11033 -7749
- package/dist/index.js +316 -309
- package/dist/input/keyState.js +42 -43
- package/dist/input/keyState.js.map +1 -1
- package/dist/input/useKeyModifiers.js +11 -0
- package/dist/input/useKeyModifiers.js.map +1 -0
- package/dist/interactions/actions/align/align.js +8 -8
- package/dist/interactions/actions/clipboard/clipboardOps.js +34 -32
- package/dist/interactions/actions/clipboard/clipboardOps.js.map +1 -1
- package/dist/interactions/actions/clipboard/materializePaste.js +10 -7
- package/dist/interactions/actions/clipboard/materializePaste.js.map +1 -1
- package/dist/interactions/actions/clipboard/wireFormat.js.map +1 -1
- package/dist/interactions/actions/clone/behaviors/cloneByAltDrag.js.map +1 -1
- package/dist/interactions/actions/defaultCommitAdapter.js +20 -18
- package/dist/interactions/actions/defaultCommitAdapter.js.map +1 -1
- package/dist/interactions/actions/defaults/align.js +9 -10
- package/dist/interactions/actions/defaults/align.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorEditing.js +59 -81
- package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
- package/dist/interactions/actions/defaults/areaSelect.js +35 -38
- package/dist/interactions/actions/defaults/areaSelect.js.map +1 -1
- package/dist/interactions/actions/defaults/clipboard.js +26 -10
- package/dist/interactions/actions/defaults/clipboard.js.map +1 -1
- package/dist/interactions/actions/defaults/clone.js +44 -60
- package/dist/interactions/actions/defaults/clone.js.map +1 -1
- package/dist/interactions/actions/defaults/copySubtree.js +40 -0
- package/dist/interactions/actions/defaults/copySubtree.js.map +1 -0
- package/dist/interactions/actions/defaults/distribute.js +14 -13
- package/dist/interactions/actions/defaults/distribute.js.map +1 -1
- package/dist/interactions/actions/defaults/duplicate.js +17 -57
- package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
- package/dist/interactions/actions/defaults/editAnchors.js +18 -18
- package/dist/interactions/actions/defaults/enterTextEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/flip.js +52 -46
- package/dist/interactions/actions/defaults/flip.js.map +1 -1
- package/dist/interactions/actions/defaults/group.js +43 -48
- package/dist/interactions/actions/defaults/group.js.map +1 -1
- package/dist/interactions/actions/defaults/ingest.js +35 -33
- package/dist/interactions/actions/defaults/ingest.js.map +1 -1
- package/dist/interactions/actions/defaults/insert.js +50 -51
- package/dist/interactions/actions/defaults/insert.js.map +1 -1
- package/dist/interactions/actions/defaults/insertPathAnchor.js +7 -7
- package/dist/interactions/actions/defaults/lassoSelect.js +67 -70
- package/dist/interactions/actions/defaults/lassoSelect.js.map +1 -1
- package/dist/interactions/actions/defaults/move.js +267 -249
- package/dist/interactions/actions/defaults/move.js.map +1 -1
- package/dist/interactions/actions/defaults/nudge.js +40 -68
- package/dist/interactions/actions/defaults/nudge.js.map +1 -1
- package/dist/interactions/actions/defaults/nudgeSteps.js +37 -0
- package/dist/interactions/actions/defaults/nudgeSteps.js.map +1 -0
- package/dist/interactions/actions/defaults/reorder.js +2 -0
- package/dist/interactions/actions/defaults/reorder.js.map +1 -1
- package/dist/interactions/actions/defaults/resize.js +104 -98
- package/dist/interactions/actions/defaults/resize.js.map +1 -1
- package/dist/interactions/actions/defaults/rotate.js +111 -110
- package/dist/interactions/actions/defaults/rotate.js.map +1 -1
- package/dist/interactions/actions/defaults/setFill.js +7 -7
- package/dist/interactions/actions/defaults/setFillOpacity.js +4 -4
- package/dist/interactions/actions/defaults/setStroke.js +12 -12
- package/dist/interactions/actions/defaults/setStrokeOpacity.js +6 -6
- package/dist/interactions/actions/defaults/sliceOps.js +19 -19
- package/dist/interactions/actions/defaults/viewportDragPan.js +37 -26
- package/dist/interactions/actions/defaults/viewportDragPan.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/geometry.js +28 -23
- package/dist/interactions/actions/edit-anchors/geometry.js.map +1 -1
- package/dist/interactions/actions/flip/helpers.js +30 -17
- package/dist/interactions/actions/flip/helpers.js.map +1 -1
- package/dist/interactions/actions/hitSelection.js +8 -0
- package/dist/interactions/actions/hitSelection.js.map +1 -0
- package/dist/interactions/actions/lasso-select/behaviors/selectFromLasso.js +14 -18
- package/dist/interactions/actions/lasso-select/behaviors/selectFromLasso.js.map +1 -1
- package/dist/interactions/actions/move/behaviors/snapBackOrDelete.js +5 -5
- package/dist/interactions/actions/move/behaviors/snapBackOrDelete.js.map +1 -1
- package/dist/interactions/actions/move/behaviors/snapToContainer.js +32 -21
- package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
- package/dist/interactions/actions/move/gestureAdapter.js +32 -15
- package/dist/interactions/actions/move/gestureAdapter.js.map +1 -1
- package/dist/interactions/actions/move/landedDescendants.js +33 -0
- package/dist/interactions/actions/move/landedDescendants.js.map +1 -0
- package/dist/interactions/actions/outlines/createOutlines.js +18 -18
- package/dist/interactions/actions/poseDescriptorDep.js +16 -4
- package/dist/interactions/actions/poseDescriptorDep.js.map +1 -1
- package/dist/interactions/actions/poseFrame.js +11 -6
- package/dist/interactions/actions/poseFrame.js.map +1 -1
- package/dist/interactions/actions/previewOverrides.js +5 -5
- package/dist/interactions/actions/previewOverrides.js.map +1 -1
- package/dist/interactions/actions/selectionSubtree.js +69 -0
- package/dist/interactions/actions/selectionSubtree.js.map +1 -0
- package/dist/interactions/actions/useStandardActions.js +66 -62
- package/dist/interactions/actions/useStandardActions.js.map +1 -1
- package/dist/interactions/gestures/dragGesture/dragGesture.js +4 -7
- package/dist/interactions/gestures/dragGesture/dragGesture.js.map +1 -1
- package/dist/interactions/gestures/dragGesture/dragPointOf.js +23 -0
- package/dist/interactions/gestures/dragGesture/dragPointOf.js.map +1 -0
- package/dist/interactions/gestures/handleDrag/handleDrag.js +21 -26
- package/dist/interactions/gestures/handleDrag/handleDrag.js.map +1 -1
- package/dist/interactions/gestures/pointerDrag/pointerDrag.js +8 -6
- package/dist/interactions/gestures/pointerDrag/pointerDrag.js.map +1 -1
- package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js +8 -4
- package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js.map +1 -1
- package/dist/{math-Drrw4ewZ.d.ts → math-J-ACHyEg.d.ts} +1 -2
- package/dist/math.d.ts +2 -3
- package/dist/move.d.ts +12 -11
- package/dist/{originProjection-DEklpDc_.d.ts → originProjection-gHnOup4e.d.ts} +1 -1
- package/dist/{registerProgram-BMZRDgrh.d.ts → registerProgram-T9S_PfAX.d.ts} +18 -7
- package/dist/renderer/DrawCommand.js.map +1 -1
- package/dist/renderer/WeaselRenderer.js +75 -73
- package/dist/renderer/WeaselRenderer.js.map +1 -1
- package/dist/renderer/cache/GLImageCache.js +15 -5
- package/dist/renderer/cache/GLImageCache.js.map +1 -1
- package/dist/renderer/cache/GLMeshCache.js +23 -23
- package/dist/renderer/cache/GLMeshCache.js.map +1 -1
- package/dist/renderer/cache/GLTextureCache.js +18 -1
- package/dist/renderer/cache/GLTextureCache.js.map +1 -1
- package/dist/renderer/cache/cache.js.map +1 -1
- package/dist/renderer/cache/markerCommandCache.js.map +1 -1
- package/dist/renderer/cache/strokeMeshCache.js.map +1 -1
- package/dist/renderer/cullDrawCommands.js +11 -11
- package/dist/renderer/draw/batch.js +133 -0
- package/dist/renderer/draw/batch.js.map +1 -0
- package/dist/renderer/draw/clip.js +89 -0
- package/dist/renderer/draw/clip.js.map +1 -0
- package/dist/renderer/draw/customShader.js +230 -0
- package/dist/renderer/draw/customShader.js.map +1 -0
- package/dist/renderer/draw/drawTriangles.js +8 -0
- package/dist/renderer/draw/drawTriangles.js.map +1 -0
- package/dist/renderer/draw/effects.js +28 -0
- package/dist/renderer/draw/effects.js.map +1 -0
- package/dist/renderer/draw/flushBatch.js +35 -0
- package/dist/renderer/draw/flushBatch.js.map +1 -0
- package/dist/renderer/draw/gradient.js +90 -0
- package/dist/renderer/draw/gradient.js.map +1 -0
- package/dist/renderer/draw/image.js +38 -0
- package/dist/renderer/draw/image.js.map +1 -0
- package/dist/renderer/draw/mesh.js +16 -0
- package/dist/renderer/draw/mesh.js.map +1 -0
- package/dist/renderer/draw/paintBind.js +70 -0
- package/dist/renderer/draw/paintBind.js.map +1 -0
- package/dist/renderer/draw/pathPaint.js +142 -0
- package/dist/renderer/draw/pathPaint.js.map +1 -0
- package/dist/renderer/draw/scratchPass.js +83 -0
- package/dist/renderer/draw/scratchPass.js.map +1 -0
- package/dist/renderer/draw/stencil.js +28 -0
- package/dist/renderer/draw/stencil.js.map +1 -0
- package/dist/renderer/draw/text.js +167 -0
- package/dist/renderer/draw/text.js.map +1 -0
- package/dist/renderer/draw/uniforms.js +77 -0
- package/dist/renderer/draw/uniforms.js.map +1 -0
- package/dist/renderer/draw.js +60 -1116
- package/dist/renderer/draw.js.map +1 -1
- package/dist/renderer/effects/EffectTargets.js +3 -0
- package/dist/renderer/effects/EffectTargets.js.map +1 -1
- package/dist/renderer/effects/composite.js +7 -5
- package/dist/renderer/effects/composite.js.map +1 -1
- package/dist/renderer/index.js +18 -17
- package/dist/renderer/math/color.js +63 -83
- package/dist/renderer/math/color.js.map +1 -1
- package/dist/renderer/math/mat3.js +15 -11
- package/dist/renderer/math/mat3.js.map +1 -1
- package/dist/renderer/math/viewToMat3.js +1 -1
- package/dist/renderer/math/viewToMat3.js.map +1 -1
- package/dist/renderer/shaders/ShaderProgram.js +13 -13
- package/dist/renderer/shaders/ShaderProgram.js.map +1 -1
- package/dist/renderer/shaders/glyphPaint.js +3 -3
- package/dist/renderer/shaders/glyphPaint.js.map +1 -1
- package/dist/renderer/shaders/gradFill.js +2 -1
- package/dist/renderer/shaders/gradFill.js.map +1 -1
- package/dist/renderer/shaders/pathFill.js +2 -1
- package/dist/renderer/shaders/pathFill.js.map +1 -1
- package/dist/renderer/shaders/patternFill.js +2 -1
- package/dist/renderer/shaders/patternFill.js.map +1 -1
- package/dist/renderer/shaders/registerProgram.js.map +1 -1
- package/dist/renderer/strokeLengths.js.map +1 -1
- package/dist/renderer/textures/registerTexture.js +25 -5
- package/dist/renderer/textures/registerTexture.js.map +1 -1
- package/dist/renderer.d.ts +16 -15
- package/dist/renderer.js +17 -16
- package/dist/resize.d.ts +5 -6
- package/dist/resize.js +5 -5
- package/dist/style.css +1 -1
- package/dist/test-hook/install.js +12 -6
- package/dist/test-hook/install.js.map +1 -1
- package/dist/{test-seams-CuIxe0xY.d.ts → test-seams-DM2B87-g.d.ts} +4 -4
- package/dist/test-seams.d.ts +2 -2
- package/dist/tools/builtin/ellipse/useEllipseTool.js +1 -0
- package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
- package/dist/tools/builtin/hand/useHandTool.js +1 -0
- package/dist/tools/builtin/hand/useHandTool.js.map +1 -1
- package/dist/tools/builtin/lasso/useLassoTool.js +11 -11
- package/dist/tools/builtin/lasso/useLassoTool.js.map +1 -1
- package/dist/tools/builtin/line/useLineTool.js +1 -0
- package/dist/tools/builtin/line/useLineTool.js.map +1 -1
- package/dist/tools/builtin/pen/usePenTool.js +153 -103
- package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
- package/dist/tools/builtin/pencil/usePencilTool.js +1 -0
- package/dist/tools/builtin/pencil/usePencilTool.js.map +1 -1
- package/dist/tools/builtin/polygon/usePolygonTool.js +13 -8
- package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
- package/dist/tools/builtin/rect/useRectTool.js +1 -0
- package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
- package/dist/tools/builtin/select/selectionContributions.js +24 -23
- package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
- package/dist/tools/builtin/select/useSelectTool.js +51 -48
- package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
- package/dist/tools/builtin/shared/pointerFollower.js +17 -0
- package/dist/tools/builtin/shared/pointerFollower.js.map +1 -0
- package/dist/tools/builtin/slice/useSliceTool.js +49 -54
- package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
- package/dist/tools/builtin/star/useStarTool.js +22 -16
- package/dist/tools/builtin/star/useStarTool.js.map +1 -1
- package/dist/tools/builtin/text/useTextTool.js +1 -0
- package/dist/tools/builtin/text/useTextTool.js.map +1 -1
- package/dist/tools/useKeybindings.js +14 -30
- package/dist/tools/useKeybindings.js.map +1 -1
- package/dist/{types-B_9g6hMM.d.ts → types-B4iJRHC3.d.ts} +5 -1
- package/dist/{types-A37hYkeR.d.ts → types-k-5Oqh-U.d.ts} +31 -7
- package/dist/util/color.js +3 -3
- package/dist/util/color.js.map +1 -1
- package/dist/util/paint.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +20 -18
- package/dist/autoPoseDescriptor-vCdt55xm.d.ts +0 -27
- package/dist/builtins-C-VgUlWI.d.ts +0 -4514
- package/dist/core/isPlainObject.js.map +0 -1
- package/dist/debug/flag.js.map +0 -1
- package/dist/interactions/actions/defaults/freshNodeId.js +0 -10
- package/dist/interactions/actions/defaults/freshNodeId.js.map +0 -1
- package/dist/renderer/shaders/imageFill.js +0 -14
- package/dist/renderer/shaders/imageFill.js.map +0 -1
- package/dist/tools/prefs.js +0 -62
- package/dist/tools/prefs.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resize.js","names":["IDENTITY_EXPAND","ids","EMPTY_POINT_SNAP","resolveDeps","geometry","poseDescriptorOf","ctx","dep","DEFAULT_RESIZE_BEHAVIORS","buildPointSnapContext","cx","pose","cy","tl","rotatePoint","rotation","tr","br","bl","draggedCorner","fixedCorner","anchor","fixedPt","draggedPt","applyPointSnap","result","dx","dy","pin","Dx","Dy","cos","sin","localW","localH","newWidth","newHeight","newCx","newCy","pointSnapToCamera","cam","w","fromPlane","m","p","pointSnapFromPlane","r","toPlane","computeProposedBounds","cs","sn","dxLocal","dyLocal","nx","ob","ny","nw","nh","resizeAction","inPlane","selection","scene","applyOps","geometryProjection","expanded","expandIds","isGroupPath","writeIds","frame","scenePoseFrame","view","stored","layer","id","carryPose","world","planeOf","startPoses","startWorlds","leafBounds","node","invertPlane","originBounds","unionBounds","originPose","originRotation","fixedLocal","fixedCornerOf","fixedWorld","startWorld","readView","gestureViewReader","readPlane","gesturePlaneReader","gestureCtx","ctxAsRect","b","behaviors","scratch","readGestureLifecycle","policy","commitResize","target","defaultCommitAdapter","reduceBehaviorEnd","commitGestureOps","lifecycle","ops","next","from","committed","sb","db","boxToBox","dataOp","geometryDataOp","nb","createTransformOp","mctx","proposedBounds","behaviorCtx","computePose","sp","poseRotationOf","remapRotatedLeaf","proposedPose","newCenterX","newCenterY","newFixedLocal","newFixedWorld","correctionX","correctionY","translatePoseViaDescriptor","poseAsRect","psCtx","plane","beh","reason","runBehaviorCancel","dropPreviewOverrides","selectionLayer"],"sources":["../../../../src/interactions/actions/defaults/resize.ts"],"sourcesContent":["/**\n * `resizeAction` — ongoing Action descriptor for anchor-relative drag resize.\n *\n * ## Status: REAL\n *\n * Performs real anchor-relative resize math for rect-shaped poses. Reads\n * `ctx.drag.affordance.anchor` to determine which corner is fixed, captures\n * start poses, applies per-frame bounds remapping, and commits one batch on\n * end — labeled, transient and observed per the `resizePolicy` dep's\n * lifecycle fields.\n *\n * ## Behaviors / point-snap / expandIds — via the `resizePolicy` dep\n *\n * The `resizePolicy` dep carries the behavior options the legacy `useResize`\n * hook exposed (`behaviors`, `pointSnapBehaviors`, `expandIds`). When the dep\n * is registered, this invoker:\n *\n * - Calls `expandIds([id])` at start. When the result expands beyond the\n * starting id, takes the group path (union-AABB origin, per-leaf remap).\n * - Runs `behaviors[]` after the raw anchor-math bounds are computed.\n * Behaviors return `{ pose? }` and rewrite the proposed bounds before\n * they're projected back into pose space.\n * - Runs `pointSnap[]` after the bounds→pose projection. The first non-null\n * `PointSnapResult` wins; this invoker back-solves a pose so the chosen\n * frame's world point lands on the snap target.\n *\n * When the dep is absent the invoker falls back to identity defaults\n * (no behaviors, no snap, `ids => ids` expansion).\n *\n * ## Pose geometry — via the `poseDescriptor` dep\n *\n * Every pose read and rewrite goes through the `poseDescriptor` dep, which\n * `<SceneCanvas>` sources from its `poseDescriptor` prop. Unsourced it is\n * `AUTO_POSE_DESCRIPTOR`, which dispatches per call to `pathPoseDescriptor`\n * for Path-shaped poses and to `RECT_POSE_DESCRIPTOR` for everything else.\n *\n * @see useResize — the React hook this descriptor mirrors.\n * @see src/interactions/actions/resize/geometry.ts — `PoseDescriptor`.\n */\n\nimport { gesturePlaneReader, gestureViewReader } from '../../gestures/shared/screenTolerance';\nimport type { Action } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport { syncPreviewOverrides, dropPreviewOverrides } from '../previewOverrides';\nimport type {\n GestureContext,\n ModifierState,\n PointSnapBehavior,\n PointSnapContext,\n PointSnapResult,\n ResizeAnchor,\n BoundsConstraint,\n RotatedPose,\n} from '../../gestures/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { ResizePolicy } from '../depSchema';\nimport { DEFAULT_RESIZE_BEHAVIORS } from '../resize/behaviors';\nimport { remapRotatedLeaf, translatePoseViaDescriptor, type PoseDescriptor } from '../resize/geometry';\nimport { poseRotationOf } from 'core/geometry/poseRotation';\nimport { poseDescriptorOf } from '../poseDescriptorDep';\nimport { fixedCornerOf } from '../resize/cornerHandles';\nimport { rotatePoint } from '../rotate/geometry';\nimport type { Op } from 'core/ops/types';\nimport type { Mat3 } from '@weasel-js/geom';\nimport { boxToBox } from '@weasel-js/geom';\nimport { createTransformOp } from 'core/ops/transform';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport { geometryDataOp, type GeometryProjection } from '../geometryProjection';\nimport { unionBounds } from 'core/geometry/unionBounds';\nimport { scenePoseFrame, type PoseFrame } from '../poseFrame';\nimport { commitGestureOps, readGestureLifecycle, reduceBehaviorEnd, runBehaviorCancel, type GestureLifecycle } from '../gestureLifecycle';\nimport { carryPose, invertPlane, inPlane, planeOf, selectionLayer } from '../planeInput';\nimport { fromPlane, toPlane, type PlaneMap } from 'core/viewport/parallax';\n\n// ---------------------------------------------------------------------------\n// Defaults applied when `resizePolicy` dep is absent. Mirrors the\n// destructuring defaults in `useResize`.\n// ---------------------------------------------------------------------------\n\nconst IDENTITY_EXPAND = (ids: string[]) => ids;\nconst EMPTY_POINT_SNAP: PointSnapBehavior<Bounds>[] = [];\n\nfunction resolveDeps(ctx: InvocationCtx): {\n behaviors: BoundsConstraint<Bounds>[];\n pointSnap: PointSnapBehavior<Bounds>[];\n expandIds: (ids: string[]) => string[];\n geometry: PoseDescriptor<unknown>;\n policy: ResizePolicy<unknown> | undefined;\n} {\n const geometry = poseDescriptorOf(ctx.deps.poseDescriptor);\n const dep = ctx.deps.resizePolicy;\n if (!dep) {\n return {\n // Standard kit behaviors (shift = aspect lock) apply even with no\n // policy wired; consumers opt out via an explicit `behaviors: []`.\n behaviors: DEFAULT_RESIZE_BEHAVIORS as BoundsConstraint<Bounds>[],\n pointSnap: EMPTY_POINT_SNAP,\n expandIds: IDENTITY_EXPAND,\n geometry,\n policy: undefined,\n };\n }\n return {\n behaviors: dep.constraints as unknown as BoundsConstraint<Bounds>[],\n pointSnap: dep.pointSnap as unknown as PointSnapBehavior<Bounds>[],\n expandIds: dep.expandIds,\n geometry,\n policy: dep,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Point-snap math (lifted from `useResize`).\n// ---------------------------------------------------------------------------\n\nfunction buildPointSnapContext<TPose extends Bounds>(\n pose: TPose,\n rotation: number,\n anchor: ResizeAnchor,\n modifiers: ModifierState,\n): PointSnapContext<TPose> {\n const cx = pose.x + pose.width / 2;\n const cy = pose.y + pose.height / 2;\n\n const tl = rotatePoint(pose.x, pose.y, cx, cy, rotation);\n const tr = rotatePoint(pose.x + pose.width, pose.y, cx, cy, rotation);\n const br = rotatePoint(pose.x + pose.width, pose.y + pose.height, cx, cy, rotation);\n const bl = rotatePoint(pose.x, pose.y + pose.height, cx, cy, rotation);\n\n let draggedCorner: { worldX: number; worldY: number } | null = null;\n let fixedCorner: { worldX: number; worldY: number } | null = null;\n\n if (anchor.x !== 'free' && anchor.y !== 'free') {\n const fixedPt =\n anchor.x === 'min' && anchor.y === 'min' ? tl :\n anchor.x === 'max' && anchor.y === 'min' ? tr :\n anchor.x === 'max' && anchor.y === 'max' ? br : bl;\n const draggedPt =\n anchor.x === 'min' && anchor.y === 'min' ? br :\n anchor.x === 'max' && anchor.y === 'min' ? bl :\n anchor.x === 'max' && anchor.y === 'max' ? tl : tr;\n fixedCorner = { worldX: fixedPt.x, worldY: fixedPt.y };\n draggedCorner = { worldX: draggedPt.x, worldY: draggedPt.y };\n }\n\n return {\n draggedCorner,\n fixedCorner,\n center: { worldX: cx, worldY: cy },\n origin: { worldX: tl.x, worldY: tl.y },\n rotation,\n anchor,\n proposed: pose,\n modifiers,\n };\n}\n\nfunction applyPointSnap<TPose extends Bounds>(\n pose: TPose,\n rotation: number,\n result: PointSnapResult,\n ctx: PointSnapContext<TPose>,\n): TPose {\n if (result.frame === 'center') {\n const dx = result.worldX - ctx.center.worldX;\n const dy = result.worldY - ctx.center.worldY;\n return { ...pose, x: pose.x + dx, y: pose.y + dy };\n }\n if (result.frame === 'origin') {\n const dx = result.worldX - ctx.origin.worldX;\n const dy = result.worldY - ctx.origin.worldY;\n return { ...pose, x: pose.x + dx, y: pose.y + dy };\n }\n const pin = result.frame === 'dragged-corner' ? ctx.fixedCorner : ctx.draggedCorner;\n if (!pin) return pose;\n const Dx = result.worldX - pin.worldX;\n const Dy = result.worldY - pin.worldY;\n const cos = Math.cos(rotation);\n const sin = Math.sin(rotation);\n const localW = Dx * cos + Dy * sin;\n const localH = -Dx * sin + Dy * cos;\n const newWidth = Math.abs(localW);\n const newHeight = Math.abs(localH);\n const newCx = (pin.worldX + result.worldX) / 2;\n const newCy = (pin.worldY + result.worldY) / 2;\n return { ...pose, x: newCx - newWidth / 2, y: newCy - newHeight / 2, width: newWidth, height: newHeight };\n}\n\n/** `ctx`'s points in the camera's world, for a snap rule written against it. */\nfunction pointSnapToCamera<TPose extends Bounds>(\n ctx: PointSnapContext<TPose>,\n m: PlaneMap,\n): PointSnapContext<TPose> {\n const cam = (p: { worldX: number; worldY: number }) => {\n const w = fromPlane(m, { x: p.worldX, y: p.worldY });\n return { worldX: w.x, worldY: w.y };\n };\n return {\n ...ctx,\n draggedCorner: ctx.draggedCorner && cam(ctx.draggedCorner),\n fixedCorner: ctx.fixedCorner && cam(ctx.fixedCorner),\n center: cam(ctx.center),\n origin: cam(ctx.origin),\n };\n}\n\n/** A snap rule's answer, back in the plane the resize works in. */\nfunction pointSnapFromPlane(\n r: PointSnapResult | null | undefined,\n m: PlaneMap,\n): PointSnapResult | null | undefined {\n if (!r) return r;\n const p = toPlane(m, { x: r.worldX, y: r.worldY });\n return { ...r, worldX: p.x, worldY: p.y };\n}\n\n// ---------------------------------------------------------------------------\n// Anchor math (rotated and unrotated).\n// ---------------------------------------------------------------------------\n\nfunction computeProposedBounds(\n ob: Bounds,\n anchor: ResizeAnchor,\n dx: number,\n dy: number,\n rotation: number,\n): Bounds {\n if (rotation !== 0) {\n const cs = Math.cos(-rotation);\n const sn = Math.sin(-rotation);\n const dxLocal = cs * dx - sn * dy;\n const dyLocal = sn * dx + cs * dy;\n dx = dxLocal;\n dy = dyLocal;\n }\n let nx = ob.x;\n let ny = ob.y;\n let nw = ob.width;\n let nh = ob.height;\n if (anchor.x === 'min') {\n nw = ob.width + dx;\n } else if (anchor.x === 'max') {\n nx = ob.x + dx;\n nw = ob.width - dx;\n }\n if (anchor.y === 'min') {\n nh = ob.height + dy;\n } else if (anchor.y === 'max') {\n ny = ob.y + dy;\n nh = ob.height - dy;\n }\n return { x: nx, y: ny, width: nw, height: nh };\n}\n\n// ---------------------------------------------------------------------------\n// Internal scratch\n// ---------------------------------------------------------------------------\n\ninterface ResizeScratch {\n /** Ids the gesture writes to. For group expansion this is the leaf set;\n * for the single-id path it's the original selection. */\n writeIds: NodeId[];\n scene: Scene<unknown, string, unknown>;\n /** World reads and local writes over the scene's composition strategy. */\n frame: PoseFrame<unknown>;\n /** Start poses keyed by write id, as stored — the `from` of each op. */\n startPoses: Map<NodeId, unknown>;\n /** Start poses in world — the frame the anchor math and the drag share. */\n startWorlds: Map<NodeId, unknown>;\n /** Shared origin bounds (union for group/multi-select, own bounds for\n * single). Used as the `src` rect for `geometry.remapBounds`. */\n originBounds: Bounds;\n anchor: ResizeAnchor;\n startWorld: { x: number; y: number };\n /** Rotation captured at gesture start (from `geometry.getRotation?`). */\n originRotation: number;\n /** World-space position of the diagonally opposite corner at start. Used\n * for the rotated-resize fixed-corner pin correction. */\n fixedWorld: { x: number; y: number };\n /** In-flight preview poses buffered during drag. */\n previews: Map<NodeId, unknown>;\n overrideEntries: Map<NodeId, { pose: unknown }>;\n geometry: PoseDescriptor<unknown>;\n behaviors: BoundsConstraint<Bounds>[];\n pointSnap: PointSnapBehavior<Bounds>[];\n /** Gesture context handed to behaviors. Reused across move/end. */\n gestureCtx: GestureContext<unknown>;\n /** Optional consumer commit hook captured at gesture start. When present,\n * the final pose commit routes through it (consumer history) instead of\n * `scene.applyBatch`. Undefined → fall back to `scene.applyBatch`. */\n applyOps?: (ops: Op[], label: string) => void;\n /** Optional eager-sync seam captured at gesture start. When present, the\n * commit emits a `setData` op per leaf mapping its data-held geometry by\n * the box→box affine the pose underwent. Undefined → pose-only commit. */\n geometryProjection?: GeometryProjection;\n /** Label, history and callbacks from the `resizePolicy` dep. */\n lifecycle: GestureLifecycle;\n}\n\n// ---------------------------------------------------------------------------\n// Descriptor\n// ---------------------------------------------------------------------------\n\n/**\n * @experimental\n * Static descriptor for the `resize` Action.\n *\n * Requires dep-schema entries: `selection`, `scene`.\n * Reads optional `resizePolicy` dep when present.\n * Requires `InvocationCtx.drag.affordance` with a `handle:*` kind.\n */\nexport const resizeAction: Action & { requires: string[] } = inPlane({\n id: 'resize',\n label: 'Resize',\n // No default binding: a bare `{ kind: 'drag' }` claimed every drag at ambient\n // scope, tying areaSelect's. The resize handles bind it\n // (`selectionResizeBindings`, the `resize` preset).\n eligible: { capability: 'transforms-selection' },\n requires: ['selection', 'scene', 'resizePolicy', 'poseDescriptor', 'applyOps', 'geometryProjection', 'poseComposition', 'view'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, _opts): OngoingHandle {\n const selection = ctx.deps.selection;\n const scene = ctx.deps.scene;\n const applyOps = ctx.deps.applyOps;\n const geometryProjection = ctx.deps.geometryProjection;\n\n if (!selection || !scene) return {};\n\n const ids = selection.get() as NodeId[];\n if (ids.length === 0) return {};\n\n const affordance = ctx.drag?.affordance;\n const anchor = affordance?.anchor;\n if (!anchor) return {};\n\n const { behaviors, pointSnap, expandIds, geometry, policy } = resolveDeps(ctx);\n\n // Group expansion. When the starting selection is a single id but\n // `expandIds` returns a different set, we're in the group path:\n // every leaf is written, and origin bounds is the union AABB.\n // When `expandIds` returns the same list (identity default or no-op),\n // we write the selected ids directly.\n const expanded = expandIds(ids as unknown as string[]);\n if (expanded.length === 0) return {};\n\n const isGroupPath =\n ids.length === 1 && (expanded.length !== 1 || expanded[0] !== (ids[0] as string));\n const writeIds = (isGroupPath ? expanded : (ids as unknown as string[])) as NodeId[];\n\n // Capture start poses + per-leaf bounds. The drag delta is world, so\n // the anchor math runs on world poses — carried into the plane the edit\n // is measured in — and each result is carried back to its node's plane\n // and stored in the node's own parent frame.\n const frame = scenePoseFrame(scene, ctx.deps.poseComposition);\n const view = ctx.deps.view;\n /** A world result for `id`, as stored. */\n const stored = (id: NodeId, world: unknown): unknown => {\n const layer = scene.get(id)?.layer;\n return frame.local(id, carryPose(geometry, world, layer === undefined ? null : planeOf(view, layer)));\n };\n const startPoses = new Map<NodeId, unknown>();\n const startWorlds = new Map<NodeId, unknown>();\n const leafBounds: Bounds[] = [];\n for (const id of writeIds) {\n const node = scene.get(id);\n if (!node) continue;\n startPoses.set(id, node.pose);\n const world = carryPose(geometry, frame.world(id), invertPlane(planeOf(view, node.layer)));\n startWorlds.set(id, world);\n leafBounds.push(geometry.getBounds(world));\n }\n if (startPoses.size === 0) return {};\n\n // `leafBounds` is non-empty here (startPoses.size === 0 guarded above),\n // and the union branch only runs for length >= 2 → `!` is safe.\n const originBounds = leafBounds.length === 1\n ? leafBounds[0]\n : unionBounds(leafBounds)!;\n\n // Rotation captured only for the single-write-id path; group-resize\n // takes the AABB-frame (unrotated) path even if leaves have rotation.\n const originPose = !isGroupPath && writeIds.length === 1\n ? startWorlds.get(writeIds[0])\n : (originBounds as unknown);\n const originRotation = !isGroupPath\n ? (geometry.getRotation?.(originPose) ?? 0)\n : 0;\n\n const fixedLocal = fixedCornerOf(originBounds, anchor);\n const fixedWorld = originRotation === 0\n ? fixedLocal\n : rotatePoint(\n fixedLocal.x, fixedLocal.y,\n originBounds.x + originBounds.width / 2,\n originBounds.y + originBounds.height / 2,\n originRotation,\n );\n\n const startWorld = { x: ctx.drag?.start.x ?? 0, y: ctx.drag?.start.y ?? 0 };\n\n // Minimal GestureContext for behaviors. `draggedIds` matches the\n // legacy hook: the starting id (not the expanded leaf set).\n const readView = gestureViewReader(ctx.deps);\n const readPlane = gesturePlaneReader(ctx.deps);\n const gestureCtx: GestureContext<unknown> = {\n draggedIds: ids as unknown as string[],\n origin: new Map<string, unknown>([[ids[0] as string, originPose]]),\n current: new Map<string, unknown>([[ids[0] as string, originPose]]),\n snap: null,\n modifiers: { ...ctx.modifiers },\n pointer: { worldX: startWorld.x, worldY: startWorld.y, clientX: 0, clientY: 0 },\n view: readView(),\n plane: readPlane(),\n // `adapter` is unused by the kit's behaviors; cast to satisfy the type.\n adapter: undefined as unknown as GestureContext<unknown>['adapter'],\n scratch: {},\n };\n\n // Fire behavior onStart hooks (parity with `useResize`).\n const ctxAsRect = gestureCtx as unknown as GestureContext<Bounds>;\n for (const b of behaviors) b.onStart?.(ctxAsRect);\n\n const scratch: ResizeScratch = {\n writeIds,\n scene,\n frame,\n startPoses,\n startWorlds,\n originBounds,\n anchor,\n startWorld,\n originRotation,\n fixedWorld,\n previews: new Map<NodeId, unknown>(),\n overrideEntries: new Map<NodeId, { pose: unknown }>(),\n geometry,\n behaviors,\n pointSnap,\n gestureCtx,\n applyOps,\n geometryProjection,\n lifecycle: readGestureLifecycle(policy, 'Resize', behaviors),\n };\n const { lifecycle } = scratch;\n lifecycle.start(writeIds as string[]);\n\n // Returns whether anything reached the document.\n const commitResize = (): boolean => {\n const target = {\n scene,\n applyOps: scratch.applyOps,\n adapter: defaultCommitAdapter(scene, selection.adapterMethods),\n };\n const r = reduceBehaviorEnd(scratch.behaviors, scratch.gestureCtx as unknown as GestureContext<Bounds>);\n if (r === null) return false;\n if (r !== undefined) {\n commitGestureOps(target, lifecycle, r);\n return true;\n }\n\n if (scratch.previews.size === 0) return false;\n\n // One transform op per write id (from = pre-drag start pose, to =\n // final preview pose), committed as a single batch → one undo entry.\n const ops: Op[] = [];\n for (const id of scratch.writeIds) {\n const next = scratch.previews.get(id);\n if (next === undefined) continue;\n const from = scratch.startPoses.get(id);\n if (from === undefined) continue;\n let committed = next;\n // Eager-sync: map data-held geometry by the box→box affine the\n // pose underwent (start-pose bounds → final-pose bounds). Opt-in\n // via the geometryProjection seam; a no-op when the dep is absent.\n if (scratch.geometryProjection) {\n const node = scratch.scene.get(id);\n if (node) {\n const sb = scratch.geometry.getBounds(from);\n const db = scratch.geometry.getBounds(next);\n const m: Mat3 = boxToBox(\n sb.x, sb.y, sb.width, sb.height,\n db.x, db.y, db.width, db.height,\n );\n const dataOp = geometryDataOp(\n scratch.geometryProjection,\n { id: id as string, data: node.data, pose: from },\n m,\n lifecycle.label,\n );\n if (dataOp) {\n ops.push(dataOp);\n // The data absorbed the affine — including any mirror from a\n // drag past the opposite edge — so the pose must commit as a\n // normalized AABB. Leaving signed extents on the pose makes\n // the node unhittable (hit-testing assumes normalized boxes).\n // Without the seam the signed pose is kept: a bare-AABB pose\n // is the only carrier of the flip there.\n if (db.width < 0 || db.height < 0) {\n const nb = {\n ...db,\n x: db.width < 0 ? db.x + db.width : db.x,\n y: db.height < 0 ? db.y + db.height : db.y,\n width: Math.abs(db.width),\n height: Math.abs(db.height),\n };\n committed = scratch.geometry.remapBounds(next, db, nb) as typeof next;\n }\n }\n }\n }\n ops.push(createTransformOp<unknown>({\n id: id as string,\n from,\n to: committed,\n label: lifecycle.label,\n }));\n }\n if (ops.length === 0) return false;\n commitGestureOps(target, lifecycle, ops);\n return true;\n };\n\n return {\n kind: 'resize',\n onMove(mctx: InvocationCtx): void {\n if (!mctx.drag) return;\n const dx = mctx.drag.current.x - scratch.startWorld.x;\n const dy = mctx.drag.current.y - scratch.startWorld.y;\n\n // Refresh modifiers + pointer on the gesture ctx for behaviors.\n scratch.gestureCtx.modifiers = { ...mctx.modifiers };\n scratch.gestureCtx.pointer = {\n worldX: mctx.drag.current.x,\n worldY: mctx.drag.current.y,\n clientX: 0,\n clientY: 0,\n };\n scratch.gestureCtx.view = readView();\n scratch.gestureCtx.plane = readPlane();\n\n let proposedBounds = computeProposedBounds(\n scratch.originBounds,\n scratch.anchor,\n dx,\n dy,\n scratch.originRotation,\n );\n\n // Behaviors run in bounds-space.\n const behaviorCtx = scratch.gestureCtx as unknown as GestureContext<Bounds>;\n for (const b of scratch.behaviors) {\n const r = b.onMove?.(behaviorCtx, {\n pose: proposedBounds,\n anchor: scratch.anchor,\n });\n if (!r) continue;\n if (r.pose !== undefined) {\n proposedBounds = {\n x: r.pose.x, y: r.pose.y, width: r.pose.width, height: r.pose.height,\n };\n }\n }\n\n // Project bounds → pose. For the group path, each leaf is remapped\n // from its own startPose; for single, from the start pose directly.\n //\n // A rotated leaf in a group needs its own frame: `src`/`dst` are\n // world-frame here, unlike the single path where the drag delta was\n // already projected into the leaf's frame, so the naive affine\n // scales the wrong pair of extents. See `remapRotatedLeaf`.\n const computePose = (id: NodeId): unknown => {\n const sp = scratch.startWorlds.get(id);\n if (sp === undefined) return undefined;\n if (isGroupPath && poseRotationOf(sp) !== null) {\n return remapRotatedLeaf(\n sp as RotatedPose, scratch.originBounds, proposedBounds,\n );\n }\n return scratch.geometry.remapBounds(sp, scratch.originBounds, proposedBounds);\n };\n\n // Single-id path: apply rotation correction + point-snap, then\n // store. Group path: rotation correction + point-snap don't apply\n // (group resize is AABB-frame).\n scratch.previews.clear();\n\n if (!isGroupPath && scratch.writeIds.length === 1) {\n const id = scratch.writeIds[0];\n let proposedPose = computePose(id);\n if (proposedPose === undefined) { syncPreviewOverrides(scratch); return; }\n\n if (scratch.originRotation !== 0) {\n const newCenterX = proposedBounds.x + proposedBounds.width / 2;\n const newCenterY = proposedBounds.y + proposedBounds.height / 2;\n const newFixedLocal = fixedCornerOf(proposedBounds, scratch.anchor);\n const newFixedWorld = rotatePoint(\n newFixedLocal.x, newFixedLocal.y,\n newCenterX, newCenterY,\n scratch.originRotation,\n );\n const correctionX = scratch.fixedWorld.x - newFixedWorld.x;\n const correctionY = scratch.fixedWorld.y - newFixedWorld.y;\n proposedPose = translatePoseViaDescriptor(proposedPose, correctionX, correctionY, scratch.geometry);\n }\n\n if (scratch.pointSnap.length > 0) {\n const rotation = scratch.originRotation;\n const poseAsRect = proposedPose as Bounds;\n const psCtx = buildPointSnapContext(\n poseAsRect,\n rotation,\n scratch.anchor,\n scratch.gestureCtx.modifiers,\n );\n // Point snaps are the surface's rules over the camera's world, so\n // on a plane their points cross at this boundary.\n const plane = scratch.gestureCtx.plane ?? null;\n for (const beh of scratch.pointSnap) {\n const result = plane\n ? pointSnapFromPlane(beh.onMove(pointSnapToCamera(psCtx, plane)), plane)\n : beh.onMove(psCtx);\n if (result) {\n proposedPose = applyPointSnap(poseAsRect, rotation, result, psCtx) as unknown;\n break;\n }\n }\n }\n\n scratch.previews.set(id, stored(id, proposedPose));\n scratch.gestureCtx.current = new Map<string, unknown>([[id as string, proposedPose]]);\n } else {\n // Group / multi path: remap each leaf and store.\n for (const id of scratch.writeIds) {\n const next = computePose(id);\n if (next === undefined) continue;\n scratch.previews.set(id, stored(id, next));\n }\n }\n\n syncPreviewOverrides(scratch);\n },\n\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n if (reason === 'commit') committed = commitResize();\n else runBehaviorCancel(scratch.behaviors, scratch.gestureCtx as unknown as GestureContext<Bounds>);\n } finally {\n dropPreviewOverrides(scratch);\n scratch.previews.clear();\n lifecycle.end(committed);\n }\n },\n previewIds: () => scratch.previews.keys(),\n previewPose: (id: string) => scratch.previews.get(id as NodeId) ?? null,\n };\n },\n },\n /**\n * Always enabled at the descriptor level. The dispatcher's\n * specificity-fallthrough loop treats anything `!== true` as \"skip and\n * try the next match\" — returning `ActionDisabledReason.SelectionRequired`\n * here makes the resize binding silently lose to lower-specificity\n * matches (e.g. ambient `insertAction`), inserting phantom nodes on\n * every drag instead of resizing. The invoker self-guards on empty\n * selection (returns `{}`), so a static `true` here is correct.\n *\n * Fix: previously `() => ActionDisabledReason.SelectionRequired`\n * — that broke every dispatcher-routed resize. See git blame.\n */\n enabled: () => true,\n}, selectionLayer);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resize.js","names":["IDENTITY_EXPAND","ids","EMPTY_POINT_SNAP","resolveDeps","geometry","poseDescriptorOf","ctx","dep","DEFAULT_RESIZE_BEHAVIORS","boundsForRules","isRectPose","pose","buildPointSnapContext","cx","cy","tl","rotatePoint","rotation","tr","br","bl","draggedCorner","fixedCorner","anchor","fixedPt","draggedPt","applyPointSnap","result","dx","dy","pin","Dx","Dy","cos","sin","localW","localH","newWidth","newHeight","newCx","newCy","pointSnapToCamera","cam","w","fromPlane","m","p","pointSnapFromPlane","r","toPlane","computeProposedBounds","cs","sn","dxLocal","dyLocal","nx","ob","ny","nw","nh","resizeAction","inPlane","selection","scene","applyOps","geometryProjection","geometryOf","nodeDescriptors","expanded","shapeSources","expandIds","isGroupPath","writeIds","frame","scenePoseFrame","view","stored","layer","id","carryPose","world","planeOf","startPoses","startWorlds","leafBounds","drawnBounds","node","g","invertPlane","visualBoundsViaDescriptor","originBounds","unionBounds","unionAABB","originPose","originGeometry","originRotation","fixedLocal","fixedCornerOf","fixedWorld","startWorld","readView","gestureViewReader","readPlane","gesturePlaneReader","ruleOrigin","gestureCtx","ctxAsRect","b","behaviors","scratch","readGestureLifecycle","policy","commitResize","target","defaultCommitAdapter","reduceBehaviorEnd","commitGestureOps","lifecycle","ops","next","from","committed","sb","db","boxToBox","dataOp","geometryDataOp","nb","createTransformOp","mctx","proposedBounds","behaviorCtx","sharedBox","computePose","sp","poseRotationOf","remapRotatedLeaf","proposedPose","newCenterX","newCenterY","newFixedLocal","newFixedWorld","correctionX","correctionY","translatePoseViaDescriptor","unsnapped","poseAsRect","psCtx","plane","beh","snapped","reason","runBehaviorCancel","dropPreviewOverrides","selectionLayer"],"sources":["../../../../src/interactions/actions/defaults/resize.ts"],"sourcesContent":["/**\n * `resizeAction` — ongoing Action descriptor for anchor-relative drag resize.\n *\n * ## Status: REAL\n *\n * Performs real anchor-relative resize math for rect-shaped poses. Reads\n * `ctx.drag.affordance.anchor` to determine which corner is fixed, captures\n * start poses, applies per-frame bounds remapping, and commits one batch on\n * end — labeled, transient and observed per the `resizePolicy` dep's\n * lifecycle fields.\n *\n * ## Behaviors / point-snap / expandIds — via the `resizePolicy` dep\n *\n * The `resizePolicy` dep carries the behavior options (`constraints`,\n * `pointSnap`, `expandIds`). When the dep\n * is registered, this invoker:\n *\n * - Calls `expandIds([id])` at start. When the result expands beyond the\n * starting id, takes the group path (union-AABB origin, per-leaf remap).\n * - Runs `behaviors[]` after the raw anchor-math bounds are computed.\n * Behaviors return `{ pose? }` and rewrite the proposed bounds before\n * they're projected back into pose space.\n * - Runs `pointSnap[]` after the bounds→pose projection. The first non-null\n * `PointSnapResult` wins; this invoker back-solves a pose so the chosen\n * frame's world point lands on the snap target.\n *\n * When the dep is absent the invoker falls back to identity defaults\n * (no behaviors, no snap, `ids => ids` expansion).\n *\n * ## Pose geometry — via the `poseDescriptor` dep\n *\n * Every pose read and rewrite goes through the `poseDescriptor` dep, which\n * `<SceneCanvas>` sources from its `poseDescriptor` prop. Unsourced it is\n * `AUTO_POSE_DESCRIPTOR`, which dispatches per call to `pathPoseDescriptor`\n * for Path-shaped poses and to `RECT_POSE_DESCRIPTOR` for everything else.\n *\n * @see src/interactions/actions/resize/geometry.ts — `PoseDescriptor`.\n */\n\nimport { gesturePlaneReader, gestureViewReader } from '../../gestures/shared/screenTolerance';\nimport type { Action } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport { syncPreviewOverrides, dropPreviewOverrides } from '../previewOverrides';\nimport type {\n GestureContext,\n ModifierState,\n PointSnapBehavior,\n PointSnapContext,\n PointSnapResult,\n ResizeAnchor,\n BoundsConstraint,\n RotatedPose,\n} from '../../gestures/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { ResizePolicy } from '../depSchema';\nimport { DEFAULT_RESIZE_BEHAVIORS } from '../resize/behaviors';\nimport { remapRotatedLeaf, translatePoseViaDescriptor, visualBoundsViaDescriptor, type PoseDescriptor } from '../resize/geometry';\nimport { poseRotationOf } from 'core/geometry/poseRotation';\nimport { nodeDescriptors, poseDescriptorOf } from '../poseDescriptorDep';\nimport { isRectPose } from '../resize/autoPoseDescriptor';\nimport { fixedCornerOf } from '../resize/cornerHandles';\nimport { rotatePoint } from '../rotate/geometry';\nimport type { Op } from 'core/ops/types';\nimport type { Mat3 } from '@weasel-js/geom';\nimport { boxToBox } from '@weasel-js/geom';\nimport { createTransformOp } from 'core/ops/transform';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport { geometryDataOp, type GeometryProjection } from '../geometryProjection';\nimport { unionAABB, unionBounds } from 'core/geometry/unionBounds';\nimport { scenePoseFrame, type PoseFrame } from '../poseFrame';\nimport { commitGestureOps, readGestureLifecycle, reduceBehaviorEnd, runBehaviorCancel, type GestureLifecycle } from '../gestureLifecycle';\nimport { carryPose, invertPlane, inPlane, planeOf, selectionLayer } from '../planeInput';\nimport { shapeSources } from '../selectionSubtree';\nimport { fromPlane, toPlane, type PlaneMap } from 'core/viewport/parallax';\n\n// ---------------------------------------------------------------------------\n// Defaults applied when `resizePolicy` dep is absent.\n// ---------------------------------------------------------------------------\n\nconst IDENTITY_EXPAND = (ids: string[]) => ids;\nconst EMPTY_POINT_SNAP: PointSnapBehavior<Bounds>[] = [];\n\nfunction resolveDeps(ctx: InvocationCtx): {\n behaviors: BoundsConstraint<Bounds>[];\n pointSnap: PointSnapBehavior<Bounds>[];\n expandIds: (ids: string[]) => string[];\n geometry: PoseDescriptor<unknown>;\n policy: ResizePolicy<unknown> | undefined;\n} {\n const geometry = poseDescriptorOf(ctx.deps.poseDescriptor);\n const dep = ctx.deps.resizePolicy;\n if (!dep) {\n return {\n // Standard kit behaviors (shift = aspect lock) apply even with no\n // policy wired; consumers opt out via an explicit `behaviors: []`.\n behaviors: DEFAULT_RESIZE_BEHAVIORS as BoundsConstraint<Bounds>[],\n pointSnap: EMPTY_POINT_SNAP,\n expandIds: IDENTITY_EXPAND,\n geometry,\n policy: undefined,\n };\n }\n return {\n behaviors: dep.constraints as unknown as BoundsConstraint<Bounds>[],\n pointSnap: dep.pointSnap as unknown as PointSnapBehavior<Bounds>[],\n expandIds: dep.expandIds,\n geometry,\n policy: dep,\n };\n}\n\n/** `pose` as the bounds a constraint or a point snap reads. A pose that is\n * already a box goes through whole, so a `rotation` on it rides along. */\nfunction boundsForRules(geometry: PoseDescriptor<unknown>, pose: unknown): Bounds {\n return isRectPose(pose) ? pose : geometry.getBounds(pose);\n}\n\n// ---------------------------------------------------------------------------\n// Point-snap math.\n// ---------------------------------------------------------------------------\n\nfunction buildPointSnapContext<TPose extends Bounds>(\n pose: TPose,\n rotation: number,\n anchor: ResizeAnchor,\n modifiers: ModifierState,\n): PointSnapContext<TPose> {\n const cx = pose.x + pose.width / 2;\n const cy = pose.y + pose.height / 2;\n\n const tl = rotatePoint(pose.x, pose.y, cx, cy, rotation);\n const tr = rotatePoint(pose.x + pose.width, pose.y, cx, cy, rotation);\n const br = rotatePoint(pose.x + pose.width, pose.y + pose.height, cx, cy, rotation);\n const bl = rotatePoint(pose.x, pose.y + pose.height, cx, cy, rotation);\n\n let draggedCorner: { worldX: number; worldY: number } | null = null;\n let fixedCorner: { worldX: number; worldY: number } | null = null;\n\n if (anchor.x !== 'free' && anchor.y !== 'free') {\n const fixedPt =\n anchor.x === 'min' && anchor.y === 'min' ? tl :\n anchor.x === 'max' && anchor.y === 'min' ? tr :\n anchor.x === 'max' && anchor.y === 'max' ? br : bl;\n const draggedPt =\n anchor.x === 'min' && anchor.y === 'min' ? br :\n anchor.x === 'max' && anchor.y === 'min' ? bl :\n anchor.x === 'max' && anchor.y === 'max' ? tl : tr;\n fixedCorner = { worldX: fixedPt.x, worldY: fixedPt.y };\n draggedCorner = { worldX: draggedPt.x, worldY: draggedPt.y };\n }\n\n return {\n draggedCorner,\n fixedCorner,\n center: { worldX: cx, worldY: cy },\n origin: { worldX: tl.x, worldY: tl.y },\n rotation,\n anchor,\n proposed: pose,\n modifiers,\n };\n}\n\nfunction applyPointSnap<TPose extends Bounds>(\n pose: TPose,\n rotation: number,\n result: PointSnapResult,\n ctx: PointSnapContext<TPose>,\n): TPose {\n if (result.frame === 'center') {\n const dx = result.worldX - ctx.center.worldX;\n const dy = result.worldY - ctx.center.worldY;\n return { ...pose, x: pose.x + dx, y: pose.y + dy };\n }\n if (result.frame === 'origin') {\n const dx = result.worldX - ctx.origin.worldX;\n const dy = result.worldY - ctx.origin.worldY;\n return { ...pose, x: pose.x + dx, y: pose.y + dy };\n }\n const pin = result.frame === 'dragged-corner' ? ctx.fixedCorner : ctx.draggedCorner;\n if (!pin) return pose;\n const Dx = result.worldX - pin.worldX;\n const Dy = result.worldY - pin.worldY;\n const cos = Math.cos(rotation);\n const sin = Math.sin(rotation);\n const localW = Dx * cos + Dy * sin;\n const localH = -Dx * sin + Dy * cos;\n const newWidth = Math.abs(localW);\n const newHeight = Math.abs(localH);\n const newCx = (pin.worldX + result.worldX) / 2;\n const newCy = (pin.worldY + result.worldY) / 2;\n return { ...pose, x: newCx - newWidth / 2, y: newCy - newHeight / 2, width: newWidth, height: newHeight };\n}\n\n/** `ctx`'s points in the camera's world, for a snap rule written against it. */\nfunction pointSnapToCamera<TPose extends Bounds>(\n ctx: PointSnapContext<TPose>,\n m: PlaneMap,\n): PointSnapContext<TPose> {\n const cam = (p: { worldX: number; worldY: number }) => {\n const w = fromPlane(m, { x: p.worldX, y: p.worldY });\n return { worldX: w.x, worldY: w.y };\n };\n return {\n ...ctx,\n draggedCorner: ctx.draggedCorner && cam(ctx.draggedCorner),\n fixedCorner: ctx.fixedCorner && cam(ctx.fixedCorner),\n center: cam(ctx.center),\n origin: cam(ctx.origin),\n };\n}\n\n/** A snap rule's answer, back in the plane the resize works in. */\nfunction pointSnapFromPlane(\n r: PointSnapResult | null | undefined,\n m: PlaneMap,\n): PointSnapResult | null | undefined {\n if (!r) return r;\n const p = toPlane(m, { x: r.worldX, y: r.worldY });\n return { ...r, worldX: p.x, worldY: p.y };\n}\n\n// ---------------------------------------------------------------------------\n// Anchor math (rotated and unrotated).\n// ---------------------------------------------------------------------------\n\nfunction computeProposedBounds(\n ob: Bounds,\n anchor: ResizeAnchor,\n dx: number,\n dy: number,\n rotation: number,\n): Bounds {\n if (rotation !== 0) {\n const cs = Math.cos(-rotation);\n const sn = Math.sin(-rotation);\n const dxLocal = cs * dx - sn * dy;\n const dyLocal = sn * dx + cs * dy;\n dx = dxLocal;\n dy = dyLocal;\n }\n let nx = ob.x;\n let ny = ob.y;\n let nw = ob.width;\n let nh = ob.height;\n if (anchor.x === 'min') {\n nw = ob.width + dx;\n } else if (anchor.x === 'max') {\n nx = ob.x + dx;\n nw = ob.width - dx;\n }\n if (anchor.y === 'min') {\n nh = ob.height + dy;\n } else if (anchor.y === 'max') {\n ny = ob.y + dy;\n nh = ob.height - dy;\n }\n return { x: nx, y: ny, width: nw, height: nh };\n}\n\n// ---------------------------------------------------------------------------\n// Internal scratch\n// ---------------------------------------------------------------------------\n\ninterface ResizeScratch {\n /** Ids the gesture writes to. For group expansion this is the leaf set;\n * for the single-id path it's the original selection. */\n writeIds: NodeId[];\n scene: Scene<unknown, string, unknown>;\n /** World reads and local writes over the scene's composition strategy. */\n frame: PoseFrame<unknown>;\n /** Start poses keyed by write id, as stored — the `from` of each op. */\n startPoses: Map<NodeId, unknown>;\n /** Start poses in world — the frame the anchor math and the drag share. */\n startWorlds: Map<NodeId, unknown>;\n /** Shared origin bounds (union for group/multi-select, own bounds for\n * single). Used as the `src` rect for `geometry.remapBounds`. */\n originBounds: Bounds;\n anchor: ResizeAnchor;\n startWorld: { x: number; y: number };\n /** Rotation captured at gesture start (from `geometry.getRotation?`). */\n originRotation: number;\n /** World-space position of the diagonally opposite corner at start. Used\n * for the rotated-resize fixed-corner pin correction. */\n fixedWorld: { x: number; y: number };\n /** In-flight preview poses buffered during drag. */\n previews: Map<NodeId, unknown>;\n overrideEntries: Map<NodeId, { pose: unknown }>;\n geometryOf: (id: NodeId) => PoseDescriptor<unknown>;\n behaviors: BoundsConstraint<Bounds>[];\n pointSnap: PointSnapBehavior<Bounds>[];\n /** Gesture context handed to behaviors. Reused across move/end. */\n gestureCtx: GestureContext<unknown>;\n /** Optional consumer commit hook captured at gesture start. When present,\n * the final pose commit routes through it (consumer history) instead of\n * `scene.applyBatch`. Undefined → fall back to `scene.applyBatch`. */\n applyOps?: (ops: Op[], label: string) => void;\n /** Optional eager-sync seam captured at gesture start. When present, the\n * commit emits a `setData` op per leaf mapping its data-held geometry by\n * the box→box affine the pose underwent. Undefined → pose-only commit. */\n geometryProjection?: GeometryProjection;\n /** Label, history and callbacks from the `resizePolicy` dep. */\n lifecycle: GestureLifecycle;\n}\n\n// ---------------------------------------------------------------------------\n// Descriptor\n// ---------------------------------------------------------------------------\n\n/**\n * @experimental\n * Static descriptor for the `resize` Action.\n *\n * Requires dep-schema entries: `selection`, `scene`.\n * Reads optional `resizePolicy` dep when present.\n * Requires `InvocationCtx.drag.affordance` with a `handle:*` kind.\n */\nexport const resizeAction: Action & { requires: string[] } = inPlane({\n id: 'resize',\n label: 'Resize',\n // No default binding: a bare `{ kind: 'drag' }` claimed every drag at ambient\n // scope, tying areaSelect's. The resize handles bind it\n // (`selectionResizeBindings`, the `resize` preset).\n eligible: { capability: 'transforms-selection' },\n requires: ['selection', 'scene', 'resizePolicy', 'poseDescriptor', 'applyOps', 'geometryProjection', 'poseComposition', 'view'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, _opts): OngoingHandle {\n const selection = ctx.deps.selection;\n const scene = ctx.deps.scene;\n const applyOps = ctx.deps.applyOps;\n const geometryProjection = ctx.deps.geometryProjection;\n\n if (!selection || !scene) return {};\n\n const ids = selection.get() as NodeId[];\n if (ids.length === 0) return {};\n\n const affordance = ctx.drag?.affordance;\n const anchor = affordance?.anchor;\n if (!anchor) return {};\n\n const { behaviors, pointSnap, expandIds, geometry, policy } = resolveDeps(ctx);\n const geometryOf = nodeDescriptors(scene, geometry);\n\n // Group expansion. When the starting selection is a single id but\n // `expandIds` returns a different set, we're in the group path:\n // every leaf is written, and origin bounds is the union AABB.\n // When `expandIds` returns the same list (identity default or no-op),\n // we write the selected ids directly.\n // A group whose pose derives from its children is resized by resizing\n // them, whatever the policy expanded to.\n const expanded = shapeSources(scene, expandIds(ids as unknown as string[]));\n if (expanded.length === 0) return {};\n\n const isGroupPath =\n ids.length === 1 && (expanded.length !== 1 || expanded[0] !== (ids[0] as string));\n const writeIds = (isGroupPath || ids.length > 1 ? expanded : (ids as unknown as string[])) as NodeId[];\n\n // Capture start poses + per-leaf bounds. The drag delta is world, so\n // the anchor math runs on world poses — carried into the plane the edit\n // is measured in — and each result is carried back to its node's plane\n // and stored in the node's own parent frame.\n const frame = scenePoseFrame(scene, ctx.deps.poseComposition);\n const view = ctx.deps.view;\n /** A world result for `id`, as stored. */\n const stored = (id: NodeId, world: unknown): unknown => {\n const layer = scene.get(id)?.layer;\n return frame.local(id, carryPose(geometryOf(id), world, layer === undefined ? null : planeOf(view, layer)));\n };\n const startPoses = new Map<NodeId, unknown>();\n const startWorlds = new Map<NodeId, unknown>();\n const leafBounds: Bounds[] = [];\n const drawnBounds: Bounds[] = [];\n for (const id of writeIds) {\n const node = scene.get(id);\n if (!node) continue;\n startPoses.set(id, node.pose);\n const g = geometryOf(id);\n const world = carryPose(g, frame.world(id), invertPlane(planeOf(view, node.layer)));\n startWorlds.set(id, world);\n leafBounds.push(g.getBounds(world));\n drawnBounds.push(visualBoundsViaDescriptor(world, g));\n }\n if (startPoses.size === 0) return {};\n\n // `leafBounds` is non-empty here (startPoses.size === 0 guarded above),\n // and the union branches only run for length >= 2 → `!` is safe. A\n // multi-selection's handles sit on the union of what is drawn, so that\n // is the box its drag resizes.\n const originBounds = leafBounds.length === 1\n ? leafBounds[0]\n : isGroupPath ? unionBounds(leafBounds)! : unionAABB(drawnBounds)!;\n\n // Rotation captured only for the single-write-id path; group-resize\n // takes the AABB-frame (unrotated) path even if leaves have rotation.\n const originPose = !isGroupPath && writeIds.length === 1\n ? startWorlds.get(writeIds[0])\n : (originBounds as unknown);\n // A lone target is read as its own shape; a shared box is a plain rect.\n const originGeometry = !isGroupPath && writeIds.length === 1 ? geometryOf(writeIds[0]) : geometry;\n const originRotation = !isGroupPath\n ? (originGeometry.getRotation?.(originPose) ?? 0)\n : 0;\n\n const fixedLocal = fixedCornerOf(originBounds, anchor);\n const fixedWorld = originRotation === 0\n ? fixedLocal\n : rotatePoint(\n fixedLocal.x, fixedLocal.y,\n originBounds.x + originBounds.width / 2,\n originBounds.y + originBounds.height / 2,\n originRotation,\n );\n\n const startWorld = { x: ctx.drag?.start.x ?? 0, y: ctx.drag?.start.y ?? 0 };\n\n // Minimal GestureContext for behaviors. `draggedIds` matches the\n // legacy hook: the starting id (not the expanded leaf set).\n const readView = gestureViewReader(ctx.deps);\n const readPlane = gesturePlaneReader(ctx.deps);\n const ruleOrigin = boundsForRules(originGeometry, originPose);\n const gestureCtx: GestureContext<unknown> = {\n draggedIds: ids as unknown as string[],\n origin: new Map<string, unknown>([[ids[0] as string, ruleOrigin]]),\n current: new Map<string, unknown>([[ids[0] as string, ruleOrigin]]),\n snap: null,\n modifiers: { ...ctx.modifiers },\n pointer: { worldX: startWorld.x, worldY: startWorld.y, clientX: 0, clientY: 0 },\n view: readView(),\n plane: readPlane(),\n // `adapter` is unused by the kit's behaviors; cast to satisfy the type.\n adapter: undefined as unknown as GestureContext<unknown>['adapter'],\n scratch: {},\n };\n\n const ctxAsRect = gestureCtx as unknown as GestureContext<Bounds>;\n for (const b of behaviors) b.onStart?.(ctxAsRect);\n\n const scratch: ResizeScratch = {\n writeIds,\n scene,\n frame,\n startPoses,\n startWorlds,\n originBounds,\n anchor,\n startWorld,\n originRotation,\n fixedWorld,\n previews: new Map<NodeId, unknown>(),\n overrideEntries: new Map<NodeId, { pose: unknown }>(),\n geometryOf,\n behaviors,\n pointSnap,\n gestureCtx,\n applyOps,\n geometryProjection,\n lifecycle: readGestureLifecycle(policy, 'Resize', behaviors),\n };\n const { lifecycle } = scratch;\n lifecycle.start(writeIds as string[]);\n\n // Returns whether anything reached the document.\n const commitResize = (): boolean => {\n const target = {\n scene,\n applyOps: scratch.applyOps,\n adapter: defaultCommitAdapter(scene, selection.adapterMethods),\n };\n const r = reduceBehaviorEnd(scratch.behaviors, scratch.gestureCtx as unknown as GestureContext<Bounds>);\n if (r === null) return false;\n if (r !== undefined) {\n commitGestureOps(target, lifecycle, r);\n return true;\n }\n\n if (scratch.previews.size === 0) return false;\n\n // One transform op per write id (from = pre-drag start pose, to =\n // final preview pose), committed as a single batch → one undo entry.\n const ops: Op[] = [];\n for (const id of scratch.writeIds) {\n const next = scratch.previews.get(id);\n if (next === undefined) continue;\n const from = scratch.startPoses.get(id);\n if (from === undefined) continue;\n let committed = next;\n // Eager-sync: map data-held geometry by the box→box affine the\n // pose underwent (start-pose bounds → final-pose bounds). Opt-in\n // via the geometryProjection seam; a no-op when the dep is absent.\n if (scratch.geometryProjection) {\n const node = scratch.scene.get(id);\n if (node) {\n const sb = scratch.geometryOf(id).getBounds(from);\n const db = scratch.geometryOf(id).getBounds(next);\n const m: Mat3 = boxToBox(\n sb.x, sb.y, sb.width, sb.height,\n db.x, db.y, db.width, db.height,\n );\n const dataOp = geometryDataOp(\n scratch.geometryProjection,\n { id: id as string, data: node.data, pose: from },\n m,\n lifecycle.label,\n );\n if (dataOp) {\n ops.push(dataOp);\n // The data absorbed the affine — including any mirror from a\n // drag past the opposite edge — so the pose must commit as a\n // normalized AABB. Leaving signed extents on the pose makes\n // the node unhittable (hit-testing assumes normalized boxes).\n // Without the seam the signed pose is kept: a bare-AABB pose\n // is the only carrier of the flip there.\n if (db.width < 0 || db.height < 0) {\n const nb = {\n ...db,\n x: db.width < 0 ? db.x + db.width : db.x,\n y: db.height < 0 ? db.y + db.height : db.y,\n width: Math.abs(db.width),\n height: Math.abs(db.height),\n };\n committed = scratch.geometryOf(id).remapBounds(next, db, nb) as typeof next;\n }\n }\n }\n }\n ops.push(createTransformOp<unknown>({\n id: id as string,\n from,\n to: committed,\n label: lifecycle.label,\n }));\n }\n if (ops.length === 0) return false;\n commitGestureOps(target, lifecycle, ops);\n return true;\n };\n\n return {\n kind: 'resize',\n onMove(mctx: InvocationCtx): void {\n if (!mctx.drag) return;\n const dx = mctx.drag.current.x - scratch.startWorld.x;\n const dy = mctx.drag.current.y - scratch.startWorld.y;\n\n // Refresh modifiers + pointer on the gesture ctx for behaviors.\n scratch.gestureCtx.modifiers = { ...mctx.modifiers };\n scratch.gestureCtx.pointer = {\n worldX: mctx.drag.current.x,\n worldY: mctx.drag.current.y,\n clientX: 0,\n clientY: 0,\n };\n scratch.gestureCtx.view = readView();\n scratch.gestureCtx.plane = readPlane();\n\n let proposedBounds = computeProposedBounds(\n scratch.originBounds,\n scratch.anchor,\n dx,\n dy,\n scratch.originRotation,\n );\n\n // Behaviors run in bounds-space.\n const behaviorCtx = scratch.gestureCtx as unknown as GestureContext<Bounds>;\n for (const b of scratch.behaviors) {\n const r = b.onMove?.(behaviorCtx, {\n pose: proposedBounds,\n anchor: scratch.anchor,\n });\n if (!r) continue;\n if (r.pose !== undefined) {\n proposedBounds = {\n x: r.pose.x, y: r.pose.y, width: r.pose.width, height: r.pose.height,\n };\n }\n }\n\n // Project bounds → pose. For the group path, each leaf is remapped\n // from its own startPose; for single, from the start pose directly.\n //\n // A rotated leaf resized with others needs its own frame: `src`/`dst`\n // are world-frame there, unlike the single path where the drag delta\n // was already projected into the leaf's frame, so the naive affine\n // scales the wrong pair of extents. See `remapRotatedLeaf`.\n const sharedBox = isGroupPath || scratch.writeIds.length > 1;\n const computePose = (id: NodeId): unknown => {\n const sp = scratch.startWorlds.get(id);\n if (sp === undefined) return undefined;\n if (sharedBox && poseRotationOf(sp) !== null) {\n return remapRotatedLeaf(\n sp as RotatedPose, scratch.originBounds, proposedBounds,\n );\n }\n return scratch.geometryOf(id).remapBounds(sp, scratch.originBounds, proposedBounds);\n };\n\n // Single-id path: apply rotation correction + point-snap, then\n // store. Group path: rotation correction + point-snap don't apply\n // (group resize is AABB-frame).\n scratch.previews.clear();\n\n if (!isGroupPath && scratch.writeIds.length === 1) {\n const id = scratch.writeIds[0];\n const g = scratch.geometryOf(id);\n let proposedPose = computePose(id);\n if (proposedPose === undefined) { syncPreviewOverrides(scratch); return; }\n\n if (scratch.originRotation !== 0) {\n const newCenterX = proposedBounds.x + proposedBounds.width / 2;\n const newCenterY = proposedBounds.y + proposedBounds.height / 2;\n const newFixedLocal = fixedCornerOf(proposedBounds, scratch.anchor);\n const newFixedWorld = rotatePoint(\n newFixedLocal.x, newFixedLocal.y,\n newCenterX, newCenterY,\n scratch.originRotation,\n );\n const correctionX = scratch.fixedWorld.x - newFixedWorld.x;\n const correctionY = scratch.fixedWorld.y - newFixedWorld.y;\n proposedPose = translatePoseViaDescriptor(proposedPose, correctionX, correctionY, g);\n }\n\n if (scratch.pointSnap.length > 0) {\n const rotation = scratch.originRotation;\n const unsnapped = proposedPose;\n const poseAsRect = boundsForRules(g, unsnapped);\n const psCtx = buildPointSnapContext(\n poseAsRect,\n rotation,\n scratch.anchor,\n scratch.gestureCtx.modifiers,\n );\n // Point snaps are the surface's rules over the camera's world, so\n // on a plane their points cross at this boundary.\n const plane = scratch.gestureCtx.plane ?? null;\n for (const beh of scratch.pointSnap) {\n const result = plane\n ? pointSnapFromPlane(beh.onMove(pointSnapToCamera(psCtx, plane)), plane)\n : beh.onMove(psCtx);\n if (result) {\n const snapped = applyPointSnap(poseAsRect, rotation, result, psCtx);\n proposedPose = isRectPose(unsnapped)\n ? snapped\n : g.remapBounds(unsnapped, poseAsRect, snapped);\n break;\n }\n }\n }\n\n scratch.previews.set(id, stored(id, proposedPose));\n scratch.gestureCtx.current = new Map<string, unknown>([\n [id as string, boundsForRules(g, proposedPose)],\n ]);\n } else {\n // Group / multi path: remap each leaf and store.\n for (const id of scratch.writeIds) {\n const next = computePose(id);\n if (next === undefined) continue;\n scratch.previews.set(id, stored(id, next));\n }\n }\n\n syncPreviewOverrides(scratch);\n },\n\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n if (reason === 'commit') committed = commitResize();\n else runBehaviorCancel(scratch.behaviors, scratch.gestureCtx as unknown as GestureContext<Bounds>);\n } finally {\n dropPreviewOverrides(scratch);\n scratch.previews.clear();\n lifecycle.end(committed);\n }\n },\n previewIds: () => scratch.previews.keys(),\n previewPose: (id: string) => scratch.previews.get(id as NodeId) ?? null,\n };\n },\n },\n /**\n * Always enabled at the descriptor level. The dispatcher's\n * specificity-fallthrough loop treats anything `!== true` as \"skip and\n * try the next match\" — returning `ActionDisabledReason.SelectionRequired`\n * here makes the resize binding silently lose to lower-specificity\n * matches (e.g. ambient `insertAction`), inserting phantom nodes on\n * every drag instead of resizing. The invoker self-guards on empty\n * selection (returns `{}`), so a static `true` here is correct.\n *\n * Fix: previously `() => ActionDisabledReason.SelectionRequired`\n * — that broke every dispatcher-routed resize. See git blame.\n */\n enabled: () => true,\n}, selectionLayer);\n"],"mappings":"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"}
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
import { dropPreviewOverrides as e, syncPreviewOverrides as t } from "../previewOverrides.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
2
|
+
import { createTransformOp as n } from "../../../core/ops/transform.js";
|
|
3
|
+
import { unionAABB as r } from "../../../core/geometry/unionBounds.js";
|
|
4
|
+
import { translatePoseViaDescriptor as i, visualBoundsViaDescriptor as a } from "../../../core/geometry/poseDescriptor.js";
|
|
5
|
+
import { gesturePlaneReader as o, gestureViewReader as s } from "../../gestures/shared/screenTolerance.js";
|
|
6
|
+
import { commitGestureOps as c, readGestureLifecycle as l, reduceBehaviorEnd as u, runBehaviorCancel as d } from "../gestureLifecycle.js";
|
|
7
|
+
import { shapeSources as f } from "../selectionSubtree.js";
|
|
8
|
+
import { nodeDescriptors as p, poseDescriptorOf as m } from "../poseDescriptorDep.js";
|
|
9
|
+
import { moveGestureAdapter as h } from "../move/gestureAdapter.js";
|
|
10
|
+
import { carryPose as g, inPlane as _, invertPlane as v, planeOf as y, selectionLayer as b } from "../planeInput.js";
|
|
11
|
+
import { defaultCommitAdapter as x } from "../defaultCommitAdapter.js";
|
|
12
|
+
import { scenePoseFrame as S } from "../poseFrame.js";
|
|
13
|
+
import { resolveParams as C } from "@weasel-js/routing";
|
|
13
14
|
//#region src/interactions/actions/defaults/rotate.ts
|
|
14
|
-
function
|
|
15
|
-
let
|
|
16
|
-
if (!
|
|
17
|
-
let
|
|
18
|
-
return
|
|
15
|
+
function w(e, t, n, r, a, o, s) {
|
|
16
|
+
let c = e.withRotation(t, n + r);
|
|
17
|
+
if (!s) return c;
|
|
18
|
+
let l = Math.cos(r), u = Math.sin(r), d = a.x - o.x, f = a.y - o.y, p = o.x + d * l - f * u, m = o.y + d * u + f * l;
|
|
19
|
+
return i(c, p - a.x, m - a.y, e);
|
|
19
20
|
}
|
|
20
|
-
var
|
|
21
|
+
var T = _({
|
|
21
22
|
id: "rotate",
|
|
22
23
|
label: "Rotate",
|
|
23
24
|
eligible: { capability: "transforms-selection" },
|
|
@@ -31,154 +32,154 @@ var w = g({
|
|
|
31
32
|
],
|
|
32
33
|
invoker: {
|
|
33
34
|
timing: "ongoing",
|
|
34
|
-
start(
|
|
35
|
-
let
|
|
36
|
-
if (!
|
|
37
|
-
let
|
|
38
|
-
if (
|
|
39
|
-
let
|
|
40
|
-
for (let e of
|
|
41
|
-
let t =
|
|
35
|
+
start(i, _) {
|
|
36
|
+
let b = i.deps.selection, T = i.deps.scene, E = i.deps.applyOps, D = C(_?.params), O = _?.behaviors ?? [];
|
|
37
|
+
if (!b || !T) return {};
|
|
38
|
+
let k = f(T, b.get());
|
|
39
|
+
if (k.length === 0) return {};
|
|
40
|
+
let A = p(T, m(i.deps.poseDescriptor)), j = S(T, i.deps.poseComposition), M = /* @__PURE__ */ new Map(), N = /* @__PURE__ */ new Map(), P = /* @__PURE__ */ new Map(), F = /* @__PURE__ */ new Map(), I = [];
|
|
41
|
+
for (let e of k) {
|
|
42
|
+
let t = T.get(e);
|
|
42
43
|
if (!t) continue;
|
|
43
|
-
let n =
|
|
44
|
+
let n = A(e);
|
|
44
45
|
if (!n.withRotation || n.supportsRotation?.(t.pose) === !1) continue;
|
|
45
|
-
|
|
46
|
-
let r =
|
|
47
|
-
|
|
48
|
-
let
|
|
49
|
-
|
|
50
|
-
x:
|
|
51
|
-
y:
|
|
52
|
-
}),
|
|
46
|
+
M.set(e, t.pose);
|
|
47
|
+
let r = g(n, j.world(e), v(y(i.deps.view, t.layer)));
|
|
48
|
+
N.set(e, r);
|
|
49
|
+
let o = n.getBounds(r);
|
|
50
|
+
P.set(e, {
|
|
51
|
+
x: o.x + o.width / 2,
|
|
52
|
+
y: o.y + o.height / 2
|
|
53
|
+
}), F.set(e, n.getRotation?.(r) ?? 0), I.push(a(r, n));
|
|
53
54
|
}
|
|
54
|
-
if (
|
|
55
|
-
let
|
|
56
|
-
x:
|
|
57
|
-
y:
|
|
58
|
-
},
|
|
59
|
-
ids:
|
|
60
|
-
scene:
|
|
61
|
-
|
|
62
|
-
frame:
|
|
63
|
-
originPoses:
|
|
64
|
-
originWorlds:
|
|
65
|
-
originCenters:
|
|
66
|
-
originRotations:
|
|
67
|
-
unionCenter:
|
|
68
|
-
startPointerAngle:
|
|
55
|
+
if (M.size === 0) return {};
|
|
56
|
+
let L = r(I), R = {
|
|
57
|
+
x: L.x + L.width / 2,
|
|
58
|
+
y: L.y + L.height / 2
|
|
59
|
+
}, z = Math.atan2(i.world.y - R.y, i.world.x - R.x), B = s(i.deps), V = i.deps.view, H = o(i.deps), U = {
|
|
60
|
+
ids: k,
|
|
61
|
+
scene: T,
|
|
62
|
+
descriptorOf: A,
|
|
63
|
+
frame: j,
|
|
64
|
+
originPoses: M,
|
|
65
|
+
originWorlds: N,
|
|
66
|
+
originCenters: P,
|
|
67
|
+
originRotations: F,
|
|
68
|
+
unionCenter: R,
|
|
69
|
+
startPointerAngle: z,
|
|
69
70
|
currentDelta: 0,
|
|
70
|
-
useUnionPivot:
|
|
71
|
+
useUnionPivot: k.length > 1 && D?.pivot !== "each",
|
|
71
72
|
previews: /* @__PURE__ */ new Map(),
|
|
72
73
|
overrideEntries: /* @__PURE__ */ new Map(),
|
|
73
|
-
applyOps:
|
|
74
|
-
lifecycle:
|
|
75
|
-
behaviors:
|
|
74
|
+
applyOps: E,
|
|
75
|
+
lifecycle: l(D, "Rotate", O),
|
|
76
|
+
behaviors: O,
|
|
76
77
|
gestureCtx: {
|
|
77
|
-
draggedIds: [...
|
|
78
|
-
origin: new Map([...
|
|
79
|
-
current: new Map([...
|
|
78
|
+
draggedIds: [...M.keys()],
|
|
79
|
+
origin: new Map([...N].map(([e, t]) => [e, t])),
|
|
80
|
+
current: new Map([...N].map(([e, t]) => [e, t])),
|
|
80
81
|
snap: null,
|
|
81
|
-
modifiers: { ...
|
|
82
|
+
modifiers: { ...i.modifiers },
|
|
82
83
|
pointer: {
|
|
83
|
-
worldX:
|
|
84
|
-
worldY:
|
|
84
|
+
worldX: i.world.x,
|
|
85
|
+
worldY: i.world.y,
|
|
85
86
|
clientX: 0,
|
|
86
87
|
clientY: 0
|
|
87
88
|
},
|
|
88
|
-
view:
|
|
89
|
-
plane:
|
|
90
|
-
adapter:
|
|
89
|
+
view: B(),
|
|
90
|
+
plane: H(),
|
|
91
|
+
adapter: h(T),
|
|
91
92
|
scratch: {}
|
|
92
93
|
}
|
|
93
|
-
}, { lifecycle:
|
|
94
|
+
}, { lifecycle: W } = U, G = (e) => {
|
|
94
95
|
let t = /* @__PURE__ */ new Map();
|
|
95
|
-
for (let [n, r] of
|
|
96
|
+
for (let [n, r] of U.originWorlds) t.set(n, w(U.descriptorOf(n), r, U.originRotations.get(n) ?? 0, e, U.originCenters.get(n) ?? {
|
|
96
97
|
x: 0,
|
|
97
98
|
y: 0
|
|
98
|
-
},
|
|
99
|
+
}, U.unionCenter, U.useUnionPivot));
|
|
99
100
|
return t;
|
|
100
|
-
},
|
|
101
|
-
let t =
|
|
102
|
-
for (let [e, n] of t)
|
|
101
|
+
}, K = (e) => {
|
|
102
|
+
let t = G(e);
|
|
103
|
+
for (let [e, n] of t) U.gestureCtx.current.set(e, n);
|
|
103
104
|
return t;
|
|
104
|
-
},
|
|
105
|
-
let n =
|
|
105
|
+
}, q = (e, t) => {
|
|
106
|
+
let n = U.gestureCtx;
|
|
106
107
|
n.modifiers = { ...e.modifiers }, n.pointer = {
|
|
107
108
|
worldX: e.world.x,
|
|
108
109
|
worldY: e.world.y,
|
|
109
110
|
clientX: 0,
|
|
110
111
|
clientY: 0
|
|
111
|
-
}, n.view =
|
|
112
|
-
let r =
|
|
113
|
-
pose:
|
|
112
|
+
}, n.view = B(), n.plane = H();
|
|
113
|
+
let r = U.originWorlds.keys().next().value, i = U.originRotations.get(r) ?? 0, a = t, o = {
|
|
114
|
+
pose: K(t).get(r),
|
|
114
115
|
rotation: i + t
|
|
115
116
|
};
|
|
116
|
-
for (let e of
|
|
117
|
+
for (let e of U.behaviors) {
|
|
117
118
|
let t = e.onMove?.(n, o);
|
|
118
119
|
if (!t || t.pose === void 0) continue;
|
|
119
|
-
let
|
|
120
|
-
a =
|
|
120
|
+
let s = U.descriptorOf(r).getRotation?.(t.pose) ?? 0;
|
|
121
|
+
a = s - i, o = {
|
|
121
122
|
pose: t.pose,
|
|
122
|
-
rotation:
|
|
123
|
+
rotation: s
|
|
123
124
|
};
|
|
124
125
|
}
|
|
125
126
|
return a;
|
|
126
|
-
},
|
|
127
|
+
}, J = () => {
|
|
127
128
|
let e = {
|
|
128
|
-
scene:
|
|
129
|
-
applyOps:
|
|
130
|
-
adapter:
|
|
129
|
+
scene: T,
|
|
130
|
+
applyOps: U.applyOps,
|
|
131
|
+
adapter: x(T, b.adapterMethods)
|
|
131
132
|
};
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
let t =
|
|
133
|
+
if (U.behaviors.length > 0) {
|
|
134
|
+
K(U.currentDelta);
|
|
135
|
+
let t = u(U.behaviors, U.gestureCtx);
|
|
135
136
|
if (t === null) return !1;
|
|
136
|
-
if (t !== void 0) return
|
|
137
|
+
if (t !== void 0) return c(e, W, t), !0;
|
|
137
138
|
}
|
|
138
|
-
if (
|
|
139
|
+
if (U.currentDelta === 0) return !1;
|
|
139
140
|
let t = [];
|
|
140
|
-
for (let e of
|
|
141
|
-
let
|
|
142
|
-
if (
|
|
143
|
-
let
|
|
144
|
-
|
|
141
|
+
for (let e of U.ids) {
|
|
142
|
+
let r = U.previews.get(e);
|
|
143
|
+
if (r === void 0) continue;
|
|
144
|
+
let i = U.originPoses.get(e);
|
|
145
|
+
i !== void 0 && t.push(n({
|
|
145
146
|
id: e,
|
|
146
|
-
from:
|
|
147
|
-
to:
|
|
148
|
-
label:
|
|
147
|
+
from: i,
|
|
148
|
+
to: r,
|
|
149
|
+
label: W.label
|
|
149
150
|
}));
|
|
150
151
|
}
|
|
151
|
-
return t.length !== 0 && (
|
|
152
|
-
},
|
|
153
|
-
if (
|
|
154
|
-
let e =
|
|
155
|
-
|
|
152
|
+
return t.length !== 0 && (c(e, W, t), !0);
|
|
153
|
+
}, Y = (e) => {
|
|
154
|
+
if (U.previews.clear(), e !== 0) for (let [t, n] of G(e)) {
|
|
155
|
+
let e = U.scene.get(t)?.layer, r = e === void 0 ? null : y(V, e);
|
|
156
|
+
U.previews.set(t, U.frame.local(t, g(U.descriptorOf(t), n, r)));
|
|
156
157
|
}
|
|
157
|
-
t(
|
|
158
|
+
t(U);
|
|
158
159
|
};
|
|
159
|
-
for (let e of
|
|
160
|
-
return
|
|
160
|
+
for (let e of O) e.onStart?.(U.gestureCtx);
|
|
161
|
+
return W.start(U.gestureCtx.draggedIds), {
|
|
161
162
|
kind: "rotate",
|
|
162
163
|
onMove(e) {
|
|
163
|
-
let t = Math.atan2(e.world.y -
|
|
164
|
-
|
|
164
|
+
let t = Math.atan2(e.world.y - U.unionCenter.y, e.world.x - U.unionCenter.x) - U.startPointerAngle;
|
|
165
|
+
U.currentDelta = U.behaviors.length > 0 ? q(e, t) : t, Y(U.currentDelta);
|
|
165
166
|
},
|
|
166
167
|
onEnd(t, n) {
|
|
167
168
|
let r = !1;
|
|
168
169
|
try {
|
|
169
|
-
n === "commit" ? r =
|
|
170
|
+
n === "commit" ? r = J() : d(U.behaviors, U.gestureCtx);
|
|
170
171
|
} finally {
|
|
171
|
-
e(
|
|
172
|
+
e(U), U.previews.clear(), W.end(r);
|
|
172
173
|
}
|
|
173
174
|
},
|
|
174
|
-
previewIds: () =>
|
|
175
|
-
previewPose: (e) =>
|
|
175
|
+
previewIds: () => U.previews.keys(),
|
|
176
|
+
previewPose: (e) => U.previews.get(e) ?? null
|
|
176
177
|
};
|
|
177
178
|
}
|
|
178
179
|
},
|
|
179
180
|
enabled: () => !0
|
|
180
|
-
},
|
|
181
|
+
}, b);
|
|
181
182
|
//#endregion
|
|
182
|
-
export {
|
|
183
|
+
export { T as rotateAction };
|
|
183
184
|
|
|
184
185
|
//# sourceMappingURL=rotate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rotate.js","names":["applyRotationDelta","rotated","d","pose","originRotation","delta","useUnionPivot","cos","sin","ox","originCenter","unionCenter","oy","nx","ny","translatePoseViaDescriptor","rotateAction","inPlane","selection","ctx","scene","applyOps","params","resolveParams","opts","behaviors","ids","descriptor","poseDescriptorOf","frame","scenePoseFrame","originPoses","originWorlds","originCenters","originRotations","visual","id","node","g","poseDescriptorForNode","world","carryPose","invertPlane","planeOf","b","visualBoundsViaDescriptor","union","unionAABB","startPointerAngle","readView","gestureViewReader","view","readPlane","gesturePlaneReader","scratch","\"pivot\"","readGestureLifecycle","p","moveGestureAdapter","turnedWorlds","out","origin","syncGestureCurrent","turned","shapeDelta","gctx","moveCtx","primary","raw","proposed","r","rotation","commitRotate","target","defaultCommitAdapter","reduceBehaviorEnd","commitGestureOps","lifecycle","ops","next","from","createTransformOp","recomputePreviews","layer","own","committed","reason","runBehaviorCancel","dropPreviewOverrides","selectionLayer"],"sources":["../../../../src/interactions/actions/defaults/rotate.ts"],"sourcesContent":["/**\n * `rotateAction` — ongoing Action descriptor for pointer-driven rotation.\n *\n * ## Status: REAL (unrotated-pivot path)\n *\n * Implements the core rotation math from `useRotate`:\n * - `start`: captures origin poses + AABB centers; computes start pointer\n * angle around the union center of selected nodes.\n * - `onMove`: derives pointer angle delta from start, applies to each node's\n * origin rotation. In union-pivot mode (multi-selection) orbits each item's\n * center around the union center.\n * - `onEnd('commit')`: builds one `createTransformOp` per node (from =\n * pre-mutation origin pose, to = rotated pose) and commits them as a\n * single batch → one undo entry for the whole drag. Routes through the\n * optional `applyOps` dep (consumer history) when present, else\n * `scene.applyBatch` + `defaultCommitAdapter`.\n * - `onEnd('cancel')`: no scene writes (scene never mutated during drag).\n *\n * ## Constraints vs `useRotate`\n *\n * - Reads and writes poses through the `poseDescriptor` dep; a pose whose\n * descriptor has no `withRotation`, or reports `supportsRotation` false, is\n * left alone.\n * - Behaviors (`opts.behaviors`) see the first rotated node's turned pose; a\n * pose one returns from `onMove` sets the rotation for the whole selection.\n * - No overlay rendering — deferred to Phase 7 overlay surface.\n * - Shift-snap (15° quantum) is NOT wired in this phase — omitted deliberately\n * to keep the invoker self-contained (would need to read shift from onMove ctx).\n * TODO: thread shift from InvocationCtx.modifiers.shift into snap logic.\n */\n\nimport { gesturePlaneReader, gestureViewReader } from '../../gestures/shared/screenTolerance';\nimport type { Action } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport { resolveParams } from '@weasel-js/routing';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport { syncPreviewOverrides, dropPreviewOverrides } from '../previewOverrides';\nimport type { Op } from 'core/ops/types';\nimport { createTransformOp } from 'core/ops/transform';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { poseDescriptorOf } from '../poseDescriptorDep';\nimport {\n poseDescriptorForNode,\n translatePoseViaDescriptor,\n visualBoundsViaDescriptor,\n type PoseDescriptor,\n} from '../resize/geometry';\nimport { scenePoseFrame, type PoseFrame } from '../poseFrame';\nimport { commitGestureOps, readGestureLifecycle, reduceBehaviorEnd, runBehaviorCancel, type GestureLifecycle } from '../gestureLifecycle';\nimport { moveGestureAdapter } from '../move/gestureAdapter';\nimport type { GestureContext, RotateBehavior, RotateProposed } from '../../gestures/types';\nimport { carryPose, invertPlane, inPlane, planeOf, selectionLayer } from '../planeInput';\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** Apply a rotation delta (radians) to a pose, optionally orbiting the item's\n * center around a shared union center. */\nfunction applyRotationDelta(\n d: PoseDescriptor<unknown>,\n pose: unknown,\n originRotation: number,\n delta: number,\n originCenter: { x: number; y: number },\n unionCenter: { x: number; y: number },\n useUnionPivot: boolean,\n): unknown {\n const rotated = d.withRotation!(pose, originRotation + delta);\n if (!useUnionPivot) return rotated;\n const cos = Math.cos(delta);\n const sin = Math.sin(delta);\n const ox = originCenter.x - unionCenter.x;\n const oy = originCenter.y - unionCenter.y;\n const nx = unionCenter.x + ox * cos - oy * sin;\n const ny = unionCenter.y + ox * sin + oy * cos;\n return translatePoseViaDescriptor(rotated, nx - originCenter.x, ny - originCenter.y, d);\n}\n\n// ---------------------------------------------------------------------------\n// Internal scratch\n// ---------------------------------------------------------------------------\n\ninterface RotateScratch {\n ids: NodeId[];\n scene: Scene<unknown, string, unknown>;\n descriptor: PoseDescriptor<unknown>;\n /** World reads and local writes over the scene's composition strategy. */\n frame: PoseFrame<unknown>;\n /** Origin pose for each selected node as stored — the `from` of its op. */\n originPoses: Map<NodeId, unknown>;\n /** Origin pose for each selected node in world — what the gesture turns. */\n originWorlds: Map<NodeId, unknown>;\n /** AABB center for each selected node (from origin pose). */\n originCenters: Map<NodeId, { x: number; y: number }>;\n /** Per-node origin rotation (radians). */\n originRotations: Map<NodeId, number>;\n /** Union center of all selected nodes — the rotation pivot. */\n unionCenter: { x: number; y: number };\n /** Pointer angle around unionCenter at drag start. */\n startPointerAngle: number;\n /** Running delta — updated each onMove, applied once at commit. */\n currentDelta: number;\n /** Use union pivot (multi-select) vs each item's own center. */\n useUnionPivot: boolean;\n /** In-flight preview poses keyed by node id. */\n previews: Map<NodeId, unknown>;\n overrideEntries: Map<NodeId, { pose: unknown }>;\n /** Optional consumer commit hook captured at gesture start. When present,\n * ops-based commits route through it (consumer history) instead of\n * `scene.applyBatch`. Undefined → fall back to `scene.applyBatch`. */\n applyOps?: (ops: Op[], label: string) => void;\n lifecycle: GestureLifecycle;\n behaviors: RotateBehavior<unknown>[];\n /** Reused gesture context handed to behaviors across the drag. */\n gestureCtx: GestureContext<unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Descriptor\n// ---------------------------------------------------------------------------\n\n/**\n * @experimental\n * Static descriptor for the `rotate` Action.\n *\n * Requires dep-schema entries: `selection`, `scene`.\n *\n * Implements the unrotated-pivot rotation path from `useRotate`.\n *\n * @see useRotate — the React hook this descriptor mirrors for the rect case.\n */\nexport const rotateAction: Action & { requires: string[] } = inPlane({\n id: 'rotate',\n label: 'Rotate',\n // No default binding. It used to be a bare `{ kind: 'drag' }`, which made\n // any drag no active tool claimed rotate a non-empty selection. The rotation\n // handle binds it (`selectionRotateBindings`, the `rotate` preset).\n eligible: { capability: 'transforms-selection' },\n requires: ['selection', 'scene', 'applyOps', 'poseDescriptor', 'poseComposition', 'view'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts): OngoingHandle {\n const selection = ctx.deps.selection;\n const scene = ctx.deps.scene;\n const applyOps = ctx.deps.applyOps;\n const params = resolveParams(opts?.params);\n const behaviors = (opts?.behaviors ?? []) as RotateBehavior<unknown>[];\n\n if (!selection || !scene) return {};\n\n const ids = selection.get() as NodeId[];\n if (ids.length === 0) return {};\n\n const descriptor = poseDescriptorOf(ctx.deps.poseDescriptor);\n // The pivot the pointer orbits is a world point, so every pose the\n // gesture turns is a world pose. Each turned result is stored back in\n // the node's own parent frame at preview and commit alike.\n const frame = scenePoseFrame(scene, ctx.deps.poseComposition);\n const originPoses = new Map<NodeId, unknown>();\n const originWorlds = new Map<NodeId, unknown>();\n const originCenters = new Map<NodeId, { x: number; y: number }>();\n const originRotations = new Map<NodeId, number>();\n const visual: Bounds[] = [];\n\n for (const id of ids) {\n const node = scene.get(id);\n if (!node) continue;\n const g = poseDescriptorForNode(descriptor, node);\n if (!g.withRotation || g.supportsRotation?.(node.pose) === false) continue;\n originPoses.set(id, node.pose);\n // The pivot is a world point, so every measurement the gesture orbits\n // is taken from the world pose, not the stored one — carried into the\n // plane the edit is measured in, where the pointer's angle is read.\n const world = carryPose(g, frame.world(id), invertPlane(planeOf(ctx.deps.view, node.layer)));\n originWorlds.set(id, world);\n const b = g.getBounds(world);\n originCenters.set(id, { x: b.x + b.width / 2, y: b.y + b.height / 2 });\n originRotations.set(id, g.getRotation?.(world) ?? 0);\n visual.push(visualBoundsViaDescriptor(world, g));\n }\n\n if (originPoses.size === 0) return {};\n\n const union = unionAABB(visual)!;\n const unionCenter = { x: union.x + union.width / 2, y: union.y + union.height / 2 };\n const startPointerAngle = Math.atan2(\n ctx.world.y - unionCenter.y,\n ctx.world.x - unionCenter.x,\n );\n\n const readView = gestureViewReader(ctx.deps);\n const view = ctx.deps.view;\n\n const readPlane = gesturePlaneReader(ctx.deps);\n const scratch: RotateScratch = {\n ids,\n scene,\n descriptor,\n frame,\n originPoses,\n originWorlds,\n originCenters,\n originRotations,\n unionCenter,\n startPointerAngle,\n currentDelta: 0,\n useUnionPivot: ids.length > 1 && params?.['pivot'] !== 'each',\n previews: new Map<NodeId, unknown>(),\n overrideEntries: new Map<NodeId, { pose: unknown }>(),\n applyOps,\n lifecycle: readGestureLifecycle(params, 'Rotate', behaviors),\n behaviors,\n gestureCtx: {\n draggedIds: [...originPoses.keys()] as string[],\n origin: new Map([...originWorlds].map(([id, p]) => [id as string, p])),\n current: new Map([...originWorlds].map(([id, p]) => [id as string, p])),\n snap: null,\n modifiers: { ...ctx.modifiers },\n pointer: { worldX: ctx.world.x, worldY: ctx.world.y, clientX: 0, clientY: 0 },\n view: readView(),\n plane: readPlane(),\n adapter: moveGestureAdapter(scene) as unknown as GestureContext<unknown>['adapter'],\n scratch: {},\n },\n };\n const { lifecycle } = scratch;\n\n /** Each rotated node's world pose turned by `delta`. */\n const turnedWorlds = (delta: number): Map<NodeId, unknown> => {\n const out = new Map<NodeId, unknown>();\n for (const [id, origin] of scratch.originWorlds) {\n out.set(id, applyRotationDelta(\n scratch.descriptor,\n origin,\n scratch.originRotations.get(id) ?? 0,\n delta,\n scratch.originCenters.get(id) ?? { x: 0, y: 0 },\n scratch.unionCenter,\n scratch.useUnionPivot,\n ));\n }\n return out;\n };\n\n const syncGestureCurrent = (delta: number): Map<NodeId, unknown> => {\n const turned = turnedWorlds(delta);\n for (const [id, pose] of turned) scratch.gestureCtx.current.set(id as string, pose);\n return turned;\n };\n\n /** The pointer's delta as the behaviors reshape it. */\n const shapeDelta = (moveCtx: InvocationCtx, raw: number): number => {\n const gctx = scratch.gestureCtx;\n gctx.modifiers = { ...moveCtx.modifiers };\n gctx.pointer = { worldX: moveCtx.world.x, worldY: moveCtx.world.y, clientX: 0, clientY: 0 };\n gctx.view = readView();\n gctx.plane = readPlane();\n const primary = scratch.originWorlds.keys().next().value as NodeId;\n const originRotation = scratch.originRotations.get(primary) ?? 0;\n let delta = raw;\n let proposed: RotateProposed<unknown> = {\n pose: syncGestureCurrent(raw).get(primary),\n rotation: originRotation + raw,\n };\n for (const b of scratch.behaviors) {\n const r = b.onMove?.(gctx, proposed);\n if (!r || r.pose === undefined) continue;\n const rotation = scratch.descriptor.getRotation?.(r.pose) ?? 0;\n delta = rotation - originRotation;\n proposed = { pose: r.pose, rotation };\n }\n return delta;\n };\n\n // Returns whether anything reached the document.\n const commitRotate = (): boolean => {\n const target = {\n scene,\n applyOps: scratch.applyOps,\n adapter: defaultCommitAdapter(scene, selection.adapterMethods),\n };\n if (scratch.behaviors.length > 0) {\n syncGestureCurrent(scratch.currentDelta);\n const r = reduceBehaviorEnd(scratch.behaviors, scratch.gestureCtx);\n if (r === null) return false;\n if (r !== undefined) {\n commitGestureOps(target, lifecycle, r);\n return true;\n }\n }\n if (scratch.currentDelta === 0) return false;\n // One transform op per node: `from` is the origin pose captured at drag\n // start, `to` the rotated preview. A single batch, so one undo entry.\n const ops: Op[] = [];\n for (const id of scratch.ids) {\n const next = scratch.previews.get(id);\n if (next === undefined) continue;\n const from = scratch.originPoses.get(id);\n if (from === undefined) continue;\n ops.push(createTransformOp<unknown>({\n id: id as string,\n from,\n to: next,\n label: lifecycle.label,\n }));\n }\n if (ops.length === 0) return false;\n commitGestureOps(target, lifecycle, ops);\n return true;\n };\n\n const recomputePreviews = (delta: number) => {\n scratch.previews.clear();\n if (delta !== 0) {\n for (const [id, turned] of turnedWorlds(delta)) {\n const layer = scratch.scene.get(id)?.layer;\n const own = layer === undefined ? null : planeOf(view, layer);\n scratch.previews.set(id, scratch.frame.local(id, carryPose(scratch.descriptor, turned, own)));\n }\n }\n syncPreviewOverrides(scratch);\n };\n\n for (const b of behaviors) b.onStart?.(scratch.gestureCtx);\n lifecycle.start(scratch.gestureCtx.draggedIds);\n\n return {\n kind: 'rotate',\n onMove(moveCtx: InvocationCtx): void {\n const pointerAngle = Math.atan2(\n moveCtx.world.y - scratch.unionCenter.y,\n moveCtx.world.x - scratch.unionCenter.x,\n );\n const raw = pointerAngle - scratch.startPointerAngle;\n scratch.currentDelta = scratch.behaviors.length > 0 ? shapeDelta(moveCtx, raw) : raw;\n recomputePreviews(scratch.currentDelta);\n },\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n if (reason === 'commit') committed = commitRotate();\n else runBehaviorCancel(scratch.behaviors, scratch.gestureCtx);\n } finally {\n dropPreviewOverrides(scratch);\n scratch.previews.clear();\n lifecycle.end(committed);\n }\n },\n previewIds: () => scratch.previews.keys(),\n previewPose: (id: string) => scratch.previews.get(id as NodeId) ?? null,\n };\n },\n },\n enabled: () => true,\n}, selectionLayer);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rotate.js","names":["applyRotationDelta","rotated","d","pose","originRotation","delta","useUnionPivot","cos","sin","ox","originCenter","unionCenter","oy","nx","ny","translatePoseViaDescriptor","rotateAction","inPlane","selection","ctx","scene","applyOps","params","resolveParams","opts","behaviors","ids","shapeSources","descriptorOf","nodeDescriptors","poseDescriptorOf","frame","scenePoseFrame","originPoses","originWorlds","originCenters","originRotations","visual","id","node","g","world","carryPose","invertPlane","planeOf","b","visualBoundsViaDescriptor","union","unionAABB","startPointerAngle","readView","gestureViewReader","view","readPlane","gesturePlaneReader","scratch","\"pivot\"","readGestureLifecycle","p","moveGestureAdapter","turnedWorlds","out","origin","syncGestureCurrent","turned","shapeDelta","gctx","moveCtx","primary","raw","proposed","r","rotation","commitRotate","target","defaultCommitAdapter","reduceBehaviorEnd","commitGestureOps","lifecycle","ops","next","from","createTransformOp","recomputePreviews","layer","own","committed","reason","runBehaviorCancel","dropPreviewOverrides","selectionLayer"],"sources":["../../../../src/interactions/actions/defaults/rotate.ts"],"sourcesContent":["/**\n * `rotateAction` — ongoing Action descriptor for pointer-driven rotation.\n *\n * The rotation math:\n * - `start`: captures origin poses + AABB centers; computes start pointer\n * angle around the union center of selected nodes.\n * - `onMove`: derives pointer angle delta from start, applies to each node's\n * origin rotation. In union-pivot mode (multi-selection) orbits each item's\n * center around the union center.\n * - `onEnd('commit')`: builds one `createTransformOp` per node (from =\n * pre-mutation origin pose, to = rotated pose) and commits them as a\n * single batch → one undo entry for the whole drag. Routes through the\n * optional `applyOps` dep (consumer history) when present, else\n * `scene.applyBatch` + `defaultCommitAdapter`.\n * - `onEnd('cancel')`: no scene writes (scene never mutated during drag).\n *\n * ## Constraints\n *\n * - Reads and writes poses through the `poseDescriptor` dep; a pose whose\n * descriptor has no `withRotation`, or reports `supportsRotation` false, is\n * left alone.\n * - Behaviors (`opts.behaviors`) see the first rotated node's turned pose; a\n * pose one returns from `onMove` sets the rotation for the whole selection.\n * - Shift-snap (15° quantum) is NOT wired in this phase — omitted deliberately\n * to keep the invoker self-contained (would need to read shift from onMove ctx).\n * TODO: thread shift from InvocationCtx.modifiers.shift into snap logic.\n */\n\nimport { gesturePlaneReader, gestureViewReader } from '../../gestures/shared/screenTolerance';\nimport type { Action } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport { resolveParams } from '@weasel-js/routing';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport { syncPreviewOverrides, dropPreviewOverrides } from '../previewOverrides';\nimport type { Op } from 'core/ops/types';\nimport { createTransformOp } from 'core/ops/transform';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { nodeDescriptors, poseDescriptorOf } from '../poseDescriptorDep';\nimport {\n translatePoseViaDescriptor,\n visualBoundsViaDescriptor,\n type PoseDescriptor,\n} from '../resize/geometry';\nimport { scenePoseFrame, type PoseFrame } from '../poseFrame';\nimport { commitGestureOps, readGestureLifecycle, reduceBehaviorEnd, runBehaviorCancel, type GestureLifecycle } from '../gestureLifecycle';\nimport { moveGestureAdapter } from '../move/gestureAdapter';\nimport type { GestureContext, RotateBehavior, RotateProposed } from '../../gestures/types';\nimport { carryPose, invertPlane, inPlane, planeOf, selectionLayer } from '../planeInput';\nimport { shapeSources } from '../selectionSubtree';\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** Apply a rotation delta (radians) to a pose, optionally orbiting the item's\n * center around a shared union center. */\nfunction applyRotationDelta(\n d: PoseDescriptor<unknown>,\n pose: unknown,\n originRotation: number,\n delta: number,\n originCenter: { x: number; y: number },\n unionCenter: { x: number; y: number },\n useUnionPivot: boolean,\n): unknown {\n const rotated = d.withRotation!(pose, originRotation + delta);\n if (!useUnionPivot) return rotated;\n const cos = Math.cos(delta);\n const sin = Math.sin(delta);\n const ox = originCenter.x - unionCenter.x;\n const oy = originCenter.y - unionCenter.y;\n const nx = unionCenter.x + ox * cos - oy * sin;\n const ny = unionCenter.y + ox * sin + oy * cos;\n return translatePoseViaDescriptor(rotated, nx - originCenter.x, ny - originCenter.y, d);\n}\n\n// ---------------------------------------------------------------------------\n// Internal scratch\n// ---------------------------------------------------------------------------\n\ninterface RotateScratch {\n ids: NodeId[];\n scene: Scene<unknown, string, unknown>;\n descriptorOf: (id: NodeId) => PoseDescriptor<unknown>;\n /** World reads and local writes over the scene's composition strategy. */\n frame: PoseFrame<unknown>;\n /** Origin pose for each selected node as stored — the `from` of its op. */\n originPoses: Map<NodeId, unknown>;\n /** Origin pose for each selected node in world — what the gesture turns. */\n originWorlds: Map<NodeId, unknown>;\n /** AABB center for each selected node (from origin pose). */\n originCenters: Map<NodeId, { x: number; y: number }>;\n /** Per-node origin rotation (radians). */\n originRotations: Map<NodeId, number>;\n /** Union center of all selected nodes — the rotation pivot. */\n unionCenter: { x: number; y: number };\n /** Pointer angle around unionCenter at drag start. */\n startPointerAngle: number;\n /** Running delta — updated each onMove, applied once at commit. */\n currentDelta: number;\n /** Use union pivot (multi-select) vs each item's own center. */\n useUnionPivot: boolean;\n /** In-flight preview poses keyed by node id. */\n previews: Map<NodeId, unknown>;\n overrideEntries: Map<NodeId, { pose: unknown }>;\n /** Optional consumer commit hook captured at gesture start. When present,\n * ops-based commits route through it (consumer history) instead of\n * `scene.applyBatch`. Undefined → fall back to `scene.applyBatch`. */\n applyOps?: (ops: Op[], label: string) => void;\n lifecycle: GestureLifecycle;\n behaviors: RotateBehavior<unknown>[];\n /** Reused gesture context handed to behaviors across the drag. */\n gestureCtx: GestureContext<unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Descriptor\n// ---------------------------------------------------------------------------\n\n/**\n * @experimental\n * Static descriptor for the `rotate` Action.\n *\n * Requires dep-schema entries: `selection`, `scene`.\n *\n */\nexport const rotateAction: Action & { requires: string[] } = inPlane({\n id: 'rotate',\n label: 'Rotate',\n // No default binding. It used to be a bare `{ kind: 'drag' }`, which made\n // any drag no active tool claimed rotate a non-empty selection. The rotation\n // handle binds it (`selectionRotateBindings`, the `rotate` preset).\n eligible: { capability: 'transforms-selection' },\n requires: ['selection', 'scene', 'applyOps', 'poseDescriptor', 'poseComposition', 'view'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts): OngoingHandle {\n const selection = ctx.deps.selection;\n const scene = ctx.deps.scene;\n const applyOps = ctx.deps.applyOps;\n const params = resolveParams(opts?.params);\n const behaviors = (opts?.behaviors ?? []) as RotateBehavior<unknown>[];\n\n if (!selection || !scene) return {};\n\n // A group whose pose derives from its children turns by turning them.\n const ids = shapeSources(scene, selection.get()) as NodeId[];\n if (ids.length === 0) return {};\n\n const descriptorOf = nodeDescriptors(scene, poseDescriptorOf(ctx.deps.poseDescriptor));\n // The pivot the pointer orbits is a world point, so every pose the\n // gesture turns is a world pose. Each turned result is stored back in\n // the node's own parent frame at preview and commit alike.\n const frame = scenePoseFrame(scene, ctx.deps.poseComposition);\n const originPoses = new Map<NodeId, unknown>();\n const originWorlds = new Map<NodeId, unknown>();\n const originCenters = new Map<NodeId, { x: number; y: number }>();\n const originRotations = new Map<NodeId, number>();\n const visual: Bounds[] = [];\n\n for (const id of ids) {\n const node = scene.get(id);\n if (!node) continue;\n const g = descriptorOf(id);\n if (!g.withRotation || g.supportsRotation?.(node.pose) === false) continue;\n originPoses.set(id, node.pose);\n // The pivot is a world point, so every measurement the gesture orbits\n // is taken from the world pose, not the stored one — carried into the\n // plane the edit is measured in, where the pointer's angle is read.\n const world = carryPose(g, frame.world(id), invertPlane(planeOf(ctx.deps.view, node.layer)));\n originWorlds.set(id, world);\n const b = g.getBounds(world);\n originCenters.set(id, { x: b.x + b.width / 2, y: b.y + b.height / 2 });\n originRotations.set(id, g.getRotation?.(world) ?? 0);\n visual.push(visualBoundsViaDescriptor(world, g));\n }\n\n if (originPoses.size === 0) return {};\n\n const union = unionAABB(visual)!;\n const unionCenter = { x: union.x + union.width / 2, y: union.y + union.height / 2 };\n const startPointerAngle = Math.atan2(\n ctx.world.y - unionCenter.y,\n ctx.world.x - unionCenter.x,\n );\n\n const readView = gestureViewReader(ctx.deps);\n const view = ctx.deps.view;\n\n const readPlane = gesturePlaneReader(ctx.deps);\n const scratch: RotateScratch = {\n ids,\n scene,\n descriptorOf,\n frame,\n originPoses,\n originWorlds,\n originCenters,\n originRotations,\n unionCenter,\n startPointerAngle,\n currentDelta: 0,\n useUnionPivot: ids.length > 1 && params?.['pivot'] !== 'each',\n previews: new Map<NodeId, unknown>(),\n overrideEntries: new Map<NodeId, { pose: unknown }>(),\n applyOps,\n lifecycle: readGestureLifecycle(params, 'Rotate', behaviors),\n behaviors,\n gestureCtx: {\n draggedIds: [...originPoses.keys()] as string[],\n origin: new Map([...originWorlds].map(([id, p]) => [id as string, p])),\n current: new Map([...originWorlds].map(([id, p]) => [id as string, p])),\n snap: null,\n modifiers: { ...ctx.modifiers },\n pointer: { worldX: ctx.world.x, worldY: ctx.world.y, clientX: 0, clientY: 0 },\n view: readView(),\n plane: readPlane(),\n adapter: moveGestureAdapter(scene) as unknown as GestureContext<unknown>['adapter'],\n scratch: {},\n },\n };\n const { lifecycle } = scratch;\n\n /** Each rotated node's world pose turned by `delta`. */\n const turnedWorlds = (delta: number): Map<NodeId, unknown> => {\n const out = new Map<NodeId, unknown>();\n for (const [id, origin] of scratch.originWorlds) {\n out.set(id, applyRotationDelta(\n scratch.descriptorOf(id),\n origin,\n scratch.originRotations.get(id) ?? 0,\n delta,\n scratch.originCenters.get(id) ?? { x: 0, y: 0 },\n scratch.unionCenter,\n scratch.useUnionPivot,\n ));\n }\n return out;\n };\n\n const syncGestureCurrent = (delta: number): Map<NodeId, unknown> => {\n const turned = turnedWorlds(delta);\n for (const [id, pose] of turned) scratch.gestureCtx.current.set(id as string, pose);\n return turned;\n };\n\n /** The pointer's delta as the behaviors reshape it. */\n const shapeDelta = (moveCtx: InvocationCtx, raw: number): number => {\n const gctx = scratch.gestureCtx;\n gctx.modifiers = { ...moveCtx.modifiers };\n gctx.pointer = { worldX: moveCtx.world.x, worldY: moveCtx.world.y, clientX: 0, clientY: 0 };\n gctx.view = readView();\n gctx.plane = readPlane();\n const primary = scratch.originWorlds.keys().next().value as NodeId;\n const originRotation = scratch.originRotations.get(primary) ?? 0;\n let delta = raw;\n let proposed: RotateProposed<unknown> = {\n pose: syncGestureCurrent(raw).get(primary),\n rotation: originRotation + raw,\n };\n for (const b of scratch.behaviors) {\n const r = b.onMove?.(gctx, proposed);\n if (!r || r.pose === undefined) continue;\n const rotation = scratch.descriptorOf(primary).getRotation?.(r.pose) ?? 0;\n delta = rotation - originRotation;\n proposed = { pose: r.pose, rotation };\n }\n return delta;\n };\n\n // Returns whether anything reached the document.\n const commitRotate = (): boolean => {\n const target = {\n scene,\n applyOps: scratch.applyOps,\n adapter: defaultCommitAdapter(scene, selection.adapterMethods),\n };\n if (scratch.behaviors.length > 0) {\n syncGestureCurrent(scratch.currentDelta);\n const r = reduceBehaviorEnd(scratch.behaviors, scratch.gestureCtx);\n if (r === null) return false;\n if (r !== undefined) {\n commitGestureOps(target, lifecycle, r);\n return true;\n }\n }\n if (scratch.currentDelta === 0) return false;\n // One transform op per node: `from` is the origin pose captured at drag\n // start, `to` the rotated preview. A single batch, so one undo entry.\n const ops: Op[] = [];\n for (const id of scratch.ids) {\n const next = scratch.previews.get(id);\n if (next === undefined) continue;\n const from = scratch.originPoses.get(id);\n if (from === undefined) continue;\n ops.push(createTransformOp<unknown>({\n id: id as string,\n from,\n to: next,\n label: lifecycle.label,\n }));\n }\n if (ops.length === 0) return false;\n commitGestureOps(target, lifecycle, ops);\n return true;\n };\n\n const recomputePreviews = (delta: number) => {\n scratch.previews.clear();\n if (delta !== 0) {\n for (const [id, turned] of turnedWorlds(delta)) {\n const layer = scratch.scene.get(id)?.layer;\n const own = layer === undefined ? null : planeOf(view, layer);\n scratch.previews.set(id, scratch.frame.local(id, carryPose(scratch.descriptorOf(id), turned, own)));\n }\n }\n syncPreviewOverrides(scratch);\n };\n\n for (const b of behaviors) b.onStart?.(scratch.gestureCtx);\n lifecycle.start(scratch.gestureCtx.draggedIds);\n\n return {\n kind: 'rotate',\n onMove(moveCtx: InvocationCtx): void {\n const pointerAngle = Math.atan2(\n moveCtx.world.y - scratch.unionCenter.y,\n moveCtx.world.x - scratch.unionCenter.x,\n );\n const raw = pointerAngle - scratch.startPointerAngle;\n scratch.currentDelta = scratch.behaviors.length > 0 ? shapeDelta(moveCtx, raw) : raw;\n recomputePreviews(scratch.currentDelta);\n },\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n if (reason === 'commit') committed = commitRotate();\n else runBehaviorCancel(scratch.behaviors, scratch.gestureCtx);\n } finally {\n dropPreviewOverrides(scratch);\n scratch.previews.clear();\n lifecycle.end(committed);\n }\n },\n previewIds: () => scratch.previews.keys(),\n previewPose: (id: string) => scratch.previews.get(id as NodeId) ?? null,\n };\n },\n },\n enabled: () => true,\n}, selectionLayer);\n"],"mappings":"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"}
|