Skip to content

feat(lab): TabBar, iOS 26's floating tab bar, with its selection lens and press tracking - #9700

Merged
cixzhang merged 30 commits into
meta:mainfrom
vjeux:tabbar/lab-bar-lens
Nov 7, 2026
Merged

cixzhang merged 30 commits into
meta:mainfrom
vjeux:tabbar/lab-bar-lens

Conversation

@vjeux

@vjeux vjeux commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #9699 (on #9754). Review only this PR's change: vjeux/astryx@a236965...270f341

User need

Phone apps on Astryx need iOS 26's bottom tab bar: top-level sections in a floating capsule, with a lens that answers a finger as UIKit does.

Evidence

iOS: taps iOS: drag iOS: busy main thread iOS: Reduce Motion Android

From earlier drafts (iOS 26.2 simulator, Android emulator).

Problem and solution fit

Under a finger or a pen in the touch presentation the lens lifts into glass, follows a drag and settles on the tab nearest the lift on UIKit's springs while the bar flexes. Sliding off the bar or a second finger cancels. With no tab selected, a held finger paints its tab. Reselecting calls onReselect.

Desktop, before → after: a mouse or pen drag carried the lens and chose the tab under its release, and a held press painted its tab, fading on --duration-fast. Now a fine pointer's press is a plain button press: a click chooses its tab; a drag chooses and paints nothing.

Current specification

  • Lab: Lab is not shipped; no spec needed.
  • CLI: official-packages.json is regenerated, so astryx discover lists TabBar (spec:AST-051 FR11).

Decisions

  1. spec:AST-094 FR4: under touch, the lens plays UIKit's measured springs from uikitTabBar.ts. Specs decision, Nov 5 2026: gesture class per AST-094 FR45.
  2. spec:AST-017 FR60: the lens's copy of the items. Open until promotion: the moving lens adds 23 elements in the 4-tab Default story while it moves (none at rest); promotion must meet AST-017 FR60 or record an approved exception. Specs decision, Nov 3 2026.

Current records already decide: sliding off cancels (family:action-groups FR3), and the slide runs only in the touch presentation (DEC-1).

Core's useActionGroupTracking (#9699) owns the press; TabBar draws the lens.

Public delta and caller burden

New Lab exports TabBar and TabBarItem with their props types; panelId sets a tab's aria-controls:

<TabBar value={tab} onChange={setTab} onReselect={popToRoot} label="Sections">
  <TabBarItem value="home" label="Home" icon={<Icon icon={HomeIcon} />} />
</TabBar>

Design and alternatives

  • The lens runs on Core's motion engine on the compositor; a click slides it on a CSS transition. No move is state-change-only, so none uses createAnimator.
  • A finger's paint is a layer that appears at once. Only its opacity fades, on --duration-exit and --ease-exit, so the compositor runs the fade (spec:AST-094 FR5, card 47). Under Reduce Motion the fade stays within 200 ms (design:reduced-motion DR2).

Scope

  • One capability is added.
  • Unrelated fixes, cleanup, and policy changes were removed or split.
  • Consumer docs, focused tests, and migration evidence ship with the feature.
  • Public text and artifacts contain no internal Meta context.

Testing

