@papernote/ui 2.0.4 → 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
@@ -14826,25 +14826,27 @@ function ActionMenu({ actions, item, }) {
14826
14826
  // Click outside handler
14827
14827
  React.useEffect(() => {
14828
14828
  const handleClickOutside = (event) => {
14829
- if (menuRef.current && !menuRef.current.contains(event.target) &&
14830
- 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)) {
14831
14833
  setIsOpen(false);
14832
14834
  }
14833
14835
  };
14834
14836
  if (isOpen) {
14835
- document.addEventListener('mousedown', handleClickOutside);
14837
+ document.addEventListener("mousedown", handleClickOutside);
14836
14838
  }
14837
14839
  return () => {
14838
- document.removeEventListener('mousedown', handleClickOutside);
14840
+ document.removeEventListener("mousedown", handleClickOutside);
14839
14841
  };
14840
14842
  }, [isOpen]);
14841
- const visibleActions = actions.filter(action => !action.show || action.show(item));
14843
+ const visibleActions = actions.filter((action) => !action.show || action.show(item));
14842
14844
  if (visibleActions.length === 0)
14843
14845
  return null;
14844
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: {
14845
14847
  zIndex: 999999,
14846
14848
  top: `${position.top}px`,
14847
- left: `${position.left}px`
14849
+ left: `${position.left}px`,
14848
14850
  }, children: visibleActions.map((action, idx) => {
14849
14851
  let iconElement = null;
14850
14852
  if (action.icon) {
@@ -14852,7 +14854,9 @@ function ActionMenu({ actions, item, }) {
14852
14854
  iconElement = action.icon;
14853
14855
  }
14854
14856
  else {
14855
- 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
+ });
14856
14860
  }
14857
14861
  }
14858
14862
  return (jsxRuntime.jsxs("button", { type: "button", onClick: async (e) => {
@@ -14862,12 +14866,12 @@ function ActionMenu({ actions, item, }) {
14862
14866
  await action.onClick(item);
14863
14867
  }
14864
14868
  catch (error) {
14865
- console.error('DataTable action error:', error);
14869
+ console.error("DataTable action error:", error);
14866
14870
  }
14867
14871
  setIsOpen(false);
14868
- }, className: `w-full flex items-center gap-3 px-4 py-2.5 text-sm transition-colors ${action.variant === 'danger'
14869
- ? 'text-error-600 hover:bg-error-50 hover:text-error-700'
14870
- : '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));
14871
14875
  }) }));
14872
14876
  return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("button", { ref: buttonRef, onClick: (e) => {
14873
14877
  e.stopPropagation();
@@ -14884,13 +14888,20 @@ function getColumnStyle(column, dynamicWidth) {
14884
14888
  style.width = `${dynamicWidth}px`;
14885
14889
  }
14886
14890
  else if (column.width !== undefined) {
14887
- style.width = typeof column.width === 'number' ? `${column.width}px` : column.width;
14891
+ style.width =
14892
+ typeof column.width === "number" ? `${column.width}px` : column.width;
14888
14893
  }
14889
14894
  if (column.minWidth !== undefined) {
14890
- 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;
14891
14899
  }
14892
14900
  if (column.maxWidth !== undefined) {
14893
- 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;
14894
14905
  }
14895
14906
  if (column.flex !== undefined) {
14896
14907
  style.flexGrow = column.flex;
@@ -14949,13 +14960,13 @@ function getColumnStyle(column, dynamicWidth) {
14949
14960
  * />
14950
14961
  * ```
14951
14962
  */
14952
- 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,
14953
14964
  // Visual customization props
14954
- 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,
14955
14966
  // Pagination props
14956
14967
  paginated = false, currentPage = 1, pageSize = 10, totalItems, onPageChange, pageSizeOptions = [10, 25, 50, 100], onPageSizeChange, showPageSizeSelector = true,
14957
14968
  // Mobile view props
14958
- mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
14969
+ mobileView = "auto", cardConfig, cardGap = "md", cardClassName, }) {
14959
14970
  // Mobile detection for auto mode
14960
14971
  const isMobileViewport = useIsMobile();
14961
14972
  // Column resizing state
@@ -14974,7 +14985,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
14974
14985
  const [hoveredRowKey, setHoveredRowKey] = React.useState(null);
14975
14986
  // Keyboard navigation state
14976
14987
  const [focusedCell, setFocusedCell] = React.useState(null);
14977
- const [announcement, setAnnouncement] = React.useState('');
14988
+ const [announcement, setAnnouncement] = React.useState("");
14978
14989
  const tableBodyRef = React.useRef(null);
14979
14990
  // Temporary row highlight state (for flash animation)
14980
14991
  const [flashingRows, setFlashingRows] = React.useState(new Set());
@@ -14986,18 +14997,18 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
14986
14997
  item: null,
14987
14998
  });
14988
14999
  // Filter columns based on hiddenColumns
14989
- const baseVisibleColumns = columns.filter(col => !hiddenColumns.includes(String(col.key)));
15000
+ const baseVisibleColumns = columns.filter((col) => !hiddenColumns.includes(String(col.key)));
14990
15001
  // Initialize column order on mount or when columns change
14991
15002
  React.useEffect(() => {
14992
15003
  if (columnOrder.length === 0) {
14993
- setColumnOrder(baseVisibleColumns.map(col => String(col.key)));
15004
+ setColumnOrder(baseVisibleColumns.map((col) => String(col.key)));
14994
15005
  }
14995
15006
  }, [baseVisibleColumns, columnOrder.length]);
14996
15007
  // Handle temporary row highlighting (flash animation)
