@absreim/react-bootstrap-data-grid-pro 2.4.1 → 2.6.0
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/grid/Grid.js +26 -30
- package/grid/InternalGrid.d.ts +1 -0
- package/grid/InternalGrid.js +17 -18
- package/grid/editing/EditControlsCell.js +3 -4
- package/grid/editing/EditableRow.js +11 -17
- package/grid/editing/inputStrsToRowData.js +4 -4
- package/grid/export/ExportForm.js +25 -49
- package/grid/export/useExportFn.js +34 -58
- package/grid/filtering/DateFilterRow.js +17 -33
- package/grid/filtering/FilterOptionsTable.js +60 -96
- package/grid/filtering/FilterRow.js +4 -13
- package/grid/filtering/NumberFilterRow.js +10 -25
- package/grid/filtering/StringFilterRow.js +10 -25
- package/grid/filtering/types.js +6 -6
- package/grid/filtering/useFilterFormState.js +52 -65
- package/grid/main/BodyRows.d.ts +3 -1
- package/grid/main/BodyRows.js +6 -13
- package/grid/main/ColHeaderCell/index.js +4 -4
- package/grid/main/ColHeaderCell/useSortHeaderStates.js +10 -10
- package/grid/main/ToggleButton.js +3 -4
- package/grid/pagination/PageSelector.js +17 -18
- package/grid/pagination/PageSizeSelector.js +5 -6
- package/grid/pagination/Pagination.js +6 -7
- package/grid/pipeline/useAugFormattedRows.js +5 -20
- package/grid/pipeline/useCombinedPipeline/index.d.ts +2 -2
- package/grid/pipeline/useCombinedPipeline/index.js +21 -22
- package/grid/pipeline/useCombinedPipeline/useCurrentPageRows.d.ts +3 -3
- package/grid/pipeline/useCombinedPipeline/useCurrentPageRows.js +29 -24
- package/grid/pipeline/useCombinedPipeline/useDisplayRows.d.ts +2 -2
- package/grid/pipeline/useCombinedPipeline/useDisplayRows.js +40 -41
- package/grid/pipeline/useCombinedPipeline/useFilter.d.ts +2 -2
- package/grid/pipeline/useCombinedPipeline/useFilter.js +9 -9
- package/grid/pipeline/useCombinedPipeline/useFilterStateFromEditable.js +5 -6
- package/grid/pipeline/useCombinedPipeline/useFilterStateStore.js +6 -7
- package/grid/pipeline/useCombinedPipeline/useSortedRows.d.ts +3 -3
- package/grid/pipeline/useCombinedPipeline/useSortedRows.js +22 -27
- package/grid/pipeline/useGetInputStrSubmitCallback.js +6 -6
- package/grid/pipeline/useGridSelectionFns.js +30 -30
- package/grid/pipeline/useUnwrappedGridStyles.js +5 -7
- package/grid/selection/SelectAllHeaderCell.d.ts +1 -0
- package/grid/selection/SelectAllHeaderCell.js +9 -10
- package/grid/selection/SelectionInput.js +4 -6
- package/grid/sorting/arrowPlaceholder.js +1 -1
- package/grid/sorting/downArrow.js +1 -1
- package/grid/sorting/sortOrderToAriaSort.d.ts +4 -0
- package/grid/sorting/sortOrderToAriaSort.js +11 -0
- package/grid/sorting/upArrow.js +1 -10
- package/grid/styling/styleModelUnwrappers.js +22 -33
- package/grid/toolbar/Toolbar.js +61 -9
- package/grid/toolbar/ToolbarContainer.js +3 -6
- package/grid/toolbar/useInterfaces.js +5 -17
- package/grid/types.d.ts +9 -5
- package/grid/util/datetime.js +2 -4
- package/grid/util/getWidthStyle.js +6 -8
- package/grid/util/isSubset.js +3 -4
- package/grid/util/useControlledHover.js +8 -8
- package/grid-pro/ColHeaderCellPro.js +47 -42
- package/grid-pro/GridPro.js +42 -32
- package/grid-pro/assets/HorizontalGrip.d.ts +6 -0
- package/grid-pro/assets/HorizontalGrip.js +3 -0
- package/grid-pro/assets/VerticalGrip.d.ts +6 -0
- package/grid-pro/assets/VerticalGrip.js +3 -0
- package/grid-pro/index.d.ts +3 -0
- package/grid-pro/index.js +3 -0
- package/grid-pro/reorder/ReorderHandleCell.d.ts +12 -0
- package/grid-pro/reorder/ReorderHandleCell.js +220 -0
- package/grid-pro/reorder/ReorderHeaderCell.d.ts +3 -0
- package/grid-pro/reorder/ReorderHeaderCell.js +4 -0
- package/grid-pro/reorder/types.d.ts +12 -0
- package/grid-pro/reorder/types.js +1 -0
- package/grid-pro/resize/useResizeModel.js +40 -62
- package/grid-pro/types.d.ts +9 -2
- package/grid-pro/util/index.d.ts +1 -0
- package/grid-pro/util/index.js +1 -0
- package/grid-pro/util/regDragCleanup.d.ts +3 -0
- package/grid-pro/util/regDragCleanup.js +28 -0
- package/grid-pro/util/reorderRows.d.ts +3 -0
- package/grid-pro/util/reorderRows.js +17 -0
- package/grid-pro/util/types.d.ts +10 -0
- package/grid-pro/util/types.js +1 -0
- package/package.json +1 -1
- package/style.css +1 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
const useControlledHover = () => {
|
|
3
|
+
const [isHovering, setIsHovering] = useState(false);
|
|
4
|
+
const handleMouseOver = () => setIsHovering(true);
|
|
5
|
+
const handleMouseOut = () => setIsHovering(false);
|
|
6
6
|
return {
|
|
7
|
-
isHovering
|
|
8
|
-
setIsHovering
|
|
9
|
-
handleMouseOver
|
|
10
|
-
handleMouseOut
|
|
7
|
+
isHovering,
|
|
8
|
+
setIsHovering,
|
|
9
|
+
handleMouseOver,
|
|
10
|
+
handleMouseOut,
|
|
11
11
|
};
|
|
12
12
|
};
|
|
13
13
|
export default useControlledHover;
|
|
@@ -4,22 +4,24 @@ import { useCallback, useMemo, useRef, } from "react";
|
|
|
4
4
|
import classNames from "classnames";
|
|
5
5
|
import getWidthStyle from "../grid/util/getWidthStyle";
|
|
6
6
|
import useSortHeaderStates from "../grid/main/ColHeaderCell/useSortHeaderStates";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
import VerticalGrip from "./assets/VerticalGrip";
|
|
8
|
+
import regDragCleanup from "./util/regDragCleanup";
|
|
9
|
+
import sortOrderToAriaSort from "../grid/sorting/sortOrderToAriaSort";
|
|
10
|
+
const setWidthStyle = (cells, width) => {
|
|
11
|
+
cells.forEach((cell) => {
|
|
12
|
+
cell.style.minWidth = `${width}px`;
|
|
13
|
+
cell.style.maxWidth = `${width}px`;
|
|
11
14
|
});
|
|
12
15
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
var clickToSortCellContents = useMemo(function () {
|
|
16
|
+
const ColHeaderCellPro = ({ label, sortModel, ariaColIndex, additionalClasses, width, displayMode, setWidth, minResizeWidth, maxResizeWidth, keyboardResizeStep, }) => {
|
|
17
|
+
const resizeable = setWidth !== undefined;
|
|
18
|
+
const cellIsClickable = !!(!resizeable && sortModel);
|
|
19
|
+
const sortDivClickable = resizeable && sortModel;
|
|
20
|
+
const { handleClick, handleMouseOver, handleMouseOut, sortSymbol } = useSortHeaderStates(sortModel);
|
|
21
|
+
const defaultMinResizeWidth = sortModel ? 64 : 32;
|
|
22
|
+
const effectiveMinResizeWidth = minResizeWidth || defaultMinResizeWidth;
|
|
23
|
+
const effectiveKbdResizeStep = keyboardResizeStep || 10;
|
|
24
|
+
const clickToSortCellContents = useMemo(() => {
|
|
23
25
|
if (!width || displayMode === "table") {
|
|
24
26
|
// Testing has shown that content gets cut off in a table cell only if
|
|
25
27
|
// the table "display" property is "block" and both "min-width" and
|
|
@@ -43,7 +45,7 @@ var ColHeaderCellPro = function (_a) {
|
|
|
43
45
|
sortSymbol,
|
|
44
46
|
width,
|
|
45
47
|
]);
|
|
46
|
-
|
|
48
|
+
const onKeyDown = useCallback((e) => {
|
|
47
49
|
if (setWidth === undefined || width === undefined) {
|
|
48
50
|
return;
|
|
49
51
|
}
|
|
@@ -62,9 +64,9 @@ var ColHeaderCellPro = function (_a) {
|
|
|
62
64
|
setWidth,
|
|
63
65
|
width,
|
|
64
66
|
]);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (event.button
|
|
67
|
+
const thRef = useRef(null);
|
|
68
|
+
const onPointerDown = useCallback((event) => {
|
|
69
|
+
if (event.button !== 0) {
|
|
68
70
|
return;
|
|
69
71
|
}
|
|
70
72
|
if (thRef.current === null ||
|
|
@@ -79,48 +81,51 @@ var ColHeaderCellPro = function (_a) {
|
|
|
79
81
|
// in a ref and having this component conditionally render based on the
|
|
80
82
|
// value of the ref. I.e., if the ref has a value, use that value for the
|
|
81
83
|
// width instead of the "width" prop.
|
|
82
|
-
|
|
84
|
+
const target = event.target;
|
|
83
85
|
target.setPointerCapture(event.pointerId);
|
|
84
|
-
|
|
86
|
+
const table = thRef.current.parentElement.parentElement
|
|
85
87
|
.parentElement;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
const tds = table.querySelectorAll(`:scope > tbody > tr > td:nth-child(${ariaColIndex})`);
|
|
89
|
+
const cellsToUpdate = Array.from(tds).concat(thRef.current);
|
|
90
|
+
const origX = event.clientX;
|
|
91
|
+
const onPointerMove = (event) => {
|
|
92
|
+
const diff = event.clientX - origX;
|
|
93
|
+
let newWidth = Math.max(effectiveMinResizeWidth, width + diff);
|
|
92
94
|
if (maxResizeWidth) {
|
|
93
95
|
newWidth = Math.min(maxResizeWidth, newWidth);
|
|
94
96
|
}
|
|
95
97
|
setWidthStyle(cellsToUpdate, newWidth);
|
|
96
98
|
};
|
|
97
|
-
|
|
98
|
-
var removePointerMove = function () {
|
|
99
|
-
return target.removeEventListener("pointermove", onPointerMove);
|
|
100
|
-
};
|
|
101
|
-
var onKeyDown = function (event) {
|
|
99
|
+
const onKeyDown = (removeListeners) => (event) => {
|
|
102
100
|
if (event.code === "Escape") {
|
|
103
101
|
setWidthStyle(cellsToUpdate, width);
|
|
104
|
-
|
|
102
|
+
removeListeners();
|
|
105
103
|
}
|
|
106
104
|
};
|
|
107
|
-
|
|
108
|
-
var onPointerUp = function () {
|
|
105
|
+
const onPointerUp = (removeListeners) => () => {
|
|
109
106
|
if (thRef.current !== null) {
|
|
110
|
-
|
|
107
|
+
const newWidth = Number(thRef.current.style.minWidth.replace("px", ""));
|
|
111
108
|
setWidth(newWidth);
|
|
112
109
|
}
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
removeListeners();
|
|
111
|
+
};
|
|
112
|
+
const onContextMenu = (event) => {
|
|
113
|
+
event.preventDefault();
|
|
115
114
|
};
|
|
116
|
-
|
|
115
|
+
regDragCleanup({
|
|
116
|
+
element: target,
|
|
117
|
+
onPointerMove,
|
|
118
|
+
onPointerUp,
|
|
119
|
+
onPointerCancel: onPointerUp,
|
|
120
|
+
onKeyDown,
|
|
121
|
+
onContextMenu,
|
|
122
|
+
});
|
|
117
123
|
}, [ariaColIndex, effectiveMinResizeWidth, maxResizeWidth, setWidth, width]);
|
|
118
|
-
|
|
124
|
+
const cellContents = useMemo(() => {
|
|
119
125
|
if (!resizeable) {
|
|
120
126
|
return clickToSortCellContents;
|
|
121
127
|
}
|
|
122
|
-
|
|
123
|
-
return (_jsxs("div", { className: "d-flex justify-content-between", children: [clickToSortCellContents, _jsx("div", { className: "rdbg-drag-marker-container", onPointerDown: onPointerDown, role: "separator", tabIndex: 0, "aria-label": "Resize column", "aria-valuenow": width, "aria-valuemin": minResizeWidth, "aria-valuemax": maxResizeWidth, onKeyDown: onKeyDown, onClick: function (e) { return e.stopPropagation(); }, children: dragHandleIcon })] }));
|
|
128
|
+
return (_jsxs("div", { className: "d-flex justify-content-between", children: [clickToSortCellContents, _jsx("div", { className: "rbdg-draggable-container rbdg-resize-container", onPointerDown: onPointerDown, role: "separator", tabIndex: 0, title: "Resize column", "aria-label": "Resize column", "aria-valuenow": width, "aria-valuemin": minResizeWidth, "aria-valuemax": maxResizeWidth, onKeyDown: onKeyDown, onClick: (e) => e.stopPropagation(), children: _jsx(VerticalGrip, { className: "rbdg-draggable-icon" }) })] }));
|
|
124
129
|
}, [
|
|
125
130
|
clickToSortCellContents,
|
|
126
131
|
maxResizeWidth,
|
|
@@ -135,6 +140,6 @@ var ColHeaderCellPro = function (_a) {
|
|
|
135
140
|
"table-active": sortModel === null || sortModel === void 0 ? void 0 : sortModel.sortOrder,
|
|
136
141
|
}, additionalClasses || []), onClick: cellIsClickable ? handleClick : undefined, onMouseOver: cellIsClickable ? handleMouseOver : undefined, onMouseOut: cellIsClickable ? handleMouseOut : undefined, "aria-description": sortModel
|
|
137
142
|
? "Column header"
|
|
138
|
-
: "Column header that can be clicked to change the sorting mode", "aria-colindex": ariaColIndex, style: getWidthStyle(width), children: cellContents }));
|
|
143
|
+
: "Column header that can be clicked to change the sorting mode", "aria-colindex": ariaColIndex, "aria-sort": sortModel ? sortOrderToAriaSort(sortModel.sortOrder) : undefined, style: getWidthStyle(width), children: cellContents }));
|
|
139
144
|
};
|
|
140
145
|
export default ColHeaderCellPro;
|
package/grid-pro/GridPro.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { useMemo } from "react";
|
|
3
|
+
import { useCallback, useMemo } from "react";
|
|
4
4
|
import useCombinedPipeline from "../grid/pipeline/useCombinedPipeline";
|
|
5
5
|
import InternalGrid from "../grid/InternalGrid";
|
|
6
6
|
import ColHeaderCellPro from "./ColHeaderCellPro";
|
|
@@ -10,47 +10,57 @@ import useGetInputStrSubmitCallback from "../grid/pipeline/useGetInputStrSubmitC
|
|
|
10
10
|
import useAugFormattedRows from "../grid/pipeline/useAugFormattedRows";
|
|
11
11
|
import useResizeModel from "./resize/useResizeModel";
|
|
12
12
|
import BodyRows from "../grid/main/BodyRows";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
import ReorderHeaderCell from "./reorder/ReorderHeaderCell";
|
|
14
|
+
import ReorderHandleCell from "./reorder/ReorderHandleCell";
|
|
15
|
+
const GridPro = (props) => {
|
|
16
|
+
const { rows, cols, editModel, filterModel, sortModel, pagination, selectModel, styleModel, displayMode, reorder, } = props;
|
|
17
|
+
const combinedPipelineOutput = useCombinedPipeline({
|
|
18
|
+
rows,
|
|
19
|
+
cols,
|
|
20
|
+
filterModel,
|
|
21
|
+
sortModel,
|
|
22
|
+
pagination,
|
|
23
|
+
selectModel,
|
|
22
24
|
});
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
var _b;
|
|
37
|
-
var name = _a.name, label = _a.label, sortable = _a.sortable, minResizeWidth = _a.minResizeWidth, maxResizeWidth = _a.maxResizeWidth, keyboardResizeStep = _a.keyboardResizeStep;
|
|
38
|
-
var colSortModel = sortingEnabled && sortable
|
|
25
|
+
const { sortedRowsOutput: { sortColDef, setSortColDef, sortingEnabled }, showSelectCol, displayRows, filterState, } = combinedPipelineOutput;
|
|
26
|
+
const gridSelectionFns = useGridSelectionFns(selectModel, rows);
|
|
27
|
+
const unwrappedStyles = useUnwrappedGridStyles(styleModel);
|
|
28
|
+
const getInputStrSubmitCallback = useGetInputStrSubmitCallback(editModel, cols);
|
|
29
|
+
const resizeModel = useResizeModel(cols, displayMode);
|
|
30
|
+
const colNameToWidth = useMemo(() => Object.keys(resizeModel).reduce((prev, fieldName) => {
|
|
31
|
+
prev[fieldName] = resizeModel[fieldName].width;
|
|
32
|
+
return prev;
|
|
33
|
+
}, {}), [resizeModel]);
|
|
34
|
+
const augFormattedRows = useAugFormattedRows(colNameToWidth, displayRows);
|
|
35
|
+
const colHeaderCells = cols.map(({ name, label, sortable, minResizeWidth, maxResizeWidth, keyboardResizeStep, }, index) => {
|
|
36
|
+
var _a;
|
|
37
|
+
const colSortModel = sortingEnabled && sortable
|
|
39
38
|
? {
|
|
40
39
|
sortOrder: (sortColDef === null || sortColDef === void 0 ? void 0 : sortColDef.name) === name ? sortColDef.order : null,
|
|
41
|
-
setSortOrder:
|
|
42
|
-
setSortColDef && setSortColDef(order && { name
|
|
40
|
+
setSortOrder: (order) => {
|
|
41
|
+
setSortColDef && setSortColDef(order && { name, order });
|
|
43
42
|
},
|
|
44
43
|
}
|
|
45
44
|
: undefined;
|
|
46
|
-
return (_jsx(ColHeaderCellPro, { label: label, sortModel: colSortModel, ariaColIndex: index + 1 + (showSelectCol ? 1 : 0), additionalClasses: ((
|
|
45
|
+
return (_jsx(ColHeaderCellPro, { label: label, sortModel: colSortModel, ariaColIndex: index + 1 + (showSelectCol ? 1 : 0), additionalClasses: ((_a = styleModel === null || styleModel === void 0 ? void 0 : styleModel.mainTableStyleModel) === null || _a === void 0 ? void 0 : _a.theadTh) &&
|
|
47
46
|
styleModel.mainTableStyleModel.theadTh(index), width: resizeModel[name].width, displayMode: displayMode, setWidth: resizeModel[name].setWidth, minResizeWidth: minResizeWidth, maxResizeWidth: maxResizeWidth, keyboardResizeStep: keyboardResizeStep }, name));
|
|
48
47
|
});
|
|
49
|
-
|
|
48
|
+
const filteringOccurring = !!(filterState &&
|
|
49
|
+
Object.values(filterState).find(({ editableState }) => editableState.enabled));
|
|
50
|
+
const sortingOccurring = !!sortColDef;
|
|
51
|
+
const renderPrefixCells = useCallback((augRow) => {
|
|
52
|
+
if (!reorder) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const reorderCallback = (destIndex) => reorder.callback(augRow.id, destIndex);
|
|
56
|
+
return (_jsx(ReorderHandleCell, { rowId: augRow.id, ariaRowIndex: augRow.prePaginationIndex + 2, disabled: filteringOccurring || sortingOccurring, reorderCallback: reorderCallback, styleModel: styleModel === null || styleModel === void 0 ? void 0 : styleModel.reorderModel }));
|
|
57
|
+
}, [filteringOccurring, reorder, sortingOccurring, styleModel === null || styleModel === void 0 ? void 0 : styleModel.reorderModel]);
|
|
58
|
+
const bodyRows = (_jsx(BodyRows, { augFormattedRows: augFormattedRows, gridSelectionFns: gridSelectionFns, selectModel: selectModel, unwrappedStyles: unwrappedStyles, combinedPipelineOutput: combinedPipelineOutput, editModel: editModel, getInputStrSubmitCallback: getInputStrSubmitCallback, renderPrefixCells: renderPrefixCells, additionalColIndexOffset: reorder ? 1 : 0 }));
|
|
59
|
+
const prefixHeader = reorder ? _jsx(ReorderHeaderCell, {}) : null;
|
|
50
60
|
return (_jsx(InternalGrid, { gridProps: props, hooks: {
|
|
51
61
|
pipelineOutput: combinedPipelineOutput,
|
|
52
62
|
selectFns: gridSelectionFns,
|
|
53
|
-
unwrappedStyles
|
|
54
|
-
}, slots: { colHeaderCells
|
|
63
|
+
unwrappedStyles,
|
|
64
|
+
}, slots: { colHeaderCells, bodyRows, prefixHeader } }));
|
|
55
65
|
};
|
|
56
66
|
export default GridPro;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
const HorizontalGrip = ({ className }) => (_jsxs("svg", { "aria-hidden": true, xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", fill: "currentColor", viewBox: "0 0 16 16", className: className, children: [_jsx("title", { children: "Horizontal Grip" }), _jsx("desc", { children: "A 2-row by 5-column array of dots" }), _jsx("path", { d: "M2 8a1 1 0 1 1 0 2 1 1 0 0 1 0-2m0-3a1 1 0 1 1 0 2 1 1 0 0 1 0-2m3 3a1 1 0 1 1 0 2 1 1 0 0 1 0-2m0-3a1 1 0 1 1 0 2 1 1 0 0 1 0-2m3 3a1 1 0 1 1 0 2 1 1 0 0 1 0-2m0-3a1 1 0 1 1 0 2 1 1 0 0 1 0-2m3 3a1 1 0 1 1 0 2 1 1 0 0 1 0-2m0-3a1 1 0 1 1 0 2 1 1 0 0 1 0-2m3 3a1 1 0 1 1 0 2 1 1 0 0 1 0-2m0-3a1 1 0 1 1 0 2 1 1 0 0 1 0-2" })] }));
|
|
3
|
+
export default HorizontalGrip;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
const VerticalGrip = ({ className }) => (_jsxs("svg", { "aria-hidden": true, xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", fill: "currentColor", viewBox: "0 0 16 16", className: className, children: [_jsx("title", { children: "Vertical Grip" }), _jsx("desc", { children: "A 5-row by 2-column array of dots" }), _jsx("path", { d: "M7 2a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0M7 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0M7 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0" })] }));
|
|
3
|
+
export default VerticalGrip;
|
package/grid-pro/index.d.ts
CHANGED
package/grid-pro/index.js
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { RowId } from "../";
|
|
3
|
+
import { ReorderStyleModel } from "./types";
|
|
4
|
+
export type ReorderHandleCellProps = {
|
|
5
|
+
rowId: RowId;
|
|
6
|
+
ariaRowIndex: number;
|
|
7
|
+
reorderCallback: (destIndex: number) => void;
|
|
8
|
+
disabled: boolean;
|
|
9
|
+
styleModel?: ReorderStyleModel;
|
|
10
|
+
};
|
|
11
|
+
declare const ReorderHandleCell: FC<ReorderHandleCellProps>;
|
|
12
|
+
export default ReorderHandleCell;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useMemo } from "react";
|
|
3
|
+
import HorizontalGrip from "../assets/HorizontalGrip";
|
|
4
|
+
import regDragCleanup from "../util/regDragCleanup";
|
|
5
|
+
import classNames from "classnames";
|
|
6
|
+
function dropTargetRefValuesEqual(first, second) {
|
|
7
|
+
if (first === null && second === null) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
if (first === null || second === null) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
return first.index === second.index && first.upper === second.upper;
|
|
14
|
+
}
|
|
15
|
+
const ReorderHandleCell = ({ rowId, ariaRowIndex, disabled, reorderCallback, styleModel, }) => {
|
|
16
|
+
const intDraggedRowClasses = useMemo(() => (styleModel === null || styleModel === void 0 ? void 0 : styleModel.draggedRowClasses) || ["rbdg-reorder-dragged-row"], [styleModel === null || styleModel === void 0 ? void 0 : styleModel.draggedRowClasses]);
|
|
17
|
+
const intDraggedRowPredecessorClasses = useMemo(() => (styleModel === null || styleModel === void 0 ? void 0 : styleModel.draggedRowPredecessorClasses) || [
|
|
18
|
+
"rbdg-reorder-dragged-row-pred",
|
|
19
|
+
], [styleModel === null || styleModel === void 0 ? void 0 : styleModel.draggedRowPredecessorClasses]);
|
|
20
|
+
const intTopBorderRowClasses = useMemo(() => (styleModel === null || styleModel === void 0 ? void 0 : styleModel.topBorderRowClasses) || ["rbdg-reorder-above-drag-target-row"], [styleModel === null || styleModel === void 0 ? void 0 : styleModel.topBorderRowClasses]);
|
|
21
|
+
const intBottomBorderRowClasses = useMemo(() => (styleModel === null || styleModel === void 0 ? void 0 : styleModel.bottomBorderRowClasses) || [
|
|
22
|
+
"rbdg-reorder-below-drag-target-row",
|
|
23
|
+
], [styleModel === null || styleModel === void 0 ? void 0 : styleModel.bottomBorderRowClasses]);
|
|
24
|
+
const intGhostTableClasses = useMemo(() => (styleModel === null || styleModel === void 0 ? void 0 : styleModel.ghostDivClasses) || ["border", "rbdg-drag-ghost"], [styleModel === null || styleModel === void 0 ? void 0 : styleModel.ghostDivClasses]);
|
|
25
|
+
const onPointerDown = useCallback((event) => {
|
|
26
|
+
const target = event.target;
|
|
27
|
+
const { pointerId, clientX, clientY, button } = event;
|
|
28
|
+
if (button !== 0) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
function createDragGhost() {
|
|
32
|
+
const ghostDiv = document.createElement("div");
|
|
33
|
+
ghostDiv.className = intGhostTableClasses.join(" ");
|
|
34
|
+
ghostDiv.style.left = `${clientX}px`;
|
|
35
|
+
ghostDiv.style.top = `${clientY}px`;
|
|
36
|
+
ghostDiv.textContent = `ID: ${rowId}`;
|
|
37
|
+
ghostDiv.setAttribute("data-testid", "rbdg-drag-ghost");
|
|
38
|
+
document.body.appendChild(ghostDiv);
|
|
39
|
+
return ghostDiv;
|
|
40
|
+
}
|
|
41
|
+
const drageeTh = target.parentElement;
|
|
42
|
+
const drageeTr = drageeTh.parentElement;
|
|
43
|
+
const tbody = drageeTr.parentElement;
|
|
44
|
+
const thead = tbody.parentElement.firstChild;
|
|
45
|
+
const headTr = thead.firstChild;
|
|
46
|
+
const trs = Array.from(tbody.children);
|
|
47
|
+
const drageeTrIndex = Number(drageeTr.ariaRowIndex) - 2;
|
|
48
|
+
const origClassesByIndex = trs.map((tr) => tr.className);
|
|
49
|
+
const origHeadTrClasses = headTr.className;
|
|
50
|
+
function applyRowClassesFromOrig(trIndex, classes) {
|
|
51
|
+
trs[trIndex].className = [
|
|
52
|
+
origClassesByIndex[trIndex],
|
|
53
|
+
classes.join(" "),
|
|
54
|
+
]
|
|
55
|
+
.join(" ")
|
|
56
|
+
.trim();
|
|
57
|
+
}
|
|
58
|
+
function applyDrageeStyles() {
|
|
59
|
+
applyRowClassesFromOrig(drageeTrIndex, intDraggedRowClasses);
|
|
60
|
+
if (drageeTrIndex - 1 === -1) {
|
|
61
|
+
headTr.className = [
|
|
62
|
+
origHeadTrClasses,
|
|
63
|
+
intDraggedRowPredecessorClasses.join(" "),
|
|
64
|
+
]
|
|
65
|
+
.join(" ")
|
|
66
|
+
.trim();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
applyRowClassesFromOrig(drageeTrIndex - 1, intDraggedRowPredecessorClasses);
|
|
70
|
+
}
|
|
71
|
+
applyDrageeStyles();
|
|
72
|
+
const baseClassesByIndex = trs.map((tr) => tr.className);
|
|
73
|
+
const baseHeadTrClasses = headTr.className;
|
|
74
|
+
const rectToIndex = trs.reduce((map, element, trIndex) => {
|
|
75
|
+
if (trIndex !== drageeTrIndex) {
|
|
76
|
+
map.set(element.getBoundingClientRect(), trIndex);
|
|
77
|
+
}
|
|
78
|
+
return map;
|
|
79
|
+
}, new Map());
|
|
80
|
+
const dropTargetRef = {
|
|
81
|
+
current: null,
|
|
82
|
+
};
|
|
83
|
+
function detectEnclosure(clientX, clientY) {
|
|
84
|
+
for (const rect of rectToIndex.keys()) {
|
|
85
|
+
if (clientY < rect.top ||
|
|
86
|
+
clientY > rect.bottom ||
|
|
87
|
+
clientX < rect.left ||
|
|
88
|
+
clientX > rect.right) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const midY = Math.floor(rect.top + rect.bottom) / 2;
|
|
92
|
+
const rectIndex = rectToIndex.get(rect);
|
|
93
|
+
if (clientY <= midY && rectIndex - 1 === drageeTrIndex) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
if (clientY <= midY && rectIndex - 1 !== drageeTrIndex) {
|
|
97
|
+
return { index: rectIndex, upper: true };
|
|
98
|
+
}
|
|
99
|
+
if (clientY > midY && rectIndex + 1 === drageeTrIndex) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
if (clientY > midY && rectIndex + 1 !== drageeTrIndex) {
|
|
103
|
+
return { index: rectIndex, upper: false };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
function restoreOrigRowClasses(trIndex) {
|
|
109
|
+
trs[trIndex].className = origClassesByIndex[trIndex];
|
|
110
|
+
}
|
|
111
|
+
function restoreOrigClasses() {
|
|
112
|
+
trs.forEach((_, trIndex) => restoreOrigRowClasses(trIndex));
|
|
113
|
+
headTr.className = origHeadTrClasses;
|
|
114
|
+
}
|
|
115
|
+
function restoreBaseRowClasses(trIndex) {
|
|
116
|
+
trs[trIndex].className = baseClassesByIndex[trIndex];
|
|
117
|
+
}
|
|
118
|
+
function restoreBaseClasses() {
|
|
119
|
+
trs.forEach((_, trIndex) => restoreBaseRowClasses(trIndex));
|
|
120
|
+
headTr.className = baseHeadTrClasses;
|
|
121
|
+
}
|
|
122
|
+
function applyRowClassesFromBase(trIndex, classes) {
|
|
123
|
+
trs[trIndex].className = [
|
|
124
|
+
baseClassesByIndex[trIndex],
|
|
125
|
+
classes.join(" "),
|
|
126
|
+
]
|
|
127
|
+
.join(" ")
|
|
128
|
+
.trim();
|
|
129
|
+
}
|
|
130
|
+
function applyDragStyles(trIndex, upper) {
|
|
131
|
+
if (upper) {
|
|
132
|
+
applyRowClassesFromBase(trIndex, intBottomBorderRowClasses);
|
|
133
|
+
}
|
|
134
|
+
if (upper && trIndex - 1 >= 0) {
|
|
135
|
+
applyRowClassesFromBase(trIndex - 1, intTopBorderRowClasses);
|
|
136
|
+
}
|
|
137
|
+
if (upper && trIndex - 1 === -1) {
|
|
138
|
+
headTr.className = [
|
|
139
|
+
baseHeadTrClasses,
|
|
140
|
+
intTopBorderRowClasses.join(" "),
|
|
141
|
+
]
|
|
142
|
+
.join(" ")
|
|
143
|
+
.trim();
|
|
144
|
+
}
|
|
145
|
+
if (!upper) {
|
|
146
|
+
applyRowClassesFromBase(trIndex, intTopBorderRowClasses);
|
|
147
|
+
}
|
|
148
|
+
if (!upper && trIndex + 1 < trs.length) {
|
|
149
|
+
applyRowClassesFromBase(trIndex + 1, intBottomBorderRowClasses);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function updateRowStyles(currentDropTargetVal) {
|
|
153
|
+
if (dropTargetRefValuesEqual(dropTargetRef.current, currentDropTargetVal)) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (currentDropTargetVal === null) {
|
|
157
|
+
restoreBaseClasses();
|
|
158
|
+
dropTargetRef.current = null;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (dropTargetRef.current !== null) {
|
|
162
|
+
restoreBaseClasses();
|
|
163
|
+
}
|
|
164
|
+
applyDragStyles(currentDropTargetVal.index, currentDropTargetVal.upper);
|
|
165
|
+
dropTargetRef.current = currentDropTargetVal;
|
|
166
|
+
}
|
|
167
|
+
target.setPointerCapture(pointerId);
|
|
168
|
+
const dragGhost = createDragGhost();
|
|
169
|
+
applyDrageeStyles();
|
|
170
|
+
function onPointerMove({ clientX, clientY }) {
|
|
171
|
+
dragGhost.style.left = `${clientX}px`;
|
|
172
|
+
dragGhost.style.top = `${clientY}px`;
|
|
173
|
+
const dragTargetVal = detectEnclosure(clientX, clientY);
|
|
174
|
+
updateRowStyles(dragTargetVal);
|
|
175
|
+
}
|
|
176
|
+
function onContextMenu(event) {
|
|
177
|
+
event.preventDefault();
|
|
178
|
+
}
|
|
179
|
+
function cleanUpDragStates() {
|
|
180
|
+
dragGhost.remove();
|
|
181
|
+
restoreOrigClasses();
|
|
182
|
+
}
|
|
183
|
+
const onKeyDown = (removeListeners) => (event) => {
|
|
184
|
+
if (event.code === "Escape") {
|
|
185
|
+
removeListeners();
|
|
186
|
+
cleanUpDragStates();
|
|
187
|
+
dropTargetRef.current = null;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
const onPointerUp = (removeListeners) => () => {
|
|
191
|
+
removeListeners();
|
|
192
|
+
cleanUpDragStates();
|
|
193
|
+
if (dropTargetRef.current !== null) {
|
|
194
|
+
reorderCallback(dropTargetRef.current.index + (dropTargetRef.current.upper ? 0 : 1));
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
target.focus();
|
|
198
|
+
regDragCleanup({
|
|
199
|
+
element: target,
|
|
200
|
+
onPointerMove,
|
|
201
|
+
onPointerUp,
|
|
202
|
+
onPointerCancel: onPointerUp,
|
|
203
|
+
onKeyDown,
|
|
204
|
+
onContextMenu,
|
|
205
|
+
});
|
|
206
|
+
}, [
|
|
207
|
+
intBottomBorderRowClasses,
|
|
208
|
+
intDraggedRowClasses,
|
|
209
|
+
intDraggedRowPredecessorClasses,
|
|
210
|
+
intGhostTableClasses,
|
|
211
|
+
intTopBorderRowClasses,
|
|
212
|
+
reorderCallback,
|
|
213
|
+
rowId,
|
|
214
|
+
]);
|
|
215
|
+
const label = `Reorder Row ${ariaRowIndex}`;
|
|
216
|
+
return (_jsx("th", { "aria-colindex": 1, children: _jsx("button", { onClick: (event) => event.stopPropagation(), "aria-label": label, title: label, onPointerDown: onPointerDown, className: classNames("rbdg-draggable-container", "rbdg-reorder-container", "rbdg-plain-icon-button", {
|
|
217
|
+
"bs-btn-disabled": disabled,
|
|
218
|
+
}), disabled: disabled, children: _jsx(HorizontalGrip, { className: "rbdg-draggable-icon" }) }) }));
|
|
219
|
+
};
|
|
220
|
+
export default ReorderHandleCell;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
const spinningArrowIcon = (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", fill: "currentColor", viewBox: "0 0 16 16", "aria-hidden": "true", children: [_jsx("desc", { children: "Two arrows that are following each other and pointing clockwise" }), _jsx("path", { d: "M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41m-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9" }), _jsx("path", { fillRule: "evenodd", d: "M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5 5 0 0 0 8 3M3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9z" })] }));
|
|
3
|
+
const ReorderHeaderCell = () => (_jsx("th", { "aria-colindex": 1, title: "Reorder Controls", "aria-label": "Reorder Controls", "aria-description": "Header cell for column with drag handles for reordering rows", children: spinningArrowIcon }));
|
|
4
|
+
export default ReorderHeaderCell;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { RowId } from "../";
|
|
2
|
+
export type ReorderCallback = (id: RowId, destIndex: number) => void;
|
|
3
|
+
export interface ReorderModel {
|
|
4
|
+
callback: ReorderCallback;
|
|
5
|
+
}
|
|
6
|
+
export interface ReorderStyleModel {
|
|
7
|
+
draggedRowClasses?: string[];
|
|
8
|
+
draggedRowPredecessorClasses?: string[];
|
|
9
|
+
topBorderRowClasses?: string[];
|
|
10
|
+
bottomBorderRowClasses?: string[];
|
|
11
|
+
ghostDivClasses?: string[];
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|