bsky-app/src/alf/index.tsx

94 lines
2.1 KiB
TypeScript
Raw Normal View History

import React from 'react'
import {Dimensions} from 'react-native'
import * as themes from '#/alf/themes'
export * as tokens from '#/alf/tokens'
export {atoms} from '#/alf/atoms'
export * from '#/alf/util/platform'
New component library based on ALF (#2459) * Install on native as well * Add button and link components * Comments * Use new prop * Add some form elements * Add labels to input * Fix line height, add suffix * Date inputs * Autofill styles * Clean up InputDate types * Improve types for InputText, value handling * Enforce a11y props on buttons * Add Dialog, Portal * Dialog contents * Native dialog * Clean up * Fix animations * Improvements to web modal, exiting still broken * Clean up dialog types * Add Prompt, Dialog refinement, mobile refinement * Integrate new design tokens, reorg storybook * Button colors * Dim mode * Reorg * Some styles * Toggles * Improve a11y * Autosize dialog, handle max height, Dialog.ScrolLView not working * Try to use BottomSheet's own APIs * Scrollable dialogs * Add web shadow * Handle overscroll * Styles * Dialog text input * Shadows * Button focus states * Button pressed states * Gradient poc * Gradient colors and hovers * Add hrefAttrs to Link * Some more a11y * Toggle invalid states * Update dialog descriptions for demo * Icons * WIP Toggle cleanup * Refactor toggle to not rely on immediate children * Make Toggle controlled * Clean up Toggles storybook * ToggleButton styles * Improve a11y labels * ToggleButton hover darkmode * Some i18n * Refactor input * Allow extension of input * Remove old input * Improve icons, add CalendarDays * Refactor DateField, web done * Add label example * Clean up old InputDate, DateField android, text area example * Consistent imports * Button context, icons * Add todo * Add closeAllDialogs control * Alignment * Expand color palette * Hitslops, add shortcut to Storybook in dev * Fix multiline on ios * Mark dialog close button as unused
2024-01-19 03:28:04 +01:00
export * from '#/alf/util/flatten'
type BreakpointName = keyof typeof breakpoints
/*
* Breakpoints
*/
const breakpoints: {
[key: string]: number
} = {
gtMobile: 800,
gtTablet: 1200,
}
function getActiveBreakpoints({width}: {width: number}) {
const active: (keyof typeof breakpoints)[] = Object.keys(breakpoints).filter(
breakpoint => width >= breakpoints[breakpoint],
)
return {
active: active[active.length - 1],
gtMobile: active.includes('gtMobile'),
gtTablet: active.includes('gtTablet'),
}
}
/*
* Context
*/
export const Context = React.createContext<{
themeName: themes.ThemeName
theme: themes.Theme
breakpoints: {
active: BreakpointName | undefined
gtMobile: boolean
gtTablet: boolean
}
}>({
themeName: 'light',
theme: themes.light,
breakpoints: {
active: undefined,
gtMobile: false,
gtTablet: false,
},
})
export function ThemeProvider({
children,
theme: themeName,
}: React.PropsWithChildren<{theme: themes.ThemeName}>) {
const theme = themes[themeName]
const [breakpoints, setBreakpoints] = React.useState(() =>
getActiveBreakpoints({width: Dimensions.get('window').width}),
)
React.useEffect(() => {
const listener = Dimensions.addEventListener('change', ({window}) => {
const bp = getActiveBreakpoints({width: window.width})
if (bp.active !== breakpoints.active) setBreakpoints(bp)
})
return listener.remove
}, [breakpoints, setBreakpoints])
return (
<Context.Provider
value={React.useMemo(
() => ({
themeName: themeName,
theme: theme,
breakpoints,
}),
[theme, themeName, breakpoints],
)}>
{children}
</Context.Provider>
)
}
export function useTheme() {
return React.useContext(Context).theme
}
export function useBreakpoints() {
return React.useContext(Context).breakpoints
}