Skip to content

Commit 9cb7798

Browse files
Add a theme provider
Adapt components to use a dynamic theme
1 parent 7a1ea77 commit 9cb7798

38 files changed

Lines changed: 799 additions & 823 deletions

eslint.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export default [
5454
rules: {
5555
'observation/no-function-without-logging': 'error',
5656

57-
'react-native/no-unused-styles': 'error',
57+
'react-native/no-unused-styles': 'off',
5858
'react-native/no-inline-styles': 'off',
5959

6060
'prettier/prettier': 'error',

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@observation.org/react-native-components",
3-
"version": "1.72.0",
3+
"version": "1.73.0",
44
"main": "src/index.ts",
55
"repository": "git@github.com:observation/react-native-components.git",
66
"author": "Observation.org",

src/components/BackButton.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,22 @@ import React from 'react'
33
import { NavigationProp, ParamListBase } from '@react-navigation/native'
44

55
import IconButton from '../components/IconButton'
6-
import { theme } from '../styles'
6+
import { useTheme } from '../theme/ThemeProvider'
77

88
type Props = {
99
navigation: NavigationProp<ParamListBase>
1010
}
1111

12-
const BackButton = ({ navigation }: Props) => (
13-
<IconButton
14-
containerStyle={{ padding: theme.margin.common }}
15-
onPress={() => navigation.goBack()}
16-
icon={{ name: 'chevron-left', size: theme.icon.size.xxl, color: theme.color.primary500 }}
17-
/>
18-
)
12+
const BackButton = ({ navigation }: Props) => {
13+
const theme = useTheme()
14+
15+
return (
16+
<IconButton
17+
containerStyle={{ padding: theme.margin.common }}
18+
onPress={() => navigation.goBack()}
19+
icon={{ name: 'chevron-left', size: theme.icon.size.xxl, color: theme.color.primary500 }}
20+
/>
21+
)
22+
}
1923

2024
export default BackButton

src/components/BottomSheet.tsx

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import React from 'react'
22
import { StyleProp, StyleSheet, Text, View, ViewStyle } from 'react-native'
33

4-
import { useTheme } from '@react-navigation/native'
4+
import { useTheme as useNavigationTheme } from '@react-navigation/native'
55

66
import LargeButton, { LargeButtonProps } from './LargeButton'
7-
import { shadow, theme } from '../styles'
7+
import { Theme } from '../@types/theme'
8+
import { shadow } from '../styles'
89
import textStyle from '../styles/text'
10+
import { useStyles, useTheme } from '../theme/ThemeProvider'
911

1012
type Props = {
1113
title?: string
@@ -17,7 +19,10 @@ type Props = {
1719
}
1820

1921
const BottomSheet = ({ title, text, buttons = [], style, testID, children }: Props) => {
20-
const { colors } = useTheme()
22+
const { colors } = useNavigationTheme()
23+
const theme = useTheme()
24+
const styles = useStyles(createStyles)
25+
2126
const buttonsMarginTop = title || text ? theme.margin.common : 0
2227
return (
2328
<View style={[styles.container, style]} testID={testID}>
@@ -59,27 +64,28 @@ const BottomSheet = ({ title, text, buttons = [], style, testID, children }: Pro
5964

6065
export default BottomSheet
6166

62-
const styles = StyleSheet.create({
63-
container: {
64-
...shadow.normal.ios,
65-
borderTopWidth: 1 / 3,
66-
borderTopColor: theme.color.grey300,
67-
},
68-
bottomSheetContainer: {
69-
...shadow.normal.android,
70-
},
71-
bottomSheet: {
72-
flexDirection: 'column',
73-
margin: theme.margin.common,
74-
},
75-
buttonContainer: {
76-
marginHorizontal: -theme.margin.half,
77-
flexDirection: 'row',
78-
alignItems: 'flex-start',
79-
},
80-
buttonStyle: {
81-
flex: 1,
82-
margin: 0,
83-
marginHorizontal: theme.margin.half,
84-
},
85-
})
67+
const createStyles = (theme: Theme) =>
68+
StyleSheet.create({
69+
container: {
70+
...shadow.normal.ios,
71+
borderTopWidth: 1 / 3,
72+
borderTopColor: theme.color.grey300,
73+
},
74+
bottomSheetContainer: {
75+
...shadow.normal.android,
76+
},
77+
bottomSheet: {
78+
flexDirection: 'column',
79+
margin: theme.margin.common,
80+
},
81+
buttonContainer: {
82+
marginHorizontal: -theme.margin.half,
83+
flexDirection: 'row',
84+
alignItems: 'flex-start',
85+
},
86+
buttonStyle: {
87+
flex: 1,
88+
margin: 0,
89+
marginHorizontal: theme.margin.half,
90+
},
91+
})

src/components/BrandIcon.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React from 'react'
33
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome'
44

55
import BrandIcons, { BrandIconName } from '../lib/BrandIcons'
6-
import { theme } from '../styles'
6+
import { useTheme } from '../theme/ThemeProvider'
77

88
type Props = {
99
name: BrandIconName
@@ -12,6 +12,7 @@ type Props = {
1212
}
1313

1414
export const BrandIcon = ({ name, color, size }: Props) => {
15+
const theme = useTheme()
1516
const icon = BrandIcons[name]
1617
const iconColor = color ?? theme.color.primary500
1718
const iconSize = size ?? theme.icon.size.l

src/components/Checkbox.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { StyleProp, StyleSheet, TouchableOpacity, View, ViewStyle } from 'react-
33

44
import { Icon } from './Icon'
55
import Log from '../lib/Log'
6-
import { theme } from '../styles'
6+
import { useTheme } from '../theme/ThemeProvider'
77

88
type Props = {
99
enabled: boolean
@@ -21,16 +21,18 @@ const Checkbox = ({
2121
containerStyle,
2222
iconContainerStyle,
2323
children,
24-
lineHeight = theme.margin.large,
24+
lineHeight,
2525
testID = 'pressable',
2626
}: Props) => {
2727
Log.debug('Checkbox')
2828

29+
const theme = useTheme()
30+
const size = lineHeight ?? theme.margin.large
2931
return (
3032
<View style={[styles.containerStyle, containerStyle]}>
3133
<View style={[styles.iconContainer, iconContainerStyle]}>
3234
<TouchableOpacity testID={testID} onPress={onPress} activeOpacity={0.5}>
33-
<View style={[styles.iconInnerContainer, { width: lineHeight, height: lineHeight }]}>
35+
<View style={[styles.iconInnerContainer, { width: size, height: size }]}>
3436
{enabled ? (
3537
<Icon name="check-square" color={theme.color.black} />
3638
) : (

src/components/Chip.tsx

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import {
1010
ViewStyle,
1111
} from 'react-native'
1212

13-
import { fontSize, theme } from '../styles'
13+
import { Theme } from '../@types/theme'
14+
import { fontSize } from '../styles'
1415
import appTextStyle from '../styles/text'
16+
import { useStyles, useTheme } from '../theme/ThemeProvider'
1517

1618
type Props = {
1719
text?: string
@@ -22,6 +24,8 @@ type Props = {
2224
}
2325

2426
const Chip = ({ text, textStyle, containerStyle, onPress, disabled }: Props) => {
27+
const theme = useTheme()
28+
const styles = useStyles(createStyles)
2529
const [borderRadius, setBorderRadius] = useState(theme.margin.common)
2630
return (
2731
<TouchableOpacity onPress={disabled ? undefined : onPress} activeOpacity={0.5} disabled={disabled}>
@@ -37,25 +41,26 @@ const Chip = ({ text, textStyle, containerStyle, onPress, disabled }: Props) =>
3741
)
3842
}
3943

40-
const styles = StyleSheet.create({
41-
chipTextContainer: {
42-
flexDirection: 'row',
43-
justifyContent: 'center',
44-
},
45-
chipText: {
46-
...appTextStyle.body,
47-
color: theme.color.white,
48-
lineHeight: theme.margin.common,
49-
fontSize: fontSize.medium,
50-
},
51-
chipContainer: {
52-
backgroundColor: theme.color.accentLime400,
53-
paddingHorizontal: theme.margin.common,
54-
paddingVertical: theme.margin.half,
55-
borderRadius: theme.margin.common,
56-
minWidth: 44,
57-
justifyContent: 'center',
58-
},
59-
})
44+
const createStyles = (theme: Theme) =>
45+
StyleSheet.create({
46+
chipTextContainer: {
47+
flexDirection: 'row',
48+
justifyContent: 'center',
49+
},
50+
chipText: {
51+
...appTextStyle.body,
52+
color: theme.color.white,
53+
lineHeight: theme.margin.common,
54+
fontSize: fontSize.medium,
55+
},
56+
chipContainer: {
57+
backgroundColor: theme.color.accentLime400,
58+
paddingHorizontal: theme.margin.common,
59+
paddingVertical: theme.margin.half,
60+
borderRadius: theme.margin.common,
61+
minWidth: 44,
62+
justifyContent: 'center',
63+
},
64+
})
6065

6166
export default Chip

src/components/ContentImage.tsx

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@ import { Dimensions, Image, StyleSheet, Text, TouchableOpacity, View } from 'rea
44
import ScalableImage from 'react-native-scalable-image'
55

66
import Lightbox from './Lightbox'
7-
import { font, rounded, shadow, theme } from '../styles'
7+
import { Theme } from '../@types/theme'
8+
import { font, rounded, shadow } from '../styles'
9+
import { useTheme } from '../theme/ThemeProvider'
810

911
type Props = {
1012
src: string
1113
alt?: string
1214
}
1315

1416
const ContentImage = ({ src, alt }: Props) => {
17+
const theme = useTheme()
18+
const styles = createStyles(theme)
1519
const [photoIndex, setPhotoIndex] = React.useState<number>()
1620
if (!alt) {
1721
return <ScalableImage width={Dimensions.get('window').width - 2 * theme.margin.common} source={{ uri: src }} />
@@ -53,43 +57,44 @@ const ContentImage = ({ src, alt }: Props) => {
5357

5458
export default ContentImage
5559

56-
const styles = StyleSheet.create({
57-
outerContainer: {
58-
margin: -theme.margin.common,
59-
marginBottom: -theme.margin.half,
60-
...shadow.normal.ios,
61-
},
62-
innerContainer: {
63-
flexDirection: 'row',
64-
margin: theme.margin.common,
65-
backgroundColor: theme.color.white,
66-
...shadow.normal.android,
67-
...rounded.large,
68-
borderWidth: 1,
69-
borderColor: theme.color.grey50,
70-
},
71-
imageContainer: {
72-
margin: theme.margin.common,
73-
marginRight: theme.margin.half,
74-
...rounded.large,
75-
},
76-
image: {
77-
height: 80,
78-
width: 80,
79-
},
80-
textContainer: {
81-
flex: 1,
82-
marginRight: theme.margin.common,
83-
marginLeft: theme.margin.half,
84-
justifyContent: 'center',
85-
},
86-
title: {
87-
...font.smallBold,
88-
color: theme.color.black,
89-
marginBottom: theme.margin.quarter,
90-
},
91-
description: {
92-
...font.small,
93-
color: theme.color.grey500,
94-
},
95-
})
60+
const createStyles = (theme: Theme) =>
61+
StyleSheet.create({
62+
outerContainer: {
63+
margin: -theme.margin.common,
64+
marginBottom: -theme.margin.half,
65+
...shadow.normal.ios,
66+
},
67+
innerContainer: {
68+
flexDirection: 'row',
69+
margin: theme.margin.common,
70+
backgroundColor: theme.color.white,
71+
...shadow.normal.android,
72+
...rounded.large,
73+
borderWidth: 1,
74+
borderColor: theme.color.grey50,
75+
},
76+
imageContainer: {
77+
margin: theme.margin.common,
78+
marginRight: theme.margin.half,
79+
...rounded.large,
80+
},
81+
image: {
82+
height: 80,
83+
width: 80,
84+
},
85+
textContainer: {
86+
flex: 1,
87+
marginRight: theme.margin.common,
88+
marginLeft: theme.margin.half,
89+
justifyContent: 'center',
90+
},
91+
title: {
92+
...font.smallBold,
93+
color: theme.color.black,
94+
marginBottom: theme.margin.quarter,
95+
},
96+
description: {
97+
...font.small,
98+
color: theme.color.grey500,
99+
},
100+
})

src/components/Date.tsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,27 @@ import { StyleProp, ViewStyle } from 'react-native'
33

44
import { Icon } from './Icon'
55
import IconText from './IconText'
6-
import { theme } from '../styles'
76
import textStyle from '../styles/text'
7+
import { useTheme } from '../theme/ThemeProvider'
88

99
type Props = {
1010
date: string
1111
containerStyle?: StyleProp<ViewStyle>
1212
}
1313

14-
const Date = ({ date, containerStyle }: Props) => (
15-
<IconText
16-
icon={<Icon name="calendar-day" style={'solid'} color={theme.color.grey300} size={theme.icon.size.m} />}
17-
text={date}
18-
style={{
19-
containerStyle,
20-
textStyle: textStyle.light,
21-
}}
22-
singleLineText
23-
/>
24-
)
14+
const Date = ({ date, containerStyle }: Props) => {
15+
const theme = useTheme()
16+
return (
17+
<IconText
18+
icon={<Icon name="calendar-day" style={'solid'} color={theme.color.grey300} size={theme.icon.size.m} />}
19+
text={date}
20+
style={{
21+
containerStyle,
22+
textStyle: textStyle.light,
23+
}}
24+
singleLineText
25+
/>
26+
)
27+
}
2528

2629
export default Date

0 commit comments

Comments
 (0)