@pk-design/react-tailwind 1.1.5 → 1.1.7

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.
@@ -4,6 +4,7 @@ var jsxRuntime = require('react/jsx-runtime');
4
4
  var tailwindMerge = require('tailwind-merge');
5
5
  var React = require('react');
6
6
  var react = require('@headlessui/react');
7
+ var reactWindow = require('react-window');
7
8
 
8
9
  function _interopNamespaceDefault(e) {
9
10
  var n = Object.create(null);
@@ -243,7 +244,7 @@ const TypeClassMap = {
243
244
  const Alert = (props) => {
244
245
  const { type = 'info', className = '', message, children, removable = false, onRemove = () => { }, ...restProps } = props;
245
246
  const Icon = AlertTypeIconMap[type] || SvgInfo;
246
- return (jsxRuntime.jsxs("div", { className: buildClassName(className, 'flex items-center justify-between rounded-md p-3 text-sm ring-1 ring-inset gap-2', TypeClassMap[type]), ...restProps, children: [jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [jsxRuntime.jsx(Icon, { className: "size-5", "data-testid": `alert-${type}-icon` }), jsxRuntime.jsx("span", { className: "pr-2 inline-flex items-center", children: message || children })] }), removable && (jsxRuntime.jsx(Button, { iconOnly: true, size: "xs", variant: "plain", theme: "secondary", className: "hover:bg-black/5 text-gray-600 dark:hover:bg-black/5 dark:text-gray-600", onClick: () => onRemove(), "data-testid": "alert-remove-btn", children: jsxRuntime.jsx(SvgX, { className: "size-4.5", "data-testid": "alert-remove-icon" }) }))] }));
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/5 text-gray-600 dark:hover:bg-black/5 dark:text-gray-600", onClick: () => onRemove(), "data-testid": "alert-remove-btn", children: jsxRuntime.jsx(SvgX, { className: "size-4.5", "data-testid": "alert-remove-icon" }) }))] }));
247
248
  };
248
249
  Alert.displayName = 'Alert';
249
250
 
@@ -256,7 +257,12 @@ const ThemeClassMap = {
256
257
  };
257
258
  const Badge = React.forwardRef((props, ref) => {
258
259
  const { theme = 'info', className = '', children, removable = false, rounded = false, onRemove = () => { }, ...restProps } = props;
259
- return (jsxRuntime.jsxs(TextContent, { ref: ref, className: buildClassName(className, 'inline-flex items-center pl-3 py-1 text-xs font-medium ring-1 ring-inset', ThemeClassMap[theme], rounded ? 'rounded-full' : 'rounded-md'), "data-testid": `badge-${theme}`, ...restProps, children: [jsxRuntime.jsx(TextContent, { className: "pr-3 inline-flex items-center", children: children }), removable ? (jsxRuntime.jsx(SvgX, { className: "size-5 px-0.5 mr-1 hover:bg-slate-200 dark:hover:bg-white/10 rounded-sm cursor-pointer text-gray-600 dark:text-gray-300", role: "button", onClick: () => onRemove() })) : null] }));
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-slate-200 dark:hover:bg-white/10 rounded-sm cursor-pointer text-gray-600 dark:text-gray-300", role: "button", tabIndex: 0, "aria-label": "Remove", onClick: () => onRemove(), onKeyDown: (e) => {
261
+ if (e.key === 'Enter' || e.key === ' ') {
262
+ e.preventDefault();
263
+ onRemove();
264
+ }
265
+ } })) : null] }));
260
266
  });
261
267
  Badge.displayName = 'Badge';
262
268
 
