[ALF] Theme & palette cleanup (#4769)

* Invert primary scale

* Invert negative palette

* Replace theme specific styles in Toggle

* Remove theme specific colors from Button, improves secondary solid on dark mode

* TextField

* Remove from MessageItem

* Threadgate editor

* IconCircle

* Muted words

* Generate themes from hues

* Cleanup

* Deprecate more values, fix circular import

* Invert positive too, hardly use

* Button tweaks, some theme diffs

* Match disabled state for negative button

* Fix unread noty bg
zio/stable
Eric Bailey 2024-07-11 16:59:12 -05:00 committed by GitHub
parent ea0586cd67
commit 74186950b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 851 additions and 654 deletions

View File

@ -1,7 +1,9 @@
import React from 'react' import React from 'react'
import {Dimensions} from 'react-native' import {Dimensions} from 'react-native'
import * as themes from '#/alf/themes' import {createThemes, defaultTheme} from '#/alf/themes'
import {Theme, ThemeName} from '#/alf/types'
import {BLUE_HUE, GREEN_HUE, RED_HUE} from '#/alf/util/colorGeneration'
export {atoms} from '#/alf/atoms' export {atoms} from '#/alf/atoms'
export * as tokens from '#/alf/tokens' export * as tokens from '#/alf/tokens'
@ -39,8 +41,8 @@ function getActiveBreakpoints({width}: {width: number}) {
* Context * Context
*/ */
export const Context = React.createContext<{ export const Context = React.createContext<{
themeName: themes.ThemeName themeName: ThemeName
theme: themes.Theme theme: Theme
breakpoints: { breakpoints: {
active: BreakpointName | undefined active: BreakpointName | undefined
gtPhone: boolean gtPhone: boolean
@ -49,7 +51,7 @@ export const Context = React.createContext<{
} }
}>({ }>({
themeName: 'light', themeName: 'light',
theme: themes.light, theme: defaultTheme,
breakpoints: { breakpoints: {
active: undefined, active: undefined,
gtPhone: false, gtPhone: false,
@ -61,7 +63,16 @@ export const Context = React.createContext<{
export function ThemeProvider({ export function ThemeProvider({
children, children,
theme: themeName, theme: themeName,
}: React.PropsWithChildren<{theme: themes.ThemeName}>) { }: React.PropsWithChildren<{theme: ThemeName}>) {
const themes = React.useMemo(() => {
return createThemes({
hues: {
primary: BLUE_HUE,
negative: RED_HUE,
positive: GREEN_HUE,
},
})
}, [])
const theme = themes[themeName] const theme = themes[themeName]
const [breakpoints, setBreakpoints] = React.useState(() => const [breakpoints, setBreakpoints] = React.useState(() =>
getActiveBreakpoints({width: Dimensions.get('window').width}), getActiveBreakpoints({width: Dimensions.get('window').width}),

View File

@ -1,199 +1,311 @@
import {atoms} from '#/alf/atoms' import {atoms} from '#/alf/atoms'
import * as tokens from '#/alf/tokens' import {Palette, Theme} from '#/alf/types'
import type {Mutable} from '#/alf/types' import {
import {BLUE_HUE, GREEN_HUE, RED_HUE} from '#/alf/util/colorGeneration' BLUE_HUE,
defaultScale,
dimScale,
GREEN_HUE,
RED_HUE,
} from '#/alf/util/colorGeneration'
export type ThemeName = 'light' | 'dim' | 'dark' const themes = createThemes({
export type ReadonlyTheme = typeof light hues: {
export type Theme = Mutable<ReadonlyTheme> & {name: ThemeName} primary: BLUE_HUE,
export type ReadonlyPalette = typeof lightPalette negative: RED_HUE,
export type Palette = Mutable<ReadonlyPalette> positive: GREEN_HUE,
},
})
export const lightPalette = { /**
white: tokens.color.gray_0, * @deprecated use ALF and access palette from `useTheme()`
black: tokens.color.gray_1000, */
export const lightPalette = themes.lightPalette
/**
* @deprecated use ALF and access palette from `useTheme()`
*/
export const darkPalette = themes.darkPalette
/**
* @deprecated use ALF and access palette from `useTheme()`
*/
export const dimPalette = themes.dimPalette
/**
* @deprecated use ALF and access theme from `useTheme()`
*/
export const light = themes.light
/**
* @deprecated use ALF and access theme from `useTheme()`
*/
export const dark = themes.dark
/**
* @deprecated use ALF and access theme from `useTheme()`
*/
export const dim = themes.dim
contrast_25: tokens.color.gray_25, export const defaultTheme = themes.light
contrast_50: tokens.color.gray_50,
contrast_100: tokens.color.gray_100,
contrast_200: tokens.color.gray_200,
contrast_300: tokens.color.gray_300,
contrast_400: tokens.color.gray_400,
contrast_500: tokens.color.gray_500,
contrast_600: tokens.color.gray_600,
contrast_700: tokens.color.gray_700,
contrast_800: tokens.color.gray_800,
contrast_900: tokens.color.gray_900,
contrast_950: tokens.color.gray_950,
contrast_975: tokens.color.gray_975,
primary_25: tokens.color.blue_25, export function createThemes({
primary_50: tokens.color.blue_50, hues,
primary_100: tokens.color.blue_100, }: {
primary_200: tokens.color.blue_200, hues: {
primary_300: tokens.color.blue_300, primary: number
primary_400: tokens.color.blue_400, negative: number
primary_500: tokens.color.blue_500, positive: number
primary_600: tokens.color.blue_600, }
primary_700: tokens.color.blue_700, }): {
primary_800: tokens.color.blue_800, lightPalette: Palette
primary_900: tokens.color.blue_900, darkPalette: Palette
primary_950: tokens.color.blue_950, dimPalette: Palette
primary_975: tokens.color.blue_975, light: Theme
dark: Theme
dim: Theme
} {
const color = {
trueBlack: '#000000',
positive_25: tokens.color.green_25, gray_0: `hsl(${hues.primary}, 20%, ${defaultScale[14]}%)`,
positive_50: tokens.color.green_50, gray_25: `hsl(${hues.primary}, 20%, ${defaultScale[13]}%)`,
positive_100: tokens.color.green_100, gray_50: `hsl(${hues.primary}, 20%, ${defaultScale[12]}%)`,
positive_200: tokens.color.green_200, gray_100: `hsl(${hues.primary}, 20%, ${defaultScale[11]}%)`,
positive_300: tokens.color.green_300, gray_200: `hsl(${hues.primary}, 20%, ${defaultScale[10]}%)`,
positive_400: tokens.color.green_400, gray_300: `hsl(${hues.primary}, 20%, ${defaultScale[9]}%)`,
positive_500: tokens.color.green_500, gray_400: `hsl(${hues.primary}, 20%, ${defaultScale[8]}%)`,
positive_600: tokens.color.green_600, gray_500: `hsl(${hues.primary}, 20%, ${defaultScale[7]}%)`,
positive_700: tokens.color.green_700, gray_600: `hsl(${hues.primary}, 24%, ${defaultScale[6]}%)`,
positive_800: tokens.color.green_800, gray_700: `hsl(${hues.primary}, 24%, ${defaultScale[5]}%)`,
positive_900: tokens.color.green_900, gray_800: `hsl(${hues.primary}, 28%, ${defaultScale[4]}%)`,
positive_950: tokens.color.green_950, gray_900: `hsl(${hues.primary}, 28%, ${defaultScale[3]}%)`,
positive_975: tokens.color.green_975, gray_950: `hsl(${hues.primary}, 28%, ${defaultScale[2]}%)`,
gray_975: `hsl(${hues.primary}, 28%, ${defaultScale[1]}%)`,
gray_1000: `hsl(${hues.primary}, 28%, ${defaultScale[0]}%)`,
negative_25: tokens.color.red_25, primary_25: `hsl(${hues.primary}, 99%, 97%)`,
negative_50: tokens.color.red_50, primary_50: `hsl(${hues.primary}, 99%, 95%)`,
negative_100: tokens.color.red_100, primary_100: `hsl(${hues.primary}, 99%, 90%)`,
negative_200: tokens.color.red_200, primary_200: `hsl(${hues.primary}, 99%, 80%)`,
negative_300: tokens.color.red_300, primary_300: `hsl(${hues.primary}, 99%, 70%)`,
negative_400: tokens.color.red_400, primary_400: `hsl(${hues.primary}, 99%, 60%)`,
negative_500: tokens.color.red_500, primary_500: `hsl(${hues.primary}, 99%, 53%)`,
negative_600: tokens.color.red_600, primary_600: `hsl(${hues.primary}, 99%, 42%)`,
negative_700: tokens.color.red_700, primary_700: `hsl(${hues.primary}, 99%, 34%)`,
negative_800: tokens.color.red_800, primary_800: `hsl(${hues.primary}, 99%, 26%)`,
negative_900: tokens.color.red_900, primary_900: `hsl(${hues.primary}, 99%, 18%)`,
negative_950: tokens.color.red_950, primary_950: `hsl(${hues.primary}, 99%, 10%)`,
negative_975: tokens.color.red_975, primary_975: `hsl(${hues.primary}, 99%, 7%)`,
green_25: `hsl(${hues.positive}, 82%, 97%)`,
green_50: `hsl(${hues.positive}, 82%, 95%)`,
green_100: `hsl(${hues.positive}, 82%, 90%)`,
green_200: `hsl(${hues.positive}, 82%, 80%)`,
green_300: `hsl(${hues.positive}, 82%, 70%)`,
green_400: `hsl(${hues.positive}, 82%, 60%)`,
green_500: `hsl(${hues.positive}, 82%, 50%)`,
green_600: `hsl(${hues.positive}, 82%, 42%)`,
green_700: `hsl(${hues.positive}, 82%, 34%)`,
green_800: `hsl(${hues.positive}, 82%, 26%)`,
green_900: `hsl(${hues.positive}, 82%, 18%)`,
green_950: `hsl(${hues.positive}, 82%, 10%)`,
green_975: `hsl(${hues.positive}, 82%, 7%)`,
red_25: `hsl(${hues.negative}, 91%, 97%)`,
red_50: `hsl(${hues.negative}, 91%, 95%)`,
red_100: `hsl(${hues.negative}, 91%, 90%)`,
red_200: `hsl(${hues.negative}, 91%, 80%)`,
red_300: `hsl(${hues.negative}, 91%, 70%)`,
red_400: `hsl(${hues.negative}, 91%, 60%)`,
red_500: `hsl(${hues.negative}, 91%, 50%)`,
red_600: `hsl(${hues.negative}, 91%, 42%)`,
red_700: `hsl(${hues.negative}, 91%, 34%)`,
red_800: `hsl(${hues.negative}, 91%, 26%)`,
red_900: `hsl(${hues.negative}, 91%, 18%)`,
red_950: `hsl(${hues.negative}, 91%, 10%)`,
red_975: `hsl(${hues.negative}, 91%, 7%)`,
} as const } as const
export const darkPalette: Palette = { const lightPalette = {
white: tokens.color.gray_0, white: color.gray_0,
black: tokens.color.trueBlack, black: color.gray_1000,
contrast_25: tokens.color.gray_1000, contrast_25: color.gray_25,
contrast_50: tokens.color.gray_975, contrast_50: color.gray_50,
contrast_100: tokens.color.gray_950, contrast_100: color.gray_100,
contrast_200: tokens.color.gray_900, contrast_200: color.gray_200,
contrast_300: tokens.color.gray_800, contrast_300: color.gray_300,
contrast_400: tokens.color.gray_700, contrast_400: color.gray_400,
contrast_500: tokens.color.gray_600, contrast_500: color.gray_500,
contrast_600: tokens.color.gray_500, contrast_600: color.gray_600,
contrast_700: tokens.color.gray_400, contrast_700: color.gray_700,
contrast_800: tokens.color.gray_300, contrast_800: color.gray_800,
contrast_900: tokens.color.gray_200, contrast_900: color.gray_900,
contrast_950: tokens.color.gray_100, contrast_950: color.gray_950,
contrast_975: tokens.color.gray_50, contrast_975: color.gray_975,
primary_25: tokens.color.blue_25, primary_25: color.primary_25,
primary_50: tokens.color.blue_50, primary_50: color.primary_50,
primary_100: tokens.color.blue_100, primary_100: color.primary_100,
primary_200: tokens.color.blue_200, primary_200: color.primary_200,
primary_300: tokens.color.blue_300, primary_300: color.primary_300,
primary_400: tokens.color.blue_400, primary_400: color.primary_400,
primary_500: tokens.color.blue_500, primary_500: color.primary_500,
primary_600: tokens.color.blue_600, primary_600: color.primary_600,
primary_700: tokens.color.blue_700, primary_700: color.primary_700,
primary_800: tokens.color.blue_800, primary_800: color.primary_800,
primary_900: tokens.color.blue_900, primary_900: color.primary_900,
primary_950: tokens.color.blue_950, primary_950: color.primary_950,
primary_975: tokens.color.blue_975, primary_975: color.primary_975,
positive_25: tokens.color.green_25, positive_25: color.green_25,
positive_50: tokens.color.green_50, positive_50: color.green_50,
positive_100: tokens.color.green_100, positive_100: color.green_100,
positive_200: tokens.color.green_200, positive_200: color.green_200,
positive_300: tokens.color.green_300, positive_300: color.green_300,
positive_400: tokens.color.green_400, positive_400: color.green_400,
positive_500: tokens.color.green_500, positive_500: color.green_500,
positive_600: tokens.color.green_600, positive_600: color.green_600,
positive_700: tokens.color.green_700, positive_700: color.green_700,
positive_800: tokens.color.green_800, positive_800: color.green_800,
positive_900: tokens.color.green_900, positive_900: color.green_900,
positive_950: tokens.color.green_950, positive_950: color.green_950,
positive_975: tokens.color.green_975, positive_975: color.green_975,
negative_25: tokens.color.red_25, negative_25: color.red_25,
negative_50: tokens.color.red_50, negative_50: color.red_50,
negative_100: tokens.color.red_100, negative_100: color.red_100,
negative_200: tokens.color.red_200, negative_200: color.red_200,
negative_300: tokens.color.red_300, negative_300: color.red_300,
negative_400: tokens.color.red_400, negative_400: color.red_400,
negative_500: tokens.color.red_500, negative_500: color.red_500,
negative_600: tokens.color.red_600, negative_600: color.red_600,
negative_700: tokens.color.red_700, negative_700: color.red_700,
negative_800: tokens.color.red_800, negative_800: color.red_800,
negative_900: tokens.color.red_900, negative_900: color.red_900,
negative_950: tokens.color.red_950, negative_950: color.red_950,
negative_975: tokens.color.red_975, negative_975: color.red_975,
} as const } as const
export const dimPalette: Palette = { const darkPalette: Palette = {
white: color.gray_0,
black: color.trueBlack,
contrast_25: color.gray_1000,
contrast_50: color.gray_975,
contrast_100: color.gray_950,
contrast_200: color.gray_900,
contrast_300: color.gray_800,
contrast_400: color.gray_700,
contrast_500: color.gray_600,
contrast_600: color.gray_500,
contrast_700: color.gray_400,
contrast_800: color.gray_300,
contrast_900: color.gray_200,
contrast_950: color.gray_100,
contrast_975: color.gray_50,
primary_25: color.primary_975,
primary_50: color.primary_950,
primary_100: color.primary_900,
primary_200: color.primary_800,
primary_300: color.primary_700,
primary_400: color.primary_600,
primary_500: color.primary_500,
primary_600: color.primary_400,
primary_700: color.primary_300,
primary_800: color.primary_200,
primary_900: color.primary_100,
primary_950: color.primary_50,
primary_975: color.primary_25,
positive_25: color.green_975,
positive_50: color.green_950,
positive_100: color.green_900,
positive_200: color.green_800,
positive_300: color.green_700,
positive_400: color.green_600,
positive_500: color.green_500,
positive_600: color.green_400,
positive_700: color.green_300,
positive_800: color.green_200,
positive_900: color.green_100,
positive_950: color.green_50,
positive_975: color.green_25,
negative_25: color.red_975,
negative_50: color.red_950,
negative_100: color.red_900,
negative_200: color.red_800,
negative_300: color.red_700,
negative_400: color.red_600,
negative_500: color.red_500,
negative_600: color.red_400,
negative_700: color.red_300,
negative_800: color.red_200,
negative_900: color.red_100,
negative_950: color.red_50,
negative_975: color.red_25,
} as const
const dimPalette: Palette = {
...darkPalette, ...darkPalette,
black: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[0]}%)`, black: `hsl(${hues.primary}, 28%, ${dimScale[0]}%)`,
contrast_25: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[1]}%)`, contrast_25: `hsl(${hues.primary}, 28%, ${dimScale[1]}%)`,
contrast_50: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[2]}%)`, contrast_50: `hsl(${hues.primary}, 28%, ${dimScale[2]}%)`,
contrast_100: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[3]}%)`, contrast_100: `hsl(${hues.primary}, 28%, ${dimScale[3]}%)`,
contrast_200: `hsl(${BLUE_HUE}, 28%, ${tokens.dimScale[4]}%)`, contrast_200: `hsl(${hues.primary}, 28%, ${dimScale[4]}%)`,
contrast_300: `hsl(${BLUE_HUE}, 24%, ${tokens.dimScale[5]}%)`, contrast_300: `hsl(${hues.primary}, 24%, ${dimScale[5]}%)`,
contrast_400: `hsl(${BLUE_HUE}, 24%, ${tokens.dimScale[6]}%)`, contrast_400: `hsl(${hues.primary}, 24%, ${dimScale[6]}%)`,
contrast_500: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[7]}%)`, contrast_500: `hsl(${hues.primary}, 20%, ${dimScale[7]}%)`,
contrast_600: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[8]}%)`, contrast_600: `hsl(${hues.primary}, 20%, ${dimScale[8]}%)`,
contrast_700: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[9]}%)`, contrast_700: `hsl(${hues.primary}, 20%, ${dimScale[9]}%)`,
contrast_800: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[10]}%)`, contrast_800: `hsl(${hues.primary}, 20%, ${dimScale[10]}%)`,
contrast_900: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[11]}%)`, contrast_900: `hsl(${hues.primary}, 20%, ${dimScale[11]}%)`,
contrast_950: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[12]}%)`, contrast_950: `hsl(${hues.primary}, 20%, ${dimScale[12]}%)`,
contrast_975: `hsl(${BLUE_HUE}, 20%, ${tokens.dimScale[13]}%)`, contrast_975: `hsl(${hues.primary}, 20%, ${dimScale[13]}%)`,
primary_25: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[13]}%)`, primary_25: `hsl(${hues.primary}, 99%, ${dimScale[1]}%)`,
primary_50: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[12]}%)`, primary_50: `hsl(${hues.primary}, 99%, ${dimScale[2]}%)`,
primary_100: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[11]}%)`, primary_100: `hsl(${hues.primary}, 99%, ${dimScale[3]}%)`,
primary_200: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[10]}%)`, primary_200: `hsl(${hues.primary}, 99%, ${dimScale[4]}%)`,
primary_300: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[9]}%)`, primary_300: `hsl(${hues.primary}, 99%, ${dimScale[5]}%)`,
primary_400: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[8]}%)`, primary_400: `hsl(${hues.primary}, 99%, ${dimScale[6]}%)`,
primary_500: `hsl(${BLUE_HUE}, 99%, ${tokens.dimScale[7]}%)`, primary_500: `hsl(${hues.primary}, 99%, ${dimScale[7]}%)`,
primary_600: `hsl(${BLUE_HUE}, 95%, ${tokens.dimScale[6]}%)`, primary_600: `hsl(${hues.primary}, 95%, ${dimScale[8]}%)`,
primary_700: `hsl(${BLUE_HUE}, 90%, ${tokens.dimScale[5]}%)`, primary_700: `hsl(${hues.primary}, 90%, ${dimScale[9]}%)`,
primary_800: `hsl(${BLUE_HUE}, 82%, ${tokens.dimScale[4]}%)`, primary_800: `hsl(${hues.primary}, 82%, ${dimScale[10]}%)`,
primary_900: `hsl(${BLUE_HUE}, 70%, ${tokens.dimScale[3]}%)`, primary_900: `hsl(${hues.primary}, 70%, ${dimScale[11]}%)`,
primary_950: `hsl(${BLUE_HUE}, 60%, ${tokens.dimScale[2]}%)`, primary_950: `hsl(${hues.primary}, 60%, ${dimScale[12]}%)`,
primary_975: `hsl(${BLUE_HUE}, 50%, ${tokens.dimScale[1]}%)`, primary_975: `hsl(${hues.primary}, 50%, ${dimScale[13]}%)`,
positive_25: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[13]}%)`, positive_25: `hsl(${hues.positive}, 82%, ${dimScale[1]}%)`,
positive_50: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[12]}%)`, positive_50: `hsl(${hues.positive}, 82%, ${dimScale[2]}%)`,
positive_100: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[11]}%)`, positive_100: `hsl(${hues.positive}, 82%, ${dimScale[3]}%)`,
positive_200: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[10]}%)`, positive_200: `hsl(${hues.positive}, 82%, ${dimScale[4]}%)`,
positive_300: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[9]}%)`, positive_300: `hsl(${hues.positive}, 82%, ${dimScale[5]}%)`,
positive_400: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[8]}%)`, positive_400: `hsl(${hues.positive}, 82%, ${dimScale[6]}%)`,
positive_500: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[7]}%)`, positive_500: `hsl(${hues.positive}, 82%, ${dimScale[7]}%)`,
positive_600: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[6]}%)`, positive_600: `hsl(${hues.positive}, 82%, ${dimScale[8]}%)`,
positive_700: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[5]}%)`, positive_700: `hsl(${hues.positive}, 82%, ${dimScale[9]}%)`,
positive_800: `hsl(${GREEN_HUE}, 82%, ${tokens.dimScale[4]}%)`, positive_800: `hsl(${hues.positive}, 82%, ${dimScale[10]}%)`,
positive_900: `hsl(${GREEN_HUE}, 70%, ${tokens.dimScale[3]}%)`, positive_900: `hsl(${hues.positive}, 70%, ${dimScale[11]}%)`,
positive_950: `hsl(${GREEN_HUE}, 60%, ${tokens.dimScale[2]}%)`, positive_950: `hsl(${hues.positive}, 60%, ${dimScale[12]}%)`,
positive_975: `hsl(${GREEN_HUE}, 50%, ${tokens.dimScale[1]}%)`, positive_975: `hsl(${hues.positive}, 50%, ${dimScale[13]}%)`,
negative_25: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[13]}%)`, negative_25: `hsl(${hues.negative}, 91%, ${dimScale[1]}%)`,
negative_50: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[12]}%)`, negative_50: `hsl(${hues.negative}, 91%, ${dimScale[2]}%)`,
negative_100: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[11]}%)`, negative_100: `hsl(${hues.negative}, 91%, ${dimScale[3]}%)`,
negative_200: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[10]}%)`, negative_200: `hsl(${hues.negative}, 91%, ${dimScale[4]}%)`,
negative_300: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[9]}%)`, negative_300: `hsl(${hues.negative}, 91%, ${dimScale[5]}%)`,
negative_400: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[8]}%)`, negative_400: `hsl(${hues.negative}, 91%, ${dimScale[6]}%)`,
negative_500: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[7]}%)`, negative_500: `hsl(${hues.negative}, 91%, ${dimScale[7]}%)`,
negative_600: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[6]}%)`, negative_600: `hsl(${hues.negative}, 91%, ${dimScale[8]}%)`,
negative_700: `hsl(${RED_HUE}, 91%, ${tokens.dimScale[5]}%)`, negative_700: `hsl(${hues.negative}, 91%, ${dimScale[9]}%)`,
negative_800: `hsl(${RED_HUE}, 88%, ${tokens.dimScale[4]}%)`, negative_800: `hsl(${hues.negative}, 88%, ${dimScale[10]}%)`,
negative_900: `hsl(${RED_HUE}, 84%, ${tokens.dimScale[3]}%)`, negative_900: `hsl(${hues.negative}, 84%, ${dimScale[11]}%)`,
negative_950: `hsl(${RED_HUE}, 80%, ${tokens.dimScale[2]}%)`, negative_950: `hsl(${hues.negative}, 80%, ${dimScale[12]}%)`,
negative_975: `hsl(${RED_HUE}, 70%, ${tokens.dimScale[1]}%)`, negative_975: `hsl(${hues.negative}, 70%, ${dimScale[13]}%)`,
} as const } as const
export const light = { const light: Theme = {
name: 'light' as ThemeName, name: 'light',
palette: lightPalette, palette: lightPalette,
atoms: { atoms: {
text: { text: {
@ -277,8 +389,8 @@ export const light = {
}, },
} }
export const dark: Theme = { const dark: Theme = {
name: 'dark' as ThemeName, name: 'dark',
palette: darkPalette, palette: darkPalette,
atoms: { atoms: {
text: { text: {
@ -350,24 +462,24 @@ export const dark: Theme = {
shadow_sm: { shadow_sm: {
...atoms.shadow_sm, ...atoms.shadow_sm,
shadowOpacity: 0.7, shadowOpacity: 0.7,
shadowColor: tokens.color.trueBlack, shadowColor: color.trueBlack,
}, },
shadow_md: { shadow_md: {
...atoms.shadow_md, ...atoms.shadow_md,
shadowOpacity: 0.7, shadowOpacity: 0.7,
shadowColor: tokens.color.trueBlack, shadowColor: color.trueBlack,
}, },
shadow_lg: { shadow_lg: {
...atoms.shadow_lg, ...atoms.shadow_lg,
shadowOpacity: 0.7, shadowOpacity: 0.7,
shadowColor: tokens.color.trueBlack, shadowColor: color.trueBlack,
}, },
}, },
} }
export const dim: Theme = { const dim: Theme = {
...dark, ...dark,
name: 'dim' as ThemeName, name: 'dim',
palette: dimPalette, palette: dimPalette,
atoms: { atoms: {
...dark.atoms, ...dark.atoms,
@ -440,17 +552,27 @@ export const dim: Theme = {
shadow_sm: { shadow_sm: {
...atoms.shadow_sm, ...atoms.shadow_sm,
shadowOpacity: 0.7, shadowOpacity: 0.7,
shadowColor: `hsl(${BLUE_HUE}, 28%, 6%)`, shadowColor: `hsl(${hues.primary}, 28%, 6%)`,
}, },
shadow_md: { shadow_md: {
...atoms.shadow_md, ...atoms.shadow_md,
shadowOpacity: 0.7, shadowOpacity: 0.7,
shadowColor: `hsl(${BLUE_HUE}, 28%, 6%)`, shadowColor: `hsl(${hues.primary}, 28%, 6%)`,
}, },
shadow_lg: { shadow_lg: {
...atoms.shadow_lg, ...atoms.shadow_lg,
shadowOpacity: 0.7, shadowOpacity: 0.7,
shadowColor: `hsl(${BLUE_HUE}, 28%, 6%)`, shadowColor: `hsl(${hues.primary}, 28%, 6%)`,
}, },
}, },
} }
return {
lightPalette,
darkPalette,
dimPalette,
light,
dark,
dim,
}
}

View File

@ -1,77 +1,6 @@
import {
BLUE_HUE,
generateScale,
GREEN_HUE,
RED_HUE,
} from '#/alf/util/colorGeneration'
export const scale = generateScale(6, 100)
// dim shifted 6% lighter
export const dimScale = generateScale(12, 100)
export const color = { export const color = {
trueBlack: '#000000',
temp_purple: 'rgb(105 0 255)', temp_purple: 'rgb(105 0 255)',
temp_purple_dark: 'rgb(83 0 202)', temp_purple_dark: 'rgb(83 0 202)',
gray_0: `hsl(${BLUE_HUE}, 20%, ${scale[14]}%)`,
gray_25: `hsl(${BLUE_HUE}, 20%, ${scale[13]}%)`,
gray_50: `hsl(${BLUE_HUE}, 20%, ${scale[12]}%)`,
gray_100: `hsl(${BLUE_HUE}, 20%, ${scale[11]}%)`,
gray_200: `hsl(${BLUE_HUE}, 20%, ${scale[10]}%)`,
gray_300: `hsl(${BLUE_HUE}, 20%, ${scale[9]}%)`,
gray_400: `hsl(${BLUE_HUE}, 20%, ${scale[8]}%)`,
gray_500: `hsl(${BLUE_HUE}, 20%, ${scale[7]}%)`,
gray_600: `hsl(${BLUE_HUE}, 24%, ${scale[6]}%)`,
gray_700: `hsl(${BLUE_HUE}, 24%, ${scale[5]}%)`,
gray_800: `hsl(${BLUE_HUE}, 28%, ${scale[4]}%)`,
gray_900: `hsl(${BLUE_HUE}, 28%, ${scale[3]}%)`,
gray_950: `hsl(${BLUE_HUE}, 28%, ${scale[2]}%)`,
gray_975: `hsl(${BLUE_HUE}, 28%, ${scale[1]}%)`,
gray_1000: `hsl(${BLUE_HUE}, 28%, ${scale[0]}%)`,
blue_25: `hsl(${BLUE_HUE}, 99%, 97%)`,
blue_50: `hsl(${BLUE_HUE}, 99%, 95%)`,
blue_100: `hsl(${BLUE_HUE}, 99%, 90%)`,
blue_200: `hsl(${BLUE_HUE}, 99%, 80%)`,
blue_300: `hsl(${BLUE_HUE}, 99%, 70%)`,
blue_400: `hsl(${BLUE_HUE}, 99%, 60%)`,
blue_500: `hsl(${BLUE_HUE}, 99%, 53%)`,
blue_600: `hsl(${BLUE_HUE}, 99%, 42%)`,
blue_700: `hsl(${BLUE_HUE}, 99%, 34%)`,
blue_800: `hsl(${BLUE_HUE}, 99%, 26%)`,
blue_900: `hsl(${BLUE_HUE}, 99%, 18%)`,
blue_950: `hsl(${BLUE_HUE}, 99%, 10%)`,
blue_975: `hsl(${BLUE_HUE}, 99%, 7%)`,
green_25: `hsl(${GREEN_HUE}, 82%, 97%)`,
green_50: `hsl(${GREEN_HUE}, 82%, 95%)`,
green_100: `hsl(${GREEN_HUE}, 82%, 90%)`,
green_200: `hsl(${GREEN_HUE}, 82%, 80%)`,
green_300: `hsl(${GREEN_HUE}, 82%, 70%)`,
green_400: `hsl(${GREEN_HUE}, 82%, 60%)`,
green_500: `hsl(${GREEN_HUE}, 82%, 50%)`,
green_600: `hsl(${GREEN_HUE}, 82%, 42%)`,
green_700: `hsl(${GREEN_HUE}, 82%, 34%)`,
green_800: `hsl(${GREEN_HUE}, 82%, 26%)`,
green_900: `hsl(${GREEN_HUE}, 82%, 18%)`,
green_950: `hsl(${GREEN_HUE}, 82%, 10%)`,
green_975: `hsl(${GREEN_HUE}, 82%, 7%)`,
red_25: `hsl(${RED_HUE}, 91%, 97%)`,
red_50: `hsl(${RED_HUE}, 91%, 95%)`,
red_100: `hsl(${RED_HUE}, 91%, 90%)`,
red_200: `hsl(${RED_HUE}, 91%, 80%)`,
red_300: `hsl(${RED_HUE}, 91%, 70%)`,
red_400: `hsl(${RED_HUE}, 91%, 60%)`,
red_500: `hsl(${RED_HUE}, 91%, 50%)`,
red_600: `hsl(${RED_HUE}, 91%, 42%)`,
red_700: `hsl(${RED_HUE}, 91%, 34%)`,
red_800: `hsl(${RED_HUE}, 91%, 26%)`,
red_900: `hsl(${RED_HUE}, 91%, 18%)`,
red_950: `hsl(${RED_HUE}, 91%, 10%)`,
red_975: `hsl(${RED_HUE}, 91%, 7%)`,
} as const } as const
export const space = { export const space = {
@ -178,10 +107,3 @@ export const gradients = {
hover_value: '#755B62', hover_value: '#755B62',
}, },
} as const } as const
export type Color = keyof typeof color
export type Space = keyof typeof space
export type FontSize = keyof typeof fontSize
export type LineHeight = keyof typeof lineHeight
export type BorderRadius = keyof typeof borderRadius
export type FontWeight = keyof typeof fontWeight

View File

@ -1,21 +1,4 @@
import {StyleProp, ViewStyle, TextStyle} from 'react-native' import {StyleProp, TextStyle, ViewStyle} from 'react-native'
type LiteralToCommon<T extends PropertyKey> = T extends number
? number
: T extends string
? string
: T extends symbol
? symbol
: never
/**
* @see https://stackoverflow.com/questions/68249999/use-as-const-in-typescript-without-adding-readonly-modifiers
*/
export type Mutable<T> = {
-readonly [K in keyof T]: T[K] extends PropertyKey
? LiteralToCommon<T[K]>
: Mutable<T[K]>
}
export type TextStyleProp = { export type TextStyleProp = {
style?: StyleProp<TextStyle> style?: StyleProp<TextStyle>
@ -24,3 +7,156 @@ export type TextStyleProp = {
export type ViewStyleProp = { export type ViewStyleProp = {
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
} }
export type ThemeName = 'light' | 'dim' | 'dark'
export type Palette = {
white: string
black: string
contrast_25: string
contrast_50: string
contrast_100: string
contrast_200: string
contrast_300: string
contrast_400: string
contrast_500: string
contrast_600: string
contrast_700: string
contrast_800: string
contrast_900: string
contrast_950: string
contrast_975: string
primary_25: string
primary_50: string
primary_100: string
primary_200: string
primary_300: string
primary_400: string
primary_500: string
primary_600: string
primary_700: string
primary_800: string
primary_900: string
primary_950: string
primary_975: string
positive_25: string
positive_50: string
positive_100: string
positive_200: string
positive_300: string
positive_400: string
positive_500: string
positive_600: string
positive_700: string
positive_800: string
positive_900: string
positive_950: string
positive_975: string
negative_25: string
negative_50: string
negative_100: string
negative_200: string
negative_300: string
negative_400: string
negative_500: string
negative_600: string
negative_700: string
negative_800: string
negative_900: string
negative_950: string
negative_975: string
}
export type ThemedAtoms = {
text: {
color: string
}
text_contrast_low: {
color: string
}
text_contrast_medium: {
color: string
}
text_contrast_high: {
color: string
}
text_inverted: {
color: string
}
bg: {
backgroundColor: string
}
bg_contrast_25: {
backgroundColor: string
}
bg_contrast_50: {
backgroundColor: string
}
bg_contrast_100: {
backgroundColor: string
}
bg_contrast_200: {
backgroundColor: string
}
bg_contrast_300: {
backgroundColor: string
}
bg_contrast_400: {
backgroundColor: string
}
bg_contrast_500: {
backgroundColor: string
}
bg_contrast_600: {
backgroundColor: string
}
bg_contrast_700: {
backgroundColor: string
}
bg_contrast_800: {
backgroundColor: string
}
bg_contrast_900: {
backgroundColor: string
}
bg_contrast_950: {
backgroundColor: string
}
bg_contrast_975: {
backgroundColor: string
}
border_contrast_low: {
borderColor: string
}
border_contrast_medium: {
borderColor: string
}
border_contrast_high: {
borderColor: string
}
shadow_sm: {
shadowRadius: number
shadowOpacity: number
elevation: number
shadowColor: string
}
shadow_md: {
shadowRadius: number
shadowOpacity: number
elevation: number
shadowColor: string
}
shadow_lg: {
shadowRadius: number
shadowOpacity: number
elevation: number
shadowColor: string
}
}
export type Theme = {
name: ThemeName
palette: Palette
atoms: ThemedAtoms
}

View File

@ -15,3 +15,7 @@ export function generateScale(start: number, end: number) {
return start + range * stop return start + range * stop
}) })
} }
export const defaultScale = generateScale(6, 100)
// dim shifted 6% lighter
export const dimScale = generateScale(12, 100)

View File

@ -1,4 +1,4 @@
import {ThemeName} from '#/alf/themes' import {ThemeName} from '#/alf/types'
export function select<T>(name: ThemeName, options: Record<ThemeName, T>) { export function select<T>(name: ThemeName, options: Record<ThemeName, T>) {
switch (name) { switch (name) {

View File

@ -4,7 +4,8 @@ import * as SystemUI from 'expo-system-ui'
import {isWeb} from 'platform/detection' import {isWeb} from 'platform/detection'
import {useThemePrefs} from 'state/shell' import {useThemePrefs} from 'state/shell'
import {dark, dim, light, ThemeName} from '#/alf/themes' import {dark, dim, light} from '#/alf/themes'
import {ThemeName} from '#/alf/types'
export function useColorModeTheme(): ThemeName { export function useColorModeTheme(): ThemeName {
const theme = useThemeName() const theme = useThemeName()

View File

@ -13,7 +13,7 @@ import {
} from 'react-native' } from 'react-native'
import {LinearGradient} from 'expo-linear-gradient' import {LinearGradient} from 'expo-linear-gradient'
import {android, atoms as a, flatten, tokens, useTheme} from '#/alf' import {android, atoms as a, flatten, select, tokens, useTheme} from '#/alf'
import {Props as SVGIconProps} from '#/components/icons/common' import {Props as SVGIconProps} from '#/components/icons/common'
import {normalizeTextStyles} from '#/components/Typography' import {normalizeTextStyles} from '#/components/Typography'
@ -152,7 +152,6 @@ export const Button = React.forwardRef<View, ButtonProps>(
const {baseStyles, hoverStyles} = React.useMemo(() => { const {baseStyles, hoverStyles} = React.useMemo(() => {
const baseStyles: ViewStyle[] = [] const baseStyles: ViewStyle[] = []
const hoverStyles: ViewStyle[] = [] const hoverStyles: ViewStyle[] = []
const light = t.name === 'light'
if (color === 'primary') { if (color === 'primary') {
if (variant === 'solid') { if (variant === 'solid') {
@ -165,7 +164,11 @@ export const Button = React.forwardRef<View, ButtonProps>(
}) })
} else { } else {
baseStyles.push({ baseStyles.push({
backgroundColor: t.palette.primary_700, backgroundColor: select(t.name, {
light: t.palette.primary_700,
dim: t.palette.primary_300,
dark: t.palette.primary_300,
}),
}) })
} }
} else if (variant === 'outline') { } else if (variant === 'outline') {
@ -178,24 +181,18 @@ export const Button = React.forwardRef<View, ButtonProps>(
borderColor: t.palette.primary_500, borderColor: t.palette.primary_500,
}) })
hoverStyles.push(a.border, { hoverStyles.push(a.border, {
backgroundColor: light backgroundColor: t.palette.primary_50,
? t.palette.primary_50
: t.palette.primary_950,
}) })
} else { } else {
baseStyles.push(a.border, { baseStyles.push(a.border, {
borderColor: light borderColor: t.palette.primary_200,
? t.palette.primary_200
: t.palette.primary_900,
}) })
} }
} else if (variant === 'ghost') { } else if (variant === 'ghost') {
if (!disabled) { if (!disabled) {
baseStyles.push(t.atoms.bg) baseStyles.push(t.atoms.bg)
hoverStyles.push({ hoverStyles.push({
backgroundColor: light backgroundColor: t.palette.primary_100,
? t.palette.primary_100
: t.palette.primary_900,
}) })
} }
} }
@ -203,14 +200,26 @@ export const Button = React.forwardRef<View, ButtonProps>(
if (variant === 'solid') { if (variant === 'solid') {
if (!disabled) { if (!disabled) {
baseStyles.push({ baseStyles.push({
backgroundColor: t.palette.contrast_25, backgroundColor: select(t.name, {
light: t.palette.contrast_25,
dim: t.palette.contrast_100,
dark: t.palette.contrast_100,
}),
}) })
hoverStyles.push({ hoverStyles.push({
backgroundColor: t.palette.contrast_50, backgroundColor: select(t.name, {
light: t.palette.contrast_50,
dim: t.palette.contrast_200,
dark: t.palette.contrast_200,
}),
}) })
} else { } else {
baseStyles.push({ baseStyles.push({
backgroundColor: t.palette.contrast_100, backgroundColor: select(t.name, {
light: t.palette.contrast_100,
dim: t.palette.contrast_25,
dark: t.palette.contrast_25,
}),
}) })
} }
} else if (variant === 'outline') { } else if (variant === 'outline') {
@ -247,7 +256,7 @@ export const Button = React.forwardRef<View, ButtonProps>(
}) })
} else { } else {
baseStyles.push({ baseStyles.push({
backgroundColor: t.palette.contrast_700, backgroundColor: t.palette.contrast_600,
}) })
} }
} else if (variant === 'outline') { } else if (variant === 'outline') {
@ -284,7 +293,11 @@ export const Button = React.forwardRef<View, ButtonProps>(
}) })
} else { } else {
baseStyles.push({ baseStyles.push({
backgroundColor: t.palette.negative_700, backgroundColor: select(t.name, {
light: t.palette.negative_700,
dim: t.palette.negative_300,
dark: t.palette.negative_300,
}),
}) })
} }
} else if (variant === 'outline') { } else if (variant === 'outline') {
@ -297,24 +310,18 @@ export const Button = React.forwardRef<View, ButtonProps>(
borderColor: t.palette.negative_500, borderColor: t.palette.negative_500,
}) })
hoverStyles.push(a.border, { hoverStyles.push(a.border, {
backgroundColor: light backgroundColor: t.palette.negative_50,
? t.palette.negative_50
: t.palette.negative_975,
}) })
} else { } else {
baseStyles.push(a.border, { baseStyles.push(a.border, {
borderColor: light borderColor: t.palette.negative_200,
? t.palette.negative_200
: t.palette.negative_900,
}) })
} }
} else if (variant === 'ghost') { } else if (variant === 'ghost') {
if (!disabled) { if (!disabled) {
baseStyles.push(t.atoms.bg) baseStyles.push(t.atoms.bg)
hoverStyles.push({ hoverStyles.push({
backgroundColor: light backgroundColor: t.palette.negative_100,
? t.palette.negative_100
: t.palette.negative_975,
}) })
} }
} }
@ -482,7 +489,6 @@ export function useSharedButtonTextStyles() {
const {color, variant, disabled, size} = useButtonContext() const {color, variant, disabled, size} = useButtonContext()
return React.useMemo(() => { return React.useMemo(() => {
const baseStyles: TextStyle[] = [] const baseStyles: TextStyle[] = []
const light = t.name === 'light'
if (color === 'primary') { if (color === 'primary') {
if (variant === 'solid') { if (variant === 'solid') {
@ -494,7 +500,7 @@ export function useSharedButtonTextStyles() {
} else if (variant === 'outline') { } else if (variant === 'outline') {
if (!disabled) { if (!disabled) {
baseStyles.push({ baseStyles.push({
color: light ? t.palette.primary_600 : t.palette.primary_500, color: t.palette.primary_600,
}) })
} else { } else {
baseStyles.push({color: t.palette.primary_600, opacity: 0.5}) baseStyles.push({color: t.palette.primary_600, opacity: 0.5})

View File

@ -2,14 +2,14 @@ import React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import { import {
useTheme,
atoms as a, atoms as a,
ViewStyleProp,
TextStyleProp,
flatten, flatten,
TextStyleProp,
useTheme,
ViewStyleProp,
} from '#/alf' } from '#/alf'
import {Growth_Stroke2_Corner0_Rounded as Growth} from '#/components/icons/Growth'
import {Props} from '#/components/icons/common' import {Props} from '#/components/icons/common'
import {Growth_Stroke2_Corner0_Rounded as Growth} from '#/components/icons/Growth'
export function IconCircle({ export function IconCircle({
icon: Icon, icon: Icon,
@ -32,8 +32,7 @@ export function IconCircle({
{ {
width: size === 'lg' ? 52 : 64, width: size === 'lg' ? 52 : 64,
height: size === 'lg' ? 52 : 64, height: size === 'lg' ? 52 : 64,
backgroundColor: backgroundColor: t.palette.primary_50,
t.name === 'light' ? t.palette.primary_50 : t.palette.primary_950,
}, },
flatten(style), flatten(style),
]}> ]}>

View File

@ -357,12 +357,11 @@ function TargetToggle({children}: React.PropsWithChildren<{}>) {
a.px_sm, a.px_sm,
gtMobile && a.px_md, gtMobile && a.px_md,
a.rounded_sm, a.rounded_sm,
t.atoms.bg_contrast_50, t.atoms.bg_contrast_25,
(ctx.hovered || ctx.focused) && t.atoms.bg_contrast_100, (ctx.hovered || ctx.focused) && t.atoms.bg_contrast_50,
ctx.selected && [ ctx.selected && [
{ {
backgroundColor: backgroundColor: t.palette.primary_50,
t.name === 'light' ? t.palette.primary_50 : t.palette.primary_975,
}, },
], ],
ctx.disabled && { ctx.disabled && {

View File

@ -196,10 +196,7 @@ function Selectable({
t.atoms.bg_contrast_50, t.atoms.bg_contrast_50,
(hovered || focused) && t.atoms.bg_contrast_100, (hovered || focused) && t.atoms.bg_contrast_100,
isSelected && { isSelected && {
backgroundColor: backgroundColor: t.palette.primary_100,
t.name === 'light'
? t.palette.primary_50
: t.palette.primary_975,
}, },
style, style,
]}> ]}>

View File

@ -72,8 +72,7 @@ let MessageItem = ({
lastInGroupRef.current = isLastInGroup lastInGroupRef.current = isLastInGroup
} }
const pendingColor = const pendingColor = t.palette.primary_200
t.name === 'light' ? t.palette.primary_200 : t.palette.primary_800
const rt = useMemo(() => { const rt = useMemo(() => {
return new RichTextAPI({text: message.text, facets: message.facets}) return new RichTextAPI({text: message.text, facets: message.facets})
@ -110,12 +109,7 @@ let MessageItem = ({
}> }>
<RichText <RichText
value={rt} value={rt}
style={[ style={[a.text_md, isFromSelf && {color: t.palette.white}]}
a.text_md,
isFromSelf && {color: t.palette.white},
isPending &&
t.name !== 'light' && {color: t.palette.primary_300},
]}
interactiveStyle={a.underline} interactiveStyle={a.underline}
enableTags enableTags
emojiMultiplier={3} emojiMultiplier={3}

View File

@ -101,16 +101,13 @@ export function useSharedInputStyles() {
] ]
const error: ViewStyle[] = [ const error: ViewStyle[] = [
{ {
backgroundColor: backgroundColor: t.palette.negative_25,
t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900, borderColor: t.palette.negative_300,
borderColor:
t.name === 'light' ? t.palette.negative_300 : t.palette.negative_800,
}, },
] ]
const errorHover: ViewStyle[] = [ const errorHover: ViewStyle[] = [
{ {
backgroundColor: backgroundColor: t.palette.negative_25,
t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900,
borderColor: t.palette.negative_500, borderColor: t.palette.negative_500,
}, },
] ]

View File

@ -281,24 +281,20 @@ export function createSharedToggleStyles({
if (selected) { if (selected) {
base.push({ base.push({
backgroundColor: backgroundColor: t.palette.primary_25,
t.name === 'light' ? t.palette.primary_25 : t.palette.primary_900,
borderColor: t.palette.primary_500, borderColor: t.palette.primary_500,
}) })
if (hovered) { if (hovered) {
baseHover.push({ baseHover.push({
backgroundColor: backgroundColor: t.palette.primary_100,
t.name === 'light' ? t.palette.primary_100 : t.palette.primary_800, borderColor: t.palette.primary_600,
borderColor:
t.name === 'light' ? t.palette.primary_600 : t.palette.primary_400,
}) })
} }
} else { } else {
if (hovered) { if (hovered) {
baseHover.push({ baseHover.push({
backgroundColor: backgroundColor: t.palette.contrast_50,
t.name === 'light' ? t.palette.contrast_50 : t.palette.contrast_100,
borderColor: t.palette.contrast_500, borderColor: t.palette.contrast_500,
}) })
} }
@ -306,16 +302,13 @@ export function createSharedToggleStyles({
if (isInvalid) { if (isInvalid) {
base.push({ base.push({
backgroundColor: backgroundColor: t.palette.negative_25,
t.name === 'light' ? t.palette.negative_25 : t.palette.negative_975, borderColor: t.palette.negative_300,
borderColor:
t.name === 'light' ? t.palette.negative_300 : t.palette.negative_800,
}) })
if (hovered) { if (hovered) {
baseHover.push({ baseHover.push({
backgroundColor: backgroundColor: t.palette.negative_25,
t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900,
borderColor: t.palette.negative_600, borderColor: t.palette.negative_600,
}) })
} }

View File

@ -4,7 +4,7 @@ import type {PathProps, SvgProps} from 'react-native-svg'
import {Defs, LinearGradient, Stop} from 'react-native-svg' import {Defs, LinearGradient, Stop} from 'react-native-svg'
import {nanoid} from 'nanoid/non-secure' import {nanoid} from 'nanoid/non-secure'
import {tokens} from '#/alf' import {tokens, useTheme} from '#/alf'
export type Props = { export type Props = {
fill?: PathProps['fill'] fill?: PathProps['fill']
@ -22,10 +22,11 @@ export const sizes = {
} }
export function useCommonSVGProps(props: Props) { export function useCommonSVGProps(props: Props) {
const t = useTheme()
const {fill, size, gradient, ...rest} = props const {fill, size, gradient, ...rest} = props
const style = StyleSheet.flatten(rest.style) const style = StyleSheet.flatten(rest.style)
const _size = Number(size ? sizes[size] : rest.width || sizes.md) const _size = Number(size ? sizes[size] : rest.width || sizes.md)
let _fill = fill || style?.color || tokens.color.blue_500 let _fill = fill || style?.color || t.palette.primary_500
let gradientDef = null let gradientDef = null
if (gradient && tokens.gradients[gradient]) { if (gradient && tokens.gradients[gradient]) {

View File

@ -1,7 +1,8 @@
import React, {ReactNode, createContext, useContext} from 'react' import React, {createContext, ReactNode, useContext} from 'react'
import {TextStyle, ViewStyle} from 'react-native' import {TextStyle, ViewStyle} from 'react-native'
import {ThemeName} from '#/alf/types'
import {darkTheme, defaultTheme, dimTheme} from './themes' import {darkTheme, defaultTheme, dimTheme} from './themes'
import {ThemeName} from '#/alf/themes'
export type ColorScheme = 'light' | 'dark' export type ColorScheme = 'light' | 'dark'

View File

@ -1,8 +1,8 @@
import {Platform} from 'react-native' import {Platform} from 'react-native'
import type {Theme} from './ThemeContext'
import {colors} from './styles'
import {darkPalette, lightPalette, dimPalette} from '#/alf/themes' import {darkPalette, dimPalette, lightPalette} from '#/alf/themes'
import {colors} from './styles'
import type {Theme} from './ThemeContext'
export const defaultTheme: Theme = { export const defaultTheme: Theme = {
colorScheme: 'light', colorScheme: 'light',
@ -308,8 +308,8 @@ export const darkTheme: Theme = {
textVeryLight: darkPalette.contrast_400, textVeryLight: darkPalette.contrast_400,
replyLine: darkPalette.contrast_200, replyLine: darkPalette.contrast_200,
replyLineDot: darkPalette.contrast_200, replyLineDot: darkPalette.contrast_200,
unreadNotifBg: darkPalette.primary_975, unreadNotifBg: darkPalette.primary_25,
unreadNotifBorder: darkPalette.primary_900, unreadNotifBorder: darkPalette.primary_100,
postCtrl: darkPalette.contrast_500, postCtrl: darkPalette.contrast_500,
brandText: darkPalette.primary_500, brandText: darkPalette.primary_500,
emptyStateIcon: darkPalette.contrast_300, emptyStateIcon: darkPalette.contrast_300,
@ -357,8 +357,8 @@ export const dimTheme: Theme = {
textVeryLight: dimPalette.contrast_400, textVeryLight: dimPalette.contrast_400,
replyLine: dimPalette.contrast_200, replyLine: dimPalette.contrast_200,
replyLineDot: dimPalette.contrast_200, replyLineDot: dimPalette.contrast_200,
unreadNotifBg: dimPalette.primary_975, unreadNotifBg: dimPalette.primary_25,
unreadNotifBorder: dimPalette.primary_900, unreadNotifBorder: dimPalette.primary_100,
postCtrl: dimPalette.contrast_500, postCtrl: dimPalette.contrast_500,
brandText: dimPalette.primary_500, brandText: dimPalette.primary_500,
emptyStateIcon: dimPalette.contrast_300, emptyStateIcon: dimPalette.contrast_300,

View File

@ -20,7 +20,8 @@ export function Buttons() {
<H1>Buttons</H1> <H1>Buttons</H1>
<View style={[a.flex_row, a.flex_wrap, a.gap_md, a.align_start]}> <View style={[a.flex_row, a.flex_wrap, a.gap_md, a.align_start]}>
{['primary', 'secondary', 'secondary_inverted'].map(color => ( {['primary', 'secondary', 'secondary_inverted', 'negative'].map(
color => (
<View key={color} style={[a.gap_md, a.align_start]}> <View key={color} style={[a.gap_md, a.align_start]}>
{['solid', 'outline', 'ghost'].map(variant => ( {['solid', 'outline', 'ghost'].map(variant => (
<React.Fragment key={variant}> <React.Fragment key={variant}>
@ -42,7 +43,8 @@ export function Buttons() {
</React.Fragment> </React.Fragment>
))} ))}
</View> </View>
))} ),
)}
<View style={[a.flex_row, a.gap_md, a.align_start]}> <View style={[a.flex_row, a.gap_md, a.align_start]}>
<View style={[a.gap_md, a.align_start]}> <View style={[a.gap_md, a.align_start]}>
@ -68,6 +70,7 @@ export function Buttons() {
), ),
)} )}
</View> </View>
{/*
<View style={[a.gap_md, a.align_start]}> <View style={[a.gap_md, a.align_start]}>
{['gradient_sunset', 'gradient_nordic', 'gradient_bonfire'].map( {['gradient_sunset', 'gradient_nordic', 'gradient_bonfire'].map(
name => ( name => (
@ -91,6 +94,7 @@ export function Buttons() {
), ),
)} )}
</View> </View>
*/}
</View> </View>
</View> </View>

View File

@ -41,6 +41,16 @@ export function Forms() {
/> />
</TextField.Root> </TextField.Root>
<TextField.Root>
<TextField.Icon icon={Globe} />
<TextField.Input
value={value}
onChangeText={setValue}
label="Text field"
isInvalid
/>
</TextField.Root>
<View style={[a.w_full]}> <View style={[a.w_full]}>
<TextField.LabelText>Text field</TextField.LabelText> <TextField.LabelText>Text field</TextField.LabelText>
<TextField.Root> <TextField.Root>