Add persistent state provider (#1830)

* Add persistent state provider

* Catch write error

* Handle read errors, update error msgs

* Fix lint

* Don't provide initial state to loader

* Remove colorMode from shell state

* Idea: hook into persisted context from other files

* Migrate settings to new hook

* Rework persisted state to split individual contexts

* Tweak persisted schema and validation

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
This commit is contained in:
Eric Bailey 2023-11-07 16:06:17 -06:00 committed by GitHub
parent bfe196bac5
commit 96d8faf4b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 467 additions and 76 deletions

View file

@ -0,0 +1,56 @@
import React from 'react'
import {isWeb} from '#/platform/detection'
import * as persisted from '#/state/persisted'
type StateContext = persisted.Schema['colorMode']
type SetContext = (v: persisted.Schema['colorMode']) => void
const stateContext = React.createContext<StateContext>('system')
const setContext = React.createContext<SetContext>(
(_: persisted.Schema['colorMode']) => {},
)
export function Provider({children}: React.PropsWithChildren<{}>) {
const [state, setState] = React.useState(persisted.get('colorMode'))
const setStateWrapped = React.useCallback(
(colorMode: persisted.Schema['colorMode']) => {
setState(colorMode)
persisted.write('colorMode', colorMode)
updateDocument(colorMode)
},
[setState],
)
React.useEffect(() => {
return persisted.onUpdate(() => {
setState(persisted.get('colorMode'))
updateDocument(persisted.get('colorMode'))
})
}, [setStateWrapped])
return (
<stateContext.Provider value={state}>
<setContext.Provider value={setStateWrapped}>
{children}
</setContext.Provider>
</stateContext.Provider>
)
}
export function useColorMode() {
return React.useContext(stateContext)
}
export function useSetColorMode() {
return React.useContext(setContext)
}
function updateDocument(colorMode: string) {
if (isWeb && typeof window !== 'undefined') {
const html = window.document.documentElement
// remove any other color mode classes
html.className = html.className.replace(/colorMode--\w+/g, '')
html.classList.add(`colorMode--${colorMode}`)
}
}

View file

@ -2,6 +2,7 @@ import React from 'react'
import {Provider as DrawerOpenProvider} from './drawer-open'
import {Provider as DrawerSwipableProvider} from './drawer-swipe-disabled'
import {Provider as MinimalModeProvider} from './minimal-mode'
import {Provider as ColorModeProvider} from './color-mode'
export {useIsDrawerOpen, useSetDrawerOpen} from './drawer-open'
export {
@ -9,12 +10,15 @@ export {
useSetDrawerSwipeDisabled,
} from './drawer-swipe-disabled'
export {useMinimalShellMode, useSetMinimalShellMode} from './minimal-mode'
export {useColorMode, useSetColorMode} from './color-mode'
export function Provider({children}: React.PropsWithChildren<{}>) {
return (
<DrawerOpenProvider>
<DrawerSwipableProvider>
<MinimalModeProvider>{children}</MinimalModeProvider>
<MinimalModeProvider>
<ColorModeProvider>{children}</ColorModeProvider>
</MinimalModeProvider>
</DrawerSwipableProvider>
</DrawerOpenProvider>
)