# @bfrs/agentic-components — Agent Context

This file is auto-generated by the `@bfrs/agentic-components` package on install.
It gives AI coding agents full knowledge of the component library so they can write
correct, idiomatic UI code without guessing.

---

## Installation

Install from the public npm registry:

```bash
npm install @bfrs/agentic-components
```

## Setup

Import the stylesheet once at your app entry point:

```tsx
import "@bfrs/agentic-components/styles";
```

Import components by name:

```tsx
import { Button, Input, Modal, DataTable, DateRangePicker, ToastProvider, useToast } from "@bfrs/agentic-components";
```

**Peer dependencies required:** `react >= 18.2.0`, `react-dom >= 18.2.0`

### Angular / Custom Elements

Angular consumers should use the Custom Elements bridge instead of importing React components directly:

```ts
// main.ts
import "@bfrs/agentic-components/custom-elements";
```

```scss
/* styles.scss */
@import "@bfrs/agentic-components/styles";
```

Add `CUSTOM_ELEMENTS_SCHEMA` where the tags are rendered:

```ts
import { CUSTOM_ELEMENTS_SCHEMA, Component } from "@angular/core";

@Component({
  selector: "app-agentic-example",
  standalone: true,
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `
    <bfrs-input label="Pickup pincode" (value-change)="pickup = $event.detail.value"></bfrs-input>
    <bfrs-button variant="primary" (click)="continue()">Continue</bfrs-button>
  `
})
export class AgenticExampleComponent {
  pickup = "";
  continue() {}
}
```

Registered tags cover the documented component surface: `bfrs-box`, `bfrs-container`, `bfrs-paper`, `bfrs-stack`, `bfrs-grid`, `bfrs-text`, `bfrs-icon`, `bfrs-button`, `bfrs-icon-button`, `bfrs-form-field`, `bfrs-label`, `bfrs-input`, `bfrs-textarea`, `bfrs-select`, `bfrs-date-range-picker`, `bfrs-searchable-select`, `bfrs-checkbox`, `bfrs-radio`, `bfrs-switch`, `bfrs-badge`, `bfrs-chip`, `bfrs-alert`, `bfrs-toast-manager`, `bfrs-spinner`, `bfrs-skeleton`, `bfrs-empty-state`, `bfrs-error-state`, `bfrs-loading-state`, `bfrs-modal`, `bfrs-drawer`, `bfrs-confirm-dialog`, `bfrs-dropdown`, `bfrs-tooltip`, `bfrs-popover`, `bfrs-avatar`, `bfrs-metric-card`, `bfrs-table-pagination`, `bfrs-data-table`, `bfrs-tabs`, `bfrs-breadcrumbs`, `bfrs-action-menu`, `bfrs-page-header`, `bfrs-section-header`, `bfrs-layout-shell`, `bfrs-form-section`, `bfrs-filter-bar`, `bfrs-filter-drawer`, `bfrs-chat-bubble`, `bfrs-chat-composer`, `bfrs-full-page-loader`, `bfrs-business-info-display-card`, and `bfrs-step-progress-card`.

Use attributes for simple props: `variant`, `size`, `tone`, `label`, `loading`, `disabled`, `required`, `error-message`, `helper-text`, `prefix`, `suffix`. Use `[props]` or the `props` JSON attribute for structured props like `options`, `items`, `columns`, `data`, `sections`, `steps`, and `toasts`.

Common Angular events: `(value-change)`, `(checked-change)`, `(open-change)`, `(close)`, `(confirm)`, `(cancel)`, `(row-click)`, `(sort-change)`, `(page-change)`, `(page-size-change)`, `(action-select)`, `(dropdown-select)`, `(date-range-change)`, `(search-change)`, `(open-filters)`, `(apply)`, `(reset)`, and `(submit)`.

```html
<bfrs-select
  placeholder="Channel"
  [props]="{ options: channelOptions, value: channel }"
  (value-change)="channel = $event.detail.value">
</bfrs-select>

<bfrs-data-table
  [props]="{ data: orders, columns: orderColumns, selection: true }"
  (row-click)="openOrder($event.detail.row)"
  (sort-change)="sorting = $event.detail.sorting">
</bfrs-data-table>
```

---

## Design System Conventions

- **Control sizes** use `"xs" | "sm" | "md" | "lg"` where supported — default is `"md"` unless noted. Use `xs` for extra-compact dashboard toolbar/filter controls.
- **Tones** are always `"neutral" | "primary" | "brand" | "success" | "warning" | "danger" | "info"`
- **Variants** control visual style (filled vs. outline vs. ghost, etc.)
- All interactive components forward refs and spread native HTML props
- Styling uses **Tailwind CSS** + **CVA** — do not add raw Tailwind classes on top of variant-controlled elements
- Use the `cn()` utility from the library for conditional class merging
- **Card surface standard** — all card-like components (`Card`, `MetricCard`, `FormSection`, `BusinessInfoDisplayCard`, and `StepProgressCard` when `surface="card"`) share the same surface style: `border-radius: 12px`, a faded green-grey gradient stroke (`dcl-faded-card-border`), `background: linear-gradient(168deg, #FFF 8.6%, #FFFFFD 97.41%)`, `box-shadow: 0 0 21.7px 0 rgba(24, 240, 64, 0.03)`. Do not override these properties unless intentionally switching to a `muted` or `soft` variant.

