@aircall/ds 0.13.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 +94 -33
  4. package/dist/index.js +292 -42
  5. package/package.json +16 -3
  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,276 @@
1
+ ---
2
+ name: aircall-ds/migrate-tractor/accordion
3
+ description: >
4
+ Migrate Tractor Accordion and AccordionSection to the @aircall/ds Accordion
5
+ compound (AccordionItem, AccordionTrigger, AccordionContent). Load when a file
6
+ imports Accordion or AccordionSection 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/accordion.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 accordion-specific steps below.
18
+
19
+ ## 1. Component mapping
20
+
21
+ Tractor `Accordion` accepted `AccordionSection` children that bundled header, chevron, and body in a single component. DS splits each section into three named parts:
22
+
23
+ | Tractor | @aircall/ds |
24
+ | --- | --- |
25
+ | `Accordion` | `Accordion` (state owner) |
26
+ | `AccordionSection` | `AccordionItem` + `AccordionTrigger` + `AccordionContent` |
27
+ | _(built into AccordionSection)_ | `AccordionTrigger` (header + built-in chevron) |
28
+ | _(built into AccordionSection)_ | `AccordionContent` (body panel) |
29
+
30
+ ## 2. Verified DS exports (`packages/ds/src/index.ts`)
31
+
32
+ ```
33
+ Accordion, AccordionItem, AccordionTrigger, AccordionContent
34
+ ```
35
+
36
+ All names used in the Before/After section below exist in the published public API.
37
+
38
+ ## 3. Imports
39
+
40
+ ```tsx
41
+ import {
42
+ Accordion,
43
+ AccordionItem,
44
+ AccordionTrigger,
45
+ AccordionContent,
46
+ } from '@aircall/ds';
47
+ ```
48
+
49
+ ## 4. Prop changes
50
+
51
+ | Tractor | DS | Notes |
52
+ | --- | --- | --- |
53
+ | _(implicit — one open at a time)_ | default (no extra prop needed) | Single-open is the DS default |
54
+ | _(allowMultiple or equivalent)_ | `multiple` on `<Accordion>` | Boolean — allows multiple items open simultaneously |
55
+ | _(section key)_ | `value` on `<AccordionItem>` | Required; `number` or `string`; index works for static lists |
56
+ | _(section disabled)_ | `disabled` on `<AccordionItem>` | Disables the trigger and keeps the panel closed |
57
+ | `defaultExpanded` / open sections | `defaultValue` on `<Accordion>` | Always an array, even in single-open mode: `defaultValue={[0]}` |
58
+ | controlled open | `value` + `onValueChange` on `<Accordion>` | `value` is an array; `onValueChange` receives `(number \| string)[]` |
59
+
60
+ ## 5. Before / After
61
+
62
+ ### Static list (most common)
63
+
64
+ ```tsx
65
+ // Before
66
+ import { Accordion, AccordionSection } from '@aircall/tractor';
67
+
68
+ <Accordion>
69
+ <AccordionSection title="General">
70
+ <p>General settings content.</p>
71
+ </AccordionSection>
72
+ <AccordionSection title="Billing">
73
+ <p>Billing details content.</p>
74
+ </AccordionSection>
75
+ </Accordion>
76
+
77
+ // After
78
+ import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '@aircall/ds';
79
+
80
+ <Accordion defaultValue={[0]}>
81
+ <AccordionItem value={0}>
82
+ <AccordionTrigger>General</AccordionTrigger>
83
+ <AccordionContent>
84
+ <p>General settings content.</p>
85
+ </AccordionContent>
86
+ </AccordionItem>
87
+ <AccordionItem value={1}>
88
+ <AccordionTrigger>Billing</AccordionTrigger>
89
+ <AccordionContent>
90
+ <p>Billing details content.</p>
91
+ </AccordionContent>
92
+ </AccordionItem>
93
+ </Accordion>
94
+ ```
95
+
96
+ Key changes:
97
+ - Each `AccordionSection` becomes three components: `AccordionItem` (identity + state), `AccordionTrigger` (header label), `AccordionContent` (body)
98
+ - `title` prop on `AccordionSection` becomes the children of `AccordionTrigger`
99
+ - Every `AccordionItem` requires a `value` prop — the index is fine for static lists
100
+ - `defaultValue` is always an array on `Accordion`
101
+
102
+ ### Dynamic list (map over data)
103
+
104
+ ```tsx
105
+ // Before
106
+ import { Accordion, AccordionSection } from '@aircall/tractor';
107
+
108
+ <Accordion>
109
+ {sections.map(section => (
110
+ <AccordionSection key={section.id} title={section.title}>
111
+ {section.body}
112
+ </AccordionSection>
113
+ ))}
114
+ </Accordion>
115
+
116
+ // After
117
+ import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '@aircall/ds';
118
+
119
+ <Accordion defaultValue={[0]}>
120
+ {sections.map((section, index) => (
121
+ <AccordionItem key={section.id} value={index}>
122
+ <AccordionTrigger>{section.title}</AccordionTrigger>
123
+ <AccordionContent>{section.body}</AccordionContent>
124
+ </AccordionItem>
125
+ ))}
126
+ </Accordion>
127
+ ```
128
+
129
+ ### Multiple sections open simultaneously
130
+
131
+ ```tsx
132
+ // After — allow more than one panel open at a time
133
+ <Accordion multiple defaultValue={[0, 1]}>
134
+ <AccordionItem value={0}>
135
+ <AccordionTrigger>General</AccordionTrigger>
136
+ <AccordionContent>General settings content.</AccordionContent>
137
+ </AccordionItem>
138
+ <AccordionItem value={1}>
139
+ <AccordionTrigger>Billing</AccordionTrigger>
140
+ <AccordionContent>Billing details content.</AccordionContent>
141
+ </AccordionItem>
142
+ </Accordion>
143
+ ```
144
+
145
+ ### Controlled
146
+
147
+ ```tsx
148
+ // After — controlled open state
149
+ const [openSections, setOpenSections] = React.useState<number[]>([0]);
150
+
151
+ <Accordion value={openSections} onValueChange={setOpenSections}>
152
+ <AccordionItem value={0}>
153
+ <AccordionTrigger>General</AccordionTrigger>
154
+ <AccordionContent>General settings content.</AccordionContent>
155
+ </AccordionItem>
156
+ <AccordionItem value={1}>
157
+ <AccordionTrigger>Billing</AccordionTrigger>
158
+ <AccordionContent>Billing details content.</AccordionContent>
159
+ </AccordionItem>
160
+ </Accordion>
161
+ ```
162
+
163
+ ### Disabled section
164
+
165
+ ```tsx
166
+ // After — disable one item
167
+ <Accordion defaultValue={[0]}>
168
+ <AccordionItem value={0}>
169
+ <AccordionTrigger>General</AccordionTrigger>
170
+ <AccordionContent>General settings content.</AccordionContent>
171
+ </AccordionItem>
172
+ <AccordionItem value={1} disabled>
173
+ <AccordionTrigger>Billing</AccordionTrigger>
174
+ <AccordionContent>Billing details content.</AccordionContent>
175
+ </AccordionItem>
176
+ </Accordion>
177
+ ```
178
+
179
+ ### Width / spacing
180
+
181
+ `Accordion` has no layout props. Apply width via `className`:
182
+
183
+ ```tsx
184
+ <Accordion defaultValue={[0]} className="w-[450px]">
185
+ ...
186
+ </Accordion>
187
+ ```
188
+
189
+ ---
190
+
191
+ ## 6. Common Mistakes
192
+
193
+ ### Mistake 1 — Adding a custom chevron inside `AccordionTrigger`
194
+
195
+ ```tsx
196
+ // Wrong — AccordionTrigger renders its own chevron; adding another doubles it
197
+ <AccordionTrigger>
198
+ General
199
+ <ChevronDownIcon />
200
+ </AccordionTrigger>
201
+
202
+ // Correct — pass only the header label as children
203
+ <AccordionTrigger>General</AccordionTrigger>
204
+ ```
205
+
206
+ `AccordionTrigger` internally renders a `ChevronDownIcon` / `ChevronUpIcon` pair that swaps on open/close state. Adding your own icon duplicates it visually. Pass only the label text (or non-icon content) as children.
207
+
208
+ Source: `packages/ds/src/components/accordion.tsx`
209
+
210
+ ---
211
+
212
+ ### Mistake 2 — Passing `defaultValue` / `value` as a scalar instead of an array
213
+
214
+ ```tsx
215
+ // Wrong — scalar causes a TypeScript error and the panel does not open
216
+ <Accordion defaultValue={0}>
217
+ <AccordionItem value={0}>
218
+ <AccordionTrigger>General</AccordionTrigger>
219
+ <AccordionContent>General settings content.</AccordionContent>
220
+ </AccordionItem>
221
+ </Accordion>
222
+
223
+ // Correct — always wrap in an array, even for a single default item
224
+ <Accordion defaultValue={[0]}>
225
+ <AccordionItem value={0}>
226
+ <AccordionTrigger>General</AccordionTrigger>
227
+ <AccordionContent>General settings content.</AccordionContent>
228
+ </AccordionItem>
229
+ </Accordion>
230
+ ```
231
+
232
+ Both `defaultValue` and `value` on `Accordion` are typed as `(number | string)[]`. Passing a bare scalar is a type error and the Base UI primitive will not open the panel.
233
+
234
+ Source: `packages/ds/src/components/accordion.tsx`
235
+
236
+ ---
237
+
238
+ ### Mistake 3 — Omitting the `value` prop on `AccordionItem`
239
+
240
+ ```tsx
241
+ // Wrong — AccordionItem without value cannot be identified for open/close state
242
+ <AccordionItem>
243
+ <AccordionTrigger>General</AccordionTrigger>
244
+ <AccordionContent>General settings content.</AccordionContent>
245
+ </AccordionItem>
246
+
247
+ // Correct — every AccordionItem needs a unique value
248
+ <AccordionItem value={0}>
249
+ <AccordionTrigger>General</AccordionTrigger>
250
+ <AccordionContent>General settings content.</AccordionContent>
251
+ </AccordionItem>
252
+ ```
253
+
254
+ `value` is required by the Base UI Accordion primitive to track which items are open. Without it the item cannot be matched against `defaultValue` / `value` on the root `Accordion`, so the panel stays permanently closed and toggling has no effect.
255
+
256
+ Source: `packages/ds/src/components/accordion.tsx`
257
+
258
+ ---
259
+
260
+ ### Mistake 4 — Using `type="multiple"` instead of the `multiple` boolean
261
+
262
+ ```tsx
263
+ // Wrong — type prop does not exist on DS Accordion; silently ignored
264
+ <Accordion type="multiple" defaultValue={[0, 1]}>
265
+ ...
266
+ </Accordion>
267
+
268
+ // Correct — DS uses a boolean `multiple` prop (same convention as ToggleGroup)
269
+ <Accordion multiple defaultValue={[0, 1]}>
270
+ ...
271
+ </Accordion>
272
+ ```
273
+
274
+ Tractor (and some other libraries) use `type="single" | "multiple"` to control this behavior. DS uses the simpler boolean `multiple` prop. Passing `type="multiple"` is silently ignored — the accordion reverts to single-open mode with no TypeScript error.
275
+
276
+ Source: `packages/ds/src/components/accordion.tsx`
@@ -0,0 +1,225 @@
1
+ ---
2
+ name: aircall-ds/migrate-tractor/alert
3
+ description: >
4
+ Migrate Tractor Banner (Banner, BannerHeading, BannerIcon, BannerParagraph) to
5
+ @aircall/ds Alert (rounded) vs Banner (inline). Load when a file imports Banner*
6
+ 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/alert-and-banner.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 alert-specific steps below.
18
+
19
+ ## 1. Alert vs Banner — pick the right component
20
+
21
+ Tractor `Banner` maps to **two** DS components. Choose based on visual shape:
22
+
23
+ | If the Tractor `Banner` looks like… | Use DS component |
24
+ | --- | --- |
25
+ | Rounded card-style callout (`rounded-3xl`, full border) | `Alert` |
26
+ | Full-width inline strip with accent edge (square corners, border on one side) | `Banner` |
27
+
28
+ `Banner` re-exports the `Alert*` sub-parts under `Banner*` aliases — the children grammar is identical. Pick the container; the parts follow.
29
+
30
+ ## 2. Sub-part mapping
31
+
32
+ | Tractor | DS (`Alert`) | DS (`Banner`) |
33
+ | --- | --- | --- |
34
+ | `BannerHeading` | `AlertTitle` | `BannerTitle` |
35
+ | `BannerIcon` | first `<svg>` child — **no wrapper** | same |
36
+ | `BannerSuffix` | `AlertAction` | `BannerAction` |
37
+ | `BannerParagraph` (body text) | `AlertDescription` | `BannerDescription` |
38
+
39
+ > **Icon is a direct child, not a part.** `Alert`/`Banner` detect a leading icon via `has-[>svg]` CSS. Render the icon as the **first child** — never wrap it. There is no `AlertIcon` or `BannerIcon` component in DS.
40
+
41
+ ## 3. Verified DS exports (`packages/ds/src/index.ts`)
42
+
43
+ ```
44
+ Alert, AlertAction, AlertDescription, AlertTitle,
45
+ Banner, BannerAction, BannerDescription, BannerTitle,
46
+ ```
47
+
48
+ All eight names exist in the published public API. Do not use any other Alert/Banner parts.
49
+
50
+ ## 4. Imports
51
+
52
+ ```tsx
53
+ import {
54
+ Alert, AlertTitle, AlertDescription, AlertAction,
55
+ Banner, BannerTitle, BannerDescription, BannerAction,
56
+ Button,
57
+ } from '@aircall/ds';
58
+ import { Info, AlertTriangle, X } from '@aircall/react-icons';
59
+ ```
60
+
61
+ ## 5. Before / After
62
+
63
+ ### Before (Tractor)
64
+
65
+ ```tsx
66
+ import { Banner, BannerHeading, BannerIcon, BannerParagraph, BannerSuffix } from '@aircall/tractor';
67
+
68
+ // Rounded callout
69
+ <Banner variant="informative">
70
+ <BannerIcon><Info /></BannerIcon>
71
+ <BannerHeading>Heads up</BannerHeading>
72
+ <BannerParagraph>Your trial ends in 3 days.</BannerParagraph>
73
+ <BannerSuffix><button onClick={onDismiss}>✕</button></BannerSuffix>
74
+ </Banner>
75
+
76
+ // Full-width inline strip
77
+ <Banner variant="critical">
78
+ <BannerIcon><AlertTriangle /></BannerIcon>
79
+ <BannerHeading>Limited connectivity</BannerHeading>
80
+ <BannerParagraph>Some calls may not connect.</BannerParagraph>
81
+ <BannerSuffix><button onClick={onRetry}>Retry</button></BannerSuffix>
82
+ </Banner>
83
+ ```
84
+
85
+ ### After (DS)
86
+
87
+ ```tsx
88
+ import {
89
+ Alert, AlertTitle, AlertDescription, AlertAction,
90
+ Banner, BannerTitle, BannerDescription, BannerAction,
91
+ Button,
92
+ } from '@aircall/ds';
93
+ import { Info, AlertTriangle, X } from '@aircall/react-icons';
94
+
95
+ // Rounded callout → Alert
96
+ <Alert variant="info">
97
+ <Info /> {/* BannerIcon → first <svg> child, no wrapper */}
98
+ <AlertTitle>Heads up</AlertTitle>
99
+ <AlertDescription>Your trial ends in 3 days.</AlertDescription>
100
+ <AlertAction>
101
+ <Button variant="ghost" size="icon-sm" onClick={onDismiss}><X /></Button>
102
+ </AlertAction>
103
+ </Alert>
104
+
105
+ // Full-width inline strip → Banner
106
+ <Banner variant="error" borderDirection="top">
107
+ <AlertTriangle />
108
+ <BannerTitle>Limited connectivity</BannerTitle>
109
+ <BannerDescription>Some calls may not connect.</BannerDescription>
110
+ <BannerAction>
111
+ <Button variant="outline" size="sm" onClick={onRetry}>Retry</Button>
112
+ </BannerAction>
113
+ </Banner>
114
+ ```
115
+
116
+ ## 6. Variant mapping
117
+
118
+ | Tractor variant | DS variant |
119
+ | --- | --- |
120
+ | `informative` | `info` |
121
+ | `critical` | `error` |
122
+ | `warning` | `warning` |
123
+ | `positive` / `success` | `success` |
124
+ | (default / none) | `default` |
125
+
126
+ Both `Alert` and `Banner` share the same set: `default` / `info` / `success` / `warning` / `error`.
127
+
128
+ ## 7. `Banner`-only prop: `borderDirection`
129
+
130
+ `Banner` accepts `borderDirection="top" | "bottom"` to place the accent border. `Alert` has no border-side prop — it is fully bordered and rounded.
131
+
132
+ ## 8. Common Mistakes
133
+
134
+ ### Mistake 1 — Wrapping the icon in a part component
135
+
136
+ ```tsx
137
+ // Wrong
138
+ <Alert variant="info">
139
+ <AlertIcon><Info /></AlertIcon> {/* AlertIcon does not exist in @aircall/ds */}
140
+ ...
141
+ </Alert>
142
+
143
+ // Correct
144
+ <Alert variant="info">
145
+ <Info /> {/* bare <svg> first child activates the grid */}
146
+ ...
147
+ </Alert>
148
+ ```
149
+
150
+ `Alert`/`Banner` use `has-[>svg]` to detect the icon slot. Wrapping the SVG in any element breaks the CSS selector and the icon fails to render in the correct grid area.
151
+ Source: `packages/ds/src/components/alert.tsx`
152
+
153
+ ---
154
+
155
+ ### Mistake 2 — Using `destructive` instead of `error`
156
+
157
+ ```tsx
158
+ // Wrong
159
+ <Alert variant="destructive">...</Alert> {/* destructive is a Button variant, not Alert */}
160
+
161
+ // Correct
162
+ <Alert variant="error">...</Alert> {/* maps Tractor critical */}
163
+ ```
164
+
165
+ `destructive` is a `Button` variant. `Alert`/`Banner` only accept `default | info | success | warning | error`. Passing an unknown variant silently falls through to `default` styling.
166
+ Source: `packages/ds/src/components/alert.tsx`
167
+
168
+ ---
169
+
170
+ ### Mistake 3 — Using `AlertAction`/`BannerAction` for the icon instead of the suffix
171
+
172
+ ```tsx
173
+ // Wrong
174
+ <Alert variant="warning">
175
+ <AlertAction><AlertTriangle /></AlertAction> {/* icon in the trailing action slot */}
176
+ <AlertTitle>Watch out</AlertTitle>
177
+ </Alert>
178
+
179
+ // Correct
180
+ <Alert variant="warning">
181
+ <AlertTriangle /> {/* first <svg> child → leading icon slot */}
182
+ <AlertTitle>Watch out</AlertTitle>
183
+ </Alert>
184
+ ```
185
+
186
+ `AlertAction`/`BannerAction` is the **trailing** slot (self-positions right, vertically centered). It is for close buttons or CTAs, not the leading icon. Placing the icon there yields wrong layout.
187
+ Source: `packages/ds/src/components/alert.tsx`
188
+
189
+ ---
190
+
191
+ ### Mistake 4 — Setting icon color manually
192
+
193
+ ```tsx
194
+ // Wrong
195
+ <Alert variant="info">
196
+ <Info className="text-blue-500" /> {/* manual color overrides variant-driven color */}
197
+ ...
198
+ </Alert>
199
+
200
+ // Correct
201
+ <Alert variant="info">
202
+ <Info /> {/* variant applies [&>svg]:text-info automatically */}
203
+ ...
204
+ </Alert>
205
+ ```
206
+
207
+ `Alert`/`Banner` apply `[&>svg]:text-<variant>` on the root. Explicit color classes on the icon fight the cascade and cause inconsistency across themes.
208
+ Source: `packages/ds/src/components/alert.tsx`
209
+
210
+ ---
211
+
212
+ ### Mistake 5 — Using `borderDirection` on `Alert`
213
+
214
+ ```tsx
215
+ // Wrong
216
+ <Alert variant="warning" borderDirection="top">...</Alert> {/* prop not supported on Alert */}
217
+
218
+ // Correct
219
+ <Banner variant="warning" borderDirection="top"> {/* Banner is the inline strip */}
220
+ ...
221
+ </Banner>
222
+ ```
223
+
224
+ `borderDirection` is a `Banner`-only prop (inline strip component). `Alert` is always fully bordered and rounded; it has no border-side prop. The prop is silently ignored on `Alert`.
225
+ Source: `packages/ds/src/components/banner.tsx`