@pk-design/react-tailwind 1.3.0 → 1.4.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 +98 -56
- package/dist/react-tailwind.cjs.js.map +1 -1
- package/dist/react-tailwind.es.js +98 -56
- package/dist/react-tailwind.es.js.map +1 -1
- package/dist/types/components/Banner/Banner.types.d.ts +2 -1
- package/dist/types/components/DataTable/DataTable.d.ts +4 -1
- package/dist/types/components/DataTable/DataTable.types.d.ts +68 -16
- package/dist/types/components/Table/Table.types.d.ts +7 -5
- package/dist/types/components/VirtualizedDataTable/VirtualizedDataTable.d.ts +2 -3
- package/dist/types/components/VirtualizedDataTable/VirtualizedDataTable.types.d.ts +31 -7
- package/dist/types/components/VirtualizedDataTable/VirtualizedRow.d.ts +2 -6
- package/package.json +1 -1
|
@@ -224,7 +224,7 @@ const TypeClassMap = {
|
|
|
224
224
|
const Alert = (props) => {
|
|
225
225
|
const { type = 'info', className = '', message, children, removable = false, onRemove = () => { }, ...restProps } = props;
|
|
226
226
|
const Icon = AlertTypeIconMap[type] || SvgInfo;
|
|
227
|
-
return (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: [jsxs("span", { className: "inline-flex items-center gap-2", children: [jsx(Icon, { className: "size-5", "data-testid": `alert-${type}-icon` }), jsx("span", { className: "pr-2 inline-flex items-center", children: message || children })] }), removable && (jsx(Button, { iconOnly: true, "aria-label": "Dismiss alert", size: "xs", variant: "plain", theme: "secondary", className: "hover:bg-black/
|
|
227
|
+
return (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: [jsxs("span", { className: "inline-flex items-center gap-2", children: [jsx(Icon, { className: "size-5", "data-testid": `alert-${type}-icon` }), jsx("span", { className: "pr-2 inline-flex items-center", children: message || children })] }), removable && (jsx(Button, { iconOnly: true, "aria-label": "Dismiss alert", size: "xs", variant: "plain", theme: "secondary", className: "hover:bg-black/10 dark:hover:bg-white/10", onClick: () => onRemove(), "data-testid": "alert-remove-btn", children: jsx(SvgX, { className: "size-4.5", "data-testid": "alert-remove-icon" }) }))] }));
|
|
228
228
|
};
|
|
229
229
|
Alert.displayName = 'Alert';
|
|
230
230
|
|
|
@@ -237,7 +237,7 @@ const ThemeClassMap = {
|
|
|
237
237
|
};
|
|
238
238
|
const Badge = forwardRef((props, ref) => {
|
|
239
239
|
const { theme = 'info', className = '', children, removable = false, rounded = false, onRemove = () => { }, ...restProps } = props;
|
|
240
|
-
return (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: [jsx(TextContent, { className: "pr-3 inline-flex items-center", children: children }), removable ? (jsx(SvgX, { className: "size-5 px-0.5 mr-1 hover:bg-
|
|
240
|
+
return (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: [jsx(TextContent, { className: "pr-3 inline-flex items-center", children: children }), removable ? (jsx(SvgX, { className: "size-5 px-0.5 mr-1 hover:bg-black/10 dark:hover:bg-white/10 rounded-sm cursor-pointer", role: "button", tabIndex: 0, "aria-label": "Remove", onClick: () => onRemove(), onKeyDown: (e) => {
|
|
241
241
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
242
242
|
e.preventDefault();
|
|
243
243
|
onRemove();
|
|
@@ -289,13 +289,11 @@ var SvgCircleCheck = function SvgCircleCheck(props) {
|
|
|
289
289
|
};
|
|
290
290
|
|
|
291
291
|
const sizeMap = {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
9: `size-9`,
|
|
298
|
-
10: `size-10`,
|
|
292
|
+
xs: 'size-4',
|
|
293
|
+
sm: 'size-5',
|
|
294
|
+
md: 'size-6',
|
|
295
|
+
lg: 'size-8',
|
|
296
|
+
xl: 'size-10',
|
|
299
297
|
};
|
|
300
298
|
const IconMap = {
|
|
301
299
|
info: SvgInfo,
|
|
@@ -304,7 +302,7 @@ const IconMap = {
|
|
|
304
302
|
warning: SvgTriangleAlert,
|
|
305
303
|
};
|
|
306
304
|
const Banner = forwardRef((props, ref) => {
|
|
307
|
-
const { type = 'info', iconSize =
|
|
305
|
+
const { type = 'info', iconSize = 'sm', children, ...restProps } = props;
|
|
308
306
|
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' : '');
|
|
309
307
|
const renderIcon = () => {
|
|
310
308
|
const Icon = IconMap[type];
|
|
@@ -430,9 +428,7 @@ const TableRowLoader = ({ colSize, rowSize }) => (jsx(Fragment, { children: Arra
|
|
|
430
428
|
/* ----------------------------------------------
|
|
431
429
|
* Table
|
|
432
430
|
* ---------------------------------------------- */
|
|
433
|
-
const Table = ({ children, layout = 'auto', className = '' }) => {
|
|
434
|
-
return (jsx("table", { className: buildClassName('border-collapse w-full divide-y divide-gray-200 dark:divide-gray-700', TABLE_LAYOUT[layout], className), children: children }));
|
|
435
|
-
};
|
|
431
|
+
const Table = ({ children, layout = 'auto', className = '', caption, }) => (jsxs("table", { className: buildClassName('border-collapse w-full divide-y divide-gray-200 dark:divide-gray-700', TABLE_LAYOUT[layout], className), children: [caption && (jsx("caption", { className: "mb-2 text-sm text-left text-gray-500 dark:text-gray-400", children: caption })), children] }));
|
|
436
432
|
/* ----------------------------------------------
|
|
437
433
|
* Head
|
|
438
434
|
* ---------------------------------------------- */
|
|
@@ -440,7 +436,7 @@ const TableHead = ({ children, className = '' }) => (jsx("thead", { className: b
|
|
|
440
436
|
/* ----------------------------------------------
|
|
441
437
|
* Body
|
|
442
438
|
* ---------------------------------------------- */
|
|
443
|
-
const TableBody = ({ children, loading, colSize, rowSize = 5, className, }) => (jsx("tbody", { className: buildClassName('text-sm text-gray-700 dark:text-white divide-y divide-gray-200 dark:divide-gray-700', className), children: loading ? jsx(TableRowLoader, { colSize: colSize, rowSize: rowSize }) : children }));
|
|
439
|
+
const TableBody = ({ children, loading, colSize = 1, rowSize = 5, className, }) => (jsx("tbody", { className: buildClassName('text-sm text-gray-700 dark:text-white divide-y divide-gray-200 dark:divide-gray-700', className), children: loading ? jsx(TableRowLoader, { colSize: colSize, rowSize: rowSize }) : children }));
|
|
444
440
|
/* ----------------------------------------------
|
|
445
441
|
* Foot
|
|
446
442
|
* ---------------------------------------------- */
|
|
@@ -453,7 +449,7 @@ const TableRow = ({ children, hoverable = false, className, ...props }) => (jsx(
|
|
|
453
449
|
* Cells
|
|
454
450
|
* ---------------------------------------------- */
|
|
455
451
|
const TableCell = ({ children, align = 'left', className, ...props }) => (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: jsx("div", { className: "leading-normal", children: children }) }));
|
|
456
|
-
const TableHeaderCell = ({ children, align = 'left', className, ...props }) => (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:
|
|
452
|
+
const TableHeaderCell = ({ children, align = 'left', className, ...props }) => (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: children }));
|
|
457
453
|
/* ----------------------------------------------
|
|
458
454
|
* Empty Row
|
|
459
455
|
* ---------------------------------------------- */
|
|
@@ -703,9 +699,11 @@ const SortIconMap = {
|
|
|
703
699
|
};
|
|
704
700
|
const getSortIcon = (sort) => sort ? (SortIconMap[sort]) : (jsx(SvgArrowUpDown, { className: "size-4 text-gray-400 shrink-0 group-hover:text-gray-800 dark:group-hover:text-white" }));
|
|
705
701
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
702
|
+
const DENSITY_CELL_CLASS$2 = {
|
|
703
|
+
compact: 'px-2 py-1.5',
|
|
704
|
+
default: '',
|
|
705
|
+
spacious: 'px-4 py-4',
|
|
706
|
+
};
|
|
709
707
|
const autoSortItems = (items, column, sort) => {
|
|
710
708
|
const path = column.name;
|
|
711
709
|
return [...items].sort((a, b) => {
|
|
@@ -721,7 +719,6 @@ const autoSortItems = (items, column, sort) => {
|
|
|
721
719
|
const dB = new Date(valueB).getTime();
|
|
722
720
|
return sort === 'asc' || sort === '1' ? dA - dB : dB - dA;
|
|
723
721
|
}
|
|
724
|
-
// String fallback
|
|
725
722
|
const sA = String(valueA).toLowerCase();
|
|
726
723
|
const sB = String(valueB).toLowerCase();
|
|
727
724
|
if (sA < sB)
|
|
@@ -731,7 +728,7 @@ const autoSortItems = (items, column, sort) => {
|
|
|
731
728
|
return 0;
|
|
732
729
|
});
|
|
733
730
|
};
|
|
734
|
-
|
|
731
|
+
function DataTable({ items, columns, sorting = {}, onSort, loading, pagination, setPagination = () => { }, emptyMessage = 'No data found', containerClass = '', wrapperClass = '', tableClass = '', headClass = '', footerRow, rowKey = 'id', onRowClick, rowClass, density = 'default', striped = false, layout = 'auto', }) {
|
|
735
732
|
const internalSorting = useRef({});
|
|
736
733
|
const [sortedItems, setSortedItems] = useState(items);
|
|
737
734
|
useEffect(() => {
|
|
@@ -746,17 +743,38 @@ const DataTable = ({ items, columns, sorting = {}, onSort, loading, pagination =
|
|
|
746
743
|
return;
|
|
747
744
|
onSort ? onSort(column) : doAutoSort(column);
|
|
748
745
|
};
|
|
749
|
-
|
|
746
|
+
const getKey = (item, idx) => {
|
|
747
|
+
var _a;
|
|
748
|
+
if (typeof rowKey === 'function')
|
|
749
|
+
return rowKey(item);
|
|
750
|
+
return (_a = item[rowKey]) !== null && _a !== void 0 ? _a : idx;
|
|
751
|
+
};
|
|
752
|
+
const getRowClass = (item, idx) => {
|
|
753
|
+
if (!rowClass)
|
|
754
|
+
return '';
|
|
755
|
+
if (typeof rowClass === 'function')
|
|
756
|
+
return rowClass(item, idx);
|
|
757
|
+
return rowClass;
|
|
758
|
+
};
|
|
759
|
+
const getCellClass = (column, item) => {
|
|
760
|
+
if (!column.cellClass)
|
|
761
|
+
return '';
|
|
762
|
+
if (typeof column.cellClass === 'function')
|
|
763
|
+
return column.cellClass(item);
|
|
764
|
+
return column.cellClass;
|
|
765
|
+
};
|
|
766
|
+
const densityCellClass = DENSITY_CELL_CLASS$2[density];
|
|
767
|
+
return (jsxs("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: [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: jsxs(Table, { className: buildClassName('relative w-full max-w-full h-fit', tableClass), layout: layout, children: [jsx(TableHead, { className: headClass, children: columns.map((column) => (jsx(TableHeaderCell, { align: column.headerAlign, style: { width: column.width || 'auto' }, className: buildClassName('bg-gray-50 dark:bg-gray-800', densityCellClass, column.sticky === 'left' &&
|
|
750
768
|
'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
|
|
751
|
-
'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]'), children: 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: [jsx(TextContent, { className: "shrink-0", children: column.label }), column.sortable ? getSortIcon(sorting[column.name]) : null] }) }, column.name))) }), jsx(TableBody, { loading: loading, colSize: columns.length, rowSize: (pagination === null || pagination === void 0 ? void 0 : pagination.limit) || 5, children: !loading && sortedItems.length === 0 ? (jsx(EmptyTableRow, { colSpan: columns.length, children: emptyMessage })) : (sortedItems.map((item) => (jsx(TableRow, { className:
|
|
769
|
+
'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]', column.headerClass), children: 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: [jsx(TextContent, { className: "shrink-0", children: column.label }), column.sortable ? getSortIcon(sorting[column.name]) : null] }) }, column.name))) }), jsx(TableBody, { loading: loading, colSize: columns.length, rowSize: (pagination === null || pagination === void 0 ? void 0 : pagination.limit) || 5, children: !loading && sortedItems.length === 0 ? (jsx(EmptyTableRow, { colSpan: columns.length, children: emptyMessage })) : (sortedItems.map((item, idx) => (jsx(TableRow, { className: buildClassName('group', onRowClick && 'cursor-pointer', striped && idx % 2 === 1 && 'bg-gray-50 dark:bg-gray-800/40', getRowClass(item, idx)), onClick: onRowClick ? () => onRowClick(item, idx) : undefined, children: columns.map((column) => {
|
|
752
770
|
var _a;
|
|
753
|
-
return (jsx(TableCell, { align: column.align, className: buildClassName(column.sticky === 'left' &&
|
|
771
|
+
return (jsx(TableCell, { align: column.align, className: buildClassName(densityCellClass, striped && idx % 2 === 1 && 'bg-gray-50 dark:bg-gray-800/40', column.sticky === 'left' &&
|
|
754
772
|
'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
|
|
755
|
-
'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]'), children: column.render
|
|
773
|
+
'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]', getCellClass(column, item)), children: column.render
|
|
756
774
|
? column.render(item)
|
|
757
775
|
: ((_a = get(item, column.name)) !== null && _a !== void 0 ? _a : 'Not set') }, column.name));
|
|
758
|
-
}) }, item
|
|
759
|
-
}
|
|
776
|
+
}) }, getKey(item, idx))))) }), footerRow && jsx(TableFoot, { children: footerRow })] }) }), pagination && (jsx(Pagination, { ...pagination, className: "rounded-b-lg border border-t-0 border-gray-200 dark:border-gray-800", onChange: setPagination }))] }));
|
|
777
|
+
}
|
|
760
778
|
DataTable.displayName = 'DataTable';
|
|
761
779
|
|
|
762
780
|
const Title = ({ children, className }) => (jsx("h1", { className: buildClassName('text-3xl font-bold', className), children: children }));
|
|
@@ -1428,33 +1446,61 @@ const ToastProvider = ({ children, placement = 'top-center' }) => {
|
|
|
1428
1446
|
return (jsxs(ToastContext.Provider, { value: { showToast, closeToast }, children: [children, jsx("div", { className: buildClassName('fixed z-50 flex flex-col gap-3 pointer-events-none', placementClass[placement]), children: toasts.map((toast, index) => (jsx("div", { className: "pointer-events-auto", onMouseEnter: () => toast.pauseOnHover && clearTimer(toast.id), onMouseLeave: () => toast.pauseOnHover && scheduleClose(toast), children: jsx(Toast, { ...toast, isTop: placement.startsWith('top'), onClose: () => closeToast(toast.id) }) }, toast.id))) })] }));
|
|
1429
1447
|
};
|
|
1430
1448
|
|
|
1431
|
-
const
|
|
1432
|
-
|
|
1449
|
+
const DENSITY_CELL_CLASS$1 = {
|
|
1450
|
+
compact: 'px-2 py-1.5',
|
|
1451
|
+
default: 'px-3 py-3',
|
|
1452
|
+
spacious: 'px-4 py-4',
|
|
1453
|
+
};
|
|
1454
|
+
const VirtualizedRow = ({ index, style, data, }) => {
|
|
1455
|
+
const { items, columns, gridTemplate, onRowClick, rowClass, density = 'default', striped } = data;
|
|
1433
1456
|
const item = items[index];
|
|
1434
|
-
|
|
1457
|
+
const isStriped = striped && index % 2 === 1;
|
|
1458
|
+
const resolvedRowClass = !rowClass
|
|
1459
|
+
? ''
|
|
1460
|
+
: typeof rowClass === 'function'
|
|
1461
|
+
? rowClass(item, index)
|
|
1462
|
+
: rowClass;
|
|
1463
|
+
const getCellClass = (col) => {
|
|
1464
|
+
if (!col.cellClass)
|
|
1465
|
+
return '';
|
|
1466
|
+
if (typeof col.cellClass === 'function')
|
|
1467
|
+
return col.cellClass(item);
|
|
1468
|
+
return col.cellClass;
|
|
1469
|
+
};
|
|
1470
|
+
const densityCellClass = DENSITY_CELL_CLASS$1[density];
|
|
1471
|
+
return (jsx("div", { role: "row", className: buildClassName('grid border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 group', onRowClick && 'cursor-pointer', isStriped && 'bg-gray-50 dark:bg-gray-800/40', resolvedRowClass), style: {
|
|
1435
1472
|
...style,
|
|
1436
1473
|
display: 'grid',
|
|
1437
1474
|
gridTemplateColumns: gridTemplate,
|
|
1438
1475
|
minWidth: 'fit-content',
|
|
1439
|
-
}, children: columns.map((col) => {
|
|
1476
|
+
}, onClick: onRowClick ? () => onRowClick(item, index) : undefined, children: columns.map((col) => {
|
|
1440
1477
|
var _a;
|
|
1441
1478
|
const content = col.render ? col.render(item) : ((_a = get(item, col.name)) !== null && _a !== void 0 ? _a : 'Not set');
|
|
1442
|
-
return (jsx("div", { role: "cell", className: buildClassName('
|
|
1479
|
+
return (jsx("div", { role: "cell", className: buildClassName('whitespace-nowrap border-r last:border-r-0 border-gray-200 dark:border-gray-700', densityCellClass, col.align === 'center' && 'text-center', col.align === 'right' && 'text-right', col.sticky === 'left' &&
|
|
1443
1480
|
'sticky left-0 z-10 bg-white dark:bg-gray-900 shadow-[2px_0_4px_rgba(0,0,0,0.05)]', col.sticky === 'right' &&
|
|
1444
|
-
'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));
|
|
1481
|
+
'sticky right-0 z-10 bg-white dark:bg-gray-900 shadow-[-2px_0_4px_rgba(0,0,0,0.05)]', isStriped && 'bg-gray-50 dark:bg-gray-800/40', getCellClass(col)), children: content }, col.name));
|
|
1445
1482
|
}) }));
|
|
1446
1483
|
};
|
|
1447
1484
|
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1485
|
+
const DENSITY_CELL_CLASS = {
|
|
1486
|
+
compact: 'px-2 py-1.5',
|
|
1487
|
+
default: 'px-3 py-3',
|
|
1488
|
+
spacious: 'px-4 py-4',
|
|
1489
|
+
};
|
|
1490
|
+
const columnWidth = (col) => {
|
|
1491
|
+
if (!col.width)
|
|
1492
|
+
return '1fr';
|
|
1493
|
+
if (typeof col.width === 'number')
|
|
1494
|
+
return `${col.width}px`;
|
|
1495
|
+
return col.width;
|
|
1496
|
+
};
|
|
1497
|
+
function VirtualizedDataTable({ items, columns, sorting = {}, onSort, loading = false, emptyMessage = 'No data available', containerClass = '', wrapperClass = '', onRowClick, rowClass, density = 'default', striped = false, rowHeight = 48, maxHeight = 400, overscanCount = 3, }) {
|
|
1453
1498
|
const scrollRef = useRef(null);
|
|
1454
1499
|
const outerRef = useRef(null);
|
|
1455
1500
|
const headerRef = useRef(null);
|
|
1456
|
-
const gridTemplate =
|
|
1457
|
-
|
|
1501
|
+
const gridTemplate = useMemo(() => columns.map((col) => columnWidth(col)).join(' '), [columns]);
|
|
1502
|
+
const densityCellClass = DENSITY_CELL_CLASS[density];
|
|
1503
|
+
const skeletonRows = Math.max(1, Math.floor(maxHeight / rowHeight));
|
|
1458
1504
|
useEffect(() => {
|
|
1459
1505
|
const el = outerRef.current;
|
|
1460
1506
|
if (!el)
|
|
@@ -1470,35 +1516,31 @@ const VirtualizedDataTable = ({ items, columns, sorting = {}, onSort, loading =
|
|
|
1470
1516
|
if (column.sortable)
|
|
1471
1517
|
onSort === null || onSort === void 0 ? void 0 : onSort(column);
|
|
1472
1518
|
}, [onSort]);
|
|
1519
|
+
const itemData = useMemo(() => ({ items, columns, gridTemplate, onRowClick, rowClass, density, striped }), [items, columns, gridTemplate, onRowClick, rowClass, density, striped]);
|
|
1473
1520
|
/* -------------------------------------------------------
|
|
1474
|
-
*
|
|
1521
|
+
* Header
|
|
1475
1522
|
* ------------------------------------------------------- */
|
|
1476
|
-
const Header = (jsx("div", { ref: headerRef, className: "overflow-hidden w-full", children: jsx("div", { className: "grid bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", style: {
|
|
1477
|
-
gridTemplateColumns: gridTemplate,
|
|
1478
|
-
minWidth: 'fit-content',
|
|
1479
|
-
}, children: columns.map((col) => (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' &&
|
|
1523
|
+
const Header = (jsx("div", { ref: headerRef, className: "overflow-hidden w-full", children: jsx("div", { className: "grid bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", style: { gridTemplateColumns: gridTemplate, minWidth: 'fit-content' }, children: columns.map((col) => (jsx("div", { role: "columnheader", className: buildClassName('font-semibold text-sm whitespace-nowrap flex items-center', densityCellClass, 'border-r last:border-r-0 border-gray-200 dark:border-gray-700', col.sticky === 'left' &&
|
|
1480
1524
|
'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' &&
|
|
1481
|
-
'sticky right-0 z-20 bg-gray-50 dark:bg-gray-800 shadow-[-2px_0_4px_rgba(0,0,0,0.05)]'), children: 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))) }) }));
|
|
1525
|
+
'sticky right-0 z-20 bg-gray-50 dark:bg-gray-800 shadow-[-2px_0_4px_rgba(0,0,0,0.05)]', col.headerClass), children: 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))) }) }));
|
|
1526
|
+
const wrapperCls = buildClassName('rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden', wrapperClass);
|
|
1482
1527
|
/* -------------------------------------------------------
|
|
1483
|
-
*
|
|
1528
|
+
* Loading state
|
|
1484
1529
|
* ------------------------------------------------------- */
|
|
1485
1530
|
if (loading) {
|
|
1486
|
-
return (jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxs("div", { className:
|
|
1487
|
-
gridTemplateColumns: gridTemplate,
|
|
1488
|
-
height: rowHeight,
|
|
1489
|
-
}, children: columns.map((col) => (jsx("div", { className: "px-3 py-3", children: jsx("div", { className: "h-4 w-3/4 bg-gray-300 dark:bg-gray-700 rounded" }) }, col.name))) }, idx))) })] }) }));
|
|
1531
|
+
return (jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxs("div", { className: wrapperCls, children: [Header, jsx("div", { style: { height: maxHeight }, className: "flex flex-col", children: Array.from({ length: skeletonRows }).map((_, idx) => (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: { gridTemplateColumns: gridTemplate, height: rowHeight }, children: columns.map((col) => (jsx("div", { className: densityCellClass, children: jsx("div", { className: "h-4 w-3/4 bg-gray-300 dark:bg-gray-700 rounded" }) }, col.name))) }, idx))) })] }) }));
|
|
1490
1532
|
}
|
|
1491
1533
|
/* -------------------------------------------------------
|
|
1492
|
-
*
|
|
1534
|
+
* Empty state
|
|
1493
1535
|
* ------------------------------------------------------- */
|
|
1494
|
-
if (
|
|
1495
|
-
return (jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxs("div", { className:
|
|
1536
|
+
if (items.length === 0) {
|
|
1537
|
+
return (jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxs("div", { className: wrapperCls, children: [Header, jsx("div", { className: "flex items-center justify-center text-gray-500 dark:text-gray-300", style: { height: maxHeight }, children: emptyMessage })] }) }));
|
|
1496
1538
|
}
|
|
1497
1539
|
/* -------------------------------------------------------
|
|
1498
|
-
*
|
|
1540
|
+
* Virtualized body
|
|
1499
1541
|
* ------------------------------------------------------- */
|
|
1500
|
-
return (jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxs("div", { className:
|
|
1501
|
-
}
|
|
1542
|
+
return (jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxs("div", { className: wrapperCls, children: [Header, jsx(FixedSizeList, { ref: scrollRef, outerRef: outerRef, height: maxHeight, width: "100%", itemCount: items.length, itemSize: rowHeight, itemData: itemData, overscanCount: overscanCount, children: VirtualizedRow })] }) }));
|
|
1543
|
+
}
|
|
1502
1544
|
|
|
1503
1545
|
const useIsMobile = () => {
|
|
1504
1546
|
const [isMobile, setIsMobile] = useState(false);
|