Skip to content

Commit 61cdf43

Browse files
committed
Remove react-native-appearance dependency and add more test
1 parent cfae018 commit 61cdf43

File tree

10 files changed

+70
-158
lines changed

10 files changed

+70
-158
lines changed

README.md

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,23 @@
1111

1212
A package that allows you to create React Native StyleSheets with support for Dark/Light/Auto Themes.
1313

14-
- Depends on react-native-appearance to choose the theme based on OS preference(Android 10/iOS 13)
1514
- Simple API
1615
- Fully typed
1716
- Builds on top of StyleSheets and Hooks
1817
- Storybook addon to change Theme Mode
1918

2019
## Installation
2120

22-
**Using Expo**
23-
24-
```
25-
expo install react-native-appearance react-native-themed-stylesheet
26-
```
27-
2821
**Using Yarn**
2922

3023
```
31-
yarn add react-native-appearance react-native-themed-stylesheet
24+
yarn add react-native-themed-stylesheet
3225
```
3326

3427
**Using NPM**
3528

3629
```
37-
npm install --save react-native-appearance react-native-themed-stylesheet
30+
npm install --save react-native-themed-stylesheet
3831
```
3932

4033
## Usage

__mocks__/react-native-appearance.tsx

Lines changed: 0 additions & 52 deletions
This file was deleted.

