@aircall/ds 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +31 -0
  2. package/dist/globals.css +1 -1
  3. package/dist/index.d.ts +28 -28
  4. package/dist/index.js +1 -1
  5. package/package.json +12 -2
  6. package/skills/aircall-ds/migrate-icons/SKILL.md +346 -0
  7. package/skills/aircall-ds/migrate-tractor/SKILL.md +314 -0
  8. package/skills/aircall-ds/migrate-tractor/accordion/SKILL.md +276 -0
  9. package/skills/aircall-ds/migrate-tractor/alert/SKILL.md +225 -0
  10. package/skills/aircall-ds/migrate-tractor/avatar/SKILL.md +272 -0
  11. package/skills/aircall-ds/migrate-tractor/badge/SKILL.md +274 -0
  12. package/skills/aircall-ds/migrate-tractor/button/SKILL.md +277 -0
  13. package/skills/aircall-ds/migrate-tractor/card/SKILL.md +278 -0
  14. package/skills/aircall-ds/migrate-tractor/combobox/SKILL.md +346 -0
  15. package/skills/aircall-ds/migrate-tractor/data-table/SKILL.md +333 -0
  16. package/skills/aircall-ds/migrate-tractor/dialog/SKILL.md +206 -0
  17. package/skills/aircall-ds/migrate-tractor/divider/SKILL.md +226 -0
  18. package/skills/aircall-ds/migrate-tractor/dropdown-menu/SKILL.md +266 -0
  19. package/skills/aircall-ds/migrate-tractor/dropzone/SKILL.md +338 -0
  20. package/skills/aircall-ds/migrate-tractor/form-and-field/SKILL.md +325 -0
  21. package/skills/aircall-ds/migrate-tractor/gauge/SKILL.md +248 -0
  22. package/skills/aircall-ds/migrate-tractor/input/SKILL.md +261 -0
  23. package/skills/aircall-ds/migrate-tractor/item/SKILL.md +298 -0
  24. package/skills/aircall-ds/migrate-tractor/link/SKILL.md +263 -0
  25. package/skills/aircall-ds/migrate-tractor/popover/SKILL.md +214 -0
  26. package/skills/aircall-ds/migrate-tractor/select/SKILL.md +245 -0
  27. package/skills/aircall-ds/migrate-tractor/sheet-vs-drawer/SKILL.md +272 -0
  28. package/skills/aircall-ds/migrate-tractor/skeleton/SKILL.md +190 -0
  29. package/skills/aircall-ds/migrate-tractor/styling/SKILL.md +421 -0
  30. package/skills/aircall-ds/migrate-tractor/tabs/SKILL.md +250 -0
  31. package/skills/aircall-ds/migrate-tractor/toast/SKILL.md +322 -0
  32. package/skills/aircall-ds/migrate-tractor/tooltip/SKILL.md +204 -0
  33. package/skills/aircall-ds/migrate-tractor/tree/SKILL.md +346 -0
  34. package/skills/aircall-ds/setup/SKILL.md +347 -0
