@epilot/volt-ui-mcp 0.1.2 → 0.1.3

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 (4) hide show
  1. package/index.js +7 -3
  2. package/package.json +2 -2
  3. package/registry.json +2128 -426
  4. package/README.md +0 -186
package/registry.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-02-05T17:52:44.279Z",
3
+ "generatedAt": "2026-03-09T12:59:07.619Z",
4
4
  "components": [
5
5
  {
6
6
  "name": "Accordion",
@@ -241,7 +241,7 @@
241
241
  {
242
242
  "language": "tsx",
243
243
  "meta": "lineNumbers",
244
- "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n</AlertDialog>"
244
+ "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button, AlertDialogPortal } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogPortal container={document.getElementById(\"root\")}>\n <AlertDialogContent size=\"lg\">\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialogPortal>\n</AlertDialog>"
245
245
  }
246
246
  ]
247
247
  },
@@ -286,7 +286,7 @@
286
286
  {
287
287
  "language": "tsx",
288
288
  "meta": "lineNumbers",
289
- "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n</AlertDialog>"
289
+ "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button, AlertDialogPortal } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogPortal container={document.getElementById(\"root\")}>\n <AlertDialogContent size=\"lg\">\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialogPortal>\n</AlertDialog>"
290
290
  }
291
291
  ]
292
292
  },
@@ -314,6 +314,12 @@
314
314
  "default": "Button size for the cancel action.",
315
315
  "description": null
316
316
  },
317
+ {
318
+ "name": "`destructive`",
319
+ "type": "`boolean`",
320
+ "default": "`false`",
321
+ "description": "Destructive styling"
322
+ },
317
323
  {
318
324
  "name": "`className`",
319
325
  "type": "string",
@@ -325,7 +331,7 @@
325
331
  {
326
332
  "language": "tsx",
327
333
  "meta": "lineNumbers",
328
- "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n</AlertDialog>"
334
+ "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button, AlertDialogPortal } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogPortal container={document.getElementById(\"root\")}>\n <AlertDialogContent size=\"lg\">\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialogPortal>\n</AlertDialog>"
329
335
  }
330
336
  ]
331
337
  },
@@ -346,13 +352,19 @@
346
352
  "type": "string",
347
353
  "default": "-",
348
354
  "description": "Additional classes for the content."
355
+ },
356
+ {
357
+ "name": "`size`",
358
+ "type": "`\"xl\" | \"lg\" | \"md\" | \"sm\"`",
359
+ "default": "`\"xl\"`",
360
+ "description": "Size of the dialog."
349
361
  }
350
362
  ],
351
363
  "examples": [
352
364
  {
353
365
  "language": "tsx",
354
366
  "meta": "lineNumbers",
355
- "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n</AlertDialog>"
367
+ "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button, AlertDialogPortal } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogPortal container={document.getElementById(\"root\")}>\n <AlertDialogContent size=\"lg\">\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialogPortal>\n</AlertDialog>"
356
368
  }
357
369
  ]
358
370
  },
@@ -379,7 +391,7 @@
379
391
  {
380
392
  "language": "tsx",
381
393
  "meta": "lineNumbers",
382
- "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n</AlertDialog>"
394
+ "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button, AlertDialogPortal } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogPortal container={document.getElementById(\"root\")}>\n <AlertDialogContent size=\"lg\">\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialogPortal>\n</AlertDialog>"
383
395
  }
384
396
  ]
385
397
  },
@@ -406,7 +418,7 @@
406
418
  {
407
419
  "language": "tsx",
408
420
  "meta": "lineNumbers",
409
- "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n</AlertDialog>"
421
+ "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button, AlertDialogPortal } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogPortal container={document.getElementById(\"root\")}>\n <AlertDialogContent size=\"lg\">\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialogPortal>\n</AlertDialog>"
410
422
  }
411
423
  ]
412
424
  },
@@ -433,7 +445,7 @@
433
445
  {
434
446
  "language": "tsx",
435
447
  "meta": "lineNumbers",
436
- "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n</AlertDialog>"
448
+ "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button, AlertDialogPortal } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogPortal container={document.getElementById(\"root\")}>\n <AlertDialogContent size=\"lg\">\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialogPortal>\n</AlertDialog>"
437
449
  }
438
450
  ]
439
451
  },
@@ -460,7 +472,7 @@
460
472
  {
461
473
  "language": "tsx",
462
474
  "meta": "lineNumbers",
463
- "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n</AlertDialog>"
475
+ "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button, AlertDialogPortal } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogPortal container={document.getElementById(\"root\")}>\n <AlertDialogContent size=\"lg\">\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialogPortal>\n</AlertDialog>"
464
476
  }
465
477
  ]
466
478
  },
@@ -493,7 +505,7 @@
493
505
  {
494
506
  "language": "tsx",
495
507
  "meta": "lineNumbers",
496
- "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n</AlertDialog>"
508
+ "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button, AlertDialogPortal } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogPortal container={document.getElementById(\"root\")}>\n <AlertDialogContent size=\"lg\">\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialogPortal>\n</AlertDialog>"
497
509
  }
498
510
  ]
499
511
  },
@@ -520,7 +532,7 @@
520
532
  {
521
533
  "language": "tsx",
522
534
  "meta": "lineNumbers",
523
- "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n</AlertDialog>"
535
+ "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button, AlertDialogPortal } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogPortal container={document.getElementById(\"root\")}>\n <AlertDialogContent size=\"lg\">\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialogPortal>\n</AlertDialog>"
524
536
  }
525
537
  ]
526
538
  },
@@ -547,7 +559,7 @@
547
559
  {
548
560
  "language": "tsx",
549
561
  "meta": "lineNumbers",
550
- "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n</AlertDialog>"
562
+ "code": "import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Button, AlertDialogPortal } from \"@epilot/volt-ui\"\n\n<AlertDialog>\n <AlertDialogTrigger asChild>\n <Button destructive>Delete Account</Button>\n </AlertDialogTrigger>\n <AlertDialogPortal container={document.getElementById(\"root\")}>\n <AlertDialogContent size=\"lg\">\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction variant=\"primary\">Confirm</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialogPortal>\n</AlertDialog>"
551
563
  }
552
564
  ]
553
565
  },
@@ -565,9 +577,9 @@
565
577
  "props": [
566
578
  {
567
579
  "name": "`color`",
568
- "type": "\"blue\" | \"sky\" | \"mint\" | \"green\" | \"teal\" | \"cyan\" | \"indigo\" | \"purple\" | \"pink\" | \"red\" | \"orange\" | \"yellow\" | \"bronze\" | \"gray\"",
569
- "default": "`\"blue\"`",
570
- "description": "The color variant of the badge."
580
+ "type": "\"accent\" | \"neutral\" | \"success\" | \"warning\" | \"error\" | \"blue\" | \"sky\" | \"mint\" | \"green\" | \"teal\" | \"cyan\" | \"indigo\" | \"purple\" | \"pink\" | \"red\" | \"orange\" | \"yellow\" | \"bronze\" | \"gray\"",
581
+ "default": "`\"accent\"`",
582
+ "description": "The color variant. Semantic colors (accent, neutral, success, warning, error) are recommended for status. Named colors are available for custom categorization."
571
583
  },
572
584
  {
573
585
  "name": "`style`",
@@ -576,10 +588,10 @@
576
588
  "description": "The style variant of the badge."
577
589
  },
578
590
  {
579
- "name": "`shape`",
580
- "type": "\"default\" | \"rounded\"",
581
- "default": "`\"default\"`",
582
- "description": "The shape variant of the badge. \"default\" uses rounded corners, \"rounded\" uses a pill shape."
591
+ "name": "`size`",
592
+ "type": "\"sm\" | \"base\" | \"lg\"",
593
+ "default": "`\"base\"`",
594
+ "description": "The size variant of the badge."
583
595
  },
584
596
  {
585
597
  "name": "`asChild`",
@@ -598,7 +610,7 @@
598
610
  {
599
611
  "language": "tsx",
600
612
  "meta": "lineNumbers",
601
- "code": "import { Badge } from \"@epilot/volt-ui\"\n\n<Badge color=\"blue\" style=\"solid\">Blue</Badge>"
613
+ "code": "import { Badge } from \"@epilot/volt-ui\"\n\n<Badge color=\"accent\">Accent</Badge>\n<Badge color=\"success\">Success</Badge>\n<Badge color=\"error\">Error</Badge>"
602
614
  }
603
615
  ]
604
616
  },
@@ -774,6 +786,117 @@
774
786
  }
775
787
  ]
776
788
  },
789
+ {
790
+ "name": "Calendar",
791
+ "title": "Date Time Picker",
792
+ "description": "A date and time picker component with calendar and time selection.",
793
+ "docsPath": "docs/content/docs/components/date-time-picker.mdx",
794
+ "docSlug": "date-time-picker",
795
+ "documentationUrl": null,
796
+ "apiReferenceUrl": null,
797
+ "sourcePaths": [
798
+ "src/components/date-time-picker/date-time-picker.tsx"
799
+ ],
800
+ "props": [
801
+ {
802
+ "name": "`value`",
803
+ "type": "`Date`",
804
+ "default": "-",
805
+ "description": "The selected date."
806
+ },
807
+ {
808
+ "name": "`onChange`",
809
+ "type": "`(date: Date) => void`",
810
+ "default": "-",
811
+ "description": "Callback fired when a date is selected."
812
+ },
813
+ {
814
+ "name": "`onDateSelect`",
815
+ "type": "`() => void`",
816
+ "default": "-",
817
+ "description": "Callback fired after date selection (for closing picker)."
818
+ },
819
+ {
820
+ "name": "`disablePast`",
821
+ "type": "`boolean`",
822
+ "default": "`false`",
823
+ "description": "When true, past dates are disabled."
824
+ },
825
+ {
826
+ "name": "`locale`",
827
+ "type": "`\"en\" | \"de\" | \"fr\"`",
828
+ "default": "`\"de\"`",
829
+ "description": "Locale for month/day names."
830
+ },
831
+ {
832
+ "name": "`previousMonthLabel`",
833
+ "type": "`string`",
834
+ "default": "`\"Previous month\"`",
835
+ "description": "Aria-label for the previous month button."
836
+ },
837
+ {
838
+ "name": "`nextMonthLabel`",
839
+ "type": "`string`",
840
+ "default": "`\"Next month\"`",
841
+ "description": "Aria-label for the next month button."
842
+ },
843
+ {
844
+ "name": "`showTodayButton`",
845
+ "type": "`boolean`",
846
+ "default": "`false`",
847
+ "description": "When true, shows a \"Today\" button below the calendar."
848
+ },
849
+ {
850
+ "name": "`todayLabel`",
851
+ "type": "`string`",
852
+ "default": "`\"Today\"`",
853
+ "description": "Label for the Today button."
854
+ },
855
+ {
856
+ "name": "`currentTimeInTimezone`",
857
+ "type": "`Date`",
858
+ "default": "-",
859
+ "description": "Override \"now\" for timezone-aware past checks."
860
+ }
861
+ ],
862
+ "examples": [
863
+ {
864
+ "language": "tsx",
865
+ "meta": "lineNumbers",
866
+ "code": "import { useState } from \"react\"\nimport { DateTimePicker } from \"@epilot/volt-ui\"\n\nconst MyComponent = () => {\n const [value, setValue] = useState<Date>(new Date())\n\n return (\n <DateTimePicker\n label=\"Appointment\"\n value={value}\n onChange={setValue}\n locale=\"en\"\n />\n )\n}"
867
+ },
868
+ {
869
+ "language": "tsx",
870
+ "meta": "lineNumbers",
871
+ "code": "<DateTimePicker\n label=\"Future Date Only\"\n value={value}\n onChange={setValue}\n disablePast\n/>"
872
+ },
873
+ {
874
+ "language": "tsx",
875
+ "meta": "lineNumbers",
876
+ "code": "<DateTimePicker\n label=\"Date & Time\"\n value={value}\n onChange={setValue}\n error=\"Please select a valid date\"\n/>"
877
+ },
878
+ {
879
+ "language": "tsx",
880
+ "meta": "lineNumbers",
881
+ "code": "<DateTimePicker\n label=\"Termin\"\n value={value}\n onChange={setValue}\n locale=\"de\"\n format=\"dd.MM.yyyy HH:mm\"\n placeholder=\"tt.mm.jjjj hh:mm\"\n/>"
882
+ },
883
+ {
884
+ "language": "tsx",
885
+ "meta": "lineNumbers",
886
+ "code": "<DateTimePicker\n label=\"Select Date\"\n value={value}\n onChange={setValue}\n showTodayButton\n todayLabel=\"Today\"\n/>"
887
+ },
888
+ {
889
+ "language": "tsx",
890
+ "meta": "lineNumbers",
891
+ "code": "<DateTimePicker\n label=\"Side Layout\"\n value={value}\n onChange={setValue}\n timePickerPosition=\"side\"\n/>"
892
+ },
893
+ {
894
+ "language": "tsx",
895
+ "meta": "lineNumbers",
896
+ "code": "<DateTimePicker\n label=\"Side Layout + Today\"\n value={value}\n onChange={setValue}\n timePickerPosition=\"side\"\n showTodayButton\n todayLabel=\"Today\"\n/>"
897
+ }
898
+ ]
899
+ },
777
900
  {
778
901
  "name": "Callout",
779
902
  "title": "Callout",
@@ -1191,282 +1314,333 @@
1191
1314
  ]
1192
1315
  },
1193
1316
  {
1194
- "name": "DataTable",
1195
- "title": "Columns & Filtering",
1196
- "description": "Column visibility, resizing, pinning, and filtering options.",
1197
- "docsPath": "docs/content/docs/components/data-table/columns.mdx",
1198
- "docSlug": "data-table/columns",
1317
+ "name": "CollapsibleSidebar",
1318
+ "title": "Collapsible Sidebar",
1319
+ "description": "A sidebar panel that collapses to a narrow strip and expands on hover, used for navigation or supplementary content.",
1320
+ "docsPath": "docs/content/docs/components/collapsible-sidebar.mdx",
1321
+ "docSlug": "collapsible-sidebar",
1199
1322
  "documentationUrl": null,
1200
1323
  "apiReferenceUrl": null,
1201
1324
  "sourcePaths": [
1202
- "src/components/data-table/data-table.tsx"
1325
+ "src/components/collapsible-sidebar/collapsible-sidebar.tsx"
1203
1326
  ],
1204
- "props": [],
1205
- "examples": [
1327
+ "props": [
1206
1328
  {
1207
- "language": "tsx",
1208
- "meta": null,
1209
- "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableToolbar } from \"@epilot/volt-ui\"\nimport { IconSearch } from \"@tabler/icons-react\"\n\nfunction MyTable() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableGlobalFilter\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n >\n <DataTableToolbar>\n <div className=\"flex items-center gap-2 rounded-lg border border-gray-a6 px-3 py-1.5\">\n <IconSearch size={18} />\n <input\n type=\"text\"\n placeholder=\"Search all columns...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1329
+ "name": "`collapsed`",
1330
+ "type": "`boolean`",
1331
+ "default": "-",
1332
+ "description": "Controlled collapsed state."
1210
1333
  },
1211
1334
  {
1212
- "language": "tsx",
1213
- "meta": null,
1214
- "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent, DataTableToolbar, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n // Get current filter values\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n // Update status filter\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n // Update type filter\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableFiltering\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n >\n <DataTableToolbar>\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n <option value=\"overdue\">Overdue</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1335
+ "name": "`defaultCollapsed`",
1336
+ "type": "`boolean`",
1337
+ "default": "`false`",
1338
+ "description": "Uncontrolled default collapsed state."
1215
1339
  },
1216
1340
  {
1217
- "language": "tsx",
1218
- "meta": null,
1219
- "code": "import { useState } from \"react\"\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n DataTableColumnVisibility,\n} from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n return (\n <DataTable columns={columns} data={data} enableSorting>\n <DataTableToolbar>\n <div className=\"flex-1\" />\n {/* Use -mr-1 wrapper to align icon with toolbar edge (compensates for button hover padding) */}\n <div className=\"-mr-1\">\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1341
+ "name": "`onCollapsedChange`",
1342
+ "type": "`(collapsed: boolean) => void`",
1343
+ "default": "-",
1344
+ "description": "Callback fired when the collapsed state changes."
1345
+ },
1346
+ {
1347
+ "name": "`width`",
1348
+ "type": "`number | string`",
1349
+ "default": "`264`",
1350
+ "description": "Width of the sidebar when expanded."
1351
+ },
1352
+ {
1353
+ "name": "`collapsedWidth`",
1354
+ "type": "`number | string`",
1355
+ "default": "`64`",
1356
+ "description": "Width of the narrow strip when collapsed."
1357
+ },
1358
+ {
1359
+ "name": "`expandOnHover`",
1360
+ "type": "`boolean`",
1361
+ "default": "`true`",
1362
+ "description": "Whether to show a floating panel with full content on hover when collapsed."
1363
+ },
1364
+ {
1365
+ "name": "`hoverDelay`",
1366
+ "type": "`number`",
1367
+ "default": "`100`",
1368
+ "description": "Delay in milliseconds before the floating panel appears on hover."
1220
1369
  },
1370
+ {
1371
+ "name": "`className`",
1372
+ "type": "`string`",
1373
+ "default": "-",
1374
+ "description": "Additional CSS classes for the root container."
1375
+ }
1376
+ ],
1377
+ "examples": [
1221
1378
  {
1222
1379
  "language": "tsx",
1223
- "meta": null,
1224
- "code": "const columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: \"Invoice\",\n enableHiding: false, // This column won't appear in the visibility dropdown\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n // enableHiding defaults to true\n },\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n enableHiding: false, // Actions column should always be visible\n },\n]"
1380
+ "meta": "lineNumbers",
1381
+ "code": "import { useState } from \"react\"\nimport { CollapsibleSidebar, CollapsibleSidebarContent, CollapsibleSidebarCondensed, CollapsibleSidebarToggle } from \"@epilot/volt-ui\"\nimport { IconLayoutSidebar, IconLayoutSidebarFilled, IconFolder, IconFile, IconStar, IconClock } from \"@tabler/icons-react\"\n\nconst [collapsed, setCollapsed] = useState(false)\n\n<CollapsibleSidebar collapsed={collapsed} onCollapsedChange={setCollapsed}>\n {/* Full content — shown when expanded, and in floating panel on hover */}\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n <nav className=\"flex flex-col gap-1 p-4 flex-1 min-h-0\">\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg bg-blue-50 text-blue-700 text-sm font-medium\" href=\"#\">\n <IconFolder size={18} />\n All files\n </a>\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-100 text-gray-700 text-sm\" href=\"#\">\n <IconStar size={18} />\n Starred\n </a>\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-100 text-gray-700 text-sm\" href=\"#\">\n <IconClock size={18} />\n Recent\n </a>\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-100 text-gray-700 text-sm\" href=\"#\">\n <IconFile size={18} />\n Documents\n </a>\n </nav>\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {({ collapsed }) => collapsed\n ? <IconLayoutSidebarFilled size={18} className=\"text-blue-600\" />\n : <IconLayoutSidebar size={18} className=\"text-gray-500\" />}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n\n {/* Collapsed strip — icon for each section + toggle at bottom */}\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n <div className=\"flex flex-col items-center gap-2 flex-1\">\n <div className=\"p-2 rounded-lg bg-blue-50\">\n <IconFolder size={18} className=\"text-blue-600\" />\n </div>\n <div className=\"p-2 rounded-lg hover:bg-gray-100\">\n <IconStar size={18} className=\"text-gray-500\" />\n </div>\n <div className=\"p-2 rounded-lg hover:bg-gray-100\">\n <IconClock size={18} className=\"text-gray-500\" />\n </div>\n <div className=\"p-2 rounded-lg hover:bg-gray-100\">\n <IconFile size={18} className=\"text-gray-500\" />\n </div>\n </div>\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {({ collapsed }) => collapsed\n ? <IconLayoutSidebarFilled size={18} className=\"text-blue-600\" />\n : <IconLayoutSidebar size={18} className=\"text-gray-500\" />}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1225
1382
  },
1226
1383
  {
1227
1384
  "language": "tsx",
1228
- "meta": null,
1229
- "code": "import { Button } from \"@epilot/volt-ui\"\n\n<DataTableColumnVisibility\n label=\"Toggle columns\"\n trigger={\n <Button variant=\"tertiary\" size=\"sm\">\n Columns\n </Button>\n }\n/>"
1385
+ "meta": "lineNumbers",
1386
+ "code": "import { useState } from \"react\"\nimport { CollapsibleSidebar, CollapsibleSidebarContent, CollapsibleSidebarCondensed, CollapsibleSidebarToggle, Button } from \"@epilot/volt-ui\"\n\nconst [collapsed, setCollapsed] = useState(false)\n\n<div className=\"flex gap-2\">\n <Button variant=\"secondary\" size=\"sm\" onClick={() => setCollapsed(false)}>Expand</Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => setCollapsed(true)}>Collapse</Button>\n</div>\n\n<CollapsibleSidebar collapsed={collapsed} onCollapsedChange={setCollapsed}>\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n {/* nav items */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n {/* icon for each section */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1230
1387
  },
1231
1388
  {
1232
1389
  "language": "tsx",
1233
- "meta": null,
1234
- "code": "const columns: ColumnDef<Invoice>[] = [\n // ... other columns\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n meta: {\n visibilityLabel: \"Actions\", // Label shown in visibility dropdown\n },\n },\n]"
1390
+ "meta": "lineNumbers",
1391
+ "code": "<CollapsibleSidebar\n collapsed={collapsed}\n onCollapsedChange={setCollapsed}\n width={320}\n collapsedWidth={48}\n>\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n {/* nav items */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n {/* condensed icons */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1235
1392
  },
1236
1393
  {
1237
1394
  "language": "tsx",
1238
- "meta": null,
1239
- "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nconst columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: \"Invoice\",\n size: 120, // Initial width\n minSize: 80, // Minimum width when resizing\n maxSize: 200, // Maximum width when resizing\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n size: 120,\n },\n {\n accessorKey: \"type\",\n header: \"Type\",\n size: 100,\n enableResizing: false, // Disable resizing for this column\n },\n // ...more columns\n]\n\n// Column resizing is enabled by default\n<DataTable columns={columns} data={data}>\n <DataTableContent />\n</DataTable>\n\n// To disable column resizing:\n<DataTable columns={columns} data={data} disableColumnResizing>\n <DataTableContent />\n</DataTable>"
1395
+ "meta": "lineNumbers",
1396
+ "code": "<CollapsibleSidebar\n collapsed={collapsed}\n onCollapsedChange={setCollapsed}\n expandOnHover={false}\n>\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n {/* nav items */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n {/* condensed icons */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1240
1397
  },
1241
1398
  {
1242
1399
  "language": "tsx",
1243
1400
  "meta": null,
1244
- "code": "import { useState } from \"react\"\nimport type { ColumnSizingState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnSizing, setColumnSizing] = useState<ColumnSizingState>({\n id: 100,\n customer: 180,\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnSizing={columnSizing}\n onColumnSizingChange={setColumnSizing}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1401
+ "code": "<CollapsibleSidebarToggle>\n {({ collapsed }) => collapsed\n ? <IconLayoutSidebarFilled size={18} />\n : <IconLayoutSidebar size={18} />}\n</CollapsibleSidebarToggle>"
1245
1402
  },
1246
1403
  {
1247
1404
  "language": "tsx",
1248
1405
  "meta": null,
1249
- "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"id\",\n header: \"ID\",\n size: 60,\n enableResizing: false, // Cannot be resized\n },\n {\n accessorKey: \"name\",\n header: \"Name\",\n size: 150,\n minSize: 100, // Minimum 100px\n maxSize: 400, // Maximum 400px\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n // Uses defaults: minSize=20, maxSize=unlimited\n },\n]"
1406
+ "code": "import { useCollapsibleSidebar } from \"@epilot/volt-ui\"\n\nconst { collapsed, onCollapsedChange, width, collapsedWidth, isHovered, expandOnHover } = useCollapsibleSidebar()"
1407
+ }
1408
+ ]
1409
+ },
1410
+ {
1411
+ "name": "CollapsibleSidebarCondensed",
1412
+ "title": "Collapsible Sidebar",
1413
+ "description": "A sidebar panel that collapses to a narrow strip and expands on hover, used for navigation or supplementary content.",
1414
+ "docsPath": "docs/content/docs/components/collapsible-sidebar.mdx",
1415
+ "docSlug": "collapsible-sidebar",
1416
+ "documentationUrl": null,
1417
+ "apiReferenceUrl": null,
1418
+ "sourcePaths": [
1419
+ "src/components/collapsible-sidebar/collapsible-sidebar.tsx"
1420
+ ],
1421
+ "props": [
1422
+ {
1423
+ "name": "`className`",
1424
+ "type": "string",
1425
+ "default": "-",
1426
+ "description": "Additional CSS classes for the condensed strip."
1427
+ }
1428
+ ],
1429
+ "examples": [
1430
+ {
1431
+ "language": "tsx",
1432
+ "meta": "lineNumbers",
1433
+ "code": "import { useState } from \"react\"\nimport { CollapsibleSidebar, CollapsibleSidebarContent, CollapsibleSidebarCondensed, CollapsibleSidebarToggle } from \"@epilot/volt-ui\"\nimport { IconLayoutSidebar, IconLayoutSidebarFilled, IconFolder, IconFile, IconStar, IconClock } from \"@tabler/icons-react\"\n\nconst [collapsed, setCollapsed] = useState(false)\n\n<CollapsibleSidebar collapsed={collapsed} onCollapsedChange={setCollapsed}>\n {/* Full content — shown when expanded, and in floating panel on hover */}\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n <nav className=\"flex flex-col gap-1 p-4 flex-1 min-h-0\">\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg bg-blue-50 text-blue-700 text-sm font-medium\" href=\"#\">\n <IconFolder size={18} />\n All files\n </a>\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-100 text-gray-700 text-sm\" href=\"#\">\n <IconStar size={18} />\n Starred\n </a>\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-100 text-gray-700 text-sm\" href=\"#\">\n <IconClock size={18} />\n Recent\n </a>\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-100 text-gray-700 text-sm\" href=\"#\">\n <IconFile size={18} />\n Documents\n </a>\n </nav>\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {({ collapsed }) => collapsed\n ? <IconLayoutSidebarFilled size={18} className=\"text-blue-600\" />\n : <IconLayoutSidebar size={18} className=\"text-gray-500\" />}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n\n {/* Collapsed strip — icon for each section + toggle at bottom */}\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n <div className=\"flex flex-col items-center gap-2 flex-1\">\n <div className=\"p-2 rounded-lg bg-blue-50\">\n <IconFolder size={18} className=\"text-blue-600\" />\n </div>\n <div className=\"p-2 rounded-lg hover:bg-gray-100\">\n <IconStar size={18} className=\"text-gray-500\" />\n </div>\n <div className=\"p-2 rounded-lg hover:bg-gray-100\">\n <IconClock size={18} className=\"text-gray-500\" />\n </div>\n <div className=\"p-2 rounded-lg hover:bg-gray-100\">\n <IconFile size={18} className=\"text-gray-500\" />\n </div>\n </div>\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {({ collapsed }) => collapsed\n ? <IconLayoutSidebarFilled size={18} className=\"text-blue-600\" />\n : <IconLayoutSidebar size={18} className=\"text-gray-500\" />}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1250
1434
  },
1251
1435
  {
1252
1436
  "language": "tsx",
1253
- "meta": null,
1254
- "code": "// Default: handles appear on header hover\n<DataTable columns={columns} data={data}>\n <DataTableContent />\n</DataTable>\n\n// Always show resize handles\n<DataTable columns={columns} data={data} resizeHandleVisibility=\"always\">\n <DataTableContent />\n</DataTable>"
1437
+ "meta": "lineNumbers",
1438
+ "code": "import { useState } from \"react\"\nimport { CollapsibleSidebar, CollapsibleSidebarContent, CollapsibleSidebarCondensed, CollapsibleSidebarToggle, Button } from \"@epilot/volt-ui\"\n\nconst [collapsed, setCollapsed] = useState(false)\n\n<div className=\"flex gap-2\">\n <Button variant=\"secondary\" size=\"sm\" onClick={() => setCollapsed(false)}>Expand</Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => setCollapsed(true)}>Collapse</Button>\n</div>\n\n<CollapsibleSidebar collapsed={collapsed} onCollapsedChange={setCollapsed}>\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n {/* nav items */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n {/* icon for each section */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1255
1439
  },
1256
1440
  {
1257
1441
  "language": "tsx",
1258
- "meta": null,
1259
- "code": "import { useState } from \"react\"\nimport type { RowSelectionState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [rowSelection, setRowSelection] = useState<RowSelectionState>({})\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableRowSelection\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n autoPinSelection // Pin checkbox column when rows are selected\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1442
+ "meta": "lineNumbers",
1443
+ "code": "<CollapsibleSidebar\n collapsed={collapsed}\n onCollapsedChange={setCollapsed}\n width={320}\n collapsedWidth={48}\n>\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n {/* nav items */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n {/* condensed icons */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1260
1444
  },
1261
1445
  {
1262
1446
  "language": "tsx",
1263
- "meta": null,
1264
- "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\n<DataTable\n columns={columns}\n data={data}\n columnPinning={{ left: [\"id\"], right: [\"actions\"] }}\n>\n <DataTableContent />\n</DataTable>"
1447
+ "meta": "lineNumbers",
1448
+ "code": "<CollapsibleSidebar\n collapsed={collapsed}\n onCollapsedChange={setCollapsed}\n expandOnHover={false}\n>\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n {/* nav items */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n {/* condensed icons */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1265
1449
  },
1266
1450
  {
1267
1451
  "language": "tsx",
1268
1452
  "meta": null,
1269
- "code": "import { useState } from \"react\"\nimport type { ColumnPinningState } from \"@epilot/volt-ui\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnPinning, setColumnPinning] = useState<ColumnPinningState>({\n left: [\"id\"],\n right: [],\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnPinning={columnPinning}\n onColumnPinningChange={setColumnPinning}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1453
+ "code": "<CollapsibleSidebarToggle>\n {({ collapsed }) => collapsed\n ? <IconLayoutSidebarFilled size={18} />\n : <IconLayoutSidebar size={18} />}\n</CollapsibleSidebarToggle>"
1270
1454
  },
1271
1455
  {
1272
1456
  "language": "tsx",
1273
1457
  "meta": null,
1274
- "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\n// Compact rows (smallest)\n<DataTable columns={columns} data={data} density=\"compact\">\n <DataTableContent />\n</DataTable>\n\n// Normal rows (default)\n<DataTable columns={columns} data={data} density=\"normal\">\n <DataTableContent />\n</DataTable>\n\n// Comfortable rows (largest)\n<DataTable columns={columns} data={data} density=\"comfortable\">\n <DataTableContent />\n</DataTable>"
1458
+ "code": "import { useCollapsibleSidebar } from \"@epilot/volt-ui\"\n\nconst { collapsed, onCollapsedChange, width, collapsedWidth, isHovered, expandOnHover } = useCollapsibleSidebar()"
1275
1459
  }
1276
1460
  ]
1277
1461
  },
1278
1462
  {
1279
- "name": "DataTableBody",
1280
- "title": "Data Table",
1281
- "description": "A powerful data table component built on Tanstack Table with support for sorting, filtering, pagination, row selection, and virtualization.",
1282
- "docsPath": "docs/content/docs/components/data-table/index.mdx",
1283
- "docSlug": "data-table/index",
1463
+ "name": "CollapsibleSidebarContent",
1464
+ "title": "Collapsible Sidebar",
1465
+ "description": "A sidebar panel that collapses to a narrow strip and expands on hover, used for navigation or supplementary content.",
1466
+ "docsPath": "docs/content/docs/components/collapsible-sidebar.mdx",
1467
+ "docSlug": "collapsible-sidebar",
1284
1468
  "documentationUrl": null,
1285
1469
  "apiReferenceUrl": null,
1286
1470
  "sourcePaths": [
1287
- "src/components/data-table/data-table-body.tsx"
1471
+ "src/components/collapsible-sidebar/collapsible-sidebar.tsx"
1472
+ ],
1473
+ "props": [
1474
+ {
1475
+ "name": "`className`",
1476
+ "type": "string",
1477
+ "default": "-",
1478
+ "description": "Additional CSS classes for the inline aside element."
1479
+ }
1288
1480
  ],
1289
- "props": [],
1290
1481
  "examples": [
1291
1482
  {
1292
1483
  "language": "tsx",
1293
- "meta": null,
1294
- "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\ntype Invoice = {\n id: string\n status: string\n customer: string\n amount: number\n}\n\nconst columns: ColumnDef<Invoice>[] = [\n { accessorKey: \"id\", header: \"Invoice\" },\n { accessorKey: \"status\", header: \"Status\" },\n { accessorKey: \"customer\", header: \"Customer\" },\n { accessorKey: \"amount\", header: \"Amount\" },\n]\n\n// Column resizing is enabled by default. Disable if you prefer fixed columns:\n<DataTable columns={columns} data={invoices} disableColumnResizing>\n <DataTableContent />\n</DataTable>"
1484
+ "meta": "lineNumbers",
1485
+ "code": "import { useState } from \"react\"\nimport { CollapsibleSidebar, CollapsibleSidebarContent, CollapsibleSidebarCondensed, CollapsibleSidebarToggle } from \"@epilot/volt-ui\"\nimport { IconLayoutSidebar, IconLayoutSidebarFilled, IconFolder, IconFile, IconStar, IconClock } from \"@tabler/icons-react\"\n\nconst [collapsed, setCollapsed] = useState(false)\n\n<CollapsibleSidebar collapsed={collapsed} onCollapsedChange={setCollapsed}>\n {/* Full content — shown when expanded, and in floating panel on hover */}\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n <nav className=\"flex flex-col gap-1 p-4 flex-1 min-h-0\">\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg bg-blue-50 text-blue-700 text-sm font-medium\" href=\"#\">\n <IconFolder size={18} />\n All files\n </a>\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-100 text-gray-700 text-sm\" href=\"#\">\n <IconStar size={18} />\n Starred\n </a>\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-100 text-gray-700 text-sm\" href=\"#\">\n <IconClock size={18} />\n Recent\n </a>\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-100 text-gray-700 text-sm\" href=\"#\">\n <IconFile size={18} />\n Documents\n </a>\n </nav>\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {({ collapsed }) => collapsed\n ? <IconLayoutSidebarFilled size={18} className=\"text-blue-600\" />\n : <IconLayoutSidebar size={18} className=\"text-gray-500\" />}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n\n {/* Collapsed strip — icon for each section + toggle at bottom */}\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n <div className=\"flex flex-col items-center gap-2 flex-1\">\n <div className=\"p-2 rounded-lg bg-blue-50\">\n <IconFolder size={18} className=\"text-blue-600\" />\n </div>\n <div className=\"p-2 rounded-lg hover:bg-gray-100\">\n <IconStar size={18} className=\"text-gray-500\" />\n </div>\n <div className=\"p-2 rounded-lg hover:bg-gray-100\">\n <IconClock size={18} className=\"text-gray-500\" />\n </div>\n <div className=\"p-2 rounded-lg hover:bg-gray-100\">\n <IconFile size={18} className=\"text-gray-500\" />\n </div>\n </div>\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {({ collapsed }) => collapsed\n ? <IconLayoutSidebarFilled size={18} className=\"text-blue-600\" />\n : <IconLayoutSidebar size={18} className=\"text-gray-500\" />}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1295
1486
  },
1296
1487
  {
1297
1488
  "language": "tsx",
1298
- "meta": null,
1299
- "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction FullExample() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [rowSelection, setRowSelection] = useState({})\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n enableRowSelection\n enableGlobalFilter\n enableFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{ pageSize: 10 }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
1489
+ "meta": "lineNumbers",
1490
+ "code": "import { useState } from \"react\"\nimport { CollapsibleSidebar, CollapsibleSidebarContent, CollapsibleSidebarCondensed, CollapsibleSidebarToggle, Button } from \"@epilot/volt-ui\"\n\nconst [collapsed, setCollapsed] = useState(false)\n\n<div className=\"flex gap-2\">\n <Button variant=\"secondary\" size=\"sm\" onClick={() => setCollapsed(false)}>Expand</Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => setCollapsed(true)}>Collapse</Button>\n</div>\n\n<CollapsibleSidebar collapsed={collapsed} onCollapsedChange={setCollapsed}>\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n {/* nav items */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n {/* icon for each section */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1300
1491
  },
1301
1492
  {
1302
1493
  "language": "tsx",
1303
- "meta": null,
1304
- "code": "import { useState, useMemo } from \"react\"\nimport type { ColumnFiltersState, PaginationState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction ServerExample() {\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 10,\n })\n const [sorting, setSorting] = useState<SortingState>([])\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [rowSelection, setRowSelection] = useState({})\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n // In a real app, use useQuery with pagination/sorting/filters as query keys\n const { data, totalItems } = useServerData({\n pagination,\n sorting,\n globalFilter,\n statusFilter,\n typeFilter,\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n manualSorting\n enableRowSelection\n enableGlobalFilter\n enableFiltering\n manualFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{\n pageIndex: pagination.pageIndex,\n pageSize: pagination.pageSize,\n totalItems: totalItems,\n onPaginationChange: setPagination,\n }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => {\n setGlobalFilter(e.target.value)\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button\n variant=\"tertiary\"\n size=\"sm\"\n onClick={() => {\n setColumnFilters([])\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n >\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
1494
+ "meta": "lineNumbers",
1495
+ "code": "<CollapsibleSidebar\n collapsed={collapsed}\n onCollapsedChange={setCollapsed}\n width={320}\n collapsedWidth={48}\n>\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n {/* nav items */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n {/* condensed icons */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1305
1496
  },
1306
1497
  {
1307
1498
  "language": "tsx",
1308
- "meta": null,
1309
- "code": "<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
1499
+ "meta": "lineNumbers",
1500
+ "code": "<CollapsibleSidebar\n collapsed={collapsed}\n onCollapsedChange={setCollapsed}\n expandOnHover={false}\n>\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n {/* nav items */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n {/* condensed icons */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1310
1501
  },
1311
1502
  {
1312
1503
  "language": "tsx",
1313
1504
  "meta": null,
1314
- "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"description\",\n header: \"Description\",\n size: 200,\n meta: { cellOverflow: \"wrap\" }, // This column wraps, others truncate\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n // Uses table default\n },\n]\n\n<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
1505
+ "code": "<CollapsibleSidebarToggle>\n {({ collapsed }) => collapsed\n ? <IconLayoutSidebarFilled size={18} />\n : <IconLayoutSidebar size={18} />}\n</CollapsibleSidebarToggle>"
1315
1506
  },
1316
1507
  {
1317
1508
  "language": "tsx",
1318
1509
  "meta": null,
1319
- "code": "import { DataTable, DataTableContent, DataTableColumnHeader } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nconst columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Invoice\" />,\n },\n {\n accessorKey: \"customer\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Customer\" />,\n },\n // ...more columns\n]\n\n<DataTable columns={columns} data={data} enableSorting>\n <DataTableContent />\n</DataTable>"
1510
+ "code": "import { useCollapsibleSidebar } from \"@epilot/volt-ui\"\n\nconst { collapsed, onCollapsedChange, width, collapsedWidth, isHovered, expandOnHover } = useCollapsibleSidebar()"
1511
+ }
1512
+ ]
1513
+ },
1514
+ {
1515
+ "name": "CollapsibleSidebarToggle",
1516
+ "title": "Collapsible Sidebar",
1517
+ "description": "A sidebar panel that collapses to a narrow strip and expands on hover, used for navigation or supplementary content.",
1518
+ "docsPath": "docs/content/docs/components/collapsible-sidebar.mdx",
1519
+ "docSlug": "collapsible-sidebar",
1520
+ "documentationUrl": null,
1521
+ "apiReferenceUrl": null,
1522
+ "sourcePaths": [
1523
+ "src/components/collapsible-sidebar/collapsible-sidebar.tsx"
1524
+ ],
1525
+ "props": [
1526
+ {
1527
+ "name": "`className`",
1528
+ "type": "`string`",
1529
+ "default": "-",
1530
+ "description": "Additional CSS classes for the toggle button. Add `border-t border-gray-100` for a separator, `justify-center` for condensed strip, `justify-end` for expanded sidebar."
1320
1531
  },
1532
+ {
1533
+ "name": "`children`",
1534
+ "type": "`ReactNode | (({ collapsed }) => ReactNode)`",
1535
+ "default": "-",
1536
+ "description": "Icon or content to render inside the button. Pass a function to receive `{ collapsed }` for icon switching."
1537
+ }
1538
+ ],
1539
+ "examples": [
1321
1540
  {
1322
1541
  "language": "tsx",
1323
- "meta": null,
1324
- "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableFooter, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [pageSize, setPageSize] = useState(5)\n const visibleData = data.slice(0, pageSize)\n const hasMore = pageSize < data.length\n\n return (\n <DataTable columns={columns} data={visibleData}>\n <DataTableContent />\n {hasMore && (\n <DataTableFooter className=\"justify-start\">\n <Button size=\"sm\" variant=\"tertiary\" onClick={() => setPageSize((prev) => prev + 3)}>\n Show more ({data.length - pageSize} remaining)\n </Button>\n </DataTableFooter>\n )}\n </DataTable>\n )\n}"
1542
+ "meta": "lineNumbers",
1543
+ "code": "import { useState } from \"react\"\nimport { CollapsibleSidebar, CollapsibleSidebarContent, CollapsibleSidebarCondensed, CollapsibleSidebarToggle } from \"@epilot/volt-ui\"\nimport { IconLayoutSidebar, IconLayoutSidebarFilled, IconFolder, IconFile, IconStar, IconClock } from \"@tabler/icons-react\"\n\nconst [collapsed, setCollapsed] = useState(false)\n\n<CollapsibleSidebar collapsed={collapsed} onCollapsedChange={setCollapsed}>\n {/* Full content — shown when expanded, and in floating panel on hover */}\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n <nav className=\"flex flex-col gap-1 p-4 flex-1 min-h-0\">\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg bg-blue-50 text-blue-700 text-sm font-medium\" href=\"#\">\n <IconFolder size={18} />\n All files\n </a>\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-100 text-gray-700 text-sm\" href=\"#\">\n <IconStar size={18} />\n Starred\n </a>\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-100 text-gray-700 text-sm\" href=\"#\">\n <IconClock size={18} />\n Recent\n </a>\n <a className=\"flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-gray-100 text-gray-700 text-sm\" href=\"#\">\n <IconFile size={18} />\n Documents\n </a>\n </nav>\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {({ collapsed }) => collapsed\n ? <IconLayoutSidebarFilled size={18} className=\"text-blue-600\" />\n : <IconLayoutSidebar size={18} className=\"text-gray-500\" />}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n\n {/* Collapsed strip icon for each section + toggle at bottom */}\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n <div className=\"flex flex-col items-center gap-2 flex-1\">\n <div className=\"p-2 rounded-lg bg-blue-50\">\n <IconFolder size={18} className=\"text-blue-600\" />\n </div>\n <div className=\"p-2 rounded-lg hover:bg-gray-100\">\n <IconStar size={18} className=\"text-gray-500\" />\n </div>\n <div className=\"p-2 rounded-lg hover:bg-gray-100\">\n <IconClock size={18} className=\"text-gray-500\" />\n </div>\n <div className=\"p-2 rounded-lg hover:bg-gray-100\">\n <IconFile size={18} className=\"text-gray-500\" />\n </div>\n </div>\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {({ collapsed }) => collapsed\n ? <IconLayoutSidebarFilled size={18} className=\"text-blue-600\" />\n : <IconLayoutSidebar size={18} className=\"text-gray-500\" />}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1325
1544
  },
1326
1545
  {
1327
1546
  "language": "tsx",
1328
- "meta": null,
1329
- "code": "{\n accessorKey: \"name\",\n header: \"Name\",\n}"
1547
+ "meta": "lineNumbers",
1548
+ "code": "import { useState } from \"react\"\nimport { CollapsibleSidebar, CollapsibleSidebarContent, CollapsibleSidebarCondensed, CollapsibleSidebarToggle, Button } from \"@epilot/volt-ui\"\n\nconst [collapsed, setCollapsed] = useState(false)\n\n<div className=\"flex gap-2\">\n <Button variant=\"secondary\" size=\"sm\" onClick={() => setCollapsed(false)}>Expand</Button>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => setCollapsed(true)}>Collapse</Button>\n</div>\n\n<CollapsibleSidebar collapsed={collapsed} onCollapsedChange={setCollapsed}>\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n {/* nav items */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n {/* icon for each section */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1330
1549
  },
1331
1550
  {
1332
1551
  "language": "tsx",
1333
- "meta": null,
1334
- "code": "{\n accessorKey: \"status\",\n header: \"Status\",\n cell: ({ row }) => <Badge>{row.getValue(\"status\")}</Badge>,\n}"
1552
+ "meta": "lineNumbers",
1553
+ "code": "<CollapsibleSidebar\n collapsed={collapsed}\n onCollapsedChange={setCollapsed}\n width={320}\n collapsedWidth={48}\n>\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n {/* nav items */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n {/* condensed icons */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1335
1554
  },
1336
1555
  {
1337
1556
  "language": "tsx",
1338
- "meta": null,
1339
- "code": "{\n accessorKey: \"date\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Date\" />,\n}"
1557
+ "meta": "lineNumbers",
1558
+ "code": "<CollapsibleSidebar\n collapsed={collapsed}\n onCollapsedChange={setCollapsed}\n expandOnHover={false}\n>\n <CollapsibleSidebarContent className=\"bg-white border-r\">\n {/* nav items */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-end\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarContent>\n <CollapsibleSidebarCondensed className=\"bg-white border-r h-full\">\n {/* condensed icons */}\n <CollapsibleSidebarToggle className=\"border-t border-gray-100 justify-center\">\n {/* toggle icon */}\n </CollapsibleSidebarToggle>\n </CollapsibleSidebarCondensed>\n</CollapsibleSidebar>"
1340
1559
  },
1341
1560
  {
1342
1561
  "language": "tsx",
1343
1562
  "meta": null,
1344
- "code": "{\n accessorKey: \"amount\",\n header: () => <div className=\"text-right\">Amount</div>,\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" },\n}"
1563
+ "code": "<CollapsibleSidebarToggle>\n {({ collapsed }) => collapsed\n ? <IconLayoutSidebarFilled size={18} />\n : <IconLayoutSidebar size={18} />}\n</CollapsibleSidebarToggle>"
1345
1564
  },
1346
1565
  {
1347
1566
  "language": "tsx",
1348
1567
  "meta": null,
1349
- "code": "{\n accessorKey: \"amount\",\n header: ({ column }) => (\n <div className=\"flex justify-end\">\n <DataTableColumnHeader column={column} title=\"Amount\" />\n </div>\n ),\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" }, // Ensures proper header padding alignment\n}"
1568
+ "code": "import { useCollapsibleSidebar } from \"@epilot/volt-ui\"\n\nconst { collapsed, onCollapsedChange, width, collapsedWidth, isHovered, expandOnHover } = useCollapsibleSidebar()"
1350
1569
  }
