@itwin/itwinui-react 3.3.4 → 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.
- package/CHANGELOG.md +11 -0
- package/cjs/core/Carousel/CarouselSlider.js +1 -1
- package/cjs/core/ComboBox/ComboBox.js +1 -1
- package/cjs/core/DatePicker/DatePicker.d.ts +8 -0
- package/cjs/core/DatePicker/DatePicker.js +9 -4
- package/cjs/core/Dialog/DialogMain.js +1 -1
- package/cjs/core/FileUpload/FileUploadTemplate.d.ts +2 -1
- package/cjs/core/FileUpload/FileUploadTemplate.js +2 -1
- package/cjs/core/LinkAction/LinkAction.d.ts +3 -2
- package/cjs/core/LinkAction/LinkAction.js +33 -1
- package/cjs/core/Modal/Modal.d.ts +12 -0
- package/cjs/core/Modal/Modal.js +4 -4
- package/cjs/core/Popover/Popover.js +1 -1
- package/cjs/core/ProgressIndicators/ProgressLinear.d.ts +15 -7
- package/cjs/core/ProgressIndicators/ProgressLinear.js +14 -6
- package/cjs/core/ProgressIndicators/ProgressRadial.d.ts +3 -2
- package/cjs/core/ProgressIndicators/ProgressRadial.js +3 -1
- package/cjs/core/Table/Table.js +1 -1
- package/cjs/core/Tabs/Tabs.js +17 -16
- package/cjs/core/Tag/Tag.d.ts +29 -7
- package/cjs/core/Tag/Tag.js +12 -5
- package/cjs/core/ThemeProvider/ThemeProvider.js +2 -2
- package/cjs/core/utils/components/VirtualScroll.js +7 -7
- package/cjs/core/utils/hooks/useIsomorphicLayoutEffect.d.ts +4 -1
- package/cjs/core/utils/hooks/useIsomorphicLayoutEffect.js +5 -2
- package/cjs/core/utils/hooks/useMediaQuery.js +1 -1
- package/cjs/core/utils/hooks/useOverflow.js +3 -3
- package/esm/core/Carousel/CarouselSlider.js +2 -2
- package/esm/core/ComboBox/ComboBox.js +2 -2
- package/esm/core/DatePicker/DatePicker.d.ts +8 -0
- package/esm/core/DatePicker/DatePicker.js +9 -4
- package/esm/core/Dialog/DialogMain.js +2 -2
- package/esm/core/FileUpload/FileUploadTemplate.d.ts +2 -1
- package/esm/core/FileUpload/FileUploadTemplate.js +2 -1
- package/esm/core/LinkAction/LinkAction.d.ts +3 -2
- package/esm/core/LinkAction/LinkAction.js +7 -1
- package/esm/core/Modal/Modal.d.ts +12 -0
- package/esm/core/Modal/Modal.js +4 -4
- package/esm/core/Popover/Popover.js +2 -2
- package/esm/core/ProgressIndicators/ProgressLinear.d.ts +15 -7
- package/esm/core/ProgressIndicators/ProgressLinear.js +14 -6
- package/esm/core/ProgressIndicators/ProgressRadial.d.ts +3 -2
- package/esm/core/ProgressIndicators/ProgressRadial.js +3 -1
- package/esm/core/Table/Table.js +2 -2
- package/esm/core/Tabs/Tabs.js +18 -17
- package/esm/core/Tag/Tag.d.ts +29 -7
- package/esm/core/Tag/Tag.js +13 -6
- package/esm/core/ThemeProvider/ThemeProvider.js +3 -3
- package/esm/core/utils/components/VirtualScroll.js +8 -8
- package/esm/core/utils/hooks/useIsomorphicLayoutEffect.d.ts +4 -1
- package/esm/core/utils/hooks/useIsomorphicLayoutEffect.js +4 -1
- package/esm/core/utils/hooks/useMediaQuery.js +2 -2
- package/esm/core/utils/hooks/useOverflow.js +4 -4
- package/package.json +2 -2
- package/styles.css +8 -8
|
@@ -64,7 +64,7 @@ const useOverflow = (items, disabled = false, orientation = 'horizontal') => {
|
|
|
64
64
|
const updateContainerSize = React.useCallback(({ width, height }) => setContainerSize(orientation === 'horizontal' ? width : height), [orientation]);
|
|
65
65
|
const [resizeRef, observer] = (0, useResizeObserver_js_1.useResizeObserver)(updateContainerSize);
|
|
66
66
|
const resizeObserverRef = React.useRef(observer);
|
|
67
|
-
(0, useIsomorphicLayoutEffect_js_1.
|
|
67
|
+
(0, useIsomorphicLayoutEffect_js_1.useLayoutEffect)(() => {
|
|
68
68
|
if (disabled) {
|
|
69
69
|
setVisibleCount(items.length);
|
|
70
70
|
}
|
|
@@ -74,7 +74,7 @@ const useOverflow = (items, disabled = false, orientation = 'horizontal') => {
|
|
|
74
74
|
}
|
|
75
75
|
}, [containerSize, disabled, items]);
|
|
76
76
|
const mergedRefs = (0, useMergedRefs_js_1.useMergedRefs)(containerRef, resizeRef);
|
|
77
|
-
(0, useIsomorphicLayoutEffect_js_1.
|
|
77
|
+
(0, useIsomorphicLayoutEffect_js_1.useLayoutEffect)(() => {
|
|
78
78
|
if (!containerRef.current || disabled) {
|
|
79
79
|
resizeObserverRef.current?.disconnect();
|
|
80
80
|
return;
|
|
@@ -103,7 +103,7 @@ const useOverflow = (items, disabled = false, orientation = 'horizontal') => {
|
|
|
103
103
|
}
|
|
104
104
|
needsFullRerender.current = false;
|
|
105
105
|
}, [containerSize, visibleCount, disabled, items.length, orientation]);
|
|
106
|
-
(0, useIsomorphicLayoutEffect_js_1.
|
|
106
|
+
(0, useIsomorphicLayoutEffect_js_1.useLayoutEffect)(() => {
|
|
107
107
|
previousContainerSize.current = containerSize;
|
|
108
108
|
}, [containerSize]);
|
|
109
109
|
return [mergedRefs, visibleCount];
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import cx from 'classnames';
|
|
7
7
|
import { CarouselContext } from './CarouselContext.js';
|
|
8
|
-
import { getWindow, useMergedRefs,
|
|
8
|
+
import { getWindow, useMergedRefs, useLayoutEffect, Box, } from '../utils/index.js';
|
|
9
9
|
/**
|
|
10
10
|
* `CarouselSlider` is the scrollable list that should consist of `CarouselSlide` components.
|
|
11
11
|
*/
|
|
@@ -23,7 +23,7 @@ export const CarouselSlider = React.forwardRef((props, ref) => {
|
|
|
23
23
|
index,
|
|
24
24
|
})
|
|
25
25
|
: child) ?? [], [children, idPrefix]);
|
|
26
|
-
|
|
26
|
+
useLayoutEffect(() => {
|
|
27
27
|
setSlideCount(items.length);
|
|
28
28
|
}, [items.length, setSlideCount]);
|
|
29
29
|
const sliderRef = React.useRef(null);
|
|
@@ -6,7 +6,7 @@ import * as React from 'react';
|
|
|
6
6
|
import { MenuExtraContent } from '../Menu/MenuExtraContent.js';
|
|
7
7
|
import { SelectTag } from '../Select/SelectTag.js';
|
|
8
8
|
import { Text } from '../Typography/Text.js';
|
|
9
|
-
import { mergeRefs, useLatestRef,
|
|
9
|
+
import { mergeRefs, useLatestRef, useLayoutEffect, AutoclearingHiddenLiveRegion, useId, } from '../utils/index.js';
|
|
10
10
|
import { usePopover } from '../Popover/Popover.js';
|
|
11
11
|
import { ComboBoxActionContext, comboBoxReducer, ComboBoxRefsContext, ComboBoxStateContext, } from './helpers.js';
|
|
12
12
|
import { ComboBoxEndIcon } from './ComboBoxEndIcon.js';
|
|
@@ -94,7 +94,7 @@ export const ComboBox = React.forwardRef((props, forwardedRef) => {
|
|
|
94
94
|
dispatch({ type: 'close' });
|
|
95
95
|
onHideRef.current?.();
|
|
96
96
|
}, [onHideRef]);
|
|
97
|
-
|
|
97
|
+
useLayoutEffect(() => {
|
|
98
98
|
// When the dropdown opens
|
|
99
99
|
if (isOpen) {
|
|
100
100
|
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
|
|
@@ -110,7 +110,7 @@ export const generateLocalizedStrings = (locale) => {
|
|
|
110
110
|
* <DatePicker date={new Date()} onChange={(e) => console.log('New date value: ' + e)} />
|
|
111
111
|
*/
|
|
112
112
|
export const DatePicker = React.forwardRef((props, forwardedRef) => {
|
|
113
|
-
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;
|
|
113
|
+
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;
|
|
114
114
|
const monthNames = localizedNames?.months ?? defaultMonths;
|
|
115
115
|
const shortDays = localizedNames?.shortDays ?? defaultShortDays;
|
|
116
116
|
const longDays = localizedNames?.days ?? defaultLongDays;
|
|
@@ -152,8 +152,9 @@ export const DatePicker = React.forwardRef((props, forwardedRef) => {
|
|
|
152
152
|
}, [date, setMonthAndYear, startDate, endDate, enableRangeSelect]);
|
|
153
153
|
const days = React.useMemo(() => {
|
|
154
154
|
let offsetToFirst = new Date(displayedYear, displayedMonthIndex, 1).getDay();
|
|
155
|
-
//
|
|
156
|
-
|
|
155
|
+
// If it's sunday, show one week before, but only if dates outside month are shown.
|
|
156
|
+
// (We do not want empty space at the top if dates outside month are not shown.)
|
|
157
|
+
if (0 === offsetToFirst && showDatesOutsideMonth) {
|
|
157
158
|
offsetToFirst = 7;
|
|
158
159
|
}
|
|
159
160
|
const daysInMonth = [];
|
|
@@ -163,7 +164,7 @@ export const DatePicker = React.forwardRef((props, forwardedRef) => {
|
|
|
163
164
|
daysInMonth.push(new Date(displayedYear, displayedMonthIndex, adjustedDay));
|
|
164
165
|
}
|
|
165
166
|
return daysInMonth;
|
|
166
|
-
}, [displayedMonthIndex, displayedYear]);
|
|
167
|
+
}, [displayedMonthIndex, displayedYear, showDatesOutsideMonth]);
|
|
167
168
|
const weeks = React.useMemo(() => {
|
|
168
169
|
const weeksInMonth = [];
|
|
169
170
|
const weekCount = Math.ceil(days.length / 7);
|
|
@@ -353,6 +354,10 @@ export const DatePicker = React.forwardRef((props, forwardedRef) => {
|
|
|
353
354
|
return (React.createElement(Box, { as: 'div', key: `week-${displayedMonthIndex}-${weekIndex}`, ...weekProps, className: cx('iui-calendar-week', weekProps?.className) }, weekDays.map((weekDay, dayIndex) => {
|
|
354
355
|
const dateValue = weekDay.getDate();
|
|
355
356
|
const isDisabled = isDateDisabled?.(weekDay);
|
|
357
|
+
const isOutsideMonth = weekDay.getMonth() !== displayedMonthIndex;
|
|
358
|
+
if (isOutsideMonth && !showDatesOutsideMonth) {
|
|
359
|
+
return (React.createElement(Box, { key: `day-${displayedMonthIndex}-${dayIndex}`, className: cx(getDayClass(weekDay), dayProps?.className), "aria-hidden": true }));
|
|
360
|
+
}
|
|
356
361
|
return (React.createElement(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) &&
|
|
357
362
|
needFocus.current &&
|
|
358
363
|
element?.focus(), ...dayProps, className: cx(getDayClass(weekDay), dayProps?.className) }, dateValue));
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import cx from 'classnames';
|
|
7
|
-
import { FocusTrap, getTranslateValuesFromElement, Resizer, useMergedRefs,
|
|
7
|
+
import { FocusTrap, getTranslateValuesFromElement, Resizer, useMergedRefs, useLayoutEffect, Box, } from '../utils/index.js';
|
|
8
8
|
import { useDialogContext } from './DialogContext.js';
|
|
9
9
|
import { CSSTransition } from 'react-transition-group';
|
|
10
10
|
import { DialogDragContext } from './DialogDragContext.js';
|
|
@@ -81,7 +81,7 @@ export const DialogMain = React.forwardRef((props, ref) => {
|
|
|
81
81
|
}
|
|
82
82
|
}, [isDraggable, onPointerDown]);
|
|
83
83
|
// Prevents dialog from moving when window is being resized
|
|
84
|
-
|
|
84
|
+
useLayoutEffect(() => {
|
|
85
85
|
if (!isDraggable || !isOpen) {
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
@@ -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
|
|
@@ -7,7 +7,8 @@ import cx from 'classnames';
|
|
|
7
7
|
import { SvgUpload, Box } from '../utils/index.js';
|
|
8
8
|
import { Anchor } from '../Typography/Anchor.js';
|
|
9
9
|
/**
|
|
10
|
-
* @deprecated Use `FileUploadCard` instead.
|
|
10
|
+
* @deprecated Use [`FileUploadCard`](https://itwinui.bentley.com/docs/fileupload#fileuploadcard) instead.
|
|
11
|
+
*
|
|
11
12
|
* Default template to be used with the `FileUpload` wrapper component.
|
|
12
13
|
* Contains a hidden input with styled labels (customizable).
|
|
13
14
|
* @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:
|
|
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:
|
|
24
|
+
export declare const LinkBox: PolymorphicForwardRefComponent<"div", {}>;
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
3
|
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import cx from 'classnames';
|
|
5
7
|
import { polymorphic } from '../utils/functions/polymorphic.js';
|
|
8
|
+
import { Box } from '../utils/components/index.js';
|
|
6
9
|
/**
|
|
7
10
|
* Polymorphic link action component.
|
|
8
11
|
* It is rendered as `a` by default.
|
|
@@ -13,7 +16,10 @@ import { polymorphic } from '../utils/functions/polymorphic.js';
|
|
|
13
16
|
* </Surface>
|
|
14
17
|
* </LinkBox>
|
|
15
18
|
*/
|
|
16
|
-
export const LinkAction =
|
|
19
|
+
export const LinkAction = React.forwardRef((props, forwardedRef) => {
|
|
20
|
+
const { as: asProp = (!!props.href ? 'a' : 'button') } = props;
|
|
21
|
+
return (React.createElement(Box, { ...props, as: asProp, className: cx('iui-link-action', props.className), ref: forwardedRef }));
|
|
22
|
+
});
|
|
17
23
|
LinkAction.displayName = 'LinkAction';
|
|
18
24
|
/**
|
|
19
25
|
* 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.
|
package/esm/core/Modal/Modal.js
CHANGED
|
@@ -26,11 +26,11 @@ import { Dialog } from '../Dialog/Dialog.js';
|
|
|
26
26
|
* </Modal>
|
|
27
27
|
*/
|
|
28
28
|
export const Modal = React.forwardRef((props, forwardedRef) => {
|
|
29
|
-
const { isOpen = false, isDismissible = true, closeOnEsc = true, closeOnExternalClick = true, onClose, title, children, portal = true, ...rest } = props;
|
|
30
|
-
return (React.createElement(Dialog, { isOpen: isOpen, closeOnEsc: closeOnEsc, closeOnExternalClick: closeOnExternalClick, isDismissible: isDismissible, onClose: onClose, preventDocumentScroll: true, trapFocus: true, setFocus: true, ref: forwardedRef, portal: portal },
|
|
31
|
-
React.createElement(Dialog.Backdrop,
|
|
29
|
+
const { isOpen = false, isDismissible = true, closeOnEsc = true, closeOnExternalClick = true, onClose, title, children, portal = true, wrapperProps, backdropProps, titleBarProps, ...rest } = props;
|
|
30
|
+
return (React.createElement(Dialog, { isOpen: isOpen, closeOnEsc: closeOnEsc, closeOnExternalClick: closeOnExternalClick, isDismissible: isDismissible, onClose: onClose, preventDocumentScroll: true, trapFocus: true, setFocus: true, ref: forwardedRef, portal: portal, ...wrapperProps },
|
|
31
|
+
React.createElement(Dialog.Backdrop, { ...backdropProps }),
|
|
32
32
|
React.createElement(Dialog.Main, { "aria-modal": true, ...rest },
|
|
33
|
-
React.createElement(Dialog.TitleBar, { titleText: title }),
|
|
33
|
+
React.createElement(Dialog.TitleBar, { titleText: title, ...titleBarProps }),
|
|
34
34
|
children)));
|
|
35
35
|
});
|
|
36
36
|
export default Modal;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import cx from 'classnames';
|
|
7
7
|
import { useFloating, useClick, useDismiss, useInteractions, size, autoUpdate, offset, flip, shift, autoPlacement, inline, hide, FloatingFocusManager, useHover, useFocus, safePolygon, useRole, FloatingPortal, } from '@floating-ui/react';
|
|
8
|
-
import { Box, cloneElementWithRef, useControlledState, useId,
|
|
8
|
+
import { Box, cloneElementWithRef, useControlledState, useId, useLayoutEffect, useMergedRefs, } from '../utils/index.js';
|
|
9
9
|
import { Portal } from '../utils/components/Portal.js';
|
|
10
10
|
import { ThemeProvider } from '../ThemeProvider/ThemeProvider.js';
|
|
11
11
|
// ----------------------------------------------------------------------------
|
|
@@ -101,7 +101,7 @@ export const Popover = React.forwardRef((props, forwardedRef) => {
|
|
|
101
101
|
const popoverRef = useMergedRefs(popover.refs.setFloating, forwardedRef, setPopoverElement);
|
|
102
102
|
const triggerId = `${useId()}-trigger`;
|
|
103
103
|
const hasAriaLabel = !!props['aria-labelledby'] || !!props['aria-label'];
|
|
104
|
-
|
|
104
|
+
useLayoutEffect(() => {
|
|
105
105
|
if (!positionReference) {
|
|
106
106
|
return;
|
|
107
107
|
}
|
|
@@ -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
|
-
*
|
|
44
|
-
* <ProgressLinear
|
|
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>;
|
|
@@ -8,16 +8,24 @@ import { Box, getBoundedValue } from '../utils/index.js';
|
|
|
8
8
|
/**
|
|
9
9
|
* Shows progress on a linear bar
|
|
10
10
|
* @example
|
|
11
|
-
* Determinate
|
|
11
|
+
* // Determinate
|
|
12
12
|
* <ProgressLinear value={25}/>
|
|
13
|
-
* Indeterminate
|
|
13
|
+
* // Indeterminate
|
|
14
14
|
* <ProgressLinear indeterminate={true}/>
|
|
15
|
-
* Labeled - Center
|
|
15
|
+
* // Labeled - Center
|
|
16
16
|
* <ProgressLinear value={50} labels={['Centered Label']} />
|
|
17
|
-
* Labeled - Left & Right
|
|
17
|
+
* // Labeled - Left & Right
|
|
18
18
|
* <ProgressLinear value={50} labels={['Loading...', '50%']} />
|
|
19
|
-
*
|
|
20
|
-
* <ProgressLinear
|
|
19
|
+
* // Status
|
|
20
|
+
* <ProgressLinear
|
|
21
|
+
* status='positive'
|
|
22
|
+
* labels={[
|
|
23
|
+
* 'Upload done!',
|
|
24
|
+
* <Icon key='icon'>
|
|
25
|
+
* <SvgStatusSuccess />{' '}
|
|
26
|
+
* </Icon>
|
|
27
|
+
* ]}
|
|
28
|
+
* />
|
|
21
29
|
* <ProgressLinear status='negative' />
|
|
22
30
|
*/
|
|
23
31
|
export const 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
|
|
@@ -12,9 +12,10 @@ import { SvgCheckmarkSmall, SvgImportantSmall, Box, getBoundedValue, } from '../
|
|
|
12
12
|
* <ProgressRadial value={50} />
|
|
13
13
|
* Indeterminate
|
|
14
14
|
* <ProgressRadial indeterminate />
|
|
15
|
-
* Positive / Negative
|
|
15
|
+
* // Positive / Negative / Warning
|
|
16
16
|
* <ProgressRadial status='positive' />
|
|
17
17
|
* <ProgressRadial status='negative' />
|
|
18
|
+
* <ProgressRadial status='warning' />
|
|
18
19
|
* Centered Content
|
|
19
20
|
* <ProgressRadial value={63}>63</ProgressRadial>
|
|
20
21
|
* Small
|
|
@@ -25,6 +26,7 @@ export const ProgressRadial = React.forwardRef((props, forwardedRef) => {
|
|
|
25
26
|
const statusMap = {
|
|
26
27
|
negative: React.createElement(SvgImportantSmall, { "aria-hidden": true }),
|
|
27
28
|
positive: React.createElement(SvgCheckmarkSmall, { "aria-hidden": true }),
|
|
29
|
+
warning: React.createElement(SvgImportantSmall, { "aria-hidden": true }),
|
|
28
30
|
};
|
|
29
31
|
return (React.createElement(Box, { className: cx('iui-progress-indicator-radial', className), "data-iui-size": size, "data-iui-status": status, "data-iui-indeterminate": indeterminate ? 'true' : undefined, ref: forwardedRef, style: {
|
|
30
32
|
...(value !== undefined && {
|
package/esm/core/Table/Table.js
CHANGED
|
@@ -7,7 +7,7 @@ import * as ReactDOM from 'react-dom';
|
|
|
7
7
|
import cx from 'classnames';
|
|
8
8
|
import { actions as TableActions, useFlexLayout, useFilters, useRowSelect, useSortBy, useTable, useExpanded, usePagination, useColumnOrder, useGlobalFilter, } from 'react-table';
|
|
9
9
|
import { ProgressRadial } from '../ProgressIndicators/ProgressRadial.js';
|
|
10
|
-
import { useGlobals, useResizeObserver, SvgSortDown, SvgSortUp,
|
|
10
|
+
import { useGlobals, useResizeObserver, SvgSortDown, SvgSortUp, useLayoutEffect, Box, createWarningLogger, } from '../utils/index.js';
|
|
11
11
|
import { getCellStyle, getStickyStyle, getSubRowStyle } from './utils.js';
|
|
12
12
|
import { TableRowMemoized } from './TableRowMemoized.js';
|
|
13
13
|
import { FilterToggle } from './filters/index.js';
|
|
@@ -328,7 +328,7 @@ export const Table = (props) => {
|
|
|
328
328
|
const [headerScrollWidth, setHeaderScrollWidth] = React.useState(0);
|
|
329
329
|
const [headerClientWidth, setHeaderClientWidth] = React.useState(0);
|
|
330
330
|
// Flexbox handles columns resize so we take new column widths before browser repaints.
|
|
331
|
-
|
|
331
|
+
useLayoutEffect(() => {
|
|
332
332
|
if (state.isTableResizing) {
|
|
333
333
|
const newColumnWidths = {};
|
|
334
334
|
flatHeaders.forEach((column) => {
|
package/esm/core/Tabs/Tabs.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import cx from 'classnames';
|
|
6
6
|
import * as React from 'react';
|
|
7
|
-
import { useSafeContext, Box, polymorphic, useIsClient,
|
|
7
|
+
import { useSafeContext, Box, polymorphic, useIsClient, useLayoutEffect, useMergedRefs, useContainerWidth, ButtonBase, mergeEventHandlers, useControlledState, useId, useLatestRef, } from '../utils/index.js';
|
|
8
8
|
import { Icon } from '../Icon/Icon.js';
|
|
9
9
|
const TabsWrapper = React.forwardRef((props, ref) => {
|
|
10
10
|
const { className, children, orientation = 'horizontal', type = 'default', focusActivationMode = 'auto', color = 'blue', defaultValue, value: activeValueProp, onValueChange, ...rest } = props;
|
|
@@ -53,27 +53,27 @@ const Tab = React.forwardRef((props, forwardedRef) => {
|
|
|
53
53
|
const isActive = activeValue === value;
|
|
54
54
|
const isActiveRef = useLatestRef(isActive);
|
|
55
55
|
// Scroll to active tab only on initial render
|
|
56
|
-
|
|
56
|
+
useLayoutEffect(() => {
|
|
57
57
|
if (isActiveRef.current) {
|
|
58
58
|
tabRef.current?.parentElement?.scrollTo({
|
|
59
59
|
[orientation === 'horizontal' ? 'left' : 'top']: tabRef.current?.[orientation === 'horizontal' ? 'offsetLeft' : 'offsetTop'] - 4,
|
|
60
60
|
behavior: 'instant', // not using 'smooth' to reduce layout shift on page load
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
|
-
}, []);
|
|
64
|
-
const updateStripe = () => {
|
|
65
|
-
const currentTabRect = tabRef.current?.getBoundingClientRect();
|
|
66
|
-
setStripeProperties({
|
|
67
|
-
'--iui-tabs-stripe-size': orientation === 'horizontal'
|
|
68
|
-
? `${currentTabRect?.width}px`
|
|
69
|
-
: `${currentTabRect?.height}px`,
|
|
70
|
-
'--iui-tabs-stripe-position': orientation === 'horizontal'
|
|
71
|
-
? `${tabRef.current?.offsetLeft}px`
|
|
72
|
-
: `${tabRef.current?.offsetTop}px`,
|
|
73
|
-
});
|
|
74
|
-
};
|
|
63
|
+
}, [isActiveRef, orientation]);
|
|
75
64
|
// CSS custom properties to place the active stripe
|
|
76
|
-
|
|
65
|
+
useLayoutEffect(() => {
|
|
66
|
+
const updateStripe = () => {
|
|
67
|
+
const currentTabRect = tabRef.current?.getBoundingClientRect();
|
|
68
|
+
setStripeProperties({
|
|
69
|
+
'--iui-tabs-stripe-size': orientation === 'horizontal'
|
|
70
|
+
? `${currentTabRect?.width}px`
|
|
71
|
+
: `${currentTabRect?.height}px`,
|
|
72
|
+
'--iui-tabs-stripe-position': orientation === 'horizontal'
|
|
73
|
+
? `${tabRef.current?.offsetLeft}px`
|
|
74
|
+
: `${tabRef.current?.offsetTop}px`,
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
77
|
if (type !== 'default' && isActive) {
|
|
78
78
|
updateStripe();
|
|
79
79
|
}
|
|
@@ -81,7 +81,8 @@ const Tab = React.forwardRef((props, forwardedRef) => {
|
|
|
81
81
|
type,
|
|
82
82
|
orientation,
|
|
83
83
|
isActive,
|
|
84
|
-
tabsWidth,
|
|
84
|
+
tabsWidth,
|
|
85
|
+
setStripeProperties,
|
|
85
86
|
]);
|
|
86
87
|
const onKeyDown = (event) => {
|
|
87
88
|
if (event.altKey) {
|
|
@@ -157,7 +158,7 @@ TabLabel.displayName = 'Tabs.TabLabel';
|
|
|
157
158
|
const TabDescription = React.forwardRef((props, ref) => {
|
|
158
159
|
const { className, children, ...rest } = props;
|
|
159
160
|
const { hasSublabel, setHasSublabel } = useSafeContext(TabsContext);
|
|
160
|
-
|
|
161
|
+
useLayoutEffect(() => {
|
|
161
162
|
if (!hasSublabel) {
|
|
162
163
|
setHasSublabel(true);
|
|
163
164
|
}
|
package/esm/core/Tag/Tag.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
*
|
|
23
|
+
* Props for customizing the remove ("❌") button.
|
|
12
24
|
*/
|
|
13
|
-
|
|
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'
|
|
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
|
package/esm/core/Tag/Tag.js
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import cx from 'classnames';
|
|
6
6
|
import * as React from 'react';
|
|
7
|
-
import { SvgCloseSmall, Box } from '../utils/index.js';
|
|
7
|
+
import { SvgCloseSmall, Box, ButtonBase } from '../utils/index.js';
|
|
8
8
|
import { IconButton } from '../Buttons/IconButton.js';
|
|
9
|
+
import { LinkAction, LinkBox } from '../LinkAction/LinkAction.js';
|
|
9
10
|
/**
|
|
10
11
|
* Tag for showing categories, filters etc.
|
|
11
12
|
* @example
|
|
@@ -13,13 +14,19 @@ import { IconButton } from '../Buttons/IconButton.js';
|
|
|
13
14
|
* <Tag variant='basic'>Basic tag</Tag>
|
|
14
15
|
*/
|
|
15
16
|
export const Tag = React.forwardRef((props, forwardedRef) => {
|
|
16
|
-
const { className, variant = 'default', children, onRemove, ...rest } = props;
|
|
17
|
-
|
|
17
|
+
const { className, variant = 'default', children, onRemove, onClick, labelProps, removeButtonProps, ...rest } = props;
|
|
18
|
+
// If both onClick and onRemove are passed, we want to render the label as a button
|
|
19
|
+
// to avoid invalid markup (nested buttons). LinkAction ensures that clicking anywhere outside
|
|
20
|
+
// the remove button (including padding) will still trigger the main onClick callback.
|
|
21
|
+
const shouldUseLinkAction = !!onClick && !!onRemove;
|
|
22
|
+
return (React.createElement(Box, { as: shouldUseLinkAction ? LinkBox : !!onClick ? ButtonBase : 'span', className: cx({
|
|
18
23
|
'iui-tag-basic': variant === 'basic',
|
|
19
24
|
'iui-tag': variant === 'default',
|
|
20
|
-
}, className),
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
}, className),
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- ref's type doesn't matter internally
|
|
27
|
+
ref: forwardedRef, onClick: !shouldUseLinkAction ? onClick : undefined, ...rest },
|
|
28
|
+
variant === 'default' ? (React.createElement(Box, { as: (shouldUseLinkAction ? LinkAction : 'span'), onClick: shouldUseLinkAction ? onClick : undefined, ...labelProps, className: cx('iui-tag-label', labelProps?.className) }, children)) : (children),
|
|
29
|
+
onRemove && (React.createElement(IconButton, { styleType: 'borderless', size: 'small', onClick: onRemove, "aria-label": 'Delete tag', ...removeButtonProps, className: cx('iui-tag-button', removeButtonProps?.className) },
|
|
23
30
|
React.createElement(SvgCloseSmall, { "aria-hidden": true })))));
|
|
24
31
|
});
|
|
25
32
|
export default Tag;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import * as ReactDOM from 'react-dom';
|
|
7
7
|
import cx from 'classnames';
|
|
8
|
-
import { useMediaQuery, useMergedRefs, Box,
|
|
8
|
+
import { useMediaQuery, useMergedRefs, Box, useLayoutEffect, useControlledState, useLatestRef, importCss, isUnitTest, } from '../utils/index.js';
|
|
9
9
|
import { ThemeContext } from './ThemeContext.js';
|
|
10
10
|
import { ToastProvider, Toaster } from '../Toast/Toaster.js';
|
|
11
11
|
/**
|
|
@@ -87,7 +87,7 @@ const useParentThemeAndContext = (rootElement) => {
|
|
|
87
87
|
const [parentThemeState, setParentTheme] = React.useState(parentContext?.theme);
|
|
88
88
|
const [parentHighContrastState, setParentHighContrastState] = React.useState(parentContext?.themeOptions?.highContrast);
|
|
89
89
|
const parentThemeRef = useLatestRef(parentContext?.theme);
|
|
90
|
-
|
|
90
|
+
useLayoutEffect(() => {
|
|
91
91
|
// bail if we already have theme from context
|
|
92
92
|
if (parentThemeRef.current) {
|
|
93
93
|
return;
|
|
@@ -126,7 +126,7 @@ const useParentThemeAndContext = (rootElement) => {
|
|
|
126
126
|
* dynamically import it (if possible) and fallback to loading it from a CDN.
|
|
127
127
|
*/
|
|
128
128
|
const FallbackStyles = ({ root }) => {
|
|
129
|
-
|
|
129
|
+
useLayoutEffect(() => {
|
|
130
130
|
// bail if styles are already loaded
|
|
131
131
|
if (getComputedStyle(root).getPropertyValue('--_iui-v3-loaded') === 'yes') {
|
|
132
132
|
return;
|