@itwin/itwinui-react 3.0.0-dev.12 → 3.0.0-dev.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/cjs/core/ColorPicker/ColorBuilder.js +2 -0
  3. package/cjs/core/ColorPicker/ColorInputPanel.js +24 -4
  4. package/cjs/core/ColorPicker/ColorPalette.js +2 -80
  5. package/cjs/core/ColorPicker/ColorSwatch.d.ts +1 -1
  6. package/cjs/core/ColorPicker/ColorSwatch.js +25 -15
  7. package/cjs/core/LabeledSelect/LabeledSelect.d.ts +1 -1
  8. package/cjs/core/LabeledSelect/LabeledSelect.js +3 -3
  9. package/cjs/core/Select/Select.d.ts +1 -1
  10. package/cjs/core/Select/Select.js +6 -4
  11. package/cjs/core/Tabs/Tabs.d.ts +222 -52
  12. package/cjs/core/Tabs/Tabs.js +436 -376
  13. package/cjs/core/ThemeProvider/ThemeProvider.js +3 -1
  14. package/cjs/index.d.ts +1 -2
  15. package/cjs/index.js +1 -2
  16. package/cjs/styles.js +4 -2
  17. package/esm/core/ColorPicker/ColorBuilder.js +2 -0
  18. package/esm/core/ColorPicker/ColorInputPanel.js +25 -5
  19. package/esm/core/ColorPicker/ColorPalette.js +3 -83
  20. package/esm/core/ColorPicker/ColorSwatch.d.ts +1 -1
  21. package/esm/core/ColorPicker/ColorSwatch.js +18 -12
  22. package/esm/core/LabeledSelect/LabeledSelect.d.ts +1 -1
  23. package/esm/core/LabeledSelect/LabeledSelect.js +3 -2
  24. package/esm/core/Select/Select.d.ts +1 -1
  25. package/esm/core/Select/Select.js +3 -3
  26. package/esm/core/Tabs/Tabs.d.ts +222 -52
  27. package/esm/core/Tabs/Tabs.js +429 -369
  28. package/esm/core/ThemeProvider/ThemeProvider.js +3 -1
  29. package/esm/index.d.ts +1 -2
  30. package/esm/index.js +1 -2
  31. package/esm/styles.js +4 -2
  32. package/package.json +2 -2
  33. package/styles.css +8 -8
  34. package/cjs/core/Tabs/Tab.d.ts +0 -40
  35. package/cjs/core/Tabs/Tab.js +0 -65
  36. package/esm/core/Tabs/Tab.d.ts +0 -40
  37. package/esm/core/Tabs/Tab.js +0 -57
