@itwin/itwinui-react 1.39.0 → 1.40.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 (56) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/cjs/core/ComboBox/ComboBox.d.ts +10 -1
  3. package/cjs/core/ComboBox/ComboBox.js +31 -14
  4. package/cjs/core/ComboBox/ComboBoxInput.js +1 -0
  5. package/cjs/core/ComboBox/helpers.js +1 -1
  6. package/cjs/core/Menu/MenuItemSkeleton.d.ts +32 -0
  7. package/cjs/core/Menu/MenuItemSkeleton.js +53 -0
  8. package/cjs/core/Menu/index.d.ts +2 -0
  9. package/cjs/core/Menu/index.js +3 -1
  10. package/cjs/core/Table/Table.js +39 -6
  11. package/cjs/core/Table/TableCell.js +10 -3
  12. package/cjs/core/Table/TableRowMemoized.js +5 -1
  13. package/cjs/core/Table/actionHandlers/resizeHandler.d.ts +8 -0
  14. package/cjs/core/Table/actionHandlers/selectHandler.d.ts +4 -0
  15. package/cjs/core/Table/columns/selectionColumn.js +4 -2
  16. package/cjs/core/Table/hooks/index.d.ts +1 -0
  17. package/cjs/core/Table/hooks/index.js +3 -1
  18. package/cjs/core/Table/hooks/useStickyColumns.d.ts +2 -0
  19. package/cjs/core/Table/hooks/useStickyColumns.js +84 -0
  20. package/cjs/core/Table/utils.d.ts +1 -0
  21. package/cjs/core/Table/utils.js +36 -1
  22. package/cjs/core/index.d.ts +2 -2
  23. package/cjs/core/index.js +4 -3
  24. package/cjs/core/utils/components/VisuallyHidden.d.ts +9 -0
  25. package/cjs/core/utils/components/VisuallyHidden.js +44 -0
  26. package/cjs/core/utils/components/index.d.ts +1 -0
  27. package/cjs/core/utils/components/index.js +1 -0
  28. package/cjs/types/react-table-config.d.ts +9 -0
  29. package/esm/core/ComboBox/ComboBox.d.ts +10 -1
  30. package/esm/core/ComboBox/ComboBox.js +31 -14
  31. package/esm/core/ComboBox/ComboBoxInput.js +1 -0
  32. package/esm/core/ComboBox/helpers.js +1 -1
  33. package/esm/core/Menu/MenuItemSkeleton.d.ts +32 -0
  34. package/esm/core/Menu/MenuItemSkeleton.js +46 -0
  35. package/esm/core/Menu/index.d.ts +2 -0
  36. package/esm/core/Menu/index.js +1 -0
  37. package/esm/core/Table/Table.js +41 -8
  38. package/esm/core/Table/TableCell.js +11 -4
  39. package/esm/core/Table/TableRowMemoized.js +5 -1
  40. package/esm/core/Table/actionHandlers/resizeHandler.d.ts +8 -0
  41. package/esm/core/Table/actionHandlers/selectHandler.d.ts +4 -0
  42. package/esm/core/Table/columns/selectionColumn.js +4 -2
  43. package/esm/core/Table/hooks/index.d.ts +1 -0
  44. package/esm/core/Table/hooks/index.js +1 -0
  45. package/esm/core/Table/hooks/useStickyColumns.d.ts +2 -0
  46. package/esm/core/Table/hooks/useStickyColumns.js +80 -0
  47. package/esm/core/Table/utils.d.ts +1 -0
  48. package/esm/core/Table/utils.js +34 -0
  49. package/esm/core/index.d.ts +2 -2
  50. package/esm/core/index.js +1 -1
  51. package/esm/core/utils/components/VisuallyHidden.d.ts +9 -0
  52. package/esm/core/utils/components/VisuallyHidden.js +38 -0
  53. package/esm/core/utils/components/index.d.ts +1 -0
  54. package/esm/core/utils/components/index.js +1 -0
  55. package/esm/types/react-table-config.d.ts +9 -0
  56. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.40.0](https://www.github.com/iTwin/iTwinUI-react/compare/v1.39.0...v1.40.0) (2022-06-10)
4
+
5
+ ### What's new
6
+
7
+ * **Combobox:** Loading state with skeletons ([#655](https://www.github.com/iTwin/iTwinUI-react/issues/655)) ([cc1c7fb](https://www.github.com/iTwin/iTwinUI-react/commit/cc1c7fb6b5c494c94c01fe06483b788e0a27ec36))
8
+ * **Table:** Add sticky columns feature ([#695](https://www.github.com/iTwin/iTwinUI-react/issues/695)) ([eb6b0c0](https://www.github.com/iTwin/iTwinUI-react/commit/eb6b0c03e83b6e1417a444901c033a52545de186))
9
+
10
+ ### Fixes
11
+
12
+ * **Table:** Overriding min-width for the whole table ([#706](https://www.github.com/iTwin/iTwinUI-react/issues/706)) ([ad8173b](https://www.github.com/iTwin/iTwinUI-react/commit/ad8173b5764277a06a4b87a408e80affb2271749))
13
+ * **Table:** Removed title from selection checkboxes ([#704](https://www.github.com/iTwin/iTwinUI-react/issues/704)) ([5f72e59](https://www.github.com/iTwin/iTwinUI-react/commit/5f72e59a6d6e66b5f69c30ad82f7b37017242df6))
14
+
3
15
  ## [1.39.0](https://www.github.com/iTwin/iTwinUI-react/compare/v1.38.0...v1.39.0) (2022-06-03)
4
16
 
5
17
  ### What's new
@@ -35,9 +35,10 @@ export declare type ComboBoxProps<T> = {
35
35
  dropdownMenuProps?: PopoverProps;
36
36
  /**
37
37
  * Message shown when no options are available.
38
+ * If `JSX.Element` is provided, it will be rendered as is and won't be wrapped with `MenuExtraContent`.
38
39
  * @default 'No options found'
39
40
  */
40
- emptyStateMessage?: string;
41
+ emptyStateMessage?: React.ReactNode;
41
42
  /**
42
43
  * A custom item renderer can be specified to control the rendering.
43
44
  *
@@ -58,6 +59,14 @@ export declare type ComboBoxProps<T> = {
58
59
  * @beta
59
60
  */
60
61
  enableVirtualization?: boolean;
62
+ /**
63
+ * Callback fired when dropdown menu is opened.
64
+ */
65
+ onShow?: () => void;
66
+ /**
67
+ * Callback fired when dropdown menu is closed.
68
+ */
69
+ onHide?: () => void;
61
70
  } & Pick<InputContainerProps, 'status'> & Omit<CommonProps, 'title'>;
62
71
  /**
63
72
  * ComboBox component that allows typing a value to filter the options in dropdown list.
@@ -62,8 +62,8 @@ var getOptionId = function (option, idPrefix) {
62
62
  * />
63
63
  */
64
64
  var ComboBox = function (props) {
65
- var _a;
66
- var options = props.options, valueProp = props.value, onChange = props.onChange, filterFunction = props.filterFunction, inputProps = props.inputProps, dropdownMenuProps = props.dropdownMenuProps, _b = props.emptyStateMessage, emptyStateMessage = _b === void 0 ? 'No options found' : _b, itemRenderer = props.itemRenderer, _c = props.enableVirtualization, enableVirtualization = _c === void 0 ? false : _c, rest = __rest(props, ["options", "value", "onChange", "filterFunction", "inputProps", "dropdownMenuProps", "emptyStateMessage", "itemRenderer", "enableVirtualization"]);
65
+ var _a, _b;
66
+ var options = props.options, valueProp = props.value, onChange = props.onChange, filterFunction = props.filterFunction, inputProps = props.inputProps, dropdownMenuProps = props.dropdownMenuProps, _c = props.emptyStateMessage, emptyStateMessage = _c === void 0 ? 'No options found' : _c, itemRenderer = props.itemRenderer, _d = props.enableVirtualization, enableVirtualization = _d === void 0 ? false : _d, onShow = props.onShow, onHide = props.onHide, rest = __rest(props, ["options", "value", "onChange", "filterFunction", "inputProps", "dropdownMenuProps", "emptyStateMessage", "itemRenderer", "enableVirtualization", "onShow", "onHide"]);
67
67
  // Generate a stateful random id if not specified
68
68
  var id = react_1.default.useState(function () {
69
69
  var _a, _b;
@@ -95,12 +95,12 @@ var ComboBox = function (props) {
95
95
  });
96
96
  }
97
97
  // Reducer where all the component-wide state is stored
98
- var _d = react_1.default.useReducer(helpers_1.comboBoxReducer, {
98
+ var _e = react_1.default.useReducer(helpers_1.comboBoxReducer, {
99
99
  isOpen: false,
100
100
  selectedIndex: -1,
101
101
  focusedIndex: -1,
102
- }), _e = _d[0], isOpen = _e.isOpen, selectedIndex = _e.selectedIndex, focusedIndex = _e.focusedIndex, dispatch = _d[1];
103
- react_1.default.useEffect(function () {
102
+ }), _f = _e[0], isOpen = _f.isOpen, selectedIndex = _f.selectedIndex, focusedIndex = _f.focusedIndex, dispatch = _e[1];
103
+ react_1.default.useLayoutEffect(function () {
104
104
  var _a, _b;
105
105
  // When the dropdown opens
106
106
  if (isOpen) {
@@ -119,20 +119,30 @@ var ComboBox = function (props) {
119
119
  }
120
120
  }, [isOpen, options, selectedIndex]);
121
121
  // Set min-width of menu to be same as input
122
- var _f = react_1.default.useState(0), minWidth = _f[0], setMinWidth = _f[1];
122
+ var _g = react_1.default.useState(0), minWidth = _g[0], setMinWidth = _g[1];
123
123
  react_1.default.useEffect(function () {
124
124
  if (inputRef.current) {
125
125
  setMinWidth(inputRef.current.offsetWidth);
126
126
  }
127
127
  }, [isOpen]);
128
- // Initialize filtered options to the latest value options
129
- var _g = react_1.default.useState(options), filteredOptions = _g[0], setFilteredOptions = _g[1];
128
+ // Update filtered options to the latest value options according to input value
129
+ var _h = react_1.default.useState(options), filteredOptions = _h[0], setFilteredOptions = _h[1];
130
130
  react_1.default.useEffect(function () {
131
- setFilteredOptions(options);
131
+ var _a;
132
+ if (inputValue) {
133
+ setFilteredOptions((_a = filterFunction === null || filterFunction === void 0 ? void 0 : filterFunction(options, inputValue)) !== null && _a !== void 0 ? _a : options.filter(function (option) {
134
+ return option.label.toLowerCase().includes(inputValue.toLowerCase());
135
+ }));
136
+ }
137
+ else {
138
+ setFilteredOptions(options);
139
+ }
132
140
  dispatch(['focus']);
141
+ // Only need to call on options update
142
+ // eslint-disable-next-line react-hooks/exhaustive-deps
133
143
  }, [options]);
134
144
  // Filter options based on input value
135
- var _h = react_1.default.useState((_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.value) !== null && _a !== void 0 ? _a : ''), inputValue = _h[0], setInputValue = _h[1];
145
+ var _j = react_1.default.useState((_b = (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.value) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : ''), inputValue = _j[0], setInputValue = _j[1];
136
146
  var handleOnInput = react_1.default.useCallback(function (event) {
137
147
  var _a, _b;
138
148
  var value = event.currentTarget.value;
@@ -179,6 +189,7 @@ var ComboBox = function (props) {
179
189
  onClick: function (e) {
180
190
  var _a, _b;
181
191
  dispatch(['select', __originalIndex]);
192
+ dispatch(['close']);
182
193
  (_b = (_a = customItem.props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, e);
183
194
  },
184
195
  // ComboBox.MenuItem handles scrollIntoView, data-iui-index and iui-focused through context
@@ -193,8 +204,13 @@ var ComboBox = function (props) {
193
204
  el === null || el === void 0 ? void 0 : el.scrollIntoView({ block: 'nearest' });
194
205
  }
195
206
  }),
196
- })) : (react_1.default.createElement(ComboBoxMenuItem_1.ComboBoxMenuItem, __assign({ key: optionId, id: optionId }, option, { isSelected: selectedIndex === __originalIndex, onClick: function () { return dispatch(['select', __originalIndex]); }, index: __originalIndex, "data-iui-filtered-index": filteredIndex }), option.label));
207
+ })) : (react_1.default.createElement(ComboBoxMenuItem_1.ComboBoxMenuItem, __assign({ key: optionId, id: optionId }, option, { isSelected: selectedIndex === __originalIndex, onClick: function () {
208
+ dispatch(['select', __originalIndex]);
209
+ dispatch(['close']);
210
+ }, index: __originalIndex, "data-iui-filtered-index": filteredIndex }), option.label));
197
211
  }, [enableVirtualization, focusedIndex, id, itemRenderer, selectedIndex]);
212
+ var emptyContent = react_1.default.useMemo(function () { return (react_1.default.createElement(react_1.default.Fragment, null, react_1.default.isValidElement(emptyStateMessage) ? (emptyStateMessage) : (react_1.default.createElement(Menu_1.MenuExtraContent, null,
213
+ react_1.default.createElement(Typography_1.Text, { isMuted: true }, emptyStateMessage))))); }, [emptyStateMessage]);
198
214
  return (react_1.default.createElement(helpers_1.ComboBoxRefsContext.Provider, { value: { inputRef: inputRef, menuRef: menuRef, toggleButtonRef: toggleButtonRef, optionsExtraInfoRef: optionsExtraInfoRef } },
199
215
  react_1.default.createElement(helpers_1.ComboBoxActionContext.Provider, { value: dispatch },
200
216
  react_1.default.createElement(helpers_1.ComboBoxStateContext.Provider, { value: {
@@ -209,9 +225,10 @@ var ComboBox = function (props) {
209
225
  react_1.default.createElement(ComboBoxInputContainer_1.ComboBoxInputContainer, __assign({ disabled: inputProps === null || inputProps === void 0 ? void 0 : inputProps.disabled }, rest),
210
226
  react_1.default.createElement(ComboBoxInput_1.ComboBoxInput, __assign({ value: inputValue }, inputProps, { onChange: handleOnInput })),
211
227
  react_1.default.createElement(ComboBoxEndIcon_1.ComboBoxEndIcon, { disabled: inputProps === null || inputProps === void 0 ? void 0 : inputProps.disabled, isOpen: isOpen })),
212
- react_1.default.createElement(ComboBoxDropdown_1.ComboBoxDropdown, __assign({}, dropdownMenuProps),
213
- react_1.default.createElement(ComboBoxMenu_1.ComboBoxMenu, null, filteredOptions.length > 0 && !enableVirtualization ? (filteredOptions.map(getMenuItem)) : (react_1.default.createElement(Menu_1.MenuExtraContent, null,
214
- react_1.default.createElement(Typography_1.Text, { isMuted: true }, emptyStateMessage)))))))));
228
+ react_1.default.createElement(ComboBoxDropdown_1.ComboBoxDropdown, __assign({}, dropdownMenuProps, { onShow: onShow, onHide: onHide }),
229
+ react_1.default.createElement(ComboBoxMenu_1.ComboBoxMenu, null, filteredOptions.length > 0 && !enableVirtualization
230
+ ? filteredOptions.map(getMenuItem)
231
+ : emptyContent))))));
215
232
  };
216
233
  exports.ComboBox = ComboBox;
217
234
  exports.default = exports.ComboBox;
@@ -118,6 +118,7 @@ exports.ComboBoxInput = react_1.default.forwardRef(function (props, forwardedRef
118
118
  event.preventDefault();
119
119
  if (isOpen) {
120
120
  dispatch(['select', focusedIndexRef.current]);
121
+ dispatch(['close']);
121
122
  }
122
123
  else {
123
124
  dispatch(['open']);
@@ -31,7 +31,7 @@ var comboBoxReducer = function (state, _a) {
31
31
  return __assign(__assign({}, state), { isOpen: false });
32
32
  }
33
33
  case 'select': {
34
- return __assign(__assign({}, state), { isOpen: false, selectedIndex: value !== null && value !== void 0 ? value : state.selectedIndex, focusedIndex: value !== null && value !== void 0 ? value : state.focusedIndex });
34
+ return __assign(__assign({}, state), { selectedIndex: value !== null && value !== void 0 ? value : state.selectedIndex, focusedIndex: value !== null && value !== void 0 ? value : state.focusedIndex });
35
35
  }
36
36
  case 'focus': {
37
37
  return __assign(__assign({}, state), { focusedIndex: (_b = value !== null && value !== void 0 ? value : state.selectedIndex) !== null && _b !== void 0 ? _b : -1 });
@@ -0,0 +1,32 @@
1
+ /// <reference types="react" />
2
+ import { CommonProps } from '../utils';
3
+ import '@itwin/itwinui-css/css/menu.css';
4
+ export declare type MenuItemSkeletonProps = {
5
+ /**
6
+ * Flag whether to show skeleton for sub-label.
7
+ */
8
+ hasSublabel?: boolean;
9
+ /**
10
+ * Flag whether to show skeleton for icon.
11
+ */
12
+ hasIcon?: boolean;
13
+ /**
14
+ * Skeleton content width.
15
+ */
16
+ contentWidth?: string;
17
+ /**
18
+ * Translated strings used for accessibility.
19
+ */
20
+ translatedStrings?: {
21
+ /**
22
+ * Label for loading state. Defaults to "Loading…".
23
+ * It is only visible for the screen readers.
24
+ */
25
+ loading: string;
26
+ };
27
+ } & CommonProps;
28
+ /**
29
+ * Menu item that uses skeletons to indicate loading state.
30
+ */
31
+ export declare const MenuItemSkeleton: (props: MenuItemSkeletonProps) => JSX.Element;
32
+ export default MenuItemSkeleton;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __rest = (this && this.__rest) || function (s, e) {
14
+ var t = {};
15
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
16
+ t[p] = s[p];
17
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
18
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
19
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
20
+ t[p[i]] = s[p[i]];
21
+ }
22
+ return t;
23
+ };
24
+ var __importDefault = (this && this.__importDefault) || function (mod) {
25
+ return (mod && mod.__esModule) ? mod : { "default": mod };
26
+ };
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.MenuItemSkeleton = void 0;
29
+ /*---------------------------------------------------------------------------------------------
30
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
31
+ * See LICENSE.md in the project root for license terms and full copyright notice.
32
+ *--------------------------------------------------------------------------------------------*/
33
+ var react_1 = __importDefault(require("react"));
34
+ var classnames_1 = __importDefault(require("classnames"));
35
+ var utils_1 = require("../utils");
36
+ require("@itwin/itwinui-css/css/menu.css");
37
+ /**
38
+ * Menu item that uses skeletons to indicate loading state.
39
+ */
40
+ var MenuItemSkeleton = function (props) {
41
+ var hasSublabel = props.hasSublabel, hasIcon = props.hasIcon, contentWidth = props.contentWidth, _a = props.translatedStrings, translatedStrings = _a === void 0 ? { loading: 'Loading…' } : _a, className = props.className, style = props.style, rest = __rest(props, ["hasSublabel", "hasIcon", "contentWidth", "translatedStrings", "className", "style"]);
42
+ (0, utils_1.useTheme)();
43
+ return (react_1.default.createElement("li", __assign({ className: (0, classnames_1.default)('iui-menu-item', 'iui-menu-item-skeleton', { 'iui-large': hasSublabel }, className), style: __assign({
44
+ '--iui-menu-item-content-skeleton-max-width': contentWidth,
45
+ }, style) }, rest),
46
+ hasIcon && react_1.default.createElement("div", { className: 'iui-icon iui-skeleton', "aria-hidden": true }),
47
+ react_1.default.createElement("span", { className: 'iui-content' },
48
+ react_1.default.createElement("div", { className: 'iui-menu-label iui-skeleton', "aria-hidden": true }),
49
+ hasSublabel && (react_1.default.createElement("div", { className: 'iui-menu-description iui-skeleton', "aria-hidden": true })),
50
+ react_1.default.createElement(utils_1.VisuallyHidden, null, translatedStrings.loading))));
51
+ };
52
+ exports.MenuItemSkeleton = MenuItemSkeleton;
53
+ exports.default = exports.MenuItemSkeleton;
@@ -6,3 +6,5 @@ export { MenuDivider } from './MenuDivider';
6
6
  export type { MenuDividerProps } from './MenuDivider';
7
7
  export { MenuExtraContent } from './MenuExtraContent';
8
8
  export type { MenuExtraContentProps } from './MenuExtraContent';
9
+ export { MenuItemSkeleton } from './MenuItemSkeleton';
10
+ export type { MenuItemSkeletonProps } from './MenuItemSkeleton';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MenuExtraContent = exports.MenuDivider = exports.MenuItem = exports.Menu = void 0;
3
+ exports.MenuItemSkeleton = exports.MenuExtraContent = exports.MenuDivider = exports.MenuItem = exports.Menu = void 0;
4
4
  /*---------------------------------------------------------------------------------------------
5
5
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
6
6
  * See LICENSE.md in the project root for license terms and full copyright notice.
@@ -13,3 +13,5 @@ var MenuDivider_1 = require("./MenuDivider");
13
13
  Object.defineProperty(exports, "MenuDivider", { enumerable: true, get: function () { return MenuDivider_1.MenuDivider; } });
14
14
  var MenuExtraContent_1 = require("./MenuExtraContent");
15
15
  Object.defineProperty(exports, "MenuExtraContent", { enumerable: true, get: function () { return MenuExtraContent_1.MenuExtraContent; } });
16
+ var MenuItemSkeleton_1 = require("./MenuItemSkeleton");
17
+ Object.defineProperty(exports, "MenuItemSkeleton", { enumerable: true, get: function () { return MenuItemSkeleton_1.MenuItemSkeleton; } });
@@ -177,8 +177,8 @@ var Table = function (props) {
177
177
  return getSubRows ? getSubRows(item, index) : item.subRows;
178
178
  });
179
179
  }, [data, getSubRows]);
180
- var instance = (0, react_table_1.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) }), react_table_1.useFlexLayout, (0, hooks_1.useResizeColumns)(ownerDocument), react_table_1.useFilters, (0, hooks_1.useSubRowFiltering)(hasAnySubRows), react_table_1.useSortBy, react_table_1.useExpanded, react_table_1.usePagination, react_table_1.useRowSelect, hooks_1.useSubRowSelection, (0, hooks_1.useExpanderCell)(subComponent, expanderCell, isRowDisabled), (0, hooks_1.useSelectionCell)(isSelectable, selectionMode, isRowDisabled), react_table_1.useColumnOrder, (0, hooks_1.useColumnDragAndDrop)(enableColumnReordering));
181
- 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;
180
+ var instance = (0, react_table_1.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) }), react_table_1.useFlexLayout, (0, hooks_1.useResizeColumns)(ownerDocument), react_table_1.useFilters, (0, hooks_1.useSubRowFiltering)(hasAnySubRows), react_table_1.useSortBy, react_table_1.useExpanded, react_table_1.usePagination, react_table_1.useRowSelect, hooks_1.useSubRowSelection, (0, hooks_1.useExpanderCell)(subComponent, expanderCell, isRowDisabled), (0, hooks_1.useSelectionCell)(isSelectable, selectionMode, isRowDisabled), react_table_1.useColumnOrder, (0, hooks_1.useColumnDragAndDrop)(enableColumnReordering), hooks_1.useStickyColumns);
181
+ 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, visibleColumns = instance.visibleColumns;
182
182
  var ariaDataAttributes = Object.entries(rest).reduce(function (result, _a) {
183
183
  var key = _a[0], value = _a[1];
184
184
  if (key.startsWith('data-') || key.startsWith('aria-')) {
@@ -293,6 +293,30 @@ var Table = function (props) {
293
293
  subComponent,
294
294
  ]);
295
295
  var virtualizedItemRenderer = react_1.default.useCallback(function (index) { return getPreparedRow(index); }, [getPreparedRow]);
296
+ var updateStickyState = function () {
297
+ if (!bodyRef.current || flatHeaders.every(function (header) { return !header.sticky; })) {
298
+ return;
299
+ }
300
+ if (bodyRef.current.scrollLeft !== 0) {
301
+ dispatch({ type: react_table_1.actions.setScrolledRight, value: true });
302
+ }
303
+ else {
304
+ dispatch({ type: react_table_1.actions.setScrolledRight, value: false });
305
+ }
306
+ // If scrolled a bit to the left looking from the right side
307
+ if (bodyRef.current.scrollLeft !==
308
+ bodyRef.current.scrollWidth - bodyRef.current.clientWidth) {
309
+ dispatch({ type: react_table_1.actions.setScrolledLeft, value: true });
310
+ }
311
+ else {
312
+ dispatch({ type: react_table_1.actions.setScrolledLeft, value: false });
313
+ }
314
+ };
315
+ react_1.default.useEffect(function () {
316
+ updateStickyState();
317
+ // Call only on init
318
+ // eslint-disable-next-line react-hooks/exhaustive-deps
319
+ }, []);
296
320
  return (react_1.default.createElement(react_1.default.Fragment, null,
297
321
  react_1.default.createElement("div", __assign({ ref: function (element) {
298
322
  setOwnerDocument(element === null || element === void 0 ? void 0 : element.ownerDocument);
@@ -301,7 +325,7 @@ var Table = function (props) {
301
325
  }
302
326
  }, id: id }, getTableProps({
303
327
  className: (0, classnames_1.default)('iui-table', (_a = {}, _a["iui-".concat(density)] = density !== 'default', _a), className),
304
- style: style,
328
+ style: __assign({ minWidth: 0 }, style),
305
329
  }), ariaDataAttributes),
306
330
  react_1.default.createElement("div", { className: 'iui-table-header-wrapper', ref: headerRef },
307
331
  react_1.default.createElement("div", { className: 'iui-table-header' }, headerGroups.slice(1).map(function (headerGroup) {
@@ -309,9 +333,13 @@ var Table = function (props) {
309
333
  className: 'iui-row',
310
334
  });
311
335
  return (react_1.default.createElement("div", __assign({}, headerGroupProps, { key: headerGroupProps.key }), headerGroup.headers.map(function (column, index) {
312
- var columnProps = column.getHeaderProps(__assign(__assign({}, column.getSortByToggleProps()), { className: (0, classnames_1.default)('iui-cell', { 'iui-actionable': column.canSort }, { 'iui-sorted': column.isSorted }, column.columnClassName), style: (0, utils_2.getCellStyle)(column, !!state.isTableResizing) }));
336
+ var columnProps = column.getHeaderProps(__assign(__assign({}, column.getSortByToggleProps()), { className: (0, classnames_1.default)('iui-cell', {
337
+ 'iui-actionable': column.canSort,
338
+ 'iui-sorted': column.isSorted,
339
+ 'iui-cell-sticky': !!column.sticky,
340
+ }, column.columnClassName), style: __assign(__assign(__assign({}, (0, utils_2.getCellStyle)(column, !!state.isTableResizing)), (0, utils_2.getStickyStyle)(column, visibleColumns)), { flexWrap: 'unset' }) }));
313
341
  return (react_1.default.createElement("div", __assign({}, columnProps, column.getDragAndDropProps(), { key: columnProps.key, title: undefined, ref: function (el) {
314
- if (el && isResizable) {
342
+ if (el) {
315
343
  columnRefs.current[column.id] = el;
316
344
  column.resizeWidth = el.getBoundingClientRect().width;
317
345
  }
@@ -326,7 +354,11 @@ var Table = function (props) {
326
354
  index !== headerGroup.headers.length - 1 && (react_1.default.createElement("div", __assign({}, column.getResizerProps(), { className: 'iui-resizer' }),
327
355
  react_1.default.createElement("div", { className: 'iui-resizer-bar' }))),
328
356
  enableColumnReordering &&
329
- !column.disableReordering && (react_1.default.createElement("div", { className: 'iui-reorder-bar' }))));
357
+ !column.disableReordering && (react_1.default.createElement("div", { className: 'iui-reorder-bar' })),
358
+ column.sticky === 'left' &&
359
+ state.sticky.isScrolledToRight && (react_1.default.createElement("div", { className: 'iui-cell-shadow-right' })),
360
+ column.sticky === 'right' &&
361
+ state.sticky.isScrolledToLeft && (react_1.default.createElement("div", { className: 'iui-cell-shadow-left' }))));
330
362
  })));
331
363
  }))),
332
364
  react_1.default.createElement("div", __assign({}, getTableBodyProps({
@@ -337,6 +369,7 @@ var Table = function (props) {
337
369
  }), { ref: bodyRef, onScroll: function () {
338
370
  if (headerRef.current && bodyRef.current) {
339
371
  headerRef.current.scrollLeft = bodyRef.current.scrollLeft;
372
+ updateStickyState();
340
373
  }
341
374
  }, tabIndex: -1 }),
342
375
  data.length !== 0 && (react_1.default.createElement(react_1.default.Fragment, null, enableVirtualization ? (react_1.default.createElement(VirtualScroll_1.default, { itemsLength: page.length, itemRenderer: virtualizedItemRenderer })) : (page.map(function (_, index) { return getPreparedRow(index); })))),
@@ -40,8 +40,10 @@ var TableCell = function (props) {
40
40
  };
41
41
  };
42
42
  var cellElementProps = cell.getCellProps({
43
- className: (0, classnames_1.default)('iui-cell', cell.column.cellClassName),
44
- style: __assign(__assign({}, (0, utils_1.getCellStyle)(cell.column, !!tableInstance.state.isTableResizing)), getSubRowStyle()),
43
+ className: (0, classnames_1.default)('iui-cell', cell.column.cellClassName, {
44
+ 'iui-cell-sticky': !!cell.column.sticky,
45
+ }),
46
+ style: __assign(__assign(__assign({}, (0, utils_1.getCellStyle)(cell.column, !!tableInstance.state.isTableResizing)), getSubRowStyle()), (0, utils_1.getStickyStyle)(cell.column, tableInstance.visibleColumns)),
45
47
  });
46
48
  var cellProps = __assign(__assign({}, tableInstance), { cell: cell, row: cell.row, value: cell.value, column: cell.column });
47
49
  var cellContent = (react_1.default.createElement(react_1.default.Fragment, null,
@@ -50,7 +52,12 @@ var TableCell = function (props) {
50
52
  var cellRendererProps = {
51
53
  cellElementProps: cellElementProps,
52
54
  cellProps: cellProps,
53
- children: cellContent,
55
+ children: (react_1.default.createElement(react_1.default.Fragment, null,
56
+ cellContent,
57
+ cell.column.sticky === 'left' &&
58
+ tableInstance.state.sticky.isScrolledToRight && (react_1.default.createElement("div", { className: 'iui-cell-shadow-right' })),
59
+ cell.column.sticky === 'right' &&
60
+ tableInstance.state.sticky.isScrolledToLeft && (react_1.default.createElement("div", { className: 'iui-cell-shadow-left' })))),
54
61
  };
55
62
  return (react_1.default.createElement(react_1.default.Fragment, null, cell.column.cellRenderer ? (cell.column.cellRenderer(__assign(__assign({}, cellRendererProps), { isDisabled: function () { return isDisabled; } }))) : (react_1.default.createElement(cells_1.DefaultCell, __assign({}, cellRendererProps, { isDisabled: function () { return isDisabled; } })))));
56
63
  };
@@ -99,5 +99,9 @@ exports.TableRowMemoized = react_1.default.memo(exports.TableRow, function (prev
99
99
  prevProp.tableHasSubRows === nextProp.tableHasSubRows &&
100
100
  prevProp.state.columnOrder === nextProp.state.columnOrder &&
101
101
  !nextProp.state.columnResizing.isResizingColumn &&
102
- prevProp.state.isTableResizing === nextProp.state.isTableResizing;
102
+ prevProp.state.isTableResizing === nextProp.state.isTableResizing &&
103
+ prevProp.state.sticky.isScrolledToLeft ===
104
+ nextProp.state.sticky.isScrolledToLeft &&
105
+ prevProp.state.sticky.isScrolledToRight ===
106
+ nextProp.state.sticky.isScrolledToRight;
103
107
  });
@@ -12,6 +12,10 @@ export declare const onTableResizeStart: <T extends Record<string, unknown>>(sta
12
12
  isResizingColumn?: string | undefined;
13
13
  };
14
14
  columnReorderStartIndex: number;
15
+ sticky: {
16
+ isScrolledToRight?: boolean | undefined;
17
+ isScrolledToLeft?: boolean | undefined;
18
+ };
15
19
  columnOrder: import("react-table").IdType<T>[];
16
20
  expanded: Record<import("react-table").IdType<T>, boolean>;
17
21
  filters: import("react-table").Filters<T>;
@@ -38,6 +42,10 @@ export declare const onTableResizeEnd: <T extends Record<string, unknown>>(state
38
42
  };
39
43
  hiddenColumns?: import("react-table").IdType<T>[] | undefined;
40
44
  columnReorderStartIndex: number;
45
+ sticky: {
46
+ isScrolledToRight?: boolean | undefined;
47
+ isScrolledToLeft?: boolean | undefined;
48
+ };
41
49
  columnOrder: import("react-table").IdType<T>[];
42
50
  expanded: Record<import("react-table").IdType<T>, boolean>;
43
51
  filters: import("react-table").Filters<T>;
@@ -20,6 +20,10 @@ export declare const onSingleSelectHandler: <T extends Record<string, unknown>>(
20
20
  };
21
21
  isTableResizing?: boolean | undefined;
22
22
  columnReorderStartIndex: number;
23
+ sticky: {
24
+ isScrolledToRight?: boolean | undefined;
25
+ isScrolledToLeft?: boolean | undefined;
26
+ };
23
27
  columnOrder: import("react-table").IdType<T>[];
24
28
  expanded: Record<import("react-table").IdType<T>, boolean>;
25
29
  filters: import("react-table").Filters<T>;
@@ -55,11 +55,13 @@ var SelectionColumn = function (props) {
55
55
  var getToggleAllRowsSelectedProps = _a.getToggleAllRowsSelectedProps, rows = _a.rows, initialRows = _a.initialRows, state = _a.state;
56
56
  var disabled = rows.every(function (row) { return isDisabled === null || isDisabled === void 0 ? void 0 : isDisabled(row.original); });
57
57
  var checked = initialRows.every(function (row) { return state.selectedRowIds[row.id] || (isDisabled === null || isDisabled === void 0 ? void 0 : isDisabled(row.original)); });
58
- return (react_1.default.createElement(Checkbox_1.Checkbox, __assign({}, getToggleAllRowsSelectedProps(), { style: {}, checked: checked && !disabled, indeterminate: !checked && Object.keys(state.selectedRowIds).length > 0, disabled: disabled })));
58
+ return (react_1.default.createElement(Checkbox_1.Checkbox, __assign({}, getToggleAllRowsSelectedProps(), { style: {}, title: '' // Removes default title that comes from react-table
59
+ , checked: checked && !disabled, indeterminate: !checked && Object.keys(state.selectedRowIds).length > 0, disabled: disabled })));
59
60
  },
60
61
  Cell: function (_a) {
61
62
  var row = _a.row;
62
- return (react_1.default.createElement(Checkbox_1.Checkbox, __assign({}, row.getToggleRowSelectedProps(), { style: {}, disabled: isDisabled === null || isDisabled === void 0 ? void 0 : isDisabled(row.original), onClick: function (e) { return e.stopPropagation(); } })));
63
+ return (react_1.default.createElement(Checkbox_1.Checkbox, __assign({}, row.getToggleRowSelectedProps(), { style: {}, title: '' // Removes default title that comes from react-table
64
+ , disabled: isDisabled === null || isDisabled === void 0 ? void 0 : isDisabled(row.original), onClick: function (e) { return e.stopPropagation(); } })));
63
65
  },
64
66
  cellRenderer: function (props) { return (react_1.default.createElement(cells_1.DefaultCell, __assign({}, props, { isDisabled: function (rowData) { return !!(isDisabled === null || isDisabled === void 0 ? void 0 : isDisabled(rowData)); } }))); },
65
67
  };
@@ -4,3 +4,4 @@ export { useSubRowFiltering } from './useSubRowFiltering';
4
4
  export { useSubRowSelection } from './useSubRowSelection';
5
5
  export { useResizeColumns } from './useResizeColumns';
6
6
  export { useColumnDragAndDrop } from './useColumnDragAndDrop';
7
+ export { useStickyColumns } from './useStickyColumns';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useColumnDragAndDrop = exports.useResizeColumns = exports.useSubRowSelection = exports.useSubRowFiltering = exports.useSelectionCell = exports.useExpanderCell = void 0;
3
+ exports.useStickyColumns = exports.useColumnDragAndDrop = exports.useResizeColumns = exports.useSubRowSelection = exports.useSubRowFiltering = exports.useSelectionCell = exports.useExpanderCell = void 0;
4
4
  /*---------------------------------------------------------------------------------------------
5
5
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
6
6
  * See LICENSE.md in the project root for license terms and full copyright notice.
@@ -17,3 +17,5 @@ var useResizeColumns_1 = require("./useResizeColumns");
17
17
  Object.defineProperty(exports, "useResizeColumns", { enumerable: true, get: function () { return useResizeColumns_1.useResizeColumns; } });
18
18
  var useColumnDragAndDrop_1 = require("./useColumnDragAndDrop");
19
19
  Object.defineProperty(exports, "useColumnDragAndDrop", { enumerable: true, get: function () { return useColumnDragAndDrop_1.useColumnDragAndDrop; } });
20
+ var useStickyColumns_1 = require("./useStickyColumns");
21
+ Object.defineProperty(exports, "useStickyColumns", { enumerable: true, get: function () { return useStickyColumns_1.useStickyColumns; } });
@@ -0,0 +1,2 @@
1
+ import { Hooks } from 'react-table';
2
+ export declare const useStickyColumns: <T extends Record<string, unknown>>(hooks: Hooks<T>) => void;
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
14
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
15
+ if (ar || !(i in from)) {
16
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
17
+ ar[i] = from[i];
18
+ }
19
+ }
20
+ return to.concat(ar || Array.prototype.slice.call(from));
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.useStickyColumns = void 0;
24
+ /*---------------------------------------------------------------------------------------------
25
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
26
+ * See LICENSE.md in the project root for license terms and full copyright notice.
27
+ *--------------------------------------------------------------------------------------------*/
28
+ var react_table_1 = require("react-table");
29
+ react_table_1.actions.setScrolledLeft = 'setScrolledLeft';
30
+ react_table_1.actions.setScrolledRight = 'setScrolledRight';
31
+ var useStickyColumns = function (hooks) {
32
+ hooks.stateReducers.push(reducer);
33
+ hooks.useInstance.push(useInstance);
34
+ };
35
+ exports.useStickyColumns = useStickyColumns;
36
+ var reducer = function (newState, action) {
37
+ var _a, _b;
38
+ if (action.type === react_table_1.actions.init) {
39
+ return __assign(__assign({}, newState), { sticky: {} });
40
+ }
41
+ if (action.type === react_table_1.actions.setScrolledLeft &&
42
+ ((_a = newState.sticky) === null || _a === void 0 ? void 0 : _a.isScrolledToLeft) !== action.value // Prevents unnecessary re-render
43
+ ) {
44
+ return __assign(__assign({}, newState), { sticky: __assign(__assign({}, newState.sticky), { isScrolledToLeft: action.value }) });
45
+ }
46
+ if (action.type === react_table_1.actions.setScrolledRight &&
47
+ ((_b = newState.sticky) === null || _b === void 0 ? void 0 : _b.isScrolledToRight) !== action.value // Prevents unnecessary re-render
48
+ ) {
49
+ return __assign(__assign({}, newState), { sticky: __assign(__assign({}, newState.sticky), { isScrolledToRight: action.value }) });
50
+ }
51
+ return newState;
52
+ };
53
+ var useInstance = function (instance) {
54
+ var flatHeaders = instance.flatHeaders;
55
+ // Edge case. Saving original sticky state in case sticky columns are reordered.
56
+ flatHeaders.forEach(function (header) {
57
+ var _a;
58
+ if (!header.originalSticky) {
59
+ header.originalSticky = (_a = header.sticky) !== null && _a !== void 0 ? _a : 'none';
60
+ }
61
+ header.sticky =
62
+ header.originalSticky === 'none' ? undefined : header.originalSticky;
63
+ });
64
+ // If there is a column that is sticked to the left, make every column prior to that sticky too.
65
+ var hasLeftStickyColumn = false;
66
+ __spreadArray([], flatHeaders, true).reverse().forEach(function (header) {
67
+ if (header.sticky === 'left') {
68
+ hasLeftStickyColumn = true;
69
+ }
70
+ if (hasLeftStickyColumn) {
71
+ header.sticky = 'left';
72
+ }
73
+ });
74
+ // If there is a column that is sticked to the right, make every column after to that sticky too.
75
+ var hasRightStickyColumn = false;
76
+ flatHeaders.forEach(function (header) {
77
+ if (header.sticky === 'right') {
78
+ hasRightStickyColumn = true;
79
+ }
80
+ if (hasRightStickyColumn) {
81
+ header.sticky = 'right';
82
+ }
83
+ });
84
+ };
@@ -1,2 +1,3 @@
1
1
  import { ColumnInstance } from 'react-table';
2
2
  export declare const getCellStyle: <T extends Record<string, unknown>>(column: ColumnInstance<T>, isTableResizing: boolean) => React.CSSProperties | undefined;
3
+ export declare const getStickyStyle: <T extends Record<string, unknown>>(column: ColumnInstance<T>, columnList: ColumnInstance<T>[]) => React.CSSProperties;
@@ -1,6 +1,15 @@
1
1
  "use strict";
2
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
3
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
4
+ if (ar || !(i in from)) {
5
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
6
+ ar[i] = from[i];
7
+ }
8
+ }
9
+ return to.concat(ar || Array.prototype.slice.call(from));
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getCellStyle = void 0;
12
+ exports.getStickyStyle = exports.getCellStyle = void 0;
4
13
  var getCellStyle = function (column, isTableResizing) {
5
14
  var style = {};
6
15
  style.flex = "1 1 145px";
@@ -24,3 +33,29 @@ var getCellStyle = function (column, isTableResizing) {
24
33
  return style;
25
34
  };
26
35
  exports.getCellStyle = getCellStyle;
36
+ var getStickyStyle = function (column, columnList) {
37
+ if (!column.sticky) {
38
+ return {};
39
+ }
40
+ var left = 0;
41
+ for (var _i = 0, columnList_1 = columnList; _i < columnList_1.length; _i++) {
42
+ var col = columnList_1[_i];
43
+ if (col.id === column.id) {
44
+ break;
45
+ }
46
+ left += Number(col.width || col.resizeWidth || 0);
47
+ }
48
+ var right = 0;
49
+ for (var _a = 0, _b = __spreadArray([], columnList, true).reverse(); _a < _b.length; _a++) {
50
+ var col = _b[_a];
51
+ if (col.id === column.id) {
52
+ break;
53
+ }
54
+ right += Number(col.width || col.resizeWidth || 0);
55
+ }
56
+ return {
57
+ '--iui-table-sticky-left': column.sticky === 'left' ? "".concat(left, "px") : undefined,
58
+ '--iui-table-sticky-right': column.sticky === 'right' ? "".concat(right, "px") : undefined,
59
+ };
60
+ };
61
+ exports.getStickyStyle = getStickyStyle;