feat: sync upstream eigenpal/docx-js-editor main branch#9
Merged
yash-giantanalytics merged 32 commits intomainfrom Apr 5, 2026
Merged
feat: sync upstream eigenpal/docx-js-editor main branch#9yash-giantanalytics merged 32 commits intomainfrom
yash-giantanalytics merged 32 commits intomainfrom
Conversation
Add EditorBridge that connects AI agent tools to a live DocxEditor instance. The agent can read the document, add comments, suggest tracked changes, and scroll — all executing on the client without reloading the document. Key changes: - DocxEditorRef: 6 new methods (addComment, replyToComment, resolveComment, proposeReplacement, scrollToIndex, getComments) - EditorBridge (packages/agent-use/bridge.ts): wraps DocxEditorRef for agent use - Tool definitions (packages/agent-use/tools/): 6 tools with OpenAI-compatible schemas (read_document, read_comments, read_changes, add_comment, suggest_replacement, scroll_to) - useAgentChat hook: wires tools to editor ref - agent-chat-demo: Next.js example with chat panel beside the editor Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace getOpenAITools/getAnthropicTools with single getToolSchemas()
(OpenAI format is the de facto standard)
- Simplify useAgentChat hook: returns { executeToolCall, toolSchemas }
(removed stale bridge, getSystemContext, provider-specific helpers)
- Demo uses useAgentChat hook instead of manual bridge creation
- Fix multi-turn history: persistent openaiHistoryRef preserves tool
call context across turns
- Fix bridge.getComments(): reads from live editor state, not stale
Document model
- Fix replyToComment: validates parent comment exists
- Add 29 tests for tools + bridge (bun:test)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract getCommentText() helper, replacing inline type-cast chain - Fix O(n^2) reply matching: pre-group with Map (same pattern as discovery.ts) - Guard redundant editorRef.getComments() call when doc comments exist - Memoize toolSchemas as module-level constant (static, never changes) - Cache bridge creation via useMemo in useAgentChat hook - Move msgId counter from module-level to useRef (scoped to component) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When `value` is undefined on first render, `stripExtension` returns undefined, causing the input to start as uncontrolled. Adding a fallback to empty string guarantees the input is controlled from the first render, preventing the React warning. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…enpal#228) * fix: set correct default font-size on header/footer inline editor The PM header editor's <p> elements used browser-default 16px font-size, but text spans were rendered at the document's default (e.g. 11pt=14.67px). This caused line-height: 1.15 to calculate based on 16px instead of 14.67px, creating a visual spacing mismatch between the inline editor and the layout painter view. Now resolves the default font size from document styles and sets it on the editor container. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: override inline spacing on header/footer editor paragraphs The PM editor paragraphs got margin-bottom and line-height from style-resolved spaceAfter/lineSpacing (e.g., Normal style), but the layout painter doesn't apply style-resolved spacing to headers/footers. This caused the editing view to show much more spacing than the layout view. Use !important on margin and line-height in .hf-editor-pm to force tight spacing matching the layout painter. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: exclude spaceBefore/spaceAfter from header/footer height measurement After editing, paragraph formatting can have style-resolved spaceAfter (e.g., from Normal style) inlined via the PM→document round-trip. The layout painter renders header/footer paragraphs without these margins, but the measurement was including them — making the header area much taller than the visible content. Now only lineSpacing is converted for measurement, matching the tight rendering. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…al#232) * feat: show tracked change replacements as single "Replaced X with Y" card When a deletion and insertion are adjacent with the same author and timestamp (a Word replace operation), merge them into a single sidebar card showing "Replaced <old> with <new>" instead of separate "Deleted" and "Added" entries. Also extracts a reusable truncateText() helper for sidebar text truncation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: preserve comment range markers for tracked change replies on save When replying to a tracked change, the reply comment was saved to comments.xml but its range markers (commentRangeStart/End) were missing from document.xml. This happened because the selective save system only patches paragraphs tracked by ParagraphChangeTracker, but TC replies only update React state (no PM transaction), so the affected paragraph was never patched. Fix: detect TC replies (parentId not in commentIdSet) alongside regular comment replies when deciding whether to force full repack. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: wrap both del+ins in comment range for TC reply markers When a tracked change reply comment is anchored to a deletion that has an adjacent insertion (replacement pair), wrap both elements inside the comment range markers. Previously, only the deletion was wrapped, which placed commentRangeEnd + commentReference between del and ins, breaking the adjacency needed for replacement grouping in other editors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: thread comments on tracked changes as TC replies Two fixes for comment-on-tracked-change interop: 1. toProseDoc: apply comment marks to text inside tracked change wrappers (insertion/deletion/moveFrom/moveTo). Previously, commentRangeStart/End were tracked but comment marks were only applied to regular runs, so comments overlapping tracked changes lost their mark in ProseMirror. 2. DocxEditor: detect comment marks overlapping tracked change marks and auto-set parentId to thread them as replies under the tracked change card in the sidebar. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…pal#233) * feat: add i18n support with locale prop and useTranslation hook (eigenpal#222) Extract all ~485 user-facing strings into i18n/en.json and replace hardcoded strings across 48 components with type-safe t() calls. - Add LocaleProvider + useTranslation() hook (zero dependencies) - Add `locale` prop on DocxEditor for partial overrides with deep merge - Auto-derive LocaleStrings type from en.json (no manual interface) - null values in locale files = "not yet translated" (falls back to English) - Add scripts/validate-i18n.mjs for CI validation of locale file sync - Add docs/i18n.md contribution guide - Export getMissingTranslations() utility for translation coverage checks Closes eigenpal#222 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: add i18n CLI (new/status), update docs, remove AGENTS_README - Add `bun run i18n:new <lang>` to scaffold locale files with null keys - Add `bun run i18n:status` to show translation coverage per locale - Update docs/i18n.md with CLI reference and improved contribution flow - Add i18n as prominent feature in README, link to contribution guide - Remove AGENTS_README.md and its link from README - Update CLAUDE.md with i18n CLI commands and "always use t()" rule Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: i18n review fixes — type safety, pluralization, memoization - Fix DeepPartial to allow null values (community locale files) - Remove all `as any` / `as Parameters<typeof t>[0]` casts by typing labelKey/nameKey fields as TranslationKey (14 files) - Add tPlural() with CLDR plural rules (Slavic, Arabic, etc.) - Add lang prop on DocxEditor for language-aware plural selection - Auto-memoize locale prop via deep equality (no re-renders for inline objects) - Fix validate-i18n.mjs: BCP 47 regex, empty parent cleanup, JSON error handling - Add Limitations section to docs/i18n.md - Convert replyCount/replyCountPlural to plural object format Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use Intl.PluralRules instead of hand-rolled plural rules Replace our incomplete hardcoded Slavic/Arabic plural rules with the browser's built-in Intl.PluralRules API — the same standard used by react-i18next and next-intl. Supports all languages correctly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: use ICU MessageFormat for plurals instead of nested objects Simpler approach: plurals are inline in the string value using ICU syntax ("{count, plural, one {# reply} other {# replies}}"). Same pattern as next-intl. Keys stay identical across all languages — translators just write their language's plural forms in the same string. - Remove tPlural() — t() now handles ICU plural syntax natively - Revert en.json replies to flat key with ICU format - Revert validator to simple key matching (no plural object detection) - Uses Intl.PluralRules for category selection Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add ICU selectordinal and exact match (=N) support Extend formatMessage to support the same ICU subset as next-intl: - Exact matches: =0, =1, =2 (checked before CLDR categories) - Cardinal plural: {count, plural, one {# item} other {# items}} - Ordinal plural: {year, selectordinal, one {#st} two {#nd} other {#th}} Add comprehensive Interpolation & Pluralization docs with examples. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: i18n remaining ~200 strings, delete dead components - Extract strings from ColorPicker, AdvancedColorPicker, FontSizePicker, TableOptionsDropdown subcomponents, TableMoreDropdown, TableToolbar, TableBorderColor/CellFill/BorderWidth pickers, HorizontalRuler, VerticalRuler, PrintPreview, LoadingIndicator, UnsavedIndicator, and dialog error messages (Hyperlink, InsertImage, PasteSpecial) - Delete dead code: ShapeGallery.tsx, TableQuickActions.tsx (unused) - Remove their en.json keys (shapes.*, tableQuickActions.*) - Total: 610 translatable keys in en.json Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: remove partial locale override examples The primary i18n path is importing a full locale file. Partial inline overrides still work (deep merge) but don't need to be advertised. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: merge lang into locale via _lang key — single prop API Remove the separate `lang` prop from DocxEditor. Language tag is now embedded in the locale file as `"_lang": "de"`, set automatically by `bun run i18n:new`. One prop to rule them all: <DocxEditor locale={de} /> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: simplify i18n — remove YAGNI code - Remove getMissingTranslations() (zero callers, CLI does the same) - Remove selectordinal support (unused in the editor) - Remove localeEqual deep-compare memoization (consumers pass stable imports) - LocaleContext.tsx: 200 → 137 lines Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: replace locale + lang props with single i18n prop API is now: <DocxEditor i18n={{ translations: de }} /> <DocxEditor i18n={{ translations: pl, locale: 'pl' }} /> - locale field is optional (defaults to "en"), only needed for languages with complex plural rules (Slavic, Arabic) - translations field is the JSON object (deep-merged with English) - Remove _lang from en.json — no magic metadata in translation files - Export I18nConfig type Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: explain why locale field matters for plural rules Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: type locale field with autocomplete for ~80 common BCP 47 tags Locale type provides IDE autocomplete for common language codes while still accepting any valid BCP 47 string. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: start Locale type with just 'en', grow with new translations Instead of listing ~80 language codes upfront, start with only 'en' and expand the union as community translations are added. Docs updated with step to add locale tag when contributing a new translation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: simplify i18n API to single prop — <DocxEditor i18n={de} /> Locale JSON files now include _lang (set by i18n:new) for plural rules. No wrapper object needed — just pass the imported JSON directly. - Remove I18nConfig, Locale types (not needed) - i18n prop is now just PartialLocaleStrings (the JSON object) - _lang read from the locale object for Intl.PluralRules - Update all docs to show simple <DocxEditor i18n={de} /> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: rename i18n prop type to Translations PartialLocaleStrings is a terrible consumer-facing name. Add a clean Translations type alias. DocxEditor prop is now `i18n?: Translations`. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove selectordinal docs (not implemented), drop redundant cast Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: eliminate type casts with isRecord type predicate Reduce casts from 8 to 3 (all at typed↔record boundaries): - Add isRecord() type predicate — eliminates all internal casts - deepMerge and getNestedValue are now cast-free internally - Remove deepMerge generic (unnecessary, operates on AnyRecord) - Zero `as any`, zero `as unknown`, zero double casts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: treat _lang as metadata in validator, add _lang to pl.json - Validator now skips _lang in key comparison (won't flag as missing/extra) - Add _lang: "pl" to pl.json - i18n:fix won't overwrite _lang with null - i18n:status doesn't count _lang as untranslated Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: remove pl.json — let community contribute real translations Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix unicode double-click word selection * Handle combining marks in word selection
The PR accidentally dropped ' (U+2019) from WORD_CHAR_REGEX, which would break word selection for text with smart/typographic quotes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…sidebar card Word assigns different revision IDs to the deletion and insertion parts of a replacement tracked change. The sidebar card used only the deletion's ID, so clicking the insertion part couldn't find the matching card. Fix: store the insertion's revisionId in TrackedChangeEntry, build an alias map, and use it in the click handler and active highlight CSS. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
eigenpal#236) Two issues fixed: 1. Tracked change marks' toDOM used text-decoration CSS (underline for insertions, line-through for deletions). The underline and strike mark extensions have parseDOM rules matching those same CSS values, so ProseMirror's DOM parsing added real formatting marks on top of the tracked change visual styling — causing double underline on insertions and double strikethrough on deletions. Fix: remove text-decoration from tracked change toDOM styles. The hidden ProseMirror is off-screen; the layout-painter handles all visible tracked change rendering independently. 2. When typing inside existing tracked changes, two problems occurred: a) insertText() inherited deletion marks from cursor position, causing nested tracked changes with conflicting visual styles. b) removeMark(insertionType) + addMark() fragmented the insertion mark span, creating a separate tracked change for each keystroke. Fix: strip inherited deletion marks only. For insertion marks, let addMark() handle it — if the cursor is inside an existing insertion by the same author, the inherited mark stays intact and addMark() with matching attrs is a no-op that preserves the continuous span. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add pl.json and de.json locale files with all 610 keys translated. Terminology verified against official Microsoft Word PL/DE UI via Microsoft Language Portal and support.microsoft.com documentation. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nges (eigenpal#244) * chore: bump to 0.0.33 * refactor: use cursor-based mark detection for sidebar expansion Replace the DOM click handler in UnifiedSidebar with ProseMirror cursor-driven detection in DocxEditor. When the cursor lands on a comment, insertion, or deletion mark, the matching sidebar card expands automatically. This also works with keyboard navigation, not just clicks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: reliable mark detection and eliminate sidebar state loop Two fixes: 1. Mark detection: $from.marks() misses inclusive:false marks at cursor boundaries. Now checks nodeAfter/nodeBefore marks first for reliable comment and tracked change detection. 2. Sidebar crash: Remove bidirectional state sync (activeItemId → internal state → onExpandedItemChange → parent) that caused max update depth. Make sidebar fully controlled — parent owns expansion state, sidebar just reads activeItemId prop. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: collect marks from all sources instead of OR chain Empty mark arrays are truthy in JS, so the OR chain (storedMarks || nodeAfter?.marks || nodeBefore?.marks) short-circuited on the first source with any node, even if that node had no comment/tracked-change marks. Now spreads all sources into a single array so we always find the mark. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: auto-open sidebar when clicking comment or tracked change The sidebar items only exist in allSidebarItems when showCommentsSidebar is true, but commentSidebarItems always has them. Search commentSidebarItems for mark matching, and auto-set showCommentsSidebar=true when a match is found so clicking on a comment or tracked change opens the sidebar. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: unify insertion/deletion handling and stabilize toggleExpand 1. Merge near-duplicate insertion and deletion mark handling into a single block with shared prefix-search and alias-resolution logic. 2. Stabilize toggleExpand callback with a ref so it doesn't recreate on every expandedItem change, avoiding unnecessary card re-renders on each cursor move. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The editor re-processed the entire document on every keystroke, causing 200-500ms input lag on 20+ page documents. This adds an incremental pipeline that only re-converts, re-measures, and re-paginates from the edited paragraph forward, with early exit when page breaks stabilize. ## Changes **Incremental block conversion (Phase 1)** - New `IncrementalBlockCache` tracks previous doc state and uses ProseMirror's structural sharing (node identity comparison) to detect which top-level nodes changed — O(1) per node - Extracted `convertTopLevelNode()` from `toFlowBlocks()` for per-node incremental conversion - List counter snapshots at each node boundary for correct numbering after partial re-conversion - Forward propagation of list counter changes until stabilization **Incremental measurement** - `measureBlocksIncremental()` reuses cached measures for clean blocks before the dirty range, re-measures only from dirtyFrom forward - Full floating zone pre-scan still runs (fast, zones can shift) **Layout engine resume + early exit (Phase 2)** - Paginator `snapshot()`/`createPaginatorFromSnapshot()` API for capturing and restoring layout state at page boundaries - `layoutDocument()` accepts `resumeFrom` option to skip blocks before the dirty range and start from a saved paginator snapshot - Early exit: after 2 consecutive blocks past the dirty range converge with the previous layout state, remaining pages are spliced from the previous run — avoids re-paginating the entire tail - `applyContextualSpacingRange()` for partial spacing application **CSS containment (Phase 3)** - `content-visibility: auto` + `contain-intrinsic-size` on page shells so the browser skips layout/paint for off-screen pages **Pipeline integration** - PagedEditor detects doc changes via PM node identity comparison (works for both transaction-driven and direct relayout calls) - Deferred cache mutation: `updateBlocks()` returns results without mutating the cache; `applyIncrementalResult()` is called only after successful paint to prevent split-state on stale aborts - Per-step performance diagnostics via `console.debug` ## Measured Results (287 blocks, 24 pages) | Step | Full pipeline | Incremental | Speedup | |------|-------------|-------------|---------| | Block conversion | 1.3ms | 0.0ms | ∞ | | Measurement | 13.7ms | 0.5ms | **27x** | | Layout | 0.5ms | 0.3ms (resumed) | 1.7x | | Paint | 12.7ms | 12.7ms | 1x | | **Total** | **~28ms** | **~13ms** | **2x** | Steps 1-3 combined: **15ms → 0.8ms (19x faster)** On larger documents (500+ blocks), the savings scale linearly since unchanged blocks are completely skipped. ## Test Coverage - 36 new unit tests (incrementalBlockCache, paginator-snapshot, layout-resume) — all passing - 368/368 total unit tests passing - Demo-docx E2E suite passing - Typecheck clean across all 4 packages Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Internal planning document, not needed in the upstream repo. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
createView() already initializes EditorState from the document prop. The document-change effect running on the same mount cycle would create an identical state and call updateState(), which is redundant and can destroy content injected by external plugins (e.g. ySyncPlugin) between the two effects. Set isInitializedRef in createView so the document-change effect skips its first run when the document identity hasn't changed.
When collaborative=true, the mount-time useEffect that calls loadDocument/loadDocumentBuffer is skipped. This allows external ProseMirror plugins (e.g. ySyncPlugin from y-prosemirror) to manage the document content lifecycle without the editor overwriting their content on mount. A document prop (e.g. createEmptyDocument()) is still required to initialize the ProseMirror schema and editor shell.
ySyncPlugin dispatches transactions during EditorView construction (in its view() callback via _forceRerender). The arrow function ignored ProseMirror's .call(this, tr) binding, and viewRef.current was still null at that point, causing the transaction to be silently dropped. This left ProseMirror with empty content even though Y.Doc had real content. Switch to a regular function so ProseMirror's this binding provides the EditorView, and eagerly set viewRef.current on first dispatch.
Merge upstream changes including: - i18n support with locale prop, useTranslation hook, and Polish/German translations - Tracked changes fixes: spurious formatting, consecutive deletion grouping, replacement tracked changes as single sidebar card - Cursor-based sidebar expansion for comments and tracked changes - Unicode double-click word selection and curly apostrophe fix - Header/footer editor line spacing alignment with layout view - Scroll-based page indicator (Google Docs style) - DocumentName controlled input fix All @eigenpal package references updated to @giantanalyticsai scope.
…egration Adds `collaborative` boolean prop to DocxEditor that skips mount-time document loading when external plugins (e.g. y-prosemirror) manage content. Prevents content corruption where mount effects would destroy Yjs-populated state and sync the damage back to Y.Doc. Also includes viewRef safety fix for transactions dispatched during EditorView construction (before viewRef.current is assigned).
…ll splitting Fixes right-click table row/column actions that were non-functional. Adds merge cells and split cell to the context menu with a dialog-backed split cell that accepts explicit row/column counts. Fixes column insertion regression when adding a row then column from mid-table.
Adds incremental layout that reuses cached measurements for unchanged blocks instead of re-measuring the entire document on every keystroke. Uses ProseMirror structural sharing to detect dirty ranges, resumes pagination from cached snapshots, and applies CSS containment for browser-level optimization. ~30x faster measurement step on 20+ page documents (13.7ms down to 0.5ms).
…tools Adds EditorBridge that connects AI agent tools to the live DocxEditor instance. Agents can read content, add comments, reply to comments, propose tracked-change replacements, and scroll to positions — all client-side. Includes useAgentChat hook, OpenAI-compatible tool schemas, and a Next.js agent-chat-demo example app.
Lock file was stale after merging upstream PRs eigenpal#201, eigenpal#243, eigenpal#246, eigenpal#247. Regenerated to include new dependencies (e.g. @happy-dom/global-registrator).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
eigenpal/docx-js-editormain branch changes into our forkLocaleProvider,useTranslationhook, and Polish/German translations (610 translatable keys)@eigenpalpackage references updated to@giantanalyticsaiscopeTest plan
bun run typecheckpasses for all packages@eigenpalreferences remain in runtime code (.ts,.tsx,.json)