1351
1570
  ]
1352
1571
  },
1353
1572
  {
1354
- "name": "DataTableColumnHeader",
1355
- "title": "Data Table",
1356
- "description": "A powerful data table component built on Tanstack Table with support for sorting, filtering, pagination, row selection, and virtualization.",
1357
- "docsPath": "docs/content/docs/components/data-table/index.mdx",
1358
- "docSlug": "data-table/index",
1573
+ "name": "DataTable",
1574
+ "title": "Columns & Filtering",
1575
+ "description": "Column visibility, resizing, pinning, and filtering options.",
1576
+ "docsPath": "docs/content/docs/components/data-table/columns.mdx",
1577
+ "docSlug": "data-table/columns",
1359
1578
  "documentationUrl": null,
1360
1579
  "apiReferenceUrl": null,
1361
1580
  "sourcePaths": [
1362
- "src/components/data-table/data-table-column-header.tsx"
1581
+ "src/components/data-table/data-table.tsx"
1363
1582
  ],
1364
1583
  "props": [],
1365
1584
  "examples": [
1366
1585
  {
1367
1586
  "language": "tsx",
1368
1587
  "meta": null,
1369
- "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\ntype Invoice = {\n id: string\n status: string\n customer: string\n amount: number\n}\n\nconst columns: ColumnDef<Invoice>[] = [\n { accessorKey: \"id\", header: \"Invoice\" },\n { accessorKey: \"status\", header: \"Status\" },\n { accessorKey: \"customer\", header: \"Customer\" },\n { accessorKey: \"amount\", header: \"Amount\" },\n]\n\n// Column resizing is enabled by default. Disable if you prefer fixed columns:\n<DataTable columns={columns} data={invoices} disableColumnResizing>\n <DataTableContent />\n</DataTable>"
1588
+ "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableToolbar } from \"@epilot/volt-ui\"\nimport { IconSearch } from \"@tabler/icons-react\"\n\nfunction MyTable() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableGlobalFilter\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n >\n <DataTableToolbar>\n <div className=\"flex items-center gap-2 rounded-lg border border-gray-a6 px-3 py-1.5\">\n <IconSearch size={18} />\n <input\n type=\"text\"\n placeholder=\"Search all columns...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1370
1589
  },
1371
1590
  {
1372
1591
  "language": "tsx",
1373
1592
  "meta": null,
1374
- "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction FullExample() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [rowSelection, setRowSelection] = useState({})\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n enableRowSelection\n enableGlobalFilter\n enableFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{ pageSize: 10 }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
1593
+ "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent, DataTableToolbar, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n // Get current filter values\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n // Update status filter\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n // Update type filter\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableFiltering\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n >\n <DataTableToolbar>\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n <option value=\"overdue\">Overdue</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1375
1594
  },
1376
1595
  {
1377
1596
  "language": "tsx",
1378
1597
  "meta": null,
1379
- "code": "import { useState, useMemo } from \"react\"\nimport type { ColumnFiltersState, PaginationState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction ServerExample() {\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 10,\n })\n const [sorting, setSorting] = useState<SortingState>([])\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [rowSelection, setRowSelection] = useState({})\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n // In a real app, use useQuery with pagination/sorting/filters as query keys\n const { data, totalItems } = useServerData({\n pagination,\n sorting,\n globalFilter,\n statusFilter,\n typeFilter,\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n manualSorting\n enableRowSelection\n enableGlobalFilter\n enableFiltering\n manualFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{\n pageIndex: pagination.pageIndex,\n pageSize: pagination.pageSize,\n totalItems: totalItems,\n onPaginationChange: setPagination,\n }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => {\n setGlobalFilter(e.target.value)\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button\n variant=\"tertiary\"\n size=\"sm\"\n onClick={() => {\n setColumnFilters([])\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n >\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
1598
+ "code": "import { useState } from \"react\"\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n DataTableColumnVisibility,\n} from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n return (\n <DataTable columns={columns} data={data} enableSorting>\n <DataTableToolbar>\n <div className=\"flex-1\" />\n {/* Use -mr-1 wrapper to align icon with toolbar edge (compensates for button hover padding) */}\n <div className=\"-mr-1\">\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1380
1599
  },
1381
1600
  {
1382
1601
  "language": "tsx",
1383
1602
  "meta": null,
1384
- "code": "<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
1603
+ "code": "const columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: \"Invoice\",\n enableHiding: false, // This column won't appear in the visibility dropdown\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n // enableHiding defaults to true\n },\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n enableHiding: false, // Actions column should always be visible\n },\n]"
1385
1604
  },
1386
1605
  {
1387
1606
  "language": "tsx",
1388
1607
  "meta": null,
1389
- "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"description\",\n header: \"Description\",\n size: 200,\n meta: { cellOverflow: \"wrap\" }, // This column wraps, others truncate\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n // Uses table default\n },\n]\n\n<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
1608
+ "code": "import { Button } from \"@epilot/volt-ui\"\n\n<DataTableColumnVisibility\n label=\"Toggle columns\"\n trigger={\n <Button variant=\"tertiary\" size=\"sm\">\n Columns\n </Button>\n }\n/>"
1390
1609
  },
1391
1610
  {
1392
1611
  "language": "tsx",
1393
1612
  "meta": null,
1394
- "code": "import { DataTable, DataTableContent, DataTableColumnHeader } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nconst columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Invoice\" />,\n },\n {\n accessorKey: \"customer\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Customer\" />,\n },\n // ...more columns\n]\n\n<DataTable columns={columns} data={data} enableSorting>\n <DataTableContent />\n</DataTable>"
1613
+ "code": "const columns: ColumnDef<Invoice>[] = [\n // ... other columns\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n meta: {\n visibilityLabel: \"Actions\", // Label shown in visibility dropdown\n },\n },\n]"
1395
1614
  },
1396
1615
  {
1397
1616
  "language": "tsx",
1398
1617
  "meta": null,
1399
- "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableFooter, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [pageSize, setPageSize] = useState(5)\n const visibleData = data.slice(0, pageSize)\n const hasMore = pageSize < data.length\n\n return (\n <DataTable columns={columns} data={visibleData}>\n <DataTableContent />\n {hasMore && (\n <DataTableFooter className=\"justify-start\">\n <Button size=\"sm\" variant=\"tertiary\" onClick={() => setPageSize((prev) => prev + 3)}>\n Show more ({data.length - pageSize} remaining)\n </Button>\n </DataTableFooter>\n )}\n </DataTable>\n )\n}"
1618
+ "code": "<DataTable columns={columns} data={data} enableColumnOrdering>\n <DataTableContent />\n</DataTable>"
1400
1619
  },
1401
1620
  {
1402
1621
  "language": "tsx",
1403
1622
  "meta": null,
1404
- "code": "{\n accessorKey: \"name\",\n header: \"Name\",\n}"
1623
+ "code": "import { useState } from \"react\"\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n DataTableColumnOrder,\n DataTableColumnVisibility,\n type ColumnOrderState,\n} from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnOrder, setColumnOrder] = useState<ColumnOrderState>([])\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnOrder={columnOrder}\n onColumnOrderChange={setColumnOrder}\n >\n <DataTableToolbar>\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1405
1624
  },
1406
1625
  {
1407
1626
  "language": "tsx",
1408
1627
  "meta": null,
1409
- "code": "{\n accessorKey: \"status\",\n header: \"Status\",\n cell: ({ row }) => <Badge>{row.getValue(\"status\")}</Badge>,\n}"
1628
+ "code": "<DataTable columns={columns} data={data}>\n <DataTableToolbar>\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n </DataTableToolbar>\n <DataTableContent />\n</DataTable>"
1410
1629
  },
1411
1630
  {
1412
1631
  "language": "tsx",
1413
1632
  "meta": null,
1414
- "code": "{\n accessorKey: \"date\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Date\" />,\n}"
1633
+ "code": "{/* Custom icon */}\n<DataTableColumnOrder label=\"Column order\" icon={<MyIcon />} />\n\n{/* Fully custom trigger */}\n<DataTableColumnOrder label=\"Column order\" trigger={<Button>Reorder</Button>} />"
1415
1634
  },
1416
1635
  {
1417
1636
  "language": "tsx",
1418
1637
  "meta": null,
1419
- "code": "{\n accessorKey: \"amount\",\n header: () => <div className=\"text-right\">Amount</div>,\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" },\n}"
1638
+ "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"id\",\n header: \"ID\",\n meta: { enableOrdering: false }, // Cannot be reordered\n },\n {\n accessorKey: \"name\",\n header: \"Name\",\n // Reorderable by default\n },\n]"
1420
1639
  },
