@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.
Files changed (55) hide show
  1. package/grid/Grid.js +1 -4
  2. package/grid/InternalGrid.d.ts +3 -2
  3. package/grid/InternalGrid.js +31 -29
  4. package/grid/editing/EditControlsCell.d.ts +5 -5
  5. package/grid/editing/EditControlsCell.js +1 -9
  6. package/grid/editing/EditableRow.d.ts +7 -7
  7. package/grid/editing/EditableRow.js +1 -1
  8. package/grid/export/ExportForm.d.ts +1 -0
  9. package/grid/export/ExportForm.js +3 -3
  10. package/grid/filtering/DateFilterRow.d.ts +4 -4
  11. package/grid/filtering/DateFilterRow.js +1 -1
  12. package/grid/filtering/FilterOptionsTable.d.ts +1 -0
  13. package/grid/filtering/FilterOptionsTable.js +14 -8
  14. package/grid/filtering/FilterRow.d.ts +4 -4
  15. package/grid/filtering/FilterRow.js +1 -1
  16. package/grid/filtering/NumberFilterRow.d.ts +3 -3
  17. package/grid/filtering/NumberFilterRow.js +1 -1
  18. package/grid/filtering/StringFilterRow.d.ts +3 -3
  19. package/grid/filtering/StringFilterRow.js +1 -1
  20. package/grid/main/BodyRows.d.ts +4 -3
  21. package/grid/main/BodyRows.js +18 -2
  22. package/grid/pagination/Pagination.d.ts +1 -1
  23. package/grid/pagination/Pagination.js +6 -3
  24. package/grid/pagination/types.d.ts +1 -1
  25. package/grid/pipeline/useCombinedPipeline/useCurrentPageRows.d.ts +2 -2
  26. package/grid/selection/SelectAllHeaderCell.d.ts +1 -1
  27. package/grid/selection/SelectAllHeaderCell.js +2 -4
  28. package/grid/selection/SelectionInput.d.ts +2 -1
  29. package/grid/selection/SelectionInput.js +2 -2
  30. package/grid/styling/types.d.ts +20 -21
  31. package/grid/toolbar/ToolbarContainer.d.ts +2 -2
  32. package/grid/toolbar/ToolbarContainer.js +11 -7
  33. package/grid/toolbar/types.d.ts +8 -0
  34. package/grid/toolbar/useInterfaces.d.ts +2 -8
  35. package/grid/toolbar/useInterfaces.js +9 -5
  36. package/grid/types.d.ts +5 -6
  37. package/grid/util/trueModulo.d.ts +2 -0
  38. package/grid/util/trueModulo.js +2 -0
  39. package/grid-pro/GridPro.js +69 -8
  40. package/grid-pro/reorder/ReorderHandleCell.d.ts +4 -3
  41. package/grid-pro/reorder/ReorderHandleCell.js +28 -29
  42. package/grid-pro/reorder/types.d.ts +15 -0
  43. package/grid-pro/reorder/useKeyboardReorder.d.ts +4 -0
  44. package/grid-pro/reorder/useKeyboardReorder.js +84 -0
  45. package/grid-pro/reorder/useKeyboardReorderListener.d.ts +3 -0
  46. package/grid-pro/reorder/useKeyboardReorderListener.js +26 -0
  47. package/grid-pro/reorder/useReorderStyles.d.ts +3 -0
  48. package/grid-pro/reorder/useReorderStyles.js +20 -0
  49. package/package.json +1 -1
  50. package/grid/main/ToggleButton.d.ts +0 -9
  51. package/grid/main/ToggleButton.js +0 -13
  52. package/grid/pipeline/useUnwrappedGridStyles.d.ts +0 -7
  53. package/grid/pipeline/useUnwrappedGridStyles.js +0 -15
  54. package/grid/styling/styleModelUnwrappers.d.ts +0 -4
  55. 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, additionalClasses, style, colIndexOffset, }) => {
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": "Input to select the current row", onClick: (event) => {
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
  };
