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