Skip to content

feat: add vue version of docx editor#245

Open
Cruiser13 wants to merge 4 commits intoeigenpal:mainfrom
pringuin:main
Open

feat: add vue version of docx editor#245
Cruiser13 wants to merge 4 commits intoeigenpal:mainfrom
pringuin:main

Conversation

@Cruiser13
Copy link
Copy Markdown

I took the liberty to use #88 and fixed some issues.
this is the enhanced version where the complete toolbar should be working fine in vue.
I noticed no bugs (fingers crossed) and would be happy to see this merged.

Let me know what you think.

Cruiser13 and others added 3 commits March 31, 2026 21:03
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 <noreply@anthropic.com>
…ation

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 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 2, 2026

@Cruiser13 is attempting to deploy a commit to the EigenPal Team on Vercel.

A member of the Team first needs to authorize it.

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docx-editor Ready Ready Preview, Comment Apr 3, 2026 8:46am

Request Review

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Cruiser13
Copy link
Copy Markdown
Author

@jedrazb what do you think?

@jedrazb
Copy link
Copy Markdown
Contributor

jedrazb commented May 4, 2026

Hey @Cruiser13 thank you for contribution, supporting native vue is still on our radar for 1.0.0 release. I will take your commits and adapt this PR

jedrazb added a commit that referenced this pull request May 4, 2026
- Drop \`private: true\` from \`packages/vue/package.json\` so it ships at 1.0.0
  with the rest. Add a minimal \`tsup.config.ts\` so the existing stub
  (\`src/index.ts\`) builds; #245 will replace the stub with the real
  implementation when it merges into \`1.0.0-release\`.
- Extend the changeset \`fixed\` group to all five packages
  (\`docx-editor-react\`, \`docx-editor-core\`, \`docx-editor-agents\`,
  \`docx-editor-vue\`, \`docx-js-editor\`) and clear \`ignore\`.
- List every package explicitly in the 1.0.0 changeset entry so the
  changelog spells out the bump per-package.
- Add \`docx-editor-vue\` to the root build pipeline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jedrazb added a commit that referenced this pull request May 4, 2026
- packages/vue/package.json: prefix description with [STUB] so the npm
  page warns Vue users that renderAsync is not yet implemented. Without
  this, a 1.0.0 version number is the loudest possible "production-ready"
  signal and the package can't back it up until #245 lands.
- README.md: flag vue as "stub at 1.0.0, not yet functional" in the
  packages table; add the prosemirror peer-deps install line under
  Quick Start for strict installers (pnpm / npm 6 / auto-install-peers
  off).
- packages/react-legacy-shim/README.md: replace vague "foreseeable
  future" wording with a concrete commitment ("ships in lockstep for the
  entire 1.x line; plan to migrate before 2.0.0").
- .changeset/1-0-0-package-restructure.md: spell out that vue is a
  runtime-throwing stub at 1.0.0 — the per-package CHANGELOG that lands
  on npm now tells the truth.
- CLAUDE.md: document the post-publish `npm deprecate
  @eigenpal/docx-js-editor` step so first-wave 1.0.0 installs get a
  migration banner.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jedrazb added a commit that referenced this pull request May 4, 2026
* feat!: rename packages and prepare 1.0.0 restructure

Renames the npm packages to a unified `docx-editor-*` naming and ships
the framework-agnostic core publicly:

- `@eigenpal/docx-js-editor`  → `@eigenpal/docx-editor-react`
- `@eigenpal/docx-core`       → `@eigenpal/docx-editor-core` (now public)
- `@eigenpal/docx-editor-vue` stays private until #245 lands its build
- `@eigenpal/docx-editor-agents` unchanged

Adds `packages/react-legacy-shim/` as a thin re-export of
`docx-editor-react` published under the old `docx-js-editor` name so
existing installs keep working without code changes. The shim is in
the changesets fixed group with `docx-editor-react` and
`docx-editor-agents` so versions stay in lockstep.

Note: changesets cannot auto-bump from `0.x` to `1.0.0`; the maintainer
needs to edit each `package.json` `version` to `1.0.0` inside the
auto-opened release PR before merging.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: address review findings on package rename

- Restore historical CHANGELOG entries for `packages/react/` and
  `packages/agent-use/` — past releases really did publish under the
  old `@eigenpal/docx-js-editor` / `@eigenpal/docx-core` names; rewriting
  the history would mislead anyone debugging an old install.
- Fix vite alias regex in `examples/{vite,vue,collaboration}/vite.config.ts`
  — bulk sed missed the regex bodies (`/^@eigenpal\/docx-core\/(.+)/`).
- Fix shim's `./styles.css` and `./i18n/*.json` exports. The previous
  paths into `./node_modules/@eigenpal/docx-editor-react/...` would not
  resolve post-publish (npm hoists the dep, and `node_modules` doesn't
  ship in the tarball). Now copies the assets into the shim's own
  `dist/styles.css` and `i18n/` at build time via `scripts/copy-assets.mjs`.
- Simplify shim's tsup `external` to a single regex.
- Drop the manual-version-bump caveat from the changeset entry — `major`
  on `0.4.1` produces `1.0.0` automatically per semver.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: unify all packages into one fixed release group

- Drop \`private: true\` from \`packages/vue/package.json\` so it ships at 1.0.0
  with the rest. Add a minimal \`tsup.config.ts\` so the existing stub
  (\`src/index.ts\`) builds; #245 will replace the stub with the real
  implementation when it merges into \`1.0.0-release\`.
- Extend the changeset \`fixed\` group to all five packages
  (\`docx-editor-react\`, \`docx-editor-core\`, \`docx-editor-agents\`,
  \`docx-editor-vue\`, \`docx-js-editor\`) and clear \`ignore\`.
- List every package explicitly in the 1.0.0 changeset entry so the
  changelog spells out the bump per-package.
- Add \`docx-editor-vue\` to the root build pipeline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(shim): preserve CSS side-effect, drop stale i18n files, parallelize build

- `packages/react-legacy-shim/package.json`: change `sideEffects: false` to
  `["*.css"]`. The shim re-exports `./styles.css`, but webpack/esbuild
  tree-shake unused side-effects when the package declares none. Match
  the upstream `@eigenpal/docx-editor-react` declaration so consumers
  doing `import '@eigenpal/docx-js-editor/styles.css'` actually get the
  styles emitted.
- `packages/react-legacy-shim/scripts/copy-assets.mjs`: rmSync the
  destination i18n dir before cpSync. Without this, `cpSync` with
  `recursive: true` merges into the existing dir, so a locale removed
  upstream still ships from a stale prior build.
- root `package.json` build pipeline: split the middle group so only
  react gates downstream. Now `core → react → (agents ∥ vue ∥ shim)` —
  agents and vue don't depend on react, but the shim's copy-assets does,
  so the shim still waits. Cuts the critical path by one tsup run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: surface vue-stub status and migration signals (DX review fixes)

- packages/vue/package.json: prefix description with [STUB] so the npm
  page warns Vue users that renderAsync is not yet implemented. Without
  this, a 1.0.0 version number is the loudest possible "production-ready"
  signal and the package can't back it up until #245 lands.
- README.md: flag vue as "stub at 1.0.0, not yet functional" in the
  packages table; add the prosemirror peer-deps install line under
  Quick Start for strict installers (pnpm / npm 6 / auto-install-peers
  off).
- packages/react-legacy-shim/README.md: replace vague "foreseeable
  future" wording with a concrete commitment ("ships in lockstep for the
  entire 1.x line; plan to migrate before 2.0.0").
- .changeset/1-0-0-package-restructure.md: spell out that vue is a
  runtime-throwing stub at 1.0.0 — the per-package CHANGELOG that lands
  on npm now tells the truth.
- CLAUDE.md: document the post-publish `npm deprecate
  @eigenpal/docx-js-editor` step so first-wave 1.0.0 installs get a
  migration banner.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jedrazb added a commit that referenced this pull request May 4, 2026
…X polish

Round 3 of reviews surfaced one blocker, two bugs, and several DX
improvements. Applying the in-scope ones.

BLOCKER
- examples/vite/src/App.tsx:233 — fetch('/docx-editor-demo.docx') is an
  absolute path, which under the parity build at /react/ falls through
  to the catchall rewrite and returns the landing HTML. The .catch
  branch then silently created an empty document. Switched to
  \`fetch(\${import.meta.env.BASE_URL}docx-editor-demo.docx)\` so vite
  rewrites the path correctly for any base.

BUGS
- examples/vue/src/App.vue:6 — pre-rename package name in the visible
  copy. Updated to @eigenpal/docx-editor-core.
- examples/vite/vercel.json — stale, never consulted at the repo root,
  but a footgun if a Vercel project is ever pointed at examples/vite as
  Root Directory. Deleted.

DX polish (parity landing)
- Added a banner above the iframes explaining Vue is in active
  development (#245) so first-time visitors don't think the package is
  half-broken when the Vue pane shows a placeholder.
- Added GitHub link + npm install snippet to the header so the landing
  page actually exits to docs / install / repo.
- Mobile layout: capped each pane at 60vh instead of stacking 200vh
  total — both labels visible at once, scroll inside iframe instead of
  the page.
- Dropped redundant <span> wrappers in <h2> and the loading="eager"
  default on <iframe>.

Code quality
- Normalized USE_PUBLISHED_PACKAGES check from === '1' to === 'true' in
  both vite configs to match the existing ENABLE_FRAMEWORK_SWITCHER
  convention. Also updated the build:parity:* scripts.
- Dropped redundant fields from vercel.json: installCommand (auto from
  bun.lock) and framework: null (omit-key equivalent in fresh config).

Contributor DX
- Added bun run dev:parity script: builds + serves the parity output on
  port 4173 in one command. Without this, contributors had to memorize
  the build + serve incantation.
- examples/parity/README.md: added a "Why this exists" section
  explaining the dev/parity build divergence and what the deployment is
  proving (real installed bytes, not source-aliased dev mode).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jedrazb added a commit that referenced this pull request May 4, 2026
…'s toolbar

You were right — having both /react /vue routes AND a ?framework= URL
param on / was redundant. Cleanup:

- Delete examples/parity/index.html (the landing iframe wrapper).
- vercel.json: / now 307-redirects to /react/. Bookmark whichever
  adapter you want.
- examples/shared/AdapterSwitcher.tsx — small React pill, two anchor
  tags pointing at /react/ and /vue/. Drop-in alongside the existing
  ExampleSwitcher in examples/vite/src/App.tsx.
- examples/vue/src/App.vue — same pill as plain HTML/CSS so the stub
  has it too. When PR #245 lands, the real Vue editor inherits the
  pattern.

Each adapter now owns the full viewport. Switcher is just navigation —
no iframe, no param, canonical URLs, bookmarkable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jedrazb added a commit that referenced this pull request May 4, 2026
…eview (#338)

* docs: document 1.0.0-release as the active integration branch

Adds a top-of-file section in CLAUDE.md so future contributors (and
agents) know that 1.0.0-related work targets the long-living
1.0.0-release branch, not main. Lists what has merged so far (#337),
what is still pending (#245), and the post-train cleanup (npm deprecate,
reset baseBranch back to main).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(examples): add /react /vue parity preview for the 1.0.0-release Vercel deploy

Adds a single deployment that mounts both example apps at distinct routes
so community members can verify React and Vue parity side by side.

  /         landing page with two iframes (React left, Vue right)
  /react/   examples/vite — @eigenpal/docx-editor-react
  /vue/     examples/vue  — @eigenpal/docx-editor-vue

Both apps build with USE_PUBLISHED_PACKAGES=1, which makes their vite
configs skip the workspace source aliases. Vite then resolves the
@eigenpal/* package names through node_modules → the workspace's
built dist/ — the same module resolution a community member gets after
\`npm install\`. So the deployment is the real installed experience,
not the dev-mode source-aliased one.

Plumbing:
- examples/{vite,vue}/vite.config.ts: gate the source-alias array on
  USE_PUBLISHED_PACKAGES, accept VITE_BASE_PATH for subroute mounting.
- examples/vite/package.json: switch dep on docx-editor-react from a
  bogus "^0.0.7" to workspace:*, add docx-editor-core (it's imported
  directly from the demo's App.tsx).
- root package.json: include examples/vite and examples/vue in the
  bun workspaces array so deps actually symlink.
- root package.json scripts: build:parity orchestrates root build →
  react example → vue example → assemble into examples/parity/dist/.
- examples/parity/index.html: landing page with side-by-side iframes,
  responsive single-column at <900px width.
- examples/parity/README.md: how to set up the new Vercel project
  (root dir, build command, output dir, branch alias).

The existing root vercel.json (latest.docx-editor.dev off main) is
untouched — the 1.0.0-release deployment is a separate Vercel project
that the maintainer configures via dashboard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(vercel): make parity build the default for all deployments

Updates root vercel.json so any Vercel project pointed at this repo
gets the /react /vue parity preview without dashboard overrides:
- buildCommand: bun run build:parity
- outputDirectory: examples/parity/dist
- rewrites: SPA fallbacks for /react/* and /vue/* plus the landing
  page fallback at /.
- framework: null (build command handles it).

This applies to:
- The existing latest.docx-editor.dev project (deploys off main) — on
  its next deploy after this lands, / will show the side-by-side
  comparison and /react/ /vue/ give the standalone experiences.
- The new 1.0.0-release Vercel project — no manual settings needed,
  just point at the repo and assign the custom domain.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(parity): resolve review findings — fetch base path, stale refs, DX polish

Round 3 of reviews surfaced one blocker, two bugs, and several DX
improvements. Applying the in-scope ones.

BLOCKER
- examples/vite/src/App.tsx:233 — fetch('/docx-editor-demo.docx') is an
  absolute path, which under the parity build at /react/ falls through
  to the catchall rewrite and returns the landing HTML. The .catch
  branch then silently created an empty document. Switched to
  \`fetch(\${import.meta.env.BASE_URL}docx-editor-demo.docx)\` so vite
  rewrites the path correctly for any base.

BUGS
- examples/vue/src/App.vue:6 — pre-rename package name in the visible
  copy. Updated to @eigenpal/docx-editor-core.
- examples/vite/vercel.json — stale, never consulted at the repo root,
  but a footgun if a Vercel project is ever pointed at examples/vite as
  Root Directory. Deleted.

DX polish (parity landing)
- Added a banner above the iframes explaining Vue is in active
  development (#245) so first-time visitors don't think the package is
  half-broken when the Vue pane shows a placeholder.
- Added GitHub link + npm install snippet to the header so the landing
  page actually exits to docs / install / repo.
- Mobile layout: capped each pane at 60vh instead of stacking 200vh
  total — both labels visible at once, scroll inside iframe instead of
  the page.
- Dropped redundant <span> wrappers in <h2> and the loading="eager"
  default on <iframe>.

Code quality
- Normalized USE_PUBLISHED_PACKAGES check from === '1' to === 'true' in
  both vite configs to match the existing ENABLE_FRAMEWORK_SWITCHER
  convention. Also updated the build:parity:* scripts.
- Dropped redundant fields from vercel.json: installCommand (auto from
  bun.lock) and framework: null (omit-key equivalent in fresh config).

Contributor DX
- Added bun run dev:parity script: builds + serves the parity output on
  port 4173 in one command. Without this, contributors had to memorize
  the build + serve incantation.
- examples/parity/README.md: added a "Why this exists" section
  explaining the dev/parity build divergence and what the deployment is
  proving (real installed bytes, not source-aliased dev mode).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(parity): switch from side-by-side to single-column with framework toggle

Side-by-side iframes felt cramped, especially on the React side where
the editor toolbar already eats horizontal space. Replaced with a
single full-width iframe and a React/Vue toggle in the header.

  Header: [docx-editor] [React | Vue] npm install ... GitHub ↗ Fullscreen ↗
  Body:   <iframe> takes the rest of the viewport

Switcher behavior:
- Default: React. ?framework=vue in the URL switches to Vue at load.
- Clicking either tab swaps the iframe src and updates the install snippet,
  the fullscreen link target, and the URL (replaceState — no scroll
  jump).
- The Vue stub banner is gated to only show when the Vue tab is active —
  no warning noise for visitors who never click Vue.

The /react/ and /vue/ routes still serve the standalone fullscreen
experiences; only the landing page changed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(parity): drop landing wrapper, switcher lives in each editor's toolbar

You were right — having both /react /vue routes AND a ?framework= URL
param on / was redundant. Cleanup:

- Delete examples/parity/index.html (the landing iframe wrapper).
- vercel.json: / now 307-redirects to /react/. Bookmark whichever
  adapter you want.
- examples/shared/AdapterSwitcher.tsx — small React pill, two anchor
  tags pointing at /react/ and /vue/. Drop-in alongside the existing
  ExampleSwitcher in examples/vite/src/App.tsx.
- examples/vue/src/App.vue — same pill as plain HTML/CSS so the stub
  has it too. When PR #245 lands, the real Vue editor inherits the
  pattern.

Each adapter now owns the full viewport. Switcher is just navigation —
no iframe, no param, canonical URLs, bookmarkable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(vercel): pin install to lockfile so cached node_modules can't drift

The 1.0.0-release deploy failed because Vercel's cached .bun/ store
held both prosemirror-transform@1.11.0 (from a pre-PR lockfile) and
1.12.0 (current). DTS build for @eigenpal/docx-editor-core saw two
incompatible Mapping types and crashed with TS2322.

Adding installCommand: 'bun install --frozen-lockfile' forces Vercel
to match the committed lockfile exactly. New version drift = build
fails fast at install rather than producing a confusing type error
mid-build. (Maintainer needs to clear Vercel build cache once for
this PR's deploy.)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(deps): tighten prosemirror-transform peer/dev to ^1.12.0

The 1.0.0-release Vercel build kept failing because a stale 1.11.0
slipped into Vercel's .bun/ store next to 1.12.0, and tsup's dts gen
pulled types from the older one — TS2322 on TableExtension.ts:2330
because Mapping has private '_maps' that diverges between minor
versions of prosemirror-transform.

Root cause: peer/dev constraint was ^1.10.2, satisfied by both 1.11.0
and 1.12.0. The root overrides force 1.12.0 in the lockfile but Vercel's
resolver evidently picks something different for transitive deps.

Bumping the constraint to ^1.12.0 in packages/core and packages/react
removes the ambiguity at the package level — every resolver, on any
platform, must land on >=1.12.0. The override stays for belt-and-braces.

Also confirmed the lockfile only carries 1.12.0 after re-resolve.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jedrazb added a commit that referenced this pull request May 4, 2026
…robust-implementation (#345)

* 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 <noreply@anthropic.com>

* 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 <noreply@anthropic.com>

* fix: image handling - resize and replace did not work

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(vue): make PR #245 cherry-picks build cleanly on 1.0.0-release

Three sets of fixes on top of the cherry-picked Cruiser13 / Lennart
Fries commits so the parity build stays green on the hardening branch:

1) Adapter API drift since #245 was authored. The contributor wrote
   useAutoSave.ts and useTableSelection.ts against an older
   AutoSaveManager / TableSelectionManager / Subscribable API:
   - AutoSaveManagerOptions field is `interval` not `intervalMs`
   - subscribe() takes `() => void`, snapshot is read separately via
     getSnapshot() (matches React's useSyncExternalStore pattern)
   - lastSaveTime is `Date | null` not `number | null`
   - getRecoveryData() returns SavedDocumentData not string
   - save() is async and takes no args
   Rewrote both composables to match the current core API while
   keeping the same Vue-facing return shape. Drop unused `computed`
   import in i18n/index.ts (causes pre-commit lint trip).

2) Vue package builder: tsup → vite. PR #245 ships .vue SFCs which
   esbuild (under tsup) can't compile. Switched packages/vue/ to
   `vite build --lib` with @vitejs/plugin-vue and vite-plugin-dts.
   External: vue, prosemirror-*, and @eigenpal/docx-editor-core
   (consumers bring those). Output: index.js (es) + index.cjs +
   declaration files. Added prosemirror-model to vue's devDeps so
   the type imports resolve.

3) Core exports map expansion. PR #245 reaches into ~25 deep core
   subpaths that weren't in the curated exports map after PR #332.
   Added the missing paths to packages/core/package.json `exports`
   AND packages/core/tsup.config.ts `entry` so consumers (and the
   Vue package's build) actually resolve them. New subpaths under:
   - utils/ (headingCollector, textSelection)
   - docx/ (parser, rezip)
   - layout-bridge/ (clickToPositionDom, measuring, toFlowBlocks)
   - layout-engine/ (types)
   - layout-painter/ (renderPage)
   - managers/ (AutoSaveManager, TableSelectionManager, types)
   - prosemirror/ (commands/{formatting,pageBreak,paragraph},
     conversion/fromProseDoc, plugins/selectionTracker, schema, styles)

   These are framework-adapter integration points the Vue adapter
   genuinely needs. Audit (post-1.0) should evaluate whether some
   should fold back into the curated top-level subpaths from #332.

Verified: bun run typecheck clean across all 5 packages,
bun run build clean, bun run build:parity produces working
examples/parity/dist with both /react/ and /vue/ routes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Lennart Fries <mail@lennartsauter.de>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
jedrazb added a commit that referenced this pull request May 4, 2026
* feat(parity): export + i18n key parity gates (§8b)

Implements §8b.3-8b.8 of the vue-editor-robust-implementation OpenSpec
change. Two new scripts gate React/Vue adapter drift in the dev loop
and CI, fast (<1s combined).

scripts/check-export-parity.mjs
- Tier 1, STRICT: package.json `exports` subpaths must match between
  React and Vue, with documented opt-outs in
  notes/intentional-export-divergence.md (`./react`, `./ui`,
  `./styles.css` are permanent react-only; `./core`, `./headless`,
  `./core-plugins`, `./mcp`, `./i18n/*.json` are temporary while Vue
  catches up).
- Tier 2, INFORMATIONAL: AST-walked named exports from src/index.ts
  on both adapters. Logs the drift count (518 react-only, 29 vue-only
  today) so the gap stays visible. Task §13b flips this to strict on
  un-stub. Uses the TS compiler API for accurate parsing of barrel
  re-exports, named exports, type exports, and aliases.
- Pulls the divergence opt-out from a markdown notes file so reasons
  live next to the path; regex matches only the FIRST backtick on a
  list-item line so prose secondary backticks don't widen the opt-out.

scripts/check-i18n-parity.mjs
- Walks every locale present in BOTH packages/react/i18n/ and
  packages/vue/i18n/, diffs key paths via the shared getLeafPaths
  helper.
- Vue-only locales fail the gate (Vue can't ship a translation React
  doesn't have without breaking the source-of-truth contract).
- React-only locales are informational; Vue catches up via community
  translation issues #341-344, #302, #303.

scripts/lib/i18n-keys.mjs (new)
- Hoisted `getLeafPaths` helper used by both scripts. The existing
  `validate-i18n.mjs` had its own copy; refactored to import from the
  shared lib. METADATA_KEYS expanded from `['_lang']` to "any key
  starting with `_`" to cover future metadata fields without script
  edits.

scripts/lib/named-exports.mjs (new)
- TS-compiler-API-based AST walker. Captures top-level `export const`,
  `export function`, `export class`, `export type`, `export interface`,
  `export enum`, `export default`, `export { X, Y as Z }`, and
  `export * from './foo'` (recursively, with cycle protection).

Pre-commit hook gains a `bun run check:parity` step before
lint-staged. Combined gate runs in <100ms — no perceptible commit
slowdown.

packages/vue/i18n/en.json: synced with React's source-of-truth so the
English key set matches (Vue PR #245 had drift; bulk-copied from
packages/react/i18n/en.json — 633 keys total, including agentPanel.*
which Vue doesn't yet use but ships forward-looking).

intentional-export-divergence.md: 8 React-only subpaths documented
with reason and lifecycle (permanent vs hardening-temporary).

Tasks 8b.3, 8b.4, 8b.5, 8b.6, 8b.7, 8b.8 — done.
New task 13.6a — flip STRICT_NAMED_EXPORTS at un-stub.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(parity): shared parity-report lib + spec align to src/index.ts

Round-2 review feedback:

HIGH (simplifier): both parity scripts repeated the same set-diff +
formatted-report pattern. Extracted into scripts/lib/parity-report.mjs
exporting diffSets() and formatDiff(). Both scripts now compose: build
two Sets, call diffSets, hand the result to formatDiff with the
appropriate strict/informational flag and labels. Truncation policy
(at 25) becomes a parameter — divergence between gates is one number
per call site, not three implementations.

NIT (reviewer): spec said "diff dist/index.d.ts named exports" but
implementation walks src/index.ts via the TS compiler API. The src
walk is more accurate (resolves through TS path aliases, no build
required, follows barrel re-exports recursively). Updated the spec
requirement wording to match implementation reality + add a sentence
explaining the choice. Also documented the two-tier (strict subpath /
informational named-export) gate split there.

Verified end-to-end:
- bun run check:parity — clean (subpath strict pass, named
  informational with the same 518/29 count, i18n en pass)
- bun run typecheck — clean across all 5 packages
- Smoke: planted `export const TestExport123 = 1` in
  packages/react/src/index.ts → count became 519 react-only;
  reverted cleanly. The drift detection works exactly as before
  the refactor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jedrazb added a commit that referenced this pull request May 4, 2026
§6.3 + §12.6 — packages/vue/README.md gains a "Scope — what's in v1,
what's deferred" section listing the three explicitly-omitted v1
features:
- third-party Vue plugins (cross-adapter plugin contract is post-v1)
- real-time collaboration (Yjs binding ships in 1.x for both adapters)
- SSR / Nuxt module (editor measures DOM at mount; <ClientOnly> wrap
  remains the recommended Nuxt pattern)

Each row includes the reason and the tracking pointer (spec §6.3 or
parity matrix omitted-v1 row). README also gains a pointer to
notes/reactivity.md for contributors touching reactive state.

Stale-task sweep — §1.1–1.5 (PR #245 review/merge cycle) and §2.1–2.3
(branch + notes/ + CLAUDE.md row) are marked done with explanatory
notes. The 1.0.0 train absorbed PR #245's surface inline through
PRs #348#363 instead of merging the long-running fork; per-file
review captured in notes/audit.md.

Docs-only — no changeset.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants