@weasel-js/core 1.13.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +300 -0
- package/README.md +8 -12
- package/dist/affordances/hitAffordanceRegions.js +1 -1
- package/dist/affordances/hitAffordanceRegions.js.map +1 -1
- package/dist/affordances/pathAnchors.js.map +1 -1
- package/dist/animation/clipTargets.js +1 -1
- package/dist/animation/clipTargets.js.map +1 -1
- package/dist/animation/poseTarget.js +5 -32
- package/dist/animation/poseTarget.js.map +1 -1
- package/dist/{autoPoseDescriptor-CZ1eXbzY.d.ts → autoPoseDescriptor-C25QVb0W.d.ts} +1 -1
- package/dist/barrel/canvas.js +8 -8
- package/dist/barrel/chrome.js +9 -9
- package/dist/barrel/input.js +1 -1
- package/dist/barrel/interactions.js +3 -3
- package/dist/barrel/paint.js +2 -2
- package/dist/barrel/paths.js +19 -17
- package/dist/barrel/renderer.js +11 -7
- package/dist/barrel/routing.js +4 -1
- package/dist/barrel/scene.js +16 -12
- package/dist/barrel/text.js +5 -5
- package/dist/barrel/viewport.js +8 -8
- package/dist/canvas/Canvas.js +2 -2
- package/dist/canvas/Canvas.js.map +1 -1
- package/dist/canvas/CanvasView.js +20 -14
- package/dist/canvas/CanvasView.js.map +1 -1
- package/dist/canvas/GestureReason.js +64 -0
- package/dist/canvas/GestureReason.js.map +1 -0
- package/dist/canvas/GestureReason.module.js +7 -0
- package/dist/canvas/GestureReason.module.js.map +1 -0
- package/dist/canvas/LeanSceneCanvas.js +3 -1
- package/dist/canvas/LeanSceneCanvas.js.map +1 -1
- package/dist/canvas/NodeShape.js +2 -0
- package/dist/canvas/NodeShape.js.map +1 -1
- package/dist/canvas/PickHud.js +7 -3
- package/dist/canvas/PickHud.js.map +1 -1
- package/dist/canvas/SceneCanvas/CanvasKitProviders.js +1 -1
- package/dist/canvas/SceneCanvas/CanvasKitProviders.js.map +1 -1
- package/dist/canvas/SceneCanvas/DevHuds.js +2 -2
- package/dist/canvas/SceneCanvas/DevHuds.js.map +1 -1
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +4 -2
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js.map +1 -1
- package/dist/canvas/SceneCanvas/SceneCanvasInput.js +3 -1
- package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
- package/dist/canvas/SceneCanvas/brushOverlay.js.map +1 -1
- package/dist/canvas/SceneCanvas/builtinToolSets.js +17 -9
- package/dist/canvas/SceneCanvas/builtinToolSets.js.map +1 -1
- package/dist/canvas/SceneCanvas/canvasPassThrough.js +2 -1
- package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js +75 -19
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js +7 -1
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultTextEditor.js +108 -0
- package/dist/canvas/SceneCanvas/defaultTextEditor.js.map +1 -0
- package/dist/canvas/SceneCanvas/describePresets.js +47 -0
- package/dist/canvas/SceneCanvas/describePresets.js.map +1 -0
- package/dist/canvas/SceneCanvas/features.js +57 -16
- package/dist/canvas/SceneCanvas/features.js.map +1 -1
- package/dist/canvas/SceneCanvas/mergeLayers.js +10 -1
- package/dist/canvas/SceneCanvas/mergeLayers.js.map +1 -1
- package/dist/canvas/SceneCanvas/namedPresets.js +52 -24
- package/dist/canvas/SceneCanvas/namedPresets.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/arrange.js +35 -10
- package/dist/canvas/SceneCanvas/presets/arrange.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/baseline.js +9 -0
- package/dist/canvas/SceneCanvas/presets/baseline.js.map +1 -0
- package/dist/canvas/SceneCanvas/presets/chrome.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/composites.js +43 -0
- package/dist/canvas/SceneCanvas/presets/composites.js.map +1 -0
- package/dist/canvas/SceneCanvas/presets/edit.js +79 -26
- package/dist/canvas/SceneCanvas/presets/edit.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/ingest.js +1 -0
- package/dist/canvas/SceneCanvas/presets/ingest.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/paths.js +58 -16
- package/dist/canvas/SceneCanvas/presets/paths.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/select.js +4 -2
- package/dist/canvas/SceneCanvas/presets/select.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/tools.js +24 -0
- package/dist/canvas/SceneCanvas/presets/tools.js.map +1 -0
- package/dist/canvas/SceneCanvas/presets/transform.js +4 -0
- package/dist/canvas/SceneCanvas/presets/transform.js.map +1 -1
- package/dist/canvas/SceneCanvas/presets/view.js +3 -1
- package/dist/canvas/SceneCanvas/presets/view.js.map +1 -1
- package/dist/canvas/SceneCanvas/props.js.map +1 -1
- package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js +1 -1
- package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js.map +1 -1
- package/dist/canvas/SceneCanvas/toolRegistry.js +5 -4
- package/dist/canvas/SceneCanvas/toolRegistry.js.map +1 -1
- package/dist/canvas/SceneCanvas/useCanvasTools.js +26 -10
- package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/useContributionRoles.js +15 -2
- package/dist/canvas/SceneCanvas/useContributionRoles.js.map +1 -1
- package/dist/canvas/SceneCanvas/useDepartureGhostLayer.js +5 -4
- package/dist/canvas/SceneCanvas/useDepartureGhostLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js +1 -1
- package/dist/canvas/SceneCanvas/useNodeAtPoint.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +9 -8
- package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasPathEdit.js +2 -2
- package/dist/canvas/SceneCanvas/useSceneCanvasPathEdit.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +4 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneChrome.js +7 -4
- package/dist/canvas/SceneCanvas/useSceneChrome.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js +9 -9
- package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js.map +1 -1
- package/dist/canvas/SceneCanvas/useScenePicking.js +4 -7
- package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneRedrawSources.js +2 -1
- package/dist/canvas/SceneCanvas/useSceneRedrawSources.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js +6 -6
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneStandardActions.js +2 -2
- package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js +1 -1
- package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSurfaceViewInputs.js.map +1 -1
- package/dist/canvas/SceneCanvas/useToolKeybindings.js +2 -2
- package/dist/canvas/SceneCanvas/useToolKeybindings.js.map +1 -1
- package/dist/canvas/SceneCanvas/useViewportActions.js +5 -2
- package/dist/canvas/SceneCanvas/useViewportActions.js.map +1 -1
- package/dist/canvas/SceneCanvas/worldPointAt.js.map +1 -1
- package/dist/canvas/SceneCanvas.js +22 -11
- package/dist/canvas/SceneCanvas.js.map +1 -1
- package/dist/canvas/SceneViewCanvas.js +1 -0
- package/dist/canvas/SceneViewCanvas.js.map +1 -1
- package/dist/canvas/ViewMarker.js.map +1 -1
- package/dist/canvas/accentColor.js +14 -1
- package/dist/canvas/accentColor.js.map +1 -1
- package/dist/canvas/affordanceAt.js +2 -2
- package/dist/canvas/affordanceAt.js.map +1 -1
- package/dist/canvas/buildSceneTree.js +5 -3
- package/dist/canvas/buildSceneTree.js.map +1 -1
- package/dist/canvas/deps/editAnchors.js +4 -4
- package/dist/canvas/deps/editAnchors.js.map +1 -1
- package/dist/canvas/deps/enteredGroup.js +14 -5
- package/dist/canvas/deps/enteredGroup.js.map +1 -1
- package/dist/canvas/deps/ingestion.js +5 -1
- package/dist/canvas/deps/ingestion.js.map +1 -1
- package/dist/canvas/deps/insert.js.map +1 -1
- package/dist/canvas/deps/insertSite.js +5 -3
- package/dist/canvas/deps/insertSite.js.map +1 -1
- package/dist/canvas/deps/nodeAtPoint.js +1 -12
- package/dist/canvas/deps/nodeAtPoint.js.map +1 -1
- package/dist/canvas/deps/pathEditCommits.js +3 -3
- package/dist/canvas/deps/pathEditCommits.js.map +1 -1
- package/dist/canvas/deps/slice.js +16 -2
- package/dist/canvas/deps/slice.js.map +1 -1
- package/dist/canvas/deps/snap.js +5 -5
- package/dist/canvas/deps/snap.js.map +1 -1
- package/dist/canvas/deps/textEdit.js +5 -6
- package/dist/canvas/deps/textEdit.js.map +1 -1
- package/dist/canvas/derivedPath.js +8 -3
- package/dist/canvas/derivedPath.js.map +1 -1
- package/dist/canvas/getNodeAtPoint.js +2 -2
- package/dist/canvas/getNodeAtPoint.js.map +1 -1
- package/dist/canvas/insertPreviewExtent.js.map +1 -1
- package/dist/canvas/layerSlots.js.map +1 -1
- package/dist/canvas/nodeShapes/measurePainter.js +1 -1
- package/dist/canvas/nodeShapes/measurePainter.js.map +1 -1
- package/dist/canvas/nodeShapes/strokedBounds.js +5 -3
- package/dist/canvas/nodeShapes/strokedBounds.js.map +1 -1
- package/dist/canvas/overlayRoleStrokes.js +6 -0
- package/dist/canvas/overlayRoleStrokes.js.map +1 -1
- package/dist/canvas/pickIndex/scenePickIndex.js +10 -12
- package/dist/canvas/pickIndex/scenePickIndex.js.map +1 -1
- package/dist/canvas/sceneAdapter.js +10 -19
- package/dist/canvas/sceneAdapter.js.map +1 -1
- package/dist/canvas/sceneClipboard.js +17 -4
- package/dist/canvas/sceneClipboard.js.map +1 -1
- package/dist/canvas/sceneViewRender.js +3 -2
- package/dist/canvas/sceneViewRender.js.map +1 -1
- package/dist/canvas/surfaceContribution.js.map +1 -1
- package/dist/canvas/useCanvasPaint.js +10 -4
- package/dist/canvas/useCanvasPaint.js.map +1 -1
- package/dist/canvas/useHitObserver.js +1 -1
- package/dist/canvas/useHitObserver.js.map +1 -1
- package/dist/canvas/useViewAim.js +1 -1
- package/dist/canvas/useViewAim.js.map +1 -1
- package/dist/canvas/useViewHelpers.js +8 -5
- package/dist/canvas/useViewHelpers.js.map +1 -1
- package/dist/canvas/useViewNesting.js +39 -12
- package/dist/canvas/useViewNesting.js.map +1 -1
- package/dist/canvas/viewInputs.js.map +1 -1
- package/dist/canvas/viewMarkers.js +2 -2
- package/dist/canvas/viewMarkers.js.map +1 -1
- package/dist/canvas/viewRegistry.js +2 -2
- package/dist/canvas/viewRegistry.js.map +1 -1
- package/dist/canvas/viewSnap.js +67 -0
- package/dist/canvas/viewSnap.js.map +1 -0
- package/dist/clipboard.d.ts +6 -12
- package/dist/{clone-qb2e1F5p.d.ts → clone-Bz4iqGfE.d.ts} +10 -5
- package/dist/clone.d.ts +5 -5
- package/dist/core/geometry/booleanOfPaths.js +23 -0
- package/dist/core/geometry/booleanOfPaths.js.map +1 -0
- package/dist/core/geometry/pathPoseDescriptor.js +12 -9
- package/dist/core/geometry/pathPoseDescriptor.js.map +1 -1
- package/dist/core/geometry/poseDescriptor.js +12 -3
- package/dist/core/geometry/poseDescriptor.js.map +1 -1
- package/dist/core/geometry/targetFrame.js +2 -13
- package/dist/core/geometry/targetFrame.js.map +1 -1
- package/dist/core/layers/render.js +2 -1
- package/dist/core/layers/render.js.map +1 -1
- package/dist/core/layers/retain.js +5 -3
- package/dist/core/layers/retain.js.map +1 -1
- package/dist/core/ops/setPath.js +3 -0
- package/dist/core/ops/setPath.js.map +1 -1
- package/dist/core/paint/meshKindLazy.js.map +1 -1
- package/dist/core/paint/paintKindEntry.js.map +1 -1
- package/dist/core/paint/paintKinds.js +8 -1
- package/dist/core/paint/paintKinds.js.map +1 -1
- package/dist/core/scene/NodeProperties.js.map +1 -1
- package/dist/core/scene/NodeRouting.js.map +1 -1
- package/dist/core/scene/booleanGroup.js +33 -0
- package/dist/core/scene/booleanGroup.js.map +1 -0
- package/dist/core/scene/booleanOfChildren.js +53 -0
- package/dist/core/scene/booleanOfChildren.js.map +1 -0
- package/dist/core/scene/carryDescendants.js +18 -6
- package/dist/core/scene/carryDescendants.js.map +1 -1
- package/dist/core/scene/composeFrame.js +42 -5
- package/dist/core/scene/composeFrame.js.map +1 -1
- package/dist/core/scene/composePose.js +35 -16
- package/dist/core/scene/composePose.js.map +1 -1
- package/dist/core/scene/depMemo.js +36 -18
- package/dist/core/scene/depMemo.js.map +1 -1
- package/dist/core/scene/derivedParts.js +2 -23
- package/dist/core/scene/derivedParts.js.map +1 -1
- package/dist/core/scene/effectivePose.js +10 -0
- package/dist/core/scene/effectivePose.js.map +1 -1
- package/dist/core/scene/historyForm.js +5 -4
- package/dist/core/scene/historyForm.js.map +1 -1
- package/dist/core/scene/kitOps.js +5 -71
- package/dist/core/scene/kitOps.js.map +1 -1
- package/dist/core/scene/kitRegistry.js +5 -0
- package/dist/core/scene/kitRegistry.js.map +1 -1
- package/dist/core/scene/layerOps.js +82 -0
- package/dist/core/scene/layerOps.js.map +1 -0
- package/dist/core/scene/layoutPass.js +14 -12
- package/dist/core/scene/layoutPass.js.map +1 -1
- package/dist/core/scene/lockGuard.js +9 -3
- package/dist/core/scene/lockGuard.js.map +1 -1
- package/dist/core/scene/nestedHit.js +5 -5
- package/dist/core/scene/nestedHit.js.map +1 -1
- package/dist/core/scene/nodeFlags.js +8 -2
- package/dist/core/scene/nodeFlags.js.map +1 -1
- package/dist/core/scene/nodeGates.js +31 -2
- package/dist/core/scene/nodeGates.js.map +1 -1
- package/dist/core/scene/pathEffects/effects.js +22 -3
- package/dist/core/scene/pathEffects/effects.js.map +1 -1
- package/dist/core/scene/pathEffects/textAlong.js +16 -3
- package/dist/core/scene/pathEffects/textAlong.js.map +1 -1
- package/dist/core/scene/pathEffects/textAlongBands.js +65 -0
- package/dist/core/scene/pathEffects/textAlongBands.js.map +1 -0
- package/dist/core/scene/reconcileSpecs.js +1 -1
- package/dist/core/scene/reconcileSpecs.js.map +1 -1
- package/dist/core/scene/scene.js +11 -5
- package/dist/core/scene/scene.js.map +1 -1
- package/dist/core/scene/sceneEdits.js +5 -2
- package/dist/core/scene/sceneEdits.js.map +1 -1
- package/dist/core/scene/scenePoseAdapter.js +10 -1
- package/dist/core/scene/scenePoseAdapter.js.map +1 -1
- package/dist/core/scene/scrollOffsets.js +93 -0
- package/dist/core/scene/scrollOffsets.js.map +1 -0
- package/dist/core/scene/serialization.js +15 -5
- package/dist/core/scene/serialization.js.map +1 -1
- package/dist/core/scene/statedFields.js +2 -1
- package/dist/core/scene/statedFields.js.map +1 -1
- package/dist/core/scene/strategyView.js +35 -0
- package/dist/core/scene/strategyView.js.map +1 -0
- package/dist/core/scene/types.js.map +1 -1
- package/dist/core/scene/useScene.js +2 -0
- package/dist/core/scene/useScene.js.map +1 -1
- package/dist/core/scene/worldSave.js +87 -0
- package/dist/core/scene/worldSave.js.map +1 -0
- package/dist/core/selection/selectionTarget.js +1 -1
- package/dist/core/selection/selectionTarget.js.map +1 -1
- package/dist/{cornerHandles-CNCb7aTY.d.ts → cornerHandles-DpmQM_z5.d.ts} +1 -1
- package/dist/{depSchema-CpIQzKWQ.d.ts → depSchema-C3BwxitB.d.ts} +119 -99
- package/dist/devtools-protocol.d.ts +2 -2
- package/dist/devtools.d.ts +2 -2
- package/dist/{features → domains}/chrome-caps/buildChromeCtx.js +1 -1
- package/dist/domains/chrome-caps/buildChromeCtx.js.map +1 -0
- package/dist/{features → domains}/chrome-caps/conditions.js +1 -1
- package/dist/domains/chrome-caps/conditions.js.map +1 -0
- package/dist/{features → domains}/chrome-caps/defaults.js +1 -1
- package/dist/domains/chrome-caps/defaults.js.map +1 -0
- package/dist/{features → domains}/chrome-caps/resolve.js +1 -1
- package/dist/domains/chrome-caps/resolve.js.map +1 -0
- package/dist/{features → domains}/chrome-caps/useChromeCaps.js +1 -1
- package/dist/domains/chrome-caps/useChromeCaps.js.map +1 -0
- package/dist/{features → domains}/chrome-caps/useHoverTracking.js +1 -1
- package/dist/domains/chrome-caps/useHoverTracking.js.map +1 -0
- package/dist/{features → domains}/ingestion/contentHandlers.js +20 -3
- package/dist/domains/ingestion/contentHandlers.js.map +1 -0
- package/dist/domains/ingestion/ghost.js +56 -0
- package/dist/domains/ingestion/ghost.js.map +1 -0
- package/dist/{features → domains}/ingestion/imageHandler.js +1 -1
- package/dist/domains/ingestion/imageHandler.js.map +1 -0
- package/dist/domains/ingestion/kitHandlers.js +22 -0
- package/dist/domains/ingestion/kitHandlers.js.map +1 -0
- package/dist/{features → domains}/ingestion/openFilePicker.js +1 -1
- package/dist/domains/ingestion/openFilePicker.js.map +1 -0
- package/dist/{features → domains}/ingestion/placement.js +1 -1
- package/dist/domains/ingestion/placement.js.map +1 -0
- package/dist/{features → domains}/ingestion/svgHandler.js +1 -1
- package/dist/domains/ingestion/svgHandler.js.map +1 -0
- package/dist/{features → domains}/ingestion/textHandler.js +9 -7
- package/dist/domains/ingestion/textHandler.js.map +1 -0
- package/dist/{features → domains}/ingestion/useCanvasIngestion.js +13 -15
- package/dist/domains/ingestion/useCanvasIngestion.js.map +1 -0
- package/dist/{features → domains}/ingestion/weaselJsonHandler.js +1 -1
- package/dist/domains/ingestion/weaselJsonHandler.js.map +1 -0
- package/dist/{features → domains}/longPress/longPressFeedback.js +1 -1
- package/dist/domains/longPress/longPressFeedback.js.map +1 -0
- package/dist/{features → domains}/measure/actionIds.js +1 -1
- package/dist/domains/measure/actionIds.js.map +1 -0
- package/dist/{features → domains}/measure/measureCommands.js +1 -1
- package/dist/domains/measure/measureCommands.js.map +1 -0
- package/dist/{features → domains}/measure/measureContribution.js +1 -1
- package/dist/domains/measure/measureContribution.js.map +1 -0
- package/dist/{features → domains}/measure/measureEdits.js +1 -1
- package/dist/domains/measure/measureEdits.js.map +1 -0
- package/dist/{features → domains}/measure/measureGestures.js +4 -7
- package/dist/domains/measure/measureGestures.js.map +1 -0
- package/dist/{features → domains}/measure/measureHit.js +1 -1
- package/dist/domains/measure/measureHit.js.map +1 -0
- package/dist/{features → domains}/measure/measureLayer.js +1 -1
- package/dist/domains/measure/measureLayer.js.map +1 -0
- package/dist/{features → domains}/measure/measurement.js +1 -1
- package/dist/domains/measure/measurement.js.map +1 -0
- package/dist/{features → domains}/measure/measurements.js +2 -2
- package/dist/domains/measure/measurements.js.map +1 -0
- package/dist/{features → domains}/modes/modeLayers.js +1 -1
- package/dist/domains/modes/modeLayers.js.map +1 -0
- package/dist/{features → domains}/modes/modeTriggers.js +3 -6
- package/dist/domains/modes/modeTriggers.js.map +1 -0
- package/dist/{features → domains}/pathEffects/effectSources.js +1 -1
- package/dist/domains/pathEffects/effectSources.js.map +1 -0
- package/dist/{features → domains}/pathEffects/index.js +1 -1
- package/dist/domains/pathEffects/index.js.map +1 -0
- package/dist/{features → domains}/pathEffects/readSource.js +1 -1
- package/dist/domains/pathEffects/readSource.js.map +1 -0
- package/dist/{features → domains}/pathEffects/textItems.js +11 -2
- package/dist/domains/pathEffects/textItems.js.map +1 -0
- package/dist/{features → domains}/pathEffects/useEffectSourcesLayer.js +1 -1
- package/dist/domains/pathEffects/useEffectSourcesLayer.js.map +1 -0
- package/dist/{features → domains}/paths/anchorData.js +1 -1
- package/dist/domains/paths/anchorData.js.map +1 -0
- package/dist/{features → domains}/paths/anchorMarkers.js +9 -7
- package/dist/domains/paths/anchorMarkers.js.map +1 -0
- package/dist/{features → domains}/paths/editablePath.js +1 -1
- package/dist/domains/paths/editablePath.js.map +1 -0
- package/dist/{features → domains}/paths/index.js +3 -3
- package/dist/{features → domains}/paths/originProjection.js +1 -1
- package/dist/domains/paths/originProjection.js.map +1 -0
- package/dist/{features → domains}/paths/pathEditExtension.js +1 -1
- package/dist/domains/paths/pathEditExtension.js.map +1 -0
- package/dist/{features → domains}/paths/pathEditState.js +1 -1
- package/dist/domains/paths/pathEditState.js.map +1 -0
- package/dist/{features → domains}/paths/pathEditingOverlayLayer.js +1 -1
- package/dist/domains/paths/pathEditingOverlayLayer.js.map +1 -0
- package/dist/{features → domains}/paths/pathLayer.js +1 -1
- package/dist/domains/paths/pathLayer.js.map +1 -0
- package/dist/{features → domains}/paths/pathRepresentation.js +1 -1
- package/dist/domains/paths/pathRepresentation.js.map +1 -0
- package/dist/{features → domains}/paths/pathSnap/glyphs.js +1 -1
- package/dist/domains/paths/pathSnap/glyphs.js.map +1 -0
- package/dist/{features → domains}/paths/pathSnap/pathSnapSource.js +1 -1
- package/dist/domains/paths/pathSnap/pathSnapSource.js.map +1 -0
- package/dist/{features → domains}/paths/pathSnap/sceneIndex.js +1 -1
- package/dist/domains/paths/pathSnap/sceneIndex.js.map +1 -0
- package/dist/{features → domains}/paths/pathSnap/snapGeometry.js +3 -2
- package/dist/domains/paths/pathSnap/snapGeometry.js.map +1 -0
- package/dist/{features → domains}/paths/penPreviewLayer.js +1 -1
- package/dist/domains/paths/penPreviewLayer.js.map +1 -0
- package/dist/{features → domains}/paths/shapeGenerator.js +6 -4
- package/dist/domains/paths/shapeGenerator.js.map +1 -0
- package/dist/{features → domains}/paths/strokeOutline.js +1 -1
- package/dist/domains/paths/strokeOutline.js.map +1 -0
- package/dist/{features → domains}/paths/useAnchorFields.js +1 -1
- package/dist/domains/paths/useAnchorFields.js.map +1 -0
- package/dist/{features → domains}/paths/usePathEdit.js +1 -1
- package/dist/domains/paths/usePathEdit.js.map +1 -0
- package/dist/{features → domains}/poseRun/usePoseRun.js +1 -1
- package/dist/domains/poseRun/usePoseRun.js.map +1 -0
- package/dist/{features → domains}/selection/enteredGroupFrame.js +49 -10
- package/dist/domains/selection/enteredGroupFrame.js.map +1 -0
- package/dist/{features → domains}/selection/enteredGroupScope.js +1 -1
- package/dist/domains/selection/enteredGroupScope.js.map +1 -0
- package/dist/domains/selection/enteredOperands.js +29 -0
- package/dist/domains/selection/enteredOperands.js.map +1 -0
- package/dist/{features → domains}/selection/handleCommands.js +1 -1
- package/dist/domains/selection/handleCommands.js.map +1 -0
- package/dist/{features → domains}/selection/overlay.js +1 -1
- package/dist/domains/selection/overlay.js.map +1 -0
- package/dist/{features → domains}/selection/selectionPose.js +1 -1
- package/dist/domains/selection/selectionPose.js.map +1 -0
- package/dist/{features → domains}/snap/angle2d.js +1 -1
- package/dist/domains/snap/angle2d.js.map +1 -0
- package/dist/{features → domains}/snap/debugCandidates.js +1 -1
- package/dist/domains/snap/debugCandidates.js.map +1 -0
- package/dist/{features → domains}/snap/gather.js +1 -1
- package/dist/domains/snap/gather.js.map +1 -0
- package/dist/{features → domains}/snap/inputSubspace.js +1 -1
- package/dist/domains/snap/inputSubspace.js.map +1 -0
- package/dist/{features → domains}/snap/lazySession.js +1 -1
- package/dist/domains/snap/lazySession.js.map +1 -0
- package/dist/{features → domains}/snap/marks.js +1 -1
- package/dist/domains/snap/marks.js.map +1 -0
- package/dist/{features → domains}/snap/outcomeStore.js +1 -1
- package/dist/domains/snap/outcomeStore.js.map +1 -0
- package/dist/{features → domains}/snap/pointSnap.js +1 -1
- package/dist/domains/snap/pointSnap.js.map +1 -0
- package/dist/{features → domains}/snap/probes2d.js +1 -1
- package/dist/domains/snap/probes2d.js.map +1 -0
- package/dist/{features → domains}/snap/readoutDraw.js +1 -1
- package/dist/domains/snap/readoutDraw.js.map +1 -0
- package/dist/{features → domains}/snap/readoutLayer.js +1 -1
- package/dist/domains/snap/readoutLayer.js.map +1 -0
- package/dist/{features → domains}/snap/registry.js +1 -1
- package/dist/domains/snap/registry.js.map +1 -0
- package/dist/{features → domains}/snap/resizeBox.js +1 -1
- package/dist/domains/snap/resizeBox.js.map +1 -0
- package/dist/{features → domains}/snap/roles.js +1 -1
- package/dist/domains/snap/roles.js.map +1 -0
- package/dist/{features → domains}/snap/rotationSource.js +1 -1
- package/dist/domains/snap/rotationSource.js.map +1 -0
- package/dist/{features → domains}/snap/sceneReads.js +24 -3
- package/dist/domains/snap/sceneReads.js.map +1 -0
- package/dist/{features → domains}/snap/sceneSession2d.js +3 -2
- package/dist/domains/snap/sceneSession2d.js.map +1 -0
- package/dist/{features → domains}/snap/screen.js +1 -1
- package/dist/domains/snap/screen.js.map +1 -0
- package/dist/{features → domains}/snap/session2d.js +3 -2
- package/dist/domains/snap/session2d.js.map +1 -0
- package/dist/{features → domains}/snap/spanSnap.js +1 -1
- package/dist/domains/snap/spanSnap.js.map +1 -0
- package/dist/{features → domains}/snap/stepAngles.js +1 -1
- package/dist/domains/snap/stepAngles.js.map +1 -0
- package/dist/{features → domains}/text/editingDrawOne.js +4 -4
- package/dist/domains/text/editingDrawOne.js.map +1 -0
- package/dist/domains/text/hostTextEditors.js +24 -0
- package/dist/domains/text/hostTextEditors.js.map +1 -0
- package/dist/{features → domains}/text/index.js +1 -1
- package/dist/{features → domains}/text/sceneTextDrafts.js +1 -1
- package/dist/domains/text/sceneTextDrafts.js.map +1 -0
- package/dist/{features → domains}/text/textHitAt.js +18 -2
- package/dist/domains/text/textHitAt.js.map +1 -0
- package/dist/{features → domains}/text/textLayer.js +1 -1
- package/dist/domains/text/textLayer.js.map +1 -0
- package/dist/{features → domains}/text/useSceneTextEdit.js +11 -3
- package/dist/domains/text/useSceneTextEdit.js.map +1 -0
- package/dist/{features → domains}/viewports/aim.js +1 -1
- package/dist/domains/viewports/aim.js.map +1 -0
- package/dist/{features → domains}/viewports/viewMarker.js +23 -5
- package/dist/domains/viewports/viewMarker.js.map +1 -0
- package/dist/{features → domains}/viewports/viewMarkerDrag.js +3 -3
- package/dist/domains/viewports/viewMarkerDrag.js.map +1 -0
- package/dist/{features → domains}/viewports/viewResolver.js +1 -1
- package/dist/domains/viewports/viewResolver.js.map +1 -0
- package/dist/{features → domains}/viewports/viewportLayer.js +1 -1
- package/dist/domains/viewports/viewportLayer.js.map +1 -0
- package/dist/icons.table.js +1 -1
- package/dist/icons.table.js.map +1 -1
- package/dist/icons.table.json +106 -6
- package/dist/index.d.ts +1441 -1050
- package/dist/index.js +90 -77
- package/dist/interactions/actions/admitsChild.js +6 -2
- package/dist/interactions/actions/admitsChild.js.map +1 -1
- package/dist/interactions/actions/align/align.js +1 -4
- package/dist/interactions/actions/align/align.js.map +1 -1
- package/dist/interactions/actions/booleans/booleanGroupAction.js +66 -0
- package/dist/interactions/actions/booleans/booleanGroupAction.js.map +1 -0
- package/dist/interactions/actions/booleans/keymap.js +52 -0
- package/dist/interactions/actions/booleans/keymap.js.map +1 -0
- package/dist/interactions/actions/booleans/operands.js +1 -1
- package/dist/interactions/actions/booleans/pieces.js +4 -11
- package/dist/interactions/actions/booleans/pieces.js.map +1 -1
- package/dist/interactions/actions/clipboard/action.js +3 -7
- package/dist/interactions/actions/clipboard/action.js.map +1 -1
- package/dist/interactions/actions/clipboard/clipboardOps.js +1 -1
- package/dist/interactions/actions/clipboard/clipboardOps.js.map +1 -1
- package/dist/interactions/actions/clipboard/materializePaste.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorEditing.js +6 -6
- package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
- package/dist/interactions/actions/defaults/bendSegment.js +1 -1
- package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
- package/dist/interactions/actions/defaults/containerScroll.js +170 -0
- package/dist/interactions/actions/defaults/containerScroll.js.map +1 -0
- package/dist/interactions/actions/defaults/contextMenu.js +2 -5
- package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
- package/dist/interactions/actions/defaults/delete.js +1 -1
- package/dist/interactions/actions/defaults/delete.js.map +1 -1
- package/dist/interactions/actions/defaults/duplicate.js +1 -3
- package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
- package/dist/interactions/actions/defaults/enterGroup.js +7 -12
- package/dist/interactions/actions/defaults/enterGroup.js.map +1 -1
- package/dist/interactions/actions/defaults/enterPathEdit.js +4 -8
- package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/group.js +12 -24
- package/dist/interactions/actions/defaults/group.js.map +1 -1
- package/dist/interactions/actions/defaults/ingest.js +18 -10
- package/dist/interactions/actions/defaults/ingest.js.map +1 -1
- package/dist/interactions/actions/defaults/insertPathAnchor.js +3 -3
- package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
- package/dist/interactions/actions/defaults/nudgeSteps.js +3 -21
- package/dist/interactions/actions/defaults/nudgeSteps.js.map +1 -1
- package/dist/interactions/actions/defaults/pathEditMarks.js.map +1 -1
- package/dist/interactions/actions/defaults/selectDeep.js +2 -2
- package/dist/interactions/actions/defaults/selectDeep.js.map +1 -1
- package/dist/interactions/actions/distribute/distribute.js.map +1 -1
- package/dist/interactions/actions/dropVerdict.js +9 -0
- package/dist/interactions/actions/dropVerdict.js.map +1 -0
- package/dist/interactions/actions/edit-anchors/action.js +2 -2
- package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/extensionDrags.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/geometry.js +8 -6
- package/dist/interactions/actions/edit-anchors/geometry.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/handleDrag.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/preview.js +1 -1
- package/dist/interactions/actions/edit-anchors/preview.js.map +1 -1
- package/dist/interactions/actions/flip/action.js +3 -2
- package/dist/interactions/actions/flip/action.js.map +1 -1
- package/dist/interactions/actions/geometryProjection.js +8 -3
- package/dist/interactions/actions/geometryProjection.js.map +1 -1
- package/dist/interactions/actions/gestureFrames.js +1 -0
- package/dist/interactions/actions/gestureFrames.js.map +1 -1
- package/dist/interactions/actions/insert/action.js +6 -2
- package/dist/interactions/actions/insert/action.js.map +1 -1
- package/dist/interactions/actions/insert/frame.js +1 -1
- package/dist/interactions/actions/insert/frame.js.map +1 -1
- package/dist/interactions/actions/insert/placeAction.js +6 -8
- package/dist/interactions/actions/insert/placeAction.js.map +1 -1
- package/dist/interactions/actions/insert/session.js +2 -2
- package/dist/interactions/actions/insert/session.js.map +1 -1
- package/dist/interactions/actions/move/action.js +6 -15
- package/dist/interactions/actions/move/action.js.map +1 -1
- package/dist/interactions/actions/move/behaviors/layoutDrop.js +12 -2
- package/dist/interactions/actions/move/behaviors/layoutDrop.js.map +1 -1
- package/dist/interactions/actions/move/behaviors/reparentOnDrop.js +29 -10
- package/dist/interactions/actions/move/behaviors/reparentOnDrop.js.map +1 -1
- package/dist/interactions/actions/move/behaviors/snapToContainer.js +42 -6
- package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
- package/dist/interactions/actions/move/capture.js +4 -8
- package/dist/interactions/actions/move/capture.js.map +1 -1
- package/dist/interactions/actions/move/commit/index.js.map +1 -1
- package/dist/interactions/actions/move/commit/layoutDrop.js +4 -3
- package/dist/interactions/actions/move/commit/layoutDrop.js.map +1 -1
- package/dist/interactions/actions/move/commit/layoutRelease.js +15 -9
- package/dist/interactions/actions/move/commit/layoutRelease.js.map +1 -1
- package/dist/interactions/actions/move/commit/reparent.js +19 -13
- package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
- package/dist/interactions/actions/move/delta.js +51 -5
- package/dist/interactions/actions/move/delta.js.map +1 -1
- package/dist/interactions/actions/move/frame.js +8 -4
- package/dist/interactions/actions/move/frame.js.map +1 -1
- package/dist/interactions/actions/move/layout/container.js +19 -9
- package/dist/interactions/actions/move/layout/container.js.map +1 -1
- package/dist/interactions/actions/move/layout/dragged.js +2 -2
- package/dist/interactions/actions/move/layout/dragged.js.map +1 -1
- package/dist/interactions/actions/move/layout/dropPass.js +36 -18
- package/dist/interactions/actions/move/layout/dropPass.js.map +1 -1
- package/dist/interactions/actions/move/layout/exits.js +2 -2
- package/dist/interactions/actions/move/layout/exits.js.map +1 -1
- package/dist/interactions/actions/move/layout/glide.js +5 -5
- package/dist/interactions/actions/move/layout/glide.js.map +1 -1
- package/dist/interactions/actions/move/layout/view.js +55 -0
- package/dist/interactions/actions/move/layout/view.js.map +1 -0
- package/dist/interactions/actions/move/refusal.js +52 -0
- package/dist/interactions/actions/move/refusal.js.map +1 -0
- package/dist/interactions/actions/move/session.js +9 -8
- package/dist/interactions/actions/move/session.js.map +1 -1
- package/dist/interactions/actions/move/translate.js +10 -4
- package/dist/interactions/actions/move/translate.js.map +1 -1
- package/dist/interactions/actions/moveNodes.js +21 -5
- package/dist/interactions/actions/moveNodes.js.map +1 -1
- package/dist/interactions/actions/pathCommands/pathNodes.js +3 -3
- package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -1
- package/dist/interactions/actions/planeInput.js +14 -13
- package/dist/interactions/actions/planeInput.js.map +1 -1
- package/dist/interactions/actions/poseFrame.js +21 -8
- package/dist/interactions/actions/poseFrame.js.map +1 -1
- package/dist/interactions/actions/resize/action.js +1 -1
- package/dist/interactions/actions/resize/action.js.map +1 -1
- package/dist/interactions/actions/resize/aspect.js +1 -1
- package/dist/interactions/actions/resize/aspect.js.map +1 -1
- package/dist/interactions/actions/resize/commit.js +10 -1
- package/dist/interactions/actions/resize/commit.js.map +1 -1
- package/dist/interactions/actions/resize/frame.js +3 -2
- package/dist/interactions/actions/resize/frame.js.map +1 -1
- package/dist/interactions/actions/resize/held.js +44 -0
- package/dist/interactions/actions/resize/held.js.map +1 -0
- package/dist/interactions/actions/resize/session.js +3 -1
- package/dist/interactions/actions/resize/session.js.map +1 -1
- package/dist/interactions/actions/resolveOverlays.js +9 -0
- package/dist/interactions/actions/resolveOverlays.js.map +1 -1
- package/dist/interactions/actions/resolvePreviews.js +23 -7
- package/dist/interactions/actions/resolvePreviews.js.map +1 -1
- package/dist/interactions/actions/rotate/action.js +1 -1
- package/dist/interactions/actions/rotate/action.js.map +1 -1
- package/dist/interactions/actions/rotate/frame.js +1 -1
- package/dist/interactions/actions/rotate/frame.js.map +1 -1
- package/dist/interactions/actions/rotate/session.js +2 -2
- package/dist/interactions/actions/rotate/session.js.map +1 -1
- package/dist/interactions/actions/selectionSubtree.js +2 -4
- package/dist/interactions/actions/selectionSubtree.js.map +1 -1
- package/dist/interactions/actions/spatialReference.js +4 -9
- package/dist/interactions/actions/spatialReference.js.map +1 -1
- package/dist/interactions/gestures/dragRadial/dragRadial.js.map +1 -1
- package/dist/interactions/gestures/dragRect/dragRect.js.map +1 -1
- package/dist/kitSettingsSchema.js +2 -2
- package/dist/kitSettingsSchema.js.map +1 -1
- package/dist/{math-C_elShP_.d.ts → math-B_unOnF4.d.ts} +2 -2
- package/dist/math.d.ts +3 -3
- package/dist/move.d.ts +6 -6
- package/dist/{options-ClEm3SEl.d.ts → options-DAjkhbcs.d.ts} +5 -5
- package/dist/{poseDescriptor-DN2yfnq_.d.ts → poseDescriptor-CvSxVhCd.d.ts} +17 -4
- package/dist/resize.d.ts +6 -6
- package/dist/style.css +14 -0
- package/dist/test-seams.d.ts +11 -15
- package/dist/test-seams.js +1 -1
- package/dist/tools/builtin/eyedropper/useEyedropperTool.js +3 -6
- package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
- package/dist/tools/builtin/line/useLineTool.js.map +1 -1
- package/dist/tools/builtin/measure/useMeasureTool.js +2 -2
- package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
- package/dist/tools/builtin/pen/penHandle.js +2 -2
- package/dist/tools/builtin/pen/penHandle.js.map +1 -1
- package/dist/tools/builtin/pen/usePenTool.js +13 -19
- package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
- package/dist/tools/builtin/polygon/usePolygonTool.js +1 -1
- package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
- package/dist/tools/builtin/select/groupEntry.js +1 -1
- package/dist/tools/builtin/select/groupEntry.js.map +1 -1
- package/dist/tools/builtin/select/selectionContributions.js +1 -1
- package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
- package/dist/tools/builtin/select/useSelectTool.js +7 -7
- package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
- package/dist/tools/builtin/slice/useSliceTool.js +5 -8
- package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
- package/dist/tools/builtin/star/useStarTool.js +1 -1
- package/dist/tools/builtin/star/useStarTool.js.map +1 -1
- package/dist/tools/index.js +2 -1
- package/dist/{types-49uYJN3j.d.ts → types-A_sNJYRd.d.ts} +8 -0
- package/dist/{types-BEdRIhNc.d.ts → types-DW14eu9B.d.ts} +131 -36
- package/dist/{types-p2alu-R1.d.ts → types-VCtfchp-.d.ts} +4 -6
- package/dist/util/color.js +12 -14
- package/dist/util/color.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +25 -24
- package/dist/canvas/poseCascade.js +0 -65
- package/dist/canvas/poseCascade.js.map +0 -1
- package/dist/features/chrome-caps/buildChromeCtx.js.map +0 -1
- package/dist/features/chrome-caps/conditions.js.map +0 -1
- package/dist/features/chrome-caps/defaults.js.map +0 -1
- package/dist/features/chrome-caps/resolve.js.map +0 -1
- package/dist/features/chrome-caps/useChromeCaps.js.map +0 -1
- package/dist/features/chrome-caps/useHoverTracking.js.map +0 -1
- package/dist/features/ingestion/contentHandlers.js.map +0 -1
- package/dist/features/ingestion/imageHandler.js.map +0 -1
- package/dist/features/ingestion/openFilePicker.js.map +0 -1
- package/dist/features/ingestion/placement.js.map +0 -1
- package/dist/features/ingestion/registerKitHandlers.js +0 -43
- package/dist/features/ingestion/registerKitHandlers.js.map +0 -1
- package/dist/features/ingestion/svgHandler.js.map +0 -1
- package/dist/features/ingestion/textHandler.js.map +0 -1
- package/dist/features/ingestion/useCanvasIngestion.js.map +0 -1
- package/dist/features/ingestion/weaselJsonHandler.js.map +0 -1
- package/dist/features/longPress/longPressFeedback.js.map +0 -1
- package/dist/features/measure/actionIds.js.map +0 -1
- package/dist/features/measure/measureCommands.js.map +0 -1
- package/dist/features/measure/measureContribution.js.map +0 -1
- package/dist/features/measure/measureEdits.js.map +0 -1
- package/dist/features/measure/measureGestures.js.map +0 -1
- package/dist/features/measure/measureHit.js.map +0 -1
- package/dist/features/measure/measureLayer.js.map +0 -1
- package/dist/features/measure/measurement.js.map +0 -1
- package/dist/features/measure/measurements.js.map +0 -1
- package/dist/features/modes/modeLayers.js.map +0 -1
- package/dist/features/modes/modeTriggers.js.map +0 -1
- package/dist/features/pathEffects/effectSources.js.map +0 -1
- package/dist/features/pathEffects/index.js.map +0 -1
- package/dist/features/pathEffects/readSource.js.map +0 -1
- package/dist/features/pathEffects/textItems.js.map +0 -1
- package/dist/features/pathEffects/useEffectSourcesLayer.js.map +0 -1
- package/dist/features/paths/anchorData.js.map +0 -1
- package/dist/features/paths/anchorMarkers.js.map +0 -1
- package/dist/features/paths/editablePath.js.map +0 -1
- package/dist/features/paths/originProjection.js.map +0 -1
- package/dist/features/paths/pathEditExtension.js.map +0 -1
- package/dist/features/paths/pathEditState.js.map +0 -1
- package/dist/features/paths/pathEditingOverlayLayer.js.map +0 -1
- package/dist/features/paths/pathLayer.js.map +0 -1
- package/dist/features/paths/pathRepresentation.js.map +0 -1
- package/dist/features/paths/pathSnap/glyphs.js.map +0 -1
- package/dist/features/paths/pathSnap/pathSnapSource.js.map +0 -1
- package/dist/features/paths/pathSnap/sceneIndex.js.map +0 -1
- package/dist/features/paths/pathSnap/snapGeometry.js.map +0 -1
- package/dist/features/paths/penPreviewLayer.js.map +0 -1
- package/dist/features/paths/shapeGenerator.js.map +0 -1
- package/dist/features/paths/strokeOutline.js.map +0 -1
- package/dist/features/paths/useAnchorFields.js.map +0 -1
- package/dist/features/paths/usePathEdit.js.map +0 -1
- package/dist/features/poseRun/usePoseRun.js.map +0 -1
- package/dist/features/selection/enteredGroupFrame.js.map +0 -1
- package/dist/features/selection/enteredGroupScope.js.map +0 -1
- package/dist/features/selection/handleCommands.js.map +0 -1
- package/dist/features/selection/overlay.js.map +0 -1
- package/dist/features/selection/selectionPose.js.map +0 -1
- package/dist/features/snap/angle2d.js.map +0 -1
- package/dist/features/snap/debugCandidates.js.map +0 -1
- package/dist/features/snap/gather.js.map +0 -1
- package/dist/features/snap/inputSubspace.js.map +0 -1
- package/dist/features/snap/lazySession.js.map +0 -1
- package/dist/features/snap/marks.js.map +0 -1
- package/dist/features/snap/outcomeStore.js.map +0 -1
- package/dist/features/snap/pointSnap.js.map +0 -1
- package/dist/features/snap/probes2d.js.map +0 -1
- package/dist/features/snap/readoutDraw.js.map +0 -1
- package/dist/features/snap/readoutLayer.js.map +0 -1
- package/dist/features/snap/registry.js.map +0 -1
- package/dist/features/snap/resizeBox.js.map +0 -1
- package/dist/features/snap/roles.js.map +0 -1
- package/dist/features/snap/rotationSource.js.map +0 -1
- package/dist/features/snap/sceneReads.js.map +0 -1
- package/dist/features/snap/sceneSession2d.js.map +0 -1
- package/dist/features/snap/screen.js.map +0 -1
- package/dist/features/snap/session2d.js.map +0 -1
- package/dist/features/snap/spanSnap.js.map +0 -1
- package/dist/features/snap/stepAngles.js.map +0 -1
- package/dist/features/text/editingDrawOne.js.map +0 -1
- package/dist/features/text/sceneTextDrafts.js.map +0 -1
- package/dist/features/text/textHitAt.js.map +0 -1
- package/dist/features/text/textLayer.js.map +0 -1
- package/dist/features/text/useSceneTextEdit.js.map +0 -1
- package/dist/features/viewports/aim.js.map +0 -1
- package/dist/features/viewports/viewMarker.js.map +0 -1
- package/dist/features/viewports/viewMarkerDrag.js.map +0 -1
- package/dist/features/viewports/viewResolver.js.map +0 -1
- package/dist/features/viewports/viewportLayer.js.map +0 -1
- /package/dist/{features → domains}/chrome-caps/index.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useViewAim.js","names":[],"sources":["../../src/canvas/useViewAim.ts"],"sourcesContent":["/**\n * A `<CanvasView>`'s camera and its aim, whichever of the two the view holds.\n * A camera-held view answers its aim from its camera; an aim-held one derives\n * its camera from the aim, through the same thunk a derived `view` uses.\n */\nimport { useCallback } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport type { Dims } from 'core/layers/render';\nimport { normalizeView, type View } from 'core/viewport/view';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { viewportWorldRect } from 'core/viewport/viewportWorldRect';\nimport { isRectAim, rectAim, viewForAim, type ViewAim } from '
|
|
1
|
+
{"version":3,"file":"useViewAim.js","names":[],"sources":["../../src/canvas/useViewAim.ts"],"sourcesContent":["/**\n * A `<CanvasView>`'s camera and its aim, whichever of the two the view holds.\n * A camera-held view answers its aim from its camera; an aim-held one derives\n * its camera from the aim, through the same thunk a derived `view` uses.\n */\nimport { useCallback } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport type { Dims } from 'core/layers/render';\nimport { normalizeView, type View } from 'core/viewport/view';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { viewportWorldRect } from 'core/viewport/viewportWorldRect';\nimport { isRectAim, rectAim, viewForAim, type ViewAim } from 'domains/viewports/aim';\nimport { useCanvasView, type CanvasViewState } from './useCanvasView';\nimport type { CanvasViewProps, ViewRect } from './canvasViewProps';\nimport { sizeOf, type useViewNesting } from './useViewNesting';\nimport { IDENTITY_VIEW, UNMEASURED_DIMS, type ViewRegistry } from './viewRegistry';\n\n/** `held` carried by the camera move that turns the world rect `from` into `to`: panned and scaled\n * with it, so the aim keeps its own shape rather than taking the frame's. */\nfunction carried(held: Bounds, from: Bounds, to: Bounds): Bounds {\n const kx = from.width > 0 ? to.width / from.width : 1;\n const ky = from.height > 0 ? to.height / from.height : 1;\n return {\n x: to.x + (held.x - from.x) * kx,\n y: to.y + (held.y - from.y) * ky,\n width: held.width * kx,\n height: held.height * ky,\n };\n}\n\ntype Nesting = ReturnType<typeof useViewNesting>;\n\nexport function useViewAim(args: {\n props: Pick<CanvasViewProps, 'view' | 'defaultView' | 'onViewChange' | 'viewBounds' | 'aim' | 'onAimChange'>;\n id: string;\n registry: ViewRegistry | null;\n derivedAt: Nesting['derivedAt'];\n rectAt: Nesting['rectAt'];\n rectNow: () => ViewRect;\n}): CanvasViewState & {\n held: 'camera' | 'aim';\n aim(): ViewAim;\n setAim(aim: ViewAim): boolean;\n /** The camera for a frame the caller names. A derived camera is asked for that frame; any other is\n * the same whatever the surface is doing. */\n cameraAt(outer: View, dims: Dims): View;\n} {\n const { props, id, registry, derivedAt, rectAt, rectNow } = args;\n const { view, defaultView, onViewChange, viewBounds, aim: aimProp, onAimChange } = props;\n const held = aimProp !== undefined ? 'aim' : 'camera';\n const live = useLatest({ view, onViewChange, aimProp, onAimChange });\n\n /** The rect an aim-held view holds, for a surface frame. */\n const heldAt = useCallback((outer: View, dims: Dims): Bounds | undefined => {\n const a = live.current.aimProp;\n return typeof a === 'function' ? derivedAt(a, outer, dims) : a;\n }, [live, derivedAt]);\n\n /** The camera derived for a surface frame, or `undefined` for a camera the view keeps. */\n const derivedCamera = useCallback((outer: View, dims: Dims): View | undefined => {\n const rect = heldAt(outer, dims);\n if (rect) return viewForAim(rect, sizeOf(rectAt(outer, dims)), 'contain');\n const v = live.current.view;\n return typeof v === 'function' ? normalizeView(derivedAt(v, outer, dims)) : undefined;\n }, [live, heldAt, rectAt, derivedAt]);\n\n const surfaceFrame = useCallback((): [View, Dims] => {\n const surface = registry?.surface();\n return [surface?.view() ?? IDENTITY_VIEW, surface?.dims() ?? UNMEASURED_DIMS];\n }, [registry]);\n\n /** A camera write on an aim-held view, reported as the held rect it carries. */\n const reportWrite = useCallback((next: View): void => {\n const frame = surfaceFrame();\n const held = heldAt(...frame);\n const current = derivedCamera(...frame);\n if (!held || !current) return;\n const size = sizeOf(rectAt(...frame));\n live.current.onAimChange?.(carried(held, viewportWorldRect(current, size), viewportWorldRect(next, size)));\n }, [live, surfaceFrame, heldAt, derivedCamera, rectAt]);\n\n const state = useCanvasView({\n view: held === 'aim' || typeof view === 'function' ? () => derivedCamera(...surfaceFrame())! : view,\n defaultView,\n onViewChange: held === 'aim'\n ? onAimChange && reportWrite\n : onViewChange,\n viewBounds,\n dims: () => sizeOf(rectNow()),\n requestRedraw: () => registry?.surface()?.requestRedraw(),\n controlledBy: held === 'aim' ? 'aim' : 'view',\n });\n const { getView, setViewFromInput } = state;\n\n const aim = useCallback((): ViewAim => {\n const rect = heldAt(...surfaceFrame());\n return rectAim(id, rect ?? viewportWorldRect(getView(), sizeOf(rectNow())));\n }, [id, heldAt, surfaceFrame, getView, rectNow]);\n\n const setAim = useCallback((next: ViewAim): boolean => {\n if (!isRectAim(next)) return false;\n const { view: v, onViewChange: onView, aimProp: a, onAimChange: report } = live.current;\n if (a === undefined) {\n if (v !== undefined && !onView) return false;\n setViewFromInput(viewForAim(next.extent, sizeOf(rectNow()), 'exact'));\n return true;\n }\n report?.(next.extent);\n return report !== undefined;\n }, [live, setViewFromInput, rectNow]);\n\n const cameraAt = useCallback(\n (outer: View, dims: Dims): View => derivedCamera(outer, dims) ?? getView(),\n [derivedCamera, getView],\n );\n\n return { ...state, held, aim, setAim, cameraAt };\n}\n"],"mappings":"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"}
|
|
@@ -58,7 +58,7 @@ function useViewHelpers(opts) {
|
|
|
58
58
|
return null;
|
|
59
59
|
}
|
|
60
60
|
}, [adapter]);
|
|
61
|
-
const
|
|
61
|
+
const selectionRef = useLatest(selection);
|
|
62
62
|
const effectiveBoundsOf = useMemo(() => boundsOf ?? baseBoundsOf, [boundsOf, baseBoundsOf]);
|
|
63
63
|
const { previewPoseOf, previewBoundsOf } = useInFlightBounds({
|
|
64
64
|
gestureSource,
|
|
@@ -78,8 +78,12 @@ function useViewHelpers(opts) {
|
|
|
78
78
|
return effectiveBoundsOf ? effectiveBoundsOf(id) : null;
|
|
79
79
|
}, [previewBoundsOf, effectiveBoundsOf]);
|
|
80
80
|
const chromeState = useMemo(() => buildChromeState({
|
|
81
|
-
selection
|
|
82
|
-
|
|
81
|
+
get selection() {
|
|
82
|
+
return selectionRef.current();
|
|
83
|
+
},
|
|
84
|
+
get multiActive() {
|
|
85
|
+
return selectionRef.current().length > 1;
|
|
86
|
+
},
|
|
83
87
|
effectiveBoundsOf: boundsWithPreview,
|
|
84
88
|
modifiers: {
|
|
85
89
|
alt: false,
|
|
@@ -96,8 +100,7 @@ function useViewHelpers(opts) {
|
|
|
96
100
|
...layerIsPainted ? { layerIsPainted } : {},
|
|
97
101
|
...adapter?.getNode ? { layerOf: (id) => adapter.getNode?.(id)?.layer } : {}
|
|
98
102
|
}), [
|
|
99
|
-
|
|
100
|
-
multiActive,
|
|
103
|
+
selectionRef,
|
|
101
104
|
boundsWithPreview,
|
|
102
105
|
geometry,
|
|
103
106
|
committedPoseOf,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useViewHelpers.js","names":[],"sources":["../../src/canvas/useViewHelpers.ts"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport { framedBounds } from 'core/geometry/poseDescriptor';\nimport { useLatest } from '@weasel-js/react';\nimport type { GestureSource, GesturePreviewSource } from './gestureBounds';\nimport { useInFlightBounds } from './useInFlightBounds';\nimport type { OngoingOverlay } from '@weasel-js/routing';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport { buildChromeState, type ChromeState } from 'core/selection/chromeState';\nimport type { PoseDescriptor } from 'interactions/actions/resize/geometry';\nimport type { NodeId } from 'core/scene/types';\nimport type { DebugSink } from '../debug/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { Scale2 } from '@weasel-js/geom';\nimport { drawnBoundsOf, type DrawnBoundsScene } from './drawnBounds';\n\nconst noOpUnsubscribe = (): void => {};\n\nconst alwaysVisible = (): boolean => true;\n\n/**\n * The half of {@link CanvasHelpers} that belongs to one view — everything\n * answered by a camera's own tools, gestures and selection. A canvas hosting\n * several viewports needs one of these per view; the surface half is shared.\n */\nexport interface CanvasViewHelpers<TPose> {\n /** Pose currently displayed for `id` — drag/resize/rotate overlay if active,\n * otherwise the committed pose from the adapter. Returns `null` if the id\n * isn't known. */\n getEffectivePose(id: string): TPose | null;\n /** Overlay-aware bounds for `id`. */\n getEffectiveBounds(id: string): Bounds | null;\n /**\n * World-space AABB of everything the in-flight gesture proposes — the\n * displaced poses of nodes being moved / resized / rotated / cloned, plus\n * any nascent insert that has no scene node yet. `null` when no gesture is\n * in flight.\n *\n * This reports the *gesture*, not the document: committed content the\n * gesture isn't touching is excluded. Select-only gestures are excluded\n * too: a marquee or lasso has geometry but proposes no content.\n *\n * The result is a plain AABB — never rotated. Rotated parts are folded in\n * by their rotated extent.\n */\n getGestureBounds(): Bounds | null;\n /**\n * Subscribe to the gesture layer's change signal, for everything on this\n * object that moves during a drag (`getEffectivePose`, `getEffectiveBounds`,\n * `getGestureBounds`). Returns an unsubscribe.\n *\n * Fires once per dispatcher pump: gesture start, every pointermove that\n * reaches an in-flight handle, end, and cancel — plus UI-driven ongoing\n * actions. It fires on the pump, not on a diff: a pump that changed nothing\n * observable still notifies, so don't hang expensive work directly off the\n * callback.\n *\n * It does **not** cover committed scene edits (subscribe to the scene for\n * those) or previews a consumer's own tool publishes from React state.\n * Without a gesture source wired — a bare `<Canvas>` — it never fires.\n */\n subscribeGestures(fn: () => void): () => void;\n /**\n * Monotonic counter bumped on exactly the events `subscribeGestures` fires\n * on. Pair the two for `useSyncExternalStore`:\n *\n * ```ts\n * const gestureVersion = useSyncExternalStore(\n * useCallback((cb) => helpersRef.current?.subscribeGestures(cb) ?? (() => {}), []),\n * () => helpersRef.current?.getGestureVersion() ?? 0,\n * );\n * ```\n *\n * Starts at 0 and only increases. `0` is also what a bare `<Canvas>` with\n * no gesture source reports, forever.\n */\n getGestureVersion(): number;\n /** The live ChromeState built once per render: overlay-aware selection\n * state for affordances and custom layers. */\n getChromeState(): ChromeState;\n /**\n * Everything publishing an in-flight preview for this view: the handles in\n * flight on its dispatcher, in dispatch order. Readers take the first\n * non-null answer per id.\n *\n * A ghost layer must read this off its draw envelope rather than close over\n * a dispatcher: one layer array paints every view, so a closure ghosts view\n * zero's drag into every panel.\n */\n getPreviewSources(): readonly GesturePreviewSource[];\n /** Overlay shapes this view's in-flight handles publish — marquee, lasso,\n * insert preview, raw commands. Same envelope rule as\n * {@link CanvasViewHelpers.getPreviewSources}. */\n getGestureOverlays(): readonly OngoingOverlay[];\n /**\n * Chrome-caps visibility predicate, keyed by chrome id. Overlay layers and\n * affordances call it per element to decide whether to draw / hit-test.\n * Unwired, it is the universal `() => true`.\n */\n getIsVisible(): (id: string) => boolean;\n}\n\n/**\n * The half of {@link CanvasHelpers} that belongs to the surface — one GL\n * context, one debug sink, however many views are drawn on it.\n */\nexport interface CanvasSurfaceHelpers {\n /** Active debug sink, when `<Canvas debug=...>` is enabled, for layers to\n * call from their `draw` callback. `null` when debug is off. */\n getDebug(): DebugSink | null;\n}\n\n/** Live overlay-aware lookups exposed to custom layers via `helpersRef`, and\n * what a layer receives as its `data` argument. */\nexport interface CanvasHelpers<TPose> extends CanvasViewHelpers<TPose>, CanvasSurfaceHelpers {\n /**\n * The view this draw is for: a `<CanvasView>` id, or `null` for the\n * surface's own camera. One layer array paints every view, so a layer that\n * belongs in some views and not others — a minimap's indicator — declines\n * the rest by this id.\n */\n readonly viewId: string | null;\n}\n\n/** What a view's pose and bounds lookups read of an adapter. */\nexport interface ViewPoseAdapter<TPose> {\n getPose(id: string): TPose;\n /** Where the node is drawn, when the adapter composes poses. An adapter\n * without it stores absolute poses, where the two agree. */\n getWorldPose?(id: string): TPose;\n /** The node an id names, whose `layer` decides whether a view that hides\n * that layer shows its selection chrome. */\n getNode?(id: string): { layer?: string } | undefined;\n}\n\nexport interface UseViewHelpersOpts<TPose> {\n adapter: ViewPoseAdapter<TPose> | undefined;\n geometry: PoseDescriptor<TPose>;\n /** Consumer-supplied bounds resolver. Falls back to the adapter's pose. */\n boundsOf: ((id: string) => Bounds | null) | undefined;\n /** Bounds of `id` drawn at an in-flight `pose`. Falls back to the\n * geometry's box of that pose, which is wrong wherever the surface draws a\n * node somewhere its pose does not say — a parallax plane. */\n boundsOfPose?: ((id: string, pose: TPose) => Bounds | null) | undefined;\n /** The nodes the adapter's ids name: with them, the fallbacks box each as\n * drawn, stroke included, rather than by its pose. */\n nodes?: DrawnBoundsScene | undefined;\n /** The view's scale, which a screen-pixel stroke is resolved at. Default 1. */\n getScale?: (() => Scale2) | undefined;\n selection: readonly NodeId[];\n gestureSource: GestureSource | undefined;\n /** The dispatcher's preview pose for an id, read through a ref so a change\n * mid-gesture doesn't rebuild the memos that depend on it. */\n previewPoseExtra: ((id: string) => unknown) | undefined;\n /** Chrome-caps predicate for this view. Absent means everything is visible. */\n getIsVisible?: (() => (id: string) => boolean) | undefined;\n /** Whether a scene layer reaches the screen in this view. Absent means\n * every layer the scene shows does. */\n layerIsPainted?: ((layerId: string) => boolean) | undefined;\n}\n\nexport interface ViewHelpersBundle<TPose> {\n helpers: CanvasViewHelpers<TPose>;\n}\n\nfunction worldPoseOf<TPose>(adapter: ViewPoseAdapter<TPose>, id: string): TPose {\n return typeof adapter.getWorldPose === 'function' ? adapter.getWorldPose(id) : adapter.getPose(id);\n}\n\n/**\n * Build one view's overlay-aware state: its chrome and the lookups its layers\n * draw and hit-test against. A canvas with N views mounts N components each\n * calling this once.\n */\nexport function useViewHelpers<TPose>(\n opts: UseViewHelpersOpts<TPose>,\n): ViewHelpersBundle<TPose> {\n const {\n adapter, geometry, boundsOf, boundsOfPose, nodes, getScale, selection, gestureSource,\n previewPoseExtra, getIsVisible, layerIsPainted,\n } = opts;\n const getScaleRef = useLatest(getScale);\n const poseBoxOf = useCallback((id: string, pose: TPose): Bounds => {\n if (!nodes) return framedBounds(pose, geometry);\n const scale = getScaleRef.current?.();\n return drawnBoundsOf(nodes, id as NodeId, pose, {\n descriptor: geometry as PoseDescriptor<unknown>,\n ...(adapter ? { worldPoseOf: (m: NodeId) => worldPoseOf(adapter, m) } : {}),\n ...(scale ? { scale } : {}),\n });\n }, [nodes, geometry, adapter, getScaleRef]);\n const boxOf = useCallback(\n (id: string, pose: TPose): Bounds | null =>\n (boundsOfPose ? boundsOfPose(id, pose) : poseBoxOf(id, pose)),\n [boundsOfPose, poseBoxOf],\n );\n\n const baseBoundsOf = useMemo(() => {\n if (boundsOf) return boundsOf;\n if (!adapter) return undefined;\n return (id: string): Bounds | null => {\n try {\n // World: chrome is drawn over the picture, so it has to agree with\n // where the renderer put the node, not with where its pose is stored.\n return poseBoxOf(id, worldPoseOf(adapter, id));\n } catch {\n return null;\n }\n };\n }, [boundsOf, adapter, poseBoxOf]);\n\n const committedPoseOf = useCallback((id: string): TPose | null => {\n if (!adapter) return null;\n try {\n return worldPoseOf(adapter, id);\n } catch {\n return null;\n }\n }, [adapter]);\n\n const multiActive = selection.length > 1;\n\n const effectiveBoundsOf = useMemo(() => boundsOf ?? baseBoundsOf, [boundsOf, baseBoundsOf]);\n const { previewPoseOf, previewBoundsOf } = useInFlightBounds({ gestureSource, previewPoseExtra, boxOf, committedPoseOf });\n\n /**\n * Bounds for `id` with any in-flight gesture folded in — what the user can\n * see, not what is committed. Both the chrome state and the layer helpers\n * answer bounds questions with this, so resize handles cannot end up a frame\n * away from the shape they belong to.\n */\n const boundsWithPreview = useCallback((id: string): Bounds | null => {\n const previewed = previewBoundsOf(id);\n if (previewed) return previewed;\n return effectiveBoundsOf ? effectiveBoundsOf(id) : null;\n }, [previewBoundsOf, effectiveBoundsOf]);\n\n const chromeState: ChromeState = useMemo(\n () => buildChromeState({\n selection,\n multiActive,\n effectiveBoundsOf: boundsWithPreview,\n modifiers: { alt: false, shift: false, meta: false, ctrl: false },\n // Absent adapter / unknown ids fall back to `true` so the affordance\n // stays visible for consumers that wire bounds without an adapter.\n canRotate: (id) => {\n if (!geometry.supportsRotation) return true;\n const pose = committedPoseOf(id);\n if (pose == null) return true;\n return geometry.supportsRotation(pose);\n },\n ...(layerIsPainted ? { layerIsPainted } : {}),\n ...(adapter?.getNode ? { layerOf: (id: string) => adapter.getNode?.(id)?.layer } : {}),\n }),\n [selection, multiActive, boundsWithPreview, geometry, committedPoseOf, layerIsPainted, adapter],\n );\n\n const helpers: CanvasViewHelpers<TPose> = {\n getEffectivePose: (id: string): TPose | null => {\n return previewPoseOf(id) ?? committedPoseOf(id);\n },\n getEffectiveBounds: boundsWithPreview,\n getGestureBounds: (): Bounds | null => {\n // The same id sets the ghost layer walks, so this cannot disagree with\n // what the user sees ghosted.\n const parts: (Bounds | null)[] = [];\n for (const id of new Set(gestureSource?.ids() ?? [])) parts.push(previewBoundsOf(id));\n const extraBounds = gestureSource?.bounds();\n if (extraBounds) for (const b of extraBounds) parts.push(b);\n return unionAABB(parts);\n },\n subscribeGestures: (fn: () => void): (() => void) =>\n gestureSource?.subscribe(fn) ?? noOpUnsubscribe,\n getGestureVersion: (): number => gestureSource?.getVersion() ?? 0,\n getChromeState: () => chromeState,\n getPreviewSources: (): readonly GesturePreviewSource[] => gestureSource?.previewSources() ?? [],\n getGestureOverlays: (): readonly OngoingOverlay[] => gestureSource?.overlays() ?? [],\n getIsVisible: (): ((id: string) => boolean) => getIsVisible?.() ?? alwaysVisible,\n };\n\n return { helpers };\n}\n"],"mappings":";;;;;;;;;AAeA,IAAM,wBAA8B,CAAC;AAErC,IAAM,sBAA+B;AAmJrC,SAAS,YAAmB,SAAiC,IAAmB;CAC9E,OAAO,OAAO,QAAQ,iBAAiB,aAAa,QAAQ,aAAa,EAAE,IAAI,QAAQ,QAAQ,EAAE;AACnG;;;;;;AAOA,SAAgB,eACd,MAC0B;CAC1B,MAAM,EACJ,SAAS,UAAU,UAAU,cAAc,OAAO,UAAU,WAAW,eACvE,kBAAkB,cAAc,mBAC9B;CACJ,MAAM,cAAc,UAAU,QAAQ;CACtC,MAAM,YAAY,aAAa,IAAY,SAAwB;EACjE,IAAI,CAAC,OAAO,OAAO,aAAa,MAAM,QAAQ;EAC9C,MAAM,QAAQ,YAAY,UAAU;EACpC,OAAO,cAAc,OAAO,IAAc,MAAM;GAC9C,YAAY;GACZ,GAAI,UAAU,EAAE,cAAc,MAAc,YAAY,SAAS,CAAC,EAAE,IAAI,CAAC;GACzE,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EAC3B,CAAC;CACH,GAAG;EAAC;EAAO;EAAU;EAAS;CAAW,CAAC;CAC1C,MAAM,QAAQ,aACX,IAAY,SACV,eAAe,aAAa,IAAI,IAAI,IAAI,UAAU,IAAI,IAAI,GAC7D,CAAC,cAAc,SAAS,CAC1B;CAEA,MAAM,eAAe,cAAc;EACjC,IAAI,UAAU,OAAO;EACrB,IAAI,CAAC,SAAS,OAAO;EACrB,QAAQ,OAA8B;GACpC,IAAI;IAGF,OAAO,UAAU,IAAI,YAAY,SAAS,EAAE,CAAC;GAC/C,QAAQ;IACN,OAAO;GACT;EACF;CACF,GAAG;EAAC;EAAU;EAAS;CAAS,CAAC;CAEjC,MAAM,kBAAkB,aAAa,OAA6B;EAChE,IAAI,CAAC,SAAS,OAAO;EACrB,IAAI;GACF,OAAO,YAAY,SAAS,EAAE;EAChC,QAAQ;GACN,OAAO;EACT;CACF,GAAG,CAAC,OAAO,CAAC;CAEZ,MAAM,cAAc,UAAU,SAAS;CAEvC,MAAM,oBAAoB,cAAc,YAAY,cAAc,CAAC,UAAU,YAAY,CAAC;CAC1F,MAAM,EAAE,eAAe,oBAAoB,kBAAkB;EAAE;EAAe;EAAkB;EAAO;CAAgB,CAAC;;;;;;;CAQxH,MAAM,oBAAoB,aAAa,OAA8B;EACnE,MAAM,YAAY,gBAAgB,EAAE;EACpC,IAAI,WAAW,OAAO;EACtB,OAAO,oBAAoB,kBAAkB,EAAE,IAAI;CACrD,GAAG,CAAC,iBAAiB,iBAAiB,CAAC;CAEvC,MAAM,cAA2B,cACzB,iBAAiB;EACrB;EACA;EACA,mBAAmB;EACnB,WAAW;GAAE,KAAK;GAAO,OAAO;GAAO,MAAM;GAAO,MAAM;EAAM;EAGhE,YAAY,OAAO;GACjB,IAAI,CAAC,SAAS,kBAAkB,OAAO;GACvC,MAAM,OAAO,gBAAgB,EAAE;GAC/B,IAAI,QAAQ,MAAM,OAAO;GACzB,OAAO,SAAS,iBAAiB,IAAI;EACvC;EACA,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;EAC3C,GAAI,SAAS,UAAU,EAAE,UAAU,OAAe,QAAQ,UAAU,EAAE,CAAC,EAAE,MAAM,IAAI,CAAC;CACtF,CAAC,GACD;EAAC;EAAW;EAAa;EAAmB;EAAU;EAAiB;EAAgB;CAAO,CAChG;CAyBA,OAAO,EAAE;EAtBP,mBAAmB,OAA6B;GAC9C,OAAO,cAAc,EAAE,KAAK,gBAAgB,EAAE;EAChD;EACA,oBAAoB;EACpB,wBAAuC;GAGrC,MAAM,QAA2B,CAAC;GAClC,KAAK,MAAM,MAAM,IAAI,IAAI,eAAe,IAAI,KAAK,CAAC,CAAC,GAAG,MAAM,KAAK,gBAAgB,EAAE,CAAC;GACpF,MAAM,cAAc,eAAe,OAAO;GAC1C,IAAI,aAAa,KAAK,MAAM,KAAK,aAAa,MAAM,KAAK,CAAC;GAC1D,OAAO,UAAU,KAAK;EACxB;EACA,oBAAoB,OAClB,eAAe,UAAU,EAAE,KAAK;EAClC,yBAAiC,eAAe,WAAW,KAAK;EAChE,sBAAsB;EACtB,yBAA0D,eAAe,eAAe,KAAK,CAAC;EAC9F,0BAAqD,eAAe,SAAS,KAAK,CAAC;EACnF,oBAA+C,eAAe,KAAK;CAG5D,EAAQ;AACnB"}
|
|
1
|
+
{"version":3,"file":"useViewHelpers.js","names":[],"sources":["../../src/canvas/useViewHelpers.ts"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport { framedBounds } from 'core/geometry/poseDescriptor';\nimport { useLatest } from '@weasel-js/react';\nimport type { GestureSource, GesturePreviewSource } from './gestureBounds';\nimport { useInFlightBounds } from './useInFlightBounds';\nimport type { OngoingOverlay } from '@weasel-js/routing';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport { buildChromeState, type ChromeState } from 'core/selection/chromeState';\nimport type { PoseDescriptor } from 'interactions/actions/resize/geometry';\nimport type { NodeId } from 'core/scene/types';\nimport type { DebugSink } from '../debug/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { Scale2 } from '@weasel-js/geom';\nimport { drawnBoundsOf, type DrawnBoundsScene } from './drawnBounds';\n\nconst noOpUnsubscribe = (): void => {};\n\nconst alwaysVisible = (): boolean => true;\n\n/**\n * The half of {@link CanvasHelpers} that belongs to one view — everything\n * answered by a camera's own tools, gestures and selection. A canvas hosting\n * several viewports needs one of these per view; the surface half is shared.\n */\nexport interface CanvasViewHelpers<TPose> {\n /** Pose currently displayed for `id` — drag/resize/rotate overlay if active,\n * otherwise the committed pose from the adapter. Returns `null` if the id\n * isn't known. */\n getEffectivePose(id: string): TPose | null;\n /** Overlay-aware bounds for `id`. */\n getEffectiveBounds(id: string): Bounds | null;\n /**\n * World-space AABB of everything the in-flight gesture proposes — the\n * displaced poses of nodes being moved / resized / rotated / cloned, plus\n * any nascent insert that has no scene node yet. `null` when no gesture is\n * in flight.\n *\n * This reports the *gesture*, not the document: committed content the\n * gesture isn't touching is excluded. Select-only gestures are excluded\n * too: a marquee or lasso has geometry but proposes no content.\n *\n * The result is a plain AABB — never rotated. Rotated parts are folded in\n * by their rotated extent.\n */\n getGestureBounds(): Bounds | null;\n /**\n * Subscribe to the gesture layer's change signal, for everything on this\n * object that moves during a drag (`getEffectivePose`, `getEffectiveBounds`,\n * `getGestureBounds`). Returns an unsubscribe.\n *\n * Fires once per dispatcher pump: gesture start, every pointermove that\n * reaches an in-flight handle, end, and cancel — plus UI-driven ongoing\n * actions. It fires on the pump, not on a diff: a pump that changed nothing\n * observable still notifies, so don't hang expensive work directly off the\n * callback.\n *\n * It does **not** cover committed scene edits (subscribe to the scene for\n * those) or previews a consumer's own tool publishes from React state.\n * Without a gesture source wired — a bare `<Canvas>` — it never fires.\n */\n subscribeGestures(fn: () => void): () => void;\n /**\n * Monotonic counter bumped on exactly the events `subscribeGestures` fires\n * on. Pair the two for `useSyncExternalStore`:\n *\n * ```ts\n * const gestureVersion = useSyncExternalStore(\n * useCallback((cb) => helpersRef.current?.subscribeGestures(cb) ?? (() => {}), []),\n * () => helpersRef.current?.getGestureVersion() ?? 0,\n * );\n * ```\n *\n * Starts at 0 and only increases. `0` is also what a bare `<Canvas>` with\n * no gesture source reports, forever.\n */\n getGestureVersion(): number;\n /** The live ChromeState built once per render: overlay-aware selection\n * state for affordances and custom layers. */\n getChromeState(): ChromeState;\n /**\n * Everything publishing an in-flight preview for this view: the handles in\n * flight on its dispatcher, in dispatch order. Readers take the first\n * non-null answer per id.\n *\n * A ghost layer must read this off its draw envelope rather than close over\n * a dispatcher: one layer array paints every view, so a closure ghosts view\n * zero's drag into every panel.\n */\n getPreviewSources(): readonly GesturePreviewSource[];\n /** Overlay shapes this view's in-flight handles publish — marquee, lasso,\n * insert preview, raw commands. Same envelope rule as\n * {@link CanvasViewHelpers.getPreviewSources}. */\n getGestureOverlays(): readonly OngoingOverlay[];\n /**\n * Chrome-caps visibility predicate, keyed by chrome id. Overlay layers and\n * affordances call it per element to decide whether to draw / hit-test.\n * Unwired, it is the universal `() => true`.\n */\n getIsVisible(): (id: string) => boolean;\n}\n\n/**\n * The half of {@link CanvasHelpers} that belongs to the surface — one GL\n * context, one debug sink, however many views are drawn on it.\n */\nexport interface CanvasSurfaceHelpers {\n /** Active debug sink, when `<Canvas debug=...>` is enabled, for layers to\n * call from their `draw` callback. `null` when debug is off. */\n getDebug(): DebugSink | null;\n}\n\n/** Live overlay-aware lookups exposed to custom layers via `helpersRef`, and\n * what a layer receives as its `data` argument. */\nexport interface CanvasHelpers<TPose> extends CanvasViewHelpers<TPose>, CanvasSurfaceHelpers {\n /**\n * The view this draw is for: a `<CanvasView>` id, or `null` for the\n * surface's own camera. One layer array paints every view, so a layer that\n * belongs in some views and not others — a minimap's indicator — declines\n * the rest by this id.\n */\n readonly viewId: string | null;\n}\n\n/** What a view's pose and bounds lookups read of an adapter. */\nexport interface ViewPoseAdapter<TPose> {\n getPose(id: string): TPose;\n /** Where the node is drawn, when the adapter composes poses. An adapter\n * without it stores absolute poses, where the two agree. */\n getWorldPose?(id: string): TPose;\n /** The node an id names, whose `layer` decides whether a view that hides\n * that layer shows its selection chrome. */\n getNode?(id: string): { layer?: string } | undefined;\n}\n\nexport interface UseViewHelpersOpts<TPose> {\n adapter: ViewPoseAdapter<TPose> | undefined;\n geometry: PoseDescriptor<TPose>;\n /** Consumer-supplied bounds resolver. Falls back to the adapter's pose. */\n boundsOf: ((id: string) => Bounds | null) | undefined;\n /** Bounds of `id` drawn at an in-flight `pose`. Falls back to the\n * geometry's box of that pose, which is wrong wherever the surface draws a\n * node somewhere its pose does not say — a parallax plane. */\n boundsOfPose?: ((id: string, pose: TPose) => Bounds | null) | undefined;\n /** The nodes the adapter's ids name: with them, the fallbacks box each as\n * drawn, stroke included, rather than by its pose. */\n nodes?: DrawnBoundsScene | undefined;\n /** The view's scale, which a screen-pixel stroke is resolved at. Default 1. */\n getScale?: (() => Scale2) | undefined;\n /** The ids selected, read whenever chrome asks: a view following another\n * reads that view's, which changes without this one rendering. */\n selection: () => readonly NodeId[];\n gestureSource: GestureSource | undefined;\n /** The dispatcher's preview pose for an id, read through a ref so a change\n * mid-gesture doesn't rebuild the memos that depend on it. */\n previewPoseExtra: ((id: string) => unknown) | undefined;\n /** Chrome-caps predicate for this view. Absent means everything is visible. */\n getIsVisible?: (() => (id: string) => boolean) | undefined;\n /** Whether a scene layer reaches the screen in this view. Absent means\n * every layer the scene shows does. */\n layerIsPainted?: ((layerId: string) => boolean) | undefined;\n}\n\nexport interface ViewHelpersBundle<TPose> {\n helpers: CanvasViewHelpers<TPose>;\n}\n\nfunction worldPoseOf<TPose>(adapter: ViewPoseAdapter<TPose>, id: string): TPose {\n return typeof adapter.getWorldPose === 'function' ? adapter.getWorldPose(id) : adapter.getPose(id);\n}\n\n/**\n * Build one view's overlay-aware state: its chrome and the lookups its layers\n * draw and hit-test against. A canvas with N views mounts N components each\n * calling this once.\n */\nexport function useViewHelpers<TPose>(\n opts: UseViewHelpersOpts<TPose>,\n): ViewHelpersBundle<TPose> {\n const {\n adapter, geometry, boundsOf, boundsOfPose, nodes, getScale, selection, gestureSource,\n previewPoseExtra, getIsVisible, layerIsPainted,\n } = opts;\n const getScaleRef = useLatest(getScale);\n const poseBoxOf = useCallback((id: string, pose: TPose): Bounds => {\n if (!nodes) return framedBounds(pose, geometry);\n const scale = getScaleRef.current?.();\n return drawnBoundsOf(nodes, id as NodeId, pose, {\n descriptor: geometry as PoseDescriptor<unknown>,\n ...(adapter ? { worldPoseOf: (m: NodeId) => worldPoseOf(adapter, m) } : {}),\n ...(scale ? { scale } : {}),\n });\n }, [nodes, geometry, adapter, getScaleRef]);\n const boxOf = useCallback(\n (id: string, pose: TPose): Bounds | null =>\n (boundsOfPose ? boundsOfPose(id, pose) : poseBoxOf(id, pose)),\n [boundsOfPose, poseBoxOf],\n );\n\n const baseBoundsOf = useMemo(() => {\n if (boundsOf) return boundsOf;\n if (!adapter) return undefined;\n return (id: string): Bounds | null => {\n try {\n // World: chrome is drawn over the picture, so it has to agree with\n // where the renderer put the node, not with where its pose is stored.\n return poseBoxOf(id, worldPoseOf(adapter, id));\n } catch {\n return null;\n }\n };\n }, [boundsOf, adapter, poseBoxOf]);\n\n const committedPoseOf = useCallback((id: string): TPose | null => {\n if (!adapter) return null;\n try {\n return worldPoseOf(adapter, id);\n } catch {\n return null;\n }\n }, [adapter]);\n\n const selectionRef = useLatest(selection);\n\n const effectiveBoundsOf = useMemo(() => boundsOf ?? baseBoundsOf, [boundsOf, baseBoundsOf]);\n const { previewPoseOf, previewBoundsOf } = useInFlightBounds({ gestureSource, previewPoseExtra, boxOf, committedPoseOf });\n\n /**\n * Bounds for `id` with any in-flight gesture folded in — what the user can\n * see, not what is committed. Both the chrome state and the layer helpers\n * answer bounds questions with this, so resize handles cannot end up a frame\n * away from the shape they belong to.\n */\n const boundsWithPreview = useCallback((id: string): Bounds | null => {\n const previewed = previewBoundsOf(id);\n if (previewed) return previewed;\n return effectiveBoundsOf ? effectiveBoundsOf(id) : null;\n }, [previewBoundsOf, effectiveBoundsOf]);\n\n const chromeState: ChromeState = useMemo(\n () => buildChromeState({\n get selection() { return selectionRef.current(); },\n get multiActive() { return selectionRef.current().length > 1; },\n effectiveBoundsOf: boundsWithPreview,\n modifiers: { alt: false, shift: false, meta: false, ctrl: false },\n // Absent adapter / unknown ids fall back to `true` so the affordance\n // stays visible for consumers that wire bounds without an adapter.\n canRotate: (id) => {\n if (!geometry.supportsRotation) return true;\n const pose = committedPoseOf(id);\n if (pose == null) return true;\n return geometry.supportsRotation(pose);\n },\n ...(layerIsPainted ? { layerIsPainted } : {}),\n ...(adapter?.getNode ? { layerOf: (id: string) => adapter.getNode?.(id)?.layer } : {}),\n }),\n [selectionRef, boundsWithPreview, geometry, committedPoseOf, layerIsPainted, adapter],\n );\n\n const helpers: CanvasViewHelpers<TPose> = {\n getEffectivePose: (id: string): TPose | null => {\n return previewPoseOf(id) ?? committedPoseOf(id);\n },\n getEffectiveBounds: boundsWithPreview,\n getGestureBounds: (): Bounds | null => {\n // The same id sets the ghost layer walks, so this cannot disagree with\n // what the user sees ghosted.\n const parts: (Bounds | null)[] = [];\n for (const id of new Set(gestureSource?.ids() ?? [])) parts.push(previewBoundsOf(id));\n const extraBounds = gestureSource?.bounds();\n if (extraBounds) for (const b of extraBounds) parts.push(b);\n return unionAABB(parts);\n },\n subscribeGestures: (fn: () => void): (() => void) =>\n gestureSource?.subscribe(fn) ?? noOpUnsubscribe,\n getGestureVersion: (): number => gestureSource?.getVersion() ?? 0,\n getChromeState: () => chromeState,\n getPreviewSources: (): readonly GesturePreviewSource[] => gestureSource?.previewSources() ?? [],\n getGestureOverlays: (): readonly OngoingOverlay[] => gestureSource?.overlays() ?? [],\n getIsVisible: (): ((id: string) => boolean) => getIsVisible?.() ?? alwaysVisible,\n };\n\n return { helpers };\n}\n"],"mappings":"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"}
|
|
@@ -71,32 +71,59 @@ function useViewNesting(registry, live) {
|
|
|
71
71
|
const p = live.current.parent;
|
|
72
72
|
return p === void 0 ? void 0 : registry?.get(p);
|
|
73
73
|
}, [live, registry]);
|
|
74
|
+
const following = useRef(false);
|
|
75
|
+
/** `read` asked of the view this one follows, while it names a live one. */
|
|
76
|
+
const ofFollowed = useCallback((read) => {
|
|
77
|
+
const id = live.current.follows?.() ?? null;
|
|
78
|
+
const reg = id === null || following.current ? void 0 : registry?.get(id);
|
|
79
|
+
if (!reg) return null;
|
|
80
|
+
following.current = true;
|
|
81
|
+
try {
|
|
82
|
+
return { value: read(reg) };
|
|
83
|
+
} finally {
|
|
84
|
+
following.current = false;
|
|
85
|
+
}
|
|
86
|
+
}, [live, registry]);
|
|
74
87
|
/** The layers this view draws, in the order it draws them: of the surface's,
|
|
75
|
-
* or of what the view it is nested in draws. */
|
|
88
|
+
* or of what the view it is nested in or follows draws. */
|
|
76
89
|
const drawnLayers = useCallback(() => {
|
|
90
|
+
const followed = ofFollowed((reg) => reg.drawnLayers());
|
|
91
|
+
if (followed) return viewPaintedLayers(followed.value, live.current);
|
|
77
92
|
if (live.current.parent !== void 0) return viewPaintedLayers(parentReg()?.drawnLayers() ?? [], live.current);
|
|
78
93
|
return viewPaintedLayers(registry?.surface()?.layers() ?? [], live.current);
|
|
79
94
|
}, [
|
|
80
95
|
registry,
|
|
81
96
|
live,
|
|
82
|
-
parentReg
|
|
97
|
+
parentReg,
|
|
98
|
+
ofFollowed
|
|
83
99
|
]);
|
|
84
100
|
const [sceneLayerGate] = useState(createSceneLayerGate);
|
|
101
|
+
/** What this view's picks, marquees and select-alls ask of a scene layer:
|
|
102
|
+
* painted here, and in every view this one is nested in or follows. */
|
|
103
|
+
const layerIsPainted = useCallback((layerId) => {
|
|
104
|
+
if (!sceneLayerGate(registry?.surface()?.layers() ?? [], live.current)(layerId)) return false;
|
|
105
|
+
const followed = ofFollowed((reg) => reg.layerIsPainted(layerId));
|
|
106
|
+
if (followed) return followed.value;
|
|
107
|
+
if (live.current.parent === void 0) return true;
|
|
108
|
+
return parentReg()?.layerIsPainted(layerId) ?? false;
|
|
109
|
+
}, [
|
|
110
|
+
registry,
|
|
111
|
+
sceneLayerGate,
|
|
112
|
+
live,
|
|
113
|
+
parentReg,
|
|
114
|
+
ofFollowed
|
|
115
|
+
]);
|
|
116
|
+
/** The selection this view owns, or else the one the view it follows owns:
|
|
117
|
+
* `undefined` while it shares the surface's. */
|
|
118
|
+
const ownedSelection = useCallback(() => live.current.viewSelection ?? ofFollowed((reg) => reg.selection())?.value, [live, ofFollowed]);
|
|
85
119
|
return {
|
|
86
120
|
frameIn,
|
|
87
121
|
rectAt,
|
|
88
122
|
derivedAt,
|
|
89
123
|
drawnLayers,
|
|
90
|
-
layerIsPainted
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return parentReg()?.layerIsPainted(layerId) ?? false;
|
|
94
|
-
}, [
|
|
95
|
-
registry,
|
|
96
|
-
sceneLayerGate,
|
|
97
|
-
live,
|
|
98
|
-
parentReg
|
|
99
|
-
])
|
|
124
|
+
layerIsPainted,
|
|
125
|
+
ownedSelection,
|
|
126
|
+
selectionNow: useCallback(() => ownedSelection() ?? live.current.shared, [ownedSelection, live])
|
|
100
127
|
};
|
|
101
128
|
}
|
|
102
129
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useViewNesting.js","names":[],"sources":["../../src/canvas/useViewNesting.ts"],"sourcesContent":["/**\n * How a `<CanvasView>` sits in the view it is nested in: the frame its\n * `bounds` and derived camera are measured against, and the layers it may\n * paint. Without a `parent` the frame is the surface's.\n */\nimport { useCallback, useRef, useState } from 'react';\nimport type { Dims, RenderLayer } from 'core/layers/render';\nimport type { View } from 'core/viewport/view';\nimport type { CanvasViewProps, ViewRect } from './canvasViewProps';\nimport { createSceneLayerGate, viewPaintedLayers } from './sceneLayerPaint';\nimport type { ViewRegistration, ViewRegistry } from './viewRegistry';\n\nexport const NO_RECT: ViewRect = { x: 0, y: 0, w: 0, h: 0 };\n\n/** What a view's `bounds` and `view` are measured against: the surface, or\n * the view it is nested in. `origin` and `clip` are in canvas CSS px. */\nexport interface OuterFrame { view: View; dims: Dims; origin: { x: number; y: number }; clip?: ViewRect }\n\n/** The props the nesting reads, as of the last committed render. */\nexport type ViewNestingInputs = Pick<CanvasViewProps, 'parent' | 'bounds' | 'layers' | 'layerVisibility' | 'layerOrder'
|
|
1
|
+
{"version":3,"file":"useViewNesting.js","names":[],"sources":["../../src/canvas/useViewNesting.ts"],"sourcesContent":["/**\n * How a `<CanvasView>` sits in the view it is nested in: the frame its\n * `bounds` and derived camera are measured against, and the layers it may\n * paint. Without a `parent` the frame is the surface's.\n */\nimport { useCallback, useRef, useState } from 'react';\nimport type { Dims, RenderLayer } from 'core/layers/render';\nimport type { View } from 'core/viewport/view';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport type { CanvasViewProps, ViewRect } from './canvasViewProps';\nimport { createSceneLayerGate, viewPaintedLayers } from './sceneLayerPaint';\nimport type { ViewRegistration, ViewRegistry } from './viewRegistry';\n\nexport const NO_RECT: ViewRect = { x: 0, y: 0, w: 0, h: 0 };\n\n/** What a view's `bounds` and `view` are measured against: the surface, or\n * the view it is nested in. `origin` and `clip` are in canvas CSS px. */\nexport interface OuterFrame { view: View; dims: Dims; origin: { x: number; y: number }; clip?: ViewRect }\n\n/** The props the nesting reads, as of the last committed render. */\nexport type ViewNestingInputs = Pick<CanvasViewProps, 'parent' | 'follows' | 'bounds' | 'layers' | 'layerVisibility' | 'layerOrder'> & {\n /** The selection the view owns, when it owns one. */\n viewSelection?: SelectionApi | undefined;\n /** The surface's selection, which the view acts on while it neither owns one nor follows a view that does. */\n shared: SelectionApi;\n};\n\n/** A view rect's size, as the `Dims` its camera looks through. */\nexport const sizeOf = (rect: ViewRect): Dims => ({ width: rect.w, height: rect.h });\n\nexport function useViewNesting(\n registry: ViewRegistry | null,\n live: { readonly current: ViewNestingInputs },\n) {\n // Set while this view asks its parent for a frame, so a parent chain that\n // loops back finds no frame rather than recursing.\n const measuring = useRef(false);\n /** The frame this view is measured in, for a surface frame; `null` while\n * its parent is missing. */\n const frameIn = useCallback((outer: View, dims: Dims): OuterFrame | null => {\n const p = live.current.parent;\n if (p === undefined) return { view: outer, dims, origin: { x: 0, y: 0 } };\n const reg = registry?.get(p);\n if (!reg || measuring.current) return null;\n measuring.current = true;\n try {\n const r = reg.layer.resolvable(outer, dims);\n return {\n view: r.view, dims: sizeOf(r.rect), origin: { x: r.rect.x, y: r.rect.y }, clip: r.clip ?? r.rect,\n };\n } finally {\n measuring.current = false;\n }\n }, [live, registry]);\n\n const rectAt = useCallback((outer: View, dims: Dims): ViewRect => {\n const frame = frameIn(outer, dims);\n if (!frame) return NO_RECT;\n const b = live.current.bounds;\n const r = typeof b === 'function' ? b(frame.view, frame.dims) : b;\n return { ...r, x: r.x + frame.origin.x, y: r.y + frame.origin.y };\n }, [live, frameIn]);\n\n /** A derived camera or aim, for a surface frame: asked of the frame it is measured in. */\n const derivedAt = useCallback(<T>(derive: (outer: View, dims: Dims) => T, outer: View, dims: Dims): T => {\n const frame = frameIn(outer, dims);\n return frame ? derive(frame.view, frame.dims) : derive(outer, dims);\n }, [frameIn]);\n\n /** The view this one is nested in, while it is registered. */\n const parentReg = useCallback((): ViewRegistration | undefined => {\n const p = live.current.parent;\n return p === undefined ? undefined : registry?.get(p);\n }, [live, registry]);\n\n // Set while this view asks the view it follows, so two views following each\n // other find nothing to follow rather than recursing.\n const following = useRef(false);\n /** `read` asked of the view this one follows, while it names a live one. */\n const ofFollowed = useCallback(<T>(read: (reg: ViewRegistration) => T): { value: T } | null => {\n const id = live.current.follows?.() ?? null;\n const reg = id === null || following.current ? undefined : registry?.get(id);\n if (!reg) return null;\n following.current = true;\n try {\n return { value: read(reg) };\n } finally {\n following.current = false;\n }\n }, [live, registry]);\n\n /** The layers this view draws, in the order it draws them: of the surface's,\n * or of what the view it is nested in or follows draws. */\n const drawnLayers = useCallback((): readonly RenderLayer<unknown>[] => {\n const followed = ofFollowed((reg) => reg.drawnLayers());\n if (followed) return viewPaintedLayers(followed.value, live.current);\n if (live.current.parent !== undefined) return viewPaintedLayers(parentReg()?.drawnLayers() ?? [], live.current);\n return viewPaintedLayers(registry?.surface()?.layers() ?? [], live.current);\n }, [registry, live, parentReg, ofFollowed]);\n\n const [sceneLayerGate] = useState(createSceneLayerGate);\n /** What this view's picks, marquees and select-alls ask of a scene layer:\n * painted here, and in every view this one is nested in or follows. */\n const layerIsPainted = useCallback((layerId: string): boolean => {\n if (!sceneLayerGate(registry?.surface()?.layers() ?? [], live.current)(layerId)) return false;\n const followed = ofFollowed((reg) => reg.layerIsPainted(layerId));\n if (followed) return followed.value;\n if (live.current.parent === undefined) return true;\n return parentReg()?.layerIsPainted(layerId) ?? false;\n }, [registry, sceneLayerGate, live, parentReg, ofFollowed]);\n\n /** The selection this view owns, or else the one the view it follows owns:\n * `undefined` while it shares the surface's. */\n const ownedSelection = useCallback((): SelectionApi | undefined => (\n live.current.viewSelection ?? ofFollowed((reg) => reg.selection())?.value\n ), [live, ofFollowed]);\n /** The selection this view acts on, as of now: a followed view's changes with the aim. */\n const selectionNow = useCallback(() => ownedSelection() ?? live.current.shared, [ownedSelection, live]);\n return { frameIn, rectAt, derivedAt, drawnLayers, layerIsPainted, ownedSelection, selectionNow };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewInputs.js","names":[],"sources":["../../src/canvas/viewInputs.tsx"],"sourcesContent":["/**\n * What {@link useViewHelpers} needs that belongs to the surface rather than to\n * one view: the adapter, the geometry and the bounds resolver.\n *\n * These are read during a view's render, so they travel as context rather than\n * on the `SurfaceHandle`, which is not attached until an effect runs.\n */\nimport type { ResizeHandleLayout } from 'interactions/actions/resize/cornerHandles';\nimport { createContext, useContext, type ReactNode } from 'react';\nimport type { UseViewHelpersOpts } from './useViewHelpers';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport type { View } from 'core/viewport/view';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { PlaneMap } from 'core/viewport/parallax';\nimport type { ChromeCaps } from '
|
|
1
|
+
{"version":3,"file":"viewInputs.js","names":[],"sources":["../../src/canvas/viewInputs.tsx"],"sourcesContent":["/**\n * What {@link useViewHelpers} needs that belongs to the surface rather than to\n * one view: the adapter, the geometry and the bounds resolver.\n *\n * These are read during a view's render, so they travel as context rather than\n * on the `SurfaceHandle`, which is not attached until an effect runs.\n */\nimport type { ResizeHandleLayout } from 'interactions/actions/resize/cornerHandles';\nimport { createContext, useContext, type ReactNode } from 'react';\nimport type { UseViewHelpersOpts } from './useViewHelpers';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport type { View } from 'core/viewport/view';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { PlaneMap } from 'core/viewport/parallax';\nimport type { ChromeCaps } from 'domains/chrome-caps/useChromeCaps';\nimport type { PickView } from './SceneCanvas/useSceneSelectTool';\nimport type { WorldPoint } from '@weasel-js/routing';\n\nexport type { ViewRuleInputs } from 'domains/chrome-caps/useChromeCaps';\n\n/**\n * @internal Provided by the surface, consumed by `<CanvasView>`.\n *\n * The scene-shaped half only. What a gesture is doing right now is read from\n * the asking view's own dispatcher, not from here.\n */\nexport interface SurfaceViewInputs\n extends Pick<UseViewHelpersOpts<unknown>, 'adapter' | 'geometry'> {\n /** A node's box for chrome, drawn under `view` — the camera of the view\n * asking, since a node on a parallax plane lands somewhere else in each. */\n boundsOf: ((id: string, view?: View | null) => Bounds | null) | undefined;\n /** How `view`'s world maps into the parallax plane `id` is drawn through,\n * or null when its layer moves with the camera. */\n planeOfNode?: ((id: string, view?: View | null) => PlaneMap | null) | undefined;\n /** `boundsOf` for `id` drawn at an in-flight `pose`, under `view`. */\n boundsOfPose?: ((id: string, pose: unknown, view?: View | null) => Bounds | null) | undefined;\n /** Every id under a world point, bottom-first. `view` is the view the\n * point was produced under — a screen-pixel tolerance cannot be converted\n * without its scale, nor a layer judged without its paint, and the world\n * point carries neither. */\n pickEvery?: (world: WorldPoint, view?: PickView | null) => string[];\n /** The one id a click resolves to, collapsing parent/child the way the\n * select tool does. Falls back to `pickEvery`'s last when absent. */\n pickBest?: (world: WorldPoint, view?: PickView | null) => string | null;\n /** A hit node's routing-trait kind, so `target: 'kind:text'` bindings match. */\n kindOfNode?: (id: string) => string | undefined;\n /** The node a double-click on a hit names (`doubleClickTarget`). */\n doubleClickNames?: ((hitId: string) => string) | undefined;\n /** The surface's chrome-caps rule table, evaluated against a view's own\n * context. */\n chromeCaps?: ChromeCaps;\n /** The surface's selection, which a view shares unless it was given one of\n * its own. */\n selectionApi: SelectionApi;\n /** The rotate badge the surface's selection overlay paints, which every\n * view drawing that overlay has to make grabbable where it is drawn. */\n rotationBadge?: { distancePx: number; sizePx: number } | null;\n /** The surface's resize-handle layout — which handles exist and their hit\n * radius — so every view grabs exactly the handles the overlay paints. */\n resizeHandles?: ResizeHandleLayout;\n}\n\nconst ViewInputsContext = createContext<SurfaceViewInputs | null>(null);\n\n/** @internal */\nexport function ViewInputsProvider(\n { value, children }: { value: SurfaceViewInputs; children: ReactNode },\n) {\n return <ViewInputsContext.Provider value={value}>{children}</ViewInputsContext.Provider>;\n}\n\n/** The hosting surface's view-helper inputs, or `null` outside one. */\nexport function useOptionalViewInputs(): SurfaceViewInputs | null {\n return useContext(ViewInputsContext);\n}\n"],"mappings":";;;;AA8DA,IAAM,oBAAoB,cAAwC,IAAI;;AAGtE,SAAgB,mBACd,EAAE,OAAO,YACT;CACA,OAAO,oBAAC,kBAAkB,UAAnB;EAAmC;EAAQ;CAAqC,CAAA;AACzF;;AAGA,SAAgB,wBAAkD;CAChE,OAAO,WAAW,iBAAiB;AACrC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { aimSpace2d } from "../
|
|
2
|
-
import { createViewMarkerLayer, grabViewMarker } from "../
|
|
1
|
+
import { aimSpace2d } from "../domains/viewports/aim.js";
|
|
2
|
+
import { createViewMarkerLayer, grabViewMarker } from "../domains/viewports/viewMarker.js";
|
|
3
3
|
import { layerAffordance } from "./affordanceAt.js";
|
|
4
4
|
|
|
5
5
|
//#region src/canvas/viewMarkers.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewMarkers.js","names":[],"sources":["../../src/canvas/viewMarkers.ts"],"sourcesContent":["/**\n * The marker half of a surface's view registry: which markers are live, the\n * layers they draw, and which one a press lands on.\n */\nimport type { Dims, RenderLayer } from 'core/layers/render';\nimport type { AffordanceHit } from '@weasel-js/routing';\nimport { aimSpace2d, type AimSpace } from '
|
|
1
|
+
{"version":3,"file":"viewMarkers.js","names":[],"sources":["../../src/canvas/viewMarkers.ts"],"sourcesContent":["/**\n * The marker half of a surface's view registry: which markers are live, the\n * layers they draw, and which one a press lands on.\n */\nimport type { Dims, RenderLayer } from 'core/layers/render';\nimport type { AffordanceHit } from '@weasel-js/routing';\nimport { aimSpace2d, type AimSpace } from 'domains/viewports/aim';\nimport type { ResolvableView } from 'domains/viewports/viewResolver';\nimport type { View } from 'core/viewport/view';\nimport {\n createViewMarkerLayer, grabViewMarker, type ViewMarkerHost, type ViewMarkerProps,\n} from 'domains/viewports/viewMarker';\nimport { layerAffordance } from './affordanceAt';\n\n/** @internal Composed into `ViewRegistry`. */\nexport interface ViewMarkerRegistry {\n /** Returns an unregister. `props` is read at every draw. An id already live\n * on the surface logs an error and is skipped, and its unregister does nothing. */\n registerMarker(props: () => ViewMarkerProps): () => void;\n /** The layers of the markers drawn in `target`'s frame, in mount order. */\n markerLayers(target: string | null): readonly RenderLayer<unknown>[];\n /** The topmost interactive marker drawn in `target` under `world` (a point\n * in `target`'s world), as the affordance a press there routes. */\n markerAt(target: string | null, world: { x: number; y: number }): AffordanceHit | null;\n /** Lets `markerAt` answer while `open()` says the surface binds a marker drag;\n * until then it answers `null`, so a press falls through. Returns an undo. */\n gateMarkers(open: () => boolean): () => void;\n}\n\n/** What the marker half reads off the rest of the registry. */\nexport interface ViewMarkerRegistryDeps {\n host: ViewMarkerHost;\n /** The surface's camera and size, or `null` before one attaches. */\n surface(): { view(): View; dims(): Dims } | null;\n /** View `id` resolved against the surface, or `undefined` while there is none. */\n resolve(id: string, outer: View, dims: Dims): ResolvableView | undefined;\n changed(): void;\n}\n\n/** @internal */\nexport function createViewMarkerRegistry(\n markers: Map<() => ViewMarkerProps, RenderLayer<unknown>>,\n deps: ViewMarkerRegistryDeps,\n): ViewMarkerRegistry {\n let gate: (() => boolean) | null = null;\n const targetSpace = (target: string | null): AimSpace | null => {\n const surface = deps.surface();\n if (!surface) return null;\n if (target === null) return aimSpace2d(null, surface.view(), surface.dims());\n const v = deps.resolve(target, surface.view(), surface.dims());\n return v ? aimSpace2d(target, v.view, { width: v.rect.w, height: v.rect.h }) : null;\n };\n return {\n registerMarker: (props) => {\n const { id } = props();\n for (const live of markers.keys()) {\n if (live().id === id) {\n console.error(`[weasel] registerMarker: marker \"${id}\" is already on this surface, so this one is skipped. Marker ids are unique per surface; rename one.`);\n return () => {};\n }\n }\n markers.set(props, createViewMarkerLayer(props, deps.host));\n deps.changed();\n return () => { markers.delete(props); deps.changed(); };\n },\n markerLayers: (target) => {\n const out: RenderLayer<unknown>[] = [];\n for (const [props, layer] of markers) if (props().target === target) out.push(layer);\n return out;\n },\n markerAt: (target, world) => {\n if (!gate?.()) return null;\n const space = targetSpace(target);\n const at = space?.project(world);\n if (!space || !at) return null;\n const live = [...markers.keys()];\n for (let i = live.length - 1; i >= 0; i--) {\n const props = live[i]!();\n if (props.target !== target) continue;\n const grab = grabViewMarker(props, deps.host, space, at);\n if (grab) return layerAffordance(`view-marker:${props.id}`, { initialScratch: grab });\n }\n return null;\n },\n gateMarkers: (open) => {\n gate = open;\n return () => { if (gate === open) gate = null; };\n },\n };\n}\n"],"mappings":";;;;;;AAwCA,SAAgB,yBACd,SACA,MACoB;CACpB,IAAI,OAA+B;CACnC,MAAM,eAAe,WAA2C;EAC9D,MAAM,UAAU,KAAK,QAAQ;EAC7B,IAAI,CAAC,SAAS,OAAO;EACrB,IAAI,WAAW,MAAM,OAAO,WAAW,MAAM,QAAQ,KAAK,GAAG,QAAQ,KAAK,CAAC;EAC3E,MAAM,IAAI,KAAK,QAAQ,QAAQ,QAAQ,KAAK,GAAG,QAAQ,KAAK,CAAC;EAC7D,OAAO,IAAI,WAAW,QAAQ,EAAE,MAAM;GAAE,OAAO,EAAE,KAAK;GAAG,QAAQ,EAAE,KAAK;EAAE,CAAC,IAAI;CACjF;CACA,OAAO;EACL,iBAAiB,UAAU;GACzB,MAAM,EAAE,OAAO,MAAM;GACrB,KAAK,MAAM,QAAQ,QAAQ,KAAK,GAC9B,IAAI,KAAK,CAAC,CAAC,OAAO,IAAI;IACpB,QAAQ,MAAM,oCAAoC,GAAG,qGAAqG;IAC1J,aAAa,CAAC;GAChB;GAEF,QAAQ,IAAI,OAAO,sBAAsB,OAAO,KAAK,IAAI,CAAC;GAC1D,KAAK,QAAQ;GACb,aAAa;IAAE,QAAQ,OAAO,KAAK;IAAG,KAAK,QAAQ;GAAG;EACxD;EACA,eAAe,WAAW;GACxB,MAAM,MAA8B,CAAC;GACrC,KAAK,MAAM,CAAC,OAAO,UAAU,SAAS,IAAI,MAAM,CAAC,CAAC,WAAW,QAAQ,IAAI,KAAK,KAAK;GACnF,OAAO;EACT;EACA,WAAW,QAAQ,UAAU;GAC3B,IAAI,CAAC,OAAO,GAAG,OAAO;GACtB,MAAM,QAAQ,YAAY,MAAM;GAChC,MAAM,KAAK,OAAO,QAAQ,KAAK;GAC/B,IAAI,CAAC,SAAS,CAAC,IAAI,OAAO;GAC1B,MAAM,OAAO,CAAC,GAAG,QAAQ,KAAK,CAAC;GAC/B,KAAK,IAAI,IAAI,KAAK,SAAS,GAAG,KAAK,GAAG,KAAK;IACzC,MAAM,QAAQ,KAAK,EAAE,CAAE;IACvB,IAAI,MAAM,WAAW,QAAQ;IAC7B,MAAM,OAAO,eAAe,OAAO,KAAK,MAAM,OAAO,EAAE;IACvD,IAAI,MAAM,OAAO,gBAAgB,eAAe,MAAM,MAAM,EAAE,gBAAgB,KAAK,CAAC;GACtF;GACA,OAAO;EACT;EACA,cAAc,SAAS;GACrB,OAAO;GACP,aAAa;IAAE,IAAI,SAAS,MAAM,OAAO;GAAM;EACjD;CACF;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createViewResolver, viewContains } from "../
|
|
2
|
-
import { isRectAim, rectAim, viewForAim } from "../
|
|
1
|
+
import { createViewResolver, viewContains } from "../domains/viewports/viewResolver.js";
|
|
2
|
+
import { isRectAim, rectAim, viewForAim } from "../domains/viewports/aim.js";
|
|
3
3
|
import { viewportWorldRect } from "../core/viewport/viewportWorldRect.js";
|
|
4
4
|
import { createViewMarkerRegistry } from "./viewMarkers.js";
|
|
5
5
|
import { createEmitter } from "@weasel-js/registry";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewRegistry.js","names":[],"sources":["../../src/canvas/viewRegistry.tsx"],"sourcesContent":["/**\n * The seam between a canvas surface and the views drawn on it.\n *\n * Traffic runs both ways: the surface attaches a handle onto its frame and its\n * layer stack, and each view registers what it contributes back — the viewport\n * node it paints into and the record the gesture dispatcher routes its events\n * to. Both sides are thunks, read at draw and dispatch time, so neither can\n * serve the other a frame that has already moved.\n */\nimport { createContext, useContext, useMemo, useRef, type ReactNode } from 'react';\nimport type { Dims, RenderLayer } from 'core/layers/render';\nimport type { LayerHit } from 'affordances/types';\nimport type { ChromeState } from 'core/selection/chromeState';\nimport type { View } from 'core/viewport/view';\nimport type { ViewportLayer } from 'features/viewports/viewportLayer';\nimport type { DispatcherViewTarget } from '@weasel-js/routing/internal';\nimport { createViewResolver, viewContains, type ViewResolver } from 'features/viewports/viewResolver';\nimport { createEmitter } from '@weasel-js/registry';\nimport type { ViewAt } from './canvasExtension';\nimport { isRectAim, rectAim, viewForAim, type ViewAim } from 'features/viewports/aim';\nimport { viewportWorldRect } from 'core/viewport/viewportWorldRect';\nimport type { ViewMarkerProps } from 'features/viewports/viewMarker';\nimport { createViewMarkerRegistry, type ViewMarkerRegistry } from './viewMarkers';\n\n/**\n * What a view needs from the surface hosting it.\n *\n * @internal Attached by the surface, read by `<CanvasView>`.\n */\nexport interface SurfaceHandle {\n /** A client point in the surface's own world — the conversion the surface\n * itself makes, its `clientToWorld` override included. */\n clientToWorld(clientX: number, clientY: number): [number, number];\n /** The outer camera. */\n view(): View;\n /** The canvas's CSS-pixel size. */\n dims(): Dims;\n /** The stack a view paints through its own camera, unless it narrows it. */\n layers(): readonly RenderLayer<unknown>[];\n requestRedraw(): void;\n /** The canvas's own view chrome — its selection, its overlay-aware bounds.\n * What a `<CanvasView>` answers for itself, answered for view zero. */\n chromeState(): ChromeState;\n /** Hit-test the externally registered layers at a world point, against the\n * frame and draw envelope of whichever view is asking. The public\n * `hitTestExtras` is this with the canvas's own frame and envelope. */\n hitTestExtras(\n worldX: number,\n worldY: number,\n view: View,\n dims: Dims,\n data: unknown,\n /** Consider only these layers — the ones the asking view paints. A layer\n * asked on a frame it was not drawn in answers for the wrong pixels. */\n only?: readonly RenderLayer<unknown>[],\n ): { layerId: string; hit: LayerHit } | null;\n /** Whether a registered layer claims a canvas-local point on the surface's\n * own frame. Registered layers paint over every view, so such a point is\n * theirs even inside a view's rect. */\n claimsAbove(x: number, y: number): boolean;\n /** The root camera's input write: clamped, forwarded when controlled, and ending a glide. */\n setView?(next: View): void;\n}\n\n/**\n * A client point in the surface's CSS pixels, from its top-left: the surface's\n * own world point put back through its camera, so a `clientToWorld` override\n * reaches every view declared on it.\n *\n * @internal\n */\nexport function surfaceLocal(\n surface: Pick<SurfaceHandle, 'clientToWorld' | 'view'> | null,\n clientX: number,\n clientY: number,\n): { x: number; y: number } {\n if (!surface) return { x: clientX, y: clientY };\n const [worldX, worldY] = surface.clientToWorld(clientX, clientY);\n const view = surface.view();\n return { x: (worldX - view.x) * view.scale.x, y: (worldY - view.y) * view.scale.y };\n}\n\n/**\n * What one view contributes to the surface hosting it.\n *\n * @internal Written by `<CanvasView>`, read by the surface. Consumers declare\n * a view, not a registration.\n */\nexport interface ViewRegistration {\n id: string;\n /** The view this one is nested in: listed, painted and hit after it, and\n * its `layer` measures itself from that view's rect and camera. */\n parent?: string;\n /**\n * Paint and hit order, low to high. Views declared as props take their array\n * index; a view mounted as a child takes `Infinity`, so it lands after them\n * however React happens to order the mount effects.\n */\n order: number;\n /** The viewport node this view paints into. Its `resolvable` is what routes\n * input here. */\n layer: ViewportLayer<unknown>;\n /** `false` keeps input over the view on the canvas beneath it. */\n interactive: boolean;\n /** `false` leaves `layer` for a host to draw — a HUD window's interior — so\n * the surface does not paint it too. */\n paint: boolean;\n /** Everything about dispatching to this view except its id. */\n target: Omit<DispatcherViewTarget, 'id'>;\n /** Whether a scene layer reaches the screen in this view. For input that\n * reaches a view without a dispatch — hover — so it judges this view's\n * paint rather than the surface's. */\n layerIsPainted(layerId: string): boolean;\n /** The layers this view draws, in order — what a view nested in it paints\n * from. */\n drawnLayers(): readonly RenderLayer<unknown>[];\n /** Whether the view keeps its camera or its aim; the other is derived. */\n held: 'camera' | 'aim';\n /** What the view shows: the aim it holds, or its camera's. */\n aim(): ViewAim;\n /** `false` for an aim the view cannot read, or one with nowhere to go. */\n setAim(aim: ViewAim): boolean;\n}\n\n\n/** @internal */\nexport interface ViewRegistry extends ViewMarkerRegistry {\n /** Returns an unregister. */\n register(reg: ViewRegistration): () => void;\n /** Live registrations in paint order, each nested view after the view it\n * is nested in. */\n list(): readonly ViewRegistration[];\n /** The live registration with `id`, if any. */\n get(id: string): ViewRegistration | undefined;\n /** The innermost view painted under a canvas-local point, whether or not it\n * takes input, passing over `except` and the views nested in it. */\n viewAt(at: { x: number; y: number }, opts?: { except?: string }): ViewAt;\n /** What view `id` shows (`null`: the surface's root), or `null` while there is no such view. */\n aimOf(id: string | null): ViewAim | null;\n /** Point view `id` at `aim`; `false` when it cannot. */\n setAim(id: string | null, aim: ViewAim): boolean;\n /** Bumped whenever the list changes. Pair with {@link ViewRegistry.subscribe}\n * for `useSyncExternalStore`. */\n getVersion(): number;\n subscribe(fn: () => void): () => void;\n /** Which view a client point belongs to, sticky for a captured pointer.\n * One per surface: every caller that routes input — the dispatcher, pinch,\n * hover — must agree about where a point landed. */\n readonly resolver: ViewResolver;\n /** The hosting surface, or `null` before one attaches. */\n surface(): SurfaceHandle | null;\n /** Returns a detach, which leaves a handle attached since alone. */\n attachSurface(handle: SurfaceHandle): () => void;\n}\n\nconst ViewRegistryContext = createContext<ViewRegistry | null>(null);\n\n/** Mounts the registry for one surface. `<SceneCanvas>` mounts one; a view\n * declaring itself as a child must be inside it. */\nexport function ViewRegistryProvider({ children }: { children: ReactNode }) {\n const entriesRef = useRef(new Map<ViewRegistration, number>());\n const seqRef = useRef(0);\n const versionRef = useRef(0);\n const surfaceRef = useRef<SurfaceHandle | null>(null);\n const markersRef = useRef(new Map<() => ViewMarkerProps, RenderLayer<unknown>>());\n\n const registry = useMemo<ViewRegistry>(() => {\n const listeners = createEmitter();\n const changed = (): void => {\n versionRef.current++;\n listeners.emit();\n };\n const ordered = (): ViewRegistration[] => nestedOrder([...entriesRef.current.keys()].sort((a, b) => (\n a.order - b.order || entriesRef.current.get(a)! - entriesRef.current.get(b)!\n )));\n const get = (id: string): ViewRegistration | undefined => {\n for (const r of entriesRef.current.keys()) if (r.id === id) return r;\n return undefined;\n };\n /** Whether `r` is `id` or nested in it, however deep. */\n const within = (r: ViewRegistration, id: string): boolean => {\n const seen = new Set<ViewRegistration>();\n for (let at: ViewRegistration | undefined = r; at && !seen.has(at); at = at.parent === undefined ? undefined : get(at.parent)) {\n if (at.id === id) return true;\n seen.add(at);\n }\n return false;\n };\n const resolver = createViewResolver({\n views: () => {\n const surface = surfaceRef.current;\n const view = surface?.view() ?? IDENTITY_VIEW;\n const dims = surface?.dims() ?? UNMEASURED_DIMS;\n return ordered().filter((r) => r.interactive).map((r) => r.layer.resolvable(view, dims));\n },\n root: () => surfaceRef.current?.view() ?? IDENTITY_VIEW,\n toLocal: (clientX, clientY) => surfaceLocal(surfaceRef.current, clientX, clientY),\n occluded: (x, y) => surfaceRef.current?.claimsAbove(x, y) ?? false,\n });\n const registry: ViewRegistry = {\n resolver,\n register: (reg) => {\n entriesRef.current.set(reg, seqRef.current++);\n changed();\n return () => { entriesRef.current.delete(reg); changed(); };\n },\n list: ordered,\n get,\n viewAt: ({ x, y }, opts) => {\n const surface = surfaceRef.current;\n const view = surface?.view() ?? IDENTITY_VIEW;\n const dims = surface?.dims() ?? UNMEASURED_DIMS;\n const except = opts?.except;\n const list = ordered();\n for (let i = list.length - 1; i >= 0; i--) {\n const r = list[i]!;\n if (except !== undefined && within(r, except)) continue;\n const v = r.layer.resolvable(view, dims);\n if (viewContains(v, x, y)) return { id: v.id, view: v.view, rect: v.rect };\n }\n return { id: null, view, rect: { x: 0, y: 0, w: dims.width, h: dims.height } };\n },\n aimOf: (id) => {\n if (id !== null) return get(id)?.aim() ?? null;\n const surface = surfaceRef.current;\n return surface ? rectAim(null, viewportWorldRect(surface.view(), surface.dims())) : null;\n },\n setAim: (id, aim) => {\n if (id !== null) return get(id)?.setAim(aim) ?? false;\n const surface = surfaceRef.current;\n if (!isRectAim(aim) || !surface?.setView) return false;\n surface.setView(viewForAim(aim.extent, surface.dims(), 'exact'));\n return true;\n },\n ...createViewMarkerRegistry(markersRef.current, {\n host: { aimOf: (id) => registry.aimOf(id), setAim: (id, aim) => registry.setAim(id, aim) },\n surface: () => surfaceRef.current,\n resolve: (id, outer, dims) => get(id)?.layer.resolvable(outer, dims),\n changed,\n }),\n getVersion: () => versionRef.current,\n subscribe: listeners.subscribe,\n surface: () => surfaceRef.current,\n attachSurface: (handle) => {\n surfaceRef.current = handle;\n return () => { if (surfaceRef.current === handle) surfaceRef.current = null; };\n },\n };\n return registry;\n }, []);\n\n return <ViewRegistryContext.Provider value={registry}>{children}</ViewRegistryContext.Provider>;\n}\n\n/** The surface's view registry, or `null` outside one. */\nexport function useOptionalViewRegistry(): ViewRegistry | null {\n return useContext(ViewRegistryContext);\n}\n\n/** Each view followed by the views nested in it, in the order given. A view\n * whose parent is not registered keeps its place; one caught in a cycle\n * goes last. */\nfunction nestedOrder(sorted: readonly ViewRegistration[]): ViewRegistration[] {\n const ids = new Set(sorted.map((r) => r.id));\n const out: ViewRegistration[] = [];\n const placed = new Set<ViewRegistration>();\n const place = (r: ViewRegistration): void => {\n if (placed.has(r)) return;\n placed.add(r);\n out.push(r);\n for (const child of sorted) if (child.parent === r.id) place(child);\n };\n for (const r of sorted) if (r.parent === undefined || !ids.has(r.parent)) place(r);\n for (const r of sorted) place(r);\n return out;\n}\n\n/** The `Dims` a surface reports before it has measured itself. */\nexport const UNMEASURED_DIMS: Dims = { width: 0, height: 0 };\n\n/** The camera a view resolves against before its surface attaches. */\nexport const IDENTITY_VIEW: View = { x: 0, y: 0, scale: { x: 1, y: 1 } };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"viewRegistry.js","names":[],"sources":["../../src/canvas/viewRegistry.tsx"],"sourcesContent":["/**\n * The seam between a canvas surface and the views drawn on it.\n *\n * Traffic runs both ways: the surface attaches a handle onto its frame and its\n * layer stack, and each view registers what it contributes back — the viewport\n * node it paints into and the record the gesture dispatcher routes its events\n * to. Both sides are thunks, read at draw and dispatch time, so neither can\n * serve the other a frame that has already moved.\n */\nimport { createContext, useContext, useMemo, useRef, type ReactNode } from 'react';\nimport type { Dims, RenderLayer } from 'core/layers/render';\nimport type { LayerHit } from 'affordances/types';\nimport type { ChromeState } from 'core/selection/chromeState';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport type { View } from 'core/viewport/view';\nimport type { ViewportLayer } from 'domains/viewports/viewportLayer';\nimport type { DispatcherViewTarget } from '@weasel-js/routing/internal';\nimport { createViewResolver, viewContains, type ViewResolver } from 'domains/viewports/viewResolver';\nimport { createEmitter } from '@weasel-js/registry';\nimport type { ViewAt } from './canvasExtension';\nimport { isRectAim, rectAim, viewForAim, type ViewAim } from 'domains/viewports/aim';\nimport { viewportWorldRect } from 'core/viewport/viewportWorldRect';\nimport type { ViewMarkerProps } from 'domains/viewports/viewMarker';\nimport { createViewMarkerRegistry, type ViewMarkerRegistry } from './viewMarkers';\n\n/**\n * What a view needs from the surface hosting it.\n *\n * @internal Attached by the surface, read by `<CanvasView>`.\n */\nexport interface SurfaceHandle {\n /** A client point in the surface's own world — the conversion the surface\n * itself makes, its `clientToWorld` override included. */\n clientToWorld(clientX: number, clientY: number): [number, number];\n /** The outer camera. */\n view(): View;\n /** The canvas's CSS-pixel size. */\n dims(): Dims;\n /** The stack a view paints through its own camera, unless it narrows it. */\n layers(): readonly RenderLayer<unknown>[];\n requestRedraw(): void;\n /** The canvas's own view chrome — its selection, its overlay-aware bounds.\n * What a `<CanvasView>` answers for itself, answered for view zero. */\n chromeState(): ChromeState;\n /** Hit-test the externally registered layers at a world point, against the\n * frame and draw envelope of whichever view is asking. The public\n * `hitTestExtras` is this with the canvas's own frame and envelope. */\n hitTestExtras(\n worldX: number,\n worldY: number,\n view: View,\n dims: Dims,\n data: unknown,\n /** Consider only these layers — the ones the asking view paints. A layer\n * asked on a frame it was not drawn in answers for the wrong pixels. */\n only?: readonly RenderLayer<unknown>[],\n ): { layerId: string; hit: LayerHit } | null;\n /** Whether a registered layer claims a canvas-local point on the surface's\n * own frame. Registered layers paint over every view, so such a point is\n * theirs even inside a view's rect. */\n claimsAbove(x: number, y: number): boolean;\n /** The root camera's input write: clamped, forwarded when controlled, and ending a glide. */\n setView?(next: View): void;\n}\n\n/**\n * A client point in the surface's CSS pixels, from its top-left: the surface's\n * own world point put back through its camera, so a `clientToWorld` override\n * reaches every view declared on it.\n *\n * @internal\n */\nexport function surfaceLocal(\n surface: Pick<SurfaceHandle, 'clientToWorld' | 'view'> | null,\n clientX: number,\n clientY: number,\n): { x: number; y: number } {\n if (!surface) return { x: clientX, y: clientY };\n const [worldX, worldY] = surface.clientToWorld(clientX, clientY);\n const view = surface.view();\n return { x: (worldX - view.x) * view.scale.x, y: (worldY - view.y) * view.scale.y };\n}\n\n/**\n * What one view contributes to the surface hosting it.\n *\n * @internal Written by `<CanvasView>`, read by the surface. Consumers declare\n * a view, not a registration.\n */\nexport interface ViewRegistration {\n id: string;\n /** The view this one is nested in: listed, painted and hit after it, and\n * its `layer` measures itself from that view's rect and camera. */\n parent?: string;\n /**\n * Paint and hit order, low to high. Views declared as props take their array\n * index; a view mounted as a child takes `Infinity`, so it lands after them\n * however React happens to order the mount effects.\n */\n order: number;\n /** The viewport node this view paints into. Its `resolvable` is what routes\n * input here. */\n layer: ViewportLayer<unknown>;\n /** `false` keeps input over the view on the canvas beneath it. */\n interactive: boolean;\n /** `false` leaves `layer` for a host to draw — a HUD window's interior — so\n * the surface does not paint it too. */\n paint: boolean;\n /** Everything about dispatching to this view except its id. */\n target: Omit<DispatcherViewTarget, 'id'>;\n /** Whether a scene layer reaches the screen in this view. For input that\n * reaches a view without a dispatch — hover — so it judges this view's\n * paint rather than the surface's. */\n layerIsPainted(layerId: string): boolean;\n /** The layers this view draws, in order — what a view nested in it paints\n * from. */\n drawnLayers(): readonly RenderLayer<unknown>[];\n /** The selection the view owns, or the one the view it follows owns;\n * `undefined` while it shares the surface's. */\n selection(): SelectionApi | undefined;\n /** Whether the view keeps its camera or its aim; the other is derived. */\n held: 'camera' | 'aim';\n /** What the view shows: the aim it holds, or its camera's. */\n aim(): ViewAim;\n /** `false` for an aim the view cannot read, or one with nowhere to go. */\n setAim(aim: ViewAim): boolean;\n}\n\n\n/** @internal */\nexport interface ViewRegistry extends ViewMarkerRegistry {\n /** Returns an unregister. */\n register(reg: ViewRegistration): () => void;\n /** Live registrations in paint order, each nested view after the view it\n * is nested in. */\n list(): readonly ViewRegistration[];\n /** The live registration with `id`, if any. */\n get(id: string): ViewRegistration | undefined;\n /** The innermost view painted under a canvas-local point, whether or not it\n * takes input, passing over `except` and the views nested in it. */\n viewAt(at: { x: number; y: number }, opts?: { except?: string }): ViewAt;\n /** What view `id` shows (`null`: the surface's root), or `null` while there is no such view. */\n aimOf(id: string | null): ViewAim | null;\n /** Point view `id` at `aim`; `false` when it cannot. */\n setAim(id: string | null, aim: ViewAim): boolean;\n /** Bumped whenever the list changes. Pair with {@link ViewRegistry.subscribe}\n * for `useSyncExternalStore`. */\n getVersion(): number;\n subscribe(fn: () => void): () => void;\n /** Which view a client point belongs to, sticky for a captured pointer.\n * One per surface: every caller that routes input — the dispatcher, pinch,\n * hover — must agree about where a point landed. */\n readonly resolver: ViewResolver;\n /** The hosting surface, or `null` before one attaches. */\n surface(): SurfaceHandle | null;\n /** Returns a detach, which leaves a handle attached since alone. */\n attachSurface(handle: SurfaceHandle): () => void;\n}\n\nconst ViewRegistryContext = createContext<ViewRegistry | null>(null);\n\n/** Mounts the registry for one surface. `<SceneCanvas>` mounts one; a view\n * declaring itself as a child must be inside it. */\nexport function ViewRegistryProvider({ children }: { children: ReactNode }) {\n const entriesRef = useRef(new Map<ViewRegistration, number>());\n const seqRef = useRef(0);\n const versionRef = useRef(0);\n const surfaceRef = useRef<SurfaceHandle | null>(null);\n const markersRef = useRef(new Map<() => ViewMarkerProps, RenderLayer<unknown>>());\n\n const registry = useMemo<ViewRegistry>(() => {\n const listeners = createEmitter();\n const changed = (): void => {\n versionRef.current++;\n listeners.emit();\n };\n const ordered = (): ViewRegistration[] => nestedOrder([...entriesRef.current.keys()].sort((a, b) => (\n a.order - b.order || entriesRef.current.get(a)! - entriesRef.current.get(b)!\n )));\n const get = (id: string): ViewRegistration | undefined => {\n for (const r of entriesRef.current.keys()) if (r.id === id) return r;\n return undefined;\n };\n /** Whether `r` is `id` or nested in it, however deep. */\n const within = (r: ViewRegistration, id: string): boolean => {\n const seen = new Set<ViewRegistration>();\n for (let at: ViewRegistration | undefined = r; at && !seen.has(at); at = at.parent === undefined ? undefined : get(at.parent)) {\n if (at.id === id) return true;\n seen.add(at);\n }\n return false;\n };\n const resolver = createViewResolver({\n views: () => {\n const surface = surfaceRef.current;\n const view = surface?.view() ?? IDENTITY_VIEW;\n const dims = surface?.dims() ?? UNMEASURED_DIMS;\n return ordered().filter((r) => r.interactive).map((r) => r.layer.resolvable(view, dims));\n },\n root: () => surfaceRef.current?.view() ?? IDENTITY_VIEW,\n toLocal: (clientX, clientY) => surfaceLocal(surfaceRef.current, clientX, clientY),\n occluded: (x, y) => surfaceRef.current?.claimsAbove(x, y) ?? false,\n });\n const registry: ViewRegistry = {\n resolver,\n register: (reg) => {\n entriesRef.current.set(reg, seqRef.current++);\n changed();\n return () => { entriesRef.current.delete(reg); changed(); };\n },\n list: ordered,\n get,\n viewAt: ({ x, y }, opts) => {\n const surface = surfaceRef.current;\n const view = surface?.view() ?? IDENTITY_VIEW;\n const dims = surface?.dims() ?? UNMEASURED_DIMS;\n const except = opts?.except;\n const list = ordered();\n for (let i = list.length - 1; i >= 0; i--) {\n const r = list[i]!;\n if (except !== undefined && within(r, except)) continue;\n const v = r.layer.resolvable(view, dims);\n if (viewContains(v, x, y)) return { id: v.id, view: v.view, rect: v.rect };\n }\n return { id: null, view, rect: { x: 0, y: 0, w: dims.width, h: dims.height } };\n },\n aimOf: (id) => {\n if (id !== null) return get(id)?.aim() ?? null;\n const surface = surfaceRef.current;\n return surface ? rectAim(null, viewportWorldRect(surface.view(), surface.dims())) : null;\n },\n setAim: (id, aim) => {\n if (id !== null) return get(id)?.setAim(aim) ?? false;\n const surface = surfaceRef.current;\n if (!isRectAim(aim) || !surface?.setView) return false;\n surface.setView(viewForAim(aim.extent, surface.dims(), 'exact'));\n return true;\n },\n ...createViewMarkerRegistry(markersRef.current, {\n host: { aimOf: (id) => registry.aimOf(id), setAim: (id, aim) => registry.setAim(id, aim) },\n surface: () => surfaceRef.current,\n resolve: (id, outer, dims) => get(id)?.layer.resolvable(outer, dims),\n changed,\n }),\n getVersion: () => versionRef.current,\n subscribe: listeners.subscribe,\n surface: () => surfaceRef.current,\n attachSurface: (handle) => {\n surfaceRef.current = handle;\n return () => { if (surfaceRef.current === handle) surfaceRef.current = null; };\n },\n };\n return registry;\n }, []);\n\n return <ViewRegistryContext.Provider value={registry}>{children}</ViewRegistryContext.Provider>;\n}\n\n/** The surface's view registry, or `null` outside one. */\nexport function useOptionalViewRegistry(): ViewRegistry | null {\n return useContext(ViewRegistryContext);\n}\n\n/** Each view followed by the views nested in it, in the order given. A view\n * whose parent is not registered keeps its place; one caught in a cycle\n * goes last. */\nfunction nestedOrder(sorted: readonly ViewRegistration[]): ViewRegistration[] {\n const ids = new Set(sorted.map((r) => r.id));\n const out: ViewRegistration[] = [];\n const placed = new Set<ViewRegistration>();\n const place = (r: ViewRegistration): void => {\n if (placed.has(r)) return;\n placed.add(r);\n out.push(r);\n for (const child of sorted) if (child.parent === r.id) place(child);\n };\n for (const r of sorted) if (r.parent === undefined || !ids.has(r.parent)) place(r);\n for (const r of sorted) place(r);\n return out;\n}\n\n/** The `Dims` a surface reports before it has measured itself. */\nexport const UNMEASURED_DIMS: Dims = { width: 0, height: 0 };\n\n/** The camera a view resolves against before its surface attaches. */\nexport const IDENTITY_VIEW: View = { x: 0, y: 0, scale: { x: 1, y: 1 } };\n"],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { sameView } from "../core/viewport/view.js";
|
|
2
|
+
|
|
3
|
+
//#region src/canvas/viewSnap.ts
|
|
4
|
+
/** A move within this of a whole device pixel is one: the renderer's own slack. */
|
|
5
|
+
var SLACK = 1e-4;
|
|
6
|
+
/**
|
|
7
|
+
* The view a canvas draws each frame under. While the view moves, its
|
|
8
|
+
* translation is rounded to whole device pixels from where the view last
|
|
9
|
+
* held, so a retained layer's surface moves whole pixels and is composited
|
|
10
|
+
* rather than drawn; once the view holds for a frame, it draws exactly.
|
|
11
|
+
* Hit-testing and every other reader of the view keep the exact one.
|
|
12
|
+
*
|
|
13
|
+
* The rounding is from where the view last held rather than from zero
|
|
14
|
+
* because that is where retained surfaces are drawn.
|
|
15
|
+
*/
|
|
16
|
+
var ViewSnap = class {
|
|
17
|
+
last;
|
|
18
|
+
/** The translation, CSS pixels, of the frame last drawn holding. */
|
|
19
|
+
grid;
|
|
20
|
+
snapped = false;
|
|
21
|
+
moved = false;
|
|
22
|
+
/** The view to draw `view` under, at `scale` device pixels to the CSS
|
|
23
|
+
* pixel. `snap` false draws every view exactly. */
|
|
24
|
+
draw(view, scale, snap) {
|
|
25
|
+
const moving = this.last !== void 0 && !sameView(this.last, view);
|
|
26
|
+
this.last = view;
|
|
27
|
+
const t = translationOf(view);
|
|
28
|
+
const grid = this.grid;
|
|
29
|
+
if (!snap || !moving || grid === void 0) {
|
|
30
|
+
this.moved = snap && grid !== void 0 && !(whole((t[0] - grid[0]) * scale) && whole((t[1] - grid[1]) * scale));
|
|
31
|
+
this.grid = t;
|
|
32
|
+
this.snapped = false;
|
|
33
|
+
return view;
|
|
34
|
+
}
|
|
35
|
+
const x = grid[0] + Math.round((t[0] - grid[0]) * scale) / scale;
|
|
36
|
+
const y = grid[1] + Math.round((t[1] - grid[1]) * scale) / scale;
|
|
37
|
+
this.moved = false;
|
|
38
|
+
this.snapped = x !== t[0] || y !== t[1];
|
|
39
|
+
if (!this.snapped) return view;
|
|
40
|
+
return {
|
|
41
|
+
x: -x / view.scale.x,
|
|
42
|
+
y: -y / view.scale.y,
|
|
43
|
+
scale: view.scale
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Whether the frame just drawn owes the canvas another: a snapped one, so
|
|
48
|
+
* the view is drawn exactly once it holds; and the frame it holds on, when
|
|
49
|
+
* that drew a retained layer straight through for being off the pixel grid
|
|
50
|
+
* its surface was drawn on, so the next frame draws the surface again on
|
|
51
|
+
* the grid the next move rounds to. `declined` is the renderer's count of
|
|
52
|
+
* retained layers it drew straight through.
|
|
53
|
+
*/
|
|
54
|
+
owesFrame(declined) {
|
|
55
|
+
return this.snapped || this.moved && declined > 0;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
function translationOf(view) {
|
|
59
|
+
return [-view.x * view.scale.x, -view.y * view.scale.y];
|
|
60
|
+
}
|
|
61
|
+
function whole(n) {
|
|
62
|
+
return Math.abs(n - Math.round(n)) <= SLACK;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
//#endregion
|
|
66
|
+
export { ViewSnap };
|
|
67
|
+
//# sourceMappingURL=viewSnap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewSnap.js","names":[],"sources":["../../src/canvas/viewSnap.ts"],"sourcesContent":["import { sameView, type View } from 'core/viewport/view';\n\n/** A move within this of a whole device pixel is one: the renderer's own slack. */\nconst SLACK = 1e-4;\n\n/**\n * The view a canvas draws each frame under. While the view moves, its\n * translation is rounded to whole device pixels from where the view last\n * held, so a retained layer's surface moves whole pixels and is composited\n * rather than drawn; once the view holds for a frame, it draws exactly.\n * Hit-testing and every other reader of the view keep the exact one.\n *\n * The rounding is from where the view last held rather than from zero\n * because that is where retained surfaces are drawn.\n */\nexport class ViewSnap {\n private last: View | undefined;\n /** The translation, CSS pixels, of the frame last drawn holding. */\n private grid: readonly [number, number] | undefined;\n private snapped = false;\n private moved = false;\n\n /** The view to draw `view` under, at `scale` device pixels to the CSS\n * pixel. `snap` false draws every view exactly. */\n draw(view: View, scale: number, snap: boolean): View {\n const moving = this.last !== undefined && !sameView(this.last, view);\n this.last = view;\n const t = translationOf(view);\n const grid = this.grid;\n if (!snap || !moving || grid === undefined) {\n this.moved = snap && grid !== undefined && !(whole((t[0] - grid[0]) * scale) && whole((t[1] - grid[1]) * scale));\n this.grid = t;\n this.snapped = false;\n return view;\n }\n const x = grid[0] + Math.round((t[0] - grid[0]) * scale) / scale;\n const y = grid[1] + Math.round((t[1] - grid[1]) * scale) / scale;\n this.moved = false;\n this.snapped = x !== t[0] || y !== t[1];\n if (!this.snapped) return view;\n return { x: -x / view.scale.x, y: -y / view.scale.y, scale: view.scale };\n }\n\n /**\n * Whether the frame just drawn owes the canvas another: a snapped one, so\n * the view is drawn exactly once it holds; and the frame it holds on, when\n * that drew a retained layer straight through for being off the pixel grid\n * its surface was drawn on, so the next frame draws the surface again on\n * the grid the next move rounds to. `declined` is the renderer's count of\n * retained layers it drew straight through.\n */\n owesFrame(declined: number): boolean {\n return this.snapped || (this.moved && declined > 0);\n }\n}\n\nfunction translationOf(view: View): readonly [number, number] {\n return [-view.x * view.scale.x, -view.y * view.scale.y];\n}\n\nfunction whole(n: number): boolean {\n return Math.abs(n - Math.round(n)) <= SLACK;\n}\n"],"mappings":";;;;AAGA,IAAM,QAAQ;;;;;;;;;;;AAYd,IAAa,WAAb,MAAsB;CACpB;;CAEA;CACA,UAAkB;CAClB,QAAgB;;;CAIhB,KAAK,MAAY,OAAe,MAAqB;EACnD,MAAM,SAAS,KAAK,SAAS,UAAa,CAAC,SAAS,KAAK,MAAM,IAAI;EACnE,KAAK,OAAO;EACZ,MAAM,IAAI,cAAc,IAAI;EAC5B,MAAM,OAAO,KAAK;EAClB,IAAI,CAAC,QAAQ,CAAC,UAAU,SAAS,QAAW;GAC1C,KAAK,QAAQ,QAAQ,SAAS,UAAa,EAAE,OAAO,EAAE,KAAK,KAAK,MAAM,KAAK,KAAK,OAAO,EAAE,KAAK,KAAK,MAAM,KAAK;GAC9G,KAAK,OAAO;GACZ,KAAK,UAAU;GACf,OAAO;EACT;EACA,MAAM,IAAI,KAAK,KAAK,KAAK,OAAO,EAAE,KAAK,KAAK,MAAM,KAAK,IAAI;EAC3D,MAAM,IAAI,KAAK,KAAK,KAAK,OAAO,EAAE,KAAK,KAAK,MAAM,KAAK,IAAI;EAC3D,KAAK,QAAQ;EACb,KAAK,UAAU,MAAM,EAAE,MAAM,MAAM,EAAE;EACrC,IAAI,CAAC,KAAK,SAAS,OAAO;EAC1B,OAAO;GAAE,GAAG,CAAC,IAAI,KAAK,MAAM;GAAG,GAAG,CAAC,IAAI,KAAK,MAAM;GAAG,OAAO,KAAK;EAAM;CACzE;;;;;;;;;CAUA,UAAU,UAA2B;EACnC,OAAO,KAAK,WAAY,KAAK,SAAS,WAAW;CACnD;AACF;AAEA,SAAS,cAAc,MAAuC;CAC5D,OAAO,CAAC,CAAC,KAAK,IAAI,KAAK,MAAM,GAAG,CAAC,KAAK,IAAI,KAAK,MAAM,CAAC;AACxD;AAEA,SAAS,MAAM,GAAoB;CACjC,OAAO,KAAK,IAAI,IAAI,KAAK,MAAM,CAAC,CAAC,KAAK;AACxC"}
|
package/dist/clipboard.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { NodeId } from '@weasel-js/routing';
|
|
2
|
-
import { P as PasteOmission, C as ClipboardSnapshot, I as InsertAdapter } from './types-
|
|
3
|
-
import './types-
|
|
1
|
+
import { NodeId, WorldPoint } from '@weasel-js/routing';
|
|
2
|
+
import { P as PasteOmission, C as ClipboardSnapshot, I as InsertAdapter } from './types-VCtfchp-.js';
|
|
3
|
+
import './types-A_sNJYRd.js';
|
|
4
4
|
import '@weasel-js/geom';
|
|
5
5
|
import '@weasel-js/history';
|
|
6
|
-
import './poseDescriptor-
|
|
6
|
+
import './poseDescriptor-CvSxVhCd.js';
|
|
7
7
|
import '@weasel-js/animator';
|
|
8
8
|
|
|
9
9
|
type Replacer$1 = (key: string, value: unknown) => unknown;
|
|
@@ -24,10 +24,7 @@ interface UseClipboardOpsOptions {
|
|
|
24
24
|
* as `ctx.dropPoint`; adapters typically use it as the cluster origin
|
|
25
25
|
* (ignoring `offset`). When null/undefined, the hook falls back to the
|
|
26
26
|
* existing cascade-offset behavior. */
|
|
27
|
-
getDropPoint?: () =>
|
|
28
|
-
worldX: number;
|
|
29
|
-
worldY: number;
|
|
30
|
-
} | null;
|
|
27
|
+
getDropPoint?: () => WorldPoint | null;
|
|
31
28
|
/** Produce the OS-clipboard flavor map for a copied snapshot. Keys are MIME
|
|
32
29
|
* types, values the serialized payload. The kit default emits
|
|
33
30
|
* `application/x-weasel-clipboard+json` plus `text/plain` carrying the
|
|
@@ -48,10 +45,7 @@ type ClipboardFlavors = Record<string, string | Promise<string>>;
|
|
|
48
45
|
interface UseClipboardOpsReturn {
|
|
49
46
|
copy(): void;
|
|
50
47
|
/** Paste at `at` when given; otherwise at the drop point, else the cascade offset. */
|
|
51
|
-
paste(at?:
|
|
52
|
-
worldX: number;
|
|
53
|
-
worldY: number;
|
|
54
|
-
}): void;
|
|
48
|
+
paste(at?: WorldPoint): void;
|
|
55
49
|
isEmpty(): boolean;
|
|
56
50
|
}
|
|
57
51
|
/** In-memory copy/paste of selections via `InsertAdapter.snapshotSelection` / `commitPaste`. */
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { a as PlaneMap } from './types-
|
|
1
|
+
import { a as PlaneMap } from './types-A_sNJYRd.js';
|
|
2
2
|
import { Op } from '@weasel-js/history';
|
|
3
|
-
import { S as SnapTarget, M as MoveAdapter } from './types-
|
|
3
|
+
import { S as SnapTarget, M as MoveAdapter } from './types-VCtfchp-.js';
|
|
4
4
|
import { FramedBox, View } from '@weasel-js/geom';
|
|
5
5
|
import { KitSettingsStore } from '@weasel-js/react';
|
|
6
|
-
import { ModifierState, ResizeAnchor } from '@weasel-js/routing';
|
|
6
|
+
import { ModifierState, ResizeAnchor, OngoingOverlay } from '@weasel-js/routing';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* What a behavior needs to take a pose between the frame a node stores it in
|
|
10
10
|
* and world. A node under a container whose pose is a frame stores its pose
|
|
11
11
|
* in that frame, so a stored pose and a world pose are different values
|
|
12
|
-
* there; under
|
|
13
|
-
* an identity.
|
|
12
|
+
* there; under `IDENTITY_POSE_COMPOSITION` they are the same and every
|
|
13
|
+
* method is an identity.
|
|
14
14
|
*/
|
|
15
15
|
interface GestureFrames<TPose> {
|
|
16
16
|
/** `id`'s pose in world, as the scene shows it now: the gesture's preview
|
|
@@ -20,6 +20,9 @@ interface GestureFrames<TPose> {
|
|
|
20
20
|
toWorld(id: string, pose: TPose): TPose;
|
|
21
21
|
/** `worldPose` as `id` stores it: what a pose op or a preview takes. */
|
|
22
22
|
toLocal(id: string, worldPose: TPose): TPose;
|
|
23
|
+
/** `worldPose` as a child of `parentId` stores it, `null` for the top of
|
|
24
|
+
* the tree: what a node reparented there is posed with. */
|
|
25
|
+
toLocalUnder(parentId: string | null, worldPose: TPose): TPose;
|
|
23
26
|
/** How the world the gesture edits in maps into the world `layer`'s nodes
|
|
24
27
|
* are stored in, read now. Null when they are the same world. */
|
|
25
28
|
planeOf(layer: string): PlaneMap | null;
|
|
@@ -172,6 +175,8 @@ interface BehaviorResult<TPose> {
|
|
|
172
175
|
* ghost, added to those of the other behaviors. */
|
|
173
176
|
opaque?: Iterable<string>;
|
|
174
177
|
snap?: SnapTarget<TPose> | null;
|
|
178
|
+
/** Chrome to paint beside the drag this frame, added to the other behaviors'. */
|
|
179
|
+
overlays?: readonly OngoingOverlay[];
|
|
175
180
|
}
|
|
176
181
|
/** What a move behavior's `onEnd` is told. */
|
|
177
182
|
interface MoveEnd extends BehaviorEnd {
|
package/dist/clone.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { C as CloneBehavior, d as CloneBehaviorResult } from './clone-
|
|
2
|
-
import './types-
|
|
1
|
+
export { C as CloneBehavior, d as CloneBehaviorResult } from './clone-Bz4iqGfE.js';
|
|
2
|
+
import './types-A_sNJYRd.js';
|
|
3
3
|
import '@weasel-js/geom';
|
|
4
4
|
import '@weasel-js/history';
|
|
5
|
-
import './types-
|
|
6
|
-
import './poseDescriptor-
|
|
5
|
+
import './types-VCtfchp-.js';
|
|
6
|
+
import './poseDescriptor-CvSxVhCd.js';
|
|
7
7
|
import '@weasel-js/animator';
|
|
8
|
-
import '@weasel-js/react';
|
|
9
8
|
import '@weasel-js/routing';
|
|
9
|
+
import '@weasel-js/react';
|