1421
1640
  {
1422
1641
  "language": "tsx",
1423
1642
  "meta": null,
1424
- "code": "{\n accessorKey: \"amount\",\n header: ({ column }) => (\n <div className=\"flex justify-end\">\n <DataTableColumnHeader column={column} title=\"Amount\" />\n </div>\n ),\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" }, // Ensures proper header padding alignment\n}"
1425
- }
1426
- ]
1427
- },
1428
- {
1429
- "name": "DataTableColumnVisibility",
1430
- "title": "Columns & Filtering",
1431
- "description": "Column visibility, resizing, pinning, and filtering options.",
1432
- "docsPath": "docs/content/docs/components/data-table/columns.mdx",
1433
- "docSlug": "data-table/columns",
1434
- "documentationUrl": null,
1435
- "apiReferenceUrl": null,
1436
- "sourcePaths": [
1437
- "src/components/data-table/data-table-column-visibility.tsx"
1438
- ],
1439
- "props": [],
1440
- "examples": [
1441
- {
1442
- "language": "tsx",
1443
- "meta": null,
1444
- "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableToolbar } from \"@epilot/volt-ui\"\nimport { IconSearch } from \"@tabler/icons-react\"\n\nfunction MyTable() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableGlobalFilter\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n >\n <DataTableToolbar>\n <div className=\"flex items-center gap-2 rounded-lg border border-gray-a6 px-3 py-1.5\">\n <IconSearch size={18} />\n <input\n type=\"text\"\n placeholder=\"Search all columns...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1445
- },
1446
- {
1447
- "language": "tsx",
1448
- "meta": null,
1449
- "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent, DataTableToolbar, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n // Get current filter values\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n // Update status filter\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n // Update type filter\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableFiltering\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n >\n <DataTableToolbar>\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n <option value=\"overdue\">Overdue</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1450
- },
1451
- {
1452
- "language": "tsx",
1453
- "meta": null,
1454
- "code": "import { useState } from \"react\"\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n DataTableColumnVisibility,\n} from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n return (\n <DataTable columns={columns} data={data} enableSorting>\n <DataTableToolbar>\n <div className=\"flex-1\" />\n {/* Use -mr-1 wrapper to align icon with toolbar edge (compensates for button hover padding) */}\n <div className=\"-mr-1\">\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1455
- },
1456
- {
1457
- "language": "tsx",
1458
- "meta": null,
1459
- "code": "const columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: \"Invoice\",\n enableHiding: false, // This column won't appear in the visibility dropdown\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n // enableHiding defaults to true\n },\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n enableHiding: false, // Actions column should always be visible\n },\n]"
1460
- },
1461
- {
1462
- "language": "tsx",
1463
- "meta": null,
1464
- "code": "import { Button } from \"@epilot/volt-ui\"\n\n<DataTableColumnVisibility\n label=\"Toggle columns\"\n trigger={\n <Button variant=\"tertiary\" size=\"sm\">\n Columns\n </Button>\n }\n/>"
1465
- },
1466
- {
1467
- "language": "tsx",
1468
- "meta": null,
1469
- "code": "const columns: ColumnDef<Invoice>[] = [\n // ... other columns\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n meta: {\n visibilityLabel: \"Actions\", // Label shown in visibility dropdown\n },\n },\n]"
1643
+ "code": "import {\n DataTable,\n DataTableContent,\n type ColumnOrderState,\n} from \"@epilot/volt-ui\"\nimport { useLocalStorage } from \"@/hooks/useSessionStorage\"\n\nfunction MyTable() {\n const [columnOrder, setColumnOrder] = useLocalStorage<ColumnOrderState>(\n \"my-table-column-order\",\n []\n )\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableColumnOrdering\n columnOrder={columnOrder}\n onColumnOrderChange={setColumnOrder}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1470
1644
  },
1471
1645
  {
1472
1646
  "language": "tsx",
@@ -1511,430 +1685,387 @@
1511
1685
  ]
1512
1686
  },
1513
1687
  {
1514
- "name": "DataTableContent",
1515
- "title": "Columns & Filtering",
1516
- "description": "Column visibility, resizing, pinning, and filtering options.",
1517
- "docsPath": "docs/content/docs/components/data-table/columns.mdx",
1518
- "docSlug": "data-table/columns",
1688
+ "name": "DataTableBody",
1689
+ "title": "Data Table",
1690
+ "description": "A powerful data table component built on Tanstack Table with support for sorting, filtering, pagination, row selection, and virtualization.",
1691
+ "docsPath": "docs/content/docs/components/data-table/index.mdx",
1692
+ "docSlug": "data-table/index",
1519
1693
  "documentationUrl": null,
1520
1694
  "apiReferenceUrl": null,
1521
1695
  "sourcePaths": [
1522
- "src/components/data-table/data-table-content.tsx"
1696
+ "src/components/data-table/data-table-body.tsx"
1523
1697
  ],
1524
1698
  "props": [],
1525
1699
  "examples": [
1526
1700
  {
1527
1701
  "language": "tsx",
1528
1702
  "meta": null,
1529
- "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableToolbar } from \"@epilot/volt-ui\"\nimport { IconSearch } from \"@tabler/icons-react\"\n\nfunction MyTable() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableGlobalFilter\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n >\n <DataTableToolbar>\n <div className=\"flex items-center gap-2 rounded-lg border border-gray-a6 px-3 py-1.5\">\n <IconSearch size={18} />\n <input\n type=\"text\"\n placeholder=\"Search all columns...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1530
- },
1531
- {
1532
- "language": "tsx",
1533
- "meta": null,
1534
- "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent, DataTableToolbar, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n // Get current filter values\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n // Update status filter\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n // Update type filter\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableFiltering\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n >\n <DataTableToolbar>\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n <option value=\"overdue\">Overdue</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1535
- },
1536
- {
1537
- "language": "tsx",
1538
- "meta": null,
1539
- "code": "import { useState } from \"react\"\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n DataTableColumnVisibility,\n} from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n return (\n <DataTable columns={columns} data={data} enableSorting>\n <DataTableToolbar>\n <div className=\"flex-1\" />\n {/* Use -mr-1 wrapper to align icon with toolbar edge (compensates for button hover padding) */}\n <div className=\"-mr-1\">\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1703
+ "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\ntype Invoice = {\n id: string\n status: string\n customer: string\n amount: number\n}\n\nconst columns: ColumnDef<Invoice>[] = [\n { accessorKey: \"id\", header: \"Invoice\" },\n { accessorKey: \"status\", header: \"Status\" },\n { accessorKey: \"customer\", header: \"Customer\" },\n { accessorKey: \"amount\", header: \"Amount\" },\n]\n\n// Column resizing is enabled by default. Disable if you prefer fixed columns:\n<DataTable columns={columns} data={invoices} disableColumnResizing>\n <DataTableContent />\n</DataTable>"
1540
1704
  },
1541
1705
  {
1542
1706
  "language": "tsx",
1543
1707
  "meta": null,
1544
- "code": "const columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: \"Invoice\",\n enableHiding: false, // This column won't appear in the visibility dropdown\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n // enableHiding defaults to true\n },\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n enableHiding: false, // Actions column should always be visible\n },\n]"
1708
+ "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableColumnOrder,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction FullExample() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [rowSelection, setRowSelection] = useState({})\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n enableRowSelection\n enableColumnOrdering\n enableGlobalFilter\n enableFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{ pageSize: 10 }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
1545
1709
  },
1546
1710
  {
1547
1711
  "language": "tsx",
1548
1712
  "meta": null,
1549
- "code": "import { Button } from \"@epilot/volt-ui\"\n\n<DataTableColumnVisibility\n label=\"Toggle columns\"\n trigger={\n <Button variant=\"tertiary\" size=\"sm\">\n Columns\n </Button>\n }\n/>"
1713
+ "code": "import { useState, useMemo } from \"react\"\nimport type { ColumnFiltersState, PaginationState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableColumnOrder,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction ServerExample() {\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 10,\n })\n const [sorting, setSorting] = useState<SortingState>([])\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [rowSelection, setRowSelection] = useState({})\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n // In a real app, use useQuery with pagination/sorting/filters as query keys\n const { data, totalItems } = useServerData({\n pagination,\n sorting,\n globalFilter,\n statusFilter,\n typeFilter,\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n manualSorting\n enableRowSelection\n enableColumnOrdering\n enableGlobalFilter\n enableFiltering\n manualFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{\n pageIndex: pagination.pageIndex,\n pageSize: pagination.pageSize,\n totalItems: totalItems,\n onPaginationChange: setPagination,\n }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => {\n setGlobalFilter(e.target.value)\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button\n variant=\"tertiary\"\n size=\"sm\"\n onClick={() => {\n setColumnFilters([])\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n >\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
1550
1714
  },
1551
1715
  {
1552
1716
  "language": "tsx",
1553
1717
  "meta": null,
1554
- "code": "const columns: ColumnDef<Invoice>[] = [\n // ... other columns\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n meta: {\n visibilityLabel: \"Actions\", // Label shown in visibility dropdown\n },\n },\n]"
1718
+ "code": "<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
1555
1719
  },
1556
1720
  {
1557
1721
  "language": "tsx",
1558
1722
  "meta": null,
1559
- "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nconst columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: \"Invoice\",\n size: 120, // Initial width\n minSize: 80, // Minimum width when resizing\n maxSize: 200, // Maximum width when resizing\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n size: 120,\n },\n {\n accessorKey: \"type\",\n header: \"Type\",\n size: 100,\n enableResizing: false, // Disable resizing for this column\n },\n // ...more columns\n]\n\n// Column resizing is enabled by default\n<DataTable columns={columns} data={data}>\n <DataTableContent />\n</DataTable>\n\n// To disable column resizing:\n<DataTable columns={columns} data={data} disableColumnResizing>\n <DataTableContent />\n</DataTable>"
1723
+ "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"description\",\n header: \"Description\",\n size: 200,\n meta: { cellOverflow: \"wrap\" }, // This column wraps, others truncate\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n // Uses table default\n },\n]\n\n<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
1560
1724
  },
1561
1725
  {
1562
1726
  "language": "tsx",
1563
1727
  "meta": null,
1564
- "code": "import { useState } from \"react\"\nimport type { ColumnSizingState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnSizing, setColumnSizing] = useState<ColumnSizingState>({\n id: 100,\n customer: 180,\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnSizing={columnSizing}\n onColumnSizingChange={setColumnSizing}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1728
+ "code": "import { DataTable, DataTableContent, DataTableColumnHeader } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nconst columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Invoice\" />,\n },\n {\n accessorKey: \"customer\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Customer\" />,\n },\n // ...more columns\n]\n\n<DataTable columns={columns} data={data} enableSorting>\n <DataTableContent />\n</DataTable>"
1565
1729
  },
1566
1730
  {
1567
1731
  "language": "tsx",
1568
1732
  "meta": null,
1569
- "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"id\",\n header: \"ID\",\n size: 60,\n enableResizing: false, // Cannot be resized\n },\n {\n accessorKey: \"name\",\n header: \"Name\",\n size: 150,\n minSize: 100, // Minimum 100px\n maxSize: 400, // Maximum 400px\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n // Uses defaults: minSize=20, maxSize=unlimited\n },\n]"
1733
+ "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableFooter, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [pageSize, setPageSize] = useState(5)\n const visibleData = data.slice(0, pageSize)\n const hasMore = pageSize < data.length\n\n return (\n <DataTable columns={columns} data={visibleData}>\n <DataTableContent />\n {hasMore && (\n <DataTableFooter className=\"justify-start\">\n <Button size=\"sm\" variant=\"tertiary\" onClick={() => setPageSize((prev) => prev + 3)}>\n Show more ({data.length - pageSize} remaining)\n </Button>\n </DataTableFooter>\n )}\n </DataTable>\n )\n}"
1570
1734
  },
1571
1735
  {
1572
1736
  "language": "tsx",
1573
1737
  "meta": null,
1574
- "code": "// Default: handles appear on header hover\n<DataTable columns={columns} data={data}>\n <DataTableContent />\n</DataTable>\n\n// Always show resize handles\n<DataTable columns={columns} data={data} resizeHandleVisibility=\"always\">\n <DataTableContent />\n</DataTable>"
1738
+ "code": "{\n accessorKey: \"name\",\n header: \"Name\",\n}"
1575
1739
  },
1576
1740
  {
1577
1741
  "language": "tsx",
1578
1742
  "meta": null,
1579
- "code": "import { useState } from \"react\"\nimport type { RowSelectionState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [rowSelection, setRowSelection] = useState<RowSelectionState>({})\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableRowSelection\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n autoPinSelection // Pin checkbox column when rows are selected\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1743
+ "code": "{\n accessorKey: \"status\",\n header: \"Status\",\n cell: ({ row }) => <Badge>{row.getValue(\"status\")}</Badge>,\n}"
1580
1744
  },
1581
1745
  {
1582
1746
  "language": "tsx",
1583
1747
  "meta": null,
1584
- "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\n<DataTable\n columns={columns}\n data={data}\n columnPinning={{ left: [\"id\"], right: [\"actions\"] }}\n>\n <DataTableContent />\n</DataTable>"
1748
+ "code": "{\n accessorKey: \"date\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Date\" />,\n}"
1585
1749
  },
1586
1750
  {
1587
1751
  "language": "tsx",
1588
1752
  "meta": null,
1589
- "code": "import { useState } from \"react\"\nimport type { ColumnPinningState } from \"@epilot/volt-ui\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnPinning, setColumnPinning] = useState<ColumnPinningState>({\n left: [\"id\"],\n right: [],\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnPinning={columnPinning}\n onColumnPinningChange={setColumnPinning}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1753
+ "code": "{\n accessorKey: \"amount\",\n header: () => <div className=\"text-right\">Amount</div>,\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" },\n}"
1590
1754
  },
1591
1755
  {
1592
1756
  "language": "tsx",
1593
1757
  "meta": null,
1594
- "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\n// Compact rows (smallest)\n<DataTable columns={columns} data={data} density=\"compact\">\n <DataTableContent />\n</DataTable>\n\n// Normal rows (default)\n<DataTable columns={columns} data={data} density=\"normal\">\n <DataTableContent />\n</DataTable>\n\n// Comfortable rows (largest)\n<DataTable columns={columns} data={data} density=\"comfortable\">\n <DataTableContent />\n</DataTable>"
1758
+ "code": "{\n accessorKey: \"amount\",\n header: ({ column }) => (\n <div className=\"flex justify-end\">\n <DataTableColumnHeader column={column} title=\"Amount\" />\n </div>\n ),\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" }, // Ensures proper header padding alignment\n}"
1595
1759
  }
1596
1760
  ]
1597
1761
  },
1598
1762
  {
1599
- "name": "DataTableError",
1600
- "title": "Advanced",
1601
- "description": "Virtualization, loading/error states, and composable API.",
1602
- "docsPath": "docs/content/docs/components/data-table/advanced.mdx",
1603
- "docSlug": "data-table/advanced",
1763
+ "name": "DataTableColumnHeader",
1764
+ "title": "Data Table",
1765
+ "description": "A powerful data table component built on Tanstack Table with support for sorting, filtering, pagination, row selection, and virtualization.",
1766
+ "docsPath": "docs/content/docs/components/data-table/index.mdx",
1767
+ "docSlug": "data-table/index",
1604
1768
  "documentationUrl": null,
1605
1769
  "apiReferenceUrl": null,
1606
1770
  "sourcePaths": [
1607
- "src/components/data-table/data-table-error.tsx"
1771
+ "src/components/data-table/data-table-column-header.tsx"
1608
1772
  ],
1609
1773
  "props": [],
1610
1774
  "examples": [
1611
1775
  {
1612
1776
  "language": "tsx",
1613
1777
  "meta": null,
1614
- "code": "import { useState, useMemo } from \"react\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction VirtualizedTable() {\n const [rowSelection, setRowSelection] = useState({})\n const largeDataset = useMemo(() => generateLargeData(15000), [])\n\n return (\n <DataTable\n columns={columns}\n data={largeDataset}\n enableSorting\n enableRowSelection\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n virtualization={{\n enabled: true,\n estimateRowHeight: 48, // Match your row height\n overscan: 10, // Render 10 extra rows beyond viewport\n containerHeight: 600, // Fixed height required for virtualization\n }}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1778
+ "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\ntype Invoice = {\n id: string\n status: string\n customer: string\n amount: number\n}\n\nconst columns: ColumnDef<Invoice>[] = [\n { accessorKey: \"id\", header: \"Invoice\" },\n { accessorKey: \"status\", header: \"Status\" },\n { accessorKey: \"customer\", header: \"Customer\" },\n { accessorKey: \"amount\", header: \"Amount\" },\n]\n\n// Column resizing is enabled by default. Disable if you prefer fixed columns:\n<DataTable columns={columns} data={invoices} disableColumnResizing>\n <DataTableContent />\n</DataTable>"
1615
1779
  },
1616
1780
  {
1617
1781
  "language": "tsx",
1618
1782
  "meta": null,
1619
- "code": "type VirtualizationConfig = {\n enabled: boolean\n estimateRowHeight?: number // Default: 48\n overscan?: number // Default: 10\n containerHeight?: number // Default: 600\n}"
1783
+ "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableColumnOrder,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction FullExample() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [rowSelection, setRowSelection] = useState({})\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n enableRowSelection\n enableColumnOrdering\n enableGlobalFilter\n enableFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{ pageSize: 10 }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
1620
1784
  },
1621
1785
  {
1622
1786
  "language": "tsx",
1623
1787
  "meta": null,
1624
- "code": "import {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableToolbar,\n} from \"@epilot/volt-ui\"\n\nfunction ComposableTable() {\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n pagination={{ pageSize: 10 }}\n >\n <DataTableToolbar>\n <input placeholder=\"Search invoices...\" />\n </DataTableToolbar>\n\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n\n <DataTablePagination className=\"mt-4\" />\n </DataTable>\n )\n}"
1788
+ "code": "import { useState, useMemo } from \"react\"\nimport type { ColumnFiltersState, PaginationState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableColumnOrder,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction ServerExample() {\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 10,\n })\n const [sorting, setSorting] = useState<SortingState>([])\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [rowSelection, setRowSelection] = useState({})\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n // In a real app, use useQuery with pagination/sorting/filters as query keys\n const { data, totalItems } = useServerData({\n pagination,\n sorting,\n globalFilter,\n statusFilter,\n typeFilter,\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n manualSorting\n enableRowSelection\n enableColumnOrdering\n enableGlobalFilter\n enableFiltering\n manualFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{\n pageIndex: pagination.pageIndex,\n pageSize: pagination.pageSize,\n totalItems: totalItems,\n onPaginationChange: setPagination,\n }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => {\n setGlobalFilter(e.target.value)\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button\n variant=\"tertiary\"\n size=\"sm\"\n onClick={() => {\n setColumnFilters([])\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n >\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
1625
1789
  },
1626
1790
  {
1627
1791
  "language": "tsx",
1628
1792
  "meta": null,
1629
- "code": "<DataTable\n columns={columns}\n data={largeDataset}\n enableSorting\n virtualization={{ enabled: true, containerHeight: 500 }}\n>\n <DataTableContent>\n <DataTableHeader sticky />\n <DataTableBody emptyState=\"No results found.\" />\n </DataTableContent>\n</DataTable>"
1793
+ "code": "<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
1630
1794
  },
1631
1795
  {
1632
1796
  "language": "tsx",
1633
1797
  "meta": null,
1634
- "code": "import { DataTable, DataTableContent, DataTableHeader, DataTableBody, DataTableLoading } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const { data, isLoading } = useQuery(...)\n\n return (\n <DataTable columns={columns} data={data ?? []}>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody\n isLoading={isLoading}\n loadingState={<DataTableLoading />}\n emptyState=\"No invoices found.\"\n />\n </DataTableContent>\n </DataTable>\n )\n}"
1798
+ "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"description\",\n header: \"Description\",\n size: 200,\n meta: { cellOverflow: \"wrap\" }, // This column wraps, others truncate\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n // Uses table default\n },\n]\n\n<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
1635
1799
  },
1636
1800
  {
1637
1801
  "language": "tsx",
1638
1802
  "meta": null,
1639
- "code": "<DataTableBody\n isLoading={isLoading}\n loadingState={\n <DataTableLoading>\n <Spinner size=\"xl\" className=\"text-accent-light\" />\n <p className=\"mt-4 text-base font-medium\">{t('table.loading')}</p>\n <p className=\"text-sm text-gray-light\">{t('table.loading.description')}</p>\n </DataTableLoading>\n }\n/>"
1803
+ "code": "import { DataTable, DataTableContent, DataTableColumnHeader } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nconst columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Invoice\" />,\n },\n {\n accessorKey: \"customer\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Customer\" />,\n },\n // ...more columns\n]\n\n<DataTable columns={columns} data={data} enableSorting>\n <DataTableContent />\n</DataTable>"
1640
1804
  },
1641
1805
  {
1642
1806
  "language": "tsx",
1643
1807
  "meta": null,
1644
- "code": "import { DataTable, DataTableContent, DataTableHeader, DataTableBody, DataTableError } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const { data, isLoading, isError, refetch } = useQuery(...)\n\n return (\n <DataTable columns={columns} data={data ?? []}>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody\n isLoading={isLoading}\n loadingState={<DataTableLoading />}\n isError={isError}\n errorState={\n <DataTableError\n title=\"Failed to load invoices\"\n description=\"There was a problem connecting to the server.\"\n retryLabel=\"Retry\"\n onRetry={refetch}\n />\n }\n emptyState=\"No invoices found.\"\n />\n </DataTableContent>\n </DataTable>\n )\n}"
1808
+ "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableFooter, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [pageSize, setPageSize] = useState(5)\n const visibleData = data.slice(0, pageSize)\n const hasMore = pageSize < data.length\n\n return (\n <DataTable columns={columns} data={visibleData}>\n <DataTableContent />\n {hasMore && (\n <DataTableFooter className=\"justify-start\">\n <Button size=\"sm\" variant=\"tertiary\" onClick={() => setPageSize((prev) => prev + 3)}>\n Show more ({data.length - pageSize} remaining)\n </Button>\n </DataTableFooter>\n )}\n </DataTable>\n )\n}"
1645
1809
  },
1646
1810
  {
1647
1811
  "language": "tsx",
1648
1812
  "meta": null,
1649
- "code": "<DataTableBody\n isError={isError}\n errorState={\n <DataTableError>\n <AlertTriangle size={48} className=\"text-error-light\" />\n <p className=\"mt-2 text-lg font-semibold\">{t('table.error.title')}</p>\n <p className=\"text-sm text-gray-light\">{t('table.error.description')}</p>\n <div className=\"flex gap-2 mt-4\">\n <Button variant=\"secondary\" size=\"sm\" onClick={refetch}>\n {t('retry')}\n </Button>\n <Button variant=\"tertiary\" size=\"sm\">\n {t('contact_support')}\n </Button>\n </div>\n </DataTableError>\n }\n/>"
1813
+ "code": "{\n accessorKey: \"name\",\n header: \"Name\",\n}"
1650
1814
  },
1651
1815
  {
1652
1816
  "language": "tsx",
1653
1817
  "meta": null,
1654
- "code": "// Default - borders visible on header and rows\n<DataTable columns={columns} data={data} />\n\n// Hide all borders\n<DataTable\n columns={columns}\n data={data}\n showHeaderBorder={false}\n showRowBorders={false}\n/>\n\n// Hide only row borders (keep header border)\n<DataTable\n columns={columns}\n data={data}\n showRowBorders={false}\n/>\n\n// Hide only header border (keep row borders)\n<DataTable\n columns={columns}\n data={data}\n showHeaderBorder={false}\n/>"
1818
+ "code": "{\n accessorKey: \"status\",\n header: \"Status\",\n cell: ({ row }) => <Badge>{row.getValue(\"status\")}</Badge>,\n}"
1655
1819
  },
1656
1820
  {
1657
1821
  "language": "tsx",
1658
1822
  "meta": null,
1659
- "code": "// Default uses var(--volt-gray-2)\n<DataTableHeader sticky />\n\n// Custom background color\n<DataTableHeader sticky stickyBackground=\"white\" />\n\n// Use a different volt gray\n<DataTableHeader sticky stickyBackground=\"var(--volt-gray-1)\" />\n\n// Custom CSS variable\n<DataTableHeader sticky stickyBackground=\"var(--my-header-bg)\" />"
1823
+ "code": "{\n accessorKey: \"date\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Date\" />,\n}"
1824
+ },
1825
+ {
1826
+ "language": "tsx",
1827
+ "meta": null,
1828
+ "code": "{\n accessorKey: \"amount\",\n header: () => <div className=\"text-right\">Amount</div>,\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" },\n}"
1829
+ },
1830
+ {
1831
+ "language": "tsx",
1832
+ "meta": null,
1833
+ "code": "{\n accessorKey: \"amount\",\n header: ({ column }) => (\n <div className=\"flex justify-end\">\n <DataTableColumnHeader column={column} title=\"Amount\" />\n </div>\n ),\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" }, // Ensures proper header padding alignment\n}"
1660
1834
  }
1661
1835
  ]
1662
1836
  },
1663
1837
  {
1664
- "name": "DataTableFooter",
1665
- "title": "Data Table",
1666
- "description": "A powerful data table component built on Tanstack Table with support for sorting, filtering, pagination, row selection, and virtualization.",
1667
- "docsPath": "docs/content/docs/components/data-table/index.mdx",
1668
- "docSlug": "data-table/index",
1838
+ "name": "DataTableColumnOrder",
1839
+ "title": "Columns & Filtering",
1840
+ "description": "Column visibility, resizing, pinning, and filtering options.",
1841
+ "docsPath": "docs/content/docs/components/data-table/columns.mdx",
1842
+ "docSlug": "data-table/columns",
1669
1843
  "documentationUrl": null,
1670
1844
  "apiReferenceUrl": null,
1671
1845
  "sourcePaths": [
1672
- "src/components/data-table/data-table-footer.tsx"
1846
+ "src/components/data-table/data-table-column-order.tsx"
1673
1847
  ],
1674
1848
  "props": [],
1675
1849
  "examples": [
1676
1850
  {
1677
1851
  "language": "tsx",
1678
1852
  "meta": null,
1679
- "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\ntype Invoice = {\n id: string\n status: string\n customer: string\n amount: number\n}\n\nconst columns: ColumnDef<Invoice>[] = [\n { accessorKey: \"id\", header: \"Invoice\" },\n { accessorKey: \"status\", header: \"Status\" },\n { accessorKey: \"customer\", header: \"Customer\" },\n { accessorKey: \"amount\", header: \"Amount\" },\n]\n\n// Column resizing is enabled by default. Disable if you prefer fixed columns:\n<DataTable columns={columns} data={invoices} disableColumnResizing>\n <DataTableContent />\n</DataTable>"
1680
- },
1681
- {
1682
- "language": "tsx",
1683
- "meta": null,
1684
- "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction FullExample() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [rowSelection, setRowSelection] = useState({})\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n enableRowSelection\n enableGlobalFilter\n enableFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{ pageSize: 10 }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
1685
- },
1686
- {
1687
- "language": "tsx",
1688
- "meta": null,
1689
- "code": "import { useState, useMemo } from \"react\"\nimport type { ColumnFiltersState, PaginationState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction ServerExample() {\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 10,\n })\n const [sorting, setSorting] = useState<SortingState>([])\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [rowSelection, setRowSelection] = useState({})\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n // In a real app, use useQuery with pagination/sorting/filters as query keys\n const { data, totalItems } = useServerData({\n pagination,\n sorting,\n globalFilter,\n statusFilter,\n typeFilter,\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n manualSorting\n enableRowSelection\n enableGlobalFilter\n enableFiltering\n manualFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{\n pageIndex: pagination.pageIndex,\n pageSize: pagination.pageSize,\n totalItems: totalItems,\n onPaginationChange: setPagination,\n }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => {\n setGlobalFilter(e.target.value)\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button\n variant=\"tertiary\"\n size=\"sm\"\n onClick={() => {\n setColumnFilters([])\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n >\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
1690
- },
1691
- {
1692
- "language": "tsx",
1693
- "meta": null,
1694
- "code": "<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
1853
+ "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableToolbar } from \"@epilot/volt-ui\"\nimport { IconSearch } from \"@tabler/icons-react\"\n\nfunction MyTable() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableGlobalFilter\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n >\n <DataTableToolbar>\n <div className=\"flex items-center gap-2 rounded-lg border border-gray-a6 px-3 py-1.5\">\n <IconSearch size={18} />\n <input\n type=\"text\"\n placeholder=\"Search all columns...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1695
1854
  },
1696
1855
  {
1697
1856
  "language": "tsx",
1698
1857
  "meta": null,
1699
- "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"description\",\n header: \"Description\",\n size: 200,\n meta: { cellOverflow: \"wrap\" }, // This column wraps, others truncate\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n // Uses table default\n },\n]\n\n<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
1858
+ "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent, DataTableToolbar, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n // Get current filter values\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n // Update status filter\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n // Update type filter\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableFiltering\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n >\n <DataTableToolbar>\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n <option value=\"overdue\">Overdue</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1700
1859
  },
1701
1860
  {
1702
1861
  "language": "tsx",
1703
1862
  "meta": null,
1704
- "code": "import { DataTable, DataTableContent, DataTableColumnHeader } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nconst columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Invoice\" />,\n },\n {\n accessorKey: \"customer\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Customer\" />,\n },\n // ...more columns\n]\n\n<DataTable columns={columns} data={data} enableSorting>\n <DataTableContent />\n</DataTable>"
1863
+ "code": "import { useState } from \"react\"\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n DataTableColumnVisibility,\n} from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n return (\n <DataTable columns={columns} data={data} enableSorting>\n <DataTableToolbar>\n <div className=\"flex-1\" />\n {/* Use -mr-1 wrapper to align icon with toolbar edge (compensates for button hover padding) */}\n <div className=\"-mr-1\">\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1705
1864
  },
1706
1865
  {
1707
1866
  "language": "tsx",
1708
1867
  "meta": null,
1709
- "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableFooter, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [pageSize, setPageSize] = useState(5)\n const visibleData = data.slice(0, pageSize)\n const hasMore = pageSize < data.length\n\n return (\n <DataTable columns={columns} data={visibleData}>\n <DataTableContent />\n {hasMore && (\n <DataTableFooter className=\"justify-start\">\n <Button size=\"sm\" variant=\"tertiary\" onClick={() => setPageSize((prev) => prev + 3)}>\n Show more ({data.length - pageSize} remaining)\n </Button>\n </DataTableFooter>\n )}\n </DataTable>\n )\n}"
1868
+ "code": "const columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: \"Invoice\",\n enableHiding: false, // This column won't appear in the visibility dropdown\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n // enableHiding defaults to true\n },\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n enableHiding: false, // Actions column should always be visible\n },\n]"
1710
1869
  },
1711
1870
  {
1712
1871
  "language": "tsx",
1713
1872
  "meta": null,
1714
- "code": "{\n accessorKey: \"name\",\n header: \"Name\",\n}"
1873
+ "code": "import { Button } from \"@epilot/volt-ui\"\n\n<DataTableColumnVisibility\n label=\"Toggle columns\"\n trigger={\n <Button variant=\"tertiary\" size=\"sm\">\n Columns\n </Button>\n }\n/>"
1715
1874
  },
1716
1875
  {
1717
1876
  "language": "tsx",
1718
1877
  "meta": null,
1719
- "code": "{\n accessorKey: \"status\",\n header: \"Status\",\n cell: ({ row }) => <Badge>{row.getValue(\"status\")}</Badge>,\n}"
1878
+ "code": "const columns: ColumnDef<Invoice>[] = [\n // ... other columns\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n meta: {\n visibilityLabel: \"Actions\", // Label shown in visibility dropdown\n },\n },\n]"
1720
1879
  },
1721
1880
  {
1722
1881
  "language": "tsx",
1723
1882
  "meta": null,
1724
- "code": "{\n accessorKey: \"date\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Date\" />,\n}"
1883
+ "code": "<DataTable columns={columns} data={data} enableColumnOrdering>\n <DataTableContent />\n</DataTable>"
1725
1884
  },
1726
1885
  {
1727
1886
  "language": "tsx",
1728
1887
  "meta": null,
1729
- "code": "{\n accessorKey: \"amount\",\n header: () => <div className=\"text-right\">Amount</div>,\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" },\n}"
1888
+ "code": "import { useState } from \"react\"\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n DataTableColumnOrder,\n DataTableColumnVisibility,\n type ColumnOrderState,\n} from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnOrder, setColumnOrder] = useState<ColumnOrderState>([])\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnOrder={columnOrder}\n onColumnOrderChange={setColumnOrder}\n >\n <DataTableToolbar>\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1730
1889
  },
