@adamosuiteservices/ui 2.13.2 → 2.13.4

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 (35) hide show
  1. package/dist/components/ui/slider/slider.d.ts +5 -2
  2. package/dist/slider.cjs +7 -8
  3. package/dist/slider.js +192 -178
  4. package/dist/styles.css +1 -1
  5. package/docs/AI-GUIDE.md +321 -321
  6. package/docs/components/layout/sidebar.md +399 -399
  7. package/docs/components/layout/toaster.md +436 -436
  8. package/docs/components/ui/accordion-rounded.md +584 -584
  9. package/docs/components/ui/accordion.md +269 -269
  10. package/docs/components/ui/calendar.md +1159 -1159
  11. package/docs/components/ui/card.md +1455 -1455
  12. package/docs/components/ui/checkbox.md +292 -292
  13. package/docs/components/ui/collapsible.md +323 -323
  14. package/docs/components/ui/dialog.md +628 -628
  15. package/docs/components/ui/field.md +706 -706
  16. package/docs/components/ui/hover-card.md +446 -446
  17. package/docs/components/ui/kbd.md +434 -434
  18. package/docs/components/ui/label.md +359 -359
  19. package/docs/components/ui/pagination.md +650 -650
  20. package/docs/components/ui/popover.md +536 -536
  21. package/docs/components/ui/progress.md +182 -182
  22. package/docs/components/ui/radio-group.md +311 -311
  23. package/docs/components/ui/separator.md +214 -214
  24. package/docs/components/ui/sheet.md +174 -174
  25. package/docs/components/ui/skeleton.md +140 -140
  26. package/docs/components/ui/slider.md +460 -341
  27. package/docs/components/ui/spinner.md +170 -170
  28. package/docs/components/ui/switch.md +408 -408
  29. package/docs/components/ui/tabs-underline.md +106 -106
  30. package/docs/components/ui/tabs.md +122 -122
  31. package/docs/components/ui/textarea.md +243 -243
  32. package/docs/components/ui/toggle.md +237 -237
  33. package/docs/components/ui/tooltip.md +317 -317
  34. package/docs/components/ui/typography.md +320 -320
  35. package/package.json +1 -1
