@itwin/itwinui-react 1.32.0 → 1.34.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 (78) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/cjs/core/ButtonGroup/ButtonGroup.d.ts +6 -1
  3. package/cjs/core/ButtonGroup/ButtonGroup.js +6 -3
  4. package/cjs/core/ComboBox/ComboBox.d.ts +6 -1
  5. package/cjs/core/ComboBox/ComboBox.js +4 -2
  6. package/cjs/core/Footer/Footer.d.ts +14 -2
  7. package/cjs/core/Footer/Footer.js +40 -17
  8. package/cjs/core/InputGroup/InputGroup.js +12 -2
  9. package/cjs/core/LabeledSelect/LabeledSelect.js +10 -4
  10. package/cjs/core/Slider/Slider.js +10 -1
  11. package/cjs/core/StatusMessage/StatusMessage.d.ts +24 -0
  12. package/cjs/core/StatusMessage/StatusMessage.js +39 -0
  13. package/cjs/core/StatusMessage/index.d.ts +4 -0
  14. package/cjs/core/StatusMessage/index.js +10 -0
  15. package/cjs/core/Table/Table.d.ts +5 -0
  16. package/cjs/core/Table/Table.js +8 -8
  17. package/cjs/core/Table/TableRowMemoized.js +1 -0
  18. package/cjs/core/Table/actionHandlers/resizeHandler.d.ts +2 -0
  19. package/cjs/core/Table/actionHandlers/selectHandler.d.ts +1 -0
  20. package/cjs/core/Table/filters/BaseFilter.js +1 -1
  21. package/cjs/core/Table/filters/FilterToggle.js +4 -4
  22. package/cjs/core/Table/hooks/index.d.ts +1 -0
  23. package/cjs/core/Table/hooks/index.js +3 -1
  24. package/cjs/core/Table/hooks/useColumnDragAndDrop.d.ts +2 -0
  25. package/cjs/core/Table/hooks/useColumnDragAndDrop.js +120 -0
  26. package/cjs/core/Table/hooks/useExpanderCell.js +1 -0
  27. package/cjs/core/Table/hooks/useResizeColumns.js +8 -4
  28. package/cjs/core/Table/hooks/useSelectionCell.js +2 -2
  29. package/cjs/core/ToggleSwitch/ToggleSwitch.js +13 -10
  30. package/cjs/core/UserIcon/UserIcon.js +1 -10
  31. package/cjs/core/index.d.ts +2 -0
  32. package/cjs/core/index.js +3 -1
  33. package/cjs/core/utils/components/InputContainer.d.ts +1 -0
  34. package/cjs/core/utils/components/InputContainer.js +8 -7
  35. package/cjs/core/utils/hooks/useIntersection.d.ts +4 -3
  36. package/cjs/core/utils/hooks/useIntersection.js +10 -5
  37. package/cjs/core/utils/hooks/useOverflow.d.ts +3 -2
  38. package/cjs/core/utils/hooks/useOverflow.js +24 -21
  39. package/cjs/types/react-table-config.d.ts +7 -0
  40. package/esm/core/ButtonGroup/ButtonGroup.d.ts +6 -1
  41. package/esm/core/ButtonGroup/ButtonGroup.js +6 -3
  42. package/esm/core/ComboBox/ComboBox.d.ts +6 -1
  43. package/esm/core/ComboBox/ComboBox.js +4 -2
  44. package/esm/core/Footer/Footer.d.ts +14 -2
  45. package/esm/core/Footer/Footer.js +40 -17
  46. package/esm/core/InputGroup/InputGroup.js +12 -2
  47. package/esm/core/LabeledSelect/LabeledSelect.js +10 -4
  48. package/esm/core/Slider/Slider.js +10 -1
  49. package/esm/core/StatusMessage/StatusMessage.d.ts +24 -0
  50. package/esm/core/StatusMessage/StatusMessage.js +32 -0
  51. package/esm/core/StatusMessage/index.d.ts +4 -0
  52. package/esm/core/StatusMessage/index.js +6 -0
  53. package/esm/core/Table/Table.d.ts +5 -0
  54. package/esm/core/Table/Table.js +10 -10
  55. package/esm/core/Table/TableRowMemoized.js +1 -0
  56. package/esm/core/Table/actionHandlers/resizeHandler.d.ts +2 -0
  57. package/esm/core/Table/actionHandlers/selectHandler.d.ts +1 -0
  58. package/esm/core/Table/filters/BaseFilter.js +1 -1
  59. package/esm/core/Table/filters/FilterToggle.js +4 -4
  60. package/esm/core/Table/hooks/index.d.ts +1 -0
  61. package/esm/core/Table/hooks/index.js +1 -0
  62. package/esm/core/Table/hooks/useColumnDragAndDrop.d.ts +2 -0
  63. package/esm/core/Table/hooks/useColumnDragAndDrop.js +116 -0
  64. package/esm/core/Table/hooks/useExpanderCell.js +1 -0
  65. package/esm/core/Table/hooks/useResizeColumns.js +8 -4
  66. package/esm/core/Table/hooks/useSelectionCell.js +2 -2
  67. package/esm/core/ToggleSwitch/ToggleSwitch.js +13 -10
  68. package/esm/core/UserIcon/UserIcon.js +1 -10
  69. package/esm/core/index.d.ts +2 -0
  70. package/esm/core/index.js +1 -0
  71. package/esm/core/utils/components/InputContainer.d.ts +1 -0
  72. package/esm/core/utils/components/InputContainer.js +8 -7
  73. package/esm/core/utils/hooks/useIntersection.d.ts +4 -3
  74. package/esm/core/utils/hooks/useIntersection.js +10 -5
  75. package/esm/core/utils/hooks/useOverflow.d.ts +3 -2
  76. package/esm/core/utils/hooks/useOverflow.js +24 -21
  77. package/esm/types/react-table-config.d.ts +7 -0
  78. package/package.json +15 -14
