UNPKG

@3mo/loading-button

Version:

A button web-component with a loading state and capable of inferring the loading state from click event handler promises.

93 lines (92 loc) 3.55 kB
import { __decorate } from "tslib"; import { EventListenerController, component, css, extractEventHandler, html, property, queryAsync, style } from '@a11d/lit'; import { Button } from '@3mo/button'; import '@3mo/circular-progress'; /** * @attr loading * @attr preventClickEventInference */ let LoadingButton = class LoadingButton extends Button { constructor() { super(...arguments); this.loading = false; this.preventClickEventInference = false; this.clickEventListeners = new Set(); this.clickEventListenerController = new EventListenerController(this, { type: 'click', target: () => this.button, listener: async (e) => { if (this.preventClickEventInference === false) { const results = [...this.clickEventListeners] .map(listener => extractEventHandler(listener)(e)) .filter(Boolean); if (results.length > 0 && this.loading === false) { e.stopImmediatePropagation(); this.loading = true; await Promise.allSettled(results); this.loading = false; } } }, }); } addEventListener(type, listener, options) { if (type === 'click') { this.clickEventListeners.add(listener); } super.addEventListener(type, listener, options); } removeEventListener(type, listener, options) { if (type === 'click') { this.clickEventListeners.delete(listener); } super.removeEventListener(type, listener, options); } static get styles() { return css ` ${super.styles} :host([loading]) { pointer-events: none; } [md-button] { position: relative; } `; } get contentTemplate() { return html ` ${super.contentTemplate} ${!this.circularProgressReplacesStartIcon && this.loading ? this.circularProgressTemplate : html.nothing} `; } get isDisabled() { return super.isDisabled || this.loading; } get startIconTemplate() { return this.circularProgressReplacesStartIcon && this.loading ? this.circularProgressTemplate : super.startIconTemplate; } get circularProgressReplacesStartIcon() { return !!this.startIcon; } get circularProgressTemplate() { return html ` <mo-circular-progress ${style({ position: this.circularProgressReplacesStartIcon ? undefined : 'absolute', top: this.circularProgressReplacesStartIcon ? undefined : '50%', insetInlineStart: this.circularProgressReplacesStartIcon ? undefined : '50%', transform: this.circularProgressReplacesStartIcon ? undefined : getComputedStyle(this).direction === 'rtl' ? 'translate(+50%, -50%)' : 'translate(-50%, -50%)', width: this.circularProgressReplacesStartIcon ? '24px' : 'auto', height: this.circularProgressReplacesStartIcon ? '24px' : '75%', })}></mo-circular-progress> `; } }; __decorate([ property({ type: Boolean, reflect: true }) ], LoadingButton.prototype, "loading", void 0); __decorate([ property({ type: Boolean }) ], LoadingButton.prototype, "preventClickEventInference", void 0); __decorate([ queryAsync('[md-button]') ], LoadingButton.prototype, "button", void 0); LoadingButton = __decorate([ component('mo-loading-button') ], LoadingButton); export { LoadingButton };