@weasel-js/core 1.6.1 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1006 -0
- package/README.md +28 -9
- package/dist/WeaselProvider.js +15 -0
- package/dist/WeaselProvider.js.map +1 -0
- package/dist/affordances/composeAffordanceLayer.js +224 -0
- package/dist/affordances/composeAffordanceLayer.js.map +1 -0
- package/dist/affordances/cornerResize.js +69 -0
- package/dist/affordances/cornerResize.js.map +1 -0
- package/dist/affordances/hitAffordanceRegions.js +138 -0
- package/dist/affordances/hitAffordanceRegions.js.map +1 -0
- package/dist/affordances/pathAnchors.js +66 -0
- package/dist/affordances/pathAnchors.js.map +1 -0
- package/dist/affordances/rotationHandle.js +103 -0
- package/dist/affordances/rotationHandle.js.map +1 -0
- package/dist/animation/behaviors/momentum.js +118 -0
- package/dist/animation/behaviors/momentum.js.map +1 -0
- package/dist/animation/colorHelpers.js +135 -0
- package/dist/animation/colorHelpers.js.map +1 -0
- package/dist/animation/colorRegistry.js +37 -0
- package/dist/animation/colorRegistry.js.map +1 -0
- package/dist/animation/index.js +20 -0
- package/dist/animation/loop.js +62 -0
- package/dist/animation/loop.js.map +1 -0
- package/dist/animation/observe.js +23 -0
- package/dist/animation/observe.js.map +1 -0
- package/dist/animation/poseHelpers.js +50 -0
- package/dist/animation/poseHelpers.js.map +1 -0
- package/dist/animation/reflow.js +121 -0
- package/dist/animation/reflow.js.map +1 -0
- package/dist/animation/rig/bindRig.js +74 -0
- package/dist/animation/rig/bindRig.js.map +1 -0
- package/dist/animation/rig/blendPoses.js +43 -0
- package/dist/animation/rig/blendPoses.js.map +1 -0
- package/dist/animation/rig/mirrorPose.js +19 -0
- package/dist/animation/rig/mirrorPose.js.map +1 -0
- package/dist/animation/rig/resolveSkeleton.js +33 -0
- package/dist/animation/rig/resolveSkeleton.js.map +1 -0
- package/dist/animation/rig/solveIk.js +103 -0
- package/dist/animation/rig/solveIk.js.map +1 -0
- package/dist/animation/rig/types.js +12 -0
- package/dist/animation/rig/types.js.map +1 -0
- package/dist/animation/rig/useRig.js +23 -0
- package/dist/animation/rig/useRig.js.map +1 -0
- package/dist/animation/slew.js +27 -0
- package/dist/animation/slew.js.map +1 -0
- package/dist/animation/stagger.js +138 -0
- package/dist/animation/stagger.js.map +1 -0
- package/dist/animation/timeline/booking.js +106 -0
- package/dist/animation/timeline/booking.js.map +1 -0
- package/dist/animation/timeline/createTimeline.js +116 -0
- package/dist/animation/timeline/createTimeline.js.map +1 -0
- package/dist/animation/timeline/sampleTrack.js +29 -0
- package/dist/animation/timeline/sampleTrack.js.map +1 -0
- package/dist/animation/useAnimator.js +329 -0
- package/dist/animation/useAnimator.js.map +1 -0
- package/dist/animation/wrappers/animateLifecycle.js +40 -0
- package/dist/animation/wrappers/animateLifecycle.js.map +1 -0
- package/dist/animation/wrappers/animateOnSetPose.js +44 -0
- package/dist/animation/wrappers/animateOnSetPose.js.map +1 -0
- package/dist/{autoPoseDescriptor-_XOyF7t4.d.ts → autoPoseDescriptor-BT_vp9FO.d.ts} +2 -2
- package/dist/{builtins-HWyuLzE-.d.ts → builtins-BSUfH8nU.d.ts} +1301 -508
- package/dist/canvas/Canvas.js +608 -0
- package/dist/canvas/Canvas.js.map +1 -0
- package/dist/canvas/CanvasView.js +255 -0
- package/dist/canvas/CanvasView.js.map +1 -0
- package/dist/canvas/CursorCoordsHud.js +75 -0
- package/dist/canvas/CursorCoordsHud.js.map +1 -0
- package/dist/canvas/DrawCanvas.js +67 -0
- package/dist/canvas/DrawCanvas.js.map +1 -0
- package/dist/canvas/MinimapCanvas.js +139 -0
- package/dist/canvas/MinimapCanvas.js.map +1 -0
- package/dist/canvas/ModalityHud.js +66 -0
- package/dist/canvas/ModalityHud.js.map +1 -0
- package/dist/canvas/NodeShape.js +391 -0
- package/dist/canvas/NodeShape.js.map +1 -0
- package/dist/canvas/PickHud.js +93 -0
- package/dist/canvas/PickHud.js.map +1 -0
- package/dist/canvas/SceneCanvas/ActionsProviderIfRoot.js +10 -0
- package/dist/canvas/SceneCanvas/ActionsProviderIfRoot.js.map +1 -0
- package/dist/canvas/SceneCanvas/DepRegistryProviderIfRoot.js +10 -0
- package/dist/canvas/SceneCanvas/DepRegistryProviderIfRoot.js.map +1 -0
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +51 -0
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js.map +1 -0
- package/dist/canvas/SceneCanvas/contributionFrameHooks.js +42 -0
- package/dist/canvas/SceneCanvas/contributionFrameHooks.js.map +1 -0
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js +549 -0
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -0
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js +26 -0
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -0
- package/dist/canvas/SceneCanvas/dispatcherGestureBounds.js +69 -0
- package/dist/canvas/SceneCanvas/dispatcherGestureBounds.js.map +1 -0
- package/dist/canvas/SceneCanvas/features.js +97 -0
- package/dist/canvas/SceneCanvas/features.js.map +1 -0
- package/dist/canvas/SceneCanvas/poseGeometry.js +46 -0
- package/dist/canvas/SceneCanvas/poseGeometry.js.map +1 -0
- package/dist/canvas/SceneCanvas/useActionsPropResolver.js +48 -0
- package/dist/canvas/SceneCanvas/useActionsPropResolver.js.map +1 -0
- package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js +70 -0
- package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js.map +1 -0
- package/dist/canvas/SceneCanvas/useContributionRoles.js +75 -0
- package/dist/canvas/SceneCanvas/useContributionRoles.js.map +1 -0
- package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js +172 -0
- package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js.map +1 -0
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js +69 -0
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js.map +1 -0
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js +127 -0
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -0
- package/dist/canvas/SceneCanvas/useViewportActions.js +30 -0
- package/dist/canvas/SceneCanvas/useViewportActions.js.map +1 -0
- package/dist/canvas/SceneCanvas.js +992 -0
- package/dist/canvas/SceneCanvas.js.map +1 -0
- package/dist/canvas/SceneViewCanvas.js +54 -0
- package/dist/canvas/SceneViewCanvas.js.map +1 -0
- package/dist/canvas/accentColor.js +9 -0
- package/dist/canvas/accentColor.js.map +1 -0
- package/dist/canvas/affordanceAt.js +63 -0
- package/dist/canvas/affordanceAt.js.map +1 -0
- package/dist/canvas/buildSceneTree.js +65 -0
- package/dist/canvas/buildSceneTree.js.map +1 -0
- package/dist/canvas/canvasRenderer.js +89 -0
- package/dist/canvas/canvasRenderer.js.map +1 -0
- package/dist/canvas/colorOverrides.js +16 -0
- package/dist/canvas/colorOverrides.js.map +1 -0
- package/dist/canvas/defaultDrawOne.js +43 -0
- package/dist/canvas/defaultDrawOne.js.map +1 -0
- package/dist/canvas/deps/areaSelect.js +19 -0
- package/dist/canvas/deps/areaSelect.js.map +1 -0
- package/dist/canvas/deps/debug.js +9 -0
- package/dist/canvas/deps/debug.js.map +1 -0
- package/dist/canvas/deps/dispatcher.js +11 -0
- package/dist/canvas/deps/dispatcher.js.map +1 -0
- package/dist/canvas/deps/editAnchors.js +101 -0
- package/dist/canvas/deps/editAnchors.js.map +1 -0
- package/dist/canvas/deps/geometryProjection.js +11 -0
- package/dist/canvas/deps/geometryProjection.js.map +1 -0
- package/dist/canvas/deps/hitTestArea.js +51 -0
- package/dist/canvas/deps/hitTestArea.js.map +1 -0
- package/dist/canvas/deps/ingestion.js +31 -0
- package/dist/canvas/deps/ingestion.js.map +1 -0
- package/dist/canvas/deps/insert.js +116 -0
- package/dist/canvas/deps/insert.js.map +1 -0
- package/dist/canvas/deps/lassoSelect.js +20 -0
- package/dist/canvas/deps/lassoSelect.js.map +1 -0
- package/dist/canvas/deps/layout.js +34 -0
- package/dist/canvas/deps/layout.js.map +1 -0
- package/dist/canvas/deps/nodeAtPoint.js +19 -0
- package/dist/canvas/deps/nodeAtPoint.js.map +1 -0
- package/dist/canvas/deps/poseComposition.js +11 -0
- package/dist/canvas/deps/poseComposition.js.map +1 -0
- package/dist/canvas/deps/poseDescriptor.js +12 -0
- package/dist/canvas/deps/poseDescriptor.js.map +1 -0
- package/dist/canvas/deps/resizePolicy.js +35 -0
- package/dist/canvas/deps/resizePolicy.js.map +1 -0
- package/dist/canvas/deps/slice.js +99 -0
- package/dist/canvas/deps/slice.js.map +1 -0
- package/dist/canvas/deps/snap.js +11 -0
- package/dist/canvas/deps/snap.js.map +1 -0
- package/dist/canvas/deps/textEdit.js +21 -0
- package/dist/canvas/deps/textEdit.js.map +1 -0
- package/dist/canvas/deps/view.js +43 -0
- package/dist/canvas/deps/view.js.map +1 -0
- package/dist/canvas/derivedPath.js +47 -0
- package/dist/canvas/derivedPath.js.map +1 -0
- package/dist/canvas/drawEnvelope.js +22 -0
- package/dist/canvas/drawEnvelope.js.map +1 -0
- package/dist/canvas/getNodeAtPoint.js +18 -0
- package/dist/canvas/getNodeAtPoint.js.map +1 -0
- package/dist/canvas/hostAnchor.js +29 -0
- package/dist/canvas/hostAnchor.js.map +1 -0
- package/dist/canvas/hud.module.js +18 -0
- package/dist/canvas/hud.module.js.map +1 -0
- package/dist/canvas/insertPreviewExtent.js +103 -0
- package/dist/canvas/insertPreviewExtent.js.map +1 -0
- package/dist/canvas/kitRequirements.js +177 -0
- package/dist/canvas/kitRequirements.js.map +1 -0
- package/dist/canvas/layerOrder.js +66 -0
- package/dist/canvas/layerOrder.js.map +1 -0
- package/dist/canvas/layerSlots.js +14 -0
- package/dist/canvas/layerSlots.js.map +1 -0
- package/dist/canvas/minimapMath.js +80 -0
- package/dist/canvas/minimapMath.js.map +1 -0
- package/dist/canvas/mountedCanvases.js +20 -0
- package/dist/canvas/mountedCanvases.js.map +1 -0
- package/dist/canvas/overlayRoleStrokes.js +17 -0
- package/dist/canvas/overlayRoleStrokes.js.map +1 -0
- package/dist/canvas/paintCull.js +20 -0
- package/dist/canvas/paintCull.js.map +1 -0
- package/dist/canvas/pickWalk.js +158 -0
- package/dist/canvas/pickWalk.js.map +1 -0
- package/dist/canvas/planeClips.js +30 -0
- package/dist/canvas/planeClips.js.map +1 -0
- package/dist/canvas/poseRotation.js +35 -0
- package/dist/canvas/poseRotation.js.map +1 -0
- package/dist/canvas/rasterToPng.js +21 -0
- package/dist/canvas/rasterToPng.js.map +1 -0
- package/dist/canvas/renderDebugSnapshot.js +32 -0
- package/dist/canvas/renderDebugSnapshot.js.map +1 -0
- package/dist/canvas/renderNeeds.js +25 -0
- package/dist/canvas/renderNeeds.js.map +1 -0
- package/dist/canvas/renderSceneToPixels.js +143 -0
- package/dist/canvas/renderSceneToPixels.js.map +1 -0
- package/dist/canvas/sceneAdapter.js +270 -0
- package/dist/canvas/sceneAdapter.js.map +1 -0
- package/dist/canvas/sceneLayerPaint.js +37 -0
- package/dist/canvas/sceneLayerPaint.js.map +1 -0
- package/dist/canvas/sceneSlotWiring.js +20 -0
- package/dist/canvas/sceneSlotWiring.js.map +1 -0
- package/dist/canvas/sceneViewRender.js +72 -0
- package/dist/canvas/sceneViewRender.js.map +1 -0
- package/dist/canvas/slopsDebugLayer.js +61 -0
- package/dist/canvas/slopsDebugLayer.js.map +1 -0
- package/dist/canvas/surfaceContribution.js +15 -0
- package/dist/canvas/surfaceContribution.js.map +1 -0
- package/dist/canvas/toolPreview.js +39 -0
- package/dist/canvas/toolPreview.js.map +1 -0
- package/dist/canvas/useCanvasRenderer.js +11 -0
- package/dist/canvas/useCanvasRenderer.js.map +1 -0
- package/dist/canvas/useFrameLoop.js +60 -0
- package/dist/canvas/useFrameLoop.js.map +1 -0
- package/dist/canvas/useHostAnchor.js +71 -0
- package/dist/canvas/useHostAnchor.js.map +1 -0
- package/dist/canvas/useLateContentRedraw.js +21 -0
- package/dist/canvas/useLateContentRedraw.js.map +1 -0
- package/dist/canvas/useRedrawOn.js +21 -0
- package/dist/canvas/useRedrawOn.js.map +1 -0
- package/dist/canvas/useViewHelpers.js +120 -0
- package/dist/canvas/useViewHelpers.js.map +1 -0
- package/dist/canvas/viewInputs.js +17 -0
- package/dist/canvas/viewInputs.js.map +1 -0
- package/dist/canvas/viewRegistry.js +61 -0
- package/dist/canvas/viewRegistry.js.map +1 -0
- package/dist/canvas/wrapNodeOutput.js +14 -0
- package/dist/canvas/wrapNodeOutput.js.map +1 -0
- package/dist/clipboard.d.ts +10 -5
- package/dist/clipboard.js +3 -5
- package/dist/clone.d.ts +3 -3
- package/dist/clone.js +2 -5
- package/dist/core/adapters/arrayAdapter.js +85 -0
- package/dist/core/adapters/arrayAdapter.js.map +1 -0
- package/dist/core/adapters/useArrayAdapter.js +13 -0
- package/dist/core/adapters/useArrayAdapter.js.map +1 -0
- package/dist/core/applyOps.js +12 -0
- package/dist/core/applyOps.js.map +1 -0
- package/dist/core/device/index.js +4 -0
- package/dist/core/device/targets.js +17 -0
- package/dist/core/device/targets.js.map +1 -0
- package/dist/core/device/useDeviceProfile.js +75 -0
- package/dist/core/device/useDeviceProfile.js.map +1 -0
- package/dist/core/fillInPoseFrame.js +102 -0
- package/dist/core/fillInPoseFrame.js.map +1 -0
- package/dist/core/geometry/poseDescriptor.js +98 -0
- package/dist/core/geometry/poseDescriptor.js.map +1 -0
- package/dist/core/geometry/poseRotation.js +58 -0
- package/dist/core/geometry/poseRotation.js.map +1 -0
- package/dist/core/geometry/regionHit.js +102 -0
- package/dist/core/geometry/regionHit.js.map +1 -0
- package/dist/core/geometry/unionBounds.js +60 -0
- package/dist/core/geometry/unionBounds.js.map +1 -0
- package/dist/core/gradient.js +136 -0
- package/dist/core/gradient.js.map +1 -0
- package/dist/core/isPlainObject.js +11 -0
- package/dist/core/isPlainObject.js.map +1 -0
- package/dist/core/layers/render.js +150 -0
- package/dist/core/layers/render.js.map +1 -0
- package/dist/core/markerInset.js +24 -0
- package/dist/core/markerInset.js.map +1 -0
- package/dist/core/mixed.js +6 -0
- package/dist/core/mixed.js.map +1 -0
- package/dist/core/ops/arrange.js +31 -0
- package/dist/core/ops/arrange.js.map +1 -0
- package/dist/core/ops/create.js +32 -0
- package/dist/core/ops/create.js.map +1 -0
- package/dist/core/ops/createHistory.js +20 -0
- package/dist/core/ops/createHistory.js.map +1 -0
- package/dist/core/ops/delete.js +89 -0
- package/dist/core/ops/delete.js.map +1 -0
- package/dist/core/ops/registry.js +17 -0
- package/dist/core/ops/registry.js.map +1 -0
- package/dist/core/ops/reorder/algorithms.js +55 -0
- package/dist/core/ops/reorder/algorithms.js.map +1 -0
- package/dist/core/ops/reorder/index.js +140 -0
- package/dist/core/ops/reorder/index.js.map +1 -0
- package/dist/core/ops/reparent.js +52 -0
- package/dist/core/ops/reparent.js.map +1 -0
- package/dist/core/ops/select.js +34 -0
- package/dist/core/ops/select.js.map +1 -0
- package/dist/core/ops/setData.js +34 -0
- package/dist/core/ops/setData.js.map +1 -0
- package/dist/core/ops/setLayer.js +34 -0
- package/dist/core/ops/setLayer.js.map +1 -0
- package/dist/core/ops/setLayout.js +31 -0
- package/dist/core/ops/setLayout.js.map +1 -0
- package/dist/core/ops/setPath.js +57 -0
- package/dist/core/ops/setPath.js.map +1 -0
- package/dist/core/ops/setText.js +34 -0
- package/dist/core/ops/setText.js.map +1 -0
- package/dist/core/ops/slot.js +37 -0
- package/dist/core/ops/slot.js.map +1 -0
- package/dist/core/ops/transform.js +42 -0
- package/dist/core/ops/transform.js.map +1 -0
- package/dist/core/paintKinds.js +156 -0
- package/dist/core/paintKinds.js.map +1 -0
- package/dist/core/scene/NodeProperties.js +20 -0
- package/dist/core/scene/NodeProperties.js.map +1 -0
- package/dist/core/scene/NodeRouting.js +24 -0
- package/dist/core/scene/NodeRouting.js.map +1 -0
- package/dist/core/scene/arrivals.js +12 -0
- package/dist/core/scene/arrivals.js.map +1 -0
- package/dist/core/scene/composeFrame.js +29 -0
- package/dist/core/scene/composeFrame.js.map +1 -0
- package/dist/core/scene/depMemo.js +18 -0
- package/dist/core/scene/depMemo.js.map +1 -0
- package/dist/core/scene/dependents.js +66 -0
- package/dist/core/scene/dependents.js.map +1 -0
- package/dist/core/scene/derivedPath.js +31 -0
- package/dist/core/scene/derivedPath.js.map +1 -0
- package/dist/core/scene/effectivePose.js +78 -0
- package/dist/core/scene/effectivePose.js.map +1 -0
- package/dist/core/scene/kitRegistry.js +33 -0
- package/dist/core/scene/kitRegistry.js.map +1 -0
- package/dist/core/scene/layoutPass.js +96 -0
- package/dist/core/scene/layoutPass.js.map +1 -0
- package/dist/core/scene/nodeFnFields.js +83 -0
- package/dist/core/scene/nodeFnFields.js.map +1 -0
- package/dist/core/scene/nodeMemo.js +28 -0
- package/dist/core/scene/nodeMemo.js.map +1 -0
- package/dist/core/scene/poseFeed.js +87 -0
- package/dist/core/scene/poseFeed.js.map +1 -0
- package/dist/core/scene/poseOverrides.js +52 -0
- package/dist/core/scene/poseOverrides.js.map +1 -0
- package/dist/core/scene/poseSnapshot.js +54 -0
- package/dist/core/scene/poseSnapshot.js.map +1 -0
- package/dist/core/scene/scene.js +1271 -0
- package/dist/core/scene/scene.js.map +1 -0
- package/dist/core/scene/types.js +6 -0
- package/dist/core/scene/types.js.map +1 -0
- package/dist/core/scene/useScene.js +32 -0
- package/dist/core/scene/useScene.js.map +1 -0
- package/dist/core/selection/chromeState.js +31 -0
- package/dist/core/selection/chromeState.js.map +1 -0
- package/dist/core/selection/selectionTarget.js +6 -0
- package/dist/core/selection/selectionTarget.js.map +1 -0
- package/dist/core/selection/useSelection.js +71 -0
- package/dist/core/selection/useSelection.js.map +1 -0
- package/dist/core/shapeKinds.js +54 -0
- package/dist/core/shapeKinds.js.map +1 -0
- package/dist/core/strokeMarkerShapes.js +139 -0
- package/dist/core/strokeMarkerShapes.js.map +1 -0
- package/dist/core/strokeMarkers.js +28 -0
- package/dist/core/strokeMarkers.js.map +1 -0
- package/dist/core/stylus/stylus.js +39 -0
- package/dist/core/stylus/stylus.js.map +1 -0
- package/dist/core/stylus/usePointerStylus.js +51 -0
- package/dist/core/stylus/usePointerStylus.js.map +1 -0
- package/dist/core/usePaintKinds.js +17 -0
- package/dist/core/usePaintKinds.js.map +1 -0
- package/dist/core/viewport/clampView.js +24 -0
- package/dist/core/viewport/clampView.js.map +1 -0
- package/dist/core/viewport/clientToWorld.js +8 -0
- package/dist/core/viewport/clientToWorld.js.map +1 -0
- package/dist/core/viewport/createVelocityTracker.js +39 -0
- package/dist/core/viewport/createVelocityTracker.js.map +1 -0
- package/dist/core/viewport/fitToBounds.js +18 -0
- package/dist/core/viewport/fitToBounds.js.map +1 -0
- package/dist/core/viewport/fitViewToBounds.js +36 -0
- package/dist/core/viewport/fitViewToBounds.js.map +1 -0
- package/dist/core/viewport/interpolateView.js +34 -0
- package/dist/core/viewport/interpolateView.js.map +1 -0
- package/dist/core/viewport/meanScale.js +8 -0
- package/dist/core/viewport/meanScale.js.map +1 -0
- package/dist/core/viewport/parallax.js +111 -0
- package/dist/core/viewport/parallax.js.map +1 -0
- package/dist/core/viewport/pxExtent.js +42 -0
- package/dist/core/viewport/pxExtent.js.map +1 -0
- package/dist/core/viewport/sceneNodeClientRect.js +18 -0
- package/dist/core/viewport/sceneNodeClientRect.js.map +1 -0
- package/dist/core/viewport/screenSlop.js +27 -0
- package/dist/core/viewport/screenSlop.js.map +1 -0
- package/dist/core/viewport/useAutoCenter.js +32 -0
- package/dist/core/viewport/useAutoCenter.js.map +1 -0
- package/dist/core/viewport/useCanvasSize.js +29 -0
- package/dist/core/viewport/useCanvasSize.js.map +1 -0
- package/dist/core/viewport/useDecayLoop.js +63 -0
- package/dist/core/viewport/useDecayLoop.js.map +1 -0
- package/dist/core/viewport/useVelocityTracker.js +10 -0
- package/dist/core/viewport/useVelocityTracker.js.map +1 -0
- package/dist/core/viewport/useViewAnimation.js +63 -0
- package/dist/core/viewport/useViewAnimation.js.map +1 -0
- package/dist/core/viewport/view.js +37 -0
- package/dist/core/viewport/view.js.map +1 -0
- package/dist/core/viewport/viewTransform.js +11 -0
- package/dist/core/viewport/viewTransform.js.map +1 -0
- package/dist/core/viewport/viewportWorldRect.js +13 -0
- package/dist/core/viewport/viewportWorldRect.js.map +1 -0
- package/dist/core/viewport/wheelHandler.js +30 -0
- package/dist/core/viewport/wheelHandler.js.map +1 -0
- package/dist/core/viewport/zoomAt.js +22 -0
- package/dist/core/viewport/zoomAt.js.map +1 -0
- package/dist/core/viewport/zoomBounds.js +20 -0
- package/dist/core/viewport/zoomBounds.js.map +1 -0
- package/dist/{pointSnapToGrid-7mCcm6qG.d.ts → cornerHandles-CDcZOV8h.d.ts} +54 -71
- package/dist/debug/createDebugOverlayLayer.js +358 -0
- package/dist/debug/createDebugOverlayLayer.js.map +1 -0
- package/dist/debug/createDebugSink.js +83 -0
- package/dist/debug/createDebugSink.js.map +1 -0
- package/dist/debug/defaultTheme.js +31 -0
- package/dist/debug/defaultTheme.js.map +1 -0
- package/dist/debug/flag.js +41 -0
- package/dist/debug/flag.js.map +1 -0
- package/dist/debug/frameStats.js +16 -0
- package/dist/debug/frameStats.js.map +1 -0
- package/dist/debug/parseDebugFlags.js +32 -0
- package/dist/debug/parseDebugFlags.js.map +1 -0
- package/dist/features/chrome-caps/buildChromeCtx.js +16 -0
- package/dist/features/chrome-caps/buildChromeCtx.js.map +1 -0
- package/dist/features/chrome-caps/conditions.js +36 -0
- package/dist/features/chrome-caps/conditions.js.map +1 -0
- package/dist/features/chrome-caps/defaults.js +26 -0
- package/dist/features/chrome-caps/defaults.js.map +1 -0
- package/dist/features/chrome-caps/index.js +7 -0
- package/dist/features/chrome-caps/resolve.js +23 -0
- package/dist/features/chrome-caps/resolve.js.map +1 -0
- package/dist/features/chrome-caps/useHoverTracking.js +27 -0
- package/dist/features/chrome-caps/useHoverTracking.js.map +1 -0
- package/dist/features/cursor/paintedCursorLayer.js +60 -0
- package/dist/features/cursor/paintedCursorLayer.js.map +1 -0
- package/dist/features/focus/gateLayer.js +14 -0
- package/dist/features/focus/gateLayer.js.map +1 -0
- package/dist/features/focus/useCanvasFocus.js +29 -0
- package/dist/features/focus/useCanvasFocus.js.map +1 -0
- package/dist/features/groups/children.js +23 -0
- package/dist/features/groups/children.js.map +1 -0
- package/dist/features/groups/composePose.js +67 -0
- package/dist/features/groups/composePose.js.map +1 -0
- package/dist/features/groups/nestedHit.js +40 -0
- package/dist/features/groups/nestedHit.js.map +1 -0
- package/dist/features/groups/unionOfChildren.js +15 -0
- package/dist/features/groups/unionOfChildren.js.map +1 -0
- package/dist/features/images/imageCache.js +94 -0
- package/dist/features/images/imageCache.js.map +1 -0
- package/dist/features/ingestion/contentHandlers.js +37 -0
- package/dist/features/ingestion/contentHandlers.js.map +1 -0
- package/dist/features/ingestion/imageHandler.js +45 -0
- package/dist/features/ingestion/imageHandler.js.map +1 -0
- package/dist/features/ingestion/index.js +8 -0
- package/dist/features/ingestion/openFilePicker.js +15 -0
- package/dist/features/ingestion/openFilePicker.js.map +1 -0
- package/dist/features/ingestion/registerKitHandlers.js +26 -0
- package/dist/features/ingestion/registerKitHandlers.js.map +1 -0
- package/dist/features/ingestion/svgHandler.js +58 -0
- package/dist/features/ingestion/svgHandler.js.map +1 -0
- package/dist/features/ingestion/weaselJsonHandler.js +39 -0
- package/dist/features/ingestion/weaselJsonHandler.js.map +1 -0
- package/dist/features/longPress/longPressFeedback.js +96 -0
- package/dist/features/longPress/longPressFeedback.js.map +1 -0
- package/dist/features/meshPaint/bake.js +79 -0
- package/dist/features/meshPaint/bake.js.map +1 -0
- package/dist/features/meshPaint/bakeCache.js +59 -0
- package/dist/features/meshPaint/bakeCache.js.map +1 -0
- package/dist/features/meshPaint/handles.js +86 -0
- package/dist/features/meshPaint/handles.js.map +1 -0
- package/dist/features/meshPaint/lazyKind.js +1298 -0
- package/dist/features/meshPaint/lazyKind.js.map +1 -0
- package/dist/features/meshPaint/meshPaint.js +236 -0
- package/dist/features/meshPaint/meshPaint.js.map +1 -0
- package/dist/features/meshPaint/meshShader.js +6 -0
- package/dist/features/meshPaint/meshShader.js.map +1 -0
- package/dist/features/meshPaint/register.js +7 -0
- package/dist/features/meshPaint/register.js.map +1 -0
- package/dist/features/meshPaint/surface.js +110 -0
- package/dist/features/meshPaint/surface.js.map +1 -0
- package/dist/features/minimap/actions.js +53 -0
- package/dist/features/minimap/actions.js.map +1 -0
- package/dist/features/minimap/createMinimapContribution.js +96 -0
- package/dist/features/minimap/createMinimapContribution.js.map +1 -0
- package/dist/features/minimap/layers.js +103 -0
- package/dist/features/minimap/layers.js.map +1 -0
- package/dist/features/modes/modeLayers.js +113 -0
- package/dist/features/modes/modeLayers.js.map +1 -0
- package/dist/features/overlays/useNodeOverlayFrame.js +103 -0
- package/dist/features/overlays/useNodeOverlayFrame.js.map +1 -0
- package/dist/features/parallax/createParallaxLayer.js +26 -0
- package/dist/features/parallax/createParallaxLayer.js.map +1 -0
- package/dist/features/parallax/createParallaxPlane.js +26 -0
- package/dist/features/parallax/createParallaxPlane.js.map +1 -0
- package/dist/features/paths/anchorEdits.js +156 -0
- package/dist/features/paths/anchorEdits.js.map +1 -0
- package/dist/features/paths/anchors.js +154 -0
- package/dist/features/paths/anchors.js.map +1 -0
- package/dist/features/paths/booleans.js +2 -0
- package/dist/features/paths/index.js +15 -0
- package/dist/features/paths/markerCommands.js +116 -0
- package/dist/features/paths/markerCommands.js.map +1 -0
- package/dist/features/paths/markerSites.js +59 -0
- package/dist/features/paths/markerSites.js.map +1 -0
- package/dist/features/paths/markers.js +95 -0
- package/dist/features/paths/markers.js.map +1 -0
- package/dist/features/paths/nearestAnchor.js +36 -0
- package/dist/features/paths/nearestAnchor.js.map +1 -0
- package/dist/features/paths/originProjection.js +16 -0
- package/dist/features/paths/originProjection.js.map +1 -0
- package/dist/features/paths/pathEditingOverlayLayer.js +137 -0
- package/dist/features/paths/pathEditingOverlayLayer.js.map +1 -0
- package/dist/features/paths/pathInWorld.js +41 -0
- package/dist/features/paths/pathInWorld.js.map +1 -0
- package/dist/features/paths/pathLayer.js +44 -0
- package/dist/features/paths/pathLayer.js.map +1 -0
- package/dist/features/paths/penPreviewLayer.js +220 -0
- package/dist/features/paths/penPreviewLayer.js.map +1 -0
- package/dist/features/paths/poseDescriptor.js +44 -0
- package/dist/features/paths/poseDescriptor.js.map +1 -0
- package/dist/features/paths/tessellate/stroke.js +230 -0
- package/dist/features/paths/tessellate/stroke.js.map +1 -0
- package/dist/features/patterns/index.js +23 -0
- package/dist/features/patterns/index.js.map +1 -0
- package/dist/features/patterns/patterns-builtin.js +38 -0
- package/dist/features/patterns/patterns-builtin.js.map +1 -0
- package/dist/features/patterns/resolveSpec.js +57 -0
- package/dist/features/patterns/resolveSpec.js.map +1 -0
- package/dist/features/patterns/tileGeometry.js +158 -0
- package/dist/features/patterns/tileGeometry.js.map +1 -0
- package/dist/features/pointer/PointerContext.js +45 -0
- package/dist/features/pointer/PointerContext.js.map +1 -0
- package/dist/features/poseRun/usePoseRun.js +70 -0
- package/dist/features/poseRun/usePoseRun.js.map +1 -0
- package/dist/features/selection/SelectionContext.js +46 -0
- package/dist/features/selection/SelectionContext.js.map +1 -0
- package/dist/features/selection/overlay.js +442 -0
- package/dist/features/selection/overlay.js.map +1 -0
- package/dist/features/simulation/createSimulation.js +61 -0
- package/dist/features/simulation/createSimulation.js.map +1 -0
- package/dist/features/simulation/types.js +6 -0
- package/dist/features/simulation/types.js.map +1 -0
- package/dist/features/simulation/useSimulation.js +74 -0
- package/dist/features/simulation/useSimulation.js.map +1 -0
- package/dist/features/text/domRuns.js +258 -0
- package/dist/features/text/domRuns.js.map +1 -0
- package/dist/features/text/fitTextPose.js +38 -0
- package/dist/features/text/fitTextPose.js.map +1 -0
- package/dist/features/text/hitTest.js +45 -0
- package/dist/features/text/hitTest.js.map +1 -0
- package/dist/features/text/renderLabel.js +14 -0
- package/dist/features/text/renderLabel.js.map +1 -0
- package/dist/features/text/runs/effectiveRangeStyle.js +66 -0
- package/dist/features/text/runs/effectiveRangeStyle.js.map +1 -0
- package/dist/features/text/runs/flagRange.js +53 -0
- package/dist/features/text/runs/flagRange.js.map +1 -0
- package/dist/features/text/runs/rangeStyle.js +135 -0
- package/dist/features/text/runs/rangeStyle.js.map +1 -0
- package/dist/features/text/textCommand.js +59 -0
- package/dist/features/text/textCommand.js.map +1 -0
- package/dist/features/text/textLayer.js +35 -0
- package/dist/features/text/textLayer.js.map +1 -0
- package/dist/features/text/textToPath.js +181 -0
- package/dist/features/text/textToPath.js.map +1 -0
- package/dist/features/text/useSceneTextEdit.js +138 -0
- package/dist/features/text/useSceneTextEdit.js.map +1 -0
- package/dist/features/text/useTextEdit.js +465 -0
- package/dist/features/text/useTextEdit.js.map +1 -0
- package/dist/features/tiling/createTiledLayer.js +63 -0
- package/dist/features/tiling/createTiledLayer.js.map +1 -0
- package/dist/features/tiling/tiledProject.js +14 -0
- package/dist/features/tiling/tiledProject.js.map +1 -0
- package/dist/features/viewports/viewResolver.js +59 -0
- package/dist/features/viewports/viewResolver.js.map +1 -0
- package/dist/features/viewports/viewportLayer.js +58 -0
- package/dist/features/viewports/viewportLayer.js.map +1 -0
- package/dist/icons/ArrowIcon.js +23 -0
- package/dist/icons/ArrowIcon.js.map +1 -0
- package/dist/icons/EllipseIcon.js +21 -0
- package/dist/icons/EllipseIcon.js.map +1 -0
- package/dist/icons/EyedropperIcon.js +49 -0
- package/dist/icons/EyedropperIcon.js.map +1 -0
- package/dist/icons/HandIcon.js +59 -0
- package/dist/icons/HandIcon.js.map +1 -0
- package/dist/icons/ImageIcon.js +34 -0
- package/dist/icons/ImageIcon.js.map +1 -0
- package/dist/icons/LassoIcon.js +22 -0
- package/dist/icons/LassoIcon.js.map +1 -0
- package/dist/icons/LineIcon.js +22 -0
- package/dist/icons/LineIcon.js.map +1 -0
- package/dist/icons/PenIcon.js +36 -0
- package/dist/icons/PenIcon.js.map +1 -0
- package/dist/icons/PencilIcon.js +25 -0
- package/dist/icons/PencilIcon.js.map +1 -0
- package/dist/icons/PolygonIcon.js +19 -0
- package/dist/icons/PolygonIcon.js.map +1 -0
- package/dist/icons/RectIcon.js +37 -0
- package/dist/icons/RectIcon.js.map +1 -0
- package/dist/icons/SelectIcon.js +20 -0
- package/dist/icons/SelectIcon.js.map +1 -0
- package/dist/icons/StarIcon.js +19 -0
- package/dist/icons/StarIcon.js.map +1 -0
- package/dist/icons/TextIcon.js +19 -0
- package/dist/icons/TextIcon.js.map +1 -0
- package/dist/icons/UnknownIcon.js +33 -0
- package/dist/icons/UnknownIcon.js.map +1 -0
- package/dist/icons/_base.js +12 -0
- package/dist/icons/_base.js.map +1 -0
- package/dist/index.css +2 -86
- package/dist/index.d.ts +2349 -2609
- package/dist/index.js +312 -13
- package/dist/input/keyState.js +76 -0
- package/dist/input/keyState.js.map +1 -0
- package/dist/input/useKeyState.js +22 -0
- package/dist/input/useKeyState.js.map +1 -0
- package/dist/interactions/actions/actionShortcuts.js +32 -0
- package/dist/interactions/actions/actionShortcuts.js.map +1 -0
- package/dist/interactions/actions/align/align.js +81 -0
- package/dist/interactions/actions/align/align.js.map +1 -0
- package/dist/interactions/actions/booleans/booleans.js +120 -0
- package/dist/interactions/actions/booleans/booleans.js.map +1 -0
- package/dist/interactions/actions/booleans/useBooleans.js +20 -0
- package/dist/interactions/actions/booleans/useBooleans.js.map +1 -0
- package/dist/interactions/actions/booleans/useBooleansAdapter.js +9 -0
- package/dist/interactions/actions/booleans/useBooleansAdapter.js.map +1 -0
- package/dist/interactions/actions/clipboard/clipboardOps.js +94 -0
- package/dist/interactions/actions/clipboard/clipboardOps.js.map +1 -0
- package/dist/interactions/actions/clipboard/materializePaste.js +25 -0
- package/dist/interactions/actions/clipboard/materializePaste.js.map +1 -0
- package/dist/interactions/actions/clipboard/wireFormat.js +43 -0
- package/dist/interactions/actions/clipboard/wireFormat.js.map +1 -0
- package/dist/interactions/actions/clone/behaviors/cloneByAltDrag.js +26 -0
- package/dist/interactions/actions/clone/behaviors/cloneByAltDrag.js.map +1 -0
- package/dist/interactions/actions/defaultCommitAdapter.js +42 -0
- package/dist/interactions/actions/defaultCommitAdapter.js.map +1 -0
- package/dist/interactions/actions/defaults/align.js +71 -0
- package/dist/interactions/actions/defaults/align.js.map +1 -0
- package/dist/interactions/actions/defaults/anchorEditing.js +235 -0
- package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -0
- package/dist/interactions/actions/defaults/areaSelect.js +75 -0
- package/dist/interactions/actions/defaults/areaSelect.js.map +1 -0
- package/dist/interactions/actions/defaults/booleans.js +52 -0
- package/dist/interactions/actions/defaults/booleans.js.map +1 -0
- package/dist/interactions/actions/defaults/cancelGesture.js +24 -0
- package/dist/interactions/actions/defaults/cancelGesture.js.map +1 -0
- package/dist/interactions/actions/defaults/clearSelection.js +19 -0
- package/dist/interactions/actions/defaults/clearSelection.js.map +1 -0
- package/dist/interactions/actions/defaults/clipboard.js +78 -0
- package/dist/interactions/actions/defaults/clipboard.js.map +1 -0
- package/dist/interactions/actions/defaults/clone.js +96 -0
- package/dist/interactions/actions/defaults/clone.js.map +1 -0
- package/dist/interactions/actions/defaults/createOutlines.js +47 -0
- package/dist/interactions/actions/defaults/createOutlines.js.map +1 -0
- package/dist/interactions/actions/defaults/createPaintAction.js +85 -0
- package/dist/interactions/actions/defaults/createPaintAction.js.map +1 -0
- package/dist/interactions/actions/defaults/delete.js +61 -0
- package/dist/interactions/actions/defaults/delete.js.map +1 -0
- package/dist/interactions/actions/defaults/distribute.js +66 -0
- package/dist/interactions/actions/defaults/distribute.js.map +1 -0
- package/dist/interactions/actions/defaults/duplicate.js +83 -0
- package/dist/interactions/actions/defaults/duplicate.js.map +1 -0
- package/dist/interactions/actions/defaults/editAnchors.js +100 -0
- package/dist/interactions/actions/defaults/editAnchors.js.map +1 -0
- package/dist/interactions/actions/defaults/enterPathEdit.js +29 -0
- package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -0
- package/dist/interactions/actions/defaults/enterTextEdit.js +20 -0
- package/dist/interactions/actions/defaults/enterTextEdit.js.map +1 -0
- package/dist/interactions/actions/defaults/escape.js +26 -0
- package/dist/interactions/actions/defaults/escape.js.map +1 -0
- package/dist/interactions/actions/defaults/exitPathEdit.js +22 -0
- package/dist/interactions/actions/defaults/exitPathEdit.js.map +1 -0
- package/dist/interactions/actions/defaults/flip.js +119 -0
- package/dist/interactions/actions/defaults/flip.js.map +1 -0
- package/dist/interactions/actions/defaults/freshNodeId.js +10 -0
- package/dist/interactions/actions/defaults/freshNodeId.js.map +1 -0
- package/dist/interactions/actions/defaults/group.js +131 -0
- package/dist/interactions/actions/defaults/group.js.map +1 -0
- package/dist/interactions/actions/defaults/icons/actionGlyphIcons.js +40 -0
- package/dist/interactions/actions/defaults/icons/actionGlyphIcons.js.map +1 -0
- package/dist/interactions/actions/defaults/icons/actionGlyphs.js +10 -0
- package/dist/interactions/actions/defaults/icons/actionGlyphs.js.map +1 -0
- package/dist/interactions/actions/defaults/icons/alignIcons.js +173 -0
- package/dist/interactions/actions/defaults/icons/alignIcons.js.map +1 -0
- package/dist/interactions/actions/defaults/icons/booleanIcons.js +171 -0
- package/dist/interactions/actions/defaults/icons/booleanIcons.js.map +1 -0
- package/dist/interactions/actions/defaults/icons/distributeIcons.js +63 -0
- package/dist/interactions/actions/defaults/icons/distributeIcons.js.map +1 -0
- package/dist/interactions/actions/defaults/icons/editIcons.js +280 -0
- package/dist/interactions/actions/defaults/icons/editIcons.js.map +1 -0
- package/dist/interactions/actions/defaults/icons/outlineIcons.js +53 -0
- package/dist/interactions/actions/defaults/icons/outlineIcons.js.map +1 -0
- package/dist/interactions/actions/defaults/ingest.js +58 -0
- package/dist/interactions/actions/defaults/ingest.js.map +1 -0
- package/dist/interactions/actions/defaults/insert.js +288 -0
- package/dist/interactions/actions/defaults/insert.js.map +1 -0
- package/dist/interactions/actions/defaults/insertPathAnchor.js +50 -0
- package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -0
- package/dist/interactions/actions/defaults/lassoSelect.js +156 -0
- package/dist/interactions/actions/defaults/lassoSelect.js.map +1 -0
- package/dist/interactions/actions/defaults/move.js +656 -0
- package/dist/interactions/actions/defaults/move.js.map +1 -0
- package/dist/interactions/actions/defaults/nudge.js +110 -0
- package/dist/interactions/actions/defaults/nudge.js.map +1 -0
- package/dist/interactions/actions/defaults/pinchZoom.js +63 -0
- package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -0
- package/dist/interactions/actions/defaults/reorder.js +143 -0
- package/dist/interactions/actions/defaults/reorder.js.map +1 -0
- package/dist/interactions/actions/defaults/requiresSelection.js +10 -0
- package/dist/interactions/actions/defaults/requiresSelection.js.map +1 -0
- package/dist/interactions/actions/defaults/resize.js +332 -0
- package/dist/interactions/actions/defaults/resize.js.map +1 -0
- package/dist/interactions/actions/defaults/rotate.js +181 -0
- package/dist/interactions/actions/defaults/rotate.js.map +1 -0
- package/dist/interactions/actions/defaults/selectAll.js +27 -0
- package/dist/interactions/actions/defaults/selectAll.js.map +1 -0
- package/dist/interactions/actions/defaults/setFill.js +27 -0
- package/dist/interactions/actions/defaults/setFill.js.map +1 -0
- package/dist/interactions/actions/defaults/setFillOpacity.js +15 -0
- package/dist/interactions/actions/defaults/setFillOpacity.js.map +1 -0
- package/dist/interactions/actions/defaults/setStroke.js +36 -0
- package/dist/interactions/actions/defaults/setStroke.js.map +1 -0
- package/dist/interactions/actions/defaults/setStrokeOpacity.js +21 -0
- package/dist/interactions/actions/defaults/setStrokeOpacity.js.map +1 -0
- package/dist/interactions/actions/defaults/slice.js +39 -0
- package/dist/interactions/actions/defaults/slice.js.map +1 -0
- package/dist/interactions/actions/defaults/sliceOps.js +60 -0
- package/dist/interactions/actions/defaults/sliceOps.js.map +1 -0
- package/dist/interactions/actions/defaults/toolActivate.js +35 -0
- package/dist/interactions/actions/defaults/toolActivate.js.map +1 -0
- package/dist/interactions/actions/defaults/toolResetToDefault.js +26 -0
- package/dist/interactions/actions/defaults/toolResetToDefault.js.map +1 -0
- package/dist/interactions/actions/defaults/undoRedo.js +51 -0
- package/dist/interactions/actions/defaults/undoRedo.js.map +1 -0
- package/dist/interactions/actions/defaults/viewportDragPan.js +88 -0
- package/dist/interactions/actions/defaults/viewportDragPan.js.map +1 -0
- package/dist/interactions/actions/defaults/viewportWheelPan.js +57 -0
- package/dist/interactions/actions/defaults/viewportWheelPan.js.map +1 -0
- package/dist/interactions/actions/defaults/viewportZoom.js +143 -0
- package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -0
- package/dist/interactions/actions/distribute/distribute.js +42 -0
- package/dist/interactions/actions/distribute/distribute.js.map +1 -0
- package/dist/interactions/actions/distribute/plan.js +29 -0
- package/dist/interactions/actions/distribute/plan.js.map +1 -0
- package/dist/interactions/actions/edit-anchors/geometry.js +61 -0
- package/dist/interactions/actions/edit-anchors/geometry.js.map +1 -0
- package/dist/interactions/actions/edit-anchors/handles.js +43 -0
- package/dist/interactions/actions/edit-anchors/handles.js.map +1 -0
- package/dist/interactions/actions/flip/helpers.js +35 -0
- package/dist/interactions/actions/flip/helpers.js.map +1 -0
- package/dist/interactions/actions/geometryProjection.js +18 -0
- package/dist/interactions/actions/geometryProjection.js.map +1 -0
- package/dist/interactions/actions/gestureLifecycle.js +44 -0
- package/dist/interactions/actions/gestureLifecycle.js.map +1 -0
- package/dist/interactions/actions/lasso-select/behaviors/selectFromLasso.js +39 -0
- package/dist/interactions/actions/lasso-select/behaviors/selectFromLasso.js.map +1 -0
- package/dist/interactions/actions/move/behaviors/snapBackOrDelete.js +36 -0
- package/dist/interactions/actions/move/behaviors/snapBackOrDelete.js.map +1 -0
- package/dist/interactions/actions/move/behaviors/snapToContainer.js +67 -0
- package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -0
- package/dist/interactions/actions/move/gestureAdapter.js +37 -0
- package/dist/interactions/actions/move/gestureAdapter.js.map +1 -0
- package/dist/interactions/actions/outlines/createOutlines.js +84 -0
- package/dist/interactions/actions/outlines/createOutlines.js.map +1 -0
- package/dist/interactions/actions/outlines/useCreateOutlinesAdapter.js +9 -0
- package/dist/interactions/actions/outlines/useCreateOutlinesAdapter.js.map +1 -0
- package/dist/interactions/actions/planeInput.js +168 -0
- package/dist/interactions/actions/planeInput.js.map +1 -0
- package/dist/interactions/actions/poseDescriptorDep.js +9 -0
- package/dist/interactions/actions/poseDescriptorDep.js.map +1 -0
- package/dist/interactions/actions/poseFrame.js +38 -0
- package/dist/interactions/actions/poseFrame.js.map +1 -0
- package/dist/interactions/actions/previewOverrides.js +25 -0
- package/dist/interactions/actions/previewOverrides.js.map +1 -0
- package/dist/interactions/actions/resize/autoPoseDescriptor.js +32 -0
- package/dist/interactions/actions/resize/autoPoseDescriptor.js.map +1 -0
- package/dist/interactions/actions/resize/behaviors/clampMinSize.js +18 -0
- package/dist/interactions/actions/resize/behaviors/clampMinSize.js.map +1 -0
- package/dist/interactions/actions/resize/behaviors/index.js +8 -0
- package/dist/interactions/actions/resize/behaviors/index.js.map +1 -0
- package/dist/interactions/actions/resize/behaviors/lockAspect.js +24 -0
- package/dist/interactions/actions/resize/behaviors/lockAspect.js.map +1 -0
- package/dist/interactions/actions/resize/cornerHandles.js +72 -0
- package/dist/interactions/actions/resize/cornerHandles.js.map +1 -0
- package/dist/interactions/actions/resolveOverlays.js +60 -0
- package/dist/interactions/actions/resolveOverlays.js.map +1 -0
- package/dist/interactions/actions/resolvePreviews.js +61 -0
- package/dist/interactions/actions/resolvePreviews.js.map +1 -0
- package/dist/interactions/actions/rotate/geometry.js +46 -0
- package/dist/interactions/actions/rotate/geometry.js.map +1 -0
- package/dist/interactions/actions/rotate/handle.js +27 -0
- package/dist/interactions/actions/rotate/handle.js.map +1 -0
- package/dist/interactions/actions/spatialReference.js +42 -0
- package/dist/interactions/actions/spatialReference.js.map +1 -0
- package/dist/interactions/actions/useStandardActions.js +142 -0
- package/dist/interactions/actions/useStandardActions.js.map +1 -0
- package/dist/interactions/gestures/dragGesture/dragGesture.js +111 -0
- package/dist/interactions/gestures/dragGesture/dragGesture.js.map +1 -0
- package/dist/interactions/gestures/dragRadial/dragRadial.js +117 -0
- package/dist/interactions/gestures/dragRadial/dragRadial.js.map +1 -0
- package/dist/interactions/gestures/dragRect/dragRect.js +164 -0
- package/dist/interactions/gestures/dragRect/dragRect.js.map +1 -0
- package/dist/interactions/gestures/handleDrag/handleDrag.js +46 -0
- package/dist/interactions/gestures/handleDrag/handleDrag.js.map +1 -0
- package/dist/interactions/gestures/pointerDrag/pointerDrag.js +118 -0
- package/dist/interactions/gestures/pointerDrag/pointerDrag.js.map +1 -0
- package/dist/interactions/gestures/shared/originProjection.js +42 -0
- package/dist/interactions/gestures/shared/originProjection.js.map +1 -0
- package/dist/interactions/gestures/shared/screenTolerance.js +21 -0
- package/dist/interactions/gestures/shared/screenTolerance.js.map +1 -0
- package/dist/interactions/gestures/shared/snap.js +24 -0
- package/dist/interactions/gestures/shared/snap.js.map +1 -0
- package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js +30 -0
- package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js.map +1 -0
- package/dist/layout/arrivals.js +36 -0
- package/dist/layout/arrivals.js.map +1 -0
- package/dist/{math-MCQcf_gc.d.ts → math-CUMxmZzn.d.ts} +8 -116
- package/dist/math.d.ts +4 -5
- package/dist/math.js +6 -4
- package/dist/mesh.d.ts +268 -0
- package/dist/mesh.js +7 -0
- package/dist/move.d.ts +7 -48
- package/dist/move.js +3 -142
- package/dist/originProjection-BSn4xiEy.d.ts +57 -0
- package/dist/patterns-builtin.js +3 -3
- package/dist/{poseDescriptor-rZa9W5hJ.d.ts → poseDescriptor-CjSXMf8X.d.ts} +3 -3
- package/dist/registerProgram-ateHDGjw.d.ts +193 -0
- package/dist/renderer/DrawCommand.js +6 -0
- package/dist/renderer/DrawCommand.js.map +1 -0
- package/dist/renderer/WeaselRenderer.js +328 -0
- package/dist/renderer/WeaselRenderer.js.map +1 -0
- package/dist/renderer/cache/GLImageCache.js +64 -0
- package/dist/renderer/cache/GLImageCache.js.map +1 -0
- package/dist/renderer/cache/GLMeshCache.js +102 -0
- package/dist/renderer/cache/GLMeshCache.js.map +1 -0
- package/dist/renderer/cache/GLTextureCache.js +51 -0
- package/dist/renderer/cache/GLTextureCache.js.map +1 -0
- package/dist/renderer/cache/GradientRampAtlas.js +82 -0
- package/dist/renderer/cache/GradientRampAtlas.js.map +1 -0
- package/dist/renderer/cache/cache.js +13 -0
- package/dist/renderer/cache/cache.js.map +1 -0
- package/dist/renderer/cache/markerCommandCache.js +59 -0
- package/dist/renderer/cache/markerCommandCache.js.map +1 -0
- package/dist/renderer/cache/outlineMeshCache.js +15 -0
- package/dist/renderer/cache/outlineMeshCache.js.map +1 -0
- package/dist/renderer/cache/outlineStrokeMeshCache.js +31 -0
- package/dist/renderer/cache/outlineStrokeMeshCache.js.map +1 -0
- package/dist/renderer/cache/strokeMeshCache.js +44 -0
- package/dist/renderer/cache/strokeMeshCache.js.map +1 -0
- package/dist/renderer/cullDrawCommands.js +89 -0
- package/dist/renderer/cullDrawCommands.js.map +1 -0
- package/dist/renderer/draw.js +1109 -0
- package/dist/renderer/draw.js.map +1 -0
- package/dist/renderer/drawBatch.js +168 -0
- package/dist/renderer/drawBatch.js.map +1 -0
- package/dist/renderer/effects/EffectTargets.js +45 -0
- package/dist/renderer/effects/EffectTargets.js.map +1 -0
- package/dist/renderer/effects/builtins.js +31 -0
- package/dist/renderer/effects/builtins.js.map +1 -0
- package/dist/renderer/effects/composite.js +9 -0
- package/dist/renderer/effects/composite.js.map +1 -0
- package/dist/renderer/effects/effectPrelude.js +10 -0
- package/dist/renderer/effects/effectPrelude.js.map +1 -0
- package/dist/renderer/effects/types.js +10 -0
- package/dist/renderer/effects/types.js.map +1 -0
- package/dist/renderer/index.js +19 -0
- package/dist/renderer/math/color.js +341 -0
- package/dist/renderer/math/color.js.map +1 -0
- package/dist/renderer/math/mat3.js +71 -0
- package/dist/renderer/math/mat3.js.map +1 -0
- package/dist/renderer/math/patternSpace.js +22 -0
- package/dist/renderer/math/patternSpace.js.map +1 -0
- package/dist/renderer/math/viewToMat3.js +19 -0
- package/dist/renderer/math/viewToMat3.js.map +1 -0
- package/dist/renderer/paintResources.js +18 -0
- package/dist/renderer/paintResources.js.map +1 -0
- package/dist/renderer/paintScratch.js +37 -0
- package/dist/renderer/paintScratch.js.map +1 -0
- package/dist/renderer/shaders/ShaderProgram.js +74 -0
- package/dist/renderer/shaders/ShaderProgram.js.map +1 -0
- package/dist/renderer/shaders/batchFill.js +118 -0
- package/dist/renderer/shaders/batchFill.js.map +1 -0
- package/dist/renderer/shaders/customPrelude.js +34 -0
- package/dist/renderer/shaders/customPrelude.js.map +1 -0
- package/dist/renderer/shaders/extractUniformNames.js +184 -0
- package/dist/renderer/shaders/extractUniformNames.js.map +1 -0
- package/dist/renderer/shaders/glyphPaint.js +61 -0
- package/dist/renderer/shaders/glyphPaint.js.map +1 -0
- package/dist/renderer/shaders/gradFill.js +30 -0
- package/dist/renderer/shaders/gradFill.js.map +1 -0
- package/dist/renderer/shaders/imageFill.js +14 -0
- package/dist/renderer/shaders/imageFill.js.map +1 -0
- package/dist/renderer/shaders/pathFill.js +13 -0
- package/dist/renderer/shaders/pathFill.js.map +1 -0
- package/dist/renderer/shaders/patternFill.js +24 -0
- package/dist/renderer/shaders/patternFill.js.map +1 -0
- package/dist/renderer/shaders/registerProgram.js +18 -0
- package/dist/renderer/shaders/registerProgram.js.map +1 -0
- package/dist/renderer/spriteSheet.js +14 -0
- package/dist/renderer/spriteSheet.js.map +1 -0
- package/dist/renderer/state/GroupState.js +77 -0
- package/dist/renderer/state/GroupState.js.map +1 -0
- package/dist/renderer/syntheticItalic.js +6 -0
- package/dist/renderer/syntheticItalic.js.map +1 -0
- package/dist/renderer/textures/registerTexture.js +14 -0
- package/dist/renderer/textures/registerTexture.js.map +1 -0
- package/dist/renderer.d.ts +18 -20
- package/dist/renderer.js +18 -13
- package/dist/resize.d.ts +10 -46
- package/dist/resize.js +7 -5
- package/dist/routing.d.ts +1 -1
- package/dist/routing.js +2 -3
- package/dist/scheduling/useVisibleRaf.js +69 -0
- package/dist/scheduling/useVisibleRaf.js.map +1 -0
- package/dist/test-hook/createTestHook.js +39 -0
- package/dist/test-hook/createTestHook.js.map +1 -0
- package/dist/test-hook/install.js +12 -0
- package/dist/test-hook/install.js.map +1 -0
- package/dist/test-seams-fYf6m5pu.d.ts +356 -0
- package/dist/test-seams.d.ts +6 -0
- package/dist/test-seams.js +3 -0
- package/dist/tools/builtin/ellipse/useEllipseTool.js +33 -0
- package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -0
- package/dist/tools/builtin/eyedropper/useEyedropperTool.js +55 -0
- package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -0
- package/dist/tools/builtin/hand/dragPanContribution.js +17 -0
- package/dist/tools/builtin/hand/dragPanContribution.js.map +1 -0
- package/dist/tools/builtin/hand/useHandTool.js +31 -0
- package/dist/tools/builtin/hand/useHandTool.js.map +1 -0
- package/dist/tools/builtin/image/useImageTool.js +41 -0
- package/dist/tools/builtin/image/useImageTool.js.map +1 -0
- package/dist/tools/builtin/lasso/useLassoTool.js +42 -0
- package/dist/tools/builtin/lasso/useLassoTool.js.map +1 -0
- package/dist/tools/builtin/line/useLineTool.js +33 -0
- package/dist/tools/builtin/line/useLineTool.js.map +1 -0
- package/dist/tools/builtin/pen/usePenTool.js +414 -0
- package/dist/tools/builtin/pen/usePenTool.js.map +1 -0
- package/dist/tools/builtin/pencil/usePencilTool.js +36 -0
- package/dist/tools/builtin/pencil/usePencilTool.js.map +1 -0
- package/dist/tools/builtin/pickTopMostHit.js +45 -0
- package/dist/tools/builtin/pickTopMostHit.js.map +1 -0
- package/dist/tools/builtin/polygon/usePolygonTool.js +81 -0
- package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -0
- package/dist/tools/builtin/rect/useRectTool.js +32 -0
- package/dist/tools/builtin/rect/useRectTool.js.map +1 -0
- package/dist/tools/builtin/select/selectionContributions.js +109 -0
- package/dist/tools/builtin/select/selectionContributions.js.map +1 -0
- package/dist/tools/builtin/select/useSelectTool.js +162 -0
- package/dist/tools/builtin/select/useSelectTool.js.map +1 -0
- package/dist/tools/builtin/shared/insertToolOptions.js +8 -0
- package/dist/tools/builtin/shared/insertToolOptions.js.map +1 -0
- package/dist/tools/builtin/slice/useSliceTool.js +263 -0
- package/dist/tools/builtin/slice/useSliceTool.js.map +1 -0
- package/dist/tools/builtin/star/useStarTool.js +82 -0
- package/dist/tools/builtin/star/useStarTool.js.map +1 -0
- package/dist/tools/builtin/text/useTextTool.js +177 -0
- package/dist/tools/builtin/text/useTextTool.js.map +1 -0
- package/dist/tools/overlayBinding.js +8 -0
- package/dist/tools/overlayBinding.js.map +1 -0
- package/dist/tools/prefs.js +47 -0
- package/dist/tools/prefs.js.map +1 -0
- package/dist/tools/useKeybindings.js +66 -0
- package/dist/tools/useKeybindings.js.map +1 -0
- package/dist/{types-CxC8P6W0.d.ts → types-CA54-mAZ.d.ts} +188 -17
- package/dist/{types-D_74YlWs.d.ts → types-DSjd6W3n.d.ts} +35 -12
- package/dist/util/color.js +26 -0
- package/dist/util/color.js.map +1 -0
- package/dist/util/constrainTo45.js +17 -0
- package/dist/util/constrainTo45.js.map +1 -0
- package/dist/util/paint.js +72 -0
- package/dist/util/paint.js.map +1 -0
- package/dist/version.js +6 -0
- package/dist/version.js.map +1 -0
- package/package.json +31 -18
- package/dist/chunk-44EWMJV2.js +0 -128
- package/dist/chunk-44EWMJV2.js.map +0 -1
- package/dist/chunk-4RJP2N2L.js +0 -143
- package/dist/chunk-4RJP2N2L.js.map +0 -1
- package/dist/chunk-BJN5ZRIJ.js +0 -167
- package/dist/chunk-BJN5ZRIJ.js.map +0 -1
- package/dist/chunk-D4AAWR64.js +0 -28
- package/dist/chunk-D4AAWR64.js.map +0 -1
- package/dist/chunk-DOBSZOPR.js +0 -29
- package/dist/chunk-DOBSZOPR.js.map +0 -1
- package/dist/chunk-H6N2JSZ3.js +0 -248
- package/dist/chunk-H6N2JSZ3.js.map +0 -1
- package/dist/chunk-HPFJUUTF.js +0 -167
- package/dist/chunk-HPFJUUTF.js.map +0 -1
- package/dist/chunk-L5YNZYEG.js +0 -648
- package/dist/chunk-L5YNZYEG.js.map +0 -1
- package/dist/chunk-MZAIDI6D.js +0 -32492
- package/dist/chunk-MZAIDI6D.js.map +0 -1
- package/dist/chunk-PNNZSYRD.js +0 -318
- package/dist/chunk-PNNZSYRD.js.map +0 -1
- package/dist/chunk-RMR4QMM6.js +0 -250
- package/dist/chunk-RMR4QMM6.js.map +0 -1
- package/dist/clipboard.js.map +0 -1
- package/dist/clone.js.map +0 -1
- package/dist/grid-BXdz8GF2.d.ts +0 -158
- package/dist/index.css.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/insert.d.ts +0 -37
- package/dist/insert.js +0 -81
- package/dist/insert.js.map +0 -1
- package/dist/math.js.map +0 -1
- package/dist/move.js.map +0 -1
- package/dist/options-CzjxFoYZ.d.ts +0 -67
- package/dist/path-JEV2c5If.d.ts +0 -48
- package/dist/patterns-builtin.js.map +0 -1
- package/dist/renderer.css +0 -86
- package/dist/renderer.css.map +0 -1
- package/dist/renderer.js.map +0 -1
- package/dist/resize.js.map +0 -1
- package/dist/routing.js.map +0 -1
- package/dist/types-D2tTKEU0.d.ts +0 -18
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTextEdit.js","names":["STYLE_SHORTCUTS","UNSHIFT","toggleForKey","raw","key","s","patchForToggle","toggle","current","on","rangeWeight","nodeStyle","nodeHasFlag","styleAtCaret","at","styleAtRange","runs","spliceRunAt","out","pos","placed","r","end","k","run","applyStyleToRange","restoreOverlayFocus","active","overlay","a","charOffsetToDomPosition","range","b","sel","placeCaretBetweenRuns","acc","index","i","offset","span","NO_PENDING","mergePending","next","prev","superseded","supersededKey","patch","value","readSelectionOffsets","start","domPositionToCharOffset","writeRunsPreservingSelection","inTextEntry","runsToDom","base","trimCaretHolder","last","trimmed","head","sameSelection","TEXT_EDIT_FONT_HOLD","useTextEdit","optsRef","useLatest","opts","editingId","setEditingId","useState","editingIdRef","overlayRef","useRef","baseRef","resolveTextStyle","tickRef","frameLoop","useVisibleRaf","initialCaretRef","selection","setSelection","rangeStyle","setRangeStyle","pendingStyle","setPendingStyle","pendingRef","pendingAtRef","armPending","useCallback","empty","dropPending","selectionRef","publishRange","collapsed","domToRuns","syncSelection","clearSelection","cancelEdit","commit","id","priorRuns","setRuns","hadRuns","runsToPlainText","runsCarryStyling","startEdit","isEditing","applyStyleToSelection","setStyle","unboldPatch","unsetFlag","setFlagOverRange","rest","toggleStyle","patchRangeStyle","useEffect","container","style","getStyle","getPaint","overlayClass","OVERLAY_SEQ","initialRuns","getText","appendOverlayText","applyOverlayStyle","hold","holdForFaces","styleEl","installSelectionStyle","clipBox","createClipBox","place","clip","held","release","holdTimer","initial","placeCaretAt","onKeyDown","onBlur","isChrome","onBeforeInput","ie","pending","after","textNode","resplitSmallCaps","normalizeSmallCaps","onInput","onPointerDownOutside","target","cssFontFamilyLoading","numericWeight","p","remaining","walker","root","node","len","el","fontFamily","cssFontFamily","fontString","edge","resolveAlign","decorations","SMALL_CAPS_SCALE_PROPERTY","smallCapsScaleFor","decls","ALIGN_ANCHOR","overlayTop","slack","verticalAlignOffset","pose","contentHeight","drop","baselineDrop","canvas","layoutTextPose","css","cssBaseline","CSS_BASELINES","parent","fontWeight","fontStyle","fontSize","lineHeight","cached","line","mark","box","scale","baseline","placeOverlay","anchor","script","scriptMetricsFor","aligned","transforms"],"sources":["../../../src/features/text/useTextEdit.ts"],"sourcesContent":["/**\n * In-place text editing via a contenteditable overlay positioned over the\n * text node's screen-space pose. Enter / blur commit; Shift+Enter inserts a\n * newline; Escape cancels. The hook owns the DOM lifecycle of the overlay\n * element — caller just provides a container, the lookup hooks, and a\n * `setText` callback (which is responsible for op-batching/undo).\n *\n * The text layer should hide the node it's currently editing\n * (`isHidden: (n) => n.id === editingId`) so the overlay isn't drawn twice.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport { useVisibleRaf } from '../../scheduling/useVisibleRaf';\nimport type { ResolvedTextStyle, TextStyle } from '@weasel-js/text';\nimport {\n fontString, numericWeight, resolveAlign, resolveTextStyle, scriptMetricsFor, smallCapsScaleFor,\n} from '@weasel-js/text';\nimport { cssFontFamily, cssFontFamilyLoading } from '@weasel-js/font';\nimport type { TextPaint, TextVerticalAlign } from '@weasel-js/text';\nimport { layoutTextPose, verticalAlignOffset } from '@weasel-js/text';\nimport type { StyledRun } from '@weasel-js/text';\nimport { runsToPlainText } from '@weasel-js/text';\nimport {\n runsToDom, domToRuns, appendOverlayText, charOffsetToDomPosition, domPositionToCharOffset, normalizeSmallCaps,\n SMALL_CAPS_SCALE_PROPERTY, type OverlayRunBase,\n} from './domRuns';\nimport { applyStyleToRange, patchRangeStyle, runsCarryStyling, styleAtRange, supersededKey } from './runs/rangeStyle';\nimport { nodeHasFlag, setFlagOverRange, unboldPatch, type FlagKey } from './runs/flagRange';\nimport { rangeWeight } from './runs/effectiveRangeStyle';\nimport type { RangeStyle, RunStylePatch } from './runs/rangeStyle';\n\n/**\n * A styling a shortcut or a control toggles. The additive booleans, plus the\n * two `script` values — which are exclusive rather than additive, so they\n * toggle against one enum rather than each owning a boolean.\n */\nexport type StyleToggle = FlagKey | 'super' | 'sub';\n\n/**\n * The shortcut each styling answers to. Strikethrough takes Cmd+Shift+X\n * (Docs' binding) and MUST require shift: bare Cmd+X is cut, and swallowing\n * it here would break cutting text mid-edit. Superscript takes Word's\n * Cmd+Shift+=; subscript takes Cmd+Shift+- rather than Word's Cmd+-, because\n * the unshifted pair is browser zoom, which a page cannot cancel.\n * `overline` has no shortcut — no editor has established one — and is\n * reachable only from a control.\n *\n * Matching is on the *unshifted* character (`shiftedKey`): a US layout\n * reports Cmd+Shift+= as `'+'` and Cmd+Shift+- as `'_'`, so keying the table\n * on what the legend says needs that mapping to survive the shift.\n *\n * Underline has to be intercepted, not merely supported. Left alone, the\n * browser runs its own `formatUnderline` and `domToRuns`' `<u>` flattening\n * makes that *look* like it worked while bypassing `patchForToggle`\n * entirely — no toggle-off, no mixed-range \"turn the whole selection on\"\n * rule, no pending style for a collapsed caret. The flattening stays\n * regardless, since it is what lets pasted decoration survive, but it is\n * defense in depth and was never the mechanism.\n */\nconst STYLE_SHORTCUTS: ReadonlyArray<{ key: string; shift: boolean; toggle: StyleToggle }> = [\n { key: 'b', shift: false, toggle: 'bold' },\n { key: 'i', shift: false, toggle: 'italic' },\n { key: 'u', shift: false, toggle: 'underline' },\n { key: 'x', shift: true, toggle: 'strikethrough' },\n { key: '=', shift: true, toggle: 'super' },\n { key: '-', shift: true, toggle: 'sub' },\n];\n\n/** The characters shift produces from the keys the table names. */\nconst UNSHIFT: Readonly<Record<string, string>> = { '+': '=', _: '-' };\n\n/** The styling `e` toggles, or null when it isn't a styling shortcut. */\nfunction toggleForKey(e: KeyboardEvent): StyleToggle | null {\n if (!e.metaKey && !e.ctrlKey) return null;\n const raw = e.key.toLowerCase();\n const key = UNSHIFT[raw] ?? raw;\n return STYLE_SHORTCUTS.find((s) => s.key === key && s.shift === e.shiftKey)?.toggle ?? null;\n}\n\n/**\n * The patch that toggles `toggle` against the styling in `current`: if it is\n * already carried, clear it; otherwise set it — so a mixed range turns fully\n * on, as in every other text editor. `script` clears to `undefined` rather\n * than to `false`, since the off state of an enum is its absence.\n *\n * `nodeStyle` is read as well as `current`, and has to be: a node flag\n * renders on every run whether or not the runs carry it, so a toggle that\n * consulted the runs alone would read Cmd+B inside a `fontWeight: 700` node\n * as \"not bold\" and *add* bold rather than clearing it. `script` has no node\n * level to consult — by design; see `StyledRun.script`.\n */\nfunction patchForToggle(\n current: RangeStyle,\n toggle: StyleToggle,\n nodeStyle: TextStyle,\n): RunStylePatch {\n if (toggle === 'super' || toggle === 'sub') {\n return { script: current.script === toggle ? undefined : toggle };\n }\n const on = toggle === 'bold'\n ? rangeWeight(current, nodeStyle).bold === true\n : current[toggle] === true || nodeHasFlag(nodeStyle, toggle);\n return { [toggle]: !on };\n}\n\n/**\n * The styling at a collapsed caret: the run to its left, or — at the very\n * start of the text — the run to its right. This is what the next typed\n * character inherits, so it is what a character bar should be showing.\n */\nfunction styleAtCaret(runs: readonly StyledRun[], at: number): RangeStyle {\n return at > 0 ? styleAtRange(runs, at - 1, at) : styleAtRange(runs, 0, 1);\n}\n\n/**\n * Splice `run` into `runs` at character offset `at`, splitting whichever run\n * spans it. The result is normalized (empty runs dropped, identical\n * neighbours merged) by the same algebra every other write goes through.\n */\nfunction spliceRunAt(runs: readonly StyledRun[], at: number, run: StyledRun): StyledRun[] {\n const out: StyledRun[] = [];\n let pos = 0;\n let placed = false;\n for (const r of runs) {\n const end = pos + r.text.length;\n if (!placed && at <= end) {\n const k = at - pos;\n if (k > 0) out.push({ ...r, text: r.text.slice(0, k) });\n out.push(run);\n if (k < r.text.length) out.push({ ...r, text: r.text.slice(k) });\n placed = true;\n } else {\n out.push({ ...r });\n }\n pos = end;\n }\n if (!placed) out.push(run);\n // An empty patch over an empty range: this is the array-wide normalization\n // pass, not a styling.\n return applyStyleToRange(out, 0, 0, {});\n}\n\n/**\n * Return focus to the overlay after a styling arrived from editor chrome.\n *\n * A control that took focus in order to be clicked still holds it when the\n * patch lands, so the next keystroke goes to that button — and in an app that\n * binds bare letters to tools, \"click Superscript, then type the 2\" activates\n * the Text tool and pans the canvas instead of typing a 2. Restoring the\n * caret is what makes a styling control usable mid-edit at all.\n *\n * Two things are left holding focus deliberately: a text entry in the chrome\n * (the user is still typing a font size — stealing that is worse than the\n * problem) and anything inside an open dialog, which is where a color\n * picker's live `onChange` fires from.\n */\nfunction restoreOverlayFocus(overlay: HTMLElement, range: TextEditSelection): void {\n const active = document.activeElement;\n if (active === overlay || overlay.contains(active)) return;\n if (\n active instanceof HTMLInputElement\n || active instanceof HTMLTextAreaElement\n || (active instanceof HTMLElement && active.isContentEditable)\n || (active instanceof Element && active.closest('[role=\"dialog\"]') !== null)\n ) return;\n overlay.focus();\n const a = charOffsetToDomPosition(overlay, range.start);\n const b = charOffsetToDomPosition(overlay, range.end);\n const sel = window.getSelection();\n if (!a || !b || !sel) return;\n const r = document.createRange();\n r.setStart(a.node, a.offset);\n r.setEnd(b.node, b.offset);\n sel.removeAllRanges();\n sel.addRange(r);\n}\n\n/**\n * Put the caret *between* two run spans when `offset` falls on the boundary\n * of one, rather than at the same offset inside the left span's text node.\n *\n * The two positions are the same character offset and browsers report them\n * identically, but they type differently: a caret inside a span has the next\n * character absorbed by that run, and one between spans starts a fresh one.\n * That distinction is the whole point after a pending style has just been\n * committed to its own run — otherwise the character after a superscript is\n * superscript too. Leaves the selection alone when the offset falls mid-run,\n * where there is no boundary to prefer.\n */\nfunction placeCaretBetweenRuns(\n overlay: HTMLElement,\n runs: readonly StyledRun[],\n offset: number,\n): void {\n let acc = 0;\n let index = -1;\n for (let i = 0; i < runs.length; i++) {\n acc += runs[i].text.length;\n if (acc === offset) { index = i; break; }\n if (acc > offset) return;\n }\n const span = index >= 0 ? overlay.children[index] : null;\n const sel = window.getSelection();\n if (!span || !sel) return;\n const range = document.createRange();\n range.setStartAfter(span);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/** No pending style. One frozen object so re-publishing an already-empty\n * pending style doesn't re-render every consumer. */\nconst NO_PENDING: RunStylePatch = Object.freeze({});\n\n/**\n * Merge `patch` into a pending style. A key set to `false` or `undefined` is\n * deleted rather than stored — the same canonical form `patchRun` keeps, so\n * the pending style and a stored run agree on what \"off\" looks like, and\n * bold and a weight supersede each other here as they do there.\n */\nfunction mergePending(prev: RunStylePatch, patch: RunStylePatch): RunStylePatch {\n const next: Record<string, unknown> = { ...prev };\n const superseded = supersededKey(patch);\n if (superseded !== undefined) delete next[superseded];\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined || value === false) delete next[key];\n else next[key] = value;\n }\n return next as RunStylePatch;\n}\n\n/**\n * The caret's character range within the text being edited. Half-open\n * `[start, end)` over the concatenated run text, normalized so `start <= end`\n * regardless of which way the user dragged. `start === end` is a collapsed\n * caret — a real position, not the absence of one, which is why the hook\n * reports `null` rather than a zero-width range when there is no caret.\n */\nexport interface TextEditSelection {\n start: number;\n end: number;\n}\n\n/**\n * Character offsets of the current DOM selection within `overlay`, or `null`\n * when there is no selection or it lies outside the overlay. The one\n * DOM→offset conversion in the hook; everything that needs offsets goes\n * through here.\n */\nfunction readSelectionOffsets(overlay: HTMLElement): TextEditSelection | null {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n const range = sel.getRangeAt(0);\n if (!overlay.contains(range.startContainer) || !overlay.contains(range.endContainer)) {\n return null;\n }\n // `Range` boundary points are already in document order, so this is the\n // normalization for a backwards drag — anchor/focus are not consulted.\n const start = domPositionToCharOffset(overlay, range.startContainer, range.startOffset);\n const end = domPositionToCharOffset(overlay, range.endContainer, range.endOffset);\n return start <= end ? { start, end } : { start: end, end: start };\n}\n\n/**\n * Replace the overlay's contents with `runs` and put the caret back on\n * `[start, end)`. Rewriting the DOM destroys the selection, and losing it\n * after every styling change would mean re-selecting the word to apply a\n * second style — so this is the only way styling writes back.\n *\n * The caret is **not** restored while focus sits in a text-entry control.\n * Browsers route editing commands by selection rather than by focus, so a\n * document selection put back inside the contenteditable while a bar's\n * number field has focus means the very Enter that committed that field also\n * runs its `insertParagraph` default over the restored range — replacing the\n * text that was just styled with a line break. (Observed in Chrome.)\n *\n * Focus on a *button* is the opposite case and must still restore: toggling\n * bold, then italic, then underline is one flow over one selection, and\n * clicking a toolbar button does take focus. Buttons turn keystrokes into\n * clicks, not into editing commands, so the range is safe there.\n *\n * The hook remembers the range as character offsets either way, so a skipped\n * restore costs the highlight, never the target.\n */\nfunction writeRunsPreservingSelection(\n overlay: HTMLElement,\n runs: readonly StyledRun[],\n start: number,\n end: number,\n base: OverlayRunBase,\n): void {\n const active = document.activeElement;\n const inTextEntry =\n active !== overlay &&\n !overlay.contains(active) &&\n (active instanceof HTMLInputElement ||\n active instanceof HTMLTextAreaElement ||\n (active instanceof HTMLElement && active.isContentEditable));\n runsToDom(runs, overlay, base);\n if (inTextEntry) return;\n const a = charOffsetToDomPosition(overlay, start);\n const b = charOffsetToDomPosition(overlay, end);\n const sel = window.getSelection();\n if (!a || !b || !sel) return;\n const range = document.createRange();\n range.setStart(a.node, a.offset);\n range.setEnd(b.node, b.offset);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * Drop the one trailing newline a contenteditable keeps so the caret has\n * somewhere to sit on the last line. `domToRuns` maps the `<br>` to a\n * literal `'\\n'`, which the edit never typed. Exactly one, so a newline\n * the user actually typed survives — the holder is never doubled.\n *\n * An empty run left behind is dropped: it carries no text and would otherwise\n * defeat `runsCarryStyling`'s \"did this edit produce styling\" question by\n * existing.\n */\nfunction trimCaretHolder(runs: StyledRun[]): StyledRun[] {\n const last = runs[runs.length - 1];\n if (last === undefined || !last.text.endsWith('\\n')) return runs;\n const trimmed = { ...last, text: last.text.slice(0, -1) };\n const head = runs.slice(0, -1);\n return trimmed.text === '' ? head : [...head, trimmed];\n}\n\nfunction sameSelection(a: TextEditSelection | null, b: TextEditSelection | null): boolean {\n if (a === null || b === null) return a === b;\n return a.start === b.start && a.end === b.end;\n}\n\n/** Screen-space pose passed to `useTextEdit` so the overlay can be placed and sized in CSS pixels. */\nexport interface TextEditScreenPose {\n /** Top-left in CSS pixels relative to `container`. Always screen pixels,\n * including when `zoom` is set — the scale is anchored at this point, not\n * translated by it. */\n x: number;\n y: number;\n /** Pre-scale — CSS pixels, or world units when `zoom` is set. */\n width: number;\n height: number;\n /** Pre-scale font size: `style.fontSize * zoom` when `zoom` is omitted, the\n * world-unit `style.fontSize` when it is set. */\n fontSize: number;\n /** Effective on-screen line height multiplier (defaults to style.lineHeight). */\n lineHeight?: number;\n /**\n * Where the text sits within `height`, as the canvas places it. `'center'`\n * and `'bottom'` size the overlay to its own content and offset it by the\n * slack, re-measured as typing changes the line count. Default `'top'`.\n */\n verticalAlign?: TextVerticalAlign;\n /**\n * CSS scale applied to the overlay (`transform: scale(zoom)`, anchored at\n * its top-left). Every other size on this pose, and every typographic\n * metric the hook writes, is then **pre-scale** — pass world units and the\n * transform does the world→screen conversion.\n *\n * This is the only way run-level typography can be correct at a zoom other\n * than 1. `runsToDom` emits run `fontSize` / `letterSpacing` in world units\n * and `domToRuns` reads them straight back; threading a scale through the\n * writer and its inverse through the reader would go lossy on fractional\n * zooms. Scaling the whole overlay instead leaves that serializer pure and\n * scales node-level and run-level values by the same factor for free.\n *\n * Omit it (the default, `1`) and the pose is plain screen pixels — the hook\n * then infers the world→screen factor from `fontSize / style.fontSize` to\n * scale node-level `letterSpacing`, and run-level overrides are left\n * unscaled. Correct only at zoom 1.\n */\n zoom?: number;\n}\n\n/** A box in CSS pixels relative to `useTextEdit`'s `container`. */\nexport interface TextEditClipRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** Options for `useTextEdit`. */\nexport interface UseTextEditOptions {\n /** Element the overlay is appended to. Must be `position: relative`/absolute. */\n container: HTMLElement | null;\n /** Read the current text for `id`. */\n getText: (id: string) => string;\n /** Read style for `id` (used for font setup on the overlay). */\n getStyle: (id: string) => TextStyle | undefined;\n /**\n * Read the node's paint for `id` — its `data.fill` / `data.stroke`. The\n * overlay paints its text and caret from the fill, so omitting this\n * renders every node's editor in the default black however the node\n * itself is painted.\n */\n getPaint?: (id: string) => TextPaint | undefined;\n /**\n * Write style back for `id`. Optional; needed only to turn a flag **off**\n * inside a node whose own `TextStyle` sets it. Run flags are additive, so\n * that edit is expressed by lowering the node flag and raising it on the\n * runs outside the selection — which needs somewhere to put the new node\n * style. Without this, such a toggle is declined and nothing changes, as\n * before. See `runs/flagRange`.\n */\n setStyle?: (id: string, style: TextStyle) => void;\n /** Read screen-space pose for `id`. Called per frame while editing. */\n getScreenPose: (id: string) => TextEditScreenPose | null;\n /**\n * The box, in CSS pixels relative to `container`, the overlay is visible\n * within — where the canvas clips the glyphs the overlay stands in for.\n * Re-read every frame. Omit it, or return `null`, to clip nothing.\n *\n * The clip cannot scroll, so a caret moving past its edge leaves the page\n * where it is; a scrollable container would drag the canvas after the caret.\n */\n getClipRect?: () => TextEditClipRect | null;\n /** Commit text. Caller wraps in op/undo. */\n setText: (id: string, text: string) => void;\n /**\n * Optional: read the current rich-text runs for `id`. When provided AND\n * returns a non-empty array, the overlay renders the runs as styled\n * `<span data-run>` elements; otherwise the overlay is seeded with plain\n * text via `getText`.\n */\n getRuns?: (id: string) => readonly StyledRun[] | undefined;\n /**\n * Optional: commit rich-text runs back to the node. When omitted, only\n * `setText` is called with the plain-text form on commit. When provided,\n * commit calls both `setText` (with `runsToPlainText(runs)`) and\n * `setRuns(id, runs)` — but only when runs are actually in play: the node\n * already had some, or the edit produced styling. A plain-text edit of a\n * plain-text node still calls `setText` alone, so a node that has never\n * been styled doesn't grow a single-run `runs` array just for being edited.\n */\n setRuns?: (id: string, runs: StyledRun[]) => void;\n /**\n * Is `el` part of the editor's own chrome — a character-options bar, a\n * color popover, anything whose whole purpose is to style the text being\n * edited? Focus moving into one does not end the edit.\n *\n * Without this, the controls the feature exists for are exactly what\n * destroys it: clicking a size field blurs the overlay, blur commits, and\n * the caret the control was about to act on is gone. Toggle buttons can\n * dodge it by `preventDefault()`-ing their own mousedown, but a field the\n * user has to type into cannot.\n *\n * Chrome focus does not disturb the reported `selection` either — see\n * `UseTextEditReturn.selection`.\n */\n isEditorChrome?: (el: Element) => boolean;\n /** What Escape does to the edit: `'cancel'` (the default) drops it,\n * `'commit'` keeps the text as Enter would. */\n escape?: 'cancel' | 'commit';\n /**\n * How long, in ms, an edit opening waits for the overlay's face before\n * showing the text in the fallback. Defaults to {@link TEXT_EDIT_FONT_HOLD}.\n *\n * The overlay stands in for canvas text the host has hidden, so the wait\n * shows nothing at all; past it, the fallback shows and reflows to the real\n * face when that lands. A face already loaded — the usual case, since\n * `@weasel-js/font` builds it as soon as its bytes arrive — shows at once.\n * `0` never waits.\n */\n fontHold?: number;\n}\n\n/**\n * The default {@link UseTextEditOptions.fontHold}: at 100ms a blank edit\n * still reads as an instant response, and it is the block period CSS gives\n * `font-display: fallback` for the same trade.\n */\nexport const TEXT_EDIT_FONT_HOLD = 100;\n\n/** Options for `useTextEdit().startEdit`. */\nexport interface StartEditOptions {\n /**\n * Where to place the caret on edit start. Number = caret offset (0..text.length);\n * `'all'` selects the whole text (default — preserves the prior behavior).\n */\n caret?: number | 'all';\n}\n\n/** Return shape of `useTextEdit`. */\nexport interface UseTextEditReturn {\n editingId: string | null;\n startEdit: (id: string, opts?: StartEditOptions) => void;\n cancelEdit: () => void;\n commit: () => void;\n isEditing: (id: string) => boolean;\n /**\n * The caret's character range, or `null` when nothing is being edited. A\n * collapsed caret reports `{ start: n, end: n }`, so `null` and \"caret at\n * n\" stay distinguishable — a styling written at a collapsed caret arms\n * {@link UseTextEditReturn.pendingStyle} instead of restyling a range.\n *\n * Follows the DOM selection, which browsers (and jsdom) report from a task\n * rather than synchronously; anything this hook writes itself updates it\n * synchronously. A DOM selection that leaves the overlay does **not** clear\n * it: that is what happens when the user clicks a styling control, and\n * reporting `null` there would read as \"collapsed caret\" and send the\n * control's patch to the node instead of to the range. It is cleared on\n * `startEdit` and when the edit ends.\n */\n selection: TextEditSelection | null;\n /**\n * The styling shared by every run in `selection` — a concrete value where\n * the range agrees, `MIXED` where it doesn't. `null` exactly when\n * `selection` is `null`. A collapsed caret reports the styling *at* the\n * caret (the run to its left, or the run to its right at offset 0), which\n * is what the next typed character inherits.\n *\n * This does not include {@link UseTextEditReturn.pendingStyle}. A control\n * showing what the next character will look like wants both, merged in\n * that order; one showing what is already written wants only this.\n */\n rangeStyle: RangeStyle | null;\n /**\n * Styling armed at a collapsed caret, applied to the next character typed\n * and then dropped. `{}` when nothing is armed — which is always the case\n * while `selection` covers a real range, since a range is styled directly.\n *\n * Moving the caret abandons it, as in any other editor.\n */\n pendingStyle: RunStylePatch;\n /**\n * Write `patch` over `selection`. A no-op with no active edit or an empty\n * patch. Over a real range this restyles the runs under it; at a collapsed\n * caret it merges into `pendingStyle` instead, so the styling lands on\n * what gets typed next rather than on text the user didn't select.\n *\n * Lowering a flag the *node* sets is neither of those — a run cannot say\n * \"not italic\" — so it rewrites instead: the node flag is cleared and raised\n * on every run outside the range. Bold is spared that: a run's own\n * `fontWeight` can say \"regular\", so it is written over the range.\n *\n * The caret survives, so a second style can be applied without\n * re-selecting, and `rangeStyle` reflects the write before this returns.\n */\n applyStyleToSelection: (patch: RunStylePatch) => void;\n /**\n * Toggle one styling over `selection` — set it if the range doesn't\n * uniformly carry it, clear it if it does. The shape a B / I / x² control\n * or a keyboard shortcut wants, and what this hook's own shortcuts call.\n */\n toggleStyle: (toggle: StyleToggle) => void;\n}\n\n/** In-place text editing via a contenteditable overlay positioned over the text node's screen-space pose. */\nexport function useTextEdit(\n opts: UseTextEditOptions,\n): UseTextEditReturn {\n const optsRef = useLatest(opts);\n\n const [editingId, setEditingId] = useState<string | null>(null);\n // `applyStyleToSelection` needs the node being edited to reach its\n // `TextStyle`, and is called from event handlers rather than from render.\n const editingIdRef = useLatest(editingId);\n const overlayRef = useRef<HTMLDivElement | null>(null);\n /** The editing node's resolved style, which run spans inheriting small caps\n * are split by whenever the runs are rewritten. */\n const baseRef = useRef<OverlayRunBase>(resolveTextStyle(undefined));\n // The overlay-follow loop is built inside the editing effect; the gate's\n // frame callback reaches it through this ref.\n const tickRef = useRef<() => void>(() => {});\n const frameLoop = useVisibleRaf(() => { tickRef.current(); });\n const initialCaretRef = useRef<number | 'all'>('all');\n const [selection, setSelection] = useState<TextEditSelection | null>(null);\n const [rangeStyle, setRangeStyle] = useState<RangeStyle | null>(null);\n const [pendingStyle, setPendingStyle] = useState<RunStylePatch>(NO_PENDING);\n /** The pending style, read synchronously by `beforeinput` — which fires\n * well before React has re-rendered with the state above. */\n const pendingRef = useRef<RunStylePatch>(NO_PENDING);\n /** The caret offset the pending style was armed at, or `null` when nothing\n * is armed. Publishing any other range abandons it. */\n const pendingAtRef = useRef<number | null>(null);\n\n const armPending = useCallback((next: RunStylePatch, at: number) => {\n const empty = Object.keys(next).length === 0;\n pendingRef.current = empty ? NO_PENDING : next;\n pendingAtRef.current = empty ? null : at;\n setPendingStyle(pendingRef.current);\n }, []);\n\n const dropPending = useCallback(() => {\n if (pendingAtRef.current === null) return;\n pendingRef.current = NO_PENDING;\n pendingAtRef.current = null;\n setPendingStyle(NO_PENDING);\n }, []);\n\n /**\n * The published range, mirrored in a ref. `applyStyleToSelection` reads it\n * synchronously, and it is the fallback when the DOM selection has moved\n * into editing chrome. Cleared with the state, never separately.\n */\n const selectionRef = useRef<TextEditSelection | null>(null);\n\n /**\n * Recompute the published caret range and its styling from the overlay.\n * Called from the `selectionchange` listener and directly after anything\n * the hook writes, so a control reading `rangeStyle` right after a patch\n * sees the new value rather than flickering back to the old one.\n *\n * A selection that is not inside the overlay leaves the published range\n * alone rather than clearing it. That state means focus moved into a\n * control — which is precisely when the range matters most, and reporting\n * `null` would read to a consumer as \"collapsed caret\" and send its patch\n * to the wrong target. The range is cleared where it is actually over: on\n * `startEdit` and on teardown.\n */\n /** Publish `range` and the styling the overlay currently carries across it. */\n const publishRange = useCallback((overlay: HTMLElement, range: TextEditSelection) => {\n const collapsed = range.start === range.end;\n // A pending style belongs to the caret position it was armed at. Any\n // other range means the caret moved, which abandons it.\n if (pendingAtRef.current !== null\n && !(collapsed && range.start === pendingAtRef.current)) {\n dropPending();\n }\n selectionRef.current = range;\n setSelection((prev) => (sameSelection(prev, range) ? prev : range));\n const runs = domToRuns(overlay);\n setRangeStyle(collapsed\n ? styleAtCaret(runs, range.start)\n : styleAtRange(runs, range.start, range.end));\n }, [dropPending]);\n\n const syncSelection = useCallback(() => {\n const overlay = overlayRef.current;\n if (!overlay) return;\n const next = readSelectionOffsets(overlay);\n if (next === null) return;\n publishRange(overlay, next);\n }, [publishRange]);\n\n /** Drop the published range — the edit session it described is over. */\n const clearSelection = useCallback(() => {\n selectionRef.current = null;\n setSelection(null);\n setRangeStyle(null);\n dropPending();\n }, [dropPending]);\n\n const cancelEdit = useCallback(() => {\n setEditingId(null);\n }, []);\n\n const commit = useCallback(() => {\n const id = editingId;\n const overlay = overlayRef.current;\n if (id == null || !overlay) {\n setEditingId(null);\n return;\n }\n // What decides this is whether *runs* are in play at the end of the\n // edit — not whether the overlay was seeded from them. Mirroring the\n // init-time guard (`getRuns` returned something non-empty) was the old\n // rule, and it silently dropped every styling a freshly created text\n // node acquired: no prior runs, so commit took the plain-text branch and\n // `domToRuns`' output went in the bin. So two ways in:\n //\n // - the node already had runs — they have to be rewritten even when the\n // edit ended up unstyled, or stale styling survives a Cmd-B that\n // turned it off; or\n // - the edit produced styling, whatever the node started as.\n //\n // A plain-text edit of a plain-text node satisfies neither and commits\n // text alone, so a node that has no `runs` doesn't grow a single-run\n // array just for being edited.\n const priorRuns = optsRef.current.getRuns?.(id);\n const setRuns = optsRef.current.setRuns;\n const runs = trimCaretHolder(domToRuns(overlay));\n const hadRuns = priorRuns != null && priorRuns.length > 0;\n // Read from the DOM, not `innerText`: a browser applies `text-transform`\n // to what that reports, and a break stand-in reads back as its `\\n`.\n optsRef.current.setText(id, runsToPlainText(runs));\n if (setRuns && (hadRuns || runsCarryStyling(runs))) setRuns(id, runs);\n setEditingId(null);\n }, [editingId, optsRef]);\n\n const startEdit = useCallback((id: string, opts?: StartEditOptions) => {\n initialCaretRef.current = opts?.caret ?? 'all';\n setEditingId(id);\n }, []);\n\n const isEditing = useCallback((id: string) => editingId === id, [editingId]);\n\n const applyStyleToSelection = useCallback((patch: RunStylePatch) => {\n const overlay = overlayRef.current;\n if (!overlay) return;\n // An empty patch would still round-trip the runs through\n // `applyStyleToRange`, whose normalization applies to the whole array and\n // not just the patched span. Nothing asked for that, so don't do it.\n if (Object.keys(patch).length === 0) return;\n // Fall back to the last range that WAS in the overlay: the caller may be\n // a control that took focus (and with it the DOM selection) to be\n // clicked. `writeRunsPreservingSelection` puts the range back afterwards,\n // so a second styling can follow without re-selecting either way.\n const range = readSelectionOffsets(overlay) ?? selectionRef.current;\n if (!range) return;\n\n // Lowering a flag the node itself sets is not expressible additively —\n // the run algebra can only add — so it takes the rewrite in\n // `setFlagOverRange`: clear the node flag, raise it outside the range.\n // This is the one styling that reaches existing text from a collapsed\n // caret, and has to: \"stop being bold from here on\" is otherwise\n // unsayable in a bold node.\n const id = editingIdRef.current;\n const setStyle = optsRef.current.setStyle;\n const runs = domToRuns(overlay);\n if (patch.bold === false && !('fontWeight' in patch) && id !== null) {\n patch = { ...patch, ...unboldPatch(optsRef.current.getStyle(id) ?? {}) };\n }\n const unsetFlag = id !== null && setStyle\n ? (Object.keys(patch) as FlagKey[]).find((key) =>\n key !== 'bold'\n && patch[key] === false\n && nodeHasFlag(optsRef.current.getStyle(id) ?? {}, key))\n : undefined;\n if (unsetFlag !== undefined && id !== null && setStyle) {\n const nodeStyle = optsRef.current.getStyle(id) ?? {};\n const r = setFlagOverRange(runs, nodeStyle, range.start, range.end, unsetFlag, false);\n setStyle(id, r.style);\n writeRunsPreservingSelection(overlay, r.runs, range.start, range.end, baseRef.current);\n publishRange(overlay, range);\n // The rewrite raised the flag on every existing run, so a caret sitting\n // at the end of one is now *inside* a flagged span and the next\n // character would be absorbed by it. Arming the `false` keeps it out:\n // it is not a storable run value, but it is enough to make\n // `beforeinput` open a fresh span, which `runsToDom` then emits bare.\n if (range.start === range.end) {\n armPending({ ...pendingRef.current, [unsetFlag]: false }, range.start);\n }\n restoreOverlayFocus(overlay, range);\n // Whatever else the patch carried still applies on its own terms.\n const rest = { ...patch };\n delete rest[unsetFlag];\n if (Object.keys(rest).length > 0) applyStyleToSelection(rest);\n return;\n }\n\n // A collapsed caret has no run to restyle, so the styling is armed for\n // the next character instead of silently doing nothing.\n if (range.start === range.end) {\n armPending(mergePending(pendingRef.current, patch), range.start);\n restoreOverlayFocus(overlay, range);\n return;\n }\n\n const next = applyStyleToRange(runs, range.start, range.end, patch);\n writeRunsPreservingSelection(overlay, next, range.start, range.end, baseRef.current);\n restoreOverlayFocus(overlay, range);\n // Republish from the range we just styled, not from the DOM selection:\n // when the patch came from chrome the selection is in that control, and\n // re-reading it would leave a consumer showing the pre-patch styling.\n publishRange(overlay, range);\n }, [publishRange, armPending, editingIdRef, optsRef]);\n\n const toggleStyle = useCallback((toggle: StyleToggle) => {\n const overlay = overlayRef.current;\n if (!overlay) return;\n const range = readSelectionOffsets(overlay) ?? selectionRef.current;\n if (!range) return;\n const runs = domToRuns(overlay);\n const id = editingIdRef.current;\n const nodeStyle = (id !== null ? optsRef.current.getStyle(id) : undefined) ?? {};\n // At a collapsed caret the styling in play is what the caret sits in plus\n // whatever is already armed, so pressing Cmd+B twice disarms rather than\n // arming a second time.\n const current = range.start === range.end\n ? patchRangeStyle(styleAtCaret(runs, range.start), pendingRef.current)\n : styleAtRange(runs, range.start, range.end);\n applyStyleToSelection(patchForToggle(current, toggle, nodeStyle));\n }, [applyStyleToSelection, editingIdRef, optsRef]);\n\n useEffect(() => {\n if (editingId == null) return;\n const { container, getText, getStyle, getPaint } = optsRef.current;\n if (!container) return;\n\n const style = resolveTextStyle(getStyle(editingId), getPaint?.(editingId));\n const overlay = document.createElement('div');\n const overlayClass = `weasel-text-edit-${++OVERLAY_SEQ}`;\n overlay.classList.add(overlayClass);\n overlay.setAttribute('contenteditable', 'true');\n overlay.spellcheck = false;\n baseRef.current = style;\n const initialRuns = optsRef.current.getRuns?.(editingId);\n if (initialRuns && initialRuns.length > 0) {\n runsToDom(initialRuns, overlay, style);\n } else if (style.fontVariantCaps === 'small-caps') {\n // Small caps needs its lowercase in pieces, which only a run span holds.\n runsToDom([{ text: getText(editingId) }], overlay, style);\n } else {\n // Not `innerText`, which turns each newline into a `<br>` the caret\n // walkers cannot count and U+2028 into a space.\n appendOverlayText(overlay, getText(editingId));\n }\n applyOverlayStyle(overlay, style);\n const hold = holdForFaces(style, initialRuns ?? []);\n if (hold) overlay.style.opacity = '0';\n const styleEl = installSelectionStyle(overlayClass, style);\n const clipBox = createClipBox();\n clipBox.appendChild(overlay);\n container.appendChild(clipBox);\n overlayRef.current = overlay;\n\n const place = () => {\n const clip = optsRef.current.getClipRect?.() ?? null;\n placeOverlay(overlay, clipBox, optsRef.current.getScreenPose(editingId), clip, style);\n };\n place();\n // Measured again on release: the first `place` ran in the fallback face.\n let held = hold !== null;\n const release = () => {\n if (!held) return;\n held = false;\n clearTimeout(holdTimer);\n place();\n overlay.style.opacity = '';\n };\n const holdTimer = held ? setTimeout(release, optsRef.current.fontHold ?? TEXT_EDIT_FONT_HOLD) : undefined;\n void hold?.then(release);\n\n const range = document.createRange();\n const initial = initialCaretRef.current;\n if (initial === 'all') {\n range.selectNodeContents(overlay);\n } else {\n placeCaretAt(overlay, range, initial);\n }\n // Focus first, then place the caret: focusing an editable host is itself\n // a selection-moving act (jsdom collapses to the start; browsers vary),\n // so a range set beforehand is not reliably the one the user ends up with.\n overlay.focus();\n const sel = window.getSelection();\n sel?.removeAllRanges();\n sel?.addRange(range);\n // The caret exists now, so publish it rather than waiting for the\n // `selectionchange` task — a control mounted alongside the editor would\n // otherwise render one frame with no selection.\n syncSelection();\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n commit();\n return;\n }\n if (e.key === 'Escape') {\n e.preventDefault();\n if (optsRef.current.escape === 'commit') commit();\n else cancelEdit();\n return;\n }\n const toggle = toggleForKey(e);\n if (toggle) {\n e.preventDefault();\n toggleStyle(toggle);\n }\n };\n const onBlur = (e: FocusEvent) => {\n const next = e.relatedTarget;\n const isChrome = optsRef.current.isEditorChrome;\n if (isChrome && next instanceof Element && isChrome(next)) return;\n commit();\n };\n\n const onBeforeInput = (ie: InputEvent) => {\n if (ie.inputType !== 'insertText' || !ie.data) return;\n const pending = pendingRef.current;\n if (Object.keys(pending).length > 0) {\n // Rebuild from the runs rather than splicing a span into the DOM.\n // `insertNode` at a caret sitting inside a run span nests the new\n // span *within* it, and `domToRuns` reads styling down the ancestor\n // chain — so a pending style that has to escape the surrounding run\n // (the `false` armed after a node-flag rewrite) would inherit exactly\n // the flag it exists to shed. Going through the algebra also gets\n // every run field for free, with no CSS written here.\n const at = readSelectionOffsets(overlay) ?? selectionRef.current;\n if (!at || at.start !== at.end) return;\n ie.preventDefault();\n const next = spliceRunAt(domToRuns(overlay), at.start, {\n ...pending, text: ie.data,\n } as StyledRun);\n const after = at.start + ie.data.length;\n writeRunsPreservingSelection(overlay, next, after, after, baseRef.current);\n placeCaretBetweenRuns(overlay, next, after);\n dropPending();\n publishRange(overlay, { start: after, end: after });\n return;\n }\n ie.preventDefault();\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n range.deleteContents();\n {\n // No pending style — insert the character as a plain text node at the\n // caret position so the surrounding run's span absorbs it.\n const textNode = document.createTextNode(ie.data);\n range.insertNode(textNode);\n const after = document.createRange();\n after.setStartAfter(textNode);\n after.collapse(true);\n sel.removeAllRanges();\n sel.addRange(after);\n }\n resplitSmallCaps();\n };\n\n /** Put small-caps letters back in the pieces their case belongs in after\n * an edit, keeping the caret. Never mid-composition: rewriting the DOM\n * under an IME ends the composition. */\n const resplitSmallCaps = (e?: Event) => {\n if (e instanceof InputEvent && e.isComposing) return;\n const at = readSelectionOffsets(overlay);\n if (!normalizeSmallCaps(overlay) || !at) return;\n const a = charOffsetToDomPosition(overlay, at.start);\n const b = charOffsetToDomPosition(overlay, at.end);\n const sel = window.getSelection();\n if (!a || !b || !sel) return;\n const r = document.createRange();\n r.setStart(a.node, a.offset);\n r.setEnd(b.node, b.offset);\n sel.removeAllRanges();\n sel.addRange(r);\n };\n const onInput = (e: Event) => {\n resplitSmallCaps(e);\n place();\n };\n\n // Blur can't be the only way out. Once focus has moved into editing\n // chrome the overlay is no longer focused, so nothing blurs when the user\n // clicks away and the edit would never end. A pointerdown that lands\n // outside both the overlay and the chrome is that click. Capture phase so\n // it runs ahead of whatever the click was aimed at (a canvas gesture, a\n // different tool) rather than after it.\n const onPointerDownOutside = (e: Event) => {\n const target = e.target;\n if (!(target instanceof Node) || overlay.contains(target)) return;\n const isChrome = optsRef.current.isEditorChrome;\n if (isChrome && target instanceof Element && isChrome(target)) return;\n commit();\n };\n\n overlay.addEventListener('keydown', onKeyDown);\n overlay.addEventListener('blur', onBlur);\n // Typing can change the line count; re-placing here rather than on the\n // next frame keeps a center/bottom-aligned overlay from jumping a frame late.\n overlay.addEventListener('input', onInput);\n overlay.addEventListener('beforeinput', onBeforeInput);\n document.addEventListener('pointerdown', onPointerDownOutside, true);\n // `selectionchange` only exists on the document — there is no per-element\n // event for it — so this listens globally and `readSelectionOffsets`\n // filters to selections inside the overlay.\n document.addEventListener('selectionchange', syncSelection);\n\n // Follows the node's screen pose every frame — behind the visibility gate,\n // so an overlay left open in a background tab costs nothing.\n tickRef.current = () => {\n place();\n frameLoop.request();\n };\n frameLoop.request();\n\n return () => {\n held = false;\n clearTimeout(holdTimer);\n frameLoop.cancel();\n tickRef.current = () => {};\n overlay.removeEventListener('keydown', onKeyDown);\n overlay.removeEventListener('blur', onBlur);\n overlay.removeEventListener('input', onInput);\n overlay.removeEventListener('beforeinput', onBeforeInput);\n document.removeEventListener('pointerdown', onPointerDownOutside, true);\n document.removeEventListener('selectionchange', syncSelection);\n clipBox.remove();\n styleEl?.remove();\n overlayRef.current = null;\n clearSelection();\n };\n }, [editingId, optsRef, commit, cancelEdit, syncSelection, clearSelection, frameLoop,\n toggleStyle, dropPending, publishRange]);\n\n return {\n editingId, startEdit, cancelEdit, commit, isEditing,\n selection, rangeStyle, pendingStyle, applyStyleToSelection, toggleStyle,\n };\n}\n\nlet OVERLAY_SEQ = 0;\n\n/**\n * The loads the overlay's faces are still waiting on — the node's and each\n * run's that names its own family — or `null` when every one is in hand.\n */\nfunction holdForFaces(style: ResolvedTextStyle, runs: readonly StyledRun[]): Promise<unknown> | null {\n const pending = [\n cssFontFamilyLoading(style.fontFamily, {\n weight: numericWeight(style.fontWeight), style: style.fontStyle,\n }),\n ...runs.filter((r) => r.fontFamily != null).map((r) => cssFontFamilyLoading(r.fontFamily!, {\n weight: r.fontWeight ?? (r.bold ? 700 : undefined),\n style: r.italic ? 'italic' : undefined,\n })),\n ].filter((p) => p !== null);\n return pending.length === 0 ? null : Promise.all(pending);\n}\n\n/**\n * Place a collapsed caret `offset` characters into the overlay's text,\n * walking its text nodes. Out-of-range offsets clamp to the end.\n */\nfunction placeCaretAt(root: HTMLElement, range: Range, offset: number): void {\n let remaining = offset;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);\n let node: Text | null = walker.nextNode() as Text | null;\n while (node) {\n const len = node.data.length;\n if (remaining <= len) {\n range.setStart(node, remaining);\n range.setEnd(node, remaining);\n return;\n }\n remaining -= len;\n node = walker.nextNode() as Text | null;\n }\n // Fallback: collapse at end of the root.\n range.selectNodeContents(root);\n range.collapse(false);\n}\n\n/** The overlay's positioning parent. Passes pointer input through everywhere\n * but the overlay itself, which spans no more than the canvas it covers. */\nfunction createClipBox(): HTMLDivElement {\n const el = document.createElement('div');\n el.style.position = 'absolute';\n el.style.margin = '0';\n el.style.padding = '0';\n el.style.border = '0';\n el.style.pointerEvents = 'none';\n return el;\n}\n\nfunction applyOverlayStyle(el: HTMLDivElement, style: ResolvedTextStyle): void {\n el.style.position = 'absolute';\n el.style.pointerEvents = 'auto';\n el.style.boxSizing = 'border-box';\n el.style.margin = '0';\n el.style.padding = '0';\n el.style.border = '0';\n el.style.outline = 'none';\n el.style.background = 'transparent';\n // Unfilled text still edits in black: the overlay has to be legible, and\n // there is no CSS spelling of \"no fill\" that leaves the glyphs visible.\n el.style.color = style.fill !== null && 'color' in style.fill ? style.fill.color : '#000';\n el.style.caretColor = style.caretColor;\n // The canvas's face, not the browser's reading of the family name.\n const fontFamily = cssFontFamily(style.fontFamily, {\n weight: numericWeight(style.fontWeight), style: style.fontStyle,\n });\n el.style.font = fontString({ ...style, fontFamily });\n el.style.lineHeight = String(style.lineHeight);\n // The overlay sets no `direction`, so a justified paragraph's last line is\n // pinned to the edge the canvas puts it at rather than left to `start`.\n const edge = resolveAlign(style.align, style.direction);\n el.style.textAlign = style.align === 'justify' ? 'justify' : edge;\n el.style.setProperty('text-align-last', style.align === 'justify' ? edge : '');\n // Node-level decoration, so the overlay looks like the canvas the moment\n // editing starts. Runs are additive over the node style (a run can't un-set\n // a flag), which is exactly how CSS decoration propagates to descendants —\n // a run span adds its own decoration but can't remove this one.\n const decorations: string[] = [];\n if (style.underline) decorations.push('underline');\n if (style.strikethrough) decorations.push('line-through');\n if (style.overline) decorations.push('overline');\n el.style.textDecoration = decorations.length > 0 ? decorations.join(' ') : 'none';\n el.style.textTransform = style.textTransform;\n // The CSS spelling for what a browser reads; the scale for the pieces\n // `runsToDom` splits inheriting runs into, so they match the canvas.\n el.style.fontVariant = style.fontVariantCaps;\n el.style.setProperty(\n SMALL_CAPS_SCALE_PROPERTY,\n style.fontVariantCaps === 'small-caps'\n ? String(smallCapsScaleFor(style.fontFamily, numericWeight(style.fontWeight), style.fontStyle))\n : '',\n );\n // Line breaks follow the node's declared `wrap`, as the canvas's do. Layout\n // breaks only between words, never inside one.\n el.style.whiteSpace = style.wrap ? 'pre-wrap' : 'pre';\n el.style.overflowWrap = 'normal';\n el.style.wordBreak = 'normal';\n}\n\n/**\n * Inject a `<style>` element scoped to `overlayClass` so the edit overlay's\n * `::selection` matches the configured colors. Returns the style element so\n * the effect cleanup can remove it. Returns `null` when no selection\n * theming was requested.\n */\nfunction installSelectionStyle(\n overlayClass: string,\n style: ResolvedTextStyle,\n): HTMLStyleElement | null {\n if (style.selectionBackground == null && style.selectionColor == null) return null;\n const el = document.createElement('style');\n const decls: string[] = [];\n if (style.selectionBackground != null) {\n decls.push(`background: ${style.selectionBackground};`);\n }\n if (style.selectionColor != null) {\n decls.push(`color: ${style.selectionColor};`);\n }\n el.textContent = `.${overlayClass}::selection { ${decls.join(' ')} }`;\n document.head.appendChild(el);\n return el;\n}\n\nconst ALIGN_ANCHOR = { left: 0, center: 0.5, right: 1 } as const;\n\n/**\n * The overlay's `top`, in container pixels, for content `contentHeight` tall\n * (pre-scale, like the rest of `pose`): the pose's top, shifted by the same\n * `verticalAlign` slack the canvas applies, plus `drop` — how far below the\n * CSS line's baseline the canvas puts its own, from {@link baselineDrop}.\n * @internal\n */\nexport function overlayTop(pose: TextEditScreenPose, contentHeight: number, drop = 0): number {\n const slack = verticalAlignOffset(pose.verticalAlign, pose.height, contentHeight);\n return pose.y + (slack + drop) * (pose.zoom ?? 1);\n}\n\n/**\n * The canvas and CSS both hang a line's baseline half the leading plus one\n * ascent below the line top, from the same ascent rule, but each engine\n * rounds the font's metrics and that leading its own way, and a face that\n * states no ascent and descent hangs from its ascent alone. So the difference\n * is read from both sides rather than predicted: the canvas's from its own layout, the\n * overlay's from a zero-height inline box on a hidden line set exactly as the\n * overlay is. Pre-scale; `0` when either side has nothing to measure.\n * @internal\n */\nexport function baselineDrop(el: HTMLElement, style: ResolvedTextStyle, pose: TextEditScreenPose, lineHeight: number): number {\n const canvas = layoutTextPose({\n x: 0, y: 0, width: pose.width, height: pose.height, text: ' ',\n style: {\n fontFamily: style.fontFamily, fontWeight: style.fontWeight, fontStyle: style.fontStyle,\n fontSize: pose.fontSize, lineHeight, script: style.script,\n },\n }).laid.lines[0]?.baselineY ?? 0;\n const css = cssBaseline(el);\n return canvas > 0 && css > 0 ? canvas - css : 0;\n}\n\nconst CSS_BASELINES = new Map<string, number>();\n\nfunction cssBaseline(el: HTMLElement): number {\n const parent = el.parentElement;\n if (!parent) return 0;\n const { fontFamily, fontWeight, fontStyle, fontSize, lineHeight } = el.style;\n const key = [fontFamily, fontWeight, fontStyle, fontSize, lineHeight].join('|');\n const cached = CSS_BASELINES.get(key);\n if (cached !== undefined) return cached;\n const line = document.createElement('div');\n Object.assign(line.style, {\n position: 'absolute', left: '0', top: '0', width: '100px', margin: '0', padding: '0', border: '0',\n visibility: 'hidden', whiteSpace: 'pre', fontFamily, fontWeight, fontStyle, fontSize, lineHeight,\n });\n const mark = document.createElement('span');\n Object.assign(mark.style, { display: 'inline-block', width: '0', height: '0', verticalAlign: 'baseline' });\n line.appendChild(mark);\n parent.appendChild(line);\n const box = line.getBoundingClientRect();\n // Rect over layout width undoes any transform on an ancestor.\n const scale = box.width / 100;\n const baseline = scale > 0 ? (mark.getBoundingClientRect().top - box.top) / scale : 0;\n line.remove();\n // A web font still loading is measured as its fallback; ask again later.\n if (baseline > 0 && document.fonts?.status !== 'loading') {\n if (CSS_BASELINES.size >= 64) CSS_BASELINES.clear();\n CSS_BASELINES.set(key, baseline);\n }\n return baseline;\n}\n\nfunction placeOverlay(\n el: HTMLDivElement,\n clipBox: HTMLDivElement,\n pose: TextEditScreenPose | null,\n clip: TextEditClipRect | null,\n style: ResolvedTextStyle,\n): void {\n if (!pose) {\n el.style.display = 'none';\n return;\n }\n // `clip` rather than `hidden`: a `hidden` box is still scrollable, and the\n // browser scrolls it to keep the caret in view.\n clipBox.style.overflow = clip ? 'clip' : 'visible';\n clipBox.style.left = `${clip?.x ?? 0}px`;\n clipBox.style.top = `${clip?.y ?? 0}px`;\n clipBox.style.width = `${clip?.width ?? 0}px`;\n clipBox.style.height = `${clip?.height ?? 0}px`;\n el.style.display = '';\n // An unwrapped line can be wider than its box, and the canvas aligns it\n // about the box's left edge, center or right edge regardless. The overlay\n // sizes to its text and grows from that same anchor: `left` puts the anchor\n // there and a trailing translate pulls the box back by that fraction of its\n // own width.\n const anchor = style.wrap ? 0 : ALIGN_ANCHOR[resolveAlign(style.align, style.direction)];\n el.style.left = `${pose.x + pose.width * (pose.zoom ?? 1) * anchor - (clip?.x ?? 0)}px`;\n el.style.width = style.wrap ? `${pose.width}px` : 'max-content';\n el.style.minWidth = style.wrap ? '' : `${pose.width}px`;\n // A node-level script draws the glyphs smaller and raised on the line the\n // plain text would hold, so the line height is pinned in pixels of the\n // unscripted size rather than left to scale with the font. The rise is\n // added to `top` with the baseline correction.\n const script = style.script\n ? scriptMetricsFor(style.fontFamily, numericWeight(style.fontWeight), style.fontStyle)[style.script]\n : undefined;\n const lineHeight = pose.lineHeight ?? style.lineHeight;\n el.style.fontSize = `${pose.fontSize * (script?.size ?? 1)}px`;\n el.style.lineHeight = script ? `${pose.fontSize * lineHeight}px` : String(lineHeight);\n // A top-aligned overlay fills its box, so a click anywhere in it lands in\n // the editor. Any other alignment needs the content's own height, which a\n // min-height would mask; `offsetHeight` is pre-transform, in pose units.\n const aligned = pose.verticalAlign !== undefined && pose.verticalAlign !== 'top';\n el.style.minHeight = aligned ? '' : `${pose.height}px`;\n const drop = baselineDrop(el, style, pose, lineHeight) - (script?.shift ?? 0) * pose.fontSize;\n el.style.top = `${overlayTop(pose, aligned ? el.offsetHeight : pose.height, drop) - (clip?.y ?? 0)}px`;\n // A declared `zoom` means every size on the pose is pre-scale and the\n // overlay carries the view scale as a transform. Anchored at the top-left so\n // `left`/`top` stay screen pixels. Written unconditionally (`none` at zoom\n // 1) because the overlay element outlives an edit session and would\n // otherwise keep a stale scale.\n el.style.transformOrigin = '0 0';\n const transforms: string[] = [];\n if (pose.zoom !== undefined && pose.zoom !== 1) transforms.push(`scale(${pose.zoom})`);\n if (anchor !== 0) transforms.push(`translateX(${-anchor * 100}%)`);\n el.style.transform = transforms.length > 0 ? transforms.join(' ') : 'none';\n // `letter-spacing` is not part of the CSS `font` shorthand, so\n // `applyOverlayStyle`'s `el.style.font` never carries it — it needs its own\n // assignment. It also lives here rather than there because without a\n // transform it is the one world-unit typography value that has to be\n // re-scaled as the view zooms.\n //\n // Under a transform there is nothing to re-scale: the world value is the\n // value, and run-level overrides — which `runsToDom` writes in world units\n // — scale by the same factor. Without one, `pose.fontSize` is documented as\n // `style.fontSize * zoom`, so their ratio is the world→screen factor; run\n // overrides then stay unscaled, which is why that path is only correct at\n // zoom 1. (CSS inheritance makes a run span's own declaration *replace* this\n // value rather than add to it, in both paths.)\n const scale =\n pose.zoom !== undefined ? 1 : style.fontSize > 0 ? pose.fontSize / style.fontSize : 1;\n el.style.letterSpacing = `${style.letterSpacing * scale}px`;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { subscribeToSources as e } from "../../core/layers/render.js";
|
|
2
|
+
import { tiledProject as t } from "./tiledProject.js";
|
|
3
|
+
//#region src/features/tiling/createTiledLayer.ts
|
|
4
|
+
function n(e, t) {
|
|
5
|
+
return e === void 0 ? {
|
|
6
|
+
x: t,
|
|
7
|
+
y: t
|
|
8
|
+
} : typeof e == "number" ? {
|
|
9
|
+
x: e,
|
|
10
|
+
y: t
|
|
11
|
+
} : {
|
|
12
|
+
x: e.x ?? t,
|
|
13
|
+
y: e.y ?? t
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function r(e, t) {
|
|
17
|
+
return new Float32Array([
|
|
18
|
+
1,
|
|
19
|
+
0,
|
|
20
|
+
0,
|
|
21
|
+
0,
|
|
22
|
+
1,
|
|
23
|
+
0,
|
|
24
|
+
e,
|
|
25
|
+
t,
|
|
26
|
+
1
|
|
27
|
+
]);
|
|
28
|
+
}
|
|
29
|
+
function i(i) {
|
|
30
|
+
let { id: a, label: o, source: s, period: c, bleed: l } = i;
|
|
31
|
+
return {
|
|
32
|
+
id: a,
|
|
33
|
+
label: o,
|
|
34
|
+
space: "world",
|
|
35
|
+
subscribe: e(s),
|
|
36
|
+
draw: (e, i, a) => {
|
|
37
|
+
let o = n(typeof c == "function" ? c(i, a) : c, Infinity), u = n(l, 0), d = a.width / i.scale.x, f = a.height / i.scale.y, p = t(i.x, i.x + d, o.x, u.x), m = t(i.y, i.y + f, o.y, u.y), h = [];
|
|
38
|
+
for (let t of s) (t.space ?? "world") === "screen" && h.push(...t.draw(e, i, a));
|
|
39
|
+
let g = s.filter((e) => (e.space ?? "world") !== "screen");
|
|
40
|
+
for (let t = p.from; t <= p.to; t++) for (let n = m.from; n <= m.to; n++) {
|
|
41
|
+
let s = Number.isFinite(o.x) ? t * o.x : 0, c = Number.isFinite(o.y) ? n * o.y : 0, l = {
|
|
42
|
+
...i,
|
|
43
|
+
x: i.x - s,
|
|
44
|
+
y: i.y - c
|
|
45
|
+
}, u = [];
|
|
46
|
+
for (let t of g) u.push(...t.draw(e, l, a));
|
|
47
|
+
u.length !== 0 && h.push(s === 0 && c === 0 ? {
|
|
48
|
+
kind: "group",
|
|
49
|
+
children: u
|
|
50
|
+
} : {
|
|
51
|
+
kind: "group",
|
|
52
|
+
transform: r(s, c),
|
|
53
|
+
children: u
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return h;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { i as createTiledLayer };
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=createTiledLayer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createTiledLayer.js","names":["axes","v","fallback","translate","tx","ty","createTiledLayer","opts","subscribeToSources","source","p","period","view","dims","b","bleed","spanX","spanY","kx","tiledProject","ky","out","layer","data","tiles","i","j","shifted","children"],"sources":["../../../src/features/tiling/createTiledLayer.ts"],"sourcesContent":["import type { DrawCommand } from '../../renderer';\nimport { subscribeToSources, type Dims, type RenderLayer } from '../../core/layers/render';\nimport type { View } from '../../core/viewport/view';\nimport { tiledProject } from './tiledProject';\n\n/**\n * How far apart the copies sit, in world units. A bare number wraps the x\n * axis only — the side-scrolling backdrop this is usually reached for.\n * `{ x, y }` wraps both; naming one key wraps that axis alone.\n *\n * The period names the axes, so there is no separate `axis` option: two ways\n * to say which axes wrap is one way for them to disagree.\n */\nexport type TilePeriod = number | { x?: number; y?: number };\n\n/** How far the content reaches outside its own cell, in world units. */\nexport type TileBleed = number | { x?: number; y?: number };\n\n/** Options for {@link createTiledLayer}. */\nexport interface CreateTiledLayerOpts<TData> {\n id: string;\n label: string;\n /** Layers redrawn once per visible copy. */\n source: RenderLayer<TData>[];\n /**\n * The lattice. A function is read per draw, so the period can follow the\n * camera or the canvas — \"one screen wide\" is a period, not a constant.\n */\n period: TilePeriod | ((view: View, dims: Dims) => TilePeriod);\n /**\n * How far the source's content reaches outside the cell `[0, period)`, in\n * world units. Content that overhangs by more than it declares pops in at\n * the edge of the view instead of scrolling in. Default 0.\n */\n bleed?: TileBleed;\n}\n\ninterface Axes { x: number; y: number }\n\nfunction axes(v: TilePeriod | TileBleed | undefined, fallback: number): Axes {\n if (v === undefined) return { x: fallback, y: fallback };\n if (typeof v === 'number') return { x: v, y: fallback };\n return { x: v.x ?? fallback, y: v.y ?? fallback };\n}\n\n/** Column-major, the layout `Mat3` documents. */\nfunction translate(tx: number, ty: number): Float32Array {\n return new Float32Array([1, 0, 0, 0, 1, 0, tx, ty, 1]);\n}\n\n/**\n * Wrap source RenderLayers in a periodic lattice: the content is authored\n * once, in the cell `[0, period)`, and every copy of it the view can see is\n * drawn. Panning in either direction keeps producing copies, so the content\n * loops seamlessly with no state and no wrap-around bookkeeping.\n *\n * Each copy draws the source through a view shifted by `-k * period`, so a\n * source that culls against the view it is handed culls per copy and never\n * learns it is being tiled. The copy's commands are then translated by\n * `+k * period` in world space.\n *\n * The lattice is per layer, not per shape. Content on two different periods\n * is two tiled layers stacked, which keeps each source ignorant of the other\n * — a per-shape period would move the lattice into the source and make the\n * wrapper unable to cull.\n *\n * The plane is `space: 'world'`, which is what lets it be a `source` of\n * `createParallaxLayer`: the parallax plane hands it the derived inner view,\n * the lattice resolves against that, and the copies ride the plane.\n *\n * **A `space: 'screen'` source is drawn once, untiled** — it ignores the view\n * by definition, so every copy would land on top of the last. Same constraint\n * `createParallaxLayer` carries.\n */\nexport function createTiledLayer<TData>(\n opts: CreateTiledLayerOpts<TData>,\n): RenderLayer<TData> {\n const { id, label, source, period, bleed } = opts;\n return {\n id,\n label,\n space: 'world',\n subscribe: subscribeToSources(source),\n draw: (data, view, dims) => {\n const p = axes(typeof period === 'function' ? period(view, dims) : period, Infinity);\n const b = axes(bleed, 0);\n const spanX = dims.width / view.scale.x;\n const spanY = dims.height / view.scale.y;\n const kx = tiledProject(view.x, view.x + spanX, p.x, b.x);\n const ky = tiledProject(view.y, view.y + spanY, p.y, b.y);\n\n const out: DrawCommand[] = [];\n for (const layer of source) {\n if ((layer.space ?? 'world') === 'screen') out.push(...layer.draw(data, view, dims));\n }\n const tiles = source.filter((layer) => (layer.space ?? 'world') !== 'screen');\n\n for (let i = kx.from; i <= kx.to; i++) {\n for (let j = ky.from; j <= ky.to; j++) {\n const tx = Number.isFinite(p.x) ? i * p.x : 0;\n const ty = Number.isFinite(p.y) ? j * p.y : 0;\n const shifted: View = { ...view, x: view.x - tx, y: view.y - ty };\n const children: DrawCommand[] = [];\n for (const layer of tiles) children.push(...layer.draw(data, shifted, dims));\n if (children.length === 0) continue;\n out.push(tx === 0 && ty === 0\n ? { kind: 'group', children }\n : { kind: 'group', transform: translate(tx, ty), children });\n }\n }\n return out;\n },\n };\n}\n"],"mappings":";;;AAuCA,SAASA,EAAK,GAAuC,GAAwB;CAG3E,OAFIC,MAAM,KAAA,IAAkB;EAAE,GAAGC;EAAU,GAAGA;CAAS,IACnD,OAAOD,KAAM,WAAiB;EAAE,GAAGA;EAAG,GAAGC;CAAS,IAC/C;EAAE,GAAGD,EAAE,KAAKC;EAAU,GAAGD,EAAE,KAAKC;CAAS;AAClD;AAGA,SAASC,EAAU,GAAY,GAA0B;CACvD,OAAO,IAAI,aAAa;EAAC;EAAG;EAAG;EAAG;EAAG;EAAG;EAAGC;EAAIC;EAAI;CAAC,CAAC;AACvD;AA0BA,SAAgBC,EACd,GACoB;CACpB,IAAM,EAAE,OAAI,UAAO,WAAQ,WAAQ,aAAUC;CAC7C,OAAO;EACL;EACA;EACA,OAAO;EACP,WAAWC,EAAmBC,CAAM;EACpC,OAAO,GAAM,GAAM,MAAS;GAC1B,IAAMC,IAAIV,EAAK,OAAOW,KAAW,aAAaA,EAAOC,GAAMC,CAAI,IAAIF,GAAQ,QAAQ,GAC7EG,IAAId,EAAKe,GAAO,CAAC,GACjBC,IAAQH,EAAK,QAAQD,EAAK,MAAM,GAChCK,IAAQJ,EAAK,SAASD,EAAK,MAAM,GACjCM,IAAKC,EAAaP,EAAK,GAAGA,EAAK,IAAII,GAAON,EAAE,GAAGI,EAAE,CAAC,GAClDM,IAAKD,EAAaP,EAAK,GAAGA,EAAK,IAAIK,GAAOP,EAAE,GAAGI,EAAE,CAAC,GAElDO,IAAqB,CAAC;GAC5B,KAAK,IAAMC,KAASb,GAClB,CAAKa,EAAM,SAAS,aAAa,YAAUD,EAAI,KAAK,GAAGC,EAAM,KAAKC,GAAMX,GAAMC,CAAI,CAAC;GAErF,IAAMW,IAAQf,EAAO,QAAQ,OAAWa,EAAM,SAAS,aAAa,QAAQ;GAE5E,KAAK,IAAIG,IAAIP,EAAG,MAAMO,KAAKP,EAAG,IAAI,KAChC,KAAK,IAAIQ,IAAIN,EAAG,MAAMM,KAAKN,EAAG,IAAI,KAAK;IACrC,IAAMhB,IAAK,OAAO,SAASM,EAAE,CAAC,IAAIe,IAAIf,EAAE,IAAI,GACtCL,IAAK,OAAO,SAASK,EAAE,CAAC,IAAIgB,IAAIhB,EAAE,IAAI,GACtCiB,IAAgB;KAAE,GAAGf;KAAM,GAAGA,EAAK,IAAIR;KAAI,GAAGQ,EAAK,IAAIP;IAAG,GAC1DuB,IAA0B,CAAC;IACjC,KAAK,IAAMN,KAASE,GAAO,EAAS,KAAK,GAAGF,EAAM,KAAKC,GAAMI,GAASd,CAAI,CAAC;IAC3E,AAAIe,EAAS,WAAW,KACxBP,EAAI,KAAKjB,MAAO,KAAKC,MAAO,IACxB;KAAE,MAAM;KAAS;IAAS,IAC1B;KAAE,MAAM;KAAS,WAAWF,EAAUC,GAAIC,CAAE;KAAG;IAAS,CAAC;GAC/D;GAEF,OAAOgB;EACT;CACF;AACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/features/tiling/tiledProject.ts
|
|
2
|
+
function e(e, t, n, r = 0) {
|
|
3
|
+
return !Number.isFinite(n) || n <= 0 ? {
|
|
4
|
+
from: 0,
|
|
5
|
+
to: 0
|
|
6
|
+
} : {
|
|
7
|
+
from: Math.floor((e - r) / n),
|
|
8
|
+
to: Math.floor((t + r) / n)
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { e as tiledProject };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=tiledProject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiledProject.js","names":["tiledProject","period","visStart","bleed","visEnd"],"sources":["../../../src/features/tiling/tiledProject.ts"],"sourcesContent":["/**\n * Which copies of a periodic lattice a visible range touches.\n *\n * A tiled layer's content is authored once, in the cell `[0, period)`, and the\n * lattice repeats it at every multiple of `period`. This answers the only\n * question drawing it needs: the integer copies `k` whose cell overlaps\n * `[visStart, visEnd]`. Copy `k` draws the authored content shifted by\n * `k * period`.\n *\n * `bleed` is how far the content reaches outside its own cell, in world\n * units — the printing term, and the same idea. Content that overhangs by\n * more than it declares pops in at the edge of the view instead of scrolling\n * in.\n */\nexport interface TileRange {\n /** First copy index, inclusive. */\n from: number;\n /** Last copy index, inclusive. `to < from` means nothing is visible. */\n to: number;\n}\n\n/** The copies of a lattice with cell size `period` that `[visStart, visEnd]`\n * touches, widened by `bleed`. A non-positive or non-finite `period` answers\n * copy 0 alone. */\nexport function tiledProject(\n visStart: number,\n visEnd: number,\n period: number,\n bleed = 0,\n): TileRange {\n if (!Number.isFinite(period) || period <= 0) return { from: 0, to: 0 };\n return {\n from: Math.floor((visStart - bleed) / period),\n to: Math.floor((visEnd + bleed) / period),\n };\n}\n"],"mappings":";AAwBA,SAAgBA,EACd,GACA,GACA,GACA,IAAQ,GACG;CAEX,OADI,CAAC,OAAO,SAASC,CAAM,KAAKA,KAAU,IAAU;EAAE,MAAM;EAAG,IAAI;CAAE,IAC9D;EACL,MAAM,KAAK,OAAOC,IAAWC,KAASF,CAAM;EAC5C,IAAI,KAAK,OAAOG,IAASD,KAASF,CAAM;CAC1C;AACF"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
//#region src/features/viewports/viewResolver.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
let { views: t, root: n, canvasOrigin: r, occluded: i } = e, a = /* @__PURE__ */ new Map();
|
|
4
|
+
function o() {
|
|
5
|
+
return {
|
|
6
|
+
id: null,
|
|
7
|
+
view: n(),
|
|
8
|
+
origin: r()
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function s(e) {
|
|
12
|
+
let t = r();
|
|
13
|
+
return {
|
|
14
|
+
id: e.id,
|
|
15
|
+
view: e.view,
|
|
16
|
+
origin: {
|
|
17
|
+
left: t.left + e.rect.x,
|
|
18
|
+
top: t.top + e.rect.y
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function c(e, n) {
|
|
23
|
+
let a = r(), o = e - a.left, s = n - a.top, c = t();
|
|
24
|
+
for (let e = c.length - 1; e >= 0; e--) {
|
|
25
|
+
let { rect: t } = c[e];
|
|
26
|
+
if (o >= t.x && o < t.x + t.w && s >= t.y && s < t.y + t.h) return i?.(o, s) ? void 0 : c[e];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function l(e, t) {
|
|
30
|
+
let n = c(e, t);
|
|
31
|
+
return n ? s(n) : o();
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
begin(e, t, n) {
|
|
35
|
+
let r = l(t, n);
|
|
36
|
+
return a.set(e, r.id), r;
|
|
37
|
+
},
|
|
38
|
+
at(e, n, r) {
|
|
39
|
+
if (e !== null && a.has(e)) {
|
|
40
|
+
let n = a.get(e);
|
|
41
|
+
if (n === null) return o();
|
|
42
|
+
let r = t().find((e) => e.id === n);
|
|
43
|
+
if (r) return s(r);
|
|
44
|
+
a.delete(e);
|
|
45
|
+
}
|
|
46
|
+
return l(n, r);
|
|
47
|
+
},
|
|
48
|
+
end(e) {
|
|
49
|
+
a.delete(e);
|
|
50
|
+
},
|
|
51
|
+
clear() {
|
|
52
|
+
a.clear();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
export { e as createViewResolver };
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=viewResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewResolver.js","names":["createViewResolver","opts","pinned","rootTarget","root","canvasOrigin","target","c","v","hit","x","clientX","y","clientY","list","views","i","rect","occluded","fresh","t","pointerId","id"],"sources":["../../../src/features/viewports/viewResolver.ts"],"sourcesContent":["import type { View } from 'core/viewport/view';\n\n/**\n * @experimental\n *\n * A view the resolver can route input to: a camera and the rect it paints\n * into, in canvas CSS-pixel space. A viewport node supplies one of these per\n * frame; so could any other per-view surface.\n */\nexport interface ResolvableView {\n id: string;\n view: View;\n rect: { x: number; y: number; w: number; h: number };\n}\n\n/**\n * @experimental\n *\n * The view an input event belongs to. `id` is `null` for the root view —\n * the whole canvas, when no viewport contains the point.\n *\n * `origin` is the client-space origin of that view's surface, ready to hand\n * to `clientToWorld` — which is the whole reason this type carries it rather\n * than leaving callers to add the canvas rect and the view rect themselves.\n */\nexport interface ViewTarget {\n id: string | null;\n view: View;\n origin: { left: number; top: number };\n}\n\n/**\n * @experimental\n *\n * Routes client points to views, and holds a captured pointer on the view its\n * gesture started in.\n *\n * Stickiness is the point. A drag that leaves its view's rect — over a\n * neighbouring view, or off the canvas — must keep reporting coordinates in\n * the space it began in, or a marquee crossing a panel edge silently starts\n * measuring against the wrong camera.\n */\nexport interface ViewResolver {\n /** Resolve and pin `pointerId`. Call on pointerdown. */\n begin(pointerId: number, clientX: number, clientY: number): ViewTarget;\n /**\n * The view for a point. A pinned `pointerId` gets its pinned view, looked\n * up fresh so a rect that moved mid-gesture is honored. Pass `null` for\n * input with no pointer to capture — wheel, hover, keys.\n */\n at(pointerId: number | null, clientX: number, clientY: number): ViewTarget;\n /** Release `pointerId`. Call on pointerup and pointercancel. */\n end(pointerId: number): void;\n /** Release every pin. */\n clear(): void;\n}\n\n/**\n * @experimental\n *\n * Options for `createViewResolver`. Each field is a function called afresh on\n * every query, so views and the canvas may move between events.\n */\nexport interface CreateViewResolverOpts {\n /** Candidate views in paint order — the last one containing a point wins. */\n views: () => readonly ResolvableView[];\n /** The camera for points no view claims. */\n root: () => View;\n /** Client-space origin of the canvas element. */\n canvasOrigin: () => { left: number; top: number };\n /**\n * Whether something painted over every view claims a canvas-local point —\n * chrome on the surface's own frame. Such a point resolves to the root even\n * inside a view's rect. Asked only where a view would otherwise win.\n */\n occluded?: (x: number, y: number) => boolean;\n}\n\n/** @experimental Build a `ViewResolver` over `opts.views`, falling back to `opts.root`. */\nexport function createViewResolver(opts: CreateViewResolverOpts): ViewResolver {\n const { views, root, canvasOrigin, occluded } = opts;\n const pinned = new Map<number, string | null>();\n\n function rootTarget(): ViewTarget {\n return { id: null, view: root(), origin: canvasOrigin() };\n }\n\n function target(v: ResolvableView): ViewTarget {\n const c = canvasOrigin();\n return {\n id: v.id,\n view: v.view,\n origin: { left: c.left + v.rect.x, top: c.top + v.rect.y },\n };\n }\n\n /** Right and bottom edges are exclusive, so neighbouring views never both\n * claim a pixel. */\n function hit(clientX: number, clientY: number): ResolvableView | undefined {\n const c = canvasOrigin();\n const x = clientX - c.left;\n const y = clientY - c.top;\n const list = views();\n for (let i = list.length - 1; i >= 0; i--) {\n const { rect } = list[i]!;\n if (x >= rect.x && x < rect.x + rect.w && y >= rect.y && y < rect.y + rect.h) {\n return occluded?.(x, y) ? undefined : list[i];\n }\n }\n return undefined;\n }\n\n function fresh(clientX: number, clientY: number): ViewTarget {\n const v = hit(clientX, clientY);\n return v ? target(v) : rootTarget();\n }\n\n return {\n begin(pointerId, clientX, clientY) {\n const t = fresh(clientX, clientY);\n pinned.set(pointerId, t.id);\n return t;\n },\n at(pointerId, clientX, clientY) {\n if (pointerId !== null && pinned.has(pointerId)) {\n const id = pinned.get(pointerId)!;\n if (id === null) return rootTarget();\n const v = views().find((c) => c.id === id);\n if (v) return target(v);\n pinned.delete(pointerId);\n }\n return fresh(clientX, clientY);\n },\n end(pointerId) {\n pinned.delete(pointerId);\n },\n clear() {\n pinned.clear();\n },\n };\n}\n"],"mappings":";AA+EA,SAAgBA,EAAmB,GAA4C;CAC7E,IAAM,EAAE,UAAO,SAAM,iBAAc,gBAAaC,GAC1CC,oBAAS,IAAI,IAA2B;CAE9C,SAASC,IAAyB;EAChC,OAAO;GAAE,IAAI;GAAM,MAAMC,EAAK;GAAG,QAAQC,EAAa;EAAE;CAC1D;CAEA,SAASC,EAAO,GAA+B;EAC7C,IAAMC,IAAIF,EAAa;EACvB,OAAO;GACL,IAAIG,EAAE;GACN,MAAMA,EAAE;GACR,QAAQ;IAAE,MAAMD,EAAE,OAAOC,EAAE,KAAK;IAAG,KAAKD,EAAE,MAAMC,EAAE,KAAK;GAAE;EAC3D;CACF;CAIA,SAASC,EAAI,GAAiB,GAA6C;EACzE,IAAMF,IAAIF,EAAa,GACjBK,IAAIC,IAAUJ,EAAE,MAChBK,IAAIC,IAAUN,EAAE,KAChBO,IAAOC,EAAM;EACnB,KAAK,IAAIC,IAAIF,EAAK,SAAS,GAAGE,KAAK,GAAG,KAAK;GACzC,IAAM,EAAE,YAASF,EAAKE;GACtB,IAAIN,KAAKO,EAAK,KAAKP,IAAIO,EAAK,IAAIA,EAAK,KAAKL,KAAKK,EAAK,KAAKL,IAAIK,EAAK,IAAIA,EAAK,GACzE,OAAOC,IAAWR,GAAGE,CAAC,IAAI,KAAA,IAAYE,EAAKE;EAE/C;CAEF;CAEA,SAASG,EAAM,GAAiB,GAA6B;EAC3D,IAAMX,IAAIC,EAAIE,GAASE,CAAO;EAC9B,OAAOL,IAAIF,EAAOE,CAAC,IAAIL,EAAW;CACpC;CAEA,OAAO;EACL,MAAM,GAAW,GAAS,GAAS;GACjC,IAAMiB,IAAID,EAAMR,GAASE,CAAO;GAEhC,OADAX,EAAO,IAAImB,GAAWD,EAAE,EAAE,GACnBA;EACT;EACA,GAAG,GAAW,GAAS,GAAS;GAC9B,IAAIC,MAAc,QAAQnB,EAAO,IAAImB,CAAS,GAAG;IAC/C,IAAMC,IAAKpB,EAAO,IAAImB,CAAS;IAC/B,IAAIC,MAAO,MAAM,OAAOnB,EAAW;IACnC,IAAMK,IAAIO,EAAM,CAAC,CAAC,MAAM,MAAMR,EAAE,OAAOe,CAAE;IACzC,IAAId,GAAG,OAAOF,EAAOE,CAAC;IACtB,EAAO,OAAOa,CAAS;GACzB;GACA,OAAOF,EAAMR,GAASE,CAAO;EAC/B;EACA,IAAI,GAAW;GACb,EAAO,OAAOQ,CAAS;EACzB;EACA,QAAQ;GACN,EAAO,MAAM;EACf;CACF;AACF"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { mat3 as e } from "../../renderer/math/mat3.js";
|
|
2
|
+
import { drawOneLayer as t, subscribeToSources as n } from "../../core/layers/render.js";
|
|
3
|
+
import { normalizeView as r } from "../../core/viewport/view.js";
|
|
4
|
+
//#region src/features/viewports/viewportLayer.ts
|
|
5
|
+
function i(i) {
|
|
6
|
+
let { id: a, label: o, source: s, view: c, bounds: l, background: u, data: d } = i, f = typeof c == "function" ? null : r(c), p = (e, t) => f ?? r(c(e, t)), m = typeof s == "function" ? s : () => s;
|
|
7
|
+
return {
|
|
8
|
+
id: a,
|
|
9
|
+
label: o,
|
|
10
|
+
space: "screen",
|
|
11
|
+
subscribe: n(m),
|
|
12
|
+
resolvable(e, t) {
|
|
13
|
+
return {
|
|
14
|
+
id: a,
|
|
15
|
+
view: p(e, t),
|
|
16
|
+
rect: l(e, t)
|
|
17
|
+
};
|
|
18
|
+
},
|
|
19
|
+
draw: (n, r, i) => {
|
|
20
|
+
let a = l(r, i), o = [];
|
|
21
|
+
u && o.push({
|
|
22
|
+
kind: "path",
|
|
23
|
+
path: {
|
|
24
|
+
kind: "rect",
|
|
25
|
+
x: 0,
|
|
26
|
+
y: 0,
|
|
27
|
+
width: a.w,
|
|
28
|
+
height: a.h
|
|
29
|
+
},
|
|
30
|
+
fill: {
|
|
31
|
+
fill: "solid",
|
|
32
|
+
color: u
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
let s = {
|
|
36
|
+
width: a.w,
|
|
37
|
+
height: a.h
|
|
38
|
+
}, c = d ? d(n) : n, f = p(r, i);
|
|
39
|
+
for (let e of m()) for (let n of t(e, c, f, s)) o.push(n);
|
|
40
|
+
return [{
|
|
41
|
+
kind: "group",
|
|
42
|
+
transform: e.translated(e.identity(), a.x, a.y),
|
|
43
|
+
clip: {
|
|
44
|
+
kind: "rect",
|
|
45
|
+
x: 0,
|
|
46
|
+
y: 0,
|
|
47
|
+
width: a.w,
|
|
48
|
+
height: a.h
|
|
49
|
+
},
|
|
50
|
+
children: o
|
|
51
|
+
}];
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { i as createViewportLayer };
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=viewportLayer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewportLayer.js","names":["createViewportLayer","sourceData","opts","fixedView","view","normalizeView","viewAt","outer","dims","sourceAt","source","subscribeToSources","bounds","b","outerView","children","background","innerDims","innerData","data","v","layer","c","drawOneLayer","mat3"],"sources":["../../../src/features/viewports/viewportLayer.ts"],"sourcesContent":["import type { DrawCommand, GroupDrawCommand } from '../../renderer';\nimport { drawOneLayer, subscribeToSources, type Dims, type RenderLayer } from 'core/layers/render';\nimport { normalizeView, type View } from 'core/viewport/view';\nimport { mat3, type GlMat3 } from '../../renderer/math/mat3';\nimport type { ResolvableView } from './viewResolver';\n\n/**\n * @experimental\n *\n * A \"viewport node\" — a screen-space rectangle on the outer canvas that\n * re-renders one or more `source` layers through an *inner* `View`, then\n * clips them to its rect.\n *\n * Use cases: picture-in-picture, minimap, scrolling container, multi-angle\n * preview. The same source layer can be rendered through multiple viewports\n * (different inner views) without duplicating data — viewports are pure\n * lenses on the source.\n *\n * **Inner view semantics.** The source layers draw as if the inner view\n * filled the screen at world-origin — each is wrapped in `viewToMat3(view)`\n * by the same `drawOneLayer` the outer canvas uses. The viewport then\n * translates the result so that the inner view's origin lands at `bounds.x,\n * bounds.y` and clips to `(bounds.w, bounds.h)`. Caller chooses\n * `innerView.{x,y,scale}` to control which slice of source-world is shown.\n *\n * **This layer paints; it does not take input.** `<CanvasView>` is built on\n * it and routes the pointer stream through the kit's gesture dispatcher —\n * declare one of those for a viewport that should be clickable. `resolvable`\n * is the seam it uses: feed it to `createViewResolver` to route input to a\n * raw viewport yourself.\n *\n * **Screen-space source layers** (e.g., debug overlays, selection chrome)\n * draw in the viewport's own CSS-pixel space: their coords are relative to\n * the rect's top-left, and they clip to it, rather than to the outer canvas.\n */\nexport interface CreateViewportLayerOpts<TData, TSource = TData> {\n id: string;\n label: string;\n /** Layers re-rendered through `view`. Each receives `(data, view, dims)`\n * exactly as the outer Canvas would call it.\n *\n * Pass a thunk for a stack that is assembled elsewhere — it is read fresh\n * on every `draw`, the same way a thunked `view` is. */\n source: readonly RenderLayer<TSource>[] | (() => readonly RenderLayer<TSource>[]);\n /**\n * The `data` the source layers receive, derived from what the outer canvas\n * passed down. Omit and they get the outer canvas's own.\n *\n * A viewport showing the same scene through a second camera wants its own\n * per-view helpers here — selection, chrome state and gesture previews that\n * belong to *this* view rather than the one hosting it.\n */\n data?: (outer: TData) => TSource;\n /**\n * The inner view. Pass a thunk for a camera that moves — it is read fresh\n * on every `draw` and `resolvable`, so the two cannot\n * disagree about where the viewport is looking mid-gesture.\n *\n * The thunk receives the outer view and dims, so a derived camera\n * (parallax, node-anchored scroll) is a function of the one hosting it.\n */\n view: View | ((outer: View, dims: Dims) => View);\n /** Where on the outer canvas this viewport is painted, in screen-space\n * CSS pixels. Recomputed every frame so the rect can track an outer\n * pose, follow a corner, etc. */\n bounds: (outer: View, dims: Dims) => { x: number; y: number; w: number; h: number };\n /** Optional opaque background painted before the source layers. Useful\n * to keep the underlying outer canvas from showing through when the\n * inner view leaves part of the viewport empty. */\n background?: string;\n}\n\n/**\n * @experimental\n *\n * A {@link RenderLayer} that can also describe itself as a routing target.\n * Returned by {@link createViewportLayer}.\n */\nexport interface ViewportLayer<TData> extends RenderLayer<TData> {\n /**\n * This viewport as a routing candidate for {@link createViewResolver} —\n * its inner view and the rect it paints into for the given outer frame.\n *\n * Pass the `outer` view and `dims` the frame was drawn with: `bounds` is a\n * pure function of those, so this reproduces the exact rect that was\n * painted rather than a remembered one.\n */\n resolvable(outer: View, dims: Dims): ResolvableView;\n}\n\n/** Build a layer that renders other layers through a second view, inside a\n * sub-region of the canvas — a minimap, an inset, a magnifier. */\nexport function createViewportLayer<TData, TSource = TData>(\n opts: CreateViewportLayerOpts<TData, TSource>,\n): ViewportLayer<TData> {\n const { id, label, source, view, bounds, background, data: sourceData } = opts;\n const fixedView = typeof view === 'function' ? null : normalizeView(view);\n const viewAt = (outer: View, dims: Dims): View =>\n fixedView ?? normalizeView((view as (outer: View, dims: Dims) => View)(outer, dims));\n const sourceAt = typeof source === 'function' ? source : () => source;\n return {\n id,\n label,\n space: 'screen',\n subscribe: subscribeToSources(sourceAt),\n resolvable(outer, dims) {\n return { id, view: viewAt(outer, dims), rect: bounds(outer, dims) };\n },\n draw: (data, outerView, dims): DrawCommand[] => {\n const b = bounds(outerView, dims);\n // Inner content drawn through `view`, then translated so the inner\n // view's screen origin lines up with the viewport top-left.\n const children: DrawCommand[] = [];\n if (background) {\n children.push({\n kind: 'path',\n path: { kind: 'rect', x: 0, y: 0, width: b.w, height: b.h },\n fill: { fill: 'solid', color: background },\n });\n }\n const innerDims = { width: b.w, height: b.h };\n // The cast holds up because `TSource` defaults to `TData`: without a\n // thunk the two are the same type by construction.\n const innerData = sourceData ? sourceData(data) : (data as unknown as TSource);\n const v = viewAt(outerView, dims);\n for (const layer of sourceAt()) {\n for (const c of drawOneLayer(layer, innerData, v, innerDims)) children.push(c);\n }\n const transform: GlMat3 = mat3.translated(mat3.identity(), b.x, b.y);\n const group: GroupDrawCommand = {\n kind: 'group',\n transform,\n clip: { kind: 'rect', x: 0, y: 0, width: b.w, height: b.h },\n children,\n };\n return [group];\n },\n };\n}\n"],"mappings":";;;;AA4FA,SAAgBA,EACd,GACsB;CACtB,IAAM,EAAE,OAAI,UAAO,WAAQ,SAAM,WAAQ,eAAY,MAAMC,MAAeC,GACpEC,IAAY,OAAOC,KAAS,aAAa,OAAOC,EAAcD,CAAI,GAClEE,KAAU,GAAa,MAC3BH,KAAaE,EAAeD,EAA2CG,GAAOC,CAAI,CAAC,GAC/EC,IAAW,OAAOC,KAAW,aAAaA,UAAeA;CAC/D,OAAO;EACL;EACA;EACA,OAAO;EACP,WAAWC,EAAmBF,CAAQ;EACtC,WAAW,GAAO,GAAM;GACtB,OAAO;IAAE;IAAI,MAAMH,EAAOC,GAAOC,CAAI;IAAG,MAAMI,EAAOL,GAAOC,CAAI;GAAE;EACpE;EACA,OAAO,GAAM,GAAW,MAAwB;GAC9C,IAAMK,IAAID,EAAOE,GAAWN,CAAI,GAG1BO,IAA0B,CAAC;GACjC,AAAIC,KACFD,EAAS,KAAK;IACZ,MAAM;IACN,MAAM;KAAE,MAAM;KAAQ,GAAG;KAAG,GAAG;KAAG,OAAOF,EAAE;KAAG,QAAQA,EAAE;IAAE;IAC1D,MAAM;KAAE,MAAM;KAAS,OAAOG;IAAW;GAC3C,CAAC;GAEH,IAAMC,IAAY;IAAE,OAAOJ,EAAE;IAAG,QAAQA,EAAE;GAAE,GAGtCK,IAAYjB,IAAaA,EAAWkB,CAAI,IAAKA,GAC7CC,IAAId,EAAOQ,GAAWN,CAAI;GAChC,KAAK,IAAMa,KAASZ,EAAS,GAC3B,KAAK,IAAMa,KAAKC,EAAaF,GAAOH,GAAWE,GAAGH,CAAS,GAAG,EAAS,KAAKK,CAAC;GAS/E,OAAO,CAAC;IALN,MAAM;IACN,WAHwBE,EAAK,WAAWA,EAAK,SAAS,GAAGX,EAAE,GAAGA,EAAE,CAGhE;IACA,MAAM;KAAE,MAAM;KAAQ,GAAG;KAAG,GAAG;KAAG,OAAOA,EAAE;KAAG,QAAQA,EAAE;IAAE;IAC1D;GAEM,CAAK;EACf;CACF;AACF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ICON_SVG_BASE as e } from "./_base.js";
|
|
2
|
+
import { jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
3
|
+
//#region src/icons/ArrowIcon.tsx
|
|
4
|
+
function r({ className: r, size: i = 20 }) {
|
|
5
|
+
return /* @__PURE__ */ n("svg", {
|
|
6
|
+
...e,
|
|
7
|
+
className: r,
|
|
8
|
+
width: i,
|
|
9
|
+
height: i,
|
|
10
|
+
children: [/* @__PURE__ */ t("path", {
|
|
11
|
+
d: "M3.5 16.5 12.9 7.1",
|
|
12
|
+
strokeLinecap: "round"
|
|
13
|
+
}), /* @__PURE__ */ t("path", {
|
|
14
|
+
d: "M16.5 3.5 11.06 5.98 14.03 8.95Z",
|
|
15
|
+
fill: "currentColor",
|
|
16
|
+
strokeLinejoin: "round"
|
|
17
|
+
})]
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { r as default };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=ArrowIcon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ArrowIcon.js","names":["ArrowIcon","ICON_SVG_BASE","size"],"sources":["../../src/icons/ArrowIcon.tsx"],"sourcesContent":["import { ICON_SVG_BASE } from './_base';\nimport type { IconProps } from './types';\n\n/** `LineIcon`'s diagonal with a filled head, so the two read as one tool with\n * and without the marker. Used for the arrow insertion tool.\n *\n * The head is filled rather than an open V: at 16px an open V's barbs merge\n * under antialiasing and the notch disappears, leaving a blob. Its base\n * corners are `tip ∓ 5.6·d ± 2.1·d⊥` — computed, and the shaft stops half a\n * unit inside the base so its round cap hides under the fill. */\nexport default function ArrowIcon({ className, size = 20 }: IconProps) {\n return (\n <svg\n {...ICON_SVG_BASE}\n className={className}\n width={size}\n height={size}\n >\n <path d=\"M3.5 16.5 12.9 7.1\" strokeLinecap=\"round\" />\n <path d=\"M16.5 3.5 11.06 5.98 14.03 8.95Z\" fill=\"currentColor\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n"],"mappings":";;;AAUA,SAAwBA,EAAU,EAAE,cAAW,UAAO,MAAiB;CACrE,OACE,kBAAC,OAAD;EACE,GAAIC;EACO;EACX,OAAOC;EACP,QAAQA;EAJV,UAAA,CAME,kBAAC,QAAD;GAAM,GAAE;GAAqB,eAAc;EAAS,CAAA,GACpD,kBAAC,QAAD;GAAM,GAAE;GAAmC,MAAK;GAAe,gBAAe;EAAS,CAAA,CACpF;;AAET"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ICON_SVG_BASE as e } from "./_base.js";
|
|
2
|
+
import { jsx as t } from "react/jsx-runtime";
|
|
3
|
+
//#region src/icons/EllipseIcon.tsx
|
|
4
|
+
function n({ className: n, size: r = 20 }) {
|
|
5
|
+
return /* @__PURE__ */ t("svg", {
|
|
6
|
+
...e,
|
|
7
|
+
className: n,
|
|
8
|
+
width: r,
|
|
9
|
+
height: r,
|
|
10
|
+
children: /* @__PURE__ */ t("ellipse", {
|
|
11
|
+
cx: "10",
|
|
12
|
+
cy: "10",
|
|
13
|
+
rx: "7",
|
|
14
|
+
ry: "5"
|
|
15
|
+
})
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { n as default };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=EllipseIcon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EllipseIcon.js","names":["EllipseIcon","ICON_SVG_BASE","size"],"sources":["../../src/icons/EllipseIcon.tsx"],"sourcesContent":["import { ICON_SVG_BASE } from './_base';\nimport type { IconProps } from './types';\n\n/** Outlined ellipse. Used for the ellipse insertion tool. */\nexport default function EllipseIcon({ className, size = 20 }: IconProps) {\n return (\n <svg\n {...ICON_SVG_BASE}\n className={className}\n width={size}\n height={size}\n >\n <ellipse cx=\"10\" cy=\"10\" rx=\"7\" ry=\"5\" />\n </svg>\n );\n}\n"],"mappings":";;;AAIA,SAAwBA,EAAY,EAAE,cAAW,UAAO,MAAiB;CACvE,OACE,kBAAC,OAAD;EACE,GAAIC;EACO;EACX,OAAOC;EACP,QAAQA;EAER,UAAA,kBAAC,WAAD;GAAS,IAAG;GAAK,IAAG;GAAK,IAAG;GAAI,IAAG;EAAK,CAAA;CACrC,CAAA;AAET"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ICON_SVG_BASE as e } from "./_base.js";
|
|
2
|
+
import { jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
3
|
+
//#region src/icons/EyedropperIcon.tsx
|
|
4
|
+
function r({ className: r, size: i = 20 }) {
|
|
5
|
+
return /* @__PURE__ */ n("svg", {
|
|
6
|
+
...e,
|
|
7
|
+
className: r,
|
|
8
|
+
width: i,
|
|
9
|
+
height: i,
|
|
10
|
+
children: [
|
|
11
|
+
/* @__PURE__ */ t("line", {
|
|
12
|
+
x1: "12.5",
|
|
13
|
+
y1: "3.5",
|
|
14
|
+
x2: "16.5",
|
|
15
|
+
y2: "7.5",
|
|
16
|
+
strokeLinecap: "round"
|
|
17
|
+
}),
|
|
18
|
+
/* @__PURE__ */ t("path", {
|
|
19
|
+
d: "M 11 7 L 13 5 a 2 2 0 0 1 2.8 0 l 1.2 1.2 a 2 2 0 0 1 0 2.8 L 15 11 Z",
|
|
20
|
+
strokeLinejoin: "round"
|
|
21
|
+
}),
|
|
22
|
+
/* @__PURE__ */ t("line", {
|
|
23
|
+
x1: "13",
|
|
24
|
+
y1: "9",
|
|
25
|
+
x2: "5",
|
|
26
|
+
y2: "17",
|
|
27
|
+
strokeLinecap: "round"
|
|
28
|
+
}),
|
|
29
|
+
/* @__PURE__ */ t("line", {
|
|
30
|
+
x1: "11",
|
|
31
|
+
y1: "7",
|
|
32
|
+
x2: "3",
|
|
33
|
+
y2: "15",
|
|
34
|
+
strokeLinecap: "round"
|
|
35
|
+
}),
|
|
36
|
+
/* @__PURE__ */ t("line", {
|
|
37
|
+
x1: "3",
|
|
38
|
+
y1: "15",
|
|
39
|
+
x2: "5",
|
|
40
|
+
y2: "17",
|
|
41
|
+
strokeLinecap: "round"
|
|
42
|
+
})
|
|
43
|
+
]
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { r as default };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=EyedropperIcon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EyedropperIcon.js","names":["EyedropperIcon","ICON_SVG_BASE","size"],"sources":["../../src/icons/EyedropperIcon.tsx"],"sourcesContent":["import { ICON_SVG_BASE } from './_base';\nimport type { IconProps } from './types';\n\n/** Eyedropper — diagonal stem running from upper-right (bulb) to\n * lower-left (tip), with a small squared bulb cap at the top. Used\n * for the eyedropper / color-picker tool. */\nexport default function EyedropperIcon({ className, size = 20 }: IconProps) {\n return (\n <svg\n {...ICON_SVG_BASE}\n className={className}\n width={size}\n height={size}\n >\n {/* Bulb cap (upper-right) */}\n <line x1=\"12.5\" y1=\"3.5\" x2=\"16.5\" y2=\"7.5\" strokeLinecap=\"round\" />\n {/* Bulb body — rounded rectangle along the diagonal */}\n <path\n d=\"M 11 7 L 13 5 a 2 2 0 0 1 2.8 0 l 1.2 1.2 a 2 2 0 0 1 0 2.8 L 15 11 Z\"\n strokeLinejoin=\"round\"\n />\n {/* Stem from bulb down to tip */}\n <line x1=\"13\" y1=\"9\" x2=\"5\" y2=\"17\" strokeLinecap=\"round\" />\n <line x1=\"11\" y1=\"7\" x2=\"3\" y2=\"15\" strokeLinecap=\"round\" />\n {/* Tip closure */}\n <line x1=\"3\" y1=\"15\" x2=\"5\" y2=\"17\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n"],"mappings":";;;AAMA,SAAwBA,EAAe,EAAE,cAAW,UAAO,MAAiB;CAC1E,OACE,kBAAC,OAAD;EACE,GAAIC;EACO;EACX,OAAOC;EACP,QAAQA;EAJV,UAAA;GAOE,kBAAC,QAAD;IAAM,IAAG;IAAO,IAAG;IAAM,IAAG;IAAO,IAAG;IAAM,eAAc;GAAS,CAAA;GAEnE,kBAAC,QAAD;IACE,GAAE;IACF,gBAAe;GAChB,CAAA;GAED,kBAAC,QAAD;IAAM,IAAG;IAAK,IAAG;IAAI,IAAG;IAAI,IAAG;IAAK,eAAc;GAAS,CAAA;GAC3D,kBAAC,QAAD;IAAM,IAAG;IAAK,IAAG;IAAI,IAAG;IAAI,IAAG;IAAK,eAAc;GAAS,CAAA;GAE3D,kBAAC,QAAD;IAAM,IAAG;IAAI,IAAG;IAAK,IAAG;IAAI,IAAG;IAAK,eAAc;GAAS,CAAA;EACxD;;AAET"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ICON_SVG_BASE as e } from "./_base.js";
|
|
2
|
+
import { jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
3
|
+
//#region src/icons/HandIcon.tsx
|
|
4
|
+
function r({ className: r, size: i = 20 }) {
|
|
5
|
+
return /* @__PURE__ */ n("svg", {
|
|
6
|
+
...e,
|
|
7
|
+
className: r,
|
|
8
|
+
width: i,
|
|
9
|
+
height: i,
|
|
10
|
+
children: [
|
|
11
|
+
/* @__PURE__ */ t("rect", {
|
|
12
|
+
x: "5",
|
|
13
|
+
y: "10",
|
|
14
|
+
width: "10",
|
|
15
|
+
height: "7.5",
|
|
16
|
+
rx: "2"
|
|
17
|
+
}),
|
|
18
|
+
/* @__PURE__ */ t("line", {
|
|
19
|
+
x1: "6.5",
|
|
20
|
+
y1: "10",
|
|
21
|
+
x2: "6.5",
|
|
22
|
+
y2: "4.5",
|
|
23
|
+
strokeLinecap: "round"
|
|
24
|
+
}),
|
|
25
|
+
/* @__PURE__ */ t("line", {
|
|
26
|
+
x1: "9",
|
|
27
|
+
y1: "10",
|
|
28
|
+
x2: "9",
|
|
29
|
+
y2: "3",
|
|
30
|
+
strokeLinecap: "round"
|
|
31
|
+
}),
|
|
32
|
+
/* @__PURE__ */ t("line", {
|
|
33
|
+
x1: "11.5",
|
|
34
|
+
y1: "10",
|
|
35
|
+
x2: "11.5",
|
|
36
|
+
y2: "3.5",
|
|
37
|
+
strokeLinecap: "round"
|
|
38
|
+
}),
|
|
39
|
+
/* @__PURE__ */ t("line", {
|
|
40
|
+
x1: "14",
|
|
41
|
+
y1: "10",
|
|
42
|
+
x2: "14",
|
|
43
|
+
y2: "5.5",
|
|
44
|
+
strokeLinecap: "round"
|
|
45
|
+
}),
|
|
46
|
+
/* @__PURE__ */ t("line", {
|
|
47
|
+
x1: "5",
|
|
48
|
+
y1: "12.5",
|
|
49
|
+
x2: "2.5",
|
|
50
|
+
y2: "14.5",
|
|
51
|
+
strokeLinecap: "round"
|
|
52
|
+
})
|
|
53
|
+
]
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
export { r as default };
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=HandIcon.js.map
|