Generated from `@cosmoops/connect-sdk/ui`'s TypeScript source and its own doc comments - see [Reference](/docs/reference) for the other entry points. Regenerated on every deploy; don't hand-edit.

## Interfaces

### Interface: ConnectEmptyStateProps [#interface-connectemptystateprops]

#### Properties

| Property | Type | Description |
| ------ | ------ | ------ |
| `icon?` | `ReactNode` | Rendered at `size-8`. Any icon element - lucide, an SVG, a glyph. |
| `title` | `ReactNode` | What is absent, in the user's words. One line. |
| `description?` | `ReactNode` | - |
| `action?` | `ReactNode` | The one control that resolves the emptiness - "New contact" for a list that has never had anything in it, "Clear filter" for one whose contents are merely hidden. |
| `variant?` | `"card"` \| `"dashed"` \| `"plain"` | - |
| `className?` | `string` | - |

***

### Interface: ConnectPageHeaderProps [#interface-connectpageheaderprops]

#### Properties

| Property | Type | Description |
| ------ | ------ | ------ |
| `title` | `ReactNode` | - |
| `description?` | `ReactNode` | - |
| `action?` | `ReactNode` | Rendered opposite the title. Keep it to one control - a page has one primary action, and a second here has nothing to align against. |
| `clamp?` | `boolean` | Set `false` when the description carries a link that must stay readable on a phone. |
| `className?` | `string` | - |

***

### Interface: ConnectPageShellProps [#interface-connectpageshellprops]

#### Properties

| Property | Type | Description |
| ------ | ------ | ------ |
| `title?` | `ReactNode` | - |
| `description?` | `ReactNode` | - |
| `action?` | `ReactNode` | - |
| `clamp?` | `boolean` | - |
| `above?` | `ReactNode` | Rendered above the header - a breadcrumb trail, a back link, a banner. |
| `className?` | `string` | Merged onto the page root, so a utility here beats the default rather than sitting beside it - `className="space-y-8"` really does widen the page gap. See `cn`. |
| `transition?` | `boolean` | The route transition - the outgoing page fades out, the arriving one fades in and rises. On by default; pass `false` where a host already animates its routes, or the two play over each other. See RouteTransition. |
| `children?` | `ReactNode` | - |

***

### Interface: ConnectSectionProps [#interface-connectsectionprops]

#### Properties

| Property | Type | Description |
| ------ | ------ | ------ |
| `title` | `ReactNode` | - |
| `description?` | `ReactNode` | What the block is for. Omit when the title says everything. |
| `action?` | `ReactNode` | Rendered opposite the title. One control - a section has one action. |
| `titleId?` | `string` | Set to reference the heading from an `aria-labelledby` in the body. |
| `className?` | `string` | - |
| `bodyClassName?` | `string` | - |
| `children?` | `ReactNode` | - |

***

### Interface: ConnectSettingRowProps [#interface-connectsettingrowprops]

#### Properties

| Property | Type | Description |
| ------ | ------ | ------ |
| `title` | `ReactNode` | - |
| `description?` | `ReactNode` | - |
| `action?` | `ReactNode` | The control this row is about - a switch, a button, a value with an edit link. |
| `children?` | `ReactNode` | Rendered under both, full width - a validation message, or a nested field the row reveals. |
| `className?` | `string` | - |

***

### Interface: ConnectStatusPresentation\<TStatus\> [#interface-connectstatuspresentation]

How one domain's status union is presented: a tone and a human label per
member.

Both are **total** `Record`s, and that is the load-bearing property - adding
a member to the status union fails the type gate until it has been given a
presentation. A loose `Record<string, …>` map silently renders the new
status as `undefined`.

#### Type Parameters

| Type Parameter |
| ------ |
| `TStatus` *extends* `string` |

#### Properties

