Repository navigation
feat!: replace style-derived values with props - #5114
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved moderate issues remain in Avatar background-style precedence and Tooltip ref forwarding and measurement fallback.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Refactors v6 components to remove style flattening and improve Reanimated animated-style support.
Changes:
- Replaces style-derived values with explicit component props.
- Updates Tooltip measurement and ref handling.
- Updates tests, snapshots, examples, linting, and migration documentation.
File summaries
| File | Summary |
|---|---|
src/utils/splitStyles.ts |
Removes obsolete utility. |
src/utils/__tests__/splitStyles.test.ts |
Removes obsolete tests. |
src/components/Tooltip/utils.ts |
Supports direct measurement. |
src/components/Tooltip/Tooltip.tsx |
Adds ref forwarding and measurement. |
src/components/Surface.tsx |
Exports shared visual prop types. |
src/components/DataTable/DataTablePagination.tsx |
Uses trailing icon positioning. |
src/components/Card/utils.tsx |
Removes style-derived radius handling. |
src/components/Card/CardCover.tsx |
Applies clipping radius to the container. |
src/components/Card/Card.tsx |
Uses themed outline color. |
src/components/Button/utils.tsx |
Uses static border-radius keys. |
src/components/Button/Button.tsx |
Adds explicit icon positioning and styling. |
src/components/BottomNavigation/BottomNavigationBar.tsx |
Moves background styling to the outer bar. |
src/components/Avatar/AvatarText.tsx |
Adds an explicit background color prop. |
src/components/Avatar/AvatarImage.tsx |
Adds an explicit background color prop. |
src/components/Avatar/AvatarIcon.tsx |
Adds an explicit background color prop. |
src/components/Appbar/utils.ts |
Removes border extraction. |
src/components/Appbar/AppbarHeader.tsx |
Updates header styling and safe-area handling. |
src/components/Appbar/Appbar.tsx |
Adds visual props and inset-aware sizing. |
src/components/__tests__/Tooltip.test.tsx |
Tests ref forwarding. |
src/components/__tests__/Card/Card.test.tsx |
Updates Card behavior tests. |
src/components/__tests__/Card/__snapshots__/Card.test.tsx.snap |
Updates Card snapshots. |
src/components/__tests__/Button.test.tsx |
Tests icon positioning. |
src/components/__tests__/Avatar.test.tsx |
Uses background color props. |
src/components/__tests__/Appbar/Appbar.test.tsx |
Tests Appbar visual props. |
src/components/__tests__/Appbar/__snapshots__/Appbar.test.tsx.snap |
Updates Appbar snapshots. |
src/components/__tests__/__snapshots__/DataTable.test.tsx.snap |
Updates pagination snapshot. |
src/components/__tests__/__snapshots__/Button.test.tsx.snap |
Updates Button snapshot. |
src/components/__tests__/__snapshots__/BottomNavigation.test.tsx.snap |
Updates navigation snapshots. |
src/components/__tests__/__snapshots__/Avatar.test.tsx.snap |
Updates Avatar snapshots. |
example/src/Examples/ButtonExample.tsx |
Migrates trailing icons. |
example/src/Examples/AvatarExample.tsx |
Migrates background colors. |
example/src/Examples/AppbarExample.tsx |
Migrates Appbar background colors. |
eslint.config.mjs |
Bans source StyleSheet.flatten usage. |
docs/6.x/docs/guides/migration.md |
Documents breaking API changes. |
Review details
Suppressed comments (3)
src/components/Appbar/Appbar.tsx:226
- This changes the Appbar layout contract by adding top and bottom safe-area values to the computed height, but the Appbar tests do not assert the resulting height for either
AppbarorAppbar.Header(including the custom header-height case described in the migration guide). Add a regression case covering the inset calculation so a future refactor cannot drop or double-count these values.
// The safe area insets are applied as padding, so they need to be included in the height
const height =
modeAppbarHeight[mode] +
(safeAreaInsets?.top ?? 0) +
(safeAreaInsets?.bottom ?? 0);
src/components/Tooltip/Tooltip.tsx:201
- The wrapper fallback only runs when the ref is null. A wrapped class or
forwardRefcomponent can yield a non-null custom instance that does not implement React Native'smeasure, so this calls an undefined method and the tooltip crashes instead of falling back as documented. Check that the ref exposesmeasurebefore selecting it; otherwise usechildrenWrapperRef.current.
const target = childRef.current ?? childrenWrapperRef.current;
target?.measure((_x, _y, width, height, pageX, pageY) => {
src/components/Tooltip/Tooltip.tsx:108
- The ref merge only reads
children.props.ref, but React 18 stores an element ref on the element rather than inprops. Since this package declares an unrestricted React peer, wrapping a child with a ref under React 18 will replace the user's ref withsetChildRefand never invoke the original ref, contrary to the forwarding behavior documented by this change. Use a React-version-compatible ref merge and add coverage for the supported React 18 path.
const childOwnRef = isValidChild
? // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
(children.props as TooltipChildProps).ref
: undefined;
// Keep a ref to the wrapped element so it can be measured directly,
// while still forwarding the ref passed by the user (if any)
const setChildRef = React.useCallback(
(node: View | null) => {
childRef.current = node;
if (typeof childOwnRef === 'function') {
childOwnRef(node);
} else if (childOwnRef) {
childOwnRef.current = node;
- Files reviewed: 34/34 changed files
- Comments generated: 4
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…-flatten # Conflicts: # src/components/Button/utils.tsx # src/components/Card/Card.tsx # src/components/Card/CardCover.tsx # src/components/Tooltip/utils.ts
|
Found potential problems with the pull request:
|
# Conflicts: # docs/6.x/docs/guides/migration.md # example/src/Examples/ButtonExample.tsx # src/components/Button/Button.tsx # src/components/Button/utils.tsx # src/components/__tests__/Button.test.tsx # src/components/__tests__/__snapshots__/Banner.test.tsx.snap # src/components/__tests__/__snapshots__/Button.test.tsx.snap # src/components/__tests__/__snapshots__/DataTable.test.tsx.snap # src/components/__tests__/__snapshots__/Menu.test.tsx.snap # src/components/__tests__/__snapshots__/Snackbar.test.tsx.snap
|
Thanks for the review, @lukewalczak. First pass, blockers only.
BREAKING CHANGE: Appbar, Appbar.Header, Avatar and Card no longer read the background color, border radius or outline color from |
Doberjohn
left a comment
There was a problem hiding this comment.
@lukewalczak I posted the two blockers above, the following five items are worth fixing here, but are not introduced by this PR neither blocking the merge. Let's see what can be fixed now that we touched their files.
- Description. It's out of date, and the squash message is built from it. It still mentions
iconPosition(that came with #5097),DataTable.Pagination, snapshots that are no longer in the diff, the closed #4943 and Tooltip ref code that's gone. It should also be under 1000 characters and have before and after screenshots, since the Appbar height and theCard.Coverclipping change visibly. Appbar.Headerheight (migration.md:302).style.heightis now the total height, not the content row, and nothing warns about it:height: 80with a 59pt inset leaves a 21pt row. Please add a before and after, e.g.height: 80 + topwithuseSafeAreaInsets(), plus a line in thestyleJSDoc.- Avatar
styletype (AvatarText.tsx:18,AvatarIcon.tsx:13,AvatarImage.tsx:21).ViewProps & {...}still acceptsbackgroundColor, so the guide's own "before" snippet compiles and silently loses its color.Omit<ViewProps, 'style'> & {...}, as Card and Button do it, makes it a type error. - Tooltip test (
Tooltip.test.tsx:165). The new test also passes onmain, so the real change, which is that the tooltip ignores the child's positioning and anchors to the wrapper, isn't tested. A test with an absolutely positioned child would cover it. - Migration guide, Style section (
migration.md:74). The new list repeats #5097'siconPositionand leaves outtextColorfor the icon color and the wrappingViewfor Tooltip. In the Button section, thelabelStylecolor andfontSizebullets need code changes, so they don't belong under "These need no code change".
|
Checked on Android and iOS (Appbar, Avatar, Button, Card, Bottom Navigation, Tooltip, Data Table): all good. Thanks, @lukewalczak! |
Motivation
Values read from
stylewithStyleSheet.flattencan't work withuseAnimatedStyle, so they move to props, followingSurfacein #5078. ESLint now bansStyleSheet.flatteninsrc.Appbar:backgroundColorand radius props, inset-aware heightAvatar:backgroundColorprop, contrast still derives from itButton:iconSizeprop,textColoralso colors the iconCard:borderColorprop,Card.Coverradius goes on the containerBottomNavigation.Bar: background moves to the outer viewTooltip: anchors to its wrapperRelated issue
Reanimated migration for v6.
Screenshots / Videos
Test plan
Check Appbar, Avatar, Button and Card in the example app.
BREAKING CHANGE:
styleno longer sets Appbar's background or radius, Avatar's background or Card's outline color, use the new props. Appbar's height includessafeAreaInsets. UseiconSizeandtextColorfor Button's icon, and a View around Tooltip for positioning.