@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.
- package/README.md +31 -0
- package/dist/globals.css +1 -1
- package/dist/index.d.ts +28 -28
- package/dist/index.js +1 -1
- package/package.json +12 -2
- package/skills/aircall-ds/migrate-icons/SKILL.md +346 -0
- package/skills/aircall-ds/migrate-tractor/SKILL.md +314 -0
- package/skills/aircall-ds/migrate-tractor/accordion/SKILL.md +276 -0
- package/skills/aircall-ds/migrate-tractor/alert/SKILL.md +225 -0
- package/skills/aircall-ds/migrate-tractor/avatar/SKILL.md +272 -0
- package/skills/aircall-ds/migrate-tractor/badge/SKILL.md +274 -0
- package/skills/aircall-ds/migrate-tractor/button/SKILL.md +277 -0
- package/skills/aircall-ds/migrate-tractor/card/SKILL.md +278 -0
- package/skills/aircall-ds/migrate-tractor/combobox/SKILL.md +346 -0
- package/skills/aircall-ds/migrate-tractor/data-table/SKILL.md +333 -0
- package/skills/aircall-ds/migrate-tractor/dialog/SKILL.md +206 -0
- package/skills/aircall-ds/migrate-tractor/divider/SKILL.md +226 -0
- package/skills/aircall-ds/migrate-tractor/dropdown-menu/SKILL.md +266 -0
- package/skills/aircall-ds/migrate-tractor/dropzone/SKILL.md +338 -0
- package/skills/aircall-ds/migrate-tractor/form-and-field/SKILL.md +325 -0
- package/skills/aircall-ds/migrate-tractor/gauge/SKILL.md +248 -0
- package/skills/aircall-ds/migrate-tractor/input/SKILL.md +261 -0
- package/skills/aircall-ds/migrate-tractor/item/SKILL.md +298 -0
- package/skills/aircall-ds/migrate-tractor/link/SKILL.md +263 -0
- package/skills/aircall-ds/migrate-tractor/popover/SKILL.md +214 -0
- package/skills/aircall-ds/migrate-tractor/select/SKILL.md +245 -0
- package/skills/aircall-ds/migrate-tractor/sheet-vs-drawer/SKILL.md +272 -0
- package/skills/aircall-ds/migrate-tractor/skeleton/SKILL.md +190 -0
- package/skills/aircall-ds/migrate-tractor/styling/SKILL.md +421 -0
- package/skills/aircall-ds/migrate-tractor/tabs/SKILL.md +250 -0
- package/skills/aircall-ds/migrate-tractor/toast/SKILL.md +322 -0
- package/skills/aircall-ds/migrate-tractor/tooltip/SKILL.md +204 -0
- package/skills/aircall-ds/migrate-tractor/tree/SKILL.md +346 -0
- package/skills/aircall-ds/setup/SKILL.md +347 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aircall-ds/migrate-tractor/sheet-vs-drawer
|
|
3
|
+
description: >
|
|
4
|
+
Migrate Tractor Drawer (desktop side panel) to @aircall/ds Sheet or Drawer.
|
|
5
|
+
Covers SheetContent side prop, DrawerPopup vs DrawerContent confusion, and
|
|
6
|
+
the render prop pattern for Trigger/Close. Load when a file imports Drawer
|
|
7
|
+
from @aircall/tractor.
|
|
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/sheet-vs-drawer.md"
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
This skill builds on aircall-ds/migrate-tractor. Apply all cross-cutting rules from that skill (prop renames, `render` prop, data attributes) before the sheet-vs-drawer-specific steps below.
|
|
19
|
+
|
|
20
|
+
## 1. Which component to use
|
|
21
|
+
|
|
22
|
+
DS ships two distinct side-panel components. The Tractor `Drawer` maps to **`Sheet`** for desktop side panels — not to DS's `Drawer`. DS's own `Drawer` is reserved for mobile-style panels with swipe-to-dismiss edge gestures.
|
|
23
|
+
|
|
24
|
+
| Use case | DS component | Built on |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| Persistent side panel (navigation, filters, settings) | `Sheet` | Base UI Dialog |
|
|
27
|
+
| Mobile-style swipe-to-dismiss edge panel | `Drawer` | Base UI Drawer (Coss UI) |
|
|
28
|
+
|
|
29
|
+
When in doubt, use `Sheet`.
|
|
30
|
+
|
|
31
|
+
## 2. Component mapping — Tractor Drawer → DS Sheet
|
|
32
|
+
|
|
33
|
+
| Tractor | @aircall/ds |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| `Drawer` (root + state) | `Sheet` |
|
|
36
|
+
| `DrawerHeader` | `SheetHeader` |
|
|
37
|
+
| `DrawerTitle` | `SheetTitle` |
|
|
38
|
+
| `DrawerBody` / body content | plain children inside `SheetContent` |
|
|
39
|
+
| `DrawerFooter` | `SheetFooter` |
|
|
40
|
+
| — | `SheetContent` (the panel popup; carries the `side` prop) |
|
|
41
|
+
| — | `SheetTrigger` (uncontrolled open trigger) |
|
|
42
|
+
| — | `SheetClose` (any element that closes the sheet) |
|
|
43
|
+
| — | `SheetDescription` (optional accessible subtitle) |
|
|
44
|
+
|
|
45
|
+
## 3. Component mapping — DS Drawer parts (swipe use case only)
|
|
46
|
+
|
|
47
|
+
| DS Drawer part | Role |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `Drawer` | Root state owner; accepts `position` and `open`/`onOpenChange` |
|
|
50
|
+
| `DrawerPopup` | The panel surface — **use this, not `DrawerContent`** |
|
|
51
|
+
| `DrawerHeader` | Header section inside `DrawerPopup` |
|
|
52
|
+
| `DrawerTitle` | Accessible title inside `DrawerHeader` |
|
|
53
|
+
| `DrawerFooter` | Footer section inside `DrawerPopup` |
|
|
54
|
+
| `DrawerClose` | Any element that closes the drawer |
|
|
55
|
+
| `DrawerTrigger` | Uncontrolled open trigger |
|
|
56
|
+
|
|
57
|
+
## 4. Before / After — Sheet (desktop side panel)
|
|
58
|
+
|
|
59
|
+
### Before (Tractor)
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
import { Drawer, DrawerHeader, DrawerTitle, DrawerBody, DrawerFooter, Button } from '@aircall/tractor';
|
|
63
|
+
|
|
64
|
+
<Drawer isOpen={isOpen} onClose={() => setIsOpen(false)} position="right">
|
|
65
|
+
<DrawerHeader>
|
|
66
|
+
<DrawerTitle>Filters</DrawerTitle>
|
|
67
|
+
</DrawerHeader>
|
|
68
|
+
<DrawerBody>
|
|
69
|
+
<p>Refine the call list.</p>
|
|
70
|
+
</DrawerBody>
|
|
71
|
+
<DrawerFooter>
|
|
72
|
+
<Button variant="outline" onClick={() => setIsOpen(false)}>Cancel</Button>
|
|
73
|
+
<Button onClick={onApply}>Apply</Button>
|
|
74
|
+
</DrawerFooter>
|
|
75
|
+
</Drawer>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### After (DS Sheet)
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import {
|
|
82
|
+
Sheet,
|
|
83
|
+
SheetClose,
|
|
84
|
+
SheetContent,
|
|
85
|
+
SheetDescription,
|
|
86
|
+
SheetFooter,
|
|
87
|
+
SheetHeader,
|
|
88
|
+
SheetTitle,
|
|
89
|
+
Button
|
|
90
|
+
} from '@aircall/ds';
|
|
91
|
+
|
|
92
|
+
<Sheet open={isOpen} onOpenChange={setIsOpen}>
|
|
93
|
+
<SheetContent side="right">
|
|
94
|
+
<SheetHeader>
|
|
95
|
+
<SheetTitle>Filters</SheetTitle>
|
|
96
|
+
<SheetDescription>Refine the call list.</SheetDescription>
|
|
97
|
+
</SheetHeader>
|
|
98
|
+
|
|
99
|
+
<p className="text-sm">Refine the call list.</p>
|
|
100
|
+
|
|
101
|
+
<SheetFooter>
|
|
102
|
+
<SheetClose render={<Button variant="outline" size="lg" />}>
|
|
103
|
+
Cancel
|
|
104
|
+
</SheetClose>
|
|
105
|
+
<Button size="lg" onClick={onApply}>Apply</Button>
|
|
106
|
+
</SheetFooter>
|
|
107
|
+
</SheetContent>
|
|
108
|
+
</Sheet>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Key changes:
|
|
112
|
+
- `isOpen` → `open`; `onClose()` → `onOpenChange(boolean)`
|
|
113
|
+
- Tractor `position="right"` → `SheetContent side="right"` (prop moved to the panel part)
|
|
114
|
+
- `DrawerBody` is removed — body content is plain children inside `SheetContent`
|
|
115
|
+
- `SheetClose` wraps any button that closes the sheet; pass the DS `Button` via `render` and put the label as children of `SheetClose`
|
|
116
|
+
- `SheetContent` renders a default "×" close button; hide it with `showCloseButton={false}` when you want to force explicit footer actions
|
|
117
|
+
|
|
118
|
+
### Uncontrolled with a trigger
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetFooter, SheetClose, Button } from '@aircall/ds';
|
|
122
|
+
|
|
123
|
+
<Sheet>
|
|
124
|
+
<SheetTrigger render={<Button size="lg" />}>Open filters</SheetTrigger>
|
|
125
|
+
<SheetContent side="right">
|
|
126
|
+
<SheetHeader>
|
|
127
|
+
<SheetTitle>Filters</SheetTitle>
|
|
128
|
+
</SheetHeader>
|
|
129
|
+
<p className="text-sm">Adjust your filters.</p>
|
|
130
|
+
<SheetFooter>
|
|
131
|
+
<SheetClose render={<Button variant="outline" size="lg" />}>Close</SheetClose>
|
|
132
|
+
</SheetFooter>
|
|
133
|
+
</SheetContent>
|
|
134
|
+
</Sheet>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## 5. Before / After — Drawer (swipe-to-dismiss, mobile)
|
|
138
|
+
|
|
139
|
+
### After (DS Drawer)
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import {
|
|
143
|
+
Drawer,
|
|
144
|
+
DrawerClose,
|
|
145
|
+
DrawerFooter,
|
|
146
|
+
DrawerHeader,
|
|
147
|
+
DrawerPopup,
|
|
148
|
+
DrawerTitle,
|
|
149
|
+
DrawerTrigger,
|
|
150
|
+
Button
|
|
151
|
+
} from '@aircall/ds';
|
|
152
|
+
|
|
153
|
+
<Drawer open={isOpen} onOpenChange={setIsOpen} position="right">
|
|
154
|
+
<DrawerPopup>
|
|
155
|
+
<DrawerHeader>
|
|
156
|
+
<DrawerTitle>Action sheet</DrawerTitle>
|
|
157
|
+
</DrawerHeader>
|
|
158
|
+
<div className="p-4">
|
|
159
|
+
<p className="text-sm">Swipe to dismiss.</p>
|
|
160
|
+
</div>
|
|
161
|
+
<DrawerFooter>
|
|
162
|
+
<DrawerClose render={<Button size="lg" />}>Done</DrawerClose>
|
|
163
|
+
</DrawerFooter>
|
|
164
|
+
</DrawerPopup>
|
|
165
|
+
</Drawer>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 6. Common mistakes
|
|
171
|
+
|
|
172
|
+
### Mistake 1 — Using `position` on `SheetContent` instead of `side`
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
// ❌ Wrong — position is a Tractor prop; SheetContent has no position prop
|
|
176
|
+
<SheetContent position="right">…</SheetContent>
|
|
177
|
+
|
|
178
|
+
// ✅ Correct — the edge is controlled by side on SheetContent
|
|
179
|
+
<SheetContent side="right">…</SheetContent>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
`SheetContent` accepts `side?: 'top' | 'right' | 'bottom' | 'left'`. The Tractor `position` prop is silently dropped; the sheet defaults to `side="right"` so the bug is invisible until a non-right position is needed.
|
|
183
|
+
|
|
184
|
+
Source: `packages/ds/src/components/sheet.tsx`
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### Mistake 2 — Using `DrawerContent` as the panel wrapper instead of `DrawerPopup`
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
// ❌ Wrong — DrawerContent is a thin inner drag-interaction primitive, not the panel
|
|
192
|
+
import { Drawer, DrawerContent } from '@aircall/ds';
|
|
193
|
+
|
|
194
|
+
<Drawer open={isOpen} onOpenChange={setIsOpen}>
|
|
195
|
+
<DrawerContent>
|
|
196
|
+
<p>Body</p>
|
|
197
|
+
</DrawerContent>
|
|
198
|
+
</Drawer>
|
|
199
|
+
|
|
200
|
+
// ✅ Correct — DrawerPopup is the full panel surface with backdrop, viewport, and styling
|
|
201
|
+
import { Drawer, DrawerPopup } from '@aircall/ds';
|
|
202
|
+
|
|
203
|
+
<Drawer open={isOpen} onOpenChange={setIsOpen}>
|
|
204
|
+
<DrawerPopup>
|
|
205
|
+
<p>Body</p>
|
|
206
|
+
</DrawerPopup>
|
|
207
|
+
</Drawer>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
`DrawerContent` is a Base UI primitive that enables text selection within drag targets — it is not a panel container. `DrawerPopup` composes the backdrop, viewport, and panel surface and is the correct high-level wrapper.
|
|
211
|
+
|
|
212
|
+
Source: `packages/ds/src/components/drawer.tsx`
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
### Mistake 3 — Using `asChild` on SheetTrigger or SheetClose instead of `render`
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
// ❌ Wrong — asChild is a Radix pattern; DS uses Base UI's render prop
|
|
220
|
+
<SheetClose asChild>
|
|
221
|
+
<Button variant="outline" size="lg">Cancel</Button>
|
|
222
|
+
</SheetClose>
|
|
223
|
+
|
|
224
|
+
// ✅ Correct — pass the DS Button via render; label goes as children of SheetClose
|
|
225
|
+
<SheetClose render={<Button variant="outline" size="lg" />}>
|
|
226
|
+
Cancel
|
|
227
|
+
</SheetClose>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
DS is built on Base UI, which uses a `render` prop instead of Radix's `asChild`. `asChild` is silently ignored — `SheetClose` still renders its own default element, the Button is never mounted, and the close handler is lost.
|
|
231
|
+
|
|
232
|
+
Source: `packages/ds/src/components/sheet.tsx`
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
### Mistake 4 — Mapping Tractor Drawer to DS Drawer for a desktop side panel
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
// ❌ Wrong — DS Drawer is for swipe-to-dismiss mobile panels, not desktop side panels
|
|
240
|
+
import { Drawer, DrawerPopup } from '@aircall/ds';
|
|
241
|
+
|
|
242
|
+
<Drawer open={isOpen} onOpenChange={setIsOpen} position="right">
|
|
243
|
+
<DrawerPopup>…</DrawerPopup>
|
|
244
|
+
</Drawer>
|
|
245
|
+
|
|
246
|
+
// ✅ Correct — Tractor Drawer (desktop) maps to DS Sheet
|
|
247
|
+
import { Sheet, SheetContent } from '@aircall/ds';
|
|
248
|
+
|
|
249
|
+
<Sheet open={isOpen} onOpenChange={setIsOpen}>
|
|
250
|
+
<SheetContent side="right">…</SheetContent>
|
|
251
|
+
</Sheet>
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
The naming is intentionally different: Tractor's `Drawer` was a general side panel. DS splits the concept in two — `Sheet` for persistent desktop panels and `Drawer` for mobile swipe gestures. Using DS `Drawer` for desktop panels adds unnecessary drag/swipe infrastructure and may produce unexpected dismiss behavior on touch devices.
|
|
255
|
+
|
|
256
|
+
Source: `packages/ds/src/components/sheet.tsx`
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
### Mistake 5 — Using `onClose` instead of `onOpenChange`
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
// ❌ Wrong — onClose is a Tractor prop; DS ignores it silently
|
|
264
|
+
<Sheet open={isOpen} onClose={() => setIsOpen(false)}>…</Sheet>
|
|
265
|
+
|
|
266
|
+
// ✅ Correct — onOpenChange receives the new boolean state
|
|
267
|
+
<Sheet open={isOpen} onOpenChange={setIsOpen}>…</Sheet>
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
`onOpenChange` fires with `false` when the sheet closes (backdrop click, Escape, or `SheetClose`). The Tractor `onClose()` callback is not forwarded and the sheet becomes uncontrollable — it opens but never closes.
|
|
271
|
+
|
|
272
|
+
Source: `packages/ds/src/components/sheet.tsx`
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aircall-ds/migrate-tractor/skeleton
|
|
3
|
+
description: >
|
|
4
|
+
Migrate Tractor Skeleton to the @aircall/ds Skeleton. Load when a file
|
|
5
|
+
imports Skeleton from @aircall/tractor. Covers the removal of shape/animation/mode
|
|
6
|
+
props and the className-based sizing pattern that replaces Tractor's BoxProps.
|
|
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:packages/ds/src/components/skeleton.tsx"
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
This skill builds on aircall-ds/migrate-tractor.
|
|
18
|
+
|
|
19
|
+
## 1. Component mapping
|
|
20
|
+
|
|
21
|
+
Tractor `Skeleton` was a styled `Box` wrapper with `shape`, `animation`, `mode`, and `animationDelay` props. DS `Skeleton` is a plain `div` with a fixed pulse animation and rounded corners — sizing and shape are controlled entirely through `className`.
|
|
22
|
+
|
|
23
|
+
| Tractor part | DS replacement | Notes |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| `<Skeleton>` | `<Skeleton>` | Direct replacement — drop Tractor-specific props |
|
|
26
|
+
| `shape="squareRounded"` | _(default)_ | DS always renders with `rounded-md`; no prop needed |
|
|
27
|
+
| `shape="circle"` | `className="rounded-full"` | Override the default `rounded-md` with `rounded-full` |
|
|
28
|
+
| `shape="square"` | `className="rounded-none"` | Override with `rounded-none` |
|
|
29
|
+
| `shape="squircle"` | `className="rounded-xl"` | Closest equivalent; pick visually |
|
|
30
|
+
| `animation="shimmer"` | _(not available)_ | DS has one animation (`animate-pulse`); no shimmer variant |
|
|
31
|
+
| `animation="wave"` | _(default)_ | DS default pulse covers this |
|
|
32
|
+
| `animationDelay` | `className="[animation-delay:200ms]"` | Use an arbitrary Tailwind value |
|
|
33
|
+
| `mode="dark"` | `className="bg-muted/60"` | DS uses `bg-muted`; adjust opacity for dark contexts |
|
|
34
|
+
| BoxProps (`w`, `h`, `width`, `height`) | `className="w-… h-…"` | Pass Tailwind sizing utilities via `className` |
|
|
35
|
+
|
|
36
|
+
## 2. Verified DS export (`packages/ds/src/index.ts`)
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
Skeleton
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 3. Imports
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { Skeleton } from '@aircall/ds';
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 4. Before / After examples
|
|
49
|
+
|
|
50
|
+
### 4a. Default squareRounded skeleton (text line placeholder)
|
|
51
|
+
|
|
52
|
+
**Before (Tractor):**
|
|
53
|
+
```tsx
|
|
54
|
+
import { Skeleton } from '@aircall/tractor';
|
|
55
|
+
|
|
56
|
+
<Skeleton shape="squareRounded" w="200px" h="16px" />
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**After (DS):**
|
|
60
|
+
```tsx
|
|
61
|
+
import { Skeleton } from '@aircall/ds';
|
|
62
|
+
|
|
63
|
+
<Skeleton className="w-[200px] h-4" />
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The DS default already applies `rounded-md`, so `shape="squareRounded"` requires no prop. Width and height move to Tailwind utilities in `className`.
|
|
67
|
+
|
|
68
|
+
### 4b. Circle skeleton (avatar placeholder)
|
|
69
|
+
|
|
70
|
+
**Before (Tractor):**
|
|
71
|
+
```tsx
|
|
72
|
+
import { Skeleton } from '@aircall/tractor';
|
|
73
|
+
|
|
74
|
+
<Skeleton shape="circle" w="40px" h="40px" />
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**After (DS):**
|
|
78
|
+
```tsx
|
|
79
|
+
import { Skeleton } from '@aircall/ds';
|
|
80
|
+
|
|
81
|
+
<Skeleton className="size-10 rounded-full" />
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`shape="circle"` maps to `rounded-full`. Use `size-10` (40px) for an exact match, or `size-8` / `size-12` for other avatar sizes.
|
|
85
|
+
|
|
86
|
+
### 4c. Card skeleton layout (multiple lines)
|
|
87
|
+
|
|
88
|
+
**Before (Tractor):**
|
|
89
|
+
```tsx
|
|
90
|
+
import { Skeleton } from '@aircall/tractor';
|
|
91
|
+
|
|
92
|
+
<div>
|
|
93
|
+
<Skeleton shape="circle" w="48px" h="48px" />
|
|
94
|
+
<Skeleton shape="squareRounded" w="120px" h="14px" animationDelay />
|
|
95
|
+
<Skeleton shape="squareRounded" w="80px" h="14px" animationDelay />
|
|
96
|
+
</div>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**After (DS):**
|
|
100
|
+
```tsx
|
|
101
|
+
import { Skeleton } from '@aircall/ds';
|
|
102
|
+
|
|
103
|
+
<div>
|
|
104
|
+
<Skeleton className="size-12 rounded-full" />
|
|
105
|
+
<Skeleton className="w-[120px] h-3.5 [animation-delay:200ms]" />
|
|
106
|
+
<Skeleton className="w-20 h-3.5 [animation-delay:200ms]" />
|
|
107
|
+
</div>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 4d. Square skeleton (image placeholder)
|
|
111
|
+
|
|
112
|
+
**Before (Tractor):**
|
|
113
|
+
```tsx
|
|
114
|
+
import { Skeleton } from '@aircall/tractor';
|
|
115
|
+
|
|
116
|
+
<Skeleton shape="square" w="64px" h="64px" />
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**After (DS):**
|
|
120
|
+
```tsx
|
|
121
|
+
import { Skeleton } from '@aircall/ds';
|
|
122
|
+
|
|
123
|
+
<Skeleton className="size-16 rounded-none" />
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## 5. Common Mistakes
|
|
127
|
+
|
|
128
|
+
### Mistake 1 — Passing `shape` as a prop to the DS Skeleton
|
|
129
|
+
|
|
130
|
+
**Wrong:**
|
|
131
|
+
```tsx
|
|
132
|
+
import { Skeleton } from '@aircall/ds';
|
|
133
|
+
|
|
134
|
+
<Skeleton shape="circle" w="40px" h="40px" />
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Correct:**
|
|
138
|
+
```tsx
|
|
139
|
+
import { Skeleton } from '@aircall/ds';
|
|
140
|
+
|
|
141
|
+
<Skeleton className="size-10 rounded-full" />
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
DS `Skeleton` extends `React.ComponentProps<'div'>` — it has no `shape` prop. Passing `shape` forwards an unknown attribute to the DOM (a React warning) and the element renders as the default `rounded-md` rectangle, not a circle.
|
|
145
|
+
|
|
146
|
+
Source: `packages/ds/src/components/skeleton.tsx`
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
### Mistake 2 — Using BoxProps (`w`, `h`) instead of `className` for sizing
|
|
151
|
+
|
|
152
|
+
**Wrong:**
|
|
153
|
+
```tsx
|
|
154
|
+
import { Skeleton } from '@aircall/ds';
|
|
155
|
+
|
|
156
|
+
<Skeleton w="200px" h="16px" />
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Correct:**
|
|
160
|
+
```tsx
|
|
161
|
+
import { Skeleton } from '@aircall/ds';
|
|
162
|
+
|
|
163
|
+
<Skeleton className="w-[200px] h-4" />
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Tractor `Skeleton` extended `BoxProps` from `@xstyled/styled-components`, so `w` and `h` were valid styled-system props. DS `Skeleton` is a plain `div` — `w` and `h` are not recognized and will be forwarded as invalid HTML attributes, producing DOM warnings and no visual effect on sizing.
|
|
167
|
+
|
|
168
|
+
Source: `packages/ds/src/components/skeleton.tsx`
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### Mistake 3 — Expecting a `animation="shimmer"` variant
|
|
173
|
+
|
|
174
|
+
**Wrong:**
|
|
175
|
+
```tsx
|
|
176
|
+
import { Skeleton } from '@aircall/ds';
|
|
177
|
+
|
|
178
|
+
<Skeleton animation="shimmer" className="w-32 h-4" />
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Correct:**
|
|
182
|
+
```tsx
|
|
183
|
+
import { Skeleton } from '@aircall/ds';
|
|
184
|
+
|
|
185
|
+
<Skeleton className="w-32 h-4" />
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
DS `Skeleton` has exactly one animation: `animate-pulse` (a CSS opacity pulse). There is no shimmer or wave variant. The `animation` prop does not exist on the DS component — passing it forwards the string to the DOM and triggers a React invalid-prop warning. Use the single DS animation as-is, or override with an arbitrary Tailwind animation utility if a shimmer effect is required for a specific design.
|
|
189
|
+
|
|
190
|
+
Source: `packages/ds/src/components/skeleton.tsx`
|