Skip to content

feat(core): createReorderable makes List rows reorderable the way an iOS table does - #8139

Draft
vjeux wants to merge 1431 commits into
meta:mainfrom
vjeux:uikit/c13-list-reorder
Draft

vjeux wants to merge 1431 commits into
meta:mainfrom
vjeux:uikit/c13-list-reorder

Conversation

@vjeux

@vjeux vjeux commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Depends on #8138 and #8336. Review only this PR's change: vjeux/astryx@fba78a3...9e84c6c

Why

People reorder playlists, to-do lists and settings on their phones. List can't do it, so apps build their own, often without a keyboard or screen-reader path.

What led to it

This is part of the UIKit-parity program, which makes Astryx's components behave like their iOS counterparts on touch screens. spec:AST-103 defines a reorderable List, and #8138 holds the measured UIKit values it plays. Here, createReorderable({onReorder}) makes the behavior, List takes it as reorderable, and each ListItem with an itemKey gets a handle:

  • On touch, a 150 ms hold picks a row up; a mouse drags it directly.
  • Activating the handle starts reorder mode. The arrow keys move the row and announce its place, and Escape ends the mode.
  • Each move calls onReorder({key, to}) once.
<List reorderable={reorderable}>
  {items.map(i => <ListItem key={i.id} itemKey={i.id} label={i.name} />)}
</List>

Options and tradeoffs

  • During the drag: slide rows aside, as UIKit does, or keep them still with a line marking the drop.
  • On touch: pick the row up at once, or after a hold, so a flick still scrolls.
  • In the markup: a wrapper around each row, or only the handle.

Why this choice

design:ordered-collection-reordering chose still rows and a line, because they need no layout work during the drag and look the same everywhere. The hold is UIKit's measured 150 ms. Only the handle is added (FR5), so rows keep their layout. List grows by 146 B gzip and ListItem by 546 B; CSS doesn't change.

How to check it

In Storybook Core/List, on a phone or with touch emulation:

  1. Reorderable: hold a grip, drag it two rows down and let go. The row lands there and the others glide.
  2. Flick a grip: the list scrolls.
  3. Tab to a grip, press Enter, press Down twice, then Escape. A screen reader reads each position.
  4. Reorder From Your UI: choose Move in a row's menu. Reorder mode starts on that row.
  5. Reorder With Pinned Rows: nothing drops above Favorites, but rows move past All mail.

I ran the unit tests and the touch and mouse browser tests in Chromium and WebKit, and all pass. Two reds come from elsewhere: touch-support-bundle, which #8671 fixes, and pr-rtl, main's newer RTL test from 0472c4e.

Evidence

On iOS 26.2 Safari: a held drag, and the drop with the main thread blocked.

Stack (merge in this order): the list stack through #8106 → #8138 and #8336 → this → #8337 → the browser proofs.

@vercel

vercel Bot commented Oct 24, 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 Oct 28, 2026 3:39pm UTC

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Oct 24, 2026
@astracat-bot

astracat-bot Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
🟡 Reviewed (for maintainers only) Oct 28, 2026, 3:59 PM UTC

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval is waiting on an engineering-owner decision. No current spec governs List.onReorder, ListItem.isReorderDisabled or the UIKit reorder model (rows slide aside, springs kept under Reduce Motion, no insertion line), so an owner needs to settle that contract and which record governs it: an amended List contract, or spec:AST-094 with its draft requirements approved. Once the governing record states it, any engineering owner, the author included, can record the decision by commenting /approve-spec <full head SHA>. These still need changes whatever that decision is:

  • The diff against main is about 31,000 authored lines from the predecessor stack. Land those pull requests or update the branch so this one carries only the reorder change.
  • Keyboard focus on a reorder handle draws two focus rings, the handle's and the whole row's, and the handle's ring is clipped at the list's edge.
  • The stacked touch row minimum heights change default List row geometry, which the List contract's FR2 says padded preserves.

[Automated review]

onPointerDown={(event: PointerEvent<HTMLButtonElement>) =>
event.stopPropagation()
}
{...focusOutlineProps.focusVisible(styles.handle)}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Keyboard focus here also lights the row: Item paints focusOutlineProps.focusWithin for any focused descendant, so a focused handle shows two 2 px rings (measured in Chromium), against architecture:interaction-modality INV3. The handle's own ring also loses its inline end to the list's overflow-inline: clip because of marginInlineEnd: -8. Excluding the handle from the row's focus-within match and keeping the ring inside the clip would leave one indicator.

