import type { ReactNode } from "react"; /** * The two contracts that make "never dead-end the user" a compile error instead of a rule * somebody remembers. * * **No component ships here, on purpose.** Seven repos have an `EmptyState.tsx` and an * `ErrorState.tsx`, and read side by side they overlap 9–37%: one draws a tinted icon badge, one a * branded illustration set, one a mascot. What they genuinely share is the PROP SHAPE, which is the * rule itself, and the only part a package can hold without deciding how eight brands look. Same * reasoning as the styled Button: share behaviour, skin per product. * * Import the type, write your own component against it, and the compiler enforces the rest. */ /** * A panel with nothing in it yet. * * The prop shape IS the rule: somebody who lands here must learn what this panel is FOR * (`title`), what belongs IN it (`description`), and how to FILL it (`action`). The first two * are required because two of the three are what make it an orientation rather than a shrug. * `action` is optional only because some panels fill themselves once a job upstream finishes. */ export interface EmptyStateProps { /** What this panel is for. Use "No lookups yet", not "No results". */ title: string; /** What belongs here, and what it will show once it does. */ description: ReactNode; /** The way forward, as a control. Usually one button. */ action?: ReactNode; /** * Defaults to `3` for a panel that already sits under a page heading, the common case. `1` when * this composer IS the page (a 404, a suspended account), which otherwise ships a document with * no `h1` in it at all. * * Only one donor had this, and it is the difference between a screen reader announcing a * page and announcing nothing. * * **The type cannot make your panel read it.** A panel that always renders an `