about summary refs log tree commit diff
path: root/src/alf/index.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/alf/index.tsx')
-rw-r--r--src/alf/index.tsx101
1 files changed, 89 insertions, 12 deletions
diff --git a/src/alf/index.tsx b/src/alf/index.tsx
index d699de6a5..f9d93d4ca 100644
--- a/src/alf/index.tsx
+++ b/src/alf/index.tsx
@@ -1,25 +1,47 @@
 import React from 'react'
 import {useMediaQuery} from 'react-responsive'
 
+import {
+  computeFontScaleMultiplier,
+  getFontFamily,
+  getFontScale,
+  setFontFamily as persistFontFamily,
+  setFontScale as persistFontScale,
+} from '#/alf/fonts'
 import {createThemes, defaultTheme} from '#/alf/themes'
 import {Theme, ThemeName} from '#/alf/types'
 import {BLUE_HUE, GREEN_HUE, RED_HUE} from '#/alf/util/colorGeneration'
+import {Device} from '#/storage'
 
 export {atoms} from '#/alf/atoms'
+export * from '#/alf/fonts'
 export * as tokens from '#/alf/tokens'
 export * from '#/alf/types'
 export * from '#/alf/util/flatten'
 export * from '#/alf/util/platform'
 export * from '#/alf/util/themeSelector'
 
-/*
- * Context
- */
-export const Context = React.createContext<{
+export type Alf = {
   themeName: ThemeName
   theme: Theme
   themes: ReturnType<typeof createThemes>
-}>({
+  fonts: {
+    scale: Exclude<Device['fontScale'], undefined>
+    scaleMultiplier: number
+    family: Device['fontFamily']
+    setFontScale: (fontScale: Exclude<Device['fontScale'], undefined>) => void
+    setFontFamily: (fontFamily: Device['fontFamily']) => void
+  }
+  /**
+   * Feature flags or other gated options
+   */
+  flags: {}
+}
+
+/*
+ * Context
+ */
+export const Context = React.createContext<Alf>({
   themeName: 'light',
   theme: defaultTheme,
   themes: createThemes({
@@ -29,12 +51,48 @@ export const Context = React.createContext<{
       positive: GREEN_HUE,
     },
   }),
+  fonts: {
+    scale: getFontScale(),
+    scaleMultiplier: computeFontScaleMultiplier(getFontScale()),
+    family: getFontFamily(),
+    setFontScale: () => {},
+    setFontFamily: () => {},
+  },
+  flags: {},
 })
 
 export function ThemeProvider({
   children,
   theme: themeName,
 }: React.PropsWithChildren<{theme: ThemeName}>) {
+  const [fontScale, setFontScale] = React.useState<Alf['fonts']['scale']>(() =>
+    getFontScale(),
+  )
+  const [fontScaleMultiplier, setFontScaleMultiplier] = React.useState(() =>
+    computeFontScaleMultiplier(fontScale),
+  )
+  const setFontScaleAndPersist = React.useCallback<
+    Alf['fonts']['setFontScale']
+  >(
+    fontScale => {
+      setFontScale(fontScale)
+      persistFontScale(fontScale)
+      setFontScaleMultiplier(computeFontScaleMultiplier(fontScale))
+    },
+    [setFontScale],
+  )
+  const [fontFamily, setFontFamily] = React.useState<Alf['fonts']['family']>(
+    () => getFontFamily(),
+  )
+  const setFontFamilyAndPersist = React.useCallback<
+    Alf['fonts']['setFontFamily']
+  >(
+    fontFamily => {
+      setFontFamily(fontFamily)
+      persistFontFamily(fontFamily)
+    },
+    [setFontFamily],
+  )
   const themes = React.useMemo(() => {
     return createThemes({
       hues: {
@@ -44,28 +102,47 @@ export function ThemeProvider({
       },
     })
   }, [])
-  const theme = themes[themeName]
 
   return (
     <Context.Provider
-      value={React.useMemo(
+      value={React.useMemo<Alf>(
         () => ({
           themes,
           themeName: themeName,
-          theme: theme,
+          theme: themes[themeName],
+          fonts: {
+            scale: fontScale,
+            scaleMultiplier: fontScaleMultiplier,
+            family: fontFamily,
+            setFontScale: setFontScaleAndPersist,
+            setFontFamily: setFontFamilyAndPersist,
+          },
+          flags: {},
         }),
-        [theme, themeName, themes],
+        [
+          themeName,
+          themes,
+          fontScale,
+          setFontScaleAndPersist,
+          fontFamily,
+          setFontFamilyAndPersist,
+          fontScaleMultiplier,
+        ],
       )}>
       {children}
     </Context.Provider>
   )
 }
 
+export function useAlf() {
+  return React.useContext(Context)
+}
+
 export function useTheme(theme?: ThemeName) {
-  const ctx = React.useContext(Context)
+  const alf = useAlf()
   return React.useMemo(() => {
-    return theme ? ctx.themes[theme] : ctx.theme
-  }, [theme, ctx])
+    return theme ? alf.themes[theme] : alf.theme
+  }, [theme, alf])
 }
 
 export function useBreakpoints() {