@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,272 @@
1
+ ---
2
+ name: aircall-ds/migrate-tractor/avatar
3
+ description: >
4
+ Migrate Tractor Avatar and QuickAvatar to the @aircall/ds Avatar compound
5
+ (Avatar, AvatarImage, AvatarFallback, AvatarBadge, AvatarGroup, AvatarGroupCount).
6
+ Load when a file imports Avatar or QuickAvatar 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/avatar.md"
15
+ ---
16
+
17
+ This skill builds on aircall-ds/migrate-tractor.
18
+
19
+ ## 1. Component mapping
20
+
21
+ | Tractor part | DS replacement | Notes |
22
+ | --- | --- | --- |
23
+ | `<Avatar src url name size>` | `<Avatar size><AvatarImage /><AvatarFallback /></Avatar>` | Compound — image and fallback are explicit children |
24
+ | `<QuickAvatar>` | `<Avatar>` | Identical DS compound; `QuickAvatar` had no extra API |
25
+ | `name="Jane Doe"` prop | `<AvatarFallback>JD</AvatarFallback>` | Derive initials yourself; DS has no auto-initials prop |
26
+ | Tractor `Badge` on avatar | `<AvatarBadge className="bg-…" />` | Child of `Avatar`; color set via `className` |
27
+ | Tractor `AvatarGroup` stack | `<AvatarGroup>` | Wraps `Avatar` children with overlap ring |
28
+ | Overflow chip `+N` | `<AvatarGroupCount>+3</AvatarGroupCount>` | Last child inside `AvatarGroup` |
29
+
30
+ ## 2. Verified DS exports (`packages/ds/src/index.ts`)
31
+
32
+ ```
33
+ Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage
34
+ ```
35
+
36
+ ## 3. Imports
37
+
38
+ ```tsx
39
+ import {
40
+ Avatar,
41
+ AvatarBadge,
42
+ AvatarFallback,
43
+ AvatarGroup,
44
+ AvatarGroupCount,
45
+ AvatarImage,
46
+ } from '@aircall/ds';
47
+ ```
48
+
49
+ ## 4. Size mapping (Tractor → DS)
50
+
51
+ | Tractor `size` | DS `size` | Rendered px |
52
+ | --- | --- | --- |
53
+ | `small` | `sm` | 24 px |
54
+ | `regular` (default) | `default` | 32 px |
55
+ | `large` | `xl` | 48 px |
56
+ | `xLarge` | `xl` | 48 px |
57
+ | _(none / 20 px)_ | `xs` | 20 px |
58
+ | _(none / 40 px)_ | `lg` | 40 px |
59
+
60
+ There is no 64 px size in DS. Map Tractor `xLarge` (64 px) to `xl` (48 px) — the closest available size.
61
+
62
+ ## 5. Before / After examples
63
+
64
+ ### 5a. Basic avatar with image and initials fallback
65
+
66
+ **Before (Tractor):**
67
+ ```tsx
68
+ import { Avatar } from '@aircall/tractor';
69
+
70
+ <Avatar
71
+ src="https://example.com/photo.jpg"
72
+ name="Jane Doe"
73
+ size="regular"
74
+ />
75
+ ```
76
+
77
+ **After (DS):**
78
+ ```tsx
79
+ import { Avatar, AvatarFallback, AvatarImage } from '@aircall/ds';
80
+
81
+ <Avatar size="default">
82
+ <AvatarImage src="https://example.com/photo.jpg" alt="Jane Doe" />
83
+ <AvatarFallback>JD</AvatarFallback>
84
+ </Avatar>
85
+ ```
86
+
87
+ ### 5b. QuickAvatar migration
88
+
89
+ **Before (Tractor):**
90
+ ```tsx
91
+ import { QuickAvatar } from '@aircall/tractor';
92
+
93
+ <QuickAvatar src={photoUrl} size="large" />
94
+ ```
95
+
96
+ **After (DS):**
97
+ ```tsx
98
+ import { Avatar, AvatarFallback, AvatarImage } from '@aircall/ds';
99
+
100
+ <Avatar size="xl">
101
+ <AvatarImage src={photoUrl} alt="" />
102
+ <AvatarFallback />
103
+ </Avatar>
104
+ ```
105
+
106
+ ### 5c. Avatar with status badge
107
+
108
+ **Before (Tractor):**
109
+ ```tsx
110
+ import { Avatar } from '@aircall/tractor';
111
+
112
+ <Avatar src={url} name="Jane Doe" size="regular" badge="online" />
113
+ ```
114
+
115
+ **After (DS):**
116
+ ```tsx
117
+ import { Avatar, AvatarBadge, AvatarFallback, AvatarImage } from '@aircall/ds';
118
+
119
+ <Avatar size="default">
120
+ <AvatarImage src={url} alt="Jane Doe" />
121
+ <AvatarFallback>JD</AvatarFallback>
122
+ <AvatarBadge className="bg-success" />
123
+ </Avatar>
124
+ ```
125
+
126
+ `AvatarBadge` auto-positions at bottom-right and sizes itself from the parent `Avatar`'s `size` attribute. Pass a Tailwind background utility via `className` to set the status color.
127
+
128
+ ### 5d. Overlapping avatar group with overflow count
129
+
130
+ **Before (Tractor):**
131
+ ```tsx
132
+ import { Avatar, AvatarGroup } from '@aircall/tractor';
133
+
134
+ <AvatarGroup max={3} users={users} />
135
+ ```
136
+
137
+ **After (DS):**
138
+ ```tsx
139
+ import {
140
+ Avatar,
141
+ AvatarFallback,
142
+ AvatarGroup,
143
+ AvatarGroupCount,
144
+ AvatarImage,
145
+ } from '@aircall/ds';
146
+
147
+ <AvatarGroup>
148
+ <Avatar>
149
+ <AvatarImage src={users[0].photo} alt={users[0].name} />
150
+ <AvatarFallback>AB</AvatarFallback>
151
+ </Avatar>
152
+ <Avatar>
153
+ <AvatarImage src={users[1].photo} alt={users[1].name} />
154
+ <AvatarFallback>CD</AvatarFallback>
155
+ </Avatar>
156
+ <AvatarGroupCount>+{users.length - 2}</AvatarGroupCount>
157
+ </AvatarGroup>
158
+ ```
159
+
160
+ DS has no built-in `max` or `users` props — slice the array yourself before rendering and compute the overflow count explicitly.
161
+
162
+ ## 6. Common mistakes
163
+
164
+ ### Mistake 1: Passing `name` as a prop instead of rendering `AvatarFallback`
165
+
166
+ **Wrong:**
167
+ ```tsx
168
+ import { Avatar } from '@aircall/ds';
169
+
170
+ <Avatar name="Jane Doe" size="default" />
171
+ ```
172
+
173
+ **Correct:**
174
+ ```tsx
175
+ import { Avatar, AvatarFallback, AvatarImage } from '@aircall/ds';
176
+
177
+ <Avatar size="default">
178
+ <AvatarImage src={url} alt="Jane Doe" />
179
+ <AvatarFallback>JD</AvatarFallback>
180
+ </Avatar>
181
+ ```
182
+
183
+ DS `Avatar` has no `name` prop. The prop is silently ignored and no fallback text renders when the image fails to load — the avatar shows a blank circle instead of initials.
184
+
185
+ Source: packages/ds/src/components/avatar.tsx — `AvatarProps` extends `AvatarPrimitive.Root.Props` which has no `name` field.
186
+
187
+ ---
188
+
189
+ ### Mistake 2: Omitting `AvatarFallback` when no image src is provided
190
+
191
+ **Wrong:**
192
+ ```tsx
193
+ import { Avatar, AvatarImage } from '@aircall/ds';
194
+
195
+ <Avatar size="default">
196
+ <AvatarImage src={maybeUndefinedUrl} alt="User" />
197
+ </Avatar>
198
+ ```
199
+
200
+ **Correct:**
201
+ ```tsx
202
+ import { Avatar, AvatarFallback, AvatarImage } from '@aircall/ds';
203
+
204
+ <Avatar size="default">
205
+ <AvatarImage src={maybeUndefinedUrl} alt="User" />
206
+ <AvatarFallback>U</AvatarFallback>
207
+ </Avatar>
208
+ ```
209
+
210
+ `AvatarImage` is a Base UI image that automatically swaps to `AvatarFallback` on load failure or when `src` is absent. Without `AvatarFallback`, a failed or missing image leaves an empty, unstyled circle with no content.
211
+
212
+ Source: packages/ds/src/components/avatar.tsx — `AvatarFallback` renders via `AvatarPrimitive.Fallback` which is only shown when the image is unavailable.
213
+
214
+ ---
215
+
216
+ ### Mistake 3: Placing `AvatarBadge` outside `Avatar`
217
+
218
+ **Wrong:**
219
+ ```tsx
220
+ import { Avatar, AvatarBadge, AvatarFallback, AvatarImage } from '@aircall/ds';
221
+
222
+ <div style={{ position: 'relative' }}>
223
+ <Avatar size="default">
224
+ <AvatarImage src={url} alt="Jane Doe" />
225
+ <AvatarFallback>JD</AvatarFallback>
226
+ </Avatar>
227
+ <AvatarBadge className="bg-success" />
228
+ </div>
229
+ ```
230
+
231
+ **Correct:**
232
+ ```tsx
233
+ import { Avatar, AvatarBadge, AvatarFallback, AvatarImage } from '@aircall/ds';
234
+
235
+ <Avatar size="default">
236
+ <AvatarImage src={url} alt="Jane Doe" />
237
+ <AvatarFallback>JD</AvatarFallback>
238
+ <AvatarBadge className="bg-success" />
239
+ </Avatar>
240
+ ```
241
+
242
+ `AvatarBadge` uses `absolute` positioning and reads the parent `group/avatar`'s `data-size` attribute to scale itself. Outside `Avatar`, it loses both the positioning context and the size-driven Tailwind group variants, so it renders at the wrong position and wrong size.
243
+
244
+ Source: packages/ds/src/components/avatar.tsx — `AvatarBadge` className includes `absolute right-0 bottom-0` and `group-data-[size=…]/avatar:size-…` variants.
245
+
246
+ ---
247
+
248
+ ### Mistake 4: Using Tractor `size="large"` or `size="xLarge"` expecting a 64 px avatar
249
+
250
+ **Wrong:**
251
+ ```tsx
252
+ import { Avatar, AvatarFallback, AvatarImage } from '@aircall/ds';
253
+
254
+ <Avatar size="large">
255
+ <AvatarImage src={url} alt="User" />
256
+ <AvatarFallback>U</AvatarFallback>
257
+ </Avatar>
258
+ ```
259
+
260
+ **Correct:**
261
+ ```tsx
262
+ import { Avatar, AvatarFallback, AvatarImage } from '@aircall/ds';
263
+
264
+ <Avatar size="xl">
265
+ <AvatarImage src={url} alt="User" />
266
+ <AvatarFallback>U</AvatarFallback>
267
+ </Avatar>
268
+ ```
269
+
270
+ DS has no `"large"` size token and no 64 px size. Passing `size="large"` falls back to the `default` (32 px) size because `data-size="large"` matches none of the Tailwind variants. The closest DS size to Tractor `xLarge` (64 px) is `xl` (48 px).
271
+
272
+ Source: packages/ds/src/components/avatar.tsx — `AvatarProps` size union is `'xs' | 'sm' | 'default' | 'lg' | 'xl'`.
@@ -0,0 +1,274 @@
1
+ ---
2
+ name: aircall-ds/migrate-tractor/badge
3
+ description: >
4
+ Migrate Tractor Tag and CounterBadge to @aircall/ds Badge, CounterBadge, BadgeGroup,
5
+ and BadgeGroupCount. Load when a file imports Tag or CounterBadge from @aircall/tractor.
6
+ Maps Tractor variant (grey/primary/blue/red/yellow/green/purple/pink/dark* prefixes)
7
+ to the DS color + tone two-axis model, and Tractor status Badge (dot) to AvatarBadge.
8
+ type: sub-skill
9
+ library: aircall-ds
10
+ library_version: "0.13.0"
11
+ requires:
12
+ - aircall-ds/setup
13
+ - aircall-ds/migrate-tractor
14
+ sources:
15
+ - "aircall/hydra:docs/migration-guides/tractor-to-ds/recipes/badge.md"
16
+ ---
17
+
18
+ This skill builds on aircall-ds/migrate-tractor.
19
+
20
+ ## 1. Component mapping
21
+
22
+ Tractor's badge surface had three distinct concepts that map to different DS components:
23
+
24
+ | Tractor component | DS replacement | Notes |
25
+ | --- | --- | --- |
26
+ | `<Tag>` | `<Badge>` | Color model changes from single `variant` to `color` + `tone` |
27
+ | `<CounterBadge>` | `<CounterBadge>` | No `max` prop — cap the value yourself before passing as children |
28
+ | `<Badge>` (status dot) | `<AvatarBadge>` | Tractor's dot-indicator badge is unrelated to DS `Badge`; see the avatar skill |
29
+ | _(grouping)_ | `<BadgeGroup>` + `<BadgeGroupCount>` | Wraps multiple badges; `BadgeGroupCount` renders the overflow "+N" chip |
30
+
31
+ ## 2. Verified DS exports (`packages/ds/src/index.ts`)
32
+
33
+ ```
34
+ Badge, BadgeGroup, BadgeGroupCount
35
+ CounterBadge, counterBadgeVariants
36
+ AvatarBadge
37
+ Chip, ChipRemove
38
+ ```
39
+
40
+ ## 3. Imports
41
+
42
+ ```tsx
43
+ import { Badge, BadgeGroup, BadgeGroupCount, CounterBadge } from '@aircall/ds';
44
+ ```
45
+
46
+ Icons inside badges import from `@aircall/react-icons` — never from `lucide-react` directly.
47
+
48
+ ## 4. `Tag` variant → `Badge` color + tone
49
+
50
+ DS Badge uses two orthogonal props instead of Tractor's single `variant`:
51
+
52
+ - `color`: `charcoal` (default) · `red` · `green` · `blue` · `purple` · `yellow` · `pink`
53
+ - `tone`: `dark` · `medium-dark` · `medium-light` · `light` (default)
54
+
55
+ | Tractor `variant` | DS `color` | DS `tone` |
56
+ | --- | --- | --- |
57
+ | `grey` / `white` | `charcoal` | `light` |
58
+ | `secondary` | `charcoal` | `medium-light` |
59
+ | `lightSecondary` | `charcoal` | `light` |
60
+ | `darkSecondary` | `charcoal` | `medium-dark` |
61
+ | `primary` | `green` | `medium-light` |
62
+ | `lightPrimary` | `green` | `light` |
63
+ | `darkPrimary` | `green` | `dark` |
64
+ | `blue` | `blue` | `medium-light` |
65
+ | `darkBlue` | `blue` | `dark` |
66
+ | `red` | `red` | `medium-light` |
67
+ | `darkRed` | `red` | `dark` |
68
+ | `yellow` | `yellow` | `medium-light` |
69
+ | `darkYellow` | `yellow` | `dark` |
70
+ | `green` | `green` | `medium-light` |
71
+ | `darkGreen` | `green` | `dark` |
72
+ | `purple` | `purple` | `medium-light` |
73
+ | `darkPurple` | `purple` | `dark` |
74
+ | `pink` | `pink` | `medium-light` |
75
+
76
+ > The base color variant maps to `medium-light`; `dark*` variants map to `dark` or `medium-dark`. `light*` variants map to `light`. Pick the tone that best matches the surface.
77
+
78
+ ### Hard-coded hex colors (`bg` prop)
79
+
80
+ When Tractor used a hard-coded hex (e.g. `bg="#0761B5"`), pass it via `legacyColor` — DS resolves it to the nearest `color` + `tone` at render time from an internal map. Unknown hexes fall back to `charcoal` / `dark`.
81
+
82
+ ```tsx
83
+ <Badge legacyColor="#0761B5">Sales</Badge>
84
+ ```
85
+
86
+ ## 5. Size mapping
87
+
88
+ | Tractor `size` | DS `size` |
89
+ | --- | --- |
90
+ | `xSmall` | `default` (20px) |
91
+ | `small` | `default` (20px) |
92
+ | `regular` (default) | `default` (20px) |
93
+ | `large` | `lg` (24px) |
94
+
95
+ DS has no `mode` prop (`outline` / `fill`). Use a lighter `tone` (e.g. `light`) to approximate the old outline look.
96
+
97
+ ## 6. CounterBadge
98
+
99
+ DS `CounterBadge` has no `max` prop. Cap the displayed value yourself before passing as children:
100
+
101
+ ```tsx
102
+ <CounterBadge>{count > 99 ? '99+' : count}</CounterBadge>
103
+ ```
104
+
105
+ Available `variant` values: `default` (destructive background) · `secondary` · `ghost`.
106
+
107
+ ## 7. Grouping badges
108
+
109
+ Use `BadgeGroup` to wrap a set of badges with consistent spacing, and `BadgeGroupCount` for the trailing overflow chip:
110
+
111
+ ```tsx
112
+ <BadgeGroup>
113
+ <Badge color="blue" tone="medium-light">Support</Badge>
114
+ <Badge color="green" tone="medium-light">Active</Badge>
115
+ <BadgeGroupCount>{overflow}</BadgeGroupCount>
116
+ </BadgeGroup>
117
+ ```
118
+
119
+ ## 8. Before / After examples
120
+
121
+ ### 8a. Simple Tag → Badge (variant rename)
122
+
123
+ **Before (Tractor):**
124
+ ```tsx
125
+ import { Tag } from '@aircall/tractor';
126
+
127
+ <Tag variant="primary">Active</Tag>
128
+ ```
129
+
130
+ **After (DS):**
131
+ ```tsx
132
+ import { Badge } from '@aircall/ds';
133
+
134
+ <Badge color="green" tone="medium-light">Active</Badge>
135
+ ```
136
+
137
+ > Tractor `primary` = green brand color → DS `color="green"` `tone="medium-light"`.
138
+
139
+ ### 8b. Dark variant
140
+
141
+ **Before (Tractor):**
142
+ ```tsx
143
+ import { Tag } from '@aircall/tractor';
144
+
145
+ <Tag variant="darkBlue">Escalated</Tag>
146
+ ```
147
+
148
+ **After (DS):**
149
+ ```tsx
150
+ import { Badge } from '@aircall/ds';
151
+
152
+ <Badge color="blue" tone="dark">Escalated</Badge>
153
+ ```
154
+
155
+ ### 8c. Hard-coded hex color
156
+
157
+ **Before (Tractor):**
158
+ ```tsx
159
+ import { Tag } from '@aircall/tractor';
160
+
161
+ <Tag bg="#0761B5">Sales</Tag>
162
+ ```
163
+
164
+ **After (DS):**
165
+ ```tsx
166
+ import { Badge } from '@aircall/ds';
167
+
168
+ <Badge legacyColor="#0761B5">Sales</Badge>
169
+ ```
170
+
171
+ ### 8d. CounterBadge with max cap
172
+
173
+ **Before (Tractor):**
174
+ ```tsx
175
+ import { CounterBadge } from '@aircall/tractor';
176
+
177
+ <CounterBadge count={count} max={99} />
178
+ ```
179
+
180
+ **After (DS):**
181
+ ```tsx
182
+ import { CounterBadge } from '@aircall/ds';
183
+
184
+ <CounterBadge>{count > 99 ? '99+' : count}</CounterBadge>
185
+ ```
186
+
187
+ ### 8e. Icon inside a Badge
188
+
189
+ **Before (Tractor):**
190
+ ```tsx
191
+ import { Tag } from '@aircall/tractor';
192
+ import { CheckCircle } from '@aircall/react-icons';
193
+
194
+ <Tag variant="green"><CheckCircle size={12} /> Verified</Tag>
195
+ ```
196
+
197
+ **After (DS):**
198
+ ```tsx
199
+ import { Badge } from '@aircall/ds';
200
+ import { CheckCircle } from '@aircall/react-icons';
201
+
202
+ <Badge color="green" tone="medium-light"><CheckCircle /> Verified</Badge>
203
+ ```
204
+
205
+ > DS auto-sizes SVG children via `[&>svg]:size-3!` (default) or `[&>svg]:size-4!` (lg). Do not pass a `size` prop to the icon.
206
+
207
+ ## 9. Common mistakes
208
+
209
+ ### Mistake 1: Using `variant` instead of `color` + `tone`
210
+
211
+ ```tsx
212
+ // Wrong — DS Badge has no `variant` prop; it is silently ignored
213
+ <Badge variant="primary">Active</Badge>
214
+
215
+ // Correct — map to the two-axis color + tone model
216
+ <Badge color="green" tone="medium-light">Active</Badge>
217
+ ```
218
+
219
+ **Mechanism:** DS Badge replaced Tractor's single `variant` string with two orthogonal props `color` and `tone`. Passing `variant` goes to the underlying `span` as an unknown HTML attribute and has no visual effect — the badge renders with the default charcoal/light appearance instead of the intended color.
220
+
221
+ Source: `packages/ds/src/components/badge.tsx` — `badgeVariants` has `color` and `tone` keys, no `variant` key.
222
+
223
+ ---
224
+
225
+ ### Mistake 2: Mapping Tractor status `Badge` (dot) to DS `Badge`
226
+
227
+ ```tsx
228
+ // Wrong — DS Badge is a label chip, not a status dot
229
+ <Badge status="online" />
230
+
231
+ // Correct — Tractor's status dot maps to AvatarBadge
232
+ import { Avatar, AvatarBadge, AvatarImage } from '@aircall/ds';
233
+
234
+ <Avatar>
235
+ <AvatarImage src={src} alt={name} />
236
+ <AvatarBadge />
237
+ </Avatar>
238
+ ```
239
+
240
+ **Mechanism:** Tractor had two components both named `Badge`: a label chip (`Tag`) and a small status dot (`Badge`). DS names them differently — `Badge` is the label chip and `AvatarBadge` is the status indicator that composes inside `Avatar`. Migrating the dot to DS `Badge` renders a text chip with no content instead of a dot.
241
+
242
+ Source: `packages/ds/src/components/badge.tsx` — `Badge` is a label chip; `packages/ds/src/components/avatar.tsx` exports `AvatarBadge` for the status dot.
243
+
244
+ ---
245
+
246
+ ### Mistake 3: Relying on DS `CounterBadge` to cap overflow automatically
247
+
248
+ ```tsx
249
+ // Wrong — DS CounterBadge has no `max` prop; it renders the raw number
250
+ <CounterBadge max={99} count={count} />
251
+
252
+ // Correct — cap the value yourself before passing as children
253
+ <CounterBadge>{count > 99 ? '99+' : count}</CounterBadge>
254
+ ```
255
+
256
+ **Mechanism:** Tractor's `CounterBadge` accepted a `max` prop and formatted "99+" internally. DS `CounterBadge` is a presentational span that renders whatever children it receives — the cap logic is the caller's responsibility. Passing `max` and `count` as props results in an empty badge with two unknown HTML attributes instead of the formatted string.
257
+
258
+ Source: `packages/ds/src/components/counter-badge.tsx` — `CounterBadge.Props` extends `useRender.ComponentProps<'span'>` with only a `variant` prop; no `max` or `count` keys.
259
+
260
+ ---
261
+
262
+ ### Mistake 4: Using `outline` / `fill` mode to style a badge
263
+
264
+ ```tsx
265
+ // Wrong — DS Badge has no `mode` prop
266
+ <Badge color="blue" mode="outline">Beta</Badge>
267
+
268
+ // Correct — reach for a lighter tone to approximate the outline look
269
+ <Badge color="blue" tone="light">Beta</Badge>
270
+ ```
271
+
272
+ **Mechanism:** Tractor's `Tag` supported a `mode` prop (`outline` / `fill`) that toggled between a bordered and a filled appearance. DS Badge has no `mode` prop — the visual weight is controlled entirely by `tone`. A lighter tone (`light` or `medium-light`) produces a softer background that approximates the old outline look.
273
+
274
+ Source: `packages/ds/src/components/badge.tsx` — `badgeVariants` has `size`, `color`, and `tone` variants; no `mode` variant.