mgcode-docx-editor 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/DocxEditor.tsx","../src/docx/generate.ts","../src/docx/pageFields.ts","../src/docx/importDocx.ts","../src/docx/pagination.ts","../src/editorCommands.ts","../src/docx/units.ts","../src/Toolbar.tsx","../src/ZoomControl.tsx","../src/Ruler.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type ChangeEvent,\n type MouseEvent as ReactMouseEvent,\n} from 'react';\nimport { Box, Chip, CircularProgress } from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material/styles';\nimport {\n DocumentModel,\n DocxEditorHandle,\n DocxEditorProps,\n PageMarginsTwips,\n} from './types';\nimport { modelToDocx, DEFAULT_MARGINS } from './docx/generate';\nimport { bufferToModel } from './docx/importDocx';\nimport {\n computePageLayout,\n createSpacerElement,\n stripPageSpacers,\n BlockBox,\n PAGE_SPACER_ATTR,\n} from './docx/pagination';\nimport { PAGE_NUMBER_TOKEN, TOTAL_PAGES_TOKEN } from './docx/pageFields';\nimport {\n execFormat,\n setFontFamily as applyFontFamily,\n setFontSize as applyFontSize,\n insertTextIntoRegion,\n} from './editorCommands';\nimport { twipsToPx } from './docx/units';\nimport Toolbar from './Toolbar';\nimport ZoomControl from './ZoomControl';\nimport Ruler, { ParagraphIndentTwips } from './Ruler';\n\n/** Página A4 em px a 100% (210 × 297 mm a 96dpi). */\nconst PAGE_WIDTH_PX = 794;\nconst PAGE_HEIGHT_PX = 1123;\n/** Espaço visual entre páginas. */\nconst PAGE_GAP_PX = 24;\n/** Distância do cabeçalho/rodapé até a borda da página (0,5pol, como o Word). */\nconst HEADER_FOOTER_DISTANCE_PX = 48;\n\nconst EMPTY_INDENT: ParagraphIndentTwips = { firstLine: 0, left: 0, right: 0 };\n\ninterface RegionElements {\n header?: HTMLDivElement | null;\n body?: HTMLDivElement | null;\n footer?: HTMLDivElement | null;\n}\n\ninterface EditableRegionProps {\n html: string;\n editable: boolean;\n ariaLabel: string;\n placeholder?: string;\n sx?: SxProps<Theme>;\n onRegister: (el: HTMLDivElement | null) => void;\n onFocus: (el: HTMLDivElement) => void;\n onBlur?: () => void;\n onInput?: () => void;\n}\n\nfunction EditableRegion(props: EditableRegionProps) {\n const setRef = (el: HTMLDivElement | null) => {\n if (el && el.dataset.initialized !== '1') {\n el.innerHTML = props.html;\n el.dataset.initialized = '1';\n }\n props.onRegister(el);\n };\n\n return (\n <Box\n component=\"div\"\n ref={setRef}\n contentEditable={props.editable}\n suppressContentEditableWarning\n onFocus={(e) => props.onFocus(e.currentTarget)}\n onBlur={props.onBlur}\n onInput={props.onInput}\n aria-label={props.ariaLabel}\n data-placeholder={props.placeholder}\n sx={[\n {\n outline: 'none',\n position: 'relative',\n minHeight: 24,\n '& p': { m: 0, mb: 1 },\n '&:empty::before': {\n content: 'attr(data-placeholder)',\n color: 'text.disabled',\n },\n },\n ...(Array.isArray(props.sx) ? props.sx : props.sx ? [props.sx] : []),\n ]}\n />\n );\n}\n\n/** Sobe do nó da seleção até o bloco (p/h/li/div) dentro da região. */\nfunction currentBlock(region: HTMLElement | null): HTMLElement | null {\n if (!region) return null;\n const selection = window.getSelection();\n let node: Node | null =\n selection && selection.anchorNode ? selection.anchorNode : null;\n if (!node || !region.contains(node)) {\n return (region.firstElementChild as HTMLElement) ?? region;\n }\n let el: HTMLElement | null =\n node.nodeType === Node.ELEMENT_NODE\n ? (node as HTMLElement)\n : node.parentElement;\n while (el && el !== region) {\n if (/^(P|H1|H2|H3|H4|LI|DIV)$/.test(el.tagName) && el.parentElement === region) {\n return el;\n }\n if (el.parentElement === region) return el;\n el = el.parentElement;\n }\n return (region.firstElementChild as HTMLElement) ?? region;\n}\n\n/** Estilo compartilhado do conteúdo dos espelhos de cabeçalho/rodapé. */\nconst mirrorSx: SxProps<Theme> = {\n pointerEvents: 'none',\n '& p': { m: 0, mb: 1 },\n};\n\n/** Nos espelhos (páginas 2+), os tokens de campo viram números reais (preview). */\nfunction withPagePreview(\n html: string,\n pageNumber: number,\n totalPages: number\n): string {\n return html\n .split(PAGE_NUMBER_TOKEN)\n .join(String(pageNumber))\n .split(TOTAL_PAGES_TOKEN)\n .join(String(totalPages));\n}\n\ntype RegionKey = 'header' | 'body' | 'footer';\n\ntype ResizeCorner = 'nw' | 'ne' | 'sw' | 'se';\n\ninterface FrameRect {\n top: number;\n left: number;\n width: number;\n height: number;\n}\n\nconst RESIZE_CORNERS: ResizeCorner[] = ['nw', 'ne', 'sw', 'se'];\n\nconst DocxEditor = forwardRef<DocxEditorHandle, DocxEditorProps>(\n function DocxEditor(props, ref) {\n const {\n documentBuffer,\n document: documentModel,\n mode,\n showToolbar = false,\n showRuler = false,\n showZoomControl = false,\n } = props;\n\n const editable = mode === 'editing';\n\n const [model, setModel] = useState<DocumentModel>(\n () => documentModel ?? { body: '' }\n );\n const [docVersion, setDocVersion] = useState(0);\n const [loading, setLoading] = useState(false);\n const [zoom, setZoom] = useState(1);\n const [margins, setMargins] = useState<PageMarginsTwips>(DEFAULT_MARGINS);\n const [indent, setIndent] = useState<ParagraphIndentTwips>(EMPTY_INDENT);\n const [pageCount, setPageCount] = useState(1);\n // HTML espelhado do header/footer nas páginas 2+ (somente visual).\n const [mirror, setMirror] = useState(() => ({\n header: documentModel?.header ?? '',\n footer: documentModel?.footer ?? '',\n }));\n // Altura medida das regiões reais de header/footer (px, sem zoom).\n const [chromeHeights, setChromeHeights] = useState({ header: 0, footer: 0 });\n // Região com foco de edição (para etiqueta + esmaecimento estilo Word).\n const [focusedRegion, setFocusedRegion] = useState<RegionKey | null>(null);\n // Imagem selecionada para redimensionamento + retângulo da moldura.\n const [selectedImg, setSelectedImg] = useState<HTMLImageElement | null>(null);\n const [frame, setFrame] = useState<FrameRect | null>(null);\n\n const regionEls = useRef<RegionElements>({});\n const activeRegion = useRef<HTMLDivElement | null>(null);\n const imageInputRef = useRef<HTMLInputElement>(null);\n const rafId = useRef<number | null>(null);\n const pagesColumnRef = useRef<HTMLDivElement>(null);\n\n const padTop = twipsToPx(margins.top);\n const padRight = twipsToPx(margins.right);\n const padBottom = twipsToPx(margins.bottom);\n const padLeft = twipsToPx(margins.left);\n\n // Área do corpo em cada página: começa abaixo do header e termina acima\n // do footer (cada um ocupa a área de margem, como no Word).\n const bodyTopPx = Math.max(\n padTop,\n HEADER_FOOTER_DISTANCE_PX + chromeHeights.header\n );\n const bodyBottomPx = Math.max(\n padBottom,\n HEADER_FOOTER_DISTANCE_PX + chromeHeights.footer\n );\n\n /**\n * Mede os blocos do corpo, calcula as quebras e injeta os espaçadores\n * não-editáveis. Recalculado a cada edição — auto-corrigível.\n */\n const recomputePagination = useCallback(() => {\n const body = regionEls.current.body;\n if (!body) return;\n\n const headerH = regionEls.current.header?.offsetHeight ?? 0;\n const footerH = regionEls.current.footer?.offsetHeight ?? 0;\n setChromeHeights((prev) =>\n prev.header === headerH && prev.footer === footerH\n ? prev\n : { header: headerH, footer: footerH }\n );\n\n const top = Math.max(\n twipsToPx(margins.top),\n HEADER_FOOTER_DISTANCE_PX + headerH\n );\n const bottom = Math.max(\n twipsToPx(margins.bottom),\n HEADER_FOOTER_DISTANCE_PX + footerH\n );\n const usableHeightPx = Math.max(PAGE_HEIGHT_PX - top - bottom, 1);\n const interPageGapPx = bottom + PAGE_GAP_PX + top;\n\n // Mede em coordenadas sem espaçadores (contrato de BlockBox.top).\n let spacerAccum = 0;\n const blocks: BlockBox[] = [];\n const blockEls: HTMLElement[] = [];\n Array.from(body.children).forEach((child) => {\n const el = child as HTMLElement;\n if (el.hasAttribute(PAGE_SPACER_ATTR)) {\n spacerAccum += el.offsetHeight;\n return;\n }\n blocks.push({ top: el.offsetTop - spacerAccum, height: el.offsetHeight });\n blockEls.push(el);\n });\n\n const layout = computePageLayout(blocks, { usableHeightPx, interPageGapPx });\n\n body\n .querySelectorAll(`[${PAGE_SPACER_ATTR}]`)\n .forEach((node) => node.remove());\n for (const spacer of layout.spacers) {\n const target = blockEls[spacer.beforeBlockIndex];\n if (target) body.insertBefore(createSpacerElement(spacer.heightPx), target);\n }\n\n setPageCount(layout.pageCount);\n }, [margins]);\n\n const schedulePagination = useCallback(() => {\n if (rafId.current !== null) cancelAnimationFrame(rafId.current);\n rafId.current = requestAnimationFrame(() => {\n rafId.current = null;\n recomputePagination();\n });\n }, [recomputePagination]);\n\n /** Sincroniza os espelhos das páginas 2+ e reflui a paginação. */\n const handleContentChanged = useCallback(() => {\n const header = regionEls.current.header?.innerHTML ?? '';\n const footer = regionEls.current.footer?.innerHTML ?? '';\n setMirror((prev) =>\n prev.header === header && prev.footer === footer\n ? prev\n : { header, footer }\n );\n schedulePagination();\n }, [schedulePagination]);\n\n // Importa um .docx quando `documentBuffer` muda.\n useEffect(() => {\n if (!documentBuffer) return;\n let cancelled = false;\n setLoading(true);\n bufferToModel(documentBuffer)\n .then((imported) => {\n if (cancelled) return;\n setModel((prev) => ({ ...imported, variables: prev.variables }));\n setMirror({\n header: imported.header ?? '',\n footer: imported.footer ?? '',\n });\n setDocVersion((v) => v + 1);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n return () => {\n cancelled = true;\n };\n }, [documentBuffer]);\n\n // Repagina após montagem, importação, mudança de margens ou de\n // altura do header/footer (mirror muda a cada edição dessas regiões).\n useEffect(() => {\n recomputePagination();\n }, [recomputePagination, docVersion, mirror]);\n\n // Imagens carregam de forma assíncrona e mudam a altura dos blocos.\n useEffect(() => {\n const body = regionEls.current.body;\n if (!body) return;\n const onLoad = () => schedulePagination();\n body.addEventListener('load', onLoad, true);\n return () => body.removeEventListener('load', onLoad, true);\n }, [schedulePagination, docVersion]);\n\n useEffect(\n () => () => {\n if (rafId.current !== null) cancelAnimationFrame(rafId.current);\n },\n []\n );\n\n const buildModel = useCallback((): DocumentModel => {\n const els = regionEls.current;\n return {\n header: els.header ? els.header.innerHTML : model.header,\n body: els.body ? stripPageSpacers(els.body.innerHTML) : model.body,\n footer: els.footer ? els.footer.innerHTML : model.footer,\n variables: model.variables,\n };\n }, [model]);\n\n useImperativeHandle(\n ref,\n () => ({\n save: () => modelToDocx(buildModel(), { margins }),\n getModel: () => buildModel(),\n }),\n [buildModel, margins]\n );\n\n const focusActive = (): HTMLDivElement | null => {\n const el = activeRegion.current ?? regionEls.current.body ?? null;\n el?.focus();\n return el;\n };\n\n const handleCommand = (command: string, value?: string) => {\n focusActive();\n execFormat(command, value);\n handleContentChanged();\n };\n\n const handleLink = () => {\n const url = window.prompt('URL do link:');\n if (!url) return;\n focusActive();\n execFormat('createLink', url);\n handleContentChanged();\n };\n\n const handleInsertImage = () => imageInputRef.current?.click();\n\n const onImagePicked = (e: ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = () => {\n focusActive();\n execFormat('insertImage', String(reader.result));\n handleContentChanged();\n };\n reader.readAsDataURL(file);\n e.target.value = '';\n };\n\n const handleInsertVariable = (name: string) => {\n const el = activeRegion.current ?? regionEls.current.body ?? null;\n if (el) {\n insertTextIntoRegion(el, `{{${name}}}`);\n handleContentChanged();\n }\n };\n\n const handleInsertPageField = (field: 'pageNumber' | 'totalPages') => {\n // Campos de página fazem sentido no rodapé — é o fallback sem foco.\n const el = activeRegion.current ?? regionEls.current.footer ?? null;\n if (el) {\n insertTextIntoRegion(\n el,\n field === 'pageNumber' ? PAGE_NUMBER_TOKEN : TOTAL_PAGES_TOKEN\n );\n handleContentChanged();\n }\n };\n\n const applyIndent = (next: ParagraphIndentTwips) => {\n setIndent(next);\n const block = currentBlock(activeRegion.current ?? regionEls.current.body ?? null);\n if (block) {\n block.style.textIndent = `${twipsToPx(next.firstLine)}px`;\n block.style.marginLeft = `${twipsToPx(next.left)}px`;\n block.style.marginRight = `${twipsToPx(next.right)}px`;\n }\n schedulePagination();\n };\n\n const registerRegion =\n (key: keyof RegionElements) => (el: HTMLDivElement | null) => {\n regionEls.current[key] = el;\n };\n\n const onRegionFocus = (el: HTMLDivElement) => {\n activeRegion.current = el;\n const els = regionEls.current;\n setFocusedRegion(\n el === els.header ? 'header' : el === els.footer ? 'footer' : 'body'\n );\n };\n\n const onRegionBlur = () => setFocusedRegion(null);\n\n const editingChrome = focusedRegion === 'header' || focusedRegion === 'footer';\n\n /** Recalcula a moldura de resize sobre a imagem selecionada (px sem zoom). */\n const updateFrame = useCallback(() => {\n const img = selectedImg;\n const column = pagesColumnRef.current;\n if (!img || !img.isConnected || !column) {\n setFrame(null);\n return;\n }\n const imgRect = img.getBoundingClientRect();\n const colRect = column.getBoundingClientRect();\n setFrame({\n top: (imgRect.top - colRect.top) / zoom,\n left: (imgRect.left - colRect.left) / zoom,\n width: imgRect.width / zoom,\n height: imgRect.height / zoom,\n });\n }, [selectedImg, zoom]);\n\n const updateFrameRef = useRef(updateFrame);\n useEffect(() => {\n updateFrameRef.current = updateFrame;\n });\n\n // Reposiciona a moldura quando o layout muda; deseleciona ao reimportar.\n useEffect(() => {\n updateFrame();\n }, [updateFrame, pageCount, margins, mirror]);\n useEffect(() => {\n setSelectedImg(null);\n }, [docVersion]);\n\n /** Seleção de imagem por delegação de clique na coluna de páginas. */\n const handleColumnClick = (e: ReactMouseEvent<HTMLDivElement>) => {\n if (!editable) return;\n const target = e.target as HTMLElement;\n if (\n target instanceof HTMLImageElement &&\n target.closest('[contenteditable]')\n ) {\n setSelectedImg(target);\n } else {\n setSelectedImg(null);\n }\n };\n\n const startResize = (corner: ResizeCorner) => (e: ReactMouseEvent) => {\n const img = selectedImg;\n if (!img) return;\n e.preventDefault();\n e.stopPropagation();\n const startX = e.clientX;\n const startWidth = img.offsetWidth;\n const region = img.closest('[contenteditable]') as HTMLElement | null;\n const maxWidth = region ? region.clientWidth : PAGE_WIDTH_PX;\n const sign = corner === 'ne' || corner === 'se' ? 1 : -1;\n\n const onMove = (ev: globalThis.MouseEvent) => {\n const dx = ((ev.clientX - startX) / zoom) * sign;\n const next = Math.round(Math.min(maxWidth, Math.max(20, startWidth + dx)));\n img.style.width = `${next}px`;\n img.style.height = 'auto';\n updateFrameRef.current();\n };\n const onUp = () => {\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n // Fixa a altura em px: a exportação lê style width/height (px → EMU).\n img.style.height = `${img.offsetHeight}px`;\n handleContentChanged();\n updateFrameRef.current();\n };\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n };\n\n const columnHeight =\n pageCount * PAGE_HEIGHT_PX + (pageCount - 1) * PAGE_GAP_PX;\n const usableFirstPagePx = Math.max(\n PAGE_HEIGHT_PX - bodyTopPx - bodyBottomPx,\n 24\n );\n\n return (\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n bgcolor: 'grey.200',\n }}\n >\n {showToolbar && (\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 1,\n flexWrap: 'wrap',\n position: 'sticky',\n top: 0,\n zIndex: 4,\n }}\n >\n <Box sx={{ flex: 1, minWidth: 0 }}>\n <Toolbar\n variables={model.variables ?? []}\n onCommand={handleCommand}\n onFontFamily={(f) => {\n focusActive();\n applyFontFamily(f);\n handleContentChanged();\n }}\n onFontSize={(pt) => {\n const el = focusActive();\n if (el) applyFontSize(el, pt);\n handleContentChanged();\n }}\n onFormatBlock={(tag) => handleCommand('formatBlock', tag)}\n onColor={(c) => handleCommand('foreColor', c)}\n onHighlight={(c) => handleCommand('hiliteColor', c)}\n onLink={handleLink}\n onInsertImage={handleInsertImage}\n onInsertVariable={handleInsertVariable}\n onInsertPageField={handleInsertPageField}\n />\n </Box>\n {showZoomControl && (\n <Box sx={{ px: 1 }}>\n <ZoomControl zoom={zoom} onChange={setZoom} />\n </Box>\n )}\n </Box>\n )}\n\n <input\n ref={imageInputRef}\n type=\"file\"\n accept=\"image/*\"\n style={{ display: 'none' }}\n onChange={onImagePicked}\n />\n\n <Box sx={{ flex: 1, overflow: 'auto', py: 3 }}>\n {showRuler && (\n <Box sx={{ display: 'flex', justifyContent: 'center', mb: 1 }}>\n <Ruler\n pageWidthPx={PAGE_WIDTH_PX}\n zoom={zoom}\n margins={margins}\n indent={indent}\n onMarginsChange={setMargins}\n onIndentChange={applyIndent}\n />\n </Box>\n )}\n\n <Box\n ref={pagesColumnRef}\n onClick={handleColumnClick}\n sx={{\n width: PAGE_WIDTH_PX,\n height: columnHeight,\n transform: `scale(${zoom})`,\n transformOrigin: 'top center',\n mx: 'auto',\n position: 'relative',\n }}\n >\n {/* Camada 0: o \"papel\" de cada página + espelhos de header/footer. */}\n {Array.from({ length: pageCount }, (_, page) => (\n <Box\n key={page}\n data-page-index={page}\n sx={{\n position: 'absolute',\n top: page * (PAGE_HEIGHT_PX + PAGE_GAP_PX),\n left: 0,\n width: '100%',\n height: PAGE_HEIGHT_PX,\n bgcolor: 'background.paper',\n boxShadow: 3,\n zIndex: 0,\n }}\n >\n {page > 0 && (\n <>\n <Box\n aria-hidden\n sx={{\n ...mirrorSx,\n position: 'absolute',\n top: HEADER_FOOTER_DISTANCE_PX,\n left: padLeft,\n right: padRight,\n zIndex: 2,\n opacity: focusedRegion === 'body' ? 0.55 : 1,\n transition: 'opacity 120ms',\n }}\n dangerouslySetInnerHTML={{\n __html: withPagePreview(mirror.header, page + 1, pageCount),\n }}\n />\n <Box\n aria-hidden\n sx={{\n ...mirrorSx,\n position: 'absolute',\n bottom: HEADER_FOOTER_DISTANCE_PX,\n left: padLeft,\n right: padRight,\n zIndex: 2,\n opacity: focusedRegion === 'body' ? 0.55 : 1,\n transition: 'opacity 120ms',\n }}\n dangerouslySetInnerHTML={{\n __html: withPagePreview(mirror.footer, page + 1, pageCount),\n }}\n />\n </>\n )}\n </Box>\n ))}\n\n {/* Camada 2: header/footer reais (editáveis), fixos na página 1.\n Ficam fora do map para não perderem o DOM quando pageCount muda. */}\n <Box\n sx={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: PAGE_HEIGHT_PX,\n zIndex: 2,\n pointerEvents: 'none',\n }}\n >\n <Box\n sx={{\n position: 'absolute',\n top: HEADER_FOOTER_DISTANCE_PX,\n left: padLeft,\n right: padRight,\n pointerEvents: 'auto',\n opacity: focusedRegion === 'body' ? 0.55 : 1,\n transition: 'opacity 120ms',\n ...(focusedRegion === 'header' && {\n outline: '1px dashed',\n outlineColor: 'primary.main',\n outlineOffset: '4px',\n }),\n }}\n >\n {focusedRegion === 'header' && (\n <Chip\n label=\"Cabeçalho\"\n size=\"small\"\n color=\"primary\"\n sx={{\n position: 'absolute',\n top: -32,\n left: -4,\n borderRadius: 0.5,\n pointerEvents: 'none',\n }}\n />\n )}\n <EditableRegion\n key={`header-${docVersion}`}\n html={model.header ?? ''}\n editable={editable}\n ariaLabel=\"Cabeçalho\"\n placeholder=\"Cabeçalho (opcional)\"\n onRegister={registerRegion('header')}\n onFocus={onRegionFocus}\n onBlur={onRegionBlur}\n onInput={handleContentChanged}\n />\n </Box>\n <Box\n sx={{\n position: 'absolute',\n bottom: HEADER_FOOTER_DISTANCE_PX,\n left: padLeft,\n right: padRight,\n pointerEvents: 'auto',\n opacity: focusedRegion === 'body' ? 0.55 : 1,\n transition: 'opacity 120ms',\n ...(focusedRegion === 'footer' && {\n outline: '1px dashed',\n outlineColor: 'primary.main',\n outlineOffset: '4px',\n }),\n }}\n >\n {focusedRegion === 'footer' && (\n <Chip\n label=\"Rodapé\"\n size=\"small\"\n color=\"primary\"\n sx={{\n position: 'absolute',\n bottom: -32,\n left: -4,\n borderRadius: 0.5,\n pointerEvents: 'none',\n }}\n />\n )}\n <EditableRegion\n key={`footer-${docVersion}`}\n html={model.footer ?? ''}\n editable={editable}\n ariaLabel=\"Rodapé\"\n placeholder=\"Rodapé (opcional)\"\n onRegister={registerRegion('footer')}\n onFocus={onRegionFocus}\n onBlur={onRegionBlur}\n onInput={handleContentChanged}\n />\n </Box>\n </Box>\n\n {/* Camada 1: corpo contínuo atravessando as páginas; os espaçadores\n fazem os blocos pularem as zonas de rodapé/cabeçalho. */}\n <Box\n sx={{\n position: 'absolute',\n top: bodyTopPx,\n left: padLeft,\n width: PAGE_WIDTH_PX - padLeft - padRight,\n zIndex: 1,\n opacity: editingChrome ? 0.45 : 1,\n transition: 'opacity 120ms',\n }}\n >\n <EditableRegion\n key={`body-${docVersion}`}\n html={model.body}\n editable={editable}\n ariaLabel=\"Corpo do documento\"\n placeholder=\"Digite o conteúdo do template…\"\n sx={{ minHeight: usableFirstPagePx }}\n onRegister={registerRegion('body')}\n onFocus={onRegionFocus}\n onBlur={onRegionBlur}\n onInput={handleContentChanged}\n />\n </Box>\n\n {/* Moldura de redimensionamento da imagem selecionada. */}\n {editable && selectedImg && frame && (\n <Box\n data-testid=\"image-resize-frame\"\n sx={{\n position: 'absolute',\n top: frame.top,\n left: frame.left,\n width: frame.width,\n height: frame.height,\n border: '1px solid',\n borderColor: 'primary.main',\n zIndex: 3,\n pointerEvents: 'none',\n }}\n >\n {RESIZE_CORNERS.map((corner) => (\n <Box\n key={corner}\n data-testid=\"image-resize-handle\"\n onMouseDown={startResize(corner)}\n sx={{\n position: 'absolute',\n width: 10,\n height: 10,\n bgcolor: 'primary.main',\n border: '1px solid #fff',\n pointerEvents: 'auto',\n cursor:\n corner === 'nw' || corner === 'se'\n ? 'nwse-resize'\n : 'nesw-resize',\n top: corner.startsWith('n') ? -5 : 'auto',\n bottom: corner.startsWith('s') ? -5 : 'auto',\n left: corner.endsWith('w') ? -5 : 'auto',\n right: corner.endsWith('e') ? -5 : 'auto',\n }}\n />\n ))}\n </Box>\n )}\n\n {loading && (\n <Box\n sx={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n bgcolor: 'rgba(255,255,255,0.6)',\n zIndex: 3,\n }}\n >\n <CircularProgress />\n </Box>\n )}\n </Box>\n </Box>\n </Box>\n );\n }\n);\n\nexport default DocxEditor;\n","import HTMLtoDOCX from '@turbodocx/html-to-docx';\nimport JSZip from 'jszip';\nimport { Buffer as BufferPolyfill } from 'buffer';\nimport { DocumentModel, PageMarginsTwips } from '../types';\nimport { hasPageFieldTokens, injectPageFields } from './pageFields';\n\nexport const DEFAULT_MARGINS: PageMarginsTwips = {\n top: 1440,\n right: 1440,\n bottom: 1440,\n left: 1440,\n};\n\n/** Tamanho de página A4 em twips (210 × 297 mm). */\nexport const PAGE_SIZE_A4_TWIPS = { width: 11906, height: 16838 };\n\n/**\n * A @turbodocx/html-to-docx usa o global `Buffer` do Node para processar\n * imagens base64; o webpack 5 (CRA) não fornece esse global no browser.\n */\nfunction ensureBufferGlobal(): void {\n const g = globalThis as { Buffer?: unknown };\n if (typeof g.Buffer === 'undefined') g.Buffer = BufferPolyfill;\n}\n\nexport interface GenerateOptions {\n margins?: PageMarginsTwips;\n font?: string;\n}\n\n/** Normaliza a saída da lib (ArrayBuffer no Node, Blob no browser) para ArrayBuffer. */\nasync function toArrayBuffer(\n out: ArrayBuffer | Blob | Uint8Array\n): Promise<ArrayBuffer> {\n if (out instanceof ArrayBuffer) return out;\n if (typeof Blob !== 'undefined' && out instanceof Blob) {\n return out.arrayBuffer();\n }\n const u8 = out as Uint8Array;\n return u8.buffer.slice(u8.byteOffset, u8.byteOffset + u8.byteLength) as ArrayBuffer;\n}\n\n/** Envolve um fragmento HTML num documento completo, preservando a fonte padrão. */\nfunction wrapBody(bodyHtml: string): string {\n return `<!DOCTYPE html><html><head><meta charset=\"utf-8\"></head><body>${bodyHtml}</body></html>`;\n}\n\n/**\n * Serializa um DocumentModel para um .docx (ArrayBuffer).\n * O corpo, o cabeçalho e o rodapé são HTML; os placeholders {{variavel}}\n * permanecem como texto literal para substituição posterior (LibreOffice/docxtemplater).\n */\nexport async function modelToDocx(\n model: DocumentModel,\n options: GenerateOptions = {}\n): Promise<ArrayBuffer> {\n ensureBufferGlobal();\n const margins = options.margins ?? DEFAULT_MARGINS;\n const hasHeader = !!model.header && model.header.trim().length > 0;\n const hasFooter = !!model.footer && model.footer.trim().length > 0;\n\n const out = await HTMLtoDOCX(\n wrapBody(model.body),\n hasHeader ? model.header! : null,\n {\n header: hasHeader,\n footer: hasFooter,\n margins,\n pageSize: PAGE_SIZE_A4_TWIPS,\n font: options.font ?? 'Arial',\n },\n hasFooter ? model.footer! : null\n );\n\n const buffer = await toArrayBuffer(out as ArrayBuffer | Blob | Uint8Array);\n\n // Tokens [[PAGINA]]/[[TOTAL_PAGINAS]] → campos PAGE/NUMPAGES do Word.\n if (!hasPageFieldTokens(model.header) && !hasPageFieldTokens(model.footer)) {\n return buffer;\n }\n const zip = await JSZip.loadAsync(buffer);\n const partNames = Object.keys(zip.files).filter((name) =>\n /^word\\/(header|footer)\\d*\\.xml$/.test(name)\n );\n for (const name of partNames) {\n const xml = await zip.file(name)!.async('string');\n zip.file(name, injectPageFields(xml));\n }\n return zip.generateAsync({ type: 'arraybuffer' });\n}\n","/**\n * Campos de página do Word: o usuário insere tokens literais no editor e,\n * na exportação, eles viram campos nativos (`w:fldSimple`) que o Word e o\n * LibreOffice atualizam sozinhos conforme a paginação real do documento.\n *\n * Os tokens usam `[[...]]` (e não `{{...}}`) para o docxtemplater nunca\n * tentar substituí-los.\n */\n\nexport const PAGE_NUMBER_TOKEN = '[[PAGINA]]';\nexport const TOTAL_PAGES_TOKEN = '[[TOTAL_PAGINAS]]';\n\nconst FIELD_BY_TOKEN: ReadonlyArray<{ token: string; instr: string }> = [\n { token: PAGE_NUMBER_TOKEN, instr: 'PAGE' },\n { token: TOTAL_PAGES_TOKEN, instr: 'NUMPAGES' },\n];\n\n/** Há algum token de campo de página neste HTML? */\nexport function hasPageFieldTokens(html: string | undefined): boolean {\n if (!html) return false;\n return FIELD_BY_TOKEN.some(({ token }) => html.includes(token));\n}\n\nconst W_NAMESPACE =\n 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';\n\n/**\n * Casa UM run inteiro por vez. O lazy até o primeiro `</r>` nunca atravessa\n * runs (runs não aninham em OOXML) — é isso que impede o embaralhamento que\n * o regex antigo causava ao \"esticar\" o grupo do rPr por cima de runs\n * vizinhos (gerava .docx corrompido).\n */\nconst RUN_PATTERN = /<(w:)?r(?:\\s[^>]*)?>[\\s\\S]*?<\\/(?:w:)?r>/g;\n\ntype RunPart = { kind: 'text'; value: string } | { kind: 'field'; instr: string };\n\n/** Tokeniza o texto de um run em segmentos de texto e campos, na ordem. */\nfunction splitTextByTokens(text: string): RunPart[] {\n const parts: RunPart[] = [];\n let rest = text;\n while (rest.length > 0) {\n let earliest = -1;\n let found: { token: string; instr: string } | null = null;\n for (const candidate of FIELD_BY_TOKEN) {\n const i = rest.indexOf(candidate.token);\n if (i !== -1 && (earliest === -1 || i < earliest)) {\n earliest = i;\n found = candidate;\n }\n }\n if (!found) {\n parts.push({ kind: 'text', value: rest });\n break;\n }\n if (earliest > 0) parts.push({ kind: 'text', value: rest.slice(0, earliest) });\n parts.push({ kind: 'field', instr: found.instr });\n rest = rest.slice(earliest + found.token.length);\n }\n return parts;\n}\n\n/**\n * Reconstrói um run que contém tokens como uma sequência de runs de texto e\n * `fldSimple`, copiando o `rPr` original para que os campos herdem a\n * formatação. Funciona com OOXML prefixado (`<w:r>`) e em namespace default\n * sem prefixo (`<r>`, formato dos header/footer da lib).\n */\nfunction rebuildRun(runXml: string, prefix: string): string {\n const tMatch = runXml.match(/<(?:w:)?t([^>]*)>([\\s\\S]*?)<\\/(?:w:)?t>/);\n if (!tMatch) return runXml;\n const [, tAttrs, text] = tMatch;\n if (!FIELD_BY_TOKEN.some(({ token }) => text.includes(token))) return runXml;\n\n const rPrMatch = runXml.match(/<(?:w:)?rPr(?:\\/>|>[\\s\\S]*?<\\/(?:w:)?rPr>)/);\n const props = rPrMatch ? rPrMatch[0] : '';\n const p = prefix;\n const tOpen = `<${p}t${tAttrs}>`;\n const tClose = `</${p}t>`;\n // Sem prefixo (namespace default), o atributo w:instr exige a declaração\n // de xmlns:w no próprio elemento.\n const nsDecl = p ? '' : ` xmlns:w=\"${W_NAMESPACE}\"`;\n\n return splitTextByTokens(text)\n .map((part) =>\n part.kind === 'text'\n ? `<${p}r>${props}${tOpen}${part.value}${tClose}</${p}r>`\n : // \"1\" é o valor em cache exibido até o Word/LibreOffice atualizar o campo.\n `<${p}fldSimple${nsDecl} w:instr=\" ${part.instr} \">` +\n `<${p}r>${props}${tOpen}1${tClose}</${p}r></${p}fldSimple>`\n )\n .join('');\n}\n\n/** Substitui os tokens por campos PAGE/NUMPAGES num XML de header/footer. */\nexport function injectPageFields(xml: string): string {\n return xml.replace(RUN_PATTERN, (runXml, prefix: string | undefined) =>\n rebuildRun(runXml, prefix ?? '')\n );\n}\n","import mammoth from 'mammoth';\nimport { DocumentModel } from '../types';\n\n/**\n * Converte um .docx existente num DocumentModel para edição.\n *\n * Limitação conhecida: o mammoth extrai apenas o corpo do documento; cabeçalho\n * e rodapé de arquivos importados de fora não são recuperados (best-effort).\n * Para templates criados pelo próprio editor, o DocumentModel é a fonte de verdade.\n */\nexport async function bufferToModel(\n buffer: ArrayBuffer\n): Promise<DocumentModel> {\n // O build node do mammoth aceita `buffer`; o build browser aceita `arrayBuffer`.\n // `Buffer` só existe no Node, então serve para distinguir os ambientes.\n const input =\n typeof Buffer !== 'undefined'\n ? { buffer: Buffer.from(buffer) }\n : { arrayBuffer: buffer };\n\n const { value: bodyHtml } = await mammoth.convertToHtml(input as never);\n\n return {\n body: bodyHtml,\n };\n}\n","/**\n * Cálculo puro de quebras de página por bloco (sem DOM).\n *\n * Coordenadas no espaço do corpo contínuo: a área útil da página N (0-based)\n * ocupa [N*(usable+gap), N*(usable+gap) + usable]. A \"zona morta\" entre áreas\n * úteis (rodapé + espaço visual entre páginas + cabeçalho) tem altura `gap`.\n */\n\nexport interface BlockBox {\n /**\n * Posição do topo do bloco em relação ao início do corpo (px, sem zoom),\n * em coordenadas SEM espaçadores: quem mede o DOM com espaçadores presentes\n * deve subtrair a altura acumulada dos espaçadores acima do bloco.\n */\n top: number;\n /** offsetHeight do bloco (px, sem zoom). */\n height: number;\n}\n\nexport interface PaginationMetrics {\n /** Altura útil do corpo por página (px). */\n usableHeightPx: number;\n /** Altura da zona morta entre áreas úteis de páginas consecutivas (px). */\n interPageGapPx: number;\n}\n\nexport interface PageSpacer {\n /** Índice do bloco que deve ser empurrado para a próxima página. */\n beforeBlockIndex: number;\n /** Altura do espaçador (px). */\n heightPx: number;\n}\n\nexport interface PageLayout {\n spacers: PageSpacer[];\n pageCount: number;\n}\n\nexport function computePageLayout(\n blocks: BlockBox[],\n metrics: PaginationMetrics\n): PageLayout {\n const { usableHeightPx, interPageGapPx } = metrics;\n const stride = usableHeightPx + interPageGapPx;\n const spacers: PageSpacer[] = [];\n let added = 0; // altura acumulada dos espaçadores já decididos\n let maxEnd = 0;\n\n blocks.forEach((block, index) => {\n let start = block.top + added;\n const page = Math.floor(start / stride);\n const regionStart = page * stride;\n const regionEnd = regionStart + usableHeightPx;\n const fitsInAPage = block.height <= usableHeightPx;\n const crossesBottom = start + block.height > regionEnd;\n\n // Empurra para a próxima página se o bloco começa na zona morta, ou se\n // cruzaria o rodapé e cabe inteiro numa página (blocos indivisíveis\n // maiores que a área útil ficam onde estão).\n if (start >= regionEnd || (crossesBottom && fitsInAPage && start > regionStart)) {\n const nextStart = (page + 1) * stride;\n const height = nextStart - start;\n spacers.push({ beforeBlockIndex: index, heightPx: height });\n added += height;\n start = nextStart;\n }\n\n maxEnd = Math.max(maxEnd, start + block.height);\n });\n\n const pageCount = Math.max(1, Math.floor(Math.max(0, maxEnd - 1) / stride) + 1);\n return { spacers, pageCount };\n}\n\n/** Atributo que marca os espaçadores de paginação no DOM do corpo. */\nexport const PAGE_SPACER_ATTR = 'data-page-spacer';\n\n/** Cria o elemento espaçador não-editável inserido antes de um bloco empurrado. */\nexport function createSpacerElement(heightPx: number): HTMLElement {\n const el = document.createElement('div');\n el.setAttribute(PAGE_SPACER_ATTR, 'true');\n el.setAttribute('contenteditable', 'false');\n el.setAttribute('aria-hidden', 'true');\n el.style.height = `${heightPx}px`;\n el.style.userSelect = 'none';\n el.style.pointerEvents = 'none';\n return el;\n}\n\n/** Remove os espaçadores de paginação de um HTML de corpo (para salvar/getModel). */\nexport function stripPageSpacers(html: string): string {\n const tmp = document.createElement('div');\n tmp.innerHTML = html;\n tmp.querySelectorAll(`[${PAGE_SPACER_ATTR}]`).forEach((n) => n.remove());\n return tmp.innerHTML;\n}\n","/**\n * Comandos de edição sobre regiões contentEditable.\n *\n * Usa document.execCommand (depreciado, porém suportado em todos os browsers\n * atuais) por ser o caminho pragmático para um editor \"do zero\" sem framework\n * de edição. A inserção de variável usa a Range API diretamente para ser\n * determinística (e testável fora de browser real).\n */\n\n/** Executa um comando de formatação, preferindo estilos inline (CSS). */\nexport function execFormat(command: string, value?: string): void {\n document.execCommand('styleWithCSS', false, 'true');\n document.execCommand(command, false, value);\n}\n\n/**\n * Aplica tamanho de fonte em pt à seleção.\n * execCommand('fontSize') só aceita os tamanhos legados 1..7, então usamos o\n * valor 7 como marcador e trocamos os <font size=\"7\"> gerados por spans com\n * font-size real em pt.\n */\nexport function setFontSize(region: HTMLElement, pt: number): void {\n document.execCommand('styleWithCSS', false, 'false');\n document.execCommand('fontSize', false, '7');\n const marked = region.querySelectorAll('font[size=\"7\"]');\n marked.forEach((el) => {\n el.removeAttribute('size');\n (el as HTMLElement).style.fontSize = `${pt}pt`;\n });\n}\n\n/** Aplica família de fonte à seleção. */\nexport function setFontFamily(family: string): void {\n document.execCommand('styleWithCSS', false, 'true');\n document.execCommand('fontName', false, family);\n}\n\n/**\n * Insere texto (ex.: \"{{patientName}}\") na região.\n * Se houver uma seleção dentro da região, insere no cursor; caso contrário,\n * anexa ao fim da região.\n */\nexport function insertTextIntoRegion(region: HTMLElement, text: string): void {\n region.focus();\n const selection = window.getSelection();\n const node = document.createTextNode(text);\n\n if (\n selection &&\n selection.rangeCount > 0 &&\n selection.anchorNode &&\n region.contains(selection.anchorNode)\n ) {\n const range = selection.getRangeAt(0);\n range.deleteContents();\n range.insertNode(node);\n range.setStartAfter(node);\n range.setEndAfter(node);\n selection.removeAllRanges();\n selection.addRange(range);\n } else {\n region.appendChild(node);\n }\n}\n","/**\n * Conversões de unidade para layout do documento.\n *\n * Referência: 1 polegada = 1440 twips = 96px (CSS) = 2.54 cm = 72 pt.\n * O OOXML (Word) usa twips para margens e recuos (w:ind), então a régua\n * converte a posição em px do usuário para twips ao exportar.\n */\n\nexport const TWIPS_PER_INCH = 1440;\nexport const PX_PER_INCH = 96;\nexport const CM_PER_INCH = 2.54;\nexport const POINTS_PER_INCH = 72;\n\nexport function pxToTwips(px: number): number {\n return Math.round((px / PX_PER_INCH) * TWIPS_PER_INCH);\n}\n\nexport function twipsToPx(twips: number): number {\n return (twips / TWIPS_PER_INCH) * PX_PER_INCH;\n}\n\nexport function cmToTwips(cm: number): number {\n return Math.round((cm / CM_PER_INCH) * TWIPS_PER_INCH);\n}\n\nexport function twipsToCm(twips: number): number {\n return (twips / TWIPS_PER_INCH) * CM_PER_INCH;\n}\n\nexport function inchesToTwips(inches: number): number {\n return Math.round(inches * TWIPS_PER_INCH);\n}\n\nexport function pointsToTwips(points: number): number {\n return Math.round((points / POINTS_PER_INCH) * TWIPS_PER_INCH);\n}\n","import { useRef, useState } from 'react';\nimport {\n Box,\n Divider,\n IconButton,\n Menu,\n MenuItem,\n Select,\n Tooltip,\n Button,\n Typography,\n} from '@mui/material';\nimport UndoIcon from '@mui/icons-material/Undo';\nimport RedoIcon from '@mui/icons-material/Redo';\nimport FormatBoldIcon from '@mui/icons-material/FormatBold';\nimport FormatItalicIcon from '@mui/icons-material/FormatItalic';\nimport FormatUnderlinedIcon from '@mui/icons-material/FormatUnderlined';\nimport StrikethroughSIcon from '@mui/icons-material/StrikethroughS';\nimport FormatColorTextIcon from '@mui/icons-material/FormatColorText';\nimport BorderColorIcon from '@mui/icons-material/BorderColor';\nimport LinkIcon from '@mui/icons-material/Link';\nimport SuperscriptIcon from '@mui/icons-material/Superscript';\nimport SubscriptIcon from '@mui/icons-material/Subscript';\nimport FormatAlignLeftIcon from '@mui/icons-material/FormatAlignLeft';\nimport FormatAlignCenterIcon from '@mui/icons-material/FormatAlignCenter';\nimport FormatAlignRightIcon from '@mui/icons-material/FormatAlignRight';\nimport FormatAlignJustifyIcon from '@mui/icons-material/FormatAlignJustify';\nimport FormatListBulletedIcon from '@mui/icons-material/FormatListBulleted';\nimport FormatListNumberedIcon from '@mui/icons-material/FormatListNumbered';\nimport FormatIndentDecreaseIcon from '@mui/icons-material/FormatIndentDecrease';\nimport FormatIndentIncreaseIcon from '@mui/icons-material/FormatIndentIncrease';\nimport FormatClearIcon from '@mui/icons-material/FormatClear';\nimport ImageIcon from '@mui/icons-material/Image';\nimport DataObjectIcon from '@mui/icons-material/DataObject';\nimport AddIcon from '@mui/icons-material/Add';\nimport RemoveIcon from '@mui/icons-material/Remove';\n\nconst FONT_FAMILIES = [\n 'Arial',\n 'Times New Roman',\n 'Calibri',\n 'Courier New',\n 'Georgia',\n 'Verdana',\n];\n\nconst BLOCK_FORMATS: Array<{ label: string; tag: string }> = [\n { label: 'Texto normal', tag: 'P' },\n { label: 'Título 1', tag: 'H1' },\n { label: 'Título 2', tag: 'H2' },\n { label: 'Título 3', tag: 'H3' },\n];\n\nexport interface ToolbarProps {\n onCommand: (command: string, value?: string) => void;\n onFontFamily: (family: string) => void;\n onFontSize: (pt: number) => void;\n onFormatBlock: (tag: string) => void;\n onColor: (color: string) => void;\n onHighlight: (color: string) => void;\n onLink: () => void;\n onInsertImage: () => void;\n onInsertVariable: (name: string) => void;\n onInsertPageField: (field: 'pageNumber' | 'totalPages') => void;\n variables: string[];\n}\n\nfunction Toolbar(props: ToolbarProps) {\n const [fontFamily, setFontFamilyState] = useState('Arial');\n const [fontSize, setFontSizeState] = useState(11);\n const [blockTag, setBlockTag] = useState('P');\n\n const [varAnchor, setVarAnchor] = useState<null | HTMLElement>(null);\n const colorInputRef = useRef<HTMLInputElement>(null);\n const highlightInputRef = useRef<HTMLInputElement>(null);\n\n const changeFontSize = (next: number) => {\n const clamped = Math.min(96, Math.max(1, next));\n setFontSizeState(clamped);\n props.onFontSize(clamped);\n };\n\n return (\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n flexWrap: 'wrap',\n gap: 0.5,\n px: 1,\n py: 0.5,\n borderBottom: 1,\n borderColor: 'divider',\n bgcolor: 'background.paper',\n }}\n // Impede que clicar na toolbar tire o foco (e a seleção) da região.\n onMouseDown={(e) => e.preventDefault()}\n >\n <Tooltip title=\"Desfazer\">\n <IconButton size=\"small\" onClick={() => props.onCommand('undo')}>\n <UndoIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Refazer\">\n <IconButton size=\"small\" onClick={() => props.onCommand('redo')}>\n <RedoIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n\n <Divider orientation=\"vertical\" flexItem sx={{ mx: 0.5 }} />\n\n <Select\n size=\"small\"\n value={blockTag}\n onChange={(e) => {\n setBlockTag(e.target.value);\n props.onFormatBlock(e.target.value);\n }}\n sx={{ minWidth: 130, height: 32 }}\n >\n {BLOCK_FORMATS.map((b) => (\n <MenuItem key={b.tag} value={b.tag}>\n {b.label}\n </MenuItem>\n ))}\n </Select>\n\n <Select\n size=\"small\"\n value={fontFamily}\n onChange={(e) => {\n setFontFamilyState(e.target.value);\n props.onFontFamily(e.target.value);\n }}\n sx={{ minWidth: 130, height: 32 }}\n >\n {FONT_FAMILIES.map((f) => (\n <MenuItem key={f} value={f} style={{ fontFamily: f }}>\n {f}\n </MenuItem>\n ))}\n </Select>\n\n <Box sx={{ display: 'flex', alignItems: 'center' }}>\n <Tooltip title=\"Diminuir fonte\">\n <IconButton size=\"small\" onClick={() => changeFontSize(fontSize - 1)}>\n <RemoveIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Typography\n component=\"span\"\n sx={{\n minWidth: 24,\n textAlign: 'center',\n fontVariantNumeric: 'tabular-nums',\n }}\n >\n {fontSize}\n </Typography>\n <Tooltip title=\"Aumentar fonte\">\n <IconButton size=\"small\" onClick={() => changeFontSize(fontSize + 1)}>\n <AddIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n </Box>\n\n <Divider orientation=\"vertical\" flexItem sx={{ mx: 0.5 }} />\n\n <Tooltip title=\"Negrito\">\n <IconButton size=\"small\" onClick={() => props.onCommand('bold')}>\n <FormatBoldIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Itálico\">\n <IconButton size=\"small\" onClick={() => props.onCommand('italic')}>\n <FormatItalicIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Sublinhado\">\n <IconButton size=\"small\" onClick={() => props.onCommand('underline')}>\n <FormatUnderlinedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Tachado\">\n <IconButton\n size=\"small\"\n onClick={() => props.onCommand('strikeThrough')}\n >\n <StrikethroughSIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n\n <Tooltip title=\"Cor do texto\">\n <IconButton size=\"small\" onClick={() => colorInputRef.current?.click()}>\n <FormatColorTextIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <input\n ref={colorInputRef}\n type=\"color\"\n aria-label=\"Cor do texto\"\n style={{ display: 'none' }}\n onChange={(e) => props.onColor(e.target.value)}\n />\n <Tooltip title=\"Realce\">\n <IconButton\n size=\"small\"\n onClick={() => highlightInputRef.current?.click()}\n >\n <BorderColorIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <input\n ref={highlightInputRef}\n type=\"color\"\n aria-label=\"Cor de realce\"\n style={{ display: 'none' }}\n onChange={(e) => props.onHighlight(e.target.value)}\n />\n\n <Tooltip title=\"Inserir link\">\n <IconButton size=\"small\" onClick={props.onLink}>\n <LinkIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Sobrescrito\">\n <IconButton size=\"small\" onClick={() => props.onCommand('superscript')}>\n <SuperscriptIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Subscrito\">\n <IconButton size=\"small\" onClick={() => props.onCommand('subscript')}>\n <SubscriptIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n\n <Divider orientation=\"vertical\" flexItem sx={{ mx: 0.5 }} />\n\n <Tooltip title=\"Alinhar à esquerda\">\n <IconButton size=\"small\" onClick={() => props.onCommand('justifyLeft')}>\n <FormatAlignLeftIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Centralizar\">\n <IconButton\n size=\"small\"\n onClick={() => props.onCommand('justifyCenter')}\n >\n <FormatAlignCenterIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Alinhar à direita\">\n <IconButton\n size=\"small\"\n onClick={() => props.onCommand('justifyRight')}\n >\n <FormatAlignRightIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Justificar\">\n <IconButton size=\"small\" onClick={() => props.onCommand('justifyFull')}>\n <FormatAlignJustifyIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n\n <Tooltip title=\"Lista com marcadores\">\n <IconButton\n size=\"small\"\n onClick={() => props.onCommand('insertUnorderedList')}\n >\n <FormatListBulletedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Lista numerada\">\n <IconButton\n size=\"small\"\n onClick={() => props.onCommand('insertOrderedList')}\n >\n <FormatListNumberedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Diminuir recuo\">\n <IconButton size=\"small\" onClick={() => props.onCommand('outdent')}>\n <FormatIndentDecreaseIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Aumentar recuo\">\n <IconButton size=\"small\" onClick={() => props.onCommand('indent')}>\n <FormatIndentIncreaseIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n\n <Divider orientation=\"vertical\" flexItem sx={{ mx: 0.5 }} />\n\n <Tooltip title=\"Inserir imagem\">\n <IconButton size=\"small\" onClick={props.onInsertImage}>\n <ImageIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Tooltip title=\"Limpar formatação\">\n <IconButton\n size=\"small\"\n onClick={() => props.onCommand('removeFormat')}\n >\n <FormatClearIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n\n <Button\n size=\"small\"\n variant=\"outlined\"\n startIcon={<DataObjectIcon />}\n onClick={(e) => setVarAnchor(e.currentTarget)}\n sx={{ ml: 0.5, textTransform: 'none' }}\n >\n Variável\n </Button>\n <Menu\n anchorEl={varAnchor}\n open={Boolean(varAnchor)}\n onClose={() => setVarAnchor(null)}\n >\n {props.variables.map((name) => (\n <MenuItem\n key={name}\n onClick={() => {\n props.onInsertVariable(name);\n setVarAnchor(null);\n }}\n >\n {name}\n </MenuItem>\n ))}\n {props.variables.length > 0 && <Divider />}\n <MenuItem\n onClick={() => {\n props.onInsertPageField('pageNumber');\n setVarAnchor(null);\n }}\n >\n Nº da página\n </MenuItem>\n <MenuItem\n onClick={() => {\n props.onInsertPageField('totalPages');\n setVarAnchor(null);\n }}\n >\n Total de páginas\n </MenuItem>\n </Menu>\n </Box>\n );\n}\n\nexport default Toolbar;\n","import { Select, MenuItem } from '@mui/material';\n\nconst ZOOM_LEVELS = [0.5, 0.75, 0.9, 1, 1.25, 1.5, 2];\n\nexport interface ZoomControlProps {\n zoom: number;\n onChange: (zoom: number) => void;\n}\n\nfunction ZoomControl(props: ZoomControlProps) {\n return (\n <Select\n size=\"small\"\n value={props.zoom}\n onChange={(e) => props.onChange(Number(e.target.value))}\n aria-label=\"Zoom\"\n sx={{ height: 32, minWidth: 88 }}\n >\n {ZOOM_LEVELS.map((z) => (\n <MenuItem key={z} value={z}>\n {Math.round(z * 100)}%\n </MenuItem>\n ))}\n </Select>\n );\n}\n\nexport default ZoomControl;\n","import { useCallback, useRef } from 'react';\nimport { Box } from '@mui/material';\nimport { PageMarginsTwips } from './types';\nimport { pxToTwips, twipsToPx, PX_PER_INCH } from './docx/units';\n\nexport interface ParagraphIndentTwips {\n firstLine: number;\n left: number;\n right: number;\n}\n\nexport interface RulerProps {\n /** Largura total da página em px a 100% de zoom. */\n pageWidthPx: number;\n zoom: number;\n margins: PageMarginsTwips;\n indent: ParagraphIndentTwips;\n onMarginsChange: (margins: PageMarginsTwips) => void;\n onIndentChange: (indent: ParagraphIndentTwips) => void;\n}\n\nconst RULER_HEIGHT = 24;\n\ntype DragKind =\n | 'leftMargin'\n | 'rightMargin'\n | 'firstLineIndent'\n | 'leftIndent'\n | 'rightIndent';\n\nfunction Ruler(props: RulerProps) {\n const { pageWidthPx, zoom, margins, indent } = props;\n const barRef = useRef<HTMLDivElement>(null);\n const scaledWidth = pageWidthPx * zoom;\n\n // px (na tela) -> twips (independente do zoom)\n const screenPxToTwips = useCallback(\n (px: number) => pxToTwips(px / zoom),\n [zoom]\n );\n\n const leftMarginPx = twipsToPx(margins.left) * zoom;\n const rightMarginFromLeftPx =\n (pageWidthPx - twipsToPx(margins.right)) * zoom;\n const firstLinePx =\n (twipsToPx(margins.left) + twipsToPx(indent.firstLine)) * zoom;\n const leftIndentPx =\n (twipsToPx(margins.left) + twipsToPx(indent.left)) * zoom;\n const rightIndentPx =\n (pageWidthPx - twipsToPx(margins.right) - twipsToPx(indent.right)) * zoom;\n\n const startDrag = (kind: DragKind) => (e: React.MouseEvent) => {\n e.preventDefault();\n const bar = barRef.current;\n if (!bar) return;\n\n const onMove = (ev: MouseEvent) => {\n const rect = bar.getBoundingClientRect();\n const x = Math.min(Math.max(ev.clientX - rect.left, 0), scaledWidth);\n const twipsFromLeft = screenPxToTwips(x);\n const pageWidthTwips = pxToTwips(pageWidthPx);\n\n switch (kind) {\n case 'leftMargin': {\n const left = Math.min(twipsFromLeft, pageWidthTwips - margins.right - 720);\n props.onMarginsChange({ ...margins, left: Math.max(0, left) });\n break;\n }\n case 'rightMargin': {\n const right = Math.min(\n pageWidthTwips - twipsFromLeft,\n pageWidthTwips - margins.left - 720\n );\n props.onMarginsChange({ ...margins, right: Math.max(0, right) });\n break;\n }\n case 'firstLineIndent': {\n props.onIndentChange({\n ...indent,\n firstLine: Math.max(0, twipsFromLeft - margins.left),\n });\n break;\n }\n case 'leftIndent': {\n props.onIndentChange({\n ...indent,\n left: Math.max(0, twipsFromLeft - margins.left),\n });\n break;\n }\n case 'rightIndent': {\n props.onIndentChange({\n ...indent,\n right: Math.max(0, pageWidthTwips - margins.right - twipsFromLeft),\n });\n break;\n }\n }\n };\n\n const onUp = () => {\n window.removeEventListener('mousemove', onMove);\n window.removeEventListener('mouseup', onUp);\n };\n window.addEventListener('mousemove', onMove);\n window.addEventListener('mouseup', onUp);\n };\n\n const ticks = [];\n const inches = Math.floor(pageWidthPx / PX_PER_INCH);\n for (let i = 0; i <= inches; i++) {\n ticks.push(\n <Box\n key={i}\n sx={{\n position: 'absolute',\n left: i * PX_PER_INCH * zoom,\n top: 0,\n bottom: 0,\n borderLeft: '1px solid',\n borderColor: 'text.disabled',\n fontSize: 9,\n color: 'text.secondary',\n pl: '2px',\n }}\n >\n {i}\n </Box>\n );\n }\n\n const marginHandleSx = {\n position: 'absolute' as const,\n top: 0,\n width: 8,\n height: RULER_HEIGHT,\n cursor: 'ew-resize',\n bgcolor: 'primary.main',\n opacity: 0.6,\n transform: 'translateX(-50%)',\n '&:hover': { opacity: 1 },\n };\n\n const indentHandleSx = {\n position: 'absolute' as const,\n width: 0,\n height: 0,\n cursor: 'ew-resize',\n borderLeft: '6px solid transparent',\n borderRight: '6px solid transparent',\n transform: 'translateX(-50%)',\n };\n\n return (\n <Box\n ref={barRef}\n sx={{\n position: 'relative',\n height: RULER_HEIGHT,\n width: scaledWidth,\n bgcolor: 'grey.100',\n borderBottom: 1,\n borderColor: 'divider',\n userSelect: 'none',\n mx: 'auto',\n }}\n role=\"presentation\"\n aria-label=\"Régua\"\n >\n {ticks}\n\n {/* Área fora das margens sombreada */}\n <Box\n sx={{\n position: 'absolute',\n left: 0,\n top: 0,\n bottom: 0,\n width: leftMarginPx,\n bgcolor: 'grey.300',\n opacity: 0.5,\n }}\n />\n <Box\n sx={{\n position: 'absolute',\n left: rightMarginFromLeftPx,\n right: 0,\n top: 0,\n bottom: 0,\n bgcolor: 'grey.300',\n opacity: 0.5,\n }}\n />\n\n {/* Marcadores de margem de página */}\n <Box\n sx={{ ...marginHandleSx, left: leftMarginPx }}\n onMouseDown={startDrag('leftMargin')}\n aria-label=\"Margem esquerda\"\n />\n <Box\n sx={{ ...marginHandleSx, left: rightMarginFromLeftPx }}\n onMouseDown={startDrag('rightMargin')}\n aria-label=\"Margem direita\"\n />\n\n {/* Recuo de primeira linha (triângulo apontando para baixo, no topo) */}\n <Box\n sx={{\n ...indentHandleSx,\n left: firstLinePx,\n top: 0,\n borderTop: '7px solid',\n borderTopColor: 'primary.dark',\n }}\n onMouseDown={startDrag('firstLineIndent')}\n aria-label=\"Recuo da primeira linha\"\n />\n {/* Recuo à esquerda (triângulo apontando para cima, na base) */}\n <Box\n sx={{\n ...indentHandleSx,\n left: leftIndentPx,\n bottom: 0,\n borderBottom: '7px solid',\n borderBottomColor: 'primary.dark',\n }}\n onMouseDown={startDrag('leftIndent')}\n aria-label=\"Recuo à esquerda\"\n />\n {/* Recuo à direita (triângulo apontando para cima, na base) */}\n <Box\n sx={{\n ...indentHandleSx,\n left: rightIndentPx,\n bottom: 0,\n borderBottom: '7px solid',\n borderBottomColor: 'primary.dark',\n }}\n onMouseDown={startDrag('rightIndent')}\n aria-label=\"Recuo à direita\"\n />\n </Box>\n );\n}\n\nexport default Ruler;\n"],"mappings":"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","names":["useCallback","useRef","useState","Box","Select","MenuItem","jsx","jsxs","useRef","Box","jsx","jsxs","useRef","Box","jsx","jsxs","Box","DocxEditor","useState","useRef","useCallback"]}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "mgcode-docx-editor",
3
+ "version": "0.1.0",
4
+ "description": "WYSIWYG .docx template editor (React) with {{variable}} placeholder support, built for docxtemplater/LibreOffice pipelines.",
5
+ "license": "MIT",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "sideEffects": false,
20
+ "scripts": {
21
+ "build": "tsup",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "typecheck": "tsc --noEmit",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "peerDependencies": {
28
+ "react": "^18.0.0 || ^19.0.0",
29
+ "react-dom": "^18.0.0 || ^19.0.0",
30
+ "@mui/material": "^9.0.0",
31
+ "@mui/icons-material": "^9.0.0",
32
+ "@emotion/react": "^11.0.0",
33
+ "@emotion/styled": "^11.0.0"
34
+ },
35
+ "dependencies": {
36
+ "@turbodocx/html-to-docx": "^1.22.0",
37
+ "buffer": "^6.0.3",
38
+ "jszip": "^3.10.1",
39
+ "mammoth": "^1.12.0"
40
+ },
41
+ "devDependencies": {
42
+ "@emotion/react": "^11.14.0",
43
+ "@emotion/styled": "^11.14.1",
44
+ "@mui/icons-material": "^9.2.0",
45
+ "@mui/material": "^9.2.0",
46
+ "@testing-library/jest-dom": "^6.9.1",
47
+ "@testing-library/react": "^16.3.2",
48
+ "@testing-library/user-event": "^14.6.1",
49
+ "@types/react": "^19.2.17",
50
+ "@types/react-dom": "^19.2.3",
51
+ "jsdom": "^25.0.1",
52
+ "react": "^19.2.7",
53
+ "react-dom": "^19.2.7",
54
+ "tsup": "^8.3.5",
55
+ "typescript": "^5.9.3",
56
+ "vitest": "^2.1.9"
57
+ }
58
+ }