@absreim/react-bootstrap-data-grid-pro 2.5.0 → 2.6.0

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