```tsx
import { cn } from "@bfrs/agentic-components";
```

---

## Components

### Primitives

---

#### `Box`

Generic polymorphic wrapper. Use when you need a semantic HTML element with class merging.

```tsx
<Box as="section" className="my-4">…</Box>
```

| Prop | Type | Default |
|------|------|---------|
| `as` | `ElementType` | `"div"` |
| `className` | `string` | — |

---

#### `Container`

Responsive max-width wrapper with horizontal padding.

```tsx
<Container size="md">…</Container>
```

| Prop | Type | Default |
|------|------|---------|
| `size` | `"sm" \| "md" \| "lg" \| "full"` | `"lg"` |

---

#### `Paper`

Card-like surface. Use for panels, cards, and content sections.

```tsx
<Paper variant="elevated" padding="lg">…</Paper>
```

| Prop | Type | Default |
|------|------|---------|
| `variant` | `"default" \| "muted" \| "elevated" \| "outlined" \| "glass"` | `"default"` |
| `padding` | `"none" \| "sm" \| "md" \| "lg"` | `"md"` |

---

#### `Stack`

Flexbox layout. Use instead of writing flex utility classes directly.

```tsx
<Stack direction="row" gap={4} align="center">
  <Button>Save</Button>
  <Button variant="ghost">Cancel</Button>
</Stack>
```

| Prop | Type | Default |
|------|------|---------|
| `direction` | `"row" \| "column"` | `"column"` |
| `gap` | `0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 8 \| 10 \| 12` | `4` |
| `align` | `CSSProperties["alignItems"]` | — |
| `justify` | `CSSProperties["justifyContent"]` | — |
| `wrap` | `boolean` | `false` |

---

#### `Grid`

Responsive CSS grid layout.

```tsx
<Grid columns={3} gap="md">
  <Card />
  <Card />
  <Card />
</Grid>
```

| Prop | Type | Default |
|------|------|---------|
| `columns` | `1 \| 2 \| 3 \| 4` | `3` |
| `gap` | `"sm" \| "md" \| "lg"` | `"md"` |

---

#### `Text`

Semantic typography. Always use this instead of raw `<p>`, `<h1>`, `<span>` for text.

```tsx
<Text variant="h2">Welcome back</Text>
<Text variant="body" tone="muted">Last seen 2 hours ago</Text>
```

| Prop | Type | Default |
|------|------|---------|
| `variant` | `"display" \| "h1" \| "h2" \| "h3" \| "title" \| "body" \| "body-sm" \| "caption" \| "label"` | `"body"` |
| `tone` | `"primary" \| "secondary" \| "muted" \| "disabled" \| "danger" \| "success" \| "accent"` | `"primary"` |
| `as` | `ElementType` | inferred from variant |

---

#### `Icon`

Phosphor icon wrapper with consistent sizing and accessibility.

```tsx
import { MagnifyingGlass } from "@phosphor-icons/react";

<Icon icon={MagnifyingGlass} size="md" weight="bold" />
```

| Prop | Type | Default |
|------|------|---------|
| `icon` | `PhosphorIconComponent` | **required** |
| `size` | `"xs" \| "sm" \| "md" \| "lg" \| number` | `"md"` |
| `weight` | `"thin" \| "light" \| "regular" \| "bold" \| "fill" \| "duotone"` | `"regular"` |
| `decorative` | `boolean` | `true` |

> When `decorative={false}`, add an `aria-label` to the wrapping element.

---

### Actions

---

#### `Button`

Primary interactive element. Covers all CTA patterns.

```tsx
<Button variant="primary" size="md" onClick={handleSave}>
  Save changes
</Button>

<Button variant="danger" loading={isDeleting}>
  Delete account
</Button>

<Button variant="tertiary">Save this view</Button>

<Button variant="outline" leftIcon={<Icon icon={Plus} />}>
  Add item
</Button>
```

| Prop | Type | Default |
|------|------|---------|
| `variant` | `"primary" \| "secondary" \| "tertiary" \| "outline" \| "ghost" \| "danger" \| "destructive" \| "link"` | `"primary"` |
| `size` | `"xs" \| "sm" \| "md" \| "lg"` | `"md"` |
| `fullWidth` | `boolean` | `false` |
| `leftIcon` | `ReactNode` | — |
| `rightIcon` | `ReactNode` | — |
| `loading` | `boolean` | `false` |
| `disabled` | `boolean` | `false` |

---

#### `IconButton`

Square button for icon-only actions. Always provide `aria-label`.

```tsx
<IconButton
  icon={<Icon icon={Trash} />}
  variant="ghost"
  size="sm"
  aria-label="Delete item"
  onClick={handleDelete}
/>
```