1731
1890
  {
1732
1891
  "language": "tsx",
1733
1892
  "meta": null,
1734
- "code": "{\n accessorKey: \"amount\",\n header: ({ column }) => (\n <div className=\"flex justify-end\">\n <DataTableColumnHeader column={column} title=\"Amount\" />\n </div>\n ),\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" }, // Ensures proper header padding alignment\n}"
1735
- }
1736
- ]
1737
- },
1738
- {
1739
- "name": "DataTableHeader",
1740
- "title": "Data Table",
1741
- "description": "A powerful data table component built on Tanstack Table with support for sorting, filtering, pagination, row selection, and virtualization.",
1742
- "docsPath": "docs/content/docs/components/data-table/index.mdx",
1743
- "docSlug": "data-table/index",
1744
- "documentationUrl": null,
1745
- "apiReferenceUrl": null,
1746
- "sourcePaths": [
1747
- "src/components/data-table/data-table-header.tsx"
1748
- ],
1749
- "props": [],
1750
- "examples": [
1751
- {
1752
- "language": "tsx",
1753
- "meta": null,
1754
- "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\ntype Invoice = {\n id: string\n status: string\n customer: string\n amount: number\n}\n\nconst columns: ColumnDef<Invoice>[] = [\n { accessorKey: \"id\", header: \"Invoice\" },\n { accessorKey: \"status\", header: \"Status\" },\n { accessorKey: \"customer\", header: \"Customer\" },\n { accessorKey: \"amount\", header: \"Amount\" },\n]\n\n// Column resizing is enabled by default. Disable if you prefer fixed columns:\n<DataTable columns={columns} data={invoices} disableColumnResizing>\n <DataTableContent />\n</DataTable>"
1893
+ "code": "<DataTable columns={columns} data={data}>\n <DataTableToolbar>\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n </DataTableToolbar>\n <DataTableContent />\n</DataTable>"
1755
1894
  },
1756
1895
  {
1757
1896
  "language": "tsx",
1758
1897
  "meta": null,
1759
- "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction FullExample() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [rowSelection, setRowSelection] = useState({})\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n enableRowSelection\n enableGlobalFilter\n enableFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{ pageSize: 10 }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
1898
+ "code": "{/* Custom icon */}\n<DataTableColumnOrder label=\"Column order\" icon={<MyIcon />} />\n\n{/* Fully custom trigger */}\n<DataTableColumnOrder label=\"Column order\" trigger={<Button>Reorder</Button>} />"
1760
1899
  },
1761
1900
  {
1762
1901
  "language": "tsx",
1763
1902
  "meta": null,
1764
- "code": "import { useState, useMemo } from \"react\"\nimport type { ColumnFiltersState, PaginationState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction ServerExample() {\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 10,\n })\n const [sorting, setSorting] = useState<SortingState>([])\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [rowSelection, setRowSelection] = useState({})\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n // In a real app, use useQuery with pagination/sorting/filters as query keys\n const { data, totalItems } = useServerData({\n pagination,\n sorting,\n globalFilter,\n statusFilter,\n typeFilter,\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n manualSorting\n enableRowSelection\n enableGlobalFilter\n enableFiltering\n manualFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{\n pageIndex: pagination.pageIndex,\n pageSize: pagination.pageSize,\n totalItems: totalItems,\n onPaginationChange: setPagination,\n }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => {\n setGlobalFilter(e.target.value)\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button\n variant=\"tertiary\"\n size=\"sm\"\n onClick={() => {\n setColumnFilters([])\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n >\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
1903
+ "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"id\",\n header: \"ID\",\n meta: { enableOrdering: false }, // Cannot be reordered\n },\n {\n accessorKey: \"name\",\n header: \"Name\",\n // Reorderable by default\n },\n]"
1765
1904
  },
1766
1905
  {
1767
1906
  "language": "tsx",
1768
1907
  "meta": null,
1769
- "code": "<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
1908
+ "code": "import {\n DataTable,\n DataTableContent,\n type ColumnOrderState,\n} from \"@epilot/volt-ui\"\nimport { useLocalStorage } from \"@/hooks/useSessionStorage\"\n\nfunction MyTable() {\n const [columnOrder, setColumnOrder] = useLocalStorage<ColumnOrderState>(\n \"my-table-column-order\",\n []\n )\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableColumnOrdering\n columnOrder={columnOrder}\n onColumnOrderChange={setColumnOrder}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1770
1909
  },
1771
1910
  {
1772
1911
  "language": "tsx",
1773
1912
  "meta": null,
1774
- "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"description\",\n header: \"Description\",\n size: 200,\n meta: { cellOverflow: \"wrap\" }, // This column wraps, others truncate\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n // Uses table default\n },\n]\n\n<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
1913
+ "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nconst columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: \"Invoice\",\n size: 120, // Initial width\n minSize: 80, // Minimum width when resizing\n maxSize: 200, // Maximum width when resizing\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n size: 120,\n },\n {\n accessorKey: \"type\",\n header: \"Type\",\n size: 100,\n enableResizing: false, // Disable resizing for this column\n },\n // ...more columns\n]\n\n// Column resizing is enabled by default\n<DataTable columns={columns} data={data}>\n <DataTableContent />\n</DataTable>\n\n// To disable column resizing:\n<DataTable columns={columns} data={data} disableColumnResizing>\n <DataTableContent />\n</DataTable>"
1775
1914
  },
1776
1915
  {
1777
1916
  "language": "tsx",
1778
1917
  "meta": null,
1779
- "code": "import { DataTable, DataTableContent, DataTableColumnHeader } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nconst columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Invoice\" />,\n },\n {\n accessorKey: \"customer\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Customer\" />,\n },\n // ...more columns\n]\n\n<DataTable columns={columns} data={data} enableSorting>\n <DataTableContent />\n</DataTable>"
1918
+ "code": "import { useState } from \"react\"\nimport type { ColumnSizingState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnSizing, setColumnSizing] = useState<ColumnSizingState>({\n id: 100,\n customer: 180,\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnSizing={columnSizing}\n onColumnSizingChange={setColumnSizing}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1780
1919
  },
1781
1920
  {
1782
1921
  "language": "tsx",
1783
1922
  "meta": null,
1784
- "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableFooter, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [pageSize, setPageSize] = useState(5)\n const visibleData = data.slice(0, pageSize)\n const hasMore = pageSize < data.length\n\n return (\n <DataTable columns={columns} data={visibleData}>\n <DataTableContent />\n {hasMore && (\n <DataTableFooter className=\"justify-start\">\n <Button size=\"sm\" variant=\"tertiary\" onClick={() => setPageSize((prev) => prev + 3)}>\n Show more ({data.length - pageSize} remaining)\n </Button>\n </DataTableFooter>\n )}\n </DataTable>\n )\n}"
1923
+ "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"id\",\n header: \"ID\",\n size: 60,\n enableResizing: false, // Cannot be resized\n },\n {\n accessorKey: \"name\",\n header: \"Name\",\n size: 150,\n minSize: 100, // Minimum 100px\n maxSize: 400, // Maximum 400px\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n // Uses defaults: minSize=20, maxSize=unlimited\n },\n]"
1785
1924
  },
1786
1925
  {
1787
1926
  "language": "tsx",
1788
1927
  "meta": null,
1789
- "code": "{\n accessorKey: \"name\",\n header: \"Name\",\n}"
1928
+ "code": "// Default: handles appear on header hover\n<DataTable columns={columns} data={data}>\n <DataTableContent />\n</DataTable>\n\n// Always show resize handles\n<DataTable columns={columns} data={data} resizeHandleVisibility=\"always\">\n <DataTableContent />\n</DataTable>"
1790
1929
  },
1791
1930
  {
1792
1931
  "language": "tsx",
1793
1932
  "meta": null,
1794
- "code": "{\n accessorKey: \"status\",\n header: \"Status\",\n cell: ({ row }) => <Badge>{row.getValue(\"status\")}</Badge>,\n}"
1933
+ "code": "import { useState } from \"react\"\nimport type { RowSelectionState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [rowSelection, setRowSelection] = useState<RowSelectionState>({})\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableRowSelection\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n autoPinSelection // Pin checkbox column when rows are selected\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1795
1934
  },
1796
1935
  {
1797
1936
  "language": "tsx",
1798
1937
  "meta": null,
1799
- "code": "{\n accessorKey: \"date\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Date\" />,\n}"
1938
+ "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\n<DataTable\n columns={columns}\n data={data}\n columnPinning={{ left: [\"id\"], right: [\"actions\"] }}\n>\n <DataTableContent />\n</DataTable>"
1800
1939
  },
1801
1940
  {
1802
1941
  "language": "tsx",
1803
1942
  "meta": null,
1804
- "code": "{\n accessorKey: \"amount\",\n header: () => <div className=\"text-right\">Amount</div>,\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" },\n}"
1943
+ "code": "import { useState } from \"react\"\nimport type { ColumnPinningState } from \"@epilot/volt-ui\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnPinning, setColumnPinning] = useState<ColumnPinningState>({\n left: [\"id\"],\n right: [],\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnPinning={columnPinning}\n onColumnPinningChange={setColumnPinning}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1805
1944
  },
1806
1945
  {
1807
1946
  "language": "tsx",
1808
1947
  "meta": null,
1809
- "code": "{\n accessorKey: \"amount\",\n header: ({ column }) => (\n <div className=\"flex justify-end\">\n <DataTableColumnHeader column={column} title=\"Amount\" />\n </div>\n ),\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" }, // Ensures proper header padding alignment\n}"
1948
+ "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\n// Compact rows (smallest)\n<DataTable columns={columns} data={data} density=\"compact\">\n <DataTableContent />\n</DataTable>\n\n// Normal rows (default)\n<DataTable columns={columns} data={data} density=\"normal\">\n <DataTableContent />\n</DataTable>\n\n// Comfortable rows (largest)\n<DataTable columns={columns} data={data} density=\"comfortable\">\n <DataTableContent />\n</DataTable>"
1810
1949
  }
1811
1950
  ]
1812
1951
  },
1813
1952
  {
1814
- "name": "DataTableLoading",
1815
- "title": "Advanced",
1816
- "description": "Virtualization, loading/error states, and composable API.",
1817
- "docsPath": "docs/content/docs/components/data-table/advanced.mdx",
1818
- "docSlug": "data-table/advanced",
1953
+ "name": "DataTableColumnVisibility",
1954
+ "title": "Columns & Filtering",
1955
+ "description": "Column visibility, resizing, pinning, and filtering options.",
1956
+ "docsPath": "docs/content/docs/components/data-table/columns.mdx",
1957
+ "docSlug": "data-table/columns",
1819
1958
  "documentationUrl": null,
1820
1959
  "apiReferenceUrl": null,
1821
1960
  "sourcePaths": [
1822
- "src/components/data-table/data-table-loading.tsx"
1961
+ "src/components/data-table/data-table-column-visibility.tsx"
1823
1962
  ],
1824
1963
  "props": [],
1825
1964
  "examples": [
1826
1965
  {
1827
1966
  "language": "tsx",
1828
1967
  "meta": null,
1829
- "code": "import { useState, useMemo } from \"react\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction VirtualizedTable() {\n const [rowSelection, setRowSelection] = useState({})\n const largeDataset = useMemo(() => generateLargeData(15000), [])\n\n return (\n <DataTable\n columns={columns}\n data={largeDataset}\n enableSorting\n enableRowSelection\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n virtualization={{\n enabled: true,\n estimateRowHeight: 48, // Match your row height\n overscan: 10, // Render 10 extra rows beyond viewport\n containerHeight: 600, // Fixed height required for virtualization\n }}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1968
+ "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableToolbar } from \"@epilot/volt-ui\"\nimport { IconSearch } from \"@tabler/icons-react\"\n\nfunction MyTable() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableGlobalFilter\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n >\n <DataTableToolbar>\n <div className=\"flex items-center gap-2 rounded-lg border border-gray-a6 px-3 py-1.5\">\n <IconSearch size={18} />\n <input\n type=\"text\"\n placeholder=\"Search all columns...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1830
1969
  },
1831
1970
  {
1832
1971
  "language": "tsx",
1833
1972
  "meta": null,
1834
- "code": "type VirtualizationConfig = {\n enabled: boolean\n estimateRowHeight?: number // Default: 48\n overscan?: number // Default: 10\n containerHeight?: number // Default: 600\n}"
1973
+ "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent, DataTableToolbar, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n // Get current filter values\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n // Update status filter\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n // Update type filter\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableFiltering\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n >\n <DataTableToolbar>\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n <option value=\"overdue\">Overdue</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1835
1974
  },
1836
1975
  {
1837
1976
  "language": "tsx",
1838
1977
  "meta": null,
1839
- "code": "import {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableToolbar,\n} from \"@epilot/volt-ui\"\n\nfunction ComposableTable() {\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n pagination={{ pageSize: 10 }}\n >\n <DataTableToolbar>\n <input placeholder=\"Search invoices...\" />\n </DataTableToolbar>\n\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n\n <DataTablePagination className=\"mt-4\" />\n </DataTable>\n )\n}"
1978
+ "code": "import { useState } from \"react\"\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n DataTableColumnVisibility,\n} from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n return (\n <DataTable columns={columns} data={data} enableSorting>\n <DataTableToolbar>\n <div className=\"flex-1\" />\n {/* Use -mr-1 wrapper to align icon with toolbar edge (compensates for button hover padding) */}\n <div className=\"-mr-1\">\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1840
1979
  },
1841
1980
  {
1842
1981
  "language": "tsx",
1843
1982
  "meta": null,
1844
- "code": "<DataTable\n columns={columns}\n data={largeDataset}\n enableSorting\n virtualization={{ enabled: true, containerHeight: 500 }}\n>\n <DataTableContent>\n <DataTableHeader sticky />\n <DataTableBody emptyState=\"No results found.\" />\n </DataTableContent>\n</DataTable>"
1983
+ "code": "const columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: \"Invoice\",\n enableHiding: false, // This column won't appear in the visibility dropdown\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n // enableHiding defaults to true\n },\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n enableHiding: false, // Actions column should always be visible\n },\n]"
1845
1984
  },
1846
1985
  {
1847
1986
  "language": "tsx",
1848
1987
  "meta": null,
1849
- "code": "import { DataTable, DataTableContent, DataTableHeader, DataTableBody, DataTableLoading } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const { data, isLoading } = useQuery(...)\n\n return (\n <DataTable columns={columns} data={data ?? []}>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody\n isLoading={isLoading}\n loadingState={<DataTableLoading />}\n emptyState=\"No invoices found.\"\n />\n </DataTableContent>\n </DataTable>\n )\n}"
1988
+ "code": "import { Button } from \"@epilot/volt-ui\"\n\n<DataTableColumnVisibility\n label=\"Toggle columns\"\n trigger={\n <Button variant=\"tertiary\" size=\"sm\">\n Columns\n </Button>\n }\n/>"
1850
1989
  },
1851
1990
  {
1852
1991
  "language": "tsx",
1853
1992
  "meta": null,
1854
- "code": "<DataTableBody\n isLoading={isLoading}\n loadingState={\n <DataTableLoading>\n <Spinner size=\"xl\" className=\"text-accent-light\" />\n <p className=\"mt-4 text-base font-medium\">{t('table.loading')}</p>\n <p className=\"text-sm text-gray-light\">{t('table.loading.description')}</p>\n </DataTableLoading>\n }\n/>"
1993
+ "code": "const columns: ColumnDef<Invoice>[] = [\n // ... other columns\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n meta: {\n visibilityLabel: \"Actions\", // Label shown in visibility dropdown\n },\n },\n]"
1855
1994
  },
1856
1995
  {
1857
1996
  "language": "tsx",
1858
1997
  "meta": null,
1859
- "code": "import { DataTable, DataTableContent, DataTableHeader, DataTableBody, DataTableError } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const { data, isLoading, isError, refetch } = useQuery(...)\n\n return (\n <DataTable columns={columns} data={data ?? []}>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody\n isLoading={isLoading}\n loadingState={<DataTableLoading />}\n isError={isError}\n errorState={\n <DataTableError\n title=\"Failed to load invoices\"\n description=\"There was a problem connecting to the server.\"\n retryLabel=\"Retry\"\n onRetry={refetch}\n />\n }\n emptyState=\"No invoices found.\"\n />\n </DataTableContent>\n </DataTable>\n )\n}"
1998
+ "code": "<DataTable columns={columns} data={data} enableColumnOrdering>\n <DataTableContent />\n</DataTable>"
1860
1999
  },
1861
2000
  {
1862
2001
  "language": "tsx",
1863
2002
  "meta": null,
1864
- "code": "<DataTableBody\n isError={isError}\n errorState={\n <DataTableError>\n <AlertTriangle size={48} className=\"text-error-light\" />\n <p className=\"mt-2 text-lg font-semibold\">{t('table.error.title')}</p>\n <p className=\"text-sm text-gray-light\">{t('table.error.description')}</p>\n <div className=\"flex gap-2 mt-4\">\n <Button variant=\"secondary\" size=\"sm\" onClick={refetch}>\n {t('retry')}\n </Button>\n <Button variant=\"tertiary\" size=\"sm\">\n {t('contact_support')}\n </Button>\n </div>\n </DataTableError>\n }\n/>"
2003
+ "code": "import { useState } from \"react\"\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n DataTableColumnOrder,\n DataTableColumnVisibility,\n type ColumnOrderState,\n} from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnOrder, setColumnOrder] = useState<ColumnOrderState>([])\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnOrder={columnOrder}\n onColumnOrderChange={setColumnOrder}\n >\n <DataTableToolbar>\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
1865
2004
  },
1866
2005
  {
1867
2006
  "language": "tsx",
1868
2007
  "meta": null,
1869
- "code": "// Default - borders visible on header and rows\n<DataTable columns={columns} data={data} />\n\n// Hide all borders\n<DataTable\n columns={columns}\n data={data}\n showHeaderBorder={false}\n showRowBorders={false}\n/>\n\n// Hide only row borders (keep header border)\n<DataTable\n columns={columns}\n data={data}\n showRowBorders={false}\n/>\n\n// Hide only header border (keep row borders)\n<DataTable\n columns={columns}\n data={data}\n showHeaderBorder={false}\n/>"
2008
+ "code": "<DataTable columns={columns} data={data}>\n <DataTableToolbar>\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n </DataTableToolbar>\n <DataTableContent />\n</DataTable>"
1870
2009
  },
1871
2010
  {
1872
2011
  "language": "tsx",
1873
2012
  "meta": null,
1874
- "code": "// Default uses var(--volt-gray-2)\n<DataTableHeader sticky />\n\n// Custom background color\n<DataTableHeader sticky stickyBackground=\"white\" />\n\n// Use a different volt gray\n<DataTableHeader sticky stickyBackground=\"var(--volt-gray-1)\" />\n\n// Custom CSS variable\n<DataTableHeader sticky stickyBackground=\"var(--my-header-bg)\" />"
1875
- }
1876
- ]
1877
- },
1878
- {
1879
- "name": "DataTablePagination",
1880
- "title": "Pagination",
1881
- "description": "Client-side and server-side pagination for DataTable.",
1882
- "docsPath": "docs/content/docs/components/data-table/pagination.mdx",
1883
- "docSlug": "data-table/pagination",
1884
- "documentationUrl": null,
1885
- "apiReferenceUrl": null,
1886
- "sourcePaths": [
1887
- "src/components/data-table/data-table-pagination.tsx"
1888
- ],
1889
- "props": [],
1890
- "examples": [
2013
+ "code": "{/* Custom icon */}\n<DataTableColumnOrder label=\"Column order\" icon={<MyIcon />} />\n\n{/* Fully custom trigger */}\n<DataTableColumnOrder label=\"Column order\" trigger={<Button>Reorder</Button>} />"
2014
+ },
1891
2015
  {
1892
2016
  "language": "tsx",
1893
2017
  "meta": null,
1894
- "code": "import { DataTable, DataTableContent, DataTablePagination } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n return (\n <DataTable\n columns={columns}\n data={data} // Full dataset\n pagination={{ pageSize: 10 }}\n >\n <DataTableContent />\n <DataTablePagination className=\"mt-4\" />\n </DataTable>\n )\n}"
2018
+ "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"id\",\n header: \"ID\",\n meta: { enableOrdering: false }, // Cannot be reordered\n },\n {\n accessorKey: \"name\",\n header: \"Name\",\n // Reorderable by default\n },\n]"
1895
2019
  },
1896
2020
  {
1897
2021
  "language": "tsx",
1898
2022
  "meta": null,
1899
- "code": "import { useState } from \"react\"\nimport type { PaginationState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent, DataTablePagination } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 10,\n })\n\n // In real app, use TanStack Query or similar\n const { data, totalItems } = useServerData(pagination)\n\n return (\n <DataTable\n columns={columns}\n data={data} // Only current page data from server\n pagination={{\n pageIndex: pagination.pageIndex,\n pageSize: pagination.pageSize,\n totalItems: totalItems,\n onPaginationChange: setPagination,\n }}\n >\n <DataTableContent />\n <DataTablePagination className=\"mt-4\" />\n </DataTable>\n )\n}"
2023
+ "code": "import {\n DataTable,\n DataTableContent,\n type ColumnOrderState,\n} from \"@epilot/volt-ui\"\nimport { useLocalStorage } from \"@/hooks/useSessionStorage\"\n\nfunction MyTable() {\n const [columnOrder, setColumnOrder] = useLocalStorage<ColumnOrderState>(\n \"my-table-column-order\",\n []\n )\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableColumnOrdering\n columnOrder={columnOrder}\n onColumnOrderChange={setColumnOrder}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
1900
2024
  },
1901
2025
  {
1902
2026
  "language": "tsx",
1903
2027
  "meta": null,
1904
- "code": "type PaginationConfig = {\n pageIndex?: number // Controlled page index (0-indexed)\n pageSize?: number // Default: 10\n pageSizeOptions?: number[] // Default: [10, 25, 50, 100]\n totalItems?: number // Server-side pagination total\n pageCount?: number // Server-side pagination page count\n onPaginationChange?: (state: PaginationState) => void\n}"
1905
- }
1906
- ]
1907
- },
1908
- {
1909
- "name": "DataTableResizeHandle",
1910
- "title": null,
1911
- "description": null,
1912
- "docsPath": null,
1913
- "docSlug": null,
1914
- "documentationUrl": null,
1915
- "apiReferenceUrl": null,
1916
- "sourcePaths": [
1917
- "src/components/data-table/data-table-resize-handle.tsx"
1918
- ],
1919
- "props": [],
1920
- "examples": []
1921
- },
1922
- {
1923
- "name": "DataTableRow",
1924
- "title": null,
1925
- "description": null,
1926
- "docsPath": null,
1927
- "docSlug": null,
1928
- "documentationUrl": null,
1929
- "apiReferenceUrl": null,
1930
- "sourcePaths": [
1931
- "src/components/data-table/data-table-row.tsx"
1932
- ],
1933
- "props": [],
1934
- "examples": []
2028
+ "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nconst columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: \"Invoice\",\n size: 120, // Initial width\n minSize: 80, // Minimum width when resizing\n maxSize: 200, // Maximum width when resizing\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n size: 120,\n },\n {\n accessorKey: \"type\",\n header: \"Type\",\n size: 100,\n enableResizing: false, // Disable resizing for this column\n },\n // ...more columns\n]\n\n// Column resizing is enabled by default\n<DataTable columns={columns} data={data}>\n <DataTableContent />\n</DataTable>\n\n// To disable column resizing:\n<DataTable columns={columns} data={data} disableColumnResizing>\n <DataTableContent />\n</DataTable>"
2029
+ },
2030
+ {
2031
+ "language": "tsx",
2032
+ "meta": null,
2033
+ "code": "import { useState } from \"react\"\nimport type { ColumnSizingState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnSizing, setColumnSizing] = useState<ColumnSizingState>({\n id: 100,\n customer: 180,\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnSizing={columnSizing}\n onColumnSizingChange={setColumnSizing}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
2034
+ },
2035
+ {
2036
+ "language": "tsx",
2037
+ "meta": null,
2038
+ "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"id\",\n header: \"ID\",\n size: 60,\n enableResizing: false, // Cannot be resized\n },\n {\n accessorKey: \"name\",\n header: \"Name\",\n size: 150,\n minSize: 100, // Minimum 100px\n maxSize: 400, // Maximum 400px\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n // Uses defaults: minSize=20, maxSize=unlimited\n },\n]"
2039
+ },
2040
+ {
2041
+ "language": "tsx",
2042
+ "meta": null,
2043
+ "code": "// Default: handles appear on header hover\n<DataTable columns={columns} data={data}>\n <DataTableContent />\n</DataTable>\n\n// Always show resize handles\n<DataTable columns={columns} data={data} resizeHandleVisibility=\"always\">\n <DataTableContent />\n</DataTable>"
2044
+ },
2045
+ {
2046
+ "language": "tsx",
2047
+ "meta": null,
2048
+ "code": "import { useState } from \"react\"\nimport type { RowSelectionState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [rowSelection, setRowSelection] = useState<RowSelectionState>({})\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableRowSelection\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n autoPinSelection // Pin checkbox column when rows are selected\n >\n <DataTableContent />\n </DataTable>\n )\n}"
2049
+ },
2050
+ {
2051
+ "language": "tsx",
2052
+ "meta": null,
2053
+ "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\n<DataTable\n columns={columns}\n data={data}\n columnPinning={{ left: [\"id\"], right: [\"actions\"] }}\n>\n <DataTableContent />\n</DataTable>"
2054
+ },
2055
+ {
2056
+ "language": "tsx",
2057
+ "meta": null,
2058
+ "code": "import { useState } from \"react\"\nimport type { ColumnPinningState } from \"@epilot/volt-ui\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnPinning, setColumnPinning] = useState<ColumnPinningState>({\n left: [\"id\"],\n right: [],\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnPinning={columnPinning}\n onColumnPinningChange={setColumnPinning}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
2059
+ },
2060
+ {
2061
+ "language": "tsx",
2062
+ "meta": null,
2063
+ "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\n// Compact rows (smallest)\n<DataTable columns={columns} data={data} density=\"compact\">\n <DataTableContent />\n</DataTable>\n\n// Normal rows (default)\n<DataTable columns={columns} data={data} density=\"normal\">\n <DataTableContent />\n</DataTable>\n\n// Comfortable rows (largest)\n<DataTable columns={columns} data={data} density=\"comfortable\">\n <DataTableContent />\n</DataTable>"
2064
+ }
2065
+ ]
1935
2066
  },
1936
2067
  {
1937
- "name": "DataTableToolbar",
2068
+ "name": "DataTableContent",
1938
2069
  "title": "Columns & Filtering",
1939
2070
  "description": "Column visibility, resizing, pinning, and filtering options.",
1940
2071
  "docsPath": "docs/content/docs/components/data-table/columns.mdx",
@@ -1942,7 +2073,7 @@
1942
2073
  "documentationUrl": null,
1943
2074
  "apiReferenceUrl": null,
1944
2075
  "sourcePaths": [
1945
- "src/components/data-table/data-table-toolbar.tsx"
2076
+ "src/components/data-table/data-table-content.tsx"
1946
2077
  ],
1947
2078
  "props": [],
1948
2079
  "examples": [
@@ -1976,6 +2107,36 @@
1976
2107
  "meta": null,
1977
2108
  "code": "const columns: ColumnDef<Invoice>[] = [\n // ... other columns\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n meta: {\n visibilityLabel: \"Actions\", // Label shown in visibility dropdown\n },\n },\n]"
1978
2109
  },
2110
+ {
2111
+ "language": "tsx",
2112
+ "meta": null,
2113
+ "code": "<DataTable columns={columns} data={data} enableColumnOrdering>\n <DataTableContent />\n</DataTable>"
2114
+ },
2115
+ {
2116
+ "language": "tsx",
2117
+ "meta": null,
2118
+ "code": "import { useState } from \"react\"\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n DataTableColumnOrder,\n DataTableColumnVisibility,\n type ColumnOrderState,\n} from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnOrder, setColumnOrder] = useState<ColumnOrderState>([])\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnOrder={columnOrder}\n onColumnOrderChange={setColumnOrder}\n >\n <DataTableToolbar>\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
2119
+ },
2120
+ {
2121
+ "language": "tsx",
2122
+ "meta": null,
2123
+ "code": "<DataTable columns={columns} data={data}>\n <DataTableToolbar>\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n </DataTableToolbar>\n <DataTableContent />\n</DataTable>"
2124
+ },
2125
+ {
2126
+ "language": "tsx",
2127
+ "meta": null,
2128
+ "code": "{/* Custom icon */}\n<DataTableColumnOrder label=\"Column order\" icon={<MyIcon />} />\n\n{/* Fully custom trigger */}\n<DataTableColumnOrder label=\"Column order\" trigger={<Button>Reorder</Button>} />"
2129
+ },
2130
+ {
2131
+ "language": "tsx",
2132
+ "meta": null,
2133
+ "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"id\",\n header: \"ID\",\n meta: { enableOrdering: false }, // Cannot be reordered\n },\n {\n accessorKey: \"name\",\n header: \"Name\",\n // Reorderable by default\n },\n]"
2134
+ },
2135
+ {
2136
+ "language": "tsx",
2137
+ "meta": null,
2138
+ "code": "import {\n DataTable,\n DataTableContent,\n type ColumnOrderState,\n} from \"@epilot/volt-ui\"\nimport { useLocalStorage } from \"@/hooks/useSessionStorage\"\n\nfunction MyTable() {\n const [columnOrder, setColumnOrder] = useLocalStorage<ColumnOrderState>(\n \"my-table-column-order\",\n []\n )\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableColumnOrdering\n columnOrder={columnOrder}\n onColumnOrderChange={setColumnOrder}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
2139
+ },
1979
2140
  {
1980
2141
  "language": "tsx",
1981
2142
  "meta": null,
@@ -2019,66 +2180,1086 @@
2019
2180
  ]
2020
2181
  },
