@itwin/itwinui-react 1.38.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.
- package/CHANGELOG.md +30 -0
- package/cjs/core/Carousel/Carousel.js +21 -12
- package/cjs/core/Carousel/CarouselContext.d.ts +4 -2
- package/cjs/core/Carousel/CarouselDotsList.js +1 -0
- package/cjs/core/Carousel/CarouselNavigation.js +8 -10
- package/cjs/core/Carousel/CarouselSlide.js +3 -7
- package/cjs/core/Carousel/CarouselSlider.js +23 -28
- package/cjs/core/ColorPicker/ColorPickerContext.d.ts +2 -2
- package/cjs/core/ComboBox/ComboBox.d.ts +17 -1
- package/cjs/core/ComboBox/ComboBox.js +50 -24
- package/cjs/core/ComboBox/ComboBoxDropdown.d.ts +5 -6
- package/cjs/core/ComboBox/ComboBoxInput.js +28 -9
- package/cjs/core/ComboBox/ComboBoxMenu.js +46 -2
- package/cjs/core/ComboBox/ComboBoxMenuItem.js +2 -3
- package/cjs/core/ComboBox/helpers.d.ts +8 -3
- package/cjs/core/ComboBox/helpers.js +1 -1
- package/cjs/core/DatePicker/DatePicker.d.ts +1 -1
- package/cjs/core/Menu/MenuItemSkeleton.d.ts +32 -0
- package/cjs/core/Menu/MenuItemSkeleton.js +53 -0
- package/cjs/core/Menu/index.d.ts +2 -0
- package/cjs/core/Menu/index.js +3 -1
- package/cjs/core/Select/Select.js +1 -1
- package/cjs/core/Table/Table.js +68 -25
- package/cjs/core/Table/TableCell.js +10 -3
- package/cjs/core/Table/TablePaginator.js +1 -1
- package/cjs/core/Table/TableRowMemoized.js +5 -1
- package/cjs/core/Table/actionHandlers/resizeHandler.d.ts +8 -0
- package/cjs/core/Table/actionHandlers/selectHandler.d.ts +4 -0
- package/cjs/core/Table/columns/selectionColumn.js +4 -2
- package/cjs/core/Table/filters/tableFilters.d.ts +3 -3
- package/cjs/core/Table/hooks/index.d.ts +1 -0
- package/cjs/core/Table/hooks/index.js +3 -1
- package/cjs/core/Table/hooks/useExpanderCell.js +11 -1
- package/cjs/core/Table/hooks/useStickyColumns.d.ts +2 -0
- package/cjs/core/Table/hooks/useStickyColumns.js +84 -0
- package/cjs/core/Table/utils.d.ts +1 -0
- package/cjs/core/Table/utils.js +36 -1
- package/cjs/core/Toast/Toaster.d.ts +1 -1
- package/cjs/core/Toast/Toaster.js +72 -29
- package/cjs/core/index.d.ts +2 -2
- package/cjs/core/index.js +4 -3
- package/cjs/core/utils/components/Popover.d.ts +1 -18
- package/cjs/core/utils/components/VirtualScroll.d.ts +35 -1
- package/cjs/core/utils/components/VirtualScroll.js +159 -26
- package/cjs/core/utils/components/VisuallyHidden.d.ts +9 -0
- package/cjs/core/utils/components/VisuallyHidden.js +44 -0
- package/cjs/core/utils/components/WithCSSTransition.d.ts +1 -2
- package/cjs/core/utils/components/icons.d.ts +4 -4
- package/cjs/core/utils/components/index.d.ts +1 -0
- package/cjs/core/utils/components/index.js +1 -0
- package/cjs/core/utils/hooks/useOverflow.js +4 -2
- package/cjs/core/utils/hooks/useTheme.d.ts +1 -1
- package/cjs/types/react-table-config.d.ts +9 -0
- package/esm/core/Carousel/Carousel.js +21 -12
- package/esm/core/Carousel/CarouselContext.d.ts +4 -2
- package/esm/core/Carousel/CarouselDotsList.js +1 -0
- package/esm/core/Carousel/CarouselNavigation.js +8 -10
- package/esm/core/Carousel/CarouselSlide.js +3 -7
- package/esm/core/Carousel/CarouselSlider.js +24 -29
- package/esm/core/ColorPicker/ColorPickerContext.d.ts +2 -2
- package/esm/core/ComboBox/ComboBox.d.ts +17 -1
- package/esm/core/ComboBox/ComboBox.js +50 -24
- package/esm/core/ComboBox/ComboBoxDropdown.d.ts +5 -6
- package/esm/core/ComboBox/ComboBoxInput.js +28 -9
- package/esm/core/ComboBox/ComboBoxMenu.js +47 -3
- package/esm/core/ComboBox/ComboBoxMenuItem.js +2 -3
- package/esm/core/ComboBox/helpers.d.ts +8 -3
- package/esm/core/ComboBox/helpers.js +1 -1
- package/esm/core/DatePicker/DatePicker.d.ts +1 -1
- package/esm/core/Menu/MenuItemSkeleton.d.ts +32 -0
- package/esm/core/Menu/MenuItemSkeleton.js +46 -0
- package/esm/core/Menu/index.d.ts +2 -0
- package/esm/core/Menu/index.js +1 -0
- package/esm/core/Select/Select.js +1 -1
- package/esm/core/Table/Table.js +70 -27
- package/esm/core/Table/TableCell.js +11 -4
- package/esm/core/Table/TablePaginator.js +1 -1
- package/esm/core/Table/TableRowMemoized.js +5 -1
- package/esm/core/Table/actionHandlers/resizeHandler.d.ts +8 -0
- package/esm/core/Table/actionHandlers/selectHandler.d.ts +4 -0
- package/esm/core/Table/columns/selectionColumn.js +4 -2
- package/esm/core/Table/filters/tableFilters.d.ts +3 -3
- package/esm/core/Table/hooks/index.d.ts +1 -0
- package/esm/core/Table/hooks/index.js +1 -0
- package/esm/core/Table/hooks/useExpanderCell.js +8 -1
- package/esm/core/Table/hooks/useStickyColumns.d.ts +2 -0
- package/esm/core/Table/hooks/useStickyColumns.js +80 -0
- package/esm/core/Table/utils.d.ts +1 -0
- package/esm/core/Table/utils.js +34 -0
- package/esm/core/Toast/Toaster.d.ts +1 -1
- package/esm/core/Toast/Toaster.js +50 -30
- package/esm/core/index.d.ts +2 -2
- package/esm/core/index.js +1 -1
- package/esm/core/utils/components/Popover.d.ts +1 -18
- package/esm/core/utils/components/VirtualScroll.d.ts +35 -1
- package/esm/core/utils/components/VirtualScroll.js +157 -25
- package/esm/core/utils/components/VisuallyHidden.d.ts +9 -0
- package/esm/core/utils/components/VisuallyHidden.js +38 -0
- package/esm/core/utils/components/WithCSSTransition.d.ts +1 -2
- package/esm/core/utils/components/icons.d.ts +4 -4
- package/esm/core/utils/components/index.d.ts +1 -0
- package/esm/core/utils/components/index.js +1 -0
- package/esm/core/utils/hooks/useOverflow.js +4 -2
- package/esm/core/utils/hooks/useTheme.d.ts +1 -1
- package/esm/types/react-table-config.d.ts +9 -0
- package/package.json +24 -39
|
@@ -5,7 +5,7 @@ export declare const ColorPickerContext: React.Context<{
|
|
|
5
5
|
setActiveColor: (color: ColorValue | ((prevColor: ColorValue) => ColorValue)) => void;
|
|
6
6
|
hsvColor: HsvColor;
|
|
7
7
|
onChangeComplete?: ((color: ColorValue) => void) | undefined;
|
|
8
|
-
applyHsvColorChange: (newColor: HsvColor, selectionChanged: boolean, newColorValue?: ColorValue
|
|
8
|
+
applyHsvColorChange: (newColor: HsvColor, selectionChanged: boolean, newColorValue?: ColorValue) => void;
|
|
9
9
|
showAlpha: boolean;
|
|
10
10
|
} | undefined>;
|
|
11
11
|
export declare const useColorPickerContext: () => {
|
|
@@ -13,6 +13,6 @@ export declare const useColorPickerContext: () => {
|
|
|
13
13
|
setActiveColor: (color: ColorValue | ((prevColor: ColorValue) => ColorValue)) => void;
|
|
14
14
|
hsvColor: HsvColor;
|
|
15
15
|
onChangeComplete?: ((color: ColorValue) => void) | undefined;
|
|
16
|
-
applyHsvColorChange: (newColor: HsvColor, selectionChanged: boolean, newColorValue?: ColorValue
|
|
16
|
+
applyHsvColorChange: (newColor: HsvColor, selectionChanged: boolean, newColorValue?: ColorValue) => void;
|
|
17
17
|
showAlpha: boolean;
|
|
18
18
|
};
|
|
@@ -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?:
|
|
41
|
+
emptyStateMessage?: React.ReactNode;
|
|
41
42
|
/**
|
|
42
43
|
* A custom item renderer can be specified to control the rendering.
|
|
43
44
|
*
|
|
@@ -51,6 +52,21 @@ export declare type ComboBoxProps<T> = {
|
|
|
51
52
|
id: string;
|
|
52
53
|
index: number;
|
|
53
54
|
}) => JSX.Element;
|
|
55
|
+
/**
|
|
56
|
+
* If enabled, virtualization is used for the scrollable dropdown list.
|
|
57
|
+
* Use it if you expect a very long list of items.
|
|
58
|
+
* @default false
|
|
59
|
+
* @beta
|
|
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;
|
|
54
70
|
} & Pick<InputContainerProps, 'status'> & Omit<CommonProps, 'title'>;
|
|
55
71
|
/**
|
|
56
72
|
* ComboBox component that allows typing a value to filter the options in dropdown list.
|
|
@@ -56,8 +56,8 @@ var getOptionId = function (option, idPrefix) {
|
|
|
56
56
|
* />
|
|
57
57
|
*/
|
|
58
58
|
export var ComboBox = function (props) {
|
|
59
|
-
var _a;
|
|
60
|
-
var options = props.options, valueProp = props.value, onChange = props.onChange, filterFunction = props.filterFunction, inputProps = props.inputProps, dropdownMenuProps = props.dropdownMenuProps,
|
|
59
|
+
var _a, _b;
|
|
60
|
+
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"]);
|
|
61
61
|
// Generate a stateful random id if not specified
|
|
62
62
|
var id = React.useState(function () {
|
|
63
63
|
var _a, _b;
|
|
@@ -89,17 +89,18 @@ export var ComboBox = function (props) {
|
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
91
|
// Reducer where all the component-wide state is stored
|
|
92
|
-
var
|
|
92
|
+
var _e = React.useReducer(comboBoxReducer, {
|
|
93
93
|
isOpen: false,
|
|
94
94
|
selectedIndex: -1,
|
|
95
95
|
focusedIndex: -1,
|
|
96
|
-
}),
|
|
97
|
-
React.
|
|
96
|
+
}), _f = _e[0], isOpen = _f.isOpen, selectedIndex = _f.selectedIndex, focusedIndex = _f.focusedIndex, dispatch = _e[1];
|
|
97
|
+
React.useLayoutEffect(function () {
|
|
98
98
|
var _a, _b;
|
|
99
99
|
// When the dropdown opens
|
|
100
100
|
if (isOpen) {
|
|
101
101
|
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); // Focus the input
|
|
102
102
|
setFilteredOptions(options); // Reset the filtered list
|
|
103
|
+
dispatch(['focus']);
|
|
103
104
|
}
|
|
104
105
|
// When the dropdown closes
|
|
105
106
|
else {
|
|
@@ -112,19 +113,30 @@ export var ComboBox = function (props) {
|
|
|
112
113
|
}
|
|
113
114
|
}, [isOpen, options, selectedIndex]);
|
|
114
115
|
// Set min-width of menu to be same as input
|
|
115
|
-
var
|
|
116
|
+
var _g = React.useState(0), minWidth = _g[0], setMinWidth = _g[1];
|
|
116
117
|
React.useEffect(function () {
|
|
117
118
|
if (inputRef.current) {
|
|
118
119
|
setMinWidth(inputRef.current.offsetWidth);
|
|
119
120
|
}
|
|
120
121
|
}, [isOpen]);
|
|
121
|
-
//
|
|
122
|
-
var
|
|
122
|
+
// Update filtered options to the latest value options according to input value
|
|
123
|
+
var _h = React.useState(options), filteredOptions = _h[0], setFilteredOptions = _h[1];
|
|
123
124
|
React.useEffect(function () {
|
|
124
|
-
|
|
125
|
+
var _a;
|
|
126
|
+
if (inputValue) {
|
|
127
|
+
setFilteredOptions((_a = filterFunction === null || filterFunction === void 0 ? void 0 : filterFunction(options, inputValue)) !== null && _a !== void 0 ? _a : options.filter(function (option) {
|
|
128
|
+
return option.label.toLowerCase().includes(inputValue.toLowerCase());
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
setFilteredOptions(options);
|
|
133
|
+
}
|
|
134
|
+
dispatch(['focus']);
|
|
135
|
+
// Only need to call on options update
|
|
136
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
125
137
|
}, [options]);
|
|
126
138
|
// Filter options based on input value
|
|
127
|
-
var
|
|
139
|
+
var _j = React.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];
|
|
128
140
|
var handleOnInput = React.useCallback(function (event) {
|
|
129
141
|
var _a, _b;
|
|
130
142
|
var value = event.currentTarget.value;
|
|
@@ -133,12 +145,11 @@ export var ComboBox = function (props) {
|
|
|
133
145
|
setFilteredOptions((_a = filterFunction === null || filterFunction === void 0 ? void 0 : filterFunction(options, value)) !== null && _a !== void 0 ? _a : options.filter(function (option) {
|
|
134
146
|
return option.label.toLowerCase().includes(value.toLowerCase());
|
|
135
147
|
}));
|
|
148
|
+
if (focusedIndex != -1) {
|
|
149
|
+
dispatch(['focus', -1]);
|
|
150
|
+
}
|
|
136
151
|
(_b = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onChange) === null || _b === void 0 ? void 0 : _b.call(inputProps, event);
|
|
137
|
-
}, [filterFunction, inputProps, options]);
|
|
138
|
-
// Reset focused item when filteredOptions change
|
|
139
|
-
React.useEffect(function () {
|
|
140
|
-
dispatch(['focus']);
|
|
141
|
-
}, [filteredOptions]);
|
|
152
|
+
}, [filterFunction, focusedIndex, inputProps, options]);
|
|
142
153
|
// When the value prop changes, update the selectedIndex
|
|
143
154
|
React.useEffect(function () {
|
|
144
155
|
dispatch([
|
|
@@ -157,7 +168,7 @@ export var ComboBox = function (props) {
|
|
|
157
168
|
(_b = onChangeProp.current) === null || _b === void 0 ? void 0 : _b.call(onChangeProp, value);
|
|
158
169
|
}
|
|
159
170
|
}, [options, selectedIndex, valueProp]);
|
|
160
|
-
var getMenuItem = React.useCallback(function (option) {
|
|
171
|
+
var getMenuItem = React.useCallback(function (option, filteredIndex) {
|
|
161
172
|
var optionId = getOptionId(option, id);
|
|
162
173
|
var __originalIndex = optionsExtraInfoRef.current[optionId].__originalIndex;
|
|
163
174
|
var customItem = itemRenderer
|
|
@@ -172,6 +183,7 @@ export var ComboBox = function (props) {
|
|
|
172
183
|
onClick: function (e) {
|
|
173
184
|
var _a, _b;
|
|
174
185
|
dispatch(['select', __originalIndex]);
|
|
186
|
+
dispatch(['close']);
|
|
175
187
|
(_b = (_a = customItem.props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, e);
|
|
176
188
|
},
|
|
177
189
|
// ComboBox.MenuItem handles scrollIntoView, data-iui-index and iui-focused through context
|
|
@@ -180,22 +192,36 @@ export var ComboBox = function (props) {
|
|
|
180
192
|
'iui-focused': focusedIndex === __originalIndex,
|
|
181
193
|
}),
|
|
182
194
|
'data-iui-index': __originalIndex,
|
|
195
|
+
'data-iui-filtered-index': filteredIndex,
|
|
183
196
|
ref: mergeRefs(customItem.props.ref, function (el) {
|
|
184
|
-
|
|
185
|
-
if (focusedIndex === __originalIndex) {
|
|
197
|
+
if (!enableVirtualization && focusedIndex === __originalIndex) {
|
|
186
198
|
el === null || el === void 0 ? void 0 : el.scrollIntoView({ block: 'nearest' });
|
|
187
199
|
}
|
|
188
200
|
}),
|
|
189
|
-
})) : (React.createElement(ComboBoxMenuItem, __assign({ key: optionId, id: optionId }, option, { isSelected: selectedIndex === __originalIndex, onClick: function () {
|
|
190
|
-
|
|
201
|
+
})) : (React.createElement(ComboBoxMenuItem, __assign({ key: optionId, id: optionId }, option, { isSelected: selectedIndex === __originalIndex, onClick: function () {
|
|
202
|
+
dispatch(['select', __originalIndex]);
|
|
203
|
+
dispatch(['close']);
|
|
204
|
+
}, index: __originalIndex, "data-iui-filtered-index": filteredIndex }), option.label));
|
|
205
|
+
}, [enableVirtualization, focusedIndex, id, itemRenderer, selectedIndex]);
|
|
206
|
+
var emptyContent = React.useMemo(function () { return (React.createElement(React.Fragment, null, React.isValidElement(emptyStateMessage) ? (emptyStateMessage) : (React.createElement(MenuExtraContent, null,
|
|
207
|
+
React.createElement(Text, { isMuted: true }, emptyStateMessage))))); }, [emptyStateMessage]);
|
|
191
208
|
return (React.createElement(ComboBoxRefsContext.Provider, { value: { inputRef: inputRef, menuRef: menuRef, toggleButtonRef: toggleButtonRef, optionsExtraInfoRef: optionsExtraInfoRef } },
|
|
192
209
|
React.createElement(ComboBoxActionContext.Provider, { value: dispatch },
|
|
193
|
-
React.createElement(ComboBoxStateContext.Provider, { value: {
|
|
210
|
+
React.createElement(ComboBoxStateContext.Provider, { value: {
|
|
211
|
+
id: id,
|
|
212
|
+
minWidth: minWidth,
|
|
213
|
+
isOpen: isOpen,
|
|
214
|
+
focusedIndex: focusedIndex,
|
|
215
|
+
enableVirtualization: enableVirtualization,
|
|
216
|
+
filteredOptions: filteredOptions,
|
|
217
|
+
getMenuItem: getMenuItem,
|
|
218
|
+
} },
|
|
194
219
|
React.createElement(ComboBoxInputContainer, __assign({ disabled: inputProps === null || inputProps === void 0 ? void 0 : inputProps.disabled }, rest),
|
|
195
220
|
React.createElement(ComboBoxInput, __assign({ value: inputValue }, inputProps, { onChange: handleOnInput })),
|
|
196
221
|
React.createElement(ComboBoxEndIcon, { disabled: inputProps === null || inputProps === void 0 ? void 0 : inputProps.disabled, isOpen: isOpen })),
|
|
197
|
-
React.createElement(ComboBoxDropdown, __assign({}, dropdownMenuProps),
|
|
198
|
-
React.createElement(ComboBoxMenu, null, filteredOptions.length > 0
|
|
199
|
-
|
|
222
|
+
React.createElement(ComboBoxDropdown, __assign({}, dropdownMenuProps, { onShow: onShow, onHide: onHide }),
|
|
223
|
+
React.createElement(ComboBoxMenu, null, filteredOptions.length > 0 && !enableVirtualization
|
|
224
|
+
? filteredOptions.map(getMenuItem)
|
|
225
|
+
: emptyContent))))));
|
|
200
226
|
};
|
|
201
227
|
export default ComboBox;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
trigger?: string | undefined;
|
|
5
|
-
placement?: import("@popperjs/core").Placement | undefined;
|
|
6
|
-
} & Omit<import("@tippyjs/react").TippyProps, "placement" | "trigger" | "visible"> & {
|
|
2
|
+
import { PopoverProps } from '../utils';
|
|
3
|
+
declare type ComboBoxDropdownProps = PopoverProps & {
|
|
7
4
|
children: JSX.Element;
|
|
8
|
-
}
|
|
5
|
+
};
|
|
6
|
+
export declare const ComboBoxDropdown: React.ForwardRefExoticComponent<Pick<ComboBoxDropdownProps, "disabled" | "children" | "placement" | "trigger" | "visible" | "content" | "render" | "animateFill" | "appendTo" | "aria" | "delay" | "duration" | "followCursor" | "getReferenceClientRect" | "hideOnClick" | "ignoreAttributes" | "inlinePositioning" | "interactive" | "interactiveBorder" | "interactiveDebounce" | "moveTransition" | "offset" | "plugins" | "popperOptions" | "showOnCreate" | "sticky" | "touch" | "triggerTarget" | "onAfterUpdate" | "onBeforeUpdate" | "onCreate" | "onDestroy" | "onHidden" | "onHide" | "onMount" | "onShow" | "onShown" | "onTrigger" | "onUntrigger" | "onClickOutside" | "allowHTML" | "animation" | "arrow" | "inertia" | "maxWidth" | "role" | "theme" | "zIndex" | "className" | "singleton" | "reference"> & React.RefAttributes<Element>>;
|
|
7
|
+
export {};
|
|
@@ -30,7 +30,7 @@ import { useSafeContext, useMergedRefs } from '../utils';
|
|
|
30
30
|
import { ComboBoxStateContext, ComboBoxActionContext, ComboBoxRefsContext, } from './helpers';
|
|
31
31
|
export var ComboBoxInput = React.forwardRef(function (props, forwardedRef) {
|
|
32
32
|
var onKeyDownProp = props.onKeyDown, onFocusProp = props.onFocus, rest = __rest(props, ["onKeyDown", "onFocus"]);
|
|
33
|
-
var _a = useSafeContext(ComboBoxStateContext), isOpen = _a.isOpen, id = _a.id, focusedIndex = _a.focusedIndex;
|
|
33
|
+
var _a = useSafeContext(ComboBoxStateContext), isOpen = _a.isOpen, id = _a.id, focusedIndex = _a.focusedIndex, enableVirtualization = _a.enableVirtualization;
|
|
34
34
|
var dispatch = useSafeContext(ComboBoxActionContext);
|
|
35
35
|
var _b = useSafeContext(ComboBoxRefsContext), inputRef = _b.inputRef, menuRef = _b.menuRef, optionsExtraInfoRef = _b.optionsExtraInfoRef;
|
|
36
36
|
var refs = useMergedRefs(inputRef, forwardedRef);
|
|
@@ -43,7 +43,7 @@ export var ComboBoxInput = React.forwardRef(function (props, forwardedRef) {
|
|
|
43
43
|
return ((_c = (_b = (_a = menuRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("[data-iui-index=\"".concat(index, "\"]"))) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : '');
|
|
44
44
|
};
|
|
45
45
|
var handleKeyDown = React.useCallback(function (event) {
|
|
46
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
46
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
47
47
|
onKeyDownProp === null || onKeyDownProp === void 0 ? void 0 : onKeyDownProp(event);
|
|
48
48
|
var length = (_a = Object.keys(optionsExtraInfoRef.current).length) !== null && _a !== void 0 ? _a : 0;
|
|
49
49
|
switch (event.key) {
|
|
@@ -56,15 +56,21 @@ export var ComboBoxInput = React.forwardRef(function (props, forwardedRef) {
|
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
58
|
if (focusedIndexRef.current === -1) {
|
|
59
|
+
var currentElement = (_b = menuRef.current) === null || _b === void 0 ? void 0 : _b.querySelector('[data-iui-index]');
|
|
59
60
|
return dispatch([
|
|
60
61
|
'focus',
|
|
61
|
-
(_c =
|
|
62
|
+
Number((_c = currentElement === null || currentElement === void 0 ? void 0 : currentElement.getAttribute('data-iui-index')) !== null && _c !== void 0 ? _c : 0),
|
|
62
63
|
]);
|
|
63
64
|
}
|
|
65
|
+
// If virtualization is enabled, dont let round scrolling
|
|
66
|
+
if (enableVirtualization &&
|
|
67
|
+
!((_e = (_d = menuRef.current) === null || _d === void 0 ? void 0 : _d.querySelector("[data-iui-index=\"".concat(focusedIndexRef.current, "\"]"))) === null || _e === void 0 ? void 0 : _e.nextElementSibling)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
64
70
|
var nextIndex = focusedIndexRef.current;
|
|
65
71
|
do {
|
|
66
|
-
var currentElement = (
|
|
67
|
-
var nextElement = (
|
|
72
|
+
var currentElement = (_f = menuRef.current) === null || _f === void 0 ? void 0 : _f.querySelector("[data-iui-index=\"".concat(nextIndex, "\"]"));
|
|
73
|
+
var nextElement = (_g = currentElement === null || currentElement === void 0 ? void 0 : currentElement.nextElementSibling) !== null && _g !== void 0 ? _g : (_h = menuRef.current) === null || _h === void 0 ? void 0 : _h.querySelector('[data-iui-index]');
|
|
68
74
|
nextIndex = Number(nextElement === null || nextElement === void 0 ? void 0 : nextElement.getAttribute('data-iui-index'));
|
|
69
75
|
if ((nextElement === null || nextElement === void 0 ? void 0 : nextElement.ariaDisabled) !== 'true') {
|
|
70
76
|
return dispatch(['focus', nextIndex]);
|
|
@@ -80,16 +86,21 @@ export var ComboBoxInput = React.forwardRef(function (props, forwardedRef) {
|
|
|
80
86
|
if (length === 0) {
|
|
81
87
|
return;
|
|
82
88
|
}
|
|
89
|
+
// If virtualization is enabled, dont let round scrolling
|
|
90
|
+
if (enableVirtualization &&
|
|
91
|
+
!((_k = (_j = menuRef.current) === null || _j === void 0 ? void 0 : _j.querySelector("[data-iui-index=\"".concat(focusedIndexRef.current, "\"]"))) === null || _k === void 0 ? void 0 : _k.previousElementSibling)) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
83
94
|
if (focusedIndexRef.current === -1) {
|
|
84
95
|
return dispatch([
|
|
85
96
|
'focus',
|
|
86
|
-
(
|
|
97
|
+
(_m = (_l = Object.values(optionsExtraInfoRef.current)) === null || _l === void 0 ? void 0 : _l[length - 1].__originalIndex) !== null && _m !== void 0 ? _m : -1,
|
|
87
98
|
]);
|
|
88
99
|
}
|
|
89
100
|
var prevIndex = focusedIndexRef.current;
|
|
90
101
|
do {
|
|
91
|
-
var currentElement = (
|
|
92
|
-
var prevElement = (
|
|
102
|
+
var currentElement = (_o = menuRef.current) === null || _o === void 0 ? void 0 : _o.querySelector("[data-iui-index=\"".concat(prevIndex, "\"]"));
|
|
103
|
+
var prevElement = (_p = currentElement === null || currentElement === void 0 ? void 0 : currentElement.previousElementSibling) !== null && _p !== void 0 ? _p : (_q = menuRef.current) === null || _q === void 0 ? void 0 : _q.querySelector('[data-iui-index]:last-of-type');
|
|
93
104
|
prevIndex = Number(prevElement === null || prevElement === void 0 ? void 0 : prevElement.getAttribute('data-iui-index'));
|
|
94
105
|
if ((prevElement === null || prevElement === void 0 ? void 0 : prevElement.ariaDisabled) !== 'true') {
|
|
95
106
|
return dispatch(['focus', prevIndex]);
|
|
@@ -101,6 +112,7 @@ export var ComboBoxInput = React.forwardRef(function (props, forwardedRef) {
|
|
|
101
112
|
event.preventDefault();
|
|
102
113
|
if (isOpen) {
|
|
103
114
|
dispatch(['select', focusedIndexRef.current]);
|
|
115
|
+
dispatch(['close']);
|
|
104
116
|
}
|
|
105
117
|
else {
|
|
106
118
|
dispatch(['open']);
|
|
@@ -116,7 +128,14 @@ export var ComboBoxInput = React.forwardRef(function (props, forwardedRef) {
|
|
|
116
128
|
dispatch(['close']);
|
|
117
129
|
break;
|
|
118
130
|
}
|
|
119
|
-
}, [
|
|
131
|
+
}, [
|
|
132
|
+
dispatch,
|
|
133
|
+
enableVirtualization,
|
|
134
|
+
isOpen,
|
|
135
|
+
menuRef,
|
|
136
|
+
onKeyDownProp,
|
|
137
|
+
optionsExtraInfoRef,
|
|
138
|
+
]);
|
|
120
139
|
var handleFocus = React.useCallback(function (event) {
|
|
121
140
|
dispatch(['open']);
|
|
122
141
|
onFocusProp === null || onFocusProp === void 0 ? void 0 : onFocusProp(event);
|
|
@@ -27,13 +27,57 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
27
27
|
import cx from 'classnames';
|
|
28
28
|
import React from 'react';
|
|
29
29
|
import { Menu } from '../Menu';
|
|
30
|
-
import {
|
|
30
|
+
import { Surface } from '../Surface';
|
|
31
|
+
import { useSafeContext, useMergedRefs, useVirtualization, mergeRefs, getWindow, } from '../utils';
|
|
31
32
|
import { ComboBoxStateContext, ComboBoxRefsContext } from './helpers';
|
|
33
|
+
var VirtualizedComboBoxMenu = React.forwardRef(function (_a, forwardedRef) {
|
|
34
|
+
var _b, _c, _d;
|
|
35
|
+
var children = _a.children, style = _a.style, rest = __rest(_a, ["children", "style"]);
|
|
36
|
+
var _e = useSafeContext(ComboBoxStateContext), minWidth = _e.minWidth, id = _e.id, filteredOptions = _e.filteredOptions, getMenuItem = _e.getMenuItem, focusedIndex = _e.focusedIndex;
|
|
37
|
+
var menuRef = useSafeContext(ComboBoxRefsContext).menuRef;
|
|
38
|
+
var virtualItemRenderer = React.useCallback(function (index) {
|
|
39
|
+
return filteredOptions.length > 0
|
|
40
|
+
? getMenuItem(filteredOptions[index], index)
|
|
41
|
+
: children;
|
|
42
|
+
}, // Here is expected empty state content
|
|
43
|
+
[filteredOptions, getMenuItem, children]);
|
|
44
|
+
var focusedVisibleIndex = React.useMemo(function () {
|
|
45
|
+
var _a, _b;
|
|
46
|
+
var currentElement = (_a = menuRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("[data-iui-index=\"".concat(focusedIndex, "\"]"));
|
|
47
|
+
if (!currentElement) {
|
|
48
|
+
return focusedIndex;
|
|
49
|
+
}
|
|
50
|
+
return Number((_b = currentElement.getAttribute('data-iui-filtered-index')) !== null && _b !== void 0 ? _b : focusedIndex);
|
|
51
|
+
}, [focusedIndex, menuRef]);
|
|
52
|
+
var _f = useVirtualization({
|
|
53
|
+
// 'Fool' VirtualScroll by passing length 1
|
|
54
|
+
// whenever there is no elements, to show empty state message
|
|
55
|
+
itemsLength: filteredOptions.length || 1,
|
|
56
|
+
itemRenderer: virtualItemRenderer,
|
|
57
|
+
scrollToIndex: focusedVisibleIndex,
|
|
58
|
+
}), outerProps = _f.outerProps, innerProps = _f.innerProps, visibleChildren = _f.visibleChildren;
|
|
59
|
+
var overflowY = ((_d = (_c = (_b = getWindow()) === null || _b === void 0 ? void 0 : _b.CSS) === null || _c === void 0 ? void 0 : _c.supports) === null || _d === void 0 ? void 0 : _d.call(_c, 'overflow-x: overlay'))
|
|
60
|
+
? { overflowY: 'overlay' }
|
|
61
|
+
: { overflowY: 'auto' };
|
|
62
|
+
var styles = React.useMemo(function () { return ({
|
|
63
|
+
minWidth: minWidth,
|
|
64
|
+
maxWidth: "min(".concat(minWidth * 2, "px, 90vw)"),
|
|
65
|
+
maxHeight: 315,
|
|
66
|
+
}); }, [minWidth]);
|
|
67
|
+
return (React.createElement(Surface, __assign({ elevation: 1, style: __assign(__assign(__assign({}, styles), overflowY), style) }, rest),
|
|
68
|
+
React.createElement("div", __assign({}, outerProps),
|
|
69
|
+
React.createElement(Menu, { id: "".concat(id, "-list"), setFocus: false, role: 'listbox', ref: mergeRefs(menuRef, innerProps.ref, forwardedRef), style: innerProps.style }, visibleChildren))));
|
|
70
|
+
});
|
|
32
71
|
export var ComboBoxMenu = React.forwardRef(function (props, forwardedRef) {
|
|
33
72
|
var className = props.className, style = props.style, rest = __rest(props, ["className", "style"]);
|
|
34
|
-
var _a = useSafeContext(ComboBoxStateContext), minWidth = _a.minWidth, id = _a.id;
|
|
73
|
+
var _a = useSafeContext(ComboBoxStateContext), minWidth = _a.minWidth, id = _a.id, enableVirtualization = _a.enableVirtualization;
|
|
35
74
|
var menuRef = useSafeContext(ComboBoxRefsContext).menuRef;
|
|
36
75
|
var refs = useMergedRefs(menuRef, forwardedRef);
|
|
37
|
-
|
|
76
|
+
var styles = React.useMemo(function () { return ({
|
|
77
|
+
minWidth: minWidth,
|
|
78
|
+
maxWidth: "min(".concat(minWidth * 2, "px, 90vw)"),
|
|
79
|
+
maxHeight: 315,
|
|
80
|
+
}); }, [minWidth]);
|
|
81
|
+
return (React.createElement(React.Fragment, null, !enableVirtualization ? (React.createElement(Menu, __assign({ id: "".concat(id, "-list"), style: __assign(__assign({}, styles), style), setFocus: false, role: 'listbox', ref: refs, className: cx('iui-scroll', className) }, rest))) : (React.createElement(VirtualizedComboBoxMenu, __assign({ ref: forwardedRef }, props)))));
|
|
38
82
|
});
|
|
39
83
|
ComboBoxMenu.displayName = 'ComboBoxMenu';
|
|
@@ -30,10 +30,9 @@ import { useSafeContext, useMergedRefs } from '../utils';
|
|
|
30
30
|
import { ComboBoxStateContext } from './helpers';
|
|
31
31
|
export var ComboBoxMenuItem = React.memo(React.forwardRef(function (props, forwardedRef) {
|
|
32
32
|
var children = props.children, isSelected = props.isSelected, disabled = props.disabled, value = props.value, onClick = props.onClick, sublabel = props.sublabel, _a = props.size, size = _a === void 0 ? !!sublabel ? 'large' : 'default' : _a, icon = props.icon, badge = props.badge, className = props.className, _b = props.role, role = _b === void 0 ? 'menuitem' : _b, index = props.index, rest = __rest(props, ["children", "isSelected", "disabled", "value", "onClick", "sublabel", "size", "icon", "badge", "className", "role", "index"]);
|
|
33
|
-
var
|
|
33
|
+
var _c = useSafeContext(ComboBoxStateContext), focusedIndex = _c.focusedIndex, enableVirtualization = _c.enableVirtualization;
|
|
34
34
|
var focusRef = function (el) {
|
|
35
|
-
|
|
36
|
-
if (focusedIndex === index) {
|
|
35
|
+
if (!enableVirtualization && focusedIndex === index) {
|
|
37
36
|
el === null || el === void 0 ? void 0 : el.scrollIntoView({ block: 'nearest' });
|
|
38
37
|
}
|
|
39
38
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { SelectOption } from '../Select/Select';
|
|
2
3
|
declare type ComboBoxAction = 'open' | 'close' | 'select' | 'focus';
|
|
3
4
|
export declare const comboBoxReducer: (state: {
|
|
4
5
|
isOpen: boolean;
|
|
@@ -17,11 +18,15 @@ export declare const ComboBoxRefsContext: React.Context<{
|
|
|
17
18
|
__originalIndex: number;
|
|
18
19
|
}>>;
|
|
19
20
|
} | undefined>;
|
|
20
|
-
|
|
21
|
+
declare type ComboBoxStateContextProps<T = unknown> = {
|
|
21
22
|
isOpen: boolean;
|
|
22
23
|
id: string;
|
|
23
24
|
minWidth: number;
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
enableVirtualization: boolean;
|
|
26
|
+
filteredOptions: SelectOption<T>[];
|
|
27
|
+
getMenuItem: (option: SelectOption<T>, filteredIndex?: number) => JSX.Element;
|
|
28
|
+
focusedIndex?: number;
|
|
29
|
+
};
|
|
30
|
+
export declare const ComboBoxStateContext: React.Context<ComboBoxStateContextProps<unknown> | undefined>;
|
|
26
31
|
export declare const ComboBoxActionContext: React.Context<((x: [ComboBoxAction] | [ComboBoxAction, number]) => void) | undefined>;
|
|
27
32
|
export {};
|
|
@@ -25,7 +25,7 @@ export var comboBoxReducer = function (state, _a) {
|
|
|
25
25
|
return __assign(__assign({}, state), { isOpen: false });
|
|
26
26
|
}
|
|
27
27
|
case 'select': {
|
|
28
|
-
return __assign(__assign({}, state), {
|
|
28
|
+
return __assign(__assign({}, state), { selectedIndex: value !== null && value !== void 0 ? value : state.selectedIndex, focusedIndex: value !== null && value !== void 0 ? value : state.focusedIndex });
|
|
29
29
|
}
|
|
30
30
|
case 'focus': {
|
|
31
31
|
return __assign(__assign({}, state), { focusedIndex: (_b = value !== null && value !== void 0 ? value : state.selectedIndex) !== null && _b !== void 0 ? _b : -1 });
|
|
@@ -5,7 +5,7 @@ import { TimePickerProps } from '../TimePicker';
|
|
|
5
5
|
* Generate localized months and days strings using `Intl.DateTimeFormat` for passed locale to use in DatePicker component.
|
|
6
6
|
* If locale is not passed, browser locale will be used.
|
|
7
7
|
*/
|
|
8
|
-
export declare const generateLocalizedStrings: (locale?: string
|
|
8
|
+
export declare const generateLocalizedStrings: (locale?: string) => {
|
|
9
9
|
months: string[];
|
|
10
10
|
shortDays: string[];
|
|
11
11
|
days: string[];
|
|
@@ -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,46 @@
|
|
|
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 __rest = (this && this.__rest) || function (s, e) {
|
|
13
|
+
var t = {};
|
|
14
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
15
|
+
t[p] = s[p];
|
|
16
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
17
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
18
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
19
|
+
t[p[i]] = s[p[i]];
|
|
20
|
+
}
|
|
21
|
+
return t;
|
|
22
|
+
};
|
|
23
|
+
/*---------------------------------------------------------------------------------------------
|
|
24
|
+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
25
|
+
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
26
|
+
*--------------------------------------------------------------------------------------------*/
|
|
27
|
+
import React from 'react';
|
|
28
|
+
import cx from 'classnames';
|
|
29
|
+
import { useTheme, VisuallyHidden } from '../utils';
|
|
30
|
+
import '@itwin/itwinui-css/css/menu.css';
|
|
31
|
+
/**
|
|
32
|
+
* Menu item that uses skeletons to indicate loading state.
|
|
33
|
+
*/
|
|
34
|
+
export var MenuItemSkeleton = function (props) {
|
|
35
|
+
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"]);
|
|
36
|
+
useTheme();
|
|
37
|
+
return (React.createElement("li", __assign({ className: cx('iui-menu-item', 'iui-menu-item-skeleton', { 'iui-large': hasSublabel }, className), style: __assign({
|
|
38
|
+
'--iui-menu-item-content-skeleton-max-width': contentWidth,
|
|
39
|
+
}, style) }, rest),
|
|
40
|
+
hasIcon && React.createElement("div", { className: 'iui-icon iui-skeleton', "aria-hidden": true }),
|
|
41
|
+
React.createElement("span", { className: 'iui-content' },
|
|
42
|
+
React.createElement("div", { className: 'iui-menu-label iui-skeleton', "aria-hidden": true }),
|
|
43
|
+
hasSublabel && (React.createElement("div", { className: 'iui-menu-description iui-skeleton', "aria-hidden": true })),
|
|
44
|
+
React.createElement(VisuallyHidden, null, translatedStrings.loading))));
|
|
45
|
+
};
|
|
46
|
+
export default MenuItemSkeleton;
|
package/esm/core/Menu/index.d.ts
CHANGED
|
@@ -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';
|
package/esm/core/Menu/index.js
CHANGED
|
@@ -140,7 +140,7 @@ export var Select = function (props) {
|
|
|
140
140
|
return options.find(function (option) { return option.value === value; });
|
|
141
141
|
}, [options, value]);
|
|
142
142
|
return (React.createElement("div", __assign({ className: cx('iui-input-with-icon', className), "aria-expanded": isOpen, "aria-haspopup": 'listbox', style: style }, rest),
|
|
143
|
-
React.createElement(DropdownMenu, __assign({ menuItems: menuItems, placement: 'bottom-start', className: cx('iui-scroll', menuClassName), style: __assign({ minWidth: minWidth, maxWidth: "min(".concat(minWidth * 2, "px, 90vw)"), maxHeight:
|
|
143
|
+
React.createElement(DropdownMenu, __assign({ menuItems: menuItems, placement: 'bottom-start', className: cx('iui-scroll', menuClassName), style: __assign({ minWidth: minWidth, maxWidth: "min(".concat(minWidth * 2, "px, 90vw)"), maxHeight: 315 }, menuStyle), role: 'listbox', onShow: onShowHandler, onHide: onHideHandler, disabled: disabled }, popoverProps, { visible: isOpen, onClickOutside: function (_, _a) {
|
|
144
144
|
var _b;
|
|
145
145
|
var target = _a.target;
|
|
146
146
|
if (!((_b = toggleButtonRef.current) === null || _b === void 0 ? void 0 : _b.contains(target))) {
|