trotl-table 1.0.97 → 1.0.98
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 +2 -1
- package/dist/Table.cjs.js +89 -33
- package/dist/Table.cjs.js.map +1 -1
- package/dist/Table.esm.js +89 -33
- 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/README.md
CHANGED
|
@@ -127,6 +127,8 @@ export default function Demo() {
|
|
|
127
127
|
- `extraSearchTerm`: string to filter + highlight rows
|
|
128
128
|
- `rowHeight`: row height in px
|
|
129
129
|
- `groupHeaderHeight`: group header height in px
|
|
130
|
+
- `mobileColumnCount`: number of data columns shown at viewport widths of 768px or less (1 or 2; default `2`). The full row details are shown in a modal when a mobile row is clicked.
|
|
131
|
+
- `mobileRowClick`: optional callback `(row) => {}` invoked instead of opening the built-in details modal when a mobile row is clicked. Clicks on row controls and action buttons keep their existing behavior.
|
|
130
132
|
- `showKey`: show row key (true/false)
|
|
131
133
|
- `enableDragRow`: enable drag‑and‑drop (true/false)
|
|
132
134
|
- `selectedRowsCallback`: callback with selected row IDs
|
|
@@ -174,4 +176,3 @@ function Toolbar({ tableId }) {
|
|
|
174
176
|
## 🏆 License
|
|
175
177
|
|
|
176
178
|
MIT — free to use, modify, and share.
|
|
177
|
-
|
package/dist/Table.cjs.js
CHANGED
|
@@ -9687,6 +9687,8 @@ function TableInner({
|
|
|
9687
9687
|
tableId = "default",
|
|
9688
9688
|
columns = [],
|
|
9689
9689
|
data = [],
|
|
9690
|
+
mobileColumnCount = 2,
|
|
9691
|
+
mobileRowClick = null,
|
|
9690
9692
|
highlightRow = null,
|
|
9691
9693
|
isGrouped = false,
|
|
9692
9694
|
groupKey = "groupId",
|
|
@@ -9754,6 +9756,8 @@ function TableInner({
|
|
|
9754
9756
|
share: "Share",
|
|
9755
9757
|
duplicate: "Duplicate",
|
|
9756
9758
|
download: "Download",
|
|
9759
|
+
details: "Details",
|
|
9760
|
+
close: "Close",
|
|
9757
9761
|
confirmDelete: "Confirm Delete",
|
|
9758
9762
|
yesDelete: "Yes, Delete",
|
|
9759
9763
|
areYouSureYouWantToDelete: "Are you sure you want to delete",
|
|
@@ -9777,6 +9781,7 @@ function TableInner({
|
|
|
9777
9781
|
const duplicateCallbackRef = React.useRef(duplicateCallback);
|
|
9778
9782
|
const downloadCallbackRef = React.useRef(downloadCallback);
|
|
9779
9783
|
const undeleteCallbackRef = React.useRef(undeleteCallback);
|
|
9784
|
+
const mobileRowClickRef = React.useRef(mobileRowClick);
|
|
9780
9785
|
const onCellChangeRef = React.useRef(onCellChange);
|
|
9781
9786
|
const cellCallbackRef = React.useRef(cellCallback);
|
|
9782
9787
|
|
|
@@ -9788,9 +9793,16 @@ function TableInner({
|
|
|
9788
9793
|
editCallbackRef.current = editCallback;
|
|
9789
9794
|
deleteCallbackRef.current = deleteCallback;
|
|
9790
9795
|
undeleteCallbackRef.current = undeleteCallback;
|
|
9796
|
+
mobileRowClickRef.current = mobileRowClick;
|
|
9791
9797
|
onCellChangeRef.current = onCellChange;
|
|
9792
9798
|
cellCallbackRef.current = cellCallback;
|
|
9793
9799
|
});
|
|
9800
|
+
const [isMobile, setIsMobile] = React.useState(() => typeof window !== "undefined" && window.innerWidth <= 768);
|
|
9801
|
+
React.useEffect(() => {
|
|
9802
|
+
const updateMobileState = () => setIsMobile(window.innerWidth <= 768);
|
|
9803
|
+
window.addEventListener("resize", updateMobileState);
|
|
9804
|
+
return () => window.removeEventListener("resize", updateMobileState);
|
|
9805
|
+
}, []);
|
|
9794
9806
|
|
|
9795
9807
|
// Context menu right click state
|
|
9796
9808
|
const [contextMenu, setContextMenu] = React.useState({
|
|
@@ -9876,6 +9888,22 @@ function TableInner({
|
|
|
9876
9888
|
flex: "1 1 0%"
|
|
9877
9889
|
};
|
|
9878
9890
|
}, [columnWidths, getColumnKey]);
|
|
9891
|
+
const allColumns = React.useMemo(() => {
|
|
9892
|
+
const composedColumns = [...columns];
|
|
9893
|
+
if (Array.isArray(customColumns)) {
|
|
9894
|
+
customColumns.forEach(col => {
|
|
9895
|
+
if (typeof col.place === "number") {
|
|
9896
|
+
composedColumns.splice(col.place, 0, {
|
|
9897
|
+
...col,
|
|
9898
|
+
isCustom: true
|
|
9899
|
+
});
|
|
9900
|
+
}
|
|
9901
|
+
});
|
|
9902
|
+
}
|
|
9903
|
+
return composedColumns;
|
|
9904
|
+
}, [columns, customColumns]);
|
|
9905
|
+
const normalizedMobileColumnCount = Math.min(2, Math.max(1, Math.floor(Number(mobileColumnCount) || 2)));
|
|
9906
|
+
const visibleColumns = isMobile ? allColumns.slice(0, normalizedMobileColumnCount) : allColumns;
|
|
9879
9907
|
const getNestedValue = React.useCallback((row, accessor) => {
|
|
9880
9908
|
if (!row || accessor == null) return undefined;
|
|
9881
9909
|
if (Array.isArray(accessor)) {
|
|
@@ -10254,6 +10282,21 @@ function TableInner({
|
|
|
10254
10282
|
}).filter(Boolean);
|
|
10255
10283
|
return [...new Set(parts)].join(", ");
|
|
10256
10284
|
}, []);
|
|
10285
|
+
const formatMobileDetailValue = React.useCallback((value, col) => {
|
|
10286
|
+
if (value == null || value === "") return "...";
|
|
10287
|
+
if (typeof value === "boolean") return value ? "✓" : "✗";
|
|
10288
|
+
if (Array.isArray(value)) return formatArrayValue(value, col) || "...";
|
|
10289
|
+
if (value instanceof Date) {
|
|
10290
|
+
return formatDateValue(value, getColumnDateFormat(col)) || "...";
|
|
10291
|
+
}
|
|
10292
|
+
if (getColumnType(col) === "date" || col?.dateFormat) {
|
|
10293
|
+
return formatDateValue(value, getColumnDateFormat(col)) || String(value);
|
|
10294
|
+
}
|
|
10295
|
+
if (typeof value === "object") {
|
|
10296
|
+
return String(value.label ?? value.name ?? value.value ?? value);
|
|
10297
|
+
}
|
|
10298
|
+
return String(col?.translate ? translate(String(value)) : value);
|
|
10299
|
+
}, [formatArrayValue, translate]);
|
|
10257
10300
|
|
|
10258
10301
|
// console.log(extraSearchTerm)
|
|
10259
10302
|
|
|
@@ -10568,6 +10611,7 @@ function TableInner({
|
|
|
10568
10611
|
// DELETE
|
|
10569
10612
|
const [showConfirm, setShowConfirm] = React.useState(false);
|
|
10570
10613
|
const [pendingDelete, setPendingDelete] = React.useState(null);
|
|
10614
|
+
const [mobileDetailRow, setMobileDetailRow] = React.useState(null);
|
|
10571
10615
|
|
|
10572
10616
|
// perform deletion for a given row (shared by immediate & modal-confirm flows)
|
|
10573
10617
|
const doDelete = React.useCallback(async row => {
|
|
@@ -11163,19 +11207,6 @@ function TableInner({
|
|
|
11163
11207
|
const visualIndex = tableDataFlat.slice(0, index).filter(i => i.type === "row").length + 1;
|
|
11164
11208
|
const highlightRowStyle = getHighlightRowStyle(row);
|
|
11165
11209
|
|
|
11166
|
-
// Compose columns + custom columns
|
|
11167
|
-
const allColumns = [...columns];
|
|
11168
|
-
// Insert custom columns at specified places
|
|
11169
|
-
if (Array.isArray(customColumns)) {
|
|
11170
|
-
customColumns.forEach(col => {
|
|
11171
|
-
if (typeof col.place === "number") {
|
|
11172
|
-
allColumns.splice(col.place, 0, {
|
|
11173
|
-
...col,
|
|
11174
|
-
isCustom: true
|
|
11175
|
-
});
|
|
11176
|
-
}
|
|
11177
|
-
});
|
|
11178
|
-
}
|
|
11179
11210
|
// handler called when user double-clicks the non-action portion of the row
|
|
11180
11211
|
const handleRowDoubleClick = e => {
|
|
11181
11212
|
if (!doubleClickEnable) return;
|
|
@@ -11185,13 +11216,24 @@ function TableInner({
|
|
|
11185
11216
|
}
|
|
11186
11217
|
editCallbackRef.current(row);
|
|
11187
11218
|
};
|
|
11219
|
+
const handleMobileRowClick = event => {
|
|
11220
|
+
if (!isMobile || event.target.closest(".checkbox-cell, .action-cell, button, input, select, textarea, a, [contenteditable='true']")) {
|
|
11221
|
+
return;
|
|
11222
|
+
}
|
|
11223
|
+
if (typeof mobileRowClickRef.current === "function") {
|
|
11224
|
+
mobileRowClickRef.current(row);
|
|
11225
|
+
} else {
|
|
11226
|
+
setMobileDetailRow(row);
|
|
11227
|
+
}
|
|
11228
|
+
};
|
|
11188
11229
|
const content = /*#__PURE__*/React.createElement("div", {
|
|
11189
11230
|
key: key,
|
|
11190
11231
|
style: highlightRowStyle ? {
|
|
11191
11232
|
...style,
|
|
11192
11233
|
...highlightRowStyle
|
|
11193
11234
|
} : style,
|
|
11194
|
-
className: "table-row",
|
|
11235
|
+
className: isMobile ? "table-row mobile-clickable" : "table-row",
|
|
11236
|
+
onClick: isMobile ? handleMobileRowClick : undefined,
|
|
11195
11237
|
onContextMenu: e => {
|
|
11196
11238
|
if (!Array.isArray(enableMouseRightClick) || enableMouseRightClick.length === 0) return;
|
|
11197
11239
|
e.preventDefault();
|
|
@@ -11225,14 +11267,20 @@ function TableInner({
|
|
|
11225
11267
|
minWidth: keyWidth,
|
|
11226
11268
|
maxWidth: keyWidth
|
|
11227
11269
|
} : undefined
|
|
11228
|
-
}, visualIndex),
|
|
11270
|
+
}, visualIndex), visibleColumns.map((col, i) => {
|
|
11229
11271
|
const resolvedAccessor = getAccessorKey(row, col.accessor);
|
|
11230
11272
|
const cellValue = getAccessorValue(row, col.accessor);
|
|
11231
11273
|
const cellStyle = getCellStyle(col, i);
|
|
11232
11274
|
return /*#__PURE__*/React.createElement("div", {
|
|
11233
11275
|
key: i,
|
|
11234
11276
|
className: "table-cell",
|
|
11235
|
-
style:
|
|
11277
|
+
style: isMobile ? {
|
|
11278
|
+
...cellStyle,
|
|
11279
|
+
flex: "1 1 0%",
|
|
11280
|
+
width: undefined,
|
|
11281
|
+
minWidth: 0,
|
|
11282
|
+
maxWidth: "100%"
|
|
11283
|
+
} : cellStyle,
|
|
11236
11284
|
onClick: () => triggerCellCallback(row, col)
|
|
11237
11285
|
}, col.isCustom ? typeof col.render === "function" ? col.render(row, i) : col.render : renderCell(cellValue, resolvedAccessor, row, col));
|
|
11238
11286
|
})), showActions && /*#__PURE__*/React.createElement("div", {
|
|
@@ -11317,7 +11365,7 @@ function TableInner({
|
|
|
11317
11365
|
}, content);
|
|
11318
11366
|
}
|
|
11319
11367
|
return content;
|
|
11320
|
-
}, [tableDataFlat,
|
|
11368
|
+
}, [tableDataFlat, visibleColumns, selectedRows, toggleRowSelection, groupRowsById, renderCell, getCellStyle, showActions, showDelete, showEdit, showKey, showView, translate, enableDragRow, moveRow, enableMultiSelect, rowHeight, tableId, customColumns, isMobile, doubleClickEnable, keyWidth, actionColumnStyle, showDuplicate, showDownload, showIcons, showShare, getHighlightRowStyle, triggerCellCallback, getAccessorKey, getAccessorValue]);
|
|
11321
11369
|
const rightClickActions = Array.isArray(enableMouseRightClick) ? enableMouseRightClick : [];
|
|
11322
11370
|
const [hoveredActionIndex, setHoveredActionIndex] = React.useState(null);
|
|
11323
11371
|
const rowHeightGetter = ({
|
|
@@ -11347,19 +11395,6 @@ function TableInner({
|
|
|
11347
11395
|
externalDrop(node);
|
|
11348
11396
|
}
|
|
11349
11397
|
}, [useExternalDndContext, enableExternalRowDrop, externalDrop]);
|
|
11350
|
-
|
|
11351
|
-
// Compose columns + custom columns for header
|
|
11352
|
-
const allColumns = [...columns];
|
|
11353
|
-
if (Array.isArray(customColumns)) {
|
|
11354
|
-
customColumns.forEach(col => {
|
|
11355
|
-
if (typeof col.place === "number") {
|
|
11356
|
-
allColumns.splice(col.place, 0, {
|
|
11357
|
-
...col,
|
|
11358
|
-
isCustom: true
|
|
11359
|
-
});
|
|
11360
|
-
}
|
|
11361
|
-
});
|
|
11362
|
-
}
|
|
11363
11398
|
const tableMarkup = /*#__PURE__*/React.createElement("div", {
|
|
11364
11399
|
className: "table-container",
|
|
11365
11400
|
ref: setTableRef,
|
|
@@ -11400,14 +11435,20 @@ function TableInner({
|
|
|
11400
11435
|
minWidth: keyWidth,
|
|
11401
11436
|
maxWidth: keyWidth
|
|
11402
11437
|
} : undefined
|
|
11403
|
-
}, "#"),
|
|
11438
|
+
}, "#"), visibleColumns.map((col, i) => {
|
|
11404
11439
|
const cellStyle = getCellStyle(col, i);
|
|
11405
11440
|
const translatedHeader = typeof col.header === "string" ? translate(col.header) : col.header;
|
|
11406
11441
|
const headerTitle = typeof translatedHeader === "string" ? translatedHeader : undefined;
|
|
11407
11442
|
return /*#__PURE__*/React.createElement("div", {
|
|
11408
11443
|
key: i,
|
|
11409
11444
|
className: "table-cell header-cell",
|
|
11410
|
-
style:
|
|
11445
|
+
style: isMobile ? {
|
|
11446
|
+
...cellStyle,
|
|
11447
|
+
flex: "1 1 0%",
|
|
11448
|
+
width: undefined,
|
|
11449
|
+
minWidth: 0,
|
|
11450
|
+
maxWidth: "100%"
|
|
11451
|
+
} : cellStyle,
|
|
11411
11452
|
title: headerTitle,
|
|
11412
11453
|
onClick: col.isCustom ? undefined : () => setSort(col.accessor)
|
|
11413
11454
|
}, col.isCustom ? translatedHeader ?? "" : translatedHeader, !col.isCustom && isSameAccessor(sorting?.column, col.accessor) && (sorting.direction === "asc" ? " ↑" : " ↓"), /*#__PURE__*/React.createElement("div", {
|
|
@@ -11500,7 +11541,22 @@ function TableInner({
|
|
|
11500
11541
|
}, typeof contextMenuModal.component === "function" ? /*#__PURE__*/React.createElement(contextMenuModal.component, {
|
|
11501
11542
|
row: contextMenu.row
|
|
11502
11543
|
}) : contextMenuModal.component) : null;
|
|
11503
|
-
|
|
11544
|
+
const mobileDetailModalMarkup = mobileDetailRow ? /*#__PURE__*/React.createElement(Modal.default, {
|
|
11545
|
+
isOpen: true,
|
|
11546
|
+
title: String(mobileDetailRow.name ?? mobileDetailRow.title ?? translate("details")),
|
|
11547
|
+
onCancel: () => setMobileDetailRow(null),
|
|
11548
|
+
cancelLabel: translate("close"),
|
|
11549
|
+
showCancel: true
|
|
11550
|
+
}, /*#__PURE__*/React.createElement("dl", {
|
|
11551
|
+
className: "mobile-row-details"
|
|
11552
|
+
}, allColumns.map((col, index) => {
|
|
11553
|
+
const header = typeof col.header === "string" ? translate(col.header) : col.header;
|
|
11554
|
+
const value = col.isCustom ? typeof col.render === "function" ? col.render(mobileDetailRow, index) : col.render ?? "..." : formatMobileDetailValue(getAccessorValue(mobileDetailRow, col.accessor), col);
|
|
11555
|
+
return /*#__PURE__*/React.createElement(React.Fragment, {
|
|
11556
|
+
key: index
|
|
11557
|
+
}, /*#__PURE__*/React.createElement("dt", null, header), /*#__PURE__*/React.createElement("dd", null, value));
|
|
11558
|
+
}))) : null;
|
|
11559
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, tableMarkup, contextMenuMarkup, contextMenuModalMarkup, mobileDetailModalMarkup);
|
|
11504
11560
|
}
|
|
11505
11561
|
function Table(props) {
|
|
11506
11562
|
const {
|