| Prop | Type | Default |
|------|------|---------|
| `icon` | `ReactNode` | **required** |
| `aria-label` | `string` | **required** |
| `variant` | `"primary" \| "secondary" \| "outline" \| "ghost" \| "danger"` | `"ghost"` |
| `size` | `"xs" \| "sm" \| "md" \| "lg"` | `"md"` |
| `loading` | `boolean` | `false` |

---

### Forms

> **Rule:** Always wrap form controls in `FormField` — it handles label, helper text, error text, and aria wiring automatically.

---

#### `FormField`

Wraps any form control with label, helper, and error text. Connects them via `aria-describedby`.

```tsx
<FormField
  label="Email address"
  required
  helperText="We'll never share your email."
  errorText={errors.email}
>
  <Input type="email" value={email} onChange={…} />
</FormField>
```

| Prop | Type | Default |
|------|------|---------|
| `label` | `ReactNode` | — |
| `required` | `boolean` | `false` |
| `helperText` | `ReactNode` | — |
| `errorText` | `ReactNode` | — |
| `disabled` | `boolean` | `false` |
| `children` | `ReactElement` | **required** |

---

#### `Label`

Standalone label. Prefer `FormField` which renders this automatically.

```tsx
<Label required>Business name</Label>
```

| Prop | Type | Default |
|------|------|---------|
| `required` | `boolean` | `false` |
| `disabled` | `boolean` | `false` |

---

#### `Input`

Standard text input.

```tsx
<Input
  placeholder="Search…"
  size="md"
  leftIcon={<Icon icon={MagnifyingGlass} />}
/>

<Input prefix="₹" suffix="INR" placeholder="0.00" />
<Input error value={val} onChange={…} />
```

| Prop | Type | Default |
|------|------|---------|
| `size` | `"xs" \| "sm" \| "md" \| "lg"` | `"md"` |
| `error` | `boolean` | `false` |
| `prefix` | `ReactNode` | — |
| `suffix` | `ReactNode` | — |
| `leftIcon` | `ReactNode` | — |
| `rightIcon` | `ReactNode` | — |
| `loading` | `boolean` | `false` |

Accepts all native `<input>` props.

---

#### `Textarea`

Multi-line text input.

```tsx
<Textarea
  rows={6}
  placeholder="Describe your issue…"
  error={!!errors.description}
/>
```

| Prop | Type | Default |
|------|------|---------|
| `size` | `"sm" \| "md" \| "lg"` | `"md"` |
| `error` | `boolean` | `false` |
| `rows` | `number` | `4` |

Accepts all native `<textarea>` props.

---

#### `Select`

Single-value dropdown. Options are `{ value: string; label: string }`.

```tsx
<Select
  options={[
    { value: "in", label: "India" },
    { value: "us", label: "United States" },
  ]}
  value={country}
  onValueChange={setCountry}
  placeholder="Select country"
/>
```

| Prop | Type | Default |
|------|------|---------|
| `options` | `{ value: string; label: string }[]` | **required** |
| `value` | `string` | — |
| `onValueChange` | `(value: string) => void` | — |
| `placeholder` | `string` | `"Select"` |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` |
| `disabled` | `boolean` | `false` |
| `error` | `boolean` | `false` |

---

#### `DateRangePicker`

Preset and custom calendar date-range filter. Presets commit immediately; custom ranges use Apply/Cancel.

```tsx
import { DateRangePicker, presetToRange, type DateRangeValue } from "@bfrs/agentic-components";

const [range, setRange] = useState<DateRangeValue>({
  preset: "Last 30 days",
  ...presetToRange("Last 30 days")
});

<DateRangePicker value={range} onChange={setRange} maxRangeDays={365} />;
```

| Prop | Type | Default |
|------|------|---------|
| `value` | `DateRangeValue` | — |
| `onChange` | `(value: DateRangeValue) => void` | — |
| `presets` | `DateRangePreset[]` | default presets |
| `size` | `"xs" \| "sm" \| "md" \| "lg"` | `"sm"` |
| `maxRangeDays` | `number` | — |
| `months` | `1 \| 2` | `2` |
| `open` / `onOpenChange` | controlled popover state | — |

Keep API date formatting, route updates, and business limits in the consuming app.

---

#### `SearchableSelect`

Combobox with search. Use when options list is long (10+).

```tsx
<SearchableSelect
  options={cities}
  value={city}
  onValueChange={setCity}
  placeholder="Select city"
  searchPlaceholder="Search cities…"
  clearable
