import React, { ElementType, ReactNode, forwardRef, CSSProperties } from 'react'; import { ResponsiveValue } from './Box'; export type TextSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | 'base'; export interface TextProps { children: ReactNode; variant?: 'high' | 'med' | 'low' | 'primary' | 'success' | 'warning' | 'critical' | 'telemetry' | 'inherit'; size?: TextSize | { base: TextSize; sm?: TextSize; md?: TextSize; lg?: TextSize; xl?: TextSize }; weight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold'; as?: ElementType; align?: 'left' | 'center' | 'right'; mono?: boolean; font?: 'sans' | 'mono'; uppercase?: boolean; leading?: 'none' | 'tight' | 'snug' | 'normal' | 'relaxed' | 'loose'; block?: boolean; truncate?: boolean; maxWidth?: string | number; lineClamp?: number; letterSpacing?: 'tight' | 'normal' | 'wide' | 'widest' | string; id?: string; /** @deprecated Use semantic props (variant, intent) instead. */ color?: string; /** @deprecated Use semantic props instead. */ className?: string; /** @deprecated Use semantic props instead. */ style?: CSSProperties; /** @deprecated Use semantic props instead. */ marginBottom?: number | string | ResponsiveValue; /** @deprecated Use semantic props instead. */ marginTop?: number | string | ResponsiveValue; /** @deprecated Use semantic props instead. */ mb?: number | string | ResponsiveValue; /** @deprecated Use semantic props instead. */ mt?: number | string | ResponsiveValue; /** @deprecated Use semantic props instead. */ ml?: number | string; /** @deprecated Use semantic props instead. */ mr?: number | string; /** @deprecated Use semantic props instead. */ mx?: string | number; /** @deprecated Use semantic props instead. */ px?: number | string; /** @deprecated Use semantic props instead. */ py?: number | string; /** @deprecated Use semantic props instead. */ textAlign?: 'left' | 'center' | 'right'; /** @deprecated Use semantic props instead. */ flexGrow?: number; /** @deprecated Use semantic props instead. */ maxHeight?: string | number; /** @deprecated Use semantic props instead. */ overflow?: string; /** @deprecated Use semantic props instead. */ opacity?: number; /** @deprecated Use semantic props instead. */ groupHoverTextColor?: string; /** @deprecated Use semantic props instead. */ lineHeight?: string | number; /** @deprecated Use semantic props instead. */ transform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase' | string; /** @deprecated Use semantic props instead. */ animate?: string; /** @deprecated Use semantic props instead. */ transition?: boolean; /** @deprecated Use semantic props instead. */ display?: string | ResponsiveValue; /** @deprecated Use semantic props instead. */ alignItems?: string; /** @deprecated Use semantic props instead. */ gap?: number; /** @deprecated Use semantic props instead. */ italic?: boolean; /** @deprecated Use semantic props instead. */ fontSize?: string | any; /** @deprecated Use semantic props instead. */ borderLeft?: boolean; /** @deprecated Use semantic props instead. */ borderColor?: string; /** @deprecated Use semantic props instead. */ pl?: number; /** @deprecated Use semantic props instead. */ borderStyle?: string; /** @deprecated Use semantic props instead. */ paddingX?: number; /** @deprecated Use semantic props instead. */ whiteSpace?: string; /** @deprecated Use semantic props instead. */ htmlFor?: string; /** @deprecated Use semantic props instead. */ width?: string | number; /** @deprecated Use semantic props instead. */ height?: string | number; /** @deprecated Use semantic props instead. */ flexShrink?: number; /** @deprecated Use semantic props instead. */ capitalize?: boolean; /** @deprecated Use semantic props instead. */ hoverVariant?: string; /** @deprecated Use semantic props instead. */ cursor?: string; } /** * Text - Redesigned for "Modern Precision" theme. * Enforces semantic props. */ export const Text = forwardRef(({ children, variant = 'med', size = 'md', weight = 'normal', as = 'p', align = 'left', mono = false, font, uppercase = false, leading = 'normal', block = false, truncate = false, maxWidth, lineClamp, letterSpacing, id, color, className, style: styleProp, marginBottom, marginTop, mb, mt, ml, mr, mx, px, py, textAlign, flexGrow, maxHeight, overflow, opacity, groupHoverTextColor, lineHeight, transform, animate, transition, display, alignItems, gap, italic, fontSize, borderLeft, borderColor, pl, borderStyle, paddingX, whiteSpace, htmlFor, width, height, flexShrink, capitalize, hoverVariant, cursor, }, ref) => { const variantClasses = { high: 'text-[var(--ui-color-text-high)]', med: 'text-[var(--ui-color-text-med)]', low: 'text-[var(--ui-color-text-low)]', primary: 'text-[var(--ui-color-intent-primary)]', success: 'text-[var(--ui-color-intent-success)]', warning: 'text-[var(--ui-color-intent-warning)]', critical: 'text-[var(--ui-color-intent-critical)]', telemetry: 'text-[var(--ui-color-intent-telemetry)]', inherit: 'text-inherit', }; const sizeMap: Record = { xs: 'text-[10px]', sm: 'text-xs', base: 'text-sm', md: 'text-sm', lg: 'text-base', xl: 'text-lg', '2xl': 'text-xl', '3xl': 'text-2xl', '4xl': 'text-3xl', }; const getResponsiveSize = (s: any) => { if (!s) return sizeMap['md']; if (typeof s === 'string') return sizeMap[s] || sizeMap['md']; const classes = []; if (s.base) classes.push(sizeMap[s.base]); if (s.sm) classes.push(`sm:${sizeMap[s.sm]}`); if (s.md) classes.push(`md:${sizeMap[s.md]}`); if (s.lg) classes.push(`lg:${sizeMap[s.lg]}`); if (s.xl) classes.push(`xl:${sizeMap[s.xl]}`); return classes.join(' '); }; const weightClasses = { light: 'font-light', normal: 'font-normal', medium: 'font-medium', semibold: 'font-semibold', bold: 'font-bold', }; const leadingClasses = { none: 'leading-none', tight: 'leading-tight', snug: 'leading-snug', normal: 'leading-normal', relaxed: 'leading-relaxed', loose: 'leading-loose', }; const letterSpacingClasses: Record = { tight: 'tracking-tight', normal: 'tracking-normal', wide: 'tracking-wide', widest: 'tracking-widest', }; const getResponsiveSpacing = (prefix: string, value: any) => { if (value === undefined) return ''; if (typeof value === 'object') { const classes = []; if (value.base !== undefined) classes.push(`${prefix}-${value.base}`); if (value.sm !== undefined) classes.push(`sm:${prefix}-${value.sm}`); if (value.md !== undefined) classes.push(`md:${prefix}-${value.md}`); if (value.lg !== undefined) classes.push(`lg:${prefix}-${value.lg}`); if (value.xl !== undefined) classes.push(`xl:${prefix}-${value.xl}`); return classes.join(' '); } return ''; // Handled in style }; const getResponsiveDisplay = (d: any) => { if (!d) return ''; if (typeof d === 'string') return d.includes(':') ? d : `flex`; // Fallback const classes = []; if (d.base) classes.push(d.base); if (d.sm) classes.push(`sm:${d.sm}`); if (d.md) classes.push(`md:${d.md}`); if (d.lg) classes.push(`lg:${d.lg}`); if (d.xl) classes.push(`xl:${d.xl}`); return classes.join(' '); }; const classes = [ variantClasses[variant as keyof typeof variantClasses] || '', getResponsiveSize(size), weightClasses[weight as keyof typeof weightClasses] || '', (align === 'center' || textAlign === 'center') ? 'text-center' : ((align === 'right' || textAlign === 'right') ? 'text-right' : 'text-left'), (mono || font === 'mono') ? 'font-mono' : 'font-sans', uppercase ? 'uppercase' : '', letterSpacing ? (letterSpacingClasses[letterSpacing] || '') : (uppercase ? 'tracking-widest' : ''), leadingClasses[leading as keyof typeof leadingClasses] || '', block ? 'block' : 'inline', truncate ? 'truncate' : '', getResponsiveSpacing('mb', mb || marginBottom), getResponsiveSpacing('mt', mt || marginTop), getResponsiveDisplay(display), italic ? 'italic' : '', animate === 'pulse' ? 'animate-pulse' : '', transition ? 'transition-all duration-200' : '', capitalize ? 'capitalize' : '', color?.startsWith('text-') ? color : '', className, ].filter(Boolean).join(' '); const style: React.CSSProperties = { ...(maxWidth !== undefined ? { maxWidth } : {}), ...(maxHeight !== undefined ? { maxHeight } : {}), ...(overflow !== undefined ? { overflow } : {}), ...(flexGrow !== undefined ? { flexGrow } : {}), ...(flexShrink !== undefined ? { flexShrink } : {}), ...(opacity !== undefined ? { opacity } : {}), ...(lineClamp !== undefined ? { display: '-webkit-box', WebkitLineClamp: lineClamp, WebkitBoxOrient: 'vertical', overflow: 'hidden' } : {}), ...(color && !color.startsWith('text-') ? { color } : {}), ...(typeof mb === 'number' || typeof mb === 'string' ? { marginBottom: typeof mb === 'number' ? `${mb * 0.25}rem` : mb } : {}), ...(typeof marginBottom === 'number' || typeof marginBottom === 'string' ? { marginBottom: typeof marginBottom === 'number' ? `${marginBottom * 0.25}rem` : marginBottom } : {}), ...(typeof mt === 'number' || typeof mt === 'string' ? { marginTop: typeof mt === 'number' ? `${mt * 0.25}rem` : mt } : {}), ...(typeof marginTop === 'number' || typeof marginTop === 'string' ? { marginTop: typeof marginTop === 'number' ? `${marginTop * 0.25}rem` : marginTop } : {}), ...(ml !== undefined ? { marginLeft: typeof ml === 'number' ? `${ml * 0.25}rem` : ml } : {}), ...(mr !== undefined ? { marginRight: typeof mr === 'number' ? `${mr * 0.25}rem` : mr } : {}), ...(mx === 'auto' ? { marginLeft: 'auto', marginRight: 'auto' } : {}), ...(px !== undefined ? { paddingLeft: typeof px === 'number' ? `${px * 0.25}rem` : px, paddingRight: typeof px === 'number' ? `${px * 0.25}rem` : px } : {}), ...(py !== undefined ? { paddingTop: typeof py === 'number' ? `${py * 0.25}rem` : py, paddingBottom: typeof py === 'number' ? `${py * 0.25}rem` : py } : {}), ...(pl !== undefined ? { paddingLeft: typeof pl === 'number' ? `${pl * 0.25}rem` : pl } : {}), ...(paddingX !== undefined ? { paddingLeft: typeof paddingX === 'number' ? `${paddingX * 0.25}rem` : paddingX, paddingRight: typeof paddingX === 'number' ? `${paddingX * 0.25}rem` : paddingX } : {}), ...(letterSpacing && !letterSpacingClasses[letterSpacing] ? { letterSpacing } : {}), ...(lineHeight ? { lineHeight } : {}), ...(transform ? { textTransform: transform as any } : {}), ...(alignItems ? { alignItems } : {}), ...(gap !== undefined ? { gap: `${gap * 0.25}rem` } : {}), ...(cursor ? { cursor } : {}), ...(fontSize && typeof fontSize === 'string' ? { fontSize } : {}), ...(borderLeft ? { borderLeft: `1px solid ${borderColor || 'var(--ui-color-border-default)'}` } : {}), ...(whiteSpace ? { whiteSpace: whiteSpace as any } : {}), ...(width !== undefined ? { width } : {}), ...(height !== undefined ? { height } : {}), ...(styleProp || {}), }; const Tag = as || 'p'; return ( 0 ? style : undefined} id={id} htmlFor={htmlFor}> {children} ); }); Text.displayName = 'Text';