@itwin/itwinui-react 3.4.2 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/cjs/core/Carousel/Carousel.d.ts +4 -4
- package/cjs/core/Carousel/CarouselNavigation.d.ts +4 -4
- package/cjs/core/Dialog/Dialog.js +19 -17
- package/cjs/core/Dialog/DialogContext.d.ts +4 -0
- package/cjs/core/Dialog/DialogMain.js +1 -1
- package/cjs/core/Dialog/DialogTitleBar.js +1 -1
- package/cjs/core/InputGroup/InputGroup.d.ts +4 -0
- package/cjs/core/InputGroup/InputGroup.js +20 -4
- package/cjs/core/InputWithDecorations/InputWithDecorations.d.ts +18 -62
- package/cjs/core/InputWithDecorations/InputWithDecorations.js +21 -6
- package/cjs/core/LabeledSelect/LabeledSelect.d.ts +376 -4
- package/cjs/core/LabeledSelect/LabeledSelect.js +1 -1
- package/cjs/core/Popover/Popover.d.ts +6 -3
- package/cjs/core/ProgressIndicators/ProgressLinear.js +6 -1
- package/cjs/core/ProgressIndicators/ProgressRadial.js +8 -3
- package/cjs/core/SearchBox/SearchBox.js +4 -6
- package/cjs/core/Select/Select.d.ts +197 -102
- package/cjs/core/Select/Select.js +72 -19
- package/cjs/core/Table/Table.js +2 -1
- package/cjs/core/Tabs/Tabs.js +19 -3
- package/cjs/core/Tile/Tile.d.ts +2 -2
- package/cjs/core/ToggleSwitch/ToggleSwitch.d.ts +4 -2
- package/cjs/core/ToggleSwitch/ToggleSwitch.js +5 -11
- package/cjs/core/Typography/Anchor.d.ts +21 -1
- package/cjs/core/Typography/Anchor.js +38 -3
- package/cjs/core/VisuallyHidden/VisuallyHidden.js +19 -3
- package/cjs/core/utils/components/InputFlexContainer.d.ts +25 -0
- package/cjs/core/utils/components/InputFlexContainer.js +19 -1
- package/cjs/core/utils/components/LineClamp.d.ts +5 -0
- package/cjs/core/utils/components/LineClamp.js +49 -0
- package/cjs/core/utils/components/ShadowRoot.d.ts +2 -1
- package/cjs/core/utils/components/ShadowRoot.js +19 -4
- package/cjs/core/utils/components/index.d.ts +1 -0
- package/cjs/core/utils/components/index.js +1 -0
- package/cjs/core/utils/functions/polymorphic.d.ts +5 -3
- package/cjs/core/utils/functions/polymorphic.js +20 -5
- package/cjs/core/utils/icons/Svg.js +5 -1
- package/cjs/core/utils/icons/SvgStatusError.js +1 -1
- package/esm/core/Carousel/Carousel.d.ts +4 -4
- package/esm/core/Carousel/CarouselNavigation.d.ts +4 -4
- package/esm/core/Dialog/Dialog.js +19 -17
- package/esm/core/Dialog/DialogContext.d.ts +4 -0
- package/esm/core/Dialog/DialogMain.js +1 -1
- package/esm/core/Dialog/DialogTitleBar.js +1 -1
- package/esm/core/InputGroup/InputGroup.d.ts +4 -0
- package/esm/core/InputGroup/InputGroup.js +20 -4
- package/esm/core/InputWithDecorations/InputWithDecorations.d.ts +18 -62
- package/esm/core/InputWithDecorations/InputWithDecorations.js +22 -7
- package/esm/core/LabeledSelect/LabeledSelect.d.ts +376 -4
- package/esm/core/LabeledSelect/LabeledSelect.js +1 -1
- package/esm/core/Popover/Popover.d.ts +6 -3
- package/esm/core/ProgressIndicators/ProgressLinear.js +7 -2
- package/esm/core/ProgressIndicators/ProgressRadial.js +9 -4
- package/esm/core/SearchBox/SearchBox.js +5 -7
- package/esm/core/Select/Select.d.ts +197 -102
- package/esm/core/Select/Select.js +73 -20
- package/esm/core/Table/Table.js +2 -1
- package/esm/core/Tabs/Tabs.js +19 -3
- package/esm/core/Tile/Tile.d.ts +2 -2
- package/esm/core/ToggleSwitch/ToggleSwitch.d.ts +4 -2
- package/esm/core/ToggleSwitch/ToggleSwitch.js +6 -12
- package/esm/core/Typography/Anchor.d.ts +21 -1
- package/esm/core/Typography/Anchor.js +11 -2
- package/esm/core/VisuallyHidden/VisuallyHidden.js +19 -3
- package/esm/core/utils/components/InputFlexContainer.d.ts +25 -0
- package/esm/core/utils/components/InputFlexContainer.js +18 -0
- package/esm/core/utils/components/LineClamp.d.ts +5 -0
- package/esm/core/utils/components/LineClamp.js +23 -0
- package/esm/core/utils/components/ShadowRoot.d.ts +2 -1
- package/esm/core/utils/components/ShadowRoot.js +19 -4
- package/esm/core/utils/components/index.d.ts +1 -0
- package/esm/core/utils/components/index.js +1 -0
- package/esm/core/utils/functions/polymorphic.d.ts +5 -3
- package/esm/core/utils/functions/polymorphic.js +20 -5
- package/esm/core/utils/icons/Svg.js +5 -1
- package/esm/core/utils/icons/SvgStatusError.js +1 -1
- package/package.json +27 -27
- package/styles.css +39 -38
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import cx from 'classnames';
|
|
7
|
-
import { InputFlexContainer, SvgSearch, SvgCloseSmall, useSafeContext, useId, useMergedRefs, mergeEventHandlers, Box, } from '../utils/index.js';
|
|
8
|
-
import { IconButton } from '../Buttons/IconButton.js';
|
|
9
|
-
import { Icon } from '../Icon/Icon.js';
|
|
7
|
+
import { InputFlexContainer, SvgSearch, SvgCloseSmall, useSafeContext, useId, useMergedRefs, mergeEventHandlers, Box, InputFlexContainerIcon, InputFlexContainerButton, } from '../utils/index.js';
|
|
10
8
|
const SearchBoxContext = React.createContext(undefined);
|
|
11
9
|
const SearchBoxComponent = React.forwardRef((props, ref) => {
|
|
12
10
|
const { size, expandable = false, isDisabled = false, onCollapse: onCollapseProp, onExpand: onExpandProp, isExpanded: isExpandedProp, children, inputProps, className, ...rest } = props;
|
|
@@ -67,7 +65,7 @@ SearchBoxExpandedState.displayName = 'SearchBox.ExpandedState';
|
|
|
67
65
|
// ----------------------------------------------------------------------------
|
|
68
66
|
const SearchBoxIcon = React.forwardRef((props, ref) => {
|
|
69
67
|
const { className, children, ...rest } = props;
|
|
70
|
-
return (React.createElement(
|
|
68
|
+
return (React.createElement(InputFlexContainerIcon, { "aria-hidden": true, className: cx('iui-search-icon', className), ref: ref, ...rest }, children ?? React.createElement(SvgSearch, null)));
|
|
71
69
|
});
|
|
72
70
|
SearchBoxIcon.displayName = 'SearchBox.Icon';
|
|
73
71
|
// ----------------------------------------------------------------------------
|
|
@@ -86,7 +84,7 @@ SearchBoxInput.displayName = 'SearchBox.Input';
|
|
|
86
84
|
const SearchBoxButton = React.forwardRef((props, ref) => {
|
|
87
85
|
const { children, ...rest } = props;
|
|
88
86
|
const { size: sizeContext, isDisabled } = useSafeContext(SearchBoxContext);
|
|
89
|
-
return (React.createElement(
|
|
87
|
+
return (React.createElement(InputFlexContainerButton, { size: sizeContext, ref: ref, disabled: isDisabled, ...rest }, children ?? React.createElement(SvgSearch, null)));
|
|
90
88
|
});
|
|
91
89
|
SearchBoxButton.displayName = 'SearchBox.Button';
|
|
92
90
|
// ----------------------------------------------------------------------------
|
|
@@ -98,9 +96,9 @@ const SearchBoxCollapseButton = React.forwardRef((props, ref) => {
|
|
|
98
96
|
SearchBoxCollapseButton.displayName = 'SearchBox.CollapseButton';
|
|
99
97
|
// ----------------------------------------------------------------------------
|
|
100
98
|
const SearchBoxExpandButton = React.forwardRef((props, ref) => {
|
|
101
|
-
const { children,
|
|
99
|
+
const { children, onClick: onClickProp, ...rest } = props;
|
|
102
100
|
const { onExpand, size: sizeContext, isDisabled, openButtonRef, } = useSafeContext(SearchBoxContext);
|
|
103
|
-
return (React.createElement(SearchBoxButton, { ref: useMergedRefs(ref, openButtonRef),
|
|
101
|
+
return (React.createElement(SearchBoxButton, { ref: useMergedRefs(ref, openButtonRef), "aria-label": 'Expand searchbox', size: sizeContext, disabled: isDisabled, onClick: mergeEventHandlers(onClickProp, onExpand), styleType: 'default', ...rest }, children ?? React.createElement(SvgSearch, null)));
|
|
104
102
|
});
|
|
105
103
|
SearchBoxExpandButton.displayName = 'SearchBox.ExpandButton';
|
|
106
104
|
// ----------------------------------------------------------------------------
|
|
@@ -1,54 +1,193 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { CommonProps } from '../utils/index.js';
|
|
3
3
|
import { usePopover } from '../Popover/Popover.js';
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Select component to select value from options.
|
|
6
|
+
* Generic type is used for value. It prevents you from mistakenly using other types in `options`, `value` and `onChange`.
|
|
7
|
+
* @example
|
|
8
|
+
* <caption>Basic select.</caption>
|
|
9
|
+
* <Select
|
|
10
|
+
* options={[
|
|
11
|
+
* { value: '1', label: 'Option 1' },
|
|
12
|
+
* { value: '2', label: 'Option 2' },
|
|
13
|
+
* { value: '3', label: 'Option 3' },
|
|
14
|
+
* ]}
|
|
15
|
+
* />
|
|
16
|
+
* @example
|
|
17
|
+
* <caption>Native select.</caption>
|
|
18
|
+
* <Select
|
|
19
|
+
* native
|
|
20
|
+
* options={[
|
|
21
|
+
* { value: '1', label: 'Option 1' },
|
|
22
|
+
* { value: '2', label: 'Option 2' },
|
|
23
|
+
* { value: '3', label: 'Option 3' },
|
|
24
|
+
* ]}
|
|
25
|
+
* />
|
|
26
|
+
* @example
|
|
27
|
+
* <caption>Disabled select with placeholder.</caption>
|
|
28
|
+
* <Select
|
|
29
|
+
* disabled={true}
|
|
30
|
+
* placeholder='Placeholder text'
|
|
31
|
+
* options={[{ value: 1, label: 'Option 1' }, { value: 2, label: 'Option 2' }, { value: 3, label: 'Option 3' }]}
|
|
32
|
+
* />
|
|
33
|
+
* @example
|
|
34
|
+
* <caption>Select with selected value and change handler.</caption>
|
|
35
|
+
* <Select
|
|
36
|
+
* value={selectedValue}
|
|
37
|
+
* onChange={(value) => setSelectedValue(value)}
|
|
38
|
+
* options={[{ value: 1, label: 'Option 1' }, { value: 2, label: 'Option 2' }, { value: 3, label: 'Option 3' }]}
|
|
39
|
+
* />
|
|
40
|
+
* @example
|
|
41
|
+
* <caption>Select using custom renderers for menu items and selected value.</caption>
|
|
42
|
+
* <Select
|
|
43
|
+
* options={[
|
|
44
|
+
* { value: 'yellow', label: 'Yellow' },
|
|
45
|
+
* { value: 'green', label: 'Green' },
|
|
46
|
+
* { value: 'red', label: 'Red' },
|
|
47
|
+
* ]}
|
|
48
|
+
* value={selectedValue}
|
|
49
|
+
* placeholder='Placeholder text'
|
|
50
|
+
* itemRenderer={(option, itemProps) => (
|
|
51
|
+
* <MenuItem
|
|
52
|
+
* style={{ color: option.value }}
|
|
53
|
+
* isSelected={itemProps.isSelected}
|
|
54
|
+
* onClick={() => {
|
|
55
|
+
* setSelectedValue(option.value);
|
|
56
|
+
* itemProps.close();
|
|
57
|
+
* }}
|
|
58
|
+
* role='option'
|
|
59
|
+
* ref={(el) => itemProps.isSelected && el?.scrollIntoView()}
|
|
60
|
+
* >
|
|
61
|
+
* {option.label}
|
|
62
|
+
* </MenuItem>
|
|
63
|
+
* )}
|
|
64
|
+
* selectedItemRenderer={(option) => (
|
|
65
|
+
* <span style={{ backgroundColor: option.value }}>{option.label}</span>
|
|
66
|
+
* )}
|
|
67
|
+
* />
|
|
68
|
+
*/
|
|
69
|
+
export declare const Select: <T>(props: SelectProps<T> & {
|
|
70
|
+
ref?: React.ForwardedRef<HTMLElement> | undefined;
|
|
71
|
+
}) => JSX.Element;
|
|
72
|
+
export type SelectProps<T> = Omit<React.ComponentPropsWithoutRef<'div'>, 'onChange' | 'placeholder' | 'value' | 'defaultValue'> & (({
|
|
5
73
|
/**
|
|
6
|
-
*
|
|
74
|
+
* If true, the native `<select>` element will be rendered.
|
|
75
|
+
*
|
|
76
|
+
* Extra props, such as `name` can be passed to the `<select>` using `triggerProps`.
|
|
77
|
+
*
|
|
78
|
+
* @default false
|
|
7
79
|
*/
|
|
8
|
-
|
|
80
|
+
native: true;
|
|
81
|
+
} & NativeSelectProps) | ({
|
|
82
|
+
native?: false;
|
|
83
|
+
} & CustomSelectProps<T> & {
|
|
9
84
|
/**
|
|
10
|
-
*
|
|
85
|
+
* styleType is only supported for `<Select native>`.
|
|
11
86
|
*/
|
|
12
|
-
|
|
13
|
-
};
|
|
14
|
-
|
|
87
|
+
styleType?: never;
|
|
88
|
+
}));
|
|
89
|
+
type NativeSelectProps = SelectCommonProps & {
|
|
15
90
|
/**
|
|
16
|
-
*
|
|
91
|
+
* Selected option value.
|
|
92
|
+
*
|
|
93
|
+
* Must be a string, because it is passed as an attribute to the native <select>.
|
|
94
|
+
*
|
|
95
|
+
* Alternatively, pass `null` to reset the value.
|
|
17
96
|
*/
|
|
18
|
-
|
|
97
|
+
value?: string | null;
|
|
19
98
|
/**
|
|
20
|
-
*
|
|
99
|
+
* Callback invoked when the selected value changes.
|
|
21
100
|
*/
|
|
22
|
-
|
|
101
|
+
onChange?: (value: string, event: React.ChangeEvent<HTMLSelectElement>) => void;
|
|
23
102
|
/**
|
|
24
|
-
*
|
|
25
|
-
* Use 'large' when any of the select options have `sublabel`.
|
|
103
|
+
* Array of options that populates the select menu.
|
|
26
104
|
*
|
|
27
|
-
*
|
|
105
|
+
* The `value` property of each option must be a string.
|
|
28
106
|
*/
|
|
29
|
-
|
|
107
|
+
options: Array<{
|
|
108
|
+
label: string;
|
|
109
|
+
value: string;
|
|
110
|
+
disabled?: boolean;
|
|
111
|
+
}>;
|
|
30
112
|
/**
|
|
31
|
-
*
|
|
113
|
+
* Default value that is selected on initial render. This is useful when you don't want to
|
|
114
|
+
* maintain your own state but still want to control the initial value.
|
|
115
|
+
*
|
|
116
|
+
* If not passed, the first option (or placeholder) will be automatically selected.
|
|
32
117
|
*/
|
|
33
|
-
|
|
118
|
+
defaultValue?: string;
|
|
34
119
|
/**
|
|
35
|
-
*
|
|
36
|
-
* SVG icon component shown on the left.
|
|
120
|
+
* Props to pass to the select element.
|
|
37
121
|
*/
|
|
38
|
-
|
|
122
|
+
triggerProps?: Omit<React.ComponentPropsWithRef<'select'>, 'size'>;
|
|
123
|
+
required?: boolean;
|
|
124
|
+
multiple?: never;
|
|
125
|
+
} & NativeSelectStyleTypeProps;
|
|
126
|
+
type NativeSelectStyleTypeProps = {
|
|
39
127
|
/**
|
|
40
|
-
*
|
|
128
|
+
* Style of the select.
|
|
129
|
+
* Use 'borderless' to hide outline.
|
|
130
|
+
* @default 'default'
|
|
41
131
|
*/
|
|
42
|
-
|
|
132
|
+
styleType?: 'default';
|
|
43
133
|
/**
|
|
44
|
-
*
|
|
134
|
+
* Placeholder for when no item is selected.
|
|
135
|
+
*
|
|
136
|
+
* Will be rendered as a disabled option at the top of the list, and automatically
|
|
137
|
+
* selected when no `value` or `defaultValue` is provided.
|
|
138
|
+
*
|
|
139
|
+
* Not allowed when `styleType` is `borderless`.
|
|
140
|
+
*/
|
|
141
|
+
placeholder?: string;
|
|
142
|
+
} | {
|
|
143
|
+
styleType: 'borderless';
|
|
144
|
+
placeholder?: never;
|
|
145
|
+
};
|
|
146
|
+
type SelectCommonProps = {
|
|
147
|
+
/**
|
|
148
|
+
* Disables select.
|
|
149
|
+
* @default false
|
|
45
150
|
*/
|
|
46
151
|
disabled?: boolean;
|
|
47
152
|
/**
|
|
48
|
-
*
|
|
153
|
+
* Modify size of select.
|
|
49
154
|
*/
|
|
50
|
-
|
|
51
|
-
|
|
155
|
+
size?: 'small' | 'large';
|
|
156
|
+
/**
|
|
157
|
+
* Status of select.
|
|
158
|
+
*/
|
|
159
|
+
status?: 'positive' | 'warning' | 'negative';
|
|
160
|
+
};
|
|
161
|
+
export type CustomSelectProps<T> = SelectCommonProps & {
|
|
162
|
+
/**
|
|
163
|
+
* Placeholder when no item is selected.
|
|
164
|
+
*/
|
|
165
|
+
placeholder?: React.ReactNode;
|
|
166
|
+
/**
|
|
167
|
+
* Array of options that populates the select menu.
|
|
168
|
+
*/
|
|
169
|
+
options: SelectOption<T>[];
|
|
170
|
+
/**
|
|
171
|
+
* Custom renderer for an item in the dropdown list. `MenuItem` item props are going to be populated if not provided.
|
|
172
|
+
*/
|
|
173
|
+
itemRenderer?: (option: SelectOption<T>, itemProps: ItemRendererProps) => JSX.Element;
|
|
174
|
+
/**
|
|
175
|
+
* Custom class for menu.
|
|
176
|
+
*/
|
|
177
|
+
menuClassName?: string;
|
|
178
|
+
/**
|
|
179
|
+
* Custom style for menu.
|
|
180
|
+
*/
|
|
181
|
+
menuStyle?: React.CSSProperties;
|
|
182
|
+
/**
|
|
183
|
+
* Props to customize Popover behavior.
|
|
184
|
+
*/
|
|
185
|
+
popoverProps?: Pick<Parameters<typeof usePopover>[0], 'visible' | 'onVisibleChange' | 'placement' | 'matchWidth' | 'closeOnOutsideClick'>;
|
|
186
|
+
/**
|
|
187
|
+
* Props to pass to the select button (trigger) element.
|
|
188
|
+
*/
|
|
189
|
+
triggerProps?: React.ComponentPropsWithRef<'div'>;
|
|
190
|
+
} & SelectMultipleTypeProps<T> & Omit<React.ComponentPropsWithoutRef<'div'>, 'size' | 'disabled' | 'placeholder' | 'onChange'>;
|
|
52
191
|
export type SelectValueChangeEvent = 'added' | 'removed';
|
|
53
192
|
export type SelectMultipleTypeProps<T> = {
|
|
54
193
|
/**
|
|
@@ -64,8 +203,10 @@ export type SelectMultipleTypeProps<T> = {
|
|
|
64
203
|
/**
|
|
65
204
|
* Selected option value.
|
|
66
205
|
* If `multiple` is enabled, it is an array of values.
|
|
206
|
+
*
|
|
207
|
+
* Pass `null` to reset the value.
|
|
67
208
|
*/
|
|
68
|
-
value?: T;
|
|
209
|
+
value?: T | null;
|
|
69
210
|
/**
|
|
70
211
|
* Callback function handling change event on select.
|
|
71
212
|
*/
|
|
@@ -76,98 +217,52 @@ export type SelectMultipleTypeProps<T> = {
|
|
|
76
217
|
value?: T[];
|
|
77
218
|
onChange?: (value: T, event: SelectValueChangeEvent) => void;
|
|
78
219
|
};
|
|
79
|
-
export type
|
|
220
|
+
export type ItemRendererProps = {
|
|
80
221
|
/**
|
|
81
|
-
*
|
|
222
|
+
* Close handler that closes the dropdown.
|
|
82
223
|
*/
|
|
83
|
-
|
|
224
|
+
close: () => void;
|
|
84
225
|
/**
|
|
85
|
-
*
|
|
226
|
+
* Indicates whether an item is selected.
|
|
86
227
|
*/
|
|
87
|
-
|
|
228
|
+
isSelected: boolean;
|
|
229
|
+
};
|
|
230
|
+
export type SelectOption<T> = {
|
|
88
231
|
/**
|
|
89
|
-
*
|
|
90
|
-
* @default false
|
|
232
|
+
* Label of the item used in dropdown list and when selected.
|
|
91
233
|
*/
|
|
92
|
-
|
|
234
|
+
label: string;
|
|
93
235
|
/**
|
|
94
|
-
*
|
|
236
|
+
* Sublabel of the item shown below the label.
|
|
95
237
|
*/
|
|
96
|
-
|
|
238
|
+
sublabel?: React.ReactNode;
|
|
97
239
|
/**
|
|
98
|
-
*
|
|
240
|
+
* Modify height of the item.
|
|
241
|
+
* Use 'large' when any of the select options have `sublabel`.
|
|
242
|
+
*
|
|
243
|
+
* Defaults to 'large' if `sublabel` provided, otherwise 'default'.
|
|
99
244
|
*/
|
|
100
|
-
|
|
245
|
+
size?: 'default' | 'large';
|
|
101
246
|
/**
|
|
102
|
-
*
|
|
247
|
+
* Value of the item.
|
|
103
248
|
*/
|
|
104
|
-
|
|
249
|
+
value: T;
|
|
105
250
|
/**
|
|
106
|
-
*
|
|
251
|
+
* @deprecated Use startIcon
|
|
252
|
+
* SVG icon component shown on the left.
|
|
107
253
|
*/
|
|
108
|
-
|
|
254
|
+
icon?: JSX.Element;
|
|
109
255
|
/**
|
|
110
|
-
*
|
|
256
|
+
* SVG icon component shown on the left.
|
|
111
257
|
*/
|
|
112
|
-
|
|
258
|
+
startIcon?: JSX.Element;
|
|
113
259
|
/**
|
|
114
|
-
*
|
|
260
|
+
* Item is disabled.
|
|
115
261
|
*/
|
|
116
|
-
|
|
262
|
+
disabled?: boolean;
|
|
117
263
|
/**
|
|
118
|
-
*
|
|
264
|
+
* Any other props.
|
|
119
265
|
*/
|
|
120
|
-
|
|
121
|
-
} &
|
|
122
|
-
|
|
123
|
-
* Select component to select value from options.
|
|
124
|
-
* Generic type is used for value. It prevents you from mistakenly using other types in `options`, `value` and `onChange`.
|
|
125
|
-
* @example
|
|
126
|
-
* <caption>Basic select.</caption>
|
|
127
|
-
* <Select<number> options={[{ value: 1, label: 'Option 1' }, { value: 2, label: 'Option 2' }, { value: 3, label: 'Option 3' }]} />
|
|
128
|
-
* @example
|
|
129
|
-
* <caption>Disabled select with placeholder.</caption>
|
|
130
|
-
* <Select
|
|
131
|
-
* disabled={true}
|
|
132
|
-
* placeholder='Placeholder text'
|
|
133
|
-
* options={[{ value: 1, label: 'Option 1' }, { value: 2, label: 'Option 2' }, { value: 3, label: 'Option 3' }]}
|
|
134
|
-
* />
|
|
135
|
-
* @example
|
|
136
|
-
* <caption>Select with selected value and change handler.</caption>
|
|
137
|
-
* <Select<number>
|
|
138
|
-
* value={selectedValue}
|
|
139
|
-
* onChange={(value) => setSelectedValue(value)}
|
|
140
|
-
* options={[{ value: 1, label: 'Option 1' }, { value: 2, label: 'Option 2' }, { value: 3, label: 'Option 3' }]}
|
|
141
|
-
* />
|
|
142
|
-
* @example
|
|
143
|
-
* <caption>Select using custom renderers for menu items and selected value.</caption>
|
|
144
|
-
* <Select<string>
|
|
145
|
-
* options={[
|
|
146
|
-
* { value: 'yellow', label: 'Yellow' },
|
|
147
|
-
* { value: 'green', label: 'Green' },
|
|
148
|
-
* { value: 'red', label: 'Red' },
|
|
149
|
-
* ]}
|
|
150
|
-
* value={selectedValue}
|
|
151
|
-
* placeholder='Placeholder text'
|
|
152
|
-
* itemRenderer={(option, itemProps) => (
|
|
153
|
-
* <MenuItem
|
|
154
|
-
* style={{ color: option.value }}
|
|
155
|
-
* isSelected={itemProps.isSelected}
|
|
156
|
-
* onClick={() => {
|
|
157
|
-
* setSelectedValue(option.value);
|
|
158
|
-
* itemProps.close();
|
|
159
|
-
* }}
|
|
160
|
-
* role='option'
|
|
161
|
-
* ref={(el) => itemProps.isSelected && el?.scrollIntoView()}
|
|
162
|
-
* >
|
|
163
|
-
* {option.label}
|
|
164
|
-
* </MenuItem>
|
|
165
|
-
* )}
|
|
166
|
-
* selectedItemRenderer={(option) => (
|
|
167
|
-
* <span style={{ backgroundColor: option.value }}>{option.label}</span>
|
|
168
|
-
* )}
|
|
169
|
-
* />
|
|
170
|
-
*/
|
|
171
|
-
export declare const Select: <T>(props: SelectProps<T> & {
|
|
172
|
-
ref?: React.ForwardedRef<HTMLElement> | undefined;
|
|
173
|
-
}) => JSX.Element;
|
|
266
|
+
[key: string]: unknown;
|
|
267
|
+
} & CommonProps;
|
|
268
|
+
export {};
|
|
@@ -6,24 +6,34 @@ import * as React from 'react';
|
|
|
6
6
|
import cx from 'classnames';
|
|
7
7
|
import { Menu } from '../Menu/Menu.js';
|
|
8
8
|
import { MenuItem } from '../Menu/MenuItem.js';
|
|
9
|
-
import { SvgCaretDownSmall, useId, AutoclearingHiddenLiveRegion, Box, Portal, useMergedRefs, SvgCheckmark, useLatestRef, InputWithIcon, } from '../utils/index.js';
|
|
9
|
+
import { SvgCaretDownSmall, useId, AutoclearingHiddenLiveRegion, Box, Portal, useMergedRefs, SvgCheckmark, useLatestRef, InputWithIcon, mergeEventHandlers, } from '../utils/index.js';
|
|
10
10
|
import { SelectTag } from './SelectTag.js';
|
|
11
11
|
import { SelectTagContainer } from './SelectTagContainer.js';
|
|
12
12
|
import { Icon } from '../Icon/Icon.js';
|
|
13
13
|
import { usePopover } from '../Popover/Popover.js';
|
|
14
|
-
|
|
15
|
-
return multiple;
|
|
16
|
-
};
|
|
17
|
-
// Type guard for multiple did not work
|
|
18
|
-
const isSingleOnChange = (onChange, multiple) => {
|
|
19
|
-
return !multiple;
|
|
20
|
-
};
|
|
14
|
+
// ----------------------------------------------------------------------------
|
|
21
15
|
/**
|
|
22
16
|
* Select component to select value from options.
|
|
23
17
|
* Generic type is used for value. It prevents you from mistakenly using other types in `options`, `value` and `onChange`.
|
|
24
18
|
* @example
|
|
25
19
|
* <caption>Basic select.</caption>
|
|
26
|
-
* <Select
|
|
20
|
+
* <Select
|
|
21
|
+
* options={[
|
|
22
|
+
* { value: '1', label: 'Option 1' },
|
|
23
|
+
* { value: '2', label: 'Option 2' },
|
|
24
|
+
* { value: '3', label: 'Option 3' },
|
|
25
|
+
* ]}
|
|
26
|
+
* />
|
|
27
|
+
* @example
|
|
28
|
+
* <caption>Native select.</caption>
|
|
29
|
+
* <Select
|
|
30
|
+
* native
|
|
31
|
+
* options={[
|
|
32
|
+
* { value: '1', label: 'Option 1' },
|
|
33
|
+
* { value: '2', label: 'Option 2' },
|
|
34
|
+
* { value: '3', label: 'Option 3' },
|
|
35
|
+
* ]}
|
|
36
|
+
* />
|
|
27
37
|
* @example
|
|
28
38
|
* <caption>Disabled select with placeholder.</caption>
|
|
29
39
|
* <Select
|
|
@@ -33,14 +43,14 @@ const isSingleOnChange = (onChange, multiple) => {
|
|
|
33
43
|
* />
|
|
34
44
|
* @example
|
|
35
45
|
* <caption>Select with selected value and change handler.</caption>
|
|
36
|
-
* <Select
|
|
46
|
+
* <Select
|
|
37
47
|
* value={selectedValue}
|
|
38
48
|
* onChange={(value) => setSelectedValue(value)}
|
|
39
49
|
* options={[{ value: 1, label: 'Option 1' }, { value: 2, label: 'Option 2' }, { value: 3, label: 'Option 3' }]}
|
|
40
50
|
* />
|
|
41
51
|
* @example
|
|
42
52
|
* <caption>Select using custom renderers for menu items and selected value.</caption>
|
|
43
|
-
* <Select
|
|
53
|
+
* <Select
|
|
44
54
|
* options={[
|
|
45
55
|
* { value: 'yellow', label: 'Yellow' },
|
|
46
56
|
* { value: 'green', label: 'Green' },
|
|
@@ -68,12 +78,38 @@ const isSingleOnChange = (onChange, multiple) => {
|
|
|
68
78
|
* />
|
|
69
79
|
*/
|
|
70
80
|
export const Select = React.forwardRef((props, forwardedRef) => {
|
|
81
|
+
const { native, ...rest } = props;
|
|
82
|
+
const Component = native ? NativeSelect : CustomSelect;
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
84
|
+
// @ts-ignore
|
|
85
|
+
return React.createElement(Component, { ...rest, ref: forwardedRef });
|
|
86
|
+
});
|
|
87
|
+
// ----------------------------------------------------------------------------
|
|
88
|
+
const NativeSelect = React.forwardRef((props, forwardedRef) => {
|
|
89
|
+
const { triggerProps, options, disabled, placeholder, defaultValue: defaultValueProp = placeholder !== undefined ? '' : undefined, value: valueProp, onChange: onChangeProp, size, status, styleType, required, ...rest } = props;
|
|
90
|
+
return (React.createElement(InputWithIcon, { ...rest, ref: forwardedRef },
|
|
91
|
+
React.createElement(SelectButton, { as: 'select', size: size, status: status, styleType: styleType, disabled: disabled, defaultValue: valueProp === undefined ? defaultValueProp : undefined, value: valueProp === null ? '' : valueProp, required: required, ...triggerProps, onKeyDown: mergeEventHandlers(triggerProps?.onKeyDown, (event) => {
|
|
92
|
+
// Firefox does not open the menu on Enter, so we need to do it manually.
|
|
93
|
+
if (event.key === 'Enter') {
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
95
|
+
// @ts-ignore
|
|
96
|
+
event.currentTarget.showPicker?.();
|
|
97
|
+
}
|
|
98
|
+
}), onChange: mergeEventHandlers(triggerProps?.onChange, (event) => {
|
|
99
|
+
onChangeProp?.(event.currentTarget.value, event);
|
|
100
|
+
}) },
|
|
101
|
+
styleType !== 'borderless' && placeholder !== undefined ? (React.createElement("option", { value: '', disabled: true }, placeholder)) : null,
|
|
102
|
+
options.map((option) => (React.createElement("option", { key: option.value, ...option }, option.label)))),
|
|
103
|
+
React.createElement(SelectEndIcon, { disabled: disabled })));
|
|
104
|
+
});
|
|
105
|
+
// ----------------------------------------------------------------------------
|
|
106
|
+
const CustomSelect = React.forwardRef((props, forwardedRef) => {
|
|
71
107
|
const uid = useId();
|
|
72
108
|
const { options, value: valueProp, onChange: onChangeProp, placeholder, disabled = false, size, itemRenderer, selectedItemRenderer, menuClassName, menuStyle, multiple = false, triggerProps, status, popoverProps, ...rest } = props;
|
|
73
109
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
74
110
|
const [liveRegionSelection, setLiveRegionSelection] = React.useState('');
|
|
75
111
|
const [uncontrolledValue, setUncontrolledValue] = React.useState();
|
|
76
|
-
const value = valueProp
|
|
112
|
+
const value = valueProp !== undefined ? valueProp : uncontrolledValue;
|
|
77
113
|
const onChangeRef = useLatestRef(onChangeProp);
|
|
78
114
|
const selectRef = React.useRef(null);
|
|
79
115
|
const show = React.useCallback(() => {
|
|
@@ -161,18 +197,13 @@ export const Select = React.forwardRef((props, forwardedRef) => {
|
|
|
161
197
|
});
|
|
162
198
|
return (React.createElement(React.Fragment, null,
|
|
163
199
|
React.createElement(InputWithIcon, { ...rest, ref: useMergedRefs(popover.refs.setPositionReference, forwardedRef) },
|
|
164
|
-
React.createElement(
|
|
165
|
-
'iui-placeholder': (!selectedItems || selectedItems.length === 0) &&
|
|
166
|
-
!!placeholder,
|
|
200
|
+
React.createElement(SelectButton, { ...popover.getReferenceProps(), tabIndex: 0, role: 'combobox', size: size, status: status, "aria-disabled": disabled ? 'true' : undefined, "aria-autocomplete": 'none', "aria-expanded": isOpen, "aria-haspopup": 'listbox', "aria-controls": `${uid}-menu`, ...triggerProps, ref: useMergedRefs(selectRef, triggerProps?.ref, popover.refs.setReference), className: cx({
|
|
201
|
+
'iui-placeholder': (!selectedItems || selectedItems.length === 0) && !!placeholder,
|
|
167
202
|
'iui-disabled': disabled,
|
|
168
203
|
}, triggerProps?.className) },
|
|
169
204
|
(!selectedItems || selectedItems.length === 0) && (React.createElement(Box, { as: 'span', className: 'iui-content' }, placeholder)),
|
|
170
205
|
isMultipleEnabled(selectedItems, multiple) ? (React.createElement(MultipleSelectButton, { selectedItems: selectedItems, selectedItemsRenderer: selectedItemRenderer, tagRenderer: tagRenderer })) : (React.createElement(SingleSelectButton, { selectedItem: selectedItems, selectedItemRenderer: selectedItemRenderer }))),
|
|
171
|
-
React.createElement(
|
|
172
|
-
'iui-disabled': disabled,
|
|
173
|
-
'iui-open': isOpen,
|
|
174
|
-
}) },
|
|
175
|
-
React.createElement(SvgCaretDownSmall, null)),
|
|
206
|
+
React.createElement(SelectEndIcon, { disabled: disabled, isOpen: isOpen }),
|
|
176
207
|
multiple ? (React.createElement(AutoclearingHiddenLiveRegion, { text: liveRegionSelection })) : null),
|
|
177
208
|
popover.open && (React.createElement(Portal, null,
|
|
178
209
|
React.createElement(Menu, { role: 'listbox', className: menuClassName, id: `${uid}-menu`, key: `${uid}-menu`, ...popover.getFloatingProps({
|
|
@@ -184,6 +215,27 @@ export const Select = React.forwardRef((props, forwardedRef) => {
|
|
|
184
215
|
},
|
|
185
216
|
}), ref: popover.refs.setFloating }, menuItems)))));
|
|
186
217
|
});
|
|
218
|
+
// ----------------------------------------------------------------------------
|
|
219
|
+
// Type guards
|
|
220
|
+
const isMultipleEnabled = (variable, multiple) => {
|
|
221
|
+
return multiple;
|
|
222
|
+
};
|
|
223
|
+
// Type guard for multiple did not work
|
|
224
|
+
const isSingleOnChange = (onChange, multiple) => {
|
|
225
|
+
return !multiple;
|
|
226
|
+
};
|
|
227
|
+
// ----------------------------------------------------------------------------
|
|
228
|
+
const SelectButton = React.forwardRef((props, forwardedRef) => {
|
|
229
|
+
const { size, status, styleType = 'default', ...rest } = props;
|
|
230
|
+
return (React.createElement(Box, { "data-iui-size": size, "data-iui-status": status, "data-iui-variant": styleType !== 'default' ? styleType : undefined, ...rest, ref: forwardedRef, className: cx('iui-select-button', props.className) }));
|
|
231
|
+
});
|
|
232
|
+
// ----------------------------------------------------------------------------
|
|
233
|
+
const SelectEndIcon = React.forwardRef((props, forwardedRef) => {
|
|
234
|
+
const { disabled, isOpen, ...rest } = props;
|
|
235
|
+
return (React.createElement(Icon, { "aria-hidden": true, ...rest, ref: forwardedRef, className: cx('iui-end-icon', { 'iui-disabled': disabled, 'iui-open': isOpen }, props.className) },
|
|
236
|
+
React.createElement(SvgCaretDownSmall, null)));
|
|
237
|
+
});
|
|
238
|
+
// ----------------------------------------------------------------------------
|
|
187
239
|
const SingleSelectButton = ({ selectedItem, selectedItemRenderer, }) => {
|
|
188
240
|
const startIcon = selectedItem?.startIcon ?? selectedItem?.icon;
|
|
189
241
|
return (React.createElement(React.Fragment, null,
|
|
@@ -194,6 +246,7 @@ const SingleSelectButton = ({ selectedItem, selectedItemRenderer, }) => {
|
|
|
194
246
|
startIcon && (React.createElement(Box, { as: 'span', className: 'iui-icon', "aria-hidden": true }, startIcon)),
|
|
195
247
|
React.createElement(Box, { as: 'span', className: 'iui-content' }, selectedItem.label)))));
|
|
196
248
|
};
|
|
249
|
+
// ----------------------------------------------------------------------------
|
|
197
250
|
const MultipleSelectButton = ({ selectedItems, selectedItemsRenderer, tagRenderer, }) => {
|
|
198
251
|
const selectedItemsElements = React.useMemo(() => {
|
|
199
252
|
if (!selectedItems) {
|
package/esm/core/Table/Table.js
CHANGED
|
@@ -261,7 +261,8 @@ export const Table = (props) => {
|
|
|
261
261
|
// This is to avoid the old columnOrder from affecting the new columns' columnOrder
|
|
262
262
|
React.useEffect(() => {
|
|
263
263
|
// Check if columns have changed (by value)
|
|
264
|
-
if (
|
|
264
|
+
if (lastPassedColumns.current.length > 0 &&
|
|
265
|
+
JSON.stringify(lastPassedColumns.current) !== JSON.stringify(columns)) {
|
|
265
266
|
instance.setColumnOrder([]);
|
|
266
267
|
}
|
|
267
268
|
lastPassedColumns.current = columns;
|
package/esm/core/Tabs/Tabs.js
CHANGED
|
@@ -42,13 +42,14 @@ const TabList = React.forwardRef((props, ref) => {
|
|
|
42
42
|
}, className), role: 'tablist', ref: refs, ...rest },
|
|
43
43
|
React.createElement(TabListContext.Provider, { value: {
|
|
44
44
|
tabsWidth,
|
|
45
|
+
tablistRef,
|
|
45
46
|
} }, children)));
|
|
46
47
|
});
|
|
47
48
|
TabList.displayName = 'Tabs.TabList';
|
|
48
49
|
const Tab = React.forwardRef((props, forwardedRef) => {
|
|
49
50
|
const { className, children, value, label, ...rest } = props;
|
|
50
51
|
const { orientation, activeValue, setActiveValue, type, setStripeProperties, idPrefix, focusActivationMode, } = useSafeContext(TabsContext);
|
|
51
|
-
const { tabsWidth } = useSafeContext(TabListContext);
|
|
52
|
+
const { tabsWidth, tablistRef } = useSafeContext(TabListContext);
|
|
52
53
|
const tabRef = React.useRef();
|
|
53
54
|
const isActive = activeValue === value;
|
|
54
55
|
const isActiveRef = useLatestRef(isActive);
|
|
@@ -65,13 +66,27 @@ const Tab = React.forwardRef((props, forwardedRef) => {
|
|
|
65
66
|
useLayoutEffect(() => {
|
|
66
67
|
const updateStripe = () => {
|
|
67
68
|
const currentTabRect = tabRef.current?.getBoundingClientRect();
|
|
69
|
+
const tabslistRect = tablistRef.current?.getBoundingClientRect();
|
|
70
|
+
// Using getBoundingClientRect() to get decimal granularity.
|
|
71
|
+
// Not using offsetLeft/offsetTop because they round to the nearest integer.
|
|
72
|
+
// Even minor inaccuracies in the stripe position can cause unexpected scroll/scrollbar.
|
|
73
|
+
// See: https://github.com/iTwin/iTwinUI/issues/1870
|
|
74
|
+
const tabsStripePosition = currentTabRect != null && tabslistRect != null
|
|
75
|
+
? {
|
|
76
|
+
horizontal: currentTabRect.x - tabslistRect.x,
|
|
77
|
+
vertical: currentTabRect.y - tabslistRect.y,
|
|
78
|
+
}
|
|
79
|
+
: {
|
|
80
|
+
horizontal: 0,
|
|
81
|
+
vertical: 0,
|
|
82
|
+
};
|
|
68
83
|
setStripeProperties({
|
|
69
84
|
'--iui-tabs-stripe-size': orientation === 'horizontal'
|
|
70
85
|
? `${currentTabRect?.width}px`
|
|
71
86
|
: `${currentTabRect?.height}px`,
|
|
72
87
|
'--iui-tabs-stripe-position': orientation === 'horizontal'
|
|
73
|
-
? `${
|
|
74
|
-
: `${
|
|
88
|
+
? `${tabsStripePosition.horizontal}px`
|
|
89
|
+
: `${tabsStripePosition.vertical}px`,
|
|
75
90
|
});
|
|
76
91
|
};
|
|
77
92
|
if (type !== 'default' && isActive) {
|
|
@@ -83,6 +98,7 @@ const Tab = React.forwardRef((props, forwardedRef) => {
|
|
|
83
98
|
isActive,
|
|
84
99
|
tabsWidth,
|
|
85
100
|
setStripeProperties,
|
|
101
|
+
tablistRef,
|
|
86
102
|
]);
|
|
87
103
|
const onKeyDown = (event) => {
|
|
88
104
|
if (event.altKey) {
|
package/esm/core/Tile/Tile.d.ts
CHANGED
|
@@ -255,7 +255,7 @@ export declare const Tile: PolymorphicForwardRefComponent<"div", TileLegacyProps
|
|
|
255
255
|
labelProps?: Omit<Omit<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
256
256
|
ref?: ((instance: HTMLDivElement | null) => void) | React.RefObject<HTMLDivElement> | null | undefined;
|
|
257
257
|
}, "as" | "children" | "content" | "portal" | keyof {
|
|
258
|
-
placement?: import("@floating-ui/
|
|
258
|
+
placement?: import("@floating-ui/core").Placement | undefined;
|
|
259
259
|
visible?: boolean | undefined;
|
|
260
260
|
onVisibleChange?: ((visible: boolean) => void) | undefined;
|
|
261
261
|
autoUpdateOptions?: {
|
|
@@ -284,7 +284,7 @@ export declare const Tile: PolymorphicForwardRefComponent<"div", TileLegacyProps
|
|
|
284
284
|
content: React.ReactNode;
|
|
285
285
|
children?: React.ReactNode;
|
|
286
286
|
} & import("../utils/index.js").PortalProps & {
|
|
287
|
-
placement?: import("@floating-ui/
|
|
287
|
+
placement?: import("@floating-ui/core").Placement | undefined;
|
|
288
288
|
visible?: boolean | undefined;
|
|
289
289
|
onVisibleChange?: ((visible: boolean) => void) | undefined;
|
|
290
290
|
autoUpdateOptions?: {
|
|
@@ -17,9 +17,11 @@ type ToggleSwitchProps = {
|
|
|
17
17
|
*/
|
|
18
18
|
size?: 'default';
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* Custom icon inside the toggle switch. Shown only when toggle is checked and size is not small.
|
|
21
|
+
*
|
|
22
|
+
* Will override the default checkmark icon.
|
|
21
23
|
*/
|
|
22
|
-
icon?: JSX.Element;
|
|
24
|
+
icon?: JSX.Element | null;
|
|
23
25
|
} | {
|
|
24
26
|
size: 'small';
|
|
25
27
|
icon?: never;
|