Repository navigation
Interactivity API Router: Add reactive navigation lifecycle and initiator API - #83280
Conversation
…eractivity privateApis seam Adds the two utilities `@wordpress/interactivity-router` needs for the navigation lifecycle: `afterNextFrame` (the directive runtime's frame scheduler) and `getScope` (its scope probe), both wired through the existing private-API bundle rather than the public surface. Adds a source-level seam test covering both the producer literal in interactivity/src/index.ts and the router's destructure, plus unit tests pinning afterNextFrame's macrotask deferral.
… token, start batch, finally, frame-scheduled end
Adds `state.navigating`/`state.initiator` and the `initiator` navigate()
option to `@wordpress/interactivity-router`. Every client-side navigation
that proceeds now claims a monotonic token, publishes an undebounced
{navigating: true, initiator} pair atomically at initiation, and — via a
single guarded `finally` — schedules exactly one end write on the
directive runtime's `afterNextFrame` scheduler, re-checking the token
inside its own callback so a superseded navigation's stale scheduled end
writes nothing. `resolveInitiator()` normalizes the `initiator` option's
three arms (string verbatim, null suppresses attribution, invalid values
warn and fall back to null); scope-based derivation for the omitted arm
is deferred to a later task. Neither key is declared in the store literal,
so the router's lazy module load never re-runs an already-bound watcher.
Sixteen acceptance rows are covered across four Jest files sharing a new
`__fixtures__/interactivity-shim.ts` harness (a `jest.mock` factory
assembling the real interactivity source modules, since the package's own
index.ts cannot be imported under Jest). Warning-count rows live in their
own files because `warn()`'s dedupe set is module-level.
…ope, with a three-clause region-id parse mirror Implements the `declared === undefined` arm of `resolveInitiator()`: the initiator is now derived from the nearest router region (self-inclusive) enclosing the element whose directive invoked the action, read via `getScope()`. Adds `parseRegionId()`, a deliberate three-clause mirror of the directive runtime's own region-id parse — it must not reuse or modify the router's existing `parseRegionAttribute()`, which disagrees with directive-side registration for `::`-namespaced and JSON-scalar ids, and region semantics are frozen. A source-level test guards that duplication by pinning `parseRegionAttribute()`'s text against a literal. No branch throws: a scope-less call, a non-element ref, or an element outside any region all degrade to `null`, with no `isConnected` check since the rule is uniform over any tree.
…cope on the router's own writes Adds a module-level writeFrameScope marker, saved-and-restored around exactly two sites -- the start batch and the existing commit batch -- and compared by scope identity as the first clause of resolveInitiator()'s derive branch. This stops a scope-less watch()/effect() reacting to one of navigate()'s own writes from inheriting the previous navigation's region id, while a withScope-wrapped callback carrying a scope of its own (e.g. a directive-driven consumer in a different region) still resolves correctly. Deliberately no marker at the scheduled end write or the popstate release: both run in detached macrotasks with an empty scope stack and an already- restored marker, so a data-wp-watch consumer there derives its own region rather than being refused -- the property AC25(b)'s region-scoped focus pattern depends on. Seven rows cover: all three lifecycle-write trigger points refusing a scope-less reactive navigation; a withScope effect carrying a different region's scope surviving the guard (the row that separates scope-identity from a rejected boolean in-write flag); a declared initiator still winning ahead of the guard; save-and-restore over set-and-clear under a nested navigation; a data-wp-watch on the end transition as a characterisation; a marker wrongly left unrestored at the end write breaking the next navigation from the same element; and a source-level drift guard on the commit batch's statements.
…first, conditional clear, guarded start/end, catch, bounded release Splits today's short-circuited `pages.has( … ) && ( await pages.get( … ) )` so the uncached decision runs before any effect-running write -- a throwing consumer effect can no longer suppress the reload. Claims the lifecycle token and arms a detached lifecycle-release timer in the handler's synchronous frame, ahead of that decision, so an abandoned claim (a parked await, a declined reload) still discharges its debt at the 10 s bound. Inside the try: a conditional supersession-moment initiator clear, the existing await, a cached-falsy reload on a normal return, the token-guarded start pair, the existing render batch (untouched), and a scheduled, re-checked guarded end. A `catch` -- not a `finally`, since navigate()'s designed non-writing exit is a suspension while popstate's are normal returns -- schedules the guarded idle restoration and rethrows immediately. Twelve rows cover: a full lifecycle cycle through a real hydrated data-wp-watch; no stale identity surviving from a prior navigation (AC18); the uncached path running no consumer code before its reload, both from idle and while superseding a navigation in flight (the row that pins the uncached-first ordering); a cached-falsy entry producing no start and no end; the conditional clear notifying nobody from idle, caught only through a raw effect(); a cached traversal superseding a still-pending navigation staying in flight throughout, then closing its own cycle; an exceptional exit restoring the lifecycle and still rethrowing the consumer's own error, driven through a captured listener rather than a dispatched event so the rejection is handleable; the release firing when a claim never resumes, and staying guarded against a second navigation left in flight at the first claim's bound; a cache entry settling after the release bound producing a second, well-ordered cycle rather than a suppressed one; and the release-bound-observability row proving the release never pre-empts a pending directive flush.
…avigation Implements Task 6 of the BILLOW-142 build plan: the shared fixture block (`test/router-navigation-lifecycle`) the rest of the e2e plan depends on, and Flows 1-12 (region-mode lifecycle, end timing, settlement, failure) in `test/e2e/specs/interactivity/router-navigation-lifecycle.spec.ts`. Two fixture traps found while building this, now documented as comments at their exact site so a future writer copying this fixture doesn't lose a debugging pass to them: - The region element must carry `data-wp-interactive` on itself, not just on an ancestor. The directive runtime's hydration resolves the namespace from any ancestor, so omitting it looks fine through first load; but `interactivity-router`'s own `regionsSelector` (`packages/interactivity-router/src/index.ts:38`) requires the region-bearing element itself to carry it, so without it `preparePage()` never registers the region under `page.regions` for any page, and every navigation silently wipes the region's content. - `populateServerData()` merges with `override: false` (`packages/interactivity/src/proxies/state.ts:378-389`), so a `data-wp-text` binding on a server-seeded key keeps showing the *first* page's value forever unless a watcher re-syncs it from `getServerState()` on every navigation, the pattern `router-regions/view.js`'s `updateCounterFromServer` already demonstrates for context. Residual R1 (the build plan's open verification: whether a held main-frame document request leaves the outgoing document alive and assertable) is resolved here, and the finding is stronger than the plan anticipated: - Neither holding a main-frame request open nor aborting it (the plan's own named fallback) keeps the outgoing document's execution context alive. Chromium commits to replacing the document the moment a top-level navigation is initiated, independent of whether the underlying request ever resolves, succeeds, fails, or is aborted -- confirmed with a standalone script outside the test file/harness (real page, `page.route(url, r => r.abort())`, a real `window.location.assign()` from within the page, context confirmed dead by a follow-up `page.evaluate`). - The plan's cited precedent for the abort fallback (`router-navigate.spec.ts:174`) aborts a resource `fetch()`, not a real top-level navigation, and lets the actual reload through unintercepted -- a different case, which is why the fallback's confidence didn't hold up under test. - The replacement instrument: `view.js` persists the counted lifecycle log to same-origin `localStorage` on `pagehide`/`beforeunload`, both of which were confirmed (same standalone script) to fire reliably on the outgoing document even when its own navigation is aborted. The spec reads it back after the natural, unintercepted reload lands via `readBeforeUnloadLog()`. This is a **deviation from the approved plan** (which named `route.abort()` as the fallback), made because that fallback does not work in this environment; flagged here for the build reviewer to adjudicate. - The new instrument was not trusted on green alone: each of the five flows resting on it (Flow 9 Part B, 10, 11, 12, and Part A's route-hit half) was driven red in its own isolated edit-rebuild-run-revert cycle against that flow's own named wrong implementation -- deleting the popstate handler's `pages.has` check (Flow 9 Part B, also the task's own required verification), moving the start batch ahead of the `clientNavigationDisabled` entry check (Flow 10), and making `forcePageReload` resolve instead of park forever so the parked generator's `finally` actually runs (Flow 11 and 12, which share the mechanism). All five went red exactly as predicted; Flow 9 Part A stayed green on its own, correctly, since the plan's own analysis says Part A alone discriminates nothing from idle. `packages/interactivity-router/` and `packages/interactivity/` are confirmed byte-identical to HEAD after all three cycles. Guardrails: js-lint and php-lint clean; js-unit (interactivity-router + interactivity) 118/118 passed, confirming no probe residue; the new spec (13 tests) and the four existing router suites (46 tests total) pass, with the pre-existing `router-navigate.spec.ts` flake documented in `.pipelines/billow-142-router-navigation-api/base/3-build/e2e-environment-note.md` not reproducing in this run.
…ation Implements Task 7 of the BILLOW-142 build plan: automates Flows 13-19 (per-region origin, cross-region supersession, same-region overlap, declared/suppressed identity, scope-less navigation, nested regions) in `test/e2e/specs/interactivity/router-navigation-lifecycle.spec.ts`, and extends the shared fixture's `render.php` with the nested-region markup Flow 19 needs. Two-region posts (rows 8-10) and nested posts (rows 11-12) are appended to Task 6's inventory, in the topological order the build plan specifies: region B's `navigate` link renders `other`, not `next`, per Task 6's second-region rule, so Flow 14's cross-region supersession has two distinct hrefs for the router's `navigatingTo` bail to separate. The nested branch adds an `inner-region` inside an `outer-region`, both individually carrying `data-wp-interactive` per the fixture's own documented trap. Flow 14 and Flow 15 were driven red against their named wrong implementations before being accepted, restoring `packages/interactivity- router/` to byte-identical-to-HEAD after each cycle (verified with `git diff --stat`): - Flow 14: temporarily removed the token guard around the `finally`'s `afterNextFrame` end write, making it unconditional. Confirmed red on the `lifecycle navigating` mid-window assertion. - Flow 15: temporarily added an unguarded `state.initiator = null` write to the same `finally`, modelling "the per-region indication cleared at every end" the plan names as the discriminating shape. Confirmed red on region A's origin class. Driving Flow 14 red surfaced a real instrumentation gap, fixed before either flow was accepted: the `released` signal I first added to the shared `holdRoute` helper (resolving once Playwright's `route.continue()` call returns) is not a reliable "the browser has resumed" checkpoint -- it fires well before the page's own fetch-then-parse pipeline lets the generator past its `yield`, so the prescribed "release, await, flush two frames" sequence passed on the broken implementation until a full extra second was added. Replacing it with `page.waitForResponse()`, the accurate browser-side signal, catches the wrong implementation reliably with no extra wait, so `holdRoute` reverts to its original Task 6 shape (`hit`/ `release` only) and both flows use `page.waitForResponse()` instead. Guardrails: js-lint and php-lint clean; js-unit (interactivity-router + interactivity) 118/118 passed both before and after the red-drive cycles, confirming no probe residue; the new Flows 13-19 (7 tests) and all five existing router suites (53 tests total) pass. One `router-navigate.spec.ts` test failed once on an unrelated `socket hang up` in REST teardown (`activateTheme`, an infra-level connection blip in a spec this task never touches) and passed cleanly on immediate re-run and on a full re-run of the whole guardrail set, so it is not attributed to this change.
Automates Flow 20: a post with two independent, non-inheriting
`core/query` blocks (`enhancedPagination: true`, `queryId` 0 and 1) plus
the shared fixture's observer block in `observerOnly` mode outside both
queries. Paginating the second Query's own "next page" link reports
`query-1` as the readable initiator both while the navigation is in
flight and at the moment it ends, and never `query-0`. Page markup is
built directly with `requestUtils.createPost`, since `core/query` is not
part of the interactive-blocks test plugin.
No file in `packages/block-library` is touched (`git diff --quiet --
packages/block-library` exits 0) -- Query's region attribute
(`data-wp-router-region="query-<queryId>"`) is written by its own
existing render callback, and its own `view.js` already calls
`actions.navigate` with no `initiator` option. This is the design's
named canary that "block-library is untouched" holds: per-instance Query
attribution is structural, not declared.
Red-driven before being accepted: temporarily replaced the per-instance
`element.closest(...)` derivation in `resolveInitiator()`
(packages/interactivity-router/src/index.ts) with the named wrong
implementation -- `document.querySelector('[data-wp-router-region]')`,
returning the first region in document order -- rebuilt, and re-ran the
flow. It failed as predicted: expected "query-1", received "query-0".
Reverted the patch (`git diff` on packages/interactivity-router/ and
packages/interactivity/ confirmed empty), rebuilt, and re-ran js-unit
and the flow, both green again.
Full guardrail e2e scope (all five in-scope router specs, 54 tests) run
clean: 54 passed, 0 failed, including router-navigate.spec.ts's
"should update the HTML only for the latest navigation", which is
documented in .pipelines/billow-142-router-navigation-api/base/3-build/e2e-environment-note.md
as a pre-existing, environment-timing-sensitive flake unrelated to this
change (A/B-exonerated against the fork base) that may or may not
reproduce on a given run; it did not reproduce this run.
Automates Flows 21-23 (build plan Task 9): a plain link no block handles reads
as having no initiator wherever it sits (inside or outside a router region),
a click handled by a block's own scoped action is identified exactly as in
region mode, and a scoped control outside every block region derives
core/body. Adds a new fixture block, test/router-navigation-full-page,
following the router-navigation-lifecycle fixture's conventions, and its
two published pages (fp-1, fp-2), where every link and control on page 1
targets page 2 so the three flows differ only in what was clicked.
The experiment (gutenberg-full-page-client-side-navigation) is enabled and
reset unconditionally in the new describe block's beforeAll/afterAll, since
this is the first e2e coverage of it in the repo and Playwright runs this
project single-worker.
All three flows were driven red against their named wrong implementation
and reverted before commit, confirmed by an empty git diff on
packages/interactivity-router/src and packages/interactivity/src and a
clean js-unit run:
- Flow 21 (both links): a temporary containment-based (closest()) derivation
in full-page.ts's document click listener, which reads core/body for the
outside link and full-page-a for the inside link instead of absent for
both.
- Flow 23: a temporary special-case in resolveInitiator mapping the
core/body region to null.
- Flow 22: a temporary combination of two fixture/router edits reproducing
the full-page listener's own frame reaching the derivation -- omitting
the fixture action's e.preventDefault() so the document listener also
processes the click, plus that listener passing an explicit
{ initiator: 'core/body' } -- read core/body instead of full-page-a.
Neither edit alone discriminated; the combination does, and is the
faithful reproduction of the flow's own stated wrong implementation.
Full e2e gate (router-navigation-lifecycle.spec.ts plus the four existing
router suites) passes 58/58, confirming no experiment leak into the
existing suites.
…fficiency Automates Flows 24-30 of BILLOW-142's build plan: initial state and hydration before the first navigation, directive bindings tracking the lifecycle mid-flight and after the end (both `hidden` polarities), degradation on a page where the router module never loads, Core's WP 6.9 loading bar cohabiting with the new keys, and the three sufficiency demonstrations (per-block spinner, region-scoped focus, a consumer-side 400 ms debounced bar) built from only the two public keys and existing primitives. Extends the shared fixture: a loading-bar replica bound to the public `core/router` store's deprecated `state.navigation` getter, a debounced-bar element plus a bare `watch()` in view.js, and a per-region spinner plus a third (never-run-counted) edge-triggered focus watcher rendered inside each region.
Expands `### Subscribing to page changes` in the Client-Side Navigation guide with ten `####` subsections covering the two new reactive keys on `core/router` and the new `navigate()` option, behaviour first. The existing heading, its anchor and its `state.url` material are untouched. - The two keys and their `undefined`-until-first-navigation reading, the consume-by-truthiness rule (as a house-style callout), why the keys are undeclared, and the no-attribute-at-all rendering of a binding to an `undefined` value. - Transitions: the ungated, undebounced, options-independent, same-URL start written as an atomic pair; the end published after the commit, on a later frame, with an unbounded delay stated as one-sided. Why "on a later frame" is what makes both transitions observable through a coalescing `data-wp-watch`. Both invalid idioms. Retention of `initiator` through the end and its level-triggered consequence. - Coverage as two lists, plus the mid-flight fallback that never ends. - Supersession: continuous in-flight reading, no gap, no extra end, and the per-region consequences under cross-region and same-region overlap. - The three `initiator` arms, the nearest-enclosing-region derivation rule (nested included), the invalid-value warning, and that derivation never throws. - The normalisation rule as reader-facing behaviour: the region id, not the attribute text; the JSON `id` property; `namespace::` stripped; empty or non-string reads absent. `parseRegionId` is not named. - What reads absent, the full-page `core/body` contrast, and the two attribution boundaries. - The two keys composed into the per-region origin answer, region granularity, and core Query pagination as the already-true case. - Which primitive carries what, and the growth contract plus deprecated flag coexistence. Deviation from the plan, on the evidence: the plan's "a `data-wp-watch` on the same element as the initiating directive derives absent" is a design-doc claim the shipped code contradicts. A `data-wp-watch` flush lands a frame later, after the write span's marker is restored, so it derives its own region regardless of element (guard row 5). The verified boundary — a synchronous `watch()` navigating from inside the router's own write frames — is documented instead, with declaring `initiator` as the remedy (guard row 3). Guardrail md-docs-lint scoped to the file: 36 violations against a recorded baseline of 34. Delta +2, both `MD033` on the added callout's own lines (781, 782) — the named house-style exception. MD031, MD036 and MD040 unchanged at 1, 20 and 2.
…on guide Task 2 of the approved documentation plan. Appends three `####` recipe subsections inside `### Subscribing to page changes`, after Task 1's material and immediately before `## The Interactivity Router in depth`, plus a cross-link from `### Handling scroll and focus`. Each recipe is drawn from the shipped e2e fixture (`packages/e2e-tests/plugins/interactive-blocks/router-navigation-lifecycle/`), verified by Flows 28, 29 and 30 of `test/e2e/specs/interactivity/router-navigation-lifecycle.spec.ts`. None of the fixture's test-only plumbing (the counted logs, the settlement probe, the `pagehide` persistence, the `FIXTURE TRAP` scaffolding) is reproduced. - Per-block loading indication: one composition, not the fixture's two computationally identical getters. Covers the static-id tier (compared against the normalised region id, with the JSON object form called out at the comparison) and the per-instance-id tier via `data-wp-context` + `getContext()`, and names `getElement().ref.closest()` as the DOM route it replaces rather than denying one exists. Closes on core Query already satisfying per-instance identity with no setup. - Region-scoped focus: an edge-triggered `data-wp-watch` per region, with the previous-`navigating` bookkeeping in a module-scope object keyed by region id (not `context`, not the region element), no DOM reference captured across the navigation, and an explicit account of why it refrains on traversals. - Debounced page-level loading bar: a scope-less `watch()` writing the consumer's own store state, with the supersession, full-page-fallback and traversal consequences that follow from tracking only `state.navigating`. Each recipe states its initial-page-load and traversal behaviour. Verified against the code rather than the design doc, per the orchestrator's design-contradictions note. Two places where the design doc's own consumer patterns were not followed, both deliberate: - Design pattern (b)'s static tier uses a scope-less module-level `watch()` for focus. No shipped flow exercises that form, and the plan requires every recipe to correspond to a form the suite runs, so the recipe teaches the `data-wp-watch` form Flow 29 verifies and notes the literal-comparand variation in one sentence. - The design's claim that a `data-wp-watch` on the initiating element derives an absent initiator is contradicted by guard row 5 and is not restated here; nothing in these recipes navigates from a watcher. One correction to the plan's framing of the `create-block` scaffold: the plan and design describe its hand-rolled `isNavigating` as a per-block flag. It is declared through `wp_interactivity_state()`, so it is store-global and every instance of the block on a page lights up together — recorded as one of the three limits the lifecycle keys remove, rather than repeated as written. Guardrail (`npm run lint:md:docs` scoped to the file): MD031 1, MD033 13, MD036 20, MD040 2 — identical to the post-Task-1 baseline, no new violation in any rule, no new MD033 (no callout added). `prettier --check` clean.
Closes the five sites named in Task 3 of the documentation plan. All five were located by heading text; every claim below was verified against the shipped source rather than taken from the plan or the design. - `### Setting up router regions`: adds the failure mode behind the existing "both directives on the same element" rule. The directive runtime resolves a namespace from any ancestor (`vdom.ts`), so the region hydrates and works, while the router's `regionsSelector` requires `data-wp-interactive` on the element itself (`interactivity-router/src/index.ts:38`). Every navigation nulls the registered region signals before refilling only the ids the destination page yielded (`:338-363`), so an undetected region is left cleared — hydrates fine, empties on first navigation, no console output. - `#### Where to place router regions`, "Inside another router region": records that a derived initiator is the nearest enclosing region while the outer region stays the update unit. Identity is attribution, not an update-unit claim. Cross-links Task 1. - `### Handling server state updates`: adds what goes wrong without the re-sync pattern. `populateServerData()` calls `deepMerge( st.state, state, false )` (`interactivity/src/store.ts:290`), and `override: false` preserves every existing key (`proxies/state.ts:281-360`), so a server-seeded key keeps the first page's value silently. Cross-links the fuller treatment in directives-and-store.md rather than duplicating it. - `#### Phase 2: Navigate`: the walk omitted both lifecycle writes and left the 400 ms threshold as the only thing it said about observability. The start is now step 2 and the end step 11, and step 5 states that the threshold gates only the built-in feedback and the deprecated `state.navigation` flags. - `#### Race condition protection`: adds the consumer-visible consequence — continuous in-flight reading, no idle gap, no second end — and notes that the lifecycle writes carry their own latest-wins check rather than the target-URL comparison the section describes. No internal identifiers named. Deviation from the plan text, on the approving reviewer's binding amendment: the start is placed after step 1, not "at the top of the walk". Step 1 is the `clientNavigationDisabled` check, which publishes no lifecycle at all — `forcePageReload()` returns a promise that never resolves (`:407-410`), so the generator never reaches the start batch. Placing the start ahead of step 1 would have taught the opposite of what Task 1 documents. md-docs-lint on the file: 36 violations, MD033 13 / MD036 20 / MD040 2 / MD031 1 — identical to the stated baseline on every rule, zero delta. No new fences and no new callouts were added. `prettier --check` passes.
… README Task 4 of the documentation plan: the package reference for `@wordpress/interactivity-router`. - `### State` now lists all three state properties with their shipped types (`state.navigating`: `boolean | undefined`, `state.initiator`: `string | null | undefined`, both optional in the `Store` interface and absent from the store literal), the `undefined` reading before the first navigation and on pages where the router never loads, the truthiness rule, and what a derived `state.initiator` compares against (the region's id: the `id` property for the JSON attribute form, a stripped `namespace::` prefix, and `null` for an empty or non-string id). The full semantics are cross-linked to the Client-Side Navigation guide rather than restated. - The `navigate` options list gains `initiator`, with all three arms as the shipped `NavigateOptions` doc comment states them. - The store snippet notes both keys and why they are not declared in the literal, and the sentence after it points at `### State`. Every claim was checked against `packages/interactivity-router/src/index.ts` and the unit tests under `src/test/`. The end transition is stated as its one-sided contract only — after the commit, on a later frame, delay unbounded — with no ordering rationale; no new public export is implied. Guardrail `npm run lint:md:docs -- packages/interactivity-router/README.md`: 11 violations before and 11 after, same codes (MD033 x9 from the house-style callouts, MD036 x2 from the pre-existing `**Params**` leads). Delta zero.
…lifecycle
The "Do not rely on DOM ready events for initialization" section offered
`state.url`-keyed callbacks as the hook for code that must run on every
navigation. Two things it did not say:
- `state.url = href` is a value write, and the store's `PropSignal.update`
short-circuits when the assigned value equals the one already held
(`packages/interactivity/src/proxies/signals.ts:166-179`). A
`navigate( window.location.href, { force: true } )` — the refresh pattern
the handbook itself teaches — therefore publishes no `state.url`
notification at all, on either primitive, while both lifecycle transitions
still fire. Pinned by lifecycle-navigate.ts row 4 clause 2.
- DOM visibility differs per primitive. `state.url = href` and
`renderPage( page )` share one batch
(`packages/interactivity-router/src/index.ts:869-884`), so a raw `watch()`
(`effect`) sees the old DOM while a `data-wp-watch`
(`useSignalEffect` → `await afterNextFrame( eff.flush )`) sees the new one.
Stated per primitive, matching Task 1; the blanket form the plan's round 1
rejected is not written.
The two analytics examples are kept and are not characterised as wrong. Three
prose/comment phrases that promised "on every navigation" for a `state.url`
key were narrowed to "when the URL changes" so the section does not contradict
itself; no example code changed. One checklist line added.
…packages Satisfies the project rule that production code changes in a package require a CHANGELOG.md entry. - interactivity-router, under New Features: the two new reactive keys on the public core/router store (state.navigating, state.initiator) and the new optional initiator field on navigate()'s options, plus what both keys read before the first navigation and on pages where the router never loads. - interactivity, under Internal: afterNextFrame and getScope added to the privateApis bundle, with no public API added or changed. Deviates from the document plan on one point, on the approving reviewer's binding amendment. The plan describes the interactivity change as exporting afterNextFrame. It does not. The only change to packages/interactivity/src/index.ts is two entries added to the privateApis literal; afterNextFrame gained an `export` in utils.ts so index.ts can import it, but utils.ts is not reachable from the package's "exports" map, and index.ts's public export list is unchanged. An entry beginning "Export afterNextFrame" would announce a public API that was never added, so the subsection is Internal rather than New Features. Both entries omit the trailing PR link every other entry in these files carries: no pull request exists for this branch, and inventing a number would link to an unrelated PR. To be filled in when the PR is opened.
Restore the guide, the compatibility doc and the router README to their text at the document review wave 2 stamp, apply the manual review's uncommitted rewrite on top, then re-add the amendment's corrections in that voice: one new "When a navigation ends without new content" section covering the render-throw and 10-second fallback cases, the uncached-traversal reset, and short corrections at each site the reviewed text still described as the pre-amendment router.
🤖 PR meta 🤖🎉 PropsIf you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. Updated as activity occurs, without notifying anyone named here. Add the 📦 Bundle sizeSize Change: +421 B (+0.01%) Total Size: 8.25 MB 📦 View Changed
⚡ PerformanceShow the resultsClient side metrics exclude the server response time. front-end-block-theme
front-end-classic-theme
media-processing
media-upload
post-editor
site-editor
🏁 Flaky testsSome tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information. default to a list of pages if there are no menus in
|
DAreRodz
left a comment
There was a problem hiding this comment.
I haven't tested the feature yet, but codewise, this looks great. 🙂
The code changes, comments and documentation updates are good. The tests, though, are a bit extense, which could seem something positive initially, but I think some of them are not necessary or counter-productive.
In particular, there are a couple of test files that read the code directly and make string assertions directly against the code. I think those should be removed. Another worrying thing is a function named waitRealTime that seems to exist only to elude a linter rule.
Being the tests so extense, I ended up asking an AI model to scan them and write a short report with its impressions, which can be reviewed below.
AI-generated report (Claude Opus 5.5)
What I'd push back on
-
Tests that read source files as text. These are the weakest part of the PR:
private-apis-seam.test.tsreadsindex.tsandvdom.tswithreadFileSyncand searches strings like'\n\t\t}\n\n\t\tif ( ignore && ! island )', checking fornot.toContain('JSON.parse').- A popstate test checks with a string search that no
awaitappears betweencatchandthrow error;. Its own comment says the two versions behave identically ("byte-identical … on every behavioural observable"). If you can't observe the difference, it shouldn't be a test. - A release-bound test uses regexes to require
const LIFECYCLE_RELEASE_BOUND = 10000;exactly once and}, LIFECYCLE_RELEASE_BOUND );exactly twice.
These fail on harmless refactors or reformatting and don't catch real bugs. The concern behind them is valid:
privateApisreturnsany, so if the two packages drift apart nothing catches it. The better fix is to giveprivateApisa real return type. -
The test shim is its own coupling problem.
__fixtures__/interactivity-shim.tsreplaces@wordpress/interactivityby importing its internal modules via../../../../interactivity/src/...and duplicating theprivateApisobject and its consent string by hand. That is a second copy of the private-API boundary that must be kept in sync. It also required changes totsconfig.test.json:rootDir: "../.."andnoImplicitReturns: false. -
A lint workaround. The E2E spec defines
waitRealTime(browserPage, ms), and its comment admits the parameter isn't namedpageso that the rule banningpage.waitForTimeoutdoesn't fire. Deliberately getting around a lint rule should at least be discussed openly. Sleeps like this are also the most common cause of flaky E2E tests in CI. -
Tests share one router instance.
vi.resetModules()can't be used here, so each file imports the router once and every test in that file shares itscore/routerstate. That makes tests depend on run order. The "pristine" popstate case had to go in its own file, which shows the problem. -
Some tests pin timing the PR says is flexible. The description says the delay between committing the new page and the end signal is "intentionally unbounded". Yet several tests fix exact frame and millisecond behaviour, for example
afterNextFramerunning at 17 ms and not 16 ms. That will get in the way of the view-transition work the PR anticipates. -
Leftovers from the AI pipeline. Test names and comments use spec-tracking labels like "Clause 1", "half 1 / half 2", "Part A/B", "row2-dest", "canary" and "characterisation". Many functions have comments longer than their bodies. The commit history shows some cleanup already ("Drop … plan references"), but it isn't finished. This makes it harder for the next person working on the code to see what each test protects.
-
A new policy exception.
vitest-policy-exceptions.jsongains an entry for stubbingrequestAnimationFrame. It's justified, but it's one more thing reviewers have to approve.
What I'd suggest
- Keep the behavioural core:
- the lifecycle protocol for
navigate() - the popstate tests for supersession and fallback
- the initiator derivation tests, trimmed down
- the
watch()scope tests - the E2E two-Query test and the recipe tests
- the lifecycle protocol for
- Delete the source-text tests and give
privateApisa real type instead. - Replace
waitRealTimewith waits on a condition, or make the negative assertions use an explicittest.slow/retry approach. - Merge the overlapping files (the two popstate files and the release-bound tests) and rename tests to describe behaviour, not spec labels.
- Remove the tests that assert on source text, and type the return value of `privateApis` instead so TypeScript checks what the router destructures. - Drop the `@wordpress/interactivity` shim and test against the real module. - Merge the lifecycle, initiator, popstate and release-bound test files into three files with shared fixtures, and name tests after behavior. - Stop pinning exact frame timings in the `afterNextFrame` tests. - Replace the E2E `waitRealTime` sleeps with a condition-based wait. - Remove leftover spec labels from test names and comments.
Make the jsdom setup fixture a module so its dynamic import type checks, and import the router in `beforeAll` so a single test can run on its own.
…router-navigation-api
|
@DAreRodz, this is ready for a re-review. |
DAreRodz
left a comment
There was a problem hiding this comment.
Thanks for the fixes, @luisherranz. The tests are much better now. The rest looks good as before. Approved!
CI shuffles tests within each file, so the "before the first navigation" tests failed whenever another test in the same file navigated first. Move them to files of their own, where Vitest loads a fresh router: `lifecycle-initial` for the calls that leave the lifecycle unset, and `lifecycle-first-traversal` for the cached traversal that starts from it. No assertion changes.
This updates the pinned commit hash of the Gutenberg repository from 954fe7f9e04631c41aec4552acd627a7203a2aad to 7b95ee96b54de2e35886971ccf7eb449c324c830 (version 24.2.0). A full list of changes included in this commit can be found on GitHub: WordPress/gutenberg@954fe7f...7b95ee9 - useServerSideRender: parse messages from caught errors (WordPress/gutenberg#83365) - Docs: Fix published Vitest migration-guide links (WordPress/gutenberg#83449) - Fix: Whitespace changes are not shown in the Resolve Block diff. (WordPress/gutenberg#82397) - Editor: Use SearchableSelect for the post author field (WordPress/gutenberg#83323) - Docs: Note that block attributes and global styles values are untrusted at render time (WordPress/gutenberg#83473) - RichText: Remove dead exports and consolidate deprecations (WordPress/gutenberg#83461) - Inserter: Manage roving tab index to skip re-rendering every item (WordPress/gutenberg#83437) - SearchableSelectControl: Add to @wordpress/ui (WordPress/gutenberg#80979) - Try: Bolder "B" icon (WordPress/gutenberg#83321) - Ignore composer vendor files from top-level gitignore. (WordPress/gutenberg#22283) - Tests: Add floating notes e2e coverage (WordPress/gutenberg#83477) - Block Editor: Check the inserter's fallback containers unmemoized (WordPress/gutenberg#83446) - Packages: Update Ariakit to 0.4.40 (WordPress/gutenberg#83278) - Tests: Enforce per-call Vitest console expectations (WordPress/gutenberg#83095) - Theme: Fix virtual modules, root styles, and seed validation (WordPress/gutenberg#83355) - DataViews: Fix README to describe sort() as receiving field values, not items (WordPress/gutenberg#83483) - Budugbox: Label popup dialogs in stories (WordPress/gutenberg#83476) - Block editor: Isolate mutable test fixtures (WordPress/gutenberg#83098) - Blocks: Isolate registration state in tests (WordPress/gutenberg#83099) - UI: Remove automatic Notice announcements (WordPress/gutenberg#82737) - Text: Migrate Emotion styles to an SCSS Module (WordPress/gutenberg#82573) - Block library: Isolate order-sensitive test interactions (WordPress/gutenberg#83101) - Format Library: unify FormatEditProps to one type, move private types (WordPress/gutenberg#83487) - UI: Announce selected chips in SearchableChipSelect (WordPress/gutenberg#82863) - Card: Migrate from Emotion to SCSS modules (WordPress/gutenberg#82577) - Components: Deprecate the private Menu API (WordPress/gutenberg#82947) - CustomGradientPicker: Migrate control wrappers to an SCSS module (WordPress/gutenberg#82576) - Components: Isolate order-sensitive UI tests (WordPress/gutenberg#83103) - Tests: Isolate mutable configuration fixtures (WordPress/gutenberg#83104) - Core data: Finish deferred selection updates in RTC test (WordPress/gutenberg#83366) - Block editor: Wait for final keyboard link suggestions (WordPress/gutenberg#83489) - Data: Assert and silence resolution error in useSuspenseSelect test (WordPress/gutenberg#83491) - Tests: Isolate deprecation warning state (WordPress/gutenberg#83107) - UI: Align selection popup checkmarks with the first label line (WordPress/gutenberg#82942) - Tests: Resolve Browser Mode commands against the live iframe (WordPress/gutenberg#83495) - Ensure position type is a string (WordPress/gutenberg#83500) - MediaUpload: Fix console error when reopening Gallery media library (WordPress/gutenberg#76749) - Refactor stylelint config detection in lint-style.js (WordPress/gutenberg#79280) - Docs: Recommend UI Tabs for switching views (WordPress/gutenberg#83516) - Popover: Close non-modal popovers on iframe interaction (WordPress/gutenberg#83509) - Typography: List only the weights inside a variable font's range (WordPress/gutenberg#83128) - Style book: Add link to example text. (WordPress/gutenberg#83448) - Tests: Add Vitest Browser Mode failure artifacts (WordPress/gutenberg#83093) - Theme: Make JavaScript token fallback transforms syntax-aware (WordPress/gutenberg#83356) - Editor: Fix new posts being published with the `auto-draft` slug (WordPress/gutenberg#83518) - Editor: Gather the View group of the Options menu into submenus (WordPress/gutenberg#82976) - Tests: Fix PostCSS browser-externalized warnings in Vitest (WordPress/gutenberg#83091) - Tests: Shuffle test cases in CI (WordPress/gutenberg#83111) - Update Styles > Blocks description. (WordPress/gutenberg#83515) - Columns: Remove the column count slider (WordPress/gutenberg#83262) - BorderControl: Remove `%` from the border width units (WordPress/gutenberg#83492) - Fields: Fix AuthorView for users who can't edit users (WordPress/gutenberg#83498) - Update and add justify icons. (WordPress/gutenberg#83519) - RichText: Refactor useMarkPersistent, fix StrictMode mount mark (WordPress/gutenberg#83463) - Theme: Improve accessibility, API documentation, and compatibility checks (WordPress/gutenberg#83358) - Theme: Preserve global token references in Lightning CSS (WordPress/gutenberg#83359) - Tests: Migrate internal linting to Vitest and remove unused Jest dependencies (WordPress/gutenberg#83502) - Improve specificity of lightbox button selector (WordPress/gutenberg#70800) - TextControl: Use design system colors when disabled (WordPress/gutenberg#83307) - Fix: Image lightbox: overlay becomes unusable (can't close) when it isn't a direct child of `<body>` (WordPress/gutenberg#83480) - Notes: Extract note selection sync into useNoteSelection hook (WordPress/gutenberg#83528) - Block Parser: Document `\WP_Block_Parser::$stack` as a list (WordPress/gutenberg#82695) - CollapsibleCard: Scope the header focus ring to its own trigger (WordPress/gutenberg#81314) - Fix broken links in docs (WordPress/gutenberg#83545) - Icons: Use assertEqualHTML() in icons registry tests (WordPress/gutenberg#83544) - Editor: Merge adjacent revision inline diffs (WordPress/gutenberg#80579) - Date: Ignore trailing format backslash instead of printing undefined (WordPress/gutenberg#81528) - Block Supports: Add background-clip block support infrastructure (WordPress/gutenberg#77141) - Block Editor: Fix translator comments for block count announcements (WordPress/gutenberg#83555) - Paste: replace non-breaking spaces at the edges of text with regular spaces (WordPress/gutenberg#83464) - Media Editor: Fix pan drag flooding undo history after wheel zoom (WordPress/gutenberg#83558) - Rich text: fix iOS double tap selection, preventing focus capture under editable host (WordPress/gutenberg#81042) - Block editor: migrate state-control badges to UI Badge (WordPress/gutenberg#82608) - Gallery: Add Order By controls for static gallery, consolidate controls in settings sidebar (WordPress/gutenberg#83438) - Media editor: show an error when saving attachment details fails (WordPress/gutenberg#83560) - Position controls: Fix useSelect warning for selected state viewports (WordPress/gutenberg#83570) - Inserter: Use design system focus ring for previews (WordPress/gutenberg#83126) - Image: Fix lightbox using thumbnail aspect ratio instead of original image ratio (WordPress/gutenberg#79058) - Docs: Clarify @wordpress/ui icon color requirements (WordPress/gutenberg#83564) - docker compose -T if stdin is not a tty (WordPress/gutenberg#78374) - Storybook: Add new contributing page. (WordPress/gutenberg#83345) - Widget Primitives: Avoid Vite warnings for runtime widget modules (WordPress/gutenberg#83602) - Build: Update Vite to 8.3.1 and simplify Storybook tooling (WordPress/gutenberg#83569) - doc(wp-env) Change core branch from trunk to master in doc (WordPress/gutenberg#83566) - wp-build: Remove the unused boot, private-apis, and route optional peer dependencies (WordPress/gutenberg#83601) - CI: Check CHANGELOG presence for published tooling and config packages (WordPress/gutenberg#83577) - Tests: Enforce Vitest assertion coverage (WordPress/gutenberg#83572) - Icons: Update heading level icons for optical balance (WordPress/gutenberg#83268) - ESLint: Add allowUseWithCaution option to use-recommended-components (WordPress/gutenberg#83536) - Notes: Refactor floating board measurement (WordPress/gutenberg#83485) - Inserter: Stop re-rendering the block list on block selection change (WordPress/gutenberg#83284) - Paste: Give each pasted data-URI image unique filename to avoid upload collisions. (WordPress/gutenberg#79480) - Changelog validator: ignore markdown & configs d46223 (WordPress/gutenberg#83618) - Font Library: Use UI Menu for collection actions (WordPress/gutenberg#82965) - Storybook: Show prop descriptions in Canvas controls (WordPress/gutenberg#83581) - test: Link upstream warning fixes in config (WordPress/gutenberg#83632) - Storybook: Use one block-editor store module (WordPress/gutenberg#83636) - Tests: Use strict assertions synced from Core changeset 63934. (WordPress/gutenberg#83619) - Math: Store cell alignment in the MathML and polyfill alignment and overlines in Chromium (WordPress/gutenberg#83164) - Storybook: Reuse PostCSS browser resolver in smoke tests (WordPress/gutenberg#83635) - Editor: Use UI Menu for template options (WordPress/gutenberg#82964) - RTC: Add a EntitySyncManager interface in core-data (WordPress/gutenberg#83410) - Term Count: Add margin support (WordPress/gutenberg#83608) - Archives: Add minimum height support (WordPress/gutenberg#83573) - Media Editor: Stop the crop pixel snap from recording undo history (WordPress/gutenberg#83571) - Term Name: Add margin support (WordPress/gutenberg#83606) - Post Author Biography: Add text indent support (WordPress/gutenberg#83614) - Code: Add minimum width and height support (WordPress/gutenberg#83574) - Details: Add minimum width support (WordPress/gutenberg#83576) - Post Content: Add minimum width support (WordPress/gutenberg#83575) - Post Excerpt: Add minimum width and height support (WordPress/gutenberg#83578) - Post Title: Add minimum width and height support (WordPress/gutenberg#83600) - Footnotes: Add minimum width and height support (WordPress/gutenberg#83579) - Storybook: Place Notice announcements under Components (WordPress/gutenberg#83617) - InputControl: Darken the field border on hover (WordPress/gutenberg#83306) - npm: Switch from legacy-peer-deps to strict-peer-deps (WordPress/gutenberg#81029) - Term Name: Add minimum width and height support (WordPress/gutenberg#83599) - Columns: Allow dropping a column at the outer edges (WordPress/gutenberg#83274) - E2E: Pin the site title in the Interactivity API router specs and give the E2E Storybook build more heap. (WordPress/gutenberg#83474) - Heading: Add minimum width and height support (WordPress/gutenberg#83580) - Login/out: Add minimum width and height support (WordPress/gutenberg#83583) - Verse: Add minimum width support (WordPress/gutenberg#83609) - Video, Cover: Don't autoplay in the editor when reduced motion is preferred (WordPress/gutenberg#83337) - Media & Text: Lower the specificity of the content padding (WordPress/gutenberg#83563) - Pagination: Add padding, margin, and block gap support (WordPress/gutenberg#83743) - Fix peer dependency conflicts left in the lockfile (WordPress/gutenberg#83754) - Comments Pagination: Add padding, margin, and block gap support (WordPress/gutenberg#83744) - Term Count: Add minimum width and height support (WordPress/gutenberg#83596) - Read More: Add border style support (WordPress/gutenberg#83735) - Cover: Don't autoplay embedded background videos when reduced motion is preferred (WordPress/gutenberg#83452) - No Results: Add minimum width and height support (WordPress/gutenberg#83584) - RichText: Rename utils.jsx to utils.js (WordPress/gutenberg#83758) - Quote: Add minimum width support (WordPress/gutenberg#83592) - Upgrade typescript-eslint to v8.70.1 (WordPress/gutenberg#83760) - Tabs: Add minimum width support (WordPress/gutenberg#83595) - Site Tagline: Add minimum width and height support (WordPress/gutenberg#83589) - Heading: Add text indent support (WordPress/gutenberg#83615) - Site Title: Add minimum width and height support (WordPress/gutenberg#83593) - Home Link: Add padding and margin support (WordPress/gutenberg#83607) - Preformatted: Add minimum width and height support (WordPress/gutenberg#83587) - Include E2E Storybook sources in docgen (WordPress/gutenberg#83634) - Extensible Site Editor: Pass custom block categories to the blocks store (WordPress/gutenberg#83762) - Packages: Declare missing peer dependencies and check them in CI (WordPress/gutenberg#83765) - Post Terms: Add minimum width and height support (WordPress/gutenberg#83586) - Group, Cover: Track drop zone element in state (WordPress/gutenberg#83756) - Global Styles: Add pseudo-state controls for Navigation Link (WordPress/gutenberg#83451) - storybook: Register playground core blocks once (WordPress/gutenberg#83637) - Document Outline: Show the design system focus ring instead of legacy box-shadow (WordPress/gutenberg#83755) - storybook: Update BlockPopover fixture to API version 3 (WordPress/gutenberg#83642) - Add typing to iAPI's getConfig() (WordPress/gutenberg#71692) - Components: deprecate Badge (WordPress/gutenberg#82379) - Block Editor: Fix style / nested attribute overwrite during multi-selection (WordPress/gutenberg#80070) - Notes: Restrict menu actions for resolution notes and resolved threads (WordPress/gutenberg#73243) - UI: Add change actions to form primitive stories (WordPress/gutenberg#83591) - Icons: Support keyword-based search in the icons registry (WordPress/gutenberg#82367) - Avatar: Explain that avatars use the Gravatar service (WordPress/gutenberg#83567) - UI: Add item labels and descriptions to remaining popups (WordPress/gutenberg#83493) - PaletteEdit: Stop changing the slug when renaming a preset (WordPress/gutenberg#83750) - Storybook: Fix missing block styles in BlockCanvas playground stories (WordPress/gutenberg#81070) - Tests: Enforce Vitest callback, promise, and title rules (WordPress/gutenberg#83620) - ItemGroup: Use design system focus ring (WordPress/gutenberg#83764) - Keep the legacy CheckboxControl visually consistent across viewports (WordPress/gutenberg#83612) - Media editor: Use UI Menu for crop aspect ratio (WordPress/gutenberg#82968) - Use strict assertions in override script tests (WordPress/gutenberg#83782) - Home Link: Add minimum width and height support (WordPress/gutenberg#83582) - Tab Panels: Add minimum height support (WordPress/gutenberg#83594) - Post Time to Read: Add minimum width and height support (WordPress/gutenberg#83598) - Term Description: Add minimum width and height support (WordPress/gutenberg#83597) - UI: Keep InputLayout chrome at md on small viewports (WordPress/gutenberg#82764) - Math: Add minimum width and height support (WordPress/gutenberg#83585) - Tests: Bump undici in the AI development test lockfile (WordPress/gutenberg#83799) - Bump brace-expansion in /test/ai-development (WordPress/gutenberg#83807) - Bump js-yaml and promptfoo in /test/ai-development (WordPress/gutenberg#83797) - Bump fast-uri from 3.1.7 to 3.1.8 (WordPress/gutenberg#83829) - Update AI Development package versions after npm audit (WordPress/gutenberg#83830) - Notes: Add show and hide options for floating notes (WordPress/gutenberg#83768) - Add separators to item popup components (WordPress/gutenberg#83776) - Components: Align RadioControl colors with UI Radio (WordPress/gutenberg#83270) - E2E: Mock Openverse in image drag-and-drop inserter test (WordPress/gutenberg#83842) - FormToggle: Match Switch colors across states (WordPress/gutenberg#83773) - Bump `@react-spring/web` from 9.4.5 to 10.1.2 (WordPress/gutenberg#83796) - ColorPalette: Show design system focus ring on custom color button (WordPress/gutenberg#83841) - Docs: Remove CheckboxControl heading from InspectorControls example (WordPress/gutenberg#83844) - Base Styles: Default the admin theme color to Blueberry (WordPress/gutenberg#83749) - Menu: Guard against nesting Group and RadioGroup (WordPress/gutenberg#83792) - Template Part: Fall back to rendering a template part from the theme file if the db version is unavailable (WordPress/gutenberg#83809) - Tests: Reset deprecation history in shared Vitest setup (WordPress/gutenberg#83849) - Menu: Disable triggers instead of roots in consumers (WordPress/gutenberg#83791) - Playlist: Replace the waveform player patch with its no-autoinit entry (WordPress/gutenberg#83132) - Update UI Spinner appearance and add a color prop (WordPress/gutenberg#83775) - UI: Align component names with their semantics (WordPress/gutenberg#83789) - Checkbox: Prevent rounded themes from making checkboxes circular (WordPress/gutenberg#83526) - Storybook: Update manifest snapshot for Spinner color prop (WordPress/gutenberg#83856) - Button: Only open the link popover on explicit user action (WordPress/gutenberg#30166) - Gallery Lightbox: Prevent image click from closing the dialog when navigation is enabled (WordPress/gutenberg#78898) - UI: Recommend Checkbox family components (WordPress/gutenberg#83771) - RadioControl: Keep a 16px visual with a larger hit target (WordPress/gutenberg#83840) - Table: replace deprecated word-break with overflow-wrap: anywhere (WordPress/gutenberg#82480) - Tag Cloud: Update styles and add `!important` (WordPress/gutenberg#70224) - Correctly document the `blockName` property as being nullable (WordPress/gutenberg#70900) - Add inertValue helper and use it for setting inert attribute (WordPress/gutenberg#83871) - Enable editableRoot for the list item block for multi-selection on mobile (WordPress/gutenberg#82816) - Verify localized data retention in override script test (WordPress/gutenberg#83845) - Tests: Bump ibm-cloud-sdk-core in the AI development test lockfile (WordPress/gutenberg#83887) - UI: Recommend Notice component (WordPress/gutenberg#82685) - Fix: MediaUpload `gallery` prop ignores `allowedTypes` (WordPress/gutenberg#78257) - Media editor: Add a session boundary above the cropper (WordPress/gutenberg#83550) - DataViews: Measure the container as the data view mounts to avoid a single column flash (WordPress/gutenberg#83752) - Pullquote: Add minimum width support (WordPress/gutenberg#83588) - Media editor: Remove initial state seeding from the session (WordPress/gutenberg#83893) - UI: Add e2e Storybook popup item layout fixtures (WordPress/gutenberg#83488) - Storybook: Give CI job a distinct name (WordPress/gutenberg#83869) - Coding standards: Skip anonymous class methods in block library function name sniff (WordPress/gutenberg#83900) - Pagination: Add border support (WordPress/gutenberg#83745) - PR meta: Move the props list into the shared comment (WordPress/gutenberg#82302) - Comments Pagination: Add border support (WordPress/gutenberg#83746) - Scripts: Resolve default configs without hoisted dependencies (WordPress/gutenberg#83902) - Image: Fix invalid CSS url() value in circle-mask style (WordPress/gutenberg#82333) - Query Total: Add minimum width and height support (WordPress/gutenberg#83590) - Scripts: Treat files passed after --fix as file arguments (WordPress/gutenberg#83521) - Editor: Remove icon for 'Export' more menu item (WordPress/gutenberg#83901) - Dashboard Widgets: let a mounted widget declare actions at runtime (WordPress/gutenberg#83877) - Framework: Switch from hoisted to isolated dependencies (WordPress/gutenberg#83847) - Test: Run Vitest type graph validation in process (WordPress/gutenberg#83851) - Remove use-memo-one usage (missing React 19 compat) (WordPress/gutenberg#83952) - Fix Post Featured Image crash when isLink is enabled (WordPress/gutenberg#81584) - Experiment: restyle classic wp-admin controls from design system tokens (WordPress/gutenberg#82425) - Tests: Lint JavaScript Vitest mock imports (WordPress/gutenberg#83783) - Build: Remove patch-package (WordPress/gutenberg#83982) - Docs: Update deprecation testing guidance for shared reset (WordPress/gutenberg#83989) - DataViews: list hideable fields alphabetically in the view config (WordPress/gutenberg#83947) - Core Data: Rank link suggestions by type, and stop discarding merged results (WordPress/gutenberg#83407) - Add new react-inert-value package with inertValue helper (WordPress/gutenberg#83987) - Connectors: Keep a stored API key read-only when it can't be verified (WordPress/gutenberg#83889) - Navigation: Search every entity type from the link UI (WordPress/gutenberg#83408) - Tests: Cover translation setup in override script tests (WordPress/gutenberg#83886) - Build: Update Vite to 8.3.2 and remove the PostCSS browser resolver (WordPress/gutenberg#83992) - Update readme title to match block name (WordPress/gutenberg#83999) - RTC: Fix undo breaking for non-synced entities (WordPress/gutenberg#83888) - CI: Cover the AI development lockfile with Dependabot instead of npm audit (WordPress/gutenberg#83997) - Latest Posts: Add minimum width and height support (WordPress/gutenberg#83905) - Avatar: Add shadow support (WordPress/gutenberg#83929) - Tab List: Add shadow support (WordPress/gutenberg#83922) - Buttons: Add minimum width and height support (WordPress/gutenberg#83894) - Social Icons: Add shadow support (WordPress/gutenberg#83920) - Columns: Add minimum width and height support (WordPress/gutenberg#83895) - Gallery: Add shadow support (WordPress/gutenberg#83919) - File: Add shadow support (WordPress/gutenberg#83918) - Page List: Add minimum width and height support (WordPress/gutenberg#83908) - Build Tooling: Read npm v12 pack --json output (WordPress/gutenberg#84011) - Accordion Heading: Add line height support (WordPress/gutenberg#83958) - Paragraph: Add shadow support (WordPress/gutenberg#83926) - Media & Text: Add minimum width and height support (WordPress/gutenberg#83906) - Tests: Patch basic-ftp in AI development dependencies (WordPress/gutenberg#84000) - Env, E2E: Update dependencies that ran native install scripts (WordPress/gutenberg#84012) - Tests: Update Vitest to 5.0.3 and Storybook to 10.6.1 (WordPress/gutenberg#83996) - Search: Add padding support (WordPress/gutenberg#83984) - Block editor: Honour background skip serialization in the editor (WordPress/gutenberg#83943) - Framework: Declare React types in the workspaces that use them (WordPress/gutenberg#84013) - Fit text: Size each block instance in a loop independently (WordPress/gutenberg#83985) - FocalPointPicker: end a drag released over the editor canvas (WordPress/gutenberg#83348) - Tests: Cover Menu scroll lock and LinkControl protocols in browsers (WordPress/gutenberg#83991) - List: Add shadow support (WordPress/gutenberg#83923) - UI: Add Progress with custom color support (WordPress/gutenberg#83781) - ESLint: Allow non-module stylesheet imports in unit tests (WordPress/gutenberg#84019) - Canvas loader: Use UI Progress and pass color via the indicator prop (WordPress/gutenberg#83860) - Menu: Align group labels and separators with indented item labels. (WordPress/gutenberg#83993) - react-inert-value: add missing types/react peer dep (WordPress/gutenberg#84024) - Docs: Refine design system agent guidance (WordPress/gutenberg#84007) - Navigation: List allowed blocks in the link UI search results + add transformSuggestions to Link Control (WordPress/gutenberg#83652) - Sync: Remove exposed wp.sync package (WordPress/gutenberg#81999) - Style: Update color to use CSS variable in edit-site (WordPress/gutenberg#79002) - Popover: drop the will-change hint once the popover stops moving (WordPress/gutenberg#77359) - MediaEdit: Show a checkerboard background behind image previews (WordPress/gutenberg#83846) - Quote: Add button colour support (WordPress/gutenberg#83983) - Media & Text: Add duotone support (WordPress/gutenberg#83981) - Gallery: Add duotone support (WordPress/gutenberg#83978) - Interactivity API Router: Add reactive navigation lifecycle and initiator API (WordPress/gutenberg#83280) - Notes: Move floating notes into a canvas margin (WordPress/gutenberg#83786) - Verse: Add text columns and indent support (WordPress/gutenberg#83962) - Notes: Scroll floating notes with the canvas (WordPress/gutenberg#83852) - Notes: Add Undo to deleted note snackbar (WordPress/gutenberg#83988) - Framework: Move @typescript/native from the root to the workspaces that use it (WordPress/gutenberg#84027) - Repair invalid peer dependencies in the lockfile (WordPress/gutenberg#84062) - Term Template: Add minimum width and height support (WordPress/gutenberg#83914) - Fix check type declarations (WordPress/gutenberg#84070) - Media: track the original attachment id for edited images (WordPress/gutenberg#81803) - Post Comments Form: Add font family support (WordPress/gutenberg#83967) - Media Utils: Add `MediaEdit` as a private API (WordPress/gutenberg#84046) - Build Tools: Fix flaky ESM package types test timeout (WordPress/gutenberg#84068) - Embed: Add padding support (WordPress/gutenberg#83963) - Interactivity API: Add a data-wp-html directive (WordPress/gutenberg#83092) - Typography and "block-default icon polish. (WordPress/gutenberg#84073) - Release Tooling: Read the npm v12 JSON output shapes (WordPress/gutenberg#84075) - Menu: Align submenu labels and highlight open parents (WordPress/gutenberg#84031) - Props Bot: Skip bare reviews that duplicate their review comment runs (WordPress/gutenberg#84076) - Dataviews: use inertValue in CompositeGrid (WordPress/gutenberg#84072) - UI: Add Meter (WordPress/gutenberg#83855) - Media & Text: Add shadow support (WordPress/gutenberg#83976) - Media editor: restore original image in modal (WordPress/gutenberg#81805) - List: Add background image, size, and gradient support (WordPress/gutenberg#83935) - List Item: Add background image, size, and gradient support (WordPress/gutenberg#83936) - Block Editor: Fix 'Manage allowed blocks' not shown when its the only 'Advanced' control (WordPress/gutenberg#84067) - Design System: Clarify tooltip labeling and UI review guidance (WordPress/gutenberg#83898) - Gallery: Add minimum width and height support (WordPress/gutenberg#83897) - File: Add minimum width and height support (WordPress/gutenberg#83896) - Media: Return 0 from the edit root lookup when there is no edit root (WordPress/gutenberg#84096) - Read More: Add minimum width and height support (WordPress/gutenberg#83912) - UI: Recommend Radio family components (WordPress/gutenberg#83872) - Latest Comments: Add minimum width and height support (WordPress/gutenberg#83904) - chore: Use v24 in .nvmrc (WordPress/gutenberg#84061) - Embed: Add minimum width and height support (WordPress/gutenberg#83903) - Post Comments Form: Add minimum width and height support (WordPress/gutenberg#83910) - Post Featured Image: Add border style support (WordPress/gutenberg#83956) - Buttons: Add shadow support (WordPress/gutenberg#83916) - Poetry: Add fit text support (WordPress/gutenberg#83980) - Video: Add duotone support (WordPress/gutenberg#83979) - Notes: Keep anchor writes out of undo history (WordPress/gutenberg#84079) - ProgressBar: Use WPDS color tokens (WordPress/gutenberg#83779) - REST API: Add action-trash link to posts and comments (WordPress/gutenberg#84045) - RSS: Add minimum width and height support (WordPress/gutenberg#83913) - Notes: Reset paragraph top margin in floating notes (WordPress/gutenberg#84101) - Global Styles: Fix popover position in Styles screen (WordPress/gutenberg#84048) - Block Switcher: Show design system focus ring on pattern previews (WordPress/gutenberg#83933) - MediaEdit: Use design system focus ring (WordPress/gutenberg#83854) - Notes: Delete permanently when the trash is disabled (WordPress/gutenberg#84102) - Release: Rewrite SVN publication scripts in Node.js (WordPress/gutenberg#84034) - ContentEditableControl: Keep a disabled field focusable (WordPress/gutenberg#84083) - States: Scope per-instance rules to the block's root element (WordPress/gutenberg#83986) - List Item: Add shadow support (WordPress/gutenberg#83925) - DataViews: Truncate filter chips instead of wrapping them (WordPress/gutenberg#83879) - Experiments: Turn the React 19 experiment on by default (WordPress/gutenberg#83784) - Notes: Extract NoteReply and lift AddNote gating (WordPress/gutenberg#84106) - Interactivity API: Remove expired deprecated behaviors (WordPress/gutenberg#84098) - Breadcrumbs: Fix typo in aria label translation context (WordPress/gutenberg#84112) - ESLint: Allow generated test titles (WordPress/gutenberg#83995) - Icons: Add keywords to icon manifest (WordPress/gutenberg#83884) - Tooltip: Control the hover delay cancellation test clock (WordPress/gutenberg#84113) - VS Code: Add managed workspace config (WordPress/gutenberg#84025) - Breadcrumb: fix getMeasurementRender for React 19 (WordPress/gutenberg#84069) - Notes: Fix flaky thread scroll e2e test (WordPress/gutenberg#84118) - Detect the database client in the unit test debug step. (WordPress/gutenberg#84089) - UI: Preserve Autocomplete item type inference (WordPress/gutenberg#84095) - UI: Recommend Switch family components (WordPress/gutenberg#84097) - Env: Add an option to choose the MariaDB version (WordPress/gutenberg#83751) - UI: Preserve Budugbox source item generics (WordPress/gutenberg#84094) - Menu: Tighten spacing, use 16px prefix icons, and cap width at 320px (WordPress/gutenberg#84028) - Notes: Preserve unsent note and reply drafts (WordPress/gutenberg#84110) - Theme: Add integration test coverage for seed colors in artifacts (WordPress/gutenberg#81161) - Progress: Migrate remaining ProgressBar usages and recommend UI Progress (WordPress/gutenberg#84021) - Components: Fix polymorphism typings leaking `as` prop (WordPress/gutenberg#82704) - Media & Text: Add background image, size, and gradient support (WordPress/gutenberg#83927) - Experiments: Use a mock plugin slug that no WordPress build ships in the unrelated-plugin test (WordPress/gutenberg#84133) - Button: Add background image, size, and gradient support (WordPress/gutenberg#83950) - Tests: Isolate Ajv per test in wp-env schema tests to avoid order dependence (WordPress/gutenberg#84139) - Storybook: Read icon keywords from the manifest (WordPress/gutenberg#84127) - SandBox: Fix embed previews that require a referrer in Safari (WordPress/gutenberg#84014) - Notes: Restore child notes trashed along with their parent note (WordPress/gutenberg#84100) - Style states: fix exception when there's no selected block (WordPress/gutenberg#84140) - Chore: Use v24.20 in `.nvmrc` config file. (WordPress/gutenberg#84138) - Security: Opt in to the npm v12 supply-chain defaults (WordPress/gutenberg#82689) - Docs: Describe isolated dependencies for agents and contributors (WordPress/gutenberg#84141) - Upgrade code and types to React 19 (WordPress/gutenberg#83941) - Latest Comments: Add border support (WordPress/gutenberg#84148) - Add prettier, eslint and stylelint to the root package.json (WordPress/gutenberg#84017) - FontSizePicker: Migrate Emotion styles to SCSS Modules (WordPress/gutenberg#84126) - Fields API: Add the server-side registry and REST route (WordPress/gutenberg#84078) - Block bindings: add support to `icon` attribute of `core/icon` (WordPress/gutenberg#80730) - VisuallyHidden: Move hiding styles outside CSS cascade layers (WordPress/gutenberg#84114) - Theme: Generate complete border token modes for Figma testing (WordPress/gutenberg#84035) - Developer tools: Simplify editor setup and add Zed settings (WordPress/gutenberg#84143) - Consolidate wp-admin container radiuses onto the design system scale (WordPress/gutenberg#82427) - CustomGradientPicker: Extend control point targets to the bar height (WordPress/gutenberg#84124) - Notes: Draw the canvas divider from body so it uses the theme text color (WordPress/gutenberg#84158) - Icons: Experiment with proportional stroke scaling (WordPress/gutenberg#84081) - Global Styles: Ignore theme.json values of unexpected types (WordPress/gutenberg#84523) - React 19 codemod: apply defaultProps when rendering a memo component (WordPress/gutenberg#84568) - React 19: add new incompatible plugins (WordPress/gutenberg#84607) - Tests: Fix HTML comparison tests (WordPress/gutenberg#84294) - Tests: Fix list item unsafe markup test on older WordPress versions (WordPress/gutenberg#84302) - Experiments: don't invalidate saved option with a legacy key (WordPress/gutenberg#84619) - Tests: Scope Classic block media checkbox locator (WordPress/gutenberg#84524) Props mamaduka. See #66340 git-svn-id: https://develop.svn.wordpress.org/trunk@64587 602fd350-edb4-49c9-b593-d223f7449a82
This updates the pinned commit hash of the Gutenberg repository from 954fe7f9e04631c41aec4552acd627a7203a2aad to 7b95ee96b54de2e35886971ccf7eb449c324c830 (version 24.2.0). A full list of changes included in this commit can be found on GitHub: WordPress/gutenberg@954fe7f...7b95ee9 - useServerSideRender: parse messages from caught errors (WordPress/gutenberg#83365) - Docs: Fix published Vitest migration-guide links (WordPress/gutenberg#83449) - Fix: Whitespace changes are not shown in the Resolve Block diff. (WordPress/gutenberg#82397) - Editor: Use SearchableSelect for the post author field (WordPress/gutenberg#83323) - Docs: Note that block attributes and global styles values are untrusted at render time (WordPress/gutenberg#83473) - RichText: Remove dead exports and consolidate deprecations (WordPress/gutenberg#83461) - Inserter: Manage roving tab index to skip re-rendering every item (WordPress/gutenberg#83437) - SearchableSelectControl: Add to @wordpress/ui (WordPress/gutenberg#80979) - Try: Bolder "B" icon (WordPress/gutenberg#83321) - Ignore composer vendor files from top-level gitignore. (WordPress/gutenberg#22283) - Tests: Add floating notes e2e coverage (WordPress/gutenberg#83477) - Block Editor: Check the inserter's fallback containers unmemoized (WordPress/gutenberg#83446) - Packages: Update Ariakit to 0.4.40 (WordPress/gutenberg#83278) - Tests: Enforce per-call Vitest console expectations (WordPress/gutenberg#83095) - Theme: Fix virtual modules, root styles, and seed validation (WordPress/gutenberg#83355) - DataViews: Fix README to describe sort() as receiving field values, not items (WordPress/gutenberg#83483) - Budugbox: Label popup dialogs in stories (WordPress/gutenberg#83476) - Block editor: Isolate mutable test fixtures (WordPress/gutenberg#83098) - Blocks: Isolate registration state in tests (WordPress/gutenberg#83099) - UI: Remove automatic Notice announcements (WordPress/gutenberg#82737) - Text: Migrate Emotion styles to an SCSS Module (WordPress/gutenberg#82573) - Block library: Isolate order-sensitive test interactions (WordPress/gutenberg#83101) - Format Library: unify FormatEditProps to one type, move private types (WordPress/gutenberg#83487) - UI: Announce selected chips in SearchableChipSelect (WordPress/gutenberg#82863) - Card: Migrate from Emotion to SCSS modules (WordPress/gutenberg#82577) - Components: Deprecate the private Menu API (WordPress/gutenberg#82947) - CustomGradientPicker: Migrate control wrappers to an SCSS module (WordPress/gutenberg#82576) - Components: Isolate order-sensitive UI tests (WordPress/gutenberg#83103) - Tests: Isolate mutable configuration fixtures (WordPress/gutenberg#83104) - Core data: Finish deferred selection updates in RTC test (WordPress/gutenberg#83366) - Block editor: Wait for final keyboard link suggestions (WordPress/gutenberg#83489) - Data: Assert and silence resolution error in useSuspenseSelect test (WordPress/gutenberg#83491) - Tests: Isolate deprecation warning state (WordPress/gutenberg#83107) - UI: Align selection popup checkmarks with the first label line (WordPress/gutenberg#82942) - Tests: Resolve Browser Mode commands against the live iframe (WordPress/gutenberg#83495) - Ensure position type is a string (WordPress/gutenberg#83500) - MediaUpload: Fix console error when reopening Gallery media library (WordPress/gutenberg#76749) - Refactor stylelint config detection in lint-style.js (WordPress/gutenberg#79280) - Docs: Recommend UI Tabs for switching views (WordPress/gutenberg#83516) - Popover: Close non-modal popovers on iframe interaction (WordPress/gutenberg#83509) - Typography: List only the weights inside a variable font's range (WordPress/gutenberg#83128) - Style book: Add link to example text. (WordPress/gutenberg#83448) - Tests: Add Vitest Browser Mode failure artifacts (WordPress/gutenberg#83093) - Theme: Make JavaScript token fallback transforms syntax-aware (WordPress/gutenberg#83356) - Editor: Fix new posts being published with the `auto-draft` slug (WordPress/gutenberg#83518) - Editor: Gather the View group of the Options menu into submenus (WordPress/gutenberg#82976) - Tests: Fix PostCSS browser-externalized warnings in Vitest (WordPress/gutenberg#83091) - Tests: Shuffle test cases in CI (WordPress/gutenberg#83111) - Update Styles > Blocks description. (WordPress/gutenberg#83515) - Columns: Remove the column count slider (WordPress/gutenberg#83262) - BorderControl: Remove `%` from the border width units (WordPress/gutenberg#83492) - Fields: Fix AuthorView for users who can't edit users (WordPress/gutenberg#83498) - Update and add justify icons. (WordPress/gutenberg#83519) - RichText: Refactor useMarkPersistent, fix StrictMode mount mark (WordPress/gutenberg#83463) - Theme: Improve accessibility, API documentation, and compatibility checks (WordPress/gutenberg#83358) - Theme: Preserve global token references in Lightning CSS (WordPress/gutenberg#83359) - Tests: Migrate internal linting to Vitest and remove unused Jest dependencies (WordPress/gutenberg#83502) - Improve specificity of lightbox button selector (WordPress/gutenberg#70800) - TextControl: Use design system colors when disabled (WordPress/gutenberg#83307) - Fix: Image lightbox: overlay becomes unusable (can't close) when it isn't a direct child of `<body>` (WordPress/gutenberg#83480) - Notes: Extract note selection sync into useNoteSelection hook (WordPress/gutenberg#83528) - Block Parser: Document `\WP_Block_Parser::$stack` as a list (WordPress/gutenberg#82695) - CollapsibleCard: Scope the header focus ring to its own trigger (WordPress/gutenberg#81314) - Fix broken links in docs (WordPress/gutenberg#83545) - Icons: Use assertEqualHTML() in icons registry tests (WordPress/gutenberg#83544) - Editor: Merge adjacent revision inline diffs (WordPress/gutenberg#80579) - Date: Ignore trailing format backslash instead of printing undefined (WordPress/gutenberg#81528) - Block Supports: Add background-clip block support infrastructure (WordPress/gutenberg#77141) - Block Editor: Fix translator comments for block count announcements (WordPress/gutenberg#83555) - Paste: replace non-breaking spaces at the edges of text with regular spaces (WordPress/gutenberg#83464) - Media Editor: Fix pan drag flooding undo history after wheel zoom (WordPress/gutenberg#83558) - Rich text: fix iOS double tap selection, preventing focus capture under editable host (WordPress/gutenberg#81042) - Block editor: migrate state-control badges to UI Badge (WordPress/gutenberg#82608) - Gallery: Add Order By controls for static gallery, consolidate controls in settings sidebar (WordPress/gutenberg#83438) - Media editor: show an error when saving attachment details fails (WordPress/gutenberg#83560) - Position controls: Fix useSelect warning for selected state viewports (WordPress/gutenberg#83570) - Inserter: Use design system focus ring for previews (WordPress/gutenberg#83126) - Image: Fix lightbox using thumbnail aspect ratio instead of original image ratio (WordPress/gutenberg#79058) - Docs: Clarify @wordpress/ui icon color requirements (WordPress/gutenberg#83564) - docker compose -T if stdin is not a tty (WordPress/gutenberg#78374) - Storybook: Add new contributing page. (WordPress/gutenberg#83345) - Widget Primitives: Avoid Vite warnings for runtime widget modules (WordPress/gutenberg#83602) - Build: Update Vite to 8.3.1 and simplify Storybook tooling (WordPress/gutenberg#83569) - doc(wp-env) Change core branch from trunk to master in doc (WordPress/gutenberg#83566) - wp-build: Remove the unused boot, private-apis, and route optional peer dependencies (WordPress/gutenberg#83601) - CI: Check CHANGELOG presence for published tooling and config packages (WordPress/gutenberg#83577) - Tests: Enforce Vitest assertion coverage (WordPress/gutenberg#83572) - Icons: Update heading level icons for optical balance (WordPress/gutenberg#83268) - ESLint: Add allowUseWithCaution option to use-recommended-components (WordPress/gutenberg#83536) - Notes: Refactor floating board measurement (WordPress/gutenberg#83485) - Inserter: Stop re-rendering the block list on block selection change (WordPress/gutenberg#83284) - Paste: Give each pasted data-URI image unique filename to avoid upload collisions. (WordPress/gutenberg#79480) - Changelog validator: ignore markdown & configs d46223 (WordPress/gutenberg#83618) - Font Library: Use UI Menu for collection actions (WordPress/gutenberg#82965) - Storybook: Show prop descriptions in Canvas controls (WordPress/gutenberg#83581) - test: Link upstream warning fixes in config (WordPress/gutenberg#83632) - Storybook: Use one block-editor store module (WordPress/gutenberg#83636) - Tests: Use strict assertions synced from Core changeset 63934. (WordPress/gutenberg#83619) - Math: Store cell alignment in the MathML and polyfill alignment and overlines in Chromium (WordPress/gutenberg#83164) - Storybook: Reuse PostCSS browser resolver in smoke tests (WordPress/gutenberg#83635) - Editor: Use UI Menu for template options (WordPress/gutenberg#82964) - RTC: Add a EntitySyncManager interface in core-data (WordPress/gutenberg#83410) - Term Count: Add margin support (WordPress/gutenberg#83608) - Archives: Add minimum height support (WordPress/gutenberg#83573) - Media Editor: Stop the crop pixel snap from recording undo history (WordPress/gutenberg#83571) - Term Name: Add margin support (WordPress/gutenberg#83606) - Post Author Biography: Add text indent support (WordPress/gutenberg#83614) - Code: Add minimum width and height support (WordPress/gutenberg#83574) - Details: Add minimum width support (WordPress/gutenberg#83576) - Post Content: Add minimum width support (WordPress/gutenberg#83575) - Post Excerpt: Add minimum width and height support (WordPress/gutenberg#83578) - Post Title: Add minimum width and height support (WordPress/gutenberg#83600) - Footnotes: Add minimum width and height support (WordPress/gutenberg#83579) - Storybook: Place Notice announcements under Components (WordPress/gutenberg#83617) - InputControl: Darken the field border on hover (WordPress/gutenberg#83306) - npm: Switch from legacy-peer-deps to strict-peer-deps (WordPress/gutenberg#81029) - Term Name: Add minimum width and height support (WordPress/gutenberg#83599) - Columns: Allow dropping a column at the outer edges (WordPress/gutenberg#83274) - E2E: Pin the site title in the Interactivity API router specs and give the E2E Storybook build more heap. (WordPress/gutenberg#83474) - Heading: Add minimum width and height support (WordPress/gutenberg#83580) - Login/out: Add minimum width and height support (WordPress/gutenberg#83583) - Verse: Add minimum width support (WordPress/gutenberg#83609) - Video, Cover: Don't autoplay in the editor when reduced motion is preferred (WordPress/gutenberg#83337) - Media & Text: Lower the specificity of the content padding (WordPress/gutenberg#83563) - Pagination: Add padding, margin, and block gap support (WordPress/gutenberg#83743) - Fix peer dependency conflicts left in the lockfile (WordPress/gutenberg#83754) - Comments Pagination: Add padding, margin, and block gap support (WordPress/gutenberg#83744) - Term Count: Add minimum width and height support (WordPress/gutenberg#83596) - Read More: Add border style support (WordPress/gutenberg#83735) - Cover: Don't autoplay embedded background videos when reduced motion is preferred (WordPress/gutenberg#83452) - No Results: Add minimum width and height support (WordPress/gutenberg#83584) - RichText: Rename utils.jsx to utils.js (WordPress/gutenberg#83758) - Quote: Add minimum width support (WordPress/gutenberg#83592) - Upgrade typescript-eslint to v8.70.1 (WordPress/gutenberg#83760) - Tabs: Add minimum width support (WordPress/gutenberg#83595) - Site Tagline: Add minimum width and height support (WordPress/gutenberg#83589) - Heading: Add text indent support (WordPress/gutenberg#83615) - Site Title: Add minimum width and height support (WordPress/gutenberg#83593) - Home Link: Add padding and margin support (WordPress/gutenberg#83607) - Preformatted: Add minimum width and height support (WordPress/gutenberg#83587) - Include E2E Storybook sources in docgen (WordPress/gutenberg#83634) - Extensible Site Editor: Pass custom block categories to the blocks store (WordPress/gutenberg#83762) - Packages: Declare missing peer dependencies and check them in CI (WordPress/gutenberg#83765) - Post Terms: Add minimum width and height support (WordPress/gutenberg#83586) - Group, Cover: Track drop zone element in state (WordPress/gutenberg#83756) - Global Styles: Add pseudo-state controls for Navigation Link (WordPress/gutenberg#83451) - storybook: Register playground core blocks once (WordPress/gutenberg#83637) - Document Outline: Show the design system focus ring instead of legacy box-shadow (WordPress/gutenberg#83755) - storybook: Update BlockPopover fixture to API version 3 (WordPress/gutenberg#83642) - Add typing to iAPI's getConfig() (WordPress/gutenberg#71692) - Components: deprecate Badge (WordPress/gutenberg#82379) - Block Editor: Fix style / nested attribute overwrite during multi-selection (WordPress/gutenberg#80070) - Notes: Restrict menu actions for resolution notes and resolved threads (WordPress/gutenberg#73243) - UI: Add change actions to form primitive stories (WordPress/gutenberg#83591) - Icons: Support keyword-based search in the icons registry (WordPress/gutenberg#82367) - Avatar: Explain that avatars use the Gravatar service (WordPress/gutenberg#83567) - UI: Add item labels and descriptions to remaining popups (WordPress/gutenberg#83493) - PaletteEdit: Stop changing the slug when renaming a preset (WordPress/gutenberg#83750) - Storybook: Fix missing block styles in BlockCanvas playground stories (WordPress/gutenberg#81070) - Tests: Enforce Vitest callback, promise, and title rules (WordPress/gutenberg#83620) - ItemGroup: Use design system focus ring (WordPress/gutenberg#83764) - Keep the legacy CheckboxControl visually consistent across viewports (WordPress/gutenberg#83612) - Media editor: Use UI Menu for crop aspect ratio (WordPress/gutenberg#82968) - Use strict assertions in override script tests (WordPress/gutenberg#83782) - Home Link: Add minimum width and height support (WordPress/gutenberg#83582) - Tab Panels: Add minimum height support (WordPress/gutenberg#83594) - Post Time to Read: Add minimum width and height support (WordPress/gutenberg#83598) - Term Description: Add minimum width and height support (WordPress/gutenberg#83597) - UI: Keep InputLayout chrome at md on small viewports (WordPress/gutenberg#82764) - Math: Add minimum width and height support (WordPress/gutenberg#83585) - Tests: Bump undici in the AI development test lockfile (WordPress/gutenberg#83799) - Bump brace-expansion in /test/ai-development (WordPress/gutenberg#83807) - Bump js-yaml and promptfoo in /test/ai-development (WordPress/gutenberg#83797) - Bump fast-uri from 3.1.7 to 3.1.8 (WordPress/gutenberg#83829) - Update AI Development package versions after npm audit (WordPress/gutenberg#83830) - Notes: Add show and hide options for floating notes (WordPress/gutenberg#83768) - Add separators to item popup components (WordPress/gutenberg#83776) - Components: Align RadioControl colors with UI Radio (WordPress/gutenberg#83270) - E2E: Mock Openverse in image drag-and-drop inserter test (WordPress/gutenberg#83842) - FormToggle: Match Switch colors across states (WordPress/gutenberg#83773) - Bump `@react-spring/web` from 9.4.5 to 10.1.2 (WordPress/gutenberg#83796) - ColorPalette: Show design system focus ring on custom color button (WordPress/gutenberg#83841) - Docs: Remove CheckboxControl heading from InspectorControls example (WordPress/gutenberg#83844) - Base Styles: Default the admin theme color to Blueberry (WordPress/gutenberg#83749) - Menu: Guard against nesting Group and RadioGroup (WordPress/gutenberg#83792) - Template Part: Fall back to rendering a template part from the theme file if the db version is unavailable (WordPress/gutenberg#83809) - Tests: Reset deprecation history in shared Vitest setup (WordPress/gutenberg#83849) - Menu: Disable triggers instead of roots in consumers (WordPress/gutenberg#83791) - Playlist: Replace the waveform player patch with its no-autoinit entry (WordPress/gutenberg#83132) - Update UI Spinner appearance and add a color prop (WordPress/gutenberg#83775) - UI: Align component names with their semantics (WordPress/gutenberg#83789) - Checkbox: Prevent rounded themes from making checkboxes circular (WordPress/gutenberg#83526) - Storybook: Update manifest snapshot for Spinner color prop (WordPress/gutenberg#83856) - Button: Only open the link popover on explicit user action (WordPress/gutenberg#30166) - Gallery Lightbox: Prevent image click from closing the dialog when navigation is enabled (WordPress/gutenberg#78898) - UI: Recommend Checkbox family components (WordPress/gutenberg#83771) - RadioControl: Keep a 16px visual with a larger hit target (WordPress/gutenberg#83840) - Table: replace deprecated word-break with overflow-wrap: anywhere (WordPress/gutenberg#82480) - Tag Cloud: Update styles and add `!important` (WordPress/gutenberg#70224) - Correctly document the `blockName` property as being nullable (WordPress/gutenberg#70900) - Add inertValue helper and use it for setting inert attribute (WordPress/gutenberg#83871) - Enable editableRoot for the list item block for multi-selection on mobile (WordPress/gutenberg#82816) - Verify localized data retention in override script test (WordPress/gutenberg#83845) - Tests: Bump ibm-cloud-sdk-core in the AI development test lockfile (WordPress/gutenberg#83887) - UI: Recommend Notice component (WordPress/gutenberg#82685) - Fix: MediaUpload `gallery` prop ignores `allowedTypes` (WordPress/gutenberg#78257) - Media editor: Add a session boundary above the cropper (WordPress/gutenberg#83550) - DataViews: Measure the container as the data view mounts to avoid a single column flash (WordPress/gutenberg#83752) - Pullquote: Add minimum width support (WordPress/gutenberg#83588) - Media editor: Remove initial state seeding from the session (WordPress/gutenberg#83893) - UI: Add e2e Storybook popup item layout fixtures (WordPress/gutenberg#83488) - Storybook: Give CI job a distinct name (WordPress/gutenberg#83869) - Coding standards: Skip anonymous class methods in block library function name sniff (WordPress/gutenberg#83900) - Pagination: Add border support (WordPress/gutenberg#83745) - PR meta: Move the props list into the shared comment (WordPress/gutenberg#82302) - Comments Pagination: Add border support (WordPress/gutenberg#83746) - Scripts: Resolve default configs without hoisted dependencies (WordPress/gutenberg#83902) - Image: Fix invalid CSS url() value in circle-mask style (WordPress/gutenberg#82333) - Query Total: Add minimum width and height support (WordPress/gutenberg#83590) - Scripts: Treat files passed after --fix as file arguments (WordPress/gutenberg#83521) - Editor: Remove icon for 'Export' more menu item (WordPress/gutenberg#83901) - Dashboard Widgets: let a mounted widget declare actions at runtime (WordPress/gutenberg#83877) - Framework: Switch from hoisted to isolated dependencies (WordPress/gutenberg#83847) - Test: Run Vitest type graph validation in process (WordPress/gutenberg#83851) - Remove use-memo-one usage (missing React 19 compat) (WordPress/gutenberg#83952) - Fix Post Featured Image crash when isLink is enabled (WordPress/gutenberg#81584) - Experiment: restyle classic wp-admin controls from design system tokens (WordPress/gutenberg#82425) - Tests: Lint JavaScript Vitest mock imports (WordPress/gutenberg#83783) - Build: Remove patch-package (WordPress/gutenberg#83982) - Docs: Update deprecation testing guidance for shared reset (WordPress/gutenberg#83989) - DataViews: list hideable fields alphabetically in the view config (WordPress/gutenberg#83947) - Core Data: Rank link suggestions by type, and stop discarding merged results (WordPress/gutenberg#83407) - Add new react-inert-value package with inertValue helper (WordPress/gutenberg#83987) - Connectors: Keep a stored API key read-only when it can't be verified (WordPress/gutenberg#83889) - Navigation: Search every entity type from the link UI (WordPress/gutenberg#83408) - Tests: Cover translation setup in override script tests (WordPress/gutenberg#83886) - Build: Update Vite to 8.3.2 and remove the PostCSS browser resolver (WordPress/gutenberg#83992) - Update readme title to match block name (WordPress/gutenberg#83999) - RTC: Fix undo breaking for non-synced entities (WordPress/gutenberg#83888) - CI: Cover the AI development lockfile with Dependabot instead of npm audit (WordPress/gutenberg#83997) - Latest Posts: Add minimum width and height support (WordPress/gutenberg#83905) - Avatar: Add shadow support (WordPress/gutenberg#83929) - Tab List: Add shadow support (WordPress/gutenberg#83922) - Buttons: Add minimum width and height support (WordPress/gutenberg#83894) - Social Icons: Add shadow support (WordPress/gutenberg#83920) - Columns: Add minimum width and height support (WordPress/gutenberg#83895) - Gallery: Add shadow support (WordPress/gutenberg#83919) - File: Add shadow support (WordPress/gutenberg#83918) - Page List: Add minimum width and height support (WordPress/gutenberg#83908) - Build Tooling: Read npm v12 pack --json output (WordPress/gutenberg#84011) - Accordion Heading: Add line height support (WordPress/gutenberg#83958) - Paragraph: Add shadow support (WordPress/gutenberg#83926) - Media & Text: Add minimum width and height support (WordPress/gutenberg#83906) - Tests: Patch basic-ftp in AI development dependencies (WordPress/gutenberg#84000) - Env, E2E: Update dependencies that ran native install scripts (WordPress/gutenberg#84012) - Tests: Update Vitest to 5.0.3 and Storybook to 10.6.1 (WordPress/gutenberg#83996) - Search: Add padding support (WordPress/gutenberg#83984) - Block editor: Honour background skip serialization in the editor (WordPress/gutenberg#83943) - Framework: Declare React types in the workspaces that use them (WordPress/gutenberg#84013) - Fit text: Size each block instance in a loop independently (WordPress/gutenberg#83985) - FocalPointPicker: end a drag released over the editor canvas (WordPress/gutenberg#83348) - Tests: Cover Menu scroll lock and LinkControl protocols in browsers (WordPress/gutenberg#83991) - List: Add shadow support (WordPress/gutenberg#83923) - UI: Add Progress with custom color support (WordPress/gutenberg#83781) - ESLint: Allow non-module stylesheet imports in unit tests (WordPress/gutenberg#84019) - Canvas loader: Use UI Progress and pass color via the indicator prop (WordPress/gutenberg#83860) - Menu: Align group labels and separators with indented item labels. (WordPress/gutenberg#83993) - react-inert-value: add missing types/react peer dep (WordPress/gutenberg#84024) - Docs: Refine design system agent guidance (WordPress/gutenberg#84007) - Navigation: List allowed blocks in the link UI search results + add transformSuggestions to Link Control (WordPress/gutenberg#83652) - Sync: Remove exposed wp.sync package (WordPress/gutenberg#81999) - Style: Update color to use CSS variable in edit-site (WordPress/gutenberg#79002) - Popover: drop the will-change hint once the popover stops moving (WordPress/gutenberg#77359) - MediaEdit: Show a checkerboard background behind image previews (WordPress/gutenberg#83846) - Quote: Add button colour support (WordPress/gutenberg#83983) - Media & Text: Add duotone support (WordPress/gutenberg#83981) - Gallery: Add duotone support (WordPress/gutenberg#83978) - Interactivity API Router: Add reactive navigation lifecycle and initiator API (WordPress/gutenberg#83280) - Notes: Move floating notes into a canvas margin (WordPress/gutenberg#83786) - Verse: Add text columns and indent support (WordPress/gutenberg#83962) - Notes: Scroll floating notes with the canvas (WordPress/gutenberg#83852) - Notes: Add Undo to deleted note snackbar (WordPress/gutenberg#83988) - Framework: Move @typescript/native from the root to the workspaces that use it (WordPress/gutenberg#84027) - Repair invalid peer dependencies in the lockfile (WordPress/gutenberg#84062) - Term Template: Add minimum width and height support (WordPress/gutenberg#83914) - Fix check type declarations (WordPress/gutenberg#84070) - Media: track the original attachment id for edited images (WordPress/gutenberg#81803) - Post Comments Form: Add font family support (WordPress/gutenberg#83967) - Media Utils: Add `MediaEdit` as a private API (WordPress/gutenberg#84046) - Build Tools: Fix flaky ESM package types test timeout (WordPress/gutenberg#84068) - Embed: Add padding support (WordPress/gutenberg#83963) - Interactivity API: Add a data-wp-html directive (WordPress/gutenberg#83092) - Typography and "block-default icon polish. (WordPress/gutenberg#84073) - Release Tooling: Read the npm v12 JSON output shapes (WordPress/gutenberg#84075) - Menu: Align submenu labels and highlight open parents (WordPress/gutenberg#84031) - Props Bot: Skip bare reviews that duplicate their review comment runs (WordPress/gutenberg#84076) - Dataviews: use inertValue in CompositeGrid (WordPress/gutenberg#84072) - UI: Add Meter (WordPress/gutenberg#83855) - Media & Text: Add shadow support (WordPress/gutenberg#83976) - Media editor: restore original image in modal (WordPress/gutenberg#81805) - List: Add background image, size, and gradient support (WordPress/gutenberg#83935) - List Item: Add background image, size, and gradient support (WordPress/gutenberg#83936) - Block Editor: Fix 'Manage allowed blocks' not shown when its the only 'Advanced' control (WordPress/gutenberg#84067) - Design System: Clarify tooltip labeling and UI review guidance (WordPress/gutenberg#83898) - Gallery: Add minimum width and height support (WordPress/gutenberg#83897) - File: Add minimum width and height support (WordPress/gutenberg#83896) - Media: Return 0 from the edit root lookup when there is no edit root (WordPress/gutenberg#84096) - Read More: Add minimum width and height support (WordPress/gutenberg#83912) - UI: Recommend Radio family components (WordPress/gutenberg#83872) - Latest Comments: Add minimum width and height support (WordPress/gutenberg#83904) - chore: Use v24 in .nvmrc (WordPress/gutenberg#84061) - Embed: Add minimum width and height support (WordPress/gutenberg#83903) - Post Comments Form: Add minimum width and height support (WordPress/gutenberg#83910) - Post Featured Image: Add border style support (WordPress/gutenberg#83956) - Buttons: Add shadow support (WordPress/gutenberg#83916) - Poetry: Add fit text support (WordPress/gutenberg#83980) - Video: Add duotone support (WordPress/gutenberg#83979) - Notes: Keep anchor writes out of undo history (WordPress/gutenberg#84079) - ProgressBar: Use WPDS color tokens (WordPress/gutenberg#83779) - REST API: Add action-trash link to posts and comments (WordPress/gutenberg#84045) - RSS: Add minimum width and height support (WordPress/gutenberg#83913) - Notes: Reset paragraph top margin in floating notes (WordPress/gutenberg#84101) - Global Styles: Fix popover position in Styles screen (WordPress/gutenberg#84048) - Block Switcher: Show design system focus ring on pattern previews (WordPress/gutenberg#83933) - MediaEdit: Use design system focus ring (WordPress/gutenberg#83854) - Notes: Delete permanently when the trash is disabled (WordPress/gutenberg#84102) - Release: Rewrite SVN publication scripts in Node.js (WordPress/gutenberg#84034) - ContentEditableControl: Keep a disabled field focusable (WordPress/gutenberg#84083) - States: Scope per-instance rules to the block's root element (WordPress/gutenberg#83986) - List Item: Add shadow support (WordPress/gutenberg#83925) - DataViews: Truncate filter chips instead of wrapping them (WordPress/gutenberg#83879) - Experiments: Turn the React 19 experiment on by default (WordPress/gutenberg#83784) - Notes: Extract NoteReply and lift AddNote gating (WordPress/gutenberg#84106) - Interactivity API: Remove expired deprecated behaviors (WordPress/gutenberg#84098) - Breadcrumbs: Fix typo in aria label translation context (WordPress/gutenberg#84112) - ESLint: Allow generated test titles (WordPress/gutenberg#83995) - Icons: Add keywords to icon manifest (WordPress/gutenberg#83884) - Tooltip: Control the hover delay cancellation test clock (WordPress/gutenberg#84113) - VS Code: Add managed workspace config (WordPress/gutenberg#84025) - Breadcrumb: fix getMeasurementRender for React 19 (WordPress/gutenberg#84069) - Notes: Fix flaky thread scroll e2e test (WordPress/gutenberg#84118) - Detect the database client in the unit test debug step. (WordPress/gutenberg#84089) - UI: Preserve Autocomplete item type inference (WordPress/gutenberg#84095) - UI: Recommend Switch family components (WordPress/gutenberg#84097) - Env: Add an option to choose the MariaDB version (WordPress/gutenberg#83751) - UI: Preserve Budugbox source item generics (WordPress/gutenberg#84094) - Menu: Tighten spacing, use 16px prefix icons, and cap width at 320px (WordPress/gutenberg#84028) - Notes: Preserve unsent note and reply drafts (WordPress/gutenberg#84110) - Theme: Add integration test coverage for seed colors in artifacts (WordPress/gutenberg#81161) - Progress: Migrate remaining ProgressBar usages and recommend UI Progress (WordPress/gutenberg#84021) - Components: Fix polymorphism typings leaking `as` prop (WordPress/gutenberg#82704) - Media & Text: Add background image, size, and gradient support (WordPress/gutenberg#83927) - Experiments: Use a mock plugin slug that no WordPress build ships in the unrelated-plugin test (WordPress/gutenberg#84133) - Button: Add background image, size, and gradient support (WordPress/gutenberg#83950) - Tests: Isolate Ajv per test in wp-env schema tests to avoid order dependence (WordPress/gutenberg#84139) - Storybook: Read icon keywords from the manifest (WordPress/gutenberg#84127) - SandBox: Fix embed previews that require a referrer in Safari (WordPress/gutenberg#84014) - Notes: Restore child notes trashed along with their parent note (WordPress/gutenberg#84100) - Style states: fix exception when there's no selected block (WordPress/gutenberg#84140) - Chore: Use v24.20 in `.nvmrc` config file. (WordPress/gutenberg#84138) - Security: Opt in to the npm v12 supply-chain defaults (WordPress/gutenberg#82689) - Docs: Describe isolated dependencies for agents and contributors (WordPress/gutenberg#84141) - Upgrade code and types to React 19 (WordPress/gutenberg#83941) - Latest Comments: Add border support (WordPress/gutenberg#84148) - Add prettier, eslint and stylelint to the root package.json (WordPress/gutenberg#84017) - FontSizePicker: Migrate Emotion styles to SCSS Modules (WordPress/gutenberg#84126) - Fields API: Add the server-side registry and REST route (WordPress/gutenberg#84078) - Block bindings: add support to `icon` attribute of `core/icon` (WordPress/gutenberg#80730) - VisuallyHidden: Move hiding styles outside CSS cascade layers (WordPress/gutenberg#84114) - Theme: Generate complete border token modes for Figma testing (WordPress/gutenberg#84035) - Developer tools: Simplify editor setup and add Zed settings (WordPress/gutenberg#84143) - Consolidate wp-admin container radiuses onto the design system scale (WordPress/gutenberg#82427) - CustomGradientPicker: Extend control point targets to the bar height (WordPress/gutenberg#84124) - Notes: Draw the canvas divider from body so it uses the theme text color (WordPress/gutenberg#84158) - Icons: Experiment with proportional stroke scaling (WordPress/gutenberg#84081) - Global Styles: Ignore theme.json values of unexpected types (WordPress/gutenberg#84523) - React 19 codemod: apply defaultProps when rendering a memo component (WordPress/gutenberg#84568) - React 19: add new incompatible plugins (WordPress/gutenberg#84607) - Tests: Fix HTML comparison tests (WordPress/gutenberg#84294) - Tests: Fix list item unsafe markup test on older WordPress versions (WordPress/gutenberg#84302) - Experiments: don't invalidate saved option with a legacy key (WordPress/gutenberg#84619) - Tests: Scope Classic block media checkbox locator (WordPress/gutenberg#84524) Props mamaduka. See #66340 Built from https://develop.svn.wordpress.org/trunk@64587 git-svn-id: http://core.svn.wordpress.org/trunk@63737 1a063a9b-81f0-0310-95a4-ce76da25c4cd
What?
Closes #80960
This gives blocks a supported way to answer two questions: "is a navigation happening right now?" and "which block started it?".
It is two new reactive keys on the existing
core/routerstore plus one optionalnavigate()option, all consumable with the existing primitives.state.navigatingis truthy while a client-side navigation is in flight, falsy otherwise. Before the first navigation (and on pages where the router never loads) it readsundefined, so consume it by truthiness, never=== false.state.initiatoris the current navigation's identity: a region id string, a declared string, ornullwhen there is no identifiable initiator. It is kept through the end so an end-watcher can still read who won, and it is overwritten at every next start.actions.navigate( url, { initiator } )lets any block declare its identity. A nonempty string always wins,nullexplicitly opts out, omitting it derives the id from the calling directive scope, and anything else warns underSCRIPT_DEBUGand resolves tonullwithout deriving.The per-region check becomes one line:
state.navigating && state.initiator === myRegionId. Two Query blocks on one page are distinguishable out of the box with no setup, because Query's pagination already navigates from its own scope.Why?
Today the router navigates silently. Besides
state.url, the only navigation state is the deprecatedstate.navigation.hasStarted/hasFinishedpair, which was never a lifecycle API: it exists for Core's loading bar, hides behind a 400 ms delay, only fires when the loading animation is on, latches after the first navigation, and knows nothing about back/forward restores, failures, or superseded navigations.How?
Start and end:
navigate()derives the initiator first, claims a token, and publishes one atomic start batch (navigating: trueplus initiator). Every path that resumes ends exactly once through a guardedfinallyscheduled on the router's ownafterNextFrame, re-checking the token inside the callback. That one-frame delay is deliberate: it letsdata-wp-watchand directive bindings observe fast cache hits that a microtask end would coalesce away. The end always lands after the new DOM is committed, so an end-watcher sees the new page and the newstate.url. The commit-to-end delay is intentionally unbounded so a future view-transition phase can settle there without breaking consumers.Coverage: every
navigate()that proceeds client-side (any call site, any options, same-URL included) and every back/forward restore served from the page cache produces a start and, unless superseded, an end. Mid-flight fallbacks to a full page load stay in-flight while the replacement is pending and are released by a bounded 10s timer if the document is never replaced, so an interactive page never sticks ontrue.prefetch()stays silent.Overlaps: latest wins, like the router already does. In-flight reads stay continuous from the first start to the winner's end,
initiatoralways shows the most recent navigation, superseded navigations publish no end of their own, and same-initiator supersession is invisible (no value changed, so no transition).Attribution: derived by default from the nearest enclosing
data-wp-router-region(self-inclusive), declared when you passinitiator, absent (null) for the full-page document listener, popstate, scope-less programmatic calls, and unwrappedwatch()callbacks.Two small fixes ride along because the feature needs them:
data-wp-router-regionvalues (plain,namespace::-prefixed, JSON object withid/attachTo, JSON scalar) are now interpreted once in@wordpress/interactivity(parseDirectiveValue, viaprivateApis()) and shared by the directive runtime, page preparation, and initiator derivation, so regions register, match, attach, and report under the same id; andwatch()now runs its callback with no ambient directive scope, so a barewatch()reacting to a store write derivesnullinstead of inheriting whoever triggered it, whiledata-wp-watchandwithScope()keep their scopes.Docs and tests: the Client-Side Navigation guide documents the lifecycle keys, timing, coverage, supersession, failures, initiator rules, and three recipes (per-block loader, region-scoped focus, debounced loading bar).
Testing Instructions
data-wp-router-region="query-0",query-1, and so on, note both values.startwithinitiator: "query-0", one or morein-flightlines with the same id, thenendstill carrying"query-0"; paginate the second block and confirm the same cycle with"query-1", proving per-instance attribution.in-flightthroughout, initiator switching to the newest block, exactly oneendfor the winner with no idle gap in the middle).start→endpair even though it completes almost instantly; press back/forward and confirm a normal cycle withinitiator: null, proving traversals are observable and distinguishable from block navigations.Use of AI Tools
This PR was substantially authored by AI coding agents working under human direction in a staged pipeline (spec, design, build, document, each with independent review), driven through OpenCode with a
gpt-luna + deepseekmodel set for implementation and planning and separate review models, plus human-authored amendments and manual review passes. Every behavior claim was verified against the shipped source by unit tests, browser e2e flows, and an independent document review; the human owner takes responsibility for the result. See the WordPress AI Guidelines: https://make.wordpress.org/ai/handbook/ai-guidelines/.