Skip to content

CORE-2710: Compose render-callback style in react-aria-components wrappers - #137

Open
OpenStaxClaude wants to merge 1 commit into
mainfrom
CORE-2710-compose-render-props-style
Open

CORE-2710: Compose render-callback style in react-aria-components wrappers#137
OpenStaxClaude wants to merge 1 commit into
mainfrom
CORE-2710-compose-render-props-style

Conversation

@OpenStaxClaude

@OpenStaxClaude OpenStaxClaude commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Jira: CORE-2710

The style half of the bug fixed for className in CORE-2708 / #136.

Problem

react-aria-components types style on anything extending StyleRenderProps as CSSProperties | ((values) => CSSProperties). Three wrappers merged the caller's style into their own CSS-variable object with a spread:

const popoverStyle: CSSPropertiesWithVariables = {
  '--navbar-popover-border-color': colors.palette.darkGreen,
  ...style   // <-- if style is a function, this contributes nothing
};

Spreading a function into an object literal is legal TypeScript and copies no enumerable own properties, so a caller-supplied style callback was silently discarded. Unlike the className case there was no type error to catch it.

Fix

NavBarMenuItem, NavBarPopover and TreeCheckbox now build their CSS variables inside a composeRenderProps callback, which resolves the callback form before the merge:

const popoverStyle = composeRenderProps(
  style,
  (resolvedStyle): CSSPropertiesWithVariables => ({
    '--navbar-popover-border-color': colors.palette.darkGreen,
    ...resolvedStyle
  })
);

The caller still spreads last, so its ability to override the wrapper's CSS variables is preserved.

TreeCheckbox also drops its as unknown as RACCheckboxProps['style'] double cast in favour of a CSSPropertiesWithVariables return-type annotation, which types the custom properties properly rather than casting them away.

Acceptance criteria

  • The three components merge a render-callback style instead of discarding it.
  • The object form is unchanged, including caller-last precedence over the wrapper's variables.
  • Each component has a callback-style test, plus an override test and an object-form test. Confirmed failing before the fix: stashing only the two source files leaves 6 failed, 11 passed across the two specs — the 6 callback/override cases fail, the object-form cases pass.
  • No snapshot churn. All 116 snapshots pass untouched; the emitted inline styles for the object form are byte-identical (RAC's useRenderProps resolves both forms to the same object, and none of MenuItem/Popover/Checkbox supply a defaultStyle).

Notes

Copilot AI 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.

Pull request overview

Fixes render-callback style handling in React Aria component wrappers while preserving caller override precedence.

Changes:

  • Composes callback and object styles for three wrappers.
  • Adds regression and override-precedence tests.
  • Corrects Jira secret references and documents the fix.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/components/Tree/TreeCheckbox.tsx Composes checkbox styles safely.
src/components/Tree/TreeCheckbox.spec.tsx Tests callback and object styles.
src/components/NavBarMenuButtons.tsx Composes menu item and popover styles.
src/components/NavBarMenuButtons.spec.tsx Adds style regression tests.
CHANGELOG.md Documents the corrected behavior.
.github/workflows/checks.yml Corrects Jira secret names.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

…ppers

NavBarMenuItem, NavBarPopover and TreeCheckbox merged the caller's `style`
into their own CSS-variable object with a spread. RAC types `style` as
`CSSProperties | ((renderProps) => CSSProperties)`, and spreading a function
into an object literal copies no enumerable own properties, so a
render-callback `style` was silently discarded — with no type error to catch
it.

Each wrapper now builds its CSS variables inside a `composeRenderProps`
callback, so the caller's declarations land on the element in both forms.
The caller still spreads last and keeps its ability to override the
wrapper's variables, and the emitted inline styles for the object form are
unchanged (snapshots pass untouched).

TreeCheckbox's `as unknown as RACCheckboxProps['style']` double cast is
replaced by a `CSSPropertiesWithVariables` return-type annotation, which
types the custom properties properly instead of casting them away.
@RoyEJohnson
RoyEJohnson force-pushed the CORE-2710-compose-render-props-style branch from a35fb0f to 61e5db8 Compare August 27, 2026 19:46
@RoyEJohnson
RoyEJohnson marked this pull request as ready for review August 27, 2026 19:51
@RoyEJohnson
RoyEJohnson requested a review from bethshook August 27, 2026 19:52
OpenStaxClaude added a commit that referenced this pull request Aug 31, 2026
Addresses review: the four wrappers that bind CSS custom properties merged
the caller's style with an object spread. react-aria-components types style
as `CSSProperties | ((renderProps) => CSSProperties)`, and spreading a
function copies nothing, so a render-callback style was silently dropped and
replaced by the wrapper's static object.

ProfileMenuButton, ProfileMenuItem, HelpMenuButton and HelpMenuItem now build
their variables inside a composeRenderProps callback, the same fix applied to
NavBarMenuItem/NavBarPopover/TreeCheckbox in CORE-2710 (#137). The caller
still spreads last, so its ability to override the wrapper's variables is
preserved, and the object form is unchanged (all 116 snapshots pass untouched).

ProfileMenuItem and HelpMenuItem pass style down to NavBarMenuItem, so they
need the CORE-2710 fix underneath to reach the DOM; this branch is stacked on
that PR rather than duplicating it.

Each wrapper gets a callback test, an override test and an object-form test.
Confirmed failing before the fix: stashing only the two component files leaves
8 failed, 33 passed across the two specs -- the 8 callback/override cases fail,
the 4 object-form cases pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
OpenStaxClaude added a commit that referenced this pull request Aug 31, 2026
Addresses Copilot's two review comments. ProfileMenuButton and HelpMenuButton
merged the caller's style into their CSS-variable object with a spread.
react-aria-components types style as `CSSProperties | ((renderProps) =>
CSSProperties)`, and spreading a function copies nothing, so a render-callback
style was silently dropped and replaced by the wrapper's static object. Both now
build their variables inside composeRenderProps, the same shape CORE-2710 (#137)
uses for NavBarMenuItem/NavBarPopover/TreeCheckbox. The caller still spreads
last, and the object form is unchanged -- all 116 snapshots pass untouched.

Their style reaches react-aria's Button directly (HelpMenuButton's by way of
NavBarButton, which passes it straight through), so this works against main as
it stands.

ProfileMenuItem and HelpMenuItem have the same defect but are left spreading for
now, with a comment saying why: they hand style to NavBarMenuItem, which spreads
it as well, so composing only here would send a function into that spread and
lose these variables along with the caller's style. Both levels have to compose
together, which needs #137 on main first.

Eight tests: three per button wrapper (render-callback merged, render-callback
overriding the wrapper variables, object form merging caller-last) plus
object-form coverage for each menu item. Confirmed failing before the fix:
stashing only the two component files leaves 4 failed, 33 passed across the two
specs -- the four callback and override cases fail, the object-form cases pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants