@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/components/DataTable.d.ts +29 -11
- package/dist/components/DataTable.d.ts.map +1 -1
- package/dist/index.d.ts +27 -9
- package/dist/index.esm.js +408 -275
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +408 -275
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/DataTable.tsx +993 -647
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 &&
|
|
14830
|
-
|
|
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(
|
|
14837
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
14836
14838
|
}
|
|
14837
14839
|
return () => {
|
|
14838
|
-
document.removeEventListener(
|
|
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, {
|
|
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(
|
|
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 ===
|
|
14869
|
-
?
|
|
14870
|
-
:
|
|
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 =
|
|
14891
|
+
style.width =
|
|
14892
|
+
typeof column.width === "number" ? `${column.width}px` : column.width;
|
|
14888
14893
|
}
|
|
14889
14894
|
if (column.minWidth !== undefined) {
|
|
14890
|
-
style.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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
15027
|
-
text:
|
|
15028
|
-
header:
|
|
15037
|
+
cell: "px-3 py-1",
|
|
15038
|
+
text: "text-xs",
|
|
15039
|
+
header: "px-3 py-2",
|
|
15029
15040
|
},
|
|
15030
15041
|
normal: {
|
|
15031
|
-
cell:
|
|
15032
|
-
text:
|
|
15033
|
-
header:
|
|
15042
|
+
cell: "px-6 py-1.5",
|
|
15043
|
+
text: "text-sm",
|
|
15044
|
+
header: "px-6 py-3",
|
|
15034
15045
|
},
|
|
15035
15046
|
comfortable: {
|
|
15036
|
-
cell:
|
|
15037
|
-
text:
|
|
15038
|
-
header:
|
|
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 ||
|
|
15047
|
-
|
|
15048
|
-
|
|
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(
|
|
15070
|
+
classes.push("animate-row-flash");
|
|
15056
15071
|
}
|
|
15057
15072
|
// Check for highlighted row
|
|
15058
|
-
else if (highlightedRowId !== undefined &&
|
|
15059
|
-
|
|
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
|
|
15072
|
-
|
|
15073
|
-
|
|
15074
|
-
|
|
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 ||
|
|
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 ===
|
|
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 =
|
|
15104
|
-
e.dataTransfer.setData(
|
|
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 =
|
|
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(
|
|
15151
|
-
document.addEventListener(
|
|
15169
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
15170
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
15152
15171
|
return () => {
|
|
15153
|
-
document.removeEventListener(
|
|
15154
|
-
document.removeEventListener(
|
|
15172
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
15173
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
15155
15174
|
};
|
|
15156
|
-
}, [
|
|
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:
|
|
15187
|
+
label: "Edit",
|
|
15163
15188
|
icon: lucideReact.Edit,
|
|
15164
15189
|
onClick: onEdit,
|
|
15165
|
-
variant:
|
|
15166
|
-
tooltip:
|
|
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 ||
|
|
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,
|
|
15202
|
+
handleExpansionWithMode(rowKey, "edit");
|
|
15178
15203
|
},
|
|
15179
|
-
variant:
|
|
15180
|
-
tooltip:
|
|
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 ||
|
|
15212
|
+
label: detailsConfig.menuLabel || "View Details",
|
|
15188
15213
|
icon: detailsConfig.menuIcon,
|
|
15189
15214
|
onClick: (item) => {
|
|
15190
15215
|
const rowKey = getRowKey(item);
|
|
15191
|
-
handleExpansionWithMode(rowKey,
|
|
15216
|
+
handleExpansionWithMode(rowKey, "details");
|
|
15192
15217
|
},
|
|
15193
|
-
variant:
|
|
15194
|
-
tooltip:
|
|
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:
|
|
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:
|
|
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:
|
|
15261
|
+
label: "Delete",
|
|
15237
15262
|
icon: lucideReact.Trash,
|
|
15238
15263
|
onClick: onDelete,
|
|
15239
|
-
variant:
|
|
15240
|
-
tooltip:
|
|
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, {
|
|
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 ===
|
|
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
|
|
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
|
|
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 ([
|
|
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 ||
|
|
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
|
|
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 ||
|
|
15408
|
+
setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue || "empty"}`);
|
|
15378
15409
|
}
|
|
15379
15410
|
break;
|
|
15380
|
-
case
|
|
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 ||
|
|
15419
|
+
setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue || "empty"}`);
|
|
15389
15420
|
}
|
|
15390
15421
|
break;
|
|
15391
|
-
case
|
|
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 ||
|
|
15430
|
+
setAnnouncement(`${colHeader}: ${cellValue || "empty"}`);
|
|
15400
15431
|
}
|
|
15401
15432
|
break;
|
|
15402
|
-
case
|
|
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 ||
|
|
15441
|
+
setAnnouncement(`${colHeader}: ${cellValue || "empty"}`);
|
|
15411
15442
|
}
|
|
15412
15443
|
break;
|
|
15413
|
-
case
|
|
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 ||
|
|
15456
|
+
setAnnouncement(`${visibleColumns[0]?.header || ""}: ${cellValue || "empty"}`);
|
|
15426
15457
|
}
|
|
15427
15458
|
break;
|
|
15428
|
-
case
|
|
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 ||
|
|
15474
|
+
setAnnouncement(`${visibleColumns[lastCol]?.header || ""}: ${cellValue || "empty"}`);
|
|
15444
15475
|
}
|
|
15445
15476
|
break;
|
|
15446
|
-
case
|
|
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(
|
|
15485
|
+
setAnnouncement("Opening edit mode");
|
|
15455
15486
|
}
|
|
15456
15487
|
else if (expandedRowConfig?.edit) {
|
|
15457
|
-
handleExpansionWithMode(rowKey,
|
|
15458
|
-
setAnnouncement(
|
|
15488
|
+
handleExpansionWithMode(rowKey, "edit");
|
|
15489
|
+
setAnnouncement("Opening inline edit");
|
|
15459
15490
|
}
|
|
15460
15491
|
else if (expandedRowConfig?.details) {
|
|
15461
|
-
handleExpansionWithMode(rowKey,
|
|
15462
|
-
setAnnouncement(
|
|
15492
|
+
handleExpansionWithMode(rowKey, "details");
|
|
15493
|
+
setAnnouncement("Opening details view");
|
|
15463
15494
|
}
|
|
15464
15495
|
else if (onRowDoubleClick) {
|
|
15465
15496
|
onRowDoubleClick(rowItem);
|
|
15466
|
-
setAnnouncement(
|
|
15497
|
+
setAnnouncement("Activating row");
|
|
15467
15498
|
}
|
|
15468
15499
|
else if (onRowClick) {
|
|
15469
15500
|
onRowClick(rowItem);
|
|
15470
|
-
setAnnouncement(
|
|
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 ?
|
|
15513
|
+
setAnnouncement(isNowSelected ? "Row selected" : "Row deselected");
|
|
15483
15514
|
}
|
|
15484
15515
|
break;
|
|
15485
|
-
case
|
|
15516
|
+
case "Escape":
|
|
15486
15517
|
e.preventDefault();
|
|
15487
15518
|
setFocusedCell(null);
|
|
15488
|
-
setAnnouncement(
|
|
15519
|
+
setAnnouncement("Table navigation exited");
|
|
15489
15520
|
// Return focus to table container
|
|
15490
|
-
tableBodyRef.current?.closest(
|
|
15521
|
+
tableBodyRef.current?.closest("table")?.focus();
|
|
15491
15522
|
break;
|
|
15492
|
-
case
|
|
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
|
|
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
|
-
}, [
|
|
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(
|
|
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) +
|
|
15526
|
-
|
|
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:
|
|
15577
|
+
targetCell.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
15532
15578
|
}
|
|
15533
15579
|
}
|
|
15534
15580
|
}
|
|
15535
|
-
}, [
|
|
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 ===
|
|
15544
|
-
onSortChange({
|
|
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:
|
|
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 ===
|
|
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}` :
|
|
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}` :
|
|
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 +
|
|
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 +
|
|
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
|
|
15616
|
-
|
|
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 ?
|
|
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 ?
|
|
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,
|
|
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,
|
|
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 &&
|
|
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 &&
|
|
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
|
|
15660
|
-
|
|
15661
|
-
|
|
15662
|
-
|
|
15663
|
-
|
|
15664
|
-
|
|
15665
|
-
|
|
15666
|
-
|
|
15667
|
-
|
|
15668
|
-
|
|
15669
|
-
|
|
15670
|
-
|
|
15671
|
-
|
|
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 &&
|
|
15751
|
+
if (expandedRowConfig?.details &&
|
|
15752
|
+
expandedRowConfig.details.triggerOnExpand !== false) {
|
|
15674
15753
|
// Trigger details mode if configured
|
|
15675
|
-
handleExpansionWithMode(rowKey,
|
|
15754
|
+
handleExpansionWithMode(rowKey, "details");
|
|
15676
15755
|
}
|
|
15677
|
-
else if (expandedRowConfig?.edit &&
|
|
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,
|
|
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 ||
|
|
15686
|
-
|
|
15687
|
-
|
|
15688
|
-
|
|
15689
|
-
|
|
15690
|
-
|
|
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 ===
|
|
15780
|
+
const value = typeof column.key === "string"
|
|
15694
15781
|
? item[column.key]
|
|
15695
15782
|
: item[column.key];
|
|
15696
|
-
const primaryContent = column.render
|
|
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 ?
|
|
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 ||
|
|
15703
|
-
})] }), hasSecondaryRow && (jsxRuntime.jsx("tr", { className: `secondary-row ${isSelected ?
|
|
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 ===
|
|
15804
|
+
const value = typeof column.key === "string"
|
|
15707
15805
|
? item[column.key]
|
|
15708
15806
|
: item[column.key];
|
|
15709
|
-
const secondaryContent = column.renderSecondary
|
|
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 ?
|
|
15713
|
-
return (jsxRuntime.jsx("td", { className: `${currentDensity.cell} py-0.5 ${paddingClass} ${column.className ||
|
|
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
|
-
((
|
|
15717
|
-
|
|
15718
|
-
|
|
15719
|
-
|
|
15720
|
-
|
|
15721
|
-
|
|
15722
|
-
|
|
15723
|
-
|
|
15724
|
-
content =
|
|
15725
|
-
|
|
15726
|
-
|
|
15727
|
-
|
|
15728
|
-
|
|
15729
|
-
|
|
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
|
-
|
|
15753
|
-
|
|
15754
|
-
|
|
15755
|
-
|
|
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
|
-
|
|
15763
|
-
|
|
15764
|
-
|
|
15765
|
-
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
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 ?
|
|
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}` :
|
|
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 ?
|
|
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}` :
|
|
15786
|
-
${reorderable ?
|
|
15787
|
-
${isDragging ?
|
|
15788
|
-
${isDragOver ?
|
|
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
|
|
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:
|
|
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 ", (
|
|
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 ===
|
|
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 =
|
|
15818
|
-
|
|
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({
|
|
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
|
-
|
|
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
|
-
|
|
15875
|
-
|
|
15876
|
-
|
|
15877
|
-
|
|
15878
|
-
|
|
15879
|
-
|
|
15880
|
-
|
|
15881
|
-
|
|
15882
|
-
|
|
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
|
-
|
|
15887
|
-
|
|
15888
|
-
|
|
16021
|
+
get data() {
|
|
16022
|
+
return this._data;
|
|
16023
|
+
}
|
|
15889
16024
|
|
|
15890
|
-
|
|
15891
|
-
|
|
15892
|
-
|
|
16025
|
+
get refs() {
|
|
16026
|
+
return this._refs;
|
|
16027
|
+
}
|
|
15893
16028
|
|
|
15894
|
-
|
|
15895
|
-
|
|
15896
|
-
|
|
16029
|
+
get length() {
|
|
16030
|
+
return this._data.length;
|
|
16031
|
+
}
|
|
15897
16032
|
|
|
15898
|
-
|
|
15899
|
-
|
|
15900
|
-
|
|
15901
|
-
|
|
15902
|
-
|
|
15903
|
-
|
|
15904
|
-
|
|
15905
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
38097
|
+
const Collection = collection;
|
|
37965
38098
|
const MAX_ROW = 1048576, MAX_COLUMN = 16384;
|
|
37966
38099
|
|
|
37967
38100
|
let Utils$1 = class Utils {
|