import { createMemo } from "@solidrt/core" import type { PointerProps } from "@solidrt/core" import type { StyleProps, TextLayoutProps } from "./types" import { theme, type TextVariant } from "./theme" import { policy } from "./policy" import { typeWeight } from "./typography" // Semantic text colors, resolved through the theme. Curated: only tokens that // make sense as a text fill; style.color takes raw values for anything else. export type TextColor = "text" | "textMuted" | "primary" | "onPrimary" | "danger" export interface TextProps extends PointerProps { children?: any // Typography role from the theme's type scale; defaults to "body". Explicit // layout font props override the role's fields individually. fontSize // (role-derived or explicit) is multiplied by policy.textScale and // fontWeight carries the typeWeight low-DPI compensation; use the core // primitive for text that must not scale. variant?: TextVariant // Semantic color from the theme; defaults to "text". style.color still wins. color?: TextColor // Sugar for color="textMuted". muted?: boolean ref?: (node: { id: number }) => void layout?: TextLayoutProps style?: StyleProps } // Font keys live in layout (they affect measurement) but belong on the inner // node, not the box . Strip them out before spreading layout. const FONT_KEYS = [ "fontFamily", "fontSize", "lineHeight", "fontStyle", "fontWeight", "textAlign", "maxLines", ] export function Text(props: TextProps) { let role = () => theme.text[props.variant ?? "body"] let size = () => (props.layout?.fontSize ?? role().size) * policy.textScale let color = () => props.style?.color ?? theme.color[props.color ?? (props.muted ? "textMuted" : "text")] let box = createMemo(() => { let l = props.layout if (!l) return {} let out: Record = {} for (let key in l) { if (!FONT_KEYS.includes(key)) out[key] = (l as Record)[key] } return out }) return ( {props.children} ) }