Skip to content

Commit b4e58d7

Browse files
authored
fix: render list separators consistently by snapping row heights to the pixel grid (#7449)
1 parent 9b34a32 commit b4e58d7

21 files changed

Lines changed: 273 additions & 168 deletions

File tree

app/containers/ActionSheet/ActionSheet.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ import { Handle } from './Handle';
1919
import { type TActionSheetOptions } from './Provider';
2020
import BottomSheetContent from './BottomSheetContent';
2121
import { HANDLE_HEIGHT, useActionSheetDetents } from './useActionSheetDetents';
22+
import { useActionSheetItemHeight } from './useActionSheetItemHeight';
2223
import styles from './styles';
2324

2425
export const ACTION_SHEET_ANIMATION_DURATION = 250;
2526

2627
const ActionSheet = memo(
2728
forwardRef(({ children }: { children: ReactElement }, ref) => {
2829
const { colors } = useTheme();
29-
const { height: windowHeight, width: windowWidth, fontScale } = useWindowDimensions();
30+
const { height: windowHeight, width: windowWidth } = useWindowDimensions();
3031
const sheetRef = useRef<TrueSheet>(null);
3132
const handleRef = useRef<View>(null);
3233
const [data, setData] = useState<TActionSheetOptions>({} as TActionSheetOptions);
@@ -38,7 +39,7 @@ const ActionSheet = memo(
3839
// To avoid content hiding behind navigation bar on older Android versions
3940
const isNewAndroid = isAndroid && Number(Platform.Version) >= 36;
4041
const bottom = isIOS || isNewAndroid ? 0 : windowHeight * 0.03;
41-
const itemHeight = 48 * fontScale;
42+
const itemHeight = useActionSheetItemHeight();
4243

4344
const handleContentLayout = ({ nativeEvent: { layout } }: LayoutChangeEvent) => {
4445
setContentHeight(layout.height);

app/containers/ActionSheet/BottomSheetContent.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FlatList, Text, useWindowDimensions, View, type ViewProps } from 'react-native';
1+
import { FlatList, Text, View, type ViewProps } from 'react-native';
22
import { memo, type ReactElement } from 'react';
33
import { useSafeAreaInsets } from 'react-native-safe-area-context';
44

@@ -10,6 +10,7 @@ import { type TActionSheetOptionsItem } from './Provider';
1010
import styles from './styles';
1111
import * as List from '../List';
1212
import Touch from '../Touch';
13+
import { useActionSheetItemHeight } from './useActionSheetItemHeight';
1314

1415
interface IBottomSheetContentProps {
1516
hasCancel?: boolean;
@@ -39,8 +40,7 @@ const BottomSheetContent = memo(
3940

4041
const { colors } = useTheme();
4142
const { bottom } = useSafeAreaInsets();
42-
const { fontScale } = useWindowDimensions();
43-
const height = 48 * fontScale;
43+
const height = useActionSheetItemHeight();
4444
const paddingBottom = isAndroid ? bottom + height : bottom;
4545
const minHeightStyle = isAndroid || !contentMinHeight ? undefined : { minHeight: contentMinHeight };
4646

app/containers/ActionSheet/Item.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { memo } from 'react';
2-
import { Text, useWindowDimensions, View } from 'react-native';
2+
import { Text, View } from 'react-native';
33

44
import { CustomIcon } from '../CustomIcon';
55
import { useTheme } from '../../theme';
@@ -9,6 +9,7 @@ import { type TActionSheetOptionsItem } from './Provider';
99
import styles from './styles';
1010
import { LISTENER } from '../Toast';
1111
import Touch from '../Touch';
12+
import { useActionSheetItemHeight } from './useActionSheetItemHeight';
1213

1314
export interface IActionSheetItem {
1415
item: TActionSheetOptionsItem;
@@ -20,7 +21,7 @@ export const Item = memo(({ item, hide }: IActionSheetItem) => {
2021

2122
const enabled = item?.enabled ?? true;
2223
const { colors } = useTheme();
23-
const { fontScale } = useWindowDimensions();
24+
const height = useActionSheetItemHeight();
2425
const onPress = () => {
2526
if (enabled) {
2627
hide();
@@ -37,7 +38,6 @@ export const Item = memo(({ item, hide }: IActionSheetItem) => {
3738
if (!enabled) {
3839
color = colors.fontDisabled;
3940
}
40-
const height = 48 * fontScale;
4141
const accessibilityLabel = item?.accessibilityLabel || (item?.subtitle ? `${item.title}. ${item.subtitle}` : item.title);
4242

4343
return (

app/containers/ActionSheet/useActionSheetDetents.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { SheetDetent } from '@lodev09/react-native-true-sheet';
22
import { useMemo } from 'react';
3-
import { useWindowDimensions } from 'react-native';
43

54
const ACTION_SHEET_MIN_HEIGHT_FRACTION = 0.15;
65
const ACTION_SHEET_MAX_HEIGHT_FRACTION = 0.75;
@@ -47,16 +46,13 @@ export function useActionSheetDetents({
4746
hasCancel = false,
4847
contentHeight
4948
}: UseActionSheetDetentsParams): { detents: SheetDetent[]; maxHeight: number; scrollEnabled: boolean } {
50-
const { fontScale } = useWindowDimensions();
51-
const CANCEL_HEIGHT = 48 * fontScale;
52-
5349
return useMemo(() => {
5450
const maxHeight = windowHeight * ACTION_SHEET_MAX_HEIGHT_FRACTION;
5551
const hasOptions = optionsLength > 0;
5652

5753
const maxSnap = hasOptions
5854
? Math.min(
59-
(itemHeight + 0.5) * optionsLength + HANDLE_HEIGHT + headerHeight + bottomInset + (hasCancel ? CANCEL_HEIGHT : 0),
55+
(itemHeight + 0.5) * optionsLength + HANDLE_HEIGHT + headerHeight + bottomInset + (hasCancel ? itemHeight : 0),
6056
maxHeight
6157
)
6258
: 0;
@@ -72,7 +68,7 @@ export function useActionSheetDetents({
7268
scrollEnabled = true;
7369
} else {
7470
const measuredHeight =
75-
optionsLength * itemHeight + HANDLE_HEIGHT + headerHeight + bottomInset + (hasCancel ? CANCEL_HEIGHT : 0);
71+
optionsLength * itemHeight + HANDLE_HEIGHT + headerHeight + bottomInset + (hasCancel ? itemHeight : 0);
7672

7773
scrollEnabled = false;
7874
detents = [heightToDetent(Math.round(measuredHeight), windowHeight)];
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { PixelRatio, useWindowDimensions } from 'react-native';
2+
3+
export const ACTION_SHEET_ITEM_HEIGHT = 48;
4+
5+
export const useActionSheetItemHeight = (): number => {
6+
const { fontScale } = useWindowDimensions();
7+
return PixelRatio.roundToNearestPixel(ACTION_SHEET_ITEM_HEIGHT * fontScale);
8+
};

app/containers/DirectoryItem/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { memo, type ReactElement } from 'react';
2-
import { Text, View, type ViewStyle } from 'react-native';
2+
import { PixelRatio, Text, View, type ViewStyle } from 'react-native';
33

44
import Touch from '../Touch';
55
import Avatar from '../Avatar';
@@ -49,7 +49,7 @@ const DirectoryItem = ({
4949
}: IDirectoryItem): ReactElement => {
5050
const { colors } = useTheme();
5151
const { fontScale } = useResponsiveLayout();
52-
const height = ROW_HEIGHT * fontScale;
52+
const height = PixelRatio.roundToNearestPixel(ROW_HEIGHT * fontScale);
5353

5454
return (
5555
<View testID={testID} accessible accessibilityLabel={`${title || ''} ${rightLabel || ''}`} importantForAccessibility='yes'>

app/containers/List/ListItem.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useMemo, memo, type ReactElement } from 'react';
22
import {
33
I18nManager,
4+
PixelRatio,
45
type StyleProp,
56
StyleSheet,
67
Text,
@@ -172,7 +173,11 @@ const Content = memo(
172173

173174
return (
174175
<View
175-
style={[styles.container, disabled && styles.disabled, { height: (heightContainer || BASE_HEIGHT) * fontScale }]}
176+
style={[
177+
styles.container,
178+
disabled && styles.disabled,
179+
{ height: PixelRatio.roundToNearestPixel((heightContainer || BASE_HEIGHT) * fontScale) }
180+
]}
176181
testID={testID}
177182
accessible={!shouldDisableAccessibility}
178183
accessibilityLabel={handleAcessibilityLabel}

app/containers/MessageActions/Header.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ const ITEM_MARGIN = 8;
3939

4040
const styles = StyleSheet.create({
4141
container: {
42+
height: HEADER_HEIGHT,
43+
justifyContent: 'center',
4244
alignItems: 'center',
4345
marginHorizontal: CONTAINER_MARGIN,
4446
paddingBottom: 16

app/containers/ServerItem/__snapshots__/ServerItem.test.tsx.snap

Lines changed: 84 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,16 @@ exports[`Story Snapshots: Content should match snapshot 1`] = `
8989
>
9090
<View
9191
style={
92-
{
93-
"alignItems": "center",
94-
"flexDirection": "row",
95-
"padding": 12,
96-
}
92+
[
93+
{
94+
"alignItems": "center",
95+
"flexDirection": "row",
96+
"padding": 12,
97+
},
98+
{
99+
"height": 68,
100+
},
101+
]
97102
}
98103
>
99104
<ViewManagerAdapter_ExpoImage
@@ -315,11 +320,16 @@ exports[`Story Snapshots: Content should match snapshot 1`] = `
315320
>
316321
<View
317322
style={
318-
{
319-
"alignItems": "center",
320-
"flexDirection": "row",
321-
"padding": 12,
322-
}
323+
[
324+
{
325+
"alignItems": "center",
326+
"flexDirection": "row",
327+
"padding": 12,
328+
},
329+
{
330+
"height": 68,
331+
},
332+
]
323333
}
324334
>
325335
<ViewManagerAdapter_ExpoImage
@@ -541,11 +551,16 @@ exports[`Story Snapshots: Content should match snapshot 1`] = `
541551
>
542552
<View
543553
style={
544-
{
545-
"alignItems": "center",
546-
"flexDirection": "row",
547-
"padding": 12,
548-
}
554+
[
555+
{
556+
"alignItems": "center",
557+
"flexDirection": "row",
558+
"padding": 12,
559+
},
560+
{
561+
"height": 68,
562+
},
563+
]
549564
}
550565
>
551566
<ViewManagerAdapter_ExpoImage
@@ -699,7 +714,7 @@ exports[`Story Snapshots: SwipeActions should match snapshot 1`] = `
699714
"right": 0,
700715
},
701716
{
702-
"height": 68,
717+
"height": 80,
703718
},
704719
{
705720
"backgroundColor": "#EC0D2A",
@@ -720,7 +735,7 @@ exports[`Story Snapshots: SwipeActions should match snapshot 1`] = `
720735
"width": 390,
721736
},
722737
{
723-
"height": 68,
738+
"height": 80,
724739
},
725740
[Function],
726741
]
@@ -901,11 +916,16 @@ exports[`Story Snapshots: SwipeActions should match snapshot 1`] = `
901916
>
902917
<View
903918
style={
904-
{
905-
"alignItems": "center",
906-
"flexDirection": "row",
907-
"padding": 12,
908-
}
919+
[
920+
{
921+
"alignItems": "center",
922+
"flexDirection": "row",
923+
"padding": 12,
924+
},
925+
{
926+
"height": 68,
927+
},
928+
]
909929
}
910930
>
911931
<ViewManagerAdapter_ExpoImage
@@ -1056,7 +1076,7 @@ exports[`Story Snapshots: SwipeActions should match snapshot 1`] = `
10561076
"right": 0,
10571077
},
10581078
{
1059-
"height": 68,
1079+
"height": 80,
10601080
},
10611081
{
10621082
"backgroundColor": "#EC0D2A",
@@ -1077,7 +1097,7 @@ exports[`Story Snapshots: SwipeActions should match snapshot 1`] = `
10771097
"width": 390,
10781098
},
10791099
{
1080-
"height": 68,
1100+
"height": 80,
10811101
},
10821102
[Function],
10831103
]
@@ -1258,11 +1278,16 @@ exports[`Story Snapshots: SwipeActions should match snapshot 1`] = `
12581278
>
12591279
<View
12601280
style={
1261-
{
1262-
"alignItems": "center",
1263-
"flexDirection": "row",
1264-
"padding": 12,
1265-
}
1281+
[
1282+
{
1283+
"alignItems": "center",
1284+
"flexDirection": "row",
1285+
"padding": 12,
1286+
},
1287+
{
1288+
"height": 68,
1289+
},
1290+
]
12661291
}
12671292
>
12681293
<ViewManagerAdapter_ExpoImage
@@ -1491,11 +1516,16 @@ exports[`Story Snapshots: Themes should match snapshot 1`] = `
14911516
>
14921517
<View
14931518
style={
1494-
{
1495-
"alignItems": "center",
1496-
"flexDirection": "row",
1497-
"padding": 12,
1498-
}
1519+
[
1520+
{
1521+
"alignItems": "center",
1522+
"flexDirection": "row",
1523+
"padding": 12,
1524+
},
1525+
{
1526+
"height": 68,
1527+
},
1528+
]
14991529
}
15001530
>
15011531
<ViewManagerAdapter_ExpoImage
@@ -1717,11 +1747,16 @@ exports[`Story Snapshots: Themes should match snapshot 1`] = `
17171747
>
17181748
<View
17191749
style={
1720-
{
1721-
"alignItems": "center",
1722-
"flexDirection": "row",
1723-
"padding": 12,
1724-
}
1750+
[
1751+
{
1752+
"alignItems": "center",
1753+
"flexDirection": "row",
1754+
"padding": 12,
1755+
},
1756+
{
1757+
"height": 68,
1758+
},
1759+
]
17251760
}
17261761
>
17271762
<ViewManagerAdapter_ExpoImage
@@ -1943,11 +1978,16 @@ exports[`Story Snapshots: Themes should match snapshot 1`] = `
19431978
>
19441979
<View
19451980
style={
1946-
{
1947-
"alignItems": "center",
1948-
"flexDirection": "row",
1949-
"padding": 12,
1950-
}
1981+
[
1982+
{
1983+
"alignItems": "center",
1984+
"flexDirection": "row",
1985+
"padding": 12,
1986+
},
1987+
{
1988+
"height": 68,
1989+
},
1990+
]
19511991
}
19521992
>
19531993
<ViewManagerAdapter_ExpoImage

0 commit comments

Comments
 (0)