@weasel-js/core 1.12.0 → 1.13.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +91 -0
- package/dist/animation/poseTarget.js +46 -15
- package/dist/animation/poseTarget.js.map +1 -1
- package/dist/animation/poseTransition.js +3 -3
- package/dist/animation/poseTransition.js.map +1 -1
- package/dist/animation/reflow.js +3 -6
- package/dist/animation/reflow.js.map +1 -1
- package/dist/animation/rig/bindRig.js +2 -2
- package/dist/animation/rig/bindRig.js.map +1 -1
- package/dist/animation/rig/skinBinding.js +2 -2
- package/dist/animation/rig/skinBinding.js.map +1 -1
- package/dist/barrel/canvas.js +5 -3
- package/dist/barrel/chrome.js +3 -1
- package/dist/barrel/paths.js +3 -2
- package/dist/barrel/routing.js +2 -2
- package/dist/barrel/scene.js +6 -1
- package/dist/canvas/NodeShape.js +1 -0
- package/dist/canvas/NodeShape.js.map +1 -1
- package/dist/canvas/SceneCanvas/SceneCanvasInput.js +2 -0
- package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
- package/dist/canvas/SceneCanvas/canvasPassThrough.js +1 -1
- package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js +2 -2
- package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
- package/dist/canvas/SceneCanvas/scenePointQuery.js +20 -2
- package/dist/canvas/SceneCanvas/scenePointQuery.js.map +1 -1
- package/dist/canvas/SceneCanvas/useCanvasTools.js +3 -0
- package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js +25 -19
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +7 -0
- package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +1 -0
- package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/useScenePicking.js +31 -6
- package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js +4 -5
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneStandardActions.js +5 -3
- package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
- package/dist/canvas/SceneCanvas.js +19 -2
- package/dist/canvas/SceneCanvas.js.map +1 -1
- package/dist/canvas/accentColor.js +26 -3
- package/dist/canvas/accentColor.js.map +1 -1
- package/dist/canvas/buildSceneTree.js +14 -20
- package/dist/canvas/buildSceneTree.js.map +1 -1
- package/dist/canvas/copiesAbove.js +1 -1
- package/dist/canvas/copiesAbove.js.map +1 -1
- package/dist/canvas/defaultDrawOne.js +10 -7
- package/dist/canvas/defaultDrawOne.js.map +1 -1
- package/dist/canvas/deps/areaSelect.js +5 -2
- package/dist/canvas/deps/areaSelect.js.map +1 -1
- package/dist/canvas/deps/booleans.js +1 -1
- package/dist/canvas/deps/booleans.js.map +1 -1
- package/dist/canvas/deps/enteredGroup.js +81 -0
- package/dist/canvas/deps/enteredGroup.js.map +1 -0
- package/dist/canvas/deps/hitTestArea.js +27 -15
- package/dist/canvas/deps/hitTestArea.js.map +1 -1
- package/dist/canvas/deps/insert.js +4 -36
- package/dist/canvas/deps/insert.js.map +1 -1
- package/dist/canvas/deps/insertSite.js +39 -0
- package/dist/canvas/deps/insertSite.js.map +1 -0
- package/dist/canvas/deps/lassoSelect.js +6 -3
- package/dist/canvas/deps/lassoSelect.js.map +1 -1
- package/dist/canvas/deps/pathLeaf.js +1 -1
- package/dist/canvas/deps/pathLeaf.js.map +1 -1
- package/dist/canvas/deps/slice.js +2 -1
- package/dist/canvas/deps/slice.js.map +1 -1
- package/dist/canvas/derivedPath.js +14 -6
- package/dist/canvas/derivedPath.js.map +1 -1
- package/dist/canvas/doubleClickTarget.js +9 -11
- package/dist/canvas/doubleClickTarget.js.map +1 -1
- package/dist/canvas/drawnBounds.js +16 -7
- package/dist/canvas/drawnBounds.js.map +1 -1
- package/dist/canvas/inheritedPaints.js +22 -11
- package/dist/canvas/inheritedPaints.js.map +1 -1
- package/dist/canvas/nodeShapes/nodePaint.js +1 -7
- package/dist/canvas/nodeShapes/nodePaint.js.map +1 -1
- package/dist/canvas/nodeShapes/pathPainter.js +2 -3
- package/dist/canvas/nodeShapes/pathPainter.js.map +1 -1
- package/dist/canvas/nodeShapes/rectFallbackPainter.js +1 -1
- package/dist/canvas/nodeShapes/rectFallbackPainter.js.map +1 -1
- package/dist/canvas/nodeShapes/shapePainter.js +2 -3
- package/dist/canvas/nodeShapes/shapePainter.js.map +1 -1
- package/dist/canvas/ownClip.js +24 -0
- package/dist/canvas/ownClip.js.map +1 -0
- package/dist/canvas/paintCull.js.map +1 -1
- package/dist/canvas/pickIndex/nodeBroadBox.js +86 -0
- package/dist/canvas/pickIndex/nodeBroadBox.js.map +1 -0
- package/dist/canvas/pickIndex/scenePickIndex.js +208 -0
- package/dist/canvas/pickIndex/scenePickIndex.js.map +1 -0
- package/dist/canvas/pickWalk.js +14 -90
- package/dist/canvas/pickWalk.js.map +1 -1
- package/dist/canvas/poseCascade.js +1 -1
- package/dist/canvas/poseCascade.js.map +1 -1
- package/dist/canvas/publishPreviews.js +97 -0
- package/dist/canvas/publishPreviews.js.map +1 -0
- package/dist/canvas/sceneAdapter.js +7 -5
- package/dist/canvas/sceneAdapter.js.map +1 -1
- package/dist/canvas/sceneClipboard.js +17 -10
- package/dist/canvas/sceneClipboard.js.map +1 -1
- package/dist/canvas/scenePickReads.js +37 -0
- package/dist/canvas/scenePickReads.js.map +1 -0
- package/dist/canvas/scenePickSource.js +74 -0
- package/dist/canvas/scenePickSource.js.map +1 -0
- package/dist/canvas/sceneSlotWiring.js +9 -4
- package/dist/canvas/sceneSlotWiring.js.map +1 -1
- package/dist/canvas/sceneViewRender.js +9 -5
- package/dist/canvas/sceneViewRender.js.map +1 -1
- package/dist/canvas/shownNodes.js +15 -0
- package/dist/canvas/shownNodes.js.map +1 -0
- package/dist/canvas/useSceneAdapter.js +5 -3
- package/dist/canvas/useSceneAdapter.js.map +1 -1
- package/dist/clipboard.d.ts +2 -2
- package/dist/{clone-C3e0OTuF.d.ts → clone-qb2e1F5p.d.ts} +2 -2
- package/dist/clone.d.ts +3 -3
- package/dist/core/isPlainObject.js +2 -2
- package/dist/core/layers/layerGroup.js.map +1 -1
- package/dist/core/scene/NodeRouting.js.map +1 -1
- package/dist/core/scene/arrivalWindow.js +1 -1
- package/dist/core/scene/arrivalWindow.js.map +1 -1
- package/dist/core/scene/clipNothing.js +2 -5
- package/dist/core/scene/clipNothing.js.map +1 -1
- package/dist/core/scene/declaredFieldSetters.js +44 -0
- package/dist/core/scene/declaredFieldSetters.js.map +1 -0
- package/dist/core/scene/depMemo.js +3 -0
- package/dist/core/scene/depMemo.js.map +1 -1
- package/dist/core/scene/dependents.js +3 -1
- package/dist/core/scene/dependents.js.map +1 -1
- package/dist/core/scene/documentOf.js +43 -0
- package/dist/core/scene/documentOf.js.map +1 -0
- package/dist/core/scene/effectivePose.js +37 -13
- package/dist/core/scene/effectivePose.js.map +1 -1
- package/dist/core/scene/fieldEdits.js +17 -14
- package/dist/core/scene/fieldEdits.js.map +1 -1
- package/dist/core/scene/historyForm.js +4 -4
- package/dist/core/scene/historyForm.js.map +1 -1
- package/dist/core/scene/inheritedPaint.js +27 -5
- package/dist/core/scene/inheritedPaint.js.map +1 -1
- package/dist/core/scene/kitOps.js +3 -23
- package/dist/core/scene/kitOps.js.map +1 -1
- package/dist/core/scene/layoutPass.js +1 -2
- package/dist/core/scene/layoutPass.js.map +1 -1
- package/dist/core/scene/nodeAsShown.js +72 -0
- package/dist/core/scene/nodeAsShown.js.map +1 -0
- package/dist/core/scene/nodeFnFields.js +2 -10
- package/dist/core/scene/nodeFnFields.js.map +1 -1
- package/dist/core/scene/nodeMemo.js +6 -1
- package/dist/core/scene/nodeMemo.js.map +1 -1
- package/dist/core/scene/nodeStore.js +2 -4
- package/dist/core/scene/nodeStore.js.map +1 -1
- package/dist/core/scene/pathEffects/derive.js +3 -2
- package/dist/core/scene/pathEffects/derive.js.map +1 -1
- package/dist/core/scene/pathEffects/foundHidden.js +35 -0
- package/dist/core/scene/pathEffects/foundHidden.js.map +1 -0
- package/dist/core/scene/plyStacks.js +89 -0
- package/dist/core/scene/plyStacks.js.map +1 -0
- package/dist/core/scene/poseHold.js +42 -24
- package/dist/core/scene/poseHold.js.map +1 -1
- package/dist/core/scene/poseOverrides.js +35 -38
- package/dist/core/scene/poseOverrides.js.map +1 -1
- package/dist/core/scene/posePlies.js +59 -0
- package/dist/core/scene/posePlies.js.map +1 -0
- package/dist/core/scene/reconcileSpecs.js +6 -15
- package/dist/core/scene/reconcileSpecs.js.map +1 -1
- package/dist/core/scene/renderOrder.js +10 -4
- package/dist/core/scene/renderOrder.js.map +1 -1
- package/dist/core/scene/sameValue.js +17 -0
- package/dist/core/scene/sameValue.js.map +1 -0
- package/dist/core/scene/scene.js +3 -3
- package/dist/core/scene/scene.js.map +1 -1
- package/dist/core/scene/sceneEdits.js +8 -0
- package/dist/core/scene/sceneEdits.js.map +1 -1
- package/dist/core/scene/sceneState.js +1 -2
- package/dist/core/scene/sceneState.js.map +1 -1
- package/dist/core/scene/serialization.js +45 -9
- package/dist/core/scene/serialization.js.map +1 -1
- package/dist/core/scene/staleReplay.js +5 -2
- package/dist/core/scene/staleReplay.js.map +1 -1
- package/dist/core/scene/statedFields.js +4 -2
- package/dist/core/scene/statedFields.js.map +1 -1
- package/dist/core/scene/treeEdits.js +2 -4
- package/dist/core/scene/treeEdits.js.map +1 -1
- package/dist/core/scene/treeOrder.js +3 -1
- package/dist/core/scene/treeOrder.js.map +1 -1
- package/dist/core/scene/treeReads.js +1 -2
- package/dist/core/scene/treeReads.js.map +1 -1
- package/dist/core/scene/treeShape.js +13 -0
- package/dist/core/scene/treeShape.js.map +1 -0
- package/dist/core/scene/types.js.map +1 -1
- package/dist/core/scene/useScene.js +1 -1
- package/dist/core/scene/useScene.js.map +1 -1
- package/dist/{cornerHandles-p8fDIAKt.d.ts → cornerHandles-CNCb7aTY.d.ts} +1 -1
- package/dist/{depSchema-mG19aEdD.d.ts → depSchema-B1RS-IJx.d.ts} +27 -54
- package/dist/devtools/handlers.js +1 -1
- package/dist/devtools/handlers.js.map +1 -1
- package/dist/devtools/protocol.js.map +1 -1
- package/dist/devtools-protocol.d.ts +4 -3
- package/dist/devtools.d.ts +3 -2
- package/dist/features/measure/measureHit.js +5 -3
- package/dist/features/measure/measureHit.js.map +1 -1
- package/dist/features/measure/measurement.js +1 -1
- package/dist/features/measure/measurement.js.map +1 -1
- package/dist/features/modes/modeLayers.js +14 -7
- package/dist/features/modes/modeLayers.js.map +1 -1
- package/dist/features/modes/modeTriggers.js +3 -3
- package/dist/features/modes/modeTriggers.js.map +1 -1
- package/dist/features/pathEffects/effectSources.js +25 -16
- package/dist/features/pathEffects/effectSources.js.map +1 -1
- package/dist/features/pathEffects/readSource.js +1 -1
- package/dist/features/pathEffects/readSource.js.map +1 -1
- package/dist/features/pathEffects/useEffectSourcesLayer.js +15 -19
- package/dist/features/pathEffects/useEffectSourcesLayer.js.map +1 -1
- package/dist/features/paths/editablePath.js +1 -1
- package/dist/features/paths/editablePath.js.map +1 -1
- package/dist/features/paths/pathSnap/sceneIndex.js +1 -1
- package/dist/features/paths/pathSnap/sceneIndex.js.map +1 -1
- package/dist/features/selection/enteredGroupFrame.js +65 -0
- package/dist/features/selection/enteredGroupFrame.js.map +1 -0
- package/dist/features/selection/enteredGroupScope.js +44 -0
- package/dist/features/selection/enteredGroupScope.js.map +1 -0
- package/dist/features/text/sceneTextDrafts.js +26 -27
- package/dist/features/text/sceneTextDrafts.js.map +1 -1
- package/dist/features/text/textHitAt.js +4 -2
- package/dist/features/text/textHitAt.js.map +1 -1
- package/dist/features/text/useSceneTextEdit.js +3 -3
- package/dist/features/text/useSceneTextEdit.js.map +1 -1
- package/dist/index.d.ts +225 -73
- package/dist/index.js +15 -5
- package/dist/interactions/actions/admitsChild.js +11 -0
- package/dist/interactions/actions/admitsChild.js.map +1 -0
- package/dist/interactions/actions/defaults/contextMenu.js +16 -3
- package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
- package/dist/interactions/actions/defaults/createPaintAction.js +4 -1
- package/dist/interactions/actions/defaults/createPaintAction.js.map +1 -1
- package/dist/interactions/actions/defaults/enterGroup.js +88 -0
- package/dist/interactions/actions/defaults/enterGroup.js.map +1 -0
- package/dist/interactions/actions/defaults/enterPathEdit.js +1 -1
- package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/enterTextEdit.js +1 -1
- package/dist/interactions/actions/defaults/enterTextEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/group.js +7 -7
- package/dist/interactions/actions/defaults/group.js.map +1 -1
- package/dist/interactions/actions/defaults/selectAll.js +7 -3
- package/dist/interactions/actions/defaults/selectAll.js.map +1 -1
- package/dist/interactions/actions/defaults/selectDeep.js +35 -0
- package/dist/interactions/actions/defaults/selectDeep.js.map +1 -0
- package/dist/interactions/actions/drawnBoxes.js +2 -1
- package/dist/interactions/actions/drawnBoxes.js.map +1 -1
- package/dist/interactions/actions/insert/action.js +1 -0
- package/dist/interactions/actions/insert/action.js.map +1 -1
- package/dist/interactions/actions/insert/parent.js +7 -5
- package/dist/interactions/actions/insert/parent.js.map +1 -1
- package/dist/interactions/actions/insert/placeAction.js +3 -2
- package/dist/interactions/actions/insert/placeAction.js.map +1 -1
- package/dist/interactions/actions/insert/session.js +2 -2
- package/dist/interactions/actions/insert/session.js.map +1 -1
- package/dist/interactions/actions/move/commit/reparent.js +1 -1
- package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
- package/dist/interactions/actions/move/gestureAdapter.js +6 -7
- package/dist/interactions/actions/move/gestureAdapter.js.map +1 -1
- package/dist/interactions/actions/move/layout/exits.js +1 -1
- package/dist/interactions/actions/move/layout/exits.js.map +1 -1
- package/dist/interactions/actions/move/session.js +4 -4
- package/dist/interactions/actions/move/session.js.map +1 -1
- package/dist/interactions/actions/pathCommands/pathNodes.js +14 -5
- package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -1
- package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js +14 -2
- package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js.map +1 -1
- package/dist/{math-B56zxVs5.d.ts → math-C_elShP_.d.ts} +2 -5
- package/dist/math.d.ts +1 -1
- package/dist/move.d.ts +4 -4
- package/dist/{options-DBxEryYq.d.ts → options-ClEm3SEl.d.ts} +1 -1
- package/dist/resize.d.ts +4 -4
- package/dist/test-seams.d.ts +6 -6
- package/dist/tools/builtin/pressTarget.js +22 -0
- package/dist/tools/builtin/pressTarget.js.map +1 -0
- package/dist/tools/builtin/select/adapterPointQuery.js +3 -3
- package/dist/tools/builtin/select/adapterPointQuery.js.map +1 -1
- package/dist/tools/builtin/select/collapseDeferred.js +40 -0
- package/dist/tools/builtin/select/collapseDeferred.js.map +1 -0
- package/dist/tools/builtin/select/groupEntry.js +82 -0
- package/dist/tools/builtin/select/groupEntry.js.map +1 -0
- package/dist/tools/builtin/select/pressDecision.js +1 -1
- package/dist/tools/builtin/select/pressDecision.js.map +1 -1
- package/dist/tools/builtin/select/useSelectTool.js +61 -45
- package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
- package/dist/{types-7puAuVD2.d.ts → types-49uYJN3j.d.ts} +1 -1
- package/dist/{types-CniVctmk.d.ts → types-BEdRIhNc.d.ts} +272 -109
- package/dist/{types-oFeQ5VjV.d.ts → types-p2alu-R1.d.ts} +1 -1
- package/dist/version.js +1 -1
- package/package.json +25 -25
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSceneTextEdit.js","names":[],"sources":["../../../src/features/text/useSceneTextEdit.ts"],"sourcesContent":["/**\n * `useSceneTextEdit` — scene-aware wrapper around `useTextEdit`: scene\n * lookups for text / style / runs / screen-pose, and\n * `scene.update(id, { data })` for commits. The overlay and a double-click\n * both read the pose a node is painted at, so text inside a container whose\n * pose is a frame is edited where it is drawn.\n *\n * Defaults assume the node's `data` carries `text` / `style` / `runs`\n * directly. For custom data shapes, override any of the optional projections.\n * Consumers with non-rect poses should drop down to raw `useTextEdit` and\n * supply their own `getScreenPose`.\n */\nimport { useCallback, useMemo, useRef, type MouseEvent } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport { asNodeId } from '../../core/scene/types';\nimport { scenePaintedPoseOf } from '../../canvas/derivedPath';\nimport type { Scene } from '../../core/scene/types';\nimport { drawOneEditing, type EditingDrawOne } from './editingDrawOne';\nimport { textHitAt } from './textHitAt';\nimport { editedData, sceneTextDrafts } from './sceneTextDrafts';\nimport type { Stroke, Fill, Inherit } from '@weasel-js/paint';\nimport { resolveScreenLength } from '@weasel-js/paint';\nimport { inheritedPaintIn } from '../../canvas/inheritedPaints';\nimport { withInheritedPaint } from '../../core/scene/inheritedPaint';\nimport { clientToCanvas } from '@weasel-js/routing';\nimport { findMountedCanvas, type MountedCanvas } from '../../canvas/mountedCanvases';\nimport type { View } from '../../core/viewport/view';\nimport type { RectPose } from 'core/geometry/unionBounds';\nimport { poseFrameOf } from '@weasel-js/geom';\nimport { isTextData, type StyledRun, type TextPaint, type TextStyle, type TextVerticalAlign } from '@weasel-js/text';\nimport { textBoxOf, type TextOverflow } from '../../canvas/nodeShapes/textPainter';\nimport { useTextEdit, type TextEditClipRect, type TextEditScreenPose, type UseTextEditReturn } from '@weasel-js/text-dom';\n\n/** Shape the default projections expect `data` to satisfy. All fields\n * optional so any object satisfies the constraint — projections fill in\n * the gaps for non-default shapes. */\nexport interface DefaultTextData {\n text?: string;\n style?: TextStyle;\n runs?: readonly StyledRun[];\n fill?: Fill | Inherit | null;\n stroke?: Stroke | Inherit | null;\n verticalAlign?: TextVerticalAlign;\n padding?: number;\n overflow?: TextOverflow;\n}\n\n/** All-optional projections + fontSize fallback. */\nexport interface UseSceneTextEditOptions<TData> {\n /**\n * Is this node text? A double-click opens an edit only on a node that\n * answers yes, and passes through any other to the text under it. Default:\n * `isTextData`, the test `inferredNodeRouting` classifies a text node by. Pass one when `getText` reads some other shape.\n */\n isText?: (data: TData) => boolean;\n /** Read plain text from `data`. Default: `data.text ?? ''`. */\n getText?: (data: TData) => string;\n /** Read style from `data`. Default: `data.style`. */\n getStyle?: (data: TData) => TextStyle | undefined;\n /** Read the node's paint from `data`. Default: `data.fill` / `data.stroke`. */\n getPaint?: (data: TData) => TextPaint | undefined;\n /** Read rich-text runs from `data`. Default: `data.runs`. */\n getRuns?: (data: TData) => readonly StyledRun[] | undefined;\n /** Read the box vertical alignment from `data`. Default: `data.verticalAlign`. */\n getVerticalAlign?: (data: TData) => TextVerticalAlign | undefined;\n /** Read the inset from the node's box to its text from `data`. Default: `data.padding`. */\n getPadding?: (data: TData) => number | undefined;\n /** Read whether the node cuts its text at its box from `data`, which the\n * overlay then does too. Default: `data.overflow`. */\n getOverflow?: (data: TData) => TextOverflow | undefined;\n /** Produce updated data with new text. Default: `{ ...data, text }`. */\n setText?: (data: TData, text: string) => TData;\n /** Produce updated data with new runs. Default: `{ ...data, runs }`. */\n setRuns?: (data: TData, runs: StyledRun[]) => TData;\n /**\n * Produce updated data with a new node-wide style. Default:\n * `{ ...data, style }`. Written only when a range toggle has to *clear* a\n * flag the node itself sets — the run algebra is additive, so that edit\n * lowers the node flag and raises it on the runs outside the range. See\n * `useTextEdit`'s `setStyle`.\n *\n * An edit's text, runs, and style are folded through these three and\n * written as one `scene.update`, so a commit is one undo step.\n */\n setStyle?: (data: TData, style: TextStyle) => TData;\n /** Fallback fontSize when `style.fontSize` is unset. Default `16`. */\n defaultFontSize?: number;\n /**\n * The view to project through. Omit it and the view is read live from the\n * weasel canvas mounted inside `container` (the one a double-click landed\n * on, when there are several). With no canvas there, the node's world box\n * is passed through as screen pixels.\n *\n * A thunk is re-read on every projection; a plain `View` is the value from\n * the render that supplied it.\n */\n view?: View | (() => View);\n /**\n * Forwarded to `useTextEdit`: is `el` part of the editor's own chrome?\n * Focus moving into it does not end the edit. Wire it to whatever renders\n * the character controls.\n */\n isEditorChrome?: (el: Element) => boolean;\n /** Forwarded to `useTextEdit`: what Escape does to the edit. */\n escape?: 'cancel' | 'commit';\n /** Forwarded to `useTextEdit`: how long an edit waits for its face. */\n fontHold?: number;\n /** Forwarded to `useTextEdit`: called as an edit of the node `id` opens,\n * whichever way it was started. */\n onStart?: (id: string) => void;\n /** Forwarded to `useTextEdit`: called as the edit of `id` closes, after\n * any commit has been written to the scene. */\n onEnd?: (id: string) => void;\n}\n\nfunction resolveView(view: View | (() => View) | undefined): View | undefined {\n return typeof view === 'function' ? view() : view;\n}\n\n/** Return shape extends `UseTextEditReturn` with an `onDoubleClick`\n * binding for the canvas container. Double-clicking inside a text\n * node enters edit mode with the caret seeded at the clicked glyph. */\nexport interface UseSceneTextEditReturn extends UseTextEditReturn {\n /** Bind to the element wrapping `<SceneCanvas>` (the same element\n * passed as `container`, or any ancestor that receives the dblclick\n * bubble). Starts an edit on the top-most text node under the cursor. */\n onDoubleClick: (e: MouseEvent<HTMLElement>) => void;\n /** The `isText` option asked of the node with this id: what\n * `TextEditDep.isTextNode` wants, so both ways into an edit agree. */\n isTextNode: (id: string) => boolean;\n /**\n * `defaultDrawOne`, less the glyphs of the node being edited: the overlay\n * stands in for its text, and the rest of the node, a `background` among\n * it, goes on painting. Pass it as `layers.scene.drawOne`, with\n * `paintBounds: defaultPaintBounds`, in place of an `alphaFor` that hides\n * the whole node.\n */\n drawOne: EditingDrawOne;\n}\n\n/** How each field is read from a node's `data`: the option's projection, else the default shape. */\nfunction projectionsOf<TData extends DefaultTextData>(opts: { readonly current: UseSceneTextEditOptions<TData> }) {\n return {\n isText: (data: TData): boolean =>\n opts.current.isText ? opts.current.isText(data) : isTextData(data),\n text: (data: TData): string =>\n opts.current.getText ? opts.current.getText(data) : (data.text ?? ''),\n style: (data: TData): TextStyle | undefined =>\n opts.current.getStyle ? opts.current.getStyle(data) : data.style,\n runs: (data: TData): readonly StyledRun[] | undefined =>\n opts.current.getRuns ? opts.current.getRuns(data) : data.runs,\n verticalAlign: (data: TData): TextVerticalAlign | undefined =>\n opts.current.getVerticalAlign ? opts.current.getVerticalAlign(data) : data.verticalAlign,\n padding: (data: TData): number | undefined =>\n opts.current.getPadding ? opts.current.getPadding(data) : data.padding,\n overflow: (data: TData): TextOverflow | undefined =>\n opts.current.getOverflow ? opts.current.getOverflow(data) : data.overflow,\n };\n}\n\n/** Wire double-click-to-edit text on a scene: mounts a DOM editing overlay\n * over the node being edited and writes the result back as an undoable op. */\nexport function useSceneTextEdit<\n TData extends DefaultTextData,\n TLayer extends string,\n TPose extends RectPose = RectPose,\n>(\n scene: Scene<TData, TLayer, TPose>,\n container: HTMLElement | null,\n options: UseSceneTextEditOptions<TData> = {},\n): UseSceneTextEditReturn {\n // Refs, so the useTextEdit callbacks always see the current values\n // without re-binding.\n const sceneRef = useLatest(scene);\n const optsRef = useLatest(options);\n const containerRef = useLatest(container);\n // The last double-click's target, so the overlay projects through the\n // canvas the edit was opened on.\n const openedOnRef = useRef<EventTarget | null>(null);\n const drafts = useMemo(() => sceneTextDrafts(sceneRef, optsRef), [sceneRef, optsRef]);\n\n // The canvas's box in container pixels is both the origin its view projects\n // from and the region its glyphs are clipped to.\n const surface = (): { canvas: MountedCanvas; box: TextEditClipRect } | null => {\n const root = containerRef.current;\n const canvas = root ? findMountedCanvas(root, openedOnRef.current) : null;\n if (!root || !canvas) return null;\n const a = canvas.element.getBoundingClientRect();\n const b = root.getBoundingClientRect();\n return {\n canvas,\n box: {\n x: a.left - b.left - root.clientLeft + root.scrollLeft,\n y: a.top - b.top - root.clientTop + root.scrollTop,\n width: a.width,\n height: a.height,\n },\n };\n };\n\n const read = useMemo(() => projectionsOf(optsRef), [optsRef]);\n\n const edit = useTextEdit({\n container,\n isEditorChrome: (el) => optsRef.current.isEditorChrome?.(el) ?? false,\n escape: options.escape,\n fontHold: options.fontHold,\n onStart: (id) => optsRef.current.onStart?.(id),\n onEnd: (id) => {\n drafts.end(id);\n optsRef.current.onEnd?.(id);\n },\n onDraft: drafts.draft,\n getText: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.text(node.data) : '';\n },\n getStyle: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.style(node.data) : undefined;\n },\n getPaint: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n if (!node) return undefined;\n const get = optsRef.current.getPaint;\n return get ? get(node.data) : shownTextPaint(sceneRef.current, node);\n },\n getScreenPose: (id) => {\n const scene = sceneRef.current;\n const node = scene.get(asNodeId(id));\n if (!node) return null;\n const at = surface();\n const view = resolveView(optsRef.current.view) ?? at?.canvas.getView();\n return screenPoseOf(node.data, scenePaintedPoseOf(scene)(node), read, view, at?.box, optsRef.current.defaultFontSize);\n },\n getClipRect: () => surface()?.box ?? null,\n getRuns: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.runs(node.data) : undefined;\n },\n commit: (id, { text, runs, style }) => {\n const nid = asNodeId(id);\n const node = sceneRef.current.get(nid);\n if (!node) return;\n drafts.commit(id, editedData(node.data, { text, runs, style }, optsRef.current));\n },\n });\n\n const onDoubleClick = useCallback((e: MouseEvent<HTMLElement>) => {\n // The dblclick bubbles from the canvas up to any wrapping container; the\n // element it started on is what the click coordinates are relative to.\n const canvas = e.target instanceof HTMLElement ? e.target : null;\n if (!canvas) return;\n // Inside the editor a double-click selects a word, and its target is a run\n // span whose box the click would be measured against as if it were a canvas.\n if (canvas.closest('[contenteditable=\"true\"]')) return;\n\n // The click is un-projected here; `textHitAt` takes it back through the\n // frame the node is drawn in.\n const [canvasX, canvasY] = clientToCanvas(canvas, e.clientX, e.clientY);\n const root = containerRef.current;\n const view = resolveView(optsRef.current.view)\n ?? (root ? findMountedCanvas(root, canvas)?.getView() : undefined);\n const cx = view ? canvasX / view.scale.x + view.x : canvasX;\n const cy = view ? canvasY / view.scale.y + view.y : canvasY;\n const hit = textHitAt(sceneRef.current, read, cx, cy);\n if (!hit) return;\n openedOnRef.current = canvas;\n edit.startEdit(hit.id, { caret: hit.caret });\n }, [edit, containerRef, optsRef, read, sceneRef]);\n\n const isTextNode = useCallback((id: string): boolean => {\n const node = sceneRef.current.get(asNodeId(id));\n return node !== undefined && read.isText(node.data);\n }, [read, sceneRef]);\n\n const drawOne = useMemo(() => drawOneEditing(edit.editingId), [edit.editingId]);\n return { ...edit, onDoubleClick, isTextNode, drawOne };\n}\n\n/** The overlay's pose for a node painted at `painted`: its text box, inset\n * about the box center, which is all the overlay's frame needs, projected\n * through `view`. */\nfunction screenPoseOf<TData extends DefaultTextData>(\n d: TData,\n painted: RectPose,\n read: ReturnType<typeof projectionsOf<TData>>,\n view: View | undefined,\n origin: TextEditClipRect | undefined,\n defaultFontSize = 16,\n): TextEditScreenPose {\n const inset = textBoxOf({ padding: read.padding(d) }, painted);\n const box = screenBoxOf({ ...painted, ...inset }, view, origin);\n return {\n ...box,\n // Against `zoom`, the same factor the overlay scales back up by, so a\n // `{ px }` size arrives on screen at the pixel count it names.\n fontSize: resolveScreenLength(read.style(d)?.fontSize ?? defaultFontSize, box.zoom),\n verticalAlign: read.verticalAlign(d),\n ...(read.overflow(d) === 'clip' ? { clip: clipToBox(inset, painted) } : {}),\n };\n}\n\n/** How far `box` reaches past `inner` on each side: the overlay's cut at\n * `box` when its own pose is `inner`. */\nfunction clipToBox(inner: RectPose, box: RectPose): NonNullable<TextEditScreenPose['clip']> {\n return {\n top: inner.y - box.y,\n left: inner.x - box.x,\n bottom: box.y + box.height - (inner.y + inner.height),\n right: box.x + box.width - (inner.x + inner.width),\n };\n}\n\n/**\n * `pose`'s box as the overlay takes it, `origin` being the canvas's corner in\n * container pixels. Only the box center is projected, since the overlay's\n * frame is about it. Width and height stay in world units and reach the\n * screen through the overlay's own `scale(zoom)` — see\n * `TextEditScreenPose.zoom`.\n */\nfunction screenBoxOf(\n pose: RectPose,\n view: View | undefined,\n origin: { x: number; y: number } | undefined,\n): Pick<TextEditScreenPose, 'x' | 'y' | 'width' | 'height' | 'frame'> & { zoom: number } {\n const zoom = view ? view.scale.x : 1;\n const zoomY = view ? view.scale.y : 1;\n const cx = (origin?.x ?? 0) + (pose.x + pose.width / 2 - (view?.x ?? 0)) * zoom;\n const cy = (origin?.y ?? 0) + (pose.y + pose.height / 2 - (view?.y ?? 0)) * zoomY;\n return {\n x: cx - (pose.width * zoom) / 2,\n y: cy - (pose.height * zoom) / 2,\n width: pose.width,\n height: pose.height,\n zoom,\n frame: frameLinearOf(pose, zoomY / zoom),\n };\n}\n\n/** The linear part of the frame `pose` is drawn in, as the overlay takes it.\n * `stretch` is the view's y scale over its x scale: the overlay scales both\n * axes by the x scale, so the frame carries what is left of y. */\nfunction frameLinearOf(pose: unknown, stretch: number): TextEditScreenPose['frame'] {\n const m = poseFrameOf(pose);\n if (!m && stretch === 1) return undefined;\n const [a, b, c, d] = m ?? [1, 0, 0, 1];\n return [a, b * stretch, c, d * stretch];\n}\n\n/** A text node's paint as the canvas paints it: an inherited one is its container's. */\nfunction shownTextPaint<TData extends DefaultTextData>(\n scene: Scene<TData, string, unknown>,\n node: NonNullable<ReturnType<Scene<TData, string, unknown>['get']>>,\n): TextPaint {\n const { fill, stroke } = withInheritedPaint(node.data, inheritedPaintIn(scene, node));\n return { fill, stroke };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useSceneTextEdit.js","names":[],"sources":["../../../src/features/text/useSceneTextEdit.ts"],"sourcesContent":["/**\n * `useSceneTextEdit` — scene-aware wrapper around `useTextEdit`: scene\n * lookups for text / style / runs / screen-pose, and\n * `scene.update(id, { data })` for commits. The overlay and a double-click\n * both read the pose a node is painted at, so text inside a container whose\n * pose is a frame is edited where it is drawn.\n *\n * Defaults assume the node's `data` carries `text` / `style` / `runs`\n * directly. For custom data shapes, override any of the optional projections.\n * Consumers with non-rect poses should drop down to raw `useTextEdit` and\n * supply their own `getScreenPose`.\n */\nimport { useCallback, useEffect, useMemo, useRef, type MouseEvent } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport { asNodeId } from '../../core/scene/types';\nimport { scenePaintedPoseOf } from '../../canvas/derivedPath';\nimport type { Scene } from '../../core/scene/types';\nimport { drawOneEditing, type EditingDrawOne } from './editingDrawOne';\nimport { textHitAt } from './textHitAt';\nimport { editedData, sceneTextDrafts } from './sceneTextDrafts';\nimport type { Stroke, Fill, Inherit } from '@weasel-js/paint';\nimport { resolveScreenLength } from '@weasel-js/paint';\nimport { inheritedPaintIn } from '../../canvas/inheritedPaints';\nimport { withInheritedPaint } from '../../core/scene/inheritedPaint';\nimport { clientToCanvas } from '@weasel-js/routing';\nimport { findMountedCanvas, type MountedCanvas } from '../../canvas/mountedCanvases';\nimport type { View } from '../../core/viewport/view';\nimport type { RectPose } from 'core/geometry/unionBounds';\nimport { poseFrameOf } from '@weasel-js/geom';\nimport { isTextData, type StyledRun, type TextPaint, type TextStyle, type TextVerticalAlign } from '@weasel-js/text';\nimport { textBoxOf, type TextOverflow } from '../../canvas/nodeShapes/textPainter';\nimport { useTextEdit, type TextEditClipRect, type TextEditScreenPose, type UseTextEditReturn } from '@weasel-js/text-dom';\n\n/** Shape the default projections expect `data` to satisfy. All fields\n * optional so any object satisfies the constraint — projections fill in\n * the gaps for non-default shapes. */\nexport interface DefaultTextData {\n text?: string;\n style?: TextStyle;\n runs?: readonly StyledRun[];\n fill?: Fill | Inherit | null;\n stroke?: Stroke | Inherit | null;\n verticalAlign?: TextVerticalAlign;\n padding?: number;\n overflow?: TextOverflow;\n}\n\n/** All-optional projections + fontSize fallback. */\nexport interface UseSceneTextEditOptions<TData> {\n /**\n * Is this node text? A double-click opens an edit only on a node that\n * answers yes, and passes through any other to the text under it. Default:\n * `isTextData`, the test `inferredNodeRouting` classifies a text node by. Pass one when `getText` reads some other shape.\n */\n isText?: (data: TData) => boolean;\n /** Read plain text from `data`. Default: `data.text ?? ''`. */\n getText?: (data: TData) => string;\n /** Read style from `data`. Default: `data.style`. */\n getStyle?: (data: TData) => TextStyle | undefined;\n /** Read the node's paint from `data`. Default: `data.fill` / `data.stroke`. */\n getPaint?: (data: TData) => TextPaint | undefined;\n /** Read rich-text runs from `data`. Default: `data.runs`. */\n getRuns?: (data: TData) => readonly StyledRun[] | undefined;\n /** Read the box vertical alignment from `data`. Default: `data.verticalAlign`. */\n getVerticalAlign?: (data: TData) => TextVerticalAlign | undefined;\n /** Read the inset from the node's box to its text from `data`. Default: `data.padding`. */\n getPadding?: (data: TData) => number | undefined;\n /** Read whether the node cuts its text at its box from `data`, which the\n * overlay then does too. Default: `data.overflow`. */\n getOverflow?: (data: TData) => TextOverflow | undefined;\n /** Produce updated data with new text. Default: `{ ...data, text }`. */\n setText?: (data: TData, text: string) => TData;\n /** Produce updated data with new runs. Default: `{ ...data, runs }`. */\n setRuns?: (data: TData, runs: StyledRun[]) => TData;\n /**\n * Produce updated data with a new node-wide style. Default:\n * `{ ...data, style }`. Written only when a range toggle has to *clear* a\n * flag the node itself sets — the run algebra is additive, so that edit\n * lowers the node flag and raises it on the runs outside the range. See\n * `useTextEdit`'s `setStyle`.\n *\n * An edit's text, runs, and style are folded through these three and\n * written as one `scene.update`, so a commit is one undo step.\n */\n setStyle?: (data: TData, style: TextStyle) => TData;\n /** Fallback fontSize when `style.fontSize` is unset. Default `16`. */\n defaultFontSize?: number;\n /**\n * The view to project through. Omit it and the view is read live from the\n * weasel canvas mounted inside `container` (the one a double-click landed\n * on, when there are several). With no canvas there, the node's world box\n * is passed through as screen pixels.\n *\n * A thunk is re-read on every projection; a plain `View` is the value from\n * the render that supplied it.\n */\n view?: View | (() => View);\n /**\n * Forwarded to `useTextEdit`: is `el` part of the editor's own chrome?\n * Focus moving into it does not end the edit. Wire it to whatever renders\n * the character controls.\n */\n isEditorChrome?: (el: Element) => boolean;\n /** Forwarded to `useTextEdit`: what Escape does to the edit. */\n escape?: 'cancel' | 'commit';\n /** Forwarded to `useTextEdit`: how long an edit waits for its face. */\n fontHold?: number;\n /** Forwarded to `useTextEdit`: called as an edit of the node `id` opens,\n * whichever way it was started. */\n onStart?: (id: string) => void;\n /** Forwarded to `useTextEdit`: called as the edit of `id` closes, after\n * any commit has been written to the scene. */\n onEnd?: (id: string) => void;\n}\n\nfunction resolveView(view: View | (() => View) | undefined): View | undefined {\n return typeof view === 'function' ? view() : view;\n}\n\n/** Return shape extends `UseTextEditReturn` with an `onDoubleClick`\n * binding for the canvas container. Double-clicking inside a text\n * node enters edit mode with the caret seeded at the clicked glyph. */\nexport interface UseSceneTextEditReturn extends UseTextEditReturn {\n /** Bind to the element wrapping `<SceneCanvas>` (the same element\n * passed as `container`, or any ancestor that receives the dblclick\n * bubble). Starts an edit on the top-most text node under the cursor. */\n onDoubleClick: (e: MouseEvent<HTMLElement>) => void;\n /** The `isText` option asked of the node with this id: what\n * `TextEditDep.isTextNode` wants, so both ways into an edit agree. */\n isTextNode: (id: string) => boolean;\n /**\n * `defaultDrawOne`, less the glyphs of the node being edited: the overlay\n * stands in for its text, and the rest of the node, a `background` among\n * it, goes on painting. Pass it as `layers.scene.drawOne`, with\n * `paintBounds: defaultPaintBounds`, in place of an `alphaFor` that hides\n * the whole node.\n */\n drawOne: EditingDrawOne;\n}\n\n/** How each field is read from a node's `data`: the option's projection, else the default shape. */\nfunction projectionsOf<TData extends DefaultTextData>(opts: { readonly current: UseSceneTextEditOptions<TData> }) {\n return {\n isText: (data: TData): boolean =>\n opts.current.isText ? opts.current.isText(data) : isTextData(data),\n text: (data: TData): string =>\n opts.current.getText ? opts.current.getText(data) : (data.text ?? ''),\n style: (data: TData): TextStyle | undefined =>\n opts.current.getStyle ? opts.current.getStyle(data) : data.style,\n runs: (data: TData): readonly StyledRun[] | undefined =>\n opts.current.getRuns ? opts.current.getRuns(data) : data.runs,\n verticalAlign: (data: TData): TextVerticalAlign | undefined =>\n opts.current.getVerticalAlign ? opts.current.getVerticalAlign(data) : data.verticalAlign,\n padding: (data: TData): number | undefined =>\n opts.current.getPadding ? opts.current.getPadding(data) : data.padding,\n overflow: (data: TData): TextOverflow | undefined =>\n opts.current.getOverflow ? opts.current.getOverflow(data) : data.overflow,\n };\n}\n\n/** Wire double-click-to-edit text on a scene: mounts a DOM editing overlay\n * over the node being edited and writes the result back as an undoable op. */\nexport function useSceneTextEdit<\n TData extends DefaultTextData,\n TLayer extends string,\n TPose extends RectPose = RectPose,\n>(\n scene: Scene<TData, TLayer, TPose>,\n container: HTMLElement | null,\n options: UseSceneTextEditOptions<TData> = {},\n): UseSceneTextEditReturn {\n // Refs, so the useTextEdit callbacks always see the current values\n // without re-binding.\n const sceneRef = useLatest(scene);\n const optsRef = useLatest(options);\n const containerRef = useLatest(container);\n // The last double-click's target, so the overlay projects through the\n // canvas the edit was opened on.\n const openedOnRef = useRef<EventTarget | null>(null);\n const drafts = useMemo(() => sceneTextDrafts(sceneRef, optsRef), [sceneRef, optsRef]);\n useEffect(() => () => drafts.close(), [drafts]);\n\n // The canvas's box in container pixels is both the origin its view projects\n // from and the region its glyphs are clipped to.\n const surface = (): { canvas: MountedCanvas; box: TextEditClipRect } | null => {\n const root = containerRef.current;\n const canvas = root ? findMountedCanvas(root, openedOnRef.current) : null;\n if (!root || !canvas) return null;\n const a = canvas.element.getBoundingClientRect();\n const b = root.getBoundingClientRect();\n return {\n canvas,\n box: {\n x: a.left - b.left - root.clientLeft + root.scrollLeft,\n y: a.top - b.top - root.clientTop + root.scrollTop,\n width: a.width,\n height: a.height,\n },\n };\n };\n\n const read = useMemo(() => projectionsOf(optsRef), [optsRef]);\n\n const edit = useTextEdit({\n container,\n isEditorChrome: (el) => optsRef.current.isEditorChrome?.(el) ?? false,\n escape: options.escape,\n fontHold: options.fontHold,\n onStart: (id) => optsRef.current.onStart?.(id),\n onEnd: (id) => {\n drafts.end(id);\n optsRef.current.onEnd?.(id);\n },\n onDraft: drafts.draft,\n getText: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.text(node.data) : '';\n },\n getStyle: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.style(node.data) : undefined;\n },\n getPaint: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n if (!node) return undefined;\n const get = optsRef.current.getPaint;\n return get ? get(node.data) : shownTextPaint(sceneRef.current, node);\n },\n getScreenPose: (id) => {\n const scene = sceneRef.current;\n const node = scene.get(asNodeId(id));\n if (!node) return null;\n const at = surface();\n const view = resolveView(optsRef.current.view) ?? at?.canvas.getView();\n return screenPoseOf(node.data, scenePaintedPoseOf(scene)(node), read, view, at?.box, optsRef.current.defaultFontSize);\n },\n getClipRect: () => surface()?.box ?? null,\n getRuns: (id) => {\n const node = sceneRef.current.get(asNodeId(id));\n return node ? read.runs(node.data) : undefined;\n },\n commit: (id, { text, runs, style }) => {\n const nid = asNodeId(id);\n const node = sceneRef.current.get(nid);\n if (!node) return;\n drafts.commit(id, editedData(node.data, { text, runs, style }, optsRef.current));\n },\n });\n\n const onDoubleClick = useCallback((e: MouseEvent<HTMLElement>) => {\n // The dblclick bubbles from the canvas up to any wrapping container; the\n // element it started on is what the click coordinates are relative to.\n const canvas = e.target instanceof HTMLElement ? e.target : null;\n if (!canvas) return;\n // Inside the editor a double-click selects a word, and its target is a run\n // span whose box the click would be measured against as if it were a canvas.\n if (canvas.closest('[contenteditable=\"true\"]')) return;\n\n // The click is un-projected here; `textHitAt` takes it back through the\n // frame the node is drawn in.\n const [canvasX, canvasY] = clientToCanvas(canvas, e.clientX, e.clientY);\n const root = containerRef.current;\n const view = resolveView(optsRef.current.view)\n ?? (root ? findMountedCanvas(root, canvas)?.getView() : undefined);\n const cx = view ? canvasX / view.scale.x + view.x : canvasX;\n const cy = view ? canvasY / view.scale.y + view.y : canvasY;\n const hit = textHitAt(sceneRef.current, read, cx, cy);\n if (!hit) return;\n openedOnRef.current = canvas;\n edit.startEdit(hit.id, { caret: hit.caret });\n }, [edit, containerRef, optsRef, read, sceneRef]);\n\n const isTextNode = useCallback((id: string): boolean => {\n const node = sceneRef.current.get(asNodeId(id));\n return node !== undefined && read.isText(node.data);\n }, [read, sceneRef]);\n\n const drawOne = useMemo(() => drawOneEditing(edit.editingId), [edit.editingId]);\n return { ...edit, onDoubleClick, isTextNode, drawOne };\n}\n\n/** The overlay's pose for a node painted at `painted`: its text box, inset\n * about the box center, which is all the overlay's frame needs, projected\n * through `view`. */\nfunction screenPoseOf<TData extends DefaultTextData>(\n d: TData,\n painted: RectPose,\n read: ReturnType<typeof projectionsOf<TData>>,\n view: View | undefined,\n origin: TextEditClipRect | undefined,\n defaultFontSize = 16,\n): TextEditScreenPose {\n const inset = textBoxOf({ padding: read.padding(d) }, painted);\n const box = screenBoxOf({ ...painted, ...inset }, view, origin);\n return {\n ...box,\n // Against `zoom`, the same factor the overlay scales back up by, so a\n // `{ px }` size arrives on screen at the pixel count it names.\n fontSize: resolveScreenLength(read.style(d)?.fontSize ?? defaultFontSize, box.zoom),\n verticalAlign: read.verticalAlign(d),\n ...(read.overflow(d) === 'clip' ? { clip: clipToBox(inset, painted) } : {}),\n };\n}\n\n/** How far `box` reaches past `inner` on each side: the overlay's cut at\n * `box` when its own pose is `inner`. */\nfunction clipToBox(inner: RectPose, box: RectPose): NonNullable<TextEditScreenPose['clip']> {\n return {\n top: inner.y - box.y,\n left: inner.x - box.x,\n bottom: box.y + box.height - (inner.y + inner.height),\n right: box.x + box.width - (inner.x + inner.width),\n };\n}\n\n/**\n * `pose`'s box as the overlay takes it, `origin` being the canvas's corner in\n * container pixels. Only the box center is projected, since the overlay's\n * frame is about it. Width and height stay in world units and reach the\n * screen through the overlay's own `scale(zoom)` — see\n * `TextEditScreenPose.zoom`.\n */\nfunction screenBoxOf(\n pose: RectPose,\n view: View | undefined,\n origin: { x: number; y: number } | undefined,\n): Pick<TextEditScreenPose, 'x' | 'y' | 'width' | 'height' | 'frame'> & { zoom: number } {\n const zoom = view ? view.scale.x : 1;\n const zoomY = view ? view.scale.y : 1;\n const cx = (origin?.x ?? 0) + (pose.x + pose.width / 2 - (view?.x ?? 0)) * zoom;\n const cy = (origin?.y ?? 0) + (pose.y + pose.height / 2 - (view?.y ?? 0)) * zoomY;\n return {\n x: cx - (pose.width * zoom) / 2,\n y: cy - (pose.height * zoom) / 2,\n width: pose.width,\n height: pose.height,\n zoom,\n frame: frameLinearOf(pose, zoomY / zoom),\n };\n}\n\n/** The linear part of the frame `pose` is drawn in, as the overlay takes it.\n * `stretch` is the view's y scale over its x scale: the overlay scales both\n * axes by the x scale, so the frame carries what is left of y. */\nfunction frameLinearOf(pose: unknown, stretch: number): TextEditScreenPose['frame'] {\n const m = poseFrameOf(pose);\n if (!m && stretch === 1) return undefined;\n const [a, b, c, d] = m ?? [1, 0, 0, 1];\n return [a, b * stretch, c, d * stretch];\n}\n\n/** A text node's paint as the canvas paints it: an inherited one is its container's. */\nfunction shownTextPaint<TData extends DefaultTextData>(\n scene: Scene<TData, string, unknown>,\n node: NonNullable<ReturnType<Scene<TData, string, unknown>['get']>>,\n): TextPaint {\n const { fill, stroke } = withInheritedPaint(node.data, inheritedPaintIn(scene, node));\n return { fill, stroke };\n}\n"],"mappings":"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"}
|