Text Components
Text Components would be best if the text itself used clamp values and calc values proportional to the styles for the headerTxt.
json
contextSetterTxt: "String value"
headerTxt: "String value"
subHeaderTxt: "String value"
copyTxt: "String value"
excerptTxt: "String value"
fullContent: {
fullMarkdownTxt: "String value",
fullHtmlTxt: "String value",
fullPlainText: "String value",
fullRichText: "String value",
pathToFullContent: "String value",
urlToRemoteFullContent: "String value"
} || "String value" || null || undefined || typescript
type FullContent = Partial<{
fullMarkdownTxt: string;
fullHtmlTxt: string;
fullPlainText: string;
fullRichText: string;
pathToFullContent: string;
urlToRemoteFullContent: string;
}> | string | null | undefined; subHeaderTxt: "String value" || null || undefined ||
copyTxt: "String value" || null || undefined ||
excerptTxt: "String value" || null || undefined ||
fullContent: {
fullMarkdownTxt: "String value",
fullHtmlTxt: "String value",
fullPlainText: "String value",
fullRichText: "String value",
pathToFullContent: "String value",
urlToRemoteFullContent: "String value"
} || "String value" || null || undefined ||
pairedImageUrl: "String value" || null || undefined ||
captionTxt: "String value" || null || undefined ||
imgAltTxt: "String value" || null || undefined ||
imgAltTxt
style properties:
align
imageOn (left, center, right, top, middle, bottom. )
typescript
interface TextComponentProps {
// Content
content?: string | ReactNode;
// Text role (determines size/weight relative to header)
role?: 'context' | 'header' | 'subheader' | 'body' | 'caption' | 'prose' | 'zinger';
// Size scale (maps to your 7-size system)
size?: 'xxs' | 'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl';
// Color role (maps to your theme)
color?: keyof ThemeColors;
// Layout
align?: 'left' | 'center' | 'right' | 'justify';
weight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold';
lineHeight?: 'none' | 'snuggiest' | 'snuggier' | 'snug' | 'normal' | 'relaxed' | 'loose' | 'looser' | 'loosest';
kerning?: 'none' | 'tightest' | 'tighter' | 'tight' | 'normal' | 'loose' | 'wider' | 'widest';
// Spacing
margin?: string;
padding?: string;
// Other
className?: string;
style?: CSSProperties;
children?: ReactNode;
} css
:root {
/* Base size that everything scales from */
--text-base-size: 1rem; /* 16px */
/* Type scale ratios */
--type-scale-ratio: 1.2;
--golden-ratio: 1.618;
/* Size calculations */
--text-xxs: calc(var(--text-base-size) / (var(--type-scale-ratio) * 1.5));
--text-xs: calc(var(--text-base-size) / var(--type-scale-ratio));
--text-sm: calc(var(--text-base-size));
--text-base: calc(var(--text-base-size) * var(--type-scale-ratio));
--text-lg: calc(var(--text-base-size) * var(--type-scale-ratio) * 1.5);
--text-xl: calc(var(--text-base-size) * var(--type-scale-ratio) * 2);
--text-2xl: calc(var(--text-base-size) * var(--type-scale-ratio) * 2.5);
/* Role-based sizes (relative to header) */
--text-header: var(--text-xl);
--text-context: calc(var(--text-header) * 0.75); /* 75% of header */
--text-subheader: calc(var(--text-header) * 0.85); /* 85% of header */
--text-body: calc(var(--text-header) * 0.5); /* 50% of header */
--text-caption: calc(var(--text-header) * 0.4); /* 40% of header */
}
/* Alignment classes */
.text-left { text-align: left; }
.text-center { text-align: center; }
.text-right { text-align: right; }
.text-justify { text-align: justify; }
/* Font weights */
.text-light { font-weight: 300; }
.text-normal { font-weight: 400; }
.text-medium { font-weight: 500; }
.text-semibold { font-weight: 600; }
.text-bold { font-weight: 700; }
/* Line heights - Extended scale */
.leading-none { line-height: 1; }
.leading-snuggiest { line-height: 1.1; }
.leading-snuggier { line-height: 1.2; }
.leading-snug { line-height: 1.375; }
.leading-normal { line-height: 1.5; }
.leading-relaxed { line-height: 1.625; }
.leading-loose { line-height: 1.75; }
.leading-looser { line-height: 1.875; }
.leading-loosest { line-height: 2; } typescript
const Text: React.FC<TextComponentProps> = ({
role = 'body',
size,
color = 'text.primary',
align = 'left',
weight = 'normal',
lineHeight = 'normal',
className = '',
style = {},
children,
...props
}) => {
// Determine size class based on role if size not explicitly set
const sizeClass = size || {
context: 'text-context',
header: 'text-header',
subheader: 'text-subheader',
body: 'text-body',
caption: 'text-caption',
}[role];
const classes = `
${sizeClass}
text-${align}
font-${weight}
leading-${lineHeight}
text-${color}
${className}
`;
return (
<span className={classes} style={style} {...props}>
{children}
</span>
);
}; Example Usage
import Text from '../components/Text.astro';
text