# @tailor-platform/app-shell — UI cheat sheet

Import from `@tailor-platform/app-shell` instead of duplicating shadcn-style `components/ui` when possible. Details: [app-shell docs/components](https://raw.github.com/tailor-platform/app-shell/tree/main/docs/components).

## Layout

- **`Layout`** — `title` / `actions` / `columns` still work; prefer **`Layout.Header`** (`title`, `actions`, children e.g. tabs) + **`Layout.Column`**.
- **`Layout.Column` `area`** — `"left" | "main" | "right"` for sidebar + main + rail; use `className` on `Layout` for gap (`columns` / `gap` deprecated).

## ActionPanel

`actions={[{ key, label, icon, onClick, disabled?, loading? }]}` — icon + label rows; use `useNavigate` inside `onClick` for routing.

## Routing helpers

`Link`, `useNavigate`, `useParams` — same package.

## DescriptionCard

Detail screens: **`data`** + **`fields`** render a responsive key/value grid.

| Prop                  | Notes                                                                  |
| --------------------- | ---------------------------------------------------------------------- |
| `data`                | `Record<string, unknown>` — values (dot keys OK, e.g. `customer.name`) |
| `fields`              | `FieldConfig[]` — each field or `{ type: "divider" }`                  |
| `columns`             | `2` \| `3` (default) \| `4`                                            |
| `className` / `style` | Card container                                                         |

**Field config** — `key`, `label`, optional `type`, `meta`, `emptyBehavior` (`"dash"` \| `"hide"`).

| `type` (default `text`) | Role / typical `meta`                                         |
| ----------------------- | ------------------------------------------------------------- |
| **text**                | `copyable`, `truncateLines`                                   |
| **badge**               | `badgeVariantMap: { [value]: variant }`                       |
| **money**               | `currencyKey` — key in `data` for ISO currency code           |
| **date**                | `dateFormat`: `short` \| `medium` \| `long` \| `relative`     |
| **link**                | `hrefKey`, `external?`                                        |
| **address**             | Value = `{ street, city, state, zip, … }` object              |
| **reference**           | `referenceIdKey`, `referenceUrlPattern` e.g. `/invoices/{id}` |

## Button / Link

Use **`render`**, not Radix `asChild`:

```tsx
<Button render={<Link to="create" />}>Create</Button>
```

Variants: `default` | `destructive` | `outline` | `secondary` | `ghost` | `link`. Sizes: `default` | `sm` | `lg` | `icon`.

## Input

Native input props; works with RHF `FormControl` + spread `field`.

## Table

```tsx
<Table.Root>
  <Table.Header>
    <Table.Row>
      <Table.Head />
    </Table.Row>
  </Table.Header>
  <Table.Body>
    <Table.Row>
      <Table.Cell />
    </Table.Row>
  </Table.Body>
</Table.Root>
```

Also `Footer`, `Caption`. Wrapper: `containerClassName`; inner table: `className`.

## Dialog / Sheet / Tooltip

Compound `*.Root`, `*.Content`, etc. Triggers: **`render={<Button />}`** (or `Link` pattern as needed).

## Menu

`Menu.Root` → `Trigger` → `Content` → `Item` / `Separator` / checkbox & radio items; nested: `SubmenuRoot` / `SubmenuTrigger`.

## Select / Combobox / Autocomplete

| Component        | Use case                                  | Extras                           |
| ---------------- | ----------------------------------------- | -------------------------------- |
| **Select**       | `items`, `placeholder`, `onValueChange`   | `Select.Async`                   |
| **Combobox**     | Searchable; `items`; multi / creatable    | `Combobox.Async`, `onCreateItem` |
| **Autocomplete** | Typed string + suggestions (value = text) | `Autocomplete.Async`             |

**`.Parts`** on each — low-level `Root`, `Trigger`, `Content`, …; hooks `useFilter`, `useAsync`, `useCreatable` for custom UIs.
