@pk-design/react-tailwind 1.0.6 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/dist/react-tailwind.cjs.js +1593 -362
  2. package/dist/react-tailwind.cjs.js.map +1 -1
  3. package/dist/react-tailwind.es.js +1579 -360
  4. package/dist/react-tailwind.es.js.map +1 -1
  5. package/dist/types/components/Alert/Alert.d.ts +3 -0
  6. package/dist/types/components/Alert/Alert.test.d.ts +1 -0
  7. package/dist/types/components/Alert/Alert.types.d.ts +34 -0
  8. package/dist/types/components/Alert/index.d.ts +2 -35
  9. package/dist/types/components/Badge/Badge.d.ts +3 -0
  10. package/dist/types/components/Badge/Badge.test.d.ts +1 -0
  11. package/dist/types/components/Badge/Badge.types.d.ts +22 -0
  12. package/dist/types/components/Badge/index.d.ts +2 -24
  13. package/dist/types/components/Banner/Banner.d.ts +3 -0
  14. package/dist/types/components/Banner/Banner.test.d.ts +1 -0
  15. package/dist/types/components/Banner/Banner.types.d.ts +14 -0
  16. package/dist/types/components/Banner/index.d.ts +2 -16
  17. package/dist/types/components/BodyText/BodyText.d.ts +3 -0
  18. package/dist/types/components/BodyText/BodyText.test.d.ts +1 -0
  19. package/dist/types/components/BodyText/BodyText.types.d.ts +27 -0
  20. package/dist/types/components/BodyText/index.d.ts +2 -28
  21. package/dist/types/components/Breadcrumb/Breadcrumb.d.ts +3 -0
  22. package/dist/types/components/Breadcrumb/Breadcrumb.test.d.ts +1 -0
  23. package/dist/types/components/Breadcrumb/Breadcrumb.types.d.ts +29 -0
  24. package/dist/types/components/Breadcrumb/index.d.ts +2 -30
  25. package/dist/types/components/Button/Button.d.ts +2 -3
  26. package/dist/types/components/Button/Button.test.d.ts +1 -0
  27. package/dist/types/components/Button/Button.types.d.ts +171 -0
  28. package/dist/types/components/Button/index.d.ts +1 -1
  29. package/dist/types/components/Card/Card.d.ts +3 -0
  30. package/dist/types/components/Card/Card.test.d.ts +1 -0
  31. package/dist/types/components/Card/Card.types.d.ts +23 -0
  32. package/dist/types/components/Card/index.d.ts +2 -9
  33. package/dist/types/components/Checkbox/Checkbox.d.ts +2 -0
  34. package/dist/types/components/Checkbox/Checkbox.test.d.ts +1 -0
  35. package/dist/types/components/Checkbox/Checkbox.types.d.ts +14 -0
  36. package/dist/types/components/Checkbox/index.d.ts +2 -13
  37. package/dist/types/components/CheckboxGroup/CheckboxGroup.d.ts +5 -0
  38. package/dist/types/components/CheckboxGroup/CheckboxGroup.test.d.ts +1 -0
  39. package/dist/types/components/CheckboxGroup/CheckboxGroup.types.d.ts +55 -0
  40. package/dist/types/components/CheckboxGroup/index.d.ts +2 -56
  41. package/dist/types/components/DataTable/DataTable.d.ts +2 -0
  42. package/dist/types/components/DataTable/DataTable.icons.d.ts +4 -0
  43. package/dist/types/components/DataTable/DataTable.test.d.ts +1 -0
  44. package/dist/types/components/DataTable/DataTable.types.d.ts +63 -0
  45. package/dist/types/components/DataTable/DataTable.utils.d.ts +12 -0
  46. package/dist/types/components/DataTable/DataTable.utils.test.d.ts +1 -0
  47. package/dist/types/components/DataTable/index.d.ts +4 -0
  48. package/dist/types/components/DetailedInformation/DetailedInformation.d.ts +2 -0
  49. package/dist/types/components/DetailedInformation/DetailedInformation.test.d.ts +1 -0
  50. package/dist/types/components/DetailedInformation/DetailedInformation.types.d.ts +54 -0
  51. package/dist/types/components/DetailedInformation/index.d.ts +2 -63
  52. package/dist/types/components/Drawer/Drawer.d.ts +1 -1
  53. package/dist/types/components/Drawer/Drawer.test.d.ts +1 -0
  54. package/dist/types/components/Drawer/{type.d.ts → Drawer.types.d.ts} +1 -1
  55. package/dist/types/components/Drawer/index.d.ts +1 -1
  56. package/dist/types/components/Dropdown/Dropdown.d.ts +3 -0
  57. package/dist/types/components/Dropdown/Dropdown.test.d.ts +1 -0
  58. package/dist/types/components/Dropdown/Dropdown.types.d.ts +107 -0
  59. package/dist/types/components/Dropdown/index.d.ts +2 -62
  60. package/dist/types/components/HeadingText/HeadingText.d.ts +9 -0
  61. package/dist/types/components/HeadingText/HeadingText.types.d.ts +5 -0
  62. package/dist/types/components/HeadingText/index.d.ts +2 -12
  63. package/dist/types/components/Input/Input.d.ts +6 -0
  64. package/dist/types/components/Input/Input.test.d.ts +1 -0
  65. package/dist/types/components/Input/Input.types.d.ts +12 -0
  66. package/dist/types/components/Input/index.d.ts +2 -13
  67. package/dist/types/components/Label/Label.d.ts +6 -0
  68. package/dist/types/components/Label/index.d.ts +1 -5
  69. package/dist/types/components/Pagination/Pagination.d.ts +1 -31
  70. package/dist/types/components/Pagination/Pagination.test.d.ts +1 -0
  71. package/dist/types/components/Pagination/Pagination.types.d.ts +36 -0
  72. package/dist/types/components/Pagination/index.d.ts +1 -0
  73. package/dist/types/components/Pagination/usePagination.d.ts +1 -5
  74. package/dist/types/components/PasswordInput/PasswordInput.d.ts +6 -0
  75. package/dist/types/components/PasswordInput/PasswordInput.test.d.ts +1 -0
  76. package/dist/types/components/PasswordInput/index.d.ts +1 -6
  77. package/dist/types/components/Radio/Radio.d.ts +2 -0
  78. package/dist/types/components/Radio/Radio.test.d.ts +1 -0
  79. package/dist/types/components/Radio/Radio.types.d.ts +14 -0
  80. package/dist/types/components/Radio/index.d.ts +2 -0
  81. package/dist/types/components/RadioGroup/RadioGroup.d.ts +3 -0
  82. package/dist/types/components/RadioGroup/RadioGroup.test.d.ts +1 -0
  83. package/dist/types/components/RadioGroup/RadioGroup.types.d.ts +65 -0
  84. package/dist/types/components/RadioGroup/index.d.ts +2 -0
  85. package/dist/types/components/RadioSwitch/RadioSwitch.d.ts +7 -0
  86. package/dist/types/components/RadioSwitch/RadioSwitch.test.d.ts +1 -0
  87. package/dist/types/components/RadioSwitch/RadioSwitch.types.d.ts +47 -0
  88. package/dist/types/components/RadioSwitch/index.d.ts +2 -0
  89. package/dist/types/components/RangeInput/-backup.d.ts +10 -0
  90. package/dist/types/components/RangeInput/RangeInput.d.ts +2 -0
  91. package/dist/types/components/RangeInput/RangeInput.test.d.ts +1 -0
  92. package/dist/types/components/RangeInput/RangeInput.types.d.ts +14 -0
  93. package/dist/types/components/RangeInput/index.d.ts +1 -10
  94. package/dist/types/components/RangeSlider/RangeSlider.d.ts +3 -0
  95. package/dist/types/components/RangeSlider/RangeSlider.test.d.ts +1 -0
  96. package/dist/types/components/RangeSlider/RangeSlider.types.d.ts +68 -0
  97. package/dist/types/components/RangeSlider/index.d.ts +2 -0
  98. package/dist/types/components/SelectBox/SelectBox.d.ts +2 -0
  99. package/dist/types/components/SelectBox/SelectBox.test.d.ts +1 -0
  100. package/dist/types/components/SelectBox/SelectBox.types.d.ts +94 -0
  101. package/dist/types/components/SelectBox/index.d.ts +2 -40
  102. package/dist/types/components/Table/Table.d.ts +10 -0
  103. package/dist/types/components/Table/Table.test.d.ts +1 -0
  104. package/dist/types/components/Table/Table.types.d.ts +91 -0
  105. package/dist/types/components/Table/index.d.ts +2 -48
  106. package/dist/types/components/Tabs/Tabs.d.ts +3 -0
  107. package/dist/types/components/Tabs/Tabs.test.d.ts +1 -0
  108. package/dist/types/components/Tabs/Tabs.types.d.ts +48 -0
  109. package/dist/types/components/Tabs/index.d.ts +1 -2
  110. package/dist/types/components/TextContent/TextContent.d.ts +3 -0
  111. package/dist/types/components/TextContent/TextContent.test.d.ts +1 -0
  112. package/dist/types/components/TextContent/TextContent.types.d.ts +23 -0
  113. package/dist/types/components/TextContent/index.d.ts +2 -10
  114. package/dist/types/components/Textarea/Textarea.d.ts +2 -0
  115. package/dist/types/components/Textarea/Textarea.test.d.ts +1 -0
  116. package/dist/types/components/Textarea/Textarea.types.d.ts +6 -0
  117. package/dist/types/components/Textarea/index.d.ts +2 -7
  118. package/dist/types/components/Toast/Toast.d.ts +4 -8
  119. package/dist/types/components/Toast/Toast.test.d.ts +1 -0
  120. package/dist/types/components/Toast/Toast.types.d.ts +117 -0
  121. package/dist/types/components/Toast/ToastProvider.d.ts +2 -11
  122. package/dist/types/components/Toast/ToastProvider.test.d.ts +1 -0
  123. package/dist/types/components/Toast/index.d.ts +1 -0
  124. package/dist/types/components/VirtualizedDataTable/VirtualizedDataTable.d.ts +3 -0
  125. package/dist/types/components/VirtualizedDataTable/VirtualizedDataTable.test.d.ts +1 -0
  126. package/dist/types/components/VirtualizedDataTable/VirtualizedDataTable.types.d.ts +18 -0
  127. package/dist/types/components/VirtualizedDataTable/VirtualizedRow.d.ts +5 -0
  128. package/dist/types/components/VirtualizedDataTable/index.d.ts +2 -0
  129. package/dist/types/components/_Dialog/Dialog.d.ts +4 -0
  130. package/dist/types/components/_Dialog/Dialog.types.d.ts +53 -0
  131. package/dist/types/components/_Dialog/index.d.ts +2 -0
  132. package/dist/types/components/common-type.d.ts +2 -1
  133. package/dist/types/hooks/use-debounce.d.ts +2 -0
  134. package/dist/types/hooks/use-is-mobile.d.ts +1 -0
  135. package/dist/types/hooks/use-is-tablet.d.ts +1 -0
  136. package/dist/types/index.d.ts +11 -6
  137. package/dist/types/utils/get.d.ts +1 -0
  138. package/package.json +20 -4
  139. package/dist/types/components/Button/type.d.ts +0 -58
  140. package/dist/types/components/RadioButton/index.d.ts +0 -7
  141. package/dist/types/components/RadioButtonGroup/index.d.ts +0 -19
  142. package/dist/types/components/RadioSwtich/index.d.ts +0 -14
  143. package/dist/types/components/Tag/index.d.ts +0 -12
  144. package/dist/types/components/hooks/use-debounce.d.ts +0 -1
@@ -26,10 +26,10 @@ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
26
26
 
27
27
  const buildClassName = (...classes) => tailwindMerge.twMerge(classes.filter(Boolean));
28
28
 
