Skip to content

fix: stabilize merged refs across core - #5267

Open
nynexman4464 wants to merge 1 commit into
fix/stabilize-text-refsfrom
fix/migrate-inline-merge-refs
Open

fix: stabilize merged refs across core#5267
nynexman4464 wants to merge 1 commit into
fix/stabilize-text-refsfrom
fix/migrate-inline-merge-refs

Conversation

@nynexman4464

@nynexman4464 nynexman4464 commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Stack

This is 2 of 3 in GitHub stack #5270:

  1. fix: add stable merged refs #5266: add useMergedRefs and fix Text/Heading
  2. fix: stabilize merged refs across core #5267 — this PR: migrate remaining core callsites
  3. lint: forbid inline mergeRefs calls #5269: enforce the safe pattern with ESLint

Review and land in this order. This PR is based directly on #5266.

Why this migration is needed

#5266 fixes the production failure in Text and Heading and introduces useMergedRefs, but the same unsafe construction appears elsewhere in core:

<Component ref={mergeRefs(forwardedRef, internalRef)} />

mergeRefs(...) returns a callback. Calling it during render creates a new callback identity every time, so React detaches the previous ref and attaches the new one even when the DOM element did not change.

The impact varies by component:

  • internal object refs receive unnecessary null → element writes
  • callback refs repeat cleanup and setup work
  • observer/listener-owning refs unsubscribe and resubscribe
  • consumer refs receive detach/attach notifications unrelated to the DOM lifecycle
  • as fix: add stable merged refs #5266 demonstrates, a state-setting ref can amplify another component's temporary update loop into React error XDSAppShell #185

What this PR changes

Migrates every remaining direct JSX use in core from:

ref={mergeRefs(a, b)}

to:

ref={useMergedRefs(a, b)}

The migration covers 43 callsites across 40 core files.

Most hook calls remain directly in unconditional JSX, which is valid under the Rules of Hooks. Calls that were inside conditional branches or after early returns were hoisted to top-level declarations. Both @eslint-react/rules-of-hooks and React Compiler lint pass over every migrated file.

No component API, DOM structure, styling, or intended ref target changes. Only callback identity changes: the merged ref now changes when one of its input refs changes, rather than on every render.

Scope

This PR intentionally covers core only. Lab is outside this migration's requested scope. The enforcement PR is likewise limited to core.

Validation

  • complete core functional suite passed; one table timing benchmark exceeded its budget while other checks ran concurrently, then passed 11/11 alone
  • pnpm -F @astryxdesign/core build
  • pnpm lint
  • focused ESLint over all 40 files: no Hooks-order findings and no unused mergeRefs imports
  • repository scan: zero remaining direct JSX mergeRefs(...) callsites in core
  • exact PR-head Storybook build driven in Chromium:
    • Dialog open/close
    • ContextMenu open/select
    • Carousel scroll
    • SideNav keyboard focus
    • TextInput editing
    • Typeahead search/select
    • no runtime errors in any tested flow

@vercel

vercel Bot commented Aug 20, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
astryx Ready Ready Preview Aug 20, 2026 11:25pm

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 20, 2026
@nynexman4464
nynexman4464 force-pushed the fix/migrate-inline-merge-refs branch from fcff8cd to f9669ec Compare August 20, 2026 22:44
@nynexman4464
nynexman4464 force-pushed the fix/migrate-inline-merge-refs branch from f9669ec to d3b2def Compare August 20, 2026 22:50
@nynexman4464 nynexman4464 changed the title fix: stabilize merged refs across core fix: stabilize merged refs across core and lab Aug 20, 2026
@nynexman4464
nynexman4464 marked this pull request as ready for review August 20, 2026 23:18
@nynexman4464 nynexman4464 changed the title fix: stabilize merged refs across core and lab fix: stabilize merged refs across core Aug 20, 2026
@nynexman4464
nynexman4464 force-pushed the fix/migrate-inline-merge-refs branch from d3b2def to c9cbbfd Compare August 20, 2026 23:21
@github-actions

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

Modified Components

AppShell (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 571 -
Complexity N/A Very High (93) -
AvatarGroup (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 256 -
Complexity N/A High (17) -
BottomSheet (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 3128 -
Complexity N/A Very High (249) -
Breadcrumbs (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 618 -
Complexity N/A Very High (48) -
ButtonGroup (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 122 -
Complexity N/A Low (3) -
Carousel (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 428 -
Complexity N/A Very High (48) -
Chat (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 5387 -
Complexity N/A Very High (438) -
CheckboxInput (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 321 -
Complexity N/A Very High (38) -
ClickableCard (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 196 -
Complexity N/A Medium (13) -
CommandPalette (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 1017 -
Complexity N/A Very High (114) -
ContextMenu (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 390 -
Complexity N/A Very High (43) -
DateInput (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 530 -
Complexity N/A Very High (85) -
DateTimeInput (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 839 -
Complexity N/A Very High (157) -
Dialog (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 626 -
Complexity N/A Very High (79) -
FileInput (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 653 -
Complexity N/A Very High (102) -
Heading (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 152 -
Complexity N/A High (23) -
Item (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 404 -
Complexity N/A Very High (58) -
Lightbox (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 640 -
Complexity N/A Very High (83) -
MobileNav (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 446 -
Complexity N/A Very High (51) -
NavMenu (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 299 -
Complexity N/A High (24) -
Outline (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 672 -
Complexity N/A High (28) -
OverflowList (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 181 -
Complexity N/A High (21) -
Overlay (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 451 -
Complexity N/A Very High (41) -
PowerSearch (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 3670 -
Complexity N/A Very High (336) -
Resizable (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 732 -
Complexity N/A Very High (88) -
SegmentedControl (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 393 -
Complexity N/A Very High (39) -
SelectableCard (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 259 -
Complexity N/A High (27) -
SideNav (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 1954 -
Complexity N/A Very High (186) -
Slider (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 816 -
Complexity N/A Very High (111) -
Switch (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 497 -
Complexity N/A Very High (46) -
TabList (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 791 -
Complexity N/A Very High (41) -
Text (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 521 -
Complexity N/A High (25) -
TextArea (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 424 -
Complexity N/A Very High (65) -
TextInput (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 331 -
Complexity N/A Very High (55) -
TimeInput (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 487 -
Complexity N/A Very High (82) -
Timestamp (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 673 -
Complexity N/A Very High (80) -
Token (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 434 -
Complexity N/A High (21) -
TopNav (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 2066 -
Complexity N/A Very High (150) -
Typeahead (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 1133 -
Complexity N/A Very High (161) -

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@astryxdesign/core N/A 4.8KB 1.2KB

Accessibility Audit

Status: 12 accessibility violation(s) found — 11 serious, 1 moderate.

Chat - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 2/9 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
ClickableCard - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 1/5 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
FileInput - 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/15 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
Heading - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 1/16 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
Outline - 1 issue(s)
  • 🟠 serious: Ensure elements that have scrollable content are accessible by keyboard in Safari
    • Rule: scrollable-region-focusable · Affects 1/10 stories · Learn more
    • WCAG: 2.1.1, 2.1.3 (Level A)
OverflowList - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 1/11 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
PowerSearch - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 2/25 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
SelectableCard - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 1/4 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
TabList - 1 issue(s)
  • 🟡 moderate: Ensure landmarks are unique
    • Rule: landmark-unique · Affects 2/11 stories · Learn more
Text - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 1/23 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
Timestamp - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 1/19 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
Token - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 2/10 stories · Learn more
    • WCAG: 1.4.3 (Level AA)

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

github-actions Bot added a commit that referenced this pull request Aug 20, 2026
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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants