@apollo-design/react-docx-preview 0.1.0 → 0.2.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.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/hooks/useDocViewer.ts","../src/context.ts","../src/components/icons/IconThumbs.tsx","../src/components/icons/IconPrevPage.tsx","../src/components/icons/IconNextPage.tsx","../src/components/icons/IconZoomOut.tsx","../src/components/icons/IconZoomIn.tsx","../src/components/icons/IconChevronDown.tsx","../src/components/icons/IconOpenFile.tsx","../src/components/icons/IconDownload.tsx","../src/components/Toolbar.tsx","../src/components/ErrorBanner.tsx","../src/components/ThumbnailsSidebar.tsx","../src/components/DocumentStage.tsx","../src/DocxViewer.tsx"],"sourcesContent":["// Core viewer logic, ported from apps/viewer/viewer.js. UI-facing values are\n// React state; everything else (library render output, thumbnail clones, page\n// corners, zoom transforms) is imperative DOM work against element refs.\n// A ref mirror (stateRef) lets the once-registered global listeners read\n// fresh values.\nimport { useEffect, useRef, useState } from 'react';\nimport type { RefObject } from 'react';\nimport { renderAsync } from '@apollo-design/docx-preview';\nimport type { Options } from '@apollo-design/docx-preview';\n\n// Zoom-button range. Stepping clamps here so a step never strands the\n// buttons in a disabled state.\nconst SCALE_MIN = 0.1;\nconst SCALE_MAX = 4;\nconst SCALE_STEP = 0.25;\n// Fit-width never upscales: a document reads best at its natural size.\nconst FIT_MAX = 1;\nconst STAGE_PADDING = 24; // .stage padding on each side, see viewer.css\nconst THUMB_WIDTH = 96; // matches .thumb-page width in viewer.css\nconst CORNER_NAMES = ['tl', 'tr', 'bl', 'br'] as const;\n\nexport interface DocxViewerRefs {\n stage: RefObject<HTMLElement | null>;\n docBox: RefObject<HTMLElement | null>;\n thumbs: RefObject<HTMLElement | null>;\n}\n\nexport interface DocxViewerOptions {\n /** 'fit' (fit-width, never upscales) or a number like 0.75 / 75 */\n initialScale?: 'fit' | number;\n /** initial thumbnail sidebar visibility (default true) */\n showThumbs?: boolean;\n /** library render options, merged over { hideWrapperOnPrint, paginate, experimental } */\n renderOptions?: Partial<Options>;\n onRendered?: (result: unknown) => void;\n onError?: (error: unknown) => void;\n}\n\n// OLE2 compound-file magic (D0 CF 11 E0 ...): legacy binary documents —\n// old .doc, and .wps as still saved by default even by recent WPS Office.\nfunction isLegacyBinary(buffer: ArrayBuffer): boolean {\n if (!buffer || buffer.byteLength < 4) return false;\n const b = new Uint8Array(buffer, 0, 4);\n return b[0] === 0xd0 && b[1] === 0xcf && b[2] === 0x11 && b[3] === 0xe0;\n}\n\nfunction errorText(err: unknown): string {\n if (err && typeof err === 'object' && 'message' in err) return String((err as Error).message);\n return String(err);\n}\n\nfunction initialScaleMode(value: 'fit' | number | undefined): 'fit' | number {\n if (typeof value === 'number' && isFinite(value) && value > 0) {\n const n = value > 10 ? value / 100 : value;\n return Math.max(SCALE_MIN, Math.min(SCALE_MAX, Math.round(n * 100) / 100));\n }\n return 'fit';\n}\n\nexport function useDocViewer(refs: DocxViewerRefs, options: DocxViewerOptions = {}) {\n // ── UI state ───────────────────────────────────────────────────────────\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<{ title: string; detail: string } | null>(null);\n const [docLoaded, setDocLoaded] = useState(false);\n const [currentPage, setCurrentPage] = useState(0);\n const [pageCount, setPageCount] = useState(0);\n const [currentScale, setCurrentScale] = useState(1);\n const [scaleMode, setScaleMode] = useState<'fit' | number>(() => initialScaleMode(options.initialScale));\n const [thumbsVisible, setThumbsVisible] = useState(options.showThumbs !== false);\n const [dropdownOpen, setDropdownOpen] = useState(false);\n\n // ── Mutable internals (live DOM produced by the library) ───────────────\n const it = useRef({\n docName: '',\n // The opened document kept as a Blob so the download button works\n // regardless of the input type (Blob / ArrayBuffer / Uint8Array).\n docBlob: null as Blob | null,\n wrapperEl: null as HTMLElement | null,\n sections: [] as HTMLElement[],\n naturalWidth: 0,\n naturalHeight: 0,\n currentPage: 0, // authoritative copy (state mirrors it for rendering)\n pageObserver: null as IntersectionObserver | null,\n thumbPageSynced: -1,\n });\n // Latest-value mirror for the once-registered global listeners.\n const stateRef = useRef({ docLoaded, currentPage, scaleMode, thumbsVisible, currentScale });\n stateRef.current = { docLoaded, currentPage, scaleMode, thumbsVisible, currentScale };\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const pagerShown = pageCount > 1;\n const thumbsShown = thumbsVisible && pageCount > 1 && docLoaded;\n const canPrev = docLoaded && currentPage > 0;\n const canNext = docLoaded && currentPage < pageCount - 1;\n const canZoomOut = docLoaded && currentScale > SCALE_MIN + 1e-6;\n const canZoomIn = docLoaded && currentScale < SCALE_MAX - 1e-6;\n const scaleLabel = scaleMode === 'fit' ? '适应宽度' : Math.round(scaleMode * 100) + '%';\n\n // ── Thumbnails ─────────────────────────────────────────────────────────\n // Deep clones of page sections shrunk with a CSS transform — no re-render.\n\n function syncThumbs() {\n const box = refs.thumbs.current;\n if (!box) return;\n const items = box.children;\n const page = it.current.currentPage;\n for (let i = 0; i < items.length; i++) {\n items[i].classList.toggle('current', Number(items[i].getAttribute('data-page')) === page);\n }\n const shown = stateRef.current.thumbsVisible && items.length > 1 && stateRef.current.docLoaded;\n if (shown && it.current.thumbPageSynced !== page && items[page]) {\n it.current.thumbPageSynced = page;\n (items[page] as HTMLElement).scrollIntoView({ block: 'nearest' });\n }\n }\n\n function buildThumbs() {\n const box = refs.thumbs.current;\n if (!box) return;\n box.innerHTML = '';\n it.current.thumbPageSynced = -1;\n const sections = it.current.sections;\n if (sections.length <= 1 || !it.current.naturalWidth) return;\n\n const scale = (THUMB_WIDTH - 2) / it.current.naturalWidth; // 2px = .thumb-page borders\n for (let i = 0; i < sections.length; i++) {\n const item = document.createElement('div');\n item.className = 'thumb';\n item.setAttribute('data-page', String(i));\n\n const page = document.createElement('div');\n page.className = 'thumb-page';\n page.style.height = Math.ceil(sections[i].offsetHeight * scale) + 'px';\n\n const clone = sections[i].cloneNode(true) as HTMLElement;\n clone.removeAttribute('data-page');\n clone.style.transform = 'scale(' + scale + ')';\n clone.style.transformOrigin = 'top left';\n page.appendChild(clone);\n\n const label = document.createElement('div');\n label.className = 'thumb-label';\n label.textContent = String(i + 1);\n\n item.appendChild(page);\n item.appendChild(label);\n box.appendChild(item);\n }\n syncThumbs();\n }\n\n // ── Zoom ───────────────────────────────────────────────────────────────\n // Zoom is pure CSS: the library renders once at natural size, and we scale\n // .docx-wrapper with a transform inside an explicitly-sized box.\n\n function fitScale() {\n const stage = refs.stage.current;\n if (!it.current.naturalWidth || !stage) return 1;\n const avail = stage.clientWidth - STAGE_PADDING * 2;\n return Math.min(FIT_MAX, avail / it.current.naturalWidth);\n }\n\n function applyScale() {\n const stage = refs.stage.current;\n const docBox = refs.docBox.current;\n const wrapperEl = it.current.wrapperEl;\n const naturalWidth = it.current.naturalWidth;\n if (!stateRef.current.docLoaded || !wrapperEl || !naturalWidth || !stage || !docBox) return;\n\n // Keep the same relative scroll position across the zoom change.\n const maxY = stage.scrollHeight - stage.clientHeight;\n const maxX = stage.scrollWidth - stage.clientWidth;\n const ratioY = maxY > 0 ? stage.scrollTop / maxY : 0;\n const ratioX = maxX > 0 ? stage.scrollLeft / maxX : 0;\n\n const mode = stateRef.current.scaleMode;\n const scale = mode === 'fit' ? fitScale() : mode;\n setCurrentScale(scale);\n docBox.style.width = Math.ceil(naturalWidth * scale) + 'px';\n docBox.style.height = Math.ceil(it.current.naturalHeight * scale) + 'px';\n // Pin the wrapper to the natural content width so the top-left-origin\n // transform lines up exactly with the zoom box.\n wrapperEl.style.width = naturalWidth + 'px';\n wrapperEl.style.transform = 'scale(' + scale + ')';\n wrapperEl.style.transformOrigin = 'top left';\n\n const newMaxY = stage.scrollHeight - stage.clientHeight;\n const newMaxX = stage.scrollWidth - stage.clientWidth;\n if (newMaxY > 0) stage.scrollTop = ratioY * newMaxY;\n if (newMaxX > 0) stage.scrollLeft = ratioX * newMaxX;\n }\n\n function zoomStep(direction: 1 | -1) {\n // currentScale carries sub-pixel fit error (e.g. 0.99998); snap to the\n // nearest grid line within tolerance first, or the buttons look dead.\n let steps = stateRef.current.currentScale / SCALE_STEP;\n const nearest = Math.round(steps);\n if (Math.abs(steps - nearest) < 0.01) steps = nearest;\n const next = direction > 0 ? (Math.floor(steps) + 1) * SCALE_STEP : (Math.ceil(steps) - 1) * SCALE_STEP;\n applyScaleWith(Math.max(SCALE_MIN, Math.min(SCALE_MAX, Math.round(next * 100) / 100)));\n }\n\n // applyScale reads scaleMode from stateRef; callers that just changed the\n // mode must update the mirror first (setScaleMode alone lands next render).\n function applyScaleWith(mode: 'fit' | number) {\n stateRef.current.scaleMode = mode;\n setScaleMode(mode);\n applyScale();\n }\n\n function setScale(value: string) {\n setDropdownOpen(false);\n applyScaleWith(value === 'fit' ? 'fit' : parseFloat(value));\n }\n\n function toggleThumbs() {\n const next = !stateRef.current.thumbsVisible;\n setThumbsVisible(next);\n stateRef.current.thumbsVisible = next;\n // The sidebar eats stage width — re-fit so fit-width stays correct.\n if (stateRef.current.docLoaded && stateRef.current.scaleMode === 'fit') applyScale();\n }\n\n // ── Page corners ───────────────────────────────────────────────────────\n // Office/WPS-style crop marks: four L-brackets whose joints sit exactly\n // on the text-area corners (the page's padding corners).\n\n function addPageCorners(section: HTMLElement) {\n const cs = getComputedStyle(section);\n const padTop = parseFloat(cs.paddingTop) || 0;\n const padRight = parseFloat(cs.paddingRight) || 0;\n const padBottom = parseFloat(cs.paddingBottom) || 0;\n const padLeft = parseFloat(cs.paddingLeft) || 0;\n const right = section.offsetWidth - padRight; // text-area right edge\n const bottom = section.offsetHeight - padBottom; // text-area bottom edge\n const size = Math.max(4, Math.round(Math.min(padTop, padRight, padBottom, padLeft) * 0.25));\n\n const boxes = {\n tl: { left: padLeft - size, top: padTop - size },\n tr: { left: right, top: padTop - size },\n bl: { left: padLeft - size, top: bottom },\n br: { left: right, top: bottom },\n };\n\n for (const name of CORNER_NAMES) {\n const corner = document.createElement('i');\n corner.className = 'page-corner ' + name;\n corner.setAttribute('aria-hidden', 'true');\n corner.style.width = size + 'px';\n corner.style.height = size + 'px';\n corner.style.left = boxes[name].left + 'px';\n corner.style.top = boxes[name].top + 'px';\n section.appendChild(corner);\n }\n }\n\n // ── Pages ──────────────────────────────────────────────────────────────\n\n function scrollStageTo(element: HTMLElement) {\n const stage = refs.stage.current;\n if (!stage) return;\n const paddingTop = parseFloat(getComputedStyle(stage).paddingTop) || 0;\n stage.scrollTop =\n stage.scrollTop +\n (element.getBoundingClientRect().top - stage.getBoundingClientRect().top) -\n paddingTop;\n }\n\n function goToPage(index: number) {\n const sections = it.current.sections;\n if (!stateRef.current.docLoaded || sections.length === 0) return;\n const clamped = Math.max(0, Math.min(index, sections.length - 1));\n it.current.currentPage = clamped;\n setCurrentPage(clamped);\n scrollStageTo(sections[clamped]);\n }\n\n function jumpToPage(inputValue: string) {\n const target = parseInt(inputValue, 10);\n if (!Number.isNaN(target)) goToPage(target - 1);\n }\n\n function trackPages() {\n if (it.current.pageObserver) {\n it.current.pageObserver.disconnect();\n it.current.pageObserver = null;\n }\n const stage = refs.stage.current;\n const sections = it.current.sections;\n if (typeof window.IntersectionObserver !== 'function' || sections.length <= 1 || !stage) return;\n\n const ratios: number[] = [];\n it.current.pageObserver = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n const index = Number((entry.target as HTMLElement).getAttribute('data-page'));\n if (!Number.isNaN(index)) ratios[index] = entry.intersectionRatio;\n }\n let bestIndex = -1;\n let bestRatio = -1;\n for (let j = 0; j < ratios.length; j++) {\n if (ratios[j] > bestRatio) {\n bestRatio = ratios[j];\n bestIndex = j;\n }\n }\n if (bestIndex >= 0 && bestRatio > 0) {\n it.current.currentPage = bestIndex;\n setCurrentPage(bestIndex);\n }\n },\n { root: stage, threshold: [0, 0.25, 0.5, 0.75, 1.0] },\n );\n for (const section of sections) it.current.pageObserver.observe(section);\n }\n\n // ── Document loading ───────────────────────────────────────────────────\n\n function resetDocument() {\n if (it.current.pageObserver) {\n it.current.pageObserver.disconnect();\n it.current.pageObserver = null;\n }\n const docBox = refs.docBox.current;\n const thumbs = refs.thumbs.current;\n if (docBox) {\n docBox.innerHTML = '';\n docBox.style.width = '';\n docBox.style.height = '';\n }\n if (thumbs) thumbs.innerHTML = '';\n it.current.thumbPageSynced = -1;\n it.current.wrapperEl = null;\n it.current.sections = [];\n it.current.naturalWidth = 0;\n it.current.naturalHeight = 0;\n it.current.currentPage = 0;\n setCurrentPage(0);\n setPageCount(0);\n setDocLoaded(false);\n }\n\n async function openBuffer(buffer: ArrayBuffer, label: string) {\n resetDocument();\n setError(null);\n setDropdownOpen(false);\n setLoading(true);\n\n if (isLegacyBinary(buffer)) {\n setLoading(false);\n const legacyErr = new Error('legacy binary document (.wps/.doc), not OOXML');\n setError({\n title: '无法打开' + (label ? '「' + label + '」' : '文档'),\n detail:\n '这是旧版二进制文档格式(.wps / .doc),不是 OOXML(.docx)。' +\n '即使是新版 WPS Office,默认保存的 .wps 仍是二进制格式。' +\n '请用 WPS 或 Word 将其另存为 .docx 后重试。',\n });\n optionsRef.current.onError?.(legacyErr);\n return;\n }\n\n const renderOptions: Partial<Options> = {\n hideWrapperOnPrint: true,\n paginate: true,\n // 'experimental' only gates tab-stop computation, which 公文版记\n // lines (right-aligned tab stops) depend on.\n experimental: true,\n ...optionsRef.current.renderOptions,\n };\n\n try {\n const docBox = refs.docBox.current;\n const stage = refs.stage.current;\n if (!docBox || !stage) throw new Error('viewer is not mounted');\n const result = await renderAsync(buffer, docBox, undefined, renderOptions);\n\n const wrapperEl = (docBox.querySelector('.docx-wrapper') as HTMLElement) || docBox;\n it.current.wrapperEl = wrapperEl;\n\n const found = wrapperEl.querySelectorAll('section');\n const sections: HTMLElement[] = [];\n for (let i = 0; i < found.length; i++) {\n const section = found[i] as HTMLElement;\n section.setAttribute('data-page', String(i));\n addPageCorners(section);\n sections.push(section);\n }\n it.current.sections = sections;\n\n // Natural page size, measured before any transform is applied. The\n // wrapper is a full-width block, so its own width is the stage's —\n // the document's real width is the widest fixed-width page section.\n let naturalWidth = 0;\n for (const section of sections) {\n naturalWidth = Math.max(naturalWidth, section.offsetWidth);\n }\n if (!naturalWidth) naturalWidth = wrapperEl.scrollWidth;\n it.current.naturalWidth = naturalWidth;\n it.current.naturalHeight = wrapperEl.offsetHeight;\n it.current.currentPage = 0;\n\n stateRef.current.docLoaded = true;\n setDocLoaded(true);\n setPageCount(sections.length);\n setCurrentPage(0);\n applyScale();\n buildThumbs();\n trackPages();\n stage.scrollTop = 0;\n stage.scrollLeft = 0;\n optionsRef.current.onRendered?.(result);\n } catch (err) {\n console.error(err);\n resetDocument();\n setError({\n title: '无法打开' + (label ? '「' + label + '」' : '文档'),\n detail: errorText(err) + ' —— 请确认这是有效且未加密的 .docx 文件。',\n });\n optionsRef.current.onError?.(err);\n } finally {\n setLoading(false);\n }\n }\n\n /** Opens a document. `data` may be a Blob, ArrayBuffer or Uint8Array. */\n async function open(data: Blob | ArrayBuffer | Uint8Array | null | undefined, name?: string) {\n if (!data) return;\n const docName =\n name || (typeof File !== 'undefined' && data instanceof File && data.name) || 'document.docx';\n it.current.docName = docName;\n it.current.docBlob = data instanceof Blob ? data : new Blob([data as ArrayBuffer]);\n\n if (data instanceof Blob) {\n let buffer: ArrayBuffer;\n try {\n buffer = await new Promise<ArrayBuffer>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as ArrayBuffer);\n reader.onerror = () => reject(reader.error || new Error('FileReader failed'));\n reader.readAsArrayBuffer(data);\n });\n } catch (err) {\n setError({ title: '读取文件失败', detail: '浏览器无法读取「' + docName + '」,请重试。' });\n optionsRef.current.onError?.(err);\n return;\n }\n return openBuffer(buffer, docName);\n }\n return openBuffer(data as ArrayBuffer, docName);\n }\n\n function download() {\n const docBlob = it.current.docBlob;\n if (!docBlob) return;\n const objectUrl = URL.createObjectURL(docBlob);\n const link = document.createElement('a');\n link.href = objectUrl;\n link.download = it.current.docName || 'document.docx';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n setTimeout(() => URL.revokeObjectURL(objectUrl), 10000);\n }\n\n // ── Global listeners (registered once, read fresh state via stateRef) ──\n\n useEffect(() => {\n function onWindowResize() {\n if (stateRef.current.docLoaded && stateRef.current.scaleMode === 'fit') applyScale();\n }\n function onDocumentClick(event: MouseEvent) {\n if (!(event.target as HTMLElement).closest('.docx-viewer .scale-select')) {\n setDropdownOpen(false);\n }\n }\n function onDocumentKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape') setDropdownOpen(false);\n\n const tag = event.target && (event.target as HTMLElement).tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return;\n // Only steal navigation keys when this viewer contains the focus.\n if (!refs.stage.current || !refs.stage.current.contains(event.target as Node)) return;\n if (event.key === 'ArrowLeft' || event.key === 'ArrowUp' || event.key === 'PageUp') {\n event.preventDefault();\n goToPage(stateRef.current.currentPage - 1);\n } else if (event.key === 'ArrowRight' || event.key === 'ArrowDown' || event.key === 'PageDown' || event.key === ' ') {\n event.preventDefault();\n goToPage(stateRef.current.currentPage + 1);\n } else if (event.key === 'Home') {\n goToPage(0);\n } else if (event.key === 'End') {\n goToPage(it.current.sections.length - 1);\n }\n }\n\n window.addEventListener('resize', onWindowResize);\n document.addEventListener('click', onDocumentClick);\n document.addEventListener('keydown', onDocumentKeydown);\n return () => {\n window.removeEventListener('resize', onWindowResize);\n document.removeEventListener('click', onDocumentClick);\n document.removeEventListener('keydown', onDocumentKeydown);\n if (it.current.pageObserver) {\n it.current.pageObserver.disconnect();\n it.current.pageObserver = null;\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // currentPage highlight in the sidebar (the Vue port uses a watcher).\n useEffect(() => {\n syncThumbs();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [currentPage, thumbsShown]);\n\n return {\n // element refs (bound by the components)\n ...refs,\n // state\n loading,\n error,\n docLoaded,\n currentPage,\n pageCount,\n currentScale,\n scaleMode,\n thumbsVisible,\n dropdownOpen,\n setDropdownOpen,\n pagerShown,\n thumbsShown,\n canPrev,\n canNext,\n canZoomOut,\n canZoomIn,\n scaleLabel,\n // actions\n open,\n goToPage,\n jumpToPage,\n zoomStep,\n setScale,\n toggleThumbs,\n download,\n };\n}\n\nexport type DocxViewerApi = ReturnType<typeof useDocViewer>;\n","import { createContext, useContext } from 'react';\nimport type { DocxViewerApi } from './hooks/useDocViewer';\n\nexport const DocxViewerContext = createContext<DocxViewerApi | null>(null);\n\nexport function useDocxViewer(): DocxViewerApi {\n const api = useContext(DocxViewerContext);\n if (!api) throw new Error('DocxViewer components must be used inside <DocxViewer>');\n return api;\n}\n","export function IconThumbs() {\n return (\n <svg width=\"16\" height=\"16\" fill=\"none\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path fill=\"currentColor\" fillRule=\"evenodd\" d=\"M21 5H11v14h10zM3 5h6v14H3zm0-2a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h18a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm2 4.25a.75.75 0 0 0 0 1.5h2a.75.75 0 0 0 0-1.5zm-.75 3.5A.75.75 0 0 1 5 10h2a.75.75 0 0 1 0 1.5H5a.75.75 0 0 1-.75-.75m.75 2a.75.75 0 0 0 0 1.5h2a.75.75 0 0 0 0-1.5z\" clipRule=\"evenodd\" />\n </svg>\n );\n}\n","export function IconPrevPage() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 10l5-5 5 5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconNextPage() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 6l5 5 5-5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconZoomOut() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M4.8 7h4.4M10.2 10.2L14 14\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconZoomIn() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M4.8 7h4.4M7 4.8v4.4M10.2 10.2L14 14\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconChevronDown() {\n return (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M2 3.5l3 3 3-3\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconOpenFile() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M2 5.2A1.7 1.7 0 0 1 3.7 3.5h2.5l1.5 1.7h4.6a1.7 1.7 0 0 1 1.7 1.7v4.4a1.7 1.7 0 0 1-1.7 1.7H3.7A1.7 1.7 0 0 1 2 11.3V5.2Z\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconDownload() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M8 2.5V10M8 10L4.8 6.8 8 10l3.2-3.2M2.5 13.5h11\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","import { useRef } from 'react';\nimport { useDocxViewer } from '../context';\nimport { IconThumbs } from './icons/IconThumbs';\nimport { IconPrevPage } from './icons/IconPrevPage';\nimport { IconNextPage } from './icons/IconNextPage';\nimport { IconZoomOut } from './icons/IconZoomOut';\nimport { IconZoomIn } from './icons/IconZoomIn';\nimport { IconChevronDown } from './icons/IconChevronDown';\nimport { IconOpenFile } from './icons/IconOpenFile';\nimport { IconDownload } from './icons/IconDownload';\n\nconst SCALES = ['fit', '0.5', '0.75', '1', '1.25', '1.5', '2'];\n\nexport function Toolbar() {\n const api = useDocxViewer();\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n function onJump(event: React.SyntheticEvent<HTMLInputElement>) {\n const input = event.currentTarget;\n api.jumpToPage(input.value);\n input.blur();\n }\n\n function onFileChange(event: React.ChangeEvent<HTMLInputElement>) {\n const input = event.currentTarget;\n const file = input.files && input.files[0];\n if (file) api.open(file);\n // Reset so picking the same file twice still fires change.\n input.value = '';\n }\n\n return (\n <header className=\"toolbar\" hidden={!api.docLoaded}>\n <div className=\"toolbar-left\">\n <button\n className={api.thumbsShown ? 'tbtn active' : 'tbtn'}\n type=\"button\"\n title=\"缩略图\"\n disabled={!api.docLoaded || api.pageCount <= 1}\n onClick={api.toggleThumbs}\n >\n <IconThumbs />\n </button>\n <span className=\"toolbar-divider\"></span>\n <span className=\"pager\" hidden={!api.pagerShown}>\n <button\n className=\"tbtn\"\n type=\"button\"\n title=\"上一页\"\n disabled={!api.canPrev}\n onClick={() => api.goToPage(api.currentPage - 1)}\n >\n <IconPrevPage />\n </button>\n <span className=\"page-info\">\n {/* Uncontrolled + keyed by page: typing is free-form, and a page\n change remounts the input with the fresh page number. */}\n <input\n key={api.currentPage}\n className=\"page-input\"\n type=\"number\"\n min={1}\n step={1}\n defaultValue={api.pageCount > 0 ? api.currentPage + 1 : ''}\n aria-label=\"当前页码\"\n onKeyDown={(e) => {\n if (e.key === 'Enter') onJump(e);\n }}\n onBlur={onJump}\n />\n <span className=\"page-total\">/ {api.pageCount > 0 ? api.pageCount : '–'}</span>\n </span>\n <button\n className=\"tbtn\"\n type=\"button\"\n title=\"下一页\"\n disabled={!api.canNext}\n onClick={() => api.goToPage(api.currentPage + 1)}\n >\n <IconNextPage />\n </button>\n </span>\n </div>\n\n <div className=\"toolbar-center\">\n <div className=\"zoom-group\">\n <button className=\"tbtn\" type=\"button\" title=\"缩小\" disabled={!api.canZoomOut} onClick={() => api.zoomStep(-1)}>\n <IconZoomOut />\n </button>\n <div className=\"scale-select\">\n <button\n className=\"tbtn scale-display\"\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n api.setDropdownOpen(!api.dropdownOpen);\n }}\n >\n <span>{api.scaleLabel}</span>\n <IconChevronDown />\n </button>\n <div className=\"dropdown\" hidden={!api.dropdownOpen}>\n {SCALES.map((s) => (\n <button\n key={s}\n type=\"button\"\n className={\n (api.scaleMode === 'fit' && s === 'fit') || String(api.scaleMode) === s ? 'selected' : undefined\n }\n onClick={() => api.setScale(s)}\n >\n {s === 'fit' ? '适应宽度' : Math.round(parseFloat(s) * 100) + '%'}\n </button>\n ))}\n </div>\n </div>\n <button className=\"tbtn\" type=\"button\" title=\"放大\" disabled={!api.canZoomIn} onClick={() => api.zoomStep(1)}>\n <IconZoomIn />\n </button>\n </div>\n </div>\n\n <div className=\"toolbar-right\">\n <button className=\"tbtn\" type=\"button\" title=\"打开文档\" onClick={() => fileInputRef.current?.click()}>\n <IconOpenFile />\n </button>\n <button className=\"tbtn\" type=\"button\" title=\"下载文档\" disabled={!api.docLoaded} onClick={api.download}>\n <IconDownload />\n </button>\n <input ref={fileInputRef} type=\"file\" accept=\".docx\" hidden onChange={onFileChange} />\n </div>\n </header>\n );\n}\n","import { useDocxViewer } from '../context';\n\nexport function ErrorBanner() {\n const api = useDocxViewer();\n\n return (\n <div className=\"error-banner\" hidden={!api.error}>\n <strong>{api.error?.title}</strong>\n <span>{api.error?.detail}</span>\n </div>\n );\n}\n","import { useDocxViewer } from '../context';\n\nexport function ThumbnailsSidebar() {\n const api = useDocxViewer();\n\n function onClick(event: React.MouseEvent) {\n const item = (event.target as HTMLElement).closest('.thumb');\n if (item) api.goToPage(Number(item.getAttribute('data-page')));\n }\n\n return (\n <aside\n ref={api.thumbs as React.RefObject<HTMLElement>}\n className=\"thumbs\"\n hidden={!api.thumbsShown}\n aria-label=\"页面缩略图\"\n onClick={onClick}\n />\n );\n}\n","import { useDocxViewer } from '../context';\n\nexport function DocumentStage() {\n const api = useDocxViewer();\n\n return (\n <main ref={api.stage as React.RefObject<HTMLElement>} className=\"stage\">\n <div className=\"loading\" hidden={!api.loading}>\n <div className=\"spinner\"></div>\n <p>加载中…</p>\n </div>\n <div ref={api.docBox as React.RefObject<HTMLDivElement>} className=\"document\"></div>\n </main>\n );\n}\n","// React DOCX viewer component — a port of apps/viewer (toolbar, pager,\n// zoom, thumbnails, page corners). The document is fed via the `data` prop\n// and re-renders when it changes; initialScale/showThumbs/renderOptions\n// describe the initial mount (like viewer.html's URL params).\nimport { useEffect, useRef } from 'react';\nimport type { CSSProperties } from 'react';\nimport type { Options } from '@apollo-design/docx-preview';\nimport { useDocViewer } from './hooks/useDocViewer';\nimport { DocxViewerContext } from './context';\nimport { Toolbar } from './components/Toolbar';\nimport { ErrorBanner } from './components/ErrorBanner';\nimport { ThumbnailsSidebar } from './components/ThumbnailsSidebar';\nimport { DocumentStage } from './components/DocumentStage';\nimport './styles/viewer.css';\n\nexport interface DocxViewerProps {\n /** document data — Blob / ArrayBuffer / Uint8Array; re-renders on change */\n data?: Blob | ArrayBuffer | Uint8Array | null;\n /** document name for the download button */\n name?: string;\n /** 'fit' | number (0.75, 75, …) — initial zoom; mount-time only */\n initialScale?: 'fit' | number;\n /** initial thumbnail sidebar visibility; mount-time only */\n showThumbs?: boolean;\n /** library render options, merged over { paginate, experimental } */\n renderOptions?: Partial<Options>;\n className?: string;\n style?: CSSProperties;\n onRendered?: (result: unknown) => void;\n onError?: (error: unknown) => void;\n}\n\nexport function DocxViewer({\n data,\n name,\n initialScale,\n showThumbs,\n renderOptions,\n className,\n style,\n onRendered,\n onError,\n}: DocxViewerProps) {\n const stage = useRef<HTMLElement>(null);\n const docBox = useRef<HTMLElement>(null);\n const thumbs = useRef<HTMLElement>(null);\n\n const api = useDocViewer(\n { stage, docBox, thumbs },\n { initialScale, showThumbs, renderOptions, onRendered, onError },\n );\n\n useEffect(() => {\n if (data) api.open(data, name);\n // open is stable (reads latest props through refs); re-run only on data.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [data, name]);\n\n return (\n <DocxViewerContext.Provider value={api}>\n <div className={className ? `docx-viewer ${className}` : 'docx-viewer'} style={style}>\n <Toolbar />\n <ErrorBanner />\n <div className=\"body\">\n <ThumbnailsSidebar />\n <DocumentStage />\n </div>\n </div>\n </DocxViewerContext.Provider>\n );\n}\n\nexport default DocxViewer;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/hooks/useDocViewer.ts","../src/context.ts","../src/components/icons/IconThumbs.tsx","../src/components/icons/IconPrevPage.tsx","../src/components/icons/IconNextPage.tsx","../src/components/icons/IconZoomOut.tsx","../src/components/icons/IconZoomIn.tsx","../src/components/icons/IconChevronDown.tsx","../src/components/icons/IconOpenFile.tsx","../src/components/icons/IconDownload.tsx","../src/components/Toolbar.tsx","../src/components/ErrorBanner.tsx","../src/components/ThumbnailsSidebar.tsx","../src/components/DocumentStage.tsx","../src/DocxViewer.tsx"],"sourcesContent":["// Core viewer logic, ported from apps/viewer/viewer.js. UI-facing values are\n// React state; everything else (library render output, thumbnail clones, page\n// corners, zoom transforms) is imperative DOM work against element refs.\n// A ref mirror (stateRef) lets the once-registered global listeners read\n// fresh values.\nimport { useEffect, useRef, useState } from 'react';\nimport type { RefObject } from 'react';\nimport { renderAsync } from '@apollo-design/docx-preview';\nimport type { Options } from '@apollo-design/docx-preview';\n\n// Zoom-button range. Stepping clamps here so a step never strands the\n// buttons in a disabled state.\nconst SCALE_MIN = 0.1;\nconst SCALE_MAX = 4;\nconst SCALE_STEP = 0.25;\n// Fit-width never upscales: a document reads best at its natural size.\nconst FIT_MAX = 1;\nconst STAGE_PADDING = 24; // .stage padding on each side, see viewer.css\nconst THUMB_WIDTH = 96; // matches .thumb-page width in viewer.css\nconst CORNER_NAMES = ['tl', 'tr', 'bl', 'br'] as const;\n\nexport interface DocxViewerRefs {\n stage: RefObject<HTMLElement | null>;\n docBox: RefObject<HTMLElement | null>;\n thumbs: RefObject<HTMLElement | null>;\n}\n\nexport interface DocxViewerOptions {\n /** 'fit' (fit-width, never upscales) or a number like 0.75 / 75 */\n initialScale?: 'fit' | number;\n /** initial thumbnail sidebar visibility (default true) */\n showThumbs?: boolean;\n /** library render options, merged over { hideWrapperOnPrint, paginate, experimental } */\n renderOptions?: Partial<Options>;\n onRendered?: (result: unknown) => void;\n onError?: (error: unknown) => void;\n}\n\n// OLE2 compound-file magic (D0 CF 11 E0 ...): legacy binary documents —\n// old .doc, and .wps as still saved by default even by recent WPS Office.\nfunction isLegacyBinary(buffer: ArrayBuffer): boolean {\n if (!buffer || buffer.byteLength < 4) return false;\n const b = new Uint8Array(buffer, 0, 4);\n return b[0] === 0xd0 && b[1] === 0xcf && b[2] === 0x11 && b[3] === 0xe0;\n}\n\nfunction errorText(err: unknown): string {\n if (err && typeof err === 'object' && 'message' in err) return String((err as Error).message);\n return String(err);\n}\n\n/** 自定义文档请求(可附加鉴权头等),返回文档数据 */\nexport type DocxCustomRequest = (url: string) => Promise<Blob | ArrayBuffer | Uint8Array | null>;\n\n// Download-button fallback name: last path segment of the URL.\nfunction nameFromUrl(url: string): string {\n try {\n const pathname = new URL(url, window.location.href).pathname;\n const last = pathname.split('/').filter(Boolean).pop();\n return (last && decodeURIComponent(last)) || 'document.docx';\n } catch {\n return 'document.docx';\n }\n}\n\nfunction initialScaleMode(value: 'fit' | number | undefined): 'fit' | number {\n if (typeof value === 'number' && isFinite(value) && value > 0) {\n const n = value > 10 ? value / 100 : value;\n return Math.max(SCALE_MIN, Math.min(SCALE_MAX, Math.round(n * 100) / 100));\n }\n return 'fit';\n}\n\nexport function useDocViewer(refs: DocxViewerRefs, options: DocxViewerOptions = {}) {\n // ── UI state ───────────────────────────────────────────────────────────\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<{ title: string; detail: string } | null>(null);\n const [docLoaded, setDocLoaded] = useState(false);\n const [currentPage, setCurrentPage] = useState(0);\n const [pageCount, setPageCount] = useState(0);\n const [currentScale, setCurrentScale] = useState(1);\n const [scaleMode, setScaleMode] = useState<'fit' | number>(() => initialScaleMode(options.initialScale));\n const [thumbsVisible, setThumbsVisible] = useState(options.showThumbs !== false);\n const [dropdownOpen, setDropdownOpen] = useState(false);\n\n // ── Mutable internals (live DOM produced by the library) ───────────────\n const it = useRef({\n docName: '',\n // The opened document kept as a Blob so the download button works\n // regardless of the input type (Blob / ArrayBuffer / Uint8Array).\n docBlob: null as Blob | null,\n wrapperEl: null as HTMLElement | null,\n sections: [] as HTMLElement[],\n naturalWidth: 0,\n naturalHeight: 0,\n currentPage: 0, // authoritative copy (state mirrors it for rendering)\n pageObserver: null as IntersectionObserver | null,\n thumbPageSynced: -1,\n });\n // Latest-value mirror for the once-registered global listeners.\n const stateRef = useRef({ docLoaded, currentPage, scaleMode, thumbsVisible, currentScale });\n stateRef.current = { docLoaded, currentPage, scaleMode, thumbsVisible, currentScale };\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const pagerShown = pageCount > 1;\n const thumbsShown = thumbsVisible && pageCount > 1 && docLoaded;\n const canPrev = docLoaded && currentPage > 0;\n const canNext = docLoaded && currentPage < pageCount - 1;\n const canZoomOut = docLoaded && currentScale > SCALE_MIN + 1e-6;\n const canZoomIn = docLoaded && currentScale < SCALE_MAX - 1e-6;\n const scaleLabel = scaleMode === 'fit' ? '适应宽度' : Math.round(scaleMode * 100) + '%';\n\n // ── Thumbnails ─────────────────────────────────────────────────────────\n // Deep clones of page sections shrunk with a CSS transform — no re-render.\n\n function syncThumbs() {\n const box = refs.thumbs.current;\n if (!box) return;\n const items = box.children;\n const page = it.current.currentPage;\n for (let i = 0; i < items.length; i++) {\n items[i].classList.toggle('current', Number(items[i].getAttribute('data-page')) === page);\n }\n const shown = stateRef.current.thumbsVisible && items.length > 1 && stateRef.current.docLoaded;\n if (shown && it.current.thumbPageSynced !== page && items[page]) {\n it.current.thumbPageSynced = page;\n (items[page] as HTMLElement).scrollIntoView({ block: 'nearest' });\n }\n }\n\n function buildThumbs() {\n const box = refs.thumbs.current;\n if (!box) return;\n box.innerHTML = '';\n it.current.thumbPageSynced = -1;\n const sections = it.current.sections;\n if (sections.length <= 1 || !it.current.naturalWidth) return;\n\n const scale = (THUMB_WIDTH - 2) / it.current.naturalWidth; // 2px = .thumb-page borders\n for (let i = 0; i < sections.length; i++) {\n const item = document.createElement('div');\n item.className = 'thumb';\n item.setAttribute('data-page', String(i));\n\n const page = document.createElement('div');\n page.className = 'thumb-page';\n page.style.height = Math.ceil(sections[i].offsetHeight * scale) + 'px';\n\n const clone = sections[i].cloneNode(true) as HTMLElement;\n clone.removeAttribute('data-page');\n clone.style.transform = 'scale(' + scale + ')';\n clone.style.transformOrigin = 'top left';\n page.appendChild(clone);\n\n const label = document.createElement('div');\n label.className = 'thumb-label';\n label.textContent = String(i + 1);\n\n item.appendChild(page);\n item.appendChild(label);\n box.appendChild(item);\n }\n syncThumbs();\n }\n\n // ── Zoom ───────────────────────────────────────────────────────────────\n // Zoom is pure CSS: the library renders once at natural size, and we scale\n // .docx-wrapper with a transform inside an explicitly-sized box.\n\n function fitScale() {\n const stage = refs.stage.current;\n if (!it.current.naturalWidth || !stage) return 1;\n const avail = stage.clientWidth - STAGE_PADDING * 2;\n return Math.min(FIT_MAX, avail / it.current.naturalWidth);\n }\n\n function applyScale() {\n const stage = refs.stage.current;\n const docBox = refs.docBox.current;\n const wrapperEl = it.current.wrapperEl;\n const naturalWidth = it.current.naturalWidth;\n if (!stateRef.current.docLoaded || !wrapperEl || !naturalWidth || !stage || !docBox) return;\n\n // Keep the same relative scroll position across the zoom change.\n const maxY = stage.scrollHeight - stage.clientHeight;\n const maxX = stage.scrollWidth - stage.clientWidth;\n const ratioY = maxY > 0 ? stage.scrollTop / maxY : 0;\n const ratioX = maxX > 0 ? stage.scrollLeft / maxX : 0;\n\n const mode = stateRef.current.scaleMode;\n const scale = mode === 'fit' ? fitScale() : mode;\n setCurrentScale(scale);\n docBox.style.width = Math.ceil(naturalWidth * scale) + 'px';\n docBox.style.height = Math.ceil(it.current.naturalHeight * scale) + 'px';\n // Pin the wrapper to the natural content width so the top-left-origin\n // transform lines up exactly with the zoom box.\n wrapperEl.style.width = naturalWidth + 'px';\n wrapperEl.style.transform = 'scale(' + scale + ')';\n wrapperEl.style.transformOrigin = 'top left';\n\n const newMaxY = stage.scrollHeight - stage.clientHeight;\n const newMaxX = stage.scrollWidth - stage.clientWidth;\n if (newMaxY > 0) stage.scrollTop = ratioY * newMaxY;\n if (newMaxX > 0) stage.scrollLeft = ratioX * newMaxX;\n }\n\n function zoomStep(direction: 1 | -1) {\n // currentScale carries sub-pixel fit error (e.g. 0.99998); snap to the\n // nearest grid line within tolerance first, or the buttons look dead.\n let steps = stateRef.current.currentScale / SCALE_STEP;\n const nearest = Math.round(steps);\n if (Math.abs(steps - nearest) < 0.01) steps = nearest;\n const next = direction > 0 ? (Math.floor(steps) + 1) * SCALE_STEP : (Math.ceil(steps) - 1) * SCALE_STEP;\n applyScaleWith(Math.max(SCALE_MIN, Math.min(SCALE_MAX, Math.round(next * 100) / 100)));\n }\n\n // applyScale reads scaleMode from stateRef; callers that just changed the\n // mode must update the mirror first (setScaleMode alone lands next render).\n function applyScaleWith(mode: 'fit' | number) {\n stateRef.current.scaleMode = mode;\n setScaleMode(mode);\n applyScale();\n }\n\n function setScale(value: string) {\n setDropdownOpen(false);\n applyScaleWith(value === 'fit' ? 'fit' : parseFloat(value));\n }\n\n function toggleThumbs() {\n const next = !stateRef.current.thumbsVisible;\n setThumbsVisible(next);\n stateRef.current.thumbsVisible = next;\n // The sidebar eats stage width — re-fit so fit-width stays correct.\n if (stateRef.current.docLoaded && stateRef.current.scaleMode === 'fit') applyScale();\n }\n\n // ── Page corners ───────────────────────────────────────────────────────\n // Office/WPS-style crop marks: four L-brackets whose joints sit exactly\n // on the text-area corners (the page's padding corners).\n\n function addPageCorners(section: HTMLElement) {\n const cs = getComputedStyle(section);\n const padTop = parseFloat(cs.paddingTop) || 0;\n const padRight = parseFloat(cs.paddingRight) || 0;\n const padBottom = parseFloat(cs.paddingBottom) || 0;\n const padLeft = parseFloat(cs.paddingLeft) || 0;\n const right = section.offsetWidth - padRight; // text-area right edge\n const bottom = section.offsetHeight - padBottom; // text-area bottom edge\n const size = Math.max(4, Math.round(Math.min(padTop, padRight, padBottom, padLeft) * 0.25));\n\n const boxes = {\n tl: { left: padLeft - size, top: padTop - size },\n tr: { left: right, top: padTop - size },\n bl: { left: padLeft - size, top: bottom },\n br: { left: right, top: bottom },\n };\n\n for (const name of CORNER_NAMES) {\n const corner = document.createElement('i');\n corner.className = 'page-corner ' + name;\n corner.setAttribute('aria-hidden', 'true');\n corner.style.width = size + 'px';\n corner.style.height = size + 'px';\n corner.style.left = boxes[name].left + 'px';\n corner.style.top = boxes[name].top + 'px';\n section.appendChild(corner);\n }\n }\n\n // ── Pages ──────────────────────────────────────────────────────────────\n\n function scrollStageTo(element: HTMLElement) {\n const stage = refs.stage.current;\n if (!stage) return;\n const paddingTop = parseFloat(getComputedStyle(stage).paddingTop) || 0;\n stage.scrollTop =\n stage.scrollTop +\n (element.getBoundingClientRect().top - stage.getBoundingClientRect().top) -\n paddingTop;\n }\n\n function goToPage(index: number) {\n const sections = it.current.sections;\n if (!stateRef.current.docLoaded || sections.length === 0) return;\n const clamped = Math.max(0, Math.min(index, sections.length - 1));\n it.current.currentPage = clamped;\n setCurrentPage(clamped);\n scrollStageTo(sections[clamped]);\n }\n\n function jumpToPage(inputValue: string) {\n const target = parseInt(inputValue, 10);\n if (!Number.isNaN(target)) goToPage(target - 1);\n }\n\n function trackPages() {\n if (it.current.pageObserver) {\n it.current.pageObserver.disconnect();\n it.current.pageObserver = null;\n }\n const stage = refs.stage.current;\n const sections = it.current.sections;\n if (typeof window.IntersectionObserver !== 'function' || sections.length <= 1 || !stage) return;\n\n const ratios: number[] = [];\n it.current.pageObserver = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n const index = Number((entry.target as HTMLElement).getAttribute('data-page'));\n if (!Number.isNaN(index)) ratios[index] = entry.intersectionRatio;\n }\n let bestIndex = -1;\n let bestRatio = -1;\n for (let j = 0; j < ratios.length; j++) {\n if (ratios[j] > bestRatio) {\n bestRatio = ratios[j];\n bestIndex = j;\n }\n }\n if (bestIndex >= 0 && bestRatio > 0) {\n it.current.currentPage = bestIndex;\n setCurrentPage(bestIndex);\n }\n },\n { root: stage, threshold: [0, 0.25, 0.5, 0.75, 1.0] },\n );\n for (const section of sections) it.current.pageObserver.observe(section);\n }\n\n // ── Document loading ───────────────────────────────────────────────────\n\n function resetDocument() {\n if (it.current.pageObserver) {\n it.current.pageObserver.disconnect();\n it.current.pageObserver = null;\n }\n const docBox = refs.docBox.current;\n const thumbs = refs.thumbs.current;\n if (docBox) {\n docBox.innerHTML = '';\n docBox.style.width = '';\n docBox.style.height = '';\n }\n if (thumbs) thumbs.innerHTML = '';\n it.current.thumbPageSynced = -1;\n it.current.wrapperEl = null;\n it.current.sections = [];\n it.current.naturalWidth = 0;\n it.current.naturalHeight = 0;\n it.current.currentPage = 0;\n setCurrentPage(0);\n setPageCount(0);\n setDocLoaded(false);\n }\n\n async function openBuffer(buffer: ArrayBuffer, label: string) {\n resetDocument();\n setError(null);\n setDropdownOpen(false);\n setLoading(true);\n\n if (isLegacyBinary(buffer)) {\n setLoading(false);\n const legacyErr = new Error('legacy binary document (.wps/.doc), not OOXML');\n setError({\n title: '无法打开' + (label ? '「' + label + '」' : '文档'),\n detail:\n '这是旧版二进制文档格式(.wps / .doc),不是 OOXML(.docx)。' +\n '即使是新版 WPS Office,默认保存的 .wps 仍是二进制格式。' +\n '请用 WPS 或 Word 将其另存为 .docx 后重试。',\n });\n optionsRef.current.onError?.(legacyErr);\n return;\n }\n\n const renderOptions: Partial<Options> = {\n hideWrapperOnPrint: true,\n paginate: true,\n // 'experimental' only gates tab-stop computation, which 公文版记\n // lines (right-aligned tab stops) depend on.\n experimental: true,\n ...optionsRef.current.renderOptions,\n };\n\n try {\n const docBox = refs.docBox.current;\n const stage = refs.stage.current;\n if (!docBox || !stage) throw new Error('viewer is not mounted');\n const result = await renderAsync(buffer, docBox, undefined, renderOptions);\n\n const wrapperEl = (docBox.querySelector('.docx-wrapper') as HTMLElement) || docBox;\n it.current.wrapperEl = wrapperEl;\n\n const found = wrapperEl.querySelectorAll('section');\n const sections: HTMLElement[] = [];\n for (let i = 0; i < found.length; i++) {\n const section = found[i] as HTMLElement;\n section.setAttribute('data-page', String(i));\n addPageCorners(section);\n sections.push(section);\n }\n it.current.sections = sections;\n\n // Natural page size, measured before any transform is applied. The\n // wrapper is a full-width block, so its own width is the stage's —\n // the document's real width is the widest fixed-width page section.\n let naturalWidth = 0;\n for (const section of sections) {\n naturalWidth = Math.max(naturalWidth, section.offsetWidth);\n }\n if (!naturalWidth) naturalWidth = wrapperEl.scrollWidth;\n it.current.naturalWidth = naturalWidth;\n it.current.naturalHeight = wrapperEl.offsetHeight;\n it.current.currentPage = 0;\n\n stateRef.current.docLoaded = true;\n setDocLoaded(true);\n setPageCount(sections.length);\n setCurrentPage(0);\n applyScale();\n buildThumbs();\n trackPages();\n stage.scrollTop = 0;\n stage.scrollLeft = 0;\n optionsRef.current.onRendered?.(result);\n } catch (err) {\n console.error(err);\n resetDocument();\n setError({\n title: '无法打开' + (label ? '「' + label + '」' : '文档'),\n detail: errorText(err) + ' —— 请确认这是有效且未加密的 .docx 文件。',\n });\n optionsRef.current.onError?.(err);\n } finally {\n setLoading(false);\n }\n }\n\n /** Opens a document. `data` may be a Blob, ArrayBuffer or Uint8Array. */\n async function open(data: Blob | ArrayBuffer | Uint8Array | null | undefined, name?: string) {\n if (!data) return;\n const docName =\n name || (typeof File !== 'undefined' && data instanceof File && data.name) || 'document.docx';\n it.current.docName = docName;\n it.current.docBlob = data instanceof Blob ? data : new Blob([data as ArrayBuffer]);\n\n if (data instanceof Blob) {\n let buffer: ArrayBuffer;\n try {\n buffer = await new Promise<ArrayBuffer>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as ArrayBuffer);\n reader.onerror = () => reject(reader.error || new Error('FileReader failed'));\n reader.readAsArrayBuffer(data);\n });\n } catch (err) {\n setError({ title: '读取文件失败', detail: '浏览器无法读取「' + docName + '」,请重试。' });\n optionsRef.current.onError?.(err);\n return;\n }\n return openBuffer(buffer, docName);\n }\n return openBuffer(data as ArrayBuffer, docName);\n }\n\n /** Opens a document from a URL — plain GET by default; pass customRequest to customize the request (auth headers, tokens, …). */\n async function openUrl(url: string, customRequest?: DocxCustomRequest, name?: string) {\n if (!url) return;\n setLoading(true);\n setError(null);\n try {\n let data: Blob | ArrayBuffer | Uint8Array | null;\n if (customRequest) {\n data = await customRequest(url);\n } else {\n const response = await fetch(url);\n if (!response.ok) throw new Error('HTTP ' + response.status + ' ' + response.statusText);\n data = await response.blob();\n }\n if (!data) throw new Error('文档数据为空');\n return await open(data, name || nameFromUrl(url));\n } catch (err) {\n console.error(err);\n setError({\n title: '加载文档失败',\n detail: errorText(err) + ' —— 请确认地址可访问(如需鉴权请使用 customRequest)。',\n });\n optionsRef.current.onError?.(err);\n } finally {\n setLoading(false);\n }\n }\n\n function download() {\n const docBlob = it.current.docBlob;\n if (!docBlob) return;\n const objectUrl = URL.createObjectURL(docBlob);\n const link = document.createElement('a');\n link.href = objectUrl;\n link.download = it.current.docName || 'document.docx';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n setTimeout(() => URL.revokeObjectURL(objectUrl), 10000);\n }\n\n // ── Global listeners (registered once, read fresh state via stateRef) ──\n\n useEffect(() => {\n function onWindowResize() {\n if (stateRef.current.docLoaded && stateRef.current.scaleMode === 'fit') applyScale();\n }\n function onDocumentClick(event: MouseEvent) {\n if (!(event.target as HTMLElement).closest('.docx-viewer .scale-select')) {\n setDropdownOpen(false);\n }\n }\n function onDocumentKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape') setDropdownOpen(false);\n\n const tag = event.target && (event.target as HTMLElement).tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return;\n // Only steal navigation keys when this viewer contains the focus.\n if (!refs.stage.current || !refs.stage.current.contains(event.target as Node)) return;\n if (event.key === 'ArrowLeft' || event.key === 'ArrowUp' || event.key === 'PageUp') {\n event.preventDefault();\n goToPage(stateRef.current.currentPage - 1);\n } else if (event.key === 'ArrowRight' || event.key === 'ArrowDown' || event.key === 'PageDown' || event.key === ' ') {\n event.preventDefault();\n goToPage(stateRef.current.currentPage + 1);\n } else if (event.key === 'Home') {\n goToPage(0);\n } else if (event.key === 'End') {\n goToPage(it.current.sections.length - 1);\n }\n }\n\n window.addEventListener('resize', onWindowResize);\n document.addEventListener('click', onDocumentClick);\n document.addEventListener('keydown', onDocumentKeydown);\n return () => {\n window.removeEventListener('resize', onWindowResize);\n document.removeEventListener('click', onDocumentClick);\n document.removeEventListener('keydown', onDocumentKeydown);\n if (it.current.pageObserver) {\n it.current.pageObserver.disconnect();\n it.current.pageObserver = null;\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // currentPage highlight in the sidebar (the Vue port uses a watcher).\n useEffect(() => {\n syncThumbs();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [currentPage, thumbsShown]);\n\n return {\n // element refs (bound by the components)\n ...refs,\n // state\n loading,\n error,\n docLoaded,\n currentPage,\n pageCount,\n currentScale,\n scaleMode,\n thumbsVisible,\n dropdownOpen,\n setDropdownOpen,\n pagerShown,\n thumbsShown,\n canPrev,\n canNext,\n canZoomOut,\n canZoomIn,\n scaleLabel,\n // actions\n open,\n openUrl,\n goToPage,\n jumpToPage,\n zoomStep,\n setScale,\n toggleThumbs,\n download,\n };\n}\n\nexport type DocxViewerApi = ReturnType<typeof useDocViewer>;\n","import { createContext, useContext } from 'react';\nimport type { DocxViewerApi } from './hooks/useDocViewer';\n\nexport const DocxViewerContext = createContext<DocxViewerApi | null>(null);\n\nexport function useDocxViewer(): DocxViewerApi {\n const api = useContext(DocxViewerContext);\n if (!api) throw new Error('DocxViewer components must be used inside <DocxViewer>');\n return api;\n}\n","export function IconThumbs() {\n return (\n <svg width=\"16\" height=\"16\" fill=\"none\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path fill=\"currentColor\" fillRule=\"evenodd\" d=\"M21 5H11v14h10zM3 5h6v14H3zm0-2a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h18a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm2 4.25a.75.75 0 0 0 0 1.5h2a.75.75 0 0 0 0-1.5zm-.75 3.5A.75.75 0 0 1 5 10h2a.75.75 0 0 1 0 1.5H5a.75.75 0 0 1-.75-.75m.75 2a.75.75 0 0 0 0 1.5h2a.75.75 0 0 0 0-1.5z\" clipRule=\"evenodd\" />\n </svg>\n );\n}\n","export function IconPrevPage() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 10l5-5 5 5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconNextPage() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 6l5 5 5-5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconZoomOut() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M4.8 7h4.4M10.2 10.2L14 14\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconZoomIn() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"4.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M4.8 7h4.4M7 4.8v4.4M10.2 10.2L14 14\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconChevronDown() {\n return (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M2 3.5l3 3 3-3\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconOpenFile() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M2 5.2A1.7 1.7 0 0 1 3.7 3.5h2.5l1.5 1.7h4.6a1.7 1.7 0 0 1 1.7 1.7v4.4a1.7 1.7 0 0 1-1.7 1.7H3.7A1.7 1.7 0 0 1 2 11.3V5.2Z\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","export function IconDownload() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M8 2.5V10M8 10L4.8 6.8 8 10l3.2-3.2M2.5 13.5h11\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n","import { useRef } from 'react';\nimport { useDocxViewer } from '../context';\nimport { IconThumbs } from './icons/IconThumbs';\nimport { IconPrevPage } from './icons/IconPrevPage';\nimport { IconNextPage } from './icons/IconNextPage';\nimport { IconZoomOut } from './icons/IconZoomOut';\nimport { IconZoomIn } from './icons/IconZoomIn';\nimport { IconChevronDown } from './icons/IconChevronDown';\nimport { IconOpenFile } from './icons/IconOpenFile';\nimport { IconDownload } from './icons/IconDownload';\n\nconst SCALES = ['fit', '0.5', '0.75', '1', '1.25', '1.5', '2'];\n\nexport function Toolbar() {\n const api = useDocxViewer();\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n function onJump(event: React.SyntheticEvent<HTMLInputElement>) {\n const input = event.currentTarget;\n api.jumpToPage(input.value);\n input.blur();\n }\n\n function onFileChange(event: React.ChangeEvent<HTMLInputElement>) {\n const input = event.currentTarget;\n const file = input.files && input.files[0];\n if (file) api.open(file);\n // Reset so picking the same file twice still fires change.\n input.value = '';\n }\n\n return (\n <header className=\"toolbar\" hidden={!api.docLoaded}>\n <div className=\"toolbar-left\">\n <button\n className={api.thumbsShown ? 'tbtn active' : 'tbtn'}\n type=\"button\"\n title=\"缩略图\"\n disabled={!api.docLoaded || api.pageCount <= 1}\n onClick={api.toggleThumbs}\n >\n <IconThumbs />\n </button>\n <span className=\"toolbar-divider\"></span>\n <span className=\"pager\" hidden={!api.pagerShown}>\n <button\n className=\"tbtn\"\n type=\"button\"\n title=\"上一页\"\n disabled={!api.canPrev}\n onClick={() => api.goToPage(api.currentPage - 1)}\n >\n <IconPrevPage />\n </button>\n <span className=\"page-info\">\n {/* Uncontrolled + keyed by page: typing is free-form, and a page\n change remounts the input with the fresh page number. */}\n <input\n key={api.currentPage}\n className=\"page-input\"\n type=\"number\"\n min={1}\n step={1}\n defaultValue={api.pageCount > 0 ? api.currentPage + 1 : ''}\n aria-label=\"当前页码\"\n onKeyDown={(e) => {\n if (e.key === 'Enter') onJump(e);\n }}\n onBlur={onJump}\n />\n <span className=\"page-total\">/ {api.pageCount > 0 ? api.pageCount : '–'}</span>\n </span>\n <button\n className=\"tbtn\"\n type=\"button\"\n title=\"下一页\"\n disabled={!api.canNext}\n onClick={() => api.goToPage(api.currentPage + 1)}\n >\n <IconNextPage />\n </button>\n </span>\n </div>\n\n <div className=\"toolbar-center\">\n <div className=\"zoom-group\">\n <button className=\"tbtn\" type=\"button\" title=\"缩小\" disabled={!api.canZoomOut} onClick={() => api.zoomStep(-1)}>\n <IconZoomOut />\n </button>\n <div className=\"scale-select\">\n <button\n className=\"tbtn scale-display\"\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n api.setDropdownOpen(!api.dropdownOpen);\n }}\n >\n <span>{api.scaleLabel}</span>\n <IconChevronDown />\n </button>\n <div className=\"dropdown\" hidden={!api.dropdownOpen}>\n {SCALES.map((s) => (\n <button\n key={s}\n type=\"button\"\n className={\n (api.scaleMode === 'fit' && s === 'fit') || String(api.scaleMode) === s ? 'selected' : undefined\n }\n onClick={() => api.setScale(s)}\n >\n {s === 'fit' ? '适应宽度' : Math.round(parseFloat(s) * 100) + '%'}\n </button>\n ))}\n </div>\n </div>\n <button className=\"tbtn\" type=\"button\" title=\"放大\" disabled={!api.canZoomIn} onClick={() => api.zoomStep(1)}>\n <IconZoomIn />\n </button>\n </div>\n </div>\n\n <div className=\"toolbar-right\">\n <button className=\"tbtn\" type=\"button\" title=\"打开文档\" onClick={() => fileInputRef.current?.click()}>\n <IconOpenFile />\n </button>\n <button className=\"tbtn\" type=\"button\" title=\"下载文档\" disabled={!api.docLoaded} onClick={api.download}>\n <IconDownload />\n </button>\n <input ref={fileInputRef} type=\"file\" accept=\".docx\" hidden onChange={onFileChange} />\n </div>\n </header>\n );\n}\n","import { useDocxViewer } from '../context';\n\nexport function ErrorBanner() {\n const api = useDocxViewer();\n\n return (\n <div className=\"error-banner\" hidden={!api.error}>\n <strong>{api.error?.title}</strong>\n <span>{api.error?.detail}</span>\n </div>\n );\n}\n","import { useDocxViewer } from '../context';\n\nexport function ThumbnailsSidebar() {\n const api = useDocxViewer();\n\n function onClick(event: React.MouseEvent) {\n const item = (event.target as HTMLElement).closest('.thumb');\n if (item) api.goToPage(Number(item.getAttribute('data-page')));\n }\n\n return (\n <aside\n ref={api.thumbs as React.RefObject<HTMLElement>}\n className=\"thumbs\"\n hidden={!api.thumbsShown}\n aria-label=\"页面缩略图\"\n onClick={onClick}\n />\n );\n}\n","import { useDocxViewer } from '../context';\n\nexport function DocumentStage() {\n const api = useDocxViewer();\n\n return (\n <main ref={api.stage as React.RefObject<HTMLElement>} className=\"stage\">\n <div className=\"loading\" hidden={!api.loading}>\n <div className=\"spinner\"></div>\n <p>加载中…</p>\n </div>\n <div ref={api.docBox as React.RefObject<HTMLDivElement>} className=\"document\"></div>\n </main>\n );\n}\n","// React DOCX viewer component — a port of apps/viewer (toolbar, pager,\n// zoom, thumbnails, page corners). The document is fetched from the `url`\n// prop (optionally via `customRequest`, e.g. for authenticated endpoints)\n// and re-renders when it changes; initialScale/showThumbs/renderOptions\n// describe the initial mount (like viewer.html's URL params).\nimport { useEffect, useRef } from 'react';\nimport type { CSSProperties } from 'react';\nimport type { Options } from '@apollo-design/docx-preview';\nimport { useDocViewer } from './hooks/useDocViewer';\nimport type { DocxCustomRequest } from './hooks/useDocViewer';\nimport { DocxViewerContext } from './context';\nimport { Toolbar } from './components/Toolbar';\nimport { ErrorBanner } from './components/ErrorBanner';\nimport { ThumbnailsSidebar } from './components/ThumbnailsSidebar';\nimport { DocumentStage } from './components/DocumentStage';\nimport './styles/viewer.css';\n\nexport interface DocxViewerProps {\n /** 文档地址,默认 GET 读取;变化即重新加载 */\n url: string;\n /** 自定义请求(可附加鉴权头等),返回文档数据;缺省用 fetch GET */\n customRequest?: DocxCustomRequest;\n /** document name for the download button; defaults to the URL's last path segment */\n name?: string;\n /** 'fit' | number (0.75, 75, …) — initial zoom; mount-time only */\n initialScale?: 'fit' | number;\n /** initial thumbnail sidebar visibility; mount-time only */\n showThumbs?: boolean;\n /** library render options, merged over { paginate, experimental } */\n renderOptions?: Partial<Options>;\n className?: string;\n style?: CSSProperties;\n onRendered?: (result: unknown) => void;\n onError?: (error: unknown) => void;\n}\n\nexport function DocxViewer({\n url,\n customRequest,\n name,\n initialScale,\n showThumbs,\n renderOptions,\n className,\n style,\n onRendered,\n onError,\n}: DocxViewerProps) {\n const stage = useRef<HTMLElement>(null);\n const docBox = useRef<HTMLElement>(null);\n const thumbs = useRef<HTMLElement>(null);\n\n const api = useDocViewer(\n { stage, docBox, thumbs },\n { initialScale, showThumbs, renderOptions, onRendered, onError },\n );\n\n // customRequest is a function prop — read it through a ref so an inline\n // lambda doesn't retrigger the load on every render.\n const requestRef = useRef(customRequest);\n requestRef.current = customRequest;\n\n useEffect(() => {\n if (url) api.openUrl(url, requestRef.current, name);\n // openUrl is stable (reads latest props through refs); re-run only on url.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [url, name]);\n\n return (\n <DocxViewerContext.Provider value={api}>\n <div className={className ? `docx-viewer ${className}` : 'docx-viewer'} style={style}>\n <Toolbar />\n <ErrorBanner />\n <div className=\"body\">\n <ThumbnailsSidebar />\n <DocumentStage />\n </div>\n </div>\n </DocxViewerContext.Provider>\n );\n}\n\nexport default DocxViewer;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apollo-design/react-docx-preview",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "React DOCX viewer component (toolbar, pager, zoom, thumbnails) built on @apollo-design/docx-preview",
5
5
  "keywords": [
6
6
  "word",
@@ -37,7 +37,7 @@
37
37
  "react": ">=17"
38
38
  },
39
39
  "dependencies": {
40
- "@apollo-design/docx-preview": "0.6.3"
40
+ "@apollo-design/docx-preview": "0.8.0"
41
41
  },
42
42
  "publishConfig": {
43
43
  "access": "public",