@weasel-js/core 1.8.0 → 1.9.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.
Files changed (139) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/README.md +9 -5
  3. package/dist/animation/useAnimator.js +20 -13
  4. package/dist/animation/useAnimator.js.map +1 -1
  5. package/dist/{builtins-BW32dOXy.d.ts → builtins-CQcvcLXh.d.ts} +105 -31
  6. package/dist/canvas/DrawCanvas.js +33 -33
  7. package/dist/canvas/DrawCanvas.js.map +1 -1
  8. package/dist/canvas/MinimapCanvas.js +29 -29
  9. package/dist/canvas/MinimapCanvas.js.map +1 -1
  10. package/dist/canvas/NodeShape.js +63 -54
  11. package/dist/canvas/NodeShape.js.map +1 -1
  12. package/dist/canvas/SceneCanvas/features.js +26 -5
  13. package/dist/canvas/SceneCanvas/features.js.map +1 -1
  14. package/dist/canvas/SceneCanvas/useSceneSelectTool.js +3 -2
  15. package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
  16. package/dist/canvas/SceneCanvas.js +526 -529
  17. package/dist/canvas/SceneCanvas.js.map +1 -1
  18. package/dist/canvas/SceneViewCanvas.js +35 -35
  19. package/dist/canvas/SceneViewCanvas.js.map +1 -1
  20. package/dist/canvas/defaultDrawOne.js +6 -1
  21. package/dist/canvas/defaultDrawOne.js.map +1 -1
  22. package/dist/canvas/pickWalk.js.map +1 -1
  23. package/dist/canvas/sceneAdapter.js.map +1 -1
  24. package/dist/canvas/useHitObserver.js +23 -0
  25. package/dist/canvas/useHitObserver.js.map +1 -0
  26. package/dist/canvas/useHostAnchor.js.map +1 -1
  27. package/dist/core/device/useDeviceProfile.js.map +1 -1
  28. package/dist/core/scene/derivedPath.js.map +1 -1
  29. package/dist/core/scene/effectivePose.js.map +1 -1
  30. package/dist/core/scene/kitRegistry.js.map +1 -1
  31. package/dist/core/scene/scene.js +9 -0
  32. package/dist/core/scene/scene.js.map +1 -1
  33. package/dist/core/scene/types.js.map +1 -1
  34. package/dist/core/scene/useScene.js.map +1 -1
  35. package/dist/core/selection/useSelection.js +27 -33
  36. package/dist/core/selection/useSelection.js.map +1 -1
  37. package/dist/core/stableStringify.js +8 -0
  38. package/dist/core/stableStringify.js.map +1 -0
  39. package/dist/core/viewport/fitViewToBounds.js +3 -3
  40. package/dist/core/viewport/fitViewToBounds.js.map +1 -1
  41. package/dist/core/viewport/screenSlop.js +8 -2
  42. package/dist/core/viewport/screenSlop.js.map +1 -1
  43. package/dist/features/minimap/actions.js.map +1 -1
  44. package/dist/features/paths/markerCommands.js +95 -63
  45. package/dist/features/paths/markerCommands.js.map +1 -1
  46. package/dist/features/paths/tessellate/dash.js +52 -0
  47. package/dist/features/paths/tessellate/dash.js.map +1 -0
  48. package/dist/features/paths/tessellate/insets.js +32 -0
  49. package/dist/features/paths/tessellate/insets.js.map +1 -0
  50. package/dist/features/paths/tessellate/metric.js +72 -0
  51. package/dist/features/paths/tessellate/metric.js.map +1 -0
  52. package/dist/features/paths/tessellate/stroke.js +74 -134
  53. package/dist/features/paths/tessellate/stroke.js.map +1 -1
  54. package/dist/features/paths/tessellate/vertexWidths.js +32 -0
  55. package/dist/features/paths/tessellate/vertexWidths.js.map +1 -0
  56. package/dist/features/pointer/PointerContext.js +2 -2
  57. package/dist/features/pointer/PointerContext.js.map +1 -1
  58. package/dist/features/poseRun/usePoseRun.js.map +1 -1
  59. package/dist/features/text/useTextEdit.js +86 -84
  60. package/dist/features/text/useTextEdit.js.map +1 -1
  61. package/dist/index.d.ts +84 -45
  62. package/dist/index.js +269 -268
  63. package/dist/interactions/actions/defaults/align.js.map +1 -1
  64. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  65. package/dist/interactions/actions/defaults/areaSelect.js.map +1 -1
  66. package/dist/interactions/actions/defaults/booleans.js.map +1 -1
  67. package/dist/interactions/actions/defaults/cancelGesture.js.map +1 -1
  68. package/dist/interactions/actions/defaults/clearSelection.js.map +1 -1
  69. package/dist/interactions/actions/defaults/clipboard.js.map +1 -1
  70. package/dist/interactions/actions/defaults/clone.js.map +1 -1
  71. package/dist/interactions/actions/defaults/createOutlines.js +1 -1
  72. package/dist/interactions/actions/defaults/createOutlines.js.map +1 -1
  73. package/dist/interactions/actions/defaults/createPaintAction.js.map +1 -1
  74. package/dist/interactions/actions/defaults/delete.js.map +1 -1
  75. package/dist/interactions/actions/defaults/distribute.js.map +1 -1
  76. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  77. package/dist/interactions/actions/defaults/editAnchors.js.map +1 -1
  78. package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
  79. package/dist/interactions/actions/defaults/enterTextEdit.js.map +1 -1
  80. package/dist/interactions/actions/defaults/escape.js +1 -1
  81. package/dist/interactions/actions/defaults/escape.js.map +1 -1
  82. package/dist/interactions/actions/defaults/exitPathEdit.js.map +1 -1
  83. package/dist/interactions/actions/defaults/flip.js.map +1 -1
  84. package/dist/interactions/actions/defaults/group.js.map +1 -1
  85. package/dist/interactions/actions/defaults/ingest.js.map +1 -1
  86. package/dist/interactions/actions/defaults/insert.js.map +1 -1
  87. package/dist/interactions/actions/defaults/insertPathAnchor.js +1 -1
  88. package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
  89. package/dist/interactions/actions/defaults/lassoSelect.js.map +1 -1
  90. package/dist/interactions/actions/defaults/move.js.map +1 -1
  91. package/dist/interactions/actions/defaults/nudge.js.map +1 -1
  92. package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
  93. package/dist/interactions/actions/defaults/reorder.js.map +1 -1
  94. package/dist/interactions/actions/defaults/requiresSelection.js.map +1 -1
  95. package/dist/interactions/actions/defaults/resize.js.map +1 -1
  96. package/dist/interactions/actions/defaults/rotate.js.map +1 -1
  97. package/dist/interactions/actions/defaults/selectAll.js.map +1 -1
  98. package/dist/interactions/actions/defaults/slice.js.map +1 -1
  99. package/dist/interactions/actions/defaults/toolActivate.js.map +1 -1
  100. package/dist/interactions/actions/defaults/toolResetToDefault.js.map +1 -1
  101. package/dist/interactions/actions/defaults/undoRedo.js +1 -1
  102. package/dist/interactions/actions/defaults/undoRedo.js.map +1 -1
  103. package/dist/interactions/actions/defaults/viewportDragPan.js.map +1 -1
  104. package/dist/interactions/actions/defaults/viewportWheelPan.js.map +1 -1
  105. package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
  106. package/dist/interactions/actions/planeInput.js.map +1 -1
  107. package/dist/interactions/gestures/shared/screenTolerance.js.map +1 -1
  108. package/dist/{registerProgram-ateHDGjw.d.ts → registerProgram-BMZRDgrh.d.ts} +4 -0
  109. package/dist/renderer/cache/markerCommandCache.js +46 -42
  110. package/dist/renderer/cache/markerCommandCache.js.map +1 -1
  111. package/dist/renderer/cache/outlineStrokeMeshCache.js +30 -25
  112. package/dist/renderer/cache/outlineStrokeMeshCache.js.map +1 -1
  113. package/dist/renderer/cache/strokeMeshCache.js +42 -31
  114. package/dist/renderer/cache/strokeMeshCache.js.map +1 -1
  115. package/dist/renderer/cullDrawCommands.js +32 -31
  116. package/dist/renderer/cullDrawCommands.js.map +1 -1
  117. package/dist/renderer/draw.js +315 -362
  118. package/dist/renderer/draw.js.map +1 -1
  119. package/dist/renderer/drawBatch.js.map +1 -1
  120. package/dist/renderer/glyphOutlineMesh.js +67 -0
  121. package/dist/renderer/glyphOutlineMesh.js.map +1 -0
  122. package/dist/renderer/math/mat3.js +8 -3
  123. package/dist/renderer/math/mat3.js.map +1 -1
  124. package/dist/renderer/shaders/batchFill.js +3 -2
  125. package/dist/renderer/shaders/batchFill.js.map +1 -1
  126. package/dist/renderer/strokeLengths.js +50 -0
  127. package/dist/renderer/strokeLengths.js.map +1 -0
  128. package/dist/renderer.d.ts +2 -2
  129. package/dist/{test-seams-fYf6m5pu.d.ts → test-seams-CuIxe0xY.d.ts} +1 -1
  130. package/dist/test-seams.d.ts +2 -2
  131. package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
  132. package/dist/tools/builtin/pen/usePenTool.js +1 -1
  133. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  134. package/dist/tools/builtin/select/selectionContributions.js +43 -23
  135. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  136. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  137. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  138. package/dist/version.js +1 -1
  139. package/package.json +17 -16