29
- var _path$d, _path2;
30
- function _extends$d() { return _extends$d = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$d.apply(null, arguments); }
29
+ var _path$i, _path2;
30
+ function _extends$i() { return _extends$i = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$i.apply(null, arguments); }
31
31
  var SvgBadgeCheck = function SvgBadgeCheck(props) {
32
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$d({
32
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$i({
33
33
  xmlns: "http://www.w3.org/2000/svg",
34
34
  width: 24,
35
35
  height: 24,
@@ -40,17 +40,17 @@ var SvgBadgeCheck = function SvgBadgeCheck(props) {
40
40
  strokeWidth: 2,
41
41
  className: "lucide lucide-badge-check-icon lucide-badge-check",
42
42
  viewBox: "0 0 24 24"
43
- }, props), _path$d || (_path$d = /*#__PURE__*/React__namespace.createElement("path", {
43
+ }, props), _path$i || (_path$i = /*#__PURE__*/React__namespace.createElement("path", {
44
44
  d: "M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76"
45
45
  })), _path2 || (_path2 = /*#__PURE__*/React__namespace.createElement("path", {
46
46
  d: "m9 12 2 2 4-4"
47
47
  })));
48
48
  };
49
49
 
50
- var _circle$4, _path$c;
51
- function _extends$c() { return _extends$c = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$c.apply(null, arguments); }
50
+ var _circle$4, _path$h;
51
+ function _extends$h() { return _extends$h = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$h.apply(null, arguments); }
52
52
  var SvgCircleX = function SvgCircleX(props) {
53
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$c({
53
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$h({
54
54
  xmlns: "http://www.w3.org/2000/svg",
55
55
  width: 24,
56
56
  height: 24,
@@ -65,15 +65,15 @@ var SvgCircleX = function SvgCircleX(props) {
65
65
  cx: 12,
66
66
  cy: 12,
67
67
  r: 10
68
- })), _path$c || (_path$c = /*#__PURE__*/React__namespace.createElement("path", {
68
+ })), _path$h || (_path$h = /*#__PURE__*/React__namespace.createElement("path", {
69
69
  d: "m15 9-6 6M9 9l6 6"
70
70
  })));
71
71
  };
72
72
 
73
- var _circle$3, _path$b;
74
- function _extends$b() { return _extends$b = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$b.apply(null, arguments); }
73
+ var _circle$3, _path$g;
74
+ function _extends$g() { return _extends$g = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$g.apply(null, arguments); }
75
75
  var SvgCircleAlert = function SvgCircleAlert(props) {
76
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$b({
76
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$g({
77
77
  xmlns: "http://www.w3.org/2000/svg",
78
78
  width: 24,
79
79
  height: 24,
@@ -88,15 +88,15 @@ var SvgCircleAlert = function SvgCircleAlert(props) {
88
88
  cx: 12,
89
89
  cy: 12,
90
90
  r: 10
91
- })), _path$b || (_path$b = /*#__PURE__*/React__namespace.createElement("path", {
91
+ })), _path$g || (_path$g = /*#__PURE__*/React__namespace.createElement("path", {
92
92
  d: "M12 8v4M12 16h.01"
93
93
  })));
94
94
  };
95
95
 
96
- var _circle$2, _path$a;
97
- function _extends$a() { return _extends$a = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$a.apply(null, arguments); }
96
+ var _circle$2, _path$f;
97
+ function _extends$f() { return _extends$f = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$f.apply(null, arguments); }
98
98
  var SvgInfo = function SvgInfo(props) {
99
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$a({
99
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$f({
100
100
  xmlns: "http://www.w3.org/2000/svg",
101
101
  width: 24,
102
102
  height: 24,
@@ -111,15 +111,15 @@ var SvgInfo = function SvgInfo(props) {
111
111
  cx: 12,
112
112
  cy: 12,
113
113
  r: 10
114
- })), _path$a || (_path$a = /*#__PURE__*/React__namespace.createElement("path", {
114
+ })), _path$f || (_path$f = /*#__PURE__*/React__namespace.createElement("path", {
115
115
  d: "M12 16v-4M12 8h.01"
116
116
  })));
117
117
  };
118
118
 
119
- var _path$9;
120
- function _extends$9() { return _extends$9 = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$9.apply(null, arguments); }
119
+ var _path$e;
120
+ function _extends$e() { return _extends$e = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$e.apply(null, arguments); }
121
121
  var SvgX = function SvgX(props) {
122
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$9({
122
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$e({
123
123
  xmlns: "http://www.w3.org/2000/svg",
124
124
  width: 24,
125
125
  height: 24,
@@ -130,7 +130,7 @@ var SvgX = function SvgX(props) {
130
130
  strokeWidth: 2,
131
131
  className: "lucide lucide-x-icon lucide-x",
132
132
  viewBox: "0 0 24 24"
133
- }, props), _path$9 || (_path$9 = /*#__PURE__*/React__namespace.createElement("path", {
133
+ }, props), _path$e || (_path$e = /*#__PURE__*/React__namespace.createElement("path", {
134
134
  d: "M18 6 6 18M6 6l12 12"
135
135
  })));
136
136
  };
@@ -141,19 +141,23 @@ const loaderSizeMap = {
141
141
  md: 'size-8',
142
142
  lg: 'size-10',
143
143
  };
144
- const Loader = ({ className = 'text-blue-600', size = 'md' }) => {
145
- return (jsxRuntime.jsx("svg", { className: buildClassName(loaderSizeMap[size], className, 'spinner'), viewBox: "0 0 50 50", children: jsxRuntime.jsx("circle", { className: "path", cx: "25", cy: "25", r: "20", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "5" }) }));
144
+ const Loader = ({ className = 'text-blue-600 dark:text-white', size = 'md', ...props }) => {
145
+ return (jsxRuntime.jsx("svg", { className: buildClassName(loaderSizeMap[size], className, 'spinner'), viewBox: "0 0 50 50", ...props, children: jsxRuntime.jsx("circle", { className: "path", cx: "25", cy: "25", r: "20", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "5" }) }));
146
146
  };
147
147
 
148
148
  const TextContent = React.forwardRef((props, ref) => {
149
- const { as = 'span', xsmall = false, small = false, strong = false, muted = false, error = false, className, ...rest } = props;
150
- return React.createElement(as, {
151
- ref,
152
- className: buildClassName(xsmall && 'text-xs/5', small && 'text-sm/6', strong && 'font-semibold', muted && 'text-gray-500', error && 'text-red-500', className),
149
+ const { xsmall = false, small = false, strong = false, muted = false, error = false, className, ...rest } = props;
150
+ return React.createElement('span', {
153
151
  ...rest,
152
+ ref,
153
+ className: buildClassName(xsmall && 'text-xs/5', small && 'text-sm/6', strong && 'font-semibold', muted && 'text-gray-500', error && 'text-red-500 dark:text-red-500', className),
154
154
  });
155
155
  });
156
+ TextContent.displayName = 'TextContent';
156
157
 
158
+ /**
159
+ * Tailwind CSS classes for theme + variant combinations.
160
+ */
157
161
  const THEMED_BTN_CLASS = {
158
162
  primary: {
159
163
  default: 'text-white bg-blue-600 hover:bg-blue-700 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-blue-600 disabled:bg-blue-400 dark:disabled:bg-blue-500',
@@ -171,22 +175,58 @@ const THEMED_BTN_CLASS = {
171
175
  plain: 'text-gray-700 hover:bg-black/5 dark:text-gray-200 dark:hover:bg-gray-700 focus:outline-blue-600 disabled:text-gray-400',
172
176
  },
173
177
  };
178
+ /**
179
+ * Generate size classes.
180
+ */
174
181
  const getBtnSizeClasses = (size, iconOnly = false) => {
175
182
  switch (size) {
176
183
  case 'xs':
177
- return `text-xs ${iconOnly ? 'p-1 rounded-sm' : 'px-2 py-1 rounded-sm gap-1'}`;
184
+ return iconOnly ? 'p-1 rounded-sm text-xs' : 'px-2 py-1 rounded-sm gap-1 text-xs';
178
185
  case 'sm':
179
- return `text-sm ${iconOnly ? 'p-1.5 rounded' : ' px-3 py-1.5 rounded gap-1.5'}`;
186
+ return iconOnly ? 'p-1.5 rounded text-sm' : 'px-3 py-1.5 rounded gap-1.5 text-sm';
180
187
  case 'md':
181
- return `text-sm ${iconOnly ? 'p-2 rounded-md' : 'px-4 py-2 rounded-md gap-2'}`;
188
+ return iconOnly ? 'p-2 rounded-md text-sm' : 'px-4 py-2 rounded-md gap-2 text-sm';
182
189
  case 'lg':
183
- return `text-base ${iconOnly ? 'p-2.5 rounded-lg' : 'px-5 py-2.5 rounded-lg gap-2'}`;
190
+ return iconOnly ? 'p-2.5 rounded-lg text-base' : 'px-5 py-2.5 rounded-lg gap-2 text-base';
184
191
  }
185
192
  };
186
- const Button = React.forwardRef((props, ref) => {
187
- const { className = '', children, theme = 'primary', variant = 'default', size = 'md', as: Element = 'button', loading = false, loadingText = '', type = 'button', rounded = false, disabled, iconOnly = false, ...buttonProps } = props;
188
- return (jsxRuntime.jsx(Element, { ref: ref, className: buildClassName(THEMED_BTN_CLASS[theme][variant], getBtnSizeClasses(size, iconOnly), 'focus:outline focus:outline-2 focus:outline-offset-2', 'font-medium flex items-center justify-center shrink-0', 'cursor-pointer disabled:cursor-not-allowed disabled:pointer-events-none disabled:opacity-75', 'transition duration-200 ease-in-out', rounded && 'rounded-full', variant === 'default' && 'shadow-xs hover:shadow-none disabled:shadow-none', className), type: type, disabled: disabled || loading, ...buttonProps, children: loading ? (jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [jsxRuntime.jsx(Loader, { className: "text-white", size: "xs" }), loadingText && jsxRuntime.jsx(TextContent, { children: loadingText })] })) : (children) }));
193
+ /**
194
+ * Base shared tailwind classes.
195
+ */
196
+ const BASE_BTN_CLASS = 'font-medium flex items-center justify-center shrink-0 cursor-pointer ' +
197
+ 'disabled:cursor-not-allowed disabled:pointer-events-none disabled:opacity-75 ' +
198
+ 'transition duration-200 ease-in-out';
199
+ const Button = React.forwardRef(({ as, type, ...props }, ref) => {
200
+ const { className = '', children, theme = 'primary', variant = 'default', size = 'md', loading = false, loadingText = '', rounded = false, disabled, iconOnly = false, noOutlineOnFocus = false, ...restProps } = props;
201
+ const Component = as || 'button';
202
+ // Accessibility guard for icon-only buttons
203
+ if (iconOnly && !restProps['aria-label']) {
204
+ console.warn('[ui] <Button iconOnly> requires aria-label for accessibility.');
205
+ }
206
+ // Disable interaction when loading
207
+ const resolvedDisabled = disabled || loading;
208
+ // Clean invalid props when not rendering a real button
209
+ const { type: _ignoreType, disabled: _ignoreDisabled, ...cleanRest } = restProps;
210
+ const buttonSpecificProps = Component === 'button'
211
+ ? {
212
+ type: type !== null && type !== void 0 ? type : 'button',
213
+ disabled: resolvedDisabled,
214
+ }
215
+ : {};
216
+ /**
217
+ * Memoized className for perf & stability.
218
+ */
219
+ const classes = React.useMemo(() => buildClassName(BASE_BTN_CLASS, THEMED_BTN_CLASS[theme][variant], getBtnSizeClasses(size, iconOnly), !noOutlineOnFocus && 'focus:outline focus:outline-2 focus:outline-offset-2', rounded && 'rounded-full', variant === 'default' && 'shadow-xs hover:shadow-none disabled:shadow-none', className), [theme, variant, size, iconOnly, rounded, noOutlineOnFocus, className]);
220
+ /**
221
+ * SPECIAL CASE:
222
+ * iconOnly + loading → show spinner only
223
+ */
224
+ if (loading && iconOnly) {
225
+ return (jsxRuntime.jsx(Component, { ref: ref, className: classes, ...buttonSpecificProps, ...cleanRest, children: jsxRuntime.jsx(Loader, { "data-testid": "btn-loader-icon", size: "xs" }) }));
226
+ }
227
+ return (jsxRuntime.jsx(Component, { ref: ref, className: classes, ...buttonSpecificProps, ...cleanRest, children: loading ? (jsxRuntime.jsxs("span", { className: "flex items-center gap-2", "aria-live": "polite", children: [jsxRuntime.jsx(Loader, { "data-testid": "btn-loader-icon", size: "xs" }), loadingText && jsxRuntime.jsx(TextContent, { children: loadingText })] })) : (children) }));
189
228
  });
229
+ Button.displayName = 'Button';
190
230
 
191
231
  const AlertTypeIconMap = {
192
232
  success: SvgBadgeCheck,
@@ -203,8 +243,9 @@ const TypeClassMap = {
203
243
  const Alert = (props) => {
204
244
  const { type = 'info', className = '', message, children, removable = false, onRemove = () => { }, ...restProps } = props;
205
245
  const Icon = AlertTypeIconMap[type] || SvgInfo;
206
- return (jsxRuntime.jsxs("div", { className: buildClassName(className, 'flex items-center justify-between rounded-md p-3 text-sm ring-1 ring-inset gap-2', TypeClassMap[type]), ...restProps, children: [jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [jsxRuntime.jsx(Icon, { className: "size-5" }), jsxRuntime.jsx("span", { className: "pr-2 inline-flex items-center", children: message || children })] }), removable && (jsxRuntime.jsx(Button, { iconOnly: true, size: "xs", variant: "plain", theme: "secondary", className: "hover:bg-black/5 text-gray-600 dark:hover:bg-black/5 dark:text-gray-600", onClick: () => onRemove(), children: jsxRuntime.jsx(SvgX, { className: "size-4.5" }) }))] }));
246
+ return (jsxRuntime.jsxs("div", { className: buildClassName(className, 'flex items-center justify-between rounded-md p-3 text-sm ring-1 ring-inset gap-2', TypeClassMap[type]), ...restProps, children: [jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [jsxRuntime.jsx(Icon, { className: "size-5", "data-testid": `alert-${type}-icon` }), jsxRuntime.jsx("span", { className: "pr-2 inline-flex items-center", children: message || children })] }), removable && (jsxRuntime.jsx(Button, { iconOnly: true, size: "xs", variant: "plain", theme: "secondary", className: "hover:bg-black/5 text-gray-600 dark:hover:bg-black/5 dark:text-gray-600", onClick: () => onRemove(), "data-testid": "alert-remove-btn", children: jsxRuntime.jsx(SvgX, { className: "size-4.5", "data-testid": "alert-remove-icon" }) }))] }));
207
247
  };
248
+ Alert.displayName = 'Alert';
208
249
 
209
250
  const ThemeClassMap = {
210
251
  success: 'bg-green-50 ring-green-600/20 text-green-700 dark:bg-green-600 dark:text-green-50 dark:ring-green-400/20',
@@ -215,13 +256,14 @@ const ThemeClassMap = {
215
256
  };
216
257
  const Badge = React.forwardRef((props, ref) => {
217
258
  const { theme = 'info', className = '', children, removable = false, rounded = false, onRemove = () => { }, ...restProps } = props;
218
- return (jsxRuntime.jsxs("span", { ref: ref, className: buildClassName(className, 'inline-flex items-center pl-3 py-1 text-xs font-medium ring-1 ring-inset', ThemeClassMap[theme], rounded ? 'rounded-full' : 'rounded-md'), ...restProps, children: [jsxRuntime.jsx("span", { className: "pr-3 inline-flex items-center", children: children }), removable ? (jsxRuntime.jsx(SvgX, { className: "size-5 px-0.5 mr-1 hover:bg-slate-200 dark:hover:bg-white/10 rounded-sm cursor-pointer", role: "button", onClick: () => onRemove() })) : null] }));
259
+ return (jsxRuntime.jsxs(TextContent, { ref: ref, className: buildClassName(className, 'inline-flex items-center pl-3 py-1 text-xs font-medium ring-1 ring-inset', ThemeClassMap[theme], rounded ? 'rounded-full' : 'rounded-md'), "data-testid": `badge-${theme}`, ...restProps, children: [jsxRuntime.jsx(TextContent, { className: "pr-3 inline-flex items-center", children: children }), removable ? (jsxRuntime.jsx(SvgX, { className: "size-5 px-0.5 mr-1 hover:bg-slate-200 dark:hover:bg-white/10 rounded-sm cursor-pointer text-gray-600 dark:text-gray-300", role: "button", onClick: () => onRemove() })) : null] }));
219
260
  });
261
+ Badge.displayName = 'Badge';
220
262
 
221
- var _path$8;
222
- function _extends$8() { return _extends$8 = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$8.apply(null, arguments); }
263
+ var _path$d;
264
+ function _extends$d() { return _extends$d = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$d.apply(null, arguments); }
223
265
  var SvgTriangleAlert = function SvgTriangleAlert(props) {
224
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$8({
266
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$d({
225
267
  xmlns: "http://www.w3.org/2000/svg",
226
268
  width: 24,
227
269
  height: 24,
@@ -232,15 +274,15 @@ var SvgTriangleAlert = function SvgTriangleAlert(props) {
232
274
  strokeWidth: 2,
233
275
  className: "lucide lucide-triangle-alert-icon lucide-triangle-alert",
234
276
  viewBox: "0 0 24 24"
235
- }, props), _path$8 || (_path$8 = /*#__PURE__*/React__namespace.createElement("path", {
277
+ }, props), _path$d || (_path$d = /*#__PURE__*/React__namespace.createElement("path", {
236
278
  d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3M12 9v4M12 17h.01"
237
279
  })));
238
280
  };
239
281
 
240
- var _circle$1, _path$7;
241
- function _extends$7() { return _extends$7 = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$7.apply(null, arguments); }
282
+ var _circle$1, _path$c;
283
+ function _extends$c() { return _extends$c = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$c.apply(null, arguments); }
242
284
  var SvgCircleCheck = function SvgCircleCheck(props) {
243
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$7({
285
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$c({
244
286
  xmlns: "http://www.w3.org/2000/svg",
245
287
  width: 24,
246
288
  height: 24,
@@ -255,12 +297,13 @@ var SvgCircleCheck = function SvgCircleCheck(props) {
255
297
  cx: 12,
256
298
  cy: 12,
257
299
  r: 10
258
- })), _path$7 || (_path$7 = /*#__PURE__*/React__namespace.createElement("path", {
300
+ })), _path$c || (_path$c = /*#__PURE__*/React__namespace.createElement("path", {
259
301
  d: "m9 12 2 2 4-4"
260
302
  })));
261
303
  };
262
304
 
263
305
  const sizeMap = {
306
+ 4: `size-4`,
264
307
  5: `size-5`,
265
308
  6: `size-6`,
266
309
  7: `size-7`,
@@ -275,14 +318,15 @@ const IconMap = {
275
318
  warning: SvgTriangleAlert,
276
319
  };
277
320
  const Banner = React.forwardRef((props, ref) => {
278
- const { type = 'info', iconSize = 5, children } = props;
279
- const className = buildClassName('text-sm banner rounded-md flex w-full p-3 mb-4 items-center', type === 'info' ? 'bg-blue-50 text-blue-700' : '', type === 'error' ? 'bg-red-50 text-red-700' : '', type === 'success' ? 'bg-green-50 text-green-700' : '', type === 'warning' ? 'bg-orange-50 border border-orange-200 text-orange-700' : '');
321
+ const { type = 'info', iconSize = 5, children, ...restProps } = props;
322
+ const className = buildClassName('text-sm banner rounded-md flex w-full p-3 items-center', type === 'info' ? 'bg-blue-50 text-blue-700' : '', type === 'error' ? 'bg-red-50 text-red-700' : '', type === 'success' ? 'bg-green-50 text-green-700' : '', type === 'warning' ? 'bg-orange-50 text-orange-700' : '');
280
323
  const renderIcon = () => {
281
324
  const Icon = IconMap[type];
282
- return jsxRuntime.jsx(Icon, { className: buildClassName('ml-1 mr-3', sizeMap[iconSize]) });
325
+ return (jsxRuntime.jsx(Icon, { "data-testid": `banner-${type}-icon`, className: buildClassName('ml-1 mr-3', sizeMap[iconSize]) }));
283
326
  };
284
- return (jsxRuntime.jsxs("div", { ref: ref, className: className, children: [renderIcon(), jsxRuntime.jsx("div", { className: "flex items-center w-full justify-between", children: children })] }));
327
+ return (jsxRuntime.jsxs("div", { ref: ref, className: className, "data-testid": `banner-${type}`, ...restProps, children: [renderIcon(), jsxRuntime.jsx("div", { className: "flex items-center w-full justify-between", children: children })] }));
285
328
  });
329
+ Banner.displayName = 'Banner';
286
330
 
287
331
  const BodyText = React.forwardRef((props, ref) => {
288
332
  const { as = 'p', small = false, strong = false, muted = false, error = false, inline = false, className, ...rest } = props;
@@ -292,11 +336,12 @@ const BodyText = React.forwardRef((props, ref) => {
292
336
  ...rest,
293
337
  });
294
338
  });
339
+ BodyText.displayName = 'BodyText';
295
340
 
296
- var _path$6;
297
- function _extends$6() { return _extends$6 = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$6.apply(null, arguments); }
341
+ var _path$b;
342
+ function _extends$b() { return _extends$b = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$b.apply(null, arguments); }
298
343
  var SvgSlash = function SvgSlash(props) {
299
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$6({
344
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$b({
300
345
  xmlns: "http://www.w3.org/2000/svg",
301
346
  width: 24,
302
347
  height: 24,
@@ -307,7 +352,7 @@ var SvgSlash = function SvgSlash(props) {
307
352
  strokeWidth: 2,
308
353
  className: "lucide lucide-slash-icon lucide-slash",
309
354
  viewBox: "0 0 24 24"
310
- }, props), _path$6 || (_path$6 = /*#__PURE__*/React__namespace.createElement("path", {
355
+ }, props), _path$b || (_path$b = /*#__PURE__*/React__namespace.createElement("path", {
311
356
  d: "M22 2 2 22"
312
357
  })));
313
358
  };
@@ -315,67 +360,156 @@ var SvgSlash = function SvgSlash(props) {
315
360
  const Breadcrumb = ({ items, render }) => {
316
361
  const count = items.length;
317
362
  const isLast = (index) => index === count - 1;
318
- return (jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2", children: items.map((item, index) => (jsxRuntime.jsxs("span", { className: "inline-flex gap-2 items-center dark:text-white", children: [isLast(index) ? jsxRuntime.jsx("span", { className: "font-medium", children: item.text }) : render(item), !isLast(index) && jsxRuntime.jsx(SvgSlash, { className: "size-4" })] }, item.key))) }));
363
+ return (jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2", "data-testid": "breadcrumb-container", children: items.map((item, index) => (jsxRuntime.jsxs("span", { className: "inline-flex gap-2 items-center dark:text-white", "data-testid": `breadcrumb-item-${item.key}`, children: [jsxRuntime.jsx("span", { className: "font-medium", children: isLast(index) ? item.text : render(item) }), !isLast(index) && (jsxRuntime.jsx(SvgSlash, { "data-testid": `breadcrumb-divider-${index}`, className: "size-4" }))] }, item.key))) }));
319
364
  };
365
+ Breadcrumb.displayName = 'Breadcrumb';
320
366
 
321
- const Card = React.forwardRef(({ className, as = 'div', hoverable = false, bordered = false, noPadding = false, ...rest }, ref) => React.createElement(as, {
322
- ref: ref,
323
- className: buildClassName('bg-white rounded-md dark:bg-gray-800', noPadding ? '' : 'p-2 md:p-4', hoverable && 'shadow hover:shadow-md transition-shadow duration-200', bordered && 'border border-gray-200 dark:border-gray-700', className),
324
- ...rest,
325
- }));
367
+ const BASE_CARD_CLASS = 'bg-white rounded-md dark:bg-gray-800';
368
+ const Card = React.forwardRef((props, ref) => {
369
+ // Remove Card-only props from rest (avoid leaking to DOM)
370
+ const { as: Element = 'div', hoverable = false, bordered = false, noPadding = false, ...rest } = props;
371
+ // Extract className safely from rest
372
+ const { className, ...cleanRest } = rest;
373
+ const classes = buildClassName(BASE_CARD_CLASS, !noPadding && 'p-2 md:p-4', hoverable && 'shadow hover:shadow-md transition-shadow duration-200', bordered && 'border border-gray-200 dark:border-gray-700', className);
374
+ return jsxRuntime.jsx(Element, { ref: ref, className: classes, ...cleanRest });
375
+ });
376
+ Card.displayName = 'Card';
326
377
 
327
378
  const Label = React.forwardRef((props, ref) => {
328
379
  const { className, children, ...labelProps } = props;
329
- return (jsxRuntime.jsx("label", { ref: ref, ...labelProps, className: buildClassName('block text-sm font-medium text-gray-500 dark:text-gray-400', className), children: children }));
380
+ return (jsxRuntime.jsx("label", { ref: ref, ...labelProps, className: buildClassName('block text-sm font-medium text-gray-600 dark:text-gray-300', className), children: children }));
330
381
  });
382
+ Label.displayName = 'Label';
331
383
 
332
384
  const Checkbox = React.forwardRef((props, ref) => {
333
- const { type, name, id = name, wrapperClass = '', containerClass = '', label = null, labelClass = '', error = null, disabled = false, className = '', ...checkboxProps } = props;
334
- return (jsxRuntime.jsxs("div", { className: buildClassName(wrapperClass), children: [jsxRuntime.jsxs("div", { className: buildClassName('flex items-center', containerClass), children: [jsxRuntime.jsxs("label", { className: buildClassName('inline-flex items-center relative', disabled ? 'cursor-not-allowed opacity-70' : 'cursor-pointer'), children: [jsxRuntime.jsx("input", { ref: ref, ...checkboxProps, id: id, name: name, type: "checkbox", disabled: disabled, className: buildClassName('peer size-4.5 cursor-pointer transition-all appearance-none rounded hover:shadow-md border border-gray-300 checked:bg-blue-600 checked:border-blue-600', 'bg-gray-50 dark:bg-gray-700', 'focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:focus:ring-offset-gray-900') }), jsxRuntime.jsx("span", { className: "absolute text-white opacity-0 peer-checked:opacity-100 top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2", children: jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-3.25 w-3.25", viewBox: "0 0 20 20", fill: "currentColor", stroke: "currentColor", strokeWidth: "1", children: jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) })] }), label && (jsxRuntime.jsx(Label, { htmlFor: id, className: `${disabled ? 'cursor-not-allowed' : 'cursor-pointer'} ml-2 font-normal text-gray-600 ${labelClass}`, children: label }))] }), error && jsxRuntime.jsx("div", { className: "mt-1 text-red-600 text-sm", children: error })] }));
385
+ var _a;
386
+ const { id, name, label, labelClass = '', wrapperClass = '', containerClass = '', error, disabled = false, className = '',
387
+ // Checkbox-only props removed from rest
388
+ ...rest } = props;
389
+ const checkboxId = (_a = id !== null && id !== void 0 ? id : name) !== null && _a !== void 0 ? _a : 'checkbox-' + Math.random();
390
+ return (jsxRuntime.jsxs("div", { className: buildClassName(wrapperClass), children: [jsxRuntime.jsxs("div", { className: buildClassName('flex items-center', containerClass), children: [jsxRuntime.jsxs("label", { htmlFor: checkboxId, className: buildClassName('inline-flex items-center relative select-none', disabled ? 'cursor-not-allowed opacity-70' : 'cursor-pointer'), children: [jsxRuntime.jsx("input", { ref: ref, ...rest, id: checkboxId, name: name, type: "checkbox", disabled: disabled, "aria-checked": rest.checked, className: buildClassName('peer size-4.5 cursor-pointer transition-all appearance-none rounded', 'border focus:ring-2 focus:ring-offset-2', 'checked:bg-blue-600 checked:border-blue-600', 'focus:ring-blue-500 dark:focus:ring-offset-gray-900', disabled
391
+ ? 'border-gray-200 dark:border-gray-700 bg-gray-100 dark:bg-gray-800 pointer-events-none'
392
+ : 'bg-white dark:bg-gray-700 border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500 hover:shadow-md', className) }), jsxRuntime.jsx("span", { className: "absolute text-white opacity-0 peer-checked:opacity-100 \n top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2", children: jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-3.25 w-3.25", viewBox: "0 0 20 20", fill: "currentColor", stroke: "currentColor", strokeWidth: "1", children: jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) })] }), label && (jsxRuntime.jsx(Label, { htmlFor: checkboxId, className: buildClassName(disabled
393
+ ? 'cursor-not-allowed text-gray-400 dark:text-gray-500'
394
+ : 'cursor-pointer text-gray-600 dark:text-gray-300', 'ml-2 font-normal', labelClass), children: label }))] }), error && (jsxRuntime.jsx("div", { className: "mt-1", children: jsxRuntime.jsx(TextContent, { error: true, small: true, children: error }) }))] }));
335
395
  });
396
+ Checkbox.displayName = 'Checkbox';
336
397
 
337
398
  const CheckboxGroup = (props) => {
338
- const { name, options, label = null, labelClass = '', labelWrapperClass = '', labelHint = null, containerClass = '', value = [], onChange, inline, } = props;
399
+ const { name, options, label, labelClass = '', labelWrapperClass = '', labelHint, containerClass = '', value = [], onChange, inline = false, } = props;
339
400
  const [items, setItems] = React.useState([]);
401
+ const groupId = React.useId(); // unique per group
402
+ /**
403
+ * Normalize options (strings → {label, value})
404
+ */
340
405
  React.useEffect(() => {
341
- setItems(() => options.map((option) => {
342
- if (typeof option === 'string') {
343
- return { label: option, value: option };
344
- }
345
- return option;
346
- }));
406
+ const normalized = options.map((opt) => typeof opt === 'string' ? { label: opt, value: opt } : opt);
407
+ setItems(normalized);
347
408
  }, [options]);
348
- return (jsxRuntime.jsxs("div", { className: buildClassName('mb-3 space-y-3', containerClass), children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, children: label }), jsxRuntime.jsx(BodyText, { muted: true, small: true, children: labelHint })] })), jsxRuntime.jsx("div", { className: buildClassName('flex gap-3', inline ? 'flex-wrap' : 'flex-col'), children: items.map((item) => (jsxRuntime.jsx(Checkbox, { label: item.label, value: item.value, checked: value.includes(item.value), name: name, id: item.value, onChange: onChange }, item.value))) })] }));
409
+ /**
410
+ * Group-level change handler. Converts raw checkbox change events
411
+ * into a typed updated values array.
412
+ */
413
+ const handleGroupChange = (e) => {
414
+ const raw = e.target.value;
415
+ const checked = e.target.checked;
416
+ // Convert HTML string value → typed T value
417
+ // Locate in normalized items
418
+ const matched = items.find((i) => String(i.value) === raw);
419
+ const itemValue = matched === null || matched === void 0 ? void 0 : matched.value;
420
+ let updated;
421
+ if (checked) {
422
+ updated = [...value, itemValue];
423
+ }
424
+ else {
425
+ updated = value.filter((v) => v !== itemValue);
426
+ }
427
+ onChange === null || onChange === void 0 ? void 0 : onChange(updated, e);
428
+ };
429
+ return (jsxRuntime.jsxs("div", { className: buildClassName('mb-3 space-y-3', containerClass), children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, children: label }), jsxRuntime.jsx(BodyText, { muted: true, small: true, children: labelHint })] })), jsxRuntime.jsx("div", { className: buildClassName('flex gap-3', inline ? 'flex-wrap' : 'flex-col'), children: items.map((item, index) => {
430
+ const key = typeof item.value === 'string' || typeof item.value === 'number' ? item.value : index;
431
+ return (jsxRuntime.jsx(Checkbox, { name: name, id: `${groupId}-${String(item.value)}`, label: item.label, value: String(item.value), checked: value.includes(item.value), onChange: handleGroupChange }, key));
432
+ }) })] }));
349
433
  };
434
+ CheckboxGroup.displayName = 'CheckboxGroup';
350
435
 
351
- const Title = ({ children, className }) => (jsxRuntime.jsx("h1", { className: buildClassName('text-3xl font-bold', className), children: children }));
352
- const SubTitle = ({ children, className }) => (jsxRuntime.jsx("h2", { className: buildClassName('text-2xl font-semibold', className), children: children }));
353
- const SubTitle2 = ({ children, className }) => (jsxRuntime.jsx("h3", { className: buildClassName('text-xl font-semibold', className), children: children }));
354
- const SubTitle3 = ({ children, className }) => (jsxRuntime.jsx("h4", { className: buildClassName('text-lg font-medium', className), children: children }));
355
- const SubTitle4 = ({ children, className }) => (jsxRuntime.jsx("h5", { className: buildClassName('text-base font-medium', className), children: children }));
356
- const HeadingText = {
357
- Title,
358
- SubTitle,
359
- SubTitle2,
360
- SubTitle3,
361
- SubTitle4,
436
+ const TEXT_ALIGN = {
437
+ left: 'text-left',
438
+ center: 'text-center',
439
+ right: 'text-right',
362
440
  };
363
-
364
- const DetailedInformation = ({ className, title, subTitle, details, compact = false, divider = true, titleClass, detailsClass, }) => {
365
- const hasTitles = title || subTitle;
366
- const filteredDetails = details.filter((detail) => !detail.hidden);
367
- return (jsxRuntime.jsxs("div", { className: buildClassName('p-2 md:p-4', compact ? 'md:p-2' : '', className), children: [hasTitles && (jsxRuntime.jsxs("div", { className: "px-4 sm:px-0 pt-2 sm:pt-0 mb-2", children: [title && (jsxRuntime.jsx(HeadingText.SubTitle2, { className: buildClassName(titleClass), children: title })), subTitle && (jsxRuntime.jsx("p", { className: "mt-1 max-w-2xl text-sm/6 text-gray-500 dark:text-gray-300", children: subTitle }))] })), filteredDetails.length ? (jsxRuntime.jsx("div", { className: buildClassName('border-gray-100 dark:border-gray-700', hasTitles && 'border-t', detailsClass), children: jsxRuntime.jsx("dl", { className: buildClassName(divider && 'divide-y divide-gray-100 dark:divide-gray-700'), children: filteredDetails.map((detail) => (jsxRuntime.jsxs("div", { className: buildClassName('px-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0 items-center', compact ? 'py-1.5' : 'py-2.5'), children: [jsxRuntime.jsx("dt", { className: "text-sm/6 font-medium text-gray-900 dark:text-gray-100", children: detail.label }), jsxRuntime.jsx("dd", { className: buildClassName('mt-1 text-sm/6 text-gray-700 dark:text-gray-300 sm:col-span-2 sm:mt-0', detail.contentClass), children: detail.value || '- -' })] }, detail.label))) }) })) : null] }));
441
+ const TABLE_LAYOUT = {
442
+ fixed: 'table-fixed',
443
+ auto: 'table-auto',
444
+ };
445
+ /* ----------------------------------------------
446
+ * Loader Rows
447
+ * ---------------------------------------------- */
448
+ const TableRowLoader = ({ colSize, rowSize }) => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: rowSize }).map((_, rowIdx) => (jsxRuntime.jsx(TableRow, { className: "animate-pulse", children: Array.from({ length: colSize }).map((_, colIdx) => (jsxRuntime.jsx(TableCell, { children: jsxRuntime.jsx("div", { className: "flex items-center h-6", children: jsxRuntime.jsx("div", { className: "h-4 bg-gray-300 dark:bg-gray-700 shimmer rounded w-full" }) }) }, colIdx))) }, rowIdx))) }));
449
+ /* ----------------------------------------------
450
+ * Table
451
+ * ---------------------------------------------- */
452
+ const Table = ({ children, layout = 'auto', className = '' }) => {
453
+ return (jsxRuntime.jsx("table", { className: buildClassName('border-collapse w-full divide-y divide-gray-200 dark:divide-gray-700', TABLE_LAYOUT[layout], className), children: children }));
368
454
  };
455
+ /* ----------------------------------------------
456
+ * Head
457
+ * ---------------------------------------------- */
458
+ const TableHead = ({ children, className = '' }) => (jsxRuntime.jsx("thead", { className: buildClassName('text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-800 dark:text-gray-300', className), children: jsxRuntime.jsx("tr", { children: children }) }));
459
+ /* ----------------------------------------------
460
+ * Body
461
+ * ---------------------------------------------- */
462
+ const TableBody = ({ children, loading, colSize, rowSize = 5, className, }) => (jsxRuntime.jsx("tbody", { className: buildClassName('text-sm text-gray-700 dark:text-white divide-y divide-gray-200 dark:divide-gray-700', className), children: loading ? jsxRuntime.jsx(TableRowLoader, { colSize: colSize, rowSize: rowSize }) : children }));
463
+ /* ----------------------------------------------
464
+ * Foot
465
+ * ---------------------------------------------- */
466
+ const TableFoot = ({ children }) => (jsxRuntime.jsx("tfoot", { children: jsxRuntime.jsx("tr", { children: children }) }));
467
+ /* ----------------------------------------------
468
+ * Rows
469
+ * ---------------------------------------------- */
470
+ const TableRow = ({ children, hoverable = false, className, ...props }) => (jsxRuntime.jsx("tr", { ...props, className: buildClassName('last:border-b border-gray-200 dark:border-gray-700', hoverable && 'group', className), children: children }));
471
+ /* ----------------------------------------------
472
+ * Cells
473
+ * ---------------------------------------------- */
474
+ const TableCell = ({ children, align = 'left', className, ...props }) => (jsxRuntime.jsx("td", { ...props, className: buildClassName('px-3 py-3 first:pl-4 last:pr-4 bg-white dark:bg-gray-900 group-hover:bg-gray-50 group-hover:dark:bg-gray-800', TEXT_ALIGN[align], className), children: jsxRuntime.jsx("div", { className: "leading-normal", children: children }) }));
475
+ const TableHeaderCell = ({ children, align = 'left', className, ...props }) => (jsxRuntime.jsx("th", { ...props, className: buildClassName('px-3 py-3 first:pl-4 last:pr-4 tracking-wider whitespace-nowrap text-gray-800 dark:text-gray-300', TEXT_ALIGN[align], className), children: jsxRuntime.jsx(BodyText, { as: "span", className: "leading-none", children: children }) }));
476
+ /* ----------------------------------------------
477
+ * Empty Row
478
+ * ---------------------------------------------- */
479
+ const EmptyTableRow = ({ children, colSpan = 1, contentClass, }) => (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: colSpan, className: "px-4 py-8", children: jsxRuntime.jsx("div", { className: buildClassName('p-6 text-center space-y-3 flex flex-col items-center justify-center', contentClass), children: children }) }) }));
369
480
 
370
- const Dot = ({ as = 'span', className, ...props }) => React.createElement(as, {
371
- className: buildClassName('inline-block rounded-full bg-gray-500 dark:bg-gray-300', 'w-1 h-1', className),
372
- ...props,
373
- });
481
+ const DOTS = '...';
482
+ const usePagination = ({ totalPages, currentPage, siblingCount = 1, // number of pages to show around currentPage
483
+ }) => {
484
+ const totalPageNumbers = siblingCount * 2 + 5;
485
+ if (totalPageNumbers >= totalPages) {
486
+ return Array.from({ length: totalPages }, (_, i) => i + 1);
487
+ }
488
+ const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);
489
+ const rightSiblingIndex = Math.min(currentPage + siblingCount, totalPages);
490
+ const shouldShowLeftDots = leftSiblingIndex > 2;
491
+ const shouldShowRightDots = rightSiblingIndex < totalPages - 1;
492
+ const firstPageIndex = 1;
493
+ const lastPageIndex = totalPages;
494
+ if (!shouldShowLeftDots && shouldShowRightDots) {
495
+ const leftRange = Array.from({ length: 3 + 2 * siblingCount }, (_, i) => i + 1);
496
+ return [...leftRange, DOTS, totalPages];
497
+ }
498
+ if (shouldShowLeftDots && !shouldShowRightDots) {
499
+ const rightRange = Array.from({ length: 3 + 2 * siblingCount }, (_, i) => totalPages - (3 + 2 * siblingCount) + 1 + i);
500
+ return [firstPageIndex, DOTS, ...rightRange];
501
+ }
502
+ if (shouldShowLeftDots && shouldShowRightDots) {
503
+ const middleRange = Array.from({ length: 2 * siblingCount + 1 }, (_, i) => leftSiblingIndex + i);
504
+ return [firstPageIndex, DOTS, ...middleRange, DOTS, lastPageIndex];
505
+ }
506
+ return [];
507
+ };
374
508
 
375
- var _path$5;
376
- function _extends$5() { return _extends$5 = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$5.apply(null, arguments); }
509
+ var _path$a;
510
+ function _extends$a() { return _extends$a = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$a.apply(null, arguments); }
377
511
  var SvgChevronLeft = function SvgChevronLeft(props) {
378
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$5({
512
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$a({
379
513
  xmlns: "http://www.w3.org/2000/svg",
380
514
  width: 24,
381
515
  height: 24,
@@ -386,48 +520,184 @@ var SvgChevronLeft = function SvgChevronLeft(props) {
386
520
  strokeWidth: 2,
387
521
  className: "lucide lucide-chevron-left-icon lucide-chevron-left",
388
522
  viewBox: "0 0 24 24"
389
- }, props), _path$5 || (_path$5 = /*#__PURE__*/React__namespace.createElement("path", {
523
+ }, props), _path$a || (_path$a = /*#__PURE__*/React__namespace.createElement("path", {
390
524
  d: "m15 18-6-6 6-6"
391
525
  })));
392
526
  };
393
527
 
394
- const alignmentMap = {
395
- center: 'items-center justify-center h-full',
396
- start: 'justify-start h-full',
397
- end: 'justify-end h-full',
398
- top: 'items-start',
399
- bottom: 'items-end h-full',
400
- 'top-center': 'items-center justify-center',
528
+ var _path$9;
529
+ function _extends$9() { return _extends$9 = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$9.apply(null, arguments); }
530
+ var SvgChevronRight = function SvgChevronRight(props) {
531
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$9({
532
+ xmlns: "http://www.w3.org/2000/svg",
533
+ width: 24,
534
+ height: 24,
535
+ fill: "none",
536
+ stroke: "currentColor",
537
+ strokeLinecap: "round",
538
+ strokeLinejoin: "round",
539
+ strokeWidth: 2,
540
+ className: "lucide lucide-chevron-right-icon lucide-chevron-right",
541
+ viewBox: "0 0 24 24"
542
+ }, props), _path$9 || (_path$9 = /*#__PURE__*/React__namespace.createElement("path", {
543
+ d: "m9 18 6-6-6-6"
544
+ })));
401
545
  };
402
- const panelAlignmentMap = {
403
- 'top-center': 'data-[closed]:transform-[translateY(-50%)] rounded-b-lg',
404
- center: 'data-[closed]:transform-[scale(95%)] rounded-lg',
405
- start: 'data-[closed]:transform-[translateX(-50%)] rounded-r-lg',
406
- end: 'data-[closed]:transform-[translateX(50%)] rounded-l-lg',
407
- top: 'data-[closed]:transform-[translateY(-50%)] rounded-b-lg',
408
- bottom: 'data-[closed]:transform-[translateY(50%)] rounded-t-lg',
546
+
547
+ const Pagination = ({ page: currentPage, limit, total, onChange, className, ellipsis = true, // Default to showing ellipsis
548
+ }) => {
549
+ const pages = new Array(Math.ceil(total / limit)).fill(null).map((_, i) => i + 1);
550
+ const isFirstPage = currentPage === 1;
551
+ const isLastPage = total === 0 || pages.length === currentPage;
552
+ const range = usePagination({ totalPages: pages.length, currentPage });
553
+ const handlePageChange = (nextVal) => {
554
+ if (nextVal === currentPage)
555
+ return;
556
+ onChange({ page: nextVal });
557
+ };
558
+ if (ellipsis) {
559
+ return (jsxRuntime.jsxs("div", { "data-testid": "pagination-container", className: buildClassName('flex items-center justify-between bg-white dark:bg-gray-800 px-4 py-3 sm:px-6', className), children: [jsxRuntime.jsxs("div", { className: "flex flex-1 justify-between sm:hidden", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "ellipsis-mobile-prev-btn", children: [jsxRuntime.jsx("span", { children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "ellipsis-mobile-next-btn", children: [jsxRuntime.jsx("span", { children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] }), jsxRuntime.jsxs("div", { className: "hidden sm:flex sm:flex-1 sm:items-center sm:justify-between", children: [jsxRuntime.jsxs("p", { "data-testid": "pagination-summary", className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1", children: ["Showing", jsxRuntime.jsx("span", { className: "font-medium", children: total === 0 ? 0 : Math.max(currentPage * limit - limit + 1, 1) }), "to", jsxRuntime.jsx("span", { className: "font-medium", children: Math.min(currentPage * limit, total) }), "of", jsxRuntime.jsx("span", { className: "font-medium", children: total }), "results"] }), jsxRuntime.jsxs("ul", { className: "flex items-center space-x-2 text-sm", children: [jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "ellipsis-next-btn", children: "Prev" }) }), range.map((page, idx) => {
560
+ if (page === DOTS) {
561
+ return (jsxRuntime.jsx("li", { "data-testid": `page-${page}`, className: "px-2 py-1 text-gray-400", children: "\u2026" }, `${page}-${idx}`));
562
+ }
563
+ return (jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: page === currentPage ? 'primary' : 'secondary', variant: page === currentPage ? 'default' : 'plain', "aria-current": page === currentPage ? 'page' : undefined, onClick: () => handlePageChange(page), children: page }) }, `${page}-${idx}`));
564
+ }), jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "ellipsis-prev-btn", children: "Next" }) })] })] })] }));
565
+ }
566
+ return (jsxRuntime.jsxs("div", { "data-testid": "pagination-container", className: buildClassName('flex items-center justify-between bg-white dark:bg-gray-800 px-4 py-3 sm:px-6', className), children: [jsxRuntime.jsxs("div", { className: "flex flex-1 justify-between sm:hidden", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "mobile-prev-btn", children: [jsxRuntime.jsx("span", { children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "mobile-next-btn", children: [jsxRuntime.jsx("span", { children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] }), jsxRuntime.jsxs("div", { className: "hidden sm:flex sm:flex-1 sm:items-center sm:justify-between", children: [jsxRuntime.jsxs("p", { "data-testid": "pagination-summary", className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1", children: ["Showing", jsxRuntime.jsx("span", { className: "font-medium", children: total === 0 ? 0 : Math.max(currentPage * limit - limit + 1, 1) }), "to", jsxRuntime.jsx("span", { className: "font-medium", children: Math.min(currentPage * limit, total) }), "of", jsxRuntime.jsx("span", { className: "font-medium", children: total }), "results"] }), jsxRuntime.jsxs("nav", { className: "isolate inline-flex items-center rounded-md", "aria-label": "Pagination", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "next-btn", children: [jsxRuntime.jsx("span", { className: "sr-only", children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), pages.map((page) => (jsxRuntime.jsx(Button, { size: "xs", theme: page === currentPage ? 'primary' : 'secondary', variant: page === currentPage ? 'default' : 'plain', "aria-current": page === currentPage ? 'page' : undefined, onClick: () => handlePageChange(page), children: jsxRuntime.jsx("span", { className: "size-4 block", children: page }) }, page))), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "prev-btn", children: [jsxRuntime.jsx("span", { className: "sr-only", children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] })] })] }));
409
567
  };
410
- const panelSizeMap = {
411
- xs: 'max-w-xs',
412
- sm: 'max-w-sm',
413
- md: 'max-w-md',
414
- lg: 'max-w-lg',
415
- xl: 'max-w-xl',
416
- '2xl': 'max-w-2xl',
417
- full: 'w-full',
568
+
569
+ function get(obj, path, defaultValue) {
570
+ var _a;
571
+ if (!path)
572
+ return defaultValue;
573
+ const keys = path
574
+ .replace(/\[(\d+)]/g, '.$1') // convert [0] to .0
575
+ .split('.')
576
+ .filter(Boolean); // remove empty parts
577
+ return ((_a = keys.reduce((acc, key) => {
578
+ if (acc !== null && acc !== undefined && Object.prototype.hasOwnProperty.call(acc, key)) {
579
+ return acc[key];
580
+ }
581
+ return undefined;
582
+ }, obj)) !== null && _a !== void 0 ? _a : defaultValue);
583
+ }
584
+
585
+ /**
586
+ * Compute the next sorting direction for a column.
587
+ * - string: undefined → asc → desc → undefined
588
+ * - number/date: undefined → 1 → -1 → undefined
589
+ */
590
+ const nextSortDirection = (prev, type = 'string') => {
591
+ if (type === 'string') {
592
+ if (!prev)
593
+ return 'asc';
594
+ if (prev === 'asc')
595
+ return 'desc';
596
+ return undefined;
597
+ }
598
+ // number / date
599
+ if (!prev)
600
+ return '1';
601
+ if (prev === '1')
602
+ return '-1';
603
+ return undefined;
418
604
  };
419
- const Drawer = ({ isOpen, onClose = () => { }, align = 'end', size = 'md', backdrop = true, title, description = null, children = null, panelClass = '', contentClass = '', titleClass = '', descriptionClass = '', titleSticky = false, showBackButton = false, }) => {
420
- return (jsxRuntime.jsxs(react.Dialog, { open: isOpen, as: "div", className: "relative z-15 focus:outline-none", onClose: onClose, children: [backdrop && jsxRuntime.jsx(react.DialogBackdrop, { className: "fixed inset-0 bg-black/20" }), jsxRuntime.jsx("div", { className: buildClassName('fixed inset-0 z-15 w-screen h-screen h-dvh'), children: jsxRuntime.jsx("div", { className: buildClassName('flex', alignmentMap[align]), children: jsxRuntime.jsxs(react.DialogPanel, { transition: true, className: buildClassName('w-full bg-white dark:bg-gray-800 backdrop-blur-2xl duration-200 ease-out data-[closed]:opacity-0 shadow-sm overflow-y-auto space-y-4', panelAlignmentMap[align], panelSizeMap[size], panelClass), children: [jsxRuntime.jsxs("div", { className: buildClassName('space-y-2 pt-2 md:pt-4 px-4 md:px-6', titleSticky && 'sticky top-0 bg-white dark:bg-gray-800 z-10'), children: [jsxRuntime.jsxs(react.DialogTitle, { as: "h3", className: buildClassName('text-lg/7 font-medium dark:text-white flex items-center gap-2', titleClass), children: [showBackButton && (jsxRuntime.jsx(Button, { iconOnly: true, variant: "plain", theme: "secondary", size: "sm", onClick: onClose, children: jsxRuntime.jsx(SvgChevronLeft, { className: "size-5" }) })), title] }), description && (jsxRuntime.jsx("p", { className: buildClassName('text-sm/6 dark:text-white/50', descriptionClass), children: description }))] }), jsxRuntime.jsx("div", { className: buildClassName(contentClass), children: children })] }) }) })] }));
605
+ /**
606
+ * Update the sort query object for a table column.
607
+ * Toggles sort direction, removing key when reset.
608
+ */
609
+ const updateSortQuery = (sortQuery, name, type = 'string') => {
610
+ const next = nextSortDirection(sortQuery[name], type);
611
+ // Shallow clone once
612
+ const updated = { ...sortQuery };
613
+ if (next == null) {
614
+ delete updated[name];
615
+ }
616
+ else {
617
+ updated[name] = next;
618
+ }
619
+ return updated;
421
620
  };
422
621
 
423
- const DROPDOWN_ITEM_CLASS = 'flex w-full px-3 py-2 cursor-pointer hover:bg-gray-50 rounded-lg';
424
- const Dropdown = ({ triggerButton, items, renderItem, itemsContainerClass, transition = true, anchor = 'bottom start', }) => {
425
- return (jsxRuntime.jsxs(react.Menu, { children: [jsxRuntime.jsx(react.MenuButton, { as: React.Fragment, children: triggerButton }), jsxRuntime.jsx(react.MenuItems, { transition: transition, anchor: anchor, className: buildClassName('w-52 origin-top-right rounded-xl border border-gray-100 bg-white shadow-sm p-1 text-sm/6 text-gray-800 transition duration-100 ease-out [--anchor-gap:--spacing(1)] focus:outline-none data-closed:scale-95 data-closed:opacity-0', itemsContainerClass), children: items.map((item) => (jsxRuntime.jsx(react.MenuItem, { children: item.divider ? (jsxRuntime.jsx("div", { className: "my-1 h-px bg-gray-200 dark:bg-white/5" })) : (renderItem(item, { className: DROPDOWN_ITEM_CLASS })) }, item.id))) })] }));
622
+ var _path$8;
623
+ function _extends$8() { return _extends$8 = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$8.apply(null, arguments); }
624
+ var SvgArrowDownWideNarrow = function SvgArrowDownWideNarrow(props) {
625
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$8({
626
+ xmlns: "http://www.w3.org/2000/svg",
627
+ width: 24,
628
+ height: 24,
629
+ fill: "none",
630
+ stroke: "currentColor",
631
+ strokeLinecap: "round",
632
+ strokeLinejoin: "round",
633
+ strokeWidth: 2,
634
+ className: "lucide lucide-arrow-down-wide-narrow-icon lucide-arrow-down-wide-narrow",
635
+ viewBox: "0 0 24 24"
636
+ }, props), _path$8 || (_path$8 = /*#__PURE__*/React__namespace.createElement("path", {
637
+ d: "m3 16 4 4 4-4M7 20V4M11 4h10M11 8h7M11 12h4"
638
+ })));
639
+ };
640
+
641
+ var _path$7;
642
+ function _extends$7() { return _extends$7 = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$7.apply(null, arguments); }
643
+ var SvgArrowDownNarrowWide = function SvgArrowDownNarrowWide(props) {
644
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$7({
645
+ xmlns: "http://www.w3.org/2000/svg",
646
+ width: 24,
647
+ height: 24,
648
+ fill: "none",
649
+ stroke: "currentColor",
650
+ strokeLinecap: "round",
651
+ strokeLinejoin: "round",
652
+ strokeWidth: 2,
653
+ className: "lucide lucide-arrow-down-narrow-wide-icon lucide-arrow-down-narrow-wide",
654
+ viewBox: "0 0 24 24"
655
+ }, props), _path$7 || (_path$7 = /*#__PURE__*/React__namespace.createElement("path", {
656
+ d: "m3 16 4 4 4-4M7 20V4M11 4h4M11 8h7M11 12h10"
657
+ })));
658
+ };
659
+
660
+ var _path$6;
661
+ function _extends$6() { return _extends$6 = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$6.apply(null, arguments); }
662
+ var SvgArrowDownAz = function SvgArrowDownAz(props) {
663
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$6({
664
+ xmlns: "http://www.w3.org/2000/svg",
665
+ width: 24,
666
+ height: 24,
667
+ fill: "none",
668
+ stroke: "currentColor",
669
+ strokeLinecap: "round",
670
+ strokeLinejoin: "round",
671
+ strokeWidth: 2,
672
+ className: "lucide lucide-arrow-down-az-icon lucide-arrow-down-a-z",
673
+ viewBox: "0 0 24 24"
674
+ }, props), _path$6 || (_path$6 = /*#__PURE__*/React__namespace.createElement("path", {
675
+ d: "m3 16 4 4 4-4M7 20V4M20 8h-5M15 10V6.5a2.5 2.5 0 0 1 5 0V10M15 14h5l-5 6h5"
676
+ })));
677
+ };
678
+
679
+ var _path$5;
680
+ function _extends$5() { return _extends$5 = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$5.apply(null, arguments); }
681
+ var SvgArrowDownZa = function SvgArrowDownZa(props) {
682
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$5({
683
+ xmlns: "http://www.w3.org/2000/svg",
684
+ width: 24,
685
+ height: 24,
686
+ fill: "none",
687
+ stroke: "currentColor",
688
+ strokeLinecap: "round",
689
+ strokeLinejoin: "round",
690
+ strokeWidth: 2,
691
+ className: "lucide lucide-arrow-down-za-icon lucide-arrow-down-z-a",
692
+ viewBox: "0 0 24 24"
693
+ }, props), _path$5 || (_path$5 = /*#__PURE__*/React__namespace.createElement("path", {
694
+ d: "m3 16 4 4 4-4M7 4v16M15 4h5l-5 6h5M15 20v-3.5a2.5 2.5 0 0 1 5 0V20M20 18h-5"
695
+ })));
426
696
  };
427
697
 
428
698
  var _path$4;
429
699
  function _extends$4() { return _extends$4 = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$4.apply(null, arguments); }
430
- var SvgFolderPlus = function SvgFolderPlus(props) {
700
+ var SvgArrowUpDown = function SvgArrowUpDown(props) {
431
701
  return /*#__PURE__*/React__namespace.createElement("svg", _extends$4({
432
702
  xmlns: "http://www.w3.org/2000/svg",
433
703
  width: 24,
@@ -437,56 +707,137 @@ var SvgFolderPlus = function SvgFolderPlus(props) {
437
707
  strokeLinecap: "round",
438
708
  strokeLinejoin: "round",
439
709
  strokeWidth: 2,
440
- className: "lucide lucide-folder-plus-icon lucide-folder-plus",
710
+ className: "lucide lucide-arrow-up-down-icon lucide-arrow-up-down",
441
711
  viewBox: "0 0 24 24"
442
712
  }, props), _path$4 || (_path$4 = /*#__PURE__*/React__namespace.createElement("path", {
443
- d: "M12 10v6M9 13h6M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"
713
+ d: "m21 16-4 4-4-4M17 20V4M3 8l4-4 4 4M7 4v16"
444
714
  })));
445
715
  };
446
716
 
447
- const EmptyState = ({ title, description, className, action = null, }) => {
448
- return (jsxRuntime.jsx("div", { className: buildClassName('w-full flex justify-center px-4 pt-16', className), children: jsxRuntime.jsxs("div", { className: "max-w-md flex flex-col items-center gap-4", children: [jsxRuntime.jsx(SvgFolderPlus, { className: "size-8" }), jsxRuntime.jsx(HeadingText.SubTitle, { children: title }), description && (jsxRuntime.jsx(BodyText, { as: "p", className: "text-center", muted: true, small: true, children: description })), action] }) }));
717
+ const SortIconMap = {
718
+ '1': (jsxRuntime.jsx(SvgArrowDownNarrowWide, { className: "size-4 text-gray-400 shrink-0 group-hover:text-gray-800 dark:group-hover:text-white" })),
719
+ asc: (jsxRuntime.jsx(SvgArrowDownAz, { className: "size-4 text-gray-400 shrink-0 group-hover:text-gray-800 dark:group-hover:text-white" })),
720
+ '-1': (jsxRuntime.jsx(SvgArrowDownWideNarrow, { className: "size-4 text-gray-400 shrink-0 group-hover:text-gray-800 dark:group-hover:text-white" })),
721
+ desc: (jsxRuntime.jsx(SvgArrowDownZa, { className: "size-4 text-gray-400 shrink-0 group-hover:text-gray-800 dark:group-hover:text-white" })),
449
722
  };
723
+ const getSortIcon = (sort) => sort ? (SortIconMap[sort]) : (jsxRuntime.jsx(SvgArrowUpDown, { className: "size-4 text-gray-400 shrink-0 group-hover:text-gray-800 dark:group-hover:text-white" }));
450
724
 
451
- const Input = React.forwardRef((props, ref) => {
452
- const { name, id = name, type, label = null, labelHint = null, className = '', labelClass = '', labelWrapperClass = '', containerClass = '', error, showErrorMessage = true, rightGroup = null, leftGroup = null, autoComplete = 'off', ...inputProps } = props;
453
- const hasError = Boolean(error);
454
- const hasRightGroup = rightGroup != null && React.isValidElement(rightGroup);
455
- const hasLeftGroup = leftGroup != null && React.isValidElement(leftGroup);
456
- return (jsxRuntime.jsxs("div", { className: buildClassName('group', hasError && 'has-error', containerClass), children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between mb-2', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, htmlFor: id, children: label }), labelHint] })), jsxRuntime.jsxs("div", { className: "relative", children: [hasLeftGroup && (jsxRuntime.jsx("span", { className: "absolute top-0 h-full flex items-center justify-center w-10", children: leftGroup })), jsxRuntime.jsx("input", { ref: ref, ...inputProps, name: name, id: id, type: type, autoComplete: autoComplete, className: buildClassName('transition-all', 'block w-full rounded-lg bg-white px-3.5 py-2 text-base sm:text-sm/6', 'text-gray-900 outline dark:outline outline-1 -outline-offset-1', 'outline-gray-300 dark:outline-gray-600', 'focus:outline-blue-600 dark:focus:outline-blue-600 focus:outline-2 focus:-outline-offset-2', 'dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-500 placeholder:text-gray-400 dark:text-white', 'invalid:group-[.has-error]:outline-red-500', 'disabled:pointer-events-none', 'dark:disabled:bg-gray-500 disabled:bg-gray-100', hasRightGroup ? 'pe-10' : '', hasLeftGroup ? 'ps-10' : '', className) }), hasRightGroup && (jsxRuntime.jsx("span", { className: "absolute end-0.75 top-0 h-full flex items-center justify-center w-10", children: rightGroup }))] }), showErrorMessage && error && (jsxRuntime.jsx("p", { className: "mt-1 text-red-500 dark:text-red-500 text-sm", children: error }))] }));
725
+ /**
726
+ * Smart auto-sort helper (optional usage)
727
+ */
728
+ const autoSortItems = (items, column, sort) => {
729
+ const path = column.name;
730
+ return [...items].sort((a, b) => {
731
+ const valueA = get(a, path);
732
+ const valueB = get(b, path);
733
+ if (column.type === 'number') {
734
+ const nA = Number(valueA);
735
+ const nB = Number(valueB);
736
+ return sort === 'asc' || sort === '1' ? nA - nB : nB - nA;
737
+ }
738
+ if (column.type === 'date') {
739
+ const dA = new Date(valueA).getTime();
740
+ const dB = new Date(valueB).getTime();
741
+ return sort === 'asc' || sort === '1' ? dA - dB : dB - dA;
742
+ }
743
+ // String fallback
744
+ const sA = String(valueA).toLowerCase();
745
+ const sB = String(valueB).toLowerCase();
746
+ if (sA < sB)
747
+ return sort === 'asc' || sort === '1' ? -1 : 1;
748
+ if (sA > sB)
749
+ return sort === 'asc' || sort === '1' ? 1 : -1;
750
+ return 0;
751
+ });
752
+ };
753
+ const DataTable = ({ items, columns, sorting = {}, onSort, loading, pagination = null, setPagination = () => { }, emptyMessage = 'No data found', containerClass = '', wrapperClass = '', layout = 'auto', }) => {
754
+ const internalSorting = React.useRef({});
755
+ const doAutoSort = (column) => {
756
+ internalSorting.current = updateSortQuery(internalSorting.current, column.name, column.type);
757
+ autoSortItems(items, column, internalSorting.current[column.name]);
758
+ };
759
+ const handleSort = (column) => {
760
+ if (!column.sortable)
761
+ return;
762
+ onSort ? onSort(column) : doAutoSort(column);
763
+ };
764
+ return (jsxRuntime.jsxs("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: [jsxRuntime.jsx("div", { className: buildClassName('overflow-x-auto overflow-y-hidden rounded-lg border border-gray-200 dark:border-gray-800', wrapperClass, pagination && 'rounded-b-none border-b-0'), children: jsxRuntime.jsxs(Table, { className: "relative w-full max-w-full h-fit", layout: layout, children: [jsxRuntime.jsx(TableHead, { children: columns.map((column) => (jsxRuntime.jsx(TableHeaderCell, { align: column.headerAlign, style: { width: column.width || 'auto' }, className: buildClassName('bg-gray-50 dark:bg-gray-800', column.sticky === 'left' &&
765
+ 'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
766
+ 'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]'), children: jsxRuntime.jsxs(TextContent, { role: column.sortable ? 'button' : undefined, className: buildClassName('group', column.sortable && 'inline-flex items-center gap-2 cursor-pointer select-none'), onClick: () => handleSort(column), children: [jsxRuntime.jsx(TextContent, { className: "shrink-0", children: column.label }), column.sortable ? getSortIcon(sorting[column.name]) : null] }) }, column.name))) }), jsxRuntime.jsx(TableBody, { loading: loading, colSize: columns.length, rowSize: (pagination === null || pagination === void 0 ? void 0 : pagination.limit) || 5, children: !loading && items.length === 0 ? (jsxRuntime.jsx(EmptyTableRow, { colSpan: columns.length, children: emptyMessage })) : (items.map((item) => (jsxRuntime.jsx(TableRow, { className: "group", children: columns.map((column) => {
767
+ var _a;
768
+ return (jsxRuntime.jsx(TableCell, { align: column.align, className: buildClassName(column.sticky === 'left' &&
769
+ 'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
770
+ 'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]'), children: column.render
771
+ ? column.render(item)
772
+ : ((_a = get(item, column.name)) !== null && _a !== void 0 ? _a : 'Not set') }, column.name));
773
+ }) }, item.id)))) })] }) }), pagination && (jsxRuntime.jsx(Pagination, { ...pagination, className: "rounded-b-lg border border-t-0 border-gray-200 dark:border-gray-800", onChange: setPagination }))] }));
774
+ };
775
+ DataTable.displayName = 'DataTable';
776
+
777
+ const Title = ({ children, className }) => (jsxRuntime.jsx("h1", { className: buildClassName('text-3xl font-bold', className), children: children }));
778
+ const SubTitle = ({ children, className }) => (jsxRuntime.jsx("h2", { className: buildClassName('text-2xl font-semibold', className), children: children }));
779
+ const SubTitle2 = ({ children, className }) => (jsxRuntime.jsx("h3", { className: buildClassName('text-xl font-semibold', className), children: children }));
780
+ const SubTitle3 = ({ children, className }) => (jsxRuntime.jsx("h4", { className: buildClassName('text-lg font-medium', className), children: children }));
781
+ const SubTitle4 = ({ children, className }) => (jsxRuntime.jsx("h5", { className: buildClassName('text-base font-medium', className), children: children }));
782
+ const HeadingText = {
783
+ Title,
784
+ SubTitle,
785
+ SubTitle2,
786
+ SubTitle3,
787
+ SubTitle4,
788
+ };
789
+
790
+ const DetailedInformation = React.forwardRef((props, ref) => {
791
+ const { className, title, subTitle, details, compact = false, divider = true, titleClass, detailsClass, ...divProps } = props;
792
+ const hasTitles = title || subTitle;
793
+ const filteredDetails = details.filter((detail) => !detail.hidden);
794
+ return (jsxRuntime.jsxs("div", { className: buildClassName('p-2 md:p-4', compact ? 'md:p-2' : '', className), ref: ref, ...divProps, children: [hasTitles && (jsxRuntime.jsxs("div", { className: "px-4 sm:px-0 pt-2 sm:pt-0 mb-2", children: [title && (jsxRuntime.jsx(HeadingText.SubTitle2, { className: buildClassName(titleClass), children: title })), subTitle && (jsxRuntime.jsx("p", { className: "mt-1 max-w-2xl text-sm/6 text-gray-500 dark:text-gray-300", children: subTitle }))] })), filteredDetails.length ? (jsxRuntime.jsx("div", { className: buildClassName('border-gray-100 dark:border-gray-700', hasTitles && 'border-t', detailsClass), children: jsxRuntime.jsx("dl", { className: buildClassName(divider && 'divide-y divide-gray-100 dark:divide-gray-700'), children: filteredDetails.map((detail) => (jsxRuntime.jsxs("div", { className: buildClassName('px-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0 items-center', compact ? 'py-1.5' : 'py-2.5'), children: [jsxRuntime.jsx("dt", { className: "text-sm/6 font-medium text-gray-900 dark:text-gray-100", children: detail.label }), jsxRuntime.jsx("dd", { className: buildClassName('mt-1 text-sm/6 text-gray-700 dark:text-gray-300 sm:col-span-2 sm:mt-0', detail.contentClass), children: detail.value || '- -' })] }, detail.label))) }) })) : null] }));
457
795
  });
796
+ DetailedInformation.displayName = 'DetailedInformation';
458
797
 
459
- const DOTS = '...';
460
- const usePagination = ({ totalPages, currentPage, siblingCount = 1, // number of pages to show around currentPage
461
- }) => {
462
- const totalPageNumbers = siblingCount * 2 + 5;
463
- if (totalPageNumbers >= totalPages) {
464
- return Array.from({ length: totalPages }, (_, i) => i + 1);
465
- }
466
- const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);
467
- const rightSiblingIndex = Math.min(currentPage + siblingCount, totalPages);
468
- const shouldShowLeftDots = leftSiblingIndex > 2;
469
- const shouldShowRightDots = rightSiblingIndex < totalPages - 1;
470
- const firstPageIndex = 1;
471
- const lastPageIndex = totalPages;
472
- if (!shouldShowLeftDots && shouldShowRightDots) {
473
- const leftRange = Array.from({ length: 3 + 2 * siblingCount }, (_, i) => i + 1);
474
- return [...leftRange, DOTS, totalPages];
475
- }
476
- if (shouldShowLeftDots && !shouldShowRightDots) {
477
- const rightRange = Array.from({ length: 3 + 2 * siblingCount }, (_, i) => totalPages - (3 + 2 * siblingCount) + 1 + i);
478
- return [firstPageIndex, DOTS, ...rightRange];
479
- }
480
- if (shouldShowLeftDots && shouldShowRightDots) {
481
- const middleRange = Array.from({ length: 2 * siblingCount + 1 }, (_, i) => leftSiblingIndex + i);
482
- return [firstPageIndex, DOTS, ...middleRange, DOTS, lastPageIndex];
483
- }
484
- return [];
798
+ const Dot = ({ as = 'span', className, ...props }) => React.createElement(as, {
799
+ className: buildClassName('inline-block rounded-full bg-gray-500 dark:bg-gray-300', 'w-1 h-1', className),
800
+ ...props,
801
+ });
802
+
803
+ const alignmentMap = {
804
+ center: 'items-center justify-center h-full',
805
+ start: 'justify-start h-full',
806
+ end: 'justify-end h-full',
807
+ top: 'items-center justify-center',
808
+ bottom: 'items-end justify-center h-full',
485
809
  };
810
+ const panelAlignmentMap = {
811
+ center: 'data-[closed]:scale-95 rounded-lg',
812
+ start: 'data-[closed]:-translate-x-1/2 rounded-r-lg',
813
+ end: 'data-[closed]:translate-x-1/2 rounded-l-lg',
814
+ top: 'data-[closed]:-translate-y-1/2 rounded-b-lg',
815
+ bottom: 'data-[closed]:translate-y-1/2 rounded-t-lg',
816
+ };
817
+ const panelSizeMap = {
818
+ xs: 'max-w-xs',
819
+ sm: 'max-w-sm',
820
+ md: 'max-w-md',
821
+ lg: 'max-w-lg',
822
+ xl: 'max-w-xl',
823
+ '2xl': 'max-w-2xl',
824
+ full: 'w-full',
825
+ };
826
+ const Drawer = ({ isOpen, onClose = () => { }, align = 'end', size = 'md', backdrop = true, title, description, children, panelClass = '', contentClass = '', titleClass = '', descriptionClass = '', titleSticky = false, showBackButton = false, }) => {
827
+ const showTitleSection = Boolean(title || description);
828
+ return (jsxRuntime.jsxs(react.Dialog, { open: isOpen, as: "div", className: "relative z-50 focus:outline-none", onClose: onClose, transition: true, children: [backdrop && jsxRuntime.jsx(react.DialogBackdrop, { className: "fixed inset-0 bg-black/20 transition-opacity" }), jsxRuntime.jsx("div", { className: "fixed inset-0 w-screen h-screen", children: jsxRuntime.jsx("div", { className: buildClassName('flex', alignmentMap[align]), children: jsxRuntime.jsxs(react.DialogPanel, { transition: true, className: buildClassName('w-full bg-white dark:bg-gray-800 backdrop-blur-2xl shadow-sm', 'overflow-y-auto space-y-4 duration-200 ease-out data-[closed]:opacity-0', panelAlignmentMap[align], panelSizeMap[size], panelClass), children: [showTitleSection && (jsxRuntime.jsxs("div", { className: buildClassName('space-y-2 pt-2 md:pt-4 px-4 md:px-6', titleSticky && 'sticky top-0 bg-white dark:bg-gray-800 z-10'), children: [jsxRuntime.jsxs(react.DialogTitle, { as: "h3", className: buildClassName('text-lg font-medium dark:text-white flex items-center gap-2', titleClass), children: [showBackButton && (jsxRuntime.jsx(Button, { iconOnly: true, variant: "plain", theme: "secondary", size: "sm", onClick: onClose, children: jsxRuntime.jsx(SvgChevronLeft, { className: "size-5" }) })), title] }), description && (jsxRuntime.jsx("p", { className: buildClassName('text-sm dark:text-white/60', descriptionClass), children: description }))] })), jsxRuntime.jsx("div", { className: contentClass, children: children })] }) }) })] }));
829
+ };
830
+ Drawer.displayName = 'Drawer';
831
+
832
+ const BASE_ITEM_CLASS = 'flex w-full px-3 py-2 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700 rounded-lg';
833
+ const Dropdown = ({ triggerButton, renderTriggerButton, items, renderItem, itemsContainerClass, transition = true, anchor = 'bottom start', menuItemClass, onMenuClick, }) => {
834
+ return (jsxRuntime.jsxs(react.Menu, { as: "div", className: "relative inline-block", children: [renderTriggerButton ? (jsxRuntime.jsx(react.MenuButton, { as: React.Fragment, children: (state) => renderTriggerButton(state) })) : (jsxRuntime.jsx(react.MenuButton, { as: React.Fragment, children: triggerButton })), jsxRuntime.jsx(react.MenuItems, { transition: transition, anchor: anchor, className: buildClassName('w-52 origin-top-right rounded-xl shadow-sm p-1 text-sm transition duration-100 ease-out', 'border border-gray-100 bg-white text-gray-800', 'dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200', 'focus:outline-none data-[closed]:scale-95 data-[closed]:opacity-0', '[--anchor-gap:--spacing(1)]', itemsContainerClass), "data-testid": "dropdown-items", as: "ul", children: items.map((item, idx) => (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx(react.MenuItem, { as: "li", disabled: item.disabled, children: ({ disabled }) => (jsxRuntime.jsx("div", { onClick: () => !disabled && (onMenuClick === null || onMenuClick === void 0 ? void 0 : onMenuClick(item, idx)), className: buildClassName(BASE_ITEM_CLASS, menuItemClass, disabled && 'cursor-not-allowed opacity-70'), "data-testid": `dropdown-item-${item.id}`, children: renderItem ? renderItem(item) : item.label })) }), item.divider && (jsxRuntime.jsx("li", { className: "my-1 h-px bg-gray-200 dark:bg-white/5", "data-testid": "dropdown-divider" }, item.id))] }, item.id))) })] }));
835
+ };
836
+ Dropdown.displayName = 'Dropdown';
486
837
 
487
838
  var _path$3;
488
839
  function _extends$3() { return _extends$3 = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$3.apply(null, arguments); }
489
- var SvgChevronRight = function SvgChevronRight(props) {
840
+ var SvgFolderPlus = function SvgFolderPlus(props) {
490
841
  return /*#__PURE__*/React__namespace.createElement("svg", _extends$3({
491
842
  xmlns: "http://www.w3.org/2000/svg",
492
843
  width: 24,
@@ -496,35 +847,33 @@ var SvgChevronRight = function SvgChevronRight(props) {
496
847
  strokeLinecap: "round",
497
848
  strokeLinejoin: "round",
498
849
  strokeWidth: 2,
499
- className: "lucide lucide-chevron-right-icon lucide-chevron-right",
850
+ className: "lucide lucide-folder-plus-icon lucide-folder-plus",
500
851
  viewBox: "0 0 24 24"
501
852
  }, props), _path$3 || (_path$3 = /*#__PURE__*/React__namespace.createElement("path", {
502
- d: "m9 18 6-6-6-6"
853
+ d: "M12 10v6M9 13h6M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"
503
854
  })));
504
855
  };
505
856
 
506
- const Pagination = ({ page: currentPage, limit, total, onChange, className, ellipsis = true, // Default to showing ellipsis
507
- }) => {
508
- const pages = new Array(Math.ceil(total / limit)).fill(null).map((_, i) => i + 1);
509
- const isFirstPage = currentPage === 1;
510
- const isLastPage = total === 0 || pages.length === currentPage;
511
- const range = usePagination({ totalPages: pages.length, currentPage });
512
- const handlePageChange = (nextVal) => {
513
- if (nextVal === currentPage)
514
- return;
515
- onChange({ page: nextVal });
516
- };
517
- if (ellipsis) {
518
- return (jsxRuntime.jsx("div", { className: buildClassName('flex items-center justify-between bg-white dark:bg-gray-800 px-4 py-3 sm:px-6', className), children: jsxRuntime.jsxs("div", { className: "hidden sm:flex sm:flex-1 sm:items-center sm:justify-between", children: [jsxRuntime.jsxs("p", { className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1", children: ["Showing", jsxRuntime.jsx("span", { className: "font-medium", children: total === 0 ? 0 : Math.max(currentPage * limit - limit + 1, 1) }), "to", jsxRuntime.jsx("span", { className: "font-medium", children: Math.min(currentPage * limit, total) }), "of", jsxRuntime.jsx("span", { className: "font-medium", children: total }), "results"] }), jsxRuntime.jsxs("ul", { className: "flex items-center space-x-2 text-sm", children: [jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), children: "Prev" }) }), range.map((page, idx) => {
519
- if (page === DOTS) {
520
- return (jsxRuntime.jsx("li", { className: "px-2 py-1 text-gray-400", children: "\u2026" }, page + idx));
521
- }
522
- return (jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: page === currentPage ? 'primary' : 'secondary', variant: page === currentPage ? 'default' : 'plain', "aria-current": page === currentPage ? 'page' : undefined, onClick: () => handlePageChange(page), children: page }, page) }, page));
523
- }), jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), children: "Next" }) })] })] }) }));
524
- }
525
- return (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between bg-white dark:bg-gray-800 px-4 py-3 sm:px-6', className), children: [jsxRuntime.jsxs("div", { className: "flex flex-1 justify-between sm:hidden", children: [jsxRuntime.jsx("a", { href: "#", className: "relative inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50", children: "Previous" }), jsxRuntime.jsx("a", { href: "#", className: "relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50", children: "Next" })] }), jsxRuntime.jsxs("div", { className: "hidden sm:flex sm:flex-1 sm:items-center sm:justify-between", children: [jsxRuntime.jsxs("p", { className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1", children: ["Showing", jsxRuntime.jsx("span", { className: "font-medium", children: total === 0 ? 0 : Math.max(currentPage * limit - limit + 1, 1) }), "to", jsxRuntime.jsx("span", { className: "font-medium", children: Math.min(currentPage * limit, total) }), "of", jsxRuntime.jsx("span", { className: "font-medium", children: total }), "results"] }), jsxRuntime.jsxs("nav", { className: "isolate inline-flex items-center rounded-md", "aria-label": "Pagination", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), children: [jsxRuntime.jsx("span", { className: "sr-only", children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), pages.map((page) => (jsxRuntime.jsx(Button, { size: "xs", theme: page === currentPage ? 'primary' : 'secondary', variant: page === currentPage ? 'default' : 'plain', "aria-current": page === currentPage ? 'page' : undefined, onClick: () => handlePageChange(page), children: jsxRuntime.jsx("span", { className: "size-4 block", children: page }) }, page))), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), children: [jsxRuntime.jsx("span", { className: "sr-only", children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] })] })] }));
857
+ const EmptyState = ({ title, description, className, action = null, }) => {
858
+ return (jsxRuntime.jsx("div", { className: buildClassName('w-full flex justify-center px-4 pt-16', className), children: jsxRuntime.jsxs("div", { className: "max-w-md flex flex-col items-center gap-4", children: [jsxRuntime.jsx(SvgFolderPlus, { className: "size-8" }), jsxRuntime.jsx(HeadingText.SubTitle, { children: title }), description && (jsxRuntime.jsx(BodyText, { as: "p", className: "text-center", muted: true, small: true, children: description })), action] }) }));
526
859
  };
527
860
 
861
+ function buildInputClass(className, { isFocusWithin = false, disabled = false } = {}) {
862
+ return buildClassName('transition-all', 'block w-full rounded-lg bg-white px-3.5 py-2 text-base sm:text-sm/6', 'text-gray-900 outline outline-1 -outline-offset-1', 'outline-gray-300 dark:outline-gray-600', 'invalid:group-[.has-error]:outline-red-500', disabled
863
+ ? 'pointer-events-none bg-gray-100 dark:bg-gray-800 dark:text-gray-600 dark:placeholder-gray-600 placeholder-gray-400 outline-gray-200 dark:outline-gray-700'
864
+ : 'bg-white dark:bg-gray-700 dark:text-white outline-gray-300 dark:outline-gray-600 dark:placeholder-gray-400 placeholder-gray-400', isFocusWithin
865
+ ? 'focus-within:outline-blue-600 dark:focus-within:outline-blue-600 focus-within:outline-2 focus-within:-outline-offset-2'
866
+ : 'focus:outline-blue-600 dark:focus:outline-blue-600 focus:outline-2 focus:-outline-offset-2', className);
867
+ }
868
+ const Input = React.forwardRef((props, ref) => {
869
+ const { name, id = name, type, label, labelHint, className, labelClass, labelWrapperClass, containerClass, error, showErrorMessage = true, rightGroup, leftGroup, ...inputProps } = props;
870
+ const hasError = Boolean(error);
871
+ const hasRightGroup = rightGroup !== null && rightGroup !== undefined;
872
+ const hasLeftGroup = leftGroup != null && leftGroup !== undefined;
873
+ return (jsxRuntime.jsxs("div", { className: buildClassName('group', hasError && 'has-error', containerClass), children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between mb-2', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, htmlFor: id, children: label }), labelHint] })), jsxRuntime.jsxs("div", { className: "relative", children: [hasLeftGroup && (jsxRuntime.jsx("span", { className: "absolute top-0 h-full flex items-center justify-center w-10", children: leftGroup })), jsxRuntime.jsx("input", { ref: ref, autoComplete: "off", ...inputProps, name: name, id: id, type: type, className: buildClassName(buildInputClass(className), hasRightGroup ? 'pe-10' : '', hasLeftGroup ? 'ps-10' : '') }), hasRightGroup && (jsxRuntime.jsx("span", { className: "absolute end-0.75 top-0 h-full flex items-center justify-center w-10", children: rightGroup }))] }), showErrorMessage && error && (jsxRuntime.jsx("div", { className: "mt-1", children: jsxRuntime.jsx(TextContent, { error: true, small: true, children: error }) }))] }));
874
+ });
875
+ Input.displayName = 'Input';
876
+
528
877
  const PASSWORD_TYPE = 'password';
529
878
  const PASSWORD_PLACEHOLDER = '••••••••••';
530
879
  const PasswordInput = (props) => {
@@ -533,13 +882,21 @@ const PasswordInput = (props) => {
533
882
  return (jsxRuntime.jsx(Input, { ...inputProps, type: showPassword ? 'text' : PASSWORD_TYPE, placeholder: PASSWORD_PLACEHOLDER, rightGroup: jsxRuntime.jsx(Button, { theme: "secondary", variant: "plain", size: "xs", className: "px-1 mr-1", type: "button", onClick: () => setShowPassword(() => !showPassword), tabIndex: -1, children: showPassword ? (jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", className: "size-4", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88" }) })) : (jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", className: "size-4", children: [jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" }), jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" })] })) }) }));
534
883
  };
535
884
 
536
- const RadioButton = React.forwardRef((props, ref) => {
537
- const { type = 'radio', name, id = name, wrapperClass = '', containerClass = '', label = null, labelClass = '', labelHint = null, error = null, ...radioProps } = props;
538
- return (jsxRuntime.jsxs("div", { className: buildClassName(wrapperClass), children: [jsxRuntime.jsxs("div", { className: buildClassName('flex items-center gap-2', containerClass), children: [jsxRuntime.jsx("div", { className: "grid place-items-center", children: jsxRuntime.jsx("input", { ref: ref, ...radioProps, type: "radio", id: id, name: name, className: "peer transition-all col-start-1 row-start-1 appearance-none shrink-0 size-4.5 border-1 border-gray-300 focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 checked:border-5 checked:border-blue-600 rounded-full bg-white" }) }), label && (jsxRuntime.jsx(Label, { htmlFor: id, className: buildClassName('cursor-pointer font-normal text-gray-600', labelClass), children: label }))] }), error && jsxRuntime.jsx("div", { className: "mt-1 text-red-600 text-sm", children: error })] }));
885
+ const Radio = React.forwardRef((props, ref) => {
886
+ var _a;
887
+ const { id, name, label, labelClass = '', wrapperClass = '', containerClass = '', error, disabled = false, className = '',
888
+ // RadioButton-only props removed from rest
889
+ ...rest } = props;
890
+ const radioId = (_a = id !== null && id !== void 0 ? id : name) !== null && _a !== void 0 ? _a : 'checkbox-' + Math.random();
891
+ return (jsxRuntime.jsxs("div", { className: buildClassName(wrapperClass), children: [jsxRuntime.jsxs("div", { className: buildClassName('flex items-center gap-2', containerClass), children: [jsxRuntime.jsx("div", { className: "grid place-items-center", children: jsxRuntime.jsx("input", { ref: ref, ...rest, id: radioId, name: name, type: "radio", disabled: disabled, "aria-selected": rest.checked, className: buildClassName('peer transition-all col-start-1 row-start-1 appearance-none shrink-0 size-4.5 rounded-full', 'border focus:ring-2 focus:ring-offset-2', 'checked:border-5 checked:bg-white', 'focus:ring-blue-500 checked:focus:ring-blue-600 dark:focus:ring-offset-gray-800', disabled
892
+ ? 'border-gray-200 dark:border-gray-700 bg-gray-100 dark:bg-gray-800 pointer-events-none'
893
+ : buildClassName('bg-white dark:bg-gray-700 border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500', 'checked:border-blue-600 checked:hover:border-blue-600 dark:checked:border-blue-600 dark:checked:hover:border-blue-600'), className) }) }), label && (jsxRuntime.jsx(Label, { htmlFor: radioId, className: buildClassName(disabled
894
+ ? 'cursor-not-allowed text-gray-400 dark:text-gray-500'
895
+ : 'cursor-pointer text-gray-600 dark:text-gray-300', labelClass), children: label }))] }), error && (jsxRuntime.jsx("div", { className: "mt-1", children: jsxRuntime.jsx(TextContent, { error: true, small: true, children: error }) }))] }));
539
896
  });
540
897
 
541
- const RadioButtonGroup = (props) => {
542
- const { name, label = null, labelClass = '', labelWrapperClass = '', labelHint = null, containerClass = '', options, value, row, onChange, } = props;
898
+ const RadioGroup = (props) => {
899
+ const { name, label, labelClass, labelWrapperClass, labelHint, containerClass, options, value, row, error, showErrorMessage, onChange, } = props;
543
900
  const [items, setItems] = React.useState([]);
544
901
  React.useEffect(() => {
545
902
  setItems(() => {
@@ -551,46 +908,45 @@ const RadioButtonGroup = (props) => {
551
908
  });
552
909
  });
553
910
  }, [options]);
554
- return (jsxRuntime.jsxs("div", { className: buildClassName(containerClass), children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between mb-4', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, children: label }), labelHint] })), jsxRuntime.jsx("div", { className: buildClassName('flex gap-2', row ? 'flex-row items-center' : 'flex-col items-start'), children: items.map((item) => (jsxRuntime.jsx(RadioButton, { name: name, id: item.value, label: item.label, value: item.value, checked: value === item.value, onChange: onChange }, item.value))) })] }));
555
- };
556
-
557
- const RadioSwitch = ({ label, items, selected, onChange }) => {
558
- const getLabel = (item) => {
559
- return typeof item === 'string' ? item : item.label;
560
- };
561
- const getValue = (item) => {
562
- return typeof item === 'string' ? item : item.value;
563
- };
564
- const getDescription = (item) => {
565
- return typeof item === 'string' ? '' : item.description || '';
566
- };
567
- return (jsxRuntime.jsx(react.RadioGroup, { value: selected, onChange: onChange, "aria-label": label, className: "flex items-center bg-white rounded-full shadow-xs p-1 dark:bg-gray-800 gap-1 border border-gray-200 dark:border-gray-700", children: items.map((item) => (jsxRuntime.jsx(react.Radio, { value: getValue(item), className: buildClassName('group relative flex cursor-pointer transition', 'text-gray-500 dark:text-gray-300', 'focus:not-data-focus:outline-none data-focus:outline data-focus:outline-white'), children: jsxRuntime.jsx("div", { className: buildClassName('dark:text-white justify-between px-3 py-1 transition', 'group-data-checked:bg-blue-600 group-data-checked:text-white rounded-full'), children: jsxRuntime.jsxs("div", { className: "text-sm/6", children: [jsxRuntime.jsx("p", { className: "font-semibold dark:text-white", children: getLabel(item) }), item.description && (jsxRuntime.jsx("div", { className: "flex gap-2 text-white/50", children: getDescription(item) }))] }) }) }, getValue(item)))) }));
911
+ return (jsxRuntime.jsxs("div", { className: buildClassName(containerClass), children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between mb-4', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, children: label }), labelHint] })), jsxRuntime.jsx("div", { className: buildClassName('flex gap-4', row ? 'flex-row items-center' : 'flex-col items-start'), children: items.map((item) => (jsxRuntime.jsx(Radio, { name: name, id: `${name}-${item.value}`, label: item.label, value: item.value, checked: value === item.value, onChange: onChange }, item.value))) }), showErrorMessage && error && (jsxRuntime.jsx("div", { className: "mt-1", children: jsxRuntime.jsx(TextContent, { error: true, small: true, children: error }) }))] }));
568
912
  };
569
913
 
570
- const RangeInput = (props) => {
571
- const { name, id = name, label = null, labelClass = '', labelWrapperClass = '', labelHint = null, containerClass = '', min = 0, max = 0, value, onChange, ...rangeProps } = props;
572
- const handleRangeChange = (e) => {
573
- const { value: _value = '0', name: _name } = e.target;
574
- let changedValue = parseInt(_value);
575
- let nextValue = {
576
- ...props.value,
577
- [_name]: changedValue,
578
- };
579
- if (e.target.name === 'max' && (value === null || value === void 0 ? void 0 : value.min) && changedValue < parseInt(value.min || '0')) {
580
- nextValue[_name] = parseInt(value.min);
581
- }
582
- if (e.target.name === 'min' && (value === null || value === void 0 ? void 0 : value.max) && changedValue > parseInt(value.max || '0')) {
583
- nextValue[_name] = parseInt(value.max);
584
- }
585
- onChange &&
586
- onChange({
587
- target: {
588
- name,
589
- value: nextValue,
590
- },
591
- });
592
- };
593
- return (jsxRuntime.jsxs("div", { className: buildClassName('mb-3 relative', containerClass), children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between mb-4', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, htmlFor: id, children: label }), labelHint] })), jsxRuntime.jsxs("div", { className: "flex w-full gap-4 items-center", children: [jsxRuntime.jsx(Input, { ...rangeProps, id: id, name: "min", type: "number", min: min, max: value === null || value === void 0 ? void 0 : value.max, value: (value === null || value === void 0 ? void 0 : value.min) || '', className: "appearance-none", containerClass: "flex-1 shrink-0 mb-0", placeholder: "Min", onChange: handleRangeChange }), jsxRuntime.jsx("span", { children: "to" }), jsxRuntime.jsx(Input, { ...rangeProps, id: id, name: "max", type: "number", min: value === null || value === void 0 ? void 0 : value.min, max: max, value: (value === null || value === void 0 ? void 0 : value.max) || '', className: "appearance-none", containerClass: "flex-1 shrink-0 mb-0", placeholder: "Max", onChange: handleRangeChange, disabled: !(value === null || value === void 0 ? void 0 : value.min) })] })] }));
914
+ /**
915
+ * GPU-accelerated Radio Switch with perfect highlight alignment.
916
+ * Supports wrapping, icons, descriptions, and dark mode.
917
+ */
918
+ const RadioSwitch = ({ label, items, selected, onChange, wrapperClass, switchClass, contentClass, descriptionClass, }) => {
919
+ const containerRef = React.useRef(null);
920
+ const [style, setStyle] = React.useState({ left: 0, top: 0, width: 0, height: 0 });
921
+ const getLabel = (i) => (typeof i === 'string' ? i : i.label);
922
+ const getValue = (i) => (typeof i === 'string' ? i : i.value);
923
+ const getDescription = (i) => { var _a; return typeof i === 'string' ? '' : ((_a = i.description) !== null && _a !== void 0 ? _a : ''); };
924
+ /** ---------------------------------------------
925
+ * Update highlight when selected changes
926
+ * ----------------------------------------------*/
927
+ React.useEffect(() => {
928
+ if (!containerRef.current)
929
+ return;
930
+ const buttons = Array.from(containerRef.current.querySelectorAll('[data-radio-item]'));
931
+ const el = buttons.find((b) => b.dataset.value === selected);
932
+ if (!el)
933
+ return;
934
+ const rect = el.getBoundingClientRect();
935
+ const parentRect = containerRef.current.getBoundingClientRect();
936
+ const left = rect.left - parentRect.left;
937
+ const top = rect.top - parentRect.top;
938
+ setStyle({
939
+ left,
940
+ top,
941
+ width: rect.width,
942
+ height: rect.height,
943
+ });
944
+ }, [selected, items]);
945
+ return (jsxRuntime.jsxs(react.RadioGroup, { value: selected, onChange: onChange, "aria-label": label, ref: containerRef, className: buildClassName('relative flex flex-wrap gap-1', 'transition-colors duration-200 overflow-hidden', wrapperClass), children: [jsxRuntime.jsx("div", { className: buildClassName('absolute rounded-md bg-blue-600 dark:bg-blue-500', 'transition-transform transition-size duration-300 ease-[cubic-bezier(.25,.8,.25,1)]', switchClass), style: {
946
+ transform: `translate(${style.left}px, ${style.top}px)`,
947
+ width: style.width,
948
+ height: style.height,
949
+ } }), items.map((item) => (jsxRuntime.jsx(react.Radio, { value: getValue(item), "data-radio-item": true, "data-value": getValue(item), className: buildClassName('relative z-10 cursor-pointer select-none group', 'px-4 py-2 rounded-md transition-colors', 'text-gray-700 dark:text-gray-300 data-checked:text-white'), children: jsxRuntime.jsxs("div", { className: buildClassName('flex flex-col items-center justify-center gap-1', contentClass), children: [jsxRuntime.jsx(BodyText, { className: "font-semibold", children: getLabel(item) }), getDescription(item) && (jsxRuntime.jsx(BodyText, { className: buildClassName('text-xs opacity-80', descriptionClass), children: getDescription(item) }))] }) }, getValue(item))))] }));
594
950
  };
595
951
 
596
952
  /**
@@ -621,6 +977,104 @@ function isEmpty(value) {
621
977
  return false; // for numbers, booleans, functions, etc.
622
978
  }
623
979
 
980
+ // export interface RangeInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {
981
+ // label?: string
982
+ // labelClass?: string
983
+ // labelHint?: React.ReactNode
984
+ // containerClass?: string
985
+ // showValue?: boolean
986
+ // valueSuffix?: string
987
+ // error?: string | null
988
+ // showErrorMessage?: boolean
989
+ // }
990
+ const RangeInput = React.forwardRef((props, ref) => {
991
+ const { label, labelClass = '', labelHint = null, containerClass = '', className = '', showValue = true, valueSuffix = '', error = null, showErrorMessage = true, id, min = 0, max = 100, value, ...inputProps } = props;
992
+ const hasError = !isEmpty(error);
993
+ return (jsxRuntime.jsxs("div", { className: buildClassName('group space-y-2', containerClass), children: [label && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [jsxRuntime.jsx(Label, { htmlFor: id, className: labelClass, children: label }), labelHint] })), jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx("input", { ref: ref, type: "range", id: id, min: min, max: max, value: value, ...inputProps, className: buildClassName('w-full h-2 rounded-lg appearance-none cursor-pointer', 'bg-gray-200 dark:bg-gray-700', 'accent-blue-600', // for WebKit
994
+ '[&::-webkit-slider-thumb]:appearance-none', '[&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4', '[&::-webkit-slider-thumb]:rounded-full', '[&::-webkit-slider-thumb]:bg-blue-600', '[&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4', '[&::-moz-range-thumb]:rounded-full', '[&::-moz-range-thumb]:bg-blue-600', hasError && 'accent-red-600', className) }), showValue && (jsxRuntime.jsxs("span", { className: "text-sm text-gray-600 dark:text-gray-300 min-w-[3rem] text-right", children: [value, valueSuffix] }))] }), showErrorMessage && hasError && (jsxRuntime.jsx("div", { className: "mt-1", children: jsxRuntime.jsx(TextContent, { error: true, small: true, children: error }) }))] }));
995
+ });
996
+
997
+ const RangeSlider = ({ label, labelHint, labelClass = '', containerClass = '', className = '', min, max, valueMin, valueMax, onChange, valueSuffix = '', error = null, showErrorMessage = true, }) => {
998
+ const trackRef = React.useRef(null);
999
+ // Refs for drag logic
1000
+ const activeThumbRef = React.useRef(null);
1001
+ // State for UI styling
1002
+ const [activeThumbState, setActiveThumbState] = React.useState(null);
1003
+ const hasError = !isEmpty(error);
1004
+ const percent = (v) => ((v - min) / (max - min)) * 100;
1005
+ // ---------------------------------------------
1006
+ // Pointer Move (drag)
1007
+ // ---------------------------------------------
1008
+ const pointerMoveHandler = (e) => {
1009
+ if (!trackRef.current || !activeThumbRef.current)
1010
+ return;
1011
+ const rect = trackRef.current.getBoundingClientRect();
1012
+ const x = Math.min(Math.max(e.clientX - rect.left, 0), rect.width);
1013
+ const rawVal = min + (x / rect.width) * (max - min);
1014
+ if (activeThumbRef.current === 'min') {
1015
+ onChange(Math.min(rawVal, valueMax - 1), valueMax);
1016
+ }
1017
+ else {
1018
+ onChange(valueMin, Math.max(rawVal, valueMin + 1));
1019
+ }
1020
+ };
1021
+ const pointerUpHandler = () => {
1022
+ activeThumbRef.current = null;
1023
+ setActiveThumbState(null);
1024
+ window.removeEventListener('pointermove', pointerMoveHandler);
1025
+ window.removeEventListener('pointerup', pointerUpHandler);
1026
+ };
1027
+ const startDrag = (thumb) => (e) => {
1028
+ activeThumbRef.current = thumb;
1029
+ setActiveThumbState(thumb);
1030
+ window.addEventListener('pointermove', pointerMoveHandler);
1031
+ window.addEventListener('pointerup', pointerUpHandler);
1032
+ };
1033
+ // ---------------------------------------------
1034
+ // Click Track to move closest thumb
1035
+ // ---------------------------------------------
1036
+ const handleTrackClick = (e) => {
1037
+ if (!trackRef.current)
1038
+ return;
1039
+ const rect = trackRef.current.getBoundingClientRect();
1040
+ const x = Math.min(Math.max(e.clientX - rect.left, 0), rect.width);
1041
+ const rawVal = min + (x / rect.width) * (max - min);
1042
+ const pxMin = (percent(valueMin) / 100) * rect.width;
1043
+ const pxMax = (percent(valueMax) / 100) * rect.width;
1044
+ // If click is left of min thumb → move min thumb
1045
+ if (x <= pxMin) {
1046
+ onChange(rawVal, valueMax);
1047
+ return;
1048
+ }
1049
+ // If click is right of max thumb → move max thumb
1050
+ if (x >= pxMax) {
1051
+ onChange(valueMin, rawVal);
1052
+ return;
1053
+ }
1054
+ // Else click is between → move closest thumb
1055
+ const distMin = Math.abs(rawVal - valueMin);
1056
+ const distMax = Math.abs(rawVal - valueMax);
1057
+ if (distMin < distMax) {
1058
+ onChange(rawVal, valueMax);
1059
+ }
1060
+ else {
1061
+ onChange(valueMin, rawVal);
1062
+ }
1063
+ };
1064
+ return (jsxRuntime.jsxs("div", { className: buildClassName('group space-y-2', hasError && 'has-error', containerClass), children: [label && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-1", children: [jsxRuntime.jsx(Label, { className: labelClass, children: label }), labelHint] })), jsxRuntime.jsxs("div", { ref: trackRef, onMouseDown: handleTrackClick, className: "relative h-8 select-none w-full", "data-testid": "range-track", children: [jsxRuntime.jsx("div", { className: "absolute top-1/2 left-0 right-0 h-2 rounded-full bg-gray-200 dark:bg-gray-700 -translate-y-1/2" }), jsxRuntime.jsx("div", { className: "absolute top-1/2 h-2 bg-blue-600 dark:bg-blue-500 -translate-y-1/2 rounded-full \n transition-all duration-150 ease-out", style: {
1065
+ left: `${percent(valueMin)}%`,
1066
+ width: `${percent(valueMax) - percent(valueMin)}%`,
1067
+ } }), jsxRuntime.jsx("div", { onPointerDown: startDrag('min'), className: buildClassName('absolute top-1/2 -translate-y-1/2 h-5 w-5 rounded-full', 'bg-white border-2 border-blue-600 shadow-md cursor-pointer touch-none', 'transition-all duration-150 ease-out', // animation
1068
+ activeThumbState === 'min' && 'ring-4 ring-blue-200', className), style: {
1069
+ left: `calc(${percent(valueMin)}% - 10px)`,
1070
+ zIndex: activeThumbState === 'min' ? 50 : 30,
1071
+ }, "data-testid": "thumb-min" }), jsxRuntime.jsx("div", { onPointerDown: startDrag('max'), className: buildClassName('absolute top-1/2 -translate-y-1/2 h-5 w-5 rounded-full', 'bg-white border-2 border-blue-600 shadow-md cursor-pointer touch-none', 'transition-all duration-150 ease-out', // animation
1072
+ activeThumbState === 'max' && 'ring-4 ring-blue-200', className), style: {
1073
+ left: `calc(${percent(valueMax)}% - 10px)`,
1074
+ zIndex: activeThumbState === 'max' ? 50 : 40,
1075
+ }, "data-testid": "thumb-max" })] }), jsxRuntime.jsxs("div", { className: "flex justify-between text-sm text-gray-700 dark:text-gray-300", children: [jsxRuntime.jsxs("span", { children: [Math.round(valueMin), valueSuffix] }), jsxRuntime.jsxs("span", { children: [Math.round(valueMax), valueSuffix] })] }), showErrorMessage && hasError && (jsxRuntime.jsx("div", { className: "mt-1", children: jsxRuntime.jsx(TextContent, { error: true, small: true, children: error }) }))] }));
1076
+ };
1077
+
624
1078
  const useDebounce = (value, delay) => {
625
1079
  const [debouncedValue, setDebouncedValue] = React.useState(value);
626
1080
  React.useEffect(() => {
@@ -634,6 +1088,13 @@ const useDebounce = (value, delay) => {
634
1088
  }, [value, delay]);
635
1089
  return debouncedValue;
636
1090
  };
1091
+ const useDebounceFn = (fn, ms) => {
1092
+ const timeout = React.useRef(null);
1093
+ return React.useCallback((...args) => {
1094
+ clearTimeout(timeout.current);
1095
+ timeout.current = setTimeout(() => fn(...args), ms);
1096
+ }, [fn, ms]);
1097
+ };
637
1098
 
638
1099
  var _path$2;
639
1100
  function _extends$2() { return _extends$2 = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends$2.apply(null, arguments); }
@@ -696,196 +1157,954 @@ var SvgCirclePlus = function SvgCirclePlus(props) {
696
1157
  })));
697
1158
  };
698
1159
 
699
- const constructInputClass = (disabled) => buildClassName('transition-all', 'block w-full rounded-lg px-3.5 py-2 text-base sm:text-sm/6', 'text-gray-900 outline dark:outline outline-1 -outline-offset-1', 'outline-gray-300 dark:outline-gray-600', 'focus:outline-blue-600 dark:focus:outline-blue-600 focus:outline-2 focus:-outline-offset-2', 'dark:border-gray-600 dark:placeholder-gray-500 placeholder:text-gray-400 dark:text-white', 'group-[.has-error]:outline-red-600 group-[.has-error]:focus:outline-red-600', '[&:has(:focus-visible)]:outline-2 [&:has(:focus-visible)]:outline-blue-600', 'group-[.has-error]:[&:has(:focus-visible)]:outline-red-600', disabled ? 'pointer-events-none bg-gray-100 dark:bg-gray-500' : 'bg-white dark:bg-gray-700');
700
- const SelectBox = (props) => {
1160
+ const constructInputClass = (disabled) => buildInputClass('', { disabled });
1161
+ const SelectBox = React.forwardRef((props, forwardedRef) => {
701
1162
  const { labelKey = 'label', valueKey = 'value', name, id = name, options, selected, label = null, labelWrapperClass = '', labelClass = '', labelHint = null, disabled = false, containerClass = '', onChange = () => { }, placeholder, dropdownContainerClass = 'z-20', multiple = false, maxSelection, immediate = true, showErrorMessage = true, error = null, async = false, searchable = true, required = false, allowAdd = false, addNewText = 'Create', onAdd = () => { }, allowClear = false, } = props;
702
1163
  const hasError = Boolean(error);
703
1164
  const [query, setQuery] = React.useState('');
704
1165
  const debouncedQuery = useDebounce(query, 500);
705
1166
  const [optionsLoading, setOptionsLoading] = React.useState(false);
706
- const shouldShowTypeToSearch = async && !debouncedQuery && !options.length;
707
- const inputClass = constructInputClass(disabled);
1167
+ const shouldShowTypeToSearch = async && !query && !optionsLoading && options.length === 0;
1168
+ const inputClass = React.useMemo(() => constructInputClass(disabled), [disabled]);
1169
+ const chevronIconClass = buildClassName('size-4', 'stroke-gray-500 group-data-[hover]:stroke-gray-800', 'dark:stroke-gray-300 dark:group-data-[hover]:stroke-gray-100', disabled && 'dark:stroke-gray-600 stroke-gray-400');
708
1170
  const inputRef = React.useRef(null);
709
- const filteredOptions = query === '' || async
710
- ? options
711
- : options.filter((option) => {
712
- if (typeof option === 'string')
713
- return option.toLowerCase().includes(query.toLowerCase());
714
- return option[labelKey].toLowerCase().includes(query.toLowerCase());
1171
+ const containerRef = React.useRef(null);
1172
+ // Expose the input element to parent
1173
+ React.useImperativeHandle(forwardedRef, () => inputRef.current, [inputRef]);
1174
+ const filteredOptions = React.useMemo(() => {
1175
+ if (query === '' || async)
1176
+ return options;
1177
+ return options.filter((opt) => {
1178
+ const label = typeof opt === 'string' ? opt : opt[labelKey];
1179
+ return label === null || label === void 0 ? void 0 : label.toLowerCase().includes(query.toLowerCase());
715
1180
  });
716
- const getDisplayValue = (option) => {
717
- return typeof option === 'string' ? option : option[labelKey];
718
- };
719
- const getValue = (option) => {
720
- return typeof option === 'string' ? option : option[valueKey];
721
- };
1181
+ }, [options, query, async, labelKey]);
1182
+ const getDisplayValue = React.useCallback((opt) => {
1183
+ return typeof opt === 'string' ? opt : opt[labelKey];
1184
+ }, [labelKey]);
1185
+ const getValue = React.useCallback((opt) => {
1186
+ return typeof opt === 'string' ? opt : opt[valueKey];
1187
+ }, [valueKey]);
722
1188
  const removeSelection = (idx) => {
723
- if (!isArray(selected)) {
1189
+ var _a;
1190
+ if (!isArray(selected))
724
1191
  return;
725
- }
726
- const nextSelectedValue = [...selected];
727
- nextSelectedValue.splice(idx, 1);
728
- onChange(nextSelectedValue);
1192
+ const next = [...selected];
1193
+ next.splice(idx, 1);
1194
+ onChange(next);
1195
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
729
1196
  };
730
- const handleOnChange = (value) => {
731
- let nextValue = !value ? (multiple ? [] : {}) : value;
732
- if (multiple && isArray(selected)) {
733
- if (maxSelection && selected.length >= maxSelection) {
1197
+ // A strongly-typed internal handler (what you expect callers to receive)
1198
+ const handleOnChangeInternal = React.useCallback((value) => {
1199
+ // normal empty value
1200
+ if (value === null) {
1201
+ onChange(multiple ? [] : null);
1202
+ setQuery('');
1203
+ return;
1204
+ }
1205
+ // enforce maxSelection
1206
+ if (multiple && Array.isArray(value) && maxSelection && value.length > maxSelection) {
1207
+ // ignore the change
1208
+ return;
1209
+ }
1210
+ onChange(value);
1211
+ setQuery('');
1212
+ }, [onChange, multiple, maxSelection]);
1213
+ /**
1214
+ * Headless UI typings are overly broad (they include null[] and EnsureArray<T> etc).
1215
+ * We therefore pass a wrapper to the Combobox with a cast (only at the call site),
1216
+ * while keeping our internal logic strongly typed.
1217
+ */
1218
+ const comboboxOnChangeWrapper = React.useCallback((raw) => {
1219
+ // normalize actual runtime shapes Headless UI uses: T | T[] | null
1220
+ if (raw === null || raw === undefined) {
1221
+ handleOnChangeInternal(null);
1222
+ return;
1223
+ }
1224
+ if (Array.isArray(raw)) {
1225
+ // sometimes union typing suggests arrays of nulls — guard it
1226
+ const allNulls = raw.length > 0 && raw.every((v) => v === null);
1227
+ if (allNulls) {
1228
+ handleOnChangeInternal([]);
734
1229
  return;
735
1230
  }
1231
+ // cast array to T[]
1232
+ handleOnChangeInternal(raw);
1233
+ return;
736
1234
  }
737
- onChange(nextValue);
738
- setQuery('');
739
- };
1235
+ // single value
1236
+ handleOnChangeInternal(raw);
1237
+ }, [handleOnChangeInternal]);
1238
+ // support create (allowAdd) as a real ComboboxOption
1239
+ const handleAddAndSelect = React.useCallback(async (valueToAdd) => {
1240
+ try {
1241
+ const result = await onAdd(valueToAdd);
1242
+ // if the parent returned a new option (string or object), select it
1243
+ if (result) {
1244
+ // If parent returned raw string or object, call onChange with that
1245
+ handleOnChangeInternal(result);
1246
+ }
1247
+ else {
1248
+ // if parent didn't return anything, select the raw string value
1249
+ handleOnChangeInternal(valueToAdd);
1250
+ }
1251
+ }
1252
+ catch (err) {
1253
+ // eslint-disable-next-line no-console
1254
+ console.error('onAdd handler error', err);
1255
+ }
1256
+ }, [onAdd, handleOnChangeInternal]);
740
1257
  const handleSearch = async (searchString) => {
741
1258
  var _a;
742
1259
  try {
743
1260
  setOptionsLoading(true);
744
1261
  await ((_a = props.onSearch) === null || _a === void 0 ? void 0 : _a.call(props, searchString));
745
1262
  }
746
- catch (error) {
747
- console.error('Error loading options:', error);
1263
+ catch (err) {
1264
+ console.error('Error loading options:', err);
748
1265
  }
749
1266
  finally {
750
1267
  setOptionsLoading(false);
751
1268
  }
752
1269
  };
753
1270
  React.useEffect(() => {
754
- if (async && debouncedQuery) {
1271
+ if (async && debouncedQuery)
755
1272
  handleSearch(debouncedQuery);
756
- }
757
1273
  }, [debouncedQuery, async]);
758
- return (jsxRuntime.jsxs("div", { className: buildClassName('group space-y-2', hasError && 'has-error', containerClass), children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, htmlFor: id, "aria-required": required, children: label }), labelHint] })), jsxRuntime.jsxs(react.Combobox, { multiple: multiple, immediate: immediate, name: name, value: selected, onChange: handleOnChange, onClose: () => setQuery(''), disabled: disabled, children: [multiple ? (jsxRuntime.jsxs("div", { className: buildClassName(inputClass, 'flex flex-wrap gap-2 peer'), children: [isArray(selected) && (selected === null || selected === void 0 ? void 0 : selected.length) > 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: selected.map((option, idx) => (jsxRuntime.jsx(Badge, { theme: "secondary", removable: !disabled, onRemove: () => removeSelection(idx), children: getDisplayValue(option) }, getValue(option)))) })), jsxRuntime.jsx(react.ComboboxInput, { className: "outline-none flex-1", "aria-label": name, value: query, autoComplete: "off", placeholder: (selected === null || selected === void 0 ? void 0 : selected.length) ? '' : placeholder, onChange: (event) => setQuery(event.target.value), id: id })] })) : (jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx(react.ComboboxInput, { "aria-label": name, displayValue: (option) => (option ? getDisplayValue(option) : null), autoComplete: "off", placeholder: placeholder, onChange: (event) => setQuery(event.target.value), className: inputClass, disabled: disabled, "data-disabled": disabled, id: id, readOnly: !searchable, ref: inputRef }), allowClear && !isEmpty(selected) && (jsxRuntime.jsx(Button, { size: "xs", iconOnly: true, theme: "secondary", variant: "plain", className: "group absolute inset-y-0 right-8 h-6 top-2", onClick: () => handleOnChange(multiple ? [] : null), disabled: disabled, children: jsxRuntime.jsx(SvgX, { className: "size-4 fill-white/60 group-data-[hover]:fill-white" }) })), jsxRuntime.jsx(react.ComboboxButton, { className: "group absolute inset-y-0 right-0 px-2.5", children: jsxRuntime.jsx(SvgChevronDown, { className: "size-4 fill-white/60 group-data-[hover]:fill-white" }) })] })), jsxRuntime.jsx(react.ComboboxOptions, { anchor: {
759
- to: 'bottom',
760
- gap: 5,
761
- }, className: buildClassName('w-[var(--input-width)] rounded-lg border border-gray-200 dark:border-white/5 bg-white dark:bg-gray-800 p-1 [--anchor-gap:var(--spacing-1)]', '[--anchor-max-height:20rem]', 'origin-top border transition duration-200 ease-out data-[closed]:translate-y-[-25%] data-[closed]:opacity-0 data-[closed]:overflow-hidden', dropdownContainerClass), children: optionsLoading ? (jsxRuntime.jsx("div", { className: "flex items-center justify-center py-2 px-3 select-none", children: jsxRuntime.jsx(Loader, { size: "sm" }) })) : shouldShowTypeToSearch ? (jsxRuntime.jsx("div", { className: "flex items-center justify-between py-2 px-3 select-none", children: "Type to search..." })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [filteredOptions.map((option) => (jsxRuntime.jsxs(react.ComboboxOption, { disabled: option.disabled, value: option, className: "group flex items-center justify-between gap-2 rounded-lg py-1.5 px-3 select-none data-[focus]:bg-black/3 dark:data-[focus]:bg-white/10 data-disabled:opacity-50 cursor-pointer data-disabled:pointer-events-none", children: [jsxRuntime.jsx("span", { className: "text-sm/6 dark:text-white", children: getDisplayValue(option) }), jsxRuntime.jsx(SvgCheck, { className: "invisible size-5 dark:fill-white group-data-[selected]:visible" })] }, getValue(option)))), filteredOptions.length === 0 && query && !optionsLoading && (jsxRuntime.jsxs("div", { className: "flex items-center gap-2 py-1.5 px-3 select-none text-gray-500 dark:text-gray-400", children: ["No results found for ", jsxRuntime.jsx("span", { className: "font-semibold", children: query })] })), allowAdd ? (jsxRuntime.jsxs("div", { role: "button", onClick: () => onAdd(query), className: "group flex items-center gap-2 rounded-lg py-1.5 px-3 cursor-pointer text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700", children: [jsxRuntime.jsx(SvgCirclePlus, { className: "size-4.5 text-blue-600" }), jsxRuntime.jsx(TextContent, { children: addNewText }), jsxRuntime.jsx(TextContent, { strong: true, children: query })] })) : null] })) })] }), showErrorMessage && error && (jsxRuntime.jsx("p", { className: "text-red-500 dark:text-red-500 text-sm", children: error }))] }));
762
- };
763
-
764
- const TEXT_ALIGN_CLASSES = {
765
- left: 'text-left',
766
- center: 'text-center',
767
- right: 'text-right',
768
- };
769
- const TABLE_LAYOUT_CLASSES = {
770
- fixed: 'table-fixed',
771
- auto: 'table-auto',
772
- };
773
- const TableRowLoader = ({ colSize, rowSize }) => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: [...Array(rowSize)].map((_, rowIndex) => (jsxRuntime.jsx(TableRow, { className: "animate-pulse", children: [...Array(colSize)].map((_, colIndex) => (jsxRuntime.jsx(TableCell, { children: jsxRuntime.jsx("div", { className: "flex items-center h-6", children: jsxRuntime.jsx("div", { className: "h-4 bg-gray-300 shimmer dark:bg-gray-700 rounded w-full" }) }) }, colIndex))) }, rowIndex))) }));
774
- const Table = ({ children, layout = 'auto', className = '' }) => (jsxRuntime.jsx("table", { className: buildClassName('border-collapse table-fixed w-full divide-y divide-gray-200', TABLE_LAYOUT_CLASSES[layout], className), children: children }));
775
- const TabelHead = ({ children, className = '', onSort }) => (jsxRuntime.jsx("thead", { className: buildClassName('text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400', className), children: jsxRuntime.jsx(TableRow, { className: "dark:hover:bg-gray-700", hoverable: false, children: React.Children.map(children, (child) => {
776
- // Check if child is a valid React element
777
- if (React.isValidElement(child)) {
778
- // Type the child explicitly to ReactElement so TypeScript knows it supports onClick
779
- return React.cloneElement(child, { onClick: onSort });
780
- }
781
- // Return child as-is if it's not a React element
782
- return child;
783
- }) }) }));
784
- const TabelBody = ({ children, loading, colSize, rowSize = 5, className = '', }) => (jsxRuntime.jsx("tbody", { className: buildClassName('text-sm text-gray-700 dark:text-white divide-y divide-gray-200 dark:divide-gray-700', className), children: loading ? (jsxRuntime.jsx(TableRowLoader, { colSize: colSize, rowSize: rowSize })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: React.Children.map(children, (child) => {
785
- // Check if child is a valid React element
786
- if (React.isValidElement(child)) {
787
- // Type the child explicitly to ReactElement so TypeScript knows it supports onClick
788
- return React.cloneElement(child);
789
- }
790
- // Return child as-is if it's not a React element
791
- return child;
792
- }) })) }));
793
- const TabelFoot = ({ children }) => (jsxRuntime.jsx("tfoot", { children: React.Children.map(children, (child) => {
794
- // Check if child is a valid React element
795
- if (React.isValidElement(child)) {
796
- // Type the child explicitly to ReactElement so TypeScript knows it supports onClick
797
- return React.cloneElement(child);
798
- }
799
- // Return child as-is if it's not a React element
800
- return child;
801
- }) }));
802
- const TableRow = ({ children, hoverable = true, className, ...props }) => (jsxRuntime.jsx("tr", { className: buildClassName('last:border-b border-gray-200 dark:border-gray-700 group h-full', className), ...props, children: children }));
803
- const TableCell = ({ children, align = 'left', className = '', ...props }) => (jsxRuntime.jsx("td", { className: buildClassName('first:pl-4 last:pr-4 px-3 py-3 bg-white dark:bg-gray-800 group-hover:bg-gray-50 group-hover:dark:bg-gray-600 whitespace-normal', className, TEXT_ALIGN_CLASSES[align]), ...props, children: jsxRuntime.jsx("div", { className: "antialiased leading-normal", children: children }) }));
804
- const TableHeaderCell = ({ children, align = 'left', className = '', ...props }) => (jsxRuntime.jsx("th", { className: buildClassName('first:pl-4 last:pr-4 px-3 py-3 tracking-wider whitespace-nowrap', 'text-gray-800 dark:text-gray-400', TEXT_ALIGN_CLASSES[align], className), ...props, children: jsxRuntime.jsx(BodyText, { as: "div", className: "block antialiased leading-none", children: children }) }));
805
- const EmptyTableRow = ({ children, colSpan = 1 }) => (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx(TableCell, { colSpan: colSpan, align: "center", children: jsxRuntime.jsx("div", { className: "p-8 space-y-3", children: children }) }) }));
806
-
807
- const Recent = () => jsxRuntime.jsx("div", { children: "Recent" });
808
- const Popular = () => jsxRuntime.jsx("div", { children: "Popular" });
809
- const Trending = () => jsxRuntime.jsx("div", { children: "Trending" });
810
- const categories = [
811
- {
812
- name: 'Recent',
813
- component: Recent,
814
- props: {},
815
- },
816
- {
817
- name: 'Popular',
818
- component: Popular,
819
- props: {},
820
- },
821
- {
822
- name: 'Trending',
823
- component: Trending,
824
- props: {},
825
- },
826
- ];
827
- const Tabs = () => {
828
- return (jsxRuntime.jsx("div", { className: "flex w-full pt-4", children: jsxRuntime.jsx("div", { className: "w-full max-w-md", children: jsxRuntime.jsxs(react.TabGroup, { children: [jsxRuntime.jsx(react.TabList, { className: "flex gap-4", children: categories.map(({ name }) => (jsxRuntime.jsx(react.Tab, { className: buildClassName('rounded-full py-1 px-3 text-sm/6 font-semibold dark:text-white border border-transparent', 'data-[selected]:bg-blue-100 dark:data-[selected]:bg-white/10 data-[selected]:text-blue-500', 'data-[hover]:bg-blue-50 dark:data-[hover]:bg-white/5', 'data-[selected]:data-[hover]:bg-blue-100 dark:data-[selected]:data-[hover]:bg-white/10', 'focus:outline-none data-[focus]:outline-1 data-[focus]:outline-blue-800 dark:data-[focus]:outline-white', 'data-[selected]:border-blue-500'), children: name }, name))) }), jsxRuntime.jsx(react.TabPanels, { className: "mt-3", children: categories.map(({ name, component: Component, props }) => (jsxRuntime.jsx(react.TabPanel, { className: "rounded-xl bg-white/5 p-3", children: jsxRuntime.jsx(Component, { ...props }) }, name))) })] }) }) }));
829
- };
1274
+ return (jsxRuntime.jsxs("div", { className: buildClassName('group space-y-2', hasError && 'has-error', containerClass), ref: containerRef, children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, htmlFor: id, "aria-required": required, children: label }), labelHint] })), jsxRuntime.jsxs(react.Combobox, { multiple: multiple, immediate: immediate, name: name, value: selected, onChange: comboboxOnChangeWrapper, onClose: () => setQuery(''), disabled: disabled, children: [multiple ? (jsxRuntime.jsxs("div", { className: buildClassName(inputClass, 'flex flex-wrap gap-2 peer relative'), ref: forwardedRef, children: [isArray(selected) &&
1275
+ (selected === null || selected === void 0 ? void 0 : selected.length) > 0 &&
1276
+ selected.map((option, idx) => (jsxRuntime.jsx(Badge, { theme: "secondary", removable: !disabled, onRemove: () => removeSelection(idx), children: getDisplayValue(option) }, `${getValue(option)}-${idx}`))), jsxRuntime.jsx(react.ComboboxInput, { className: "outline-none flex-1 dark:placeholder-gray-400 placeholder-gray-400", "aria-label": name, value: query, autoComplete: "off", placeholder: (selected === null || selected === void 0 ? void 0 : selected.length) ? '' : placeholder, onChange: (e) => setQuery(e.target.value), id: id, ref: inputRef, onKeyDown: (e) => {
1277
+ if (multiple && e.key === 'Backspace' && !query) {
1278
+ if (Array.isArray(selected) && selected.length > 0) {
1279
+ removeSelection(selected.length - 1);
1280
+ }
1281
+ }
1282
+ }, "data-testid": "combobox-input" }), jsxRuntime.jsx(react.ComboboxButton, { className: "group absolute inset-y-0 right-0 px-2.5", "data-testid": "combobox-button", children: jsxRuntime.jsx(SvgChevronDown, { className: chevronIconClass }) })] })) : (jsxRuntime.jsxs("div", { className: "relative", ref: forwardedRef, children: [jsxRuntime.jsx(react.ComboboxInput, { "aria-label": name, displayValue: (option) => (option ? getDisplayValue(option) : null), autoComplete: "off", placeholder: placeholder, onChange: (event) => setQuery(event.target.value), className: inputClass, disabled: disabled, id: id, readOnly: !searchable, ref: inputRef, "data-testid": "combobox-input" }), allowClear && !isEmpty(selected) && (jsxRuntime.jsx(Button, { size: "xs", iconOnly: true, theme: "secondary", variant: "plain", className: "group absolute inset-y-0 right-8 h-6 top-2", onClick: () => handleOnChangeInternal(multiple ? [] : null), disabled: disabled, "data-testid": "combobox-clear-button", noOutlineOnFocus: true, children: jsxRuntime.jsx(SvgX, { className: "size-4 stroke-gray-500" }) })), jsxRuntime.jsx(react.ComboboxButton, { className: "group absolute inset-y-0 right-0 px-2.5", "data-testid": "combobox-button", children: jsxRuntime.jsx(SvgChevronDown, { className: chevronIconClass }) })] })), jsxRuntime.jsx(react.ComboboxOptions, { anchor: { to: 'bottom', gap: 5 }, as: "div", className: buildClassName('w-[var(--input-width)] rounded-lg border border-gray-200 dark:border-white/5 bg-white dark:bg-gray-800 p-1 [--anchor-gap:var(--spacing-1)]', '[--anchor-max-height:20rem]', 'origin-top border transition duration-200 ease-[cubic-bezier(0.4, 0.0, 0.2, 1)] data-[closed]:translate-y-[-15%] data-[closed]:opacity-0', dropdownContainerClass), transition: true, "data-testid": "combobox-options", children: optionsLoading ? (jsxRuntime.jsx("div", { "data-testid": "options-loading", className: "flex items-center justify-center py-2 px-3 select-none", children: jsxRuntime.jsx(Loader, { size: "sm" }) })) : shouldShowTypeToSearch ? (jsxRuntime.jsx("div", { className: "flex items-center justify-between py-2 px-3 select-none", children: "Type to search..." })) : (jsxRuntime.jsxs("div", { children: [filteredOptions.map((option) => (jsxRuntime.jsx(react.ComboboxOption, { disabled: option.disabled, value: option, className: "group rounded-lg py-1.5 px-3 select-none data-[focus]:bg-black/3 dark:data-[focus]:bg-white/10 data-disabled:opacity-50 cursor-pointer data-disabled:pointer-events-none", children: jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 dark:text-white group-data-[selected]:text-blue-600", children: [jsxRuntime.jsx("span", { className: "text-sm/6", children: getDisplayValue(option) }), jsxRuntime.jsx(SvgCheck, { className: "invisible size-5 dark:stroke-gray-300 group-data-[selected]:visible" })] }) }, getValue(option)))), filteredOptions.length === 0 && query && !optionsLoading && (jsxRuntime.jsxs("div", { "data-testid": "no-result-found", className: "flex items-center gap-2 py-1.5 px-3 select-none text-gray-500 dark:text-gray-400", children: ["No results found for ", jsxRuntime.jsx("span", { className: "font-semibold", children: query })] })), allowAdd && (jsxRuntime.jsx(react.ComboboxOption, { value: query, className: "group rounded-lg py-1.5 px-3 cursor-pointer text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700", onClick: () => void handleAddAndSelect(query), children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx(SvgCirclePlus, { className: "size-4.5" }), jsxRuntime.jsxs(TextContent, { children: [addNewText, " \"", query, "\""] })] }) }))] })) })] }), showErrorMessage && error && (jsxRuntime.jsx("div", { className: "mt-1", children: jsxRuntime.jsx(TextContent, { error: true, small: true, children: error }) }))] }));
1283
+ });
830
1284
 