14997
15008
  React.useEffect(() => {
14998
15009
  if (highlightedRows.length > 0) {
14999
15010
  // Add new highlighted rows to flashing set
15000
- const newFlashingRows = new Set(highlightedRows.map(id => String(id)));
15011
+ const newFlashingRows = new Set(highlightedRows.map((id) => String(id)));
15001
15012
  setFlashingRows(newFlashingRows);
15002
15013
  // Clear any existing timeout
15003
15014
  if (flashTimeoutRef.current) {
@@ -15017,25 +15028,25 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15017
15028
  // Apply column order
15018
15029
  const visibleColumns = reorderable && columnOrder.length > 0
15019
15030
  ? columnOrder
15020
- .map(key => baseVisibleColumns.find(col => String(col.key) === key))
15031
+ .map((key) => baseVisibleColumns.find((col) => String(col.key) === key))
15021
15032
  .filter((col) => col !== undefined)
15022
15033
  : baseVisibleColumns;
15023
15034
  // Density classes
15024
15035
  const densityClasses = {
15025
15036
  compact: {
15026
- cell: 'px-3 py-1',
15027
- text: 'text-xs',
15028
- header: 'px-3 py-2',
15037
+ cell: "px-3 py-1",
15038
+ text: "text-xs",
15039
+ header: "px-3 py-2",
15029
15040
  },
15030
15041
  normal: {
15031
- cell: 'px-6 py-1.5',
15032
- text: 'text-sm',
15033
- header: 'px-6 py-3',
15042
+ cell: "px-6 py-1.5",
15043
+ text: "text-sm",
15044
+ header: "px-6 py-3",
15034
15045
  },
15035
15046
  comfortable: {
15036
- cell: 'px-6 py-3',
15037
- text: 'text-base',
15038
- header: 'px-6 py-4',
15047
+ cell: "px-6 py-3",
15048
+ text: "text-base",
15049
+ header: "px-6 py-4",
15039
15050
  },
15040
15051
  };
15041
15052
  const currentDensity = densityClasses[density];
@@ -15043,20 +15054,25 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15043
15054
  const getRowKey = keyExtractor || ((row) => String(row.id));
15044
15055
  // Calculate if there are any actions (for keyboard navigation column calculation)
15045
15056
  // This is computed early so it can be used in keyboard handlers
15046
- const hasAnyActions = !!(onEdit || onDelete || actions.length > 0 ||
15047
- expandedRowConfig?.edit || expandedRowConfig?.details ||
15048
- 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);
15049
15064
  // Get row background class based on striping and highlighting
15050
15065
  const getRowBackgroundClass = (item, index) => {
15051
15066
  const classes = [];
15052
15067
  const rowKey = getRowKey(item);
15053
15068
  // Check for temporary flash highlight (takes priority)
15054
15069
  if (flashingRows.has(rowKey)) {
15055
- classes.push('animate-row-flash');
15070
+ classes.push("animate-row-flash");
15056
15071
  }
15057
15072
  // Check for highlighted row
15058
- else if (highlightedRowId !== undefined && rowKey === String(highlightedRowId)) {
15059
- classes.push('bg-accent-100');
15073
+ else if (highlightedRowId !== undefined &&
15074
+ rowKey === String(highlightedRowId)) {
15075
+ classes.push("bg-accent-100");
15060
15076
  }
15061
15077
  // Check for custom row highlight
15062
15078
  else if (rowHighlight) {
@@ -15068,24 +15084,27 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15068
15084
  // Check for striping
15069
15085
  else if (striped) {
15070
15086
  const isOdd = index % 2 === 0; // 0-indexed, so even index = odd row
15071
- const shouldStripe = striped === true ? isOdd :
15072
- striped === 'odd' ? isOdd :
15073
- striped === 'even' ? !isOdd :
15074
- false;
15087
+ const shouldStripe = striped === true
15088
+ ? isOdd
15089
+ : striped === "odd"
15090
+ ? isOdd
15091
+ : striped === "even"
15092
+ ? !isOdd
15093
+ : false;
15075
15094
  if (shouldStripe) {
15076
- classes.push(stripedColor || 'bg-paper-50');
15095
+ classes.push(stripedColor || "bg-paper-50");
15077
15096
  }
15078
15097
  }
15079
15098
  // Add custom row class
15080
15099
  if (rowClassName) {
15081
- if (typeof rowClassName === 'string') {
15100
+ if (typeof rowClassName === "string") {
15082
15101
  classes.push(rowClassName);
15083
15102
  }
15084
15103
  else {
15085
15104
  classes.push(rowClassName(item, index));
15086
15105
  }
15087
15106
  }
15088
- return classes.join(' ');
15107
+ return classes.join(" ");
15089
15108
  };
15090
15109
  // NEW: Expansion mode state management (for expandedRowConfig)
15091
15110
  const [expansionState, setExpansionState] = React.useState(null);
@@ -15100,12 +15119,12 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15100
15119
  // Column reorder handlers
15101
15120
  const handleDragStart = (e, columnKey) => {
15102
15121
  setDraggingColumn(columnKey);
15103
- e.dataTransfer.effectAllowed = 'move';
15104
- e.dataTransfer.setData('text/html', columnKey);
15122
+ e.dataTransfer.effectAllowed = "move";
15123
+ e.dataTransfer.setData("text/html", columnKey);
15105
15124
  };
15106
15125
  const handleDragOver = (e, columnKey) => {
15107
15126
  e.preventDefault();
15108
- e.dataTransfer.dropEffect = 'move';
15127
+ e.dataTransfer.dropEffect = "move";
15109
15128
  if (draggingColumn && draggingColumn !== columnKey) {
15110
15129
  setDragOverColumn(columnKey);
15111
15130
  }
@@ -15136,7 +15155,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15136
15155
  const handleMouseMove = (e) => {
15137
15156
  const delta = e.clientX - resizeStartX;
15138
15157
  const newWidth = Math.max(50, resizeStartWidth + delta); // Min width 50px
15139
- setColumnWidths(prev => ({
15158
+ setColumnWidths((prev) => ({
15140
15159
  ...prev,
15141
15160
  [resizingColumn]: newWidth,
15142
15161
  }));
@@ -15147,56 +15166,62 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15147
15166
  }
15148
15167
  setResizingColumn(null);
15149
15168
  };
15150
- document.addEventListener('mousemove', handleMouseMove);
15151
- document.addEventListener('mouseup', handleMouseUp);
15169
+ document.addEventListener("mousemove", handleMouseMove);
15170
+ document.addEventListener("mouseup", handleMouseUp);
15152
15171
  return () => {
15153
- document.removeEventListener('mousemove', handleMouseMove);
15154
- document.removeEventListener('mouseup', handleMouseUp);
15172
+ document.removeEventListener("mousemove", handleMouseMove);
15173
+ document.removeEventListener("mouseup", handleMouseUp);
15155
15174
  };
15156
- }, [resizingColumn, resizeStartX, resizeStartWidth, columnWidths, onColumnResize]);
15175
+ }, [
15176
+ resizingColumn,
15177
+ resizeStartX,
15178
+ resizeStartWidth,
15179
+ columnWidths,
15180
+ onColumnResize,
15181
+ ]);
15157
15182
  // Build combined actions: built-in edit/delete + custom actions + expansion mode actions
15158
15183
  const builtInActions = [];
15159
15184
  // Legacy onEdit (still supported)
15160
15185
  if (onEdit) {
15161
15186
  builtInActions.push({
15162
- label: 'Edit',
15187
+ label: "Edit",
15163
15188
  icon: lucideReact.Edit,
15164
15189
  onClick: onEdit,
15165
- variant: 'secondary',
15166
- tooltip: 'Edit item'
15190
+ variant: "secondary",
15191
+ tooltip: "Edit item",
15167
15192
  });
15168
15193
  }
15169
15194
  // NEW: Edit mode from expandedRowConfig
15170
15195
  if (expandedRowConfig?.edit && !onEdit) {
15171
15196
  const editConfig = expandedRowConfig.edit;
15172
15197
  builtInActions.push({
15173
- label: editConfig.menuLabel || 'Edit',
15198
+ label: editConfig.menuLabel || "Edit",
15174
15199
  icon: editConfig.menuIcon || lucideReact.Edit,
15175
15200
  onClick: (item) => {
15176
15201
  const rowKey = getRowKey(item);
15177
- handleExpansionWithMode(rowKey, 'edit');
15202
+ handleExpansionWithMode(rowKey, "edit");
15178
15203
  },
15179
- variant: 'secondary',
15180
- tooltip: 'Edit inline'
15204
+ variant: "secondary",
15205
+ tooltip: "Edit inline",
15181
15206
  });
15182
15207
  }
15183
15208
  // NEW: View details mode from expandedRowConfig
15184
15209
  if (expandedRowConfig?.details) {
15185
15210
  const detailsConfig = expandedRowConfig.details;
15186
15211
  builtInActions.push({
15187
- label: detailsConfig.menuLabel || 'View Details',
15212
+ label: detailsConfig.menuLabel || "View Details",
15188
15213
  icon: detailsConfig.menuIcon,
15189
15214
  onClick: (item) => {
15190
15215
  const rowKey = getRowKey(item);
15191
- handleExpansionWithMode(rowKey, 'details');
15216
+ handleExpansionWithMode(rowKey, "details");
15192
15217
  },
15193
- variant: 'ghost',
15194
- tooltip: 'View details'
15218
+ variant: "ghost",
15219
+ tooltip: "View details",
15195
15220
  });
15196
15221
  }
15197
15222
  // NEW: Add related modes from expandedRowConfig
15198
15223
  if (expandedRowConfig?.addRelated) {
15199
- expandedRowConfig.addRelated.forEach(config => {
15224
+ expandedRowConfig.addRelated.forEach((config) => {
15200
15225
  if (config.showInMenu !== false) {
15201
15226
  builtInActions.push({
15202
15227
  label: config.label,
@@ -15205,15 +15230,15 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15205
15230
  const rowKey = getRowKey(item);
15206
15231
  handleExpansionWithMode(rowKey, `addRelated-${config.key}`);
15207
15232
  },
15208
- variant: 'secondary',
15209
- tooltip: config.label
15233
+ variant: "secondary",
15234
+ tooltip: config.label,
15210
15235
  });
15211
15236
  }
15212
15237
  });
15213
15238
  }
15214
15239
  // NEW: Manage related modes from expandedRowConfig
15215
15240
  if (expandedRowConfig?.manageRelated) {
15216
- expandedRowConfig.manageRelated.forEach(config => {
15241
+ expandedRowConfig.manageRelated.forEach((config) => {
15217
15242
  if (config.showInMenu !== false) {
15218
15243
  builtInActions.push({
15219
15244
  label: config.label,
@@ -15222,8 +15247,8 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15222
15247
  const rowKey = getRowKey(item);
15223
15248
  handleExpansionWithMode(rowKey, `manageRelated-${config.key}`);
15224
15249
  },
15225
- variant: 'ghost',
15226
- tooltip: config.label
15250
+ variant: "ghost",
15251
+ tooltip: config.label,
15227
15252
  });
15228
15253
  }
15229
15254
  });
@@ -15233,11 +15258,11 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15233
15258
  let deleteAction = null;
15234
15259
  if (onDelete) {
15235
15260
  deleteAction = {
15236
- label: 'Delete',
15261
+ label: "Delete",
15237
15262
  icon: lucideReact.Trash,
15238
15263
  onClick: onDelete,
15239
- variant: 'danger',
15240
- tooltip: 'Delete item'
15264
+ variant: "danger",
15265
+ tooltip: "Delete item",
15241
15266
  };
15242
15267
  }
15243
15268
  // Build final actions array with consistent ordering:
@@ -15250,11 +15275,11 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15250
15275
  const allActions = [
15251
15276
  ...builtInActions,
15252
15277
  ...actions,
15253
- ...(deleteAction ? [deleteAction] : [])
15278
+ ...(deleteAction ? [deleteAction] : []),
15254
15279
  ];
15255
15280
  // Convert actions to menu items for context menu
15256
15281
  const convertActionsToMenuItems = (item) => {
15257
- const visibleActions = allActions.filter(action => !action.show || action.show(item));
15282
+ const visibleActions = allActions.filter((action) => !action.show || action.show(item));
15258
15283
  return visibleActions.map((action, idx) => {
15259
15284
  let iconElement = null;
15260
15285
  if (action.icon) {
@@ -15262,7 +15287,9 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15262
15287
  iconElement = action.icon;
15263
15288
  }
15264
15289
  else {
15265
- iconElement = React.createElement(action.icon, { className: 'h-4 w-4' });
15290
+ iconElement = React.createElement(action.icon, {
15291
+ className: "h-4 w-4",
15292
+ });
15266
15293
  }
15267
15294
  }
15268
15295
  return {
@@ -15270,7 +15297,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15270
15297
  label: action.label,
15271
15298
  icon: iconElement,
15272
15299
  onClick: () => action.onClick(item),
15273
- danger: action.variant === 'danger',
15300
+ danger: action.variant === "danger",
15274
15301
  };
15275
15302
  });
15276
15303
  };
@@ -15279,7 +15306,9 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15279
15306
  // Expansion state management
15280
15307
  const [internalExpandedRows, setInternalExpandedRows] = React.useState(new Set());
15281
15308
  // Use external selection if provided, otherwise internal
15282
- const selectedRowsSet = externalSelectedRows !== undefined ? externalSelectedRows : internalSelectedRows;
15309
+ const selectedRowsSet = externalSelectedRows !== undefined
15310
+ ? externalSelectedRows
15311
+ : internalSelectedRows;
15283
15312
  const setSelectedRows = (newSet) => {
15284
15313
  if (externalSelectedRows !== undefined) {
15285
15314
  // Controlled component - notify parent
@@ -15313,7 +15342,9 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15313
15342
  }
15314
15343
  };
15315
15344
  // Use external expansion if provided, otherwise internal
15316
- const expandedRowsSet = externalExpandedRows !== undefined ? externalExpandedRows : internalExpandedRows;
15345
+ const expandedRowsSet = externalExpandedRows !== undefined
15346
+ ? externalExpandedRows
15347
+ : internalExpandedRows;
15317
15348
  const setExpandedRows = (newSet) => {
15318
15349
  if (externalExpandedRows !== undefined) ;
15319
15350
  else {
@@ -15355,10 +15386,10 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15355
15386
  const totalCols = visibleColumns.length;
15356
15387
  // If no cell is focused, focus first data cell on first arrow key
15357
15388
  if (!focusedCell) {
15358
- if (['ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {
15389
+ if (["ArrowDown", "ArrowUp", "ArrowLeft", "ArrowRight"].includes(e.key)) {
15359
15390
  e.preventDefault();
15360
15391
  setFocusedCell({ row: 0, col: 0 });
15361
- const colHeader = visibleColumns[0]?.header || 'first column';
15392
+ const colHeader = visibleColumns[0]?.header || "first column";
15362
15393
  setAnnouncement(`Row 1, ${colHeader}`);
15363
15394
  return;
15364
15395
  }
@@ -15366,73 +15397,73 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15366
15397
  }
15367
15398
  const { row, col } = focusedCell;
15368
15399
  switch (e.key) {
15369
- case 'ArrowDown':
15400
+ case "ArrowDown":
15370
15401
  e.preventDefault();
15371
15402
  if (row < totalRows - 1) {
15372
15403
  const newRow = row + 1;
15373
15404
  setFocusedCell({ row: newRow, col });
15374
15405
  const rowItem = data[newRow];
15375
- const colHeader = visibleColumns[col]?.header || '';
15406
+ const colHeader = visibleColumns[col]?.header || "";
15376
15407
  const cellValue = rowItem[visibleColumns[col]?.key];
15377
- setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue || 'empty'}`);
15408
+ setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue || "empty"}`);
15378
15409
  }
15379
15410
  break;
15380
- case 'ArrowUp':
15411
+ case "ArrowUp":
15381
15412
  e.preventDefault();
15382
15413
  if (row > 0) {
15383
15414
  const newRow = row - 1;
15384
15415
  setFocusedCell({ row: newRow, col });
15385
15416
  const rowItem = data[newRow];
15386
- const colHeader = visibleColumns[col]?.header || '';
15417
+ const colHeader = visibleColumns[col]?.header || "";
15387
15418
  const cellValue = rowItem[visibleColumns[col]?.key];
15388
- setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue || 'empty'}`);
15419
+ setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue || "empty"}`);
15389
15420
  }
15390
15421
  break;
15391
- case 'ArrowRight':
15422
+ case "ArrowRight":
15392
15423
  e.preventDefault();
15393
15424
  if (col < totalCols - 1) {
15394
15425
  const newCol = col + 1;
15395
15426
  setFocusedCell({ row, col: newCol });
15396
15427
  const rowItem = data[row];
15397
- const colHeader = visibleColumns[newCol]?.header || '';
15428
+ const colHeader = visibleColumns[newCol]?.header || "";
15398
15429
  const cellValue = rowItem[visibleColumns[newCol]?.key];
15399
- setAnnouncement(`${colHeader}: ${cellValue || 'empty'}`);
15430
+ setAnnouncement(`${colHeader}: ${cellValue || "empty"}`);
15400
15431
  }
15401
15432
  break;
15402
- case 'ArrowLeft':
15433
+ case "ArrowLeft":
15403
15434
  e.preventDefault();
15404
15435
  if (col > 0) {
15405
15436
  const newCol = col - 1;
15406
15437
  setFocusedCell({ row, col: newCol });
15407
15438
  const rowItem = data[row];
15408
- const colHeader = visibleColumns[newCol]?.header || '';
15439
+ const colHeader = visibleColumns[newCol]?.header || "";
15409
15440
  const cellValue = rowItem[visibleColumns[newCol]?.key];
15410
- setAnnouncement(`${colHeader}: ${cellValue || 'empty'}`);
15441
+ setAnnouncement(`${colHeader}: ${cellValue || "empty"}`);
15411
15442
  }
15412
15443
  break;
15413
- case 'Home':
15444
+ case "Home":
15414
15445
  e.preventDefault();
15415
15446
  if (e.ctrlKey) {
15416
15447
  // Ctrl+Home: Go to first cell
15417
15448
  setFocusedCell({ row: 0, col: 0 });
15418
- setAnnouncement(`First cell, Row 1, ${visibleColumns[0]?.header || ''}`);
15449
+ setAnnouncement(`First cell, Row 1, ${visibleColumns[0]?.header || ""}`);
15419
15450
  }
15420
15451
  else {
15421
15452
  // Home: Go to first cell in current row
15422
15453
  setFocusedCell({ row, col: 0 });
15423
15454
  const rowItem = data[row];
15424
15455
  const cellValue = rowItem[visibleColumns[0]?.key];
15425
- setAnnouncement(`${visibleColumns[0]?.header || ''}: ${cellValue || 'empty'}`);
15456
+ setAnnouncement(`${visibleColumns[0]?.header || ""}: ${cellValue || "empty"}`);
15426
15457
  }
15427
15458
  break;
15428
- case 'End':
15459
+ case "End":
15429
15460
  e.preventDefault();
15430
15461
  if (e.ctrlKey) {
15431
15462
  // Ctrl+End: Go to last cell
15432
15463
  const lastRow = totalRows - 1;
15433
15464
  const lastCol = totalCols - 1;
15434
15465
  setFocusedCell({ row: lastRow, col: lastCol });
15435
- setAnnouncement(`Last cell, Row ${lastRow + 1}, ${visibleColumns[lastCol]?.header || ''}`);
15466
+ setAnnouncement(`Last cell, Row ${lastRow + 1}, ${visibleColumns[lastCol]?.header || ""}`);
15436
15467
  }
15437
15468
  else {
15438
15469
  // End: Go to last cell in current row
@@ -15440,10 +15471,10 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15440
15471
  setFocusedCell({ row, col: lastCol });
15441
15472
  const rowItem = data[row];
15442
15473
  const cellValue = rowItem[visibleColumns[lastCol]?.key];
15443
- setAnnouncement(`${visibleColumns[lastCol]?.header || ''}: ${cellValue || 'empty'}`);
15474
+ setAnnouncement(`${visibleColumns[lastCol]?.header || ""}: ${cellValue || "empty"}`);
15444
15475
  }
15445
15476
  break;
15446
- case 'Enter':
15477
+ case "Enter":
15447
15478
  e.preventDefault();
15448
15479
  {
15449
15480
  const rowItem = data[row];
@@ -15451,27 +15482,27 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15451
15482
  // Priority: Edit mode > Details mode > Row double-click handler
15452
15483
  if (onEdit) {
15453
15484
  onEdit(rowItem);
15454
- setAnnouncement('Opening edit mode');
15485
+ setAnnouncement("Opening edit mode");
15455
15486
  }
15456
15487
  else if (expandedRowConfig?.edit) {
15457
- handleExpansionWithMode(rowKey, 'edit');
15458
- setAnnouncement('Opening inline edit');
15488
+ handleExpansionWithMode(rowKey, "edit");
15489
+ setAnnouncement("Opening inline edit");
15459
15490
  }
15460
15491
  else if (expandedRowConfig?.details) {
15461
- handleExpansionWithMode(rowKey, 'details');
15462
- setAnnouncement('Opening details view');
15492
+ handleExpansionWithMode(rowKey, "details");
15493
+ setAnnouncement("Opening details view");
15463
15494
  }
15464
15495
  else if (onRowDoubleClick) {
15465
15496
  onRowDoubleClick(rowItem);
15466
- setAnnouncement('Activating row');
15497
+ setAnnouncement("Activating row");
15467
15498
  }
15468
15499
  else if (onRowClick) {
15469
15500
  onRowClick(rowItem);
15470
- setAnnouncement('Row selected');
15501
+ setAnnouncement("Row selected");
15471
15502
  }
15472
15503
  }
15473
15504
  break;
15474
- case ' ':
15505
+ case " ":
15475
15506
  // Space: Toggle selection if selectable
15476
15507
  if (selectable) {
15477
15508
  e.preventDefault();
@@ -15479,60 +15510,82 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15479
15510
  const rowKey = getRowKey(rowItem);
15480
15511
  handleRowSelect(rowKey);
15481
15512
  const isNowSelected = !selectedRowsSet.has(rowKey);
15482
- setAnnouncement(isNowSelected ? 'Row selected' : 'Row deselected');
15513
+ setAnnouncement(isNowSelected ? "Row selected" : "Row deselected");
15483
15514
  }
15484
15515
  break;
15485
- case 'Escape':
15516
+ case "Escape":
15486
15517
  e.preventDefault();
15487
15518
  setFocusedCell(null);
15488
- setAnnouncement('Table navigation exited');
15519
+ setAnnouncement("Table navigation exited");
15489
15520
  // Return focus to table container
15490
- tableBodyRef.current?.closest('table')?.focus();
15521
+ tableBodyRef.current?.closest("table")?.focus();
15491
15522
  break;
15492
- case 'PageDown':
15523
+ case "PageDown":
15493
15524
  e.preventDefault();
15494
15525
  {
15495
15526
  const jumpSize = 10;
15496
15527
  const newRow = Math.min(row + jumpSize, totalRows - 1);
15497
15528
  setFocusedCell({ row: newRow, col });
15498
- const colHeader = visibleColumns[col]?.header || '';
15529
+ const colHeader = visibleColumns[col]?.header || "";
15499
15530
  setAnnouncement(`Row ${newRow + 1} of ${totalRows}, ${colHeader}`);
15500
15531
  }
15501
15532
  break;
15502
- case 'PageUp':
15533
+ case "PageUp":
15503
15534
  e.preventDefault();
15504
15535
  {
15505
15536
  const jumpSize = 10;
15506
15537
  const newRow = Math.max(row - jumpSize, 0);
15507
15538
  setFocusedCell({ row: newRow, col });
15508
- const colHeader = visibleColumns[col]?.header || '';
15539
+ const colHeader = visibleColumns[col]?.header || "";
15509
15540
  setAnnouncement(`Row ${newRow + 1} of ${totalRows}, ${colHeader}`);
15510
15541
  }
15511
15542
  break;
15512
15543
  }
15513
- }, [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
+ ]);
15514
15558
  // Focus the appropriate cell when focusedCell changes
15515
15559
  React.useEffect(() => {
15516
15560
  if (focusedCell && tableBodyRef.current) {
15517
15561
  const { row, col } = focusedCell;
15518
- const rows = tableBodyRef.current.querySelectorAll('tr[data-row-index]');
15562
+ const rows = tableBodyRef.current.querySelectorAll("tr[data-row-index]");
15519
15563
  const targetRow = rows[row];
15520
15564
  if (targetRow) {
15521
15565
  // Calculate actual column index including extra columns
15522
15566
  const hasSelectionCol = selectable;
15523
15567
  const hasExpandCol = (expandable || expandedRowConfig) && showExpandChevron;
15524
15568
  const hasActionsCol = hasAnyActions;
15525
- const extraColsBefore = (hasSelectionCol ? 1 : 0) + (hasExpandCol ? 1 : 0) + (hasActionsCol ? 1 : 0);
15526
- 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");
15527
15573
  const targetCell = cells[col + extraColsBefore];
15528
15574
  if (targetCell) {
15529
15575
  targetCell.focus();
15530
15576
  // Scroll into view if needed
15531
- targetCell.scrollIntoView({ block: 'nearest', inline: 'nearest' });
15577
+ targetCell.scrollIntoView({ block: "nearest", inline: "nearest" });
15532
15578
  }
15533
15579
  }
15534
15580
  }
15535
- }, [focusedCell, selectable, expandable, expandedRowConfig, showExpandChevron, hasAnyActions]);
15581
+ }, [
15582
+ focusedCell,
15583
+ selectable,
15584
+ expandable,
15585
+ expandedRowConfig,
15586
+ showExpandChevron,
15587
+ hasAnyActions,
15588
+ ]);
15536
15589
  // Handle column header click for sorting
15537
15590
  const handleSort = (column) => {
15538
15591
  if (!column.sortable || !onSortChange)
@@ -15540,8 +15593,12 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15540
15593
  const columnKey = String(column.key);
15541
15594
  // If clicking the same column, toggle direction
15542
15595
  if (currentSort?.key === columnKey) {
15543
- if (currentSort.direction === 'asc') {
15544
- 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
+ });
15545
15602
  }
15546
15603
  else {
15547
15604
  // Remove sort on third click
@@ -15550,7 +15607,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15550
15607
  }
15551
15608
  else {
15552
15609
  // New column - start with ascending
15553
- onSortChange({ key: columnKey, direction: 'asc', label: column.header });
15610
+ onSortChange({ key: columnKey, direction: "asc", label: column.header });
15554
15611
  }
15555
15612
  };
15556
15613
  // Get sort icon SVG for column (matches reference ui-preview.html)
@@ -15559,7 +15616,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15559
15616
  return null;
15560
15617
  const columnKey = String(column.key);
15561
15618
  const isActive = currentSort?.key === columnKey;
15562
- const isAscending = currentSort?.direction === 'asc';
15619
+ const isAscending = currentSort?.direction === "asc";
15563
15620
  // Inactive state - show neutral up/down arrows
15564
15621
  if (!isActive) {
15565
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" }) }));
@@ -15572,17 +15629,23 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15572
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" }) }));
15573
15630
  };
15574
15631
  // Render loading skeleton
15575
- 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) => {
15576
15633
  const columnKey = String(column.key);
15577
15634
  const dynamicWidth = columnWidths[columnKey];
15578
- 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}`));
15579
15636
  })] }, `loading-${i}`))) }));
15580
15637
  // Render empty state
15581
15638
  const renderEmptyStateContent = () => {
15582
15639
  if (customRenderEmptyState) {
15583
- 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() }) }));
15584
15644
  }
15585
- 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 }) }));
15586
15649
  };
15587
15650
  // Virtual scrolling calculations
15588
15651
  const getVisibleRange = () => {
@@ -15612,14 +15675,18 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15612
15675
  const isSelected = selectedRowsSet.has(rowKey);
15613
15676
  const isExpanded = expandedRowsSet.has(rowKey);
15614
15677
  const rowBgClass = getRowBackgroundClass(item, index);
15615
- const borderClass = bordered ? `border-b ${borderColor}` : (!visibleColumns.some(col => !!col.renderSecondary) ? `border-b ${borderColor}` : '');
15616
- 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);
15617
15684
  // Hover state for row pair (primary + secondary)
15618
15685
  const isHovered = hoveredRowKey === rowKey;
15619
- const hoverClass = disableHover ? '' : (isHovered ? 'bg-paper-100' : '');
15686
+ const hoverClass = disableHover ? "" : isHovered ? "bg-paper-100" : "";
15620
15687
  // Check if this row is keyboard-focused
15621
15688
  const isKeyboardFocused = focusedCell?.row === index;
15622
- 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) => {
15623
15690
  if (enableContextMenu && allActions.length > 0) {
15624
15691
  e.preventDefault();
15625
15692
  e.stopPropagation();
@@ -15638,109 +15705,146 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15638
15705
  }
15639
15706
  // Priority 2: If there's an expandable edit mode, trigger it
15640
15707
  else if (expandedRowConfig?.edit) {
15641
- handleExpansionWithMode(rowKey, 'edit');
15708
+ handleExpansionWithMode(rowKey, "edit");
15642
15709
  }
15643
15710
  // Priority 3: If there's an expandable details mode, trigger it
15644
15711
  else if (expandedRowConfig?.details) {
15645
- handleExpansionWithMode(rowKey, 'details');
15712
+ handleExpansionWithMode(rowKey, "details");
15646
15713
  }
15647
15714
  // Priority 4: If there's any addRelated mode, trigger the first one
15648
- else if (expandedRowConfig?.addRelated && expandedRowConfig.addRelated.length > 0) {
15715
+ else if (expandedRowConfig?.addRelated &&
15716
+ expandedRowConfig.addRelated.length > 0) {
15649
15717
  handleExpansionWithMode(rowKey, `addRelated-${expandedRowConfig.addRelated[0].key}`);
15650
15718
  }
15651
15719
  // Priority 5: If there's any manageRelated mode, trigger the first one
15652
- else if (expandedRowConfig?.manageRelated && expandedRowConfig.manageRelated.length > 0) {
15720
+ else if (expandedRowConfig?.manageRelated &&
15721
+ expandedRowConfig.manageRelated.length > 0) {
15653
15722
  handleExpansionWithMode(rowKey, `manageRelated-${expandedRowConfig.manageRelated[0].key}`);
15654
15723
  }
15655
15724
  // Priority 6: Legacy onRowDoubleClick handler
15656
15725
  else {
15657
15726
  onRowDoubleClick?.(item);
15658
15727
  }
15659
- }, title: onEdit ? 'Double-click to edit' :
15660
- expandedRowConfig?.edit ? 'Double-click to edit inline' :
15661
- expandedRowConfig?.details ? 'Double-click to view details' :
15662
- expandedRowConfig?.addRelated && expandedRowConfig.addRelated.length > 0 ? `Double-click to ${expandedRowConfig.addRelated[0].label}` :
15663
- expandedRowConfig?.manageRelated && expandedRowConfig.manageRelated.length > 0 ? `Double-click to ${expandedRowConfig.manageRelated[0].label}` :
15664
- onRowDoubleClick ? 'Double-click for details' :
15665
- onRowClick ? 'Click to select' :
15666
- undefined, children: [selectable && (jsxRuntime.jsx("td", { className: `sticky left-0 z-10 ${bordered ? `border ${borderColor}` : ''}`, style: {
15667
- backgroundColor: 'inherit',
15668
- verticalAlign: 'middle',
15669
- padding: '0.375rem 0.75rem',
15670
- textAlign: 'center'
15671
- }, 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: () => {
15672
15750
  // NEW: Enhanced logic for expandedRowConfig
15673
- if (expandedRowConfig?.details && expandedRowConfig.details.triggerOnExpand !== false) {
15751
+ if (expandedRowConfig?.details &&
15752
+ expandedRowConfig.details.triggerOnExpand !== false) {
15674
15753
  // Trigger details mode if configured
15675
- handleExpansionWithMode(rowKey, 'details');
15754
+ handleExpansionWithMode(rowKey, "details");
15676
15755
  }
15677
- else if (expandedRowConfig?.edit && expandedRowConfig.edit.triggerOnDoubleClick !== false) {
15756
+ else if (expandedRowConfig?.edit &&
15757
+ expandedRowConfig.edit.triggerOnDoubleClick !== false) {
15678
15758
  // Fallback to edit mode if no details but edit is available
15679
- handleExpansionWithMode(rowKey, 'edit');
15759
+ handleExpansionWithMode(rowKey, "edit");
15680
15760
  }
15681
15761
  else {
15682
15762
  // Legacy: use handleRowExpand
15683
15763
  handleRowExpand(rowKey);
15684
15764
  }
15685
- }, 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: {
15686
- width: '28px',
15687
- padding: '0',
15688
- backgroundColor: 'inherit',
15689
- verticalAlign: 'middle'
15690
- }, 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) => {
15691
15778
  const columnKey = String(column.key);
15692
15779
  const dynamicWidth = columnWidths[columnKey];
15693
- const value = typeof column.key === 'string'
15780
+ const value = typeof column.key === "string"
15694
15781
  ? item[column.key]
15695
15782
  : item[column.key];
15696
- 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;
15697
15795
  // Reduce left padding on first column when there are action buttons
15698
15796
  const isFirstColumn = colIdx === 0;
15699
- const paddingClass = isFirstColumn && allActions.length > 0 ? 'pl-3' : '';
15797
+ const paddingClass = isFirstColumn && allActions.length > 0 ? "pl-3" : "";
15700
15798
  // Check if this cell is keyboard-focused
15701
15799
  const isCellFocused = focusedCell?.row === index && focusedCell?.col === colIdx;
15702
- 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}`));
15703
- })] }), 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) => {
15704
15802
  const columnKey = String(column.key);
15705
15803
  const dynamicWidth = columnWidths[columnKey];
15706
- const value = typeof column.key === 'string'
15804
+ const value = typeof column.key === "string"
15707
15805
  ? item[column.key]
15708
15806
  : item[column.key];
15709
- 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
+ }
15710
15827
  // Reduce left padding on first column when there are action buttons
