noteloom 0.3.2 → 0.4.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 (104) hide show
  1. package/README.md +344 -53
  2. package/bin/noteloom.mjs +139 -0
  3. package/dist/canvas.cjs +2 -0
  4. package/dist/canvas.cjs.map +1 -0
  5. package/dist/canvas.d.ts +2 -0
  6. package/dist/canvas.js +5 -0
  7. package/dist/canvas.js.map +1 -0
  8. package/dist/collab.cjs +2 -0
  9. package/dist/collab.cjs.map +1 -0
  10. package/dist/collab.d.ts +19 -0
  11. package/dist/collab.js +379 -0
  12. package/dist/collab.js.map +1 -0
  13. package/dist/comments.cjs +2 -0
  14. package/dist/comments.cjs.map +1 -0
  15. package/dist/comments.d.ts +17 -0
  16. package/dist/comments.js +19 -0
  17. package/dist/comments.js.map +1 -0
  18. package/dist/index.cjs +2 -0
  19. package/dist/index.cjs.map +1 -0
  20. package/dist/index.d.ts +392 -32
  21. package/dist/index.js +3983 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/persistence.cjs +2 -0
  24. package/dist/persistence.cjs.map +1 -0
  25. package/dist/persistence.d.ts +11 -0
  26. package/dist/persistence.js +12 -0
  27. package/dist/persistence.js.map +1 -0
  28. package/dist/shared/CommentAvatar-TKqsM8vG.js +53 -0
  29. package/dist/shared/CommentAvatar-TKqsM8vG.js.map +1 -0
  30. package/dist/shared/CommentAvatar-V457IgoQ.cjs +2 -0
  31. package/dist/shared/CommentAvatar-V457IgoQ.cjs.map +1 -0
  32. package/dist/shared/CommentThreadCard-CAJ3oPdr.cjs +2 -0
  33. package/dist/shared/CommentThreadCard-CAJ3oPdr.cjs.map +1 -0
  34. package/dist/shared/CommentThreadCard-Cxf8GwHJ.js +213 -0
  35. package/dist/shared/CommentThreadCard-Cxf8GwHJ.js.map +1 -0
  36. package/dist/shared/CommentsPanel-BwVVyMOC.js +76 -0
  37. package/dist/shared/CommentsPanel-BwVVyMOC.js.map +1 -0
  38. package/dist/shared/CommentsPanel-CES4uzye.cjs +2 -0
  39. package/dist/shared/CommentsPanel-CES4uzye.cjs.map +1 -0
  40. package/dist/shared/VersionHistory-Bg6fufP5.js +1120 -0
  41. package/dist/shared/VersionHistory-Bg6fufP5.js.map +1 -0
  42. package/dist/shared/VersionHistory-DELa2Wbq.cjs +12 -0
  43. package/dist/shared/VersionHistory-DELa2Wbq.cjs.map +1 -0
  44. package/dist/shared/VoiceListeningIndicator-BOfVmLK0.js +338 -0
  45. package/dist/shared/VoiceListeningIndicator-BOfVmLK0.js.map +1 -0
  46. package/dist/shared/VoiceListeningIndicator-DNX8JlQM.cjs +2 -0
  47. package/dist/shared/VoiceListeningIndicator-DNX8JlQM.cjs.map +1 -0
  48. package/dist/shared/fieldRegistry-BoYyW3GH.cjs +2 -0
  49. package/dist/shared/fieldRegistry-BoYyW3GH.cjs.map +1 -0
  50. package/dist/shared/fieldRegistry-PjJWXFoB.js +223 -0
  51. package/dist/shared/fieldRegistry-PjJWXFoB.js.map +1 -0
  52. package/dist/shared/icons-C1_s0jKK.js +4269 -0
  53. package/dist/shared/icons-C1_s0jKK.js.map +1 -0
  54. package/dist/shared/icons-DtCsXuU6.cjs +3531 -0
  55. package/dist/shared/icons-DtCsXuU6.cjs.map +1 -0
  56. package/dist/shared/index-B9jyyL8u.js +2145 -0
  57. package/dist/shared/index-B9jyyL8u.js.map +1 -0
  58. package/dist/shared/index-D9WEXpYM.cjs +2 -0
  59. package/dist/shared/index-D9WEXpYM.cjs.map +1 -0
  60. package/dist/shared/indexedDbPersistence-BKlGPFTP.js +112 -0
  61. package/dist/shared/indexedDbPersistence-BKlGPFTP.js.map +1 -0
  62. package/dist/shared/indexedDbPersistence-BWJ1h5Vp.cjs +2 -0
  63. package/dist/shared/indexedDbPersistence-BWJ1h5Vp.cjs.map +1 -0
  64. package/dist/shared/leafBlockFactory-A9eUhSe-.js +335 -0
  65. package/dist/shared/leafBlockFactory-A9eUhSe-.js.map +1 -0
  66. package/dist/shared/leafBlockFactory-Dp382eP8.cjs +2 -0
  67. package/dist/shared/leafBlockFactory-Dp382eP8.cjs.map +1 -0
  68. package/dist/shared/serialize-DWEfk0vU.cjs +3 -0
  69. package/dist/shared/serialize-DWEfk0vU.cjs.map +1 -0
  70. package/dist/shared/serialize-T9Odwx24.js +86 -0
  71. package/dist/shared/serialize-T9Odwx24.js.map +1 -0
  72. package/dist/shared/starter-kit-CY5wzYDf.js +4980 -0
  73. package/dist/shared/starter-kit-CY5wzYDf.js.map +1 -0
  74. package/dist/shared/starter-kit-lPN-NpJ5.cjs +27 -0
  75. package/dist/shared/starter-kit-lPN-NpJ5.cjs.map +1 -0
  76. package/dist/shared/usePopoverEdgeClamp-CDG26jBM.cjs +2 -0
  77. package/dist/shared/usePopoverEdgeClamp-CDG26jBM.cjs.map +1 -0
  78. package/dist/shared/usePopoverEdgeClamp-gmFm0CnI.js +109 -0
  79. package/dist/shared/usePopoverEdgeClamp-gmFm0CnI.js.map +1 -0
  80. package/dist/shared/useServiceWorkerUpdate-BduabXv6.js +94 -0
  81. package/dist/shared/useServiceWorkerUpdate-BduabXv6.js.map +1 -0
  82. package/dist/shared/useServiceWorkerUpdate-DQboGesi.cjs +2 -0
  83. package/dist/shared/useServiceWorkerUpdate-DQboGesi.cjs.map +1 -0
  84. package/dist/starter-kit.cjs +2 -0
  85. package/dist/starter-kit.cjs.map +1 -0
  86. package/dist/starter-kit.d.ts +9 -0
  87. package/dist/starter-kit.js +10 -0
  88. package/dist/starter-kit.js.map +1 -0
  89. package/dist/style.css +3529 -3200
  90. package/dist/versions.cjs +2 -0
  91. package/dist/versions.cjs.map +1 -0
  92. package/dist/versions.d.ts +11 -0
  93. package/dist/versions.js +13 -0
  94. package/dist/versions.js.map +1 -0
  95. package/dist/voice.cjs +2 -0
  96. package/dist/voice.cjs.map +1 -0
  97. package/dist/voice.d.ts +7 -0
  98. package/dist/voice.js +8 -0
  99. package/dist/voice.js.map +1 -0
  100. package/package.json +159 -92
  101. package/dist/noteloom.cjs +0 -3209
  102. package/dist/noteloom.cjs.map +0 -1
  103. package/dist/noteloom.es.js +0 -14622
  104. package/dist/noteloom.es.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-B9jyyL8u.js","sources":["../../src/react/useBlock.js","../../src/react/useOutsideClickAndEscape.js","../../src/blocks/canvas/strokeOutline.js","../../src/blocks/canvas/canvasGeometry.js","../../src/blocks/canvas/shapeGeometry.js","../../src/react/useDragResize.js","../../src/blocks/canvas/createCanvasBlock.js","../../src/inline/marks.js","../../src/blocks/canvas/zOrder.js","../../src/blocks/canvas/exportSvg.js","../../src/blocks/canvas/CanvasBlock.jsx","../../src/registry/define.js","../../src/blocks/canvas/index.js"],"sourcesContent":["import { useCallback, useSyncExternalStore } from 'react';\nimport { useEditorStore } from './EditorProvider.jsx';\n\n/**\n * Subscribes to exactly one block by id. `store.getBlock(id)` is guaranteed\n * by EditorStore's mutation discipline to return the same reference across\n * renders unless that exact block changed, which is what makes this safe\n * with useSyncExternalStore (no infinite-loop / \"getSnapshot should be\n * cached\" warning). Never derive a new object from the snapshot here — do\n * that in the calling component with useMemo instead.\n */\nexport function useBlock(id) {\n const store = useEditorStore();\n const subscribe = useCallback((onStoreChange) => store.subscribe(id, onStoreChange), [store, id]);\n const getSnapshot = useCallback(() => store.getBlock(id), [store, id]);\n return useSyncExternalStore(subscribe, getSnapshot);\n}\n\n/** Same contract as useBlock, for inline Run leaves. */\nexport function useRun(id) {\n const store = useEditorStore();\n const subscribe = useCallback((onStoreChange) => store.subscribe(id, onStoreChange), [store, id]);\n const getSnapshot = useCallback(() => store.getRun(id), [store, id]);\n return useSyncExternalStore(subscribe, getSnapshot);\n}\n","import { useEffect } from 'react';\n\n/**\n * Closes whatever `isOpen` gates when the user clicks outside every ref in\n * `refs`, or presses Escape — the same ~15-line pattern this codebase\n * previously copy-pasted independently in FloatingToolbar, TableHeaderRow's\n * column menu, and Modal. Extracted here so a new consumer (Select) doesn't\n * need a fourth copy; the existing three call sites are left as-is (their\n * own small variations — e.g. Modal's backdrop-click check — aren't worth\n * disturbing for this).\n *\n * `refs` accepts either a single ref or an array of refs — a consumer whose\n * popover is portaled somewhere else in the DOM (e.g. Select's popover,\n * portaled to document.body so it isn't nested inside a contentEditable\n * region) needs a second ref for that portaled element, since it's no\n * longer a DOM descendant of the trigger's own root.\n *\n * Also always treats a click landing inside ANY currently-open `Select`\n * popover as \"inside,\" regardless of whose refs were passed — a `Select`\n * nested inside this hook's OWN gated popover (the table column menu's\n * \"Column type\"/field-type pickers, a menu's own filter dropdown, ...) is\n * ALSO portaled to `document.body`, so a plain `ref.current.contains()`\n * check can never see it as a descendant either, and picking an option in\n * it would otherwise close the outer popover as an unwanted side effect —\n * confirmed as a real, pre-existing bug (not hypothetical) doing exactly\n * that to the table column menu's own type selector before this fix.\n */\nexport function useOutsideClickAndEscape(refs, isOpen, onClose) {\n useEffect(() => {\n if (!isOpen) return undefined;\n const refList = Array.isArray(refs) ? refs : [refs];\n const handlePointerDown = (event) => {\n const inside =\n refList.some((ref) => ref.current && ref.current.contains(event.target)) ||\n event.target.closest?.('.be-select-popover') != null;\n if (!inside) onClose();\n };\n const handleKeyDown = (event) => {\n if (event.key === 'Escape') onClose();\n };\n document.addEventListener('mousedown', handlePointerDown);\n document.addEventListener('keydown', handleKeyDown);\n return () => {\n document.removeEventListener('mousedown', handlePointerDown);\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [isOpen, onClose, refs]);\n}\n","const DEFAULT_SIZE = 8;\nconst DEFAULT_THINNING = 0.5;\nconst DEFAULT_SMOOTHING = 0.5;\nconst TAPER_POINT_COUNT = 4;\nconst MIN_RADIUS_FACTOR = 0.15;\n// \"Speed\" is approximated as raw distance between consecutive input samples\n// (no real timestamps are captured/needed) — a reasonable proxy since\n// pointermove sampling density is roughly constant for a given device, and\n// this only needs to feel right, not model real velocity precisely. This is\n// the normalized-space (0..1000) distance a step must cover to count as\n// \"fast enough to fully thin\" the stroke.\nconst SPEED_NORM = 8;\n\nfunction dist(a, b) {\n return Math.hypot(a[0] - b[0], a[1] - b[1]);\n}\n\nfunction clamp(value, min, max) {\n return Math.min(max, Math.max(min, value));\n}\n\nfunction round(n) {\n return Math.round(n * 100) / 100;\n}\n\n// Every pointer event handler in CanvasBlock.jsx falls back to a hardcoded\n// `event.pressure || 0.5` when the input device reports no real pressure\n// (true for every mouse and most touchscreens — only an actual\n// pressure-sensitive stylus reports something else) — see the doc comment\n// on `hasRealPressureVariation` below for what that default is used for.\nconst DEFAULT_PRESSURE = 0.5;\n\n/**\n * Whether this stroke carries genuine pressure DATA — some point's pressure\n * differs from the plain default every non-stylus input device reports.\n * Only strokes with real variation get pressure-based width scaling in\n * `computeRadii` below; otherwise the overwhelmingly common case (mouse/\n * touch, no stylus) would ALWAYS render at a fraction of its own chosen\n * `size` — a stroke drawn at \"width 20\" looking visibly thinner than a\n * width-20 shape outline, which is exactly the mismatch this exists to\n * avoid. A real stylus's pressure data is trusted and still gets full\n * variable-width treatment, since that's genuinely useful, expected\n * behavior for that input method.\n */\nexport function hasRealPressureVariation(points) {\n return points.some(([, , pressure]) => pressure !== undefined && pressure !== DEFAULT_PRESSURE);\n}\n\n/**\n * One radius (half-width) per input point — a zero-dependency reimplementation\n * of perfect-freehand's most visually important trait, not a full port of its\n * configurable easing system. Blends a pressure-based base width with a\n * velocity-based thinning term (faster movement between consecutive samples\n * -> thinner ink), then tapers both ends of the whole stroke down toward a\n * point (the \"comes to a point\" look real ink/brushes have). Exported\n * directly so its shape (radius shrinks toward both ends relative to the\n * middle) is independently testable without parsing path-string geometry.\n *\n * ALL of that — pressure scaling, velocity thinning, AND end-taper — is\n * gated behind `hasRealPressureVariation`: without genuine stylus pressure\n * data (a mouse/touchscreen stroke, the overwhelmingly common case), the\n * radius is simply `size / 2` at every single point, full stop. A stroke\n * drawn at \"width 20\" must look exactly as wide as a width-20 shape\n * outline, everywhere along its length — not just \"close\" at rest with a\n * thinner middle whenever the cursor moved at a normal drawing speed\n * (thinning) or thinner tips (taper). Only a real stylus's pressure data\n * unlocks the full natural \"ink\" look these terms exist for.\n */\nexport function computeRadii(points, { size = DEFAULT_SIZE, thinning = DEFAULT_THINNING } = {}) {\n const baseRadius = size / 2;\n const n = points.length;\n const usePressure = hasRealPressureVariation(points);\n\n if (!usePressure) return new Array(n).fill(baseRadius);\n\n const radii = new Array(n);\n let speed = 0;\n\n for (let i = 0; i < n; i += 1) {\n if (i > 0) {\n const step = dist(points[i], points[i - 1]);\n speed = speed * 0.8 + step * 0.2;\n }\n const speedFactor = clamp(speed / SPEED_NORM, 0, 1);\n const pressure = points[i][2] ?? DEFAULT_PRESSURE;\n const pressureFactor = 0.4 + 0.6 * clamp(pressure, 0, 1);\n const radius = clamp(\n baseRadius * pressureFactor * (1 - thinning * speedFactor),\n baseRadius * MIN_RADIUS_FACTOR,\n baseRadius,\n );\n radii[i] = radius;\n }\n\n const taperCount = Math.min(TAPER_POINT_COUNT, Math.floor(n / 2));\n for (let i = 0; i < taperCount; i += 1) {\n const t = (i + 1) / (taperCount + 1); // ramps 0 (exclusive) -> 1 (exclusive)\n const factor = MIN_RADIUS_FACTOR + (1 - MIN_RADIUS_FACTOR) * t;\n radii[i] *= factor;\n radii[n - 1 - i] *= factor;\n }\n\n return radii;\n}\n\n/** Simple moving-average smoothing over the centerline (position only, never pressure) — removes visible raw-input jitter without any external dependency. Endpoints are left untouched so the stroke's start/end position is never shifted. */\nfunction smoothPoints(points, smoothing) {\n const n = points.length;\n if (n < 3 || smoothing <= 0) return points;\n const result = new Array(n);\n result[0] = points[0];\n result[n - 1] = points[n - 1];\n for (let i = 1; i < n - 1; i += 1) {\n const midX = (points[i - 1][0] + points[i + 1][0]) / 2;\n const midY = (points[i - 1][1] + points[i + 1][1]) / 2;\n const x = points[i][0] + (midX - points[i][0]) * smoothing;\n const y = points[i][1] + (midY - points[i][1]) * smoothing;\n result[i] = [x, y, points[i][2]];\n }\n return result;\n}\n\n/** Left/right offset points at each centerline point, using a central-difference tangent (one-sided at the ends) rotated 90deg for the normal. */\nfunction computeOffsets(points, radii) {\n const n = points.length;\n const left = new Array(n);\n const right = new Array(n);\n for (let i = 0; i < n; i += 1) {\n const prev = points[Math.max(0, i - 1)];\n const next = points[Math.min(n - 1, i + 1)];\n let tx = next[0] - prev[0];\n let ty = next[1] - prev[1];\n const len = Math.hypot(tx, ty) || 1;\n tx /= len;\n ty /= len;\n const nx = -ty; // tangent rotated 90deg = normal\n const ny = tx;\n const r = radii[i];\n left[i] = [points[i][0] + nx * r, points[i][1] + ny * r];\n right[i] = [points[i][0] - nx * r, points[i][1] - ny * r];\n }\n return { left, right };\n}\n\nfunction pathFromPolygon(poly) {\n if (poly.length === 0) return '';\n let d = `M${round(poly[0][0])},${round(poly[0][1])}`;\n for (let i = 1; i < poly.length; i += 1) d += ` L${round(poly[i][0])},${round(poly[i][1])}`;\n return d;\n}\n\n/** A regular-polygon approximation of a filled circle, built from plain line segments (consistent with the rest of this module's \"no bezier curves in v1\" simplification) — used for a tap-without-drag, so a single click still leaves a visible mark. */\nfunction dotPath([x, y], radius) {\n const sides = 12;\n const poly = [];\n for (let i = 0; i < sides; i += 1) {\n const angle = (i / sides) * Math.PI * 2;\n poly.push([x + Math.cos(angle) * radius, y + Math.sin(angle) * radius]);\n }\n return `${pathFromPolygon(poly)} Z`;\n}\n\n/**\n * Builds an SVG path `d` string for one stroke's filled variable-width\n * outline, from raw `[x, y, pressure]` input points in the block's fixed\n * 0..1000 normalized coordinate space. This is the whole \"ink\" look: a\n * FILLED polygon (native `stroke-width` can't vary along a path), not a\n * stroked centerline.\n *\n * `size` is the stroke's full width at maximum thickness (radius = size/2);\n * `thinning` (0..1) controls how much faster movement thins the ink;\n * `smoothing` (0..1) controls how much the raw input jitter is smoothed out.\n */\nexport function getStrokeOutlinePath(rawPoints, options = {}) {\n const {\n size = DEFAULT_SIZE,\n thinning = DEFAULT_THINNING,\n smoothing = DEFAULT_SMOOTHING,\n } = options;\n if (!rawPoints || rawPoints.length === 0) return '';\n\n // Drop consecutive near-duplicate points — avoids zero-length tangents/\n // divide-by-zero in computeOffsets, and can legitimately happen if the\n // pointer pauses mid-stroke without moving.\n const points = [rawPoints[0]];\n for (let i = 1; i < rawPoints.length; i += 1) {\n if (dist(rawPoints[i], points[points.length - 1]) > 0.1) points.push(rawPoints[i]);\n }\n\n if (points.length === 1) {\n const pressure = points[0][2] ?? 0.5;\n const radius = (size / 2) * (0.4 + 0.6 * clamp(pressure, 0, 1));\n return dotPath(points[0], radius);\n }\n\n const radii = computeRadii(points, { size, thinning });\n const smoothed = smoothPoints(points, smoothing);\n const { left, right } = computeOffsets(smoothed, radii);\n\n const polygon = [...left, ...right.slice().reverse()];\n return `${pathFromPolygon(polygon)} Z`;\n}\n\n/** Plain min/max bounding box over raw points — reused by the eraser's hit-test (see canvasGeometry.js). */\nexport function strokeBoundingBox(points) {\n if (!points || points.length === 0) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const [x, y] of points) {\n if (x < minX) minX = x;\n if (y < minY) minY = y;\n if (x > maxX) maxX = x;\n if (y > maxY) maxY = y;\n }\n return { minX, minY, maxX, maxY };\n}\n","/**\n * The `<svg>` keeps its default `preserveAspectRatio` (\"xMidYMid meet\"),\n * which scales a `size x size` SQUARE viewBox to fit inside the rendered\n * box UNIFORMLY (same factor on both axes) and CENTERS it — letterboxing\n * whichever axis is \"too big\" — rather than stretching each axis\n * independently to fill it. `width`/`height` (the block's own rendered\n * pixel size) default to 480x320, a non-square box, so this letterboxing is\n * the common case, not an edge case.\n *\n * A naive `(clientX - rect.left) / rect.width` (dividing by each axis'\n * OWN rendered dimension independently) ignores that letterbox offset\n * entirely — it's only correct when the rendered box happens to be exactly\n * square. Otherwise the cursor and the point actually drawn silently drift\n * apart, worse the more the rendered box's aspect ratio departs from\n * square. This replicates the browser's own \"meet\" math (one shared\n * `scale`, plus a centering offset on whichever axis has the extra space)\n * so the two always agree, for ANY rendered box shape.\n */\nfunction computeViewTransform(svgEl, size) {\n const rect = svgEl.getBoundingClientRect();\n const rectWidth = rect.width || 1;\n const rectHeight = rect.height || 1;\n const scale = Math.min(rectWidth / size, rectHeight / size);\n const offsetX = (rectWidth - size * scale) / 2;\n const offsetY = (rectHeight - size * scale) / 2;\n return { rect, scale, offsetX, offsetY };\n}\n\n/**\n * Converts a pointer event's client coordinates into the block's fixed\n * 0..1000 normalized drawing space (see createCanvasBlock.js) — independent\n * of the SVG's own rendered pixel size, so drawing stays correct regardless\n * of how the block has been resized.\n *\n * `view` is the currently-visible window into that fixed space (pan/zoom —\n * see CanvasBlock.jsx's local, non-persisted `view` state): `{x, y}` is the\n * top-left corner currently shown and `size` is how much of the space is\n * visible across the SVG's full rendered width/height (matching whatever\n * `viewBox` the `<svg>` was actually given). Defaults to the whole\n * un-panned/un-zoomed space, so a caller that never introduces pan/zoom\n * (or a test that doesn't care about it) gets the exact same mapping as\n * before pan/zoom existed.\n */\nexport function clientToLocal(event, svgEl, view = { x: 0, y: 0, size: 1000 }) {\n const { rect, scale, offsetX, offsetY } = computeViewTransform(svgEl, view.size);\n const x = view.x + (event.clientX - rect.left - offsetX) / scale;\n const y = view.y + (event.clientY - rect.top - offsetY) / scale;\n return [x, y];\n}\n\n/**\n * How many local-space units correspond to one CSS pixel of the SVG's own\n * rendered box, at the given local `size` — used to convert a client-space\n * pixel DELTA (a pan drag's mouse movement) into a local-space delta,\n * without needing `clientToLocal`'s absolute `view.x`/`view.y` offset,\n * which a plain delta doesn't care about. Shares the exact same letterbox-\n * aware `scale` as `clientToLocal` so panning tracks the cursor 1:1\n * regardless of the rendered box's aspect ratio.\n */\nexport function localPixelScale(svgEl, size) {\n return computeViewTransform(svgEl, size).scale;\n}\n\n/**\n * Computes the next pan/zoom `view` (see CanvasBlock.jsx) that keeps the\n * point currently under the cursor fixed on screen as the zoom level\n * changes — the standard \"zoom toward the cursor\" behavior. `prevView` is\n * the view before this wheel tick; `nextSize` is the new (post-zoom) local\n * window size (`VIEW_SIZE / nextZoom`).\n */\nexport function zoomAnchoredView(event, svgEl, prevView, nextSize) {\n const [cursorLocalX, cursorLocalY] = clientToLocal(event, svgEl, prevView);\n const { rect, scale, offsetX, offsetY } = computeViewTransform(svgEl, nextSize);\n const x = cursorLocalX - (event.clientX - rect.left - offsetX) / scale;\n const y = cursorLocalY - (event.clientY - rect.top - offsetY) / scale;\n return { x, y };\n}\n\n/**\n * Computes the next pan/zoom view that keeps the CURRENT VIEW'S OWN CENTER\n * point fixed as zoom changes — the zoom in/out toolbar buttons' own\n * variant of `zoomAnchoredView` above, for when there's no cursor position\n * to anchor to (a button click, not a wheel event). Needs no DOM/event at\n * all, unlike `zoomAnchoredView` — it's pure arithmetic on the view itself.\n */\nexport function zoomCenteredView(prevView, nextSize) {\n const centerX = prevView.x + prevView.size / 2;\n const centerY = prevView.y + prevView.size / 2;\n return { x: centerX - nextSize / 2, y: centerY - nextSize / 2 };\n}\n\n/**\n * Clamps a pan offset once the view window is zoomed out wider than the\n * fixed `boundsSize x boundsSize` sheet itself (see CanvasBlock.jsx's\n * VIEW_SIZE) -- used after every pan/zoom update (wheel-drag, toolbar\n * buttons, mouse/touch drag) so scrolling can't push the sheet off to one\n * side once it's already small enough to see the whole thing at once.\n * `size <= boundsSize` (100% zoom or zoomed in) is passed through\n * unclamped -- there's always at most one sheet-edge in view at a time\n * there, so panning to any of them is meaningful, same as before this\n * clamp existed. Only once `size > boundsSize` (zoomed out PAST 100%, all\n * the way down through MIN_ZOOM) does the offset lock to dead-center --\n * beyond that point the whole sheet already fits, so there is nowhere left\n * to usefully pan to and letting the offset drift would only ever show\n * blank space beyond the sheet's edges.\n */\nexport function clampViewOffset(x, y, size, boundsSize) {\n if (size <= boundsSize) return { x, y };\n const centered = (boundsSize - size) / 2;\n return { x: centered, y: centered };\n}\n\n/** True if two `{minX,minY,maxX,maxY}` boxes overlap, optionally padded outward by `padding` on both — used by the eraser's hit-test (a stroke's own half-width is a natural padding, so a thin eraser pass still catches thick ink). */\nexport function boxesIntersect(a, b, padding = 0) {\n return (\n a.minX - padding <= b.maxX &&\n a.maxX + padding >= b.minX &&\n a.minY - padding <= b.maxY &&\n a.maxY + padding >= b.minY\n );\n}\n","/**\n * Turns two drag corners (in either direction — the user may drag up/left\n * just as easily as down/right) into a valid, always-non-negative-size box.\n * Shared by both the live drag preview and the final commit, so a shape's\n * stored `{x, y, width, height}` is always in this normalized form —\n * `pointInRect`/rendering never has to handle a negative width/height.\n */\nexport function normalizeRect(x1, y1, x2, y2) {\n const x = Math.min(x1, x2);\n const y = Math.min(y1, y2);\n const width = Math.abs(x2 - x1);\n const height = Math.abs(y2 - y1);\n return { x, y, width, height };\n}\n\n/**\n * Rotates `(px, py)` by `angleDeg` degrees (clockwise, matching SVG's own\n * `rotate()` transform convention) around `(cx, cy)`. Used both ways by the\n * rotate tool: to place a rotated shape's own handle/hit-test points in\n * screen space (forward), and to map a click point back into a rotated\n * shape's own unrotated local frame before running the ordinary\n * pointInRect/pointInEllipse/pointInPolygon tests (inverse — pass\n * `-angleDeg`).\n */\nexport function rotatePoint(px, py, cx, cy, angleDeg) {\n const radians = (angleDeg * Math.PI) / 180;\n const cos = Math.cos(radians);\n const sin = Math.sin(radians);\n const dx = px - cx;\n const dy = py - cy;\n return [cx + dx * cos - dy * sin, cy + dx * sin + dy * cos];\n}\n\n/** True if `(px, py)` falls anywhere inside `rect`'s bounding box. */\nexport function pointInRect(px, py, rect) {\n return px >= rect.x && px <= rect.x + rect.width && py >= rect.y && py <= rect.y + rect.height;\n}\n\n/**\n * True if `(px, py)` falls inside the ellipse inscribed in `rect`'s\n * bounding box (standard `(dx/rx)^2 + (dy/ry)^2 <= 1` test) — matches what\n * is actually rendered (an `<ellipse>` inscribed in the same box a\n * rectangle would occupy), not just the box itself.\n */\nexport function pointInEllipse(px, py, rect) {\n const rx = rect.width / 2;\n const ry = rect.height / 2;\n if (rx === 0 || ry === 0) return false;\n const cx = rect.x + rx;\n const cy = rect.y + ry;\n const dx = (px - cx) / rx;\n const dy = (py - cy) / ry;\n return dx * dx + dy * dy <= 1;\n}\n\n/**\n * Distance from `(px, py)` to the line segment `(x1,y1)-(x2,y2)`, clamped to\n * the segment (not the infinite line) — the standard \"project onto the\n * segment, clamp t to [0,1]\" formula. Used for the arrow tool's hit-test:\n * `pointNearSegment(...) <= tolerance`.\n */\nexport function distanceToSegment(px, py, x1, y1, x2, y2) {\n const dx = x2 - x1;\n const dy = y2 - y1;\n const lengthSquared = dx * dx + dy * dy;\n if (lengthSquared === 0) return Math.hypot(px - x1, py - y1);\n let t = ((px - x1) * dx + (py - y1) * dy) / lengthSquared;\n t = Math.min(1, Math.max(0, t));\n const projX = x1 + t * dx;\n const projY = y1 + t * dy;\n return Math.hypot(px - projX, py - projY);\n}\n\n/** `distanceToSegment(...) <= tolerance` — the arrow tool's own hit-test. */\nexport function pointNearSegment(px, py, x1, y1, x2, y2, tolerance) {\n return distanceToSegment(px, py, x1, y1, x2, y2) <= tolerance;\n}\n\n/** The 4 edge-midpoints of `rect`'s bounding box (top/right/bottom/left), in order — the vertices of the diamond inscribed in it. */\nexport function diamondPoints(rect) {\n const { x, y, width, height } = rect;\n return [\n [x + width / 2, y],\n [x + width, y + height / 2],\n [x + width / 2, y + height],\n [x, y + height / 2],\n ];\n}\n\n/**\n * The 3 vertices of a triangle inscribed in `rect`'s bounding box\n * (top-mid, bottom-right, bottom-left) — the shape behind the \"polygon\"\n * tool for this pass (a variable side-count control is out of scope). Not\n * necessarily equilateral unless the box happens to be square, same\n * \"inscribed in the bounding box\" convention `pointInEllipse` already uses\n * rather than a claim of geometric regularity.\n */\nexport function trianglePoints(rect) {\n const { x, y, width, height } = rect;\n return [\n [x + width / 2, y],\n [x + width, y + height],\n [x, y + height],\n ];\n}\n\n/**\n * The `spikes * 2` vertices of a star polygon centered in `rect`'s bounding\n * box, alternating between the outer radius (the box's own half-width/\n * height) and a fixed inner radius (0.4x the outer one — no configurable\n * spike count/ratio in this pass), starting from the top and going\n * clockwise.\n */\nexport function starPoints(rect, spikes = 5) {\n const { x, y, width, height } = rect;\n const cx = x + width / 2;\n const cy = y + height / 2;\n const outerRx = width / 2;\n const outerRy = height / 2;\n const innerRatio = 0.4;\n const points = [];\n const step = Math.PI / spikes;\n let angle = -Math.PI / 2;\n for (let i = 0; i < spikes * 2; i += 1) {\n const isOuter = i % 2 === 0;\n const rx = isOuter ? outerRx : outerRx * innerRatio;\n const ry = isOuter ? outerRy : outerRy * innerRatio;\n points.push([cx + Math.cos(angle) * rx, cy + Math.sin(angle) * ry]);\n angle += step;\n }\n return points;\n}\n\n/**\n * Standard ray-casting point-in-polygon test — shared by every polygon-\n * based shape's hit-test (diamond, triangle, star, and any future one),\n * rather than a bespoke closed-form check per shape. `vertices` is a plain\n * `[[x,y], ...]` array, same shape every `*Points` function above returns.\n */\nexport function pointInPolygon(px, py, vertices) {\n let inside = false;\n for (let i = 0, j = vertices.length - 1; i < vertices.length; j = i, i += 1) {\n const [xi, yi] = vertices[i];\n const [xj, yj] = vertices[j];\n const crosses = yi > py !== yj > py;\n if (crosses && px < ((xj - xi) * (py - yi)) / (yj - yi) + xi) inside = !inside;\n }\n return inside;\n}\n\n/**\n * The 3 points of a small filled triangle for an arrow's arrowhead, planted\n * at `(x2, y2)` (the arrow's end point) and oriented along the segment's\n * own direction — computed at render time from the two endpoints rather\n * than stored, the same \"derive presentation from data\" principle\n * `strokeOutline.js` already uses for stroke outlines. Degenerates to a\n * triangle pointing along the +x axis for a zero-length segment (start\n * and end coincide) rather than producing NaNs.\n */\nexport function arrowheadPoints(x1, y1, x2, y2, size = 24) {\n const dx = x2 - x1;\n const dy = y2 - y1;\n const length = Math.hypot(dx, dy);\n const [ux, uy] = length === 0 ? [1, 0] : [dx / length, dy / length];\n const backX = x2 - ux * size;\n const backY = y2 - uy * size;\n const nx = -uy;\n const ny = ux;\n const halfWidth = size / 2;\n return [\n [x2, y2],\n [backX + nx * halfWidth, backY + ny * halfWidth],\n [backX - nx * halfWidth, backY - ny * halfWidth],\n ];\n}\n","import { useCallback, useState } from 'react';\n\n/**\n * Generic \"drag a handle -> live-preview local state -> commit once on\n * release\" hook — extracted from `EmbedBlock.jsx`'s own inlined resize-drag\n * pattern (`mousedown` on a handle attaches `document`-level `mousemove`/\n * `mouseup`; `mousemove` only updates local state for a live preview, zero\n * store writes; `mouseup` removes both listeners and makes exactly ONE\n * commit) — the canvas block needs this identical shape a second time.\n * Deliberately NOT also wired into `EmbedBlock.jsx`/`TableHeaderRow.jsx` in\n * this same change — that would touch already-working, already-tested\n * files for no reason tied to this feature; a later, separate cleanup task\n * could migrate them onto this shared hook if desired.\n *\n * `compute(event, start)` embeds the caller's own geometry — `start` is\n * whatever snapshot the caller captured when the drag began (e.g.\n * `{ startX, startY, startWidth, startHeight }`); `compute` returns the\n * caller's own value shape (a plain number, or an object like\n * `{ width, height }`). `onCommit(value)` is called exactly once, on\n * release, with the final computed value.\n *\n * Returns `{ dragValue, startDrag }` — `dragValue` is the live in-progress\n * value (`null` when not dragging, for the caller's own\n * `effective = dragValue ?? committedValue` pattern); `startDrag(event,\n * start)` is the `onMouseDown` handler to wire onto the resize handle.\n */\nexport function useDragResize({ compute, onCommit }) {\n const [dragValue, setDragValue] = useState(null);\n\n const startDrag = useCallback(\n (event, start) => {\n event.preventDefault();\n const handleMouseMove = (moveEvent) => setDragValue(compute(moveEvent, start));\n const handleMouseUp = (upEvent) => {\n document.removeEventListener('mousemove', handleMouseMove);\n document.removeEventListener('mouseup', handleMouseUp);\n onCommit(compute(upEvent, start));\n setDragValue(null);\n };\n document.addEventListener('mousemove', handleMouseMove);\n document.addEventListener('mouseup', handleMouseUp);\n },\n [compute, onCommit],\n );\n\n return { dragValue, startDrag };\n}\n","import { genId } from '../../utils/idGen.js';\n\nexport const DEFAULT_CANVAS_WIDTH = 480;\nexport const DEFAULT_CANVAS_HEIGHT = 320;\n\n/**\n * factory(parentId) -> {block, runs} for a freehand-drawing surface — a pure\n * \"widget\" block with no runs at all (contentIds always []), same shape as\n * divider/embed. `strokes` is an array of `{ id, points, color, size }`,\n * where `points` are raw `[x, y, pressure]` triples authored in a FIXED\n * 0..1000 normalized coordinate space, decoupled from `width`/`height` (the\n * block's own rendered pixel size) — resizing the block never has to touch\n * or rescale stroke data, it only changes how big that fixed space is drawn.\n *\n * `shapes` is a sibling array in that same fixed space — rectangle/ellipse\n * entries are `{ id, type, x, y, width, height, color, strokeWidth }`\n * (top-left + always-normalized-positive size), arrow entries are\n * `{ id, type: 'arrow', x1, y1, x2, y2, color, strokeWidth }` (two\n * endpoints; the arrowhead itself is derived at render time, not stored —\n * see shapeGeometry.js's `arrowheadPoints`).\n */\nexport function createCanvasBlock({\n strokes = [],\n shapes = [],\n width = DEFAULT_CANVAS_WIDTH,\n height = DEFAULT_CANVAS_HEIGHT,\n} = {}) {\n return function factory(parentId) {\n return {\n block: {\n id: genId(),\n type: 'canvas',\n parentId,\n contentIds: [],\n props: { strokes, shapes, width, height },\n },\n runs: [],\n };\n };\n}\n","/**\n * Serialization for a single inline Run. Shared by every leaf block type\n * (paragraph, heading, list item title, table cell) so formatting logic is\n * written exactly once instead of once per block type.\n *\n * `ctx.inlineRegistry` is optional — callers that don't mix in any\n * non-text inline types (or are serializing a run known to be plain text)\n * can omit it; a non-text run with no registry available just falls back\n * to its raw `value` rather than throwing.\n */\n\nexport function escapeHTML(str) {\n return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\nexport function escapeAttr(str) {\n return escapeHTML(str).replace(/\"/g, '&quot;');\n}\n\nexport function runToHTML(run, ctx) {\n if (!run) return '';\n\n if (run.type !== 'text') {\n const entry = ctx?.inlineRegistry?.get(run.type);\n return entry ? entry.toHTML(run, ctx) : escapeHTML(run.value ?? '');\n }\n\n const marks = run.marks ?? {};\n let html = escapeHTML(run.value ?? '');\n if (marks.code) html = `<code>${html}</code>`;\n if (marks.bold) html = `<strong>${html}</strong>`;\n if (marks.italic) html = `<em>${html}</em>`;\n if (marks.underline) html = `<u>${html}</u>`;\n if (marks.strike) html = `<s>${html}</s>`;\n if (marks.subscript) html = `<sub>${html}</sub>`;\n if (marks.superscript) html = `<sup>${html}</sup>`;\n if (marks.color) html = `<span style=\"color:${escapeAttr(marks.color)}\">${html}</span>`;\n if (marks.highlight)\n html = `<span style=\"background-color:${escapeAttr(marks.highlight)}\">${html}</span>`;\n if (marks.link?.href) {\n const targetAttrs =\n marks.link.target === '_blank' ? ' target=\"_blank\" rel=\"noopener noreferrer\"' : '';\n html = `<a href=\"${escapeAttr(marks.link.href)}\"${targetAttrs}>${html}</a>`;\n }\n return html;\n}\n\n/** Serializes a whole ordered run list to one HTML string — every leaf block's own toHTML already inlines exactly this. */\nexport function runsToHTML(runs, ctx) {\n return (runs ?? []).map((run) => runToHTML(run, ctx)).join('');\n}\n\nexport function runToPlainText(run, ctx) {\n if (!run) return '';\n if (run.type !== 'text') {\n const entry = ctx?.inlineRegistry?.get(run.type);\n return entry ? entry.toPlainText(run, ctx) : (run.value ?? '');\n }\n return run.value ?? '';\n}\n\n/**\n * Escapes characters that CommonMark would otherwise interpret as syntax\n * inside plain run text — backslash, backtick, `*`, `_`, `[`, `]` (the ones\n * that actually trigger unwanted emphasis/code/link parsing mid-sentence).\n * Deliberately NOT exhaustive (leaves `#`, `-`, `.`, `!`, `>` alone) — those\n * only matter at the START of a line, a block-level concern the per-block\n * `toMarkdown` functions own, not this run-level escaper; escaping them\n * unconditionally everywhere would turn ordinary sentences into a mess of\n * backslashes for no benefit.\n */\nexport function escapeMarkdown(str) {\n return (str ?? '').replace(/[\\\\`*_[\\]]/g, (c) => `\\\\${c}`);\n}\n\n/**\n * Markdown counterpart to `runToHTML` — same shared-across-every-leaf-block\n * design. A non-text run (select/date/mention/checkbox chip, ...) falls\n * back to its own `toPlainText` (no per-inline-type `toMarkdown` exists;\n * chips don't have a meaningful alternate Markdown form worth a whole\n * separate code path per inline type). Marks with no native Markdown\n * syntax (underline, sub/superscript, color, highlight) fall back to\n * inline HTML tags, which CommonMark passes through — most Markdown\n * renderers (GitHub included) render them correctly.\n */\nexport function runToMarkdown(run, ctx) {\n if (!run) return '';\n if (run.type !== 'text') {\n const entry = ctx?.inlineRegistry?.get(run.type);\n return entry ? entry.toPlainText(run, ctx) : (run.value ?? '');\n }\n\n const marks = run.marks ?? {};\n const raw = run.value ?? '';\n let md = marks.code ? raw : escapeMarkdown(raw); // code span content is literal, never escaped\n if (marks.code) md = `\\`${md}\\``;\n if (marks.bold) md = `**${md}**`;\n if (marks.italic) md = `*${md}*`;\n if (marks.strike) md = `~~${md}~~`;\n if (marks.underline) md = `<u>${md}</u>`;\n if (marks.subscript) md = `<sub>${md}</sub>`;\n if (marks.superscript) md = `<sup>${md}</sup>`;\n if (marks.color) md = `<span style=\"color:${escapeAttr(marks.color)}\">${md}</span>`;\n if (marks.highlight)\n md = `<span style=\"background-color:${escapeAttr(marks.highlight)}\">${md}</span>`;\n if (marks.link?.href) md = `[${md}](${marks.link.href})`;\n return md;\n}\n\n/** Serializes a whole ordered run list to one Markdown string — every leaf block's own toMarkdown inlines exactly this. */\nexport function runsToMarkdown(runs, ctx) {\n return (runs ?? []).map((run) => runToMarkdown(run, ctx)).join('');\n}\n","/**\n * Strokes and shapes are stored as two separate arrays (`props.strokes`/\n * `props.shapes`) for backward compatibility, but visually they share ONE\n * stacking order — a pen stroke drawn after a filled shape needs to render\n * on top of it, and vice versa, the same way every layer-based drawing tool\n * (this package included, as of this module) behaves. Before this module\n * existed, the two arrays had a hard-coded stacking instead: every shape\n * rendered above every stroke, regardless of which was actually drawn more\n * recently -- there was no way to draw on top of an already-placed shape.\n *\n * Documents from before this existed have no `z` on their strokes/shapes at\n * all. `LEGACY_Z_BASE` is a value comfortably larger than any realistic\n * shape/stroke count, so an item WITHOUT an explicit `z` keeps exactly that\n * old two-layer ordering (strokes 0..n-1, shapes LEGACY_Z_BASE..+m-1) when\n * merged into one list here -- no migration needed, nothing visually\n * changes for an already-drawn document until something new is added to it.\n * Items WITH an explicit `z` (everything created going forward, via\n * `nextZIndex` below) interleave by real creation order instead, and always\n * sort after every legacy item since their `z` starts above `LEGACY_Z_BASE`\n * too (see `nextZIndex`).\n */\nconst LEGACY_Z_BASE = 1e6;\n\nfunction effectiveZ(item, isShape, index) {\n return typeof item.z === 'number' ? item.z : isShape ? LEGACY_Z_BASE + index : index;\n}\n\n/** Merges strokes+shapes into one bottom-to-top render/hit-test order. Each entry is `{ kind: 'stroke' | 'shape', item, z }`. */\nexport function orderedDrawables(strokes, shapes) {\n const items = [\n ...strokes.map((item, i) => ({ kind: 'stroke', item, z: effectiveZ(item, false, i) })),\n ...shapes.map((item, i) => ({ kind: 'shape', item, z: effectiveZ(item, true, i) })),\n ];\n items.sort((a, b) => a.z - b.z);\n return items;\n}\n\n/** The z to stamp on a brand-new stroke/shape so it renders above everything already on the canvas (legacy or not). */\nexport function nextZIndex(strokes, shapes) {\n let maxZ = -1;\n strokes.forEach((item, i) => {\n maxZ = Math.max(maxZ, effectiveZ(item, false, i));\n });\n shapes.forEach((item, i) => {\n maxZ = Math.max(maxZ, effectiveZ(item, true, i));\n });\n return maxZ + 1;\n}\n\n/** The z one below everything already on the canvas — \"send to back\"'s own counterpart to `nextZIndex`. */\nexport function minZIndex(strokes, shapes) {\n let minZ = Infinity;\n strokes.forEach((item, i) => {\n minZ = Math.min(minZ, effectiveZ(item, false, i));\n });\n shapes.forEach((item, i) => {\n minZ = Math.min(minZ, effectiveZ(item, true, i));\n });\n return minZ === Infinity ? 0 : minZ - 1;\n}\n","import { getStrokeOutlinePath } from './strokeOutline.js';\nimport { arrowheadPoints, diamondPoints, trianglePoints, starPoints } from './shapeGeometry.js';\nimport { escapeAttr, escapeHTML } from '../../inline/marks.js';\nimport { orderedDrawables } from './zOrder.js';\n\nconst POLYGON_POINTS_BY_TYPE = {\n diamond: diamondPoints,\n triangle: trianglePoints,\n star: starPoints,\n};\n\n/**\n * Bakes one shape (rectangle/ellipse/arrow/text/diamond/triangle/star) to\n * markup — reusing the exact same `arrowheadPoints`/`*Points` functions the\n * live `ShapeElement` renders with, so export always matches on-screen.\n * `fillColor` (rect/ellipse/diamond/triangle/star only) defaults to\n * `fill=\"none\"` when unset, matching `ShapeElement`. A non-zero `rotation`\n * (rect/ellipse/diamond/triangle/star/text only — arrows are never\n * rotated, see CanvasBlock.jsx's own doc comment on rotation's scope) wraps\n * the markup in a `<g rotate()>`, the same pivot (bounding-box center)\n * `ShapeElement` uses.\n */\nexport function shapeToHTML(shape) {\n const strokeWidth = shape.strokeWidth ?? 8;\n const color = escapeAttr(shape.color);\n if (shape.type === 'arrow') {\n const headSize = Math.max(16, strokeWidth * 3);\n const head = arrowheadPoints(shape.x1, shape.y1, shape.x2, shape.y2, headSize);\n const points = head.map(([x, y]) => `${x},${y}`).join(' ');\n return (\n `<line x1=\"${shape.x1}\" y1=\"${shape.y1}\" x2=\"${shape.x2}\" y2=\"${shape.y2}\" stroke=\"${color}\" stroke-width=\"${strokeWidth}\"></line>` +\n `<polygon points=\"${points}\" fill=\"${color}\"></polygon>`\n );\n }\n const fill = shape.fillColor ? escapeAttr(shape.fillColor) : 'none';\n let content;\n if (shape.type === 'rectangle') {\n content = `<rect x=\"${shape.x}\" y=\"${shape.y}\" width=\"${shape.width}\" height=\"${shape.height}\" fill=\"${fill}\" stroke=\"${color}\" stroke-width=\"${strokeWidth}\"></rect>`;\n } else if (shape.type === 'ellipse') {\n const cx = shape.x + shape.width / 2;\n const cy = shape.y + shape.height / 2;\n content = `<ellipse cx=\"${cx}\" cy=\"${cy}\" rx=\"${shape.width / 2}\" ry=\"${shape.height / 2}\" fill=\"${fill}\" stroke=\"${color}\" stroke-width=\"${strokeWidth}\"></ellipse>`;\n } else if (shape.type === 'text') {\n // Same <foreignObject><div> approach as the live ShapeElement — real\n // browser text wrapping, not reimplemented SVG <text>/<tspan> layout.\n // `white-space:pre-wrap` alone (no manual <br> conversion) renders raw\n // newline characters as line breaks, matching how the live component's\n // own `{shape.text}` React text node renders under the same CSS.\n const fontSize = shape.fontSize ?? 28;\n const text = escapeHTML(shape.text ?? '');\n content =\n `<foreignObject x=\"${shape.x}\" y=\"${shape.y}\" width=\"${shape.width}\" height=\"${shape.height}\">` +\n `<div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"width:100%;height:100%;overflow:hidden;color:${color};font-size:${fontSize}px;line-height:1.3;white-space:pre-wrap;word-break:break-word;\">${text}</div>` +\n `</foreignObject>`;\n } else {\n const pointsFn = POLYGON_POINTS_BY_TYPE[shape.type];\n if (!pointsFn) return '';\n const rect = { x: shape.x, y: shape.y, width: shape.width, height: shape.height };\n const points = pointsFn(rect)\n .map(([x, y]) => `${x},${y}`)\n .join(' ');\n content = `<polygon points=\"${points}\" fill=\"${fill}\" stroke=\"${color}\" stroke-width=\"${strokeWidth}\"></polygon>`;\n }\n if (!shape.rotation) return content;\n const cx = shape.x + shape.width / 2;\n const cy = shape.y + shape.height / 2;\n return `<g transform=\"rotate(${shape.rotation} ${cx} ${cy})\">${content}</g>`;\n}\n\n/**\n * Bakes a canvas block's `strokes`/`shapes` into one self-contained\n * `<svg>...</svg>` string — reusing the exact same `getStrokeOutlinePath`/\n * `shapeToHTML` functions the live component renders with, so this always\n * matches what's on screen, INCLUDING their relative stacking order\n * (`orderedDrawables`, see zOrder.js — a pen stroke drawn on top of a\n * shape live must still render on top of it here). Shared by two call sites that both need the\n * SAME markup for two different purposes (this module exists specifically\n * to let them both import it without a circular dependency — `index.js`'s\n * own `toHTML` needs `CanvasBlock.jsx` for its `component` field, and\n * `CanvasBlock.jsx`'s PNG-export button needs this markup, so this couldn't\n * live in either of those two files without one importing the other):\n * - `index.js`'s `toHTML` embeds it inline in exported document HTML.\n * - `CanvasBlock.jsx`'s \"Export PNG\" button loads it into an `Image` (via\n * an `xmlns`-qualified, standalone-valid SVG document — required for a\n * browser to parse it outside an HTML embedding context) and rasterizes\n * that onto an offscreen `<canvas>`.\n */\nexport function buildCanvasSVGMarkup(block) {\n const { strokes = [], shapes = [], width, height } = block.props;\n const markup = orderedDrawables(strokes, shapes)\n .map(({ kind, item }) =>\n kind === 'stroke'\n ? `<path fill=\"${escapeAttr(item.color)}\" d=\"${getStrokeOutlinePath(item.points, { size: item.size })}\"></path>`\n : shapeToHTML(item),\n )\n .join('');\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1000 1000\" width=\"${width}\" height=\"${height}\">${markup}</svg>`;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useBlock } from '../../react/useBlock.js';\nimport { useBlockClassName, useEditorStore } from '../../react/EditorProvider.jsx';\nimport { useOutsideClickAndEscape } from '../../react/useOutsideClickAndEscape.js';\nimport { updateBlockProps } from '../../store/operations.js';\nimport { genId } from '../../utils/idGen.js';\nimport { getStrokeOutlinePath, strokeBoundingBox } from './strokeOutline.js';\nimport {\n clientToLocal,\n boxesIntersect,\n localPixelScale,\n zoomAnchoredView,\n zoomCenteredView,\n clampViewOffset,\n} from './canvasGeometry.js';\nimport {\n arrowheadPoints,\n normalizeRect,\n pointInRect,\n pointInEllipse,\n pointNearSegment,\n diamondPoints,\n trianglePoints,\n starPoints,\n pointInPolygon,\n rotatePoint,\n} from './shapeGeometry.js';\nimport { useDragResize } from '../../react/useDragResize.js';\nimport { DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT } from './createCanvasBlock.js';\nimport { buildCanvasSVGMarkup } from './exportSvg.js';\nimport { orderedDrawables, nextZIndex, minZIndex } from './zOrder.js';\nimport {\n PencilIcon,\n XIcon,\n SquareIcon,\n CircleIcon,\n ArrowDiagonalIcon,\n CursorIcon,\n DiamondIcon,\n TriangleIcon,\n StarIcon,\n ArrowUpIcon,\n ArrowDownIcon,\n TextIcon,\n MagnetIcon,\n DownloadIcon,\n EraserIcon,\n} from '../../react/icons.jsx';\n\n// The whole drawing surface is authored in this fixed logical space —\n// `props.width`/`props.height` only control the SVG's *rendered* pixel\n// size (the viewBox/rendered-size split below), never the coordinates\n// stroke data is stored in. This is what makes resizing the block a pure\n// \"change how big this is drawn\" operation that never touches `strokes`.\nconst VIEW_SIZE = 1000;\n\nconst DEFAULT_COLOR = '#1a1a1a';\nconst DEFAULT_STROKE_SIZE = 8;\n// A small fixed palette, same spirit as FloatingToolbar's own text-color\n// swatches — a pen stroke always needs a concrete color (no \"Default\"/null\n// option the way text color has, since ink has to render as *something*).\nconst COLOR_SWATCHES = ['#1a1a1a', '#e03131', '#2f9e44', '#1971c2', '#f08c00'];\nconst MIN_STROKE_SIZE = 2;\nconst MAX_STROKE_SIZE = 40;\n// Half-width of the eraser's own hit area, in the same fixed 0..1000\n// normalized space strokes are authored in. Two selectable eraser modes\n// (see the toolbar's own Eraser popover) share the exact same hit-test\n// logic (`hitTestEraserAt`, erasing whole strokes/shapes it touches, never\n// partial pixels) — they differ only in this radius: \"Object Eraser\" is\n// deliberately generous (bigger than a typical pen stroke), forgiving to\n// aim when you want to clear something out quickly; \"Precise Eraser\" uses\n// a much smaller radius, for working close to other ink without\n// accidentally sweeping up a neighboring stroke/shape. \"Forgiving to aim\"\n// is about REACH (how close you need to get to a stroke), not precision,\n// though — the actual hit-test (see `strokeNearPoint`) still only counts a\n// stroke as touched where the eraser is actually near its real path, not\n// merely somewhere inside its overall bounding box, regardless of mode.\nconst ERASER_RADIUS = 24;\nconst ERASER_RADIUS_PRECISE = 6;\nconst MIN_CANVAS_WIDTH = 160;\nconst MIN_CANVAS_HEIGHT = 120;\nconst MIN_ZOOM = 0.5;\nconst MAX_ZOOM = 4;\nconst ZOOM_STEP = 1.1;\n// Below this local-space drag distance (on either axis), a marquee drag is\n// treated as a plain click instead — see commitMarquee.\nconst MARQUEE_MIN_DRAG = 4;\n// How far a pasted/duplicated copy is offset from its source, in the same\n// fixed 0..1000 normalized space — enough to be visibly distinct from the\n// original without landing off a typically-visible canvas area.\nconst PASTE_OFFSET = 24;\n// Arrow-key nudge step for the selection, in the same fixed 0..1000\n// normalized space — Shift+arrow moves 10x further, the common \"fine vs.\n// coarse nudge\" convention.\nconst NUDGE_STEP = 1;\nconst NUDGE_STEP_LARGE = 10;\nconst NUDGE_DELTAS = {\n ArrowUp: [0, -1],\n ArrowDown: [0, 1],\n ArrowLeft: [-1, 0],\n ArrowRight: [1, 0],\n};\n// A freshly-placed text box's default size/font, in the same fixed\n// 0..1000 normalized space — no auto-grow-to-fit-content or a dedicated\n// font-size control in this pass (a deliberate v1 scope cut); the box can\n// still be resized afterward via the same corner-drag every other shape\n// already supports, since a text shape's `{x,y,width,height}` is the exact\n// same shape those generic helpers already operate on.\nconst DEFAULT_TEXT_WIDTH = 220;\nconst DEFAULT_TEXT_HEIGHT = 60;\nconst DEFAULT_TEXT_FONT_SIZE = 28;\nconst MIN_TEXT_FONT_SIZE = 12;\nconst MAX_TEXT_FONT_SIZE = 96;\n\n// Snapping (toggleable via the toolbar's magnet button, on by default): a\n// plain fixed grid in the same 0..1000 normalized space — not \"snap to\n// other shapes' edges/centers\" alignment guides, which is a substantially\n// bigger feature (computing candidate lines from every other shape,\n// rendering guide lines, etc.) explicitly out of scope for this pass.\n// Applies to pointer DRAGS (draw/move/resize/rotate), which are imprecise\n// by hand — not to arrow-key nudge, which is already exact.\nconst SNAP_GRID_SIZE = 10;\nconst SNAP_ROTATION_STEP = 15;\n// The visible grid-dot spacing is coarser than SNAP_GRID_SIZE itself (a\n// dot at every actual 10-unit snap line would be a dense, unhelpful wall\n// of dots at this space's scale) — purely a visual reference for \"this is\n// what snapping aligns to,\" not a 1:1 rendering of every snap position.\nconst SNAP_GRID_VISUAL_SPACING = SNAP_GRID_SIZE * 5;\n\nfunction snapValue(v) {\n return Math.round(v / SNAP_GRID_SIZE) * SNAP_GRID_SIZE;\n}\n\nfunction snapAngle(deg) {\n return Math.round(deg / SNAP_ROTATION_STEP) * SNAP_ROTATION_STEP;\n}\n\n/**\n * One stroke's outline path is pure/deterministic from its own `points`\n * (see strokeOutline.js) — cached by stroke object identity so committing a\n * NEW stroke (or resizing the block) never recomputes every other already-\n * drawn stroke's path, only whichever ones are new. Strokes are only ever\n * appended/replaced wholesale (never mutated in place — see\n * createCanvasBlock.js's doc comment), so identity-based caching is safe.\n *\n * A `WeakMap`, not a `Map` — a long editing session's erases/undo-redo\n * cycles replace/drop stroke objects constantly, and a plain `Map` would\n * hold every one of them (and its computed path string) forever, since\n * nothing ever deleted old entries: an unbounded memory leak that grows\n * with total strokes EVER drawn in the session, not just the current\n * count. A `WeakMap` holds its keys weakly, so once a stroke is no longer\n * referenced anywhere else (dropped from `props.strokes` AND far enough\n * out of undo/redo history), its cache entry becomes collectible\n * automatically — no manual pruning needed.\n */\nfunction useStrokePathCache() {\n const cacheRef = useRef(new WeakMap());\n return (stroke) => {\n const cache = cacheRef.current;\n let path = cache.get(stroke);\n if (path === undefined) {\n path = getStrokeOutlinePath(stroke.points, { size: stroke.size });\n cache.set(stroke, path);\n }\n return path;\n };\n}\n\nfunction pointBox(x, y, r) {\n return { minX: x - r, minY: y - r, maxX: x + r, maxY: y + r };\n}\n\n/** The average client position of every currently-down touch pointer — the anchor point a two-finger pan drag tracks (see touchPanRef in CanvasBlock). */\nfunction touchCentroid(pointsMap) {\n let sumX = 0;\n let sumY = 0;\n for (const point of pointsMap.values()) {\n sumX += point.x;\n sumY += point.y;\n }\n const count = pointsMap.size || 1;\n return { x: sumX / count, y: sumY / count };\n}\n\n/**\n * Whether `(x, y)` falls within `tolerance` of the ACTUAL stroke path — its\n * real polyline segments (or, for a single-point \"dot\" stroke, that one\n * point) — rather than just its bounding box. The eraser's own hit-test\n * uses this as the final decision (after `boxesIntersect` against\n * `strokeBoundingBox` as a cheap pre-filter, since this per-segment walk is\n * more expensive): a bounding box alone is only tight for a straight\n * stroke — an L-shaped or diagonal one has real empty space inside its own\n * box that the eraser shouldn't be able to trigger on, which is exactly\n * the \"eraser erases things it never actually touched\" imprecision this\n * replaces.\n */\nfunction strokeNearPoint(stroke, x, y, tolerance) {\n const points = stroke.points;\n if (points.length === 1) {\n const [px, py] = points[0];\n return Math.hypot(x - px, y - py) <= tolerance;\n }\n for (let i = 0; i < points.length - 1; i += 1) {\n const [x1, y1] = points[i];\n const [x2, y2] = points[i + 1];\n if (pointNearSegment(x, y, x1, y1, x2, y2, tolerance)) return true;\n }\n return false;\n}\n\nconst SHAPE_TOOLS = new Set(['rectangle', 'ellipse', 'arrow', 'diamond', 'triangle', 'star']);\n\n/** Maps a polygon-based shape type to its own vertex-generator function (see shapeGeometry.js) — the one place that association lives, reused by both rendering and hit-testing. */\nconst POLYGON_POINTS_BY_TYPE = {\n diamond: diamondPoints,\n triangle: trianglePoints,\n star: starPoints,\n};\n\n/** The 6 shape tools, folded into one popover (see the toolbar JSX) rather than 6 always-visible buttons — Pen/Select stay individual buttons since those are used far more often; Eraser gets its own small popover too (see ERASER_MODE_LIST) since it now has 2 modes. */\nconst SHAPE_TOOL_LIST = [\n { type: 'rectangle', label: 'Rectangle', Icon: SquareIcon },\n { type: 'ellipse', label: 'Ellipse', Icon: CircleIcon },\n { type: 'arrow', label: 'Arrow', Icon: ArrowDiagonalIcon },\n { type: 'diamond', label: 'Diamond', Icon: DiamondIcon },\n { type: 'triangle', label: 'Triangle', Icon: TriangleIcon },\n { type: 'star', label: 'Star', Icon: StarIcon },\n];\n\n/**\n * The 2 eraser modes, folded into one popover (mirroring SHAPE_TOOL_LIST's\n * own pattern). Object Eraser removes whichever WHOLE stroke/shape it\n * touches, same as a real \"select and delete.\" Precise Eraser removes only\n * the individual POINTS of a stroke it actually passes over — like a real\n * pencil eraser, it can rub out just the middle of a line and leave the\n * two remaining ends behind as separate strokes (see `splitStrokePoints`\n * and `hitTestEraserAt`'s own doc comment) — plus uses a smaller hit\n * radius (ERASER_RADIUS_PRECISE vs ERASER_RADIUS) for working close to\n * other ink. Shapes have no per-point path to partially erase, so BOTH\n * modes remove a touched shape whole — Precise mode's only difference for\n * shapes is the smaller radius.\n */\nconst ERASER_MODE_LIST = [\n { mode: 'object', label: 'Object Eraser', Icon: EraserIcon },\n { mode: 'precise', label: 'Precise Eraser', Icon: XIcon },\n];\n\n/**\n * Turns an in-progress drag draft (`{ type, x1, y1, x2, y2 }`) into the same\n * shape-object shape `ShapeElement` and a committed `props.shapes` entry\n * both use — shared by the live preview and the final commit so they're\n * guaranteed to render identically (see `normalizeRect`'s own doc comment\n * for why rectangle/ellipse always come out non-negative regardless of\n * drag direction).\n */\nfunction buildDraftShape(draft, color, strokeWidth, fillColor) {\n if (draft.type === 'arrow') {\n return {\n type: 'arrow',\n x1: draft.x1,\n y1: draft.y1,\n x2: draft.x2,\n y2: draft.y2,\n color,\n strokeWidth,\n };\n }\n return {\n type: draft.type,\n ...normalizeRect(draft.x1, draft.y1, draft.x2, draft.y2),\n color,\n strokeWidth,\n fillColor,\n };\n}\n\n// Generous hit-test tolerance for the arrow tool (a thin line is otherwise\n// hard to click precisely), in the same fixed 0..1000 normalized space —\n// same spirit as the eraser's own deliberately-forgiving ERASER_RADIUS.\nconst ARROW_HIT_TOLERANCE = 16;\n\n/**\n * Which shape (if any) the select tool's pointerdown landed on — walked in\n * reverse (last-drawn/topmost first) so overlapping shapes resolve to\n * whichever one visually renders on top, matching how every other \"click\n * to select\" surface behaves. Rectangle/ellipse hit-test their whole\n * bounding box (see shapeGeometry.js's own doc comment on `pointInRect`/\n * `pointInEllipse` for why — a deliberate v1 simplification for unfilled\n * shapes); arrow hit-tests a tolerance band around its line segment.\n * Diamond/triangle/star hit-test their own precise polygon (see\n * shapeGeometry.js's `pointInPolygon`) rather than falling back to the\n * bounding box — unlike a rectangle, their box has substantial area\n * outside the actual shape (e.g. a diamond's 4 corner triangles) that a\n * bounding-box test would wrongly treat as \"inside.\"\n */\nfunction hitTestOneShape(shape, x, y) {\n if (shape.type === 'arrow') {\n return pointNearSegment(x, y, shape.x1, shape.y1, shape.x2, shape.y2, ARROW_HIT_TOLERANCE);\n }\n const rect = { x: shape.x, y: shape.y, width: shape.width, height: shape.height };\n // A rotated shape is rendered rotated (see ShapeElement) but stored in\n // its own unrotated `x/y/width/height` — map the click point back into\n // that unrotated local frame (inverse rotation around the shape's own\n // center) before running the ordinary tests below, rather than teaching\n // every one of those tests about rotation individually.\n let [testX, testY] = [x, y];\n if (shape.rotation) {\n const { cx, cy } = shapeCenter(shape);\n [testX, testY] = rotatePoint(x, y, cx, cy, -shape.rotation);\n }\n const pointsFn = POLYGON_POINTS_BY_TYPE[shape.type];\n if (pointsFn) return pointInPolygon(testX, testY, pointsFn(rect));\n return shape.type === 'ellipse'\n ? pointInEllipse(testX, testY, rect)\n : pointInRect(testX, testY, rect);\n}\n\nfunction hitTestShapeAt(x, y, shapes) {\n for (let i = shapes.length - 1; i >= 0; i -= 1) {\n if (hitTestOneShape(shapes[i], x, y)) return shapes[i].id;\n }\n return null;\n}\n\n/** Translates a shape by `(dx, dy)` — used both to commit a finished move and to render its live in-progress preview. */\nfunction applyShapeOffset(shape, dx, dy) {\n if (shape.type === 'arrow') {\n return { ...shape, x1: shape.x1 + dx, y1: shape.y1 + dy, x2: shape.x2 + dx, y2: shape.y2 + dy };\n }\n return { ...shape, x: shape.x + dx, y: shape.y + dy };\n}\n\n/** A shape's own bounding box, regardless of type — used to size the selection overlay. */\nfunction shapeBoundingBox(shape) {\n if (shape.type === 'arrow') {\n return {\n x: Math.min(shape.x1, shape.x2),\n y: Math.min(shape.y1, shape.y2),\n width: Math.abs(shape.x2 - shape.x1),\n height: Math.abs(shape.y2 - shape.y1),\n };\n }\n return { x: shape.x, y: shape.y, width: shape.width, height: shape.height };\n}\n\n/** A shape's own rotation center — the midpoint of its bounding box, the same pivot `ShapeElement`'s `rotate()` transform uses. Arrows are never rotated (see the component doc comment on rotation's scope), so this is only meaningful for rect/ellipse/diamond/triangle/star. */\nfunction shapeCenter(shape) {\n const box = shapeBoundingBox(shape);\n return { cx: box.x + box.width / 2, cy: box.y + box.height / 2 };\n}\n\n/** Translates a stroke's every point by `(dx, dy)` — the multi-select move drag's own analogue of `applyShapeOffset`, used both to commit a finished group move and to render its live preview. */\nfunction applyStrokeOffset(stroke, dx, dy) {\n return { ...stroke, points: stroke.points.map(([x, y, pressure]) => [x + dx, y + dy, pressure]) };\n}\n\n/**\n * The Precise Eraser's own commit step: splits a stroke's points AROUND\n * whichever indices were erased, into one run per surviving contiguous\n * group — a real pencil-eraser \"rub out just this part\" result, not a\n * whole-stroke delete. Returns an array of point arrays (each with >=1\n * point); an empty array means every point was erased, so the stroke\n * disappears entirely. `commitErase` gives the FIRST resulting run the\n * stroke's own original id (so an edit that doesn't actually split\n * anything — erasing only from one end — doesn't need a new id) and a\n * fresh id for every additional run a split in the MIDDLE produces.\n */\nfunction splitStrokePoints(points, erasedIndices) {\n const runs = [];\n let current = [];\n for (let i = 0; i < points.length; i += 1) {\n if (erasedIndices.has(i)) {\n if (current.length > 0) runs.push(current);\n current = [];\n } else {\n current.push(points[i]);\n }\n }\n if (current.length > 0) runs.push(current);\n return runs;\n}\n\n/** A stroke's own bounding box, in the same `{x,y,width,height}` shape `shapeBoundingBox` returns (rather than strokeOutline.js's own `{minX,minY,maxX,maxY}`), so both selectable kinds share one rendering/hit-test code path. */\nfunction strokeBoxRect(stroke) {\n const box = strokeBoundingBox(stroke.points);\n return { x: box.minX, y: box.minY, width: box.maxX - box.minX, height: box.maxY - box.minY };\n}\n\n/** Either selectable kind's own bounding box, in `{x,y,width,height}` form. */\nfunction selectableBoundingBox(kind, item) {\n return kind === 'stroke' ? strokeBoxRect(item) : shapeBoundingBox(item);\n}\n\n/**\n * Resolves a multi-select id to whichever of `strokes`/`shapes` it belongs\n * to — an id may be either, since multi-select spans both arrays (see the\n * component doc comment on the \"select\" tool below).\n */\nfunction findSelectable(block, selId) {\n const strokes = block?.props?.strokes ?? [];\n const shapes = block?.props?.shapes ?? [];\n const stroke = strokes.find((s) => s.id === selId);\n if (stroke) return { kind: 'stroke', item: stroke };\n const shape = shapes.find((s) => s.id === selId);\n if (shape) return { kind: 'shape', item: shape };\n return null;\n}\n\n/**\n * Which stroke or shape (if any) the select tool's pointerdown landed on —\n * walks the SAME merged bottom-to-top order rendering uses (`orderedDrawables`,\n * see zOrder.js), topmost first, so overlapping items resolve to whichever\n * one is actually visible on top, regardless of whether it's a stroke or a\n * shape. Strokes hit-test their own bounding box — the same deliberate v1\n * simplification rectangle/ellipse click-select already uses, not\n * per-point path distance.\n */\nfunction hitTestSelectableAt(x, y, strokes, shapes) {\n const ordered = orderedDrawables(strokes, shapes);\n for (let i = ordered.length - 1; i >= 0; i -= 1) {\n const { kind, item } = ordered[i];\n if (kind === 'shape') {\n if (hitTestOneShape(item, x, y)) return { kind: 'shape', id: item.id };\n } else if (pointInRect(x, y, strokeBoxRect(item))) {\n return { kind: 'stroke', id: item.id };\n }\n }\n return null;\n}\n\n// Generous hit radius for grabbing a resize/endpoint handle, and its own\n// visual size — both in the same fixed 0..1000 normalized space everything\n// else here uses (so handles scale naturally with zoom, same as stroke\n// widths already do).\nconst HANDLE_HIT_RADIUS = 24;\nconst HANDLE_VISUAL_SIZE = 14;\n\n/** The 4 corner points of a rectangle/ellipse shape's own bounding box, keyed by compass corner. */\nfunction rectCorners(shape) {\n return {\n nw: [shape.x, shape.y],\n ne: [shape.x + shape.width, shape.y],\n sw: [shape.x, shape.y + shape.height],\n se: [shape.x + shape.width, shape.y + shape.height],\n };\n}\n\nconst OPPOSITE_CORNER = { nw: 'se', ne: 'sw', sw: 'ne', se: 'nw' };\n\n// How far above the shape's own (unrotated) top edge the rotate handle\n// floats, in the same fixed 0..1000 normalized space as everything else.\nconst ROTATE_HANDLE_OFFSET = 32;\n\n/**\n * The rotate handle's own position — a fixed distance above the shape's\n * unrotated bounding-box top-center, then rotated around the shape's own\n * center by its current `rotation` so the handle visually stays attached\n * as the shape spins (same \"computed from stored state, not itself stored\"\n * principle as arrowheadPoints). Arrows are never rotated (see the\n * component doc comment on rotation's scope), so this is only meaningful\n * for rect/ellipse/diamond/triangle/star.\n */\nfunction rotateHandlePoint(shape) {\n const box = shapeBoundingBox(shape);\n const localX = box.x + box.width / 2;\n const localY = box.y - ROTATE_HANDLE_OFFSET;\n if (!shape.rotation) return [localX, localY];\n const { cx, cy } = shapeCenter(shape);\n return rotatePoint(localX, localY, cx, cy, shape.rotation);\n}\n\n/**\n * Which resize/endpoint/rotate handle (if any) `(x, y)` landed on, for the\n * CURRENTLY SELECTED shape only (handles for every other shape are neither\n * rendered nor hit-tested) — checked before the general\n * `hitTestShapeAt` body hit-test, so grabbing a handle always takes\n * priority over re-selecting/moving the shape it belongs to. The rotate\n * handle is checked first since it sits outside the shape's own bounding\n * box, never overlapping a corner handle. Corner resize handles are hidden\n * (and un-hit-testable) once a shape has any rotation — see the component\n * doc comment on rotation's scope: no rotated-resize math in this pass.\n */\nfunction hitTestHandle(x, y, shape) {\n if (!shape) return null;\n if (shape.type === 'arrow') {\n if (Math.hypot(x - shape.x1, y - shape.y1) <= HANDLE_HIT_RADIUS) return 'start';\n if (Math.hypot(x - shape.x2, y - shape.y2) <= HANDLE_HIT_RADIUS) return 'end';\n return null;\n }\n const [rhx, rhy] = rotateHandlePoint(shape);\n if (Math.hypot(x - rhx, y - rhy) <= HANDLE_HIT_RADIUS) return 'rotate';\n if (shape.rotation) return null;\n for (const [corner, [cx, cy]] of Object.entries(rectCorners(shape))) {\n if (Math.hypot(x - cx, y - cy) <= HANDLE_HIT_RADIUS) return corner;\n }\n return null;\n}\n\n/**\n * Builds the live (or final, at commit time) resized/endpoint-dragged/\n * rotated shape from an in-progress resize draft — `normalizeRect` (the\n * same function that turns a fresh rectangle/ellipse drag into a valid\n * box, see `buildDraftShape`) does the real work for the corner-drag case:\n * dragging ANY corner is just \"normalize a box between the fixed opposite\n * corner and wherever the pointer currently is,\" so no separate per-corner\n * math is needed. The rotate case just reuses whatever angle\n * `handlePointerMove` already computed onto the draft (see its own\n * 'rotate'-mode branch) — this function's only job there is picking it off\n * the draft into the shape.\n */\nfunction buildResizedShape(shape, draft) {\n if (draft.mode === 'arrow-endpoint') {\n return draft.endpoint === 'start'\n ? { ...shape, x1: draft.x, y1: draft.y }\n : { ...shape, x2: draft.x, y2: draft.y };\n }\n if (draft.mode === 'rotate') {\n return { ...shape, rotation: draft.rotation };\n }\n return { ...shape, ...normalizeRect(draft.fixedX, draft.fixedY, draft.x, draft.y) };\n}\n\n/**\n * Renders one shape (rectangle, ellipse, arrow, text, or a polygon type) —\n * reused for both a committed `props.shapes` entry and the in-progress\n * drag preview, so the live preview and the final render are guaranteed to\n * look identical (same component, same props shape). `fillColor` (rect/\n * ellipse/diamond/triangle/star only) defaults to `fill=\"none\"` when unset\n * — arrows have no fill of their own (their arrowhead polygon is always\n * solid-filled with the stroke color, not a separate fill), and text uses\n * `color` for its own text color rather than a fill. A non-zero `rotation`\n * (rect/ellipse/diamond/triangle/star/text — arrows are never rotated, see\n * the component doc comment on rotation's scope) wraps the shape in a `<g>`\n * with an SVG `rotate()` transform around its own bounding-box center — the\n * exact pivot `shapeCenter`/`rotatePoint`-based hit-testing and the rotate\n * handle's own position both use, so click-select and the handle stay\n * visually in sync with what this renders.\n */\nfunction ShapeElement({ shape, opacity = 1 }) {\n const strokeWidth = shape.strokeWidth ?? DEFAULT_STROKE_SIZE;\n let content;\n if (shape.type === 'rectangle') {\n content = (\n <rect\n x={shape.x}\n y={shape.y}\n width={shape.width}\n height={shape.height}\n fill={shape.fillColor ?? 'none'}\n stroke={shape.color}\n strokeWidth={strokeWidth}\n opacity={opacity}\n />\n );\n } else if (shape.type === 'ellipse') {\n content = (\n <ellipse\n cx={shape.x + shape.width / 2}\n cy={shape.y + shape.height / 2}\n rx={shape.width / 2}\n ry={shape.height / 2}\n fill={shape.fillColor ?? 'none'}\n stroke={shape.color}\n strokeWidth={strokeWidth}\n opacity={opacity}\n />\n );\n } else if (shape.type === 'arrow') {\n const headSize = Math.max(16, strokeWidth * 3);\n const head = arrowheadPoints(shape.x1, shape.y1, shape.x2, shape.y2, headSize);\n return (\n <g opacity={opacity}>\n <line\n x1={shape.x1}\n y1={shape.y1}\n x2={shape.x2}\n y2={shape.y2}\n stroke={shape.color}\n strokeWidth={strokeWidth}\n />\n <polygon points={head.map(([x, y]) => `${x},${y}`).join(' ')} fill={shape.color} />\n </g>\n );\n } else if (shape.type === 'text') {\n // A <foreignObject> + plain HTML <div> gets real browser text\n // wrapping/line-breaking for free — reimplementing that in raw SVG\n // <text>/<tspan> layout is a lot of work for no benefit here. No\n // auto-grow-to-fit: overflow is clipped to the box, same \"resize the\n // box yourself\" convention as every other shape's fixed bounding box.\n content = (\n <foreignObject\n x={shape.x}\n y={shape.y}\n width={shape.width}\n height={shape.height}\n opacity={opacity}\n >\n <div\n // eslint-disable-next-line react/no-unknown-property\n xmlns=\"http://www.w3.org/1999/xhtml\"\n style={{\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n color: shape.color,\n fontSize: shape.fontSize ?? DEFAULT_TEXT_FONT_SIZE,\n lineHeight: 1.3,\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n fontFamily: 'inherit',\n }}\n >\n {shape.text}\n </div>\n </foreignObject>\n );\n } else {\n const pointsFn = POLYGON_POINTS_BY_TYPE[shape.type];\n if (!pointsFn) return null;\n const rect = { x: shape.x, y: shape.y, width: shape.width, height: shape.height };\n const points = pointsFn(rect)\n .map(([x, y]) => `${x},${y}`)\n .join(' ');\n content = (\n <polygon\n points={points}\n fill={shape.fillColor ?? 'none'}\n stroke={shape.color}\n strokeWidth={strokeWidth}\n opacity={opacity}\n />\n );\n }\n if (!shape.rotation) return content;\n const { cx, cy } = shapeCenter(shape);\n return <g transform={`rotate(${shape.rotation} ${cx} ${cy})`}>{content}</g>;\n}\n\n/**\n * A pure \"widget\" block — no runs/text at all (contentIds always []), same\n * shape as DividerBlock/EmbedBlock — so it participates in cross-block\n * select/copy/cut/delete for free via the exact same generic mechanisms\n * those already exercise (see `src/blocks/shared/contentless.js`): a\n * canvas block backspaced-into from a neighboring paragraph behaves exactly\n * like an image/divider would, with zero canvas-specific code needed for\n * that lifecycle.\n *\n * Renders every committed stroke as one filled `<path>` (see\n * strokeOutline.js) inside an SVG whose `viewBox` is the fixed logical\n * VIEW_SIZE space and whose `width`/`height` attributes are the block's own\n * rendered pixel size (`props.width`/`props.height`).\n *\n * Both tools below share the same \"local state/refs during the gesture,\n * exactly ONE store write on release\" discipline (mirroring EmbedBlock.jsx's\n * resize-drag convention, adapted to native Pointer Events +\n * `setPointerCapture` instead of document-level mouse listeners):\n *\n * - **Pen** (Phase 2): raw `[x, y, pressure]` points accumulate in\n * `pointsRef` on every `pointermove` — a plain ref mutation, never itself\n * a React state update or a store write. The in-progress stroke's visual\n * preview updates only via a `requestAnimationFrame`-throttled\n * `previewPath` state (capped at ~60 recomputes/sec regardless of\n * pointermove frequency). `pointerup` makes the one real commit: appends\n * the finished stroke via `updateBlockProps`.\n * - **Eraser** (Phase 3): whole-object removal (strokes AND shapes alike),\n * not pixel erasing — 2 selectable modes (see ERASER_MODE_LIST) share\n * this whole discipline and differ only in hit radius. Each pointermove\n * hit-tests the eraser's small local radius against every not-yet-erased\n * stroke's ACTUAL path (`strokeNearPoint`, walking its real segments —\n * not just its bounding box, which a diagonal or L-shaped stroke has real\n * empty space inside of) and every not-yet-erased shape's bounding box,\n * marking touched ids in `erasedStrokeIdsRef`/`erasedShapeIdsRef` (refs,\n * not store writes) — a cheap `boxesIntersect` bounding-box pre-filter\n * (see strokeOutline.js's `strokeBoundingBox`) skips the more expensive\n * per-segment walk for strokes nowhere near the eraser at all. The\n * rAF-throttled `erasingIds`/`erasingShapeIds` state only drives a live\n * fade-out preview. `pointerup` makes the one commit: `strokes` AND\n * `shapes` each filtered to drop every touched id, in a single\n * `updateBlockProps` call — a whole erase drag removing N objects is\n * still just one undo step, same discipline as pen.\n *\n * Pan/zoom (Phase 5) is plain LOCAL component state (`view`), never written\n * through `updateBlockProps` and never undo-tracked — it's a viewport\n * preference (\"where am I currently looking\"), not document content, the\n * same reasoning as why no block in this codebase persists a scroll\n * position. Applied purely via the `<svg>`'s own `viewBox` attribute, so\n * stroke coordinates themselves are never touched by panning/zooming.\n * Zoom is Ctrl/Cmd+wheel — also how a trackpad OR touchscreen pinch\n * gesture reports itself. Pan is: a middle-mouse-button drag (a plain,\n * always-available gesture that doesn't depend on which tool is currently\n * active or on keyboard focus, unlike a space-bar-held convention would);\n * a plain (non-ctrl) wheel, i.e. a trackpad's two-finger scroll; or two\n * fingers dragging on a touchscreen (see touchPanRef/cancelActiveSingleGesture) —\n * the latter takes over from whatever the first finger alone had already\n * started (drawing, erasing, ...) the instant a second finger touches down.\n */\nexport function CanvasBlock({ id }) {\n const store = useEditorStore();\n const block = useBlock(id);\n const className = useBlockClassName('be-canvas', block);\n const getStrokePath = useStrokePathCache();\n\n const [tool, setTool] = useState('pen'); // 'pen' | 'eraser' | 'select' | 'text' | one of SHAPE_TOOLS — ephemeral UI state, not persisted (same reasoning as pan/zoom: an authoring detail, not document content)\n // Which eraser mode is active (see ERASER_MODE_LIST/ERASER_RADIUS*'s own\n // doc comments) — remembered the same way `lastShapeTool` is, so the\n // Eraser popover's trigger button always shows a meaningful icon.\n const [eraserMode, setEraserMode] = useState('object');\n const [color, setColor] = useState(DEFAULT_COLOR);\n const [strokeSize, setStrokeSize] = useState(DEFAULT_STROKE_SIZE);\n // Fill color for NEW rect/ellipse/diamond/triangle/star shapes — `null`\n // means \"no fill\" (`fill=\"none\"`, today's only behavior before this\n // control existed, and still the default). Arrows have no fill (they're\n // inherently linear) and text uses `color` for its own text color, so\n // neither reads this. Same \"tool default, not retroactive to an already-\n // selected shape\" scope as `color`/`strokeSize` — changing it only\n // affects shapes drawn from then on.\n const [fill, setFill] = useState(null);\n // Grid snapping, on by default — toggled via the toolbar's magnet\n // button. Ephemeral UI state, not persisted, same reasoning as `tool`.\n const [snapEnabled, setSnapEnabled] = useState(true);\n // Font size for the text tool — same \"tool default for the NEXT new\n // box\" scope as color/strokeSize/fill, EXCEPT while a text box is\n // actively being edited (`textEditDraft` set): the size picker's\n // onChange then also live-updates that draft's own fontSize directly\n // (see its JSX below), since seeing the effect immediately while typing\n // is far more useful than only affecting boxes placed afterward.\n const [textFontSize, setTextFontSize] = useState(DEFAULT_TEXT_FONT_SIZE);\n // Remembers whichever shape tool was picked most recently, so the shape\n // popover's own trigger button can show a meaningful icon (and so\n // re-clicking a would-be \"repeat last shape\" affordance would have\n // something to repeat) even while Pen/Eraser/Select is the active tool.\n const [lastShapeTool, setLastShapeTool] = useState('rectangle');\n\n // Color/size/shape pickers: small inline popovers (position:relative\n // wrapper + position:absolute popover, same convention as\n // FloatingToolbar's own text-color/highlight pickers) rather than a\n // portaled menu — these are small pickers anchored to a toolbar that's\n // always already inside the document's normal flow, not a standalone\n // floating menu that needs viewport-overflow handling of its own.\n const [isColorPickerOpen, setIsColorPickerOpen] = useState(false);\n const [isFillPickerOpen, setIsFillPickerOpen] = useState(false);\n const [isSizePickerOpen, setIsSizePickerOpen] = useState(false);\n const [isShapePickerOpen, setIsShapePickerOpen] = useState(false);\n const [isFontSizePickerOpen, setIsFontSizePickerOpen] = useState(false);\n const [isEraserPickerOpen, setIsEraserPickerOpen] = useState(false);\n const colorTriggerRef = useRef(null);\n const colorPopoverRef = useRef(null);\n const fillTriggerRef = useRef(null);\n const fillPopoverRef = useRef(null);\n const sizeTriggerRef = useRef(null);\n const sizePopoverRef = useRef(null);\n const shapeTriggerRef = useRef(null);\n const shapePopoverRef = useRef(null);\n const fontSizeTriggerRef = useRef(null);\n const fontSizePopoverRef = useRef(null);\n const eraserTriggerRef = useRef(null);\n const eraserPopoverRef = useRef(null);\n const colorRefs = useMemo(() => [colorTriggerRef, colorPopoverRef], []);\n const fillRefs = useMemo(() => [fillTriggerRef, fillPopoverRef], []);\n const sizeRefs = useMemo(() => [sizeTriggerRef, sizePopoverRef], []);\n const shapeRefs = useMemo(() => [shapeTriggerRef, shapePopoverRef], []);\n const fontSizeRefs = useMemo(() => [fontSizeTriggerRef, fontSizePopoverRef], []);\n const eraserRefs = useMemo(() => [eraserTriggerRef, eraserPopoverRef], []);\n const closeColorPicker = useCallback(() => setIsColorPickerOpen(false), []);\n const closeFillPicker = useCallback(() => setIsFillPickerOpen(false), []);\n const closeSizePicker = useCallback(() => setIsSizePickerOpen(false), []);\n const closeShapePicker = useCallback(() => setIsShapePickerOpen(false), []);\n const closeFontSizePicker = useCallback(() => setIsFontSizePickerOpen(false), []);\n const closeEraserPicker = useCallback(() => setIsEraserPickerOpen(false), []);\n useOutsideClickAndEscape(colorRefs, isColorPickerOpen, closeColorPicker);\n useOutsideClickAndEscape(fillRefs, isFillPickerOpen, closeFillPicker);\n useOutsideClickAndEscape(sizeRefs, isSizePickerOpen, closeSizePicker);\n useOutsideClickAndEscape(shapeRefs, isShapePickerOpen, closeShapePicker);\n useOutsideClickAndEscape(fontSizeRefs, isFontSizePickerOpen, closeFontSizePicker);\n useOutsideClickAndEscape(eraserRefs, isEraserPickerOpen, closeEraserPicker);\n\n const svgRef = useRef(null);\n const pointsRef = useRef([]);\n const drawingRef = useRef(false);\n const rafRef = useRef(null);\n const [previewPath, setPreviewPath] = useState(null);\n\n // Separate sets for strokes vs. shapes — both kinds are erasable (in\n // either mode), but live in different `props` arrays, so touched ids\n // need to be tracked (and later filtered out) per kind.\n const erasedStrokeIdsRef = useRef(new Set());\n const erasedShapeIdsRef = useRef(new Set());\n // Precise Eraser only: which POINT INDICES within each touched stroke\n // were erased — Object Eraser never touches this, it only ever removes\n // whole strokes/shapes via the two Sets above. Shapes have no per-point\n // path to partially erase, so Precise mode still removes a touched shape\n // whole (via erasedShapeIdsRef, just with the smaller radius) — a\n // deliberate, unavoidable-given-the-data-model scope decision.\n const erasedPointIndicesRef = useRef(new Map());\n const erasingRef = useRef(false);\n const eraseRafRef = useRef(null);\n const [erasingIds, setErasingIds] = useState(() => new Set());\n const [erasingShapeIds, setErasingShapeIds] = useState(() => new Set());\n\n // Shape tools (rectangle/ellipse/arrow): same \"ref buffer during the\n // drag, one commit on pointerup\" discipline as the pen tool, but no rAF\n // throttling is needed here — a shape's live preview is 4-6 numbers, not\n // hundreds of accumulated points, cheap enough to update on every\n // pointermove directly.\n const shapeDraftRef = useRef(null); // { type, x1, y1, x2, y2 } | null\n const [shapeDraftPreview, setShapeDraftPreview] = useState(null);\n\n // Select tool: which strokes/shapes are selected is local, ephemeral UI\n // state, not persisted (same reasoning as `tool`/`view` — an authoring\n // detail, not document content). An id may resolve to either\n // `props.strokes` or `props.shapes` — see `findSelectable` above.\n // `moveDraftRef` mirrors every other gesture's own \"authoritative ref,\n // state only for the visual preview\" split — `dx`/`dy` are mutated\n // directly on every pointermove so `commitMove` always reads the\n // up-to-date total offset synchronously, without waiting on React state\n // to flush.\n const [selectedIds, setSelectedIds] = useState(() => new Set());\n const moveDraftRef = useRef(null); // { ids: string[], startX, startY, dx, dy } | null\n const [moveOverride, setMoveOverride] = useState(null); // { ids: string[], dx, dy } | null\n\n // Marquee (rubber-band) drag: starting a click-drag on empty space\n // selects every stroke/shape whose bounding box intersects the dragged\n // rectangle, replacing the previous selection — an empty-result marquee\n // (e.g. a near-zero-drag click) clears the selection, which is how\n // \"click empty space to deselect\" falls out of this as a special case\n // rather than a separate code path.\n const marqueeDraftRef = useRef(null); // { startX, startY, x, y } | null (local space)\n const [marqueeRect, setMarqueeRect] = useState(null); // {x,y,width,height} | null, local space\n\n // Copy/paste/duplicate (Ctrl/Cmd+C / Ctrl/Cmd+V / Ctrl/Cmd+D): an\n // in-memory clipboard, not the OS clipboard — this editor has no other\n // block that round-trips through the system clipboard for its own\n // internal structured data either (see useClipboardHandlers.js's own\n // text/HTML-only scope), and an internal ref avoids needing\n // `navigator.clipboard` permissions for what's purely an in-block\n // operation. Holds the ORIGINAL (unshifted) items so every repeated paste\n // offsets from the same source, not cumulatively from the last paste.\n const clipboardRef = useRef([]); // Array<{ kind: 'stroke'|'shape', item }>\n\n // Text tool: unlike every other shape, a text box needs a live text-input\n // surface, not just a drag gesture — this local draft holds whatever's\n // currently being typed (a NEW box, or re-editing an EXISTING committed\n // one), rendered as its own <foreignObject><textarea> overlay (see the\n // JSX below), completely separate from the plain, non-editable\n // `<foreignObject><div>` `ShapeElement` renders for every already-\n // committed text shape. Nothing is written to the store until the\n // textarea blurs/commits — same \"local draft, one commit\" discipline as\n // every other tool here.\n const [textEditDraft, setTextEditDraft] = useState(null); // { id: string|null, x, y, width, height, text, color, fontSize } | null — id is null for a brand-new (not-yet-committed) box\n\n // Resize (rectangle/ellipse corner drag) + endpoint-drag (arrow) — same\n // ref-is-authoritative/state-is-preview split as move. `resizeDraftRef`'s\n // `mode` is `'rect-corner'` (`fixedX`/`fixedY` pin the OPPOSITE corner,\n // `x`/`y` track the pointer) or `'arrow-endpoint'` (`endpoint` says which\n // of the two points is being dragged).\n const resizeDraftRef = useRef(null);\n const [resizePreviewShape, setResizePreviewShape] = useState(null);\n\n // Pan/zoom (Phase 5): local view-only state, see the doc comment above —\n // never touches block.props or the store.\n const [view, setView] = useState({ x: 0, y: 0, zoom: 1 });\n const viewSize = VIEW_SIZE / view.zoom;\n const panRef = useRef(null); // { startClientX, startClientY, startViewX, startViewY } | null\n // Two-finger touch pan: every currently-down TOUCH pointer, keyed by its\n // own pointerId -> last known client position — tracked so a second\n // finger landing mid-gesture can compute the two-touch centroid right\n // away, and so a still-down finger's position stays current while the\n // OTHER finger is the one moving. `touchPanRef` (set once 2+ fingers are\n // down) mirrors `panRef` above almost exactly — same view-delta math,\n // just anchored to the two-touch centroid instead of one mouse position\n // — so a two-finger drag pans the exact same `view` state the middle-\n // mouse-drag pan and Ctrl/Cmd+wheel zoom already share. Pinch-zoom itself\n // stays entirely on the existing `handleWheel` path (trackpad AND\n // touchscreen pinch both reach it as a synthesized ctrl+wheel event) —\n // this only adds the PAN gesture that path has no way to express.\n const touchPointsRef = useRef(new Map()); // pointerId -> { x, y } (client coords)\n const touchPanRef = useRef(null); // { startCenterX, startCenterY, startViewX, startViewY } | null\n\n // Resize (Phase 4): existing strokes never need rescaling here — they're\n // authored in the fixed 0..1000 normalized space (see VIEW_SIZE above),\n // completely decoupled from the SVG's own rendered pixel size, so\n // dragging the handle is purely \"change how big this is drawn.\"\n const { dragValue: dragSize, startDrag: startResize } = useDragResize({\n compute: (event, start) => ({\n width: Math.max(\n MIN_CANVAS_WIDTH,\n Math.round(start.startWidth + (event.clientX - start.startX)),\n ),\n height: Math.max(\n MIN_CANVAS_HEIGHT,\n Math.round(start.startHeight + (event.clientY - start.startY)),\n ),\n }),\n onCommit: (size) => store.applyOperation(updateBlockProps(id, size)),\n });\n\n const schedulePreviewUpdate = useCallback((size) => {\n if (rafRef.current != null) return; // already scheduled for this frame — pointermove just adds more points to the same buffer\n rafRef.current = requestAnimationFrame(() => {\n rafRef.current = null;\n setPreviewPath(getStrokeOutlinePath(pointsRef.current, { size }));\n });\n }, []);\n\n const stopDrawing = useCallback(() => {\n drawingRef.current = false;\n if (rafRef.current != null) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n pointsRef.current = [];\n setPreviewPath(null);\n }, []);\n\n const commitStroke = useCallback(() => {\n const points = pointsRef.current;\n if (points.length === 0) return;\n // A tap-without-drag still commits a single-point stroke — getStrokeOutlinePath\n // itself renders a single point as a small filled \"dot\", so no special-casing\n // is needed here beyond just storing whatever points were captured.\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n const newStroke = {\n id: genId(),\n points,\n color,\n size: strokeSize,\n z: nextZIndex(currentStrokes, currentShapes),\n };\n store.applyOperation(updateBlockProps(id, { strokes: [...currentStrokes, newStroke] }));\n }, [store, id, block, color, strokeSize]);\n\n const scheduleErasingPreview = useCallback(() => {\n if (eraseRafRef.current != null) return;\n eraseRafRef.current = requestAnimationFrame(() => {\n eraseRafRef.current = null;\n setErasingIds(new Set(erasedStrokeIdsRef.current));\n setErasingShapeIds(new Set(erasedShapeIdsRef.current));\n });\n }, []);\n\n /**\n * Erases whatever the eraser (radius set by `eraserMode` — see\n * ERASER_RADIUS/ERASER_RADIUS_PRECISE's doc comment) touches. Shapes are\n * always whole-object (a plain bounding-box-vs-eraser-circle test for\n * every type — the same \"click anywhere in the box\" simplification\n * rectangle/ellipse click-select already uses). Strokes differ by mode:\n * Object Eraser marks the WHOLE stroke touched (via the precise\n * per-segment `strokeNearPoint` check, after a cheap bounding-box\n * pre-filter) for a later whole-stroke removal in `commitErase`; Precise\n * Eraser instead marks just the individual POINT INDICES that fall\n * within its (smaller) radius, for a later partial split.\n */\n const hitTestEraserAt = useCallback(\n (x, y) => {\n const radius = eraserMode === 'precise' ? ERASER_RADIUS_PRECISE : ERASER_RADIUS;\n const eraserBox = pointBox(x, y, radius);\n const strokes = block?.props?.strokes ?? [];\n for (const stroke of strokes) {\n if (eraserMode === 'precise') {\n const box = strokeBoundingBox(stroke.points);\n if (!boxesIntersect(box, eraserBox, stroke.size / 2)) continue; // cheap reject before the per-point walk\n let indices = erasedPointIndicesRef.current.get(stroke.id);\n stroke.points.forEach(([px, py], i) => {\n if (indices?.has(i)) return;\n if (Math.hypot(px - x, py - y) > radius) return;\n if (!indices) {\n indices = new Set();\n erasedPointIndicesRef.current.set(stroke.id, indices);\n }\n indices.add(i);\n });\n if (indices?.size) erasedStrokeIdsRef.current.add(stroke.id); // preview-only flag, not a whole-stroke delete in this mode\n continue;\n }\n if (erasedStrokeIdsRef.current.has(stroke.id)) continue;\n const padding = stroke.size / 2;\n const box = strokeBoundingBox(stroke.points);\n if (!boxesIntersect(box, eraserBox, padding)) continue; // cheap reject before the precise per-segment check\n if (strokeNearPoint(stroke, x, y, radius + padding))\n erasedStrokeIdsRef.current.add(stroke.id);\n }\n const shapes = block?.props?.shapes ?? [];\n for (const shape of shapes) {\n if (erasedShapeIdsRef.current.has(shape.id)) continue;\n const box = shapeBoundingBox(shape);\n const shapeBox = {\n minX: box.x,\n minY: box.y,\n maxX: box.x + box.width,\n maxY: box.y + box.height,\n };\n if (boxesIntersect(shapeBox, eraserBox)) erasedShapeIdsRef.current.add(shape.id);\n }\n scheduleErasingPreview();\n },\n [block, eraserMode, scheduleErasingPreview],\n );\n\n const stopErasing = useCallback(() => {\n erasingRef.current = false;\n if (eraseRafRef.current != null) {\n cancelAnimationFrame(eraseRafRef.current);\n eraseRafRef.current = null;\n }\n erasedStrokeIdsRef.current = new Set();\n erasedShapeIdsRef.current = new Set();\n erasedPointIndicesRef.current = new Map();\n setErasingIds(new Set());\n setErasingShapeIds(new Set());\n }, []);\n\n const commitErase = useCallback(() => {\n const hasWholeStrokeErase = eraserMode !== 'precise' && erasedStrokeIdsRef.current.size > 0;\n const hasPartialErase = eraserMode === 'precise' && erasedPointIndicesRef.current.size > 0;\n if (!hasWholeStrokeErase && !hasPartialErase && erasedShapeIdsRef.current.size === 0) return;\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n let nextStrokes;\n if (hasWholeStrokeErase) {\n nextStrokes = currentStrokes.filter((stroke) => !erasedStrokeIdsRef.current.has(stroke.id));\n } else if (hasPartialErase) {\n nextStrokes = [];\n for (const stroke of currentStrokes) {\n const erasedIndices = erasedPointIndicesRef.current.get(stroke.id);\n if (!erasedIndices || erasedIndices.size === 0) {\n nextStrokes.push(stroke);\n continue;\n }\n splitStrokePoints(stroke.points, erasedIndices).forEach((points, i) => {\n nextStrokes.push({ ...stroke, id: i === 0 ? stroke.id : genId(), points });\n });\n }\n } else {\n nextStrokes = currentStrokes;\n }\n // Touching both arrays together (an erase drag can sweep up strokes\n // and shapes alike) is still exactly one undo step.\n store.applyOperation(\n updateBlockProps(id, {\n strokes: nextStrokes,\n shapes: currentShapes.filter((shape) => !erasedShapeIdsRef.current.has(shape.id)),\n }),\n );\n }, [store, id, block, eraserMode]);\n\n const stopShapeDraft = useCallback(() => {\n shapeDraftRef.current = null;\n setShapeDraftPreview(null);\n }, []);\n\n const commitShapeDraft = useCallback(() => {\n const draft = shapeDraftRef.current;\n if (!draft) return;\n // A click-without-drag draws nothing (a zero-size rectangle/ellipse or a\n // zero-length arrow is a pointless, invisible shape) — same \"no-op is\n // fine\" choice the resize handle makes for a non-drag click, distinct\n // from the pen tool's own tap-still-draws-a-dot behavior, since a dot\n // is a real intentional mark and a degenerate shape is not.\n if (draft.type === 'arrow') {\n if (draft.x1 === draft.x2 && draft.y1 === draft.y2) return;\n } else {\n const rect = normalizeRect(draft.x1, draft.y1, draft.x2, draft.y2);\n if (rect.width === 0 || rect.height === 0) return;\n }\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n const newShape = {\n id: genId(),\n ...buildDraftShape(draft, color, strokeSize, fill),\n z: nextZIndex(currentStrokes, currentShapes),\n };\n store.applyOperation(updateBlockProps(id, { shapes: [...currentShapes, newShape] }));\n }, [store, id, block, color, strokeSize, fill]);\n\n const stopMove = useCallback(() => {\n moveDraftRef.current = null;\n setMoveOverride(null);\n }, []);\n\n const commitMove = useCallback(() => {\n const draft = moveDraftRef.current;\n if (!draft) return;\n if (draft.dx === 0 && draft.dy === 0) return; // a click-without-drag on an already-selected item is just a (re-)selection, nothing to commit\n const idSet = new Set(draft.ids);\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n const nextStrokes = currentStrokes.map((stroke) =>\n idSet.has(stroke.id) ? applyStrokeOffset(stroke, draft.dx, draft.dy) : stroke,\n );\n const nextShapes = currentShapes.map((shape) =>\n idSet.has(shape.id) ? applyShapeOffset(shape, draft.dx, draft.dy) : shape,\n );\n // Touching both arrays together (a selection can span strokes and\n // shapes) is still exactly one undo step — updateBlockProps already\n // shallow-merges multiple prop keys from a single op.\n store.applyOperation(updateBlockProps(id, { strokes: nextStrokes, shapes: nextShapes }));\n }, [store, id, block]);\n\n const stopMarquee = useCallback(() => {\n marqueeDraftRef.current = null;\n setMarqueeRect(null);\n }, []);\n\n const commitMarquee = useCallback(() => {\n const draft = marqueeDraftRef.current;\n if (!draft) return;\n const rect = normalizeRect(draft.startX, draft.startY, draft.x, draft.y);\n // A near-zero drag is a plain click, not a rubber-band selection — treat\n // it as \"clicked empty space\" (clear the selection) rather than running\n // a bounding-box intersection test, which would wrongly catch whatever\n // bounding box the click point happens to fall inside even when the\n // precise click-select hit-test (hitTestSelectableAt) already said no\n // (e.g. inside a diamond's bounding box corner but outside the diamond\n // itself).\n if (rect.width < MARQUEE_MIN_DRAG && rect.height < MARQUEE_MIN_DRAG) {\n setSelectedIds(new Set());\n return;\n }\n const marqueeBox = {\n minX: rect.x,\n minY: rect.y,\n maxX: rect.x + rect.width,\n maxY: rect.y + rect.height,\n };\n const strokes = block?.props?.strokes ?? [];\n const shapes = block?.props?.shapes ?? [];\n const hitIds = [];\n for (const stroke of strokes) {\n if (boxesIntersect(strokeBoundingBox(stroke.points), marqueeBox)) hitIds.push(stroke.id);\n }\n for (const shape of shapes) {\n const box = shapeBoundingBox(shape);\n const shapeBox = {\n minX: box.x,\n minY: box.y,\n maxX: box.x + box.width,\n maxY: box.y + box.height,\n };\n if (boxesIntersect(shapeBox, marqueeBox)) hitIds.push(shape.id);\n }\n setSelectedIds(new Set(hitIds)); // replaces the previous selection; an empty result clears it\n }, [block]);\n\n const copySelection = useCallback(() => {\n if (selectedIds.size === 0) return;\n clipboardRef.current = [...selectedIds]\n .map((selId) => findSelectable(block, selId))\n .filter(Boolean);\n }, [block, selectedIds]);\n\n /**\n * Inserts one fresh (regenerated-id, offset-by-PASTE_OFFSET) copy of\n * every clipboard entry, in one `updateBlockProps` call spanning both\n * arrays — a paste of a mixed stroke+shape selection is still one undo\n * step, same discipline as group move/delete. The new copies become the\n * selection, so an immediate drag can reposition them, and the tool\n * switches to `select` so that drag is available regardless of whichever\n * tool was active when paste/duplicate was pressed.\n */\n const pasteClipboard = useCallback(() => {\n const items = clipboardRef.current;\n if (items.length === 0) return;\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n // Pasted copies always land on top of everything already on the canvas\n // (nextZIndex, bumped once per item so the pasted group also keeps its\n // OWN relative stacking order among each other).\n let nextZ = nextZIndex(currentStrokes, currentShapes);\n const newStrokes = [];\n const newShapes = [];\n const newIds = [];\n for (const { kind, item } of items) {\n const newId = genId();\n newIds.push(newId);\n const z = nextZ;\n nextZ += 1;\n if (kind === 'stroke') {\n newStrokes.push({ ...applyStrokeOffset(item, PASTE_OFFSET, PASTE_OFFSET), id: newId, z });\n } else {\n newShapes.push({ ...applyShapeOffset(item, PASTE_OFFSET, PASTE_OFFSET), id: newId, z });\n }\n }\n store.applyOperation(\n updateBlockProps(id, {\n strokes: [...currentStrokes, ...newStrokes],\n shapes: [...currentShapes, ...newShapes],\n }),\n );\n setSelectedIds(new Set(newIds));\n setTool('select');\n }, [store, id, block]);\n\n /**\n * Z-order (front/back): strokes and shapes share one interleaved stacking\n * order (see zOrder.js) — this stamps a fresh, consecutive `z` on every\n * selected item, all above (front) or below (back) everything else on the\n * canvas, in whatever bottom-to-top order the selected items themselves\n * were already in — the standard \"bring to front\"/\"send to back\"\n * behavior for a multi-item selection, now spanning strokes and shapes\n * alike instead of each kind's own array independently.\n */\n const reorderSelection = useCallback(\n (toFront) => {\n if (selectedIds.size === 0) return;\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n const selectedStrokes = currentStrokes.filter((item) => selectedIds.has(item.id));\n const selectedShapes = currentShapes.filter((item) => selectedIds.has(item.id));\n const selectedOrdered = orderedDrawables(selectedStrokes, selectedShapes);\n if (selectedOrdered.length === 0) return;\n const baseZ = toFront\n ? nextZIndex(currentStrokes, currentShapes)\n : minZIndex(currentStrokes, currentShapes) - selectedOrdered.length;\n const zById = new Map(selectedOrdered.map(({ item }, i) => [item.id, baseZ + i]));\n const stampZ = (item) => (zById.has(item.id) ? { ...item, z: zById.get(item.id) } : item);\n store.applyOperation(\n updateBlockProps(id, {\n strokes: currentStrokes.map(stampZ),\n shapes: currentShapes.map(stampZ),\n }),\n );\n },\n [store, id, block, selectedIds],\n );\n\n const handleBringToFront = useCallback(() => reorderSelection(true), [reorderSelection]);\n const handleSendToBack = useCallback(() => reorderSelection(false), [reorderSelection]);\n\n /** Opens the text-edit overlay for a brand-new box at `(x, y)`. */\n const startNewTextEdit = useCallback(\n (x, y) => {\n setTextEditDraft({\n id: null,\n x,\n y,\n width: DEFAULT_TEXT_WIDTH,\n height: DEFAULT_TEXT_HEIGHT,\n text: '',\n color,\n fontSize: textFontSize,\n });\n },\n [color, textFontSize],\n );\n\n /** Re-opens the text-edit overlay for an already-committed text shape, preserving its box/color/font. */\n const startExistingTextEdit = useCallback((shape) => {\n setTextEditDraft({\n id: shape.id,\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n text: shape.text,\n color: shape.color,\n fontSize: shape.fontSize ?? DEFAULT_TEXT_FONT_SIZE,\n });\n }, []);\n\n const cancelTextEdit = useCallback(() => {\n setTextEditDraft(null);\n }, []);\n\n /**\n * Commits the current text draft: empty text is treated as \"nothing to\n * keep\" — a brand-new box is simply discarded (same \"a click-without-\n * content draws nothing\" convention every other shape tool uses for a\n * degenerate result), and an existing box that's been fully cleared is\n * DELETED rather than left behind as an empty husk. Non-empty text\n * upserts one shape (new id for a new box, same id + unchanged box/color\n * for an edit) in one `updateBlockProps` call, selects it, and returns to\n * the select tool — same \"the result becomes the selection, tool reverts\n * to select\" convention paste/duplicate already use.\n */\n const commitTextEdit = useCallback(() => {\n const draft = textEditDraft;\n if (!draft) return;\n setTextEditDraft(null);\n const currentShapes = block?.props?.shapes ?? [];\n const text = draft.text;\n if (!text.trim()) {\n if (draft.id) {\n store.applyOperation(\n updateBlockProps(id, { shapes: currentShapes.filter((shape) => shape.id !== draft.id) }),\n );\n setSelectedIds(new Set());\n }\n // Restores real DOM focus to the <svg> now that the textarea (which\n // held it) is about to unmount — without this, Delete/nudge/Enter-\n // to-re-edit/... would all silently do nothing right after finishing\n // a text edit, since none of those keydown handlers fire unless the\n // svg itself has focus.\n svgRef.current?.focus();\n return;\n }\n const shapeId = draft.id ?? genId();\n const nextShape = {\n id: shapeId,\n type: 'text',\n x: draft.x,\n y: draft.y,\n width: draft.width,\n height: draft.height,\n text,\n color: draft.color,\n fontSize: draft.fontSize,\n };\n const nextShapes = draft.id\n ? currentShapes.map((shape) => (shape.id === draft.id ? nextShape : shape))\n : [...currentShapes, nextShape];\n store.applyOperation(updateBlockProps(id, { shapes: nextShapes }));\n setSelectedIds(new Set([shapeId]));\n // handlePointerDown's own \"clicked away while still in the text tool\"\n // guard sets `tool` straight back to 'text' right after triggering\n // this (via blur) when it wants to keep placing more boxes — since\n // both updates land in the same batch, that later call simply wins.\n setTool('select');\n svgRef.current?.focus(); // see the doc comment on the early-return branch above\n }, [store, id, block, textEditDraft]);\n\n const stopResize = useCallback(() => {\n resizeDraftRef.current = null;\n setResizePreviewShape(null);\n }, []);\n\n const commitResize = useCallback(() => {\n const draft = resizeDraftRef.current;\n if (!draft) return;\n const currentShapes = block?.props?.shapes ?? [];\n const original = currentShapes.find((shape) => shape.id === draft.shapeId);\n if (!original) return;\n const resized = buildResizedShape(original, draft);\n // Dragging a rectangle/ellipse corner onto (or past) its opposite\n // corner would otherwise commit a degenerate zero-size shape — skip,\n // same \"no-op is fine\" choice a zero-drag draw already makes.\n if (resized.type !== 'arrow' && (resized.width === 0 || resized.height === 0)) return;\n const nextShapes = currentShapes.map((shape) => (shape.id === draft.shapeId ? resized : shape));\n store.applyOperation(updateBlockProps(id, { shapes: nextShapes }));\n }, [store, id, block]);\n\n /**\n * Discards whichever single-pointer gesture (draw/erase/shape-draft/move/\n * marquee/resize) the given (first) touch pointer had already started,\n * without committing it — called the instant a SECOND finger touches\n * down mid-gesture, so touch transitions straight into a two-finger pan\n * instead of also leaving behind a stray in-progress stroke/drag from\n * the first finger alone.\n */\n const cancelActiveSingleGesture = useCallback(\n (pointerId) => {\n const svg = svgRef.current;\n if (svg?.hasPointerCapture?.(pointerId)) svg.releasePointerCapture(pointerId);\n if (shapeDraftRef.current) {\n stopShapeDraft();\n return;\n }\n if (moveDraftRef.current) {\n stopMove();\n return;\n }\n if (marqueeDraftRef.current) {\n stopMarquee();\n return;\n }\n if (resizeDraftRef.current) {\n stopResize();\n return;\n }\n if (drawingRef.current) {\n stopDrawing();\n return;\n }\n if (erasingRef.current) {\n stopErasing();\n }\n },\n [stopShapeDraft, stopMove, stopMarquee, stopResize, stopDrawing, stopErasing],\n );\n\n // Delete/Backspace removes the selection; arrow keys nudge it by\n // NUDGE_STEP (Shift+arrow by NUDGE_STEP_LARGE); Enter re-opens the\n // text-edit overlay for a selected text shape; Ctrl/Cmd+C/V copy/paste\n // the selection through an in-block clipboard (see clipboardRef above);\n // Ctrl/Cmd+D duplicates it directly (copy + paste in one keystroke, no\n // separate clipboard step); Ctrl/Cmd+Shift+]/[ bring the selection to\n // front/send it to back. Verified against\n // src/react/useEditorKeyboardShortcuts.js: its global native keydown\n // handler only acts on Backspace/Delete when a whole BLOCK is selected\n // (getSelectedBlockId(), which this canvas never sets) or a real\n // cross-block *text* selection resolves (resolveCrossBlockSelection,\n // which an SVG has none of), and never inspects 'c'/'v'/'d'/']'/'[' at\n // all — with neither true, that handler does nothing, so this plain\n // keydown scoped to the <svg> itself is safe without any\n // stopPropagation/interference concerns. The <svg> needs real DOM focus\n // for this to fire at all — see handlePointerDown's select-tool branch,\n // which calls `.focus()` the moment an item becomes selected.\n const handleKeyDown = useCallback(\n (event) => {\n if (event.key === 'Backspace' || event.key === 'Delete') {\n if (selectedIds.size === 0) return;\n event.preventDefault();\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n // A selection can span both kinds — removing both arrays' matches in\n // one op keeps the whole delete a single undo step.\n store.applyOperation(\n updateBlockProps(id, {\n strokes: currentStrokes.filter((stroke) => !selectedIds.has(stroke.id)),\n shapes: currentShapes.filter((shape) => !selectedIds.has(shape.id)),\n }),\n );\n setSelectedIds(new Set());\n return;\n }\n if (NUDGE_DELTAS[event.key] && !event.ctrlKey && !event.metaKey) {\n if (selectedIds.size === 0) return;\n event.preventDefault();\n const step = event.shiftKey ? NUDGE_STEP_LARGE : NUDGE_STEP;\n const [dirX, dirY] = NUDGE_DELTAS[event.key];\n const dx = dirX * step;\n const dy = dirY * step;\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n store.applyOperation(\n updateBlockProps(id, {\n strokes: currentStrokes.map((stroke) =>\n selectedIds.has(stroke.id) ? applyStrokeOffset(stroke, dx, dy) : stroke,\n ),\n shapes: currentShapes.map((shape) =>\n selectedIds.has(shape.id) ? applyShapeOffset(shape, dx, dy) : shape,\n ),\n }),\n );\n return;\n }\n if (event.key === 'Enter' && !event.ctrlKey && !event.metaKey) {\n // Re-opens the text-edit overlay for a selected text shape — the\n // \"select it, press Enter to edit\" convention (same one Figma\n // uses), since there's no double-click detection in this pass.\n if (selectedIds.size !== 1) return;\n const [selId] = selectedIds;\n const shape = (block?.props?.shapes ?? []).find((s) => s.id === selId && s.type === 'text');\n if (!shape) return;\n event.preventDefault();\n startExistingTextEdit(shape);\n return;\n }\n const mod = event.ctrlKey || event.metaKey;\n if (!mod) return;\n const key = event.key.toLowerCase();\n if (key === 'c') {\n if (selectedIds.size === 0) return;\n event.preventDefault();\n copySelection();\n } else if (key === 'v') {\n if (clipboardRef.current.length === 0) return;\n event.preventDefault();\n pasteClipboard();\n } else if (key === 'd') {\n if (selectedIds.size === 0) return;\n event.preventDefault();\n copySelection();\n pasteClipboard();\n } else if (event.shiftKey && (key === ']' || key === '[')) {\n // Ctrl/Cmd+Shift+]/[ — the common \"bring to front\"/\"send to back\"\n // shortcut convention (Figma, Illustrator, ...); also reachable via\n // the toolbar's own buttons.\n if (selectedIds.size === 0) return;\n event.preventDefault();\n reorderSelection(key === ']');\n }\n },\n [\n store,\n id,\n block,\n selectedIds,\n copySelection,\n pasteClipboard,\n reorderSelection,\n startExistingTextEdit,\n ],\n );\n\n const currentView = { x: view.x, y: view.y, size: viewSize };\n\n const handleWheel = useCallback(\n (event) => {\n const svg = svgRef.current;\n if (!svg) return;\n event.preventDefault();\n if (event.ctrlKey || event.metaKey) {\n // Ctrl/Cmd+wheel — also how a trackpad OR touchscreen pinch gesture\n // reports itself — zooms the canvas.\n setView((prev) => {\n const zoomFactor = event.deltaY < 0 ? ZOOM_STEP : 1 / ZOOM_STEP;\n const nextZoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, prev.zoom * zoomFactor));\n const nextSize = VIEW_SIZE / nextZoom;\n // keep the point under the cursor fixed on screen as the zoom changes\n const { x, y } = zoomAnchoredView(\n event,\n svg,\n { x: prev.x, y: prev.y, size: VIEW_SIZE / prev.zoom },\n nextSize,\n );\n return { ...clampViewOffset(x, y, nextSize, VIEW_SIZE), zoom: nextZoom };\n });\n return;\n }\n // A plain wheel (no ctrl/meta) is most commonly a trackpad's\n // two-finger scroll gesture (deltaX/deltaY) — pan the canvas view\n // with it instead of letting it scroll the surrounding page, the\n // same \"this block owns wheel input\" choice the zoom branch above\n // already makes.\n const scale = localPixelScale(svg, viewSize);\n setView((prev) => ({\n ...prev,\n ...clampViewOffset(\n prev.x + event.deltaX / scale,\n prev.y + event.deltaY / scale,\n viewSize,\n VIEW_SIZE,\n ),\n }));\n },\n [viewSize],\n );\n\n // React registers `wheel` (like `touchstart`/`touchmove`) as a PASSIVE\n // listener at the root by default, a deliberate perf decision so\n // scrolling is never blocked by JS — `event.preventDefault()` inside a\n // passive listener is silently a no-op. That meant Ctrl/Cmd+wheel here\n // was zooming the canvas but ALSO zooming the whole browser page, since\n // the JSX `onWheel` prop's preventDefault never actually took effect. A\n // real native listener (added imperatively, same pattern as\n // EditableBlockContent.jsx's own `beforeinput` listener, for the same\n // \"React's synthetic system doesn't give the needed control\" reason)\n // isn't forced passive by the browser for `wheel` — only `touchstart`/\n // `touchmove` get that browser-level default — so this fixes it.\n useEffect(() => {\n const svg = svgRef.current;\n if (!svg) return undefined;\n svg.addEventListener('wheel', handleWheel, { passive: false });\n return () => svg.removeEventListener('wheel', handleWheel);\n }, [handleWheel]);\n\n const handleZoomIn = useCallback(() => {\n setView((prev) => {\n const nextZoom = Math.min(MAX_ZOOM, prev.zoom * ZOOM_STEP);\n const nextSize = VIEW_SIZE / nextZoom;\n const { x, y } = zoomCenteredView(\n { x: prev.x, y: prev.y, size: VIEW_SIZE / prev.zoom },\n nextSize,\n );\n return { ...clampViewOffset(x, y, nextSize, VIEW_SIZE), zoom: nextZoom };\n });\n }, []);\n\n const handleZoomOut = useCallback(() => {\n setView((prev) => {\n const nextZoom = Math.max(MIN_ZOOM, prev.zoom / ZOOM_STEP);\n const nextSize = VIEW_SIZE / nextZoom;\n const { x, y } = zoomCenteredView(\n { x: prev.x, y: prev.y, size: VIEW_SIZE / prev.zoom },\n nextSize,\n );\n return { ...clampViewOffset(x, y, nextSize, VIEW_SIZE), zoom: nextZoom };\n });\n }, []);\n\n const handleZoomReset = useCallback(() => {\n setView({ x: 0, y: 0, zoom: 1 });\n }, []);\n\n /**\n * Exports the current drawing as a downloaded PNG file — rasterizes\n * `buildCanvasSVGMarkup`'s own output (the exact same markup `toHTML`\n * embeds into exported document HTML, see exportSvg.js) by loading it\n * into an `Image` and drawing that onto an offscreen `<canvas>`, at the\n * block's own `width`/`height` (not the fixed 1000x1000 logical space —\n * that's just the SVG's `viewBox`, scaled to fit `width`/`height` exactly\n * like the live component already renders it).\n *\n * Deliberately avoids `Blob`/`URL.createObjectURL` for the SVG-to-Image\n * step — a plain `data:image/svg+xml,...` URI (built with\n * `encodeURIComponent`, which is UTF-8 safe, unlike `btoa` which throws\n * on any non-Latin1 character a typed text box could easily contain) has\n * fewer moving parts and is supported essentially everywhere, including\n * environments where `URL.createObjectURL` might not be. Likewise uses\n * `canvas.toDataURL` (synchronous, universally supported) rather than\n * the async `canvas.toBlob`, and appends the download `<a>` to the\n * document before calling `.click()` — some browsers (notably Firefox)\n * don't reliably trigger a `download`-attribute save from a detached,\n * never-inserted anchor.\n *\n * This whole pipeline is genuinely browser-only: jsdom (the test\n * environment) has no real `<canvas>` 2D context, so `ctx` below comes\n * back null there, and no real `Image` decoding, so `onload` never\n * fires — both make a test that clicks this button a safe no-op rather\n * than a crash, at the cost of the actual rasterization itself not being\n * exercised by the test suite (the pure `buildCanvasSVGMarkup`\n * markup-building logic is what's unit-tested instead).\n */\n const handleExportPNG = useCallback(() => {\n if (!block) return;\n const svgMarkup = buildCanvasSVGMarkup(block);\n const svgDataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgMarkup)}`;\n const img = new Image();\n img.onload = () => {\n const exportCanvas = document.createElement('canvas');\n exportCanvas.width = block.props.width;\n exportCanvas.height = block.props.height;\n const ctx = exportCanvas.getContext('2d');\n if (!ctx) return;\n ctx.drawImage(img, 0, 0, exportCanvas.width, exportCanvas.height);\n const link = document.createElement('a');\n link.href = exportCanvas.toDataURL('image/png');\n link.download = 'canvas.png';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n };\n img.src = svgDataUrl;\n }, [block]);\n\n /**\n * Double-clicking a text shape re-opens its edit overlay — the standard,\n * discoverable way most editors expect (Enter-on-a-selected-text-shape,\n * wired in handleKeyDown, still works too, as a keyboard-only\n * alternative). Uses the native `dblclick` event rather than manually\n * tracking click timing/position — the browser already does that\n * correctly, including canceling itself on drags, and there's no\n * meaningful risk of firing this by accident during any of this\n * component's own drag gestures, all of which are driven by\n * pointerdown/pointermove/pointerup rather than click/dblclick.\n */\n const handleDoubleClick = useCallback(\n (event) => {\n if (tool !== 'select') return;\n const svg = svgRef.current;\n if (!svg) return;\n const [x, y] = clientToLocal(event, svg, { x: view.x, y: view.y, size: viewSize });\n const shapes = block?.props?.shapes ?? [];\n const hitId = hitTestShapeAt(x, y, shapes);\n const shape = shapes.find((s) => s.id === hitId);\n if (shape?.type !== 'text') return;\n setSelectedIds(new Set([shape.id]));\n startExistingTextEdit(shape);\n },\n [tool, view.x, view.y, viewSize, block, startExistingTextEdit],\n );\n\n const handlePointerDown = useCallback(\n (event) => {\n const svg = svgRef.current;\n if (!svg) return;\n\n if (event.pointerType === 'touch') {\n touchPointsRef.current.set(event.pointerId, { x: event.clientX, y: event.clientY });\n if (touchPointsRef.current.size >= 2) {\n // A second finger landing mid-gesture: switch straight into a\n // two-finger pan, discarding whatever the first finger alone had\n // already started (see cancelActiveSingleGesture).\n event.preventDefault();\n svg.setPointerCapture?.(event.pointerId);\n if (!touchPanRef.current) {\n for (const pointerId of touchPointsRef.current.keys()) {\n if (pointerId !== event.pointerId) cancelActiveSingleGesture(pointerId);\n }\n const center = touchCentroid(touchPointsRef.current);\n touchPanRef.current = {\n startCenterX: center.x,\n startCenterY: center.y,\n startViewX: view.x,\n startViewY: view.y,\n };\n }\n return;\n }\n }\n\n if (textEditDraft) {\n // A pointerdown landing on the textarea ITSELF (repositioning the\n // cursor, selecting text while typing) is normal editing\n // interaction, not \"clicked away\" — let the browser handle it,\n // skip all tool logic below entirely.\n if (event.target?.closest?.('.be-canvas-text-editor')) return;\n // Anything else landing on this <svg> means the user clicked away\n // from an in-progress text edit. This can't be left to the\n // textarea's own onBlur to happen naturally on its own timing:\n // `pointerdown` (and this handler) fires BEFORE the browser's\n // mousedown-triggered blur/focus-change default action, so without\n // forcing the blur here FIRST, whatever this pointerdown is about\n // to do below (start a new text box, select a shape, start\n // drawing, ...) would run first and the in-progress edit's typed\n // text would be silently discarded instead of committed — the bug\n // this guard exists to prevent. Blurring synchronously (rather\n // than calling commitTextEdit directly here too) routes through\n // the textarea's own onBlur so there's exactly one commit path,\n // not two that could double-fire and create a duplicate shape.\n document.activeElement?.blur?.();\n if (tool === 'text') {\n // Immediately place the next box at this same click rather than\n // falling through to the branches below, which would otherwise\n // still be dispatching this same pointerdown against the OLD\n // (pre-commit) state. The blur above already committed the\n // previous box and set `tool` to 'select' (see commitTextEdit) —\n // setting it back to 'text' keeps the tool active for placing\n // further boxes in one continuous flow.\n let [textX, textY] = clientToLocal(event, svg, currentView);\n if (snapEnabled) [textX, textY] = [snapValue(textX), snapValue(textY)];\n startNewTextEdit(textX, textY);\n setTool('text');\n return;\n }\n }\n\n if (event.button === 1) {\n // Middle-mouse-button drag pans, regardless of the currently active\n // tool — a plain, always-available gesture (see the component doc\n // comment for why this was chosen over a space-bar-held convention).\n event.preventDefault();\n svg.setPointerCapture?.(event.pointerId);\n panRef.current = {\n startClientX: event.clientX,\n startClientY: event.clientY,\n startViewX: view.x,\n startViewY: view.y,\n };\n return;\n }\n if (!event.isPrimary || (event.button !== undefined && event.button !== 0)) return;\n\n event.preventDefault();\n // Optional chaining: SVG pointer capture isn't universally implemented\n // (notably missing in jsdom, and historically inconsistent in some\n // browsers) — drawing/erasing still works without it, just without the\n // \"keeps tracking outside the element bounds\" guarantee.\n svg.setPointerCapture?.(event.pointerId);\n const [x, y] = clientToLocal(event, svg, currentView);\n\n if (tool === 'eraser') {\n erasedStrokeIdsRef.current = new Set();\n erasedShapeIdsRef.current = new Set();\n erasedPointIndicesRef.current = new Map();\n erasingRef.current = true;\n hitTestEraserAt(x, y); // a click-without-drag still erases whatever's right under it\n } else if (SHAPE_TOOLS.has(tool)) {\n const startX = snapEnabled ? snapValue(x) : x;\n const startY = snapEnabled ? snapValue(y) : y;\n shapeDraftRef.current = { type: tool, x1: startX, y1: startY, x2: startX, y2: startY };\n setShapeDraftPreview(buildDraftShape(shapeDraftRef.current, color, strokeSize, fill));\n } else if (tool === 'select') {\n const strokesList = block?.props?.strokes ?? [];\n const shapesList = block?.props?.shapes ?? [];\n // Resize/endpoint handles are single-selection-only, and only for a\n // shape (strokes were never resizable) — see the component doc\n // comment.\n const singleSelectedShape =\n selectedIds.size === 1\n ? (shapesList.find((shape) => selectedIds.has(shape.id)) ?? null)\n : null;\n const handle = hitTestHandle(x, y, singleSelectedShape);\n if (handle) {\n // Grabbing a handle always takes priority over re-selecting/moving\n // the shape it belongs to.\n if (handle === 'rotate') {\n const { cx, cy } = shapeCenter(singleSelectedShape);\n // The pointer's own angle from the shape's center, at drag\n // start — every subsequent pointermove compares its own angle\n // against this to get a rotation DELTA, added onto the\n // shape's rotation at drag start (not overwritten), so\n // starting a new rotate drag from an already-rotated shape\n // continues from there rather than snapping.\n const startAngle = (Math.atan2(y - cy, x - cx) * 180) / Math.PI;\n resizeDraftRef.current = {\n mode: 'rotate',\n shapeId: singleSelectedShape.id,\n cx,\n cy,\n startAngle,\n startRotation: singleSelectedShape.rotation ?? 0,\n rotation: singleSelectedShape.rotation ?? 0,\n };\n } else if (singleSelectedShape.type === 'arrow') {\n resizeDraftRef.current = {\n mode: 'arrow-endpoint',\n shapeId: singleSelectedShape.id,\n endpoint: handle,\n x,\n y,\n };\n } else {\n const [fixedX, fixedY] = rectCorners(singleSelectedShape)[OPPOSITE_CORNER[handle]];\n resizeDraftRef.current = {\n mode: 'rect-corner',\n shapeId: singleSelectedShape.id,\n fixedX,\n fixedY,\n x,\n y,\n };\n }\n setResizePreviewShape(buildResizedShape(singleSelectedShape, resizeDraftRef.current));\n return;\n }\n const hit = hitTestSelectableAt(x, y, strokesList, shapesList);\n if (hit) {\n if (event.shiftKey) {\n // Shift+click only toggles membership — a deliberate plain\n // click-drag afterward is needed to move the adjusted selection.\n setSelectedIds((prev) => {\n const next = new Set(prev);\n if (next.has(hit.id)) next.delete(hit.id);\n else next.add(hit.id);\n return next;\n });\n return;\n }\n // Clicking an already-selected item starts a group move of the\n // WHOLE current selection; clicking a not-yet-selected item\n // collapses selection to just that one first — group-move-of-1 is\n // the same code path. Either way this both selects AND\n // immediately starts a move drag in the same gesture, the\n // standard \"click-drag to move\" convention.\n const nextIds = selectedIds.has(hit.id) ? selectedIds : new Set([hit.id]);\n setSelectedIds(nextIds);\n moveDraftRef.current = { ids: [...nextIds], startX: x, startY: y, dx: 0, dy: 0 };\n svg.focus(); // real DOM focus so handleKeyDown's own Delete/Backspace can fire\n } else {\n // Empty space: start a marquee drag instead of immediately\n // clearing the selection — an empty-result marquee clears it on\n // release (see commitMarquee), preserving that behavior as a\n // special case.\n marqueeDraftRef.current = { startX: x, startY: y, x, y };\n }\n } else if (tool === 'text') {\n // A click-drag isn't needed to size a text box (unlike the other\n // shape tools) — it starts at a fixed default size, resizable\n // afterward like any other shape — so pointerdown alone is enough\n // to open the edit overlay; there's no shapeDraftRef drag to track.\n startNewTextEdit(snapEnabled ? snapValue(x) : x, snapEnabled ? snapValue(y) : y);\n } else if (tool === 'pen') {\n pointsRef.current = [[x, y, event.pressure || 0.5]];\n drawingRef.current = true;\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n tool,\n hitTestEraserAt,\n view.x,\n view.y,\n viewSize,\n color,\n strokeSize,\n fill,\n snapEnabled,\n block,\n selectedIds,\n startNewTextEdit,\n textEditDraft,\n cancelActiveSingleGesture,\n ],\n );\n\n const handlePointerMove = useCallback(\n (event) => {\n const svg = svgRef.current;\n if (!svg) return;\n\n if (event.pointerType === 'touch' && touchPointsRef.current.has(event.pointerId)) {\n touchPointsRef.current.set(event.pointerId, { x: event.clientX, y: event.clientY });\n if (touchPanRef.current) {\n event.preventDefault();\n const scale = localPixelScale(svg, viewSize);\n const center = touchCentroid(touchPointsRef.current);\n const { startCenterX, startCenterY, startViewX, startViewY } = touchPanRef.current;\n const dx = (center.x - startCenterX) / scale;\n const dy = (center.y - startCenterY) / scale;\n // startViewX/startViewY are captured above (not read from the ref\n // inside this updater) — several of these events can be queued\n // within the same React batch, and touchPanRef.current may\n // already have been reset to null by a LATER pointerup/pointer-\n // cancel by the time this updater actually runs.\n setView((prev) => ({\n ...prev,\n ...clampViewOffset(startViewX - dx, startViewY - dy, viewSize, VIEW_SIZE),\n }));\n return;\n }\n }\n\n if (panRef.current) {\n // Same letterbox-aware scale clientToLocal uses (see canvasGeometry.js) —\n // a delta only needs the shared scale factor, not the absolute view.x/y offset.\n const scale = localPixelScale(svg, viewSize);\n const { startClientX, startClientY, startViewX, startViewY } = panRef.current;\n const dx = (event.clientX - startClientX) / scale;\n const dy = (event.clientY - startClientY) / scale;\n // startViewX/startViewY are captured above rather than read from\n // the ref inside this updater — a queued functional setView update\n // runs later, by which point panRef.current could already have\n // been reset to null by a subsequent pointerup/pointercancel\n // dispatched within the same batch (see the identical touch-pan\n // fix above, where this exact lazy-read pattern crashed).\n setView((prev) => ({\n ...prev,\n ...clampViewOffset(startViewX - dx, startViewY - dy, viewSize, VIEW_SIZE),\n }));\n return;\n }\n if (shapeDraftRef.current) {\n let [x, y] = clientToLocal(event, svg, currentView);\n if (snapEnabled) [x, y] = [snapValue(x), snapValue(y)];\n shapeDraftRef.current = { ...shapeDraftRef.current, x2: x, y2: y };\n setShapeDraftPreview(buildDraftShape(shapeDraftRef.current, color, strokeSize, fill));\n return;\n }\n if (moveDraftRef.current) {\n const [x, y] = clientToLocal(event, svg, currentView);\n const draft = moveDraftRef.current;\n // Snaps the DELTA itself (not an absolute position — ambiguous for\n // a multi-item group, each with its own origin) to the grid, so a\n // drag's movement is quantized to grid-sized steps rather than\n // landing any particular item exactly on a grid line.\n draft.dx = snapEnabled ? snapValue(x - draft.startX) : x - draft.startX;\n draft.dy = snapEnabled ? snapValue(y - draft.startY) : y - draft.startY;\n setMoveOverride({ ids: draft.ids, dx: draft.dx, dy: draft.dy });\n return;\n }\n if (marqueeDraftRef.current) {\n const [x, y] = clientToLocal(event, svg, currentView);\n const draft = marqueeDraftRef.current;\n draft.x = x;\n draft.y = y;\n setMarqueeRect(normalizeRect(draft.startX, draft.startY, draft.x, draft.y));\n return;\n }\n if (resizeDraftRef.current) {\n let [x, y] = clientToLocal(event, svg, currentView);\n const draft = resizeDraftRef.current;\n if (draft.mode === 'rotate') {\n const currentAngle = (Math.atan2(y - draft.cy, x - draft.cx) * 180) / Math.PI;\n const rawRotation = draft.startRotation + (currentAngle - draft.startAngle);\n draft.rotation = snapEnabled ? snapAngle(rawRotation) : rawRotation;\n } else {\n // A single point (a resize corner or arrow endpoint) snapping to\n // the grid, unlike a group move's delta, unambiguously means\n // \"land exactly on a grid line.\"\n if (snapEnabled) [x, y] = [snapValue(x), snapValue(y)];\n draft.x = x;\n draft.y = y;\n }\n const shapes = block?.props?.shapes ?? [];\n const original = shapes.find((shape) => shape.id === draft.shapeId);\n if (original) setResizePreviewShape(buildResizedShape(original, draft));\n return;\n }\n if (drawingRef.current) {\n const [x, y] = clientToLocal(event, svg, currentView);\n pointsRef.current.push([x, y, event.pressure || 0.5]);\n schedulePreviewUpdate(strokeSize);\n } else if (erasingRef.current) {\n const [x, y] = clientToLocal(event, svg, currentView);\n hitTestEraserAt(x, y);\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n schedulePreviewUpdate,\n hitTestEraserAt,\n view.x,\n view.y,\n viewSize,\n strokeSize,\n color,\n fill,\n snapEnabled,\n block,\n ],\n );\n\n const releaseCapture = useCallback((event) => {\n const svg = svgRef.current;\n if (svg?.hasPointerCapture?.(event.pointerId)) svg.releasePointerCapture(event.pointerId);\n }, []);\n\n const handlePointerUp = useCallback(\n (event) => {\n if (event.pointerType === 'touch') {\n touchPointsRef.current.delete(event.pointerId);\n if (touchPanRef.current) {\n releaseCapture(event);\n if (touchPointsRef.current.size < 2) touchPanRef.current = null;\n return;\n }\n }\n if (panRef.current) {\n releaseCapture(event);\n panRef.current = null;\n return;\n }\n if (shapeDraftRef.current) {\n releaseCapture(event);\n commitShapeDraft();\n stopShapeDraft();\n return;\n }\n if (moveDraftRef.current) {\n releaseCapture(event);\n commitMove();\n stopMove();\n return;\n }\n if (marqueeDraftRef.current) {\n releaseCapture(event);\n commitMarquee();\n stopMarquee();\n return;\n }\n if (resizeDraftRef.current) {\n releaseCapture(event);\n commitResize();\n stopResize();\n return;\n }\n if (drawingRef.current) {\n releaseCapture(event);\n commitStroke();\n stopDrawing();\n } else if (erasingRef.current) {\n releaseCapture(event);\n commitErase();\n stopErasing();\n }\n },\n [\n releaseCapture,\n commitShapeDraft,\n stopShapeDraft,\n commitMove,\n stopMove,\n commitMarquee,\n stopMarquee,\n commitResize,\n stopResize,\n commitStroke,\n stopDrawing,\n commitErase,\n stopErasing,\n ],\n );\n\n // A pointercancel (palm rejection, an OS gesture taking over, ...) means\n // the interaction was aborted, not finished — discard rather than commit,\n // unlike pointerup.\n const handlePointerCancel = useCallback(\n (event) => {\n if (event.pointerType === 'touch') {\n touchPointsRef.current.delete(event.pointerId);\n if (touchPanRef.current) {\n releaseCapture(event);\n if (touchPointsRef.current.size < 2) touchPanRef.current = null;\n return;\n }\n }\n if (panRef.current) {\n releaseCapture(event);\n panRef.current = null;\n return;\n }\n if (shapeDraftRef.current) {\n releaseCapture(event);\n stopShapeDraft();\n return;\n }\n if (moveDraftRef.current) {\n releaseCapture(event);\n stopMove();\n return;\n }\n if (marqueeDraftRef.current) {\n releaseCapture(event);\n stopMarquee();\n return;\n }\n if (resizeDraftRef.current) {\n releaseCapture(event);\n stopResize();\n return;\n }\n if (drawingRef.current) {\n releaseCapture(event);\n stopDrawing();\n } else if (erasingRef.current) {\n releaseCapture(event);\n stopErasing();\n }\n },\n [releaseCapture, stopShapeDraft, stopMove, stopMarquee, stopResize, stopDrawing, stopErasing],\n );\n\n const handleResizeStart = useCallback(\n (event) => {\n startResize(event, {\n startX: event.clientX,\n startY: event.clientY,\n startWidth: block?.props?.width ?? DEFAULT_CANVAS_WIDTH,\n startHeight: block?.props?.height ?? DEFAULT_CANVAS_HEIGHT,\n });\n },\n [startResize, block],\n );\n\n // Same gap/fix as EmbedBlock's and the table column's own resize handles\n // (role=\"slider\" alone isn't keyboard-operable): Left/Right resize width,\n // Up/Down resize height (Shift for a finer 4px step instead of 24px),\n // Home resets both to their minimum.\n const handleResizeKeyDown = useCallback(\n (event) => {\n const currentWidth = block?.props?.width ?? DEFAULT_CANVAS_WIDTH;\n const currentHeight = block?.props?.height ?? DEFAULT_CANVAS_HEIGHT;\n const step = event.shiftKey ? 4 : 24;\n let patch;\n if (event.key === 'ArrowLeft')\n patch = { width: Math.max(MIN_CANVAS_WIDTH, currentWidth - step) };\n else if (event.key === 'ArrowRight') patch = { width: currentWidth + step };\n else if (event.key === 'ArrowUp')\n patch = { height: Math.max(MIN_CANVAS_HEIGHT, currentHeight - step) };\n else if (event.key === 'ArrowDown') patch = { height: currentHeight + step };\n else if (event.key === 'Home') patch = { width: MIN_CANVAS_WIDTH, height: MIN_CANVAS_HEIGHT };\n else return;\n event.preventDefault();\n store.applyOperation(updateBlockProps(id, patch));\n },\n [store, id, block],\n );\n\n if (!block) return null;\n const { strokes = [], shapes = [], width, height } = block.props;\n const effectiveWidth = dragSize?.width ?? width;\n const effectiveHeight = dragSize?.height ?? height;\n\n const SELECTION_PADDING = 6;\n // One dashed box per selected item (strokes and shapes alike), reflecting\n // an in-progress group move's live offset — 2+ selected renders one box\n // each, no union/group bounding box in this pass.\n const selectionBoxes = [...selectedIds]\n .map((selId) => {\n const found = findSelectable(block, selId);\n if (!found) return null;\n let { kind, item } = found;\n if (moveOverride?.ids?.includes(selId)) {\n item =\n kind === 'stroke'\n ? applyStrokeOffset(item, moveOverride.dx, moveOverride.dy)\n : applyShapeOffset(item, moveOverride.dx, moveOverride.dy);\n } else if (kind === 'shape' && resizePreviewShape?.id === selId) {\n item = resizePreviewShape;\n }\n return {\n id: selId,\n kind,\n item,\n box: selectableBoundingBox(kind, item),\n rotation: kind === 'shape' ? item.rotation : 0,\n };\n })\n .filter(Boolean);\n\n // Resize/endpoint/rotate handles are shown only for exactly 1 selected\n // item, and only when it's a shape (strokes were never resizable) — no\n // group-resize/rotate in this pass.\n const singleSelectedShapeEntry =\n selectionBoxes.length === 1 && selectionBoxes[0].kind === 'shape' ? selectionBoxes[0] : null;\n const selectedDisplayShape = singleSelectedShapeEntry?.item ?? null;\n // Corner resize handles are hidden once the shape has any rotation — see\n // the component doc comment on rotation's scope (no rotated-resize math\n // in this pass); the rotate handle itself is unaffected by that and shown\n // for any non-arrow single selection, rotated or not.\n const selectionHandlePoints =\n selectedDisplayShape && selectedDisplayShape.type === 'arrow'\n ? [\n ['start', selectedDisplayShape.x1, selectedDisplayShape.y1],\n ['end', selectedDisplayShape.x2, selectedDisplayShape.y2],\n ]\n : selectedDisplayShape && !selectedDisplayShape.rotation\n ? Object.entries(rectCorners(selectedDisplayShape)).map(([corner, [cx, cy]]) => [\n corner,\n cx,\n cy,\n ])\n : [];\n const rotateHandle =\n selectedDisplayShape && selectedDisplayShape.type !== 'arrow'\n ? rotateHandlePoint(selectedDisplayShape)\n : null;\n\n return (\n <div\n className={className}\n data-block-id={id}\n data-tool={tool}\n contentEditable={false}\n tabIndex={-1}\n >\n <div className=\"be-canvas-toolbar\" contentEditable={false}>\n <button\n type=\"button\"\n className={`be-canvas-toolbar-btn${tool === 'pen' ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-pressed={tool === 'pen'}\n aria-label=\"Pen\"\n title=\"Pen\"\n onClick={() => setTool('pen')}\n >\n <PencilIcon size={14} />\n </button>\n <div className=\"be-canvas-picker-wrap\">\n <button\n ref={eraserTriggerRef}\n type=\"button\"\n className={`be-canvas-toolbar-btn${tool === 'eraser' ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-haspopup=\"true\"\n aria-expanded={isEraserPickerOpen}\n aria-pressed={tool === 'eraser'}\n aria-label=\"Eraser\"\n title=\"Eraser\"\n onClick={() => setIsEraserPickerOpen((open) => !open)}\n >\n {(() => {\n const ActiveEraserIcon =\n ERASER_MODE_LIST.find((e) => e.mode === eraserMode)?.Icon ?? EraserIcon;\n return <ActiveEraserIcon size={14} />;\n })()}\n </button>\n {isEraserPickerOpen && (\n <div\n ref={eraserPopoverRef}\n className=\"be-canvas-picker be-canvas-shape-picker\"\n role=\"menu\"\n aria-label=\"Eraser\"\n >\n {ERASER_MODE_LIST.map(({ mode, label, Icon }) => (\n <button\n key={mode}\n type=\"button\"\n role=\"menuitem\"\n className={`be-canvas-toolbar-btn${tool === 'eraser' && eraserMode === mode ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-pressed={tool === 'eraser' && eraserMode === mode}\n aria-label={label}\n title={label}\n onClick={() => {\n setTool('eraser');\n setEraserMode(mode);\n closeEraserPicker();\n }}\n >\n <Icon size={14} />\n </button>\n ))}\n </div>\n )}\n </div>\n <button\n type=\"button\"\n className={`be-canvas-toolbar-btn${tool === 'select' ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-pressed={tool === 'select'}\n aria-label=\"Select\"\n title=\"Select\"\n onClick={() => setTool('select')}\n >\n <CursorIcon size={14} />\n </button>\n <button\n type=\"button\"\n className={`be-canvas-toolbar-btn${tool === 'text' ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-pressed={tool === 'text'}\n aria-label=\"Text\"\n title=\"Text\"\n onClick={() => setTool('text')}\n >\n <TextIcon size={14} />\n </button>\n <div className=\"be-canvas-picker-wrap\">\n <button\n ref={fontSizeTriggerRef}\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-haspopup=\"true\"\n aria-expanded={isFontSizePickerOpen}\n aria-label={`Font size: ${textEditDraft ? textEditDraft.fontSize : textFontSize}`}\n title=\"Font size\"\n onClick={() => setIsFontSizePickerOpen((open) => !open)}\n >\n <span className=\"be-canvas-font-size-trigger\">A</span>\n </button>\n {isFontSizePickerOpen && (\n <div\n ref={fontSizePopoverRef}\n className=\"be-canvas-picker be-canvas-size-picker\"\n role=\"dialog\"\n aria-label=\"Font size\"\n >\n <span className=\"be-canvas-size-preview\" aria-hidden=\"true\">\n <span\n className=\"be-canvas-font-size-preview-letter\"\n style={{ fontSize: textEditDraft ? textEditDraft.fontSize : textFontSize }}\n >\n A\n </span>\n </span>\n <input\n type=\"range\"\n className=\"be-canvas-size-slider\"\n min={MIN_TEXT_FONT_SIZE}\n max={MAX_TEXT_FONT_SIZE}\n value={textEditDraft ? textEditDraft.fontSize : textFontSize}\n onChange={(event) => {\n const value = Number(event.target.value);\n setTextFontSize(value);\n // Live-updates the box actively being typed into, if any\n // — see textFontSize's own doc comment above for why.\n if (textEditDraft)\n setTextEditDraft((prev) => (prev ? { ...prev, fontSize: value } : prev));\n }}\n aria-label=\"Font size\"\n />\n <span className=\"be-canvas-size-value\">\n {textEditDraft ? textEditDraft.fontSize : textFontSize}px\n </span>\n </div>\n )}\n </div>\n <button\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-label=\"Bring to front\"\n title=\"Bring to front\"\n onClick={handleBringToFront}\n disabled={selectedIds.size === 0}\n >\n <ArrowUpIcon size={14} />\n </button>\n <button\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-label=\"Send to back\"\n title=\"Send to back\"\n onClick={handleSendToBack}\n disabled={selectedIds.size === 0}\n >\n <ArrowDownIcon size={14} />\n </button>\n <span className=\"be-canvas-toolbar-divider\" />\n <div className=\"be-canvas-picker-wrap\">\n <button\n ref={shapeTriggerRef}\n type=\"button\"\n className={`be-canvas-toolbar-btn${SHAPE_TOOLS.has(tool) ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-haspopup=\"true\"\n aria-expanded={isShapePickerOpen}\n aria-label=\"Shape\"\n title=\"Shape\"\n onClick={() => setIsShapePickerOpen((open) => !open)}\n >\n {(() => {\n const ActiveShapeIcon =\n SHAPE_TOOL_LIST.find(\n (s) => s.type === (SHAPE_TOOLS.has(tool) ? tool : lastShapeTool),\n )?.Icon ?? SquareIcon;\n return <ActiveShapeIcon size={14} />;\n })()}\n </button>\n {isShapePickerOpen && (\n <div\n ref={shapePopoverRef}\n className=\"be-canvas-picker be-canvas-shape-picker\"\n role=\"menu\"\n aria-label=\"Shape\"\n >\n {SHAPE_TOOL_LIST.map(({ type, label, Icon }) => (\n <button\n key={type}\n type=\"button\"\n role=\"menuitem\"\n className={`be-canvas-toolbar-btn${tool === type ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-pressed={tool === type}\n aria-label={label}\n title={label}\n onClick={() => {\n setTool(type);\n setLastShapeTool(type);\n closeShapePicker();\n }}\n >\n <Icon size={14} />\n </button>\n ))}\n </div>\n )}\n </div>\n <span className=\"be-canvas-toolbar-divider\" />\n <div className=\"be-canvas-picker-wrap\">\n <button\n ref={colorTriggerRef}\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-haspopup=\"true\"\n aria-expanded={isColorPickerOpen}\n aria-label={`Color: ${color}`}\n title=\"Color\"\n onClick={() => setIsColorPickerOpen((open) => !open)}\n >\n <span className=\"be-canvas-color-trigger-dot\" style={{ backgroundColor: color }} />\n </button>\n {isColorPickerOpen && (\n <div\n ref={colorPopoverRef}\n className=\"be-canvas-picker be-canvas-color-picker\"\n role=\"menu\"\n aria-label=\"Pen color\"\n >\n {COLOR_SWATCHES.map((swatch) => (\n <button\n key={swatch}\n type=\"button\"\n role=\"menuitem\"\n className={`be-canvas-toolbar-swatch${color === swatch ? ' be-canvas-toolbar-swatch-active' : ''}`}\n style={{ backgroundColor: swatch }}\n aria-pressed={color === swatch}\n aria-label={`Color ${swatch}`}\n title={`Color ${swatch}`}\n onClick={() => {\n setColor(swatch);\n closeColorPicker();\n }}\n />\n ))}\n <label\n className=\"be-canvas-custom-swatch\"\n title=\"Custom color\"\n aria-label=\"Custom color\"\n >\n <input\n type=\"color\"\n value={color}\n onChange={(event) => setColor(event.target.value)}\n />\n </label>\n </div>\n )}\n </div>\n <span className=\"be-canvas-toolbar-divider\" />\n <div className=\"be-canvas-picker-wrap\">\n <button\n ref={fillTriggerRef}\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-haspopup=\"true\"\n aria-expanded={isFillPickerOpen}\n aria-label={`Fill: ${fill ?? 'none'}`}\n title=\"Fill\"\n onClick={() => setIsFillPickerOpen((open) => !open)}\n >\n <span\n className={`be-canvas-fill-trigger-dot${fill ? '' : ' be-canvas-fill-trigger-dot-none'}`}\n style={fill ? { backgroundColor: fill } : undefined}\n />\n </button>\n {isFillPickerOpen && (\n <div\n ref={fillPopoverRef}\n className=\"be-canvas-picker be-canvas-color-picker\"\n role=\"menu\"\n aria-label=\"Shape fill\"\n >\n <button\n type=\"button\"\n role=\"menuitem\"\n className={`be-canvas-toolbar-swatch be-canvas-fill-swatch-none${fill === null ? ' be-canvas-toolbar-swatch-active' : ''}`}\n aria-pressed={fill === null}\n aria-label=\"No fill\"\n title=\"No fill\"\n onClick={() => {\n setFill(null);\n closeFillPicker();\n }}\n />\n {COLOR_SWATCHES.map((swatch) => (\n <button\n key={swatch}\n type=\"button\"\n role=\"menuitem\"\n className={`be-canvas-toolbar-swatch${fill === swatch ? ' be-canvas-toolbar-swatch-active' : ''}`}\n style={{ backgroundColor: swatch }}\n aria-pressed={fill === swatch}\n aria-label={`Fill ${swatch}`}\n title={`Fill ${swatch}`}\n onClick={() => {\n setFill(swatch);\n closeFillPicker();\n }}\n />\n ))}\n <label\n className=\"be-canvas-custom-swatch\"\n title=\"Custom fill\"\n aria-label=\"Custom fill\"\n >\n <input\n type=\"color\"\n value={fill ?? DEFAULT_COLOR}\n onChange={(event) => setFill(event.target.value)}\n />\n </label>\n </div>\n )}\n </div>\n <span className=\"be-canvas-toolbar-divider\" />\n <div className=\"be-canvas-picker-wrap\">\n <button\n ref={sizeTriggerRef}\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-haspopup=\"true\"\n aria-expanded={isSizePickerOpen}\n aria-label={`Stroke size: ${strokeSize}`}\n title=\"Stroke size\"\n onClick={() => setIsSizePickerOpen((open) => !open)}\n >\n <span\n className=\"be-canvas-size-trigger-dot\"\n style={{ width: Math.min(strokeSize, 16), height: Math.min(strokeSize, 16) }}\n />\n </button>\n {isSizePickerOpen && (\n <div\n ref={sizePopoverRef}\n className=\"be-canvas-picker be-canvas-size-picker\"\n role=\"dialog\"\n aria-label=\"Stroke size\"\n >\n <span className=\"be-canvas-size-preview\" aria-hidden=\"true\">\n <span\n className=\"be-canvas-size-preview-dot\"\n style={{ width: strokeSize, height: strokeSize }}\n />\n </span>\n <input\n type=\"range\"\n className=\"be-canvas-size-slider\"\n min={MIN_STROKE_SIZE}\n max={MAX_STROKE_SIZE}\n value={strokeSize}\n onChange={(event) => setStrokeSize(Number(event.target.value))}\n aria-label=\"Stroke size\"\n />\n <span className=\"be-canvas-size-value\">{strokeSize}px</span>\n </div>\n )}\n </div>\n <span className=\"be-canvas-toolbar-divider\" />\n <button\n type=\"button\"\n className={`be-canvas-toolbar-btn${snapEnabled ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-pressed={snapEnabled}\n aria-label=\"Snap to grid\"\n title={\n snapEnabled\n ? 'Snap to grid: ON — drawing, moving, resizing and rotating align to the dotted grid. Click to turn off.'\n : 'Snap to grid: OFF — click to turn on (aligns drawing, moving, resizing and rotating to a grid)'\n }\n onClick={() => setSnapEnabled((prev) => !prev)}\n >\n <MagnetIcon size={14} />\n </button>\n <span className=\"be-canvas-toolbar-divider\" />\n <button\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-label=\"Zoom out\"\n title=\"Zoom out\"\n onClick={handleZoomOut}\n disabled={view.zoom <= MIN_ZOOM}\n >\n −\n </button>\n <button\n type=\"button\"\n className=\"be-canvas-zoom-label\"\n aria-label={`Zoom: ${Math.round(view.zoom * 100)}%. Click to reset to 100%.`}\n title=\"Reset zoom to 100%\"\n onClick={handleZoomReset}\n >\n {Math.round(view.zoom * 100)}%\n </button>\n <button\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-label=\"Zoom in\"\n title=\"Zoom in\"\n onClick={handleZoomIn}\n disabled={view.zoom >= MAX_ZOOM}\n >\n +\n </button>\n <span className=\"be-canvas-toolbar-divider\" />\n <button\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-label=\"Export PNG\"\n title=\"Export as PNG\"\n onClick={handleExportPNG}\n disabled={strokes.length === 0 && shapes.length === 0}\n >\n <DownloadIcon size={14} />\n </button>\n </div>\n <svg\n ref={svgRef}\n className=\"be-canvas-surface\"\n viewBox={`${view.x} ${view.y} ${viewSize} ${viewSize}`}\n width={effectiveWidth}\n height={effectiveHeight}\n tabIndex={-1}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerCancel}\n onDoubleClick={handleDoubleClick}\n onKeyDown={handleKeyDown}\n >\n {snapEnabled && (\n <>\n {/* A dot grid at a coarser spacing than SNAP_GRID_SIZE itself\n (10 units) — showing every actual snap line would be a\n 10x10=100 solid wall of dots at this space's scale, not a\n helpful visual reference. This exists purely so \"snap to\n grid\" has something visible to point at (see the toolbar\n button's own title) — drawing/dragging still snaps to the\n finer, unrendered SNAP_GRID_SIZE lines underneath it. */}\n <defs>\n <pattern\n id={`be-canvas-grid-${id}`}\n width={SNAP_GRID_VISUAL_SPACING}\n height={SNAP_GRID_VISUAL_SPACING}\n patternUnits=\"userSpaceOnUse\"\n >\n <circle cx={1} cy={1} r={1.5} className=\"be-canvas-grid-dot\" />\n </pattern>\n </defs>\n <rect\n className=\"be-canvas-grid-background\"\n x={view.x}\n y={view.y}\n width={viewSize}\n height={viewSize}\n fill={`url(#be-canvas-grid-${id})`}\n />\n </>\n )}\n {/* One shared bottom-to-top stacking order across strokes AND shapes (see zOrder.js) — a pen\n stroke drawn after a filled shape now renders on top of it, instead of every shape always\n painting over every stroke regardless of draw order. */}\n {orderedDrawables(strokes, shapes).map(({ kind, item }) => {\n if (kind === 'stroke') {\n const stroke = item;\n const moved = moveOverride?.ids?.includes(stroke.id);\n const path = moved\n ? getStrokeOutlinePath(\n applyStrokeOffset(stroke, moveOverride.dx, moveOverride.dy).points,\n { size: stroke.size },\n )\n : getStrokePath(stroke);\n return (\n <path\n key={stroke.id}\n d={path}\n fill={stroke.color}\n fillRule=\"nonzero\"\n opacity={erasingIds.has(stroke.id) ? 0.25 : 1}\n />\n );\n }\n const shape = item;\n let displayShape = shape;\n if (moveOverride?.ids?.includes(shape.id))\n displayShape = applyShapeOffset(shape, moveOverride.dx, moveOverride.dy);\n else if (resizePreviewShape?.id === shape.id) displayShape = resizePreviewShape;\n return (\n <ShapeElement\n key={shape.id}\n shape={displayShape}\n opacity={erasingShapeIds.has(shape.id) ? 0.25 : 1}\n />\n );\n })}\n {/* The in-progress pen/shape draft always renders on top of everything else while actively drawing. */}\n {previewPath && <path d={previewPath} fill={color} fillRule=\"nonzero\" />}\n {shapeDraftPreview && <ShapeElement shape={shapeDraftPreview} opacity={0.6} />}\n {selectionBoxes.map(({ id: selId, box, rotation }) => (\n <g\n key={selId}\n transform={\n rotation\n ? `rotate(${rotation} ${box.x + box.width / 2} ${box.y + box.height / 2})`\n : undefined\n }\n >\n <rect\n className=\"be-canvas-selection-box\"\n x={box.x - SELECTION_PADDING}\n y={box.y - SELECTION_PADDING}\n width={box.width + SELECTION_PADDING * 2}\n height={box.height + SELECTION_PADDING * 2}\n fill=\"none\"\n />\n </g>\n ))}\n {selectionHandlePoints.map(([corner, cx, cy]) => (\n <rect\n key={corner}\n className=\"be-canvas-selection-handle\"\n x={cx - HANDLE_VISUAL_SIZE / 2}\n y={cy - HANDLE_VISUAL_SIZE / 2}\n width={HANDLE_VISUAL_SIZE}\n height={HANDLE_VISUAL_SIZE}\n />\n ))}\n {rotateHandle && (\n <circle\n className=\"be-canvas-rotate-handle\"\n cx={rotateHandle[0]}\n cy={rotateHandle[1]}\n r={HANDLE_VISUAL_SIZE / 2}\n />\n )}\n {marqueeRect && (\n <rect\n className=\"be-canvas-marquee\"\n x={marqueeRect.x}\n y={marqueeRect.y}\n width={marqueeRect.width}\n height={marqueeRect.height}\n />\n )}\n {textEditDraft && (\n <foreignObject\n x={textEditDraft.x}\n y={textEditDraft.y}\n width={textEditDraft.width}\n height={textEditDraft.height}\n >\n <textarea\n // eslint-disable-next-line react/no-unknown-property\n xmlns=\"http://www.w3.org/1999/xhtml\"\n ref={(el) => el?.focus()}\n className=\"be-canvas-text-editor\"\n value={textEditDraft.text}\n style={{ color: textEditDraft.color, fontSize: textEditDraft.fontSize }}\n onChange={(event) =>\n setTextEditDraft((prev) => (prev ? { ...prev, text: event.target.value } : prev))\n }\n onBlur={() => commitTextEdit()}\n onKeyDown={(event) => {\n // Escape discards the draft (a new box vanishes; an edit\n // reverts to whatever was last committed) instead of\n // committing whatever's currently typed — plain Enter\n // inserts a newline (multi-line text is the whole point of\n // a resizable box), so there's no separate \"confirm\" key.\n if (event.key === 'Escape') {\n event.preventDefault();\n cancelTextEdit();\n }\n event.stopPropagation(); // don't let the svg's own onKeyDown (Delete/nudge/paste/...) fire while typing\n }}\n />\n </foreignObject>\n )}\n </svg>\n <div\n className=\"be-canvas-resize-handle\"\n onMouseDown={handleResizeStart}\n onKeyDown={handleResizeKeyDown}\n role=\"slider\"\n tabIndex={0}\n aria-label=\"Resize canvas (Left/Right for width, Up/Down for height)\"\n aria-valuemin={MIN_CANVAS_WIDTH}\n aria-valuenow={effectiveWidth}\n contentEditable={false}\n />\n </div>\n );\n}\n","// defineBlock / defineInline — the typed, validating factories for authoring a\n// block or inline type (docs/repackaging-plan.md Phase 3). A result is a plain\n// object that is ALSO a valid BlockRegistry/InlineRegistry entry, so it drops\n// straight into the existing `registry.register(type, entry)` path — this is an\n// addition next to `registerBlocks` / `registerBuiltInBlocks`, not a\n// replacement. `registerExtensions` walks an `extensions: [...]` array and\n// registers each item on the right registry.\n\nconst BLOCK_KIND = 'block';\nconst INLINE_KIND = 'inline';\nconst EXTENSION_KIND = 'extension';\n\n// 'blocks' -> holds child blocks (isLeaf false); 'runs'/'void' -> a leaf\n// (isLeaf true) whose contentIds point at text runs, or nothing at all.\nconst CONTENT_MODEL_IS_LEAF = { blocks: false, runs: true, void: true };\n\nfunction fail(fn, message) {\n throw new TypeError(`${fn}: ${message}`);\n}\n\n/**\n * @param {object} config\n * - `name` (required): unique string, used as the block `type`.\n * - `component` (required): React component, receives `{ id }`.\n * - `contentModel`: 'blocks' | 'runs' | 'void' (default 'blocks'). Sets `isLeaf`.\n * - `isLeaf`: escape hatch — pass it directly instead of `contentModel`\n * (used when wrapping a pre-existing entry object).\n * - any other entry fields (`defaultProps`, `toHTML`, `fromHTML`,\n * `toPlainText`, `toMarkdown`, `slashCommand`, `slashCommands`, …) pass\n * through untouched.\n * @returns a BlockRegistry entry: the config plus `kind: 'block'` and a\n * resolved `isLeaf`.\n */\nexport function defineBlock(config) {\n if (!config || typeof config !== 'object') fail('defineBlock', 'config must be an object');\n const { name, component, contentModel, isLeaf, ...rest } = config;\n\n if (typeof name !== 'string' || !name.trim()) {\n fail('defineBlock', '`name` must be a non-empty string');\n }\n if (typeof component !== 'function') {\n fail('defineBlock', `block \"${name}\": \\`component\\` must be a React component`);\n }\n if (contentModel !== undefined && !(contentModel in CONTENT_MODEL_IS_LEAF)) {\n fail(\n 'defineBlock',\n `block \"${name}\": \\`contentModel\\` must be 'blocks', 'runs', or 'void' (got ${JSON.stringify(contentModel)})`,\n );\n }\n\n const resolvedIsLeaf =\n isLeaf !== undefined\n ? Boolean(isLeaf)\n : contentModel === undefined\n ? false\n : CONTENT_MODEL_IS_LEAF[contentModel];\n\n return {\n ...rest,\n ...(contentModel !== undefined ? { contentModel } : {}),\n name,\n kind: BLOCK_KIND,\n component,\n isLeaf: resolvedIsLeaf,\n };\n}\n\n/**\n * @param {object} config\n * - `name` (required): unique string, used as the run `type`.\n * - `component` (required): React component, receives `{ id }`.\n * - `atomic` / `isAtomic`: only `true` is supported today (the default) —\n * every inline type renders as one contenteditable=false island.\n * - any other entry fields (`toHTML`, `fromHTML`, `toPlainText`,\n * `slashCommand(s)`, `atCommand(s)`, …) pass through untouched.\n * @returns an InlineRegistry entry: the config plus `kind: 'inline'` and\n * `isAtomic: true`.\n */\nexport function defineInline(config) {\n if (!config || typeof config !== 'object') fail('defineInline', 'config must be an object');\n const { name, component, atomic, isAtomic, ...rest } = config;\n\n if (typeof name !== 'string' || !name.trim()) {\n fail('defineInline', '`name` must be a non-empty string');\n }\n if (typeof component !== 'function') {\n fail('defineInline', `inline \"${name}\": \\`component\\` must be a React component`);\n }\n const resolvedAtomic =\n atomic !== undefined ? Boolean(atomic) : isAtomic !== undefined ? Boolean(isAtomic) : true;\n if (resolvedAtomic !== true) {\n fail('defineInline', `inline \"${name}\": only atomic inline types are supported today`);\n }\n\n return {\n ...rest,\n name,\n kind: INLINE_KIND,\n component,\n isAtomic: true,\n };\n}\n\n/**\n * A named unit dropped into an `extensions: [...]` array. Can carry:\n * - `blocks` / `inlineTypes` — `defineBlock()` / `defineInline()` results to\n * register (a plugin that ships several types as one install).\n * - `keymap` — `{ 'Mod-Shift-x': (ctx, event) => boolean }`; return truthy to\n * mark the key handled (the editor calls preventDefault + stops it there).\n * - `onBeforeInput(ctx, event)` / `onPaste(ctx, event)` — same \"return truthy\n * = handled\" contract, for `beforeinput` / `paste` on the editor surface.\n * - `setup(ctx)` — run once when the editor mounts; may return a cleanup fn.\n *\n * The behavior fields only do anything when the extension is passed through\n * `useEditor({ extensions })` and rendered by `<NoteloomEditor>` (which wires\n * `useExtensionBehaviors`). `ctx` is the stable facade that hook builds — see\n * its doc comment for the shape. Markdown-style input rules that convert a\n * whole block are still block-coupled and not expressible here yet.\n *\n * @param {object} config — `name` (required, a label) plus any of the above.\n */\nexport function defineExtension(config) {\n if (!config || typeof config !== 'object') fail('defineExtension', 'config must be an object');\n const {\n name,\n blocks = [],\n inlineTypes = [],\n keymap,\n onBeforeInput,\n onPaste,\n setup,\n ...rest\n } = config;\n\n if (typeof name !== 'string' || !name.trim()) {\n fail('defineExtension', '`name` must be a non-empty string');\n }\n if (!Array.isArray(blocks)) {\n fail('defineExtension', `extension \"${name}\": \\`blocks\\` must be an array`);\n }\n if (!Array.isArray(inlineTypes)) {\n fail('defineExtension', `extension \"${name}\": \\`inlineTypes\\` must be an array`);\n }\n if (keymap !== undefined && (typeof keymap !== 'object' || keymap === null)) {\n fail('defineExtension', `extension \"${name}\": \\`keymap\\` must be an object`);\n }\n for (const [field, value] of [\n ['onBeforeInput', onBeforeInput],\n ['onPaste', onPaste],\n ['setup', setup],\n ]) {\n if (value !== undefined && typeof value !== 'function') {\n fail('defineExtension', `extension \"${name}\": \\`${field}\\` must be a function`);\n }\n }\n\n return {\n ...rest,\n name,\n kind: EXTENSION_KIND,\n blocks,\n inlineTypes,\n ...(keymap !== undefined ? { keymap } : {}),\n ...(onBeforeInput !== undefined ? { onBeforeInput } : {}),\n ...(onPaste !== undefined ? { onPaste } : {}),\n ...(setup !== undefined ? { setup } : {}),\n };\n}\n\nexport function isBlockDefinition(value) {\n return Boolean(value) && value.kind === BLOCK_KIND;\n}\n\nexport function isInlineDefinition(value) {\n return Boolean(value) && value.kind === INLINE_KIND;\n}\n\nexport function isExtensionBundle(value) {\n return Boolean(value) && value.kind === EXTENSION_KIND;\n}\n\n/**\n * Registers a flat or nested array of `defineBlock()` / `defineInline()`\n * results (and `defineExtension()` bundles, which are unpacked recursively)\n * onto the given registries — the primitive behind\n * `useEditor({ extensions: [...] })`, also usable directly against your own\n * `createBlockRegistry()` / `createInlineRegistry()`.\n */\nexport function registerExtensions(extensions, { registry, inlineRegistry }) {\n if (!Array.isArray(extensions)) {\n fail('registerExtensions', '`extensions` must be an array');\n }\n for (const ext of extensions.flat(Infinity)) {\n if (isExtensionBundle(ext)) {\n registerExtensions([...ext.blocks, ...ext.inlineTypes], { registry, inlineRegistry });\n } else if (isBlockDefinition(ext)) {\n if (!registry) fail('registerExtensions', `no block registry given for \"${ext.name}\"`);\n registry.register(ext.name, ext);\n } else if (isInlineDefinition(ext)) {\n if (!inlineRegistry) fail('registerExtensions', `no inline registry given for \"${ext.name}\"`);\n inlineRegistry.register(ext.name, ext);\n } else {\n fail(\n 'registerExtensions',\n 'each item must be a defineBlock() / defineInline() result or a defineExtension() bundle (missing `kind`)',\n );\n }\n }\n}\n","import { CanvasBlock } from './CanvasBlock.jsx';\nimport { defineBlock } from '../../registry/define.js';\nimport {\n createCanvasBlock,\n DEFAULT_CANVAS_WIDTH,\n DEFAULT_CANVAS_HEIGHT,\n} from './createCanvasBlock.js';\nimport { buildCanvasSVGMarkup } from './exportSvg.js';\nimport { insertSiblingAfter, insertSiblingAfterAndFocus } from '../shared/blockCommands.js';\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\nimport { updateRun } from '../../store/operations.js';\nimport { ScribbleIcon } from '../../react/icons.jsx';\n\n/**\n * Bakes a self-contained inline `<svg>` (see exportSvg.js's own doc\n * comment for why that logic lives in its own module rather than here).\n * Mirrors embed's own `if (!src) return '<p></p>';` convention for\n * \"nothing meaningful here yet\" (see embed/index.js's toHTML).\n */\nfunction toHTML(block) {\n const { strokes = [], shapes = [] } = block.props;\n if (!strokes.length && !shapes.length) return '<p></p>';\n return buildCanvasSVGMarkup(block);\n}\n\n// A drawing has no meaningful plain-text representation (unlike embed,\n// which at least has a filename, or divider's decorative \"---\") — this is a\n// deliberate, permanent v1 limitation: no OCR/description generation.\nfunction toPlainText() {\n return '';\n}\n\n// No paste-round-trip import of arbitrary pasted <svg> markup back into\n// stroke data in v1 — reverse-parsing arbitrary path `d` data back into a\n// normalized-space point array is a non-trivial, out-of-scope problem. A\n// canvas block can only be created via its own slash command for now;\n// pasting exported HTML back in falls through to whatever the paste\n// pipeline does for an unrecognized node.\nfunction fromHTML() {\n return null;\n}\n\n/** Same pattern as divider's/embed's slash command: a canvas has no run of its own to focus into, so seed and focus a following paragraph. */\nfunction insertCanvasCommand(store, { blockId, runId, sliceStart, sliceEnd }) {\n const run = store.getRun(runId);\n const value = run?.value ?? '';\n store.applyOperation(\n updateRun(runId, { value: value.slice(0, sliceStart) + value.slice(sliceEnd) }),\n );\n const canvasId = insertSiblingAfter(store, blockId, createCanvasBlock());\n insertSiblingAfterAndFocus(store, canvasId, createTextLeafBlock('paragraph'));\n return canvasId;\n}\n\nexport const canvasBlockType = defineBlock({\n name: 'canvas',\n contentModel: 'void',\n component: CanvasBlock,\n defaultProps: {\n strokes: [],\n shapes: [],\n width: DEFAULT_CANVAS_WIDTH,\n height: DEFAULT_CANVAS_HEIGHT,\n },\n toHTML,\n toPlainText,\n fromHTML,\n slashCommand: {\n label: 'Canvas',\n icon: ScribbleIcon,\n keywords: ['canvas', 'draw', 'drawing', 'sketch', 'freehand'],\n run: insertCanvasCommand,\n },\n});\n"],"names":["useBlock","id","store","useEditorStore","subscribe","useCallback","onStoreChange","getSnapshot","useSyncExternalStore","useRun","useOutsideClickAndEscape","refs","isOpen","onClose","useEffect","refList","handlePointerDown","event","ref","_b","_a","handleKeyDown","DEFAULT_SIZE","DEFAULT_THINNING","DEFAULT_SMOOTHING","TAPER_POINT_COUNT","MIN_RADIUS_FACTOR","SPEED_NORM","dist","a","b","clamp","value","min","max","round","n","DEFAULT_PRESSURE","hasRealPressureVariation","points","pressure","computeRadii","size","thinning","baseRadius","radii","speed","i","step","speedFactor","pressureFactor","radius","taperCount","t","factor","smoothPoints","smoothing","result","midX","midY","x","y","computeOffsets","left","right","prev","next","tx","ty","len","nx","ny","r","pathFromPolygon","poly","d","dotPath","angle","getStrokeOutlinePath","rawPoints","options","smoothed","polygon","strokeBoundingBox","minX","minY","maxX","maxY","computeViewTransform","svgEl","rect","rectWidth","rectHeight","scale","offsetX","offsetY","clientToLocal","view","localPixelScale","zoomAnchoredView","prevView","nextSize","cursorLocalX","cursorLocalY","zoomCenteredView","centerX","centerY","clampViewOffset","boundsSize","centered","boxesIntersect","padding","normalizeRect","x1","y1","x2","y2","width","height","rotatePoint","px","py","cx","cy","angleDeg","radians","cos","sin","dx","dy","pointInRect","pointInEllipse","rx","ry","distanceToSegment","lengthSquared","projX","projY","pointNearSegment","tolerance","diamondPoints","trianglePoints","starPoints","spikes","outerRx","outerRy","innerRatio","isOuter","pointInPolygon","vertices","inside","j","xi","yi","xj","yj","arrowheadPoints","length","ux","uy","backX","backY","halfWidth","useDragResize","compute","onCommit","dragValue","setDragValue","useState","startDrag","start","handleMouseMove","moveEvent","handleMouseUp","upEvent","DEFAULT_CANVAS_WIDTH","DEFAULT_CANVAS_HEIGHT","createCanvasBlock","strokes","shapes","parentId","genId","escapeHTML","str","escapeAttr","runToHTML","run","ctx","entry","marks","html","targetAttrs","runsToHTML","runs","runToPlainText","escapeMarkdown","c","runToMarkdown","raw","md","runsToMarkdown","LEGACY_Z_BASE","effectiveZ","item","isShape","index","orderedDrawables","items","nextZIndex","maxZ","minZIndex","minZ","POLYGON_POINTS_BY_TYPE","shapeToHTML","shape","strokeWidth","color","headSize","fill","content","fontSize","text","pointsFn","buildCanvasSVGMarkup","block","markup","kind","VIEW_SIZE","DEFAULT_COLOR","DEFAULT_STROKE_SIZE","COLOR_SWATCHES","MIN_STROKE_SIZE","MAX_STROKE_SIZE","ERASER_RADIUS","ERASER_RADIUS_PRECISE","MIN_CANVAS_WIDTH","MIN_CANVAS_HEIGHT","MIN_ZOOM","MAX_ZOOM","ZOOM_STEP","MARQUEE_MIN_DRAG","PASTE_OFFSET","NUDGE_STEP","NUDGE_STEP_LARGE","NUDGE_DELTAS","DEFAULT_TEXT_WIDTH","DEFAULT_TEXT_HEIGHT","DEFAULT_TEXT_FONT_SIZE","MIN_TEXT_FONT_SIZE","MAX_TEXT_FONT_SIZE","SNAP_GRID_SIZE","SNAP_ROTATION_STEP","SNAP_GRID_VISUAL_SPACING","snapValue","v","snapAngle","deg","useStrokePathCache","cacheRef","useRef","stroke","cache","path","pointBox","touchCentroid","pointsMap","sumX","sumY","point","count","strokeNearPoint","SHAPE_TOOLS","SHAPE_TOOL_LIST","SquareIcon","CircleIcon","ArrowDiagonalIcon","DiamondIcon","TriangleIcon","StarIcon","ERASER_MODE_LIST","EraserIcon","XIcon","buildDraftShape","draft","fillColor","ARROW_HIT_TOLERANCE","hitTestOneShape","testX","testY","shapeCenter","hitTestShapeAt","applyShapeOffset","shapeBoundingBox","box","applyStrokeOffset","splitStrokePoints","erasedIndices","current","strokeBoxRect","selectableBoundingBox","findSelectable","selId","s","hitTestSelectableAt","ordered","HANDLE_HIT_RADIUS","HANDLE_VISUAL_SIZE","rectCorners","OPPOSITE_CORNER","ROTATE_HANDLE_OFFSET","rotateHandlePoint","localX","localY","hitTestHandle","rhx","rhy","corner","buildResizedShape","ShapeElement","opacity","jsx","head","jsxs","CanvasBlock","className","useBlockClassName","getStrokePath","tool","setTool","eraserMode","setEraserMode","setColor","strokeSize","setStrokeSize","setFill","snapEnabled","setSnapEnabled","textFontSize","setTextFontSize","lastShapeTool","setLastShapeTool","isColorPickerOpen","setIsColorPickerOpen","isFillPickerOpen","setIsFillPickerOpen","isSizePickerOpen","setIsSizePickerOpen","isShapePickerOpen","setIsShapePickerOpen","isFontSizePickerOpen","setIsFontSizePickerOpen","isEraserPickerOpen","setIsEraserPickerOpen","colorTriggerRef","colorPopoverRef","fillTriggerRef","fillPopoverRef","sizeTriggerRef","sizePopoverRef","shapeTriggerRef","shapePopoverRef","fontSizeTriggerRef","fontSizePopoverRef","eraserTriggerRef","eraserPopoverRef","colorRefs","useMemo","fillRefs","sizeRefs","shapeRefs","fontSizeRefs","eraserRefs","closeColorPicker","closeFillPicker","closeSizePicker","closeShapePicker","closeFontSizePicker","closeEraserPicker","svgRef","pointsRef","drawingRef","rafRef","previewPath","setPreviewPath","erasedStrokeIdsRef","erasedShapeIdsRef","erasedPointIndicesRef","erasingRef","eraseRafRef","erasingIds","setErasingIds","erasingShapeIds","setErasingShapeIds","shapeDraftRef","shapeDraftPreview","setShapeDraftPreview","selectedIds","setSelectedIds","moveDraftRef","moveOverride","setMoveOverride","marqueeDraftRef","marqueeRect","setMarqueeRect","clipboardRef","textEditDraft","setTextEditDraft","resizeDraftRef","resizePreviewShape","setResizePreviewShape","setView","viewSize","panRef","touchPointsRef","touchPanRef","dragSize","startResize","updateBlockProps","schedulePreviewUpdate","stopDrawing","commitStroke","currentStrokes","currentShapes","newStroke","scheduleErasingPreview","hitTestEraserAt","eraserBox","indices","shapeBox","stopErasing","commitErase","hasWholeStrokeErase","hasPartialErase","nextStrokes","stopShapeDraft","commitShapeDraft","newShape","stopMove","commitMove","idSet","nextShapes","stopMarquee","commitMarquee","marqueeBox","hitIds","copySelection","pasteClipboard","nextZ","newStrokes","newShapes","newIds","newId","z","reorderSelection","toFront","selectedStrokes","selectedShapes","selectedOrdered","baseZ","zById","stampZ","handleBringToFront","handleSendToBack","startNewTextEdit","startExistingTextEdit","cancelTextEdit","commitTextEdit","shapeId","nextShape","_c","stopResize","commitResize","original","resized","cancelActiveSingleGesture","pointerId","svg","dirX","dirY","_d","_e","key","currentView","handleWheel","zoomFactor","nextZoom","handleZoomIn","handleZoomOut","handleZoomReset","handleExportPNG","svgMarkup","svgDataUrl","img","exportCanvas","link","handleDoubleClick","hitId","center","textX","textY","_f","_g","startX","startY","strokesList","_h","shapesList","_i","singleSelectedShape","handle","startAngle","fixedX","fixedY","hit","nextIds","handlePointerMove","startCenterX","startCenterY","startViewX","startViewY","startClientX","startClientY","currentAngle","rawRotation","releaseCapture","handlePointerUp","handlePointerCancel","handleResizeStart","handleResizeKeyDown","currentWidth","currentHeight","patch","effectiveWidth","effectiveHeight","SELECTION_PADDING","selectionBoxes","found","singleSelectedShapeEntry","selectedDisplayShape","selectionHandlePoints","rotateHandle","PencilIcon","open","ActiveEraserIcon","e","mode","label","Icon","CursorIcon","TextIcon","ArrowUpIcon","ArrowDownIcon","ActiveShapeIcon","type","swatch","MagnetIcon","DownloadIcon","Fragment","displayShape","rotation","el","BLOCK_KIND","INLINE_KIND","EXTENSION_KIND","CONTENT_MODEL_IS_LEAF","fail","fn","message","defineBlock","config","name","component","contentModel","isLeaf","rest","resolvedIsLeaf","defineInline","atomic","isAtomic","defineExtension","blocks","inlineTypes","keymap","onBeforeInput","onPaste","setup","field","isBlockDefinition","isInlineDefinition","isExtensionBundle","registerExtensions","extensions","registry","inlineRegistry","ext","toHTML","toPlainText","fromHTML","insertCanvasCommand","blockId","runId","sliceStart","sliceEnd","updateRun","canvasId","insertSiblingAfter","insertSiblingAfterAndFocus","createTextLeafBlock","canvasBlockType","ScribbleIcon"],"mappings":"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"}