Skip to content

Commit 4cc1002

Browse files
refactor: iOS Surface styles
1 parent 1ef5f69 commit 4cc1002

File tree

3 files changed

+133
-15
lines changed

3 files changed

+133
-15
lines changed

example/src/Examples/SurfaceExample.tsx

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
2-
import { StyleSheet } from 'react-native';
2+
import { StyleSheet, View } from 'react-native';
33

4-
import { MD3Elevation, Surface, Text } from 'react-native-paper';
4+
import { MD3Elevation, Surface, Text, MD3Colors } from 'react-native-paper';
55

66
import { useExampleTheme } from '..';
77
import { isWeb } from '../../utils';
@@ -31,6 +31,23 @@ const SurfaceExample = () => {
3131
</Text>
3232
</Surface>
3333
))}
34+
35+
<View style={styles.horizontalSurfacesContainer}>
36+
<Surface style={styles.horizontalSurface}>
37+
<Text style={styles.centerText}>Left</Text>
38+
</Surface>
39+
<Surface style={styles.horizontalSurface}>
40+
<Text style={styles.centerText}>Right</Text>
41+
</Surface>
42+
</View>
43+
<View style={styles.verticalSurfacesContainer}>
44+
<Surface style={styles.verticalSurface}>
45+
<Text style={styles.centerText}>Top</Text>
46+
</Surface>
47+
<Surface style={styles.verticalSurface}>
48+
<Text style={styles.centerText}>Bottom</Text>
49+
</Surface>
50+
</View>
3451
</ScreenWrapper>
3552
);
3653
};
@@ -61,6 +78,37 @@ const styles = StyleSheet.create({
6178
alignItems: 'center',
6279
justifyContent: 'center',
6380
},
81+
82+
horizontalSurfacesContainer: {
83+
flexDirection: 'row',
84+
justifyContent: 'space-between',
85+
width: '100%',
86+
marginBottom: 20,
87+
borderColor: MD3Colors.tertiary50,
88+
padding: 10,
89+
borderWidth: 1,
90+
},
91+
horizontalSurface: {
92+
width: '48%',
93+
},
94+
95+
verticalSurfacesContainer: {
96+
height: 400,
97+
justifyContent: 'space-between',
98+
width: '100%',
99+
marginBottom: 100,
100+
borderColor: MD3Colors.tertiary50,
101+
padding: 10,
102+
borderWidth: 1,
103+
},
104+
verticalSurface: {
105+
height: '48%',
106+
justifyContent: 'center',
107+
},
108+
109+
centerText: {
110+
textAlign: 'center',
111+
},
64112
});
65113

66114
export default SurfaceExample;

src/components/Surface.tsx

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import overlay, { isAnimatedValue } from '../styles/overlay';
1313
import shadow from '../styles/shadow';
1414
import type { ThemeProp, MD3Elevation } from '../types';
1515
import { forwardRef } from '../utils/forwardRef';
16+
import { splitStyles } from '../utils/splitStyles';
1617

1718
export type Props = React.ComponentPropsWithRef<typeof View> & {
1819
/**
@@ -229,10 +230,32 @@ const Surface = forwardRef<View, Props>(
229230
start,
230231
end,
231232
flex,
233+
backgroundColor: backgroundColorStyle,
234+
width,
235+
height,
236+
transform,
237+
opacity,
232238
...restStyle
233239
} = (StyleSheet.flatten(style) || {}) as ViewStyle;
234240

235-
const absoluteStyles = {
241+
const [filteredStyle, borderRadiusStyle, marginStyle] = splitStyles(
242+
restStyle,
243+
(style) => style.startsWith('border') && style.endsWith('Radius'),
244+
(style) => style.startsWith('margin')
245+
);
246+
247+
const sharedStyles = {
248+
flex: height ? 1 : undefined,
249+
};
250+
251+
const innerLayerViewStyles = [
252+
filteredStyle,
253+
sharedStyles,
254+
borderRadiusStyle,
255+
{ backgroundColor: backgroundColorStyle || backgroundColor },
256+
];
257+
258+
const outerLayerViewStyles = {
236259
position,
237260
alignSelf,
238261
top,
@@ -241,14 +264,14 @@ const Surface = forwardRef<View, Props>(
241264
left,
242265
start,
243266
end,
267+
flex,
268+
width,
269+
height,
270+
transform,
271+
opacity,
272+
...marginStyle,
244273
};
245274

246-
const sharedStyle = [{ backgroundColor, flex }, restStyle];
247-
248-
const innerLayerViewStyles = [{ flex }];
249-
250-
const outerLayerViewStyles = [absoluteStyles, innerLayerViewStyles];
251-
252275
if (isAnimatedValue(elevation)) {
253276
const inputRange = [0, 1, 2, 3, 4, 5];
254277

@@ -280,10 +303,14 @@ const Surface = forwardRef<View, Props>(
280303
testID={`${testID}-outer-layer`}
281304
>
282305
<Animated.View
283-
style={[getStyleForAnimatedShadowLayer(1), innerLayerViewStyles]}
284-
testID={`${testID}-inner-layer`}
306+
style={[getStyleForAnimatedShadowLayer(1), sharedStyles]}
307+
testID={`${testID}-middle-layer`}
285308
>
286-
<Animated.View {...props} testID={testID} style={sharedStyle}>
309+
<Animated.View
310+
{...props}
311+
testID={testID}
312+
style={innerLayerViewStyles}
313+
>
287314
{children}
288315
</Animated.View>
289316
</Animated.View>
@@ -312,10 +339,14 @@ const Surface = forwardRef<View, Props>(
312339
testID={`${testID}-outer-layer`}
313340
>
314341
<Animated.View
315-
style={[getStyleForShadowLayer(1), innerLayerViewStyles]}
316-
testID={`${testID}-inner-layer`}
342+
style={[getStyleForShadowLayer(1), sharedStyles]}
343+
testID={`${testID}-middle-layer`}
317344
>
318-
<Animated.View {...props} testID={testID} style={sharedStyle}>
345+
<Animated.View
346+
{...props}
347+
testID={testID}
348+
style={innerLayerViewStyles}
349+
>
319350
{children}
320351
</Animated.View>
321352
</Animated.View>

src/utils/splitStyles.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import type { ViewStyle } from 'react-native';
2+
3+
type Tuple = readonly ((style: string) => boolean)[];
4+
5+
type MappedTuple<T extends Tuple> = {
6+
[Index in keyof T]: ViewStyle;
7+
} & { length: T['length'] };
8+
9+
export function splitStyles<T extends Tuple>(styles: ViewStyle, ...filters: T) {
10+
const newStyles = filters.map<[string, ViewStyle][]>(returnEmptyArray);
11+
12+
// Rest styles
13+
newStyles.push([]);
14+
15+
outer: for (const item of Object.entries(styles) as [string, ViewStyle][]) {
16+
for (let i = 0; i < filters.length; i++) {
17+
if (filters[i](item[0])) {
18+
newStyles[i].push(item);
19+
continue outer;
20+
}
21+
}
22+
23+
// Adds to rest styles if not filtered
24+
newStyles[filters.length].push(item);
25+
}
26+
27+
// Put rest styles in the beginning
28+
const last = newStyles.pop()!;
29+
newStyles.unshift(last);
30+
31+
return newStyles.map((styles) => Object.fromEntries(styles)) as unknown as [
32+
ViewStyle,
33+
...MappedTuple<T>
34+
];
35+
}
36+
37+
function returnEmptyArray<T extends unknown[]>() {
38+
return [] as unknown as T;
39+
}

0 commit comments

Comments
 (0)