2021
2182
  {
2022
- "name": "DataTableVirtualizerContext",
2023
- "title": null,
2024
- "description": null,
2025
- "docsPath": null,
2026
- "docSlug": null,
2183
+ "name": "DataTableError",
2184
+ "title": "Advanced",
2185
+ "description": "Virtualization, loading/error states, and composable API.",
2186
+ "docsPath": "docs/content/docs/components/data-table/advanced.mdx",
2187
+ "docSlug": "data-table/advanced",
2027
2188
  "documentationUrl": null,
2028
2189
  "apiReferenceUrl": null,
2029
2190
  "sourcePaths": [
2030
- "src/components/data-table/data-table-context.tsx"
2191
+ "src/components/data-table/data-table-error.tsx"
2031
2192
  ],
2032
2193
  "props": [],
2033
- "examples": []
2194
+ "examples": [
2195
+ {
2196
+ "language": "tsx",
2197
+ "meta": null,
2198
+ "code": "import { useState, useMemo } from \"react\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction VirtualizedTable() {\n const [rowSelection, setRowSelection] = useState({})\n const largeDataset = useMemo(() => generateLargeData(15000), [])\n\n return (\n <DataTable\n columns={columns}\n data={largeDataset}\n enableSorting\n enableRowSelection\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n virtualization={{\n enabled: true,\n estimateRowHeight: 48, // Match your row height\n overscan: 10, // Render 10 extra rows beyond viewport\n containerHeight: 600, // Fixed height required for virtualization\n }}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
2199
+ },
2200
+ {
2201
+ "language": "tsx",
2202
+ "meta": null,
2203
+ "code": "type VirtualizationConfig = {\n enabled: boolean\n estimateRowHeight?: number // Default: 48\n overscan?: number // Default: 10\n containerHeight?: number // Default: 600\n}"
2204
+ },
2205
+ {
2206
+ "language": "tsx",
2207
+ "meta": null,
2208
+ "code": "import {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableToolbar,\n} from \"@epilot/volt-ui\"\n\nfunction ComposableTable() {\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n pagination={{ pageSize: 10 }}\n >\n <DataTableToolbar>\n <input placeholder=\"Search invoices...\" />\n </DataTableToolbar>\n\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n\n <DataTablePagination className=\"mt-4\" />\n </DataTable>\n )\n}"
2209
+ },
2210
+ {
2211
+ "language": "tsx",
2212
+ "meta": null,
2213
+ "code": "<DataTable\n columns={columns}\n data={largeDataset}\n enableSorting\n virtualization={{ enabled: true, containerHeight: 500 }}\n>\n <DataTableContent>\n <DataTableHeader sticky />\n <DataTableBody emptyState=\"No results found.\" />\n </DataTableContent>\n</DataTable>"
2214
+ },
2215
+ {
2216
+ "language": "tsx",
2217
+ "meta": null,
2218
+ "code": "import { DataTable, DataTableContent, DataTableHeader, DataTableBody, DataTableLoading } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const { data, isLoading } = useQuery(...)\n\n return (\n <DataTable columns={columns} data={data ?? []}>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody\n isLoading={isLoading}\n loadingState={<DataTableLoading />}\n emptyState=\"No invoices found.\"\n />\n </DataTableContent>\n </DataTable>\n )\n}"
2219
+ },
2220
+ {
2221
+ "language": "tsx",
2222
+ "meta": null,
2223
+ "code": "<DataTableBody\n isLoading={isLoading}\n loadingState={\n <DataTableLoading>\n <Spinner size=\"xl\" className=\"text-accent-light\" />\n <p className=\"mt-4 text-base font-medium\">{t('table.loading')}</p>\n <p className=\"text-sm text-gray-light\">{t('table.loading.description')}</p>\n </DataTableLoading>\n }\n/>"
2224
+ },
2225
+ {
2226
+ "language": "tsx",
2227
+ "meta": null,
2228
+ "code": "import { DataTable, DataTableContent, DataTableHeader, DataTableBody, DataTableError } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const { data, isLoading, isError, refetch } = useQuery(...)\n\n return (\n <DataTable columns={columns} data={data ?? []}>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody\n isLoading={isLoading}\n loadingState={<DataTableLoading />}\n isError={isError}\n errorState={\n <DataTableError\n title=\"Failed to load invoices\"\n description=\"There was a problem connecting to the server.\"\n retryLabel=\"Retry\"\n onRetry={refetch}\n />\n }\n emptyState=\"No invoices found.\"\n />\n </DataTableContent>\n </DataTable>\n )\n}"
2229
+ },
2230
+ {
2231
+ "language": "tsx",
2232
+ "meta": null,
2233
+ "code": "<DataTableBody\n isError={isError}\n errorState={\n <DataTableError>\n <AlertTriangle size={48} className=\"text-error-light\" />\n <p className=\"mt-2 text-lg font-semibold\">{t('table.error.title')}</p>\n <p className=\"text-sm text-gray-light\">{t('table.error.description')}</p>\n <div className=\"flex gap-2 mt-4\">\n <Button variant=\"secondary\" size=\"sm\" onClick={refetch}>\n {t('retry')}\n </Button>\n <Button variant=\"tertiary\" size=\"sm\">\n {t('contact_support')}\n </Button>\n </div>\n </DataTableError>\n }\n/>"
2234
+ },
2235
+ {
2236
+ "language": "tsx",
2237
+ "meta": null,
2238
+ "code": "// Default - borders visible on header and rows\n<DataTable columns={columns} data={data} />\n\n// Hide all borders\n<DataTable\n columns={columns}\n data={data}\n showHeaderBorder={false}\n showRowBorders={false}\n/>\n\n// Hide only row borders (keep header border)\n<DataTable\n columns={columns}\n data={data}\n showRowBorders={false}\n/>\n\n// Hide only header border (keep row borders)\n<DataTable\n columns={columns}\n data={data}\n showHeaderBorder={false}\n/>"
2239
+ },
2240
+ {
2241
+ "language": "tsx",
2242
+ "meta": null,
2243
+ "code": "// Default uses var(--volt-gray-2)\n<DataTableHeader sticky />\n\n// Custom background color\n<DataTableHeader sticky stickyBackground=\"white\" />\n\n// Use a different volt gray\n<DataTableHeader sticky stickyBackground=\"var(--volt-gray-1)\" />\n\n// Custom CSS variable\n<DataTableHeader sticky stickyBackground=\"var(--my-header-bg)\" />"
2244
+ }
2245
+ ]
2034
2246
  },
2035
2247
  {
2036
- "name": "Dialog",
2037
- "title": "Dialog",
2038
- "description": "A Dialog is a modal surface that appears above the main interface to capture the user’s attention",
2039
- "docsPath": "docs/content/docs/components/dialog.mdx",
2040
- "docSlug": "dialog",
2041
- "documentationUrl": "https://www.radix-ui.com/docs/primitives/components/dialog",
2042
- "apiReferenceUrl": "https://www.radix-ui.com/docs/primitives/components/dialog#api-reference",
2248
+ "name": "DataTableFooter",
2249
+ "title": "Data Table",
2250
+ "description": "A powerful data table component built on Tanstack Table with support for sorting, filtering, pagination, row selection, and virtualization.",
2251
+ "docsPath": "docs/content/docs/components/data-table/index.mdx",
2252
+ "docSlug": "data-table/index",
2253
+ "documentationUrl": null,
2254
+ "apiReferenceUrl": null,
2043
2255
  "sourcePaths": [
2044
- "src/components/dialog/dialog.tsx"
2256
+ "src/components/data-table/data-table-footer.tsx"
2045
2257
  ],
2046
- "props": [
2258
+ "props": [],
2259
+ "examples": [
2047
2260
  {
2048
- "name": "`open`",
2049
- "type": "boolean",
2050
- "default": "-",
2051
- "description": "Controlled open state of the dialog."
2261
+ "language": "tsx",
2262
+ "meta": null,
2263
+ "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\ntype Invoice = {\n id: string\n status: string\n customer: string\n amount: number\n}\n\nconst columns: ColumnDef<Invoice>[] = [\n { accessorKey: \"id\", header: \"Invoice\" },\n { accessorKey: \"status\", header: \"Status\" },\n { accessorKey: \"customer\", header: \"Customer\" },\n { accessorKey: \"amount\", header: \"Amount\" },\n]\n\n// Column resizing is enabled by default. Disable if you prefer fixed columns:\n<DataTable columns={columns} data={invoices} disableColumnResizing>\n <DataTableContent />\n</DataTable>"
2052
2264
  },
2053
2265
  {
2054
- "name": "`defaultOpen`",
2055
- "type": "boolean",
2056
- "default": "`false`",
2057
- "description": "Uncontrolled default open state."
2266
+ "language": "tsx",
2267
+ "meta": null,
2268
+ "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableColumnOrder,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction FullExample() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [rowSelection, setRowSelection] = useState({})\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n enableRowSelection\n enableColumnOrdering\n enableGlobalFilter\n enableFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{ pageSize: 10 }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
2058
2269
  },
2059
2270
  {
2060
- "name": "`onOpenChange`",
2061
- "type": "(open: boolean) => void",
2062
- "default": "-",
2063
- "description": "Callback fired when the open state changes."
2271
+ "language": "tsx",
2272
+ "meta": null,
2273
+ "code": "import { useState, useMemo } from \"react\"\nimport type { ColumnFiltersState, PaginationState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableColumnOrder,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction ServerExample() {\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 10,\n })\n const [sorting, setSorting] = useState<SortingState>([])\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [rowSelection, setRowSelection] = useState({})\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n // In a real app, use useQuery with pagination/sorting/filters as query keys\n const { data, totalItems } = useServerData({\n pagination,\n sorting,\n globalFilter,\n statusFilter,\n typeFilter,\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n manualSorting\n enableRowSelection\n enableColumnOrdering\n enableGlobalFilter\n enableFiltering\n manualFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{\n pageIndex: pagination.pageIndex,\n pageSize: pagination.pageSize,\n totalItems: totalItems,\n onPaginationChange: setPagination,\n }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => {\n setGlobalFilter(e.target.value)\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button\n variant=\"tertiary\"\n size=\"sm\"\n onClick={() => {\n setColumnFilters([])\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n >\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
2064
2274
  },
2065
2275
  {
2066
- "name": "`modal`",
2067
- "type": "boolean",
2068
- "default": "`true`",
2069
- "description": "When true, focus is trapped within the dialog and outside interaction is disabled."
2276
+ "language": "tsx",
2277
+ "meta": null,
2278
+ "code": "<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
2279
+ },
2280
+ {
2281
+ "language": "tsx",
2282
+ "meta": null,
2283
+ "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"description\",\n header: \"Description\",\n size: 200,\n meta: { cellOverflow: \"wrap\" }, // This column wraps, others truncate\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n // Uses table default\n },\n]\n\n<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
2284
+ },
2285
+ {
2286
+ "language": "tsx",
2287
+ "meta": null,
2288
+ "code": "import { DataTable, DataTableContent, DataTableColumnHeader } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nconst columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Invoice\" />,\n },\n {\n accessorKey: \"customer\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Customer\" />,\n },\n // ...more columns\n]\n\n<DataTable columns={columns} data={data} enableSorting>\n <DataTableContent />\n</DataTable>"
2289
+ },
2290
+ {
2291
+ "language": "tsx",
2292
+ "meta": null,
2293
+ "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableFooter, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [pageSize, setPageSize] = useState(5)\n const visibleData = data.slice(0, pageSize)\n const hasMore = pageSize < data.length\n\n return (\n <DataTable columns={columns} data={visibleData}>\n <DataTableContent />\n {hasMore && (\n <DataTableFooter className=\"justify-start\">\n <Button size=\"sm\" variant=\"tertiary\" onClick={() => setPageSize((prev) => prev + 3)}>\n Show more ({data.length - pageSize} remaining)\n </Button>\n </DataTableFooter>\n )}\n </DataTable>\n )\n}"
2294
+ },
2295
+ {
2296
+ "language": "tsx",
2297
+ "meta": null,
2298
+ "code": "{\n accessorKey: \"name\",\n header: \"Name\",\n}"
2299
+ },
2300
+ {
2301
+ "language": "tsx",
2302
+ "meta": null,
2303
+ "code": "{\n accessorKey: \"status\",\n header: \"Status\",\n cell: ({ row }) => <Badge>{row.getValue(\"status\")}</Badge>,\n}"
2304
+ },
2305
+ {
2306
+ "language": "tsx",
2307
+ "meta": null,
2308
+ "code": "{\n accessorKey: \"date\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Date\" />,\n}"
2309
+ },
2310
+ {
2311
+ "language": "tsx",
2312
+ "meta": null,
2313
+ "code": "{\n accessorKey: \"amount\",\n header: () => <div className=\"text-right\">Amount</div>,\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" },\n}"
2314
+ },
2315
+ {
2316
+ "language": "tsx",
2317
+ "meta": null,
2318
+ "code": "{\n accessorKey: \"amount\",\n header: ({ column }) => (\n <div className=\"flex justify-end\">\n <DataTableColumnHeader column={column} title=\"Amount\" />\n </div>\n ),\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" }, // Ensures proper header padding alignment\n}"
2070
2319
  }