*/
export const listRowStyles = stylex.create({
touchOneLine: {
minHeight: {default: null, [TOUCH]: listRowConsts.touchRowHeight},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Every ListItem gets this minimum on a coarse pointer (applied in ListItem.tsx lines 456-460), so default lists grow from 41 px to 52 px rows on phones. component:List FR2 says "padded MUST preserve current header, list, and row geometry", so this needs that record amended or should stay out of this diff.

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR

🧪 Sandbox Preview

View Sandbox for this PR

Modified Components

Item (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Entry File (ESM) 284B 284B 0B
Lines of Code 1372 1411 -
Complexity Very High Very High (128) -
TreeList (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Entry File (ESM) 648B 648B 0B
Lines of Code 1068 1257 -
Complexity Very High Very High (138) -

Component Size

Component Import before Import after Delta CSS before CSS after Delta
charts/Chart N/A 65.1KB N/A N/A 20B N/A
charts/ChartAxis N/A 6.7KB N/A N/A 112B N/A
charts/ChartLegend N/A 54.2KB N/A N/A 20B N/A
charts/ChartTooltip N/A 54.2KB N/A N/A 20B N/A
core/AlertDialog 57.3KB 57.9KB +680B 12.5KB 12.6KB +21B
core/AppShell 66.8KB 67.4KB +621B 11.8KB 11.8KB +22B
core/AspectRatio 3.7KB 3.8KB +66B 3.5KB 3.5KB +40B
core/Avatar 37.8KB 38.1KB +287B 6.3KB 6.3KB +23B
core/AvatarGroup 40.2KB 40.5KB +288B 6.4KB 6.5KB +22B
core/AvatarGroupOverflow 40.3KB 41.0KB +687B 6.4KB 6.4KB +23B
core/AvatarStatusDot 7.1KB 7.1KB +61B 3.4KB 3.4KB +41B
core/Badge 3.9KB 4.0KB +64B 3.8KB 3.9KB +39B
core/Banner 48.5KB 49.1KB +664B 10.1KB 10.1KB +21B
core/BaseTypeahead 55.0KB 55.6KB +659B 10.1KB 10.1KB +21B
core/Blockquote 3.5KB 3.6KB +66B 3.4KB 3.4KB +39B
core/BottomSheet 33.9KB 34.0KB +71B 7.9KB 7.9KB +24B
core/BottomSheetSwitcher 14.8KB 14.8KB +62B 3.3KB 3.3KB +41B
core/BreadcrumbItem 67.3KB 68.5KB +1.2KB 11.2KB 11.5KB +362B
core/Breadcrumbs 22.8KB 23.1KB +297B 3.3KB 3.3KB +40B
core/Button 43.7KB 44.3KB +680B 9.3KB 9.3KB +21B
core/ButtonGroup 8.4KB 8.5KB +67B 3.3KB 3.3KB +40B
core/Calendar 55.6KB 56.2KB +656B 10.2KB 10.2KB +23B
core/Card 6.4KB 6.5KB +66B 6.3KB 6.4KB +42B
core/Carousel 50.9KB 51.5KB +624B 10.3KB 10.4KB +22B
core/Center 4.2KB 4.2KB +63B 4.6KB 4.6KB +42B
core/ChatComposer 61.3KB 62.0KB +649B 11.0KB 11.0KB +20B
core/ChatComposerDrawer 24.3KB 24.6KB +305B 4.5KB 4.6KB +39B
core/ChatComposerInput 56.2KB 56.8KB +655B 10.2KB 10.2KB +20B
core/ChatComposerTokenElement 56.2KB 56.8KB +655B 10.2KB 10.2KB +20B
core/ChatDictationButton 47.2KB 47.8KB +659B 9.6KB 9.7KB +21B
core/ChatLayout 49.5KB 50.2KB +709B 10.1KB 10.1KB +22B
core/ChatLayoutScrollButton 47.0KB 47.7KB +669B 9.7KB 9.8KB +21B
core/ChatMessage 23.4KB 23.7KB +295B 3.5KB 3.6KB +39B
core/ChatMessageBubble 7.0KB 7.1KB +67B 3.6KB 3.6KB +42B
core/ChatMessageList 29.3KB 29.6KB +309B 7.8KB 7.8KB +21B
core/ChatMessageMetadata 26.4KB 26.7KB +302B 4.0KB 4.0KB +22B
core/ChatSendButton 46.4KB 47.0KB +669B 9.3KB 9.3KB +20B
core/ChatSystemMessage 6.7KB 6.8KB +71B 3.7KB 3.7KB +39B
core/ChatTokenizedText 6.9KB 7.0KB +63B 3.9KB 3.9KB +40B
core/ChatToolCalls 32.4KB 32.7KB +311B 9.1KB 9.1KB +22B
core/CheckIndicator 9.2KB 9.3KB +64B 3.7KB 3.8KB +41B
core/CheckboxIndicator 4.1KB 4.1KB +65B 3.8KB 3.8KB +22B
core/CheckboxInput 50.5KB 51.2KB +665B 9.5KB 9.5KB +22B
core/CheckboxList 46.6KB 60.4KB +13.8KB ⚠️ 8.3KB 8.4KB +78B
core/CheckboxListItem 54.7KB 59.0KB +4.3KB ⚠️ 10.6KB 11.2KB +611B
core/Citation 26.5KB 26.8KB +305B 4.3KB 4.3KB +40B
core/ClickableCard 12.8KB 13.2KB +459B 6.9KB 7.0KB +45B
core/Code 3.5KB 3.6KB +63B 3.4KB 3.4KB +41B
core/CodeBlock 61.2KB 61.8KB +665B 10.8KB 10.9KB +21B
core/Collapsible 18.7KB 19.1KB +373B 4.4KB 4.4KB +41B
core/CollapsibleGroup 6.4KB 6.4KB +71B 3.2KB 3.2KB +40B
core/CommandPalette 51.5KB 52.2KB +675B 12.0KB 12.0KB +24B
core/CommandPaletteEmpty 6.1KB 6.2KB +64B 3.3KB 3.4KB +42B
core/CommandPaletteFooter 23.6KB 23.9KB +304B 3.5KB 3.6KB +39B
core/CommandPaletteGroup 3.5KB 3.5KB +64B 3.3KB 3.4KB +39B
core/CommandPaletteInput 32.9KB 33.2KB +301B 8.3KB 8.3KB +23B
core/CommandPaletteItem 8.4KB 8.9KB +438B 3.5KB 3.5KB +40B
core/CommandPaletteList 22.8KB 23.1KB +291B 3.3KB 3.3KB +41B
core/ComplexSelector 56.5KB 57.1KB +673B 10.8KB 10.8KB +20B
core/ContextMenu 75.3KB 93.2KB +18.0KB ⚠️ 14.8KB 15.5KB +669B
core/ContextMenuItem 53.5KB 54.2KB +664B 9.8KB 9.8KB +21B
core/DateInput 100.2KB 100.9KB +708B 14.9KB 15.0KB +20B
core/DateRangeInput 70.1KB 70.8KB +674B 11.4KB 11.4KB +21B
core/DateTimeInput 110.4KB 111.1KB +677B 15.4KB 15.4KB +21B
core/Dialog 16.2KB 16.3KB +64B 7.1KB 7.1KB +23B
core/DialogHeader 49.5KB 50.2KB +706B 10.0KB 10.0KB +20B
core/Divider 6.5KB 6.5KB +64B 3.6KB 3.6KB +43B
core/Drawer 31.6KB 31.6KB +57B 8.0KB 8.1KB +23B
core/DrawerHeader 49.6KB 50.2KB +667B 11.4KB 11.4KB +21B
core/DropdownMenu 73.4KB 74.7KB +1.3KB 15.0KB 15.6KB +655B
core/DropdownMenuCheckboxItem 16.4KB 17.4KB +1015B 5.7KB 6.1KB +352B
core/DropdownMenuDivider 6.6KB 6.6KB +61B 3.6KB 3.6KB +42B
core/DropdownMenuGroup 6.1KB 6.1KB +69B 3.3KB 3.3KB +39B
core/DropdownMenuItem 15.6KB 16.6KB +1001B 5.3KB 5.7KB +373B
core/DropdownMenuRadioGroup 6.0KB 6.1KB +62B 3.2KB 3.2KB +43B
core/DropdownMenuRadioItem 16.4KB 17.4KB +1023B 5.7KB 6.1KB +352B
core/DropdownMenuSubMenu 58.7KB 59.9KB +1.2KB 9.7KB 10.0KB +361B
core/EmptyState 7.7KB 7.8KB +64B 3.5KB 3.6KB +42B
core/Field 44.8KB 45.1KB +304B 8.1KB 8.2KB +22B
core/FieldLabel 40.3KB 40.6KB +296B 6.7KB 6.7KB +21B
core/FieldStatus 10.6KB 10.6KB +70B 4.4KB 4.4KB +22B
core/FileInput 54.8KB 55.4KB +663B 10.5KB 10.5KB +22B
core/FormLayout 6.3KB 6.3KB +66B 3.4KB 3.4KB +40B
core/Grid 4.3KB 4.4KB +67B 3.7KB 3.7KB +40B
core/GridSpan 3.4KB 3.5KB +63B 3.2KB 3.3KB +40B
core/HStack 7.3KB 7.3KB +62B 4.9KB 4.9KB +44B
core/Heading 9.1KB 9.2KB +64B 6.8KB 6.8KB +23B
core/Icon 9.0KB 9.1KB +67B 3.7KB 3.8KB +41B
core/IconButton 43.7KB 44.4KB +687B 9.3KB 9.3KB +21B
core/InputGroup 45.4KB 45.7KB +288B 8.2KB 8.2KB +22B
core/InputGroupText 6.3KB 6.4KB +66B 3.7KB 3.8KB +40B
core/Item 11.4KB 12.3KB +952B 4.7KB 5.0KB +373B
core/Kbd 23.4KB 23.7KB +295B 3.5KB 3.5KB +40B
core/LayerProvider 64.0KB 64.7KB +672B 10.3KB 10.3KB +24B
core/Layout 8.1KB 8.2KB +63B 5.5KB 5.5KB +43B
core/LayoutContent 7.4KB 7.5KB +64B 4.9KB 5.0KB +43B
core/LayoutFooter 7.3KB 7.4KB +68B 4.8KB 4.9KB +42B
core/LayoutHeader 7.4KB 7.4KB +65B 4.8KB 4.9KB +42B
core/LayoutPanel 7.6KB 7.6KB +65B 4.8KB 4.9KB +43B
core/Lightbox 51.9KB 52.5KB +655B 10.0KB 10.0KB +22B
core/Link 44.1KB 44.7KB +662B 7.7KB 7.8KB +25B
core/List 6.7KB 20.7KB +13.9KB ⚠️ 3.4KB 3.6KB +184B
core/ListItem 54.1KB 58.5KB +4.3KB ⚠️ 10.6KB 11.2KB +611B
core/Markdown 145.2KB 163.3KB +18.1KB ⚠️ 17.8KB 18.4KB +665B
core/MetadataList 23.5KB 23.8KB +307B 3.6KB 3.6KB +42B
core/MetadataListItem 6.5KB 6.5KB +64B 3.4KB 3.4KB +43B
core/MobileNav 51.7KB 52.3KB +609B 10.2KB 10.3KB +23B
core/MobileNavToggle 46.9KB 47.5KB +649B 9.6KB 9.6KB +21B
core/MoreMenu 73.7KB 75.0KB +1.3KB 15.0KB 15.6KB +655B
core/MultiSelector 73.6KB 74.3KB +700B 14.8KB 14.8KB +24B
core/NavHeadingMenu 13.0KB 13.0KB +77B 3.3KB 3.3KB +39B
core/NavIcon 3.4KB 3.5KB +63B 3.3KB 3.3KB +42B
core/NumberInput 56.4KB 57.1KB +703B 10.9KB 10.9KB +20B
core/Outline 29.0KB 29.7KB +672B 4.0KB 4.1KB +40B
core/OverflowList 8.5KB 8.6KB +67B 3.5KB 3.5KB +40B
core/Overlay 19.5KB 19.6KB +43B 3.8KB 3.9KB +17B
core/Pagination 85.5KB 86.7KB +1.3KB 15.5KB 15.8KB +348B
core/Popover 50.3KB 50.9KB +681B 12.2KB 12.2KB +20B
core/PowerSearch 166.6KB 178.8KB +12.2KB ⚠️ 20.1KB 20.4KB +355B
core/ProgressBar 7.7KB 7.8KB +66B 6.6KB 6.6KB +20B
core/RadioIndicator 3.8KB 3.9KB +61B 3.7KB 3.7KB +20B
core/RadioList 46.2KB 46.5KB +297B 8.2KB 8.2KB +21B
core/RadioListItem 52.8KB 54.0KB +1.2KB 9.8KB 10.2KB +352B
core/ResizeHandle 25.5KB 25.8KB +310B 3.9KB 3.9KB +41B
core/Section 7.5KB 7.6KB +67B 6.2KB 6.2KB +42B
core/SegmentedControl 39.1KB 39.4KB +312B 6.3KB 6.4KB +22B
core/SegmentedControlItem 8.6KB 9.0KB +440B 3.9KB 3.9KB +41B
core/SelectableCard 12.8KB 13.2KB +455B 7.1KB 7.2KB +43B
core/Selector 77.0KB 78.2KB +1.2KB 15.2KB 15.5KB +349B
core/SelectorOption 14.7KB 15.6KB +959B 5.2KB 5.6KB +373B
core/SideNav 64.6KB 65.3KB +636B 10.7KB 10.7KB +21B
core/SideNavCollapseButton 47.3KB 47.9KB +665B 9.6KB 9.6KB +20B
core/SideNavHeading 59.2KB 59.8KB +649B 10.4KB 10.4KB +20B
core/SideNavItem 55.3KB 55.9KB +653B 10.3KB 10.3KB +21B
core/SideNavSection 6.5KB 6.6KB +59B 3.6KB 3.6KB +38B
core/Skeleton 3.8KB 3.8KB +60B 3.6KB 3.6KB +22B
core/Slider 49.1KB 49.4KB +303B 8.7KB 8.7KB +20B
core/Spinner 26.7KB 27.0KB +297B 7.5KB 7.5KB +19B
core/Stack 7.1KB 7.1KB +62B 4.9KB 4.9KB +44B
core/StackItem 6.0KB 6.1KB +63B 3.3KB 3.3KB +38B
core/StatusDot 19.0KB 19.0KB +59B 6.2KB 6.2KB +19B
core/Step 33.0KB 33.7KB +662B 5.5KB 5.5KB +23B
core/Stepper 48.1KB 48.7KB +661B 9.7KB 9.8KB +21B
core/Switch 49.0KB 49.6KB +650B 9.5KB 9.5KB +21B
core/Tab 9.7KB 10.2KB +460B 4.1KB 4.1KB +41B
core/TabList 40.6KB 40.9KB +307B 7.3KB 7.3KB +22B
core/TabMenu 55.9KB 56.6KB +647B 10.2KB 10.3KB +20B
core/Table 84.7KB 102.6KB +17.9KB ⚠️ 15.6KB 16.2KB +659B
core/TableBody 3.3KB 3.3KB +63B 3.2KB 3.2KB +42B
core/TableCell 76.5KB 94.4KB +17.9KB ⚠️ 15.3KB 15.9KB +661B
core/TableFooter 3.3KB 3.3KB +63B 3.2KB 3.2KB +42B
core/TableHeader 3.3KB 3.3KB +63B 3.2KB 3.2KB +42B
core/TableHeaderCell 76.1KB 94.0KB +17.9KB ⚠️ 15.0KB 15.7KB +653B
core/TableRow 6.4KB 6.5KB +57B 3.8KB 3.8KB +42B
core/TableSelectionToolbar 52.8KB 53.5KB +680B 11.3KB 11.3KB +21B
core/Text 8.6KB 8.6KB +66B 6.8KB 6.8KB +23B
core/TextArea 50.0KB 50.3KB +318B 9.5KB 9.6KB +22B
core/TextInput 54.2KB 54.9KB +640B 10.6KB 10.6KB +20B
core/Thumbnail 51.4KB 52.0KB +662B 11.1KB 11.2KB +23B
core/TimeInput 87.5KB 88.1KB +614B 13.9KB 13.9KB +20B
core/Timer 9.2KB 9.3KB +70B 6.8KB 6.8KB +23B
core/Timestamp 27.9KB 28.2KB +309B 9.7KB 9.7KB +21B
core/Toast 60.6KB 61.2KB +664B 9.9KB 9.9KB +22B
core/ToggleButton 44.5KB 45.2KB +655B 9.4KB 9.4KB +21B
core/ToggleButtonGroup 6.3KB 6.4KB +68B 3.2KB 3.3KB +42B
core/Token 30.2KB 30.8KB +663B 4.6KB 4.7KB +41B
core/Tokenizer 69.3KB 70.0KB +676B 16.7KB 16.7KB +20B
core/Toolbar 40.1KB 40.4KB +303B 7.7KB 7.8KB +46B
core/TopNav 52.5KB 53.1KB +616B 10.5KB 10.5KB +21B
core/TopNavHeading 58.6KB 59.2KB +664B 10.2KB 10.2KB +20B
core/TopNavItem 9.0KB 9.5KB +446B 3.8KB 3.9KB +39B
core/TopNavMegaMenu 55.0KB 55.6KB +652B 11.0KB 11.0KB +21B
core/TopNavMegaMenuFeaturedCard 6.7KB 6.8KB +66B 3.4KB 3.4KB +38B
core/TopNavMegaMenuItem 9.1KB 9.5KB +438B 4.1KB 4.1KB +38B
core/TopNavMenu 58.3KB 58.9KB +655B 10.3KB 10.3KB +23B
core/TreeList 40.4KB 51.9KB +11.5KB ⚠️ 4.8KB 5.2KB +384B
core/Typeahead 62.2KB 62.8KB +679B 11.4KB 11.5KB +21B
core/TypeaheadItem 6.2KB 6.3KB +60B 3.4KB 3.5KB +39B
core/VStack 7.3KB 7.3KB +61B 4.9KB 4.9KB +44B
lab/ChartDotGL N/A 7.4KB N/A N/A 20B N/A
lab/ChartDotGLInteractive N/A 8.3KB N/A N/A 20B N/A
lab/ChartHeatmapGL N/A 8.5KB N/A N/A 20B N/A
lab/ChartStreamGL N/A 7.4KB N/A N/A 20B N/A
lab/ChatEmojiPicker N/A 66.4KB N/A N/A 773B N/A
lab/ChatReactionBar N/A 67.0KB N/A N/A 1.1KB N/A
lab/ChatReasoning N/A 7.0KB N/A N/A 967B N/A
lab/ChatTypingIndicator N/A 24.2KB N/A N/A 612B N/A
lab/ChatUnreadDivider N/A 3.6KB N/A N/A 348B N/A
lab/CircularProgress N/A 7.2KB N/A N/A 1.0KB N/A
lab/CodeEditor N/A 14.6KB N/A N/A 665B N/A
lab/CommentComposer N/A 95.4KB N/A N/A 1.9KB N/A
lab/CommentPin N/A 48.6KB N/A N/A 1.2KB N/A
lab/CommentThread N/A 234.2KB N/A N/A 2.4KB N/A
lab/Comments N/A 238.8KB N/A N/A 2.5KB N/A
lab/DiffViewer N/A 46.8KB N/A N/A 2.1KB N/A
lab/EmojiPicker N/A 64.3KB N/A N/A 722B N/A
lab/InfoTip N/A 22.0KB N/A N/A 458B N/A
lab/ListInput N/A 76.5KB N/A N/A 1.6KB N/A
lab/LogStream N/A 8.0KB N/A N/A 1.6KB N/A
lab/MobilePowerSearch N/A 165.7KB N/A N/A 1.4KB N/A
lab/MobileTokenizer N/A 93.4KB N/A N/A 809B N/A
lab/SVGIcon N/A 7.6KB N/A N/A 764B N/A
lab/Schedule N/A 61.1KB N/A N/A 3.9KB N/A
lab/Stat N/A 4.1KB N/A N/A 646B N/A
lab/ThreeDScatterGL N/A 7.6KB N/A N/A 20B N/A
lab/TourStep N/A 56.3KB N/A N/A 590B N/A
lab/TransferList N/A 82.5KB N/A N/A 1.7KB N/A
lab/TransferListSelector N/A 88.3KB N/A N/A 1.9KB N/A
richtext/RichTextEditor N/A 272.1KB N/A N/A 2.6KB N/A
richtext/RichTextEditorToolbar N/A 214.3KB N/A N/A 454B N/A
richtext/RichTextView N/A 252.5KB N/A N/A 2.3KB N/A

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.

⚠️ Touch-only size budget

These components grew past the touch-only budget (2 KB gzip JavaScript or 1 KB gzip CSS per component). If the growth runs only on a coarse pointer, load its JavaScript lazily so the import does not carry it, or justify the cost in the pull request description; CSS stays in the package stylesheet, so justify it.

Component JavaScript CSS
core/CheckboxList +13.8KB ⚠️ +78B
core/CheckboxListItem +4.3KB ⚠️ +611B
core/ContextMenu +18.0KB ⚠️ +669B
core/List +13.9KB ⚠️ +184B
core/ListItem +4.3KB ⚠️ +611B
core/Markdown +18.1KB ⚠️ +665B
core/PowerSearch +12.2KB ⚠️ +355B
core/Table +17.9KB ⚠️ +659B
core/TableCell +17.9KB ⚠️ +661B
core/TableHeaderCell +17.9KB ⚠️ +653B
core/TreeList +11.5KB ⚠️ +384B

Bundle Size Summary

Gzip figures measure each package's entry file, not the code an import pulls in.

Package Entry (ESM) Entry gzip before Entry gzip after Delta
@astryxdesign/core 5.0KB 1.2KB 1.3KB +31B
Package stylesheet Gzip before Gzip after Delta
@astryxdesign/core 35.4KB 36.6KB +1.2KB

Accessibility Audit

Status: 2 accessibility violation(s) found — 2 serious.

Radio group pattern - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 3/11 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
RadioList - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 3/14 stories · Learn more
    • WCAG: 1.4.3 (Level AA)

Visual Regression

55 of 504 shot(s) changed.

A change here is a question, not a failure: check whether the after is the
picture you intended. Record that review on the PR. Baseline maintenance is an
explicit dispatch of CI; this report never rewrites the baseline or adds a release gate.

component story theme mode pixels
Selector Indicator Space Bottom Sheet Narrow End RTL neutral light 753,933
Selector Indicator Space Bottom Sheet Wide Start neutral light 740,072
RichTextEditor Markdown parity: side by side probe dark 558,840
RichTextEditor Markdown parity: side by side probe light 540,756
Chat Full AI Chat probe light 230,823
Chat Full AI Chat probe dark 229,805
AppShell With Mobile Nav probe light 217,010
AppShell With Mobile Nav probe dark 216,960
Collapsible Dividers probe dark 66,445
Collapsible Dividers probe light 66,445
AppShell Playground neutral dark 65,198
AppShell Playground neutral light 63,788
Chat Default neutral dark 36,304
Chat Default neutral light 35,767
Chat Empty State probe light 23,531
Chat Empty State probe dark 22,622
ChatAutoScroll Scroll Behavior Comparison neutral dark 15,378
ChatAutoScroll Scroll Behavior Comparison neutral light 14,107
Chat With Attachments probe light 13,406
Chat With Attachments probe dark 11,232

and 35 more.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval is waiting on an engineering-owner decision: no current spec governs List.onReorder, ListItem.isReorderDisabled or the UIKit reorder model (rows slide aside, springs kept under Reduce Motion, no insertion line), so an owner needs to settle that contract and which record governs it, an amended List contract or spec:AST-094 with its draft requirements approved. Once the governing record states it, any engineering owner, the author included, can record the decision by commenting /approve-spec <full head SHA>. These still need changes whatever that decision is:

  • The diff against main is about 31,000 authored lines from the predecessor stack; land those pull requests or update the branch so this one carries only the reorder change.
  • Keyboard focus on a reorder handle draws two focus rings, the handle's and the whole row's, and the handle's ring is clipped at the list's edge.
  • The stacked touch row minimum heights change default List row geometry, which the List contract's FR2 says padded preserves.
  • spec:AST-094 FR7 cites an AST-090 record that does not exist in the repository.

[Automated review]

follows.
- **FR7 — Exits animate as UIKit's do.** A touch presentation MUST play the
exit its UIKit counterpart plays. **Proposed; pending owner review:** this
departs from the draft `spec:AST-090` FR1 (exits off by default) and FR10

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No AST-090 record exists in the repository, at this head or on main, so an owner cannot check what FR7 departs from. Cite the record where it lives, or drop the departure until it lands.

* nothing, and a disabled row's handle stays focusable but inert
* @position Tests for List/useListReorder.ts and List/ListReorderHandle.tsx;
* the touch and mouse drags are proven in a real browser by
* ListReorder.interaction.browser.spec.ts

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ListReorder.interaction.browser.spec.ts is not in the tree at this head (the SYNC note in useListReorder.ts line 44 names it too). Drop the reference or land the browser proof with this change.

vjeux added a commit to vjeux/astryx that referenced this pull request Oct 24, 2026
@vjeux

vjeux commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

On the predecessor stack: this pull request is stacked, as its first line says, and only its last commit (d67ffca, 10 files, +1,703 −7) is its own. It rebases onto main as each predecessor lands, and the diff then shrinks to that commit.

@cixzhang

Copy link
Copy Markdown
Contributor

Posted by Cindy's agent on her behalf.

Parts of this PR re-implement behavior that already exists, or is being specified, as a shared part of core. Converging keeps one implementation per behavior:

This is about where the behavior lives, not about the PR's intent.

@vjeux

vjeux commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

Agreed: one implementation.

The reorder also now keys its motion on the resolver's touch presentation (useTouchPresentation), the same on every touch screen, instead of a platform check.

…composed path

Inside an open shadow root the document's listeners see the shadow host,
in event.target and in a touch's target alike, so a recognizer on an
element in the root never got its finger, and nothing claimed it. landedOn
takes the composed path's first element for the event's own target and for
a touch whose target is the event's (another finger keeps its own): a
touch's start, a pointer's press and its pairing, the last touch a scroll
reads, a cancelled pointer's touch and hover.
vjeux added 6 commits October 27, 2026 05:29
…ouch target never drops below 44 px

- A click in a link row's own box, outside its anchor (its padding, or a tap
  in its touch hit area under a finger), goes to the row's anchor with its
  modifier keys, so link rows gain the reach other rows have. Item marks the
  row's anchor `data-astryx-row-link`; a row with both `onClick` and `href`
  keeps `onClick`.
- The touch target is 44 px (`spec:AST-094` FR42), or more where the page sets
  `--size-touch-target` larger; a smaller value never lowers it. The docs and
  the changeset no longer tell themes to set it.
- The code cites FR42, and `component:List` FR10 where it applies.
- Under a finger an interactive row's `::after` is its touch hit layer, so the
  row press layer's notes say to decorate a row with a child.

Red first: a tap in a link row's growth follows its link (browser); a click in
a link row's padding reaches its anchor, modifiers included, and a row with
both `onClick` and `href` keeps `onClick` (unit); a page's 30 px touch target
leaves 44 px (unit, browser).
… hit area; the target never drops below 44 px) into the tree expansion change
… hit area; the target never drops below 44 px) into the list updates change
…in when the pointer or theme changes

`--size-touch-target` was read once, when a row mounted, and only in px: a
theme's `3.75rem` kept the 44 px reach, and a pointer that turned coarse, or
a theme that changed, left the size the row first read. The size is now
resolved in px, rem (through the root's font size) or em (through the
element's), still never below 44 px, and read again when the primary pointer
changes or the theme does.

Red first (unit): a 3.75rem size and a 3em size at 20 px give 60 px; a
pointer turning coarse re-reads it; a theme change re-reads it.
…again on a pointer or theme change) into the tree expansion change
…again on a pointer or theme change) into the list updates change

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Changes are needed before this can land, although the reorder contract and the drag's look now follow the current specs everywhere except reorder mode's missing hint. Please address these:

  • Update the branch once #8138 and #8336 land: 38,226 authored lines change against main, and 32,809 of them are that open stack.
  • Ship reorder mode's hint (Move up, Move down and Done) here, or land #8337 with this pull request, since spec:AST-103 FR4 and spec:AST-094 FR39 need a way to move a row with a mouse and no drag.
  • scripts/touch-support-bundle.test.mjs fails “is absent from the root entry” because createReorderable brings the gesture modules into the package root, so #8671 (or another approved change to that check) has to land first.
  • Add mouse browser tests for the drag, drop and cancel (spec:AST-103 FR3), here or by landing #8140 with this pull request.

[Automated review]

[controller, isTouch],
);
return (
<span id={controller.hintId} hidden>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reorder mode renders only these hidden instructions: no hint with move buttons and Done. A mouse user who clicks a handle then has nothing on screen to move the row or end the mode (spec:AST-103 FR4, FR4a; spec:AST-094 FR39). Fold the hint in, or land #8337 with this pull request.

@@ -172,6 +172,9 @@ export * from './Outline';
// Overflow list
export * from './OverflowList';

// Reorder (a collection's `reorderable` prop)
export * from './reorderable';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This export brings the reorder engine, and through ListReorderTouch.ts 14 gesture modules (61,003 minified bytes), into the root entry, so main's scripts/touch-support-bundle.test.mjs fails “is absent from the root entry”. #8671, or another approved change to that check, has to land first.

* Enters reorder mode for the item with `key` from the app's own UI, such
* as a Move item in its context menu or a toolbar button, as activating
* its handle does: the focus moves to the handle, which scrolls into view,
* and the mode's keys, hint, announcements and exits follow. A key that

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This promises a hint that this revision does not render; keep “hint” only if #8337 lands together with this pull request.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Changes are needed before this can land, although the reorder contract and the drag's look follow the current specs everywhere except reorder mode's missing hint. Please address these:

  • Update the branch once #8138 and #8336 land: 38,474 authored lines change against main, and 33,057 of them are that open stack.
  • Ship reorder mode's hint (Move up, Move down and Done) here, or land #8337 together with this pull request, since spec:AST-103 FR4 and spec:AST-094 FR39 need a way to move a row with a mouse and no drag.
  • scripts/touch-support-bundle.test.mjs fails "is absent from the root entry" because createReorderable brings the gesture modules into the package root, so #8671 (or another approved change to that check) has to land first.
  • Add mouse browser tests for the drag, drop and cancel (spec:AST-103 FR3), here or by landing #8140 with this pull request.

[Automated review]

[controller, isTouch],
);
return (
<span id={controller.hintId} hidden>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reorder mode renders only these hidden instructions: no hint with move buttons and Done. A mouse user who clicks a handle then has nothing on screen to move the row or end the mode (spec:AST-103 FR4, FR4a; spec:AST-094 FR39). Fold the hint in, or land #8337 with this pull request.

@@ -172,6 +172,9 @@ export * from './Outline';
// Overflow list
export * from './OverflowList';

// Reorder (a collection's `reorderable` prop)
export * from './reorderable';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This export brings the reorder engine, and through ListReorderTouch.ts 14 gesture modules (61,052 minified bytes), into the root entry, so main's scripts/touch-support-bundle.test.mjs fails "is absent from the root entry". #8671, or another approved change to that check, has to land first.

* Enters reorder mode for the item with `key` from the app's own UI, such
* as a Move item in its context menu or a toolbar button, as activating
* its handle does: the focus moves to the handle, which scrolls into view,
* and the mode's keys, hint, announcements and exits follow. A key that

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This promises a hint that this revision does not render; keep "hint" only if #8337 lands together with this pull request.

@cixzhang

cixzhang commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Posted by Cindy's agent on her behalf.

Correction: "dividers hide on press" comes from #8079, which this PR stacks on. Whether it lands is a pending decision for Cindy, not a settled one, so no change is needed here for now. Details are on #8079.

@cixzhang

Copy link
Copy Markdown
Contributor

Posted by Cindy's agent on her behalf: closed and reopened only to restart this PR's CI on the current workflow after tonight's queue-wide cancel; nothing in the PR changed.

cixzhang and others added 3 commits October 27, 2026 20:51
… hold

A divided List row keeps its dividers while it is pressed, as it does today, and Core keeps no selection hold: products show a row kept selected through ListItem's isSelected. This removes the touch press's divider hiding (its ListItem styles, docs, changeset, tests and browser proofs) and the selection hold (selectionHold.ts, its held press state in the shared press code, its internal deselect constants, the row focus-return lines, story, changeset and proofs). The shared test helpers, the press-coverage guard and the press release's own clock stay.

Co-authored-by: Christopher Chedeau <vjeuxx@gmail.com>
…tion hold) as a dependency

