@absreim/react-bootstrap-data-grid-pro 2.6.1 → 3.0.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 +1 -4
- package/grid/InternalGrid.d.ts +3 -2
- package/grid/InternalGrid.js +31 -29
- package/grid/editing/EditControlsCell.d.ts +5 -5
- package/grid/editing/EditControlsCell.js +1 -9
- package/grid/editing/EditableRow.d.ts +7 -7
- package/grid/editing/EditableRow.js +1 -1
- package/grid/export/ExportForm.d.ts +1 -0
- package/grid/export/ExportForm.js +3 -3
- package/grid/filtering/DateFilterRow.d.ts +4 -4
- package/grid/filtering/DateFilterRow.js +1 -1
- package/grid/filtering/FilterOptionsTable.d.ts +1 -0
- package/grid/filtering/FilterOptionsTable.js +14 -8
- package/grid/filtering/FilterRow.d.ts +4 -4
- package/grid/filtering/FilterRow.js +1 -1
- package/grid/filtering/NumberFilterRow.d.ts +3 -3
- package/grid/filtering/NumberFilterRow.js +1 -1
- package/grid/filtering/StringFilterRow.d.ts +3 -3
- package/grid/filtering/StringFilterRow.js +1 -1
- package/grid/main/BodyRows.d.ts +4 -3
- package/grid/main/BodyRows.js +18 -2
- package/grid/pagination/Pagination.d.ts +1 -1
- package/grid/pagination/Pagination.js +6 -3
- package/grid/pagination/types.d.ts +1 -1
- package/grid/pipeline/useCombinedPipeline/useCurrentPageRows.d.ts +2 -2
- package/grid/selection/SelectAllHeaderCell.d.ts +1 -1
- package/grid/selection/SelectAllHeaderCell.js +2 -4
- package/grid/selection/SelectionInput.d.ts +2 -1
- package/grid/selection/SelectionInput.js +2 -2
- package/grid/styling/types.d.ts +20 -21
- package/grid/toolbar/ToolbarContainer.d.ts +2 -2
- package/grid/toolbar/ToolbarContainer.js +11 -7
- package/grid/toolbar/types.d.ts +8 -0
- package/grid/toolbar/useInterfaces.d.ts +2 -8
- package/grid/toolbar/useInterfaces.js +9 -5
- package/grid/types.d.ts +5 -6
- package/grid/util/trueModulo.d.ts +2 -0
- package/grid/util/trueModulo.js +2 -0
- package/grid-pro/GridPro.js +69 -8
- 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/main/ToggleButton.d.ts +0 -9
- package/grid/main/ToggleButton.js +0 -13
- package/grid/pipeline/useUnwrappedGridStyles.d.ts +0 -7
- package/grid/pipeline/useUnwrappedGridStyles.js +0 -15
- package/grid/styling/styleModelUnwrappers.d.ts +0 -4
- package/grid/styling/styleModelUnwrappers.js +0 -47
|
@@ -40,15 +40,13 @@ const getCheckboxState = (selectionInfo, noRows) => {
|
|
|
40
40
|
// single select mode and none selected
|
|
41
41
|
return disabledState;
|
|
42
42
|
};
|
|
43
|
-
const SelectAllHeaderCell = ({ onClick, selectionInfo, totalRows,
|
|
43
|
+
const SelectAllHeaderCell = ({ onClick, selectionInfo, totalRows, customClasses, style, colIndexOffset, }) => {
|
|
44
44
|
const noRows = totalRows === 0;
|
|
45
45
|
const { indeterminate, checked, disabled, description } = getCheckboxState(selectionInfo, noRows);
|
|
46
46
|
const ref = useRef(null);
|
|
47
47
|
useEffect(() => {
|
|
48
48
|
ref.current.indeterminate = indeterminate;
|
|
49
49
|
}, [indeterminate]);
|
|
50
|
-
return (_jsx("th", { style: style, "aria-colindex": 1 + (colIndexOffset || 0), title: description, "aria-description": description, className: classNames({
|
|
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 }) }));
|
|
50
|
+
return (_jsx("th", { style: style, "aria-colindex": 1 + (colIndexOffset || 0), title: description, "aria-description": description, className: classNames(customClasses || "btn-primary"), children: _jsx("input", { tabIndex: 0, type: "checkbox", checked: checked, ref: ref, disabled: disabled, "aria-label": description, onChange: onClick }) }));
|
|
53
51
|
};
|
|
54
52
|
export default SelectAllHeaderCell;
|
|
@@ -13,7 +13,8 @@ export interface SelectionInputProps {
|
|
|
13
13
|
selected: boolean;
|
|
14
14
|
selectionInputModel: SelectionInputModel;
|
|
15
15
|
selectCallback: () => void;
|
|
16
|
-
additionalClasses?: string[];
|
|
16
|
+
additionalClasses?: string[] | null;
|
|
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
|
};
|
package/grid/styling/types.d.ts
CHANGED
|
@@ -4,40 +4,39 @@ export interface SharedTableStyleModel {
|
|
|
4
4
|
tbody?: string[];
|
|
5
5
|
thead?: string[];
|
|
6
6
|
theadTr?: string[];
|
|
7
|
-
theadTh?: (colIndex: number) => string[];
|
|
7
|
+
theadTh?: (colIndex: number) => string[] | null;
|
|
8
8
|
caption?: string[];
|
|
9
9
|
}
|
|
10
10
|
export type TableStyleModel = SharedTableStyleModel & {
|
|
11
|
-
tbodyTr?: (rowId: RowId, displayIndex: number) => string[];
|
|
12
|
-
tbodyTd?: (rowId: RowId, displayRowIndex: number, colIndex: number) => string[];
|
|
13
|
-
tbodyTdInput?: (rowId: RowId, displayRowIndex: number, colIndex: number) => string[];
|
|
11
|
+
tbodyTr?: (rowId: RowId, displayIndex: number) => string[] | null;
|
|
12
|
+
tbodyTd?: (rowId: RowId, displayRowIndex: number, colIndex: number) => string[] | null;
|
|
13
|
+
tbodyTdInput?: (rowId: RowId, displayRowIndex: number, colIndex: number) => string[] | null;
|
|
14
14
|
editColTh?: string[];
|
|
15
|
-
editColTd?: (rowId: RowId, displayIndex: number) => string[];
|
|
16
|
-
editStartButton?: (rowId: RowId, displayIndex: number) => string[];
|
|
17
|
-
editDeleteButton?: (rowId: RowId, displayIndex: number) => string[];
|
|
18
|
-
editSaveButton?: (rowId: RowId, displayIndex: number) => string[];
|
|
19
|
-
editCancelButton?: (rowId: RowId, displayIndex: number) => string[];
|
|
15
|
+
editColTd?: (rowId: RowId, displayIndex: number) => string[] | null;
|
|
16
|
+
editStartButton?: (rowId: RowId, displayIndex: number) => string[] | null;
|
|
17
|
+
editDeleteButton?: (rowId: RowId, displayIndex: number) => string[] | null;
|
|
18
|
+
editSaveButton?: (rowId: RowId, displayIndex: number) => string[] | null;
|
|
19
|
+
editCancelButton?: (rowId: RowId, displayIndex: number) => string[] | null;
|
|
20
20
|
rowSelectColTh?: string[];
|
|
21
|
-
rowSelectColTd?: (rowId: RowId, displayIndex: number) => string[];
|
|
22
|
-
rowSelectInput?: (rowId: RowId, displayIndex: number) => string[];
|
|
21
|
+
rowSelectColTd?: (rowId: RowId, displayIndex: number) => string[] | null;
|
|
22
|
+
rowSelectInput?: (rowId: RowId, displayIndex: number) => string[] | null;
|
|
23
23
|
};
|
|
24
24
|
export type FilterInputTableStyleModel = SharedTableStyleModel & {
|
|
25
|
-
tbodyTr?: (rowIndex: number) => string[];
|
|
26
|
-
tbodyTd?: (rowIndex: number, colIndex: number) => string[];
|
|
27
|
-
enablementInput?: (rowIndex: number) => string[];
|
|
28
|
-
schemeSelectionInput?: (rowIndex: number) => string[];
|
|
29
|
-
searchStringInput?: (rowIndex: number) => string[];
|
|
30
|
-
numberInput?: (rowIndex: number) => string[];
|
|
31
|
-
startDateInput?: (rowIndex: number) => string[];
|
|
32
|
-
endDateInput?: (rowIndex: number) => string[];
|
|
25
|
+
tbodyTr?: (rowIndex: number) => string[] | null;
|
|
26
|
+
tbodyTd?: (rowIndex: number, colIndex: number) => string[] | null;
|
|
27
|
+
enablementInput?: (rowIndex: number) => string[] | null;
|
|
28
|
+
schemeSelectionInput?: (rowIndex: number) => string[] | null;
|
|
29
|
+
searchStringInput?: (rowIndex: number) => string[] | null;
|
|
30
|
+
numberInput?: (rowIndex: number) => string[] | null;
|
|
31
|
+
startDateInput?: (rowIndex: number) => string[] | null;
|
|
32
|
+
endDateInput?: (rowIndex: number) => string[] | null;
|
|
33
33
|
submitButton?: string[];
|
|
34
34
|
form?: string[];
|
|
35
35
|
};
|
|
36
36
|
export interface AdditionalComponentsStyleModel {
|
|
37
37
|
topLevelDiv?: string[];
|
|
38
|
-
filterInputsDiv?: string[];
|
|
39
38
|
tableAndPaginationDiv?: string[];
|
|
40
|
-
|
|
39
|
+
tableDiv?: string[];
|
|
41
40
|
paginationUiDiv?: string[];
|
|
42
41
|
}
|
|
43
42
|
export interface ToolbarStyleModel {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { InterfaceNodeGenerator } from "./types";
|
|
2
2
|
import { FC } from "react";
|
|
3
3
|
import { ToolbarStyleModel } from "../styling/types";
|
|
4
4
|
interface ToolbarContainerProps {
|
|
5
|
-
|
|
5
|
+
interfaceGen: InterfaceNodeGenerator;
|
|
6
6
|
styleModel?: ToolbarStyleModel;
|
|
7
7
|
}
|
|
8
8
|
declare const ToolbarContainer: FC<ToolbarContainerProps>;
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
2
|
+
import { useCallback, useMemo, useState } from "react";
|
|
3
3
|
import Toolbar from "./Toolbar";
|
|
4
4
|
import classNames from "classnames";
|
|
5
|
-
const ToolbarContainer = ({
|
|
5
|
+
const ToolbarContainer = ({ interfaceGen, styleModel, }) => {
|
|
6
6
|
const [option, setOption] = useState(null);
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return prev
|
|
11
|
-
|
|
7
|
+
const closeUiCallback = useCallback(() => setOption(null), []);
|
|
8
|
+
const interfaces = useMemo(() => interfaceGen(closeUiCallback), [closeUiCallback, interfaceGen]);
|
|
9
|
+
const enabledFeatures = useMemo(() => {
|
|
10
|
+
return Object.keys(interfaces).reduce((prev, toolbarOption) => {
|
|
11
|
+
prev[toolbarOption] =
|
|
12
|
+
!!interfaces[toolbarOption];
|
|
13
|
+
return prev;
|
|
14
|
+
}, {});
|
|
15
|
+
}, [interfaces]);
|
|
12
16
|
return (_jsxs("div", { className: "vstack", "data-testid": "toolbar container", children: [_jsx(Toolbar, { enabledFeatures: enabledFeatures, option: option, setOption: setOption, toolbarClasses: styleModel === null || styleModel === void 0 ? void 0 : styleModel.toolbar, activeClasses: styleModel === null || styleModel === void 0 ? void 0 : styleModel.activeButton, inactiveClasses: styleModel === null || styleModel === void 0 ? void 0 : styleModel.inactiveButton }), _jsx("div", { className: "position-relative", children: option !== null && (_jsx("div", { "data-testid": "toolbar feature interface content container", className: classNames((styleModel === null || styleModel === void 0 ? void 0 : styleModel.interfaceContainer) || [
|
|
13
17
|
"position-absolute",
|
|
14
18
|
"z-1",
|
package/grid/toolbar/types.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
+
import { FilterOptionsTableProps } from "../filtering/FilterOptionsTable";
|
|
3
|
+
import { ExportFormProps } from "../export/ExportForm";
|
|
2
4
|
export type ToolbarOption = "filtering" | "exporting";
|
|
3
5
|
export type ToolbarInterfaces = Partial<Record<ToolbarOption, ReactNode>>;
|
|
6
|
+
export interface InterfaceParams {
|
|
7
|
+
filtering?: FilterOptionsTableProps;
|
|
8
|
+
exporting?: ExportFormProps;
|
|
9
|
+
}
|
|
10
|
+
export type InterfacePropGenerator = (closeUiCallback: () => void) => InterfaceParams;
|
|
11
|
+
export type InterfaceNodeGenerator = (closeUiCallback: () => void) => ToolbarInterfaces;
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { ExportFormProps } from "../export/ExportForm";
|
|
4
|
-
export interface InterfaceParams {
|
|
5
|
-
filtering?: FilterOptionsTableProps;
|
|
6
|
-
exporting?: ExportFormProps;
|
|
7
|
-
}
|
|
8
|
-
declare const useInterfaces: (params: InterfaceParams) => ToolbarInterfaces;
|
|
1
|
+
import { InterfacePropGenerator, ToolbarInterfaces } from "./types";
|
|
2
|
+
declare const useInterfaces: (gen: InterfacePropGenerator) => (closeCallback: () => void) => ToolbarInterfaces;
|
|
9
3
|
export default useInterfaces;
|
|
@@ -2,10 +2,14 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import FilterOptionsTable from "../filtering/FilterOptionsTable";
|
|
3
3
|
import { useMemo } from "react";
|
|
4
4
|
import ExportForm from "../export/ExportForm";
|
|
5
|
-
const useInterfaces = (
|
|
6
|
-
return useMemo(() => ({
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
const useInterfaces = (gen) => {
|
|
6
|
+
return useMemo(() => (closeCallback) => {
|
|
7
|
+
const props = gen(closeCallback);
|
|
8
|
+
const { exporting, filtering } = props;
|
|
9
|
+
return {
|
|
10
|
+
filtering: filtering ? (_jsx(FilterOptionsTable, Object.assign({}, filtering))) : undefined,
|
|
11
|
+
exporting: exporting ? _jsx(ExportForm, Object.assign({}, exporting)) : undefined,
|
|
12
|
+
};
|
|
13
|
+
}, [gen]);
|
|
10
14
|
};
|
|
11
15
|
export default useInterfaces;
|
package/grid/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CellData, EditModel } from "./editing/types";
|
|
2
|
-
import {
|
|
2
|
+
import { PaginationModel } from "./pagination/types";
|
|
3
3
|
import { ColSortModel, TableSortModel } from "./sorting/types";
|
|
4
4
|
import { FilterModel } from "./filtering/types";
|
|
5
5
|
import { SelectModel } from "./selection/types";
|
|
@@ -26,7 +26,7 @@ export interface RowDef<Data extends ValidRowData = ValidRowData> {
|
|
|
26
26
|
export type AugRowDef<Data extends ValidRowData = ValidRowData> = RowDef<Data> & {
|
|
27
27
|
origIndex: number;
|
|
28
28
|
};
|
|
29
|
-
export type PostPaginationRowDef<Data extends ValidRowData = ValidRowData> = AugRowDef & {
|
|
29
|
+
export type PostPaginationRowDef<Data extends ValidRowData = ValidRowData> = AugRowDef<Data> & {
|
|
30
30
|
prePaginationIndex: number;
|
|
31
31
|
};
|
|
32
32
|
export type FormattedRow = {
|
|
@@ -44,16 +44,15 @@ export type DisplayMode = "table" | "block";
|
|
|
44
44
|
export interface GridProps {
|
|
45
45
|
rows: RowDef[];
|
|
46
46
|
cols: ColDef[];
|
|
47
|
-
pagination?:
|
|
47
|
+
pagination?: PaginationModel;
|
|
48
48
|
sortModel?: TableSortModel;
|
|
49
49
|
filterModel?: FilterModel;
|
|
50
50
|
selectModel?: SelectModel;
|
|
51
51
|
editModel?: EditModel;
|
|
52
52
|
caption?: string;
|
|
53
53
|
styleModel?: StyleModel;
|
|
54
|
-
useToolbar?: boolean;
|
|
55
|
-
responsive?: boolean;
|
|
56
54
|
displayMode?: DisplayMode;
|
|
55
|
+
allowExport?: boolean;
|
|
57
56
|
}
|
|
58
57
|
export type BaseGridProps = Omit<GridProps, "cols"> & {
|
|
59
58
|
cols: ColDefBase[];
|
|
@@ -62,6 +61,6 @@ export interface ColHeaderCellProps {
|
|
|
62
61
|
label: string;
|
|
63
62
|
sortModel?: ColSortModel;
|
|
64
63
|
ariaColIndex: number;
|
|
65
|
-
additionalClasses?: string[];
|
|
64
|
+
additionalClasses?: string[] | null;
|
|
66
65
|
width?: number;
|
|
67
66
|
}
|
package/grid-pro/GridPro.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
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";
|
|
7
7
|
import useGridSelectionFns from "../grid/pipeline/useGridSelectionFns";
|
|
8
|
-
import useUnwrappedGridStyles from "../grid/pipeline/useUnwrappedGridStyles";
|
|
9
8
|
import useGetInputStrSubmitCallback from "../grid/pipeline/useGetInputStrSubmitCallback";
|
|
10
9
|
import useAugFormattedRows from "../grid/pipeline/useAugFormattedRows";
|
|
11
10
|
import useResizeModel from "./resize/useResizeModel";
|
|
12
11
|
import BodyRows from "../grid/main/BodyRows";
|
|
13
12
|
import ReorderHeaderCell from "./reorder/ReorderHeaderCell";
|
|
14
13
|
import ReorderHandleCell from "./reorder/ReorderHandleCell";
|
|
14
|
+
import useKeyboardReorder from "./reorder/useKeyboardReorder";
|
|
15
|
+
import useReorderStyles from "./reorder/useReorderStyles";
|
|
16
|
+
import useKeyboardReorderListener from "./reorder/useKeyboardReorderListener";
|
|
15
17
|
const GridPro = (props) => {
|
|
16
18
|
const { rows, cols, editModel, filterModel, sortModel, pagination, selectModel, styleModel, displayMode, reorder, } = props;
|
|
17
19
|
const combinedPipelineOutput = useCombinedPipeline({
|
|
@@ -24,7 +26,6 @@ const GridPro = (props) => {
|
|
|
24
26
|
});
|
|
25
27
|
const { sortedRowsOutput: { sortColDef, setSortColDef, sortingEnabled }, showSelectCol, displayRows, filterState, } = combinedPipelineOutput;
|
|
26
28
|
const gridSelectionFns = useGridSelectionFns(selectModel, rows);
|
|
27
|
-
const unwrappedStyles = useUnwrappedGridStyles(styleModel);
|
|
28
29
|
const getInputStrSubmitCallback = useGetInputStrSubmitCallback(editModel, cols);
|
|
29
30
|
const resizeModel = useResizeModel(cols, displayMode);
|
|
30
31
|
const colNameToWidth = useMemo(() => Object.keys(resizeModel).reduce((prev, fieldName) => {
|
|
@@ -32,6 +33,57 @@ const GridPro = (props) => {
|
|
|
32
33
|
return prev;
|
|
33
34
|
}, {}), [resizeModel]);
|
|
34
35
|
const augFormattedRows = useAugFormattedRows(colNameToWidth, displayRows);
|
|
36
|
+
const displayRowIds = useMemo(() => displayRows.map(({ id }) => id), [displayRows]);
|
|
37
|
+
const { drageeState, setDragee } = useKeyboardReorder(displayRowIds);
|
|
38
|
+
const reorderStyles = useReorderStyles(styleModel === null || styleModel === void 0 ? void 0 : styleModel.reorderModel);
|
|
39
|
+
const additionalBodyRowStyles = useCallback((id, displayIndex) => {
|
|
40
|
+
if (!drageeState) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
const { rowId, drageeIndex, destIndex } = drageeState;
|
|
44
|
+
if (id === rowId) {
|
|
45
|
+
return reorderStyles.draggedRowClasses;
|
|
46
|
+
}
|
|
47
|
+
const isDraggedRowPred = drageeIndex > 0 && displayIndex === drageeIndex - 1;
|
|
48
|
+
const isTargetUpperNeighbor = destIndex > 0 && displayIndex === destIndex - 1;
|
|
49
|
+
const isTargetLowerNeighbor = destIndex === displayIndex;
|
|
50
|
+
if (isDraggedRowPred && isTargetLowerNeighbor) {
|
|
51
|
+
return reorderStyles.draggedRowPredecessorClasses.concat(reorderStyles.bottomBorderRowClasses);
|
|
52
|
+
}
|
|
53
|
+
if (isDraggedRowPred && !isTargetLowerNeighbor) {
|
|
54
|
+
return reorderStyles.draggedRowPredecessorClasses;
|
|
55
|
+
}
|
|
56
|
+
if (!isDraggedRowPred && isTargetLowerNeighbor) {
|
|
57
|
+
return reorderStyles.bottomBorderRowClasses;
|
|
58
|
+
}
|
|
59
|
+
if (isTargetUpperNeighbor) {
|
|
60
|
+
return reorderStyles.topBorderRowClasses;
|
|
61
|
+
}
|
|
62
|
+
return [];
|
|
63
|
+
}, [reorderStyles, drageeState]);
|
|
64
|
+
const additionalHeaderRowStyles = useMemo(() => {
|
|
65
|
+
if (!drageeState) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
if (drageeState.drageeIndex === 0) {
|
|
69
|
+
return reorderStyles.draggedRowPredecessorClasses;
|
|
70
|
+
}
|
|
71
|
+
if (drageeState.destIndex === 0) {
|
|
72
|
+
return reorderStyles.topBorderRowClasses;
|
|
73
|
+
}
|
|
74
|
+
return [];
|
|
75
|
+
}, [
|
|
76
|
+
drageeState,
|
|
77
|
+
reorderStyles.draggedRowPredecessorClasses,
|
|
78
|
+
reorderStyles.topBorderRowClasses,
|
|
79
|
+
]);
|
|
80
|
+
const tableOnKeydown = useKeyboardReorderListener(drageeState, reorder === null || reorder === void 0 ? void 0 : reorder.callback);
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
document.addEventListener("keydown", tableOnKeydown);
|
|
83
|
+
return () => {
|
|
84
|
+
document.removeEventListener("keydown", tableOnKeydown);
|
|
85
|
+
};
|
|
86
|
+
}, [tableOnKeydown]);
|
|
35
87
|
const colHeaderCells = cols.map(({ name, label, sortable, minResizeWidth, maxResizeWidth, keyboardResizeStep, }, index) => {
|
|
36
88
|
var _a;
|
|
37
89
|
const colSortModel = sortingEnabled && sortable
|
|
@@ -53,14 +105,23 @@ const GridPro = (props) => {
|
|
|
53
105
|
return null;
|
|
54
106
|
}
|
|
55
107
|
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
|
-
|
|
108
|
+
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 }));
|
|
109
|
+
}, [
|
|
110
|
+
displayRows.length,
|
|
111
|
+
drageeState,
|
|
112
|
+
filteringOccurring,
|
|
113
|
+
reorder,
|
|
114
|
+
reorderStyles,
|
|
115
|
+
setDragee,
|
|
116
|
+
sortingOccurring,
|
|
117
|
+
]);
|
|
118
|
+
const bodyRows = (_jsx(BodyRows, { augFormattedRows: augFormattedRows, gridSelectionFns: gridSelectionFns, selectModel: selectModel, combinedPipelineOutput: combinedPipelineOutput, editModel: editModel, getInputStrSubmitCallback: getInputStrSubmitCallback, renderPrefixCells: renderPrefixCells, additionalColIndexOffset: reorder ? 1 : 0, additionalRowStyles: additionalBodyRowStyles, tableStyleModel: styleModel === null || styleModel === void 0 ? void 0 : styleModel.mainTableStyleModel }));
|
|
59
119
|
const prefixHeader = reorder ? _jsx(ReorderHeaderCell, {}) : null;
|
|
60
120
|
return (_jsx(InternalGrid, { gridProps: props, hooks: {
|
|
61
121
|
pipelineOutput: combinedPipelineOutput,
|
|
62
122
|
selectFns: gridSelectionFns,
|
|
63
|
-
|
|
64
|
-
|
|
123
|
+
}, slots: { colHeaderCells, bodyRows, prefixHeader }, classes: {
|
|
124
|
+
headerRow: additionalHeaderRowStyles,
|
|
125
|
+
} }));
|
|
65
126
|
};
|
|
66
127
|
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;
|