2320
+ ]
2321
+ },
2322
+ {
2323
+ "name": "DataTableHeader",
2324
+ "title": "Data Table",
2325
+ "description": "A powerful data table component built on Tanstack Table with support for sorting, filtering, pagination, row selection, and virtualization.",
2326
+ "docsPath": "docs/content/docs/components/data-table/index.mdx",
2327
+ "docSlug": "data-table/index",
2328
+ "documentationUrl": null,
2329
+ "apiReferenceUrl": null,
2330
+ "sourcePaths": [
2331
+ "src/components/data-table/data-table-header.tsx"
2071
2332
  ],
2333
+ "props": [],
2072
2334
  "examples": [
2335
+ {
2336
+ "language": "tsx",
2337
+ "meta": null,
2338
+ "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\ntype Invoice = {\n id: string\n status: string\n customer: string\n amount: number\n}\n\nconst columns: ColumnDef<Invoice>[] = [\n { accessorKey: \"id\", header: \"Invoice\" },\n { accessorKey: \"status\", header: \"Status\" },\n { accessorKey: \"customer\", header: \"Customer\" },\n { accessorKey: \"amount\", header: \"Amount\" },\n]\n\n// Column resizing is enabled by default. Disable if you prefer fixed columns:\n<DataTable columns={columns} data={invoices} disableColumnResizing>\n <DataTableContent />\n</DataTable>"
2339
+ },
2340
+ {
2341
+ "language": "tsx",
2342
+ "meta": null,
2343
+ "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableColumnOrder,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction FullExample() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [rowSelection, setRowSelection] = useState({})\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n enableRowSelection\n enableColumnOrdering\n enableGlobalFilter\n enableFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{ pageSize: 10 }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
2344
+ },
2345
+ {
2346
+ "language": "tsx",
2347
+ "meta": null,
2348
+ "code": "import { useState, useMemo } from \"react\"\nimport type { ColumnFiltersState, PaginationState, SortingState } from \"@tanstack/react-table\"\nimport {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableColumnVisibility,\n DataTableColumnOrder,\n DataTableToolbar,\n Button,\n} from \"@epilot/volt-ui\"\n\nfunction ServerExample() {\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 10,\n })\n const [sorting, setSorting] = useState<SortingState>([])\n const [globalFilter, setGlobalFilter] = useState(\"\")\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [rowSelection, setRowSelection] = useState({})\n\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }\n\n // In a real app, use useQuery with pagination/sorting/filters as query keys\n const { data, totalItems } = useServerData({\n pagination,\n sorting,\n globalFilter,\n statusFilter,\n typeFilter,\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n manualSorting\n enableRowSelection\n enableColumnOrdering\n enableGlobalFilter\n enableFiltering\n manualFiltering\n sorting={sorting}\n onSortingChange={setSorting}\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n pagination={{\n pageIndex: pagination.pageIndex,\n pageSize: pagination.pageSize,\n totalItems: totalItems,\n onPaginationChange: setPagination,\n }}\n >\n <DataTableToolbar>\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={globalFilter}\n onChange={(e) => {\n setGlobalFilter(e.target.value)\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n />\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button\n variant=\"tertiary\"\n size=\"sm\"\n onClick={() => {\n setColumnFilters([])\n setPagination((prev) => ({ ...prev, pageIndex: 0 }))\n }}\n >\n Clear filters\n </Button>\n )}\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n <DataTablePagination />\n </DataTable>\n )\n}"
2349
+ },
2350
+ {
2351
+ "language": "tsx",
2352
+ "meta": null,
2353
+ "code": "<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
2354
+ },
2355
+ {
2356
+ "language": "tsx",
2357
+ "meta": null,
2358
+ "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"description\",\n header: \"Description\",\n size: 200,\n meta: { cellOverflow: \"wrap\" }, // This column wraps, others truncate\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n // Uses table default\n },\n]\n\n<DataTable columns={columns} data={data} cellOverflow=\"truncate\">\n <DataTableContent />\n</DataTable>"
2359
+ },
2360
+ {
2361
+ "language": "tsx",
2362
+ "meta": null,
2363
+ "code": "import { DataTable, DataTableContent, DataTableColumnHeader } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nconst columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Invoice\" />,\n },\n {\n accessorKey: \"customer\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Customer\" />,\n },\n // ...more columns\n]\n\n<DataTable columns={columns} data={data} enableSorting>\n <DataTableContent />\n</DataTable>"
2364
+ },
2365
+ {
2366
+ "language": "tsx",
2367
+ "meta": null,
2368
+ "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableFooter, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [pageSize, setPageSize] = useState(5)\n const visibleData = data.slice(0, pageSize)\n const hasMore = pageSize < data.length\n\n return (\n <DataTable columns={columns} data={visibleData}>\n <DataTableContent />\n {hasMore && (\n <DataTableFooter className=\"justify-start\">\n <Button size=\"sm\" variant=\"tertiary\" onClick={() => setPageSize((prev) => prev + 3)}>\n Show more ({data.length - pageSize} remaining)\n </Button>\n </DataTableFooter>\n )}\n </DataTable>\n )\n}"
2369
+ },
2370
+ {
2371
+ "language": "tsx",
2372
+ "meta": null,
2373
+ "code": "{\n accessorKey: \"name\",\n header: \"Name\",\n}"
2374
+ },
2375
+ {
2376
+ "language": "tsx",
2377
+ "meta": null,
2378
+ "code": "{\n accessorKey: \"status\",\n header: \"Status\",\n cell: ({ row }) => <Badge>{row.getValue(\"status\")}</Badge>,\n}"
2379
+ },
2380
+ {
2381
+ "language": "tsx",
2382
+ "meta": null,
2383
+ "code": "{\n accessorKey: \"date\",\n header: ({ column }) => <DataTableColumnHeader column={column} title=\"Date\" />,\n}"
2384
+ },
2385
+ {
2386
+ "language": "tsx",
2387
+ "meta": null,
2388
+ "code": "{\n accessorKey: \"amount\",\n header: () => <div className=\"text-right\">Amount</div>,\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" },\n}"
2389
+ },
2390
+ {
2391
+ "language": "tsx",
2392
+ "meta": null,
2393
+ "code": "{\n accessorKey: \"amount\",\n header: ({ column }) => (\n <div className=\"flex justify-end\">\n <DataTableColumnHeader column={column} title=\"Amount\" />\n </div>\n ),\n cell: ({ row }) => (\n <div className=\"text-right tabular-nums\">\n {formatCurrency(row.getValue(\"amount\"))}\n </div>\n ),\n meta: { align: \"right\" }, // Ensures proper header padding alignment\n}"
2394
+ }
2395
+ ]
2396
+ },
2397
+ {
2398
+ "name": "DataTableLoading",
2399
+ "title": "Advanced",
2400
+ "description": "Virtualization, loading/error states, and composable API.",
2401
+ "docsPath": "docs/content/docs/components/data-table/advanced.mdx",
2402
+ "docSlug": "data-table/advanced",
2403
+ "documentationUrl": null,
2404
+ "apiReferenceUrl": null,
2405
+ "sourcePaths": [
2406
+ "src/components/data-table/data-table-loading.tsx"
2407
+ ],
2408
+ "props": [],
2409
+ "examples": [
2410
+ {
2411
+ "language": "tsx",
2412
+ "meta": null,
2413
+ "code": "import { useState, useMemo } from \"react\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction VirtualizedTable() {\n const [rowSelection, setRowSelection] = useState({})\n const largeDataset = useMemo(() => generateLargeData(15000), [])\n\n return (\n <DataTable\n columns={columns}\n data={largeDataset}\n enableSorting\n enableRowSelection\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n virtualization={{\n enabled: true,\n estimateRowHeight: 48, // Match your row height\n overscan: 10, // Render 10 extra rows beyond viewport\n containerHeight: 600, // Fixed height required for virtualization\n }}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
2414
+ },
2415
+ {
2416
+ "language": "tsx",
2417
+ "meta": null,
2418
+ "code": "type VirtualizationConfig = {\n enabled: boolean\n estimateRowHeight?: number // Default: 48\n overscan?: number // Default: 10\n containerHeight?: number // Default: 600\n}"
2419
+ },
2420
+ {
2421
+ "language": "tsx",
2422
+ "meta": null,
2423
+ "code": "import {\n DataTable,\n DataTableContent,\n DataTableHeader,\n DataTableBody,\n DataTablePagination,\n DataTableToolbar,\n} from \"@epilot/volt-ui\"\n\nfunction ComposableTable() {\n return (\n <DataTable\n columns={columns}\n data={data}\n enableSorting\n pagination={{ pageSize: 10 }}\n >\n <DataTableToolbar>\n <input placeholder=\"Search invoices...\" />\n </DataTableToolbar>\n\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody />\n </DataTableContent>\n\n <DataTablePagination className=\"mt-4\" />\n </DataTable>\n )\n}"
2424
+ },
2425
+ {
2426
+ "language": "tsx",
2427
+ "meta": null,
2428
+ "code": "<DataTable\n columns={columns}\n data={largeDataset}\n enableSorting\n virtualization={{ enabled: true, containerHeight: 500 }}\n>\n <DataTableContent>\n <DataTableHeader sticky />\n <DataTableBody emptyState=\"No results found.\" />\n </DataTableContent>\n</DataTable>"
2429
+ },
2430
+ {
2431
+ "language": "tsx",
2432
+ "meta": null,
2433
+ "code": "import { DataTable, DataTableContent, DataTableHeader, DataTableBody, DataTableLoading } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const { data, isLoading } = useQuery(...)\n\n return (\n <DataTable columns={columns} data={data ?? []}>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody\n isLoading={isLoading}\n loadingState={<DataTableLoading />}\n emptyState=\"No invoices found.\"\n />\n </DataTableContent>\n </DataTable>\n )\n}"
2434
+ },
2435
+ {
2436
+ "language": "tsx",
2437
+ "meta": null,
2438
+ "code": "<DataTableBody\n isLoading={isLoading}\n loadingState={\n <DataTableLoading>\n <Spinner size=\"xl\" className=\"text-accent-light\" />\n <p className=\"mt-4 text-base font-medium\">{t('table.loading')}</p>\n <p className=\"text-sm text-gray-light\">{t('table.loading.description')}</p>\n </DataTableLoading>\n }\n/>"
2439
+ },
2440
+ {
2441
+ "language": "tsx",
2442
+ "meta": null,
2443
+ "code": "import { DataTable, DataTableContent, DataTableHeader, DataTableBody, DataTableError } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const { data, isLoading, isError, refetch } = useQuery(...)\n\n return (\n <DataTable columns={columns} data={data ?? []}>\n <DataTableContent>\n <DataTableHeader />\n <DataTableBody\n isLoading={isLoading}\n loadingState={<DataTableLoading />}\n isError={isError}\n errorState={\n <DataTableError\n title=\"Failed to load invoices\"\n description=\"There was a problem connecting to the server.\"\n retryLabel=\"Retry\"\n onRetry={refetch}\n />\n }\n emptyState=\"No invoices found.\"\n />\n </DataTableContent>\n </DataTable>\n )\n}"
2444
+ },
2445
+ {
2446
+ "language": "tsx",
2447
+ "meta": null,
2448
+ "code": "<DataTableBody\n isError={isError}\n errorState={\n <DataTableError>\n <AlertTriangle size={48} className=\"text-error-light\" />\n <p className=\"mt-2 text-lg font-semibold\">{t('table.error.title')}</p>\n <p className=\"text-sm text-gray-light\">{t('table.error.description')}</p>\n <div className=\"flex gap-2 mt-4\">\n <Button variant=\"secondary\" size=\"sm\" onClick={refetch}>\n {t('retry')}\n </Button>\n <Button variant=\"tertiary\" size=\"sm\">\n {t('contact_support')}\n </Button>\n </div>\n </DataTableError>\n }\n/>"
2449
+ },
2450
+ {
2451
+ "language": "tsx",
2452
+ "meta": null,
2453
+ "code": "// Default - borders visible on header and rows\n<DataTable columns={columns} data={data} />\n\n// Hide all borders\n<DataTable\n columns={columns}\n data={data}\n showHeaderBorder={false}\n showRowBorders={false}\n/>\n\n// Hide only row borders (keep header border)\n<DataTable\n columns={columns}\n data={data}\n showRowBorders={false}\n/>\n\n// Hide only header border (keep row borders)\n<DataTable\n columns={columns}\n data={data}\n showHeaderBorder={false}\n/>"
2454
+ },
2455
+ {
2456
+ "language": "tsx",
2457
+ "meta": null,
2458
+ "code": "// Default uses var(--volt-gray-2)\n<DataTableHeader sticky />\n\n// Custom background color\n<DataTableHeader sticky stickyBackground=\"white\" />\n\n// Use a different volt gray\n<DataTableHeader sticky stickyBackground=\"var(--volt-gray-1)\" />\n\n// Custom CSS variable\n<DataTableHeader sticky stickyBackground=\"var(--my-header-bg)\" />"
2459
+ }
2460
+ ]
2461
+ },
2462
+ {
2463
+ "name": "DataTablePagination",
2464
+ "title": "Pagination",
2465
+ "description": "Client-side and server-side pagination for DataTable.",
2466
+ "docsPath": "docs/content/docs/components/data-table/pagination.mdx",
2467
+ "docSlug": "data-table/pagination",
2468
+ "documentationUrl": null,
2469
+ "apiReferenceUrl": null,
2470
+ "sourcePaths": [
2471
+ "src/components/data-table/data-table-pagination.tsx"
2472
+ ],
2473
+ "props": [],
2474
+ "examples": [
2475
+ {
2476
+ "language": "tsx",
2477
+ "meta": null,
2478
+ "code": "import { DataTable, DataTableContent, DataTablePagination } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n return (\n <DataTable\n columns={columns}\n data={data} // Full dataset\n pagination={{ pageSize: 10 }}\n >\n <DataTableContent />\n <DataTablePagination className=\"mt-4\" />\n </DataTable>\n )\n}"
2479
+ },
2480
+ {
2481
+ "language": "tsx",
2482
+ "meta": null,
2483
+ "code": "import { useState } from \"react\"\nimport type { PaginationState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent, DataTablePagination } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [pagination, setPagination] = useState<PaginationState>({\n pageIndex: 0,\n pageSize: 10,\n })\n\n // In real app, use TanStack Query or similar\n const { data, totalItems } = useServerData(pagination)\n\n return (\n <DataTable\n columns={columns}\n data={data} // Only current page data from server\n pagination={{\n pageIndex: pagination.pageIndex,\n pageSize: pagination.pageSize,\n totalItems: totalItems,\n onPaginationChange: setPagination,\n }}\n >\n <DataTableContent />\n <DataTablePagination className=\"mt-4\" />\n </DataTable>\n )\n}"
2484
+ },
2485
+ {
2486
+ "language": "tsx",
2487
+ "meta": null,
2488
+ "code": "type PaginationConfig = {\n pageIndex?: number // Controlled page index (0-indexed)\n pageSize?: number // Default: 10\n pageSizeOptions?: number[] // Default: [10, 25, 50, 100]\n totalItems?: number // Server-side pagination total\n pageCount?: number // Server-side pagination page count\n onPaginationChange?: (state: PaginationState) => void\n}"
2489
+ }
2490
+ ]
2491
+ },
2492
+ {
2493
+ "name": "DataTableResizeHandle",
2494
+ "title": null,
2495
+ "description": null,
2496
+ "docsPath": null,
2497
+ "docSlug": null,
2498
+ "documentationUrl": null,
2499
+ "apiReferenceUrl": null,
2500
+ "sourcePaths": [
2501
+ "src/components/data-table/data-table-resize-handle.tsx"
2502
+ ],
2503
+ "props": [],
2504
+ "examples": []
2505
+ },
2506
+ {
2507
+ "name": "DataTableRow",
2508
+ "title": null,
2509
+ "description": null,
2510
+ "docsPath": null,
2511
+ "docSlug": null,
2512
+ "documentationUrl": null,
2513
+ "apiReferenceUrl": null,
2514
+ "sourcePaths": [
2515
+ "src/components/data-table/data-table-row.tsx"
2516
+ ],
2517
+ "props": [],
2518
+ "examples": []
2519
+ },
2520
+ {
2521
+ "name": "DataTableToolbar",
2522
+ "title": "Columns & Filtering",
2523
+ "description": "Column visibility, resizing, pinning, and filtering options.",
2524
+ "docsPath": "docs/content/docs/components/data-table/columns.mdx",
2525
+ "docSlug": "data-table/columns",
2526
+ "documentationUrl": null,
2527
+ "apiReferenceUrl": null,
2528
+ "sourcePaths": [
2529
+ "src/components/data-table/data-table-toolbar.tsx"
2530
+ ],
2531
+ "props": [],
2532
+ "examples": [
2533
+ {
2534
+ "language": "tsx",
2535
+ "meta": null,
2536
+ "code": "import { useState } from \"react\"\nimport { DataTable, DataTableContent, DataTableToolbar } from \"@epilot/volt-ui\"\nimport { IconSearch } from \"@tabler/icons-react\"\n\nfunction MyTable() {\n const [globalFilter, setGlobalFilter] = useState(\"\")\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableGlobalFilter\n globalFilter={globalFilter}\n onGlobalFilterChange={setGlobalFilter}\n >\n <DataTableToolbar>\n <div className=\"flex items-center gap-2 rounded-lg border border-gray-a6 px-3 py-1.5\">\n <IconSearch size={18} />\n <input\n type=\"text\"\n placeholder=\"Search all columns...\"\n value={globalFilter}\n onChange={(e) => setGlobalFilter(e.target.value)}\n />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
2537
+ },
2538
+ {
2539
+ "language": "tsx",
2540
+ "meta": null,
2541
+ "code": "import { useState } from \"react\"\nimport type { ColumnFiltersState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent, DataTableToolbar, Button } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n\n // Get current filter values\n const statusFilter = columnFilters.find((f) => f.id === \"status\")?.value as string | undefined\n const typeFilter = columnFilters.find((f) => f.id === \"type\")?.value as string | undefined\n\n // Update status filter\n const setStatusFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"status\"), { id: \"status\", value }]\n : prev.filter((f) => f.id !== \"status\")\n )\n }\n\n // Update type filter\n const setTypeFilter = (value: string | undefined) => {\n setColumnFilters((prev) =>\n value\n ? [...prev.filter((f) => f.id !== \"type\"), { id: \"type\", value }]\n : prev.filter((f) => f.id !== \"type\")\n )\n }\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableFiltering\n columnFilters={columnFilters}\n onColumnFiltersChange={setColumnFilters}\n >\n <DataTableToolbar>\n <select\n value={statusFilter ?? \"\"}\n onChange={(e) => setStatusFilter(e.target.value || undefined)}\n >\n <option value=\"\">All statuses</option>\n <option value=\"paid\">Paid</option>\n <option value=\"pending\">Pending</option>\n <option value=\"overdue\">Overdue</option>\n </select>\n <select\n value={typeFilter ?? \"\"}\n onChange={(e) => setTypeFilter(e.target.value || undefined)}\n >\n <option value=\"\">All types</option>\n <option value=\"credit\">Credit</option>\n <option value=\"debit\">Debit</option>\n </select>\n {columnFilters.length > 0 && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={() => setColumnFilters([])}>\n Clear filters\n </Button>\n )}\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
2542
+ },
2543
+ {
2544
+ "language": "tsx",
2545
+ "meta": null,
2546
+ "code": "import { useState } from \"react\"\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n DataTableColumnVisibility,\n} from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n return (\n <DataTable columns={columns} data={data} enableSorting>\n <DataTableToolbar>\n <div className=\"flex-1\" />\n {/* Use -mr-1 wrapper to align icon with toolbar edge (compensates for button hover padding) */}\n <div className=\"-mr-1\">\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </div>\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
2547
+ },
2548
+ {
2549
+ "language": "tsx",
2550
+ "meta": null,
2551
+ "code": "const columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: \"Invoice\",\n enableHiding: false, // This column won't appear in the visibility dropdown\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n // enableHiding defaults to true\n },\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n enableHiding: false, // Actions column should always be visible\n },\n]"
2552
+ },
2553
+ {
2554
+ "language": "tsx",
2555
+ "meta": null,
2556
+ "code": "import { Button } from \"@epilot/volt-ui\"\n\n<DataTableColumnVisibility\n label=\"Toggle columns\"\n trigger={\n <Button variant=\"tertiary\" size=\"sm\">\n Columns\n </Button>\n }\n/>"
2557
+ },
2558
+ {
2559
+ "language": "tsx",
2560
+ "meta": null,
2561
+ "code": "const columns: ColumnDef<Invoice>[] = [\n // ... other columns\n {\n id: \"actions\",\n cell: ({ row }) => <ActionsMenu row={row} />,\n meta: {\n visibilityLabel: \"Actions\", // Label shown in visibility dropdown\n },\n },\n]"
2562
+ },
2563
+ {
2564
+ "language": "tsx",
2565
+ "meta": null,
2566
+ "code": "<DataTable columns={columns} data={data} enableColumnOrdering>\n <DataTableContent />\n</DataTable>"
2567
+ },
2568
+ {
2569
+ "language": "tsx",
2570
+ "meta": null,
2571
+ "code": "import { useState } from \"react\"\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n DataTableColumnOrder,\n DataTableColumnVisibility,\n type ColumnOrderState,\n} from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnOrder, setColumnOrder] = useState<ColumnOrderState>([])\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnOrder={columnOrder}\n onColumnOrderChange={setColumnOrder}\n >\n <DataTableToolbar>\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n <DataTableColumnVisibility label=\"Toggle columns\" />\n </DataTableToolbar>\n <DataTableContent />\n </DataTable>\n )\n}"
2572
+ },
2573
+ {
2574
+ "language": "tsx",
2575
+ "meta": null,
2576
+ "code": "<DataTable columns={columns} data={data}>\n <DataTableToolbar>\n <div className=\"flex-1\" />\n <DataTableColumnOrder label=\"Column order\" />\n </DataTableToolbar>\n <DataTableContent />\n</DataTable>"
2577
+ },
2578
+ {
2579
+ "language": "tsx",
2580
+ "meta": null,
2581
+ "code": "{/* Custom icon */}\n<DataTableColumnOrder label=\"Column order\" icon={<MyIcon />} />\n\n{/* Fully custom trigger */}\n<DataTableColumnOrder label=\"Column order\" trigger={<Button>Reorder</Button>} />"
2582
+ },
2583
+ {
2584
+ "language": "tsx",
2585
+ "meta": null,
2586
+ "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"id\",\n header: \"ID\",\n meta: { enableOrdering: false }, // Cannot be reordered\n },\n {\n accessorKey: \"name\",\n header: \"Name\",\n // Reorderable by default\n },\n]"
2587
+ },
2588
+ {
2589
+ "language": "tsx",
2590
+ "meta": null,
2591
+ "code": "import {\n DataTable,\n DataTableContent,\n type ColumnOrderState,\n} from \"@epilot/volt-ui\"\nimport { useLocalStorage } from \"@/hooks/useSessionStorage\"\n\nfunction MyTable() {\n const [columnOrder, setColumnOrder] = useLocalStorage<ColumnOrderState>(\n \"my-table-column-order\",\n []\n )\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableColumnOrdering\n columnOrder={columnOrder}\n onColumnOrderChange={setColumnOrder}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
2592
+ },
2593
+ {
2594
+ "language": "tsx",
2595
+ "meta": null,
2596
+ "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nconst columns: ColumnDef<Invoice>[] = [\n {\n accessorKey: \"id\",\n header: \"Invoice\",\n size: 120, // Initial width\n minSize: 80, // Minimum width when resizing\n maxSize: 200, // Maximum width when resizing\n },\n {\n accessorKey: \"status\",\n header: \"Status\",\n size: 120,\n },\n {\n accessorKey: \"type\",\n header: \"Type\",\n size: 100,\n enableResizing: false, // Disable resizing for this column\n },\n // ...more columns\n]\n\n// Column resizing is enabled by default\n<DataTable columns={columns} data={data}>\n <DataTableContent />\n</DataTable>\n\n// To disable column resizing:\n<DataTable columns={columns} data={data} disableColumnResizing>\n <DataTableContent />\n</DataTable>"
2597
+ },
2598
+ {
2599
+ "language": "tsx",
2600
+ "meta": null,
2601
+ "code": "import { useState } from \"react\"\nimport type { ColumnSizingState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnSizing, setColumnSizing] = useState<ColumnSizingState>({\n id: 100,\n customer: 180,\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnSizing={columnSizing}\n onColumnSizingChange={setColumnSizing}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
2602
+ },
2603
+ {
2604
+ "language": "tsx",
2605
+ "meta": null,
2606
+ "code": "const columns: ColumnDef<Data>[] = [\n {\n accessorKey: \"id\",\n header: \"ID\",\n size: 60,\n enableResizing: false, // Cannot be resized\n },\n {\n accessorKey: \"name\",\n header: \"Name\",\n size: 150,\n minSize: 100, // Minimum 100px\n maxSize: 400, // Maximum 400px\n },\n {\n accessorKey: \"email\",\n header: \"Email\",\n // Uses defaults: minSize=20, maxSize=unlimited\n },\n]"
2607
+ },
2608
+ {
2609
+ "language": "tsx",
2610
+ "meta": null,
2611
+ "code": "// Default: handles appear on header hover\n<DataTable columns={columns} data={data}>\n <DataTableContent />\n</DataTable>\n\n// Always show resize handles\n<DataTable columns={columns} data={data} resizeHandleVisibility=\"always\">\n <DataTableContent />\n</DataTable>"
2612
+ },
2613
+ {
2614
+ "language": "tsx",
2615
+ "meta": null,
2616
+ "code": "import { useState } from \"react\"\nimport type { RowSelectionState } from \"@tanstack/react-table\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [rowSelection, setRowSelection] = useState<RowSelectionState>({})\n\n return (\n <DataTable\n columns={columns}\n data={data}\n enableRowSelection\n rowSelection={rowSelection}\n onRowSelectionChange={setRowSelection}\n autoPinSelection // Pin checkbox column when rows are selected\n >\n <DataTableContent />\n </DataTable>\n )\n}"
2617
+ },
2618
+ {
2619
+ "language": "tsx",
2620
+ "meta": null,
2621
+ "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\n<DataTable\n columns={columns}\n data={data}\n columnPinning={{ left: [\"id\"], right: [\"actions\"] }}\n>\n <DataTableContent />\n</DataTable>"
2622
+ },
2623
+ {
2624
+ "language": "tsx",
2625
+ "meta": null,
2626
+ "code": "import { useState } from \"react\"\nimport type { ColumnPinningState } from \"@epilot/volt-ui\"\nimport { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\nfunction MyTable() {\n const [columnPinning, setColumnPinning] = useState<ColumnPinningState>({\n left: [\"id\"],\n right: [],\n })\n\n return (\n <DataTable\n columns={columns}\n data={data}\n columnPinning={columnPinning}\n onColumnPinningChange={setColumnPinning}\n >\n <DataTableContent />\n </DataTable>\n )\n}"
2627
+ },
2628
+ {
2629
+ "language": "tsx",
2630
+ "meta": null,
2631
+ "code": "import { DataTable, DataTableContent } from \"@epilot/volt-ui\"\n\n// Compact rows (smallest)\n<DataTable columns={columns} data={data} density=\"compact\">\n <DataTableContent />\n</DataTable>\n\n// Normal rows (default)\n<DataTable columns={columns} data={data} density=\"normal\">\n <DataTableContent />\n</DataTable>\n\n// Comfortable rows (largest)\n<DataTable columns={columns} data={data} density=\"comfortable\">\n <DataTableContent />\n</DataTable>"
2632
+ }
2633
+ ]
2634
+ },
2635
+ {
2636
+ "name": "DataTableVirtualizerContext",
2637
+ "title": null,
2638
+ "description": null,
2639
+ "docsPath": null,
2640
+ "docSlug": null,
2641
+ "documentationUrl": null,
2642
+ "apiReferenceUrl": null,
2643
+ "sourcePaths": [
2644
+ "src/components/data-table/data-table-context.tsx"
2645
+ ],
2646
+ "props": [],
2647
+ "examples": []
2648
+ },
2649
+ {
2650
+ "name": "DateRangePicker",
2651
+ "title": "Date Range Picker",
2652
+ "description": "A date range picker component with two side-by-side calendars for selecting a start and end date.",
2653
+ "docsPath": "docs/content/docs/components/date-range-picker.mdx",
2654
+ "docSlug": "date-range-picker",
2655
+ "documentationUrl": null,
2656
+ "apiReferenceUrl": null,
2657
+ "sourcePaths": [
2658
+ "src/components/date-range-picker/date-range-picker.tsx"
2659
+ ],
2660
+ "props": [
2661
+ {
2662
+ "name": "`value`",
2663
+ "type": "`DateRange`",
2664
+ "default": "-",
2665
+ "description": "The selected date range (`{ start: Date | null, end: Date | null }`)."
2666
+ },
2667
+ {
2668
+ "name": "`onChange`",
2669
+ "type": "`(range: DateRange) => void`",
2670
+ "default": "-",
2671
+ "description": "Callback fired when the date range changes."
2672
+ },
2673
+ {
2674
+ "name": "`onBlur`",
2675
+ "type": "`() => void`",
2676
+ "default": "-",
2677
+ "description": "Callback fired when an input loses focus."
2678
+ },
2679
+ {
2680
+ "name": "`disabled`",
2681
+ "type": "`boolean`",
2682
+ "default": "`false`",
2683
+ "description": "When true, the picker is disabled."
2684
+ },
2685
+ {
2686
+ "name": "`disablePast`",
2687
+ "type": "`boolean`",
2688
+ "default": "`false`",
2689
+ "description": "When true, past dates cannot be selected."
2690
+ },
2691
+ {
2692
+ "name": "`label`",
2693
+ "type": "`string`",
2694
+ "default": "-",
2695
+ "description": "Label text displayed above the input."
2696
+ },
2697
+ {
2698
+ "name": "`error`",
2699
+ "type": "`string`",
2700
+ "default": "-",
2701
+ "description": "Error message to display below the input."
2702
+ },
2703
+ {
2704
+ "name": "`startPlaceholder`",
2705
+ "type": "`string`",
2706
+ "default": "`\"dd/mm/yyyy\"`",
2707
+ "description": "Placeholder for the start date input."
2708
+ },
2709
+ {
2710
+ "name": "`endPlaceholder`",
2711
+ "type": "`string`",
2712
+ "default": "`\"dd/mm/yyyy\"`",
2713
+ "description": "Placeholder for the end date input."
2714
+ },
2715
+ {
2716
+ "name": "`format`",
2717
+ "type": "`string`",
2718
+ "default": "`\"dd/MM/yyyy\"`",
2719
+ "description": "Date format string (uses date-fns format tokens)."
2720
+ },
2721
+ {
2722
+ "name": "`locale`",
2723
+ "type": "`\"en\" | \"de\" | \"fr\"`",
2724
+ "default": "`\"de\"`",
2725
+ "description": "Locale for month/day names and formatting."
2726
+ },
2727
+ {
2728
+ "name": "`className`",
2729
+ "type": "`string`",
2730
+ "default": "-",
2731
+ "description": "Additional CSS classes for the container."
2732
+ },
2733
+ {
2734
+ "name": "`keyboardIcon`",
2735
+ "type": "`ReactNode`",
2736
+ "default": "`<CalendarIcon />`",
2737
+ "description": "Custom icon for the calendar button."
2738
+ },
2739
+ {
2740
+ "name": "`inputAriaLabel`",
2741
+ "type": "`string`",
2742
+ "default": "-",
2743
+ "description": "Aria-label for the start date input."
2744
+ },
2745
+ {
2746
+ "name": "`openPickerAriaLabel`",
2747
+ "type": "`string`",
2748
+ "default": "`\"Open date picker\"`",
2749
+ "description": "Aria-label for the calendar button."
2750
+ },
2751
+ {
2752
+ "name": "`previousMonthLabel`",
2753
+ "type": "`string`",
2754
+ "default": "`\"Previous month\"`",
2755
+ "description": "Aria-label for the previous month button."
2756
+ },
2757
+ {
2758
+ "name": "`nextMonthLabel`",
2759
+ "type": "`string`",
2760
+ "default": "`\"Next month\"`",
2761
+ "description": "Aria-label for the next month button."
2762
+ },
2763
+ {
2764
+ "name": "`testId`",
2765
+ "type": "`string`",
2766
+ "default": "-",
2767
+ "description": "Test ID prefix (creates `{testId}-start` and `{testId}-end`)."
2768
+ },
2769
+ {
2770
+ "name": "`currentTimeInTimezone`",
2771
+ "type": "`Date`",
2772
+ "default": "-",
2773
+ "description": "Override \"now\" for timezone-aware past checks."
2774
+ }
2775
+ ],
2776
+ "examples": [
2777
+ {
2778
+ "language": "tsx",
2779
+ "meta": "lineNumbers",
2780
+ "code": "import { useState } from \"react\"\nimport { DateRangePicker } from \"@epilot/volt-ui\"\nimport type { DateRange } from \"@epilot/volt-ui\"\n\nconst MyComponent = () => {\n const [value, setValue] = useState<DateRange>({\n start: new Date(),\n end: null,\n })\n\n return (\n <DateRangePicker\n label=\"Date Range\"\n value={value}\n onChange={setValue}\n locale=\"en\"\n />\n )\n}"
2781
+ },
2782
+ {
2783
+ "language": "tsx",
2784
+ "meta": "lineNumbers",
2785
+ "code": "<DateRangePicker\n label=\"Future Dates Only\"\n value={value}\n onChange={setValue}\n disablePast\n/>"
2786
+ },
2787
+ {
2788
+ "language": "tsx",
2789
+ "meta": "lineNumbers",
2790
+ "code": "<DateRangePicker\n label=\"Date Range\"\n value={value}\n onChange={setValue}\n error=\"Please select a valid date range\"\n/>"
2791
+ }
2792
+ ]
2793
+ },
2794
+ {
2795
+ "name": "DateTimePicker",
2796
+ "title": "Date Time Picker",
2797
+ "description": "A date and time picker component with calendar and time selection.",
2798
+ "docsPath": "docs/content/docs/components/date-time-picker.mdx",
2799
+ "docSlug": "date-time-picker",
2800
+ "documentationUrl": null,
2801
+ "apiReferenceUrl": null,
2802
+ "sourcePaths": [
2803
+ "src/components/date-time-picker/date-time-picker.tsx"
2804
+ ],
2805
+ "props": [
2806
+ {
2807
+ "name": "`value`",
2808
+ "type": "`Date`",
2809
+ "default": "-",
2810
+ "description": "The selected date and time value."
2811
+ },
2812
+ {
2813
+ "name": "`onChange`",
2814
+ "type": "`(date: Date) => void`",
2815
+ "default": "-",
2816
+ "description": "Callback fired when the date/time changes."
2817
+ },
2818
+ {
2819
+ "name": "`onBlur`",
2820
+ "type": "`() => void`",
2821
+ "default": "-",
2822
+ "description": "Callback fired when the input loses focus."
2823
+ },
2824
+ {
2825
+ "name": "`disabled`",
2826
+ "type": "`boolean`",
2827
+ "default": "`false`",
2828
+ "description": "When true, the picker is disabled."
2829
+ },
2830
+ {
2831
+ "name": "`disablePast`",
2832
+ "type": "`boolean`",
2833
+ "default": "`false`",
2834
+ "description": "When true, past dates and times cannot be selected."
2835
+ },
2836
+ {
2837
+ "name": "`label`",
2838
+ "type": "`string`",
2839
+ "default": "-",
2840
+ "description": "Label text displayed above the input."
2841
+ },
2842
+ {
2843
+ "name": "`error`",
2844
+ "type": "`string`",
2845
+ "default": "-",
2846
+ "description": "Error message to display below the input."
2847
+ },
2848
+ {
2849
+ "name": "`placeholder`",
2850
+ "type": "`string`",
2851
+ "default": "`\"dd/mm/yyyy hh:mm\"`",
2852
+ "description": "Placeholder text for the input."
2853
+ },
2854
+ {
2855
+ "name": "`format`",
2856
+ "type": "`string`",
2857
+ "default": "`\"dd/MM/yyyy HH:mm\"`",
2858
+ "description": "Date format string (uses date-fns format tokens)."
2859
+ },
2860
+ {
2861
+ "name": "`locale`",
2862
+ "type": "`\"en\" | \"de\" | \"fr\"`",
2863
+ "default": "`\"de\"`",
2864
+ "description": "Locale for month/day names and formatting."
2865
+ },
2866
+ {
2867
+ "name": "`className`",
2868
+ "type": "`string`",
2869
+ "default": "-",
2870
+ "description": "Additional CSS classes for the container."
2871
+ },
2872
+ {
2873
+ "name": "`keyboardIcon`",
2874
+ "type": "`ReactNode`",
2875
+ "default": "`<CalendarIcon />`",
2876
+ "description": "Custom icon for the calendar button."
2877
+ },
2878
+ {
2879
+ "name": "`okLabel`",
2880
+ "type": "`string`",
2881
+ "default": "`\"OK\"`",
2882
+ "description": "Label for the OK button."
2883
+ },
2884
+ {
2885
+ "name": "`cancelLabel`",
2886
+ "type": "`string`",
2887
+ "default": "`\"Cancel\"`",
2888
+ "description": "Label for the Cancel button."
2889
+ },
2890
+ {
2891
+ "name": "`inputAriaLabel`",
2892
+ "type": "`string`",
2893
+ "default": "`\"change date and time\"`",
2894
+ "description": "Aria-label for the input field."
2895
+ },
2896
+ {
2897
+ "name": "`openPickerAriaLabel`",
2898
+ "type": "`string`",
2899
+ "default": "`\"Open date picker\"`",
2900
+ "description": "Aria-label for the calendar button."
2901
+ },
2902
+ {
2903
+ "name": "`previousMonthLabel`",
2904
+ "type": "`string`",
2905
+ "default": "`\"Previous month\"`",
2906
+ "description": "Aria-label for the previous month button."
2907
+ },
2908
+ {
2909
+ "name": "`nextMonthLabel`",
2910
+ "type": "`string`",
2911
+ "default": "`\"Next month\"`",
2912
+ "description": "Aria-label for the next month button."
2913
+ },
2914
+ {
2915
+ "name": "`hoursLabel`",
2916
+ "type": "`string`",
2917
+ "default": "`\"HH\"`",
2918
+ "description": "Label for the hours column."
2919
+ },
2920
+ {
2921
+ "name": "`minutesLabel`",
2922
+ "type": "`string`",
2923
+ "default": "`\"MM\"`",
2924
+ "description": "Label for the minutes column."
2925
+ },
2926
+ {
2927
+ "name": "`showTodayButton`",
2928
+ "type": "`boolean`",
2929
+ "default": "`false`",
2930
+ "description": "When true, shows a \"Today\" button below the calendar."
2931
+ },
2932
+ {
2933
+ "name": "`todayLabel`",
2934
+ "type": "`string`",
2935
+ "default": "`\"Today\"`",
2936
+ "description": "Label for the Today button."
2937
+ },
2938
+ {
2939
+ "name": "`testId`",
2940
+ "type": "`string`",
2941
+ "default": "-",
2942
+ "description": "Test ID for the input (sets `data-testid`)."
2943
+ },
2944
+ {
2945
+ "name": "`currentTimeInTimezone`",
2946
+ "type": "`Date`",
2947
+ "default": "-",
2948
+ "description": "Override \"now\" for timezone-aware past checks."
2949
+ },
2950
+ {
2951
+ "name": "`timePickerPosition`",
2952
+ "type": "`\"bottom\" | \"side\"`",
2953
+ "default": "`\"bottom\"`",
2954
+ "description": "Position the time picker below or beside the calendar."
2955
+ }
2956
+ ],
2957
+ "examples": [
2958
+ {
2959
+ "language": "tsx",
2960
+ "meta": "lineNumbers",
2961
+ "code": "import { useState } from \"react\"\nimport { DateTimePicker } from \"@epilot/volt-ui\"\n\nconst MyComponent = () => {\n const [value, setValue] = useState<Date>(new Date())\n\n return (\n <DateTimePicker\n label=\"Appointment\"\n value={value}\n onChange={setValue}\n locale=\"en\"\n />\n )\n}"
2962
+ },
2963
+ {
2964
+ "language": "tsx",
2965
+ "meta": "lineNumbers",
2966
+ "code": "<DateTimePicker\n label=\"Future Date Only\"\n value={value}\n onChange={setValue}\n disablePast\n/>"
2967
+ },
2968
+ {
2969
+ "language": "tsx",
2970
+ "meta": "lineNumbers",
2971
+ "code": "<DateTimePicker\n label=\"Date & Time\"\n value={value}\n onChange={setValue}\n error=\"Please select a valid date\"\n/>"
2972
+ },
2973
+ {
2974
+ "language": "tsx",
2975
+ "meta": "lineNumbers",
2976
+ "code": "<DateTimePicker\n label=\"Termin\"\n value={value}\n onChange={setValue}\n locale=\"de\"\n format=\"dd.MM.yyyy HH:mm\"\n placeholder=\"tt.mm.jjjj hh:mm\"\n/>"
2977
+ },
2978
+ {
2979
+ "language": "tsx",
2980
+ "meta": "lineNumbers",
2981
+ "code": "<DateTimePicker\n label=\"Select Date\"\n value={value}\n onChange={setValue}\n showTodayButton\n todayLabel=\"Today\"\n/>"
2982
+ },
2983
+ {
2984
+ "language": "tsx",
2985
+ "meta": "lineNumbers",
2986
+ "code": "<DateTimePicker\n label=\"Side Layout\"\n value={value}\n onChange={setValue}\n timePickerPosition=\"side\"\n/>"
2987
+ },
2988
+ {
2989
+ "language": "tsx",
2990
+ "meta": "lineNumbers",
2991
+ "code": "<DateTimePicker\n label=\"Side Layout + Today\"\n value={value}\n onChange={setValue}\n timePickerPosition=\"side\"\n showTodayButton\n todayLabel=\"Today\"\n/>"
2992
+ }
2993
+ ]
2994
+ },
2995
+ {
2996
+ "name": "Dialog",
2997
+ "title": "Dialog",
2998
+ "description": "A Dialog is a modal surface that appears above the main interface to capture the user’s attention",
2999
+ "docsPath": "docs/content/docs/components/dialog.mdx",
3000
+ "docSlug": "dialog",
3001
+ "documentationUrl": "https://www.radix-ui.com/docs/primitives/components/dialog",
3002
+ "apiReferenceUrl": "https://www.radix-ui.com/docs/primitives/components/dialog#api-reference",
3003
+ "sourcePaths": [
3004
+ "src/components/dialog/dialog.tsx"
3005
+ ],
3006
+ "props": [
3007
+ {
3008
+ "name": "`open`",
3009
+ "type": "boolean",
3010
+ "default": "-",
3011
+ "description": "Controlled open state of the dialog."
3012
+ },
3013
+ {
3014
+ "name": "`defaultOpen`",
3015
+ "type": "boolean",
3016
+ "default": "`false`",
3017
+ "description": "Uncontrolled default open state."
3018
+ },
3019
+ {
3020
+ "name": "`onOpenChange`",
3021
+ "type": "(open: boolean) => void",
3022
+ "default": "-",
3023
+ "description": "Callback fired when the open state changes."
3024
+ },
3025
+ {
3026
+ "name": "`modal`",
3027
+ "type": "boolean",
3028
+ "default": "`true`",
3029
+ "description": "When true, focus is trapped within the dialog and outside interaction is disabled."
3030
+ }
3031
+ ],
3032
+ "examples": [
3033
+ {
3034
+ "language": "tsx",
3035
+ "meta": "lineNumbers",
3036
+ "code": "import { Dialog, DialogTrigger, DialogContent, DialogPortal, DialogFooter, DialogClose, Button, DialogHeader, DialogTitle, DialogDescription } from \"@epilot/volt-ui\"\n\n<div className=\"flex flex-col gap-4\">\n <Dialog>\n <DialogTrigger asChild>\n <Button variant=\"outline\">Open</Button>\n </DialogTrigger>\n <DialogPortal container={document.getElementById(\"root\")}>\n <DialogOverlay />\n <DialogContent size=\"2xl\">\n <DialogHeader>\n <DialogTitle>Edit profile</DialogTitle>\n <DialogDescription>\n Make changes to your profile here. Click save when you&apos;re\n done.\n </DialogDescription>\n </DialogHeader>\n <form className=\"flex flex-col gap-4 w-full\">\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Full Name</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"text\" placeholder=\"John Doe\" />\n </div>\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Email</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"email\" placeholder=\"john.doe@example.com\" />\n </div>\n </form>\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"secondary\">Cancel</Button>\n </DialogClose>\n <Button type=\"submit\">Save changes</Button>\n </DialogFooter>\n </DialogContent>\n </DialogPortal>\n </Dialog>\n</div>"
3037
+ }
3038
+ ]
3039
+ },
3040
+ {
3041
+ "name": "DialogClose",
3042
+ "title": null,
3043
+ "description": null,
3044
+ "docsPath": null,
3045
+ "docSlug": null,
3046
+ "documentationUrl": null,
3047
+ "apiReferenceUrl": null,
3048
+ "sourcePaths": [
3049
+ "src/components/dialog/dialog.tsx"
3050
+ ],
3051
+ "props": [],
3052
+ "examples": []
3053
+ },
3054
+ {
3055
+ "name": "DialogContent",
3056
+ "title": null,
3057
+ "description": null,
3058
+ "docsPath": null,
3059
+ "docSlug": null,
3060
+ "documentationUrl": null,
3061
+ "apiReferenceUrl": null,
3062
+ "sourcePaths": [
3063
+ "src/components/dialog/dialog.tsx"
3064
+ ],
3065
+ "props": [],
3066
+ "examples": []
3067
+ },
3068
+ {
3069
+ "name": "DialogDescription",
3070
+ "title": null,
3071
+ "description": null,
3072
+ "docsPath": null,
3073
+ "docSlug": null,
3074
+ "documentationUrl": null,
3075
+ "apiReferenceUrl": null,
3076
+ "sourcePaths": [
3077
+ "src/components/dialog/dialog.tsx"
3078
+ ],
3079
+ "props": [],
3080
+ "examples": []
3081
+ },
3082
+ {
3083
+ "name": "DialogFooter",
3084
+ "title": null,
3085
+ "description": null,
3086
+ "docsPath": null,
3087
+ "docSlug": null,
3088
+ "documentationUrl": null,
3089
+ "apiReferenceUrl": null,
3090
+ "sourcePaths": [
3091
+ "src/components/dialog/dialog.tsx"
3092
+ ],
3093
+ "props": [],
3094
+ "examples": []
3095
+ },
3096
+ {
3097
+ "name": "DialogHeader",
3098
+ "title": null,
3099
+ "description": null,
3100
+ "docsPath": null,
3101
+ "docSlug": null,
3102
+ "documentationUrl": null,
3103
+ "apiReferenceUrl": null,
3104
+ "sourcePaths": [
3105
+ "src/components/dialog/dialog.tsx"
3106
+ ],
3107
+ "props": [],
3108
+ "examples": []
3109
+ },
3110
+ {
3111
+ "name": "DialogOverlay",
3112
+ "title": "Dialog",
3113
+ "description": "A Dialog is a modal surface that appears above the main interface to capture the user’s attention",
3114
+ "docsPath": "docs/content/docs/components/dialog.mdx",
3115
+ "docSlug": "dialog",
3116
+ "documentationUrl": "https://www.radix-ui.com/docs/primitives/components/dialog",
3117
+ "apiReferenceUrl": "https://www.radix-ui.com/docs/primitives/components/dialog#api-reference",
3118
+ "sourcePaths": [
3119
+ "src/components/dialog/dialog.tsx"
3120
+ ],
3121
+ "props": [
3122
+ {
3123
+ "name": "`className`",
3124
+ "type": "string",
3125
+ "default": "-",
3126
+ "description": "Additional CSS classes to apply to the overlay."
3127
+ }
3128
+ ],
3129
+ "examples": [
3130
+ {
3131
+ "language": "tsx",
3132
+ "meta": "lineNumbers",
3133
+ "code": "import { Dialog, DialogTrigger, DialogContent, DialogPortal, DialogFooter, DialogClose, Button, DialogHeader, DialogTitle, DialogDescription } from \"@epilot/volt-ui\"\n\n<div className=\"flex flex-col gap-4\">\n <Dialog>\n <DialogTrigger asChild>\n <Button variant=\"outline\">Open</Button>\n </DialogTrigger>\n <DialogPortal container={document.getElementById(\"root\")}>\n <DialogOverlay />\n <DialogContent size=\"2xl\">\n <DialogHeader>\n <DialogTitle>Edit profile</DialogTitle>\n <DialogDescription>\n Make changes to your profile here. Click save when you&apos;re\n done.\n </DialogDescription>\n </DialogHeader>\n <form className=\"flex flex-col gap-4 w-full\">\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Full Name</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"text\" placeholder=\"John Doe\" />\n </div>\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Email</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"email\" placeholder=\"john.doe@example.com\" />\n </div>\n </form>\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"secondary\">Cancel</Button>\n </DialogClose>\n <Button type=\"submit\">Save changes</Button>\n </DialogFooter>\n </DialogContent>\n </DialogPortal>\n </Dialog>\n</div>"
3134
+ }
3135
+ ]
3136
+ },
3137
+ {
3138
+ "name": "DialogPortal",
3139
+ "title": "Dialog",
3140
+ "description": "A Dialog is a modal surface that appears above the main interface to capture the user’s attention",
3141
+ "docsPath": "docs/content/docs/components/dialog.mdx",
3142
+ "docSlug": "dialog",
3143
+ "documentationUrl": "https://www.radix-ui.com/docs/primitives/components/dialog",
3144
+ "apiReferenceUrl": "https://www.radix-ui.com/docs/primitives/components/dialog#api-reference",
3145
+ "sourcePaths": [
3146
+ "src/components/dialog/dialog.tsx"
3147
+ ],
3148
+ "props": [
3149
+ {
3150
+ "name": "`container`",
3151
+ "type": "Element / DocumentFragment",
3152
+ "default": "-",
3153
+ "description": "The container to render the portal in. Recommended to use your MFE root element (e.g., `document.getElementById(\"epilot360-entity\")`) instead of `document.body` to avoid conflicts."
3154
+ },
3155
+ {
3156
+ "name": "`forceMount`",
3157
+ "type": "boolean",
3158
+ "default": "`false`",
3159
+ "description": "When true, the dialog content is always mounted."
3160
+ }
3161
+ ],
3162
+ "examples": [
3163
+ {
3164
+ "language": "tsx",
3165
+ "meta": "lineNumbers",
3166
+ "code": "import { Dialog, DialogTrigger, DialogContent, DialogPortal, DialogFooter, DialogClose, Button, DialogHeader, DialogTitle, DialogDescription } from \"@epilot/volt-ui\"\n\n<div className=\"flex flex-col gap-4\">\n <Dialog>\n <DialogTrigger asChild>\n <Button variant=\"outline\">Open</Button>\n </DialogTrigger>\n <DialogPortal container={document.getElementById(\"root\")}>\n <DialogOverlay />\n <DialogContent size=\"2xl\">\n <DialogHeader>\n <DialogTitle>Edit profile</DialogTitle>\n <DialogDescription>\n Make changes to your profile here. Click save when you&apos;re\n done.\n </DialogDescription>\n </DialogHeader>\n <form className=\"flex flex-col gap-4 w-full\">\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Full Name</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"text\" placeholder=\"John Doe\" />\n </div>\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Email</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"email\" placeholder=\"john.doe@example.com\" />\n </div>\n </form>\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"secondary\">Cancel</Button>\n </DialogClose>\n <Button type=\"submit\">Save changes</Button>\n </DialogFooter>\n </DialogContent>\n </DialogPortal>\n </Dialog>\n</div>"
3167
+ }
3168
+ ]
3169
+ },
3170
+ {
3171
+ "name": "DialogTitle",
3172
+ "title": null,
3173
+ "description": null,
3174
+ "docsPath": null,
3175
+ "docSlug": null,
3176
+ "documentationUrl": null,
3177
+ "apiReferenceUrl": null,
3178
+ "sourcePaths": [
3179
+ "src/components/dialog/dialog.tsx"
3180
+ ],
3181
+ "props": [],
3182
+ "examples": []
3183
+ },
3184
+ {
3185
+ "name": "DialogTrigger",
3186
+ "title": "Dialog",
3187
+ "description": "A Dialog is a modal surface that appears above the main interface to capture the user’s attention",
3188
+ "docsPath": "docs/content/docs/components/dialog.mdx",
3189
+ "docSlug": "dialog",
3190
+ "documentationUrl": "https://www.radix-ui.com/docs/primitives/components/dialog",
3191
+ "apiReferenceUrl": "https://www.radix-ui.com/docs/primitives/components/dialog#api-reference",
3192
+ "sourcePaths": [
3193
+ "src/components/dialog/dialog.tsx"
3194
+ ],
3195
+ "props": [
3196
+ {
3197
+ "name": "`asChild`",
3198
+ "type": "boolean",
3199
+ "default": "`false`",
3200
+ "description": "When true, merges props with the child element instead of rendering a button."
3201
+ }
3202
+ ],
3203
+ "examples": [
3204
+ {
3205
+ "language": "tsx",
3206
+ "meta": "lineNumbers",
3207
+ "code": "import { Dialog, DialogTrigger, DialogContent, DialogPortal, DialogFooter, DialogClose, Button, DialogHeader, DialogTitle, DialogDescription } from \"@epilot/volt-ui\"\n\n<div className=\"flex flex-col gap-4\">\n <Dialog>\n <DialogTrigger asChild>\n <Button variant=\"outline\">Open</Button>\n </DialogTrigger>\n <DialogPortal container={document.getElementById(\"root\")}>\n <DialogOverlay />\n <DialogContent size=\"2xl\">\n <DialogHeader>\n <DialogTitle>Edit profile</DialogTitle>\n <DialogDescription>\n Make changes to your profile here. Click save when you&apos;re\n done.\n </DialogDescription>\n </DialogHeader>\n <form className=\"flex flex-col gap-4 w-full\">\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Full Name</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"text\" placeholder=\"John Doe\" />\n </div>\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Email</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"email\" placeholder=\"john.doe@example.com\" />\n </div>\n </form>\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"secondary\">Cancel</Button>\n </DialogClose>\n <Button type=\"submit\">Save changes</Button>\n </DialogFooter>\n </DialogContent>\n </DialogPortal>\n </Dialog>\n</div>"
3208
+ }
3209
+ ]
3210
+ },
3211
+ {
3212
+ "name": "Drawer",
3213
+ "title": "Drawer",
3214
+ "description": "A side panel that slides in from the edge of the screen, used for navigation, detail views, or supplementary content",
3215
+ "docsPath": "docs/content/docs/components/drawer.mdx",
3216
+ "docSlug": "drawer",
3217
+ "documentationUrl": "https://www.radix-ui.com/docs/primitives/components/dialog",
3218
+ "apiReferenceUrl": "https://www.radix-ui.com/docs/primitives/components/dialog#api-reference",
3219
+ "sourcePaths": [
3220
+ "src/components/drawer/drawer.tsx"
3221
+ ],
3222
+ "props": [
3223
+ {
3224
+ "name": "`open`",
3225
+ "type": "boolean",
3226
+ "default": "-",
3227
+ "description": "Controlled open state of the drawer."
3228
+ },
3229
+ {
3230
+ "name": "`defaultOpen`",
3231
+ "type": "boolean",
3232
+ "default": "`false`",
3233
+ "description": "Uncontrolled default open state."
3234
+ },
3235
+ {
3236
+ "name": "`onOpenChange`",
3237
+ "type": "(open: boolean) => void",
3238
+ "default": "-",
3239
+ "description": "Callback fired when the open state changes."
3240
+ },
3241
+ {
3242
+ "name": "`modal`",
3243
+ "type": "boolean",
3244
+ "default": "`true`",
3245
+ "description": "When true, focus is trapped within the drawer and outside interaction is disabled."
3246
+ }
3247
+ ],
3248
+ "examples": [
3249
+ {
3250
+ "language": "tsx",
3251
+ "meta": "lineNumbers",
3252
+ "code": "import { Drawer, DrawerTrigger, DrawerContent, DrawerPortal, DrawerOverlay, DrawerFooter, DrawerClose, DrawerHeader, DrawerTitle, DrawerDescription, Button } from \"@epilot/volt-ui\"\n\n<Drawer>\n <DrawerTrigger asChild>\n <Button variant=\"primary\">Open Drawer</Button>\n </DrawerTrigger>\n <DrawerPortal container={document.getElementById(\"root\")}>\n <DrawerOverlay />\n <DrawerContent className=\"w-96\">\n <DrawerHeader>\n <DrawerTitle>Details</DrawerTitle>\n <DrawerDescription>\n View and edit the details below.\n </DrawerDescription>\n </DrawerHeader>\n <div className=\"flex flex-col gap-4 flex-1 overflow-auto\">\n <p>Drawer content goes here.</p>\n </div>\n <DrawerFooter>\n <DrawerClose asChild>\n <Button variant=\"secondary\">Close</Button>\n </DrawerClose>\n <Button>Save</Button>\n </DrawerFooter>\n </DrawerContent>\n </DrawerPortal>\n</Drawer>"
3253
+ },
2073
3254
  {
2074
3255
  "language": "tsx",
2075
3256
  "meta": "lineNumbers",
2076
- "code": "import { Dialog, DialogTrigger, DialogContent, DialogPortal, DialogFooter, DialogClose, Button, DialogHeader, DialogTitle, DialogDescription } from \"@epilot/volt-ui\"\n\n<div className=\"flex flex-col gap-4\">\n <Dialog>\n <DialogTrigger asChild>\n <Button variant=\"outline\">Open</Button>\n </DialogTrigger>\n <DialogPortal container={document.getElementById(\"root\")}>\n <DialogOverlay />\n <DialogContent size=\"2xl\">\n <DialogHeader>\n <DialogTitle>Edit profile</DialogTitle>\n <DialogDescription>\n Make changes to your profile here. Click save when you&apos;re\n done.\n </DialogDescription>\n </DialogHeader>\n <form className=\"flex flex-col gap-4 w-full\">\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Full Name</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"text\" placeholder=\"John Doe\" />\n </div>\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Email</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"email\" placeholder=\"john.doe@example.com\" />\n </div>\n </form>\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"secondary\">Cancel</Button>\n </DialogClose>\n <Button type=\"submit\">Save changes</Button>\n </DialogFooter>\n </DialogContent>\n </DialogPortal>\n </Dialog>\n</div>"
3257
+ "code": "<Drawer>\n <DrawerTrigger asChild>\n <Button>Open Left</Button>\n </DrawerTrigger>\n <DrawerPortal container={document.getElementById(\"root\")}>\n <DrawerOverlay />\n <DrawerContent side=\"left\" className=\"w-80\">\n <DrawerHeader>\n <DrawerTitle>Left Drawer</DrawerTitle>\n </DrawerHeader>\n <p>This drawer slides in from the left.</p>\n </DrawerContent>\n </DrawerPortal>\n</Drawer>"
2077
3258
  }
2078
3259
  ]
2079
3260
  },