@@ -11,8 +11,10 @@ export declare type TitleTranslations = {
11
11
  export declare type FooterProps = {
12
12
  /**
13
13
  * Customize footer elements.
14
+ * Providing a `FooterElement[]` will append the custom elements to the end of the default elements.
15
+ * Providing a function that returns a `FooterElement[]` allows further customization - whatever is returned from the function is displayed in the footer with no amendments.
14
16
  */
15
- customElements?: FooterElement[];
17
+ customElements?: FooterElement[] | ((defaultElements: FooterElement[]) => FooterElement[]);
16
18
  /**
17
19
  * Provide localized strings.
18
20
  */
@@ -27,13 +29,23 @@ export declare type FooterElement = {
27
29
  * URL of the footer element.
28
30
  */
29
31
  url?: string;
32
+ /**
33
+ * Key of the footer element.
34
+ */
35
+ key?: keyof TitleTranslations | 'copyright' | (string & Record<never, never>);
30
36
  };
31
37
  /**
32
38
  * Footer element with all needed legal and info links.
33
39
  * Be sure to place it manually at the bottom of your page.
34
40
  * You can use position 'absolute' with relative body or set the height of the content and place footer at the end.
35
- * @example
41
+ * @example <caption>Appending custom element after default elements</caption>
36
42
  * <Footer customElements={[{title: 'Bentley', url: 'https://www.bentley.com/'}]} />
43
+ * @example <caption>Returning only custom elements</caption>
44
+ * <Footer customElements={() => newFooterElements)} />
45
+ * @example <caption>Filtering out a specific element</caption>
46
+ * <Footer customElements={(defaultElements) => defaultElements.filter(({ key }) => key !== 'privacy' )} />
47
+ * @example <caption>Changing a url</caption>
48
+ * <Footer customElements={(defaultElements) => defaultElements.map(element => ({ ...element, url: element.key === 'privacy' ? customPrivacyUrl : element.url }))} />
37
49
  */
38
50
  export declare const Footer: (props: FooterProps) => JSX.Element;
39
51
  export default Footer;
@@ -48,39 +48,62 @@ var footerTranslations = {
48
48
  * Footer element with all needed legal and info links.
49
49
  * Be sure to place it manually at the bottom of your page.
50
50
  * You can use position 'absolute' with relative body or set the height of the content and place footer at the end.
51
- * @example
51
+ * @example <caption>Appending custom element after default elements</caption>
52
52
  * <Footer customElements={[{title: 'Bentley', url: 'https://www.bentley.com/'}]} />
53
+ * @example <caption>Returning only custom elements</caption>
54
+ * <Footer customElements={() => newFooterElements)} />
55
+ * @example <caption>Filtering out a specific element</caption>
56
+ * <Footer customElements={(defaultElements) => defaultElements.filter(({ key }) => key !== 'privacy' )} />
57
+ * @example <caption>Changing a url</caption>
58
+ * <Footer customElements={(defaultElements) => defaultElements.map(element => ({ ...element, url: element.key === 'privacy' ? customPrivacyUrl : element.url }))} />
53
59
  */
54
60
  export var Footer = function (props) {
55
61
  var customElements = props.customElements, translatedTitles = props.translatedTitles, className = props.className, rest = __rest(props, ["customElements", "translatedTitles", "className"]);
56
62
  useTheme();
57
- var today = new Date();
58
63
  var titles = __assign(__assign({}, footerTranslations), translatedTitles);
59
64
  var defaultElements = [
60
65
  {
66
+ key: 'copyright',
67
+ title: "\u00A9 " + new Date().getFullYear() + " Bentley Systems, Incorporated",
68
+ },
69
+ {
70
+ key: 'termsOfService',
61
71
  title: titles.termsOfService,
62
72
  url: 'https://connect-agreementportal.bentley.com/AgreementApp/Home/Eula/view/readonly/BentleyConnect',
63
73
  },
64
- { title: titles.privacy, url: 'https://www.bentley.com/en/privacy-policy' },
65
74
  {
75
+ key: 'privacy',
76
+ title: titles.privacy,
77
+ url: 'https://www.bentley.com/en/privacy-policy',
78
+ },
79
+ {
80
+ key: 'termsOfUse',
66
81
  title: titles.termsOfUse,
67
82
  url: 'https://www.bentley.com/en/terms-of-use-and-select-online-agreement',
68
83
  },
69
- { title: titles.cookies, url: 'https://www.bentley.com/en/cookie-policy' },
70
- { title: titles.legalNotices, url: 'https://connect.bentley.com/Legal' },
84
+ {
85
+ key: 'cookies',
86
+ title: titles.cookies,
87
+ url: 'https://www.bentley.com/en/cookie-policy',
88
+ },
89
+ {
90
+ key: 'legalNotices',
91
+ title: titles.legalNotices,
92
+ url: 'https://connect.bentley.com/Legal',
93
+ },
71
94
  ];
72
- var elements = customElements
73
- ? __spreadArray(__spreadArray([], defaultElements, true), customElements, true) : defaultElements;
95
+ var elements = defaultElements;
96
+ if (customElements) {
97
+ elements =
98
+ typeof customElements === 'function'
99
+ ? customElements(defaultElements)
100
+ : __spreadArray(__spreadArray([], defaultElements, true), customElements, true);
101
+ }
74
102
  return (React.createElement("footer", __assign({ className: cx('iui-legal-footer', className) }, rest),
75
- React.createElement("ul", null,
76
- React.createElement("li", null,
77
- "\u00A9 ",
78
- today.getFullYear(),
79
- " Bentley Systems, Incorporated"),
80
- elements.map(function (element, index) {
81
- return (React.createElement("li", { key: element.title + "-" + index },
82
- React.createElement("span", { className: 'iui-separator' }),
83
- element.url ? (React.createElement("a", { href: element.url, target: '_blank', rel: 'noreferrer' }, element.title)) : (element.title)));
84
- }))));
103
+ React.createElement("ul", null, elements.map(function (element, index) {
104
+ return (React.createElement("li", { key: element.key || element.title + "-" + index },
105
+ index > 0 && React.createElement("span", { className: 'iui-separator' }),
106
+ element.url ? (React.createElement("a", { href: element.url, target: '_blank', rel: 'noreferrer' }, element.title)) : (element.title)));
107
+ }))));
85
108
  };