/>
```

| Prop | Type | Default |
|------|------|---------|
| `options` | `{ value: string; label: string }[]` | **required** |
| `value` | `string` | — |
| `onValueChange` | `(value: string \| undefined) => void` | — |
| `placeholder` | `string` | `"Select"` |
| `searchPlaceholder` | `string` | `"Search..."` |
| `emptyText` | `string` | `"No results found"` |
| `loading` | `boolean` | `false` |
| `disabled` | `boolean` | `false` |
| `error` | `boolean` | `false` |
| `clearable` | `boolean` | `true` |

---

#### `Checkbox`

Square checklist control for independent true/false decisions or multi-select choices.
Use `Radio` instead when exactly one option in a group can be selected.

```tsx
<Checkbox
  checked={agreed}
  onCheckedChange={setAgreed}
  label="Accept terms"
  description="Use checkboxes when each option can be selected independently."
/>

<Checkbox label="Partially selected" checked="indeterminate" />
```

| Prop | Type | Default |
|------|------|---------|
| `label` | `ReactNode` | — |
| `description` | `ReactNode` | — |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` |
| `error` | `boolean` | `false` |
| `checked` | `boolean \| "indeterminate"` | — |
| `onCheckedChange` | `(checked: boolean \| "indeterminate") => void` | — |

---

#### `Radio`

Radio group. Renders a list of mutually exclusive options.

```tsx
<Radio
  value={plan}
  onValueChange={setPlan}
  options={[
    { value: "free", label: "Free" },
    { value: "pro", label: "Pro" },
    { value: "enterprise", label: "Enterprise" },
  ]}
/>
```

| Prop | Type | Default |
|------|------|---------|
| `options` | `{ value: string; label: string }[]` | **required** |
| `value` | `string` | — |
| `onValueChange` | `(value: string) => void` | — |
| `error` | `boolean` | `false` |

---

#### `Switch`

Toggle switch with optional label.

```tsx
<Switch
  checked={notifications}
  onCheckedChange={setNotifications}
  label="Email notifications"
/>
```

| Prop | Type | Default |
|------|------|---------|
| `label` | `string` | — |
| `checked` | `boolean` | — |
| `onCheckedChange` | `(checked: boolean) => void` | — |

---

### Feedback

---

#### `Badge`

Small inline status label.

```tsx
<Badge tone="success">Active</Badge>
<Badge tone="warning">Pending</Badge>
<Badge tone="danger">Blocked</Badge>
<Badge count={3} aria-label="3 active filters" />
```

| Prop | Type | Default |
|------|------|---------|
| `size` | `"xs" \| "sm" \| "md" \| "lg"` | `"sm"` |
| `variant` | `"default" \| "neutral" \| "primary" \| "brand" \| "success" \| "warning" \| "danger" \| "info"` | `"default"` |
| `tone` | `"neutral" \| "primary" \| "brand" \| "success" \| "warning" \| "danger" \| "info"` | `"neutral"` |
| `dot` | `boolean` | `false` |
| `count` | `number` | — |

---

#### `Chip`

Removable tag. Use in filter bars and multi-select UIs.

```tsx
<Chip
  tone="primary"
  variant="soft"
  leftIcon={<Icon icon={Tag} />}
  removable
  onRemove={() => removeFilter("status")}
>
  Status: Active
</Chip>
```

| Prop | Type | Default |
|------|------|---------|
| `variant` | `"default" \| "filled" \| "soft" \| "outline"` | `"default"` |
| `tone` | `"neutral" \| "primary" \| "brand" \| "success" \| "warning" \| "danger" \| "info"` | `"neutral"` |
| `size` | `"xs" \| "sm" \| "md" \| "lg"` | `"sm"` |
| `leftIcon` | `ReactNode` | — |
| `removable` | `boolean` | `false` |
| `onRemove` | `() => void` | — |
| `removeLabel` | `string` | `"Remove"` |

---

#### `Alert`

Contextual message banner. Auto-selects an icon based on tone.

```tsx
<Alert
  tone="warning"
  title="Your trial ends in 3 days"
  action={<Button size="sm">Upgrade now</Button>}
>
  Upgrade to keep access to all features.
</Alert>
```

| Prop | Type | Default |
|------|------|---------|
| `tone` | `"info" \| "success" \| "warning" \| "danger"` | `"info"` |
| `title` | `ReactNode` | — |
| `action` | `ReactNode` | — |
| `icon` | `ReactNode` | auto (from tone) |

---

#### `ToastProvider`, `useToast`, `ToastManager`

App-wide transient feedback manager. Wrap the app once, then call toast helpers from event handlers.

```tsx
function SaveButton() {
  const { success, danger } = useToast();

  async function save() {
    try {
      await saveRequest();
      success("Changes saved");
    } catch {
      danger({ title: "Save failed", description: "Try again in a moment." });
    }
  }

  return <Button onClick={save}>Save</Button>;
}

<ToastProvider placement="bottom-center">
  <SaveButton />
</ToastProvider>;
```

| Prop / API | Type | Default |
|------|------|---------|
| `placement` | `"top-left" \| "top-center" \| "top-right" \| "bottom-left" \| "bottom-center" \| "bottom-right"` | `"bottom-center"` |
| `maxToasts` | `number` | `4` |
| `defaultDuration` | `number` | `2600` |
| `toast` | `(input: ToastInput) => string` | — |
| `success` / `warning` / `danger` / `info` | semantic helper functions | — |
| `dismiss` / `clear` | manager controls | — |

