UNPKG

@postnord/web-components

Version:

PostNord Web Components

482 lines (481 loc) 17.6 kB
/*! * Built with Stencil * By PostNord. */ import { awaitTopbar, en, ripple } from "../../../index"; import { Host, h } from "@stencil/core"; import { alert_info_circle, check_circle, alert_exclamation_triangle, alert_exclamation_circle, close, } from "pn-design-assets/pn-assets/icons.js"; import { translations } from "./translation"; /** * This component is able to fill many roles of a classic toast. * It has 4 different colors, a temporary state, hide button, icon and illustration support. * * The `pn-toast` will expand to its parent containers full width. * Either limit the parent width or set a CSS rule to your specific width if needed. */ export class PnToast { toast; button; animation; hostElement; isClosing = false; isExpanding = false; hasSlottedContent = false; /** * Set a title for the toast. Requires the `text` prop in order to work. * @description Can be used together with slotted content. */ heading = ''; /** * Set a paragraph of text for the toast. * @description Can be used together with slotted content. */ text = ''; /** Give the toast a HTML ID. */ toastId; /** * Default color is blue, you also have the option of success (green), warning (orange) and error (red). * @category Visual */ appearance; /** * This will apply a shadow and border to the toast. * @category Visual */ temporary = false; /** * Set an SVG icon. * @category Visual */ icon; /** * Set an SVG illustration. * @category Visual */ illustration; /** * Control the visibility of the toast. If the `closable` prop is active, the toast will set the `hide` prop on its own. * @see {@link closable} * @category Features */ hide = false; /** * Show close button. * @category Features */ closable = false; /** * Manually set the language, only needed if the `closable` prop is enabled. * @see {@link closable} * @category Features */ language = null; handleHide() { const { matches } = window.matchMedia('(prefers-reduced-motion: reduce)'); if (matches) return this.hidden.emit(this.hide); if (this.hide) this.closeGrid(); else this.openGrid(); } /** Event fired when the close button is pressed. */ close; /** * This event is fired when the toast is fully hidden after the animation is finished. * Triggers from the close button or if the prop `hide` is set to true. **/ hidden; async componentWillLoad() { if (this.hide) this.hostElement.style.height = '0'; if (this.language === null) await awaitTopbar(this.hostElement); // Any text content at this stage means there is slotted content present. this.hasSlottedContent = !!this.hostElement.textContent; } componentDidLoad() { if (!!this.heading && !this.text && !this.hasSlottedContent) console.warn('The %s prop is only available if you use the %s prop or slotted content.', 'heading', 'text'); } getRect(element) { return element.getBoundingClientRect(); } openGrid() { requestAnimationFrame(() => { const { scrollHeight } = this.hostElement; const { height } = this.getRect(this.hostElement); this.hostElement.style.height = `${height}px`; this.isExpanding = true; this.animate(true, `${height}px`, `${scrollHeight}px`); }); } closeGrid() { const { scrollHeight, clientHeight } = this.hostElement; const height = this.isExpanding ? clientHeight : scrollHeight; this.hostElement.style.height = `0px`; this.isClosing = true; this.animate(false, `${height}px`, `0px`); } animate(open, startHeight, endHeight) { this.cancelAnimations(); this.animation = this.hostElement.animate({ height: [startHeight, endHeight], }, { duration: 400, easing: 'cubic-bezier(0.6, 0, 0.2, 1)', }); this.animation.onfinish = () => this.animationFinish(); this.animation.oncancel = () => (open ? (this.isExpanding = false) : (this.isClosing = false)); } animationFinish() { this.cancelAnimations(); if (!this.hide) this.hostElement.style.height = ''; else this.hidden.emit(this.hide); this.isClosing = false; this.isExpanding = false; } cancelAnimations() { if (this.animation) this.animation.cancel(); } closeToast(event) { this.hide = true; this.close.emit(this.hide); ripple(event, this.toast); } getIcon() { if (this.illustration) return ''; if (this.icon) return this.icon; if (this.appearance === 'success') return check_circle; if (this.appearance === 'warning') return alert_exclamation_triangle; if (this.appearance === 'error') return alert_exclamation_circle; return alert_info_circle; } getRole() { return this.appearance === 'error' ? 'alert' : 'status'; } showIcon() { return !this.illustration; } showIllustration() { return !this.showIcon(); } showTitle() { return (this.hasSlottedContent || !!this.text) && !!this.heading; } translate(prop) { return translations?.[prop]?.[this.language || en] || prop; } hideToast() { return this.hide && !(this.isClosing || this.isExpanding); } render() { return (h(Host, { key: 'e1d530ec1396c479685092dfdc6d668a80071b15' }, h("output", { key: '9aae177ffec7556f30789964e1a1f6698d07b5e5', id: this.toastId, class: "pn-toast", role: this.getRole(), "data-appearance": this.appearance, "data-temporary": this.temporary, "data-hide": this.hideToast(), ref: el => (this.toast = el) }, this.showIcon() && h("pn-icon", { key: '91a1f34ce7ca572f74a9f4bc90f102eefa84b7c2', class: "pn-toast-icon", icon: this.getIcon() }), h("div", { key: '1df901ec80ebf06265f517b97ed83e70aef4ec51', class: "pn-toast-content" }, this.showTitle() && h("h4", { key: '9e6b540a4eecc675bdcfeebeb1186b0f8834a769', class: "pn-toast-heading" }, this.heading), this.text && h("p", { key: '21c656c0af57f103c6b2ed734d79d2423399ce0c', class: "pn-toast-text" }, this.text), h("slot", { key: '8b99e035f2c276480f71d7c8f428a259256e2f68' })), this.showIllustration() && h("pn-illustration", { key: 'b259e69da37e02e728f89596bc4beadb35220eab', illustration: this.illustration, width: "5.5em", height: "5.5em" }), this.closable && (h("button", { key: 'c4e841ae4ec6a21f42e7de285837beda8884f86b', class: "pn-toast-button", type: "button", "aria-label": this.translate('HIDE'), onClick: (event) => this.closeToast(event), ref: el => (this.button = el) }, h("pn-icon", { key: '370667bd83527321a154a542761062e84704844a', icon: close })))))); } static get is() { return "pn-toast"; } static get originalStyleUrls() { return { "$": ["pn-toast.scss"] }; } static get styleUrls() { return { "$": ["pn-toast.css"] }; } static get properties() { return { "heading": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "description", "text": "Can be used together with slotted content." }], "text": "Set a title for the toast. Requires the `text` prop in order to work." }, "getter": false, "setter": false, "attribute": "heading", "reflect": false, "defaultValue": "''" }, "text": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "description", "text": "Can be used together with slotted content." }], "text": "Set a paragraph of text for the toast." }, "getter": false, "setter": false, "attribute": "text", "reflect": false, "defaultValue": "''" }, "toastId": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Give the toast a HTML ID." }, "getter": false, "setter": false, "attribute": "toast-id", "reflect": false }, "appearance": { "type": "string", "mutable": false, "complexType": { "original": "'' | 'success' | 'warning' | 'error'", "resolved": "\"\" | \"error\" | \"success\" | \"warning\"", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Visual" }], "text": "Default color is blue, you also have the option of success (green), warning (orange) and error (red)." }, "getter": false, "setter": false, "attribute": "appearance", "reflect": false }, "temporary": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "category", "text": "Visual" }], "text": "This will apply a shadow and border to the toast." }, "getter": false, "setter": false, "attribute": "temporary", "reflect": false, "defaultValue": "false" }, "icon": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Visual" }], "text": "Set an SVG icon." }, "getter": false, "setter": false, "attribute": "icon", "reflect": false }, "illustration": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Visual" }], "text": "Set an SVG illustration." }, "getter": false, "setter": false, "attribute": "illustration", "reflect": false }, "hide": { "type": "boolean", "mutable": true, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "see", "text": "{@link closable }" }, { "name": "category", "text": "Features" }], "text": "Control the visibility of the toast. If the `closable` prop is active, the toast will set the `hide` prop on its own." }, "getter": false, "setter": false, "attribute": "hide", "reflect": true, "defaultValue": "false" }, "closable": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "category", "text": "Features" }], "text": "Show close button." }, "getter": false, "setter": false, "attribute": "closable", "reflect": false, "defaultValue": "false" }, "language": { "type": "string", "mutable": true, "complexType": { "original": "PnLanguages", "resolved": "\"\" | \"da\" | \"en\" | \"fi\" | \"no\" | \"sv\"", "references": { "PnLanguages": { "location": "import", "path": "@/index", "id": "src/index.ts::PnLanguages" } } }, "required": false, "optional": true, "docs": { "tags": [{ "name": "see", "text": "{@link closable }" }, { "name": "category", "text": "Features" }], "text": "Manually set the language, only needed if the `closable` prop is enabled." }, "getter": false, "setter": false, "attribute": "language", "reflect": false, "defaultValue": "null" } }; } static get states() { return { "isClosing": {}, "isExpanding": {}, "hasSlottedContent": {} }; } static get events() { return [{ "method": "close", "name": "close", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event fired when the close button is pressed." }, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} } }, { "method": "hidden", "name": "hidden", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "This event is fired when the toast is fully hidden after the animation is finished.\nTriggers from the close button or if the prop `hide` is set to true." }, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} } }]; } static get elementRef() { return "hostElement"; } static get watchers() { return [{ "propName": "hide", "methodName": "handleHide" }]; } } //# sourceMappingURL=pn-toast.js.map