@@ -0,0 +1,214 @@
1
+ ---
2
+ name: aircall-ds/migrate-tractor/popover
3
+ description: >
4
+ Migrate Tractor Popover (single-component, content + placement props) to the
5
+ @aircall/ds Popover compound (Popover, PopoverTrigger, PopoverContent, PopoverHeader,
6
+ PopoverTitle, PopoverDescription). Load when a file imports Popover from @aircall/tractor.
7
+ type: sub-skill
8
+ library: aircall-ds
9
+ library_version: "0.13.0"
10
+ requires:
11
+ - aircall-ds/setup
12
+ - aircall-ds/migrate-tractor
13
+ sources:
14
+ - "aircall/hydra:docs/migration-guides/tractor-to-ds/recipes/popover.md"
15
+ ---
16
+
17
+ This skill builds on aircall-ds/migrate-tractor. Apply all cross-cutting rules from that skill (prop renames, `render` prop, data attributes) before the popover-specific steps below.
18
+
19
+ ## 1. Component mapping
20
+
21
+ Tractor `Popover` was a single component: you passed a `content` prop (the panel) and a `placement` prop (positioning) alongside the trigger child. DS uses a Base UI compound where each concern is a named part.
22
+
23
+ | Tractor | @aircall/ds | Role |
24
+ | --- | --- | --- |
25
+ | `<Popover>` | `<Popover>` | State owner (open, onOpenChange) |
26
+ | _(trigger child of `<Popover>`)_ | `<PopoverTrigger>` | The anchor element that opens the panel |
27
+ | `content={…}` prop | `<PopoverContent>` | The floating panel; children replace the prop |
28
+ | `placement="bottom-start"` | `side="bottom" align="start"` on `<PopoverContent>` | Split into two props |
29
+ | _(no equivalent)_ | `<PopoverHeader>` | Optional structured header wrapper |
30
+ | _(no equivalent)_ | `<PopoverTitle>` | Accessible title inside the panel |
31
+ | _(no equivalent)_ | `<PopoverDescription>` | Accessible description inside the panel |
32
+
33
+ ## 2. Verified DS exports (`packages/ds/src/index.ts`)
34
+
35
+ ```
36
+ Popover, PopoverContent, PopoverDescription,
37
+ PopoverHeader, PopoverTitle, PopoverTrigger
38
+ ```
39
+
40
+ ## 3. Imports
41
+
42
+ ```tsx
43
+ import {
44
+ Popover,
45
+ PopoverContent,
46
+ PopoverDescription,
47
+ PopoverHeader,
48
+ PopoverTitle,
49
+ PopoverTrigger,
50
+ Button,
51
+ } from '@aircall/ds';
52
+ ```
53
+
54
+ ## 4. Before / After
55
+
56
+ ### Uncontrolled (most common)
57
+
58
+ ```tsx
59
+ // Before
60
+ import { Popover, Button } from '@aircall/tractor';
61
+
62
+ <Popover
63
+ placement="bottom-start"
64
+ content={
65
+ <div>
66
+ <strong>Title</strong>
67
+ <p>A short description.</p>
68
+ <p>Body content.</p>
69
+ </div>
70
+ }
71
+ >
72
+ <Button variant="secondary" mode="outline">Open</Button>
73
+ </Popover>
74
+
75
+ // After
76
+ import { Popover, PopoverContent, PopoverHeader, PopoverTitle, PopoverDescription, PopoverTrigger, Button } from '@aircall/ds';
77
+
78
+ <Popover>
79
+ <PopoverTrigger render={<Button variant="outline" />}>Open</PopoverTrigger>
80
+ <PopoverContent side="bottom" align="start">
81
+ <PopoverHeader>
82
+ <PopoverTitle>Title</PopoverTitle>
83
+ <PopoverDescription>A short description.</PopoverDescription>
84
+ </PopoverHeader>
85
+ <p>Body content.</p>
86
+ </PopoverContent>
87
+ </Popover>
88
+ ```
89
+
90
+ ### Controlled (replaces `isOpen` / `onClose`)
91
+
92
+ ```tsx
93
+ // Before
94
+ import { Popover, Button } from '@aircall/tractor';
95
+
96
+ <Popover
97
+ isOpen={isOpen}
98
+ onClose={() => setIsOpen(false)}
99
+ placement="top"
100
+ content={<p>Settings panel</p>}
101
+ >
102
+ <Button variant="primary">Settings</Button>
103
+ </Popover>
104
+
105
+ // After
106
+ import { Popover, PopoverContent, PopoverTrigger, Button } from '@aircall/ds';
107
+
108
+ <Popover open={isOpen} onOpenChange={setIsOpen}>
109
+ <PopoverTrigger render={<Button variant="default" />}>Settings</PopoverTrigger>
110
+ <PopoverContent side="top">
111
+ <p>Settings panel</p>
112
+ </PopoverContent>
113
+ </Popover>
114
+ ```
115
+
116
+ Key changes:
117
+ - `isOpen` → `open`; `onClose` → `onOpenChange` (receives the new boolean)
118
+ - `content={…}` prop is removed — panel content is children of `PopoverContent`
119
+ - Tractor's trigger child becomes `<PopoverTrigger render={<Button />}>` — label goes on `PopoverTrigger`, not inside the `render` element
120
+ - `placement="bottom-start"` splits into `side="bottom" align="start"` on `PopoverContent`
121
+
122
+ ## 5. Positioning
123
+
124
+ Tractor's single `placement` string maps to two props on `PopoverContent`:
125
+
126
+ | Tractor `placement` | DS `side` | DS `align` |
127
+ | --- | --- | --- |
128
+ | `"bottom"` | `"bottom"` | `"center"` (default) |
129
+ | `"bottom-start"` | `"bottom"` | `"start"` |
130
+ | `"bottom-end"` | `"bottom"` | `"end"` |
131
+ | `"top"` | `"top"` | `"center"` (default) |
132
+ | `"top-start"` | `"top"` | `"start"` |
133
+ | `"top-end"` | `"top"` | `"end"` |
134
+ | `"left"` | `"left"` | `"center"` (default) |
135
+ | `"right"` | `"right"` | `"center"` (default) |
136
+
137
+ Defaults when omitted: `side="bottom"`, `align="center"`, `sideOffset={4}`. Fine-tune gap with `sideOffset` / `alignOffset`.
138
+
139
+ ## 6. Panel surface
140
+
141
+ `PopoverContent` ships its own surface styles — `rounded-md`, `ring-1`, `bg-popover`, `p-4`, `shadow-md`. Do not re-add a wrapper `<div>` with manual padding, background, or border inside `PopoverContent`; it will double the spacing and styling.
142
+
143
+ ---
144
+
145
+ ## 7. Common mistakes
146
+
147
+ ### Mistake 1 — Keeping `content` as a prop instead of children
148
+
149
+ ```tsx
150
+ // Wrong — content prop does not exist on DS Popover
151
+ <Popover content={<p>Body content.</p>}>
152
+ <PopoverTrigger render={<Button variant="outline" />}>Open</PopoverTrigger>
153
+ </Popover>
154
+
155
+ // Correct — panel content is children of PopoverContent
156
+ <Popover>
157
+ <PopoverTrigger render={<Button variant="outline" />}>Open</PopoverTrigger>
158
+ <PopoverContent>
159
+ <p>Body content.</p>
160
+ </PopoverContent>
161
+ </Popover>
162
+ ```
163
+
164
+ The DS compound has no `content` prop on `Popover`. Passing it silently does nothing — the popover renders with an empty panel. Move the JSX into children of `PopoverContent`.
165
+
166
+ Source: `packages/ds/src/components/popover.tsx`
167
+
168
+ ---
169
+
170
+ ### Mistake 2 — Putting the label inside the `render` Button instead of `PopoverTrigger`
171
+
172
+ ```tsx
173
+ // Wrong — label ends up inside Button's children prop, not managed by PopoverTrigger
174
+ <PopoverTrigger render={<Button variant="outline">Open</Button>} />
175
+
176
+ // Correct — label is a child of PopoverTrigger; it is merged into the rendered Button
177
+ <PopoverTrigger render={<Button variant="outline" />}>Open</PopoverTrigger>
178
+ ```
179
+
180
+ `PopoverTrigger` uses the Base UI `render` prop pattern: it clones the element passed as `render` and merges its own open/close handler. The visible label must be the child of `PopoverTrigger`, not of the inner Button — otherwise it is ignored and the button renders empty.
181
+
182
+ Source: `packages/ds/src/components/popover.tsx`
183
+
184
+ ---
185
+
186
+ ### Mistake 3 — Passing a single `placement` string instead of `side` + `align`
187
+
188
+ ```tsx
189
+ // Wrong — placement is a Tractor prop; DS PopoverContent does not accept it
190
+ <PopoverContent placement="bottom-start">…</PopoverContent>
191
+
192
+ // Correct — split into side and align
193
+ <PopoverContent side="bottom" align="start">…</PopoverContent>
194
+ ```
195
+
196
+ The DS `PopoverContent` accepts `side` and `align` as separate props (sourced from `PopoverPrimitive.Positioner`). A `placement` string is silently ignored, and the panel falls back to the default `side="bottom" align="center"` — which may look correct until the layout shifts.
197
+
198
+ Source: `packages/ds/src/components/popover.tsx`
199
+
200
+ ---
201
+
202
+ ### Mistake 4 — Using `isOpen` / `onClose` instead of `open` / `onOpenChange`
203
+
204
+ ```tsx
205
+ // Wrong — isOpen and onClose are Tractor props; DS Popover ignores them
206
+ <Popover isOpen={isOpen} onClose={() => setIsOpen(false)}>…</Popover>
207
+
208
+ // Correct — controlled via open and onOpenChange
209
+ <Popover open={isOpen} onOpenChange={setIsOpen}>…</Popover>
210
+ ```
211
+
212
+ DS `Popover` follows the Base UI controlled pattern: `open` (boolean) and `onOpenChange` (callback receiving the new boolean). `onClose` is not called — the popover stays open permanently when `onClose` is the only handler provided.
213
+
214
+ Source: `packages/ds/src/components/popover.tsx`
@@ -0,0 +1,245 @@
1
+ ---
2
+ name: aircall-ds/migrate-tractor/select
3
+ description: >
4
+ Migrate Tractor Select to the @aircall/ds Select compound. Load when a file
5
+ imports Select from @aircall/tractor. Covers the compound parts, the nullable
6
+ onValueChange, and the Group-wraps-Label rule.
7
+ type: sub-skill
8
+ library: aircall-ds
9
+ library_version: "0.13.0"
10
+ requires:
11
+ - aircall-ds/setup
12
+ - aircall-ds/migrate-tractor
13
+ sources:
14
+ - "aircall/hydra:docs/migration-guides/tractor-to-ds/recipes/select.md"
15
+ ---
16
+
17
+ This skill builds on aircall-ds/migrate-tractor. Apply all cross-cutting rules from that skill (prop renames, `render` prop, data attributes) before the select-specific steps below.
18
+
19
+ ## 1. Component mapping
20
+
21
+ Tractor `Select` was a flat component with `SelectOption` children. DS uses a compound structure where each visual slot is a named part:
22
+
23
+ | Tractor | DS compound part | Role |
24
+ | --- | --- | --- |
25
+ | `<Select>` | `<Select>` | State owner (value, open, disabled) |
26
+ | _(no equivalent)_ | `<SelectTrigger>` | Visible field / button |
27
+ | _(no equivalent)_ | `<SelectValue>` | Renders current label or placeholder |
28
+ | _(no equivalent)_ | `<SelectContent>` | Dropdown container |
29
+ | `<SelectOption>` | `<SelectItem>` | Individual option |
30
+ | _(no equivalent)_ | `<SelectGroup>` | Required wrapper around a labelled section |
31
+ | _(no equivalent)_ | `<SelectLabel>` | Section heading inside a `SelectGroup` |
32
+
33
+ ## 2. Verified DS exports (`packages/ds/src/index.ts`)
34
+
35
+ ```
36
+ Select, SelectContent, SelectGroup, SelectItem,
37
+ SelectLabel, SelectTrigger, SelectValue,
38
+ SelectScrollDownButton, SelectScrollUpButton, SelectSeparator,
39
+ selectTriggerVariants
40
+ ```
41
+
42
+ All names listed in the Before/After section below exist in the published public API.
43
+
44
+ ## 3. Imports
45
+
46
+ ```tsx
47
+ import {
48
+ Select,
49
+ SelectContent,
50
+ SelectGroup,
51
+ SelectItem,
52
+ SelectLabel,
53
+ SelectTrigger,
54
+ SelectValue,
55
+ } from '@aircall/ds';
56
+ ```
57
+
58
+ ## 4. Prop renames
59
+
60
+ | Tractor prop | DS prop | Notes |
61
+ | --- | --- | --- |
62
+ | `onChange` | `onValueChange` | Signature change — see Mistake 1 below |
63
+ | `placeholder` on `<Select>` | `placeholder` on `<SelectValue>` | Moved to the value part |
64
+ | `selectedOption` / `value` | `value` | Unchanged name, same position |
65
+
66
+ ## 5. Before / After
67
+
68
+ ### Before (Tractor)
69
+
70
+ ```tsx
71
+ import { Select, SelectOption } from '@aircall/tractor';
72
+
73
+ <Select
74
+ value={channelType}
75
+ onChange={(value) => setChannelType(value)}
76
+ placeholder="Pick a channel"
77
+ >
78
+ <SelectOption value="phone">Phone</SelectOption>
79
+ <SelectOption value="email">Email</SelectOption>
80
+ <SelectOption value="sms">SMS</SelectOption>
81
+ </Select>
82
+ ```
83
+
84
+ ### After (DS)
85
+
86
+ ```tsx
87
+ import {
88
+ Select,
89
+ SelectContent,
90
+ SelectItem,
91
+ SelectTrigger,
92
+ SelectValue,
93
+ } from '@aircall/ds';
94
+
95
+ <Select
96
+ value={channelType}
97
+ onValueChange={(value: string | null) => {
98
+ if (value !== null) setChannelType(value);
99
+ }}
100
+ >
101
+ <SelectTrigger>
102
+ <SelectValue placeholder="Pick a channel" />
103
+ </SelectTrigger>
104
+ <SelectContent>
105
+ <SelectItem value="phone">Phone</SelectItem>
106
+ <SelectItem value="email">Email</SelectItem>
107
+ <SelectItem value="sms">SMS</SelectItem>
108
+ </SelectContent>
109
+ </Select>
110
+ ```
111
+
112
+ ## 6. With sections (Labels)
113
+
114
+ When grouping options under a label, `SelectLabel` **must** be inside a `SelectGroup` along with its items. Direct children of `SelectContent` are not accessibility-correct in Base UI.
115
+
116
+ ```tsx
117
+ import {
118
+ Select,
119
+ SelectContent,
120
+ SelectGroup,
121
+ SelectItem,
122
+ SelectLabel,
123
+ SelectTrigger,
124
+ SelectValue,
125
+ } from '@aircall/ds';
126
+
127
+ <Select value={value} onValueChange={setValue}>
128
+ <SelectTrigger>
129
+ <SelectValue placeholder="Pick a channel" />
130
+ </SelectTrigger>
131
+ <SelectContent>
132
+ <SelectGroup>
133
+ <SelectLabel>Voice</SelectLabel>
134
+ <SelectItem value="phone">Phone</SelectItem>
135
+ <SelectItem value="sms">SMS</SelectItem>
136
+ </SelectGroup>
137
+ <SelectGroup>
138
+ <SelectLabel>Written</SelectLabel>
139
+ <SelectItem value="email">Email</SelectItem>
140
+ </SelectGroup>
141
+ </SelectContent>
142
+ </Select>
143
+ ```
144
+
145
+ ## 7. Size
146
+
147
+ `SelectTrigger` accepts a `size` prop:
148
+
149
+ | Value | Height | Use for |
150
+ | --- | --- | --- |
151
+ | `"default"` | 40px | Any Tractor `regular` or `small` size |
152
+ | `"sm"` | 32px | Compact layouts |
153
+
154
+ ## 8. When to use Combobox instead
155
+
156
+ If users need to **search or filter** the options list, use `Combobox` rather than `Select`. Plain `Select` is for short, fixed-enum lists where no search is needed.
157
+
158
+ ## 9. Common Mistakes
159
+
160
+ ### Mistake 1 — Not widening the `onValueChange` handler for `null`
161
+
162
+ ```tsx
163
+ // Wrong
164
+ <Select onValueChange={(value: string) => setChannelType(value)}>
165
+ ...
166
+ </Select>
167
+
168
+ // Correct
169
+ <Select
170
+ onValueChange={(value: string | null) => {
171
+ if (value !== null) setChannelType(value);
172
+ }}
173
+ >
174
+ ...
175
+ </Select>
176
+ ```
177
+
178
+ The DS `onValueChange` callback receives `string | null` — `null` is emitted when the selection is cleared. Typing the parameter as `string` causes a TypeScript error; omitting the null guard causes a runtime `null` to propagate into state that expects a string.
179
+ Source: `packages/ds/src/components/select.tsx`
180
+
181
+ ---
182
+
183
+ ### Mistake 2 — Placing `SelectLabel` as a direct child of `SelectContent`
184
+
185
+ ```tsx
186
+ // Wrong
187
+ <SelectContent>
188
+ <SelectLabel>Voice</SelectLabel> {/* label outside a SelectGroup */}
189
+ <SelectItem value="phone">Phone</SelectItem>
190
+ </SelectContent>
191
+
192
+ // Correct
193
+ <SelectContent>
194
+ <SelectGroup>
195
+ <SelectLabel>Voice</SelectLabel> {/* label always inside a SelectGroup */}
196
+ <SelectItem value="phone">Phone</SelectItem>
197
+ </SelectGroup>
198
+ </SelectContent>
199
+ ```
200
+
201
+ In Base UI, `SelectLabel` must be a sibling of its items inside a `SelectGroup`. A bare `SelectLabel` in `SelectContent` is not accessibility-correct — the group association that screen readers rely on is missing, and the label may render incorrectly.
202
+ Source: `packages/ds/src/components/select.tsx`
203
+
204
+ ---
205
+
206
+ ### Mistake 3 — Keeping `placeholder` on `<Select>` instead of `<SelectValue>`
207
+
208
+ ```tsx
209
+ // Wrong
210
+ <Select placeholder="Pick a channel">
211
+ <SelectTrigger>
212
+ <SelectValue />
213
+ </SelectTrigger>
214
+ ...
215
+ </Select>
216
+
217
+ // Correct
218
+ <Select>
219
+ <SelectTrigger>
220
+ <SelectValue placeholder="Pick a channel" />
221
+ </SelectTrigger>
222
+ ...
223
+ </Select>
224
+ ```
225
+
226
+ Tractor accepted `placeholder` on the root `<Select>`. In the DS compound, the `placeholder` prop lives on `<SelectValue>` — it is silently ignored when placed on `<Select>`, so no placeholder text appears in the trigger.
227
+ Source: `packages/ds/src/components/select.tsx`
228
+
229
+ ---
230
+
231
+ ### Mistake 4 — Using `SelectOption` instead of `SelectItem`
232
+
233
+ ```tsx
234
+ // Wrong
235
+ import { Select, SelectOption } from '@aircall/tractor';
236
+ // SelectOption does not exist in @aircall/ds
237
+
238
+ // Correct
239
+ import { Select, SelectItem } from '@aircall/ds';
240
+
241
+ <SelectItem value="phone">Phone</SelectItem>
242
+ ```
243
+
244
+ Tractor used `SelectOption` for each choice. The DS compound uses `SelectItem`. `SelectOption` is not exported from `@aircall/ds` — importing it will cause a build error.
245
+ Source: `packages/ds/src/components/select.tsx`