infinity-ui-elements 1.5.1-beta.0 → 1.5.1-beta.2

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 (84) hide show
  1. package/dist/components/Avatar/Avatar.d.ts +59 -0
  2. package/dist/components/Avatar/Avatar.d.ts.map +1 -0
  3. package/dist/components/Avatar/Avatar.stories.d.ts +119 -0
  4. package/dist/components/Avatar/Avatar.stories.d.ts.map +1 -0
  5. package/dist/components/Avatar/index.d.ts +3 -0
  6. package/dist/components/Avatar/index.d.ts.map +1 -0
  7. package/dist/components/Badge/Badge.d.ts +1 -1
  8. package/dist/components/Button/Button.d.ts +1 -1
  9. package/dist/components/ButtonGroup/ButtonGroup.d.ts +26 -0
  10. package/dist/components/ButtonGroup/ButtonGroup.d.ts.map +1 -0
  11. package/dist/components/ButtonGroup/ButtonGroup.stories.d.ts +102 -0
  12. package/dist/components/ButtonGroup/ButtonGroup.stories.d.ts.map +1 -0
  13. package/dist/components/ButtonGroup/index.d.ts +3 -0
  14. package/dist/components/ButtonGroup/index.d.ts.map +1 -0
  15. package/dist/components/Checkbox/Checkbox.d.ts +1 -1
  16. package/dist/components/Counter/Counter.d.ts +1 -1
  17. package/dist/components/Dropdown/Dropdown.d.ts +1 -1
  18. package/dist/components/Dropdown/Dropdown.stories.d.ts +1 -1
  19. package/dist/components/Dropdown/DropdownMenu.d.ts +4 -0
  20. package/dist/components/Dropdown/DropdownMenu.d.ts.map +1 -1
  21. package/dist/components/FormHeader/FormHeader.d.ts.map +1 -1
  22. package/dist/components/Link/Link.d.ts +1 -1
  23. package/dist/components/Modal/Modal.d.ts +78 -0
  24. package/dist/components/Modal/Modal.d.ts.map +1 -0
  25. package/dist/components/Modal/Modal.stories.d.ts +20 -0
  26. package/dist/components/Modal/Modal.stories.d.ts.map +1 -0
  27. package/dist/components/Modal/index.d.ts +3 -0
  28. package/dist/components/Modal/index.d.ts.map +1 -0
  29. package/dist/components/Pagination/Pagination.d.ts +81 -0
  30. package/dist/components/Pagination/Pagination.d.ts.map +1 -0
  31. package/dist/components/Pagination/Pagination.stories.d.ts +22 -0
  32. package/dist/components/Pagination/Pagination.stories.d.ts.map +1 -0
  33. package/dist/components/Pagination/index.d.ts +3 -0
  34. package/dist/components/Pagination/index.d.ts.map +1 -0
  35. package/dist/components/Radio/Radio.d.ts +1 -1
  36. package/dist/components/SearchableDropdown/SearchableDropdown.d.ts +4 -0
  37. package/dist/components/SearchableDropdown/SearchableDropdown.d.ts.map +1 -1
  38. package/dist/components/SearchableDropdown/SearchableDropdown.stories.d.ts +10 -9
  39. package/dist/components/SearchableDropdown/SearchableDropdown.stories.d.ts.map +1 -1
  40. package/dist/components/Select/Select.d.ts +148 -0
  41. package/dist/components/Select/Select.d.ts.map +1 -0
  42. package/dist/components/Select/Select.stories.d.ts +32 -0
  43. package/dist/components/Select/Select.stories.d.ts.map +1 -0
  44. package/dist/components/Select/index.d.ts +2 -0
  45. package/dist/components/Select/index.d.ts.map +1 -0
  46. package/dist/components/Switch/Switch.d.ts +1 -1
  47. package/dist/components/TabItem/TabItem.d.ts +1 -1
  48. package/dist/components/Table/DetailPanel.d.ts +10 -0
  49. package/dist/components/Table/DetailPanel.d.ts.map +1 -0
  50. package/dist/components/Table/Table.d.ts +39 -0
  51. package/dist/components/Table/Table.d.ts.map +1 -0
  52. package/dist/components/Table/Table.refactored.d.ts +39 -0
  53. package/dist/components/Table/Table.refactored.d.ts.map +1 -0
  54. package/dist/components/Table/Table.stories.d.ts +23 -0
  55. package/dist/components/Table/Table.stories.d.ts.map +1 -0
  56. package/dist/components/Table/TableBody.d.ts +18 -0
  57. package/dist/components/Table/TableBody.d.ts.map +1 -0
  58. package/dist/components/Table/TableCellTypes.d.ts +32 -0
  59. package/dist/components/Table/TableCellTypes.d.ts.map +1 -0
  60. package/dist/components/Table/TableDetailPanel.d.ts +25 -0
  61. package/dist/components/Table/TableDetailPanel.d.ts.map +1 -0
  62. package/dist/components/Table/TableHeader.d.ts +18 -0
  63. package/dist/components/Table/TableHeader.d.ts.map +1 -0
  64. package/dist/components/Table/index.d.ts +6 -0
  65. package/dist/components/Table/index.d.ts.map +1 -0
  66. package/dist/components/Table/tableHelpers.d.ts +7 -0
  67. package/dist/components/Table/tableHelpers.d.ts.map +1 -0
  68. package/dist/components/Table/tableVariants.d.ts +12 -0
  69. package/dist/components/Table/tableVariants.d.ts.map +1 -0
  70. package/dist/components/TextArea/TextArea.d.ts +1 -1
  71. package/dist/components/TextField/TextField.d.ts +1 -1
  72. package/dist/index.css +1 -1
  73. package/dist/index.d.ts +6 -0
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.esm.js +893 -42
  76. package/dist/index.esm.js.map +1 -1
  77. package/dist/index.js +910 -40
  78. package/dist/index.js.map +1 -1
  79. package/dist/lib/icons.d.ts +5 -1
  80. package/dist/lib/icons.d.ts.map +1 -1
  81. package/dist/lib/index.d.ts +3 -0
  82. package/dist/lib/index.d.ts.map +1 -0
  83. package/dist/lib/utils.d.ts.map +1 -1
  84. package/package.json +6 -1
package/dist/index.esm.js CHANGED
@@ -5,7 +5,9 @@ import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
6
  import { Slot } from '@radix-ui/react-slot';
7
7
  import { PulseLoader, ClipLoader } from 'react-spinners';
8
- import { ExternalLink, Loader2, Search } from 'lucide-react';
8
+ import { ExternalLink, Loader2, Search, X, ChevronDown, ChevronLeft, ChevronRight } from 'lucide-react';
9
+ import { createPortal } from 'react-dom';
10
+ import { flexRender } from '@tanstack/react-table';
9
11
 
10
12
  // Define patterns for custom classes that should be preserved
11
13
  // This approach is more scalable than hardcoding individual class names
@@ -46,6 +48,106 @@ function cn(...inputs) {
46
48
  return clsx(mergedStandard, customClasses);
47
49
  }
48
50
 
