mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-03 06:53:24 +00:00
99 lines
2.6 KiB
TypeScript
99 lines
2.6 KiB
TypeScript
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<MuiTypographyProps, "children" | "color" | "variant"> & {
|
|
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<TextTone, MuiTypographyProps["color"]> = {
|
|
default: "text.primary",
|
|
muted: "text.secondary",
|
|
error: "error",
|
|
success: "success.main",
|
|
warning: "warning.main",
|
|
};
|
|
|
|
const familyValue: Record<TextFamily, string> = {
|
|
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 (
|
|
<MuiTypography
|
|
component={as ?? config.element}
|
|
variant={config.muiVariant}
|
|
color={toneColor[resolvedTone]}
|
|
sx={[
|
|
{ fontFamily: familyValue[family ?? config.family] },
|
|
...(Array.isArray(sx) ? sx : [sx]),
|
|
]}
|
|
{...liveProps}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</MuiTypography>
|
|
);
|
|
}
|