You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
3.0 KiB
127 lines
3.0 KiB
/** |
|
* 主题化组件 |
|
* |
|
* 提供自动适配主题的 Text 和 View 组件 |
|
* 支持从 settingsStore 读取主题设置 |
|
*/ |
|
|
|
import { Text as DefaultText, View as DefaultView, TextStyle } from 'react-native'; |
|
|
|
import Colors from '@/constants/Colors'; |
|
import { useColorScheme } from '@/hooks/useTheme'; |
|
|
|
type ThemeProps = { |
|
lightColor?: string; |
|
darkColor?: string; |
|
}; |
|
|
|
export type TextProps = ThemeProps & DefaultText['props']; |
|
export type ViewProps = ThemeProps & DefaultView['props']; |
|
|
|
/** |
|
* 获取主题颜色 |
|
* |
|
* @param props - 包含 light 和 dark 颜色的对象 |
|
* @param colorName - Colors 中定义的颜色名称 |
|
* @returns 当前主题对应的颜色值 |
|
*/ |
|
export function useThemeColor( |
|
props: { light?: string; dark?: string }, |
|
colorName: keyof typeof Colors.light & keyof typeof Colors.dark |
|
) { |
|
const theme = useColorScheme() ?? 'light'; |
|
const colorFromProps = props[theme]; |
|
|
|
if (colorFromProps) { |
|
return colorFromProps; |
|
} else { |
|
return Colors[theme][colorName]; |
|
} |
|
} |
|
|
|
/** |
|
* 主题化 Text 组件 |
|
* |
|
* 自动应用当前主题的文本颜色 |
|
*/ |
|
export function Text(props: TextProps) { |
|
const { style, lightColor, darkColor, ...otherProps } = props; |
|
const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text'); |
|
|
|
return <DefaultText style={[{ color }, style]} {...otherProps} />; |
|
} |
|
|
|
/** |
|
* 主题化 View 组件 |
|
* |
|
* 自动应用当前主题的背景颜色 |
|
*/ |
|
export function View(props: ViewProps) { |
|
const { style, lightColor, darkColor, ...otherProps } = props; |
|
const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background'); |
|
|
|
return <DefaultView style={[{ backgroundColor }, style]} {...otherProps} />; |
|
} |
|
|
|
/** |
|
* 主题化 Text 组件(带类型) |
|
* |
|
* 支持不同的文本类型:title, subtitle, defaultSemiBold, link |
|
*/ |
|
export type ThemedTextProps = TextProps & { |
|
type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link'; |
|
}; |
|
|
|
export function ThemedText({ style, type = 'default', ...rest }: ThemedTextProps) { |
|
const color = useThemeColor({}, 'text'); |
|
const linkColor = useThemeColor({}, 'tint'); |
|
|
|
const typeStyles: Record<string, TextStyle> = { |
|
default: { |
|
fontSize: 16, |
|
lineHeight: 24, |
|
}, |
|
defaultSemiBold: { |
|
fontSize: 16, |
|
lineHeight: 24, |
|
fontWeight: '600', |
|
}, |
|
title: { |
|
fontSize: 32, |
|
fontWeight: 'bold', |
|
lineHeight: 40, |
|
}, |
|
subtitle: { |
|
fontSize: 20, |
|
fontWeight: '600', |
|
lineHeight: 28, |
|
}, |
|
link: { |
|
fontSize: 16, |
|
lineHeight: 24, |
|
color: linkColor, |
|
}, |
|
}; |
|
|
|
return ( |
|
<Text |
|
style={[ |
|
{ color }, |
|
typeStyles[type], |
|
style, |
|
]} |
|
{...rest} |
|
/> |
|
); |
|
} |
|
|
|
/** |
|
* 主题化 View 组件 |
|
*/ |
|
export type ThemedViewProps = ViewProps; |
|
|
|
export function ThemedView({ style, ...otherProps }: ThemedViewProps) { |
|
const backgroundColor = useThemeColor({}, 'background'); |
|
|
|
return <DefaultView style={[{ backgroundColor }, style]} {...otherProps} />; |
|
}
|
|
|