86
109
  export default Footer;
@@ -45,8 +45,18 @@ import '@itwin/itwinui-css/css/inputs.css';
45
45
  export var InputGroup = function (props) {
46
46
  var children = props.children, _a = props.disabled, disabled = _a === void 0 ? false : _a, _b = props.displayStyle, displayStyle = _b === void 0 ? 'default' : _b, label = props.label, message = props.message, status = props.status, svgIcon = props.svgIcon, className = props.className, style = props.style, _c = props.required, required = _c === void 0 ? false : _c, rest = __rest(props, ["children", "disabled", "displayStyle", "label", "message", "status", "svgIcon", "className", "style", "required"]);
47
47
  useTheme();
48
- var icon = svgIcon !== null && svgIcon !== void 0 ? svgIcon : (status && StatusIconMap[status]());
49
- return (React.createElement(InputContainer, __assign({ label: label, disabled: disabled, required: required, status: status, message: message, icon: icon ? React.cloneElement(icon, { 'aria-hidden': true }) : undefined, isLabelInline: displayStyle === 'inline', className: className, style: style }, rest),
48
+ var icon = function () {
49
+ if (svgIcon) {
50
+ return React.cloneElement(svgIcon, { 'aria-hidden': true });
51
+ }
52
+ if (status && message) {
53
+ return React.cloneElement(StatusIconMap[status](), {
54
+ 'aria-hidden': true,
55
+ });
56
+ }
57
+ return undefined;
58
+ };
59
+ return (React.createElement(InputContainer, __assign({ label: label, disabled: disabled, required: required, status: status, message: message, icon: icon(), isLabelInline: displayStyle === 'inline', className: className, style: style }, rest),
50
60
  React.createElement("div", { className: 'iui-input-group' }, children)));
51
61
  };
52
62
  export default InputGroup;
@@ -64,10 +64,16 @@ import '@itwin/itwinui-css/css/inputs.css';
64
64
  export var LabeledSelect = function (props) {
65
65
  var className = props.className, _a = props.disabled, disabled = _a === void 0 ? false : _a, label = props.label, message = props.message, status = props.status, svgIcon = props.svgIcon, _b = props.displayStyle, displayStyle = _b === void 0 ? 'default' : _b, style = props.style, selectClassName = props.selectClassName, selectStyle = props.selectStyle, _c = props.required, required = _c === void 0 ? false : _c, rest = __rest(props, ["className", "disabled", "label", "message", "status", "svgIcon", "displayStyle", "style", "selectClassName", "selectStyle", "required"]);
66
66
  useTheme();
67
- var icon = svgIcon !== null && svgIcon !== void 0 ? svgIcon : (status && StatusIconMap[status]());
68
- return (React.createElement(InputContainer, { label: label, disabled: disabled, required: required, status: status, message: message, icon: displayStyle === 'default' && icon
69
- ? React.cloneElement(icon, { 'aria-hidden': true })
70
- : undefined, isLabelInline: displayStyle === 'inline', className: className, style: style },
67
+ var icon = function () {
68
+ if (svgIcon) {
69
+ return React.cloneElement(svgIcon, { 'aria-hidden': true });
70
+ }
71
+ if (status && message) {
72
+ return StatusIconMap[status]();
73
+ }
74
+ return undefined;
75
+ };
76
+ return (React.createElement(InputContainer, { label: label, disabled: disabled, required: required, status: status, message: message, icon: displayStyle === 'default' ? icon() : undefined, isLabelInline: displayStyle === 'inline', className: className, style: style },
71
77
  React.createElement(Select, __assign({ disabled: disabled, className: selectClassName, style: selectStyle }, rest))));
72
78
  };
73
79
  export default LabeledSelect;
@@ -202,11 +202,20 @@ export var Slider = React.forwardRef(function (props, ref) {
202
202
  newValues[closestValueIndex] = pointerValue;
203
203
  setCurrentValues(newValues);
204
204
  onChange === null || onChange === void 0 ? void 0 : onChange(newValues);
205
+ onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(newValues);
205
206
  focusThumb(containerRef.current, closestValueIndex);
206
207
  event.preventDefault();
207
208
  event.stopPropagation();
208
209
  }
209
- }, [min, max, step, currentValues, getAllowableThumbRange, onChange]);
210
+ }, [
211
+ min,
212
+ max,
213
+ step,
214
+ currentValues,
215
+ getAllowableThumbRange,
216
+ onChange,
217
+ onUpdate,
218
+ ]);
210
219
  useEventListener('pointermove', handlePointerMove, (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument);
211
220
  useEventListener('pointerup', handlePointerUp, (_b = containerRef.current) === null || _b === void 0 ? void 0 : _b.ownerDocument);
212
221
  var tickMarkArea = React.useMemo(function () {
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ export declare type StatusMessageProps = {
3
+ /**
4
+ * Custom icon to be displayed at the beginning.
5
+ * It will default to the `status` icon, if it's set.
6
+ */
7
+ startIcon?: JSX.Element;
8
+ /**
9
+ * Message content.
10
+ */
11
+ children: React.ReactNode;
12
+ /**
13
+ * Status of the message.
14
+ */
15
+ status?: 'positive' | 'warning' | 'negative';
16
+ };
17
+ /**
18
+ * Component to display icon and text below the `Combobox` component.
19
+ * @example
20
+ * <StatusMessage>This is the text</StatusMessage>
21
+ * <StatusMessage startIcon={<SvgStar />}>This is the text</StatusMessage>
22
+ */
23
+ export declare const StatusMessage: ({ startIcon: userStartIcon, children, status, }: StatusMessageProps) => JSX.Element;
24
+ export default StatusMessage;
@@ -0,0 +1,32 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import React from 'react';
6
+ import { StatusIconMap, useTheme } from '../utils';
7
+ import cx from 'classnames';
8
+ /**
9
+ * Component to display icon and text below the `Combobox` component.
10
+ * @example
11
+ * <StatusMessage>This is the text</StatusMessage>
12
+ * <StatusMessage startIcon={<SvgStar />}>This is the text</StatusMessage>
13
+ */
14
+ export var StatusMessage = function (_a) {
15
+ var userStartIcon = _a.startIcon, children = _a.children, status = _a.status;
16
+ useTheme();
17
+ var StartIcon = function () {
18
+ var _a;
19
+ var icon = userStartIcon !== null && userStartIcon !== void 0 ? userStartIcon : (status && StatusIconMap[status]());
20
+ if (!icon) {
21
+ return null;
22
+ }
23
+ return React.cloneElement(icon, {
24
+ className: cx('iui-input-icon', (_a = icon.props) === null || _a === void 0 ? void 0 : _a.className),
25
+ 'aria-hidden': true,
26
+ });
27
+ };
28
+ return (React.createElement(React.Fragment, null,
29
+ React.createElement(StartIcon, null),
30
+ React.createElement("div", { className: 'iui-message' }, children)));
31
+ };
32
+ export default StatusMessage;
@@ -0,0 +1,4 @@
1
+ export { StatusMessage } from './StatusMessage';
2
+ export type { StatusMessageProps } from './StatusMessage';
3
+ declare const _default: "./StatusMessage";
4
+ export default _default;
@@ -0,0 +1,6 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ export { StatusMessage } from './StatusMessage';
6
+ export default './StatusMessage';
@@ -170,6 +170,11 @@ export declare type TableProps<T extends Record<string, unknown> = Record<string
170
170
  * @beta
171
171
  */
172
172
  enableVirtualization?: boolean;
173
+ /**
174
+ * Flag whether columns can be reordered.
175
+ * @default false
176
+ */
177
+ enableColumnReordering?: boolean;
173
178
  } & Omit<CommonProps, 'title'>;
174
179
  /**
175
180
  * Table based on [react-table](https://react-table.tanstack.com/docs/api/overview).
@@ -26,7 +26,7 @@ var __rest = (this && this.__rest) || function (s, e) {
26
26
  *--------------------------------------------------------------------------------------------*/
27
27
  import React from 'react';
28
28
  import cx from 'classnames';
29
- import { actions as TableActions, useFlexLayout, useFilters, useRowSelect, useSortBy, useTable, useExpanded, usePagination, } from 'react-table';
29
+ import { actions as TableActions, useFlexLayout, useFilters, useRowSelect, useSortBy, useTable, useExpanded, usePagination, useColumnOrder, } from 'react-table';
30
30
  import { ProgressRadial } from '../ProgressIndicators';
31
31
  import { useTheme, useResizeObserver } from '../utils';
32
32
  import '@itwin/itwinui-css/css/table.css';
@@ -36,7 +36,7 @@ import { getCellStyle } from './utils';
36
36
  import { TableRowMemoized } from './TableRowMemoized';
37
37
  import { FilterToggle } from './filters';
38
38
  import { customFilterFunctions } from './filters/customFilterFunctions';
39
- import { useExpanderCell, useSelectionCell, useSubRowFiltering, useSubRowSelection, useResizeColumns, } from './hooks';
39
+ import { useExpanderCell, useSelectionCell, useSubRowFiltering, useSubRowSelection, useResizeColumns, useColumnDragAndDrop, } from './hooks';
40
40
  import { onExpandHandler, onFilterHandler, onSelectHandler, } from './actionHandlers';
41
41
  import { onSingleSelectHandler } from './actionHandlers/selectHandler';
42
42
  import { onTableResizeEnd, onTableResizeStart, } from './actionHandlers/resizeHandler';
@@ -88,9 +88,9 @@ var tableResizeEndAction = 'tableResizeEnd';
88
88
  */
89
89
  export var Table = function (props) {
90
90
  var _a;
91
- var data = props.data, columns = props.columns, _b = props.isLoading, isLoading = _b === void 0 ? false : _b, emptyTableContent = props.emptyTableContent, className = props.className, style = props.style, id = props.id, _c = props.isSelectable, isSelectable = _c === void 0 ? false : _c, onSelect = props.onSelect, onRowClick = props.onRowClick, _d = props.isSortable, isSortable = _d === void 0 ? false : _d, onSort = props.onSort, stateReducer = props.stateReducer, onBottomReached = props.onBottomReached, onRowInViewport = props.onRowInViewport, _e = props.intersectionMargin, intersectionMargin = _e === void 0 ? 300 : _e, subComponent = props.subComponent, onExpand = props.onExpand, onFilter = props.onFilter, emptyFilteredTableContent = props.emptyFilteredTableContent, filterFunctions = props.filterTypes, expanderCell = props.expanderCell, isRowDisabled = props.isRowDisabled, rowProps = props.rowProps, _f = props.density, density = _f === void 0 ? 'default' : _f, _g = props.selectSubRows, selectSubRows = _g === void 0 ? true : _g, getSubRows = props.getSubRows, _h = props.selectRowOnClick, selectRowOnClick = _h === void 0 ? true : _h, paginatorRenderer = props.paginatorRenderer, _j = props.pageSize, pageSize = _j === void 0 ? 25 : _j, _k = props.isResizable, isResizable = _k === void 0 ? false : _k, _l = props.styleType, styleType = _l === void 0 ? 'default' : _l, _m = props.enableVirtualization, enableVirtualization = _m === void 0 ? false : _m, rest = __rest(props, ["data", "columns", "isLoading", "emptyTableContent", "className", "style", "id", "isSelectable", "onSelect", "onRowClick", "isSortable", "onSort", "stateReducer", "onBottomReached", "onRowInViewport", "intersectionMargin", "subComponent", "onExpand", "onFilter", "emptyFilteredTableContent", "filterTypes", "expanderCell", "isRowDisabled", "rowProps", "density", "selectSubRows", "getSubRows", "selectRowOnClick", "paginatorRenderer", "pageSize", "isResizable", "styleType", "enableVirtualization"]);
91
+ var data = props.data, columns = props.columns, _b = props.isLoading, isLoading = _b === void 0 ? false : _b, emptyTableContent = props.emptyTableContent, className = props.className, style = props.style, id = props.id, _c = props.isSelectable, isSelectable = _c === void 0 ? false : _c, onSelect = props.onSelect, onRowClick = props.onRowClick, _d = props.isSortable, isSortable = _d === void 0 ? false : _d, onSort = props.onSort, stateReducer = props.stateReducer, onBottomReached = props.onBottomReached, onRowInViewport = props.onRowInViewport, _e = props.intersectionMargin, intersectionMargin = _e === void 0 ? 300 : _e, subComponent = props.subComponent, onExpand = props.onExpand, onFilter = props.onFilter, emptyFilteredTableContent = props.emptyFilteredTableContent, filterFunctions = props.filterTypes, expanderCell = props.expanderCell, isRowDisabled = props.isRowDisabled, rowProps = props.rowProps, _f = props.density, density = _f === void 0 ? 'default' : _f, _g = props.selectSubRows, selectSubRows = _g === void 0 ? true : _g, getSubRows = props.getSubRows, _h = props.selectRowOnClick, selectRowOnClick = _h === void 0 ? true : _h, paginatorRenderer = props.paginatorRenderer, _j = props.pageSize, pageSize = _j === void 0 ? 25 : _j, _k = props.isResizable, isResizable = _k === void 0 ? false : _k, _l = props.styleType, styleType = _l === void 0 ? 'default' : _l, _m = props.enableVirtualization, enableVirtualization = _m === void 0 ? false : _m, _o = props.enableColumnReordering, enableColumnReordering = _o === void 0 ? false : _o, rest = __rest(props, ["data", "columns", "isLoading", "emptyTableContent", "className", "style", "id", "isSelectable", "onSelect", "onRowClick", "isSortable", "onSort", "stateReducer", "onBottomReached", "onRowInViewport", "intersectionMargin", "subComponent", "onExpand", "onFilter", "emptyFilteredTableContent", "filterTypes", "expanderCell", "isRowDisabled", "rowProps", "density", "selectSubRows", "getSubRows", "selectRowOnClick", "paginatorRenderer", "pageSize", "isResizable", "styleType", "enableVirtualization", "enableColumnReordering"]);
92
92
  useTheme();
93
- var _o = React.useState(), ownerDocument = _o[0], setOwnerDocument = _o[1];
93
+ var _p = React.useState(), ownerDocument = _p[0], setOwnerDocument = _p[1];
94
94
  var defaultColumn = React.useMemo(function () { return ({
95
95
  maxWidth: 0,
96
96
  minWidth: 0,
@@ -146,7 +146,7 @@ export var Table = function (props) {
146
146
  return getSubRows ? getSubRows(item, index) : item.subRows;
147
147
  });
148
148
  }, [data, getSubRows]);
149
- var instance = useTable(__assign(__assign({ manualPagination: !paginatorRenderer, paginateExpandedRows: false }, props), { columns: columns, defaultColumn: defaultColumn, disableSortBy: !isSortable, stateReducer: tableStateReducer, filterTypes: filterTypes, selectSubRows: selectSubRows, data: data, getSubRows: getSubRows, initialState: __assign({ pageSize: pageSize }, props.initialState) }), useFlexLayout, useResizeColumns(ownerDocument), useFilters, useSubRowFiltering(hasAnySubRows), useSortBy, useExpanded, usePagination, useRowSelect, useSubRowSelection, useExpanderCell(subComponent, expanderCell, isRowDisabled), useSelectionCell(isSelectable, isRowDisabled));
149
+ var instance = useTable(__assign(__assign({ manualPagination: !paginatorRenderer, paginateExpandedRows: false }, props), { columns: columns, defaultColumn: defaultColumn, disableSortBy: !isSortable, stateReducer: tableStateReducer, filterTypes: filterTypes, selectSubRows: selectSubRows, data: data, getSubRows: getSubRows, initialState: __assign({ pageSize: pageSize }, props.initialState) }), useFlexLayout, useResizeColumns(ownerDocument), useFilters, useSubRowFiltering(hasAnySubRows), useSortBy, useExpanded, usePagination, useRowSelect, useSubRowSelection, useExpanderCell(subComponent, expanderCell, isRowDisabled), useSelectionCell(isSelectable, isRowDisabled), useColumnOrder, useColumnDragAndDrop(enableColumnReordering));
150
150
  var getTableProps = instance.getTableProps, rows = instance.rows, headerGroups = instance.headerGroups, getTableBodyProps = instance.getTableBodyProps, prepareRow = instance.prepareRow, state = instance.state, allColumns = instance.allColumns, filteredFlatRows = instance.filteredFlatRows, dispatch = instance.dispatch, page = instance.page, gotoPage = instance.gotoPage, setPageSize = instance.setPageSize, flatHeaders = instance.flatHeaders;
151
151
  var ariaDataAttributes = Object.entries(rest).reduce(function (result, _a) {
152
152
  var key = _a[0], value = _a[1];
@@ -260,21 +260,21 @@ export var Table = function (props) {
260
260
  className: 'iui-row',
261
261
  });
262
262
  return (React.createElement("div", __assign({}, headerGroupProps, { key: headerGroupProps.key }), headerGroup.headers.map(function (column, index) {
263
- var _a = column.getSortByToggleProps(), onSortClick = _a.onClick, sortByProps = __rest(_a, ["onClick"]);
264
- var columnProps = column.getHeaderProps(__assign(__assign({}, sortByProps), { className: cx('iui-cell', { 'iui-actionable': column.canSort }, { 'iui-sorted': column.isSorted }, column.columnClassName), style: __assign({}, getCellStyle(column, !!state.isTableResizing)) }));
265
- return (React.createElement("div", __assign({}, columnProps, { key: columnProps.key, title: undefined, ref: function (el) {
263
+ var columnProps = column.getHeaderProps(__assign(__assign({}, column.getSortByToggleProps()), { className: cx('iui-cell', { 'iui-actionable': column.canSort }, { 'iui-sorted': column.isSorted }, column.columnClassName), style: __assign({}, getCellStyle(column, !!state.isTableResizing)) }));
264
+ return (React.createElement("div", __assign({}, columnProps, column.getDragAndDropProps(), { key: columnProps.key, title: undefined, ref: function (el) {
266
265
  if (el && isResizable) {
267
266
  columnRefs.current[column.id] = el;
268
267
  column.resizeWidth = el.getBoundingClientRect().width;
269
268
  }
270
- }, onMouseDown: onSortClick }),
269
+ } }),
271
270
  column.render('Header'),
272
271
  !isLoading && (data.length != 0 || areFiltersSet) && (React.createElement(FilterToggle, { column: column, ownerDocument: ownerDocument })),
273
272
  !isLoading && data.length != 0 && column.canSort && (React.createElement("div", { className: 'iui-cell-end-icon' }, column.isSorted && column.isSortedDesc ? (React.createElement(SvgSortUp, { className: 'iui-icon iui-sort', "aria-hidden": true })) : (React.createElement(SvgSortDown, { className: 'iui-icon iui-sort', "aria-hidden": true })))),
274
273
  isResizable &&
275
274
  column.isResizerVisible &&
276
275
  index !== headerGroup.headers.length - 1 && (React.createElement("div", __assign({}, column.getResizerProps(), { className: 'iui-resizer' }),
277
- React.createElement("div", { className: 'iui-resizer-bar' })))));
276
+ React.createElement("div", { className: 'iui-resizer-bar' }))),
277
+ enableColumnReordering && !column.disableReordering && (React.createElement("div", { className: 'iui-reorder-bar' }))));
278
278
  })));
279
279
  })),
280
280
  React.createElement("div", __assign({}, getTableBodyProps({
@@ -85,6 +85,7 @@ export var TableRowMemoized = React.memo(TableRow, function (prevProp, nextProp)
85
85
  prevProp.rowProps === nextProp.rowProps &&
86
86
  prevProp.expanderCell === nextProp.expanderCell &&
87
87
  prevProp.tableHasSubRows === nextProp.tableHasSubRows &&
88
+ prevProp.state.columnOrder === nextProp.state.columnOrder &&
88
89
  !nextProp.state.columnResizing.isResizingColumn &&
89
90
  !nextProp.state.isTableResizing;
90
91
  });
@@ -11,6 +11,7 @@ export declare const onTableResizeStart: <T extends Record<string, unknown>>(sta
11
11
  columnWidths: Record<string, number>;
12
12
  isResizingColumn?: string | undefined;
13
13
  };
14
+ columnReorderStartIndex: number;
14
15
  columnOrder: import("react-table").IdType<T>[];
15
16
  expanded: Record<import("react-table").IdType<T>, boolean>;
16
17
  filters: import("react-table").Filters<T>;
@@ -36,6 +37,7 @@ export declare const onTableResizeEnd: <T extends Record<string, unknown>>(state
36
37
  isResizingColumn?: string | undefined;
37
38
  };
38
39
  hiddenColumns?: import("react-table").IdType<T>[] | undefined;
40
+ columnReorderStartIndex: number;
39
41
  columnOrder: import("react-table").IdType<T>[];
40
42
  expanded: Record<import("react-table").IdType<T>, boolean>;
41
43
  filters: import("react-table").Filters<T>;
@@ -19,6 +19,7 @@ export declare const onSingleSelectHandler: <T extends Record<string, unknown>>(
19
19
  isResizingColumn?: string | undefined;
20
20
  };
21
21
  isTableResizing?: boolean | undefined;
22
+ columnReorderStartIndex: number;
22
23
  columnOrder: import("react-table").IdType<T>[];
23
24
  expanded: Record<import("react-table").IdType<T>, boolean>;
24
25
  filters: import("react-table").Filters<T>;
@@ -25,7 +25,7 @@ export var BaseFilter = function (props) {
25
25
  useTheme();
26
26
  return (React.createElement("div", { className: cx('iui-column-filter', className), style: style,
27
27
  // Prevents from triggering sort
28
- onMouseDown: function (e) {
28
+ onClick: function (e) {
29
29
  e.stopPropagation();
30
30
  }, id: id }, children));
31
31
  };
@@ -48,9 +48,9 @@ export var FilterToggle = function (props) {
48
48
  close();
49
49
  }, [close, column]);
50
50
  return (React.createElement(React.Fragment, null, column.canFilter && column.Filter && (React.createElement(Popover, { content: column.render('Filter', { close: close, setFilter: setFilter, clearFilter: clearFilter }), placement: 'bottom-start', visible: isVisible, onClickOutside: close, appendTo: ownerDocument === null || ownerDocument === void 0 ? void 0 : ownerDocument.body },
51
- React.createElement(IconButton, __assign({ styleType: 'borderless', isActive: isVisible || column.filterValue, className: cx('iui-filter-button', className), onClick: function () {
51
+ React.createElement(IconButton, __assign({ styleType: 'borderless', isActive: isVisible || column.filterValue, className: cx('iui-filter-button', className), onClick: function (e) {
52
52
  setIsVisible(function (v) { return !v; });
53
- },
54
- // Prevents from triggering sort
55
- onMouseDown: function (e) { return e.stopPropagation(); } }, rest), column.filterValue ? React.createElement(SvgFilter, null) : React.createElement(SvgFilterHollow, null))))));
53
+ // Prevents from triggering sort
54
+ e.stopPropagation();
55
+ } }, rest), column.filterValue ? React.createElement(SvgFilter, null) : React.createElement(SvgFilterHollow, null))))));
56
56
  };
