diff --git a/README.md b/README.md
index 6407dfd..c04d8bb 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,6 @@
A package that allows you to create React Native StyleSheets with support for Dark/Light/Auto Themes.
-- Depends on react-native-appearance to choose the theme based on OS preference(Android 10/iOS 13)
- Simple API
- Fully typed
- Builds on top of StyleSheets and Hooks
@@ -19,22 +18,16 @@ A package that allows you to create React Native StyleSheets with support for Da
## Installation
-**Using Expo**
-
-```
-expo install react-native-appearance react-native-themed-stylesheet
-```
-
**Using Yarn**
```
-yarn add react-native-appearance react-native-themed-stylesheet
+yarn add react-native-themed-stylesheet
```
**Using NPM**
```
-npm install --save react-native-appearance react-native-themed-stylesheet
+npm install --save react-native-themed-stylesheet
```
## Usage
diff --git a/__mocks__/react-native-appearance.tsx b/__mocks__/react-native-appearance.tsx
deleted file mode 100644
index 465ccfd..0000000
--- a/__mocks__/react-native-appearance.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import * as React from 'react'
-import { View } from 'react-native'
-import {
- AppearancePreferences,
- ColorSchemeName,
- AppearanceListener
-} from 'react-native-appearance/src/Appearance.types'
-
-type EventSubscription = {
- remove: () => void
-}
-
-export class Appearance {
- private static _preference: ColorSchemeName = 'no-preference'
- private static _listeners: AppearanceListener[] = []
- static getColorScheme (): ColorSchemeName {
- return this._preference
- }
-
- static get preference (): ColorSchemeName {
- return this._preference
- }
-
- static set preference (newPreference: ColorSchemeName) {
- this._preference = newPreference
- this._listeners.forEach(l => l({ colorScheme: this._preference }))
- }
-
- static set (_preferences: AppearancePreferences): void {}
-
- static addChangeListener (_listener: AppearanceListener): EventSubscription {
- this._listeners.push(_listener)
- return {
- remove: () => {
- this._listeners = this._listeners.filter(l => l !== _listener)
- }
- }
- }
-
- /**
- * Unused: some people might expect to remove the listener like this, but they shouldn't.
- */
- static removeChangeListener (_listener: AppearanceListener): void {}
-}
-
-export const AppearanceProvider = (props: any) => (
-
-)
-
-export function useColorScheme (): ColorSchemeName {
- return 'no-preference'
-}
diff --git a/package.json b/package.json
index b1cfbe7..5e7934d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-native-themed-stylesheet",
- "version": "0.3.2",
+ "version": "0.3.3",
"description": "React Native StyleSheets with Theming Support",
"author": "Andre Pedroza",
"license": "MIT",
@@ -29,8 +29,7 @@
"peerDependencies": {
"@storybook/addons": "*",
"react": "*",
- "react-native": "*",
- "react-native-appearance": "*"
+ "react-native": "*"
},
"devDependencies": {
"@babel/core": "^7.12.16",
@@ -52,7 +51,6 @@
"jest": "^26.6.3",
"react": "16.13.1",
"react-native": "0.63.4",
- "react-native-appearance": "~0.3.3",
"react-test-renderer": "16.13.1",
"ts-jest": "^26.5.1",
"typescript": "~4.0.0"
diff --git a/src/index.ts b/src/index.ts
index ed7fc75..958b231 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -7,8 +7,13 @@ import React, {
useEffect,
useState
} from 'react'
-import { ImageStyle, StyleSheet, TextStyle, ViewStyle } from 'react-native'
-import { Appearance, AppearanceProvider } from 'react-native-appearance'
+import {
+ ImageStyle,
+ StyleSheet,
+ TextStyle,
+ useColorScheme,
+ ViewStyle
+} from 'react-native'
import merge from 'ts-deepmerge'
export interface BaseTheme {}
@@ -67,7 +72,7 @@ type ThemeProviderProps = {
const themeContext = createContext({} as ThemeContext)
-const generateTheme = (mode: ThemeMode, themes: Themes) => {
+const generateTheme = (mode: Exclude, themes: Themes) => {
if (
typeof themes !== 'object' ||
!themes ||
@@ -78,42 +83,27 @@ const generateTheme = (mode: ThemeMode, themes: Themes) => {
) {
return {}
}
- const constants = 'constants' in themes ? themes['constants'] : {}
- const systemColorScheme = Appearance.getColorScheme()
- const currentMode =
- mode !== 'auto'
- ? mode
- : systemColorScheme !== 'no-preference'
- ? systemColorScheme
- : 'light'
- return merge(constants, themes[currentMode])
+ const constants = ('constants' in themes ? themes['constants'] : {}) || {}
+ return merge(constants, themes[mode])
}
-const RawThemeProvider: React.FC = ({
+export const ThemeProvider: React.FC = ({
children,
mode: initialMode,
themes: initialThemes
}) => {
+ const colorScheme = useColorScheme()
const [mode, setMode] = useState(initialMode ?? 'auto')
const [themes, setThemes] = useState(initialThemes)
- const [theme, setTheme] = useState(generateTheme(mode, themes))
+ const [theme, setTheme] = useState(
+ generateTheme(mode !== 'auto' ? mode : colorScheme || 'light', themes)
+ )
useEffect(() => {
- let subscription: any
- setTheme(generateTheme(mode, themes))
- if (mode === 'auto') {
- subscription = Appearance.addChangeListener(({ colorScheme }) => {
- setTheme(
- generateTheme(
- colorScheme !== 'no-preference' ? colorScheme : 'light',
- themes
- )
- )
- })
- }
- return () => {
- subscription && subscription.remove()
- }
+ mode !== 'auto' && setTheme(generateTheme(mode, themes))
}, [mode, themes])
+ useEffect(() => {
+ mode === 'auto' && setTheme(generateTheme(colorScheme || 'light', themes))
+ }, [colorScheme, mode, themes])
return createElement(
themeContext.Provider,
{
@@ -129,16 +119,6 @@ const RawThemeProvider: React.FC = ({
)
}
-export const ThemeProvider: typeof RawThemeProvider = ({
- children,
- ...props
-}) =>
- createElement(
- AppearanceProvider,
- null,
- createElement(RawThemeProvider, props, children)
- )
-
export const useMode: UseMode = () => {
const { mode, setMode } = useContext(themeContext)
return [mode, setMode]
diff --git a/tests/__mocks__/react-native.ts b/tests/__mocks__/react-native.ts
new file mode 100644
index 0000000..c1e4faf
--- /dev/null
+++ b/tests/__mocks__/react-native.ts
@@ -0,0 +1,14 @@
+import { useState } from 'react'
+import * as ReactNative from 'react-native'
+import { Appearance } from '../fixture'
+
+// eslint-disable-next-line import/export
+export * from 'react-native'
+
+export const useColorScheme = () => {
+ const [value, setValue] = useState<'dark' | 'light' | null>(null)
+ Appearance.listener = setValue
+ return value
+}
+
+export default Object.setPrototypeOf({ useColorScheme }, ReactNative)
diff --git a/tests/fixture.ts b/tests/fixture.ts
index 1220003..577b8e5 100644
--- a/tests/fixture.ts
+++ b/tests/fixture.ts
@@ -1,3 +1,16 @@
+type AppearanceType = {
+ listener: null | ((v: 'dark' | 'light' | null) => void)
+ set: (v: 'dark' | 'light' | null) => void
+}
+
+export const Appearance: AppearanceType = {
+ listener: null,
+ set (v) {
+ typeof this.listener === 'function' && this.listener(v)
+ this.listener = null
+ }
+}
+
export const themes1 = {
light: {
colors: {
diff --git a/tests/with-constants.ts b/tests/with-constants.ts
index cd46018..02dcd0a 100644
--- a/tests/with-constants.ts
+++ b/tests/with-constants.ts
@@ -1,7 +1,6 @@
import { createElement } from 'react'
import { TextStyle } from 'react-native'
import { renderHook, act } from '@testing-library/react-hooks/native'
-import { Appearance } from '../__mocks__/react-native-appearance'
import {
ThemeProvider,
useCreateStyles,
@@ -9,17 +8,12 @@ import {
useTheme,
useThemes
} from '../src/index'
-import { createStyles, themes1, themes2 } from './fixture'
-
+import { Appearance, createStyles, themes1, themes2 } from './fixture'
declare module '../src/index' {
type Themes1 = typeof themes1
export interface BaseTheme extends Themes1 {}
}
-beforeEach(() => {
- Appearance.preference = 'no-preference'
-})
-
describe('Auto Mode', () => {
const wrapper: typeof ThemeProvider = ({ children }) =>
createElement(ThemeProvider, { themes: themes1 }, children)
@@ -64,14 +58,14 @@ describe('Change System Preference', () => {
test('To "no-preference" to Get Light Mode', () => {
const { result } = renderHook(() => useTheme(), { wrapper })
act(() => {
- Appearance.preference = 'no-preference'
+ Appearance.set(null)
})
expect(result.current.colors.primary).toEqual('#a1a1a1')
})
test('To Dark Mode', () => {
const { result } = renderHook(() => useTheme(), { wrapper })
act(() => {
- Appearance.preference = 'dark'
+ Appearance.set('dark')
})
expect(result.current.colors.primary).toEqual('#a2a2a2')
})
@@ -85,7 +79,7 @@ describe('Change System Preference', () => {
{ wrapper }
)
act(() => {
- Appearance.preference = 'light'
+ Appearance.set('light')
result.current.setMode('dark')
})
expect(result.current.theme.colors.primary).toEqual('#a2a2a2')
diff --git a/tests/with-exceptions.ts b/tests/with-exceptions.ts
index 42112fe..d10c5ee 100644
--- a/tests/with-exceptions.ts
+++ b/tests/with-exceptions.ts
@@ -1,12 +1,7 @@
import { createElement } from 'react'
import { renderHook } from '@testing-library/react-hooks/native'
-import { Appearance } from '../__mocks__/react-native-appearance'
import { ThemeProvider, useTheme } from '../src/index'
-beforeEach(() => {
- Appearance.preference = 'no-preference'
-})
-
describe('With Exceptions', () => {
test('Themes as null', () => {
const wrapper: typeof ThemeProvider = ({ children }) =>
@@ -56,4 +51,20 @@ describe('With Exceptions', () => {
const { result } = renderHook(() => useTheme(), { wrapper })
expect(Object.keys(result.current).length).toEqual(0)
})
+ test('Constants as undefined', () => {
+ const wrapper: typeof ThemeProvider = ({ children }) =>
+ createElement(
+ ThemeProvider,
+ {
+ themes: {
+ constants: undefined,
+ dark: { color: '#a1a1a1' },
+ light: { color: '#a2a2a2' }
+ }
+ },
+ children
+ )
+ const { result } = renderHook(() => useTheme(), { wrapper })
+ expect(Object.keys(result.current).length).toEqual(1)
+ })
})
diff --git a/tests/without-constants.ts b/tests/without-constants.ts
index 57e89f6..bdbd4d7 100644
--- a/tests/without-constants.ts
+++ b/tests/without-constants.ts
@@ -1,6 +1,5 @@
import { createElement } from 'react'
import { renderHook } from '@testing-library/react-hooks/native'
-import { Appearance } from '../__mocks__/react-native-appearance'
import { ThemeProvider, useTheme } from '../src/index'
import { themes3 } from './fixture'
@@ -9,10 +8,6 @@ declare module '../src/index' {
export interface BaseTheme extends Themes3 {}
}
-beforeEach(() => {
- Appearance.preference = 'no-preference'
-})
-
describe('Without Constants', () => {
const wrapper: typeof ThemeProvider = ({ children }) =>
createElement(ThemeProvider, { themes: themes3 }, children)
diff --git a/yarn.lock b/yarn.lock
index 6337cad..737b0c5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2525,11 +2525,6 @@ copy-descriptor@^0.1.0:
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
-core-js@^1.0.0:
- version "1.2.7"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz"
- integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=
-
core-js@^2.4.1:
version "2.6.12"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz"
@@ -3340,13 +3335,6 @@ fb-watchman@^2.0.0:
dependencies:
bser "2.1.1"
-fbemitter@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-2.1.1.tgz"
- integrity sha1-Uj4U/a9SSIBbsC9i78M75wP1GGU=
- dependencies:
- fbjs "^0.8.4"
-
fbjs-css-vars@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz"
@@ -3368,19 +3356,6 @@ fbjs-scripts@^1.1.0:
semver "^5.1.0"
through2 "^2.0.0"
-fbjs@^0.8.4:
- version "0.8.17"
- resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz"
- integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=
- dependencies:
- core-js "^1.0.0"
- isomorphic-fetch "^2.1.1"
- loose-envify "^1.0.0"
- object-assign "^4.1.0"
- promise "^7.1.1"
- setimmediate "^1.0.5"
- ua-parser-js "^0.7.18"
-
fbjs@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-1.0.0.tgz"
@@ -6115,15 +6090,6 @@ react-lifecycles-compat@^3.0.4:
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
-react-native-appearance@~0.3.3:
- version "0.3.4"
- resolved "https://registry.yarnpkg.com/react-native-appearance/-/react-native-appearance-0.3.4.tgz"
- integrity sha512-Vz3zdJbAEiMDwuw6wH98TT1WVfBvWjvANutYtkIbl16KGRCigtSgt6IIiLsF3/TSS3y3FtHhWDelFeGw/rtuig==
- dependencies:
- fbemitter "^2.1.1"
- invariant "^2.2.4"
- use-subscription "^1.0.0"
-
react-native@0.63.4:
version "0.63.4"
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.63.4.tgz"