Do not put API calls, route logic, or app stores inside the library toast manager.

---

#### `Spinner`

Loading indicator. Use inside buttons, inline loaders, or page sections.

```tsx
<Spinner size="md" label="Fetching orders…" />
```

| Prop | Type | Default |
|------|------|---------|
| `size` | `"sm" \| "md" \| "lg"` | `"md"` |
| `label` | `string` | `"Loading"` |

---

#### `Skeleton`

Shimmer placeholder while content loads. Match the variant to the shape of the real content.

```tsx
<Skeleton variant="text" />   // single line
<Skeleton variant="card" />   // card-height block
<Skeleton variant="avatar" /> // circle
<Skeleton variant="block" />  // rectangular block
<Skeleton variant="text" animated={false} /> // static shimmer
```

| Prop | Type | Default |
|------|------|---------|
| `variant` | `"text" \| "block" \| "card" \| "avatar"` | `"block"` |
| `animated` | `boolean` | `true` |

---

#### `EmptyState`

Centered empty state for lists, tables, and search results.

```tsx
<EmptyState
  icon={<Icon icon={Package} size="lg" />}
  title="No orders yet"
  description="Orders placed by your customers will appear here."
  action={<Button>Create order</Button>}
/>
```

| Prop | Type | Default |
|------|------|---------|
| `title` | `ReactNode` | **required** |
| `icon` | `ReactNode` | — |
| `description` | `ReactNode` | — |
| `action` | `ReactNode` | — |

---

### Overlays

---

#### `Modal`

Centered modal. Use for confirmations, forms, and focused tasks.

```tsx
<Modal
  trigger={<Button>Delete account</Button>}
  title="Are you sure?"
  description="This action cannot be undone."
  footer={
    <Stack direction="row" gap={2} justify="flex-end">
      <Button variant="ghost">Cancel</Button>
      <Button variant="destructive" onClick={handleDelete}>Delete</Button>
    </Stack>
  }
>
  All your data will be permanently removed.
</Modal>
```

| Prop | Type | Default |
|------|------|---------|
| `title` | `ReactNode` | **required** |
| `children` | `ReactNode` | **required** |
| `trigger` | `ReactNode` | — |
| `description` | `ReactNode` | — |
| `footer` | `ReactNode` | — |
| `size` | `"sm" \| "md" \| "lg" \| "xl" \| "full"` | `"md"` |
| `open` | `boolean` | — |
| `onOpenChange` | `(open: boolean) => void` | — |

`Dialog` is a deprecated compatibility alias. Use `Modal` in new code.

---

#### `Drawer`

Slide-out panel. Use for detail views, settings, and secondary flows.

```tsx
<Drawer
  trigger={<Button variant="outline">View details</Button>}
  title="Order #1234"
  placement="right"
  size="xl"
>
  <OrderDetail id="1234" />
</Drawer>
```

| Prop | Type | Default |
|------|------|---------|
| `title` | `ReactNode` | **required** |
| `children` | `ReactNode` | **required** |
| `placement` | `"left" \| "right" \| "bottom"` | `"right"` |
| `size` | `"sm" \| "md" \| "lg" \| "xl"` | `"md"` |
| `trigger` | `ReactNode` | — |
| `description` | `ReactNode` | — |
| `open` | `boolean` | — |
| `onOpenChange` | `(open: boolean) => void` | — |

---

#### `Dropdown`

Context menu attached to a trigger. Items support destructive and checked states.

```tsx
<Dropdown
  trigger={<IconButton icon={<Icon icon={DotsThree} />} aria-label="More actions" />}
  align="end"
  items={[
    { label: "Edit", onSelect: handleEdit },
    { label: "Duplicate", onSelect: handleDuplicate },
    { label: "Delete", onSelect: handleDelete, destructive: true },
  ]}
/>
```

| Prop | Type | Default |
|------|------|---------|
| `trigger` | `ReactNode` | **required** |
| `items` | `{ label: string; onSelect: () => void; disabled?: boolean; destructive?: boolean; checked?: boolean }[]` | **required** |
| `align` | `"start" \| "center" \| "end"` | `"end"` |
| `size` | `"xs" \| "sm" \| "md" \| "lg"` | `"md"` |

---

#### `Tooltip`

Floating label on hover. Provide `content` as the tooltip text.

```tsx
<Tooltip content="Copy to clipboard" side="top">
  <IconButton icon={<Icon icon={Copy} />} aria-label="Copy" />
</Tooltip>
```

| Prop | Type | Default |
|------|------|---------|
| `content` | `ReactNode` | **required** |
| `children` | `ReactNode` | **required** |
| `side` | `"top" \| "right" \| "bottom" \| "left"` | `"top"` |
| `delayDuration` | `number` | `350` |

---

#### `Popover`

Floating content panel. Use for filters, pickers, and inline forms.