@@ -1,536 +1,536 @@
1
- # Popover
2
-
3
- Contenido flotante anclado a un trigger, basado en Radix UI. Ideal para forms compactos, settings, información adicional o acciones contextuales.
4
-
5
- ## Descripción
6
-
7
- El componente `Popover` muestra contenido flotante anclado a un elemento trigger.
8
-
9
- ## Importación
10
-
11
- ```typescript
12
- import {
13
- Popover,
14
- PopoverContent,
15
- PopoverTrigger,
16
- } from "@adamosuiteservices/ui/popover";
17
- ```
18
-
19
- ## Anatomía
20
-
21
- ```tsx
22
- <Popover>
23
- <PopoverTrigger>Open</PopoverTrigger>
24
- <PopoverContent>Place content for the popover here.</PopoverContent>
25
- </Popover>
26
- ```
27
-
28
- **Componentes**: 4 (Popover, PopoverTrigger, PopoverContent, PopoverAnchor)
29
-
30
- ## Props Principales
31
-
32
- ### Popover (Root)
33
-
34
- | Prop | Tipo | Default | Descripción |
35
- | -------------- | ------------------------- | ------- | --------------------------------------- |
36
- | `open` | `boolean` | - | Estado controlado |
37
- | `defaultOpen` | `boolean` | `false` | Estado inicial no controlado |
38
- | `onOpenChange` | `(open: boolean) => void` | - | Callback cuando cambia estado |
39
- | `modal` | `boolean` | `false` | Si es modal (bloquea interacción fuera) |
40
-
41
- ### PopoverTrigger
42
-
43
- | Prop | Tipo | Descripción |
44
- | ----------- | --------- | -------------------------------------------------- |
45
- | `asChild` | `boolean` | Pasa props al child en lugar de renderizar wrapper |
46
- | `className` | `string` | Clases CSS adicionales |
47
-
48
- ### PopoverContent
49
-
50
- | Prop | Tipo | Default | Descripción |
51
- | ------------- | ---------------------------------------- | ---------- | -------------------------------- |
52
- | `side` | `"top" \| "right" \| "bottom" \| "left"` | `"bottom"` | Lado donde aparece |
53
- | `align` | `"start" \| "center" \| "end"` | `"center"` | Alineamiento horizontal/vertical |
54
- | `sideOffset` | `number` | `4` | Distancia desde trigger (px) |
55
- | `alignOffset` | `number` | `0` | Offset del alineamiento |
56
- | `className` | `string` | - | Clases CSS adicionales |
57
-
58
- **Estilos default**: `w-72`, `p-4`, `rounded-md`, `border`, `shadow-md`, `z-50`
59
-
60
- ### PopoverAnchor
61
-
62
- | Prop | Tipo | Descripción |
63
- | ----------- | --------- | ---------------------- |
64
- | `asChild` | `boolean` | Pasa props al child |
65
- | `className` | `string` | Clases CSS adicionales |
66
-
67
- **Uso**: Ancla popover a elemento diferente del trigger
68
-
69
- ## Patrones de Uso
70
-
71
- ### Básico
72
-
73
- ```tsx
74
- <Popover>
75
- <PopoverTrigger asChild>
76
- <Button variant="outline">Open popover</Button>
77
- </PopoverTrigger>
78
- <PopoverContent className="w-80">
79
- <div className="grid gap-4">
80
- <div className="space-y-2">
81
- <h4 className="font-medium leading-none">Dimensions</h4>
82
- <p className="text-sm text-muted-foreground">
83
- Set the dimensions for the layer.
84
- </p>
85
- </div>
86
- <div className="grid gap-2">
87
- <div className="grid grid-cols-3 items-center gap-4">
88
- <Label htmlFor="width">Width</Label>
89
- <Input id="width" defaultValue="100%" className="col-span-2 h-8" />
90
- </div>
91
- <div className="grid grid-cols-3 items-center gap-4">
92
- <Label htmlFor="height">Height</Label>
93
- <Input id="height" defaultValue="25px" className="col-span-2 h-8" />
94
- </div>
95
- </div>
96
- </div>
97
- </PopoverContent>
98
- </Popover>
99
- ```
100
-
101
- ### Simple
102
-
103
- ```tsx
104
- <Popover>
105
- <PopoverTrigger asChild>
106
- <Button variant="outline">Click me</Button>
107
- </PopoverTrigger>
108
- <PopoverContent>
109
- <p>This is a simple popover with just text content.</p>
110
- </PopoverContent>
111
- </Popover>
112
- ```
113
-
114
- ### Con User Profile
115
-
116
- ```tsx
117
- import {
118
- Avatar,
119
- AvatarImage,
120
- AvatarFallback,
121
- } from "@adamosuiteservices/ui/avatar";
122
- import { Icon } from "@adamosuiteservices/ui/icon";
123
-
124
- <Popover>
125
- <PopoverTrigger asChild>
126
- <Button variant="ghost" className="h-auto p-2">
127
- <Avatar className="h-8 w-8">
128
- <AvatarImage src="https://github.com/shadcn.png" />
129
- <AvatarFallback>SC</AvatarFallback>
130
- </Avatar>
131
- </Button>
132
- </PopoverTrigger>
133
- <PopoverContent className="w-80">
134
- <div className="flex gap-4">
135
- <Avatar>
136
- <AvatarImage src="https://github.com/shadcn.png" />
137
- <AvatarFallback>SC</AvatarFallback>
138
- </Avatar>
139
- <div className="space-y-1">
140
- <h4 className="text-sm font-semibold">@shadcn</h4>
141
- <p className="text-sm">
142
- The React Framework – created and maintained by @vercel.
143
- </p>
144
- <div className="flex items-center pt-2">
145
- <Icon symbol="calendar_month" className="mr-2 text-lg opacity-70" />
146
- <span className="text-xs text-muted-foreground">
147
- Joined December 2021
148
- </span>
149
- </div>
150
- </div>
151
- </div>
152
- </PopoverContent>
153
- </Popover>;
154
- ```
155
-
156
- ### Con Settings
157
-
158
- ```tsx
159
- import { Switch } from "@adamosuiteservices/ui/switch";
160
- import { Separator } from "@adamosuiteservices/ui/separator";
161
- import { Icon } from "@adamosuiteservices/ui/icon";
162
-
163
- <Popover>
164
- <PopoverTrigger asChild>
165
- <Button variant="outline" size="icon">
166
- <Icon symbol="settings" className="text-lg" />
167
- </Button>
168
- </PopoverTrigger>
169
- <PopoverContent className="w-80">
170
- <div className="grid gap-4">
171
- <div className="space-y-2">
172
- <h4 className="font-medium leading-none">Settings</h4>
173
- <p className="text-sm text-muted-foreground">
174
- Configure your preferences
175
- </p>
176
- </div>
177
- <div className="grid gap-2">
178
- <div className="flex items-center justify-between">
179
- <Label htmlFor="notifications">Push notifications</Label>
180
- <Switch id="notifications" />
181
- </div>
182
- <div className="flex items-center justify-between">
183
- <Label htmlFor="emails">Email updates</Label>
184
- <Switch id="emails" defaultChecked />
185
- </div>
186
- </div>
187
- <Separator />
188
- <div className="flex justify-between">
189
- <Button variant="outline" size="sm">
190
- Cancel
191
- </Button>
192
- <Button size="sm">Save changes</Button>
193
- </div>
194
- </div>
195
- </PopoverContent>
196
- </Popover>;
197
- ```
198
-
199
- ### Con Calendar
200
-
201
- ```tsx
202
- import { useState } from "react";
203
- import { Calendar } from "@adamosuiteservices/ui/calendar";
204
- import { Icon } from "@adamosuiteservices/ui/icon";
205
-
206
- function App() {
207
- const [date, setDate] = useState<Date | undefined>(new Date());
208
-
209
- return (
210
- <Popover>
211
- <PopoverTrigger asChild>
212
- <Button
213
- variant="outline"
214
- className={cn(
215
- "w-[240px] justify-start text-left font-normal",
216
- !date && "text-muted-foreground"
217
- )}
218
- >
219
- <Icon symbol="calendar_month" className="mr-2 text-lg" />
220
- {date ? date.toLocaleDateString() : "Pick a date"}
221
- </Button>
222
- </PopoverTrigger>
223
- <PopoverContent className="w-auto p-0" align="start">
224
- <Calendar
225
- mode="single"
226
- selected={date}
227
- onSelect={setDate}
228
- initialFocus
229
- />
230
- </PopoverContent>
231
- </Popover>
232
- );
233
- }
234
- ```
235
-
236
- ### Con Counter
237
-
238
- ```tsx
239
- import { useState } from "react";
240
- import { Icon } from "@adamosuiteservices/ui/icon";
241
-
242
- function App() {
243
- const [count, setCount] = useState(0);
244
-
245
- return (
246
- <Popover>
247
- <PopoverTrigger asChild>
248
- <Button variant="outline">Counter: {count}</Button>
249
- </PopoverTrigger>
250
- <PopoverContent className="w-64">
251
- <div className="grid gap-4">
252
- <div className="space-y-2">
253
- <h4 className="font-medium leading-none">Counter Control</h4>
254
- <p className="text-sm text-muted-foreground">
255
- Adjust the counter value
256
- </p>
257
- </div>
258
- <div className="flex items-center justify-center space-x-2">
259
- <Button
260
- variant="outline"
261
- size="icon"
262
- onClick={() => setCount(Math.max(0, count - 1))}
263
- disabled={count === 0}
264
- >
265
- <Icon symbol="remove" className="text-lg" />
266
- </Button>
267
- <div className="flex items-center justify-center w-16 h-10 border rounded">
268
- {count}
269
- </div>
270
- <Button
271
- variant="outline"
272
- size="icon"
273
- onClick={() => setCount(count + 1)}
274
- >
275
- <Icon symbol="add" className="text-lg" />
276
- </Button>
277
- </div>
278
- <div className="flex gap-2">
279
- <Button variant="outline" size="sm" onClick={() => setCount(0)}>
280
- Reset
281
- </Button>
282
- <Button size="sm" onClick={() => setCount(10)}>
283
- Set to 10
284
- </Button>
285
- </div>
286
- </div>
287
- </PopoverContent>
288
- </Popover>
289
- );
290
- }
291
- ```
292
-
293
- ### Con Info Icon
294
-
295
- ```tsx
296
- import { Icon } from "@adamosuiteservices/ui/icon";
297
-
298
- <div className="flex items-center gap-4">
299
- <span>Complex Feature</span>
300
- <Popover>
301
- <PopoverTrigger asChild>
302
- <Button variant="ghost" size="icon" className="h-5 w-5">
303
- <Icon symbol="info" className="text-sm" />
304
- </Button>
305
- </PopoverTrigger>
306
- <PopoverContent className="w-80">
307
- <div className="space-y-3">
308
- <div className="flex items-center gap-2">
309
- <Icon symbol="error" className="text-lg text-primary" />
310
- <h4 className="font-medium">About this feature</h4>
311
- </div>
312
- <p className="text-sm text-muted-foreground">
313
- This is a complex feature that requires additional explanation.
314
- </p>
315
- <div className="space-y-2">
316
- <h5 className="text-sm font-medium">Key benefits:</h5>
317
- <ul className="text-sm space-y-1 text-muted-foreground">
318
- <li>• Improved performance</li>
319
- <li>• Better user experience</li>
320
- <li>• Advanced customization</li>
321
- </ul>
322
- </div>
323
- </div>
324
- </PopoverContent>
325
- </Popover>
326
- </div>;
327
- ```
328
-
329
- ### Con Notifications
330
-
331
- ```tsx
332
- import { Icon } from "@adamosuiteservices/ui/icon";
333
- import { Badge } from "@adamosuiteservices/ui/badge";
334
- import { Separator } from "@adamosuiteservices/ui/separator";
335
-
336
- <Popover>
337
- <PopoverTrigger asChild>
338
- <Button variant="outline" size="icon" className="relative">
339
- <Icon symbol="mail" className="text-lg" />
340
- <Badge
341
- className="absolute -top-2 -right-2 h-5 w-5 p-0 flex items-center justify-center"
342
- variant="destructive"
343
- >
344
- 3
345
- </Badge>
346
- </Button>
347
- </PopoverTrigger>
348
- <PopoverContent className="w-80">
349
- <div className="space-y-3">
350
- <div className="flex items-center justify-between">
351
- <h4 className="font-medium">Notifications</h4>
352
- <Button variant="ghost" size="sm">
353
- Mark all read
354
- </Button>
355
- </div>
356
- <div className="space-y-2">
357
- <div className="flex items-start gap-3 p-2 rounded hover:bg-muted bg-muted/50">
358
- <div className="flex-1">
359
- <p className="text-sm font-medium">New message</p>
360
- <p className="text-xs text-muted-foreground">2 min ago</p>
361
- </div>
362
- <div className="h-2 w-2 bg-primary rounded-full mt-1" />
363
- </div>
364
- </div>
365
- <Separator />
366
- <Button variant="outline" size="sm" className="w-full">
367
- View all notifications
368
- </Button>
369
- </div>
370
- </PopoverContent>
371
- </Popover>;
372
- ```
373
-
374
- ### Posicionamiento Custom
375
-
376
- ```tsx
377
- {
378
- /* Top */
379
- }
380
- <Popover>
381
- <PopoverTrigger asChild>
382
- <Button variant="outline">Top</Button>
383
- </PopoverTrigger>
384
- <PopoverContent side="top">
385
- <p>This popover appears on top</p>
386
- </PopoverContent>
387
- </Popover>;
388
-
389
- {
390
- /* Right */
391
- }
392
- <Popover>
393
- <PopoverTrigger asChild>
394
- <Button variant="outline">Right</Button>
395
- </PopoverTrigger>
396
- <PopoverContent side="right">
397
- <p>This popover appears on the right</p>
398
- </PopoverContent>
399
- </Popover>;
400
-
401
- {
402
- /* Start aligned */
403
- }
404
- <Popover>
405
- <PopoverTrigger asChild>
406
- <Button variant="outline">Start aligned</Button>
407
- </PopoverTrigger>
408
- <PopoverContent align="start">
409
- <p>This popover is aligned to the start</p>
410
- </PopoverContent>
411
- </Popover>;
412
- ```
413
-
414
- ### Con Anchor
415
-
416
- ```tsx
417
- <div className="space-y-4">
418
- <p>
419
- This is some text with an{" "}
420
- <Popover>
421
- <PopoverAnchor asChild>
422
- <span className="underline cursor-pointer">anchored element</span>
423
- </PopoverAnchor>
424
- <PopoverTrigger asChild>
425
- <Button variant="outline" className="ml-2">
426
- Show info
427
- </Button>
428
- </PopoverTrigger>
429
- <PopoverContent>
430
- <p>This popover is anchored to the underlined text above!</p>
431
- </PopoverContent>
432
- </Popover>
433
- </p>
434
- </div>
435
- ```
436
-
437
- ### Controlado
438
-
439
- ```tsx
440
- import { useState } from "react";
441
-
442
- function App() {
443
- const [open, setOpen] = useState(false);
444
-
445
- return (
446
- <Popover open={open} onOpenChange={setOpen}>
447
- <PopoverTrigger asChild>
448
- <Button variant="outline">Toggle</Button>
449
- </PopoverTrigger>
450
- <PopoverContent>
451
- <div className="space-y-2">
452
- <p>Controlled popover content</p>
453
- <Button onClick={() => setOpen(false)}>Close</Button>
454
- </div>
455
- </PopoverContent>
456
- </Popover>
457
- );
458
- }
459
- ```
460
-
461
- ## Casos de Uso Comunes
462
-
463
- **Date pickers**: Mostrar calendar en popover
464
- **Settings**: Controles compactos de configuración
465
- **User profiles**: Preview de perfiles al hover/click
466
- **Notifications**: Lista de notificaciones
467
- **Quick actions**: Acciones contextuales sin modal
468
- **Info tooltips**: Información rica vs tooltip simple
469
- **Forms**: Formularios compactos inline
470
-
471
- ## Estados y Data Attributes
472
-
473
- ### PopoverContent States
474
-
475
- - **Open**: `data-[state=open]` → `animate-in`, `fade-in-0`, `zoom-in-95`
476
- - **Closed**: `data-[state=closed]` → `animate-out`, `fade-out-0`, `zoom-out-95`
477
-
478
- ### Side Animations
479
-
480
- - **Top**: `data-[side=top]` → `slide-in-from-bottom-2`
481
- - **Right**: `data-[side=right]` → `slide-in-from-left-2`
482
- - **Bottom**: `data-[side=bottom]` → `slide-in-from-top-2`
483
- - **Left**: `data-[side=left]` → `slide-in-from-right-2`
484
-
485
- ## Interacción
486
-
487
- - ✅ **Click to open**: Click en trigger abre popover
488
- - ✅ **Click outside**: Click fuera cierra popover (si no es modal)
489
- - ✅ **Escape**: Presionar Esc cierra popover
490
- - ✅ **Focus trap**: Si `modal=true`, foco queda atrapado dentro
491
- - ✅ **Keyboard**: Tab navega entre elementos internos
492
-
493
- ## Accesibilidad
494
-
495
- - ✅ **ARIA**: `role="dialog"`, `aria-labelledby`, `aria-describedby` según contenido
496
- - ✅ **Focus management**: Focus automático al abrir
497
- - ✅ **Keyboard**: Esc para cerrar, Tab para navegar
498
- - ✅ **Portal**: Renderiza en `document.body` para evitar problemas de z-index
499
- - ✅ **Modal mode**: `modal=true` para bloquear interacción fuera del popover
500
-
501
- ## Notas de Implementación
502
-
503
- - **Radix UI**: Basado en `@radix-ui/react-popover`
504
- - **Portal rendering**: Content se renderiza en `document.body`
505
- - **Collision detection**: Auto-ajusta posición si sale del viewport
506
- - **Transform origin**: CSS variables de Radix para animaciones
507
- - **Default width**: `w-72` (288px)
508
- - **Default padding**: `p-4`
509
- - **Z-index**: 50 para aparecer sobre contenido
510
- - **Modal**: Por defecto `modal=false` (permite interacción fuera)
511
-
512
- ## Diferencias con Dialog y HoverCard
513
-
514
- | Aspecto | Popover | Dialog | HoverCard |
515
- | ---------------- | ----------------- | --------------------- | --------------- |
516
- | **Trigger** | Click | Click | Hover |
517
- | **Modal** | Opcional | Siempre | No |
518
- | **Backdrop** | Opcional | Sí | No |
519
- | **Contenido** | Compacto | Extenso | Preview |
520
- | **Persistencia** | Hasta click fuera | Hasta close explícito | Hasta hover out |
521
-
522
- ## Troubleshooting
523
-
524
- **No aparece**: Verifica que PopoverContent esté dentro de Popover root
525
- **Posición incorrecta**: Ajusta `side`, `align`, `sideOffset` y `alignOffset`
526
- **Contenido cortado**: Verifica que no haya `overflow: hidden` en containers
527
- **No cierra**: Si `modal=true`, solo cierra con Esc o close explícito
528
- **Focus no funciona**: Content debe tener elementos focuseables
529
- **Backdrop no se ve**: Popover no tiene backdrop por defecto, usa `modal=true` y customiza
530
- **Z-index issues**: Content usa portal, debe aparecer sobre todo
531
- **Anchor no funciona**: PopoverAnchor debe estar dentro de Popover root
532
-
533
- ## Referencias
534
-
535
- - **Radix UI Popover**: <https://www.radix-ui.com/primitives/docs/components/popover>
536
- - **shadcn/ui Popover**: <https://ui.shadcn.com/docs/components/popover>
1
+ # Popover
2
+
3
+ Contenido flotante anclado a un trigger, basado en Radix UI. Ideal para forms compactos, settings, información adicional o acciones contextuales.
4
+
5
+ ## Descripción
6
+
7
+ El componente `Popover` muestra contenido flotante anclado a un elemento trigger.
8
+
9
+ ## Importación
10
+
11
+ ```typescript
12
+ import {
13
+ Popover,
14
+ PopoverContent,
15
+ PopoverTrigger,
16
+ } from "@adamosuiteservices/ui/popover";
17
+ ```
18
+
19
+ ## Anatomía
20
+
21
+ ```tsx
22
+ <Popover>
23
+ <PopoverTrigger>Open</PopoverTrigger>
24
+ <PopoverContent>Place content for the popover here.</PopoverContent>
25
+ </Popover>
26
+ ```
27
+
28
+ **Componentes**: 4 (Popover, PopoverTrigger, PopoverContent, PopoverAnchor)
29
+
30
+ ## Props Principales
31
+
32
+ ### Popover (Root)
33
+
34
+ | Prop | Tipo | Default | Descripción |
35
+ | -------------- | ------------------------- | ------- | --------------------------------------- |
36
+ | `open` | `boolean` | - | Estado controlado |
37
+ | `defaultOpen` | `boolean` | `false` | Estado inicial no controlado |
38
+ | `onOpenChange` | `(open: boolean) => void` | - | Callback cuando cambia estado |
39
+ | `modal` | `boolean` | `false` | Si es modal (bloquea interacción fuera) |
40
+
41
+ ### PopoverTrigger
42
+
43
+ | Prop | Tipo | Descripción |
44
+ | ----------- | --------- | -------------------------------------------------- |
45
+ | `asChild` | `boolean` | Pasa props al child en lugar de renderizar wrapper |
46
+ | `className` | `string` | Clases CSS adicionales |
47
+
48
+ ### PopoverContent
49
+
50
+ | Prop | Tipo | Default | Descripción |
51
+ | ------------- | ---------------------------------------- | ---------- | -------------------------------- |
52
+ | `side` | `"top" \| "right" \| "bottom" \| "left"` | `"bottom"` | Lado donde aparece |
53
+ | `align` | `"start" \| "center" \| "end"` | `"center"` | Alineamiento horizontal/vertical |
54
+ | `sideOffset` | `number` | `4` | Distancia desde trigger (px) |
55
+ | `alignOffset` | `number` | `0` | Offset del alineamiento |
56
+ | `className` | `string` | - | Clases CSS adicionales |
57
+
58
+ **Estilos default**: `w-72`, `p-4`, `rounded-md`, `border`, `shadow-md`, `z-50`
59
+
60
+ ### PopoverAnchor
61
+
62
+ | Prop | Tipo | Descripción |
63
+ | ----------- | --------- | ---------------------- |
64
+ | `asChild` | `boolean` | Pasa props al child |
65
+ | `className` | `string` | Clases CSS adicionales |
66
+
67
+ **Uso**: Ancla popover a elemento diferente del trigger
68
+
69
+ ## Patrones de Uso
70
+
71
+ ### Básico
72
+
73
+ ```tsx
74
+ <Popover>
75
+ <PopoverTrigger asChild>
76
+ <Button variant="outline">Open popover</Button>
77
+ </PopoverTrigger>
78
+ <PopoverContent className="w-80">
79
+ <div className="grid gap-4">
80
+ <div className="space-y-2">
81
+ <h4 className="font-medium leading-none">Dimensions</h4>
82
+ <p className="text-sm text-muted-foreground">
83
+ Set the dimensions for the layer.
84
+ </p>
85
+ </div>
86
+ <div className="grid gap-2">
87
+ <div className="grid grid-cols-3 items-center gap-4">
88
+ <Label htmlFor="width">Width</Label>
89
+ <Input id="width" defaultValue="100%" className="col-span-2 h-8" />
90
+ </div>
91
+ <div className="grid grid-cols-3 items-center gap-4">
92
+ <Label htmlFor="height">Height</Label>
93
+ <Input id="height" defaultValue="25px" className="col-span-2 h-8" />
94
+ </div>
95
+ </div>
96
+ </div>
97
+ </PopoverContent>
98
+ </Popover>
99
+ ```
100
+
101
+ ### Simple
102
+
103
+ ```tsx
104
+ <Popover>
105
+ <PopoverTrigger asChild>
106
+ <Button variant="outline">Click me</Button>
107
+ </PopoverTrigger>
108
+ <PopoverContent>
109
+ <p>This is a simple popover with just text content.</p>
110
+ </PopoverContent>
111
+ </Popover>
112
+ ```
113
+
114
+ ### Con User Profile
115
+
116
+ ```tsx
117
+ import {
118
+ Avatar,
119
+ AvatarImage,
120
+ AvatarFallback,
121
+ } from "@adamosuiteservices/ui/avatar";
122
+ import { Icon } from "@adamosuiteservices/ui/icon";
123
+
124
+ <Popover>
125
+ <PopoverTrigger asChild>
126
+ <Button variant="ghost" className="h-auto p-2">
127
+ <Avatar className="h-8 w-8">
128
+ <AvatarImage src="https://github.com/shadcn.png" />
129
+ <AvatarFallback>SC</AvatarFallback>
130
+ </Avatar>
131
+ </Button>
132
+ </PopoverTrigger>
133
+ <PopoverContent className="w-80">
134
+ <div className="flex gap-4">
135
+ <Avatar>
136
+ <AvatarImage src="https://github.com/shadcn.png" />
137
+ <AvatarFallback>SC</AvatarFallback>
138
+ </Avatar>
139
+ <div className="space-y-1">
140
+ <h4 className="text-sm font-semibold">@shadcn</h4>
141
+ <p className="text-sm">
142
+ The React Framework – created and maintained by @vercel.
143
+ </p>
144
+ <div className="flex items-center pt-2">
145
+ <Icon symbol="calendar_month" className="mr-2 text-lg opacity-70" />
146
+ <span className="text-xs text-muted-foreground">
147
+ Joined December 2021
148
+ </span>
149
+ </div>
150
+ </div>
151
+ </div>
152
+ </PopoverContent>
153
+ </Popover>;
154
+ ```
155
+
156
+ ### Con Settings
157
+
158
+ ```tsx
159
+ import { Switch } from "@adamosuiteservices/ui/switch";
160
+ import { Separator } from "@adamosuiteservices/ui/separator";
161
+ import { Icon } from "@adamosuiteservices/ui/icon";
162
+
163
+ <Popover>
164
+ <PopoverTrigger asChild>
165
+ <Button variant="outline" size="icon">
166
+ <Icon symbol="settings" className="text-lg" />
167
+ </Button>
168
+ </PopoverTrigger>
169
+ <PopoverContent className="w-80">
170
+ <div className="grid gap-4">
171
+ <div className="space-y-2">
172
+ <h4 className="font-medium leading-none">Settings</h4>
173
+ <p className="text-sm text-muted-foreground">
174
+ Configure your preferences
175
+ </p>
176
+ </div>
177
+ <div className="grid gap-2">
178
+ <div className="flex items-center justify-between">
179
+ <Label htmlFor="notifications">Push notifications</Label>
180
+ <Switch id="notifications" />
181
+ </div>
182
+ <div className="flex items-center justify-between">
183
+ <Label htmlFor="emails">Email updates</Label>
184
+ <Switch id="emails" defaultChecked />
185
+ </div>
186
+ </div>
187
+ <Separator />
188
+ <div className="flex justify-between">
189
+ <Button variant="outline" size="sm">
190
+ Cancel
191
+ </Button>
192
+ <Button size="sm">Save changes</Button>
193
+ </div>
194
+ </div>
195
+ </PopoverContent>
196
+ </Popover>;
197
+ ```
198
+
199
+ ### Con Calendar
200
+
201
+ ```tsx
202
+ import { useState } from "react";
203
+ import { Calendar } from "@adamosuiteservices/ui/calendar";
204
+ import { Icon } from "@adamosuiteservices/ui/icon";
205
+
206
+ function App() {
207
+ const [date, setDate] = useState<Date | undefined>(new Date());
208
+
209
+ return (
210
+ <Popover>
211
+ <PopoverTrigger asChild>
212
+ <Button
213
+ variant="outline"
214
+ className={cn(
215
+ "w-[240px] justify-start text-left font-normal",
216
+ !date && "text-muted-foreground"
217
+ )}
218
+ >
219
+ <Icon symbol="calendar_month" className="mr-2 text-lg" />
220
+ {date ? date.toLocaleDateString() : "Pick a date"}
221
+ </Button>
222
+ </PopoverTrigger>
223
+ <PopoverContent className="w-auto p-0" align="start">
224
+ <Calendar
225
+ mode="single"
226
+ selected={date}
227
+ onSelect={setDate}
228
+ initialFocus
229
+ />
230
+ </PopoverContent>
231
+ </Popover>
232
+ );
233
+ }
234
+ ```
235
+
236
+ ### Con Counter
237
+
238
+ ```tsx
239
+ import { useState } from "react";
240
+ import { Icon } from "@adamosuiteservices/ui/icon";
241
+
242
+ function App() {
243
+ const [count, setCount] = useState(0);
244
+
245
+ return (
246
+ <Popover>
247
+ <PopoverTrigger asChild>
248
+ <Button variant="outline">Counter: {count}</Button>
249
+ </PopoverTrigger>
250
+ <PopoverContent className="w-64">
251
+ <div className="grid gap-4">
252
+ <div className="space-y-2">
253
+ <h4 className="font-medium leading-none">Counter Control</h4>
254
+ <p className="text-sm text-muted-foreground">
255
+ Adjust the counter value
256
+ </p>
257
+ </div>
258
+ <div className="flex items-center justify-center space-x-2">
259
+ <Button
260
+ variant="outline"
261
+ size="icon"
262
+ onClick={() => setCount(Math.max(0, count - 1))}
263
+ disabled={count === 0}
264
+ >
265
+ <Icon symbol="remove" className="text-lg" />
266
+ </Button>
267
+ <div className="flex items-center justify-center w-16 h-10 border rounded">
268
+ {count}
269
+ </div>
270
+ <Button
271
+ variant="outline"
272
+ size="icon"
273
+ onClick={() => setCount(count + 1)}
274
+ >
275
+ <Icon symbol="add" className="text-lg" />
276
+ </Button>
277
+ </div>
278
+ <div className="flex gap-2">
279
+ <Button variant="outline" size="sm" onClick={() => setCount(0)}>
280
+ Reset
281
+ </Button>
282
+ <Button size="sm" onClick={() => setCount(10)}>
283
+ Set to 10
284
+ </Button>
285
+ </div>
286
+ </div>
287
+ </PopoverContent>
288
+ </Popover>
289
+ );
290
+ }
291
+ ```
292
+
293
+ ### Con Info Icon
294
+
295
+ ```tsx
296
+ import { Icon } from "@adamosuiteservices/ui/icon";
297
+
298
+ <div className="flex items-center gap-4">
299
+ <span>Complex Feature</span>
300
+ <Popover>
301
+ <PopoverTrigger asChild>
302
+ <Button variant="ghost" size="icon" className="h-5 w-5">
303
+ <Icon symbol="info" className="text-sm" />
304
+ </Button>
305
+ </PopoverTrigger>
306
+ <PopoverContent className="w-80">
307
+ <div className="space-y-3">
308
+ <div className="flex items-center gap-2">
309
+ <Icon symbol="error" className="text-lg text-primary" />
310
+ <h4 className="font-medium">About this feature</h4>
311
+ </div>
312
+ <p className="text-sm text-muted-foreground">
313
+ This is a complex feature that requires additional explanation.
314
+ </p>
315
+ <div className="space-y-2">
316
+ <h5 className="text-sm font-medium">Key benefits:</h5>
317
+ <ul className="text-sm space-y-1 text-muted-foreground">
318
+ <li>• Improved performance</li>
319
+ <li>• Better user experience</li>
320
+ <li>• Advanced customization</li>
321
+ </ul>
322
+ </div>
323
+ </div>
324
+ </PopoverContent>
325
+ </Popover>
326
+ </div>;
327
+ ```
328
+
329
+ ### Con Notifications
330
+
331
+ ```tsx
332
+ import { Icon } from "@adamosuiteservices/ui/icon";
333
+ import { Badge } from "@adamosuiteservices/ui/badge";
334
+ import { Separator } from "@adamosuiteservices/ui/separator";
335
+
336
+ <Popover>
337
+ <PopoverTrigger asChild>
338
+ <Button variant="outline" size="icon" className="relative">
339
+ <Icon symbol="mail" className="text-lg" />
340
+ <Badge
341
+ className="absolute -top-2 -right-2 h-5 w-5 p-0 flex items-center justify-center"
342
+ variant="destructive"
343
+ >
344
+ 3
345
+ </Badge>
346
+ </Button>
347
+ </PopoverTrigger>
348
+ <PopoverContent className="w-80">
349
+ <div className="space-y-3">
350
+ <div className="flex items-center justify-between">
351
+ <h4 className="font-medium">Notifications</h4>
352
+ <Button variant="ghost" size="sm">
353
+ Mark all read
354
+ </Button>
355
+ </div>
356
+ <div className="space-y-2">
357
+ <div className="flex items-start gap-3 p-2 rounded hover:bg-muted bg-muted/50">
358
+ <div className="flex-1">
359
+ <p className="text-sm font-medium">New message</p>
360
+ <p className="text-xs text-muted-foreground">2 min ago</p>
361
+ </div>
362
+ <div className="h-2 w-2 bg-primary rounded-full mt-1" />
363
+ </div>
364
+ </div>
365
+ <Separator />
366
+ <Button variant="outline" size="sm" className="w-full">
367
+ View all notifications
368
+ </Button>
369
+ </div>
370
+ </PopoverContent>
371
+ </Popover>;
372
+ ```
373
+
374
+ ### Posicionamiento Custom
375
+
376
+ ```tsx
377
+ {
378
+ /* Top */
379
+ }
380
+ <Popover>
381
+ <PopoverTrigger asChild>
382
+ <Button variant="outline">Top</Button>
383
+ </PopoverTrigger>
384
+ <PopoverContent side="top">
385
+ <p>This popover appears on top</p>
386
+ </PopoverContent>
387
+ </Popover>;
388
+
389
+ {
390
+ /* Right */
391
+ }
392
+ <Popover>
393
+ <PopoverTrigger asChild>
394
+ <Button variant="outline">Right</Button>
395
+ </PopoverTrigger>
396
+ <PopoverContent side="right">
397
+ <p>This popover appears on the right</p>
398
+ </PopoverContent>
399
+ </Popover>;
400
+
401
+ {
402
+ /* Start aligned */
403
+ }
404
+ <Popover>
405
+ <PopoverTrigger asChild>
406
+ <Button variant="outline">Start aligned</Button>
407
+ </PopoverTrigger>
408
+ <PopoverContent align="start">
409
+ <p>This popover is aligned to the start</p>
410
+ </PopoverContent>
411
+ </Popover>;
412
+ ```
413
+
414
+ ### Con Anchor
415
+
416
+ ```tsx
417
+ <div className="space-y-4">
418
+ <p>
419
+ This is some text with an{" "}
420
+ <Popover>
421
+ <PopoverAnchor asChild>
422
+ <span className="underline cursor-pointer">anchored element</span>
423
+ </PopoverAnchor>
424
+ <PopoverTrigger asChild>
425
+ <Button variant="outline" className="ml-2">
426
+ Show info
427
+ </Button>
428
+ </PopoverTrigger>
429
+ <PopoverContent>
430
+ <p>This popover is anchored to the underlined text above!</p>
431
+ </PopoverContent>
432
+ </Popover>
433
+ </p>
434
+ </div>
435
+ ```
436
+
437
+ ### Controlado
438
+
439
+ ```tsx
440
+ import { useState } from "react";
441
+
442
+ function App() {
443
+ const [open, setOpen] = useState(false);
444
+
445
+ return (
446
+ <Popover open={open} onOpenChange={setOpen}>
447
+ <PopoverTrigger asChild>
448
+ <Button variant="outline">Toggle</Button>
449
+ </PopoverTrigger>
450
+ <PopoverContent>
451
+ <div className="space-y-2">
452
+ <p>Controlled popover content</p>
453
+ <Button onClick={() => setOpen(false)}>Close</Button>
454
+ </div>
455
+ </PopoverContent>
456
+ </Popover>
457
+ );
458
+ }
459
+ ```
460
+
461
+ ## Casos de Uso Comunes
462
+
463
+ **Date pickers**: Mostrar calendar en popover
464
+ **Settings**: Controles compactos de configuración
465
+ **User profiles**: Preview de perfiles al hover/click
466
+ **Notifications**: Lista de notificaciones
467
+ **Quick actions**: Acciones contextuales sin modal
468
+ **Info tooltips**: Información rica vs tooltip simple
469
+ **Forms**: Formularios compactos inline
470
+
471
+ ## Estados y Data Attributes
472
+
473
+ ### PopoverContent States
474
+
475
+ - **Open**: `data-[state=open]` → `animate-in`, `fade-in-0`, `zoom-in-95`
476
+ - **Closed**: `data-[state=closed]` → `animate-out`, `fade-out-0`, `zoom-out-95`
477
+
478
+ ### Side Animations
479
+
480
+ - **Top**: `data-[side=top]` → `slide-in-from-bottom-2`
481
+ - **Right**: `data-[side=right]` → `slide-in-from-left-2`
482
+ - **Bottom**: `data-[side=bottom]` → `slide-in-from-top-2`
483
+ - **Left**: `data-[side=left]` → `slide-in-from-right-2`
484
+
485
+ ## Interacción
486
+
487
+ - ✅ **Click to open**: Click en trigger abre popover
488
+ - ✅ **Click outside**: Click fuera cierra popover (si no es modal)
489
+ - ✅ **Escape**: Presionar Esc cierra popover
490
+ - ✅ **Focus trap**: Si `modal=true`, foco queda atrapado dentro
491
+ - ✅ **Keyboard**: Tab navega entre elementos internos
492
+
493
+ ## Accesibilidad
494
+
495
+ - ✅ **ARIA**: `role="dialog"`, `aria-labelledby`, `aria-describedby` según contenido
496
+ - ✅ **Focus management**: Focus automático al abrir
497
+ - ✅ **Keyboard**: Esc para cerrar, Tab para navegar
498
+ - ✅ **Portal**: Renderiza en `document.body` para evitar problemas de z-index
499
+ - ✅ **Modal mode**: `modal=true` para bloquear interacción fuera del popover
500
+
501
+ ## Notas de Implementación
502
+
503
+ - **Radix UI**: Basado en `@radix-ui/react-popover`
504
+ - **Portal rendering**: Content se renderiza en `document.body`
505
+ - **Collision detection**: Auto-ajusta posición si sale del viewport
506
+ - **Transform origin**: CSS variables de Radix para animaciones
507
+ - **Default width**: `w-72` (288px)
508
+ - **Default padding**: `p-4`
509
+ - **Z-index**: 50 para aparecer sobre contenido
510
+ - **Modal**: Por defecto `modal=false` (permite interacción fuera)
511
+
512
+ ## Diferencias con Dialog y HoverCard
513
+
514
+ | Aspecto | Popover | Dialog | HoverCard |
515
+ | ---------------- | ----------------- | --------------------- | --------------- |
516
+ | **Trigger** | Click | Click | Hover |
517
+ | **Modal** | Opcional | Siempre | No |
518
+ | **Backdrop** | Opcional | Sí | No |
519
+ | **Contenido** | Compacto | Extenso | Preview |
520
+ | **Persistencia** | Hasta click fuera | Hasta close explícito | Hasta hover out |
521
+
522
+ ## Troubleshooting
523
+
524
+ **No aparece**: Verifica que PopoverContent esté dentro de Popover root
525
+ **Posición incorrecta**: Ajusta `side`, `align`, `sideOffset` y `alignOffset`
526
+ **Contenido cortado**: Verifica que no haya `overflow: hidden` en containers
527
+ **No cierra**: Si `modal=true`, solo cierra con Esc o close explícito
528
+ **Focus no funciona**: Content debe tener elementos focuseables
529
+ **Backdrop no se ve**: Popover no tiene backdrop por defecto, usa `modal=true` y customiza
530
+ **Z-index issues**: Content usa portal, debe aparecer sobre todo
531
+ **Anchor no funciona**: PopoverAnchor debe estar dentro de Popover root
532
+
533
+ ## Referencias
534
+
535
+ - **Radix UI Popover**: <https://www.radix-ui.com/primitives/docs/components/popover>
536
+ - **shadcn/ui Popover**: <https://ui.shadcn.com/docs/components/popover>