diff --git a/packages/beeq/src/components/toast/_storybook/bq-toast.stories.tsx b/packages/beeq/src/components/toast/_storybook/bq-toast.stories.tsx index d5ddae52f..492cdb521 100644 --- a/packages/beeq/src/components/toast/_storybook/bq-toast.stories.tsx +++ b/packages/beeq/src/components/toast/_storybook/bq-toast.stories.tsx @@ -58,8 +58,7 @@ const Template = (args: Args) => { @bqShow=${args.bqShow} @bqHide=${onToastHide} > - ${args.text} - ${type === 'custom' ? html`` : null} + ${args.text} ${type === 'custom' ? html`` : null} `, @@ -96,7 +95,7 @@ const CustomIconTemplate = (args: Args) => { @bqHide=${onToastHide} > ${args.text} - + `; }; diff --git a/packages/beeq/src/components/toast/bq-toast.tsx b/packages/beeq/src/components/toast/bq-toast.tsx index e1b91f41f..c3912d317 100644 --- a/packages/beeq/src/components/toast/bq-toast.tsx +++ b/packages/beeq/src/components/toast/bq-toast.tsx @@ -1,15 +1,18 @@ -import { Component, Element, Event, EventEmitter, h, Host, Listen, Method, Prop, Watch } from '@stencil/core'; +import { Component, Element, Event, EventEmitter, h, Host, Listen, Method, Prop, State, Watch } from '@stencil/core'; import { TOAST_PLACEMENT, TOAST_TYPE, TToastBorderRadius, TToastPlacement, TToastType } from './bq-toast.types'; import { debounce, TDebounce, validatePropValue } from '../../shared/utils'; -const toastPortal = Object.assign(document.createElement('div'), { className: 'bq-toast-portal' }); +const TOAST_PORTAL_SELECTOR = 'bq-toast-portal'; /** * @part wrapper - The component's internal wrapper inside the shadow DOM. * @part icon-info - The `
` container that holds the icon component. * @part base - The `
` container of the internal bq-icon component. * @part svg - The `` element of the internal bq-icon component. + * + * @slot - The content to be displayed in the toast component. + * @slot icon - The icon to be displayed in the toast component. */ @Component({ tag: 'bq-toast', @@ -31,6 +34,8 @@ export class BqToast { // Inlined decorator, alphabetical order // ======================================= + @State() private toastPortal = document.querySelector(`.${TOAST_PORTAL_SELECTOR}`); + // Public Property API // ======================== @@ -61,8 +66,9 @@ export class BqToast { validatePropValue(TOAST_TYPE, 'default', this.el, 'type'); validatePropValue(TOAST_PLACEMENT, 'bottom-center', this.el, 'placement'); - toastPortal.classList.remove(...TOAST_PLACEMENT); - toastPortal.classList.add(this.placement); + const { toastPortal } = this; + toastPortal?.classList.remove(...TOAST_PLACEMENT); + toastPortal?.classList.add(this.placement); } @Watch('time') @@ -99,6 +105,13 @@ export class BqToast { // Ordered by their natural call order // ===================================== + connectedCallback() { + const { toastPortal } = this; + if (!toastPortal) { + this.toastPortal = Object.assign(document.createElement('div'), { className: TOAST_PORTAL_SELECTOR }); + } + } + componentWillLoad() { this.checkPropValues(); this.handleTimeChange(); @@ -115,10 +128,11 @@ export class BqToast { @Listen('bqHide') onNotificationHide() { try { - toastPortal.removeChild(this.el); + const { toastPortal } = this; + toastPortal?.removeChild(this.el); // Remove the toast portal from the DOM when there are no more toasts - if (toastPortal.querySelector('bq-toast') === null) { - toastPortal.remove(); + if (toastPortal?.querySelector(this.el.tagName.toLowerCase()) === null) { + toastPortal?.remove(); } } catch (error) { /** @@ -152,11 +166,12 @@ export class BqToast { /** This method can be used to display toasts in a fixed-position element that allows for stacking multiple toasts vertically */ @Method() async toast() { - if (toastPortal.parentElement === null) { + const { toastPortal } = this; + if (toastPortal?.parentElement === null) { document.body.append(toastPortal); } - toastPortal.appendChild(this.el); + toastPortal?.appendChild(this.el); requestAnimationFrame(() => { this.show(); @@ -183,26 +198,15 @@ export class BqToast { }; private get iconName() { - switch (this.type) { - case 'success': { - return 'check-circle'; - } - case 'error': { - return 'x-circle'; - } - case 'loading': { - return 'spinner-gap'; - } - case 'alert': { - return 'warning'; - } - case 'info': { - return 'info'; - } - default: { - return 'info'; - } - } + const typeMap = { + success: 'check-circle-bold', + error: 'x-circle-bold', + loading: 'spinner-gap-bold', + alert: 'warning-bold', + info: 'info-bold', + }; + + return typeMap[this.type] || 'info-bold'; } // render() function @@ -225,7 +229,7 @@ export class BqToast {
- +
diff --git a/packages/beeq/src/components/toast/readme.md b/packages/beeq/src/components/toast/readme.md index 11832621c..ee17bf135 100644 --- a/packages/beeq/src/components/toast/readme.md +++ b/packages/beeq/src/components/toast/readme.md @@ -58,6 +58,14 @@ Type: `Promise` +## Slots + +| Slot | Description | +| -------- | --------------------------------------------------- | +| | The content to be displayed in the toast component. | +| `"icon"` | The icon to be displayed in the toast component. | + + ## Shadow Parts | Part | Description |