2080
3261
  {
2081
- "name": "DialogClose",
3262
+ "name": "DrawerClose",
2082
3263
  "title": null,
2083
3264
  "description": null,
2084
3265
  "docsPath": null,
@@ -2086,13 +3267,13 @@
2086
3267
  "documentationUrl": null,
2087
3268
  "apiReferenceUrl": null,
2088
3269
  "sourcePaths": [
2089
- "src/components/dialog/dialog.tsx"
3270
+ "src/components/drawer/drawer.tsx"
2090
3271
  ],
2091
3272
  "props": [],
2092
3273
  "examples": []
2093
3274
  },
2094
3275
  {
2095
- "name": "DialogContent",
3276
+ "name": "DrawerContent",
2096
3277
  "title": null,
2097
3278
  "description": null,
2098
3279
  "docsPath": null,
@@ -2100,13 +3281,13 @@
2100
3281
  "documentationUrl": null,
2101
3282
  "apiReferenceUrl": null,
2102
3283
  "sourcePaths": [
2103
- "src/components/dialog/dialog.tsx"
3284
+ "src/components/drawer/drawer.tsx"
2104
3285
  ],
2105
3286
  "props": [],
2106
3287
  "examples": []
2107
3288
  },
2108
3289
  {
2109
- "name": "DialogDescription",
3290
+ "name": "DrawerDescription",
2110
3291
  "title": null,
2111
3292
  "description": null,
2112
3293
  "docsPath": null,
@@ -2114,13 +3295,13 @@
2114
3295
  "documentationUrl": null,
2115
3296
  "apiReferenceUrl": null,
2116
3297
  "sourcePaths": [
2117
- "src/components/dialog/dialog.tsx"
3298
+ "src/components/drawer/drawer.tsx"
2118
3299
  ],
2119
3300
  "props": [],
2120
3301
  "examples": []
2121
3302
  },
2122
3303
  {
2123
- "name": "DialogFooter",
3304
+ "name": "DrawerFooter",
2124
3305
  "title": null,
2125
3306
  "description": null,
2126
3307
  "docsPath": null,
@@ -2128,13 +3309,13 @@
2128
3309
  "documentationUrl": null,
2129
3310
  "apiReferenceUrl": null,
2130
3311
  "sourcePaths": [
2131
- "src/components/dialog/dialog.tsx"
3312
+ "src/components/drawer/drawer.tsx"
2132
3313
  ],
2133
3314
  "props": [],
2134
3315
  "examples": []
2135
3316
  },
2136
3317
  {
2137
- "name": "DialogHeader",
3318
+ "name": "DrawerHeader",
2138
3319
  "title": null,
2139
3320
  "description": null,
2140
3321
  "docsPath": null,
@@ -2142,21 +3323,21 @@
2142
3323
  "documentationUrl": null,
2143
3324
  "apiReferenceUrl": null,
2144
3325
  "sourcePaths": [
2145
- "src/components/dialog/dialog.tsx"
3326
+ "src/components/drawer/drawer.tsx"
2146
3327
  ],
2147
3328
  "props": [],
2148
3329
  "examples": []
2149
3330
  },
2150
3331
  {
2151
- "name": "DialogOverlay",
2152
- "title": "Dialog",
2153
- "description": "A Dialog is a modal surface that appears above the main interface to capture the user’s attention",
2154
- "docsPath": "docs/content/docs/components/dialog.mdx",
2155
- "docSlug": "dialog",
3332
+ "name": "DrawerOverlay",
3333
+ "title": "Drawer",
3334
+ "description": "A side panel that slides in from the edge of the screen, used for navigation, detail views, or supplementary content",
3335
+ "docsPath": "docs/content/docs/components/drawer.mdx",
3336
+ "docSlug": "drawer",
2156
3337
  "documentationUrl": "https://www.radix-ui.com/docs/primitives/components/dialog",
2157
3338
  "apiReferenceUrl": "https://www.radix-ui.com/docs/primitives/components/dialog#api-reference",
2158
3339
  "sourcePaths": [
2159
- "src/components/dialog/dialog.tsx"
3340
+ "src/components/drawer/drawer.tsx"
2160
3341
  ],
2161
3342
  "props": [
2162
3343
  {
@@ -2170,20 +3351,25 @@
2170
3351
  {
2171
3352
  "language": "tsx",
2172
3353
  "meta": "lineNumbers",
2173
- "code": "import { Dialog, DialogTrigger, DialogContent, DialogPortal, DialogFooter, DialogClose, Button, DialogHeader, DialogTitle, DialogDescription } from \"@epilot/volt-ui\"\n\n<div className=\"flex flex-col gap-4\">\n <Dialog>\n <DialogTrigger asChild>\n <Button variant=\"outline\">Open</Button>\n </DialogTrigger>\n <DialogPortal container={document.getElementById(\"root\")}>\n <DialogOverlay />\n <DialogContent size=\"2xl\">\n <DialogHeader>\n <DialogTitle>Edit profile</DialogTitle>\n <DialogDescription>\n Make changes to your profile here. Click save when you&apos;re\n done.\n </DialogDescription>\n </DialogHeader>\n <form className=\"flex flex-col gap-4 w-full\">\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Full Name</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"text\" placeholder=\"John Doe\" />\n </div>\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Email</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"email\" placeholder=\"john.doe@example.com\" />\n </div>\n </form>\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"secondary\">Cancel</Button>\n </DialogClose>\n <Button type=\"submit\">Save changes</Button>\n </DialogFooter>\n </DialogContent>\n </DialogPortal>\n </Dialog>\n</div>"
3354
+ "code": "import { Drawer, DrawerTrigger, DrawerContent, DrawerPortal, DrawerOverlay, DrawerFooter, DrawerClose, DrawerHeader, DrawerTitle, DrawerDescription, Button } from \"@epilot/volt-ui\"\n\n<Drawer>\n <DrawerTrigger asChild>\n <Button variant=\"primary\">Open Drawer</Button>\n </DrawerTrigger>\n <DrawerPortal container={document.getElementById(\"root\")}>\n <DrawerOverlay />\n <DrawerContent className=\"w-96\">\n <DrawerHeader>\n <DrawerTitle>Details</DrawerTitle>\n <DrawerDescription>\n View and edit the details below.\n </DrawerDescription>\n </DrawerHeader>\n <div className=\"flex flex-col gap-4 flex-1 overflow-auto\">\n <p>Drawer content goes here.</p>\n </div>\n <DrawerFooter>\n <DrawerClose asChild>\n <Button variant=\"secondary\">Close</Button>\n </DrawerClose>\n <Button>Save</Button>\n </DrawerFooter>\n </DrawerContent>\n </DrawerPortal>\n</Drawer>"
3355
+ },
3356
+ {
3357
+ "language": "tsx",
3358
+ "meta": "lineNumbers",
3359
+ "code": "<Drawer>\n <DrawerTrigger asChild>\n <Button>Open Left</Button>\n </DrawerTrigger>\n <DrawerPortal container={document.getElementById(\"root\")}>\n <DrawerOverlay />\n <DrawerContent side=\"left\" className=\"w-80\">\n <DrawerHeader>\n <DrawerTitle>Left Drawer</DrawerTitle>\n </DrawerHeader>\n <p>This drawer slides in from the left.</p>\n </DrawerContent>\n </DrawerPortal>\n</Drawer>"
2174
3360
  }
2175
3361
  ]
2176
3362
  },
2177
3363
  {
2178
- "name": "DialogPortal",
2179
- "title": "Dialog",
2180
- "description": "A Dialog is a modal surface that appears above the main interface to capture the user’s attention",
2181
- "docsPath": "docs/content/docs/components/dialog.mdx",
2182
- "docSlug": "dialog",
3364
+ "name": "DrawerPortal",
3365
+ "title": "Drawer",
3366
+ "description": "A side panel that slides in from the edge of the screen, used for navigation, detail views, or supplementary content",
3367
+ "docsPath": "docs/content/docs/components/drawer.mdx",
3368
+ "docSlug": "drawer",
2183
3369
  "documentationUrl": "https://www.radix-ui.com/docs/primitives/components/dialog",
2184
3370
  "apiReferenceUrl": "https://www.radix-ui.com/docs/primitives/components/dialog#api-reference",
2185
3371
  "sourcePaths": [
2186
- "src/components/dialog/dialog.tsx"
3372
+ "src/components/drawer/drawer.tsx"
2187
3373
  ],
2188
3374
  "props": [
2189
3375
  {
@@ -2196,19 +3382,24 @@
2196
3382
  "name": "`forceMount`",
2197
3383
  "type": "boolean",
2198
3384
  "default": "`false`",
2199
- "description": "When true, the dialog content is always mounted."
3385
+ "description": "When true, the drawer content is always mounted."
2200
3386
  }
2201
3387
  ],
2202
3388
  "examples": [
2203
3389
  {
2204
3390
  "language": "tsx",
2205
3391
  "meta": "lineNumbers",
2206
- "code": "import { Dialog, DialogTrigger, DialogContent, DialogPortal, DialogFooter, DialogClose, Button, DialogHeader, DialogTitle, DialogDescription } from \"@epilot/volt-ui\"\n\n<div className=\"flex flex-col gap-4\">\n <Dialog>\n <DialogTrigger asChild>\n <Button variant=\"outline\">Open</Button>\n </DialogTrigger>\n <DialogPortal container={document.getElementById(\"root\")}>\n <DialogOverlay />\n <DialogContent size=\"2xl\">\n <DialogHeader>\n <DialogTitle>Edit profile</DialogTitle>\n <DialogDescription>\n Make changes to your profile here. Click save when you&apos;re\n done.\n </DialogDescription>\n </DialogHeader>\n <form className=\"flex flex-col gap-4 w-full\">\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Full Name</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"text\" placeholder=\"John Doe\" />\n </div>\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Email</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"email\" placeholder=\"john.doe@example.com\" />\n </div>\n </form>\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"secondary\">Cancel</Button>\n </DialogClose>\n <Button type=\"submit\">Save changes</Button>\n </DialogFooter>\n </DialogContent>\n </DialogPortal>\n </Dialog>\n</div>"
3392
+ "code": "import { Drawer, DrawerTrigger, DrawerContent, DrawerPortal, DrawerOverlay, DrawerFooter, DrawerClose, DrawerHeader, DrawerTitle, DrawerDescription, Button } from \"@epilot/volt-ui\"\n\n<Drawer>\n <DrawerTrigger asChild>\n <Button variant=\"primary\">Open Drawer</Button>\n </DrawerTrigger>\n <DrawerPortal container={document.getElementById(\"root\")}>\n <DrawerOverlay />\n <DrawerContent className=\"w-96\">\n <DrawerHeader>\n <DrawerTitle>Details</DrawerTitle>\n <DrawerDescription>\n View and edit the details below.\n </DrawerDescription>\n </DrawerHeader>\n <div className=\"flex flex-col gap-4 flex-1 overflow-auto\">\n <p>Drawer content goes here.</p>\n </div>\n <DrawerFooter>\n <DrawerClose asChild>\n <Button variant=\"secondary\">Close</Button>\n </DrawerClose>\n <Button>Save</Button>\n </DrawerFooter>\n </DrawerContent>\n </DrawerPortal>\n</Drawer>"
3393
+ },
3394
+ {
3395
+ "language": "tsx",
3396
+ "meta": "lineNumbers",
3397
+ "code": "<Drawer>\n <DrawerTrigger asChild>\n <Button>Open Left</Button>\n </DrawerTrigger>\n <DrawerPortal container={document.getElementById(\"root\")}>\n <DrawerOverlay />\n <DrawerContent side=\"left\" className=\"w-80\">\n <DrawerHeader>\n <DrawerTitle>Left Drawer</DrawerTitle>\n </DrawerHeader>\n <p>This drawer slides in from the left.</p>\n </DrawerContent>\n </DrawerPortal>\n</Drawer>"
2207
3398
  }
2208
3399
  ]
2209
3400
  },
2210
3401
  {
2211
- "name": "DialogTitle",
3402
+ "name": "DrawerTitle",
2212
3403
  "title": null,
2213
3404
  "description": null,
2214
3405
  "docsPath": null,
@@ -2216,21 +3407,21 @@
2216
3407
  "documentationUrl": null,
2217
3408
  "apiReferenceUrl": null,
2218
3409
  "sourcePaths": [
2219
- "src/components/dialog/dialog.tsx"
3410
+ "src/components/drawer/drawer.tsx"
2220
3411
  ],
2221
3412
  "props": [],
2222
3413
  "examples": []
2223
3414
  },
2224
3415
  {
2225
- "name": "DialogTrigger",
2226
- "title": "Dialog",
2227
- "description": "A Dialog is a modal surface that appears above the main interface to capture the user’s attention",
2228
- "docsPath": "docs/content/docs/components/dialog.mdx",
2229
- "docSlug": "dialog",
3416
+ "name": "DrawerTrigger",
3417
+ "title": "Drawer",
3418
+ "description": "A side panel that slides in from the edge of the screen, used for navigation, detail views, or supplementary content",
3419
+ "docsPath": "docs/content/docs/components/drawer.mdx",
3420
+ "docSlug": "drawer",
2230
3421
  "documentationUrl": "https://www.radix-ui.com/docs/primitives/components/dialog",
2231
3422
  "apiReferenceUrl": "https://www.radix-ui.com/docs/primitives/components/dialog#api-reference",
2232
3423
  "sourcePaths": [
2233
- "src/components/dialog/dialog.tsx"
3424
+ "src/components/drawer/drawer.tsx"
2234
3425
  ],
2235
3426
  "props": [
2236
3427
  {
@@ -2244,7 +3435,12 @@
2244
3435
  {
2245
3436
  "language": "tsx",
2246
3437
  "meta": "lineNumbers",
2247
- "code": "import { Dialog, DialogTrigger, DialogContent, DialogPortal, DialogFooter, DialogClose, Button, DialogHeader, DialogTitle, DialogDescription } from \"@epilot/volt-ui\"\n\n<div className=\"flex flex-col gap-4\">\n <Dialog>\n <DialogTrigger asChild>\n <Button variant=\"outline\">Open</Button>\n </DialogTrigger>\n <DialogPortal container={document.getElementById(\"root\")}>\n <DialogOverlay />\n <DialogContent size=\"2xl\">\n <DialogHeader>\n <DialogTitle>Edit profile</DialogTitle>\n <DialogDescription>\n Make changes to your profile here. Click save when you&apos;re\n done.\n </DialogDescription>\n </DialogHeader>\n <form className=\"flex flex-col gap-4 w-full\">\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Full Name</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"text\" placeholder=\"John Doe\" />\n </div>\n <div className=\"flex gap-4\">\n <Label className=\"w-1/4\">Email</Label>\n <input className=\"w-full border rounded-lg p-2\" type=\"email\" placeholder=\"john.doe@example.com\" />\n </div>\n </form>\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"secondary\">Cancel</Button>\n </DialogClose>\n <Button type=\"submit\">Save changes</Button>\n </DialogFooter>\n </DialogContent>\n </DialogPortal>\n </Dialog>\n</div>"
3438
+ "code": "import { Drawer, DrawerTrigger, DrawerContent, DrawerPortal, DrawerOverlay, DrawerFooter, DrawerClose, DrawerHeader, DrawerTitle, DrawerDescription, Button } from \"@epilot/volt-ui\"\n\n<Drawer>\n <DrawerTrigger asChild>\n <Button variant=\"primary\">Open Drawer</Button>\n </DrawerTrigger>\n <DrawerPortal container={document.getElementById(\"root\")}>\n <DrawerOverlay />\n <DrawerContent className=\"w-96\">\n <DrawerHeader>\n <DrawerTitle>Details</DrawerTitle>\n <DrawerDescription>\n View and edit the details below.\n </DrawerDescription>\n </DrawerHeader>\n <div className=\"flex flex-col gap-4 flex-1 overflow-auto\">\n <p>Drawer content goes here.</p>\n </div>\n <DrawerFooter>\n <DrawerClose asChild>\n <Button variant=\"secondary\">Close</Button>\n </DrawerClose>\n <Button>Save</Button>\n </DrawerFooter>\n </DrawerContent>\n </DrawerPortal>\n</Drawer>"
3439
+ },
3440
+ {
3441
+ "language": "tsx",
3442
+ "meta": "lineNumbers",
3443
+ "code": "<Drawer>\n <DrawerTrigger asChild>\n <Button>Open Left</Button>\n </DrawerTrigger>\n <DrawerPortal container={document.getElementById(\"root\")}>\n <DrawerOverlay />\n <DrawerContent side=\"left\" className=\"w-80\">\n <DrawerHeader>\n <DrawerTitle>Left Drawer</DrawerTitle>\n </DrawerHeader>\n <p>This drawer slides in from the left.</p>\n </DrawerContent>\n </DrawerPortal>\n</Drawer>"
2248
3444
  }
2249
3445
  ]
2250
3446
  },
@@ -3760,6 +4956,98 @@
3760
4956
  }
3761
4957
  ]
3762
4958
  },
4959
+ {
4960
+ "name": "Pill",
4961
+ "title": "Pill",
4962
+ "description": "Pills are interactive UI elements that represent selections, inputs, filters, or categories",
4963
+ "docsPath": "docs/content/docs/components/pill.mdx",
4964
+ "docSlug": "pill",
4965
+ "documentationUrl": null,
4966
+ "apiReferenceUrl": null,
4967
+ "sourcePaths": [
4968
+ "src/components/pill/pill.tsx"
4969
+ ],
4970
+ "props": [
4971
+ {
4972
+ "name": "`color`",
4973
+ "type": "\"accent\" | \"success\" | \"warning\" | \"error\" | \"gray\" | \"blue\" | \"sky\" | \"mint\" | \"lime\" | \"green\" | \"teal\" | \"cyan\" | \"indigo\" | \"purple\" | \"pink\" | \"red\" | \"orange\" | \"yellow\" | \"bronze\"",
4974
+ "default": "`\"accent\"`",
4975
+ "description": "The color variant of the pill. Semantic colors (accent, success, warning, error) are recommended for most use cases."
4976
+ },
4977
+ {
4978
+ "name": "`style`",
4979
+ "type": "\"soft\" | \"solid\" | \"surface\"",
4980
+ "default": "`\"soft\"`",
4981
+ "description": "The visual style variant of the pill."
4982
+ },
4983
+ {
4984
+ "name": "`disabled`",
4985
+ "type": "boolean",
4986
+ "default": "`false`",
4987
+ "description": "When true, renders the pill in a non-interactive gray state."
4988
+ },
4989
+ {
4990
+ "name": "`onClick`",
4991
+ "type": "(e: React.MouseEvent) => void",
4992
+ "default": "-",
4993
+ "description": "When provided, makes the pill interactive with hover state, pointer cursor, keyboard focus (`role=\"button\"`), and Enter/Space support."
4994
+ },
4995
+ {
4996
+ "name": "`onRemove`",
4997
+ "type": "(e: React.MouseEvent) => void",
4998
+ "default": "-",
4999
+ "description": "When provided, renders a remove button. Called when the remove button is clicked."
5000
+ },
5001
+ {
5002
+ "name": "`className`",
5003
+ "type": "string",
5004
+ "default": "-",
5005
+ "description": "Additional CSS classes to apply to the pill."
5006
+ }
5007
+ ],
5008
+ "examples": [
5009
+ {
5010
+ "language": "tsx",
5011
+ "meta": "lineNumbers",
5012
+ "code": "import { Pill } from \"@epilot/volt-ui\"\n\n<Pill color=\"accent\" style=\"solid\">Accent</Pill>\n<Pill color=\"success\" style=\"surface\">Success</Pill>\n<Pill color=\"warning\" style=\"soft\">Warning</Pill>\n<Pill color=\"error\" style=\"solid\">Error</Pill>"
5013
+ },
5014
+ {
5015
+ "language": "tsx",
5016
+ "meta": "lineNumbers",
5017
+ "code": "<Pill color=\"accent\" style=\"solid\">Solid</Pill>\n<Pill color=\"accent\" style=\"surface\">Surface</Pill>\n<Pill color=\"accent\" style=\"soft\">Soft</Pill>"
5018
+ },
5019
+ {
5020
+ "language": "tsx",
5021
+ "meta": "lineNumbers",
5022
+ "code": "<Pill color=\"blue\" style=\"solid\">Blue</Pill>\n<Pill color=\"purple\" style=\"surface\">Purple</Pill>\n<Pill color=\"green\" style=\"soft\">Green</Pill>"
5023
+ },
5024
+ {
5025
+ "language": "tsx",
5026
+ "meta": "lineNumbers",
5027
+ "code": "<Pill color=\"accent\" style=\"solid\" onClick={() => handleClick()}>\n Clickable\n</Pill>"
5028
+ },
5029
+ {
5030
+ "language": "tsx",
5031
+ "meta": "lineNumbers",
5032
+ "code": "<Pill color=\"blue\" style=\"solid\" onRemove={() => handleRemove(id)}>\n Removable\n</Pill>"
5033
+ },
5034
+ {
5035
+ "language": "tsx",
5036
+ "meta": "lineNumbers",
5037
+ "code": "import { IconTag } from \"@tabler/icons-react\"\n\n<Pill color=\"blue\" style=\"solid\">\n <IconTag /> Tagged\n</Pill>"
5038
+ },
5039
+ {
5040
+ "language": "tsx",
5041
+ "meta": "lineNumbers",
5042
+ "code": "import { Pill, Badge } from \"@epilot/volt-ui\"\n\n<Pill color=\"blue\" style=\"solid\">\n Label <Badge size=\"sm\" color=\"blue\" style=\"solid\">3</Badge>\n</Pill>"
5043
+ },
5044
+ {
5045
+ "language": "tsx",
5046
+ "meta": "lineNumbers",
5047
+ "code": "<Pill disabled style=\"solid\">Disabled</Pill>"
5048
+ }
5049
+ ]
5050
+ },
3763
5051
  {
3764
5052
  "name": "Popover",
3765
5053
  "title": "Popover",
@@ -4063,6 +5351,85 @@
4063
5351
  }
4064
5352
  ]