```tsx
<Popover
  trigger={<Button variant="outline">Filter</Button>}
  align="start"
>
  <FilterForm />
</Popover>
```

| Prop | Type | Default |
|------|------|---------|
| `trigger` | `ReactNode` | **required** |
| `children` | `ReactNode` | **required** |
| `align` | `"start" \| "center" \| "end"` | `"center"` |

---

### Data Display

---

#### `Avatar`

User avatar with image, initials fallback, and online status.

```tsx
<Avatar
  src={user.avatarUrl}
  name={user.fullName}
  size="md"
  status="online"
/>
```

| Prop | Type | Default |
|------|------|---------|
| `src` | `string` | — |
| `alt` | `string` | — |
| `name` | `string` | — |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` |
| `status` | `"online" \| "busy" \| "offline"` | — |

> When `src` is absent, renders initials derived from `name`.

---

#### `TablePagination`

Table page navigation. Handles ellipsis, edge pages, and optional page-size controls.

```tsx
<TablePagination
  page={currentPage}
  totalPages={totalPages}
  pageSize={pageSize}
  onPageChange={setCurrentPage}
  onPageSizeChange={setPageSize}
/>
```

| Prop | Type | Default |
|------|------|---------|
| `page` | `number` | **required** |
| `totalPages` | `number` | **required** |
| `onPageChange` | `(page: number) => void` | **required** |
| `pageSize` | `number` | — |
| `onPageSizeChange` | `(pageSize: number) => void` | — |

---

#### `DataTable`

Generic data table with sorting, loading skeleton, row actions, selection, pagination, and empty/error states.

```tsx
<DataTable
  columns={[
    { id: "name", header: "Name", accessorKey: "name", sortable: true },
    { id: "status", header: "Status", cell: (row) => <Badge tone={row.status === "active" ? "success" : "neutral"}>{row.status}</Badge> },
  ]}
  data={orders}
  loading={isLoading}
  sorting={sorting}
  onSortingChange={setSorting}
  onRowClick={(row) => navigate(`/orders/${row.id}`)}
  rowActions={(row) => (
    <ActionMenu trigger={…} items={[…]} />
  )}
  emptyTitle="No orders found"
  emptyDescription="Try adjusting your filters."
/>
```

| Prop | Type | Default |
|------|------|---------|
| `columns` | `DataTableColumn<T>[]` | **required** |
| `data` | `T[]` | **required** |
| `loading` | `boolean` | `false` |
| `enableSorting` | `boolean` | `true` |
| `sorting` | `{ columnId: string; direction: "asc" \| "desc" }` | — |
| `onSortingChange` | `(sorting) => void` | — |
| `enableColumnPinning` | `boolean` | `true` |
| `enableColumnReordering` | `boolean` | `true` |
| `onRowClick` | `(row: T) => void` | — |
| `rowActions` | `(row: T) => ReactNode` | — |
| `selection` | `boolean` | `false` |
| `density` | `"compact" \| "default" \| "comfortable"` | `"default"` |
| `emptyTitle` | `ReactNode` | `"No records found"` |
| `emptyDescription` | `ReactNode` | — |

`DataTableColumn<T>`:
```ts
{
  id: string;
  header: ReactNode;
  accessorKey?: keyof T;
  accessorFn?: (row: T) => unknown;
  sortable?: boolean;
  cell?: (row: T) => ReactNode;
}
```

`enableSorting`, `enableColumnPinning`, and `enableColumnReordering` are enabled by default. Pass `false` to disable each behavior for a simpler table.

When `loading` is true, `DataTable` renders built-in table-row skeleton placeholders rather than a spinner. The consumer app only owns the loading boolean.

---

### Navigation

---

#### `Tabs`

Tabbed content switcher.

```tsx
<Tabs
  variant="line"
  defaultValue="overview"
  items={[
    { value: "overview", label: "Overview", content: <Overview /> },
    { value: "orders", label: "Orders", content: <Orders /> },
    { value: "settings", label: "Settings", content: <Settings /> },
  ]}
/>

<Tabs defaultValue="overview">
  <Tabs.List>
    <Tabs.Trigger value="overview">Overview</Tabs.Trigger>
    <Tabs.Trigger value="orders" badge={<Badge count={12} />}>Orders</Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="overview">...</Tabs.Content>
  <Tabs.Content value="orders">...</Tabs.Content>
</Tabs>
```

| Prop | Type | Default |
|------|------|---------|
| `items` | `{ value: string; label: ReactNode; content?: ReactNode; badge?: ReactNode }[]` | — |
| `variant` | `"line" \| "pill"` | `"line"` |
| `size` | `"xs" \| "sm" \| "md" \| "lg"` | `"md"` |
| `defaultValue` | `string` | — |
| `value` | `string` | — |
| `onValueChange` | `(value: string) => void` | — |

---

#### `Breadcrumbs`

Navigation trail. Last item is rendered as plain text (current page).

```tsx
<Breadcrumbs
  items={[
    { label: "Home", href: "/" },
    { label: "Orders", href: "/orders" },
    { label: "Order #1234" },
  ]}
