Add a design system (#34)

* Add theming system

* Add standard Button control and update RadioButtons

* Unify radiobutton with design system

* Update debug screen to have multiple views

* Add ToggleButton

* Update error controls to use design system

* Add typography to <Text> element

* Move DropdownButton into the design system

* Clean out old code

* Move Text into design system

* Add 'inverted' color palette

* Move LoadingPlaceholder into the design system
This commit is contained in:
Paul Frazee 2022-12-28 14:06:01 -06:00 committed by GitHub
parent cc63660982
commit 7e31645e9a
78 changed files with 1431 additions and 375 deletions

View file

@ -0,0 +1,70 @@
import React, {createContext, useContext, useMemo} from 'react'
import {TextStyle, useColorScheme, ViewStyle} from 'react-native'
import {darkTheme, defaultTheme} from './themes'
export type ColorScheme = 'light' | 'dark'
export type PaletteColorName =
| 'default'
| 'primary'
| 'secondary'
| 'inverted'
| 'error'
export type PaletteColor = {
isLowContrast: boolean
background: string
backgroundLight: string
text: string
textLight: string
textInverted: string
link: string
border: string
icon: string
}
export type Palette = Record<PaletteColorName, PaletteColor>
export type ShapeName = 'button' | 'bigButton' | 'smallButton'
export type Shapes = Record<ShapeName, ViewStyle>
export type TypographyVariant =
| 'h1'
| 'h2'
| 'h3'
| 'h4'
| 'subtitle1'
| 'subtitle2'
| 'body1'
| 'body2'
| 'button'
| 'caption'
| 'overline'
export type Typography = Record<TypographyVariant, TextStyle>
export interface Theme {
colorScheme: ColorScheme
palette: Palette
shapes: Shapes
typography: Typography
}
export interface ThemeProviderProps {
theme?: ColorScheme
}
export const ThemeContext = createContext<Theme>(defaultTheme)
export const useTheme = () => useContext(ThemeContext)
export const ThemeProvider: React.FC<ThemeProviderProps> = ({
theme,
children,
}) => {
const colorScheme = useColorScheme()
const value = useMemo(
() => ((theme || colorScheme) === 'dark' ? darkTheme : defaultTheme),
[colorScheme, theme],
)
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
}

View file

@ -1,6 +1,6 @@
import {useState} from 'react'
import {NativeSyntheticEvent, NativeScrollEvent} from 'react-native'
import {RootStoreModel} from '../../state'
import {RootStoreModel} from '../../../state'
export type OnScrollCb = (
event: NativeSyntheticEvent<NativeScrollEvent>,

View file

@ -0,0 +1,41 @@
import {TextStyle, ViewStyle} from 'react-native'
import {useTheme, PaletteColorName, PaletteColor} from '../ThemeContext'
export interface UsePaletteValue {
colors: PaletteColor
view: ViewStyle
border: ViewStyle
text: TextStyle
textLight: TextStyle
textInverted: TextStyle
link: TextStyle
}
export function usePalette(color: PaletteColorName): UsePaletteValue {
const palette = useTheme().palette[color]
return {
colors: palette,
view: {
backgroundColor: palette.background,
},
border: {
borderWidth: 1,
borderColor: palette.border,
},
text: {
color: palette.text,
fontWeight: palette.isLowContrast ? '500' : undefined,
},
textLight: {
color: palette.textLight,
fontWeight: palette.isLowContrast ? '500' : undefined,
},
textInverted: {
color: palette.textInverted,
fontWeight: palette.isLowContrast ? '500' : undefined,
},
link: {
color: palette.link,
fontWeight: palette.isLowContrast ? '500' : undefined,
},
}
}

163
src/view/lib/themes.ts Normal file
View file

@ -0,0 +1,163 @@
import type {Theme} from './ThemeContext'
import {colors} from './styles'
export const defaultTheme: Theme = {
colorScheme: 'light',
palette: {
default: {
isLowContrast: false,
background: colors.white,
backgroundLight: colors.gray2,
text: colors.black,
textLight: colors.gray5,
textInverted: colors.white,
link: colors.blue3,
border: colors.gray3,
icon: colors.gray2,
},
primary: {
isLowContrast: true,
background: colors.blue3,
backgroundLight: colors.blue2,
text: colors.white,
textLight: colors.blue0,
textInverted: colors.blue3,
link: colors.blue0,
border: colors.blue4,
icon: colors.blue4,
},
secondary: {
isLowContrast: true,
background: colors.green3,
backgroundLight: colors.green2,
text: colors.white,
textLight: colors.green1,
textInverted: colors.green4,
link: colors.green1,
border: colors.green4,
icon: colors.green4,
},
inverted: {
isLowContrast: true,
background: colors.black,
backgroundLight: colors.gray6,
text: colors.white,
textLight: colors.gray3,
textInverted: colors.black,
link: colors.blue2,
border: colors.gray3,
icon: colors.gray5,
},
error: {
isLowContrast: true,
background: colors.red3,
backgroundLight: colors.red2,
text: colors.white,
textLight: colors.red1,
textInverted: colors.red3,
link: colors.red1,
border: colors.red4,
icon: colors.red4,
},
},
shapes: {
button: {
// TODO
},
bigButton: {
// TODO
},
smallButton: {
// TODO
},
},
typography: {
h1: {
fontSize: 48,
fontWeight: '500',
},
h2: {
fontSize: 34,
letterSpacing: 0.25,
fontWeight: '500',
},
h3: {
fontSize: 24,
fontWeight: '500',
},
h4: {
fontWeight: '500',
fontSize: 20,
letterSpacing: 0.15,
},
subtitle1: {
fontSize: 16,
letterSpacing: 0.15,
},
subtitle2: {
fontWeight: '500',
fontSize: 14,
letterSpacing: 0.1,
},
body1: {
fontSize: 16,
letterSpacing: 0.5,
},
body2: {
fontSize: 14,
letterSpacing: 0.25,
},
button: {
fontWeight: '500',
fontSize: 14,
letterSpacing: 0.5,
},
caption: {
fontSize: 12,
letterSpacing: 0.4,
},
overline: {
fontSize: 10,
letterSpacing: 1.5,
textTransform: 'uppercase',
},
},
}
export const darkTheme: Theme = {
...defaultTheme,
colorScheme: 'dark',
palette: {
...defaultTheme.palette,
default: {
isLowContrast: true,
background: colors.black,
backgroundLight: colors.gray6,
text: colors.white,
textLight: colors.gray3,
textInverted: colors.black,
link: colors.blue2,
border: colors.gray3,
icon: colors.gray5,
},
primary: {
...defaultTheme.palette.primary,
textInverted: colors.blue2,
},
secondary: {
...defaultTheme.palette.secondary,
textInverted: colors.green2,
},
inverted: {
isLowContrast: false,
background: colors.white,
backgroundLight: colors.gray2,
text: colors.black,
textLight: colors.gray5,
textInverted: colors.white,
link: colors.blue3,
border: colors.gray3,
icon: colors.gray1,
},
},
}

View file

@ -1,2 +0,0 @@
export const FAB = 1
export const BASE = 0