Local gates at 270f341 (on #9699 a236965), node 24.22.1 from .nvmrc:

  1. Interaction specs, built Storybook: TabBar's, Chromium 49/49 and WebKit 40 passed, 9 skipped (Chromium-only evidence: CDP traces, scripted touch times, and a second finger, which Playwright's WebKit can't lift apart); AlertDialog's, 12/12 in each engine.
  2. Red-first, this push (2/2 in each engine): on 634a859 plus only the new case (f5d87b6), a finger's release ran a background-color transition on the item box, not an opacity fade on its layer.
  3. Same look: the lift fade's pixels on 634a859 and at this head differ by at most 1/255 per channel in each engine. Probes 0f0975c and db5cb7c freeze every animation at 0, 50, 100, 150 and 200 ms after the lift, with the theme's paint, a 300 ms exit, and a strong overlay whose fade spans about 110 levels.
  4. Red-first, earlier rulings (2/2 in each engine unless noted): on the previous head's build (be8f19a) a mouse press dragged from Library to Browse painted its tab, moved the lens and chose Browse; a pen drag chose its tab, and under a fine pointer the bar's element carried listeners (Chromium, CDP; controls: a planted probe listener, and the bar's own touchmove in the touch presentation). On a build without the exit-token change, with a 300 ms theme exit under Reduce Motion a finger's release read 125 ms (must be 200), and with a 90 ms exit the paint's duration and curve differed from the tokens.
  5. Red-first, earlier rounds: a second finger landing mid-drag let the lift choose Browse; after a finger's slide focus stayed on Home; a press the tab list ended moved focus at the lift; a finger lifted off the bar chose Library; past the bar's end the lift reselected; a release that reports twice made a click a reselect; with no tab selected a held finger painted nothing; panelId rendered no aria-controls (unit).
  6. Presentation switch: a switch to a fine pointer under a held finger lands the lens back and leaves no paint, which pins chore(core): Core's internal touch entry re-exports the action-group tracking hook, extended for Lab's TabBar, and a tab-bar string joins the catalog #9699's cancel when tracking turns off.
  7. Scene clock: the drag's chase law and the finger landing before the last lift run on the page freeze, at scripted instants, so a loaded runner can't change them.
  8. Unit and static: 81 unit tests (TabBar, its model, its UIKit table's sources, Lab's motion-engine hook, the CLI official list); Lab typecheck; strict ESLint on the changed files, 0 problems, and pnpm lint, 0 errors; Prettier; the CLI node suite, 335; review:pre.

Still owed before ready: the WebKit CI profile ×10 and the busy-main-thread proof ×10 at this head, and the feel check on a phone.

Batch: L1 · Lab: iOS chrome (TabBar, SearchField, NavigationStack, PageControl)

Size: 5,027 added lines, about half tests. Minimize through More follow in a second batch.

Supersedes #8129, #8141 and #8703.

Stack: #9699 → #9700
Merge group: #9699, #9700

#9701, TabBar's second Lab batch, also builds on this PR.

@vercel

vercel Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
astryx Ready Ready Preview Nov 7, 2026 1:45pm UTC

Request Review

@astracat-bot

astracat-bot Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

AI review status for this pull request.

Review status Updated
🟢 Reviewed (for maintainers only) Nov 7, 2026, 1:57 PM UTC

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Nov 3, 2026
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

🔎 Preview · 04ca7ba

Storybook · Sandbox · built from this PR's head

Modified components

Component Size LoC Visual · A11y · RTL
lab/TabBar 73.0 kB (new) · 1.8 kB CSS (new) — — · ✓ · ✗
lab/TabBarItem 3.8 kB (new) · 1.8 kB CSS (new) — — · ✓ · ✗
lab/CommentThread 317.3 kB (+92 B) · 2.4 kB CSS (0) — — · — · —
7 more components
Component Size LoC Visual · A11y · RTL
lab/Comments 322.2 kB (+85 B) · 2.5 kB CSS (0) — — · — · —
lab/Schedule 103.0 kB (+66 B) · 3.9 kB CSS (0) — — · — · —
ButtonGroup 40.6 kB (+62 B) · 3.7 kB CSS (0) — — · — · —
AlertDialog 103.1 kB (+58 B) · 14.2 kB CSS (0) — — · — · —
lab/NavigationStack 79.0 kB (+18 B) · 1.5 kB CSS (0) — — · — · —
lab/NavigationScreen 79.0 kB (+17 B) · 1.5 kB CSS (0) — — · — · —
lab/PageControl 72.3 kB (+13 B) · 709 B CSS (0) — — · — · —

Package size:

  • @astryxdesign/cli 3.49 MB packed (+15 B); no new dependencies
  • @astryxdesign/core 6.89 MB packed (+819 B); no new dependencies

API changes: none in this pull request

Committed API report behind this build: cli 19 rows, core 25 rows; run pnpm api:report.

Touched components checked; add ci:run-visual, ci:run-a11y or ci:run-rtl to run the full suites.


Generated by PR Enrichment workflow | View full report

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval waits on an engineering owner's spec decision, and three independent changes are needed either way.

This pull request also changes Core, the interaction harness, Storybook and CLI data, so current records bind TabBar as a family:action-groups member. An engineering owner needs to decide each of these departures, or update the records first:

  • Under a finger, a lift off the bar chooses the nearest tab, while family:action-groups FR3 says a lift outside the group acts on nothing.
  • The lens plays measured UIKit springs (and SearchField's bottom field plays measured frames) instead of motion roles, which spec:AST-094 FR4 forbids.
  • Under touch the moving lens mounts a copy of the items in a bar that is not a layer, beyond what spec:AST-017 FR60 allows.
  • A mouse or pen drag carries the lens, a new fine-pointer feel that spec:AST-017 FR59 says needs its own owner decision.

Required changes:

  • Retarget the pull request onto its parent so it carries only the TabBar commit; against main it also lands #9399, #9699 and #9698, 12,769 authored lines in all.
  • Drive the press tracking through Core's actionGroupTracker, re-exported from @astryxdesign/core/internal/touch as this change does for 14 other modules, instead of the recognizer and target resolution in useTabBarLens.ts.
  • Move @astryx.tabBar.more, @astryx.tabBar.cancelSearch and the matching changeset sentence to #9701, since nothing in this change reads them.

An engineering owner records the decision by commenting /approve-spec <full head SHA> on this pull request, and the author may do so if they are an engineering owner.

[Automated review]

Comment thread packages/core/locales/en.json Resolved
@vjeux
vjeux force-pushed the tabbar/lab-bar-lens branch from f277ee0 to ba1aaaf Compare November 3, 2026 07:42
@vjeux

vjeux commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

Round 1 is addressed in ba1aaaf, restacked on #9399's new head:

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval waits on an engineering owner's decision on two spec departures, and two independent changes are needed either way.

The press now runs through Core's action-group tracker, and a slide off the bar cancels under every pointer, so those earlier points are resolved. This pull request also changes Core, the interaction harness, Storybook and CLI data, so current records bind TabBar. An engineering owner needs to approve these departures, or update the records first:

  • The lens and the bar's flex play measured UIKit springs (and SearchField's bottom field plays measured frames) instead of motion roles, which spec:AST-094 FR4 forbids.
  • Under touch the moving lens mounts a copy of the items in a bar that is not a layer, beyond what spec:AST-017 FR60 allows.

Required changes:

  • Land #9399, #9699 and #9698 first so this pull request carries only TabBar's commit, since against main it is 13,527 authored lines, including Core re-exports and two catalog strings nothing here reads.
  • Delete the Effect at useTabBarLens.ts:684, because the tracker it disposes holds no timer, attribute or listener, so it synchronizes nothing (architecture:react-component-runtime INV3).

An engineering owner records the decision by commenting /approve-spec <full head SHA> on this pull request, and the author may do so as an engineering owner.

[Automated review]

Comment thread packages/lab/src/TabBar/TabBarTouch.ts Resolved
@vjeux
vjeux force-pushed the tabbar/lab-bar-lens branch from ba1aaaf to a7d0520 Compare November 3, 2026 09:06
@vjeux

vjeux commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

Round 2 is addressed in a7d0520. The no-op dispose Effect is gone, and the stale mouse-drag comments and the test's record citation are fixed. The two spec departures (FR4's measured springs, FR60's lens copy) are open cards with the engineering owner. The stack point stands until #9399, #9699 and #9698 land; until then, the body's compare link shows this PR's own commit.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval waits on an engineering owner's decision on two spec departures, and one independent change is needed either way.

This pull request also changes Core, the interaction harness, Storybook and CLI data, so current records bind TabBar and SearchField; an engineering owner needs to approve these departures or update the records first:

  • The lens and the bar's flex play measured UIKit springs, and SearchField plays a measured 383.3 ms activation clock and frame tables, instead of motion roles, which spec:AST-094 FR4 forbids.
  • Under touch the moving lens mounts a copy of the items in a bar that is not a layer, 23 extra elements in the Default story where the description counts 18, beyond what spec:AST-017 FR60 allows without an owner exception.

Required change:

  • Land #9399, #9699 and #9698 first so this pull request carries only TabBar's commit, since against main it is 13,525 authored lines, above the 8,000-line owner-directed batch ceiling, including Core re-exports and two catalog strings nothing here reads.

An engineering owner records the decision by commenting /approve-spec <full head SHA> on this pull request, and the author may do so as an engineering owner.

[Automated review]

Comment thread packages/core/locales/en.json Resolved
Comment thread packages/core/src/internal/touch.ts Resolved
@vjeux
vjeux force-pushed the tabbar/lab-bar-lens branch from a7d0520 to 6f87bcd Compare November 3, 2026 11:10
@vjeux

vjeux commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

Round 3 is addressed in 6f87bcd, restacked on #9399's head 7b86fe2 and #9698's approved head:

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval waits on an engineering owner's decision on two spec departures, and one independent change is needed either way.

This pull request also changes Core, the interaction harness, Storybook and CLI data, so current records bind TabBar and SearchField at this head; an engineering owner needs to approve these departures or update the records first:

  • The lens and the bar's flex play measured UIKit springs, and SearchField plays a measured 383.3 ms activation clock and frame tables, instead of motion roles, which spec:AST-094 FR4 forbids.
  • Under touch the moving lens mounts a copy of the items in a bar that is not a layer, 23 extra elements in the Default story (52 in the tablist against 29 at rest), beyond what spec:AST-017 FR60 allows without an owner exception.

Required change:

  • Land #9399, #9699 and #9698 first so this pull request carries only TabBar's commit, since against main it is 13,760 authored lines, above the 8,000-line owner-directed batch ceiling, including Core re-exports and two catalog strings nothing here reads.

The mouse click is now pinned to a single report, and the restating comments are gone. An engineering owner records the decision by commenting /approve-spec <full head SHA> on this pull request, and the author may do so as an engineering owner.

[Automated review]

Comment thread packages/lab/src/TabBar/TabBar.tsx Resolved
@vjeux
vjeux force-pushed the tabbar/lab-bar-lens branch from 6f87bcd to 81ca5e6 Compare November 3, 2026 15:32
@vjeux

vjeux commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

Restacked on #9699 over #9754, since #9399 won't merge, so SearchField is gone from this diff. The lens now uses Core's renamed internal motion engine (createMotionEngine, useMotionEngine). No move here is state-change-only, so none uses the public createAnimator. The body notes what is open until promotion: tap moves play the theme's motion tokens, and only gesture-driven motion springs from velocity.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval waits on an engineering owner's decision on two spec departures, and two independent changes are needed either way.

This pull request also changes Core, a Storybook story and CLI data, so current records bind TabBar at this head. An engineering owner needs to approve these departures or update the records first:

  • The lens and the bar's flex play measured UIKit springs instead of motion roles, which spec:AST-094 FR4 forbids.
  • Under touch the moving lens mounts a copy of the items in a bar that is not a layer, beyond what spec:AST-017 FR60 allows without an owner exception with before and after counts.

Required changes:

  • A second finger landing during a press must end it with nothing chosen (family:action-groups FR3), which Core's useActionGroupTracking already does, so route TabBar's press through that hook, extended for the lens, instead of its own long-press recognizer.
  • Move @astryx.tabBar.more, @astryx.tabBar.cancelSearch and the internal re-exports nothing here reads to #9701, which also lets the owner-directed batch cover this pull request's size.

The long comment above TabBar is still to be trimmed to its reasons (non-blocking). An engineering owner records the decision by commenting /approve-spec <full head SHA> on this pull request, and the author may do so as an engineering owner.

[Automated review]

Comment thread packages/core/locales/en.json Resolved
Comment thread packages/lab/src/TabBar/TabBar.tsx Resolved
@cixzhang

cixzhang commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

/approve-spec b416f9f

@cixzhang

cixzhang commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

/approve-spec ec8e3a4

@astracat-bot astracat-bot Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved pending CI: the required test check failed only because the Chromium interaction leg 2/2 reached CI's 15-minute job limit with no test failing, just as TabBar's spec began, so a re-run of that job is the next step. That leg already took about 14.5 minutes at an earlier head, and TabBar's spec adds about a minute and a half to it, so it may need splitting.

#9754: approved. It has landed.

#9699: approved. An engineering owner approved this head. Merging main left its own lines unchanged, and AlertDialog and ButtonGroup keep their defaults.

#9700: approved. An engineering owner's /approve-spec for this head covers TabBar's measured springs, its touch lens copy and its missing component record, and no blocking finding remains. Three non-blocking test notes stay open: a stale test title (TabBar.interaction.browser.spec.ts:1043), a stale file header (tabBarModel.test.ts:8), and a copied pointer helper in TabBar.test.tsx that Lab's own test helpers now provide.

Stack: the stack passes as a whole. A pull request lands only when it and every pull request below it are approved.

[Automated review]

@cixzhang

cixzhang commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

/approve-spec f9b11ba

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved: an engineering owner approved this head, CI passes, and no blocking finding remains.

#9754: approved. It has landed.

#9699: approved. An engineering owner approved its new head; merging main left its own lines unchanged, and AlertDialog and ButtonGroup keep their defaults.

#9700: approved. An engineering owner's /approve-spec for this head covers TabBar's measured springs, its touch lens copy and its missing component record. Three non-blocking test notes stay open:

  • TabBar.interaction.browser.spec.ts:1043: the title's tie parenthetical points at a case tabBarModel.test.ts no longer has.
  • tabBarModel.test.ts:8: the header still lists "the item a lift commits", which the file no longer tests.
  • TabBar.test.tsx:69-92: the copied coarsePrimaryPointer can import Lab's own test helper (packages/lab/src/internal/__tests__/coarsePointer.ts) instead.

Stack: the stack passes as a whole. A pull request lands only when it and every pull request below it are approved.

[Automated review]

@cixzhang

cixzhang commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

/approve-spec 92b3acb

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Waiting on an engineering owner: TabBar's departures from current records need an owner decision at this head, and no blocking defect remains in the stack.

#9754: approved. It has landed.

#9699: approved. An engineering owner approved its new head; merging main left its own lines unchanged apart from one resolved import-path conflict in Core's internal touch entry.

#9700: waiting on an owner decision. Its own patch is unchanged, but the last owner approval names the previous head, so these departures need an engineering owner's decision again, or TabBar must conform, or the records must change first:

  • Under touch, the lens and the bar's flex play UIKit's measured springs from uikitTabBar.ts, key- and app-driven slides included, instead of motion roles (spec:AST-094 FR4).
  • Under touch, the moving lens mounts a copy of the items in a bar that is not a layer (spec:AST-017 FR60).
  • TabBar has no component record, so nothing current settles its behavior, including the badged tab's spoken name.

An engineering owner records the decision by commenting /approve-spec 92b3acbefc3747e8c3be5ce5733a1677aae0c82f on this pull request, and the author, as an engineering owner, may do so. Four non-blocking notes (a 47-line JSDoc on useTabBarLens, two stale test details and a duplicated test helper) are in the review.

Stack: no blocking finding across the stack; CI's one failure (test-node (3/4), the WebKit routing test) comes from main, not this stack. A pull request lands only when it and every pull request below it are approved.

[Automated review]

Comment on lines +134 to +180
/**
* WHAT MOVES (uikitTabBar.ts, all measured on iOS 26.2)
*
* The lens is a CSS resting place over the selected item (TabBar.tsx) with a
* body inside it that this hook moves. `x` is its offset from the resting
* place, `scaleX` / `scaleY` its lift, and its `::before` the shadow that fades
* in as it lifts. Inside the body, a clip holds the selected copy of the items
* while the lens moves. The clip's background is the opaque fill, and its
* `::before` is the glass that fades in as the lens lifts. The copy is
* counter-transformed so the items stay put while the lens moves over them. Its
* curves derive from the body's (tabBarModel's `copyTransform`). Each copied
* item grows by the lift's magnification about its own centre. The copy mounts
* when a finger lands or a slide starts and goes once everything rests. At rest
* the selected tab draws its own look (TabBar.tsx).
*
* Under a finger or a pen in the touch presentation, iOS and Android alike.
* The press is a long press with no delay, so it begins on the touch, as
* UIKit's selection tracker does:
* - landing: the lens travels toward the finger (`lensTravel`) and lifts
* (`lift`: outset, glass, magnification), and the capsule flexes
* (`flexPress`);
* - dragging (past the long press's allowable movement): the lens chases the
* finger (`lensTrack`), rubber-banded past the first and last items;
* - lifting: the item nearest the finger is chosen, the lens settles onto it
* (`lensSettle`), the lift and the flex relax (`lift`, `flexRelease`). A
* cancelled touch settles back onto the selected item.
* - off the bar: the lens shows the selected item again, and a lift there
* chooses nothing. Sliding off cancels.
* The choice reaches the app (`onLift`) from the lift itself, right after the
* settle has started in the same task. The settle's first frame waits for the
* browser's commit, so the app rendering the new tab delays its start rather
* than freezing it midway. The report renders synchronously, and if the app
* keeps the old selection the lens settles back onto it. The finger is read in
* the capsule's own coordinates, before its flex scale, as UIKit reads it.
* Under the flex the lens drifts slightly away from the finger toward the ends,
* as on iOS.
*
* A selection change slides the body from where the lens was on screen to its
* new resting place. On `lensTravel` from rest (a key, the app), or continuing
* the settle a lift started. Every animation runs on the compositor; a finger's
* moves retarget them, so the lens keeps moving through a busy main thread.
* Under Reduce Motion the animator cross-fades instead of moving and a press
* scales nothing. Each spring plays as measured, from the UIKit table.
*
* Under a fine pointer nothing here runs. A press there is a plain button
* press: its click chooses the tab, and TabBar's CSS slides the lens.
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Miss, non-blocking (INV29): this JSDoc runs 47 lines and repeats the lens description in TabBar.tsx and uikitTabBar.ts's header. Keep the contract (what each ref drives, and that nothing runs under a fine pointer) and leave the spring list to uikitTabBar.ts.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved: no blocking finding remains in the stack.

#9754: approved. It has landed.

#9699: approved. An engineering owner approved its current head.

#9700: approved. An engineering owner's approval for this head covers TabBar's measured springs, its touch lens copy and its missing component record; four non-blocking notes (a 47-line JSDoc on useTabBarLens, two stale test details and a duplicated test helper) are in the review.

Stack: passes. CI's one failure, the WebKit routing test in test-node (3/4), comes from main, not this stack, and a pull request lands only when it and every pull request below it are approved.

[Automated review]

@cixzhang
cixzhang marked this pull request as draft November 7, 2026 08:55
@cixzhang
cixzhang marked this pull request as ready for review November 7, 2026 08:55
@cixzhang

cixzhang commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

/approve-spec c7adb12

@astracat-bot astracat-bot Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes requested: one blocking finding in #9700; the pull requests below it are approved.

#9754: approved. It has landed.

#9699: approved. An engineering owner approved its current head, and it has no blocking finding.

#9700: changes requested. An engineering owner's approval for this head covers TabBar's measured springs, its touch lens copy and its missing component record.

  • Regression: merging main brought in the interaction harness's required judges option, and TabBar.interaction.browser.spec.ts still calls holdAnimations(page) at lines 402, 812 and 937 and animationStoryboard without judges at line 2070, so CI's typecheck, build and test checks fail; name the motion each hold judges, for example {judges: {target: lensBody(page), property: 'translate'}}.

Four non-blocking notes (a 47-line JSDoc on useTabBarLens, two stale test details and a duplicated test helper) are in the review.

Stack: fails at this head on the finding above; a pull request lands only when it and every pull request below it are approved.

[Automated review]

Main's interaction harness now requires every hold sent from a test
to name the motion it judges. Each TabBar case names what it samples
after the hold:
- the keyed slide: the lens body's and the lens copy's translate;
- the finger landing: the capsule's scale, the lens body's scale and
  translate, and the lens clip's ::before opacity;
- the lift: the capsule's and the lens body's scale;
- the selection storyboard: the lens body's translate.
@cixzhang

cixzhang commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

/approve-spec a309756

@astracat-bot astracat-bot Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved: every pull request in this stack is approved at its current head.

#9754: approved. It has landed.

#9699: approved. An engineering owner approved its current head, and it has no blocking finding.

#9700: approved. An engineering owner's approval for this head covers TabBar's measured springs, its touch lens copy and its missing component record, and CI passes at this head.

Four non-blocking notes stand in the review: a 47-line JSDoc on useTabBarLens, two stale test details and a duplicated test helper.

Stack: passes at this head; a pull request lands only when it and every pull request below it are approved.

[Automated review]

@cixzhang

cixzhang commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

/approve-spec 04ca7ba

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved: every pull request in this stack is approved at its current head, and CI passes.

#9699: approved. An engineering owner approved its current head, and it has no blocking finding.

#9700: approved. An engineering owner's approval for this head covers TabBar's measured springs, its touch lens copy and its missing component record, and TabBar's interaction cases pass in Chromium and WebKit at this head.

Four non-blocking notes stand in the review: a 47-line JSDoc on useTabBarLens, two stale test details and a duplicated test helper.

Stack: passes at this head; a pull request lands only when it and every pull request below it are approved.

[Automated review]

@cixzhang
cixzhang merged commit c18bc58 into meta:main Nov 7, 2026
74 checks passed
@vjeux
vjeux deleted the tabbar/lab-bar-lens branch November 7, 2026 14:38

This branch was successfully deployed

1 active deployment
Preview — 04ca7ba6 Deployed Nov 7, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:run A maintainer lets this outside contributor's pull request run CI (AST-030 FR17) CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants