/** * Box (web). * * The single most-used primitive. Polymorphic: renders any HTML element * via the `as` prop while preserving the element's native attribute types. * * ```tsx * Link * Submit * ``` * * The matching `index.native.tsx` always renders a `` (RN has no * polymorphism story worth simulating). `as` is silently ignored on native. * * Variants resolve via cva for type-safe className output AND via inline * styles from the active theme so the primitive works without a stylesheet. * Classes are kept as override hooks for consumers who want their own CSS. */ import { forwardRef, type ElementType, type ForwardedRef, type CSSProperties } from "react"; import type { PolymorphicComponentPropsWithRef } from "@plyxui/core"; import { radius as radiusTokens, spacing } from "@plyxui/core"; import { useTheme } from "@plyxui/styles"; import { boxConfig, type BoxVariants } from "./config"; type BoxOwnProps = BoxVariants & { className?: string; style?: CSSProperties; }; export type BoxProps = PolymorphicComponentPropsWithRef< C, BoxOwnProps >; function joinClass(...parts: Array): string { return parts.filter(Boolean).join(" "); } const padMap: Record, number> = { none: 0, sm: spacing[2], md: spacing[4], lg: spacing[6], }; const radiusMap: Record, number> = { none: 0, sm: radiusTokens.sm, md: radiusTokens.md, lg: radiusTokens.lg, pill: radiusTokens.pill, }; function BoxImpl( { as, className, style, surface, padding, radius, children, ...rest }: BoxProps, ref: ForwardedRef, ) { const Component = (as ?? "div") as ElementType; const { colors } = useTheme(); const variantClass = boxConfig({ surface, padding, radius }); const surfaceColor = surface === "primary" ? colors.primaryFill : surface === "raised" ? colors.surfaceFill : surface === "sunken" ? colors.containerFill : undefined; const computed: CSSProperties = { boxSizing: "border-box", padding: padMap[padding ?? "none"], borderRadius: radiusMap[radius ?? "none"], ...(surfaceColor ? { backgroundColor: surfaceColor } : null), ...style, }; return ( {children} ); } /** * Forwarded-ref + polymorphic Box. * * NOTE: React's forwardRef erases polymorphic generics, so the cast below * is intentional. The exported type carries the generics; runtime is unchanged. */ export const Box = forwardRef(BoxImpl) as ( props: BoxProps, ) => React.ReactElement | null;