@@ -1 +1 @@
1
- {"version":3,"file":"usePoseRun.js","names":["EMPTY","usePoseRun","optsRef","useLatest","opts","state","useRef","running","frame","mounted","loop","useVisibleRaf","syncState","useCallback","pinnedNow","pinned","id","overrides","entry","commit","scene","moved","previews","pose","dropPreviewOverrides","halt","tick","poses","syncPreviewOverrides","done","useEffect","useMemo"],"sources":["../../../src/features/poseRun/usePoseRun.ts"],"sourcesContent":["/**\n * A pose run: poses published per frame, committed once.\n *\n * The frames go to `scene.overrides` — the ephemeral table a drag publishes to,\n * which `effectivePose`, the derived-geometry lookup and the pick source\n * already read. So an edge follows a node the run is moving with nothing added,\n * and the whole run lands as one undo entry when it settles.\n *\n * It knows nothing about layout. Each frame it asks `step` for poses and\n * whether it is finished; a relaxation, an eased transition to a target, and a\n * scrubbed timeline are all the same shape to it.\n *\n * **A node another gesture owns is pinned, not driven.** The run publishes\n * entries it holds by reference, so an override it did not put there belongs to\n * somebody else — a drag, a resize. It never writes that id, never commits it,\n * and hands it to `step` as pinned so the producer can hold its neighbors\n * against it.\n */\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport { useVisibleRaf } from '../../scheduling/useVisibleRaf';\nimport {\n dropPreviewOverrides,\n syncPreviewOverrides,\n} from '../../interactions/actions/previewOverrides';\nimport type { NodeId, Scene } from '../../core/scene/types';\n\n/** What a producer is told before it is asked for a frame. */\nexport interface PoseRunCtx<TPose> {\n /** Nodes another gesture is moving, and the pose each is drawn at. The run\n * will not write these, so a producer holds them fixed. */\n pinned: ReadonlyMap<NodeId, TPose>;\n /** Frames this run has produced, starting at 0. */\n frame: number;\n}\n\n/** One frame of a run. */\nexport interface PoseRunStep<TPose> {\n /** Where the nodes it drives are this frame — the whole picture, not a\n * delta. An id the frame omits stops being published, which is how a node\n * leaves the run's hands: a producer that drops a grabbed box and its rows\n * from one frame has released them by the next. */\n poses: Iterable<readonly [NodeId, TPose]>;\n /** Whether the run is finished. The frame is published either way, and a\n * finished run commits. */\n done: boolean;\n}\n\n/** Options for `usePoseRun`. Read fresh each frame, so they may change mid-run. */\nexport interface UsePoseRunOptions<TPose> {\n scene: Scene<unknown, string, TPose>;\n /** Called once per frame while running, for that frame's poses. */\n step: (ctx: PoseRunCtx<TPose>) => PoseRunStep<TPose>;\n /** The undo entry's name. Default `'Layout'`. */\n label?: string;\n /** How many nodes the commit wrote. Fires after the ops land. */\n onCommit?: (moved: number) => void;\n /** Clock injection, for tests. Defaults to `requestAnimationFrame`. */\n requestFrame?: (cb: (t: number) => void) => number;\n cancelFrame?: (handle: number) => void;\n}\n\n/** Controls for a pose run. Stable for the life of the component. */\nexport interface PoseRun {\n /** Begin a new run, counting frames from 0. Idempotent while running. */\n start(): void;\n /** Finish now: commit what is published, then drop the overrides. */\n stop(): void;\n /** Abandon: drop the overrides and write nothing, like a canceled drag. */\n cancel(): void;\n isRunning(): boolean;\n}\n\nconst EMPTY: ReadonlyMap<NodeId, unknown> = new Map<NodeId, unknown>();\n\n/**\n * Drive node poses frame by frame through `scene.overrides`, committing them as\n * one undo entry when `step` reports done or `stop` is called. Idle until\n * `start`; unmounting abandons the run without writing.\n */\nexport function usePoseRun<TPose>(opts: UsePoseRunOptions<TPose>): PoseRun {\n const optsRef = useLatest(opts);\n\n /** This frame's poses, and the entries published for them. Held by\n * reference so a frame mutates in place rather than re-notifying per node. */\n const state = useRef({\n previews: new Map<NodeId, unknown>(),\n overrideEntries: new Map<NodeId, { pose: unknown }>(),\n });\n const running = useRef(false);\n const frame = useRef(0);\n const mounted = useRef(true);\n\n // The gate defaults an absent clock to `requestAnimationFrame` itself, so\n // these pass straight through rather than being defaulted twice.\n const loop = useVisibleRaf(() => { tick(); }, {\n requestFrame: opts.requestFrame,\n cancelFrame: opts.cancelFrame,\n });\n\n /** The scene as the previous frame left it, for `syncPreviewOverrides`. */\n const syncState = useCallback((): {\n scene: Scene<unknown, string, unknown>;\n previews: Map<NodeId, unknown>;\n overrideEntries: Map<NodeId, { pose: unknown }>;\n } => ({\n scene: optsRef.current.scene as Scene<unknown, string, unknown>,\n previews: state.current.previews,\n overrideEntries: state.current.overrideEntries,\n }), [optsRef]);\n\n /** Overrides somebody else published, and the pose each carries. */\n const pinnedNow = (): ReadonlyMap<NodeId, TPose> => {\n const { overrides } = optsRef.current.scene;\n let pinned: Map<NodeId, TPose> | undefined;\n for (const id of overrides.ids()) {\n const entry = overrides.get(id);\n if (entry === undefined || entry === state.current.overrideEntries.get(id)) continue;\n if (entry.pose === undefined) continue;\n (pinned ??= new Map()).set(id, entry.pose);\n }\n return pinned ?? (EMPTY as ReadonlyMap<NodeId, TPose>);\n };\n\n const commit = (): void => {\n const { previews } = state.current;\n const scene = optsRef.current.scene;\n let moved = 0;\n if (previews.size > 0) {\n scene.batch(optsRef.current.label ?? 'Layout', () => {\n for (const [id, pose] of previews) {\n if (scene.get(id) === undefined) continue;\n scene.setPose(id, pose as TPose);\n moved++;\n }\n });\n }\n // After the ops land: dropping first leaves a window in which the scene\n // answers with the pre-run pose.\n dropPreviewOverrides(syncState());\n previews.clear();\n optsRef.current.onCommit?.(moved);\n };\n\n const halt = (): void => {\n running.current = false;\n loop.cancel();\n };\n\n const tick = (): void => {\n if (!mounted.current || !running.current) return;\n const pinned = pinnedNow();\n const { poses, done } = optsRef.current.step({ pinned, frame: frame.current });\n frame.current++;\n // Each frame replaces the last: an id this one omits — a node just\n // grabbed, or a row under one — stops being published, rather than being\n // held at a pose from before the press while the gesture carries it\n // somewhere else.\n state.current.previews.clear();\n for (const [id, pose] of poses) {\n if (pinned.has(id)) continue;\n state.current.previews.set(id, pose);\n }\n syncPreviewOverrides(syncState());\n if (done) {\n halt();\n commit();\n return;\n }\n loop.request();\n };\n\n useEffect(() => {\n mounted.current = true;\n const { previews } = state.current;\n return () => {\n mounted.current = false;\n loop.cancel();\n // Teardown is not a decision: an unmounted run abandons its frames\n // rather than writing them.\n dropPreviewOverrides(syncState());\n previews.clear();\n };\n }, [loop, syncState]);\n\n return useMemo<PoseRun>(() => ({\n start() {\n if (running.current || !mounted.current) return;\n running.current = true;\n frame.current = 0;\n loop.request();\n },\n stop() {\n if (!running.current) return;\n halt();\n commit();\n },\n cancel() {\n halt();\n dropPreviewOverrides(syncState());\n state.current.previews.clear();\n },\n isRunning: () => running.current,\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }), [loop]);\n}\n"],"mappings":";;;;;AAyEA,IAAMA,oBAAsC,IAAI,IAAqB;AAOrE,SAAgBC,EAAkB,GAAyC;CACzE,IAAMC,IAAUC,EAAUC,CAAI,GAIxBC,IAAQC,EAAO;EACnB,0BAAU,IAAI,IAAqB;EACnC,iCAAiB,IAAI,IAA+B;CACtD,CAAC,GACKC,IAAUD,EAAO,EAAK,GACtBE,IAAQF,EAAO,CAAC,GAChBG,IAAUH,EAAO,EAAI,GAIrBI,IAAOC,QAAoB;EAAE,EAAK;CAAG,GAAG;EAC5C,cAAcP,EAAK;EACnB,aAAaA,EAAK;CACpB,CAAC,GAGKQ,IAAYC,SAIZ;EACJ,OAAOX,EAAQ,QAAQ;EACvB,UAAUG,EAAM,QAAQ;EACxB,iBAAiBA,EAAM,QAAQ;CACjC,IAAI,CAACH,CAAO,CAAC,GAGPY,UAA8C;EAClD,IAAM,EAAE,iBAAcZ,EAAQ,QAAQ,OAClCa;EACJ,KAAK,IAAMC,KAAMC,EAAU,IAAI,GAAG;GAChC,IAAMC,IAAQD,EAAU,IAAID,CAAE;GAC9B,AAAIE,MAAU,KAAA,KAAaA,MAAUb,EAAM,QAAQ,gBAAgB,IAAIW,CAAE,KACrEE,EAAM,SAAS,KAAA,MAClB,sBAAW,IAAI,IAAI,EAAA,CAAG,IAAIF,GAAIE,EAAM,IAAI;EAC3C;EACA,OAAOH,KAAWf;CACpB,GAEMmB,UAAqB;EACzB,IAAM,EAAE,gBAAad,EAAM,SACrBe,IAAQlB,EAAQ,QAAQ,OAC1BmB,IAAQ;EAcZ,AAbIC,EAAS,OAAO,KAClBF,EAAM,MAAMlB,EAAQ,QAAQ,SAAS,gBAAgB;GACnD,KAAK,IAAM,CAACc,GAAIO,MAASD,GACvB,AAAIF,EAAM,IAAIJ,CAAE,MAAM,KAAA,MACtBI,EAAM,QAAQJ,GAAIO,CAAa,GAC/B;EAEJ,CAAC,GAIHC,EAAqBZ,EAAU,CAAC,GAChCU,EAAS,MAAM,GACfpB,EAAQ,QAAQ,WAAWmB,CAAK;CAClC,GAEMI,UAAmB;EAEvB,AADA,EAAQ,UAAU,IAClBf,EAAK,OAAO;CACd,GAEMgB,UAAmB;EACvB,IAAI,CAACjB,EAAQ,WAAW,CAACF,EAAQ,SAAS;EAC1C,IAAMQ,IAASD,EAAU,GACnB,EAAE,UAAO,YAASZ,EAAQ,QAAQ,KAAK;GAAE;GAAQ,OAAOM,EAAM;EAAQ,CAAC;EAM7E,AALA,EAAM,WAKNH,EAAM,QAAQ,SAAS,MAAM;EAC7B,KAAK,IAAM,CAACW,GAAIO,MAASI,GACvB,AAAIZ,EAAO,IAAIC,CAAE,KACjBX,EAAM,QAAQ,SAAS,IAAIW,GAAIO,CAAI;EAGrC,IADAK,EAAqBhB,EAAU,CAAC,GAC5BiB,GAAM;GAER,AADAJ,EAAK,GACLN,EAAO;GACP;EACF;EACA,EAAK,QAAQ;CACf;CAeA,OAbAW,QAAgB;EACd,EAAQ,UAAU;EAClB,IAAM,EAAE,gBAAazB,EAAM;EAC3B,aAAa;GAMX,AALA,EAAQ,UAAU,IAClBK,EAAK,OAAO,GAGZc,EAAqBZ,EAAU,CAAC,GAChCU,EAAS,MAAM;EACjB;CACF,GAAG,CAACZ,GAAME,CAAS,CAAC,GAEbmB,SAAwB;EAC7B,QAAQ;GACN,AAAI,GAAQ,WAAYtB,EAAQ,YAChC,EAAQ,UAAU,IAClB,EAAM,UAAU,GAChBC,EAAK,QAAQ;EACf;EACA,OAAO;GACL,AAAKH,EAAQ,YACbkB,EAAK,GACLN,EAAO;EACT;EACA,SAAS;GAGP,AAFAM,EAAK,GACLD,EAAqBZ,EAAU,CAAC,GAChCP,EAAM,QAAQ,SAAS,MAAM;EAC/B;EACA,iBAAiBE,EAAQ;CAE3B,IAAI,CAACG,CAAI,CAAC;AACZ"}
1
+ {"version":3,"file":"usePoseRun.js","names":["EMPTY","usePoseRun","optsRef","useLatest","opts","state","useRef","running","frame","mounted","loop","useVisibleRaf","syncState","useCallback","pinnedNow","pinned","id","overrides","entry","commit","scene","moved","previews","pose","dropPreviewOverrides","halt","tick","poses","syncPreviewOverrides","done","useEffect","useMemo"],"sources":["../../../src/features/poseRun/usePoseRun.ts"],"sourcesContent":["/**\n * A pose run: poses published per frame, committed once.\n *\n * The frames go to `scene.overrides` — the ephemeral table a drag publishes to,\n * which `effectivePose`, the derived-geometry lookup and the pick source\n * already read. So an edge follows a node the run is moving with nothing added,\n * and the whole run lands as one undo entry when it settles.\n *\n * It knows nothing about layout. Each frame it asks `step` for poses and\n * whether it is finished; a relaxation, an eased transition to a target, and a\n * scrubbed timeline are all the same shape to it.\n *\n * **A node another gesture owns is pinned, not driven.** The run publishes\n * entries it holds by reference, so an override it did not put there belongs to\n * somebody else — a drag, a resize. It never writes that id, never commits it,\n * and hands it to `step` as pinned so the producer can hold its neighbors\n * against it.\n */\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport { useVisibleRaf } from '../../scheduling/useVisibleRaf';\nimport {\n dropPreviewOverrides,\n syncPreviewOverrides,\n} from '../../interactions/actions/previewOverrides';\nimport type { NodeId, Scene } from '../../core/scene/types';\n\n/** What a producer is told before it is asked for a frame. */\nexport interface PoseRunCtx<TPose> {\n /** Nodes another gesture is moving, and the pose each is drawn at. The run\n * will not write these, so a producer holds them fixed. */\n pinned: ReadonlyMap<NodeId, TPose>;\n /** Frames this run has produced, starting at 0. */\n frame: number;\n}\n\n/** One frame of a run. */\nexport interface PoseRunStep<TPose> {\n /** Where the nodes it drives are this frame — the whole picture, not a\n * delta. An id the frame omits stops being published, which is how a node\n * leaves the run's hands: a producer that drops a grabbed box and its rows\n * from one frame has released them by the next. */\n poses: Iterable<readonly [NodeId, TPose]>;\n /** Whether the run is finished. The frame is published either way, and a\n * finished run commits. */\n done: boolean;\n}\n\n/** Options for `usePoseRun`. Read fresh each frame, so they may change mid-run. */\nexport interface UsePoseRunOptions<TPose> {\n scene: Scene<unknown, string, TPose>;\n /** Called once per frame while running, for that frame's poses. */\n step: (ctx: PoseRunCtx<TPose>) => PoseRunStep<TPose>;\n /** The undo entry's name. Default `'Layout'`. */\n label?: string;\n /** How many nodes the commit wrote. Fires after the ops land. */\n onCommit?: (moved: number) => void;\n /** Clock injection, for tests. Defaults to `requestAnimationFrame`. */\n requestFrame?: (cb: (t: number) => void) => number;\n cancelFrame?: (handle: number) => void;\n}\n\n/** Controls for a pose run. Stable for the life of the component. */\nexport interface PoseRun {\n /** Begin a new run, counting frames from 0. Idempotent while running. */\n start(): void;\n /** Finish now: commit what is published, then drop the overrides. */\n stop(): void;\n /** Abandon: drop the overrides and write nothing, like a canceled drag. */\n cancel(): void;\n isRunning(): boolean;\n}\n\nconst EMPTY: ReadonlyMap<NodeId, unknown> = new Map<NodeId, unknown>();\n\n/**\n * Drive node poses frame by frame through `scene.overrides`, committing them as\n * one undo entry when `step` reports done or `stop` is called. Idle until\n * `start`; unmounting abandons the run without writing.\n */\nexport function usePoseRun<TPose>(opts: UsePoseRunOptions<TPose>): PoseRun {\n const optsRef = useLatest(opts);\n\n /** This frame's poses, and the entries published for them. Held by\n * reference so a frame mutates in place rather than re-notifying per node. */\n const state = useRef({\n previews: new Map<NodeId, unknown>(),\n overrideEntries: new Map<NodeId, { pose: unknown }>(),\n });\n const running = useRef(false);\n const frame = useRef(0);\n const mounted = useRef(true);\n\n // The gate defaults an absent clock to `requestAnimationFrame` itself, so\n // these pass straight through rather than being defaulted twice.\n const loop = useVisibleRaf(() => { tick(); }, {\n requestFrame: opts.requestFrame,\n cancelFrame: opts.cancelFrame,\n });\n\n /** The scene as the previous frame left it, for `syncPreviewOverrides`. */\n const syncState = useCallback((): {\n scene: Scene<unknown, string, unknown>;\n previews: Map<NodeId, unknown>;\n overrideEntries: Map<NodeId, { pose: unknown }>;\n } => ({\n scene: optsRef.current.scene,\n previews: state.current.previews,\n overrideEntries: state.current.overrideEntries,\n }), [optsRef]);\n\n /** Overrides somebody else published, and the pose each carries. */\n const pinnedNow = (): ReadonlyMap<NodeId, TPose> => {\n const { overrides } = optsRef.current.scene;\n let pinned: Map<NodeId, TPose> | undefined;\n for (const id of overrides.ids()) {\n const entry = overrides.get(id);\n if (entry === undefined || entry === state.current.overrideEntries.get(id)) continue;\n if (entry.pose === undefined) continue;\n (pinned ??= new Map()).set(id, entry.pose);\n }\n return pinned ?? (EMPTY as ReadonlyMap<NodeId, TPose>);\n };\n\n const commit = (): void => {\n const { previews } = state.current;\n const scene = optsRef.current.scene;\n let moved = 0;\n if (previews.size > 0) {\n scene.batch(optsRef.current.label ?? 'Layout', () => {\n for (const [id, pose] of previews) {\n if (scene.get(id) === undefined) continue;\n scene.setPose(id, pose as TPose);\n moved++;\n }\n });\n }\n // After the ops land: dropping first leaves a window in which the scene\n // answers with the pre-run pose.\n dropPreviewOverrides(syncState());\n previews.clear();\n optsRef.current.onCommit?.(moved);\n };\n\n const halt = (): void => {\n running.current = false;\n loop.cancel();\n };\n\n const tick = (): void => {\n if (!mounted.current || !running.current) return;\n const pinned = pinnedNow();\n const { poses, done } = optsRef.current.step({ pinned, frame: frame.current });\n frame.current++;\n // Each frame replaces the last: an id this one omits — a node just\n // grabbed, or a row under one — stops being published, rather than being\n // held at a pose from before the press while the gesture carries it\n // somewhere else.\n state.current.previews.clear();\n for (const [id, pose] of poses) {\n if (pinned.has(id)) continue;\n state.current.previews.set(id, pose);\n }\n syncPreviewOverrides(syncState());\n if (done) {\n halt();\n commit();\n return;\n }\n loop.request();\n };\n\n useEffect(() => {\n mounted.current = true;\n const { previews } = state.current;\n return () => {\n mounted.current = false;\n loop.cancel();\n // Teardown is not a decision: an unmounted run abandons its frames\n // rather than writing them.\n dropPreviewOverrides(syncState());\n previews.clear();\n };\n }, [loop, syncState]);\n\n return useMemo<PoseRun>(() => ({\n start() {\n if (running.current || !mounted.current) return;\n running.current = true;\n frame.current = 0;\n loop.request();\n },\n stop() {\n if (!running.current) return;\n halt();\n commit();\n },\n cancel() {\n halt();\n dropPreviewOverrides(syncState());\n state.current.previews.clear();\n },\n isRunning: () => running.current,\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }), [loop]);\n}\n"],"mappings":";;;;;AAyEA,IAAMA,oBAAsC,IAAI,IAAqB;AAOrE,SAAgBC,EAAkB,GAAyC;CACzE,IAAMC,IAAUC,EAAUC,CAAI,GAIxBC,IAAQC,EAAO;EACnB,0BAAU,IAAI,IAAqB;EACnC,iCAAiB,IAAI,IAA+B;CACtD,CAAC,GACKC,IAAUD,EAAO,EAAK,GACtBE,IAAQF,EAAO,CAAC,GAChBG,IAAUH,EAAO,EAAI,GAIrBI,IAAOC,QAAoB;EAAE,EAAK;CAAG,GAAG;EAC5C,cAAcP,EAAK;EACnB,aAAaA,EAAK;CACpB,CAAC,GAGKQ,IAAYC,SAIZ;EACJ,OAAOX,EAAQ,QAAQ;EACvB,UAAUG,EAAM,QAAQ;EACxB,iBAAiBA,EAAM,QAAQ;CACjC,IAAI,CAACH,CAAO,CAAC,GAGPY,UAA8C;EAClD,IAAM,EAAE,iBAAcZ,EAAQ,QAAQ,OAClCa;EACJ,KAAK,IAAMC,KAAMC,EAAU,IAAI,GAAG;GAChC,IAAMC,IAAQD,EAAU,IAAID,CAAE;GAC9B,AAAIE,MAAU,KAAA,KAAaA,MAAUb,EAAM,QAAQ,gBAAgB,IAAIW,CAAE,KACrEE,EAAM,SAAS,KAAA,MAClB,sBAAW,IAAI,IAAI,EAAA,CAAG,IAAIF,GAAIE,EAAM,IAAI;EAC3C;EACA,OAAOH,KAAWf;CACpB,GAEMmB,UAAqB;EACzB,IAAM,EAAE,gBAAad,EAAM,SACrBe,IAAQlB,EAAQ,QAAQ,OAC1BmB,IAAQ;EAcZ,AAbIC,EAAS,OAAO,KAClBF,EAAM,MAAMlB,EAAQ,QAAQ,SAAS,gBAAgB;GACnD,KAAK,IAAM,CAACc,GAAIO,MAASD,GACvB,AAAIF,EAAM,IAAIJ,CAAE,MAAM,KAAA,MACtBI,EAAM,QAAQJ,GAAIO,CAAa,GAC/B;EAEJ,CAAC,GAIHC,EAAqBZ,EAAU,CAAC,GAChCU,EAAS,MAAM,GACfpB,EAAQ,QAAQ,WAAWmB,CAAK;CAClC,GAEMI,UAAmB;EAEvB,AADA,EAAQ,UAAU,IAClBf,EAAK,OAAO;CACd,GAEMgB,UAAmB;EACvB,IAAI,CAACjB,EAAQ,WAAW,CAACF,EAAQ,SAAS;EAC1C,IAAMQ,IAASD,EAAU,GACnB,EAAE,UAAO,YAASZ,EAAQ,QAAQ,KAAK;GAAE;GAAQ,OAAOM,EAAM;EAAQ,CAAC;EAM7E,AALA,EAAM,WAKNH,EAAM,QAAQ,SAAS,MAAM;EAC7B,KAAK,IAAM,CAACW,GAAIO,MAASI,GACvB,AAAIZ,EAAO,IAAIC,CAAE,KACjBX,EAAM,QAAQ,SAAS,IAAIW,GAAIO,CAAI;EAGrC,IADAK,EAAqBhB,EAAU,CAAC,GAC5BiB,GAAM;GAER,AADAJ,EAAK,GACLN,EAAO;GACP;EACF;EACA,EAAK,QAAQ;CACf;CAeA,OAbAW,QAAgB;EACd,EAAQ,UAAU;EAClB,IAAM,EAAE,gBAAazB,EAAM;EAC3B,aAAa;GAMX,AALA,EAAQ,UAAU,IAClBK,EAAK,OAAO,GAGZc,EAAqBZ,EAAU,CAAC,GAChCU,EAAS,MAAM;EACjB;CACF,GAAG,CAACZ,GAAME,CAAS,CAAC,GAEbmB,SAAwB;EAC7B,QAAQ;GACN,AAAI,GAAQ,WAAYtB,EAAQ,YAChC,EAAQ,UAAU,IAClB,EAAM,UAAU,GAChBC,EAAK,QAAQ;EACf;EACA,OAAO;GACL,AAAKH,EAAQ,YACbkB,EAAK,GACLN,EAAO;EACT;EACA,SAAS;GAGP,AAFAM,EAAK,GACLD,EAAqBZ,EAAU,CAAC,GAChCP,EAAM,QAAQ,SAAS,MAAM;EAC/B;EACA,iBAAiBE,EAAQ;CAE3B,IAAI,CAACG,CAAI,CAAC;AACZ"}
@@ -3,12 +3,12 @@ import { SMALL_CAPS_SCALE_PROPERTY as t, appendOverlayText as n, charOffsetToDom
3
3
  import { applyStyleToRange as c, patchRangeStyle as l, runsCarryStyling as u, styleAtRange as d, supersededKey as f } from "./runs/rangeStyle.js";
4
4
  import { nodeHasFlag as p, setFlagOverRange as m, unboldPatch as h } from "./runs/flagRange.js";
5
5
  import { rangeWeight as g } from "./runs/effectiveRangeStyle.js";
6
- import { cssFontFamily as _, cssFontFamilyLoading as v } from "@weasel-js/font";
7
- import { fontString as y, layoutTextPose as b, numericWeight as x, resolveAlign as S, resolveTextStyle as C, runsToPlainText as w, scriptMetricsFor as T, smallCapsScaleFor as E, verticalAlignOffset as D } from "@weasel-js/text";
8
- import { useCallback as O, useEffect as k, useRef as A, useState as j } from "react";
9
- import { useLatest as M } from "@weasel-js/react";
6
+ import { cssFontFamily as _, cssFontFamilyLoading as v, isCanvasFont as y } from "@weasel-js/font";
7
+ import { fontString as b, layoutTextPose as x, numericWeight as S, resolveAlign as C, resolveTextStyle as w, runsToPlainText as T, scriptMetricsFor as E, smallCapsScaleFor as D, verticalAlignOffset as O } from "@weasel-js/text";
8
+ import { useCallback as k, useEffect as A, useRef as j, useState as M } from "react";
9
+ import { useLatest as N } from "@weasel-js/react";
10
10
  //#region src/features/text/useTextEdit.ts
11
- var N = [
11
+ var P = [
12
12
  {
13
13
  key: "b",
14
14
  shift: !1,
@@ -39,21 +39,21 @@ var N = [
39
39
  shift: !0,
40
40
  toggle: "sub"
41
41
  }
42
- ], P = {
42
+ ], F = {
43
43
  "+": "=",
44
44
  _: "-"
45
45
  };
46
46
  function ee(e) {
47
47
  if (!e.metaKey && !e.ctrlKey) return null;
48
- let t = e.key.toLowerCase(), n = P[t] ?? t;
49
- return N.find((t) => t.key === n && t.shift === e.shiftKey)?.toggle ?? null;
48
+ let t = e.key.toLowerCase(), n = F[t] ?? t;
49
+ return P.find((t) => t.key === n && t.shift === e.shiftKey)?.toggle ?? null;
50
50
  }
51
- function F(e, t, n) {
51
+ function I(e, t, n) {
52
52
  if (t === "super" || t === "sub") return { script: e.script === t ? void 0 : t };
53
53
  let r = t === "bold" ? g(e, n).bold === !0 : e[t] === !0 || p(n, t);
54
54
  return { [t]: !r };
55
55
  }
56
- function I(e, t) {
56
+ function L(e, t) {
57
57
  return t > 0 ? d(e, t - 1, t) : d(e, 0, 1);
58
58
  }
59
59
  function te(e, t, n) {
@@ -74,7 +74,7 @@ function te(e, t, n) {
74
74
  }
75
75
  return a || r.push(n), c(r, 0, 0, {});
76
76
  }
77
- function L(e, t) {
77
+ function R(e, t) {
78
78
  let n = document.activeElement;
79
79
  if (n === e || e.contains(n) || n instanceof HTMLInputElement || n instanceof HTMLTextAreaElement || n instanceof HTMLElement && n.isContentEditable || n instanceof Element && n.closest("[role=\"dialog\"]") !== null) return;
80
80
  e.focus();
@@ -97,14 +97,14 @@ function ne(e, t, n) {
97
97
  let s = document.createRange();
98
98
  s.setStartAfter(a), s.collapse(!0), o.removeAllRanges(), o.addRange(s);
99
99
  }
100
- var R = Object.freeze({});
100
+ var z = Object.freeze({});
101
101
  function re(e, t) {
102
102
  let n = { ...e }, r = f(t);
103
103
  r !== void 0 && delete n[r];
104
104
  for (let [e, r] of Object.entries(t)) r === void 0 || r === !1 ? delete n[e] : n[e] = r;
105
105
  return n;
106
106
  }
107
- function z(e) {
107
+ function B(e) {
108
108
  let t = window.getSelection();
109
109
  if (!t || t.rangeCount === 0) return null;
110
110
  let n = t.getRangeAt(0);
@@ -118,7 +118,7 @@ function z(e) {
118
118
  end: r
119
119
  };
120
120
  }
121
- function B(e, t, n, i, a) {
121
+ function V(e, t, n, i, a) {
122
122
  let o = document.activeElement, c = o !== e && !e.contains(o) && (o instanceof HTMLInputElement || o instanceof HTMLTextAreaElement || o instanceof HTMLElement && o.isContentEditable);
123
123
  if (s(t, e, a), c) return;
124
124
  let l = r(e, n), u = r(e, i), d = window.getSelection();
@@ -138,43 +138,43 @@ function ie(e) {
138
138
  function ae(e, t) {
139
139
  return e === null || t === null ? e === t : e.start === t.start && e.end === t.end;
140
140
  }
141
- var V = 100;
142
- function H(t) {
143
- let i = M(t), [f, g] = j(null), _ = M(f), v = A(null), y = A(C(void 0)), b = A(() => {}), x = e(() => {
141
+ var H = 100;
142
+ function U(t) {
143
+ let i = N(t), [f, g] = M(null), _ = N(f), v = j(null), y = j(w(void 0)), b = j(() => {}), x = e(() => {
144
144
  b.current();
145
- }), S = A("all"), [T, E] = j(null), [D, N] = j(null), [P, H] = j(R), U = A(R), W = A(null), G = O((e, t) => {
145
+ }), S = j("all"), [C, E] = M(null), [D, O] = M(null), [P, F] = M(z), U = j(z), W = j(null), G = k((e, t) => {
146
146
  let n = Object.keys(e).length === 0;
147
- U.current = n ? R : e, W.current = n ? null : t, H(U.current);
148
- }, []), K = O(() => {
149
- W.current !== null && (U.current = R, W.current = null, H(R));
150
- }, []), q = A(null), J = O((e, t) => {
147
+ U.current = n ? z : e, W.current = n ? null : t, F(U.current);
148
+ }, []), K = k(() => {
149
+ W.current !== null && (U.current = z, W.current = null, F(z));
150
+ }, []), q = j(null), J = k((e, t) => {
151
151
  let n = t.start === t.end;
152
152
  W.current !== null && !(n && t.start === W.current) && K(), q.current = t, E((e) => ae(e, t) ? e : t);
153
153
  let r = a(e);
154
- N(n ? I(r, t.start) : d(r, t.start, t.end));
155
- }, [K]), Y = O(() => {
154
+ O(n ? L(r, t.start) : d(r, t.start, t.end));
155
+ }, [K]), Y = k(() => {
156
156
  let e = v.current;
157
157
  if (!e) return;
158
- let t = z(e);
158
+ let t = B(e);
159
159
  t !== null && J(e, t);
160
- }, [J]), pe = O(() => {
161
- q.current = null, E(null), N(null), K();
162
- }, [K]), X = O(() => {
160
+ }, [J]), pe = k(() => {
161
+ q.current = null, E(null), O(null), K();
162
+ }, [K]), X = k(() => {
163
163
  g(null);
164
- }, []), Z = O(() => {
164
+ }, []), Z = k(() => {
165
165
  let e = f, t = v.current;
166
166
  if (e == null || !t) {
167
167
  g(null);
168
168
  return;
169
169
  }
170
170
  let n = i.current.getRuns?.(e), r = i.current.setRuns, o = ie(a(t)), s = n != null && n.length > 0;
171
- i.current.setText(e, w(o)), r && (s || u(o)) && r(e, o), g(null);
172
- }, [f, i]), me = O((e, t) => {
171
+ i.current.setText(e, T(o)), r && (s || u(o)) && r(e, o), g(null);
172
+ }, [f, i]), me = k((e, t) => {
173
173
  S.current = t?.caret ?? "all", g(e);
174
- }, []), he = O((e) => f === e, [f]), Q = O((e) => {
174
+ }, []), he = k((e) => f === e, [f]), Q = k((e) => {
175
175
  let t = v.current;
176
176
  if (!t || Object.keys(e).length === 0) return;
177
- let n = z(t) ?? q.current;
177
+ let n = B(t) ?? q.current;
178
178
  if (!n) return;
179
179
  let r = _.current, o = i.current.setStyle, s = a(t);
180
180
  e.bold === !1 && !("fontWeight" in e) && r !== null && (e = {
@@ -184,41 +184,41 @@ function H(t) {
184
184
  let l = r !== null && o ? Object.keys(e).find((t) => t !== "bold" && e[t] === !1 && p(i.current.getStyle(r) ?? {}, t)) : void 0;
185
185
  if (l !== void 0 && r !== null && o) {
186
186
  let a = i.current.getStyle(r) ?? {}, c = m(s, a, n.start, n.end, l, !1);
187
- o(r, c.style), B(t, c.runs, n.start, n.end, y.current), J(t, n), n.start === n.end && G({
187
+ o(r, c.style), V(t, c.runs, n.start, n.end, y.current), J(t, n), n.start === n.end && G({
188
188
  ...U.current,
189
189
  [l]: !1
190
- }, n.start), L(t, n);
190
+ }, n.start), R(t, n);
191
191
  let u = { ...e };
192
192
  delete u[l], Object.keys(u).length > 0 && Q(u);
193
193
  return;
194
194
  }
195
195
  if (n.start === n.end) {
196
- G(re(U.current, e), n.start), L(t, n);
196
+ G(re(U.current, e), n.start), R(t, n);
197
197
  return;
198
198
  }
199
- B(t, c(s, n.start, n.end, e), n.start, n.end, y.current), L(t, n), J(t, n);
199
+ V(t, c(s, n.start, n.end, e), n.start, n.end, y.current), R(t, n), J(t, n);
200
200
  }, [
201
201
  J,
202
202
  G,
203
203
  _,
204
204
  i
205
- ]), $ = O((e) => {
205
+ ]), $ = k((e) => {
206
206
  let t = v.current;
207
207
  if (!t) return;
208
- let n = z(t) ?? q.current;
208
+ let n = B(t) ?? q.current;
209
209
  if (!n) return;
210
- let r = a(t), o = _.current, s = (o === null ? void 0 : i.current.getStyle(o)) ?? {}, c = n.start === n.end ? l(I(r, n.start), U.current) : d(r, n.start, n.end);
211
- Q(F(c, e, s));
210
+ let r = a(t), o = _.current, s = (o === null ? void 0 : i.current.getStyle(o)) ?? {}, c = n.start === n.end ? l(L(r, n.start), U.current) : d(r, n.start, n.end);
211
+ Q(I(c, e, s));
212
212
  }, [
213
213
  Q,
214
214
  _,
215
215
  i
216
216
  ]);
217
- return k(() => {
217
+ return A(() => {
218
218
  if (f == null) return;
219
219
  let { container: e, getText: t, getStyle: c, getPaint: l } = i.current;
220
220
  if (!e) return;
221
- let u = C(c(f), l?.(f)), d = document.createElement("div"), p = `weasel-text-edit-${++oe}`;
221
+ let u = w(c(f), l?.(f)), d = document.createElement("div"), p = `weasel-text-edit-${++oe}`;
222
222
  d.classList.add(p), d.setAttribute("contenteditable", "true"), d.spellcheck = !1, y.current = u;
223
223
  let m = i.current.getRuns?.(f);
224
224
  m && m.length > 0 ? s(m, d, u) : u.fontVariantCaps === "small-caps" ? s([{ text: t(f) }], d, u) : n(d, t(f)), ue(d, u);
@@ -226,14 +226,14 @@ function H(t) {
226
226
  h && (d.style.opacity = "0");
227
227
  let g = de(p, u), _ = le();
228
228
  _.appendChild(d), e.appendChild(_), v.current = d;
229
- let w = () => {
229
+ let C = () => {
230
230
  let e = i.current.getClipRect?.() ?? null;
231
231
  fe(d, _, i.current.getScreenPose(f), e, u);
232
232
  };
233
- w();
233
+ C();
234
234
  let T = h !== null, E = () => {
235
- T && (T = !1, clearTimeout(D), w(), d.style.opacity = "");
236
- }, D = T ? setTimeout(E, i.current.fontHold ?? V) : void 0;
235
+ T && (T = !1, clearTimeout(D), C(), d.style.opacity = "");
236
+ }, D = T ? setTimeout(E, i.current.fontHold ?? H) : void 0;
237
237
  h?.then(E);
238
238
  let O = document.createRange(), k = S.current;
239
239
  k === "all" ? O.selectNodeContents(d) : ce(d, O, k), d.focus();
@@ -257,14 +257,14 @@ function H(t) {
257
257
  if (e.inputType !== "insertText" || !e.data) return;
258
258
  let t = U.current;
259
259
  if (Object.keys(t).length > 0) {
260
- let n = z(d) ?? q.current;
260
+ let n = B(d) ?? q.current;
261
261
  if (!n || n.start !== n.end) return;
262
262
  e.preventDefault();
263
263
  let r = te(a(d), n.start, {
264
264
  ...t,
265
265
  text: e.data
266
266
  }), i = n.start + e.data.length;
267
- B(d, r, i, i, y.current), ne(d, r, i), K(), J(d, {
267
+ V(d, r, i, i, y.current), ne(d, r, i), K(), J(d, {
268
268
  start: i,
269
269
  end: i
270
270
  });
@@ -284,14 +284,14 @@ function H(t) {
284
284
  P();
285
285
  }, P = (e) => {
286
286
  if (e instanceof InputEvent && e.isComposing) return;
287
- let t = z(d);
287
+ let t = B(d);
288
288
  if (!o(d) || !t) return;
289
289
  let n = r(d, t.start), i = r(d, t.end), a = window.getSelection();
290
290
  if (!n || !i || !a) return;
291
291
  let s = document.createRange();
292
292
  s.setStart(n.node, n.offset), s.setEnd(i.node, i.offset), a.removeAllRanges(), a.addRange(s);
293
293
  }, F = (e) => {
294
- P(e), w();
294
+ P(e), C();
295
295
  }, I = (e) => {
296
296
  let t = e.target;
297
297
  if (!(t instanceof Node) || d.contains(t)) return;
@@ -299,7 +299,7 @@ function H(t) {
299
299
  n && t instanceof Element && n(t) || Z();
300
300
  };
301
301
  return d.addEventListener("keydown", j), d.addEventListener("blur", M), d.addEventListener("input", F), d.addEventListener("beforeinput", N), document.addEventListener("pointerdown", I, !0), document.addEventListener("selectionchange", Y), b.current = () => {
302
- w(), x.request();
302
+ C(), x.request();
303
303
  }, x.request(), () => {
304
304
  T = !1, clearTimeout(D), x.cancel(), b.current = () => {}, d.removeEventListener("keydown", j), d.removeEventListener("blur", M), d.removeEventListener("input", F), d.removeEventListener("beforeinput", N), document.removeEventListener("pointerdown", I, !0), document.removeEventListener("selectionchange", Y), _.remove(), g?.remove(), v.current = null, pe();
305
305
  };
@@ -320,7 +320,7 @@ function H(t) {
320
320
  cancelEdit: X,
321
321
  commit: Z,
322
322
  isEditing: he,
323
- selection: T,
323
+ selection: C,
324
324
  rangeStyle: D,
325
325
  pendingStyle: P,
326
326
  applyStyleToSelection: Q,
@@ -330,7 +330,7 @@ function H(t) {
330
330
  var oe = 0;
331
331
  function se(e, t) {
332
332
  let n = [v(e.fontFamily, {
333
- weight: x(e.fontWeight),
333
+ weight: S(e.fontWeight),
334
334
  style: e.fontStyle
335
335
  }), ...t.filter((e) => e.fontFamily != null).map((e) => v(e.fontFamily, {
336
336
  weight: e.fontWeight ?? (e.bold ? 700 : void 0),
@@ -357,34 +357,34 @@ function le() {
357
357
  function ue(e, n) {
358
358
  e.style.position = "absolute", e.style.pointerEvents = "auto", e.style.boxSizing = "border-box", e.style.margin = "0", e.style.padding = "0", e.style.border = "0", e.style.outline = "none", e.style.background = "transparent", e.style.color = n.fill !== null && "color" in n.fill ? n.fill.color : "#000", e.style.caretColor = n.caretColor;
359
359
  let r = _(n.fontFamily, {
360
- weight: x(n.fontWeight),
360
+ weight: S(n.fontWeight),
361
361
  style: n.fontStyle
362
362
  });
363
- e.style.font = y({
363
+ e.style.font = b({
364
364
  ...n,
365
365
  fontFamily: r
366
- }), e.style.lineHeight = String(n.lineHeight);
367
- let i = S(n.align, n.direction);
366
+ }), e.style.textRendering = y(n.fontFamily) ? "" : "geometricPrecision", e.style.lineHeight = String(n.lineHeight);
367
+ let i = C(n.align, n.direction);
368
368
  e.style.textAlign = n.align === "justify" ? "justify" : i, e.style.setProperty("text-align-last", n.align === "justify" ? i : "");
369
369
  let a = [];
370
- n.underline && a.push("underline"), n.strikethrough && a.push("line-through"), n.overline && a.push("overline"), e.style.textDecoration = a.length > 0 ? a.join(" ") : "none", e.style.textTransform = n.textTransform, e.style.fontVariant = n.fontVariantCaps, e.style.setProperty(t, n.fontVariantCaps === "small-caps" ? String(E(n.fontFamily, x(n.fontWeight), n.fontStyle)) : ""), e.style.whiteSpace = n.wrap ? "pre-wrap" : "pre", e.style.overflowWrap = "normal", e.style.wordBreak = "normal";
370
+ n.underline && a.push("underline"), n.strikethrough && a.push("line-through"), n.overline && a.push("overline"), e.style.textDecoration = a.length > 0 ? a.join(" ") : "none", e.style.textTransform = n.textTransform, e.style.fontVariant = n.fontVariantCaps, e.style.setProperty(t, n.fontVariantCaps === "small-caps" ? String(D(n.fontFamily, S(n.fontWeight), n.fontStyle)) : ""), e.style.whiteSpace = n.wrap ? "pre-wrap" : "pre", e.style.overflowWrap = "normal", e.style.wordBreak = "normal";
371
371
  }
372
372
  function de(e, t) {
373
373
  if (t.selectionBackground == null && t.selectionColor == null) return null;
374
374
  let n = document.createElement("style"), r = [];
375
375
  return t.selectionBackground != null && r.push(`background: ${t.selectionBackground};`), t.selectionColor != null && r.push(`color: ${t.selectionColor};`), n.textContent = `.${e}::selection { ${r.join(" ")} }`, document.head.appendChild(n), n;
376
376
  }
377
- var U = {
377
+ var W = {
378
378
  left: 0,
379
379
  center: .5,
380
380
  right: 1
381
381
  };
382
- function W(e, t, n = 0) {
383
- let r = D(e.verticalAlign, e.height, t);
382
+ function G(e, t, n = 0) {
383
+ let r = O(e.verticalAlign, e.height, t);
384
384
  return e.y + (r + n) * (e.zoom ?? 1);
385
385
  }
386
- function G(e, t, n, r) {
387
- let i = b({
386
+ function K(e, t, n, r) {
387
+ let i = x({
388
388
  x: 0,
389
389
  y: 0,
390
390
  width: n.width,
@@ -398,23 +398,24 @@ function G(e, t, n, r) {
398
398
  lineHeight: r,
399
399
  script: t.script
400
400
  }
401
- }).laid.lines[0]?.baselineY ?? 0, a = q(e);
401
+ }).laid.lines[0]?.baselineY ?? 0, a = J(e);
402
402
  return i > 0 && a > 0 ? i - a : 0;
403
403
  }
404
- var K = /* @__PURE__ */ new Map();
405
- function q(e) {
404
+ var q = /* @__PURE__ */ new Map();
405
+ function J(e) {
406
406
  let t = e.parentElement;
407
407
  if (!t) return 0;
408
- let { fontFamily: n, fontWeight: r, fontStyle: i, fontSize: a, lineHeight: o } = e.style, s = [
408
+ let { fontFamily: n, fontWeight: r, fontStyle: i, fontSize: a, lineHeight: o, textRendering: s } = e.style, c = [
409
409
  n,
410
410
  r,
411
411
  i,
412
412
  a,
413
- o
414
- ].join("|"), c = K.get(s);
415
- if (c !== void 0) return c;
416
- let l = document.createElement("div");
417
- Object.assign(l.style, {
413
+ o,
414
+ s
415
+ ].join("|"), l = q.get(c);
416
+ if (l !== void 0) return l;
417
+ let u = document.createElement("div");
418
+ Object.assign(u.style, {
418
419
  position: "absolute",
419
420
  left: "0",
420
421
  top: "0",
@@ -428,17 +429,18 @@ function q(e) {
428
429
  fontWeight: r,
429
430
  fontStyle: i,
430
431
  fontSize: a,
431
- lineHeight: o
432
+ lineHeight: o,
433
+ textRendering: s
432
434
  });
433
- let u = document.createElement("span");
434
- Object.assign(u.style, {
435
+ let d = document.createElement("span");
436
+ Object.assign(d.style, {
435
437
  display: "inline-block",
436
438
  width: "0",
437
439
  height: "0",
438
440
  verticalAlign: "baseline"
439
- }), l.appendChild(u), t.appendChild(l);
440
- let d = l.getBoundingClientRect(), f = d.width / 100, p = f > 0 ? (u.getBoundingClientRect().top - d.top) / f : 0;
441
- return l.remove(), p > 0 && document.fonts?.status !== "loading" && (K.size >= 64 && K.clear(), K.set(s, p)), p;
441
+ }), u.appendChild(d), t.appendChild(u);
442
+ let f = u.getBoundingClientRect(), p = f.width / 100, m = p > 0 ? (d.getBoundingClientRect().top - f.top) / p : 0;
443
+ return u.remove(), m > 0 && document.fonts?.status !== "loading" && (q.size >= 64 && q.clear(), q.set(c, m)), m;
442
444
  }
443
445
  function fe(e, t, n, r, i) {
444
446
  if (!n) {
@@ -446,20 +448,20 @@ function fe(e, t, n, r, i) {
446
448
  return;
447
449
  }
448
450
  t.style.overflow = r ? "clip" : "visible", t.style.left = `${r?.x ?? 0}px`, t.style.top = `${r?.y ?? 0}px`, t.style.width = `${r?.width ?? 0}px`, t.style.height = `${r?.height ?? 0}px`, e.style.display = "";
449
- let a = i.wrap ? 0 : U[S(i.align, i.direction)];
451
+ let a = i.wrap ? 0 : W[C(i.align, i.direction)];
450
452
  e.style.left = `${n.x + n.width * (n.zoom ?? 1) * a - (r?.x ?? 0)}px`, e.style.width = i.wrap ? `${n.width}px` : "max-content", e.style.minWidth = i.wrap ? "" : `${n.width}px`;
451
- let o = i.script ? T(i.fontFamily, x(i.fontWeight), i.fontStyle)[i.script] : void 0, s = n.lineHeight ?? i.lineHeight;
453
+ let o = i.script ? E(i.fontFamily, S(i.fontWeight), i.fontStyle)[i.script] : void 0, s = n.lineHeight ?? i.lineHeight;
452
454
  e.style.fontSize = `${n.fontSize * (o?.size ?? 1)}px`, e.style.lineHeight = o ? `${n.fontSize * s}px` : String(s);
453
455
  let c = n.verticalAlign !== void 0 && n.verticalAlign !== "top";
454
456
  e.style.minHeight = c ? "" : `${n.height}px`;
455
- let l = G(e, i, n, s) - (o?.shift ?? 0) * n.fontSize;
456
- e.style.top = `${W(n, c ? e.offsetHeight : n.height, l) - (r?.y ?? 0)}px`, e.style.transformOrigin = "0 0";
457
+ let l = K(e, i, n, s) - (o?.shift ?? 0) * n.fontSize;
458
+ e.style.top = `${G(n, c ? e.offsetHeight : n.height, l) - (r?.y ?? 0)}px`, e.style.transformOrigin = "0 0";
457
459
  let u = [];
458
460
  n.zoom !== void 0 && n.zoom !== 1 && u.push(`scale(${n.zoom})`), a !== 0 && u.push(`translateX(${-a * 100}%)`), e.style.transform = u.length > 0 ? u.join(" ") : "none";
459
461
  let d = n.zoom === void 0 && i.fontSize > 0 ? n.fontSize / i.fontSize : 1;
460
462
  e.style.letterSpacing = `${i.letterSpacing * d}px`;
461
463
  }
462
464
  //#endregion
463
- export { V as TEXT_EDIT_FONT_HOLD, G as baselineDrop, W as overlayTop, H as useTextEdit };
465
+ export { H as TEXT_EDIT_FONT_HOLD, K as baselineDrop, G as overlayTop, U as useTextEdit };
464
466
 
465
467
  //# sourceMappingURL=useTextEdit.js.map