15711
15828
  const isFirstColumn = colIdx === 0;
15712
- const paddingClass = isFirstColumn && allActions.length > 0 ? 'pl-3' : '';
15713
- 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`));
15714
15831
  }) })), expandable && isExpanded && renderExpandedRow && (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: visibleColumns.length +
15715
15832
  (selectable ? 1 : 0) +
15716
- (((expandable || expandedRowConfig) && showExpandChevron) ? 1 : 0) +
15717
- (allActions.length > 0 ? 1 : 0), className: `${currentDensity.cell} py-4 bg-paper-50`, children: renderExpandedRow(item) }) })), expansionState && expansionState.rowKey === rowKey && expandedRowConfig && (() => {
15718
- const mode = expansionState.mode;
15719
- let content = null;
15720
- let bgColorClass = 'bg-paper-50'; // Default
15721
- // Edit mode
15722
- if (mode === 'edit' && expandedRowConfig.edit) {
15723
- bgColorClass = 'bg-paper-100/80 border-t border-b border-paper-300/80';
15724
- content = expandedRowConfig.edit.render(item, async (_updated) => {
15725
- // Handle save
15726
- handleCollapseExpansion();
15727
- }, () => {
15728
- // Handle cancel
15729
- handleCollapseExpansion();
15730
- });
15731
- }
15732
- // Details mode
15733
- else if (mode === 'details' && expandedRowConfig.details) {
15734
- bgColorClass = 'bg-primary-50/80 border-t border-b border-primary-200/80';
15735
- content = expandedRowConfig.details.render(item);
15736
- }
15737
- // Add related modes
15738
- else if (mode.startsWith('addRelated-') && expandedRowConfig.addRelated) {
15739
- const key = mode.replace('addRelated-', '');
15740
- const config = expandedRowConfig.addRelated.find(c => c.key === key);
15741
- if (config) {
15742
- bgColorClass = 'bg-success-50/80 border-t border-b border-success-200/80';
15743
- 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) => {
15744
15848
  // Handle save
15745
15849
  handleCollapseExpansion();
15746
15850
  }, () => {
@@ -15748,31 +15852,57 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15748
15852
  handleCollapseExpansion();
15749
15853
  });
15750
15854
  }
15751
- }
15752
- // Manage related modes
15753
- else if (mode.startsWith('manageRelated-') && expandedRowConfig.manageRelated) {
15754
- const key = mode.replace('manageRelated-', '');
15755
- const config = expandedRowConfig.manageRelated.find(c => c.key === key);
15756
- if (config) {
15757
- bgColorClass = 'bg-slate-50/80 border-t border-b border-slate-200/80';
15758
- const handleClose = () => setExpansionState(null);
15759
- 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);
15760
15860
  }
15761
- }
15762
- if (!content)
15763
- return null;
15764
- return (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: visibleColumns.length +
15765
- (selectable ? 1 : 0) +
15766
- (((expandable || expandedRowConfig) && showExpandChevron) ? 1 : 0) +
15767
- (allActions.length > 0 ? 1 : 0), className: `${currentDensity.cell} py-4 ${bgColorClass} animate-expand`, children: content }) }, `expanded-${rowKey}`));
15768
- })()] }, 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));
15769
15899
  });
15770
15900
  };
15771
- 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) => {
15772
15902
  const columnKey = String(column.key);
15773
15903
  const dynamicWidth = columnWidths[columnKey];
15774
15904
  return (jsxRuntime.jsx("col", { style: getColumnStyle(column, dynamicWidth) }, index));
15775
- })] }), 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) => {
15776
15906
  const columnKey = String(column.key);
15777
15907
  const dynamicWidth = columnWidths[columnKey];
15778
15908
  const thRef = React.useRef(null);
@@ -15780,24 +15910,28 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15780
15910
  const isDragOver = dragOverColumn === columnKey;
15781
15911
  // Reduce left padding on first column when there are action buttons (match body cells)
15782
15912
  const isFirstColumn = colIdx === 0;
15783
- const headerPaddingClass = isFirstColumn && allActions.length > 0 ? 'pl-3' : '';
15913
+ const headerPaddingClass = isFirstColumn && allActions.length > 0 ? "pl-3" : "";
15784
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: `
15785
- ${currentDensity.header} ${headerPaddingClass} text-left border-b ${borderColor} ${bordered ? `border ${borderColor}` : ''} relative
15786
- ${reorderable ? 'cursor-move' : ''}
15787
- ${isDragging ? 'opacity-50' : ''}
15788
- ${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" : ""}
15789
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) => {
15790
15920
  const currentWidth = thRef.current?.offsetWidth || 100;
15791
15921
  handleResizeStart(e, columnKey, currentWidth);
15792
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));
15793
- })] }) }), 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() })] })] }));
15794
15928
  // Wrap in scrollable container if virtualized
