@linzjs/lui 21.35.1-0 → 21.36.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 CHANGED
@@ -1,3 +1,10 @@
1
+ # [21.36.0](https://github.com/linz/lui/compare/v21.35.0...v21.36.0) (2024-07-01)
2
+
3
+
4
+ ### Features
5
+
6
+ * **useToast:** merge update & add APIs ([#1128](https://github.com/linz/lui/issues/1128)) ([1cdd7b6](https://github.com/linz/lui/commit/1cdd7b6c9c412d4cbc8d76e042328d4f3242133a))
7
+
1
8
  # [21.35.0](https://github.com/linz/lui/compare/v21.34.0...v21.35.0) (2024-06-26)
2
9
 
3
10
 
@@ -18,11 +18,6 @@ export declare type ToastAction = {
18
18
  } | {
19
19
  type: 'remove';
20
20
  id: number;
21
- } | {
22
- type: 'update';
23
- notification: ToastNode;
24
- options?: ToastOptions;
25
- id: number;
26
21
  };
27
22
  export interface IToast {
28
23
  id: number;
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ export declare const ToastVersion: import("react").Context<"v1" | "v2">;
3
+ export declare const useToastVersion: () => "v1" | "v2";
@@ -1,13 +1,38 @@
1
1
  import { ComponentProps, ReactNode } from 'react';
2
2
  import { LuiToastMessage as LuiToastMessageOld } from '../../LuiToastMessage/LuiToastMessage';
3
- declare type ProviderProps = {
4
- children: ReactNode;
5
- upgrade?: boolean;
3
+ declare type ProviderPropsV1 = {
4
+ /** Use v2 explicitely to get the new designs */
5
+ version?: 'v1';
6
+ /** Default timeout is not permitted in v1 */
7
+ defaultTimeout?: never;
8
+ /** Stack is not permitted in v1 */
9
+ stack?: never;
10
+ };
11
+ declare type ProviderPropsV2 = {
12
+ /** Latest designs */
13
+ version: 'v2';
14
+ /** Default timeout for ephemeral toasts is 4000ms */
15
+ defaultTimeout?: number;
16
+ /** Max number of toast allowed simultaneously. Default value is 5. */
17
+ stack?: number;
6
18
  };
19
+ declare type ProviderProps = {
20
+ children?: ReactNode;
21
+ } & (ProviderPropsV1 | ProviderPropsV2);
7
22
  /**
8
- * @deprecated Use ToastProvider or LuiMessagingContextProvider with upgrade prop set to true to get the new designs
23
+ * Context provider to handle global logic of toast messages. It defaults to legacy version 'v1'.
24
+ * @description Set version property to 'v2' to get the latest designs.
9
25
  */
10
26
  export declare const LuiMessagingContextProvider: (props: ProviderProps) => JSX.Element;
27
+ /**
28
+ * Hook to display pop-up messages in response to a user action or state change. Examples include: Saving, exporting, committing, deleting, etc.
29
+ * @description Legacy hook to trigger toasts. It requires {@linkcode LuiMessagingContextProvider}.
30
+ * @alias useToast. For a more flexible API when you're using v2 designs, using useToast is recommended.
31
+ * @returns Toaster function to trigger branded toasts (e.g. warning, error, info) in the top right of the page.
32
+ * @example
33
+ * const toaster = useShowLUIMessage();
34
+ * toaster({ message: 'Failed to save', messageType: 'toast', messageLevel: 'error' });
35
+ */
11
36
  export declare const useShowLUIMessage: () => (props: import("../../../contexts/LuiMessagingContextProvider").ShowMessageProps) => void;
12
37
  declare type LuiToastMessageProps = ComponentProps<typeof LuiToastMessageOld>;
13
38
  export declare const LuiToastMessage: (props: LuiToastMessageProps) => JSX.Element;
@@ -2,4 +2,4 @@ import { ShowMessageProps } from '../../../contexts/LuiMessagingContextProvider'
2
2
  /**
3
3
  * Provide new toast hook with old interface from original useShowLUIMessage
4
4
  */
5
- export declare const useShowLUIMessageCompatibleInterface: () => (props: ShowMessageProps) => void;
5
+ export declare const useShowLUIMessageCompatibleInterface: () => (props: ShowMessageProps) => number;
@@ -1,10 +1,38 @@
1
1
  import './ToastProvider.scss';
2
2
  import { ReactNode } from 'react';
3
3
  import { ToastNode, ToastOptions } from './Helpers/ToastTypes';
4
- declare type BannerToast = (children: ReactNode, config?: ToastOptions) => number;
5
- declare type Result = {
6
- toast: (notification: ToastNode, options?: ToastOptions) => number;
7
- update: (toastId: number, notification: ToastNode, options?: ToastOptions) => number;
4
+ declare type Config = ToastOptions & {
5
+ id?: number;
6
+ };
7
+ declare type BannerToast = (children: ReactNode, config?: Config) => number;
8
+ /**
9
+ * Hook to display pop-up messages in response to a user action or state change. Examples include: Saving, exporting, committing, deleting, etc.
10
+ * It requires 'LuiMessagingContextProvider' with property version set to 'v2'.
11
+ * Toasts that are `warning` or `error` won't timeout automatically, unless configured otherwise.
12
+ * @description Hook to trigger pop-up messages (a.k.a. toasts). Each toast helper function returns a a toast id `number` that can be used for manual dismiss or updates.
13
+ * @example
14
+ * // Error message
15
+ * const { error } = useToast();
16
+ * error("Failed to save");
17
+ * @example
18
+ * // Toast error and then turn toast into success
19
+ * const { error, success } = useToast();
20
+ * const toastId = error("Failed to save");
21
+ * success('Toast updated to success', { id: toastId });
22
+ * @example
23
+ * // Dismiss info toast that won't dismiss automatically
24
+ * const { info, dismiss } = useToast();
25
+ * const toastId = info(<a href="#">Some useful link</a>, { timeout: Infinity });
26
+ * dismiss(toastId);
27
+ * @example
28
+ * // Custom toasts accept `ReactNode` or `({ close: () => void }) => ReactNode`
29
+ * const { toast } = useToast();
30
+ * toast(({ close }) => <button onClick={() => close()}>Click me to dismiss</button>, { timeout: Infinity });
31
+ * toast(<div>I will be dismissed in 3s.</div>, { timeout: 3000 });
32
+ * toast("I'm placed in the topLeft of the page", { position: 'topLeft' });
33
+ */
34
+ export declare const useToast: () => {
35
+ toast: (notification: ToastNode, config?: Config) => number;
8
36
  dismiss: (toastId: number) => void;
9
37
  info: BannerToast;
10
38
  success: BannerToast;
@@ -12,5 +40,4 @@ declare type Result = {
12
40
  warning: BannerToast;
13
41
  plain: BannerToast;
14
42
  };
15
- export declare const useToast: () => Result;
16
43
  export {};
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * @param onEscape the handler function
6
6
  */
7
- export declare const useEscapeFunction: (onEscape: (e: KeyboardEvent) => void | Promise<void>, trigger?: 'keyup' | 'keydown') => void;
7
+ export declare const useEscapeFunction: (onEscape: () => void) => void;
8
8
  /**
9
9
  * A hook which allows handling of click event anywhere on the page.
10
10
  * Provides a way of handling clicks done inside or outside the element bound to the returned react ref.
@@ -1,4 +1,4 @@
1
- import { MutableRefObject, RefObject } from 'react';
1
+ import React from 'react';
2
2
  /**
3
3
  * This hook will callback with handleClickOutside() when "mousedown" dom event occurs off the refElement
4
4
  * usage:
@@ -11,4 +11,4 @@ import { MutableRefObject, RefObject } from 'react';
11
11
  return <button ref={refElement}>Click Me!</button>;
12
12
  ```
13
13
  */
14
- export declare function useClickedOutsideElement(refElement: RefObject<HTMLElement> | MutableRefObject<HTMLElement>, handleClickOutside: CallableFunction): void;
14
+ export declare function useClickedOutsideElement(refElement: React.RefObject<HTMLElement>, handleClickOutside: CallableFunction): void;
package/dist/index.d.ts CHANGED
@@ -37,8 +37,6 @@ export * from './components/LuiHeaderMenu/LuiHeaderMenus';
37
37
  export * from './components/LuiHeaderMenuV2/LuiHeaderMenusV2';
38
38
  export { LuiUpdatesSplashModal } from './components/LuiUpdateSplashModal/LuiUpdatesSplashModal';
39
39
  export { LuiModal, LuiAlertModal, LuiAlertModalButtons, } from './components/LuiModal/LuiModal';
40
- export { LuiModalV2, type LuiModalV2Props, } from './components/LuiModal/LuiModalV2';
41
- export { LuiAlertModalV2, type LuiAlertModalLevel, type LuiAlertModalV2Props, } from './components/LuiModal/LuiAlertModalV2';
42
40
  export { type ISearchInputProps, LuiSearchInput, } from './components/LuiSearchInput/LuiSearchInput';
43
41
  export { type ISearchGroupedResult, type ISearchResult, } from './components/LuiSearchInput/ResultsDisplay';
44
42
  export { type ISearchMenuOption, type ILuiSearchBoxProps, LuiSearchBox, } from './components/LuiSearchBox/LuiSearchBox';
@@ -74,5 +72,5 @@ export { LuiPagination } from './components/LuiPagination/LuiPagination';
74
72
  export { Splitter } from './components/Splitter/Splitter';
75
73
  export { useSplitterRef } from './components/Splitter/useSplitterRef';
76
74
  export { LuiBannerV2 } from './components/LuiBannerV2/LuiBannerV2';
77
- export { useToast, ToastProvider } from './components/Toast';
75
+ export { useToast } from './components/Toast';
78
76
  export { LuiMessagingContextProvider, useShowLUIMessage, LuiToastMessage, } from './components/Toast/Upgrade';
package/dist/index.js CHANGED
@@ -39830,12 +39830,17 @@ var motif = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0id
39830
39830
  *
39831
39831
  * @param onEscape the handler function
39832
39832
  */
39833
- var useEscapeFunction = function (onEscape, trigger) {
39834
- if (trigger === void 0) { trigger = 'keydown'; }
39835
- var escFunction = React.useCallback(function (event) { return event.key === 'Escape' && onEscape(event); }, [onEscape]);
39833
+ var useEscapeFunction = function (onEscape) {
39834
+ var escFunction = React.useCallback(function (event) {
39835
+ if (event.keyCode === 27) {
39836
+ onEscape();
39837
+ }
39838
+ }, [onEscape]);
39836
39839
  React.useEffect(function () {
39837
- document.addEventListener(trigger, escFunction);
39838
- return function () { return document.removeEventListener(trigger, escFunction); };
39840
+ document.addEventListener('keydown', escFunction, false);
39841
+ return function () {
39842
+ document.removeEventListener('keydown', escFunction, false);
39843
+ };
39839
39844
  }, [escFunction]);
39840
39845
  };
39841
39846
  /**
@@ -42197,119 +42202,6 @@ var LuiModalHeader = function (props) {
42197
42202
  React__default["default"].createElement(LuiIcon, { name: "ic_clear", alt: "Help", size: "lg" }))))))));
42198
42203
  };
42199
42204
 
42200
- /**
42201
- * This hook will callback with handleClickOutside() when "mousedown" dom event occurs off the refElement
42202
- * usage:
42203
- ```typescript
42204
- const refElement = React.useRef<HTMLButtonElement>(null);
42205
- const handleClickOutside = () => {
42206
- console.log("hello world");
42207
- };
42208
- useClickedOutsideElement(refElement, handleClickOutside);
42209
- return <button ref={refElement}>Click Me!</button>;
42210
- ```
42211
- */
42212
- function useClickedOutsideElement(refElement, handleClickOutside) {
42213
- React__default["default"].useEffect(function () {
42214
- function onOutsideClicked(event) {
42215
- var element = refElement.current;
42216
- if (!(element === null || element === void 0 ? void 0 : element.contains(event.target))) {
42217
- handleClickOutside();
42218
- }
42219
- }
42220
- document.addEventListener('mousedown', onOutsideClicked);
42221
- return function () {
42222
- document.removeEventListener('mousedown', onOutsideClicked);
42223
- };
42224
- // eslint-disable-next-line react-hooks/exhaustive-deps
42225
- }, []);
42226
- }
42227
-
42228
- var _a;
42229
- var LuiModalV2 = function (props) {
42230
- var _a;
42231
- var modalRef = React.useRef(null);
42232
- var handleClickOutside = React.useCallback(function () { var _a; return props.shouldCloseOnOverlayClick && ((_a = props.onClose) === null || _a === void 0 ? void 0 : _a.call(props)); }, [props.shouldCloseOnEsc, props.onClose]);
42233
- useClickedOutsideElement(modalRef, handleClickOutside);
42234
- var handleEsc = React.useCallback(function (e) {
42235
- var _a;
42236
- if (props.shouldCloseOnEsc !== false) {
42237
- e.stopPropagation();
42238
- (_a = props.onClose) === null || _a === void 0 ? void 0 : _a.call(props);
42239
- }
42240
- }, [props.shouldCloseOnEsc, props.onClose]);
42241
- useEscapeFunction(handleEsc, props.shouldCloseOnEsc === 'use-keyup' ? 'keyup' : 'keydown');
42242
- var handleAutoFocus = function (el) {
42243
- if (props.preventAutoFocus)
42244
- return;
42245
- if (el && !el.contains(el.ownerDocument.activeElement)) {
42246
- var firstFocusableElement = el.querySelector('input,button');
42247
- firstFocusableElement === null || firstFocusableElement === void 0 ? void 0 : firstFocusableElement.focus();
42248
- }
42249
- };
42250
- var showCloseButton = Boolean(props.showCloseButton && props.onClose);
42251
- var showHelpButton = Boolean(props.helpLink);
42252
- var showButtons = showCloseButton || showHelpButton;
42253
- var showHeadingIcon = props.headingIcon && !props.isLoading;
42254
- return (React__default["default"].createElement(Modal, { key: props.key, isOpen: true,
42255
- // disble the `shouldClose` props as we handle them ourselves
42256
- shouldCloseOnOverlayClick: false, shouldCloseOnEsc: false, overlayClassName: "modal", className: props.lowContrast ? 'lui-scrim-low-contrast' : 'lui-scrim',
42257
- // required to prevent warnings that are not applicable in real usage
42258
- ariaHideApp: !isTest, parentSelector: props.appendToElement },
42259
- React__default["default"].createElement("div", { ref: function (el) {
42260
- modalRef.current = el;
42261
- handleAutoFocus(el);
42262
- }, className: clsx('lui-modal-v2 lui-box-shadow', props.maxWidth && 'lui-max-width', props.className) },
42263
- React__default["default"].createElement("div", { className: "lui-modal-v2-header" },
42264
- props.isLoading && (React__default["default"].createElement(LuiMiniSpinner, { size: 20, divProps: { className: 'lui-modal-v2-header-spinner' } })),
42265
- showHeadingIcon && (React__default["default"].createElement("div", { className: "lui-modal-v2-header-icon" },
42266
- React__default["default"].createElement(LuiIcon, __assign({ size: "md", name: "", alt: "Help" }, props.headingIcon, { className: clsx('', (_a = props.headingIcon) === null || _a === void 0 ? void 0 : _a.className) })))),
42267
- props.headingText && (React__default["default"].createElement("h2", { className: "lui-modal-v2-header-title" }, props.headingText)),
42268
- showButtons && (React__default["default"].createElement("div", { className: "lui-modal-v2-header-buttons" },
42269
- showHelpButton && React__default["default"].createElement(HelpButton, { helpLink: props.helpLink }),
42270
- showCloseButton && React__default["default"].createElement(CloseButton, { onClose: props.onClose })))),
42271
- React__default["default"].createElement("div", { className: "lui-modal-v2-contents" }, props.children))));
42272
- };
42273
- var ButtonRow = function (props) { return (React__default["default"].createElement("div", { className: clsx('lui-modal-v2-btn-row', props.className) }, props.children)); };
42274
- LuiModalV2.Buttons = ButtonRow;
42275
- var HelpButton = function (props) { return (React__default["default"].createElement("button", { "aria-label": "Modal Help", title: "Help", className: "lui-modal-v2-header-help-btn", onClick: typeof props.helpLink === 'string'
42276
- ? function () { return window.open(props.helpLink, '_blank'); }
42277
- : props.helpLink },
42278
- React__default["default"].createElement(LuiIcon, { name: "ic_help_outline", alt: "Help", size: "md" }))); };
42279
- var CloseButton = function (props) { return (React__default["default"].createElement("button", { "aria-label": "Modal Close", title: "Close", className: "lui-modal-v2-header-close-btn", onClick: props.onClose },
42280
- React__default["default"].createElement(LuiIcon, { name: "ic_clear", alt: "Help", size: "md" }))); };
42281
- /** Allows injecting the modal header text. Useful when you can't use the `headingText` prop directly, or when you need to render styled content. */
42282
- var HeaderTitle = function (props) {
42283
- var _a = React.useState(), target = _a[0], setTarget = _a[1];
42284
- // on mount, find the parent modal and set it as the target
42285
- if (!target)
42286
- return (React__default["default"].createElement("div", { style: { display: 'none' }, ref: function (el) {
42287
- var modal = el === null || el === void 0 ? void 0 : el.closest(".lui-modal-v2");
42288
- var modalHeader = modal === null || modal === void 0 ? void 0 : modal.querySelector(':scope > .lui-modal-v2-header');
42289
- modalHeader && setTarget(modalHeader);
42290
- } }));
42291
- return ReactDOM.createPortal(React__default["default"].createElement("h2", { className: clsx('lui-modal-v2-header-title lui-modal-v2-header-title-portal', props.className) }, props.children), target);
42292
- };
42293
- LuiModalV2.HeaderTitle = HeaderTitle;
42294
- // this is here for the tests
42295
- var isTest = typeof process !== 'undefined' && ((_a = process === null || process === void 0 ? void 0 : process.env) === null || _a === void 0 ? void 0 : _a.NODE_ENV) === 'test';
42296
- if (!isTest)
42297
- Modal.setAppElement('#root');
42298
-
42299
- var LuiAlertModalV2 = function (props) {
42300
- var level = props.level, className = props.className, children = props.children, rest = __rest(props, ["level", "className", "children"]);
42301
- var materialIcon = getMaterialIconForLevel(level);
42302
- var status = Object.keys(ICON_STATUS).includes(level)
42303
- ? level
42304
- : 'interactive';
42305
- return (React__default["default"].createElement(LuiModalV2, __assign({}, rest, { className: clsx("lui-modal-v2-alert lui-modal-v2-".concat(level), className), headingIcon: {
42306
- name: "ic_".concat(materialIcon),
42307
- alt: "".concat(level, " status icon"),
42308
- size: 'md',
42309
- status: status
42310
- } }), children));
42311
- };
42312
-
42313
42205
  var css_248z$g = "@keyframes react-loading-skeleton {\n 100% {\n transform: translateX(100%);\n }\n}\n\n.react-loading-skeleton {\n --base-color: #ebebeb;\n --highlight-color: #f5f5f5;\n --animation-duration: 1.5s;\n --animation-direction: normal;\n --pseudo-element-display: block; /* Enable animation */\n\n background-color: var(--base-color);\n\n width: 100%;\n border-radius: 0.25rem;\n display: inline-flex;\n line-height: 1;\n\n position: relative;\n user-select: none;\n overflow: hidden;\n z-index: 1; /* Necessary for overflow: hidden to work correctly in Safari */\n}\n\n.react-loading-skeleton::after {\n content: ' ';\n display: var(--pseudo-element-display);\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 100%;\n background-repeat: no-repeat;\n background-image: linear-gradient(\n 90deg,\n var(--base-color),\n var(--highlight-color),\n var(--base-color)\n );\n transform: translateX(-100%);\n\n animation-name: react-loading-skeleton;\n animation-direction: var(--animation-direction);\n animation-duration: var(--animation-duration);\n animation-timing-function: ease-in-out;\n animation-iteration-count: infinite;\n}\n\n@media (prefers-reduced-motion) {\n .react-loading-skeleton {\n --pseudo-element-display: none; /* Disable animation */\n }\n}\n";
42314
42206
  styleInject(css_248z$g);
42315
42207
 
@@ -46908,6 +46800,34 @@ var LuiTooltip = function (props) {
46908
46800
  return React__default["default"].createElement(Tippy, __assign({}, tippyProps), children);
46909
46801
  };
46910
46802
 
46803
+ /**
46804
+ * This hook will callback with handleClickOutside() when "mousedown" dom event occurs off the refElement
46805
+ * usage:
46806
+ ```typescript
46807
+ const refElement = React.useRef<HTMLButtonElement>(null);
46808
+ const handleClickOutside = () => {
46809
+ console.log("hello world");
46810
+ };
46811
+ useClickedOutsideElement(refElement, handleClickOutside);
46812
+ return <button ref={refElement}>Click Me!</button>;
46813
+ ```
46814
+ */
46815
+ function useClickedOutsideElement(refElement, handleClickOutside) {
46816
+ React__default["default"].useEffect(function () {
46817
+ function onOutsideClicked(event) {
46818
+ var element = refElement.current;
46819
+ if (!(element === null || element === void 0 ? void 0 : element.contains(event.target))) {
46820
+ handleClickOutside();
46821
+ }
46822
+ }
46823
+ document.addEventListener('mousedown', onOutsideClicked);
46824
+ return function () {
46825
+ document.removeEventListener('mousedown', onOutsideClicked);
46826
+ };
46827
+ // eslint-disable-next-line react-hooks/exhaustive-deps
46828
+ }, []);
46829
+ }
46830
+
46911
46831
  var getFillClassName = function (fillVariation, backgroundFill) {
46912
46832
  if (backgroundFill) {
46913
46833
  return 'LuiBadge--fill';
@@ -59490,20 +59410,23 @@ var Toast = function (props) {
59490
59410
  var reducer = function (state, action) {
59491
59411
  var updatedAt = new Date().getTime();
59492
59412
  if (action.type === 'add') {
59493
- var createdAt = updatedAt;
59494
- var notification = action.notification, options = action.options, id = action.id;
59495
- var toast = { notification: notification, options: options, id: id, updatedAt: updatedAt, createdAt: createdAt };
59496
- var toasts = __spreadArray([toast], state.toasts, true);
59497
- return trim(__assign(__assign({}, state), { toasts: toasts }));
59413
+ var notification = action.notification, options = action.options, id_1 = action.id;
59414
+ var base = { notification: notification, options: options, id: id_1, updatedAt: updatedAt };
59415
+ var found = state.toasts.find(function (t) { return t.id === id_1; });
59416
+ if (!found) {
59417
+ var toast = __assign(__assign({}, base), { createdAt: updatedAt });
59418
+ var toasts = __spreadArray([toast], state.toasts, true);
59419
+ return trim(__assign(__assign({}, state), { toasts: toasts }));
59420
+ }
59421
+ else {
59422
+ var toast_1 = __assign(__assign({}, found), base);
59423
+ var toasts = state.toasts.map(function (t) { return (t.id !== id_1 ? t : toast_1); });
59424
+ return __assign(__assign({}, state), { toasts: toasts });
59425
+ }
59498
59426
  }
59499
59427
  if (action.type === 'remove') {
59500
59428
  return __assign(__assign({}, state), { toasts: state.toasts.filter(function (t) { return t.id !== action.id; }) });
59501
59429
  }
59502
- if (action.type === 'update') {
59503
- var notification = action.notification, options = action.options, id_1 = action.id;
59504
- var updated_1 = { notification: notification, options: options, id: id_1, updatedAt: updatedAt };
59505
- return __assign(__assign({}, state), { toasts: state.toasts.map(function (t) { return (t.id !== id_1 ? t : __assign(__assign({}, t), updated_1)); }) });
59506
- }
59507
59430
  return state;
59508
59431
  };
59509
59432
  var useToastState = function (_a) {
@@ -59539,6 +59462,9 @@ var trim = function (state) { return (__assign(__assign({}, state), { toasts: Ob
59539
59462
  })
59540
59463
  .flat() })); };
59541
59464
 
59465
+ var ToastVersion = React.createContext('v1');
59466
+ var useToastVersion = function () { return React.useContext(ToastVersion); };
59467
+
59542
59468
  var ToastContext = React__namespace.createContext(undefined);
59543
59469
  var portal = getToastProviderEl();
59544
59470
  var ToastProvider = function (_a) {
@@ -59548,7 +59474,7 @@ var ToastProvider = function (_a) {
59548
59474
  if (React.useContext(ToastContext)) {
59549
59475
  return React__namespace.createElement(React__namespace.Fragment, null, children);
59550
59476
  }
59551
- return (React__namespace.createElement(React__namespace.Fragment, null,
59477
+ return (React__namespace.createElement(ToastVersion.Provider, { value: "v2" },
59552
59478
  ReactDOM__default["default"].createPortal(React__namespace.createElement(React__namespace.Fragment, null, Object.entries(toasts).map(function (_a) {
59553
59479
  var section = _a[0], list = _a[1];
59554
59480
  return (React__namespace.createElement(ToastSection, __assign({ key: section }, {
@@ -59561,30 +59487,35 @@ var ToastProvider = function (_a) {
59561
59487
  React__namespace.createElement(ToastContext.Provider, { value: dispatch }, children)));
59562
59488
  };
59563
59489
 
59564
- var getUniqueToastId = function () { return Math.floor(Math.random() * 10000); };
59490
+ var getUniqueToastId = function () {
59491
+ var _a;
59492
+ var id = Number("".concat(Math.floor(Math.random() * 10000000)).slice(0, 4));
59493
+ var selector = "[data-toastid=\"".concat(id, "\"]");
59494
+ var duplicate = ((_a = getToastProviderEl().querySelectorAll(selector)) === null || _a === void 0 ? void 0 : _a.length) > 0;
59495
+ if (duplicate) {
59496
+ return getUniqueToastId();
59497
+ }
59498
+ return id;
59499
+ };
59565
59500
  var toastFunctions = function (dispatch) {
59566
- var toast = function (notification, options) {
59567
- var id = getUniqueToastId();
59501
+ var toast = function (notification, config) {
59502
+ if (config === void 0) { config = {}; }
59503
+ var _a = config.id, id = _a === void 0 ? getUniqueToastId() : _a, options = __rest(config, ["id"]);
59568
59504
  dispatch === null || dispatch === void 0 ? void 0 : dispatch({ type: 'add', notification: notification, options: options, id: id });
59569
59505
  return id;
59570
59506
  };
59571
- var update = function (id, notification, options) {
59572
- dispatch === null || dispatch === void 0 ? void 0 : dispatch({ type: 'update', notification: notification, options: options, id: id });
59573
- return id;
59574
- };
59575
59507
  var banner = function (level, defaults) {
59576
59508
  if (defaults === void 0) { defaults = {}; }
59577
59509
  return function (children, options) {
59578
59510
  if (options === void 0) { options = defaults; }
59579
59511
  return toast(function (_a) {
59580
- var close = _a.close;
59581
- return (React__namespace.createElement(LuiBannerV2, __assign({}, { level: level, children: children }, { onDismiss: options.timeout === Infinity ? close : undefined })));
59512
+ var onDismiss = _a.close;
59513
+ return (React__namespace.createElement(LuiBannerV2, __assign({}, { level: level, children: children, onDismiss: onDismiss })));
59582
59514
  }, options);
59583
59515
  };
59584
59516
  };
59585
59517
  return {
59586
59518
  toast: toast,
59587
- update: update,
59588
59519
  dismiss: function (id) { return dispatch === null || dispatch === void 0 ? void 0 : dispatch({ type: 'remove', id: id }); },
59589
59520
  info: banner('info'),
59590
59521
  success: banner('success'),
@@ -59593,6 +59524,32 @@ var toastFunctions = function (dispatch) {
59593
59524
  plain: banner()
59594
59525
  };
59595
59526
  };
59527
+ /**
59528
+ * Hook to display pop-up messages in response to a user action or state change. Examples include: Saving, exporting, committing, deleting, etc.
59529
+ * It requires 'LuiMessagingContextProvider' with property version set to 'v2'.
59530
+ * Toasts that are `warning` or `error` won't timeout automatically, unless configured otherwise.
59531
+ * @description Hook to trigger pop-up messages (a.k.a. toasts). Each toast helper function returns a a toast id `number` that can be used for manual dismiss or updates.
59532
+ * @example
59533
+ * // Error message
59534
+ * const { error } = useToast();
59535
+ * error("Failed to save");
59536
+ * @example
59537
+ * // Toast error and then turn toast into success
59538
+ * const { error, success } = useToast();
59539
+ * const toastId = error("Failed to save");
59540
+ * success('Toast updated to success', { id: toastId });
59541
+ * @example
59542
+ * // Dismiss info toast that won't dismiss automatically
59543
+ * const { info, dismiss } = useToast();
59544
+ * const toastId = info(<a href="#">Some useful link</a>, { timeout: Infinity });
59545
+ * dismiss(toastId);
59546
+ * @example
59547
+ * // Custom toasts accept `ReactNode` or `({ close: () => void }) => ReactNode`
59548
+ * const { toast } = useToast();
59549
+ * toast(({ close }) => <button onClick={() => close()}>Click me to dismiss</button>, { timeout: Infinity });
59550
+ * toast(<div>I will be dismissed in 3s.</div>, { timeout: 3000 });
59551
+ * toast("I'm placed in the topLeft of the page", { position: 'topLeft' });
59552
+ */
59596
59553
  var useToast = function () {
59597
59554
  var dispatch = React.useContext(ToastContext);
59598
59555
  return React.useMemo(function () { return toastFunctions(dispatch); }, [dispatch]);
@@ -59684,7 +59641,7 @@ var LuiToastMessageCompatibleInterface = function (props) {
59684
59641
  var toastIdRef = React.useRef(undefined);
59685
59642
  var onceDismissedRef = React.useRef(false);
59686
59643
  var displayRef = React.useRef(display);
59687
- var _c = useToast(), toast = _c.toast, dismiss = _c.dismiss, update = _c.update;
59644
+ var _c = useToast(), toast = _c.toast, dismiss = _c.dismiss;
59688
59645
  displayRef.current = display;
59689
59646
  // Close when it's unmounted
59690
59647
  React.useEffect(function () {
@@ -59700,23 +59657,18 @@ var LuiToastMessageCompatibleInterface = function (props) {
59700
59657
  if (display && !onceDismissed) {
59701
59658
  var notification = function (_a) {
59702
59659
  var close = _a.close;
59703
- var onDismiss = requireDismiss ? close : undefined;
59704
- return React__default["default"].createElement(LuiBannerV2, __assign({}, { level: level, onDismiss: onDismiss, children: children }));
59660
+ return React__default["default"].createElement(LuiBannerV2, __assign({}, { level: level, onDismiss: close, children: children }));
59705
59661
  };
59706
59662
  var options = {
59707
- timeout: displayTimeout === 0 ? Infinity : displayTimeout,
59663
+ timeout: requireDismiss || !displayTimeout ? Infinity : displayTimeout,
59708
59664
  onLeave: function () {
59709
59665
  onClose === null || onClose === void 0 ? void 0 : onClose();
59710
59666
  onceDismissedRef.current = displayRef.current;
59711
59667
  toastIdRef.current = undefined;
59712
- }
59668
+ },
59669
+ id: toastIdRef.current
59713
59670
  };
59714
- if (!toastIdRef.current) {
59715
- toastIdRef.current = toast(notification, options);
59716
- }
59717
- else {
59718
- update(toastIdRef.current, notification, options);
59719
- }
59671
+ toastIdRef.current = toast(notification, options);
59720
59672
  }
59721
59673
  if (!display && toastIdRef.current !== undefined) {
59722
59674
  dismiss(toastIdRef.current);
@@ -59726,47 +59678,49 @@ var LuiToastMessageCompatibleInterface = function (props) {
59726
59678
  return React__default["default"].createElement(React__default["default"].Fragment, null);
59727
59679
  };
59728
59680
 
59681
+ var getTimeout = function (_a) {
59682
+ var requireDismiss = _a.requireDismiss, messageLevel = _a.messageLevel;
59683
+ return (requireDismiss !== null && requireDismiss !== void 0 ? requireDismiss : messageLevel === 'error') ? Infinity : undefined;
59684
+ };
59729
59685
  /**
59730
59686
  * Provide new toast hook with old interface from original useShowLUIMessage
59731
59687
  */
59732
59688
  var useShowLUIMessageCompatibleInterface = function () {
59733
- var toast = useToast().toast;
59689
+ var t = useToast();
59734
59690
  return function (props) {
59735
- var message = props.message, messageLevel = props.messageLevel, requireDismiss = props.requireDismiss;
59736
- var toastProps = { children: message, level: messageLevel };
59737
- if (requireDismiss || messageLevel === 'error') {
59738
- toast(function (_a) {
59739
- var close = _a.close;
59740
- return React__default["default"].createElement(LuiBannerV2, __assign({}, toastProps, { onDismiss: close }));
59741
- });
59742
- }
59743
- else {
59744
- toast(React__default["default"].createElement(LuiBannerV2, __assign({}, toastProps)));
59745
- }
59691
+ return t[props.messageLevel](props.message, { timeout: getTimeout(props) });
59746
59692
  };
59747
59693
  };
59748
59694
 
59749
- var ToastUpgrade = React.createContext(false);
59750
- var useToastUpgrade = function () { return React.useContext(ToastUpgrade); };
59751
59695
  /**
59752
- * @deprecated Use ToastProvider or LuiMessagingContextProvider with upgrade prop set to true to get the new designs
59696
+ * Context provider to handle global logic of toast messages. It defaults to legacy version 'v1'.
59697
+ * @description Set version property to 'v2' to get the latest designs.
59753
59698
  */
59754
59699
  var LuiMessagingContextProvider = function (props) {
59755
- var _a = props.upgrade, upgrade = _a === void 0 ? false : _a, rest = __rest(props, ["upgrade"]);
59756
59700
  if (React.useContext(ToastContext)) {
59757
- return React__default["default"].createElement(React__default["default"].Fragment, null, rest.children);
59701
+ return React__default["default"].createElement(React__default["default"].Fragment, null, props.children);
59758
59702
  }
59759
- return (React__default["default"].createElement(ToastUpgrade.Provider, { value: upgrade }, upgrade ? (React__default["default"].createElement(ToastProvider, __assign({}, rest))) : (React__default["default"].createElement(LuiMessagingContextProvider$1, __assign({}, rest)))));
59703
+ return (React__default["default"].createElement(React__default["default"].Fragment, null, props.version === 'v2' ? (React__default["default"].createElement(ToastProvider, { stack: props.stack, defaultTimeout: props.defaultTimeout }, props.children)) : (React__default["default"].createElement(ToastVersion.Provider, { value: "v1" },
59704
+ React__default["default"].createElement(LuiMessagingContextProvider$1, null, props.children)))));
59760
59705
  };
59706
+ /**
59707
+ * Hook to display pop-up messages in response to a user action or state change. Examples include: Saving, exporting, committing, deleting, etc.
59708
+ * @description Legacy hook to trigger toasts. It requires {@linkcode LuiMessagingContextProvider}.
59709
+ * @alias useToast. For a more flexible API when you're using v2 designs, using useToast is recommended.
59710
+ * @returns Toaster function to trigger branded toasts (e.g. warning, error, info) in the top right of the page.
59711
+ * @example
59712
+ * const toaster = useShowLUIMessage();
59713
+ * toaster({ message: 'Failed to save', messageType: 'toast', messageLevel: 'error' });
59714
+ */
59761
59715
  var useShowLUIMessage = function () {
59762
- var upgrade = useToastUpgrade();
59716
+ var version = useToastVersion();
59763
59717
  var older = useShowLUIMessage$1();
59764
59718
  var newer = useShowLUIMessageCompatibleInterface();
59765
- return upgrade ? newer : older;
59719
+ return version === 'v2' ? newer : older;
59766
59720
  };
59767
59721
  var LuiToastMessage = function (props) {
59768
- var upgrade = useToastUpgrade();
59769
- return upgrade ? (React__default["default"].createElement(LuiToastMessageCompatibleInterface, __assign({}, props))) : (React__default["default"].createElement(LuiToastMessage$1, __assign({}, props)));
59722
+ var version = useToastVersion();
59723
+ return version === 'v2' ? (React__default["default"].createElement(LuiToastMessageCompatibleInterface, __assign({}, props))) : (React__default["default"].createElement(LuiToastMessage$1, __assign({}, props)));
59770
59724
  };
59771
59725
 
59772
59726
  exports.CheckboxItemRenderer = CheckboxItemRenderer;
@@ -59776,7 +59730,6 @@ exports.LuiAccordicardStatic = LuiAccordicardStatic;
59776
59730
  exports.LuiAccordion = LuiAccordion;
59777
59731
  exports.LuiAlertModal = LuiAlertModal;
59778
59732
  exports.LuiAlertModalButtons = LuiAlertModalButtons;
59779
- exports.LuiAlertModalV2 = LuiAlertModalV2;
59780
59733
  exports.LuiAppFooterSml = LuiAppFooterSml;
59781
59734
  exports.LuiBadge = LuiBadge;
59782
59735
  exports.LuiBanner = LuiBanner;
@@ -59830,7 +59783,6 @@ exports.LuiMenuCloseButtonV2 = LuiMenuCloseButtonV2;
59830
59783
  exports.LuiMessagingContextProvider = LuiMessagingContextProvider;
59831
59784
  exports.LuiMiniSpinner = LuiMiniSpinner;
59832
59785
  exports.LuiModal = LuiModal;
59833
- exports.LuiModalV2 = LuiModalV2;
59834
59786
  exports.LuiMoneyInput = LuiMoneyInput;
59835
59787
  exports.LuiMultiSwitch = LuiMultiSwitch;
59836
59788
  exports.LuiMultiSwitchYesNo = LuiMultiSwitchYesNo;
@@ -59870,7 +59822,6 @@ exports.LuiTooltip = LuiTooltip;
59870
59822
  exports.LuiUpdatesSplashModal = LuiUpdatesSplashModal;
59871
59823
  exports.RadioItemRenderer = RadioItemRenderer;
59872
59824
  exports.Splitter = Splitter;
59873
- exports.ToastProvider = ToastProvider;
59874
59825
  exports.ToolbarButton = ToolbarButton;
59875
59826
  exports.ToolbarItem = ToolbarItem;
59876
59827
  exports.ToolbarItemSeparator = ToolbarItemSeparator;