@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.esm.js
CHANGED
|
@@ -14806,25 +14806,27 @@ function ActionMenu({ actions, item, }) {
|
|
|
14806
14806
|
// Click outside handler
|
|
14807
14807
|
useEffect(() => {
|
|
14808
14808
|
const handleClickOutside = (event) => {
|
|
14809
|
-
if (menuRef.current &&
|
|
14810
|
-
|
|
14809
|
+
if (menuRef.current &&
|
|
14810
|
+
!menuRef.current.contains(event.target) &&
|
|
14811
|
+
buttonRef.current &&
|
|
14812
|
+
!buttonRef.current.contains(event.target)) {
|
|
14811
14813
|
setIsOpen(false);
|
|
14812
14814
|
}
|
|
14813
14815
|
};
|
|
14814
14816
|
if (isOpen) {
|
|
14815
|
-
document.addEventListener(
|
|
14817
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
14816
14818
|
}
|
|
14817
14819
|
return () => {
|
|
14818
|
-
document.removeEventListener(
|
|
14820
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
14819
14821
|
};
|
|
14820
14822
|
}, [isOpen]);
|
|
14821
|
-
const visibleActions = actions.filter(action => !action.show || action.show(item));
|
|
14823
|
+
const visibleActions = actions.filter((action) => !action.show || action.show(item));
|
|
14822
14824
|
if (visibleActions.length === 0)
|
|
14823
14825
|
return null;
|
|
14824
14826
|
const dropdownContent = isOpen && (jsx("div", { ref: menuRef, className: "fixed w-56 bg-white rounded-lg shadow-lg border border-paper-300 py-1", style: {
|
|
14825
14827
|
zIndex: 999999,
|
|
14826
14828
|
top: `${position.top}px`,
|
|
14827
|
-
left: `${position.left}px
|
|
14829
|
+
left: `${position.left}px`,
|
|
14828
14830
|
}, children: visibleActions.map((action, idx) => {
|
|
14829
14831
|
let iconElement = null;
|
|
14830
14832
|
if (action.icon) {
|
|
@@ -14832,7 +14834,9 @@ function ActionMenu({ actions, item, }) {
|
|
|
14832
14834
|
iconElement = action.icon;
|
|
14833
14835
|
}
|
|
14834
14836
|
else {
|
|
14835
|
-
iconElement = React__default.createElement(action.icon, {
|
|
14837
|
+
iconElement = React__default.createElement(action.icon, {
|
|
14838
|
+
className: "h-4 w-4 flex-shrink-0",
|
|
14839
|
+
});
|
|
14836
14840
|
}
|
|
14837
14841
|
}
|
|
14838
14842
|
return (jsxs("button", { type: "button", onClick: async (e) => {
|
|
@@ -14842,12 +14846,12 @@ function ActionMenu({ actions, item, }) {
|
|
|
14842
14846
|
await action.onClick(item);
|
|
14843
14847
|
}
|
|
14844
14848
|
catch (error) {
|
|
14845
|
-
console.error(
|
|
14849
|
+
console.error("DataTable action error:", error);
|
|
14846
14850
|
}
|
|
14847
14851
|
setIsOpen(false);
|
|
14848
|
-
}, className: `w-full flex items-center gap-3 px-4 py-2.5 text-sm transition-colors ${action.variant ===
|
|
14849
|
-
?
|
|
14850
|
-
:
|
|
14852
|
+
}, className: `w-full flex items-center gap-3 px-4 py-2.5 text-sm transition-colors ${action.variant === "danger"
|
|
14853
|
+
? "text-error-600 hover:bg-error-50 hover:text-error-700"
|
|
14854
|
+
: "text-ink-700 hover:bg-paper-50"}`, title: action.tooltip, children: [iconElement, jsx("span", { className: "flex-1 text-left", children: action.label })] }, idx));
|
|
14851
14855
|
}) }));
|
|
14852
14856
|
return (jsxs(Fragment, { children: [jsx("button", { ref: buttonRef, onClick: (e) => {
|
|
14853
14857
|
e.stopPropagation();
|
|
@@ -14864,13 +14868,20 @@ function getColumnStyle(column, dynamicWidth) {
|
|
|
14864
14868
|
style.width = `${dynamicWidth}px`;
|
|
14865
14869
|
}
|
|
14866
14870
|
else if (column.width !== undefined) {
|
|
14867
|
-
style.width =
|
|
14871
|
+
style.width =
|
|
14872
|
+
typeof column.width === "number" ? `${column.width}px` : column.width;
|
|
14868
14873
|
}
|
|
14869
14874
|
if (column.minWidth !== undefined) {
|
|
14870
|
-
style.minWidth =
|
|
14875
|
+
style.minWidth =
|
|
14876
|
+
typeof column.minWidth === "number"
|
|
14877
|
+
? `${column.minWidth}px`
|
|
14878
|
+
: column.minWidth;
|
|
14871
14879
|
}
|
|
14872
14880
|
if (column.maxWidth !== undefined) {
|
|
14873
|
-
style.maxWidth =
|
|
14881
|
+
style.maxWidth =
|
|
14882
|
+
typeof column.maxWidth === "number"
|
|
14883
|
+
? `${column.maxWidth}px`
|
|
14884
|
+
: column.maxWidth;
|
|
14874
14885
|
}
|
|
14875
14886
|
if (column.flex !== undefined) {
|
|
14876
14887
|
style.flexGrow = column.flex;
|
|
@@ -14929,13 +14940,13 @@ function getColumnStyle(column, dynamicWidth) {
|
|
|
14929
14940
|
* />
|
|
14930
14941
|
* ```
|
|
14931
14942
|
*/
|
|
14932
|
-
function DataTable({ data, columns, loading = false, error = null, emptyMessage =
|
|
14943
|
+
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,
|
|
14933
14944
|
// Visual customization props
|
|
14934
|
-
striped = false, stripedColor, density =
|
|
14945
|
+
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,
|
|
14935
14946
|
// Pagination props
|
|
14936
14947
|
paginated = false, currentPage = 1, pageSize = 10, totalItems, onPageChange, pageSizeOptions = [10, 25, 50, 100], onPageSizeChange, showPageSizeSelector = true,
|
|
14937
14948
|
// Mobile view props
|
|
14938
|
-
mobileView =
|
|
14949
|
+
mobileView = "auto", cardConfig, cardGap = "md", cardClassName, }) {
|
|
14939
14950
|
// Mobile detection for auto mode
|
|
14940
14951
|
const isMobileViewport = useIsMobile();
|
|
14941
14952
|
// Column resizing state
|
|
@@ -14954,7 +14965,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
14954
14965
|
const [hoveredRowKey, setHoveredRowKey] = useState(null);
|
|
14955
14966
|
// Keyboard navigation state
|
|
14956
14967
|
const [focusedCell, setFocusedCell] = useState(null);
|
|
14957
|
-
const [announcement, setAnnouncement] = useState(
|
|
14968
|
+
const [announcement, setAnnouncement] = useState("");
|
|
14958
14969
|
const tableBodyRef = useRef(null);
|
|
14959
14970
|
// Temporary row highlight state (for flash animation)
|
|
14960
14971
|
const [flashingRows, setFlashingRows] = useState(new Set());
|
|
@@ -14966,18 +14977,18 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
14966
14977
|
item: null,
|
|
14967
14978
|
});
|
|
14968
14979
|
// Filter columns based on hiddenColumns
|
|
14969
|
-
const baseVisibleColumns = columns.filter(col => !hiddenColumns.includes(String(col.key)));
|
|
14980
|
+
const baseVisibleColumns = columns.filter((col) => !hiddenColumns.includes(String(col.key)));
|
|
14970
14981
|
// Initialize column order on mount or when columns change
|
|
14971
14982
|
useEffect(() => {
|
|
14972
14983
|
if (columnOrder.length === 0) {
|
|
14973
|
-
setColumnOrder(baseVisibleColumns.map(col => String(col.key)));
|
|
14984
|
+
setColumnOrder(baseVisibleColumns.map((col) => String(col.key)));
|
|
14974
14985
|
}
|
|
14975
14986
|
}, [baseVisibleColumns, columnOrder.length]);
|
|
14976
14987
|
// Handle temporary row highlighting (flash animation)
|
|
14977
14988
|
useEffect(() => {
|
|
14978
14989
|
if (highlightedRows.length > 0) {
|
|
14979
14990
|
// Add new highlighted rows to flashing set
|
|
14980
|
-
const newFlashingRows = new Set(highlightedRows.map(id => String(id)));
|
|
14991
|
+
const newFlashingRows = new Set(highlightedRows.map((id) => String(id)));
|
|
14981
14992
|
setFlashingRows(newFlashingRows);
|
|
14982
14993
|
// Clear any existing timeout
|
|
14983
14994
|
if (flashTimeoutRef.current) {
|
|
@@ -14997,25 +15008,25 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
14997
15008
|
// Apply column order
|
|
14998
15009
|
const visibleColumns = reorderable && columnOrder.length > 0
|
|
14999
15010
|
? columnOrder
|
|
15000
|
-
.map(key => baseVisibleColumns.find(col => String(col.key) === key))
|
|
15011
|
+
.map((key) => baseVisibleColumns.find((col) => String(col.key) === key))
|
|
15001
15012
|
.filter((col) => col !== undefined)
|
|
15002
15013
|
: baseVisibleColumns;
|
|
15003
15014
|
// Density classes
|
|
15004
15015
|
const densityClasses = {
|
|
15005
15016
|
compact: {
|
|
15006
|
-
cell:
|
|
15007
|
-
text:
|
|
15008
|
-
header:
|
|
15017
|
+
cell: "px-3 py-1",
|
|
15018
|
+
text: "text-xs",
|
|
15019
|
+
header: "px-3 py-2",
|
|
15009
15020
|
},
|
|
15010
15021
|
normal: {
|
|
15011
|
-
cell:
|
|
15012
|
-
text:
|
|
15013
|
-
header:
|
|
15022
|
+
cell: "px-6 py-1.5",
|
|
15023
|
+
text: "text-sm",
|
|
15024
|
+
header: "px-6 py-3",
|
|
15014
15025
|
},
|
|
15015
15026
|
comfortable: {
|
|
15016
|
-
cell:
|
|
15017
|
-
text:
|
|
15018
|
-
header:
|
|
15027
|
+
cell: "px-6 py-3",
|
|
15028
|
+
text: "text-base",
|
|
15029
|
+
header: "px-6 py-4",
|
|
15019
15030
|
},
|
|
15020
15031
|
};
|
|
15021
15032
|
const currentDensity = densityClasses[density];
|
|
@@ -15023,20 +15034,25 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15023
15034
|
const getRowKey = keyExtractor || ((row) => String(row.id));
|
|
15024
15035
|
// Calculate if there are any actions (for keyboard navigation column calculation)
|
|
15025
15036
|
// This is computed early so it can be used in keyboard handlers
|
|
15026
|
-
const hasAnyActions = !!(onEdit ||
|
|
15027
|
-
|
|
15028
|
-
|
|
15037
|
+
const hasAnyActions = !!(onEdit ||
|
|
15038
|
+
onDelete ||
|
|
15039
|
+
actions.length > 0 ||
|
|
15040
|
+
expandedRowConfig?.edit ||
|
|
15041
|
+
expandedRowConfig?.details ||
|
|
15042
|
+
expandedRowConfig?.addRelated?.length ||
|
|
15043
|
+
expandedRowConfig?.manageRelated?.length);
|
|
15029
15044
|
// Get row background class based on striping and highlighting
|
|
15030
15045
|
const getRowBackgroundClass = (item, index) => {
|
|
15031
15046
|
const classes = [];
|
|
15032
15047
|
const rowKey = getRowKey(item);
|
|
15033
15048
|
// Check for temporary flash highlight (takes priority)
|
|
15034
15049
|
if (flashingRows.has(rowKey)) {
|
|
15035
|
-
classes.push(
|
|
15050
|
+
classes.push("animate-row-flash");
|
|
15036
15051
|
}
|
|
15037
15052
|
// Check for highlighted row
|
|
15038
|
-
else if (highlightedRowId !== undefined &&
|
|
15039
|
-
|
|
15053
|
+
else if (highlightedRowId !== undefined &&
|
|
15054
|
+
rowKey === String(highlightedRowId)) {
|
|
15055
|
+
classes.push("bg-accent-100");
|
|
15040
15056
|
}
|
|
15041
15057
|
// Check for custom row highlight
|
|
15042
15058
|
else if (rowHighlight) {
|
|
@@ -15048,24 +15064,27 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15048
15064
|
// Check for striping
|
|
15049
15065
|
else if (striped) {
|
|
15050
15066
|
const isOdd = index % 2 === 0; // 0-indexed, so even index = odd row
|
|
15051
|
-
const shouldStripe = striped === true
|
|
15052
|
-
|
|
15053
|
-
|
|
15054
|
-
|
|
15067
|
+
const shouldStripe = striped === true
|
|
15068
|
+
? isOdd
|
|
15069
|
+
: striped === "odd"
|
|
15070
|
+
? isOdd
|
|
15071
|
+
: striped === "even"
|
|
15072
|
+
? !isOdd
|
|
15073
|
+
: false;
|
|
15055
15074
|
if (shouldStripe) {
|
|
15056
|
-
classes.push(stripedColor ||
|
|
15075
|
+
classes.push(stripedColor || "bg-paper-50");
|
|
15057
15076
|
}
|
|
15058
15077
|
}
|
|
15059
15078
|
// Add custom row class
|
|
15060
15079
|
if (rowClassName) {
|
|
15061
|
-
if (typeof rowClassName ===
|
|
15080
|
+
if (typeof rowClassName === "string") {
|
|
15062
15081
|
classes.push(rowClassName);
|
|
15063
15082
|
}
|
|
15064
15083
|
else {
|
|
15065
15084
|
classes.push(rowClassName(item, index));
|
|
15066
15085
|
}
|
|
15067
15086
|
}
|
|
15068
|
-
return classes.join(
|
|
15087
|
+
return classes.join(" ");
|
|
15069
15088
|
};
|
|
15070
15089
|
// NEW: Expansion mode state management (for expandedRowConfig)
|
|
15071
15090
|
const [expansionState, setExpansionState] = useState(null);
|
|
@@ -15080,12 +15099,12 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15080
15099
|
// Column reorder handlers
|
|
15081
15100
|
const handleDragStart = (e, columnKey) => {
|
|
15082
15101
|
setDraggingColumn(columnKey);
|
|
15083
|
-
e.dataTransfer.effectAllowed =
|
|
15084
|
-
e.dataTransfer.setData(
|
|
15102
|
+
e.dataTransfer.effectAllowed = "move";
|
|
15103
|
+
e.dataTransfer.setData("text/html", columnKey);
|
|
15085
15104
|
};
|
|
15086
15105
|
const handleDragOver = (e, columnKey) => {
|
|
15087
15106
|
e.preventDefault();
|
|
15088
|
-
e.dataTransfer.dropEffect =
|
|
15107
|
+
e.dataTransfer.dropEffect = "move";
|
|
15089
15108
|
if (draggingColumn && draggingColumn !== columnKey) {
|
|
15090
15109
|
setDragOverColumn(columnKey);
|
|
15091
15110
|
}
|
|
@@ -15116,7 +15135,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15116
15135
|
const handleMouseMove = (e) => {
|
|
15117
15136
|
const delta = e.clientX - resizeStartX;
|
|
15118
15137
|
const newWidth = Math.max(50, resizeStartWidth + delta); // Min width 50px
|
|
15119
|
-
setColumnWidths(prev => ({
|
|
15138
|
+
setColumnWidths((prev) => ({
|
|
15120
15139
|
...prev,
|
|
15121
15140
|
[resizingColumn]: newWidth,
|
|
15122
15141
|
}));
|
|
@@ -15127,56 +15146,62 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15127
15146
|
}
|
|
15128
15147
|
setResizingColumn(null);
|
|
15129
15148
|
};
|
|
15130
|
-
document.addEventListener(
|
|
15131
|
-
document.addEventListener(
|
|
15149
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
15150
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
15132
15151
|
return () => {
|
|
15133
|
-
document.removeEventListener(
|
|
15134
|
-
document.removeEventListener(
|
|
15152
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
15153
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
15135
15154
|
};
|
|
15136
|
-
}, [
|
|
15155
|
+
}, [
|
|
15156
|
+
resizingColumn,
|
|
15157
|
+
resizeStartX,
|
|
15158
|
+
resizeStartWidth,
|
|
15159
|
+
columnWidths,
|
|
15160
|
+
onColumnResize,
|
|
15161
|
+
]);
|
|
15137
15162
|
// Build combined actions: built-in edit/delete + custom actions + expansion mode actions
|
|
15138
15163
|
const builtInActions = [];
|
|
15139
15164
|
// Legacy onEdit (still supported)
|
|
15140
15165
|
if (onEdit) {
|
|
15141
15166
|
builtInActions.push({
|
|
15142
|
-
label:
|
|
15167
|
+
label: "Edit",
|
|
15143
15168
|
icon: Edit,
|
|
15144
15169
|
onClick: onEdit,
|
|
15145
|
-
variant:
|
|
15146
|
-
tooltip:
|
|
15170
|
+
variant: "secondary",
|
|
15171
|
+
tooltip: "Edit item",
|
|
15147
15172
|
});
|
|
15148
15173
|
}
|
|
15149
15174
|
// NEW: Edit mode from expandedRowConfig
|
|
15150
15175
|
if (expandedRowConfig?.edit && !onEdit) {
|
|
15151
15176
|
const editConfig = expandedRowConfig.edit;
|
|
15152
15177
|
builtInActions.push({
|
|
15153
|
-
label: editConfig.menuLabel ||
|
|
15178
|
+
label: editConfig.menuLabel || "Edit",
|
|
15154
15179
|
icon: editConfig.menuIcon || Edit,
|
|
15155
15180
|
onClick: (item) => {
|
|
15156
15181
|
const rowKey = getRowKey(item);
|
|
15157
|
-
handleExpansionWithMode(rowKey,
|
|
15182
|
+
handleExpansionWithMode(rowKey, "edit");
|
|
15158
15183
|
},
|
|
15159
|
-
variant:
|
|
15160
|
-
tooltip:
|
|
15184
|
+
variant: "secondary",
|
|
15185
|
+
tooltip: "Edit inline",
|
|
15161
15186
|
});
|
|
15162
15187
|
}
|
|
15163
15188
|
// NEW: View details mode from expandedRowConfig
|
|
15164
15189
|
if (expandedRowConfig?.details) {
|
|
15165
15190
|
const detailsConfig = expandedRowConfig.details;
|
|
15166
15191
|
builtInActions.push({
|
|
15167
|
-
label: detailsConfig.menuLabel ||
|
|
15192
|
+
label: detailsConfig.menuLabel || "View Details",
|
|
15168
15193
|
icon: detailsConfig.menuIcon,
|
|
15169
15194
|
onClick: (item) => {
|
|
15170
15195
|
const rowKey = getRowKey(item);
|
|
15171
|
-
handleExpansionWithMode(rowKey,
|
|
15196
|
+
handleExpansionWithMode(rowKey, "details");
|
|
15172
15197
|
},
|
|
15173
|
-
variant:
|
|
15174
|
-
tooltip:
|
|
15198
|
+
variant: "ghost",
|
|
15199
|
+
tooltip: "View details",
|
|
15175
15200
|
});
|
|
15176
15201
|
}
|
|
15177
15202
|
// NEW: Add related modes from expandedRowConfig
|
|
15178
15203
|
if (expandedRowConfig?.addRelated) {
|
|
15179
|
-
expandedRowConfig.addRelated.forEach(config => {
|
|
15204
|
+
expandedRowConfig.addRelated.forEach((config) => {
|
|
15180
15205
|
if (config.showInMenu !== false) {
|
|
15181
15206
|
builtInActions.push({
|
|
15182
15207
|
label: config.label,
|
|
@@ -15185,15 +15210,15 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15185
15210
|
const rowKey = getRowKey(item);
|
|
15186
15211
|
handleExpansionWithMode(rowKey, `addRelated-${config.key}`);
|
|
15187
15212
|
},
|
|
15188
|
-
variant:
|
|
15189
|
-
tooltip: config.label
|
|
15213
|
+
variant: "secondary",
|
|
15214
|
+
tooltip: config.label,
|
|
15190
15215
|
});
|
|
15191
15216
|
}
|
|
15192
15217
|
});
|
|
15193
15218
|
}
|
|
15194
15219
|
// NEW: Manage related modes from expandedRowConfig
|
|
15195
15220
|
if (expandedRowConfig?.manageRelated) {
|
|
15196
|
-
expandedRowConfig.manageRelated.forEach(config => {
|
|
15221
|
+
expandedRowConfig.manageRelated.forEach((config) => {
|
|
15197
15222
|
if (config.showInMenu !== false) {
|
|
15198
15223
|
builtInActions.push({
|
|
15199
15224
|
label: config.label,
|
|
@@ -15202,8 +15227,8 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15202
15227
|
const rowKey = getRowKey(item);
|
|
15203
15228
|
handleExpansionWithMode(rowKey, `manageRelated-${config.key}`);
|
|
15204
15229
|
},
|
|
15205
|
-
variant:
|
|
15206
|
-
tooltip: config.label
|
|
15230
|
+
variant: "ghost",
|
|
15231
|
+
tooltip: config.label,
|
|
15207
15232
|
});
|
|
15208
15233
|
}
|
|
15209
15234
|
});
|
|
@@ -15213,11 +15238,11 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15213
15238
|
let deleteAction = null;
|
|
15214
15239
|
if (onDelete) {
|
|
15215
15240
|
deleteAction = {
|
|
15216
|
-
label:
|
|
15241
|
+
label: "Delete",
|
|
15217
15242
|
icon: Trash,
|
|
15218
15243
|
onClick: onDelete,
|
|
15219
|
-
variant:
|
|
15220
|
-
tooltip:
|
|
15244
|
+
variant: "danger",
|
|
15245
|
+
tooltip: "Delete item",
|
|
15221
15246
|
};
|
|
15222
15247
|
}
|
|
15223
15248
|
// Build final actions array with consistent ordering:
|
|
@@ -15230,11 +15255,11 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15230
15255
|
const allActions = [
|
|
15231
15256
|
...builtInActions,
|
|
15232
15257
|
...actions,
|
|
15233
|
-
...(deleteAction ? [deleteAction] : [])
|
|
15258
|
+
...(deleteAction ? [deleteAction] : []),
|
|
15234
15259
|
];
|
|
15235
15260
|
// Convert actions to menu items for context menu
|
|
15236
15261
|
const convertActionsToMenuItems = (item) => {
|
|
15237
|
-
const visibleActions = allActions.filter(action => !action.show || action.show(item));
|
|
15262
|
+
const visibleActions = allActions.filter((action) => !action.show || action.show(item));
|
|
15238
15263
|
return visibleActions.map((action, idx) => {
|
|
15239
15264
|
let iconElement = null;
|
|
15240
15265
|
if (action.icon) {
|
|
@@ -15242,7 +15267,9 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15242
15267
|
iconElement = action.icon;
|
|
15243
15268
|
}
|
|
15244
15269
|
else {
|
|
15245
|
-
iconElement = React__default.createElement(action.icon, {
|
|
15270
|
+
iconElement = React__default.createElement(action.icon, {
|
|
15271
|
+
className: "h-4 w-4",
|
|
15272
|
+
});
|
|
15246
15273
|
}
|
|
15247
15274
|
}
|
|
15248
15275
|
return {
|
|
@@ -15250,7 +15277,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15250
15277
|
label: action.label,
|
|
15251
15278
|
icon: iconElement,
|
|
15252
15279
|
onClick: () => action.onClick(item),
|
|
15253
|
-
danger: action.variant ===
|
|
15280
|
+
danger: action.variant === "danger",
|
|
15254
15281
|
};
|
|
15255
15282
|
});
|
|
15256
15283
|
};
|
|
@@ -15259,7 +15286,9 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15259
15286
|
// Expansion state management
|
|
15260
15287
|
const [internalExpandedRows, setInternalExpandedRows] = useState(new Set());
|
|
15261
15288
|
// Use external selection if provided, otherwise internal
|
|
15262
|
-
const selectedRowsSet = externalSelectedRows !== undefined
|
|
15289
|
+
const selectedRowsSet = externalSelectedRows !== undefined
|
|
15290
|
+
? externalSelectedRows
|
|
15291
|
+
: internalSelectedRows;
|
|
15263
15292
|
const setSelectedRows = (newSet) => {
|
|
15264
15293
|
if (externalSelectedRows !== undefined) {
|
|
15265
15294
|
// Controlled component - notify parent
|
|
@@ -15293,7 +15322,9 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15293
15322
|
}
|
|
15294
15323
|
};
|
|
15295
15324
|
// Use external expansion if provided, otherwise internal
|
|
15296
|
-
const expandedRowsSet = externalExpandedRows !== undefined
|
|
15325
|
+
const expandedRowsSet = externalExpandedRows !== undefined
|
|
15326
|
+
? externalExpandedRows
|
|
15327
|
+
: internalExpandedRows;
|
|
15297
15328
|
const setExpandedRows = (newSet) => {
|
|
15298
15329
|
if (externalExpandedRows !== undefined) ;
|
|
15299
15330
|
else {
|
|
@@ -15335,10 +15366,10 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15335
15366
|
const totalCols = visibleColumns.length;
|
|
15336
15367
|
// If no cell is focused, focus first data cell on first arrow key
|
|
15337
15368
|
if (!focusedCell) {
|
|
15338
|
-
if ([
|
|
15369
|
+
if (["ArrowDown", "ArrowUp", "ArrowLeft", "ArrowRight"].includes(e.key)) {
|
|
15339
15370
|
e.preventDefault();
|
|
15340
15371
|
setFocusedCell({ row: 0, col: 0 });
|
|
15341
|
-
const colHeader = visibleColumns[0]?.header ||
|
|
15372
|
+
const colHeader = visibleColumns[0]?.header || "first column";
|
|
15342
15373
|
setAnnouncement(`Row 1, ${colHeader}`);
|
|
15343
15374
|
return;
|
|
15344
15375
|
}
|
|
@@ -15346,73 +15377,73 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15346
15377
|
}
|
|
15347
15378
|
const { row, col } = focusedCell;
|
|
15348
15379
|
switch (e.key) {
|
|
15349
|
-
case
|
|
15380
|
+
case "ArrowDown":
|
|
15350
15381
|
e.preventDefault();
|
|
15351
15382
|
if (row < totalRows - 1) {
|
|
15352
15383
|
const newRow = row + 1;
|
|
15353
15384
|
setFocusedCell({ row: newRow, col });
|
|
15354
15385
|
const rowItem = data[newRow];
|
|
15355
|
-
const colHeader = visibleColumns[col]?.header ||
|
|
15386
|
+
const colHeader = visibleColumns[col]?.header || "";
|
|
15356
15387
|
const cellValue = rowItem[visibleColumns[col]?.key];
|
|
15357
|
-
setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue ||
|
|
15388
|
+
setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue || "empty"}`);
|
|
15358
15389
|
}
|
|
15359
15390
|
break;
|
|
15360
|
-
case
|
|
15391
|
+
case "ArrowUp":
|
|
15361
15392
|
e.preventDefault();
|
|
15362
15393
|
if (row > 0) {
|
|
15363
15394
|
const newRow = row - 1;
|
|
15364
15395
|
setFocusedCell({ row: newRow, col });
|
|
15365
15396
|
const rowItem = data[newRow];
|
|
15366
|
-
const colHeader = visibleColumns[col]?.header ||
|
|
15397
|
+
const colHeader = visibleColumns[col]?.header || "";
|
|
15367
15398
|
const cellValue = rowItem[visibleColumns[col]?.key];
|
|
15368
|
-
setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue ||
|
|
15399
|
+
setAnnouncement(`Row ${newRow + 1}, ${colHeader}: ${cellValue || "empty"}`);
|
|
15369
15400
|
}
|
|
15370
15401
|
break;
|
|
15371
|
-
case
|
|
15402
|
+
case "ArrowRight":
|
|
15372
15403
|
e.preventDefault();
|
|
15373
15404
|
if (col < totalCols - 1) {
|
|
15374
15405
|
const newCol = col + 1;
|
|
15375
15406
|
setFocusedCell({ row, col: newCol });
|
|
15376
15407
|
const rowItem = data[row];
|
|
15377
|
-
const colHeader = visibleColumns[newCol]?.header ||
|
|
15408
|
+
const colHeader = visibleColumns[newCol]?.header || "";
|
|
15378
15409
|
const cellValue = rowItem[visibleColumns[newCol]?.key];
|
|
15379
|
-
setAnnouncement(`${colHeader}: ${cellValue ||
|
|
15410
|
+
setAnnouncement(`${colHeader}: ${cellValue || "empty"}`);
|
|
15380
15411
|
}
|
|
15381
15412
|
break;
|
|
15382
|
-
case
|
|
15413
|
+
case "ArrowLeft":
|
|
15383
15414
|
e.preventDefault();
|
|
15384
15415
|
if (col > 0) {
|
|
15385
15416
|
const newCol = col - 1;
|
|
15386
15417
|
setFocusedCell({ row, col: newCol });
|
|
15387
15418
|
const rowItem = data[row];
|
|
15388
|
-
const colHeader = visibleColumns[newCol]?.header ||
|
|
15419
|
+
const colHeader = visibleColumns[newCol]?.header || "";
|
|
15389
15420
|
const cellValue = rowItem[visibleColumns[newCol]?.key];
|
|
15390
|
-
setAnnouncement(`${colHeader}: ${cellValue ||
|
|
15421
|
+
setAnnouncement(`${colHeader}: ${cellValue || "empty"}`);
|
|
15391
15422
|
}
|
|
15392
15423
|
break;
|
|
15393
|
-
case
|
|
15424
|
+
case "Home":
|
|
15394
15425
|
e.preventDefault();
|
|
15395
15426
|
if (e.ctrlKey) {
|
|
15396
15427
|
// Ctrl+Home: Go to first cell
|
|
15397
15428
|
setFocusedCell({ row: 0, col: 0 });
|
|
15398
|
-
setAnnouncement(`First cell, Row 1, ${visibleColumns[0]?.header ||
|
|
15429
|
+
setAnnouncement(`First cell, Row 1, ${visibleColumns[0]?.header || ""}`);
|
|
15399
15430
|
}
|
|
15400
15431
|
else {
|
|
15401
15432
|
// Home: Go to first cell in current row
|
|
15402
15433
|
setFocusedCell({ row, col: 0 });
|
|
15403
15434
|
const rowItem = data[row];
|
|
15404
15435
|
const cellValue = rowItem[visibleColumns[0]?.key];
|
|
15405
|
-
setAnnouncement(`${visibleColumns[0]?.header ||
|
|
15436
|
+
setAnnouncement(`${visibleColumns[0]?.header || ""}: ${cellValue || "empty"}`);
|
|
15406
15437
|
}
|
|
15407
15438
|
break;
|
|
15408
|
-
case
|
|
15439
|
+
case "End":
|
|
15409
15440
|
e.preventDefault();
|
|
15410
15441
|
if (e.ctrlKey) {
|
|
15411
15442
|
// Ctrl+End: Go to last cell
|
|
15412
15443
|
const lastRow = totalRows - 1;
|
|
15413
15444
|
const lastCol = totalCols - 1;
|
|
15414
15445
|
setFocusedCell({ row: lastRow, col: lastCol });
|
|
15415
|
-
setAnnouncement(`Last cell, Row ${lastRow + 1}, ${visibleColumns[lastCol]?.header ||
|
|
15446
|
+
setAnnouncement(`Last cell, Row ${lastRow + 1}, ${visibleColumns[lastCol]?.header || ""}`);
|
|
15416
15447
|
}
|
|
15417
15448
|
else {
|
|
15418
15449
|
// End: Go to last cell in current row
|
|
@@ -15420,10 +15451,10 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15420
15451
|
setFocusedCell({ row, col: lastCol });
|
|
15421
15452
|
const rowItem = data[row];
|
|
15422
15453
|
const cellValue = rowItem[visibleColumns[lastCol]?.key];
|
|
15423
|
-
setAnnouncement(`${visibleColumns[lastCol]?.header ||
|
|
15454
|
+
setAnnouncement(`${visibleColumns[lastCol]?.header || ""}: ${cellValue || "empty"}`);
|
|
15424
15455
|
}
|
|
15425
15456
|
break;
|
|
15426
|
-
case
|
|
15457
|
+
case "Enter":
|
|
15427
15458
|
e.preventDefault();
|
|
15428
15459
|
{
|
|
15429
15460
|
const rowItem = data[row];
|
|
@@ -15431,27 +15462,27 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15431
15462
|
// Priority: Edit mode > Details mode > Row double-click handler
|
|
15432
15463
|
if (onEdit) {
|
|
15433
15464
|
onEdit(rowItem);
|
|
15434
|
-
setAnnouncement(
|
|
15465
|
+
setAnnouncement("Opening edit mode");
|
|
15435
15466
|
}
|
|
15436
15467
|
else if (expandedRowConfig?.edit) {
|
|
15437
|
-
handleExpansionWithMode(rowKey,
|
|
15438
|
-
setAnnouncement(
|
|
15468
|
+
handleExpansionWithMode(rowKey, "edit");
|
|
15469
|
+
setAnnouncement("Opening inline edit");
|
|
15439
15470
|
}
|
|
15440
15471
|
else if (expandedRowConfig?.details) {
|
|
15441
|
-
handleExpansionWithMode(rowKey,
|
|
15442
|
-
setAnnouncement(
|
|
15472
|
+
handleExpansionWithMode(rowKey, "details");
|
|
15473
|
+
setAnnouncement("Opening details view");
|
|
15443
15474
|
}
|
|
15444
15475
|
else if (onRowDoubleClick) {
|
|
15445
15476
|
onRowDoubleClick(rowItem);
|
|
15446
|
-
setAnnouncement(
|
|
15477
|
+
setAnnouncement("Activating row");
|
|
15447
15478
|
}
|
|
15448
15479
|
else if (onRowClick) {
|
|
15449
15480
|
onRowClick(rowItem);
|
|
15450
|
-
setAnnouncement(
|
|
15481
|
+
setAnnouncement("Row selected");
|
|
15451
15482
|
}
|
|
15452
15483
|
}
|
|
15453
15484
|
break;
|
|
15454
|
-
case
|
|
15485
|
+
case " ":
|
|
15455
15486
|
// Space: Toggle selection if selectable
|
|
15456
15487
|
if (selectable) {
|
|
15457
15488
|
e.preventDefault();
|
|
@@ -15459,60 +15490,82 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15459
15490
|
const rowKey = getRowKey(rowItem);
|
|
15460
15491
|
handleRowSelect(rowKey);
|
|
15461
15492
|
const isNowSelected = !selectedRowsSet.has(rowKey);
|
|
15462
|
-
setAnnouncement(isNowSelected ?
|
|
15493
|
+
setAnnouncement(isNowSelected ? "Row selected" : "Row deselected");
|
|
15463
15494
|
}
|
|
15464
15495
|
break;
|
|
15465
|
-
case
|
|
15496
|
+
case "Escape":
|
|
15466
15497
|
e.preventDefault();
|
|
15467
15498
|
setFocusedCell(null);
|
|
15468
|
-
setAnnouncement(
|
|
15499
|
+
setAnnouncement("Table navigation exited");
|
|
15469
15500
|
// Return focus to table container
|
|
15470
|
-
tableBodyRef.current?.closest(
|
|
15501
|
+
tableBodyRef.current?.closest("table")?.focus();
|
|
15471
15502
|
break;
|
|
15472
|
-
case
|
|
15503
|
+
case "PageDown":
|
|
15473
15504
|
e.preventDefault();
|
|
15474
15505
|
{
|
|
15475
15506
|
const jumpSize = 10;
|
|
15476
15507
|
const newRow = Math.min(row + jumpSize, totalRows - 1);
|
|
15477
15508
|
setFocusedCell({ row: newRow, col });
|
|
15478
|
-
const colHeader = visibleColumns[col]?.header ||
|
|
15509
|
+
const colHeader = visibleColumns[col]?.header || "";
|
|
15479
15510
|
setAnnouncement(`Row ${newRow + 1} of ${totalRows}, ${colHeader}`);
|
|
15480
15511
|
}
|
|
15481
15512
|
break;
|
|
15482
|
-
case
|
|
15513
|
+
case "PageUp":
|
|
15483
15514
|
e.preventDefault();
|
|
15484
15515
|
{
|
|
15485
15516
|
const jumpSize = 10;
|
|
15486
15517
|
const newRow = Math.max(row - jumpSize, 0);
|
|
15487
15518
|
setFocusedCell({ row: newRow, col });
|
|
15488
|
-
const colHeader = visibleColumns[col]?.header ||
|
|
15519
|
+
const colHeader = visibleColumns[col]?.header || "";
|
|
15489
15520
|
setAnnouncement(`Row ${newRow + 1} of ${totalRows}, ${colHeader}`);
|
|
15490
15521
|
}
|
|
15491
15522
|
break;
|
|
15492
15523
|
}
|
|
15493
|
-
}, [
|
|
15524
|
+
}, [
|
|
15525
|
+
data,
|
|
15526
|
+
visibleColumns,
|
|
15527
|
+
focusedCell,
|
|
15528
|
+
selectable,
|
|
15529
|
+
expandedRowConfig,
|
|
15530
|
+
onEdit,
|
|
15531
|
+
onRowDoubleClick,
|
|
15532
|
+
onRowClick,
|
|
15533
|
+
getRowKey,
|
|
15534
|
+
handleExpansionWithMode,
|
|
15535
|
+
handleRowSelect,
|
|
15536
|
+
selectedRowsSet,
|
|
15537
|
+
]);
|
|
15494
15538
|
// Focus the appropriate cell when focusedCell changes
|
|
15495
15539
|
useEffect(() => {
|
|
15496
15540
|
if (focusedCell && tableBodyRef.current) {
|
|
15497
15541
|
const { row, col } = focusedCell;
|
|
15498
|
-
const rows = tableBodyRef.current.querySelectorAll(
|
|
15542
|
+
const rows = tableBodyRef.current.querySelectorAll("tr[data-row-index]");
|
|
15499
15543
|
const targetRow = rows[row];
|
|
15500
15544
|
if (targetRow) {
|
|
15501
15545
|
// Calculate actual column index including extra columns
|
|
15502
15546
|
const hasSelectionCol = selectable;
|
|
15503
15547
|
const hasExpandCol = (expandable || expandedRowConfig) && showExpandChevron;
|
|
15504
15548
|
const hasActionsCol = hasAnyActions;
|
|
15505
|
-
const extraColsBefore = (hasSelectionCol ? 1 : 0) +
|
|
15506
|
-
|
|
15549
|
+
const extraColsBefore = (hasSelectionCol ? 1 : 0) +
|
|
15550
|
+
(hasExpandCol ? 1 : 0) +
|
|
15551
|
+
(hasActionsCol ? 1 : 0);
|
|
15552
|
+
const cells = targetRow.querySelectorAll("td");
|
|
15507
15553
|
const targetCell = cells[col + extraColsBefore];
|
|
15508
15554
|
if (targetCell) {
|
|
15509
15555
|
targetCell.focus();
|
|
15510
15556
|
// Scroll into view if needed
|
|
15511
|
-
targetCell.scrollIntoView({ block:
|
|
15557
|
+
targetCell.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
15512
15558
|
}
|
|
15513
15559
|
}
|
|
15514
15560
|
}
|
|
15515
|
-
}, [
|
|
15561
|
+
}, [
|
|
15562
|
+
focusedCell,
|
|
15563
|
+
selectable,
|
|
15564
|
+
expandable,
|
|
15565
|
+
expandedRowConfig,
|
|
15566
|
+
showExpandChevron,
|
|
15567
|
+
hasAnyActions,
|
|
15568
|
+
]);
|
|
15516
15569
|
// Handle column header click for sorting
|
|
15517
15570
|
const handleSort = (column) => {
|
|
15518
15571
|
if (!column.sortable || !onSortChange)
|
|
@@ -15520,8 +15573,12 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15520
15573
|
const columnKey = String(column.key);
|
|
15521
15574
|
// If clicking the same column, toggle direction
|
|
15522
15575
|
if (currentSort?.key === columnKey) {
|
|
15523
|
-
if (currentSort.direction ===
|
|
15524
|
-
onSortChange({
|
|
15576
|
+
if (currentSort.direction === "asc") {
|
|
15577
|
+
onSortChange({
|
|
15578
|
+
key: columnKey,
|
|
15579
|
+
direction: "desc",
|
|
15580
|
+
label: column.header,
|
|
15581
|
+
});
|
|
15525
15582
|
}
|
|
15526
15583
|
else {
|
|
15527
15584
|
// Remove sort on third click
|
|
@@ -15530,7 +15587,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15530
15587
|
}
|
|
15531
15588
|
else {
|
|
15532
15589
|
// New column - start with ascending
|
|
15533
|
-
onSortChange({ key: columnKey, direction:
|
|
15590
|
+
onSortChange({ key: columnKey, direction: "asc", label: column.header });
|
|
15534
15591
|
}
|
|
15535
15592
|
};
|
|
15536
15593
|
// Get sort icon SVG for column (matches reference ui-preview.html)
|
|
@@ -15539,7 +15596,7 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15539
15596
|
return null;
|
|
15540
15597
|
const columnKey = String(column.key);
|
|
15541
15598
|
const isActive = currentSort?.key === columnKey;
|
|
15542
|
-
const isAscending = currentSort?.direction ===
|
|
15599
|
+
const isAscending = currentSort?.direction === "asc";
|
|
15543
15600
|
// Inactive state - show neutral up/down arrows
|
|
15544
15601
|
if (!isActive) {
|
|
15545
15602
|
return (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: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4" }) }));
|
|
@@ -15552,17 +15609,23 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15552
15609
|
return (jsx("svg", { className: "ml-2 w-4 h-4 text-accent-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M16 17l-4 4m0 0l-4-4m4 4V3" }) }));
|
|
15553
15610
|
};
|
|
15554
15611
|
// Render loading skeleton
|
|
15555
|
-
const renderLoadingSkeleton = () => (jsx(Fragment, { children: Array.from({ length: loadingRows }, (_, i) => (jsxs("tr", { className: `animate-pulse table-row-stable ${bordered ? `border-b ${borderColor}` :
|
|
15612
|
+
const renderLoadingSkeleton = () => (jsx(Fragment, { children: Array.from({ length: loadingRows }, (_, i) => (jsxs("tr", { className: `animate-pulse table-row-stable ${bordered ? `border-b ${borderColor}` : ""}`, children: [selectable && (jsx("td", { className: `sticky left-0 bg-white ${currentDensity.cell} border-b ${borderColor} z-10 align-middle`, children: jsx("div", { className: "h-4 w-4 bg-paper-200 rounded" }) })), expandable && (jsx("td", { className: `sticky left-0 bg-white px-2 ${currentDensity.cell} border-b ${borderColor} z-10`, children: jsx("div", { className: "h-4 w-4 bg-paper-200 rounded" }) })), allActions.length > 0 && (jsx("td", { className: `sticky left-0 bg-white px-2 ${currentDensity.cell} border-b ${borderColor} z-10`, children: jsx("div", { className: "h-8 w-8 bg-paper-200 rounded" }) })), visibleColumns.map((column, colIndex) => {
|
|
15556
15613
|
const columnKey = String(column.key);
|
|
15557
15614
|
const dynamicWidth = columnWidths[columnKey];
|
|
15558
|
-
return (jsxs("td", { className: `${currentDensity.cell} whitespace-nowrap table-row-stable ${bordered ? `border ${borderColor}` :
|
|
15615
|
+
return (jsxs("td", { className: `${currentDensity.cell} whitespace-nowrap table-row-stable ${bordered ? `border ${borderColor}` : ""}`, style: getColumnStyle(column, dynamicWidth), children: [jsx("div", { className: "h-4 bg-paper-200 rounded mb-1" }), jsx("div", { className: "h-3 bg-paper-200 rounded w-3/4" })] }, `loading-${i}-${colIndex}`));
|
|
15559
15616
|
})] }, `loading-${i}`))) }));
|
|
15560
15617
|
// Render empty state
|
|
15561
15618
|
const renderEmptyStateContent = () => {
|
|
15562
15619
|
if (customRenderEmptyState) {
|
|
15563
|
-
return (jsx("tr", { children: jsx("td", { colSpan: visibleColumns.length +
|
|
15620
|
+
return (jsx("tr", { children: jsx("td", { colSpan: visibleColumns.length +
|
|
15621
|
+
(allActions.length > 0 ? 1 : 0) +
|
|
15622
|
+
(selectable ? 1 : 0) +
|
|
15623
|
+
(expandable ? 1 : 0), children: customRenderEmptyState() }) }));
|
|
15564
15624
|
}
|
|
15565
|
-
return (jsx("tr", { children: jsx("td", { colSpan: visibleColumns.length +
|
|
15625
|
+
return (jsx("tr", { children: jsx("td", { colSpan: visibleColumns.length +
|
|
15626
|
+
(allActions.length > 0 ? 1 : 0) +
|
|
15627
|
+
(selectable ? 1 : 0) +
|
|
15628
|
+
(expandable ? 1 : 0), className: `${currentDensity.cell} py-8 text-center text-ink-500`, children: error || emptyMessage }) }));
|
|
15566
15629
|
};
|
|
15567
15630
|
// Virtual scrolling calculations
|
|
15568
15631
|
const getVisibleRange = () => {
|
|
@@ -15592,14 +15655,18 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15592
15655
|
const isSelected = selectedRowsSet.has(rowKey);
|
|
15593
15656
|
const isExpanded = expandedRowsSet.has(rowKey);
|
|
15594
15657
|
const rowBgClass = getRowBackgroundClass(item, index);
|
|
15595
|
-
const borderClass = bordered
|
|
15596
|
-
|
|
15658
|
+
const borderClass = bordered
|
|
15659
|
+
? `border-b ${borderColor}`
|
|
15660
|
+
: !visibleColumns.some((col) => !!col.renderSecondary)
|
|
15661
|
+
? `border-b ${borderColor}`
|
|
15662
|
+
: "";
|
|
15663
|
+
const hasSecondaryRow = visibleColumns.some((col) => !!col.renderSecondary);
|
|
15597
15664
|
// Hover state for row pair (primary + secondary)
|
|
15598
15665
|
const isHovered = hoveredRowKey === rowKey;
|
|
15599
|
-
const hoverClass = disableHover ?
|
|
15666
|
+
const hoverClass = disableHover ? "" : isHovered ? "bg-paper-100" : "";
|
|
15600
15667
|
// Check if this row is keyboard-focused
|
|
15601
15668
|
const isKeyboardFocused = focusedCell?.row === index;
|
|
15602
|
-
return (jsxs(React__default.Fragment, { children: [jsxs("tr", { "data-row-index": index, className: `table-row-stable ${onRowDoubleClick || onRowClick || onEdit || expandedRowConfig?.edit || expandedRowConfig?.details || expandedRowConfig?.addRelated?.length || expandedRowConfig?.manageRelated?.length ?
|
|
15669
|
+
return (jsxs(React__default.Fragment, { children: [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) => {
|
|
15603
15670
|
if (enableContextMenu && allActions.length > 0) {
|
|
15604
15671
|
e.preventDefault();
|
|
15605
15672
|
e.stopPropagation();
|
|
@@ -15618,109 +15685,146 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15618
15685
|
}
|
|
15619
15686
|
// Priority 2: If there's an expandable edit mode, trigger it
|
|
15620
15687
|
else if (expandedRowConfig?.edit) {
|
|
15621
|
-
handleExpansionWithMode(rowKey,
|
|
15688
|
+
handleExpansionWithMode(rowKey, "edit");
|
|
15622
15689
|
}
|
|
15623
15690
|
// Priority 3: If there's an expandable details mode, trigger it
|
|
15624
15691
|
else if (expandedRowConfig?.details) {
|
|
15625
|
-
handleExpansionWithMode(rowKey,
|
|
15692
|
+
handleExpansionWithMode(rowKey, "details");
|
|
15626
15693
|
}
|
|
15627
15694
|
// Priority 4: If there's any addRelated mode, trigger the first one
|
|
15628
|
-
else if (expandedRowConfig?.addRelated &&
|
|
15695
|
+
else if (expandedRowConfig?.addRelated &&
|
|
15696
|
+
expandedRowConfig.addRelated.length > 0) {
|
|
15629
15697
|
handleExpansionWithMode(rowKey, `addRelated-${expandedRowConfig.addRelated[0].key}`);
|
|
15630
15698
|
}
|
|
15631
15699
|
// Priority 5: If there's any manageRelated mode, trigger the first one
|
|
15632
|
-
else if (expandedRowConfig?.manageRelated &&
|
|
15700
|
+
else if (expandedRowConfig?.manageRelated &&
|
|
15701
|
+
expandedRowConfig.manageRelated.length > 0) {
|
|
15633
15702
|
handleExpansionWithMode(rowKey, `manageRelated-${expandedRowConfig.manageRelated[0].key}`);
|
|
15634
15703
|
}
|
|
15635
15704
|
// Priority 6: Legacy onRowDoubleClick handler
|
|
15636
15705
|
else {
|
|
15637
15706
|
onRowDoubleClick?.(item);
|
|
15638
15707
|
}
|
|
15639
|
-
}, title: onEdit
|
|
15640
|
-
|
|
15641
|
-
|
|
15642
|
-
|
|
15643
|
-
|
|
15644
|
-
|
|
15645
|
-
|
|
15646
|
-
|
|
15647
|
-
|
|
15648
|
-
|
|
15649
|
-
|
|
15650
|
-
|
|
15651
|
-
|
|
15708
|
+
}, title: onEdit
|
|
15709
|
+
? "Double-click to edit"
|
|
15710
|
+
: expandedRowConfig?.edit
|
|
15711
|
+
? "Double-click to edit inline"
|
|
15712
|
+
: expandedRowConfig?.details
|
|
15713
|
+
? "Double-click to view details"
|
|
15714
|
+
: expandedRowConfig?.addRelated &&
|
|
15715
|
+
expandedRowConfig.addRelated.length > 0
|
|
15716
|
+
? `Double-click to ${expandedRowConfig.addRelated[0].label}`
|
|
15717
|
+
: expandedRowConfig?.manageRelated &&
|
|
15718
|
+
expandedRowConfig.manageRelated.length > 0
|
|
15719
|
+
? `Double-click to ${expandedRowConfig.manageRelated[0].label}`
|
|
15720
|
+
: onRowDoubleClick
|
|
15721
|
+
? "Double-click for details"
|
|
15722
|
+
: onRowClick
|
|
15723
|
+
? "Click to select"
|
|
15724
|
+
: undefined, children: [selectable && (jsx("td", { className: `sticky left-0 z-10 ${bordered ? `border ${borderColor}` : ""}`, style: {
|
|
15725
|
+
backgroundColor: "inherit",
|
|
15726
|
+
verticalAlign: "middle",
|
|
15727
|
+
padding: "0.375rem 0.75rem",
|
|
15728
|
+
textAlign: "center",
|
|
15729
|
+
}, rowSpan: hasSecondaryRow ? 2 : 1, children: 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 && (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: jsx("button", { onClick: () => {
|
|
15652
15730
|
// NEW: Enhanced logic for expandedRowConfig
|
|
15653
|
-
if (expandedRowConfig?.details &&
|
|
15731
|
+
if (expandedRowConfig?.details &&
|
|
15732
|
+
expandedRowConfig.details.triggerOnExpand !== false) {
|
|
15654
15733
|
// Trigger details mode if configured
|
|
15655
|
-
handleExpansionWithMode(rowKey,
|
|
15734
|
+
handleExpansionWithMode(rowKey, "details");
|
|
15656
15735
|
}
|
|
15657
|
-
else if (expandedRowConfig?.edit &&
|
|
15736
|
+
else if (expandedRowConfig?.edit &&
|
|
15737
|
+
expandedRowConfig.edit.triggerOnDoubleClick !== false) {
|
|
15658
15738
|
// Fallback to edit mode if no details but edit is available
|
|
15659
|
-
handleExpansionWithMode(rowKey,
|
|
15739
|
+
handleExpansionWithMode(rowKey, "edit");
|
|
15660
15740
|
}
|
|
15661
15741
|
else {
|
|
15662
15742
|
// Legacy: use handleRowExpand
|
|
15663
15743
|
handleRowExpand(rowKey);
|
|
15664
15744
|
}
|
|
15665
|
-
}, className: "text-ink-500 hover:text-ink-900 transition-colors", "aria-label": isExpanded ||
|
|
15666
|
-
|
|
15667
|
-
|
|
15668
|
-
|
|
15669
|
-
|
|
15670
|
-
|
|
15745
|
+
}, className: "text-ink-500 hover:text-ink-900 transition-colors", "aria-label": isExpanded || expansionState?.rowKey === rowKey
|
|
15746
|
+
? "Collapse row"
|
|
15747
|
+
: "Expand row", children: isExpanded || expansionState?.rowKey === rowKey ? (jsx(ChevronDown, { className: "h-4 w-4" })) : (jsx(ChevronRight, { className: "h-4 w-4" })) }) })), allActions.length > 0 && (jsx("td", { className: "sticky left-0 whitespace-nowrap shadow-[4px_0_6px_-2px_rgba(0,0,0,0.1)] z-10", style: {
|
|
15748
|
+
width: "28px",
|
|
15749
|
+
padding: "0",
|
|
15750
|
+
backgroundColor: "inherit",
|
|
15751
|
+
verticalAlign: "middle",
|
|
15752
|
+
}, onClick: (e) => e.stopPropagation(), rowSpan: hasSecondaryRow ? 2 : 1, children: jsx("div", { style: {
|
|
15753
|
+
display: "inline-flex",
|
|
15754
|
+
alignItems: "center",
|
|
15755
|
+
justifyContent: "center",
|
|
15756
|
+
width: "28px",
|
|
15757
|
+
}, children: jsx(ActionMenu, { actions: allActions, item: item }) }) })), visibleColumns.map((column, colIdx) => {
|
|
15671
15758
|
const columnKey = String(column.key);
|
|
15672
15759
|
const dynamicWidth = columnWidths[columnKey];
|
|
15673
|
-
const value = typeof column.key ===
|
|
15760
|
+
const value = typeof column.key === "string"
|
|
15674
15761
|
? item[column.key]
|
|
15675
15762
|
: item[column.key];
|
|
15676
|
-
const primaryContent = column.render
|
|
15763
|
+
const primaryContent = column.render
|
|
15764
|
+
? column.render(item, value)
|
|
15765
|
+
: String(value || "");
|
|
15766
|
+
// Tooltip: caller-provided > raw value stringified. Empty
|
|
15767
|
+
// strings get dropped so we don't render an empty title
|
|
15768
|
+
// attribute (which the browser would still show as a
|
|
15769
|
+
// 0-width tooltip box on hover).
|
|
15770
|
+
const primaryTooltipText = column.tooltip
|
|
15771
|
+
? column.tooltip(item, value)
|
|
15772
|
+
: value !== null && value !== undefined && value !== ""
|
|
15773
|
+
? String(value)
|
|
15774
|
+
: undefined;
|
|
15677
15775
|
// Reduce left padding on first column when there are action buttons
|
|
15678
15776
|
const isFirstColumn = colIdx === 0;
|
|
15679
|
-
const paddingClass = isFirstColumn && allActions.length > 0 ?
|
|
15777
|
+
const paddingClass = isFirstColumn && allActions.length > 0 ? "pl-3" : "";
|
|
15680
15778
|
// Check if this cell is keyboard-focused
|
|
15681
15779
|
const isCellFocused = focusedCell?.row === index && focusedCell?.col === colIdx;
|
|
15682
|
-
return (jsx("td", { className: `${currentDensity.cell} ${paddingClass} ${column.className ||
|
|
15683
|
-
})] }), hasSecondaryRow && (jsx("tr", { className: `secondary-row ${isSelected ?
|
|
15780
|
+
return (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: jsx("div", { className: `${currentDensity.text} leading-tight`, title: primaryTooltipText, children: primaryContent }) }, `${item.id}-${columnKey}`));
|
|
15781
|
+
})] }), hasSecondaryRow && (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) => {
|
|
15684
15782
|
const columnKey = String(column.key);
|
|
15685
15783
|
const dynamicWidth = columnWidths[columnKey];
|
|
15686
|
-
const value = typeof column.key ===
|
|
15784
|
+
const value = typeof column.key === "string"
|
|
15687
15785
|
? item[column.key]
|
|
15688
15786
|
: item[column.key];
|
|
15689
|
-
const secondaryContent = column.renderSecondary
|
|
15787
|
+
const secondaryContent = column.renderSecondary
|
|
15788
|
+
? column.renderSecondary(item, value)
|
|
15789
|
+
: null;
|
|
15790
|
+
// Tooltip on the secondary row prefixes the field label when
|
|
15791
|
+
// available so the otherwise-unlabeled second row stays
|
|
15792
|
+
// self-describing on hover. Caller can override entirely
|
|
15793
|
+
// via `secondaryTooltip`.
|
|
15794
|
+
const hasSecondaryValue = value !== null && value !== undefined && value !== "";
|
|
15795
|
+
let secondaryTooltipText;
|
|
15796
|
+
if (column.secondaryTooltip) {
|
|
15797
|
+
secondaryTooltipText = column.secondaryTooltip(item, value);
|
|
15798
|
+
}
|
|
15799
|
+
else if (hasSecondaryValue) {
|
|
15800
|
+
secondaryTooltipText = column.secondaryHeader
|
|
15801
|
+
? `${column.secondaryHeader}: ${value}`
|
|
15802
|
+
: String(value);
|
|
15803
|
+
}
|
|
15804
|
+
else if (column.secondaryHeader) {
|
|
15805
|
+
secondaryTooltipText = column.secondaryHeader;
|
|
15806
|
+
}
|
|
15690
15807
|
// Reduce left padding on first column when there are action buttons
|
|
15691
15808
|
const isFirstColumn = colIdx === 0;
|
|
15692
|
-
const paddingClass = isFirstColumn && allActions.length > 0 ?
|
|
15693
|
-
return (jsx("td", { className: `${currentDensity.cell} py-0.5 ${paddingClass} ${column.className ||
|
|
15809
|
+
const paddingClass = isFirstColumn && allActions.length > 0 ? "pl-3" : "";
|
|
15810
|
+
return (jsx("td", { className: `${currentDensity.cell} py-0.5 ${paddingClass} ${column.className || ""} ${bordered ? `border ${borderColor}` : ""}`, style: getColumnStyle(column, dynamicWidth), children: jsx("div", { className: "text-xs text-ink-500 leading-tight", title: secondaryTooltipText, children: secondaryContent || jsx("span", { className: "invisible", children: "\u2014" }) }) }, `${item.id}-${columnKey}-secondary`));
|
|
15694
15811
|
}) })), expandable && isExpanded && renderExpandedRow && (jsx("tr", { children: jsx("td", { colSpan: visibleColumns.length +
|
|
15695
15812
|
(selectable ? 1 : 0) +
|
|
15696
|
-
((
|
|
15697
|
-
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
|
|
15701
|
-
|
|
15702
|
-
|
|
15703
|
-
|
|
15704
|
-
content =
|
|
15705
|
-
|
|
15706
|
-
|
|
15707
|
-
|
|
15708
|
-
|
|
15709
|
-
|
|
15710
|
-
|
|
15711
|
-
}
|
|
15712
|
-
// Details mode
|
|
15713
|
-
else if (mode === 'details' && expandedRowConfig.details) {
|
|
15714
|
-
bgColorClass = 'bg-primary-50/80 border-t border-b border-primary-200/80';
|
|
15715
|
-
content = expandedRowConfig.details.render(item);
|
|
15716
|
-
}
|
|
15717
|
-
// Add related modes
|
|
15718
|
-
else if (mode.startsWith('addRelated-') && expandedRowConfig.addRelated) {
|
|
15719
|
-
const key = mode.replace('addRelated-', '');
|
|
15720
|
-
const config = expandedRowConfig.addRelated.find(c => c.key === key);
|
|
15721
|
-
if (config) {
|
|
15722
|
-
bgColorClass = 'bg-success-50/80 border-t border-b border-success-200/80';
|
|
15723
|
-
content = config.render(item, async (_newItem) => {
|
|
15813
|
+
((expandable || expandedRowConfig) && showExpandChevron
|
|
15814
|
+
? 1
|
|
15815
|
+
: 0) +
|
|
15816
|
+
(allActions.length > 0 ? 1 : 0), className: `${currentDensity.cell} py-4 bg-paper-50`, children: renderExpandedRow(item) }) })), expansionState &&
|
|
15817
|
+
expansionState.rowKey === rowKey &&
|
|
15818
|
+
expandedRowConfig &&
|
|
15819
|
+
(() => {
|
|
15820
|
+
const mode = expansionState.mode;
|
|
15821
|
+
let content = null;
|
|
15822
|
+
let bgColorClass = "bg-paper-50"; // Default
|
|
15823
|
+
// Edit mode
|
|
15824
|
+
if (mode === "edit" && expandedRowConfig.edit) {
|
|
15825
|
+
bgColorClass =
|
|
15826
|
+
"bg-paper-100/80 border-t border-b border-paper-300/80";
|
|
15827
|
+
content = expandedRowConfig.edit.render(item, async (_updated) => {
|
|
15724
15828
|
// Handle save
|
|
15725
15829
|
handleCollapseExpansion();
|
|
15726
15830
|
}, () => {
|
|
@@ -15728,31 +15832,57 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15728
15832
|
handleCollapseExpansion();
|
|
15729
15833
|
});
|
|
15730
15834
|
}
|
|
15731
|
-
|
|
15732
|
-
|
|
15733
|
-
|
|
15734
|
-
|
|
15735
|
-
|
|
15736
|
-
if (config) {
|
|
15737
|
-
bgColorClass = 'bg-slate-50/80 border-t border-b border-slate-200/80';
|
|
15738
|
-
const handleClose = () => setExpansionState(null);
|
|
15739
|
-
content = config.render(item, handleClose);
|
|
15835
|
+
// Details mode
|
|
15836
|
+
else if (mode === "details" && expandedRowConfig.details) {
|
|
15837
|
+
bgColorClass =
|
|
15838
|
+
"bg-primary-50/80 border-t border-b border-primary-200/80";
|
|
15839
|
+
content = expandedRowConfig.details.render(item);
|
|
15740
15840
|
}
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
15744
|
-
|
|
15745
|
-
|
|
15746
|
-
|
|
15747
|
-
|
|
15748
|
-
|
|
15841
|
+
// Add related modes
|
|
15842
|
+
else if (mode.startsWith("addRelated-") &&
|
|
15843
|
+
expandedRowConfig.addRelated) {
|
|
15844
|
+
const key = mode.replace("addRelated-", "");
|
|
15845
|
+
const config = expandedRowConfig.addRelated.find((c) => c.key === key);
|
|
15846
|
+
if (config) {
|
|
15847
|
+
bgColorClass =
|
|
15848
|
+
"bg-success-50/80 border-t border-b border-success-200/80";
|
|
15849
|
+
content = config.render(item, async (_newItem) => {
|
|
15850
|
+
// Handle save
|
|
15851
|
+
handleCollapseExpansion();
|
|
15852
|
+
}, () => {
|
|
15853
|
+
// Handle cancel
|
|
15854
|
+
handleCollapseExpansion();
|
|
15855
|
+
});
|
|
15856
|
+
}
|
|
15857
|
+
}
|
|
15858
|
+
// Manage related modes
|
|
15859
|
+
else if (mode.startsWith("manageRelated-") &&
|
|
15860
|
+
expandedRowConfig.manageRelated) {
|
|
15861
|
+
const key = mode.replace("manageRelated-", "");
|
|
15862
|
+
const config = expandedRowConfig.manageRelated.find((c) => c.key === key);
|
|
15863
|
+
if (config) {
|
|
15864
|
+
bgColorClass =
|
|
15865
|
+
"bg-slate-50/80 border-t border-b border-slate-200/80";
|
|
15866
|
+
const handleClose = () => setExpansionState(null);
|
|
15867
|
+
content = config.render(item, handleClose);
|
|
15868
|
+
}
|
|
15869
|
+
}
|
|
15870
|
+
if (!content)
|
|
15871
|
+
return null;
|
|
15872
|
+
return (jsx("tr", { children: jsx("td", { colSpan: visibleColumns.length +
|
|
15873
|
+
(selectable ? 1 : 0) +
|
|
15874
|
+
((expandable || expandedRowConfig) && showExpandChevron
|
|
15875
|
+
? 1
|
|
15876
|
+
: 0) +
|
|
15877
|
+
(allActions.length > 0 ? 1 : 0), className: `${currentDensity.cell} py-4 ${bgColorClass} animate-expand`, children: content }) }, `expanded-${rowKey}`));
|
|
15878
|
+
})()] }, rowKey));
|
|
15749
15879
|
});
|
|
15750
15880
|
};
|
|
15751
|
-
const tableContent = (jsxs("div", { className: `bg-white rounded-lg shadow border-2 ${borderColor} ${virtualized ?
|
|
15881
|
+
const tableContent = (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 && (jsx("div", { className: "absolute inset-0 bg-white/75 flex items-center justify-center z-20", style: { backdropFilter: "blur(2px)" }, children: jsxs("div", { className: "flex flex-col items-center gap-3", children: [jsx("div", { className: "loading-spinner", style: { width: "32px", height: "32px", borderWidth: "3px" } }), jsx("span", { className: "text-sm font-medium text-ink-600", children: "Loading..." })] }) })), 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: [jsxs("colgroup", { children: [selectable && jsx("col", { className: "w-12" }), (expandable || expandedRowConfig) && showExpandChevron && (jsx("col", { className: "w-10" })), allActions.length > 0 && jsx("col", { style: { width: "28px" } }), visibleColumns.map((column, index) => {
|
|
15752
15882
|
const columnKey = String(column.key);
|
|
15753
15883
|
const dynamicWidth = columnWidths[columnKey];
|
|
15754
15884
|
return (jsx("col", { style: getColumnStyle(column, dynamicWidth) }, index));
|
|
15755
|
-
})] }), jsx("thead", { className: `bg-paper-100 sticky top-0 z-10 ${headerClassName}`, children: jsxs("tr", { className: "table-header-row", children: [selectable && (jsx("th", { className: `sticky left-0 bg-paper-100 ${currentDensity.header} border-b ${borderColor} z-20 w-12 ${bordered ? `border ${borderColor}` :
|
|
15885
|
+
})] }), jsx("thead", { className: `bg-paper-100 sticky top-0 z-10 ${headerClassName}`, children: jsxs("tr", { className: "table-header-row", children: [selectable && (jsx("th", { className: `sticky left-0 bg-paper-100 ${currentDensity.header} border-b ${borderColor} z-20 w-12 ${bordered ? `border ${borderColor}` : ""}`, children: 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 && (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 && (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) => {
|
|
15756
15886
|
const columnKey = String(column.key);
|
|
15757
15887
|
const dynamicWidth = columnWidths[columnKey];
|
|
15758
15888
|
const thRef = useRef(null);
|
|
@@ -15760,24 +15890,28 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15760
15890
|
const isDragOver = dragOverColumn === columnKey;
|
|
15761
15891
|
// Reduce left padding on first column when there are action buttons (match body cells)
|
|
15762
15892
|
const isFirstColumn = colIdx === 0;
|
|
15763
|
-
const headerPaddingClass = isFirstColumn && allActions.length > 0 ?
|
|
15893
|
+
const headerPaddingClass = isFirstColumn && allActions.length > 0 ? "pl-3" : "";
|
|
15764
15894
|
return (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: `
|
|
15765
|
-
${currentDensity.header} ${headerPaddingClass} text-left border-b ${borderColor} ${bordered ? `border ${borderColor}` :
|
|
15766
|
-
${reorderable ?
|
|
15767
|
-
${isDragging ?
|
|
15768
|
-
${isDragOver ?
|
|
15895
|
+
${currentDensity.header} ${headerPaddingClass} text-left border-b ${borderColor} ${bordered ? `border ${borderColor}` : ""} relative
|
|
15896
|
+
${reorderable ? "cursor-move" : ""}
|
|
15897
|
+
${isDragging ? "opacity-50" : ""}
|
|
15898
|
+
${isDragOver ? "bg-accent-100" : ""}
|
|
15769
15899
|
`, style: getColumnStyle(column, dynamicWidth), children: [column.sortable ? (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: [jsx("span", { children: column.header }), getSortIcon(column)] })) : (jsx("span", { className: "text-xs font-medium text-ink-500 uppercase tracking-wider", children: column.header })), resizable && (jsx("div", { className: "absolute right-0 top-0 bottom-0 w-1 cursor-col-resize hover:bg-accent-400 group", onMouseDown: (e) => {
|
|
15770
15900
|
const currentWidth = thRef.current?.offsetWidth || 100;
|
|
15771
15901
|
handleResizeStart(e, columnKey, currentWidth);
|
|
15772
15902
|
}, children: jsx("div", { className: "absolute right-0 top-0 bottom-0 w-1 bg-paper-300 group-hover:bg-accent-400 transition-colors" }) }))] }, columnKey));
|
|
15773
|
-
})] }) }), 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
|
|
15903
|
+
})] }) }), 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
|
|
15904
|
+
? renderLoadingSkeleton()
|
|
15905
|
+
: data.length === 0
|
|
15906
|
+
? renderEmptyStateContent()
|
|
15907
|
+
: renderDataRows() })] })] }));
|
|
15774
15908
|
// Wrap in scrollable container if virtualized
|
|
15775
|
-
const finalContent = virtualized ? (jsx("div", { ref: tableContainerRef, onScroll: handleScroll, style: { height: virtualHeight, overflow:
|
|
15909
|
+
const finalContent = virtualized ? (jsx("div", { ref: tableContainerRef, onScroll: handleScroll, style: { height: virtualHeight, overflow: "auto" }, className: "rounded-lg", children: tableContent })) : (tableContent);
|
|
15776
15910
|
// Calculate pagination values
|
|
15777
15911
|
const effectiveTotalItems = totalItems ?? data.length;
|
|
15778
15912
|
const totalPages = Math.ceil(effectiveTotalItems / pageSize);
|
|
15779
15913
|
// Page size selector options
|
|
15780
|
-
const pageSizeSelectOptions = pageSizeOptions.map(size => ({
|
|
15914
|
+
const pageSizeSelectOptions = pageSizeOptions.map((size) => ({
|
|
15781
15915
|
value: String(size),
|
|
15782
15916
|
label: `${size} per page`,
|
|
15783
15917
|
}));
|
|
@@ -15785,17 +15919,20 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15785
15919
|
const renderPaginationControls = () => {
|
|
15786
15920
|
if (!paginated)
|
|
15787
15921
|
return null;
|
|
15788
|
-
return (jsxs("div", { className: "flex items-center justify-between mb-4 px-1", children: [jsxs("div", { className: "flex items-center gap-4", children: [showPageSizeSelector && onPageSizeChange && (jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm text-ink-600", children: "Show:" }), jsx(Select, { options: pageSizeSelectOptions, value: String(pageSize), onChange: (value) => onPageSizeChange?.(Number(value)) })] })), jsx("span", { className: "text-sm text-ink-600", children: effectiveTotalItems > 0 ? (jsxs(Fragment, { children: ["Showing ", (
|
|
15922
|
+
return (jsxs("div", { className: "flex items-center justify-between mb-4 px-1", children: [jsxs("div", { className: "flex items-center gap-4", children: [showPageSizeSelector && onPageSizeChange && (jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm text-ink-600", children: "Show:" }), jsx(Select, { options: pageSizeSelectOptions, value: String(pageSize), onChange: (value) => onPageSizeChange?.(Number(value)) })] })), jsx("span", { className: "text-sm text-ink-600", children: effectiveTotalItems > 0 ? (jsxs(Fragment, { children: ["Showing ", (currentPage - 1) * pageSize + 1, " -", " ", Math.min(currentPage * pageSize, effectiveTotalItems), " of", " ", effectiveTotalItems] })) : ("No items") })] }), totalPages > 1 && onPageChange && (jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange }))] }));
|
|
15789
15923
|
};
|
|
15790
15924
|
// Determine if we should show card view
|
|
15791
|
-
const shouldShowCardView = mobileView ===
|
|
15792
|
-
(mobileView === 'auto' && isMobileViewport);
|
|
15925
|
+
const shouldShowCardView = mobileView === "card" || (mobileView === "auto" && isMobileViewport);
|
|
15793
15926
|
// Card view content
|
|
15794
15927
|
const cardViewContent = shouldShowCardView ? (jsx(DataTableCardView, { data: data, columns: visibleColumns, cardConfig: cardConfig, loading: loading, loadingRows: loadingRows, emptyMessage: emptyMessage, onCardClick: onRowClick, onCardLongPress: (item, event) => {
|
|
15795
15928
|
if (enableContextMenu && allActions.length > 0) {
|
|
15796
15929
|
event.preventDefault();
|
|
15797
|
-
const clientX =
|
|
15798
|
-
|
|
15930
|
+
const clientX = "touches" in event
|
|
15931
|
+
? event.touches[0].clientX
|
|
15932
|
+
: event.clientX;
|
|
15933
|
+
const clientY = "touches" in event
|
|
15934
|
+
? event.touches[0].clientY
|
|
15935
|
+
: event.clientY;
|
|
15799
15936
|
setContextMenuState({
|
|
15800
15937
|
isOpen: true,
|
|
15801
15938
|
position: { x: clientX, y: clientY },
|
|
@@ -15804,7 +15941,11 @@ mobileView = 'auto', cardConfig, cardGap = 'md', cardClassName, }) {
|
|
|
15804
15941
|
}
|
|
15805
15942
|
}, 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;
|
|
15806
15943
|
// Render with context menu
|
|
15807
|
-
return (jsxs(Fragment, { children: [jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "true", className: "sr-only", children: announcement }), renderPaginationControls(), shouldShowCardView ? cardViewContent : finalContent, contextMenuState.isOpen && contextMenuState.item && (jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({
|
|
15944
|
+
return (jsxs(Fragment, { children: [jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "true", className: "sr-only", children: announcement }), renderPaginationControls(), shouldShowCardView ? cardViewContent : finalContent, contextMenuState.isOpen && contextMenuState.item && (jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({
|
|
15945
|
+
isOpen: false,
|
|
15946
|
+
position: { x: 0, y: 0 },
|
|
15947
|
+
item: null,
|
|
15948
|
+
}) }))] }));
|
|
15808
15949
|
}
|
|
15809
15950
|
|
|
15810
15951
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
@@ -15843,52 +15984,44 @@ function getAugmentedNamespace(n) {
|
|
|
15843
15984
|
* (A1, A1:C5, ...)
|
|
15844
15985
|
*/
|
|
15845
15986
|
|
|
15846
|
-
|
|
15847
|
-
var hasRequiredCollection;
|
|
15848
|
-
|
|
15849
|
-
function requireCollection () {
|
|
15850
|
-
if (hasRequiredCollection) return collection;
|
|
15851
|
-
hasRequiredCollection = 1;
|
|
15852
|
-
class Collection {
|
|
15987
|
+
let Collection$3 = class Collection {
|
|
15853
15988
|
|
|
15854
|
-
|
|
15855
|
-
|
|
15856
|
-
|
|
15857
|
-
|
|
15858
|
-
|
|
15859
|
-
|
|
15860
|
-
|
|
15861
|
-
|
|
15862
|
-
|
|
15863
|
-
|
|
15864
|
-
|
|
15989
|
+
constructor(data, refs) {
|
|
15990
|
+
if (data == null && refs == null) {
|
|
15991
|
+
this._data = [];
|
|
15992
|
+
this._refs = [];
|
|
15993
|
+
} else {
|
|
15994
|
+
if (data.length !== refs.length)
|
|
15995
|
+
throw Error('Collection: data length should match references length.');
|
|
15996
|
+
this._data = data;
|
|
15997
|
+
this._refs = refs;
|
|
15998
|
+
}
|
|
15999
|
+
}
|
|
15865
16000
|
|
|
15866
|
-
|
|
15867
|
-
|
|
15868
|
-
|
|
16001
|
+
get data() {
|
|
16002
|
+
return this._data;
|
|
16003
|
+
}
|
|
15869
16004
|
|
|
15870
|
-
|
|
15871
|
-
|
|
15872
|
-
|
|
16005
|
+
get refs() {
|
|
16006
|
+
return this._refs;
|
|
16007
|
+
}
|
|
15873
16008
|
|
|
15874
|
-
|
|
15875
|
-
|
|
15876
|
-
|
|
16009
|
+
get length() {
|
|
16010
|
+
return this._data.length;
|
|
16011
|
+
}
|
|
15877
16012
|
|
|
15878
|
-
|
|
15879
|
-
|
|
15880
|
-
|
|
15881
|
-
|
|
15882
|
-
|
|
15883
|
-
|
|
15884
|
-
|
|
15885
|
-
|
|
15886
|
-
|
|
15887
|
-
|
|
16013
|
+
/**
|
|
16014
|
+
* Add data and references to this collection.
|
|
16015
|
+
* @param {{}} obj - data
|
|
16016
|
+
* @param {{}} ref - reference
|
|
16017
|
+
*/
|
|
16018
|
+
add(obj, ref) {
|
|
16019
|
+
this._data.push(obj);
|
|
16020
|
+
this._refs.push(ref);
|
|
16021
|
+
}
|
|
16022
|
+
};
|
|
15888
16023
|
|
|
15889
|
-
|
|
15890
|
-
return collection;
|
|
15891
|
-
}
|
|
16024
|
+
var collection = Collection$3;
|
|
15892
16025
|
|
|
15893
16026
|
var helpers;
|
|
15894
16027
|
var hasRequiredHelpers;
|
|
@@ -15897,7 +16030,7 @@ function requireHelpers () {
|
|
|
15897
16030
|
if (hasRequiredHelpers) return helpers;
|
|
15898
16031
|
hasRequiredHelpers = 1;
|
|
15899
16032
|
const FormulaError = requireError();
|
|
15900
|
-
const Collection =
|
|
16033
|
+
const Collection = collection;
|
|
15901
16034
|
|
|
15902
16035
|
const Types = {
|
|
15903
16036
|
NUMBER: 0,
|
|
@@ -25551,7 +25684,7 @@ var engineering = EngineeringFunctions;
|
|
|
25551
25684
|
|
|
25552
25685
|
const FormulaError$b = requireError();
|
|
25553
25686
|
const {FormulaHelpers: FormulaHelpers$8, Types: Types$6, WildCard, Address: Address$3} = requireHelpers();
|
|
25554
|
-
const Collection$2 =
|
|
25687
|
+
const Collection$2 = collection;
|
|
25555
25688
|
const H$5 = FormulaHelpers$8;
|
|
25556
25689
|
|
|
25557
25690
|
const ReferenceFunctions$1 = {
|
|
@@ -37179,7 +37312,7 @@ var parsing = {
|
|
|
37179
37312
|
const FormulaError$4 = requireError();
|
|
37180
37313
|
const {Address: Address$1} = requireHelpers();
|
|
37181
37314
|
const {Prefix: Prefix$1, Postfix: Postfix$1, Infix: Infix$1, Operators: Operators$1} = operators;
|
|
37182
|
-
const Collection$1 =
|
|
37315
|
+
const Collection$1 = collection;
|
|
37183
37316
|
const MAX_ROW$1 = 1048576, MAX_COLUMN$1 = 16384;
|
|
37184
37317
|
const {NotAllInputParsedException} = require$$4;
|
|
37185
37318
|
|
|
@@ -37941,7 +38074,7 @@ var hooks$1 = {
|
|
|
37941
38074
|
const FormulaError$2 = requireError();
|
|
37942
38075
|
const {FormulaHelpers: FormulaHelpers$1, Types, Address} = requireHelpers();
|
|
37943
38076
|
const {Prefix, Postfix, Infix, Operators} = operators;
|
|
37944
|
-
const Collection =
|
|
38077
|
+
const Collection = collection;
|
|
37945
38078
|
const MAX_ROW = 1048576, MAX_COLUMN = 16384;
|
|
37946
38079
|
|
|
37947
38080
|
let Utils$1 = class Utils {
|