Skip to content

docs: flatten the migration guide and its MCP tool (nuxt/ui@a3c3ff3, nuxt/ui@60db60e) - #608

Merged
IgorShevchik merged 1 commit into
mainfrom
sync/nuxt-a3c3ff34
Sep 18, 2026
Merged

IgorShevchik merged 1 commit into
mainfrom
sync/nuxt-a3c3ff34

Conversation

@IgorShevchik

Copy link
Copy Markdown
Collaborator

Ports nuxt/ui@a3c3ff34 and nuxt/ui@60db60e0 — flattening the migration guide, and the MCP tool that reads it.

Journals: a3c3ff34…md · 60db60e0…md

One PR for two commits — they are contiguous upstream and inseparable in effect: after the flattening the tool's LIKE %/migration/v2 matches nothing, so it would answer 404 for the only guide this library has. §6 step 4b permits a contiguous run.

The change

3.migration/1.v2.md3.migration.md; the directory and its .navigation.yml
go. Upstream's reasoning holds for a fork whose major is 2 — the version lives in
the package, not in the URL.

Ported, not copied — five places against upstream's four

None of the URL lines could be taken verbatim. This site uses trailing
slashes, so every route is /docs/getting-started/migration/. Copying upstream's
targets would have 301'd to a path this site does not serve.