51
+ // Helper function to get the text utility class name
52
+ function getTextClassName(variant = "body", size = "medium", weight = "regular", color = "default") {
53
+ // Build the base class name
54
+ let baseClass = `text-${variant}`;
55
+ // Add size
56
+ if (size) {
57
+ baseClass += `-${size}`;
58
+ }
59
+ // Add weight
60
+ if (weight) {
61
+ baseClass += `-${weight}`;
62
+ }
63
+ // Add color class separately
64
+ const colorClass = `text-color-${color}`;
65
+ return `${baseClass} ${colorClass}`;
66
+ }
67
+ const Text = React.forwardRef(({ className, variant = "body", size = "medium", weight = "regular", color = "default", as = "p", children, ...props }, ref) => {
68
+ const Component = as;
69
+ const textClass = getTextClassName(variant, size, weight, color);
70
+ return React.createElement(Component, {
71
+ className: cn(textClass, className),
72
+ ref,
73
+ ...props,
74
+ }, children);
75
+ });
76
+ Text.displayName = "Text";
77
+
78
+ const avatarVariants = cva("inline-flex items-center justify-center font-medium text-center select-none", {
79
+ variants: {
80
+ color: {
81
+ a1: "bg-avatar-fill-a1-bg text-avatar-fill-a1-on-bg",
82
+ a2: "bg-avatar-fill-a2-bg text-avatar-fill-a2-on-bg",
83
+ a3: "bg-avatar-fill-a3-bg text-avatar-fill-a3-on-bg",
84
+ a4: "bg-avatar-fill-a4-bg text-avatar-fill-a4-on-bg",
85
+ a5: "bg-avatar-fill-a5-bg text-avatar-fill-a5-on-bg",
86
+ },
87
+ size: {
88
+ small: "h-[24px] w-[24px] text-body-medium-regular rounded-large",
89
+ medium: "h-[32px] w-[32px] text-body-medium-regular rounded-xlarge",
90
+ },
91
+ },
92
+ defaultVariants: {
93
+ color: "a1",
94
+ size: "medium",
95
+ },
96
+ });
97
+ const statusVariants = cva("absolute flex items-center justify-center rounded-full border-2 border-surface-fill-neutral-intense", {
98
+ variants: {
99
+ size: {
100
+ small: "h-5 w-5 -bottom-0.5 -right-0.5",
101
+ medium: "h-6 w-6 -bottom-1 -right-1",
102
+ },
103
+ statusColor: {
104
+ positive: "bg-action-fill-positive-default",
105
+ negative: "bg-action-fill-negative-default",
106
+ notice: "bg-action-fill-notice-default",
107
+ info: "bg-action-fill-info-default",
108
+ neutral: "bg-action-fill-neutral-default",
109
+ },
110
+ },
111
+ defaultVariants: {
112
+ size: "medium",
113
+ statusColor: "notice",
114
+ },
115
+ });
116
+ const Avatar = React.forwardRef(({ className, color, size, children, src, alt, showStatus = false, statusColor = "notice", statusIcon, label, trailingComponent, containerClassName, ...props }, ref) => {
117
+ const [imageError, setImageError] = React.useState(false);
118
+ const handleImageError = () => {
119
+ setImageError(true);
120
+ };
121
+ const getStatusIconSize = () => {
122
+ switch (size) {
123
+ case "small":
124
+ return "h-3.5 w-3.5";
125
+ case "medium":
126
+ return "h-4 w-4";
127
+ default:
128
+ return "h-4 w-4";
129
+ }
130
+ };
131
+ const getTextSize = () => {
132
+ switch (size) {
133
+ case "small":
134
+ return "small";
135
+ case "medium":
136
+ return "medium";
137
+ default:
138
+ return "medium";
139
+ }
140
+ };
141
+ const avatarElement = (jsxs("div", { className: "relative inline-block", children: [jsx("div", { className: cn(avatarVariants({ color, size }), className), ...props, children: src && !imageError ? (jsx("img", { src: src, alt: alt || "Avatar", className: cn("h-full w-full object-cover", size === "small" ? "rounded-large" : "rounded-xlarge"), onError: handleImageError })) : (children) }), showStatus && (jsx("div", { className: cn(statusVariants({ size, statusColor })), children: statusIcon && (jsx("span", { className: cn("text-action-ink-on-primary-normal", getStatusIconSize()), children: statusIcon })) }))] }));
142
+ // If no label or trailing component, return just the avatar
143
+ if (!label && !trailingComponent) {
144
+ return jsx("div", { ref: ref, children: avatarElement });
145
+ }
146
+ // Otherwise, return avatar with label and/or trailing component
147
+ return (jsxs("div", { ref: ref, className: cn("inline-flex items-center gap-3", containerClassName), children: [avatarElement, label && (jsx(Text, { variant: "body", size: getTextSize(), weight: "medium", color: "default", as: "span", children: label })), trailingComponent && (jsx("span", { className: "ml-auto", children: trailingComponent }))] }));
148
+ });
149
+ Avatar.displayName = "Avatar";
150
+
49
151
  const badgeVariants = cva("inline-flex items-center whitespace-nowrap transition-colors", {
50
152
  variants: {
51
153
  variant: {
@@ -462,32 +564,145 @@ const Button = React.forwardRef(({ className, variant = "primary", color = "prim
462
564
  });
463
565
  Button.displayName = "Button";
464
566
 
465
- // Helper function to get the text utility class name
466
- function getTextClassName(variant = "body", size = "medium", weight = "regular", color = "default") {
467
- // Build the base class name
468
- let baseClass = `text-${variant}`;
469
- // Add size
470
- if (size) {
471
- baseClass += `-${size}`;
472
- }
473
- // Add weight
474
- if (weight) {
475
- baseClass += `-${weight}`;
476
- }
477
- // Add color class separately
478
- const colorClass = `text-color-${color}`;
479
- return `${baseClass} ${colorClass}`;
480
- }
481
- const Text = React.forwardRef(({ className, variant = "body", size = "medium", weight = "regular", color = "default", as = "p", children, ...props }, ref) => {
482
- const Component = as;
483
- const textClass = getTextClassName(variant, size, weight, color);
484
- return React.createElement(Component, {
485
- className: cn(textClass, className),
486
- ref,
487
- ...props,
488
- }, children);
567
+ const buttonGroupVariants = cva("inline-flex", {
568
+ variants: {
569
+ variant: {
570
+ attached: "",
571
+ separated: "",
572
+ },
573
+ orientation: {
574
+ horizontal: "flex-row",
575
+ vertical: "flex-col",
576
+ },
577
+ size: {
578
+ xsmall: "",
579
+ small: "",
580
+ medium: "",
581
+ large: "",
582
+ },
583
+ isFullWidth: {
584
+ true: "w-full",
585
+ false: "w-fit",
586
+ },
587
+ isDisabled: {
588
+ true: "pointer-events-none opacity-50",
589
+ false: "",
590
+ },
591
+ },
592
+ compoundVariants: [
593
+ {
594
+ variant: "separated",
595
+ orientation: "horizontal",
596
+ class: "gap-2",
597
+ },
598
+ {
599
+ variant: "separated",
600
+ orientation: "vertical",
601
+ class: "gap-2",
602
+ },
603
+ ],
604
+ defaultVariants: {
605
+ variant: "attached",
606
+ orientation: "horizontal",
607
+ size: "medium",
608
+ isFullWidth: false,
609
+ isDisabled: false,
610
+ },
489
611
  });
490
- Text.displayName = "Text";
612
+ const ButtonGroup = React.forwardRef(({ className, variant = "attached", orientation = "horizontal", size = "medium", isDisabled = false, isFullWidth = false, value, onChange, children, ...props }, ref) => {
613
+ const childrenArray = React.Children.toArray(children);
614
+ const isControlled = value !== undefined && onChange !== undefined;
615
+ return (jsx("div", { ref: ref, className: cn(buttonGroupVariants({
616
+ variant,
617
+ orientation,
618
+ size,
619
+ isDisabled,
620
+ isFullWidth,
621
+ }), className), role: "group", ...props, children: childrenArray.map((child, index) => {
622
+ if (!React.isValidElement(child)) {
623
+ return child;
624
+ }
625
+ const isFirst = index === 0;
626
+ const isLast = index === childrenArray.length - 1;
627
+ const isMiddle = !isFirst && !isLast;
628
+ // Get value from child props for controlled mode
629
+ const childValue = child.props.value;
630
+ const isSelected = isControlled && childValue === value;
631
+ // Build classes to apply border radius removal and borders
632
+ let groupClasses = "";
633
+ // Only apply connected styling for "attached" variant
634
+ if (variant === "attached") {
635
+ if (orientation === "horizontal") {
636
+ if (isFirst) {
637
+ groupClasses = "rounded-r-none border-r-0";
638
+ }
639
+ else if (isLast) {
640
+ groupClasses = "rounded-l-none";
641
+ }
642
+ else if (isMiddle) {
643
+ groupClasses = "rounded-none border-r-0";
644
+ }
645
+ }
646
+ else {
647
+ // vertical
648
+ if (isFirst) {
649
+ groupClasses = "rounded-b-none border-b-0";
650
+ }
651
+ else if (isLast) {
652
+ groupClasses = "rounded-t-none";
653
+ }
654
+ else if (isMiddle) {
655
+ groupClasses = "rounded-none border-b-0";
656
+ }
657
+ }
658
+ }
659
+ // Determine the variant to use
660
+ const childVariant = child.props.variant;
661
+ const hasExplicitVariant = childVariant !== undefined;
662
+ // For controlled mode with explicit variant, maintain the variant
663
+ // and add styling classes for selected state
664
+ let finalVariant = childVariant;
665
+ let selectedStateClasses = "";
666
+ if (isControlled) {
667
+ if (hasExplicitVariant) {
668
+ // Keep the child's variant and add selected state styling
669
+ if (isSelected && childVariant === "tertiary") {
670
+ selectedStateClasses = "bg-action-fill-primary-faded";
671
+ }
672
+ else if (isSelected && childVariant === "secondary") {
673
+ selectedStateClasses =
674
+ "bg-action-fill-primary-faded border-action-outline-primary-faded";
675
+ }
676
+ }
677
+ else {
678
+ // No explicit variant: use primary for selected, secondary for unselected
679
+ finalVariant = isSelected ? "primary" : "secondary";
680
+ }
681
+ }
682
+ // Clone child and add our classes and handlers
683
+ return React.cloneElement(child, {
684
+ ...child.props,
685
+ className: cn(child.props.className, groupClasses, isFullWidth && "flex-1",
686
+ // For attached variant, ensure proper layering
687
+ variant === "attached" && "relative", variant === "attached" && !isSelected && "hover:z-10 focus:z-10", variant === "attached" && isSelected && "z-20",
688
+ // Apply selected state classes for explicit variants
689
+ selectedStateClasses),
690
+ disabled: isDisabled || child.props.disabled,
691
+ size: size || child.props.size,
692
+ // If controlled and has value, handle click
693
+ onClick: isControlled && childValue !== undefined
694
+ ? (e) => {
695
+ child.props.onClick?.(e);
696
+ if (!isDisabled && !child.props.disabled) {
697
+ onChange(childValue);
698
+ }
699
+ }
700
+ : child.props.onClick,
701
+ variant: finalVariant,
702
+ });
703
+ }) }));
704
+ });
705
+ ButtonGroup.displayName = "ButtonGroup";
491
706
 
492
707
  const FormFooter = React.forwardRef(({ helperText, trailingText, validationState = "default", size = "medium", isDisabled = false, className, helperTextClassName, trailingTextClassName, }, ref) => {
493
708
  // Size-based configurations
@@ -562,6 +777,9 @@ const iconRegistry = {
562
777
  // Alias: check points to the same icon as tick
563
778
  check: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
564
779
  <path d="M10.364 15.1924L19.5564 6L20.9706 7.41421L10.364 18.0208L4 11.6569L5.41422 10.2427L10.364 15.1924Z" fill="#081416"/>
780
+ </svg>`,
781
+ add: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
782
+ <path d="M12.9 11.0999L21 11.0997V12.8997L12.9 12.8999V21H11.1V12.8999L3.00004 12.9001L3 11.1001L11.1 11.0999L11.0999 3.00001L12.8999 3L12.9 11.0999Z" fill="#081416"/>
565
783
  </svg>`,
566
784
  };
567
785
  const Icon = ({ name, size = 24, className = "", style = {}, ...props }) => {
@@ -579,17 +797,17 @@ const Icon = ({ name, size = 24, className = "", style = {}, ...props }) => {
579
797
  console.error(`Invalid SVG content for icon "${String(name)}"`);
580
798
  return null;
581
799
  }
582
- // Extract viewBox attribute
800
+ // Get the viewBox for proper scaling
583
801
  const viewBox = svgElement.getAttribute("viewBox") || "0 0 24 24";
584
- let innerHTML = svgElement.innerHTML;
585
- // Replace hardcoded fill and stroke colors with currentColor
586
- // This allows the icon color to be controlled via CSS color property
587
- innerHTML = innerHTML
802
+ // Get all SVG content as string and replace hardcoded colors with currentColor
803
+ let innerSVG = svgElement.innerHTML;
804
+ // Replace common hardcoded colors with currentColor
805
+ // This allows the icon to inherit text color from parent
806
+ innerSVG = innerSVG
588
807
  .replace(/fill="[^"]*"/g, 'fill="currentColor"')
589
808
  .replace(/stroke="[^"]*"/g, 'stroke="currentColor"');
590
- return (jsx("svg", { width: size, height: size, viewBox: viewBox, fill: "none", xmlns: "http://www.w3.org/2000/svg", className: className, style: style, ...props, dangerouslySetInnerHTML: { __html: innerHTML } }));
809
+ return (jsx("svg", { width: size, height: size, viewBox: viewBox, className: className, style: style, xmlns: "http://www.w3.org/2000/svg", ...props, dangerouslySetInnerHTML: { __html: innerSVG } }));
591
810
  };
592
- Icon.displayName = "Icon";
593
811
  /**
594
812
  * Get all available icon names from the registry
595
813
  * @returns Array of registered icon names
@@ -1203,7 +1421,7 @@ const Link = React.forwardRef(({ className, type = "anchor", color = "primary",
1203
1421
  });
1204
1422
  Link.displayName = "Link";
1205
1423
 
1206
- const DropdownMenu = React.forwardRef(({ items = [], sectionHeading, isLoading = false, isEmpty = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText = "Primary", secondaryButtonText = "Secondary", onPrimaryClick, onSecondaryClick, showChevron = false, emptyIcon, disableFooter = false, onClose, focusedIndex = -1, className, width = "auto", }, ref) => {
1424
+ const DropdownMenu = React.forwardRef(({ items = [], sectionHeading, isLoading = false, isEmpty = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText = "Primary", secondaryButtonText = "Secondary", onPrimaryClick, onSecondaryClick, showChevron = false, emptyIcon, disableFooter = false, footerLayout = "horizontal", onClose, focusedIndex = -1, className, width = "auto", }, ref) => {
1207
1425
  const renderContent = () => {
1208
1426
  if (isLoading) {
1209
1427
  return (jsx("div", { className: "flex flex-col items-center justify-center py-12 px-6", children: jsx(Loader2, { className: "w-12 h-12 text-action-ink-primary-normal mb-4 animate-spin" }) }));
@@ -1217,10 +1435,12 @@ const DropdownMenu = React.forwardRef(({ items = [], sectionHeading, isLoading =
1217
1435
  }, containerClassName: cn(index === focusedIndex && "bg-action-fill-primary-faded") }, item.id))) })] }));
1218
1436
  };
1219
1437
  const widthClass = width === "full" ? "w-full" : width === "auto" ? "w-auto" : "";
1220
- return (jsxs("div", { ref: ref, className: cn("bg-surface-fill-primary-normal rounded-large overflow-hidden", widthClass, className), style: {
1438
+ return (jsxs("div", { ref: ref, className: cn("bg-white rounded-large overflow-hidden", widthClass, className), style: {
1221
1439
  boxShadow: "0 1px 2px rgba(25, 25, 30, 0.1), 0 2px 6px rgba(25, 25, 30, 0.06)",
1222
1440
  ...(width !== "full" && width !== "auto" ? { width } : {}),
1223
- }, children: [renderContent(), !disableFooter && (jsxs("div", { className: "flex flex-col", children: [jsx(Divider, { thickness: "thin", variant: "muted" }), jsxs("div", { className: "flex items-center gap-3 p-4", children: [jsx(Button, { variant: "secondary", color: "primary", size: "medium", isFullWidth: true, onClick: onSecondaryClick, children: secondaryButtonText }), jsx(Button, { variant: "primary", color: "primary", size: "medium", isFullWidth: true, onClick: onPrimaryClick, children: primaryButtonText })] })] }))] }));
1441
+ }, children: [renderContent(), !disableFooter && (jsxs("div", { className: "flex flex-col", children: [jsx(Divider, { thickness: "thin", variant: "muted" }), jsxs("div", { className: cn("flex gap-3 p-4", footerLayout === "vertical"
1442
+ ? "flex-col"
1443
+ : "items-center flex-row"), children: [jsx(Button, { variant: "secondary", color: "primary", size: "medium", isFullWidth: true, onClick: onSecondaryClick, children: secondaryButtonText }), jsx(Button, { variant: "primary", color: "primary", size: "medium", isFullWidth: true, onClick: onPrimaryClick, children: primaryButtonText })] })] }))] }));
1224
1444
  });
1225
1445
  DropdownMenu.displayName = "DropdownMenu";
1226
1446
 
@@ -1537,10 +1757,370 @@ const FormHeader = React.forwardRef(({ label, size = "medium", isOptional = fals
1537
1757
  },
1538
1758
  };
1539
1759
  const config = sizeConfig[size];
1540
- return (jsxs("div", { ref: ref, className: cn("flex items-center justify-between px-1", config.gap, className), children: [jsxs("div", { className: cn("flex items-center", config.gap), children: [jsxs("label", { htmlFor: htmlFor, className: cn("flex items-center", labelClassName), children: [jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "semibold", color: "subtle", children: label }), isRequired && (jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "semibold", className: "text-feedback-ink-negative-subtle ml-0.5", children: "*" })), isOptional && (jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "regular", className: "text-surface-ink-neutral-muted ml-1", children: "(optional)" }))] }), infoDescription && (jsx(Tooltip, { description: infoDescription, heading: infoHeading, children: jsxs("svg", { width: config.iconSize, height: config.iconSize, viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "text-surface-ink-neutral-muted cursor-help", children: [jsx("circle", { cx: "7", cy: "7", r: "6", stroke: "currentColor", strokeWidth: "1" }), jsx("path", { d: "M7 6V10M7 4.5V4", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round" })] }) }))] }), linkText && (jsx("a", { href: linkHref, onClick: onLinkClick, className: cn("text-surface-ink-primary-normal hover:text-surface-ink-primary-hover transition-colors cursor-pointer font-display font-semibold leading-tight shrink-0", size === "small" && "text-xs", size === "medium" && "text-xs", size === "large" && "text-sm", linkClassName), children: linkText }))] }));
1760
+ return (jsxs("div", { ref: ref, className: cn("flex items-center justify-between px-1", config.gap, className), children: [jsxs("div", { className: cn("flex items-center", config.gap), children: [jsxs("label", { htmlFor: htmlFor, className: cn("flex items-center", labelClassName), children: [jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "semibold", color: "subtle", children: label }), isRequired && (jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "semibold", color: "negative", className: "ml-0.5", children: "*" })), isOptional && (jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "regular", className: "text-surface-ink-neutral-muted italic ml-1", children: "(optional)" }))] }), infoDescription && (jsx(Tooltip, { description: infoDescription, heading: infoHeading, children: jsxs("svg", { width: config.iconSize, height: config.iconSize, viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "text-surface-ink-neutral-muted", children: [jsx("circle", { cx: "7", cy: "7", r: "6", stroke: "currentColor", strokeWidth: "1" }), jsx("path", { d: "M7 6V10M7 4.5V4", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round" })] }) }))] }), linkText && (jsx("a", { href: linkHref, onClick: onLinkClick, className: cn("text-surface-ink-primary-normal hover:text-surface-ink-primary-hover transition-colors cursor-pointer font-display font-semibold leading-tight shrink-0", size === "small" && "text-xs", size === "medium" && "text-xs", size === "large" && "text-sm", linkClassName), children: linkText }))] }));
1541
1761
  });
1542
1762
  FormHeader.displayName = "FormHeader";
1543
1763
 
1764
+ const Modal = React.forwardRef(({ isOpen, onClose, title, description, footer, children, size = "medium", showCloseButton = true, closeOnOverlayClick = true, closeOnEscape = true, className, contentClassName, headerClassName, bodyClassName, footerClassName, overlayClassName, ariaLabel, ariaDescribedBy, }, ref) => {
1765
+ const modalRef = React.useRef(null);
1766
+ const contentRef = ref || modalRef;
1767
+ // Size configurations
1768
+ const sizeConfig = {
1769
+ small: "max-w-sm",
1770
+ medium: "max-w-md",
1771
+ large: "max-w-lg",
1772
+ xlarge: "max-w-2xl",
1773
+ };
1774
+ // Handle escape key
1775
+ React.useEffect(() => {
1776
+ if (!isOpen || !closeOnEscape)
1777
+ return;
1778
+ const handleEscape = (e) => {
1779
+ if (e.key === "Escape") {
1780
+ onClose();
1781
+ }
1782
+ };
1783
+ document.addEventListener("keydown", handleEscape);
1784
+ return () => document.removeEventListener("keydown", handleEscape);
1785
+ }, [isOpen, closeOnEscape, onClose]);
1786
+ // Prevent body scroll when modal is open
1787
+ React.useEffect(() => {
1788
+ if (isOpen) {
1789
+ document.body.style.overflow = "hidden";
1790
+ }
1791
+ else {
1792
+ document.body.style.overflow = "";
1793
+ }
1794
+ return () => {
1795
+ document.body.style.overflow = "";
1796
+ };
1797
+ }, [isOpen]);
1798
+ // Handle overlay click
1799
+ const handleOverlayClick = (e) => {
1800
+ if (closeOnOverlayClick && e.target === e.currentTarget) {
1801
+ onClose();
1802
+ }
1803
+ };
1804
+ // Don't render if not open
1805
+ if (!isOpen)
1806
+ return null;
1807
+ const hasHeader = title || description;
1808
+ return (jsxs("div", { className: cn("fixed inset-0 z-50 flex items-center justify-center p-4", className), role: "dialog", "aria-modal": "true", "aria-label": ariaLabel || title, "aria-describedby": ariaDescribedBy, children: [jsx("div", { className: cn("absolute inset-0 bg-black/50 backdrop-blur-sm transition-opacity", overlayClassName), onClick: handleOverlayClick, "aria-hidden": "true" }), jsxs("div", { ref: contentRef, className: cn("relative w-full bg-white rounded-large shadow-xl transition-all", "flex flex-col max-h-[90vh]", sizeConfig[size], contentClassName), children: [hasHeader && (jsxs("div", { className: cn("flex items-start justify-between gap-4 px-6 pt-6", !description && "pb-4", description && "pb-2", headerClassName), children: [jsxs("div", { className: "flex-1", children: [title && (jsx(Text, { as: "h2", variant: "body", size: "large", weight: "semibold", color: "default", children: title })), description && (jsx(Text, { as: "p", variant: "body", size: "small", weight: "regular", color: "subtle", className: "mt-1", children: description }))] }), showCloseButton && (jsx("button", { type: "button", onClick: onClose, className: cn("shrink-0 rounded-medium p-1.5 transition-colors", "text-surface-ink-neutral-muted hover:text-surface-ink-neutral-default", "hover:bg-surface-fill-neutral-faded focus:outline-none focus:ring-2", "focus:ring-action-outline-primary-default focus:ring-offset-2"), "aria-label": "Close modal", children: jsx(X, { className: "h-5 w-5" }) }))] })), !hasHeader && showCloseButton && (jsx("div", { className: "absolute top-4 right-4 z-10", children: jsx("button", { type: "button", onClick: onClose, className: cn("shrink-0 rounded-medium p-1.5 transition-colors", "text-surface-ink-neutral-muted hover:text-surface-ink-neutral-default", "hover:bg-surface-fill-neutral-faded focus:outline-none focus:ring-2", "focus:ring-action-outline-primary-default focus:ring-offset-2"), "aria-label": "Close modal", children: jsx(X, { className: "h-5 w-5" }) }) })), jsx("div", { className: cn("flex-1 overflow-y-auto px-6", hasHeader ? "py-4" : "pt-6 pb-4", !footer && "pb-6", bodyClassName), children: children }), footer && (jsxs("div", { className: "flex flex-col", children: [jsx(Divider, { thickness: "thin", variant: "muted" }), jsx("div", { className: cn("flex items-center justify-end gap-3 px-6 py-4", footerClassName), children: footer })] }))] })] }));
1809
+ });
1810
+ Modal.displayName = "Modal";
1811
+
1812
+ const selectVariants = cva("relative flex items-center gap-2 border rounded-medium transition-all font-display font-size-100 leading-100", {
1813
+ variants: {
1814
+ size: {
1815
+ small: "h-[28px] px-3 text-xs gap-2",
1816
+ medium: "h-[36px] px-4 text-sm gap-2",
1817
+ large: "h-[44px] px-5 text-base gap-3",
1818
+ },
1819
+ validationState: {
1820
+ none: `
1821
+ border-action-outline-neutral-faded
1822
+ hover:border-action-outline-primary-hover
1823
+ focus-within:border-action-outline-primary-hover
1824
+ focus-within:ring-2
1825
+ ring-action-outline-primary-faded-hover`,
1826
+ positive: `
1827
+ border-action-outline-positive-default
1828
+ focus-within:border-action-outline-positive-hover
1829
+ focus-within:ring-2
1830
+ ring-action-outline-positive-faded-hover`,
1831
+ negative: `border-action-outline-negative-default
1832
+ focus-within:border-action-outline-negative-hover
1833
+ focus-within:ring-2
1834
+ ring-action-outline-negative-faded-hover`,
1835
+ },
1836
+ isDisabled: {
1837
+ true: `
1838
+ border-[var(--border-width-thinner)]
1839
+ hover:border-action-outline-neutral-disabled
1840
+ border-action-outline-neutral-disabled
1841
+ bg-surface-fill-neutral-intense cursor-not-allowed opacity-60`,
1842
+ false: "bg-surface-fill-neutral-intense",
1843
+ },
1844
+ },
1845
+ defaultVariants: {
1846
+ size: "medium",
1847
+ validationState: "none",
1848
+ isDisabled: false,
1849
+ },
1850
+ });
1851
+ const Select = React.forwardRef(({ className, options = [], value: controlledValue, defaultValue, onChange, placeholder = "Select an option", label, helperText, errorText, successText, validationState = "none", isDisabled = false, isRequired = false, isOptional = false, isLoading = false, size = "medium", prefix, suffix, showClearButton = false, onClear, containerClassName, labelClassName, triggerClassName, menuClassName, menuWidth = "full", sectionHeading, emptyTitle = "No options available", emptyDescription = "There are no options to select from.", emptyIcon, infoHeading, infoDescription, linkText, linkHref, onLinkClick, ...props }, ref) => {
1852
+ const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);
1853
+ const [isOpen, setIsOpen] = React.useState(false);
1854
+ const selectRef = React.useRef(null);
1855
+ const value = controlledValue !== undefined ? controlledValue : uncontrolledValue;
1856
+ // Find the selected option
1857
+ const selectedOption = options.find((opt) => opt.value === value);
1858
+ const hasValue = value !== undefined && value !== "";
1859
+ // Determine which helper text to show
1860
+ const displayHelperText = errorText || successText || helperText;
1861
+ const currentValidationState = errorText
1862
+ ? "negative"
1863
+ : successText
1864
+ ? "positive"
1865
+ : validationState;
1866
+ const handleOpenChange = (newOpen) => {
1867
+ if (!isDisabled && !isLoading) {
1868
+ setIsOpen(newOpen);
1869
+ }
1870
+ };
1871
+ const toggleOpen = () => {
1872
+ handleOpenChange(!isOpen);
1873
+ };
1874
+ const handleSelect = (option) => {
1875
+ if (controlledValue === undefined) {
1876
+ setUncontrolledValue(option.value);
1877
+ }
1878
+ onChange?.(option.value, option);
1879
+ setIsOpen(false);
1880
+ };
1881
+ const handleClear = (e) => {
1882
+ e.stopPropagation();
1883
+ if (onClear) {
1884
+ onClear();
1885
+ }
1886
+ else {
1887
+ if (controlledValue === undefined) {
1888
+ setUncontrolledValue(undefined);
1889
+ }
1890
+ onChange?.("", {});
1891
+ }
1892
+ };
1893
+ // Close dropdown when clicking outside
1894
+ React.useEffect(() => {
1895
+ const handleClickOutside = (event) => {
1896
+ if (selectRef.current &&
1897
+ !selectRef.current.contains(event.target)) {
1898
+ handleOpenChange(false);
1899
+ }
1900
+ };
1901
+ if (isOpen) {
1902
+ document.addEventListener("mousedown", handleClickOutside);
1903
+ return () => {
1904
+ document.removeEventListener("mousedown", handleClickOutside);
1905
+ };
1906
+ }
1907
+ }, [isOpen]);
1908
+ // Close on escape key
1909
+ React.useEffect(() => {
1910
+ const handleEscape = (event) => {
1911
+ if (event.key === "Escape") {
1912
+ handleOpenChange(false);
1913
+ }
1914
+ };
1915
+ if (isOpen) {
1916
+ document.addEventListener("keydown", handleEscape);
1917
+ return () => {
1918
+ document.removeEventListener("keydown", handleEscape);
1919
+ };
1920
+ }
1921
+ }, [isOpen]);
1922
+ // Handle keyboard navigation
1923
+ React.useEffect(() => {
1924
+ const handleKeyDown = (event) => {
1925
+ if (isDisabled || isLoading)
1926
+ return;
1927
+ if (!isOpen && (event.key === "Enter" || event.key === " ")) {
1928
+ event.preventDefault();
1929
+ setIsOpen(true);
1930
+ return;
1931
+ }
1932
+ if (isOpen) {
1933
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
1934
+ event.preventDefault();
1935
+ const currentIndex = options.findIndex((opt) => opt.value === value);
1936
+ const nextIndex = event.key === "ArrowDown"
1937
+ ? Math.min(currentIndex + 1, options.length - 1)
1938
+ : Math.max(currentIndex - 1, 0);
1939
+ if (options[nextIndex] && !options[nextIndex].isDisabled) {
1940
+ handleSelect(options[nextIndex]);
1941
+ }
1942
+ }
1943
+ }
1944
+ };
1945
+ if (selectRef.current) {
1946
+ selectRef.current.addEventListener("keydown", handleKeyDown);
1947
+ return () => {
1948
+ selectRef.current?.removeEventListener("keydown", handleKeyDown);
1949
+ };
1950
+ }
1951
+ }, [isOpen, value, options, isDisabled, isLoading]);
1952
+ // Transform options to dropdown menu items
1953
+ const menuItems = options.map((option) => ({
1954
+ ...option,
1955
+ onClick: () => handleSelect(option),
1956
+ }));
1957
+ const widthStyle = menuWidth === "full" ? "100%" : menuWidth === "auto" ? "auto" : menuWidth;
1958
+ const sizeConfig = {
1959
+ small: {
1960
+ gap: "gap-2",
1961
+ },
1962
+ medium: {
1963
+ gap: "gap-2",
1964
+ },
1965
+ large: {
1966
+ gap: "gap-3",
1967
+ },
1968
+ };
1969
+ return (jsxs("div", { className: cn("w-full flex flex-col", sizeConfig[size].gap, containerClassName), children: [label && (jsx(FormHeader, { label: label, size: size, isRequired: isRequired, isOptional: isOptional, infoHeading: infoHeading, infoDescription: infoDescription, linkText: linkText, linkHref: linkHref, onLinkClick: onLinkClick, htmlFor: props.id, className: "mb-2", labelClassName: labelClassName })), jsxs("div", { ref: selectRef, className: cn(selectVariants({
1970
+ size,
1971
+ validationState: currentValidationState,
1972
+ isDisabled,
1973
+ }), "relative w-full cursor-pointer", className), onClick: !isDisabled && !isLoading ? toggleOpen : undefined, role: "combobox", "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-disabled": isDisabled, ...props, children: [prefix && (jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
1974
+ ? "text-surface-ink-neutral-disabled"
1975
+ : currentValidationState === "positive"
1976
+ ? "text-feedback-ink-positive-intense"
1977
+ : currentValidationState === "negative"
1978
+ ? "text-feedback-ink-negative-subtle"
1979
+ : "text-surface-ink-neutral-muted"), children: prefix })), jsx("span", { className: cn("flex-1 text-left truncate", !selectedOption && "text-surface-ink-neutral-muted", isDisabled && "text-surface-ink-neutral-disabled"), children: isLoading
1980
+ ? "Loading..."
1981
+ : selectedOption?.label || selectedOption?.title || placeholder }), showClearButton && hasValue && !isDisabled && !isLoading && (jsx("button", { type: "button", onClick: handleClear, className: "shrink-0 flex items-center justify-center text-surface-ink-neutral-muted hover:text-surface-ink-neutral-normal transition-colors", tabIndex: -1, children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) })), suffix && !showClearButton && (jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
1982
+ ? "text-surface-ink-neutral-disabled"
1983
+ : currentValidationState === "positive"
1984
+ ? "text-feedback-ink-positive-intense"
1985
+ : currentValidationState === "negative"
1986
+ ? "text-feedback-ink-negative-subtle"
1987
+ : "text-surface-ink-neutral-muted"), children: suffix })), jsx(ChevronDown, { className: cn("shrink-0 w-4 h-4 transition-transform", isDisabled
1988
+ ? "text-surface-ink-neutral-disabled"
1989
+ : currentValidationState === "positive"
1990
+ ? "text-feedback-ink-positive-intense"
1991
+ : currentValidationState === "negative"
1992
+ ? "text-feedback-ink-negative-subtle"
1993
+ : "text-surface-ink-neutral-muted", isOpen && "transform rotate-180") }), isOpen && !isDisabled && !isLoading && (jsx("div", { className: "absolute z-50 left-0 right-0 top-full mt-1", children: jsx(DropdownMenu, { ref: ref, items: menuItems, sectionHeading: sectionHeading, isEmpty: options.length === 0, emptyTitle: emptyTitle, emptyDescription: emptyDescription, emptyIcon: emptyIcon, disableFooter: true, onClose: () => handleOpenChange(false), className: menuClassName, width: widthStyle }) }))] }), jsx(FormFooter, { helperText: displayHelperText, validationState: currentValidationState === "none"
1994
+ ? "default"
1995
+ : currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1" })] }));
1996
+ });
1997
+ Select.displayName = "Select";
1998
+
1999
+ const paginationVariants = cva("flex items-center gap-4 font-display text-body-medium-medium", {
2000
+ variants: {
2001
+ size: {
2002
+ small: "text-xs gap-2",
2003
+ medium: "text-sm gap-4",
2004
+ large: "text-base gap-5",
2005
+ },
2006
+ },
2007
+ defaultVariants: {
2008
+ size: "medium",
2009
+ },
2010
+ });
2011
+ const Pagination = React.forwardRef(({ className, currentPage: controlledCurrentPage, totalPages, rowsPerPage: controlledRowsPerPage, rowsPerPageOptions = [5, 10, 15, 20, 25, 50, 100], showRowsPerPage = true, onPageChange, onRowsPerPageChange, size = "medium", isDisabled = false, rowsPerPageLabel = "Row per page", ofLabel = "of", prevLabel = "Prev", nextLabel = "Next", showPrevNext = true, showPageJumper = true, showPageNumber = true, pageStatus, maxPageButtons = 5, ...props }, ref) => {
2012
+ const [uncontrolledCurrentPage, setUncontrolledCurrentPage] = React.useState(1);
2013
+ const [uncontrolledRowsPerPage, setUncontrolledRowsPerPage] = React.useState(rowsPerPageOptions[0] || 10);
2014
+ const currentPage = controlledCurrentPage !== undefined
2015
+ ? controlledCurrentPage
2016
+ : uncontrolledCurrentPage;
2017
+ const rowsPerPage = controlledRowsPerPage !== undefined
2018
+ ? controlledRowsPerPage
2019
+ : uncontrolledRowsPerPage;
2020
+ // Generate rows per page options
2021
+ const rowsPerPageSelectOptions = rowsPerPageOptions.map((value) => {
2022
+ const valueStr = String(value);
2023
+ // Pad with leading zero if needed (manual implementation for compatibility)
2024
+ const label = valueStr.length < 2 ? "0" + valueStr : valueStr;
2025
+ return {
2026
+ id: `rows-${valueStr}`,
2027
+ value: valueStr,
2028
+ label: label,
2029
+ title: valueStr,
2030
+ };
2031
+ });
2032
+ // Generate page options
2033
+ const pageOptions = Array.from({ length: totalPages }, (_, i) => {
2034
+ const pageNum = i + 1;
2035
+ const pageStr = String(pageNum);
2036
+ return {
2037
+ id: `page-${pageStr}`,
2038
+ value: pageStr,
2039
+ label: pageStr,
2040
+ title: `Page ${pageNum}`,
2041
+ };
2042
+ });
2043
+ const handlePageChange = (newPage) => {
2044
+ if (newPage < 1 || newPage > totalPages)
2045
+ return;
2046
+ if (controlledCurrentPage === undefined) {
2047
+ setUncontrolledCurrentPage(newPage);
2048
+ }
2049
+ onPageChange?.(newPage);
2050
+ };
2051
+ const handleRowsPerPageChange = (value) => {
2052
+ const newRowsPerPage = typeof value === "string" ? parseInt(value) : value;
2053
+ if (controlledRowsPerPage === undefined) {
2054
+ setUncontrolledRowsPerPage(newRowsPerPage);
2055
+ }
2056
+ onRowsPerPageChange?.(newRowsPerPage);
2057
+ // Reset to first page when rows per page changes
2058
+ handlePageChange(1);
2059
+ };
2060
+ const handlePrevPage = () => {
2061
+ handlePageChange(currentPage - 1);
2062
+ };
2063
+ const handleNextPage = () => {
2064
+ handlePageChange(currentPage + 1);
2065
+ };
2066
+ const isPrevDisabled = currentPage <= 1 || isDisabled;
2067
+ const isNextDisabled = currentPage >= totalPages || isDisabled;
2068
+ const selectSize = size === "small" ? "small" : size === "large" ? "large" : "medium";
2069
+ // Map pagination size to button size
2070
+ const buttonSize = size === "small" ? "xsmall" : size === "large" ? "large" : "small";
2071
+ // Generate page numbers to display
2072
+ const getPageNumbers = () => {
2073
+ if (totalPages <= maxPageButtons) {
2074
+ // Show all pages if total is less than max
2075
+ return Array.from({ length: totalPages }, (_, i) => i + 1);
2076
+ }
2077
+ // Determine page status if not provided
2078
+ const effectivePageStatus = pageStatus ||
2079
+ (currentPage <= 2
2080
+ ? "first"
2081
+ : currentPage >= totalPages - 1
2082
+ ? "last"
2083
+ : "middle");
2084
+ if (effectivePageStatus === "first") {
2085
+ // Show first pages: 1, 2, 3, 4, 5
2086
+ return Array.from({ length: Math.min(maxPageButtons, totalPages) }, (_, i) => i + 1);
2087
+ }
2088
+ else if (effectivePageStatus === "last") {
2089
+ // Show last pages
2090
+ const start = totalPages - maxPageButtons + 1;
2091
+ return Array.from({ length: maxPageButtons }, (_, i) => start + i);
2092
+ }
2093
+ else if (effectivePageStatus === "middle") {
2094
+ // Show pages around current page
2095
+ const halfMax = Math.floor(maxPageButtons / 2);
2096
+ let start = currentPage - halfMax;
2097
+ let end = currentPage + halfMax;
2098
+ // Adjust if at boundaries
2099
+ if (start < 1) {
2100
+ end += 1 - start;
2101
+ start = 1;
2102
+ }
2103
+ if (end > totalPages) {
2104
+ start -= end - totalPages;
2105
+ end = totalPages;
2106
+ }
2107
+ start = Math.max(1, start);
2108
+ end = Math.min(totalPages, end);
2109
+ return Array.from({ length: end - start + 1 }, (_, i) => start + i);
2110
+ }
2111
+ // pageStatus === "none" - don't show any page numbers
2112
+ return [];
2113
+ };
2114
+ const pageNumbers = getPageNumbers();
2115
+ return (jsxs("div", { ref: ref, className: cn(paginationVariants({ size }), className), ...props, children: [showRowsPerPage && (jsxs("div", { className: "flex items-center gap-3", children: [jsx("span", { className: "text-surface-ink-neutral-muted whitespace-nowrap", children: rowsPerPageLabel }), jsx("div", { className: "w-[80px]", children: jsx(Select, { value: rowsPerPage.toString(), options: rowsPerPageSelectOptions, onChange: handleRowsPerPageChange, size: selectSize, isDisabled: isDisabled, menuWidth: "auto" }) })] })), jsxs("div", { className: "flex items-center gap-3 ml-auto", children: [showPrevNext && (jsx(Button, { variant: "tertiary", color: "neutral", size: buttonSize, onClick: handlePrevPage, isDisabled: isPrevDisabled, leadingIcon: jsx(ChevronLeft, { className: "w-4 h-4" }), "aria-label": "Previous page", children: prevLabel })), showPageJumper ? (
2116
+ // Show page dropdown selector
2117
+ jsxs("div", { className: "flex items-center gap-3", children: [jsx("div", { className: "w-[80px]", children: jsx(Select, { value: currentPage.toString(), options: pageOptions, onChange: (value) => handlePageChange(typeof value === "string" ? parseInt(value) : value), size: selectSize, isDisabled: isDisabled, menuWidth: "auto" }) }), jsxs("span", { className: "text-surface-ink-neutral-muted whitespace-nowrap", children: [ofLabel, " ", totalPages] })] })) : (
2118
+ // Show numbered page buttons
2119
+ showPageNumber &&
2120
+ pageNumbers.length > 0 && (jsx(ButtonGroup, { variant: "separated", size: buttonSize, isDisabled: isDisabled, value: currentPage, onChange: (value) => handlePageChange(value), children: pageNumbers.map((pageNum) => (jsx(Button, { value: pageNum, variant: "tertiary", color: "primary", "aria-label": `Page ${pageNum}`, "aria-current": pageNum === currentPage ? "page" : undefined, children: pageNum }, pageNum))) }))), showPrevNext && (jsx(Button, { variant: "tertiary", color: "neutral", size: buttonSize, onClick: handleNextPage, isDisabled: isNextDisabled, trailingIcon: jsx(ChevronRight, { className: "w-4 h-4" }), "aria-label": "Next page", children: nextLabel }))] })] }));
2121
+ });
2122
+ Pagination.displayName = "Pagination";
2123
+
1544
2124
  const radioVariants = cva("relative inline-flex items-center justify-center shrink-0 border transition-all cursor-pointer rounded-full", {
1545
2125
  variants: {
1546
2126
  size: {
@@ -1815,13 +2395,30 @@ const defaultFilter = (item, query) => {
1815
2395
  return (item.title.toLowerCase().includes(searchQuery) ||
1816
2396
  (item.description?.toLowerCase().includes(searchQuery) ?? false));
1817
2397
  };
1818
- const SearchableDropdown = React.forwardRef(({ className, items = [], sectionHeading, isLoading = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText = "Primary", secondaryButtonText = "Secondary", onPrimaryClick, onSecondaryClick, dropdownWidth = "full", showChevron = false, emptyIcon, disableFooter = false, onSearchChange, onItemSelect, filterFunction = defaultFilter, searchValue: controlledSearchValue, defaultSearchValue = "", dropdownClassName, minSearchLength = 0, showOnFocus = true, containerClassName, ...textFieldProps }, ref) => {
2398
+ const SearchableDropdown = React.forwardRef(({ className, items = [], sectionHeading, isLoading = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText = "Primary", secondaryButtonText = "Secondary", onPrimaryClick, onSecondaryClick, dropdownWidth = "full", showChevron = false, emptyIcon, disableFooter = false, footerLayout = "horizontal", onSearchChange, onItemSelect, filterFunction = defaultFilter, searchValue: controlledSearchValue, defaultSearchValue = "", dropdownClassName, minSearchLength = 0, showOnFocus = true, containerClassName, ...textFieldProps }, ref) => {
1819
2399
  const [uncontrolledSearchValue, setUncontrolledSearchValue] = React.useState(defaultSearchValue);
1820
2400
  const [isOpen, setIsOpen] = React.useState(false);
1821
2401
  const [focusedIndex, setFocusedIndex] = React.useState(-1);
1822
2402
  const dropdownRef = React.useRef(null);
1823
2403
  const inputRef = React.useRef(null);
2404
+ const menuRef = React.useRef(null);
2405
+ const [position, setPosition] = React.useState({
2406
+ top: 0,
2407
+ left: 0,
2408
+ width: 0,
2409
+ });
1824
2410
  React.useImperativeHandle(ref, () => inputRef.current);
2411
+ // Update position when dropdown opens or window resizes
2412
+ React.useEffect(() => {
2413
+ if (isOpen && dropdownRef.current) {
2414
+ const rect = dropdownRef.current.getBoundingClientRect();
2415
+ setPosition({
2416
+ top: rect.bottom + window.scrollY,
2417
+ left: rect.left + window.scrollX,
2418
+ width: rect.width,
2419
+ });
2420
+ }
2421
+ }, [isOpen]);
1825
2422
  const searchValue = controlledSearchValue !== undefined
1826
2423
  ? controlledSearchValue
1827
2424
  : uncontrolledSearchValue;
@@ -1847,7 +2444,7 @@ const SearchableDropdown = React.forwardRef(({ className, items = [], sectionHea
1847
2444
  const handleItemSelect = (item) => {
1848
2445
  onItemSelect?.(item);
1849
2446
  if (controlledSearchValue === undefined) {
1850
- setUncontrolledSearchValue(item.value || item.title);
2447
+ setUncontrolledSearchValue(item.title);
1851
2448
  }
1852
2449
  setIsOpen(false);
1853
2450
  inputRef.current?.focus();
@@ -1862,7 +2459,9 @@ const SearchableDropdown = React.forwardRef(({ className, items = [], sectionHea
1862
2459
  React.useEffect(() => {
1863
2460
  const handleClickOutside = (event) => {
1864
2461
  if (dropdownRef.current &&
1865
- !dropdownRef.current.contains(event.target)) {
2462
+ !dropdownRef.current.contains(event.target) &&
2463
+ menuRef.current &&
2464
+ !menuRef.current.contains(event.target)) {
1866
2465
  setIsOpen(false);
1867
2466
  }
1868
2467
  };
@@ -1910,7 +2509,16 @@ const SearchableDropdown = React.forwardRef(({ className, items = [], sectionHea
1910
2509
  onClick: () => handleItemSelect(item),
1911
2510
  }));
1912
2511
  const showDropdown = isOpen && searchValue.length >= minSearchLength;
1913
- return (jsxs("div", { ref: dropdownRef, className: cn("relative", containerClassName), children: [jsx(TextField, { ref: inputRef, value: searchValue, onChange: handleSearchChange, onFocus: handleFocus, onKeyDown: handleKeyDown, containerClassName: "mb-0", ...textFieldProps }), showDropdown && (jsx(DropdownMenu, { items: itemsWithHandlers, sectionHeading: sectionHeading, isLoading: isLoading, isEmpty: filteredItems.length === 0, emptyTitle: emptyTitle, emptyDescription: emptyDescription, emptyLinkText: emptyLinkText, onEmptyLinkClick: onEmptyLinkClick, primaryButtonText: primaryButtonText, secondaryButtonText: secondaryButtonText, onPrimaryClick: onPrimaryClick, onSecondaryClick: onSecondaryClick, showChevron: showChevron, emptyIcon: emptyIcon, disableFooter: disableFooter, onClose: () => setIsOpen(false), focusedIndex: focusedIndex, className: cn("absolute z-50 mt-2", dropdownClassName), width: dropdownWidth === "full" ? "full" : "auto" }))] }));
2512
+ const dropdownMenu = showDropdown && (jsx("div", { ref: menuRef, style: {
2513
+ position: "absolute",
2514
+ top: `${position.top + 8}px`,
2515
+ left: `${position.left}px`,
2516
+ width: dropdownWidth === "full" ? `${position.width}px` : "auto",
2517
+ zIndex: 9999,
2518
+ }, children: jsx(DropdownMenu, { items: itemsWithHandlers, sectionHeading: sectionHeading, isLoading: isLoading, isEmpty: filteredItems.length === 0, emptyTitle: emptyTitle, emptyDescription: emptyDescription, emptyLinkText: emptyLinkText, onEmptyLinkClick: onEmptyLinkClick, primaryButtonText: primaryButtonText, secondaryButtonText: secondaryButtonText, onPrimaryClick: onPrimaryClick, onSecondaryClick: onSecondaryClick, showChevron: showChevron, emptyIcon: emptyIcon, disableFooter: disableFooter, footerLayout: footerLayout, onClose: () => setIsOpen(false), focusedIndex: focusedIndex, className: dropdownClassName, width: dropdownWidth === "full" ? "full" : "auto" }) }));
2519
+ return (jsxs(Fragment, { children: [jsx("div", { ref: dropdownRef, className: cn("relative", containerClassName), children: jsx(TextField, { ref: inputRef, value: searchValue, onChange: handleSearchChange, onFocus: handleFocus, onKeyDown: handleKeyDown, containerClassName: "mb-0", ...textFieldProps }) }), typeof document !== "undefined" &&
2520
+ dropdownMenu &&
2521
+ createPortal(dropdownMenu, document.body)] }));
1914
2522
  });
1915
2523
  SearchableDropdown.displayName = "SearchableDropdown";
1916
2524
 
@@ -2054,6 +2662,249 @@ const Switch = React.forwardRef(({ label, size = "medium", isDisabled = false, c
2054
2662
  });
2055
2663
  Switch.displayName = "Switch";
2056
2664
 
2665
+ const tableVariants = cva("w-full border-collapse", {
2666
+ variants: {
2667
+ variant: {
2668
+ default: "border-separate border-spacing-0",
2669
+ bordered: "border-separate border-spacing-0",
2670
+ striped: "border-separate border-spacing-0",
2671
+ },
2672
+ size: {
2673
+ small: "text-body-small-medium",
2674
+ medium: "text-body-medium-medium",
2675
+ large: "text-body-large-medium",
2676
+ },
2677
+ },
2678
+ defaultVariants: {
2679
+ variant: "default",
2680
+ size: "medium",
2681
+ },
2682
+ });
2683
+ const tableHeaderVariants = cva("text-body-medium-regular text-left text-surface-ink-neutral-normal border-b border-surface-outline-neutral-muted", {
2684
+ variants: {
2685
+ size: {
2686
+ small: "px-3 py-2 h-[32px]",
2687
+ medium: "px-4 py-3 h-[40px]",
2688
+ large: "px-6 py-4 h-[48px]",
2689
+ },
2690
+ },
2691
+ defaultVariants: {
2692
+ size: "medium",
2693
+ },
2694
+ });
2695
+ const tableCellVariants = cva("text-body-medium-regular border-b border-surface-outline-neutral-muted text-surface-ink-neutral-normal transition-colors duration-150", {
2696
+ variants: {
2697
+ size: {
2698
+ small: "px-3 py-2 h-[40px]",
2699
+ medium: "px-4 py-3 h-[72px]",
2700
+ large: "px-6 py-4 h-[56px]",
2701
+ },
2702
+ state: {
2703
+ default: "",
2704
+ focus: "",
2705
+ // focus:
2706
+ // "outline outline-2 outline-action-outline-primary-default outline-offset-[-2px]",
2707
+ },
2708
+ },
2709
+ defaultVariants: {
2710
+ size: "medium",
2711
+ state: "default",
2712
+ },
2713
+ });
2714
+
2715
+ function TableHeader({ headerGroups, enableRowSelection, enableSelectAll, showHeaderBackground, stickyHeader, size, headerClassName, isDetailPanelOpen, visibleHeadersCount, onToggleAllRows, isAllRowsSelected, isSomeRowsSelected, }) {
2716
+ return (jsx("thead", { className: cn(showHeaderBackground && "bg-surface-fill-neutral-moderate", stickyHeader && "sticky top-0 z-10"), children: headerGroups.map((headerGroup) => (jsxs("tr", { children: [enableRowSelection && enableSelectAll && (jsx("th", { className: cn(tableHeaderVariants({ size }), showHeaderBackground && "bg-surface-fill-neutral-moderate", "w-10 rounded-tl-xlarge rounded-bl-xlarge", headerClassName), children: jsx(Checkbox, { checked: isAllRowsSelected, isIndeterminate: isSomeRowsSelected, onChange: onToggleAllRows, "aria-label": "Select all rows" }) })), headerGroup.headers.map((header, index) => {
2717
+ const shouldHideColumn = isDetailPanelOpen && index >= visibleHeadersCount;
2718
+ const isLastVisibleColumn = isDetailPanelOpen
2719
+ ? index === visibleHeadersCount - 1
2720
+ : index === headerGroup.headers.length - 1;
2721
+ return (jsx("th", { className: cn(tableHeaderVariants({ size }), showHeaderBackground &&
2722
+ "bg-surface-fill-neutral-moderate border-none", !enableRowSelection &&
2723
+ index === 0 &&
2724
+ "rounded-tl-xlarge rounded-bl-xlarge", isLastVisibleColumn && "rounded-tr-xlarge rounded-br-xlarge", header.column.columnDef.meta?.headerClassName, headerClassName, "transition-all duration-300 ease-in-out", shouldHideColumn
2725
+ ? "opacity-0 translate-x-8 pointer-events-none"
2726
+ : "opacity-100 translate-x-0"), style: {
2727
+ width: header.getSize(),
2728
+ minWidth: header.column.columnDef.minSize,
2729
+ maxWidth: header.column.columnDef.maxSize,
2730
+ }, children: header.isPlaceholder ? null : (jsxs("div", { className: cn("flex items-center gap-2", header.column.getCanSort() && "cursor-pointer select-none"), onClick: header.column.getToggleSortingHandler(), children: [flexRender(header.column.columnDef.header, header.getContext()), header.column.getCanSort() && (jsx("span", { className: "text-surface-ink-neutral-muted", children: {
2731
+ asc: "↑",
2732
+ desc: "↓",
2733
+ }[header.column.getIsSorted()] ?? "↕" }))] })) }, header.id));
2734
+ })] }, headerGroup.id))) }));
2735
+ }
2736
+
2737
+ function TableBody({ rows, enableRowSelection, size, variant, showRowHover, cellClassName, isDetailPanelOpen, visibleHeadersCount, effectiveSelectedRowId, onRowClick, getRowClassName, handleRowClick, }) {
2738
+ const [focusedCell, setFocusedCell] = React.useState(null);
2739
+ const [hoveredRow, setHoveredRow] = React.useState(null);
2740
+ return (jsx("tbody", { className: "bg-surface-fill-neutral-intense", children: rows.map((row) => {
2741
+ const isRowSelected = row.id === effectiveSelectedRowId;
2742
+ const isRowHovered = hoveredRow === row.id;
2743
+ const handleClick = () => handleRowClick(row.original, row.id);
2744
+ return (jsxs("tr", { className: cn(variant === "striped" &&
2745
+ row.index % 2 === 1 &&
2746
+ "bg-surface-fill-neutral-moderate", onRowClick && "cursor-pointer", isRowSelected && "bg-action-fill-primary-faded", isRowHovered &&
2747
+ showRowHover &&
2748
+ "bg-surface-fill-neutral-moderate", getRowClassName(row.original)), onClick: handleClick, onMouseEnter: () => setHoveredRow(row.id), onMouseLeave: () => setHoveredRow(null), children: [enableRowSelection && (jsx("td", { className: cn(tableCellVariants({ size }), "w-10", cellClassName), children: jsx(Checkbox, { checked: row.getIsSelected(), isIndeterminate: row.getIsSomeSelected(), onChange: row.getToggleSelectedHandler(), onClick: (e) => e.stopPropagation(), "aria-label": `Select row ${row.id}` }) })), row.getVisibleCells().map((cell, cellIndex) => {
2749
+ const shouldHideColumn = isDetailPanelOpen && cellIndex >= visibleHeadersCount;
2750
+ const isCellFocused = focusedCell?.rowId === row.id &&
2751
+ focusedCell?.cellId === cell.id;
2752
+ const cellState = isCellFocused ? "focus" : "default";
2753
+ return (jsx("td", { className: cn(tableCellVariants({ size, state: cellState }), cell.column.columnDef.meta?.cellClassName, cellClassName, "transition-all duration-300 ease-in-out", shouldHideColumn
2754
+ ? "opacity-0 translate-x-8 pointer-events-none"
2755
+ : "opacity-100 translate-x-0"), style: {
2756
+ width: cell.column.getSize(),
2757
+ minWidth: cell.column.columnDef.minSize,
2758
+ maxWidth: cell.column.columnDef.maxSize,
2759
+ }, tabIndex: 0, onFocus: () => setFocusedCell({ rowId: row.id, cellId: cell.id }), onBlur: () => setFocusedCell(null), children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id));
2760
+ })] }, row.id));
2761
+ }) }));
2762
+ }
2763
+
2764
+ function DetailPanel({ isOpen, content, data, onClose, }) {
2765
+ return (jsx("div", { className: cn("absolute top-0 right-0 h-full z-20 transition-all duration-300 ease-in-out", isOpen
2766
+ ? "translate-x-0 opacity-100"
2767
+ : "translate-x-full opacity-0 pointer-events-none"), style: { width: "332px", paddingLeft: "12px" }, children: jsx("div", { className: "w-full h-full bg-white border border-surface-outline-neutral-muted rounded-tr-xlarge rounded-br-xlarge overflow-hidden", children: jsx("div", { className: "w-full h-full overflow-auto", children: data && (jsxs("div", { className: "relative h-full", children: [jsx("button", { onClick: (e) => {
2768
+ e.stopPropagation();
2769
+ onClose();
2770
+ }, className: "absolute top-4 right-4 z-10 p-2 rounded-medium hover:bg-surface-fill-neutral-faded transition-colors", "aria-label": "Close detail panel", children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "text-surface-ink-neutral-muted", children: jsx("path", { d: "M12 4L4 12M4 4l8 8", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) }), content(data)] })) }) }) }));
2771
+ }
2772
+
2773
+ function renderDefaultLoadingState({ colSpan }) {
2774
+ return (jsx("tr", { children: jsx("td", { colSpan: colSpan, className: "text-center py-12 text-surface-ink-neutral-muted", children: jsxs("div", { className: "flex items-center justify-center gap-2", children: [jsx("div", { className: "animate-spin rounded-full h-6 w-6 border-b-2 border-action-fill-primary-default" }), jsx("span", { children: "Loading..." })] }) }) }));
2775
+ }
2776
+ function renderDefaultEmptyState({ colSpan }) {
2777
+ return (jsx("tr", { children: jsx("td", { colSpan: colSpan, className: "text-center py-12 text-surface-ink-neutral-muted", children: "No data available" }) }));
2778
+ }
2779
+
2780
+ // ==================== Component ====================
2781
+ function TableComponent({ className, wrapperClassName, containerClassName, variant, size = "medium", table, enableRowSelection = false, enableSelectAll = false, isLoading = false, loadingComponent, emptyComponent, enableHorizontalScroll = false, stickyHeader = false, maxHeight, showRowHover = true, onRowClick, rowClassName, headerClassName, cellClassName, showHeaderBackground = true, detailPanel, hideColumnsOnDetailOpen = 3, selectedRowId, onRowSelectionChange, ...props }, ref) {
2782
+ // ==================== State ====================
2783
+ const [internalSelectedRowId, setInternalSelectedRowId] = React.useState(null);
2784
+ const selectedRowIdRef = React.useRef(null);
2785
+ const effectiveSelectedRowId = selectedRowId !== undefined ? selectedRowId : internalSelectedRowId;
2786
+ const isDetailPanelOpen = Boolean(effectiveSelectedRowId);
2787
+ // ==================== Effects ====================
2788
+ // Keep ref in sync
2789
+ React.useEffect(() => {
2790
+ selectedRowIdRef.current = effectiveSelectedRowId;
2791
+ }, [effectiveSelectedRowId]);
2792
+ // Clear selection if selected row is not in current data
2793
+ React.useEffect(() => {
2794
+ if (effectiveSelectedRowId) {
2795
+ const rowExists = table
2796
+ .getRowModel()
2797
+ .rows.some((r) => r.id === effectiveSelectedRowId);
2798
+ if (!rowExists) {
2799
+ if (selectedRowId === undefined) {
2800
+ setInternalSelectedRowId(null);
2801
+ }
2802
+ if (onRowSelectionChange) {
2803
+ onRowSelectionChange(null);
2804
+ }
2805
+ }
2806
+ }
2807
+ }, [
2808
+ table.getRowModel().rows,
2809
+ effectiveSelectedRowId,
2810
+ selectedRowId,
2811
+ onRowSelectionChange,
2812
+ ]);
2813
+ // ==================== Computed Values ====================
2814
+ const hasData = table.getRowModel().rows?.length > 0;
2815
+ const headerGroups = table.getHeaderGroups();
2816
+ const headers = headerGroups[0]?.headers || [];
2817
+ const visibleHeadersCount = React.useMemo(() => {
2818
+ return isDetailPanelOpen
2819
+ ? headers.length - hideColumnsOnDetailOpen
2820
+ : headers.length;
2821
+ }, [isDetailPanelOpen, headers.length, hideColumnsOnDetailOpen]);
2822
+ // ==================== Callbacks ====================
2823
+ const getRowClassName = React.useCallback((row) => {
2824
+ if (typeof rowClassName === "function") {
2825
+ return rowClassName(row);
2826
+ }
2827
+ return rowClassName || "";
2828
+ }, [rowClassName]);
2829
+ const handleRowClickInternal = React.useCallback((row, rowId) => {
2830
+ const currentSelectedId = selectedRowIdRef.current;
2831
+ const newSelectedId = currentSelectedId === rowId ? null : rowId;
2832
+ if (selectedRowId === undefined) {
2833
+ setInternalSelectedRowId(newSelectedId);
2834
+ }
2835
+ if (onRowSelectionChange) {
2836
+ onRowSelectionChange(newSelectedId);
2837
+ }
2838
+ if (onRowClick) {
2839
+ onRowClick(row);
2840
+ }
2841
+ }, [selectedRowId, onRowSelectionChange, onRowClick]);
2842
+ const getSelectedRowData = () => {
2843
+ if (!effectiveSelectedRowId)
2844
+ return null;
2845
+ const row = table
2846
+ .getRowModel()
2847
+ .rows.find((r) => r.id === effectiveSelectedRowId);
2848
+ return row ? row.original : null;
2849
+ };
2850
+ const handleDetailPanelClose = () => {
2851
+ if (selectedRowId === undefined) {
2852
+ setInternalSelectedRowId(null);
2853
+ }
2854
+ if (onRowSelectionChange) {
2855
+ onRowSelectionChange(null);
2856
+ }
2857
+ };
2858
+ // ==================== Render Helpers ====================
2859
+ const renderLoadingState = () => {
2860
+ if (loadingComponent)
2861
+ return loadingComponent;
2862
+ return renderDefaultLoadingState({ colSpan: table.getAllColumns().length });
2863
+ };
2864
+ const renderEmptyState = () => {
2865
+ if (emptyComponent)
2866
+ return emptyComponent;
2867
+ return renderDefaultEmptyState({ colSpan: table.getAllColumns().length });
2868
+ };
2869
+ // ==================== Render ====================
2870
+ return (jsx("div", { ref: ref, className: cn("w-full", wrapperClassName), ...props, children: jsxs("div", { className: cn("relative overflow-x-hidden", maxHeight && "overflow-y-auto", containerClassName), style: maxHeight ? { maxHeight } : undefined, children: [jsxs("table", { className: cn(tableVariants({ variant, size }), className), children: [jsx(TableHeader, { headerGroups: headerGroups, enableRowSelection: enableRowSelection, enableSelectAll: enableSelectAll, showHeaderBackground: showHeaderBackground, stickyHeader: stickyHeader, size: size || "medium", headerClassName: headerClassName, isDetailPanelOpen: isDetailPanelOpen, visibleHeadersCount: visibleHeadersCount, onToggleAllRows: (e) => table.getToggleAllRowsSelectedHandler()(e), isAllRowsSelected: table.getIsAllRowsSelected(), isSomeRowsSelected: table.getIsSomeRowsSelected() }), isLoading ? (jsx("tbody", { children: renderLoadingState() })) : !hasData ? (jsx("tbody", { children: renderEmptyState() })) : (jsx(TableBody, { rows: table.getRowModel().rows, enableRowSelection: enableRowSelection, size: size || "medium", variant: variant || "default", showRowHover: showRowHover, cellClassName: cellClassName, isDetailPanelOpen: isDetailPanelOpen, visibleHeadersCount: visibleHeadersCount, effectiveSelectedRowId: effectiveSelectedRowId, onRowClick: onRowClick, getRowClassName: getRowClassName, handleRowClick: handleRowClickInternal }))] }), detailPanel && (jsx(DetailPanel, { isOpen: isDetailPanelOpen, content: detailPanel, data: getSelectedRowData(), onClose: handleDetailPanelClose }))] }) }));
2871
+ }
2872
+ // ==================== Export ====================
2873
+ const Table = React.forwardRef(TableComponent);
2874
+ Table.displayName = "Table";
2875
+
2876
+ const TableDetailPanel = React.forwardRef(({ isOpen, onClose, children, className, width = "400px" }, ref) => {
2877
+ return (jsx("div", { ref: ref, className: cn("absolute top-0 right-0 h-full bg-white border border-surface-outline-neutral-muted transition-transform duration-300 ease-in-out overflow-auto", isOpen ? "translate-x-0" : "translate-x-full", className), style: { width }, children: children }));
2878
+ });
2879
+ TableDetailPanel.displayName = "TableDetailPanel";
2880
+
2881
+ function NumberCell({ value, currency, subtitle, className, }) {
2882
+ return (jsxs("div", { className: cn("flex flex-col", className), children: [jsxs("div", { className: "text-body-medium-medium text-surface-ink-neutral-normal", children: [currency, " ", value.toLocaleString("en-IN", {
2883
+ minimumFractionDigits: 2,
2884
+ maximumFractionDigits: 2,
2885
+ })] }), subtitle && (jsx("div", { className: "text-body-small-regular text-surface-ink-neutral-muted", children: subtitle }))] }));
2886
+ }
2887
+ function IconCell({ icon, background = "neutral", className, }) {
2888
+ const backgrounds = {
2889
+ neutral: "bg-surface-fill-neutral-faded",
2890
+ primary: "bg-action-fill-primary-faded",
2891
+ success: "bg-action-fill-positive-faded",
2892
+ warning: "bg-action-fill-warning-faded",
2893
+ danger: "bg-action-fill-negative-faded",
2894
+ };
2895
+ return (jsx("div", { className: cn("inline-flex items-center justify-center w-10 h-10 rounded-medium", backgrounds[background], className), children: icon }));
2896
+ }
2897
+ // ==================== Spacer Cell ====================
2898
+ function SpacerCell() {
2899
+ return jsx("div", { className: "w-full h-full" });
2900
+ }
2901
+ function SlotCell({ onDragStart, onDragEnd, className }) {
2902
+ return (jsx("div", { draggable: true, onDragStart: onDragStart, onDragEnd: onDragEnd, className: cn("flex items-center justify-center cursor-grab active:cursor-grabbing", className), children: jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "text-surface-ink-neutral-muted", children: [jsx("path", { d: "M6 4C6 3.44772 5.55228 3 5 3C4.44772 3 4 3.44772 4 4C4 4.55228 4.44772 5 5 5C5.55228 5 6 4.55228 6 4Z", fill: "currentColor" }), jsx("path", { d: "M6 8C6 7.44772 5.55228 7 5 7C4.44772 7 4 7.44772 4 8C4 8.55228 4.44772 9 5 9C5.55228 9 6 8.55228 6 8Z", fill: "currentColor" }), jsx("path", { d: "M6 12C6 11.4477 5.55228 11 5 11C4.44772 11 4 11.4477 4 12C4 12.5523 4.44772 13 5 13C5.55228 13 6 12.5523 6 12Z", fill: "currentColor" }), jsx("path", { d: "M12 4C12 3.44772 11.5523 3 11 3C10.4477 3 10 3.44772 10 4C10 4.55228 10.4477 5 11 5C11.5523 5 12 4.55228 12 4Z", fill: "currentColor" }), jsx("path", { d: "M12 8C12 7.44772 11.5523 7 11 7C10.4477 7 10 7.44772 10 8C10 8.55228 10.4477 9 11 9C11.5523 9 12 8.55228 12 8Z", fill: "currentColor" }), jsx("path", { d: "M12 12C12 11.4477 11.5523 11 11 11C10.4477 11 10 11.4477 10 12C10 12.5523 10.4477 13 11 13C11.5523 13 12 12.5523 12 12Z", fill: "currentColor" })] }) }));
2903
+ }
2904
+ function AvatarCell({ name, initials, avatar, subtitle, color = "a1", className, }) {
2905
+ return (jsxs("div", { className: cn("flex items-center gap-3", className), children: [avatar ? (jsx("img", { src: avatar, alt: name, className: "w-10 h-10 rounded-full object-cover" })) : (jsx("div", { className: cn("w-10 h-10 rounded-full flex items-center justify-center text-body-medium-medium", `bg-${color}`), children: initials || name.charAt(0).toUpperCase() })), jsxs("div", { className: "flex flex-col", children: [jsx("div", { className: "text-body-medium-medium text-surface-ink-neutral-normal", children: name }), subtitle && (jsx("div", { className: "text-body-small-regular text-surface-ink-neutral-muted", children: subtitle }))] })] }));
2906
+ }
2907
+
2057
2908
  const tabItemVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 relative cursor-pointer", {
2058
2909
  variants: {
2059
2910
  variant: {
@@ -2256,5 +3107,5 @@ const TextArea = React.forwardRef(({ label, helperText, errorText, successText,
2256
3107
  });
2257
3108
  TextArea.displayName = "TextArea";
2258
3109
 
2259
- export { Badge, Button, Checkbox, Counter, Divider, Dropdown, DropdownMenu, FormFooter, FormHeader, Icon, Link, ListItem, Radio, SearchableDropdown, Switch, TabItem, Tabs, Text, TextArea, TextField, Tooltip, badgeVariants, buttonVariants, checkboxVariants, cn, counterVariants, dropdownVariants, getAvailableIcons, hasIcon, iconRegistry, linkVariants, listItemVariants, radioVariants, switchVariants, textAreaVariants, textFieldVariants, tooltipVariants };
3110
+ export { Avatar, AvatarCell, Badge, Button, ButtonGroup, Checkbox, Counter, Divider, Dropdown, DropdownMenu, FormFooter, FormHeader, Icon, IconCell, Link, ListItem, Modal, NumberCell, Pagination, Radio, SearchableDropdown, Select, SlotCell, SpacerCell, Switch, TabItem, Table, TableDetailPanel, Tabs, Text, TextArea, TextField, Tooltip, avatarVariants, badgeVariants, buttonGroupVariants, buttonVariants, checkboxVariants, cn, counterVariants, dropdownVariants, getAvailableIcons, hasIcon, iconRegistry, linkVariants, listItemVariants, paginationVariants, radioVariants, selectVariants, switchVariants, tableCellVariants, tableHeaderVariants, tableVariants, textAreaVariants, textFieldVariants, tooltipVariants };
2260
3111
  //# sourceMappingURL=index.esm.js.map