@limetech/lime-elements
Version:
411 lines (410 loc) • 14.9 kB
JavaScript
import { h, } from "@stencil/core";
import translate from "../../global/translations";
import { SnackbarContainer } from "./container";
import { createRandomString } from "../../util/random-string";
const container = new SnackbarContainer();
const hideAnimationDuration = 300;
/**
* A Snackbar –also known as "Toast"– is used to inform the end user
* about an action or a process in the system.
* The information could vary from announcing that a process has just started,
* is taking place now, has ended, or has been interrupted or canceled.
*
* The information that you provide using a snackbar should be:
* - temporary
* - contextual
* - short
* - and most importantly, ignorable.
*
* It means if the user misses the information, it shouldn't be a big deal.
*
* :::note
* If the information you want to display has a higher importance or priority,
* and you need to make sure that the user takes an action to dismiss it,
* consider using the [Banner](#/component/limel-banner/) component instead.
* For more complex interactions and for delivering more detailed information,
* [Dialog](#/component/limel-dialog/) is a better choice.
* :::
*
* @exampleComponent limel-example-snackbar-basic
* @exampleComponent limel-example-snackbar-with-action
* @exampleComponent limel-example-snackbar-with-changing-messages
* @exampleComponent limel-example-snackbar-dismissible
* @exampleComponent limel-example-snackbar-persistent
* @exampleComponent limel-example-snackbar-persistent-non-dismissible
*/
export class Snackbar {
constructor() {
/**
* `true` if the snackbar is open, `false` otherwise.
*/
this.open = false;
/**
* The amount of time in milliseconds to show the snackbar.
* If set to `-1`, the snackbar will be persistent.
* This means:
* - either the end user will need to close it manually,
* which requires the `dismissible` property to be set to `true`.
* - or the snackbar needs to be closed programmatically.
*/
this.timeout = 5000;
/**
* When `true` displays a dismiss button on the snackbar,
* allowing users to close it.
*/
this.dismissible = true;
/**
* Defines the language for translations.
*/
this.language = 'en';
this.offset = 0;
this.isOpen = false;
this.closing = true;
this.handleOpen = () => {
if (this.isOpen) {
return;
}
this.isOpen = true;
this.closing = false;
container.add(this.host);
if (this.timeout && this.timeout !== -1) {
this.timeoutId = window.setTimeout(this.handleClose, Math.max(this.timeout - hideAnimationDuration, hideAnimationDuration));
}
};
this.handleClose = () => {
if (!this.isOpen) {
return;
}
this.closing = true;
if (this.timeoutId) {
clearTimeout(this.timeoutId);
this.timeoutId = undefined;
}
setTimeout(() => {
this.isOpen = false;
container.remove(this.host);
this.hide.emit();
this.offset = 0;
}, hideAnimationDuration);
};
this.handleClickAction = () => {
this.action.emit();
};
this.snackbarId = createRandomString();
}
componentDidLoad() {
if (this.open) {
requestAnimationFrame(this.handleOpen);
}
}
onChangeIndex(event) {
event.stopPropagation();
this.offset = event.detail;
}
watchOpen() {
if (this.open) {
this.handleOpen();
}
else {
this.handleClose();
}
this.isOpen = this.open;
}
/**
* Show the snackbar
* @deprecated Use the `open` property instead.
*/
async show() {
console.warn('The `show` method in `limel-snackbar` is deprecated. Please use the `open` property instead.');
if (!this.open) {
this.handleOpen();
}
}
render() {
return (h("aside", { key: '0c9605ecafcab256f9e1b2ac43b72c70695c1719', popover: "manual", style: {
'--snackbar-timeout': `${Math.max(this.timeout || 0, 0)}ms`,
'--snackbar-distance-to-top-edge': `${this.offset}px`,
}, class: {
open: this.open,
'is-closing': this.closing,
'limel-portal--parent': true,
}, id: this.snackbarId, role: this.setAriaRoles(), "aria-atomic": this.open ? 'true' : undefined, "aria-relevant": this.open ? 'additions' : undefined }, h("div", { key: '58b4d6d2f94be604273c46e0babccade357798ab', class: "surface" }, h("div", { key: '148001236225eb6980f3894151e04fd43037863e', class: "label" }, this.message), this.renderActions(this.actionText), this.renderDismissButton(this.dismissible))));
}
setAriaRoles() {
if (!this.open) {
return;
}
if (!this.timeout || this.timeout === -1) {
return 'alertdialog';
}
return 'status';
}
renderActions(actionText) {
if (!actionText) {
return;
}
return h("div", { class: "actions" }, this.renderActionButton(actionText));
}
renderActionButton(actionText) {
if (!actionText) {
return;
}
return (h("limel-button", { label: actionText, onClick: this.handleClickAction }));
}
renderDismissButton(dismissible) {
if (!dismissible) {
return;
}
const label = translate.get('snackbar.dismiss', this.language);
return (h("div", { class: "dismiss" }, this.renderTimeoutVisualization(), h("limel-icon-button", { class: "dismiss-button", icon: "multiply", label: label, onClick: this.handleClose, "aria-controls": this.snackbarId })));
}
renderTimeoutVisualization() {
if (!this.timeout || this.timeout === -1) {
return;
}
return (h("svg", { width: "36", height: "36", viewBox: "0 0 36 36" }, h("circle", { r: "18", cx: "18", cy: "18", fill: "var(--track-color)" }), h("path", { class: "track", d: "M 18,18 m -16,0 a 16,16 0 1,0 32,0 a 16,16 0 1,0 -32,0", stroke: "var(--fill-color)" })));
}
static get is() { return "limel-snackbar"; }
static get encapsulation() { return "shadow"; }
static get originalStyleUrls() {
return {
"$": ["snackbar.scss"]
};
}
static get styleUrls() {
return {
"$": ["snackbar.css"]
};
}
static get properties() {
return {
"open": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "`true` if the snackbar is open, `false` otherwise."
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "open",
"defaultValue": "false"
},
"message": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "The text message to display."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "message"
},
"timeout": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "The amount of time in milliseconds to show the snackbar.\nIf set to `-1`, the snackbar will be persistent.\nThis means:\n- either the end user will need to close it manually,\nwhich requires the `dismissible` property to be set to `true`.\n- or the snackbar needs to be closed programmatically."
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "timeout",
"defaultValue": "5000"
},
"actionText": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "The text to display for the action button."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "action-text"
},
"dismissible": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "When `true` displays a dismiss button on the snackbar,\nallowing users to close it."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "dismissible",
"defaultValue": "true"
},
"multiline": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [{
"name": "deprecated",
"text": "Setting this property no longer has any effect. The property will be removed in a future major version."
}],
"text": "Whether to show the snackbar with space for multiple lines of text"
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "multiline"
},
"language": {
"type": "string",
"mutable": false,
"complexType": {
"original": "Languages",
"resolved": "\"da\" | \"de\" | \"en\" | \"fi\" | \"fr\" | \"nb\" | \"nl\" | \"no\" | \"sv\"",
"references": {
"Languages": {
"location": "import",
"path": "../date-picker/date.types",
"id": "src/components/date-picker/date.types.ts::Languages",
"referenceLocation": "Languages"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Defines the language for translations."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "language",
"defaultValue": "'en'"
}
};
}
static get states() {
return {
"offset": {},
"isOpen": {},
"closing": {}
};
}
static get events() {
return [{
"method": "action",
"name": "action",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": "Emitted when the action button is pressed"
},
"complexType": {
"original": "void",
"resolved": "void",
"references": {}
}
}, {
"method": "hide",
"name": "hide",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": "Emitted when the snackbar hides itself"
},
"complexType": {
"original": "void",
"resolved": "void",
"references": {}
}
}];
}
static get methods() {
return {
"show": {
"complexType": {
"signature": "() => Promise<void>",
"parameters": [],
"references": {
"Promise": {
"location": "global",
"id": "global::Promise"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "Show the snackbar",
"tags": [{
"name": "deprecated",
"text": "Use the `open` property instead."
}]
}
}
};
}
static get elementRef() { return "host"; }
static get watchers() {
return [{
"propName": "open",
"methodName": "watchOpen"
}];
}
static get listeners() {
return [{
"name": "changeOffset",
"method": "onChangeIndex",
"target": undefined,
"capture": false,
"passive": false
}];
}
}