15795
- 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);
15796
15930
  // Calculate pagination values
15797
15931
  const effectiveTotalItems = totalItems ?? data.length;
15798
15932
  const totalPages = Math.ceil(effectiveTotalItems / pageSize);
15799
15933
  // Page size selector options
15800
- const pageSizeSelectOptions = pageSizeOptions.map(size => ({
15934
+ const pageSizeSelectOptions = pageSizeOptions.map((size) => ({
15801
15935
  value: String(size),
15802
15936
  label: `${size} per page`,
15803
15937
  }));
@@ -15805,17 +15939,20 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15805
15939
  const renderPaginationControls = () => {
15806
15940
  if (!paginated)
15807
15941
  return null;
15808
- 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 }))] }));
15809
15943
  };
15810
15944
  // Determine if we should show card view
15811
- const shouldShowCardView = mobileView === 'card' ||
15812
- (mobileView === 'auto' && isMobileViewport);
15945
+ const shouldShowCardView = mobileView === "card" || (mobileView === "auto" && isMobileViewport);
15813
15946
  // Card view content
15814
15947
  const cardViewContent = shouldShowCardView ? (jsxRuntime.jsx(DataTableCardView, { data: data, columns: visibleColumns, cardConfig: cardConfig, loading: loading, loadingRows: loadingRows, emptyMessage: emptyMessage, onCardClick: onRowClick, onCardLongPress: (item, event) => {
15815
15948
  if (enableContextMenu && allActions.length > 0) {
15816
15949
  event.preventDefault();
15817
- const clientX = 'touches' in event ? event.touches[0].clientX : event.clientX;
15818
- 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;
15819
15956
  setContextMenuState({
15820
15957
  isOpen: true,
15821
15958
  position: { x: clientX, y: clientY },
@@ -15824,7 +15961,11 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
15824
15961
  }
15825
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;
15826
15963
  // Render with context menu
15827
- 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
+ }) }))] }));
15828
15969
  }
