-
Notifications
You must be signed in to change notification settings - Fork 136
/
Copy pathuseRestyle.ts
103 lines (93 loc) · 2.77 KB
/
useRestyle.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import {useMemo} from 'react';
import {StyleProp} from 'react-native';
import {BaseTheme, RNStyle, Dimensions} from '../types';
import {getKeys} from '../typeHelpers';
import useDimensions from './useDimensions';
import useTheme from './useTheme';
const filterRestyleProps = <
TRestyleProps,
TProps extends Record<string, unknown> & TRestyleProps
>(
componentProps: TProps,
omitPropertiesMap: Record<keyof TProps, boolean>,
) => {
const props = omitPropertiesMap.variant
? {variant: 'defaults', ...componentProps}
: componentProps;
return getKeys(props).reduce(
({cleanProps, restyleProps, serializedRestyleProps}, key) => {
if (omitPropertiesMap[key as keyof TProps]) {
return {
cleanProps,
restyleProps: {...restyleProps, [key]: props[key]},
serializedRestyleProps: `${serializedRestyleProps}${key}:${props[key]};`,
};
} else {
return {
cleanProps: {...cleanProps, [key]: props[key]},
restyleProps,
serializedRestyleProps,
};
}
},
{cleanProps: {}, restyleProps: {}, serializedRestyleProps: ''} as {
cleanProps: TProps;
restyleProps: TRestyleProps;
serializedRestyleProps: string;
},
);
};
const useRestyle = <
Theme extends BaseTheme,
TRestyleProps extends Record<string, any>,
TProps extends TRestyleProps & {style?: StyleProp<RNStyle>}
>(
composedRestyleFunction: {
buildStyle: <TInputProps extends TProps>(
props: TInputProps,
{
theme,
dimensions,
}: {
theme: Theme;
dimensions: Dimensions;
},
) => RNStyle;
properties: (keyof TProps)[];
propertiesMap: Record<keyof TProps, boolean>;
},
props: TProps,
) => {
const theme = useTheme<Theme>();
const dimensions = useDimensions();
const {cleanProps, restyleProps, serializedRestyleProps} = filterRestyleProps(
props,
composedRestyleFunction.propertiesMap,
);
const calculatedStyle = useMemo(() => {
const style = composedRestyleFunction.buildStyle(restyleProps as TProps, {
theme,
dimensions,
});
const styleProp = props.style;
if (typeof styleProp === 'function') {
return (...args: any[]) => [style, styleProp(...args)].filter(Boolean);
}
return [style, styleProp].filter(Boolean);
// We disable the exhaustive deps rule here in order to trigger the useMemo
// when the serialized string of restyleProps changes instead of the object
// reference which will change on every render.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
theme,
dimensions,
props.style,
serializedRestyleProps,
composedRestyleFunction,
]);
return {
...cleanProps,
style: calculatedStyle,
};
};
export default useRestyle;