UNPKG

@bliss-design-system/button

Version:

Button component, or an anchor element styled as a button.

197 lines (196 loc) 6.45 kB
var _a; import { __decorate } from "tslib"; /* eslint-disable consistent-return */ import { html, property, LitElement, } from 'lit-element'; import { ifDefined } from 'lit-html/directives/if-defined'; import { IconMixin } from '@bliss-design-system/shared'; import { styles } from './index.css.js'; const observer = Symbol('observer'); /** * @element bliss-button * * @prop {String} [type=button] - input type, one of 'button', 'submit' or 'reset' * @prop {String} [href] - converts button into an anchor tag * @prop {String} {_blank|_parent|_self|_top} [target] - where to open the link, requires `href` attribute * @prop {String} [rel] - sets the relationship between the link and the document, requires `href` attribute * @prop {String} [download] - download instead of navigate, requires `href` attribute * * @attr {Boolean} [disabled=false] - whether or not to disable the button * @attr {Boolean} [loading=false] - whether or not to display loading spinner * @attr {String} [icon] - The name of the icon to display * @attr {Boolean} [icon-trailing=false] - whether to display the icon after the label * @attr {Boolean} [icon-only=false] - whether to display an icon only * @attr {Boolean} [full-width=false] - whether to make the button full width of its container * @attr {primary|secondary|ghost} [variant=primary] - button variant * @attr {default|netural|critical} [theme=default] - button theme * @attr {small|medium} [size=medium] - button size * @attr {Boolean} [transparent=false] - whether the background color of the button is transparent or not * * @slot - Default text slot * @slot icon — icon slot * * @csspart button */ export class BlissButton extends IconMixin(LitElement) { constructor() { super(); this.iconTrailing = false; this.iconOnly = false; this.loading = false; this.disabled = false; this.type = 'button'; this.addEventListener('click', this.handleClick, { capture: true, }); } static get styles() { return [styles]; } handleClick(event) { if (this.disabled && !this.href) { event.preventDefault(); event.stopImmediatePropagation(); event.stopPropagation(); return false; } } setAriaLabel(text) { if (!(text === null || text === void 0 ? void 0 : text.trim())) { console.warn('%c[Bliss Warn]:', 'font-weight: 600;', `<bliss-button> requires text content.`); } this.content = (text === null || text === void 0 ? void 0 : text.trim()) || ''; } firstUpdated(changed) { super.firstUpdated(changed); super.setIcon(); this.setAriaLabel(this.textContent); } slotObserver() { if (!this[observer]) { const cb = (mutations) => { mutations.forEach(mutation => { switch (mutation.type) { case 'characterData': this.setAriaLabel(mutation.target.textContent); break; case 'attributes': super.setIcon(); break; default: break; } }); }; this[observer] = new MutationObserver(cb); } } observe() { const config = { attributeFilter: ['icon'], characterData: true, subtree: true, }; this.slotObserver(); return this[observer].observe(this, config); } connectedCallback() { super.connectedCallback(); this.observe(); } disconnectedCallback() { this[observer].disconnect(); super.disconnectedCallback(); } get contentTemplate() { const icon = html ` <slot part="icon" name="icon" aria-hidden> <bliss-icon name="${this.icon}"></bliss-icon> </slot> `; const loading = html ` <bliss-loading part="loading"></bliss-loading> `; const template = [ html ` <span part="content" ?hidden=${this.iconOnly}> <slot></slot> </span> ${super.setSVGSymbol()} `, ]; if (this.loading) { template.push(loading); } if (!this.icon) { return template; } if (this.iconTrailing) { template.push(icon); } else { template.unshift(icon); } return template; } renderAnchor() { return html ` <a href="${this.href}" target="${ifDefined(this.target)}" rel="${ifDefined(this.target)}" download="${ifDefined(this.download)}" part="button" > ${this.contentTemplate} </a> `; } renderButton() { return html ` <button ?disabled="${this.disabled || this.loading}" ?aria-disabled="${this.disabled}" aria-label="${this.content}" type="${this.type}" part="button" > ${this.contentTemplate} </button> `; } render() { return this.href ? this.renderAnchor() : this.renderButton(); } } _a = observer; __decorate([ property({ attribute: false }) ], BlissButton.prototype, _a, void 0); __decorate([ property({ attribute: false }) ], BlissButton.prototype, "content", void 0); __decorate([ property({ type: Boolean, reflect: true, attribute: 'icon-trailing' }) ], BlissButton.prototype, "iconTrailing", void 0); __decorate([ property({ type: Boolean, reflect: true, attribute: 'icon-only' }) ], BlissButton.prototype, "iconOnly", void 0); __decorate([ property({ type: Boolean }) ], BlissButton.prototype, "loading", void 0); __decorate([ property({ type: Boolean }) ], BlissButton.prototype, "disabled", void 0); __decorate([ property({ type: String }) ], BlissButton.prototype, "type", void 0); __decorate([ property({ type: String, reflect: true }) ], BlissButton.prototype, "href", void 0); __decorate([ property({ reflect: true }) ], BlissButton.prototype, "target", void 0); __decorate([ property({ reflect: true }) ], BlissButton.prototype, "rel", void 0); __decorate([ property({ reflect: true }) ], BlissButton.prototype, "download", void 0);