@pk-design/react-tailwind 1.5.0 → 1.5.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 +136 -27
- package/dist/react-tailwind.cjs.js.map +1 -1
- package/dist/react-tailwind.es.js +137 -29
- package/dist/react-tailwind.es.js.map +1 -1
- package/dist/types/components/DataTable/DataTable.d.ts +1 -1
- package/dist/types/components/DataTable/DataTable.types.d.ts +16 -0
- package/dist/types/components/DataTable/DataTable.utils.d.ts +21 -0
- package/dist/types/components/VirtualizedDataTable/VirtualizedDataTable.d.ts +1 -1
- package/dist/types/components/VirtualizedDataTable/VirtualizedDataTable.types.d.ts +7 -2
- package/package.json +1 -1
|
@@ -790,6 +790,48 @@ const updateSortQuery = (sortQuery, name, type = 'string') => {
|
|
|
790
790
|
}
|
|
791
791
|
return updated;
|
|
792
792
|
};
|
|
793
|
+
/**
|
|
794
|
+
* Shared row-selection state/behaviour used by DataTable and VirtualizedDataTable.
|
|
795
|
+
* Supports controlled (`selectedRowKeys`) and uncontrolled (`defaultSelectedRowKeys`) usage.
|
|
796
|
+
*/
|
|
797
|
+
const useRowSelection = ({ items, getKey, selectedRowKeys, defaultSelectedRowKeys = [], onSelectionChange, isRowSelectable, }) => {
|
|
798
|
+
const [internalKeys, setInternalKeys] = React.useState(defaultSelectedRowKeys);
|
|
799
|
+
const isControlled = selectedRowKeys !== undefined;
|
|
800
|
+
const keys = isControlled ? selectedRowKeys : internalKeys;
|
|
801
|
+
const keySet = React.useMemo(() => new Set(keys), [keys]);
|
|
802
|
+
const selectableEntries = React.useMemo(() => items
|
|
803
|
+
.map((item, idx) => ({ item, key: getKey(item, idx) }))
|
|
804
|
+
.filter(({ item }) => !isRowSelectable || isRowSelectable(item)), [items, getKey, isRowSelectable]);
|
|
805
|
+
const emit = React.useCallback((nextKeys) => {
|
|
806
|
+
if (!isControlled)
|
|
807
|
+
setInternalKeys(nextKeys);
|
|
808
|
+
const nextKeySet = new Set(nextKeys);
|
|
809
|
+
const nextItems = items.filter((item, idx) => nextKeySet.has(getKey(item, idx)));
|
|
810
|
+
onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange(nextKeys, nextItems);
|
|
811
|
+
}, [isControlled, items, getKey, onSelectionChange]);
|
|
812
|
+
const toggleRow = React.useCallback((key) => {
|
|
813
|
+
emit(keySet.has(key) ? keys.filter((k) => k !== key) : [...keys, key]);
|
|
814
|
+
}, [keys, keySet, emit]);
|
|
815
|
+
const allSelected = selectableEntries.length > 0 && selectableEntries.every(({ key }) => keySet.has(key));
|
|
816
|
+
const someSelected = !allSelected && selectableEntries.some(({ key }) => keySet.has(key));
|
|
817
|
+
const toggleAll = React.useCallback(() => {
|
|
818
|
+
const selectableKeySet = new Set(selectableEntries.map(({ key }) => key));
|
|
819
|
+
if (allSelected) {
|
|
820
|
+
emit(keys.filter((k) => !selectableKeySet.has(k)));
|
|
821
|
+
}
|
|
822
|
+
else {
|
|
823
|
+
emit(Array.from(new Set([...keys, ...selectableKeySet])));
|
|
824
|
+
}
|
|
825
|
+
}, [allSelected, selectableEntries, keys, emit]);
|
|
826
|
+
return {
|
|
827
|
+
selectedKeys: keys,
|
|
828
|
+
isSelected: (key) => keySet.has(key),
|
|
829
|
+
toggleRow,
|
|
830
|
+
toggleAll,
|
|
831
|
+
allSelected,
|
|
832
|
+
someSelected,
|
|
833
|
+
};
|
|
834
|
+
};
|
|
793
835
|
|
|
794
836
|
var _path$7;
|
|
795
837
|
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); }
|
|
@@ -923,7 +965,7 @@ const autoSortItems = (items, column, sort) => {
|
|
|
923
965
|
return 0;
|
|
924
966
|
});
|
|
925
967
|
};
|
|
926
|
-
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', }) {
|
|
968
|
+
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', selectable = false, selectedRowKeys, defaultSelectedRowKeys, onSelectionChange, isRowSelectable, }) {
|
|
927
969
|
const internalSorting = React.useRef({});
|
|
928
970
|
const [sortedItems, setSortedItems] = React.useState(items);
|
|
929
971
|
React.useEffect(() => {
|
|
@@ -958,17 +1000,33 @@ function DataTable({ items, columns, sorting = {}, onSort, loading, pagination,
|
|
|
958
1000
|
return column.cellClass(item);
|
|
959
1001
|
return column.cellClass;
|
|
960
1002
|
};
|
|
1003
|
+
const { isSelected, toggleRow, toggleAll, allSelected, someSelected } = useRowSelection({
|
|
1004
|
+
items: sortedItems,
|
|
1005
|
+
getKey,
|
|
1006
|
+
selectedRowKeys,
|
|
1007
|
+
defaultSelectedRowKeys,
|
|
1008
|
+
onSelectionChange,
|
|
1009
|
+
isRowSelectable,
|
|
1010
|
+
});
|
|
961
1011
|
const densityCellClass = DENSITY_CELL_CLASS$2[density];
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1012
|
+
const colSize = columns.length + (selectable ? 1 : 0);
|
|
1013
|
+
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.jsxs(TableHead, { className: headClass, children: [selectable && (jsxRuntime.jsx(TableHeaderCell, { className: buildClassName('bg-gray-50 dark:bg-gray-800 w-px', densityCellClass), children: jsxRuntime.jsx(Checkbox, { "aria-label": "Select all rows", checked: allSelected, ref: (el) => {
|
|
1014
|
+
if (el)
|
|
1015
|
+
el.indeterminate = someSelected;
|
|
1016
|
+
}, onChange: toggleAll }) })), 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' &&
|
|
1017
|
+
'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
|
|
1018
|
+
'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: colSize, rowSize: (pagination === null || pagination === void 0 ? void 0 : pagination.limit) || 5, children: !loading && sortedItems.length === 0 ? (jsxRuntime.jsx(EmptyTableRow, { colSpan: colSize, children: emptyMessage })) : (sortedItems.map((item, idx) => {
|
|
1019
|
+
const key = getKey(item, idx);
|
|
1020
|
+
const rowSelectable = !isRowSelectable || isRowSelectable(item);
|
|
1021
|
+
return (jsxRuntime.jsxs(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: [selectable && (jsxRuntime.jsx(TableCell, { className: buildClassName(densityCellClass, striped && idx % 2 === 1 && 'bg-gray-50 dark:bg-gray-800/40'), children: jsxRuntime.jsx("span", { onClick: (e) => e.stopPropagation(), children: jsxRuntime.jsx(Checkbox, { "aria-label": "Select row", checked: isSelected(key), disabled: !rowSelectable, onChange: () => toggleRow(key) }) }) })), columns.map((column) => {
|
|
1022
|
+
var _a;
|
|
1023
|
+
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' &&
|
|
1024
|
+
'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
|
|
1025
|
+
'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]', getCellClass(column, item)), children: column.render
|
|
1026
|
+
? column.render(item)
|
|
1027
|
+
: ((_a = get(item, column.name)) !== null && _a !== void 0 ? _a : 'Not set') }, column.name));
|
|
1028
|
+
})] }, key));
|
|
1029
|
+
})) }), 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 }))] }));
|
|
972
1030
|
}
|
|
973
1031
|
DataTable.displayName = 'DataTable';
|
|
974
1032
|
|
|
@@ -1635,9 +1693,12 @@ const DENSITY_CELL_CLASS$1 = {
|
|
|
1635
1693
|
spacious: 'px-4 py-4',
|
|
1636
1694
|
};
|
|
1637
1695
|
const VirtualizedRow = ({ index, style, data, }) => {
|
|
1638
|
-
|
|
1696
|
+
var _a, _b;
|
|
1697
|
+
const { items, columns, gridTemplate, onRowClick, rowClass, density = 'default', striped, selectable, getKey, isSelected, toggleRow, isRowSelectable, } = data;
|
|
1639
1698
|
const item = items[index];
|
|
1640
1699
|
const isStriped = striped && index % 2 === 1;
|
|
1700
|
+
const key = (_a = getKey === null || getKey === void 0 ? void 0 : getKey(item, index)) !== null && _a !== void 0 ? _a : index;
|
|
1701
|
+
const rowSelectable = !isRowSelectable || isRowSelectable(item);
|
|
1641
1702
|
const resolvedRowClass = !rowClass
|
|
1642
1703
|
? ''
|
|
1643
1704
|
: typeof rowClass === 'function'
|
|
@@ -1651,20 +1712,21 @@ const VirtualizedRow = ({ index, style, data, }) => {
|
|
|
1651
1712
|
return col.cellClass;
|
|
1652
1713
|
};
|
|
1653
1714
|
const densityCellClass = DENSITY_CELL_CLASS$1[density];
|
|
1654
|
-
return (jsxRuntime.
|
|
1715
|
+
return (jsxRuntime.jsxs("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: {
|
|
1655
1716
|
...style,
|
|
1656
1717
|
display: 'grid',
|
|
1657
1718
|
gridTemplateColumns: gridTemplate,
|
|
1658
1719
|
minWidth: 'fit-content',
|
|
1659
|
-
}, onClick: onRowClick ? () => onRowClick(item, index) : undefined, children: columns.map((col) => {
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1720
|
+
}, onClick: onRowClick ? () => onRowClick(item, index) : undefined, children: [selectable && (jsxRuntime.jsx("div", { role: "cell", className: buildClassName('flex items-center whitespace-nowrap border-r last:border-r-0 border-gray-200 dark:border-gray-700', densityCellClass, isStriped && 'bg-gray-50 dark:bg-gray-800/40'), onClick: (e) => e.stopPropagation(), children: jsxRuntime.jsx(Checkbox, { "aria-label": "Select row", checked: (_b = isSelected === null || isSelected === void 0 ? void 0 : isSelected(key)) !== null && _b !== void 0 ? _b : false, disabled: !rowSelectable, onChange: () => toggleRow === null || toggleRow === void 0 ? void 0 : toggleRow(key) }) })), columns.map((col) => {
|
|
1721
|
+
var _a;
|
|
1722
|
+
const content = col.render ? col.render(item) : ((_a = get(item, col.name)) !== null && _a !== void 0 ? _a : 'Not set');
|
|
1723
|
+
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' &&
|
|
1724
|
+
'sticky left-0 z-10 bg-white dark:bg-gray-900 shadow-[2px_0_4px_rgba(0,0,0,0.05)]', col.sticky === 'right' &&
|
|
1725
|
+
'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));
|
|
1726
|
+
})] }));
|
|
1666
1727
|
};
|
|
1667
1728
|
|
|
1729
|
+
const SELECTION_COLUMN_WIDTH = '44px';
|
|
1668
1730
|
const DENSITY_CELL_CLASS = {
|
|
1669
1731
|
compact: 'px-2 py-1.5',
|
|
1670
1732
|
default: 'px-3 py-3',
|
|
@@ -1677,11 +1739,28 @@ const columnWidth = (col) => {
|
|
|
1677
1739
|
return `${col.width}px`;
|
|
1678
1740
|
return col.width;
|
|
1679
1741
|
};
|
|
1680
|
-
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, }) {
|
|
1742
|
+
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, rowKey = 'id', selectable = false, selectedRowKeys, defaultSelectedRowKeys, onSelectionChange, isRowSelectable, }) {
|
|
1681
1743
|
const scrollRef = React.useRef(null);
|
|
1682
1744
|
const outerRef = React.useRef(null);
|
|
1683
1745
|
const headerRef = React.useRef(null);
|
|
1684
|
-
const
|
|
1746
|
+
const getKey = React.useCallback((item, idx) => {
|
|
1747
|
+
var _a;
|
|
1748
|
+
if (typeof rowKey === 'function')
|
|
1749
|
+
return rowKey(item);
|
|
1750
|
+
return (_a = item[rowKey]) !== null && _a !== void 0 ? _a : idx;
|
|
1751
|
+
}, [rowKey]);
|
|
1752
|
+
const { isSelected, toggleRow, toggleAll, allSelected, someSelected } = useRowSelection({
|
|
1753
|
+
items,
|
|
1754
|
+
getKey,
|
|
1755
|
+
selectedRowKeys,
|
|
1756
|
+
defaultSelectedRowKeys,
|
|
1757
|
+
onSelectionChange,
|
|
1758
|
+
isRowSelectable,
|
|
1759
|
+
});
|
|
1760
|
+
const gridTemplate = React.useMemo(() => {
|
|
1761
|
+
const widths = columns.map((col) => columnWidth(col));
|
|
1762
|
+
return selectable ? [SELECTION_COLUMN_WIDTH, ...widths].join(' ') : widths.join(' ');
|
|
1763
|
+
}, [columns, selectable]);
|
|
1685
1764
|
const densityCellClass = DENSITY_CELL_CLASS[density];
|
|
1686
1765
|
const skeletonRows = Math.max(1, Math.floor(maxHeight / rowHeight));
|
|
1687
1766
|
React.useEffect(() => {
|
|
@@ -1699,19 +1778,48 @@ function VirtualizedDataTable({ items, columns, sorting = {}, onSort, loading =
|
|
|
1699
1778
|
if (column.sortable)
|
|
1700
1779
|
onSort === null || onSort === void 0 ? void 0 : onSort(column);
|
|
1701
1780
|
}, [onSort]);
|
|
1702
|
-
const itemData = React.useMemo(() => ({
|
|
1781
|
+
const itemData = React.useMemo(() => ({
|
|
1782
|
+
items,
|
|
1783
|
+
columns,
|
|
1784
|
+
gridTemplate,
|
|
1785
|
+
onRowClick,
|
|
1786
|
+
rowClass,
|
|
1787
|
+
density,
|
|
1788
|
+
striped,
|
|
1789
|
+
selectable,
|
|
1790
|
+
getKey,
|
|
1791
|
+
isSelected,
|
|
1792
|
+
toggleRow,
|
|
1793
|
+
isRowSelectable,
|
|
1794
|
+
}), [
|
|
1795
|
+
items,
|
|
1796
|
+
columns,
|
|
1797
|
+
gridTemplate,
|
|
1798
|
+
onRowClick,
|
|
1799
|
+
rowClass,
|
|
1800
|
+
density,
|
|
1801
|
+
striped,
|
|
1802
|
+
selectable,
|
|
1803
|
+
getKey,
|
|
1804
|
+
isSelected,
|
|
1805
|
+
toggleRow,
|
|
1806
|
+
isRowSelectable,
|
|
1807
|
+
]);
|
|
1703
1808
|
/* -------------------------------------------------------
|
|
1704
1809
|
* Header
|
|
1705
1810
|
* ------------------------------------------------------- */
|
|
1706
|
-
const Header = (jsxRuntime.jsx("div", { ref: headerRef, className: "overflow-hidden w-full", children: jsxRuntime.
|
|
1707
|
-
|
|
1708
|
-
|
|
1811
|
+
const Header = (jsxRuntime.jsx("div", { ref: headerRef, className: "overflow-hidden w-full", children: jsxRuntime.jsxs("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: [selectable && (jsxRuntime.jsx("div", { role: "columnheader", className: buildClassName('flex items-center border-r last:border-r-0 border-gray-200 dark:border-gray-700', densityCellClass), children: jsxRuntime.jsx(Checkbox, { "aria-label": "Select all rows", checked: allSelected, ref: (el) => {
|
|
1812
|
+
if (el)
|
|
1813
|
+
el.indeterminate = someSelected;
|
|
1814
|
+
}, onChange: toggleAll }) })), 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' &&
|
|
1815
|
+
'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' &&
|
|
1816
|
+
'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)))] }) }));
|
|
1709
1817
|
const wrapperCls = buildClassName('rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden', wrapperClass);
|
|
1710
1818
|
/* -------------------------------------------------------
|
|
1711
1819
|
* Loading state
|
|
1712
1820
|
* ------------------------------------------------------- */
|
|
1713
1821
|
if (loading) {
|
|
1714
|
-
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.
|
|
1822
|
+
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.jsxs("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: [selectable && jsxRuntime.jsx("div", { className: densityCellClass }), 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))) })] }) }));
|
|
1715
1823
|
}
|
|
1716
1824
|
/* -------------------------------------------------------
|
|
1717
1825
|
* Empty state
|
|
@@ -1822,5 +1930,6 @@ exports.useIsMobile = useIsMobile;
|
|
|
1822
1930
|
exports.useIsTablet = useIsTablet;
|
|
1823
1931
|
exports.useIsTabletOrMobile = useIsTabletOrMobile;
|
|
1824
1932
|
exports.usePagination = usePagination;
|
|
1933
|
+
exports.useRowSelection = useRowSelection;
|
|
1825
1934
|
exports.useToast = useToast;
|
|
1826
1935
|
//# sourceMappingURL=react-tailwind.cjs.js.map
|