package.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-themed-stylesheet",
3-
"version": "0.3.2",
3+
"version": "0.3.3",
44
"description": "React Native StyleSheets with Theming Support",
55
"author": "Andre Pedroza",
66
"license": "MIT",
@@ -29,8 +29,7 @@
2929
"peerDependencies": {
3030
"@storybook/addons": "*",
3131
"react": "*",
32-
"react-native": "*",
33-
"react-native-appearance": "*"
32+
"react-native": "*"
3433
},
3534
"devDependencies": {
3635
"@babel/core": "^7.12.16",
@@ -52,7 +51,6 @@
5251
"jest": "^26.6.3",
5352
"react": "16.13.1",
5453
"react-native": "0.63.4",
55-
"react-native-appearance": "~0.3.3",
5654
"react-test-renderer": "16.13.1",
5755
"ts-jest": "^26.5.1",
5856
"typescript": "~4.0.0"

src/index.ts

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@ import React, {
77
useEffect,
88
useState
99
} from 'react'
10-
import { ImageStyle, StyleSheet, TextStyle, ViewStyle } from 'react-native'
11-
import { Appearance, AppearanceProvider } from 'react-native-appearance'
10+
import {
11+
ImageStyle,
12+
StyleSheet,
13+
TextStyle,
14+
useColorScheme,
15+
ViewStyle
16+
} from 'react-native'
1217
import merge from 'ts-deepmerge'
1318

1419
export interface BaseTheme {}
@@ -67,7 +72,7 @@ type ThemeProviderProps = {
6772

6873
const themeContext = createContext<ThemeContext>({} as ThemeContext)
6974

70-
const generateTheme = (mode: ThemeMode, themes: Themes) => {
75+
const generateTheme = (mode: Exclude<ThemeMode, 'auto'>, themes: Themes) => {
7176
if (
7277
typeof themes !== 'object' ||
7378
!themes ||
@@ -78,42 +83,27 @@ const generateTheme = (mode: ThemeMode, themes: Themes) => {
7883
) {
7984
return {}
8085
}
81-
const constants = 'constants' in themes ? themes['constants'] : {}
82-
const systemColorScheme = Appearance.getColorScheme()
83-
const currentMode =
84-
mode !== 'auto'
85-
? mode
86-
: systemColorScheme !== 'no-preference'
87-
? systemColorScheme
88-
: 'light'
89-
return merge(constants, themes[currentMode])
86+
const constants = ('constants' in themes ? themes['constants'] : {}) || {}
87+
return merge(constants, themes[mode])
9088
}
9189

92-
const RawThemeProvider: React.FC<ThemeProviderProps> = ({
90+
export const ThemeProvider: React.FC<ThemeProviderProps> = ({
9391
children,
9492
mode: initialMode,
9593
themes: initialThemes
9694
}) => {
95+
const colorScheme = useColorScheme()
9796
const [mode, setMode] = useState(initialMode ?? 'auto')
9897
const [themes, setThemes] = useState(initialThemes)
99-
const [theme, setTheme] = useState(generateTheme(mode, themes))
98+
const [theme, setTheme] = useState(
99+
generateTheme(mode !== 'auto' ? mode : colorScheme || 'light', themes)
100+
)
100101
useEffect(() => {
101-
let subscription: any
102-
setTheme(generateTheme(mode, themes))
103-
if (mode === 'auto') {
104-
subscription = Appearance.addChangeListener(({ colorScheme }) => {
105-
setTheme(
106-
generateTheme(
107-
colorScheme !== 'no-preference' ? colorScheme : 'light',
108-
themes
109-
)
110-
)
111-
})
112-
}
113-
return () => {
114-
subscription && subscription.remove()
115-
}
102+
mode !== 'auto' && setTheme(generateTheme(mode, themes))
116103
}, [mode, themes])
104+
useEffect(() => {
105+
mode === 'auto' && setTheme(generateTheme(colorScheme || 'light', themes))
106+
}, [colorScheme, mode, themes])
117107
return createElement(
118108
themeContext.Provider,
119109
{
@@ -129,16 +119,6 @@ const RawThemeProvider: React.FC<ThemeProviderProps> = ({
129119
)
130120
}
131121

132-
export const ThemeProvider: typeof RawThemeProvider = ({
133-
children,
134-
...props
135-
}) =>
136-
createElement(
137-
AppearanceProvider,
138-
null,
139-
createElement(RawThemeProvider, props, children)
140-
)
141-
142122
export const useMode: UseMode = () => {
143123
const { mode, setMode } = useContext(themeContext)
144124
return [mode, setMode]

tests/__mocks__/react-native.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { useState } from 'react'
2+
import * as ReactNative from 'react-native'
3+
import { Appearance } from '../fixture'
4+
5+
// eslint-disable-next-line import/export
6+
export * from 'react-native'
7+
8+
export const useColorScheme = () => {
9+
const [value, setValue] = useState<'dark' | 'light' | null>(null)
10+
Appearance.listener = setValue
11+
return value
12+
}
13+
14+
export default Object.setPrototypeOf({ useColorScheme }, ReactNative)

tests/fixture.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
type AppearanceType = {
2+
listener: null | ((v: 'dark' | 'light' | null) => void)
3+
set: (v: 'dark' | 'light' | null) => void
4+
}
5+
6+
export const Appearance: AppearanceType = {
7+
listener: null,
8+
set (v) {
9+
typeof this.listener === 'function' && this.listener(v)
10+
this.listener = null
11+
}
12+
}
13+
114
export const themes1 = {
215
light: {
316
colors: {

tests/with-constants.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,19 @@
11
import { createElement } from 'react'
22
import { TextStyle } from 'react-native'
33
import { renderHook, act } from '@testing-library/react-hooks/native'
4-
import { Appearance } from '../__mocks__/react-native-appearance'
54
import {
65
ThemeProvider,
76
useCreateStyles,
87
useMode,
98
useTheme,
109
useThemes
1110
} from '../src/index'
12-
import { createStyles, themes1, themes2 } from './fixture'
13-
11+
import { Appearance, createStyles, themes1, themes2 } from './fixture'
1412
declare module '../src/index' {
1513
type Themes1 = typeof themes1
1614
export interface BaseTheme extends Themes1 {}
1715
}
1816

19-
beforeEach(() => {
20-
Appearance.preference = 'no-preference'
21-
})
22-
2317
describe('Auto Mode', () => {
2418
const wrapper: typeof ThemeProvider = ({ children }) =>
2519
createElement(ThemeProvider, { themes: themes1 }, children)
@@ -64,14 +58,14 @@ describe('Change System Preference', () => {
6458
test('To "no-preference" to Get Light Mode', () => {
6559
const { result } = renderHook(() => useTheme(), { wrapper })
6660
act(() => {
67-
Appearance.preference = 'no-preference'
61+
Appearance.set(null)
6862
})
6963
expect(result.current.colors.primary).toEqual('#a1a1a1')
7064
})
7165
test('To Dark Mode', () => {
7266
const { result } = renderHook(() => useTheme(), { wrapper })
7367
act(() => {
74-
Appearance.preference = 'dark'
68+
Appearance.set('dark')
7569
})
7670
expect(result.current.colors.primary).toEqual('#a2a2a2')
7771
})
@@ -85,7 +79,7 @@ describe('Change System Preference', () => {
8579
{ wrapper }
8680
)
8781
act(() => {
88-
Appearance.preference = 'light'
82+
Appearance.set('light')
8983
result.current.setMode('dark')
9084
})
9185
expect(result.current.theme.colors.primary).toEqual('#a2a2a2')

tests/with-exceptions.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
import { createElement } from 'react'
22
import { renderHook } from '@testing-library/react-hooks/native'
3-
import { Appearance } from '../__mocks__/react-native-appearance'
43
import { ThemeProvider, useTheme } from '../src/index'
54

6-
beforeEach(() => {
7-
Appearance.preference = 'no-preference'
8-
})
9-
105
describe('With Exceptions', () => {
116
test('Themes as null', () => {
127
const wrapper: typeof ThemeProvider = ({ children }) =>
@@ -56,4 +51,20 @@ describe('With Exceptions', () => {
5651
const { result } = renderHook(() => useTheme(), { wrapper })
5752
expect(Object.keys(result.current).length).toEqual(0)
5853
})
54+
test('Constants as undefined', () => {
55+
const wrapper: typeof ThemeProvider = ({ children }) =>
56+
createElement(
57+
ThemeProvider,
58+
{
59+
themes: {
60+
constants: undefined,
61+
dark: { color: '#a1a1a1' },
62+
light: { color: '#a2a2a2' }
63+
}
64+
},
65+
children
66+
)
67+
const { result } = renderHook(() => useTheme(), { wrapper })
68+
expect(Object.keys(result.current).length).toEqual(1)
69+
})
5970
})

tests/without-constants.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { createElement } from 'react'
22
import { renderHook } from '@testing-library/react-hooks/native'
3-
import { Appearance } from '../__mocks__/react-native-appearance'
43
import { ThemeProvider, useTheme } from '../src/index'
54
import { themes3 } from './fixture'
65

@@ -9,10 +8,6 @@ declare module '../src/index' {
98
export interface BaseTheme extends Themes3 {}
109
}
1110

12-
beforeEach(() => {
13-
Appearance.preference = 'no-preference'
14-
})
15-
1611
describe('Without Constants', () => {
1712
const wrapper: typeof ThemeProvider = ({ children }) =>
1813
createElement(ThemeProvider, { themes: themes3 }, children)

0 commit comments

Comments
 (0)