@@ -55,7 +55,9 @@ exports.ThemeProvider = React.forwardRef((props, forwardedRef) => {
55
55
  const shouldApplyBackground = themeOptions?.applyBackground ?? !parentTheme;
56
56
  const contextValue = React.useMemo(
57
57
  () => ({ theme, themeOptions, portalContainer }),
58
- [theme, themeOptions, portalContainer],
58
+ // we do include all dependencies below, but we want to stringify the objects as they could be different on each render
59
+ // eslint-disable-next-line react-hooks/exhaustive-deps
60
+ [theme, JSON.stringify(themeOptions), portalContainer],
59
61
  );
60
62
  return React.createElement(
61
63
  ThemeContext_js_1.ThemeContext.Provider,
package/cjs/index.d.ts CHANGED
@@ -39,8 +39,7 @@ export { HeaderLogo } from './core/Header/HeaderLogo.js';
39
39
  export { List } from './core/List/List.js';
40
40
  export { ListItem } from './core/List/ListItem.js';
41
41
  export { TransferList } from './core/TransferList/TransferList.js';
42
- export { Tabs } from './core/Tabs/Tabs.js';
43
- export { Tab } from './core/Tabs/Tab.js';
42
+ export { Tabs, Tab } from './core/Tabs/Tabs.js';
44
43
  export { InformationPanel } from './core/InformationPanel/InformationPanel.js';
45
44
  export { InformationPanelWrapper } from './core/InformationPanel/InformationPanelWrapper.js';
46
45
  export { InformationPanelHeader } from './core/InformationPanel/InformationPanelHeader.js';
package/cjs/index.js CHANGED
@@ -420,11 +420,10 @@ Object.defineProperty(exports, 'Tabs', {
420
420
  return Tabs_js_1.Tabs;
421
421
  },
422
422
  });
423
- var Tab_js_1 = require('./core/Tabs/Tab.js');
424
423
  Object.defineProperty(exports, 'Tab', {
425
424
  enumerable: true,
426
425
  get: function () {
427
- return Tab_js_1.Tab;
426
+ return Tabs_js_1.Tab;
428
427
  },
429
428
  });
430
429
  var InformationPanel_js_1 = require('./core/InformationPanel/InformationPanel.js');
package/cjs/styles.js CHANGED
@@ -215,10 +215,10 @@ const styles = {
215
215
  'iui-overlay-exiting': '_iui3-overlay-exiting',
216
216
  closeAnimation,
217
217
  'iui-progress-indicator-radial': '_iui3-progress-indicator-radial',
218
- 'iui-usy2q6d': '_iui3-usy2q6d',
218
+ 'iui-uktpgli': '_iui3-uktpgli',
219
219
  'iui-progress-indicator-linear-label':
220
220
  '_iui3-progress-indicator-linear-label',
221
- 'iui-usy2q6u': '_iui3-usy2q6u',
221
+ 'iui-uktpgmg': '_iui3-uktpgmg',
222
222
  'iui-radio': '_iui3-radio',
223
223
  'iui-radio-tile': '_iui3-radio-tile',
224
224
  'iui-radio-tile-icon': '_iui3-radio-tile-icon',
@@ -326,9 +326,11 @@ const styles = {
326
326
  'iui-tabs-wrapper': '_iui3-tabs-wrapper',
327
327
  'iui-horizontal': '_iui3-horizontal',
328
328
  'iui-tabs': '_iui3-tabs',
329
+ 'scroll-shadow-inset-horizontal': '_iui3-scroll-shadow-inset-horizontal',
329
330
  'iui-borderless': '_iui3-borderless',
330
331
  'iui-tab': '_iui3-tab',
331
332
  'iui-vertical': '_iui3-vertical',
333
+ 'scroll-shadow-inset-vertical': '_iui3-scroll-shadow-inset-vertical',
332
334
  'iui-tabs-content': '_iui3-tabs-content',
333
335
  'iui-tabs-actions-wrapper': '_iui3-tabs-actions-wrapper',
334
336
  'iui-default': '_iui3-default',
@@ -273,6 +273,7 @@ export const ColorBuilder = React.forwardRef((props, ref) => {
273
273
  },
274
274
  min: 0,
275
275
  max: 359,
276
+ thumbProps: () => ({ 'aria-label': 'Hue' }),
276
277
  }),
277
278
  showAlpha &&
278
279
  React.createElement(Slider, {
@@ -294,6 +295,7 @@ export const ColorBuilder = React.forwardRef((props, ref) => {
294
295
  style: {
295
296
  '--iui-color-picker-selected-color': hueColorString,
296
297
  },
298
+ thumbProps: () => ({ 'aria-label': 'Opacity' }),
297
299
  }),
298
300
  );
299
301
  });
@@ -6,7 +6,7 @@ import * as React from 'react';
6
6
  import cx from 'classnames';
7
7
  import { IconButton } from '../Buttons/IconButton.js';
8
8
  import { Input } from '../Input/Input.js';
9
- import { ColorValue, SvgSwap, Box } from '../utils/index.js';
9
+ import { ColorValue, SvgSwap, Box, useId } from '../utils/index.js';
10
10
  import { useColorPickerContext } from './ColorPickerContext.js';
11
11
  /**
12
12
  * `ColorInputPanel` shows input fields to enter precise color values in the specified format.
@@ -140,6 +140,7 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
140
140
  maxLength: showAlpha ? 9 : 7,
141
141
  minLength: 1,
142
142
  placeholder: 'HEX',
143
+ 'aria-label': 'Hex',
143
144
  value: input[0],
144
145
  onChange: (event) => {
145
146
  const value = event.target.value.startsWith('#')
@@ -169,6 +170,7 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
169
170
  max: '359',
170
171
  step: '.1',
171
172
  placeholder: 'H',
173
+ 'aria-label': 'Hue',
172
174
  value: input[0] ?? '',
173
175
  onChange: (event) => {
174
176
  setInput([event.target.value, input[1], input[2], input[3]]);
@@ -195,6 +197,7 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
195
197
  max: '100',
196
198
  step: '.1',
197
199
  placeholder: 'S',
200
+ 'aria-label': 'Saturation',
198
201
  value: input[1] ?? '',
199
202
  onChange: (event) => {
200
203
  setInput([input[0], event.target.value, input[2], input[3]]);
@@ -221,6 +224,7 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
221
224
  max: '100',
222
225
  step: '.1',
223
226
  placeholder: 'L',
227
+ 'aria-label': 'Lightness',
224
228
  value: input[2] ?? '',
225
229
  onChange: (event) => {
226
230
  setInput([input[0], input[1], event.target.value, input[3]]);
@@ -248,6 +252,7 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
248
252
  max: '1',
249
253
  step: '.01',
250
254
  placeholder: 'A',
255
+ 'aria-label': 'Alpha',
251
256
  value: input[3] ?? '',
252
257
  onChange: (event) => {
253
258
  setInput([input[0], input[1], input[2], event.target.value]);
@@ -277,6 +282,7 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
277
282
  min: '0',
278
283
  max: '255',
279
284
  placeholder: 'R',
285
+ 'aria-label': 'Red',
280
286
  value: input[0] ?? '',
281
287
  onChange: (event) => {
282
288
  setInput([event.target.value, input[1], input[2], input[3]]);
@@ -302,6 +308,7 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
302
308
  min: '0',
303
309
  max: '255',
304
310
  placeholder: 'G',
311
+ 'aria-label': 'Green',
305
312
  value: input[1] ?? '',
306
313
  onChange: (event) => {
307
314
  setInput([input[0], event.target.value, input[2], input[3]]);
@@ -327,6 +334,7 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
327
334
  min: '0',
328
335
  max: '255',
329
336
  placeholder: 'B',
337
+ 'aria-label': 'Blue',
330
338
  value: input[2] ?? '',
331
339
  onChange: (event) => {
332
340
  setInput([input[0], input[1], event.target.value, input[3]]);
@@ -354,6 +362,7 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
354
362
  max: '1',
355
363
  step: '.01',
356
364
  placeholder: 'A',
365
+ 'aria-label': 'Alpha',
357
366
  value: input[3] ?? '',
358
367
  onChange: (event) => {
359
368
  setInput([input[0], input[1], input[2], event.target.value]);
@@ -374,13 +383,14 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
374
383
  Number(input[3]) < 0 || Number(input[3]) > 1 ? 'negative' : undefined,
375
384
  }),
376
385
  );
386
+ const labelId = useId();
377
387
  return React.createElement(
378
388
  Box,
379
389
  { className: cx('iui-color-input-wrapper', className), ref: ref, ...rest },
380
390
  React.createElement(
381
391
  Box,
382
- { className: 'iui-color-picker-section-label' },
383
- showAlpha && currentFormat != 'hex'
392
+ { className: 'iui-color-picker-section-label', id: labelId },
393
+ showAlpha && currentFormat !== 'hex'
384
394
  ? currentFormat.toUpperCase() + 'A'
385
395
  : currentFormat.toUpperCase(),
386
396
  ),
@@ -390,12 +400,22 @@ export const ColorInputPanel = React.forwardRef((props, ref) => {
390
400
  allowedColorFormats.length > 1 &&
391
401
  React.createElement(
392
402
  IconButton,
393
- { styleType: 'borderless', onClick: swapColorFormat, size: 'small' },
403
+ {
404
+ styleType: 'borderless',
405
+ onClick: swapColorFormat,
406
+ size: 'small',
407
+ label: 'Switch format',
408
+ },
394
409
  React.createElement(SvgSwap, null),
395
410
  ),
396
411
  React.createElement(
397
412
  Box,
398
- { ref: inputsContainerRef, className: 'iui-color-input-fields' },
413
+ {
414
+ ref: inputsContainerRef,
415
+ className: 'iui-color-input-fields',
416
+ role: currentFormat !== 'hex' ? 'group' : undefined,
417
+ 'aria-labelledby': currentFormat !== 'hex' ? labelId : undefined,
418
+ },
399
419
  currentFormat === 'hex' && hexInputField,
400
420
  currentFormat === 'rgb' && rgbInputs,
401
421
  currentFormat === 'hsl' && hslInputs,
@@ -4,12 +4,7 @@
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import * as React from 'react';
6
6
  import cx from 'classnames';
7
- import {
8
- ColorValue,
9
- getFocusableElements,
10
- useMergedRefs,
11
- Box,
12
- } from '../utils/index.js';
7
+ import { ColorValue, Box } from '../utils/index.js';
13
8
  import { getColorValue } from './ColorPicker.js';
14
9
  import { ColorSwatch } from './ColorSwatch.js';
15
10
  import { useColorPickerContext } from './ColorPickerContext.js';
@@ -28,76 +23,6 @@ export const ColorPalette = React.forwardRef((props, ref) => {
28
23
  const { colors, label, className, children, ...rest } = props;
29
24
  const { activeColor, setActiveColor, onChangeComplete } =
30
25
  useColorPickerContext();
31
- const [focusedIndex, setFocusedIndex] = React.useState();
32
- // callback ref to set tabindex=0 on first child if none of the swatches are tabbable
33
- const setDefaultTabIndex = (el) => {
34
- if (el && !el.querySelector('[tabindex="0"]')) {
35
- el.firstElementChild?.setAttribute('tabindex', '0');
36
- }
37
- };
38
- const paletteRef = React.useRef(null);
39
- const paletteRefs = useMergedRefs(paletteRef, setDefaultTabIndex);
40
- // Color palette arrow key navigation
41
- const handleKeyDown = (event) => {
42
- if (event.altKey) {
43
- return;
44
- }
45
- const swatches = getFocusableElements(paletteRef.current);
46
- if (!swatches.length) {
47
- return;
48
- }
49
- const currentIndex = swatches.findIndex(
50
- (swatch) => swatch === paletteRef.current?.ownerDocument.activeElement,
51
- );
52
- if (currentIndex < 0) {
53
- return;
54
- }
55
- let newIndex = -1;
56
- switch (event.key) {
57
- case 'ArrowDown': {
58
- // Look for next ColorSwatch with same offsetLeft value
59
- newIndex = swatches.findIndex(
60
- (swatch, index) =>
61
- index > currentIndex &&
62
- swatch.offsetLeft === swatches[currentIndex].offsetLeft,
63
- );
64
- break;
65
- }
66
- case 'ArrowUp': {
67
- // Look backwards for next ColorSwatch with same offsetLeft value
68
- for (let i = currentIndex - 1; i >= 0; i--) {
69
- if (swatches[i].offsetLeft === swatches[currentIndex].offsetLeft) {
70
- newIndex = i;
71
- break;
72
- }
73
- }
74
- break;
75
- }
76
- case 'ArrowLeft':
77
- newIndex = Math.max(currentIndex - 1, 0);
78
- break;
79
- case 'ArrowRight':
80
- newIndex = Math.min(currentIndex + 1, swatches.length - 1);
81
- break;
82
- case 'Enter':
83
- case ' ':
84
- case 'Spacebar':
85
- swatches[currentIndex].click();
86
- event.preventDefault();
87
- return;
88
- }
89
- if (newIndex >= 0 && newIndex < swatches.length) {
90
- setFocusedIndex(newIndex);
91
- event.preventDefault();
92
- }
93
- };
94
- // call focus() when focusedIndex changes
95
- React.useEffect(() => {
96
- if (focusedIndex != null) {
97
- const swatches = getFocusableElements(paletteRef.current);
98
- swatches[focusedIndex]?.focus();
99
- }
100
- }, [focusedIndex]);
101
26
  return React.createElement(
102
27
  Box,
103
28
  {
@@ -113,11 +38,7 @@ export const ColorPalette = React.forwardRef((props, ref) => {
113
38
  ),
114
39
  React.createElement(
115
40
  Box,
116
- {
117
- className: 'iui-color-palette',
118
- onKeyDown: handleKeyDown,
119
- ref: paletteRefs,
120
- },
41
+ { className: 'iui-color-palette' },
121
42
  children,
122
43
  colors &&
123
44
  colors.map((_color, index) => {
@@ -125,8 +46,7 @@ export const ColorPalette = React.forwardRef((props, ref) => {
125
46
  return React.createElement(ColorSwatch, {
126
47
  key: index,
127
48
  color: color,
128
- onClick: (event) => {
129
- event.preventDefault();
49
+ onClick: () => {
130
50
  onChangeComplete?.(color);
131
51
  setActiveColor(color);
132
52
  },
@@ -16,5 +16,5 @@ type ColorSwatchProps = {
16
16
  * <ColorSwatch color='#23450b' onClick={onClick}/>
17
17
  * <ColorSwatch color={{ r: 255, g: 255, b: 0 }} onClick={onClick}/>
18
18
  */
19
- export declare const ColorSwatch: PolymorphicForwardRefComponent<"div", ColorSwatchProps>;
19
+ export declare const ColorSwatch: PolymorphicForwardRefComponent<"button", ColorSwatchProps>;
20
20
  export default ColorSwatch;
@@ -4,8 +4,9 @@
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import * as React from 'react';
6
6
  import cx from 'classnames';
7
- import { ColorValue, Box } from '../utils/index.js';
7
+ import { ColorValue, Box, ButtonBase } from '../utils/index.js';
8
8
  import { getColorValue } from './ColorPicker.js';
9
+ import { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden.js';
9
10
  /**
10
11
  * ColorSwatch component to display within a color palette.
11
12
  * @example
@@ -21,17 +22,22 @@ export const ColorSwatch = React.forwardRef((props, ref) => {
21
22
  : getColorValue(color).toHslString(true),
22
23
  [color],
23
24
  );
24
- return React.createElement(Box, {
25
- className: cx('iui-color-swatch', { 'iui-active': isActive }, className),
26
- style: {
27
- '--iui-color-swatch-background': colorString,
28
- ...style,
25
+ return React.createElement(
26
+ Box,
27
+ {
28
+ as: !!onClick ? ButtonBase : 'span',
29
+ className: cx('iui-color-swatch', { 'iui-active': isActive }, className),
30
+ style: {
31
+ '--iui-color-swatch-background': colorString,
32
+ ...style,
33
+ },
34
+ onClick: onClick,
35
+ 'aria-pressed': !!onClick && isActive ? 'true' : undefined,
36
+ ref: ref,
37
+ ...rest,
29
38
  },
30
- onClick: onClick,
31
- tabIndex: isActive ? 0 : -1,
32
- 'aria-selected': isActive,
33
- ref: ref,
34
- ...rest,
35
- });
39
+ props.children ??
40
+ React.createElement(VisuallyHidden, null, colorString.toUpperCase()),
41
+ );
36
42
  });
37
43
  export default ColorSwatch;
@@ -76,5 +76,5 @@ export type LabeledSelectProps<T> = {
76
76
  * svgIcon={<SvgCamera />}
77
77
  * />
78
78
  */
79
- export declare const LabeledSelect: <T>(props: LabeledSelectProps<T>) => JSX.Element;
79
+ export declare const LabeledSelect: React.ForwardRefExoticComponent<LabeledSelectProps<unknown> & React.RefAttributes<HTMLElement>>;
80
80
  export default LabeledSelect;
@@ -42,7 +42,7 @@ import { Icon } from '../Icon/Icon.js';
42
42
  * svgIcon={<SvgCamera />}
43
43
  * />
44
44
  */
45
- export const LabeledSelect = (props) => {
45
+ export const LabeledSelect = React.forwardRef((props, forwardedRef) => {
46
46
  const {
47
47
  className,
48
48
  disabled = false,
@@ -91,6 +91,7 @@ export const LabeledSelect = (props) => {
91
91
  style: style,
92
92
  status: status,
93
93
  ...rest,
94
+ ref: forwardedRef,
94
95
  triggerProps: {
95
96
  'aria-labelledby': labelId,
96
97
  ...triggerProps,
@@ -109,5 +110,5 @@ export const LabeledSelect = (props) => {
109
110
  )
110
111
  : message,
111
112
  );
112
- };
113
+ });
113
114
  export default LabeledSelect;
@@ -168,5 +168,5 @@ export type SelectProps<T> = {
168
168
  * )}
169
169
  * />
170
170
  */
171
- export declare const Select: <T>(props: SelectProps<T>) => JSX.Element;
171
+ export declare const Select: React.ForwardRefExoticComponent<SelectProps<unknown> & React.RefAttributes<HTMLElement>>;
172
172
  export default Select;
@@ -75,7 +75,7 @@ const isSingleOnChange = (onChange, multiple) => {
75
75
  * )}
76
76
  * />
77
77
  */
78
- export const Select = (props) => {
78
+ export const Select = React.forwardRef((props, forwardedRef) => {
79
79
  const uid = useId();
80
80
  const {
81
81
  options,
@@ -194,7 +194,7 @@ export const Select = (props) => {
194
194
  className: cx('iui-input-with-icon', className),
195
195
  style: style,
196
196
  ...rest,
197
- ref: popover.refs.setPositionReference,
197
+ ref: useMergedRefs(popover.refs.setPositionReference, forwardedRef),
198
198
  },
199
199
  React.createElement(
200
200
  Box,
@@ -281,7 +281,7 @@ export const Select = (props) => {
281
281
  ),
282
282
  ),
283
283
  );
284
- };
284
+ });
285
285
  const SingleSelectButton = ({ selectedItem, selectedItemRenderer }) => {
286
286
  const startIcon = selectedItem?.startIcon ?? selectedItem?.icon;
287
287
  return React.createElement(