trotl-table 1.0.97 → 1.0.99
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/README.md +3 -1
- package/dist/Table.cjs.js +130 -34
- package/dist/Table.cjs.js.map +1 -1
- package/dist/Table.esm.js +130 -34
- package/dist/Table.esm.js.map +1 -1
- package/dist/WorkOrderAnalyticsByClient.cjs.js +417 -0
- package/dist/WorkOrderAnalyticsByClient.cjs.js.map +1 -0
- package/dist/WorkOrderAnalyticsByClient.esm.js +412 -0
- package/dist/WorkOrderAnalyticsByClient.esm.js.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/package.json +1 -1
package/dist/Table.esm.js
CHANGED
|
@@ -9665,6 +9665,8 @@ function TableInner({
|
|
|
9665
9665
|
tableId = "default",
|
|
9666
9666
|
columns = [],
|
|
9667
9667
|
data = [],
|
|
9668
|
+
mobileColumnCount = 2,
|
|
9669
|
+
mobileRowClick = null,
|
|
9668
9670
|
highlightRow = null,
|
|
9669
9671
|
isGrouped = false,
|
|
9670
9672
|
groupKey = "groupId",
|
|
@@ -9732,6 +9734,8 @@ function TableInner({
|
|
|
9732
9734
|
share: "Share",
|
|
9733
9735
|
duplicate: "Duplicate",
|
|
9734
9736
|
download: "Download",
|
|
9737
|
+
details: "Details",
|
|
9738
|
+
close: "Close",
|
|
9735
9739
|
confirmDelete: "Confirm Delete",
|
|
9736
9740
|
yesDelete: "Yes, Delete",
|
|
9737
9741
|
areYouSureYouWantToDelete: "Are you sure you want to delete",
|
|
@@ -9755,6 +9759,11 @@ function TableInner({
|
|
|
9755
9759
|
const duplicateCallbackRef = useRef(duplicateCallback);
|
|
9756
9760
|
const downloadCallbackRef = useRef(downloadCallback);
|
|
9757
9761
|
const undeleteCallbackRef = useRef(undeleteCallback);
|
|
9762
|
+
const mobileRowClickRef = useRef(mobileRowClick);
|
|
9763
|
+
const lastTapRef = useRef({
|
|
9764
|
+
timer: null,
|
|
9765
|
+
rowId: null
|
|
9766
|
+
});
|
|
9758
9767
|
const onCellChangeRef = useRef(onCellChange);
|
|
9759
9768
|
const cellCallbackRef = useRef(cellCallback);
|
|
9760
9769
|
|
|
@@ -9766,9 +9775,16 @@ function TableInner({
|
|
|
9766
9775
|
editCallbackRef.current = editCallback;
|
|
9767
9776
|
deleteCallbackRef.current = deleteCallback;
|
|
9768
9777
|
undeleteCallbackRef.current = undeleteCallback;
|
|
9778
|
+
mobileRowClickRef.current = mobileRowClick;
|
|
9769
9779
|
onCellChangeRef.current = onCellChange;
|
|
9770
9780
|
cellCallbackRef.current = cellCallback;
|
|
9771
9781
|
});
|
|
9782
|
+
const [isMobile, setIsMobile] = useState(() => typeof window !== "undefined" && window.innerWidth <= 768);
|
|
9783
|
+
useEffect(() => {
|
|
9784
|
+
const updateMobileState = () => setIsMobile(window.innerWidth <= 768);
|
|
9785
|
+
window.addEventListener("resize", updateMobileState);
|
|
9786
|
+
return () => window.removeEventListener("resize", updateMobileState);
|
|
9787
|
+
}, []);
|
|
9772
9788
|
|
|
9773
9789
|
// Context menu right click state
|
|
9774
9790
|
const [contextMenu, setContextMenu] = useState({
|
|
@@ -9854,6 +9870,22 @@ function TableInner({
|
|
|
9854
9870
|
flex: "1 1 0%"
|
|
9855
9871
|
};
|
|
9856
9872
|
}, [columnWidths, getColumnKey]);
|
|
9873
|
+
const allColumns = useMemo(() => {
|
|
9874
|
+
const composedColumns = [...columns];
|
|
9875
|
+
if (Array.isArray(customColumns)) {
|
|
9876
|
+
customColumns.forEach(col => {
|
|
9877
|
+
if (typeof col.place === "number") {
|
|
9878
|
+
composedColumns.splice(col.place, 0, {
|
|
9879
|
+
...col,
|
|
9880
|
+
isCustom: true
|
|
9881
|
+
});
|
|
9882
|
+
}
|
|
9883
|
+
});
|
|
9884
|
+
}
|
|
9885
|
+
return composedColumns;
|
|
9886
|
+
}, [columns, customColumns]);
|
|
9887
|
+
const normalizedMobileColumnCount = Math.min(2, Math.max(1, Math.floor(Number(mobileColumnCount) || 2)));
|
|
9888
|
+
const visibleColumns = isMobile ? allColumns.slice(0, normalizedMobileColumnCount) : allColumns;
|
|
9857
9889
|
const getNestedValue = useCallback((row, accessor) => {
|
|
9858
9890
|
if (!row || accessor == null) return undefined;
|
|
9859
9891
|
if (Array.isArray(accessor)) {
|
|
@@ -10232,6 +10264,21 @@ function TableInner({
|
|
|
10232
10264
|
}).filter(Boolean);
|
|
10233
10265
|
return [...new Set(parts)].join(", ");
|
|
10234
10266
|
}, []);
|
|
10267
|
+
const formatMobileDetailValue = useCallback((value, col) => {
|
|
10268
|
+
if (value == null || value === "") return "...";
|
|
10269
|
+
if (typeof value === "boolean") return value ? "✓" : "✗";
|
|
10270
|
+
if (Array.isArray(value)) return formatArrayValue(value, col) || "...";
|
|
10271
|
+
if (value instanceof Date) {
|
|
10272
|
+
return formatDateValue(value, getColumnDateFormat(col)) || "...";
|
|
10273
|
+
}
|
|
10274
|
+
if (getColumnType(col) === "date" || col?.dateFormat) {
|
|
10275
|
+
return formatDateValue(value, getColumnDateFormat(col)) || String(value);
|
|
10276
|
+
}
|
|
10277
|
+
if (typeof value === "object") {
|
|
10278
|
+
return String(value.label ?? value.name ?? value.value ?? value);
|
|
10279
|
+
}
|
|
10280
|
+
return String(col?.translate ? translate(String(value)) : value);
|
|
10281
|
+
}, [formatArrayValue, translate]);
|
|
10235
10282
|
|
|
10236
10283
|
// console.log(extraSearchTerm)
|
|
10237
10284
|
|
|
@@ -10546,6 +10593,7 @@ function TableInner({
|
|
|
10546
10593
|
// DELETE
|
|
10547
10594
|
const [showConfirm, setShowConfirm] = useState(false);
|
|
10548
10595
|
const [pendingDelete, setPendingDelete] = useState(null);
|
|
10596
|
+
const [mobileDetailRow, setMobileDetailRow] = useState(null);
|
|
10549
10597
|
|
|
10550
10598
|
// perform deletion for a given row (shared by immediate & modal-confirm flows)
|
|
10551
10599
|
const doDelete = useCallback(async row => {
|
|
@@ -10913,7 +10961,7 @@ function TableInner({
|
|
|
10913
10961
|
const showUndelete = buttons.includes("undelete");
|
|
10914
10962
|
const showDuplicate = buttons.includes("duplicate") || buttons.includes("duplicates");
|
|
10915
10963
|
const showDownload = buttons.includes("download");
|
|
10916
|
-
const showActions = showView || showEdit || showDelete || showShare || showUndelete || showDuplicate || showDownload;
|
|
10964
|
+
const showActions = !isMobile && (showView || showEdit || showDelete || showShare || showUndelete || showDuplicate || showDownload);
|
|
10917
10965
|
const visibleActionCount = [showView, showEdit, showDuplicate, showDelete, showShare, showUndelete, showDownload].filter(Boolean).length;
|
|
10918
10966
|
const actionColumnStyle = useMemo(() => {
|
|
10919
10967
|
if (!showActions) return undefined;
|
|
@@ -11141,19 +11189,6 @@ function TableInner({
|
|
|
11141
11189
|
const visualIndex = tableDataFlat.slice(0, index).filter(i => i.type === "row").length + 1;
|
|
11142
11190
|
const highlightRowStyle = getHighlightRowStyle(row);
|
|
11143
11191
|
|
|
11144
|
-
// Compose columns + custom columns
|
|
11145
|
-
const allColumns = [...columns];
|
|
11146
|
-
// Insert custom columns at specified places
|
|
11147
|
-
if (Array.isArray(customColumns)) {
|
|
11148
|
-
customColumns.forEach(col => {
|
|
11149
|
-
if (typeof col.place === "number") {
|
|
11150
|
-
allColumns.splice(col.place, 0, {
|
|
11151
|
-
...col,
|
|
11152
|
-
isCustom: true
|
|
11153
|
-
});
|
|
11154
|
-
}
|
|
11155
|
-
});
|
|
11156
|
-
}
|
|
11157
11192
|
// handler called when user double-clicks the non-action portion of the row
|
|
11158
11193
|
const handleRowDoubleClick = e => {
|
|
11159
11194
|
if (!doubleClickEnable) return;
|
|
@@ -11163,13 +11198,60 @@ function TableInner({
|
|
|
11163
11198
|
}
|
|
11164
11199
|
editCallbackRef.current(row);
|
|
11165
11200
|
};
|
|
11201
|
+
const handleMobileRowClick = event => {
|
|
11202
|
+
if (!isMobile || event.target.closest(".checkbox-cell, .action-cell, button, input, select, textarea, a, [contenteditable='true']")) {
|
|
11203
|
+
return;
|
|
11204
|
+
}
|
|
11205
|
+
const openSingleTap = () => {
|
|
11206
|
+
if (typeof mobileRowClickRef.current === "function") {
|
|
11207
|
+
mobileRowClickRef.current(row);
|
|
11208
|
+
} else {
|
|
11209
|
+
setMobileDetailRow(row);
|
|
11210
|
+
}
|
|
11211
|
+
};
|
|
11212
|
+
const hasContextActions = Array.isArray(enableMouseRightClick) && enableMouseRightClick.length > 0;
|
|
11213
|
+
if (!hasContextActions) {
|
|
11214
|
+
openSingleTap();
|
|
11215
|
+
return;
|
|
11216
|
+
}
|
|
11217
|
+
|
|
11218
|
+
// Double tap opens the context menu; a single tap waits briefly so
|
|
11219
|
+
// the first tap of a double tap does not open the details modal.
|
|
11220
|
+
const tap = lastTapRef.current;
|
|
11221
|
+
if (tap.timer && tap.rowId === row.id) {
|
|
11222
|
+
window.clearTimeout(tap.timer);
|
|
11223
|
+
lastTapRef.current = {
|
|
11224
|
+
timer: null,
|
|
11225
|
+
rowId: null
|
|
11226
|
+
};
|
|
11227
|
+
setContextMenu({
|
|
11228
|
+
visible: true,
|
|
11229
|
+
x: Math.max(0, Math.min(event.clientX, window.innerWidth - 180)),
|
|
11230
|
+
y: Math.max(0, Math.min(event.clientY, window.innerHeight - 160)),
|
|
11231
|
+
row
|
|
11232
|
+
});
|
|
11233
|
+
return;
|
|
11234
|
+
}
|
|
11235
|
+
window.clearTimeout(tap.timer);
|
|
11236
|
+
lastTapRef.current = {
|
|
11237
|
+
rowId: row.id,
|
|
11238
|
+
timer: window.setTimeout(() => {
|
|
11239
|
+
lastTapRef.current = {
|
|
11240
|
+
timer: null,
|
|
11241
|
+
rowId: null
|
|
11242
|
+
};
|
|
11243
|
+
openSingleTap();
|
|
11244
|
+
}, 280)
|
|
11245
|
+
};
|
|
11246
|
+
};
|
|
11166
11247
|
const content = /*#__PURE__*/React__default.createElement("div", {
|
|
11167
11248
|
key: key,
|
|
11168
11249
|
style: highlightRowStyle ? {
|
|
11169
11250
|
...style,
|
|
11170
11251
|
...highlightRowStyle
|
|
11171
11252
|
} : style,
|
|
11172
|
-
className: "table-row",
|
|
11253
|
+
className: isMobile ? "table-row mobile-clickable" : "table-row",
|
|
11254
|
+
onClick: isMobile ? handleMobileRowClick : undefined,
|
|
11173
11255
|
onContextMenu: e => {
|
|
11174
11256
|
if (!Array.isArray(enableMouseRightClick) || enableMouseRightClick.length === 0) return;
|
|
11175
11257
|
e.preventDefault();
|
|
@@ -11203,14 +11285,20 @@ function TableInner({
|
|
|
11203
11285
|
minWidth: keyWidth,
|
|
11204
11286
|
maxWidth: keyWidth
|
|
11205
11287
|
} : undefined
|
|
11206
|
-
}, visualIndex),
|
|
11288
|
+
}, visualIndex), visibleColumns.map((col, i) => {
|
|
11207
11289
|
const resolvedAccessor = getAccessorKey(row, col.accessor);
|
|
11208
11290
|
const cellValue = getAccessorValue(row, col.accessor);
|
|
11209
11291
|
const cellStyle = getCellStyle(col, i);
|
|
11210
11292
|
return /*#__PURE__*/React__default.createElement("div", {
|
|
11211
11293
|
key: i,
|
|
11212
11294
|
className: "table-cell",
|
|
11213
|
-
style:
|
|
11295
|
+
style: isMobile ? {
|
|
11296
|
+
...cellStyle,
|
|
11297
|
+
flex: "1 1 0%",
|
|
11298
|
+
width: undefined,
|
|
11299
|
+
minWidth: 0,
|
|
11300
|
+
maxWidth: "100%"
|
|
11301
|
+
} : cellStyle,
|
|
11214
11302
|
onClick: () => triggerCellCallback(row, col)
|
|
11215
11303
|
}, col.isCustom ? typeof col.render === "function" ? col.render(row, i) : col.render : renderCell(cellValue, resolvedAccessor, row, col));
|
|
11216
11304
|
})), showActions && /*#__PURE__*/React__default.createElement("div", {
|
|
@@ -11295,7 +11383,7 @@ function TableInner({
|
|
|
11295
11383
|
}, content);
|
|
11296
11384
|
}
|
|
11297
11385
|
return content;
|
|
11298
|
-
}, [tableDataFlat,
|
|
11386
|
+
}, [tableDataFlat, visibleColumns, selectedRows, toggleRowSelection, groupRowsById, renderCell, getCellStyle, showActions, showDelete, showEdit, showKey, showView, translate, enableDragRow, moveRow, enableMultiSelect, rowHeight, tableId, customColumns, isMobile, enableMouseRightClick, doubleClickEnable, keyWidth, actionColumnStyle, showDuplicate, showDownload, showIcons, showShare, getHighlightRowStyle, triggerCellCallback, getAccessorKey, getAccessorValue]);
|
|
11299
11387
|
const rightClickActions = Array.isArray(enableMouseRightClick) ? enableMouseRightClick : [];
|
|
11300
11388
|
const [hoveredActionIndex, setHoveredActionIndex] = useState(null);
|
|
11301
11389
|
const rowHeightGetter = ({
|
|
@@ -11325,19 +11413,6 @@ function TableInner({
|
|
|
11325
11413
|
externalDrop(node);
|
|
11326
11414
|
}
|
|
11327
11415
|
}, [useExternalDndContext, enableExternalRowDrop, externalDrop]);
|
|
11328
|
-
|
|
11329
|
-
// Compose columns + custom columns for header
|
|
11330
|
-
const allColumns = [...columns];
|
|
11331
|
-
if (Array.isArray(customColumns)) {
|
|
11332
|
-
customColumns.forEach(col => {
|
|
11333
|
-
if (typeof col.place === "number") {
|
|
11334
|
-
allColumns.splice(col.place, 0, {
|
|
11335
|
-
...col,
|
|
11336
|
-
isCustom: true
|
|
11337
|
-
});
|
|
11338
|
-
}
|
|
11339
|
-
});
|
|
11340
|
-
}
|
|
11341
11416
|
const tableMarkup = /*#__PURE__*/React__default.createElement("div", {
|
|
11342
11417
|
className: "table-container",
|
|
11343
11418
|
ref: setTableRef,
|
|
@@ -11378,14 +11453,20 @@ function TableInner({
|
|
|
11378
11453
|
minWidth: keyWidth,
|
|
11379
11454
|
maxWidth: keyWidth
|
|
11380
11455
|
} : undefined
|
|
11381
|
-
}, "#"),
|
|
11456
|
+
}, "#"), visibleColumns.map((col, i) => {
|
|
11382
11457
|
const cellStyle = getCellStyle(col, i);
|
|
11383
11458
|
const translatedHeader = typeof col.header === "string" ? translate(col.header) : col.header;
|
|
11384
11459
|
const headerTitle = typeof translatedHeader === "string" ? translatedHeader : undefined;
|
|
11385
11460
|
return /*#__PURE__*/React__default.createElement("div", {
|
|
11386
11461
|
key: i,
|
|
11387
11462
|
className: "table-cell header-cell",
|
|
11388
|
-
style:
|
|
11463
|
+
style: isMobile ? {
|
|
11464
|
+
...cellStyle,
|
|
11465
|
+
flex: "1 1 0%",
|
|
11466
|
+
width: undefined,
|
|
11467
|
+
minWidth: 0,
|
|
11468
|
+
maxWidth: "100%"
|
|
11469
|
+
} : cellStyle,
|
|
11389
11470
|
title: headerTitle,
|
|
11390
11471
|
onClick: col.isCustom ? undefined : () => setSort(col.accessor)
|
|
11391
11472
|
}, col.isCustom ? translatedHeader ?? "" : translatedHeader, !col.isCustom && isSameAccessor(sorting?.column, col.accessor) && (sorting.direction === "asc" ? " ↑" : " ↓"), /*#__PURE__*/React__default.createElement("div", {
|
|
@@ -11478,7 +11559,22 @@ function TableInner({
|
|
|
11478
11559
|
}, typeof contextMenuModal.component === "function" ? /*#__PURE__*/React__default.createElement(contextMenuModal.component, {
|
|
11479
11560
|
row: contextMenu.row
|
|
11480
11561
|
}) : contextMenuModal.component) : null;
|
|
11481
|
-
|
|
11562
|
+
const mobileDetailModalMarkup = mobileDetailRow ? /*#__PURE__*/React__default.createElement(Modal, {
|
|
11563
|
+
isOpen: true,
|
|
11564
|
+
title: String(mobileDetailRow.name ?? mobileDetailRow.title ?? translate("details")),
|
|
11565
|
+
onCancel: () => setMobileDetailRow(null),
|
|
11566
|
+
cancelLabel: translate("close"),
|
|
11567
|
+
showCancel: true
|
|
11568
|
+
}, /*#__PURE__*/React__default.createElement("dl", {
|
|
11569
|
+
className: "mobile-row-details"
|
|
11570
|
+
}, allColumns.map((col, index) => {
|
|
11571
|
+
const header = typeof col.header === "string" ? translate(col.header) : col.header;
|
|
11572
|
+
const value = col.isCustom ? typeof col.render === "function" ? col.render(mobileDetailRow, index) : col.render ?? "..." : formatMobileDetailValue(getAccessorValue(mobileDetailRow, col.accessor), col);
|
|
11573
|
+
return /*#__PURE__*/React__default.createElement(React__default.Fragment, {
|
|
11574
|
+
key: index
|
|
11575
|
+
}, /*#__PURE__*/React__default.createElement("dt", null, header), /*#__PURE__*/React__default.createElement("dd", null, value));
|
|
11576
|
+
}))) : null;
|
|
11577
|
+
return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, tableMarkup, contextMenuMarkup, contextMenuModalMarkup, mobileDetailModalMarkup);
|
|
11482
11578
|
}
|
|
11483
11579
|
function Table(props) {
|
|
11484
11580
|
const {
|