import { type JSX, Show, splitProps, mergeProps, createUniqueId } from 'solid-js'; import { cn } from '../utils/cn'; import { AlertTriangle } from 'lucide-solid'; export interface CardProps extends JSX.HTMLAttributes { /** Heading rendered in the card chrome (the contract's CardEnvelope.title). * NB: NOT `title` — `title` is a reserved IDL attr (see define.tsx RESERVED). */ heading?: string; /** Optional supporting text under the heading. */ description?: string; /** Media region (image/icon) rendered above the heading. */ media?: JSX.Element; /** Footer action region (buttons). */ actions?: JSX.Element; /** When set, the card renders its standard inline error state INSTEAD of body. */ errorMessage?: string; /** Compact spacing for dense lists of cards. */ dense?: boolean; /** Stable id for the heading (so composing cards can `aria-labelledby` it). * Auto-generated when omitted. */ headingId?: string; } /** * `Card` — the shared presentational chrome every native card composes from: * an optional media region, a heading + description, a body (default slot), an * actions footer, and one consistent inline **error** state (the contract's * "never a broken/partial card" rule). It is intentionally chrome-only: it reads * no `CardContext` and emits no `CardEvent` — the cards that compose it (e.g. * `kc-form`) own the contract interaction. */ export function Card(props: CardProps): JSX.Element { const merged = mergeProps({ dense: false }, props); const [local, rest] = splitProps(merged, [ 'heading', 'description', 'media', 'actions', 'errorMessage', 'dense', 'headingId', 'class', 'children', ]); const autoId = createUniqueId(); const headingId = () => local.headingId ?? `kc-card-heading-${autoId}`; const hasError = () => local.errorMessage !== undefined && local.errorMessage !== ''; const hasHeader = () => Boolean(local.heading) || Boolean(local.description); return (
{local.media}

{local.heading}

{local.description}

{local.children}
{local.actions}
} >
); }