Repository navigation
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
PR Analysis Report
Component Size
Sizes are gzip. Import counts the JavaScript the import loads eagerly; CSS counts the package stylesheet rules referenced by the modules it can load from its own package, lazily loaded ones included. Bundle Size SummaryGzip figures measure each package's entry file, not the code an import pulls in.
Accessibility AuditStatus: No accessibility violations detected. Visual Regression55 of 502 shot(s) changed. A change here is a question, not a failure: check whether the after is the
and 35 more. Generated by PR Enrichment workflow | View full report |
There was a problem hiding this comment.
This pull request needs an owner decision before it can be approved. No current spec governs the lab TabBar, and the PR marks the More tab API (moreValue, TabBarMoreList) as proposed and pending owner review; the same is true of the draft AST-094 that the stack adds. An engineering owner can record the decision by commenting /approve-spec <full head SHA> on this pull request (the author can do this as an engineering owner), or by naming the spec that governs the More tab. Whatever that decision is, these changes are still needed:
- Rebase onto
mainonce #8210 and its predecessors land, so this PR carries only the More commit instead of about 32,000 authored lines. - Keep
presentation="adaptive"on its(max-width: 768px) and (pointer: coarse)query until the Selector spec's DEC-1 is amended, because the new query changes stable Selector, MultiSelector and menu behavior on landscape phones in a patch release. - With a search tab, a section opened inside More leaves Home in the search circle and tapping it returns to Home, so map the remembered overflow value to More (
TabBar.tsx, around line 915). - Badges on tabs past the fourth are not shown anywhere, so render them in the
TabBarMoreListrows or document the limit.
[Automated review]
| const previousIndex = items.findIndex( | ||
| item => item.value === previousValueRef.current, | ||
| ); |
There was a problem hiding this comment.
With more than five tabs, previousValueRef can hold an overflow value ('settings'), which items.findIndex cannot find among the five shown items. shownIndex then falls back to index 0, so while searching the circle shows and returns to the first tab instead of More. Mapping an overflow value onto MAX_TABS - 1, as selectedIndex already does, would keep More.
| {overflowItems(children).map(item => ( | ||
| <ListItem | ||
| key={item.value} | ||
| label={item.label} | ||
| startContent={item.icon} | ||
| endContent={<Icon icon="chevronRight" />} | ||
| isSelected={item.value === value} | ||
| isDisabled={item.isDisabled} | ||
| onClick={() => onChoose(item.value)} | ||
| /> | ||
| ))} |
There was a problem hiding this comment.
A badge (and badgeLabel) on a tab past the fourth is rendered neither here nor in the bar, so the count disappears for everyone. Consider showing it in the row's end content beside the chevron, or documenting that tabs in More show no badge.
| // and large touch displays stay anchored, phones in either orientation get | ||
| // the sheet. The query is the shared touch presentation's | ||
| // (utils/touchPresentation.ts). | ||
| export const COMPACT_TOUCH_PRESENTATION_QUERY = COMPACT_TOUCH_QUERY; |
There was a problem hiding this comment.
This changes presentation="adaptive" for stable Selector (its default), MultiSelector, DropdownMenu, ContextMenu and MoreMenu: a landscape phone over 768 px wide now gets the sheet, and a 744–768 px touch screen gets the popover. The Selector spec's DEC-1 says adaptive "keeps its width-and-pointer query", so this needs that record amended (or the old query kept here) before it ships in a patch.
bdda8db to
5a1660e
Compare
There was a problem hiding this comment.
This pull request needs an engineering owner's decision before it can be approved: no current spec governs the lab TabBar's More tab (moreValue, TabBarMoreList), which the PR marks as proposed and pending owner review, and the draft AST-094 that the stack adds is unapproved. An engineering owner can record that decision by commenting /approve-spec <full head SHA> on this pull request (the author may do so as an engineering owner), or by naming the spec that governs the More tab. Whatever that decision is, these changes are still needed:
- Rebase onto
mainonce #8210 and its predecessors land, so this pull request carries only the More commit instead of about 32,600 authored lines. - Keep
presentation="adaptive"on its(max-width: 768px) and (pointer: coarse)query until the Selector spec's DEC-1 is amended, because the new query turns the popover into a modal sheet on phones in landscape wider than 768 px and changes sub-menus in a patch release. - With a search tab, a section opened inside More leaves Home in the search circle and tapping it opens Home, so map the remembered overflow value to More (
TabBar.tsx, around line 915). - Badges on tabs past the fourth are not shown anywhere, so render them in the
TabBarMoreListrows or document the limit.
[Automated review]
…-touch-model restack)
…-touch-model restack)
5a1660e to
c36f020
Compare
c36f020 to
d2b777b
Compare
There was a problem hiding this comment.
This pull request needs an engineering owner's decision before it can be approved: no current spec governs the lab TabBar's More tab (moreValue, TabBarMoreList), which the PR marks as proposed and pending owner review, the stacked isRtlElement, reducedMotion.stylex and useFingerScroll additions carry the same marker, and the draft AST-094 the stack adds is unapproved. An engineering owner can record that decision by commenting /approve-spec <full head SHA> on this pull request (the author may do so if they are an engineering owner), or by naming the specs that govern these surfaces. Whatever that decision is, these changes are still needed:
- Rebase onto
mainonce #8210 and its predecessors land, so this pull request carries only the More commit instead of about 42,600 authored lines. - Keep the new selection and callout lock off stable
usePressFeedbacksurfaces (pressFeedback.ts), since it changes stable touch behavior, including the iOS long-press callout on links, under an[experimental]patch changeset. - When the bar mounts on its search tab, the leading circle named "Home" does nothing; fall back to the shown tab when no tab has been chosen (
TabBar.tsx, around line 1034). - Under Reduce Motion the selection lens shows the first tab's icon and label in the chosen slot, More included; land the lens copy at rest (
useTabBarLens.ts, around line 686). presentation="adaptive"keeps 768 px when a theme overridesmd; read the theme's breakpoints or say so in the changeset.
[Automated review]
| const chooseCircle = () => { | ||
| if (isSearchSelected) { | ||
| // Back to the tab search was chosen from (a section inside More, too). | ||
| if (lastTabValue != null) { |
There was a problem hiding this comment.
When the bar mounts on its search tab, lastTabValue is still null, so the circle (named "Home", showing Home's icon) does nothing when tapped; before this change it chose the shown tab. Falling back to the shown item when no tab has been chosen keeps it working, for example choose(lastTabValue != null ? (allItems.find(item => item.value === lastTabValue) ?? {value: lastTabValue}) : selectedItem), which also keeps the remembered tab's isDisabled.
| @@ -283,6 +301,9 @@ function onPointerDown(event: PointerEvent): void { | |||
| gesture: idlePressGesture(), | |||
| pointerId: event.pointerId, | |||
| timer: null, | |||
| // A held finger never starts text selection on the surface (UIKit's | |||
| // controls and cells never do), on any coarse pointer. | |||
| unlock: lockSelection([element], event.target), | |||
There was a problem hiding this comment.
This takes the selection and callout lock on every stable usePressFeedback surface under a finger or pen (Button, Link, Item and the rest): text selection is off while the finger is held, and on iOS a long press on a stable Link no longer gets the system link callout (-webkit-touch-callout: none). That changes stable behavior in a patch under an [experimental] changeset; keeping the lock to the experimental recognizers and press trackers avoids it.
| }, | ||
| {at: now, touchRelease: fromLift}, | ||
| ); | ||
| playCopy(now); |
There was a problem hiding this comment.
Under Reduce Motion with a finger, the body's touchRelease call lands with a plain write, but the copy's curve derived here keeps its starting offset (translate: 274.169px after a tap on More, in Chromium), so the lens shows the first tab's face in the chosen slot. Setting the copy to its rest transform when body.animator.reducedMotion({touchRelease}) is not 'off' fixes it; the Reduce Motion interaction test could also assert which copy item sits in the lens.
| export const COMPACT_QUERY = DEFAULT_COMPACT_DEFINITION.query; | ||
|
|
||
| /** Both: presentations such as a sheet in place of a popover. */ | ||
| export const COMPACT_TOUCH_QUERY = |
There was a problem hiding this comment.
COMPACT_TOUCH_QUERY is built from the default compact definition, so presentation="adaptive" keeps 768 px when a theme overrides md, while AST-012 FR9 defines compact by the effective md and the changeset says the rule follows "the theme's md point". Reading the nearest theme's breakpoints with compactDefinition(points), or saying in the changeset that the default applies for now, would close the gap.
d2b777b to
70e5e44
Compare
… spring from rest The turn used to come after the page settled, when the accessory had almost stopped, so a carried and a dropped velocity looked alike. The drag now ends at rest and the circle is tapped at once, and the first frame back is compared with the expand spring from rest.
Holding every animation made the earliest one the sampling origin; when the bar's other layers started a frame before the field, the samples ran ahead of the spring by about half a pixel in WebKit.
The chevron sits beside the row's label button, not inside it.
…rt times The expand's first frame is checked against the expand spring started from the offset the accessory turns from, with the speed the collapse had at the turn. The turn's moment is the two animations' start times apart, so a late tap (a loaded box) moves the prediction with it instead of failing the case.
There was a problem hiding this comment.
Approval of this pull request waits on an engineering owner's decision: no current spec governs the lab TabBar's More tab (moreValue, the first-four-plus-More layout, the reselect rule and TabBarMoreList), which the pull request itself says needs an owner's decision. An engineering owner can record that decision by commenting /approve-spec <full head SHA> on this pull request (the author may do so as an engineering owner), or by naming the record that governs the More tab. Whatever that decision is, these changes are still needed:
- Land #8210 and its predecessors and rebase, so this pull request carries only the More layer instead of about 37,300 authored lines.
- Make the gesture host attach for every pointer, as AST-094 FR19 and FR43 and the runtime architecture's INV13 now require, instead of only where the primary pointer is coarse.
- Bring the tab bar in line with the action-groups family it joins by membership: a lift outside the bar acts on nothing (FR3) and a mouse or pen slide across the tabs is tracked (FR5), or have an engineering owner amend the family for the tab bar.
[Automated review]
| * ONLY WHERE THE PRIMARY POINTER IS COARSE | ||
| * | ||
| * - Recognizers attach, and the host registers listeners, only while the | ||
| * primary pointer is coarse (`spec:AST-094` FR19, FR24; coarsePointer.ts). | ||
| * Where it is fine, an attach is recorded but nothing is installed: no | ||
| * document, window or element listener, no `touch-action` or other style, | ||
| * nothing delivered, so a finger on a touchscreen laptop gets the | ||
| * browser's defaults. The host follows the query: turning coarse installs | ||
| * it and styles every registration; turning fine cancels every touch in | ||
| * flight and removes it all. A development warning names the first attach | ||
| * under a fine pointer. |
There was a problem hiding this comment.
Current spec:AST-094 FR19 now reads "Recognizers attach for every pointer, with FR43's exceptions", FR43 "Gestures attach for every pointer, a mouse, a pen, and a finger, not only a coarse primary pointer" (DEC-21 rejects keeping gestures touch-only), and architecture:react-component-runtime INV13 "The gesture host attaches for every pointer, with no touch-only query". This header cites FR19 for the opposite. Attach for every pointer with FR43's listed exceptions, keeping FR24's fine-pointer budget.
| * - The lift commits the item whose centre is nearest the finger (ties go to | ||
| * the leading item, no projection, and leaving the bar does not cancel); |
There was a problem hiding this comment.
A tab bar joins family:action-groups by its membership rule, whose FR3 says "A press that lifts outside the group acts on nothing"; here a lift outside the bar still commits (the browser test "a drag that leaves the bar upward still commits where it lifts"). FR5 also asks a mouse or pen slide to be tracked, while the bar treats a mouse as a plain click. Follow the family, or have an engineering owner amend it for the tab bar.
…arch field covers it Under a finger the active field spans the bar's row over the leading circle, which kept its tab stop and its name. It is inert while the field is active there, with a browser test (red first: the covered circle took focus).
The Effect that ends a press when the recognizer turns off, and the one that ends it when the tab list changes under a finger, now say what they synchronize, as the selection Effect does.
While the bar is collapsed its tabs are inert, so focus never lands on a tab: keyboard focus reaches the circle, whose activation expands the bar. The prop doc, the component doc and the hook said focus on a tab expands it.
…tree (AST-085 FR5) Reads Chromium's accessibility tree: the disabled tab keeps its name and is announced disabled on the tab itself; no other tab is.
There was a problem hiding this comment.
Approval of this pull request waits on an engineering owner's decision: no current spec governs the lab TabBar's More tab (moreValue, the first-four-plus-More layout, the reselect rule and TabBarMoreList), which the pull request itself says needs an owner's decision. An engineering owner can record that decision by commenting /approve-spec <full head SHA> on this pull request (the author may do so as an engineering owner), or by naming the record that governs the More tab. The newest change, which takes the covered leading circle out of the tab order, needs nothing further, but these changes are still needed whatever that decision is:
- Land #8210 and its predecessors and rebase, so this pull request carries only the More layer instead of about 37,400 authored lines.
- Make the gesture host attach for every pointer, as AST-094 FR19 and FR43 and the runtime architecture's INV13 require, instead of only where the primary pointer is coarse.
- Bring the tab bar in line with the action-groups family it joins by membership: a lift outside the bar acts on nothing (FR3) and a mouse or pen slide across the tabs is tracked (FR5), or have an engineering owner amend the family for the tab bar.
[Automated review]
There was a problem hiding this comment.
Approval of this pull request waits on an engineering owner's decision: no current spec governs the lab TabBar's More tab (moreValue, the first-four-plus-More layout, the reselect rule and TabBarMoreList), which the pull request itself says needs an owner's decision. An engineering owner can record that decision by commenting /approve-spec <full head SHA> on this pull request (the author may do so as an engineering owner), or by naming the record that governs the More tab. The newest change, which makes two Effect comments name what they synchronize and adds a disabled-tab accessibility-tree test, needs nothing further, but these changes are still needed whatever that decision is:
- Land #8210 and its predecessors and rebase, so this pull request carries only the More layer instead of about 37,400 authored lines.
- Make the gesture host attach for every pointer, as AST-094 FR19 and FR43 and the runtime architecture's INV13 require, instead of only where the primary pointer is coarse.
- Bring the tab bar in line with the action-groups family it joins by membership: a lift outside the bar acts on nothing (FR3) and a mouse or pen slide across the tabs is tracked (FR5), or have an engineering owner amend the family for the tab bar.
[Automated review]
Depends on #8210.
Review only this PR's change: vjeux/astryx@9efd4fd...6793453
User need
Part of matching Astryx's touch components to iOS 26, so apps built with it feel native on phones. Apps with six or more sections need each one reachable from the bar. iOS keeps the bar to five: the first four tabs and More, whose screen lists the rest. #8210's bar has no overflow. This adds More, measured with six tabs.
Problem and solution fit
valueismoreValueor any tab past the fourth, so the lens stays on More; More again returns to its list (onReselect), as iOS pops More's stack.TabBarMoreList: More's screen, one row per tab past the fourth, given the same children as TabBar; badges show in the rows.Current specification
spec:AST-094FR13, FR8. An engineering owner decides (no record governs it): this API.Public delta and caller burden
New
moreValueprop andTabBarMoreList(children, value, onChoose); core's catalog gains@astryx.tabBar.more("More"). The app rendersTabBarMoreListwhilevalueismoreValue.Size, gzip against #8210's head: TabBar's import 63.7 → 66.7 KB JavaScript, 1,968 → 1,968 B CSS.
Design and alternatives
Evidence
iOS 26.2 simulator: More opens its list, a section chosen there keeps the lens on More, More again returns to the list; then Android 15 Chrome.
Scope
Stack: #8076 → … → #8320 → #8129 → … → #8210 → this PR.
Testing
Try it:
pnpm storybook, Lab › TabBar › More Tab (six sections).Browser tests: More holds the lens while a section inside it is selected; More again returns to the list; a badged row is read with its badge.
Passing:
pnpm test:interaction TabBar,pnpm vitest run packages/lab/src/TabBar,pnpm typecheck, lint.