forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import React from 'react'
2import {type Theme, type ThemeName} from '@bsky.app/alf'
3
4import {
5 computeFontScaleMultiplier,
6 getFontFamily,
7 getFontScale,
8 setFontFamily as persistFontFamily,
9 setFontScale as persistFontScale,
10} from '#/alf/fonts'
11import {themes} from '#/alf/themes'
12import {type Device} from '#/storage'
13
14export {type TextStyleProp, type Theme, type ViewStyleProp} from '@bsky.app/alf'
15export {atoms} from '#/alf/atoms'
16export * from '#/alf/breakpoints'
17export * from '#/alf/fonts'
18export * as tokens from '#/alf/tokens'
19export * from '#/alf/util/flatten'
20export * from '#/alf/util/platform'
21export * from '#/alf/util/themeSelector'
22export * from '#/alf/util/useGutters'
23
24export type Alf = {
25 themeName: ThemeName
26 theme: Theme
27 themes: typeof themes
28 fonts: {
29 scale: Exclude<Device['fontScale'], undefined>
30 scaleMultiplier: number
31 family: Device['fontFamily']
32 setFontScale: (fontScale: Exclude<Device['fontScale'], undefined>) => void
33 setFontFamily: (fontFamily: Device['fontFamily']) => void
34 }
35 /**
36 * Feature flags or other gated options
37 */
38 flags: {}
39}
40
41/*
42 * Context
43 */
44export const Context = React.createContext<Alf>({
45 themeName: 'light',
46 theme: themes.light,
47 themes,
48 fonts: {
49 scale: getFontScale(),
50 scaleMultiplier: computeFontScaleMultiplier(getFontScale()),
51 family: getFontFamily(),
52 setFontScale: () => {},
53 setFontFamily: () => {},
54 },
55 flags: {},
56})
57Context.displayName = 'AlfContext'
58
59export function ThemeProvider({
60 children,
61 theme: themeName,
62}: React.PropsWithChildren<{theme: ThemeName}>) {
63 const [fontScale, setFontScale] = React.useState<Alf['fonts']['scale']>(() =>
64 getFontScale(),
65 )
66 const [fontScaleMultiplier, setFontScaleMultiplier] = React.useState(() =>
67 computeFontScaleMultiplier(fontScale),
68 )
69 const setFontScaleAndPersist = React.useCallback<
70 Alf['fonts']['setFontScale']
71 >(
72 fs => {
73 setFontScale(fs)
74 persistFontScale(fs)
75 setFontScaleMultiplier(computeFontScaleMultiplier(fs))
76 },
77 [setFontScale],
78 )
79 const [fontFamily, setFontFamily] = React.useState<Alf['fonts']['family']>(
80 () => getFontFamily(),
81 )
82 const setFontFamilyAndPersist = React.useCallback<
83 Alf['fonts']['setFontFamily']
84 >(
85 ff => {
86 setFontFamily(ff)
87 persistFontFamily(ff)
88 },
89 [setFontFamily],
90 )
91
92 const value = React.useMemo<Alf>(
93 () => ({
94 themes,
95 themeName: themeName,
96 theme: themes[themeName],
97 fonts: {
98 scale: fontScale,
99 scaleMultiplier: fontScaleMultiplier,
100 family: fontFamily,
101 setFontScale: setFontScaleAndPersist,
102 setFontFamily: setFontFamilyAndPersist,
103 },
104 flags: {},
105 }),
106 [
107 themeName,
108 fontScale,
109 setFontScaleAndPersist,
110 fontFamily,
111 setFontFamilyAndPersist,
112 fontScaleMultiplier,
113 ],
114 )
115
116 return <Context.Provider value={value}>{children}</Context.Provider>
117}
118
119export function useAlf() {
120 return React.useContext(Context)
121}
122
123export function useTheme(theme?: ThemeName) {
124 const alf = useAlf()
125 return React.useMemo(() => {
126 return theme ? alf.themes[theme] : alf.theme
127 }, [theme, alf])
128}