@@ -360,7 +366,7 @@ var SvgSlash = function SvgSlash(props) {
360
366
  const Breadcrumb = ({ items, render }) => {
361
367
  const count = items.length;
362
368
  const isLast = (index) => index === count - 1;
363
- return (jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2", "data-testid": "breadcrumb-container", children: items.map((item, index) => (jsxRuntime.jsxs("span", { className: "inline-flex gap-2 items-center dark:text-white", "data-testid": `breadcrumb-item-${item.key}`, children: [jsxRuntime.jsx("span", { className: "font-medium", children: isLast(index) ? item.text : render(item) }), !isLast(index) && (jsxRuntime.jsx(SvgSlash, { "data-testid": `breadcrumb-divider-${index}`, className: "size-4" }))] }, item.key))) }));
369
+ return (jsxRuntime.jsx("nav", { "aria-label": "Breadcrumb", className: "flex flex-wrap items-center gap-2", "data-testid": "breadcrumb-container", children: items.map((item, index) => (jsxRuntime.jsxs("span", { className: "inline-flex gap-2 items-center dark:text-white", "data-testid": `breadcrumb-item-${item.key}`, children: [jsxRuntime.jsx("span", { className: "font-medium", ...(isLast(index) ? { 'aria-current': 'page' } : {}), children: isLast(index) ? item.text : render(item) }), !isLast(index) && (jsxRuntime.jsx(SvgSlash, { "data-testid": `breadcrumb-divider-${index}`, className: "size-4" }))] }, item.key))) }));
364
370
  };
365
371
  Breadcrumb.displayName = 'Breadcrumb';
366
372
 
@@ -387,7 +393,8 @@ const Checkbox = React.forwardRef((props, ref) => {
387
393
  const { id, name, label, labelClass = '', wrapperClass = '', containerClass = '', error, disabled = false, className = '',
388
394
  // Checkbox-only props removed from rest
389
395
  ...rest } = props;
390
- const checkboxId = (_a = id !== null && id !== void 0 ? id : name) !== null && _a !== void 0 ? _a : 'checkbox-' + Math.random();
396
+ const generatedId = React.useId();
397
+ const checkboxId = (_a = id !== null && id !== void 0 ? id : name) !== null && _a !== void 0 ? _a : generatedId;
391
398
  return (jsxRuntime.jsxs("div", { className: buildClassName(wrapperClass), children: [jsxRuntime.jsxs("div", { className: buildClassName('flex items-center', containerClass), children: [jsxRuntime.jsxs("label", { htmlFor: checkboxId, className: buildClassName('inline-flex items-center relative select-none', disabled ? 'cursor-not-allowed opacity-70' : 'cursor-pointer'), children: [jsxRuntime.jsx("input", { ref: ref, ...rest, id: checkboxId, name: name, type: "checkbox", disabled: disabled, "aria-checked": rest.checked, className: buildClassName('peer size-4.5 cursor-pointer transition-all appearance-none rounded', 'border focus:ring-2 focus:ring-offset-2', 'checked:bg-blue-600 checked:border-blue-600', 'focus:ring-blue-500 dark:focus:ring-offset-gray-900', disabled
392
399
  ? 'border-gray-200 dark:border-gray-700 bg-gray-100 dark:bg-gray-800 pointer-events-none'
393
400
  : 'bg-white dark:bg-gray-700 border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500 hover:shadow-md', className) }), jsxRuntime.jsx("span", { className: "absolute text-white opacity-0 peer-checked:opacity-100 \n top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2", children: jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-3.25 w-3.25", viewBox: "0 0 20 20", fill: "currentColor", stroke: "currentColor", strokeWidth: "1", children: jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) })] }), label && (jsxRuntime.jsx(Label, { htmlFor: checkboxId, className: buildClassName(disabled
@@ -398,15 +405,8 @@ Checkbox.displayName = 'Checkbox';
398
405
 
399
406
  const CheckboxGroup = (props) => {
400
407
  const { name, options, label, labelClass = '', labelWrapperClass = '', labelHint, containerClass = '', value = [], onChange, inline = false, } = props;
401
- const [items, setItems] = React.useState([]);
402
- const groupId = React.useId(); // unique per group
403
- /**
404
- * Normalize options (strings → {label, value})
405
- */
406
- React.useEffect(() => {
407
- const normalized = options.map((opt) => typeof opt === 'string' ? { label: opt, value: opt } : opt);
408
- setItems(normalized);
409
- }, [options]);
408
+ const groupId = React.useId();
409
+ const items = React.useMemo(() => options.map((opt) => typeof opt === 'string' ? { label: opt, value: opt } : opt), [options]);
410
410
  /**
411
411
  * Group-level change handler. Converts raw checkbox change events
412
412
  * into a typed updated values array.
@@ -557,14 +557,14 @@ const Pagination = ({ page: currentPage, limit, total, onChange, className, elli
557
557
  onChange({ page: nextVal });
558
558
  };
559
559
  if (ellipsis) {
560
- return (jsxRuntime.jsxs("div", { "data-testid": "pagination-container", className: buildClassName('flex items-center justify-between bg-white dark:bg-gray-800 px-4 py-3 sm:px-6', className), children: [jsxRuntime.jsxs("div", { className: "flex flex-1 justify-between sm:hidden", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "ellipsis-mobile-prev-btn", children: [jsxRuntime.jsx("span", { children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "ellipsis-mobile-next-btn", children: [jsxRuntime.jsx("span", { children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] }), jsxRuntime.jsxs("div", { className: "hidden sm:flex sm:flex-1 sm:items-center sm:justify-between", children: [jsxRuntime.jsxs("p", { "data-testid": "pagination-summary", className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1", children: ["Showing", jsxRuntime.jsx("span", { className: "font-medium", children: total === 0 ? 0 : Math.max(currentPage * limit - limit + 1, 1) }), "to", jsxRuntime.jsx("span", { className: "font-medium", children: Math.min(currentPage * limit, total) }), "of", jsxRuntime.jsx("span", { className: "font-medium", children: total }), "results"] }), jsxRuntime.jsxs("ul", { className: "flex items-center space-x-2 text-sm", children: [jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "ellipsis-next-btn", children: "Prev" }) }), range.map((page, idx) => {
560
+ return (jsxRuntime.jsxs("div", { "data-testid": "pagination-container", className: buildClassName('flex items-center justify-between bg-white dark:bg-gray-800 px-4 py-3 sm:px-6', className), children: [jsxRuntime.jsxs("div", { className: "flex flex-1 justify-between sm:hidden", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "ellipsis-mobile-prev-btn", children: [jsxRuntime.jsx("span", { children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "ellipsis-mobile-next-btn", children: [jsxRuntime.jsx("span", { children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] }), jsxRuntime.jsxs("div", { className: "hidden sm:flex sm:flex-1 sm:items-center sm:justify-between", children: [jsxRuntime.jsxs("p", { "data-testid": "pagination-summary", className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1", children: ["Showing", jsxRuntime.jsx("span", { className: "font-medium", children: total === 0 ? 0 : Math.max(currentPage * limit - limit + 1, 1) }), "to", jsxRuntime.jsx("span", { className: "font-medium", children: Math.min(currentPage * limit, total) }), "of", jsxRuntime.jsx("span", { className: "font-medium", children: total }), "results"] }), jsxRuntime.jsxs("ul", { className: "flex items-center space-x-2 text-sm", children: [jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "ellipsis-prev-btn", children: "Prev" }) }), range.map((page, idx) => {
561
561
  if (page === DOTS) {
562
562
  return (jsxRuntime.jsx("li", { "data-testid": `page-${page}`, className: "px-2 py-1 text-gray-400", children: "\u2026" }, `${page}-${idx}`));
563
563
  }
564
564
  return (jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: page === currentPage ? 'primary' : 'secondary', variant: page === currentPage ? 'default' : 'plain', "aria-current": page === currentPage ? 'page' : undefined, onClick: () => handlePageChange(page), children: page }) }, `${page}-${idx}`));
565
- }), jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "ellipsis-prev-btn", children: "Next" }) })] })] })] }));
565
+ }), jsxRuntime.jsx("li", { children: jsxRuntime.jsx(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "ellipsis-next-btn", children: "Next" }) })] })] })] }));
566
566
  }
567
- return (jsxRuntime.jsxs("div", { "data-testid": "pagination-container", className: buildClassName('flex items-center justify-between bg-white dark:bg-gray-800 px-4 py-3 sm:px-6', className), children: [jsxRuntime.jsxs("div", { className: "flex flex-1 justify-between sm:hidden", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "mobile-prev-btn", children: [jsxRuntime.jsx("span", { children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "mobile-next-btn", children: [jsxRuntime.jsx("span", { children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] }), jsxRuntime.jsxs("div", { className: "hidden sm:flex sm:flex-1 sm:items-center sm:justify-between", children: [jsxRuntime.jsxs("p", { "data-testid": "pagination-summary", className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1", children: ["Showing", jsxRuntime.jsx("span", { className: "font-medium", children: total === 0 ? 0 : Math.max(currentPage * limit - limit + 1, 1) }), "to", jsxRuntime.jsx("span", { className: "font-medium", children: Math.min(currentPage * limit, total) }), "of", jsxRuntime.jsx("span", { className: "font-medium", children: total }), "results"] }), jsxRuntime.jsxs("nav", { className: "isolate inline-flex items-center rounded-md", "aria-label": "Pagination", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "next-btn", children: [jsxRuntime.jsx("span", { className: "sr-only", children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), pages.map((page) => (jsxRuntime.jsx(Button, { size: "xs", theme: page === currentPage ? 'primary' : 'secondary', variant: page === currentPage ? 'default' : 'plain', "aria-current": page === currentPage ? 'page' : undefined, onClick: () => handlePageChange(page), children: jsxRuntime.jsx("span", { className: "size-4 block", children: page }) }, page))), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "prev-btn", children: [jsxRuntime.jsx("span", { className: "sr-only", children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] })] })] }));
567
+ return (jsxRuntime.jsxs("div", { "data-testid": "pagination-container", className: buildClassName('flex items-center justify-between bg-white dark:bg-gray-800 px-4 py-3 sm:px-6', className), children: [jsxRuntime.jsxs("div", { className: "flex flex-1 justify-between sm:hidden", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "mobile-prev-btn", children: [jsxRuntime.jsx("span", { children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "mobile-next-btn", children: [jsxRuntime.jsx("span", { children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] }), jsxRuntime.jsxs("div", { className: "hidden sm:flex sm:flex-1 sm:items-center sm:justify-between", children: [jsxRuntime.jsxs("p", { "data-testid": "pagination-summary", className: "text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1", children: ["Showing", jsxRuntime.jsx("span", { className: "font-medium", children: total === 0 ? 0 : Math.max(currentPage * limit - limit + 1, 1) }), "to", jsxRuntime.jsx("span", { className: "font-medium", children: Math.min(currentPage * limit, total) }), "of", jsxRuntime.jsx("span", { className: "font-medium", children: total }), "results"] }), jsxRuntime.jsxs("nav", { className: "isolate inline-flex items-center rounded-md", "aria-label": "Pagination", children: [jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isFirstPage, onClick: () => handlePageChange(currentPage - 1), "data-testid": "prev-btn", children: [jsxRuntime.jsx("span", { className: "sr-only", children: "Previous" }), jsxRuntime.jsx(SvgChevronLeft, { className: "size-4" })] }), pages.map((page) => (jsxRuntime.jsx(Button, { size: "xs", theme: page === currentPage ? 'primary' : 'secondary', variant: page === currentPage ? 'default' : 'plain', "aria-current": page === currentPage ? 'page' : undefined, onClick: () => handlePageChange(page), children: jsxRuntime.jsx("span", { className: "size-4 block", children: page }) }, page))), jsxRuntime.jsxs(Button, { size: "xs", theme: "secondary", variant: "plain", disabled: isLastPage, onClick: () => handlePageChange(currentPage + 1), "data-testid": "next-btn", children: [jsxRuntime.jsx("span", { className: "sr-only", children: "Next" }), jsxRuntime.jsx(SvgChevronRight, { className: "size-4" })] })] })] })] }));
568
568
  };
569
569
 
570
570
  function get(obj, path, defaultValue) {
@@ -753,9 +753,13 @@ const autoSortItems = (items, column, sort) => {
753
753
  };
754
754
  const DataTable = ({ items, columns, sorting = {}, onSort, loading, pagination = null, setPagination = () => { }, emptyMessage = 'No data found', containerClass = '', wrapperClass = '', layout = 'auto', }) => {
755
755
  const internalSorting = React.useRef({});
756
+ const [sortedItems, setSortedItems] = React.useState(items);
757
+ React.useEffect(() => {
758
+ setSortedItems(items);
759
+ }, [items]);
756
760
  const doAutoSort = (column) => {
757
761
  internalSorting.current = updateSortQuery(internalSorting.current, column.name, column.type);
758
- autoSortItems(items, column, internalSorting.current[column.name]);
762
+ setSortedItems(autoSortItems(items, column, internalSorting.current[column.name]));
759
763
  };
760
764
  const handleSort = (column) => {
761
765
  if (!column.sortable)
@@ -764,7 +768,7 @@ const DataTable = ({ items, columns, sorting = {}, onSort, loading, pagination =
764
768
  };
765
769
  return (jsxRuntime.jsxs("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: [jsxRuntime.jsx("div", { className: buildClassName('overflow-x-auto overflow-y-hidden rounded-lg border border-gray-200 dark:border-gray-800', wrapperClass, pagination && 'rounded-b-none border-b-0'), children: jsxRuntime.jsxs(Table, { className: "relative w-full max-w-full h-fit", layout: layout, children: [jsxRuntime.jsx(TableHead, { children: columns.map((column) => (jsxRuntime.jsx(TableHeaderCell, { align: column.headerAlign, style: { width: column.width || 'auto' }, className: buildClassName('bg-gray-50 dark:bg-gray-800', column.sticky === 'left' &&
766
770
  'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
767
- 'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]'), children: jsxRuntime.jsxs(TextContent, { role: column.sortable ? 'button' : undefined, className: buildClassName('group', column.sortable && 'inline-flex items-center gap-2 cursor-pointer select-none'), onClick: () => handleSort(column), children: [jsxRuntime.jsx(TextContent, { className: "shrink-0", children: column.label }), column.sortable ? getSortIcon(sorting[column.name]) : null] }) }, column.name))) }), jsxRuntime.jsx(TableBody, { loading: loading, colSize: columns.length, rowSize: (pagination === null || pagination === void 0 ? void 0 : pagination.limit) || 5, children: !loading && items.length === 0 ? (jsxRuntime.jsx(EmptyTableRow, { colSpan: columns.length, children: emptyMessage })) : (items.map((item) => (jsxRuntime.jsx(TableRow, { className: "group", children: columns.map((column) => {
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: "group", children: columns.map((column) => {
768
772
  var _a;
769
773
  return (jsxRuntime.jsx(TableCell, { align: column.align, className: buildClassName(column.sticky === 'left' &&
770
774
  'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
@@ -878,7 +882,7 @@ Input.displayName = 'Input';
878
882
  const PASSWORD_TYPE = 'password';
879
883
  const PASSWORD_PLACEHOLDER = '••••••••••';
880
884
  const PasswordInput = (props) => {
881
- const { type, placeholder, ...inputProps } = props;
885
+ const { ...inputProps } = props;
882
886
  const [showPassword, setShowPassword] = React.useState(false);
883
887
  return (jsxRuntime.jsx(Input, { ...inputProps, type: showPassword ? 'text' : PASSWORD_TYPE, placeholder: PASSWORD_PLACEHOLDER, rightGroup: jsxRuntime.jsx(Button, { theme: "secondary", variant: "plain", size: "xs", className: "px-1 mr-1", type: "button", onClick: () => setShowPassword(() => !showPassword), tabIndex: -1, children: showPassword ? (jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", className: "size-4", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88" }) })) : (jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", className: "size-4", children: [jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" }), jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" })] })) }) }));
884
888
  };
@@ -888,8 +892,9 @@ const Radio = React.forwardRef((props, ref) => {
888
892
  const { id, name, label, labelClass = '', wrapperClass = '', containerClass = '', error, disabled = false, className = '',
889
893
  // RadioButton-only props removed from rest
890
894
  ...rest } = props;
891
- const radioId = (_a = id !== null && id !== void 0 ? id : name) !== null && _a !== void 0 ? _a : 'checkbox-' + Math.random();
892
- return (jsxRuntime.jsxs("div", { className: buildClassName(wrapperClass), children: [jsxRuntime.jsxs("div", { className: buildClassName('flex items-center gap-2', containerClass), children: [jsxRuntime.jsx("div", { className: "grid place-items-center", children: jsxRuntime.jsx("input", { ref: ref, ...rest, id: radioId, name: name, type: "radio", disabled: disabled, "aria-selected": rest.checked, className: buildClassName('peer transition-all col-start-1 row-start-1 appearance-none shrink-0 size-4.5 rounded-full', 'border focus:ring-2 focus:ring-offset-2', 'checked:border-5 checked:bg-white', 'focus:ring-blue-500 checked:focus:ring-blue-600 dark:focus:ring-offset-gray-800', disabled
895
+ const generatedId = React.useId();
896
+ const radioId = (_a = id !== null && id !== void 0 ? id : name) !== null && _a !== void 0 ? _a : generatedId;
897
+ return (jsxRuntime.jsxs("div", { className: buildClassName(wrapperClass), children: [jsxRuntime.jsxs("div", { className: buildClassName('flex items-center gap-2', containerClass), children: [jsxRuntime.jsx("div", { className: "grid place-items-center", children: jsxRuntime.jsx("input", { ref: ref, ...rest, id: radioId, name: name, type: "radio", disabled: disabled, "aria-checked": rest.checked, className: buildClassName('peer transition-all col-start-1 row-start-1 appearance-none shrink-0 size-4.5 rounded-full', 'border focus:ring-2 focus:ring-offset-2', 'checked:border-5 checked:bg-white', 'focus:ring-blue-500 checked:focus:ring-blue-600 dark:focus:ring-offset-gray-800', disabled
893
898
  ? 'border-gray-200 dark:border-gray-700 bg-gray-100 dark:bg-gray-800 pointer-events-none'
894
899
  : buildClassName('bg-white dark:bg-gray-700 border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500', 'checked:border-blue-600 checked:hover:border-blue-600 dark:checked:border-blue-600 dark:checked:hover:border-blue-600'), className) }) }), label && (jsxRuntime.jsx(Label, { htmlFor: radioId, className: buildClassName(disabled
895
900
  ? 'cursor-not-allowed text-gray-400 dark:text-gray-500'
@@ -898,16 +903,9 @@ const Radio = React.forwardRef((props, ref) => {
898
903
 
899
904
  const RadioGroup = (props) => {
900
905
  const { name, label, labelClass, labelWrapperClass, labelHint, containerClass, options, value, row, error, showErrorMessage, onChange, } = props;
901
- const [items, setItems] = React.useState([]);
902
- React.useEffect(() => {
903
- setItems(() => {
904
- return options === null || options === void 0 ? void 0 : options.map((option) => {
905
- if (typeof option === 'string') {
906
- return { label: option, value: option };
907
- }
908
- return option;
909
- });
910
- });
906
+ const items = React.useMemo(() => {
907
+ var _a;
908
+ return (_a = options === null || options === void 0 ? void 0 : options.map((option) => typeof option === 'string' ? { label: option, value: option } : option)) !== null && _a !== void 0 ? _a : [];
911
909
  }, [options]);
912
910
  return (jsxRuntime.jsxs("div", { className: buildClassName(containerClass), children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between mb-4', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, children: label }), labelHint] })), jsxRuntime.jsx("div", { className: buildClassName('flex gap-4', row ? 'flex-row items-center' : 'flex-col items-start'), children: items.map((item) => (jsxRuntime.jsx(Radio, { name: name, id: `${name}-${item.value}`, label: item.label, value: item.value, checked: value === item.value, onChange: onChange }, item.value))) }), showErrorMessage && error && (jsxRuntime.jsx("div", { className: "mt-1", children: jsxRuntime.jsx(TextContent, { error: true, small: true, children: error }) }))] }));
913
911
  };
@@ -1001,35 +999,53 @@ const RangeSlider = ({ label, labelHint, labelClass = '', containerClass = '', c
1001
999
  const activeThumbRef = React.useRef(null);
1002
1000
  // State for UI styling
1003
1001
  const [activeThumbState, setActiveThumbState] = React.useState(null);
1002
+ // Keep prop values in refs so drag handlers always use latest values (no stale closure)
1003
+ const valueMinRef = React.useRef(valueMin);
1004
+ const valueMaxRef = React.useRef(valueMax);
1005
+ const onChangeRef = React.useRef(onChange);
1006
+ valueMinRef.current = valueMin;
1007
+ valueMaxRef.current = valueMax;
1008
+ onChangeRef.current = onChange;
1004
1009
  const hasError = !isEmpty(error);
1005
1010
  const percent = (v) => ((v - min) / (max - min)) * 100;
1006
- // ---------------------------------------------
1007
- // Pointer Move (drag)
1008
- // ---------------------------------------------
1009
- const pointerMoveHandler = (e) => {
1011
+ // Stable handler references registered on window — these never change identity
1012
+ // so removeEventListener always finds the right listener to remove.
1013
+ const stablePointerMoveRef = React.useRef((e) => {
1010
1014
  if (!trackRef.current || !activeThumbRef.current)
1011
1015
  return;
1012
1016
  const rect = trackRef.current.getBoundingClientRect();
1013
1017
  const x = Math.min(Math.max(e.clientX - rect.left, 0), rect.width);
1014
1018
  const rawVal = min + (x / rect.width) * (max - min);
1015
1019
  if (activeThumbRef.current === 'min') {
1016
- onChange(Math.min(rawVal, valueMax - 1), valueMax);
1020
+ onChangeRef.current(Math.min(rawVal, valueMaxRef.current - 1), valueMaxRef.current);
1017
1021
  }
1018
1022
  else {
1019
- onChange(valueMin, Math.max(rawVal, valueMin + 1));
1023
+ onChangeRef.current(valueMinRef.current, Math.max(rawVal, valueMinRef.current + 1));
1020
1024
  }
1021
- };
1022
- const pointerUpHandler = () => {
1025
+ });
1026
+ const stablePointerUpRef = React.useRef(() => {
1023
1027
  activeThumbRef.current = null;
1024
1028
  setActiveThumbState(null);
1025
- window.removeEventListener('pointermove', pointerMoveHandler);
1026
- window.removeEventListener('pointerup', pointerUpHandler);
1027
- };
1028
- const startDrag = (thumb) => (e) => {
1029
+ window.removeEventListener('pointermove', stablePointerMoveRef.current);
1030
+ window.removeEventListener('pointerup', stablePointerUpRef.current);
1031
+ });
1032
+ // Remove listeners on unmount in case a drag is in progress
1033
+ React.useEffect(() => {
1034
+ const move = stablePointerMoveRef.current;
1035
+ const up = stablePointerUpRef.current;
1036
+ return () => {
1037
+ window.removeEventListener('pointermove', move);
1038
+ window.removeEventListener('pointerup', up);
1039
+ };
1040
+ }, []);
1041
+ // ---------------------------------------------
1042
+ // Pointer Move (drag)
1043
+ // ---------------------------------------------
1044
+ const startDrag = (thumb) => (_e) => {
1029
1045
  activeThumbRef.current = thumb;
1030
1046
  setActiveThumbState(thumb);
1031
- window.addEventListener('pointermove', pointerMoveHandler);
1032
- window.addEventListener('pointerup', pointerUpHandler);
1047
+ window.addEventListener('pointermove', stablePointerMoveRef.current);
1048
+ window.addEventListener('pointerup', stablePointerUpRef.current);
1033
1049
  };
1034
1050
  // ---------------------------------------------
1035
1051
  // Click Track to move closest thumb
@@ -1091,6 +1107,9 @@ const useDebounce = (value, delay) => {
1091
1107
  };
1092
1108
  const useDebounceFn = (fn, ms) => {
1093
1109
  const timeout = React.useRef(null);
1110
+ React.useEffect(() => {
1111
+ return () => clearTimeout(timeout.current);
1112
+ }, []);
1094
1113
  return React.useCallback((...args) => {
1095
1114
  clearTimeout(timeout.current);
1096
1115
  timeout.current = setTimeout(() => fn(...args), ms);
@@ -1255,7 +1274,7 @@ const SelectBox = React.forwardRef((props, forwardedRef) => {
1255
1274
  console.error('onAdd handler error', err);
1256
1275
  }
1257
1276
  }, [onAdd, handleOnChangeInternal]);
1258
- const handleSearch = async (searchString) => {
1277
+ const handleSearch = React.useCallback(async (searchString) => {
1259
1278
  var _a;
1260
1279
  try {
1261
1280
  setOptionsLoading(true);
@@ -1267,11 +1286,11 @@ const SelectBox = React.forwardRef((props, forwardedRef) => {
1267
1286
  finally {
1268
1287
  setOptionsLoading(false);
1269
1288
  }
1270
- };
1289
+ }, [props.onSearch]);
1271
1290
  React.useEffect(() => {
1272
1291
  if (async && debouncedQuery)
1273
1292
  handleSearch(debouncedQuery);
1274
- }, [debouncedQuery, async]);
1293
+ }, [debouncedQuery, async, handleSearch]);
1275
1294
  return (jsxRuntime.jsxs("div", { className: buildClassName('group space-y-2', hasError && 'has-error', containerClass), ref: containerRef, children: [label && (jsxRuntime.jsxs("div", { className: buildClassName('flex items-center justify-between', labelWrapperClass), children: [jsxRuntime.jsx(Label, { className: labelClass, htmlFor: id, "aria-required": required, children: label }), labelHint] })), jsxRuntime.jsxs(react.Combobox, { multiple: multiple, immediate: immediate, name: name, value: selected, onChange: comboboxOnChangeWrapper, onClose: () => setQuery(''), disabled: disabled, children: [multiple ? (jsxRuntime.jsxs("div", { className: buildClassName(inputClass, 'flex flex-wrap gap-2 peer relative'), ref: forwardedRef, children: [isArray(selected) &&
1276
1295
  (selected === null || selected === void 0 ? void 0 : selected.length) > 0 &&
1277
1296
  selected.map((option, idx) => (jsxRuntime.jsx(Badge, { theme: "secondary", removable: !disabled, onRemove: () => removeSelection(idx), children: getDisplayValue(option) }, `${getValue(option)}-${idx}`))), jsxRuntime.jsx(react.ComboboxInput, { className: "outline-none flex-1 dark:placeholder-gray-400 placeholder-gray-400", "aria-label": name, value: query, autoComplete: "off", placeholder: (selected === null || selected === void 0 ? void 0 : selected.length) ? '' : placeholder, onChange: (e) => setQuery(e.target.value), id: id, ref: inputRef, onKeyDown: (e) => {
@@ -1384,7 +1403,11 @@ const ToastProvider = ({ children, placement = 'top-center' }) => {
1384
1403
  timeoutRefs.current.delete(id);
1385
1404
  }
1386
1405
  };
1387
- const scheduleClose = (toast) => {
1406
+ const closeToast = React.useCallback((id) => {
1407
+ clearTimer(id);
1408
+ setToasts((prev) => prev.filter((t) => t.id !== id));
1409
+ }, []);
1410
+ const scheduleClose = React.useCallback((toast) => {
1388
1411
  if (!toast.autoClose)
1389
1412
  return;
1390
1413
  clearTimer(toast.id);
@@ -1392,7 +1415,11 @@ const ToastProvider = ({ children, placement = 'top-center' }) => {
1392
1415
  closeToast(toast.id);
1393
1416
  }, toast.duration);
1394
1417
  timeoutRefs.current.set(toast.id, timeout);
1395
- };
1418
+ }, [closeToast]);
1419
+ React.useEffect(() => {
1420
+ const refs = timeoutRefs.current;
1421
+ return () => refs.forEach((id) => clearTimeout(id));
1422
+ }, []);
1396
1423
  const showToast = React.useCallback((message, options) => {
1397
1424
  var _a, _b, _c, _d;
1398
1425
  const id = ++toastCounter;
@@ -1411,612 +1438,12 @@ const ToastProvider = ({ children, placement = 'top-center' }) => {
1411
1438
  return updated;
1412
1439
  });
1413
1440
  scheduleClose(newToast);
1414
- }, []);
1415
- const closeToast = React.useCallback((id) => {
1416
- clearTimer(id);
1417
- setToasts((prev) => prev.filter((t) => t.id !== id));
1418
- }, []);
1441
+ }, [scheduleClose]);
1419
1442
  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))) })] }));
1420
1443
  };
1421
1444
 
1422
- const q = typeof window < "u" ? React.useLayoutEffect : React.useEffect;
1423
- function oe(e) {
1424
- if (e !== void 0)
1425
- switch (typeof e) {
1426
- case "number":
1427
- return e;
1428
- case "string": {
1429
- if (e.endsWith("px"))
1430
- return parseFloat(e);
1431
- break;
1432
- }
1433
- }
1434
- }
1435
- function Ie({
1436
- box: e,
1437
- defaultHeight: t,
1438
- defaultWidth: s,
1439
- disabled: r,
1440
- element: n,
1441
- mode: o,
1442
- style: i
1443
- }) {
1444
- const { styleHeight: f, styleWidth: l } = React.useMemo(
1445
- () => ({
1446
- styleHeight: oe(i?.height),
1447
- styleWidth: oe(i?.width)
1448
- }),
1449
- [i?.height, i?.width]
1450
- ), [c, d] = React.useState({
1451
- height: t,
1452
- width: s
1453
- }), a = r || f !== void 0 || o === "only-width" || f !== void 0 && l !== void 0;
1454
- return q(() => {
1455
- if (n === null || a)
1456
- return;
1457
- const u = new ResizeObserver((I) => {
1458
- for (const m of I) {
1459
- const { contentRect: b, target: g } = m;
1460
- n === g && d((w) => w.height === b.height && w.width === b.width ? w : {
1461
- height: b.height,
1462
- width: b.width
1463
- });
1464
- }
1465
- });
1466
- return u.observe(n, { box: e }), () => {
1467
- u?.unobserve(n);
1468
- };
1469
- }, [e, a, n, f, l]), React.useMemo(
1470
- () => ({
1471
- height: f ?? c.height,
1472
- width: l ?? c.width
1473
- }),
1474
- [c, f, l]
1475
- );
1476
- }
1477
- function ae(e) {
1478
- const t = React.useRef(() => {
1479
- throw new Error("Cannot call during render.");
1480
- });
1481
- return q(() => {
1482
- t.current = e;
1483
- }, [e]), React.useCallback((s) => t.current?.(s), [t]);
1484
- }
1485
- function Z({
1486
- containerElement: e,
1487
- direction: t,
1488
- isRtl: s,
1489
- scrollOffset: r
1490
- }) {
1491
- return r;
1492
- }
1493
- function $(e, t = "Assertion error") {
1494
- if (!e)
1495
- throw console.error(t), Error(t);
1496
- }
1497
- function Y(e, t) {
1498
- if (e === t)
1499
- return true;
1500
- if (!!e != !!t || ($(e !== void 0), $(t !== void 0), Object.keys(e).length !== Object.keys(t).length))
1501
- return false;
1502
- for (const s in e)
1503
- if (!Object.is(t[s], e[s]))
1504
- return false;
1505
- return true;
1506
- }
1507
- function fe({
1508
- cachedBounds: e,
1509
- itemCount: t,
1510
- itemSize: s
1511
- }) {
1512
- if (t === 0)
1513
- return 0;
1514
- if (typeof s == "number")
1515
- return t * s;
1516
- {
1517
- const r = e.get(
1518
- e.size === 0 ? 0 : e.size - 1
1519
- );
1520
- $(r !== void 0, "Unexpected bounds cache miss");
1521
- const n = (r.scrollOffset + r.size) / e.size;
1522
- return t * n;
1523
- }
1524
- }
1525
- function we({
1526
- align: e,
1527
- cachedBounds: t,
1528
- index: s,
1529
- itemCount: r,
1530
- itemSize: n,
1531
- containerScrollOffset: o,
1532
- containerSize: i
1533
- }) {
1534
- if (s < 0 || s >= r)
1535
- throw RangeError(`Invalid index specified: ${s}`, {
1536
- cause: `Index ${s} is not within the range of 0 - ${r - 1}`
1537
- });
1538
- const f = fe({
1539
- cachedBounds: t,
1540
- itemCount: r,
1541
- itemSize: n
1542
- }), l = t.get(s), c = Math.max(
1543
- 0,
1544
- Math.min(f - i, l.scrollOffset)
1545
- ), d = Math.max(
1546
- 0,
1547
- l.scrollOffset - i + l.size
1548
- );
1549
- switch (e === "smart" && (o >= d && o <= c ? e = "auto" : e = "center"), e) {
1550
- case "start":
1551
- return c;
1552
- case "end":
1553
- return d;
1554
- case "center":
1555
- return l.scrollOffset <= i / 2 ? 0 : l.scrollOffset + l.size / 2 >= f - i / 2 ? f - i : l.scrollOffset + l.size / 2 - i / 2;
1556
- case "auto":
1557
- default:
1558
- return o >= d && o <= c ? o : o < d ? d : c;
1559
- }
1560
- }
1561
- function ie({
1562
- cachedBounds: e,
1563
- containerScrollOffset: t,
1564
- containerSize: s,
1565
- itemCount: r,
1566
- overscanCount: n
1567
- }) {
1568
- const o = r - 1;
1569
- let i = 0, f = -1, l = 0, c = -1, d = 0;
1570
- for (; d < o; ) {
1571
- const a = e.get(d);
1572
- if (a.scrollOffset + a.size > t)
1573
- break;
1574
- d++;
1575
- }
1576
- for (i = d, l = Math.max(0, i - n); d < o; ) {
1577
- const a = e.get(d);
1578
- if (a.scrollOffset + a.size >= t + s)
1579
- break;
1580
- d++;
1581
- }
1582
- return f = Math.min(o, d), c = Math.min(r - 1, f + n), i < 0 && (i = 0, f = -1, l = 0, c = -1), {
1583
- startIndexVisible: i,
1584
- stopIndexVisible: f,
1585
- startIndexOverscan: l,
1586
- stopIndexOverscan: c
1587
- };
1588
- }
1589
- function me({
1590
- itemCount: e,
1591
- itemProps: t,
1592
- itemSize: s
1593
- }) {
1594
- const r = /* @__PURE__ */ new Map();
1595
- return {
1596
- get(n) {
1597
- for ($(n < e, `Invalid index ${n}`); r.size - 1 < n; ) {
1598
- const i = r.size;
1599
- let f;
1600
- switch (typeof s) {
1601
- case "function": {
1602
- f = s(i, t);
1603
- break;
1604
- }
1605
- case "number": {
1606
- f = s;
1607
- break;
1608
- }
1609
- }
1610
- if (i === 0)
1611
- r.set(i, {
1612
- size: f,
1613
- scrollOffset: 0
1614
- });
1615
- else {
1616
- const l = r.get(i - 1);
1617
- $(
1618
- l !== void 0,
1619
- `Unexpected bounds cache miss for index ${n}`
1620
- ), r.set(i, {
1621
- scrollOffset: l.scrollOffset + l.size,
1622
- size: f
1623
- });
1624
- }
1625
- }
1626
- const o = r.get(n);
1627
- return $(
1628
- o !== void 0,
1629
- `Unexpected bounds cache miss for index ${n}`
1630
- ), o;
1631
- },
1632
- set(n, o) {
1633
- r.set(n, o);
1634
- },
1635
- get size() {
1636
- return r.size;
1637
- }
1638
- };
1639
- }
1640
- function Oe({
1641
- itemCount: e,
1642
- itemProps: t,
1643
- itemSize: s
1644
- }) {
1645
- return React.useMemo(
1646
- () => me({
1647
- itemCount: e,
1648
- itemProps: t,
1649
- itemSize: s
1650
- }),
1651
- [e, t, s]
1652
- );
1653
- }
1654
- function ye({
1655
- containerSize: e,
1656
- itemSize: t
1657
- }) {
1658
- let s;
1659
- switch (typeof t) {
1660
- case "string": {
1661
- $(
1662
- t.endsWith("%"),
1663
- `Invalid item size: "${t}"; string values must be percentages (e.g. "100%")`
1664
- ), $(
1665
- e !== void 0,
1666
- "Container size must be defined if a percentage item size is specified"
1667
- ), s = e * parseInt(t) / 100;
1668
- break;
1669
- }
1670
- default: {
1671
- s = t;
1672
- break;
1673
- }
1674
- }
1675
- return s;
1676
- }
1677
- function ee({
1678
- containerElement: e,
1679
- containerStyle: t,
1680
- defaultContainerSize: s = 0,
1681
- direction: r,
1682
- isRtl: n = false,
1683
- itemCount: o,
1684
- itemProps: i,
1685
- itemSize: f,
1686
- onResize: l,
1687
- overscanCount: c
1688
- }) {
1689
- const [d, a] = React.useState({
1690
- startIndexVisible: 0,
1691
- startIndexOverscan: 0,
1692
- stopIndexVisible: -1,
1693
- stopIndexOverscan: -1
1694
- }), {
1695
- startIndexVisible: u,
1696
- startIndexOverscan: I,
1697
- stopIndexVisible: m,
1698
- stopIndexOverscan: b
1699
- } = {
1700
- startIndexVisible: Math.min(o - 1, d.startIndexVisible),
1701
- startIndexOverscan: Math.min(o - 1, d.startIndexOverscan),
1702
- stopIndexVisible: Math.min(o - 1, d.stopIndexVisible),
1703
- stopIndexOverscan: Math.min(o - 1, d.stopIndexOverscan)
1704
- }, { height: g = s, width: w = s } = Ie({
1705
- defaultHeight: s ,
1706
- defaultWidth: void 0,
1707
- element: e,
1708
- mode: "only-height" ,
1709
- style: t
1710
- }), y = React.useRef({
1711
- height: 0,
1712
- width: 0
1713
- }), V = g , h = ye({ containerSize: V, itemSize: f });
1714
- React.useLayoutEffect(() => {
1715
- if (typeof l == "function") {
1716
- const p = y.current;
1717
- (p.height !== g || p.width !== w) && (l({ height: g, width: w }, { ...p }), p.height = g, p.width = w);
1718
- }
1719
- }, [g, l, w]);
1720
- const z = Oe({
1721
- itemCount: o,
1722
- itemProps: i,
1723
- itemSize: h
1724
- }), k = React.useCallback(
1725
- (p) => z.get(p),
1726
- [z]
1727
- ), S = React.useCallback(
1728
- () => fe({
1729
- cachedBounds: z,
1730
- itemCount: o,
1731
- itemSize: h
1732
- }),
1733
- [z, o, h]
1734
- ), W = React.useCallback(
1735
- (p) => {
1736
- const T = Z({
1737
- containerElement: e,
1738
- direction: r,
1739
- isRtl: n,
1740
- scrollOffset: p
1741
- });
1742
- return ie({
1743
- cachedBounds: z,
1744
- containerScrollOffset: T,
1745
- containerSize: V,
1746
- itemCount: o,
1747
- overscanCount: c
1748
- });
1749
- },
1750
- [
1751
- z,
1752
- e,
1753
- V,
1754
- r,
1755
- n,
1756
- o,
1757
- c
1758
- ]
1759
- );
1760
- q(() => {
1761
- const p = (e?.scrollTop ) ?? 0;
1762
- a(W(p));
1763
- }, [e, r, W]), q(() => {
1764
- if (!e)
1765
- return;
1766
- const p = () => {
1767
- a((T) => {
1768
- const { scrollLeft: R, scrollTop: v } = e, x = Z({
1769
- containerElement: e,
1770
- direction: r,
1771
- isRtl: n,
1772
- scrollOffset: v
1773
- }), A = ie({
1774
- cachedBounds: z,
1775
- containerScrollOffset: x,
1776
- containerSize: V,
1777
- itemCount: o,
1778
- overscanCount: c
1779
- });
1780
- return Y(A, T) ? T : A;
1781
- });
1782
- };
1783
- return e.addEventListener("scroll", p), () => {
1784
- e.removeEventListener("scroll", p);
1785
- };
1786
- }, [
1787
- z,
1788
- e,
1789
- V,
1790
- r,
1791
- o,
1792
- c
1793
- ]);
1794
- const O = ae(
1795
- ({
1796
- align: p = "auto",
1797
- containerScrollOffset: T,
1798
- index: R
1799
- }) => {
1800
- let v = we({
1801
- align: p,
1802
- cachedBounds: z,
1803
- containerScrollOffset: T,
1804
- containerSize: V,
1805
- index: R,
1806
- itemCount: o,
1807
- itemSize: h
1808
- });
1809
- if (e) {
1810
- if (v = Z({
1811
- containerElement: e,
1812
- direction: r,
1813
- isRtl: n,
1814
- scrollOffset: v
1815
- }), typeof e.scrollTo != "function") {
1816
- const x = W(v);
1817
- Y(d, x) || a(x);
1818
- }
1819
- return v;
1820
- }
1821
- }
1822
- );
1823
- return {
1824
- getCellBounds: k,
1825
- getEstimatedSize: S,
1826
- scrollToIndex: O,
1827
- startIndexOverscan: I,
1828
- startIndexVisible: u,
1829
- stopIndexOverscan: b,
1830
- stopIndexVisible: m
1831
- };
1832
- }
1833
- function de(e) {
1834
- return React.useMemo(() => e, Object.values(e));
1835
- }
1836
- function ue(e, t) {
1837
- const {
1838
- ariaAttributes: s,
1839
- style: r,
1840
- ...n
1841
- } = e, {
1842
- ariaAttributes: o,
1843
- style: i,
1844
- ...f
1845
- } = t;
1846
- return Y(s, o) && Y(r, i) && Y(n, f);
1847
- }
1848
- function ze(e) {
1849
- return e != null && typeof e == "object" && "getAverageRowHeight" in e && typeof e.getAverageRowHeight == "function";
1850
- }
1851
- const te = "data-react-window-index";
1852
- function Ae({
1853
- children: e,
1854
- className: t,
1855
- defaultHeight: s = 0,
1856
- listRef: r,
1857
- onResize: n,
1858
- onRowsRendered: o,
1859
- overscanCount: i = 3,
1860
- rowComponent: f,
1861
- rowCount: l,
1862
- rowHeight: c,
1863
- rowProps: d,
1864
- tagName: a = "div",
1865
- style: u,
1866
- ...I
1867
- }) {
1868
- const m = de(d), b = React.useMemo(
1869
- () => React.memo(f, ue),
1870
- [f]
1871
- ), [g, w] = React.useState(null), y = ze(c), V = React.useMemo(() => y ? (v) => c.getRowHeight(v) ?? c.getAverageRowHeight() : c, [y, c]), {
1872
- getCellBounds: h,
1873
- getEstimatedSize: z,
1874
- scrollToIndex: k,
1875
- startIndexOverscan: S,
1876
- startIndexVisible: W,
1877
- stopIndexOverscan: O,
1878
- stopIndexVisible: p
1879
- } = ee({
1880
- containerElement: g,
1881
- containerStyle: u,
1882
- defaultContainerSize: s,
1883
- direction: "vertical",
1884
- itemCount: l,
1885
- itemProps: m,
1886
- itemSize: V,
1887
- onResize: n,
1888
- overscanCount: i
1889
- });
1890
- React.useImperativeHandle(
1891
- r,
1892
- () => ({
1893
- get element() {
1894
- return g;
1895
- },
1896
- scrollToRow({
1897
- align: v = "auto",
1898
- behavior: x = "auto",
1899
- index: A
1900
- }) {
1901
- const M = k({
1902
- align: v,
1903
- containerScrollOffset: g?.scrollTop ?? 0,
1904
- index: A
1905
- });
1906
- typeof g?.scrollTo == "function" && g.scrollTo({
1907
- behavior: x,
1908
- top: M
1909
- });
1910
- }
1911
- }),
1912
- [g, k]
1913
- ), q(() => {
1914
- if (!g)
1915
- return;
1916
- const v = Array.from(g.children).filter((x, A) => {
1917
- if (x.hasAttribute("aria-hidden"))
1918
- return false;
1919
- const M = `${S + A}`;
1920
- return x.setAttribute(te, M), true;
1921
- });
1922
- if (y)
1923
- return c.observeRowElements(v);
1924
- }, [
1925
- g,
1926
- y,
1927
- c,
1928
- S,
1929
- O
1930
- ]), React.useEffect(() => {
1931
- S >= 0 && O >= 0 && o && o(
1932
- {
1933
- startIndex: W,
1934
- stopIndex: p
1935
- },
1936
- {
1937
- startIndex: S,
1938
- stopIndex: O
1939
- }
1940
- );
1941
- }, [
1942
- o,
1943
- S,
1944
- W,
1945
- O,
1946
- p
1947
- ]);
1948
- const T = React.useMemo(() => {
1949
- const v = [];
1950
- if (l > 0)
1951
- for (let x = S; x <= O; x++) {
1952
- const A = h(x);
1953
- v.push(
1954
- /* @__PURE__ */ React.createElement(
1955
- b,
1956
- {
1957
- ...m,
1958
- ariaAttributes: {
1959
- "aria-posinset": x + 1,
1960
- "aria-setsize": l,
1961
- role: "listitem"
1962
- },
1963
- key: x,
1964
- index: x,
1965
- style: {
1966
- position: "absolute",
1967
- left: 0,
1968
- transform: `translateY(${A.scrollOffset}px)`,
1969
- // In case of dynamic row heights, don't specify a height style
1970
- // otherwise a default/estimated height would mask the actual height
1971
- height: y ? void 0 : A.size,
1972
- width: "100%"
1973
- }
1974
- }
1975
- )
1976
- );
1977
- }
1978
- return v;
1979
- }, [
1980
- b,
1981
- h,
1982
- y,
1983
- l,
1984
- m,
1985
- S,
1986
- O
1987
- ]), R = /* @__PURE__ */ jsxRuntime.jsx(
1988
- "div",
1989
- {
1990
- "aria-hidden": true,
1991
- style: {
1992
- height: z(),
1993
- width: "100%",
1994
- zIndex: -1
1995
- }
1996
- }
1997
- );
1998
- return React.createElement(
1999
- a,
2000
- {
2001
- role: "list",
2002
- ...I,
2003
- className: t,
2004
- ref: w,
2005
- style: {
2006
- position: "relative",
2007
- maxHeight: "100%",
2008
- flexGrow: 1,
2009
- overflowY: "auto",
2010
- ...u
2011
- }
2012
- },
2013
- T,
2014
- e,
2015
- R
2016
- );
2017
- }
2018
-
2019
- const VirtualizedRow = ({ index, style, items, columns, gridTemplate, }) => {
1445
+ const VirtualizedRow = ({ index, style, data }) => {
1446
+ const { items, columns, gridTemplate } = data;
2020
1447
  const item = items[index];
2021
1448
  return (jsxRuntime.jsx("div", { role: "row", className: "grid border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 group", style: {
2022
1449
  ...style,
@@ -2038,14 +1465,21 @@ const VirtualizedRow = ({ index, style, items, columns, gridTemplate, }) => {
2038
1465
  const useGridTemplate = (columns) => React.useMemo(() => columns.map((col) => (col.width ? `${col.width}px` : '1fr')).join(' '), [columns]);
2039
1466
  const VirtualizedDataTable = ({ items, columns, sorting = {}, onSort, loading = false, emptyMessage = 'No data available', containerClass = '', wrapperClass = '', rowHeight = 48, maxHeight = 400, }) => {
2040
1467
  const scrollRef = React.useRef(null);
1468
+ const outerRef = React.useRef(null);
2041
1469
  const headerRef = React.useRef(null);
2042
1470
  const gridTemplate = useGridTemplate(columns);
2043
- /** Sync body → header scroll */
2044
- const handleScrollSync = (scrollOffset) => {
2045
- if (headerRef.current) {
2046
- headerRef.current.scrollLeft = scrollOffset;
2047
- }
2048
- };
1471
+ /** Sync horizontal scroll of the virtualized body → header */
1472
+ React.useEffect(() => {
1473
+ const el = outerRef.current;
1474
+ if (!el)
1475
+ return;
1476
+ const handler = () => {
1477
+ if (headerRef.current)
1478
+ headerRef.current.scrollLeft = el.scrollLeft;
1479
+ };
1480
+ el.addEventListener('scroll', handler);
1481
+ return () => el.removeEventListener('scroll', handler);
1482
+ }, []);
2049
1483
  const handleSort = React.useCallback((column) => {
2050
1484
  if (column.sortable)
2051
1485
  onSort === null || onSort === void 0 ? void 0 : onSort(column);
@@ -2077,11 +1511,7 @@ const VirtualizedDataTable = ({ items, columns, sorting = {}, onSort, loading =
2077
1511
  /* -------------------------------------------------------
2078
1512
  * MAIN (virtualized body)
2079
1513
  * ------------------------------------------------------- */
2080
- return (jsxRuntime.jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxRuntime.jsxs("div", { className: buildClassName('rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden', wrapperClass), children: [Header, jsxRuntime.jsx("div", { style: {
2081
- height: maxHeight,
2082
- overflowY: 'auto',
2083
- overflowX: 'auto',
2084
- }, children: jsxRuntime.jsx(Ae, { listRef: scrollRef, rowComponent: VirtualizedRow, rowCount: items.length, rowHeight: rowHeight, rowProps: { items, columns, gridTemplate }, onScroll: (e) => handleScrollSync(e.currentTarget.scrollLeft) }) })] }) }));
1514
+ return (jsxRuntime.jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxRuntime.jsxs("div", { className: buildClassName('rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden', wrapperClass), children: [Header, jsxRuntime.jsx(reactWindow.FixedSizeList, { ref: scrollRef, outerRef: outerRef, height: maxHeight, width: "100%", itemCount: items.length, itemSize: rowHeight, itemData: { items, columns, gridTemplate }, children: VirtualizedRow })] }) }));
2085
1515
  };
2086
1516
 
2087
1517
  const useIsMobile = () => {