Composable empty-state panel component that renders a centered layout combining an optional icon/title/description message, clickable action blocks, and a footer button — each region rendered only when its inputs are provided. ## Key Components | Export | Type | Description | |--------|------|-------------| | `NoData` | `React.ForwardRefExoticComponent` | Main empty-state container component | | `NoDataProps` | `interface` | Props extending `HTMLDivElement` attributes | ### Props | Prop | Type | Description | |------|------|-------------| | `icon` | `React.ReactNode` | Leading glyph (16px mobile / 24px md+) | | `title` | `React.ReactNode` | Primary message line | | `description` | `React.ReactNode` | Secondary message line | | `actions` | `NoDataActionProps[]` | Clickable block items; hidden when empty | | `buttonLabel` | `React.ReactNode` | Footer button label text | | `buttonIcon` | `React.ReactNode` | Footer button leading icon | | `onButtonClick` | `ButtonProps["onClick"]` | Footer button click handler | | `buttonProps` | `Partial` | Extra props forwarded to the footer button | | `button` | `React.ReactNode` | Fully custom footer node; overrides `buttonLabel`/`buttonIcon` | ## Usage Example ```typescript import { NoData } from "./no-data" import { SearchIcon } from "lucide-react" // Minimal — message only } title="No results found" description="Try adjusting your search filters." /> // Full layout — message + actions + footer button } title="No devices found" description="Add a device to get started." actions={[ { label: "Import CSV", onClick: handleImport }, { label: "Sync from RMM", onClick: handleSync }, ]} buttonLabel="Add Device" buttonIcon={} onButtonClick={handleAdd} /> // Custom footer node } /> ``` Regions are conditionally rendered — `hasMessage` and `hasActions` guards ensure no empty wrappers are mounted. The footer `button` prop takes full precedence over the `buttonLabel`/`buttonIcon` convenience path.