From 3d3370a20496516d922f0236cf1bb7ce580a859b Mon Sep 17 00:00:00 2001 From: Lennart Fries Date: Tue, 31 Mar 2026 21:03:16 +0200 Subject: [PATCH 1/3] feat: add minimal Vue package harness with working editor component Implements a Vue 3 wrapper for the DOCX editor with DocxEditorVue component, BasicToolbar, and useDocxEditor composable. Includes drag-to-select, blinking caret, scroll-aware selection overlay, and working toolbar state updates. Co-Authored-By: Claude Opus 4.6 --- bun.lock | 11 +- examples/vue/public/sample.docx | Bin 0 -> 39238 bytes examples/vue/src/App.vue | 239 +++++++++-- package.json | 5 +- packages/vue/package.json | 1 + packages/vue/src/components/BasicToolbar.vue | 94 ++++ packages/vue/src/components/DocxEditorVue.vue | 308 ++++++++++++++ packages/vue/src/composables/useDocxEditor.ts | 401 ++++++++++++++++++ packages/vue/src/index.ts | 10 +- packages/vue/src/renderAsync.ts | 71 +++- packages/vue/src/shims-vue.d.ts | 6 + 11 files changed, 1093 insertions(+), 53 deletions(-) create mode 100644 examples/vue/public/sample.docx create mode 100644 packages/vue/src/components/BasicToolbar.vue create mode 100644 packages/vue/src/components/DocxEditorVue.vue create mode 100644 packages/vue/src/composables/useDocxEditor.ts create mode 100644 packages/vue/src/shims-vue.d.ts diff --git a/bun.lock b/bun.lock index 58bd80b4..946fd2f5 100644 --- a/bun.lock +++ b/bun.lock @@ -17,6 +17,7 @@ "@typescript-eslint/eslint-plugin": "^8.54.0", "@typescript-eslint/parser": "^8.54.0", "@vitejs/plugin-react": "^5.1.2", + "@vitejs/plugin-vue": "^6.0.4", "autoprefixer": "^10.4.17", "class-variance-authority": "^0.7.0", "eslint": "^10.0.3", @@ -34,11 +35,12 @@ "tsup": "^8.0.1", "typescript": "^5.3.3", "vite": "^7.3.1", + "vue": "^3.5.29", }, }, "packages/agent-use": { "name": "@eigenpal/docx-editor-agents", - "version": "0.0.31", + "version": "0.0.32", "dependencies": { "docxtemplater": "^3.50.0", "jszip": "^3.10.1", @@ -70,7 +72,7 @@ }, "packages/react": { "name": "@eigenpal/docx-js-editor", - "version": "0.0.31", + "version": "0.0.32", "dependencies": { "@radix-ui/react-select": "^2.2.6", "clsx": "^2.1.0", @@ -101,6 +103,7 @@ "@eigenpal/docx-core": "workspace:*", }, "devDependencies": { + "prosemirror-state": "^1.4.3", "prosemirror-view": "^1.41.6", }, "peerDependencies": { @@ -465,6 +468,8 @@ "@vitejs/plugin-react": ["@vitejs/plugin-react@5.2.0", "", { "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-rc.3", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw=="], + "@vitejs/plugin-vue": ["@vitejs/plugin-vue@6.0.5", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-rc.2" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", "vue": "^3.2.25" } }, "sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg=="], + "@vue/compiler-core": ["@vue/compiler-core@3.5.30", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/shared": "3.5.30", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw=="], "@vue/compiler-dom": ["@vue/compiler-dom@3.5.30", "", { "dependencies": { "@vue/compiler-core": "3.5.30", "@vue/shared": "3.5.30" } }, "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g=="], @@ -1297,6 +1302,8 @@ "@manypkg/get-packages/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + "@vitejs/plugin-vue/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.2", "", {}, "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw=="], + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], diff --git a/examples/vue/public/sample.docx b/examples/vue/public/sample.docx new file mode 100644 index 0000000000000000000000000000000000000000..a18bf1861eca43200d4bb6f93e46e9b74ca05608 GIT binary patch literal 39238 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

^UY^>2BK5w)UzAR3Ob#~#nF=wd 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 HCCGmO+lCvf literal 0 HcmV?d00001 diff --git a/examples/vue/src/App.vue b/examples/vue/src/App.vue index 0eedf409..ac0c2da9 100644 --- a/examples/vue/src/App.vue +++ b/examples/vue/src/App.vue @@ -1,59 +1,226 @@ - diff --git a/package.json b/package.json index 6d4b70f3..30aa4f63 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "dev:nextjs": "cd examples/nextjs && npm run dev", "dev:remix": "cd examples/remix && npm run dev", "dev:astro": "cd examples/astro && npm run dev", + "dev:vue": "cd examples/vue && bun run dev", "dev:demo": "bash examples/dev-all.sh", "build": "bun run --filter '@eigenpal/docx-core' build && bun run --filter '@eigenpal/docx-js-editor' build", "build:demo": "vite build --config examples/vite/vite.config.ts", @@ -47,6 +48,7 @@ "@typescript-eslint/eslint-plugin": "^8.54.0", "@typescript-eslint/parser": "^8.54.0", "@vitejs/plugin-react": "^5.1.2", + "@vitejs/plugin-vue": "^6.0.4", "autoprefixer": "^10.4.17", "class-variance-authority": "^0.7.0", "eslint": "^10.0.3", @@ -63,7 +65,8 @@ "tailwindcss-animate": "^1.0.7", "tsup": "^8.0.1", "typescript": "^5.3.3", - "vite": "^7.3.1" + "vite": "^7.3.1", + "vue": "^3.5.29" }, "keywords": [ "docx", diff --git a/packages/vue/package.json b/packages/vue/package.json index 867142a2..c4f929ae 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -45,6 +45,7 @@ "access": "public" }, "devDependencies": { + "prosemirror-state": "^1.4.3", "prosemirror-view": "^1.41.6" } } diff --git a/packages/vue/src/components/BasicToolbar.vue b/packages/vue/src/components/BasicToolbar.vue new file mode 100644 index 00000000..f8cb0873 --- /dev/null +++ b/packages/vue/src/components/BasicToolbar.vue @@ -0,0 +1,94 @@ + + + + + diff --git a/packages/vue/src/components/DocxEditorVue.vue b/packages/vue/src/components/DocxEditorVue.vue new file mode 100644 index 00000000..5314ac86 --- /dev/null +++ b/packages/vue/src/components/DocxEditorVue.vue @@ -0,0 +1,308 @@ + + + + + diff --git a/packages/vue/src/composables/useDocxEditor.ts b/packages/vue/src/composables/useDocxEditor.ts new file mode 100644 index 00000000..aedf8f50 --- /dev/null +++ b/packages/vue/src/composables/useDocxEditor.ts @@ -0,0 +1,401 @@ +/** + * useDocxEditor — Vue composable for the DOCX editor lifecycle. + * + * Manages: DOCX parsing → ProseMirror state → layout pipeline → DOM painting. + * This is the Vue equivalent of PagedEditor + HiddenProseMirror from the React package. + */ + +import { ref, onBeforeUnmount, shallowRef, type Ref } from 'vue'; +import { EditorState, type Transaction, type Plugin } from 'prosemirror-state'; +import { EditorView } from 'prosemirror-view'; + +// Core imports — these all resolve through Vite aliases to packages/core/src/ +import { parseDocx } from '@eigenpal/docx-core/docx/parser'; +import { toProseDoc, createEmptyDoc } from '@eigenpal/docx-core/prosemirror/conversion'; +import { fromProseDoc } from '@eigenpal/docx-core/prosemirror/conversion/fromProseDoc'; +import { singletonManager } from '@eigenpal/docx-core/prosemirror/schema'; +import { toFlowBlocks } from '@eigenpal/docx-core/layout-bridge/toFlowBlocks'; +import { measureParagraph } from '@eigenpal/docx-core/layout-bridge/measuring'; +import { layoutDocument } from '@eigenpal/docx-core/layout-engine'; +import { renderPages } from '@eigenpal/docx-core/layout-painter/renderPage'; +import type { + FlowBlock, + Measure, + ParagraphBlock, + TableBlock, + TableMeasure, + ImageBlock, + PageMargins, +} from '@eigenpal/docx-core/layout-engine/types'; +import type { BlockLookup } from '@eigenpal/docx-core/layout-painter'; +import type { Document, SectionProperties } from '@eigenpal/docx-core/types/document'; + +// ProseMirror CSS — must be imported for the hidden editor to work +import 'prosemirror-view/style/prosemirror.css'; +import '@eigenpal/docx-core/prosemirror/editor.css'; + +// ============================================================================ +// CONSTANTS +// ============================================================================ + +const DEFAULT_PAGE_WIDTH = 816; // 8.5in at 96dpi +const DEFAULT_PAGE_HEIGHT = 1056; // 11in at 96dpi +const DEFAULT_MARGINS: PageMargins = { top: 96, right: 96, bottom: 96, left: 96 }; +const DEFAULT_PAGE_GAP = 24; + +// ============================================================================ +// HELPERS +// ============================================================================ + +function twipsToPixels(twips: number): number { + return Math.round((twips / 1440) * 96); +} + +function getPageSize(sp: SectionProperties | null | undefined) { + return { + w: sp?.pageWidth ? twipsToPixels(sp.pageWidth) : DEFAULT_PAGE_WIDTH, + h: sp?.pageHeight ? twipsToPixels(sp.pageHeight) : DEFAULT_PAGE_HEIGHT, + }; +} + +function getMargins(sp: SectionProperties | null | undefined): PageMargins { + return { + top: sp?.marginTop ? twipsToPixels(sp.marginTop) : DEFAULT_MARGINS.top, + right: sp?.marginRight ? twipsToPixels(sp.marginRight) : DEFAULT_MARGINS.right, + bottom: sp?.marginBottom ? twipsToPixels(sp.marginBottom) : DEFAULT_MARGINS.bottom, + left: sp?.marginLeft ? twipsToPixels(sp.marginLeft) : DEFAULT_MARGINS.left, + }; +} + +/** + * Simplified block measurement (no floating zone support for the minimal harness). + * Contributors can port the full measureBlocks from PagedEditor later. + */ +function measureBlock(block: FlowBlock, contentWidth: number): Measure { + switch (block.kind) { + case 'paragraph': + return measureParagraph(block as ParagraphBlock, contentWidth); + + case 'table': { + const tb = block as TableBlock; + let columnWidths = tb.columnWidths ?? []; + if (columnWidths.length === 0 && tb.rows.length > 0) { + const colCount = tb.rows[0].cells.reduce((sum, cell) => sum + (cell.colSpan ?? 1), 0); + const equalWidth = contentWidth / Math.max(1, colCount); + columnWidths = Array(colCount).fill(equalWidth); + } + + const rows = tb.rows.map((row) => { + let colIdx = 0; + const cells = row.cells.map((cell) => { + const colSpan = cell.colSpan ?? 1; + let cellWidth = 0; + for (let c = 0; c < colSpan && colIdx + c < columnWidths.length; c++) { + cellWidth += columnWidths[colIdx + c] ?? 0; + } + if (cellWidth === 0) cellWidth = cell.width ?? 100; + colIdx += colSpan; + + const cellContentWidth = Math.max(1, cellWidth - 14); // ~7px padding each side + const blocks = cell.blocks.map((b) => measureBlock(b, cellContentWidth)); + const height = + blocks.reduce( + (h, m) => h + ('totalHeight' in m ? (m as { totalHeight: number }).totalHeight : 0), + 0 + ) + 2; // padding + + return { blocks, width: cellWidth, height, colSpan: cell.colSpan, rowSpan: cell.rowSpan }; + }); + + const maxHeight = Math.max(24, ...cells.map((c) => c.height)); + return { cells, height: maxHeight }; + }); + + const totalWidth = columnWidths.reduce((s, w) => s + w, 0) || contentWidth; + const totalHeight = rows.reduce((h, r) => h + r.height, 0); + return { kind: 'table', rows, columnWidths, totalWidth, totalHeight } as TableMeasure; + } + + case 'image': { + const ib = block as ImageBlock; + return { kind: 'image', width: ib.width ?? 100, height: ib.height ?? 100 }; + } + + case 'pageBreak': + return { kind: 'pageBreak' }; + + case 'columnBreak': + return { kind: 'columnBreak' }; + + case 'sectionBreak': + return { kind: 'sectionBreak' }; + + default: + return { kind: 'paragraph', lines: [], totalHeight: 0 }; + } +} + +function measureBlocks(blocks: FlowBlock[], contentWidth: number): Measure[] { + return blocks.map((b) => measureBlock(b, contentWidth)); +} + +// ============================================================================ +// COMPOSABLE +// ============================================================================ + +export interface UseDocxEditorOptions { + /** Container element for the hidden ProseMirror editor */ + hiddenContainer: Ref; + /** Container element for the visible pages */ + pagesContainer: Ref; + /** Whether the editor is read-only */ + readOnly?: boolean; + /** Page gap in pixels */ + pageGap?: number; + /** Callback on document change */ + onChange?: (doc: Document) => void; + /** Callback on error */ + onError?: (error: Error) => void; + /** Callback on selection change */ + onSelectionUpdate?: () => void; +} + +export function useDocxEditor(options: UseDocxEditorOptions) { + const { + hiddenContainer, + pagesContainer, + readOnly = false, + pageGap = DEFAULT_PAGE_GAP, + onChange, + onError, + onSelectionUpdate, + } = options; + + // State + const document = shallowRef(null); + const editorView = shallowRef(null); + const isReady = ref(false); + const parseError = ref(null); + + // Use the singleton extension manager — same schema used by toProseDoc/commands + const mgr = singletonManager; + + // ======================================================================== + // Layout pipeline + // ======================================================================== + + function runLayoutPipeline(state: EditorState) { + const container = pagesContainer.value; + if (!container || !document.value) return; + + const sp = document.value.package?.document?.finalSectionProperties ?? null; + const pageSize = getPageSize(sp); + const margins = getMargins(sp); + const contentWidth = pageSize.w - margins.left - margins.right; + const pageContentHeight = pageSize.h - margins.top - margins.bottom; + const theme = document.value.package?.theme ?? null; + + try { + // Step 1: PM doc → flow blocks + const blocks = toFlowBlocks(state.doc, { theme, pageContentHeight }); + + // Step 2: Measure blocks + const measures = measureBlocks(blocks, contentWidth); + + // Step 3: Layout + const newLayout = layoutDocument(blocks, measures, { pageSize, margins }); + + // Step 4: Build block lookup and paint + const blockLookup: BlockLookup = new Map(); + for (let i = 0; i < blocks.length; i++) { + const block = blocks[i]; + const measure = measures[i]; + if (block && measure) { + blockLookup.set(String(block.id), { block, measure }); + } + } + + renderPages(newLayout.pages, container, { + pageGap, + showShadow: true, + pageBackground: '#fff', + blockLookup, + theme, + } as Parameters[2]); + + // renderPages sets display:flex on the container — fix scrolling + container.style.overflowY = 'auto'; + container.style.minHeight = '0'; + // Prevent page elements from stretching to fill the flex container + for (const child of Array.from(container.children)) { + (child as HTMLElement).style.flexShrink = '0'; + } + } catch (err) { + console.error('[useDocxEditor] Layout pipeline error:', err); + onError?.(err instanceof Error ? err : new Error(String(err))); + } + } + + // ======================================================================== + // ProseMirror setup + // ======================================================================== + + function createEditorView() { + const host = hiddenContainer.value; + if (!host) return; + + const doc = document.value + ? toProseDoc(document.value, { + styles: document.value.package?.styles ?? undefined, + }) + : createEmptyDoc(); + + const plugins: Plugin[] = [...(mgr.getPlugins() ?? [])]; + + const state = EditorState.create({ + doc, + schema: mgr.getSchema(), + plugins, + }); + + const view = new EditorView(host, { + state, + editable: () => !readOnly, + dispatchTransaction(transaction: Transaction) { + if (!view) return; + const newState = view.state.apply(transaction); + view.updateState(newState); + + // Re-layout on doc changes + if (transaction.docChanged) { + runLayoutPipeline(newState); + // Notify parent about document change + if (document.value) { + const updatedDoc = fromProseDoc(newState.doc, document.value); + onChange?.(updatedDoc); + } + } + + // Notify about selection changes (for highlight overlay) + onSelectionUpdate?.(); + }, + }); + + editorView.value = view; + isReady.value = true; + + // Initial layout + runLayoutPipeline(state); + } + + function destroyEditorView() { + if (editorView.value) { + editorView.value.destroy(); + editorView.value = null; + } + isReady.value = false; + } + + // ======================================================================== + // Document loading + // ======================================================================== + + async function loadBuffer(buffer: ArrayBuffer | Uint8Array | Blob | File) { + parseError.value = null; + isReady.value = false; + + try { + let arrayBuf: ArrayBuffer; + if (buffer instanceof Blob || buffer instanceof File) { + arrayBuf = await buffer.arrayBuffer(); + } else if (buffer instanceof Uint8Array) { + arrayBuf = buffer.buffer.slice( + buffer.byteOffset, + buffer.byteOffset + buffer.byteLength + ) as ArrayBuffer; + } else { + arrayBuf = buffer; + } + + const doc = await parseDocx(arrayBuf); + document.value = doc; + + // Recreate PM view with new document + destroyEditorView(); + createEditorView(); + } catch (err) { + const error = err instanceof Error ? err : new Error(String(err)); + parseError.value = error.message; + onError?.(error); + } + } + + function loadDocument(doc: Document) { + parseError.value = null; + document.value = doc; + destroyEditorView(); + createEditorView(); + } + + // ======================================================================== + // Public API + // ======================================================================== + + async function save(): Promise { + if (!editorView.value || !document.value) return null; + + const { repackDocx, createDocx } = await import('@eigenpal/docx-core/docx/rezip'); + + const updatedDoc = fromProseDoc(editorView.value.state.doc, document.value); + let buffer: ArrayBuffer; + if (updatedDoc.originalBuffer) { + buffer = await repackDocx(updatedDoc); + } else { + buffer = await createDocx(updatedDoc); + } + return new Blob([buffer], { + type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + }); + } + + function focus() { + editorView.value?.focus(); + } + + function destroy() { + destroyEditorView(); + document.value = null; + } + + function getDocument(): Document | null { + return document.value; + } + + // ======================================================================== + // Lifecycle + // ======================================================================== + + onBeforeUnmount(() => { + destroy(); + }); + + function getCommands() { + return mgr.getCommands(); + } + + return { + // State + editorView, + isReady, + parseError, + + // Actions + loadBuffer, + loadDocument, + save, + focus, + destroy, + getDocument, + getCommands, + }; +} diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts index 65bb80bc..d03b046d 100644 --- a/packages/vue/src/index.ts +++ b/packages/vue/src/index.ts @@ -4,7 +4,15 @@ // This package provides Vue 3 components wrapping @eigenpal/docx-core. // Contributions welcome! See the repository README for guidelines. -// renderAsync stub +// Components +export { default as DocxEditorVue } from './components/DocxEditorVue.vue'; +export { default as BasicToolbar } from './components/BasicToolbar.vue'; + +// Composables +export { useDocxEditor } from './composables/useDocxEditor'; +export type { UseDocxEditorOptions } from './composables/useDocxEditor'; + +// renderAsync export { renderAsync } from './renderAsync'; export type { VueRenderAsyncOptions } from './renderAsync'; diff --git a/packages/vue/src/renderAsync.ts b/packages/vue/src/renderAsync.ts index 02a0376e..92ec9417 100644 --- a/packages/vue/src/renderAsync.ts +++ b/packages/vue/src/renderAsync.ts @@ -1,13 +1,12 @@ /** - * Vue renderAsync — scaffold for community implementation. - * - * This is a placeholder that defines the expected API. - * A Vue contributor can implement this using `createApp().mount()`. + * Vue renderAsync — mounts a DocxEditorVue into a container element. */ +import { createApp, h, type App } from 'vue'; +import DocxEditorVue from './components/DocxEditorVue.vue'; import type { EditorHandle } from '@eigenpal/docx-core'; -/** Options for the Vue renderAsync (to be defined by implementor). */ +/** Options for the Vue renderAsync. */ export interface VueRenderAsyncOptions { readOnly?: boolean; showToolbar?: boolean; @@ -21,13 +20,59 @@ export interface VueRenderAsyncOptions { * @param options - Editor configuration * @returns A handle implementing the framework-agnostic EditorHandle interface */ -export function renderAsync( - _input: ArrayBuffer | Uint8Array | Blob | File, - _container: HTMLElement, - _options: VueRenderAsyncOptions = {} +export async function renderAsync( + input: ArrayBuffer | Uint8Array | Blob | File, + container: HTMLElement, + options: VueRenderAsyncOptions = {} ): Promise { - throw new Error( - '@eigenpal/docx-editor-vue renderAsync is not yet implemented. ' + - 'Community contributions welcome!' - ); + // Convert to ArrayBuffer upfront — loadBuffer also handles this, + // but we need a stable value for the prop. + let buffer: ArrayBuffer; + if (input instanceof Blob || input instanceof File) { + buffer = await input.arrayBuffer(); + } else if (input instanceof Uint8Array) { + buffer = input.buffer.slice( + input.byteOffset, + input.byteOffset + input.byteLength + ) as ArrayBuffer; + } else { + buffer = input; + } + + let editorRef: any = null; + + const app: App = createApp({ + setup() { + return () => + h(DocxEditorVue, { + documentBuffer: buffer, + showToolbar: options.showToolbar ?? true, + readOnly: options.readOnly ?? false, + ref: (el: any) => { + editorRef = el; + }, + }); + }, + }); + + app.mount(container); + + // Wait a tick for mount to complete + await new Promise((resolve) => setTimeout(resolve, 0)); + + return { + save: async () => { + return editorRef?.save() ?? null; + }, + getDocument: () => { + return editorRef?.getDocument() ?? null; + }, + focus: () => { + editorRef?.focus(); + }, + destroy: () => { + editorRef?.destroy(); + app.unmount(); + }, + }; } diff --git a/packages/vue/src/shims-vue.d.ts b/packages/vue/src/shims-vue.d.ts new file mode 100644 index 00000000..0c729c99 --- /dev/null +++ b/packages/vue/src/shims-vue.d.ts @@ -0,0 +1,6 @@ +declare module '*.vue' { + import type { DefineComponent } from 'vue'; + + const component: DefineComponent<{}, {}, any>; + export default component; +} From 48026e65da9406330435aa4dc115c4461b9523b4 Mon Sep 17 00:00:00 2001 From: Lennart Fries Date: Thu, 2 Apr 2026 21:13:36 +0200 Subject: [PATCH 2/3] feat(vue): add full toolbar, dialogs, sidebar, and fix command integration Adds all Vue components (toolbar, dialogs, context menus, sidebar, overlays), composables (zoom, auto-save, table selection), and i18n support. Fixes toolbar reactivity for font size/family/color by reading marks from first text node in selection range. Fixes page break insertion, style dropdown (with style resolution), page setup re-layout, text color, and clear formatting commands. Co-Authored-By: Claude Opus 4.6 --- packages/vue/i18n/en.json | 745 +++++++++++++++++ packages/vue/src/components/AIContextMenu.vue | 133 +++ .../vue/src/components/AIResponsePreview.vue | 196 +++++ packages/vue/src/components/BasicToolbar.vue | 763 +++++++++++++++++- packages/vue/src/components/DocumentName.vue | 70 ++ .../vue/src/components/DocumentOutline.vue | 94 +++ packages/vue/src/components/DocxEditorVue.vue | 746 ++++++++++++++++- packages/vue/src/components/ErrorBoundary.vue | 145 ++++ .../vue/src/components/FindReplaceDialog.vue | 382 +++++++++ .../components/FootnotePropertiesDialog.vue | 143 ++++ .../vue/src/components/HorizontalRuler.vue | 280 +++++++ .../vue/src/components/HyperlinkDialog.vue | 140 ++++ .../vue/src/components/ImageEditOverlay.vue | 246 ++++++ .../src/components/ImagePositionDialog.vue | 183 +++++ .../src/components/ImagePropertiesDialog.vue | 181 +++++ .../components/InlineHeaderFooterEditor.vue | 164 ++++ .../vue/src/components/InsertImageDialog.vue | 173 ++++ .../vue/src/components/InsertSymbolDialog.vue | 214 +++++ .../vue/src/components/InsertTableDialog.vue | 76 ++ .../components/KeyboardShortcutsDialog.vue | 198 +++++ packages/vue/src/components/MenuBar.vue | 122 +++ .../vue/src/components/PageSetupDialog.vue | 183 +++++ .../vue/src/components/PasteSpecialDialog.vue | 98 +++ packages/vue/src/components/PrintButton.vue | 54 ++ .../vue/src/components/ResponsiveToolbar.vue | 130 +++ .../src/components/TablePropertiesDialog.vue | 95 +++ .../vue/src/components/TableStyleGallery.vue | 137 ++++ packages/vue/src/components/TableToolbar.vue | 106 +++ .../vue/src/components/TextContextMenu.vue | 177 ++++ .../vue/src/components/UnsavedIndicator.vue | 104 +++ packages/vue/src/components/VerticalRuler.vue | 211 +++++ .../src/components/sidebar/AddCommentCard.vue | 95 +++ .../src/components/sidebar/CommentCard.vue | 218 +++++ .../components/sidebar/TrackedChangeCard.vue | 127 +++ .../src/components/sidebar/UnifiedSidebar.vue | 184 +++++ .../src/components/sidebar/sidebarUtils.ts | 64 ++ packages/vue/src/composables/useAutoSave.ts | 101 +++ packages/vue/src/composables/useDocxEditor.ts | 42 +- .../vue/src/composables/useTableSelection.ts | 56 ++ packages/vue/src/composables/useZoom.ts | 71 ++ packages/vue/src/i18n/index.ts | 160 ++++ packages/vue/src/index.ts | 42 + 42 files changed, 7801 insertions(+), 48 deletions(-) create mode 100644 packages/vue/i18n/en.json create mode 100644 packages/vue/src/components/AIContextMenu.vue create mode 100644 packages/vue/src/components/AIResponsePreview.vue create mode 100644 packages/vue/src/components/DocumentName.vue create mode 100644 packages/vue/src/components/DocumentOutline.vue create mode 100644 packages/vue/src/components/ErrorBoundary.vue create mode 100644 packages/vue/src/components/FindReplaceDialog.vue create mode 100644 packages/vue/src/components/FootnotePropertiesDialog.vue create mode 100644 packages/vue/src/components/HorizontalRuler.vue create mode 100644 packages/vue/src/components/HyperlinkDialog.vue create mode 100644 packages/vue/src/components/ImageEditOverlay.vue create mode 100644 packages/vue/src/components/ImagePositionDialog.vue create mode 100644 packages/vue/src/components/ImagePropertiesDialog.vue create mode 100644 packages/vue/src/components/InlineHeaderFooterEditor.vue create mode 100644 packages/vue/src/components/InsertImageDialog.vue create mode 100644 packages/vue/src/components/InsertSymbolDialog.vue create mode 100644 packages/vue/src/components/InsertTableDialog.vue create mode 100644 packages/vue/src/components/KeyboardShortcutsDialog.vue create mode 100644 packages/vue/src/components/MenuBar.vue create mode 100644 packages/vue/src/components/PageSetupDialog.vue create mode 100644 packages/vue/src/components/PasteSpecialDialog.vue create mode 100644 packages/vue/src/components/PrintButton.vue create mode 100644 packages/vue/src/components/ResponsiveToolbar.vue create mode 100644 packages/vue/src/components/TablePropertiesDialog.vue create mode 100644 packages/vue/src/components/TableStyleGallery.vue create mode 100644 packages/vue/src/components/TableToolbar.vue create mode 100644 packages/vue/src/components/TextContextMenu.vue create mode 100644 packages/vue/src/components/UnsavedIndicator.vue create mode 100644 packages/vue/src/components/VerticalRuler.vue create mode 100644 packages/vue/src/components/sidebar/AddCommentCard.vue create mode 100644 packages/vue/src/components/sidebar/CommentCard.vue create mode 100644 packages/vue/src/components/sidebar/TrackedChangeCard.vue create mode 100644 packages/vue/src/components/sidebar/UnifiedSidebar.vue create mode 100644 packages/vue/src/components/sidebar/sidebarUtils.ts create mode 100644 packages/vue/src/composables/useAutoSave.ts create mode 100644 packages/vue/src/composables/useTableSelection.ts create mode 100644 packages/vue/src/composables/useZoom.ts create mode 100644 packages/vue/src/i18n/index.ts diff --git a/packages/vue/i18n/en.json b/packages/vue/i18n/en.json new file mode 100644 index 00000000..0c8e38fe --- /dev/null +++ b/packages/vue/i18n/en.json @@ -0,0 +1,745 @@ +{ + "_lang": "en", + "common": { + "cancel": "Cancel", + "insert": "Insert", + "apply": "Apply", + "close": "Close", + "delete": "Delete", + "update": "Update", + "save": "Save", + "retry": "Retry", + "send": "Send", + "edit": "Edit", + "comment": "Comment", + "reply": "Reply", + "accept": "Accept", + "reject": "Reject", + "dismiss": "Dismiss", + "change": "Change", + "px": "px", + "closeDialog": "Close dialog" + }, + "toolbar": { + "ariaLabel": "Formatting toolbar", + "file": "File", + "format": "Format", + "insert": "Insert", + "print": "Print", + "printShortcut": "Ctrl+P", + "pageSetup": "Page setup", + "leftToRight": "Left-to-right text", + "rightToLeft": "Right-to-left text", + "image": "Image", + "table": "Table", + "pageBreak": "Page break", + "tableOfContents": "Table of contents", + "symbol": "Symbol" + }, + "formattingBar": { + "groups": { + "history": "History", + "zoom": "Zoom", + "styles": "Styles", + "font": "Font", + "textFormatting": "Text formatting", + "script": "Script", + "alignment": "Alignment", + "listFormatting": "List formatting", + "image": "Image", + "table": "Table" + }, + "undo": "Undo", + "undoShortcut": "Undo (Ctrl+Z)", + "redo": "Redo", + "redoShortcut": "Redo (Ctrl+Y)", + "bold": "Bold", + "boldShortcut": "Bold (Ctrl+B)", + "italic": "Italic", + "italicShortcut": "Italic (Ctrl+I)", + "underline": "Underline", + "underlineShortcut": "Underline (Ctrl+U)", + "strikethrough": "Strikethrough", + "fontColor": "Font Color", + "highlightColor": "Text Highlight Color", + "insertLink": "Insert link", + "insertLinkShortcut": "Insert link (Ctrl+K)", + "superscript": "Superscript", + "superscriptShortcut": "Superscript (Ctrl+Shift+=)", + "subscript": "Subscript", + "subscriptShortcut": "Subscript (Ctrl+=)", + "imageProperties": "Image properties", + "imagePropertiesShortcut": "Image properties (alt text, border)...", + "clearFormatting": "Clear formatting" + }, + "alignment": { + "alignLeft": "Align Left", + "alignLeftShortcut": "Ctrl+L", + "center": "Center", + "centerShortcut": "Ctrl+E", + "alignRight": "Align Right", + "alignRightShortcut": "Ctrl+R", + "justify": "Justify", + "justifyShortcut": "Ctrl+J" + }, + "lists": { + "ariaLabel": "List formatting", + "typeAriaLabel": "List type", + "indentationAriaLabel": "List indentation", + "bulletList": "Bullet List", + "numberedList": "Numbered List", + "decreaseIndent": "Decrease Indent", + "increaseIndent": "Increase Indent" + }, + "lineSpacing": { + "single": "Single", + "double": "Double", + "lineSpacingTitle": "Line spacing: {label}", + "paragraphSpacing": "Paragraph spacing" + }, + "styles": { + "selectAriaLabel": "Select paragraph style", + "normalText": "Normal text", + "title": "Title", + "subtitle": "Subtitle", + "heading1": "Heading 1", + "heading2": "Heading 2", + "heading3": "Heading 3" + }, + "font": { + "selectAriaLabel": "Select font family", + "sansSerif": "Sans Serif", + "serif": "Serif", + "monospace": "Monospace" + }, + "fontSize": { + "decrease": "Decrease font size", + "increase": "Increase font size", + "label": "Font size", + "listLabel": "Font sizes" + }, + "zoom": { + "ariaLabel": "Zoom: {label}" + }, + "colorPicker": { + "ariaLabel": "{type} color picker", + "highlightColors": "Highlight Colors", + "customColor": "Custom Color", + "noColor": "No Color", + "automatic": "Automatic", + "themeColors": "Theme Colors", + "standardColors": "Standard Colors", + "colors": { + "black": "Black", + "darkRed": "Dark Red", + "red": "Red", + "orange": "Orange", + "yellow": "Yellow", + "darkYellow": "Dark Yellow", + "green": "Green", + "darkGreen": "Dark Green", + "teal": "Teal", + "darkTeal": "Dark Teal", + "blue": "Blue", + "darkBlue": "Dark Blue", + "purple": "Purple", + "darkPurple": "Dark Purple", + "brown": "Brown", + "grey50": "Grey 50%", + "grey25": "Grey 25%", + "grey10": "Grey 10%", + "white": "White", + "lightRed": "Light Red", + "lightOrange": "Light Orange", + "lightYellow": "Light Yellow", + "lightGreen": "Light Green", + "lightBlue": "Light Blue", + "lightPurple": "Light Purple", + "pink": "Pink", + "rose": "Rose", + "gold": "Gold", + "aqua": "Aqua", + "lavender": "Lavender", + "silver": "Silver", + "darkOrange": "Dark Orange", + "darkGray": "Dark Gray", + "gray": "Gray", + "cyan": "Cyan", + "magenta": "Magenta", + "paleGreen": "Pale Green", + "lightCyan": "Light Cyan", + "skyBlue": "Sky Blue", + "lightBlue2": "Light Blue 2", + "lightMagenta": "Light Magenta", + "brightGreen": "Bright Green", + "violet": "Violet" + } + }, + "dialogs": { + "findReplace": { + "titleFind": "Find", + "titleFindReplace": "Find and Replace", + "findLabel": "Find:", + "findPlaceholder": "Enter text to find...", + "findAriaLabel": "Find text", + "findPrevious": "Find previous", + "findPreviousTitle": "Find Previous (Shift+Enter)", + "findNext": "Find next", + "findNextTitle": "Find Next (Enter)", + "matchCount": "{current} of {total} matches", + "noResults": "No results found", + "replaceLabel": "Replace:", + "replacePlaceholder": "Enter replacement text...", + "replaceAriaLabel": "Replace text", + "replaceButton": "Replace", + "replaceCurrentTitle": "Replace current match", + "replaceAllButton": "Replace All", + "replaceAllTitle": "Replace all matches", + "matchCase": "Match case", + "wholeWords": "Whole words", + "toggleReplace": "+ Replace" + }, + "hyperlink": { + "titleEdit": "Edit Hyperlink", + "titleInsert": "Insert Hyperlink", + "tabWebAddress": "Web Address", + "tabBookmark": "Bookmark", + "urlLabel": "URL", + "urlPlaceholder": "https://example.com", + "urlHint": "Enter a web address, email (mailto:), or phone (tel:)", + "bookmarkLabel": "Bookmark", + "bookmarkPlaceholder": "Select a bookmark...", + "displayTextLabel": "Display Text", + "displayTextPlaceholder": "Text to display (optional)", + "displayTextHint": "Leave empty to use the selected text", + "tooltipLabel": "Tooltip (optional)", + "tooltipPlaceholder": "Text shown on hover", + "removeLink": "Remove Link", + "invalidUrl": "Please enter a valid URL", + "urlRequired": "URL is required" + }, + "insertTable": { + "title": "Insert Table", + "hoverToSelect": "Hover to select size", + "tableSize": "{cols} x {rows} Table", + "orSpecifySize": "or specify size", + "rowsLabel": "Rows:", + "columnsLabel": "Columns:", + "insertButton": "Insert Table", + "sizeSelector": "Table size selector" + }, + "insertImage": { + "title": "Insert Image", + "uploadAriaLabel": "Click or drag to upload image", + "uploadText": "Click to select or drag and drop an image", + "uploadSubtext": "PNG, JPG, GIF up to 10MB", + "dimensions": "Dimensions", + "widthLabel": "Width:", + "heightLabel": "Height:", + "aspectRatioLocked": "Aspect ratio locked", + "aspectRatioUnlocked": "Aspect ratio unlocked", + "altTextLabel": "Alt Text (optional)", + "altTextPlaceholder": "Describe the image for accessibility", + "insertButton": "Insert Image", + "invalidFile": "Please select a valid image file", + "fileTooLarge": "Image file is too large (max 10MB)", + "readFailed": "Failed to read image file", + "loadFailed": "Failed to load image", + "preview": "Preview" + }, + "insertSymbol": { + "title": "Insert Symbol", + "searchPlaceholder": "Search symbols (character or Unicode)...", + "noResults": "No symbols found for \"{query}\"", + "decimal": "Decimal: {value}", + "categories": { + "common": "Common", + "arrows": "Arrows", + "math": "Math", + "greek": "Greek", + "shapes": "Shapes", + "punctuation": "Punctuation", + "currency": "Currency", + "music": "Music", + "emoji": "Emoji" + } + }, + "imageProperties": { + "title": "Image Properties", + "altText": "Alt Text", + "altTextPlaceholder": "Describe this image for accessibility...", + "border": "Border", + "width": "Width", + "style": "Style", + "color": "Color", + "preview": "Preview", + "borderStyles": { + "solid": "Solid", + "dashed": "Dashed", + "dotted": "Dotted", + "double": "Double", + "groove": "Groove", + "ridge": "Ridge", + "inset": "Inset", + "outset": "Outset" + } + }, + "imagePosition": { + "title": "Image Position", + "horizontal": "Horizontal", + "vertical": "Vertical", + "position": "Position", + "alignment": "Alignment", + "offset": "Offset", + "offsetPx": "Offset (px)", + "align": "Align", + "relativeTo": "Relative to", + "alignOptions": { + "left": "Left", + "center": "Center", + "right": "Right", + "top": "Top", + "bottom": "Bottom" + }, + "relativeOptions": { + "page": "Page", + "column": "Column", + "margin": "Margin", + "character": "Character", + "paragraph": "Paragraph", + "line": "Line" + } + }, + "pageSetup": { + "title": "Page Setup", + "pageSize": "PAGE SIZE", + "sizeLabel": "Size", + "custom": "Custom", + "orientation": "Orientation", + "portrait": "Portrait", + "landscape": "Landscape", + "margins": "MARGINS", + "top": "Top", + "bottom": "Bottom", + "left": "Left", + "right": "Right", + "pageSizes": { + "letter": "Letter (8.5\" × 11\")", + "a4": "A4 (8.27\" × 11.69\")", + "legal": "Legal (8.5\" × 14\")", + "a3": "A3 (11.69\" × 16.54\")", + "a5": "A5 (5.83\" × 8.27\")", + "b5": "B5 (6.93\" × 9.84\")", + "executive": "Executive (7.25\" × 10.5\")" + } + }, + "tableProperties": { + "title": "Table Properties", + "widthType": "Width type", + "widthLabel": "Width", + "alignmentLabel": "Alignment", + "widthTypes": { + "auto": "Auto", + "fixed": "Fixed (twips)", + "percentage": "Percentage" + }, + "units": { + "fiftiethsPercent": "(50ths of %)", + "twips": "tw" + }, + "alignOptions": { + "left": "Left", + "center": "Center", + "right": "Right" + } + }, + "pasteSpecial": { + "title": "Paste Special", + "keepFormatting": "Keep Source Formatting", + "keepFormattingDescription": "Paste with original formatting", + "keepFormattingShortcut": "Ctrl+V", + "plainText": "Paste as Plain Text", + "plainTextDescription": "Paste without any formatting", + "plainTextShortcut": "Ctrl+Shift+V", + "readingClipboard": "Reading clipboard...", + "preview": "Preview:", + "noContent": "No content available to paste", + "clipboardError": "Unable to read clipboard. Please use Ctrl+V to paste." + }, + "footnoteProperties": { + "title": "Footnote & Endnote Properties", + "footnotes": "Footnotes", + "endnotes": "Endnotes", + "position": "Position", + "numberFormat": "Number format", + "startAt": "Start at", + "numbering": "Numbering", + "footnotePositions": { + "bottomOfPage": "Bottom of page", + "belowText": "Below text" + }, + "endnotePositions": { + "endOfDocument": "End of document", + "endOfSection": "End of section" + }, + "numberingOptions": { + "continuous": "Continuous", + "restartSection": "Restart each section", + "restartPage": "Restart each page" + }, + "formats": { + "decimal": "1, 2, 3, ...", + "lowerRoman": "i, ii, iii, ...", + "upperRoman": "I, II, III, ...", + "lowerAlpha": "a, b, c, ...", + "upperAlpha": "A, B, C, ...", + "symbols": "*, †, ‡, ..." + } + }, + "keyboardShortcuts": { + "ariaLabel": "Keyboard Shortcuts", + "searchPlaceholder": "Search shortcuts...", + "categories": { + "editing": "Editing", + "formatting": "Formatting", + "navigation": "Navigation", + "clipboard": "Clipboard", + "selection": "Selection", + "view": "View", + "file": "File", + "other": "Other" + }, + "shortcuts": { + "save": "Save", + "saveDescription": "Save document", + "print": "Print", + "printDescription": "Print document", + "undo": "Undo", + "undoDescription": "Undo last action", + "redo": "Redo", + "redoDescription": "Redo last action", + "delete": "Delete", + "deleteDescription": "Delete selected text", + "find": "Find", + "findDescription": "Find text in document", + "findReplace": "Find & Replace", + "findReplaceDescription": "Find and replace text", + "cut": "Cut", + "cutDescription": "Cut selected text", + "copy": "Copy", + "copyDescription": "Copy selected text", + "paste": "Paste", + "pasteDescription": "Paste from clipboard", + "pastePlainText": "Paste as Plain Text", + "pastePlainTextDescription": "Paste without formatting", + "bold": "Bold", + "boldDescription": "Toggle bold formatting", + "italic": "Italic", + "italicDescription": "Toggle italic formatting", + "underline": "Underline", + "underlineDescription": "Toggle underline formatting", + "strikethrough": "Strikethrough", + "strikethroughDescription": "Toggle strikethrough", + "subscript": "Subscript", + "subscriptDescription": "Toggle subscript", + "superscript": "Superscript", + "superscriptDescription": "Toggle superscript", + "alignLeft": "Align Left", + "alignLeftDescription": "Left align paragraph", + "alignCenter": "Align Center", + "alignCenterDescription": "Center align paragraph", + "alignRight": "Align Right", + "alignRightDescription": "Right align paragraph", + "justify": "Justify", + "justifyDescription": "Justify paragraph", + "increaseIndent": "Increase Indent", + "increaseIndentDescription": "Increase paragraph indent", + "decreaseIndent": "Decrease Indent", + "decreaseIndentDescription": "Decrease paragraph indent", + "selectAll": "Select All", + "selectAllDescription": "Select all content", + "selectWord": "Select Word", + "selectWordDescription": "Select current word", + "selectParagraph": "Select Paragraph", + "selectParagraphDescription": "Select current paragraph", + "extendSelectionByWord": "Extend Selection by Word", + "extendSelectionByWordDescription": "Extend selection to next/previous word", + "extendSelectionToLineEdge": "Extend Selection to Line Edge", + "extendSelectionToLineEdgeDescription": "Extend selection to line start/end", + "moveByWord": "Move by Word", + "moveByWordDescription": "Move cursor to next/previous word", + "moveToLineStart": "Move to Line Start", + "moveToLineStartDescription": "Move cursor to start of line", + "moveToLineEnd": "Move to Line End", + "moveToLineEndDescription": "Move cursor to end of line", + "moveToDocumentStart": "Move to Document Start", + "moveToDocumentStartDescription": "Move cursor to start of document", + "moveToDocumentEnd": "Move to Document End", + "moveToDocumentEndDescription": "Move cursor to end of document", + "pageUp": "Page Up", + "pageUpDescription": "Scroll up one page", + "pageDown": "Page Down", + "pageDownDescription": "Scroll down one page", + "zoomIn": "Zoom In", + "zoomInDescription": "Increase zoom level", + "zoomOut": "Zoom Out", + "zoomOutDescription": "Decrease zoom level", + "resetZoom": "Reset Zoom", + "resetZoomDescription": "Reset zoom to 100%", + "keyboardShortcuts": "Keyboard Shortcuts", + "keyboardShortcutsDescription": "Show this help dialog" + }, + "noResults": "No shortcuts found matching \"{query}\"", + "pressEscToClose": "Press {key} to close", + "or": "or" + } + }, + "comments": { + "resolved": "Resolved", + "resolve": "Resolve", + "reopen": "Reopen", + "moreOptions": "More options", + "unknown": "Unknown", + "addComment": "Add a comment...", + "replyPlaceholder": "Reply or add others with @", + "replyCount": "{count, plural, one {# reply} other {# replies}}" + }, + "trackedChanges": { + "unknown": "Unknown", + "replaced": "Replaced", + "with": "with", + "added": "Added", + "deleted": "Deleted" + }, + "contextMenu": { + "ariaLabel": "AI actions menu", + "textMenuAriaLabel": "Text editing menu", + "customPromptPlaceholder": "Enter custom prompt...", + "cut": "Cut", + "cutShortcut": "Ctrl+X", + "copy": "Copy", + "copyShortcut": "Ctrl+C", + "paste": "Paste", + "pasteShortcut": "Ctrl+V", + "pastePlainText": "Paste as Plain Text", + "pastePlainTextShortcut": "Ctrl+Shift+V", + "delete": "Delete", + "deleteShortcut": "Del", + "selectAll": "Select All", + "selectAllShortcut": "Ctrl+A", + "selected": "Selected:", + "aiActions": { + "askAi": "Ask AI", + "rewrite": "Rewrite", + "expand": "Expand", + "summarize": "Summarize", + "translate": "Translate", + "explain": "Explain", + "fixGrammar": "Fix Grammar", + "makeFormal": "Make Formal", + "makeCasual": "Make Casual", + "custom": "Custom" + } + }, + "documentOutline": { + "ariaLabel": "Document outline", + "closeAriaLabel": "Close outline", + "closeTitle": "Close outline", + "title": "Outline", + "noHeadings": "No headings found. Add headings to your document to see them here." + }, + "sidebar": { + "ariaLabel": "Annotations sidebar" + }, + "titleBar": { + "untitled": "Untitled", + "documentNameAriaLabel": "Document name", + "menuBarAriaLabel": "Menu bar" + }, + "errors": { + "loadingDocument": "Loading document...", + "noDocumentLoaded": "No document loaded", + "failedToLoad": "Failed to Load Document", + "unableToParse": "Unable to Parse Document", + "somethingWentWrong": "Something went wrong", + "errorDescription": "An error occurred while rendering this component. Please try again or contact support if the problem persists.", + "errorLabel": "Error:", + "componentStack": "Component Stack:", + "tryAgain": "Try Again", + "showDetails": "Show details", + "hideDetails": "Hide details", + "unsavedChanges": "You have unsaved changes. Are you sure you want to leave?" + }, + "table": { + "insertRowAbove": "Insert row above", + "insertRowBelow": "Insert row below", + "insertColumnLeft": "Insert column left", + "insertColumnRight": "Insert column right", + "deleteRow": "Delete row", + "deleteColumn": "Delete column", + "deleteTable": "Delete table", + "mergeCells": "Merge cells", + "splitCell": "Split cell", + "editingTools": "Table editing tools", + "label": "Table:", + "cellFillColor": "Cell Fill Color", + "borderColor": "Border Color", + "borderWidth": "Border width", + "unknownAction": "Unknown Action", + "borders": { + "all": "All borders", + "outside": "Outside borders", + "inside": "Inside borders", + "none": "No borders", + "remove": "Remove borders", + "top": "Top border", + "bottom": "Bottom border", + "left": "Left border", + "right": "Right border", + "styleAriaLabel": "Border style", + "tooltip": "Borders" + }, + "moreOptions": "More table options", + "styles": { + "title": "Table Styles", + "label": "Styles", + "normalTable": "Normal Table", + "tableGrid": "Table Grid", + "gridTableLight": "Grid Table Light", + "plainTable1": "Plain Table 1", + "plainTable2": "Plain Table 2", + "plainTable3": "Plain Table 3", + "plainTable4": "Plain Table 4", + "gridTable1Light": "Grid Table 1 Light", + "gridTable4Accent1": "Grid Table 4 Accent 1", + "gridTable5Dark": "Grid Table 5 Dark", + "listTable3Accent2": "List Table 3 Accent 2", + "listTable4Accent3": "List Table 4 Accent 3", + "gridTable4Accent5": "Grid Table 4 Accent 5", + "gridTable4Accent6": "Grid Table 4 Accent 6" + } + }, + "tableAdvanced": { + "verticalAlignment": "Vertical alignment", + "top": "Top", + "middle": "Middle", + "bottom": "Bottom", + "cellMargins": "Cell margins", + "textDirection": "Text direction", + "textDirections": { + "horizontal": "Horizontal (LR)", + "verticalRL": "Vertical (top-bottom, RL)", + "verticalLR": "Vertical (bottom-top, LR)" + }, + "toggleNoWrap": "Toggle no-wrap", + "rowHeight": "Row height", + "heightRules": { + "auto": "Auto", + "atLeast": "At least", + "exact": "Exact" + }, + "rule": "Rule", + "height": "Height", + "toggleHeaderRow": "Toggle header row", + "distributeColumns": "Distribute columns evenly", + "autoFit": "Auto-fit to contents", + "tableProperties": "Table properties...", + "tableAlignment": "Table alignment", + "alignTableLeft": "Align table left", + "alignTableCenter": "Align table center", + "alignTableRight": "Align table right", + "tableOptionsMenu": "Table options menu", + "tableOptions": "Table options" + }, + "imageTransform": { + "tooltip": "Transform", + "rotateClockwise": "Rotate clockwise", + "rotateCounterClockwise": "Rotate counter-clockwise", + "flipHorizontal": "Flip horizontal", + "flipVertical": "Flip vertical" + }, + "imageWrap": { + "inline": "Inline with text", + "floatLeft": "Float left (wrap right)", + "floatRight": "Float right (wrap left)", + "topAndBottom": "Top and bottom", + "behindText": "Behind text", + "inFrontOfText": "In front of text", + "tooltipPrefix": "Wrap: {label}" + }, + "responsePreview": { + "loading": "{action}...", + "result": "{action} Result", + "closeEsc": "Close (Esc)", + "editPrompt": "Edit the result before accepting:", + "changes": "Changes:", + "original": "Original:", + "new": "New:", + "cancelEdit": "Cancel Edit" + }, + "commentMarkers": { + "resolvedComment": "Resolved comment", + "comment": "Comment" + }, + "editor": { + "toggleCommentsSidebar": "Toggle comments sidebar", + "showDocumentOutline": "Show document outline", + "editing": "Editing", + "editingDescription": "Edit document directly", + "suggesting": "Suggesting", + "suggestingDescription": "Edits become suggestions", + "viewing": "Viewing", + "viewingDescription": "Read-only, no edits", + "failedToParse": "Failed to parse document", + "linkRemoved": "Link removed", + "linkCopied": "Link copied to clipboard", + "failedToSave": "Failed to save document" + }, + "hyperlinkPopup": { + "displayTextPlaceholder": "Display text", + "urlPlaceholder": "https://example.com", + "copyLink": "Copy link", + "editLink": "Edit link", + "removeLink": "Remove link" + }, + "headerFooter": { + "header": "Header", + "footer": "Footer", + "options": "Options", + "insertPageNumber": "Insert current page number", + "insertTotalPages": "Insert total page count", + "remove": "Remove {label}", + "closeEditing": "Close {label} editing" + }, + "image": { + "placeholder": "Image placeholder", + "placeholderText": "[Image]", + "editableAriaLabel": "Editable image" + }, + "ruler": { + "horizontal": "Horizontal ruler", + "vertical": "Vertical ruler", + "firstLineIndent": "First line indent", + "leftIndent": "Left indent", + "rightIndent": "Right indent", + "topMargin": "Top margin", + "bottomMargin": "Bottom margin" + }, + "print": { + "label": "Print", + "allPages": "All ({totalPages} pages)", + "singlePage": "Page {start}", + "pageRange": "Pages {start}-{end}" + }, + "unsaved": { + "unsaved": "Unsaved", + "saved": "Saved", + "unsavedTitle": "Document has unsaved changes", + "savedTitle": "All changes saved", + "unsavedAriaLabel": "Unsaved changes", + "savedAriaLabel": "All changes saved" + }, + "loading": { + "label": "Loading" + } +} diff --git a/packages/vue/src/components/AIContextMenu.vue b/packages/vue/src/components/AIContextMenu.vue new file mode 100644 index 00000000..2f518b04 --- /dev/null +++ b/packages/vue/src/components/AIContextMenu.vue @@ -0,0 +1,133 @@ + + + + + diff --git a/packages/vue/src/components/AIResponsePreview.vue b/packages/vue/src/components/AIResponsePreview.vue new file mode 100644 index 00000000..f3f0aaa9 --- /dev/null +++ b/packages/vue/src/components/AIResponsePreview.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/packages/vue/src/components/InlineHeaderFooterEditor.vue b/packages/vue/src/components/InlineHeaderFooterEditor.vue new file mode 100644 index 00000000..cb740a57 --- /dev/null +++ b/packages/vue/src/components/InlineHeaderFooterEditor.vue @@ -0,0 +1,164 @@ + + + + + diff --git a/packages/vue/src/components/InsertImageDialog.vue b/packages/vue/src/components/InsertImageDialog.vue new file mode 100644 index 00000000..33e07993 --- /dev/null +++ b/packages/vue/src/components/InsertImageDialog.vue @@ -0,0 +1,173 @@ + + + + + diff --git a/packages/vue/src/components/InsertSymbolDialog.vue b/packages/vue/src/components/InsertSymbolDialog.vue new file mode 100644 index 00000000..991b858c --- /dev/null +++ b/packages/vue/src/components/InsertSymbolDialog.vue @@ -0,0 +1,214 @@ + + + + + diff --git a/packages/vue/src/components/InsertTableDialog.vue b/packages/vue/src/components/InsertTableDialog.vue new file mode 100644 index 00000000..6cb1b3ca --- /dev/null +++ b/packages/vue/src/components/InsertTableDialog.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/packages/vue/src/components/KeyboardShortcutsDialog.vue b/packages/vue/src/components/KeyboardShortcutsDialog.vue new file mode 100644 index 00000000..e45b74a2 --- /dev/null +++ b/packages/vue/src/components/KeyboardShortcutsDialog.vue @@ -0,0 +1,198 @@ + + + + + diff --git a/packages/vue/src/components/MenuBar.vue b/packages/vue/src/components/MenuBar.vue new file mode 100644 index 00000000..f79d5667 --- /dev/null +++ b/packages/vue/src/components/MenuBar.vue @@ -0,0 +1,122 @@ + + + + + diff --git a/packages/vue/src/components/PageSetupDialog.vue b/packages/vue/src/components/PageSetupDialog.vue new file mode 100644 index 00000000..7e49615d --- /dev/null +++ b/packages/vue/src/components/PageSetupDialog.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/packages/vue/src/components/PasteSpecialDialog.vue b/packages/vue/src/components/PasteSpecialDialog.vue new file mode 100644 index 00000000..9fce8966 --- /dev/null +++ b/packages/vue/src/components/PasteSpecialDialog.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/packages/vue/src/components/PrintButton.vue b/packages/vue/src/components/PrintButton.vue new file mode 100644 index 00000000..31e2ff20 --- /dev/null +++ b/packages/vue/src/components/PrintButton.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/packages/vue/src/components/ResponsiveToolbar.vue b/packages/vue/src/components/ResponsiveToolbar.vue new file mode 100644 index 00000000..8d08dd91 --- /dev/null +++ b/packages/vue/src/components/ResponsiveToolbar.vue @@ -0,0 +1,130 @@ + + + + + diff --git a/packages/vue/src/components/TablePropertiesDialog.vue b/packages/vue/src/components/TablePropertiesDialog.vue new file mode 100644 index 00000000..e14b6b2b --- /dev/null +++ b/packages/vue/src/components/TablePropertiesDialog.vue @@ -0,0 +1,95 @@ + + + + + diff --git a/packages/vue/src/components/TableStyleGallery.vue b/packages/vue/src/components/TableStyleGallery.vue new file mode 100644 index 00000000..9a06e4d9 --- /dev/null +++ b/packages/vue/src/components/TableStyleGallery.vue @@ -0,0 +1,137 @@ + + + + + diff --git a/packages/vue/src/components/TableToolbar.vue b/packages/vue/src/components/TableToolbar.vue new file mode 100644 index 00000000..ebbd3a04 --- /dev/null +++ b/packages/vue/src/components/TableToolbar.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/packages/vue/src/components/TextContextMenu.vue b/packages/vue/src/components/TextContextMenu.vue new file mode 100644 index 00000000..fb2d03e3 --- /dev/null +++ b/packages/vue/src/components/TextContextMenu.vue @@ -0,0 +1,177 @@ + + + + + diff --git a/packages/vue/src/components/UnsavedIndicator.vue b/packages/vue/src/components/UnsavedIndicator.vue new file mode 100644 index 00000000..f9fb2d47 --- /dev/null +++ b/packages/vue/src/components/UnsavedIndicator.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/packages/vue/src/components/VerticalRuler.vue b/packages/vue/src/components/VerticalRuler.vue new file mode 100644 index 00000000..36ad080d --- /dev/null +++ b/packages/vue/src/components/VerticalRuler.vue @@ -0,0 +1,211 @@ + + + + + diff --git a/packages/vue/src/components/sidebar/AddCommentCard.vue b/packages/vue/src/components/sidebar/AddCommentCard.vue new file mode 100644 index 00000000..b9ad390a --- /dev/null +++ b/packages/vue/src/components/sidebar/AddCommentCard.vue @@ -0,0 +1,95 @@ +