@itwin/itwinui-react 3.0.0-dev.2 → 3.0.0-dev.4
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 +35 -0
- package/cjs/core/Alert/Alert.d.ts +2 -2
- package/cjs/core/Avatar/Avatar.d.ts +0 -4
- package/cjs/core/Avatar/Avatar.js +1 -5
- package/cjs/core/Avatar/index.d.ts +1 -1
- package/cjs/core/Avatar/index.js +1 -2
- package/cjs/core/AvatarGroup/AvatarGroup.d.ts +0 -4
- package/cjs/core/AvatarGroup/AvatarGroup.js +1 -5
- package/cjs/core/AvatarGroup/index.d.ts +1 -1
- package/cjs/core/AvatarGroup/index.js +1 -2
- package/cjs/core/FileUpload/FileUpload.d.ts +3 -4
- package/cjs/core/FileUpload/FileUpload.js +2 -2
- package/cjs/core/FileUpload/FileUploadTemplate.d.ts +1 -0
- package/cjs/core/FileUpload/FileUploadTemplate.js +1 -0
- package/cjs/core/Header/Header.d.ts +1 -20
- package/cjs/core/Header/Header.js +1 -2
- package/cjs/core/ProgressIndicators/ProgressRadial/ProgressRadial.d.ts +2 -2
- package/cjs/core/ProgressIndicators/ProgressRadial/ProgressRadial.js +10 -17
- package/cjs/core/Slider/Slider.d.ts +2 -1
- package/cjs/core/Slider/Thumb.d.ts +2 -2
- package/cjs/core/Slider/Thumb.js +1 -1
- package/cjs/core/Stepper/index.d.ts +0 -4
- package/cjs/core/Stepper/index.js +1 -4
- package/cjs/core/Tabs/Tabs.d.ts +0 -36
- package/cjs/core/Tabs/Tabs.js +1 -29
- package/cjs/core/Tabs/index.d.ts +1 -1
- package/cjs/core/Tabs/index.js +1 -3
- package/cjs/core/ThemeProvider/ThemeProvider.js +5 -2
- package/cjs/core/Tile/Tile.d.ts +157 -99
- package/cjs/core/Tile/Tile.js +273 -99
- package/cjs/core/Toast/Toast.d.ts +5 -10
- package/cjs/core/Toast/Toast.js +15 -13
- package/cjs/core/Toast/Toaster.d.ts +24 -26
- package/cjs/core/Toast/Toaster.js +91 -116
- package/cjs/core/Toast/index.d.ts +1 -4
- package/cjs/core/Toast/index.js +3 -6
- package/cjs/core/Tooltip/Tooltip.d.ts +67 -7
- package/cjs/core/Tooltip/Tooltip.js +96 -7
- package/cjs/core/index.d.ts +6 -7
- package/cjs/core/index.js +4 -12
- package/cjs/core/utils/components/Popover.d.ts +1 -1
- package/cjs/core/utils/functions/dom.d.ts +0 -8
- package/cjs/core/utils/functions/dom.js +1 -24
- package/cjs/core/utils/functions/polymorphic.d.ts +1 -1
- package/cjs/styles.js +1 -5
- package/esm/core/Alert/Alert.d.ts +2 -2
- package/esm/core/Avatar/Avatar.d.ts +0 -4
- package/esm/core/Avatar/Avatar.js +0 -4
- package/esm/core/Avatar/index.d.ts +1 -1
- package/esm/core/Avatar/index.js +1 -1
- package/esm/core/AvatarGroup/AvatarGroup.d.ts +0 -4
- package/esm/core/AvatarGroup/AvatarGroup.js +0 -4
- package/esm/core/AvatarGroup/index.d.ts +1 -1
- package/esm/core/AvatarGroup/index.js +1 -1
- package/esm/core/FileUpload/FileUpload.d.ts +3 -4
- package/esm/core/FileUpload/FileUpload.js +2 -2
- package/esm/core/FileUpload/FileUploadTemplate.d.ts +1 -0
- package/esm/core/FileUpload/FileUploadTemplate.js +1 -0
- package/esm/core/Header/Header.d.ts +1 -20
- package/esm/core/Header/Header.js +1 -2
- package/esm/core/ProgressIndicators/ProgressRadial/ProgressRadial.d.ts +2 -2
- package/esm/core/ProgressIndicators/ProgressRadial/ProgressRadial.js +11 -18
- package/esm/core/Slider/Slider.d.ts +2 -1
- package/esm/core/Slider/Thumb.d.ts +2 -2
- package/esm/core/Slider/Thumb.js +1 -1
- package/esm/core/Stepper/index.d.ts +0 -4
- package/esm/core/Stepper/index.js +0 -2
- package/esm/core/Tabs/Tabs.d.ts +0 -36
- package/esm/core/Tabs/Tabs.js +0 -26
- package/esm/core/Tabs/index.d.ts +1 -1
- package/esm/core/Tabs/index.js +1 -1
- package/esm/core/ThemeProvider/ThemeProvider.js +5 -2
- package/esm/core/Tile/Tile.d.ts +157 -99
- package/esm/core/Tile/Tile.js +273 -99
- package/esm/core/Toast/Toast.d.ts +5 -10
- package/esm/core/Toast/Toast.js +16 -14
- package/esm/core/Toast/Toaster.d.ts +24 -26
- package/esm/core/Toast/Toaster.js +85 -116
- package/esm/core/Toast/index.d.ts +1 -4
- package/esm/core/Toast/index.js +1 -3
- package/esm/core/Tooltip/Tooltip.d.ts +67 -7
- package/esm/core/Tooltip/Tooltip.js +97 -7
- package/esm/core/index.d.ts +6 -7
- package/esm/core/index.js +5 -5
- package/esm/core/utils/components/Popover.d.ts +1 -1
- package/esm/core/utils/functions/dom.d.ts +0 -8
- package/esm/core/utils/functions/dom.js +0 -19
- package/esm/core/utils/functions/polymorphic.d.ts +1 -1
- package/esm/styles.js +1 -5
- package/package.json +4 -3
- package/styles.css +55 -52
- package/cjs/core/Stepper/Wizard.d.ts +0 -46
- package/cjs/core/Stepper/Wizard.js +0 -55
- package/cjs/core/Toast/ToastWrapper.d.ts +0 -10
- package/cjs/core/Toast/ToastWrapper.js +0 -49
- package/esm/core/Stepper/Wizard.d.ts +0 -46
- package/esm/core/Stepper/Wizard.js +0 -29
- package/esm/core/Toast/ToastWrapper.d.ts +0 -10
- package/esm/core/Toast/ToastWrapper.js +0 -20
|
@@ -22,10 +22,9 @@ export declare type ToastProps = {
|
|
|
22
22
|
*/
|
|
23
23
|
type?: 'persisting' | 'temporary';
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
26
|
-
* When false, will close the Toast and call onRemove when finished closing.
|
|
25
|
+
* Controlled boolean prop indicating whether the toast is visible.
|
|
27
26
|
*/
|
|
28
|
-
isVisible
|
|
27
|
+
isVisible?: boolean;
|
|
29
28
|
/**
|
|
30
29
|
* Duration of the toast in millisecond.
|
|
31
30
|
* @default 7000
|
|
@@ -37,12 +36,12 @@ export declare type ToastProps = {
|
|
|
37
36
|
*/
|
|
38
37
|
hasCloseButton?: boolean;
|
|
39
38
|
/**
|
|
40
|
-
*
|
|
39
|
+
* Props for a button/link that can be used to perform an action
|
|
40
|
+
* (e.g. to show additional information).
|
|
41
41
|
*/
|
|
42
42
|
link?: {
|
|
43
|
-
onClick: () => void;
|
|
44
43
|
title: string;
|
|
45
|
-
}
|
|
44
|
+
} & Omit<React.ComponentPropsWithoutRef<'button'>, 'children'>;
|
|
46
45
|
/**
|
|
47
46
|
* Function called when the toast is all the way closed.
|
|
48
47
|
*/
|
|
@@ -51,10 +50,6 @@ export declare type ToastProps = {
|
|
|
51
50
|
* Element to which the toast will animate out to.
|
|
52
51
|
*/
|
|
53
52
|
animateOutTo?: HTMLElement | null;
|
|
54
|
-
/**
|
|
55
|
-
* Parent toaster placement position for smoother animation.
|
|
56
|
-
*/
|
|
57
|
-
placementPosition?: 'top' | 'bottom';
|
|
58
53
|
};
|
|
59
54
|
/**
|
|
60
55
|
* Generic Toast Component
|
package/esm/core/Toast/Toast.js
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import { Transition } from 'react-transition-group';
|
|
7
7
|
import cx from 'classnames';
|
|
8
|
-
import { getWindow, StatusIconMap, SvgCloseSmall, Box, } from '../utils/index.js';
|
|
8
|
+
import { getWindow, StatusIconMap, SvgCloseSmall, Box, useSafeContext, } from '../utils/index.js';
|
|
9
9
|
import { IconButton } from '../Buttons/index.js';
|
|
10
|
+
import { ToasterStateContext } from './Toaster.js';
|
|
10
11
|
const isMotionOk = () => getWindow()?.matchMedia?.('(prefers-reduced-motion: no-preference)')?.matches;
|
|
11
12
|
/**
|
|
12
13
|
* Generic Toast Component
|
|
@@ -17,9 +18,12 @@ const isMotionOk = () => getWindow()?.matchMedia?.('(prefers-reduced-motion: no-
|
|
|
17
18
|
* <Toast type='persisting' content='Job processing error.' category='negative' />
|
|
18
19
|
*/
|
|
19
20
|
export const Toast = (props) => {
|
|
20
|
-
const { content, category, type = 'temporary', isVisible, link, duration = 7000, hasCloseButton, onRemove, animateOutTo,
|
|
21
|
+
const { content, category, type = 'temporary', isVisible: isVisibleProp, link, duration = 7000, hasCloseButton, onRemove, animateOutTo, } = props;
|
|
21
22
|
const closeTimeout = React.useRef(0);
|
|
22
|
-
const
|
|
23
|
+
const { placement } = useSafeContext(ToasterStateContext).settings;
|
|
24
|
+
const placementPosition = placement.startsWith('top') ? 'top' : 'bottom';
|
|
25
|
+
const [visible, setVisible] = React.useState(isVisibleProp ?? true);
|
|
26
|
+
const isVisible = isVisibleProp ?? visible;
|
|
23
27
|
const [height, setHeight] = React.useState(0);
|
|
24
28
|
const thisElement = React.useRef(null);
|
|
25
29
|
const [margin, setMargin] = React.useState(0);
|
|
@@ -38,9 +42,6 @@ export const Toast = (props) => {
|
|
|
38
42
|
};
|
|
39
43
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
40
44
|
}, [duration, type]);
|
|
41
|
-
React.useEffect(() => {
|
|
42
|
-
setVisible(isVisible);
|
|
43
|
-
}, [isVisible]);
|
|
44
45
|
React.useEffect(() => {
|
|
45
46
|
// if we don't have animateOutTo point and not isVisible, set negative margin to move other toasts up.
|
|
46
47
|
// Close all and close on toasts with no anchor.
|
|
@@ -84,7 +85,7 @@ export const Toast = (props) => {
|
|
|
84
85
|
}
|
|
85
86
|
return { translateX, translateY };
|
|
86
87
|
};
|
|
87
|
-
return (React.createElement(Transition, { timeout: { enter: 240, exit: animateOutTo ? 400 : 120 }, in:
|
|
88
|
+
return (React.createElement(Transition, { timeout: { enter: 240, exit: animateOutTo ? 400 : 120 }, in: isVisible, appear: true, unmountOnExit: true, onEnter: (node) => {
|
|
88
89
|
if (isMotionOk()) {
|
|
89
90
|
node.style.transform = 'translateY(15%)';
|
|
90
91
|
node.style.transitionTimingFunction = 'ease';
|
|
@@ -103,12 +104,13 @@ export const Toast = (props) => {
|
|
|
103
104
|
node.style.transitionDuration = animateOutTo ? '400ms' : '120ms';
|
|
104
105
|
node.style.transitionTimingFunction = 'cubic-bezier(0.4, 0, 1, 1)';
|
|
105
106
|
}
|
|
106
|
-
}, onExited: onRemove },
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
React.createElement(
|
|
107
|
+
}, onExited: onRemove },
|
|
108
|
+
React.createElement(Box, { ref: thisElement, className: 'iui-toast-all', style: {
|
|
109
|
+
height,
|
|
110
|
+
...marginStyle(),
|
|
111
|
+
} },
|
|
112
|
+
React.createElement("div", { ref: onRef },
|
|
113
|
+
React.createElement(ToastPresentation, { category: category, content: content, link: link, type: type, hasCloseButton: hasCloseButton, onClose: close })))));
|
|
112
114
|
};
|
|
113
115
|
/**
|
|
114
116
|
* The presentational part of a toast, without any animation or logic.
|
|
@@ -120,7 +122,7 @@ export const ToastPresentation = (props) => {
|
|
|
120
122
|
return (React.createElement(Box, { className: cx(`iui-toast iui-${category}`, className), ...rest },
|
|
121
123
|
React.createElement(Box, { className: 'iui-status-area' }, React.createElement(StatusIcon, { className: 'iui-icon' })),
|
|
122
124
|
React.createElement(Box, { className: 'iui-message' }, content),
|
|
123
|
-
link && (React.createElement(Box, { as: '
|
|
125
|
+
link && (React.createElement(Box, { as: 'button', className: 'iui-toast-anchor', ...link, title: undefined }, link.title)),
|
|
124
126
|
(type === 'persisting' || hasCloseButton) && (React.createElement(IconButton, { size: 'small', styleType: 'borderless', onClick: onClose, "aria-label": 'Close' },
|
|
125
127
|
React.createElement(SvgCloseSmall, null)))));
|
|
126
128
|
};
|
|
@@ -4,45 +4,43 @@ export declare type ToasterSettings = {
|
|
|
4
4
|
/**
|
|
5
5
|
* Order of toasts.
|
|
6
6
|
* When set to 'descending', most recent toasts are on top. When set to 'ascending', most recent toasts are on bottom.
|
|
7
|
-
|
|
8
|
-
* When `placement` is set to a top value,
|
|
7
|
+
*
|
|
8
|
+
* When set to `auto`, it will behave like 'descending' when `placement` is set to a top value, otherwise 'ascending'.
|
|
9
|
+
*
|
|
10
|
+
* @default 'auto'
|
|
9
11
|
*/
|
|
10
|
-
order
|
|
12
|
+
order: 'descending' | 'ascending' | 'auto';
|
|
11
13
|
/**
|
|
12
14
|
* Placement of toasts.
|
|
13
15
|
* Changes placement of toasts. Start indicates left side of viewport. End - right side of viewport.
|
|
14
16
|
* @default 'top'
|
|
15
17
|
*/
|
|
16
|
-
placement
|
|
18
|
+
placement: 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end';
|
|
17
19
|
};
|
|
18
20
|
export declare type ToastOptions = Omit<ToastProps, 'category' | 'isVisible' | 'id' | 'content'>;
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
private lastId;
|
|
22
|
-
private settings;
|
|
23
|
-
private toastsRef;
|
|
24
|
-
private isInitialized;
|
|
25
|
-
private asyncInit;
|
|
26
|
-
/**
|
|
27
|
-
* Set global Toaster settings for toasts order and placement.
|
|
28
|
-
* Settings will be applied to new toasts on the page.
|
|
29
|
-
*/
|
|
30
|
-
setSettings(newSettings: ToasterSettings): void;
|
|
31
|
-
positive(content: React.ReactNode, options?: ToastOptions): {
|
|
21
|
+
export declare const useToaster: () => {
|
|
22
|
+
positive: (content: React.ReactNode, options?: ToastOptions) => {
|
|
32
23
|
close: () => void;
|
|
33
24
|
};
|
|
34
|
-
informational(content: React.ReactNode, options?: ToastOptions)
|
|
25
|
+
informational: (content: React.ReactNode, options?: ToastOptions) => {
|
|
35
26
|
close: () => void;
|
|
36
27
|
};
|
|
37
|
-
negative(content: React.ReactNode, options?: ToastOptions)
|
|
28
|
+
negative: (content: React.ReactNode, options?: ToastOptions) => {
|
|
38
29
|
close: () => void;
|
|
39
30
|
};
|
|
40
|
-
warning(content: React.ReactNode, options?: ToastOptions)
|
|
31
|
+
warning: (content: React.ReactNode, options?: ToastOptions) => {
|
|
41
32
|
close: () => void;
|
|
42
33
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
closeAll: () => void;
|
|
35
|
+
setSettings: (settings: Partial<ToasterSettings>) => void;
|
|
36
|
+
};
|
|
37
|
+
export declare const Toaster: () => JSX.Element;
|
|
38
|
+
export declare const ToastProvider: ({ children }: {
|
|
39
|
+
children: React.ReactNode;
|
|
40
|
+
}) => JSX.Element;
|
|
41
|
+
export declare const ToasterStateContext: React.Context<ToasterState | undefined>;
|
|
42
|
+
declare type ToasterState = {
|
|
43
|
+
toasts: ToastProps[];
|
|
44
|
+
settings: ToasterSettings;
|
|
45
|
+
};
|
|
46
|
+
export {};
|
|
@@ -3,125 +3,94 @@
|
|
|
3
3
|
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import * as React from 'react';
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
import cx from 'classnames';
|
|
7
|
+
import { Box, useSafeContext } from '../utils/index.js';
|
|
8
|
+
import { Toast } from './Toast.js';
|
|
9
|
+
// ----------------------------------------------------------------------------
|
|
10
|
+
export const useToaster = () => {
|
|
11
|
+
const dispatch = useSafeContext(ToasterDispatchContext);
|
|
12
|
+
const showToast = React.useCallback((category) => (content, options) => {
|
|
13
|
+
const id = nextId();
|
|
14
|
+
dispatch({
|
|
15
|
+
type: 'add',
|
|
16
|
+
toast: { ...options, id, content, category },
|
|
17
|
+
});
|
|
18
|
+
return { close: () => dispatch({ type: 'remove', id }) };
|
|
19
|
+
}, [dispatch]);
|
|
20
|
+
return {
|
|
21
|
+
positive: showToast('positive'),
|
|
22
|
+
informational: showToast('informational'),
|
|
23
|
+
negative: showToast('negative'),
|
|
24
|
+
warning: showToast('warning'),
|
|
25
|
+
closeAll: () => {
|
|
26
|
+
dispatch({ type: 'close-all' });
|
|
27
|
+
},
|
|
28
|
+
setSettings: (settings) => {
|
|
29
|
+
dispatch({ type: 'settings', settings });
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
// ----------------------------------------------------------------------------
|
|
34
|
+
export const Toaster = () => {
|
|
35
|
+
const { toasts, settings } = useSafeContext(ToasterStateContext);
|
|
36
|
+
return (React.createElement(Box, { className: cx(`iui-toast-wrapper`, `iui-placement-${settings.placement}`) }, toasts.map((toastProps) => {
|
|
37
|
+
return React.createElement(Toast, { key: toastProps.id, ...toastProps });
|
|
38
|
+
})));
|
|
39
|
+
};
|
|
40
|
+
// ----------------------------------------------------------------------------
|
|
41
|
+
export const ToastProvider = ({ children }) => {
|
|
42
|
+
const [toasterState, dispatch] = React.useReducer(toastReducer, {
|
|
43
|
+
toasts: [],
|
|
44
|
+
settings: {
|
|
45
|
+
order: 'auto',
|
|
16
46
|
placement: 'top',
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
return (React.createElement(ToasterDispatchContext.Provider, { value: dispatch },
|
|
50
|
+
React.createElement(ToasterStateContext.Provider, { value: toasterState }, children)));
|
|
51
|
+
};
|
|
52
|
+
const toastReducer = (state, action) => {
|
|
53
|
+
if (action.type === 'add') {
|
|
54
|
+
let order = state.settings.order;
|
|
55
|
+
if (order === 'auto') {
|
|
56
|
+
order = state.settings.placement.startsWith('top')
|
|
57
|
+
? 'descending'
|
|
58
|
+
: 'ascending';
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
...state,
|
|
62
|
+
toasts: [
|
|
63
|
+
...(order === 'ascending' ? state.toasts : []),
|
|
64
|
+
action.toast,
|
|
65
|
+
...(order === 'descending' ? state.toasts : []),
|
|
66
|
+
],
|
|
17
67
|
};
|
|
18
|
-
this.toastsRef = React.createRef();
|
|
19
|
-
this.isInitialized = false;
|
|
20
|
-
// Create container on demand.
|
|
21
|
-
// Cannot do it in constructor, because SSG/SSR apps would fail.
|
|
22
|
-
this.asyncInit = async () => {
|
|
23
|
-
if (this.isInitialized) {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
const container = getContainer(TOASTS_CONTAINER_ID) ?? getDocument()?.body;
|
|
27
|
-
if (!container) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
this.isInitialized = true;
|
|
31
|
-
const toastWrapper = React.createElement(ToastWrapper, { ref: this.toastsRef });
|
|
32
|
-
const _ReactDOM = ReactDOM; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
33
|
-
// v18 mode
|
|
34
|
-
if (_ReactDOM.createRoot) {
|
|
35
|
-
const _ReactDOMInternals = _ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
|
36
|
-
// suppress warning about importing createRoot from react-dom/client
|
|
37
|
-
if (_ReactDOMInternals) {
|
|
38
|
-
_ReactDOMInternals.usingClientEntryPoint = true;
|
|
39
|
-
}
|
|
40
|
-
const root = _ReactDOM.createRoot(container);
|
|
41
|
-
root.render(toastWrapper);
|
|
42
|
-
// revert suppression, not to influence users app
|
|
43
|
-
if (_ReactDOMInternals) {
|
|
44
|
-
_ReactDOMInternals.usingClientEntryPoint = false;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
// v17 and before
|
|
49
|
-
ReactDOM.render(toastWrapper, container);
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Set global Toaster settings for toasts order and placement.
|
|
55
|
-
* Settings will be applied to new toasts on the page.
|
|
56
|
-
*/
|
|
57
|
-
setSettings(newSettings) {
|
|
58
|
-
newSettings.placement ?? (newSettings.placement = this.settings.placement);
|
|
59
|
-
newSettings.order ?? (newSettings.order = newSettings.placement?.startsWith('bottom')
|
|
60
|
-
? 'ascending'
|
|
61
|
-
: 'descending');
|
|
62
|
-
this.settings = newSettings;
|
|
63
|
-
this.asyncInit().then(() => {
|
|
64
|
-
this.toastsRef.current?.setPlacement(this.settings.placement ?? 'top');
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
positive(content, options) {
|
|
68
|
-
return this.createToast(content, 'positive', options);
|
|
69
|
-
}
|
|
70
|
-
informational(content, options) {
|
|
71
|
-
return this.createToast(content, 'informational', options);
|
|
72
|
-
}
|
|
73
|
-
negative(content, options) {
|
|
74
|
-
return this.createToast(content, 'negative', options);
|
|
75
|
-
}
|
|
76
|
-
warning(content, options) {
|
|
77
|
-
return this.createToast(content, 'warning', options);
|
|
78
68
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
{
|
|
85
|
-
...options,
|
|
86
|
-
content,
|
|
87
|
-
category,
|
|
88
|
-
onRemove: () => {
|
|
89
|
-
this.removeToast(currentId);
|
|
90
|
-
options?.onRemove?.();
|
|
91
|
-
},
|
|
92
|
-
id: currentId,
|
|
93
|
-
isVisible: true,
|
|
94
|
-
},
|
|
95
|
-
...(this.settings.order === 'descending' ? this.toasts : []),
|
|
96
|
-
];
|
|
97
|
-
this.updateView();
|
|
98
|
-
return { close: () => this.closeToast(currentId) };
|
|
99
|
-
}
|
|
100
|
-
removeToast(id) {
|
|
101
|
-
this.toasts = this.toasts.filter((toast) => toast.id !== id);
|
|
102
|
-
this.updateView();
|
|
103
|
-
}
|
|
104
|
-
updateView() {
|
|
105
|
-
this.asyncInit().then(() => {
|
|
106
|
-
this.toastsRef.current?.setToasts(this.toasts);
|
|
107
|
-
});
|
|
69
|
+
if (action.type === 'remove') {
|
|
70
|
+
return {
|
|
71
|
+
...state,
|
|
72
|
+
toasts: state.toasts.filter((toast) => toast.id !== action.id),
|
|
73
|
+
};
|
|
108
74
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
};
|
|
115
|
-
});
|
|
116
|
-
this.updateView();
|
|
75
|
+
if (action.type === 'close-all') {
|
|
76
|
+
return {
|
|
77
|
+
...state,
|
|
78
|
+
toasts: state.toasts.map((toast) => ({ ...toast, isVisible: false })),
|
|
79
|
+
};
|
|
117
80
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
...toast,
|
|
122
|
-
isVisible: false,
|
|
123
|
-
};
|
|
124
|
-
});
|
|
125
|
-
this.updateView();
|
|
81
|
+
if (action.type === 'settings') {
|
|
82
|
+
return { ...state, settings: { ...state.settings, ...action.settings } };
|
|
126
83
|
}
|
|
127
|
-
|
|
84
|
+
return state;
|
|
85
|
+
};
|
|
86
|
+
// ----------------------------------------------------------------------------
|
|
87
|
+
export const ToasterStateContext = React.createContext(undefined);
|
|
88
|
+
ToasterStateContext.displayName = 'ToasterStateContext';
|
|
89
|
+
// ----------------------------------------------------------------------------
|
|
90
|
+
const ToasterDispatchContext = React.createContext(undefined);
|
|
91
|
+
ToasterDispatchContext.displayName = 'ToasterDispatchContext';
|
|
92
|
+
// ----------------------------------------------------------------------------
|
|
93
|
+
const nextId = (() => {
|
|
94
|
+
let count = 0;
|
|
95
|
+
return () => ++count;
|
|
96
|
+
})();
|
package/esm/core/Toast/index.js
CHANGED
|
@@ -2,6 +2,4 @@
|
|
|
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
|
-
|
|
6
|
-
const toaster = new Toaster();
|
|
7
|
-
export default toaster;
|
|
5
|
+
export { useToaster } from './Toaster.js';
|
|
@@ -1,6 +1,49 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
2
|
+
import type { Placement } from '@floating-ui/react';
|
|
3
|
+
import type { PolymorphicForwardRefComponent } from '../utils/index.js';
|
|
4
|
+
declare type TooltipOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* Placement of the Tooltip
|
|
7
|
+
* @default 'top'
|
|
8
|
+
*/
|
|
9
|
+
placement?: Placement;
|
|
10
|
+
/**
|
|
11
|
+
* Property for manual visibility control
|
|
12
|
+
*/
|
|
13
|
+
visible?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* autoUpdate options that recalculates position
|
|
16
|
+
* to ensure the floating element remains anchored
|
|
17
|
+
* to its reference element, such as when scrolling
|
|
18
|
+
* and resizing the screen
|
|
19
|
+
*
|
|
20
|
+
* https://floating-ui.com/docs/autoUpdate#options
|
|
21
|
+
*/
|
|
22
|
+
autoUpdateOptions?: {
|
|
23
|
+
ancestorScroll?: boolean;
|
|
24
|
+
ancestorResize?: boolean;
|
|
25
|
+
elementResize?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Use this if you want Tooltip to follow moving trigger element
|
|
28
|
+
*/
|
|
29
|
+
animationFrame?: boolean;
|
|
30
|
+
layoutShift?: boolean;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Tooltip middleware options.
|
|
34
|
+
* https://floating-ui.com/docs/offset
|
|
35
|
+
*/
|
|
36
|
+
middleware?: {
|
|
37
|
+
offset?: number;
|
|
38
|
+
flip?: boolean;
|
|
39
|
+
shift?: boolean;
|
|
40
|
+
size?: boolean;
|
|
41
|
+
autoPlacement?: boolean;
|
|
42
|
+
hide?: boolean;
|
|
43
|
+
inline?: boolean;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
declare type TooltipOwnProps = {
|
|
4
47
|
/**
|
|
5
48
|
* Content of the tooltip.
|
|
6
49
|
*/
|
|
@@ -9,18 +52,35 @@ export declare type TooltipProps = {
|
|
|
9
52
|
* Element to have tooltip on. Has to be a valid JSX element and needs to forward its ref.
|
|
10
53
|
* If not specified, the `reference` prop should be used instead.
|
|
11
54
|
*/
|
|
12
|
-
children?:
|
|
13
|
-
|
|
55
|
+
children?: React.ReactNode;
|
|
56
|
+
/**
|
|
57
|
+
* Element to portal tooltip to.
|
|
58
|
+
* Portals to ThemeProvider portalContainerRef by default.
|
|
59
|
+
* @default true;
|
|
60
|
+
*/
|
|
61
|
+
portal?: boolean | {
|
|
62
|
+
to: HTMLElement;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Sets reference point to user provided element.
|
|
66
|
+
* @example
|
|
67
|
+
* const buttonRef = React.useRef();
|
|
68
|
+
* ...
|
|
69
|
+
* <Button ref={buttonRef} />
|
|
70
|
+
* <Tooltip content='tooltip text' reference={buttonRef} />
|
|
71
|
+
*/
|
|
72
|
+
reference?: React.RefObject<HTMLElement>;
|
|
73
|
+
};
|
|
14
74
|
/**
|
|
15
75
|
* Basic tooltip component to display informative content when an element is hovered or focused.
|
|
16
|
-
* Uses
|
|
76
|
+
* Uses [FloatingUI](https://floating-ui.com/).
|
|
17
77
|
* @example
|
|
18
|
-
* <Tooltip content='tooltip text' placement='top'
|
|
78
|
+
* <Tooltip content='tooltip text' placement='top'>Hover here</Tooltip>
|
|
19
79
|
* @example
|
|
20
80
|
* const buttonRef = React.useRef();
|
|
21
81
|
* ...
|
|
22
82
|
* <Button ref={buttonRef} />
|
|
23
83
|
* <Tooltip content='tooltip text' reference={buttonRef} />
|
|
24
84
|
*/
|
|
25
|
-
export declare const Tooltip:
|
|
85
|
+
export declare const Tooltip: PolymorphicForwardRefComponent<"div", TooltipOwnProps & TooltipOptions>;
|
|
26
86
|
export default Tooltip;
|
|
@@ -4,20 +4,110 @@
|
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import cx from 'classnames';
|
|
7
|
-
import {
|
|
7
|
+
import { useFloating, autoUpdate, offset, flip, shift, useClick, useHover, useFocus, useDismiss, useRole, useInteractions, safePolygon, size, autoPlacement, hide, inline, } from '@floating-ui/react';
|
|
8
|
+
import { Box, getDocument, mergeRefs, useGlobals, useMergedRefs, } from '../utils/index.js';
|
|
9
|
+
import ReactDOM from 'react-dom';
|
|
10
|
+
const useTooltip = (options = {}) => {
|
|
11
|
+
const { placement, visible: controlledOpen, middleware = {
|
|
12
|
+
flip: true,
|
|
13
|
+
shift: true,
|
|
14
|
+
}, autoUpdateOptions = {}, } = options;
|
|
15
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);
|
|
16
|
+
const open = controlledOpen ?? uncontrolledOpen;
|
|
17
|
+
const data = useFloating({
|
|
18
|
+
placement,
|
|
19
|
+
open,
|
|
20
|
+
onOpenChange: setUncontrolledOpen,
|
|
21
|
+
whileElementsMounted: (referenceEl, floatingEl, update) => autoUpdate(referenceEl, floatingEl, update, {
|
|
22
|
+
animationFrame: autoUpdateOptions.animationFrame,
|
|
23
|
+
ancestorScroll: autoUpdateOptions.ancestorScroll,
|
|
24
|
+
ancestorResize: autoUpdateOptions.ancestorResize,
|
|
25
|
+
elementResize: autoUpdateOptions.elementResize,
|
|
26
|
+
layoutShift: autoUpdateOptions.layoutShift,
|
|
27
|
+
}),
|
|
28
|
+
middleware: [
|
|
29
|
+
middleware.offset !== undefined ? offset(middleware.offset) : offset(4),
|
|
30
|
+
middleware.flip && flip(),
|
|
31
|
+
middleware.shift && shift(),
|
|
32
|
+
middleware.size && size(),
|
|
33
|
+
middleware.autoPlacement && autoPlacement(),
|
|
34
|
+
middleware.inline && inline(),
|
|
35
|
+
middleware.hide && hide(),
|
|
36
|
+
].filter(Boolean),
|
|
37
|
+
});
|
|
38
|
+
const context = data.context;
|
|
39
|
+
const hover = useHover(context, {
|
|
40
|
+
enabled: controlledOpen == null,
|
|
41
|
+
delay: {
|
|
42
|
+
open: 50,
|
|
43
|
+
close: 250,
|
|
44
|
+
},
|
|
45
|
+
handleClose: safePolygon({ buffer: -Infinity }),
|
|
46
|
+
});
|
|
47
|
+
const focus = useFocus(context, {
|
|
48
|
+
enabled: controlledOpen == null,
|
|
49
|
+
});
|
|
50
|
+
const click = useClick(context, {
|
|
51
|
+
enabled: controlledOpen == null,
|
|
52
|
+
});
|
|
53
|
+
const dismiss = useDismiss(context, {
|
|
54
|
+
enabled: controlledOpen == null,
|
|
55
|
+
});
|
|
56
|
+
const role = useRole(context, { role: 'tooltip' });
|
|
57
|
+
const interactions = useInteractions([click, hover, focus, dismiss, role]);
|
|
58
|
+
return React.useMemo(() => ({
|
|
59
|
+
open,
|
|
60
|
+
setUncontrolledOpen,
|
|
61
|
+
...interactions,
|
|
62
|
+
...data,
|
|
63
|
+
}), [open, interactions, data]);
|
|
64
|
+
};
|
|
8
65
|
/**
|
|
9
66
|
* Basic tooltip component to display informative content when an element is hovered or focused.
|
|
10
|
-
* Uses
|
|
67
|
+
* Uses [FloatingUI](https://floating-ui.com/).
|
|
11
68
|
* @example
|
|
12
|
-
* <Tooltip content='tooltip text' placement='top'
|
|
69
|
+
* <Tooltip content='tooltip text' placement='top'>Hover here</Tooltip>
|
|
13
70
|
* @example
|
|
14
71
|
* const buttonRef = React.useRef();
|
|
15
72
|
* ...
|
|
16
73
|
* <Button ref={buttonRef} />
|
|
17
74
|
* <Tooltip content='tooltip text' reference={buttonRef} />
|
|
18
75
|
*/
|
|
19
|
-
export const Tooltip = (props) => {
|
|
20
|
-
const { content, children,
|
|
21
|
-
|
|
22
|
-
|
|
76
|
+
export const Tooltip = React.forwardRef((props, forwardRef) => {
|
|
77
|
+
const { content, children, portal = true, placement = 'top', autoUpdateOptions, middleware, style, className, visible, reference, ...rest } = props;
|
|
78
|
+
const tooltip = useTooltip({
|
|
79
|
+
placement,
|
|
80
|
+
visible,
|
|
81
|
+
autoUpdateOptions,
|
|
82
|
+
middleware,
|
|
83
|
+
});
|
|
84
|
+
const context = useGlobals();
|
|
85
|
+
React.useEffect(() => {
|
|
86
|
+
if (reference) {
|
|
87
|
+
tooltip.refs.setReference(reference.current);
|
|
88
|
+
}
|
|
89
|
+
}, [reference, tooltip.refs]);
|
|
90
|
+
const portalTo = typeof portal !== 'boolean'
|
|
91
|
+
? portal.to
|
|
92
|
+
: portal
|
|
93
|
+
? context?.portalContainerRef?.current ?? getDocument()?.body
|
|
94
|
+
: null;
|
|
95
|
+
const contentBox = (React.createElement(Box, { className: cx('iui-tooltip', className), ref: useMergedRefs(tooltip.refs.setFloating, forwardRef), style: { ...tooltip.floatingStyles, ...style }, ...tooltip.getFloatingProps(), ...rest }, content));
|
|
96
|
+
const childrenRef = React.isValidElement(children) &&
|
|
97
|
+
mergeRefs(tooltip.refs.setReference,
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
99
|
+
children.ref);
|
|
100
|
+
return (React.createElement(React.Fragment, null,
|
|
101
|
+
React.isValidElement(children)
|
|
102
|
+
? React.cloneElement(children, tooltip.getReferenceProps({
|
|
103
|
+
ref: childrenRef,
|
|
104
|
+
...children.props,
|
|
105
|
+
}))
|
|
106
|
+
: null,
|
|
107
|
+
tooltip.open
|
|
108
|
+
? portalTo
|
|
109
|
+
? ReactDOM.createPortal(contentBox, portalTo)
|
|
110
|
+
: contentBox
|
|
111
|
+
: null));
|
|
112
|
+
});
|
|
23
113
|
export default Tooltip;
|
package/esm/core/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { Alert } from './Alert/index.js';
|
|
2
|
-
export { Avatar
|
|
3
|
-
export { AvatarGroup
|
|
2
|
+
export { Avatar } from './Avatar/index.js';
|
|
3
|
+
export { AvatarGroup } from './AvatarGroup/index.js';
|
|
4
4
|
export { Backdrop } from './Backdrop/index.js';
|
|
5
5
|
export { Badge } from './Badge/index.js';
|
|
6
6
|
export { Breadcrumbs } from './Breadcrumbs/index.js';
|
|
@@ -23,7 +23,7 @@ export type { FooterElement, TitleTranslations } from './Footer/index.js';
|
|
|
23
23
|
export { Header, HeaderBreadcrumbs, HeaderButton, HeaderLogo, } from './Header/index.js';
|
|
24
24
|
export { List, ListItem } from './List/index.js';
|
|
25
25
|
export { TransferList } from './TransferList/index.js';
|
|
26
|
-
export {
|
|
26
|
+
export { Tabs, Tab } from './Tabs/index.js';
|
|
27
27
|
export { InformationPanel, InformationPanelWrapper, InformationPanelHeader, InformationPanelBody, InformationPanelContent, } from './InformationPanel/index.js';
|
|
28
28
|
export { Input } from './Input/index.js';
|
|
29
29
|
export { Label } from './Label/index.js';
|
|
@@ -51,8 +51,7 @@ export { Textarea } from './Textarea/index.js';
|
|
|
51
51
|
export { Tile } from './Tile/index.js';
|
|
52
52
|
export { TimePicker } from './TimePicker/index.js';
|
|
53
53
|
export type { MeridiemType } from './TimePicker/index.js';
|
|
54
|
-
export {
|
|
55
|
-
export type { ToastOptions } from './Toast/index.js';
|
|
54
|
+
export { useToaster } from './Toast/index.js';
|
|
56
55
|
export { ThemeProvider } from './ThemeProvider/index.js';
|
|
57
56
|
export type { ThemeType } from './ThemeProvider/index.js';
|
|
58
57
|
export { ToggleSwitch } from './ToggleSwitch/index.js';
|
|
@@ -60,7 +59,7 @@ export { Tooltip } from './Tooltip/index.js';
|
|
|
60
59
|
export { Tree, TreeNode, TreeNodeExpander } from './Tree/index.js';
|
|
61
60
|
export type { NodeData, NodeRenderProps } from './Tree/index.js';
|
|
62
61
|
export { Anchor, Blockquote, Code, Kbd, KbdKeys, Text, } from './Typography/index.js';
|
|
63
|
-
export {
|
|
64
|
-
export type { StepProperties,
|
|
62
|
+
export { Stepper, WorkflowDiagram } from './Stepper/index.js';
|
|
63
|
+
export type { StepProperties, StepperLocalization } from './Stepper/index.js';
|
|
65
64
|
export { SearchBox } from './SearchBox/index.js';
|
|
66
65
|
export { getUserColor, ColorValue, MiddleTextTruncation, LinkBox, LinkAction, Icon, Flex, VisuallyHidden, Divider, } from './utils/index.js';
|