@bliss-design-system/button
Version:
Button component, or an anchor element styled as a button.
197 lines (196 loc) • 6.45 kB
JavaScript
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);