831
- const variantMap = {
832
- primary: 'bg-blue-100 text-blue-600 border border-blue-200',
833
- secondary: 'bg-gray-100 text-gray-600 border border-gray-200',
834
- success: 'bg-green-100 text-green-600 border border-green-200',
835
- warning: 'bg-orange-100 text-orange-600 border border-orange-200',
836
- error: 'bg-red-100 text-red-600 border border-red-200',
837
- };
838
- const Tag = (props) => {
839
- const { as: Element = 'span', text, className = '', onClose, variant = 'secondary', ...elemProps } = props;
840
- return (jsxRuntime.jsxs(Element, { ...elemProps, className: buildClassName(className, 'px-1.5 py-0.5 text-sm/6 font-normal', variantMap[variant], 'rounded'), children: [jsxRuntime.jsx("span", { children: text }), onClose && jsxRuntime.jsx(SvgCircleX, { className: "size-3", onClick: () => onClose(), role: "button" })] }));
1285
+ const Tabs = ({ tabs, defaultIndex = 0, variant = 'underline', className = '', listClass = '', panelClass = '', }) => {
1286
+ return (jsxRuntime.jsxs(react.TabGroup, { defaultIndex: defaultIndex, className: className, children: [jsxRuntime.jsx(react.TabList, { className: buildClassName('flex gap-2', listClass), children: tabs.map((tab, idx) => (jsxRuntime.jsx(react.Tab, { as: React.Fragment, children: ({ selected }) => (jsxRuntime.jsx("button", { className: buildTabClass({ selected, variant }), children: tab.label })) }, idx))) }), jsxRuntime.jsx(react.TabPanels, { className: buildClassName('mt-3', panelClass), children: tabs.map((tab, idx) => (jsxRuntime.jsx(react.TabPanel, { className: "rounded-lg bg-white dark:bg-gray-800 p-4 shadow-sm", children: tab.content }, idx))) })] }));
841
1287
  };
1288
+ /**
1289
+ * Build tab styles based on variant + active state
1290
+ */
1291
+ function buildTabClass({ selected, variant, }) {
1292
+ switch (variant) {
1293
+ /**
1294
+ * UNDERLINE (Default)
1295
+ */
1296
+ case 'underline':
1297
+ return buildClassName('px-3 py-1.5 text-sm font-medium transition relative', 'text-gray-600 dark:text-gray-300', 'hover:text-gray-900 dark:hover:text-white', selected &&
1298
+ 'text-gray-900 dark:text-white after:absolute after:left-0 after:right-0 after:-bottom-1 after:h-0.5 after:bg-blue-600');
1299
+ /**
1300
+ * SEGMENTED
1301
+ */
1302
+ case 'segmented':
1303
+ return buildClassName('px-3 py-1.5 text-sm font-medium rounded-lg transition', selected
1304
+ ? 'bg-blue-600 text-white'
1305
+ : 'text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700');
1306
+ /**
1307
+ * SOLID
1308
+ */
1309
+ case 'solid':
1310
+ return buildClassName('px-3 py-1.5 text-sm font-medium rounded-md transition', selected
1311
+ ? 'bg-gray-900 dark:bg-gray-700 text-white'
1312
+ : 'bg-gray-200 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-700');
1313
+ }
1314
+ }
842
1315
 
843
1316
  const Textarea = React.forwardRef((props, ref) => {
844
1317
  const { name, id = name, label = null, labelHint = null, className = '', labelClass = '', labelWrapperClass = '', containerClass = '', error, showErrorMessage = true, rightGroup = null, leftGroup = null, ...inputProps } = props;
845
1318
  const hasError = !isEmpty(error);
846
- const hasRightGroup = rightGroup != null && React.isValidElement(rightGroup);
847
- const hasLeftGroup = leftGroup != null && React.isValidElement(leftGroup);
848
- return (jsxRuntime.jsxs("div", { className: buildClassName('group', hasError && 'has-error', containerClass), children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between mb-2', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, htmlFor: id, children: label }), labelHint] })), jsxRuntime.jsxs("div", { className: "relative", children: [hasLeftGroup && (jsxRuntime.jsx("span", { className: "absolute top-0 h-full flex items-center justify-center w-10", children: leftGroup })), jsxRuntime.jsx("textarea", { ref: ref, ...inputProps, name: name, id: id, className: buildClassName('transition-all', 'block w-full rounded-lg bg-white px-3.5 py-2 text-base sm:text-sm/6', 'text-gray-900 outline dark:outline outline-1 -outline-offset-1', 'outline-gray-300 dark:outline-gray-600', 'focus:outline-blue-600 dark:focus:outline-blue-600 focus:outline-2 focus:-outline-offset-2', 'dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-500 placeholder:text-gray-400 dark:text-white', 'invalid:group-[.has-error]:outline-red-500', 'disabled:pointer-events-none disabled:bg-gray-100', 'dark:disabled:bg-gray-500', hasRightGroup ? 'pe-10' : '', hasLeftGroup ? 'ps-10' : '', className) }), hasRightGroup && (jsxRuntime.jsx("span", { className: "absolute end-0.75 top-0 h-full flex items-center justify-center", children: rightGroup }))] }), showErrorMessage && error && (jsxRuntime.jsx("p", { className: "mt-1 text-red-500 dark:text-red-500 text-sm", children: error }))] }));
1319
+ const hasRightGroup = rightGroup != null && rightGroup !== undefined;
1320
+ const hasLeftGroup = leftGroup != null && leftGroup !== undefined;
1321
+ return (jsxRuntime.jsxs("div", { className: buildClassName('group', hasError && 'has-error', containerClass), children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between mb-2', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, htmlFor: id, children: label }), labelHint] })), jsxRuntime.jsxs("div", { className: "relative", children: [hasLeftGroup && (jsxRuntime.jsx("span", { className: "absolute top-0 h-full flex items-center justify-center w-10", children: leftGroup })), jsxRuntime.jsx("textarea", { ref: ref, autoComplete: "off", ...inputProps, name: name, id: id, className: buildClassName('transition-all', 'block w-full rounded-lg bg-white px-3.5 py-2 text-base sm:text-sm/6', 'text-gray-900 outline dark:outline outline-1 -outline-offset-1', 'outline-gray-300 dark:outline-gray-600', 'focus:outline-blue-600 dark:focus:outline-blue-600 focus:outline-2 focus:-outline-offset-2', 'dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-500 placeholder:text-gray-400 dark:text-white', 'invalid:group-[.has-error]:outline-red-500', 'disabled:pointer-events-none disabled:bg-gray-100', 'dark:disabled:bg-gray-500', hasRightGroup ? 'pe-10' : '', hasLeftGroup ? 'ps-10' : '', className) }), hasRightGroup && (jsxRuntime.jsx("span", { className: "absolute end-0.75 top-0 h-full flex items-center justify-center", children: rightGroup }))] }), showErrorMessage && error && (jsxRuntime.jsx("div", { className: "mt-1", children: jsxRuntime.jsx(TextContent, { error: true, small: true, children: error }) }))] }));
849
1322
  });
850
1323
 
851
- const typeStyles = {
852
- success: 'bg-green-500 text-white',
853
- error: 'bg-red-500 text-white',
854
- info: 'bg-blue-500 text-white',
855
- warning: 'bg-yellow-400 text-black',
1324
+ /**
1325
+ * Icons for each toast type
1326
+ */
1327
+ const iconMap = {
1328
+ success: jsxRuntime.jsx(SvgCircleCheck, { className: "size-5 text-green-600 dark:text-green-400" }),
1329
+ error: jsxRuntime.jsx(SvgCircleAlert, { className: "size-5 text-red-600 dark:text-red-400" }),
1330
+ info: jsxRuntime.jsx(SvgInfo, { className: "size-5 text-blue-600 dark:text-blue-400" }),
1331
+ warning: jsxRuntime.jsx(SvgTriangleAlert, { className: "size-5 text-yellow-600 dark:text-yellow-400" }),
1332
+ };
1333
+ /**
1334
+ * Subtle icon + text color adjustments
1335
+ */
1336
+ const textColorMap = {
1337
+ success: 'text-green-900 dark:text-green-200',
1338
+ error: 'text-red-900 dark:text-red-200',
1339
+ info: 'text-blue-900 dark:text-blue-200',
1340
+ warning: 'text-yellow-900 dark:text-yellow-200',
856
1341
  };
857
- const Toast = ({ message, type, onClose }) => {
858
- return (jsxRuntime.jsx(react.Transition, { appear: true, show: true, enter: "transform transition duration-300", enterFrom: "opacity-0 translate-x-4", enterTo: "opacity-100 translate-x-0", leave: "transition duration-200 ease-in", leaveFrom: "opacity-100", leaveTo: "opacity-0", children: jsxRuntime.jsxs("div", { className: `flex items-center justify-between rounded-lg px-4 py-3 shadow-lg min-w-[240px] ${typeStyles[type]}`, children: [jsxRuntime.jsx("span", { children: message }), jsxRuntime.jsx("button", { onClick: onClose, className: "ml-3 text-xl leading-none hover:opacity-75", "aria-label": "Close toast", children: jsxRuntime.jsx(SvgX, { className: "size-5" }) })] }) }));
1342
+ /**
1343
+ * Pleasant colored *top border only*
1344
+ * No background color — soft neutral surface
1345
+ */
1346
+ const borderStyle = {
1347
+ success: 'border-t-4 border-green-600 dark:border-green-400',
1348
+ error: 'border-t-4 border-red-600 dark:border-red-400',
1349
+ info: 'border-t-4 border-blue-600 dark:border-blue-400',
1350
+ warning: 'border-t-4 border-yellow-600 dark:border-yellow-400',
1351
+ };
1352
+ const Toast = ({ message, type, onClose, className, id, isTop = true, }) => {
1353
+ const enterFrom = isTop ? 'opacity-0 -translate-y-3 scale-95' : 'opacity-0 translate-y-3 scale-95';
1354
+ const leaveTo = isTop ? 'opacity-0 -translate-y-2 scale-95' : 'opacity-0 translate-y-2 scale-95';
1355
+ return (jsxRuntime.jsx(react.Transition, { appear: true, show: true, enter: "transform transition duration-300", enterFrom: enterFrom, enterTo: "opacity-100 translate-y-0 scale-100", leave: "transition duration-200", leaveFrom: "opacity-100 translate-y-0 scale-100", leaveTo: leaveTo, children: jsxRuntime.jsxs("div", { role: "status", className: buildClassName('flex items-center gap-3 rounded-lg px-4 py-3 shadow-lg min-w-[260px] max-w-sm', 'bg-white dark:bg-gray-900 dark:border-gray-700', borderStyle[type], className), id: id.toString(), children: [jsxRuntime.jsx(TextContent, { className: buildClassName(textColorMap[type]), children: iconMap[type] }), jsxRuntime.jsx(TextContent, { className: "flex-1 text-sm font-medium", children: message }), jsxRuntime.jsx(Button, { onClick: onClose, "aria-label": "Close toast", className: "opacity-60 hover:opacity-100 transition", iconOnly: true, size: "xs", variant: "plain", theme: "secondary", noOutlineOnFocus: true, children: jsxRuntime.jsx(SvgX, { className: "size-4" }) })] }) }));
859
1356
  };
860
1357
 
861
1358
  const ToastContext = React.createContext(undefined);
1359
+ let toastCounter = 0;
862
1360
  const useToast = () => {
863
1361
  const context = React.useContext(ToastContext);
864
1362
  if (!context)
865
1363
  throw new Error('useToast must be used within ToastProvider');
866
1364
  return context;
867
1365
  };
868
- const ToastProvider = ({ children }) => {
1366
+ // Maximum visible toasts at once
1367
+ const MAX_TOASTS = 5;
1368
+ const placementClass = {
1369
+ 'top-right': 'top-10 right-4 items-end',
1370
+ 'top-left': 'top-10 left-4 items-start',
1371
+ 'top-center': 'top-10 left-1/2 -translate-x-1/2 items-center',
1372
+ 'bottom-right': 'bottom-10 right-4 items-end',
1373
+ 'bottom-left': 'bottom-10 left-4 items-start',
1374
+ 'bottom-center': 'bottom-10 left-1/2 -translate-x-1/2 items-center',
1375
+ };
1376
+ const ToastProvider = ({ children, placement = 'top-center' }) => {
869
1377
  const [toasts, setToasts] = React.useState([]);
870
- const showToast = (message, options) => {
871
- var _a, _b, _c;
872
- const id = Date.now();
1378
+ const timeoutRefs = React.useRef(new Map());
1379
+ const clearTimer = (id) => {
1380
+ const timeout = timeoutRefs.current.get(id);
1381
+ if (timeout) {
1382
+ clearTimeout(timeout);
1383
+ timeoutRefs.current.delete(id);
1384
+ }
1385
+ };
1386
+ const scheduleClose = (toast) => {
1387
+ if (!toast.autoClose)
1388
+ return;
1389
+ clearTimer(toast.id);
1390
+ const timeout = setTimeout(() => {
1391
+ closeToast(toast.id);
1392
+ }, toast.duration);
1393
+ timeoutRefs.current.set(toast.id, timeout);
1394
+ };
1395
+ const showToast = React.useCallback((message, options) => {
1396
+ var _a, _b, _c, _d;
1397
+ const id = ++toastCounter;
873
1398
  const newToast = {
874
1399
  id,
875
1400
  message,
876
1401
  type: (_a = options === null || options === void 0 ? void 0 : options.type) !== null && _a !== void 0 ? _a : 'info',
877
1402
  duration: (_b = options === null || options === void 0 ? void 0 : options.duration) !== null && _b !== void 0 ? _b : 3000,
878
1403
  autoClose: (_c = options === null || options === void 0 ? void 0 : options.autoClose) !== null && _c !== void 0 ? _c : true,
1404
+ pauseOnHover: (_d = options === null || options === void 0 ? void 0 : options.pauseOnHover) !== null && _d !== void 0 ? _d : true,
879
1405
  };
880
- setToasts((prev) => [...prev, newToast]);
881
- if (newToast.autoClose) {
882
- setTimeout(() => closeToast(id), newToast.duration);
1406
+ setToasts((prev) => {
1407
+ const updated = [...prev, newToast];
1408
+ if (updated.length > MAX_TOASTS)
1409
+ updated.shift();
1410
+ return updated;
1411
+ });
1412
+ scheduleClose(newToast);
1413
+ }, []);
1414
+ const closeToast = React.useCallback((id) => {
1415
+ clearTimer(id);
1416
+ setToasts((prev) => prev.filter((t) => t.id !== id));
1417
+ }, []);
1418
+ return (jsxRuntime.jsxs(ToastContext.Provider, { value: { showToast, closeToast }, children: [children, jsxRuntime.jsx("div", { className: buildClassName('fixed z-50 flex flex-col gap-3 pointer-events-none', placementClass[placement]), children: toasts.map((toast, index) => (jsxRuntime.jsx("div", { className: "pointer-events-auto", onMouseEnter: () => toast.pauseOnHover && clearTimer(toast.id), onMouseLeave: () => toast.pauseOnHover && scheduleClose(toast), children: jsxRuntime.jsx(Toast, { ...toast, isTop: placement.startsWith('top'), onClose: () => closeToast(toast.id) }) }, toast.id))) })] }));
1419
+ };
1420
+
1421
+ const q = typeof window < "u" ? React.useLayoutEffect : React.useEffect;
1422
+ function oe(e) {
1423
+ if (e !== void 0)
1424
+ switch (typeof e) {
1425
+ case "number":
1426
+ return e;
1427
+ case "string": {
1428
+ if (e.endsWith("px"))
1429
+ return parseFloat(e);
1430
+ break;
1431
+ }
1432
+ }
1433
+ }
1434
+ function Ie({
1435
+ box: e,
1436
+ defaultHeight: t,
1437
+ defaultWidth: s,
1438
+ disabled: r,
1439
+ element: n,
1440
+ mode: o,
1441
+ style: i
1442
+ }) {
1443
+ const { styleHeight: f, styleWidth: l } = React.useMemo(
1444
+ () => ({
1445
+ styleHeight: oe(i?.height),
1446
+ styleWidth: oe(i?.width)
1447
+ }),
1448
+ [i?.height, i?.width]
1449
+ ), [c, d] = React.useState({
1450
+ height: t,
1451
+ width: s
1452
+ }), a = r || f !== void 0 || o === "only-width" || f !== void 0 && l !== void 0;
1453
+ return q(() => {
1454
+ if (n === null || a)
1455
+ return;
1456
+ const u = new ResizeObserver((I) => {
1457
+ for (const m of I) {
1458
+ const { contentRect: b, target: g } = m;
1459
+ n === g && d((w) => w.height === b.height && w.width === b.width ? w : {
1460
+ height: b.height,
1461
+ width: b.width
1462
+ });
1463
+ }
1464
+ });
1465
+ return u.observe(n, { box: e }), () => {
1466
+ u?.unobserve(n);
1467
+ };
1468
+ }, [e, a, n, f, l]), React.useMemo(
1469
+ () => ({
1470
+ height: f ?? c.height,
1471
+ width: l ?? c.width
1472
+ }),
1473
+ [c, f, l]
1474
+ );
1475
+ }
1476
+ function ae(e) {
1477
+ const t = React.useRef(() => {
1478
+ throw new Error("Cannot call during render.");
1479
+ });
1480
+ return q(() => {
1481
+ t.current = e;
1482
+ }, [e]), React.useCallback((s) => t.current?.(s), [t]);
1483
+ }
1484
+ function Z({
1485
+ containerElement: e,
1486
+ direction: t,
1487
+ isRtl: s,
1488
+ scrollOffset: r
1489
+ }) {
1490
+ return r;
1491
+ }
1492
+ function $(e, t = "Assertion error") {
1493
+ if (!e)
1494
+ throw console.error(t), Error(t);
1495
+ }
1496
+ function Y(e, t) {
1497
+ if (e === t)
1498
+ return true;
1499
+ if (!!e != !!t || ($(e !== void 0), $(t !== void 0), Object.keys(e).length !== Object.keys(t).length))
1500
+ return false;
1501
+ for (const s in e)
1502
+ if (!Object.is(t[s], e[s]))
1503
+ return false;
1504
+ return true;
1505
+ }
1506
+ function fe({
1507
+ cachedBounds: e,
1508
+ itemCount: t,
1509
+ itemSize: s
1510
+ }) {
1511
+ if (t === 0)
1512
+ return 0;
1513
+ if (typeof s == "number")
1514
+ return t * s;
1515
+ {
1516
+ const r = e.get(
1517
+ e.size === 0 ? 0 : e.size - 1
1518
+ );
1519
+ $(r !== void 0, "Unexpected bounds cache miss");
1520
+ const n = (r.scrollOffset + r.size) / e.size;
1521
+ return t * n;
1522
+ }
1523
+ }
1524
+ function we({
1525
+ align: e,
1526
+ cachedBounds: t,
1527
+ index: s,
1528
+ itemCount: r,
1529
+ itemSize: n,
1530
+ containerScrollOffset: o,
1531
+ containerSize: i
1532
+ }) {
1533
+ if (s < 0 || s >= r)
1534
+ throw RangeError(`Invalid index specified: ${s}`, {
1535
+ cause: `Index ${s} is not within the range of 0 - ${r - 1}`
1536
+ });
1537
+ const f = fe({
1538
+ cachedBounds: t,
1539
+ itemCount: r,
1540
+ itemSize: n
1541
+ }), l = t.get(s), c = Math.max(
1542
+ 0,
1543
+ Math.min(f - i, l.scrollOffset)
1544
+ ), d = Math.max(
1545
+ 0,
1546
+ l.scrollOffset - i + l.size
1547
+ );
1548
+ switch (e === "smart" && (o >= d && o <= c ? e = "auto" : e = "center"), e) {
1549
+ case "start":
1550
+ return c;
1551
+ case "end":
1552
+ return d;
1553
+ case "center":
1554
+ return l.scrollOffset <= i / 2 ? 0 : l.scrollOffset + l.size / 2 >= f - i / 2 ? f - i : l.scrollOffset + l.size / 2 - i / 2;
1555
+ case "auto":
1556
+ default:
1557
+ return o >= d && o <= c ? o : o < d ? d : c;
1558
+ }
1559
+ }
1560
+ function ie({
1561
+ cachedBounds: e,
1562
+ containerScrollOffset: t,
1563
+ containerSize: s,
1564
+ itemCount: r,
1565
+ overscanCount: n
1566
+ }) {
1567
+ const o = r - 1;
1568
+ let i = 0, f = -1, l = 0, c = -1, d = 0;
1569
+ for (; d < o; ) {
1570
+ const a = e.get(d);
1571
+ if (a.scrollOffset + a.size > t)
1572
+ break;
1573
+ d++;
1574
+ }
1575
+ for (i = d, l = Math.max(0, i - n); d < o; ) {
1576
+ const a = e.get(d);
1577
+ if (a.scrollOffset + a.size >= t + s)
1578
+ break;
1579
+ d++;
1580
+ }
1581
+ return f = Math.min(o, d), c = Math.min(r - 1, f + n), i < 0 && (i = 0, f = -1, l = 0, c = -1), {
1582
+ startIndexVisible: i,
1583
+ stopIndexVisible: f,
1584
+ startIndexOverscan: l,
1585
+ stopIndexOverscan: c
1586
+ };
1587
+ }
1588
+ function me({
1589
+ itemCount: e,
1590
+ itemProps: t,
1591
+ itemSize: s
1592
+ }) {
1593
+ const r = /* @__PURE__ */ new Map();
1594
+ return {
1595
+ get(n) {
1596
+ for ($(n < e, `Invalid index ${n}`); r.size - 1 < n; ) {
1597
+ const i = r.size;
1598
+ let f;
1599
+ switch (typeof s) {
1600
+ case "function": {
1601
+ f = s(i, t);
1602
+ break;
1603
+ }
1604
+ case "number": {
1605
+ f = s;
1606
+ break;
1607
+ }
883
1608
  }
1609
+ if (i === 0)
1610
+ r.set(i, {
1611
+ size: f,
1612
+ scrollOffset: 0
1613
+ });
1614
+ else {
1615
+ const l = r.get(i - 1);
1616
+ $(
1617
+ l !== void 0,
1618
+ `Unexpected bounds cache miss for index ${n}`
1619
+ ), r.set(i, {
1620
+ scrollOffset: l.scrollOffset + l.size,
1621
+ size: f
1622
+ });
1623
+ }
1624
+ }
1625
+ const o = r.get(n);
1626
+ return $(
1627
+ o !== void 0,
1628
+ `Unexpected bounds cache miss for index ${n}`
1629
+ ), o;
1630
+ },
1631
+ set(n, o) {
1632
+ r.set(n, o);
1633
+ },
1634
+ get size() {
1635
+ return r.size;
1636
+ }
1637
+ };
1638
+ }
1639
+ function Oe({
1640
+ itemCount: e,
1641
+ itemProps: t,
1642
+ itemSize: s
1643
+ }) {
1644
+ return React.useMemo(
1645
+ () => me({
1646
+ itemCount: e,
1647
+ itemProps: t,
1648
+ itemSize: s
1649
+ }),
1650
+ [e, t, s]
1651
+ );
1652
+ }
1653
+ function ye({
1654
+ containerSize: e,
1655
+ itemSize: t
1656
+ }) {
1657
+ let s;
1658
+ switch (typeof t) {
1659
+ case "string": {
1660
+ $(
1661
+ t.endsWith("%"),
1662
+ `Invalid item size: "${t}"; string values must be percentages (e.g. "100%")`
1663
+ ), $(
1664
+ e !== void 0,
1665
+ "Container size must be defined if a percentage item size is specified"
1666
+ ), s = e * parseInt(t) / 100;
1667
+ break;
1668
+ }
1669
+ default: {
1670
+ s = t;
1671
+ break;
1672
+ }
1673
+ }
1674
+ return s;
1675
+ }
1676
+ function ee({
1677
+ containerElement: e,
1678
+ containerStyle: t,
1679
+ defaultContainerSize: s = 0,
1680
+ direction: r,
1681
+ isRtl: n = false,
1682
+ itemCount: o,
1683
+ itemProps: i,
1684
+ itemSize: f,
1685
+ onResize: l,
1686
+ overscanCount: c
1687
+ }) {
1688
+ const [d, a] = React.useState({
1689
+ startIndexVisible: 0,
1690
+ startIndexOverscan: 0,
1691
+ stopIndexVisible: -1,
1692
+ stopIndexOverscan: -1
1693
+ }), {
1694
+ startIndexVisible: u,
1695
+ startIndexOverscan: I,
1696
+ stopIndexVisible: m,
1697
+ stopIndexOverscan: b
1698
+ } = {
1699
+ startIndexVisible: Math.min(o - 1, d.startIndexVisible),
1700
+ startIndexOverscan: Math.min(o - 1, d.startIndexOverscan),
1701
+ stopIndexVisible: Math.min(o - 1, d.stopIndexVisible),
1702
+ stopIndexOverscan: Math.min(o - 1, d.stopIndexOverscan)
1703
+ }, { height: g = s, width: w = s } = Ie({
1704
+ defaultHeight: s ,
1705
+ defaultWidth: void 0,
1706
+ element: e,
1707
+ mode: "only-height" ,
1708
+ style: t
1709
+ }), y = React.useRef({
1710
+ height: 0,
1711
+ width: 0
1712
+ }), V = g , h = ye({ containerSize: V, itemSize: f });
1713
+ React.useLayoutEffect(() => {
1714
+ if (typeof l == "function") {
1715
+ const p = y.current;
1716
+ (p.height !== g || p.width !== w) && (l({ height: g, width: w }, { ...p }), p.height = g, p.width = w);
1717
+ }
1718
+ }, [g, l, w]);
1719
+ const z = Oe({
1720
+ itemCount: o,
1721
+ itemProps: i,
1722
+ itemSize: h
1723
+ }), k = React.useCallback(
1724
+ (p) => z.get(p),
1725
+ [z]
1726
+ ), S = React.useCallback(
1727
+ () => fe({
1728
+ cachedBounds: z,
1729
+ itemCount: o,
1730
+ itemSize: h
1731
+ }),
1732
+ [z, o, h]
1733
+ ), W = React.useCallback(
1734
+ (p) => {
1735
+ const T = Z({
1736
+ containerElement: e,
1737
+ direction: r,
1738
+ isRtl: n,
1739
+ scrollOffset: p
1740
+ });
1741
+ return ie({
1742
+ cachedBounds: z,
1743
+ containerScrollOffset: T,
1744
+ containerSize: V,
1745
+ itemCount: o,
1746
+ overscanCount: c
1747
+ });
1748
+ },
1749
+ [
1750
+ z,
1751
+ e,
1752
+ V,
1753
+ r,
1754
+ n,
1755
+ o,
1756
+ c
1757
+ ]
1758
+ );
1759
+ q(() => {
1760
+ const p = (e?.scrollTop ) ?? 0;
1761
+ a(W(p));
1762
+ }, [e, r, W]), q(() => {
1763
+ if (!e)
1764
+ return;
1765
+ const p = () => {
1766
+ a((T) => {
1767
+ const { scrollLeft: R, scrollTop: v } = e, x = Z({
1768
+ containerElement: e,
1769
+ direction: r,
1770
+ isRtl: n,
1771
+ scrollOffset: v
1772
+ }), A = ie({
1773
+ cachedBounds: z,
1774
+ containerScrollOffset: x,
1775
+ containerSize: V,
1776
+ itemCount: o,
1777
+ overscanCount: c
1778
+ });
1779
+ return Y(A, T) ? T : A;
1780
+ });
884
1781
  };
885
- const closeToast = (id) => {
886
- setToasts((prev) => prev.filter((t) => t.id !== id));
1782
+ return e.addEventListener("scroll", p), () => {
1783
+ e.removeEventListener("scroll", p);
887
1784
  };
888
- return (jsxRuntime.jsxs(ToastContext.Provider, { value: { showToast, closeToast }, children: [children, jsxRuntime.jsx("div", { className: "fixed top-4 right-4 z-50 space-y-3", children: toasts.map((toast) => (jsxRuntime.jsx(Toast, { ...toast, onClose: () => closeToast(toast.id) }, toast.id))) })] }));
1785
+ }, [
1786
+ z,
1787
+ e,
1788
+ V,
1789
+ r,
1790
+ o,
1791
+ c
1792
+ ]);
1793
+ const O = ae(
1794
+ ({
1795
+ align: p = "auto",
1796
+ containerScrollOffset: T,
1797
+ index: R
1798
+ }) => {
1799
+ let v = we({
1800
+ align: p,
1801
+ cachedBounds: z,
1802
+ containerScrollOffset: T,
1803
+ containerSize: V,
1804
+ index: R,
1805
+ itemCount: o,
1806
+ itemSize: h
1807
+ });
1808
+ if (e) {
1809
+ if (v = Z({
1810
+ containerElement: e,
1811
+ direction: r,
1812
+ isRtl: n,
1813
+ scrollOffset: v
1814
+ }), typeof e.scrollTo != "function") {
1815
+ const x = W(v);
1816
+ Y(d, x) || a(x);
1817
+ }
1818
+ return v;
1819
+ }
1820
+ }
1821
+ );
1822
+ return {
1823
+ getCellBounds: k,
1824
+ getEstimatedSize: S,
1825
+ scrollToIndex: O,
1826
+ startIndexOverscan: I,
1827
+ startIndexVisible: u,
1828
+ stopIndexOverscan: b,
1829
+ stopIndexVisible: m
1830
+ };
1831
+ }
1832
+ function de(e) {
1833
+ return React.useMemo(() => e, Object.values(e));
1834
+ }
1835
+ function ue(e, t) {
1836
+ const {
1837
+ ariaAttributes: s,
1838
+ style: r,
1839
+ ...n
1840
+ } = e, {
1841
+ ariaAttributes: o,
1842
+ style: i,
1843
+ ...f
1844
+ } = t;
1845
+ return Y(s, o) && Y(r, i) && Y(n, f);
1846
+ }
1847
+ function ze(e) {
1848
+ return e != null && typeof e == "object" && "getAverageRowHeight" in e && typeof e.getAverageRowHeight == "function";
1849
+ }
1850
+ const te = "data-react-window-index";
1851
+ function Ae({
1852
+ children: e,
1853
+ className: t,
1854
+ defaultHeight: s = 0,
1855
+ listRef: r,
1856
+ onResize: n,
1857
+ onRowsRendered: o,
1858
+ overscanCount: i = 3,
1859
+ rowComponent: f,
1860
+ rowCount: l,
1861
+ rowHeight: c,
1862
+ rowProps: d,
1863
+ tagName: a = "div",
1864
+ style: u,
1865
+ ...I
1866
+ }) {
1867
+ const m = de(d), b = React.useMemo(
1868
+ () => React.memo(f, ue),
1869
+ [f]
1870
+ ), [g, w] = React.useState(null), y = ze(c), V = React.useMemo(() => y ? (v) => c.getRowHeight(v) ?? c.getAverageRowHeight() : c, [y, c]), {
1871
+ getCellBounds: h,
1872
+ getEstimatedSize: z,
1873
+ scrollToIndex: k,
1874
+ startIndexOverscan: S,
1875
+ startIndexVisible: W,
1876
+ stopIndexOverscan: O,
1877
+ stopIndexVisible: p
1878
+ } = ee({
1879
+ containerElement: g,
1880
+ containerStyle: u,
1881
+ defaultContainerSize: s,
1882
+ direction: "vertical",
1883
+ itemCount: l,
1884
+ itemProps: m,
1885
+ itemSize: V,
1886
+ onResize: n,
1887
+ overscanCount: i
1888
+ });
1889
+ React.useImperativeHandle(
1890
+ r,
1891
+ () => ({
1892
+ get element() {
1893
+ return g;
1894
+ },
1895
+ scrollToRow({
1896
+ align: v = "auto",
1897
+ behavior: x = "auto",
1898
+ index: A
1899
+ }) {
1900
+ const M = k({
1901
+ align: v,
1902
+ containerScrollOffset: g?.scrollTop ?? 0,
1903
+ index: A
1904
+ });
1905
+ typeof g?.scrollTo == "function" && g.scrollTo({
1906
+ behavior: x,
1907
+ top: M
1908
+ });
1909
+ }
1910
+ }),
1911
+ [g, k]
1912
+ ), q(() => {
1913
+ if (!g)
1914
+ return;
1915
+ const v = Array.from(g.children).filter((x, A) => {
1916
+ if (x.hasAttribute("aria-hidden"))
1917
+ return false;
1918
+ const M = `${S + A}`;
1919
+ return x.setAttribute(te, M), true;
1920
+ });
1921
+ if (y)
1922
+ return c.observeRowElements(v);
1923
+ }, [
1924
+ g,
1925
+ y,
1926
+ c,
1927
+ S,
1928
+ O
1929
+ ]), React.useEffect(() => {
1930
+ S >= 0 && O >= 0 && o && o(
1931
+ {
1932
+ startIndex: W,
1933
+ stopIndex: p
1934
+ },
1935
+ {
1936
+ startIndex: S,
1937
+ stopIndex: O
1938
+ }
1939
+ );
1940
+ }, [
1941
+ o,
1942
+ S,
1943
+ W,
1944
+ O,
1945
+ p
1946
+ ]);
1947
+ const T = React.useMemo(() => {
1948
+ const v = [];
1949
+ if (l > 0)
1950
+ for (let x = S; x <= O; x++) {
1951
+ const A = h(x);
1952
+ v.push(
1953
+ /* @__PURE__ */ React.createElement(
1954
+ b,
1955
+ {
1956
+ ...m,
1957
+ ariaAttributes: {
1958
+ "aria-posinset": x + 1,
1959
+ "aria-setsize": l,
1960
+ role: "listitem"
1961
+ },
1962
+ key: x,
1963
+ index: x,
1964
+ style: {
1965
+ position: "absolute",
1966
+ left: 0,
1967
+ transform: `translateY(${A.scrollOffset}px)`,
1968
+ // In case of dynamic row heights, don't specify a height style
1969
+ // otherwise a default/estimated height would mask the actual height
1970
+ height: y ? void 0 : A.size,
1971
+ width: "100%"
1972
+ }
1973
+ }
1974
+ )
1975
+ );
1976
+ }
1977
+ return v;
1978
+ }, [
1979
+ b,
1980
+ h,
1981
+ y,
1982
+ l,
1983
+ m,
1984
+ S,
1985
+ O
1986
+ ]), R = /* @__PURE__ */ jsxRuntime.jsx(
1987
+ "div",
1988
+ {
1989
+ "aria-hidden": true,
1990
+ style: {
1991
+ height: z(),
1992
+ width: "100%",
1993
+ zIndex: -1
1994
+ }
1995
+ }
1996
+ );
1997
+ return React.createElement(
1998
+ a,
1999
+ {
2000
+ role: "list",
2001
+ ...I,
2002
+ className: t,
2003
+ ref: w,
2004
+ style: {
2005
+ position: "relative",
2006
+ maxHeight: "100%",
2007
+ flexGrow: 1,
2008
+ overflowY: "auto",
2009
+ ...u
2010
+ }
2011
+ },
2012
+ T,
2013
+ e,
2014
+ R
2015
+ );
2016
+ }
2017
+
2018
+ const VirtualizedRow = ({ index, style, items, columns, gridTemplate, }) => {
2019
+ const item = items[index];
2020
+ return (jsxRuntime.jsx("div", { role: "row", className: "grid border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 group", style: {
2021
+ ...style,
2022
+ display: 'grid',
2023
+ gridTemplateColumns: gridTemplate,
2024
+ minWidth: 'fit-content',
2025
+ }, children: columns.map((col) => {
2026
+ var _a;
2027
+ const content = col.render ? col.render(item) : ((_a = get(item, col.name)) !== null && _a !== void 0 ? _a : 'Not set');
2028
+ return (jsxRuntime.jsx("div", { role: "cell", className: buildClassName('px-3 py-3 whitespace-nowrap border-r last:border-r-0 border-gray-200 dark:border-gray-700', col.align === 'center' && 'text-center', col.align === 'right' && 'text-right', col.sticky === 'left' &&
2029
+ 'sticky left-0 z-10 bg-white dark:bg-gray-900 shadow-[2px_0_4px_rgba(0,0,0,0.05)]', col.sticky === 'right' &&
2030
+ 'sticky right-0 z-10 bg-white dark:bg-gray-900 shadow-[-2px_0_4px_rgba(0,0,0,0.05)]'), children: content }, col.name));
2031
+ }) }));
2032
+ };
2033
+
2034
+ /* -------------------------------------------------------
2035
+ * Convert column definitions into CSS grid template
2036
+ * ------------------------------------------------------- */
2037
+ const useGridTemplate = (columns) => React.useMemo(() => columns.map((col) => (col.width ? `${col.width}px` : '1fr')).join(' '), [columns]);
2038
+ const VirtualizedDataTable = ({ items, columns, sorting = {}, onSort, loading = false, emptyMessage = 'No data available', containerClass = '', wrapperClass = '', rowHeight = 48, maxHeight = 400, }) => {
2039
+ const scrollRef = React.useRef(null);
2040
+ const headerRef = React.useRef(null);
2041
+ const gridTemplate = useGridTemplate(columns);
2042
+ /** Sync body → header scroll */
2043
+ const handleScrollSync = (scrollOffset) => {
2044
+ if (headerRef.current) {
2045
+ headerRef.current.scrollLeft = scrollOffset;
2046
+ }
2047
+ };
2048
+ const handleSort = React.useCallback((column) => {
2049
+ if (column.sortable)
2050
+ onSort === null || onSort === void 0 ? void 0 : onSort(column);
2051
+ }, [onSort]);
2052
+ /* -------------------------------------------------------
2053
+ * RENDER: Header row (real DOM for accessibility)
2054
+ * ------------------------------------------------------- */
2055
+ const Header = (jsxRuntime.jsx("div", { ref: headerRef, className: "overflow-hidden w-full", children: jsxRuntime.jsx("div", { className: "grid bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", style: {
2056
+ gridTemplateColumns: gridTemplate,
2057
+ minWidth: 'fit-content',
2058
+ }, children: columns.map((col) => (jsxRuntime.jsx("div", { role: "columnheader", className: buildClassName('px-3 py-3 font-semibold text-sm whitespace-nowrap flex items-center', 'border-r last:border-r-0 border-gray-200 dark:border-gray-700', col.sticky === 'left' &&
2059
+ 'sticky left-0 z-20 bg-gray-50 dark:bg-gray-800 shadow-[2px_0_4px_rgba(0,0,0,0.05)]', col.sticky === 'right' &&
2060
+ 'sticky right-0 z-20 bg-gray-50 dark:bg-gray-800 shadow-[-2px_0_4px_rgba(0,0,0,0.05)]'), children: jsxRuntime.jsxs(TextContent, { role: col.sortable ? 'button' : undefined, className: buildClassName(col.sortable && 'inline-flex items-center gap-2 cursor-pointer select-none'), onClick: () => handleSort(col), children: [col.label, col.sortable ? getSortIcon(sorting[col.name]) : null] }) }, col.name))) }) }));
2061
+ /* -------------------------------------------------------
2062
+ * LOADING STATE (non-virtualized placeholder)
2063
+ * ------------------------------------------------------- */
2064
+ if (loading) {
2065
+ return (jsxRuntime.jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxRuntime.jsxs("div", { className: buildClassName('rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden', wrapperClass), children: [Header, jsxRuntime.jsx("div", { style: { height: maxHeight }, className: "flex flex-col", children: [...Array(6)].map((_, idx) => (jsxRuntime.jsx("div", { "data-testid": "skeleton-row", className: "grid animate-pulse bg-white dark:bg-gray-900 border-b border-gray-100 dark:border-gray-800", style: {
2066
+ gridTemplateColumns: gridTemplate,
2067
+ height: rowHeight,
2068
+ }, children: columns.map((col) => (jsxRuntime.jsx("div", { className: "px-3 py-3", children: jsxRuntime.jsx("div", { className: "h-4 w-3/4 bg-gray-300 dark:bg-gray-700 rounded" }) }, col.name))) }, idx))) })] }) }));
2069
+ }
2070
+ /* -------------------------------------------------------
2071
+ * EMPTY STATE (non-virtualized → single row)
2072
+ * ------------------------------------------------------- */
2073
+ if (!loading && items.length === 0) {
2074
+ return (jsxRuntime.jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxRuntime.jsxs("div", { className: buildClassName('rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden', wrapperClass), children: [Header, jsxRuntime.jsx("div", { className: "flex items-center justify-center text-gray-500 dark:text-gray-300", style: { height: maxHeight }, children: emptyMessage })] }) }));
2075
+ }
2076
+ /* -------------------------------------------------------
2077
+ * MAIN (virtualized body)
2078
+ * ------------------------------------------------------- */
2079
+ return (jsxRuntime.jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxRuntime.jsxs("div", { className: buildClassName('rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden', wrapperClass), children: [Header, jsxRuntime.jsx("div", { style: {
2080
+ height: maxHeight,
2081
+ overflowY: 'auto',
2082
+ overflowX: 'auto',
2083
+ }, children: jsxRuntime.jsx(Ae, { listRef: scrollRef, rowComponent: VirtualizedRow, rowCount: items.length, rowHeight: rowHeight, rowProps: { items, columns, gridTemplate }, onScroll: (e) => handleScrollSync(e.currentTarget.scrollLeft) }) })] }) }));
2084
+ };
2085
+
2086
+ const useIsMobile = () => {
2087
+ const [isMobile, setIsMobile] = React.useState(window.innerWidth < 768);
2088
+ React.useEffect(() => {
2089
+ function handleResize() {
2090
+ setIsMobile(window.innerWidth < 768);
2091
+ }
2092
+ window.addEventListener('resize', handleResize);
2093
+ return () => window.removeEventListener('resize', handleResize);
2094
+ }, []);
2095
+ return isMobile;
2096
+ };
2097
+
2098
+ const useIsTablet = () => {
2099
+ const [isTablet, setIsTablet] = React.useState(window.innerWidth < 768 && window.innerHeight > 960);
2100
+ React.useEffect(() => {
2101
+ function handleResize() {
2102
+ setIsTablet(window.innerWidth > 768 && window.innerHeight < 960);
2103
+ }
2104
+ window.addEventListener('resize', handleResize);
2105
+ return () => window.removeEventListener('resize', handleResize);
2106
+ }, []);
2107
+ return isTablet;
889
2108
  };
890
2109
 
891
2110
  exports.Alert = Alert;
@@ -898,6 +2117,7 @@ exports.Card = Card;
898
2117
  exports.Checkbox = Checkbox;
899
2118
  exports.CheckboxGroup = CheckboxGroup;
900
2119
  exports.DOTS = DOTS;
2120
+ exports.DataTable = DataTable;
901
2121
  exports.DetailedInformation = DetailedInformation;
902
2122
  exports.Dot = Dot;
903
2123
  exports.Drawer = Drawer;
@@ -912,27 +2132,38 @@ exports.PASSWORD_PLACEHOLDER = PASSWORD_PLACEHOLDER;
912
2132
  exports.PASSWORD_TYPE = PASSWORD_TYPE;
913
2133
  exports.Pagination = Pagination;
914
2134
  exports.PasswordInput = PasswordInput;
915
- exports.RadioButton = RadioButton;
916
- exports.RadioButtonGroup = RadioButtonGroup;
2135
+ exports.Radio = Radio;
2136
+ exports.RadioGroup = RadioGroup;
917
2137
  exports.RadioSwitch = RadioSwitch;
918
2138
  exports.RangeInput = RangeInput;
2139
+ exports.RangeSlider = RangeSlider;
919
2140
  exports.SelectBox = SelectBox;
920
- exports.TabelBody = TabelBody;
921
- exports.TabelFoot = TabelFoot;
922
- exports.TabelHead = TabelHead;
2141
+ exports.SortIconMap = SortIconMap;
923
2142
  exports.Table = Table;
2143
+ exports.TableBody = TableBody;
924
2144
  exports.TableCell = TableCell;
2145
+ exports.TableFoot = TableFoot;
2146
+ exports.TableHead = TableHead;
925
2147
  exports.TableHeaderCell = TableHeaderCell;
926
2148
  exports.TableRow = TableRow;
927
2149
  exports.Tabs = Tabs;
928
- exports.Tag = Tag;
929
2150
  exports.TextContent = TextContent;
930
2151
  exports.Textarea = Textarea;
2152
+ exports.Toast = Toast;
931
2153
  exports.ToastProvider = ToastProvider;
2154
+ exports.VirtualizedDataTable = VirtualizedDataTable;
932
2155
  exports.buildClassName = buildClassName;
2156
+ exports.buildInputClass = buildInputClass;
2157
+ exports.get = get;
2158
+ exports.getSortIcon = getSortIcon;
933
2159
  exports.isArray = isArray;
934
2160
  exports.isEmpty = isEmpty;
2161
+ exports.nextSortDirection = nextSortDirection;
2162
+ exports.updateSortQuery = updateSortQuery;
935
2163
  exports.useDebounce = useDebounce;
2164
+ exports.useDebounceFn = useDebounceFn;
2165
+ exports.useIsMobile = useIsMobile;
2166
+ exports.useIsTablet = useIsTablet;
936
2167
  exports.usePagination = usePagination;
937
2168
  exports.useToast = useToast;
938
2169
  //# sourceMappingURL=react-tailwind.cjs.js.map