/>
```

| Prop | Type | Default |
|------|------|---------|
| `items` | `{ label: ReactNode; href?: string }[]` | **required** |

---

### Patterns

> Patterns are opinionated compositions for common full-page and feature-level layouts.

---

#### `PageHeader`

Standardized page title section. Use at the top of every page.

```tsx
<PageHeader
  eyebrow="Orders"
  title="All orders"
  description="View and manage customer orders."
  actions={<Button leftIcon={<Icon icon={Plus} />}>New order</Button>}
  secondaryActions={<Button variant="outline">Export</Button>}
  onBack={() => navigate(-1)}
/>
```

| Prop | Type | Default |
|------|------|---------|
| `title` | `ReactNode` | **required** |
| `eyebrow` | `ReactNode` | — |
| `description` | `ReactNode` | — |
| `onBack` | `() => void` | — |
| `actions` | `ReactNode` | — |
| `secondaryActions` | `ReactNode` | — |

---

#### `LayoutShell`

Full-page app shell with sticky header and collapsible sidebar.

```tsx
<LayoutShell
  header={<AppHeader />}
  sidebar={<SideNav />}
>
  <Outlet />
</LayoutShell>
```

| Prop | Type | Default |
|------|------|---------|
| `children` | `ReactNode` | **required** |
| `header` | `ReactNode` | — |
| `sidebar` | `ReactNode` | — |

---

#### `ChatBubble`

Chat message bubble. Renders differently for `user`, `assistant`, and `system` senders. Assistant messages support a Figma-derived identity block with an uppercase eyebrow, title, and muted body copy.

```tsx
<ChatBubble sender="assistant" eyebrow="Identity" title="Your details are ready" timestamp="2:34 PM" loading={isStreaming}>
  We've found your name and email linked to your number.
  <br />
  Review and continue, or edit if needed.
</ChatBubble>

<ChatBubble sender="user" timestamp="2:35 PM">
  Can you filter by last 7 days?
</ChatBubble>
```

| Prop | Type | Default |
|------|------|---------|
| `sender` | `"user" \| "assistant" \| "system"` | **required** |
| `children` | `ReactNode` | — |
| `eyebrow` | `ReactNode` | — |
| `title` | `ReactNode` | — |
| `timestamp` | `ReactNode` | — |
| `status` | `ReactNode` | — |
| `loading` | `boolean` | `false` |
| `errorAction` | `ReactNode` | — |

---

#### `ChatComposer`

Chat input with attachment and action slots. Submits on `Ctrl+Enter`.

```tsx
<ChatComposer
  value={message}
  onValueChange={setMessage}
  onSubmit={handleSend}
  loading={isSending}
  placeholder="Ask me anything"
  attachmentSlot={<IconButton icon={<Icon icon={Paperclip} />} aria-label="Attach" />}
/>
```

| Prop | Type | Default |
|------|------|---------|
| `value` | `string` | **required** |
| `onValueChange` | `(value: string) => void` | **required** |
| `onSubmit` | `() => void` | — |
| `loading` | `boolean` | `false` |
| `disabled` | `boolean` | `false` |
| `placeholder` | `string` | `"Ask me anything"` |
| `attachmentSlot` | `ReactNode` | — |
| `actionSlot` | `ReactNode` | — |

---

#### `FullPageLoader`

Branded full-screen loading screen. Use during auth redirects and account setup.

```tsx
<FullPageLoader
  titlePrefix="Setting up your "
  titleHighlight="workspace"
  titleSuffix="…"
  description="This takes just a moment."
  statusLabel="Configuring account"
/>
```

| Prop | Type | Default |
|------|------|---------|
| `titlePrefix` | `ReactNode` | `"Your account is ready. I'll take you to your "` |
| `titleHighlight` | `ReactNode` | `"dashboard"` |
| `titleSuffix` | `ReactNode` | `" now."` |
| `description` | `ReactNode` | `"Your account is being configured…"` |
| `fullScreen` | `boolean` | `true` |
| `statusLabel` | `string` | `"Loading account dashboard"` |

---

#### `BusinessInfoDisplayCard`

Rich business identity card with centered profile identity, metadata chips, and compact label-value details. Uses the standard card surface (faded green-grey gradient stroke, white gradient background, green-glow shadow) and the Figma-derived green header wash.

Built-in loading behavior:
- Bootstrap loading with `businessName=""` and `sections={[]}` renders static shimmer placeholders for avatar, name, subtitle/email, order-volume chip, category chip, and six detail rows.
- Missing or empty `initials` renders a static shimmer avatar circle when no `logoSrc` is provided.
- Missing item values (`value: undefined`, `null`, `false`, or `""`) render skeletons for both the key and value. Field labels only appear once their values are present.

```tsx
<BusinessInfoDisplayCard
  businessName="Deeksha Gahlot"
  subtitle="deekshagahlot@gmail.com"
  initials="DG"
  chips={[{ label: "30-100/ month" }, { label: "Starting Up" }]}
  sections={[
    {
      items: [
        { label: "Business Type", value: "Registered" },
        { label: "Company Name", value: "Deedoodle" },
        { label: "Pickup Pincode", value: "122099" },
      ],
    },
  ]}