@@ -3,3 +3,4 @@ export { SELECTION_CELL_ID, useSelectionCell } from './useSelectionCell';
3
3
  export { useSubRowFiltering } from './useSubRowFiltering';
4
4
  export { useSubRowSelection } from './useSubRowSelection';
5
5
  export { useResizeColumns } from './useResizeColumns';
6
+ export { useColumnDragAndDrop } from './useColumnDragAndDrop';
@@ -7,3 +7,4 @@ export { SELECTION_CELL_ID, useSelectionCell } from './useSelectionCell';
7
7
  export { useSubRowFiltering } from './useSubRowFiltering';
8
8
  export { useSubRowSelection } from './useSubRowSelection';
9
9
  export { useResizeColumns } from './useResizeColumns';
10
+ export { useColumnDragAndDrop } from './useColumnDragAndDrop';
@@ -0,0 +1,2 @@
1
+ import { Hooks } from 'react-table';
2
+ export declare const useColumnDragAndDrop: <T extends Record<string, unknown>>(isEnabled: boolean) => (hooks: Hooks<T>) => void;
@@ -0,0 +1,116 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
13
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
14
+ if (ar || !(i in from)) {
15
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
16
+ ar[i] = from[i];
17
+ }
18
+ }
19
+ return to.concat(ar || Array.prototype.slice.call(from));
20
+ };
21
+ import { actions, makePropGetter, useGetLatest, } from 'react-table';
22
+ var REORDER_ACTIONS = {
23
+ columnDragStart: 'columnDragStart',
24
+ columnDragEnd: 'columnDragEnd',
25
+ };
26
+ export var useColumnDragAndDrop = function (isEnabled) { return function (hooks) {
27
+ hooks.getDragAndDropProps = [defaultGetDragAndDropProps(isEnabled)];
28
+ hooks.stateReducers.push(reducer);
29
+ hooks.useInstance.push(useInstance);
30
+ }; };
31
+ var defaultGetDragAndDropProps = function (isEnabled) { return function (props, _a) {
32
+ var instance = _a.instance, header = _a.header;
33
+ if (!isEnabled || header.disableReordering) {
34
+ return props;
35
+ }
36
+ var onDragStart = function () {
37
+ instance.dispatch({
38
+ type: REORDER_ACTIONS.columnDragStart,
39
+ columnIndex: instance.flatHeaders.indexOf(header),
40
+ });
41
+ };
42
+ var setOnDragColumnStyle = function (event, position) {
43
+ var columnElement = event.currentTarget;
44
+ columnElement.classList.remove('iui-reorder-column-right');
45
+ columnElement.classList.remove('iui-reorder-column-left');
46
+ if (position === 'left') {
47
+ columnElement.classList.add('iui-reorder-column-left');
48
+ }
49
+ else if (position === 'right') {
50
+ columnElement.classList.add('iui-reorder-column-right');
51
+ }
52
+ };
53
+ var reorderColumns = function (tableColumns, srcIndex, dstIndex) {
54
+ var newTableColumns = __spreadArray([], tableColumns, true);
55
+ var removed = newTableColumns.splice(srcIndex, 1)[0];
56
+ newTableColumns.splice(dstIndex, 0, removed);
57
+ return newTableColumns;
58
+ };
59
+ var onDragOver = function (event) {
60
+ event.preventDefault();
61
+ var headerIndex = instance.flatHeaders.indexOf(header);
62
+ if (instance.state.columnReorderStartIndex !== headerIndex) {
63
+ setOnDragColumnStyle(event, instance.state.columnReorderStartIndex > headerIndex ? 'left' : 'right');
64
+ }
65
+ };
66
+ var onDragLeave = function (event) {
67
+ setOnDragColumnStyle(event);
68
+ };
69
+ var onDrop = function (event) {
70
+ event.preventDefault();
71
+ setOnDragColumnStyle(event);
72
+ var columnIds = instance.flatHeaders.map(function (x) { return x.id; });
73
+ var srcIndex = instance.state.columnReorderStartIndex;
74
+ var dstIndex = columnIds.findIndex(function (x) { return x === header.id; });
75
+ if (srcIndex === dstIndex || srcIndex === -1 || dstIndex === -1) {
76
+ return;
77
+ }
78
+ instance.setColumnOrder(reorderColumns(columnIds, srcIndex, dstIndex));
79
+ instance.dispatch({
80
+ type: REORDER_ACTIONS.columnDragEnd,
81
+ columnIndex: -1,
82
+ });
83
+ };
84
+ return [
85
+ props,
86
+ {
87
+ draggable: true,
88
+ onDragStart: onDragStart,
89
+ onDragOver: onDragOver,
90
+ onDragLeave: onDragLeave,
91
+ onDrop: onDrop,
92
+ },
93
+ ];
94
+ }; };
95
+ var reducer = function (newState, action) {
96
+ switch (action.type) {
97
+ case actions.init:
98
+ return __assign(__assign({}, newState), { columnReorderStartIndex: -1 });
99
+ case REORDER_ACTIONS.columnDragStart:
100
+ return __assign(__assign({}, newState), { columnReorderStartIndex: action.columnIndex });
101
+ case REORDER_ACTIONS.columnDragEnd:
102
+ return __assign(__assign({}, newState), { columnReorderStartIndex: -1 });
103
+ default:
104
+ return newState;
105
+ }
106
+ };
107
+ var useInstance = function (instance) {
108
+ var flatHeaders = instance.flatHeaders, getHooks = instance.getHooks;
109
+ var getInstance = useGetLatest(instance);
110
+ flatHeaders.forEach(function (header) {
111
+ header.getDragAndDropProps = makePropGetter(getHooks().getDragAndDropProps, {
112
+ instance: getInstance(),
113
+ header: header,
114
+ });
115
+ });
116
+ };
@@ -29,6 +29,7 @@ export var useExpanderCell = function (subComponent, expanderCell, isRowDisabled
29
29
  maxWidth: 48,
30
30
  columnClassName: 'iui-slot',
31
31
  cellClassName: 'iui-slot',
32
+ disableReordering: true,
32
33
  Cell: function (props) {
33
34
  var row = props.row;
34
35
  if (!subComponent(row)) {
@@ -108,16 +108,20 @@ var defaultGetResizerProps = function (ownerDocument) { return function (props,
108
108
  return [
109
109
  props,
110
110
  {
111
- onMouseDown: function (e) {
112
- e.persist();
111
+ onClick: function (e) {
113
112
  // Prevents from triggering sort
114
113
  e.stopPropagation();
114
+ },
115
+ onMouseDown: function (e) {
116
+ e.persist();
117
+ // Prevents from triggering drag'n'drop
118
+ e.preventDefault();
115
119
  onResizeStart(e, header);
116
120
  },
117
121
  onTouchStart: function (e) {
118
122
  e.persist();
119
- // Prevents from triggering sort
120
- e.stopPropagation();
123
+ // Prevents from triggering drag'n'drop
124
+ e.preventDefault();
121
125
  onResizeStart(e, header);
122
126
  },
123
127
  style: {
@@ -39,6 +39,7 @@ export var useSelectionCell = function (isSelectable, isRowDisabled) { return fu
39
39
  maxWidth: 48,
40
40
  columnClassName: 'iui-slot',
41
41
  cellClassName: 'iui-slot',
42
+ disableReordering: true,
42
43
  Header: function (_a) {
43
44
  var getToggleAllRowsSelectedProps = _a.getToggleAllRowsSelectedProps, rows = _a.rows, initialRows = _a.initialRows, state = _a.state;
44
45
  var disabled = rows.every(function (row) { return isRowDisabled === null || isRowDisabled === void 0 ? void 0 : isRowDisabled(row.original); });
@@ -49,8 +50,7 @@ export var useSelectionCell = function (isSelectable, isRowDisabled) { return fu
49
50
  },
50
51
  Cell: function (_a) {
51
52
  var row = _a.row;
52
- return (React.createElement("span", { onClick: function (e) { return e.stopPropagation(); } },
53
- React.createElement(Checkbox, __assign({}, row.getToggleRowSelectedProps(), { disabled: isRowDisabled === null || isRowDisabled === void 0 ? void 0 : isRowDisabled(row.original) }))));
53
+ return (React.createElement(Checkbox, __assign({}, row.getToggleRowSelectedProps(), { disabled: isRowDisabled === null || isRowDisabled === void 0 ? void 0 : isRowDisabled(row.original), onClick: function (e) { return e.stopPropagation(); } })));
54
54
  },
55
55
  }
56
56
  ], columns, true); });