@aircall/blocks
Version:
Aircall Blocks — higher-level UI compositions built on @aircall/ds
177 lines (142 loc) • 4.4 kB
Markdown
---
name: aircall-blocks/migrate-dashboard/toggle-row
description: >
Migrate @dashboard/library ToggleRow to @aircall/ds Field + Switch composition.
Load when a file imports ToggleRow from @dashboard/library.
type: sub-skill
library: aircall-blocks
requires:
- aircall-blocks/setup
- aircall-blocks/migrate-dashboard
sources:
- "aircall/hydra:packages/ds/src/index.ts"
---
This skill builds on aircall-blocks/migrate-dashboard.
## 1. Key premise
`ToggleRow` was a single component. The DS replacement is a **composition** of
`Field` (orientation="horizontal") + `Switch` + `FieldLabel` + optional `FieldDescription`.
There is no 1:1 component — you must assemble the parts.
## 2. Verified DS exports (`packages/ds/src/index.ts`)
```
Field, FieldLabel, FieldDescription, FieldTitle, FieldContent
Switch
Spinner
```
## 3. Imports
```tsx
import { Field, FieldDescription, FieldLabel, Spinner, Switch } from '@aircall/ds';
```
## 4. Prop mapping
| `ToggleRow` prop | DS equivalent |
| --- | --- |
| `label` | `<FieldLabel>` inside `<Field orientation="horizontal">` |
| `description` | `<FieldDescription>` next to `<FieldLabel>` |
| `value` | `<Switch checked={…}>` or `<Switch defaultChecked>` |
| `onChange` | `<Switch onCheckedChange={…}>` |
| `disabled` | `<Switch disabled>` |
| `loading` | Replace `<Switch>` with a `<Spinner>` in a `data-slot="switch"` wrapper (see §6) |
| `data-test` | Pass to `<Switch>` directly |
## 5. Structure
```tsx
<Field orientation="horizontal">
<Switch /> {/* or Spinner placeholder when loading */}
<FieldLabel>Label text</FieldLabel>
</Field>
```
With description:
```tsx
<Field orientation="horizontal" className="max-w-sm">
<Switch />
<div className="flex flex-col gap-0.5">
<FieldLabel>Label text</FieldLabel>
<FieldDescription>Supporting description.</FieldDescription>
</div>
</Field>
```
## 6. Before / After examples
### 6a. Label only
**Before:**
```tsx
import { ToggleRow } from '@dashboard/library';
<ToggleRow
label="Enable notifications"
value={enabled}
onChange={setEnabled}
/>
```
**After:**
```tsx
import { Field, FieldLabel, Switch } from '@aircall/ds';
<Field orientation="horizontal">
<Switch checked={enabled} onCheckedChange={setEnabled} />
<FieldLabel>Enable notifications</FieldLabel>
</Field>
```
### 6b. With description
**Before:**
```tsx
<ToggleRow
label="Recording"
description="Automatically record all inbound calls."
value={recording}
onChange={setRecording}
/>
```
**After:**
```tsx
import { Field, FieldDescription, FieldLabel, Switch } from '@aircall/ds';
<Field orientation="horizontal" className="max-w-sm">
<Switch checked={recording} onCheckedChange={setRecording} />
<div className="flex flex-col gap-0.5">
<FieldLabel>Recording</FieldLabel>
<FieldDescription>Automatically record all inbound calls.</FieldDescription>
</div>
</Field>
```
### 6c. Loading state
`ToggleRow` accepted a `loading` prop that replaced the toggle with a spinner.
In the DS, swap the `Switch` for a `Spinner` placed inside a `data-slot="switch"`
wrapper so Field's horizontal layout still aligns correctly:
**Before:**
```tsx
<ToggleRow label="Syncing contacts" loading={true} />
```
**After:**
```tsx
import { Field, FieldLabel, Spinner } from '@aircall/ds';
<Field orientation="horizontal">
<div data-slot="switch" className="grid h-6 w-10 shrink-0 place-items-center">
<Spinner size="default" />
</div>
<FieldLabel>Syncing contacts</FieldLabel>
</Field>
```
## 7. Common mistakes
### Mistake 1: Using `Switch` without `Field`
```tsx
// WRONG — no layout wrapper; label and switch won't align
<Switch checked={value} onCheckedChange={onChange} />
<label>Enable notifications</label>
```
```tsx
// CORRECT — Field orientation="horizontal" provides the flex row layout
<Field orientation="horizontal">
<Switch checked={value} onCheckedChange={onChange} />
<FieldLabel>Enable notifications</FieldLabel>
</Field>
```
### Mistake 2: Putting description inside FieldLabel
```tsx
// WRONG — FieldLabel is for the label text only
<FieldLabel>
Recording
<FieldDescription>…</FieldDescription>
</FieldLabel>
```
```tsx
// CORRECT — wrap label + description in a flex column div
<div className="flex flex-col gap-0.5">
<FieldLabel>Recording</FieldLabel>
<FieldDescription>…</FieldDescription>
</div>
```