/>

<BusinessInfoDisplayCard businessName="" sections={[]} />

<BusinessInfoDisplayCard
  businessName="Deedoodle"
  initials="DD"
  sections={[
    {
      title: "Account Details",
      items: [
        { label: "Phone", value: "9876543210" },
        { label: "GST Number", value: undefined },
      ],
    },
  ]}
/>
```

| Prop | Type | Default |
|------|------|---------|
| `businessName` | `ReactNode` | **required** |
| `sections` | `BusinessInfoSection[]` | **required** |
| `subtitle` | `ReactNode` | — |
| `initials` | `string` | — |
| `logoSrc` | `string` | — |
| `logoAlt` | `string` | — |
| `chips` | `{ label: ReactNode; icon?: ReactNode }[]` | `"30-100/ month"`, `"Starting Up"` |
| `background` | `string` | — |
| `gradient` | `string` | — |
| `headerBackground` | `string` | — |
| `headerGradient` | `string` | — |

`BusinessInfoSection`:
```ts
{ title?: ReactNode; items: { label: ReactNode; value?: ReactNode }[] }
```

---

#### `StepProgressCard`

Step-by-step progress indicator. Calculates `done` / `active` / `pending` state automatically from `currentStep` and preserves the animated completed-dot, active-star, and rail-fill transitions. Defaults to the Figma-derived plain progress block; pass `surface="card"` for the standard card wrapper.

```tsx
<StepProgressCard
  eyebrow="Identity & Contact"
  title="Getting your details ready…"
  currentStep={1}
  animated
  steps={[
    { label: "Securely Fetching to your account" },
    { label: "Verifying your identity" },
    { label: "Retrieving business details" },
    { label: "Validating your information" },
  ]}
/>
```

| Prop | Type | Default |
|------|------|---------|
| `steps` | `{ label: ReactNode; status?: "done" \| "active" \| "pending" \| "disabled"; disabled?: boolean }[]` | **required** |
| `currentStep` | `number` | `0` |
| `eyebrow` | `ReactNode` | `"Identity & Contact"` |
| `title` | `ReactNode` | `"Getting your details ready…"` |
| `surface` | `"card" \| "plain"` | `"plain"` |
| `animated` | `boolean` | `true` |

---

## Common Patterns

### Form with validation

```tsx
<Stack gap={4}>
  <FormField label="Full name" required errorText={errors.name}>
    <Input value={name} onChange={(e) => setName(e.target.value)} state={errors.name ? "error" : "default"} />
  </FormField>

  <FormField label="Plan" required errorText={errors.plan}>
    <Select options={planOptions} value={plan} onValueChange={setPlan} error={!!errors.plan} />
  </FormField>

  <Stack direction="row" gap={2} justify="flex-end">
    <Button variant="ghost">Cancel</Button>
    <Button loading={isSubmitting} onClick={handleSubmit}>Save</Button>
  </Stack>
</Stack>
```

### Table page

```tsx
<Container>
  <PageHeader
    title="Orders"
    actions={<Button leftIcon={<Icon icon={Plus} />}>New order</Button>}
  />
  <Card>
    <DataTable
      columns={columns}
      data={orders}
      loading={isLoading}
      sorting={sorting}
      onSortingChange={setSorting}
      pagination={{ page, totalPages, onPageChange: setPage }}
    />
  </Card>
</Container>
```

### Confirm delete dialog

```tsx
<ConfirmDialog
  open={showConfirm}
  onOpenChange={setShowConfirm}
  destructive
  title="Delete order?"
  description="This cannot be undone."
  confirmLabel="Delete"
  loading={isDeleting}
  onConfirm={handleDelete}
/>
```

### Chat interface

```tsx
<LayoutShell header={<AppHeader />}>
  <Stack gap={0}>
    {messages.map((msg) => (
      <ChatBubble key={msg.id} sender={msg.sender} timestamp={msg.time}>
        {msg.text}
      </ChatBubble>
    ))}
    {isStreaming && <ChatBubble sender="assistant" loading />}
  </Stack>
  <ChatComposer
    value={input}
    onValueChange={setInput}
    onSubmit={sendMessage}
    loading={isStreaming}
  />
</LayoutShell>
```

---

## What NOT to do

- Do not use raw Tailwind classes for spacing, color, or typography — use `Stack`, `Text`, and component props instead
- Do not build custom modals, drawers, or dropdowns — use `Modal`, `ConfirmDialog`, `Drawer`, and `ActionMenu`
- Do not render form labels manually — use `FormField` which wires aria attributes automatically
- Do not use `<h1>`–`<h6>` or `<p>` directly — use `<Text variant="h1">` etc.
- Do not add `loading` spinners manually — all interactive components accept a `loading` prop
