@lensui/lens-table 0.1.76 → 0.1.78
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/index.cjs +120 -154
- package/dist/index.css +7 -0
- package/dist/index.js +120 -154
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -332,10 +332,25 @@ function LoadingSpinnerIcon() {
|
|
|
332
332
|
|
|
333
333
|
// src/components/editors/ChoiceEditor.tsx
|
|
334
334
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
335
|
+
var SEARCHABLE_CHOICE_POPUP_MAX_WIDTH = 360;
|
|
336
|
+
var SEARCHABLE_CHOICE_POPUP_HORIZONTAL_PADDING = 44;
|
|
337
|
+
var SEARCHABLE_CHOICE_POPUP_VIEWPORT_GAP = 8;
|
|
338
|
+
function getSearchableChoicePopupHorizontalLayout(anchorLeft, anchorWidth, longestLabelWidth, viewportWidth) {
|
|
339
|
+
const availableWidth = Math.max(0, viewportWidth - SEARCHABLE_CHOICE_POPUP_VIEWPORT_GAP * 2);
|
|
340
|
+
const desiredWidth = Math.max(anchorWidth, longestLabelWidth + SEARCHABLE_CHOICE_POPUP_HORIZONTAL_PADDING);
|
|
341
|
+
const width = Math.min(desiredWidth, SEARCHABLE_CHOICE_POPUP_MAX_WIDTH, availableWidth);
|
|
342
|
+
const left = Math.max(
|
|
343
|
+
SEARCHABLE_CHOICE_POPUP_VIEWPORT_GAP,
|
|
344
|
+
Math.min(anchorLeft, viewportWidth - SEARCHABLE_CHOICE_POPUP_VIEWPORT_GAP - width)
|
|
345
|
+
);
|
|
346
|
+
return { left, width };
|
|
347
|
+
}
|
|
335
348
|
function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownHeight, style, labels, onChange, onCommit, onCancel }) {
|
|
336
349
|
const editorRef = (0, import_react2.useRef)(null);
|
|
337
350
|
const popupRef = (0, import_react2.useRef)(null);
|
|
338
351
|
const activeOptionRef = (0, import_react2.useRef)(null);
|
|
352
|
+
const popupReadyRef = (0, import_react2.useRef)(false);
|
|
353
|
+
const navigationSourceRef = (0, import_react2.useRef)(null);
|
|
339
354
|
const originalValueRef = (0, import_react2.useRef)(value);
|
|
340
355
|
const listboxId = (0, import_react2.useId)();
|
|
341
356
|
const originalValue = originalValueRef.current;
|
|
@@ -344,7 +359,10 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
|
|
|
344
359
|
const selectedIndex = options.findIndex((option) => option.value === value);
|
|
345
360
|
return selectedIndex >= 0 ? selectedIndex : 0;
|
|
346
361
|
});
|
|
347
|
-
const [popupStyle, setPopupStyle] = (0, import_react2.useState)({
|
|
362
|
+
const [popupStyle, setPopupStyle] = (0, import_react2.useState)({
|
|
363
|
+
position: "fixed",
|
|
364
|
+
visibility: "hidden"
|
|
365
|
+
});
|
|
348
366
|
const filteredOptions = (0, import_react2.useMemo)(() => {
|
|
349
367
|
const query = inputValue.trim().toLocaleLowerCase();
|
|
350
368
|
if (!query || query === originalValue.toLocaleLowerCase()) return options;
|
|
@@ -354,24 +372,36 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
|
|
|
354
372
|
const positionPopup = () => {
|
|
355
373
|
const rect = editorRef.current?.getBoundingClientRect();
|
|
356
374
|
if (!rect) return;
|
|
375
|
+
const longestLabelWidth = Math.max(
|
|
376
|
+
0,
|
|
377
|
+
...Array.from(popupRef.current?.querySelectorAll(".rvg-choice-item > span") ?? []).map((label) => label.scrollWidth)
|
|
378
|
+
);
|
|
379
|
+
const horizontal = getSearchableChoicePopupHorizontalLayout(
|
|
380
|
+
rect.left,
|
|
381
|
+
rect.width,
|
|
382
|
+
longestLabelWidth,
|
|
383
|
+
window.innerWidth
|
|
384
|
+
);
|
|
357
385
|
const availableBelow = window.innerHeight - rect.bottom - 8;
|
|
358
386
|
const availableAbove = rect.top - 8;
|
|
359
387
|
if (availableBelow < 120 && availableAbove > availableBelow) {
|
|
360
388
|
setPopupStyle({
|
|
361
389
|
position: "fixed",
|
|
362
390
|
bottom: window.innerHeight - rect.top + 4,
|
|
363
|
-
left:
|
|
364
|
-
width:
|
|
365
|
-
maxHeight: Math.min(maxDropdownHeight, availableAbove)
|
|
391
|
+
left: horizontal.left,
|
|
392
|
+
width: horizontal.width,
|
|
393
|
+
maxHeight: Math.min(maxDropdownHeight, availableAbove),
|
|
394
|
+
visibility: popupReadyRef.current ? "visible" : "hidden"
|
|
366
395
|
});
|
|
367
396
|
return;
|
|
368
397
|
}
|
|
369
398
|
setPopupStyle({
|
|
370
399
|
position: "fixed",
|
|
371
400
|
top: rect.bottom + 4,
|
|
372
|
-
left:
|
|
373
|
-
width:
|
|
374
|
-
maxHeight: Math.min(maxDropdownHeight, Math.max(80, availableBelow))
|
|
401
|
+
left: horizontal.left,
|
|
402
|
+
width: horizontal.width,
|
|
403
|
+
maxHeight: Math.min(maxDropdownHeight, Math.max(80, availableBelow)),
|
|
404
|
+
visibility: popupReadyRef.current ? "visible" : "hidden"
|
|
375
405
|
});
|
|
376
406
|
};
|
|
377
407
|
positionPopup();
|
|
@@ -383,8 +413,22 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
|
|
|
383
413
|
};
|
|
384
414
|
}, [maxDropdownHeight]);
|
|
385
415
|
(0, import_react2.useLayoutEffect)(() => {
|
|
386
|
-
|
|
387
|
-
|
|
416
|
+
if (popupReadyRef.current) return;
|
|
417
|
+
if (popupStyle.top === void 0 && popupStyle.bottom === void 0) return;
|
|
418
|
+
const selectedOption = popupRef.current?.querySelector('[aria-selected="true"]') ?? activeOptionRef.current;
|
|
419
|
+
selectedOption?.scrollIntoView?.({ block: "center", inline: "nearest" });
|
|
420
|
+
popupReadyRef.current = true;
|
|
421
|
+
setPopupStyle((current) => ({ ...current, visibility: "visible" }));
|
|
422
|
+
}, [popupStyle.bottom, popupStyle.top]);
|
|
423
|
+
(0, import_react2.useLayoutEffect)(() => {
|
|
424
|
+
if (!popupReadyRef.current) return;
|
|
425
|
+
if (navigationSourceRef.current === "keyboard") {
|
|
426
|
+
activeOptionRef.current?.scrollIntoView?.({ block: "nearest", inline: "nearest" });
|
|
427
|
+
} else if (navigationSourceRef.current === "filter" && popupRef.current) {
|
|
428
|
+
popupRef.current.scrollTop = 0;
|
|
429
|
+
}
|
|
430
|
+
navigationSourceRef.current = null;
|
|
431
|
+
}, [activeIndex, filteredOptions]);
|
|
388
432
|
(0, import_react2.useEffect)(() => {
|
|
389
433
|
const handleOutsidePointer = (event) => {
|
|
390
434
|
const target = event.target;
|
|
@@ -404,10 +448,12 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
|
|
|
404
448
|
if (event.key === "Escape") onCancel();
|
|
405
449
|
if (event.key === "ArrowDown") {
|
|
406
450
|
event.preventDefault();
|
|
451
|
+
navigationSourceRef.current = "keyboard";
|
|
407
452
|
setActiveIndex((index) => Math.min(filteredOptions.length - 1, index + 1));
|
|
408
453
|
}
|
|
409
454
|
if (event.key === "ArrowUp") {
|
|
410
455
|
event.preventDefault();
|
|
456
|
+
navigationSourceRef.current = "keyboard";
|
|
411
457
|
setActiveIndex((index) => Math.max(0, index - 1));
|
|
412
458
|
}
|
|
413
459
|
if (event.key === "Enter") {
|
|
@@ -430,6 +476,7 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
|
|
|
430
476
|
onChange: (event) => {
|
|
431
477
|
setInputValue(event.target.value);
|
|
432
478
|
onChange(event.target.value);
|
|
479
|
+
navigationSourceRef.current = "filter";
|
|
433
480
|
setActiveIndex(0);
|
|
434
481
|
},
|
|
435
482
|
onKeyDown: handleKeyDown
|
|
@@ -445,7 +492,10 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
|
|
|
445
492
|
"aria-selected": option.value === originalValue,
|
|
446
493
|
className: `rvg-choice-item${index === activeIndex ? " is-active" : ""}${option.value === originalValue ? " is-selected" : ""}`,
|
|
447
494
|
onPointerDown: (event) => event.preventDefault(),
|
|
448
|
-
onMouseEnter: () =>
|
|
495
|
+
onMouseEnter: () => {
|
|
496
|
+
navigationSourceRef.current = "pointer";
|
|
497
|
+
setActiveIndex(index);
|
|
498
|
+
},
|
|
449
499
|
onClick: () => selectOption(option),
|
|
450
500
|
children: [
|
|
451
501
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: option.label }),
|
|
@@ -941,25 +991,6 @@ function TextAreaEditor({ value, title, maxLength, style, labels, onChange, onCo
|
|
|
941
991
|
] });
|
|
942
992
|
}
|
|
943
993
|
|
|
944
|
-
// src/icons/domIcons.ts
|
|
945
|
-
function createRowDragHandleSvg() {
|
|
946
|
-
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
947
|
-
svg.setAttribute("viewBox", "0 0 16 16");
|
|
948
|
-
for (const [cx, cy] of [[5, 4], [11, 4], [5, 8], [11, 8], [5, 12], [11, 12]]) {
|
|
949
|
-
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
950
|
-
circle.setAttribute("cx", String(cx));
|
|
951
|
-
circle.setAttribute("cy", String(cy));
|
|
952
|
-
circle.setAttribute("r", "1");
|
|
953
|
-
svg.appendChild(circle);
|
|
954
|
-
}
|
|
955
|
-
return svg;
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
// src/Table.tsx
|
|
959
|
-
var import_adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
|
|
960
|
-
var import_set_custom_native_drag_preview = require("@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview");
|
|
961
|
-
var import_closest_edge = require("@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge");
|
|
962
|
-
|
|
963
994
|
// src/core/format.ts
|
|
964
995
|
function getDisplayLabel(column, row, rowIndex) {
|
|
965
996
|
const value = column.dataIndex === void 0 ? void 0 : row[column.dataIndex];
|
|
@@ -2041,6 +2072,7 @@ function TableInner({
|
|
|
2041
2072
|
const columnDragRef = (0, import_react8.useRef)(null);
|
|
2042
2073
|
const columnOrderDragRef = (0, import_react8.useRef)(null);
|
|
2043
2074
|
const columnOrderLongPressTimerRef = (0, import_react8.useRef)(null);
|
|
2075
|
+
const rowOrderDragRef = (0, import_react8.useRef)(null);
|
|
2044
2076
|
const dragGuideRef = (0, import_react8.useRef)(null);
|
|
2045
2077
|
const rowDragGuideRef = (0, import_react8.useRef)(null);
|
|
2046
2078
|
const selectionFocusRef = (0, import_react8.useRef)(null);
|
|
@@ -3341,131 +3373,61 @@ function TableInner({
|
|
|
3341
3373
|
const rowIndex = Math.floor((localY - bodyTop + scrollRef.current.top) / rowHeight);
|
|
3342
3374
|
return rowIndex >= 0 && rowIndex < rows.length ? rowIndex : -1;
|
|
3343
3375
|
}, [bodyTop, rowHeight, rows.length]);
|
|
3344
|
-
(0, import_react8.
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
const
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
const canvasRect = canvas.getBoundingClientRect();
|
|
3357
|
-
const input = location.current.input;
|
|
3358
|
-
const previewOffset = {
|
|
3359
|
-
x: Math.max(0, Math.min(canvasRect.width, input.clientX - canvasRect.left)) + 2,
|
|
3360
|
-
y: Math.max(0, Math.min(rowHeight, input.clientY - canvasRect.top - bodyTop - sourceIndex * rowHeight + scrollRef.current.top)) + 2
|
|
3361
|
-
};
|
|
3362
|
-
(0, import_set_custom_native_drag_preview.setCustomNativeDragPreview)({
|
|
3363
|
-
nativeSetDragImage,
|
|
3364
|
-
getOffset: () => previewOffset,
|
|
3365
|
-
render: ({ container }) => {
|
|
3366
|
-
const frame = document.createElement("div");
|
|
3367
|
-
frame.className = "rvg-row-drag-preview-frame";
|
|
3368
|
-
frame.style.width = `${canvasRect.width + 4}px`;
|
|
3369
|
-
frame.style.height = `${rowHeight + 4}px`;
|
|
3370
|
-
const preview = document.createElement("div");
|
|
3371
|
-
preview.className = "rvg-row-drag-preview";
|
|
3372
|
-
preview.style.width = `${canvasRect.width}px`;
|
|
3373
|
-
preview.style.height = `${rowHeight}px`;
|
|
3374
|
-
const row = rows[sourceIndex];
|
|
3375
|
-
const rowKey2 = getRowKey(row, sourceIndex);
|
|
3376
|
-
columns.forEach((column, columnIndex) => {
|
|
3377
|
-
const left = getDisplayedColumnLeft(columnIndex);
|
|
3378
|
-
const columnWidth = metrics[columnIndex].width;
|
|
3379
|
-
if (left + columnWidth <= 0 || left >= canvasRect.width) return;
|
|
3380
|
-
const cell = document.createElement("div");
|
|
3381
|
-
cell.className = "rvg-row-drag-preview-cell";
|
|
3382
|
-
cell.style.left = `${left}px`;
|
|
3383
|
-
cell.style.width = `${columnWidth}px`;
|
|
3384
|
-
cell.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
|
|
3385
|
-
if (column.rowDragHandle && !column.rowSelection) {
|
|
3386
|
-
cell.appendChild(createRowDragHandleSvg());
|
|
3387
|
-
} else if (column.rowSelection) {
|
|
3388
|
-
if (column.rowSelectionIndicator !== "none") {
|
|
3389
|
-
const checkbox = document.createElement("span");
|
|
3390
|
-
checkbox.className = selectedRowKeySet.has(rowKey2) ? "rvg-preview-checkbox is-checked" : "rvg-preview-checkbox";
|
|
3391
|
-
checkbox.textContent = selectedRowKeySet.has(rowKey2) ? "\u2713" : "";
|
|
3392
|
-
cell.appendChild(checkbox);
|
|
3393
|
-
}
|
|
3394
|
-
} else {
|
|
3395
|
-
cell.textContent = getCellLabel(sourceIndex, columnIndex);
|
|
3396
|
-
}
|
|
3397
|
-
if (selection?.rowKey === rowKey2 && selection.columnKey === column.key) cell.classList.add("is-selected");
|
|
3398
|
-
preview.appendChild(cell);
|
|
3399
|
-
});
|
|
3400
|
-
frame.appendChild(preview);
|
|
3401
|
-
container.appendChild(frame);
|
|
3402
|
-
return () => frame.remove();
|
|
3403
|
-
}
|
|
3404
|
-
});
|
|
3405
|
-
},
|
|
3406
|
-
onDragStart: ({ source }) => {
|
|
3407
|
-
const sourceIndex = Number(source.data.sourceIndex);
|
|
3408
|
-
suppressClickRef.current = true;
|
|
3409
|
-
hideDragTooltips();
|
|
3410
|
-
document.documentElement.classList.add("rvg-is-dragging");
|
|
3411
|
-
canvas.style.cursor = "move";
|
|
3412
|
-
setRowDragPreview({ sourceIndex, targetIndex: sourceIndex });
|
|
3413
|
-
},
|
|
3414
|
-
onDrag: ({ source, location }) => {
|
|
3415
|
-
const target = location.current.dropTargets[0]?.data;
|
|
3416
|
-
const sourceIndex = Number(source.data.sourceIndex);
|
|
3417
|
-
const rawTargetIndex = Number(target?.targetIndex);
|
|
3418
|
-
if (!Number.isInteger(rawTargetIndex)) {
|
|
3419
|
-
setRowDragPreview(null);
|
|
3420
|
-
setRowDragGuide(null);
|
|
3421
|
-
return;
|
|
3422
|
-
}
|
|
3423
|
-
const edge = target?.rowEdge;
|
|
3424
|
-
let targetIndex = rawTargetIndex + (edge === "bottom" ? 1 : 0);
|
|
3425
|
-
if (sourceIndex < targetIndex) targetIndex -= 1;
|
|
3426
|
-
targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
|
|
3427
|
-
setRowDragPreview((current) => current?.sourceIndex === sourceIndex && current.targetIndex === targetIndex ? current : { sourceIndex, targetIndex });
|
|
3428
|
-
setRowDragGuide(bodyTop + rawTargetIndex * rowHeight - scrollRef.current.top + (edge === "bottom" ? rowHeight : 0));
|
|
3429
|
-
},
|
|
3430
|
-
onDrop: ({ source, location }) => {
|
|
3431
|
-
const target = location.current.dropTargets[0]?.data;
|
|
3432
|
-
const sourceIndex = Number(source.data.sourceIndex);
|
|
3433
|
-
const rawTargetIndex = Number(target?.targetIndex);
|
|
3434
|
-
let targetIndex = rawTargetIndex + (target?.rowEdge === "bottom" ? 1 : 0);
|
|
3435
|
-
if (sourceIndex < targetIndex) targetIndex -= 1;
|
|
3436
|
-
targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
|
|
3437
|
-
scrollerRef.current?.classList.add("rvg-row-drop-settling");
|
|
3438
|
-
setRowDragPreview(null);
|
|
3439
|
-
setRowDragGuide(null);
|
|
3440
|
-
document.documentElement.classList.remove("rvg-is-dragging");
|
|
3441
|
-
canvas.style.cursor = "default";
|
|
3442
|
-
if (Number.isInteger(rawTargetIndex) && sourceIndex !== targetIndex) applyRowOrder(sourceIndex, targetIndex);
|
|
3443
|
-
requestAnimationFrame(() => {
|
|
3444
|
-
requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
|
|
3445
|
-
});
|
|
3446
|
-
window.setTimeout(() => {
|
|
3447
|
-
suppressClickRef.current = false;
|
|
3448
|
-
}, 0);
|
|
3449
|
-
}
|
|
3450
|
-
});
|
|
3451
|
-
const cleanupDrop = (0, import_adapter.dropTargetForElements)({
|
|
3452
|
-
element: canvas,
|
|
3453
|
-
canDrop: ({ source }) => source.data.type === "table-row",
|
|
3454
|
-
getDropEffect: () => "move",
|
|
3455
|
-
getData: ({ input, element }) => {
|
|
3456
|
-
const targetIndex = locateRow(input.clientY);
|
|
3457
|
-
if (targetIndex < 0) return { targetIndex: -1 };
|
|
3458
|
-
const rowTop = bodyTop + targetIndex * rowHeight - scrollRef.current.top;
|
|
3459
|
-
const rowEdge = input.clientY - canvas.getBoundingClientRect().top < rowTop + rowHeight / 2 ? "top" : "bottom";
|
|
3460
|
-
return (0, import_closest_edge.attachClosestEdge)({ targetIndex, rowEdge }, { element, input, allowedEdges: ["top", "bottom"] });
|
|
3461
|
-
}
|
|
3462
|
-
});
|
|
3463
|
-
return () => {
|
|
3464
|
-
document.documentElement.classList.remove("rvg-is-dragging");
|
|
3465
|
-
cleanupDrag();
|
|
3466
|
-
cleanupDrop();
|
|
3376
|
+
const handleRowOrderPointerDown = (0, import_react8.useCallback)((event) => {
|
|
3377
|
+
if (!rowDraggable || event.button !== 0 || rowOrderDragRef.current) return;
|
|
3378
|
+
const columnIndex = locateColumn(event.clientX);
|
|
3379
|
+
const sourceIndex = locateRow(event.clientY);
|
|
3380
|
+
if (columnIndex < 0 || sourceIndex < 0 || !columns[columnIndex].rowDragHandle) return;
|
|
3381
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
3382
|
+
rowOrderDragRef.current = {
|
|
3383
|
+
pointerId: event.pointerId,
|
|
3384
|
+
startY: event.clientY,
|
|
3385
|
+
active: false,
|
|
3386
|
+
sourceIndex,
|
|
3387
|
+
targetIndex: sourceIndex
|
|
3467
3388
|
};
|
|
3468
|
-
}, [
|
|
3389
|
+
}, [columns, locateColumn, locateRow, rowDraggable]);
|
|
3390
|
+
const handleRowOrderPointerMove = (0, import_react8.useCallback)((event) => {
|
|
3391
|
+
const drag = rowOrderDragRef.current;
|
|
3392
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
3393
|
+
if (!drag.active) {
|
|
3394
|
+
if (Math.abs(event.clientY - drag.startY) < 4) return;
|
|
3395
|
+
drag.active = true;
|
|
3396
|
+
suppressClickRef.current = true;
|
|
3397
|
+
hideDragTooltips();
|
|
3398
|
+
document.documentElement.classList.add("rvg-is-dragging");
|
|
3399
|
+
event.currentTarget.style.cursor = "move";
|
|
3400
|
+
}
|
|
3401
|
+
event.preventDefault();
|
|
3402
|
+
const rawTargetIndex = locateRow(event.clientY);
|
|
3403
|
+
if (rawTargetIndex < 0) return;
|
|
3404
|
+
const canvasTop = event.currentTarget.getBoundingClientRect().top;
|
|
3405
|
+
const rowTop = bodyTop + rawTargetIndex * rowHeight - scrollRef.current.top;
|
|
3406
|
+
const edge = event.clientY - canvasTop < rowTop + rowHeight / 2 ? "top" : "bottom";
|
|
3407
|
+
let targetIndex = rawTargetIndex + (edge === "bottom" ? 1 : 0);
|
|
3408
|
+
if (drag.sourceIndex < targetIndex) targetIndex -= 1;
|
|
3409
|
+
targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
|
|
3410
|
+
drag.targetIndex = targetIndex;
|
|
3411
|
+
setRowDragPreview((current) => current?.sourceIndex === drag.sourceIndex && current.targetIndex === targetIndex ? current : { sourceIndex: drag.sourceIndex, targetIndex });
|
|
3412
|
+
setRowDragGuide(rowTop + (edge === "bottom" ? rowHeight : 0));
|
|
3413
|
+
}, [bodyTop, hideDragTooltips, locateRow, rowHeight, rows.length, setRowDragGuide]);
|
|
3414
|
+
const finishRowOrderPointerDrag = (0, import_react8.useCallback)((event, apply) => {
|
|
3415
|
+
const drag = rowOrderDragRef.current;
|
|
3416
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
3417
|
+
if (event.currentTarget.hasPointerCapture?.(event.pointerId)) event.currentTarget.releasePointerCapture?.(event.pointerId);
|
|
3418
|
+
rowOrderDragRef.current = null;
|
|
3419
|
+
setRowDragPreview(null);
|
|
3420
|
+
setRowDragGuide(null);
|
|
3421
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
3422
|
+
event.currentTarget.style.cursor = "default";
|
|
3423
|
+
if (apply && drag.active && drag.sourceIndex !== drag.targetIndex) {
|
|
3424
|
+
scrollerRef.current?.classList.add("rvg-row-drop-settling");
|
|
3425
|
+
applyRowOrder(drag.sourceIndex, drag.targetIndex);
|
|
3426
|
+
requestAnimationFrame(() => {
|
|
3427
|
+
requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
|
|
3428
|
+
});
|
|
3429
|
+
}
|
|
3430
|
+
}, [applyRowOrder, setRowDragGuide]);
|
|
3469
3431
|
const locateCell = (0, import_react8.useCallback)((clientX, clientY) => {
|
|
3470
3432
|
const canvas = canvasRef.current;
|
|
3471
3433
|
if (!canvas) return null;
|
|
@@ -5058,7 +5020,7 @@ function TableInner({
|
|
|
5058
5020
|
}
|
|
5059
5021
|
}
|
|
5060
5022
|
}
|
|
5061
|
-
const cursor = inHeader && locateHeaderResizeCell(event.clientX, event.clientY) ? "col-resize" : hoveredAction ? "pointer" : hoveredDragHandle ? "move" : columnIndex >= 0 && columns[columnIndex].
|
|
5023
|
+
const cursor = inHeader && locateHeaderResizeCell(event.clientX, event.clientY) ? "col-resize" : hoveredAction ? "pointer" : hoveredDragHandle ? "move" : !inHeader && rowDraggable && columnIndex >= 0 && columns[columnIndex].rowDragHandle ? "move" : columnIndex >= 0 && columns[columnIndex].rowSelection ? "pointer" : "default";
|
|
5062
5024
|
if (event.currentTarget.style.cursor !== cursor) event.currentTarget.style.cursor = cursor;
|
|
5063
5025
|
},
|
|
5064
5026
|
onMouseLeave: (event) => {
|
|
@@ -5077,6 +5039,7 @@ function TableInner({
|
|
|
5077
5039
|
}
|
|
5078
5040
|
},
|
|
5079
5041
|
onPointerDown: (event) => {
|
|
5042
|
+
handleRowOrderPointerDown(event);
|
|
5080
5043
|
handleColumnPointerDown(event);
|
|
5081
5044
|
if (columnDragRef.current) return;
|
|
5082
5045
|
const headerDragCell = columnDraggable ? locateHeaderCell(event.clientX, event.clientY) : null;
|
|
@@ -5089,16 +5052,19 @@ function TableInner({
|
|
|
5089
5052
|
beginRangeDrag(event);
|
|
5090
5053
|
},
|
|
5091
5054
|
onPointerMove: (event) => {
|
|
5055
|
+
handleRowOrderPointerMove(event);
|
|
5092
5056
|
handleColumnPointerMove(event);
|
|
5093
5057
|
handleColumnOrderPointerMove(event);
|
|
5094
5058
|
updateRangeDrag(event);
|
|
5095
5059
|
},
|
|
5096
5060
|
onPointerUp: (event) => {
|
|
5061
|
+
finishRowOrderPointerDrag(event, true);
|
|
5097
5062
|
handleColumnPointerUp(event);
|
|
5098
5063
|
finishColumnOrderPointerDrag(event, true);
|
|
5099
5064
|
endRangeDrag(event);
|
|
5100
5065
|
},
|
|
5101
5066
|
onPointerCancel: (event) => {
|
|
5067
|
+
finishRowOrderPointerDrag(event, false);
|
|
5102
5068
|
handleColumnPointerUp(event);
|
|
5103
5069
|
finishColumnOrderPointerDrag(event, false);
|
|
5104
5070
|
endRangeDrag(event);
|
package/dist/index.css
CHANGED
|
@@ -2704,10 +2704,17 @@
|
|
|
2704
2704
|
}
|
|
2705
2705
|
.rvg-searchable-choice-content .rvg-choice-item {
|
|
2706
2706
|
width: 100%;
|
|
2707
|
+
min-width: 0;
|
|
2707
2708
|
border: 0;
|
|
2708
2709
|
background: transparent;
|
|
2709
2710
|
text-align: left;
|
|
2710
2711
|
}
|
|
2712
|
+
.rvg-searchable-choice-content .rvg-choice-item > span {
|
|
2713
|
+
min-width: 0;
|
|
2714
|
+
overflow: hidden;
|
|
2715
|
+
white-space: nowrap;
|
|
2716
|
+
text-overflow: ellipsis;
|
|
2717
|
+
}
|
|
2711
2718
|
.rvg-searchable-choice-content .rvg-choice-item:is(:hover, .is-active) {
|
|
2712
2719
|
background: var(--rvg-color-hover);
|
|
2713
2720
|
}
|
package/dist/index.js
CHANGED
|
@@ -302,10 +302,25 @@ function LoadingSpinnerIcon() {
|
|
|
302
302
|
|
|
303
303
|
// src/components/editors/ChoiceEditor.tsx
|
|
304
304
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
305
|
+
var SEARCHABLE_CHOICE_POPUP_MAX_WIDTH = 360;
|
|
306
|
+
var SEARCHABLE_CHOICE_POPUP_HORIZONTAL_PADDING = 44;
|
|
307
|
+
var SEARCHABLE_CHOICE_POPUP_VIEWPORT_GAP = 8;
|
|
308
|
+
function getSearchableChoicePopupHorizontalLayout(anchorLeft, anchorWidth, longestLabelWidth, viewportWidth) {
|
|
309
|
+
const availableWidth = Math.max(0, viewportWidth - SEARCHABLE_CHOICE_POPUP_VIEWPORT_GAP * 2);
|
|
310
|
+
const desiredWidth = Math.max(anchorWidth, longestLabelWidth + SEARCHABLE_CHOICE_POPUP_HORIZONTAL_PADDING);
|
|
311
|
+
const width = Math.min(desiredWidth, SEARCHABLE_CHOICE_POPUP_MAX_WIDTH, availableWidth);
|
|
312
|
+
const left = Math.max(
|
|
313
|
+
SEARCHABLE_CHOICE_POPUP_VIEWPORT_GAP,
|
|
314
|
+
Math.min(anchorLeft, viewportWidth - SEARCHABLE_CHOICE_POPUP_VIEWPORT_GAP - width)
|
|
315
|
+
);
|
|
316
|
+
return { left, width };
|
|
317
|
+
}
|
|
305
318
|
function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownHeight, style, labels, onChange, onCommit, onCancel }) {
|
|
306
319
|
const editorRef = useRef(null);
|
|
307
320
|
const popupRef = useRef(null);
|
|
308
321
|
const activeOptionRef = useRef(null);
|
|
322
|
+
const popupReadyRef = useRef(false);
|
|
323
|
+
const navigationSourceRef = useRef(null);
|
|
309
324
|
const originalValueRef = useRef(value);
|
|
310
325
|
const listboxId = useId2();
|
|
311
326
|
const originalValue = originalValueRef.current;
|
|
@@ -314,7 +329,10 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
|
|
|
314
329
|
const selectedIndex = options.findIndex((option) => option.value === value);
|
|
315
330
|
return selectedIndex >= 0 ? selectedIndex : 0;
|
|
316
331
|
});
|
|
317
|
-
const [popupStyle, setPopupStyle] = useState({
|
|
332
|
+
const [popupStyle, setPopupStyle] = useState({
|
|
333
|
+
position: "fixed",
|
|
334
|
+
visibility: "hidden"
|
|
335
|
+
});
|
|
318
336
|
const filteredOptions = useMemo(() => {
|
|
319
337
|
const query = inputValue.trim().toLocaleLowerCase();
|
|
320
338
|
if (!query || query === originalValue.toLocaleLowerCase()) return options;
|
|
@@ -324,24 +342,36 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
|
|
|
324
342
|
const positionPopup = () => {
|
|
325
343
|
const rect = editorRef.current?.getBoundingClientRect();
|
|
326
344
|
if (!rect) return;
|
|
345
|
+
const longestLabelWidth = Math.max(
|
|
346
|
+
0,
|
|
347
|
+
...Array.from(popupRef.current?.querySelectorAll(".rvg-choice-item > span") ?? []).map((label) => label.scrollWidth)
|
|
348
|
+
);
|
|
349
|
+
const horizontal = getSearchableChoicePopupHorizontalLayout(
|
|
350
|
+
rect.left,
|
|
351
|
+
rect.width,
|
|
352
|
+
longestLabelWidth,
|
|
353
|
+
window.innerWidth
|
|
354
|
+
);
|
|
327
355
|
const availableBelow = window.innerHeight - rect.bottom - 8;
|
|
328
356
|
const availableAbove = rect.top - 8;
|
|
329
357
|
if (availableBelow < 120 && availableAbove > availableBelow) {
|
|
330
358
|
setPopupStyle({
|
|
331
359
|
position: "fixed",
|
|
332
360
|
bottom: window.innerHeight - rect.top + 4,
|
|
333
|
-
left:
|
|
334
|
-
width:
|
|
335
|
-
maxHeight: Math.min(maxDropdownHeight, availableAbove)
|
|
361
|
+
left: horizontal.left,
|
|
362
|
+
width: horizontal.width,
|
|
363
|
+
maxHeight: Math.min(maxDropdownHeight, availableAbove),
|
|
364
|
+
visibility: popupReadyRef.current ? "visible" : "hidden"
|
|
336
365
|
});
|
|
337
366
|
return;
|
|
338
367
|
}
|
|
339
368
|
setPopupStyle({
|
|
340
369
|
position: "fixed",
|
|
341
370
|
top: rect.bottom + 4,
|
|
342
|
-
left:
|
|
343
|
-
width:
|
|
344
|
-
maxHeight: Math.min(maxDropdownHeight, Math.max(80, availableBelow))
|
|
371
|
+
left: horizontal.left,
|
|
372
|
+
width: horizontal.width,
|
|
373
|
+
maxHeight: Math.min(maxDropdownHeight, Math.max(80, availableBelow)),
|
|
374
|
+
visibility: popupReadyRef.current ? "visible" : "hidden"
|
|
345
375
|
});
|
|
346
376
|
};
|
|
347
377
|
positionPopup();
|
|
@@ -353,8 +383,22 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
|
|
|
353
383
|
};
|
|
354
384
|
}, [maxDropdownHeight]);
|
|
355
385
|
useLayoutEffect(() => {
|
|
356
|
-
|
|
357
|
-
|
|
386
|
+
if (popupReadyRef.current) return;
|
|
387
|
+
if (popupStyle.top === void 0 && popupStyle.bottom === void 0) return;
|
|
388
|
+
const selectedOption = popupRef.current?.querySelector('[aria-selected="true"]') ?? activeOptionRef.current;
|
|
389
|
+
selectedOption?.scrollIntoView?.({ block: "center", inline: "nearest" });
|
|
390
|
+
popupReadyRef.current = true;
|
|
391
|
+
setPopupStyle((current) => ({ ...current, visibility: "visible" }));
|
|
392
|
+
}, [popupStyle.bottom, popupStyle.top]);
|
|
393
|
+
useLayoutEffect(() => {
|
|
394
|
+
if (!popupReadyRef.current) return;
|
|
395
|
+
if (navigationSourceRef.current === "keyboard") {
|
|
396
|
+
activeOptionRef.current?.scrollIntoView?.({ block: "nearest", inline: "nearest" });
|
|
397
|
+
} else if (navigationSourceRef.current === "filter" && popupRef.current) {
|
|
398
|
+
popupRef.current.scrollTop = 0;
|
|
399
|
+
}
|
|
400
|
+
navigationSourceRef.current = null;
|
|
401
|
+
}, [activeIndex, filteredOptions]);
|
|
358
402
|
useEffect(() => {
|
|
359
403
|
const handleOutsidePointer = (event) => {
|
|
360
404
|
const target = event.target;
|
|
@@ -374,10 +418,12 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
|
|
|
374
418
|
if (event.key === "Escape") onCancel();
|
|
375
419
|
if (event.key === "ArrowDown") {
|
|
376
420
|
event.preventDefault();
|
|
421
|
+
navigationSourceRef.current = "keyboard";
|
|
377
422
|
setActiveIndex((index) => Math.min(filteredOptions.length - 1, index + 1));
|
|
378
423
|
}
|
|
379
424
|
if (event.key === "ArrowUp") {
|
|
380
425
|
event.preventDefault();
|
|
426
|
+
navigationSourceRef.current = "keyboard";
|
|
381
427
|
setActiveIndex((index) => Math.max(0, index - 1));
|
|
382
428
|
}
|
|
383
429
|
if (event.key === "Enter") {
|
|
@@ -400,6 +446,7 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
|
|
|
400
446
|
onChange: (event) => {
|
|
401
447
|
setInputValue(event.target.value);
|
|
402
448
|
onChange(event.target.value);
|
|
449
|
+
navigationSourceRef.current = "filter";
|
|
403
450
|
setActiveIndex(0);
|
|
404
451
|
},
|
|
405
452
|
onKeyDown: handleKeyDown
|
|
@@ -415,7 +462,10 @@ function SearchableChoiceEditor({ value, options, allowCustomValue, maxDropdownH
|
|
|
415
462
|
"aria-selected": option.value === originalValue,
|
|
416
463
|
className: `rvg-choice-item${index === activeIndex ? " is-active" : ""}${option.value === originalValue ? " is-selected" : ""}`,
|
|
417
464
|
onPointerDown: (event) => event.preventDefault(),
|
|
418
|
-
onMouseEnter: () =>
|
|
465
|
+
onMouseEnter: () => {
|
|
466
|
+
navigationSourceRef.current = "pointer";
|
|
467
|
+
setActiveIndex(index);
|
|
468
|
+
},
|
|
419
469
|
onClick: () => selectOption(option),
|
|
420
470
|
children: [
|
|
421
471
|
/* @__PURE__ */ jsx3("span", { children: option.label }),
|
|
@@ -911,25 +961,6 @@ function TextAreaEditor({ value, title, maxLength, style, labels, onChange, onCo
|
|
|
911
961
|
] });
|
|
912
962
|
}
|
|
913
963
|
|
|
914
|
-
// src/icons/domIcons.ts
|
|
915
|
-
function createRowDragHandleSvg() {
|
|
916
|
-
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
917
|
-
svg.setAttribute("viewBox", "0 0 16 16");
|
|
918
|
-
for (const [cx, cy] of [[5, 4], [11, 4], [5, 8], [11, 8], [5, 12], [11, 12]]) {
|
|
919
|
-
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
920
|
-
circle.setAttribute("cx", String(cx));
|
|
921
|
-
circle.setAttribute("cy", String(cy));
|
|
922
|
-
circle.setAttribute("r", "1");
|
|
923
|
-
svg.appendChild(circle);
|
|
924
|
-
}
|
|
925
|
-
return svg;
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
// src/Table.tsx
|
|
929
|
-
import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
|
930
|
-
import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview";
|
|
931
|
-
import { attachClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
|
|
932
|
-
|
|
933
964
|
// src/core/format.ts
|
|
934
965
|
function getDisplayLabel(column, row, rowIndex) {
|
|
935
966
|
const value = column.dataIndex === void 0 ? void 0 : row[column.dataIndex];
|
|
@@ -2011,6 +2042,7 @@ function TableInner({
|
|
|
2011
2042
|
const columnDragRef = useRef4(null);
|
|
2012
2043
|
const columnOrderDragRef = useRef4(null);
|
|
2013
2044
|
const columnOrderLongPressTimerRef = useRef4(null);
|
|
2045
|
+
const rowOrderDragRef = useRef4(null);
|
|
2014
2046
|
const dragGuideRef = useRef4(null);
|
|
2015
2047
|
const rowDragGuideRef = useRef4(null);
|
|
2016
2048
|
const selectionFocusRef = useRef4(null);
|
|
@@ -3311,131 +3343,61 @@ function TableInner({
|
|
|
3311
3343
|
const rowIndex = Math.floor((localY - bodyTop + scrollRef.current.top) / rowHeight);
|
|
3312
3344
|
return rowIndex >= 0 && rowIndex < rows.length ? rowIndex : -1;
|
|
3313
3345
|
}, [bodyTop, rowHeight, rows.length]);
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
const
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
const canvasRect = canvas.getBoundingClientRect();
|
|
3327
|
-
const input = location.current.input;
|
|
3328
|
-
const previewOffset = {
|
|
3329
|
-
x: Math.max(0, Math.min(canvasRect.width, input.clientX - canvasRect.left)) + 2,
|
|
3330
|
-
y: Math.max(0, Math.min(rowHeight, input.clientY - canvasRect.top - bodyTop - sourceIndex * rowHeight + scrollRef.current.top)) + 2
|
|
3331
|
-
};
|
|
3332
|
-
setCustomNativeDragPreview({
|
|
3333
|
-
nativeSetDragImage,
|
|
3334
|
-
getOffset: () => previewOffset,
|
|
3335
|
-
render: ({ container }) => {
|
|
3336
|
-
const frame = document.createElement("div");
|
|
3337
|
-
frame.className = "rvg-row-drag-preview-frame";
|
|
3338
|
-
frame.style.width = `${canvasRect.width + 4}px`;
|
|
3339
|
-
frame.style.height = `${rowHeight + 4}px`;
|
|
3340
|
-
const preview = document.createElement("div");
|
|
3341
|
-
preview.className = "rvg-row-drag-preview";
|
|
3342
|
-
preview.style.width = `${canvasRect.width}px`;
|
|
3343
|
-
preview.style.height = `${rowHeight}px`;
|
|
3344
|
-
const row = rows[sourceIndex];
|
|
3345
|
-
const rowKey2 = getRowKey(row, sourceIndex);
|
|
3346
|
-
columns.forEach((column, columnIndex) => {
|
|
3347
|
-
const left = getDisplayedColumnLeft(columnIndex);
|
|
3348
|
-
const columnWidth = metrics[columnIndex].width;
|
|
3349
|
-
if (left + columnWidth <= 0 || left >= canvasRect.width) return;
|
|
3350
|
-
const cell = document.createElement("div");
|
|
3351
|
-
cell.className = "rvg-row-drag-preview-cell";
|
|
3352
|
-
cell.style.left = `${left}px`;
|
|
3353
|
-
cell.style.width = `${columnWidth}px`;
|
|
3354
|
-
cell.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
|
|
3355
|
-
if (column.rowDragHandle && !column.rowSelection) {
|
|
3356
|
-
cell.appendChild(createRowDragHandleSvg());
|
|
3357
|
-
} else if (column.rowSelection) {
|
|
3358
|
-
if (column.rowSelectionIndicator !== "none") {
|
|
3359
|
-
const checkbox = document.createElement("span");
|
|
3360
|
-
checkbox.className = selectedRowKeySet.has(rowKey2) ? "rvg-preview-checkbox is-checked" : "rvg-preview-checkbox";
|
|
3361
|
-
checkbox.textContent = selectedRowKeySet.has(rowKey2) ? "\u2713" : "";
|
|
3362
|
-
cell.appendChild(checkbox);
|
|
3363
|
-
}
|
|
3364
|
-
} else {
|
|
3365
|
-
cell.textContent = getCellLabel(sourceIndex, columnIndex);
|
|
3366
|
-
}
|
|
3367
|
-
if (selection?.rowKey === rowKey2 && selection.columnKey === column.key) cell.classList.add("is-selected");
|
|
3368
|
-
preview.appendChild(cell);
|
|
3369
|
-
});
|
|
3370
|
-
frame.appendChild(preview);
|
|
3371
|
-
container.appendChild(frame);
|
|
3372
|
-
return () => frame.remove();
|
|
3373
|
-
}
|
|
3374
|
-
});
|
|
3375
|
-
},
|
|
3376
|
-
onDragStart: ({ source }) => {
|
|
3377
|
-
const sourceIndex = Number(source.data.sourceIndex);
|
|
3378
|
-
suppressClickRef.current = true;
|
|
3379
|
-
hideDragTooltips();
|
|
3380
|
-
document.documentElement.classList.add("rvg-is-dragging");
|
|
3381
|
-
canvas.style.cursor = "move";
|
|
3382
|
-
setRowDragPreview({ sourceIndex, targetIndex: sourceIndex });
|
|
3383
|
-
},
|
|
3384
|
-
onDrag: ({ source, location }) => {
|
|
3385
|
-
const target = location.current.dropTargets[0]?.data;
|
|
3386
|
-
const sourceIndex = Number(source.data.sourceIndex);
|
|
3387
|
-
const rawTargetIndex = Number(target?.targetIndex);
|
|
3388
|
-
if (!Number.isInteger(rawTargetIndex)) {
|
|
3389
|
-
setRowDragPreview(null);
|
|
3390
|
-
setRowDragGuide(null);
|
|
3391
|
-
return;
|
|
3392
|
-
}
|
|
3393
|
-
const edge = target?.rowEdge;
|
|
3394
|
-
let targetIndex = rawTargetIndex + (edge === "bottom" ? 1 : 0);
|
|
3395
|
-
if (sourceIndex < targetIndex) targetIndex -= 1;
|
|
3396
|
-
targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
|
|
3397
|
-
setRowDragPreview((current) => current?.sourceIndex === sourceIndex && current.targetIndex === targetIndex ? current : { sourceIndex, targetIndex });
|
|
3398
|
-
setRowDragGuide(bodyTop + rawTargetIndex * rowHeight - scrollRef.current.top + (edge === "bottom" ? rowHeight : 0));
|
|
3399
|
-
},
|
|
3400
|
-
onDrop: ({ source, location }) => {
|
|
3401
|
-
const target = location.current.dropTargets[0]?.data;
|
|
3402
|
-
const sourceIndex = Number(source.data.sourceIndex);
|
|
3403
|
-
const rawTargetIndex = Number(target?.targetIndex);
|
|
3404
|
-
let targetIndex = rawTargetIndex + (target?.rowEdge === "bottom" ? 1 : 0);
|
|
3405
|
-
if (sourceIndex < targetIndex) targetIndex -= 1;
|
|
3406
|
-
targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
|
|
3407
|
-
scrollerRef.current?.classList.add("rvg-row-drop-settling");
|
|
3408
|
-
setRowDragPreview(null);
|
|
3409
|
-
setRowDragGuide(null);
|
|
3410
|
-
document.documentElement.classList.remove("rvg-is-dragging");
|
|
3411
|
-
canvas.style.cursor = "default";
|
|
3412
|
-
if (Number.isInteger(rawTargetIndex) && sourceIndex !== targetIndex) applyRowOrder(sourceIndex, targetIndex);
|
|
3413
|
-
requestAnimationFrame(() => {
|
|
3414
|
-
requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
|
|
3415
|
-
});
|
|
3416
|
-
window.setTimeout(() => {
|
|
3417
|
-
suppressClickRef.current = false;
|
|
3418
|
-
}, 0);
|
|
3419
|
-
}
|
|
3420
|
-
});
|
|
3421
|
-
const cleanupDrop = dropTargetForElements({
|
|
3422
|
-
element: canvas,
|
|
3423
|
-
canDrop: ({ source }) => source.data.type === "table-row",
|
|
3424
|
-
getDropEffect: () => "move",
|
|
3425
|
-
getData: ({ input, element }) => {
|
|
3426
|
-
const targetIndex = locateRow(input.clientY);
|
|
3427
|
-
if (targetIndex < 0) return { targetIndex: -1 };
|
|
3428
|
-
const rowTop = bodyTop + targetIndex * rowHeight - scrollRef.current.top;
|
|
3429
|
-
const rowEdge = input.clientY - canvas.getBoundingClientRect().top < rowTop + rowHeight / 2 ? "top" : "bottom";
|
|
3430
|
-
return attachClosestEdge({ targetIndex, rowEdge }, { element, input, allowedEdges: ["top", "bottom"] });
|
|
3431
|
-
}
|
|
3432
|
-
});
|
|
3433
|
-
return () => {
|
|
3434
|
-
document.documentElement.classList.remove("rvg-is-dragging");
|
|
3435
|
-
cleanupDrag();
|
|
3436
|
-
cleanupDrop();
|
|
3346
|
+
const handleRowOrderPointerDown = useCallback2((event) => {
|
|
3347
|
+
if (!rowDraggable || event.button !== 0 || rowOrderDragRef.current) return;
|
|
3348
|
+
const columnIndex = locateColumn(event.clientX);
|
|
3349
|
+
const sourceIndex = locateRow(event.clientY);
|
|
3350
|
+
if (columnIndex < 0 || sourceIndex < 0 || !columns[columnIndex].rowDragHandle) return;
|
|
3351
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
3352
|
+
rowOrderDragRef.current = {
|
|
3353
|
+
pointerId: event.pointerId,
|
|
3354
|
+
startY: event.clientY,
|
|
3355
|
+
active: false,
|
|
3356
|
+
sourceIndex,
|
|
3357
|
+
targetIndex: sourceIndex
|
|
3437
3358
|
};
|
|
3438
|
-
}, [
|
|
3359
|
+
}, [columns, locateColumn, locateRow, rowDraggable]);
|
|
3360
|
+
const handleRowOrderPointerMove = useCallback2((event) => {
|
|
3361
|
+
const drag = rowOrderDragRef.current;
|
|
3362
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
3363
|
+
if (!drag.active) {
|
|
3364
|
+
if (Math.abs(event.clientY - drag.startY) < 4) return;
|
|
3365
|
+
drag.active = true;
|
|
3366
|
+
suppressClickRef.current = true;
|
|
3367
|
+
hideDragTooltips();
|
|
3368
|
+
document.documentElement.classList.add("rvg-is-dragging");
|
|
3369
|
+
event.currentTarget.style.cursor = "move";
|
|
3370
|
+
}
|
|
3371
|
+
event.preventDefault();
|
|
3372
|
+
const rawTargetIndex = locateRow(event.clientY);
|
|
3373
|
+
if (rawTargetIndex < 0) return;
|
|
3374
|
+
const canvasTop = event.currentTarget.getBoundingClientRect().top;
|
|
3375
|
+
const rowTop = bodyTop + rawTargetIndex * rowHeight - scrollRef.current.top;
|
|
3376
|
+
const edge = event.clientY - canvasTop < rowTop + rowHeight / 2 ? "top" : "bottom";
|
|
3377
|
+
let targetIndex = rawTargetIndex + (edge === "bottom" ? 1 : 0);
|
|
3378
|
+
if (drag.sourceIndex < targetIndex) targetIndex -= 1;
|
|
3379
|
+
targetIndex = Math.max(0, Math.min(rows.length - 1, targetIndex));
|
|
3380
|
+
drag.targetIndex = targetIndex;
|
|
3381
|
+
setRowDragPreview((current) => current?.sourceIndex === drag.sourceIndex && current.targetIndex === targetIndex ? current : { sourceIndex: drag.sourceIndex, targetIndex });
|
|
3382
|
+
setRowDragGuide(rowTop + (edge === "bottom" ? rowHeight : 0));
|
|
3383
|
+
}, [bodyTop, hideDragTooltips, locateRow, rowHeight, rows.length, setRowDragGuide]);
|
|
3384
|
+
const finishRowOrderPointerDrag = useCallback2((event, apply) => {
|
|
3385
|
+
const drag = rowOrderDragRef.current;
|
|
3386
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
3387
|
+
if (event.currentTarget.hasPointerCapture?.(event.pointerId)) event.currentTarget.releasePointerCapture?.(event.pointerId);
|
|
3388
|
+
rowOrderDragRef.current = null;
|
|
3389
|
+
setRowDragPreview(null);
|
|
3390
|
+
setRowDragGuide(null);
|
|
3391
|
+
document.documentElement.classList.remove("rvg-is-dragging");
|
|
3392
|
+
event.currentTarget.style.cursor = "default";
|
|
3393
|
+
if (apply && drag.active && drag.sourceIndex !== drag.targetIndex) {
|
|
3394
|
+
scrollerRef.current?.classList.add("rvg-row-drop-settling");
|
|
3395
|
+
applyRowOrder(drag.sourceIndex, drag.targetIndex);
|
|
3396
|
+
requestAnimationFrame(() => {
|
|
3397
|
+
requestAnimationFrame(() => scrollerRef.current?.classList.remove("rvg-row-drop-settling"));
|
|
3398
|
+
});
|
|
3399
|
+
}
|
|
3400
|
+
}, [applyRowOrder, setRowDragGuide]);
|
|
3439
3401
|
const locateCell = useCallback2((clientX, clientY) => {
|
|
3440
3402
|
const canvas = canvasRef.current;
|
|
3441
3403
|
if (!canvas) return null;
|
|
@@ -5028,7 +4990,7 @@ function TableInner({
|
|
|
5028
4990
|
}
|
|
5029
4991
|
}
|
|
5030
4992
|
}
|
|
5031
|
-
const cursor = inHeader && locateHeaderResizeCell(event.clientX, event.clientY) ? "col-resize" : hoveredAction ? "pointer" : hoveredDragHandle ? "move" : columnIndex >= 0 && columns[columnIndex].
|
|
4993
|
+
const cursor = inHeader && locateHeaderResizeCell(event.clientX, event.clientY) ? "col-resize" : hoveredAction ? "pointer" : hoveredDragHandle ? "move" : !inHeader && rowDraggable && columnIndex >= 0 && columns[columnIndex].rowDragHandle ? "move" : columnIndex >= 0 && columns[columnIndex].rowSelection ? "pointer" : "default";
|
|
5032
4994
|
if (event.currentTarget.style.cursor !== cursor) event.currentTarget.style.cursor = cursor;
|
|
5033
4995
|
},
|
|
5034
4996
|
onMouseLeave: (event) => {
|
|
@@ -5047,6 +5009,7 @@ function TableInner({
|
|
|
5047
5009
|
}
|
|
5048
5010
|
},
|
|
5049
5011
|
onPointerDown: (event) => {
|
|
5012
|
+
handleRowOrderPointerDown(event);
|
|
5050
5013
|
handleColumnPointerDown(event);
|
|
5051
5014
|
if (columnDragRef.current) return;
|
|
5052
5015
|
const headerDragCell = columnDraggable ? locateHeaderCell(event.clientX, event.clientY) : null;
|
|
@@ -5059,16 +5022,19 @@ function TableInner({
|
|
|
5059
5022
|
beginRangeDrag(event);
|
|
5060
5023
|
},
|
|
5061
5024
|
onPointerMove: (event) => {
|
|
5025
|
+
handleRowOrderPointerMove(event);
|
|
5062
5026
|
handleColumnPointerMove(event);
|
|
5063
5027
|
handleColumnOrderPointerMove(event);
|
|
5064
5028
|
updateRangeDrag(event);
|
|
5065
5029
|
},
|
|
5066
5030
|
onPointerUp: (event) => {
|
|
5031
|
+
finishRowOrderPointerDrag(event, true);
|
|
5067
5032
|
handleColumnPointerUp(event);
|
|
5068
5033
|
finishColumnOrderPointerDrag(event, true);
|
|
5069
5034
|
endRangeDrag(event);
|
|
5070
5035
|
},
|
|
5071
5036
|
onPointerCancel: (event) => {
|
|
5037
|
+
finishRowOrderPointerDrag(event, false);
|
|
5072
5038
|
handleColumnPointerUp(event);
|
|
5073
5039
|
finishColumnOrderPointerDrag(event, false);
|
|
5074
5040
|
endRangeDrag(event);
|