Co-authored-by: Christopher Chedeau <vjeuxx@gmail.com>
The previous merge left List.tsx's hasDividers JSDoc unresolved and the List stories empty. This restores the stories (without the selection hold demo) and the plain hasDividers line.

Co-authored-by: Christopher Chedeau <vjeuxx@gmail.com>

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Changes are needed before this can land: the List reorder follows current spec:AST-103 in most places, but the branch carries the open predecessor stack, conflicts with main, and misses four current AST-103 requirements. Please address these:

  • Update the branch once #8138, #8336, #8106 and #8076 land: 36,294 authored lines change against main, 30,875 of them that stack, and it now conflicts in TreeList.tsx, TreeListItem.tsx and routes.lock.json.
  • Ship reorder mode's hint (Move up, Move down and Done) here or land #8337 with this, since AST-103 FR4 and spec:AST-094 FR39 need a way to move a row with a mouse and no drag.
  • Let a pen, and a finger where the primary pointer is fine, drag a row (AST-103 FR3, AST-094 FR43), and add attach and positions (AST-103 FR1, FR4b), here or by landing #8683 and #8719 with this.
  • scripts/touch-support-bundle.test.mjs fails “is absent from the root entry” because createReorderable brings the gesture modules into the package root, so #8671 (or another approved change to that check) has to land first.
  • Add mouse and pen browser tests for the drag, drop and cancel (AST-103 FR3), here or by landing #8140 with this.

