@progressive-development/pd-page
Version:
Progressive development page helper, teaser, menu, footer.
223 lines (205 loc) • 6.56 kB
JavaScript
import { css, LitElement, html } from 'lit';
import { state, property } from 'lit/decorators.js';
import { localized, msg } from '@lit/localize';
import { pdIcons } from '@progressive-development/pd-icon';
import { toastBus } from '../toast-bus/toast-bus.js';
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result) __defProp(target, key, result);
return result;
};
const DEFAULT_DURATION = 6e3;
const ANIMATION_DURATION = 300;
let PdToast = class extends LitElement {
constructor() {
super(...arguments);
this._message = "";
this.isError = false;
this.isSuccess = false;
// ---------------------------------------------------------------------------
// Private
// ---------------------------------------------------------------------------
this._queue = [];
this._isProcessing = false;
this._boundHandleToast = this._handleToast.bind(this);
}
// ---------------------------------------------------------------------------
// Lifecycle
// ---------------------------------------------------------------------------
connectedCallback() {
super.connectedCallback();
this.setAttribute("aria-live", "polite");
toastBus.addEventListener("toast", this._boundHandleToast);
}
disconnectedCallback() {
super.disconnectedCallback();
this._clearTimer();
toastBus.removeEventListener(
"toast",
this._boundHandleToast
);
}
// ---------------------------------------------------------------------------
// Render
// ---------------------------------------------------------------------------
render() {
return html`
<div class="content" part="content">${this._message}</div>
<pd-icon
icon=${pdIcons.ICON_CLOSE}
class="close-icon"
tabindex="0"
role="button"
aria-label="${msg("Schließen", { id: "pdPage.toast.ariaClose" })}"
@click=${this._close}
@keydown=${this._onCloseKeyDown}
></pd-icon>
`;
}
_onCloseKeyDown(e) {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
this._close();
}
}
// ---------------------------------------------------------------------------
// Queue Processing
// ---------------------------------------------------------------------------
_handleToast(event) {
const detail = event.detail;
this._queue.push(detail);
this._processQueue();
}
_processQueue() {
if (this._isProcessing || this._queue.length === 0) {
return;
}
const item = this._queue.shift();
this._showToast(item);
}
_showToast(detail) {
this._isProcessing = true;
this._message = detail.message;
this.isError = detail.type === "error";
this.isSuccess = detail.type === "success";
if (this.isError) {
this.setAttribute("role", "alert");
} else {
this.removeAttribute("role");
}
this.classList.add("visible");
const duration = detail.duration ?? DEFAULT_DURATION;
if (duration > 0) {
this._autoCloseTimer = window.setTimeout(() => {
this._close();
}, duration);
}
}
_close() {
this._clearTimer();
this.classList.remove("visible");
this._isProcessing = false;
window.setTimeout(() => {
this._processQueue();
}, ANIMATION_DURATION);
}
_clearTimer() {
if (this._autoCloseTimer !== void 0) {
window.clearTimeout(this._autoCloseTimer);
this._autoCloseTimer = void 0;
}
}
};
// ---------------------------------------------------------------------------
// Styles
// ---------------------------------------------------------------------------
PdToast.styles = css`
:host {
--pd-icon-size: 1rem;
--_toast-transition-duration: 300ms;
/* Mobile first: smaller margins */
--_toast-margin: 12px;
position: fixed;
bottom: var(--pd-toast-bottom, var(--_toast-margin));
left: var(--pd-toast-left, var(--_toast-margin));
width: calc(100% - var(--_toast-margin) * 2);
max-width: var(--pd-toast-max-width, 400px);
z-index: var(--pd-toast-z-index, 105);
background: var(--pd-toast-bg, var(--app-primary-color, #ebcf57));
color: var(--pd-toast-color, #0a3a48);
padding: var(--pd-toast-padding, 0.6rem);
padding-right: calc(var(--pd-toast-padding, 0.6rem) + 1.4rem);
border-radius: var(
--pd-toast-border-radius,
var(--item-border-radius, 2px)
);
box-shadow: var(--pd-toast-shadow, 3px 5px 5px 3px lightgrey);
display: flex;
align-items: center;
gap: 0.5rem;
transform: translateX(-150%);
opacity: 0;
transition:
transform var(--_toast-transition-duration) ease-out,
opacity var(--_toast-transition-duration) ease-out;
pointer-events: none;
}
/* Tablet and up: more spacing */
@media (min-width: 768px) {
:host {
--_toast-margin: 30px;
}
}
:host([isError]) {
background: var(--pd-toast-error-bg, darkred);
color: var(--pd-toast-error-color, #fff);
}
:host([isSuccess]) {
background: var(--pd-toast-success-bg, green);
color: var(--pd-toast-success-color, #fff);
}
:host(.visible) {
transform: translateX(0);
opacity: 1;
pointer-events: auto;
}
.content {
flex: 1;
word-wrap: break-word;
overflow-wrap: break-word;
}
.close-icon {
position: absolute;
cursor: pointer;
right: var(--pd-spacing-sm, 0.5rem);
top: var(--pd-spacing-sm, 0.5rem);
}
.close-icon:focus {
outline: 2px solid currentColor;
outline-offset: 2px;
border-radius: var(--pd-radius-sm, 2px);
}
@media (prefers-reduced-motion: reduce) {
:host {
--_toast-transition-duration: 0ms;
}
}
`;
__decorateClass([
state()
], PdToast.prototype, "_message", 2);
__decorateClass([
property({ type: Boolean, reflect: true })
], PdToast.prototype, "isError", 2);
__decorateClass([
property({ type: Boolean, reflect: true })
], PdToast.prototype, "isSuccess", 2);
PdToast = __decorateClass([
localized()
], PdToast);
export { PdToast };