@sofereditor/react 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +757 -147
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -2
- package/dist/index.d.ts +36 -2
- package/dist/index.js +643 -34
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/Editor.tsx","../src/dom-bridge.ts","../src/BehindImageSelectAffordance.tsx","../src/LinkHoverTooltip.tsx","../src/platform.ts","../src/EditorContext.tsx","../src/LinkDialog.tsx","../src/dialogCenterStyle.ts","../src/PageConfigDialog.tsx","../src/ImageCaptionDialog.tsx","../src/ImageResizeOverlay.tsx","../src/RemoteCursorsOverlay.tsx","../src/NodeView.tsx","../src/renderInline.tsx","../src/sliceDelta.ts","../src/TableResizeOverlay.tsx","../src/usePagination.ts","../src/useEditor.ts","../src/usePageSettings.ts","../src/Toolbar.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type JSX,\n type KeyboardEvent,\n type ReactNode,\n type RefObject,\n} from \"react\";\nimport {\n deleteBackward,\n deleteForward,\n deleteSelection,\n encodeSelection,\n insertParagraph,\n insertSlice,\n insertText,\n serializeSelection,\n sliceToText,\n SOFER_MIME,\n type ClipboardSlice,\n type CommandContext,\n type ListKind,\n type MarkName,\n type SerializedBlock,\n} from \"@sofereditor/core\";\nimport { applyDomSelection, isTableRectSelection, readDomSelection, selectionsEqual } from \"./dom-bridge\";\nimport { BehindImageSelectAffordance } from \"./BehindImageSelectAffordance\";\nimport { LinkHoverTooltip } from \"./LinkHoverTooltip\";\nimport { EditorProvider } from \"./EditorContext\";\nimport { ImageResizeOverlay } from \"./ImageResizeOverlay\";\nimport {\n RemoteCursorsOverlay,\n type AwarenessLike,\n} from \"./RemoteCursorsOverlay\";\nimport { NodeView, type NodeViewFragment } from \"./NodeView\";\nimport {\n A4_PAGE,\n defaultPageLayout,\n usePageLayout,\n type PageGeometry,\n type PageLayout,\n type PageSlot,\n} from \"./usePagination\";\nimport { useEditor, type UseEditorResult } from \"./useEditor\";\nimport { usePageSettings } from \"./usePageSettings\";\n\nexport interface PageRenderContext {\n pageNumber: number;\n pageCount: number;\n}\n\nexport type PageRenderProp = (ctx: PageRenderContext) => ReactNode;\n\nexport interface EditorProps {\n editor?: UseEditorResult;\n className?: string;\n /**\n * Page geometry override. When **omitted**, the editor reads page settings\n * from `editor.doc` (the `docSettings` Y.Map populated via `setPageSettings`\n * or `import-docx`). When **set**, this value wins for rendering — but is\n * NOT written back to the Y.Doc (view-only override; useful when the host\n * app must pin a size regardless of doc state, e.g. a prova generator).\n * Pass **null** to disable pagination entirely (flat flow).\n */\n pageGeometry?: PageGeometry | null;\n /**\n * Custom page header. Receives `{ pageNumber, pageCount }` and renders inside\n * the top margin of every page (above the content area). Pass `null` to omit.\n */\n renderPageHeader?: PageRenderProp | null;\n /**\n * Custom page footer. Receives `{ pageNumber, pageCount }`. Defaults to\n * `\"<n> / <total>\"` centered. Pass `null` to omit.\n */\n renderPageFooter?: PageRenderProp | null;\n /**\n * Awareness do Yjs (de `useCollab().binding.awareness`). Quando presente,\n * o editor publica a seleção local e desenha os cursores/seleções dos outros\n * usuários (presença colaborativa). Omitir = sem cursores remotos.\n */\n awareness?: AwarenessLike;\n}\n\nconst defaultFooter: PageRenderProp = ({ pageNumber, pageCount }) =>\n `${pageNumber} / ${pageCount}`;\n\nexport function Editor({\n editor: providedEditor,\n className,\n pageGeometry,\n renderPageHeader,\n renderPageFooter = defaultFooter,\n awareness,\n}: EditorProps): JSX.Element {\n const internal = useEditor();\n const editor = providedEditor ?? internal;\n const { doc, history, snapshot, getSelection, setSelection } = editor;\n\n const rootRef = useRef<HTMLDivElement>(null);\n const isComposingRef = useRef(false);\n // The `behind` image the pointer is currently hovering (by geometry), so we\n // can show a click affordance to select it through the text on top of it.\n const [hoveredBehind, setHoveredBehind] = useState<{\n blockIndex: number;\n offset: number;\n cellIndex?: number;\n } | null>(null);\n const hoveredBehindRef = useRef<typeof hoveredBehind>(null);\n // The link the pointer is hovering — drives the URL tooltip (rect in viewport\n // coords). Tracked by element identity to avoid re-render churn on every move.\n const [hoveredLink, setHoveredLink] = useState<{\n href: string;\n rect: { top: number; left: number; bottom: number; width: number };\n } | null>(null);\n const hoveredLinkElRef = useRef<HTMLAnchorElement | null>(null);\n const suppressSelectionSyncRef = useRef(false);\n\n // Presença colaborativa: publica a seleção local no awareness (throttle por\n // rAF). Outros editores desenham nosso caret via RemoteCursorsOverlay.\n useEffect(() => {\n if (!awareness) return;\n const root = rootRef.current;\n if (!root) return;\n let raf: number | null = null;\n const publish = () => {\n raf = null;\n const sel = readDomSelection(root);\n awareness.setLocalStateField(\n \"cursor\",\n sel ? encodeSelection(doc, sel) ?? null : null,\n );\n };\n const onSelChange = () => {\n const s = document.getSelection();\n if (!s || s.rangeCount === 0) return;\n // Só publica quando a seleção está dentro do nosso editor.\n if (s.anchorNode && !root.contains(s.anchorNode)) return;\n if (raf != null) return;\n raf = requestAnimationFrame(publish);\n };\n const onBlur = () => awareness.setLocalStateField(\"cursor\", null);\n document.addEventListener(\"selectionchange\", onSelChange);\n root.addEventListener(\"blur\", onBlur, true);\n return () => {\n document.removeEventListener(\"selectionchange\", onSelChange);\n root.removeEventListener(\"blur\", onBlur, true);\n if (raf != null) cancelAnimationFrame(raf);\n awareness.setLocalStateField(\"cursor\", null);\n };\n }, [awareness, doc]);\n\n const ctxRef = useRef<CommandContext>({ doc, getSelection, setSelection });\n ctxRef.current = { doc, getSelection, setSelection };\n const historyRef = useRef(history);\n historyRef.current = history;\n const editorRef = useRef(editor);\n editorRef.current = editor;\n\n // Run after every render — not just when selection or snapshot change — so\n // we re-apply the caret after pagination's two-phase render cycle (which\n // mutates `layout` state without touching `editor.selection` or `snapshot`,\n // and tears down/rebuilds the text nodes the prior DOM selection was attached\n // to). The early-return when DOM already matches the model keeps this cheap.\n useLayoutEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n if (isComposingRef.current) return;\n if (document.activeElement !== root) return;\n const current = readDomSelection(root);\n if (current && selectionsEqual(current, editor.selection)) return;\n if (isTableRectSelection(editor.selection)) {\n // Cross-cell (rectangular) table selection: the native DOM selection is\n // intentionally empty — TableView paints the highlight via CSS classes.\n // Keep it empty but do NOT arm the suppress guard. The guard exists to\n // ignore render-collapsed carets while TYPING; for a rect selection the\n // empty native selection is the steady state, so arming it would make the\n // selectionchange handler ignore a genuine click-away — the rect would\n // stick in the model and the next keystroke would overwrite the selected\n // cells instead of writing at the clicked caret.\n applyDomSelection(root, editor.selection);\n suppressSelectionSyncRef.current = false;\n return;\n }\n // DOM caret diverged from the model — typically a re-render replaced the\n // text node and collapsed the native caret to offset 0. Suppress the\n // selectionchange handler until the DOM settles back to the model; otherwise\n // a render-induced selectionchange writes the collapsed caret over a newer\n // keystroke's selection and the caret jumps backward when typing fast.\n // Cleared deterministically in the selectionchange handler once the DOM\n // settles to the live model — NOT on a timer, because timers race the event.\n suppressSelectionSyncRef.current = true;\n applyDomSelection(root, editor.selection);\n });\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const handler = () => {\n if (isComposingRef.current) return;\n if (document.activeElement !== root) {\n // Focus left the editor — nothing to capture here. Release any pending\n // suppression so a stuck flag can't swallow the next genuine change.\n suppressSelectionSyncRef.current = false;\n return;\n }\n const modelSel = readDomSelection(root);\n if (suppressSelectionSyncRef.current) {\n // Mid-reconciliation: a render moved the caret. Resume capturing user\n // selection only once the DOM caret has settled to match the LIVE model\n // (our applyDomSelection landed). Transient render-collapsed carets\n // (DOM != model) are ignored — those are the spurious events that used\n // to clobber the model selection and make the caret jump back.\n if (modelSel && selectionsEqual(modelSel, editorRef.current.getSelection())) {\n suppressSelectionSyncRef.current = false;\n }\n return;\n }\n if (modelSel) setSelection(modelSel);\n };\n document.addEventListener(\"selectionchange\", handler);\n return () => document.removeEventListener(\"selectionchange\", handler);\n }, [setSelection]);\n\n // ---------- Sub-phase 4.5: rectangular table-cell drag ----------\n //\n // mousedown captures the anchor cell. mousemove flips into \"rect mode\" the\n // moment the pointer enters a DIFFERENT cell of the same table, at which\n // point we suppress the native cross-cell selection and write a rectangular\n // selection to the model. The visual highlight is drawn by TableView via\n // CSS classes (see isTableRectSelection in dom-bridge).\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n interface DragState {\n blockIndex: number;\n anchorCellIndex: number;\n anchorTableEl: HTMLTableElement;\n rectActive: boolean;\n }\n let drag: DragState | null = null;\n\n function cellFromTarget(target: EventTarget | null): {\n blockIndex: number;\n cellIndex: number;\n tableEl: HTMLTableElement;\n } | null {\n if (!(target instanceof Node)) return null;\n let n: Node | null = target;\n let cellEl: HTMLElement | null = null;\n let tableEl: HTMLTableElement | null = null;\n while (n && n !== root) {\n if (n.nodeType === Node.ELEMENT_NODE) {\n const e = n as HTMLElement;\n if (!cellEl && e.dataset.cellIndex != null) cellEl = e;\n if (e.tagName === \"TABLE\" && e.dataset.blockIndex != null) {\n tableEl = e as HTMLTableElement;\n break;\n }\n }\n n = n.parentNode;\n }\n if (!cellEl || !tableEl) return null;\n const cellIndex = Number.parseInt(cellEl.dataset.cellIndex!, 10);\n const blockIndex = Number.parseInt(tableEl.dataset.blockIndex!, 10);\n return { blockIndex, cellIndex, tableEl };\n }\n\n const onPointerDown = (e: PointerEvent) => {\n if (e.button !== 0) return;\n const hit = cellFromTarget(e.target);\n if (!hit) {\n drag = null;\n return;\n }\n drag = {\n blockIndex: hit.blockIndex,\n anchorCellIndex: hit.cellIndex,\n anchorTableEl: hit.tableEl,\n rectActive: false,\n };\n };\n\n const onPointerMove = (e: PointerEvent) => {\n if (!drag) return;\n // Only treat as drag when the primary button is still pressed.\n if ((e.buttons & 1) === 0) {\n drag = null;\n return;\n }\n const hit = cellFromTarget(e.target);\n if (!hit) return;\n if (hit.blockIndex !== drag.blockIndex) return; // never cross tables\n if (hit.cellIndex === drag.anchorCellIndex && !drag.rectActive) return;\n\n if (!drag.rectActive) {\n drag.rectActive = true;\n // Kill any in-progress native cross-cell selection.\n window.getSelection()?.removeAllRanges();\n }\n e.preventDefault();\n ctxRef.current.setSelection({\n anchor: { blockIndex: drag.blockIndex, cellIndex: drag.anchorCellIndex, offset: 0 },\n focus: { blockIndex: drag.blockIndex, cellIndex: hit.cellIndex, offset: 0 },\n });\n };\n\n const onPointerUp = () => {\n drag = null;\n };\n\n root.addEventListener(\"pointerdown\", onPointerDown);\n document.addEventListener(\"pointermove\", onPointerMove);\n document.addEventListener(\"pointerup\", onPointerUp);\n return () => {\n root.removeEventListener(\"pointerdown\", onPointerDown);\n document.removeEventListener(\"pointermove\", onPointerMove);\n document.removeEventListener(\"pointerup\", onPointerUp);\n };\n }, []);\n\n // ---------- Fase 5: drag-drop de imagens ----------\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const onDragOver = (e: DragEvent) => {\n if (!e.dataTransfer) return;\n const hasFiles = Array.from(e.dataTransfer.items ?? []).some(\n (i) => i.kind === \"file\",\n );\n if (!hasFiles) return;\n e.preventDefault();\n e.dataTransfer.dropEffect = \"copy\";\n };\n const onDrop = (e: DragEvent) => {\n if (!e.dataTransfer) return;\n const images = Array.from(e.dataTransfer.files).filter((f) =>\n f.type.startsWith(\"image/\"),\n );\n if (images.length === 0) return;\n e.preventDefault();\n // Position the caret at the drop point so the insertion lands there.\n const range = caretRangeFromPoint(e.clientX, e.clientY);\n if (range) {\n const dom = window.getSelection();\n dom?.removeAllRanges();\n dom?.addRange(range);\n const sel = readDomSelection(root);\n if (sel) ctxRef.current.setSelection(sel);\n }\n void (async () => {\n for (const f of images) await editorRef.current.insertImageFromFile(f);\n })();\n };\n root.addEventListener(\"dragover\", onDragOver);\n root.addEventListener(\"drop\", onDrop);\n return () => {\n root.removeEventListener(\"dragover\", onDragOver);\n root.removeEventListener(\"drop\", onDrop);\n };\n }, []);\n\n // ---------- Fase 5: clique numa imagem seleciona o embed ----------\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const onPointerDown = (e: PointerEvent) => {\n if (e.button !== 0) return;\n const target = e.target;\n if (!(target instanceof Element)) return;\n const img = target.closest('img[data-embed=\"image\"]') as HTMLElement | null;\n if (!img) return;\n const blockEl = img.closest(\"[data-block-index]\") as HTMLElement | null;\n if (!blockEl) return;\n const blockIndex = Number.parseInt(blockEl.dataset.blockIndex!, 10);\n const offsetAttr = img.dataset.embedOffset;\n if (offsetAttr == null) return;\n const localOffset = Number.parseInt(offsetAttr, 10);\n const fragmentStart = Number.parseInt(blockEl.dataset.fragmentStart ?? \"0\", 10) || 0;\n const cellEl = img.closest(\"[data-cell-index]\") as HTMLElement | null;\n const cellIndex = cellEl\n ? Number.parseInt(cellEl.dataset.cellIndex!, 10)\n : undefined;\n const offset = fragmentStart + localOffset;\n e.preventDefault();\n ctxRef.current.setSelection({\n anchor: { blockIndex, cellIndex, offset },\n focus: { blockIndex, cellIndex, offset: offset + 1 },\n });\n };\n root.addEventListener(\"pointerdown\", onPointerDown);\n return () => root.removeEventListener(\"pointerdown\", onPointerDown);\n }, []);\n\n // Hover detection for `behind` images: they sit at z-index:-1, so the text on\n // top intercepts clicks and the image can't be selected by clicking there. On\n // pointer move we find — BY GEOMETRY — the behind image under the pointer and\n // expose a select affordance (rendered below). Throttled to one check/frame.\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const same = (\n a: typeof hoveredBehind,\n b: typeof hoveredBehind,\n ): boolean =>\n a === b ||\n (!!a &&\n !!b &&\n a.blockIndex === b.blockIndex &&\n a.offset === b.offset &&\n (a.cellIndex ?? -1) === (b.cellIndex ?? -1));\n const set = (next: typeof hoveredBehind) => {\n if (same(next, hoveredBehindRef.current)) return;\n hoveredBehindRef.current = next;\n setHoveredBehind(next);\n };\n let raf = 0;\n const onMove = (e: PointerEvent) => {\n if (raf) return;\n const x = e.clientX;\n const y = e.clientY;\n raf = requestAnimationFrame(() => {\n raf = 0;\n const imgs = root.querySelectorAll<HTMLImageElement>(\n 'img[data-embed=\"image\"][data-embed-layout=\"behind\"]',\n );\n let hit: HTMLImageElement | null = null;\n for (const img of imgs) {\n const r = img.getBoundingClientRect();\n if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) {\n hit = img;\n break;\n }\n }\n if (!hit) {\n set(null);\n return;\n }\n const blockEl = hit.closest<HTMLElement>(\"[data-block-index]\");\n const offsetAttr = hit.dataset.embedOffset;\n if (!blockEl || offsetAttr == null) {\n set(null);\n return;\n }\n const blockIndex = Number.parseInt(blockEl.dataset.blockIndex!, 10);\n const fragmentStart = Number.parseInt(blockEl.dataset.fragmentStart ?? \"0\", 10) || 0;\n const cellEl = hit.closest<HTMLElement>(\"[data-cell-index]\");\n const cellIndex = cellEl\n ? Number.parseInt(cellEl.dataset.cellIndex!, 10)\n : undefined;\n set({ blockIndex, offset: fragmentStart + Number.parseInt(offsetAttr, 10), cellIndex });\n });\n };\n const onLeave = () => set(null);\n root.addEventListener(\"pointermove\", onMove);\n root.addEventListener(\"pointerleave\", onLeave);\n return () => {\n root.removeEventListener(\"pointermove\", onMove);\n root.removeEventListener(\"pointerleave\", onLeave);\n if (raf) cancelAnimationFrame(raf);\n };\n }, []);\n\n // Link hover tooltip: show the URL while the pointer is over a link. Uses\n // `mouseover` delegation (fires on element enter, far cheaper than mousemove)\n // and tracks the hovered <a> by identity to avoid re-render churn. Cleared on\n // leave/scroll (the cached viewport rect would otherwise go stale).\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const clear = () => {\n if (hoveredLinkElRef.current) {\n hoveredLinkElRef.current = null;\n setHoveredLink(null);\n }\n };\n const onOver = (e: MouseEvent) => {\n const target = e.target as Element | null;\n const a = target?.closest?.(\"a[href]\") as HTMLAnchorElement | null;\n if (a && root.contains(a)) {\n if (hoveredLinkElRef.current === a) return;\n hoveredLinkElRef.current = a;\n const r = a.getBoundingClientRect();\n setHoveredLink({\n href: a.getAttribute(\"href\") ?? \"\",\n rect: { top: r.top, left: r.left, bottom: r.bottom, width: r.width },\n });\n } else {\n clear();\n }\n };\n root.addEventListener(\"mouseover\", onOver);\n root.addEventListener(\"mouseleave\", clear);\n root.addEventListener(\"scroll\", clear, true);\n window.addEventListener(\"scroll\", clear, true);\n return () => {\n root.removeEventListener(\"mouseover\", onOver);\n root.removeEventListener(\"mouseleave\", clear);\n root.removeEventListener(\"scroll\", clear, true);\n window.removeEventListener(\"scroll\", clear, true);\n };\n }, []);\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n const handler = (e: InputEvent) => {\n const ctx = ctxRef.current;\n const hist = historyRef.current;\n const ed = editorRef.current;\n const type = e.inputType;\n\n if (isComposingRef.current && type === \"insertCompositionText\") return;\n\n switch (type) {\n case \"insertText\": {\n const data = e.data ?? \"\";\n if (data.length > 0) {\n e.preventDefault();\n insertText(ctx, data, ed.consumePendingMarks());\n }\n return;\n }\n case \"insertLineBreak\": {\n // Shift+Enter inside a listItem inserts a soft line break (`\\n`)\n // INSIDE the item instead of splitting it into a new numbered entry\n // — useful for spacing between question lines without bumping the\n // numbering. Other blocks fall through to the regular paragraph\n // split (= same as Enter), because TipTap-style \"soft break\" inside\n // a paragraph isn't part of this model.\n e.preventDefault();\n if (ed.getBlockType() === \"listItem\") {\n insertText(ctx, \"\\n\", ed.consumePendingMarks());\n return;\n }\n // Fall through to the same path as insertParagraph.\n const selEmbed = ed.getSelectedEmbed();\n if (selEmbed) {\n const off = selEmbed.offset + 1;\n ctx.setSelection({\n anchor: {\n blockIndex: selEmbed.blockIndex,\n cellIndex: selEmbed.cellIndex,\n offset: off,\n },\n focus: {\n blockIndex: selEmbed.blockIndex,\n cellIndex: selEmbed.cellIndex,\n offset: off,\n },\n });\n }\n if (ed.splitListItem()) return;\n insertParagraph(ctx);\n return;\n }\n case \"insertParagraph\": {\n e.preventDefault();\n // If an embed is the entire selection, drop the caret RIGHT AFTER it\n // before splitting — otherwise the default \"delete range then insert\n // paragraph\" path would remove the image.\n const selectedEmbed = ed.getSelectedEmbed();\n if (selectedEmbed) {\n const off = selectedEmbed.offset + 1;\n ctx.setSelection({\n anchor: {\n blockIndex: selectedEmbed.blockIndex,\n cellIndex: selectedEmbed.cellIndex,\n offset: off,\n },\n focus: {\n blockIndex: selectedEmbed.blockIndex,\n cellIndex: selectedEmbed.cellIndex,\n offset: off,\n },\n });\n }\n if (ed.splitListItem()) return;\n insertParagraph(ctx);\n return;\n }\n case \"insertReplacementText\": {\n const text = e.data ?? e.dataTransfer?.getData(\"text/plain\") ?? \"\";\n if (text.length > 0) {\n e.preventDefault();\n insertText(ctx, text, ed.consumePendingMarks());\n }\n return;\n }\n case \"insertFromPaste\": {\n // Paste é tratado pelo handler `paste` (useEffect de clipboard). Quando\n // ele NÃO faz preventDefault (ex.: clipboard só com text/html, ou sem\n // clipboardData), o browser cai aqui — este no-op bloqueia a inserção\n // crua no DOM em vez de corromper o documento virtual.\n e.preventDefault();\n return;\n }\n case \"deleteContentBackward\":\n case \"deleteWordBackward\":\n case \"deleteSoftLineBackward\":\n case \"deleteHardLineBackward\": {\n e.preventDefault();\n deleteBackward(ctx);\n return;\n }\n case \"deleteContentForward\":\n case \"deleteWordForward\":\n case \"deleteSoftLineForward\":\n case \"deleteHardLineForward\": {\n e.preventDefault();\n deleteForward(ctx);\n return;\n }\n case \"historyUndo\": {\n e.preventDefault();\n hist.undo();\n return;\n }\n case \"historyRedo\": {\n e.preventDefault();\n hist.redo();\n return;\n }\n default: {\n e.preventDefault();\n return;\n }\n }\n };\n\n root.addEventListener(\"beforeinput\", handler);\n return () => root.removeEventListener(\"beforeinput\", handler);\n }, []);\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n const writeSlice = (e: ClipboardEvent): boolean => {\n const ctx = ctxRef.current;\n const slice = serializeSelection(ctx.doc, ctx.getSelection());\n if (!slice || !e.clipboardData) return false;\n e.clipboardData.setData(SOFER_MIME, JSON.stringify(slice));\n e.clipboardData.setData(\"text/plain\", sliceToText(slice));\n return true;\n };\n\n const onCopy = (e: ClipboardEvent) => {\n if (writeSlice(e)) e.preventDefault();\n };\n\n const onCut = (e: ClipboardEvent) => {\n // Always block the native cut: it mutates the contenteditable DOM directly\n // and would write its own clipboard serialization. When we have a slice we\n // delete via the model; an unsupported selection (writeSlice false) becomes\n // a clean no-op instead of a \"cut that doesn't delete\".\n e.preventDefault();\n if (writeSlice(e)) deleteSelection(ctxRef.current);\n };\n\n const onPaste = (e: ClipboardEvent) => {\n const ctx = ctxRef.current;\n const cd = e.clipboardData;\n if (!cd) return;\n // 1) Our own rich slice.\n const raw = cd.getData(SOFER_MIME);\n if (raw) {\n try {\n const slice = JSON.parse(raw) as ClipboardSlice;\n if (slice && Array.isArray(slice.blocks)) {\n e.preventDefault();\n insertSlice(ctx, slice);\n return;\n }\n } catch {\n // fall through to plain handling\n }\n }\n // 2) Image files (OS paste).\n const images = Array.from(cd.files ?? []).filter((f) => f.type.startsWith(\"image/\"));\n if (images.length > 0) {\n e.preventDefault();\n void (async () => {\n for (const f of images) await editorRef.current.insertImageFromFile(f);\n })();\n return;\n }\n // 3) Plain text.\n const text = cd.getData(\"text/plain\");\n if (text.length === 0) return;\n e.preventDefault();\n const lines = text.split(/\\r\\n|\\r|\\n/);\n lines.forEach((line, i) => {\n if (i > 0) insertParagraph(ctx);\n if (line.length > 0) insertText(ctx, line);\n });\n };\n\n root.addEventListener(\"copy\", onCopy);\n root.addEventListener(\"cut\", onCut);\n root.addEventListener(\"paste\", onPaste);\n return () => {\n root.removeEventListener(\"copy\", onCopy);\n root.removeEventListener(\"cut\", onCut);\n root.removeEventListener(\"paste\", onPaste);\n };\n }, []);\n\n const onKeyDown = useCallback((e: KeyboardEvent<HTMLDivElement>) => {\n const ed = editorRef.current;\n const mod = e.metaKey || e.ctrlKey;\n\n if (e.key === \"Tab\") {\n e.preventDefault();\n // Inside a table, Tab/Shift+Tab navigates between cells; at the last\n // cell Tab appends a new row.\n if (ed.isInTable()) {\n if (e.shiftKey) ed.moveToPrevCell();\n else ed.moveToNextCell();\n return;\n }\n if (e.shiftKey) ed.dedentList();\n else ed.indentList();\n return;\n }\n\n // Home/End: move the caret to the visual start/end of the current line.\n // The default contenteditable behavior is inconsistent with paginated\n // fragments — Chrome occasionally jumps to the start/end of the block\n // element instead of the visual line. We explicitly use the native\n // `Selection.modify(\"lineboundary\")` API (Chrome/Edge/Safari) which\n // respects visual line wrapping inside any contenteditable.\n //\n // `Cmd/Ctrl+Home/End` keep the default browser behavior (document scroll).\n if (!mod && (e.key === \"Home\" || e.key === \"End\")) {\n const root = rootRef.current;\n const sel = window.getSelection();\n const sm = (sel as unknown as { modify?: (alter: string, direction: string, granularity: string) => void })?.modify;\n if (root && sel && sel.rangeCount > 0 && typeof sm === \"function\") {\n e.preventDefault();\n const alter = e.shiftKey ? \"extend\" : \"move\";\n const direction = e.key === \"Home\" ? \"left\" : \"right\";\n sm.call(sel, alter, direction, \"lineboundary\");\n const modelSel = readDomSelection(root);\n if (modelSel) ctxRef.current.setSelection(modelSel);\n }\n return;\n }\n\n if (!mod) return;\n const key = e.key.toLowerCase();\n\n if (!e.shiftKey && !e.altKey && key === \"z\") {\n e.preventDefault();\n historyRef.current.undo();\n return;\n }\n if (!e.altKey && (key === \"y\" || (e.shiftKey && key === \"z\"))) {\n e.preventDefault();\n historyRef.current.redo();\n return;\n }\n\n if (e.altKey && !e.shiftKey && /^[0-6]$/.test(key)) {\n e.preventDefault();\n const n = Number(key);\n if (n === 0) ed.setBlockType(\"paragraph\");\n else ed.setBlockType(\"heading\", { level: n as 1 | 2 | 3 | 4 | 5 | 6 });\n return;\n }\n\n if (e.shiftKey && !e.altKey && (key === \"7\" || key === \"8\")) {\n e.preventDefault();\n ed.toggleList(key === \"7\" ? \"ordered\" : \"bullet\");\n return;\n }\n\n const markToggle = !e.shiftKey && !e.altKey\n ? (BOOLEAN_SHORTCUTS[key] as MarkName | undefined)\n : undefined;\n if (markToggle) {\n e.preventDefault();\n ed.toggleMark(markToggle);\n return;\n }\n if (e.shiftKey && !e.altKey && key === \"x\") {\n e.preventDefault();\n ed.toggleMark(\"strike\");\n return;\n }\n\n if (!e.altKey && !e.shiftKey && key === \"k\") {\n e.preventDefault();\n const active = ed.getActiveMarks();\n const currentHref =\n active.link && typeof active.link === \"object\" && \"href\" in active.link\n ? (active.link.href as string)\n : \"\";\n void ed.requestLink(currentHref).then((href) => {\n if (href === null) return;\n if (href === \"\") ed.removeMark(\"link\");\n else ed.setMark(\"link\", { href });\n });\n }\n }, []);\n\n const onCompositionStart = useCallback(() => {\n isComposingRef.current = true;\n }, []);\n\n const onCompositionEnd = useCallback((e: React.CompositionEvent<HTMLDivElement>) => {\n isComposingRef.current = false;\n if (e.data && e.data.length > 0) {\n insertText(ctxRef.current, e.data);\n }\n }, []);\n\n const topLevels = useMemo(() => groupTopLevels(snapshot.blocks), [snapshot]);\n // Chave estrutural dos topLevels: muda só quando a SHAPE muda (tipos,\n // contagem de itens em lists, list kind/style/start), não quando o texto\n // dentro de um block é editado. Usada como dep do `usePageLayout` em\n // lugar do array `topLevels` (cuja referência muda a cada keystroke), o\n // que cortava repaginações desnecessárias — antes 1.3M DOM mutations\n // por ~10 teclas viraram zero. O array `topLevels` em si continua fresh\n // pra `renderSlot` ler o texto atualizado de cada block.\n const topLevelsStructuralKey = useMemo(\n () =>\n topLevels\n .map((t) =>\n t.kind === \"list\"\n ? `L:${t.listKind}:${t.items.length}:${t.ordinalStart}`\n : `B:${t.block.type}:${t.block.attrs.level ?? \"\"}`,\n )\n .join(\"|\"),\n [topLevels],\n );\n // Page geometry sources, in precedence order:\n // 1. `pageGeometry` prop when explicitly set (view-only override — does NOT\n // write back to the Y.Doc; useful for apps that force a fixed size, e.g.\n // prova generator pinned to A4).\n // 2. `editor.doc` page settings (Y.Doc-backed, sync-aware).\n // 3. `A4_PAGE` fallback when both unavailable.\n // `pageGeometry={null}` continues to disable pagination entirely.\n const docSettings = usePageSettings(editor.doc);\n const propIsSet = pageGeometry !== undefined;\n const geom: PageGeometry = propIsSet ? (pageGeometry ?? A4_PAGE) : docSettings;\n const paginated = pageGeometry !== null;\n // Reads from snapshot + selection; recomputed on every render.\n const selectedEmbed = editor.getSelectedEmbed();\n\n const { layout, phase: paginationPhase } = usePageLayout(\n rootRef as RefObject<HTMLElement>,\n geom,\n topLevels.length,\n // Usar a chave estrutural (string) em vez do array `topLevels` direto:\n // o array reference muda a cada keystroke, mas a chave só muda quando\n // a SHAPE dos top-levels muda. `usePageLayout` compara deps via\n // `shallowArrayEqual` — string equality cobre isso.\n [topLevelsStructuralKey, pageGeometry],\n );\n\n const effectiveLayout: PageLayout = paginated ? layout : defaultPageLayout(topLevels.length);\n\n // pageStyle memoizado: CSS custom properties são HERDADAS, então qualquer\n // toggle de `style` no `.ed-root` invalidava estilos em todos os\n // descendentes (~165k elementos no caso do bug histórico) e alimentava\n // style recalc pesado a cada keystroke. Memo aqui mantém a mesma\n // referência enquanto width/height/margens não mudam.\n const pageStyle = useMemo(\n () =>\n paginated\n ? ({\n \"--ed-page-width\": `${geom.width}px`,\n \"--ed-page-height\": `${geom.height}px`,\n \"--ed-page-margin-top\": `${geom.marginTop}px`,\n \"--ed-page-margin-bottom\": `${geom.marginBottom}px`,\n \"--ed-page-margin-left\": `${geom.marginLeft}px`,\n \"--ed-page-margin-right\": `${geom.marginRight}px`,\n } as React.CSSProperties)\n : undefined,\n [\n paginated,\n geom.width,\n geom.height,\n geom.marginTop,\n geom.marginBottom,\n geom.marginLeft,\n geom.marginRight,\n ],\n );\n\n const body = (\n <div\n ref={rootRef}\n contentEditable\n suppressContentEditableWarning\n spellCheck\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n role=\"textbox\"\n aria-multiline=\"true\"\n className={\n (className ?? \"ed-root\") + (paginated ? \" ed-root--paged\" : \" ed-root--flat\")\n }\n data-pagination-phase={paginated ? paginationPhase : undefined}\n style={pageStyle}\n onKeyDown={onKeyDown}\n onCompositionStart={onCompositionStart}\n onCompositionEnd={onCompositionEnd}\n >\n {paginated\n ? effectiveLayout.pages.map((page, pi) => {\n const ctx: PageRenderContext = {\n pageNumber: pi + 1,\n pageCount: effectiveLayout.pages.length,\n };\n // Apenas a pág 1 recebe o `firstPageExtraTop` adicional. Inline\n // style sobrescreve a CSS var herdada do `.ed-root` (que vale para\n // as páginas seguintes).\n const pageInlineStyle =\n pi === 0 && geom.firstPageExtraTop\n ? ({\n \"--ed-page-margin-top\": `${geom.marginTop + geom.firstPageExtraTop}px`,\n } as React.CSSProperties)\n : undefined;\n return (\n <div\n key={`page-${pi}`}\n className=\"ed-page\"\n data-page-number={ctx.pageNumber}\n data-page-total={ctx.pageCount}\n style={pageInlineStyle}\n >\n {renderPageHeader && (\n <div className=\"ed-page-header\" contentEditable={false}>\n {renderPageHeader(ctx)}\n </div>\n )}\n <div className=\"ed-page-content\">\n {page.slots.map((slot) => renderSlot(slot, topLevels))}\n </div>\n {renderPageFooter && (\n <div className=\"ed-page-footer\" contentEditable={false}>\n {renderPageFooter(ctx)}\n </div>\n )}\n </div>\n );\n })\n : topLevels.map((t) => renderTopLevel(t))}\n {selectedEmbed && (\n <ImageResizeOverlay\n rootRef={rootRef}\n blockIndex={selectedEmbed.blockIndex}\n offset={selectedEmbed.offset}\n cellIndex={selectedEmbed.cellIndex}\n embed={selectedEmbed.embed}\n onCommit={(w, h) =>\n editor.setImageAttrs(\n selectedEmbed.blockIndex,\n selectedEmbed.offset,\n { width: w, height: h },\n selectedEmbed.cellIndex,\n )\n }\n onCommitMove={(ox, oy) =>\n editor.setImageAttrs(\n selectedEmbed.blockIndex,\n selectedEmbed.offset,\n { offsetX: ox, offsetY: oy },\n selectedEmbed.cellIndex,\n )\n }\n onReanchor={(to, ox, oy) =>\n editor.moveEmbedAnchor(\n {\n blockIndex: selectedEmbed.blockIndex,\n offset: selectedEmbed.offset,\n cellIndex: selectedEmbed.cellIndex,\n },\n to,\n ox,\n oy,\n )\n }\n />\n )}\n {hoveredBehind &&\n !(\n selectedEmbed &&\n selectedEmbed.blockIndex === hoveredBehind.blockIndex &&\n selectedEmbed.offset === hoveredBehind.offset &&\n (selectedEmbed.cellIndex ?? -1) === (hoveredBehind.cellIndex ?? -1)\n ) && (\n <BehindImageSelectAffordance\n rootRef={rootRef}\n blockIndex={hoveredBehind.blockIndex}\n offset={hoveredBehind.offset}\n cellIndex={hoveredBehind.cellIndex}\n onSelect={() =>\n setSelection({\n anchor: {\n blockIndex: hoveredBehind.blockIndex,\n cellIndex: hoveredBehind.cellIndex,\n offset: hoveredBehind.offset,\n },\n focus: {\n blockIndex: hoveredBehind.blockIndex,\n cellIndex: hoveredBehind.cellIndex,\n offset: hoveredBehind.offset + 1,\n },\n })\n }\n />\n )}\n {hoveredLink && hoveredLink.href && (\n <LinkHoverTooltip href={hoveredLink.href} rect={hoveredLink.rect} />\n )}\n {awareness && (\n <RemoteCursorsOverlay\n rootRef={rootRef}\n doc={doc}\n awareness={awareness}\n revision={snapshot}\n />\n )}\n </div>\n );\n\n return <EditorProvider editor={editor}>{body}</EditorProvider>;\n}\n\n// ---------- Top-level grouping (data, not JSX) ----------\n\ninterface ListEntry {\n block: SerializedBlock;\n index: number;\n}\n\ntype TopLevel =\n | { kind: \"block\"; block: SerializedBlock; blockIndex: number; key: number }\n | {\n kind: \"list\";\n items: ListEntry[];\n listKind: ListKind;\n /**\n * Number to seed the `<ol>` `start` attribute. Pulled from the first\n * item's `listStart` attr, defaulting to 1. Only meaningful for\n * `listKind === \"ordered\"`.\n */\n ordinalStart: number;\n /**\n * Optional CSS `list-style-type` override for this group. Pulled from\n * the first item's `listStyle` attr. Undefined means \"use the cascade\n * cycle from sofer-editor.css\".\n */\n listStyle?: string;\n key: number;\n };\n\nfunction groupTopLevels(snapshot: SerializedBlock[]): TopLevel[] {\n const out: TopLevel[] = [];\n let i = 0;\n while (i < snapshot.length) {\n const block = snapshot[i];\n if (block.type === \"listItem\") {\n const groupStart = i;\n const items: ListEntry[] = [];\n const kind: ListKind = block.attrs.listKind === \"ordered\" ? \"ordered\" : \"bullet\";\n const groupStyle = block.attrs.listStyle as string | undefined;\n // A `listStart` on the FIRST item of the group seeds the `<ol start>`.\n // A `listStart` or `listStyle` on a LATER item breaks the group at that\n // item — its first item becomes the seed of the next group.\n while (i < snapshot.length) {\n const b = snapshot[i];\n if (b.type !== \"listItem\") break;\n if ((b.attrs.listKind ?? \"bullet\") !== kind) break;\n if (i > groupStart) {\n // Continuation: break the group ONLY when this item EXPLICITLY\n // declares a renumbering. An undefined `listStart` / `listStyle`\n // means \"inherit from the current group leader\" — that's the\n // common case (user only tags the first item of the new sequence).\n if (typeof b.attrs.listStart === \"number\") break;\n const itemStyle = b.attrs.listStyle as string | undefined;\n if (itemStyle !== undefined && itemStyle !== groupStyle) break;\n }\n items.push({ block: b, index: i });\n i++;\n }\n const firstAttrs = items[0].block.attrs;\n const ordinalStart =\n typeof firstAttrs.listStart === \"number\" && firstAttrs.listStart > 0\n ? firstAttrs.listStart\n : 1;\n out.push({\n kind: \"list\",\n items,\n listKind: kind,\n ordinalStart,\n listStyle: groupStyle,\n key: groupStart,\n });\n continue;\n }\n out.push({ kind: \"block\", block, blockIndex: i, key: i });\n i++;\n }\n return out;\n}\n\nfunction renderSlot(slot: PageSlot, topLevels: TopLevel[]): JSX.Element | null {\n const top = topLevels[slot.topLevelIndex];\n if (!top) return null;\n if (slot.fragment && top.kind === \"block\") {\n const f: NodeViewFragment = {\n index: slot.fragment.index,\n start: slot.fragment.start,\n end: slot.fragment.end,\n };\n return (\n <NodeView\n key={`${top.key}-f${f.index}`}\n block={top.block}\n index={top.blockIndex}\n fragment={f}\n />\n );\n }\n if (slot.tableFragment && top.kind === \"block\" && top.block.type === \"table\") {\n return (\n <NodeView\n key={`${top.key}-tf${slot.tableFragment.index}`}\n block={top.block}\n index={top.blockIndex}\n tableFragment={slot.tableFragment}\n />\n );\n }\n if (slot.listFragment && top.kind === \"list\") {\n return renderListFragment(top, slot.listFragment);\n }\n return renderTopLevel(top);\n}\n\nfunction renderTopLevel(top: TopLevel): JSX.Element {\n if (top.kind === \"list\") {\n const tree = buildListTree(top.items);\n return renderListTree(tree, top, top.ordinalStart, `list-${top.key}`);\n }\n return <NodeView key={top.key} block={top.block} index={top.blockIndex} />;\n}\n\n/**\n * Render a sub-range of a list group's top-level items, as produced by\n * `placeFragmentedList`. The continuation `<ol>` carries an adjusted `start`\n * so numbering remains contiguous across the page break.\n */\nfunction renderListFragment(top: TopLevel & { kind: \"list\" }, frag: { index: number; itemStart: number; itemEnd: number }): JSX.Element {\n const ranges = topLevelItemRanges(top.items);\n const startRange = ranges[frag.itemStart];\n const endRange = ranges[frag.itemEnd - 1];\n if (!startRange || !endRange) return renderTopLevel(top);\n const sliced = top.items.slice(startRange[0], endRange[1]);\n // Continuation start = group's seed + count of top-level items already on prior pages.\n const ordinalStart = top.ordinalStart + frag.itemStart;\n const key = `list-${top.key}-f${frag.index}`;\n const slicedTop: TopLevel & { kind: \"list\" } = { ...top, items: sliced };\n const tree = buildListTree(sliced);\n return renderListTree(tree, slicedTop, ordinalStart, key);\n}\n\n/**\n * Index ranges within a flat `ListEntry[]` corresponding to each top-level\n * (level-0) item plus its nested descendants. Used by `renderListFragment` to\n * slice the flat list on a top-level boundary that matches what the paginator\n * measured against direct `<li>` children.\n */\nfunction topLevelItemRanges(items: ListEntry[]): Array<[number, number]> {\n const out: Array<[number, number]> = [];\n let currentStart = -1;\n items.forEach((it, idx) => {\n const level = clampListLevel(it.block.attrs.listLevel);\n if (level === 0) {\n if (currentStart >= 0) out.push([currentStart, idx]);\n currentStart = idx;\n }\n });\n if (currentStart >= 0) out.push([currentStart, items.length]);\n return out;\n}\n\ninterface ListNode {\n entry: ListEntry;\n children: ListNode[];\n}\n\nfunction buildListTree(items: ListEntry[]): ListNode[] {\n const roots: ListNode[] = [];\n const stack: { children: ListNode[]; level: number }[] = [{ children: roots, level: -1 }];\n for (const it of items) {\n const level = clampListLevel(it.block.attrs.listLevel);\n while (stack.length > 1 && stack[stack.length - 1].level >= level) stack.pop();\n const node: ListNode = { entry: it, children: [] };\n stack[stack.length - 1].children.push(node);\n stack.push({ children: node.children, level });\n }\n return roots;\n}\n\nfunction renderListTree(\n tree: ListNode[],\n top: TopLevel & { kind: \"list\" },\n start: number,\n key: string,\n): JSX.Element {\n const className = `ed-list ed-list-${top.listKind}`;\n const style: React.CSSProperties | undefined = top.listStyle\n ? { listStyleType: top.listStyle }\n : undefined;\n const items = tree.map((node) => (\n <NodeView key={node.entry.index} block={node.entry.block} index={node.entry.index}>\n {node.children.length > 0\n ? renderNestedListTree(node.children, top.listKind, `nested-${node.entry.index}`)\n : null}\n </NodeView>\n ));\n if (top.listKind === \"ordered\") {\n return (\n <ol\n key={key}\n className={className}\n data-list-kind=\"ordered\"\n start={start > 1 ? start : undefined}\n style={style}\n >\n {items}\n </ol>\n );\n }\n return (\n <ul key={key} className={className} data-list-kind=\"bullet\" style={style}>\n {items}\n </ul>\n );\n}\n\n/**\n * Nested sub-lists never carry an explicit `start`/`listStyle` from a parent\n * item: the cascade in `sofer-editor.css` handles the per-level style cycle\n * (decimal → lower-alpha → lower-roman). Only the TOP-level `<ol>` for a\n * group needs an explicit `start`/`listStyleType`.\n */\nfunction renderNestedListTree(tree: ListNode[], kind: ListKind, key: string): JSX.Element {\n const Tag = kind === \"ordered\" ? \"ol\" : \"ul\";\n return (\n <Tag key={key} className={`ed-list ed-list-${kind}`} data-list-kind={kind}>\n {tree.map((node) => (\n <NodeView key={node.entry.index} block={node.entry.block} index={node.entry.index}>\n {node.children.length > 0\n ? renderNestedListTree(node.children, kind, `nested-${node.entry.index}`)\n : null}\n </NodeView>\n ))}\n </Tag>\n );\n}\n\nfunction clampListLevel(l: unknown): number {\n if (typeof l !== \"number\" || !Number.isFinite(l)) return 0;\n return Math.max(0, Math.min(5, Math.trunc(l)));\n}\n\nconst BOOLEAN_SHORTCUTS: Record<string, MarkName> = {\n b: \"bold\",\n i: \"italic\",\n u: \"underline\",\n};\n\ninterface CaretRangeFromPoint {\n caretRangeFromPoint(x: number, y: number): Range | null;\n}\ninterface CaretPositionFromPoint {\n caretPositionFromPoint(\n x: number,\n y: number,\n ): { offsetNode: Node; offset: number } | null;\n}\n\nfunction caretRangeFromPoint(x: number, y: number): Range | null {\n const doc = document as unknown as Partial<CaretRangeFromPoint & CaretPositionFromPoint>;\n if (typeof doc.caretRangeFromPoint === \"function\") {\n return doc.caretRangeFromPoint(x, y);\n }\n if (typeof doc.caretPositionFromPoint === \"function\") {\n const pos = doc.caretPositionFromPoint(x, y);\n if (!pos) return null;\n const range = document.createRange();\n range.setStart(pos.offsetNode, pos.offset);\n range.collapse(true);\n return range;\n }\n return null;\n}\n","import type { Position, Selection } from \"@sofereditor/core\";\n\n/**\n * Mapping between the model and the contenteditable DOM.\n *\n * Each block is rendered as one or more elements carrying `data-block-index`.\n * Unfragmented blocks have a single such element. A paragraph fragmented across\n * pages (Sub-phase 3.2) has multiple elements with the same `data-block-index`,\n * each carrying `data-fragment-start` / `data-fragment-end` indicating the\n * character offsets within the block's text that the element covers.\n *\n * Table blocks (Sub-phase 4.1) render the `<table>` itself with `data-block-index`.\n * Each `<td>` cell carries `data-cell-index` (flat row-major). Model positions\n * inside a table always include `cellIndex`; their `offset` is local to that\n * cell's text.\n */\n\n/** Walks up from `node` to the first ancestor that carries `data-block-index`. */\nfunction findContainingBlockElement(node: Node, root: HTMLElement): HTMLElement | null {\n let cur: Node | null = node;\n while (cur && cur !== root) {\n if (cur.nodeType === Node.ELEMENT_NODE) {\n const el = cur as HTMLElement;\n if (el.dataset.blockIndex != null) return el;\n }\n cur = cur.parentNode;\n }\n return null;\n}\n\n/** Walks up to the first ancestor carrying `data-cell-index`, stopping at the block element. */\nfunction findContainingCellElement(\n node: Node,\n blockEl: HTMLElement,\n): HTMLElement | null {\n let cur: Node | null = node;\n while (cur && cur !== blockEl) {\n if (cur.nodeType === Node.ELEMENT_NODE) {\n const el = cur as HTMLElement;\n if (el.dataset.cellIndex != null) return el;\n }\n cur = cur.parentNode;\n }\n return null;\n}\n\nexport function findBlockIndex(node: Node, root: HTMLElement): number | null {\n const el = findContainingBlockElement(node, root);\n if (!el) return null;\n return Number.parseInt(el.dataset.blockIndex!, 10);\n}\n\n/**\n * Returns the first DOM element for `blockIndex`. For a fragmented block this\n * is the first fragment. Prefer `getFragmentForOffset` when you need the\n * fragment that contains a specific offset.\n */\nexport function getBlockElement(root: HTMLElement, blockIndex: number): HTMLElement | null {\n return root.querySelector<HTMLElement>(`[data-block-index=\"${blockIndex}\"]`);\n}\n\nfunction readFragmentStart(el: HTMLElement): number {\n const s = el.dataset.fragmentStart;\n if (s == null) return 0;\n const n = Number.parseInt(s, 10);\n return Number.isFinite(n) ? n : 0;\n}\n\nfunction readFragmentEnd(el: HTMLElement): number | undefined {\n const s = el.dataset.fragmentEnd;\n if (s == null) return undefined;\n const n = Number.parseInt(s, 10);\n return Number.isFinite(n) ? n : undefined;\n}\n\n/**\n * Returns the DOM element responsible for `offset` inside `blockIndex`.\n * - Unfragmented block (single element): returns it.\n * - Fragmented block: returns the fragment whose `[start, end)` covers `offset`.\n * For the end-of-block offset, returns the last fragment.\n */\nexport function getFragmentForOffset(\n root: HTMLElement,\n blockIndex: number,\n offset: number,\n): HTMLElement | null {\n const candidates = root.querySelectorAll<HTMLElement>(`[data-block-index=\"${blockIndex}\"]`);\n if (candidates.length === 0) return null;\n if (candidates.length === 1) return candidates[0];\n let last: HTMLElement | null = null;\n for (const el of candidates) {\n last = el;\n const start = readFragmentStart(el);\n const end = readFragmentEnd(el);\n if (end == null) return el;\n if (offset >= start && offset < end) return el;\n }\n return last; // end-of-block offset falls on the last fragment\n}\n\n/**\n * Returns the `<td>` element for `(blockIndex, cellIndex)`. Tables are\n * unfragmented in 4.1 so there's at most one block element to search inside.\n */\nexport function getCellElement(\n root: HTMLElement,\n blockIndex: number,\n cellIndex: number,\n): HTMLElement | null {\n const blockEl = getBlockElement(root, blockIndex);\n if (!blockEl) return null;\n return blockEl.querySelector<HTMLElement>(`[data-cell-index=\"${cellIndex}\"]`);\n}\n\n/**\n * `true` when `el` is an image embed (a length-1 atomic insert in the model).\n * Image embeds participate in offset arithmetic as 1 char each. Intentionally\n * not a type predicate — narrowing `n is HTMLElement` would collapse the\n * \"already an HTMLElement\" path to `never` and break downstream code.\n */\nfunction isImgEmbed(n: Node): boolean {\n return (\n n.nodeType === Node.ELEMENT_NODE &&\n (n as HTMLElement).dataset.embed === \"image\"\n );\n}\n\n/**\n * `true` when `el` is the float-wrap anchor `<img>` rendered at the START of a\n * block (so CSS float can wrap text around it). The model places this embed at\n * its original offset — represented in the DOM by a zero-width phantom span —\n * so the anchor itself must be SKIPPED during offset counting.\n */\nfunction isWrapAnchorImg(n: Node): boolean {\n return (\n n.nodeType === Node.ELEMENT_NODE &&\n (n as HTMLElement).dataset.wrapAnchor === \"true\"\n );\n}\n\n/**\n * `true` when `el` is the zero-width sentinel left at the model offset of a\n * float-wrap image. Counts as 1 char in offset arithmetic, mirroring how the\n * embed counts in the model.\n */\nfunction isPhantomEmbed(n: Node): boolean {\n return (\n n.nodeType === Node.ELEMENT_NODE &&\n (n as HTMLElement).dataset.embedPhantom === \"true\"\n );\n}\n\n/** Index of `n` within its parent's `childNodes`. */\nfunction indexInParent(n: Node): number {\n const parent = n.parentNode;\n if (!parent) return 0;\n let i = 0;\n for (const c of Array.from(parent.childNodes)) {\n if (c === n) return i;\n i++;\n }\n return 0;\n}\n\n/**\n * `true` when the subtree rooted at `el` should be skipped during a\n * container-scoped walk — i.e. it belongs to a different block or to a sibling\n * cell when scoping a cell container.\n */\nfunction isRejectedSubtree(el: HTMLElement, container: HTMLElement): boolean {\n if (el === container) return false;\n if (el.dataset.blockIndex != null) return true;\n if (container.dataset.cellIndex != null && el.dataset.cellIndex != null) return true;\n return false;\n}\n\n/**\n * Sum length of all text nodes plus 1 for each image embed inside `container`,\n * up to the boundary defined by `(node, offsetInNode)`. Mirrors how the model\n * counts characters: embeds are atomic length-1 inserts.\n */\nexport function textOffsetWithin(\n container: HTMLElement,\n node: Node,\n offsetInNode: number,\n): number {\n // Normalize an anchor pointing AT an image embed to (parent, indexOfImg).\n let target: Node = node;\n let targetOff = offsetInNode;\n if (isImgEmbed(target) && target.parentNode) {\n targetOff = indexInParent(target);\n target = target.parentNode as Node;\n }\n\n let offset = 0;\n let done = false;\n\n function visit(n: Node): void {\n if (done) return;\n if (n === target) {\n if (n.nodeType === Node.TEXT_NODE) {\n offset += targetOff;\n done = true;\n return;\n }\n // Element target: consume childNodes[0..targetOff-1] recursively.\n const children = n.childNodes;\n for (let i = 0; i < targetOff && i < children.length; i++) {\n visit(children[i]);\n if (done) return;\n }\n done = true;\n return;\n }\n if (n.nodeType === Node.TEXT_NODE) {\n offset += (n.textContent ?? \"\").length;\n return;\n }\n if (n.nodeType !== Node.ELEMENT_NODE) return;\n const el = n as HTMLElement;\n if (isRejectedSubtree(el, container)) return;\n // Float-wrap anchor `<img>` is rendered at the block start as a pure\n // visual; its model position lives in the phantom span downstream.\n if (isImgEmbed(el) && isWrapAnchorImg(el)) return;\n if (isImgEmbed(el) || isPhantomEmbed(el)) {\n offset += 1;\n return;\n }\n for (const child of Array.from(el.childNodes)) {\n visit(child);\n if (done) return;\n }\n }\n\n visit(container);\n return offset;\n}\n\ninterface ResolvedAnchor {\n blockIdx: number;\n cellIdx: number | undefined;\n /** The element whose text content offsets are computed against. */\n container: HTMLElement;\n /** Number to add to within-container offsets — non-zero only for fragmented blocks. */\n containerStart: number;\n}\n\nfunction resolveAnchorElement(\n node: Node,\n root: HTMLElement,\n): ResolvedAnchor | null {\n const blockEl = findContainingBlockElement(node, root);\n if (!blockEl) return null;\n const blockIdx = Number.parseInt(blockEl.dataset.blockIndex!, 10);\n const blockType = blockEl.dataset.blockType;\n if (blockType === \"table\") {\n const cellEl = findContainingCellElement(node, blockEl);\n if (!cellEl) {\n // Click landed inside the table but not in any cell — snap to first cell.\n const firstCell = blockEl.querySelector<HTMLElement>(\"[data-cell-index]\");\n if (!firstCell) return null;\n return {\n blockIdx,\n cellIdx: 0,\n container: firstCell,\n containerStart: 0,\n };\n }\n const cellIdx = Number.parseInt(cellEl.dataset.cellIndex!, 10);\n return {\n blockIdx,\n cellIdx,\n container: cellEl,\n containerStart: 0,\n };\n }\n return {\n blockIdx,\n cellIdx: undefined,\n container: blockEl,\n containerStart: readFragmentStart(blockEl),\n };\n}\n\nexport function readDomSelection(root: HTMLElement): Selection | null {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n if (!sel.anchorNode || !sel.focusNode) return null;\n if (!root.contains(sel.anchorNode) || !root.contains(sel.focusNode)) return null;\n\n const a = resolveAnchorElement(sel.anchorNode, root);\n const f = resolveAnchorElement(sel.focusNode, root);\n if (!a || !f) return null;\n\n const anchor: Position = {\n blockIndex: a.blockIdx,\n cellIndex: a.cellIdx,\n offset: a.containerStart + textOffsetWithin(a.container, sel.anchorNode, sel.anchorOffset),\n };\n const focus: Position = {\n blockIndex: f.blockIdx,\n cellIndex: f.cellIdx,\n offset: f.containerStart + textOffsetWithin(f.container, sel.focusNode, sel.focusOffset),\n };\n return { anchor, focus };\n}\n\ninterface DomPoint {\n node: Node;\n offset: number;\n}\n\nexport function locatePoint(root: HTMLElement, pos: Position): DomPoint | null {\n let container: HTMLElement | null;\n let containerStart = 0;\n\n if (pos.cellIndex != null) {\n container = getCellElement(root, pos.blockIndex, pos.cellIndex);\n if (!container) return null;\n } else {\n container = getFragmentForOffset(root, pos.blockIndex, pos.offset);\n if (!container) return null;\n containerStart = readFragmentStart(container);\n }\n\n let remaining = Math.max(0, pos.offset - containerStart);\n let result: DomPoint | null = null;\n let lastImg: HTMLElement | null = null;\n let lastText: Text | null = null;\n\n function visit(n: Node): void {\n if (result) return;\n if (n.nodeType === Node.TEXT_NODE) {\n const len = (n.textContent ?? \"\").length;\n if (remaining <= len) {\n result = { node: n, offset: remaining };\n return;\n }\n remaining -= len;\n lastImg = null;\n lastText = n as Text;\n return;\n }\n if (n.nodeType !== Node.ELEMENT_NODE) return;\n const el = n as HTMLElement;\n if (isRejectedSubtree(el, container!)) return;\n // Skip the float-wrap anchor — its slot in the model lives on the phantom.\n if (isImgEmbed(el) && isWrapAnchorImg(el)) return;\n if (isImgEmbed(el) || isPhantomEmbed(el)) {\n if (remaining === 0) {\n const parent = el.parentNode;\n if (parent) {\n result = { node: parent, offset: indexInParent(el) };\n return;\n }\n }\n remaining -= 1;\n lastImg = el;\n return;\n }\n for (const child of Array.from(el.childNodes)) {\n visit(child);\n if (result) return;\n }\n }\n\n visit(container);\n if (result) return result;\n\n // Walked the whole container without consuming `remaining` — caret lands\n // just AFTER the last embed if it was the last visited node.\n if (lastImg && remaining === 0) {\n const parent = (lastImg as HTMLElement).parentNode;\n if (parent) return { node: parent, offset: indexInParent(lastImg) + 1 };\n }\n // Offset overflowed the container's content (the model selection is\n // transiently AHEAD of the rendered DOM — insertText commits the new\n // selection one React commit before the new text). Clamp to the END of the\n // last text node so the caret stays at the end of the line. Collapsing to\n // the container's start instead would paint the caret at the start of the\n // line for one frame before the next commit corrects it (bug #1 flash).\n if (lastText) {\n const t = lastText as Text;\n return { node: t, offset: (t.textContent ?? \"\").length };\n }\n return { node: container, offset: 0 };\n}\n\nexport function selectionsEqual(a: Selection, b: Selection): boolean {\n return (\n a.anchor.blockIndex === b.anchor.blockIndex &&\n (a.anchor.cellIndex ?? -1) === (b.anchor.cellIndex ?? -1) &&\n a.anchor.offset === b.anchor.offset &&\n a.focus.blockIndex === b.focus.blockIndex &&\n (a.focus.cellIndex ?? -1) === (b.focus.cellIndex ?? -1) &&\n a.focus.offset === b.focus.offset\n );\n}\n\n/**\n * `true` when the selection is a rectangular table-cell range — both endpoints\n * inside cells of the same block, addressing different cells. The visual\n * highlight comes from CSS classes applied by `<TableView>`; we deliberately\n * leave the native DOM selection empty so the browser doesn't draw a confusing\n * cross-`<td>` range.\n */\nexport function isTableRectSelection(sel: Selection): boolean {\n if (sel.anchor.blockIndex !== sel.focus.blockIndex) return false;\n if (sel.anchor.cellIndex == null || sel.focus.cellIndex == null) return false;\n return sel.anchor.cellIndex !== sel.focus.cellIndex;\n}\n\nexport function applyDomSelection(root: HTMLElement, modelSel: Selection): void {\n const domSel = window.getSelection();\n if (!domSel) return;\n if (isTableRectSelection(modelSel)) {\n // Don't paint a native range — TableView highlights the rect via classes.\n domSel.removeAllRanges();\n return;\n }\n const anchorPt = locatePoint(root, modelSel.anchor);\n const focusPt = locatePoint(root, modelSel.focus);\n if (!anchorPt || !focusPt) return;\n\n // Already on the resolved points? Don't touch the live range. `removeAllRanges`\n // momentarily clears the selection (the caret blinks out), so re-applying an\n // identical selection is a visible no-op flash. This matters when the offset\n // clamped to the end of the line (model transiently ahead of the DOM): the\n // caret is already there, so we must leave it alone (bug #1 flash).\n if (\n domSel.anchorNode === anchorPt.node &&\n domSel.anchorOffset === anchorPt.offset &&\n domSel.focusNode === focusPt.node &&\n domSel.focusOffset === focusPt.offset\n ) {\n return;\n }\n\n try {\n domSel.removeAllRanges();\n domSel.setBaseAndExtent(anchorPt.node, anchorPt.offset, focusPt.node, focusPt.offset);\n } catch {\n // ignore — node may not be attached yet\n }\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useState,\n type CSSProperties,\n type JSX,\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n} from \"react\";\nimport { getFragmentForOffset } from \"./dom-bridge\";\n\ninterface Rect {\n top: number;\n left: number;\n width: number;\n height: number;\n}\n\ninterface BehindImageSelectAffordanceProps {\n blockIndex: number;\n offset: number;\n cellIndex?: number;\n rootRef: RefObject<HTMLDivElement>;\n /** Select the embed (shows the resize/move overlay). */\n onSelect: () => void;\n}\n\nconst ACCENT = \"#3b82f6\";\n\n/**\n * Hover affordance to select a `behind` image (z-index:-1) even when text sits\n * on top of it. The image's own box doesn't receive the click there — the text\n * /block does — so the overlay can't appear from a plain click. On hover we draw\n * a dashed outline (pointer-events:none, so it never steals a text click) plus a\n * clickable badge that selects the image. Lives in the un-clipped `.ed-root`\n * layer, positioned over the image (same measure pattern as ImageResizeOverlay).\n * Inline styles only — the package ships no CSS.\n */\nexport function BehindImageSelectAffordance({\n blockIndex,\n offset,\n cellIndex,\n rootRef,\n onSelect,\n}: BehindImageSelectAffordanceProps): JSX.Element | null {\n const [rect, setRect] = useState<Rect | null>(null);\n\n const locateImage = useCallback((): HTMLImageElement | null => {\n const root = rootRef.current;\n if (!root) return null;\n let container: HTMLElement | null = null;\n if (cellIndex != null) {\n container = root.querySelector<HTMLElement>(\n `[data-block-index=\"${blockIndex}\"] [data-cell-index=\"${cellIndex}\"]`,\n );\n } else {\n container = getFragmentForOffset(root, blockIndex, offset);\n }\n if (!container) return null;\n const fragmentStart = container.dataset.fragmentStart\n ? Number.parseInt(container.dataset.fragmentStart, 10) || 0\n : 0;\n const localOffset = offset - fragmentStart;\n return container.querySelector<HTMLImageElement>(\n `img[data-embed=\"image\"][data-embed-offset=\"${localOffset}\"]`,\n );\n }, [rootRef, blockIndex, offset, cellIndex]);\n\n const measure = useCallback(() => {\n const img = locateImage();\n const root = rootRef.current;\n if (!img || !root) {\n setRect((prev) => (prev === null ? prev : null));\n return;\n }\n const r = img.getBoundingClientRect();\n const rr = root.getBoundingClientRect();\n const next: Rect = {\n top: r.top - rr.top + root.scrollTop,\n left: r.left - rr.left + root.scrollLeft,\n width: r.width,\n height: r.height,\n };\n setRect((prev) =>\n prev &&\n prev.top === next.top &&\n prev.left === next.left &&\n prev.width === next.width &&\n prev.height === next.height\n ? prev\n : next,\n );\n }, [locateImage, rootRef]);\n\n useLayoutEffect(() => {\n measure();\n let cancelled = false;\n const remeasure = () => {\n if (!cancelled) measure();\n };\n const id =\n typeof requestAnimationFrame === \"function\"\n ? requestAnimationFrame(remeasure)\n : (queueMicrotask(remeasure), 0);\n return () => {\n cancelled = true;\n if (typeof cancelAnimationFrame === \"function\" && typeof id === \"number\" && id > 0) {\n cancelAnimationFrame(id);\n }\n };\n }, [measure]);\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const onScroll = () => measure();\n window.addEventListener(\"resize\", onScroll);\n root.addEventListener(\"scroll\", onScroll);\n return () => {\n window.removeEventListener(\"resize\", onScroll);\n root.removeEventListener(\"scroll\", onScroll);\n };\n }, [measure, rootRef]);\n\n if (!rect) return null;\n\n const outlineStyle: CSSProperties = {\n position: \"absolute\",\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n border: `1.5px dashed ${ACCENT}`,\n borderRadius: 2,\n boxSizing: \"border-box\",\n pointerEvents: \"none\",\n zIndex: 4,\n };\n\n const badgeStyle: CSSProperties = {\n position: \"absolute\",\n top: rect.top - 2,\n left: rect.left - 2,\n width: 24,\n height: 24,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n background: ACCENT,\n color: \"#fff\",\n borderRadius: 4,\n cursor: \"pointer\",\n pointerEvents: \"auto\",\n boxShadow: \"0 1px 3px rgba(0,0,0,0.3)\",\n zIndex: 5,\n };\n\n const onBadgeDown = (e: ReactPointerEvent<HTMLDivElement>) => {\n if (e.button !== 0) return;\n e.preventDefault();\n e.stopPropagation();\n onSelect();\n };\n\n return (\n <>\n <div style={outlineStyle} contentEditable={false} aria-hidden />\n <div\n style={badgeStyle}\n contentEditable={false}\n onPointerDown={onBadgeDown}\n role=\"button\"\n aria-label=\"Selecionar imagem\"\n title=\"Selecionar imagem\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n <path d=\"M5 9l-3 3 3 3M9 5l3-3 3 3M15 19l-3 3-3-3M19 9l3 3-3 3M2 12h20M12 2v20\" />\n </svg>\n </div>\n </>\n );\n}\n","import { type CSSProperties, type JSX } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { MOD_SYMBOL } from \"./platform\";\n\ninterface LinkHoverTooltipProps {\n href: string;\n /** Link bounding box in viewport coordinates (from getBoundingClientRect). */\n rect: { top: number; left: number; bottom: number; width: number };\n}\n\nconst MAX_WIDTH = 360;\nconst GAP = 6;\n\n/**\n * Small floating tooltip shown while hovering a link in the editor. Displays the\n * link URL plus a hint that Cmd/Ctrl+click opens it. Lives at `position: fixed`\n * (viewport coords from the link's rect) so it isn't clipped by the paginated\n * page boxes; `pointerEvents: none` so it never steals the hover/click from the\n * link underneath. The package ships no CSS — all styling is inline.\n */\nexport function LinkHoverTooltip({ href, rect }: LinkHoverTooltipProps): JSX.Element {\n // Prefer above the link; flip below when too close to the viewport top.\n const above = rect.top > 48;\n const viewportW = typeof window !== \"undefined\" ? window.innerWidth : MAX_WIDTH + 16;\n const left = Math.max(8, Math.min(rect.left, viewportW - MAX_WIDTH - 8));\n\n const style: CSSProperties = {\n position: \"fixed\",\n left,\n top: above ? rect.top - GAP : rect.bottom + GAP,\n transform: above ? \"translateY(-100%)\" : undefined,\n maxWidth: MAX_WIDTH,\n background: \"#1f2937\",\n color: \"#fff\",\n fontSize: 12,\n lineHeight: 1.4,\n padding: \"6px 9px\",\n borderRadius: 6,\n boxShadow: \"0 4px 14px rgba(0,0,0,0.28)\",\n zIndex: 60,\n pointerEvents: \"none\",\n };\n\n const urlStyle: CSSProperties = {\n display: \"block\",\n maxWidth: MAX_WIDTH - 18,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n fontWeight: 600,\n };\n\n const hintStyle: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n gap: 4,\n marginTop: 3,\n fontSize: 11,\n opacity: 0.85,\n };\n\n // Keycap look (the package ships no CSS): a small key-shaped chip around the\n // modifier glyph and the mouse-click glyph.\n const keycapStyle: CSSProperties = {\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minWidth: 16,\n height: 16,\n padding: \"0 4px\",\n fontSize: 11,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n background: \"rgba(255,255,255,0.16)\",\n border: \"1px solid rgba(255,255,255,0.4)\",\n borderRadius: 4,\n boxShadow: \"inset 0 -1px 0 rgba(0,0,0,0.25)\",\n };\n\n // Render into <body> so `position: fixed` stays viewport-relative even if the\n // editor is nested under a transformed/filtered ancestor (which would turn it\n // into the containing block for fixed elements). SSR-safe: no body, no portal.\n if (typeof document === \"undefined\") return <></>;\n\n return createPortal(\n <div style={style} contentEditable={false} aria-hidden role=\"tooltip\">\n <span style={urlStyle}>{href}</span>\n <span style={hintStyle}>\n <kbd style={keycapStyle}>{MOD_SYMBOL}</kbd>\n <span style={{ opacity: 0.8 }}>+ clique para abrir</span>\n </span>\n </div>,\n document.body,\n );\n}\n","/**\n * Platform detection for keyboard-modifier conventions. On macOS the \"command\"\n * modifier is ⌘ (`metaKey`); elsewhere it's Ctrl (`ctrlKey`). Computed once.\n */\nexport const IS_MAC: boolean = (() => {\n if (typeof navigator === \"undefined\") return false;\n // NB: case-INSENSITIVE. Chrome's `navigator.userAgentData.platform` returns\n // \"macOS\" (lowercase m), while `navigator.platform` returns \"MacIntel\" — a\n // `/Mac/` (case-sensitive) test silently missed \"macOS\", so Macs were treated\n // as non-Mac (showed \"Ctrl\", and Cmd+click didn't open).\n const platform =\n (navigator as Navigator & { userAgentData?: { platform?: string } }).userAgentData?.platform ||\n navigator.platform ||\n navigator.userAgent ||\n \"\";\n return /mac|iphone|ipad|ipod/i.test(platform);\n})();\n\n/** Text label for the platform's primary command modifier (\"Cmd\" / \"Ctrl\"). */\nexport const MOD_LABEL: string = IS_MAC ? \"Cmd\" : \"Ctrl\";\n\n/**\n * Keyboard GLYPH for the platform's command modifier: ⌘ (Command) on macOS,\n * ⌃ (Control) elsewhere. Used for keycap-style hints instead of the text label.\n */\nexport const MOD_SYMBOL: string = IS_MAC ? \"⌘\" : \"⌃\";\n\n/** True when the platform's \"open in new tab\" modifier is held during a click. */\nexport function hasOpenModifier(e: { metaKey: boolean; ctrlKey: boolean }): boolean {\n return IS_MAC ? e.metaKey : e.ctrlKey;\n}\n","import { createContext, useContext, type JSX, type ReactNode } from \"react\";\nimport { LinkDialog } from \"./LinkDialog\";\nimport { PageConfigDialog } from \"./PageConfigDialog\";\nimport { ImageCaptionDialog } from \"./ImageCaptionDialog\";\nimport type { UseEditorResult } from \"./useEditor\";\n\nconst EditorContext = createContext<UseEditorResult | null>(null);\n\nexport interface EditorProviderProps {\n editor: UseEditorResult;\n children: ReactNode;\n}\n\nexport function EditorProvider({ editor, children }: EditorProviderProps): JSX.Element {\n return (\n <EditorContext.Provider value={editor}>\n {children}\n <LinkDialog />\n <PageConfigDialog />\n <ImageCaptionDialog />\n </EditorContext.Provider>\n );\n}\n\nexport function useEditorContext(): UseEditorResult {\n const ctx = useContext(EditorContext);\n if (!ctx) {\n throw new Error(\"useEditorContext must be used inside an <EditorProvider>\");\n }\n return ctx;\n}\n","import {\n useEffect,\n useRef,\n useState,\n type FormEvent,\n type JSX,\n} from \"react\";\nimport { useEditorContext } from \"./EditorContext\";\nimport { DIALOG_CENTER_STYLE } from \"./dialogCenterStyle\";\n\n/**\n * Modal dialog for entering a link URL. Replaces the bare `window.prompt`\n * previously wired to Cmd+K and the toolbar link button. Renders only when\n * `editor.linkRequest` is set; consumes that state via `resolveLinkRequest`.\n *\n * Uses the native `<dialog>` element for focus trapping, ESC handling, and the\n * browser-provided backdrop.\n */\nexport function LinkDialog(): JSX.Element | null {\n const { linkRequest, resolveLinkRequest } = useEditorContext();\n const dialogRef = useRef<HTMLDialogElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const [href, setHref] = useState(\"\");\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n if (linkRequest) {\n setHref(linkRequest.initialHref);\n if (!dialog.open) dialog.showModal();\n // Defer focus + select-all to after the dialog finishes opening.\n queueMicrotask(() => {\n const input = inputRef.current;\n if (input) {\n input.focus();\n input.select();\n }\n });\n } else if (dialog.open) {\n dialog.close();\n }\n }, [linkRequest]);\n\n if (!linkRequest) return null;\n\n const onSubmit = (e: FormEvent) => {\n e.preventDefault();\n resolveLinkRequest(href.trim());\n };\n\n const onRemove = () => {\n // Empty string signals \"remove the link mark\".\n resolveLinkRequest(\"\");\n };\n\n const onCancel = () => {\n resolveLinkRequest(null);\n };\n\n return (\n <dialog\n ref={dialogRef}\n className=\"ed-link-dialog\"\n style={DIALOG_CENTER_STYLE}\n onClose={onCancel}\n onCancel={(e) => {\n e.preventDefault();\n onCancel();\n }}\n >\n <form onSubmit={onSubmit} className=\"ed-link-dialog-form\">\n <div className=\"ed-link-dialog-row\">\n <label htmlFor=\"ed-link-href\">URL</label>\n <input\n id=\"ed-link-href\"\n ref={inputRef}\n type=\"url\"\n inputMode=\"url\"\n value={href}\n onChange={(e) => setHref(e.target.value)}\n placeholder=\"https://exemplo.com\"\n autoComplete=\"off\"\n />\n </div>\n <div className=\"ed-link-dialog-actions\">\n {linkRequest.initialHref ? (\n <button type=\"button\" onClick={onRemove} className=\"ed-link-dialog-remove\">\n Remover link\n </button>\n ) : (\n <span />\n )}\n <div className=\"ed-link-dialog-confirm\">\n <button type=\"button\" onClick={onCancel}>\n Cancelar\n </button>\n <button type=\"submit\" className=\"ed-link-dialog-apply\">\n Aplicar\n </button>\n </div>\n </div>\n </form>\n </dialog>\n );\n}\n","import type { CSSProperties } from \"react\";\n\n/**\n * Inline centering for the editor's native `<dialog showModal()>` modals\n * (link / caption / page-config). The package ships no CSS, so it can't rely on\n * the consumer keeping the UA `dialog { margin: auto }` centering intact — some\n * apps (Tailwind/HeroUI resets, custom `dialog { margin: 0 }`) override it and\n * the modal then opens in the top-left corner. `position: fixed` + translate is\n * reset-proof; `maxHeight`/`overflow` keep a tall dialog from spilling\n * off-screen when translated.\n */\nexport const DIALOG_CENTER_STYLE: CSSProperties = {\n position: \"fixed\",\n top: \"50%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n margin: 0,\n maxHeight: \"90vh\",\n overflow: \"auto\",\n};\n","import { useEffect, useMemo, useRef, useState, type FormEvent, type JSX } from \"react\";\nimport {\n MARGIN_PRESETS,\n PAGE_PRESETS,\n detectPreset,\n mmToPx,\n pxToMm,\n type PageSettings,\n type PagePreset,\n} from \"@sofereditor/core\";\nimport { useEditorContext } from \"./EditorContext\";\nimport { DIALOG_CENTER_STYLE } from \"./dialogCenterStyle\";\n\ntype MarginPreset = \"normal\" | \"narrow\" | \"wide\" | \"custom\";\n\n/**\n * Modal dialog to configure page size and margins. Mirrors `LinkDialog` —\n * driven by `editor.pageConfigRequest`. On apply, writes via\n * `editor.setPageSettings`; on cancel, no write.\n */\nexport function PageConfigDialog(): JSX.Element | null {\n const { pageConfigRequest, resolvePageConfigRequest, setPageSettings } = useEditorContext();\n const dialogRef = useRef<HTMLDialogElement>(null);\n\n // Form state. Sizes are kept in mm for user-facing inputs; we convert to px\n // when applying. Width/height pair determines the size preset.\n const [sizePreset, setSizePreset] = useState<PagePreset>(\"a4\");\n const [widthMm, setWidthMm] = useState(210);\n const [heightMm, setHeightMm] = useState(297);\n const [marginPreset, setMarginPreset] = useState<MarginPreset>(\"normal\");\n const [marginTopMm, setMarginTopMm] = useState(25.4);\n const [marginBottomMm, setMarginBottomMm] = useState(25.4);\n const [marginLeftMm, setMarginLeftMm] = useState(25.4);\n const [marginRightMm, setMarginRightMm] = useState(25.4);\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n if (pageConfigRequest) {\n hydrateFromSettings(pageConfigRequest.initial, {\n setSizePreset,\n setWidthMm,\n setHeightMm,\n setMarginPreset,\n setMarginTopMm,\n setMarginBottomMm,\n setMarginLeftMm,\n setMarginRightMm,\n });\n if (!dialog.open) dialog.showModal();\n } else if (dialog.open) {\n dialog.close();\n }\n }, [pageConfigRequest]);\n\n // When the user picks a size preset, snap width/height back to the canonical\n // values. \"custom\" leaves the user free to edit.\n useEffect(() => {\n if (sizePreset === \"custom\") return;\n const p = PAGE_PRESETS[sizePreset];\n setWidthMm(roundMm(pxToMm(p.width)));\n setHeightMm(roundMm(pxToMm(p.height)));\n }, [sizePreset]);\n\n // When the user picks a margin preset, set all 4 margins to that value.\n useEffect(() => {\n if (marginPreset === \"custom\") return;\n const px = MARGIN_PRESETS[marginPreset];\n const mm = roundMm(pxToMm(px));\n setMarginTopMm(mm);\n setMarginBottomMm(mm);\n setMarginLeftMm(mm);\n setMarginRightMm(mm);\n }, [marginPreset]);\n\n const customWidth = sizePreset === \"custom\";\n\n // Live preview of the dimensions in px so the test/QA loop is easy to read.\n const previewPx = useMemo(\n () => ({\n width: Math.round(mmToPx(widthMm)),\n height: Math.round(mmToPx(heightMm)),\n }),\n [widthMm, heightMm],\n );\n\n if (!pageConfigRequest) return null;\n\n const onApply = (e: FormEvent) => {\n e.preventDefault();\n const next: Partial<PageSettings> = {\n width: mmToPx(widthMm),\n height: mmToPx(heightMm),\n marginTop: mmToPx(marginTopMm),\n marginBottom: mmToPx(marginBottomMm),\n marginLeft: mmToPx(marginLeftMm),\n marginRight: mmToPx(marginRightMm),\n };\n setPageSettings(next);\n resolvePageConfigRequest(true);\n };\n const onCancel = () => resolvePageConfigRequest(false);\n\n return (\n <dialog\n ref={dialogRef}\n className=\"ed-page-config-dialog\"\n style={DIALOG_CENTER_STYLE}\n onClose={onCancel}\n onCancel={(e) => {\n e.preventDefault();\n onCancel();\n }}\n >\n <form onSubmit={onApply} className=\"ed-page-config-form\">\n <h2>Configurar página</h2>\n\n <fieldset>\n <legend>Tamanho</legend>\n <div className=\"ed-page-config-row\">\n <label>\n <input\n type=\"radio\"\n name=\"size\"\n checked={sizePreset === \"a4\"}\n onChange={() => setSizePreset(\"a4\")}\n />{\" \"}\n A4 (210 × 297 mm)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"size\"\n checked={sizePreset === \"letter\"}\n onChange={() => setSizePreset(\"letter\")}\n />{\" \"}\n Carta (216 × 279 mm)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"size\"\n checked={sizePreset === \"oficio\"}\n onChange={() => setSizePreset(\"oficio\")}\n />{\" \"}\n Ofício (216 × 330 mm)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"size\"\n checked={sizePreset === \"custom\"}\n onChange={() => setSizePreset(\"custom\")}\n />{\" \"}\n Personalizado\n </label>\n </div>\n <div className=\"ed-page-config-row\">\n <label>\n Largura (mm){\" \"}\n <input\n type=\"number\"\n step={0.1}\n min={50}\n max={1000}\n value={widthMm}\n onChange={(e) => setWidthMm(Number(e.target.value))}\n disabled={!customWidth}\n />\n </label>\n <label>\n Altura (mm){\" \"}\n <input\n type=\"number\"\n step={0.1}\n min={50}\n max={1000}\n value={heightMm}\n onChange={(e) => setHeightMm(Number(e.target.value))}\n disabled={!customWidth}\n />\n </label>\n <span className=\"ed-page-config-preview\">\n {previewPx.width} × {previewPx.height} px\n </span>\n </div>\n </fieldset>\n\n <fieldset>\n <legend>Margens</legend>\n <div className=\"ed-page-config-row\">\n <label>\n <input\n type=\"radio\"\n name=\"margin\"\n checked={marginPreset === \"normal\"}\n onChange={() => setMarginPreset(\"normal\")}\n />{\" \"}\n Normal (25,4 mm)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"margin\"\n checked={marginPreset === \"narrow\"}\n onChange={() => setMarginPreset(\"narrow\")}\n />{\" \"}\n Estreita (12,7 mm)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"margin\"\n checked={marginPreset === \"wide\"}\n onChange={() => setMarginPreset(\"wide\")}\n />{\" \"}\n Larga (50,8 mm)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"margin\"\n checked={marginPreset === \"custom\"}\n onChange={() => setMarginPreset(\"custom\")}\n />{\" \"}\n Personalizada\n </label>\n </div>\n <div className=\"ed-page-config-row\">\n <label>\n Topo{\" \"}\n <input\n type=\"number\"\n step={0.1}\n min={0}\n max={200}\n value={marginTopMm}\n onChange={(e) => {\n setMarginTopMm(Number(e.target.value));\n setMarginPreset(\"custom\");\n }}\n />\n </label>\n <label>\n Inferior{\" \"}\n <input\n type=\"number\"\n step={0.1}\n min={0}\n max={200}\n value={marginBottomMm}\n onChange={(e) => {\n setMarginBottomMm(Number(e.target.value));\n setMarginPreset(\"custom\");\n }}\n />\n </label>\n <label>\n Esquerda{\" \"}\n <input\n type=\"number\"\n step={0.1}\n min={0}\n max={200}\n value={marginLeftMm}\n onChange={(e) => {\n setMarginLeftMm(Number(e.target.value));\n setMarginPreset(\"custom\");\n }}\n />\n </label>\n <label>\n Direita{\" \"}\n <input\n type=\"number\"\n step={0.1}\n min={0}\n max={200}\n value={marginRightMm}\n onChange={(e) => {\n setMarginRightMm(Number(e.target.value));\n setMarginPreset(\"custom\");\n }}\n />\n </label>\n </div>\n </fieldset>\n\n <div className=\"ed-page-config-actions\">\n <button type=\"button\" onClick={onCancel}>\n Cancelar\n </button>\n <button type=\"submit\" className=\"ed-page-config-apply\">\n Aplicar\n </button>\n </div>\n </form>\n </dialog>\n );\n}\n\nfunction roundMm(mm: number): number {\n return Math.round(mm * 10) / 10;\n}\n\nfunction hydrateFromSettings(\n s: PageSettings,\n setters: {\n setSizePreset: (v: PagePreset) => void;\n setWidthMm: (v: number) => void;\n setHeightMm: (v: number) => void;\n setMarginPreset: (v: MarginPreset) => void;\n setMarginTopMm: (v: number) => void;\n setMarginBottomMm: (v: number) => void;\n setMarginLeftMm: (v: number) => void;\n setMarginRightMm: (v: number) => void;\n },\n): void {\n const preset = detectPreset(s.width, s.height);\n setters.setSizePreset(preset);\n setters.setWidthMm(roundMm(pxToMm(s.width)));\n setters.setHeightMm(roundMm(pxToMm(s.height)));\n const top = roundMm(pxToMm(s.marginTop));\n const bottom = roundMm(pxToMm(s.marginBottom));\n const left = roundMm(pxToMm(s.marginLeft));\n const right = roundMm(pxToMm(s.marginRight));\n setters.setMarginTopMm(top);\n setters.setMarginBottomMm(bottom);\n setters.setMarginLeftMm(left);\n setters.setMarginRightMm(right);\n setters.setMarginPreset(detectMarginPreset(s));\n}\n\nfunction detectMarginPreset(s: PageSettings): MarginPreset {\n const TOL = 1; // px\n const allEqual =\n Math.abs(s.marginTop - s.marginBottom) <= TOL &&\n Math.abs(s.marginTop - s.marginLeft) <= TOL &&\n Math.abs(s.marginTop - s.marginRight) <= TOL;\n if (!allEqual) return \"custom\";\n for (const [name, px] of Object.entries(MARGIN_PRESETS) as Array<[keyof typeof MARGIN_PRESETS, number]>) {\n if (Math.abs(s.marginTop - px) <= TOL) return name as MarginPreset;\n }\n return \"custom\";\n}\n","import { useEffect, useRef, useState, type FormEvent, type JSX } from \"react\";\nimport { useEditorContext } from \"./EditorContext\";\nimport { DIALOG_CENTER_STYLE } from \"./dialogCenterStyle\";\nimport type { CaptionAlign } from \"./useEditor\";\n\n/**\n * Modal dialog for entering an image caption. Mirrors `LinkDialog` — driven by\n * `editor.imageCaptionRequest`. Empty input is treated as \"remove caption\".\n *\n * The only configurable property besides the text itself is the caption's\n * horizontal alignment (left / center / right). Word-style figure-caption\n * controls stop here intentionally — see `ImageEmbed.captionAlign`.\n */\nexport function ImageCaptionDialog(): JSX.Element | null {\n const { imageCaptionRequest, resolveImageCaptionRequest } = useEditorContext();\n const dialogRef = useRef<HTMLDialogElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const [caption, setCaption] = useState(\"\");\n const [align, setAlign] = useState<CaptionAlign>(\"center\");\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n if (imageCaptionRequest) {\n setCaption(imageCaptionRequest.initialCaption);\n setAlign(imageCaptionRequest.initialAlign);\n if (!dialog.open) dialog.showModal();\n queueMicrotask(() => {\n const input = inputRef.current;\n if (input) {\n input.focus();\n input.select();\n }\n });\n } else if (dialog.open) {\n dialog.close();\n }\n }, [imageCaptionRequest]);\n\n if (!imageCaptionRequest) return null;\n\n const onSubmit = (e: FormEvent) => {\n e.preventDefault();\n resolveImageCaptionRequest({ caption, align });\n };\n const onRemove = () => resolveImageCaptionRequest({ caption: \"\", align });\n const onCancel = () => resolveImageCaptionRequest(null);\n\n return (\n <dialog\n ref={dialogRef}\n className=\"ed-caption-dialog ed-link-dialog\"\n // Centraliza por estilo inline (o pacote não envia CSS): consumidores com\n // reset global de `dialog` (ex.: `margin:0`) quebram a centralização do\n // <dialog> nativo via UA `margin:auto` → o modal abria no canto superior\n // esquerdo. `position:fixed` + translate é à prova de reset.\n style={DIALOG_CENTER_STYLE}\n onClose={onCancel}\n onCancel={(e) => {\n e.preventDefault();\n onCancel();\n }}\n >\n <form onSubmit={onSubmit} className=\"ed-link-dialog-form\">\n <div className=\"ed-link-dialog-row\">\n <label htmlFor=\"ed-caption-input\">Legenda</label>\n <input\n id=\"ed-caption-input\"\n ref={inputRef}\n type=\"text\"\n value={caption}\n onChange={(e) => setCaption(e.target.value)}\n placeholder=\"Ex.: Figura 1 — Mapa do Brasil\"\n autoComplete=\"off\"\n />\n </div>\n <div className=\"ed-link-dialog-row\">\n <span>Alinhamento</span>\n <div className=\"ed-caption-align-group\" role=\"radiogroup\" aria-label=\"Alinhamento da legenda\">\n {([\"left\", \"center\", \"right\"] as const).map((value) => (\n <label key={value} className=\"ed-caption-align-option\">\n <input\n type=\"radio\"\n name=\"caption-align\"\n value={value}\n checked={align === value}\n onChange={() => setAlign(value)}\n />\n {value === \"left\" ? \"Esquerda\" : value === \"center\" ? \"Centro\" : \"Direita\"}\n </label>\n ))}\n </div>\n </div>\n <div className=\"ed-link-dialog-actions\">\n {imageCaptionRequest.initialCaption ? (\n <button type=\"button\" onClick={onRemove} className=\"ed-link-dialog-remove\">\n Remover legenda\n </button>\n ) : (\n <span />\n )}\n <div className=\"ed-link-dialog-confirm\">\n <button type=\"button\" onClick={onCancel}>\n Cancelar\n </button>\n <button type=\"submit\" className=\"ed-link-dialog-apply\">\n Aplicar\n </button>\n </div>\n </div>\n </form>\n </dialog>\n );\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type JSX,\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n} from \"react\";\nimport type { ImageEmbed } from \"@sofereditor/core\";\nimport { findBlockIndex, getFragmentForOffset } from \"./dom-bridge\";\n\ninterface ImageResizeOverlayProps {\n rootRef: RefObject<HTMLDivElement>;\n blockIndex: number;\n offset: number;\n cellIndex?: number;\n embed: ImageEmbed;\n /** Called once on pointer-up with the final width/height (in CSS px). */\n onCommit: (width: number, height: number) => void;\n /**\n * Called once on pointer-up after a move-drag with the new offset\n * coordinates (CSS px). Only fired when `embed.layout` is non-inline.\n */\n onCommitMove?: (offsetX: number, offsetY: number) => void;\n /**\n * Called once on pointer-up after a move-drag when the image was dropped on a\n * DIFFERENT page than its current anchor. Re-anchors the embed to a block on\n * the destination page. Only fired for non-inline layouts.\n */\n onReanchor?: (\n to: { blockIndex: number; offset: number; cellIndex?: number },\n newOffsetX: number,\n newOffsetY: number,\n ) => void;\n}\n\ntype Corner = \"nw\" | \"ne\" | \"sw\" | \"se\";\n\ninterface Rect {\n top: number;\n left: number;\n width: number;\n height: number;\n}\n\n/**\n * Floating overlay drawn over the currently-selected image embed: 4 corner\n * handles + outline. Drag a handle to resize keeping aspect ratio. Changes are\n * applied live to the `<img>` style during the drag (no Y.Doc transactions per\n * frame); a single commit happens on pointer-up so Undo treats it as one step.\n */\nexport function ImageResizeOverlay({\n rootRef,\n blockIndex,\n offset,\n cellIndex,\n embed,\n onCommit,\n onCommitMove,\n onReanchor,\n}: ImageResizeOverlayProps): JSX.Element | null {\n const [rect, setRect] = useState<Rect | null>(null);\n const [isMoving, setIsMoving] = useState(false);\n const imgRef = useRef<HTMLImageElement | null>(null);\n\n const locateImage = useCallback((): HTMLImageElement | null => {\n const root = rootRef.current;\n if (!root) return null;\n let container: HTMLElement | null = null;\n if (cellIndex != null) {\n container = root.querySelector<HTMLElement>(\n `[data-block-index=\"${blockIndex}\"] [data-cell-index=\"${cellIndex}\"]`,\n );\n } else {\n container = getFragmentForOffset(root, blockIndex, offset);\n }\n if (!container) return null;\n // The renderInline data-embed-offset is LOCAL to the fragment / container.\n const fragmentStart = container.dataset.fragmentStart\n ? Number.parseInt(container.dataset.fragmentStart, 10) || 0\n : 0;\n const localOffset = offset - fragmentStart;\n return container.querySelector<HTMLImageElement>(\n `img[data-embed=\"image\"][data-embed-offset=\"${localOffset}\"]`,\n );\n }, [rootRef, blockIndex, offset, cellIndex]);\n\n const measure = useCallback(() => {\n const img = locateImage();\n if (!img) {\n setRect((prev) => (prev === null ? prev : null));\n return;\n }\n imgRef.current = img;\n const root = rootRef.current;\n if (!root) return;\n const r = img.getBoundingClientRect();\n const rr = root.getBoundingClientRect();\n const next: Rect = {\n top: r.top - rr.top + root.scrollTop,\n left: r.left - rr.left + root.scrollLeft,\n width: r.width,\n height: r.height,\n };\n setRect((prev) =>\n prev &&\n prev.top === next.top &&\n prev.left === next.left &&\n prev.width === next.width &&\n prev.height === next.height\n ? prev\n : next,\n );\n }, [locateImage, rootRef]);\n\n useLayoutEffect(() => {\n measure();\n // Pagination runs in a SEPARATE effect after this one, on LATER frames. So\n // right after an embed prop change OR a re-anchor (blockIndex/offset change\n // from a cross-page drag), the target <img> may not be locatable yet —\n // `measure()` sets rect=null and the overlay renders nothing. Re-measure\n // across a few frames UNTIL the image is found (rect set), then stop.\n // A single rAF wasn't enough: pagination can take several frames to place\n // the re-anchored block, leaving the overlay hidden until the next\n // selection change (bug: \"can't click to select the image right after it\n // re-anchors onto the new page\").\n let cancelled = false;\n let frame = 0;\n let rafId = 0;\n const remeasure = () => {\n if (cancelled) return;\n measure();\n // Keep retrying while the image still isn't locatable (bounded budget).\n if (!locateImage() && frame++ < 30) {\n rafId =\n typeof requestAnimationFrame === \"function\"\n ? requestAnimationFrame(remeasure)\n : (queueMicrotask(remeasure), 0);\n }\n };\n rafId =\n typeof requestAnimationFrame === \"function\"\n ? requestAnimationFrame(remeasure)\n : (queueMicrotask(remeasure), 0);\n return () => {\n cancelled = true;\n if (typeof cancelAnimationFrame === \"function\" && typeof rafId === \"number\" && rafId > 0) {\n cancelAnimationFrame(rafId);\n }\n };\n }, [\n measure,\n locateImage,\n embed.width,\n embed.height,\n embed.align,\n embed.src,\n embed.layout,\n embed.offsetX,\n embed.offsetY,\n ]);\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const onScroll = () => measure();\n window.addEventListener(\"resize\", onScroll);\n root.addEventListener(\"scroll\", onScroll);\n return () => {\n window.removeEventListener(\"resize\", onScroll);\n root.removeEventListener(\"scroll\", onScroll);\n };\n }, [measure, rootRef]);\n\n /*\n * The `useLayoutEffect` above re-measures synchronously when embed props\n * change — but the pagination engine runs its own re-layout in a SEPARATE\n * effect right after. That post-pagination shift can move the image by\n * dozens of pixels (e.g. when `align: center` flips it to `display: block`\n * and the paragraph reflows), leaving the overlay at the pre-shift\n * coordinates.\n *\n * A ResizeObserver on both the image AND the editor root fires whenever\n * either box changes — covers reflow, resize, font load, page repagination,\n * and image-load-late-decoded scenarios. Falls back to no-op in jsdom etc.\n */\n useEffect(() => {\n if (typeof ResizeObserver === \"undefined\") return;\n const img = locateImage();\n const root = rootRef.current;\n if (!img || !root) return;\n const ro = new ResizeObserver(() => measure());\n ro.observe(img);\n ro.observe(root);\n return () => ro.disconnect();\n }, [locateImage, measure, rootRef, embed.layout, embed.align, embed.src]);\n\n if (!rect) return null;\n\n const layout = embed.layout ?? \"inline\";\n const movable = layout !== \"inline\" && onCommitMove !== undefined;\n\n return (\n <div\n className=\"ed-image-overlay\"\n style={{ top: rect.top, left: rect.left, width: rect.width, height: rect.height }}\n contentEditable={false}\n >\n {isMoving && (\n // Non-clipped drag preview (Tier 2): the overlay lives in .ed-root and\n // follows the cursor, so the image stays visible while it crosses the\n // page boundary (the real, clipped figure is hidden during the drag).\n // Inline styles only — the package does not ship CSS.\n <img\n src={embed.src}\n alt=\"\"\n aria-hidden\n draggable={false}\n style={{\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"fill\",\n opacity: 0.8,\n pointerEvents: \"none\",\n }}\n />\n )}\n {movable && (\n <MoveHandle\n layout={layout}\n startOffsetX={embed.offsetX ?? 0}\n startOffsetY={embed.offsetY ?? 0}\n imgRef={imgRef}\n onCommit={onCommitMove!}\n onLiveChange={measure}\n rootRef={rootRef}\n blockIndex={blockIndex}\n offset={offset}\n cellIndex={cellIndex}\n onReanchor={onReanchor}\n onMoveStart={() => setIsMoving(true)}\n onMoveEnd={() => setIsMoving(false)}\n />\n )}\n <Handle\n corner=\"nw\"\n startW={embed.width}\n startH={embed.height}\n imgRef={imgRef}\n onCommit={onCommit}\n onLiveChange={measure}\n />\n <Handle\n corner=\"ne\"\n startW={embed.width}\n startH={embed.height}\n imgRef={imgRef}\n onCommit={onCommit}\n onLiveChange={measure}\n />\n <Handle\n corner=\"sw\"\n startW={embed.width}\n startH={embed.height}\n imgRef={imgRef}\n onCommit={onCommit}\n onLiveChange={measure}\n />\n <Handle\n corner=\"se\"\n startW={embed.width}\n startH={embed.height}\n imgRef={imgRef}\n onCommit={onCommit}\n onLiveChange={measure}\n />\n </div>\n );\n}\n\ninterface MoveHandleProps {\n layout: \"wrap-left\" | \"wrap-right\" | \"behind\" | \"front\" | \"inline\";\n startOffsetX: number;\n startOffsetY: number;\n imgRef: RefObject<HTMLImageElement | null>;\n onCommit: (ox: number, oy: number) => void;\n onLiveChange: () => void;\n rootRef: RefObject<HTMLDivElement>;\n blockIndex: number;\n offset: number;\n cellIndex?: number;\n onReanchor?: (\n to: { blockIndex: number; offset: number; cellIndex?: number },\n newOffsetX: number,\n newOffsetY: number,\n ) => void;\n /** Fired when a move-drag starts/ends, so the overlay can show a drag preview. */\n onMoveStart?: () => void;\n onMoveEnd?: () => void;\n}\n\nfunction MoveHandle({\n layout,\n startOffsetX,\n startOffsetY,\n imgRef,\n onCommit,\n onLiveChange,\n rootRef,\n blockIndex,\n offset,\n cellIndex,\n onReanchor,\n onMoveStart,\n onMoveEnd,\n}: MoveHandleProps): JSX.Element {\n const dragRef = useRef<{\n startX: number;\n startY: number;\n liveOX: number;\n liveOY: number;\n } | null>(null);\n\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>) => {\n if (e.button !== 0) return;\n if (!imgRef.current) return;\n e.preventDefault();\n e.stopPropagation();\n (e.target as HTMLElement).setPointerCapture(e.pointerId);\n dragRef.current = {\n startX: e.clientX,\n startY: e.clientY,\n liveOX: startOffsetX,\n liveOY: startOffsetY,\n };\n // Hide the real (clipped) image and show a non-clipped preview in the\n // overlay for the duration of the drag, so the image stays visible while\n // it crosses the page boundary (Tier 2). The figure keeps being moved\n // below (drives the overlay/preview position via onLiveChange) — it's just\n // invisible. Restored in finish().\n const styled = imgRef.current.closest<HTMLElement>(\".ed-figure\") ?? imgRef.current;\n styled.style.opacity = \"0\";\n onMoveStart?.();\n };\n\n const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>) => {\n const d = dragRef.current;\n if (!d || !imgRef.current) return;\n const dx = e.clientX - d.startX;\n const dy = e.clientY - d.startY;\n // Post-#11 the positioned/styled element is the <figure> wrapper, not the\n // <img> (which renders position:static inside it). Mutate the figure so the\n // live drag actually moves the image; fall back to the img defensively.\n const styled = imgRef.current.closest<HTMLElement>(\".ed-figure\") ?? imgRef.current;\n let nox = startOffsetX;\n let noy = startOffsetY;\n if (layout === \"wrap-left\") {\n // dx → right margin (gap to text); negative dx clamped to 8 (min gap).\n nox = Math.max(8, startOffsetX + dx);\n noy = Math.max(0, startOffsetY + dy);\n styled.style.marginRight = `${nox}px`;\n styled.style.marginTop = `${noy}px`;\n } else if (layout === \"wrap-right\") {\n // dx is mirrored: dragging LEFT increases the gap to text.\n nox = Math.max(8, startOffsetX - dx);\n noy = Math.max(0, startOffsetY + dy);\n styled.style.marginLeft = `${nox}px`;\n styled.style.marginTop = `${noy}px`;\n } else if (layout === \"behind\" || layout === \"front\") {\n nox = startOffsetX + dx;\n noy = startOffsetY + dy;\n styled.style.left = `${nox}px`;\n styled.style.top = `${noy}px`;\n }\n d.liveOX = nox;\n d.liveOY = noy;\n onLiveChange();\n };\n\n // Clamp a behind/front vertical offset so the image stays within `frag`'s\n // page content box (never clipped by .ed-page-content overflow:hidden).\n // Offsets are fragment-local (position:absolute relative to the .ed-block).\n // Used for BOTH the same-page path and the re-anchor path (dest fragment).\n const clampOffsetToFragment = (frag: HTMLElement, oy: number): number => {\n const img = imgRef.current;\n if (!img) return oy;\n const page = frag.closest<HTMLElement>(\".ed-page\");\n const content = page?.querySelector<HTMLElement>(\".ed-page-content\");\n if (!content) return oy;\n const fragRect = frag.getBoundingClientRect();\n const contentRect = content.getBoundingClientRect();\n const imgH = img.getBoundingClientRect().height;\n // Allowed top range in fragment-local px: [contentTop, contentBottom-imgH].\n const minLocalTop = contentRect.top - fragRect.top;\n const maxLocalTop = contentRect.bottom - fragRect.top - imgH;\n return Math.round(Math.max(minLocalTop, Math.min(oy, maxLocalTop)));\n };\n\n const clampedCommit = (ox: number, oy: number) => {\n const img = imgRef.current;\n const root = rootRef.current;\n if (!img || !root || (layout !== \"behind\" && layout !== \"front\")) {\n onCommit(ox, oy);\n return;\n }\n const frag = getFragmentForOffset(root, blockIndex, offset);\n if (!frag) {\n onCommit(ox, oy);\n return;\n }\n onCommit(ox, clampOffsetToFragment(frag, oy));\n };\n\n const finish = (e: ReactPointerEvent<HTMLDivElement>) => {\n const d = dragRef.current;\n if (!d) return;\n dragRef.current = null;\n try {\n (e.target as HTMLElement).releasePointerCapture(e.pointerId);\n } catch {\n // ignore\n }\n\n // End the drag preview and restore the real image's visibility. Restoring\n // imperatively (not just relying on React's commit re-render) avoids a\n // one-frame flicker between the commit and the re-render.\n if (imgRef.current) {\n const styled = imgRef.current.closest<HTMLElement>(\".ed-figure\") ?? imgRef.current;\n styled.style.opacity = \"\";\n }\n onMoveEnd?.();\n\n const img = imgRef.current;\n const root = rootRef.current;\n const liveOX = Math.round(d.liveOX);\n const liveOY = Math.round(d.liveOY);\n\n // Tables / wrap-anchors-in-cell are out of scope: keep the current path.\n // Re-anchoring only happens for non-inline embeds dropped on a DIFFERENT\n // top-level page, with onReanchor wired.\n if (!img || !root || onReanchor === undefined || cellIndex != null) {\n clampedCommit(liveOX, liveOY);\n return;\n }\n\n const imgRect = img.getBoundingClientRect();\n const centerY = imgRect.top + imgRect.height / 2;\n\n // Destination page by GEOMETRY. `elementFromPoint(center)` was unreliable:\n // it returns null in the gap between pages or off-viewport, so cross-page\n // drops failed to re-anchor and snapped back to page 1. Instead pick the\n // .ed-page whose box CONTAINS the image center, else the NEAREST page —\n // never null. imgRect and getBoundingClientRect share the viewport-relative\n // coordinate space, so the comparison holds at any scroll.\n const pages = Array.from(root.querySelectorAll<HTMLElement>(\".ed-page\"));\n let destPage: HTMLElement | null = null;\n let bestPageDist = Infinity;\n for (const pg of pages) {\n const r = pg.getBoundingClientRect();\n if (centerY >= r.top && centerY <= r.bottom) {\n destPage = pg;\n break;\n }\n const dist = centerY < r.top ? r.top - centerY : centerY - r.bottom;\n if (dist < bestPageDist) {\n bestPageDist = dist;\n destPage = pg;\n }\n }\n\n // Current anchor page = the page owning the current fragment.\n const currentFrag = getFragmentForOffset(root, blockIndex, offset);\n const currentPage = currentFrag?.closest<HTMLElement>(\".ed-page\") ?? null;\n\n // Same page (or no page resolved) → existing same-anchor path.\n if (destPage == null || destPage === currentPage) {\n clampedCommit(liveOX, liveOY);\n return;\n }\n\n // ---- Re-anchor to a block on the destination page ----\n // Destination anchor block by GEOMETRY: the block fragment on destPage whose\n // top is nearest the dropped image's top (no elementFromPoint).\n const blocksOnPage = Array.from(\n destPage.querySelectorAll<HTMLElement>(\"[data-block-index]\"),\n );\n let destFrag: HTMLElement | null = null;\n let bestBlockDist = Infinity;\n for (const b of blocksOnPage) {\n const dist = Math.abs(b.getBoundingClientRect().top - imgRect.top);\n if (dist < bestBlockDist) {\n bestBlockDist = dist;\n destFrag = b;\n }\n }\n\n // Empty destination page (no block fragments) → keep same-anchor + clamp.\n if (!destFrag) {\n clampedCommit(liveOX, liveOY);\n return;\n }\n\n const destBlockIndex = findBlockIndex(destFrag, root);\n if (destBlockIndex == null) {\n clampedCommit(liveOX, liveOY);\n return;\n }\n\n // Destination offset = the fragment's first rendered offset (fragmentStart),\n // so the anchor lands in the FRACTION of the block that lives on this page.\n const destOffset = destFrag.dataset.fragmentStart\n ? Number.parseInt(destFrag.dataset.fragmentStart, 10) || 0\n : 0;\n\n // Recompute absolute coords relative to the destination fragment box, and\n // CLAMP so the re-anchored image is never clipped on the destination page.\n // behind/front render position:absolute; left:ox; top:oy relative to the\n // .ed-block fragment (position:relative). So ox = imgLeft - fragLeft.\n const fragRect = destFrag.getBoundingClientRect();\n const newOffsetX = Math.round(imgRect.left - fragRect.left);\n const newOffsetY = clampOffsetToFragment(\n destFrag,\n Math.round(imgRect.top - fragRect.top),\n );\n\n onReanchor(\n { blockIndex: destBlockIndex, offset: destOffset, cellIndex: undefined },\n newOffsetX,\n newOffsetY,\n );\n };\n\n return (\n <div\n className=\"ed-image-move\"\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={finish}\n onPointerCancel={finish}\n />\n );\n}\n\ninterface HandleProps {\n corner: Corner;\n startW: number;\n startH: number;\n imgRef: RefObject<HTMLImageElement | null>;\n onCommit: (w: number, h: number) => void;\n onLiveChange: () => void;\n}\n\nconst MIN_W = 20;\n\nfunction Handle({\n corner,\n startW,\n startH,\n imgRef,\n onCommit,\n onLiveChange,\n}: HandleProps): JSX.Element {\n const dragRef = useRef<{\n startX: number;\n startY: number;\n startW: number;\n startH: number;\n aspect: number;\n liveW: number;\n liveH: number;\n } | null>(null);\n\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>) => {\n if (e.button !== 0) return;\n if (!imgRef.current) return;\n e.preventDefault();\n e.stopPropagation();\n (e.target as HTMLElement).setPointerCapture(e.pointerId);\n const aspect = startW > 0 && startH > 0 ? startW / startH : 1;\n dragRef.current = {\n startX: e.clientX,\n startY: e.clientY,\n startW,\n startH,\n aspect,\n liveW: startW,\n liveH: startH,\n };\n };\n\n const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>) => {\n const d = dragRef.current;\n if (!d || !imgRef.current) return;\n const dxRaw = e.clientX - d.startX;\n // SE/NE handles grow with +dx; NW/SW grow with -dx.\n const dx = corner === \"se\" || corner === \"ne\" ? dxRaw : -dxRaw;\n let w = Math.max(MIN_W, d.startW + dx);\n let h = w / d.aspect;\n // Apply live to the img element directly — no transaction.\n imgRef.current.style.width = `${w}px`;\n imgRef.current.style.height = `${h}px`;\n imgRef.current.width = Math.round(w);\n imgRef.current.height = Math.round(h);\n d.liveW = w;\n d.liveH = h;\n onLiveChange();\n };\n\n const finish = (e: ReactPointerEvent<HTMLDivElement>) => {\n const d = dragRef.current;\n if (!d) return;\n dragRef.current = null;\n try {\n (e.target as HTMLElement).releasePointerCapture(e.pointerId);\n } catch {\n // ignore\n }\n onCommit(Math.round(d.liveW), Math.round(d.liveH));\n };\n\n return (\n <div\n className={`ed-image-handle ${corner}`}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={finish}\n onPointerCancel={finish}\n />\n );\n}\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type CSSProperties,\n type JSX,\n type RefObject,\n} from \"react\";\nimport {\n decodeSelection,\n type EditorDocument,\n type EncodedCursor,\n} from \"@sofereditor/core\";\nimport { locatePoint } from \"./dom-bridge\";\n\n/**\n * Subconjunto mínimo da Awareness do y-protocols que o overlay usa. Tipar assim\n * evita que `@sofereditor/react` dependa de `y-protocols` — o objeto vem de fora\n * (de `useCollab().binding.awareness`) e é estruturalmente compatível.\n */\nexport interface AwarenessLike {\n clientID: number;\n getStates(): Map<number, Record<string, unknown>>;\n on(event: \"change\", cb: () => void): void;\n off(event: \"change\", cb: () => void): void;\n setLocalStateField(field: string, value: unknown): void;\n}\n\ninterface Rect {\n top: number;\n left: number;\n width: number;\n height: number;\n}\n\ninterface PeerCursorView {\n clientId: number;\n name: string;\n color: string;\n caret: { top: number; left: number; height: number } | null;\n selection: Rect[];\n}\n\ninterface RemoteCursorsOverlayProps {\n rootRef: RefObject<HTMLDivElement>;\n doc: EditorDocument;\n awareness: AwarenessLike;\n /** Muda a cada edição/repaginação → re-medir os carets remotos. */\n revision?: unknown;\n}\n\nconst DEFAULT_COLOR = \"#3b82f6\";\n\n/**\n * Desenha o caret + seleção + nome de cada usuário remoto sobre o conteúdo\n * paginado. Posições remotas chegam via awareness (campo `cursor`, codificado\n * com Y.RelativePosition pelo core) e são resolvidas para coordenadas DOM com\n * o mesmo bridge da seleção local — ciente de fragmentação por página.\n */\nexport function RemoteCursorsOverlay({\n rootRef,\n doc,\n awareness,\n revision,\n}: RemoteCursorsOverlayProps): JSX.Element | null {\n const [views, setViews] = useState<PeerCursorView[]>([]);\n const rafRef = useRef<number | null>(null);\n\n const measure = useCallback(() => {\n const root = rootRef.current;\n if (!root) {\n setViews((prev) => (prev.length === 0 ? prev : []));\n return;\n }\n const rr = root.getBoundingClientRect();\n const out: PeerCursorView[] = [];\n\n awareness.getStates().forEach((state, clientId) => {\n if (clientId === awareness.clientID) return;\n const s = state as {\n user?: { name?: string; color?: string };\n cursor?: EncodedCursor;\n };\n if (!s.cursor) return;\n const sel = decodeSelection(doc, s.cursor);\n if (!sel) return;\n\n const color = s.user?.color || DEFAULT_COLOR;\n const name = s.user?.name || \"Anônimo\";\n\n const focus = locatePoint(root, sel.focus);\n let caret: PeerCursorView[\"caret\"] = null;\n if (focus) {\n try {\n const range = document.createRange();\n range.setStart(focus.node, focus.offset);\n range.collapse(true);\n let rect = range.getBoundingClientRect();\n if (rect.height === 0 && focus.node.nodeType === Node.ELEMENT_NODE) {\n rect = (focus.node as HTMLElement).getBoundingClientRect();\n }\n caret = {\n top: rect.top - rr.top + root.scrollTop,\n left: rect.left - rr.left + root.scrollLeft,\n height: rect.height || 18,\n };\n } catch {\n /* range inválido — sem caret */\n }\n }\n\n const collapsed =\n sel.anchor.blockIndex === sel.focus.blockIndex &&\n (sel.anchor.cellIndex ?? -1) === (sel.focus.cellIndex ?? -1) &&\n sel.anchor.offset === sel.focus.offset;\n\n const selection: Rect[] = [];\n if (!collapsed && focus) {\n const anchor = locatePoint(root, sel.anchor);\n if (anchor) {\n try {\n const r = document.createRange();\n r.setStart(anchor.node, anchor.offset);\n r.setEnd(focus.node, focus.offset);\n if (r.collapsed) {\n r.setStart(focus.node, focus.offset);\n r.setEnd(anchor.node, anchor.offset);\n }\n for (const cr of Array.from(r.getClientRects())) {\n if (cr.width === 0 || cr.height === 0) continue;\n selection.push({\n top: cr.top - rr.top + root.scrollTop,\n left: cr.left - rr.left + root.scrollLeft,\n width: cr.width,\n height: cr.height,\n });\n }\n } catch {\n /* seleção cross-fragmento inválida — ignora */\n }\n }\n }\n\n out.push({ clientId, name, color, caret, selection });\n });\n\n setViews(out);\n }, [rootRef, doc, awareness]);\n\n const scheduleMeasure = useCallback(() => {\n if (rafRef.current != null) return;\n const raf =\n typeof requestAnimationFrame === \"function\"\n ? requestAnimationFrame\n : (cb: FrameRequestCallback) => setTimeout(() => cb(0), 16) as unknown as number;\n rafRef.current = raf(() => {\n rafRef.current = null;\n measure();\n });\n }, [measure]);\n\n // Awareness: re-mede quando qualquer peer muda cursor/entra/sai.\n useEffect(() => {\n const onChange = () => scheduleMeasure();\n awareness.on(\"change\", onChange);\n scheduleMeasure();\n return () => awareness.off(\"change\", onChange);\n }, [awareness, scheduleMeasure]);\n\n // Edição/repaginação local.\n useEffect(() => {\n scheduleMeasure();\n }, [revision, scheduleMeasure]);\n\n // Resize do root + scroll re-posicionam os carets.\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const onScroll = () => scheduleMeasure();\n root.addEventListener(\"scroll\", onScroll, { passive: true });\n let ro: ResizeObserver | null = null;\n if (typeof ResizeObserver !== \"undefined\") {\n ro = new ResizeObserver(() => scheduleMeasure());\n ro.observe(root);\n }\n return () => {\n root.removeEventListener(\"scroll\", onScroll);\n ro?.disconnect();\n };\n }, [rootRef, scheduleMeasure]);\n\n if (views.length === 0) return null;\n\n const layer: CSSProperties = {\n position: \"absolute\",\n inset: 0,\n pointerEvents: \"none\",\n zIndex: 6,\n };\n\n return (\n <div className=\"ed-remote-cursors\" aria-hidden style={layer}>\n {views.map((v) => (\n <div key={v.clientId}>\n {v.selection.map((r, i) => (\n <div\n key={i}\n style={{\n position: \"absolute\",\n top: r.top,\n left: r.left,\n width: r.width,\n height: r.height,\n background: v.color,\n opacity: 0.22,\n borderRadius: 2,\n }}\n />\n ))}\n {v.caret && (\n <div\n style={{\n position: \"absolute\",\n top: v.caret.top,\n left: v.caret.left,\n height: v.caret.height,\n width: 2,\n background: v.color,\n }}\n >\n <span\n style={{\n position: \"absolute\",\n top: -15,\n left: -1,\n fontSize: 10,\n lineHeight: \"14px\",\n padding: \"0 4px\",\n borderRadius: 3,\n color: \"#fff\",\n background: v.color,\n whiteSpace: \"nowrap\",\n fontFamily: \"system-ui, sans-serif\",\n userSelect: \"none\",\n }}\n >\n {v.name}\n </span>\n </div>\n )}\n </div>\n ))}\n </div>\n );\n}\n","import { useMemo, useRef, type CSSProperties, type JSX, type ReactNode } from \"react\";\nimport {\n answerLineStyle,\n cellBorderStyle,\n tableRectSelection,\n type BlockAttrs,\n type CellAttrs,\n type SerializedBlock,\n type StyleRecord,\n} from \"@sofereditor/core\";\nimport { useEditorContext } from \"./EditorContext\";\nimport { renderInline } from \"./renderInline\";\nimport { sliceDelta } from \"./sliceDelta\";\nimport { TableResizeOverlay } from \"./TableResizeOverlay\";\n\nexport interface NodeViewFragment {\n index: number;\n start: number;\n end: number;\n}\n\ninterface NodeViewProps {\n block: SerializedBlock;\n index: number;\n /** Optional nested content. Used by `listItem` to host the nested <ol>/<ul>. */\n children?: ReactNode;\n /** Optional fragment slice — when present, the rendered DOM covers only chars [start, end). */\n fragment?: NodeViewFragment;\n /**\n * Optional table-row fragmentation slice for Sub-phase 4.6. When set, only\n * the rows in `[rowStart, rowEnd)` are rendered, and the resize overlay is\n * suppressed except on the FIRST fragment.\n */\n tableFragment?: { index: number; rowStart: number; rowEnd: number };\n}\n\nexport function NodeView({ block, index, children, fragment, tableFragment }: NodeViewProps): JSX.Element {\n if (block.type === \"table\") {\n return <TableView block={block} index={index} tableFragment={tableFragment} />;\n }\n const inline = fragment\n ? renderInline(sliceDelta(block.delta, fragment.start, fragment.end), index)\n : renderInline(block.delta, index);\n const common = commonBlockProps(block.attrs, index, block.type, fragment);\n\n switch (block.type) {\n case \"heading\": {\n const level = clampLevel(block.attrs.level);\n const Tag = (`h${level}` as unknown) as keyof JSX.IntrinsicElements;\n return (\n <Tag\n {...common}\n className={`ed-block ed-heading ed-heading-${level}${alignClass(block.attrs.align)}${fragmentClass(fragment)}`}\n >\n {inline}\n </Tag>\n );\n }\n case \"blockquote\":\n return (\n <blockquote\n {...common}\n className={`ed-block ed-blockquote${alignClass(block.attrs.align)}${fragmentClass(fragment)}`}\n >\n {inline}\n </blockquote>\n );\n case \"codeBlock\":\n return (\n <pre\n {...common}\n data-language={block.attrs.language ?? undefined}\n className={`ed-block ed-codeblock${alignClass(block.attrs.align)}`}\n >\n <code>{inline}</code>\n </pre>\n );\n case \"listItem\": {\n const level = clampListLevel(block.attrs.listLevel);\n return (\n <li\n {...common}\n data-list-kind={block.attrs.listKind ?? \"bullet\"}\n data-list-level={level}\n className={`ed-block ed-listitem${alignClass(block.attrs.align)}`}\n >\n {inline}\n {children}\n </li>\n );\n }\n case \"paragraph\":\n default:\n return (\n <div\n {...common}\n className={`ed-block ed-paragraph${alignClass(block.attrs.align)}${fragmentClass(fragment)}`}\n >\n {inline}\n </div>\n );\n }\n}\n\nexport function commonBlockProps(\n attrs: BlockAttrs,\n index: number,\n type: string,\n fragment: NodeViewFragment | undefined,\n) {\n const style: CSSProperties = {};\n if (attrs.align) style.textAlign = attrs.align;\n // Linha de resposta: régua inferior + entrelinha. Vem de um helper puro em\n // core para o HTML de servidor emitir exatamente o mesmo estilo.\n Object.assign(style, answerLineStyle(attrs) ?? {});\n const base: Record<string, unknown> = {\n \"data-block-index\": index,\n \"data-block-type\": type,\n dir: attrs.dir,\n style: Object.keys(style).length > 0 ? style : undefined,\n };\n if (!fragment) return base;\n base[\"data-fragment-index\"] = fragment.index;\n base[\"data-fragment-start\"] = fragment.start;\n base[\"data-fragment-end\"] = fragment.end;\n return base;\n}\n\nfunction fragmentClass(f?: NodeViewFragment): string {\n if (!f) return \"\";\n // First fragment keeps top margin, last keeps bottom; intermediate fragments drop both.\n return ` ed-fragment ed-fragment-${f.index}`;\n}\n\nfunction alignClass(a?: BlockAttrs[\"align\"]): string {\n return a ? ` ed-align-${a}` : \"\";\n}\n\n/**\n * Inline style for a table cell's visual attrs (align, bgColor).\n * Returns undefined when the cell has none, so the <td> carries no style attr.\n */\nexport function cellStyle(\n attrs?: CellAttrs,\n border?: StyleRecord,\n): CSSProperties | undefined {\n const style: CSSProperties = { ...(border as CSSProperties | undefined) };\n if (attrs?.align) style.textAlign = attrs.align;\n if (attrs?.bgColor) style.backgroundColor = attrs.bgColor;\n return Object.keys(style).length > 0 ? style : undefined;\n}\n\nfunction clampLevel(l: BlockAttrs[\"level\"]): 1 | 2 | 3 | 4 | 5 | 6 {\n if (l === 2 || l === 3 || l === 4 || l === 5 || l === 6) return l;\n return 1;\n}\n\nfunction clampListLevel(l: BlockAttrs[\"listLevel\"]): number {\n if (typeof l !== \"number\" || !Number.isFinite(l)) return 0;\n return Math.max(0, Math.min(5, Math.trunc(l)));\n}\n\ninterface TableViewProps {\n block: SerializedBlock;\n index: number;\n tableFragment?: { index: number; rowStart: number; rowEnd: number };\n}\n\nfunction TableView({ block, index, tableFragment }: TableViewProps): JSX.Element {\n const rows = clampPositive(block.attrs.rows);\n const cols = clampPositive(block.attrs.cols);\n const cells = block.cells ?? [];\n const widths = readColWidths(block.attrs.colWidths, cols);\n const tableRef = useRef<HTMLTableElement | null>(null);\n\n // Row range to render. Default = full table.\n const rowStart = tableFragment?.rowStart ?? 0;\n const rowEnd = tableFragment?.rowEnd ?? rows;\n const isFirstFragment = !tableFragment || tableFragment.index === 0;\n\n // Recompute the rectangular cell selection each render. Reading the snapshot\n // off `editor.snapshot` ties this to the same render that NodeView is in.\n const editor = useEditorContext();\n const rect = useMemo(() => {\n if (editor.selection.anchor.blockIndex !== index) return null;\n if (editor.selection.focus.blockIndex !== index) return null;\n return tableRectSelection(editor.doc, editor.selection);\n }, [editor.doc, editor.selection, index]);\n\n return (\n <div className=\"ed-table-wrap\">\n <table\n ref={tableRef}\n data-block-index={index}\n data-block-type=\"table\"\n className=\"ed-block ed-table\"\n >\n {widths && (\n <colgroup>\n {widths.map((w, c) => (\n <col key={c} style={w != null ? { width: `${w}px` } : undefined} />\n ))}\n </colgroup>\n )}\n <tbody>\n {Array.from({ length: rowEnd - rowStart }, (_, i) => {\n const r = rowStart + i;\n return (\n <tr key={r} data-cell-row={r}>\n {Array.from({ length: cols }, (_, c) => {\n const flat = r * cols + c;\n const cell = cells[flat];\n if (cell?.attrs.covered === true) return null;\n const rowspan = spanAttr(cell?.attrs.rowspan);\n const colspan = spanAttr(cell?.attrs.colspan);\n const delta = cell?.delta ?? [];\n const inRect =\n rect !== null &&\n r >= rect.top && r <= rect.bottom &&\n c >= rect.left && c <= rect.right;\n // Cell align is applied via inline textAlign; block-level align uses ed-align-* classes instead.\n return (\n <td\n key={c}\n data-cell-index={flat}\n data-cell-row={r}\n data-cell-col={c}\n data-cell-rowspan={rowspan}\n data-cell-colspan={colspan}\n rowSpan={rowspan > 1 ? rowspan : undefined}\n colSpan={colspan > 1 ? colspan : undefined}\n style={cellStyle(\n cell?.attrs,\n // rowStart/rowEnd são os limites do FRAGMENTO: numa tabela\n // quebrada entre páginas, cada página fecha a própria caixa.\n cellBorderStyle(\n block.attrs.borderPreset,\n { row: r, col: c, rowspan, colspan, cols, rowStart, rowEnd },\n \"screen\",\n block.attrs.borderColor,\n ),\n )}\n className={inRect ? \"ed-cell ed-cell--selected\" : \"ed-cell\"}\n >\n {renderInline(delta, `t${index}-c${flat}`)}\n </td>\n );\n })}\n </tr>\n );\n })}\n </tbody>\n </table>\n {isFirstFragment && (\n <TableResizeOverlay tableRef={tableRef} blockIndex={index} cols={cols} />\n )}\n </div>\n );\n}\n\nfunction readColWidths(raw: unknown, cols: number): (number | null)[] | null {\n if (!Array.isArray(raw)) return null;\n const out: (number | null)[] = [];\n for (let i = 0; i < cols; i++) {\n const v = raw[i];\n out.push(typeof v === \"number\" && Number.isFinite(v) && v > 0 ? v : null);\n }\n return out;\n}\n\nfunction spanAttr(v: unknown): number {\n if (typeof v !== \"number\" || !Number.isFinite(v) || v < 1) return 1;\n return Math.trunc(v);\n}\n\nfunction clampPositive(n: unknown): number {\n if (typeof n !== \"number\" || !Number.isFinite(n) || n <= 0) return 1;\n return Math.trunc(n);\n}\n","import { Fragment, memo, type CSSProperties, type ReactNode } from \"react\";\nimport {\n BLANK_STYLE,\n isImageEmbed,\n splitUnderscoreRuns,\n type DeltaOp,\n type ImageEmbed,\n type MarkAttrs,\n} from \"@sofereditor/core\";\nimport { hasOpenModifier } from \"./platform\";\n\n/**\n * Convert a Y.Text delta into ReactNodes.\n *\n * Wrap order (innermost → outermost): bold → italic → underline → strike → font/color span → link.\n * Semantic tags carry bold/italic/underline/strike; color and fonts go on a styled <span>.\n *\n * Keys are stable on `${blockIndex}-${runningOffset}` so React reconciliation\n * survives split/merge of runs under collaboration.\n */\nexport function renderInline(delta: DeltaOp[], keyPrefix: number | string): ReactNode {\n if (\n delta.length === 0 ||\n (delta.length === 1 &&\n typeof delta[0].insert === \"string\" &&\n delta[0].insert === \"\")\n ) {\n return <br data-empty=\"true\" />;\n }\n let offset = 0;\n // Float-wrap images (wrap-left / wrap-right) are emitted as the FIRST DOM\n // children of the block so CSS float can flow the whole paragraph around\n // them — float only wraps siblings that come after it in DOM order. A\n // zero-width phantom span is left at the embed's original offset so the\n // caret-position math in dom-bridge keeps counting the embed as 1 char in\n // its true model position.\n const wrapAnchors: ReactNode[] = [];\n const body: ReactNode[] = [];\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n const text = op.insert;\n if (text.length === 0) continue;\n const key = `${keyPrefix}-${offset}`;\n body.push(<Fragment key={key}>{wrap(text, op.attributes)}</Fragment>);\n offset += text.length;\n } else if (isImageEmbed(op.insert)) {\n const key = `${keyPrefix}-${offset}`;\n const layout = op.insert.layout ?? \"inline\";\n // Marks aplicadas ao 1-char range que cobre o embed: hoje só\n // `comment` é renderizada visualmente (espelha o tratamento de\n // texto em `wrap()`). Outras marks (bold/italic/etc.) não fazem\n // sentido em embed visual e são ignoradas.\n const commentMarkId = op.attributes?.comment?.markId;\n if (layout === \"wrap-left\" || layout === \"wrap-right\") {\n wrapAnchors.push(\n <ImageEmbedView key={`${key}-anchor`} embed={op.insert} offset={offset} wrapAnchor />,\n );\n body.push(\n <span\n key={`${key}-phantom`}\n data-embed-phantom=\"true\"\n data-embed-offset={offset}\n contentEditable={false}\n style={PHANTOM_STYLE}\n />,\n );\n } else {\n const imgNode = <ImageEmbedView key={key} embed={op.insert} offset={offset} />;\n if (commentMarkId) {\n body.push(\n <span key={`${key}-cmt`} data-comment-id={commentMarkId} className=\"ed-comment\">\n {imgNode}\n </span>,\n );\n } else {\n body.push(imgNode);\n }\n }\n offset += 1;\n } else if (op.insert != null) {\n // Unknown embed kind — reserve the offset slot so caret math stays correct.\n offset += 1;\n }\n }\n if (wrapAnchors.length === 0 && body.length === 0) return <br data-empty=\"true\" />;\n return [...wrapAnchors, ...body];\n}\n\nconst PHANTOM_STYLE: CSSProperties = {\n display: \"inline-block\",\n width: 0,\n height: 0,\n overflow: \"hidden\",\n verticalAlign: \"baseline\",\n};\n\n// Inline style for links (the package ships no CSS). `color`/underline give the\n// link its visual affordance; `cursor: \"text\"` matches the surrounding editable\n// text — the browser's UA stylesheet makes `<a href>` use `cursor: pointer`,\n// which flickers pointer↔text across the link boundary inside a contentEditable\n// (hard to click / \"cursor oscila\"). To FOLLOW a link, Cmd/Ctrl+click.\nconst LINK_STYLE: CSSProperties = {\n color: \"#2563eb\",\n textDecoration: \"underline\",\n cursor: \"text\",\n};\n\ninterface ImageEmbedViewProps {\n embed: ImageEmbed;\n offset: number;\n wrapAnchor?: boolean;\n}\n\n/**\n * `embed.src` is a (potentially huge) base64 data URL. Y.Text.toDelta() builds\n * a fresh `ImageEmbed` object every time the parent snapshot recomputes — so\n * by default React would re-render `<img src={...}>` on every keystroke even\n * when nothing about the image changed. Memoizing by *value* on the cheap\n * fields and skipping the src deep-compare (it's stable while the embed is\n * stable; if src actually changes, width/height typically change too) keeps\n * the `<img>` DOM node fully stable across keystrokes.\n */\nfunction imageEmbedPropsEqual(a: ImageEmbedViewProps, b: ImageEmbedViewProps): boolean {\n if (a.offset !== b.offset || a.wrapAnchor !== b.wrapAnchor) return false;\n const x = a.embed;\n const y = b.embed;\n if (x === y) return true;\n return (\n x.width === y.width &&\n x.height === y.height &&\n x.layout === y.layout &&\n x.align === y.align &&\n x.offsetX === y.offsetX &&\n x.offsetY === y.offsetY &&\n x.caption === y.caption &&\n x.captionAlign === y.captionAlign &&\n // src is the expensive compare — only fall back to ref equality. Fresh\n // toDelta() objects share the same string reference for embed payloads\n // because Y.js stores the embed in its content map and re-exposes it.\n x.src === y.src\n );\n}\n\nconst ImageEmbedView = memo(ImageEmbedViewImpl, imageEmbedPropsEqual);\n\nfunction ImageEmbedViewImpl({\n embed,\n offset,\n wrapAnchor,\n}: ImageEmbedViewProps): ReactNode {\n const layout = embed.layout ?? \"inline\";\n const align = embed.align;\n const ox = embed.offsetX ?? 0;\n const oy = embed.offsetY ?? 0;\n const hasCaption = !!embed.caption && embed.caption.length > 0;\n\n // The outer style positions the wrapper (float / absolute / inline-block /\n // block-with-align). The img itself stays at intrinsic width × height so the\n // existing caret-position math (`data-embed-offset`) and ImageResizeOverlay\n // queries (`img[data-embed=\"image\"]`) keep working. A `<figcaption>` lives\n // inside the wrapper when a caption is set.\n let outerStyle: CSSProperties;\n switch (layout) {\n case \"wrap-left\":\n outerStyle = {\n float: \"left\",\n width: embed.width,\n marginRight: Math.max(8, ox),\n marginTop: Math.max(0, oy),\n marginBottom: 4,\n };\n break;\n case \"wrap-right\":\n outerStyle = {\n float: \"right\",\n width: embed.width,\n marginLeft: Math.max(8, ox),\n marginTop: Math.max(0, oy),\n marginBottom: 4,\n };\n break;\n case \"behind\":\n case \"front\":\n outerStyle = {\n position: \"absolute\",\n left: ox,\n top: oy,\n width: embed.width,\n zIndex: layout === \"behind\" ? -1 : 2,\n };\n break;\n case \"inline\":\n default:\n outerStyle = align\n ? {\n display: \"block\",\n width: embed.width,\n marginLeft: align === \"left\" ? 0 : \"auto\",\n marginRight: align === \"right\" ? 0 : \"auto\",\n }\n : {\n display: \"inline-block\",\n verticalAlign: \"text-bottom\",\n width: embed.width,\n };\n break;\n }\n\n // The img always carries the data-* attributes used by Editor/Overlay.\n //\n // Structure-stable rendering (bug #11): the <img> ALWAYS lives inside a\n // <figure> that carries `outerStyle`, so adding/removing a caption never\n // changes the <img>'s parent type. React then keeps the same <img> DOM node\n // instead of unmounting+remounting it — a remount would force a synchronous\n // base64 re-decode (`decoding=\"sync\"` below), freezing the UI on large\n // images. The <img> therefore always uses the intrinsic-size style; the\n // <figure> owns the positioning.\n const imgStyle: CSSProperties = {\n width: embed.width,\n height: embed.height,\n display: \"block\",\n };\n\n // `decoding=\"sync\"` + `loading=\"eager\"` evita o piscar quando a paginação\n // remonta o <img> (consumidor com `renderPageHeader` faz a 1ª página ter\n // marginTop diferente, o que muda o DOM pai do bloco quando ele cruza\n // páginas): com cache do browser quente, o frame de remount já vem pintado.\n const img = (\n <img\n src={embed.src}\n width={embed.width}\n height={embed.height}\n contentEditable={false}\n draggable={false}\n decoding=\"sync\"\n loading=\"eager\"\n data-embed=\"image\"\n data-embed-offset={offset}\n data-embed-align={align ?? \"\"}\n data-embed-layout={layout}\n data-wrap-anchor={wrapAnchor ? \"true\" : undefined}\n style={imgStyle}\n alt=\"\"\n />\n );\n\n // Always render the <figure> wrapper (structure-stable; see imgStyle note).\n // The <figcaption> is the ONLY part that toggles with the caption — the\n // <img> stays mounted, so no re-decode/freeze.\n const captionAlign = embed.captionAlign ?? \"center\";\n return (\n <figure\n className=\"ed-figure\"\n contentEditable={false}\n data-embed-figure={hasCaption ? \"true\" : undefined}\n data-embed-layout={layout}\n style={outerStyle}\n >\n {img}\n {hasCaption && (\n <figcaption\n className=\"ed-figcaption\"\n data-caption-align={captionAlign}\n style={{ textAlign: captionAlign }}\n >\n {embed.caption}\n </figcaption>\n )}\n </figure>\n );\n}\n\n/**\n * Corridas de 3+ underlines viram um traço contínuo (lacuna de prova).\n *\n * Os caracteres PERMANECEM no DOM como nós de texto: `dom-bridge` mapeia\n * posição de DOM → offset do modelo somando `textContent.length`, então dividir\n * a run em sub-spans é seguro, mas introduzir ou remover caracteres não seria.\n */\nfunction decorateBlanks(text: string): ReactNode {\n const segs = splitUnderscoreRuns(text);\n // Caminho comum (texto sem lacuna): devolve a string crua, sem wrapper.\n if (segs.length === 1 && !segs[0].blank) return text;\n return segs.map((s, i) =>\n s.blank ? (\n <span key={i} data-blank=\"true\" style={BLANK_STYLE as CSSProperties}>\n {s.text}\n </span>\n ) : (\n <Fragment key={i}>{s.text}</Fragment>\n ),\n );\n}\n\nfunction wrap(text: string, attrs?: MarkAttrs): ReactNode {\n // A lacuna fica DENTRO dos wrappers de mark: é decoração do texto, não uma mark.\n let node: ReactNode = decorateBlanks(text);\n if (!attrs) return node;\n\n if (attrs.bold) node = <strong>{node}</strong>;\n if (attrs.italic) node = <em>{node}</em>;\n if (attrs.underline) node = <u>{node}</u>;\n if (attrs.strike) node = <s>{node}</s>;\n\n const styleParts: CSSProperties = {};\n if (attrs.color) styleParts.color = attrs.color;\n if (attrs.highlight) styleParts.backgroundColor = attrs.highlight;\n if (attrs.fontFamily) styleParts.fontFamily = attrs.fontFamily;\n if (attrs.fontSize) styleParts.fontSize = attrs.fontSize;\n if (Object.keys(styleParts).length > 0) {\n node = <span style={styleParts}>{node}</span>;\n }\n\n if (attrs.link?.href) {\n node = (\n <a\n href={attrs.link.href}\n title={attrs.link.title}\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n style={LINK_STYLE}\n onClick={(e) => {\n // Plain click edits the link text (caret), never navigates. The\n // platform \"open\" modifier (⌘ on macOS, Ctrl elsewhere) opens the\n // link directly in a new tab. We `preventDefault` in BOTH cases and\n // open via `window.open` ourselves: inside a contentEditable the\n // browser doesn't reliably navigate an `<a>` on modifier-click, so\n // relying on the default action did nothing.\n e.preventDefault();\n if (hasOpenModifier(e) && attrs.link?.href) {\n window.open(attrs.link.href, \"_blank\", \"noopener,noreferrer\");\n }\n }}\n >\n {node}\n </a>\n );\n }\n\n if (attrs.comment?.markId) {\n node = (\n <span data-comment-id={attrs.comment.markId} className=\"ed-comment\">\n {node}\n </span>\n );\n }\n\n return node;\n}\n","import type { DeltaOp } from \"@sofereditor/core\";\n\n/** Total number of inserted characters. Embeds (non-string inserts) count as 1. */\nexport function deltaLength(delta: DeltaOp[]): number {\n let sum = 0;\n for (const op of delta) {\n if (typeof op.insert === \"string\") sum += op.insert.length;\n else if (op.insert != null) sum += 1;\n }\n return sum;\n}\n\n/**\n * Return the subset of `delta` covering `[start, end)` characters. Attributes\n * are preserved on each intersecting op. Embeds are atomic length-1 ops:\n * included whole if their slot intersects the range.\n */\nexport function sliceDelta(delta: DeltaOp[], start: number, end: number): DeltaOp[] {\n if (end <= start) return [];\n const out: DeltaOp[] = [];\n let cursor = 0;\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n const opStart = cursor;\n const opEnd = cursor + op.insert.length;\n cursor = opEnd;\n if (opEnd <= start) continue;\n if (opStart >= end) break;\n const sliceFrom = Math.max(opStart, start) - opStart;\n const sliceTo = Math.min(opEnd, end) - opStart;\n out.push({\n insert: op.insert.slice(sliceFrom, sliceTo),\n attributes: op.attributes,\n });\n } else if (op.insert != null) {\n const opStart = cursor;\n const opEnd = cursor + 1;\n cursor = opEnd;\n if (opEnd <= start) continue;\n if (opStart >= end) break;\n out.push({ insert: op.insert, attributes: op.attributes });\n }\n }\n return out;\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type JSX,\n type RefObject,\n} from \"react\";\nimport { useEditorContext } from \"./EditorContext\";\n\ninterface Props {\n /** Ref to the underlying `<table>` element. */\n tableRef: RefObject<HTMLTableElement | null>;\n blockIndex: number;\n cols: number;\n}\n\n/**\n * Renders absolute-positioned drag handles aligned with each column boundary\n * (except the table's left edge). While dragging, calls the editor's\n * `setColumnWidth` with the live width so the model — and therefore the\n * `<colgroup>` — updates in real time.\n *\n * Lives as a sibling of the `<table>` inside a `position: relative` wrapper.\n * Handles are `contentEditable={false}` so they don't interfere with caret\n * placement inside cells.\n */\nexport function TableResizeOverlay({ tableRef, blockIndex, cols }: Props): JSX.Element | null {\n const editor = useEditorContext();\n const [positions, setPositions] = useState<{ x: number; height: number } | null>(null);\n // The handle X positions and the table's total height. Recomputed after every layout.\n const [layout, setLayout] = useState<{ rights: number[]; height: number } | null>(null);\n const draggingRef = useRef<{ col: number; startX: number; startWidth: number } | null>(null);\n\n // Measure column right-edges relative to the table's left edge.\n const measure = useCallback(() => {\n const table = tableRef.current;\n if (!table) return;\n const tableRect = table.getBoundingClientRect();\n // Prefer measuring via `<col>` elements when present.\n const cgCols = table.querySelectorAll<HTMLTableColElement>(\"colgroup > col\");\n let rights: number[] = [];\n if (cgCols.length === cols) {\n let acc = 0;\n cgCols.forEach((c) => {\n acc += c.getBoundingClientRect().width;\n rights.push(acc);\n });\n } else {\n // Fallback: use the first row's <td> bounding rects.\n const firstRowCells = table.querySelectorAll<HTMLTableCellElement>(\"tbody > tr:first-child > td\");\n let acc = 0;\n firstRowCells.forEach((td) => {\n // Account for colSpan: split the width evenly across the spanned cols.\n const cs = Math.max(1, td.colSpan || 1);\n const w = td.getBoundingClientRect().width / cs;\n for (let i = 0; i < cs; i++) {\n acc += w;\n rights.push(acc);\n }\n });\n }\n if (rights.length !== cols) {\n // Shape mismatch — bail out rather than place handles in wrong spots.\n setLayout(null);\n return;\n }\n setLayout({ rights, height: tableRect.height });\n }, [cols, tableRef]);\n\n useLayoutEffect(() => {\n measure();\n }, [measure]);\n\n useEffect(() => {\n const table = tableRef.current;\n if (!table) return;\n const ro = new ResizeObserver(() => measure());\n ro.observe(table);\n return () => ro.disconnect();\n }, [measure, tableRef]);\n\n const onPointerDown = useCallback(\n (col: number) => (e: React.PointerEvent<HTMLDivElement>) => {\n // Prevent the editor from losing focus / caret being placed on the handle.\n e.preventDefault();\n e.stopPropagation();\n const table = tableRef.current;\n if (!table) return;\n const cgCols = table.querySelectorAll<HTMLTableColElement>(\"colgroup > col\");\n const startWidth = cgCols[col]?.getBoundingClientRect().width ?? 100;\n draggingRef.current = { col, startX: e.clientX, startWidth };\n setPositions({ x: e.clientX, height: layout?.height ?? 0 });\n (e.currentTarget as Element).setPointerCapture(e.pointerId);\n },\n [layout, tableRef],\n );\n\n const onPointerMove = useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n const d = draggingRef.current;\n if (!d) return;\n const dx = e.clientX - d.startX;\n const next = Math.max(40, d.startWidth + dx);\n editor.setColumnWidth(blockIndex, d.col, next);\n },\n [blockIndex, editor],\n );\n\n const onPointerUp = useCallback((e: React.PointerEvent<HTMLDivElement>) => {\n draggingRef.current = null;\n setPositions(null);\n try {\n (e.currentTarget as Element).releasePointerCapture(e.pointerId);\n } catch {\n /* ignore */\n }\n }, []);\n\n if (!layout) return null;\n const handleStyle = (x: number): CSSProperties => ({\n position: \"absolute\",\n top: 0,\n left: `${x - 3}px`,\n width: \"6px\",\n height: `${layout.height}px`,\n cursor: \"col-resize\",\n zIndex: 5,\n });\n\n // Render handles for every column EXCEPT we don't need a left-edge handle\n // (the table's left edge isn't a resizable boundary). Each handle resizes\n // the column whose right edge it sits on.\n void positions;\n return (\n <>\n {layout.rights.map((x, c) => (\n <div\n key={c}\n contentEditable={false}\n className=\"ed-col-resize-handle\"\n style={handleStyle(x)}\n onPointerDown={onPointerDown(c)}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n aria-label={`Redimensionar coluna ${c + 1}`}\n role=\"separator\"\n />\n ))}\n </>\n );\n}\n","import { useLayoutEffect, useRef, useState, type RefObject } from \"react\";\n\n/**\n * Sub-phase 3.2 — page layout with intra-paragraph fragmentation.\n *\n * Two-phase render cycle:\n * 1. \"measure\" phase: editor renders with the default (unfragmented) layout\n * — every top-level on page 1. After the DOM commits, `usePageLayout`\n * reads each top-level's geometry, runs `computeLayout`, and sets the\n * real layout (with page splits and fragment offsets).\n * 2. \"stable\" phase: editor renders the real layout. No further measurement\n * until `deps` change (typically `[topLevels]`), at which point we go\n * back to step 1.\n *\n * Fragmentation only applies to \"fragmentable\" top-levels (paragraph, heading,\n * blockquote — single Y.Text blocks). List groups and code blocks are placed\n * atomically: if they don't fit they jump to the next page and bleed if larger\n * than a page.\n */\n\nexport interface PageGeometry {\n /** Page width in CSS px (A4 @ 96dpi = ~794). */\n width: number;\n /** Page height in CSS px (A4 @ 96dpi = ~1123). */\n height: number;\n marginTop: number;\n marginBottom: number;\n marginLeft: number;\n marginRight: number;\n /**\n * Espaço adicional somado ao marginTop só na 1ª página. Útil para clientes\n * que rendem um header fixo (timbrado, identificação) na pág 1 via\n * `renderPageHeader` e não querem que esse espaço seja reservado nas demais.\n * Quando omitido, todas as páginas têm a mesma `contentHeight`.\n */\n firstPageExtraTop?: number;\n}\n\nexport const A4_PAGE: PageGeometry = {\n width: 794,\n height: 1123,\n marginTop: 96,\n marginBottom: 96,\n marginLeft: 96,\n marginRight: 96,\n};\n\nexport function contentHeight(g: PageGeometry, pageIndex: number = 0): number {\n const extra = pageIndex === 0 ? g.firstPageExtraTop ?? 0 : 0;\n return g.height - g.marginTop - g.marginBottom - extra;\n}\n\nexport function contentWidth(g: PageGeometry): number {\n return g.width - g.marginLeft - g.marginRight;\n}\n\nexport interface BlockFragment {\n index: number;\n start: number;\n end: number;\n}\n\nexport interface TableRowFragment {\n /** 0, 1, 2... sequential fragment id within the table. */\n index: number;\n /** First row included (inclusive). */\n rowStart: number;\n /** First row NOT included (exclusive). */\n rowEnd: number;\n}\n\nexport interface ListItemRangeFragment {\n /** 0, 1, 2... sequential fragment id within the list group. */\n index: number;\n /** First top-level item (level 0) included (inclusive). */\n itemStart: number;\n /** First top-level item (level 0) NOT included (exclusive). */\n itemEnd: number;\n}\n\nexport interface PageSlot {\n topLevelIndex: number;\n /** Set when this slot represents a paragraph/heading/blockquote line-level fragment. */\n fragment?: BlockFragment;\n /** Set when this slot is a row-range fragment of a table (Sub-phase 4.6). */\n tableFragment?: TableRowFragment;\n /** Set when this slot is an item-range fragment of an ordered/bullet list. */\n listFragment?: ListItemRangeFragment;\n}\n\nexport interface PageEntry {\n slots: PageSlot[];\n}\n\nexport interface PageLayout {\n pages: PageEntry[];\n}\n\nexport function defaultPageLayout(topLevelCount: number): PageLayout {\n return {\n pages: [\n {\n slots: Array.from({ length: topLevelCount }, (_, i) => ({ topLevelIndex: i })),\n },\n ],\n };\n}\n\nexport type PaginationPhase = \"measure\" | \"stable\";\n\nexport interface PageLayoutResult {\n layout: PageLayout;\n /**\n * \"measure\" between a deps change and the post-commit measurement; \"stable\"\n * once the layout matches the rendered DOM. Consumers can hide the caret /\n * suppress visible flashes during \"measure\" (the DOM is briefly in the\n * unfragmented intermediate state and the native caret may jump to the start\n * of the line before useLayoutEffect re-applies the model selection).\n */\n phase: PaginationPhase;\n}\n\nexport function usePageLayout(\n rootRef: RefObject<HTMLElement>,\n geometry: PageGeometry,\n topLevelCount: number,\n deps: ReadonlyArray<unknown>,\n): PageLayoutResult {\n const [phase, setPhase] = useState<PaginationPhase>(\"measure\");\n const [layout, setLayout] = useState<PageLayout>(() => defaultPageLayout(topLevelCount));\n const lastDepsRef = useRef<unknown[] | null>(null);\n\n // Reset effect: when `deps` (consumer-provided), `topLevelCount`, or\n // `geometry` change, go back to the unfragmented default layout and\n // re-enter the measure phase.\n //\n // Why a useLayoutEffect (instead of `setState` in render body, the previous\n // approach): with concurrent rendering / Strict Mode, mutating\n // `lastDepsRef.current` during render is fragile — React may discard a\n // render pass while keeping the ref mutation, so a subsequent pass sees\n // \"deps unchanged\" and the reset never fires. The historical symptom was\n // a doc whose N blocks arrived entirely via remote `Y.applyUpdate`\n // (e.g. an Hocuspocus / y-websocket sync): the editor's snapshot updated\n // to N in `useEditor`, but `layout` stayed at 1 page × 1 slot — the reset\n // condition in the old render-body path silently missed firing.\n //\n // Doing the reset in a useLayoutEffect runs after the commit (so refs are\n // stable and visible), but BEFORE paint (so the user never sees a frame\n // with stale layout). The phase change schedules a synchronous re-render\n // and the measure effect below picks up immediately.\n //\n // Equality uses `shallowArrayEqual` for deps (consumer's responsibility to\n // pass stable references / structural keys) and `layoutsDeepEqual` for\n // the layout itself (fragment-aware — see the historical bug where shallow\n // equality let a fragmented layout matching `1 page × 1 slot` survive the\n // reset and lock subsequent measures via `!isUnfragmented(layout)`).\n useLayoutEffect(() => {\n const currentDeps = [...deps, topLevelCount, geometry];\n if (lastDepsRef.current !== null && shallowArrayEqual(lastDepsRef.current, currentDeps)) {\n return;\n }\n lastDepsRef.current = currentDeps;\n setLayout((prev) => {\n const next = defaultPageLayout(topLevelCount);\n return layoutsDeepEqual(prev, next) ? prev : next;\n });\n setPhase(\"measure\");\n // No dependency array: this effect runs after every commit and decides\n // internally whether deps changed. We can't put `[...deps, topLevelCount, geometry]`\n // here because `deps` is a variable-length array from the caller — React's\n // hook deps must be a fixed-shape list. Running every commit is cheap (one\n // shallow array compare).\n });\n\n // Measure effect: when in the measure phase with an unfragmented layout,\n // read the DOM and compute the real (possibly multi-page, possibly\n // fragmented) layout. Returns to the \"stable\" phase.\n useLayoutEffect(() => {\n if (phase !== \"measure\") return;\n const root = rootRef.current;\n if (!root) return;\n // Only safe to measure when the DOM is in the unfragmented state.\n if (!isUnfragmented(layout)) return;\n const next = computeLayout(root, geometry, topLevelCount);\n if (!layoutsDeepEqual(layout, next)) setLayout(next);\n setPhase(\"stable\");\n }, [phase, layout, geometry, topLevelCount, rootRef]);\n\n return { layout, phase };\n}\n\n// ---------- Layout computation ----------\n\nfunction isUnfragmented(layout: PageLayout): boolean {\n return (\n layout.pages.length === 1 &&\n layout.pages[0].slots.every(\n (s) =>\n s.fragment === undefined &&\n s.tableFragment === undefined &&\n s.listFragment === undefined,\n )\n );\n}\n\nfunction computeLayout(\n root: HTMLElement,\n geometry: PageGeometry,\n topLevelCount: number,\n): PageLayout {\n const tops = collectTopLevelElements(root);\n if (tops.length === 0) return defaultPageLayout(topLevelCount);\n\n // `firstPageExtraTop` faz a pág 0 ter content height menor; usar uma função\n // permite recomputar quando empurramos novas páginas.\n const limitFor = (pageIndex: number) => contentHeight(geometry, pageIndex);\n const pages: PageEntry[] = [{ slots: [] }];\n let currentPage = pages[0];\n let limit = limitFor(0);\n let used = 0;\n\n const cap = Math.min(tops.length, topLevelCount);\n for (let i = 0; i < cap; i++) {\n const el = tops[i];\n const h = elTotalHeight(el);\n\n if (used + h <= limit) {\n currentPage.slots.push({ topLevelIndex: i });\n used += h;\n continue;\n }\n\n if (isFragmentable(el)) {\n const result = placeFragmentedBlock(el, i, pages, used, limitFor);\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = result.lastUsed;\n continue;\n }\n\n if (isTableTopLevel(el)) {\n const result = placeFragmentedTable(el, i, pages, used, limitFor);\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = result.lastUsed;\n continue;\n }\n\n if (isListTopLevel(el)) {\n const result = placeFragmentedList(el, i, pages, used, limitFor);\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = result.lastUsed;\n continue;\n }\n\n // Atomic top-level that doesn't fit\n if (currentPage.slots.length === 0) {\n // empty current page; place anyway (bleed if huge)\n currentPage.slots.push({ topLevelIndex: i });\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n } else {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n currentPage.slots.push({ topLevelIndex: i });\n used = h;\n }\n }\n\n // Strip trailing empty page if any\n if (pages.length > 1 && pages[pages.length - 1].slots.length === 0) pages.pop();\n\n return { pages };\n}\n\nfunction placeFragmentedBlock(\n el: HTMLElement,\n topLevelIndex: number,\n pages: PageEntry[],\n startUsed: number,\n limitFor: (pageIndex: number) => number,\n): { lastUsed: number } {\n let limit = limitFor(pages.length - 1);\n const totalChars = getBlockTextLength(el);\n if (totalChars === 0) {\n const h = elTotalHeight(el);\n let currentPage = pages[pages.length - 1];\n if (startUsed + h > limit && currentPage.slots.length > 0) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n startUsed = 0;\n }\n currentPage.slots.push({ topLevelIndex });\n return { lastUsed: startUsed + h };\n }\n\n // Measure every original line. Splitting only at line boundaries is what\n // makes fragmentation work correctly: when fragment K starts at an original\n // line boundary AND is rendered at the same width, its line wrapping matches\n // the original exactly, so our measured height predicts the rendered height.\n const lines = measureLines(el);\n if (lines.length === 0) {\n // Couldn't measure (no text nodes?) — place atomically as last resort.\n const h = elTotalHeight(el);\n let currentPage = pages[pages.length - 1];\n if (startUsed + h > limit && currentPage.slots.length > 0) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n startUsed = 0;\n }\n currentPage.slots.push({ topLevelIndex });\n return { lastUsed: startUsed + h };\n }\n\n let lineIdx = 0;\n let currentPage = pages[pages.length - 1];\n let used = startUsed;\n let fragIndex = 0;\n\n while (lineIdx < lines.length) {\n const available = Math.max(0, limit - used);\n if (available <= 0) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n continue;\n }\n\n // Greedy: include as many consecutive lines as fit. bestK is the last fitting line index.\n const startTop = lines[lineIdx].top;\n let bestK = -1;\n for (let k = lineIdx; k < lines.length; k++) {\n const h = lines[k].bottom - startTop;\n if (h <= available) bestK = k;\n else break;\n }\n\n if (bestK < 0) {\n // Not even one line fits in the remaining space.\n if (currentPage.slots.length === 0) {\n // Page is empty; force-place a single oversized line (bleed).\n bestK = lineIdx;\n } else {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n continue;\n }\n }\n\n const fragStart = lines[lineIdx].start;\n const fragEnd = bestK + 1 < lines.length ? lines[bestK + 1].start : totalChars;\n const fragHeight = lines[bestK].bottom - startTop;\n\n currentPage.slots.push({\n topLevelIndex,\n fragment: { index: fragIndex, start: fragStart, end: fragEnd },\n });\n used += fragHeight;\n fragIndex++;\n lineIdx = bestK + 1;\n\n if (lineIdx < lines.length) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n }\n }\n\n return { lastUsed: used };\n}\n\ninterface LineMetric {\n /** Char offset (within the block) of the first char on this line. */\n start: number;\n /** Viewport-y top of the line. */\n top: number;\n /** Viewport-y bottom of the line. */\n bottom: number;\n}\n\n/**\n * Walk every text node inside `el`, measuring each character's rect to detect\n * line boundaries. Linear in total character count.\n *\n * Memoized by `(offsetWidth, textContent)`: a block whose width and text\n * haven't changed (the common case during typing — only ONE block changes per\n * keystroke) skips the measurement entirely. This is the perf core of Sub-phase\n * 3.3's incremental repagination story.\n *\n * NOTE: cached `top`/`bottom` are viewport-absolute, but `placeFragmentedBlock`\n * only ever uses RELATIVE differences (`lines[k].bottom - lines[j].top`), which\n * are invariant to scroll/layout offsets — so cached values stay correct.\n */\nconst lineMetricsCache = new Map<string, LineMetric[]>();\nconst LINE_METRICS_CACHE_LIMIT = 200;\n\nfunction measureLines(el: HTMLElement): LineMetric[] {\n const text = el.textContent ?? \"\";\n const cacheKey = `${el.offsetWidth}|${text}`;\n const cached = lineMetricsCache.get(cacheKey);\n if (cached) {\n // LRU touch\n lineMetricsCache.delete(cacheKey);\n lineMetricsCache.set(cacheKey, cached);\n return cached;\n }\n\n const fresh = measureLinesUncached(el);\n lineMetricsCache.set(cacheKey, fresh);\n if (lineMetricsCache.size > LINE_METRICS_CACHE_LIMIT) {\n const oldest = lineMetricsCache.keys().next().value;\n if (oldest !== undefined) lineMetricsCache.delete(oldest);\n }\n return fresh;\n}\n\nfunction measureLinesUncached(el: HTMLElement): LineMetric[] {\n const range = document.createRange();\n const lines: LineMetric[] = [];\n\n // Walk text nodes AND image embeds — embeds count as 1 char in offset\n // arithmetic and contribute their bounding rect as a line (or part of one).\n const walker = document.createTreeWalker(\n el,\n NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT,\n blockBoundaryFilter(el),\n );\n let n: Node | null;\n let charOffset = 0;\n\n while ((n = walker.nextNode())) {\n if (n.nodeType === Node.TEXT_NODE) {\n const text = n.textContent ?? \"\";\n for (let i = 0; i < text.length; i++) {\n try {\n range.setStart(n, i);\n range.setEnd(n, i + 1);\n } catch {\n continue;\n }\n const rect = range.getBoundingClientRect();\n if (rect.width === 0 && rect.height === 0) continue;\n const last = lines[lines.length - 1];\n if (!last || rect.top >= last.bottom) {\n lines.push({ start: charOffset + i, top: rect.top, bottom: rect.bottom });\n } else {\n last.top = Math.min(last.top, rect.top);\n last.bottom = Math.max(last.bottom, rect.bottom);\n }\n }\n charOffset += text.length;\n continue;\n }\n if (\n n.nodeType === Node.ELEMENT_NODE &&\n (n as HTMLElement).dataset.embed === \"image\"\n ) {\n const rect = (n as HTMLElement).getBoundingClientRect();\n if (rect.height > 0) {\n const last = lines[lines.length - 1];\n if (!last || rect.top >= last.bottom) {\n lines.push({ start: charOffset, top: rect.top, bottom: rect.bottom });\n } else {\n last.top = Math.min(last.top, rect.top);\n last.bottom = Math.max(last.bottom, rect.bottom);\n }\n }\n charOffset += 1;\n }\n }\n return lines;\n}\n\n// ---------- DOM measurement primitives ----------\n\nfunction elTotalHeight(el: HTMLElement): number {\n const cs = getComputedStyle(el);\n const m = parseFloat(cs.marginTop || \"0\") + parseFloat(cs.marginBottom || \"0\");\n return el.offsetHeight + m;\n}\n\nfunction isFragmentable(el: HTMLElement): boolean {\n // Top-level fragmentable types: paragraph, heading, blockquote.\n // Tables fragment via `placeFragmentedTable` (row-level), not the line engine.\n const type = el.getAttribute(\"data-block-type\");\n if (type === \"paragraph\") return true;\n if (type === \"heading\") return true;\n if (type === \"blockquote\") return true;\n return false;\n}\n\n/**\n * The top-level for a table block is a `<div class=\"ed-table-wrap\">` wrapper —\n * the `data-block-type=\"table\"` attribute lives on the nested `<table>`.\n */\nfunction isTableTopLevel(el: HTMLElement): boolean {\n return el.querySelector(':scope > table[data-block-type=\"table\"]') !== null;\n}\n\ninterface PlaceFragmentedTableResult { lastUsed: number; }\n\n/**\n * Sub-phase 4.6 — split a table that doesn't fit on the current page across\n * pages at row boundaries.\n *\n * Constraints:\n * - A break between rows `r` and `r+1` is INVALID when any cell with\n * `rowSpan > 1` whose owner sits at row `r' <= r` extends into row `r+1`.\n * We compute this by walking each row's `<td>`s: a `rowSpan = N > 1` at row\n * `r` blocks the boundaries `(r, r+1), (r+1, r+2), … (r+N-2, r+N-1)`.\n *\n * - If no clean break fits the available height (e.g. a very tall span at the\n * top of the table), and the current page already has content, we move to\n * the next page and try again. If even an empty page can't fit a valid\n * prefix, we bleed the smallest legal prefix rather than loop forever.\n *\n * Heights come from `<tr>.getBoundingClientRect()` — these are measured against\n * the unfragmented render, but row layout is invariant under fragmentation as\n * long as the `<colgroup>` widths don't change (they don't), and as long as a\n * span isn't cut (which is exactly the constraint above).\n */\nfunction placeFragmentedTable(\n el: HTMLElement,\n topLevelIndex: number,\n pages: PageEntry[],\n startUsed: number,\n limitFor: (pageIndex: number) => number,\n): PlaceFragmentedTableResult {\n let limit = limitFor(pages.length - 1);\n const table = el.querySelector(':scope > table[data-block-type=\"table\"]') as HTMLTableElement | null;\n const tbody = table?.querySelector(':scope > tbody');\n const trs = tbody ? (Array.from(tbody.children) as HTMLTableRowElement[]) : [];\n if (trs.length === 0) {\n // Empty / no rows — fall back to atomic.\n const h = elTotalHeight(el);\n let currentPage = pages[pages.length - 1];\n if (startUsed + h > limit && currentPage.slots.length > 0) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n startUsed = 0;\n }\n currentPage.slots.push({ topLevelIndex });\n return { lastUsed: startUsed + h };\n }\n\n const rowHeights = trs.map((tr) => tr.getBoundingClientRect().height);\n\n // Invalid break boundaries — indices `k` for which the break between row `k`\n // and `k+1` is blocked by a rowspan crossing it.\n const invalid = new Set<number>();\n for (let r = 0; r < trs.length; r++) {\n const tds = Array.from(trs[r].children) as HTMLTableCellElement[];\n for (const td of tds) {\n const rs = td.rowSpan || 1;\n if (rs > 1) {\n for (let k = r; k <= r + rs - 2 && k < trs.length - 1; k++) {\n invalid.add(k);\n }\n }\n }\n }\n\n // Vertical padding/margin around the table proper, distributed conservatively\n // onto the FIRST fragment only — keeps subsequent fragments compact.\n const wrapHeight = elTotalHeight(el);\n const tableHeight = table ? table.getBoundingClientRect().height : 0;\n const chrome = Math.max(0, wrapHeight - tableHeight);\n\n let rowIdx = 0;\n let used = startUsed;\n let fragIndex = 0;\n let currentPage = pages[pages.length - 1];\n\n while (rowIdx < trs.length) {\n const overhead = fragIndex === 0 ? chrome : 0;\n const available = Math.max(0, limit - used - overhead);\n if (available <= 0) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n continue;\n }\n\n // Greedy: keep extending the run as long as height fits and we haven't\n // passed a valid break boundary. Track the LAST valid `bestEnd`.\n let bestEnd = -1;\n let accH = 0;\n for (let k = rowIdx; k < trs.length; k++) {\n accH += rowHeights[k];\n if (accH > available) break;\n if (k === trs.length - 1 || !invalid.has(k)) bestEnd = k + 1;\n }\n\n if (bestEnd < 0) {\n if (currentPage.slots.length === 0) {\n // Empty page yet still no valid prefix fits — find the smallest legal\n // prefix and bleed (better than an infinite loop).\n let k = rowIdx;\n while (k < trs.length - 1 && invalid.has(k)) k++;\n bestEnd = k + 1;\n } else {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n continue;\n }\n }\n\n let fragHeight = 0;\n for (let k = rowIdx; k < bestEnd; k++) fragHeight += rowHeights[k];\n if (fragIndex === 0) fragHeight += chrome;\n\n currentPage.slots.push({\n topLevelIndex,\n tableFragment: { index: fragIndex, rowStart: rowIdx, rowEnd: bestEnd },\n });\n used += fragHeight;\n fragIndex++;\n rowIdx = bestEnd;\n\n if (rowIdx < trs.length) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n }\n }\n\n return { lastUsed: used };\n}\n\n/**\n * A top-level for a list group is the `<ol>` or `<ul>` rendered by\n * `renderListTree`. Its direct `<li>` children are the level-0 entries of\n * the group; nested sub-lists live INSIDE those `<li>`s and travel with them.\n */\nfunction isListTopLevel(el: HTMLElement): boolean {\n if (el.tagName !== \"OL\" && el.tagName !== \"UL\") return false;\n return el.classList.contains(\"ed-list\");\n}\n\ninterface PlaceFragmentedListResult { lastUsed: number; }\n\n/**\n * Split a list group that doesn't fit on the current page across pages at\n * top-level `<li>` boundaries. Nested sub-lists stay attached to their parent\n * `<li>` (we never break inside a nested list — that's reserved for the rare\n * case where a single top-level item is itself taller than a full page, in\n * which case we bleed it).\n *\n * Heights come from `<li>.getBoundingClientRect()` measured against the\n * unfragmented render. They include the nested sub-list height when present.\n */\nfunction placeFragmentedList(\n el: HTMLElement,\n topLevelIndex: number,\n pages: PageEntry[],\n startUsed: number,\n limitFor: (pageIndex: number) => number,\n): PlaceFragmentedListResult {\n let limit = limitFor(pages.length - 1);\n\n // Direct <li> children of the top-level <ol>/<ul>. Filter strictly by\n // `.ed-listitem` class so any other DOM injected by the consumer (markers,\n // dividers) doesn't get counted as an item.\n const items: HTMLLIElement[] = [];\n for (const c of Array.from(el.children)) {\n if (c instanceof HTMLLIElement && c.classList.contains(\"ed-listitem\")) {\n items.push(c);\n }\n }\n\n if (items.length === 0) {\n const h = elTotalHeight(el);\n let currentPage = pages[pages.length - 1];\n if (startUsed + h > limit && currentPage.slots.length > 0) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n startUsed = 0;\n }\n currentPage.slots.push({ topLevelIndex });\n return { lastUsed: startUsed + h };\n }\n\n const heights = items.map((li) => elTotalHeight(li));\n // Vertical padding/margin contributed by the wrapping <ol>/<ul> itself\n // (margin-block + padding-block beyond the sum of item heights). We charge\n // this overhead only to the FIRST fragment's page so subsequent continuation\n // fragments don't double-count it.\n const sumHeights = heights.reduce((a, b) => a + b, 0);\n const wrapperOverhead = Math.max(0, elTotalHeight(el) - sumHeights);\n\n let i = 0;\n let currentPage = pages[pages.length - 1];\n let used = startUsed;\n let fragIndex = 0;\n\n while (i < items.length) {\n const available = Math.max(0, limit - used);\n // Greedy: include as many consecutive items as fit. bestK is the last\n // fitting item index.\n const isFirstFragment = fragIndex === 0;\n let bestK = -1;\n let runningH = isFirstFragment ? wrapperOverhead : 0;\n for (let k = i; k < items.length; k++) {\n runningH += heights[k];\n if (runningH <= available) bestK = k;\n else break;\n }\n\n if (bestK < 0) {\n // Not even one item fits in the remaining space.\n if (currentPage.slots.length === 0) {\n // Page is empty; force-place a single oversized item (bleed).\n bestK = i;\n } else {\n // Move to next page and retry.\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n continue;\n }\n }\n\n currentPage.slots.push({\n topLevelIndex,\n listFragment: { index: fragIndex, itemStart: i, itemEnd: bestK + 1 },\n });\n\n // Account for consumed height on the current page.\n let consumed = isFirstFragment ? wrapperOverhead : 0;\n for (let k = i; k <= bestK; k++) consumed += heights[k];\n used += consumed;\n\n i = bestK + 1;\n fragIndex++;\n if (i < items.length) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n }\n }\n\n return { lastUsed: used };\n}\n\nfunction collectTopLevelElements(root: HTMLElement): HTMLElement[] {\n // The root may be in one of three shapes:\n // - flat: root > top1, top2, ...\n // - paged simple: root > .ed-page > .ed-page-content > top1, top2, ...\n // - paged + fragments: same as above, but some \"tops\" are fragments of the\n // same block index. We don't expect to be called in\n // that state (caller guards on isUnfragmented), so\n // collecting direct children is fine.\n const pageContents = root.querySelectorAll<HTMLElement>(\":scope > .ed-page > .ed-page-content\");\n if (pageContents.length > 0) {\n const out: HTMLElement[] = [];\n pageContents.forEach((pc) => {\n Array.from(pc.children).forEach((c) => out.push(c as HTMLElement));\n });\n return out;\n }\n return Array.from(root.children) as HTMLElement[];\n}\n\n/**\n * Sum text-node lengths inside `el` plus 1 for each image embed, skipping any\n * descendant `[data-block-index]`. Mirrors the model's notion of \"length\".\n */\nfunction getBlockTextLength(el: HTMLElement): number {\n const walker = document.createTreeWalker(\n el,\n NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT,\n blockBoundaryFilter(el),\n );\n let n: Node | null;\n let sum = 0;\n while ((n = walker.nextNode())) {\n if (n.nodeType === Node.TEXT_NODE) {\n sum += (n.textContent ?? \"\").length;\n } else if (\n n.nodeType === Node.ELEMENT_NODE &&\n (n as HTMLElement).dataset.embed === \"image\"\n ) {\n sum += 1;\n }\n }\n return sum;\n}\n\nfunction blockBoundaryFilter(blockEl: HTMLElement): NodeFilter {\n return {\n acceptNode(n: Node) {\n let p: Node | null = n.parentNode;\n while (p && p !== blockEl) {\n if (p.nodeType === Node.ELEMENT_NODE) {\n const e = p as HTMLElement;\n if (e.dataset.blockIndex != null) return NodeFilter.FILTER_REJECT;\n }\n p = p.parentNode;\n }\n return NodeFilter.FILTER_ACCEPT;\n },\n };\n}\n\n// ---------- Equality helpers ----------\n\nfunction shallowArrayEqual(a: unknown[], b: unknown[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n\nfunction layoutsDeepEqual(a: PageLayout, b: PageLayout): boolean {\n if (a.pages.length !== b.pages.length) return false;\n for (let i = 0; i < a.pages.length; i++) {\n const sA = a.pages[i].slots;\n const sB = b.pages[i].slots;\n if (sA.length !== sB.length) return false;\n for (let j = 0; j < sA.length; j++) {\n if (sA[j].topLevelIndex !== sB[j].topLevelIndex) return false;\n const fA = sA[j].fragment;\n const fB = sB[j].fragment;\n if (fA || fB) {\n if (!fA || !fB) return false;\n if (fA.index !== fB.index || fA.start !== fB.start || fA.end !== fB.end) return false;\n }\n const tA = sA[j].tableFragment;\n const tB = sB[j].tableFragment;\n if (tA || tB) {\n if (!tA || !tB) return false;\n if (tA.index !== tB.index || tA.rowStart !== tB.rowStart || tA.rowEnd !== tB.rowEnd) {\n return false;\n }\n }\n const lA = sA[j].listFragment;\n const lB = sB[j].listFragment;\n if (lA || lB) {\n if (!lA || !lB) return false;\n if (lA.index !== lB.index || lA.itemStart !== lB.itemStart || lA.itemEnd !== lB.itemEnd) {\n return false;\n }\n }\n }\n }\n return true;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { usePageSettings } from \"./usePageSettings\";\nimport {\n EditorDocument,\n EditorHistory,\n collapsedSelection,\n dedentList as cmdDedentList,\n deleteTable as cmdDeleteTable,\n deleteTableColumn as cmdDeleteColumn,\n deleteTableRow as cmdDeleteRow,\n insertImage as cmdInsertImage,\n mergeDown as cmdMergeDown,\n mergeRight as cmdMergeRight,\n mergeSelection as cmdMergeSelection,\n moveEmbedAnchor as cmdMoveEmbedAnchor,\n setBlockAttrAtIndex as cmdSetBlockAttrAtIndex,\n setColumnWidth as cmdSetColumnWidth,\n setImageAttrs as cmdSetImageAttrs,\n splitCell as cmdSplitCell,\n tableRectSelection,\n getMarksInRange,\n indentList as cmdIndentList,\n insertAnswerLines as cmdInsertAnswerLines,\n insertTable as cmdInsertTable,\n insertTableColumn as cmdInsertColumn,\n insertTableRow as cmdInsertRow,\n isImageEmbed,\n isMarkUniformInRange,\n moveToNextCell as cmdMoveNextCell,\n moveToPrevCell as cmdMovePrevCell,\n orderedRange,\n removeMark as cmdRemoveMark,\n setBlockAttr as cmdSetBlockAttr,\n setCellAttr as cmdSetCellAttr,\n setBlockType as cmdSetBlockType,\n setMark as cmdSetMark,\n splitListItem as cmdSplitListItem,\n tableLocationOf,\n toggleList as cmdToggleList,\n toggleMark as cmdToggleMark,\n type AlignValue,\n type BlockAttrs,\n type AnswerLineSpacing,\n type BlockType,\n type TableBorderPreset,\n type CommandContext,\n type DeltaOp,\n type EmbedLoc,\n type ImageEmbed,\n type ListKind,\n type MarkAttrs,\n type MarkName,\n type PageSettings,\n type SerializedDocument,\n type Selection,\n type TableLocation,\n type TableRect,\n} from \"@sofereditor/core\";\n\nexport interface UseEditorOptions {\n document?: EditorDocument;\n /**\n * Quando definido, `insertImageFromFile` chama esta função pra obter a URL\n * final em vez de embutir o arquivo como data URL base64 no Y.Doc.\n *\n * Use isto quando o app tem storage externo (S3, Azure Blob, etc.) e não quer\n * inflar o documento com imagens base64. O componente `<Editor>` propaga o\n * mesmo upload para paste/drop/file picker.\n */\n uploadImage?: (file: File) => Promise<string>;\n}\n\nexport type PendingMarks = Partial<Record<MarkName, MarkAttrs[MarkName] | null>>;\n\nexport interface LinkRequest {\n initialHref: string;\n resolve: (href: string | null) => void;\n /** Model selection captured when the link was requested (bug #6). */\n selection: Selection;\n}\n\nexport interface PageConfigRequest {\n initial: PageSettings;\n resolve: (applied: boolean) => void;\n}\n\nexport type CaptionAlign = \"left\" | \"center\" | \"right\";\n\nexport interface ImageCaptionResult {\n caption: string;\n align: CaptionAlign;\n}\n\nexport interface ImageCaptionRequest {\n initialCaption: string;\n initialAlign: CaptionAlign;\n /**\n * Resolves with the new caption + alignment, or null on cancel. An empty\n * `caption` string means \"remove caption\" (align is ignored in that case).\n */\n resolve: (result: ImageCaptionResult | null) => void;\n}\n\nexport interface UseEditorResult {\n doc: EditorDocument;\n history: EditorHistory;\n /** Snapshot of the model, re-computed on every Y.js update. */\n snapshot: SerializedDocument;\n /** Current model selection. Use `setSelection` to move the caret. */\n selection: Selection;\n setSelection: (sel: Selection) => void;\n /** Stable getter — commands read this to know where the caret is. */\n getSelection: () => Selection;\n\n // ---- Mark API (added in Sub-phase 2.1) ----\n isMarkActive: (name: MarkName, value?: MarkAttrs[MarkName]) => boolean;\n getActiveMarks: () => Partial<Record<MarkName, MarkAttrs[MarkName] | \"mixed\">>;\n toggleMark: (name: MarkName, value?: MarkAttrs[MarkName]) => void;\n setMark: (name: MarkName, value: MarkAttrs[MarkName]) => void;\n removeMark: (name: MarkName) => void;\n\n // ---- Block API (added in Sub-phase 2.2) ----\n /** Returns the type of the focus block (or \"mixed\" when the selection covers heterogeneous blocks). */\n getBlockType: () => BlockType | \"mixed\";\n /** Returns one block attribute at the focus block, or \"mixed\" when not uniform across the selection. */\n getBlockAttr: <K extends keyof BlockAttrs>(key: K) => BlockAttrs[K] | \"mixed\" | undefined;\n setBlockType: (type: BlockType, attrs?: BlockAttrs) => void;\n setBlockAttr: <K extends keyof BlockAttrs>(key: K, value: BlockAttrs[K] | null) => void;\n setAlign: (value: AlignValue) => void;\n getAlign: () => AlignValue | \"mixed\" | undefined;\n /** Cor de fundo das células selecionadas (rect) ou da célula focada. `null` remove. No-op fora de tabela. */\n setCellBackground: (color: string | null) => void;\n /** Cor de fundo da célula focada; undefined fora de tabela ou sem cor. */\n getCellBackground: () => string | undefined;\n /** Onde as linhas da grade da tabela focada aparecem. No-op fora de tabela. */\n setTableBorderPreset: (preset: TableBorderPreset) => void;\n /** Preset da tabela focada; \"all\" fora de tabela ou quando ausente. */\n getTableBorderPreset: () => TableBorderPreset;\n /** Cor das linhas da grade da tabela focada. `null` restaura o padrão. No-op fora de tabela. */\n setTableBorderColor: (color: string | null) => void;\n /** Cor da tabela focada; undefined fora de tabela ou quando usa o padrão. */\n getTableBorderColor: () => string | undefined;\n\n // ---- List API (added in Sub-phase 2.3) ----\n isListActive: (kind: ListKind) => boolean;\n toggleList: (kind: ListKind) => void;\n indentList: () => void;\n dedentList: () => void;\n /** Returns true when handled (current block is a listItem); false to fall back to insertParagraph. */\n splitListItem: () => boolean;\n\n /** Marks queued for the next `insertText` (e.g. user pressed Cmd+B with a collapsed caret). */\n pendingMarks: PendingMarks;\n /** Consumed by the input layer right before calling `insertText`. */\n consumePendingMarks: () => PendingMarks | undefined;\n\n // ---- Link dialog (Polish iteration) ----\n linkRequest: LinkRequest | null;\n /** Open the link dialog; resolves with the entered href, empty string to remove, or null on cancel. */\n requestLink: (initialHref?: string) => Promise<string | null>;\n /** Called by the LinkDialog itself when the user submits or cancels. */\n resolveLinkRequest: (href: string | null) => void;\n\n // ---- Page settings (Fase 9.6) ----\n /** Reactive page settings snapshot (re-renders when the Y.Doc docSettings changes). */\n pageSettings: PageSettings;\n /** Merge a partial PageSettings into the Y.Doc. Not undoable. */\n setPageSettings: (partial: Partial<PageSettings>) => void;\n /** Page-config dialog request (null when closed). */\n pageConfigRequest: PageConfigRequest | null;\n /** Open the page-config dialog; resolves true on apply, false on cancel. */\n requestPageConfig: () => Promise<boolean>;\n /** Resolver called by `<PageConfigDialog>` on apply/cancel. */\n resolvePageConfigRequest: (applied: boolean) => void;\n\n // ---- Image caption (Fase 9.6+) ----\n imageCaptionRequest: ImageCaptionRequest | null;\n /** Open the image-caption dialog with the current caption + alignment pre-filled. */\n requestImageCaption: (\n initialCaption?: string,\n initialAlign?: CaptionAlign,\n ) => Promise<ImageCaptionResult | null>;\n /** Resolver called by `<ImageCaptionDialog>` on apply/cancel. */\n resolveImageCaptionRequest: (result: ImageCaptionResult | null) => void;\n\n // ---- Tables (Phase 4) ----\n /** True iff the focus position lies inside a table cell. */\n isInTable: () => boolean;\n /** Returns `{blockIndex, row, col}` for the focus position, or null when outside a table. */\n getTableLocation: () => TableLocation | null;\n /** Insere `count` linhas de resposta pautadas depois do bloco focado. */\n insertAnswerLines: (count: number, spacing: AnswerLineSpacing) => void;\n insertTable: (rows: number, cols: number) => void;\n /** Removes the table at `blockIndex`. Defaults to the current focus table. */\n deleteTable: (blockIndex?: number) => void;\n insertRowAbove: () => void;\n insertRowBelow: () => void;\n deleteCurrentRow: () => void;\n insertColumnLeft: () => void;\n insertColumnRight: () => void;\n deleteCurrentColumn: () => void;\n moveToNextCell: () => void;\n moveToPrevCell: () => void;\n mergeRight: () => boolean;\n mergeDown: () => boolean;\n splitCell: () => boolean;\n setColumnWidth: (blockIndex: number, col: number, widthPx: number) => void;\n /** Returns the table rectangle if the current selection is a multi-cell range, else null. */\n getTableRect: () => TableRect | null;\n /** True when there's a rectangular table-cell selection. */\n hasTableRectSelection: () => boolean;\n /** Merge every cell in the rectangular selection. Returns true on success. */\n mergeSelection: () => boolean;\n\n // ---- Inline images (Fase 5) ----\n insertImage: (embed: ImageEmbed) => void;\n setImageAttrs: (\n blockIndex: number,\n offset: number,\n partial: Partial<ImageEmbed>,\n cellIndex?: number,\n newOffset?: number,\n ) => void;\n /**\n * Move a floating image embed from one anchor to another (re-anchor across\n * blocks/pages) in a single transaction. No-op for inline embeds.\n */\n moveEmbedAnchor: (\n from: EmbedLoc,\n to: EmbedLoc,\n newOffsetX: number,\n newOffsetY: number,\n ) => void;\n /** Read a File (image) and insert it inline at the caret as a data-URL embed. */\n insertImageFromFile: (file: File) => Promise<void>;\n /**\n * Returns the embed currently selected (single 1-char range over an image),\n * or null when no embed is solely selected.\n */\n getSelectedEmbed: () =>\n | { blockIndex: number; offset: number; cellIndex?: number; embed: ImageEmbed }\n | null;\n}\n\n/** Max display width when inserting an image. Larger sources are scaled keeping aspect ratio. */\nconst MAX_INSERT_WIDTH = 600;\n\nexport function useEditor(opts: UseEditorOptions = {}): UseEditorResult {\n const doc = useMemo(() => opts.document ?? new EditorDocument(), [opts.document]);\n const history = useMemo(() => new EditorHistory(doc), [doc]);\n\n const [snapshot, setSnapshot] = useState<SerializedDocument>(() => doc.toJSON());\n const [selection, setSelectionState] = useState<Selection>(() =>\n collapsedSelection({ blockIndex: 0, offset: 0 }),\n );\n const selectionRef = useRef(selection);\n selectionRef.current = selection;\n\n // pendingMarks lives on a ref so the beforeinput handler reads the latest value\n // without re-binding listeners on every render. The state copy exists so the\n // Toolbar can render a \"pressed\" hint when a mark is armed at a collapsed caret.\n const pendingMarksRef = useRef<PendingMarks>({});\n const [pendingMarks, setPendingMarksState] = useState<PendingMarks>({});\n\n const setPendingMarks = useCallback((next: PendingMarks) => {\n pendingMarksRef.current = next;\n setPendingMarksState(next);\n }, []);\n\n useEffect(() => {\n // Coalesce snapshot recomputation: `afterTransaction` fires per Y.js\n // transaction, which means once per keystroke for normal typing — but on\n // paste / multi-op commands it can fire N times in a microtask burst.\n // `toJSON()` is expensive for docs with embedded images (each call deep-\n // clones every block's delta, including base64 image src). Coalescing\n // into rAF guarantees at most one recompute per animation frame regardless\n // of how many transactions fire underneath. A pending flag avoids\n // scheduling multiple rAFs.\n let scheduled = false;\n let cancelled = false;\n let frame = 0 as number | ReturnType<typeof requestAnimationFrame>;\n const flush = () => {\n scheduled = false;\n if (cancelled) return;\n setSnapshot(doc.toJSON());\n };\n const schedule = () => {\n if (scheduled) return;\n scheduled = true;\n // Use rAF when available (browser), fall back to microtask in jsdom/Node.\n if (typeof requestAnimationFrame === \"function\") {\n frame = requestAnimationFrame(flush);\n } else {\n queueMicrotask(flush);\n }\n };\n doc.ydoc.on(\"afterTransaction\", schedule);\n return () => {\n cancelled = true;\n if (\n scheduled &&\n typeof requestAnimationFrame === \"function\" &&\n typeof cancelAnimationFrame === \"function\"\n ) {\n cancelAnimationFrame(frame as number);\n }\n doc.ydoc.off(\"afterTransaction\", schedule);\n };\n }, [doc]);\n\n const getSelection = useCallback(() => selectionRef.current, []);\n const setSelection = useCallback(\n (sel: Selection) => {\n const prev = selectionRef.current;\n selectionRef.current = sel;\n setSelectionState(sel);\n // Any caret movement that isn't a direct typing follow-up clears the queue.\n if (\n Object.keys(pendingMarksRef.current).length > 0 &&\n (prev.focus.blockIndex !== sel.focus.blockIndex || prev.focus.offset !== sel.focus.offset)\n ) {\n // Heuristic: typing advances the caret by exactly 1; everything else clears.\n const advancedByOne =\n prev.focus.blockIndex === sel.focus.blockIndex &&\n sel.focus.offset === prev.focus.offset + 1;\n if (!advancedByOne) {\n pendingMarksRef.current = {};\n setPendingMarksState({});\n }\n }\n },\n [],\n );\n\n const ctxRef = useRef<CommandContext>({ doc, getSelection, setSelection });\n ctxRef.current = { doc, getSelection, setSelection };\n\n const consumePendingMarks = useCallback((): PendingMarks | undefined => {\n const current = pendingMarksRef.current;\n if (Object.keys(current).length === 0) return undefined;\n pendingMarksRef.current = {};\n setPendingMarksState({});\n return current;\n }, []);\n\n const isMarkActive = useCallback(\n (name: MarkName, value?: MarkAttrs[MarkName]): boolean => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n if (start.blockIndex === end.blockIndex && start.offset === end.offset) {\n // Collapsed: union of pending and ambient (mark of the char immediately before caret).\n const pending = pendingMarksRef.current[name];\n if (pending !== undefined) {\n if (pending === null) return false;\n return value === undefined ? true : sameValue(pending, value);\n }\n const yText = doc.getBlockText(start.blockIndex);\n if (!yText || start.offset === 0) return false;\n return isMarkUniformInRange(yText, start.offset - 1, start.offset, name, value);\n }\n if (start.blockIndex !== end.blockIndex) {\n // Multi-block: active only if uniformly active on every covered slice.\n for (let i = start.blockIndex; i <= end.blockIndex; i++) {\n const yText = doc.getBlockText(i);\n if (!yText) return false;\n const s = i === start.blockIndex ? start.offset : 0;\n const e = i === end.blockIndex ? end.offset : yText.length;\n if (s >= e) continue;\n if (!isMarkUniformInRange(yText, s, e, name, value)) return false;\n }\n return true;\n }\n const yText = doc.getBlockText(start.blockIndex);\n if (!yText) return false;\n return isMarkUniformInRange(yText, start.offset, end.offset, name, value);\n },\n [doc],\n );\n\n const getActiveMarks = useCallback(() => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n if (start.blockIndex !== end.blockIndex) {\n // For Sub-phase 2.1 we conservatively report empty across multi-block selections.\n return {};\n }\n const yText = doc.getBlockText(start.blockIndex);\n if (!yText) return {};\n if (start.offset === end.offset) {\n if (start.offset === 0) return {};\n return getMarksInRange(yText, start.offset - 1, start.offset);\n }\n return getMarksInRange(yText, start.offset, end.offset);\n }, [doc]);\n\n const toggleMark = useCallback(\n (name: MarkName, value?: MarkAttrs[MarkName]) => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;\n if (isCollapsed) {\n // Queue for next insert.\n const next: PendingMarks = { ...pendingMarksRef.current };\n const currentlyActive = isMarkActive(name, value);\n if (currentlyActive) {\n next[name] = null;\n } else {\n next[name] = value ?? (booleanMarks.has(name) ? true : null);\n }\n setPendingMarks(next);\n return;\n }\n cmdToggleMark(ctxRef.current, name, value);\n },\n [isMarkActive, setPendingMarks],\n );\n\n const setMark = useCallback(\n (name: MarkName, value: MarkAttrs[MarkName]) => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;\n if (isCollapsed) {\n setPendingMarks({ ...pendingMarksRef.current, [name]: value });\n return;\n }\n cmdSetMark(ctxRef.current, name, value);\n },\n [setPendingMarks],\n );\n\n const removeMark = useCallback(\n (name: MarkName) => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;\n if (isCollapsed) {\n setPendingMarks({ ...pendingMarksRef.current, [name]: null });\n return;\n }\n cmdRemoveMark(ctxRef.current, name);\n },\n [setPendingMarks],\n );\n\n const getBlockType = useCallback((): BlockType | \"mixed\" => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n const first = doc.getBlockType(start.blockIndex);\n if (first === undefined) return \"paragraph\";\n for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {\n if (doc.getBlockType(i) !== first) return \"mixed\";\n }\n return first;\n }, [doc]);\n\n const getBlockAttr = useCallback(\n <K extends keyof BlockAttrs>(key: K): BlockAttrs[K] | \"mixed\" | undefined => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n const first = doc.getBlockAttrs(start.blockIndex)[key];\n for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {\n const next = doc.getBlockAttrs(i)[key];\n if (next !== first) return \"mixed\";\n }\n return first;\n },\n [doc],\n );\n\n const setBlockType = useCallback((type: BlockType, attrs?: BlockAttrs) => {\n cmdSetBlockType(ctxRef.current, type, attrs);\n }, []);\n\n const setBlockAttr = useCallback(\n <K extends keyof BlockAttrs>(key: K, value: BlockAttrs[K] | null) => {\n cmdSetBlockAttr(ctxRef.current, key, value);\n },\n [],\n );\n\n const setAlign = useCallback((value: AlignValue) => {\n const sel = selectionRef.current;\n // Route on focus only: setCellAttr keys off sel.focus.cellIndex internally\n // and returns early unless the focus position is inside a table cell.\n const inCell = sel.focus.cellIndex != null;\n if (inCell) cmdSetCellAttr(ctxRef.current, \"align\", value);\n else cmdSetBlockAttr(ctxRef.current, \"align\", value);\n }, []);\n\n const getAlign = useCallback((): AlignValue | \"mixed\" | undefined => {\n const sel = selectionRef.current;\n if (sel.focus.cellIndex != null && doc.isTable(sel.focus.blockIndex)) {\n // Cell path: single focused-cell read (multi-cell mixed-state is out of scope).\n return doc.getCellAttrs(sel.focus.blockIndex, sel.focus.cellIndex).align;\n }\n // Block path: delegate to getBlockAttr so multi-block selections return \"mixed\".\n return getBlockAttr(\"align\");\n }, [doc, getBlockAttr]);\n\n const setCellBackground = useCallback((color: string | null) => {\n // setCellAttr keys off sel.focus.cellIndex internally: applies to the\n // rect selection (or the focused cell) and no-ops outside a table.\n cmdSetCellAttr(ctxRef.current, \"bgColor\", color);\n }, []);\n\n const getCellBackground = useCallback((): string | undefined => {\n const sel = selectionRef.current;\n if (sel.focus.cellIndex == null || !doc.isTable(sel.focus.blockIndex)) return undefined;\n // Single focused-cell read, like getAlign (multi-cell mixed-state out of scope).\n return doc.getCellAttrs(sel.focus.blockIndex, sel.focus.cellIndex).bgColor;\n }, [doc]);\n\n const setTableBorderPreset = useCallback((preset: TableBorderPreset) => {\n const sel = selectionRef.current;\n if (!doc.isTable(sel.focus.blockIndex)) return;\n // setBlockAttr é inerte com o caret dentro de uma célula — que é sempre o\n // caso aqui. Por isso a escrita é por índice de bloco.\n cmdSetBlockAttrAtIndex(ctxRef.current, sel.focus.blockIndex, \"borderPreset\", preset);\n }, [doc]);\n\n const getTableBorderPreset = useCallback((): TableBorderPreset => {\n const sel = selectionRef.current;\n if (!doc.isTable(sel.focus.blockIndex)) return \"all\";\n return doc.getBlockAttrs(sel.focus.blockIndex).borderPreset ?? \"all\";\n }, [doc]);\n\n const setTableBorderColor = useCallback((color: string | null) => {\n const sel = selectionRef.current;\n if (!doc.isTable(sel.focus.blockIndex)) return;\n cmdSetBlockAttrAtIndex(ctxRef.current, sel.focus.blockIndex, \"borderColor\", color);\n }, [doc]);\n\n const getTableBorderColor = useCallback((): string | undefined => {\n const sel = selectionRef.current;\n if (!doc.isTable(sel.focus.blockIndex)) return undefined;\n return doc.getBlockAttrs(sel.focus.blockIndex).borderColor;\n }, [doc]);\n\n const isListActive = useCallback(\n (kind: ListKind): boolean => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n for (let i = start.blockIndex; i <= end.blockIndex; i++) {\n if (doc.getBlockType(i) !== \"listItem\") return false;\n if (doc.getBlockAttrs(i).listKind !== kind) return false;\n }\n return true;\n },\n [doc],\n );\n\n const toggleList = useCallback((kind: ListKind) => {\n cmdToggleList(ctxRef.current, kind);\n }, []);\n const indentList = useCallback(() => {\n cmdIndentList(ctxRef.current);\n }, []);\n const dedentList = useCallback(() => {\n cmdDedentList(ctxRef.current);\n }, []);\n const splitListItem = useCallback((): boolean => {\n return cmdSplitListItem(ctxRef.current);\n }, []);\n\n // ---- Tables ----\n const isInTable = useCallback((): boolean => {\n return selectionRef.current.focus.cellIndex != null;\n }, []);\n const getTableLocation = useCallback((): TableLocation | null => {\n return tableLocationOf(doc, selectionRef.current.focus);\n }, [doc]);\n const insertTable = useCallback((rows: number, cols: number) => {\n cmdInsertTable(ctxRef.current, rows, cols);\n }, []);\n const insertAnswerLines = useCallback((count: number, spacing: AnswerLineSpacing) => {\n cmdInsertAnswerLines(ctxRef.current, count, spacing);\n }, []);\n const deleteTable = useCallback((blockIndex?: number) => {\n const idx = blockIndex ?? selectionRef.current.focus.blockIndex;\n cmdDeleteTable(ctxRef.current, idx);\n }, []);\n const insertRowAbove = useCallback(() => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return;\n cmdInsertRow(ctxRef.current, loc.blockIndex, loc.row, \"before\");\n }, [doc]);\n const insertRowBelow = useCallback(() => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return;\n cmdInsertRow(ctxRef.current, loc.blockIndex, loc.row, \"after\");\n }, [doc]);\n const deleteCurrentRow = useCallback(() => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return;\n cmdDeleteRow(ctxRef.current, loc.blockIndex, loc.row);\n }, [doc]);\n const insertColumnLeft = useCallback(() => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return;\n cmdInsertColumn(ctxRef.current, loc.blockIndex, loc.col, \"before\");\n }, [doc]);\n const insertColumnRight = useCallback(() => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return;\n cmdInsertColumn(ctxRef.current, loc.blockIndex, loc.col, \"after\");\n }, [doc]);\n const deleteCurrentColumn = useCallback(() => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return;\n cmdDeleteColumn(ctxRef.current, loc.blockIndex, loc.col);\n }, [doc]);\n const moveToNextCell = useCallback(() => {\n cmdMoveNextCell(ctxRef.current);\n }, []);\n const moveToPrevCell = useCallback(() => {\n cmdMovePrevCell(ctxRef.current);\n }, []);\n const mergeRight = useCallback((): boolean => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return false;\n return cmdMergeRight(ctxRef.current, loc.blockIndex, loc.row, loc.col);\n }, [doc]);\n const mergeDown = useCallback((): boolean => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return false;\n return cmdMergeDown(ctxRef.current, loc.blockIndex, loc.row, loc.col);\n }, [doc]);\n const splitCell = useCallback((): boolean => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return false;\n return cmdSplitCell(ctxRef.current, loc.blockIndex, loc.row, loc.col);\n }, [doc]);\n const setColumnWidth = useCallback(\n (blockIndex: number, col: number, widthPx: number) => {\n cmdSetColumnWidth(ctxRef.current, blockIndex, col, widthPx);\n },\n [],\n );\n const getTableRect = useCallback(\n () => tableRectSelection(doc, selectionRef.current),\n [doc],\n );\n const hasTableRectSelection = useCallback((): boolean => {\n return tableRectSelection(doc, selectionRef.current) !== null;\n }, [doc]);\n const mergeSelection = useCallback((): boolean => {\n return cmdMergeSelection(ctxRef.current);\n }, []);\n\n // ---- Inline images ----\n const insertImage = useCallback((embed: ImageEmbed) => {\n cmdInsertImage(ctxRef.current, embed);\n }, []);\n const setImageAttrs = useCallback(\n (\n blockIndex: number,\n offset: number,\n partial: Partial<ImageEmbed>,\n cellIndex?: number,\n newOffset?: number,\n ) => {\n cmdSetImageAttrs(ctxRef.current, blockIndex, offset, partial, cellIndex, newOffset);\n },\n [],\n );\n const moveEmbedAnchor = useCallback(\n (from: EmbedLoc, to: EmbedLoc, newOffsetX: number, newOffsetY: number) => {\n cmdMoveEmbedAnchor(ctxRef.current, from, to, newOffsetX, newOffsetY);\n },\n [],\n );\n const uploadImageRef = useRef(opts.uploadImage);\n uploadImageRef.current = opts.uploadImage;\n const insertImageFromFile = useCallback(async (file: File): Promise<void> => {\n if (!file.type.startsWith(\"image/\")) return;\n // Lê dimensões a partir de um dataUrl temporário em ambos os caminhos\n // (lê o arquivo só uma vez; o uploadImage decide se persiste essa data\n // ou faz upload pra um storage externo).\n const dataUrl = await readAsDataURL(file);\n const dims = await readImageDimensions(dataUrl);\n let w = dims.width;\n let h = dims.height;\n if (w > MAX_INSERT_WIDTH) {\n h = Math.round((h * MAX_INSERT_WIDTH) / w);\n w = MAX_INSERT_WIDTH;\n }\n const upload = uploadImageRef.current;\n const src = upload ? await upload(file) : dataUrl;\n cmdInsertImage(ctxRef.current, { type: \"image\", src, width: w, height: h });\n }, []);\n const getSelectedEmbed = useCallback(() => {\n const sel = selectionRef.current;\n if (sel.anchor.blockIndex !== sel.focus.blockIndex) return null;\n if ((sel.anchor.cellIndex ?? -1) !== (sel.focus.cellIndex ?? -1)) return null;\n const a = sel.anchor.offset;\n const b = sel.focus.offset;\n if (Math.abs(a - b) !== 1) return null;\n const start = Math.min(a, b);\n const yText = doc.textAt(sel.anchor.blockIndex, sel.anchor.cellIndex);\n if (!yText) return null;\n const delta = yText.toDelta() as DeltaOp[];\n let cursor = 0;\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n cursor += op.insert.length;\n continue;\n }\n if (cursor === start && isImageEmbed(op.insert)) {\n return {\n blockIndex: sel.anchor.blockIndex,\n cellIndex: sel.anchor.cellIndex,\n offset: start,\n embed: op.insert,\n };\n }\n cursor += 1;\n }\n return null;\n }, [doc]);\n\n const [linkRequest, setLinkRequest] = useState<LinkRequest | null>(null);\n const linkRequestRef = useRef<LinkRequest | null>(null);\n const requestLink = useCallback((initialHref = \"\"): Promise<string | null> => {\n return new Promise((resolve) => {\n // Capture the model selection NOW (bug #6): the modal round-trip can\n // collapse it (the editor refocuses on close → selectionchange overwrites\n // the model), and the consumer applies the link mark AFTER the modal —\n // a no-op on a collapsed selection. We restore it on resolve.\n const req: LinkRequest = { initialHref, resolve, selection: selectionRef.current };\n linkRequestRef.current = req;\n setLinkRequest(req);\n });\n }, []);\n const resolveLinkRequest = useCallback(\n (href: string | null) => {\n const req = linkRequestRef.current;\n linkRequestRef.current = null;\n setLinkRequest(null);\n if (req) {\n // Restore the captured selection so the consumer's setMark applies to\n // the originally-selected text even if the modal collapsed it.\n setSelection(req.selection);\n req.resolve(href);\n }\n },\n [setSelection],\n );\n\n // ---- Page settings ----\n const pageSettings = usePageSettings(doc);\n const setPageSettings = useCallback(\n (partial: Partial<PageSettings>) => {\n doc.setPageSettings(partial);\n },\n [doc],\n );\n const [pageConfigRequest, setPageConfigRequest] = useState<PageConfigRequest | null>(null);\n const requestPageConfig = useCallback((): Promise<boolean> => {\n return new Promise((resolve) => {\n setPageConfigRequest({ initial: doc.getPageSettings(), resolve });\n });\n }, [doc]);\n const resolvePageConfigRequest = useCallback((applied: boolean) => {\n setPageConfigRequest((prev) => {\n if (prev) prev.resolve(applied);\n return null;\n });\n }, []);\n\n // ---- Image caption ----\n const [imageCaptionRequest, setImageCaptionRequest] =\n useState<ImageCaptionRequest | null>(null);\n const requestImageCaption = useCallback(\n (initialCaption = \"\", initialAlign: CaptionAlign = \"center\"): Promise<ImageCaptionResult | null> => {\n return new Promise((resolve) => {\n setImageCaptionRequest({ initialCaption, initialAlign, resolve });\n });\n },\n [],\n );\n const resolveImageCaptionRequest = useCallback((result: ImageCaptionResult | null) => {\n setImageCaptionRequest((prev) => {\n if (prev) prev.resolve(result);\n return null;\n });\n }, []);\n\n return {\n doc,\n history,\n snapshot,\n selection,\n setSelection,\n getSelection,\n isMarkActive,\n getActiveMarks,\n toggleMark,\n setMark,\n removeMark,\n pendingMarks,\n consumePendingMarks,\n getBlockType,\n getBlockAttr,\n setBlockType,\n setBlockAttr,\n setAlign,\n getAlign,\n setCellBackground,\n getCellBackground,\n setTableBorderPreset,\n getTableBorderPreset,\n setTableBorderColor,\n getTableBorderColor,\n isListActive,\n toggleList,\n indentList,\n dedentList,\n splitListItem,\n linkRequest,\n requestLink,\n resolveLinkRequest,\n isInTable,\n getTableLocation,\n insertAnswerLines,\n insertTable,\n deleteTable,\n insertRowAbove,\n insertRowBelow,\n deleteCurrentRow,\n insertColumnLeft,\n insertColumnRight,\n deleteCurrentColumn,\n moveToNextCell,\n moveToPrevCell,\n mergeRight,\n mergeDown,\n splitCell,\n setColumnWidth,\n getTableRect,\n hasTableRectSelection,\n mergeSelection,\n insertImage,\n setImageAttrs,\n moveEmbedAnchor,\n insertImageFromFile,\n getSelectedEmbed,\n pageSettings,\n setPageSettings,\n pageConfigRequest,\n requestPageConfig,\n resolvePageConfigRequest,\n imageCaptionRequest,\n requestImageCaption,\n resolveImageCaptionRequest,\n };\n}\n\nfunction readAsDataURL(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onerror = () => reject(reader.error ?? new Error(\"FileReader error\"));\n reader.onload = () => resolve(reader.result as string);\n reader.readAsDataURL(file);\n });\n}\n\nfunction readImageDimensions(src: string): Promise<{ width: number; height: number }> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onerror = () => reject(new Error(\"image load failed\"));\n img.onload = () => resolve({ width: img.naturalWidth, height: img.naturalHeight });\n img.src = src;\n });\n}\n\nconst booleanMarks: Set<MarkName> = new Set([\"bold\", \"italic\", \"underline\", \"strike\"]);\n\nfunction sameValue(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a === \"object\" && a && b && typeof b === \"object\") {\n const ak = Object.keys(a);\n const bk = Object.keys(b);\n if (ak.length !== bk.length) return false;\n return ak.every((k) => (a as Record<string, unknown>)[k] === (b as Record<string, unknown>)[k]);\n }\n return false;\n}\n","import { useCallback, useRef, useSyncExternalStore } from \"react\";\nimport type { EditorDocument, PageSettings } from \"@sofereditor/core\";\n\n/**\n * Reactive snapshot of an `EditorDocument`'s page settings. Re-renders the\n * component when `docSettings` changes (either locally via `setPageSettings`\n * or remotely via Y.js sync).\n *\n * Caches the snapshot reference to satisfy `useSyncExternalStore`'s stable-\n * identity requirement — `getPageSettings` returns a fresh object each call,\n * which would loop the store forever without this caching.\n */\nexport function usePageSettings(doc: EditorDocument): PageSettings {\n const cacheRef = useRef<PageSettings | null>(null);\n\n const subscribe = useCallback(\n (notify: () => void) => doc.observePageSettings(notify),\n [doc],\n );\n\n const getSnapshot = useCallback((): PageSettings => {\n const next = doc.getPageSettings();\n const prev = cacheRef.current;\n if (prev && shallowEqual(prev, next)) return prev;\n cacheRef.current = next;\n return next;\n }, [doc]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nfunction shallowEqual(a: PageSettings, b: PageSettings): boolean {\n return (\n a.width === b.width &&\n a.height === b.height &&\n a.marginTop === b.marginTop &&\n a.marginBottom === b.marginBottom &&\n a.marginLeft === b.marginLeft &&\n a.marginRight === b.marginRight &&\n a.preset === b.preset &&\n a.systemHeaderTitle === b.systemHeaderTitle &&\n a.systemHeaderAuthor === b.systemHeaderAuthor\n );\n}\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type ChangeEvent,\n type JSX,\n type MouseEvent,\n type ReactNode,\n} from \"react\";\nimport { useEditorContext } from \"./EditorContext\";\nimport { ANSWER_LINE_MAX, TABLE_BORDER_COLOR } from \"@sofereditor/core\";\nimport type {\n AlignValue,\n AnswerLineSpacing,\n BlockType,\n DirValue,\n ImageLayout,\n MarkName,\n TableBorderPreset,\n} from \"@sofereditor/core\";\n\n// School standard: Arial only. The dropdown is kept (instead of removed) so\n// that the surrounding font-size / color UI stays balanced and future font\n// additions are a one-liner.\nconst FONT_FAMILIES = [\"Arial\"];\nconst FONT_SIZES = [\"8pt\", \"10pt\", \"11pt\", \"12pt\", \"14pt\", \"16pt\", \"18pt\", \"24pt\", \"32pt\", \"48pt\"];\n\ninterface BlockOption {\n value: string;\n label: string;\n type: BlockType;\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n}\n\nconst BLOCK_OPTIONS: BlockOption[] = [\n { value: \"paragraph\", label: \"Parágrafo\", type: \"paragraph\" },\n { value: \"h1\", label: \"Título 1\", type: \"heading\", level: 1 },\n { value: \"h2\", label: \"Título 2\", type: \"heading\", level: 2 },\n { value: \"h3\", label: \"Título 3\", type: \"heading\", level: 3 },\n { value: \"h4\", label: \"Título 4\", type: \"heading\", level: 4 },\n { value: \"h5\", label: \"Título 5\", type: \"heading\", level: 5 },\n { value: \"h6\", label: \"Título 6\", type: \"heading\", level: 6 },\n { value: \"blockquote\", label: \"Citação\", type: \"blockquote\" },\n { value: \"codeBlock\", label: \"Código\", type: \"codeBlock\" },\n];\n\nconst ALIGN_OPTIONS: { value: AlignValue; label: string; title: string }[] = [\n { value: \"left\", label: \"⇤\", title: \"Alinhar à esquerda\" },\n { value: \"center\", label: \"≡\", title: \"Centralizar\" },\n { value: \"right\", label: \"⇥\", title: \"Alinhar à direita\" },\n { value: \"justify\", label: \"☰\", title: \"Justificar\" },\n];\n\nconst IMAGE_ALIGN_VALUES = new Set<AlignValue>([\"left\", \"center\", \"right\"]);\n\n/**\n * Controles nativos que PRECISAM receber o `mousedown` para abrir seu\n * dropdown/picker. Prevenir o mousedown num `<select>` impede o dropdown de\n * abrir — foi exatamente assim que o seletor de bordas da tabela nasceu morto.\n *\n * A regra vivia duplicada em três handlers com três listas diferentes; fica\n * aqui numa fonte só para não voltar a divergir.\n */\nconst NATIVE_CONTROL_TAGS = new Set([\"SELECT\", \"INPUT\", \"OPTION\"]);\n\nexport function isNativeControl(t: EventTarget | null): boolean {\n const el = t as HTMLElement | null;\n return !!el && NATIVE_CONTROL_TAGS.has(el.tagName);\n}\n\n/**\n * Alvos dentro de um popover que mantêm o próprio `mousedown`. Superconjunto de\n * `isNativeControl` mais `BUTTON` — o resto é fundo de popover, onde o\n * `preventDefault` protege a seleção do editor.\n */\nexport function keepsOwnMouseDown(t: EventTarget | null): boolean {\n const el = t as HTMLElement | null;\n return !!el && (NATIVE_CONTROL_TAGS.has(el.tagName) || el.tagName === \"BUTTON\");\n}\n\nconst IMAGE_LAYOUT_OPTIONS: { value: ImageLayout; label: string; title: string }[] = [\n { value: \"inline\", label: \"↔\", title: \"Inline (no fluxo do texto)\" },\n { value: \"wrap-left\", label: \"◧\", title: \"Texto contorna à direita\" },\n { value: \"wrap-right\", label: \"◨\", title: \"Texto contorna à esquerda\" },\n { value: \"behind\", label: \"▢↓\", title: \"Atrás do texto\" },\n { value: \"front\", label: \"▢↑\", title: \"Na frente do texto\" },\n];\n\nexport interface ToolbarProps {\n className?: string;\n}\n\nexport function Toolbar({ className }: ToolbarProps): JSX.Element {\n const editor = useEditorContext();\n const {\n isMarkActive,\n getActiveMarks,\n toggleMark,\n setMark,\n removeMark,\n getBlockType,\n getBlockAttr,\n setBlockType,\n setBlockAttr,\n setAlign,\n getAlign,\n isListActive,\n toggleList,\n indentList,\n dedentList,\n } = editor;\n const active = getActiveMarks();\n const blockType = getBlockType();\n const blockLevel = getBlockAttr(\"level\");\n const blockAlign = getAlign();\n const blockDir = getBlockAttr(\"dir\");\n\n // Preserve contenteditable focus when clicking the toolbar background or buttons,\n // BUT let native form controls (select/input) receive mousedown normally so their\n // dropdowns/pickers can open.\n const stop = (e: MouseEvent) => {\n if (isNativeControl(e.target)) return;\n e.preventDefault();\n };\n\n const onToggle = (name: MarkName) => (e: MouseEvent) => {\n e.preventDefault();\n toggleMark(name);\n };\n\n const onColorChange = (e: ChangeEvent<HTMLInputElement>) => {\n setMark(\"color\", e.target.value);\n };\n\n const onHighlightChange = (e: ChangeEvent<HTMLInputElement>) => {\n setMark(\"highlight\", e.target.value);\n };\n\n const onFontFamilyChange = (e: ChangeEvent<HTMLSelectElement>) => {\n const v = e.target.value;\n if (v === \"\") removeMark(\"fontFamily\");\n else setMark(\"fontFamily\", v);\n };\n\n const onFontSizeChange = (e: ChangeEvent<HTMLSelectElement>) => {\n const v = e.target.value;\n if (v === \"\") removeMark(\"fontSize\");\n else setMark(\"fontSize\", v);\n };\n\n const onBlockChange = (e: ChangeEvent<HTMLSelectElement>) => {\n const opt = BLOCK_OPTIONS.find((o) => o.value === e.target.value);\n if (!opt) return;\n setBlockType(opt.type, opt.level !== undefined ? { level: opt.level } : undefined);\n };\n\n const onAlign = (value: AlignValue) => (e: MouseEvent) => {\n e.preventDefault();\n // When an image embed is selected, the three image-friendly alignments\n // (left/center/right) target the embed itself; otherwise fall through to\n // the block-level align attribute (which also handles \"justify\").\n const selectedEmbed = editor.getSelectedEmbed();\n if (selectedEmbed && IMAGE_ALIGN_VALUES.has(value)) {\n editor.setImageAttrs(\n selectedEmbed.blockIndex,\n selectedEmbed.offset,\n { align: value as \"left\" | \"center\" | \"right\" },\n selectedEmbed.cellIndex,\n );\n return;\n }\n setAlign(value);\n };\n\n const onInsertImageClick = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n imageInputRef.current?.click();\n },\n [],\n );\n const onImageInputChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (file) void editor.insertImageFromFile(file);\n e.target.value = \"\";\n },\n [editor],\n );\n const imageInputRef = useRef<HTMLInputElement>(null);\n\n const onToggleDir = (e: MouseEvent) => {\n e.preventDefault();\n const next: DirValue = blockDir === \"rtl\" ? \"ltr\" : \"rtl\";\n setBlockAttr(\"dir\", next);\n };\n\n const linkActive = isMarkActive(\"link\");\n const onLinkClick = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n const currentHref =\n active.link && typeof active.link === \"object\" && \"href\" in active.link\n ? (active.link.href as string)\n : \"\";\n void editor.requestLink(currentHref).then((href) => {\n if (href === null) return;\n if (href === \"\") removeMark(\"link\");\n else setMark(\"link\", { href });\n });\n },\n [active.link, editor, removeMark, setMark],\n );\n\n const colorValue = typeof active.color === \"string\" ? active.color : \"#000000\";\n // Amarelo clássico de marca-texto como padrão do picker quando nada está marcado.\n const highlightValue = typeof active.highlight === \"string\" ? active.highlight : \"#fff176\";\n const fontFamilyValue = typeof active.fontFamily === \"string\" ? active.fontFamily : \"\";\n const fontSizeValue = typeof active.fontSize === \"string\" ? active.fontSize : \"\";\n const blockValue = blockSelectValue(blockType, blockLevel);\n\n // The image layout group is only visible when an image embed is selected.\n // We read it fresh every render so the visibility tracks selection changes.\n const selectedEmbed = editor.getSelectedEmbed();\n const currentImageLayout: ImageLayout = selectedEmbed\n ? (selectedEmbed.embed.layout ?? \"inline\")\n : \"inline\";\n\n const onImageLayoutClick = (layout: ImageLayout) => (e: MouseEvent) => {\n e.preventDefault();\n const sel = editor.getSelectedEmbed();\n if (!sel) return;\n // Reset position offsets when switching modes; the previous values would\n // refer to a different coordinate system (margins vs. left/top).\n const reset =\n layout !== (sel.embed.layout ?? \"inline\")\n ? { offsetX: 0, offsetY: 0 }\n : {};\n editor.setImageAttrs(\n sel.blockIndex,\n sel.offset,\n { layout, ...reset },\n sel.cellIndex,\n );\n };\n\n return (\n <div\n className={className ?? \"ed-toolbar\"}\n role=\"toolbar\"\n aria-label=\"Editor toolbar\"\n onMouseDown={stop}\n >\n <Group>\n <select\n className=\"ed-toolbar-select\"\n value={blockValue}\n onChange={onBlockChange}\n onMouseDown={stop}\n aria-label=\"Tipo de bloco\"\n >\n {blockValue === \"\" && <option value=\"\">— (misto)</option>}\n {BLOCK_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>{o.label}</option>\n ))}\n </select>\n </Group>\n\n <Group>\n <MarkButton title=\"Negrito (⌘B)\" pressed={isMarkActive(\"bold\")} onClick={onToggle(\"bold\")}>\n <strong>B</strong>\n </MarkButton>\n <MarkButton title=\"Itálico (⌘I)\" pressed={isMarkActive(\"italic\")} onClick={onToggle(\"italic\")}>\n <em>I</em>\n </MarkButton>\n <MarkButton title=\"Sublinhado (⌘U)\" pressed={isMarkActive(\"underline\")} onClick={onToggle(\"underline\")}>\n <u>U</u>\n </MarkButton>\n <MarkButton title=\"Tachado (⌘⇧X)\" pressed={isMarkActive(\"strike\")} onClick={onToggle(\"strike\")}>\n <s>S</s>\n </MarkButton>\n </Group>\n\n <Group>\n <label className=\"ed-toolbar-label\">\n <span className=\"ed-toolbar-swatch\" aria-hidden style={{ background: colorValue }} />\n <input type=\"color\" value={colorValue} onChange={onColorChange} onMouseDown={stop} aria-label=\"Cor do texto\" />\n </label>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Remover cor\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n removeMark(\"color\");\n }}\n >\n ⌫\n </button>\n <label className=\"ed-toolbar-label\" title=\"Marca-texto\">\n <span\n className=\"ed-toolbar-swatch ed-toolbar-swatch--highlight\"\n aria-hidden\n style={{ background: highlightValue }}\n />\n <input\n type=\"color\"\n value={highlightValue}\n onChange={onHighlightChange}\n onMouseDown={stop}\n aria-label=\"Marca-texto\"\n />\n </label>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Remover marca-texto\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n removeMark(\"highlight\");\n }}\n >\n ⌫\n </button>\n </Group>\n\n <Group>\n <select\n className=\"ed-toolbar-select\"\n value={fontFamilyValue}\n onChange={onFontFamilyChange}\n onMouseDown={stop}\n aria-label=\"Família da fonte\"\n >\n <option value=\"\">Fonte…</option>\n {FONT_FAMILIES.map((f) => (\n <option key={f} value={f}>{f}</option>\n ))}\n </select>\n <select\n className=\"ed-toolbar-select\"\n value={fontSizeValue}\n onChange={onFontSizeChange}\n onMouseDown={stop}\n aria-label=\"Tamanho da fonte\"\n >\n <option value=\"\">Tamanho…</option>\n {FONT_SIZES.map((s) => (\n <option key={s} value={s}>{s}</option>\n ))}\n </select>\n </Group>\n\n <Group>\n {ALIGN_OPTIONS.map((a) => (\n <button\n key={a.value}\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title={a.title}\n aria-pressed={blockAlign === a.value}\n onMouseDown={stop}\n onClick={onAlign(a.value)}\n >\n {a.label}\n </button>\n ))}\n </Group>\n\n <Group>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n aria-pressed={blockDir === \"rtl\"}\n title={blockDir === \"rtl\" ? \"Mudar para LTR\" : \"Mudar para RTL (hebraico)\"}\n onMouseDown={stop}\n onClick={onToggleDir}\n >\n {blockDir === \"rtl\" ? \"RTL\" : \"LTR\"}\n </button>\n </Group>\n\n <Group>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n aria-pressed={isListActive(\"bullet\")}\n title=\"Lista com marcadores (⌘⇧8)\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n toggleList(\"bullet\");\n }}\n >\n •\n </button>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n aria-pressed={isListActive(\"ordered\")}\n title=\"Lista numerada (⌘⇧7)\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n toggleList(\"ordered\");\n }}\n >\n 1.\n </button>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Diminuir recuo (⇧Tab)\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n dedentList();\n }}\n >\n ⇤\n </button>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Aumentar recuo (Tab)\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n indentList();\n }}\n >\n ⇥\n </button>\n </Group>\n\n <Group>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n aria-pressed={linkActive}\n title={linkActive ? \"Remover link (⌘K)\" : \"Adicionar link (⌘K)\"}\n onMouseDown={stop}\n onClick={onLinkClick}\n >\n 🔗\n </button>\n </Group>\n\n <Group>\n <TableMenu />\n <AnswerLinesMenu />\n </Group>\n\n <Group>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Inserir imagem\"\n onMouseDown={stop}\n onClick={onInsertImageClick}\n >\n 🖼\n </button>\n <input\n ref={imageInputRef}\n type=\"file\"\n accept=\"image/*\"\n hidden\n onChange={onImageInputChange}\n />\n </Group>\n\n {selectedEmbed && (\n <Group>\n {IMAGE_LAYOUT_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title={opt.title}\n aria-pressed={currentImageLayout === opt.value}\n onMouseDown={stop}\n onClick={onImageLayoutClick(opt.value)}\n >\n {opt.label}\n </button>\n ))}\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Legenda da imagem\"\n aria-pressed={!!selectedEmbed.embed.caption}\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n const initialCaption = selectedEmbed.embed.caption ?? \"\";\n const initialAlign = selectedEmbed.embed.captionAlign ?? \"center\";\n void editor.requestImageCaption(initialCaption, initialAlign).then((result) => {\n if (result === null) return; // cancelled\n const empty = result.caption.length === 0;\n editor.setImageAttrs(\n selectedEmbed.blockIndex,\n selectedEmbed.offset,\n {\n caption: empty ? undefined : result.caption,\n captionAlign: empty ? undefined : result.align,\n },\n selectedEmbed.cellIndex,\n );\n });\n }}\n >\n Legenda\n </button>\n </Group>\n )}\n\n <Group>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Configurar página (tamanho, margens)\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n void editor.requestPageConfig();\n }}\n >\n ⚙\n </button>\n </Group>\n </div>\n );\n}\n\n// ---------- Table menu ----------\n\n/**\n * Linhas de resposta: parágrafos pautados para o aluno escrever.\n *\n * Um botão em vez da digitação de underlines porque a régua precisa acompanhar\n * a margem — uma fileira de `_` quebra ao mudar tamanho de página ou fonte.\n */\nfunction AnswerLinesMenu(): JSX.Element {\n const editor = useEditorContext();\n const [open, setOpen] = useState(false);\n const [count, setCount] = useState(5);\n const [spacing, setSpacing] = useState<AnswerLineSpacing>(1.5);\n const rootRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!open) return;\n const onDown = (e: globalThis.MouseEvent) => {\n if (!rootRef.current) return;\n if (rootRef.current.contains(e.target as Node)) return;\n setOpen(false);\n };\n document.addEventListener(\"mousedown\", onDown);\n return () => document.removeEventListener(\"mousedown\", onDown);\n }, [open]);\n\n const clamped = Math.max(1, Math.min(ANSWER_LINE_MAX, Math.trunc(count) || 1));\n\n return (\n <div ref={rootRef} className=\"ed-toolbar-tablemenu\">\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Linhas de resposta\"\n aria-pressed={open}\n onMouseDown={(e) => e.preventDefault()}\n onClick={(e) => {\n e.preventDefault();\n setOpen((v) => !v);\n }}\n >\n ☰\n </button>\n {open && (\n <div\n className=\"ed-table-popover ed-answerlines-popover\"\n role=\"menu\"\n onMouseDown={(e) => {\n if (!keepsOwnMouseDown(e.target)) e.preventDefault();\n }}\n >\n <label className=\"ed-toolbar-label\">\n Quantidade\n <input\n type=\"number\"\n min={1}\n max={ANSWER_LINE_MAX}\n value={count}\n onChange={(e) => setCount(Number(e.target.value))}\n aria-label=\"Quantidade de linhas\"\n />\n </label>\n <label className=\"ed-toolbar-label\">\n Entrelinha\n <select\n value={String(spacing)}\n onChange={(e) => setSpacing(Number(e.target.value) as AnswerLineSpacing)}\n aria-label=\"Entrelinha\"\n >\n <option value=\"1\">Simples</option>\n <option value=\"1.5\">1,5</option>\n <option value=\"2\">Duplo</option>\n </select>\n </label>\n <button\n type=\"button\"\n onClick={() => {\n setOpen(false);\n editor.insertAnswerLines(clamped, spacing);\n }}\n >\n Inserir {clamped} linha{clamped > 1 ? \"s\" : \"\"}\n </button>\n </div>\n )}\n </div>\n );\n}\n\nfunction TableMenu(): JSX.Element {\n const editor = useEditorContext();\n const inTable = editor.isInTable();\n const [open, setOpen] = useState(false);\n const rootRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!open) return;\n const onDown = (e: globalThis.MouseEvent) => {\n if (!rootRef.current) return;\n if (rootRef.current.contains(e.target as Node)) return;\n setOpen(false);\n };\n document.addEventListener(\"mousedown\", onDown);\n return () => document.removeEventListener(\"mousedown\", onDown);\n }, [open]);\n\n return (\n <div ref={rootRef} className=\"ed-toolbar-tablemenu\">\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Tabela\"\n aria-pressed={open}\n onMouseDown={(e) => e.preventDefault()}\n onClick={(e) => {\n e.preventDefault();\n setOpen((v) => !v);\n }}\n >\n ▦\n </button>\n {open && (\n <div\n className=\"ed-table-popover\"\n role=\"menu\"\n onMouseDown={(e) => {\n // Do not let mousedown clear the editor selection.\n if (!keepsOwnMouseDown(e.target)) e.preventDefault();\n }}\n >\n <TableSizePicker\n onPick={(rows, cols) => {\n setOpen(false);\n editor.insertTable(rows, cols);\n }}\n />\n {inTable && (\n <div className=\"ed-table-actions\">\n <hr />\n <button type=\"button\" onClick={() => { setOpen(false); editor.insertRowAbove(); }}>\n Inserir linha acima\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.insertRowBelow(); }}>\n Inserir linha abaixo\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.insertColumnLeft(); }}>\n Inserir coluna à esquerda\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.insertColumnRight(); }}>\n Inserir coluna à direita\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.deleteCurrentRow(); }}>\n Excluir linha\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.deleteCurrentColumn(); }}>\n Excluir coluna\n </button>\n <hr />\n {editor.hasTableRectSelection() && (\n <button\n type=\"button\"\n onClick={() => { setOpen(false); editor.mergeSelection(); }}\n >\n Mesclar células selecionadas\n </button>\n )}\n <button type=\"button\" onClick={() => { setOpen(false); editor.mergeRight(); }}>\n Mesclar com célula à direita\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.mergeDown(); }}>\n Mesclar com célula abaixo\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.splitCell(); }}>\n Dividir células mescladas\n </button>\n <hr />\n <label className=\"ed-toolbar-label ed-table-bgcolor\">\n <span\n className=\"ed-toolbar-swatch\"\n aria-hidden\n style={{ background: editor.getCellBackground() ?? \"#ffffff\" }}\n />\n Cor de fundo da célula\n <input\n type=\"color\"\n value={editor.getCellBackground() ?? \"#ffffff\"}\n onChange={(e) => editor.setCellBackground(e.target.value)}\n aria-label=\"Cor de fundo da célula\"\n />\n </label>\n <button type=\"button\" onClick={() => { setOpen(false); editor.setCellBackground(null); }}>\n Remover cor de fundo\n </button>\n <hr />\n <label className=\"ed-toolbar-label\">\n Bordas\n <select\n value={editor.getTableBorderPreset()}\n onChange={(e) =>\n editor.setTableBorderPreset(e.target.value as TableBorderPreset)\n }\n aria-label=\"Bordas da tabela\"\n >\n <option value=\"all\">Todas</option>\n <option value=\"outer\">Só externas</option>\n <option value=\"horizontal\">Só horizontais</option>\n <option value=\"vertical\">Só verticais</option>\n <option value=\"none\">Nenhuma</option>\n </select>\n </label>\n <label className=\"ed-toolbar-label ed-table-bgcolor\">\n <span\n className=\"ed-toolbar-swatch\"\n aria-hidden\n style={{ background: editor.getTableBorderColor() ?? TABLE_BORDER_COLOR }}\n />\n Cor da borda\n <input\n type=\"color\"\n value={editor.getTableBorderColor() ?? TABLE_BORDER_COLOR}\n onChange={(e) => editor.setTableBorderColor(e.target.value)}\n aria-label=\"Cor da borda\"\n />\n </label>\n <button\n type=\"button\"\n onClick={() => { setOpen(false); editor.setTableBorderColor(null); }}\n >\n Restaurar cor padrão\n </button>\n <hr />\n <button\n type=\"button\"\n className=\"ed-table-delete\"\n onClick={() => { setOpen(false); editor.deleteTable(); }}\n >\n Excluir tabela\n </button>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\nconst PICKER_MAX_ROWS = 8;\nconst PICKER_MAX_COLS = 10;\n\ninterface TableSizePickerProps {\n onPick: (rows: number, cols: number) => void;\n}\n\nfunction TableSizePicker({ onPick }: TableSizePickerProps): JSX.Element {\n const [hover, setHover] = useState<{ r: number; c: number } | null>(null);\n const label = hover ? `${hover.r + 1} × ${hover.c + 1}` : \"Inserir tabela\";\n return (\n <div className=\"ed-table-picker\">\n <div className=\"ed-table-picker-label\">{label}</div>\n <div\n className=\"ed-table-picker-grid\"\n style={{\n gridTemplateColumns: `repeat(${PICKER_MAX_COLS}, 18px)`,\n gridTemplateRows: `repeat(${PICKER_MAX_ROWS}, 18px)`,\n }}\n onMouseLeave={() => setHover(null)}\n >\n {Array.from({ length: PICKER_MAX_ROWS }, (_, r) =>\n Array.from({ length: PICKER_MAX_COLS }, (_, c) => {\n const filled = hover != null && r <= hover.r && c <= hover.c;\n return (\n <button\n key={`${r}-${c}`}\n type=\"button\"\n className={`ed-table-picker-cell${filled ? \" filled\" : \"\"}`}\n onMouseEnter={() => setHover({ r, c })}\n onMouseDown={(e) => e.preventDefault()}\n onClick={(e) => {\n e.preventDefault();\n onPick(r + 1, c + 1);\n }}\n aria-label={`${r + 1} × ${c + 1}`}\n />\n );\n }),\n )}\n </div>\n </div>\n );\n}\n\nfunction blockSelectValue(\n type: BlockType | \"mixed\",\n level: unknown,\n): string {\n if (type === \"mixed\") return \"\";\n if (type === \"heading\") {\n if (typeof level === \"number\" && level >= 1 && level <= 6) return `h${level}`;\n return \"h1\";\n }\n return type;\n}\n\nfunction Group({ children }: { children: ReactNode }): JSX.Element {\n return <div className=\"ed-toolbar-group\">{children}</div>;\n}\n\ninterface MarkButtonProps {\n title: string;\n pressed: boolean;\n onClick: (e: MouseEvent) => void;\n children: ReactNode;\n}\n\nfunction MarkButton({ title, pressed, onClick, children }: MarkButtonProps): JSX.Element {\n return (\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n aria-pressed={pressed}\n title={title}\n onMouseDown={(e) => e.preventDefault()}\n onClick={onClick}\n >\n {children}\n </button>\n );\n}\n"],"mappings":"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","names":["useCallback","useEffect","useLayoutEffect","useMemo","useRef","useState","Fragment","jsx","jsxs","useEffect","useState","jsx","jsxs","useState","useEffect","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useEffect","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useEffect","jsx","jsxs","useCallback","useEffect","useLayoutEffect","useRef","useState","jsx","jsxs","useState","useRef","useCallback","useLayoutEffect","useEffect","useCallback","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useCallback","useEffect","useMemo","useRef","Fragment","jsx","jsxs","Fragment","useCallback","useEffect","useLayoutEffect","useRef","useState","Fragment","jsx","useState","useRef","useCallback","useLayoutEffect","useEffect","jsx","jsxs","useRef","useMemo","_","useLayoutEffect","useRef","useState","currentPage","useCallback","useEffect","useMemo","useRef","useState","useCallback","useRef","tableRectSelection","isImageEmbed","useMemo","useState","useRef","useCallback","useEffect","yText","jsx","jsxs","useRef","useState","useEffect","useLayoutEffect","selectedEmbed","useCallback","useMemo","clampListLevel","useCallback","useEffect","useRef","useState","jsx","jsxs","selectedEmbed","useCallback","useRef","useState","useEffect","_"]}
|
|
1
|
+
{"version":3,"sources":["../src/Editor.tsx","../src/dom-bridge.ts","../src/pastePlan.ts","../src/htmlToSlice.ts","../src/BehindImageSelectAffordance.tsx","../src/LinkHoverTooltip.tsx","../src/platform.ts","../src/EditorContext.tsx","../src/LinkDialog.tsx","../src/dialogCenterStyle.ts","../src/PageConfigDialog.tsx","../src/ImageCaptionDialog.tsx","../src/ImageResizeOverlay.tsx","../src/RemoteCursorsOverlay.tsx","../src/NodeView.tsx","../src/renderInline.tsx","../src/sliceDelta.ts","../src/TableResizeOverlay.tsx","../src/usePagination.ts","../src/useEditor.ts","../src/usePageSettings.ts","../src/Toolbar.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type JSX,\n type KeyboardEvent,\n type ReactNode,\n type RefObject,\n} from \"react\";\nimport {\n deleteBackward,\n deleteForward,\n deleteSelection,\n encodeSelection,\n insertParagraph,\n insertSlice,\n insertText,\n serializeSelection,\n sliceToText,\n SOFER_MIME,\n type CommandContext,\n type ListKind,\n type MarkName,\n type SerializedBlock,\n} from \"@sofereditor/core\";\nimport { applyDomSelection, isTableRectSelection, readDomSelection, selectionsEqual } from \"./dom-bridge\";\nimport { planPaste } from \"./pastePlan\";\nimport { BehindImageSelectAffordance } from \"./BehindImageSelectAffordance\";\nimport { LinkHoverTooltip } from \"./LinkHoverTooltip\";\nimport { EditorProvider } from \"./EditorContext\";\nimport { ImageResizeOverlay } from \"./ImageResizeOverlay\";\nimport {\n RemoteCursorsOverlay,\n type AwarenessLike,\n} from \"./RemoteCursorsOverlay\";\nimport { NodeView, type NodeViewFragment } from \"./NodeView\";\nimport {\n A4_PAGE,\n defaultPageLayout,\n usePageLayout,\n type PageGeometry,\n type PageLayout,\n type PageSlot,\n} from \"./usePagination\";\nimport { useEditor, type UseEditorResult } from \"./useEditor\";\nimport { usePageSettings } from \"./usePageSettings\";\n\nexport interface PageRenderContext {\n pageNumber: number;\n pageCount: number;\n}\n\nexport type PageRenderProp = (ctx: PageRenderContext) => ReactNode;\n\nexport interface EditorProps {\n editor?: UseEditorResult;\n className?: string;\n /**\n * Page geometry override. When **omitted**, the editor reads page settings\n * from `editor.doc` (the `docSettings` Y.Map populated via `setPageSettings`\n * or `import-docx`). When **set**, this value wins for rendering — but is\n * NOT written back to the Y.Doc (view-only override; useful when the host\n * app must pin a size regardless of doc state, e.g. a prova generator).\n * Pass **null** to disable pagination entirely (flat flow).\n */\n pageGeometry?: PageGeometry | null;\n /**\n * Custom page header. Receives `{ pageNumber, pageCount }` and renders inside\n * the top margin of every page (above the content area). Pass `null` to omit.\n */\n renderPageHeader?: PageRenderProp | null;\n /**\n * Custom page footer. Receives `{ pageNumber, pageCount }`. Defaults to\n * `\"<n> / <total>\"` centered. Pass `null` to omit.\n */\n renderPageFooter?: PageRenderProp | null;\n /**\n * Awareness do Yjs (de `useCollab().binding.awareness`). Quando presente,\n * o editor publica a seleção local e desenha os cursores/seleções dos outros\n * usuários (presença colaborativa). Omitir = sem cursores remotos.\n */\n awareness?: AwarenessLike;\n}\n\nconst defaultFooter: PageRenderProp = ({ pageNumber, pageCount }) =>\n `${pageNumber} / ${pageCount}`;\n\nexport function Editor({\n editor: providedEditor,\n className,\n pageGeometry,\n renderPageHeader,\n renderPageFooter = defaultFooter,\n awareness,\n}: EditorProps): JSX.Element {\n const internal = useEditor();\n const editor = providedEditor ?? internal;\n const { doc, history, snapshot, getSelection, setSelection } = editor;\n\n const rootRef = useRef<HTMLDivElement>(null);\n const isComposingRef = useRef(false);\n // The `behind` image the pointer is currently hovering (by geometry), so we\n // can show a click affordance to select it through the text on top of it.\n const [hoveredBehind, setHoveredBehind] = useState<{\n blockIndex: number;\n offset: number;\n cellIndex?: number;\n } | null>(null);\n const hoveredBehindRef = useRef<typeof hoveredBehind>(null);\n // The link the pointer is hovering — drives the URL tooltip (rect in viewport\n // coords). Tracked by element identity to avoid re-render churn on every move.\n const [hoveredLink, setHoveredLink] = useState<{\n href: string;\n rect: { top: number; left: number; bottom: number; width: number };\n } | null>(null);\n const hoveredLinkElRef = useRef<HTMLAnchorElement | null>(null);\n const suppressSelectionSyncRef = useRef(false);\n\n // Presença colaborativa: publica a seleção local no awareness (throttle por\n // rAF). Outros editores desenham nosso caret via RemoteCursorsOverlay.\n useEffect(() => {\n if (!awareness) return;\n const root = rootRef.current;\n if (!root) return;\n let raf: number | null = null;\n const publish = () => {\n raf = null;\n const sel = readDomSelection(root);\n awareness.setLocalStateField(\n \"cursor\",\n sel ? encodeSelection(doc, sel) ?? null : null,\n );\n };\n const onSelChange = () => {\n const s = document.getSelection();\n if (!s || s.rangeCount === 0) return;\n // Só publica quando a seleção está dentro do nosso editor.\n if (s.anchorNode && !root.contains(s.anchorNode)) return;\n if (raf != null) return;\n raf = requestAnimationFrame(publish);\n };\n const onBlur = () => awareness.setLocalStateField(\"cursor\", null);\n document.addEventListener(\"selectionchange\", onSelChange);\n root.addEventListener(\"blur\", onBlur, true);\n return () => {\n document.removeEventListener(\"selectionchange\", onSelChange);\n root.removeEventListener(\"blur\", onBlur, true);\n if (raf != null) cancelAnimationFrame(raf);\n awareness.setLocalStateField(\"cursor\", null);\n };\n }, [awareness, doc]);\n\n const ctxRef = useRef<CommandContext>({ doc, getSelection, setSelection });\n ctxRef.current = { doc, getSelection, setSelection };\n const historyRef = useRef(history);\n historyRef.current = history;\n const editorRef = useRef(editor);\n editorRef.current = editor;\n\n // Run after every render — not just when selection or snapshot change — so\n // we re-apply the caret after pagination's two-phase render cycle (which\n // mutates `layout` state without touching `editor.selection` or `snapshot`,\n // and tears down/rebuilds the text nodes the prior DOM selection was attached\n // to). The early-return when DOM already matches the model keeps this cheap.\n useLayoutEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n if (isComposingRef.current) return;\n if (document.activeElement !== root) return;\n const current = readDomSelection(root);\n if (current && selectionsEqual(current, editor.selection)) return;\n if (isTableRectSelection(editor.selection)) {\n // Cross-cell (rectangular) table selection: the native DOM selection is\n // intentionally empty — TableView paints the highlight via CSS classes.\n // Keep it empty but do NOT arm the suppress guard. The guard exists to\n // ignore render-collapsed carets while TYPING; for a rect selection the\n // empty native selection is the steady state, so arming it would make the\n // selectionchange handler ignore a genuine click-away — the rect would\n // stick in the model and the next keystroke would overwrite the selected\n // cells instead of writing at the clicked caret.\n applyDomSelection(root, editor.selection);\n suppressSelectionSyncRef.current = false;\n return;\n }\n // DOM caret diverged from the model — typically a re-render replaced the\n // text node and collapsed the native caret to offset 0. Suppress the\n // selectionchange handler until the DOM settles back to the model; otherwise\n // a render-induced selectionchange writes the collapsed caret over a newer\n // keystroke's selection and the caret jumps backward when typing fast.\n // Cleared deterministically in the selectionchange handler once the DOM\n // settles to the live model — NOT on a timer, because timers race the event.\n suppressSelectionSyncRef.current = true;\n applyDomSelection(root, editor.selection);\n });\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const handler = () => {\n if (isComposingRef.current) return;\n if (document.activeElement !== root) {\n // Focus left the editor — nothing to capture here. Release any pending\n // suppression so a stuck flag can't swallow the next genuine change.\n suppressSelectionSyncRef.current = false;\n return;\n }\n const modelSel = readDomSelection(root);\n if (suppressSelectionSyncRef.current) {\n // Mid-reconciliation: a render moved the caret. Resume capturing user\n // selection only once the DOM caret has settled to match the LIVE model\n // (our applyDomSelection landed). Transient render-collapsed carets\n // (DOM != model) are ignored — those are the spurious events that used\n // to clobber the model selection and make the caret jump back.\n if (modelSel && selectionsEqual(modelSel, editorRef.current.getSelection())) {\n suppressSelectionSyncRef.current = false;\n }\n return;\n }\n if (modelSel) setSelection(modelSel);\n };\n document.addEventListener(\"selectionchange\", handler);\n return () => document.removeEventListener(\"selectionchange\", handler);\n }, [setSelection]);\n\n // ---------- Sub-phase 4.5: rectangular table-cell drag ----------\n //\n // mousedown captures the anchor cell. mousemove flips into \"rect mode\" the\n // moment the pointer enters a DIFFERENT cell of the same table, at which\n // point we suppress the native cross-cell selection and write a rectangular\n // selection to the model. The visual highlight is drawn by TableView via\n // CSS classes (see isTableRectSelection in dom-bridge).\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n interface DragState {\n blockIndex: number;\n anchorCellIndex: number;\n anchorTableEl: HTMLTableElement;\n rectActive: boolean;\n }\n let drag: DragState | null = null;\n\n function cellFromTarget(target: EventTarget | null): {\n blockIndex: number;\n cellIndex: number;\n tableEl: HTMLTableElement;\n } | null {\n if (!(target instanceof Node)) return null;\n let n: Node | null = target;\n let cellEl: HTMLElement | null = null;\n let tableEl: HTMLTableElement | null = null;\n while (n && n !== root) {\n if (n.nodeType === Node.ELEMENT_NODE) {\n const e = n as HTMLElement;\n if (!cellEl && e.dataset.cellIndex != null) cellEl = e;\n if (e.tagName === \"TABLE\" && e.dataset.blockIndex != null) {\n tableEl = e as HTMLTableElement;\n break;\n }\n }\n n = n.parentNode;\n }\n if (!cellEl || !tableEl) return null;\n const cellIndex = Number.parseInt(cellEl.dataset.cellIndex!, 10);\n const blockIndex = Number.parseInt(tableEl.dataset.blockIndex!, 10);\n return { blockIndex, cellIndex, tableEl };\n }\n\n const onPointerDown = (e: PointerEvent) => {\n if (e.button !== 0) return;\n const hit = cellFromTarget(e.target);\n if (!hit) {\n drag = null;\n return;\n }\n drag = {\n blockIndex: hit.blockIndex,\n anchorCellIndex: hit.cellIndex,\n anchorTableEl: hit.tableEl,\n rectActive: false,\n };\n };\n\n const onPointerMove = (e: PointerEvent) => {\n if (!drag) return;\n // Only treat as drag when the primary button is still pressed.\n if ((e.buttons & 1) === 0) {\n drag = null;\n return;\n }\n const hit = cellFromTarget(e.target);\n if (!hit) return;\n if (hit.blockIndex !== drag.blockIndex) return; // never cross tables\n if (hit.cellIndex === drag.anchorCellIndex && !drag.rectActive) return;\n\n if (!drag.rectActive) {\n drag.rectActive = true;\n // Kill any in-progress native cross-cell selection.\n window.getSelection()?.removeAllRanges();\n }\n e.preventDefault();\n ctxRef.current.setSelection({\n anchor: { blockIndex: drag.blockIndex, cellIndex: drag.anchorCellIndex, offset: 0 },\n focus: { blockIndex: drag.blockIndex, cellIndex: hit.cellIndex, offset: 0 },\n });\n };\n\n const onPointerUp = () => {\n drag = null;\n };\n\n root.addEventListener(\"pointerdown\", onPointerDown);\n document.addEventListener(\"pointermove\", onPointerMove);\n document.addEventListener(\"pointerup\", onPointerUp);\n return () => {\n root.removeEventListener(\"pointerdown\", onPointerDown);\n document.removeEventListener(\"pointermove\", onPointerMove);\n document.removeEventListener(\"pointerup\", onPointerUp);\n };\n }, []);\n\n // ---------- Fase 5: drag-drop de imagens ----------\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const onDragOver = (e: DragEvent) => {\n if (!e.dataTransfer) return;\n const hasFiles = Array.from(e.dataTransfer.items ?? []).some(\n (i) => i.kind === \"file\",\n );\n if (!hasFiles) return;\n e.preventDefault();\n e.dataTransfer.dropEffect = \"copy\";\n };\n const onDrop = (e: DragEvent) => {\n if (!e.dataTransfer) return;\n const images = Array.from(e.dataTransfer.files).filter((f) =>\n f.type.startsWith(\"image/\"),\n );\n if (images.length === 0) return;\n e.preventDefault();\n // Position the caret at the drop point so the insertion lands there.\n const range = caretRangeFromPoint(e.clientX, e.clientY);\n if (range) {\n const dom = window.getSelection();\n dom?.removeAllRanges();\n dom?.addRange(range);\n const sel = readDomSelection(root);\n if (sel) ctxRef.current.setSelection(sel);\n }\n void (async () => {\n for (const f of images) await editorRef.current.insertImageFromFile(f);\n })();\n };\n root.addEventListener(\"dragover\", onDragOver);\n root.addEventListener(\"drop\", onDrop);\n return () => {\n root.removeEventListener(\"dragover\", onDragOver);\n root.removeEventListener(\"drop\", onDrop);\n };\n }, []);\n\n // ---------- Fase 5: clique numa imagem seleciona o embed ----------\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const onPointerDown = (e: PointerEvent) => {\n if (e.button !== 0) return;\n const target = e.target;\n if (!(target instanceof Element)) return;\n const img = target.closest('img[data-embed=\"image\"]') as HTMLElement | null;\n if (!img) return;\n const blockEl = img.closest(\"[data-block-index]\") as HTMLElement | null;\n if (!blockEl) return;\n const blockIndex = Number.parseInt(blockEl.dataset.blockIndex!, 10);\n const offsetAttr = img.dataset.embedOffset;\n if (offsetAttr == null) return;\n const localOffset = Number.parseInt(offsetAttr, 10);\n const fragmentStart = Number.parseInt(blockEl.dataset.fragmentStart ?? \"0\", 10) || 0;\n const cellEl = img.closest(\"[data-cell-index]\") as HTMLElement | null;\n const cellIndex = cellEl\n ? Number.parseInt(cellEl.dataset.cellIndex!, 10)\n : undefined;\n const offset = fragmentStart + localOffset;\n e.preventDefault();\n ctxRef.current.setSelection({\n anchor: { blockIndex, cellIndex, offset },\n focus: { blockIndex, cellIndex, offset: offset + 1 },\n });\n };\n root.addEventListener(\"pointerdown\", onPointerDown);\n return () => root.removeEventListener(\"pointerdown\", onPointerDown);\n }, []);\n\n // Hover detection for `behind` images: they sit at z-index:-1, so the text on\n // top intercepts clicks and the image can't be selected by clicking there. On\n // pointer move we find — BY GEOMETRY — the behind image under the pointer and\n // expose a select affordance (rendered below). Throttled to one check/frame.\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const same = (\n a: typeof hoveredBehind,\n b: typeof hoveredBehind,\n ): boolean =>\n a === b ||\n (!!a &&\n !!b &&\n a.blockIndex === b.blockIndex &&\n a.offset === b.offset &&\n (a.cellIndex ?? -1) === (b.cellIndex ?? -1));\n const set = (next: typeof hoveredBehind) => {\n if (same(next, hoveredBehindRef.current)) return;\n hoveredBehindRef.current = next;\n setHoveredBehind(next);\n };\n let raf = 0;\n const onMove = (e: PointerEvent) => {\n if (raf) return;\n const x = e.clientX;\n const y = e.clientY;\n raf = requestAnimationFrame(() => {\n raf = 0;\n const imgs = root.querySelectorAll<HTMLImageElement>(\n 'img[data-embed=\"image\"][data-embed-layout=\"behind\"]',\n );\n let hit: HTMLImageElement | null = null;\n for (const img of imgs) {\n const r = img.getBoundingClientRect();\n if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) {\n hit = img;\n break;\n }\n }\n if (!hit) {\n set(null);\n return;\n }\n const blockEl = hit.closest<HTMLElement>(\"[data-block-index]\");\n const offsetAttr = hit.dataset.embedOffset;\n if (!blockEl || offsetAttr == null) {\n set(null);\n return;\n }\n const blockIndex = Number.parseInt(blockEl.dataset.blockIndex!, 10);\n const fragmentStart = Number.parseInt(blockEl.dataset.fragmentStart ?? \"0\", 10) || 0;\n const cellEl = hit.closest<HTMLElement>(\"[data-cell-index]\");\n const cellIndex = cellEl\n ? Number.parseInt(cellEl.dataset.cellIndex!, 10)\n : undefined;\n set({ blockIndex, offset: fragmentStart + Number.parseInt(offsetAttr, 10), cellIndex });\n });\n };\n const onLeave = () => set(null);\n root.addEventListener(\"pointermove\", onMove);\n root.addEventListener(\"pointerleave\", onLeave);\n return () => {\n root.removeEventListener(\"pointermove\", onMove);\n root.removeEventListener(\"pointerleave\", onLeave);\n if (raf) cancelAnimationFrame(raf);\n };\n }, []);\n\n // Link hover tooltip: show the URL while the pointer is over a link. Uses\n // `mouseover` delegation (fires on element enter, far cheaper than mousemove)\n // and tracks the hovered <a> by identity to avoid re-render churn. Cleared on\n // leave/scroll (the cached viewport rect would otherwise go stale).\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const clear = () => {\n if (hoveredLinkElRef.current) {\n hoveredLinkElRef.current = null;\n setHoveredLink(null);\n }\n };\n const onOver = (e: MouseEvent) => {\n const target = e.target as Element | null;\n const a = target?.closest?.(\"a[href]\") as HTMLAnchorElement | null;\n if (a && root.contains(a)) {\n if (hoveredLinkElRef.current === a) return;\n hoveredLinkElRef.current = a;\n const r = a.getBoundingClientRect();\n setHoveredLink({\n href: a.getAttribute(\"href\") ?? \"\",\n rect: { top: r.top, left: r.left, bottom: r.bottom, width: r.width },\n });\n } else {\n clear();\n }\n };\n root.addEventListener(\"mouseover\", onOver);\n root.addEventListener(\"mouseleave\", clear);\n root.addEventListener(\"scroll\", clear, true);\n window.addEventListener(\"scroll\", clear, true);\n return () => {\n root.removeEventListener(\"mouseover\", onOver);\n root.removeEventListener(\"mouseleave\", clear);\n root.removeEventListener(\"scroll\", clear, true);\n window.removeEventListener(\"scroll\", clear, true);\n };\n }, []);\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n const handler = (e: InputEvent) => {\n const ctx = ctxRef.current;\n const hist = historyRef.current;\n const ed = editorRef.current;\n const type = e.inputType;\n\n if (isComposingRef.current && type === \"insertCompositionText\") return;\n\n switch (type) {\n case \"insertText\": {\n const data = e.data ?? \"\";\n if (data.length > 0) {\n e.preventDefault();\n insertText(ctx, data, ed.consumePendingMarks());\n }\n return;\n }\n case \"insertLineBreak\": {\n // Shift+Enter inside a listItem inserts a soft line break (`\\n`)\n // INSIDE the item instead of splitting it into a new numbered entry\n // — useful for spacing between question lines without bumping the\n // numbering. Other blocks fall through to the regular paragraph\n // split (= same as Enter), because TipTap-style \"soft break\" inside\n // a paragraph isn't part of this model.\n e.preventDefault();\n if (ed.getBlockType() === \"listItem\") {\n insertText(ctx, \"\\n\", ed.consumePendingMarks());\n return;\n }\n // Fall through to the same path as insertParagraph.\n const selEmbed = ed.getSelectedEmbed();\n if (selEmbed) {\n const off = selEmbed.offset + 1;\n ctx.setSelection({\n anchor: {\n blockIndex: selEmbed.blockIndex,\n cellIndex: selEmbed.cellIndex,\n offset: off,\n },\n focus: {\n blockIndex: selEmbed.blockIndex,\n cellIndex: selEmbed.cellIndex,\n offset: off,\n },\n });\n }\n if (ed.splitListItem()) return;\n insertParagraph(ctx);\n return;\n }\n case \"insertParagraph\": {\n e.preventDefault();\n // If an embed is the entire selection, drop the caret RIGHT AFTER it\n // before splitting — otherwise the default \"delete range then insert\n // paragraph\" path would remove the image.\n const selectedEmbed = ed.getSelectedEmbed();\n if (selectedEmbed) {\n const off = selectedEmbed.offset + 1;\n ctx.setSelection({\n anchor: {\n blockIndex: selectedEmbed.blockIndex,\n cellIndex: selectedEmbed.cellIndex,\n offset: off,\n },\n focus: {\n blockIndex: selectedEmbed.blockIndex,\n cellIndex: selectedEmbed.cellIndex,\n offset: off,\n },\n });\n }\n if (ed.splitListItem()) return;\n insertParagraph(ctx);\n return;\n }\n case \"insertReplacementText\": {\n const text = e.data ?? e.dataTransfer?.getData(\"text/plain\") ?? \"\";\n if (text.length > 0) {\n e.preventDefault();\n insertText(ctx, text, ed.consumePendingMarks());\n }\n return;\n }\n case \"insertFromPaste\": {\n // Paste é tratado pelo handler `paste` (useEffect de clipboard). Quando\n // ele NÃO faz preventDefault (ex.: clipboard só com text/html, ou sem\n // clipboardData), o browser cai aqui — este no-op bloqueia a inserção\n // crua no DOM em vez de corromper o documento virtual.\n e.preventDefault();\n return;\n }\n case \"deleteContentBackward\":\n case \"deleteWordBackward\":\n case \"deleteSoftLineBackward\":\n case \"deleteHardLineBackward\": {\n e.preventDefault();\n deleteBackward(ctx);\n return;\n }\n case \"deleteContentForward\":\n case \"deleteWordForward\":\n case \"deleteSoftLineForward\":\n case \"deleteHardLineForward\": {\n e.preventDefault();\n deleteForward(ctx);\n return;\n }\n case \"historyUndo\": {\n e.preventDefault();\n hist.undo();\n return;\n }\n case \"historyRedo\": {\n e.preventDefault();\n hist.redo();\n return;\n }\n default: {\n e.preventDefault();\n return;\n }\n }\n };\n\n root.addEventListener(\"beforeinput\", handler);\n return () => root.removeEventListener(\"beforeinput\", handler);\n }, []);\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n const writeSlice = (e: ClipboardEvent): boolean => {\n const ctx = ctxRef.current;\n const slice = serializeSelection(ctx.doc, ctx.getSelection());\n if (!slice || !e.clipboardData) return false;\n e.clipboardData.setData(SOFER_MIME, JSON.stringify(slice));\n e.clipboardData.setData(\"text/plain\", sliceToText(slice));\n return true;\n };\n\n const onCopy = (e: ClipboardEvent) => {\n if (writeSlice(e)) e.preventDefault();\n };\n\n const onCut = (e: ClipboardEvent) => {\n // Always block the native cut: it mutates the contenteditable DOM directly\n // and would write its own clipboard serialization. When we have a slice we\n // delete via the model; an unsupported selection (writeSlice false) becomes\n // a clean no-op instead of a \"cut that doesn't delete\".\n e.preventDefault();\n if (writeSlice(e)) deleteSelection(ctxRef.current);\n };\n\n const onPaste = (e: ClipboardEvent) => {\n const ctx = ctxRef.current;\n const cd = e.clipboardData;\n if (!cd) return;\n // A escolha do ramo (e sobretudo a ORDEM deles) vive em `planPaste`, para\n // ser testável sem montar o editor. Ver o comentário lá sobre por que o\n // HTML precisa vir antes dos arquivos de imagem.\n const plan = planPaste(cd);\n if (plan.kind === \"none\") return;\n e.preventDefault();\n switch (plan.kind) {\n case \"sofer\":\n case \"html\":\n insertSlice(ctx, plan.slice);\n return;\n case \"images\":\n void (async () => {\n for (const f of plan.files) await editorRef.current.insertImageFromFile(f);\n })();\n return;\n case \"text\": {\n const lines = plan.text.split(/\\r\\n|\\r|\\n/);\n lines.forEach((line, i) => {\n if (i > 0) insertParagraph(ctx);\n if (line.length > 0) insertText(ctx, line);\n });\n return;\n }\n }\n };\n\n root.addEventListener(\"copy\", onCopy);\n root.addEventListener(\"cut\", onCut);\n root.addEventListener(\"paste\", onPaste);\n return () => {\n root.removeEventListener(\"copy\", onCopy);\n root.removeEventListener(\"cut\", onCut);\n root.removeEventListener(\"paste\", onPaste);\n };\n }, []);\n\n const onKeyDown = useCallback((e: KeyboardEvent<HTMLDivElement>) => {\n const ed = editorRef.current;\n const mod = e.metaKey || e.ctrlKey;\n\n if (e.key === \"Tab\") {\n e.preventDefault();\n // Inside a table, Tab/Shift+Tab navigates between cells; at the last\n // cell Tab appends a new row.\n if (ed.isInTable()) {\n if (e.shiftKey) ed.moveToPrevCell();\n else ed.moveToNextCell();\n return;\n }\n if (e.shiftKey) ed.dedentList();\n else ed.indentList();\n return;\n }\n\n // Home/End: move the caret to the visual start/end of the current line.\n // The default contenteditable behavior is inconsistent with paginated\n // fragments — Chrome occasionally jumps to the start/end of the block\n // element instead of the visual line. We explicitly use the native\n // `Selection.modify(\"lineboundary\")` API (Chrome/Edge/Safari) which\n // respects visual line wrapping inside any contenteditable.\n //\n // `Cmd/Ctrl+Home/End` keep the default browser behavior (document scroll).\n if (!mod && (e.key === \"Home\" || e.key === \"End\")) {\n const root = rootRef.current;\n const sel = window.getSelection();\n const sm = (sel as unknown as { modify?: (alter: string, direction: string, granularity: string) => void })?.modify;\n if (root && sel && sel.rangeCount > 0 && typeof sm === \"function\") {\n e.preventDefault();\n const alter = e.shiftKey ? \"extend\" : \"move\";\n const direction = e.key === \"Home\" ? \"left\" : \"right\";\n sm.call(sel, alter, direction, \"lineboundary\");\n const modelSel = readDomSelection(root);\n if (modelSel) ctxRef.current.setSelection(modelSel);\n }\n return;\n }\n\n if (!mod) return;\n const key = e.key.toLowerCase();\n\n if (!e.shiftKey && !e.altKey && key === \"z\") {\n e.preventDefault();\n historyRef.current.undo();\n return;\n }\n if (!e.altKey && (key === \"y\" || (e.shiftKey && key === \"z\"))) {\n e.preventDefault();\n historyRef.current.redo();\n return;\n }\n\n if (e.altKey && !e.shiftKey && /^[0-6]$/.test(key)) {\n e.preventDefault();\n const n = Number(key);\n if (n === 0) ed.setBlockType(\"paragraph\");\n else ed.setBlockType(\"heading\", { level: n as 1 | 2 | 3 | 4 | 5 | 6 });\n return;\n }\n\n if (e.shiftKey && !e.altKey && (key === \"7\" || key === \"8\")) {\n e.preventDefault();\n ed.toggleList(key === \"7\" ? \"ordered\" : \"bullet\");\n return;\n }\n\n const markToggle = !e.shiftKey && !e.altKey\n ? (BOOLEAN_SHORTCUTS[key] as MarkName | undefined)\n : undefined;\n if (markToggle) {\n e.preventDefault();\n ed.toggleMark(markToggle);\n return;\n }\n if (e.shiftKey && !e.altKey && key === \"x\") {\n e.preventDefault();\n ed.toggleMark(\"strike\");\n return;\n }\n\n if (!e.altKey && !e.shiftKey && key === \"k\") {\n e.preventDefault();\n const active = ed.getActiveMarks();\n const currentHref =\n active.link && typeof active.link === \"object\" && \"href\" in active.link\n ? (active.link.href as string)\n : \"\";\n void ed.requestLink(currentHref).then((href) => {\n if (href === null) return;\n if (href === \"\") ed.removeMark(\"link\");\n else ed.setMark(\"link\", { href });\n });\n }\n }, []);\n\n const onCompositionStart = useCallback(() => {\n isComposingRef.current = true;\n }, []);\n\n const onCompositionEnd = useCallback((e: React.CompositionEvent<HTMLDivElement>) => {\n isComposingRef.current = false;\n if (e.data && e.data.length > 0) {\n insertText(ctxRef.current, e.data);\n }\n }, []);\n\n const topLevels = useMemo(() => groupTopLevels(snapshot.blocks), [snapshot]);\n // Chave estrutural dos topLevels: muda só quando a SHAPE muda (tipos,\n // contagem de itens em lists, list kind/style/start), não quando o texto\n // dentro de um block é editado. Usada como dep do `usePageLayout` em\n // lugar do array `topLevels` (cuja referência muda a cada keystroke), o\n // que cortava repaginações desnecessárias — antes 1.3M DOM mutations\n // por ~10 teclas viraram zero. O array `topLevels` em si continua fresh\n // pra `renderSlot` ler o texto atualizado de cada block.\n const topLevelsStructuralKey = useMemo(\n () =>\n topLevels\n .map((t) =>\n t.kind === \"list\"\n ? `L:${t.listKind}:${t.items.length}:${t.ordinalStart}`\n : `B:${t.block.type}:${t.block.attrs.level ?? \"\"}`,\n )\n .join(\"|\"),\n [topLevels],\n );\n // Page geometry sources, in precedence order:\n // 1. `pageGeometry` prop when explicitly set (view-only override — does NOT\n // write back to the Y.Doc; useful for apps that force a fixed size, e.g.\n // prova generator pinned to A4).\n // 2. `editor.doc` page settings (Y.Doc-backed, sync-aware).\n // 3. `A4_PAGE` fallback when both unavailable.\n // `pageGeometry={null}` continues to disable pagination entirely.\n const docSettings = usePageSettings(editor.doc);\n const propIsSet = pageGeometry !== undefined;\n const geom: PageGeometry = propIsSet ? (pageGeometry ?? A4_PAGE) : docSettings;\n const paginated = pageGeometry !== null;\n // Reads from snapshot + selection; recomputed on every render.\n const selectedEmbed = editor.getSelectedEmbed();\n\n const { layout, phase: paginationPhase } = usePageLayout(\n rootRef as RefObject<HTMLElement>,\n geom,\n topLevels.length,\n // Usar a chave estrutural (string) em vez do array `topLevels` direto:\n // o array reference muda a cada keystroke, mas a chave só muda quando\n // a SHAPE dos top-levels muda. `usePageLayout` compara deps via\n // `shallowArrayEqual` — string equality cobre isso.\n [topLevelsStructuralKey, pageGeometry],\n );\n\n const effectiveLayout: PageLayout = paginated ? layout : defaultPageLayout(topLevels.length);\n\n // pageStyle memoizado: CSS custom properties são HERDADAS, então qualquer\n // toggle de `style` no `.ed-root` invalidava estilos em todos os\n // descendentes (~165k elementos no caso do bug histórico) e alimentava\n // style recalc pesado a cada keystroke. Memo aqui mantém a mesma\n // referência enquanto width/height/margens não mudam.\n const pageStyle = useMemo(\n () =>\n paginated\n ? ({\n \"--ed-page-width\": `${geom.width}px`,\n \"--ed-page-height\": `${geom.height}px`,\n \"--ed-page-margin-top\": `${geom.marginTop}px`,\n \"--ed-page-margin-bottom\": `${geom.marginBottom}px`,\n \"--ed-page-margin-left\": `${geom.marginLeft}px`,\n \"--ed-page-margin-right\": `${geom.marginRight}px`,\n } as React.CSSProperties)\n : undefined,\n [\n paginated,\n geom.width,\n geom.height,\n geom.marginTop,\n geom.marginBottom,\n geom.marginLeft,\n geom.marginRight,\n ],\n );\n\n const body = (\n <div\n ref={rootRef}\n contentEditable\n suppressContentEditableWarning\n spellCheck\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n role=\"textbox\"\n aria-multiline=\"true\"\n className={\n (className ?? \"ed-root\") + (paginated ? \" ed-root--paged\" : \" ed-root--flat\")\n }\n data-pagination-phase={paginated ? paginationPhase : undefined}\n style={pageStyle}\n onKeyDown={onKeyDown}\n onCompositionStart={onCompositionStart}\n onCompositionEnd={onCompositionEnd}\n >\n {paginated\n ? effectiveLayout.pages.map((page, pi) => {\n const ctx: PageRenderContext = {\n pageNumber: pi + 1,\n pageCount: effectiveLayout.pages.length,\n };\n // Apenas a pág 1 recebe o `firstPageExtraTop` adicional. Inline\n // style sobrescreve a CSS var herdada do `.ed-root` (que vale para\n // as páginas seguintes).\n const pageInlineStyle =\n pi === 0 && geom.firstPageExtraTop\n ? ({\n \"--ed-page-margin-top\": `${geom.marginTop + geom.firstPageExtraTop}px`,\n } as React.CSSProperties)\n : undefined;\n return (\n <div\n key={`page-${pi}`}\n className=\"ed-page\"\n data-page-number={ctx.pageNumber}\n data-page-total={ctx.pageCount}\n style={pageInlineStyle}\n >\n {renderPageHeader && (\n <div className=\"ed-page-header\" contentEditable={false}>\n {renderPageHeader(ctx)}\n </div>\n )}\n <div className=\"ed-page-content\">\n {page.slots.map((slot) => renderSlot(slot, topLevels))}\n </div>\n {renderPageFooter && (\n <div className=\"ed-page-footer\" contentEditable={false}>\n {renderPageFooter(ctx)}\n </div>\n )}\n </div>\n );\n })\n : topLevels.map((t) => renderTopLevel(t))}\n {selectedEmbed && (\n <ImageResizeOverlay\n rootRef={rootRef}\n blockIndex={selectedEmbed.blockIndex}\n offset={selectedEmbed.offset}\n cellIndex={selectedEmbed.cellIndex}\n embed={selectedEmbed.embed}\n onCommit={(w, h) =>\n editor.setImageAttrs(\n selectedEmbed.blockIndex,\n selectedEmbed.offset,\n { width: w, height: h },\n selectedEmbed.cellIndex,\n )\n }\n onCommitMove={(ox, oy) =>\n editor.setImageAttrs(\n selectedEmbed.blockIndex,\n selectedEmbed.offset,\n { offsetX: ox, offsetY: oy },\n selectedEmbed.cellIndex,\n )\n }\n onReanchor={(to, ox, oy) =>\n editor.moveEmbedAnchor(\n {\n blockIndex: selectedEmbed.blockIndex,\n offset: selectedEmbed.offset,\n cellIndex: selectedEmbed.cellIndex,\n },\n to,\n ox,\n oy,\n )\n }\n />\n )}\n {hoveredBehind &&\n !(\n selectedEmbed &&\n selectedEmbed.blockIndex === hoveredBehind.blockIndex &&\n selectedEmbed.offset === hoveredBehind.offset &&\n (selectedEmbed.cellIndex ?? -1) === (hoveredBehind.cellIndex ?? -1)\n ) && (\n <BehindImageSelectAffordance\n rootRef={rootRef}\n blockIndex={hoveredBehind.blockIndex}\n offset={hoveredBehind.offset}\n cellIndex={hoveredBehind.cellIndex}\n onSelect={() =>\n setSelection({\n anchor: {\n blockIndex: hoveredBehind.blockIndex,\n cellIndex: hoveredBehind.cellIndex,\n offset: hoveredBehind.offset,\n },\n focus: {\n blockIndex: hoveredBehind.blockIndex,\n cellIndex: hoveredBehind.cellIndex,\n offset: hoveredBehind.offset + 1,\n },\n })\n }\n />\n )}\n {hoveredLink && hoveredLink.href && (\n <LinkHoverTooltip href={hoveredLink.href} rect={hoveredLink.rect} />\n )}\n {awareness && (\n <RemoteCursorsOverlay\n rootRef={rootRef}\n doc={doc}\n awareness={awareness}\n revision={snapshot}\n />\n )}\n </div>\n );\n\n return <EditorProvider editor={editor}>{body}</EditorProvider>;\n}\n\n// ---------- Top-level grouping (data, not JSX) ----------\n\ninterface ListEntry {\n block: SerializedBlock;\n index: number;\n}\n\ntype TopLevel =\n | { kind: \"block\"; block: SerializedBlock; blockIndex: number; key: number }\n | {\n kind: \"list\";\n items: ListEntry[];\n listKind: ListKind;\n /**\n * Number to seed the `<ol>` `start` attribute. Pulled from the first\n * item's `listStart` attr, defaulting to 1. Only meaningful for\n * `listKind === \"ordered\"`.\n */\n ordinalStart: number;\n /**\n * Optional CSS `list-style-type` override for this group. Pulled from\n * the first item's `listStyle` attr. Undefined means \"use the cascade\n * cycle from sofer-editor.css\".\n */\n listStyle?: string;\n key: number;\n };\n\nexport function groupTopLevels(snapshot: SerializedBlock[]): TopLevel[] {\n const out: TopLevel[] = [];\n let i = 0;\n while (i < snapshot.length) {\n const block = snapshot[i];\n if (block.type === \"listItem\") {\n const groupStart = i;\n const items: ListEntry[] = [];\n const kind: ListKind = block.attrs.listKind === \"ordered\" ? \"ordered\" : \"bullet\";\n const leaderLevel = clampListLevel(block.attrs.listLevel);\n const groupStyle = block.attrs.listStyle as string | undefined;\n // A `listStart` on the FIRST item of the group seeds the `<ol start>`.\n // A `listStart` or `listStyle` on a LATER item breaks the group at that\n // item — its first item becomes the seed of the next group.\n while (i < snapshot.length) {\n const b = snapshot[i];\n if (b.type !== \"listItem\") break;\n // A type change breaks the group whenever the item sits AT OR ABOVE\n // the group leader's level — that's a genuine sibling list of a\n // different type (or a return to a shallower level, which\n // `buildListTree`'s stack treats as a new root, same as the leader).\n // Only a type change STRICTLY DEEPER than the leader stays in the\n // group: that's a sublist (e.g. a bullet sub-list under a numbered\n // item pasted from Word), and `buildListTree` nests it under its\n // parent instead of making it a root.\n const bLevel = clampListLevel(b.attrs.listLevel);\n if (bLevel <= leaderLevel && (b.attrs.listKind ?? \"bullet\") !== kind) {\n break;\n }\n if (i > groupStart) {\n // Continuation: break the group ONLY when this item EXPLICITLY\n // declares a renumbering. An undefined `listStart` / `listStyle`\n // means \"inherit from the current group leader\" — that's the\n // common case (user only tags the first item of the new sequence).\n if (typeof b.attrs.listStart === \"number\") break;\n const itemStyle = b.attrs.listStyle as string | undefined;\n if (itemStyle !== undefined && itemStyle !== groupStyle) break;\n }\n items.push({ block: b, index: i });\n i++;\n }\n const firstAttrs = items[0].block.attrs;\n const ordinalStart =\n typeof firstAttrs.listStart === \"number\" && firstAttrs.listStart > 0\n ? firstAttrs.listStart\n : 1;\n out.push({\n kind: \"list\",\n items,\n listKind: kind,\n ordinalStart,\n listStyle: groupStyle,\n key: groupStart,\n });\n continue;\n }\n out.push({ kind: \"block\", block, blockIndex: i, key: i });\n i++;\n }\n return out;\n}\n\nfunction renderSlot(slot: PageSlot, topLevels: TopLevel[]): JSX.Element | null {\n const top = topLevels[slot.topLevelIndex];\n if (!top) return null;\n if (slot.fragment && top.kind === \"block\") {\n const f: NodeViewFragment = {\n index: slot.fragment.index,\n start: slot.fragment.start,\n end: slot.fragment.end,\n };\n return (\n <NodeView\n key={`${top.key}-f${f.index}`}\n block={top.block}\n index={top.blockIndex}\n fragment={f}\n />\n );\n }\n if (slot.tableFragment && top.kind === \"block\" && top.block.type === \"table\") {\n return (\n <NodeView\n key={`${top.key}-tf${slot.tableFragment.index}`}\n block={top.block}\n index={top.blockIndex}\n tableFragment={slot.tableFragment}\n />\n );\n }\n if (slot.listFragment && top.kind === \"list\") {\n return renderListFragment(top, slot.listFragment);\n }\n return renderTopLevel(top);\n}\n\nexport function renderTopLevel(top: TopLevel): JSX.Element {\n if (top.kind === \"list\") {\n const tree = buildListTree(top.items);\n return renderListTree(tree, top, top.ordinalStart, `list-${top.key}`);\n }\n return <NodeView key={top.key} block={top.block} index={top.blockIndex} />;\n}\n\n/**\n * Render a sub-range of a list group's top-level items, as produced by\n * `placeFragmentedList`. The continuation `<ol>` carries an adjusted `start`\n * so numbering remains contiguous across the page break.\n */\nexport function renderListFragment(top: TopLevel & { kind: \"list\" }, frag: { index: number; itemStart: number; itemEnd: number }): JSX.Element {\n const ranges = topLevelItemRanges(top.items);\n const startRange = ranges[frag.itemStart];\n const endRange = ranges[frag.itemEnd - 1];\n if (!startRange || !endRange) return renderTopLevel(top);\n const sliced = top.items.slice(startRange[0], endRange[1]);\n // Continuation start = group's seed + count of top-level items already on prior pages.\n const ordinalStart = top.ordinalStart + frag.itemStart;\n const key = `list-${top.key}-f${frag.index}`;\n const slicedTop: TopLevel & { kind: \"list\" } = { ...top, items: sliced };\n const tree = buildListTree(sliced);\n return renderListTree(tree, slicedTop, ordinalStart, key);\n}\n\n/**\n * Index ranges within a flat `ListEntry[]` corresponding to each top-level\n * (level-0) item plus its nested descendants. Used by `renderListFragment` to\n * slice the flat list on a top-level boundary that matches what the paginator\n * measured against direct `<li>` children.\n */\nexport function topLevelItemRanges(items: ListEntry[]): Array<[number, number]> {\n const out: Array<[number, number]> = [];\n let currentStart = -1;\n items.forEach((it, idx) => {\n const level = clampListLevel(it.block.attrs.listLevel);\n if (level === 0) {\n if (currentStart >= 0) out.push([currentStart, idx]);\n currentStart = idx;\n }\n });\n if (currentStart >= 0) out.push([currentStart, items.length]);\n return out;\n}\n\ninterface ListNode {\n entry: ListEntry;\n children: ListNode[];\n}\n\nfunction buildListTree(items: ListEntry[]): ListNode[] {\n const roots: ListNode[] = [];\n const stack: { children: ListNode[]; level: number }[] = [{ children: roots, level: -1 }];\n for (const it of items) {\n const level = clampListLevel(it.block.attrs.listLevel);\n while (stack.length > 1 && stack[stack.length - 1].level >= level) stack.pop();\n const node: ListNode = { entry: it, children: [] };\n stack[stack.length - 1].children.push(node);\n stack.push({ children: node.children, level });\n }\n return roots;\n}\n\nfunction renderListTree(\n tree: ListNode[],\n top: TopLevel & { kind: \"list\" },\n start: number,\n key: string,\n): JSX.Element {\n const className = `ed-list ed-list-${top.listKind}`;\n const style: React.CSSProperties | undefined = top.listStyle\n ? { listStyleType: top.listStyle }\n : undefined;\n const items = tree.map((node) => (\n <NodeView key={node.entry.index} block={node.entry.block} index={node.entry.index}>\n {node.children.length > 0\n ? renderNestedListTree(node.children, `nested-${node.entry.index}`)\n : null}\n </NodeView>\n ));\n if (top.listKind === \"ordered\") {\n return (\n <ol\n key={key}\n className={className}\n data-list-kind=\"ordered\"\n start={start > 1 ? start : undefined}\n style={style}\n >\n {items}\n </ol>\n );\n }\n return (\n <ul key={key} className={className} data-list-kind=\"bullet\" style={style}>\n {items}\n </ul>\n );\n}\n\n/**\n * Nested sub-lists never carry an explicit `start`/`listStyle` from a parent\n * item: the cascade in `sofer-editor.css` handles the per-level style cycle\n * (decimal → lower-alpha → lower-roman). Only the TOP-level `<ol>` for a\n * group needs an explicit `start`/`listStyleType`.\n *\n * The sublist's own `listKind` comes from ITS first item, never from the\n * parent/ancestor group. A numbered item pasted from Word can have a bullet\n * sub-list underneath (or vice-versa) — `groupTopLevels` now keeps those\n * together in one group since the type change happens below the group's\n * level-0 leader, so this function must not impose the ancestor's kind on\n * every descendant level.\n */\nfunction renderNestedListTree(tree: ListNode[], key: string): JSX.Element {\n const kind: ListKind = tree[0]?.entry.block.attrs.listKind === \"ordered\" ? \"ordered\" : \"bullet\";\n const Tag = kind === \"ordered\" ? \"ol\" : \"ul\";\n return (\n <Tag key={key} className={`ed-list ed-list-${kind}`} data-list-kind={kind}>\n {tree.map((node) => (\n <NodeView key={node.entry.index} block={node.entry.block} index={node.entry.index}>\n {node.children.length > 0\n ? renderNestedListTree(node.children, `nested-${node.entry.index}`)\n : null}\n </NodeView>\n ))}\n </Tag>\n );\n}\n\nfunction clampListLevel(l: unknown): number {\n if (typeof l !== \"number\" || !Number.isFinite(l)) return 0;\n return Math.max(0, Math.min(5, Math.trunc(l)));\n}\n\nconst BOOLEAN_SHORTCUTS: Record<string, MarkName> = {\n b: \"bold\",\n i: \"italic\",\n u: \"underline\",\n};\n\ninterface CaretRangeFromPoint {\n caretRangeFromPoint(x: number, y: number): Range | null;\n}\ninterface CaretPositionFromPoint {\n caretPositionFromPoint(\n x: number,\n y: number,\n ): { offsetNode: Node; offset: number } | null;\n}\n\nfunction caretRangeFromPoint(x: number, y: number): Range | null {\n const doc = document as unknown as Partial<CaretRangeFromPoint & CaretPositionFromPoint>;\n if (typeof doc.caretRangeFromPoint === \"function\") {\n return doc.caretRangeFromPoint(x, y);\n }\n if (typeof doc.caretPositionFromPoint === \"function\") {\n const pos = doc.caretPositionFromPoint(x, y);\n if (!pos) return null;\n const range = document.createRange();\n range.setStart(pos.offsetNode, pos.offset);\n range.collapse(true);\n return range;\n }\n return null;\n}\n","import type { Position, Selection } from \"@sofereditor/core\";\n\n/**\n * Mapping between the model and the contenteditable DOM.\n *\n * Each block is rendered as one or more elements carrying `data-block-index`.\n * Unfragmented blocks have a single such element. A paragraph fragmented across\n * pages (Sub-phase 3.2) has multiple elements with the same `data-block-index`,\n * each carrying `data-fragment-start` / `data-fragment-end` indicating the\n * character offsets within the block's text that the element covers.\n *\n * Table blocks (Sub-phase 4.1) render the `<table>` itself with `data-block-index`.\n * Each `<td>` cell carries `data-cell-index` (flat row-major). Model positions\n * inside a table always include `cellIndex`; their `offset` is local to that\n * cell's text.\n */\n\n/** Walks up from `node` to the first ancestor that carries `data-block-index`. */\nfunction findContainingBlockElement(node: Node, root: HTMLElement): HTMLElement | null {\n let cur: Node | null = node;\n while (cur && cur !== root) {\n if (cur.nodeType === Node.ELEMENT_NODE) {\n const el = cur as HTMLElement;\n if (el.dataset.blockIndex != null) return el;\n }\n cur = cur.parentNode;\n }\n return null;\n}\n\n/** Walks up to the first ancestor carrying `data-cell-index`, stopping at the block element. */\nfunction findContainingCellElement(\n node: Node,\n blockEl: HTMLElement,\n): HTMLElement | null {\n let cur: Node | null = node;\n while (cur && cur !== blockEl) {\n if (cur.nodeType === Node.ELEMENT_NODE) {\n const el = cur as HTMLElement;\n if (el.dataset.cellIndex != null) return el;\n }\n cur = cur.parentNode;\n }\n return null;\n}\n\nexport function findBlockIndex(node: Node, root: HTMLElement): number | null {\n const el = findContainingBlockElement(node, root);\n if (!el) return null;\n return Number.parseInt(el.dataset.blockIndex!, 10);\n}\n\n/**\n * Returns the first DOM element for `blockIndex`. For a fragmented block this\n * is the first fragment. Prefer `getFragmentForOffset` when you need the\n * fragment that contains a specific offset.\n */\nexport function getBlockElement(root: HTMLElement, blockIndex: number): HTMLElement | null {\n return root.querySelector<HTMLElement>(`[data-block-index=\"${blockIndex}\"]`);\n}\n\nfunction readFragmentStart(el: HTMLElement): number {\n const s = el.dataset.fragmentStart;\n if (s == null) return 0;\n const n = Number.parseInt(s, 10);\n return Number.isFinite(n) ? n : 0;\n}\n\nfunction readFragmentEnd(el: HTMLElement): number | undefined {\n const s = el.dataset.fragmentEnd;\n if (s == null) return undefined;\n const n = Number.parseInt(s, 10);\n return Number.isFinite(n) ? n : undefined;\n}\n\n/**\n * Returns the DOM element responsible for `offset` inside `blockIndex`.\n * - Unfragmented block (single element): returns it.\n * - Fragmented block: returns the fragment whose `[start, end)` covers `offset`.\n * For the end-of-block offset, returns the last fragment.\n */\nexport function getFragmentForOffset(\n root: HTMLElement,\n blockIndex: number,\n offset: number,\n): HTMLElement | null {\n const candidates = root.querySelectorAll<HTMLElement>(`[data-block-index=\"${blockIndex}\"]`);\n if (candidates.length === 0) return null;\n if (candidates.length === 1) return candidates[0];\n let last: HTMLElement | null = null;\n for (const el of candidates) {\n last = el;\n const start = readFragmentStart(el);\n const end = readFragmentEnd(el);\n if (end == null) return el;\n if (offset >= start && offset < end) return el;\n }\n return last; // end-of-block offset falls on the last fragment\n}\n\n/**\n * Returns the `<td>` element for `(blockIndex, cellIndex)`. Tables are\n * unfragmented in 4.1 so there's at most one block element to search inside.\n */\nexport function getCellElement(\n root: HTMLElement,\n blockIndex: number,\n cellIndex: number,\n): HTMLElement | null {\n const blockEl = getBlockElement(root, blockIndex);\n if (!blockEl) return null;\n return blockEl.querySelector<HTMLElement>(`[data-cell-index=\"${cellIndex}\"]`);\n}\n\n/**\n * `true` when `el` is an image embed (a length-1 atomic insert in the model).\n * Image embeds participate in offset arithmetic as 1 char each. Intentionally\n * not a type predicate — narrowing `n is HTMLElement` would collapse the\n * \"already an HTMLElement\" path to `never` and break downstream code.\n */\nfunction isImgEmbed(n: Node): boolean {\n return (\n n.nodeType === Node.ELEMENT_NODE &&\n (n as HTMLElement).dataset.embed === \"image\"\n );\n}\n\n/**\n * `true` when `el` is the float-wrap anchor `<img>` rendered at the START of a\n * block (so CSS float can wrap text around it). The model places this embed at\n * its original offset — represented in the DOM by a zero-width phantom span —\n * so the anchor itself must be SKIPPED during offset counting.\n */\nfunction isWrapAnchorImg(n: Node): boolean {\n return (\n n.nodeType === Node.ELEMENT_NODE &&\n (n as HTMLElement).dataset.wrapAnchor === \"true\"\n );\n}\n\n/**\n * `true` when `el` is the zero-width sentinel left at the model offset of a\n * float-wrap image. Counts as 1 char in offset arithmetic, mirroring how the\n * embed counts in the model.\n */\nfunction isPhantomEmbed(n: Node): boolean {\n return (\n n.nodeType === Node.ELEMENT_NODE &&\n (n as HTMLElement).dataset.embedPhantom === \"true\"\n );\n}\n\n/** Index of `n` within its parent's `childNodes`. */\nfunction indexInParent(n: Node): number {\n const parent = n.parentNode;\n if (!parent) return 0;\n let i = 0;\n for (const c of Array.from(parent.childNodes)) {\n if (c === n) return i;\n i++;\n }\n return 0;\n}\n\n/**\n * `true` when the subtree rooted at `el` should be skipped during a\n * container-scoped walk — i.e. it belongs to a different block or to a sibling\n * cell when scoping a cell container.\n */\nfunction isRejectedSubtree(el: HTMLElement, container: HTMLElement): boolean {\n if (el === container) return false;\n if (el.dataset.blockIndex != null) return true;\n if (container.dataset.cellIndex != null && el.dataset.cellIndex != null) return true;\n return false;\n}\n\n/**\n * Sum length of all text nodes plus 1 for each image embed inside `container`,\n * up to the boundary defined by `(node, offsetInNode)`. Mirrors how the model\n * counts characters: embeds are atomic length-1 inserts.\n */\nexport function textOffsetWithin(\n container: HTMLElement,\n node: Node,\n offsetInNode: number,\n): number {\n // Normalize an anchor pointing AT an image embed to (parent, indexOfImg).\n let target: Node = node;\n let targetOff = offsetInNode;\n if (isImgEmbed(target) && target.parentNode) {\n targetOff = indexInParent(target);\n target = target.parentNode as Node;\n }\n\n let offset = 0;\n let done = false;\n\n function visit(n: Node): void {\n if (done) return;\n if (n === target) {\n if (n.nodeType === Node.TEXT_NODE) {\n offset += targetOff;\n done = true;\n return;\n }\n // Element target: consume childNodes[0..targetOff-1] recursively.\n const children = n.childNodes;\n for (let i = 0; i < targetOff && i < children.length; i++) {\n visit(children[i]);\n if (done) return;\n }\n done = true;\n return;\n }\n if (n.nodeType === Node.TEXT_NODE) {\n offset += (n.textContent ?? \"\").length;\n return;\n }\n if (n.nodeType !== Node.ELEMENT_NODE) return;\n const el = n as HTMLElement;\n if (isRejectedSubtree(el, container)) return;\n // Float-wrap anchor `<img>` is rendered at the block start as a pure\n // visual; its model position lives in the phantom span downstream.\n if (isImgEmbed(el) && isWrapAnchorImg(el)) return;\n if (isImgEmbed(el) || isPhantomEmbed(el)) {\n offset += 1;\n return;\n }\n for (const child of Array.from(el.childNodes)) {\n visit(child);\n if (done) return;\n }\n }\n\n visit(container);\n return offset;\n}\n\ninterface ResolvedAnchor {\n blockIdx: number;\n cellIdx: number | undefined;\n /** The element whose text content offsets are computed against. */\n container: HTMLElement;\n /** Number to add to within-container offsets — non-zero only for fragmented blocks. */\n containerStart: number;\n}\n\nfunction resolveAnchorElement(\n node: Node,\n root: HTMLElement,\n): ResolvedAnchor | null {\n const blockEl = findContainingBlockElement(node, root);\n if (!blockEl) return null;\n const blockIdx = Number.parseInt(blockEl.dataset.blockIndex!, 10);\n const blockType = blockEl.dataset.blockType;\n if (blockType === \"table\") {\n const cellEl = findContainingCellElement(node, blockEl);\n if (!cellEl) {\n // Click landed inside the table but not in any cell — snap to first cell.\n const firstCell = blockEl.querySelector<HTMLElement>(\"[data-cell-index]\");\n if (!firstCell) return null;\n return {\n blockIdx,\n cellIdx: 0,\n container: firstCell,\n containerStart: 0,\n };\n }\n const cellIdx = Number.parseInt(cellEl.dataset.cellIndex!, 10);\n return {\n blockIdx,\n cellIdx,\n container: cellEl,\n containerStart: 0,\n };\n }\n return {\n blockIdx,\n cellIdx: undefined,\n container: blockEl,\n containerStart: readFragmentStart(blockEl),\n };\n}\n\nexport function readDomSelection(root: HTMLElement): Selection | null {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n if (!sel.anchorNode || !sel.focusNode) return null;\n if (!root.contains(sel.anchorNode) || !root.contains(sel.focusNode)) return null;\n\n const a = resolveAnchorElement(sel.anchorNode, root);\n const f = resolveAnchorElement(sel.focusNode, root);\n if (!a || !f) return null;\n\n const anchor: Position = {\n blockIndex: a.blockIdx,\n cellIndex: a.cellIdx,\n offset: a.containerStart + textOffsetWithin(a.container, sel.anchorNode, sel.anchorOffset),\n };\n const focus: Position = {\n blockIndex: f.blockIdx,\n cellIndex: f.cellIdx,\n offset: f.containerStart + textOffsetWithin(f.container, sel.focusNode, sel.focusOffset),\n };\n return { anchor, focus };\n}\n\ninterface DomPoint {\n node: Node;\n offset: number;\n}\n\nexport function locatePoint(root: HTMLElement, pos: Position): DomPoint | null {\n let container: HTMLElement | null;\n let containerStart = 0;\n\n if (pos.cellIndex != null) {\n container = getCellElement(root, pos.blockIndex, pos.cellIndex);\n if (!container) return null;\n } else {\n container = getFragmentForOffset(root, pos.blockIndex, pos.offset);\n if (!container) return null;\n containerStart = readFragmentStart(container);\n }\n\n let remaining = Math.max(0, pos.offset - containerStart);\n let result: DomPoint | null = null;\n let lastImg: HTMLElement | null = null;\n let lastText: Text | null = null;\n\n function visit(n: Node): void {\n if (result) return;\n if (n.nodeType === Node.TEXT_NODE) {\n const len = (n.textContent ?? \"\").length;\n if (remaining <= len) {\n result = { node: n, offset: remaining };\n return;\n }\n remaining -= len;\n lastImg = null;\n lastText = n as Text;\n return;\n }\n if (n.nodeType !== Node.ELEMENT_NODE) return;\n const el = n as HTMLElement;\n if (isRejectedSubtree(el, container!)) return;\n // Skip the float-wrap anchor — its slot in the model lives on the phantom.\n if (isImgEmbed(el) && isWrapAnchorImg(el)) return;\n if (isImgEmbed(el) || isPhantomEmbed(el)) {\n if (remaining === 0) {\n const parent = el.parentNode;\n if (parent) {\n result = { node: parent, offset: indexInParent(el) };\n return;\n }\n }\n remaining -= 1;\n lastImg = el;\n return;\n }\n for (const child of Array.from(el.childNodes)) {\n visit(child);\n if (result) return;\n }\n }\n\n visit(container);\n if (result) return result;\n\n // Walked the whole container without consuming `remaining` — caret lands\n // just AFTER the last embed if it was the last visited node.\n if (lastImg && remaining === 0) {\n const parent = (lastImg as HTMLElement).parentNode;\n if (parent) return { node: parent, offset: indexInParent(lastImg) + 1 };\n }\n // Offset overflowed the container's content (the model selection is\n // transiently AHEAD of the rendered DOM — insertText commits the new\n // selection one React commit before the new text). Clamp to the END of the\n // last text node so the caret stays at the end of the line. Collapsing to\n // the container's start instead would paint the caret at the start of the\n // line for one frame before the next commit corrects it (bug #1 flash).\n if (lastText) {\n const t = lastText as Text;\n return { node: t, offset: (t.textContent ?? \"\").length };\n }\n return { node: container, offset: 0 };\n}\n\nexport function selectionsEqual(a: Selection, b: Selection): boolean {\n return (\n a.anchor.blockIndex === b.anchor.blockIndex &&\n (a.anchor.cellIndex ?? -1) === (b.anchor.cellIndex ?? -1) &&\n a.anchor.offset === b.anchor.offset &&\n a.focus.blockIndex === b.focus.blockIndex &&\n (a.focus.cellIndex ?? -1) === (b.focus.cellIndex ?? -1) &&\n a.focus.offset === b.focus.offset\n );\n}\n\n/**\n * `true` when the selection is a rectangular table-cell range — both endpoints\n * inside cells of the same block, addressing different cells. The visual\n * highlight comes from CSS classes applied by `<TableView>`; we deliberately\n * leave the native DOM selection empty so the browser doesn't draw a confusing\n * cross-`<td>` range.\n */\nexport function isTableRectSelection(sel: Selection): boolean {\n if (sel.anchor.blockIndex !== sel.focus.blockIndex) return false;\n if (sel.anchor.cellIndex == null || sel.focus.cellIndex == null) return false;\n return sel.anchor.cellIndex !== sel.focus.cellIndex;\n}\n\nexport function applyDomSelection(root: HTMLElement, modelSel: Selection): void {\n const domSel = window.getSelection();\n if (!domSel) return;\n if (isTableRectSelection(modelSel)) {\n // Don't paint a native range — TableView highlights the rect via classes.\n domSel.removeAllRanges();\n return;\n }\n const anchorPt = locatePoint(root, modelSel.anchor);\n const focusPt = locatePoint(root, modelSel.focus);\n if (!anchorPt || !focusPt) return;\n\n // Already on the resolved points? Don't touch the live range. `removeAllRanges`\n // momentarily clears the selection (the caret blinks out), so re-applying an\n // identical selection is a visible no-op flash. This matters when the offset\n // clamped to the end of the line (model transiently ahead of the DOM): the\n // caret is already there, so we must leave it alone (bug #1 flash).\n if (\n domSel.anchorNode === anchorPt.node &&\n domSel.anchorOffset === anchorPt.offset &&\n domSel.focusNode === focusPt.node &&\n domSel.focusOffset === focusPt.offset\n ) {\n return;\n }\n\n try {\n domSel.removeAllRanges();\n domSel.setBaseAndExtent(anchorPt.node, anchorPt.offset, focusPt.node, focusPt.offset);\n } catch {\n // ignore — node may not be attached yet\n }\n}\n","import type { ClipboardSlice } from \"@sofereditor/core\";\nimport { SOFER_MIME } from \"@sofereditor/core\";\nimport { htmlToSlice } from \"./htmlToSlice\";\n\n/**\n * O que fazer com uma colagem, decidido só a partir do clipboard.\n *\n * Vive separado do handler para que a ORDEM dos ramos seja testável sem montar\n * o editor inteiro. A ordem já regrediu uma vez em produção (ver `planPaste`).\n */\nexport type PastePlan =\n /** Slice do próprio editor (cópia interna). */\n | { kind: \"sofer\"; slice: ClipboardSlice }\n /** HTML externo (Word, Google Docs, navegador) com conteúdo aproveitável. */\n | { kind: \"html\"; slice: ClipboardSlice }\n /** Arquivos de imagem do sistema operacional. */\n | { kind: \"images\"; files: File[] }\n /** Texto puro; `text` nunca é vazio. */\n | { kind: \"text\"; text: string }\n /** Nada aproveitável — o handler não deve nem chamar preventDefault. */\n | { kind: \"none\" };\n\n/**\n * Decide o ramo da colagem.\n *\n * **A ordem é o ponto deste módulo.** HTML vem ANTES de arquivos de imagem: ao\n * copiar TEXTO, o Word coloca no clipboard o HTML completo E um PNG com o\n * trecho renderizado. Medido num caso real (2026-08-19): `types` =\n * `[\"text/plain\",\"text/html\",\"text/rtf\",\"Files\"]`, HTML de 40.517 bytes e\n * `image.png` de 7.392 bytes. Com arquivos na frente, o texto do professor era\n * colado como FIGURA e a formatação nunca era lida. O Google Docs não manda\n * arquivo — por isso só o Word sofria.\n *\n * Inverter é seguro porque `htmlToSlice` ignora imagens e devolve `null` quando\n * não sobra conteúdo: colar uma imagem (do Word, de um site ou do Finder) cai\n * no ramo de arquivos exatamente como antes.\n */\nexport function planPaste(cd: DataTransfer): PastePlan {\n // 1) Slice do próprio editor — sempre vence, é a representação mais fiel.\n const raw = cd.getData(SOFER_MIME);\n if (raw) {\n try {\n const slice = JSON.parse(raw) as ClipboardSlice;\n if (slice && Array.isArray(slice.blocks)) return { kind: \"sofer\", slice };\n } catch {\n // JSON corrompido — segue para os ramos externos.\n }\n }\n\n // 2) HTML externo, ANTES dos arquivos. Ver o comentário acima.\n const html = cd.getData(\"text/html\");\n if (html) {\n const slice = htmlToSlice(html);\n if (slice) return { kind: \"html\", slice };\n }\n\n // 3) Arquivos de imagem.\n const files = Array.from(cd.files ?? []).filter((f) => f.type.startsWith(\"image/\"));\n if (files.length > 0) return { kind: \"images\", files };\n\n // 4) Texto puro.\n const text = cd.getData(\"text/plain\");\n if (text.length > 0) return { kind: \"text\", text };\n\n return { kind: \"none\" };\n}\n","import type {\n AlignValue,\n BlockAttrs,\n BlockType,\n ClipboardSlice,\n DeltaOp,\n ListKind,\n MarkAttrs,\n SerializedBlock,\n} from \"@sofereditor/core\";\nimport { MAX_LIST_LEVEL } from \"@sofereditor/core\";\n\n/**\n * Converte o HTML do clipboard (Word / Google Docs / navegador) num\n * `ClipboardSlice` que o editor já sabe inserir via `insertSlice`.\n *\n * Sempre bloco-inteiro: `openStart`/`openEnd` são `false` e `blockLevel` é\n * `true` — o conteúdo colado de fora não é um fragmento de um dos blocos do\n * editor, é uma sequência de blocos novos. `blockLevel: true` é o que diz a\n * `insertSlice` (em `@sofereditor/core`) para adotar type/attrs do bloco\n * colado em vez de tratá-lo como fragmento de seleção — ver o comentário em\n * `ClipboardSlice.blockLevel`.\n *\n * Retorna `null` quando não sobra nada aproveitável, para o chamador (`Editor.tsx`)\n * cair no ramo de texto puro em vez de engolir a colagem.\n *\n * Duas armadilhas reais que este módulo trata explicitamente (ver testes):\n * - Google Docs embrulha o documento inteiro num `<b style=\"font-weight:normal\"\n * id=\"docs-internal-guid-...\">` — uma tag inline por fora de blocos inteiros.\n * `hasBlockDescendant` detecta isso e trata o wrapper como transparente\n * (propaga as marcas resolvidas, mas não achata os blocos internos).\n * - Word não usa `<ul>/<ol>/<li>` — usa `<p style=\"mso-list:l0 level1 ...\">`\n * com o marcador (número/símbolo) como texto literal dentro de um span\n * `mso-list:Ignore`. `parseWordListLevel` + a exclusão desse span tratam isso.\n *\n * fontFamily é deliberadamente NUNCA emitida: a escola padroniza Arial e cada\n * documento tem sua própria tipografia (mesma decisão de `import-docx`, que\n * descarta `w:rFonts`). fontSize É preservado (ver `parseFontSizePt`): o\n * modelo já suporta a mark, a barra já tem controle de tamanho, e descartar o\n * tamanho perdia informação real (título de 37.5pt colado do Google Docs saía\n * do tamanho do corpo). Unidades que dependem do contexto de herança do\n * documento de origem (em/rem/%/larger/smaller/medium) não são resolvíveis\n * aqui e por isso não emitem marca — sem tamanho é melhor que tamanho errado.\n */\nexport function htmlToSlice(html: string): ClipboardSlice | null {\n if (!html || html.trim().length === 0) return null;\n let doc: Document;\n try {\n doc = new DOMParser().parseFromString(html, \"text/html\");\n } catch {\n return null;\n }\n const body = doc.body;\n if (!body) return null;\n\n const blocks: SerializedBlock[] = [];\n try {\n walkBlockLevel(body, {}, blocks);\n } catch {\n // M7: aninhamento extremo (milhares de <span> aninhados, por exemplo)\n // estoura a pilha de chamadas em `walkInlineNode`/`walkBlockLevel`, que\n // são recursivas. O try/catch original só cobria o `DOMParser`, não o\n // walk — a exceção subia por `planPaste` e a colagem não fazia nada, nem\n // caía no fallback de texto puro. Devolvendo `null` aqui, o chamador\n // degrada para esse fallback em vez de engolir a colagem em silêncio.\n return null;\n }\n if (blocks.length === 0) return null;\n\n // I4: se o professor copia a partir de um sub-item, o primeiro listItem da\n // colagem pode não ser nível 0 (forma irmã do Docs, ou um `mso-list …\n // level2` sozinho/em sequência). O renderizador (`topLevelItemRanges`,\n // `Editor.tsx`) só abre um range de página em `level === 0` — sem esse\n // nível presente, o fatiamento de página perde um item num fragmento e\n // duplica a lista inteira noutro. Não é conserto na paginação (fora de\n // escopo aqui): fecha o caminho normalizando cada sequência contígua de\n // listItem para que o primeiro item sempre comece em 0.\n normalizeListLevels(blocks);\n\n // Nada aproveitável = TODO bloco sem texto. Acontece quando o HTML só\n // carregava imagem, que este conversor ignora por escopo: o Word manda uma\n // imagem como `<p class=MsoNormal><img ...><o:p></o:p></p>`, o que produziria\n // um parágrafo vazio. Devolver esse parágrafo faria `planPaste` escolher o\n // ramo de HTML e a imagem seria DESCARTADA — colar imagem do Word passaria a\n // inserir uma linha em branco. Devolvendo null, a colagem segue para o ramo\n // de arquivos, que insere a imagem.\n //\n // Parágrafo vazio NO MEIO de conteúdo real é linha em branco de propósito e\n // continua preservado — a regra só descarta quando não sobrou texto nenhum.\n const temTexto = blocks.some((b) => b.text.trim().length > 0);\n if (!temTexto) return null;\n\n // `blockLevel: true` diz a `insertSlice` para ADOTAR o type/attrs do bloco\n // colado em vez de fazer splice inline (ver o comentário em `insertSlice`).\n // Isso só vale a pena quando o resultado tem mais de um bloco (é\n // inequivocamente uma sequência de blocos externa) OU quando o único bloco\n // NÃO é um parágrafo simples (heading/listItem/blockquote — adotar o tipo é\n // o ganho real). Um ÚNICO parágrafo — a forma mais comum de colagem curta,\n // vinda de nós inline soltos (site/Chrome `<span>`, Word `<p class=\n // MsoNormal><span>`, Docs `<b style=\"font-weight:normal\">`) — NÃO é uma\n // \"colagem de bloco inteiro\" no sentido que importa aqui: marcar\n // `blockLevel` nesse caso faz `insertSlice` tratar até um trecho de duas\n // palavras como bloco externo, partindo o parágrafo do professor em três\n // (Dhead / bloco colado / tail) em vez de um splice inline, e — pior —\n // colar no offset 0 de um heading fazia `am.clear()` nos attrs do bloco\n // alvo, rebaixando o título a `paragraph`. Sem `blockLevel`, esse caso cai\n // no ramo de splice inline (comportamento de antes da branch); um bloco\n // único que É heading/listItem/blockquote continua adotando o tipo — o\n // ganho que motivou esta branch.\n const blockLevel = blocks.length > 1 || blocks[0].type !== \"paragraph\";\n return { blocks, openStart: false, openEnd: false, ...(blockLevel ? { blockLevel: true as const } : {}) };\n}\n\n// ---------------------------------------------------------------------------\n// Classificação de tags\n// ---------------------------------------------------------------------------\n\n/** Tags cujo conteúdo nunca vira texto (script/style vazam pra dentro do body\n * no HTML que o Google Docs cola; o:p/w:.../v:... são namespaces do Word). */\nconst IGNORED_TAGS = new Set([\"script\", \"style\", \"meta\", \"link\", \"head\", \"title\", \"xml\"]);\n\n/** Tags \"block-ish\": sem filhos de bloco viram UM parágrafo; com filhos de\n * bloco são tratadas como container transparente (ver `hasBlockDescendant`). */\nconst BLOCK_LEVEL_TAGS = new Set([\n \"p\",\n \"div\",\n \"section\",\n \"article\",\n \"header\",\n \"footer\",\n \"main\",\n \"figure\",\n \"figcaption\",\n \"pre\",\n \"address\",\n]);\n\n/** Tags que, se aparecerem como descendente direto ou indireto de um elemento\n * não tratado explicitamente, forçam esse elemento a ser um container\n * transparente em vez de uma corrida inline (caso do wrapper `<b>` do Docs). */\nconst BLOCK_TRIGGER_TAGS = new Set([\n \"p\",\n \"div\",\n \"ul\",\n \"ol\",\n \"li\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"blockquote\",\n \"table\",\n \"tr\",\n \"td\",\n \"th\",\n]);\n\nfunction isNamespacedTag(tag: string): boolean {\n return tag.includes(\":\");\n}\n\nfunction hasBlockDescendant(el: Element): boolean {\n const all = el.querySelectorAll(\"*\");\n for (const e of Array.from(all)) {\n if (BLOCK_TRIGGER_TAGS.has(e.tagName.toLowerCase())) return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Walker de nível de bloco\n// ---------------------------------------------------------------------------\n\nfunction walkBlockLevel(container: Element, marks: MarkAttrs, blocks: SerializedBlock[]): void {\n let loose: ChildNode[] = [];\n const flushLoose = () => {\n if (loose.length === 0) return;\n const nodes = loose;\n loose = [];\n const delta = inlineDeltaFromNodes(nodes, marks);\n if (delta.length > 0) blocks.push(makeBlock(\"paragraph\", delta, {}));\n };\n\n for (const node of Array.from(container.childNodes)) {\n if (node.nodeType === Node.COMMENT_NODE) continue;\n if (node.nodeType === Node.TEXT_NODE) {\n loose.push(node);\n continue;\n }\n if (node.nodeType !== Node.ELEMENT_NODE) continue;\n const el = node as Element;\n const tag = el.tagName.toLowerCase();\n if (IGNORED_TAGS.has(tag) || isNamespacedTag(tag)) continue;\n\n switch (tag) {\n case \"ul\":\n case \"ol\": {\n flushLoose();\n handleList(el, tag === \"ol\" ? \"ordered\" : \"bullet\", 0, marks, blocks);\n break;\n }\n case \"h1\":\n case \"h2\":\n case \"h3\":\n case \"h4\":\n case \"h5\":\n case \"h6\": {\n flushLoose();\n const level = Number(tag[1]) as 1 | 2 | 3 | 4 | 5 | 6;\n const attrs: BlockAttrs = { level };\n const align = readAlign(el);\n if (align) attrs.align = align;\n const delta = inlineDeltaFromNodes(Array.from(el.childNodes), marks);\n blocks.push(makeBlock(\"heading\", delta, attrs));\n break;\n }\n case \"blockquote\": {\n flushLoose();\n handleBlockquote(el, marks, blocks);\n break;\n }\n case \"table\": {\n flushLoose();\n handleTable(el, marks, blocks);\n break;\n }\n case \"li\": {\n // <li> fora de <ul>/<ol> (defensivo) — trata como bullet nível 0.\n // Mesma exclusão de listas aninhadas do <li> normal (handleList):\n // sem isso, um <li> defensivo com filho <ul> vazaria o texto do\n // filho pro pai e perderia a estrutura de listItem do filho.\n flushLoose();\n const nestedLists = topLevelListDescendants(el);\n const clone = el.cloneNode(true) as Element;\n for (const l of topLevelListDescendants(clone)) l.remove();\n const delta = inlineDeltaFromNodes(Array.from(clone.childNodes), marks);\n blocks.push(makeBlock(\"listItem\", delta, { listKind: \"bullet\", listLevel: 0 }));\n for (const nested of nestedLists) {\n const nestedKind: ListKind = nested.tagName.toLowerCase() === \"ol\" ? \"ordered\" : \"bullet\";\n handleList(nested, nestedKind, 1, marks, blocks);\n }\n break;\n }\n case \"img\":\n // Imagens são ignoradas neste caminho — colar imagem sozinha já\n // funciona pelo ramo de arquivos do clipboard.\n break;\n case \"br\":\n loose.push(node);\n break;\n default: {\n const styleAttr = el.getAttribute(\"style\") ?? \"\";\n const wordListLevel = parseWordListLevel(styleAttr);\n if (wordListLevel != null && !hasBlockDescendant(el)) {\n flushLoose();\n const marker = findWordListMarker(el);\n const listKind: ListKind = marker ? detectWordListKind(marker) : \"bullet\";\n const attrs: BlockAttrs = { listKind, listLevel: wordListLevel };\n const align = readAlign(el);\n if (align) attrs.align = align;\n const delta = inlineDeltaFromNodes(Array.from(el.childNodes), marks);\n blocks.push(makeBlock(\"listItem\", delta, attrs));\n break;\n }\n if (hasBlockDescendant(el)) {\n // Container transparente: tag inline (ou div) por fora de blocos\n // inteiros — caso clássico do wrapper do Google Docs. Propaga as\n // marcas resolvidas do próprio elemento para os blocos internos,\n // sem achatar a estrutura.\n flushLoose();\n let nextMarks = applyTagMarks(tag, marks);\n nextMarks = applyStyleMarks(el.getAttribute(\"style\"), nextMarks);\n walkBlockLevel(el, nextMarks, blocks);\n break;\n }\n if (BLOCK_LEVEL_TAGS.has(tag)) {\n flushLoose();\n const attrs: BlockAttrs = {};\n const align = readAlign(el);\n if (align) attrs.align = align;\n const delta = inlineDeltaFromNodes(Array.from(el.childNodes), marks);\n blocks.push(makeBlock(\"paragraph\", delta, attrs));\n break;\n }\n // Tag inline \"solta\" (span/b/i/a/font/...) sem filhos de bloco — junta\n // ao parágrafo corrente.\n loose.push(node);\n }\n }\n }\n flushLoose();\n}\n\n/**\n * Listas do Google Docs: `<ul>/<ol>` reais aninhados; nível = profundidade.\n *\n * Duas formas de aninhamento coexistem na prática e as duas têm que\n * funcionar:\n * - Canônica: `<li>texto<ul>...</ul></li>` — a lista filha é descendente do\n * `<li>` (direta, ou dentro de outro container como `<div>`).\n * - Real do Google Docs: `<li>texto</li><ul>...</ul>` — a lista filha é\n * IRMÃ do `<li>` dentro do mesmo `<ul>/<ol>` pai, não descendente dele.\n * Sem tratar essa forma, o item aninhado inteiro some (não aparece nem\n * como filho de outro bloco nem como block próprio).\n */\nfunction handleList(\n listEl: Element,\n kind: ListKind,\n level: number,\n marks: MarkAttrs,\n blocks: SerializedBlock[],\n): void {\n for (const child of Array.from(listEl.children)) {\n const tag = child.tagName.toLowerCase();\n if (tag === \"ul\" || tag === \"ol\") {\n // Forma \"irmã\": lista aninhada emitida como irmã do <li> anterior, não\n // dentro dele. Semanticamente ela pertence ao item anterior — sobe um\n // nível a partir do nível da lista atual.\n const siblingKind: ListKind = tag === \"ol\" ? \"ordered\" : \"bullet\";\n handleList(child, siblingKind, level + 1, marks, blocks);\n continue;\n }\n if (tag !== \"li\") continue;\n\n // Acha as listas aninhadas descendentes do <li> — diretas (forma\n // canônica) ou dentro de outro container (`<div>` etc; `<p>` nunca\n // aninha `<ul>` porque o parser HTML fecha o `<p>` antes). Só pega as\n // \"de fora para dentro\": uma lista aninhada dentro de outra lista já\n // encontrada não conta de novo aqui — ela é tratada recursivamente\n // quando a lista externa for percorrida.\n const nestedLists = topLevelListDescendants(child);\n\n // Clona o <li> e remove as listas aninhadas correspondentes do clone\n // antes de extrair o delta inline — sem isso, o texto do item filho\n // vaza para dentro do item pai (ex.: \"B1\" + \"B2\" viram \"B1B2\" quando a\n // lista aninhada está dentro de um <div> em vez de direta no <li>).\n const clone = child.cloneNode(true) as Element;\n for (const l of topLevelListDescendants(clone)) l.remove();\n const delta = inlineDeltaFromNodes(Array.from(clone.childNodes), marks);\n\n const attrs: BlockAttrs = { listKind: kind, listLevel: clampLevel(level) };\n const align = readAlign(child);\n if (align) attrs.align = align;\n blocks.push(makeBlock(\"listItem\", delta, attrs));\n for (const nested of nestedLists) {\n const nestedKind: ListKind = nested.tagName.toLowerCase() === \"ol\" ? \"ordered\" : \"bullet\";\n handleList(nested, nestedKind, level + 1, marks, blocks);\n }\n }\n}\n\n/** `<ul>/<ol>` descendentes de `root` que não estão, por sua vez, dentro de\n * outro `<ul>/<ol>` descendente de `root` — ou seja, o nível mais externo\n * de listas aninhadas dentro de `root`, não importa quantos containers\n * (`<div>`, `<p>`...) estejam no meio. Não atravessa fronteira de tabela:\n * uma lista dentro de uma `<td>`/`<th>` de uma `<table>` que por sua vez\n * esteja dentro de `root` pertence à célula, não ao `<li>` que contém a\n * tabela — não é \"promovida\" a listItem irmão (edge case raro, tabela\n * dentro de item de lista; ver `handleTable`, que não é chamado a partir\n * daqui, então o conteúdo da tabela continua achatado como antes). */\nfunction topLevelListDescendants(root: Element): Element[] {\n const all = Array.from(root.querySelectorAll(\"ul, ol\"));\n return all.filter((el) => {\n let p = el.parentElement;\n while (p && p !== root) {\n const t = p.tagName.toLowerCase();\n if (t === \"ul\" || t === \"ol\" || t === \"table\" || t === \"td\" || t === \"th\") return false;\n p = p.parentElement;\n }\n return true;\n });\n}\n\n/** `<blockquote>` — se tiver filhos de bloco (ex.: `<p>` internos), cada um\n * vira seu próprio bloco `blockquote`; senão, um único bloco a partir do\n * conteúdo inline. */\nfunction handleBlockquote(el: Element, marks: MarkAttrs, blocks: SerializedBlock[]): void {\n if (!hasBlockDescendant(el)) {\n const attrs: BlockAttrs = {};\n const align = readAlign(el);\n if (align) attrs.align = align;\n const delta = inlineDeltaFromNodes(Array.from(el.childNodes), marks);\n blocks.push(makeBlock(\"blockquote\", delta, attrs));\n return;\n }\n const nested: SerializedBlock[] = [];\n walkBlockLevel(el, marks, nested);\n for (const b of nested) {\n blocks.push(b.type === \"paragraph\" ? { ...b, type: \"blockquote\" } : b);\n }\n}\n\n/** Tabelas ficam de fora do modelo: o texto de cada célula sobrevive como\n * parágrafo(s), em ordem de leitura (linha a linha, célula a célula). Nunca\n * descarta texto — só a estrutura de grade é perdida, de propósito. */\nfunction handleTable(table: Element, marks: MarkAttrs, blocks: SerializedBlock[]): void {\n for (const row of directRows(table)) {\n const cells = Array.from(row.children).filter((c) =>\n [\"td\", \"th\"].includes(c.tagName.toLowerCase()),\n );\n for (const cell of cells) {\n const cellBlocks: SerializedBlock[] = [];\n walkBlockLevel(cell, marks, cellBlocks);\n for (const b of cellBlocks) {\n const attrs: BlockAttrs = {};\n if (b.attrs.align) attrs.align = b.attrs.align;\n blocks.push(makeBlock(\"paragraph\", b.delta, attrs));\n }\n }\n }\n}\n\nfunction directRows(table: Element): Element[] {\n const rows: Element[] = [];\n for (const child of Array.from(table.children)) {\n const tag = child.tagName.toLowerCase();\n if (tag === \"tr\") {\n rows.push(child);\n } else if (tag === \"tbody\" || tag === \"thead\" || tag === \"tfoot\") {\n for (const r of Array.from(child.children)) {\n if (r.tagName.toLowerCase() === \"tr\") rows.push(r);\n }\n }\n }\n return rows;\n}\n\n// ---------------------------------------------------------------------------\n// Word: `mso-list` (sem <ul>/<ol>/<li> reais)\n// ---------------------------------------------------------------------------\n\n/**\n * `mso-list:l0 level2 lfo1` → nível 1 (level é 1-based no Word).\n *\n * Isso sozinho não basta: o Word pode usar duas listas mso-list *separadas*\n * para pai e filho (`l0`/`lfo1` vs `l1`/`lfo2`) e marcar as duas como\n * `level1` — a profundidade real então só aparece no `margin-left` do\n * parágrafo, não no `levelN`. Por isso o nível final é o MAIOR entre o que\n * vem do `levelN` e o que vem da indentação (`nivelPelaMargem`): nenhum dos\n * dois caminhos é descartado, porque cada um cobre um caso que o outro não\n * cobre (levelN real sem margin-left; margin-left real com level1 repetido).\n */\nfunction parseWordListLevel(styleAttr: string): number | null {\n const m = /mso-list\\s*:\\s*l\\d+\\s+level(\\d+)/i.exec(styleAttr);\n if (!m) return null;\n const n = Number.parseInt(m[1], 10);\n const fromLevelN = Number.isFinite(n) ? Math.max(0, n - 1) : 0;\n const fromMargin = wordListLevelFromMarginLeft(marginLeftPt(styleAttr));\n return clampLevel(Math.max(fromLevelN, fromMargin));\n}\n\n/** `margin-left` do parágrafo, convertido para pt. Aceita `pt`/`cm`/`in`/`px`;\n * ausente, `auto`, negativo ou não-parseável conta como 0 (nunca reduz o\n * nível abaixo do que `levelN` já indicava). Ignora `text-indent` de\n * propósito — é o recuo pendente do marcador (`-18pt` típico), não a\n * profundidade do item. */\nfunction marginLeftPt(styleAttr: string): number {\n const raw = parseStyle(styleAttr)[\"margin-left\"];\n if (!raw) return 0;\n const m = /^(-?[\\d.]+)\\s*(pt|cm|in|px)$/i.exec(raw.trim());\n if (!m) return 0;\n const val = Number.parseFloat(m[1]);\n if (!Number.isFinite(val) || val < 0) return 0;\n switch (m[2].toLowerCase()) {\n case \"pt\":\n return val;\n case \"cm\":\n return val * 28.3465;\n case \"in\":\n return val * 72;\n case \"px\":\n return val * 0.75;\n default:\n return 0;\n }\n}\n\n/** 36pt (0,5\") é o passo padrão de indentação de lista do Word: primeiro\n * nível de recuo (36pt) é nível 0, cada 36pt adicional soma 1 nível. */\nfunction wordListLevelFromMarginLeft(pt: number): number {\n if (pt <= 0) return 0;\n return Math.max(0, Math.round(pt / 36) - 1);\n}\n\n/** Acha o span `mso-list:Ignore` que embrulha o marcador (número/símbolo +\n * o espaço de tabulação até o texto real). */\nfunction findWordListMarker(el: Element): Element | null {\n const all = el.querySelectorAll(\"*\");\n for (const e of Array.from(all)) {\n const style = (e.getAttribute(\"style\") ?? \"\").toLowerCase().replace(/\\s+/g, \"\");\n if (style.includes(\"mso-list:ignore\")) return e;\n }\n return null;\n}\n\n/** Marcador com dígito/letra seguido de `.`/`)` → ordered; símbolo (Symbol/\n * Wingdings ou glifo não alfanumérico) → bullet. */\nfunction detectWordListKind(markerEl: Element): ListKind {\n const all = [markerEl, ...Array.from(markerEl.querySelectorAll(\"*\"))];\n for (const e of all) {\n const style = (e.getAttribute(\"style\") ?? \"\").toLowerCase();\n if (style.includes(\"symbol\") || style.includes(\"wingdings\")) return \"bullet\";\n }\n const text = (markerEl.textContent ?? \"\").replace(/ /g, \" \").trim();\n if (/^[0-9]+[.)]/.test(text)) return \"ordered\";\n if (/^[a-zA-Z][.)]/.test(text)) return \"ordered\";\n return \"bullet\";\n}\n\n// ---------------------------------------------------------------------------\n// Walker inline (marcas + texto)\n// ---------------------------------------------------------------------------\n\nfunction inlineDeltaFromNodes(nodes: ChildNode[], marks: MarkAttrs): DeltaOp[] {\n const ops: DeltaOp[] = [];\n for (const n of nodes) walkInlineNode(n, marks, ops);\n return trimEdgeWhitespace(collapseRepeatedSpaces(mergeAdjacentOps(ops)));\n}\n\n/** Runs de espaço adjacentes em nós de texto distintos (ex.: \"antes \" + <img>\n * removida + \" depois\") colapsam pra um único espaço quando as marcas batem\n * e por isso já viraram um único op em `mergeAdjacentOps`. */\nfunction collapseRepeatedSpaces(ops: DeltaOp[]): DeltaOp[] {\n return ops.map((op) =>\n typeof op.insert === \"string\" ? { ...op, insert: op.insert.replace(/ {2,}/g, \" \") } : op,\n );\n}\n\nfunction walkInlineNode(node: ChildNode, marks: MarkAttrs, ops: DeltaOp[]): void {\n if (node.nodeType === Node.COMMENT_NODE) return;\n if (node.nodeType === Node.TEXT_NODE) {\n const text = normalizeWhitespace(node.textContent ?? \"\");\n if (text.length > 0) pushOp(ops, text, marks);\n return;\n }\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n const el = node as Element;\n const tag = el.tagName.toLowerCase();\n\n if (IGNORED_TAGS.has(tag) || isNamespacedTag(tag)) return;\n if (tag === \"img\") return; // imagens ignoradas neste caminho.\n if (tag === \"br\") {\n // \"\\n\" literal só é legítimo dentro de célula de tabela (ver\n // `core/src/commands.ts`, com `white-space: pre-wrap` no CSS da célula).\n // `.ed-block` não tem `pre-wrap`, então um \"\\n\" aqui virava espaço visual\n // mas continuava sendo um caractere invisível que contava offset e\n // travava o caret ao passar por ele. Correção mínima pra esta release:\n // emitir \" \" em vez de quebrar em blocos de verdade — quebrar em blocos\n // mudaria o contrato de `inlineDeltaFromNodes` (que hoje devolve um delta\n // pra um bloco só). Fica como trabalho futuro.\n ops.push({ insert: \" \" });\n return;\n }\n\n const styleAttr = (el.getAttribute(\"style\") ?? \"\").toLowerCase().replace(/\\s+/g, \"\");\n if (styleAttr.includes(\"mso-list:ignore\")) return; // marcador de lista do Word.\n\n let nextMarks = applyTagMarks(tag, marks);\n nextMarks = applyStyleMarks(el.getAttribute(\"style\"), nextMarks);\n if (tag === \"a\") {\n const href = el.getAttribute(\"href\");\n if (href) nextMarks = { ...nextMarks, link: { href } };\n }\n\n for (const child of Array.from(el.childNodes)) walkInlineNode(child, nextMarks, ops);\n}\n\n/** Negrito/itálico/sublinhado/tachado por NOME da tag. `style` explícito\n * (aplicado depois, em `applyStyleMarks`) tem prioridade e pode cancelar. */\nfunction applyTagMarks(tag: string, marks: MarkAttrs): MarkAttrs {\n switch (tag) {\n case \"b\":\n case \"strong\":\n return { ...marks, bold: true };\n case \"i\":\n case \"em\":\n return { ...marks, italic: true };\n case \"u\":\n return { ...marks, underline: true };\n case \"s\":\n case \"strike\":\n case \"del\":\n return { ...marks, strike: true };\n default:\n return marks;\n }\n}\n\nfunction parseStyle(styleAttr: string | null): Record<string, string> {\n const out: Record<string, string> = {};\n if (!styleAttr) return out;\n for (const decl of styleAttr.split(\";\")) {\n const idx = decl.indexOf(\":\");\n if (idx === -1) continue;\n const prop = decl.slice(0, idx).trim().toLowerCase();\n const val = decl.slice(idx + 1).trim();\n if (prop) out[prop] = val;\n }\n return out;\n}\n\n/**\n * Aplica overrides de `style` inline por cima das marcas herdadas/de tag.\n * A regra central: `font-weight`/`font-style`/`text-decoration` explícitos no\n * style VENCEM o nome da tag — é o que impede o wrapper `<b style=\"font-\n * weight:normal\">` do Google Docs de deixar o documento inteiro em negrito.\n *\n * `fontFamily` é intencionalmente NUNCA lida daqui — descartada sempre, junto\n * com `w:rFonts` no import-docx, pelo mesmo motivo (Arial-only). `fontSize` É\n * lida e normalizada para `pt` via `parseFontSizePt` — ver o comentário no\n * topo do arquivo.\n */\nfunction applyStyleMarks(styleAttr: string | null, marks: MarkAttrs): MarkAttrs {\n const decls = parseStyle(styleAttr);\n if (Object.keys(decls).length === 0) return marks;\n const next: MarkAttrs = { ...marks };\n\n if (\"font-weight\" in decls) {\n const v = decls[\"font-weight\"].toLowerCase();\n if (v === \"bold\" || /^[5-9]00$/.test(v)) next.bold = true;\n else if (v === \"normal\" || /^[1-4]00$/.test(v)) delete next.bold;\n }\n\n if (\"font-style\" in decls) {\n const v = decls[\"font-style\"].toLowerCase();\n if (v === \"italic\" || v === \"oblique\") next.italic = true;\n else if (v === \"normal\") delete next.italic;\n }\n\n const deco = decls[\"text-decoration-line\"] ?? decls[\"text-decoration\"];\n if (deco !== undefined) {\n const v = deco.toLowerCase();\n delete next.underline;\n delete next.strike;\n if (v.includes(\"underline\")) next.underline = true;\n if (v.includes(\"line-through\")) next.strike = true;\n }\n\n if (\"color\" in decls) {\n const css = normalizeCssColor(decls.color);\n if (css && !isBlack(css)) next.color = css;\n else delete next.color;\n }\n\n const bg = decls[\"background-color\"] ?? decls.background;\n if (bg !== undefined) {\n const css = normalizeCssColor(bg);\n if (css && css !== \"#ffffff\") next.highlight = css;\n else delete next.highlight;\n }\n\n if (\"font-size\" in decls) {\n const pt = parseFontSizePt(decls[\"font-size\"]);\n // Só troca quando dá para resolver. Quando NÃO dá (em/%/larger/... ou\n // valor absurdo), o local não sobrescreve — mantém o que já veio herdado\n // do ancestral em vez de apagar um tamanho que já tínhamos resolvido\n // corretamente. Não é o mesmo padrão de `color`/`highlight` (que apagam\n // no valor não resolvível): lá um valor ausente/errado é positivamente\n // \"sem cor\"; aqui um `em`/`%` não resolvível não é \"sem tamanho\", é\n // \"tamanho relativo que não sabemos calcular\" — silenciar é melhor que\n // apagar informação que já tínhamos.\n if (pt != null) next.fontSize = formatFontSizePt(pt);\n }\n\n return next;\n}\n\n/** `font-size` do CSS → pt, ou `undefined` quando a unidade depende do\n * contexto de herança do documento de origem (que não temos) ou o valor é\n * absurdo. `px`/`in` convertem para pt; `pt` passa direto; `em`/`rem`/`%`/\n * palavras-chave relativas (`larger`/`smaller`) e `medium`/`small`/`large`\n * (que também dependem do tamanho herdado) são ignorados de propósito — ver\n * o comentário no topo do arquivo. */\nfunction parseFontSizePt(raw: string): number | undefined {\n const v = raw.trim().toLowerCase();\n const m = /^(-?[\\d.]+)\\s*(pt|px|in)$/.exec(v);\n if (!m) return undefined;\n const num = Number.parseFloat(m[1]);\n if (!Number.isFinite(num)) return undefined;\n let pt: number;\n switch (m[2]) {\n case \"pt\":\n pt = num;\n break;\n case \"px\":\n pt = num * 0.75;\n break;\n case \"in\":\n pt = num * 72;\n break;\n default:\n return undefined;\n }\n // O bound usa o valor JÁ ARREDONDADO pra uma casa decimal — é isso que vai\n // pro `formatFontSizePt`. Sem isso, algo como `0.04pt` passa no `pt > 0`\n // aqui mas arredonda pra `\"0pt\"` lá na frente, violando a regra de \"≤0 não\n // emite\" por trás do arredondamento em vez de antes dele.\n const rounded = Math.round(pt * 10) / 10;\n if (rounded <= 0 || rounded > 200) return undefined;\n return rounded;\n}\n\n/** No máximo uma casa decimal, sem zero à toa: `37.5pt`, `11pt` — nunca\n * `37.50pt` nem `11.0pt`. */\nfunction formatFontSizePt(pt: number): string {\n const rounded = Math.round(pt * 10) / 10;\n const str = Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1);\n return `${str}pt`;\n}\n\nconst NAMED_COLORS: Record<string, string> = {\n black: \"#000000\",\n white: \"#ffffff\",\n red: \"#ff0000\",\n green: \"#008000\",\n blue: \"#0000ff\",\n yellow: \"#ffff00\",\n cyan: \"#00ffff\",\n magenta: \"#ff00ff\",\n gray: \"#808080\",\n grey: \"#808080\",\n orange: \"#ffa500\",\n purple: \"#800080\",\n};\n\n/** CSS color (hex/rgb(a)/nomeado) → hex normalizado, ou `undefined` quando\n * transparente/inválido/palavra-chave que não representa cor (inherit...). */\nfunction normalizeCssColor(raw: string | undefined): string | undefined {\n if (!raw) return undefined;\n const v = raw.trim().toLowerCase();\n if (!v || v === \"transparent\" || v === \"none\" || v === \"inherit\" || v === \"initial\") return undefined;\n if (v.startsWith(\"#\")) {\n let hex = v.slice(1);\n if (hex.length === 3) hex = hex.split(\"\").map((c) => c + c).join(\"\");\n return /^[0-9a-f]{6}$/.test(hex) ? `#${hex}` : undefined;\n }\n const rgbMatch = /^rgba?\\(([^)]+)\\)$/.exec(v);\n if (rgbMatch) {\n const parts = rgbMatch[1].split(\",\").map((s) => s.trim());\n if (parts.length < 3) return undefined;\n const alpha = parts[3] !== undefined ? Number.parseFloat(parts[3]) : 1;\n if (alpha === 0) return undefined;\n const toHex = (n: string) => {\n const num = Math.max(0, Math.min(255, Number.parseInt(n, 10) || 0));\n return num.toString(16).padStart(2, \"0\");\n };\n return `#${toHex(parts[0])}${toHex(parts[1])}${toHex(parts[2])}`;\n }\n return NAMED_COLORS[v];\n}\n\nfunction isBlack(hex: string): boolean {\n return hex.toLowerCase() === \"#000000\";\n}\n\nfunction readAlign(el: Element): AlignValue | undefined {\n const style = parseStyle(el.getAttribute(\"style\"));\n const v = style[\"text-align\"];\n if (!v) return undefined;\n switch (v.toLowerCase()) {\n case \"left\":\n case \"start\":\n return \"left\";\n case \"center\":\n return \"center\";\n case \"right\":\n case \"end\":\n return \"right\";\n case \"justify\":\n return \"justify\";\n default:\n return undefined;\n }\n}\n\nfunction clampLevel(n: number): number {\n if (!Number.isFinite(n)) return 0;\n return Math.max(0, Math.min(MAX_LIST_LEVEL, Math.trunc(n)));\n}\n\n/**\n * Normaliza `listLevel` de cada sequência CONTÍGUA de blocos `listItem` em\n * `blocks`, subtraindo o nível mínimo da sequência — o primeiro item da\n * colagem sempre acaba em nível 0, e as profundidades relativas entre os\n * itens são preservadas (ver I4 no comentário de `htmlToSlice`).\n *\n * Só desloca sequências com MAIS de um item. Um item sozinho não desloca:\n * o defeito de paginação que motiva esta normalização (`topLevelItemRanges`\n * em `Editor.tsx` só abrindo range em `level === 0`) exige pelo menos dois\n * itens pra se manifestar — com um item só, `topLevelItemRanges` devolve `[]`\n * e `renderListFragment` cai no fallback `renderTopLevel` (sem perda nem\n * duplicação). Deslocar um item sozinho SEMPRE daria nível 0 (o mínimo de um\n * conjunto de um elemento é o próprio elemento), apagando o nível real que\n * `parseWordListLevel` calculou a partir de `levelN`/`margin-left` — o que\n * destruiria informação sem nenhum ganho, porque o bug que isso fecha não\n * existe nesse caso.\n */\nfunction normalizeListLevels(blocks: SerializedBlock[]): void {\n let i = 0;\n while (i < blocks.length) {\n if (blocks[i].type !== \"listItem\") {\n i++;\n continue;\n }\n let j = i + 1;\n while (j < blocks.length && blocks[j].type === \"listItem\") j++;\n if (j - i > 1) {\n let min = Number.POSITIVE_INFINITY;\n for (let k = i; k < j; k++) {\n const lvl = (blocks[k].attrs.listLevel as number | undefined) ?? 0;\n if (lvl < min) min = lvl;\n }\n if (min > 0) {\n for (let k = i; k < j; k++) {\n const lvl = (blocks[k].attrs.listLevel as number | undefined) ?? 0;\n blocks[k].attrs.listLevel = clampLevel(lvl - min);\n }\n }\n }\n i = j;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Delta helpers\n// ---------------------------------------------------------------------------\n\nfunction pushOp(ops: DeltaOp[], text: string, marks: MarkAttrs): void {\n const hasMarks = Object.keys(marks).length > 0;\n ops.push(hasMarks ? { insert: text, attributes: { ...marks } } : { insert: text });\n}\n\n/** HTML colapsa espaço/tab/quebra-de-linha ASCII em um único espaço; ` `\n * (já decodificado pelo DOMParser em U+00A0) é preservado literalmente — NÃO\n * vira espaço normal (I2). \"Nome: … Turma:\" (a linha mais\n * comum de uma prova) e os spans `mso-tab-count` do Word (corridas de\n * ` `) dependem disso: colapsar U+00A0 pra espaço ASCII destrói o\n * espaçamento intencional do cabeçalho. As regexes de colapso\n * (`collapseRepeatedSpaces`) e trim (`trimEdgeWhitespace`) abaixo são\n * ASCII-only de propósito — `/ {2,}/` e `/[ \\t\\r\\n]+/` — então o nbsp passa\n * por elas intacto. */\nfunction normalizeWhitespace(raw: string): string {\n return raw.replace(/[ \\t\\r\\n]+/g, \" \");\n}\n\n/** Remove espaço em branco nas bordas do bloco — HTML não renderiza\n * espaço/quebra de linha logo após abrir ou logo antes de fechar um bloco. */\nfunction trimEdgeWhitespace(ops: DeltaOp[]): DeltaOp[] {\n let out = ops;\n if (out.length > 0 && typeof out[0].insert === \"string\") {\n const trimmed = out[0].insert.replace(/^ +/, \"\");\n if (trimmed.length === 0) out = out.slice(1);\n else if (trimmed !== out[0].insert) out = [{ ...out[0], insert: trimmed }, ...out.slice(1)];\n }\n if (out.length > 0 && typeof out[out.length - 1].insert === \"string\") {\n const last = out[out.length - 1];\n const trimmed = (last.insert as string).replace(/ +$/, \"\");\n if (trimmed.length === 0) out = out.slice(0, -1);\n else if (trimmed !== last.insert) out = [...out.slice(0, -1), { ...last, insert: trimmed }];\n }\n return out;\n}\n\nfunction mergeAdjacentOps(ops: DeltaOp[]): DeltaOp[] {\n const out: DeltaOp[] = [];\n for (const op of ops) {\n const prev = out[out.length - 1];\n if (\n prev &&\n typeof prev.insert === \"string\" &&\n typeof op.insert === \"string\" &&\n sameMarks(prev.attributes, op.attributes)\n ) {\n prev.insert = prev.insert + op.insert;\n continue;\n }\n out.push({ ...op });\n }\n return out;\n}\n\nfunction sameMarks(a: MarkAttrs | undefined, b: MarkAttrs | undefined): boolean {\n const ak = a ? Object.keys(a).sort() : [];\n const bk = b ? Object.keys(b).sort() : [];\n if (ak.length !== bk.length) return false;\n for (let i = 0; i < ak.length; i++) {\n if (ak[i] !== bk[i]) return false;\n const av = (a as Record<string, unknown>)[ak[i]];\n const bv = (b as Record<string, unknown>)[bk[i]];\n if (typeof av === \"object\" && av !== null && typeof bv === \"object\" && bv !== null) {\n if (JSON.stringify(av) !== JSON.stringify(bv)) return false;\n } else if (av !== bv) {\n return false;\n }\n }\n return true;\n}\n\nfunction deltaToText(delta: DeltaOp[]): string {\n let s = \"\";\n for (const op of delta) if (typeof op.insert === \"string\") s += op.insert;\n return s;\n}\n\nfunction makeBlock(type: BlockType, delta: DeltaOp[], attrs: BlockAttrs): SerializedBlock {\n return { type, text: deltaToText(delta), delta, attrs };\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useState,\n type CSSProperties,\n type JSX,\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n} from \"react\";\nimport { getFragmentForOffset } from \"./dom-bridge\";\n\ninterface Rect {\n top: number;\n left: number;\n width: number;\n height: number;\n}\n\ninterface BehindImageSelectAffordanceProps {\n blockIndex: number;\n offset: number;\n cellIndex?: number;\n rootRef: RefObject<HTMLDivElement>;\n /** Select the embed (shows the resize/move overlay). */\n onSelect: () => void;\n}\n\nconst ACCENT = \"#3b82f6\";\n\n/**\n * Hover affordance to select a `behind` image (z-index:-1) even when text sits\n * on top of it. The image's own box doesn't receive the click there — the text\n * /block does — so the overlay can't appear from a plain click. On hover we draw\n * a dashed outline (pointer-events:none, so it never steals a text click) plus a\n * clickable badge that selects the image. Lives in the un-clipped `.ed-root`\n * layer, positioned over the image (same measure pattern as ImageResizeOverlay).\n * Inline styles only — the package ships no CSS.\n */\nexport function BehindImageSelectAffordance({\n blockIndex,\n offset,\n cellIndex,\n rootRef,\n onSelect,\n}: BehindImageSelectAffordanceProps): JSX.Element | null {\n const [rect, setRect] = useState<Rect | null>(null);\n\n const locateImage = useCallback((): HTMLImageElement | null => {\n const root = rootRef.current;\n if (!root) return null;\n let container: HTMLElement | null = null;\n if (cellIndex != null) {\n container = root.querySelector<HTMLElement>(\n `[data-block-index=\"${blockIndex}\"] [data-cell-index=\"${cellIndex}\"]`,\n );\n } else {\n container = getFragmentForOffset(root, blockIndex, offset);\n }\n if (!container) return null;\n const fragmentStart = container.dataset.fragmentStart\n ? Number.parseInt(container.dataset.fragmentStart, 10) || 0\n : 0;\n const localOffset = offset - fragmentStart;\n return container.querySelector<HTMLImageElement>(\n `img[data-embed=\"image\"][data-embed-offset=\"${localOffset}\"]`,\n );\n }, [rootRef, blockIndex, offset, cellIndex]);\n\n const measure = useCallback(() => {\n const img = locateImage();\n const root = rootRef.current;\n if (!img || !root) {\n setRect((prev) => (prev === null ? prev : null));\n return;\n }\n const r = img.getBoundingClientRect();\n const rr = root.getBoundingClientRect();\n const next: Rect = {\n top: r.top - rr.top + root.scrollTop,\n left: r.left - rr.left + root.scrollLeft,\n width: r.width,\n height: r.height,\n };\n setRect((prev) =>\n prev &&\n prev.top === next.top &&\n prev.left === next.left &&\n prev.width === next.width &&\n prev.height === next.height\n ? prev\n : next,\n );\n }, [locateImage, rootRef]);\n\n useLayoutEffect(() => {\n measure();\n let cancelled = false;\n const remeasure = () => {\n if (!cancelled) measure();\n };\n const id =\n typeof requestAnimationFrame === \"function\"\n ? requestAnimationFrame(remeasure)\n : (queueMicrotask(remeasure), 0);\n return () => {\n cancelled = true;\n if (typeof cancelAnimationFrame === \"function\" && typeof id === \"number\" && id > 0) {\n cancelAnimationFrame(id);\n }\n };\n }, [measure]);\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const onScroll = () => measure();\n window.addEventListener(\"resize\", onScroll);\n root.addEventListener(\"scroll\", onScroll);\n return () => {\n window.removeEventListener(\"resize\", onScroll);\n root.removeEventListener(\"scroll\", onScroll);\n };\n }, [measure, rootRef]);\n\n if (!rect) return null;\n\n const outlineStyle: CSSProperties = {\n position: \"absolute\",\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n border: `1.5px dashed ${ACCENT}`,\n borderRadius: 2,\n boxSizing: \"border-box\",\n pointerEvents: \"none\",\n zIndex: 4,\n };\n\n const badgeStyle: CSSProperties = {\n position: \"absolute\",\n top: rect.top - 2,\n left: rect.left - 2,\n width: 24,\n height: 24,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n background: ACCENT,\n color: \"#fff\",\n borderRadius: 4,\n cursor: \"pointer\",\n pointerEvents: \"auto\",\n boxShadow: \"0 1px 3px rgba(0,0,0,0.3)\",\n zIndex: 5,\n };\n\n const onBadgeDown = (e: ReactPointerEvent<HTMLDivElement>) => {\n if (e.button !== 0) return;\n e.preventDefault();\n e.stopPropagation();\n onSelect();\n };\n\n return (\n <>\n <div style={outlineStyle} contentEditable={false} aria-hidden />\n <div\n style={badgeStyle}\n contentEditable={false}\n onPointerDown={onBadgeDown}\n role=\"button\"\n aria-label=\"Selecionar imagem\"\n title=\"Selecionar imagem\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n <path d=\"M5 9l-3 3 3 3M9 5l3-3 3 3M15 19l-3 3-3-3M19 9l3 3-3 3M2 12h20M12 2v20\" />\n </svg>\n </div>\n </>\n );\n}\n","import { type CSSProperties, type JSX } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { MOD_SYMBOL } from \"./platform\";\n\ninterface LinkHoverTooltipProps {\n href: string;\n /** Link bounding box in viewport coordinates (from getBoundingClientRect). */\n rect: { top: number; left: number; bottom: number; width: number };\n}\n\nconst MAX_WIDTH = 360;\nconst GAP = 6;\n\n/**\n * Small floating tooltip shown while hovering a link in the editor. Displays the\n * link URL plus a hint that Cmd/Ctrl+click opens it. Lives at `position: fixed`\n * (viewport coords from the link's rect) so it isn't clipped by the paginated\n * page boxes; `pointerEvents: none` so it never steals the hover/click from the\n * link underneath. The package ships no CSS — all styling is inline.\n */\nexport function LinkHoverTooltip({ href, rect }: LinkHoverTooltipProps): JSX.Element {\n // Prefer above the link; flip below when too close to the viewport top.\n const above = rect.top > 48;\n const viewportW = typeof window !== \"undefined\" ? window.innerWidth : MAX_WIDTH + 16;\n const left = Math.max(8, Math.min(rect.left, viewportW - MAX_WIDTH - 8));\n\n const style: CSSProperties = {\n position: \"fixed\",\n left,\n top: above ? rect.top - GAP : rect.bottom + GAP,\n transform: above ? \"translateY(-100%)\" : undefined,\n maxWidth: MAX_WIDTH,\n background: \"#1f2937\",\n color: \"#fff\",\n fontSize: 12,\n lineHeight: 1.4,\n padding: \"6px 9px\",\n borderRadius: 6,\n boxShadow: \"0 4px 14px rgba(0,0,0,0.28)\",\n zIndex: 60,\n pointerEvents: \"none\",\n };\n\n const urlStyle: CSSProperties = {\n display: \"block\",\n maxWidth: MAX_WIDTH - 18,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n fontWeight: 600,\n };\n\n const hintStyle: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n gap: 4,\n marginTop: 3,\n fontSize: 11,\n opacity: 0.85,\n };\n\n // Keycap look (the package ships no CSS): a small key-shaped chip around the\n // modifier glyph and the mouse-click glyph.\n const keycapStyle: CSSProperties = {\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minWidth: 16,\n height: 16,\n padding: \"0 4px\",\n fontSize: 11,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n background: \"rgba(255,255,255,0.16)\",\n border: \"1px solid rgba(255,255,255,0.4)\",\n borderRadius: 4,\n boxShadow: \"inset 0 -1px 0 rgba(0,0,0,0.25)\",\n };\n\n // Render into <body> so `position: fixed` stays viewport-relative even if the\n // editor is nested under a transformed/filtered ancestor (which would turn it\n // into the containing block for fixed elements). SSR-safe: no body, no portal.\n if (typeof document === \"undefined\") return <></>;\n\n return createPortal(\n <div style={style} contentEditable={false} aria-hidden role=\"tooltip\">\n <span style={urlStyle}>{href}</span>\n <span style={hintStyle}>\n <kbd style={keycapStyle}>{MOD_SYMBOL}</kbd>\n <span style={{ opacity: 0.8 }}>+ clique para abrir</span>\n </span>\n </div>,\n document.body,\n );\n}\n","/**\n * Platform detection for keyboard-modifier conventions. On macOS the \"command\"\n * modifier is ⌘ (`metaKey`); elsewhere it's Ctrl (`ctrlKey`). Computed once.\n */\nexport const IS_MAC: boolean = (() => {\n if (typeof navigator === \"undefined\") return false;\n // NB: case-INSENSITIVE. Chrome's `navigator.userAgentData.platform` returns\n // \"macOS\" (lowercase m), while `navigator.platform` returns \"MacIntel\" — a\n // `/Mac/` (case-sensitive) test silently missed \"macOS\", so Macs were treated\n // as non-Mac (showed \"Ctrl\", and Cmd+click didn't open).\n const platform =\n (navigator as Navigator & { userAgentData?: { platform?: string } }).userAgentData?.platform ||\n navigator.platform ||\n navigator.userAgent ||\n \"\";\n return /mac|iphone|ipad|ipod/i.test(platform);\n})();\n\n/** Text label for the platform's primary command modifier (\"Cmd\" / \"Ctrl\"). */\nexport const MOD_LABEL: string = IS_MAC ? \"Cmd\" : \"Ctrl\";\n\n/**\n * Keyboard GLYPH for the platform's command modifier: ⌘ (Command) on macOS,\n * ⌃ (Control) elsewhere. Used for keycap-style hints instead of the text label.\n */\nexport const MOD_SYMBOL: string = IS_MAC ? \"⌘\" : \"⌃\";\n\n/** True when the platform's \"open in new tab\" modifier is held during a click. */\nexport function hasOpenModifier(e: { metaKey: boolean; ctrlKey: boolean }): boolean {\n return IS_MAC ? e.metaKey : e.ctrlKey;\n}\n","import { createContext, useContext, type JSX, type ReactNode } from \"react\";\nimport { LinkDialog } from \"./LinkDialog\";\nimport { PageConfigDialog } from \"./PageConfigDialog\";\nimport { ImageCaptionDialog } from \"./ImageCaptionDialog\";\nimport type { UseEditorResult } from \"./useEditor\";\n\nconst EditorContext = createContext<UseEditorResult | null>(null);\n\nexport interface EditorProviderProps {\n editor: UseEditorResult;\n children: ReactNode;\n}\n\nexport function EditorProvider({ editor, children }: EditorProviderProps): JSX.Element {\n return (\n <EditorContext.Provider value={editor}>\n {children}\n <LinkDialog />\n <PageConfigDialog />\n <ImageCaptionDialog />\n </EditorContext.Provider>\n );\n}\n\nexport function useEditorContext(): UseEditorResult {\n const ctx = useContext(EditorContext);\n if (!ctx) {\n throw new Error(\"useEditorContext must be used inside an <EditorProvider>\");\n }\n return ctx;\n}\n","import {\n useEffect,\n useRef,\n useState,\n type FormEvent,\n type JSX,\n} from \"react\";\nimport { useEditorContext } from \"./EditorContext\";\nimport { DIALOG_CENTER_STYLE } from \"./dialogCenterStyle\";\n\n/**\n * Modal dialog for entering a link URL. Replaces the bare `window.prompt`\n * previously wired to Cmd+K and the toolbar link button. Renders only when\n * `editor.linkRequest` is set; consumes that state via `resolveLinkRequest`.\n *\n * Uses the native `<dialog>` element for focus trapping, ESC handling, and the\n * browser-provided backdrop.\n */\nexport function LinkDialog(): JSX.Element | null {\n const { linkRequest, resolveLinkRequest } = useEditorContext();\n const dialogRef = useRef<HTMLDialogElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const [href, setHref] = useState(\"\");\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n if (linkRequest) {\n setHref(linkRequest.initialHref);\n if (!dialog.open) dialog.showModal();\n // Defer focus + select-all to after the dialog finishes opening.\n queueMicrotask(() => {\n const input = inputRef.current;\n if (input) {\n input.focus();\n input.select();\n }\n });\n } else if (dialog.open) {\n dialog.close();\n }\n }, [linkRequest]);\n\n if (!linkRequest) return null;\n\n const onSubmit = (e: FormEvent) => {\n e.preventDefault();\n resolveLinkRequest(href.trim());\n };\n\n const onRemove = () => {\n // Empty string signals \"remove the link mark\".\n resolveLinkRequest(\"\");\n };\n\n const onCancel = () => {\n resolveLinkRequest(null);\n };\n\n return (\n <dialog\n ref={dialogRef}\n className=\"ed-link-dialog\"\n style={DIALOG_CENTER_STYLE}\n onClose={onCancel}\n onCancel={(e) => {\n e.preventDefault();\n onCancel();\n }}\n >\n <form onSubmit={onSubmit} className=\"ed-link-dialog-form\">\n <div className=\"ed-link-dialog-row\">\n <label htmlFor=\"ed-link-href\">URL</label>\n <input\n id=\"ed-link-href\"\n ref={inputRef}\n type=\"url\"\n inputMode=\"url\"\n value={href}\n onChange={(e) => setHref(e.target.value)}\n placeholder=\"https://exemplo.com\"\n autoComplete=\"off\"\n />\n </div>\n <div className=\"ed-link-dialog-actions\">\n {linkRequest.initialHref ? (\n <button type=\"button\" onClick={onRemove} className=\"ed-link-dialog-remove\">\n Remover link\n </button>\n ) : (\n <span />\n )}\n <div className=\"ed-link-dialog-confirm\">\n <button type=\"button\" onClick={onCancel}>\n Cancelar\n </button>\n <button type=\"submit\" className=\"ed-link-dialog-apply\">\n Aplicar\n </button>\n </div>\n </div>\n </form>\n </dialog>\n );\n}\n","import type { CSSProperties } from \"react\";\n\n/**\n * Inline centering for the editor's native `<dialog showModal()>` modals\n * (link / caption / page-config). The package ships no CSS, so it can't rely on\n * the consumer keeping the UA `dialog { margin: auto }` centering intact — some\n * apps (Tailwind/HeroUI resets, custom `dialog { margin: 0 }`) override it and\n * the modal then opens in the top-left corner. `position: fixed` + translate is\n * reset-proof; `maxHeight`/`overflow` keep a tall dialog from spilling\n * off-screen when translated.\n */\nexport const DIALOG_CENTER_STYLE: CSSProperties = {\n position: \"fixed\",\n top: \"50%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n margin: 0,\n maxHeight: \"90vh\",\n overflow: \"auto\",\n};\n","import { useEffect, useMemo, useRef, useState, type FormEvent, type JSX } from \"react\";\nimport {\n MARGIN_PRESETS,\n PAGE_PRESETS,\n detectPreset,\n mmToPx,\n pxToMm,\n type PageSettings,\n type PagePreset,\n} from \"@sofereditor/core\";\nimport { useEditorContext } from \"./EditorContext\";\nimport { DIALOG_CENTER_STYLE } from \"./dialogCenterStyle\";\n\ntype MarginPreset = \"normal\" | \"narrow\" | \"wide\" | \"custom\";\n\n/**\n * Modal dialog to configure page size and margins. Mirrors `LinkDialog` —\n * driven by `editor.pageConfigRequest`. On apply, writes via\n * `editor.setPageSettings`; on cancel, no write.\n */\nexport function PageConfigDialog(): JSX.Element | null {\n const { pageConfigRequest, resolvePageConfigRequest, setPageSettings } = useEditorContext();\n const dialogRef = useRef<HTMLDialogElement>(null);\n\n // Form state. Sizes are kept in mm for user-facing inputs; we convert to px\n // when applying. Width/height pair determines the size preset.\n const [sizePreset, setSizePreset] = useState<PagePreset>(\"a4\");\n const [widthMm, setWidthMm] = useState(210);\n const [heightMm, setHeightMm] = useState(297);\n const [marginPreset, setMarginPreset] = useState<MarginPreset>(\"normal\");\n const [marginTopMm, setMarginTopMm] = useState(25.4);\n const [marginBottomMm, setMarginBottomMm] = useState(25.4);\n const [marginLeftMm, setMarginLeftMm] = useState(25.4);\n const [marginRightMm, setMarginRightMm] = useState(25.4);\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n if (pageConfigRequest) {\n hydrateFromSettings(pageConfigRequest.initial, {\n setSizePreset,\n setWidthMm,\n setHeightMm,\n setMarginPreset,\n setMarginTopMm,\n setMarginBottomMm,\n setMarginLeftMm,\n setMarginRightMm,\n });\n if (!dialog.open) dialog.showModal();\n } else if (dialog.open) {\n dialog.close();\n }\n }, [pageConfigRequest]);\n\n // When the user picks a size preset, snap width/height back to the canonical\n // values. \"custom\" leaves the user free to edit.\n useEffect(() => {\n if (sizePreset === \"custom\") return;\n const p = PAGE_PRESETS[sizePreset];\n setWidthMm(roundMm(pxToMm(p.width)));\n setHeightMm(roundMm(pxToMm(p.height)));\n }, [sizePreset]);\n\n // When the user picks a margin preset, set all 4 margins to that value.\n useEffect(() => {\n if (marginPreset === \"custom\") return;\n const px = MARGIN_PRESETS[marginPreset];\n const mm = roundMm(pxToMm(px));\n setMarginTopMm(mm);\n setMarginBottomMm(mm);\n setMarginLeftMm(mm);\n setMarginRightMm(mm);\n }, [marginPreset]);\n\n const customWidth = sizePreset === \"custom\";\n\n // Live preview of the dimensions in px so the test/QA loop is easy to read.\n const previewPx = useMemo(\n () => ({\n width: Math.round(mmToPx(widthMm)),\n height: Math.round(mmToPx(heightMm)),\n }),\n [widthMm, heightMm],\n );\n\n if (!pageConfigRequest) return null;\n\n const onApply = (e: FormEvent) => {\n e.preventDefault();\n const next: Partial<PageSettings> = {\n width: mmToPx(widthMm),\n height: mmToPx(heightMm),\n marginTop: mmToPx(marginTopMm),\n marginBottom: mmToPx(marginBottomMm),\n marginLeft: mmToPx(marginLeftMm),\n marginRight: mmToPx(marginRightMm),\n };\n setPageSettings(next);\n resolvePageConfigRequest(true);\n };\n const onCancel = () => resolvePageConfigRequest(false);\n\n return (\n <dialog\n ref={dialogRef}\n className=\"ed-page-config-dialog\"\n style={DIALOG_CENTER_STYLE}\n onClose={onCancel}\n onCancel={(e) => {\n e.preventDefault();\n onCancel();\n }}\n >\n <form onSubmit={onApply} className=\"ed-page-config-form\">\n <h2>Configurar página</h2>\n\n <fieldset>\n <legend>Tamanho</legend>\n <div className=\"ed-page-config-row\">\n <label>\n <input\n type=\"radio\"\n name=\"size\"\n checked={sizePreset === \"a4\"}\n onChange={() => setSizePreset(\"a4\")}\n />{\" \"}\n A4 (210 × 297 mm)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"size\"\n checked={sizePreset === \"letter\"}\n onChange={() => setSizePreset(\"letter\")}\n />{\" \"}\n Carta (216 × 279 mm)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"size\"\n checked={sizePreset === \"oficio\"}\n onChange={() => setSizePreset(\"oficio\")}\n />{\" \"}\n Ofício (216 × 330 mm)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"size\"\n checked={sizePreset === \"custom\"}\n onChange={() => setSizePreset(\"custom\")}\n />{\" \"}\n Personalizado\n </label>\n </div>\n <div className=\"ed-page-config-row\">\n <label>\n Largura (mm){\" \"}\n <input\n type=\"number\"\n step={0.1}\n min={50}\n max={1000}\n value={widthMm}\n onChange={(e) => setWidthMm(Number(e.target.value))}\n disabled={!customWidth}\n />\n </label>\n <label>\n Altura (mm){\" \"}\n <input\n type=\"number\"\n step={0.1}\n min={50}\n max={1000}\n value={heightMm}\n onChange={(e) => setHeightMm(Number(e.target.value))}\n disabled={!customWidth}\n />\n </label>\n <span className=\"ed-page-config-preview\">\n {previewPx.width} × {previewPx.height} px\n </span>\n </div>\n </fieldset>\n\n <fieldset>\n <legend>Margens</legend>\n <div className=\"ed-page-config-row\">\n <label>\n <input\n type=\"radio\"\n name=\"margin\"\n checked={marginPreset === \"normal\"}\n onChange={() => setMarginPreset(\"normal\")}\n />{\" \"}\n Normal (25,4 mm)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"margin\"\n checked={marginPreset === \"narrow\"}\n onChange={() => setMarginPreset(\"narrow\")}\n />{\" \"}\n Estreita (12,7 mm)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"margin\"\n checked={marginPreset === \"wide\"}\n onChange={() => setMarginPreset(\"wide\")}\n />{\" \"}\n Larga (50,8 mm)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"margin\"\n checked={marginPreset === \"custom\"}\n onChange={() => setMarginPreset(\"custom\")}\n />{\" \"}\n Personalizada\n </label>\n </div>\n <div className=\"ed-page-config-row\">\n <label>\n Topo{\" \"}\n <input\n type=\"number\"\n step={0.1}\n min={0}\n max={200}\n value={marginTopMm}\n onChange={(e) => {\n setMarginTopMm(Number(e.target.value));\n setMarginPreset(\"custom\");\n }}\n />\n </label>\n <label>\n Inferior{\" \"}\n <input\n type=\"number\"\n step={0.1}\n min={0}\n max={200}\n value={marginBottomMm}\n onChange={(e) => {\n setMarginBottomMm(Number(e.target.value));\n setMarginPreset(\"custom\");\n }}\n />\n </label>\n <label>\n Esquerda{\" \"}\n <input\n type=\"number\"\n step={0.1}\n min={0}\n max={200}\n value={marginLeftMm}\n onChange={(e) => {\n setMarginLeftMm(Number(e.target.value));\n setMarginPreset(\"custom\");\n }}\n />\n </label>\n <label>\n Direita{\" \"}\n <input\n type=\"number\"\n step={0.1}\n min={0}\n max={200}\n value={marginRightMm}\n onChange={(e) => {\n setMarginRightMm(Number(e.target.value));\n setMarginPreset(\"custom\");\n }}\n />\n </label>\n </div>\n </fieldset>\n\n <div className=\"ed-page-config-actions\">\n <button type=\"button\" onClick={onCancel}>\n Cancelar\n </button>\n <button type=\"submit\" className=\"ed-page-config-apply\">\n Aplicar\n </button>\n </div>\n </form>\n </dialog>\n );\n}\n\nfunction roundMm(mm: number): number {\n return Math.round(mm * 10) / 10;\n}\n\nfunction hydrateFromSettings(\n s: PageSettings,\n setters: {\n setSizePreset: (v: PagePreset) => void;\n setWidthMm: (v: number) => void;\n setHeightMm: (v: number) => void;\n setMarginPreset: (v: MarginPreset) => void;\n setMarginTopMm: (v: number) => void;\n setMarginBottomMm: (v: number) => void;\n setMarginLeftMm: (v: number) => void;\n setMarginRightMm: (v: number) => void;\n },\n): void {\n const preset = detectPreset(s.width, s.height);\n setters.setSizePreset(preset);\n setters.setWidthMm(roundMm(pxToMm(s.width)));\n setters.setHeightMm(roundMm(pxToMm(s.height)));\n const top = roundMm(pxToMm(s.marginTop));\n const bottom = roundMm(pxToMm(s.marginBottom));\n const left = roundMm(pxToMm(s.marginLeft));\n const right = roundMm(pxToMm(s.marginRight));\n setters.setMarginTopMm(top);\n setters.setMarginBottomMm(bottom);\n setters.setMarginLeftMm(left);\n setters.setMarginRightMm(right);\n setters.setMarginPreset(detectMarginPreset(s));\n}\n\nfunction detectMarginPreset(s: PageSettings): MarginPreset {\n const TOL = 1; // px\n const allEqual =\n Math.abs(s.marginTop - s.marginBottom) <= TOL &&\n Math.abs(s.marginTop - s.marginLeft) <= TOL &&\n Math.abs(s.marginTop - s.marginRight) <= TOL;\n if (!allEqual) return \"custom\";\n for (const [name, px] of Object.entries(MARGIN_PRESETS) as Array<[keyof typeof MARGIN_PRESETS, number]>) {\n if (Math.abs(s.marginTop - px) <= TOL) return name as MarginPreset;\n }\n return \"custom\";\n}\n","import { useEffect, useRef, useState, type FormEvent, type JSX } from \"react\";\nimport { useEditorContext } from \"./EditorContext\";\nimport { DIALOG_CENTER_STYLE } from \"./dialogCenterStyle\";\nimport type { CaptionAlign } from \"./useEditor\";\n\n/**\n * Modal dialog for entering an image caption. Mirrors `LinkDialog` — driven by\n * `editor.imageCaptionRequest`. Empty input is treated as \"remove caption\".\n *\n * The only configurable property besides the text itself is the caption's\n * horizontal alignment (left / center / right). Word-style figure-caption\n * controls stop here intentionally — see `ImageEmbed.captionAlign`.\n */\nexport function ImageCaptionDialog(): JSX.Element | null {\n const { imageCaptionRequest, resolveImageCaptionRequest } = useEditorContext();\n const dialogRef = useRef<HTMLDialogElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const [caption, setCaption] = useState(\"\");\n const [align, setAlign] = useState<CaptionAlign>(\"center\");\n\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!dialog) return;\n if (imageCaptionRequest) {\n setCaption(imageCaptionRequest.initialCaption);\n setAlign(imageCaptionRequest.initialAlign);\n if (!dialog.open) dialog.showModal();\n queueMicrotask(() => {\n const input = inputRef.current;\n if (input) {\n input.focus();\n input.select();\n }\n });\n } else if (dialog.open) {\n dialog.close();\n }\n }, [imageCaptionRequest]);\n\n if (!imageCaptionRequest) return null;\n\n const onSubmit = (e: FormEvent) => {\n e.preventDefault();\n resolveImageCaptionRequest({ caption, align });\n };\n const onRemove = () => resolveImageCaptionRequest({ caption: \"\", align });\n const onCancel = () => resolveImageCaptionRequest(null);\n\n return (\n <dialog\n ref={dialogRef}\n className=\"ed-caption-dialog ed-link-dialog\"\n // Centraliza por estilo inline (o pacote não envia CSS): consumidores com\n // reset global de `dialog` (ex.: `margin:0`) quebram a centralização do\n // <dialog> nativo via UA `margin:auto` → o modal abria no canto superior\n // esquerdo. `position:fixed` + translate é à prova de reset.\n style={DIALOG_CENTER_STYLE}\n onClose={onCancel}\n onCancel={(e) => {\n e.preventDefault();\n onCancel();\n }}\n >\n <form onSubmit={onSubmit} className=\"ed-link-dialog-form\">\n <div className=\"ed-link-dialog-row\">\n <label htmlFor=\"ed-caption-input\">Legenda</label>\n <input\n id=\"ed-caption-input\"\n ref={inputRef}\n type=\"text\"\n value={caption}\n onChange={(e) => setCaption(e.target.value)}\n placeholder=\"Ex.: Figura 1 — Mapa do Brasil\"\n autoComplete=\"off\"\n />\n </div>\n <div className=\"ed-link-dialog-row\">\n <span>Alinhamento</span>\n <div className=\"ed-caption-align-group\" role=\"radiogroup\" aria-label=\"Alinhamento da legenda\">\n {([\"left\", \"center\", \"right\"] as const).map((value) => (\n <label key={value} className=\"ed-caption-align-option\">\n <input\n type=\"radio\"\n name=\"caption-align\"\n value={value}\n checked={align === value}\n onChange={() => setAlign(value)}\n />\n {value === \"left\" ? \"Esquerda\" : value === \"center\" ? \"Centro\" : \"Direita\"}\n </label>\n ))}\n </div>\n </div>\n <div className=\"ed-link-dialog-actions\">\n {imageCaptionRequest.initialCaption ? (\n <button type=\"button\" onClick={onRemove} className=\"ed-link-dialog-remove\">\n Remover legenda\n </button>\n ) : (\n <span />\n )}\n <div className=\"ed-link-dialog-confirm\">\n <button type=\"button\" onClick={onCancel}>\n Cancelar\n </button>\n <button type=\"submit\" className=\"ed-link-dialog-apply\">\n Aplicar\n </button>\n </div>\n </div>\n </form>\n </dialog>\n );\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type JSX,\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n} from \"react\";\nimport type { ImageEmbed } from \"@sofereditor/core\";\nimport { findBlockIndex, getFragmentForOffset } from \"./dom-bridge\";\n\ninterface ImageResizeOverlayProps {\n rootRef: RefObject<HTMLDivElement>;\n blockIndex: number;\n offset: number;\n cellIndex?: number;\n embed: ImageEmbed;\n /** Called once on pointer-up with the final width/height (in CSS px). */\n onCommit: (width: number, height: number) => void;\n /**\n * Called once on pointer-up after a move-drag with the new offset\n * coordinates (CSS px). Only fired when `embed.layout` is non-inline.\n */\n onCommitMove?: (offsetX: number, offsetY: number) => void;\n /**\n * Called once on pointer-up after a move-drag when the image was dropped on a\n * DIFFERENT page than its current anchor. Re-anchors the embed to a block on\n * the destination page. Only fired for non-inline layouts.\n */\n onReanchor?: (\n to: { blockIndex: number; offset: number; cellIndex?: number },\n newOffsetX: number,\n newOffsetY: number,\n ) => void;\n}\n\ntype Corner = \"nw\" | \"ne\" | \"sw\" | \"se\";\n\ninterface Rect {\n top: number;\n left: number;\n width: number;\n height: number;\n}\n\n/**\n * Floating overlay drawn over the currently-selected image embed: 4 corner\n * handles + outline. Drag a handle to resize keeping aspect ratio. Changes are\n * applied live to the `<img>` style during the drag (no Y.Doc transactions per\n * frame); a single commit happens on pointer-up so Undo treats it as one step.\n */\nexport function ImageResizeOverlay({\n rootRef,\n blockIndex,\n offset,\n cellIndex,\n embed,\n onCommit,\n onCommitMove,\n onReanchor,\n}: ImageResizeOverlayProps): JSX.Element | null {\n const [rect, setRect] = useState<Rect | null>(null);\n const [isMoving, setIsMoving] = useState(false);\n const imgRef = useRef<HTMLImageElement | null>(null);\n\n const locateImage = useCallback((): HTMLImageElement | null => {\n const root = rootRef.current;\n if (!root) return null;\n let container: HTMLElement | null = null;\n if (cellIndex != null) {\n container = root.querySelector<HTMLElement>(\n `[data-block-index=\"${blockIndex}\"] [data-cell-index=\"${cellIndex}\"]`,\n );\n } else {\n container = getFragmentForOffset(root, blockIndex, offset);\n }\n if (!container) return null;\n // The renderInline data-embed-offset is LOCAL to the fragment / container.\n const fragmentStart = container.dataset.fragmentStart\n ? Number.parseInt(container.dataset.fragmentStart, 10) || 0\n : 0;\n const localOffset = offset - fragmentStart;\n return container.querySelector<HTMLImageElement>(\n `img[data-embed=\"image\"][data-embed-offset=\"${localOffset}\"]`,\n );\n }, [rootRef, blockIndex, offset, cellIndex]);\n\n const measure = useCallback(() => {\n const img = locateImage();\n if (!img) {\n setRect((prev) => (prev === null ? prev : null));\n return;\n }\n imgRef.current = img;\n const root = rootRef.current;\n if (!root) return;\n const r = img.getBoundingClientRect();\n const rr = root.getBoundingClientRect();\n const next: Rect = {\n top: r.top - rr.top + root.scrollTop,\n left: r.left - rr.left + root.scrollLeft,\n width: r.width,\n height: r.height,\n };\n setRect((prev) =>\n prev &&\n prev.top === next.top &&\n prev.left === next.left &&\n prev.width === next.width &&\n prev.height === next.height\n ? prev\n : next,\n );\n }, [locateImage, rootRef]);\n\n useLayoutEffect(() => {\n measure();\n // Pagination runs in a SEPARATE effect after this one, on LATER frames. So\n // right after an embed prop change OR a re-anchor (blockIndex/offset change\n // from a cross-page drag), the target <img> may not be locatable yet —\n // `measure()` sets rect=null and the overlay renders nothing. Re-measure\n // across a few frames UNTIL the image is found (rect set), then stop.\n // A single rAF wasn't enough: pagination can take several frames to place\n // the re-anchored block, leaving the overlay hidden until the next\n // selection change (bug: \"can't click to select the image right after it\n // re-anchors onto the new page\").\n let cancelled = false;\n let frame = 0;\n let rafId = 0;\n const remeasure = () => {\n if (cancelled) return;\n measure();\n // Keep retrying while the image still isn't locatable (bounded budget).\n if (!locateImage() && frame++ < 30) {\n rafId =\n typeof requestAnimationFrame === \"function\"\n ? requestAnimationFrame(remeasure)\n : (queueMicrotask(remeasure), 0);\n }\n };\n rafId =\n typeof requestAnimationFrame === \"function\"\n ? requestAnimationFrame(remeasure)\n : (queueMicrotask(remeasure), 0);\n return () => {\n cancelled = true;\n if (typeof cancelAnimationFrame === \"function\" && typeof rafId === \"number\" && rafId > 0) {\n cancelAnimationFrame(rafId);\n }\n };\n }, [\n measure,\n locateImage,\n embed.width,\n embed.height,\n embed.align,\n embed.src,\n embed.layout,\n embed.offsetX,\n embed.offsetY,\n ]);\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const onScroll = () => measure();\n window.addEventListener(\"resize\", onScroll);\n root.addEventListener(\"scroll\", onScroll);\n return () => {\n window.removeEventListener(\"resize\", onScroll);\n root.removeEventListener(\"scroll\", onScroll);\n };\n }, [measure, rootRef]);\n\n /*\n * The `useLayoutEffect` above re-measures synchronously when embed props\n * change — but the pagination engine runs its own re-layout in a SEPARATE\n * effect right after. That post-pagination shift can move the image by\n * dozens of pixels (e.g. when `align: center` flips it to `display: block`\n * and the paragraph reflows), leaving the overlay at the pre-shift\n * coordinates.\n *\n * A ResizeObserver on both the image AND the editor root fires whenever\n * either box changes — covers reflow, resize, font load, page repagination,\n * and image-load-late-decoded scenarios. Falls back to no-op in jsdom etc.\n */\n useEffect(() => {\n if (typeof ResizeObserver === \"undefined\") return;\n const img = locateImage();\n const root = rootRef.current;\n if (!img || !root) return;\n const ro = new ResizeObserver(() => measure());\n ro.observe(img);\n ro.observe(root);\n return () => ro.disconnect();\n }, [locateImage, measure, rootRef, embed.layout, embed.align, embed.src]);\n\n if (!rect) return null;\n\n const layout = embed.layout ?? \"inline\";\n const movable = layout !== \"inline\" && onCommitMove !== undefined;\n\n return (\n <div\n className=\"ed-image-overlay\"\n style={{ top: rect.top, left: rect.left, width: rect.width, height: rect.height }}\n contentEditable={false}\n >\n {isMoving && (\n // Non-clipped drag preview (Tier 2): the overlay lives in .ed-root and\n // follows the cursor, so the image stays visible while it crosses the\n // page boundary (the real, clipped figure is hidden during the drag).\n // Inline styles only — the package does not ship CSS.\n <img\n src={embed.src}\n alt=\"\"\n aria-hidden\n draggable={false}\n style={{\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"fill\",\n opacity: 0.8,\n pointerEvents: \"none\",\n }}\n />\n )}\n {movable && (\n <MoveHandle\n layout={layout}\n startOffsetX={embed.offsetX ?? 0}\n startOffsetY={embed.offsetY ?? 0}\n imgRef={imgRef}\n onCommit={onCommitMove!}\n onLiveChange={measure}\n rootRef={rootRef}\n blockIndex={blockIndex}\n offset={offset}\n cellIndex={cellIndex}\n onReanchor={onReanchor}\n onMoveStart={() => setIsMoving(true)}\n onMoveEnd={() => setIsMoving(false)}\n />\n )}\n <Handle\n corner=\"nw\"\n startW={embed.width}\n startH={embed.height}\n imgRef={imgRef}\n onCommit={onCommit}\n onLiveChange={measure}\n />\n <Handle\n corner=\"ne\"\n startW={embed.width}\n startH={embed.height}\n imgRef={imgRef}\n onCommit={onCommit}\n onLiveChange={measure}\n />\n <Handle\n corner=\"sw\"\n startW={embed.width}\n startH={embed.height}\n imgRef={imgRef}\n onCommit={onCommit}\n onLiveChange={measure}\n />\n <Handle\n corner=\"se\"\n startW={embed.width}\n startH={embed.height}\n imgRef={imgRef}\n onCommit={onCommit}\n onLiveChange={measure}\n />\n </div>\n );\n}\n\ninterface MoveHandleProps {\n layout: \"wrap-left\" | \"wrap-right\" | \"behind\" | \"front\" | \"inline\";\n startOffsetX: number;\n startOffsetY: number;\n imgRef: RefObject<HTMLImageElement | null>;\n onCommit: (ox: number, oy: number) => void;\n onLiveChange: () => void;\n rootRef: RefObject<HTMLDivElement>;\n blockIndex: number;\n offset: number;\n cellIndex?: number;\n onReanchor?: (\n to: { blockIndex: number; offset: number; cellIndex?: number },\n newOffsetX: number,\n newOffsetY: number,\n ) => void;\n /** Fired when a move-drag starts/ends, so the overlay can show a drag preview. */\n onMoveStart?: () => void;\n onMoveEnd?: () => void;\n}\n\nfunction MoveHandle({\n layout,\n startOffsetX,\n startOffsetY,\n imgRef,\n onCommit,\n onLiveChange,\n rootRef,\n blockIndex,\n offset,\n cellIndex,\n onReanchor,\n onMoveStart,\n onMoveEnd,\n}: MoveHandleProps): JSX.Element {\n const dragRef = useRef<{\n startX: number;\n startY: number;\n liveOX: number;\n liveOY: number;\n } | null>(null);\n\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>) => {\n if (e.button !== 0) return;\n if (!imgRef.current) return;\n e.preventDefault();\n e.stopPropagation();\n (e.target as HTMLElement).setPointerCapture(e.pointerId);\n dragRef.current = {\n startX: e.clientX,\n startY: e.clientY,\n liveOX: startOffsetX,\n liveOY: startOffsetY,\n };\n // Hide the real (clipped) image and show a non-clipped preview in the\n // overlay for the duration of the drag, so the image stays visible while\n // it crosses the page boundary (Tier 2). The figure keeps being moved\n // below (drives the overlay/preview position via onLiveChange) — it's just\n // invisible. Restored in finish().\n const styled = imgRef.current.closest<HTMLElement>(\".ed-figure\") ?? imgRef.current;\n styled.style.opacity = \"0\";\n onMoveStart?.();\n };\n\n const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>) => {\n const d = dragRef.current;\n if (!d || !imgRef.current) return;\n const dx = e.clientX - d.startX;\n const dy = e.clientY - d.startY;\n // Post-#11 the positioned/styled element is the <figure> wrapper, not the\n // <img> (which renders position:static inside it). Mutate the figure so the\n // live drag actually moves the image; fall back to the img defensively.\n const styled = imgRef.current.closest<HTMLElement>(\".ed-figure\") ?? imgRef.current;\n let nox = startOffsetX;\n let noy = startOffsetY;\n if (layout === \"wrap-left\") {\n // dx → right margin (gap to text); negative dx clamped to 8 (min gap).\n nox = Math.max(8, startOffsetX + dx);\n noy = Math.max(0, startOffsetY + dy);\n styled.style.marginRight = `${nox}px`;\n styled.style.marginTop = `${noy}px`;\n } else if (layout === \"wrap-right\") {\n // dx is mirrored: dragging LEFT increases the gap to text.\n nox = Math.max(8, startOffsetX - dx);\n noy = Math.max(0, startOffsetY + dy);\n styled.style.marginLeft = `${nox}px`;\n styled.style.marginTop = `${noy}px`;\n } else if (layout === \"behind\" || layout === \"front\") {\n nox = startOffsetX + dx;\n noy = startOffsetY + dy;\n styled.style.left = `${nox}px`;\n styled.style.top = `${noy}px`;\n }\n d.liveOX = nox;\n d.liveOY = noy;\n onLiveChange();\n };\n\n // Clamp a behind/front vertical offset so the image stays within `frag`'s\n // page content box (never clipped by .ed-page-content overflow:hidden).\n // Offsets are fragment-local (position:absolute relative to the .ed-block).\n // Used for BOTH the same-page path and the re-anchor path (dest fragment).\n const clampOffsetToFragment = (frag: HTMLElement, oy: number): number => {\n const img = imgRef.current;\n if (!img) return oy;\n const page = frag.closest<HTMLElement>(\".ed-page\");\n const content = page?.querySelector<HTMLElement>(\".ed-page-content\");\n if (!content) return oy;\n const fragRect = frag.getBoundingClientRect();\n const contentRect = content.getBoundingClientRect();\n const imgH = img.getBoundingClientRect().height;\n // Allowed top range in fragment-local px: [contentTop, contentBottom-imgH].\n const minLocalTop = contentRect.top - fragRect.top;\n const maxLocalTop = contentRect.bottom - fragRect.top - imgH;\n return Math.round(Math.max(minLocalTop, Math.min(oy, maxLocalTop)));\n };\n\n const clampedCommit = (ox: number, oy: number) => {\n const img = imgRef.current;\n const root = rootRef.current;\n if (!img || !root || (layout !== \"behind\" && layout !== \"front\")) {\n onCommit(ox, oy);\n return;\n }\n const frag = getFragmentForOffset(root, blockIndex, offset);\n if (!frag) {\n onCommit(ox, oy);\n return;\n }\n onCommit(ox, clampOffsetToFragment(frag, oy));\n };\n\n const finish = (e: ReactPointerEvent<HTMLDivElement>) => {\n const d = dragRef.current;\n if (!d) return;\n dragRef.current = null;\n try {\n (e.target as HTMLElement).releasePointerCapture(e.pointerId);\n } catch {\n // ignore\n }\n\n // End the drag preview and restore the real image's visibility. Restoring\n // imperatively (not just relying on React's commit re-render) avoids a\n // one-frame flicker between the commit and the re-render.\n if (imgRef.current) {\n const styled = imgRef.current.closest<HTMLElement>(\".ed-figure\") ?? imgRef.current;\n styled.style.opacity = \"\";\n }\n onMoveEnd?.();\n\n const img = imgRef.current;\n const root = rootRef.current;\n const liveOX = Math.round(d.liveOX);\n const liveOY = Math.round(d.liveOY);\n\n // Tables / wrap-anchors-in-cell are out of scope: keep the current path.\n // Re-anchoring only happens for non-inline embeds dropped on a DIFFERENT\n // top-level page, with onReanchor wired.\n if (!img || !root || onReanchor === undefined || cellIndex != null) {\n clampedCommit(liveOX, liveOY);\n return;\n }\n\n const imgRect = img.getBoundingClientRect();\n const centerY = imgRect.top + imgRect.height / 2;\n\n // Destination page by GEOMETRY. `elementFromPoint(center)` was unreliable:\n // it returns null in the gap between pages or off-viewport, so cross-page\n // drops failed to re-anchor and snapped back to page 1. Instead pick the\n // .ed-page whose box CONTAINS the image center, else the NEAREST page —\n // never null. imgRect and getBoundingClientRect share the viewport-relative\n // coordinate space, so the comparison holds at any scroll.\n const pages = Array.from(root.querySelectorAll<HTMLElement>(\".ed-page\"));\n let destPage: HTMLElement | null = null;\n let bestPageDist = Infinity;\n for (const pg of pages) {\n const r = pg.getBoundingClientRect();\n if (centerY >= r.top && centerY <= r.bottom) {\n destPage = pg;\n break;\n }\n const dist = centerY < r.top ? r.top - centerY : centerY - r.bottom;\n if (dist < bestPageDist) {\n bestPageDist = dist;\n destPage = pg;\n }\n }\n\n // Current anchor page = the page owning the current fragment.\n const currentFrag = getFragmentForOffset(root, blockIndex, offset);\n const currentPage = currentFrag?.closest<HTMLElement>(\".ed-page\") ?? null;\n\n // Same page (or no page resolved) → existing same-anchor path.\n if (destPage == null || destPage === currentPage) {\n clampedCommit(liveOX, liveOY);\n return;\n }\n\n // ---- Re-anchor to a block on the destination page ----\n // Destination anchor block by GEOMETRY: the block fragment on destPage whose\n // top is nearest the dropped image's top (no elementFromPoint).\n const blocksOnPage = Array.from(\n destPage.querySelectorAll<HTMLElement>(\"[data-block-index]\"),\n );\n let destFrag: HTMLElement | null = null;\n let bestBlockDist = Infinity;\n for (const b of blocksOnPage) {\n const dist = Math.abs(b.getBoundingClientRect().top - imgRect.top);\n if (dist < bestBlockDist) {\n bestBlockDist = dist;\n destFrag = b;\n }\n }\n\n // Empty destination page (no block fragments) → keep same-anchor + clamp.\n if (!destFrag) {\n clampedCommit(liveOX, liveOY);\n return;\n }\n\n const destBlockIndex = findBlockIndex(destFrag, root);\n if (destBlockIndex == null) {\n clampedCommit(liveOX, liveOY);\n return;\n }\n\n // Destination offset = the fragment's first rendered offset (fragmentStart),\n // so the anchor lands in the FRACTION of the block that lives on this page.\n const destOffset = destFrag.dataset.fragmentStart\n ? Number.parseInt(destFrag.dataset.fragmentStart, 10) || 0\n : 0;\n\n // Recompute absolute coords relative to the destination fragment box, and\n // CLAMP so the re-anchored image is never clipped on the destination page.\n // behind/front render position:absolute; left:ox; top:oy relative to the\n // .ed-block fragment (position:relative). So ox = imgLeft - fragLeft.\n const fragRect = destFrag.getBoundingClientRect();\n const newOffsetX = Math.round(imgRect.left - fragRect.left);\n const newOffsetY = clampOffsetToFragment(\n destFrag,\n Math.round(imgRect.top - fragRect.top),\n );\n\n onReanchor(\n { blockIndex: destBlockIndex, offset: destOffset, cellIndex: undefined },\n newOffsetX,\n newOffsetY,\n );\n };\n\n return (\n <div\n className=\"ed-image-move\"\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={finish}\n onPointerCancel={finish}\n />\n );\n}\n\ninterface HandleProps {\n corner: Corner;\n startW: number;\n startH: number;\n imgRef: RefObject<HTMLImageElement | null>;\n onCommit: (w: number, h: number) => void;\n onLiveChange: () => void;\n}\n\nconst MIN_W = 20;\n\nfunction Handle({\n corner,\n startW,\n startH,\n imgRef,\n onCommit,\n onLiveChange,\n}: HandleProps): JSX.Element {\n const dragRef = useRef<{\n startX: number;\n startY: number;\n startW: number;\n startH: number;\n aspect: number;\n liveW: number;\n liveH: number;\n } | null>(null);\n\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>) => {\n if (e.button !== 0) return;\n if (!imgRef.current) return;\n e.preventDefault();\n e.stopPropagation();\n (e.target as HTMLElement).setPointerCapture(e.pointerId);\n const aspect = startW > 0 && startH > 0 ? startW / startH : 1;\n dragRef.current = {\n startX: e.clientX,\n startY: e.clientY,\n startW,\n startH,\n aspect,\n liveW: startW,\n liveH: startH,\n };\n };\n\n const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>) => {\n const d = dragRef.current;\n if (!d || !imgRef.current) return;\n const dxRaw = e.clientX - d.startX;\n // SE/NE handles grow with +dx; NW/SW grow with -dx.\n const dx = corner === \"se\" || corner === \"ne\" ? dxRaw : -dxRaw;\n let w = Math.max(MIN_W, d.startW + dx);\n let h = w / d.aspect;\n // Apply live to the img element directly — no transaction.\n imgRef.current.style.width = `${w}px`;\n imgRef.current.style.height = `${h}px`;\n imgRef.current.width = Math.round(w);\n imgRef.current.height = Math.round(h);\n d.liveW = w;\n d.liveH = h;\n onLiveChange();\n };\n\n const finish = (e: ReactPointerEvent<HTMLDivElement>) => {\n const d = dragRef.current;\n if (!d) return;\n dragRef.current = null;\n try {\n (e.target as HTMLElement).releasePointerCapture(e.pointerId);\n } catch {\n // ignore\n }\n onCommit(Math.round(d.liveW), Math.round(d.liveH));\n };\n\n return (\n <div\n className={`ed-image-handle ${corner}`}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={finish}\n onPointerCancel={finish}\n />\n );\n}\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type CSSProperties,\n type JSX,\n type RefObject,\n} from \"react\";\nimport {\n decodeSelection,\n type EditorDocument,\n type EncodedCursor,\n} from \"@sofereditor/core\";\nimport { locatePoint } from \"./dom-bridge\";\n\n/**\n * Subconjunto mínimo da Awareness do y-protocols que o overlay usa. Tipar assim\n * evita que `@sofereditor/react` dependa de `y-protocols` — o objeto vem de fora\n * (de `useCollab().binding.awareness`) e é estruturalmente compatível.\n */\nexport interface AwarenessLike {\n clientID: number;\n getStates(): Map<number, Record<string, unknown>>;\n on(event: \"change\", cb: () => void): void;\n off(event: \"change\", cb: () => void): void;\n setLocalStateField(field: string, value: unknown): void;\n}\n\ninterface Rect {\n top: number;\n left: number;\n width: number;\n height: number;\n}\n\ninterface PeerCursorView {\n clientId: number;\n name: string;\n color: string;\n caret: { top: number; left: number; height: number } | null;\n selection: Rect[];\n}\n\ninterface RemoteCursorsOverlayProps {\n rootRef: RefObject<HTMLDivElement>;\n doc: EditorDocument;\n awareness: AwarenessLike;\n /** Muda a cada edição/repaginação → re-medir os carets remotos. */\n revision?: unknown;\n}\n\nconst DEFAULT_COLOR = \"#3b82f6\";\n\n/**\n * Desenha o caret + seleção + nome de cada usuário remoto sobre o conteúdo\n * paginado. Posições remotas chegam via awareness (campo `cursor`, codificado\n * com Y.RelativePosition pelo core) e são resolvidas para coordenadas DOM com\n * o mesmo bridge da seleção local — ciente de fragmentação por página.\n */\nexport function RemoteCursorsOverlay({\n rootRef,\n doc,\n awareness,\n revision,\n}: RemoteCursorsOverlayProps): JSX.Element | null {\n const [views, setViews] = useState<PeerCursorView[]>([]);\n const rafRef = useRef<number | null>(null);\n\n const measure = useCallback(() => {\n const root = rootRef.current;\n if (!root) {\n setViews((prev) => (prev.length === 0 ? prev : []));\n return;\n }\n const rr = root.getBoundingClientRect();\n const out: PeerCursorView[] = [];\n\n awareness.getStates().forEach((state, clientId) => {\n if (clientId === awareness.clientID) return;\n const s = state as {\n user?: { name?: string; color?: string };\n cursor?: EncodedCursor;\n };\n if (!s.cursor) return;\n const sel = decodeSelection(doc, s.cursor);\n if (!sel) return;\n\n const color = s.user?.color || DEFAULT_COLOR;\n const name = s.user?.name || \"Anônimo\";\n\n const focus = locatePoint(root, sel.focus);\n let caret: PeerCursorView[\"caret\"] = null;\n if (focus) {\n try {\n const range = document.createRange();\n range.setStart(focus.node, focus.offset);\n range.collapse(true);\n let rect = range.getBoundingClientRect();\n if (rect.height === 0 && focus.node.nodeType === Node.ELEMENT_NODE) {\n rect = (focus.node as HTMLElement).getBoundingClientRect();\n }\n caret = {\n top: rect.top - rr.top + root.scrollTop,\n left: rect.left - rr.left + root.scrollLeft,\n height: rect.height || 18,\n };\n } catch {\n /* range inválido — sem caret */\n }\n }\n\n const collapsed =\n sel.anchor.blockIndex === sel.focus.blockIndex &&\n (sel.anchor.cellIndex ?? -1) === (sel.focus.cellIndex ?? -1) &&\n sel.anchor.offset === sel.focus.offset;\n\n const selection: Rect[] = [];\n if (!collapsed && focus) {\n const anchor = locatePoint(root, sel.anchor);\n if (anchor) {\n try {\n const r = document.createRange();\n r.setStart(anchor.node, anchor.offset);\n r.setEnd(focus.node, focus.offset);\n if (r.collapsed) {\n r.setStart(focus.node, focus.offset);\n r.setEnd(anchor.node, anchor.offset);\n }\n for (const cr of Array.from(r.getClientRects())) {\n if (cr.width === 0 || cr.height === 0) continue;\n selection.push({\n top: cr.top - rr.top + root.scrollTop,\n left: cr.left - rr.left + root.scrollLeft,\n width: cr.width,\n height: cr.height,\n });\n }\n } catch {\n /* seleção cross-fragmento inválida — ignora */\n }\n }\n }\n\n out.push({ clientId, name, color, caret, selection });\n });\n\n setViews(out);\n }, [rootRef, doc, awareness]);\n\n const scheduleMeasure = useCallback(() => {\n if (rafRef.current != null) return;\n const raf =\n typeof requestAnimationFrame === \"function\"\n ? requestAnimationFrame\n : (cb: FrameRequestCallback) => setTimeout(() => cb(0), 16) as unknown as number;\n rafRef.current = raf(() => {\n rafRef.current = null;\n measure();\n });\n }, [measure]);\n\n // Awareness: re-mede quando qualquer peer muda cursor/entra/sai.\n useEffect(() => {\n const onChange = () => scheduleMeasure();\n awareness.on(\"change\", onChange);\n scheduleMeasure();\n return () => awareness.off(\"change\", onChange);\n }, [awareness, scheduleMeasure]);\n\n // Edição/repaginação local.\n useEffect(() => {\n scheduleMeasure();\n }, [revision, scheduleMeasure]);\n\n // Resize do root + scroll re-posicionam os carets.\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n const onScroll = () => scheduleMeasure();\n root.addEventListener(\"scroll\", onScroll, { passive: true });\n let ro: ResizeObserver | null = null;\n if (typeof ResizeObserver !== \"undefined\") {\n ro = new ResizeObserver(() => scheduleMeasure());\n ro.observe(root);\n }\n return () => {\n root.removeEventListener(\"scroll\", onScroll);\n ro?.disconnect();\n };\n }, [rootRef, scheduleMeasure]);\n\n if (views.length === 0) return null;\n\n const layer: CSSProperties = {\n position: \"absolute\",\n inset: 0,\n pointerEvents: \"none\",\n zIndex: 6,\n };\n\n return (\n <div className=\"ed-remote-cursors\" aria-hidden style={layer}>\n {views.map((v) => (\n <div key={v.clientId}>\n {v.selection.map((r, i) => (\n <div\n key={i}\n style={{\n position: \"absolute\",\n top: r.top,\n left: r.left,\n width: r.width,\n height: r.height,\n background: v.color,\n opacity: 0.22,\n borderRadius: 2,\n }}\n />\n ))}\n {v.caret && (\n <div\n style={{\n position: \"absolute\",\n top: v.caret.top,\n left: v.caret.left,\n height: v.caret.height,\n width: 2,\n background: v.color,\n }}\n >\n <span\n style={{\n position: \"absolute\",\n top: -15,\n left: -1,\n fontSize: 10,\n lineHeight: \"14px\",\n padding: \"0 4px\",\n borderRadius: 3,\n color: \"#fff\",\n background: v.color,\n whiteSpace: \"nowrap\",\n fontFamily: \"system-ui, sans-serif\",\n userSelect: \"none\",\n }}\n >\n {v.name}\n </span>\n </div>\n )}\n </div>\n ))}\n </div>\n );\n}\n","import { useMemo, useRef, type CSSProperties, type JSX, type ReactNode } from \"react\";\nimport {\n answerLineStyle,\n cellBorderStyle,\n tableRectSelection,\n type BlockAttrs,\n type CellAttrs,\n type SerializedBlock,\n type StyleRecord,\n} from \"@sofereditor/core\";\nimport { useEditorContext } from \"./EditorContext\";\nimport { renderInline } from \"./renderInline\";\nimport { sliceDelta } from \"./sliceDelta\";\nimport { TableResizeOverlay } from \"./TableResizeOverlay\";\n\nexport interface NodeViewFragment {\n index: number;\n start: number;\n end: number;\n}\n\ninterface NodeViewProps {\n block: SerializedBlock;\n index: number;\n /** Optional nested content. Used by `listItem` to host the nested <ol>/<ul>. */\n children?: ReactNode;\n /** Optional fragment slice — when present, the rendered DOM covers only chars [start, end). */\n fragment?: NodeViewFragment;\n /**\n * Optional table-row fragmentation slice for Sub-phase 4.6. When set, only\n * the rows in `[rowStart, rowEnd)` are rendered, and the resize overlay is\n * suppressed except on the FIRST fragment.\n */\n tableFragment?: { index: number; rowStart: number; rowEnd: number };\n}\n\nexport function NodeView({ block, index, children, fragment, tableFragment }: NodeViewProps): JSX.Element {\n if (block.type === \"table\") {\n return <TableView block={block} index={index} tableFragment={tableFragment} />;\n }\n const inline = fragment\n ? renderInline(sliceDelta(block.delta, fragment.start, fragment.end), index)\n : renderInline(block.delta, index);\n const common = commonBlockProps(block.attrs, index, block.type, fragment);\n\n switch (block.type) {\n case \"heading\": {\n const level = clampLevel(block.attrs.level);\n const Tag = (`h${level}` as unknown) as keyof JSX.IntrinsicElements;\n return (\n <Tag\n {...common}\n className={`ed-block ed-heading ed-heading-${level}${alignClass(block.attrs.align)}${fragmentClass(fragment)}`}\n >\n {inline}\n </Tag>\n );\n }\n case \"blockquote\":\n return (\n <blockquote\n {...common}\n className={`ed-block ed-blockquote${alignClass(block.attrs.align)}${fragmentClass(fragment)}`}\n >\n {inline}\n </blockquote>\n );\n case \"codeBlock\":\n return (\n <pre\n {...common}\n data-language={block.attrs.language ?? undefined}\n className={`ed-block ed-codeblock${alignClass(block.attrs.align)}`}\n >\n <code>{inline}</code>\n </pre>\n );\n case \"listItem\": {\n const level = clampListLevel(block.attrs.listLevel);\n return (\n <li\n {...common}\n data-list-kind={block.attrs.listKind ?? \"bullet\"}\n data-list-level={level}\n className={`ed-block ed-listitem${alignClass(block.attrs.align)}`}\n >\n {inline}\n {children}\n </li>\n );\n }\n case \"paragraph\":\n default:\n return (\n <div\n {...common}\n className={`ed-block ed-paragraph${alignClass(block.attrs.align)}${fragmentClass(fragment)}`}\n >\n {inline}\n </div>\n );\n }\n}\n\nexport function commonBlockProps(\n attrs: BlockAttrs,\n index: number,\n type: string,\n fragment: NodeViewFragment | undefined,\n) {\n const style: CSSProperties = {};\n if (attrs.align) style.textAlign = attrs.align;\n // Linha de resposta: régua inferior + entrelinha. Vem de um helper puro em\n // core para o HTML de servidor emitir exatamente o mesmo estilo.\n Object.assign(style, answerLineStyle(attrs) ?? {});\n const base: Record<string, unknown> = {\n \"data-block-index\": index,\n \"data-block-type\": type,\n dir: attrs.dir,\n style: Object.keys(style).length > 0 ? style : undefined,\n };\n if (!fragment) return base;\n base[\"data-fragment-index\"] = fragment.index;\n base[\"data-fragment-start\"] = fragment.start;\n base[\"data-fragment-end\"] = fragment.end;\n return base;\n}\n\nfunction fragmentClass(f?: NodeViewFragment): string {\n if (!f) return \"\";\n // First fragment keeps top margin, last keeps bottom; intermediate fragments drop both.\n return ` ed-fragment ed-fragment-${f.index}`;\n}\n\nfunction alignClass(a?: BlockAttrs[\"align\"]): string {\n return a ? ` ed-align-${a}` : \"\";\n}\n\n/**\n * Inline style for a table cell's visual attrs (align, bgColor).\n * Returns undefined when the cell has none, so the <td> carries no style attr.\n */\nexport function cellStyle(\n attrs?: CellAttrs,\n border?: StyleRecord,\n): CSSProperties | undefined {\n const style: CSSProperties = { ...(border as CSSProperties | undefined) };\n if (attrs?.align) style.textAlign = attrs.align;\n if (attrs?.bgColor) style.backgroundColor = attrs.bgColor;\n return Object.keys(style).length > 0 ? style : undefined;\n}\n\nfunction clampLevel(l: BlockAttrs[\"level\"]): 1 | 2 | 3 | 4 | 5 | 6 {\n if (l === 2 || l === 3 || l === 4 || l === 5 || l === 6) return l;\n return 1;\n}\n\nfunction clampListLevel(l: BlockAttrs[\"listLevel\"]): number {\n if (typeof l !== \"number\" || !Number.isFinite(l)) return 0;\n return Math.max(0, Math.min(5, Math.trunc(l)));\n}\n\ninterface TableViewProps {\n block: SerializedBlock;\n index: number;\n tableFragment?: { index: number; rowStart: number; rowEnd: number };\n}\n\nfunction TableView({ block, index, tableFragment }: TableViewProps): JSX.Element {\n const rows = clampPositive(block.attrs.rows);\n const cols = clampPositive(block.attrs.cols);\n const cells = block.cells ?? [];\n const widths = readColWidths(block.attrs.colWidths, cols);\n const tableRef = useRef<HTMLTableElement | null>(null);\n\n // Row range to render. Default = full table.\n const rowStart = tableFragment?.rowStart ?? 0;\n const rowEnd = tableFragment?.rowEnd ?? rows;\n const isFirstFragment = !tableFragment || tableFragment.index === 0;\n\n // Recompute the rectangular cell selection each render. Reading the snapshot\n // off `editor.snapshot` ties this to the same render that NodeView is in.\n const editor = useEditorContext();\n const rect = useMemo(() => {\n if (editor.selection.anchor.blockIndex !== index) return null;\n if (editor.selection.focus.blockIndex !== index) return null;\n return tableRectSelection(editor.doc, editor.selection);\n }, [editor.doc, editor.selection, index]);\n\n return (\n <div className=\"ed-table-wrap\">\n <table\n ref={tableRef}\n data-block-index={index}\n data-block-type=\"table\"\n className=\"ed-block ed-table\"\n >\n {widths && (\n <colgroup>\n {widths.map((w, c) => (\n <col key={c} style={w != null ? { width: `${w}px` } : undefined} />\n ))}\n </colgroup>\n )}\n <tbody>\n {Array.from({ length: rowEnd - rowStart }, (_, i) => {\n const r = rowStart + i;\n return (\n <tr key={r} data-cell-row={r}>\n {Array.from({ length: cols }, (_, c) => {\n const flat = r * cols + c;\n const cell = cells[flat];\n if (cell?.attrs.covered === true) return null;\n const rowspan = spanAttr(cell?.attrs.rowspan);\n const colspan = spanAttr(cell?.attrs.colspan);\n const delta = cell?.delta ?? [];\n const inRect =\n rect !== null &&\n r >= rect.top && r <= rect.bottom &&\n c >= rect.left && c <= rect.right;\n // Cell align is applied via inline textAlign; block-level align uses ed-align-* classes instead.\n return (\n <td\n key={c}\n data-cell-index={flat}\n data-cell-row={r}\n data-cell-col={c}\n data-cell-rowspan={rowspan}\n data-cell-colspan={colspan}\n rowSpan={rowspan > 1 ? rowspan : undefined}\n colSpan={colspan > 1 ? colspan : undefined}\n style={cellStyle(\n cell?.attrs,\n // rowStart/rowEnd são os limites do FRAGMENTO: numa tabela\n // quebrada entre páginas, cada página fecha a própria caixa.\n cellBorderStyle(\n block.attrs.borderPreset,\n { row: r, col: c, rowspan, colspan, cols, rowStart, rowEnd },\n \"screen\",\n block.attrs.borderColor,\n ),\n )}\n className={inRect ? \"ed-cell ed-cell--selected\" : \"ed-cell\"}\n >\n {renderInline(delta, `t${index}-c${flat}`)}\n </td>\n );\n })}\n </tr>\n );\n })}\n </tbody>\n </table>\n {isFirstFragment && (\n <TableResizeOverlay tableRef={tableRef} blockIndex={index} cols={cols} />\n )}\n </div>\n );\n}\n\nfunction readColWidths(raw: unknown, cols: number): (number | null)[] | null {\n if (!Array.isArray(raw)) return null;\n const out: (number | null)[] = [];\n for (let i = 0; i < cols; i++) {\n const v = raw[i];\n out.push(typeof v === \"number\" && Number.isFinite(v) && v > 0 ? v : null);\n }\n return out;\n}\n\nfunction spanAttr(v: unknown): number {\n if (typeof v !== \"number\" || !Number.isFinite(v) || v < 1) return 1;\n return Math.trunc(v);\n}\n\nfunction clampPositive(n: unknown): number {\n if (typeof n !== \"number\" || !Number.isFinite(n) || n <= 0) return 1;\n return Math.trunc(n);\n}\n","import { Fragment, memo, type CSSProperties, type ReactNode } from \"react\";\nimport {\n BLANK_STYLE,\n isImageEmbed,\n splitUnderscoreRuns,\n type DeltaOp,\n type ImageEmbed,\n type MarkAttrs,\n} from \"@sofereditor/core\";\nimport { hasOpenModifier } from \"./platform\";\n\n/**\n * Convert a Y.Text delta into ReactNodes.\n *\n * Wrap order (innermost → outermost): bold → italic → underline → strike → font/color span → link.\n * Semantic tags carry bold/italic/underline/strike; color and fonts go on a styled <span>.\n *\n * Keys are stable on `${blockIndex}-${runningOffset}` so React reconciliation\n * survives split/merge of runs under collaboration.\n */\nexport function renderInline(delta: DeltaOp[], keyPrefix: number | string): ReactNode {\n if (\n delta.length === 0 ||\n (delta.length === 1 &&\n typeof delta[0].insert === \"string\" &&\n delta[0].insert === \"\")\n ) {\n return <br data-empty=\"true\" />;\n }\n let offset = 0;\n // Float-wrap images (wrap-left / wrap-right) are emitted as the FIRST DOM\n // children of the block so CSS float can flow the whole paragraph around\n // them — float only wraps siblings that come after it in DOM order. A\n // zero-width phantom span is left at the embed's original offset so the\n // caret-position math in dom-bridge keeps counting the embed as 1 char in\n // its true model position.\n const wrapAnchors: ReactNode[] = [];\n const body: ReactNode[] = [];\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n const text = op.insert;\n if (text.length === 0) continue;\n const key = `${keyPrefix}-${offset}`;\n body.push(<Fragment key={key}>{wrap(text, op.attributes)}</Fragment>);\n offset += text.length;\n } else if (isImageEmbed(op.insert)) {\n const key = `${keyPrefix}-${offset}`;\n const layout = op.insert.layout ?? \"inline\";\n // Marks aplicadas ao 1-char range que cobre o embed: hoje só\n // `comment` é renderizada visualmente (espelha o tratamento de\n // texto em `wrap()`). Outras marks (bold/italic/etc.) não fazem\n // sentido em embed visual e são ignoradas.\n const commentMarkId = op.attributes?.comment?.markId;\n if (layout === \"wrap-left\" || layout === \"wrap-right\") {\n wrapAnchors.push(\n <ImageEmbedView key={`${key}-anchor`} embed={op.insert} offset={offset} wrapAnchor />,\n );\n body.push(\n <span\n key={`${key}-phantom`}\n data-embed-phantom=\"true\"\n data-embed-offset={offset}\n contentEditable={false}\n style={PHANTOM_STYLE}\n />,\n );\n } else {\n const imgNode = <ImageEmbedView key={key} embed={op.insert} offset={offset} />;\n if (commentMarkId) {\n body.push(\n <span key={`${key}-cmt`} data-comment-id={commentMarkId} className=\"ed-comment\">\n {imgNode}\n </span>,\n );\n } else {\n body.push(imgNode);\n }\n }\n offset += 1;\n } else if (op.insert != null) {\n // Unknown embed kind — reserve the offset slot so caret math stays correct.\n offset += 1;\n }\n }\n if (wrapAnchors.length === 0 && body.length === 0) return <br data-empty=\"true\" />;\n return [...wrapAnchors, ...body];\n}\n\nconst PHANTOM_STYLE: CSSProperties = {\n display: \"inline-block\",\n width: 0,\n height: 0,\n overflow: \"hidden\",\n verticalAlign: \"baseline\",\n};\n\n// Inline style for links (the package ships no CSS). `color`/underline give the\n// link its visual affordance; `cursor: \"text\"` matches the surrounding editable\n// text — the browser's UA stylesheet makes `<a href>` use `cursor: pointer`,\n// which flickers pointer↔text across the link boundary inside a contentEditable\n// (hard to click / \"cursor oscila\"). To FOLLOW a link, Cmd/Ctrl+click.\nconst LINK_STYLE: CSSProperties = {\n color: \"#2563eb\",\n textDecoration: \"underline\",\n cursor: \"text\",\n};\n\ninterface ImageEmbedViewProps {\n embed: ImageEmbed;\n offset: number;\n wrapAnchor?: boolean;\n}\n\n/**\n * `embed.src` is a (potentially huge) base64 data URL. Y.Text.toDelta() builds\n * a fresh `ImageEmbed` object every time the parent snapshot recomputes — so\n * by default React would re-render `<img src={...}>` on every keystroke even\n * when nothing about the image changed. Memoizing by *value* on the cheap\n * fields and skipping the src deep-compare (it's stable while the embed is\n * stable; if src actually changes, width/height typically change too) keeps\n * the `<img>` DOM node fully stable across keystrokes.\n */\nfunction imageEmbedPropsEqual(a: ImageEmbedViewProps, b: ImageEmbedViewProps): boolean {\n if (a.offset !== b.offset || a.wrapAnchor !== b.wrapAnchor) return false;\n const x = a.embed;\n const y = b.embed;\n if (x === y) return true;\n return (\n x.width === y.width &&\n x.height === y.height &&\n x.layout === y.layout &&\n x.align === y.align &&\n x.offsetX === y.offsetX &&\n x.offsetY === y.offsetY &&\n x.caption === y.caption &&\n x.captionAlign === y.captionAlign &&\n // src is the expensive compare — only fall back to ref equality. Fresh\n // toDelta() objects share the same string reference for embed payloads\n // because Y.js stores the embed in its content map and re-exposes it.\n x.src === y.src\n );\n}\n\nconst ImageEmbedView = memo(ImageEmbedViewImpl, imageEmbedPropsEqual);\n\nfunction ImageEmbedViewImpl({\n embed,\n offset,\n wrapAnchor,\n}: ImageEmbedViewProps): ReactNode {\n const layout = embed.layout ?? \"inline\";\n const align = embed.align;\n const ox = embed.offsetX ?? 0;\n const oy = embed.offsetY ?? 0;\n const hasCaption = !!embed.caption && embed.caption.length > 0;\n\n // The outer style positions the wrapper (float / absolute / inline-block /\n // block-with-align). The img itself stays at intrinsic width × height so the\n // existing caret-position math (`data-embed-offset`) and ImageResizeOverlay\n // queries (`img[data-embed=\"image\"]`) keep working. A `<figcaption>` lives\n // inside the wrapper when a caption is set.\n let outerStyle: CSSProperties;\n switch (layout) {\n case \"wrap-left\":\n outerStyle = {\n float: \"left\",\n width: embed.width,\n marginRight: Math.max(8, ox),\n marginTop: Math.max(0, oy),\n marginBottom: 4,\n };\n break;\n case \"wrap-right\":\n outerStyle = {\n float: \"right\",\n width: embed.width,\n marginLeft: Math.max(8, ox),\n marginTop: Math.max(0, oy),\n marginBottom: 4,\n };\n break;\n case \"behind\":\n case \"front\":\n outerStyle = {\n position: \"absolute\",\n left: ox,\n top: oy,\n width: embed.width,\n zIndex: layout === \"behind\" ? -1 : 2,\n };\n break;\n case \"inline\":\n default:\n outerStyle = align\n ? {\n display: \"block\",\n width: embed.width,\n marginLeft: align === \"left\" ? 0 : \"auto\",\n marginRight: align === \"right\" ? 0 : \"auto\",\n }\n : {\n display: \"inline-block\",\n verticalAlign: \"text-bottom\",\n width: embed.width,\n };\n break;\n }\n\n // The img always carries the data-* attributes used by Editor/Overlay.\n //\n // Structure-stable rendering (bug #11): the <img> ALWAYS lives inside a\n // <figure> that carries `outerStyle`, so adding/removing a caption never\n // changes the <img>'s parent type. React then keeps the same <img> DOM node\n // instead of unmounting+remounting it — a remount would force a synchronous\n // base64 re-decode (`decoding=\"sync\"` below), freezing the UI on large\n // images. The <img> therefore always uses the intrinsic-size style; the\n // <figure> owns the positioning.\n const imgStyle: CSSProperties = {\n width: embed.width,\n height: embed.height,\n display: \"block\",\n };\n\n // `decoding=\"sync\"` + `loading=\"eager\"` evita o piscar quando a paginação\n // remonta o <img> (consumidor com `renderPageHeader` faz a 1ª página ter\n // marginTop diferente, o que muda o DOM pai do bloco quando ele cruza\n // páginas): com cache do browser quente, o frame de remount já vem pintado.\n const img = (\n <img\n src={embed.src}\n width={embed.width}\n height={embed.height}\n contentEditable={false}\n draggable={false}\n decoding=\"sync\"\n loading=\"eager\"\n data-embed=\"image\"\n data-embed-offset={offset}\n data-embed-align={align ?? \"\"}\n data-embed-layout={layout}\n data-wrap-anchor={wrapAnchor ? \"true\" : undefined}\n style={imgStyle}\n alt=\"\"\n />\n );\n\n // Always render the <figure> wrapper (structure-stable; see imgStyle note).\n // The <figcaption> is the ONLY part that toggles with the caption — the\n // <img> stays mounted, so no re-decode/freeze.\n const captionAlign = embed.captionAlign ?? \"center\";\n return (\n <figure\n className=\"ed-figure\"\n contentEditable={false}\n data-embed-figure={hasCaption ? \"true\" : undefined}\n data-embed-layout={layout}\n style={outerStyle}\n >\n {img}\n {hasCaption && (\n <figcaption\n className=\"ed-figcaption\"\n data-caption-align={captionAlign}\n style={{ textAlign: captionAlign }}\n >\n {embed.caption}\n </figcaption>\n )}\n </figure>\n );\n}\n\n/**\n * Corridas de 3+ underlines viram um traço contínuo (lacuna de prova).\n *\n * Os caracteres PERMANECEM no DOM como nós de texto: `dom-bridge` mapeia\n * posição de DOM → offset do modelo somando `textContent.length`, então dividir\n * a run em sub-spans é seguro, mas introduzir ou remover caracteres não seria.\n */\nfunction decorateBlanks(text: string): ReactNode {\n const segs = splitUnderscoreRuns(text);\n // Caminho comum (texto sem lacuna): devolve a string crua, sem wrapper.\n if (segs.length === 1 && !segs[0].blank) return text;\n return segs.map((s, i) =>\n s.blank ? (\n <span key={i} data-blank=\"true\" style={BLANK_STYLE as CSSProperties}>\n {s.text}\n </span>\n ) : (\n <Fragment key={i}>{s.text}</Fragment>\n ),\n );\n}\n\nfunction wrap(text: string, attrs?: MarkAttrs): ReactNode {\n // A lacuna fica DENTRO dos wrappers de mark: é decoração do texto, não uma mark.\n let node: ReactNode = decorateBlanks(text);\n if (!attrs) return node;\n\n if (attrs.bold) node = <strong>{node}</strong>;\n if (attrs.italic) node = <em>{node}</em>;\n if (attrs.underline) node = <u>{node}</u>;\n if (attrs.strike) node = <s>{node}</s>;\n\n const styleParts: CSSProperties = {};\n if (attrs.color) styleParts.color = attrs.color;\n if (attrs.highlight) styleParts.backgroundColor = attrs.highlight;\n if (attrs.fontFamily) styleParts.fontFamily = attrs.fontFamily;\n if (attrs.fontSize) styleParts.fontSize = attrs.fontSize;\n if (Object.keys(styleParts).length > 0) {\n node = <span style={styleParts}>{node}</span>;\n }\n\n if (attrs.link?.href) {\n node = (\n <a\n href={attrs.link.href}\n title={attrs.link.title}\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n style={LINK_STYLE}\n onClick={(e) => {\n // Plain click edits the link text (caret), never navigates. The\n // platform \"open\" modifier (⌘ on macOS, Ctrl elsewhere) opens the\n // link directly in a new tab. We `preventDefault` in BOTH cases and\n // open via `window.open` ourselves: inside a contentEditable the\n // browser doesn't reliably navigate an `<a>` on modifier-click, so\n // relying on the default action did nothing.\n e.preventDefault();\n if (hasOpenModifier(e) && attrs.link?.href) {\n window.open(attrs.link.href, \"_blank\", \"noopener,noreferrer\");\n }\n }}\n >\n {node}\n </a>\n );\n }\n\n if (attrs.comment?.markId) {\n node = (\n <span data-comment-id={attrs.comment.markId} className=\"ed-comment\">\n {node}\n </span>\n );\n }\n\n return node;\n}\n","import type { DeltaOp } from \"@sofereditor/core\";\n\n/** Total number of inserted characters. Embeds (non-string inserts) count as 1. */\nexport function deltaLength(delta: DeltaOp[]): number {\n let sum = 0;\n for (const op of delta) {\n if (typeof op.insert === \"string\") sum += op.insert.length;\n else if (op.insert != null) sum += 1;\n }\n return sum;\n}\n\n/**\n * Return the subset of `delta` covering `[start, end)` characters. Attributes\n * are preserved on each intersecting op. Embeds are atomic length-1 ops:\n * included whole if their slot intersects the range.\n */\nexport function sliceDelta(delta: DeltaOp[], start: number, end: number): DeltaOp[] {\n if (end <= start) return [];\n const out: DeltaOp[] = [];\n let cursor = 0;\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n const opStart = cursor;\n const opEnd = cursor + op.insert.length;\n cursor = opEnd;\n if (opEnd <= start) continue;\n if (opStart >= end) break;\n const sliceFrom = Math.max(opStart, start) - opStart;\n const sliceTo = Math.min(opEnd, end) - opStart;\n out.push({\n insert: op.insert.slice(sliceFrom, sliceTo),\n attributes: op.attributes,\n });\n } else if (op.insert != null) {\n const opStart = cursor;\n const opEnd = cursor + 1;\n cursor = opEnd;\n if (opEnd <= start) continue;\n if (opStart >= end) break;\n out.push({ insert: op.insert, attributes: op.attributes });\n }\n }\n return out;\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type JSX,\n type RefObject,\n} from \"react\";\nimport { useEditorContext } from \"./EditorContext\";\n\ninterface Props {\n /** Ref to the underlying `<table>` element. */\n tableRef: RefObject<HTMLTableElement | null>;\n blockIndex: number;\n cols: number;\n}\n\n/**\n * Renders absolute-positioned drag handles aligned with each column boundary\n * (except the table's left edge). While dragging, calls the editor's\n * `setColumnWidth` with the live width so the model — and therefore the\n * `<colgroup>` — updates in real time.\n *\n * Lives as a sibling of the `<table>` inside a `position: relative` wrapper.\n * Handles are `contentEditable={false}` so they don't interfere with caret\n * placement inside cells.\n */\nexport function TableResizeOverlay({ tableRef, blockIndex, cols }: Props): JSX.Element | null {\n const editor = useEditorContext();\n const [positions, setPositions] = useState<{ x: number; height: number } | null>(null);\n // The handle X positions and the table's total height. Recomputed after every layout.\n const [layout, setLayout] = useState<{ rights: number[]; height: number } | null>(null);\n const draggingRef = useRef<{ col: number; startX: number; startWidth: number } | null>(null);\n\n // Measure column right-edges relative to the table's left edge.\n const measure = useCallback(() => {\n const table = tableRef.current;\n if (!table) return;\n const tableRect = table.getBoundingClientRect();\n // Prefer measuring via `<col>` elements when present.\n const cgCols = table.querySelectorAll<HTMLTableColElement>(\"colgroup > col\");\n let rights: number[] = [];\n if (cgCols.length === cols) {\n let acc = 0;\n cgCols.forEach((c) => {\n acc += c.getBoundingClientRect().width;\n rights.push(acc);\n });\n } else {\n // Fallback: use the first row's <td> bounding rects.\n const firstRowCells = table.querySelectorAll<HTMLTableCellElement>(\"tbody > tr:first-child > td\");\n let acc = 0;\n firstRowCells.forEach((td) => {\n // Account for colSpan: split the width evenly across the spanned cols.\n const cs = Math.max(1, td.colSpan || 1);\n const w = td.getBoundingClientRect().width / cs;\n for (let i = 0; i < cs; i++) {\n acc += w;\n rights.push(acc);\n }\n });\n }\n if (rights.length !== cols) {\n // Shape mismatch — bail out rather than place handles in wrong spots.\n setLayout(null);\n return;\n }\n setLayout({ rights, height: tableRect.height });\n }, [cols, tableRef]);\n\n useLayoutEffect(() => {\n measure();\n }, [measure]);\n\n useEffect(() => {\n const table = tableRef.current;\n if (!table) return;\n const ro = new ResizeObserver(() => measure());\n ro.observe(table);\n return () => ro.disconnect();\n }, [measure, tableRef]);\n\n const onPointerDown = useCallback(\n (col: number) => (e: React.PointerEvent<HTMLDivElement>) => {\n // Prevent the editor from losing focus / caret being placed on the handle.\n e.preventDefault();\n e.stopPropagation();\n const table = tableRef.current;\n if (!table) return;\n const cgCols = table.querySelectorAll<HTMLTableColElement>(\"colgroup > col\");\n const startWidth = cgCols[col]?.getBoundingClientRect().width ?? 100;\n draggingRef.current = { col, startX: e.clientX, startWidth };\n setPositions({ x: e.clientX, height: layout?.height ?? 0 });\n (e.currentTarget as Element).setPointerCapture(e.pointerId);\n },\n [layout, tableRef],\n );\n\n const onPointerMove = useCallback(\n (e: React.PointerEvent<HTMLDivElement>) => {\n const d = draggingRef.current;\n if (!d) return;\n const dx = e.clientX - d.startX;\n const next = Math.max(40, d.startWidth + dx);\n editor.setColumnWidth(blockIndex, d.col, next);\n },\n [blockIndex, editor],\n );\n\n const onPointerUp = useCallback((e: React.PointerEvent<HTMLDivElement>) => {\n draggingRef.current = null;\n setPositions(null);\n try {\n (e.currentTarget as Element).releasePointerCapture(e.pointerId);\n } catch {\n /* ignore */\n }\n }, []);\n\n if (!layout) return null;\n const handleStyle = (x: number): CSSProperties => ({\n position: \"absolute\",\n top: 0,\n left: `${x - 3}px`,\n width: \"6px\",\n height: `${layout.height}px`,\n cursor: \"col-resize\",\n zIndex: 5,\n });\n\n // Render handles for every column EXCEPT we don't need a left-edge handle\n // (the table's left edge isn't a resizable boundary). Each handle resizes\n // the column whose right edge it sits on.\n void positions;\n return (\n <>\n {layout.rights.map((x, c) => (\n <div\n key={c}\n contentEditable={false}\n className=\"ed-col-resize-handle\"\n style={handleStyle(x)}\n onPointerDown={onPointerDown(c)}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n aria-label={`Redimensionar coluna ${c + 1}`}\n role=\"separator\"\n />\n ))}\n </>\n );\n}\n","import { useLayoutEffect, useRef, useState, type RefObject } from \"react\";\n\n/**\n * Sub-phase 3.2 — page layout with intra-paragraph fragmentation.\n *\n * Two-phase render cycle:\n * 1. \"measure\" phase: editor renders with the default (unfragmented) layout\n * — every top-level on page 1. After the DOM commits, `usePageLayout`\n * reads each top-level's geometry, runs `computeLayout`, and sets the\n * real layout (with page splits and fragment offsets).\n * 2. \"stable\" phase: editor renders the real layout. No further measurement\n * until `deps` change (typically `[topLevels]`), at which point we go\n * back to step 1.\n *\n * Fragmentation only applies to \"fragmentable\" top-levels (paragraph, heading,\n * blockquote — single Y.Text blocks). List groups and code blocks are placed\n * atomically: if they don't fit they jump to the next page and bleed if larger\n * than a page.\n */\n\nexport interface PageGeometry {\n /** Page width in CSS px (A4 @ 96dpi = ~794). */\n width: number;\n /** Page height in CSS px (A4 @ 96dpi = ~1123). */\n height: number;\n marginTop: number;\n marginBottom: number;\n marginLeft: number;\n marginRight: number;\n /**\n * Espaço adicional somado ao marginTop só na 1ª página. Útil para clientes\n * que rendem um header fixo (timbrado, identificação) na pág 1 via\n * `renderPageHeader` e não querem que esse espaço seja reservado nas demais.\n * Quando omitido, todas as páginas têm a mesma `contentHeight`.\n */\n firstPageExtraTop?: number;\n}\n\nexport const A4_PAGE: PageGeometry = {\n width: 794,\n height: 1123,\n marginTop: 96,\n marginBottom: 96,\n marginLeft: 96,\n marginRight: 96,\n};\n\nexport function contentHeight(g: PageGeometry, pageIndex: number = 0): number {\n const extra = pageIndex === 0 ? g.firstPageExtraTop ?? 0 : 0;\n return g.height - g.marginTop - g.marginBottom - extra;\n}\n\nexport function contentWidth(g: PageGeometry): number {\n return g.width - g.marginLeft - g.marginRight;\n}\n\nexport interface BlockFragment {\n index: number;\n start: number;\n end: number;\n}\n\nexport interface TableRowFragment {\n /** 0, 1, 2... sequential fragment id within the table. */\n index: number;\n /** First row included (inclusive). */\n rowStart: number;\n /** First row NOT included (exclusive). */\n rowEnd: number;\n}\n\nexport interface ListItemRangeFragment {\n /** 0, 1, 2... sequential fragment id within the list group. */\n index: number;\n /** First top-level item (level 0) included (inclusive). */\n itemStart: number;\n /** First top-level item (level 0) NOT included (exclusive). */\n itemEnd: number;\n}\n\nexport interface PageSlot {\n topLevelIndex: number;\n /** Set when this slot represents a paragraph/heading/blockquote line-level fragment. */\n fragment?: BlockFragment;\n /** Set when this slot is a row-range fragment of a table (Sub-phase 4.6). */\n tableFragment?: TableRowFragment;\n /** Set when this slot is an item-range fragment of an ordered/bullet list. */\n listFragment?: ListItemRangeFragment;\n}\n\nexport interface PageEntry {\n slots: PageSlot[];\n}\n\nexport interface PageLayout {\n pages: PageEntry[];\n}\n\nexport function defaultPageLayout(topLevelCount: number): PageLayout {\n return {\n pages: [\n {\n slots: Array.from({ length: topLevelCount }, (_, i) => ({ topLevelIndex: i })),\n },\n ],\n };\n}\n\nexport type PaginationPhase = \"measure\" | \"stable\";\n\nexport interface PageLayoutResult {\n layout: PageLayout;\n /**\n * \"measure\" between a deps change and the post-commit measurement; \"stable\"\n * once the layout matches the rendered DOM. Consumers can hide the caret /\n * suppress visible flashes during \"measure\" (the DOM is briefly in the\n * unfragmented intermediate state and the native caret may jump to the start\n * of the line before useLayoutEffect re-applies the model selection).\n */\n phase: PaginationPhase;\n}\n\nexport function usePageLayout(\n rootRef: RefObject<HTMLElement>,\n geometry: PageGeometry,\n topLevelCount: number,\n deps: ReadonlyArray<unknown>,\n): PageLayoutResult {\n const [phase, setPhase] = useState<PaginationPhase>(\"measure\");\n const [layout, setLayout] = useState<PageLayout>(() => defaultPageLayout(topLevelCount));\n const lastDepsRef = useRef<unknown[] | null>(null);\n\n // Reset effect: when `deps` (consumer-provided), `topLevelCount`, or\n // `geometry` change, go back to the unfragmented default layout and\n // re-enter the measure phase.\n //\n // Why a useLayoutEffect (instead of `setState` in render body, the previous\n // approach): with concurrent rendering / Strict Mode, mutating\n // `lastDepsRef.current` during render is fragile — React may discard a\n // render pass while keeping the ref mutation, so a subsequent pass sees\n // \"deps unchanged\" and the reset never fires. The historical symptom was\n // a doc whose N blocks arrived entirely via remote `Y.applyUpdate`\n // (e.g. an Hocuspocus / y-websocket sync): the editor's snapshot updated\n // to N in `useEditor`, but `layout` stayed at 1 page × 1 slot — the reset\n // condition in the old render-body path silently missed firing.\n //\n // Doing the reset in a useLayoutEffect runs after the commit (so refs are\n // stable and visible), but BEFORE paint (so the user never sees a frame\n // with stale layout). The phase change schedules a synchronous re-render\n // and the measure effect below picks up immediately.\n //\n // Equality uses `shallowArrayEqual` for deps (consumer's responsibility to\n // pass stable references / structural keys) and `layoutsDeepEqual` for\n // the layout itself (fragment-aware — see the historical bug where shallow\n // equality let a fragmented layout matching `1 page × 1 slot` survive the\n // reset and lock subsequent measures via `!isUnfragmented(layout)`).\n useLayoutEffect(() => {\n const currentDeps = [...deps, topLevelCount, geometry];\n if (lastDepsRef.current !== null && shallowArrayEqual(lastDepsRef.current, currentDeps)) {\n return;\n }\n lastDepsRef.current = currentDeps;\n setLayout((prev) => {\n const next = defaultPageLayout(topLevelCount);\n return layoutsDeepEqual(prev, next) ? prev : next;\n });\n setPhase(\"measure\");\n // No dependency array: this effect runs after every commit and decides\n // internally whether deps changed. We can't put `[...deps, topLevelCount, geometry]`\n // here because `deps` is a variable-length array from the caller — React's\n // hook deps must be a fixed-shape list. Running every commit is cheap (one\n // shallow array compare).\n });\n\n // Measure effect: when in the measure phase with an unfragmented layout,\n // read the DOM and compute the real (possibly multi-page, possibly\n // fragmented) layout. Returns to the \"stable\" phase.\n useLayoutEffect(() => {\n if (phase !== \"measure\") return;\n const root = rootRef.current;\n if (!root) return;\n // Only safe to measure when the DOM is in the unfragmented state.\n if (!isUnfragmented(layout)) return;\n const next = computeLayout(root, geometry, topLevelCount);\n if (!layoutsDeepEqual(layout, next)) setLayout(next);\n setPhase(\"stable\");\n }, [phase, layout, geometry, topLevelCount, rootRef]);\n\n return { layout, phase };\n}\n\n// ---------- Layout computation ----------\n\nfunction isUnfragmented(layout: PageLayout): boolean {\n return (\n layout.pages.length === 1 &&\n layout.pages[0].slots.every(\n (s) =>\n s.fragment === undefined &&\n s.tableFragment === undefined &&\n s.listFragment === undefined,\n )\n );\n}\n\nfunction computeLayout(\n root: HTMLElement,\n geometry: PageGeometry,\n topLevelCount: number,\n): PageLayout {\n const tops = collectTopLevelElements(root);\n if (tops.length === 0) return defaultPageLayout(topLevelCount);\n\n // `firstPageExtraTop` faz a pág 0 ter content height menor; usar uma função\n // permite recomputar quando empurramos novas páginas.\n const limitFor = (pageIndex: number) => contentHeight(geometry, pageIndex);\n const pages: PageEntry[] = [{ slots: [] }];\n let currentPage = pages[0];\n let limit = limitFor(0);\n let used = 0;\n\n const cap = Math.min(tops.length, topLevelCount);\n for (let i = 0; i < cap; i++) {\n const el = tops[i];\n const h = elTotalHeight(el);\n\n if (used + h <= limit) {\n currentPage.slots.push({ topLevelIndex: i });\n used += h;\n continue;\n }\n\n if (isFragmentable(el)) {\n const result = placeFragmentedBlock(el, i, pages, used, limitFor);\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = result.lastUsed;\n continue;\n }\n\n if (isTableTopLevel(el)) {\n const result = placeFragmentedTable(el, i, pages, used, limitFor);\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = result.lastUsed;\n continue;\n }\n\n if (isListTopLevel(el)) {\n const result = placeFragmentedList(el, i, pages, used, limitFor);\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = result.lastUsed;\n continue;\n }\n\n // Atomic top-level that doesn't fit\n if (currentPage.slots.length === 0) {\n // empty current page; place anyway (bleed if huge)\n currentPage.slots.push({ topLevelIndex: i });\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n } else {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n currentPage.slots.push({ topLevelIndex: i });\n used = h;\n }\n }\n\n // Strip trailing empty page if any\n if (pages.length > 1 && pages[pages.length - 1].slots.length === 0) pages.pop();\n\n return { pages };\n}\n\nfunction placeFragmentedBlock(\n el: HTMLElement,\n topLevelIndex: number,\n pages: PageEntry[],\n startUsed: number,\n limitFor: (pageIndex: number) => number,\n): { lastUsed: number } {\n let limit = limitFor(pages.length - 1);\n const totalChars = getBlockTextLength(el);\n if (totalChars === 0) {\n const h = elTotalHeight(el);\n let currentPage = pages[pages.length - 1];\n if (startUsed + h > limit && currentPage.slots.length > 0) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n startUsed = 0;\n }\n currentPage.slots.push({ topLevelIndex });\n return { lastUsed: startUsed + h };\n }\n\n // Measure every original line. Splitting only at line boundaries is what\n // makes fragmentation work correctly: when fragment K starts at an original\n // line boundary AND is rendered at the same width, its line wrapping matches\n // the original exactly, so our measured height predicts the rendered height.\n const lines = measureLines(el);\n if (lines.length === 0) {\n // Couldn't measure (no text nodes?) — place atomically as last resort.\n const h = elTotalHeight(el);\n let currentPage = pages[pages.length - 1];\n if (startUsed + h > limit && currentPage.slots.length > 0) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n startUsed = 0;\n }\n currentPage.slots.push({ topLevelIndex });\n return { lastUsed: startUsed + h };\n }\n\n let lineIdx = 0;\n let currentPage = pages[pages.length - 1];\n let used = startUsed;\n let fragIndex = 0;\n\n while (lineIdx < lines.length) {\n const available = Math.max(0, limit - used);\n if (available <= 0) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n continue;\n }\n\n // Greedy: include as many consecutive lines as fit. bestK is the last fitting line index.\n const startTop = lines[lineIdx].top;\n let bestK = -1;\n for (let k = lineIdx; k < lines.length; k++) {\n const h = lines[k].bottom - startTop;\n if (h <= available) bestK = k;\n else break;\n }\n\n if (bestK < 0) {\n // Not even one line fits in the remaining space.\n if (currentPage.slots.length === 0) {\n // Page is empty; force-place a single oversized line (bleed).\n bestK = lineIdx;\n } else {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n continue;\n }\n }\n\n const fragStart = lines[lineIdx].start;\n const fragEnd = bestK + 1 < lines.length ? lines[bestK + 1].start : totalChars;\n const fragHeight = lines[bestK].bottom - startTop;\n\n currentPage.slots.push({\n topLevelIndex,\n fragment: { index: fragIndex, start: fragStart, end: fragEnd },\n });\n used += fragHeight;\n fragIndex++;\n lineIdx = bestK + 1;\n\n if (lineIdx < lines.length) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n }\n }\n\n return { lastUsed: used };\n}\n\ninterface LineMetric {\n /** Char offset (within the block) of the first char on this line. */\n start: number;\n /** Viewport-y top of the line. */\n top: number;\n /** Viewport-y bottom of the line. */\n bottom: number;\n}\n\n/**\n * Walk every text node inside `el`, measuring each character's rect to detect\n * line boundaries. Linear in total character count.\n *\n * Memoized by `(offsetWidth, textContent)`: a block whose width and text\n * haven't changed (the common case during typing — only ONE block changes per\n * keystroke) skips the measurement entirely. This is the perf core of Sub-phase\n * 3.3's incremental repagination story.\n *\n * NOTE: cached `top`/`bottom` are viewport-absolute, but `placeFragmentedBlock`\n * only ever uses RELATIVE differences (`lines[k].bottom - lines[j].top`), which\n * are invariant to scroll/layout offsets — so cached values stay correct.\n */\nconst lineMetricsCache = new Map<string, LineMetric[]>();\nconst LINE_METRICS_CACHE_LIMIT = 200;\n\nfunction measureLines(el: HTMLElement): LineMetric[] {\n const text = el.textContent ?? \"\";\n const cacheKey = `${el.offsetWidth}|${text}`;\n const cached = lineMetricsCache.get(cacheKey);\n if (cached) {\n // LRU touch\n lineMetricsCache.delete(cacheKey);\n lineMetricsCache.set(cacheKey, cached);\n return cached;\n }\n\n const fresh = measureLinesUncached(el);\n lineMetricsCache.set(cacheKey, fresh);\n if (lineMetricsCache.size > LINE_METRICS_CACHE_LIMIT) {\n const oldest = lineMetricsCache.keys().next().value;\n if (oldest !== undefined) lineMetricsCache.delete(oldest);\n }\n return fresh;\n}\n\nfunction measureLinesUncached(el: HTMLElement): LineMetric[] {\n const range = document.createRange();\n const lines: LineMetric[] = [];\n\n // Walk text nodes AND image embeds — embeds count as 1 char in offset\n // arithmetic and contribute their bounding rect as a line (or part of one).\n const walker = document.createTreeWalker(\n el,\n NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT,\n blockBoundaryFilter(el),\n );\n let n: Node | null;\n let charOffset = 0;\n\n while ((n = walker.nextNode())) {\n if (n.nodeType === Node.TEXT_NODE) {\n const text = n.textContent ?? \"\";\n for (let i = 0; i < text.length; i++) {\n try {\n range.setStart(n, i);\n range.setEnd(n, i + 1);\n } catch {\n continue;\n }\n const rect = range.getBoundingClientRect();\n if (rect.width === 0 && rect.height === 0) continue;\n const last = lines[lines.length - 1];\n if (!last || rect.top >= last.bottom) {\n lines.push({ start: charOffset + i, top: rect.top, bottom: rect.bottom });\n } else {\n last.top = Math.min(last.top, rect.top);\n last.bottom = Math.max(last.bottom, rect.bottom);\n }\n }\n charOffset += text.length;\n continue;\n }\n if (\n n.nodeType === Node.ELEMENT_NODE &&\n (n as HTMLElement).dataset.embed === \"image\"\n ) {\n const rect = (n as HTMLElement).getBoundingClientRect();\n if (rect.height > 0) {\n const last = lines[lines.length - 1];\n if (!last || rect.top >= last.bottom) {\n lines.push({ start: charOffset, top: rect.top, bottom: rect.bottom });\n } else {\n last.top = Math.min(last.top, rect.top);\n last.bottom = Math.max(last.bottom, rect.bottom);\n }\n }\n charOffset += 1;\n }\n }\n return lines;\n}\n\n// ---------- DOM measurement primitives ----------\n\nfunction elTotalHeight(el: HTMLElement): number {\n const cs = getComputedStyle(el);\n const m = parseFloat(cs.marginTop || \"0\") + parseFloat(cs.marginBottom || \"0\");\n return el.offsetHeight + m;\n}\n\nfunction isFragmentable(el: HTMLElement): boolean {\n // Top-level fragmentable types: paragraph, heading, blockquote.\n // Tables fragment via `placeFragmentedTable` (row-level), not the line engine.\n const type = el.getAttribute(\"data-block-type\");\n if (type === \"paragraph\") return true;\n if (type === \"heading\") return true;\n if (type === \"blockquote\") return true;\n return false;\n}\n\n/**\n * The top-level for a table block is a `<div class=\"ed-table-wrap\">` wrapper —\n * the `data-block-type=\"table\"` attribute lives on the nested `<table>`.\n */\nfunction isTableTopLevel(el: HTMLElement): boolean {\n return el.querySelector(':scope > table[data-block-type=\"table\"]') !== null;\n}\n\ninterface PlaceFragmentedTableResult { lastUsed: number; }\n\n/**\n * Sub-phase 4.6 — split a table that doesn't fit on the current page across\n * pages at row boundaries.\n *\n * Constraints:\n * - A break between rows `r` and `r+1` is INVALID when any cell with\n * `rowSpan > 1` whose owner sits at row `r' <= r` extends into row `r+1`.\n * We compute this by walking each row's `<td>`s: a `rowSpan = N > 1` at row\n * `r` blocks the boundaries `(r, r+1), (r+1, r+2), … (r+N-2, r+N-1)`.\n *\n * - If no clean break fits the available height (e.g. a very tall span at the\n * top of the table), and the current page already has content, we move to\n * the next page and try again. If even an empty page can't fit a valid\n * prefix, we bleed the smallest legal prefix rather than loop forever.\n *\n * Heights come from `<tr>.getBoundingClientRect()` — these are measured against\n * the unfragmented render, but row layout is invariant under fragmentation as\n * long as the `<colgroup>` widths don't change (they don't), and as long as a\n * span isn't cut (which is exactly the constraint above).\n */\nfunction placeFragmentedTable(\n el: HTMLElement,\n topLevelIndex: number,\n pages: PageEntry[],\n startUsed: number,\n limitFor: (pageIndex: number) => number,\n): PlaceFragmentedTableResult {\n let limit = limitFor(pages.length - 1);\n const table = el.querySelector(':scope > table[data-block-type=\"table\"]') as HTMLTableElement | null;\n const tbody = table?.querySelector(':scope > tbody');\n const trs = tbody ? (Array.from(tbody.children) as HTMLTableRowElement[]) : [];\n if (trs.length === 0) {\n // Empty / no rows — fall back to atomic.\n const h = elTotalHeight(el);\n let currentPage = pages[pages.length - 1];\n if (startUsed + h > limit && currentPage.slots.length > 0) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n startUsed = 0;\n }\n currentPage.slots.push({ topLevelIndex });\n return { lastUsed: startUsed + h };\n }\n\n const rowHeights = trs.map((tr) => tr.getBoundingClientRect().height);\n\n // Invalid break boundaries — indices `k` for which the break between row `k`\n // and `k+1` is blocked by a rowspan crossing it.\n const invalid = new Set<number>();\n for (let r = 0; r < trs.length; r++) {\n const tds = Array.from(trs[r].children) as HTMLTableCellElement[];\n for (const td of tds) {\n const rs = td.rowSpan || 1;\n if (rs > 1) {\n for (let k = r; k <= r + rs - 2 && k < trs.length - 1; k++) {\n invalid.add(k);\n }\n }\n }\n }\n\n // Vertical padding/margin around the table proper, distributed conservatively\n // onto the FIRST fragment only — keeps subsequent fragments compact.\n const wrapHeight = elTotalHeight(el);\n const tableHeight = table ? table.getBoundingClientRect().height : 0;\n const chrome = Math.max(0, wrapHeight - tableHeight);\n\n let rowIdx = 0;\n let used = startUsed;\n let fragIndex = 0;\n let currentPage = pages[pages.length - 1];\n\n while (rowIdx < trs.length) {\n const overhead = fragIndex === 0 ? chrome : 0;\n const available = Math.max(0, limit - used - overhead);\n if (available <= 0) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n continue;\n }\n\n // Greedy: keep extending the run as long as height fits and we haven't\n // passed a valid break boundary. Track the LAST valid `bestEnd`.\n let bestEnd = -1;\n let accH = 0;\n for (let k = rowIdx; k < trs.length; k++) {\n accH += rowHeights[k];\n if (accH > available) break;\n if (k === trs.length - 1 || !invalid.has(k)) bestEnd = k + 1;\n }\n\n if (bestEnd < 0) {\n if (currentPage.slots.length === 0) {\n // Empty page yet still no valid prefix fits — find the smallest legal\n // prefix and bleed (better than an infinite loop).\n let k = rowIdx;\n while (k < trs.length - 1 && invalid.has(k)) k++;\n bestEnd = k + 1;\n } else {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n continue;\n }\n }\n\n let fragHeight = 0;\n for (let k = rowIdx; k < bestEnd; k++) fragHeight += rowHeights[k];\n if (fragIndex === 0) fragHeight += chrome;\n\n currentPage.slots.push({\n topLevelIndex,\n tableFragment: { index: fragIndex, rowStart: rowIdx, rowEnd: bestEnd },\n });\n used += fragHeight;\n fragIndex++;\n rowIdx = bestEnd;\n\n if (rowIdx < trs.length) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n }\n }\n\n return { lastUsed: used };\n}\n\n/**\n * A top-level for a list group is the `<ol>` or `<ul>` rendered by\n * `renderListTree`. Its direct `<li>` children are the level-0 entries of\n * the group; nested sub-lists live INSIDE those `<li>`s and travel with them.\n */\nfunction isListTopLevel(el: HTMLElement): boolean {\n if (el.tagName !== \"OL\" && el.tagName !== \"UL\") return false;\n return el.classList.contains(\"ed-list\");\n}\n\ninterface PlaceFragmentedListResult { lastUsed: number; }\n\n/**\n * Split a list group that doesn't fit on the current page across pages at\n * top-level `<li>` boundaries. Nested sub-lists stay attached to their parent\n * `<li>` (we never break inside a nested list — that's reserved for the rare\n * case where a single top-level item is itself taller than a full page, in\n * which case we bleed it).\n *\n * Heights come from `<li>.getBoundingClientRect()` measured against the\n * unfragmented render. They include the nested sub-list height when present.\n */\nfunction placeFragmentedList(\n el: HTMLElement,\n topLevelIndex: number,\n pages: PageEntry[],\n startUsed: number,\n limitFor: (pageIndex: number) => number,\n): PlaceFragmentedListResult {\n let limit = limitFor(pages.length - 1);\n\n // Direct <li> children of the top-level <ol>/<ul>. Filter strictly by\n // `.ed-listitem` class so any other DOM injected by the consumer (markers,\n // dividers) doesn't get counted as an item.\n const items: HTMLLIElement[] = [];\n for (const c of Array.from(el.children)) {\n if (c instanceof HTMLLIElement && c.classList.contains(\"ed-listitem\")) {\n items.push(c);\n }\n }\n\n if (items.length === 0) {\n const h = elTotalHeight(el);\n let currentPage = pages[pages.length - 1];\n if (startUsed + h > limit && currentPage.slots.length > 0) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n startUsed = 0;\n }\n currentPage.slots.push({ topLevelIndex });\n return { lastUsed: startUsed + h };\n }\n\n const heights = items.map((li) => elTotalHeight(li));\n // Vertical padding/margin contributed by the wrapping <ol>/<ul> itself\n // (margin-block + padding-block beyond the sum of item heights). We charge\n // this overhead only to the FIRST fragment's page so subsequent continuation\n // fragments don't double-count it.\n const sumHeights = heights.reduce((a, b) => a + b, 0);\n const wrapperOverhead = Math.max(0, elTotalHeight(el) - sumHeights);\n\n let i = 0;\n let currentPage = pages[pages.length - 1];\n let used = startUsed;\n let fragIndex = 0;\n\n while (i < items.length) {\n const available = Math.max(0, limit - used);\n // Greedy: include as many consecutive items as fit. bestK is the last\n // fitting item index.\n const isFirstFragment = fragIndex === 0;\n let bestK = -1;\n let runningH = isFirstFragment ? wrapperOverhead : 0;\n for (let k = i; k < items.length; k++) {\n runningH += heights[k];\n if (runningH <= available) bestK = k;\n else break;\n }\n\n if (bestK < 0) {\n // Not even one item fits in the remaining space.\n if (currentPage.slots.length === 0) {\n // Page is empty; force-place a single oversized item (bleed).\n bestK = i;\n } else {\n // Move to next page and retry.\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n continue;\n }\n }\n\n currentPage.slots.push({\n topLevelIndex,\n listFragment: { index: fragIndex, itemStart: i, itemEnd: bestK + 1 },\n });\n\n // Account for consumed height on the current page.\n let consumed = isFirstFragment ? wrapperOverhead : 0;\n for (let k = i; k <= bestK; k++) consumed += heights[k];\n used += consumed;\n\n i = bestK + 1;\n fragIndex++;\n if (i < items.length) {\n pages.push({ slots: [] });\n currentPage = pages[pages.length - 1];\n limit = limitFor(pages.length - 1);\n used = 0;\n }\n }\n\n return { lastUsed: used };\n}\n\nfunction collectTopLevelElements(root: HTMLElement): HTMLElement[] {\n // The root may be in one of three shapes:\n // - flat: root > top1, top2, ...\n // - paged simple: root > .ed-page > .ed-page-content > top1, top2, ...\n // - paged + fragments: same as above, but some \"tops\" are fragments of the\n // same block index. We don't expect to be called in\n // that state (caller guards on isUnfragmented), so\n // collecting direct children is fine.\n const pageContents = root.querySelectorAll<HTMLElement>(\":scope > .ed-page > .ed-page-content\");\n if (pageContents.length > 0) {\n const out: HTMLElement[] = [];\n pageContents.forEach((pc) => {\n Array.from(pc.children).forEach((c) => out.push(c as HTMLElement));\n });\n return out;\n }\n return Array.from(root.children) as HTMLElement[];\n}\n\n/**\n * Sum text-node lengths inside `el` plus 1 for each image embed, skipping any\n * descendant `[data-block-index]`. Mirrors the model's notion of \"length\".\n */\nfunction getBlockTextLength(el: HTMLElement): number {\n const walker = document.createTreeWalker(\n el,\n NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT,\n blockBoundaryFilter(el),\n );\n let n: Node | null;\n let sum = 0;\n while ((n = walker.nextNode())) {\n if (n.nodeType === Node.TEXT_NODE) {\n sum += (n.textContent ?? \"\").length;\n } else if (\n n.nodeType === Node.ELEMENT_NODE &&\n (n as HTMLElement).dataset.embed === \"image\"\n ) {\n sum += 1;\n }\n }\n return sum;\n}\n\nfunction blockBoundaryFilter(blockEl: HTMLElement): NodeFilter {\n return {\n acceptNode(n: Node) {\n let p: Node | null = n.parentNode;\n while (p && p !== blockEl) {\n if (p.nodeType === Node.ELEMENT_NODE) {\n const e = p as HTMLElement;\n if (e.dataset.blockIndex != null) return NodeFilter.FILTER_REJECT;\n }\n p = p.parentNode;\n }\n return NodeFilter.FILTER_ACCEPT;\n },\n };\n}\n\n// ---------- Equality helpers ----------\n\nfunction shallowArrayEqual(a: unknown[], b: unknown[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n return true;\n}\n\nfunction layoutsDeepEqual(a: PageLayout, b: PageLayout): boolean {\n if (a.pages.length !== b.pages.length) return false;\n for (let i = 0; i < a.pages.length; i++) {\n const sA = a.pages[i].slots;\n const sB = b.pages[i].slots;\n if (sA.length !== sB.length) return false;\n for (let j = 0; j < sA.length; j++) {\n if (sA[j].topLevelIndex !== sB[j].topLevelIndex) return false;\n const fA = sA[j].fragment;\n const fB = sB[j].fragment;\n if (fA || fB) {\n if (!fA || !fB) return false;\n if (fA.index !== fB.index || fA.start !== fB.start || fA.end !== fB.end) return false;\n }\n const tA = sA[j].tableFragment;\n const tB = sB[j].tableFragment;\n if (tA || tB) {\n if (!tA || !tB) return false;\n if (tA.index !== tB.index || tA.rowStart !== tB.rowStart || tA.rowEnd !== tB.rowEnd) {\n return false;\n }\n }\n const lA = sA[j].listFragment;\n const lB = sB[j].listFragment;\n if (lA || lB) {\n if (!lA || !lB) return false;\n if (lA.index !== lB.index || lA.itemStart !== lB.itemStart || lA.itemEnd !== lB.itemEnd) {\n return false;\n }\n }\n }\n }\n return true;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { usePageSettings } from \"./usePageSettings\";\nimport {\n EditorDocument,\n EditorHistory,\n collapsedSelection,\n dedentList as cmdDedentList,\n deleteTable as cmdDeleteTable,\n deleteTableColumn as cmdDeleteColumn,\n deleteTableRow as cmdDeleteRow,\n insertImage as cmdInsertImage,\n mergeDown as cmdMergeDown,\n mergeRight as cmdMergeRight,\n mergeSelection as cmdMergeSelection,\n moveEmbedAnchor as cmdMoveEmbedAnchor,\n setBlockAttrAtIndex as cmdSetBlockAttrAtIndex,\n setColumnWidth as cmdSetColumnWidth,\n setImageAttrs as cmdSetImageAttrs,\n splitCell as cmdSplitCell,\n tableRectSelection,\n getMarksInRange,\n indentList as cmdIndentList,\n insertAnswerLines as cmdInsertAnswerLines,\n insertTable as cmdInsertTable,\n insertTableColumn as cmdInsertColumn,\n insertTableRow as cmdInsertRow,\n isImageEmbed,\n isMarkUniformInRange,\n moveToNextCell as cmdMoveNextCell,\n moveToPrevCell as cmdMovePrevCell,\n orderedRange,\n removeMark as cmdRemoveMark,\n setBlockAttr as cmdSetBlockAttr,\n setCellAttr as cmdSetCellAttr,\n setBlockType as cmdSetBlockType,\n setMark as cmdSetMark,\n splitListItem as cmdSplitListItem,\n tableLocationOf,\n toggleList as cmdToggleList,\n toggleMark as cmdToggleMark,\n type AlignValue,\n type BlockAttrs,\n type AnswerLineSpacing,\n type BlockType,\n type TableBorderPreset,\n type CommandContext,\n type DeltaOp,\n type EmbedLoc,\n type ImageEmbed,\n type ListKind,\n type MarkAttrs,\n type MarkName,\n type PageSettings,\n type SerializedDocument,\n type Selection,\n type TableLocation,\n type TableRect,\n} from \"@sofereditor/core\";\n\nexport interface UseEditorOptions {\n document?: EditorDocument;\n /**\n * Quando definido, `insertImageFromFile` chama esta função pra obter a URL\n * final em vez de embutir o arquivo como data URL base64 no Y.Doc.\n *\n * Use isto quando o app tem storage externo (S3, Azure Blob, etc.) e não quer\n * inflar o documento com imagens base64. O componente `<Editor>` propaga o\n * mesmo upload para paste/drop/file picker.\n */\n uploadImage?: (file: File) => Promise<string>;\n}\n\nexport type PendingMarks = Partial<Record<MarkName, MarkAttrs[MarkName] | null>>;\n\nexport interface LinkRequest {\n initialHref: string;\n resolve: (href: string | null) => void;\n /** Model selection captured when the link was requested (bug #6). */\n selection: Selection;\n}\n\nexport interface PageConfigRequest {\n initial: PageSettings;\n resolve: (applied: boolean) => void;\n}\n\nexport type CaptionAlign = \"left\" | \"center\" | \"right\";\n\nexport interface ImageCaptionResult {\n caption: string;\n align: CaptionAlign;\n}\n\nexport interface ImageCaptionRequest {\n initialCaption: string;\n initialAlign: CaptionAlign;\n /**\n * Resolves with the new caption + alignment, or null on cancel. An empty\n * `caption` string means \"remove caption\" (align is ignored in that case).\n */\n resolve: (result: ImageCaptionResult | null) => void;\n}\n\nexport interface UseEditorResult {\n doc: EditorDocument;\n history: EditorHistory;\n /** Snapshot of the model, re-computed on every Y.js update. */\n snapshot: SerializedDocument;\n /** Current model selection. Use `setSelection` to move the caret. */\n selection: Selection;\n setSelection: (sel: Selection) => void;\n /** Stable getter — commands read this to know where the caret is. */\n getSelection: () => Selection;\n\n // ---- Mark API (added in Sub-phase 2.1) ----\n isMarkActive: (name: MarkName, value?: MarkAttrs[MarkName]) => boolean;\n getActiveMarks: () => Partial<Record<MarkName, MarkAttrs[MarkName] | \"mixed\">>;\n toggleMark: (name: MarkName, value?: MarkAttrs[MarkName]) => void;\n setMark: (name: MarkName, value: MarkAttrs[MarkName]) => void;\n removeMark: (name: MarkName) => void;\n\n // ---- Block API (added in Sub-phase 2.2) ----\n /** Returns the type of the focus block (or \"mixed\" when the selection covers heterogeneous blocks). */\n getBlockType: () => BlockType | \"mixed\";\n /** Returns one block attribute at the focus block, or \"mixed\" when not uniform across the selection. */\n getBlockAttr: <K extends keyof BlockAttrs>(key: K) => BlockAttrs[K] | \"mixed\" | undefined;\n setBlockType: (type: BlockType, attrs?: BlockAttrs) => void;\n setBlockAttr: <K extends keyof BlockAttrs>(key: K, value: BlockAttrs[K] | null) => void;\n setAlign: (value: AlignValue) => void;\n getAlign: () => AlignValue | \"mixed\" | undefined;\n /** Cor de fundo das células selecionadas (rect) ou da célula focada. `null` remove. No-op fora de tabela. */\n setCellBackground: (color: string | null) => void;\n /** Cor de fundo da célula focada; undefined fora de tabela ou sem cor. */\n getCellBackground: () => string | undefined;\n /** Onde as linhas da grade da tabela focada aparecem. No-op fora de tabela. */\n setTableBorderPreset: (preset: TableBorderPreset) => void;\n /** Preset da tabela focada; \"all\" fora de tabela ou quando ausente. */\n getTableBorderPreset: () => TableBorderPreset;\n /** Cor das linhas da grade da tabela focada. `null` restaura o padrão. No-op fora de tabela. */\n setTableBorderColor: (color: string | null) => void;\n /** Cor da tabela focada; undefined fora de tabela ou quando usa o padrão. */\n getTableBorderColor: () => string | undefined;\n\n // ---- List API (added in Sub-phase 2.3) ----\n isListActive: (kind: ListKind) => boolean;\n toggleList: (kind: ListKind) => void;\n indentList: () => void;\n dedentList: () => void;\n /** Returns true when handled (current block is a listItem); false to fall back to insertParagraph. */\n splitListItem: () => boolean;\n\n /** Marks queued for the next `insertText` (e.g. user pressed Cmd+B with a collapsed caret). */\n pendingMarks: PendingMarks;\n /** Consumed by the input layer right before calling `insertText`. */\n consumePendingMarks: () => PendingMarks | undefined;\n\n // ---- Link dialog (Polish iteration) ----\n linkRequest: LinkRequest | null;\n /** Open the link dialog; resolves with the entered href, empty string to remove, or null on cancel. */\n requestLink: (initialHref?: string) => Promise<string | null>;\n /** Called by the LinkDialog itself when the user submits or cancels. */\n resolveLinkRequest: (href: string | null) => void;\n\n // ---- Page settings (Fase 9.6) ----\n /** Reactive page settings snapshot (re-renders when the Y.Doc docSettings changes). */\n pageSettings: PageSettings;\n /** Merge a partial PageSettings into the Y.Doc. Not undoable. */\n setPageSettings: (partial: Partial<PageSettings>) => void;\n /** Page-config dialog request (null when closed). */\n pageConfigRequest: PageConfigRequest | null;\n /** Open the page-config dialog; resolves true on apply, false on cancel. */\n requestPageConfig: () => Promise<boolean>;\n /** Resolver called by `<PageConfigDialog>` on apply/cancel. */\n resolvePageConfigRequest: (applied: boolean) => void;\n\n // ---- Image caption (Fase 9.6+) ----\n imageCaptionRequest: ImageCaptionRequest | null;\n /** Open the image-caption dialog with the current caption + alignment pre-filled. */\n requestImageCaption: (\n initialCaption?: string,\n initialAlign?: CaptionAlign,\n ) => Promise<ImageCaptionResult | null>;\n /** Resolver called by `<ImageCaptionDialog>` on apply/cancel. */\n resolveImageCaptionRequest: (result: ImageCaptionResult | null) => void;\n\n // ---- Tables (Phase 4) ----\n /** True iff the focus position lies inside a table cell. */\n isInTable: () => boolean;\n /** Returns `{blockIndex, row, col}` for the focus position, or null when outside a table. */\n getTableLocation: () => TableLocation | null;\n /** Insere `count` linhas de resposta pautadas depois do bloco focado. */\n insertAnswerLines: (count: number, spacing: AnswerLineSpacing) => void;\n insertTable: (rows: number, cols: number) => void;\n /** Removes the table at `blockIndex`. Defaults to the current focus table. */\n deleteTable: (blockIndex?: number) => void;\n insertRowAbove: () => void;\n insertRowBelow: () => void;\n deleteCurrentRow: () => void;\n insertColumnLeft: () => void;\n insertColumnRight: () => void;\n deleteCurrentColumn: () => void;\n moveToNextCell: () => void;\n moveToPrevCell: () => void;\n mergeRight: () => boolean;\n mergeDown: () => boolean;\n splitCell: () => boolean;\n setColumnWidth: (blockIndex: number, col: number, widthPx: number) => void;\n /** Returns the table rectangle if the current selection is a multi-cell range, else null. */\n getTableRect: () => TableRect | null;\n /** True when there's a rectangular table-cell selection. */\n hasTableRectSelection: () => boolean;\n /** Merge every cell in the rectangular selection. Returns true on success. */\n mergeSelection: () => boolean;\n\n // ---- Inline images (Fase 5) ----\n insertImage: (embed: ImageEmbed) => void;\n setImageAttrs: (\n blockIndex: number,\n offset: number,\n partial: Partial<ImageEmbed>,\n cellIndex?: number,\n newOffset?: number,\n ) => void;\n /**\n * Move a floating image embed from one anchor to another (re-anchor across\n * blocks/pages) in a single transaction. No-op for inline embeds.\n */\n moveEmbedAnchor: (\n from: EmbedLoc,\n to: EmbedLoc,\n newOffsetX: number,\n newOffsetY: number,\n ) => void;\n /** Read a File (image) and insert it inline at the caret as a data-URL embed. */\n insertImageFromFile: (file: File) => Promise<void>;\n /**\n * Returns the embed currently selected (single 1-char range over an image),\n * or null when no embed is solely selected.\n */\n getSelectedEmbed: () =>\n | { blockIndex: number; offset: number; cellIndex?: number; embed: ImageEmbed }\n | null;\n}\n\n/** Max display width when inserting an image. Larger sources are scaled keeping aspect ratio. */\nconst MAX_INSERT_WIDTH = 600;\n\nexport function useEditor(opts: UseEditorOptions = {}): UseEditorResult {\n const doc = useMemo(() => opts.document ?? new EditorDocument(), [opts.document]);\n const history = useMemo(() => new EditorHistory(doc), [doc]);\n\n const [snapshot, setSnapshot] = useState<SerializedDocument>(() => doc.toJSON());\n const [selection, setSelectionState] = useState<Selection>(() =>\n collapsedSelection({ blockIndex: 0, offset: 0 }),\n );\n const selectionRef = useRef(selection);\n selectionRef.current = selection;\n\n // pendingMarks lives on a ref so the beforeinput handler reads the latest value\n // without re-binding listeners on every render. The state copy exists so the\n // Toolbar can render a \"pressed\" hint when a mark is armed at a collapsed caret.\n const pendingMarksRef = useRef<PendingMarks>({});\n const [pendingMarks, setPendingMarksState] = useState<PendingMarks>({});\n\n const setPendingMarks = useCallback((next: PendingMarks) => {\n pendingMarksRef.current = next;\n setPendingMarksState(next);\n }, []);\n\n useEffect(() => {\n // Coalesce snapshot recomputation: `afterTransaction` fires per Y.js\n // transaction, which means once per keystroke for normal typing — but on\n // paste / multi-op commands it can fire N times in a microtask burst.\n // `toJSON()` is expensive for docs with embedded images (each call deep-\n // clones every block's delta, including base64 image src). Coalescing\n // into rAF guarantees at most one recompute per animation frame regardless\n // of how many transactions fire underneath. A pending flag avoids\n // scheduling multiple rAFs.\n let scheduled = false;\n let cancelled = false;\n let frame = 0 as number | ReturnType<typeof requestAnimationFrame>;\n const flush = () => {\n scheduled = false;\n if (cancelled) return;\n setSnapshot(doc.toJSON());\n };\n const schedule = () => {\n if (scheduled) return;\n scheduled = true;\n // Use rAF when available (browser), fall back to microtask in jsdom/Node.\n if (typeof requestAnimationFrame === \"function\") {\n frame = requestAnimationFrame(flush);\n } else {\n queueMicrotask(flush);\n }\n };\n doc.ydoc.on(\"afterTransaction\", schedule);\n return () => {\n cancelled = true;\n if (\n scheduled &&\n typeof requestAnimationFrame === \"function\" &&\n typeof cancelAnimationFrame === \"function\"\n ) {\n cancelAnimationFrame(frame as number);\n }\n doc.ydoc.off(\"afterTransaction\", schedule);\n };\n }, [doc]);\n\n const getSelection = useCallback(() => selectionRef.current, []);\n const setSelection = useCallback(\n (sel: Selection) => {\n const prev = selectionRef.current;\n selectionRef.current = sel;\n setSelectionState(sel);\n // Any caret movement that isn't a direct typing follow-up clears the queue.\n if (\n Object.keys(pendingMarksRef.current).length > 0 &&\n (prev.focus.blockIndex !== sel.focus.blockIndex || prev.focus.offset !== sel.focus.offset)\n ) {\n // Heuristic: typing advances the caret by exactly 1; everything else clears.\n const advancedByOne =\n prev.focus.blockIndex === sel.focus.blockIndex &&\n sel.focus.offset === prev.focus.offset + 1;\n if (!advancedByOne) {\n pendingMarksRef.current = {};\n setPendingMarksState({});\n }\n }\n },\n [],\n );\n\n const ctxRef = useRef<CommandContext>({ doc, getSelection, setSelection });\n ctxRef.current = { doc, getSelection, setSelection };\n\n const consumePendingMarks = useCallback((): PendingMarks | undefined => {\n const current = pendingMarksRef.current;\n if (Object.keys(current).length === 0) return undefined;\n pendingMarksRef.current = {};\n setPendingMarksState({});\n return current;\n }, []);\n\n const isMarkActive = useCallback(\n (name: MarkName, value?: MarkAttrs[MarkName]): boolean => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n if (start.blockIndex === end.blockIndex && start.offset === end.offset) {\n // Collapsed: union of pending and ambient (mark of the char immediately before caret).\n const pending = pendingMarksRef.current[name];\n if (pending !== undefined) {\n if (pending === null) return false;\n return value === undefined ? true : sameValue(pending, value);\n }\n const yText = doc.getBlockText(start.blockIndex);\n if (!yText || start.offset === 0) return false;\n return isMarkUniformInRange(yText, start.offset - 1, start.offset, name, value);\n }\n if (start.blockIndex !== end.blockIndex) {\n // Multi-block: active only if uniformly active on every covered slice.\n for (let i = start.blockIndex; i <= end.blockIndex; i++) {\n const yText = doc.getBlockText(i);\n if (!yText) return false;\n const s = i === start.blockIndex ? start.offset : 0;\n const e = i === end.blockIndex ? end.offset : yText.length;\n if (s >= e) continue;\n if (!isMarkUniformInRange(yText, s, e, name, value)) return false;\n }\n return true;\n }\n const yText = doc.getBlockText(start.blockIndex);\n if (!yText) return false;\n return isMarkUniformInRange(yText, start.offset, end.offset, name, value);\n },\n [doc],\n );\n\n const getActiveMarks = useCallback(() => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n if (start.blockIndex !== end.blockIndex) {\n // For Sub-phase 2.1 we conservatively report empty across multi-block selections.\n return {};\n }\n const yText = doc.getBlockText(start.blockIndex);\n if (!yText) return {};\n if (start.offset === end.offset) {\n if (start.offset === 0) return {};\n return getMarksInRange(yText, start.offset - 1, start.offset);\n }\n return getMarksInRange(yText, start.offset, end.offset);\n }, [doc]);\n\n const toggleMark = useCallback(\n (name: MarkName, value?: MarkAttrs[MarkName]) => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;\n if (isCollapsed) {\n // Queue for next insert.\n const next: PendingMarks = { ...pendingMarksRef.current };\n const currentlyActive = isMarkActive(name, value);\n if (currentlyActive) {\n next[name] = null;\n } else {\n next[name] = value ?? (booleanMarks.has(name) ? true : null);\n }\n setPendingMarks(next);\n return;\n }\n cmdToggleMark(ctxRef.current, name, value);\n },\n [isMarkActive, setPendingMarks],\n );\n\n const setMark = useCallback(\n (name: MarkName, value: MarkAttrs[MarkName]) => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;\n if (isCollapsed) {\n setPendingMarks({ ...pendingMarksRef.current, [name]: value });\n return;\n }\n cmdSetMark(ctxRef.current, name, value);\n },\n [setPendingMarks],\n );\n\n const removeMark = useCallback(\n (name: MarkName) => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;\n if (isCollapsed) {\n setPendingMarks({ ...pendingMarksRef.current, [name]: null });\n return;\n }\n cmdRemoveMark(ctxRef.current, name);\n },\n [setPendingMarks],\n );\n\n const getBlockType = useCallback((): BlockType | \"mixed\" => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n const first = doc.getBlockType(start.blockIndex);\n if (first === undefined) return \"paragraph\";\n for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {\n if (doc.getBlockType(i) !== first) return \"mixed\";\n }\n return first;\n }, [doc]);\n\n const getBlockAttr = useCallback(\n <K extends keyof BlockAttrs>(key: K): BlockAttrs[K] | \"mixed\" | undefined => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n const first = doc.getBlockAttrs(start.blockIndex)[key];\n for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {\n const next = doc.getBlockAttrs(i)[key];\n if (next !== first) return \"mixed\";\n }\n return first;\n },\n [doc],\n );\n\n const setBlockType = useCallback((type: BlockType, attrs?: BlockAttrs) => {\n cmdSetBlockType(ctxRef.current, type, attrs);\n }, []);\n\n const setBlockAttr = useCallback(\n <K extends keyof BlockAttrs>(key: K, value: BlockAttrs[K] | null) => {\n cmdSetBlockAttr(ctxRef.current, key, value);\n },\n [],\n );\n\n const setAlign = useCallback((value: AlignValue) => {\n const sel = selectionRef.current;\n // Route on focus only: setCellAttr keys off sel.focus.cellIndex internally\n // and returns early unless the focus position is inside a table cell.\n const inCell = sel.focus.cellIndex != null;\n if (inCell) cmdSetCellAttr(ctxRef.current, \"align\", value);\n else cmdSetBlockAttr(ctxRef.current, \"align\", value);\n }, []);\n\n const getAlign = useCallback((): AlignValue | \"mixed\" | undefined => {\n const sel = selectionRef.current;\n if (sel.focus.cellIndex != null && doc.isTable(sel.focus.blockIndex)) {\n // Cell path: single focused-cell read (multi-cell mixed-state is out of scope).\n return doc.getCellAttrs(sel.focus.blockIndex, sel.focus.cellIndex).align;\n }\n // Block path: delegate to getBlockAttr so multi-block selections return \"mixed\".\n return getBlockAttr(\"align\");\n }, [doc, getBlockAttr]);\n\n const setCellBackground = useCallback((color: string | null) => {\n // setCellAttr keys off sel.focus.cellIndex internally: applies to the\n // rect selection (or the focused cell) and no-ops outside a table.\n cmdSetCellAttr(ctxRef.current, \"bgColor\", color);\n }, []);\n\n const getCellBackground = useCallback((): string | undefined => {\n const sel = selectionRef.current;\n if (sel.focus.cellIndex == null || !doc.isTable(sel.focus.blockIndex)) return undefined;\n // Single focused-cell read, like getAlign (multi-cell mixed-state out of scope).\n return doc.getCellAttrs(sel.focus.blockIndex, sel.focus.cellIndex).bgColor;\n }, [doc]);\n\n const setTableBorderPreset = useCallback((preset: TableBorderPreset) => {\n const sel = selectionRef.current;\n if (!doc.isTable(sel.focus.blockIndex)) return;\n // setBlockAttr é inerte com o caret dentro de uma célula — que é sempre o\n // caso aqui. Por isso a escrita é por índice de bloco.\n cmdSetBlockAttrAtIndex(ctxRef.current, sel.focus.blockIndex, \"borderPreset\", preset);\n }, [doc]);\n\n const getTableBorderPreset = useCallback((): TableBorderPreset => {\n const sel = selectionRef.current;\n if (!doc.isTable(sel.focus.blockIndex)) return \"all\";\n return doc.getBlockAttrs(sel.focus.blockIndex).borderPreset ?? \"all\";\n }, [doc]);\n\n const setTableBorderColor = useCallback((color: string | null) => {\n const sel = selectionRef.current;\n if (!doc.isTable(sel.focus.blockIndex)) return;\n cmdSetBlockAttrAtIndex(ctxRef.current, sel.focus.blockIndex, \"borderColor\", color);\n }, [doc]);\n\n const getTableBorderColor = useCallback((): string | undefined => {\n const sel = selectionRef.current;\n if (!doc.isTable(sel.focus.blockIndex)) return undefined;\n return doc.getBlockAttrs(sel.focus.blockIndex).borderColor;\n }, [doc]);\n\n const isListActive = useCallback(\n (kind: ListKind): boolean => {\n const sel = selectionRef.current;\n const { start, end } = orderedRange(sel);\n for (let i = start.blockIndex; i <= end.blockIndex; i++) {\n if (doc.getBlockType(i) !== \"listItem\") return false;\n if (doc.getBlockAttrs(i).listKind !== kind) return false;\n }\n return true;\n },\n [doc],\n );\n\n const toggleList = useCallback((kind: ListKind) => {\n cmdToggleList(ctxRef.current, kind);\n }, []);\n const indentList = useCallback(() => {\n cmdIndentList(ctxRef.current);\n }, []);\n const dedentList = useCallback(() => {\n cmdDedentList(ctxRef.current);\n }, []);\n const splitListItem = useCallback((): boolean => {\n return cmdSplitListItem(ctxRef.current);\n }, []);\n\n // ---- Tables ----\n const isInTable = useCallback((): boolean => {\n return selectionRef.current.focus.cellIndex != null;\n }, []);\n const getTableLocation = useCallback((): TableLocation | null => {\n return tableLocationOf(doc, selectionRef.current.focus);\n }, [doc]);\n const insertTable = useCallback((rows: number, cols: number) => {\n cmdInsertTable(ctxRef.current, rows, cols);\n }, []);\n const insertAnswerLines = useCallback((count: number, spacing: AnswerLineSpacing) => {\n cmdInsertAnswerLines(ctxRef.current, count, spacing);\n }, []);\n const deleteTable = useCallback((blockIndex?: number) => {\n const idx = blockIndex ?? selectionRef.current.focus.blockIndex;\n cmdDeleteTable(ctxRef.current, idx);\n }, []);\n const insertRowAbove = useCallback(() => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return;\n cmdInsertRow(ctxRef.current, loc.blockIndex, loc.row, \"before\");\n }, [doc]);\n const insertRowBelow = useCallback(() => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return;\n cmdInsertRow(ctxRef.current, loc.blockIndex, loc.row, \"after\");\n }, [doc]);\n const deleteCurrentRow = useCallback(() => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return;\n cmdDeleteRow(ctxRef.current, loc.blockIndex, loc.row);\n }, [doc]);\n const insertColumnLeft = useCallback(() => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return;\n cmdInsertColumn(ctxRef.current, loc.blockIndex, loc.col, \"before\");\n }, [doc]);\n const insertColumnRight = useCallback(() => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return;\n cmdInsertColumn(ctxRef.current, loc.blockIndex, loc.col, \"after\");\n }, [doc]);\n const deleteCurrentColumn = useCallback(() => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return;\n cmdDeleteColumn(ctxRef.current, loc.blockIndex, loc.col);\n }, [doc]);\n const moveToNextCell = useCallback(() => {\n cmdMoveNextCell(ctxRef.current);\n }, []);\n const moveToPrevCell = useCallback(() => {\n cmdMovePrevCell(ctxRef.current);\n }, []);\n const mergeRight = useCallback((): boolean => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return false;\n return cmdMergeRight(ctxRef.current, loc.blockIndex, loc.row, loc.col);\n }, [doc]);\n const mergeDown = useCallback((): boolean => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return false;\n return cmdMergeDown(ctxRef.current, loc.blockIndex, loc.row, loc.col);\n }, [doc]);\n const splitCell = useCallback((): boolean => {\n const loc = tableLocationOf(doc, selectionRef.current.focus);\n if (!loc) return false;\n return cmdSplitCell(ctxRef.current, loc.blockIndex, loc.row, loc.col);\n }, [doc]);\n const setColumnWidth = useCallback(\n (blockIndex: number, col: number, widthPx: number) => {\n cmdSetColumnWidth(ctxRef.current, blockIndex, col, widthPx);\n },\n [],\n );\n const getTableRect = useCallback(\n () => tableRectSelection(doc, selectionRef.current),\n [doc],\n );\n const hasTableRectSelection = useCallback((): boolean => {\n return tableRectSelection(doc, selectionRef.current) !== null;\n }, [doc]);\n const mergeSelection = useCallback((): boolean => {\n return cmdMergeSelection(ctxRef.current);\n }, []);\n\n // ---- Inline images ----\n const insertImage = useCallback((embed: ImageEmbed) => {\n cmdInsertImage(ctxRef.current, embed);\n }, []);\n const setImageAttrs = useCallback(\n (\n blockIndex: number,\n offset: number,\n partial: Partial<ImageEmbed>,\n cellIndex?: number,\n newOffset?: number,\n ) => {\n cmdSetImageAttrs(ctxRef.current, blockIndex, offset, partial, cellIndex, newOffset);\n },\n [],\n );\n const moveEmbedAnchor = useCallback(\n (from: EmbedLoc, to: EmbedLoc, newOffsetX: number, newOffsetY: number) => {\n cmdMoveEmbedAnchor(ctxRef.current, from, to, newOffsetX, newOffsetY);\n },\n [],\n );\n const uploadImageRef = useRef(opts.uploadImage);\n uploadImageRef.current = opts.uploadImage;\n const insertImageFromFile = useCallback(async (file: File): Promise<void> => {\n if (!file.type.startsWith(\"image/\")) return;\n // Lê dimensões a partir de um dataUrl temporário em ambos os caminhos\n // (lê o arquivo só uma vez; o uploadImage decide se persiste essa data\n // ou faz upload pra um storage externo).\n const dataUrl = await readAsDataURL(file);\n const dims = await readImageDimensions(dataUrl);\n let w = dims.width;\n let h = dims.height;\n if (w > MAX_INSERT_WIDTH) {\n h = Math.round((h * MAX_INSERT_WIDTH) / w);\n w = MAX_INSERT_WIDTH;\n }\n const upload = uploadImageRef.current;\n const src = upload ? await upload(file) : dataUrl;\n cmdInsertImage(ctxRef.current, { type: \"image\", src, width: w, height: h });\n }, []);\n const getSelectedEmbed = useCallback(() => {\n const sel = selectionRef.current;\n if (sel.anchor.blockIndex !== sel.focus.blockIndex) return null;\n if ((sel.anchor.cellIndex ?? -1) !== (sel.focus.cellIndex ?? -1)) return null;\n const a = sel.anchor.offset;\n const b = sel.focus.offset;\n if (Math.abs(a - b) !== 1) return null;\n const start = Math.min(a, b);\n const yText = doc.textAt(sel.anchor.blockIndex, sel.anchor.cellIndex);\n if (!yText) return null;\n const delta = yText.toDelta() as DeltaOp[];\n let cursor = 0;\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n cursor += op.insert.length;\n continue;\n }\n if (cursor === start && isImageEmbed(op.insert)) {\n return {\n blockIndex: sel.anchor.blockIndex,\n cellIndex: sel.anchor.cellIndex,\n offset: start,\n embed: op.insert,\n };\n }\n cursor += 1;\n }\n return null;\n }, [doc]);\n\n const [linkRequest, setLinkRequest] = useState<LinkRequest | null>(null);\n const linkRequestRef = useRef<LinkRequest | null>(null);\n const requestLink = useCallback((initialHref = \"\"): Promise<string | null> => {\n return new Promise((resolve) => {\n // Capture the model selection NOW (bug #6): the modal round-trip can\n // collapse it (the editor refocuses on close → selectionchange overwrites\n // the model), and the consumer applies the link mark AFTER the modal —\n // a no-op on a collapsed selection. We restore it on resolve.\n const req: LinkRequest = { initialHref, resolve, selection: selectionRef.current };\n linkRequestRef.current = req;\n setLinkRequest(req);\n });\n }, []);\n const resolveLinkRequest = useCallback(\n (href: string | null) => {\n const req = linkRequestRef.current;\n linkRequestRef.current = null;\n setLinkRequest(null);\n if (req) {\n // Restore the captured selection so the consumer's setMark applies to\n // the originally-selected text even if the modal collapsed it.\n setSelection(req.selection);\n req.resolve(href);\n }\n },\n [setSelection],\n );\n\n // ---- Page settings ----\n const pageSettings = usePageSettings(doc);\n const setPageSettings = useCallback(\n (partial: Partial<PageSettings>) => {\n doc.setPageSettings(partial);\n },\n [doc],\n );\n const [pageConfigRequest, setPageConfigRequest] = useState<PageConfigRequest | null>(null);\n const requestPageConfig = useCallback((): Promise<boolean> => {\n return new Promise((resolve) => {\n setPageConfigRequest({ initial: doc.getPageSettings(), resolve });\n });\n }, [doc]);\n const resolvePageConfigRequest = useCallback((applied: boolean) => {\n setPageConfigRequest((prev) => {\n if (prev) prev.resolve(applied);\n return null;\n });\n }, []);\n\n // ---- Image caption ----\n const [imageCaptionRequest, setImageCaptionRequest] =\n useState<ImageCaptionRequest | null>(null);\n const requestImageCaption = useCallback(\n (initialCaption = \"\", initialAlign: CaptionAlign = \"center\"): Promise<ImageCaptionResult | null> => {\n return new Promise((resolve) => {\n setImageCaptionRequest({ initialCaption, initialAlign, resolve });\n });\n },\n [],\n );\n const resolveImageCaptionRequest = useCallback((result: ImageCaptionResult | null) => {\n setImageCaptionRequest((prev) => {\n if (prev) prev.resolve(result);\n return null;\n });\n }, []);\n\n return {\n doc,\n history,\n snapshot,\n selection,\n setSelection,\n getSelection,\n isMarkActive,\n getActiveMarks,\n toggleMark,\n setMark,\n removeMark,\n pendingMarks,\n consumePendingMarks,\n getBlockType,\n getBlockAttr,\n setBlockType,\n setBlockAttr,\n setAlign,\n getAlign,\n setCellBackground,\n getCellBackground,\n setTableBorderPreset,\n getTableBorderPreset,\n setTableBorderColor,\n getTableBorderColor,\n isListActive,\n toggleList,\n indentList,\n dedentList,\n splitListItem,\n linkRequest,\n requestLink,\n resolveLinkRequest,\n isInTable,\n getTableLocation,\n insertAnswerLines,\n insertTable,\n deleteTable,\n insertRowAbove,\n insertRowBelow,\n deleteCurrentRow,\n insertColumnLeft,\n insertColumnRight,\n deleteCurrentColumn,\n moveToNextCell,\n moveToPrevCell,\n mergeRight,\n mergeDown,\n splitCell,\n setColumnWidth,\n getTableRect,\n hasTableRectSelection,\n mergeSelection,\n insertImage,\n setImageAttrs,\n moveEmbedAnchor,\n insertImageFromFile,\n getSelectedEmbed,\n pageSettings,\n setPageSettings,\n pageConfigRequest,\n requestPageConfig,\n resolvePageConfigRequest,\n imageCaptionRequest,\n requestImageCaption,\n resolveImageCaptionRequest,\n };\n}\n\nfunction readAsDataURL(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onerror = () => reject(reader.error ?? new Error(\"FileReader error\"));\n reader.onload = () => resolve(reader.result as string);\n reader.readAsDataURL(file);\n });\n}\n\nfunction readImageDimensions(src: string): Promise<{ width: number; height: number }> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onerror = () => reject(new Error(\"image load failed\"));\n img.onload = () => resolve({ width: img.naturalWidth, height: img.naturalHeight });\n img.src = src;\n });\n}\n\nconst booleanMarks: Set<MarkName> = new Set([\"bold\", \"italic\", \"underline\", \"strike\"]);\n\nfunction sameValue(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a === \"object\" && a && b && typeof b === \"object\") {\n const ak = Object.keys(a);\n const bk = Object.keys(b);\n if (ak.length !== bk.length) return false;\n return ak.every((k) => (a as Record<string, unknown>)[k] === (b as Record<string, unknown>)[k]);\n }\n return false;\n}\n","import { useCallback, useRef, useSyncExternalStore } from \"react\";\nimport type { EditorDocument, PageSettings } from \"@sofereditor/core\";\n\n/**\n * Reactive snapshot of an `EditorDocument`'s page settings. Re-renders the\n * component when `docSettings` changes (either locally via `setPageSettings`\n * or remotely via Y.js sync).\n *\n * Caches the snapshot reference to satisfy `useSyncExternalStore`'s stable-\n * identity requirement — `getPageSettings` returns a fresh object each call,\n * which would loop the store forever without this caching.\n */\nexport function usePageSettings(doc: EditorDocument): PageSettings {\n const cacheRef = useRef<PageSettings | null>(null);\n\n const subscribe = useCallback(\n (notify: () => void) => doc.observePageSettings(notify),\n [doc],\n );\n\n const getSnapshot = useCallback((): PageSettings => {\n const next = doc.getPageSettings();\n const prev = cacheRef.current;\n if (prev && shallowEqual(prev, next)) return prev;\n cacheRef.current = next;\n return next;\n }, [doc]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nfunction shallowEqual(a: PageSettings, b: PageSettings): boolean {\n return (\n a.width === b.width &&\n a.height === b.height &&\n a.marginTop === b.marginTop &&\n a.marginBottom === b.marginBottom &&\n a.marginLeft === b.marginLeft &&\n a.marginRight === b.marginRight &&\n a.preset === b.preset &&\n a.systemHeaderTitle === b.systemHeaderTitle &&\n a.systemHeaderAuthor === b.systemHeaderAuthor\n );\n}\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type ChangeEvent,\n type JSX,\n type MouseEvent,\n type ReactNode,\n} from \"react\";\nimport { useEditorContext } from \"./EditorContext\";\nimport { ANSWER_LINE_MAX, TABLE_BORDER_COLOR } from \"@sofereditor/core\";\nimport type {\n AlignValue,\n AnswerLineSpacing,\n BlockType,\n DirValue,\n ImageLayout,\n MarkName,\n TableBorderPreset,\n} from \"@sofereditor/core\";\n\n// School standard: Arial only. The dropdown is kept (instead of removed) so\n// that the surrounding font-size / color UI stays balanced and future font\n// additions are a one-liner.\nconst FONT_FAMILIES = [\"Arial\"];\nconst FONT_SIZES = [\"8pt\", \"10pt\", \"11pt\", \"12pt\", \"14pt\", \"16pt\", \"18pt\", \"24pt\", \"32pt\", \"48pt\"];\n\ninterface BlockOption {\n value: string;\n label: string;\n type: BlockType;\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n}\n\nconst BLOCK_OPTIONS: BlockOption[] = [\n { value: \"paragraph\", label: \"Parágrafo\", type: \"paragraph\" },\n { value: \"h1\", label: \"Título 1\", type: \"heading\", level: 1 },\n { value: \"h2\", label: \"Título 2\", type: \"heading\", level: 2 },\n { value: \"h3\", label: \"Título 3\", type: \"heading\", level: 3 },\n { value: \"h4\", label: \"Título 4\", type: \"heading\", level: 4 },\n { value: \"h5\", label: \"Título 5\", type: \"heading\", level: 5 },\n { value: \"h6\", label: \"Título 6\", type: \"heading\", level: 6 },\n { value: \"blockquote\", label: \"Citação\", type: \"blockquote\" },\n { value: \"codeBlock\", label: \"Código\", type: \"codeBlock\" },\n];\n\nconst ALIGN_OPTIONS: { value: AlignValue; label: string; title: string }[] = [\n { value: \"left\", label: \"⇤\", title: \"Alinhar à esquerda\" },\n { value: \"center\", label: \"≡\", title: \"Centralizar\" },\n { value: \"right\", label: \"⇥\", title: \"Alinhar à direita\" },\n { value: \"justify\", label: \"☰\", title: \"Justificar\" },\n];\n\nconst IMAGE_ALIGN_VALUES = new Set<AlignValue>([\"left\", \"center\", \"right\"]);\n\n/**\n * Controles nativos que PRECISAM receber o `mousedown` para abrir seu\n * dropdown/picker. Prevenir o mousedown num `<select>` impede o dropdown de\n * abrir — foi exatamente assim que o seletor de bordas da tabela nasceu morto.\n *\n * A regra vivia duplicada em três handlers com três listas diferentes; fica\n * aqui numa fonte só para não voltar a divergir.\n */\nconst NATIVE_CONTROL_TAGS = new Set([\"SELECT\", \"INPUT\", \"OPTION\"]);\n\nexport function isNativeControl(t: EventTarget | null): boolean {\n const el = t as HTMLElement | null;\n return !!el && NATIVE_CONTROL_TAGS.has(el.tagName);\n}\n\n/**\n * Alvos dentro de um popover que mantêm o próprio `mousedown`. Superconjunto de\n * `isNativeControl` mais `BUTTON` — o resto é fundo de popover, onde o\n * `preventDefault` protege a seleção do editor.\n */\nexport function keepsOwnMouseDown(t: EventTarget | null): boolean {\n const el = t as HTMLElement | null;\n return !!el && (NATIVE_CONTROL_TAGS.has(el.tagName) || el.tagName === \"BUTTON\");\n}\n\nconst IMAGE_LAYOUT_OPTIONS: { value: ImageLayout; label: string; title: string }[] = [\n { value: \"inline\", label: \"↔\", title: \"Inline (no fluxo do texto)\" },\n { value: \"wrap-left\", label: \"◧\", title: \"Texto contorna à direita\" },\n { value: \"wrap-right\", label: \"◨\", title: \"Texto contorna à esquerda\" },\n { value: \"behind\", label: \"▢↓\", title: \"Atrás do texto\" },\n { value: \"front\", label: \"▢↑\", title: \"Na frente do texto\" },\n];\n\nexport interface ToolbarProps {\n className?: string;\n}\n\nexport function Toolbar({ className }: ToolbarProps): JSX.Element {\n const editor = useEditorContext();\n const {\n isMarkActive,\n getActiveMarks,\n toggleMark,\n setMark,\n removeMark,\n getBlockType,\n getBlockAttr,\n setBlockType,\n setBlockAttr,\n setAlign,\n getAlign,\n isListActive,\n toggleList,\n indentList,\n dedentList,\n } = editor;\n const active = getActiveMarks();\n const blockType = getBlockType();\n const blockLevel = getBlockAttr(\"level\");\n const blockAlign = getAlign();\n const blockDir = getBlockAttr(\"dir\");\n\n // Preserve contenteditable focus when clicking the toolbar background or buttons,\n // BUT let native form controls (select/input) receive mousedown normally so their\n // dropdowns/pickers can open.\n const stop = (e: MouseEvent) => {\n if (isNativeControl(e.target)) return;\n e.preventDefault();\n };\n\n const onToggle = (name: MarkName) => (e: MouseEvent) => {\n e.preventDefault();\n toggleMark(name);\n };\n\n const onColorChange = (e: ChangeEvent<HTMLInputElement>) => {\n setMark(\"color\", e.target.value);\n };\n\n const onHighlightChange = (e: ChangeEvent<HTMLInputElement>) => {\n setMark(\"highlight\", e.target.value);\n };\n\n const onFontFamilyChange = (e: ChangeEvent<HTMLSelectElement>) => {\n const v = e.target.value;\n if (v === \"\") removeMark(\"fontFamily\");\n else setMark(\"fontFamily\", v);\n };\n\n const onFontSizeChange = (e: ChangeEvent<HTMLSelectElement>) => {\n const v = e.target.value;\n if (v === \"\") removeMark(\"fontSize\");\n else setMark(\"fontSize\", v);\n };\n\n const onBlockChange = (e: ChangeEvent<HTMLSelectElement>) => {\n const opt = BLOCK_OPTIONS.find((o) => o.value === e.target.value);\n if (!opt) return;\n setBlockType(opt.type, opt.level !== undefined ? { level: opt.level } : undefined);\n };\n\n const onAlign = (value: AlignValue) => (e: MouseEvent) => {\n e.preventDefault();\n // When an image embed is selected, the three image-friendly alignments\n // (left/center/right) target the embed itself; otherwise fall through to\n // the block-level align attribute (which also handles \"justify\").\n const selectedEmbed = editor.getSelectedEmbed();\n if (selectedEmbed && IMAGE_ALIGN_VALUES.has(value)) {\n editor.setImageAttrs(\n selectedEmbed.blockIndex,\n selectedEmbed.offset,\n { align: value as \"left\" | \"center\" | \"right\" },\n selectedEmbed.cellIndex,\n );\n return;\n }\n setAlign(value);\n };\n\n const onInsertImageClick = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n imageInputRef.current?.click();\n },\n [],\n );\n const onImageInputChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (file) void editor.insertImageFromFile(file);\n e.target.value = \"\";\n },\n [editor],\n );\n const imageInputRef = useRef<HTMLInputElement>(null);\n\n const onToggleDir = (e: MouseEvent) => {\n e.preventDefault();\n const next: DirValue = blockDir === \"rtl\" ? \"ltr\" : \"rtl\";\n setBlockAttr(\"dir\", next);\n };\n\n const linkActive = isMarkActive(\"link\");\n const onLinkClick = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n const currentHref =\n active.link && typeof active.link === \"object\" && \"href\" in active.link\n ? (active.link.href as string)\n : \"\";\n void editor.requestLink(currentHref).then((href) => {\n if (href === null) return;\n if (href === \"\") removeMark(\"link\");\n else setMark(\"link\", { href });\n });\n },\n [active.link, editor, removeMark, setMark],\n );\n\n const colorValue = typeof active.color === \"string\" ? active.color : \"#000000\";\n // Amarelo clássico de marca-texto como padrão do picker quando nada está marcado.\n const highlightValue = typeof active.highlight === \"string\" ? active.highlight : \"#fff176\";\n const fontFamilyValue = typeof active.fontFamily === \"string\" ? active.fontFamily : \"\";\n const fontSizeValue = typeof active.fontSize === \"string\" ? active.fontSize : \"\";\n const blockValue = blockSelectValue(blockType, blockLevel);\n\n // The image layout group is only visible when an image embed is selected.\n // We read it fresh every render so the visibility tracks selection changes.\n const selectedEmbed = editor.getSelectedEmbed();\n const currentImageLayout: ImageLayout = selectedEmbed\n ? (selectedEmbed.embed.layout ?? \"inline\")\n : \"inline\";\n\n const onImageLayoutClick = (layout: ImageLayout) => (e: MouseEvent) => {\n e.preventDefault();\n const sel = editor.getSelectedEmbed();\n if (!sel) return;\n // Reset position offsets when switching modes; the previous values would\n // refer to a different coordinate system (margins vs. left/top).\n const reset =\n layout !== (sel.embed.layout ?? \"inline\")\n ? { offsetX: 0, offsetY: 0 }\n : {};\n editor.setImageAttrs(\n sel.blockIndex,\n sel.offset,\n { layout, ...reset },\n sel.cellIndex,\n );\n };\n\n return (\n <div\n className={className ?? \"ed-toolbar\"}\n role=\"toolbar\"\n aria-label=\"Editor toolbar\"\n onMouseDown={stop}\n >\n <Group>\n <select\n className=\"ed-toolbar-select\"\n value={blockValue}\n onChange={onBlockChange}\n onMouseDown={stop}\n aria-label=\"Tipo de bloco\"\n >\n {blockValue === \"\" && <option value=\"\">— (misto)</option>}\n {BLOCK_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>{o.label}</option>\n ))}\n </select>\n </Group>\n\n <Group>\n <MarkButton title=\"Negrito (⌘B)\" pressed={isMarkActive(\"bold\")} onClick={onToggle(\"bold\")}>\n <strong>B</strong>\n </MarkButton>\n <MarkButton title=\"Itálico (⌘I)\" pressed={isMarkActive(\"italic\")} onClick={onToggle(\"italic\")}>\n <em>I</em>\n </MarkButton>\n <MarkButton title=\"Sublinhado (⌘U)\" pressed={isMarkActive(\"underline\")} onClick={onToggle(\"underline\")}>\n <u>U</u>\n </MarkButton>\n <MarkButton title=\"Tachado (⌘⇧X)\" pressed={isMarkActive(\"strike\")} onClick={onToggle(\"strike\")}>\n <s>S</s>\n </MarkButton>\n </Group>\n\n <Group>\n <label className=\"ed-toolbar-label\">\n <span className=\"ed-toolbar-swatch\" aria-hidden style={{ background: colorValue }} />\n <input type=\"color\" value={colorValue} onChange={onColorChange} onMouseDown={stop} aria-label=\"Cor do texto\" />\n </label>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Remover cor\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n removeMark(\"color\");\n }}\n >\n ⌫\n </button>\n <label className=\"ed-toolbar-label\" title=\"Marca-texto\">\n <span\n className=\"ed-toolbar-swatch ed-toolbar-swatch--highlight\"\n aria-hidden\n style={{ background: highlightValue }}\n />\n <input\n type=\"color\"\n value={highlightValue}\n onChange={onHighlightChange}\n onMouseDown={stop}\n aria-label=\"Marca-texto\"\n />\n </label>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Remover marca-texto\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n removeMark(\"highlight\");\n }}\n >\n ⌫\n </button>\n </Group>\n\n <Group>\n <select\n className=\"ed-toolbar-select\"\n value={fontFamilyValue}\n onChange={onFontFamilyChange}\n onMouseDown={stop}\n aria-label=\"Família da fonte\"\n >\n <option value=\"\">Fonte…</option>\n {FONT_FAMILIES.map((f) => (\n <option key={f} value={f}>{f}</option>\n ))}\n </select>\n <select\n className=\"ed-toolbar-select\"\n value={fontSizeValue}\n onChange={onFontSizeChange}\n onMouseDown={stop}\n aria-label=\"Tamanho da fonte\"\n >\n <option value=\"\">Tamanho…</option>\n {FONT_SIZES.map((s) => (\n <option key={s} value={s}>{s}</option>\n ))}\n </select>\n </Group>\n\n <Group>\n {ALIGN_OPTIONS.map((a) => (\n <button\n key={a.value}\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title={a.title}\n aria-pressed={blockAlign === a.value}\n onMouseDown={stop}\n onClick={onAlign(a.value)}\n >\n {a.label}\n </button>\n ))}\n </Group>\n\n <Group>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n aria-pressed={blockDir === \"rtl\"}\n title={blockDir === \"rtl\" ? \"Mudar para LTR\" : \"Mudar para RTL (hebraico)\"}\n onMouseDown={stop}\n onClick={onToggleDir}\n >\n {blockDir === \"rtl\" ? \"RTL\" : \"LTR\"}\n </button>\n </Group>\n\n <Group>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n aria-pressed={isListActive(\"bullet\")}\n title=\"Lista com marcadores (⌘⇧8)\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n toggleList(\"bullet\");\n }}\n >\n •\n </button>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n aria-pressed={isListActive(\"ordered\")}\n title=\"Lista numerada (⌘⇧7)\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n toggleList(\"ordered\");\n }}\n >\n 1.\n </button>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Diminuir recuo (⇧Tab)\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n dedentList();\n }}\n >\n ⇤\n </button>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Aumentar recuo (Tab)\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n indentList();\n }}\n >\n ⇥\n </button>\n </Group>\n\n <Group>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n aria-pressed={linkActive}\n title={linkActive ? \"Remover link (⌘K)\" : \"Adicionar link (⌘K)\"}\n onMouseDown={stop}\n onClick={onLinkClick}\n >\n 🔗\n </button>\n </Group>\n\n <Group>\n <TableMenu />\n <AnswerLinesMenu />\n </Group>\n\n <Group>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Inserir imagem\"\n onMouseDown={stop}\n onClick={onInsertImageClick}\n >\n 🖼\n </button>\n <input\n ref={imageInputRef}\n type=\"file\"\n accept=\"image/*\"\n hidden\n onChange={onImageInputChange}\n />\n </Group>\n\n {selectedEmbed && (\n <Group>\n {IMAGE_LAYOUT_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title={opt.title}\n aria-pressed={currentImageLayout === opt.value}\n onMouseDown={stop}\n onClick={onImageLayoutClick(opt.value)}\n >\n {opt.label}\n </button>\n ))}\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Legenda da imagem\"\n aria-pressed={!!selectedEmbed.embed.caption}\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n const initialCaption = selectedEmbed.embed.caption ?? \"\";\n const initialAlign = selectedEmbed.embed.captionAlign ?? \"center\";\n void editor.requestImageCaption(initialCaption, initialAlign).then((result) => {\n if (result === null) return; // cancelled\n const empty = result.caption.length === 0;\n editor.setImageAttrs(\n selectedEmbed.blockIndex,\n selectedEmbed.offset,\n {\n caption: empty ? undefined : result.caption,\n captionAlign: empty ? undefined : result.align,\n },\n selectedEmbed.cellIndex,\n );\n });\n }}\n >\n Legenda\n </button>\n </Group>\n )}\n\n <Group>\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Configurar página (tamanho, margens)\"\n onMouseDown={stop}\n onClick={(e) => {\n e.preventDefault();\n void editor.requestPageConfig();\n }}\n >\n ⚙\n </button>\n </Group>\n </div>\n );\n}\n\n// ---------- Table menu ----------\n\n/**\n * Linhas de resposta: parágrafos pautados para o aluno escrever.\n *\n * Um botão em vez da digitação de underlines porque a régua precisa acompanhar\n * a margem — uma fileira de `_` quebra ao mudar tamanho de página ou fonte.\n */\nfunction AnswerLinesMenu(): JSX.Element {\n const editor = useEditorContext();\n const [open, setOpen] = useState(false);\n const [count, setCount] = useState(5);\n const [spacing, setSpacing] = useState<AnswerLineSpacing>(1.5);\n const rootRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!open) return;\n const onDown = (e: globalThis.MouseEvent) => {\n if (!rootRef.current) return;\n if (rootRef.current.contains(e.target as Node)) return;\n setOpen(false);\n };\n document.addEventListener(\"mousedown\", onDown);\n return () => document.removeEventListener(\"mousedown\", onDown);\n }, [open]);\n\n const clamped = Math.max(1, Math.min(ANSWER_LINE_MAX, Math.trunc(count) || 1));\n\n return (\n <div ref={rootRef} className=\"ed-toolbar-tablemenu\">\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Linhas de resposta\"\n aria-pressed={open}\n onMouseDown={(e) => e.preventDefault()}\n onClick={(e) => {\n e.preventDefault();\n setOpen((v) => !v);\n }}\n >\n ☰\n </button>\n {open && (\n <div\n className=\"ed-table-popover ed-answerlines-popover\"\n role=\"menu\"\n onMouseDown={(e) => {\n if (!keepsOwnMouseDown(e.target)) e.preventDefault();\n }}\n >\n <label className=\"ed-toolbar-label\">\n Quantidade\n <input\n type=\"number\"\n min={1}\n max={ANSWER_LINE_MAX}\n value={count}\n onChange={(e) => setCount(Number(e.target.value))}\n aria-label=\"Quantidade de linhas\"\n />\n </label>\n <label className=\"ed-toolbar-label\">\n Entrelinha\n <select\n value={String(spacing)}\n onChange={(e) => setSpacing(Number(e.target.value) as AnswerLineSpacing)}\n aria-label=\"Entrelinha\"\n >\n <option value=\"1\">Simples</option>\n <option value=\"1.5\">1,5</option>\n <option value=\"2\">Duplo</option>\n </select>\n </label>\n <button\n type=\"button\"\n onClick={() => {\n setOpen(false);\n editor.insertAnswerLines(clamped, spacing);\n }}\n >\n Inserir {clamped} linha{clamped > 1 ? \"s\" : \"\"}\n </button>\n </div>\n )}\n </div>\n );\n}\n\nfunction TableMenu(): JSX.Element {\n const editor = useEditorContext();\n const inTable = editor.isInTable();\n const [open, setOpen] = useState(false);\n const rootRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!open) return;\n const onDown = (e: globalThis.MouseEvent) => {\n if (!rootRef.current) return;\n if (rootRef.current.contains(e.target as Node)) return;\n setOpen(false);\n };\n document.addEventListener(\"mousedown\", onDown);\n return () => document.removeEventListener(\"mousedown\", onDown);\n }, [open]);\n\n return (\n <div ref={rootRef} className=\"ed-toolbar-tablemenu\">\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n title=\"Tabela\"\n aria-pressed={open}\n onMouseDown={(e) => e.preventDefault()}\n onClick={(e) => {\n e.preventDefault();\n setOpen((v) => !v);\n }}\n >\n ▦\n </button>\n {open && (\n <div\n className=\"ed-table-popover\"\n role=\"menu\"\n onMouseDown={(e) => {\n // Do not let mousedown clear the editor selection.\n if (!keepsOwnMouseDown(e.target)) e.preventDefault();\n }}\n >\n <TableSizePicker\n onPick={(rows, cols) => {\n setOpen(false);\n editor.insertTable(rows, cols);\n }}\n />\n {inTable && (\n <div className=\"ed-table-actions\">\n <hr />\n <button type=\"button\" onClick={() => { setOpen(false); editor.insertRowAbove(); }}>\n Inserir linha acima\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.insertRowBelow(); }}>\n Inserir linha abaixo\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.insertColumnLeft(); }}>\n Inserir coluna à esquerda\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.insertColumnRight(); }}>\n Inserir coluna à direita\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.deleteCurrentRow(); }}>\n Excluir linha\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.deleteCurrentColumn(); }}>\n Excluir coluna\n </button>\n <hr />\n {editor.hasTableRectSelection() && (\n <button\n type=\"button\"\n onClick={() => { setOpen(false); editor.mergeSelection(); }}\n >\n Mesclar células selecionadas\n </button>\n )}\n <button type=\"button\" onClick={() => { setOpen(false); editor.mergeRight(); }}>\n Mesclar com célula à direita\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.mergeDown(); }}>\n Mesclar com célula abaixo\n </button>\n <button type=\"button\" onClick={() => { setOpen(false); editor.splitCell(); }}>\n Dividir células mescladas\n </button>\n <hr />\n <label className=\"ed-toolbar-label ed-table-bgcolor\">\n <span\n className=\"ed-toolbar-swatch\"\n aria-hidden\n style={{ background: editor.getCellBackground() ?? \"#ffffff\" }}\n />\n Cor de fundo da célula\n <input\n type=\"color\"\n value={editor.getCellBackground() ?? \"#ffffff\"}\n onChange={(e) => editor.setCellBackground(e.target.value)}\n aria-label=\"Cor de fundo da célula\"\n />\n </label>\n <button type=\"button\" onClick={() => { setOpen(false); editor.setCellBackground(null); }}>\n Remover cor de fundo\n </button>\n <hr />\n <label className=\"ed-toolbar-label\">\n Bordas\n <select\n value={editor.getTableBorderPreset()}\n onChange={(e) =>\n editor.setTableBorderPreset(e.target.value as TableBorderPreset)\n }\n aria-label=\"Bordas da tabela\"\n >\n <option value=\"all\">Todas</option>\n <option value=\"outer\">Só externas</option>\n <option value=\"horizontal\">Só horizontais</option>\n <option value=\"vertical\">Só verticais</option>\n <option value=\"none\">Nenhuma</option>\n </select>\n </label>\n <label className=\"ed-toolbar-label ed-table-bgcolor\">\n <span\n className=\"ed-toolbar-swatch\"\n aria-hidden\n style={{ background: editor.getTableBorderColor() ?? TABLE_BORDER_COLOR }}\n />\n Cor da borda\n <input\n type=\"color\"\n value={editor.getTableBorderColor() ?? TABLE_BORDER_COLOR}\n onChange={(e) => editor.setTableBorderColor(e.target.value)}\n aria-label=\"Cor da borda\"\n />\n </label>\n <button\n type=\"button\"\n onClick={() => { setOpen(false); editor.setTableBorderColor(null); }}\n >\n Restaurar cor padrão\n </button>\n <hr />\n <button\n type=\"button\"\n className=\"ed-table-delete\"\n onClick={() => { setOpen(false); editor.deleteTable(); }}\n >\n Excluir tabela\n </button>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\nconst PICKER_MAX_ROWS = 8;\nconst PICKER_MAX_COLS = 10;\n\ninterface TableSizePickerProps {\n onPick: (rows: number, cols: number) => void;\n}\n\nfunction TableSizePicker({ onPick }: TableSizePickerProps): JSX.Element {\n const [hover, setHover] = useState<{ r: number; c: number } | null>(null);\n const label = hover ? `${hover.r + 1} × ${hover.c + 1}` : \"Inserir tabela\";\n return (\n <div className=\"ed-table-picker\">\n <div className=\"ed-table-picker-label\">{label}</div>\n <div\n className=\"ed-table-picker-grid\"\n style={{\n gridTemplateColumns: `repeat(${PICKER_MAX_COLS}, 18px)`,\n gridTemplateRows: `repeat(${PICKER_MAX_ROWS}, 18px)`,\n }}\n onMouseLeave={() => setHover(null)}\n >\n {Array.from({ length: PICKER_MAX_ROWS }, (_, r) =>\n Array.from({ length: PICKER_MAX_COLS }, (_, c) => {\n const filled = hover != null && r <= hover.r && c <= hover.c;\n return (\n <button\n key={`${r}-${c}`}\n type=\"button\"\n className={`ed-table-picker-cell${filled ? \" filled\" : \"\"}`}\n onMouseEnter={() => setHover({ r, c })}\n onMouseDown={(e) => e.preventDefault()}\n onClick={(e) => {\n e.preventDefault();\n onPick(r + 1, c + 1);\n }}\n aria-label={`${r + 1} × ${c + 1}`}\n />\n );\n }),\n )}\n </div>\n </div>\n );\n}\n\nfunction blockSelectValue(\n type: BlockType | \"mixed\",\n level: unknown,\n): string {\n if (type === \"mixed\") return \"\";\n if (type === \"heading\") {\n if (typeof level === \"number\" && level >= 1 && level <= 6) return `h${level}`;\n return \"h1\";\n }\n return type;\n}\n\nfunction Group({ children }: { children: ReactNode }): JSX.Element {\n return <div className=\"ed-toolbar-group\">{children}</div>;\n}\n\ninterface MarkButtonProps {\n title: string;\n pressed: boolean;\n onClick: (e: MouseEvent) => void;\n children: ReactNode;\n}\n\nfunction MarkButton({ title, pressed, onClick, children }: MarkButtonProps): JSX.Element {\n return (\n <button\n type=\"button\"\n className=\"ed-toolbar-btn\"\n aria-pressed={pressed}\n title={title}\n onMouseDown={(e) => e.preventDefault()}\n onClick={onClick}\n >\n {children}\n </button>\n );\n}\n"],"mappings":"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","names":["useCallback","useEffect","useLayoutEffect","useMemo","useRef","useState","SOFER_MIME","Fragment","jsx","jsxs","useEffect","useState","jsx","jsxs","useState","useEffect","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useEffect","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useEffect","jsx","jsxs","useCallback","useEffect","useLayoutEffect","useRef","useState","jsx","jsxs","useState","useRef","useCallback","useLayoutEffect","useEffect","useCallback","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useCallback","useEffect","useMemo","useRef","Fragment","jsx","jsxs","Fragment","useCallback","useEffect","useLayoutEffect","useRef","useState","Fragment","jsx","useState","useRef","useCallback","useLayoutEffect","useEffect","jsx","jsxs","clampLevel","useRef","useMemo","_","useLayoutEffect","useRef","useState","currentPage","useCallback","useEffect","useMemo","useRef","useState","useCallback","useRef","tableRectSelection","isImageEmbed","useMemo","useState","useRef","useCallback","useEffect","yText","jsx","jsxs","useRef","useState","useEffect","useLayoutEffect","selectedEmbed","SOFER_MIME","useCallback","useMemo","clampListLevel","useCallback","useEffect","useRef","useState","jsx","jsxs","selectedEmbed","useCallback","useRef","useState","useEffect","_"]}
|