@papernote/ui 2.0.3 → 2.0.5

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/index.js CHANGED
@@ -2765,7 +2765,7 @@ function FormControl({ label, required = false, error, helperText, children, cla
2765
2765
  return (jsxRuntime.jsxs("div", { className: `${className}`, children: [label && (jsxRuntime.jsxs("label", { htmlFor: htmlFor, className: "block text-sm font-medium text-ink-700 mb-1", children: [label, required && jsxRuntime.jsx("span", { className: "text-error-500 ml-1", children: "*" })] })), jsxRuntime.jsx("div", { children: children }), (error || helperText) && (jsxRuntime.jsx("p", { className: `mt-1 text-xs ${error ? 'text-error-600' : 'text-ink-500'}`, children: error || helperText }))] }));
2766
2766
  }
2767
2767
 
2768
- function FilterBar({ filters, values, onChange, className = '', onClear, showClearButton = false, }) {
2768
+ function FilterBar({ filters, values, onChange, className = "", onClear, showClearButton = false, }) {
2769
2769
  const handleFilterChange = (key, value) => {
2770
2770
  onChange({
2771
2771
  ...values,
@@ -2779,16 +2779,19 @@ function FilterBar({ filters, values, onChange, className = '', onClear, showCle
2779
2779
  else {
2780
2780
  // Default clear: set all values to null/empty
2781
2781
  const clearedValues = {};
2782
- filters.forEach(filter => {
2783
- if (filter.type === 'text' || filter.type === 'search') {
2784
- clearedValues[filter.key] = '';
2782
+ filters.forEach((filter) => {
2783
+ if (filter.type === "text" || filter.type === "search") {
2784
+ clearedValues[filter.key] = "";
2785
2785
  }
2786
- else if (filter.type === 'dateRange') {
2786
+ else if (filter.type === "dateRange") {
2787
2787
  clearedValues[filter.key] = { from: undefined, to: undefined };
2788
2788
  }
2789
- else if (filter.type === 'multiSelect') {
2789
+ else if (filter.type === "multiSelect") {
2790
2790
  clearedValues[filter.key] = [];
2791
2791
  }
2792
+ else if (filter.type === "switch") {
2793
+ clearedValues[filter.key] = false;
2794
+ }
2792
2795
  else {
2793
2796
  clearedValues[filter.key] = null;
2794
2797
  }
@@ -2799,51 +2802,70 @@ function FilterBar({ filters, values, onChange, className = '', onClear, showCle
2799
2802
  const renderFilter = (filter) => {
2800
2803
  const value = values[filter.key];
2801
2804
  switch (filter.type) {
2802
- case 'text':
2803
- return (jsxRuntime.jsx(Input, { type: "text", placeholder: filter.placeholder || `Filter by ${filter.label}`, value: value || '', onChange: (e) => handleFilterChange(filter.key, e.target.value) }));
2804
- case 'select': {
2805
+ case "text":
2806
+ return (jsxRuntime.jsx(Input, { type: "text", placeholder: filter.placeholder || `Filter by ${filter.label}`, value: value || "", onChange: (e) => handleFilterChange(filter.key, e.target.value) }));
2807
+ case "select": {
2805
2808
  const selectOptions = [
2806
- { value: '', label: `All ${filter.label}` },
2807
- ...(filter.options?.map(opt => ({
2809
+ { value: "", label: `All ${filter.label}` },
2810
+ ...(filter.options?.map((opt) => ({
2808
2811
  value: String(opt.value),
2809
2812
  label: opt.label,
2810
2813
  })) || []),
2811
2814
  ];
2812
- return (jsxRuntime.jsx(Select, { options: selectOptions, value: String(value || ''), onChange: (newValue) => handleFilterChange(filter.key, newValue || null) }));
2815
+ return (jsxRuntime.jsx(Select, { options: selectOptions, value: String(value || ""), onChange: (newValue) => handleFilterChange(filter.key, newValue || null) }));
2813
2816
  }
2814
- case 'date':
2815
- return (jsxRuntime.jsx("input", { type: "date", value: value || '', onChange: (e) => handleFilterChange(filter.key, e.target.value), className: "input" }));
2816
- case 'number':
2817
- return (jsxRuntime.jsx("input", { type: "number", placeholder: filter.placeholder || `Filter by ${filter.label}`, value: value !== null && value !== undefined ? String(value) : '', onChange: (e) => handleFilterChange(filter.key, e.target.value ? Number(e.target.value) : null), className: "input" }));
2818
- case 'boolean': {
2817
+ case "date":
2818
+ return (jsxRuntime.jsx("input", { type: "date", value: value || "", onChange: (e) => handleFilterChange(filter.key, e.target.value), className: "input" }));
2819
+ case "number":
2820
+ return (jsxRuntime.jsx("input", { type: "number", placeholder: filter.placeholder || `Filter by ${filter.label}`, value: value !== null && value !== undefined ? String(value) : "", onChange: (e) => handleFilterChange(filter.key, e.target.value ? Number(e.target.value) : null), className: "input" }));
2821
+ case "boolean": {
2819
2822
  const boolOptions = [
2820
- { value: '', label: 'All' },
2821
- { value: 'true', label: 'Yes' },
2822
- { value: 'false', label: 'No' },
2823
+ { value: "", label: "All" },
2824
+ { value: "true", label: "Yes" },
2825
+ { value: "false", label: "No" },
2823
2826
  ];
2824
- return (jsxRuntime.jsx(Select, { options: boolOptions, value: value === null || value === undefined ? '' : String(value), onChange: (newValue) => handleFilterChange(filter.key, newValue === '' ? null : newValue === 'true') }));
2827
+ return (jsxRuntime.jsx(Select, { options: boolOptions, value: value === null || value === undefined ? "" : String(value), onChange: (newValue) => handleFilterChange(filter.key, newValue === "" ? null : newValue === "true") }));
2825
2828
  }
2826
- case 'search':
2827
- return (jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none", children: jsxRuntime.jsx(lucideReact.Search, { className: "h-4 w-4 text-ink-400" }) }), jsxRuntime.jsx("input", { type: "text", placeholder: filter.placeholder || `Search ${filter.label}...`, value: value || '', onChange: (e) => handleFilterChange(filter.key, e.target.value), className: "input pl-9" })] }));
2828
- case 'dateRange': {
2829
+ case "search":
2830
+ return (jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none", children: jsxRuntime.jsx(lucideReact.Search, { className: "h-4 w-4 text-ink-400" }) }), jsxRuntime.jsx("input", { type: "text", placeholder: filter.placeholder || `Search ${filter.label}...`, value: value || "", onChange: (e) => handleFilterChange(filter.key, e.target.value), className: "input pl-9" })] }));
2831
+ case "dateRange": {
2829
2832
  const rangeValue = value || {};
2830
- return (jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("input", { type: "date", value: rangeValue.from || '', onChange: (e) => handleFilterChange(filter.key, { ...rangeValue, from: e.target.value || undefined }), className: "input text-sm", "aria-label": `${filter.label} from` }), jsxRuntime.jsx("span", { className: "text-ink-400 text-xs", children: "to" }), jsxRuntime.jsx("input", { type: "date", value: rangeValue.to || '', onChange: (e) => handleFilterChange(filter.key, { ...rangeValue, to: e.target.value || undefined }), className: "input text-sm", "aria-label": `${filter.label} to` })] }));
2831
- }
2832
- case 'toggle': {
2833
+ return (jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("input", { type: "date", value: rangeValue.from || "", onChange: (e) => handleFilterChange(filter.key, {
2834
+ ...rangeValue,
2835
+ from: e.target.value || undefined,
2836
+ }), className: "input text-sm", "aria-label": `${filter.label} from` }), jsxRuntime.jsx("span", { className: "text-ink-400 text-xs", children: "to" }), jsxRuntime.jsx("input", { type: "date", value: rangeValue.to || "", onChange: (e) => handleFilterChange(filter.key, {
2837
+ ...rangeValue,
2838
+ to: e.target.value || undefined,
2839
+ }), className: "input text-sm", "aria-label": `${filter.label} to` })] }));
2840
+ }
2841
+ case "toggle": {
2833
2842
  const toggleOptions = [
2834
- { value: '', label: 'All' },
2835
- { value: 'true', label: 'Yes' },
2836
- { value: 'false', label: 'No' },
2843
+ { value: "", label: "All" },
2844
+ { value: "true", label: "Yes" },
2845
+ { value: "false", label: "No" },
2837
2846
  ];
2838
- const currentVal = value === null || value === undefined ? '' : String(value);
2839
- return (jsxRuntime.jsx("div", { className: "flex rounded-lg border border-paper-300 overflow-hidden", role: "group", children: toggleOptions.map((opt) => (jsxRuntime.jsx("button", { type: "button", onClick: () => handleFilterChange(filter.key, opt.value === '' ? null : opt.value === 'true'), className: `px-3 py-1.5 text-xs font-medium transition-colors ${currentVal === opt.value
2840
- ? 'bg-accent-500 text-white'
2841
- : 'bg-white text-ink-600 hover:bg-paper-50'} ${opt.value !== '' ? 'border-l border-paper-300' : ''}`, children: opt.label }, opt.value))) }));
2842
- }
2843
- case 'multiSelect': {
2847
+ const currentVal = value === null || value === undefined ? "" : String(value);
2848
+ return (jsxRuntime.jsx("div", { className: "flex rounded-lg border border-paper-300 overflow-hidden", role: "group", children: toggleOptions.map((opt) => (jsxRuntime.jsx("button", { type: "button", onClick: () => handleFilterChange(filter.key, opt.value === "" ? null : opt.value === "true"), className: `px-3 py-1.5 text-xs font-medium transition-colors ${currentVal === opt.value
2849
+ ? "bg-accent-500 text-white"
2850
+ : "bg-white text-ink-600 hover:bg-paper-50"} ${opt.value !== "" ? "border-l border-paper-300" : ""}`, children: opt.label }, opt.value))) }));
2851
+ }
2852
+ case "switch": {
2853
+ // Single binary toggle — use when the filter is naturally on/off
2854
+ // (e.g. "Mine only", "Archived"), unlike `boolean` / `toggle` which
2855
+ // present an All/Yes/No tri-state. Stored value is a plain boolean.
2856
+ const checked = value === true;
2857
+ return (jsxRuntime.jsxs("button", { type: "button", role: "switch", "aria-checked": checked, onClick: () => handleFilterChange(filter.key, !checked), className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-accent-400 focus:ring-offset-2 ${checked ? "bg-accent-500" : "bg-paper-300"}`, children: [jsxRuntime.jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${checked ? "translate-x-6" : "translate-x-1"}` }), jsxRuntime.jsx("span", { className: "sr-only", children: filter.label })] }));
2858
+ }
2859
+ case "multiSelect": {
2844
2860
  const selectedValues = Array.isArray(value) ? value : [];
2845
2861
  const msOptions = filter.options || [];
2846
- return (jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx(Select, { options: [{ value: '', label: `All ${filter.label}` }, ...msOptions.map(o => ({ value: String(o.value), label: o.label }))], value: "", onChange: (newValue) => {
2862
+ return (jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx(Select, { options: [
2863
+ { value: "", label: `All ${filter.label}` },
2864
+ ...msOptions.map((o) => ({
2865
+ value: String(o.value),
2866
+ label: o.label,
2867
+ })),
2868
+ ], value: "", onChange: (newValue) => {
2847
2869
  if (!newValue) {
2848
2870
  handleFilterChange(filter.key, []);
2849
2871
  }
@@ -2851,8 +2873,8 @@ function FilterBar({ filters, values, onChange, className = '', onClear, showCle
2851
2873
  handleFilterChange(filter.key, [...selectedValues, newValue]);
2852
2874
  }
2853
2875
  } }), selectedValues.length > 0 && (jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1 mt-1", children: selectedValues.map((sv) => {
2854
- const opt = msOptions.find(o => String(o.value) === sv);
2855
- return (jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs bg-accent-100 text-accent-700 rounded-full", children: [opt?.label || sv, jsxRuntime.jsx("button", { type: "button", onClick: () => handleFilterChange(filter.key, selectedValues.filter(v => v !== sv)), className: "hover:text-accent-900", children: jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" }) })] }, sv));
2876
+ const opt = msOptions.find((o) => String(o.value) === sv);
2877
+ return (jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs bg-accent-100 text-accent-700 rounded-full", children: [opt?.label || sv, jsxRuntime.jsx("button", { type: "button", onClick: () => handleFilterChange(filter.key, selectedValues.filter((v) => v !== sv)), className: "hover:text-accent-900", children: jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" }) })] }, sv));
2856
2878
  }) }))] }));
2857
2879
  }
2858
2880
  default:
@@ -14804,25 +14826,27 @@ function ActionMenu({ actions, item, }) {
14804
14826
  // Click outside handler
14805
14827
  React.useEffect(() => {
14806
14828
  const handleClickOutside = (event) => {
14807
- if (menuRef.current && !menuRef.current.contains(event.target) &&
14808
- buttonRef.current && !buttonRef.current.contains(event.target)) {
14829
+ if (menuRef.current &&
14830
+ !menuRef.current.contains(event.target) &&
14831
+ buttonRef.current &&
14832
+ !buttonRef.current.contains(event.target)) {
14809
14833
  setIsOpen(false);
14810
14834
  }
14811
14835
  };
14812
14836
  if (isOpen) {
14813
- document.addEventListener('mousedown', handleClickOutside);
14837
+ document.addEventListener("mousedown", handleClickOutside);
14814
14838
  }
14815
14839
  return () => {
14816
- document.removeEventListener('mousedown', handleClickOutside);
14840
+ document.removeEventListener("mousedown", handleClickOutside);
14817
14841
  };
14818
14842
  }, [isOpen]);
14819
- const visibleActions = actions.filter(action => !action.show || action.show(item));
14843
+ const visibleActions = actions.filter((action) => !action.show || action.show(item));
14820
14844
  if (visibleActions.length === 0)
14821
14845
  return null;
14822
14846
  const dropdownContent = isOpen && (jsxRuntime.jsx("div", { ref: menuRef, className: "fixed w-56 bg-white rounded-lg shadow-lg border border-paper-300 py-1", style: {
14823
14847
  zIndex: 999999,
14824
14848
  top: `${position.top}px`,
14825
- left: `${position.left}px`
14849
+ left: `${position.left}px`,
14826
14850
  }, children: visibleActions.map((action, idx) => {
14827
14851
  let iconElement = null;
14828
14852
  if (action.icon) {
@@ -14830,7 +14854,9 @@ function ActionMenu({ actions, item, }) {
14830
14854
  iconElement = action.icon;
14831
14855
  }
14832
14856
  else {
14833
- iconElement = React.createElement(action.icon, { className: 'h-4 w-4 flex-shrink-0' });
14857
+ iconElement = React.createElement(action.icon, {
14858
+ className: "h-4 w-4 flex-shrink-0",
14859
+ });
14834
14860
  }
14835
14861
  }
14836
14862
  return (jsxRuntime.jsxs("button", { type: "button", onClick: async (e) => {
@@ -14840,12 +14866,12 @@ function ActionMenu({ actions, item, }) {
14840
14866
  await action.onClick(item);
14841
14867
  }
14842
14868
  catch (error) {
14843
- console.error('DataTable action error:', error);
14869
+ console.error("DataTable action error:", error);
14844
14870
  }
14845
14871
  setIsOpen(false);
14846
- }, className: `w-full flex items-center gap-3 px-4 py-2.5 text-sm transition-colors ${action.variant === 'danger'
14847
- ? 'text-error-600 hover:bg-error-50 hover:text-error-700'
14848
- : 'text-ink-700 hover:bg-paper-50'}`, title: action.tooltip, children: [iconElement, jsxRuntime.jsx("span", { className: "flex-1 text-left", children: action.label })] }, idx));
14872
+ }, className: `w-full flex items-center gap-3 px-4 py-2.5 text-sm transition-colors ${action.variant === "danger"
14873
+ ? "text-error-600 hover:bg-error-50 hover:text-error-700"
14874
+ : "text-ink-700 hover:bg-paper-50"}`, title: action.tooltip, children: [iconElement, jsxRuntime.jsx("span", { className: "flex-1 text-left", children: action.label })] }, idx));
14849
14875
  }) }));
14850
14876
  return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("button", { ref: buttonRef, onClick: (e) => {
14851
14877
  e.stopPropagation();
@@ -14862,13 +14888,20 @@ function getColumnStyle(column, dynamicWidth) {
14862
14888
  style.width = `${dynamicWidth}px`;
14863
14889
  }
14864
14890
  else if (column.width !== undefined) {
14865
- style.width = typeof column.width === 'number' ? `${column.width}px` : column.width;
14891
+ style.width =
14892
+ typeof column.width === "number" ? `${column.width}px` : column.width;
14866
14893
  }
14867
14894
  if (column.minWidth !== undefined) {
14868
- style.minWidth = typeof column.minWidth === 'number' ? `${column.minWidth}px` : column.minWidth;
14895
+ style.minWidth =
14896
+ typeof column.minWidth === "number"
14897
+ ? `${column.minWidth}px`
14898
+ : column.minWidth;
14869
14899
  }
14870
14900
  if (column.maxWidth !== undefined) {
14871
- style.maxWidth = typeof column.maxWidth === 'number' ? `${column.maxWidth}px` : column.maxWidth;
14901
+ style.maxWidth =
14902
+ typeof column.maxWidth === "number"
14903
+ ? `${column.maxWidth}px`
14904
+ : column.maxWidth;
14872
14905
  }
14873
14906
  if (column.flex !== undefined) {
14874
14907
  style.flexGrow = column.flex;
@@ -14927,13 +14960,13 @@ function getColumnStyle(column, dynamicWidth) {
14927
14960
  * />
14928
14961
  * ```
14929
14962
  */
14930
- function DataTable({ data, columns, loading = false, error = null, emptyMessage = 'No data available', loadingRows = 5, className = '', onSortChange, currentSort = null, onEdit, onDelete, actions = [], enableContextMenu = true, onRowClick, onRowDoubleClick, selectable = false, selectedRows: externalSelectedRows, onRowSelect, keyExtractor, expandable = false, expandedRows: externalExpandedRows, renderExpandedRow, expandedRowConfig, showExpandChevron = false,
14963
+ function DataTable({ data, columns, loading = false, error = null, emptyMessage = "No data available", loadingRows = 5, className = "", onSortChange, currentSort = null, onEdit, onDelete, actions = [], enableContextMenu = true, onRowClick, onRowDoubleClick, selectable = false, selectedRows: externalSelectedRows, onRowSelect, keyExtractor, expandable = false, expandedRows: externalExpandedRows, renderExpandedRow, expandedRowConfig, showExpandChevron = false,
14931
14964
  // Visual customization props
14932
- striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, highlightedRowId, highlightedRows = [], highlightDuration = 2000, bordered = false, borderColor = 'border-paper-200', disableHover = false, hiddenColumns = [], headerClassName = '', renderEmptyState: customRenderEmptyState, resizable = false, onColumnResize, reorderable = false, onColumnReorder, virtualized = false, virtualHeight = '600px', virtualRowHeight = 60,
14965
+ striped = false, stripedColor, density = "normal", rowClassName, rowHighlight, highlightedRowId, highlightedRows = [], highlightDuration = 2000, bordered = false, borderColor = "border-paper-200", disableHover = false, hiddenColumns = [], headerClassName = "", renderEmptyState: customRenderEmptyState, resizable = false, onColumnResize, reorderable = false, onColumnReorder, virtualized = false, virtualHeight = "600px", virtualRowHeight = 60,
14933
14966
  // Pagination props
14934
14967
  paginated = false, currentPage = 1, pageSize = 10, totalItems, onPageChange, pageSizeOptions = [10, 25, 50, 100], onPageSizeChange, showPageSizeSelector = true,
14935
14968
  // Mobile view props
14936
- mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
14969
+ mobileView = "auto", cardConfig, cardGap = "md", cardClassName, }) {
14937
14970
  // Mobile detection for auto mode
14938
14971
  const isMobileViewport = useIsMobile();
14939
14972
  // Column resizing state
@@ -14952,7 +14985,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
14952
14985
  const [hoveredRowKey, setHoveredRowKey] = React.useState(null);
14953
14986
  // Keyboard navigation state
14954
14987
  const [focusedCell, setFocusedCell] = React.useState(null);
14955
- const [announcement, setAnnouncement] = React.useState('');
14988
+ const [announcement, setAnnouncement] = React.useState("");
14956
14989
  const tableBodyRef = React.useRef(null);
14957
14990
  // Temporary row highlight state (for flash animation)
14958
14991
  const [flashingRows, setFlashingRows] = React.useState(new Set());
@@ -14964,18 +14997,18 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
14964
14997
  item: null,
14965
14998
  });
14966
14999
  // Filter columns based on hiddenColumns
14967
- const baseVisibleColumns = columns.filter(col => !hiddenColumns.includes(String(col.key)));
15000
+ const baseVisibleColumns = columns.filter((col) => !hiddenColumns.includes(String(col.key)));
14968
15001
  // Initialize column order on mount or when columns change
14969
15002
  React.useEffect(() => {
14970
15003
  if (columnOrder.length === 0) {
14971
- setColumnOrder(baseVisibleColumns.map(col => String(col.key)));
15004
+ setColumnOrder(baseVisibleColumns.map((col) => String(col.key)));
14972
15005
  }
14973
15006
  }, [baseVisibleColumns, columnOrder.length]);
14974
15007
  // Handle temporary row highlighting (flash animation)
14975
15008
  React.useEffect(() => {
14976
15009
  if (highlightedRows.length > 0) {
14977
15010
  // Add new highlighted rows to flashing set
14978
- const newFlashingRows = new Set(highlightedRows.map(id => String(id)));
15011
+ const newFlashingRows = new Set(highlightedRows.map((id) => String(id)));
14979
15012
  setFlashingRows(newFlashingRows);
14980
15013
  // Clear any existing timeout
14981
15014
  if (flashTimeoutRef.current) {
@@ -14995,25 +15028,25 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
14995
15028
  // Apply column order
14996
15029
  const visibleColumns = reorderable && columnOrder.length > 0
14997
15030
  ? columnOrder
14998
- .map(key => baseVisibleColumns.find(col => String(col.key) === key))
15031
+ .map((key) => baseVisibleColumns.find((col) => String(col.key) === key))
14999
15032
  .filter((col) => col !== undefined)
15000
15033
  : baseVisibleColumns;
15001
15034
  // Density classes
15002
15035
  const densityClasses = {
15003
15036
  compact: {
15004
- cell: 'px-3 py-1',
15005
- text: 'text-xs',
15006
- header: 'px-3 py-2',
15037
+ cell: "px-3 py-1",
15038
+ text: "text-xs",
15039
+ header: "px-3 py-2",
15007
15040
  },
15008
15041
  normal: {
15009
- cell: 'px-6 py-1.5',
15010
- text: 'text-sm',
15011
- header: 'px-6 py-3',
15042
+ cell: "px-6 py-1.5",
15043
+ text: "text-sm",
15044
+ header: "px-6 py-3",
15012
15045
  },
15013
15046
  comfortable: {
15014
- cell: 'px-6 py-3',
15015
- text: 'text-base',
15016
- header: 'px-6 py-4',
15047
+ cell: "px-6 py-3",
15048
+ text: "text-base",
15049
+ header: "px-6 py-4",
15017
15050
  },
15018
15051
  };
15019
15052
  const currentDensity = densityClasses[density];
@@ -15021,20 +15054,25 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15021
15054
  const getRowKey = keyExtractor || ((row) => String(row.id));
15022
15055
  // Calculate if there are any actions (for keyboard navigation column calculation)
15023
15056
  // This is computed early so it can be used in keyboard handlers
15024
- const hasAnyActions = !!(onEdit || onDelete || actions.length > 0 ||
15025
- expandedRowConfig?.edit || expandedRowConfig?.details ||
15026
- expandedRowConfig?.addRelated?.length || expandedRowConfig?.manageRelated?.length);
15057
+ const hasAnyActions = !!(onEdit ||
15058
+ onDelete ||
15059
+ actions.length > 0 ||
15060
+ expandedRowConfig?.edit ||
15061
+ expandedRowConfig?.details ||
15062
+ expandedRowConfig?.addRelated?.length ||
15063
+ expandedRowConfig?.manageRelated?.length);
15027
15064
  // Get row background class based on striping and highlighting
15028
15065
  const getRowBackgroundClass = (item, index) => {
15029
15066
  const classes = [];
15030
15067
  const rowKey = getRowKey(item);
15031
15068
  // Check for temporary flash highlight (takes priority)
15032
15069
  if (flashingRows.has(rowKey)) {
15033
- classes.push('animate-row-flash');
15070
+ classes.push("animate-row-flash");
15034
15071
  }
15035
15072
  // Check for highlighted row
15036
- else if (highlightedRowId !== undefined && rowKey === String(highlightedRowId)) {
15037
- classes.push('bg-accent-100');
15073
+ else if (highlightedRowId !== undefined &&
15074
+ rowKey === String(highlightedRowId)) {
15075
+ classes.push("bg-accent-100");
15038
15076
  }
15039
15077
  // Check for custom row highlight
15040
15078
  else if (rowHighlight) {
@@ -15046,24 +15084,27 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15046
15084
  // Check for striping
15047
15085
  else if (striped) {
15048
15086
  const isOdd = index % 2 === 0; // 0-indexed, so even index = odd row
15049
- const shouldStripe = striped === true ? isOdd :
15050
- striped === 'odd' ? isOdd :
15051
- striped === 'even' ? !isOdd :
15052
- false;
15087
+ const shouldStripe = striped === true
15088
+ ? isOdd
15089
+ : striped === "odd"
15090
+ ? isOdd
15091
+ : striped === "even"
15092
+ ? !isOdd
15093
+ : false;
15053
15094
  if (shouldStripe) {
15054
- classes.push(stripedColor || 'bg-paper-50');
15095
+ classes.push(stripedColor || "bg-paper-50");
15055
15096
  }
15056
15097
  }
15057
15098
  // Add custom row class
15058
15099
  if (rowClassName) {
15059
- if (typeof rowClassName === 'string') {
15100
+ if (typeof rowClassName === "string") {
15060
15101
  classes.push(rowClassName);
15061
15102
  }
15062
15103
  else {
15063
15104
  classes.push(rowClassName(item, index));
15064
15105
  }
15065
15106
  }
15066
- return classes.join(' ');
15107
+ return classes.join(" ");
15067
15108
  };
15068
15109
  // NEW: Expansion mode state management (for expandedRowConfig)
15069
15110
  const [expansionState, setExpansionState] = React.useState(null);
@@ -15078,12 +15119,12 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15078
15119
  // Column reorder handlers
15079
15120
  const handleDragStart = (e, columnKey) => {
15080
15121
  setDraggingColumn(columnKey);
15081
- e.dataTransfer.effectAllowed = 'move';
15082
- e.dataTransfer.setData('text/html', columnKey);
15122
+ e.dataTransfer.effectAllowed = "move";
15123
+ e.dataTransfer.setData("text/html", columnKey);
15083
15124
  };
15084
15125
  const handleDragOver = (e, columnKey) => {
15085
15126
  e.preventDefault();
15086
- e.dataTransfer.dropEffect = 'move';
15127
+ e.dataTransfer.dropEffect = "move";
15087
15128
  if (draggingColumn && draggingColumn !== columnKey) {
15088
15129
  setDragOverColumn(columnKey);
15089
15130
  }
@@ -15114,7 +15155,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15114
15155
  const handleMouseMove = (e) => {
15115
15156
  const delta = e.clientX - resizeStartX;
15116
15157
  const newWidth = Math.max(50, resizeStartWidth + delta); // Min width 50px
15117
- setColumnWidths(prev => ({
15158
+ setColumnWidths((prev) => ({
15118
15159
  ...prev,
15119
15160
  [resizingColumn]: newWidth,
15120
15161
  }));
@@ -15125,56 +15166,62 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15125
15166
  }
15126
15167
  setResizingColumn(null);
15127
15168
  };
15128
- document.addEventListener('mousemove', handleMouseMove);
15129
- document.addEventListener('mouseup', handleMouseUp);
15169
+ document.addEventListener("mousemove", handleMouseMove);
15170
+ document.addEventListener("mouseup", handleMouseUp);
15130
15171
  return () => {
15131
- document.removeEventListener('mousemove', handleMouseMove);
15132
- document.removeEventListener('mouseup', handleMouseUp);
15172
+ document.removeEventListener("mousemove", handleMouseMove);
15173
+ document.removeEventListener("mouseup", handleMouseUp);
15133
15174
  };
15134
- }, [resizingColumn, resizeStartX, resizeStartWidth, columnWidths, onColumnResize]);
15175
+ }, [
15176
+ resizingColumn,
15177
+ resizeStartX,
15178
+ resizeStartWidth,
15179
+ columnWidths,
15180
+ onColumnResize,
15181
+ ]);
15135
15182
  // Build combined actions: built-in edit/delete + custom actions + expansion mode actions
15136
15183
  const builtInActions = [];
15137
15184
  // Legacy onEdit (still supported)
15138
15185
  if (onEdit) {
15139
15186
  builtInActions.push({
15140
- label: 'Edit',
15187
+ label: "Edit",
15141
15188
  icon: lucideReact.Edit,
15142
15189
  onClick: onEdit,
15143
- variant: 'secondary',
15144
- tooltip: 'Edit item'
15190
+ variant: "secondary",
15191
+ tooltip: "Edit item",
15145
15192
  });
15146
15193
  }
15147
15194
  // NEW: Edit mode from expandedRowConfig
15148
15195
  if (expandedRowConfig?.edit && !onEdit) {
15149
15196
  const editConfig = expandedRowConfig.edit;
15150
15197
  builtInActions.push({
15151
- label: editConfig.menuLabel || 'Edit',
15198
+ label: editConfig.menuLabel || "Edit",
15152
15199
  icon: editConfig.menuIcon || lucideReact.Edit,
15153
15200
  onClick: (item) => {
15154
15201
  const rowKey = getRowKey(item);
15155
- handleExpansionWithMode(rowKey, 'edit');
15202
+ handleExpansionWithMode(rowKey, "edit");
15156
15203
  },
15157
- variant: 'secondary',
15158
- tooltip: 'Edit inline'
15204
+ variant: "secondary",
15205
+ tooltip: "Edit inline",
15159
15206
  });
15160
15207
  }
15161
15208
  // NEW: View details mode from expandedRowConfig
15162
15209
  if (expandedRowConfig?.details) {
15163
15210
  const detailsConfig = expandedRowConfig.details;
15164
15211
  builtInActions.push({
15165
- label: detailsConfig.menuLabel || 'View Details',
15212
+ label: detailsConfig.menuLabel || "View Details",
15166
15213
  icon: detailsConfig.menuIcon,
15167
15214
  onClick: (item) => {
15168
15215
  const rowKey = getRowKey(item);
15169
- handleExpansionWithMode(rowKey, 'details');
15216
+ handleExpansionWithMode(rowKey, "details");
15170
15217
  },
15171
- variant: 'ghost',
15172
- tooltip: 'View details'
15218
+ variant: "ghost",
15219
+ tooltip: "View details",
15173
15220
  });
15174
15221
  }
15175
15222
  // NEW: Add related modes from expandedRowConfig
15176
15223
  if (expandedRowConfig?.addRelated) {
15177
- expandedRowConfig.addRelated.forEach(config => {
15224
+ expandedRowConfig.addRelated.forEach((config) => {
15178
15225
  if (config.showInMenu !== false) {
15179
15226
  builtInActions.push({
15180
15227
  label: config.label,
@@ -15183,15 +15230,15 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15183
15230
  const rowKey = getRowKey(item);
15184
15231
  handleExpansionWithMode(rowKey, `addRelated-${config.key}`);
15185
15232
  },
15186
- variant: 'secondary',
15187
- tooltip: config.label
15233
+ variant: "secondary",
15234
+ tooltip: config.label,
15188
15235
  });
15189
15236
  }
15190
15237
  });
15191
15238
  }
15192
15239
  // NEW: Manage related modes from expandedRowConfig
15193
15240
  if (expandedRowConfig?.manageRelated) {
15194
- expandedRowConfig.manageRelated.forEach(config => {
15241
+ expandedRowConfig.manageRelated.forEach((config) => {
15195
15242
  if (config.showInMenu !== false) {
15196
15243
  builtInActions.push({
15197
15244
  label: config.label,
@@ -15200,8 +15247,8 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15200
15247
  const rowKey = getRowKey(item);
15201
15248
  handleExpansionWithMode(rowKey, `manageRelated-${config.key}`);
15202
15249
  },
15203
- variant: 'ghost',
15204
- tooltip: config.label
15250
+ variant: "ghost",
15251
+ tooltip: config.label,
15205
15252
  });
15206
15253
  }
15207
15254
  });
@@ -15211,11 +15258,11 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15211
15258
  let deleteAction = null;
15212
15259
  if (onDelete) {
15213
15260
  deleteAction = {
15214
- label: 'Delete',
15261
+ label: "Delete",
15215
15262
  icon: lucideReact.Trash,
15216
15263
  onClick: onDelete,
15217
- variant: 'danger',
15218
- tooltip: 'Delete item'
15264
+ variant: "danger",
15265
+ tooltip: "Delete item",
15219
15266
  };
15220
15267
  }
15221
15268
  // Build final actions array with consistent ordering:
@@ -15228,11 +15275,11 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15228
15275
  const allActions = [
15229
15276
  ...builtInActions,
15230
15277
  ...actions,
15231
- ...(deleteAction ? [deleteAction] : [])
15278
+ ...(deleteAction ? [deleteAction] : []),
15232
15279
  ];
15233
15280
  // Convert actions to menu items for context menu
15234
15281
  const convertActionsToMenuItems = (item) => {
15235
- const visibleActions = allActions.filter(action => !action.show || action.show(item));
15282
+ const visibleActions = allActions.filter((action) => !action.show || action.show(item));
15236
15283
  return visibleActions.map((action, idx) => {
15237
15284
  let iconElement = null;
15238
15285
  if (action.icon) {
@@ -15240,7 +15287,9 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15240
15287
  iconElement = action.icon;
15241
15288
  }
15242
15289
  else {
15243
- iconElement = React.createElement(action.icon, { className: 'h-4 w-4' });
15290
+ iconElement = React.createElement(action.icon, {
15291
+ className: "h-4 w-4",
15292
+ });
15244
15293
  }
15245
15294
  }
15246
15295
  return {
@@ -15248,7 +15297,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15248
15297
  label: action.label,
15249
15298
  icon: iconElement,
15250
15299
  onClick: () => action.onClick(item),
15251
- danger: action.variant === 'danger',
15300
+ danger: action.variant === "danger",
15252
15301
  };
15253
15302
  });
15254
15303
  };
@@ -15257,7 +15306,9 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15257
15306
  // Expansion state management
15258
15307
  const [internalExpandedRows, setInternalExpandedRows] = React.useState(new Set());
15259
15308
  // Use external selection if provided, otherwise internal
15260
- const selectedRowsSet = externalSelectedRows !== undefined ? externalSelectedRows : internalSelectedRows;
15309
+ const selectedRowsSet = externalSelectedRows !== undefined
15310
+ ? externalSelectedRows
15311
+ : internalSelectedRows;
15261
15312
  const setSelectedRows = (newSet) => {
15262
15313
  if (externalSelectedRows !== undefined) {
15263
15314
  // Controlled component - notify parent
@@ -15291,7 +15342,9 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15291
15342
  }
15292
15343
  };
15293
15344
  // Use external expansion if provided, otherwise internal
15294
- const expandedRowsSet = externalExpandedRows !== undefined ? externalExpandedRows : internalExpandedRows;
15345
+ const expandedRowsSet = externalExpandedRows !== undefined
15346
+ ? externalExpandedRows
15347
+ : internalExpandedRows;
15295
15348
  const setExpandedRows = (newSet) => {
15296
15349
  if (externalExpandedRows !== undefined) ;
15297
15350
  else {
@@ -15333,10 +15386,10 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15333
15386
  const totalCols = visibleColumns.length;
15334
15387
  // If no cell is focused, focus first data cell on first arrow key
15335
15388
  if (!focusedCell) {
15336
- if (['ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {
15389
+ if (["ArrowDown", "ArrowUp", "ArrowLeft", "ArrowRight"].includes(e.key)) {
15337
15390
  e.preventDefault();
15338
15391
  setFocusedCell({ row: 0, col: 0 });
15339
- const colHeader = visibleColumns[0]?.header || 'first column';
15392
+ const colHeader = visibleColumns[0]?.header || "first column";
15340
15393
  setAnnouncement(`Row 1, ${colHeader}`);
15341
15394
  return;
15342
15395
  }
@@ -15344,73 +15397,73 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15344
15397
  }
15345
15398
  const { row, col } = focusedCell;
15346
15399
  switch (e.key) {
15347
- case 'ArrowDown':
15400
+ case "ArrowDown":
15348
15401
  e.preventDefault();
15349
15402
  if (row < totalRows - 1) {
15350
15403
  const newRow = row + 1;
15351
15404
  setFocusedCell({ row: newRow, col });
15352
15405
  const rowItem = data[newRow];
15353
- const colHeader = visibleColumns[col]?.header || '';
15406
+ const colHeader = visibleColumns[col]?.header || "";
15354
15407
  const cellValue = rowItem[visibleColumns[col]?.key];
15355
- setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue || 'empty'}`);
15408
+ setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue || "empty"}`);
15356
15409
  }
15357
15410
  break;
15358
- case 'ArrowUp':
15411
+ case "ArrowUp":
15359
15412
  e.preventDefault();
15360
15413
  if (row > 0) {
15361
15414
  const newRow = row - 1;
15362
15415
  setFocusedCell({ row: newRow, col });
15363
15416
  const rowItem = data[newRow];
15364
- const colHeader = visibleColumns[col]?.header || '';
15417
+ const colHeader = visibleColumns[col]?.header || "";
15365
15418
  const cellValue = rowItem[visibleColumns[col]?.key];
15366
- setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue || 'empty'}`);
15419
+ setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue || "empty"}`);
15367
15420
  }
15368
15421
  break;
15369
- case 'ArrowRight':
15422
+ case "ArrowRight":
15370
15423
  e.preventDefault();
15371
15424
  if (col < totalCols - 1) {
15372
15425
  const newCol = col + 1;
15373
15426
  setFocusedCell({ row, col: newCol });
15374
15427
  const rowItem = data[row];
15375
- const colHeader = visibleColumns[newCol]?.header || '';
15428
+ const colHeader = visibleColumns[newCol]?.header || "";
15376
15429
  const cellValue = rowItem[visibleColumns[newCol]?.key];
15377
- setAnnouncement(`${colHeader}: ${cellValue || 'empty'}`);
15430
+ setAnnouncement(`${colHeader}: ${cellValue || "empty"}`);
15378
15431
  }
15379
15432
  break;
15380
- case 'ArrowLeft':
15433
+ case "ArrowLeft":
15381
15434
  e.preventDefault();
15382
15435
  if (col > 0) {
15383
15436
  const newCol = col - 1;
15384
15437
  setFocusedCell({ row, col: newCol });
15385
15438
  const rowItem = data[row];
15386
- const colHeader = visibleColumns[newCol]?.header || '';
15439
+ const colHeader = visibleColumns[newCol]?.header || "";
15387
15440
  const cellValue = rowItem[visibleColumns[newCol]?.key];
15388
- setAnnouncement(`${colHeader}: ${cellValue || 'empty'}`);
15441
+ setAnnouncement(`${colHeader}: ${cellValue || "empty"}`);
15389
15442
  }
15390
15443
  break;
15391
- case 'Home':
15444
+ case "Home":
15392
15445
  e.preventDefault();
15393
15446
  if (e.ctrlKey) {
15394
15447
  // Ctrl+Home: Go to first cell
15395
15448
  setFocusedCell({ row: 0, col: 0 });
15396
- setAnnouncement(`First cell, Row 1, ${visibleColumns[0]?.header || ''}`);
15449
+ setAnnouncement(`First cell, Row 1, ${visibleColumns[0]?.header || ""}`);
15397
15450
  }
15398
15451
  else {
15399
15452
  // Home: Go to first cell in current row
15400
15453
  setFocusedCell({ row, col: 0 });
15401
15454
  const rowItem = data[row];
15402
15455
  const cellValue = rowItem[visibleColumns[0]?.key];
15403
- setAnnouncement(`${visibleColumns[0]?.header || ''}: ${cellValue || 'empty'}`);
15456
+ setAnnouncement(`${visibleColumns[0]?.header || ""}: ${cellValue || "empty"}`);
15404
15457
  }
15405
15458
  break;
15406
- case 'End':
15459
+ case "End":
15407
15460
  e.preventDefault();
15408
15461
  if (e.ctrlKey) {
15409
15462
  // Ctrl+End: Go to last cell
15410
15463
  const lastRow = totalRows - 1;
15411
15464
  const lastCol = totalCols - 1;
15412
15465
  setFocusedCell({ row: lastRow, col: lastCol });
15413
- setAnnouncement(`Last cell, Row ${lastRow + 1}, ${visibleColumns[lastCol]?.header || ''}`);
15466
+ setAnnouncement(`Last cell, Row ${lastRow + 1}, ${visibleColumns[lastCol]?.header || ""}`);
15414
15467
  }
15415
15468
  else {
15416
15469
  // End: Go to last cell in current row
@@ -15418,10 +15471,10 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15418
15471
  setFocusedCell({ row, col: lastCol });
15419
15472
  const rowItem = data[row];
15420
15473
  const cellValue = rowItem[visibleColumns[lastCol]?.key];
15421
- setAnnouncement(`${visibleColumns[lastCol]?.header || ''}: ${cellValue || 'empty'}`);
15474
+ setAnnouncement(`${visibleColumns[lastCol]?.header || ""}: ${cellValue || "empty"}`);
15422
15475
  }
15423
15476
  break;
15424
- case 'Enter':
15477
+ case "Enter":
15425
15478
  e.preventDefault();
15426
15479
  {
15427
15480
  const rowItem = data[row];
@@ -15429,27 +15482,27 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15429
15482
  // Priority: Edit mode > Details mode > Row double-click handler
15430
15483
  if (onEdit) {
15431
15484
  onEdit(rowItem);
15432
- setAnnouncement('Opening edit mode');
15485
+ setAnnouncement("Opening edit mode");
15433
15486
  }
15434
15487
  else if (expandedRowConfig?.edit) {
15435
- handleExpansionWithMode(rowKey, 'edit');
15436
- setAnnouncement('Opening inline edit');
15488
+ handleExpansionWithMode(rowKey, "edit");
15489
+ setAnnouncement("Opening inline edit");
15437
15490
  }
15438
15491
  else if (expandedRowConfig?.details) {
15439
- handleExpansionWithMode(rowKey, 'details');
15440
- setAnnouncement('Opening details view');
15492
+ handleExpansionWithMode(rowKey, "details");
15493
+ setAnnouncement("Opening details view");
15441
15494
  }
15442
15495
  else if (onRowDoubleClick) {
15443
15496
  onRowDoubleClick(rowItem);
15444
- setAnnouncement('Activating row');
15497
+ setAnnouncement("Activating row");
15445
15498
  }
15446
15499
  else if (onRowClick) {
15447
15500
  onRowClick(rowItem);
15448
- setAnnouncement('Row selected');
15501
+ setAnnouncement("Row selected");
15449
15502
  }
15450
15503
  }
15451
15504
  break;
15452
- case ' ':
15505
+ case " ":
15453
15506
  // Space: Toggle selection if selectable
15454
15507
  if (selectable) {
15455
15508
  e.preventDefault();
@@ -15457,60 +15510,82 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15457
15510
  const rowKey = getRowKey(rowItem);
15458
15511
  handleRowSelect(rowKey);
15459
15512
  const isNowSelected = !selectedRowsSet.has(rowKey);
15460
- setAnnouncement(isNowSelected ? 'Row selected' : 'Row deselected');
15513
+ setAnnouncement(isNowSelected ? "Row selected" : "Row deselected");
15461
15514
  }
15462
15515
  break;
15463
- case 'Escape':
15516
+ case "Escape":
15464
15517
  e.preventDefault();
15465
15518
  setFocusedCell(null);
15466
- setAnnouncement('Table navigation exited');
15519
+ setAnnouncement("Table navigation exited");
15467
15520
  // Return focus to table container
15468
- tableBodyRef.current?.closest('table')?.focus();
15521
+ tableBodyRef.current?.closest("table")?.focus();
15469
15522
  break;
15470
- case 'PageDown':
15523
+ case "PageDown":
15471
15524
  e.preventDefault();
15472
15525
  {
15473
15526
  const jumpSize = 10;
15474
15527
  const newRow = Math.min(row + jumpSize, totalRows - 1);
15475
15528
  setFocusedCell({ row: newRow, col });
15476
- const colHeader = visibleColumns[col]?.header || '';
15529
+ const colHeader = visibleColumns[col]?.header || "";
15477
15530
  setAnnouncement(`Row ${newRow + 1} of ${totalRows}, ${colHeader}`);
15478
15531
  }
15479
15532
  break;
15480
- case 'PageUp':
15533
+ case "PageUp":
15481
15534
  e.preventDefault();
15482
15535
  {
15483
15536
  const jumpSize = 10;
15484
15537
  const newRow = Math.max(row - jumpSize, 0);
15485
15538
  setFocusedCell({ row: newRow, col });
15486
- const colHeader = visibleColumns[col]?.header || '';
15539
+ const colHeader = visibleColumns[col]?.header || "";
15487
15540
  setAnnouncement(`Row ${newRow + 1} of ${totalRows}, ${colHeader}`);
15488
15541
  }
15489
15542
  break;
15490
15543
  }
15491
- }, [data, visibleColumns, focusedCell, selectable, expandedRowConfig, onEdit, onRowDoubleClick, onRowClick, getRowKey, handleExpansionWithMode, handleRowSelect, selectedRowsSet]);
15544
+ }, [
15545
+ data,
15546
+ visibleColumns,
15547
+ focusedCell,
15548
+ selectable,
15549
+ expandedRowConfig,
15550
+ onEdit,
15551
+ onRowDoubleClick,
15552
+ onRowClick,
15553
+ getRowKey,
15554
+ handleExpansionWithMode,
15555
+ handleRowSelect,
15556
+ selectedRowsSet,
15557
+ ]);
15492
15558
  // Focus the appropriate cell when focusedCell changes
15493
15559
  React.useEffect(() => {
15494
15560
  if (focusedCell && tableBodyRef.current) {
15495
15561
  const { row, col } = focusedCell;
15496
- const rows = tableBodyRef.current.querySelectorAll('tr[data-row-index]');
15562
+ const rows = tableBodyRef.current.querySelectorAll("tr[data-row-index]");
15497
15563
  const targetRow = rows[row];
15498
15564
  if (targetRow) {
15499
15565
  // Calculate actual column index including extra columns
15500
15566
  const hasSelectionCol = selectable;
15501
15567
  const hasExpandCol = (expandable || expandedRowConfig) && showExpandChevron;
15502
15568
  const hasActionsCol = hasAnyActions;
15503
- const extraColsBefore = (hasSelectionCol ? 1 : 0) + (hasExpandCol ? 1 : 0) + (hasActionsCol ? 1 : 0);
15504
- const cells = targetRow.querySelectorAll('td');
15569
+ const extraColsBefore = (hasSelectionCol ? 1 : 0) +
15570
+ (hasExpandCol ? 1 : 0) +
15571
+ (hasActionsCol ? 1 : 0);
15572
+ const cells = targetRow.querySelectorAll("td");
15505
15573
  const targetCell = cells[col + extraColsBefore];
15506
15574
  if (targetCell) {
15507
15575
  targetCell.focus();
15508
15576
  // Scroll into view if needed
15509
- targetCell.scrollIntoView({ block: 'nearest', inline: 'nearest' });
15577
+ targetCell.scrollIntoView({ block: "nearest", inline: "nearest" });
15510
15578
  }
15511
15579
  }
15512
15580
  }
15513
- }, [focusedCell, selectable, expandable, expandedRowConfig, showExpandChevron, hasAnyActions]);
15581
+ }, [
15582
+ focusedCell,
15583
+ selectable,
15584
+ expandable,
15585
+ expandedRowConfig,
15586
+ showExpandChevron,
15587
+ hasAnyActions,
15588
+ ]);
15514
15589
  // Handle column header click for sorting
15515
15590
  const handleSort = (column) => {
15516
15591
  if (!column.sortable || !onSortChange)
@@ -15518,8 +15593,12 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15518
15593
  const columnKey = String(column.key);
15519
15594
  // If clicking the same column, toggle direction
15520
15595
  if (currentSort?.key === columnKey) {
15521
- if (currentSort.direction === 'asc') {
15522
- onSortChange({ key: columnKey, direction: 'desc', label: column.header });
15596
+ if (currentSort.direction === "asc") {
15597
+ onSortChange({
15598
+ key: columnKey,
15599
+ direction: "desc",
15600
+ label: column.header,
15601
+ });
15523
15602
  }
15524
15603
  else {
15525
15604
  // Remove sort on third click
@@ -15528,7 +15607,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15528
15607
  }
15529
15608
  else {
15530
15609
  // New column - start with ascending
15531
- onSortChange({ key: columnKey, direction: 'asc', label: column.header });
15610
+ onSortChange({ key: columnKey, direction: "asc", label: column.header });
15532
15611
  }
15533
15612
  };
15534
15613
  // Get sort icon SVG for column (matches reference ui-preview.html)
@@ -15537,7 +15616,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15537
15616
  return null;
15538
15617
  const columnKey = String(column.key);
15539
15618
  const isActive = currentSort?.key === columnKey;
15540
- const isAscending = currentSort?.direction === 'asc';
15619
+ const isAscending = currentSort?.direction === "asc";
15541
15620
  // Inactive state - show neutral up/down arrows
15542
15621
  if (!isActive) {
15543
15622
  return (jsxRuntime.jsx("svg", { className: "ml-2 w-4 h-4 text-ink-400 group-hover:text-ink-700", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4" }) }));
@@ -15550,17 +15629,23 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15550
15629
  return (jsxRuntime.jsx("svg", { className: "ml-2 w-4 h-4 text-accent-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M16 17l-4 4m0 0l-4-4m4 4V3" }) }));
15551
15630
  };
15552
15631
  // Render loading skeleton
15553
- const renderLoadingSkeleton = () => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: loadingRows }, (_, i) => (jsxRuntime.jsxs("tr", { className: `animate-pulse table-row-stable ${bordered ? `border-b ${borderColor}` : ''}`, children: [selectable && (jsxRuntime.jsx("td", { className: `sticky left-0 bg-white ${currentDensity.cell} border-b ${borderColor} z-10 align-middle`, children: jsxRuntime.jsx("div", { className: "h-4 w-4 bg-paper-200 rounded" }) })), expandable && (jsxRuntime.jsx("td", { className: `sticky left-0 bg-white px-2 ${currentDensity.cell} border-b ${borderColor} z-10`, children: jsxRuntime.jsx("div", { className: "h-4 w-4 bg-paper-200 rounded" }) })), allActions.length > 0 && (jsxRuntime.jsx("td", { className: `sticky left-0 bg-white px-2 ${currentDensity.cell} border-b ${borderColor} z-10`, children: jsxRuntime.jsx("div", { className: "h-8 w-8 bg-paper-200 rounded" }) })), visibleColumns.map((column, colIndex) => {
15632
+ const renderLoadingSkeleton = () => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: loadingRows }, (_, i) => (jsxRuntime.jsxs("tr", { className: `animate-pulse table-row-stable ${bordered ? `border-b ${borderColor}` : ""}`, children: [selectable && (jsxRuntime.jsx("td", { className: `sticky left-0 bg-white ${currentDensity.cell} border-b ${borderColor} z-10 align-middle`, children: jsxRuntime.jsx("div", { className: "h-4 w-4 bg-paper-200 rounded" }) })), expandable && (jsxRuntime.jsx("td", { className: `sticky left-0 bg-white px-2 ${currentDensity.cell} border-b ${borderColor} z-10`, children: jsxRuntime.jsx("div", { className: "h-4 w-4 bg-paper-200 rounded" }) })), allActions.length > 0 && (jsxRuntime.jsx("td", { className: `sticky left-0 bg-white px-2 ${currentDensity.cell} border-b ${borderColor} z-10`, children: jsxRuntime.jsx("div", { className: "h-8 w-8 bg-paper-200 rounded" }) })), visibleColumns.map((column, colIndex) => {
15554
15633
  const columnKey = String(column.key);
15555
15634
  const dynamicWidth = columnWidths[columnKey];
15556
- return (jsxRuntime.jsxs("td", { className: `${currentDensity.cell} whitespace-nowrap table-row-stable ${bordered ? `border ${borderColor}` : ''}`, style: getColumnStyle(column, dynamicWidth), children: [jsxRuntime.jsx("div", { className: "h-4 bg-paper-200 rounded mb-1" }), jsxRuntime.jsx("div", { className: "h-3 bg-paper-200 rounded w-3/4" })] }, `loading-${i}-${colIndex}`));
15635
+ return (jsxRuntime.jsxs("td", { className: `${currentDensity.cell} whitespace-nowrap table-row-stable ${bordered ? `border ${borderColor}` : ""}`, style: getColumnStyle(column, dynamicWidth), children: [jsxRuntime.jsx("div", { className: "h-4 bg-paper-200 rounded mb-1" }), jsxRuntime.jsx("div", { className: "h-3 bg-paper-200 rounded w-3/4" })] }, `loading-${i}-${colIndex}`));
15557
15636
  })] }, `loading-${i}`))) }));
15558
15637
  // Render empty state
15559
15638
  const renderEmptyStateContent = () => {
15560
15639
  if (customRenderEmptyState) {
15561
- return (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: visibleColumns.length + (allActions.length > 0 ? 1 : 0) + (selectable ? 1 : 0) + (expandable ? 1 : 0), children: customRenderEmptyState() }) }));
15640
+ return (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: visibleColumns.length +
15641
+ (allActions.length > 0 ? 1 : 0) +
15642
+ (selectable ? 1 : 0) +
15643
+ (expandable ? 1 : 0), children: customRenderEmptyState() }) }));
15562
15644
  }
15563
- return (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: visibleColumns.length + (allActions.length > 0 ? 1 : 0) + (selectable ? 1 : 0) + (expandable ? 1 : 0), className: `${currentDensity.cell} py-8 text-center text-ink-500`, children: error || emptyMessage }) }));
15645
+ return (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: visibleColumns.length +
15646
+ (allActions.length > 0 ? 1 : 0) +
15647
+ (selectable ? 1 : 0) +
15648
+ (expandable ? 1 : 0), className: `${currentDensity.cell} py-8 text-center text-ink-500`, children: error || emptyMessage }) }));
15564
15649
  };
15565
15650
  // Virtual scrolling calculations
15566
15651
  const getVisibleRange = () => {
@@ -15590,14 +15675,18 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15590
15675
  const isSelected = selectedRowsSet.has(rowKey);
15591
15676
  const isExpanded = expandedRowsSet.has(rowKey);
15592
15677
  const rowBgClass = getRowBackgroundClass(item, index);
15593
- const borderClass = bordered ? `border-b ${borderColor}` : (!visibleColumns.some(col => !!col.renderSecondary) ? `border-b ${borderColor}` : '');
15594
- const hasSecondaryRow = visibleColumns.some(col => !!col.renderSecondary);
15678
+ const borderClass = bordered
15679
+ ? `border-b ${borderColor}`
15680
+ : !visibleColumns.some((col) => !!col.renderSecondary)
15681
+ ? `border-b ${borderColor}`
15682
+ : "";
15683
+ const hasSecondaryRow = visibleColumns.some((col) => !!col.renderSecondary);
15595
15684
  // Hover state for row pair (primary + secondary)
15596
15685
  const isHovered = hoveredRowKey === rowKey;
15597
- const hoverClass = disableHover ? '' : (isHovered ? 'bg-paper-100' : '');
15686
+ const hoverClass = disableHover ? "" : isHovered ? "bg-paper-100" : "";
15598
15687
  // Check if this row is keyboard-focused
15599
15688
  const isKeyboardFocused = focusedCell?.row === index;
15600
- return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsxs("tr", { "data-row-index": index, className: `table-row-stable ${onRowDoubleClick || onRowClick || onEdit || expandedRowConfig?.edit || expandedRowConfig?.details || expandedRowConfig?.addRelated?.length || expandedRowConfig?.manageRelated?.length ? 'cursor-pointer' : ''} ${isSelected ? 'bg-accent-50 border-l-2 border-accent-500' : hoverClass || rowBgClass} ${borderClass} ${isKeyboardFocused ? 'ring-2 ring-inset ring-accent-400' : ''}`, onMouseEnter: () => !disableHover && setHoveredRowKey(rowKey), onMouseLeave: () => !disableHover && setHoveredRowKey(null), onClick: () => onRowClick?.(item), onContextMenu: (e) => {
15689
+ return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsxs("tr", { "data-row-index": index, className: `table-row-stable ${onRowDoubleClick || onRowClick || onEdit || expandedRowConfig?.edit || expandedRowConfig?.details || expandedRowConfig?.addRelated?.length || expandedRowConfig?.manageRelated?.length ? "cursor-pointer" : ""} ${isSelected ? "bg-accent-50 border-l-2 border-accent-500" : hoverClass || rowBgClass} ${borderClass} ${isKeyboardFocused ? "ring-2 ring-inset ring-accent-400" : ""}`, onMouseEnter: () => !disableHover && setHoveredRowKey(rowKey), onMouseLeave: () => !disableHover && setHoveredRowKey(null), onClick: () => onRowClick?.(item), onContextMenu: (e) => {
15601
15690
  if (enableContextMenu && allActions.length > 0) {
15602
15691
  e.preventDefault();
15603
15692
  e.stopPropagation();
@@ -15616,109 +15705,146 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15616
15705
  }
15617
15706
  // Priority 2: If there's an expandable edit mode, trigger it
15618
15707
  else if (expandedRowConfig?.edit) {
15619
- handleExpansionWithMode(rowKey, 'edit');
15708
+ handleExpansionWithMode(rowKey, "edit");
15620
15709
  }
15621
15710
  // Priority 3: If there's an expandable details mode, trigger it
15622
15711
  else if (expandedRowConfig?.details) {
15623
- handleExpansionWithMode(rowKey, 'details');
15712
+ handleExpansionWithMode(rowKey, "details");
15624
15713
  }
15625
15714
  // Priority 4: If there's any addRelated mode, trigger the first one
15626
- else if (expandedRowConfig?.addRelated && expandedRowConfig.addRelated.length > 0) {
15715
+ else if (expandedRowConfig?.addRelated &&
15716
+ expandedRowConfig.addRelated.length > 0) {
15627
15717
  handleExpansionWithMode(rowKey, `addRelated-${expandedRowConfig.addRelated[0].key}`);
15628
15718
  }
15629
15719
  // Priority 5: If there's any manageRelated mode, trigger the first one
15630
- else if (expandedRowConfig?.manageRelated && expandedRowConfig.manageRelated.length > 0) {
15720
+ else if (expandedRowConfig?.manageRelated &&
15721
+ expandedRowConfig.manageRelated.length > 0) {
15631
15722
  handleExpansionWithMode(rowKey, `manageRelated-${expandedRowConfig.manageRelated[0].key}`);
15632
15723
  }
15633
15724
  // Priority 6: Legacy onRowDoubleClick handler
15634
15725
  else {
15635
15726
  onRowDoubleClick?.(item);
15636
15727
  }
15637
- }, title: onEdit ? 'Double-click to edit' :
15638
- expandedRowConfig?.edit ? 'Double-click to edit inline' :
15639
- expandedRowConfig?.details ? 'Double-click to view details' :
15640
- expandedRowConfig?.addRelated && expandedRowConfig.addRelated.length > 0 ? `Double-click to ${expandedRowConfig.addRelated[0].label}` :
15641
- expandedRowConfig?.manageRelated && expandedRowConfig.manageRelated.length > 0 ? `Double-click to ${expandedRowConfig.manageRelated[0].label}` :
15642
- onRowDoubleClick ? 'Double-click for details' :
15643
- onRowClick ? 'Click to select' :
15644
- undefined, children: [selectable && (jsxRuntime.jsx("td", { className: `sticky left-0 z-10 ${bordered ? `border ${borderColor}` : ''}`, style: {
15645
- backgroundColor: 'inherit',
15646
- verticalAlign: 'middle',
15647
- padding: '0.375rem 0.75rem',
15648
- textAlign: 'center'
15649
- }, rowSpan: hasSecondaryRow ? 2 : 1, children: jsxRuntime.jsx("input", { type: "checkbox", checked: isSelected, onChange: () => handleRowSelect(rowKey), className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": `Select row ${rowKey}` }) })), ((expandable || expandedRowConfig) && showExpandChevron) && (jsxRuntime.jsx("td", { className: `sticky left-0 px-2 ${currentDensity.cell} z-10 ${bordered ? `border ${borderColor}` : ''}`, style: { backgroundColor: 'inherit', verticalAlign: 'middle' }, rowSpan: hasSecondaryRow ? 2 : 1, children: jsxRuntime.jsx("button", { onClick: () => {
15728
+ }, title: onEdit
15729
+ ? "Double-click to edit"
15730
+ : expandedRowConfig?.edit
15731
+ ? "Double-click to edit inline"
15732
+ : expandedRowConfig?.details
15733
+ ? "Double-click to view details"
15734
+ : expandedRowConfig?.addRelated &&
15735
+ expandedRowConfig.addRelated.length > 0
15736
+ ? `Double-click to ${expandedRowConfig.addRelated[0].label}`
15737
+ : expandedRowConfig?.manageRelated &&
15738
+ expandedRowConfig.manageRelated.length > 0
15739
+ ? `Double-click to ${expandedRowConfig.manageRelated[0].label}`
15740
+ : onRowDoubleClick
15741
+ ? "Double-click for details"
15742
+ : onRowClick
15743
+ ? "Click to select"
15744
+ : undefined, children: [selectable && (jsxRuntime.jsx("td", { className: `sticky left-0 z-10 ${bordered ? `border ${borderColor}` : ""}`, style: {
15745
+ backgroundColor: "inherit",
15746
+ verticalAlign: "middle",
15747
+ padding: "0.375rem 0.75rem",
15748
+ textAlign: "center",
15749
+ }, rowSpan: hasSecondaryRow ? 2 : 1, children: jsxRuntime.jsx("input", { type: "checkbox", checked: isSelected, onChange: () => handleRowSelect(rowKey), className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": `Select row ${rowKey}` }) })), (expandable || expandedRowConfig) && showExpandChevron && (jsxRuntime.jsx("td", { className: `sticky left-0 px-2 ${currentDensity.cell} z-10 ${bordered ? `border ${borderColor}` : ""}`, style: { backgroundColor: "inherit", verticalAlign: "middle" }, rowSpan: hasSecondaryRow ? 2 : 1, children: jsxRuntime.jsx("button", { onClick: () => {
15650
15750
  // NEW: Enhanced logic for expandedRowConfig
15651
- if (expandedRowConfig?.details && expandedRowConfig.details.triggerOnExpand !== false) {
15751
+ if (expandedRowConfig?.details &&
15752
+ expandedRowConfig.details.triggerOnExpand !== false) {
15652
15753
  // Trigger details mode if configured
15653
- handleExpansionWithMode(rowKey, 'details');
15754
+ handleExpansionWithMode(rowKey, "details");
15654
15755
  }
15655
- else if (expandedRowConfig?.edit && expandedRowConfig.edit.triggerOnDoubleClick !== false) {
15756
+ else if (expandedRowConfig?.edit &&
15757
+ expandedRowConfig.edit.triggerOnDoubleClick !== false) {
15656
15758
  // Fallback to edit mode if no details but edit is available
15657
- handleExpansionWithMode(rowKey, 'edit');
15759
+ handleExpansionWithMode(rowKey, "edit");
15658
15760
  }
15659
15761
  else {
15660
15762
  // Legacy: use handleRowExpand
15661
15763
  handleRowExpand(rowKey);
15662
15764
  }
15663
- }, className: "text-ink-500 hover:text-ink-900 transition-colors", "aria-label": isExpanded || (expansionState?.rowKey === rowKey) ? 'Collapse row' : 'Expand row', children: isExpanded || (expansionState?.rowKey === rowKey) ? (jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4" })) : (jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })) }) })), allActions.length > 0 && (jsxRuntime.jsx("td", { className: "sticky left-0 whitespace-nowrap shadow-[4px_0_6px_-2px_rgba(0,0,0,0.1)] z-10", style: {
15664
- width: '28px',
15665
- padding: '0',
15666
- backgroundColor: 'inherit',
15667
- verticalAlign: 'middle'
15668
- }, onClick: (e) => e.stopPropagation(), rowSpan: hasSecondaryRow ? 2 : 1, children: jsxRuntime.jsx("div", { style: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: '28px' }, children: jsxRuntime.jsx(ActionMenu, { actions: allActions, item: item }) }) })), visibleColumns.map((column, colIdx) => {
15765
+ }, className: "text-ink-500 hover:text-ink-900 transition-colors", "aria-label": isExpanded || expansionState?.rowKey === rowKey
15766
+ ? "Collapse row"
15767
+ : "Expand row", children: isExpanded || expansionState?.rowKey === rowKey ? (jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4" })) : (jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })) }) })), allActions.length > 0 && (jsxRuntime.jsx("td", { className: "sticky left-0 whitespace-nowrap shadow-[4px_0_6px_-2px_rgba(0,0,0,0.1)] z-10", style: {
15768
+ width: "28px",
15769
+ padding: "0",
15770
+ backgroundColor: "inherit",
15771
+ verticalAlign: "middle",
15772
+ }, onClick: (e) => e.stopPropagation(), rowSpan: hasSecondaryRow ? 2 : 1, children: jsxRuntime.jsx("div", { style: {
15773
+ display: "inline-flex",
15774
+ alignItems: "center",
15775
+ justifyContent: "center",
15776
+ width: "28px",
15777
+ }, children: jsxRuntime.jsx(ActionMenu, { actions: allActions, item: item }) }) })), visibleColumns.map((column, colIdx) => {
15669
15778
  const columnKey = String(column.key);
15670
15779
  const dynamicWidth = columnWidths[columnKey];
15671
- const value = typeof column.key === 'string'
15780
+ const value = typeof column.key === "string"
15672
15781
  ? item[column.key]
15673
15782
  : item[column.key];
15674
- const primaryContent = column.render ? column.render(item, value) : String(value || '');
15783
+ const primaryContent = column.render
15784
+ ? column.render(item, value)
15785
+ : String(value || "");
15786
+ // Tooltip: caller-provided > raw value stringified. Empty
15787
+ // strings get dropped so we don't render an empty title
15788
+ // attribute (which the browser would still show as a
15789
+ // 0-width tooltip box on hover).
15790
+ const primaryTooltipText = column.tooltip
15791
+ ? column.tooltip(item, value)
15792
+ : value !== null && value !== undefined && value !== ""
15793
+ ? String(value)
15794
+ : undefined;
15675
15795
  // Reduce left padding on first column when there are action buttons
15676
15796
  const isFirstColumn = colIdx === 0;
15677
- const paddingClass = isFirstColumn && allActions.length > 0 ? 'pl-3' : '';
15797
+ const paddingClass = isFirstColumn && allActions.length > 0 ? "pl-3" : "";
15678
15798
  // Check if this cell is keyboard-focused
15679
15799
  const isCellFocused = focusedCell?.row === index && focusedCell?.col === colIdx;
15680
- return (jsxRuntime.jsx("td", { className: `${currentDensity.cell} ${paddingClass} ${column.className || ''} ${bordered ? `border ${borderColor}` : ''} ${isCellFocused ? 'outline outline-2 outline-accent-500 outline-offset-[-2px]' : ''}`, style: getColumnStyle(column, dynamicWidth), tabIndex: isCellFocused ? 0 : -1, role: "gridcell", "aria-colindex": colIdx + 1, children: jsxRuntime.jsx("div", { className: `${currentDensity.text} leading-tight`, children: primaryContent }) }, `${item.id}-${columnKey}`));
15681
- })] }), hasSecondaryRow && (jsxRuntime.jsx("tr", { className: `secondary-row ${isSelected ? 'bg-accent-50 border-l-2 border-accent-500' : hoverClass || rowBgClass} border-b ${borderColor}`, onMouseEnter: () => !disableHover && setHoveredRowKey(rowKey), onMouseLeave: () => !disableHover && setHoveredRowKey(null), children: visibleColumns.map((column, colIdx) => {
15800
+ return (jsxRuntime.jsx("td", { className: `${currentDensity.cell} ${paddingClass} ${column.className || ""} ${bordered ? `border ${borderColor}` : ""} ${isCellFocused ? "outline outline-2 outline-accent-500 outline-offset-[-2px]" : ""}`, style: getColumnStyle(column, dynamicWidth), tabIndex: isCellFocused ? 0 : -1, role: "gridcell", "aria-colindex": colIdx + 1, children: jsxRuntime.jsx("div", { className: `${currentDensity.text} leading-tight`, title: primaryTooltipText, children: primaryContent }) }, `${item.id}-${columnKey}`));
15801
+ })] }), hasSecondaryRow && (jsxRuntime.jsx("tr", { className: `secondary-row ${isSelected ? "bg-accent-50 border-l-2 border-accent-500" : hoverClass || rowBgClass} border-b ${borderColor}`, onMouseEnter: () => !disableHover && setHoveredRowKey(rowKey), onMouseLeave: () => !disableHover && setHoveredRowKey(null), children: visibleColumns.map((column, colIdx) => {
15682
15802
  const columnKey = String(column.key);
15683
15803
  const dynamicWidth = columnWidths[columnKey];
15684
- const value = typeof column.key === 'string'
15804
+ const value = typeof column.key === "string"
15685
15805
  ? item[column.key]
15686
15806
  : item[column.key];
15687
- const secondaryContent = column.renderSecondary ? column.renderSecondary(item, value) : null;
15807
+ const secondaryContent = column.renderSecondary
15808
+ ? column.renderSecondary(item, value)
15809
+ : null;
15810
+ // Tooltip on the secondary row prefixes the field label when
15811
+ // available so the otherwise-unlabeled second row stays
15812
+ // self-describing on hover. Caller can override entirely
15813
+ // via `secondaryTooltip`.
15814
+ const hasSecondaryValue = value !== null && value !== undefined && value !== "";
15815
+ let secondaryTooltipText;
15816
+ if (column.secondaryTooltip) {
15817
+ secondaryTooltipText = column.secondaryTooltip(item, value);
15818
+ }
15819
+ else if (hasSecondaryValue) {
15820
+ secondaryTooltipText = column.secondaryHeader
15821
+ ? `${column.secondaryHeader}: ${value}`
15822
+ : String(value);
15823
+ }
15824
+ else if (column.secondaryHeader) {
15825
+ secondaryTooltipText = column.secondaryHeader;
15826
+ }
15688
15827
  // Reduce left padding on first column when there are action buttons
15689
15828
  const isFirstColumn = colIdx === 0;
15690
- const paddingClass = isFirstColumn && allActions.length > 0 ? 'pl-3' : '';
15691
- return (jsxRuntime.jsx("td", { className: `${currentDensity.cell} py-0.5 ${paddingClass} ${column.className || ''} ${bordered ? `border ${borderColor}` : ''}`, style: getColumnStyle(column, dynamicWidth), children: jsxRuntime.jsx("div", { className: "text-xs text-ink-500 leading-tight", children: secondaryContent || jsxRuntime.jsx("span", { className: "invisible", children: "\u2014" }) }) }, `${item.id}-${columnKey}-secondary`));
15829
+ const paddingClass = isFirstColumn && allActions.length > 0 ? "pl-3" : "";
15830
+ return (jsxRuntime.jsx("td", { className: `${currentDensity.cell} py-0.5 ${paddingClass} ${column.className || ""} ${bordered ? `border ${borderColor}` : ""}`, style: getColumnStyle(column, dynamicWidth), children: jsxRuntime.jsx("div", { className: "text-xs text-ink-500 leading-tight", title: secondaryTooltipText, children: secondaryContent || jsxRuntime.jsx("span", { className: "invisible", children: "\u2014" }) }) }, `${item.id}-${columnKey}-secondary`));
15692
15831
  }) })), expandable && isExpanded && renderExpandedRow && (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: visibleColumns.length +
15693
15832
  (selectable ? 1 : 0) +
15694
- (((expandable || expandedRowConfig) && showExpandChevron) ? 1 : 0) +
15695
- (allActions.length > 0 ? 1 : 0), className: `${currentDensity.cell} py-4 bg-paper-50`, children: renderExpandedRow(item) }) })), expansionState && expansionState.rowKey === rowKey && expandedRowConfig && (() => {
15696
- const mode = expansionState.mode;
15697
- let content = null;
15698
- let bgColorClass = 'bg-paper-50'; // Default
15699
- // Edit mode
15700
- if (mode === 'edit' && expandedRowConfig.edit) {
15701
- bgColorClass = 'bg-paper-100/80 border-t border-b border-paper-300/80';
15702
- content = expandedRowConfig.edit.render(item, async (_updated) => {
15703
- // Handle save
15704
- handleCollapseExpansion();
15705
- }, () => {
15706
- // Handle cancel
15707
- handleCollapseExpansion();
15708
- });
15709
- }
15710
- // Details mode
15711
- else if (mode === 'details' && expandedRowConfig.details) {
15712
- bgColorClass = 'bg-primary-50/80 border-t border-b border-primary-200/80';
15713
- content = expandedRowConfig.details.render(item);
15714
- }
15715
- // Add related modes
15716
- else if (mode.startsWith('addRelated-') && expandedRowConfig.addRelated) {
15717
- const key = mode.replace('addRelated-', '');
15718
- const config = expandedRowConfig.addRelated.find(c => c.key === key);
15719
- if (config) {
15720
- bgColorClass = 'bg-success-50/80 border-t border-b border-success-200/80';
15721
- content = config.render(item, async (_newItem) => {
15833
+ ((expandable || expandedRowConfig) && showExpandChevron
15834
+ ? 1
15835
+ : 0) +
15836
+ (allActions.length > 0 ? 1 : 0), className: `${currentDensity.cell} py-4 bg-paper-50`, children: renderExpandedRow(item) }) })), expansionState &&
15837
+ expansionState.rowKey === rowKey &&
15838
+ expandedRowConfig &&
15839
+ (() => {
15840
+ const mode = expansionState.mode;
15841
+ let content = null;
15842
+ let bgColorClass = "bg-paper-50"; // Default
15843
+ // Edit mode
15844
+ if (mode === "edit" && expandedRowConfig.edit) {
15845
+ bgColorClass =
15846
+ "bg-paper-100/80 border-t border-b border-paper-300/80";
15847
+ content = expandedRowConfig.edit.render(item, async (_updated) => {
15722
15848
  // Handle save
15723
15849
  handleCollapseExpansion();
15724
15850
  }, () => {
@@ -15726,31 +15852,57 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15726
15852
  handleCollapseExpansion();
15727
15853
  });
15728
15854
  }
15729
- }
15730
- // Manage related modes
15731
- else if (mode.startsWith('manageRelated-') && expandedRowConfig.manageRelated) {
15732
- const key = mode.replace('manageRelated-', '');
15733
- const config = expandedRowConfig.manageRelated.find(c => c.key === key);
15734
- if (config) {
15735
- bgColorClass = 'bg-slate-50/80 border-t border-b border-slate-200/80';
15736
- const handleClose = () => setExpansionState(null);
15737
- content = config.render(item, handleClose);
15855
+ // Details mode
15856
+ else if (mode === "details" && expandedRowConfig.details) {
15857
+ bgColorClass =
15858
+ "bg-primary-50/80 border-t border-b border-primary-200/80";
15859
+ content = expandedRowConfig.details.render(item);
15738
15860
  }
15739
- }
15740
- if (!content)
15741
- return null;
15742
- return (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: visibleColumns.length +
15743
- (selectable ? 1 : 0) +
15744
- (((expandable || expandedRowConfig) && showExpandChevron) ? 1 : 0) +
15745
- (allActions.length > 0 ? 1 : 0), className: `${currentDensity.cell} py-4 ${bgColorClass} animate-expand`, children: content }) }, `expanded-${rowKey}`));
15746
- })()] }, rowKey));
15861
+ // Add related modes
15862
+ else if (mode.startsWith("addRelated-") &&
15863
+ expandedRowConfig.addRelated) {
15864
+ const key = mode.replace("addRelated-", "");
15865
+ const config = expandedRowConfig.addRelated.find((c) => c.key === key);
15866
+ if (config) {
15867
+ bgColorClass =
15868
+ "bg-success-50/80 border-t border-b border-success-200/80";
15869
+ content = config.render(item, async (_newItem) => {
15870
+ // Handle save
15871
+ handleCollapseExpansion();
15872
+ }, () => {
15873
+ // Handle cancel
15874
+ handleCollapseExpansion();
15875
+ });
15876
+ }
15877
+ }
15878
+ // Manage related modes
15879
+ else if (mode.startsWith("manageRelated-") &&
15880
+ expandedRowConfig.manageRelated) {
15881
+ const key = mode.replace("manageRelated-", "");
15882
+ const config = expandedRowConfig.manageRelated.find((c) => c.key === key);
15883
+ if (config) {
15884
+ bgColorClass =
15885
+ "bg-slate-50/80 border-t border-b border-slate-200/80";
15886
+ const handleClose = () => setExpansionState(null);
15887
+ content = config.render(item, handleClose);
15888
+ }
15889
+ }
15890
+ if (!content)
15891
+ return null;
15892
+ return (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: visibleColumns.length +
15893
+ (selectable ? 1 : 0) +
15894
+ ((expandable || expandedRowConfig) && showExpandChevron
15895
+ ? 1
15896
+ : 0) +
15897
+ (allActions.length > 0 ? 1 : 0), className: `${currentDensity.cell} py-4 ${bgColorClass} animate-expand`, children: content }) }, `expanded-${rowKey}`));
15898
+ })()] }, rowKey));
15747
15899
  });
15748
15900
  };
15749
- const tableContent = (jsxRuntime.jsxs("div", { className: `bg-white rounded-lg shadow border-2 ${borderColor} ${virtualized ? 'overflow-hidden' : 'overflow-x-auto overflow-y-visible'} ${className}`, style: { position: 'relative' }, children: [loading && data.length > 0 && (jsxRuntime.jsx("div", { className: "absolute inset-0 bg-white/75 flex items-center justify-center z-20", style: { backdropFilter: 'blur(2px)' }, children: jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-3", children: [jsxRuntime.jsx("div", { className: "loading-spinner", style: { width: '32px', height: '32px', borderWidth: '3px' } }), jsxRuntime.jsx("span", { className: "text-sm font-medium text-ink-600", children: "Loading..." })] }) })), jsxRuntime.jsxs("table", { className: `table-stable w-full ${bordered ? 'border-collapse' : ''}`, role: "grid", "aria-label": "Data table", "aria-rowcount": data.length, "aria-colcount": visibleColumns.length, children: [jsxRuntime.jsxs("colgroup", { children: [selectable && jsxRuntime.jsx("col", { className: "w-12" }), ((expandable || expandedRowConfig) && showExpandChevron) && jsxRuntime.jsx("col", { className: "w-10" }), allActions.length > 0 && jsxRuntime.jsx("col", { style: { width: '28px' } }), visibleColumns.map((column, index) => {
15901
+ const tableContent = (jsxRuntime.jsxs("div", { className: `bg-white rounded-lg shadow border-2 ${borderColor} ${virtualized ? "overflow-hidden" : "overflow-x-auto overflow-y-visible"} ${className}`, style: { position: "relative" }, children: [loading && data.length > 0 && (jsxRuntime.jsx("div", { className: "absolute inset-0 bg-white/75 flex items-center justify-center z-20", style: { backdropFilter: "blur(2px)" }, children: jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-3", children: [jsxRuntime.jsx("div", { className: "loading-spinner", style: { width: "32px", height: "32px", borderWidth: "3px" } }), jsxRuntime.jsx("span", { className: "text-sm font-medium text-ink-600", children: "Loading..." })] }) })), jsxRuntime.jsxs("table", { className: `table-stable w-full ${bordered ? "border-collapse" : ""}`, role: "grid", "aria-label": "Data table", "aria-rowcount": data.length, "aria-colcount": visibleColumns.length, children: [jsxRuntime.jsxs("colgroup", { children: [selectable && jsxRuntime.jsx("col", { className: "w-12" }), (expandable || expandedRowConfig) && showExpandChevron && (jsxRuntime.jsx("col", { className: "w-10" })), allActions.length > 0 && jsxRuntime.jsx("col", { style: { width: "28px" } }), visibleColumns.map((column, index) => {
15750
15902
  const columnKey = String(column.key);
15751
15903
  const dynamicWidth = columnWidths[columnKey];
15752
15904
  return (jsxRuntime.jsx("col", { style: getColumnStyle(column, dynamicWidth) }, index));
15753
- })] }), jsxRuntime.jsx("thead", { className: `bg-paper-100 sticky top-0 z-10 ${headerClassName}`, children: jsxRuntime.jsxs("tr", { className: "table-header-row", children: [selectable && (jsxRuntime.jsx("th", { className: `sticky left-0 bg-paper-100 ${currentDensity.header} border-b ${borderColor} z-20 w-12 ${bordered ? `border ${borderColor}` : ''}`, children: jsxRuntime.jsx("input", { type: "checkbox", checked: selectedRowsSet.size === data.length && data.length > 0, onChange: handleSelectAll, className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": "Select all rows" }) })), ((expandable || expandedRowConfig) && showExpandChevron) && (jsxRuntime.jsx("th", { className: `sticky left-0 bg-paper-100 px-2 ${currentDensity.header} border-b ${borderColor} z-19 w-10 ${bordered ? `border ${borderColor}` : ''}` })), allActions.length > 0 && (jsxRuntime.jsx("th", { className: `sticky left-0 bg-paper-100 text-center text-xs font-medium text-ink-700 uppercase tracking-wider border-b ${borderColor} z-20 ${bordered ? `border ${borderColor}` : ''}`, style: { width: '28px', padding: '0' } })), visibleColumns.map((column, colIdx) => {
15905
+ })] }), jsxRuntime.jsx("thead", { className: `bg-paper-100 sticky top-0 z-10 ${headerClassName}`, children: jsxRuntime.jsxs("tr", { className: "table-header-row", children: [selectable && (jsxRuntime.jsx("th", { className: `sticky left-0 bg-paper-100 ${currentDensity.header} border-b ${borderColor} z-20 w-12 ${bordered ? `border ${borderColor}` : ""}`, children: jsxRuntime.jsx("input", { type: "checkbox", checked: selectedRowsSet.size === data.length && data.length > 0, onChange: handleSelectAll, className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": "Select all rows" }) })), (expandable || expandedRowConfig) && showExpandChevron && (jsxRuntime.jsx("th", { className: `sticky left-0 bg-paper-100 px-2 ${currentDensity.header} border-b ${borderColor} z-19 w-10 ${bordered ? `border ${borderColor}` : ""}` })), allActions.length > 0 && (jsxRuntime.jsx("th", { className: `sticky left-0 bg-paper-100 text-center text-xs font-medium text-ink-700 uppercase tracking-wider border-b ${borderColor} z-20 ${bordered ? `border ${borderColor}` : ""}`, style: { width: "28px", padding: "0" } })), visibleColumns.map((column, colIdx) => {
15754
15906
  const columnKey = String(column.key);
15755
15907
  const dynamicWidth = columnWidths[columnKey];
15756
15908
  const thRef = React.useRef(null);
@@ -15758,24 +15910,28 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15758
15910
  const isDragOver = dragOverColumn === columnKey;
15759
15911
  // Reduce left padding on first column when there are action buttons (match body cells)
15760
15912
  const isFirstColumn = colIdx === 0;
15761
- const headerPaddingClass = isFirstColumn && allActions.length > 0 ? 'pl-3' : '';
15913
+ const headerPaddingClass = isFirstColumn && allActions.length > 0 ? "pl-3" : "";
15762
15914
  return (jsxRuntime.jsxs("th", { ref: thRef, draggable: reorderable, onDragStart: (e) => reorderable && handleDragStart(e, columnKey), onDragOver: (e) => reorderable && handleDragOver(e, columnKey), onDragEnd: handleDragEnd, onDrop: (e) => reorderable && handleDrop(e, columnKey), className: `
15763
- ${currentDensity.header} ${headerPaddingClass} text-left border-b ${borderColor} ${bordered ? `border ${borderColor}` : ''} relative
15764
- ${reorderable ? 'cursor-move' : ''}
15765
- ${isDragging ? 'opacity-50' : ''}
15766
- ${isDragOver ? 'bg-accent-100' : ''}
15915
+ ${currentDensity.header} ${headerPaddingClass} text-left border-b ${borderColor} ${bordered ? `border ${borderColor}` : ""} relative
15916
+ ${reorderable ? "cursor-move" : ""}
15917
+ ${isDragging ? "opacity-50" : ""}
15918
+ ${isDragOver ? "bg-accent-100" : ""}
15767
15919
  `, style: getColumnStyle(column, dynamicWidth), children: [column.sortable ? (jsxRuntime.jsxs("button", { onClick: () => handleSort(column), className: "group inline-flex items-center text-xs font-medium text-ink-500 uppercase tracking-wider hover:text-ink-900 transition-colors", children: [jsxRuntime.jsx("span", { children: column.header }), getSortIcon(column)] })) : (jsxRuntime.jsx("span", { className: "text-xs font-medium text-ink-500 uppercase tracking-wider", children: column.header })), resizable && (jsxRuntime.jsx("div", { className: "absolute right-0 top-0 bottom-0 w-1 cursor-col-resize hover:bg-accent-400 group", onMouseDown: (e) => {
15768
15920
  const currentWidth = thRef.current?.offsetWidth || 100;
15769
15921
  handleResizeStart(e, columnKey, currentWidth);
15770
15922
  }, children: jsxRuntime.jsx("div", { className: "absolute right-0 top-0 bottom-0 w-1 bg-paper-300 group-hover:bg-accent-400 transition-colors" }) }))] }, columnKey));
15771
- })] }) }), jsxRuntime.jsx("tbody", { ref: tableBodyRef, className: "bg-white table-loading transition-opacity duration-200", onKeyDown: handleKeyboardNavigation, tabIndex: 0, role: "rowgroup", "aria-label": "Table data", children: loading && data.length === 0 ? (renderLoadingSkeleton()) : data.length === 0 ? (renderEmptyStateContent()) : (renderDataRows()) })] })] }));
15923
+ })] }) }), jsxRuntime.jsx("tbody", { ref: tableBodyRef, className: "bg-white table-loading transition-opacity duration-200", onKeyDown: handleKeyboardNavigation, tabIndex: 0, role: "rowgroup", "aria-label": "Table data", children: loading && data.length === 0
15924
+ ? renderLoadingSkeleton()
15925
+ : data.length === 0
15926
+ ? renderEmptyStateContent()
15927
+ : renderDataRows() })] })] }));
15772
15928
  // Wrap in scrollable container if virtualized
15773
- const finalContent = virtualized ? (jsxRuntime.jsx("div", { ref: tableContainerRef, onScroll: handleScroll, style: { height: virtualHeight, overflow: 'auto' }, className: "rounded-lg", children: tableContent })) : tableContent;
15929
+ const finalContent = virtualized ? (jsxRuntime.jsx("div", { ref: tableContainerRef, onScroll: handleScroll, style: { height: virtualHeight, overflow: "auto" }, className: "rounded-lg", children: tableContent })) : (tableContent);
15774
15930
  // Calculate pagination values
15775
15931
  const effectiveTotalItems = totalItems ?? data.length;
15776
15932
  const totalPages = Math.ceil(effectiveTotalItems / pageSize);
15777
15933
  // Page size selector options
15778
- const pageSizeSelectOptions = pageSizeOptions.map(size => ({
15934
+ const pageSizeSelectOptions = pageSizeOptions.map((size) => ({
15779
15935
  value: String(size),
15780
15936
  label: `${size} per page`,
15781
15937
  }));
@@ -15783,17 +15939,20 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15783
15939
  const renderPaginationControls = () => {
15784
15940
  if (!paginated)
15785
15941
  return null;
15786
- return (jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4 px-1", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [showPageSizeSelector && onPageSizeChange && (jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("span", { className: "text-sm text-ink-600", children: "Show:" }), jsxRuntime.jsx(Select, { options: pageSizeSelectOptions, value: String(pageSize), onChange: (value) => onPageSizeChange?.(Number(value)) })] })), jsxRuntime.jsx("span", { className: "text-sm text-ink-600", children: effectiveTotalItems > 0 ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: ["Showing ", ((currentPage - 1) * pageSize) + 1, " - ", Math.min(currentPage * pageSize, effectiveTotalItems), " of ", effectiveTotalItems] })) : ('No items') })] }), totalPages > 1 && onPageChange && (jsxRuntime.jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange }))] }));
15942
+ return (jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4 px-1", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [showPageSizeSelector && onPageSizeChange && (jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("span", { className: "text-sm text-ink-600", children: "Show:" }), jsxRuntime.jsx(Select, { options: pageSizeSelectOptions, value: String(pageSize), onChange: (value) => onPageSizeChange?.(Number(value)) })] })), jsxRuntime.jsx("span", { className: "text-sm text-ink-600", children: effectiveTotalItems > 0 ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: ["Showing ", (currentPage - 1) * pageSize + 1, " -", " ", Math.min(currentPage * pageSize, effectiveTotalItems), " of", " ", effectiveTotalItems] })) : ("No items") })] }), totalPages > 1 && onPageChange && (jsxRuntime.jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange }))] }));
15787
15943
  };
15788
15944
  // Determine if we should show card view
15789
- const shouldShowCardView = mobileView === 'card' ||
15790
- (mobileView === 'auto' && isMobileViewport);
15945
+ const shouldShowCardView = mobileView === "card" || (mobileView === "auto" && isMobileViewport);
15791
15946
  // Card view content
15792
15947
  const cardViewContent = shouldShowCardView ? (jsxRuntime.jsx(DataTableCardView, { data: data, columns: visibleColumns, cardConfig: cardConfig, loading: loading, loadingRows: loadingRows, emptyMessage: emptyMessage, onCardClick: onRowClick, onCardLongPress: (item, event) => {
15793
15948
  if (enableContextMenu && allActions.length > 0) {
15794
15949
  event.preventDefault();
15795
- const clientX = 'touches' in event ? event.touches[0].clientX : event.clientX;
15796
- const clientY = 'touches' in event ? event.touches[0].clientY : event.clientY;
15950
+ const clientX = "touches" in event
15951
+ ? event.touches[0].clientX
15952
+ : event.clientX;
15953
+ const clientY = "touches" in event
15954
+ ? event.touches[0].clientY
15955
+ : event.clientY;
15797
15956
  setContextMenuState({
15798
15957
  isOpen: true,
15799
15958
  position: { x: clientX, y: clientY },
@@ -15802,7 +15961,11 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15802
15961
  }
15803
15962
  }, selectable: selectable, selectedRows: selectedRowsSet, onSelectionChange: onRowSelect ? (rows) => onRowSelect(rows) : undefined, keyExtractor: getRowKey, actions: allActions, onEdit: onEdit, onDelete: onDelete, className: className, cardClassName: cardClassName, gap: cardGap })) : null;
15804
15963
  // Render with context menu
15805
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "true", className: "sr-only", children: announcement }), renderPaginationControls(), shouldShowCardView ? cardViewContent : finalContent, contextMenuState.isOpen && contextMenuState.item && (jsxRuntime.jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({ isOpen: false, position: { x: 0, y: 0 }, item: null }) }))] }));
15964
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "true", className: "sr-only", children: announcement }), renderPaginationControls(), shouldShowCardView ? cardViewContent : finalContent, contextMenuState.isOpen && contextMenuState.item && (jsxRuntime.jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({
15965
+ isOpen: false,
15966
+ position: { x: 0, y: 0 },
15967
+ item: null,
15968
+ }) }))] }));
15806
15969
  }
15807
15970
 
15808
15971
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};