Skip to content

fix(pagination): center the first/last double-chevron caret icons under RTL - #4752

Closed
freddymeta wants to merge 1 commit into
mainfrom
fix/pagination-double-caret-centering
Closed

fix(pagination): center the first/last double-chevron caret icons under RTL#4752
freddymeta wants to merge 1 commit into
mainfrom
fix/pagination-double-caret-centering

Conversation

@freddymeta

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #4723. That PR fixed the vertical centering of the prev/next caret icons by moving the RTL mirror off a display: contents wrapper span and onto the Icon directly via xstyle. The input variant's first/last («/») double-chevron buttons were still using the old wrapper span, so they kept the same few-pixels-high offset — the "double caret looks off" bug.

This applies the identical, already-reviewed fix to both double-chevron carets, so all four carets (first / prev / next / last) now share one consistent approach.

The fix

// before — mirror on a display:contents wrapper (drops the icon out of the
// button's flex-centering context, so the glyph sits a few px high)
icon={
  <span {...stylex.props(rtlStyles.mirror)}>
    <Icon icon="chevronsLeft" size={isSm ? 'sm' : 'md'} />
  </span>
}

// after — mirror rides on the Icon itself (stays a centered flex child,
// still flips under RTL, no wrapper element)
icon={
  <Icon icon="chevronsLeft" size={isSm ? 'sm' : 'md'} xstyle={rtlStyles.mirror} />
}

Why it slipped through

When #4723 landed, the first/last buttons didn't exist on main yet — they came in with the input variant (#4505). #4723 could only fix the carets that existed at the time; the double-chevrons inherited the wrapper pattern and shipped with the offset.

Tests

Extended the #4723 regression test to cover all four carets in one pass (it now renders the input variant so first/last are present) and to assert the mirror class rides on the icon element itself rather than a wrapper. I verified the test genuinely fails when a caret is reverted to the wrapper form. 93/93 Pagination tests, typecheck, and strict lint all green.

RTL flip is preserved (scaleX(-1) still applies via the shared rtlStyles.mirror); centering is verified visually in Storybook.

…er RTL

The prev/next carets were fixed in #4723 by moving the RTL mirror from a
display:contents wrapper span onto the Icon via xstyle, so the glyph stays a
centered flex child. The input variants first/last (<< / >>) double-chevron
buttons still used the old wrapper span, so they kept the same few-pixels-high
offset. Apply the identical xstyle fix to both double-chevron carets. Extends
the #4723 regression test to assert the mirror class rides on the icon element
itself for all four carets (first/prev/next/last).
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 6, 2026
@vercel

vercel Bot commented Aug 6, 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 6, 2026 12:55pm

Request Review

@github-actions github-actions Bot added community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge needs:design-review Affects visuals — Design should review labels Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

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

Pagination (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 641 -
Complexity N/A Very High (92) -

Bundle Size Summary

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

Accessibility Audit

Status: No accessibility violations detected.


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

github-actions Bot added a commit that referenced this pull request Aug 6, 2026
@github-actions github-actions Bot removed the needs:code-review High-risk change (new package/component/API) — needs human code review before merge label Aug 6, 2026
cixzhang added a commit that referenced this pull request Aug 7, 2026
)

* refactor(core): move RTL mirror styles from icon wrappers onto Icon xstyle

The <span {...stylex.props(rtlStyles.mirror)}> wrappers around directional
chevrons exist only to carry the mirror transform. Icon extends BaseProps and
merges xstyle into the same span it already renders, so the style lands on the
same element and one DOM node goes away. Pagination's prev/next carets already
use this shape (#4752); this brings first/last, Carousel, Lightbox and the
Table row-expansion menu icon in line.

Sites: Carousel x2, Lightbox x2, Pagination x2, Table/rowExpansion x1.

* refactor(core): move style-only wrapper styles onto the component root

Each wrapper here carried only positioning/spacing for the single Astryx
component inside it, so the styles move onto that component's own root:

- Lightbox close/prev/next: absolute placement onto IconButton's xstyle.
  navButton switches transform: translateY(-50%) to the individual translate
  property, because on the Button root a transform replaces the Button's own
  transform rules and kills its scale(0.98) press feedback; translate composes
  with them, which is what the wrapper+button pair did before.
- Pagination page-size Selector: the wrapper set width, so it becomes the
  documented width prop. Selector's xstyle targets the trigger box, not the
  field root, so xstyle would have sized the wrong element.
- MobileNav header Heading, Switch FieldStatus, TopNav drawer Divider,
  TopNavMegaMenu Grid: straight move onto xstyle.

Measured with Playwright against Storybook: rendered geometry is unchanged
except where the wrapper was actively mis-centering the icon — Lightbox
prev/next chevrons and Pagination first/last chevrons were 2.5-3px off the
button's vertical center (same defect #4752 fixed for prev/next) and are now
centered.

* chore(changeset): style-only wrapper migration

* docs(utils): rtlStyles now applies to the icons themselves, not wrappers
@freddymeta

Copy link
Copy Markdown
Contributor Author

Closing without merging — superseded by #4775.

#4775 ("migrate style-only wrappers onto component xstyle") swept the same change across all four carets: on main, first/prev/next/last all render <Icon xstyle={rtlStyles.mirror} /> directly, with no display:contents wrapper span. This PR's caret fix is now a no-op against main, so there's nothing left to land here.

@freddymeta freddymeta closed this Aug 7, 2026
@github-actions
github-actions Bot deleted the fix/pagination-double-caret-centering branch August 8, 2026 06:25
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. community Authored by a community contributor (not on the eng/design team) needs:design-review Affects visuals — Design should review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants