feat(i18n,a11y,dnd,media): graduate four modules toward Stable (#141–#144) - #157
Merged
Conversation
…142, #143, #144) Collected PR for the next four open stabilization tickets, implemented on one branch. Closes #141 Closes #142 Closes #143 Closes #144 ## #141 — i18n toward Stable: ICU MessageFormat + message extraction - ICU MessageFormat support routed through a locale-aware formatter backed by `Intl.PluralRules`: `plural`, `selectordinal`, `select`, nested arguments, `offset:`, exact `=N` selectors, the `#` token, and apostrophe escaping. Plain `{name}` interpolation and the legacy `singular | plural` pipe form are unchanged (legacy fast path is untouched; ICU is detected automatically). - New authoring helpers `defineMessages()` (identity + extraction anchor) and `formatMessage()` (standalone single-message formatter). - Optional, dependency-free message-extraction tooling at the new `@bquery/bquery/i18n/extract` entry + `bquery-i18n` CLI: scans `defineMessages` catalogs and `t()`/`tc()` calls, merges into JSON catalogs without overwriting translations (`--prune` opt-in). Zero-build runtime path preserved. - Frozen-surface, ICU coverage table (with documented non-coverage), extraction, and lazy-loading docs in the i18n guide. Tests for ICU + extraction + CLI. ## #142 — a11y toward Stable: documented audit scope - Every `AuditFinding` now carries a `wcag` criterion; the full rule catalog is exported as `auditRules` (rule → WCAG → severity → what it cannot detect). - Audit-scope table with known limitations (contrast, focus order, etc.) in the a11y guide; frozen surface reference. Tests for audit scope, focus trapping, live regions, inert/scrollLock, and preference signals. ## #143 — dnd toward Stable: keyboard accessibility statement - Frozen surface + accessibility statement documenting the keyboard model (pick up / move / drop / cancel, `aria-grabbed`) and confirming drag announcements route through the shared a11y live-region announcer. - Tests for keyboard pick/move/drop/cancel, aria-grabbed transitions, and the grid/delay/viewport option surface. ## #144 — media toward Stable: SSR-safe defaults + cleanup (bake-and-verify) - Per-composable SSR fallback + cleanup contract documented; frozen surface. - Tests for SSR-safe defaults, idempotent destroy(), listener detachment (no leaks), and AbortSignal teardown. No new features. ## Shared / build - Externalize `node:*` in the Vite lib build so the CLI entries emit real `import('node:fs/promises')` instead of Vite's browser-external stub — this also fixes the previously-shipped `bquery-view-compile` CLI in dist. - README stability matrix, introduction.md stability paragraphs, CHANGELOG, `src/full.ts` exports, and package.json (`./i18n/extract` export + bin) updated. Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This was referenced Jun 29, 2026
Merged
JosunLP
added a commit
that referenced
this pull request
Jun 29, 2026
…ork (#159) ## Problem Vite's library build bundled `node:*` imports into its **browser-external stub** (an empty default export). That left `await import('node:fs/promises')` in the optional CLI entry resolving to `undefined`, so the published **`bquery-view-compile`** CLI crashed at runtime with `e is not a function` when run against the `dist` build. ## Fix Mark `node:*` as external in `rollupOptions` so those imports are emitted verbatim and resolved by Node at runtime: ```ts rollupOptions: { external: (id) => id.startsWith('node:'), output: { ... }, } ``` Browser entries never import `node:*`, so this is a no-op for them. ## Verification - Rebuilt `dist`; the `vite-browser-external` stub is **gone** from `dist/view-compiler.es.mjs` (0 references, was 1). - `bquery-view-compile --out-dir … file.html` runs end-to-end against the built bundle (`1/1 compiled`). ## Note This is the standalone hotfix for `dev`. The same one-line change is also present in the stable-graduation PR #157 (which introduces the `bquery-i18n` CLI that surfaced the bug); since the change is byte-identical, the branches reconcile cleanly when both land — or the line can be dropped from #157 once this merges. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <[email protected]>
Signed-off-by: Jonas Pfalzgraf <[email protected]>
- a11y-stable: coalesce optional activeElement id to '' so toContain receives a string instead of `string | undefined` (TS2769). - dnd-stable: drop the unsupported `keyboard` option from the useSortable() call. sortable() is pointer-only; keyboard a11y lives on draggable, which the first test already covers (TS2353). The PR's local `tsc --noEmit` used the default tsconfig (excludes tests/); CI runs tsconfig.component-test.json, which includes them and caught this. Co-Authored-By: Claude Opus 4.8 <[email protected]>
… Stable (#145–#148) (#158) Collected PR for the next four open stabilization tickets, implemented on one branch. > **Stacked on #157.** Base is set to the #157 branch so this diff shows only the plugin/devtools/testing/storybook changes. It targets **dev** after #157 lands (GitHub auto-retargets to `dev` when #157 merges). Merge #157 first. Closes #145 Closes #146 Closes #147 Closes #148 ## #145 — plugin toward Stable: frozen extension contract - New additive **`definePlugin()`** authoring helper (identity + install-options inference) — a single, stable entry point for third-party authors. - Hook-bus / DI / install-lifecycle / directive-registration surface frozen; **plugin-author guide** published (lifecycle, hook timing, DI resolution, directive namespacing). - **Install/uninstall symmetry** proven with tests: nothing a plugin registers (directives, filters, actions, DI bindings) leaks after `uninstall()`; re-install is clean. ## #146 — devtools toward Stable: bridge protocol + browser extension - New stable, **versioned bridge protocol**: `connectDevtoolsBridge()` (over `window.postMessage`), the transport-agnostic `createBridgeServer()`, `serializeComponentTree()`, and `BRIDGE_PROTOCOL_VERSION` / `BRIDGE_SOURCE` / `BRIDGE_CAPABILITIES`. Built-in methods `ping` / `getSnapshot` / `getTimeline` / `getComponentTree`; timeline events stream as `event` messages. - Reference **Manifest V3 extension** in [`extension/`](../tree/feat/plugin-devtools-testing-storybook-stable/extension) (component tree, signal/store inspection, live timeline) that connects over the protocol. - `installBrowserBridge()` advertises the protocol version (back-compatible). ## #147 — testing toward Stable: runner-agnostic + shadow-DOM parity - Surface frozen; **runner integration beyond `bun:test`** documented (Vitest / Jest) with `cleanup()` / `autoCleanup()` guidance. - Shadow-DOM-aware `screen` / `within` queries, `userEvent` / `fireEvent`, and a mock are **tested across light + shadow DOM**. `expectAccessible` documented as sharing the a11y audit's rule definitions. ## #148 — storybook toward Stable: pinned `unsafeHtml` contract - Helper surface frozen; the **`unsafeHtml` security contract** is pinned and documented — `storyHtml`/`storySvg` sanitize every interpolation via the security module, and only brand-checked, author-controlled fragments are inserted verbatim. Sanitization, the bypass, brand-spoofing rejection, and each helper's output are covered by tests. ## Shared / build - README stability matrix, `introduction.md` stability paragraphs, CHANGELOG, and `src/full.ts` exports (`definePlugin` + the devtools bridge surface). ## Verification - `bun test` — **2959 pass / 0 fail** (30 new tests across 4 files). - `tsc --noEmit` clean; `check:doc-exports` 100% for plugin/devtools/testing/storybook; `check:full-bundle` passes; eslint clean; `build:lib` emits the devtools bundle. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <[email protected]>
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.
Collected PR for the next four open stabilization tickets, implemented on one branch.
Closes #141
Closes #142
Closes #143
Closes #144
#141 — i18n toward Stable: ICU MessageFormat + message extraction
Intl.PluralRules:plural,selectordinal,select, nested arguments,offset:, exact=Nselectors, the#token, and apostrophe escaping. ICU is detected automatically; plain{name}interpolation and the legacysingular | pluralpipe form keep the untouched fast path.defineMessages()(identity + extraction anchor) andformatMessage()(standalone single-message formatter).@bquery/bquery/i18n/extractentry +bquery-i18nCLI: scansdefineMessagescatalogs andt()/tc()calls, merges into nested JSON catalogs without overwriting translations (--pruneopt-in). Zero-build runtime path preserved.number/dateskeletons, rich-text), extraction, and lazy-loading. Tests cover ICU + extraction + CLI.#142 — a11y toward Stable: documented audit scope
AuditFindingnow carries awcagcriterion; the full rule catalog is exported asauditRules(rule → WCAG → severity → what it cannot detect).inert/scrollLock, and preference signals.#143 — dnd toward Stable: keyboard accessibility statement
aria-grabbed) and confirmation that drag announcements route through the shared a11y live-region announcer (no second channel).aria-grabbedtransitions, and thegrid/delay/viewportoption surface.#144 — media toward Stable: SSR-safe defaults + cleanup (bake-and-verify)
destroy(), listener detachment (no leaks), andAbortSignalteardown.Shared / build
node:*in the Vite lib build so the CLI entries emit realimport('node:fs/promises')instead of Vite's browser-external stub — this also fixes the previously-shippedbquery-view-compileCLI indist.introduction.mdstability paragraphs, CHANGELOG,src/full.tsexports, andpackage.json(./i18n/extractexport +bquery-i18nbin) updated.Verification
bun test— 2929 pass / 0 fail (47 new tests across 5 files).tsc --noEmitclean;check:doc-exports100% for i18n/a11y/dnd/media;check:full-bundleandcheck:ai-guidancepass.bquery-i18n extract "src/**/*.ts" --out en.jsonsmoke-tested end-to-end against the builtdist.🤖 Generated with Claude Code