15829
15970
 
15830
15971
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
@@ -15863,52 +16004,44 @@ function getAugmentedNamespace(n) {
15863
16004
  * (A1, A1:C5, ...)
15864
16005
  */
15865
16006
 
15866
- var collection;
15867
- var hasRequiredCollection;
15868
-
15869
- function requireCollection () {
15870
- if (hasRequiredCollection) return collection;
15871
- hasRequiredCollection = 1;
15872
- class Collection {
16007
+ let Collection$3 = class Collection {
15873
16008
 
15874
- constructor(data, refs) {
15875
- if (data == null && refs == null) {
15876
- this._data = [];
15877
- this._refs = [];
15878
- } else {
15879
- if (data.length !== refs.length)
15880
- throw Error('Collection: data length should match references length.');
15881
- this._data = data;
15882
- this._refs = refs;
15883
- }
15884
- }
16009
+ constructor(data, refs) {
16010
+ if (data == null && refs == null) {
16011
+ this._data = [];
16012
+ this._refs = [];
16013
+ } else {
16014
+ if (data.length !== refs.length)
16015
+ throw Error('Collection: data length should match references length.');
16016
+ this._data = data;
16017
+ this._refs = refs;
16018
+ }
16019
+ }
15885
16020
 
15886
- get data() {
15887
- return this._data;
15888
- }
16021
+ get data() {
16022
+ return this._data;
16023
+ }
15889
16024
 
15890
- get refs() {
15891
- return this._refs;
15892
- }
16025
+ get refs() {
16026
+ return this._refs;
16027
+ }
15893
16028
 
15894
- get length() {
15895
- return this._data.length;
15896
- }
16029
+ get length() {
16030
+ return this._data.length;
16031
+ }
15897
16032
 
15898
- /**
15899
- * Add data and references to this collection.
15900
- * @param {{}} obj - data
15901
- * @param {{}} ref - reference
15902
- */
15903
- add(obj, ref) {
15904
- this._data.push(obj);
15905
- this._refs.push(ref);
15906
- }
15907
- }
16033
+ /**
16034
+ * Add data and references to this collection.
16035
+ * @param {{}} obj - data
16036
+ * @param {{}} ref - reference
16037
+ */
16038
+ add(obj, ref) {
16039
+ this._data.push(obj);
16040
+ this._refs.push(ref);
16041
+ }
16042
+ };
15908
16043
 
15909
- collection = Collection;
15910
- return collection;
15911
- }
16044
+ var collection = Collection$3;
15912
16045
 
15913
16046
  var helpers;
15914
16047
  var hasRequiredHelpers;
@@ -15917,7 +16050,7 @@ function requireHelpers () {
15917
16050
  if (hasRequiredHelpers) return helpers;
15918
16051
  hasRequiredHelpers = 1;
15919
16052
  const FormulaError = requireError();
15920
- const Collection = requireCollection();
16053
+ const Collection = collection;
15921
16054
 
15922
16055
  const Types = {
15923
16056
  NUMBER: 0,
@@ -25571,7 +25704,7 @@ var engineering = EngineeringFunctions;
25571
25704
 
25572
25705
  const FormulaError$b = requireError();
25573
25706
  const {FormulaHelpers: FormulaHelpers$8, Types: Types$6, WildCard, Address: Address$3} = requireHelpers();
25574
- const Collection$2 = requireCollection();
25707
+ const Collection$2 = collection;
25575
25708
  const H$5 = FormulaHelpers$8;
25576
25709
 
25577
25710
  const ReferenceFunctions$1 = {
@@ -37199,7 +37332,7 @@ var parsing = {
37199
37332
  const FormulaError$4 = requireError();
37200
37333
  const {Address: Address$1} = requireHelpers();
37201
37334
  const {Prefix: Prefix$1, Postfix: Postfix$1, Infix: Infix$1, Operators: Operators$1} = operators;
37202
- const Collection$1 = requireCollection();
37335
+ const Collection$1 = collection;
37203
37336
  const MAX_ROW$1 = 1048576, MAX_COLUMN$1 = 16384;
37204
37337
  const {NotAllInputParsedException} = require$$4;
37205
37338
 
@@ -37961,7 +38094,7 @@ var hooks$1 = {
37961
38094
  const FormulaError$2 = requireError();
37962
38095
  const {FormulaHelpers: FormulaHelpers$1, Types, Address} = requireHelpers();
37963
38096
  const {Prefix, Postfix, Infix, Operators} = operators;
37964
- const Collection = requireCollection();
38097
+ const Collection = collection;
37965
38098
  const MAX_ROW = 1048576, MAX_COLUMN = 16384;
37966
38099
 
37967
38100
  let Utils$1 = class Utils {