@@ -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
- filterUiToggleButton?: string[];
39
+ tableDiv?: string[];
41
40
  paginationUiDiv?: string[];
42
41
  }
43
42
  export interface ToolbarStyleModel {
@@ -1,8 +1,8 @@
1
- import { ToolbarInterfaces } from "./types";
1
+ import { InterfaceNodeGenerator } from "./types";
2
2
  import { FC } from "react";
3
3
  import { ToolbarStyleModel } from "../styling/types";
4
4
  interface ToolbarContainerProps {
5
- interfaces: ToolbarInterfaces;
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 = ({ interfaces, styleModel, }) => {
5
+ const ToolbarContainer = ({ interfaceGen, styleModel, }) => {
6
6
  const [option, setOption] = useState(null);
7
- const enabledFeatures = Object.keys(interfaces).reduce((prev, toolbarOption) => {
8
- prev[toolbarOption] =
9
- !!interfaces[toolbarOption];
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",
@@ -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 { FilterOptionsTableProps } from "../filtering/FilterOptionsTable";
2
- import { ToolbarInterfaces } from "./types";
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 = ({ filtering, exporting, }) => {
6
- return useMemo(() => ({
7
- filtering: filtering ? _jsx(FilterOptionsTable, Object.assign({}, filtering)) : undefined,
8
- exporting: exporting ? _jsx(ExportForm, Object.assign({}, exporting)) : undefined,
9
- }), [exporting, filtering]);
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 { GridPaginationState } from "./pagination/types";
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?: GridPaginationState;
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
  }
@@ -0,0 +1,2 @@
1
+ declare const trueModulo: (num: number, divisor: number) => number;
2
+ export default trueModulo;
@@ -0,0 +1,2 @@
1
+ const trueModulo = (num, divisor) => ((num % divisor) + divisor) % divisor;
2
+ export default trueModulo;
@@ -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, 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 }));
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
- unwrappedStyles,
64
- }, slots: { colHeaderCells, bodyRows, prefixHeader } }));
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
- styleModel?: ReorderStyleModel;
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, useMemo } from "react";
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, 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]);
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 = intGhostTableClasses.join(" ");
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, intDraggedRowClasses);
50
+ applyRowClassesFromOrig(drageeTrIndex, draggedRowClasses);
60
51
  if (drageeTrIndex - 1 === -1) {
61
52
  headTr.className = [
62
53
  origHeadTrClasses,
63
- intDraggedRowPredecessorClasses.join(" "),
54
+ draggedRowPredecessorClasses.join(" "),
64
55
  ]
65
56
  .join(" ")
66
57
  .trim();
67
58
  return;
68
59
  }
69
- applyRowClassesFromOrig(drageeTrIndex - 1, intDraggedRowPredecessorClasses);
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, intBottomBorderRowClasses);
123
+ applyRowClassesFromBase(trIndex, bottomBorderRowClasses);
133
124
  }
134
125
  if (upper && trIndex - 1 >= 0) {
135
- applyRowClassesFromBase(trIndex - 1, intTopBorderRowClasses);
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, intTopBorderRowClasses);
134
+ applyRowClassesFromBase(trIndex, topBorderRowClasses);
147
135
  }
148
136
  if (!upper && trIndex + 1 < trs.length) {
149
- applyRowClassesFromBase(trIndex + 1, intBottomBorderRowClasses);
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
- intBottomBorderRowClasses,
208
- intDraggedRowClasses,
209
- intDraggedRowPredecessorClasses,
210
- intGhostTableClasses,
211
- intTopBorderRowClasses,
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
- 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", {
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,4 @@
1
+ import { RowId } from "../";
2
+ import { UseKeyboardReorderOutput } from "./types";
3
+ declare const useKeyboardReorder: (displayRowIds: RowId[]) => UseKeyboardReorderOutput;
4
+ export default useKeyboardReorder;
@@ -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;