@pk-design/react-tailwind 1.0.6 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react-tailwind.cjs.js +1593 -362
- package/dist/react-tailwind.cjs.js.map +1 -1
- package/dist/react-tailwind.es.js +1579 -360
- package/dist/react-tailwind.es.js.map +1 -1
- package/dist/types/components/Alert/Alert.d.ts +3 -0
- package/dist/types/components/Alert/Alert.test.d.ts +1 -0
- package/dist/types/components/Alert/Alert.types.d.ts +34 -0
- package/dist/types/components/Alert/index.d.ts +2 -35
- package/dist/types/components/Badge/Badge.d.ts +3 -0
- package/dist/types/components/Badge/Badge.test.d.ts +1 -0
- package/dist/types/components/Badge/Badge.types.d.ts +22 -0
- package/dist/types/components/Badge/index.d.ts +2 -24
- package/dist/types/components/Banner/Banner.d.ts +3 -0
- package/dist/types/components/Banner/Banner.test.d.ts +1 -0
- package/dist/types/components/Banner/Banner.types.d.ts +14 -0
- package/dist/types/components/Banner/index.d.ts +2 -16
- package/dist/types/components/BodyText/BodyText.d.ts +3 -0
- package/dist/types/components/BodyText/BodyText.test.d.ts +1 -0
- package/dist/types/components/BodyText/BodyText.types.d.ts +27 -0
- package/dist/types/components/BodyText/index.d.ts +2 -28
- package/dist/types/components/Breadcrumb/Breadcrumb.d.ts +3 -0
- package/dist/types/components/Breadcrumb/Breadcrumb.test.d.ts +1 -0
- package/dist/types/components/Breadcrumb/Breadcrumb.types.d.ts +29 -0
- package/dist/types/components/Breadcrumb/index.d.ts +2 -30
- package/dist/types/components/Button/Button.d.ts +2 -3
- package/dist/types/components/Button/Button.test.d.ts +1 -0
- package/dist/types/components/Button/Button.types.d.ts +171 -0
- package/dist/types/components/Button/index.d.ts +1 -1
- package/dist/types/components/Card/Card.d.ts +3 -0
- package/dist/types/components/Card/Card.test.d.ts +1 -0
- package/dist/types/components/Card/Card.types.d.ts +23 -0
- package/dist/types/components/Card/index.d.ts +2 -9
- package/dist/types/components/Checkbox/Checkbox.d.ts +2 -0
- package/dist/types/components/Checkbox/Checkbox.test.d.ts +1 -0
- package/dist/types/components/Checkbox/Checkbox.types.d.ts +14 -0
- package/dist/types/components/Checkbox/index.d.ts +2 -13
- package/dist/types/components/CheckboxGroup/CheckboxGroup.d.ts +5 -0
- package/dist/types/components/CheckboxGroup/CheckboxGroup.test.d.ts +1 -0
- package/dist/types/components/CheckboxGroup/CheckboxGroup.types.d.ts +55 -0
- package/dist/types/components/CheckboxGroup/index.d.ts +2 -56
- package/dist/types/components/DataTable/DataTable.d.ts +2 -0
- package/dist/types/components/DataTable/DataTable.icons.d.ts +4 -0
- package/dist/types/components/DataTable/DataTable.test.d.ts +1 -0
- package/dist/types/components/DataTable/DataTable.types.d.ts +63 -0
- package/dist/types/components/DataTable/DataTable.utils.d.ts +12 -0
- package/dist/types/components/DataTable/DataTable.utils.test.d.ts +1 -0
- package/dist/types/components/DataTable/index.d.ts +4 -0
- package/dist/types/components/DetailedInformation/DetailedInformation.d.ts +2 -0
- package/dist/types/components/DetailedInformation/DetailedInformation.test.d.ts +1 -0
- package/dist/types/components/DetailedInformation/DetailedInformation.types.d.ts +54 -0
- package/dist/types/components/DetailedInformation/index.d.ts +2 -63
- package/dist/types/components/Drawer/Drawer.d.ts +1 -1
- package/dist/types/components/Drawer/Drawer.test.d.ts +1 -0
- package/dist/types/components/Drawer/{type.d.ts → Drawer.types.d.ts} +1 -1
- package/dist/types/components/Drawer/index.d.ts +1 -1
- package/dist/types/components/Dropdown/Dropdown.d.ts +3 -0
- package/dist/types/components/Dropdown/Dropdown.test.d.ts +1 -0
- package/dist/types/components/Dropdown/Dropdown.types.d.ts +107 -0
- package/dist/types/components/Dropdown/index.d.ts +2 -62
- package/dist/types/components/HeadingText/HeadingText.d.ts +9 -0
- package/dist/types/components/HeadingText/HeadingText.types.d.ts +5 -0
- package/dist/types/components/HeadingText/index.d.ts +2 -12
- package/dist/types/components/Input/Input.d.ts +6 -0
- package/dist/types/components/Input/Input.test.d.ts +1 -0
- package/dist/types/components/Input/Input.types.d.ts +12 -0
- package/dist/types/components/Input/index.d.ts +2 -13
- package/dist/types/components/Label/Label.d.ts +6 -0
- package/dist/types/components/Label/index.d.ts +1 -5
- package/dist/types/components/Pagination/Pagination.d.ts +1 -31
- package/dist/types/components/Pagination/Pagination.test.d.ts +1 -0
- package/dist/types/components/Pagination/Pagination.types.d.ts +36 -0
- package/dist/types/components/Pagination/index.d.ts +1 -0
- package/dist/types/components/Pagination/usePagination.d.ts +1 -5
- package/dist/types/components/PasswordInput/PasswordInput.d.ts +6 -0
- package/dist/types/components/PasswordInput/PasswordInput.test.d.ts +1 -0
- package/dist/types/components/PasswordInput/index.d.ts +1 -6
- package/dist/types/components/Radio/Radio.d.ts +2 -0
- package/dist/types/components/Radio/Radio.test.d.ts +1 -0
- package/dist/types/components/Radio/Radio.types.d.ts +14 -0
- package/dist/types/components/Radio/index.d.ts +2 -0
- package/dist/types/components/RadioGroup/RadioGroup.d.ts +3 -0
- package/dist/types/components/RadioGroup/RadioGroup.test.d.ts +1 -0
- package/dist/types/components/RadioGroup/RadioGroup.types.d.ts +65 -0
- package/dist/types/components/RadioGroup/index.d.ts +2 -0
- package/dist/types/components/RadioSwitch/RadioSwitch.d.ts +7 -0
- package/dist/types/components/RadioSwitch/RadioSwitch.test.d.ts +1 -0
- package/dist/types/components/RadioSwitch/RadioSwitch.types.d.ts +47 -0
- package/dist/types/components/RadioSwitch/index.d.ts +2 -0
- package/dist/types/components/RangeInput/-backup.d.ts +10 -0
- package/dist/types/components/RangeInput/RangeInput.d.ts +2 -0
- package/dist/types/components/RangeInput/RangeInput.test.d.ts +1 -0
- package/dist/types/components/RangeInput/RangeInput.types.d.ts +14 -0
- package/dist/types/components/RangeInput/index.d.ts +1 -10
- package/dist/types/components/RangeSlider/RangeSlider.d.ts +3 -0
- package/dist/types/components/RangeSlider/RangeSlider.test.d.ts +1 -0
- package/dist/types/components/RangeSlider/RangeSlider.types.d.ts +68 -0
- package/dist/types/components/RangeSlider/index.d.ts +2 -0
- package/dist/types/components/SelectBox/SelectBox.d.ts +2 -0
- package/dist/types/components/SelectBox/SelectBox.test.d.ts +1 -0
- package/dist/types/components/SelectBox/SelectBox.types.d.ts +94 -0
- package/dist/types/components/SelectBox/index.d.ts +2 -40
- package/dist/types/components/Table/Table.d.ts +10 -0
- package/dist/types/components/Table/Table.test.d.ts +1 -0
- package/dist/types/components/Table/Table.types.d.ts +91 -0
- package/dist/types/components/Table/index.d.ts +2 -48
- package/dist/types/components/Tabs/Tabs.d.ts +3 -0
- package/dist/types/components/Tabs/Tabs.test.d.ts +1 -0
- package/dist/types/components/Tabs/Tabs.types.d.ts +48 -0
- package/dist/types/components/Tabs/index.d.ts +1 -2
- package/dist/types/components/TextContent/TextContent.d.ts +3 -0
- package/dist/types/components/TextContent/TextContent.test.d.ts +1 -0
- package/dist/types/components/TextContent/TextContent.types.d.ts +23 -0
- package/dist/types/components/TextContent/index.d.ts +2 -10
- package/dist/types/components/Textarea/Textarea.d.ts +2 -0
- package/dist/types/components/Textarea/Textarea.test.d.ts +1 -0
- package/dist/types/components/Textarea/Textarea.types.d.ts +6 -0
- package/dist/types/components/Textarea/index.d.ts +2 -7
- package/dist/types/components/Toast/Toast.d.ts +4 -8
- package/dist/types/components/Toast/Toast.test.d.ts +1 -0
- package/dist/types/components/Toast/Toast.types.d.ts +117 -0
- package/dist/types/components/Toast/ToastProvider.d.ts +2 -11
- package/dist/types/components/Toast/ToastProvider.test.d.ts +1 -0
- package/dist/types/components/Toast/index.d.ts +1 -0
- package/dist/types/components/VirtualizedDataTable/VirtualizedDataTable.d.ts +3 -0
- package/dist/types/components/VirtualizedDataTable/VirtualizedDataTable.test.d.ts +1 -0
- package/dist/types/components/VirtualizedDataTable/VirtualizedDataTable.types.d.ts +18 -0
- package/dist/types/components/VirtualizedDataTable/VirtualizedRow.d.ts +5 -0
- package/dist/types/components/VirtualizedDataTable/index.d.ts +2 -0
- package/dist/types/components/_Dialog/Dialog.d.ts +4 -0
- package/dist/types/components/_Dialog/Dialog.types.d.ts +53 -0
- package/dist/types/components/_Dialog/index.d.ts +2 -0
- package/dist/types/components/common-type.d.ts +2 -1
- package/dist/types/hooks/use-debounce.d.ts +2 -0
- package/dist/types/hooks/use-is-mobile.d.ts +1 -0
- package/dist/types/hooks/use-is-tablet.d.ts +1 -0
- package/dist/types/index.d.ts +11 -6
- package/dist/types/utils/get.d.ts +1 -0
- package/package.json +20 -4
- package/dist/types/components/Button/type.d.ts +0 -58
- package/dist/types/components/RadioButton/index.d.ts +0 -7
- package/dist/types/components/RadioButtonGroup/index.d.ts +0 -19
- package/dist/types/components/RadioSwtich/index.d.ts +0 -14
- package/dist/types/components/Tag/index.d.ts +0 -12
- 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$
|
|
30
|
-
function _extends$
|
|
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$
|
|
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$
|
|
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$
|
|
51
|
-
function _extends$
|
|
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$
|
|
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$
|
|
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$
|
|
74
|
-
function _extends$
|
|
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$
|
|
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$
|
|
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$
|
|
97
|
-
function _extends$
|
|
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$
|
|
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$
|
|
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$
|
|
120
|
-
function _extends$
|
|
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$
|
|
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$
|
|
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 {
|
|
150
|
-
return React.createElement(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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(
|
|
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$
|
|
222
|
-
function _extends$
|
|
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$
|
|
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$
|
|
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$
|
|
241
|
-
function _extends$
|
|
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$
|
|
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$
|
|
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
|
|
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$
|
|
297
|
-
function _extends$
|
|
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$
|
|
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$
|
|
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: [
|
|
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
|
|
322
|
-
|
|
323
|
-
|
|
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-
|
|
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
|
-
|
|
334
|
-
|
|
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
|
|
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
|
-
|
|
342
|
-
|
|
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
|
-
|
|
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
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
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
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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
|
|
371
|
-
|
|
372
|
-
|
|
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$
|
|
376
|
-
function _extends$
|
|
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$
|
|
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$
|
|
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
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
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
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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
|
-
|
|
420
|
-
|
|
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
|
-
|
|
424
|
-
|
|
425
|
-
|
|
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
|
|
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-
|
|
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: "
|
|
713
|
+
d: "m21 16-4 4-4-4M17 20V4M3 8l4-4 4 4M7 4v16"
|
|
444
714
|
})));
|
|
445
715
|
};
|
|
446
716
|
|
|
447
|
-
const
|
|
448
|
-
|
|
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
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
const
|
|
456
|
-
return
|
|
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
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
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, "aria-label": "Close drawer", 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
|
|
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-
|
|
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: "
|
|
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
|
|
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
|
|
537
|
-
|
|
538
|
-
|
|
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
|
|
542
|
-
const { name, label
|
|
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-
|
|
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
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
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) =>
|
|
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 && !
|
|
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
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
return
|
|
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
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
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
|
-
|
|
1189
|
+
var _a;
|
|
1190
|
+
if (!isArray(selected))
|
|
724
1191
|
return;
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
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
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
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
|
-
|
|
738
|
-
|
|
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 (
|
|
747
|
-
console.error('Error loading options:',
|
|
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:
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
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, "aria-label": "Clear selection", 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
|
|
832
|
-
|
|
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 &&
|
|
847
|
-
const hasLeftGroup = leftGroup != null &&
|
|
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("
|
|
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
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
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
|
-
|
|
858
|
-
|
|
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
|
-
|
|
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
|
|
871
|
-
|
|
872
|
-
const
|
|
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) =>
|
|
881
|
-
|
|
882
|
-
|
|
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
|
-
|
|
886
|
-
|
|
1782
|
+
return e.addEventListener("scroll", p), () => {
|
|
1783
|
+
e.removeEventListener("scroll", p);
|
|
887
1784
|
};
|
|
888
|
-
|
|
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.
|
|
916
|
-
exports.
|
|
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.
|
|
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
|