Skip to content

Commit c7789ae

Browse files
committed
fix: add theme handling
- create theme; - only use useNativeDriver on mobile platforms; - move magic numbers to theme.
1 parent 47a259b commit c7789ae

File tree

8 files changed

+96
-40
lines changed

8 files changed

+96
-40
lines changed

src/components/caret.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
import { useEffect, useRef } from 'react';
2-
import { StyleSheet, Animated } from 'react-native';
3-
import { DEFAULT_DARK_COLOR } from '../constants';
2+
import { StyleSheet, Animated, Platform } from 'react-native';
43
import { useTextInputOTP } from '../hooks/use-text-input-otp';
4+
import { useThemeColor } from '../hooks/use-theme-color';
5+
import { theme } from '../theme';
56

67
export function Caret() {
78
const opacity = useRef(new Animated.Value(0)).current;
9+
const useNativeDriver = Platform.OS === 'ios' || Platform.OS === 'android';
810
const { caretColor } = useTextInputOTP();
11+
const defaultBackgroundColor = useThemeColor({
12+
light: theme.colorBlack,
13+
dark: theme.colorWhite,
14+
});
915

1016
useEffect(() => {
1117
Animated.loop(
1218
Animated.sequence([
1319
Animated.timing(opacity, {
1420
toValue: 0,
1521
duration: 500,
16-
useNativeDriver: true,
22+
useNativeDriver: false,
1723
}),
1824
Animated.timing(opacity, {
1925
toValue: 1,
2026
duration: 500,
21-
useNativeDriver: true,
27+
useNativeDriver,
2228
}),
2329
])
2430
).start();
@@ -29,16 +35,16 @@ export function Caret() {
2935
testID="caret"
3036
style={[
3137
styles.caret,
32-
{ opacity, backgroundColor: caretColor ?? DEFAULT_DARK_COLOR },
38+
{ opacity, backgroundColor: caretColor ?? defaultBackgroundColor },
3339
]}
3440
/>
3541
);
3642
}
3743

3844
const styles = StyleSheet.create({
3945
caret: {
40-
width: 2,
41-
height: 16,
42-
borderRadius: 16,
46+
width: theme.space2,
47+
height: theme.space16,
48+
borderRadius: theme.borderRadius16,
4349
},
4450
});
Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
import { View, StyleSheet } from 'react-native';
2-
import { DEFAULT_DARK_COLOR } from '../constants';
32
import type { TextInputOTPSeparatorProps } from '../types';
3+
import { useThemeColor } from '../hooks/use-theme-color';
4+
import { theme } from '../theme';
45

56
export function TextInputOTPSeparator({
67
separatorStyles,
78
}: TextInputOTPSeparatorProps) {
9+
const defaultBackgroundColor = useThemeColor({
10+
light: theme.colorBlack,
11+
dark: theme.colorWhite,
12+
});
13+
814
return (
9-
<View style={StyleSheet.flatten([styles.separator, separatorStyles])} />
15+
<View
16+
style={StyleSheet.flatten([
17+
styles.separator,
18+
{ backgroundColor: defaultBackgroundColor },
19+
separatorStyles,
20+
])}
21+
/>
1022
);
1123
}
1224

1325
const styles = StyleSheet.create({
1426
separator: {
15-
width: 10,
16-
height: 4,
17-
backgroundColor: DEFAULT_DARK_COLOR,
18-
borderRadius: 15,
27+
width: theme.space10,
28+
height: theme.space4,
29+
borderRadius: theme.space16,
1930
},
2031
});

src/components/text-input-otp-slot.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { memo } from 'react';
22
import { Pressable, Text, StyleSheet } from 'react-native';
3-
import { Caret } from './caret';
43
import { useTextInputOTP } from '../hooks/use-text-input-otp';
54
import { useSlotBorderStyles } from '../hooks/use-slot-border-styles';
6-
import { DEFAULT_DARK_COLOR, SLOT_HEIGHT, SLOT_WIDTH } from '../constants';
5+
import { useThemeColor } from '../hooks/use-theme-color';
6+
import { SLOT_HEIGHT, SLOT_WIDTH } from '../constants';
77
import type {
88
TextInputOTPSlotInternalProps,
99
TextInputOTPSlotProps,
1010
} from '../types';
11+
import { theme } from '../theme';
12+
import { Caret } from './caret';
1113

1214
function TextInputOTPSlotComponent({
1315
index,
@@ -22,6 +24,11 @@ function TextInputOTPSlotComponent({
2224
const { code, currentIndex, handlePress, caretHidden } = useTextInputOTP();
2325
const isFocused = currentIndex === index;
2426
const borderStyles = useSlotBorderStyles({ isFocused, isFirst, isLast });
27+
const defaultTextColor = useThemeColor({
28+
light: theme.colorBlack,
29+
dark: theme.colorWhite,
30+
});
31+
2532
const shouldRenderCaret = isFocused && !code[index] && !caretHidden;
2633

2734
return (
@@ -39,6 +46,7 @@ function TextInputOTPSlotComponent({
3946
<Text
4047
style={StyleSheet.flatten([
4148
styles.slotText,
49+
{ color: defaultTextColor },
4250
isFocused ? focusedSlotTextStyles : slotTextStyles,
4351
])}
4452
>
@@ -61,8 +69,7 @@ const styles = StyleSheet.create({
6169
alignItems: 'center',
6270
},
6371
slotText: {
64-
color: DEFAULT_DARK_COLOR,
65-
fontSize: 14,
66-
fontWeight: 'bold',
72+
fontSize: theme.fontSize14,
73+
fontWeight: theme.fontWeightBold,
6774
},
6875
});

src/components/text-input-otp.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
import { forwardRef } from 'react';
12
import { View, StyleSheet } from 'react-native';
23
import { TextInputOTPProvider } from '../hooks/use-text-input-otp';
3-
import { TextInput } from './text-input';
4-
import { forwardRef } from 'react';
54
import type { TextInputOTPProps, TextInputOTPRef } from '../types';
5+
import { theme } from '../theme';
6+
import { TextInput } from './text-input';
67

78
export const TextInputOTP = forwardRef<TextInputOTPRef, TextInputOTPProps>(
89
({ children, containerStyles, ...rest }, ref) => {
@@ -22,6 +23,6 @@ const styles = StyleSheet.create({
2223
flexDirection: 'row',
2324
alignItems: 'center',
2425
justifyContent: 'center',
25-
gap: 10,
26+
gap: theme.space10,
2627
},
2728
});

src/constants.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
export const SLOT_WIDTH = 50;
22
export const SLOT_HEIGHT = 50;
33
export const FOCUSED_SLOT_HEIGHT = 54;
4-
export const DEFAULT_DARK_COLOR = '#030712';
5-
export const DEFAULT_LIGHT_COLOR = '#E4E7EC';
Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
1-
import {
2-
DEFAULT_DARK_COLOR,
3-
DEFAULT_LIGHT_COLOR,
4-
FOCUSED_SLOT_HEIGHT,
5-
SLOT_HEIGHT,
6-
} from '../constants';
1+
import type { StyleProp, ViewStyle } from 'react-native';
2+
import { FOCUSED_SLOT_HEIGHT, SLOT_HEIGHT } from '../constants';
3+
import { theme } from '../theme';
74
import type { UseSlotBorderStylesProps } from '../types';
5+
import { useThemeColor } from './use-theme-color';
86

97
export function useSlotBorderStyles({
108
isFocused,
119
isFirst,
1210
isLast,
13-
}: UseSlotBorderStylesProps) {
11+
}: UseSlotBorderStylesProps): StyleProp<ViewStyle> {
12+
const darkBorder = useThemeColor({
13+
light: theme.colorBlack,
14+
dark: theme.colorWhite,
15+
});
16+
const lightBorder = useThemeColor({
17+
light: theme.colorLightGrey,
18+
dark: theme.colorDarkGrey,
19+
});
20+
1421
return {
1522
height: isFocused ? FOCUSED_SLOT_HEIGHT : SLOT_HEIGHT,
16-
borderColor: isFocused ? DEFAULT_DARK_COLOR : DEFAULT_LIGHT_COLOR,
17-
borderTopWidth: 2,
18-
borderBottomWidth: 2,
19-
borderLeftWidth: isFocused || isFirst ? 2 : 1,
20-
borderRightWidth: isFocused || isLast ? 2 : 1,
21-
borderTopLeftRadius: isFirst ? 8 : 0,
22-
borderTopRightRadius: isLast ? 8 : 0,
23-
borderBottomLeftRadius: isFirst ? 8 : 0,
24-
borderBottomRightRadius: isLast ? 8 : 0,
23+
borderColor: isFocused ? darkBorder : lightBorder,
24+
borderTopWidth: theme.space2,
25+
borderBottomWidth: theme.space2,
26+
borderLeftWidth: isFocused || isFirst ? theme.space2 : theme.space1,
27+
borderRightWidth: isFocused || isLast ? theme.space2 : theme.space1,
28+
borderTopLeftRadius: isFirst ? theme.borderRadius8 : theme.borderRadius0,
29+
borderTopRightRadius: isLast ? theme.borderRadius8 : theme.borderRadius0,
30+
borderBottomLeftRadius: isFirst ? theme.borderRadius8 : theme.borderRadius0,
31+
borderBottomRightRadius: isLast ? theme.borderRadius8 : theme.borderRadius0,
2532
};
2633
}

src/hooks/use-theme-color.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { useColorScheme } from 'react-native';
2+
3+
export function useThemeColor<T, U>(props: { light: T; dark: U }) {
4+
const theme = useColorScheme() ?? 'light';
5+
return props[theme];
6+
}

src/theme.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export const theme = {
2+
colorBlack: '#030712',
3+
colorWhite: '#E4E7EC',
4+
colorLightGrey: '#E4E7EC',
5+
colorDarkGrey: '#4b5563',
6+
7+
fontSize14: 14,
8+
9+
fontWeightBold: 'bold' as 'bold',
10+
11+
space1: 1,
12+
space2: 2,
13+
space4: 4,
14+
space10: 10,
15+
space16: 16,
16+
17+
borderRadius0: 0,
18+
borderRadius8: 8,
19+
borderRadius16: 16,
20+
};

0 commit comments

Comments
 (0)