@itwin/itwinui-react 3.3.3 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/cjs/core/Carousel/CarouselSlider.js +1 -1
  3. package/cjs/core/ComboBox/ComboBox.js +1 -1
  4. package/cjs/core/DatePicker/DatePicker.d.ts +8 -0
  5. package/cjs/core/DatePicker/DatePicker.js +9 -4
  6. package/cjs/core/Dialog/DialogMain.js +5 -4
  7. package/cjs/core/FileUpload/FileUploadTemplate.d.ts +2 -1
  8. package/cjs/core/FileUpload/FileUploadTemplate.js +2 -1
  9. package/cjs/core/LinkAction/LinkAction.d.ts +3 -2
  10. package/cjs/core/LinkAction/LinkAction.js +33 -1
  11. package/cjs/core/Modal/Modal.d.ts +12 -0
  12. package/cjs/core/Modal/Modal.js +4 -4
  13. package/cjs/core/Popover/Popover.js +1 -1
  14. package/cjs/core/ProgressIndicators/ProgressLinear.d.ts +15 -7
  15. package/cjs/core/ProgressIndicators/ProgressLinear.js +14 -6
  16. package/cjs/core/ProgressIndicators/ProgressRadial.d.ts +3 -2
  17. package/cjs/core/ProgressIndicators/ProgressRadial.js +3 -1
  18. package/cjs/core/Table/Table.js +23 -10
  19. package/cjs/core/Tabs/Tabs.js +17 -16
  20. package/cjs/core/Tag/Tag.d.ts +29 -7
  21. package/cjs/core/Tag/Tag.js +12 -5
  22. package/cjs/core/ThemeProvider/ThemeProvider.js +2 -2
  23. package/cjs/core/utils/components/VirtualScroll.js +7 -7
  24. package/cjs/core/utils/hooks/useIsomorphicLayoutEffect.d.ts +4 -1
  25. package/cjs/core/utils/hooks/useIsomorphicLayoutEffect.js +5 -2
  26. package/cjs/core/utils/hooks/useMediaQuery.js +1 -1
  27. package/cjs/core/utils/hooks/useOverflow.js +3 -3
  28. package/esm/core/Carousel/CarouselSlider.js +2 -2
  29. package/esm/core/ComboBox/ComboBox.js +2 -2
  30. package/esm/core/DatePicker/DatePicker.d.ts +8 -0
  31. package/esm/core/DatePicker/DatePicker.js +9 -4
  32. package/esm/core/Dialog/DialogMain.js +6 -5
  33. package/esm/core/FileUpload/FileUploadTemplate.d.ts +2 -1
  34. package/esm/core/FileUpload/FileUploadTemplate.js +2 -1
  35. package/esm/core/LinkAction/LinkAction.d.ts +3 -2
  36. package/esm/core/LinkAction/LinkAction.js +7 -1
  37. package/esm/core/Modal/Modal.d.ts +12 -0
  38. package/esm/core/Modal/Modal.js +4 -4
  39. package/esm/core/Popover/Popover.js +2 -2
  40. package/esm/core/ProgressIndicators/ProgressLinear.d.ts +15 -7
  41. package/esm/core/ProgressIndicators/ProgressLinear.js +14 -6
  42. package/esm/core/ProgressIndicators/ProgressRadial.d.ts +3 -2
  43. package/esm/core/ProgressIndicators/ProgressRadial.js +3 -1
  44. package/esm/core/Table/Table.js +24 -11
  45. package/esm/core/Tabs/Tabs.js +18 -17
  46. package/esm/core/Tag/Tag.d.ts +29 -7
  47. package/esm/core/Tag/Tag.js +13 -6
  48. package/esm/core/ThemeProvider/ThemeProvider.js +3 -3
  49. package/esm/core/utils/components/VirtualScroll.js +8 -8
  50. package/esm/core/utils/hooks/useIsomorphicLayoutEffect.d.ts +4 -1
  51. package/esm/core/utils/hooks/useIsomorphicLayoutEffect.js +4 -1
  52. package/esm/core/utils/hooks/useMediaQuery.js +2 -2
  53. package/esm/core/utils/hooks/useOverflow.js +4 -4
  54. package/package.json +2 -2
  55. package/styles.css +9 -9
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1824](https://github.com/iTwin/iTwinUI/pull/1824): `LinkAction` will now automatically render a `<button>` by default if no `href` is passed.
8
+ - [#1815](https://github.com/iTwin/iTwinUI/pull/1815): Removed unnecessary `Tag` styles, and added support for tags to be used as `<button>` elements.
9
+ - [#1813](https://github.com/iTwin/iTwinUI/pull/1813): Added warning status for `ProgressRadial`/`ProgressLinear`
10
+ - [#1815](https://github.com/iTwin/iTwinUI/pull/1815): Added `labelProps` and `removeButtonProps` to `Tag` to allow customizing internal parts.
11
+ - [#1821](https://github.com/iTwin/iTwinUI/pull/1821): Added new props to `Modal` to allow customizing inner DOM elements: `wrapperProps`, `backdropProps`, `titleBarProps`.
12
+ - [#1822](https://github.com/iTwin/iTwinUI/pull/1822): Added new `showDatesOutsideMonth` prop to `DatePicker`. Currently defaults to `true` but is recommended to be set to `false`.
13
+
14
+ ## 3.3.4
15
+
16
+ ### Patch Changes
17
+
18
+ - [#1816](https://github.com/iTwin/iTwinUI/pull/1816): Fixed an issue where `Table` was showing a dummy vertical scrollbar track inside the table header in Chromium 121 + Windows.
19
+ - [#1810](https://github.com/iTwin/iTwinUI/pull/1810): Fixed `Surface.Body` not being visually aligned with `Surface.Header` depending on scrollbar visibility.
20
+ - [#1776](https://github.com/iTwin/iTwinUI/pull/1776): Fixed broken animation in full-page `Modal` and `Dialog`.
21
+ - [#1809](https://github.com/iTwin/iTwinUI/pull/1809): Fixed `Table` bug where the table-body had an incorrect horizontal scrollbar/overflow when the `Table`'s width is reduced below the initial width.
22
+
3
23
  ## 3.3.3
4
24
 
5
25
  ### Patch Changes
@@ -52,7 +52,7 @@ exports.CarouselSlider = React.forwardRef((props, ref) => {
52
52
  index,
53
53
  })
54
54
  : child) ?? [], [children, idPrefix]);
55
- (0, index_js_1.useIsomorphicLayoutEffect)(() => {
55
+ (0, index_js_1.useLayoutEffect)(() => {
56
56
  setSlideCount(items.length);
57
57
  }, [items.length, setSlideCount]);
58
58
  const sliderRef = React.useRef(null);
@@ -120,7 +120,7 @@ exports.ComboBox = React.forwardRef((props, forwardedRef) => {
120
120
  dispatch({ type: 'close' });
121
121
  onHideRef.current?.();
122
122
  }, [onHideRef]);
123
- (0, index_js_1.useIsomorphicLayoutEffect)(() => {
123
+ (0, index_js_1.useLayoutEffect)(() => {
124
124
  // When the dropdown opens
125
125
  if (isOpen) {
126
126
  inputRef.current?.focus(); // Focus the input
@@ -96,6 +96,14 @@ type DatePickerProps = {
96
96
  * @default true
97
97
  */
98
98
  applyBackground?: boolean;
99
+ /**
100
+ * Whether dates outside the current month should be displayed (in a muted text style).
101
+ *
102
+ * It is recommended to set this to false. Currently it defaults to true for backward compatibility.
103
+ *
104
+ * @default true
105
+ */
106
+ showDatesOutsideMonth?: boolean;
99
107
  } & DateRangePickerProps & Omit<TimePickerProps, 'date' | 'onChange' | 'setFocusHour'>;
100
108
  /**
101
109
  * Date picker component
@@ -140,7 +140,7 @@ exports.generateLocalizedStrings = generateLocalizedStrings;
140
140
  * <DatePicker date={new Date()} onChange={(e) => console.log('New date value: ' + e)} />
141
141
  */
142
142
  exports.DatePicker = React.forwardRef((props, forwardedRef) => {
143
- const { date, onChange, localizedNames, className, setFocus = false, showTime = false, use12Hours = false, precision, hourStep, minuteStep, secondStep, useCombinedRenderer, combinedRenderer, hourRenderer, minuteRenderer, secondRenderer, meridiemRenderer, showYearSelection = false, enableRangeSelect = false, startDate, endDate, monthYearProps, calendarProps, monthProps, weekDayProps, dayProps, weekProps, isDateDisabled, applyBackground = true, ...rest } = props;
143
+ const { date, onChange, localizedNames, className, setFocus = false, showTime = false, use12Hours = false, precision, hourStep, minuteStep, secondStep, useCombinedRenderer, combinedRenderer, hourRenderer, minuteRenderer, secondRenderer, meridiemRenderer, showYearSelection = false, enableRangeSelect = false, startDate, endDate, monthYearProps, calendarProps, monthProps, weekDayProps, dayProps, weekProps, isDateDisabled, applyBackground = true, showDatesOutsideMonth = true, ...rest } = props;
144
144
  const monthNames = localizedNames?.months ?? defaultMonths;
145
145
  const shortDays = localizedNames?.shortDays ?? defaultShortDays;
146
146
  const longDays = localizedNames?.days ?? defaultLongDays;
@@ -182,8 +182,9 @@ exports.DatePicker = React.forwardRef((props, forwardedRef) => {
182
182
  }, [date, setMonthAndYear, startDate, endDate, enableRangeSelect]);
183
183
  const days = React.useMemo(() => {
184
184
  let offsetToFirst = new Date(displayedYear, displayedMonthIndex, 1).getDay();
185
- // if its sunday, show one week before
186
- if (0 === offsetToFirst) {
185
+ // If it's sunday, show one week before, but only if dates outside month are shown.
186
+ // (We do not want empty space at the top if dates outside month are not shown.)
187
+ if (0 === offsetToFirst && showDatesOutsideMonth) {
187
188
  offsetToFirst = 7;
188
189
  }
189
190
  const daysInMonth = [];
@@ -193,7 +194,7 @@ exports.DatePicker = React.forwardRef((props, forwardedRef) => {
193
194
  daysInMonth.push(new Date(displayedYear, displayedMonthIndex, adjustedDay));
194
195
  }
195
196
  return daysInMonth;
196
- }, [displayedMonthIndex, displayedYear]);
197
+ }, [displayedMonthIndex, displayedYear, showDatesOutsideMonth]);
197
198
  const weeks = React.useMemo(() => {
198
199
  const weeksInMonth = [];
199
200
  const weekCount = Math.ceil(days.length / 7);
@@ -383,6 +384,10 @@ exports.DatePicker = React.forwardRef((props, forwardedRef) => {
383
384
  return (React.createElement(index_js_1.Box, { as: 'div', key: `week-${displayedMonthIndex}-${weekIndex}`, ...weekProps, className: (0, classnames_1.default)('iui-calendar-week', weekProps?.className) }, weekDays.map((weekDay, dayIndex) => {
384
385
  const dateValue = weekDay.getDate();
385
386
  const isDisabled = isDateDisabled?.(weekDay);
387
+ const isOutsideMonth = weekDay.getMonth() !== displayedMonthIndex;
388
+ if (isOutsideMonth && !showDatesOutsideMonth) {
389
+ return (React.createElement(index_js_1.Box, { key: `day-${displayedMonthIndex}-${dayIndex}`, className: (0, classnames_1.default)(getDayClass(weekDay), dayProps?.className), "aria-hidden": true }));
390
+ }
386
391
  return (React.createElement(index_js_1.Box, { as: 'div', key: `day-${displayedMonthIndex}-${dayIndex}`, onClick: () => !isDisabled && onDayClick(weekDay), role: 'option', tabIndex: isSameDay(weekDay, focusedDay) ? 0 : -1, "aria-disabled": isDisabled ? 'true' : undefined, ref: (element) => isSameDay(weekDay, focusedDay) &&
387
392
  needFocus.current &&
388
393
  element?.focus(), ...dayProps, className: (0, classnames_1.default)(getDayClass(weekDay), dayProps?.className) }, dateValue));
@@ -38,6 +38,7 @@ const DialogContext_js_1 = require("./DialogContext.js");
38
38
  const react_transition_group_1 = require("react-transition-group");
39
39
  const DialogDragContext_js_1 = require("./DialogDragContext.js");
40
40
  const useDragAndDrop_js_1 = __importDefault(require("../utils/hooks/useDragAndDrop.js"));
41
+ const styles_js_1 = __importDefault(require("../../styles.js"));
41
42
  /**
42
43
  * Dialog component which can wrap any content.
43
44
  * @example
@@ -109,7 +110,7 @@ exports.DialogMain = React.forwardRef((props, ref) => {
109
110
  }
110
111
  }, [isDraggable, onPointerDown]);
111
112
  // Prevents dialog from moving when window is being resized
112
- (0, index_js_1.useIsomorphicLayoutEffect)(() => {
113
+ (0, index_js_1.useLayoutEffect)(() => {
113
114
  if (!isDraggable || !isOpen) {
114
115
  return;
115
116
  }
@@ -133,7 +134,6 @@ exports.DialogMain = React.forwardRef((props, ref) => {
133
134
  const content = (React.createElement(index_js_1.Box, { className: (0, classnames_1.default)('iui-dialog', {
134
135
  'iui-dialog-default': styleType === 'default',
135
136
  'iui-dialog-full-page': styleType === 'fullPage',
136
- 'iui-dialog-visible': isOpen,
137
137
  'iui-dialog-draggable': isDraggable,
138
138
  }, className), role: 'dialog', ref: (0, index_js_1.useMergedRefs)(dialogRef, ref), onKeyDown: handleKeyDown, tabIndex: -1, "data-iui-placement": placement, style: {
139
139
  transform,
@@ -148,8 +148,9 @@ exports.DialogMain = React.forwardRef((props, ref) => {
148
148
  }, onResizeEnd: setResizeStyle })),
149
149
  children));
150
150
  return (React.createElement(react_transition_group_1.CSSTransition, { in: isOpen, classNames: {
151
- enter: 'iui-dialog-animation-enter',
152
- enterActive: 'iui-dialog-animation-enter-active',
151
+ enter: styles_js_1.default['iui-dialog-animation-enter'],
152
+ enterActive: styles_js_1.default['iui-dialog-animation-enter-active'],
153
+ enterDone: styles_js_1.default['iui-dialog-visible'],
153
154
  }, timeout: { exit: 600 },
154
155
  // Focuses dialog when opened
155
156
  onEntered: () => {
@@ -32,7 +32,8 @@ type FileUploadTemplateProps = {
32
32
  children?: React.ReactNode;
33
33
  };
34
34
  /**
35
- * @deprecated Use `FileUploadCard` instead.
35
+ * @deprecated Use [`FileUploadCard`](https://itwinui.bentley.com/docs/fileupload#fileuploadcard) instead.
36
+ *
36
37
  * Default template to be used with the `FileUpload` wrapper component.
37
38
  * Contains a hidden input with styled labels (customizable).
38
39
  * @example
@@ -36,7 +36,8 @@ const classnames_1 = __importDefault(require("classnames"));
36
36
  const index_js_1 = require("../utils/index.js");
37
37
  const Anchor_js_1 = require("../Typography/Anchor.js");
38
38
  /**
39
- * @deprecated Use `FileUploadCard` instead.
39
+ * @deprecated Use [`FileUploadCard`](https://itwinui.bentley.com/docs/fileupload#fileuploadcard) instead.
40
+ *
40
41
  * Default template to be used with the `FileUpload` wrapper component.
41
42
  * Contains a hidden input with styled labels (customizable).
42
43
  * @example
@@ -1,3 +1,4 @@
1
+ import type { PolymorphicForwardRefComponent } from '../utils/props.js';
1
2
  /**
2
3
  * Polymorphic link action component.
3
4
  * It is rendered as `a` by default.
@@ -8,7 +9,7 @@
8
9
  * </Surface>
9
10
  * </LinkBox>
10
11
  */
11
- export declare const LinkAction: import("../utils/props.js").PolymorphicForwardRefComponent<"a", {}>;
12
+ export declare const LinkAction: PolymorphicForwardRefComponent<"a", {}>;
12
13
  /**
13
14
  * Polymorphic link box component.
14
15
  * Used to wrap around your component to use LinkAction.
@@ -20,4 +21,4 @@ export declare const LinkAction: import("../utils/props.js").PolymorphicForwardR
20
21
  * </Surface>
21
22
  * </LinkBox>
22
23
  */
23
- export declare const LinkBox: import("../utils/props.js").PolymorphicForwardRefComponent<"div", {}>;
24
+ export declare const LinkBox: PolymorphicForwardRefComponent<"div", {}>;
@@ -1,11 +1,40 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
2
28
  Object.defineProperty(exports, "__esModule", { value: true });
3
29
  exports.LinkBox = exports.LinkAction = void 0;
4
30
  /*---------------------------------------------------------------------------------------------
5
31
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
6
32
  * See LICENSE.md in the project root for license terms and full copyright notice.
7
33
  *--------------------------------------------------------------------------------------------*/
34
+ const React = __importStar(require("react"));
35
+ const classnames_1 = __importDefault(require("classnames"));
8
36
  const polymorphic_js_1 = require("../utils/functions/polymorphic.js");
37
+ const index_js_1 = require("../utils/components/index.js");
9
38
  /**
10
39
  * Polymorphic link action component.
11
40
  * It is rendered as `a` by default.
@@ -16,7 +45,10 @@ const polymorphic_js_1 = require("../utils/functions/polymorphic.js");
16
45
  * </Surface>
17
46
  * </LinkBox>
18
47
  */
19
- exports.LinkAction = polymorphic_js_1.polymorphic.a('iui-link-action');
48
+ exports.LinkAction = React.forwardRef((props, forwardedRef) => {
49
+ const { as: asProp = (!!props.href ? 'a' : 'button') } = props;
50
+ return (React.createElement(index_js_1.Box, { ...props, as: asProp, className: (0, classnames_1.default)('iui-link-action', props.className), ref: forwardedRef }));
51
+ });
20
52
  exports.LinkAction.displayName = 'LinkAction';
21
53
  /**
22
54
  * Polymorphic link box component.
@@ -42,6 +42,18 @@ type ModalProps = {
42
42
  * Content of the modal.
43
43
  */
44
44
  children: React.ReactNode;
45
+ /**
46
+ * Props for customizing the title bar element.
47
+ */
48
+ titleBarProps?: React.ComponentPropsWithRef<'div'>;
49
+ /**
50
+ * Props for customizing the dialog-wrapper element.
51
+ */
52
+ wrapperProps?: React.ComponentPropsWithoutRef<'div'>;
53
+ /**
54
+ * Props for customizing the backdrop element.
55
+ */
56
+ backdropProps?: React.ComponentPropsWithRef<'div'>;
45
57
  } & Pick<DialogMainProps, 'isOpen' | 'styleType'>;
46
58
  /**
47
59
  * Modal component which can wrap any content.
@@ -52,11 +52,11 @@ const Dialog_js_1 = require("../Dialog/Dialog.js");
52
52
  * </Modal>
53
53
  */
54
54
  exports.Modal = React.forwardRef((props, forwardedRef) => {
55
- const { isOpen = false, isDismissible = true, closeOnEsc = true, closeOnExternalClick = true, onClose, title, children, portal = true, ...rest } = props;
56
- return (React.createElement(Dialog_js_1.Dialog, { isOpen: isOpen, closeOnEsc: closeOnEsc, closeOnExternalClick: closeOnExternalClick, isDismissible: isDismissible, onClose: onClose, preventDocumentScroll: true, trapFocus: true, setFocus: true, ref: forwardedRef, portal: portal },
57
- React.createElement(Dialog_js_1.Dialog.Backdrop, null),
55
+ const { isOpen = false, isDismissible = true, closeOnEsc = true, closeOnExternalClick = true, onClose, title, children, portal = true, wrapperProps, backdropProps, titleBarProps, ...rest } = props;
56
+ return (React.createElement(Dialog_js_1.Dialog, { isOpen: isOpen, closeOnEsc: closeOnEsc, closeOnExternalClick: closeOnExternalClick, isDismissible: isDismissible, onClose: onClose, preventDocumentScroll: true, trapFocus: true, setFocus: true, ref: forwardedRef, portal: portal, ...wrapperProps },
57
+ React.createElement(Dialog_js_1.Dialog.Backdrop, { ...backdropProps }),
58
58
  React.createElement(Dialog_js_1.Dialog.Main, { "aria-modal": true, ...rest },
59
- React.createElement(Dialog_js_1.Dialog.TitleBar, { titleText: title }),
59
+ React.createElement(Dialog_js_1.Dialog.TitleBar, { titleText: title, ...titleBarProps }),
60
60
  children)));
61
61
  });
62
62
  exports.default = exports.Modal;
@@ -131,7 +131,7 @@ exports.Popover = React.forwardRef((props, forwardedRef) => {
131
131
  const popoverRef = (0, index_js_1.useMergedRefs)(popover.refs.setFloating, forwardedRef, setPopoverElement);
132
132
  const triggerId = `${(0, index_js_1.useId)()}-trigger`;
133
133
  const hasAriaLabel = !!props['aria-labelledby'] || !!props['aria-label'];
134
- (0, index_js_1.useIsomorphicLayoutEffect)(() => {
134
+ (0, index_js_1.useLayoutEffect)(() => {
135
135
  if (!positionReference) {
136
136
  return;
137
137
  }
@@ -23,7 +23,7 @@ type ProgressLinearProps = {
23
23
  /**
24
24
  * Status of progress.
25
25
  */
26
- status?: 'positive' | 'negative';
26
+ status?: 'positive' | 'negative' | 'warning';
27
27
  /**
28
28
  * Pass props to ProgressLinear label group.
29
29
  */
@@ -32,16 +32,24 @@ type ProgressLinearProps = {
32
32
  /**
33
33
  * Shows progress on a linear bar
34
34
  * @example
35
- * Determinate
35
+ * // Determinate
36
36
  * <ProgressLinear value={25}/>
37
- * Indeterminate
37
+ * // Indeterminate
38
38
  * <ProgressLinear indeterminate={true}/>
39
- * Labeled - Center
39
+ * // Labeled - Center
40
40
  * <ProgressLinear value={50} labels={['Centered Label']} />
41
- * Labeled - Left & Right
41
+ * // Labeled - Left & Right
42
42
  * <ProgressLinear value={50} labels={['Loading...', '50%']} />
43
- * Positive / Negative.
44
- * <ProgressLinear status='positive' labels={['Upload done!', <SvgStatusSuccessHollow />]} />
43
+ * // Status
44
+ * <ProgressLinear
45
+ * status='positive'
46
+ * labels={[
47
+ * 'Upload done!',
48
+ * <Icon key='icon'>
49
+ * <SvgStatusSuccess />{' '}
50
+ * </Icon>
51
+ * ]}
52
+ * />
45
53
  * <ProgressLinear status='negative' />
46
54
  */
47
55
  export declare const ProgressLinear: PolymorphicForwardRefComponent<"div", ProgressLinearProps>;
@@ -37,16 +37,24 @@ const index_js_1 = require("../utils/index.js");
37
37
  /**
38
38
  * Shows progress on a linear bar
39
39
  * @example
40
- * Determinate
40
+ * // Determinate
41
41
  * <ProgressLinear value={25}/>
42
- * Indeterminate
42
+ * // Indeterminate
43
43
  * <ProgressLinear indeterminate={true}/>
44
- * Labeled - Center
44
+ * // Labeled - Center
45
45
  * <ProgressLinear value={50} labels={['Centered Label']} />
46
- * Labeled - Left & Right
46
+ * // Labeled - Left & Right
47
47
  * <ProgressLinear value={50} labels={['Loading...', '50%']} />
48
- * Positive / Negative.
49
- * <ProgressLinear status='positive' labels={['Upload done!', <SvgStatusSuccessHollow />]} />
48
+ * // Status
49
+ * <ProgressLinear
50
+ * status='positive'
51
+ * labels={[
52
+ * 'Upload done!',
53
+ * <Icon key='icon'>
54
+ * <SvgStatusSuccess />{' '}
55
+ * </Icon>
56
+ * ]}
57
+ * />
50
58
  * <ProgressLinear status='negative' />
51
59
  */
52
60
  exports.ProgressLinear = React.forwardRef((props, forwardedRef) => {
@@ -14,7 +14,7 @@ type ProgressRadialProps = {
14
14
  /**
15
15
  * Status of Progress. Positive status always has 100% value.
16
16
  */
17
- status?: 'positive' | 'negative';
17
+ status?: 'positive' | 'negative' | 'warning';
18
18
  /**
19
19
  * Size of the progress indicator. Defaults to medium size.
20
20
  * @default ''
@@ -32,9 +32,10 @@ type ProgressRadialProps = {
32
32
  * <ProgressRadial value={50} />
33
33
  * Indeterminate
34
34
  * <ProgressRadial indeterminate />
35
- * Positive / Negative
35
+ * // Positive / Negative / Warning
36
36
  * <ProgressRadial status='positive' />
37
37
  * <ProgressRadial status='negative' />
38
+ * <ProgressRadial status='warning' />
38
39
  * Centered Content
39
40
  * <ProgressRadial value={63}>63</ProgressRadial>
40
41
  * Small
@@ -41,9 +41,10 @@ const index_js_1 = require("../utils/index.js");
41
41
  * <ProgressRadial value={50} />
42
42
  * Indeterminate
43
43
  * <ProgressRadial indeterminate />
44
- * Positive / Negative
44
+ * // Positive / Negative / Warning
45
45
  * <ProgressRadial status='positive' />
46
46
  * <ProgressRadial status='negative' />
47
+ * <ProgressRadial status='warning' />
47
48
  * Centered Content
48
49
  * <ProgressRadial value={63}>63</ProgressRadial>
49
50
  * Small
@@ -54,6 +55,7 @@ exports.ProgressRadial = React.forwardRef((props, forwardedRef) => {
54
55
  const statusMap = {
55
56
  negative: React.createElement(index_js_1.SvgImportantSmall, { "aria-hidden": true }),
56
57
  positive: React.createElement(index_js_1.SvgCheckmarkSmall, { "aria-hidden": true }),
58
+ warning: React.createElement(index_js_1.SvgImportantSmall, { "aria-hidden": true }),
57
59
  };
58
60
  return (React.createElement(index_js_1.Box, { className: (0, classnames_1.default)('iui-progress-indicator-radial', className), "data-iui-size": size, "data-iui-status": status, "data-iui-indeterminate": indeterminate ? 'true' : undefined, ref: forwardedRef, style: {
59
61
  ...(value !== undefined && {
@@ -316,10 +316,19 @@ const Table = (props) => {
316
316
  instance.selectedFlatRows,
317
317
  selectionMode,
318
318
  ]);
319
+ const headerRef = React.useRef(null);
320
+ const bodyRef = React.useRef(null);
319
321
  const { scrollToIndex, tableRowRef } = (0, index_js_3.useScrollToRow)({ ...props, page });
320
322
  const columnRefs = React.useRef({});
321
323
  const previousTableWidth = React.useRef(0);
322
324
  const onTableResize = React.useCallback(({ width }) => {
325
+ // Handle header properties, regardless of whether the table is resizable
326
+ setHeaderScrollWidth(headerRef.current?.scrollWidth ?? 0);
327
+ setHeaderClientWidth(headerRef.current?.clientWidth ?? 0);
328
+ // Handle table properties, but only when table is resizable
329
+ if (!isResizable) {
330
+ return;
331
+ }
323
332
  instance.tableWidth = width;
324
333
  if (width === previousTableWidth.current) {
325
334
  return;
@@ -337,10 +346,18 @@ const Table = (props) => {
337
346
  return;
338
347
  }
339
348
  dispatch({ type: exports.tableResizeStartAction });
340
- }, [dispatch, state.columnResizing.columnWidths, flatHeaders, instance]);
349
+ }, [
350
+ dispatch,
351
+ state.columnResizing.columnWidths,
352
+ flatHeaders,
353
+ instance,
354
+ isResizable,
355
+ ]);
341
356
  const [resizeRef] = (0, index_js_1.useResizeObserver)(onTableResize);
357
+ const [headerScrollWidth, setHeaderScrollWidth] = React.useState(0);
358
+ const [headerClientWidth, setHeaderClientWidth] = React.useState(0);
342
359
  // Flexbox handles columns resize so we take new column widths before browser repaints.
343
- (0, index_js_1.useIsomorphicLayoutEffect)(() => {
360
+ (0, index_js_1.useLayoutEffect)(() => {
344
361
  if (state.isTableResizing) {
345
362
  const newColumnWidths = {};
346
363
  flatHeaders.forEach((column) => {
@@ -352,8 +369,6 @@ const Table = (props) => {
352
369
  dispatch({ type: tableResizeEndAction, columnWidths: newColumnWidths });
353
370
  }
354
371
  });
355
- const headerRef = React.useRef(null);
356
- const bodyRef = React.useRef(null);
357
372
  const getPreparedRow = React.useCallback((index) => {
358
373
  const row = page[index];
359
374
  prepareRow(row);
@@ -403,9 +418,7 @@ const Table = (props) => {
403
418
  return (React.createElement(React.Fragment, null,
404
419
  React.createElement(index_js_1.Box, { ref: (element) => {
405
420
  ownerDocument.current = element?.ownerDocument;
406
- if (isResizable) {
407
- resizeRef(element);
408
- }
421
+ resizeRef(element);
409
422
  }, id: id, ...getTableProps({
410
423
  className: (0, classnames_1.default)('iui-table', className),
411
424
  style: {
@@ -497,12 +510,12 @@ const Table = (props) => {
497
510
  }, tabIndex: -1, "aria-multiselectable": (isSelectable && selectionMode === 'multi') || undefined },
498
511
  React.createElement(ShadowTemplate, null,
499
512
  React.createElement("slot", null),
500
- React.createElement("div", { "aria-hidden": true, style: {
513
+ rows.length === 0 && headerScrollWidth > headerClientWidth && (React.createElement("div", { "aria-hidden": true, style: {
501
514
  // This ensures that the table-body is always the same width as the table-header,
502
515
  // even if the table has no rows. See https://github.com/iTwin/iTwinUI/pull/1725
503
- width: headerRef.current?.scrollWidth,
516
+ width: headerScrollWidth,
504
517
  height: 0.1,
505
- } })),
518
+ } }))),
506
519
  data.length !== 0 && (React.createElement(React.Fragment, null, enableVirtualization ? (React.createElement(VirtualScroll_js_1.default, { itemsLength: page.length, itemRenderer: virtualizedItemRenderer, scrollToIndex: scrollToIndex })) : (page.map((_, index) => getPreparedRow(index))))),
507
520
  isLoading && data.length === 0 && (React.createElement(index_js_1.Box, { as: 'div', ...emptyTableContentProps, className: (0, classnames_1.default)('iui-table-empty', emptyTableContentProps?.className) },
508
521
  React.createElement(ProgressRadial_js_1.ProgressRadial, { indeterminate: true }))),
@@ -82,27 +82,27 @@ const Tab = React.forwardRef((props, forwardedRef) => {
82
82
  const isActive = activeValue === value;
83
83
  const isActiveRef = (0, index_js_1.useLatestRef)(isActive);
84
84
  // Scroll to active tab only on initial render
85
- (0, index_js_1.useIsomorphicLayoutEffect)(() => {
85
+ (0, index_js_1.useLayoutEffect)(() => {
86
86
  if (isActiveRef.current) {
87
87
  tabRef.current?.parentElement?.scrollTo({
88
88
  [orientation === 'horizontal' ? 'left' : 'top']: tabRef.current?.[orientation === 'horizontal' ? 'offsetLeft' : 'offsetTop'] - 4,
89
89
  behavior: 'instant', // not using 'smooth' to reduce layout shift on page load
90
90
  });
91
91
  }
92
- }, []);
93
- const updateStripe = () => {
94
- const currentTabRect = tabRef.current?.getBoundingClientRect();
95
- setStripeProperties({
96
- '--iui-tabs-stripe-size': orientation === 'horizontal'
97
- ? `${currentTabRect?.width}px`
98
- : `${currentTabRect?.height}px`,
99
- '--iui-tabs-stripe-position': orientation === 'horizontal'
100
- ? `${tabRef.current?.offsetLeft}px`
101
- : `${tabRef.current?.offsetTop}px`,
102
- });
103
- };
92
+ }, [isActiveRef, orientation]);
104
93
  // CSS custom properties to place the active stripe
105
- (0, index_js_1.useIsomorphicLayoutEffect)(() => {
94
+ (0, index_js_1.useLayoutEffect)(() => {
95
+ const updateStripe = () => {
96
+ const currentTabRect = tabRef.current?.getBoundingClientRect();
97
+ setStripeProperties({
98
+ '--iui-tabs-stripe-size': orientation === 'horizontal'
99
+ ? `${currentTabRect?.width}px`
100
+ : `${currentTabRect?.height}px`,
101
+ '--iui-tabs-stripe-position': orientation === 'horizontal'
102
+ ? `${tabRef.current?.offsetLeft}px`
103
+ : `${tabRef.current?.offsetTop}px`,
104
+ });
105
+ };
106
106
  if (type !== 'default' && isActive) {
107
107
  updateStripe();
108
108
  }
@@ -110,7 +110,8 @@ const Tab = React.forwardRef((props, forwardedRef) => {
110
110
  type,
111
111
  orientation,
112
112
  isActive,
113
- tabsWidth, // to fix visual artifact on initial render
113
+ tabsWidth,
114
+ setStripeProperties,
114
115
  ]);
115
116
  const onKeyDown = (event) => {
116
117
  if (event.altKey) {
@@ -186,7 +187,7 @@ TabLabel.displayName = 'Tabs.TabLabel';
186
187
  const TabDescription = React.forwardRef((props, ref) => {
187
188
  const { className, children, ...rest } = props;
188
189
  const { hasSublabel, setHasSublabel } = (0, index_js_1.useSafeContext)(TabsContext);
189
- (0, index_js_1.useIsomorphicLayoutEffect)(() => {
190
+ (0, index_js_1.useLayoutEffect)(() => {
190
191
  if (!hasSublabel) {
191
192
  setHasSublabel(true);
192
193
  }
@@ -2,22 +2,44 @@ import * as React from 'react';
2
2
  import type { PolymorphicForwardRefComponent } from '../utils/index.js';
3
3
  type TagProps = {
4
4
  /**
5
- * Callback function that handles click on close icon.
6
- * Close icon is shown only when this function is passed.
7
- * Use only with 'default' Tag.
5
+ * Text inside the tag.
6
+ */
7
+ children: React.ReactNode;
8
+ /**
9
+ * Callback invoked when the tag is clicked.
10
+ *
11
+ * When this prop is passed, the tag will be rendered as a button.
12
+ */
13
+ onClick?: React.MouseEventHandler;
14
+ /**
15
+ * Callback function that handles click on the remove ("❌") button.
16
+ * If not passed, the remove button will not be shown.
17
+ *
18
+ * If both `onClick` and `onRemove` are passed, then the tag label (rather than the tag itself)
19
+ * will be rendered as a button, to avoid invalid markup (nested buttons).
8
20
  */
9
21
  onRemove?: React.MouseEventHandler;
10
22
  /**
11
- * Text inside the tag.
23
+ * Props for customizing the remove ("❌") button.
12
24
  */
13
- children: React.ReactNode;
25
+ removeButtonProps?: React.ComponentPropsWithRef<'button'>;
26
+ } & ({
14
27
  /**
15
28
  * Variant of tag.
16
29
  * Basic tags don't have an outline.
17
30
  * @default 'default'
18
31
  */
19
- variant?: 'default' | 'basic';
20
- };
32
+ variant?: 'default';
33
+ /**
34
+ * Props for customizing the label.
35
+ *
36
+ * Only relevant for the 'default' Tag.
37
+ */
38
+ labelProps?: React.ComponentPropsWithRef<'span'>;
39
+ } | {
40
+ variant?: 'basic';
41
+ labelProps?: never;
42
+ });
21
43
  /**
22
44
  * Tag for showing categories, filters etc.
23
45
  * @example
@@ -35,6 +35,7 @@ const classnames_1 = __importDefault(require("classnames"));
35
35
  const React = __importStar(require("react"));
36
36
  const index_js_1 = require("../utils/index.js");
37
37
  const IconButton_js_1 = require("../Buttons/IconButton.js");
38
+ const LinkAction_js_1 = require("../LinkAction/LinkAction.js");
38
39
  /**
39
40
  * Tag for showing categories, filters etc.
40
41
  * @example
@@ -42,13 +43,19 @@ const IconButton_js_1 = require("../Buttons/IconButton.js");
42
43
  * <Tag variant='basic'>Basic tag</Tag>
43
44
  */
44
45
  exports.Tag = React.forwardRef((props, forwardedRef) => {
45
- const { className, variant = 'default', children, onRemove, ...rest } = props;
46
- return (React.createElement(index_js_1.Box, { as: 'span', className: (0, classnames_1.default)({
46
+ const { className, variant = 'default', children, onRemove, onClick, labelProps, removeButtonProps, ...rest } = props;
47
+ // If both onClick and onRemove are passed, we want to render the label as a button
48
+ // to avoid invalid markup (nested buttons). LinkAction ensures that clicking anywhere outside
49
+ // the remove button (including padding) will still trigger the main onClick callback.
50
+ const shouldUseLinkAction = !!onClick && !!onRemove;
51
+ return (React.createElement(index_js_1.Box, { as: shouldUseLinkAction ? LinkAction_js_1.LinkBox : !!onClick ? index_js_1.ButtonBase : 'span', className: (0, classnames_1.default)({
47
52
  'iui-tag-basic': variant === 'basic',
48
53
  'iui-tag': variant === 'default',
49
- }, className), ref: forwardedRef, ...rest },
50
- variant === 'default' ? (React.createElement(index_js_1.Box, { as: 'span', className: 'iui-tag-label' }, children)) : (children),
51
- onRemove && (React.createElement(IconButton_js_1.IconButton, { styleType: 'borderless', size: 'small', onClick: onRemove, "aria-label": 'Delete tag', className: 'iui-tag-button' },
54
+ }, className),
55
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ref's type doesn't matter internally
56
+ ref: forwardedRef, onClick: !shouldUseLinkAction ? onClick : undefined, ...rest },
57
+ variant === 'default' ? (React.createElement(index_js_1.Box, { as: (shouldUseLinkAction ? LinkAction_js_1.LinkAction : 'span'), onClick: shouldUseLinkAction ? onClick : undefined, ...labelProps, className: (0, classnames_1.default)('iui-tag-label', labelProps?.className) }, children)) : (children),
58
+ onRemove && (React.createElement(IconButton_js_1.IconButton, { styleType: 'borderless', size: 'small', onClick: onRemove, "aria-label": 'Delete tag', ...removeButtonProps, className: (0, classnames_1.default)('iui-tag-button', removeButtonProps?.className) },
52
59
  React.createElement(index_js_1.SvgCloseSmall, { "aria-hidden": true })))));
53
60
  });
54
61
  exports.default = exports.Tag;