The redirect had to reverse, not be edited. Ours read
'/docs/getting-started/migration/': { redirect: '…/migration/v2/' }, and after
flattening /migration/ is the page — that rule would have shadowed the page
with a redirect to a route that no longer exists. It now points the other way,
with a 301 for the /raw/**.md twin beside it.

The fifth place has no counterpart in the upstream diff, and is the one a
faithful-looking port would have missed: docs/nuxt.config.ts:12 holds a
fork-only pages array that line 401 maps into /raw/<page>.md prerender routes.
Leaving /migration/v2/ there would have kept generating the twin for a page that
no longer exists and stopped generating the one that does.

.navigation.yml held only shadow: true (upstream's also had an icon) —
asserted before deleting, so nothing else went with it. The page keeps its own
navigation.title: 'Migration', so the sidebar entry is unchanged.

In the MCP tool, two fork-only lines are deliberately kept: path and url
are built from baseUrl + withTrailingSlash, which upstream does not do. The
asymmetry that leaves is correct rather than sloppy — the query matches
/docs/getting-started/migration without a slash, because that is the path
nuxt/content stores, while the response adds one, because that is what the site
serves.

Verified against the built site, not the diff

docs:full:generate with deploy.yml's env — zero prerender errors:

/docs/getting-started/migration/index.html 192 KB, <title>Migration to v2 - Bitrix24 UI</title>
/raw/docs/getting-started/migration.md present, correct frontmatter and canonical_url
/docs/getting-started/migration/v2/ not prerendered — it is a redirect now
sidebar link href="/b24ui/docs/getting-started/migration/"

The one thing worth checking rather than assuming: /migration/v2/ used to be
a real prerendered page and is now a redirect, and this site has no server. So does
the old URL still work?

Yes, and by the mechanism already in use: /docs/getting-started/theme/,
/installation/, /integrations/ and /ai/ are all prerender: false redirects
and all equally un-prerendered today. GitHub Pages serves 404.html, which loads
/b24ui/_nuxt/CB7xbCUL.js — the same bundle a grep for migration/v2 finds the
rule in. This PR uses the established path, it does not introduce a new one.

Gate

dev:prepare · lint · typecheck · build · test:coverage (355 files, 8079
passed) · test:module · docs:full:generate — green.

Cursor advances ee37a5b4a3c3ff3460db60e0; the ee37a5b4 entry is
reconciled with #607 / ecd9e83a.

Remaining queue: three component fixes — aab2d10d (SelectMenu),
8e4546e3 (InputDate/InputTime), b3d4342d (InputMenu).

🤖 Generated with Claude Code

https://claude.ai/code/session_01JS8ypVfQSFzYVZzkTHhURb


Generated by Claude Code

…uxt/ui@60db60e)

Two contiguous upstream commits in one PR, per §6 step 4b: after the flattening
the tool's `LIKE %/migration/v2` matches nothing, so it would answer 404 for the
only guide this library has.

`3.migration/1.v2.md` becomes `3.migration.md`; the directory and its
`.navigation.yml` go. Upstream's reasoning holds for a fork whose major is 2 —
the version lives in the package, not in the URL.

Five places here against upstream's four, and none of the URL lines could be
taken verbatim.

This site uses trailing slashes, so every route is `/docs/getting-started/migration/`;
copying upstream's targets would have 301'd to a path this site does not serve.
The redirect had to reverse rather than be edited — ours pointed `/migration/` at
`/migration/v2/`, and after flattening `/migration/` *is* the page, so that rule
would have shadowed it with a redirect to a route that no longer exists. It now
points the other way, with a 301 for the `/raw/**.md` twin beside it.

The fifth place has no counterpart in the upstream diff and is the one a
faithful-looking port would have missed: `docs/nuxt.config.ts:12` holds a
fork-only `pages` array that line 401 maps into `/raw/<page>.md` prerender routes.
Leaving `/migration/v2/` there would have kept generating the twin for a page that
no longer exists and stopped generating the one that does.

`.navigation.yml` held only `shadow: true` (upstream's also had an `icon`),
asserted before deleting so nothing else went with it; it marks a directory whose
index defers to a child and has no meaning without one. The page keeps its own
`navigation.title: 'Migration'`, so the sidebar entry is unchanged.

In the MCP tool, two fork-only lines are deliberately kept: `path` and `url` are
built from `baseUrl` + `withTrailingSlash`, which upstream does not do. The
asymmetry that leaves is correct rather than sloppy — the query matches
`/docs/getting-started/migration` without a slash, because that is the path
nuxt/content stores, while the response adds one, because that is what the site
serves.

Also reconciles the `ee37a5b4` entry with #607 / ecd9e83.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JS8ypVfQSFzYVZzkTHhURb
@IgorShevchik
IgorShevchik merged commit 0fe8ece into main Sep 18, 2026
2 checks passed
@IgorShevchik
IgorShevchik deleted the sync/nuxt-a3c3ff34 branch September 18, 2026 10:11
IgorShevchik added a commit that referenced this pull request Sep 18, 2026
…nt fixes (nuxt/ui@aab2d10, nuxt/ui@8e4546e, nuxt/ui@b3d4342) (#609)

Three contiguous upstream commits in one PR, per §6 step 4b. Different
components, non-overlapping tests, so a failure still names the one that broke.

SelectMenu — reka's `ComboboxTrigger` hard-codes `aria-label="Show popup"`, which
beats every other naming mechanism, so a screen reader announced it instead of the
`B24FormField` label. Measurably present: 53 occurrences in each of the two
snapshot files. Fixed with `'aria-label': undefined` placed BEFORE the spreads, so
a caller-supplied label still wins — it clears a default rather than blocking the
prop, which is what upstream's second test pins. 106 snapshots updated, and every
pair was compared rather than accepted: 106 of 106 differ only by the removed
attribute, 0 differ by anything else, and the string is now absent from both files.

InputDate/InputTime — a date field is several focusable segments, and `@blur` /
`@focus` fire on each, so moving from day to month emitted blur+focus and a form
validating on blur ran mid-entry. Now `@focusout`/`@focusin`, which bubble, with a
guard ignoring movement inside the field. `test/utils/form.ts` registers
`B24InputDate` and `B24InputTime` so `renderForm` can mount them. Each half is
pinned by a different test: dropping the guard fails the "between segments" pair,
reverting the listeners fails "focus and blur events" and "validate on blur works".

InputMenu — in `multiple` mode `TagsInputInput` adds the search term as a tag on
Enter, but `TagsInputRoot` is driven by the combobox, so the tag never reaches
`modelValue` and renders a chip that is not selected.

That last one needed more than a faithful port. Upstream's two tests both pin real
behaviour, but removing the `isComposing || !searchTerm` guard left all 166 tests
green — upstream's included. A line nothing checks is a line a later cleanup
deletes with a green suite, so the `!searchTerm` half is now pinned by a test that
is red without the guard and green with it: with nothing typed there is no tag to
add, and preventing the key would also swallow the implicit form submission an
empty field allows.

`event.isComposing` is left uncovered, and the failed attempt is recorded rather
than papered over. A probe building `new KeyboardEvent('keydown', { isComposing:
true })` reads the flag back as true, but the event is reported prevented anyway —
`defaultPrevented` there is influenced by other handlers on the same key, so the
probe cannot attribute the outcome to this guard, and a test asserting on it would
pass for a reason unrelated to the line it claims to cover. What the flag is for:
during IME composition Enter confirms the candidate character, and swallowing it
would break text entry for Chinese, Japanese and Korean users.

Also reconciles the `a3c3ff34` and `60db60e0` entries with #608 / 0fe8ece.


Claude-Session: https://claude.ai/code/session_01JS8ypVfQSFzYVZzkTHhURb

Co-authored-by: Shevchik Igor <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