managarten/apps/picture/apps/mobile/components/Text.tsx
Wuesteon d36b321d9d style: auto-format codebase with Prettier
Applied formatting to 1487+ files using pnpm format:write
  - TypeScript/JavaScript files
  - Svelte components
  - Astro pages
  - JSON configs
  - Markdown docs

  13 files still need manual review (Astro JSX comments)
2025-11-27 18:33:16 +01:00

163 lines
3.2 KiB
TypeScript

import { forwardRef } from 'react';
import { Text as RNText, TextProps as RNTextProps, TextStyle } from 'react-native';
import { useTheme } from '~/contexts/ThemeContext';
type TextVariant =
| 'h1'
| 'h2'
| 'h3'
| 'h4'
| 'title'
| 'body'
| 'bodyLarge'
| 'bodySmall'
| 'caption'
| 'label'
| 'button';
type TextColor = 'primary' | 'secondary' | 'tertiary' | 'inverse' | 'error' | 'success' | 'warning';
type TextWeight = 'regular' | 'medium' | 'semibold' | 'bold';
type TextProps = {
variant?: TextVariant;
color?: TextColor;
weight?: TextWeight;
align?: 'left' | 'center' | 'right';
children?: React.ReactNode;
} & RNTextProps;
export const Text = forwardRef<RNText, TextProps>(
(
{ variant = 'body', color = 'primary', weight, align = 'left', style, children, ...props },
ref
) => {
const { theme } = useTheme();
// Variant styles
const getVariantStyle = (): TextStyle => {
switch (variant) {
case 'h1':
return {
fontSize: 32,
fontWeight: '700',
lineHeight: 40,
};
case 'h2':
return {
fontSize: 28,
fontWeight: '700',
lineHeight: 36,
};
case 'h3':
return {
fontSize: 24,
fontWeight: '600',
lineHeight: 32,
};
case 'h4':
return {
fontSize: 20,
fontWeight: '600',
lineHeight: 28,
};
case 'title':
return {
fontSize: 44,
fontWeight: '800',
lineHeight: 52,
};
case 'bodyLarge':
return {
fontSize: 18,
fontWeight: '400',
lineHeight: 28,
};
case 'body':
return {
fontSize: 16,
fontWeight: '400',
lineHeight: 24,
};
case 'bodySmall':
return {
fontSize: 14,
fontWeight: '400',
lineHeight: 20,
};
case 'caption':
return {
fontSize: 12,
fontWeight: '400',
lineHeight: 16,
};
case 'label':
return {
fontSize: 14,
fontWeight: '500',
lineHeight: 20,
};
case 'button':
return {
fontSize: 16,
fontWeight: '600',
lineHeight: 24,
};
default:
return {};
}
};
// Color mapping
const getTextColor = (): string => {
switch (color) {
case 'primary':
return theme.colors.text.primary;
case 'secondary':
return theme.colors.text.secondary;
case 'tertiary':
return theme.colors.text.tertiary;
case 'inverse':
return theme.colors.text.inverse;
case 'error':
return theme.colors.error;
case 'success':
return theme.colors.success;
case 'warning':
return theme.colors.warning;
default:
return theme.colors.text.primary;
}
};
// Weight mapping
const getFontWeight = (): TextStyle['fontWeight'] => {
if (weight) {
const weightMap: Record<TextWeight, TextStyle['fontWeight']> = {
regular: '400',
medium: '500',
semibold: '600',
bold: '700',
};
return weightMap[weight];
}
return undefined;
};
const textStyle: TextStyle = {
...getVariantStyle(),
color: getTextColor(),
textAlign: align,
...(weight && { fontWeight: getFontWeight() }),
...(style as TextStyle),
};
return (
<RNText ref={ref} style={textStyle} {...props}>
{children}
</RNText>
);
}
);
Text.displayName = 'Text';