| Property | Modifier | Type |
| ------ | ------ | ------ |
| `tone` | `readonly` | `Readonly`\<`Record`\<`TStatus`, [`ConnectStatusTone`](#type-alias-connectstatustone)\>\> |
| `label` | `readonly` | `Readonly`\<`Record`\<`TStatus`, `string`\>\> |
## Type Aliases

### Type Alias: ConnectStatusTone [#type-alias-connectstatustone]

```ts
type ConnectStatusTone = "success" | "warning" | "danger" | "accent" | "default";
```

The closed set of tones a status may resolve to.

Deliberately five, and deliberately narrower than HeroUI's `Chip` colour
union: a status is either fine, needs attention, is broken, is in progress,
or is inert. A sixth tone would have to mean one of those five again, which
is where hand-written status chips start disagreeing with each other.
## Variables

### Variable: cn [#variable-cn]

```ts
const cn: <T>(...classnames: T) => CnReturn;
```

Combines class names and merges conflicting Tailwind classes (default config).

#### Type Parameters

| Type Parameter |
| ------ |
| `T` *extends* `CnOptions` |

#### Parameters

| Parameter | Type |
| ------ | ------ |
| ...`classnames` | `T` |

#### Returns

`CnReturn`
## Functions

### Function: ConnectEmptyState() [#function-connectemptystate]

```ts
function ConnectEmptyState(__namedParameters: Readonly<ConnectEmptyStateProps>): Element;
```

What a list, grid or table shows when it has nothing to show.

**The two empty states are different facts and the copy must say so.** "You
have no contacts" and "no contacts match this filter" call for different
words and a different action - create the thing, versus undo the filter
hiding it. Both render through here; the caller decides which by what it
passes as `action`. Getting this wrong costs a user real time: an
unfiltered-looking empty state in front of a filtered list reads as data
loss.

`variant` chooses the container by what the state stands *in*: `card` (the
default), `dashed` for a region that will be filled in place - a file grid,
a board column - where the outline is what says "things appear here", and
`plain` for a slot already inside a card that would otherwise nest two
borders.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `__namedParameters` | `Readonly`\<[`ConnectEmptyStateProps`](#interface-connectemptystateprops)\> |

#### Returns

`Element`

***

### Function: ConnectPageHeader() [#function-connectpageheader]

```ts
function ConnectPageHeader(__namedParameters: Readonly<ConnectPageHeaderProps>): Element;
```

The title / description / action block a page opens with.

The structure is the point, not the styling. The action is a peer of the
**title**, not of the block, so nothing below the first line can move it -
the common hand-rolled shape puts the action after the description, which
makes the vertical position of a page's primary control a function of how
long someone wrote the paragraph above it. On a phone that pushes it most of
a thumb's reach down the screen.

Mobile-first, and the two axes are separate decisions: the title row is a
`justify-between` at every width (title left, action right, where a thumb
expects it), while the description is clamped to two lines on a phone and
released from `sm` up.

An `h2`, because the document's `h1` is the application itself.

No hooks and no state, so this renders from a Server Component - which is
why it lives in `@cosmoops/connect-sdk/ui` rather than `/client`.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `__namedParameters` | `Readonly`\<[`ConnectPageHeaderProps`](#interface-connectpageheaderprops)\> |

#### Returns

`Element`

***

### Function: ConnectPageShell() [#function-connectpageshell]

```ts
function ConnectPageShell(__namedParameters: Readonly<ConnectPageShellProps>): Element;
```

The frame a page opens with: its vertical rhythm, its header, and the
suspended regions beneath.

**The header is a prop, so it renders in the static shell** - above and
outside every `<Suspense>` boundary. That is the one bug this component
exists to make unrepresentable: rendering the header inside the async child
makes a page's own title wait on a data read, and under Next's partial
prefetching the route's shared App Shell loses it as well. There is no
arrangement of `children` that reaches the header slot.

A detail route is the honest exception, and it has its own door:
`ConnectPageShell.Header` renders the identical header from inside an async
child, for a page whose title is data it does not have yet. Pair it with a
skeleton header in the fallback. The rule is that a *static* title must
never be made to wait, not that every title can be static.

`space-y-5` is the page gap, owned here so it has exactly one definition.

**It is also where the route transition lives**, because it is the one
thing every page opens with. A transition has to wrap the *page*: a layout
persists across navigation, so its enter and exit never fire, and a
`template.tsx` remounts its subtree on every navigation, discarding the
form drafts and scroll positions Next's `<Activity>` keeps. Where a layout
draws the shell instead - a record with tabs - entering and leaving the
record animates and switching tabs does not, which is right: a tab is the
same place. `default="none"` keeps it still during anything else - a
filter written to the URL, a `router.refresh()` after a save. The
animations are `connect-page-enter`/`connect-page-exit` in `theme.css`.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `__namedParameters` | `Readonly`\<[`ConnectPageShellProps`](#interface-connectpageshellprops)\> |

#### Returns

`Element`

***

### Function: ConnectSection() [#function-connectsection]

```ts
function ConnectSection(__namedParameters: Readonly<ConnectSectionProps>): Element;
```

One titled block inside a page: a card, its heading, what it is for, and the
one control that acts on it.

The heading is an `h3` - `ConnectPageHeader` renders the page title as an
`h2`, so a block *inside* a page is a level below it. Hand-rolled sections
reliably use `h2`, which makes every settings block a sibling of the page it
sits in and flattens the outline a screen reader announces.

As in the page header, the action is a peer of the title rather than of the
block, so its position does not move with the length of the description.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `__namedParameters` | `Readonly`\<[`ConnectSectionProps`](#interface-connectsectionprops)\> |

#### Returns

`Element`

***

### Function: ConnectSettingRow() [#function-connectsettingrow]

```ts
function ConnectSettingRow(__namedParameters: Readonly<ConnectSettingRowProps>): Element;
```

One labelled setting inside a `ConnectSection`.

Stacks on a phone and goes side-by-side from `sm` up, rather than shrinking
a two-column row until neither column is readable. The control keeps its
intrinsic width so truncation lands on the description.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `__namedParameters` | `Readonly`\<[`ConnectSettingRowProps`](#interface-connectsettingrowprops)\> |

#### Returns

`Element`

***

### Function: ConnectStatusChip() [#function-connectstatuschip]

```ts
function ConnectStatusChip<TStatus>(__namedParameters: Readonly<{
  status: TStatus;
  presentation: ConnectStatusPresentation<TStatus>;
  className?: string;
}>): Element;
```

One status, rendered the way every status should be.

Domain knowledge stays in the domain: each caller exports its own
`ConnectStatusPresentation` next to the union it describes, and this renders
it. A status whose *rendering* carries real logic - a scheduled cancellation
outranking a running trial, say - keeps its own component and calls this for
the final chip. A map cannot express precedence.

#### Type Parameters

| Type Parameter |
| ------ |
| `TStatus` *extends* `string` |

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `__namedParameters` | `Readonly`\<\{ `status`: `TStatus`; `presentation`: [`ConnectStatusPresentation`](#interface-connectstatuspresentation)\<`TStatus`\>; `className?`: `string`; \}\> |

#### Returns

`Element`