11import { createContext , useCallback , useContext , useEffect , useMemo , useState } from 'react'
22import { Theme } from '../types/Theme'
3- import { usePreference } from './Preference'
3+ import { usePreference , type Preference } from './Preference'
4+ import { usePersistent } from '../hooks/usePersistent'
45import { Themes } from '../data/themes'
56import { ThemeProvider as BaseThemeProvider , CfmActionsProvider , migrateTheme } from '@concrnt/ui'
67import { useClient } from './Client'
@@ -17,6 +18,24 @@ interface Props {
1718 children : React . ReactNode
1819}
1920
21+ // 前回解決されたテーマのlocalStorageキャッシュ。ThemeProviderが解決のたびに書き、
22+ // client構築前(CachedThemeProvider)とカスタムテーマの非同期ロード完了までのつなぎ
23+ // (ThemeProvider自身のフォールバック)が読む
24+ const CACHED_THEME_KEY = 'cachedTheme'
25+
26+ // clientなしで前回のテーマを適用する軽量版Provider。起動時ローディングなど
27+ // ThemeProviderの外側で使う。キャッシュ未生成時(初回起動)はpreferenceの
28+ // テーマ名をビルトインから引き、それも無ければblue
29+ export const CachedThemeProvider = ( props : { children : React . ReactNode } ) => {
30+ const [ cachedPref ] = usePersistent < Preference > ( 'preference' )
31+ const [ cachedTheme ] = usePersistent < Theme > ( CACHED_THEME_KEY )
32+ return (
33+ < BaseThemeProvider theme = { cachedTheme ?? Themes [ cachedPref ?. themeName ?? '' ] ?? Themes . blue } >
34+ { props . children }
35+ </ BaseThemeProvider >
36+ )
37+ }
38+
2039interface ThemeLibraryState {
2140 customThemes : Record < string , Theme >
2241 reloadThemes : ( ) => Promise < void >
@@ -35,13 +54,16 @@ export const ThemeProvider = (props: Props) => {
3554 const { client } = useClient ( )
3655 const [ themeName , setThemeName ] = usePreference ( 'themeName' )
3756 const [ customThemes , setCustomThemes ] = useState < Record < string , Theme > > ( { } )
38- const theme = props . theme ?? customThemes [ themeName ] ?? Themes [ themeName ] ?? Themes . blue
57+ // カスタムテーマはロード完了までcustomThemesに入らないため、その間は前回キャッシュで
58+ // つなぐ(blueに落とすとローディング画面からの切替時に一瞬デフォルトテーマがチラつく)
59+ const [ cachedTheme ] = usePersistent < Theme > ( CACHED_THEME_KEY )
60+ const theme = props . theme ?? customThemes [ themeName ] ?? Themes [ themeName ] ?? cachedTheme ?? Themes . blue
3961
40- // 次回起動時のCachedThemeProvider用に、 解決できたテーマをキャッシュする。
41- // カスタムテーマはロード完了前は解決できないため、 未解決のままblueを書き込まないよう条件付き
62+ // 解決できたテーマをキャッシュする。カスタムテーマはロード完了前は解決できないため、
63+ // 未解決のままblueを書き込まないよう条件付き
4264 useEffect ( ( ) => {
4365 const resolved = customThemes [ themeName ] ?? Themes [ themeName ]
44- if ( resolved ) localStorage . setItem ( 'cachedTheme' , JSON . stringify ( resolved ) )
66+ if ( resolved ) localStorage . setItem ( CACHED_THEME_KEY , JSON . stringify ( resolved ) )
4567 } , [ customThemes , themeName ] )
4668
4769 const reloadThemes = useCallback ( async ( ) => {
0 commit comments