4065
5353
  },
5354
+ {
5355
+ "name": "RangeCalendar",
5356
+ "title": "Date Range Picker",
5357
+ "description": "A date range picker component with two side-by-side calendars for selecting a start and end date.",
5358
+ "docsPath": "docs/content/docs/components/date-range-picker.mdx",
5359
+ "docSlug": "date-range-picker",
5360
+ "documentationUrl": null,
5361
+ "apiReferenceUrl": null,
5362
+ "sourcePaths": [
5363
+ "src/components/date-range-picker/date-range-picker.tsx"
5364
+ ],
5365
+ "props": [
5366
+ {
5367
+ "name": "`value`",
5368
+ "type": "`DateRange`",
5369
+ "default": "-",
5370
+ "description": "The selected date range."
5371
+ },
5372
+ {
5373
+ "name": "`onChange`",
5374
+ "type": "`(range: DateRange) => void`",
5375
+ "default": "-",
5376
+ "description": "Callback fired when the range changes."
5377
+ },
5378
+ {
5379
+ "name": "`onRangeComplete`",
5380
+ "type": "`() => void`",
5381
+ "default": "-",
5382
+ "description": "Callback fired when both start and end are selected."
5383
+ },
5384
+ {
5385
+ "name": "`disablePast`",
5386
+ "type": "`boolean`",
5387
+ "default": "`false`",
5388
+ "description": "When true, past dates are disabled."
5389
+ },
5390
+ {
5391
+ "name": "`locale`",
5392
+ "type": "`\"en\" | \"de\" | \"fr\"`",
5393
+ "default": "`\"de\"`",
5394
+ "description": "Locale for month/day names."
5395
+ },
5396
+ {
5397
+ "name": "`previousMonthLabel`",
5398
+ "type": "`string`",
5399
+ "default": "`\"Previous month\"`",
5400
+ "description": "Aria-label for the previous month button."
5401
+ },
5402
+ {
5403
+ "name": "`nextMonthLabel`",
5404
+ "type": "`string`",
5405
+ "default": "`\"Next month\"`",
5406
+ "description": "Aria-label for the next month button."
5407
+ },
5408
+ {
5409
+ "name": "`currentTimeInTimezone`",
5410
+ "type": "`Date`",
5411
+ "default": "-",
5412
+ "description": "Override \"now\" for timezone-aware past checks."
5413
+ }
5414
+ ],
5415
+ "examples": [
5416
+ {
5417
+ "language": "tsx",
5418
+ "meta": "lineNumbers",
5419
+ "code": "import { useState } from \"react\"\nimport { DateRangePicker } from \"@epilot/volt-ui\"\nimport type { DateRange } from \"@epilot/volt-ui\"\n\nconst MyComponent = () => {\n const [value, setValue] = useState<DateRange>({\n start: new Date(),\n end: null,\n })\n\n return (\n <DateRangePicker\n label=\"Date Range\"\n value={value}\n onChange={setValue}\n locale=\"en\"\n />\n )\n}"
5420
+ },
5421
+ {
5422
+ "language": "tsx",
5423
+ "meta": "lineNumbers",
5424
+ "code": "<DateRangePicker\n label=\"Future Dates Only\"\n value={value}\n onChange={setValue}\n disablePast\n/>"
5425
+ },
5426
+ {
5427
+ "language": "tsx",
5428
+ "meta": "lineNumbers",
5429
+ "code": "<DateRangePicker\n label=\"Date Range\"\n value={value}\n onChange={setValue}\n error=\"Please select a valid date range\"\n/>"
5430
+ }
5431
+ ]
5432
+ },
4066
5433
  {
4067
5434
  "name": "Select",
4068
5435
  "title": "Field Select",
@@ -5254,80 +6621,184 @@
5254
6621
  "name": "`value`",
5255
6622
  "type": "`string`",
5256
6623
  "default": "-",
5257
- "description": "A unique value that associates the trigger with a content panel."
6624
+ "description": "A unique value that associates the trigger with a content panel."
6625
+ },
6626
+ {
6627
+ "name": "`disabled`",
6628
+ "type": "`boolean`",
6629
+ "default": "`false`",
6630
+ "description": "When true, prevents the user from interacting with the tab."
6631
+ },
6632
+ {
6633
+ "name": "`className`",
6634
+ "type": "`string`",
6635
+ "default": "-",
6636
+ "description": "Additional CSS classes to apply."
6637
+ }
6638
+ ],
6639
+ "examples": [
6640
+ {
6641
+ "language": "tsx",
6642
+ "meta": "lineNumbers",
6643
+ "code": "import { Tabs, TabsList, TabsTrigger, TabsContent, Badge } from \"@epilot/volt-ui\"\n\n<Tabs variant=\"highlight\" defaultValue=\"account\">\n <TabsList>\n <TabsTrigger value=\"account\">Account <Badge size=\"sm\">1</Badge></TabsTrigger>\n <TabsTrigger value=\"password\">Password</TabsTrigger>\n <TabsTrigger value=\"settings\">Settings</TabsTrigger>\n </TabsList>\n <TabsContent value=\"account\"></TabsContent>\n <TabsContent value=\"password\"></TabsContent>\n <TabsContent value=\"settings\"></TabsContent>\n</Tabs>"
6644
+ },
6645
+ {
6646
+ "language": "tsx",
6647
+ "meta": "lineNumbers",
6648
+ "code": "import { Tabs, TabsList, TabsTrigger, TabsContentm } from \"@epilot/volt-ui\"\n\n<Tabs defaultValue=\"account\" orientation=\"vertical\">\n <TabsList>\n <TabsTrigger value=\"account\">Account</TabsTrigger>\n <TabsTrigger value=\"password\">Password</TabsTrigger>\n <TabsTrigger value=\"settings\">Settings</TabsTrigger>\n </TabsList>\n <TabsContent value=\"account\"></TabsContent>\n <TabsContent value=\"password\"></TabsContent>\n <TabsContent value=\"settings\"></TabsContent>\n</Tabs>"
6649
+ }
6650
+ ]
6651
+ },
6652
+ {
6653
+ "name": "Text",
6654
+ "title": "Text",
6655
+ "description": "A text component with typography variants.",
6656
+ "docsPath": "docs/content/docs/components/text.mdx",
6657
+ "docSlug": "text",
6658
+ "documentationUrl": null,
6659
+ "apiReferenceUrl": null,
6660
+ "sourcePaths": [
6661
+ "src/components/text/text.tsx"
6662
+ ],
6663
+ "props": [
6664
+ {
6665
+ "name": "`variant`",
6666
+ "type": "See variants below",
6667
+ "default": "`\"body2\"`",
6668
+ "description": "The typography variant from the design system."
6669
+ },
6670
+ {
6671
+ "name": "`asChild`",
6672
+ "type": "boolean",
6673
+ "default": "`false`",
6674
+ "description": "When `true`, merges props onto the child element instead of rendering a `<span>`. Useful for applying Text styles to semantic HTML elements."
6675
+ },
6676
+ {
6677
+ "name": "`className`",
6678
+ "type": "string",
6679
+ "default": "-",
6680
+ "description": "Additional Tailwind classes merged with the defaults."
6681
+ }
6682
+ ],
6683
+ "examples": [
6684
+ {
6685
+ "language": "tsx",
6686
+ "meta": "lineNumbers",
6687
+ "code": "import { Text } from \"@epilot/volt-ui\"\n\n<Text variant=\"title3\">Title 3</Text>\n<Text variant=\"body2\">Body text</Text>\n<Text variant=\"body1\">Small emphasized text</Text>"
6688
+ },
6689
+ {
6690
+ "language": "tsx",
6691
+ "meta": "lineNumbers",
6692
+ "code": "import { Text } from \"@epilot/volt-ui\"\n\n<Text asChild variant=\"title1\"><h1>Title 1</h1></Text>\n<Text asChild variant=\"heading1\"><h2>Heading 1</h2></Text>"
6693
+ },
6694
+ {
6695
+ "language": "tsx",
6696
+ "meta": null,
6697
+ "code": "<Text asChild variant=\"title1\"><h1>Page title</h1></Text>\n<Text asChild variant=\"heading2\"><h2>Section heading</h2></Text>"
6698
+ },
6699
+ {
6700
+ "language": "tsx",
6701
+ "meta": null,
6702
+ "code": "<Text className=\"volt-text-accent-default volt-text-center\">\n Centered accent text\n</Text>\n<Text variant=\"heading2\" className=\"volt-text-error-default\">\n Error message heading\n</Text>"
6703
+ }
6704
+ ]
6705
+ },
6706
+ {
6707
+ "name": "TimePicker",
6708
+ "title": "Date Time Picker",
6709
+ "description": "A date and time picker component with calendar and time selection.",
6710
+ "docsPath": "docs/content/docs/components/date-time-picker.mdx",
6711
+ "docSlug": "date-time-picker",
6712
+ "documentationUrl": null,
6713
+ "apiReferenceUrl": null,
6714
+ "sourcePaths": [
6715
+ "src/components/date-time-picker/date-time-picker.tsx"
6716
+ ],
6717
+ "props": [
6718
+ {
6719
+ "name": "`value`",
6720
+ "type": "`Date`",
6721
+ "default": "-",
6722
+ "description": "The date object containing the time to display."
6723
+ },
6724
+ {
6725
+ "name": "`onChange`",
6726
+ "type": "`(date: Date) => void`",
6727
+ "default": "-",
6728
+ "description": "Callback fired when time changes."
6729
+ },
6730
+ {
6731
+ "name": "`onTimeSelect`",
6732
+ "type": "`() => void`",
6733
+ "default": "-",
6734
+ "description": "Callback fired after time selection."
5258
6735
  },
5259
6736
  {
5260
- "name": "`disabled`",
6737
+ "name": "`disablePast`",
5261
6738
  "type": "`boolean`",
5262
6739
  "default": "`false`",
5263
- "description": "When true, prevents the user from interacting with the tab."
6740
+ "description": "When true, past times are disabled (only on current day)."
5264
6741
  },
5265
6742
  {
5266
- "name": "`className`",
6743
+ "name": "`locale`",
6744
+ "type": "`\"en\" | \"de\" | \"fr\"`",
6745
+ "default": "`\"de\"`",
6746
+ "description": "Locale (reserved for future use)."
6747
+ },
6748
+ {
6749
+ "name": "`hoursLabel`",
6750
+ "type": "`string`",
6751
+ "default": "`\"HH\"`",
6752
+ "description": "Label for the hours column."
6753
+ },
6754
+ {
6755
+ "name": "`minutesLabel`",
5267
6756
  "type": "`string`",
6757
+ "default": "`\"MM\"`",
6758
+ "description": "Label for the minutes column."
6759
+ },
6760
+ {
6761
+ "name": "`currentTimeInTimezone`",
6762
+ "type": "`Date`",
5268
6763
  "default": "-",
5269
- "description": "Additional CSS classes to apply."
6764
+ "description": "Override \"now\" for timezone-aware past checks."
5270
6765
  }
5271
6766
  ],
5272
6767
  "examples": [
5273
6768
  {
5274
6769
  "language": "tsx",
5275
6770
  "meta": "lineNumbers",
5276
- "code": "import { Tabs, TabsList, TabsTrigger, TabsContent, Badge } from \"@epilot/volt-ui\"\n\n<Tabs variant=\"highlight\" defaultValue=\"account\">\n <TabsList>\n <TabsTrigger value=\"account\">Account <Badge size=\"sm\">1</Badge></TabsTrigger>\n <TabsTrigger value=\"password\">Password</TabsTrigger>\n <TabsTrigger value=\"settings\">Settings</TabsTrigger>\n </TabsList>\n <TabsContent value=\"account\"></TabsContent>\n <TabsContent value=\"password\"></TabsContent>\n <TabsContent value=\"settings\"></TabsContent>\n</Tabs>"
6771
+ "code": "import { useState } from \"react\"\nimport { DateTimePicker } from \"@epilot/volt-ui\"\n\nconst MyComponent = () => {\n const [value, setValue] = useState<Date>(new Date())\n\n return (\n <DateTimePicker\n label=\"Appointment\"\n value={value}\n onChange={setValue}\n locale=\"en\"\n />\n )\n}"
5277
6772
  },
5278
6773
  {
5279
6774
  "language": "tsx",
5280
6775
  "meta": "lineNumbers",
5281
- "code": "import { Tabs, TabsList, TabsTrigger, TabsContentm } from \"@epilot/volt-ui\"\n\n<Tabs defaultValue=\"account\" orientation=\"vertical\">\n <TabsList>\n <TabsTrigger value=\"account\">Account</TabsTrigger>\n <TabsTrigger value=\"password\">Password</TabsTrigger>\n <TabsTrigger value=\"settings\">Settings</TabsTrigger>\n </TabsList>\n <TabsContent value=\"account\"></TabsContent>\n <TabsContent value=\"password\"></TabsContent>\n <TabsContent value=\"settings\"></TabsContent>\n</Tabs>"
5282
- }
5283
- ]
5284
- },
5285
- {
5286
- "name": "Text",
5287
- "title": "Text",
5288
- "description": "A text component with typography variants.",
5289
- "docsPath": "docs/content/docs/components/text.mdx",
5290
- "docSlug": "text",
5291
- "documentationUrl": null,
5292
- "apiReferenceUrl": null,
5293
- "sourcePaths": [
5294
- "src/components/text/text.tsx"
5295
- ],
5296
- "props": [
5297
- {
5298
- "name": "`variant`",
5299
- "type": "See variants below",
5300
- "default": "`\"body2\"`",
5301
- "description": "The typography variant from the design system."
6776
+ "code": "<DateTimePicker\n label=\"Future Date Only\"\n value={value}\n onChange={setValue}\n disablePast\n/>"
5302
6777
  },
5303
6778
  {
5304
- "name": "`asChild`",
5305
- "type": "boolean",
5306
- "default": "`false`",
5307
- "description": "When `true`, merges props onto the child element instead of rendering a `<span>`. Useful for applying Text styles to semantic HTML elements."
6779
+ "language": "tsx",
6780
+ "meta": "lineNumbers",
6781
+ "code": "<DateTimePicker\n label=\"Date & Time\"\n value={value}\n onChange={setValue}\n error=\"Please select a valid date\"\n/>"
5308
6782
  },
5309
6783
  {
5310
- "name": "`className`",
5311
- "type": "string",
5312
- "default": "-",
5313
- "description": "Additional Tailwind classes merged with the defaults."
5314
- }
5315
- ],
5316
- "examples": [
6784
+ "language": "tsx",
6785
+ "meta": "lineNumbers",
6786
+ "code": "<DateTimePicker\n label=\"Termin\"\n value={value}\n onChange={setValue}\n locale=\"de\"\n format=\"dd.MM.yyyy HH:mm\"\n placeholder=\"tt.mm.jjjj hh:mm\"\n/>"
6787
+ },
5317
6788
  {
5318
6789
  "language": "tsx",
5319
6790
  "meta": "lineNumbers",
5320
- "code": "import { Text } from \"@epilot/volt-ui\"\n\n<Text variant=\"title3\">Title 3</Text>\n<Text variant=\"body2\">Body text</Text>\n<Text variant=\"body1\">Small emphasized text</Text>"
6791
+ "code": "<DateTimePicker\n label=\"Select Date\"\n value={value}\n onChange={setValue}\n showTodayButton\n todayLabel=\"Today\"\n/>"
5321
6792
  },
5322
6793
  {
5323
6794
  "language": "tsx",
5324
6795
  "meta": "lineNumbers",
5325
- "code": "import { Text } from \"@epilot/volt-ui\"\n\n<Text asChild variant=\"title1\"><h1>Title 1</h1></Text>\n<Text asChild variant=\"heading1\"><h2>Heading 1</h2></Text>"
6796
+ "code": "<DateTimePicker\n label=\"Side Layout\"\n value={value}\n onChange={setValue}\n timePickerPosition=\"side\"\n/>"
5326
6797
  },
5327
6798
  {
5328
6799
  "language": "tsx",
5329
- "meta": null,
5330
- "code": "<Text className=\"volt-text-accent-default volt-text-center\">\n Centered accent text\n</Text>\n<Text variant=\"heading2\" className=\"volt-text-error-default\">\n Error message heading\n</Text>"
6800
+ "meta": "lineNumbers",
6801
+ "code": "<DateTimePicker\n label=\"Side Layout + Today\"\n value={value}\n onChange={setValue}\n timePickerPosition=\"side\"\n showTodayButton\n todayLabel=\"Today\"\n/>"
5331
6802
  }
5332
6803
  ]
5333
6804
  },
@@ -14387,6 +15858,13 @@
14387
15858
  "group": "semantic",
14388
15859
  "sourcePath": "src/styles/colors-semantic-utilities.css"
14389
15860
  },
15861
+ {
15862
+ "name": "--color-accent-surface-hover",
15863
+ "value": "var(--volt-accent-a3)",
15864
+ "theme": "global",
15865
+ "group": "semantic",
15866
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
15867
+ },
14390
15868
  {
14391
15869
  "name": "--color-accent-ui",
14392
15870
  "value": "var(--volt-accent-a7)",
@@ -14471,6 +15949,13 @@
14471
15949
  "group": "semantic",
14472
15950
  "sourcePath": "src/styles/colors-semantic-utilities.css"
14473
15951
  },
15952
+ {
15953
+ "name": "--color-error-surface-hover",
15954
+ "value": "var(--volt-error-a3)",
15955
+ "theme": "global",
15956
+ "group": "semantic",
15957
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
15958
+ },
14474
15959
  {
14475
15960
  "name": "--color-error-ui",
14476
15961
  "value": "var(--volt-error-a7)",
@@ -14555,6 +16040,13 @@
14555
16040
  "group": "semantic",
14556
16041
  "sourcePath": "src/styles/colors-semantic-utilities.css"
14557
16042
  },
16043
+ {
16044
+ "name": "--color-gray-surface-hover",
16045
+ "value": "var(--volt-gray-a3)",
16046
+ "theme": "global",
16047
+ "group": "semantic",
16048
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16049
+ },
14558
16050
  {
14559
16051
  "name": "--color-gray-ui",
14560
16052
  "value": "var(--volt-gray-a7)",
@@ -14639,6 +16131,13 @@
14639
16131
  "group": "semantic",
14640
16132
  "sourcePath": "src/styles/colors-semantic-utilities.css"
14641
16133
  },
16134
+ {
16135
+ "name": "--color-info-surface-hover",
16136
+ "value": "var(--volt-info-a3)",
16137
+ "theme": "global",
16138
+ "group": "semantic",
16139
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16140
+ },
14642
16141
  {
14643
16142
  "name": "--color-info-ui",
14644
16143
  "value": "var(--volt-info-a7)",
@@ -14723,6 +16222,13 @@
14723
16222
  "group": "semantic",
14724
16223
  "sourcePath": "src/styles/colors-semantic-utilities.css"
14725
16224
  },
16225
+ {
16226
+ "name": "--color-success-surface-hover",
16227
+ "value": "var(--volt-success-a3)",
16228
+ "theme": "global",
16229
+ "group": "semantic",
16230
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16231
+ },
14726
16232
  {
14727
16233
  "name": "--color-success-ui",
14728
16234
  "value": "var(--volt-success-a7)",
@@ -14807,6 +16313,13 @@
14807
16313
  "group": "semantic",
14808
16314
  "sourcePath": "src/styles/colors-semantic-utilities.css"
14809
16315
  },
16316
+ {
16317
+ "name": "--color-warning-surface-hover",
16318
+ "value": "var(--volt-warning-a3)",
16319
+ "theme": "global",
16320
+ "group": "semantic",
16321
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16322
+ },
14810
16323
  {
14811
16324
  "name": "--color-warning-ui",
14812
16325
  "value": "var(--volt-warning-a7)",
@@ -14891,6 +16404,13 @@
14891
16404
  "group": "semantic",
14892
16405
  "sourcePath": "src/styles/colors-semantic-utilities.css"
14893
16406
  },
16407
+ {
16408
+ "name": "--color-blue-surface-hover",
16409
+ "value": "var(--volt-blue-a3)",
16410
+ "theme": "global",
16411
+ "group": "semantic",
16412
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16413
+ },
14894
16414
  {
14895
16415
  "name": "--color-blue-ui",
14896
16416
  "value": "var(--volt-blue-a7)",
@@ -14975,6 +16495,13 @@
14975
16495
  "group": "semantic",
14976
16496
  "sourcePath": "src/styles/colors-semantic-utilities.css"
14977
16497
  },
16498
+ {
16499
+ "name": "--color-bronze-surface-hover",
16500
+ "value": "var(--volt-bronze-a3)",
16501
+ "theme": "global",
16502
+ "group": "semantic",
16503
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16504
+ },
14978
16505
  {
14979
16506
  "name": "--color-bronze-ui",
14980
16507
  "value": "var(--volt-bronze-a7)",
@@ -15059,6 +16586,13 @@
15059
16586
  "group": "semantic",
15060
16587
  "sourcePath": "src/styles/colors-semantic-utilities.css"
15061
16588
  },
16589
+ {
16590
+ "name": "--color-cyan-surface-hover",
16591
+ "value": "var(--volt-cyan-a3)",
16592
+ "theme": "global",
16593
+ "group": "semantic",
16594
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16595
+ },
15062
16596
  {
15063
16597
  "name": "--color-cyan-ui",
15064
16598
  "value": "var(--volt-cyan-a7)",
@@ -15143,6 +16677,13 @@
15143
16677
  "group": "semantic",
15144
16678
  "sourcePath": "src/styles/colors-semantic-utilities.css"
15145
16679
  },
16680
+ {
16681
+ "name": "--color-green-surface-hover",
16682
+ "value": "var(--volt-green-a3)",
16683
+ "theme": "global",
16684
+ "group": "semantic",
16685
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16686
+ },
15146
16687
  {
15147
16688
  "name": "--color-green-ui",
15148
16689
  "value": "var(--volt-green-a7)",
@@ -15227,6 +16768,13 @@
15227
16768
  "group": "semantic",
15228
16769
  "sourcePath": "src/styles/colors-semantic-utilities.css"
15229
16770
  },
16771
+ {
16772
+ "name": "--color-indigo-surface-hover",
16773
+ "value": "var(--volt-indigo-a3)",
16774
+ "theme": "global",
16775
+ "group": "semantic",
16776
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16777
+ },
15230
16778
  {
15231
16779
  "name": "--color-indigo-ui",
15232
16780
  "value": "var(--volt-indigo-a7)",
@@ -15241,6 +16789,97 @@
15241
16789
  "group": "semantic",
15242
16790
  "sourcePath": "src/styles/colors-semantic-utilities.css"
15243
16791
  },
16792
+ {
16793
+ "name": "--color-lime-contrast",
16794
+ "value": "var(--volt-lime-contrast)",
16795
+ "theme": "global",
16796
+ "group": "semantic",
16797
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16798
+ },
16799
+ {
16800
+ "name": "--color-lime-default",
16801
+ "value": "var(--volt-lime-a12)",
16802
+ "theme": "global",
16803
+ "group": "semantic",
16804
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16805
+ },
16806
+ {
16807
+ "name": "--color-lime-disabled",
16808
+ "value": "var(--volt-lime-a8)",
16809
+ "theme": "global",
16810
+ "group": "semantic",
16811
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16812
+ },
16813
+ {
16814
+ "name": "--color-lime-high-contrast",
16815
+ "value": "var(--volt-lime-a12)",
16816
+ "theme": "global",
16817
+ "group": "semantic",
16818
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16819
+ },
16820
+ {
16821
+ "name": "--color-lime-light",
16822
+ "value": "var(--volt-lime-a11)",
16823
+ "theme": "global",
16824
+ "group": "semantic",
16825
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16826
+ },
16827
+ {
16828
+ "name": "--color-lime-soft",
16829
+ "value": "var(--volt-lime-a3)",
16830
+ "theme": "global",
16831
+ "group": "semantic",
16832
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16833
+ },
16834
+ {
16835
+ "name": "--color-lime-soft-hover",
16836
+ "value": "var(--volt-lime-a2)",
16837
+ "theme": "global",
16838
+ "group": "semantic",
16839
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16840
+ },
16841
+ {
16842
+ "name": "--color-lime-solid",
16843
+ "value": "var(--volt-lime-a9)",
16844
+ "theme": "global",
16845
+ "group": "semantic",
16846
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16847
+ },
16848
+ {
16849
+ "name": "--color-lime-solid-hover",
16850
+ "value": "var(--volt-lime-a10)",
16851
+ "theme": "global",
16852
+ "group": "semantic",
16853
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16854
+ },
16855
+ {
16856
+ "name": "--color-lime-surface",
16857
+ "value": "var(--volt-lime-surface)",
16858
+ "theme": "global",
16859
+ "group": "semantic",
16860
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16861
+ },
16862
+ {
16863
+ "name": "--color-lime-surface-hover",
16864
+ "value": "var(--volt-lime-a3)",
16865
+ "theme": "global",
16866
+ "group": "semantic",
16867
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16868
+ },
16869
+ {
16870
+ "name": "--color-lime-ui",
16871
+ "value": "var(--volt-lime-a7)",
16872
+ "theme": "global",
16873
+ "group": "semantic",
16874
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16875
+ },
16876
+ {
16877
+ "name": "--color-lime-ui-hover",
16878
+ "value": "var(--volt-lime-a8)",
16879
+ "theme": "global",
16880
+ "group": "semantic",
16881
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16882
+ },
15244
16883
  {
15245
16884
  "name": "--color-mauve-contrast",
15246
16885
  "value": "var(--volt-mauve-contrast)",
@@ -15311,6 +16950,13 @@
15311
16950
  "group": "semantic",
15312
16951
  "sourcePath": "src/styles/colors-semantic-utilities.css"
15313
16952
  },
16953
+ {
16954
+ "name": "--color-mauve-surface-hover",
16955
+ "value": "var(--volt-mauve-a3)",
16956
+ "theme": "global",
16957
+ "group": "semantic",
16958
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
16959
+ },
15314
16960
  {
15315
16961
  "name": "--color-mauve-ui",
15316
16962
  "value": "var(--volt-mauve-a7)",
@@ -15395,6 +17041,13 @@
15395
17041
  "group": "semantic",
15396
17042
  "sourcePath": "src/styles/colors-semantic-utilities.css"
15397
17043
  },
17044
+ {
17045
+ "name": "--color-mint-surface-hover",
17046
+ "value": "var(--volt-mint-a3)",
17047
+ "theme": "global",
17048
+ "group": "semantic",
17049
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
17050
+ },
15398
17051
  {
15399
17052
  "name": "--color-mint-ui",
15400
17053
  "value": "var(--volt-mint-a7)",
@@ -15479,6 +17132,13 @@
15479
17132
  "group": "semantic",
15480
17133
  "sourcePath": "src/styles/colors-semantic-utilities.css"
15481
17134
  },
17135
+ {
17136
+ "name": "--color-orange-surface-hover",
17137
+ "value": "var(--volt-orange-a3)",
17138
+ "theme": "global",
17139
+ "group": "semantic",
17140
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
17141
+ },
15482
17142
  {
15483
17143
  "name": "--color-orange-ui",
15484
17144
  "value": "var(--volt-orange-a7)",
@@ -15563,6 +17223,13 @@
15563
17223
  "group": "semantic",
15564
17224
  "sourcePath": "src/styles/colors-semantic-utilities.css"
15565
17225
  },
17226
+ {
17227
+ "name": "--color-pink-surface-hover",
17228
+ "value": "var(--volt-pink-a3)",
17229
+ "theme": "global",
17230
+ "group": "semantic",
17231
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
17232
+ },
15566
17233
  {
15567
17234
  "name": "--color-pink-ui",
15568
17235
  "value": "var(--volt-pink-a7)",
@@ -15647,6 +17314,13 @@
15647
17314
  "group": "semantic",
15648
17315
  "sourcePath": "src/styles/colors-semantic-utilities.css"
15649
17316
  },
17317
+ {
17318
+ "name": "--color-purple-surface-hover",
17319
+ "value": "var(--volt-purple-a3)",
17320
+ "theme": "global",
17321
+ "group": "semantic",
17322
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
17323
+ },
15650
17324
  {
15651
17325
  "name": "--color-purple-ui",
15652
17326
  "value": "var(--volt-purple-a7)",
@@ -15731,6 +17405,13 @@
15731
17405
  "group": "semantic",
15732
17406
  "sourcePath": "src/styles/colors-semantic-utilities.css"
15733
17407
  },
17408
+ {
17409
+ "name": "--color-red-surface-hover",
17410
+ "value": "var(--volt-red-a3)",
17411
+ "theme": "global",
17412
+ "group": "semantic",
17413
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
17414
+ },
15734
17415
  {
15735
17416
  "name": "--color-red-ui",
15736
17417
  "value": "var(--volt-red-a7)",
@@ -15815,6 +17496,13 @@
15815
17496
  "group": "semantic",
15816
17497
  "sourcePath": "src/styles/colors-semantic-utilities.css"
15817
17498
  },
17499
+ {
17500
+ "name": "--color-sky-surface-hover",
17501
+ "value": "var(--volt-sky-a3)",
17502
+ "theme": "global",
17503
+ "group": "semantic",
17504
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
17505
+ },
15818
17506
  {
15819
17507
  "name": "--color-sky-ui",
15820
17508
  "value": "var(--volt-sky-a7)",
@@ -15899,6 +17587,13 @@
15899
17587
  "group": "semantic",
15900
17588
  "sourcePath": "src/styles/colors-semantic-utilities.css"
15901
17589
  },
17590
+ {
17591
+ "name": "--color-teal-surface-hover",
17592
+ "value": "var(--volt-teal-a3)",
17593
+ "theme": "global",
17594
+ "group": "semantic",
17595
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
17596
+ },
15902
17597
  {
15903
17598
  "name": "--color-teal-ui",
15904
17599
  "value": "var(--volt-teal-a7)",
@@ -15983,6 +17678,13 @@
15983
17678
  "group": "semantic",
15984
17679
  "sourcePath": "src/styles/colors-semantic-utilities.css"
15985
17680
  },
17681
+ {
17682
+ "name": "--color-yellow-surface-hover",
17683
+ "value": "var(--volt-yellow-a3)",
17684
+ "theme": "global",
17685
+ "group": "semantic",
17686
+ "sourcePath": "src/styles/colors-semantic-utilities.css"
17687
+ },
15986
17688
  {
15987
17689
  "name": "--color-yellow-ui",
15988
17690
  "value": "var(--volt-yellow-a7)",