import type { ElementType, ReactNode } from "react"; import { Typography as MuiTypography, type TypographyProps as MuiTypographyProps, } from "@mui/material"; type TextVariant = | "display" | "title" | "heading" | "body" | "description" | "label" | "feedback" | "error" | "caption" | "code"; type TextTone = "default" | "muted" | "error" | "success" | "warning"; type TextFamily = "display" | "body" | "mono"; export type TextProps = Omit & { children: ReactNode; as?: ElementType; family?: TextFamily; tone?: TextTone; variant?: TextVariant; when?: boolean; }; const variantConfig: Record< TextVariant, { element: ElementType; muiVariant: MuiTypographyProps["variant"]; family: TextFamily } > = { display: { element: "h1", muiVariant: "h3", family: "display" }, title: { element: "h2", muiVariant: "h5", family: "display" }, heading: { element: "h3", muiVariant: "h6", family: "display" }, body: { element: "p", muiVariant: "body1", family: "body" }, description: { element: "p", muiVariant: "body2", family: "body" }, label: { element: "span", muiVariant: "subtitle2", family: "body" }, feedback: { element: "p", muiVariant: "body2", family: "body" }, error: { element: "p", muiVariant: "body2", family: "body" }, caption: { element: "span", muiVariant: "caption", family: "body" }, code: { element: "code", muiVariant: "body2", family: "mono" }, }; const toneColor: Record = { default: "text.primary", muted: "text.secondary", error: "error", success: "success.main", warning: "warning.main", }; const familyValue: Record = { display: "var(--font-display)", body: "var(--font-sans)", mono: "var(--font-mono)", }; export function Text({ as, children, family, tone, variant = "body", when = true, sx, ...props }: TextProps) { if (!when) { return null; } const config = variantConfig[variant]; const resolvedTone = tone ?? (variant === "error" ? "error" : "default"); let liveProps = {}; if (variant === "error") { liveProps = { role: "alert", "aria-live": "assertive" as const }; } else if (variant === "feedback") { liveProps = { role: "status", "aria-live": "polite" as const }; } return ( {children} ); }