[Automated review]

return () => {};
}
const onPointerDown = (event: PointerEvent) => {
if (event.pointerType !== 'mouse' || event.button !== 0) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This path takes only a mouse, and the hold attaches only under a coarse primary pointer (line 1866), so on a touchscreen laptop or with a desktop pen tablet a pen or a finger cannot drag a row. Current spec:AST-103 FR3 has a pen on a fine primary pointer drag without a hold and a finger keep the hold, and spec:AST-094 FR43 attaches gestures for every pointer; #8683 carries that change, so fold it in or land it with this.

export function createReorderable<
TKey extends string | number = string | number,
TTo = number,
>(options: ReorderableOptions<TKey, TTo>): Reorderable<TKey, TTo> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Current spec:AST-103 FR4b says the object exposes attach(container, {items}), and FR1 gives the options an optional positions(); this object has only start, and the options only onReorder and isReorderable, so the spec's own attach example does not type-check. Fold in #8719, land it with this, or have an engineering owner record on main that they ship later.

* Off by default; with a mouse nothing moves.
* @default false
*/
hasAnimatedChanges?: boolean;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This boolean comes from the predecessor stack (#8106). Current component:List FR12 gives this job to an animatedLayout handle from useAnimatedLayout (spec:AST-105 FR1), and AST-105 FR6 says “no other API does this job; and it is not a visual boolean”, so shipping hasAnimatedChanges adds a second public shape that a later release would have to remove.

@vjeux

vjeux commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

An offer that brings #8106's new head into this PR: offer/list-reorder-animated-layout fast-forwards this branch with four commits.

  1. It merges feat(List): animate row inserts, removals and moves through the animatedLayout handle #8106 (942b324). The List reorder now works with animatedLayout in place of hasAnimatedChanges. itemKey is declared once, with wording that covers both of its roles, and the route lock is regenerated by its script. This clears the conflict with main.
  2. The reorder follows feat(List): animate row inserts, removals and moves through the animatedLayout handle #8106's new row-motion module. A dropped row's glide starts at the finger's release speed, so rowMotion gets back an animateRow that records the motion. That lets the row keep its stacking until the glide ends.
  3. Exact-set console checks. The reorder tests now check the exact set of console warnings, so no new warning can hide behind an expected one.
  4. The insertion line from the start of reorder mode (spec:AST-103 FR4). As the mode starts, the line marks the gap before the item, then moves with each move. Before, it appeared only after the first move.

The List, reorder and motion unit tests, typecheck, lint and pnpm check:repo pass. So do the reorder and row-update browser tests in Chromium and WebKit; WebKit skips the cases its driver can't run.

If you want it here, merge the branch.

…t and the route lock

- TreeList.tsx and TreeListItem.tsx: main's meta#8568 (useAnimatedLayout and
  the TreeList glide) against the tree expansion change carried through
  meta#8106. Resolved as meta#8088's own merge of that main resolves the same
  conflict (6801c11): the row renders its children through
  renderChildren, plays its touch slide only without an animated-layout
  handle (useTreeExpansionMotion's isEnabled), and a group collapsing
  under a handle is marked as exiting and inert; this branch's revert
  (dividers stay drawn on press, no Core selection hold) stays applied.
- internal/shadcn-registry/routes.lock.json: regenerated by the docsite's
  generate-data.mjs (UPDATE_SHADCN_ROUTE_LOCK=1); it lists both
  hook-create-reorderable and main's hook-use-animated-layout.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Changes are needed before this can land: the merge with main resolves the earlier conflict, but the branch still carries the open predecessor stack, fails main's root-entry bundle test in CI, and misses parts of current spec:AST-103. Please address these:

  • Update the branch once #8138, #8336, #8106 and #8076 land: 36,308 authored lines change against main, about 30,889 of them that stack.
  • Land #8671, or another approved change to scripts/touch-support-bundle.test.mjs, first: createReorderable's root export brings 14 gesture modules into the root entry, and test-node fails on it.
  • Ship reorder mode's hint (Move up, Move down and Done) here, or land #8337 with this, since AST-103 FR4 and spec:AST-094 FR39 need a way to move a row with a mouse and no drag.
  • Let a pen, and a finger where the primary pointer is fine, drag a row (AST-103 FR3, AST-094 FR43), and add attach and positions (FR1, FR4b), here or by landing #8683 and #8719 with this.
  • Show the insertion line as soon as reorder mode starts (FR4), as your offered branch does, and add mouse and pen browser tests for the drag (FR3), here or with #8140.

[Automated review]

[controller, isTouch],
);
return (
<span id={controller.hintId} hidden>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reorder mode renders only this hidden description: no hint with move buttons and Done, so a mouse user who clicks a handle has nothing on screen to move the row or end the mode (spec:AST-103 FR4, FR4a; spec:AST-094 FR39). Fold the hint in, or land #8337 with this pull request.

return () => {};
}
const onPointerDown = (event: PointerEvent) => {
if (event.pointerType !== 'mouse' || event.button !== 0) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This path takes only a mouse, and the hold attaches only under a coarse primary pointer (line 1866), so a pen, or a finger on a touchscreen laptop, cannot drag a row. Current spec:AST-103 FR3 has a pen on a fine primary pointer drag without a hold and a finger keep the hold, and spec:AST-094 FR43 attaches gestures for every pointer; #8683 carries the change.

*/
private placeModeLine(list: HTMLElement): void {
const row = this.rowOf(this.modeHandle);
if (row == null || this.lastStep == null) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

With lastStep null the line is cleared, so entering reorder mode shows no insertion line until the first arrow press. Current spec:AST-103 FR4 has the line mark the item's place for as long as it is in reorder mode; the fix described in comment 6467628718 would close this.

export function createReorderable<
TKey extends string | number = string | number,
TTo = number,
>(options: ReorderableOptions<TKey, TTo>): Reorderable<TKey, TTo> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Current spec:AST-103 FR4b says the object exposes attach(container, {items}), and FR1 gives the options an optional positions(); this object has only start, and the options only onReorder and isReorderable, so the spec's own attach example does not type-check. Fold in #8719, land it with this, or have an owner record on main that these ship later.

@@ -172,6 +172,9 @@ export * from './Outline';
// Overflow list
export * from './OverflowList';

// Reorder (a collection's `reorderable` prop)
export * from './reorderable';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This export brings the reorder engine, and through ListReorderTouch.ts 14 gesture modules (61,052 bytes), into the root entry, and CI's test-node (2/4) fails scripts/touch-support-bundle.test.mjs “is absent from the root entry” on it. #8671, or another approved change to that check, has to land first.

* Off by default; with a mouse nothing moves.
* @default false
*/
hasAnimatedChanges?: boolean;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This boolean comes from the predecessor stack (#8106). Current component:List FR12 gives this job to an animatedLayout handle from useAnimatedLayout (spec:AST-105 FR1), and AST-105 FR6 says “no other API does this job; and it is not a visual boolean”, so shipping hasAnimatedChanges adds a public shape that would need a breaking removal.

This branch was successfully deployed

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

Labels

CLA Signed This label is managed by the Meta Open Source bot. needs:design-review Affects visuals — Design should review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants