Skip to content

perf(core): an overlay's eager import no longer carries the lazy BottomSheet's padding - #8550

Merged
cixzhang merged 5 commits into
meta:mainfrom
vjeux:uikit/overlay-eager-padding
Nov 4, 2026
Merged

cixzhang merged 5 commits into
meta:mainfrom
vjeux:uikit/overlay-eager-padding

Conversation

@vjeux

@vjeux vjeux commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

User impact

Importing Popover, DropdownMenu, Carousel, ContextMenu, DateRangeInput, Markdown, MoreMenu or Table loads BottomSheet's container padding styles up front, though BottomSheet loads only on a phone. (Measured at c4a9ae0, the padding and the focus helper together were about 3.5 KB minified; see "Since main moved" below.)

Problem and solution fit

  • Popover loads its phone BottomSheet with import() (feat(Popover): presentation — a BottomSheet on a phone when asked, as iOS presents a popover #8229), so its import should not carry it.

  • With code splitting, a module both eager code and the lazy chunk import lands in one shared chunk the entry imports statically, keeping every export either side uses.

  • Layout/padding.stylex.ts was one: usePopover uses paddingStyles and useLayer overlayPaddingReset, while BottomSheetPanel uses the container padding variables. Popover's import carried 3,975 B of it, against 1,413 B before feat(Popover): presentation — a BottomSheet on a phone when asked, as iOS presents a popover #8229.

  • utils/focusReturn.ts was another: the utils barrel's isFocusDetached re-export reaches it eagerly, while only BottomSheet uses its focusForLastInput (264 B).

  • Since main moved: useFocusTrap and DropdownMenu now import focusReturn eagerly on main, so Popover's import still carries the focus helper. Only the padding half saves bytes for Popover today. The isFocusDetached module still keeps the utils entry off focusReturn. The size figures under Evidence were measured at c4a9ae0; the pull request's size report gives them at the current head.

Expected behavior and authority

architecture:component-style-authoring INV6: a coarse-pointer feature loads lazily, so the component's import does not carry it.

Smallest restoration

  • paddingStyles and overlayPaddingReset move to their own modules, which padding.stylex.ts re-exports (its public entry is unchanged) and useLayer and usePopover import.
  • isFocusDetached moves to its own module, still re-exported by utils.
  • Two tests follow the move (a source read, and StyleX's development class name).

Evidence

The INV6 size tool's bundle, main c4a9ae0 to this head:

Component Minified Gzip
Carousel −3,824 −973
ContextMenu −3,548 −1,028
Markdown −3,545 −1,033
Table −3,540 −987
Popover −2,880 −728
DateRangeInput −2,875 −620
DropdownMenu −2,566 −628
MoreMenu −2,559 −647

Scope

  • One defect is restored.
  • Separable contradictory or unsettled tagalongs were removed or split.
  • No new public API, visual representation, default, or interaction model is hidden under the bug-fix label.
  • Public text and artifacts contain no internal Meta context.

Testing

  • Core unit tests, touched components: 123 files, 3,205 passed.
  • Root build (no generated changes), typecheck, check:changesets, eslint, prettier: clean.
  • Open pull requests touching these files: 7 of 10 merge cleanly; 3 conflict with main identically without this change.

…omSheet's padding and focus code

Since Popover loads a BottomSheet with import() for its phone presentation (meta#8229), esbuild puts a module that both the eager code and the BottomSheet chunk import into one shared chunk, which the entry imports statically and which keeps every export either side uses. Layout/padding.stylex.ts was such a module: usePopover uses paddingStyles and useLayer uses overlayPaddingReset, while BottomSheetPanel uses the container padding variables, so every component that imports Popover eagerly carried 3,975 B of it instead of 1,413. utils/focusReturn.ts was another, reached eagerly through the utils barrel's isFocusDetached re-export while only BottomSheet uses its focusForLastInput (264 B). paddingStyles and overlayPaddingReset now live in their own modules, which padding.stylex.ts re-exports for its public entry and which useLayer and usePopover import directly; isFocusDetached moves to its own module, which the barrel re-exports.
@vercel

vercel Bot commented Oct 26, 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 3, 2026 8:07pm UTC

Request Review

@github-actions github-actions Bot added the needs:design-review Affects visuals — Design should review label Oct 26, 2026
@astracat-bot

astracat-bot Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

AI review status for this pull request.

Review status Updated
🟢 Reviewed (for maintainers only) Nov 3, 2026, 8:18 PM UTC

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

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

🔎 Preview · af0d1f6

Storybook · Sandbox · built from this PR's head

Modified components

Component Size LoC Visual · A11y · RTL
TreeList 38.2 kB (+107 B) · 5.0 kB CSS (0) — — · — · —
Selector 78.4 kB (+31 B) · 15.7 kB CSS (0) — — · — · —
lab/CommentPin 47.5 kB (+31 B) · 1.2 kB CSS (0) — — · — · —
200 more components
Component Size LoC Visual · A11y · RTL
Pagination 87.3 kB (+25 B) · 16.1 kB CSS (0) — — · — · —
Toolbar 34.8 kB (+25 B) · 7.9 kB CSS (0) — — · — · —
BottomSheet 37.3 kB (+9 B) · 7.5 kB CSS (0) — — · — · —
lab/TransferListSelector 83.2 kB (+9 B) · 1.9 kB CSS (0) — — · — · —
Citation 19.9 kB (+5 B) · 4.4 kB CSS (0) — — · — · —
MultiSelector 73.7 kB (+5 B) · 15.3 kB CSS (0) — — · — · —
CommandPaletteFooter 17.0 kB (+4 B) · 3.7 kB CSS (0) — — · — · —
lab/DiffViewer 71.8 kB (+4 B) · 2.1 kB CSS (0) — — · — · —
richtext/RichTextView 259.1 kB (+4 B) · 2.3 kB CSS (0) — — · — · —
ChatSystemMessage 6.8 kB (+2 B) · 3.8 kB CSS (0) — — · — · —
Dialog 19.0 kB (+1 B) · 6.7 kB CSS (0) — — · — · —
Overlay 19.8 kB (+1 B) · 4.0 kB CSS (0) — — · — · —
richtext/RichTextEditor 278.7 kB (+1 B) · 2.6 kB CSS (0) — — · — · —
charts/ChartAxis 6.7 kB (0) · 112 B CSS (0) — — · — · —
AspectRatio 3.8 kB (0) · 3.6 kB CSS (0) — — · — · —
AvatarStatusDot 7.2 kB (0) · 3.6 kB CSS (0) — — · — · —
Badge 4.0 kB (0) · 4.0 kB CSS (0) — — · — · —
Blockquote 3.6 kB (0) · 3.5 kB CSS (0) — — · — · —
BottomSheetSwitcher 17.0 kB (0) · 3.4 kB CSS (0) — — · — · —
Breadcrumbs 16.0 kB (0) · 3.4 kB CSS (0) — — · — · —
ButtonGroup 9.0 kB (0) · 3.4 kB CSS (0) — — · — · —
ChatComposerDrawer 17.5 kB (0) · 4.7 kB CSS (0) — — · — · —
ChatMessage 16.7 kB (0) · 3.7 kB CSS (0) — — · — · —
ChatMessageBubble 7.1 kB (0) · 3.7 kB CSS (0) — — · — · —
ChatMessageMetadata 19.6 kB (0) · 4.1 kB CSS (0) — — · — · —
ChatTokenizedText 7.1 kB (0) · 4.0 kB CSS (0) — — · — · —
Code 3.6 kB (0) · 3.5 kB CSS (0) — — · — · —
CollapsibleGroup 6.5 kB (0) · 3.3 kB CSS (0) — — · — · —
CommandPaletteEmpty 6.2 kB (0) · 3.5 kB CSS (0) — — · — · —
CommandPaletteGroup 3.5 kB (0) · 3.5 kB CSS (0) — — · — · —
CommandPaletteItem 10.0 kB (0) · 3.6 kB CSS (0) — — · — · —
DropdownMenuCheckboxItem 18.3 kB (0) · 5.9 kB CSS (0) — — · — · —
DropdownMenuGroup 6.2 kB (0) · 3.4 kB CSS (0) — — · — · —
DropdownMenuRadioGroup 6.1 kB (0) · 3.3 kB CSS (0) — — · — · —
DropdownMenuRadioItem 18.3 kB (0) · 5.9 kB CSS (0) — — · — · —
FormLayout 6.4 kB (0) · 3.5 kB CSS (0) — — · — · —
Grid 4.4 kB (0) · 3.8 kB CSS (0) — — · — · —
GridSpan 3.5 kB (0) · 3.4 kB CSS (0) — — · — · —
InputGroupText 6.4 kB (0) · 3.9 kB CSS (0) — — · — · —
Kbd 16.7 kB (0) · 3.6 kB CSS (0) — — · — · —
MetadataList 16.7 kB (0) · 3.8 kB CSS (0) — — · — · —
MetadataListItem 6.6 kB (0) · 3.5 kB CSS (0) — — · — · —
NavIcon 3.5 kB (0) · 3.4 kB CSS (0) — — · — · —
Outline 21.9 kB (0) · 4.2 kB CSS (0) — — · — · —
OverflowList 8.6 kB (0) · 3.6 kB CSS (0) — — · — · —
ResizeHandle 19.5 kB (0) · 4.3 kB CSS (0) — — · — · —
SegmentedControlItem 10.4 kB (0) · 4.0 kB CSS (0) — — · — · —
SelectorOption 16.6 kB (0) · 5.4 kB CSS (0) — — · — · —
SideNavSection 6.6 kB (0) · 3.7 kB CSS (0) — — · — · —
Skeleton 3.8 kB (0) · 3.8 kB CSS (0) — — · — · —
Step 27.9 kB (0) · 5.6 kB CSS (0) — — · — · —
Tab 11.3 kB (0) · 4.2 kB CSS (0) — — · — · —
TableBody 3.4 kB (0) · 3.3 kB CSS (0) — — · — · —
TableFooter 3.4 kB (0) · 3.3 kB CSS (0) — — · — · —
TableHeader 3.4 kB (0) · 3.3 kB CSS (0) — — · — · —
TableRow 6.5 kB (0) · 4.0 kB CSS (0) — — · — · —
ToggleButtonGroup 6.4 kB (0) · 3.4 kB CSS (0) — — · — · —
Token 25.2 kB (0) · 4.8 kB CSS (0) — — · — · —
TopNavItem 10.7 kB (0) · 4.0 kB CSS (0) — — · — · —
TopNavMegaMenuFeaturedCard 6.9 kB (0) · 3.6 kB CSS (0) — — · — · —
TopNavMegaMenuItem 10.8 kB (0) · 4.2 kB CSS (0) — — · — · —
TypeaheadItem 6.3 kB (0) · 3.6 kB CSS (0) — — · — · —
lab/ChartDotGL 7.4 kB (0) · 20 B CSS (0) — — · — · —
lab/ChartDotGLInteractive 8.3 kB (0) · 20 B CSS (0) — — · — · —
lab/ChartHeatmapGL 8.5 kB (0) · 20 B CSS (0) — — · — · —
lab/ChartStreamGL 7.5 kB (0) · 20 B CSS (0) — — · — · —
lab/ChatReasoning 7.0 kB (0) · 967 B CSS (0) — — · — · —
lab/ChatTypingIndicator 24.8 kB (0) · 612 B CSS (0) — — · — · —
lab/ChatUnreadDivider 3.6 kB (0) · 348 B CSS (0) — — · — · —
lab/CircularProgress 8.5 kB (0) · 1.1 kB CSS (0) — — · — · —
lab/CodeEditor 14.1 kB (0) · 743 B CSS (0) — — · — · —
lab/LogStream 8.0 kB (0) · 1.6 kB CSS (0) — — · — · —
lab/Stat 4.2 kB (0) · 646 B CSS (0) — — · — · —
lab/SVGIcon 7.6 kB (0) · 764 B CSS (0) — — · — · —
lab/ThreeDScatterGL 7.6 kB (0) · 20 B CSS (0) — — · — · —
CommandPaletteList 16.0 kB (−2 B) · 3.4 kB CSS (0) — — · — · —
DropdownMenuItem 17.5 kB (−2 B) · 5.5 kB CSS (0) — — · — · —
Collapsible 22.7 kB (−3 B) · 4.5 kB CSS (0) — — · — · —
NavHeadingMenu 14.8 kB (−10 B) · 3.4 kB CSS (0) — — · — · —
lab/TourStep 58.6 kB (−20 B) · 590 B CSS (0) — — · — · —
Section 7.6 kB (+7 B) · 6.3 kB CSS (−54 B) — — · — · —
Layout 6.8 kB (0) · 2.3 kB CSS (−53 B) — — · — · —
LayoutPanel 7.6 kB (+3 B) · 4.9 kB CSS (−67 B) — — · — · —
CommandPalette 50.7 kB (−71 B) · 12.3 kB CSS (0) — — · — · —
LayoutContent 6.0 kB (+1 B) · 1.7 kB CSS (−79 B) — — · — · —
LayoutFooter 5.9 kB (+1 B) · 1.6 kB CSS (−80 B) — — · — · —
LayoutHeader 6.0 kB (−4 B) · 1.6 kB CSS (−81 B) — — · — · —
richtext/RichTextEditorToolbar 225.5 kB (−86 B) · 454 B CSS (0) — — · — · —
SelectableCard 14.6 kB (+1 B) · 7.2 kB CSS (−91 B) — — · — · —
Card 6.5 kB (−1 B) · 6.4 kB CSS (−91 B) — — · — · —
ClickableCard 14.6 kB (+1 B) · 7.0 kB CSS (−93 B) — — · — · —
ScrollableArea 10.7 kB (−1 B) · 4.3 kB CSS (−110 B) — — · — · —
Center 4.2 kB (−3 B) · 4.6 kB CSS (−109 B) — — · — · —
DrawerHeader 48.8 kB (−116 B) · 11.6 kB CSS (0) — — · — · —
HStack 5.9 kB (0) · 1.6 kB CSS (−119 B) — — · — · —
Stack 5.7 kB (0) · 1.6 kB CSS (−119 B) — — · — · —
VStack 5.9 kB (0) · 1.6 kB CSS (−119 B) — — · — · —
lab/Comments 259.0 kB (−194 B) · 2.5 kB CSS (0) — — · — · —
lab/EmojiPicker 71.0 kB (−194 B) · 722 B CSS (0) — — · — · —
DialogHeader 48.7 kB (−206 B) · 10.2 kB CSS (0) — — · — · —
Drawer 39.0 kB (−254 B) · 8.2 kB CSS (0) — — · — · —
AppShell 70.6 kB (−269 B) · 12.2 kB CSS (0) — — · — · —
lab/CommentThread 253.8 kB (−285 B) · 2.4 kB CSS (0) — — · — · —
TableSelectionToolbar 55.4 kB (−299 B) · 11.8 kB CSS (0) — — · — · —
PowerSearch · Storybook 194.0 kB (−311 B) · 21.6 kB CSS (0) 6,789 (0) — · — · —
TimeInput 92.4 kB (−321 B) · 14.3 kB CSS (0) — — · — · —
DateTimeInput 162.3 kB (−329 B) · 17.1 kB CSS (0) — — · — · —
DateInput 105.6 kB (−334 B) · 15.4 kB CSS (0) — — · — · —
lab/CommentComposer 105.1 kB (−338 B) · 1.9 kB CSS (0) — — · — · —
lab/MobileTokenizer 103.7 kB (−387 B) · 880 B CSS (0) — — · — · —
lab/MobilePowerSearch 218.4 kB (−400 B) · 1.2 kB CSS (0) — — · — · —
AlertDialog 83.9 kB (−534 B) · 13.1 kB CSS (0) — — · — · —
lab/ChatReactionBar 66.9 kB (−601 B) · 1.1 kB CSS (0) — — · — · —
lab/ChatEmojiPicker 66.3 kB (−602 B) · 773 B CSS (0) — — · — · —
TopNavMenu 59.0 kB (+37 B) · 9.9 kB CSS (−688 B) — — · — · —
ComplexSelector 56.3 kB (+17 B) · 10.4 kB CSS (−695 B) — — · — · —
DropdownMenu 73.4 kB (−684 B) · 15.5 kB CSS (0) — — · — · —
SideNavHeading 59.7 kB (+20 B) · 9.9 kB CSS (−705 B) — — · — · —
SideNavItem 55.3 kB (+12 B) · 9.8 kB CSS (−697 B) — — · — · —
MoreMenu 73.7 kB (−689 B) · 15.5 kB CSS (0) — — · — · —
TopNavHeading 59.1 kB (+15 B) · 9.7 kB CSS (−706 B) — — · — · —
Typeahead 63.5 kB (−11 B) · 11.2 kB CSS (−696 B) — — · — · —
BaseTypeahead 55.8 kB (−19 B) · 9.6 kB CSS (−690 B) — — · — · —
Popover · Storybook 52.5 kB (−725 B) · 12.7 kB CSS (0) 1,038 (0) — · — · —
TopNavMegaMenu 54.7 kB (−34 B) · 10.6 kB CSS (−691 B) — — · — · —
ChatComposerInput 59.9 kB (−49 B) · 10.0 kB CSS (−694 B) — — · — · —
ChatComposerTokenElement 59.9 kB (−49 B) · 10.0 kB CSS (−694 B) — — · — · —
TabMenu 56.2 kB (−44 B) · 9.8 kB CSS (−699 B) — — · — · —
ChatComposer 61.9 kB (−61 B) · 10.6 kB CSS (−698 B) — — · — · —
BreadcrumbItem 68.3 kB (−105 B) · 10.8 kB CSS (−688 B) — — · — · —
Markdown 145.4 kB (−917 B) · 18.4 kB CSS (0) — — · — · —
Table 84.4 kB (−961 B) · 16.1 kB CSS (0) — — · — · —
lab/ListInput 82.6 kB (−1.0 kB) · 1.6 kB CSS (0) — — · — · —
AvatarGroup 38.1 kB (+56 B) · 5.5 kB CSS (−1.1 kB) — — · — · —
Avatar 35.3 kB (+51 B) · 5.4 kB CSS (−1.1 kB) — — · — · —
TableCell 76.0 kB (−1.1 kB) · 15.9 kB CSS (0) — — · — · —
TableHeaderCell 75.6 kB (−1.1 kB) · 15.6 kB CSS (0) — — · — · —
lab/TransferList 75.6 kB (−1.1 kB) · 1.7 kB CSS (0) — — · — · —
lab/Schedule 60.9 kB (−1.1 kB) · 3.9 kB CSS (0) — — · — · —
ChatLayout 49.0 kB (+3 B) · 9.2 kB CSS (−1.1 kB) — — · — · —
AvatarGroupOverflow 39.3 kB (+37 B) · 5.5 kB CSS (−1.1 kB) — — · — · —
Timestamp 21.3 kB (−1 B) · 8.9 kB CSS (−1.1 kB) — — · — · —
ContextMenu 74.8 kB (−1.1 kB) · 15.4 kB CSS (0) — — · — · —
SegmentedControl 82.5 kB (+21 B) · 6.7 kB CSS (−1.1 kB) — — · — · —
Lightbox · Storybook 52.8 kB (+19 B) · 9.1 kB CSS (−1.1 kB) 833 (0) — · — · —
Tooltip 21.3 kB (+7 B) · 3.9 kB CSS (−1.1 kB) — — · — · —
HoverCard 19.2 kB (+6 B) · 3.9 kB CSS (−1.1 kB) — — · — · —
ChatToolCalls 25.9 kB (0) · 8.2 kB CSS (−1.1 kB) — — · — · —
RadioList 41.6 kB (−2 B) · 6.4 kB CSS (−1.1 kB) — — · — · —
Heading 7.9 kB (0) · 4.9 kB CSS (−1.1 kB) — — · — · —
Text 7.4 kB (−1 B) · 4.9 kB CSS (−1.1 kB) — — · — · —
Field 40.2 kB (−6 B) · 6.3 kB CSS (−1.1 kB) — — · — · —
ChatLayoutScrollButton 46.3 kB (+1 B) · 8.9 kB CSS (−1.1 kB) — — · — · —
FieldLabel 36.4 kB (+4 B) · 4.8 kB CSS (−1.1 kB) — — · — · —
InfoTip 38.1 kB (+5 B) · 5.1 kB CSS (−1.1 kB) — — · — · —
InputGroup 42.4 kB (+7 B) · 7.3 kB CSS (−1.1 kB) — — · — · —
LayerProvider 63.6 kB (+6 B) · 9.4 kB CSS (−1.1 kB) — — · — · —
Spinner 18.5 kB (0) · 5.7 kB CSS (−1.1 kB) — — · — · —
Calendar 54.7 kB (+4 B) · 9.3 kB CSS (−1.1 kB) — — · — · —
RadioListItem 51.7 kB (−11 B) · 9.0 kB CSS (−1.1 kB) — — · — · —
SideNavCollapseButton 46.7 kB (+11 B) · 8.8 kB CSS (−1.1 kB) — — · — · —
TextArea 47.6 kB (−6 B) · 8.8 kB CSS (−1.1 kB) — — · — · —
Timer 9.6 kB (0) · 5.9 kB CSS (−1.1 kB) — — · — · —
ProgressBar 10.8 kB (0) · 6.2 kB CSS (−1.1 kB) — — · — · —
Switch 87.6 kB (−6 B) · 9.5 kB CSS (−1.1 kB) — — · — · —
Slider 89.4 kB (−3 B) · 8.3 kB CSS (−1.1 kB) — — · — · —
Toast 59.7 kB (+6 B) · 9.0 kB CSS (−1.1 kB) — — · — · —
ChatMessageList 22.9 kB (+1 B) · 6.9 kB CSS (−1.1 kB) — — · — · —
MobileNavToggle 46.1 kB (+4 B) · 8.7 kB CSS (−1.1 kB) — — · — · —
TopNav 54.1 kB (+7 B) · 9.6 kB CSS (−1.1 kB) — — · — · —
CheckboxList 43.7 kB (+1 B) · 7.5 kB CSS (−1.1 kB) — — · — · —
CheckboxListItem 53.8 kB (−7 B) · 10.0 kB CSS (−1.1 kB) — — · — · —
Link 43.3 kB (0) · 6.9 kB CSS (−1.1 kB) — — · — · —
StatusDot 23.5 kB (−4 B) · 5.2 kB CSS (−1.1 kB) — — · — · —
Button 45.8 kB (−1 B) · 8.7 kB CSS (−1.1 kB) — — · — · —
ChatDictationButton 46.4 kB (0) · 8.8 kB CSS (−1.1 kB) — — · — · —
TabList 35.4 kB (−12 B) · 6.4 kB CSS (−1.1 kB) — — · — · —
ToggleButton 46.7 kB (0) · 8.8 kB CSS (−1.1 kB) — — · — · —
DropdownMenuSubMenu 56.5 kB (−7 B) · 8.8 kB CSS (−1.1 kB) — — · — · —
FileInput 54.3 kB (+7 B) · 9.7 kB CSS (−1.1 kB) — — · — · —
NumberInput 55.7 kB (+3 B) · 10.1 kB CSS (−1.1 kB) — — · — · —
CommandPaletteInput 26.8 kB (0) · 7.4 kB CSS (−1.1 kB) — — · — · —
IconButton 45.8 kB (−5 B) · 8.7 kB CSS (−1.1 kB) — — · — · —
ChatSendButton 46.2 kB (−5 B) · 8.7 kB CSS (−1.1 kB) — — · — · —
CheckboxInput 49.1 kB (−12 B) · 8.7 kB CSS (−1.1 kB) — — · — · —
Banner 47.7 kB (−1 B) · 9.2 kB CSS (−1.1 kB) — — · — · —
TextInput 53.4 kB (+3 B) · 9.9 kB CSS (−1.1 kB) — — · — · —
Thumbnail 50.1 kB (−4 B) · 10.3 kB CSS (−1.1 kB) — — · — · —
MobileNav 52.5 kB (−2 B) · 9.3 kB CSS (−1.1 kB) — — · — · —
Stepper 47.5 kB (−11 B) · 8.9 kB CSS (−1.1 kB) — — · — · —
ListItem 53.2 kB (−19 B) · 10.0 kB CSS (−1.1 kB) — — · — · —
SideNav 68.8 kB (−31 B) · 10.1 kB CSS (−1.1 kB) — — · — · —
CodeBlock 59.7 kB (+20 B) · 10.0 kB CSS (−1.2 kB) — — · — · —
Tokenizer · Storybook 70.1 kB (−1.2 kB) · 17.1 kB CSS (0) 2,115 (0) — · — · —
DateRangeInput 71.4 kB (−611 B) · 11.2 kB CSS (−693 B) — — · — · —
charts/ChartLegend 24.6 kB (−1.4 kB) · 20 B CSS (0) — — · — · —
charts/Chart 27.0 kB (−1.4 kB) · 20 B CSS (0) — — · — · —
charts/ChartTooltip 24.6 kB (−1.4 kB) · 20 B CSS (0) — — · — · —
Carousel 50.1 kB (−1.1 kB) · 9.5 kB CSS (−1.1 kB) — — · — · —
ContextMenuItem 24.6 kB (−1.6 kB) · 3.9 kB CSS (−1.1 kB) — — · — · —

Package size: @astryxdesign/core 6.24 MB packed (+1.1 kB); no new dependencies.

API changes: none in this pull request

Committed API report behind this build: core 2 rows; run pnpm api:report.

Wide change (7 components): add ci:run-visual, ci:run-a11y or ci:run-rtl to run them.


Generated by PR Enrichment workflow | View full report

@vjeux
vjeux marked this pull request as draft October 29, 2026 22:37

@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.

This looks ready to merge: moving paddingStyles, overlayPaddingReset and isFocusDetached into their own modules keeps BottomSheet-only code out of the eager bundles of Popover, DropdownMenu and the components built on them, while the public entry points, the built stylesheet and the rendered stories stay the same. The visual report compares against an older baseline: the Selector sheet, Collapsible and AppShell stories it flags render identically before and after this change. One optional fix: the changeset's "about 3.5 KB minified" fits Carousel, ContextMenu, Markdown and Table, but Popover saves about 2.9 KB, DropdownMenu about 2.6 KB and DateInput only 66 B, so "up to about 3.8 KB minified (about 1 KB gzip)" would be accurate.

[Automated review]

Comment thread .changeset/overlay-eager-padding.md Outdated
'@astryxdesign/core': patch
---

[perf] Components that import Popover no longer load BottomSheet's container padding styles and focus helper up front. Popover loads a BottomSheet on demand for its phone presentation, and a bundler that splits code put the modules both of them use into one chunk that loads with the component, keeping every export either side uses: about 3.5 KB minified in Popover, Carousel, DateRangeInput, DropdownMenu, Table and the other components that import Popover or DropdownMenu. `paddingStyles` and `overlayPaddingReset` now have their own modules, still exported from `@astryxdesign/core/Layout/padding.stylex`, and `isFocusDetached` has its own module, still exported from `@astryxdesign/core/utils`. Rendering is unchanged.

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.

Optional: "about 3.5 KB minified" fits Carousel, ContextMenu, Markdown and Table, but Popover saves about 2.9 KB, DateRangeInput about 2.9 KB, DropdownMenu about 2.6 KB and DateInput only 66 B. "Up to about 3.8 KB minified (about 1 KB gzip)" would be accurate.

cixzhang pushed a commit that referenced this pull request Oct 31, 2026
…rs (#9130)

## User impact

A `DropdownMenu` whose trigger also has a tooltip (a custom trigger in `Tooltip`, or the default button's `tooltip`) rewrites that button's inline style on every render around it. The menu's anchor comes off and goes back, so `anchor-name` is rewritten and its two names swap order. A page that renders often never settles. We found it moving one app onto Astryx.

## Problem and solution fit

- `DropdownMenu`'s trigger ref was a new function each render, so React called it again on every commit (`null`, then the element), moving the anchor each time.
- Stabilizing those refs alone was not enough. They wrap `usePopover`'s `triggerRef`, keyed on the whole layer object, which changes whenever `onShow` or `onHide` does; `DropdownMenu`'s `onShow` changes with an inline `renderTrigger`, `onClick` or `onOpenChange`. That version still made 2 and 4 writes per render in the tests below.
- So the fix is in the hook:

```ts
const layerRef = layer.ref;
const triggerRef = useCallback(
  (el: HTMLElement | null) => {
    triggerElementRef.current = el;
    layerRef(el);
  },
  [layerRef],
);
```

The callback reads nothing else from the layer, and `layer.ref` (`useLayer`'s anchor callback, keyed on the anchor name and anchor-clearance option) reads only refs, so nothing goes stale.

## Expected behavior and authority

Tooltip (#5951) and `useHoverCard` (#6606) got the same fix: a trigger ref keeps its identity when nothing about the trigger changes. No API or record changes.

## Smallest restoration

- `usePopover`: `triggerRef` is keyed on `layer.ref` instead of `layer`.
- `DropdownMenu`: stable refs on its three trigger paths, a custom trigger, the default button (still forwarding the caller's `ref`) and the bottom-sheet trigger.
- Triggers that take `usePopover`'s ref directly get it stable too: ComplexSelector's built-in trigger, DateTimeInput's date field and Breadcrumbs.

Not chosen: stabilizing each `DropdownMenu` callback instead, leaving every other `usePopover` caller churning.

Also edited by open #7677 and #8550, both of which merge cleanly with this change.

## Evidence

- Before (main eae5d92): one parent render writes the trigger's style 2 times with a custom trigger in `Tooltip`, and 4 times with the default button's `tooltip` and an inline `onOpenChange`. The two anchor names swap order, and `usePopover`'s `triggerRef` changes whenever `onShow` or `onHide` does.
- After: 0 writes, the same order, the same ref. A caller's `ref` on the default button still gets the element.

## Scope

- [x] One defect is restored.
- [x] Separable contradictory or unsettled tagalongs were removed or split.
- [x] No new public API, visual representation, default, or interaction model is hidden under the bug-fix label.
- [x] Public text and artifacts contain no internal Meta context.

## Testing

How to check:
1. Render `<DropdownMenu button={{label: 'Actions', tooltip: 'More'}} onOpenChange={() => {}}>` inside a component that renders every second.
2. Watch the button's `style` attribute in the browser's Elements panel. Before: it flashes every second. After: it stays still.

The new cases in `DropdownMenu.test.tsx` and `Popover.test.tsx` count the trigger's style writes with a MutationObserver. They fail on main and pass with the fix.

Local gates at 08a5dc5:
- The DropdownMenu, Popover, Tooltip and Layer suites, plus every other component that uses `usePopover`'s trigger ref (Breadcrumbs, Chat, ComplexSelector, DateInput, DateRangeInput, DateTimeInput, MultiSelector): 2,171 tests pass. The 6 new cases fail on main.
- The DropdownMenu, Tooltip and Popover Chromium specs: 217 passed.
- Core typecheck, ESLint with no warnings, Prettier, `pnpm check:repo` and the Storybook build.
- `pnpm test:ui` and `pnpm test:node`: the same failures as on main, none in these components.
main added isFocusLost, noteFocusWithin, moveFocusLeftBehind and
prepareFocusReturnOnRemoval to focusReturn.ts; they stay there, importing
isFocusDetached from its own module. Callers main added since (usePopover,
Tokenizer, PowerSearch for isFocusDetached; layoutReset, Lightbox, MobileNav
for overlayPaddingReset) import the split modules. The changeset drops its
size figure: main's own eager focusReturn imports changed it, and the pull
request's size report gives it at this head.

Co-authored-by: Cindy Zhang <cindyxz@meta.com>

@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: the padding split works, but the release note promises more than this head delivers.

  • The changeset and title say Popover's import no longer loads BottomSheet's focus helper, but hooks/useFocusTrap.ts still imports isFocusLost from utils/focusReturn.ts, so focusForLastInput stays in the eager import of Popover, DropdownMenu, DateRangeInput, Table and most other components that use them (only Carousel drops it); limit the changeset, title and size figures to the padding styles, or also move isFocusLost out of focusReturn.ts.

With the padding move, Popover and DropdownMenu save about 2.6 KB minified (about 0.7 KB gzip), and Carousel, ContextMenu, Markdown, Table and Tokenizer save 3.5 to 5.3 KB, while the stylesheet and the public entry points stay the same. A few new header comments run past the short-sentence comment style; the inline notes suggest shorter wording.

[Automated review]

Comment thread .changeset/overlay-eager-padding.md Outdated
'@astryxdesign/core': patch
---

[perf] Components that import Popover no longer load BottomSheet's container padding styles and focus helper up front. Popover loads a BottomSheet on demand for its phone presentation, and a bundler that splits code put the modules both of them use into one chunk that loads with the component, keeping every export either side uses, in Popover, Carousel, DateRangeInput, DropdownMenu, Table and the other components that import Popover or DropdownMenu. `paddingStyles` and `overlayPaddingReset` now have their own modules, still exported from `@astryxdesign/core/Layout/padding.stylex`, and `isFocusDetached` has its own module, still exported from `@astryxdesign/core/utils`. Rendering is unchanged.

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.

This promises that components importing Popover stop loading the focus helper up front, but hooks/useFocusTrap.ts still imports isFocusLost from utils/focusReturn.ts, so focusForLastInput stays in the eager import of Popover, DropdownMenu, DateRangeInput and Table; only Carousel drops it. Please limit the note (and the title) to the padding styles, for example:

[perf] Popover, DropdownMenu, Carousel, ContextMenu, DateRangeInput, Markdown, MoreMenu, Table and Tokenizer no longer load BottomSheet's container padding styles up front: 2,591 to 5,301 B less minified JavaScript (611 to 1,252 B gzip). `paddingStyles` and `overlayPaddingReset` now have their own modules, still exported from `@astryxdesign/core/Layout/padding.stylex`, and `isFocusDetached` has its own module, still exported from `@astryxdesign/core/utils`. Rendering is unchanged.

Or also move isFocusLost out of focusReturn.ts, so Popover's eager useFocusTrap no longer reaches it.

Comment on lines +16 to +18
// In their own modules so an overlay's eager code imports them without this
// one, and a lazily loaded overlay that uses the container padding styles
// below keeps those out of the chunk it shares with that code.

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.

Optional: this is one 37-word sentence with two topics. A shorter version that keeps the reason:

// Eager overlay code imports these from their own modules. The lazy
// BottomSheet then keeps the container padding styles below in its own chunk.

Comment on lines +10 to +12
* somewhere the user chose. Apart from focusReturn.ts so the utils barrel
* does not reach focusForLastInput: an overlay loaded with import() that
* uses it then keeps it out of the chunk it shares with eager code.

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.

Optional: the second half does not hold where useFocusTrap or a menu hook imports focusReturn.ts, which is most overlays at this head. Suggested: "Apart from focusReturn.ts, so the utils barrel does not reach focusForLastInput."

… the focus helper

CodeBunny on meta#8550: useFocusTrap imports focusReturn eagerly on main, so
Popover still loads the focus helper up front.

Co-authored-by: Cindy Zhang <cindyxz@meta.com>

@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: the padding split works and the changeset is now accurate, but two things still need fixing before this can merge.

  • The title still says an overlay's eager import drops BottomSheet's focus code, but hooks/useFocusTrap.ts imports isFocusLost from utils/focusReturn.ts, so the focus helper stays in the eager import of Popover, DropdownMenu and every other overlay (only Carousel drops it); retitle to the padding styles, or also move isFocusLost out of focusReturn.ts.
  • Layout/overlayPaddingReset.stylex.ts line 31 keeps (#5208) from the moved comment, and the comment-provenance lint baseline allows it only in padding.stylex.ts, so pnpm lint reports an error in CI's strict mode once the pull request leaves draft; drop the reference and the stale baseline entry.

With the padding move, Popover and DropdownMenu save about 2.6 KB minified (about 0.7 KB gzip), and Carousel, ContextMenu, Markdown, Table and Tokenizer save 3.5 to 5.3 KB, while the stylesheet and the public entry points stay the same. The description's new correction bullet lost its inline code formatting, so it no longer says which module moved.

[Automated review]

* a fixed/top-layer `<dialog>` is a DOM descendant of the padded page while
* being nowhere near it on screen. It inherits values describing padding that
* is not there, and its content compensates against phantom space: a `Section`
* inside a 640px sheet rendered 672px wide and hung off both edges (#5208).

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.

This (#5208) moved here from padding.stylex.ts, where the comment-provenance lint baseline allows it. In this new file it is not baselined, so ESLint reports it as an error in CI's strict mode (CI=true), and pnpm lint fails once the pull request leaves draft. Dropping the reference fixes it; the baseline entry for padding.stylex.ts in internal/eslint-plugin-astryx/no-comment-provenance.baseline.json can go too:

 * inside a 640px sheet rendered 672px wide and hung off both edges.

CodeBunny on meta#8550: strict lint refuses a comment that names an issue in a
new file.

Co-authored-by: Cindy Zhang <cindyxz@meta.com>
@cixzhang cixzhang changed the title perf(core): an overlay's eager import no longer carries the lazy BottomSheet's padding and focus code perf(core): an overlay's eager import no longer carries the lazy BottomSheet's padding Nov 3, 2026

@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: the padding split works, and the title and the moved comment are now fixed, but the changeset still promises the saving to more components than get it.

  • .changeset/overlay-eager-padding.md says every component that imports Popover or DropdownMenu stops loading BottomSheet's container padding styles up front, but Selector, MultiSelector, Pagination and PowerSearch still load Layout/padding.stylex.js eagerly through Section or Stack, and DateInput and DateTimeInput through their eager BottomSheetPanel, so please name the nine components that gain (Popover, DropdownMenu, Carousel, ContextMenu, DateRangeInput, Markdown, MoreMenu, Table and Tokenizer) instead.

With the split, those nine components load 2.6 to 5.3 KB less minified JavaScript up front, while the stylesheet and the public entry points stay the same. Optionally, the comment-provenance baseline can drop its now-unused #5208 entry for padding.stylex.ts.

[Automated review]

Comment thread .changeset/overlay-eager-padding.md Outdated
'@astryxdesign/core': patch
---

[perf] Components that import Popover no longer load BottomSheet's container padding styles up front. Popover loads a BottomSheet on demand for its phone presentation, and a bundler that splits code put the padding module both of them use into one chunk that loads with the component, keeping every export either side uses, in Popover, Carousel, DateRangeInput, DropdownMenu, Table and the other components that import Popover or DropdownMenu. `paddingStyles` and `overlayPaddingReset` now have their own modules, still exported from `@astryxdesign/core/Layout/padding.stylex`, and `isFocusDetached` has its own module, still exported from `@astryxdesign/core/utils`. Rendering is unchanged.

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.

This promises the saving to every component that imports Popover or DropdownMenu, but at this head Selector, MultiSelector, Pagination and PowerSearch still load Layout/padding.stylex.js up front (Section or Stack in their eager import pulls the shared module in with BottomSheet's exports), and DateInput and DateTimeInput load it with their eager BottomSheetPanel. Naming the components that gain keeps the note accurate, for example:

[perf] Popover, DropdownMenu, Carousel, ContextMenu, DateRangeInput, Markdown, MoreMenu, Table and Tokenizer no longer load BottomSheet's container padding styles up front.

… padding

CodeBunny on meta#8550: Selector, PowerSearch, DateInput and others still load
it, so the changeset names the measured components only.

Co-authored-by: Cindy Zhang <cindyxz@meta.com>

@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.

This looks ready to merge: the changeset now names only the components that gain, and each of Popover, DropdownMenu, Carousel, ContextMenu, DateRangeInput, Markdown, MoreMenu and Table drops Layout/padding.stylex.js from its eager import (2.6 to 3.9 KB less minified JavaScript), while the built stylesheet and the public entry points stay the same.

Optional cleanups: the new @position notes in overlayPaddingReset.stylex.ts and paddingStyles.stylex.ts are single 37-word sentences (suggestions inline), the comment-provenance baseline still lists #5208 for padding.stylex.ts, and the header of overlayPaddingReset.test.tsx still says the reset lives in padding.stylex.ts.

[Automated review]

Comment on lines +8 to +11
* Its own module so an overlay's eager code (useLayer) imports it without
* padding.stylex.ts: a lazily loaded overlay that uses the container padding
* styles there then keeps them out of the eager chunk it shares with this
* module.

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.

Optional (comment style): this reason is one 37-word sentence. A shorter version that keeps it:

 *   Its own module, so eager overlay code imports it without padding.stylex.ts.
 *   A lazily loaded BottomSheet then keeps the container padding styles out of
 *   the eager chunk.

Comment on lines +7 to +10
* @position Layout utility, re-exported by padding.stylex.ts. Its own module so an
* overlay's eager code (usePopover) imports it without padding.stylex.ts:
* a lazily loaded overlay that uses the container padding styles there then
* keeps them out of the eager chunk it shares with this module.

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.

Optional (comment style): the same 37-word sentence as in overlayPaddingReset.stylex.ts. For example:

 * @position Layout utility, re-exported by padding.stylex.ts. Its own module,
 *   so eager overlay code imports it without padding.stylex.ts. A lazily loaded
 *   BottomSheet then keeps the container padding styles out of the eager chunk.

@cixzhang
cixzhang marked this pull request as ready for review November 3, 2026 21:06
@cixzhang cixzhang added the ci:run A maintainer lets this outside contributor's pull request run CI (AST-030 FR17) label Nov 3, 2026
@cixzhang
cixzhang marked this pull request as draft November 3, 2026 23:04
@cixzhang
cixzhang marked this pull request as ready for review November 3, 2026 23:05
@cixzhang cixzhang closed this Nov 4, 2026
@cixzhang cixzhang reopened this Nov 4, 2026
@cixzhang
cixzhang merged commit 9462110 into meta:main Nov 4, 2026
204 of 209 checks passed

This branch was successfully deployed

1 active deployment
Preview — af0d1f65 Deployed Nov 3, 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. needs:design-review Affects visuals — Design should review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants