bolt-table 0.1.13 → 0.1.14
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 +228 -2
- package/dist/index.d.mts +38 -1
- package/dist/index.d.ts +38 -1
- package/dist/index.js +475 -149
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +475 -149
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -110,6 +110,10 @@ var PinOffIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtim
|
|
|
110
110
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", x2: "12", y1: "17", y2: "22" }),
|
|
111
111
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 9v1.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V17h14v-1.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V6h1a2 2 0 0 0 0-4H8a2 2 0 0 0 0 4" })
|
|
112
112
|
] });
|
|
113
|
+
var CopyIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
|
|
114
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2" }),
|
|
115
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
|
|
116
|
+
] });
|
|
113
117
|
var EyeOffIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
|
|
114
118
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }),
|
|
115
119
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }),
|
|
@@ -165,21 +169,49 @@ var DraggableHeader = import_react.default.memo(
|
|
|
165
169
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
166
170
|
}
|
|
167
171
|
}, [contextMenu]);
|
|
168
|
-
const
|
|
169
|
-
e.preventDefault();
|
|
170
|
-
e.stopPropagation();
|
|
172
|
+
const showContextMenuAt = (clientX, clientY) => {
|
|
171
173
|
const menuWidth = 160;
|
|
172
174
|
const menuHeight = 180;
|
|
173
|
-
let x =
|
|
174
|
-
let y =
|
|
175
|
-
if (x + menuWidth > window.innerWidth)
|
|
175
|
+
let x = clientX;
|
|
176
|
+
let y = clientY;
|
|
177
|
+
if (x + menuWidth > window.innerWidth)
|
|
176
178
|
x = window.innerWidth - menuWidth - 10;
|
|
177
|
-
|
|
178
|
-
if (y + menuHeight > window.innerHeight) {
|
|
179
|
+
if (y + menuHeight > window.innerHeight)
|
|
179
180
|
y = window.innerHeight - menuHeight - 10;
|
|
180
|
-
}
|
|
181
181
|
setContextMenu({ x, y });
|
|
182
182
|
};
|
|
183
|
+
const handleContextMenu = (e) => {
|
|
184
|
+
e.preventDefault();
|
|
185
|
+
e.stopPropagation();
|
|
186
|
+
showContextMenuAt(e.clientX, e.clientY);
|
|
187
|
+
};
|
|
188
|
+
const longPressTimerRef = (0, import_react.useRef)(
|
|
189
|
+
null
|
|
190
|
+
);
|
|
191
|
+
const touchStartRef = (0, import_react.useRef)(null);
|
|
192
|
+
const cancelLongPress = () => {
|
|
193
|
+
if (longPressTimerRef.current) {
|
|
194
|
+
clearTimeout(longPressTimerRef.current);
|
|
195
|
+
longPressTimerRef.current = null;
|
|
196
|
+
}
|
|
197
|
+
touchStartRef.current = null;
|
|
198
|
+
};
|
|
199
|
+
const handleTouchStart = (e) => {
|
|
200
|
+
cancelLongPress();
|
|
201
|
+
const touch = e.touches[0];
|
|
202
|
+
touchStartRef.current = { x: touch.clientX, y: touch.clientY };
|
|
203
|
+
longPressTimerRef.current = setTimeout(() => {
|
|
204
|
+
longPressTimerRef.current = null;
|
|
205
|
+
showContextMenuAt(touch.clientX, touch.clientY);
|
|
206
|
+
}, 500);
|
|
207
|
+
};
|
|
208
|
+
const handleTouchMove = (e) => {
|
|
209
|
+
if (!touchStartRef.current) return;
|
|
210
|
+
const touch = e.touches[0];
|
|
211
|
+
const dx = touch.clientX - touchStartRef.current.x;
|
|
212
|
+
const dy = touch.clientY - touchStartRef.current.y;
|
|
213
|
+
if (Math.abs(dx) > 10 || Math.abs(dy) > 10) cancelLongPress();
|
|
214
|
+
};
|
|
183
215
|
const handleResizeStart = (e) => {
|
|
184
216
|
e.preventDefault();
|
|
185
217
|
e.stopPropagation();
|
|
@@ -229,6 +261,10 @@ var DraggableHeader = import_react.default.memo(
|
|
|
229
261
|
style: headerStyle,
|
|
230
262
|
className: `${column.className ?? ""} ${classNames?.header ?? ""} ${isPinned ? classNames?.pinnedHeader ?? "" : ""}`,
|
|
231
263
|
onContextMenu: handleContextMenu,
|
|
264
|
+
onTouchStart: handleTouchStart,
|
|
265
|
+
onTouchMove: handleTouchMove,
|
|
266
|
+
onTouchEnd: cancelLongPress,
|
|
267
|
+
onTouchCancel: cancelLongPress,
|
|
232
268
|
children: [
|
|
233
269
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
234
270
|
"div",
|
|
@@ -1110,6 +1146,8 @@ var TableBody = ({
|
|
|
1110
1146
|
"div",
|
|
1111
1147
|
{
|
|
1112
1148
|
"data-row-key": rowKey,
|
|
1149
|
+
"data-column-key": col.key,
|
|
1150
|
+
"data-bt-cell": "",
|
|
1113
1151
|
"data-selected": isSelected || void 0,
|
|
1114
1152
|
style: {
|
|
1115
1153
|
position: "absolute",
|
|
@@ -1224,85 +1262,100 @@ var TableBody = ({
|
|
|
1224
1262
|
style: {
|
|
1225
1263
|
gridColumn: "1 / -1",
|
|
1226
1264
|
gridRow: 2,
|
|
1227
|
-
|
|
1228
|
-
|
|
1265
|
+
height: `${totalSize}px`,
|
|
1266
|
+
position: "relative",
|
|
1229
1267
|
zIndex: 20,
|
|
1230
|
-
|
|
1268
|
+
pointerEvents: "none"
|
|
1231
1269
|
},
|
|
1232
|
-
children:
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
backgroundColor: pinnedRowBg,
|
|
1266
|
-
...isPinned && styles?.pinnedCell ? styles.pinnedCell : {}
|
|
1267
|
-
},
|
|
1268
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1270
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1271
|
+
"div",
|
|
1272
|
+
{
|
|
1273
|
+
style: {
|
|
1274
|
+
position: "sticky",
|
|
1275
|
+
top: headerHeight,
|
|
1276
|
+
pointerEvents: "auto",
|
|
1277
|
+
boxShadow: "0 2px 6px -1px rgba(0,0,0,0.08)"
|
|
1278
|
+
},
|
|
1279
|
+
children: pinnedTopData.map((row, rowIdx) => {
|
|
1280
|
+
const rk = getRowKey ? getRowKey(row, rowIdx) : String(rowIdx);
|
|
1281
|
+
const isSelected = selectedKeySet.has(rk);
|
|
1282
|
+
const isExpanded = resolvedExpandedKeys?.has(rk) ?? false;
|
|
1283
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1284
|
+
"div",
|
|
1285
|
+
{
|
|
1286
|
+
className: classNames?.pinnedRow ?? "",
|
|
1287
|
+
style: {
|
|
1288
|
+
display: "grid",
|
|
1289
|
+
gridTemplateColumns: gridTemplateColumns ?? "",
|
|
1290
|
+
minWidth: totalTableWidth ? `${totalTableWidth}px` : void 0,
|
|
1291
|
+
...styles?.pinnedRow
|
|
1292
|
+
},
|
|
1293
|
+
children: orderedColumns.map((col) => {
|
|
1294
|
+
const cellValue = row[col.dataIndex];
|
|
1295
|
+
const stickyOffset = columnOffsets.get(col.key);
|
|
1296
|
+
const isPinned = Boolean(col.pinned);
|
|
1297
|
+
let zIndex = 0;
|
|
1298
|
+
if (col.key === "__select__" || col.key === "__expand__")
|
|
1299
|
+
zIndex = 11;
|
|
1300
|
+
else if (isPinned) zIndex = 2;
|
|
1301
|
+
const recordFingerprint = col.render ? JSON.stringify(row) : void 0;
|
|
1302
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1269
1303
|
"div",
|
|
1270
1304
|
{
|
|
1305
|
+
"data-row-key": rk,
|
|
1306
|
+
"data-column-key": col.key,
|
|
1307
|
+
"data-bt-cell": "",
|
|
1308
|
+
"data-selected": isSelected || void 0,
|
|
1271
1309
|
style: {
|
|
1272
|
-
|
|
1273
|
-
|
|
1310
|
+
position: isPinned ? "sticky" : "relative",
|
|
1311
|
+
...col.pinned === "left" && stickyOffset !== void 0 ? { left: `${stickyOffset}px` } : {},
|
|
1312
|
+
...col.pinned === "right" && stickyOffset !== void 0 ? { right: `${stickyOffset}px` } : {},
|
|
1313
|
+
zIndex,
|
|
1314
|
+
backgroundColor: pinnedRowBg,
|
|
1315
|
+
backdropFilter: "blur(12px)",
|
|
1316
|
+
WebkitBackdropFilter: "blur(12px)",
|
|
1317
|
+
...isPinned && styles?.pinnedCell ? styles.pinnedCell : {}
|
|
1274
1318
|
},
|
|
1275
1319
|
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1276
|
-
|
|
1320
|
+
"div",
|
|
1277
1321
|
{
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1322
|
+
style: {
|
|
1323
|
+
height: `${rowHeight}px`,
|
|
1324
|
+
position: "relative"
|
|
1325
|
+
},
|
|
1326
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1327
|
+
Cell,
|
|
1328
|
+
{
|
|
1329
|
+
value: cellValue,
|
|
1330
|
+
record: row,
|
|
1331
|
+
column: col,
|
|
1332
|
+
rowIndex: rowIdx,
|
|
1333
|
+
classNames,
|
|
1334
|
+
styles,
|
|
1335
|
+
isSelected,
|
|
1336
|
+
isExpanded,
|
|
1337
|
+
rowSelection,
|
|
1338
|
+
normalizedSelectedKeys,
|
|
1339
|
+
rowKey: rk,
|
|
1340
|
+
allData: allDataForSelection,
|
|
1341
|
+
getRowKey,
|
|
1342
|
+
accentColor,
|
|
1343
|
+
isLoading: false,
|
|
1344
|
+
recordFingerprint
|
|
1345
|
+
}
|
|
1346
|
+
)
|
|
1294
1347
|
}
|
|
1295
1348
|
)
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1349
|
+
},
|
|
1350
|
+
col.key
|
|
1351
|
+
);
|
|
1352
|
+
})
|
|
1353
|
+
},
|
|
1354
|
+
`pinned-top-${rk}`
|
|
1355
|
+
);
|
|
1356
|
+
})
|
|
1357
|
+
}
|
|
1358
|
+
)
|
|
1306
1359
|
}
|
|
1307
1360
|
),
|
|
1308
1361
|
pinnedBottomData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -1311,86 +1364,103 @@ var TableBody = ({
|
|
|
1311
1364
|
style: {
|
|
1312
1365
|
gridColumn: "1 / -1",
|
|
1313
1366
|
gridRow: 2,
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
alignSelf: "end",
|
|
1367
|
+
height: `${totalSize}px`,
|
|
1368
|
+
position: "relative",
|
|
1317
1369
|
zIndex: 20,
|
|
1318
|
-
|
|
1370
|
+
pointerEvents: "none",
|
|
1371
|
+
display: "flex",
|
|
1372
|
+
flexDirection: "column"
|
|
1319
1373
|
},
|
|
1320
|
-
children:
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
...isPinned && styles?.pinnedCell ? styles.pinnedCell : {}
|
|
1355
|
-
},
|
|
1356
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1374
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1375
|
+
"div",
|
|
1376
|
+
{
|
|
1377
|
+
style: {
|
|
1378
|
+
marginTop: "auto",
|
|
1379
|
+
position: "sticky",
|
|
1380
|
+
bottom: 0,
|
|
1381
|
+
pointerEvents: "auto",
|
|
1382
|
+
boxShadow: "0 -2px 6px -1px rgba(0,0,0,0.08)"
|
|
1383
|
+
},
|
|
1384
|
+
children: pinnedBottomData.map((row, rowIdx) => {
|
|
1385
|
+
const rk = getRowKey ? getRowKey(row, rowIdx) : String(rowIdx);
|
|
1386
|
+
const isSelected = selectedKeySet.has(rk);
|
|
1387
|
+
const isExpanded = resolvedExpandedKeys?.has(rk) ?? false;
|
|
1388
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1389
|
+
"div",
|
|
1390
|
+
{
|
|
1391
|
+
className: classNames?.pinnedRow ?? "",
|
|
1392
|
+
style: {
|
|
1393
|
+
display: "grid",
|
|
1394
|
+
gridTemplateColumns: gridTemplateColumns ?? "",
|
|
1395
|
+
minWidth: totalTableWidth ? `${totalTableWidth}px` : void 0,
|
|
1396
|
+
...styles?.pinnedRow
|
|
1397
|
+
},
|
|
1398
|
+
children: orderedColumns.map((col) => {
|
|
1399
|
+
const cellValue = row[col.dataIndex];
|
|
1400
|
+
const stickyOffset = columnOffsets.get(col.key);
|
|
1401
|
+
const isPinned = Boolean(col.pinned);
|
|
1402
|
+
let zIndex = 0;
|
|
1403
|
+
if (col.key === "__select__" || col.key === "__expand__")
|
|
1404
|
+
zIndex = 11;
|
|
1405
|
+
else if (isPinned) zIndex = 2;
|
|
1406
|
+
const recordFingerprint = col.render ? JSON.stringify(row) : void 0;
|
|
1407
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1357
1408
|
"div",
|
|
1358
1409
|
{
|
|
1410
|
+
"data-row-key": rk,
|
|
1411
|
+
"data-column-key": col.key,
|
|
1412
|
+
"data-bt-cell": "",
|
|
1413
|
+
"data-selected": isSelected || void 0,
|
|
1359
1414
|
style: {
|
|
1360
|
-
|
|
1361
|
-
|
|
1415
|
+
position: isPinned ? "sticky" : "relative",
|
|
1416
|
+
...col.pinned === "left" && stickyOffset !== void 0 ? { left: `${stickyOffset}px` } : {},
|
|
1417
|
+
...col.pinned === "right" && stickyOffset !== void 0 ? { right: `${stickyOffset}px` } : {},
|
|
1418
|
+
zIndex,
|
|
1419
|
+
backgroundColor: pinnedRowBg,
|
|
1420
|
+
backdropFilter: "blur(12px)",
|
|
1421
|
+
WebkitBackdropFilter: "blur(12px)",
|
|
1422
|
+
...isPinned && styles?.pinnedCell ? styles.pinnedCell : {}
|
|
1362
1423
|
},
|
|
1363
1424
|
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1364
|
-
|
|
1425
|
+
"div",
|
|
1365
1426
|
{
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1427
|
+
style: {
|
|
1428
|
+
height: `${rowHeight}px`,
|
|
1429
|
+
position: "relative"
|
|
1430
|
+
},
|
|
1431
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1432
|
+
Cell,
|
|
1433
|
+
{
|
|
1434
|
+
value: cellValue,
|
|
1435
|
+
record: row,
|
|
1436
|
+
column: col,
|
|
1437
|
+
rowIndex: rowIdx,
|
|
1438
|
+
classNames,
|
|
1439
|
+
styles,
|
|
1440
|
+
isSelected,
|
|
1441
|
+
isExpanded,
|
|
1442
|
+
rowSelection,
|
|
1443
|
+
normalizedSelectedKeys,
|
|
1444
|
+
rowKey: rk,
|
|
1445
|
+
allData: allDataForSelection,
|
|
1446
|
+
getRowKey,
|
|
1447
|
+
accentColor,
|
|
1448
|
+
isLoading: false,
|
|
1449
|
+
recordFingerprint
|
|
1450
|
+
}
|
|
1451
|
+
)
|
|
1382
1452
|
}
|
|
1383
1453
|
)
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1454
|
+
},
|
|
1455
|
+
col.key
|
|
1456
|
+
);
|
|
1457
|
+
})
|
|
1458
|
+
},
|
|
1459
|
+
`pinned-bottom-${rk}`
|
|
1460
|
+
);
|
|
1461
|
+
})
|
|
1462
|
+
}
|
|
1463
|
+
)
|
|
1394
1464
|
}
|
|
1395
1465
|
)
|
|
1396
1466
|
] });
|
|
@@ -1428,6 +1498,7 @@ function BoltTable({
|
|
|
1428
1498
|
onColumnHide,
|
|
1429
1499
|
rowSelection,
|
|
1430
1500
|
rowPinning,
|
|
1501
|
+
onRowPin,
|
|
1431
1502
|
expandable,
|
|
1432
1503
|
rowKey = "id",
|
|
1433
1504
|
onEndReached,
|
|
@@ -1997,6 +2068,44 @@ function BoltTable({
|
|
|
1997
2068
|
}, [processedData, rowPinning, getRowKey]);
|
|
1998
2069
|
const pinnedTopHeight = pinnedTopRows.length * rowHeight;
|
|
1999
2070
|
const pinnedBottomHeight = pinnedBottomRows.length * rowHeight;
|
|
2071
|
+
const pinnedTopKeySet = (0, import_react4.useMemo)(
|
|
2072
|
+
() => new Set((rowPinning?.top ?? []).map(String)),
|
|
2073
|
+
[rowPinning?.top]
|
|
2074
|
+
);
|
|
2075
|
+
const pinnedBottomKeySet = (0, import_react4.useMemo)(
|
|
2076
|
+
() => new Set((rowPinning?.bottom ?? []).map(String)),
|
|
2077
|
+
[rowPinning?.bottom]
|
|
2078
|
+
);
|
|
2079
|
+
const [cellContextMenu, setCellContextMenu] = (0, import_react4.useState)(null);
|
|
2080
|
+
const cellMenuRef = (0, import_react4.useRef)(null);
|
|
2081
|
+
const cellLongPressTimer = (0, import_react4.useRef)(
|
|
2082
|
+
null
|
|
2083
|
+
);
|
|
2084
|
+
const cellTouchStart = (0, import_react4.useRef)(null);
|
|
2085
|
+
const cancelCellLongPress = (0, import_react4.useCallback)(() => {
|
|
2086
|
+
if (cellLongPressTimer.current) {
|
|
2087
|
+
clearTimeout(cellLongPressTimer.current);
|
|
2088
|
+
cellLongPressTimer.current = null;
|
|
2089
|
+
}
|
|
2090
|
+
cellTouchStart.current = null;
|
|
2091
|
+
}, []);
|
|
2092
|
+
import_react4.default.useEffect(() => {
|
|
2093
|
+
if (!cellContextMenu) return;
|
|
2094
|
+
const close = (e) => {
|
|
2095
|
+
if (cellMenuRef.current && cellMenuRef.current.contains(e.target))
|
|
2096
|
+
return;
|
|
2097
|
+
setCellContextMenu(null);
|
|
2098
|
+
};
|
|
2099
|
+
const onKey = (e) => {
|
|
2100
|
+
if (e.key === "Escape") setCellContextMenu(null);
|
|
2101
|
+
};
|
|
2102
|
+
document.addEventListener("mousedown", close);
|
|
2103
|
+
document.addEventListener("keydown", onKey);
|
|
2104
|
+
return () => {
|
|
2105
|
+
document.removeEventListener("mousedown", close);
|
|
2106
|
+
document.removeEventListener("keydown", onKey);
|
|
2107
|
+
};
|
|
2108
|
+
}, [cellContextMenu]);
|
|
2000
2109
|
const columnFiltersKey = Object.keys(columnFilters).sort().map((k) => `${k}:${columnFilters[k]}`).join("|");
|
|
2001
2110
|
import_react4.default.useEffect(() => {
|
|
2002
2111
|
tableAreaRef.current?.scrollTo({ top: 0 });
|
|
@@ -2358,6 +2467,64 @@ function BoltTable({
|
|
|
2358
2467
|
position: "relative",
|
|
2359
2468
|
...isEmpty ? { height: "100%" } : {}
|
|
2360
2469
|
},
|
|
2470
|
+
onContextMenu: (e) => {
|
|
2471
|
+
const cell = e.target.closest("[data-bt-cell]");
|
|
2472
|
+
if (!cell) return;
|
|
2473
|
+
const rk = cell.dataset.rowKey;
|
|
2474
|
+
const ck = cell.dataset.columnKey;
|
|
2475
|
+
if (!rk || !ck) return;
|
|
2476
|
+
const col = freshOrderedColumns.find(
|
|
2477
|
+
(c) => c.key === ck
|
|
2478
|
+
);
|
|
2479
|
+
const hasCopy = col?.copy;
|
|
2480
|
+
const hasRowPin = !!onRowPin;
|
|
2481
|
+
if (!hasCopy && !hasRowPin) return;
|
|
2482
|
+
e.preventDefault();
|
|
2483
|
+
setCellContextMenu({
|
|
2484
|
+
x: Math.min(e.clientX, window.innerWidth - 200),
|
|
2485
|
+
y: Math.min(e.clientY, window.innerHeight - 200),
|
|
2486
|
+
rowKey: rk,
|
|
2487
|
+
columnKey: ck
|
|
2488
|
+
});
|
|
2489
|
+
},
|
|
2490
|
+
onTouchStart: (e) => {
|
|
2491
|
+
cancelCellLongPress();
|
|
2492
|
+
const cell = e.target.closest("[data-bt-cell]");
|
|
2493
|
+
if (!cell) return;
|
|
2494
|
+
const touch = e.touches[0];
|
|
2495
|
+
cellTouchStart.current = {
|
|
2496
|
+
x: touch.clientX,
|
|
2497
|
+
y: touch.clientY
|
|
2498
|
+
};
|
|
2499
|
+
const rk = cell.dataset.rowKey;
|
|
2500
|
+
const ck = cell.dataset.columnKey;
|
|
2501
|
+
cellLongPressTimer.current = setTimeout(() => {
|
|
2502
|
+
cellLongPressTimer.current = null;
|
|
2503
|
+
if (!rk || !ck) return;
|
|
2504
|
+
const col = freshOrderedColumns.find(
|
|
2505
|
+
(c) => c.key === ck
|
|
2506
|
+
);
|
|
2507
|
+
const hasCopy = col?.copy;
|
|
2508
|
+
const hasRowPin = !!onRowPin;
|
|
2509
|
+
if (!hasCopy && !hasRowPin) return;
|
|
2510
|
+
setCellContextMenu({
|
|
2511
|
+
x: Math.min(touch.clientX, window.innerWidth - 200),
|
|
2512
|
+
y: Math.min(touch.clientY, window.innerHeight - 200),
|
|
2513
|
+
rowKey: rk,
|
|
2514
|
+
columnKey: ck
|
|
2515
|
+
});
|
|
2516
|
+
}, 500);
|
|
2517
|
+
},
|
|
2518
|
+
onTouchMove: (e) => {
|
|
2519
|
+
if (!cellTouchStart.current) return;
|
|
2520
|
+
const touch = e.touches[0];
|
|
2521
|
+
const dx = touch.clientX - cellTouchStart.current.x;
|
|
2522
|
+
const dy = touch.clientY - cellTouchStart.current.y;
|
|
2523
|
+
if (Math.abs(dx) > 10 || Math.abs(dy) > 10)
|
|
2524
|
+
cancelCellLongPress();
|
|
2525
|
+
},
|
|
2526
|
+
onTouchEnd: cancelCellLongPress,
|
|
2527
|
+
onTouchCancel: cancelCellLongPress,
|
|
2361
2528
|
children: [
|
|
2362
2529
|
orderedColumns.map((column, visualIndex) => {
|
|
2363
2530
|
if (column.key === "__select__" && rowSelection) {
|
|
@@ -2856,7 +3023,166 @@ function BoltTable({
|
|
|
2856
3023
|
}
|
|
2857
3024
|
),
|
|
2858
3025
|
document.body
|
|
2859
|
-
)
|
|
3026
|
+
),
|
|
3027
|
+
cellContextMenu && typeof document !== "undefined" && (() => {
|
|
3028
|
+
const menuCol = freshOrderedColumns.find(
|
|
3029
|
+
(c) => c.key === cellContextMenu.columnKey
|
|
3030
|
+
);
|
|
3031
|
+
const isPinnedTop = pinnedTopKeySet.has(cellContextMenu.rowKey);
|
|
3032
|
+
const isPinnedBottom = pinnedBottomKeySet.has(
|
|
3033
|
+
cellContextMenu.rowKey
|
|
3034
|
+
);
|
|
3035
|
+
const hasCopy = menuCol?.copy;
|
|
3036
|
+
const hasRowPin = !!onRowPin;
|
|
3037
|
+
let menuRecord;
|
|
3038
|
+
let menuRowIndex = 0;
|
|
3039
|
+
const allRows = [
|
|
3040
|
+
...pinnedTopRows,
|
|
3041
|
+
...displayData,
|
|
3042
|
+
...pinnedBottomRows
|
|
3043
|
+
];
|
|
3044
|
+
for (let i = 0; i < allRows.length; i++) {
|
|
3045
|
+
const rk = getRowKey(allRows[i], i);
|
|
3046
|
+
if (rk === cellContextMenu.rowKey) {
|
|
3047
|
+
menuRecord = allRows[i];
|
|
3048
|
+
menuRowIndex = i;
|
|
3049
|
+
break;
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
const menuValue = menuRecord && menuCol ? menuRecord[menuCol.dataIndex] : void 0;
|
|
3053
|
+
const btnStyle = {
|
|
3054
|
+
display: "flex",
|
|
3055
|
+
width: "100%",
|
|
3056
|
+
alignItems: "center",
|
|
3057
|
+
gap: 8,
|
|
3058
|
+
background: "none",
|
|
3059
|
+
border: "none",
|
|
3060
|
+
padding: "6px 12px",
|
|
3061
|
+
fontSize: 12,
|
|
3062
|
+
cursor: "pointer",
|
|
3063
|
+
color: "inherit",
|
|
3064
|
+
whiteSpace: "nowrap"
|
|
3065
|
+
};
|
|
3066
|
+
return (0, import_react_dom2.createPortal)(
|
|
3067
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3068
|
+
"div",
|
|
3069
|
+
{
|
|
3070
|
+
ref: cellMenuRef,
|
|
3071
|
+
style: {
|
|
3072
|
+
position: "fixed",
|
|
3073
|
+
top: cellContextMenu.y,
|
|
3074
|
+
left: cellContextMenu.x,
|
|
3075
|
+
zIndex: 99999,
|
|
3076
|
+
minWidth: 170,
|
|
3077
|
+
borderRadius: 8,
|
|
3078
|
+
border: "1px solid rgba(128,128,128,0.2)",
|
|
3079
|
+
boxShadow: "0 4px 24px rgba(0,0,0,0.12)",
|
|
3080
|
+
backdropFilter: "blur(16px)",
|
|
3081
|
+
WebkitBackdropFilter: "blur(16px)",
|
|
3082
|
+
backgroundColor: "rgba(128,128,128,0.08)",
|
|
3083
|
+
padding: "4px 0",
|
|
3084
|
+
fontSize: 10
|
|
3085
|
+
},
|
|
3086
|
+
children: [
|
|
3087
|
+
hasRowPin && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
3088
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3089
|
+
"button",
|
|
3090
|
+
{
|
|
3091
|
+
"data-bt-ctx-item": true,
|
|
3092
|
+
style: btnStyle,
|
|
3093
|
+
onClick: () => {
|
|
3094
|
+
onRowPin(
|
|
3095
|
+
cellContextMenu.rowKey,
|
|
3096
|
+
isPinnedTop ? false : "top"
|
|
3097
|
+
);
|
|
3098
|
+
setCellContextMenu(null);
|
|
3099
|
+
},
|
|
3100
|
+
children: [
|
|
3101
|
+
isPinnedTop ? icons?.pinOff ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3102
|
+
PinOffIcon,
|
|
3103
|
+
{
|
|
3104
|
+
style: { width: 14, height: 14, flexShrink: 0 }
|
|
3105
|
+
}
|
|
3106
|
+
) : icons?.pin ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3107
|
+
PinIcon,
|
|
3108
|
+
{
|
|
3109
|
+
style: { width: 14, height: 14, flexShrink: 0 }
|
|
3110
|
+
}
|
|
3111
|
+
),
|
|
3112
|
+
isPinnedTop ? "Unpin Row from Top" : "Pin Row to Top"
|
|
3113
|
+
]
|
|
3114
|
+
}
|
|
3115
|
+
),
|
|
3116
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3117
|
+
"button",
|
|
3118
|
+
{
|
|
3119
|
+
"data-bt-ctx-item": true,
|
|
3120
|
+
style: btnStyle,
|
|
3121
|
+
onClick: () => {
|
|
3122
|
+
onRowPin(
|
|
3123
|
+
cellContextMenu.rowKey,
|
|
3124
|
+
isPinnedBottom ? false : "bottom"
|
|
3125
|
+
);
|
|
3126
|
+
setCellContextMenu(null);
|
|
3127
|
+
},
|
|
3128
|
+
children: [
|
|
3129
|
+
isPinnedBottom ? icons?.pinOff ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3130
|
+
PinOffIcon,
|
|
3131
|
+
{
|
|
3132
|
+
style: { width: 14, height: 14, flexShrink: 0 }
|
|
3133
|
+
}
|
|
3134
|
+
) : icons?.pin ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3135
|
+
PinIcon,
|
|
3136
|
+
{
|
|
3137
|
+
style: {
|
|
3138
|
+
width: 14,
|
|
3139
|
+
height: 14,
|
|
3140
|
+
flexShrink: 0,
|
|
3141
|
+
transform: "rotate(180deg)"
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
),
|
|
3145
|
+
isPinnedBottom ? "Unpin Row from Bottom" : "Pin Row to Bottom"
|
|
3146
|
+
]
|
|
3147
|
+
}
|
|
3148
|
+
)
|
|
3149
|
+
] }),
|
|
3150
|
+
hasRowPin && hasCopy && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3151
|
+
"div",
|
|
3152
|
+
{
|
|
3153
|
+
style: {
|
|
3154
|
+
borderTop: "1px solid rgba(128,128,128,0.2)",
|
|
3155
|
+
margin: "4px 0"
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
),
|
|
3159
|
+
hasCopy && menuRecord && menuCol && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3160
|
+
"button",
|
|
3161
|
+
{
|
|
3162
|
+
"data-bt-ctx-item": true,
|
|
3163
|
+
style: btnStyle,
|
|
3164
|
+
onClick: () => {
|
|
3165
|
+
const text = typeof menuCol.copy === "function" ? menuCol.copy(menuValue, menuRecord, menuRowIndex) : String(menuValue ?? "");
|
|
3166
|
+
navigator.clipboard?.writeText(text);
|
|
3167
|
+
setCellContextMenu(null);
|
|
3168
|
+
},
|
|
3169
|
+
children: [
|
|
3170
|
+
icons?.copy ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3171
|
+
CopyIcon,
|
|
3172
|
+
{
|
|
3173
|
+
style: { width: 14, height: 14, flexShrink: 0 }
|
|
3174
|
+
}
|
|
3175
|
+
),
|
|
3176
|
+
"Copy"
|
|
3177
|
+
]
|
|
3178
|
+
}
|
|
3179
|
+
)
|
|
3180
|
+
]
|
|
3181
|
+
}
|
|
3182
|
+
),
|
|
3183
|
+
document.body
|
|
3184
|
+
);
|
|
3185
|
+
})()
|
|
2860
3186
|
] });
|
|
2861
3187
|
}
|
|
2862
3188
|
// Annotate the CommonJS export names for ESM import in node:
|