@itwin/itwinui-react 1.30.0 → 1.32.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 +27 -0
- package/cjs/core/Badge/Badge.js +2 -2
- package/cjs/core/Checkbox/Checkbox.d.ts +13 -0
- package/cjs/core/Checkbox/Checkbox.js +15 -22
- package/cjs/core/ColorPicker/ColorBuilder.js +7 -8
- package/cjs/core/ColorPicker/ColorSwatch.d.ts +1 -1
- package/cjs/core/ColorPicker/ColorSwatch.js +2 -2
- package/cjs/core/ComboBox/ComboBox.d.ts +11 -0
- package/cjs/core/ComboBox/ComboBox.js +93 -55
- package/cjs/core/ExpandableBlock/ExpandableBlock.d.ts +6 -0
- package/cjs/core/ExpandableBlock/ExpandableBlock.js +3 -2
- package/cjs/core/Menu/Menu.js +3 -3
- package/cjs/core/Menu/MenuItem.js +1 -1
- package/cjs/core/Radio/Radio.d.ts +13 -0
- package/cjs/core/Radio/Radio.js +7 -8
- package/cjs/core/Select/Select.js +23 -8
- package/cjs/core/Table/TablePaginator.js +7 -9
- package/cjs/core/Table/filters/DateRangeFilter/DatePickerInput.js +1 -1
- package/cjs/core/Tile/Tile.js +4 -4
- package/cjs/core/Tree/Tree.d.ts +123 -0
- package/cjs/core/Tree/Tree.js +177 -0
- package/cjs/core/Tree/TreeContext.d.ts +25 -0
- package/cjs/core/Tree/TreeContext.js +20 -0
- package/cjs/core/Tree/TreeNode.d.ts +87 -0
- package/cjs/core/Tree/TreeNode.js +169 -0
- package/cjs/core/Tree/TreeNodeExpander.d.ts +8 -0
- package/cjs/core/Tree/TreeNodeExpander.js +46 -0
- package/cjs/core/Tree/index.d.ts +6 -0
- package/cjs/core/Tree/index.js +13 -0
- package/cjs/core/index.d.ts +2 -0
- package/cjs/core/index.js +5 -1
- package/cjs/core/utils/components/Popover.js +1 -1
- package/cjs/core/utils/functions/focusable.js +6 -2
- package/esm/core/Badge/Badge.js +2 -2
- package/esm/core/Checkbox/Checkbox.d.ts +13 -0
- package/esm/core/Checkbox/Checkbox.js +15 -22
- package/esm/core/ColorPicker/ColorBuilder.js +7 -8
- package/esm/core/ColorPicker/ColorSwatch.d.ts +1 -1
- package/esm/core/ColorPicker/ColorSwatch.js +2 -2
- package/esm/core/ComboBox/ComboBox.d.ts +11 -0
- package/esm/core/ComboBox/ComboBox.js +94 -56
- package/esm/core/ExpandableBlock/ExpandableBlock.d.ts +6 -0
- package/esm/core/ExpandableBlock/ExpandableBlock.js +3 -2
- package/esm/core/Menu/Menu.js +3 -3
- package/esm/core/Menu/MenuItem.js +1 -1
- package/esm/core/Radio/Radio.d.ts +13 -0
- package/esm/core/Radio/Radio.js +7 -8
- package/esm/core/Select/Select.js +23 -8
- package/esm/core/Table/TablePaginator.js +7 -9
- package/esm/core/Table/filters/DateRangeFilter/DatePickerInput.js +1 -1
- package/esm/core/Tile/Tile.js +4 -4
- package/esm/core/Tree/Tree.d.ts +123 -0
- package/esm/core/Tree/Tree.js +170 -0
- package/esm/core/Tree/TreeContext.d.ts +25 -0
- package/esm/core/Tree/TreeContext.js +13 -0
- package/esm/core/Tree/TreeNode.d.ts +87 -0
- package/esm/core/Tree/TreeNode.js +162 -0
- package/esm/core/Tree/TreeNodeExpander.d.ts +8 -0
- package/esm/core/Tree/TreeNodeExpander.js +39 -0
- package/esm/core/Tree/index.d.ts +6 -0
- package/esm/core/Tree/index.js +7 -0
- package/esm/core/index.d.ts +2 -0
- package/esm/core/index.js +1 -0
- package/esm/core/utils/components/Popover.js +1 -1
- package/esm/core/utils/functions/focusable.js +6 -2
- package/package.json +2 -2
|
@@ -29,7 +29,7 @@ import cx from 'classnames';
|
|
|
29
29
|
import { Input } from '../Input';
|
|
30
30
|
import { Menu, MenuExtraContent, MenuItem } from '../Menu';
|
|
31
31
|
import { Text } from '../Typography';
|
|
32
|
-
import { InputContainer, useTheme, Popover, getFocusableElements, getRandomValue, } from '../utils';
|
|
32
|
+
import { InputContainer, useTheme, Popover, getFocusableElements, getRandomValue, mergeRefs, } from '../utils';
|
|
33
33
|
import SvgCaretDownSmall from '@itwin/itwinui-icons-react/cjs/icons/CaretDownSmall';
|
|
34
34
|
import 'tippy.js/animations/shift-away.css';
|
|
35
35
|
/**
|
|
@@ -46,7 +46,7 @@ import 'tippy.js/animations/shift-away.css';
|
|
|
46
46
|
* />
|
|
47
47
|
*/
|
|
48
48
|
export var ComboBox = function (props) {
|
|
49
|
-
var options = props.options, value = props.value, onChange = props.onChange, filterFunction = props.filterFunction, className = props.className, inputProps = props.inputProps, dropdownMenuProps = props.dropdownMenuProps, _a = props.emptyStateMessage, emptyStateMessage = _a === void 0 ? 'No options found' : _a, rest = __rest(props, ["options", "value", "onChange", "filterFunction", "className", "inputProps", "dropdownMenuProps", "emptyStateMessage"]);
|
|
49
|
+
var options = props.options, value = props.value, onChange = props.onChange, filterFunction = props.filterFunction, className = props.className, inputProps = props.inputProps, dropdownMenuProps = props.dropdownMenuProps, _a = props.emptyStateMessage, emptyStateMessage = _a === void 0 ? 'No options found' : _a, itemRenderer = props.itemRenderer, rest = __rest(props, ["options", "value", "onChange", "filterFunction", "className", "inputProps", "dropdownMenuProps", "emptyStateMessage", "itemRenderer"]);
|
|
50
50
|
// Generate a stateful random id if not specified
|
|
51
51
|
var id = React.useState(function () {
|
|
52
52
|
var _a, _b;
|
|
@@ -61,16 +61,31 @@ export var ComboBox = function (props) {
|
|
|
61
61
|
return value === options[index].value;
|
|
62
62
|
});
|
|
63
63
|
}, [options, id]);
|
|
64
|
+
var userOnChange = React.useRef(onChange);
|
|
64
65
|
var memoizedItems = React.useMemo(function () {
|
|
65
|
-
return options.map(function (
|
|
66
|
-
var label =
|
|
67
|
-
|
|
66
|
+
return options.map(function (option, index) {
|
|
67
|
+
var label = option.label, value = option.value, rest = __rest(option, ["label", "value"]);
|
|
68
|
+
var additionalProps = {
|
|
69
|
+
value: value,
|
|
70
|
+
role: 'option',
|
|
71
|
+
onClick: function () {
|
|
72
|
+
var _a;
|
|
68
73
|
setSelectedValue(value);
|
|
69
|
-
|
|
74
|
+
(_a = userOnChange.current) === null || _a === void 0 ? void 0 : _a.call(userOnChange, value);
|
|
70
75
|
setIsOpen(false);
|
|
71
|
-
}
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
if (itemRenderer) {
|
|
79
|
+
return React.cloneElement(itemRenderer(option, {
|
|
80
|
+
id: getOptionId(index),
|
|
81
|
+
index: index,
|
|
82
|
+
isSelected: false,
|
|
83
|
+
isFocused: false,
|
|
84
|
+
}), additionalProps);
|
|
85
|
+
}
|
|
86
|
+
return (React.createElement(MenuItem, __assign({ id: getOptionId(index), key: getOptionId(index) }, additionalProps, rest), label));
|
|
72
87
|
});
|
|
73
|
-
}, [options, getOptionId,
|
|
88
|
+
}, [options, getOptionId, itemRenderer]);
|
|
74
89
|
var inputRef = React.useRef(null);
|
|
75
90
|
var menuRef = React.useRef(null);
|
|
76
91
|
var toggleButtonRef = React.useRef(null);
|
|
@@ -149,6 +164,7 @@ export var ComboBox = function (props) {
|
|
|
149
164
|
});
|
|
150
165
|
}, [inputValue, options, selectedValue, isOpen, filterFunction]);
|
|
151
166
|
var onKeyDown = React.useCallback(function (event) {
|
|
167
|
+
var _a;
|
|
152
168
|
var focusableOptions = getFocusableElements(menuRef.current);
|
|
153
169
|
var focusedIndexInFilteredList = focusableOptions.findIndex(function (_a) {
|
|
154
170
|
var _b;
|
|
@@ -182,7 +198,7 @@ export var ComboBox = function (props) {
|
|
|
182
198
|
case 'Enter':
|
|
183
199
|
if (isOpen) {
|
|
184
200
|
setSelectedValue(options[focusedIndex].value);
|
|
185
|
-
|
|
201
|
+
(_a = userOnChange.current) === null || _a === void 0 ? void 0 : _a.call(userOnChange, options[focusedIndex].value);
|
|
186
202
|
}
|
|
187
203
|
setIsOpen(function (open) { return !open; });
|
|
188
204
|
event.preventDefault();
|
|
@@ -202,26 +218,41 @@ export var ComboBox = function (props) {
|
|
|
202
218
|
}
|
|
203
219
|
break;
|
|
204
220
|
}
|
|
205
|
-
}, [focusedIndex, isOpen, options, getOptionId
|
|
221
|
+
}, [focusedIndex, isOpen, options, getOptionId]);
|
|
206
222
|
var menuItems = React.useMemo(function () {
|
|
207
223
|
if (filteredOptions.length === 0) {
|
|
208
|
-
return
|
|
209
|
-
React.createElement(
|
|
224
|
+
return [
|
|
225
|
+
React.createElement(MenuExtraContent, { key: 0 },
|
|
226
|
+
React.createElement(Text, { isMuted: true }, emptyStateMessage)),
|
|
227
|
+
];
|
|
210
228
|
}
|
|
211
229
|
return filteredOptions.map(function (option) {
|
|
230
|
+
var _a;
|
|
212
231
|
var index = options.findIndex(function (_a) {
|
|
213
232
|
var value = _a.value;
|
|
214
233
|
return option.value === value;
|
|
215
234
|
});
|
|
216
235
|
if (index < 0) {
|
|
217
|
-
return;
|
|
236
|
+
return React.createElement(React.Fragment, null);
|
|
218
237
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
238
|
+
var id = getOptionId(index);
|
|
239
|
+
var isSelected = selectedValue === option.value;
|
|
240
|
+
var isFocused = focusedIndex === index;
|
|
241
|
+
var focusScrollRef = function (el) {
|
|
242
|
+
return isFocused && (el === null || el === void 0 ? void 0 : el.scrollIntoView({ block: 'nearest' }));
|
|
243
|
+
};
|
|
244
|
+
if (isSelected || isFocused) {
|
|
245
|
+
var item = (_a = itemRenderer === null || itemRenderer === void 0 ? void 0 : itemRenderer(option, { index: index, id: id, isSelected: isSelected, isFocused: isFocused })) !== null && _a !== void 0 ? _a : React.cloneElement(memoizedItems[index], { isSelected: isSelected });
|
|
246
|
+
return React.cloneElement(item, {
|
|
247
|
+
className: cx({ 'iui-focused': isFocused }, item.props.className),
|
|
248
|
+
ref: mergeRefs(focusScrollRef, item.props.ref),
|
|
249
|
+
value: option.value,
|
|
250
|
+
role: 'option',
|
|
251
|
+
onClick: function () {
|
|
252
|
+
var _a;
|
|
253
|
+
setSelectedValue(option.value);
|
|
254
|
+
(_a = userOnChange.current) === null || _a === void 0 ? void 0 : _a.call(userOnChange, option.value);
|
|
255
|
+
setIsOpen(false);
|
|
225
256
|
},
|
|
226
257
|
});
|
|
227
258
|
}
|
|
@@ -231,45 +262,52 @@ export var ComboBox = function (props) {
|
|
|
231
262
|
filteredOptions,
|
|
232
263
|
emptyStateMessage,
|
|
233
264
|
options,
|
|
234
|
-
|
|
265
|
+
getOptionId,
|
|
235
266
|
selectedValue,
|
|
267
|
+
focusedIndex,
|
|
268
|
+
itemRenderer,
|
|
236
269
|
memoizedItems,
|
|
237
270
|
]);
|
|
238
|
-
return (React.createElement(InputContainer, __assign({ className: className, isIconInline: true,
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
271
|
+
return (React.createElement(InputContainer, __assign({ className: className, isIconInline: true }, rest, { id: id }),
|
|
272
|
+
React.createElement("div", { className: 'iui-input-with-icon' },
|
|
273
|
+
React.createElement(Popover, __assign({ placement: 'bottom-start', visible: isOpen, onClickOutside: function (_, _a) {
|
|
274
|
+
var _b;
|
|
275
|
+
var target = _a.target;
|
|
276
|
+
if (!((_b = toggleButtonRef.current) === null || _b === void 0 ? void 0 : _b.contains(target))) {
|
|
277
|
+
setIsOpen(false);
|
|
278
|
+
}
|
|
279
|
+
}, animation: 'shift-away', duration: 200 }, dropdownMenuProps, { content: React.createElement(Menu, { id: id + "-list", className: 'iui-scroll', style: {
|
|
280
|
+
minWidth: minWidth,
|
|
281
|
+
maxWidth: "min(" + minWidth * 2 + "px, 90vw)",
|
|
282
|
+
maxHeight: 300,
|
|
283
|
+
}, setFocus: false, role: 'listbox', ref: menuRef }, menuItems), onHide: function (instance) {
|
|
284
|
+
var _a;
|
|
285
|
+
var selectedIndex = options.findIndex(function (_a) {
|
|
286
|
+
var value = _a.value;
|
|
287
|
+
return value === selectedValue;
|
|
288
|
+
});
|
|
289
|
+
setFocusedIndex(selectedIndex);
|
|
290
|
+
if (selectedIndex > -1) {
|
|
291
|
+
setInputValue(options[selectedIndex].label); // update input value to be same as selected value
|
|
292
|
+
}
|
|
293
|
+
(_a = dropdownMenuProps === null || dropdownMenuProps === void 0 ? void 0 : dropdownMenuProps.onHide) === null || _a === void 0 ? void 0 : _a.call(dropdownMenuProps, instance);
|
|
294
|
+
} }),
|
|
295
|
+
React.createElement(Input, __assign({ ref: inputRef, onKeyDown: onKeyDown, onFocus: function () { return setIsOpen(true); }, onChange: onInput, value: inputValue, "aria-activedescendant": isOpen && focusedIndex > -1
|
|
296
|
+
? getOptionId(focusedIndex)
|
|
297
|
+
: undefined, role: 'combobox', "aria-controls": isOpen ? id + "-list" : undefined, "aria-autocomplete": 'list', spellCheck: false, autoCapitalize: 'none', autoCorrect: 'off' }, inputProps))),
|
|
298
|
+
React.createElement("span", { ref: toggleButtonRef, className: cx('iui-end-icon', {
|
|
299
|
+
'iui-actionable': !(inputProps === null || inputProps === void 0 ? void 0 : inputProps.disabled),
|
|
300
|
+
'iui-disabled': inputProps === null || inputProps === void 0 ? void 0 : inputProps.disabled,
|
|
301
|
+
'iui-open': isOpen,
|
|
302
|
+
}), onClick: function () {
|
|
303
|
+
var _a;
|
|
304
|
+
if (isOpen) {
|
|
305
|
+
setIsOpen(false);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
309
|
+
}
|
|
310
|
+
} },
|
|
311
|
+
React.createElement(SvgCaretDownSmall, { "aria-hidden": true })))));
|
|
274
312
|
};
|
|
275
313
|
export default ComboBox;
|
|
@@ -38,6 +38,12 @@ export declare type ExpandableBlockProps = {
|
|
|
38
38
|
* @default 'default'
|
|
39
39
|
*/
|
|
40
40
|
size?: 'default' | 'small';
|
|
41
|
+
/**
|
|
42
|
+
* Style of the ExpandableBlock.
|
|
43
|
+
* Use 'borderless' to hide outline.
|
|
44
|
+
* @default 'default'
|
|
45
|
+
*/
|
|
46
|
+
styleType?: 'default' | 'borderless';
|
|
41
47
|
} & Omit<CommonProps, 'title'>;
|
|
42
48
|
/**
|
|
43
49
|
* Container that allows content to be hidden behind a brief title and a caption.
|
|
@@ -40,10 +40,10 @@ import '@itwin/itwinui-css/css/expandable-block.css';
|
|
|
40
40
|
*/
|
|
41
41
|
export var ExpandableBlock = function (props) {
|
|
42
42
|
var _a;
|
|
43
|
-
var caption = props.caption, children = props.children, className = props.className, title = props.title, onToggle = props.onToggle, style = props.style, _b = props.isExpanded, isExpanded = _b === void 0 ? false : _b, endIcon = props.endIcon, status = props.status, _c = props.size, size = _c === void 0 ? 'default' : _c, rest = __rest(props, ["caption", "children", "className", "title", "onToggle", "style", "isExpanded", "endIcon", "status", "size"]);
|
|
43
|
+
var caption = props.caption, children = props.children, className = props.className, title = props.title, onToggle = props.onToggle, style = props.style, _b = props.isExpanded, isExpanded = _b === void 0 ? false : _b, endIcon = props.endIcon, status = props.status, _c = props.size, size = _c === void 0 ? 'default' : _c, _d = props.styleType, styleType = _d === void 0 ? 'default' : _d, rest = __rest(props, ["caption", "children", "className", "title", "onToggle", "style", "isExpanded", "endIcon", "status", "size", "styleType"]);
|
|
44
44
|
useTheme();
|
|
45
45
|
var icon = endIcon !== null && endIcon !== void 0 ? endIcon : (status && StatusIconMap[status]());
|
|
46
|
-
var
|
|
46
|
+
var _e = React.useState(isExpanded), expanded = _e[0], setExpanded = _e[1];
|
|
47
47
|
React.useEffect(function () {
|
|
48
48
|
setExpanded(isExpanded);
|
|
49
49
|
}, [isExpanded]);
|
|
@@ -62,6 +62,7 @@ export var ExpandableBlock = function (props) {
|
|
|
62
62
|
'iui-with-caption': !!caption,
|
|
63
63
|
'iui-expanded': expanded,
|
|
64
64
|
'iui-small': size === 'small',
|
|
65
|
+
'iui-borderless': styleType === 'borderless',
|
|
65
66
|
}, className), style: style }, rest),
|
|
66
67
|
React.createElement("div", { "aria-expanded": expanded, className: 'iui-header', tabIndex: 0, onClick: handleToggle, onKeyDown: onKeyDown },
|
|
67
68
|
React.createElement(SvgChevronRight, { className: 'iui-icon', "aria-hidden": true }),
|
package/esm/core/Menu/Menu.js
CHANGED
|
@@ -37,6 +37,9 @@ export var Menu = React.forwardRef(function (props, ref) {
|
|
|
37
37
|
var _c = React.useState(), focusedIndex = _c[0], setFocusedIndex = _c[1];
|
|
38
38
|
var menuRef = React.useRef(null);
|
|
39
39
|
var refs = useMergedRefs(menuRef, ref);
|
|
40
|
+
React.useEffect(function () {
|
|
41
|
+
setFocusedIndex(null);
|
|
42
|
+
}, [children]);
|
|
40
43
|
React.useEffect(function () {
|
|
41
44
|
var _a;
|
|
42
45
|
var items = getFocusableElements(menuRef.current);
|
|
@@ -49,9 +52,6 @@ export var Menu = React.forwardRef(function (props, ref) {
|
|
|
49
52
|
setFocusedIndex(selectedIndex > -1 ? selectedIndex : 0);
|
|
50
53
|
}
|
|
51
54
|
}, [setFocus, focusedIndex]);
|
|
52
|
-
React.useEffect(function () {
|
|
53
|
-
setFocusedIndex(null);
|
|
54
|
-
}, [children]);
|
|
55
55
|
var onKeyDown = function (event) {
|
|
56
56
|
var items = getFocusableElements(menuRef.current);
|
|
57
57
|
if (!(items === null || items === void 0 ? void 0 : items.length)) {
|
|
@@ -100,7 +100,7 @@ export var MenuItem = React.forwardRef(function (props, ref) {
|
|
|
100
100
|
className: cx(badge.props.className, 'iui-icon'),
|
|
101
101
|
})));
|
|
102
102
|
return subMenuItems.length === 0 ? (listItem) : (React.createElement(MenuItemContext.Provider, { value: { ref: menuItemRef } },
|
|
103
|
-
React.createElement(Popover, { placement: 'right-start', visible: isSubmenuVisible, content: React.createElement("div", { onMouseLeave: function () { return setIsSubmenuVisible(false); }, onBlur: function (e) {
|
|
103
|
+
React.createElement(Popover, { placement: 'right-start', visible: isSubmenuVisible, appendTo: 'parent', content: React.createElement("div", { onMouseLeave: function () { return setIsSubmenuVisible(false); }, onBlur: function (e) {
|
|
104
104
|
var _a, _b;
|
|
105
105
|
!!(e.relatedTarget instanceof Node) &&
|
|
106
106
|
!((_a = subMenuRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.relatedTarget)) &&
|
|
@@ -11,10 +11,16 @@ export declare type RadioProps = {
|
|
|
11
11
|
status?: 'positive' | 'warning' | 'negative';
|
|
12
12
|
/**
|
|
13
13
|
* Custom CSS class name for the checkmark element.
|
|
14
|
+
*
|
|
15
|
+
* @deprecated As of 1.32.0, this is applied on the actual radio `<input>` element.
|
|
16
|
+
* The checkmark has been moved into a pseudo-element.
|
|
14
17
|
*/
|
|
15
18
|
checkmarkClassName?: string;
|
|
16
19
|
/**
|
|
17
20
|
* Custom CSS Style for the checkmark element.
|
|
21
|
+
*
|
|
22
|
+
* @deprecated As of 1.32.0, this is applied on the actual radio `<input>` element.
|
|
23
|
+
* The checkmark has been moved into a pseudo-element.
|
|
18
24
|
*/
|
|
19
25
|
checkmarkStyle?: React.CSSProperties;
|
|
20
26
|
/**
|
|
@@ -26,6 +32,7 @@ export declare type RadioProps = {
|
|
|
26
32
|
/**
|
|
27
33
|
* Basic radio input component
|
|
28
34
|
* @example
|
|
35
|
+
* <Radio />
|
|
29
36
|
* <Radio label='Radio' />
|
|
30
37
|
* <Radio disabled={true} label='Radio' />
|
|
31
38
|
* <Radio status='positive' label='Positive' />
|
|
@@ -43,10 +50,16 @@ export declare const Radio: React.ForwardRefExoticComponent<{
|
|
|
43
50
|
status?: "positive" | "warning" | "negative" | undefined;
|
|
44
51
|
/**
|
|
45
52
|
* Custom CSS class name for the checkmark element.
|
|
53
|
+
*
|
|
54
|
+
* @deprecated As of 1.32.0, this is applied on the actual radio `<input>` element.
|
|
55
|
+
* The checkmark has been moved into a pseudo-element.
|
|
46
56
|
*/
|
|
47
57
|
checkmarkClassName?: string | undefined;
|
|
48
58
|
/**
|
|
49
59
|
* Custom CSS Style for the checkmark element.
|
|
60
|
+
*
|
|
61
|
+
* @deprecated As of 1.32.0, this is applied on the actual radio `<input>` element.
|
|
62
|
+
* The checkmark has been moved into a pseudo-element.
|
|
50
63
|
*/
|
|
51
64
|
checkmarkStyle?: React.CSSProperties | undefined;
|
|
52
65
|
/**
|
package/esm/core/Radio/Radio.js
CHANGED
|
@@ -31,6 +31,7 @@ import '@itwin/itwinui-css/css/inputs.css';
|
|
|
31
31
|
/**
|
|
32
32
|
* Basic radio input component
|
|
33
33
|
* @example
|
|
34
|
+
* <Radio />
|
|
34
35
|
* <Radio label='Radio' />
|
|
35
36
|
* <Radio disabled={true} label='Radio' />
|
|
36
37
|
* <Radio status='positive' label='Positive' />
|
|
@@ -38,8 +39,8 @@ import '@itwin/itwinui-css/css/inputs.css';
|
|
|
38
39
|
* <Radio status='negative' label='Negative' />
|
|
39
40
|
*/
|
|
40
41
|
export var Radio = React.forwardRef(function (props, ref) {
|
|
41
|
-
var _a;
|
|
42
|
-
var className = props.className,
|
|
42
|
+
var _a, _b;
|
|
43
|
+
var className = props.className, _c = props.disabled, disabled = _c === void 0 ? false : _c, label = props.label, status = props.status, style = props.style, checkmarkClassName = props.checkmarkClassName, checkmarkStyle = props.checkmarkStyle, _d = props.setFocus, setFocus = _d === void 0 ? false : _d, rest = __rest(props, ["className", "disabled", "label", "status", "style", "checkmarkClassName", "checkmarkStyle", "setFocus"]);
|
|
43
44
|
useTheme();
|
|
44
45
|
var inputElementRef = React.useRef(null);
|
|
45
46
|
var refs = useMergedRefs(inputElementRef, ref);
|
|
@@ -48,11 +49,9 @@ export var Radio = React.forwardRef(function (props, ref) {
|
|
|
48
49
|
inputElementRef.current.focus();
|
|
49
50
|
}
|
|
50
51
|
}, [setFocus]);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
React.createElement("circle", { cx: '8', cy: '8', r: '4' }))),
|
|
56
|
-
label && React.createElement("span", { className: 'iui-label' }, label)));
|
|
52
|
+
var radio = (React.createElement("input", __assign({ className: cx('iui-radio', className && (_a = {}, _a[className] = !label, _a), checkmarkClassName), style: __assign(__assign({}, (!label && style)), checkmarkStyle), disabled: disabled, type: 'radio', ref: refs }, rest)));
|
|
53
|
+
return !label ? (radio) : (React.createElement("label", { className: cx('iui-radio-wrapper', (_b = { 'iui-disabled': disabled }, _b["iui-" + status] = !!status, _b), className), style: style },
|
|
54
|
+
radio,
|
|
55
|
+
label && React.createElement("span", { className: 'iui-radio-label' }, label)));
|
|
57
56
|
});
|
|
58
57
|
export default Radio;
|
|
@@ -30,6 +30,7 @@ import { DropdownMenu } from '../DropdownMenu';
|
|
|
30
30
|
import { MenuItem } from '../Menu/MenuItem';
|
|
31
31
|
import { useTheme } from '../utils';
|
|
32
32
|
import '@itwin/itwinui-css/css/inputs.css';
|
|
33
|
+
import SvgCaretDownSmall from '@itwin/itwinui-icons-react/cjs/icons/CaretDownSmall';
|
|
33
34
|
/**
|
|
34
35
|
* Select component to select value from options.
|
|
35
36
|
* Generic type is used for value. It prevents you from mistakenly using other types in `options`, `value` and `onChange`.
|
|
@@ -91,6 +92,7 @@ export var Select = function (props) {
|
|
|
91
92
|
var _f = React.useState(0), minWidth = _f[0], setMinWidth = _f[1];
|
|
92
93
|
var toggle = function () { return setIsOpen(function (open) { return !open; }); };
|
|
93
94
|
var selectRef = React.useRef(null);
|
|
95
|
+
var toggleButtonRef = React.useRef(null);
|
|
94
96
|
var onShowHandler = React.useCallback(function (instance) {
|
|
95
97
|
setIsOpen(true);
|
|
96
98
|
onShow === null || onShow === void 0 ? void 0 : onShow(instance);
|
|
@@ -137,13 +139,20 @@ export var Select = function (props) {
|
|
|
137
139
|
}
|
|
138
140
|
return options.find(function (option) { return option.value === value; });
|
|
139
141
|
}, [options, value]);
|
|
140
|
-
return (React.createElement("div", __assign({ className: cx('iui-
|
|
141
|
-
React.createElement(DropdownMenu, __assign({ menuItems: menuItems, placement: 'bottom-start', className: cx('iui-scroll', menuClassName), style: __assign({ minWidth: minWidth, maxWidth: "min(" + minWidth * 2 + "px, 90vw)", maxHeight: "300px" }, menuStyle), role: 'listbox', onShow: onShowHandler, onHide: onHideHandler, disabled: disabled }, popoverProps, { visible: isOpen
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
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(" + minWidth * 2 + "px, 90vw)", maxHeight: "300px" }, menuStyle), role: 'listbox', onShow: onShowHandler, onHide: onHideHandler, disabled: disabled }, popoverProps, { visible: isOpen, onClickOutside: function (_, _a) {
|
|
144
|
+
var _b;
|
|
145
|
+
var target = _a.target;
|
|
146
|
+
if (!((_b = toggleButtonRef.current) === null || _b === void 0 ? void 0 : _b.contains(target))) {
|
|
147
|
+
setIsOpen(false);
|
|
148
|
+
}
|
|
149
|
+
} }),
|
|
150
|
+
React.createElement("div", { ref: selectRef, className: cx('iui-select-button', (_a = {
|
|
151
|
+
'iui-placeholder': !selectedItem && !!placeholder,
|
|
152
|
+
'iui-disabled': disabled
|
|
153
|
+
},
|
|
154
|
+
_a["iui-" + size] = !!size,
|
|
155
|
+
_a)), onClick: function () { return !disabled && toggle(); }, onKeyDown: function (e) { return !disabled && onKeyDown(e, toggle); }, tabIndex: !disabled ? 0 : undefined },
|
|
147
156
|
!selectedItem && React.createElement("span", { className: 'iui-content' }, placeholder),
|
|
148
157
|
selectedItem &&
|
|
149
158
|
selectedItemRenderer &&
|
|
@@ -153,6 +162,12 @@ export var Select = function (props) {
|
|
|
153
162
|
React.cloneElement(selectedItem.icon, {
|
|
154
163
|
className: cx(selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.icon.props.className, 'iui-icon'),
|
|
155
164
|
}),
|
|
156
|
-
React.createElement("span", { className: 'iui-content' }, selectedItem.label)))))
|
|
165
|
+
React.createElement("span", { className: 'iui-content' }, selectedItem.label))))),
|
|
166
|
+
React.createElement("span", { ref: toggleButtonRef, className: cx('iui-end-icon', {
|
|
167
|
+
'iui-actionable': !disabled,
|
|
168
|
+
'iui-disabled': disabled,
|
|
169
|
+
'iui-open': isOpen,
|
|
170
|
+
}), onClick: function () { return !disabled && toggle(); } },
|
|
171
|
+
React.createElement(SvgCaretDownSmall, { "aria-hidden": true }))));
|
|
157
172
|
};
|
|
158
173
|
export default Select;
|
|
@@ -79,11 +79,10 @@ export var TablePaginator = function (props) {
|
|
|
79
79
|
var buttonSize = size != 'default' ? 'small' : undefined;
|
|
80
80
|
var pageButton = React.useCallback(function (index, tabIndex) {
|
|
81
81
|
if (tabIndex === void 0) { tabIndex = index === focusedIndex ? 0 : -1; }
|
|
82
|
-
return (React.createElement("
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}), onClick: function () { return onPageChange(index); }, "aria-current": index === currentPage, "aria-label": localization.goToPageLabel(index + 1), tabIndex: tabIndex }, index + 1)));
|
|
82
|
+
return (React.createElement("button", { key: index, className: cx('iui-paginator-page-button', {
|
|
83
|
+
'iui-active': index === currentPage,
|
|
84
|
+
'iui-paginator-page-button-small': buttonSize === 'small',
|
|
85
|
+
}), onClick: function () { return onPageChange(index); }, "aria-current": index === currentPage, "aria-label": localization.goToPageLabel(index + 1), tabIndex: tabIndex }, index + 1));
|
|
87
86
|
}, [focusedIndex, currentPage, localization, buttonSize, onPageChange]);
|
|
88
87
|
var totalPagesCount = Math.ceil(totalRowsCount / pageSize);
|
|
89
88
|
var pageList = React.useMemo(function () {
|
|
@@ -145,10 +144,9 @@ export var TablePaginator = function (props) {
|
|
|
145
144
|
var hasNoRows = totalPagesCount === 0;
|
|
146
145
|
var showPagesList = totalPagesCount > 1 || isLoading;
|
|
147
146
|
var showPageSizeList = pageSizeList && onPageSizeChange && !!totalRowsCount;
|
|
148
|
-
var ellipsis = (React.createElement("
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}) }, "\u2026")));
|
|
147
|
+
var ellipsis = (React.createElement("span", { className: cx('iui-paginator-ellipsis', {
|
|
148
|
+
'iui-paginator-ellipsis-small': size === 'small',
|
|
149
|
+
}) }, "\u2026"));
|
|
152
150
|
var noRowsContent = (React.createElement(React.Fragment, null, isLoading ? (React.createElement(ProgressRadial, { indeterminate: true, size: 'small' })) : (React.createElement(Button, { styleType: 'borderless', disabled: true, size: buttonSize }, "1"))));
|
|
153
151
|
if (!showPagesList && !showPageSizeList) {
|
|
154
152
|
return null;
|
|
@@ -63,7 +63,7 @@ var DatePickerInput = function (props) {
|
|
|
63
63
|
if (!((_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
|
|
64
64
|
close();
|
|
65
65
|
}
|
|
66
|
-
} },
|
|
66
|
+
}, appendTo: 'parent' },
|
|
67
67
|
React.createElement(LabeledInput, __assign({ displayStyle: 'inline', value: inputValue, onChange: onInputChange, onClick: close, svgIcon: React.createElement(IconButton, { styleType: 'borderless', onClick: function () { return setIsVisible(function (v) { return !v; }); }, ref: buttonRef },
|
|
68
68
|
React.createElement(SvgCalendar, null)) }, rest))));
|
|
69
69
|
};
|
package/esm/core/Tile/Tile.js
CHANGED
|
@@ -82,7 +82,6 @@ export var Tile = function (props) {
|
|
|
82
82
|
moreOptions && (React.createElement(DropdownMenu, { onShow: showMenu, onHide: hideMenu, menuItems: function (close) {
|
|
83
83
|
return moreOptions.map(function (option) {
|
|
84
84
|
return React.cloneElement(option, {
|
|
85
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
86
85
|
onClick: function (value) {
|
|
87
86
|
var _a, _b;
|
|
88
87
|
close();
|
|
@@ -91,10 +90,11 @@ export var Tile = function (props) {
|
|
|
91
90
|
});
|
|
92
91
|
});
|
|
93
92
|
} },
|
|
94
|
-
React.createElement(
|
|
93
|
+
React.createElement("div", { className: cx('iui-tile-more-options', {
|
|
95
94
|
'iui-visible': isMenuVisible,
|
|
96
|
-
})
|
|
97
|
-
React.createElement(
|
|
95
|
+
}) },
|
|
96
|
+
React.createElement(IconButton, { styleType: 'borderless', size: 'small', "aria-label": 'More options' },
|
|
97
|
+
React.createElement(SvgMore, null))))),
|
|
98
98
|
children),
|
|
99
99
|
buttons && React.createElement("div", { className: 'iui-tile-buttons' }, buttons)));
|
|
100
100
|
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { CommonProps } from '../utils';
|
|
3
|
+
import '@itwin/itwinui-css/css/tree.css';
|
|
4
|
+
export declare type NodeData<T> = {
|
|
5
|
+
/**
|
|
6
|
+
* Array of the child nodes contained in the node.
|
|
7
|
+
*/
|
|
8
|
+
subNodes?: Array<T>;
|
|
9
|
+
/**
|
|
10
|
+
* Unique id of the node.
|
|
11
|
+
*/
|
|
12
|
+
nodeId: string;
|
|
13
|
+
/**
|
|
14
|
+
* Custom type used to map type `T` to `NodeData`
|
|
15
|
+
*/
|
|
16
|
+
node: T;
|
|
17
|
+
/**
|
|
18
|
+
* Flag whether the node is expanded.
|
|
19
|
+
*/
|
|
20
|
+
isExpanded?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Flag whether the node is disabled.
|
|
23
|
+
*/
|
|
24
|
+
isDisabled?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Flag whether the node is selected.
|
|
27
|
+
*/
|
|
28
|
+
isSelected?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Flag whether the node has sub-nodes.
|
|
31
|
+
* Used to determine if node should be expandable.
|
|
32
|
+
*/
|
|
33
|
+
hasSubNodes: boolean;
|
|
34
|
+
};
|
|
35
|
+
export declare type NodeRenderProps<T> = Omit<NodeData<T>, 'subNodes'>;
|
|
36
|
+
export declare type TreeProps<T> = {
|
|
37
|
+
/**
|
|
38
|
+
* Render function that should return the node element.
|
|
39
|
+
* Recommended to use `TreeNode` component.
|
|
40
|
+
* Must be memoized.
|
|
41
|
+
* @example
|
|
42
|
+
* const nodeRenderer = React.useCallback(({ node, ...rest }: NodeRenderProps<DataType>) => (
|
|
43
|
+
* <TreeNode
|
|
44
|
+
* label={node.label}
|
|
45
|
+
* onNodeExpanded={onNodeExpanded}
|
|
46
|
+
* {...rest}
|
|
47
|
+
* />
|
|
48
|
+
* ), [onNodeExpanded])
|
|
49
|
+
*/
|
|
50
|
+
nodeRenderer: (props: NodeRenderProps<T>) => JSX.Element;
|
|
51
|
+
/**
|
|
52
|
+
* Array of custom data used for `TreeNodes` inside `Tree`.
|
|
53
|
+
*/
|
|
54
|
+
data: T[];
|
|
55
|
+
/**
|
|
56
|
+
* Function that maps your `data` entry to `NodeData` that has all info about the node state.
|
|
57
|
+
* It will be used to render a tree node in `nodeRenderer`.
|
|
58
|
+
* Must be memoized.
|
|
59
|
+
* @example
|
|
60
|
+
* const getNode = React.useCallback((node: DemoData): NodeData<DemoData> => {
|
|
61
|
+
* return {
|
|
62
|
+
* subNodes: node.subItems,
|
|
63
|
+
* nodeId: node.id,
|
|
64
|
+
* node,
|
|
65
|
+
* isExpanded: expandedNodes[node.id],
|
|
66
|
+
* hasSubNodes: node.subItems.length > 0,
|
|
67
|
+
* };
|
|
68
|
+
* }, [expandedNodes]);
|
|
69
|
+
*/
|
|
70
|
+
getNode: (node: T) => NodeData<T>;
|
|
71
|
+
} & Omit<CommonProps, 'title'>;
|
|
72
|
+
/**
|
|
73
|
+
* Tree component used to display a hierarchical structure of `TreeNodes`.
|
|
74
|
+
* User should control state of expanded, selected and disabled nodes using `getNode` prop.
|
|
75
|
+
* @example
|
|
76
|
+
type DemoData = {
|
|
77
|
+
id: string;
|
|
78
|
+
label: string;
|
|
79
|
+
subItems: DemoData[];
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const data: Array<DemoData> = [
|
|
83
|
+
{
|
|
84
|
+
id: 'Node-1',
|
|
85
|
+
label: 'Facility 1',
|
|
86
|
+
subItems: [{ id: 'Node-1-1', label: 'Unit 1', subItems: [] }],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: 'Node-2',
|
|
90
|
+
label: 'Facility 2',
|
|
91
|
+
subItems: [{ id: 'Node-2-1', label: 'Unit 2', subItems: [] }],
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
const [expandedNodes, setExpandedNodes] = React.useState<Record<string, boolean>>({});
|
|
96
|
+
const onNodeExpanded = React.useCallback((nodeId: string, isExpanded: boolean) => {
|
|
97
|
+
setExpandedNodes((oldExpanded) => ({ ...oldExpanded, [nodeId]: isExpanded }));
|
|
98
|
+
}, []);
|
|
99
|
+
|
|
100
|
+
const getNode = React.useCallback((node: DemoData): NodeData<DemoData> => {
|
|
101
|
+
return {
|
|
102
|
+
subNodes: node.subItems,
|
|
103
|
+
nodeId: node.id,
|
|
104
|
+
node,
|
|
105
|
+
isExpanded: expandedNodes[node.id],
|
|
106
|
+
hasSubNodes: node.subItems.length > 0,
|
|
107
|
+
};
|
|
108
|
+
}, [expandedNodes]);
|
|
109
|
+
|
|
110
|
+
<Tree<DemoData>
|
|
111
|
+
data={data}
|
|
112
|
+
getNode={getNode}
|
|
113
|
+
nodeRenderer={React.useCallback(({ node, ...rest }) => (
|
|
114
|
+
<TreeNode
|
|
115
|
+
label={node.label}
|
|
116
|
+
onNodeExpanded={onNodeExpanded}
|
|
117
|
+
{...rest}
|
|
118
|
+
/>
|
|
119
|
+
), [onNodeExpanded])}
|
|
120
|
+
/>
|
|
121
|
+
*/
|
|
122
|
+
export declare const Tree: <T>(props: TreeProps<T>) => JSX.Element;
|
|
123
|
+
export default Tree;
|