@postnord/web-components
Version:
PostNord Web Components
482 lines (481 loc) • 17.6 kB
JavaScript
/*!
* 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