From 2cb2b81570d13ba4ab8d7ef3197b057356d29832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Muzyk?= Date: Mon, 29 Jun 2026 10:58:09 +0200 Subject: [PATCH 1/8] refactor: non standard component; avatar --- src/components/Avatar/AvatarIcon.tsx | 25 ++++---- src/components/Avatar/AvatarImage.tsx | 17 +++--- src/components/Avatar/AvatarText.tsx | 24 ++++---- src/components/Avatar/utils.ts | 33 ++++++++++ .../__snapshots__/Avatar.test.tsx.snap | 60 ++++++++++++++----- 5 files changed, 110 insertions(+), 49 deletions(-) create mode 100644 src/components/Avatar/utils.ts diff --git a/src/components/Avatar/AvatarIcon.tsx b/src/components/Avatar/AvatarIcon.tsx index 9c3b813e59..5e0c5d0c00 100644 --- a/src/components/Avatar/AvatarIcon.tsx +++ b/src/components/Avatar/AvatarIcon.tsx @@ -2,13 +2,11 @@ import { StyleSheet, View } from 'react-native'; import type { StyleProp, ViewProps, ViewStyle } from 'react-native'; import { useInternalTheme } from '../../core/theming'; -import { white } from '../../theme/colors'; +import { cornerFull } from '../../theme/tokens/sys/shape'; import type { ThemeProp } from '../../types'; -import getContrastingColor from '../../utils/getContrastingColor'; import Icon from '../Icon'; import type { IconSource } from '../Icon'; - -const defaultSize = 64; +import { DEFAULT_SIZE, ICON_SIZE_RATIO, resolveAvatarColors } from './utils'; export type Props = ViewProps & { /** @@ -45,17 +43,18 @@ export type Props = ViewProps & { */ const Avatar = ({ icon, - size = defaultSize, + size = DEFAULT_SIZE, style, theme: themeOverrides, ...rest }: Props) => { const theme = useInternalTheme(themeOverrides); - const { backgroundColor = theme.colors?.primary, ...restStyle } = - StyleSheet.flatten(style) || {}; - const textColor = - rest.color ?? - getContrastingColor(backgroundColor, white, 'rgba(0, 0, 0, .54)'); + const { backgroundColor, ...restStyle } = StyleSheet.flatten(style) || {}; + const { background, textColor } = resolveAvatarColors({ + theme, + backgroundColor, + color: rest.color, + }); return ( - + ); }; diff --git a/src/components/Avatar/AvatarImage.tsx b/src/components/Avatar/AvatarImage.tsx index 51330dd70c..17d61354ff 100644 --- a/src/components/Avatar/AvatarImage.tsx +++ b/src/components/Avatar/AvatarImage.tsx @@ -8,11 +8,11 @@ import type { ViewStyle, } from 'react-native'; +import { DEFAULT_SIZE, resolveAvatarColors } from './utils'; import { useInternalTheme } from '../../core/theming'; +import { cornerFull } from '../../theme/tokens/sys/shape'; import type { ThemeProp } from '../../types'; -const defaultSize = 64; - export type AvatarImageSource = | ImageSourcePropType | ((props: { size: number }) => React.ReactNode); @@ -74,7 +74,7 @@ export type Props = ViewProps & { * ``` */ const AvatarImage = ({ - size = defaultSize, + size = DEFAULT_SIZE, source, style, onError, @@ -87,8 +87,9 @@ const AvatarImage = ({ testID, ...rest }: Props) => { - const { colors } = useInternalTheme(themeOverrides); - const { backgroundColor = colors?.primary } = StyleSheet.flatten(style) || {}; + const theme = useInternalTheme(themeOverrides); + const { backgroundColor } = StyleSheet.flatten(style) || {}; + const { background } = resolveAvatarColors({ theme, backgroundColor }); return ( { const theme = useInternalTheme(themeOverrides); - const { backgroundColor = theme.colors?.primary, ...restStyle } = - StyleSheet.flatten(style) || {}; - const textColor = - customColor ?? - getContrastingColor(backgroundColor, white, 'rgba(0, 0, 0, .54)'); + const { backgroundColor, ...restStyle } = StyleSheet.flatten(style) || {}; + const { background, textColor } = resolveAvatarColors({ + theme, + backgroundColor, + color: customColor, + }); const { fontScale } = useWindowDimensions(); return ( @@ -77,8 +76,8 @@ const AvatarText = ({ { width: size, height: size, - borderRadius: size / 2, - backgroundColor, + borderRadius: cornerFull, + backgroundColor: background, }, styles.container, restStyle, @@ -88,6 +87,7 @@ const AvatarText = ({ { + const usingDefault = backgroundColor == null; + const background = backgroundColor ?? theme.colors.primaryContainer; + const textColor = + color ?? + (usingDefault + ? theme.colors.onPrimaryContainer + : getContrastingColor(background, white, 'rgba(0, 0, 0, .54)')); + return { background, textColor }; +}; diff --git a/src/components/__tests__/__snapshots__/Avatar.test.tsx.snap b/src/components/__tests__/__snapshots__/Avatar.test.tsx.snap index 9e55666cef..074f5ba05d 100644 --- a/src/components/__tests__/__snapshots__/Avatar.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/Avatar.test.tsx.snap @@ -5,8 +5,8 @@ exports[`renders avatar with icon 1`] = ` style={ [ { - "backgroundColor": "rgba(103, 80, 164, 1)", - "borderRadius": 32, + "backgroundColor": "rgba(234, 221, 255, 1)", + "borderRadius": 9999, "height": 64, "width": 64, }, @@ -26,7 +26,7 @@ exports[`renders avatar with icon 1`] = ` style={ [ { - "color": "#ffffff", + "color": "rgba(33, 0, 93, 1)", "fontSize": 38.4, }, [ @@ -56,7 +56,7 @@ exports[`renders avatar with icon and custom background color 1`] = ` [ { "backgroundColor": "#f44336", - "borderRadius": 32, + "borderRadius": 9999, "height": 64, "width": 64, }, @@ -105,8 +105,8 @@ exports[`renders avatar with image 1`] = ` style={ [ { - "backgroundColor": "rgba(103, 80, 164, 1)", - "borderRadius": 32, + "backgroundColor": "rgba(234, 221, 255, 1)", + "borderRadius": 9999, "height": 64, "width": 64, }, @@ -123,7 +123,7 @@ exports[`renders avatar with image 1`] = ` } style={ { - "borderRadius": 32, + "borderRadius": 9999, "height": 64, "width": 64, } @@ -137,8 +137,8 @@ exports[`renders avatar with text 1`] = ` style={ [ { - "backgroundColor": "rgba(103, 80, 164, 1)", - "borderRadius": 32, + "backgroundColor": "rgba(234, 221, 255, 1)", + "borderRadius": 9999, "height": 64, "width": 64, }, @@ -172,7 +172,14 @@ exports[`renders avatar with text 1`] = ` "textAlignVertical": "center", }, { - "color": "#ffffff", + "fontFamily": "System", + "fontSize": 16, + "fontWeight": "500", + "letterSpacing": 0.15, + "lineHeight": 24, + }, + { + "color": "rgba(33, 0, 93, 1)", "fontSize": 32, "lineHeight": 64, }, @@ -192,7 +199,7 @@ exports[`renders avatar with text and custom background color 1`] = ` [ { "backgroundColor": "#f44336", - "borderRadius": 32, + "borderRadius": 9999, "height": 64, "width": 64, }, @@ -225,6 +232,13 @@ exports[`renders avatar with text and custom background color 1`] = ` "textAlign": "center", "textAlignVertical": "center", }, + { + "fontFamily": "System", + "fontSize": 16, + "fontWeight": "500", + "letterSpacing": 0.15, + "lineHeight": 24, + }, { "color": "#ffffff", "fontSize": 32, @@ -245,8 +259,8 @@ exports[`renders avatar with text and custom colors 1`] = ` style={ [ { - "backgroundColor": "rgba(103, 80, 164, 1)", - "borderRadius": 32, + "backgroundColor": "rgba(234, 221, 255, 1)", + "borderRadius": 9999, "height": 64, "width": 64, }, @@ -279,6 +293,13 @@ exports[`renders avatar with text and custom colors 1`] = ` "textAlign": "center", "textAlignVertical": "center", }, + { + "fontFamily": "System", + "fontSize": 16, + "fontWeight": "500", + "letterSpacing": 0.15, + "lineHeight": 24, + }, { "color": "#FFFFFF", "fontSize": 32, @@ -299,8 +320,8 @@ exports[`renders avatar with text and custom size 1`] = ` style={ [ { - "backgroundColor": "rgba(103, 80, 164, 1)", - "borderRadius": 48, + "backgroundColor": "rgba(234, 221, 255, 1)", + "borderRadius": 9999, "height": 96, "width": 96, }, @@ -334,7 +355,14 @@ exports[`renders avatar with text and custom size 1`] = ` "textAlignVertical": "center", }, { - "color": "#ffffff", + "fontFamily": "System", + "fontSize": 16, + "fontWeight": "500", + "letterSpacing": 0.15, + "lineHeight": 24, + }, + { + "color": "rgba(33, 0, 93, 1)", "fontSize": 48, "lineHeight": 96, }, From 6e07fc718bb8fb76f5f4dd524e12df2455a2d0df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Muzyk?= Date: Mon, 29 Jun 2026 14:22:42 +0200 Subject: [PATCH 2/8] refactor: banner --- src/components/Banner.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/Banner.tsx b/src/components/Banner.tsx index 4f28cf0390..b7f44d90f5 100644 --- a/src/components/Banner.tsx +++ b/src/components/Banner.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { Animated, StyleSheet, View } from 'react-native'; +import { Animated, Easing, StyleSheet, View } from 'react-native'; import type { StyleProp, ViewStyle } from 'react-native'; import type { LayoutChangeEvent } from 'react-native'; @@ -14,6 +14,7 @@ import { useInternalTheme } from '../core/theming'; import type { $Omit, $RemoveChildren, Theme, ThemeProp } from '../types'; const DEFAULT_MAX_WIDTH = 960; +const ICON_SIZE = 40; export type Props = $Omit<$RemoveChildren, 'mode'> & { /** @@ -148,7 +149,7 @@ const Banner = ({ const showCallback = useLatestCallback(onShowAnimationFinished); const hideCallback = useLatestCallback(onHideAnimationFinished); - const { scale } = theme.animation; + const { duration, easing } = theme.motion; const opacity = position.interpolate({ inputRange: [0, 0.1, 1], @@ -159,20 +160,22 @@ const Banner = ({ if (visible) { // show Animated.timing(position, { - duration: 250 * scale, + duration: duration.medium1, toValue: 1, useNativeDriver: false, + easing: Easing.bezier(...easing.standard), }).start(showCallback); } else { // hide Animated.timing(position, { - duration: 200 * scale, + duration: duration.short4, toValue: 0, useNativeDriver: false, + easing: Easing.bezier(...easing.standard), }).start(hideCallback); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [visible, position, scale]); + }, [visible, position, duration, easing]); const handleLayout = ({ nativeEvent }: LayoutChangeEvent) => { const { height } = nativeEvent.layout; @@ -221,7 +224,7 @@ const Banner = ({ {icon ? ( - + ) : null} Date: Mon, 29 Jun 2026 15:32:28 +0200 Subject: [PATCH 3/8] refactor: data table --- src/components/DataTable/DataTableCell.tsx | 1 + .../DataTable/DataTablePagination.tsx | 3 +- src/components/DataTable/DataTableTitle.tsx | 20 +- .../__snapshots__/DataTable.test.tsx.snap | 297 ++++++++++-------- 4 files changed, 182 insertions(+), 139 deletions(-) diff --git a/src/components/DataTable/DataTableCell.tsx b/src/components/DataTable/DataTableCell.tsx index ce59206af6..39769f6936 100644 --- a/src/components/DataTable/DataTableCell.tsx +++ b/src/components/DataTable/DataTableCell.tsx @@ -105,6 +105,7 @@ const CellContent = ({ return ( )} { Animated.timing(spinAnim, { toValue: sortDirection === 'ascending' ? 0 : 1, - duration: 150, + duration: duration.short3, + easing: Easing.bezier(...easing.standard), useNativeDriver: true, }).start(); - }, [sortDirection, spinAnim]); + }, [sortDirection, spinAnim, duration, easing]); const textColor = theme.colors.onSurface; @@ -132,6 +141,7 @@ const DataTableTitle = ({ {icon} Date: Thu, 20 Aug 2026 16:53:43 +0200 Subject: [PATCH 4/8] fix: respect animation scale in Banner --- src/components/Banner.tsx | 7 +++--- src/components/__tests__/Banner.test.tsx | 27 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/components/Banner.tsx b/src/components/Banner.tsx index b7f44d90f5..5c4a24623d 100644 --- a/src/components/Banner.tsx +++ b/src/components/Banner.tsx @@ -150,6 +150,7 @@ const Banner = ({ const hideCallback = useLatestCallback(onHideAnimationFinished); const { duration, easing } = theme.motion; + const { scale } = theme.animation; const opacity = position.interpolate({ inputRange: [0, 0.1, 1], @@ -160,7 +161,7 @@ const Banner = ({ if (visible) { // show Animated.timing(position, { - duration: duration.medium1, + duration: duration.medium1 * scale, toValue: 1, useNativeDriver: false, easing: Easing.bezier(...easing.standard), @@ -168,14 +169,14 @@ const Banner = ({ } else { // hide Animated.timing(position, { - duration: duration.short4, + duration: duration.short4 * scale, toValue: 0, useNativeDriver: false, easing: Easing.bezier(...easing.standard), }).start(hideCallback); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [visible, position, duration, easing]); + }, [visible, position, duration, easing, scale]); const handleLayout = ({ nativeEvent }: LayoutChangeEvent) => { const { height } = nativeEvent.layout; diff --git a/src/components/__tests__/Banner.test.tsx b/src/components/__tests__/Banner.test.tsx index 80bd3e9017..d5f3047de6 100644 --- a/src/components/__tests__/Banner.test.tsx +++ b/src/components/__tests__/Banner.test.tsx @@ -145,6 +145,33 @@ describe('animations', () => { hideCallback = undefined; }); + it('uses zero-duration animations when animation scale is disabled', async () => { + const timingSpy = jest.spyOn(Animated, 'timing'); + const view = await render( + + Text + + ); + + expect(timingSpy).toHaveBeenLastCalledWith( + expect.anything(), + expect.objectContaining({ duration: 0 }) + ); + + await view.rerender( + + Text + + ); + + expect(timingSpy).toHaveBeenLastCalledWith( + expect.anything(), + expect.objectContaining({ duration: 0 }) + ); + + timingSpy.mockRestore(); + }); + describe('when component is rendered hidden', () => { // This behaviour is probably a bug. Needs triage before next version. it('will fire onHideAnimationFinished on mount', async () => { From e384ae10915d42cdd527c6a6011be992e9ad4d5b Mon Sep 17 00:00:00 2001 From: Mikita Kliushun Date: Tue, 25 Aug 2026 17:57:53 +0200 Subject: [PATCH 5/8] fix: respect animation scale in DataTable title --- src/components/DataTable/DataTableTitle.tsx | 5 +++-- src/components/__tests__/DataTable.test.tsx | 24 ++++++++++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/components/DataTable/DataTableTitle.tsx b/src/components/DataTable/DataTableTitle.tsx index c41e9607ef..c6ed902e98 100644 --- a/src/components/DataTable/DataTableTitle.tsx +++ b/src/components/DataTable/DataTableTitle.tsx @@ -101,15 +101,16 @@ const DataTableTitle = ({ ); const { duration, easing } = theme.motion; + const { scale } = theme.animation; React.useEffect(() => { Animated.timing(spinAnim, { toValue: sortDirection === 'ascending' ? 0 : 1, - duration: duration.short3, + duration: duration.short3 * scale, easing: Easing.bezier(...easing.standard), useNativeDriver: true, }).start(); - }, [sortDirection, spinAnim, duration, easing]); + }, [sortDirection, spinAnim, duration, easing, scale]); const textColor = theme.colors.onSurface; diff --git a/src/components/__tests__/DataTable.test.tsx b/src/components/__tests__/DataTable.test.tsx index 49f863720a..de147e6520 100644 --- a/src/components/__tests__/DataTable.test.tsx +++ b/src/components/__tests__/DataTable.test.tsx @@ -1,4 +1,6 @@ -import { describe, expect, it } from '@jest/globals'; +import { Animated } from 'react-native'; + +import { describe, expect, it, jest } from '@jest/globals'; import { render, screen } from '../../test-utils'; import Checkbox from '../Checkbox'; @@ -20,6 +22,26 @@ describe('DataTable.Header', () => { }); describe('DataTable.Title', () => { + it('uses zero-duration sort animation when animation scale is disabled', async () => { + const timingSpy = jest.spyOn(Animated, 'timing'); + + await render( + + Dessert + + ); + + expect(timingSpy).toHaveBeenLastCalledWith( + expect.anything(), + expect.objectContaining({ duration: 0 }) + ); + + timingSpy.mockRestore(); + }); + it('renders data table title with sort icon', async () => { const tree = ( await render( From b318fad3724fc55d57add54760e46596e226ee33 Mon Sep 17 00:00:00 2001 From: Mikita Kliushun Date: Mon, 21 Sep 2026 18:05:02 +0200 Subject: [PATCH 6/8] fix: simplify Avatar custom color handling --- docs/6.x/docs/guides/migration.md | 13 +++++++++++++ src/components/Avatar/AvatarIcon.tsx | 7 +++---- src/components/Avatar/AvatarImage.tsx | 5 ++--- src/components/Avatar/AvatarText.tsx | 4 +--- src/components/Avatar/utils.ts | 19 +++---------------- .../__snapshots__/Avatar.test.tsx.snap | 16 ++++++++++------ 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/docs/6.x/docs/guides/migration.md b/docs/6.x/docs/guides/migration.md index a4d7123a09..e78bb93c40 100644 --- a/docs/6.x/docs/guides/migration.md +++ b/docs/6.x/docs/guides/migration.md @@ -159,6 +159,19 @@ e.g.: - The default elevation changed from level `1` to level `3`. - The `style` prop no longer configures the background color or border radius. You can override `theme.colors.surfaceContainerHigh` and `theme.shapes.corner.extraLarge` using the `theme` prop instead. +### Avatar + +`Avatar.Icon` and `Avatar.Text` no longer derive their icon or text color from `style.backgroundColor`. Specify matching `color` explicitly when using custom background color. + +```diff + +``` + ### TextInput The Paper 6.x `TextInput` is a complete rewrite with a new API. Import the component the same way, but note that the props and behavior have changed significantly. diff --git a/src/components/Avatar/AvatarIcon.tsx b/src/components/Avatar/AvatarIcon.tsx index f5f579b3e4..db63668891 100644 --- a/src/components/Avatar/AvatarIcon.tsx +++ b/src/components/Avatar/AvatarIcon.tsx @@ -46,14 +46,13 @@ const Avatar = ({ size = DEFAULT_SIZE, style, theme: themeOverrides, + color: customColor, ...rest }: Props) => { const theme = useInternalTheme(themeOverrides); - const { backgroundColor, ...restStyle } = StyleSheet.flatten(style) || {}; const { background, textColor } = resolveAvatarColors({ theme, - backgroundColor, - color: rest.color, + color: customColor, }); return ( @@ -66,7 +65,7 @@ const Avatar = ({ backgroundColor: background, }, styles.container, - restStyle, + style ?? {}, ]} {...rest} > diff --git a/src/components/Avatar/AvatarImage.tsx b/src/components/Avatar/AvatarImage.tsx index 17d707630d..b51b078e85 100644 --- a/src/components/Avatar/AvatarImage.tsx +++ b/src/components/Avatar/AvatarImage.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { Image, StyleSheet, View } from 'react-native'; +import { Image, View } from 'react-native'; import type { ImageProps, ImageSourcePropType, @@ -88,8 +88,7 @@ const AvatarImage = ({ ...rest }: Props) => { const theme = useInternalTheme(themeOverrides); - const { backgroundColor } = StyleSheet.flatten(style) || {}; - const { background } = resolveAvatarColors({ theme, backgroundColor }); + const { background } = resolveAvatarColors({ theme }); return ( { const theme = useInternalTheme(themeOverrides); - const { backgroundColor, ...restStyle } = StyleSheet.flatten(style) || {}; const { background, textColor } = resolveAvatarColors({ theme, - backgroundColor, color: customColor, }); const { fontScale } = useWindowDimensions(); @@ -80,7 +78,7 @@ const AvatarText = ({ backgroundColor: background, }, styles.container, - restStyle, + style ?? {}, ]} {...rest} > diff --git a/src/components/Avatar/utils.ts b/src/components/Avatar/utils.ts index b5739d319b..32d687c82e 100644 --- a/src/components/Avatar/utils.ts +++ b/src/components/Avatar/utils.ts @@ -1,33 +1,20 @@ -import type { ColorValue } from 'react-native'; - -import { white } from '../../theme/colors'; import type { InternalTheme } from '../../theme/types'; -import getContrastingColor from '../../utils/getContrastingColor'; export const DEFAULT_SIZE = 64; export const ICON_SIZE_RATIO = 0.6; /** * Resolve background and content colors for an avatar. - * - No custom background → MD3 container pair (primaryContainer / onPrimaryContainer). - * - Custom background → keep luminance-based contrast so arbitrary per-user - * colors stay legible (contentColorFor only handles known theme roles). */ export const resolveAvatarColors = ({ theme, - backgroundColor, color, }: { theme: InternalTheme; - backgroundColor?: ColorValue; color?: string; }) => { - const usingDefault = backgroundColor == null; - const background = backgroundColor ?? theme.colors.primaryContainer; - const textColor = - color ?? - (usingDefault - ? theme.colors.onPrimaryContainer - : getContrastingColor(background, white, 'rgba(0, 0, 0, .54)')); + const background = theme.colors.primaryContainer; + const textColor = color ?? theme.colors.onPrimaryContainer; + return { background, textColor }; }; diff --git a/src/components/__tests__/__snapshots__/Avatar.test.tsx.snap b/src/components/__tests__/__snapshots__/Avatar.test.tsx.snap index 074f5ba05d..afc6e66557 100644 --- a/src/components/__tests__/__snapshots__/Avatar.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/Avatar.test.tsx.snap @@ -55,7 +55,7 @@ exports[`renders avatar with icon and custom background color 1`] = ` style={ [ { - "backgroundColor": "#f44336", + "backgroundColor": "rgba(234, 221, 255, 1)", "borderRadius": 9999, "height": 64, "width": 64, @@ -64,7 +64,9 @@ exports[`renders avatar with icon and custom background color 1`] = ` "alignItems": "center", "justifyContent": "center", }, - {}, + { + "backgroundColor": "#f44336", + }, ] } > @@ -76,7 +78,7 @@ exports[`renders avatar with icon and custom background color 1`] = ` style={ [ { - "color": "#ffffff", + "color": "rgba(33, 0, 93, 1)", "fontSize": 38.4, }, [ @@ -198,7 +200,7 @@ exports[`renders avatar with text and custom background color 1`] = ` style={ [ { - "backgroundColor": "#f44336", + "backgroundColor": "rgba(234, 221, 255, 1)", "borderRadius": 9999, "height": 64, "width": 64, @@ -207,7 +209,9 @@ exports[`renders avatar with text and custom background color 1`] = ` "alignItems": "center", "justifyContent": "center", }, - {}, + { + "backgroundColor": "#f44336", + }, ] } > @@ -240,7 +244,7 @@ exports[`renders avatar with text and custom background color 1`] = ` "lineHeight": 24, }, { - "color": "#ffffff", + "color": "rgba(33, 0, 93, 1)", "fontSize": 32, "lineHeight": 64, }, From 57c83217cdceffe41007d98a6303768e8aba11a8 Mon Sep 17 00:00:00 2001 From: Mikita Kliushun Date: Mon, 21 Sep 2026 18:10:11 +0200 Subject: [PATCH 7/8] fix: forward DataTable theme overrides --- src/components/DataTable/DataTableCell.tsx | 7 ++++++- src/components/DataTable/DataTablePagination.tsx | 2 ++ src/components/DataTable/DataTableTitle.tsx | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/DataTable/DataTableCell.tsx b/src/components/DataTable/DataTableCell.tsx index 7739db20d3..f656fbeaad 100644 --- a/src/components/DataTable/DataTableCell.tsx +++ b/src/components/DataTable/DataTableCell.tsx @@ -74,18 +74,21 @@ const DataTableCell = ({ numeric, maxFontSizeMultiplier, testID, + theme: themeOverrides, ...rest }: Props) => { return ( {children} @@ -98,9 +101,10 @@ const CellContent = ({ textStyle, maxFontSizeMultiplier, testID, + theme, }: Pick< Props, - 'children' | 'textStyle' | 'testID' | 'maxFontSizeMultiplier' + 'children' | 'textStyle' | 'testID' | 'maxFontSizeMultiplier' | 'theme' >) => { if (React.isValidElement(children)) { return children; @@ -113,6 +117,7 @@ const CellContent = ({ numberOfLines={1} maxFontSizeMultiplier={maxFontSizeMultiplier} testID={`${testID}-text-container`} + theme={theme} > {children} diff --git a/src/components/DataTable/DataTablePagination.tsx b/src/components/DataTable/DataTablePagination.tsx index e78a3700e8..6ce9244789 100644 --- a/src/components/DataTable/DataTablePagination.tsx +++ b/src/components/DataTable/DataTablePagination.tsx @@ -299,6 +299,7 @@ const DataTablePagination = ({ > Date: Mon, 21 Sep 2026 18:10:52 +0200 Subject: [PATCH 8/8] test: clean up animation regression tests --- src/components/__tests__/Banner.test.tsx | 2 - src/components/__tests__/DataTable.test.tsx | 44 +-------------------- 2 files changed, 1 insertion(+), 45 deletions(-) diff --git a/src/components/__tests__/Banner.test.tsx b/src/components/__tests__/Banner.test.tsx index f6bf0a82f3..25e0df658a 100644 --- a/src/components/__tests__/Banner.test.tsx +++ b/src/components/__tests__/Banner.test.tsx @@ -165,8 +165,6 @@ describe('animations', () => { Text ); - // A disabled animation scale settles within a frame instead of taking the - // full `motion.duration.medium1`. await act(() => { jest.advanceTimersByTime(16); }); diff --git a/src/components/__tests__/DataTable.test.tsx b/src/components/__tests__/DataTable.test.tsx index 5d69106923..49f863720a 100644 --- a/src/components/__tests__/DataTable.test.tsx +++ b/src/components/__tests__/DataTable.test.tsx @@ -1,6 +1,4 @@ -import { describe, expect, it, jest } from '@jest/globals'; -import { act } from '@testing-library/react-native'; -import { getAnimatedStyle } from 'react-native-reanimated'; +import { describe, expect, it } from '@jest/globals'; import { render, screen } from '../../test-utils'; import Checkbox from '../Checkbox'; @@ -22,46 +20,6 @@ describe('DataTable.Header', () => { }); describe('DataTable.Title', () => { - const sortIcon = () => { - const node = screen.getByText('arrow-up', { - includeHiddenElements: true, - }).parent; - - if (!node) { - throw new Error('Sort icon not found'); - } - - return node; - }; - - it('uses zero-duration sort animation when animation scale is disabled', async () => { - const view = await render( - - Dessert - - ); - - await view.rerender( - - Dessert - - ); - await act(() => { - jest.advanceTimersByTime(16); - }); - - // A disabled animation scale lands on the final rotation within a frame. - expect(getAnimatedStyle(sortIcon())).toMatchObject({ - transform: [{ rotate: '180deg' }], - }); - }); - it('renders data table title with sort icon', async () => { const tree = ( await render(