@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
|
@@ -244,7 +244,7 @@ const TypeClassMap = {
|
|
|
244
244
|
const Alert = (props) => {
|
|
245
245
|
const { type = 'info', className = '', message, children, removable = false, onRemove = () => { }, ...restProps } = props;
|
|
246
246
|
const Icon = AlertTypeIconMap[type] || SvgInfo;
|
|
247
|
-
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, "aria-label": "Dismiss alert", size: "xs", variant: "plain", theme: "secondary", className: "hover:bg-black/
|
|
247
|
+
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, "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: jsxRuntime.jsx(SvgX, { className: "size-4.5", "data-testid": "alert-remove-icon" }) }))] }));
|
|
248
248
|
};
|
|
249
249
|
Alert.displayName = 'Alert';
|
|
250
250
|
|
|
@@ -257,7 +257,7 @@ const ThemeClassMap = {
|
|
|
257
257
|
};
|
|
258
258
|
const Badge = React.forwardRef((props, ref) => {
|
|
259
259
|
const { theme = 'info', className = '', children, removable = false, rounded = false, onRemove = () => { }, ...restProps } = props;
|
|
260
|
-
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-
|
|
260
|
+
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-black/10 dark:hover:bg-white/10 rounded-sm cursor-pointer", role: "button", tabIndex: 0, "aria-label": "Remove", onClick: () => onRemove(), onKeyDown: (e) => {
|
|
261
261
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
262
262
|
e.preventDefault();
|
|
263
263
|
onRemove();
|
|
@@ -309,13 +309,11 @@ var SvgCircleCheck = function SvgCircleCheck(props) {
|
|
|
309
309
|
};
|
|
310
310
|
|
|
311
311
|
const sizeMap = {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
9: `size-9`,
|
|
318
|
-
10: `size-10`,
|
|
312
|
+
xs: 'size-4',
|
|
313
|
+
sm: 'size-5',
|
|
314
|
+
md: 'size-6',
|
|
315
|
+
lg: 'size-8',
|
|
316
|
+
xl: 'size-10',
|
|
319
317
|
};
|
|
320
318
|
const IconMap = {
|
|
321
319
|
info: SvgInfo,
|
|
@@ -324,7 +322,7 @@ const IconMap = {
|
|
|
324
322
|
warning: SvgTriangleAlert,
|
|
325
323
|
};
|
|
326
324
|
const Banner = React.forwardRef((props, ref) => {
|
|
327
|
-
const { type = 'info', iconSize =
|
|
325
|
+
const { type = 'info', iconSize = 'sm', children, ...restProps } = props;
|
|
328
326
|
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' : '');
|
|
329
327
|
const renderIcon = () => {
|
|
330
328
|
const Icon = IconMap[type];
|
|
@@ -450,9 +448,7 @@ const TableRowLoader = ({ colSize, rowSize }) => (jsxRuntime.jsx(jsxRuntime.Frag
|
|
|
450
448
|
/* ----------------------------------------------
|
|
451
449
|
* Table
|
|
452
450
|
* ---------------------------------------------- */
|
|
453
|
-
const Table = ({ children, layout = 'auto', className = '' }) => {
|
|
454
|
-
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 }));
|
|
455
|
-
};
|
|
451
|
+
const Table = ({ children, layout = 'auto', className = '', caption, }) => (jsxRuntime.jsxs("table", { className: buildClassName('border-collapse w-full divide-y divide-gray-200 dark:divide-gray-700', TABLE_LAYOUT[layout], className), children: [caption && (jsxRuntime.jsx("caption", { className: "mb-2 text-sm text-left text-gray-500 dark:text-gray-400", children: caption })), children] }));
|
|
456
452
|
/* ----------------------------------------------
|
|
457
453
|
* Head
|
|
458
454
|
* ---------------------------------------------- */
|
|
@@ -460,7 +456,7 @@ const TableHead = ({ children, className = '' }) => (jsxRuntime.jsx("thead", { c
|
|
|
460
456
|
/* ----------------------------------------------
|
|
461
457
|
* Body
|
|
462
458
|
* ---------------------------------------------- */
|
|
463
|
-
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 }));
|
|
459
|
+
const TableBody = ({ children, loading, colSize = 1, 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 }));
|
|
464
460
|
/* ----------------------------------------------
|
|
465
461
|
* Foot
|
|
466
462
|
* ---------------------------------------------- */
|
|
@@ -473,7 +469,7 @@ const TableRow = ({ children, hoverable = false, className, ...props }) => (jsxR
|
|
|
473
469
|
* Cells
|
|
474
470
|
* ---------------------------------------------- */
|
|
475
471
|
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 }) }));
|
|
476
|
-
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:
|
|
472
|
+
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: children }));
|
|
477
473
|
/* ----------------------------------------------
|
|
478
474
|
* Empty Row
|
|
479
475
|
* ---------------------------------------------- */
|
|
@@ -723,9 +719,11 @@ const SortIconMap = {
|
|
|
723
719
|
};
|
|
724
720
|
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" }));
|
|
725
721
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
722
|
+
const DENSITY_CELL_CLASS$2 = {
|
|
723
|
+
compact: 'px-2 py-1.5',
|
|
724
|
+
default: '',
|
|
725
|
+
spacious: 'px-4 py-4',
|
|
726
|
+
};
|
|
729
727
|
const autoSortItems = (items, column, sort) => {
|
|
730
728
|
const path = column.name;
|
|
731
729
|
return [...items].sort((a, b) => {
|
|
@@ -741,7 +739,6 @@ const autoSortItems = (items, column, sort) => {
|
|
|
741
739
|
const dB = new Date(valueB).getTime();
|
|
742
740
|
return sort === 'asc' || sort === '1' ? dA - dB : dB - dA;
|
|
743
741
|
}
|
|
744
|
-
// String fallback
|
|
745
742
|
const sA = String(valueA).toLowerCase();
|
|
746
743
|
const sB = String(valueB).toLowerCase();
|
|
747
744
|
if (sA < sB)
|
|
@@ -751,7 +748,7 @@ const autoSortItems = (items, column, sort) => {
|
|
|
751
748
|
return 0;
|
|
752
749
|
});
|
|
753
750
|
};
|
|
754
|
-
|
|
751
|
+
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', }) {
|
|
755
752
|
const internalSorting = React.useRef({});
|
|
756
753
|
const [sortedItems, setSortedItems] = React.useState(items);
|
|
757
754
|
React.useEffect(() => {
|
|
@@ -766,17 +763,38 @@ const DataTable = ({ items, columns, sorting = {}, onSort, loading, pagination =
|
|
|
766
763
|
return;
|
|
767
764
|
onSort ? onSort(column) : doAutoSort(column);
|
|
768
765
|
};
|
|
769
|
-
|
|
766
|
+
const getKey = (item, idx) => {
|
|
767
|
+
var _a;
|
|
768
|
+
if (typeof rowKey === 'function')
|
|
769
|
+
return rowKey(item);
|
|
770
|
+
return (_a = item[rowKey]) !== null && _a !== void 0 ? _a : idx;
|
|
771
|
+
};
|
|
772
|
+
const getRowClass = (item, idx) => {
|
|
773
|
+
if (!rowClass)
|
|
774
|
+
return '';
|
|
775
|
+
if (typeof rowClass === 'function')
|
|
776
|
+
return rowClass(item, idx);
|
|
777
|
+
return rowClass;
|
|
778
|
+
};
|
|
779
|
+
const getCellClass = (column, item) => {
|
|
780
|
+
if (!column.cellClass)
|
|
781
|
+
return '';
|
|
782
|
+
if (typeof column.cellClass === 'function')
|
|
783
|
+
return column.cellClass(item);
|
|
784
|
+
return column.cellClass;
|
|
785
|
+
};
|
|
786
|
+
const densityCellClass = DENSITY_CELL_CLASS$2[density];
|
|
787
|
+
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: buildClassName('relative w-full max-w-full h-fit', tableClass), layout: layout, children: [jsxRuntime.jsx(TableHead, { className: headClass, children: columns.map((column) => (jsxRuntime.jsx(TableHeaderCell, { align: column.headerAlign, style: { width: column.width || 'auto' }, className: buildClassName('bg-gray-50 dark:bg-gray-800', densityCellClass, column.sticky === 'left' &&
|
|
770
788
|
'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
|
|
771
|
-
'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 && sortedItems.length === 0 ? (jsxRuntime.jsx(EmptyTableRow, { colSpan: columns.length, children: emptyMessage })) : (sortedItems.map((item) => (jsxRuntime.jsx(TableRow, { className:
|
|
789
|
+
'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]', column.headerClass), 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 && sortedItems.length === 0 ? (jsxRuntime.jsx(EmptyTableRow, { colSpan: columns.length, children: emptyMessage })) : (sortedItems.map((item, idx) => (jsxRuntime.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) => {
|
|
772
790
|
var _a;
|
|
773
|
-
return (jsxRuntime.jsx(TableCell, { align: column.align, className: buildClassName(column.sticky === 'left' &&
|
|
791
|
+
return (jsxRuntime.jsx(TableCell, { align: column.align, className: buildClassName(densityCellClass, striped && idx % 2 === 1 && 'bg-gray-50 dark:bg-gray-800/40', column.sticky === 'left' &&
|
|
774
792
|
'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
|
|
775
|
-
'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]'), children: column.render
|
|
793
|
+
'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]', getCellClass(column, item)), children: column.render
|
|
776
794
|
? column.render(item)
|
|
777
795
|
: ((_a = get(item, column.name)) !== null && _a !== void 0 ? _a : 'Not set') }, column.name));
|
|
778
|
-
}) }, item
|
|
779
|
-
}
|
|
796
|
+
}) }, getKey(item, idx))))) }), footerRow && jsxRuntime.jsx(TableFoot, { children: footerRow })] }) }), pagination && (jsxRuntime.jsx(Pagination, { ...pagination, className: "rounded-b-lg border border-t-0 border-gray-200 dark:border-gray-800", onChange: setPagination }))] }));
|
|
797
|
+
}
|
|
780
798
|
DataTable.displayName = 'DataTable';
|
|
781
799
|
|
|
782
800
|
const Title = ({ children, className }) => (jsxRuntime.jsx("h1", { className: buildClassName('text-3xl font-bold', className), children: children }));
|
|
@@ -1448,33 +1466,61 @@ const ToastProvider = ({ children, placement = 'top-center' }) => {
|
|
|
1448
1466
|
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))) })] }));
|
|
1449
1467
|
};
|
|
1450
1468
|
|
|
1451
|
-
const
|
|
1452
|
-
|
|
1469
|
+
const DENSITY_CELL_CLASS$1 = {
|
|
1470
|
+
compact: 'px-2 py-1.5',
|
|
1471
|
+
default: 'px-3 py-3',
|
|
1472
|
+
spacious: 'px-4 py-4',
|
|
1473
|
+
};
|
|
1474
|
+
const VirtualizedRow = ({ index, style, data, }) => {
|
|
1475
|
+
const { items, columns, gridTemplate, onRowClick, rowClass, density = 'default', striped } = data;
|
|
1453
1476
|
const item = items[index];
|
|
1454
|
-
|
|
1477
|
+
const isStriped = striped && index % 2 === 1;
|
|
1478
|
+
const resolvedRowClass = !rowClass
|
|
1479
|
+
? ''
|
|
1480
|
+
: typeof rowClass === 'function'
|
|
1481
|
+
? rowClass(item, index)
|
|
1482
|
+
: rowClass;
|
|
1483
|
+
const getCellClass = (col) => {
|
|
1484
|
+
if (!col.cellClass)
|
|
1485
|
+
return '';
|
|
1486
|
+
if (typeof col.cellClass === 'function')
|
|
1487
|
+
return col.cellClass(item);
|
|
1488
|
+
return col.cellClass;
|
|
1489
|
+
};
|
|
1490
|
+
const densityCellClass = DENSITY_CELL_CLASS$1[density];
|
|
1491
|
+
return (jsxRuntime.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: {
|
|
1455
1492
|
...style,
|
|
1456
1493
|
display: 'grid',
|
|
1457
1494
|
gridTemplateColumns: gridTemplate,
|
|
1458
1495
|
minWidth: 'fit-content',
|
|
1459
|
-
}, children: columns.map((col) => {
|
|
1496
|
+
}, onClick: onRowClick ? () => onRowClick(item, index) : undefined, children: columns.map((col) => {
|
|
1460
1497
|
var _a;
|
|
1461
1498
|
const content = col.render ? col.render(item) : ((_a = get(item, col.name)) !== null && _a !== void 0 ? _a : 'Not set');
|
|
1462
|
-
return (jsxRuntime.jsx("div", { role: "cell", className: buildClassName('
|
|
1499
|
+
return (jsxRuntime.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' &&
|
|
1463
1500
|
'sticky left-0 z-10 bg-white dark:bg-gray-900 shadow-[2px_0_4px_rgba(0,0,0,0.05)]', col.sticky === 'right' &&
|
|
1464
|
-
'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));
|
|
1501
|
+
'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));
|
|
1465
1502
|
}) }));
|
|
1466
1503
|
};
|
|
1467
1504
|
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1505
|
+
const DENSITY_CELL_CLASS = {
|
|
1506
|
+
compact: 'px-2 py-1.5',
|
|
1507
|
+
default: 'px-3 py-3',
|
|
1508
|
+
spacious: 'px-4 py-4',
|
|
1509
|
+
};
|
|
1510
|
+
const columnWidth = (col) => {
|
|
1511
|
+
if (!col.width)
|
|
1512
|
+
return '1fr';
|
|
1513
|
+
if (typeof col.width === 'number')
|
|
1514
|
+
return `${col.width}px`;
|
|
1515
|
+
return col.width;
|
|
1516
|
+
};
|
|
1517
|
+
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, }) {
|
|
1473
1518
|
const scrollRef = React.useRef(null);
|
|
1474
1519
|
const outerRef = React.useRef(null);
|
|
1475
1520
|
const headerRef = React.useRef(null);
|
|
1476
|
-
const gridTemplate =
|
|
1477
|
-
|
|
1521
|
+
const gridTemplate = React.useMemo(() => columns.map((col) => columnWidth(col)).join(' '), [columns]);
|
|
1522
|
+
const densityCellClass = DENSITY_CELL_CLASS[density];
|
|
1523
|
+
const skeletonRows = Math.max(1, Math.floor(maxHeight / rowHeight));
|
|
1478
1524
|
React.useEffect(() => {
|
|
1479
1525
|
const el = outerRef.current;
|
|
1480
1526
|
if (!el)
|
|
@@ -1490,35 +1536,31 @@ const VirtualizedDataTable = ({ items, columns, sorting = {}, onSort, loading =
|
|
|
1490
1536
|
if (column.sortable)
|
|
1491
1537
|
onSort === null || onSort === void 0 ? void 0 : onSort(column);
|
|
1492
1538
|
}, [onSort]);
|
|
1539
|
+
const itemData = React.useMemo(() => ({ items, columns, gridTemplate, onRowClick, rowClass, density, striped }), [items, columns, gridTemplate, onRowClick, rowClass, density, striped]);
|
|
1493
1540
|
/* -------------------------------------------------------
|
|
1494
|
-
*
|
|
1541
|
+
* Header
|
|
1495
1542
|
* ------------------------------------------------------- */
|
|
1496
|
-
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: {
|
|
1497
|
-
gridTemplateColumns: gridTemplate,
|
|
1498
|
-
minWidth: 'fit-content',
|
|
1499
|
-
}, 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' &&
|
|
1543
|
+
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: { gridTemplateColumns: gridTemplate, minWidth: 'fit-content' }, children: columns.map((col) => (jsxRuntime.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' &&
|
|
1500
1544
|
'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' &&
|
|
1501
|
-
'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))) }) }));
|
|
1545
|
+
'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: 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))) }) }));
|
|
1546
|
+
const wrapperCls = buildClassName('rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden', wrapperClass);
|
|
1502
1547
|
/* -------------------------------------------------------
|
|
1503
|
-
*
|
|
1548
|
+
* Loading state
|
|
1504
1549
|
* ------------------------------------------------------- */
|
|
1505
1550
|
if (loading) {
|
|
1506
|
-
return (jsxRuntime.jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxRuntime.jsxs("div", { className:
|
|
1507
|
-
gridTemplateColumns: gridTemplate,
|
|
1508
|
-
height: rowHeight,
|
|
1509
|
-
}, 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))) })] }) }));
|
|
1551
|
+
return (jsxRuntime.jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxRuntime.jsxs("div", { className: wrapperCls, children: [Header, jsxRuntime.jsx("div", { style: { height: maxHeight }, className: "flex flex-col", children: Array.from({ length: skeletonRows }).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: { gridTemplateColumns: gridTemplate, height: rowHeight }, children: columns.map((col) => (jsxRuntime.jsx("div", { className: densityCellClass, children: jsxRuntime.jsx("div", { className: "h-4 w-3/4 bg-gray-300 dark:bg-gray-700 rounded" }) }, col.name))) }, idx))) })] }) }));
|
|
1510
1552
|
}
|
|
1511
1553
|
/* -------------------------------------------------------
|
|
1512
|
-
*
|
|
1554
|
+
* Empty state
|
|
1513
1555
|
* ------------------------------------------------------- */
|
|
1514
|
-
if (
|
|
1515
|
-
return (jsxRuntime.jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxRuntime.jsxs("div", { className:
|
|
1556
|
+
if (items.length === 0) {
|
|
1557
|
+
return (jsxRuntime.jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxRuntime.jsxs("div", { className: wrapperCls, children: [Header, jsxRuntime.jsx("div", { className: "flex items-center justify-center text-gray-500 dark:text-gray-300", style: { height: maxHeight }, children: emptyMessage })] }) }));
|
|
1516
1558
|
}
|
|
1517
1559
|
/* -------------------------------------------------------
|
|
1518
|
-
*
|
|
1560
|
+
* Virtualized body
|
|
1519
1561
|
* ------------------------------------------------------- */
|
|
1520
|
-
return (jsxRuntime.jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxRuntime.jsxs("div", { className:
|
|
1521
|
-
}
|
|
1562
|
+
return (jsxRuntime.jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxRuntime.jsxs("div", { className: wrapperCls, children: [Header, jsxRuntime.jsx(reactWindow.FixedSizeList, { ref: scrollRef, outerRef: outerRef, height: maxHeight, width: "100%", itemCount: items.length, itemSize: rowHeight, itemData: itemData, overscanCount: overscanCount, children: VirtualizedRow })] }) }));
|
|
1563
|
+
}
|
|
1522
1564
|
|
|
1523
1565
|
const useIsMobile = () => {
|
|
1524
1566
|
const [isMobile, setIsMobile] = React.useState(false);
|