@absreim/react-bootstrap-data-grid-pro 2.6.0 → 2.7.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/InternalGrid.d.ts +3 -0
- package/grid/InternalGrid.js +2 -2
- package/grid/main/BodyRows.d.ts +2 -1
- package/grid/main/BodyRows.js +2 -2
- package/grid/selection/SelectAllHeaderCell.js +1 -1
- package/grid/selection/SelectionInput.d.ts +1 -0
- package/grid/selection/SelectionInput.js +2 -2
- package/grid/util/trueModulo.d.ts +2 -0
- package/grid/util/trueModulo.js +2 -0
- package/grid-pro/ColHeaderCellPro.js +6 -3
- package/grid-pro/GridPro.js +69 -5
- package/grid-pro/reorder/ReorderHandleCell.d.ts +4 -3
- package/grid-pro/reorder/ReorderHandleCell.js +28 -29
- package/grid-pro/reorder/types.d.ts +15 -0
- package/grid-pro/reorder/useKeyboardReorder.d.ts +4 -0
- package/grid-pro/reorder/useKeyboardReorder.js +84 -0
- package/grid-pro/reorder/useKeyboardReorderListener.d.ts +3 -0
- package/grid-pro/reorder/useKeyboardReorderListener.js +26 -0
- package/grid-pro/reorder/useReorderStyles.d.ts +3 -0
- package/grid-pro/reorder/useReorderStyles.js +20 -0
- package/package.json +1 -1
package/grid/InternalGrid.d.ts
CHANGED
package/grid/InternalGrid.js
CHANGED
|
@@ -10,7 +10,7 @@ import useInterfaces from "./toolbar/useInterfaces";
|
|
|
10
10
|
import ToolbarContainer from "./toolbar/ToolbarContainer";
|
|
11
11
|
import useExportFn from "./export/useExportFn";
|
|
12
12
|
import getWidthStyle from "./util/getWidthStyle";
|
|
13
|
-
const InternalGrid = ({ gridProps: { rows, cols, pagination, filterModel, selectModel, editModel, caption, styleModel, useToolbar, responsive, displayMode, }, hooks: { pipelineOutput, selectFns, unwrappedStyles }, slots: { colHeaderCells, bodyRows, prefixHeader }, }) => {
|
|
13
|
+
const InternalGrid = ({ gridProps: { rows, cols, pagination, filterModel, selectModel, editModel, caption, styleModel, useToolbar, responsive, displayMode, }, hooks: { pipelineOutput, selectFns, unwrappedStyles }, slots: { colHeaderCells, bodyRows, prefixHeader }, classes, }) => {
|
|
14
14
|
var _a;
|
|
15
15
|
const { normalizedTableFilterModel, filteredRows, filterState, sortedRowsOutput: { sortedRows }, currentPageRowsOutput: { paginatedRows, normalizedModel }, showSelectCol, } = pipelineOutput;
|
|
16
16
|
const [filterOptionsVisible, setFilterOptionsVisible] = useState(false);
|
|
@@ -50,7 +50,7 @@ const InternalGrid = ({ gridProps: { rows, cols, pagination, filterModel, select
|
|
|
50
50
|
const mainTable = (_jsxs("table", { className: classNames("table", {
|
|
51
51
|
"table-hover": rowsAreSelectable,
|
|
52
52
|
"d-block": displayMode === "block",
|
|
53
|
-
}, unwrappedTableModel.table), "aria-rowcount": filteredRows.length + 1, children: [caption !== undefined && (_jsx("caption", { className: classNames(unwrappedTableModel.caption), children: caption })), _jsx("thead", { className: classNames(unwrappedTableModel.thead), children: _jsxs("tr", { "aria-rowindex": 1, className: classNames(unwrappedTableModel.theadTr), children: [prefixHeader, showSelectCol && (_jsx(SelectAllHeaderCell, { style: getWidthStyle(selectModel === null || selectModel === void 0 ? void 0 : selectModel.selectColWidth), selectionInfo: selectionInfo, onClick: selectAllOnClick, totalRows: rows.length, additionalClasses: unwrappedTableModel.rowSelectColTh, colIndexOffset: prefixHeader ? 1 : 0 })), colHeaderCells, editModel && (_jsx("th", { "aria-colindex": cols.length + 1 + (showSelectCol ? 1 : 0), className: classNames(unwrappedTableModel.editColTh), style: getWidthStyle(editModel === null || editModel === void 0 ? void 0 : editModel.editColWidth), children: "Edit Controls" }))] }) }), _jsx("tbody", { className: classNames(unwrappedTableModel.tbody), children: bodyRows })] }));
|
|
53
|
+
}, unwrappedTableModel.table), "aria-rowcount": filteredRows.length + 1, children: [caption !== undefined && (_jsx("caption", { className: classNames(unwrappedTableModel.caption), children: caption })), _jsx("thead", { className: classNames(unwrappedTableModel.thead), children: _jsxs("tr", { "aria-rowindex": 1, className: classNames(unwrappedTableModel.theadTr, (classes === null || classes === void 0 ? void 0 : classes.headerRow) || []), children: [prefixHeader, showSelectCol && (_jsx(SelectAllHeaderCell, { style: getWidthStyle(selectModel === null || selectModel === void 0 ? void 0 : selectModel.selectColWidth), selectionInfo: selectionInfo, onClick: selectAllOnClick, totalRows: rows.length, additionalClasses: unwrappedTableModel.rowSelectColTh, colIndexOffset: prefixHeader ? 1 : 0 })), colHeaderCells, editModel && (_jsx("th", { "aria-colindex": cols.length + 1 + (showSelectCol ? 1 : 0), className: classNames(unwrappedTableModel.editColTh), style: getWidthStyle(editModel === null || editModel === void 0 ? void 0 : editModel.editColWidth), children: "Edit Controls" }))] }) }), _jsx("tbody", { className: classNames(unwrappedTableModel.tbody), children: bodyRows })] }));
|
|
54
54
|
return (_jsxs("div", { "data-testid": "rbdg-top-level-div", className: classNames(unwrappedAdditionalStyleModel.topLevelDiv), children: [normalizedTableFilterModel && !useToolbar && (_jsxs("div", { "data-testid": "rbdg-filter-inputs-div", className: classNames(unwrappedAdditionalStyleModel.filterInputsDiv), children: [_jsx(ToggleButton, { isActive: filterOptionsVisible, label: `${filterOptionsVisible ? "Hide" : "Show "} Filter Options`, onClick: handleToggleFilterOptions, classes: (_a = styleModel === null || styleModel === void 0 ? void 0 : styleModel.additionalComponentsStyleModel) === null || _a === void 0 ? void 0 : _a.filterUiToggleButton }), filterOptionsVisible && (_jsx(FilterOptionsTable, { caption: filterModel.filterTableCaption, filterState: filterState, setFilterState: normalizedTableFilterModel.setTableFilterState, styleModel: styleModel === null || styleModel === void 0 ? void 0 : styleModel.filterInputTableStyleModel }))] })), useToolbar && (_jsx(ToolbarContainer, { interfaces: toolbarInterfaces, styleModel: styleModel === null || styleModel === void 0 ? void 0 : styleModel.toolbarStyleModel })), _jsxs("div", { "data-testid": "rbdg-table-and-pagination-div", className: classNames(unwrappedAdditionalStyleModel.tableAndPaginationDiv), children: [responsive ? (_jsx("div", { "data-testid": "rbdg-table-div", className: "table-responsive", children: mainTable })) : (_jsx(_Fragment, { children: mainTable })), normalizedModel && (_jsx(Pagination, { normalizedModel: normalizedModel, prePagingNumRows: sortedRows.length, containerDivClasses: unwrappedAdditionalStyleModel.paginationUiDiv }))] })] }));
|
|
55
55
|
};
|
|
56
56
|
export default InternalGrid;
|
package/grid/main/BodyRows.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AugFormattedRow } from "../types";
|
|
1
|
+
import { AugFormattedRow, RowId } from "../types";
|
|
2
2
|
import { FC, ReactNode } from "react";
|
|
3
3
|
import { UseGridSelectionFnsHook } from "../pipeline/useGridSelectionFns";
|
|
4
4
|
import { UseUnwrappedGridStylesHook } from "../pipeline/useUnwrappedGridStyles";
|
|
@@ -16,6 +16,7 @@ interface BodyRowsProps {
|
|
|
16
16
|
getInputStrSubmitCallback: UseGetInputStrSubmitCallbackHook;
|
|
17
17
|
additionalColIndexOffset?: number;
|
|
18
18
|
renderPrefixCells?: (augFormattedRows: AugFormattedRow) => ReactNode;
|
|
19
|
+
additionalRowStyles?: (rowId: RowId, displayIndex: number) => string[];
|
|
19
20
|
}
|
|
20
21
|
declare const BodyRows: FC<BodyRowsProps>;
|
|
21
22
|
export default BodyRows;
|
package/grid/main/BodyRows.js
CHANGED
|
@@ -3,9 +3,9 @@ import EditableRow from "../editing/EditableRow";
|
|
|
3
3
|
import classNames from "classnames";
|
|
4
4
|
import getWidthStyle from "../util/getWidthStyle";
|
|
5
5
|
import SelectionInput from "../selection/SelectionInput";
|
|
6
|
-
const BodyRows = ({ augFormattedRows, gridSelectionFns: { selectedSet, getSelectInputModel, getSelectHandler, getRowClickHandler, getAriaSelectedValue, }, unwrappedStyles: { unwrappedTableModel }, combinedPipelineOutput: { showSelectCol, ariaColIndexOffset }, selectModel, editModel, getInputStrSubmitCallback, additionalColIndexOffset, renderPrefixCells, }) => augFormattedRows.map((row, index) => {
|
|
6
|
+
const BodyRows = ({ augFormattedRows, gridSelectionFns: { selectedSet, getSelectInputModel, getSelectHandler, getRowClickHandler, getAriaSelectedValue, }, unwrappedStyles: { unwrappedTableModel }, combinedPipelineOutput: { showSelectCol, ariaColIndexOffset }, selectModel, editModel, getInputStrSubmitCallback, additionalColIndexOffset, renderPrefixCells, additionalRowStyles, }) => augFormattedRows.map((row, index) => {
|
|
7
7
|
return (_jsxs(EditableRow, { onClick: getRowClickHandler(row.id), className: classNames({
|
|
8
8
|
"table-active": selectedSet.has(row.id),
|
|
9
|
-
}, unwrappedTableModel.tbodyTr(row.id, index)), "aria-rowindex": row.prePaginationIndex + 2, dataRowId: row.id, "aria-selected": getAriaSelectedValue(row.id), ariaColIndexOffset: ariaColIndexOffset + (additionalColIndexOffset || 0), cellData: row.contents, updateCallback: getInputStrSubmitCallback && getInputStrSubmitCallback(row.id), deleteCallback: (editModel === null || editModel === void 0 ? void 0 : editModel.getDeleteCallback) && editModel.getDeleteCallback(row.id), dataCellClasses: (colIndex) => unwrappedTableModel.tbodyTd(row.id, index, colIndex), dataCellInputClasses: (colIndex) => unwrappedTableModel.tbodyTdInput(row.id, index, colIndex), editCellClasses: unwrappedTableModel.editColTd(row.id, index), saveButtonClasses: unwrappedTableModel.editSaveButton(row.id, index), deleteButtonClasses: unwrappedTableModel.editDeleteButton(row.id, index), startButtonClasses: unwrappedTableModel.editStartButton(row.id, index), cancelButtonClasses: unwrappedTableModel.editCancelButton(row.id, index), children: [renderPrefixCells && renderPrefixCells(row), showSelectCol && (_jsx("td", { className: classNames(unwrappedTableModel.rowSelectColTd(row.id, index)), "aria-colindex": 1 + (additionalColIndexOffset || 0), style: getWidthStyle(selectModel.selectColWidth), children: _jsx(SelectionInput, { selected: selectedSet.has(row.id), selectionInputModel: getSelectInputModel(row.id, selectModel), selectCallback: getSelectHandler(row.id), additionalClasses: unwrappedTableModel.rowSelectInput(row.id, index) }) }))] }, row.id));
|
|
9
|
+
}, unwrappedTableModel.tbodyTr(row.id, index), additionalRowStyles ? additionalRowStyles(row.id, index) : []), "aria-rowindex": row.prePaginationIndex + 2, dataRowId: row.id, "aria-selected": getAriaSelectedValue(row.id), ariaColIndexOffset: ariaColIndexOffset + (additionalColIndexOffset || 0), cellData: row.contents, updateCallback: getInputStrSubmitCallback && getInputStrSubmitCallback(row.id), deleteCallback: (editModel === null || editModel === void 0 ? void 0 : editModel.getDeleteCallback) && editModel.getDeleteCallback(row.id), dataCellClasses: (colIndex) => unwrappedTableModel.tbodyTd(row.id, index, colIndex), dataCellInputClasses: (colIndex) => unwrappedTableModel.tbodyTdInput(row.id, index, colIndex), editCellClasses: unwrappedTableModel.editColTd(row.id, index), saveButtonClasses: unwrappedTableModel.editSaveButton(row.id, index), deleteButtonClasses: unwrappedTableModel.editDeleteButton(row.id, index), startButtonClasses: unwrappedTableModel.editStartButton(row.id, index), cancelButtonClasses: unwrappedTableModel.editCancelButton(row.id, index), children: [renderPrefixCells && renderPrefixCells(row), showSelectCol && (_jsx("td", { className: classNames(unwrappedTableModel.rowSelectColTd(row.id, index)), "aria-colindex": 1 + (additionalColIndexOffset || 0), style: getWidthStyle(selectModel.selectColWidth), children: _jsx(SelectionInput, { index: index, selected: selectedSet.has(row.id), selectionInputModel: getSelectInputModel(row.id, selectModel), selectCallback: getSelectHandler(row.id), additionalClasses: unwrappedTableModel.rowSelectInput(row.id, index) }) }))] }, row.id));
|
|
10
10
|
});
|
|
11
11
|
export default BodyRows;
|
|
@@ -49,6 +49,6 @@ const SelectAllHeaderCell = ({ onClick, selectionInfo, totalRows, additionalClas
|
|
|
49
49
|
}, [indeterminate]);
|
|
50
50
|
return (_jsx("th", { style: style, "aria-colindex": 1 + (colIndexOffset || 0), title: description, "aria-description": description, className: classNames({
|
|
51
51
|
"btn-primary": !additionalClasses || additionalClasses.length === 0,
|
|
52
|
-
}, additionalClasses || []), children: _jsx("input", { type: "checkbox", checked: checked, ref: ref, disabled: disabled, "aria-label": description, onChange: onClick }) }));
|
|
52
|
+
}, additionalClasses || []), children: _jsx("input", { tabIndex: 0, type: "checkbox", checked: checked, ref: ref, disabled: disabled, "aria-label": description, onChange: onClick }) }));
|
|
53
53
|
};
|
|
54
54
|
export default SelectAllHeaderCell;
|
|
@@ -14,6 +14,7 @@ export interface SelectionInputProps {
|
|
|
14
14
|
selectionInputModel: SelectionInputModel;
|
|
15
15
|
selectCallback: () => void;
|
|
16
16
|
additionalClasses?: string[];
|
|
17
|
+
index: number;
|
|
17
18
|
}
|
|
18
19
|
declare const SelectionInput: FC<SelectionInputProps>;
|
|
19
20
|
export default SelectionInput;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import classNames from "classnames";
|
|
3
|
-
const SelectionInput = ({ selectionInputModel, selected, selectCallback, additionalClasses, }) => {
|
|
3
|
+
const SelectionInput = ({ selectionInputModel, selected, selectCallback, additionalClasses, index, }) => {
|
|
4
4
|
const type = selectionInputModel.type;
|
|
5
5
|
const onChange = ({ target: { checked }, }) => {
|
|
6
6
|
// theoretically, a radio button shouldn't become unchecked so the below
|
|
@@ -14,7 +14,7 @@ const SelectionInput = ({ selectionInputModel, selected, selectCallback, additio
|
|
|
14
14
|
selectCallback();
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
|
-
return (_jsx("input", { className: classNames(additionalClasses || []), "aria-label":
|
|
17
|
+
return (_jsx("input", { tabIndex: 0, className: classNames(additionalClasses || []), "aria-label": `Select row with index ${index}`, onClick: (event) => {
|
|
18
18
|
event.stopPropagation();
|
|
19
19
|
}, type: type, checked: selected, onChange: onChange, name: selectionInputModel.name }));
|
|
20
20
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useMemo, useRef, } from "react";
|
|
4
4
|
import classNames from "classnames";
|
|
5
5
|
import getWidthStyle from "../grid/util/getWidthStyle";
|
|
@@ -22,6 +22,9 @@ const ColHeaderCellPro = ({ label, sortModel, ariaColIndex, additionalClasses, w
|
|
|
22
22
|
const effectiveMinResizeWidth = minResizeWidth || defaultMinResizeWidth;
|
|
23
23
|
const effectiveKbdResizeStep = keyboardResizeStep || 10;
|
|
24
24
|
const clickToSortCellContents = useMemo(() => {
|
|
25
|
+
if (!sortModel) {
|
|
26
|
+
return _jsx(_Fragment, { children: label });
|
|
27
|
+
}
|
|
25
28
|
if (!width || displayMode === "table") {
|
|
26
29
|
// Testing has shown that content gets cut off in a table cell only if
|
|
27
30
|
// the table "display" property is "block" and both "min-width" and
|
|
@@ -139,7 +142,7 @@ const ColHeaderCellPro = ({ label, sortModel, ariaColIndex, additionalClasses, w
|
|
|
139
142
|
"rbdg-sort-toggler": cellIsClickable,
|
|
140
143
|
"table-active": sortModel === null || sortModel === void 0 ? void 0 : sortModel.sortOrder,
|
|
141
144
|
}, additionalClasses || []), onClick: cellIsClickable ? handleClick : undefined, onMouseOver: cellIsClickable ? handleMouseOver : undefined, onMouseOut: cellIsClickable ? handleMouseOut : undefined, "aria-description": sortModel
|
|
142
|
-
? "Column header"
|
|
143
|
-
: "Column header
|
|
145
|
+
? "Column header that can be clicked to change the sorting mode"
|
|
146
|
+
: "Column header", "aria-colindex": ariaColIndex, "aria-sort": sortModel ? sortOrderToAriaSort(sortModel.sortOrder) : undefined, style: getWidthStyle(width), children: cellContents }));
|
|
144
147
|
};
|
|
145
148
|
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 { useCallback, useMemo } from "react";
|
|
3
|
+
import { useCallback, useEffect, useMemo } from "react";
|
|
4
4
|
import useCombinedPipeline from "../grid/pipeline/useCombinedPipeline";
|
|
5
5
|
import InternalGrid from "../grid/InternalGrid";
|
|
6
6
|
import ColHeaderCellPro from "./ColHeaderCellPro";
|
|
@@ -12,6 +12,9 @@ import useResizeModel from "./resize/useResizeModel";
|
|
|
12
12
|
import BodyRows from "../grid/main/BodyRows";
|
|
13
13
|
import ReorderHeaderCell from "./reorder/ReorderHeaderCell";
|
|
14
14
|
import ReorderHandleCell from "./reorder/ReorderHandleCell";
|
|
15
|
+
import useKeyboardReorder from "./reorder/useKeyboardReorder";
|
|
16
|
+
import useReorderStyles from "./reorder/useReorderStyles";
|
|
17
|
+
import useKeyboardReorderListener from "./reorder/useKeyboardReorderListener";
|
|
15
18
|
const GridPro = (props) => {
|
|
16
19
|
const { rows, cols, editModel, filterModel, sortModel, pagination, selectModel, styleModel, displayMode, reorder, } = props;
|
|
17
20
|
const combinedPipelineOutput = useCombinedPipeline({
|
|
@@ -32,6 +35,57 @@ const GridPro = (props) => {
|
|
|
32
35
|
return prev;
|
|
33
36
|
}, {}), [resizeModel]);
|
|
34
37
|
const augFormattedRows = useAugFormattedRows(colNameToWidth, displayRows);
|
|
38
|
+
const displayRowIds = useMemo(() => displayRows.map(({ id }) => id), [displayRows]);
|
|
39
|
+
const { drageeState, setDragee } = useKeyboardReorder(displayRowIds);
|
|
40
|
+
const reorderStyles = useReorderStyles(styleModel === null || styleModel === void 0 ? void 0 : styleModel.reorderModel);
|
|
41
|
+
const additionalBodyRowStyles = useCallback((id, displayIndex) => {
|
|
42
|
+
if (!drageeState) {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
const { rowId, drageeIndex, destIndex } = drageeState;
|
|
46
|
+
if (id === rowId) {
|
|
47
|
+
return reorderStyles.draggedRowClasses;
|
|
48
|
+
}
|
|
49
|
+
const isDraggedRowPred = drageeIndex > 0 && displayIndex === drageeIndex - 1;
|
|
50
|
+
const isTargetUpperNeighbor = destIndex > 0 && displayIndex === destIndex - 1;
|
|
51
|
+
const isTargetLowerNeighbor = destIndex === displayIndex;
|
|
52
|
+
if (isDraggedRowPred && isTargetLowerNeighbor) {
|
|
53
|
+
return reorderStyles.draggedRowPredecessorClasses.concat(reorderStyles.bottomBorderRowClasses);
|
|
54
|
+
}
|
|
55
|
+
if (isDraggedRowPred && !isTargetLowerNeighbor) {
|
|
56
|
+
return reorderStyles.draggedRowPredecessorClasses;
|
|
57
|
+
}
|
|
58
|
+
if (!isDraggedRowPred && isTargetLowerNeighbor) {
|
|
59
|
+
return reorderStyles.bottomBorderRowClasses;
|
|
60
|
+
}
|
|
61
|
+
if (isTargetUpperNeighbor) {
|
|
62
|
+
return reorderStyles.topBorderRowClasses;
|
|
63
|
+
}
|
|
64
|
+
return [];
|
|
65
|
+
}, [reorderStyles, drageeState]);
|
|
66
|
+
const additionalHeaderRowStyles = useMemo(() => {
|
|
67
|
+
if (!drageeState) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
if (drageeState.drageeIndex === 0) {
|
|
71
|
+
return reorderStyles.draggedRowPredecessorClasses;
|
|
72
|
+
}
|
|
73
|
+
if (drageeState.destIndex === 0) {
|
|
74
|
+
return reorderStyles.topBorderRowClasses;
|
|
75
|
+
}
|
|
76
|
+
return [];
|
|
77
|
+
}, [
|
|
78
|
+
drageeState,
|
|
79
|
+
reorderStyles.draggedRowPredecessorClasses,
|
|
80
|
+
reorderStyles.topBorderRowClasses,
|
|
81
|
+
]);
|
|
82
|
+
const tableOnKeydown = useKeyboardReorderListener(drageeState, reorder === null || reorder === void 0 ? void 0 : reorder.callback);
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
document.addEventListener("keydown", tableOnKeydown);
|
|
85
|
+
return () => {
|
|
86
|
+
document.removeEventListener("keydown", tableOnKeydown);
|
|
87
|
+
};
|
|
88
|
+
}, [tableOnKeydown]);
|
|
35
89
|
const colHeaderCells = cols.map(({ name, label, sortable, minResizeWidth, maxResizeWidth, keyboardResizeStep, }, index) => {
|
|
36
90
|
var _a;
|
|
37
91
|
const colSortModel = sortingEnabled && sortable
|
|
@@ -53,14 +107,24 @@ const GridPro = (props) => {
|
|
|
53
107
|
return null;
|
|
54
108
|
}
|
|
55
109
|
const reorderCallback = (destIndex) => reorder.callback(augRow.id, destIndex);
|
|
56
|
-
return (_jsx(ReorderHandleCell, { rowId: augRow.id, ariaRowIndex: augRow.prePaginationIndex + 2, disabled: filteringOccurring || sortingOccurring, reorderCallback: reorderCallback,
|
|
57
|
-
}, [
|
|
58
|
-
|
|
110
|
+
return (_jsx(ReorderHandleCell, { rowId: augRow.id, ariaRowIndex: augRow.prePaginationIndex + 2, disabled: filteringOccurring || sortingOccurring || displayRows.length <= 1, reorderCallback: reorderCallback, styles: reorderStyles, keyboardStartCallback: () => setDragee(augRow.id), suppressKeyboardClick: drageeState !== null }));
|
|
111
|
+
}, [
|
|
112
|
+
displayRows.length,
|
|
113
|
+
drageeState,
|
|
114
|
+
filteringOccurring,
|
|
115
|
+
reorder,
|
|
116
|
+
reorderStyles,
|
|
117
|
+
setDragee,
|
|
118
|
+
sortingOccurring,
|
|
119
|
+
]);
|
|
120
|
+
const bodyRows = (_jsx(BodyRows, { augFormattedRows: augFormattedRows, gridSelectionFns: gridSelectionFns, selectModel: selectModel, unwrappedStyles: unwrappedStyles, combinedPipelineOutput: combinedPipelineOutput, editModel: editModel, getInputStrSubmitCallback: getInputStrSubmitCallback, renderPrefixCells: renderPrefixCells, additionalColIndexOffset: reorder ? 1 : 0, additionalRowStyles: additionalBodyRowStyles }));
|
|
59
121
|
const prefixHeader = reorder ? _jsx(ReorderHeaderCell, {}) : null;
|
|
60
122
|
return (_jsx(InternalGrid, { gridProps: props, hooks: {
|
|
61
123
|
pipelineOutput: combinedPipelineOutput,
|
|
62
124
|
selectFns: gridSelectionFns,
|
|
63
125
|
unwrappedStyles,
|
|
64
|
-
}, slots: { colHeaderCells, bodyRows, prefixHeader }
|
|
126
|
+
}, slots: { colHeaderCells, bodyRows, prefixHeader }, classes: {
|
|
127
|
+
headerRow: additionalHeaderRowStyles,
|
|
128
|
+
} }));
|
|
65
129
|
};
|
|
66
130
|
export default GridPro;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { FC } from "react";
|
|
2
|
-
import { RowId } from "../";
|
|
3
|
-
import { ReorderStyleModel } from "./types";
|
|
2
|
+
import { ReorderStyles, RowId } from "../";
|
|
4
3
|
export type ReorderHandleCellProps = {
|
|
5
4
|
rowId: RowId;
|
|
6
5
|
ariaRowIndex: number;
|
|
7
6
|
reorderCallback: (destIndex: number) => void;
|
|
7
|
+
keyboardStartCallback: () => void;
|
|
8
8
|
disabled: boolean;
|
|
9
|
-
|
|
9
|
+
suppressKeyboardClick: boolean;
|
|
10
|
+
styles: ReorderStyles;
|
|
10
11
|
};
|
|
11
12
|
declare const ReorderHandleCell: FC<ReorderHandleCellProps>;
|
|
12
13
|
export default ReorderHandleCell;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback,
|
|
2
|
+
import { useCallback, } from "react";
|
|
3
3
|
import HorizontalGrip from "../assets/HorizontalGrip";
|
|
4
4
|
import regDragCleanup from "../util/regDragCleanup";
|
|
5
5
|
import classNames from "classnames";
|
|
@@ -12,16 +12,7 @@ function dropTargetRefValuesEqual(first, second) {
|
|
|
12
12
|
}
|
|
13
13
|
return first.index === second.index && first.upper === second.upper;
|
|
14
14
|
}
|
|
15
|
-
const ReorderHandleCell = ({ rowId, ariaRowIndex, disabled, reorderCallback,
|
|
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]);
|
|
15
|
+
const ReorderHandleCell = ({ rowId, ariaRowIndex, disabled, reorderCallback, styles: { draggedRowClasses, draggedRowPredecessorClasses, topBorderRowClasses, bottomBorderRowClasses, ghostDivClasses, }, keyboardStartCallback, suppressKeyboardClick, }) => {
|
|
25
16
|
const onPointerDown = useCallback((event) => {
|
|
26
17
|
const target = event.target;
|
|
27
18
|
const { pointerId, clientX, clientY, button } = event;
|
|
@@ -30,7 +21,7 @@ const ReorderHandleCell = ({ rowId, ariaRowIndex, disabled, reorderCallback, sty
|
|
|
30
21
|
}
|
|
31
22
|
function createDragGhost() {
|
|
32
23
|
const ghostDiv = document.createElement("div");
|
|
33
|
-
ghostDiv.className =
|
|
24
|
+
ghostDiv.className = ghostDivClasses.join(" ");
|
|
34
25
|
ghostDiv.style.left = `${clientX}px`;
|
|
35
26
|
ghostDiv.style.top = `${clientY}px`;
|
|
36
27
|
ghostDiv.textContent = `ID: ${rowId}`;
|
|
@@ -56,17 +47,17 @@ const ReorderHandleCell = ({ rowId, ariaRowIndex, disabled, reorderCallback, sty
|
|
|
56
47
|
.trim();
|
|
57
48
|
}
|
|
58
49
|
function applyDrageeStyles() {
|
|
59
|
-
applyRowClassesFromOrig(drageeTrIndex,
|
|
50
|
+
applyRowClassesFromOrig(drageeTrIndex, draggedRowClasses);
|
|
60
51
|
if (drageeTrIndex - 1 === -1) {
|
|
61
52
|
headTr.className = [
|
|
62
53
|
origHeadTrClasses,
|
|
63
|
-
|
|
54
|
+
draggedRowPredecessorClasses.join(" "),
|
|
64
55
|
]
|
|
65
56
|
.join(" ")
|
|
66
57
|
.trim();
|
|
67
58
|
return;
|
|
68
59
|
}
|
|
69
|
-
applyRowClassesFromOrig(drageeTrIndex - 1,
|
|
60
|
+
applyRowClassesFromOrig(drageeTrIndex - 1, draggedRowPredecessorClasses);
|
|
70
61
|
}
|
|
71
62
|
applyDrageeStyles();
|
|
72
63
|
const baseClassesByIndex = trs.map((tr) => tr.className);
|
|
@@ -129,24 +120,21 @@ const ReorderHandleCell = ({ rowId, ariaRowIndex, disabled, reorderCallback, sty
|
|
|
129
120
|
}
|
|
130
121
|
function applyDragStyles(trIndex, upper) {
|
|
131
122
|
if (upper) {
|
|
132
|
-
applyRowClassesFromBase(trIndex,
|
|
123
|
+
applyRowClassesFromBase(trIndex, bottomBorderRowClasses);
|
|
133
124
|
}
|
|
134
125
|
if (upper && trIndex - 1 >= 0) {
|
|
135
|
-
applyRowClassesFromBase(trIndex - 1,
|
|
126
|
+
applyRowClassesFromBase(trIndex - 1, topBorderRowClasses);
|
|
136
127
|
}
|
|
137
128
|
if (upper && trIndex - 1 === -1) {
|
|
138
|
-
headTr.className = [
|
|
139
|
-
baseHeadTrClasses,
|
|
140
|
-
intTopBorderRowClasses.join(" "),
|
|
141
|
-
]
|
|
129
|
+
headTr.className = [baseHeadTrClasses, topBorderRowClasses.join(" ")]
|
|
142
130
|
.join(" ")
|
|
143
131
|
.trim();
|
|
144
132
|
}
|
|
145
133
|
if (!upper) {
|
|
146
|
-
applyRowClassesFromBase(trIndex,
|
|
134
|
+
applyRowClassesFromBase(trIndex, topBorderRowClasses);
|
|
147
135
|
}
|
|
148
136
|
if (!upper && trIndex + 1 < trs.length) {
|
|
149
|
-
applyRowClassesFromBase(trIndex + 1,
|
|
137
|
+
applyRowClassesFromBase(trIndex + 1, bottomBorderRowClasses);
|
|
150
138
|
}
|
|
151
139
|
}
|
|
152
140
|
function updateRowStyles(currentDropTargetVal) {
|
|
@@ -204,16 +192,27 @@ const ReorderHandleCell = ({ rowId, ariaRowIndex, disabled, reorderCallback, sty
|
|
|
204
192
|
onContextMenu,
|
|
205
193
|
});
|
|
206
194
|
}, [
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
195
|
+
bottomBorderRowClasses,
|
|
196
|
+
draggedRowClasses,
|
|
197
|
+
draggedRowPredecessorClasses,
|
|
198
|
+
ghostDivClasses,
|
|
199
|
+
topBorderRowClasses,
|
|
212
200
|
reorderCallback,
|
|
213
201
|
rowId,
|
|
214
202
|
]);
|
|
215
203
|
const label = `Reorder Row ${ariaRowIndex}`;
|
|
216
|
-
|
|
204
|
+
const onClick = (event) => {
|
|
205
|
+
event.stopPropagation();
|
|
206
|
+
if (event.detail === 0) {
|
|
207
|
+
keyboardStartCallback();
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
const onKeydown = (event) => {
|
|
211
|
+
if (suppressKeyboardClick) {
|
|
212
|
+
event.preventDefault();
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
return (_jsx("th", { "aria-colindex": 1, children: _jsx("button", { tabIndex: 0, onClick: onClick, "aria-label": label, title: label, onPointerDown: onPointerDown, onKeyDown: onKeydown, className: classNames("rbdg-draggable-container", "rbdg-reorder-container", "rbdg-plain-icon-button", {
|
|
217
216
|
"bs-btn-disabled": disabled,
|
|
218
217
|
}), disabled: disabled, children: _jsx(HorizontalGrip, { className: "rbdg-draggable-icon" }) }) }));
|
|
219
218
|
};
|
|
@@ -10,3 +10,18 @@ export interface ReorderStyleModel {
|
|
|
10
10
|
bottomBorderRowClasses?: string[];
|
|
11
11
|
ghostDivClasses?: string[];
|
|
12
12
|
}
|
|
13
|
+
export type ReorderStyles = Required<ReorderStyleModel>;
|
|
14
|
+
export interface KeyboardReorderState {
|
|
15
|
+
rowId: RowId;
|
|
16
|
+
destIndex: number;
|
|
17
|
+
}
|
|
18
|
+
export type ActiveKeyboardReorderState = KeyboardReorderState & {
|
|
19
|
+
moveToPrevTarget: () => void;
|
|
20
|
+
moveToNextTarget: () => void;
|
|
21
|
+
clearState: () => void;
|
|
22
|
+
drageeIndex: number;
|
|
23
|
+
};
|
|
24
|
+
export interface UseKeyboardReorderOutput {
|
|
25
|
+
drageeState: ActiveKeyboardReorderState | null;
|
|
26
|
+
setDragee: (rowId: RowId) => void;
|
|
27
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { useCallback, useMemo, useState } from "react";
|
|
2
|
+
import trueModulo from "../../grid/util/trueModulo";
|
|
3
|
+
const useKeyboardReorder = (displayRowIds) => {
|
|
4
|
+
const [state, setState] = useState(null);
|
|
5
|
+
// A change the displayed rows can suddenly make the existing state invalid.
|
|
6
|
+
// To cope with this possibility, the hook checks the validity of the state on
|
|
7
|
+
// each render and defaults to null when the state is invalid.
|
|
8
|
+
// Consumers of the hook can then call setState (generally via user
|
|
9
|
+
// interaction) to set the state back to a valid value.
|
|
10
|
+
const effectiveState = useMemo(() => {
|
|
11
|
+
if (displayRowIds.length <= 1 || state === null) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const drageeIndex = displayRowIds.findIndex((id) => state.rowId === id);
|
|
15
|
+
if (drageeIndex < 0) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
if (drageeIndex === state.destIndex ||
|
|
19
|
+
drageeIndex + 1 === state.destIndex) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return state;
|
|
23
|
+
}, [displayRowIds, state]);
|
|
24
|
+
const setDragee = useCallback((rowId) => {
|
|
25
|
+
const foundIndex = displayRowIds.findIndex((id) => rowId === id);
|
|
26
|
+
if (foundIndex < 0) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// Shouldn't happen under normal circumstances dye to the button being
|
|
30
|
+
// disabled in the UI. Not sure if some sort of
|
|
31
|
+
// race condition is possible with React to get this situation to occur.
|
|
32
|
+
if (displayRowIds.length < 2) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (foundIndex + 2 > displayRowIds.length) {
|
|
36
|
+
setState({
|
|
37
|
+
rowId,
|
|
38
|
+
destIndex: foundIndex - 1,
|
|
39
|
+
});
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
setState({
|
|
43
|
+
rowId,
|
|
44
|
+
destIndex: foundIndex + 2,
|
|
45
|
+
});
|
|
46
|
+
}, [displayRowIds]);
|
|
47
|
+
const output = useMemo(() => {
|
|
48
|
+
if (effectiveState === null) {
|
|
49
|
+
return {
|
|
50
|
+
drageeState: null,
|
|
51
|
+
setDragee,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const moveToPrevTarget = () => {
|
|
55
|
+
let newIndex = trueModulo(effectiveState.destIndex - 1, displayRowIds.length + 1);
|
|
56
|
+
const foundIndex = displayRowIds.findIndex((id) => effectiveState.rowId === id);
|
|
57
|
+
if (newIndex === foundIndex + 1) {
|
|
58
|
+
newIndex = trueModulo(newIndex - 2, displayRowIds.length + 1);
|
|
59
|
+
}
|
|
60
|
+
setState({
|
|
61
|
+
rowId: effectiveState.rowId,
|
|
62
|
+
destIndex: newIndex,
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
const moveToNextTarget = () => {
|
|
66
|
+
let newIndex = trueModulo(effectiveState.destIndex + 1, displayRowIds.length + 1);
|
|
67
|
+
const foundIndex = displayRowIds.findIndex((id) => effectiveState.rowId === id);
|
|
68
|
+
if (newIndex === foundIndex) {
|
|
69
|
+
newIndex = trueModulo(newIndex + 2, displayRowIds.length + 1);
|
|
70
|
+
}
|
|
71
|
+
setState({
|
|
72
|
+
rowId: effectiveState.rowId,
|
|
73
|
+
destIndex: newIndex,
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
return {
|
|
77
|
+
drageeState: Object.assign(Object.assign({}, effectiveState), { moveToPrevTarget,
|
|
78
|
+
moveToNextTarget, clearState: () => setState(null), drageeIndex: displayRowIds.findIndex((id) => effectiveState.rowId === id) }),
|
|
79
|
+
setDragee,
|
|
80
|
+
};
|
|
81
|
+
}, [displayRowIds, effectiveState, setDragee]);
|
|
82
|
+
return output;
|
|
83
|
+
};
|
|
84
|
+
export default useKeyboardReorder;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { ActiveKeyboardReorderState, ReorderCallback } from "./types";
|
|
2
|
+
declare const useKeyboardReorderListener: (state: ActiveKeyboardReorderState | null, reorderCallback: ReorderCallback | undefined) => (event: KeyboardEvent) => void;
|
|
3
|
+
export default useKeyboardReorderListener;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
const useKeyboardReorderListener = (state, reorderCallback) => {
|
|
3
|
+
return useCallback((event) => {
|
|
4
|
+
if (state === null || reorderCallback === undefined) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
const { moveToPrevTarget, moveToNextTarget, clearState, rowId, destIndex, } = state;
|
|
8
|
+
if (event.key === "ArrowUp") {
|
|
9
|
+
moveToPrevTarget();
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (event.key === "ArrowDown") {
|
|
13
|
+
moveToNextTarget();
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (event.key === " " || event.key === "Enter") {
|
|
17
|
+
reorderCallback(rowId, destIndex);
|
|
18
|
+
clearState();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (event.key === "Escape") {
|
|
22
|
+
clearState();
|
|
23
|
+
}
|
|
24
|
+
}, [reorderCallback, state]);
|
|
25
|
+
};
|
|
26
|
+
export default useKeyboardReorderListener;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
const useReorderStyles = (styleModel) => {
|
|
3
|
+
const draggedRowClasses = useMemo(() => (styleModel === null || styleModel === void 0 ? void 0 : styleModel.draggedRowClasses) || ["rbdg-reorder-dragged-row"], [styleModel === null || styleModel === void 0 ? void 0 : styleModel.draggedRowClasses]);
|
|
4
|
+
const draggedRowPredecessorClasses = useMemo(() => (styleModel === null || styleModel === void 0 ? void 0 : styleModel.draggedRowPredecessorClasses) || [
|
|
5
|
+
"rbdg-reorder-dragged-row-pred",
|
|
6
|
+
], [styleModel === null || styleModel === void 0 ? void 0 : styleModel.draggedRowPredecessorClasses]);
|
|
7
|
+
const topBorderRowClasses = 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]);
|
|
8
|
+
const bottomBorderRowClasses = useMemo(() => (styleModel === null || styleModel === void 0 ? void 0 : styleModel.bottomBorderRowClasses) || [
|
|
9
|
+
"rbdg-reorder-below-drag-target-row",
|
|
10
|
+
], [styleModel === null || styleModel === void 0 ? void 0 : styleModel.bottomBorderRowClasses]);
|
|
11
|
+
const ghostDivClasses = useMemo(() => (styleModel === null || styleModel === void 0 ? void 0 : styleModel.ghostDivClasses) || ["border", "rbdg-drag-ghost"], [styleModel === null || styleModel === void 0 ? void 0 : styleModel.ghostDivClasses]);
|
|
12
|
+
return {
|
|
13
|
+
draggedRowClasses,
|
|
14
|
+
draggedRowPredecessorClasses,
|
|
15
|
+
topBorderRowClasses,
|
|
16
|
+
bottomBorderRowClasses,
|
|
17
|
+
ghostDivClasses,
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export default useReorderStyles;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@absreim/react-bootstrap-data-grid-pro",
|
|
3
3
|
"description": "Pro Version of data grid UI component for use with web apps using React and Bootstrap",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.7.0",
|
|
5
5
|
"license": "Commercial. See LICENSE file.",
|
|
6
6
|
"author": "Brook Li",
|
|
7
7
|
"homepage": "https://react-bootstrap-data-grid.vercel.app/",
|