@pk-design/react-tailwind 1.5.0 → 1.5.2

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.
@@ -550,7 +550,7 @@ const Card = React.forwardRef(({ as, ...props }, ref) => {
550
550
  const Component = as || 'div';
551
551
  // Extract className safely from rest
552
552
  const { className, ...cleanRest } = rest;
553
- const classes = buildClassName(BASE_CARD_CLASS, zeroPadding ? '' : compact ? 'p-2' : 'p-6', hoverable && 'transition-background duration-200 hover:bg-gray-100 dark:hover:bg-gray-800', bordered && 'border border-gray-200 dark:border-gray-800', className);
553
+ const classes = buildClassName(BASE_CARD_CLASS, zeroPadding ? '' : compact ? 'p-2' : 'p-6', hoverable && 'transition-background duration-200 hover:bg-gray-100 dark:hover:bg-gray-800', bordered && 'border border-[var(--ui-border)]', className);
554
554
  return jsxRuntime.jsx(Component, { ref: ref, className: classes, ...cleanRest });
555
555
  });
556
556
  Card.displayName = 'Card';
@@ -623,7 +623,7 @@ const TableRowLoader = ({ colSize, rowSize }) => (jsxRuntime.jsx(jsxRuntime.Frag
623
623
  /* ----------------------------------------------
624
624
  * Table
625
625
  * ---------------------------------------------- */
626
- 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] }));
626
+ const Table = ({ children, layout = 'auto', className = '', caption, }) => (jsxRuntime.jsxs("table", { className: buildClassName('border-collapse w-full divide-y divide-[var(--ui-border)]', 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] }));
627
627
  /* ----------------------------------------------
628
628
  * Head
629
629
  * ---------------------------------------------- */
@@ -631,7 +631,7 @@ const TableHead = ({ children, className = '' }) => (jsxRuntime.jsx("thead", { c
631
631
  /* ----------------------------------------------
632
632
  * Body
633
633
  * ---------------------------------------------- */
634
- 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 }));
634
+ 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-[var(--ui-border)]', className), children: loading ? jsxRuntime.jsx(TableRowLoader, { colSize: colSize, rowSize: rowSize }) : children }));
635
635
  /* ----------------------------------------------
636
636
  * Foot
637
637
  * ---------------------------------------------- */
@@ -639,7 +639,7 @@ const TableFoot = ({ children }) => (jsxRuntime.jsx("tfoot", { children: jsxRunt
639
639
  /* ----------------------------------------------
640
640
  * Rows
641
641
  * ---------------------------------------------- */
642
- 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 }));
642
+ const TableRow = ({ children, hoverable = false, className, ...props }) => (jsxRuntime.jsx("tr", { ...props, className: buildClassName('last:border-b border-[var(--ui-border)]', hoverable && 'group', className), children: children }));
643
643
  /* ----------------------------------------------
644
644
  * Cells
645
645
  * ---------------------------------------------- */
@@ -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
- 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' &&
963
- 'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
964
- '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) => {
965
- var _a;
966
- 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' &&
967
- 'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
968
- 'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]', getCellClass(column, item)), children: column.render
969
- ? column.render(item)
970
- : ((_a = get(item, column.name)) !== null && _a !== void 0 ? _a : 'Not set') }, column.name));
971
- }) }, 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 }))] }));
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-[var(--ui-border)]', 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-[var(--ui-border)]", onChange: setPagination }))] }));
972
1030
  }
973
1031
  DataTable.displayName = 'DataTable';
974
1032
 
@@ -986,10 +1044,10 @@ const HeadingText = {
986
1044
  };
987
1045
 
988
1046
  const DetailedInformation = React.forwardRef((props, ref) => {
989
- const { className, title, subTitle, details, compact = false, divider = true, titleClass, detailsClass, ...divProps } = props;
1047
+ const { className, title, subTitle, details, compact = false, divider = true, titleClass, detailsClass, bordered = false, ...divProps } = props;
990
1048
  const hasTitles = title || subTitle;
991
1049
  const filteredDetails = details.filter((detail) => !detail.hidden);
992
- 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] }));
1050
+ return (jsxRuntime.jsxs("div", { className: buildClassName('p-2 md:p-4', compact ? 'md:p-2' : '', bordered ? 'border border-[var(--ui-border)]' : '', 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-[var(--ui-border-muted)]', hasTitles && 'border-t', detailsClass), children: jsxRuntime.jsx("dl", { className: buildClassName(divider && 'divide-y divide-[var(--ui-border-muted)]'), 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] }));
993
1051
  });
994
1052
  DetailedInformation.displayName = 'DetailedInformation';
995
1053
 
@@ -1029,7 +1087,7 @@ Drawer.displayName = 'Drawer';
1029
1087
 
1030
1088
  const BASE_ITEM_CLASS = 'flex w-full px-3 py-2 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700 rounded-lg';
1031
1089
  const Dropdown = ({ triggerButton, renderTriggerButton, items, renderItem, itemsContainerClass, transition = true, anchor = 'bottom start', menuItemClass, onMenuClick, }) => {
1032
- 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))) })] }));
1090
+ 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-[var(--ui-border-muted)] bg-white text-gray-800', '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))) })] }));
1033
1091
  };
1034
1092
  Dropdown.displayName = 'Dropdown';
1035
1093
 
@@ -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
- const { items, columns, gridTemplate, onRowClick, rowClass, density = 'default', striped } = data;
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.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: {
1715
+ return (jsxRuntime.jsxs("div", { role: "row", className: buildClassName('grid border-b border-[var(--ui-border)] 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
- var _a;
1661
- const content = col.render ? col.render(item) : ((_a = get(item, col.name)) !== null && _a !== void 0 ? _a : 'Not set');
1662
- 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' &&
1663
- 'sticky left-0 z-10 bg-white dark:bg-gray-900 shadow-[2px_0_4px_rgba(0,0,0,0.05)]', col.sticky === 'right' &&
1664
- '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));
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-[var(--ui-border)]', 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-[var(--ui-border)]', 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 gridTemplate = React.useMemo(() => columns.map((col) => columnWidth(col)).join(' '), [columns]);
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(() => ({ items, columns, gridTemplate, onRowClick, rowClass, density, striped }), [items, columns, gridTemplate, onRowClick, rowClass, density, striped]);
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.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' &&
1707
- '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' &&
1708
- '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
- const wrapperCls = buildClassName('rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden', wrapperClass);
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-[var(--ui-border)]", 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-[var(--ui-border)]', 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-[var(--ui-border)]', 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)))] }) }));
1817
+ const wrapperCls = buildClassName('rounded-lg border border-[var(--ui-border)] 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.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))) })] }) }));
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-[var(--ui-border-muted)]", 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