Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { html, ifDefined, classMap } from "../vendor/lit.all.mjs";
import { MozLitElement } from "../lit-utils.mjs";
/**
* A button with multiple types and two sizes.
*
* @tagname moz-button
* @property {string} label - The button's label, will be overridden by slotted content.
* @property {string} type - The button type.
* Options: default, primary, destructive, icon, icon ghost, ghost.
* @property {string} size - The button size.
* Options: default, small.
* @property {boolean} disabled - The disabled state.
* @property {string} title - The button's title attribute, used in shadow DOM and therefore not as an attribute on moz-button.
* @property {string} titleAttribute - Internal, map title attribute to the title JS property.
* @property {string} tooltipText - Set the title property, the title attribute will be used first.
* @property {string} ariaLabel - The button's arial-label attribute, used in shadow DOM and therefore not as an attribute on moz-button.
* @property {string} iconSrc - Path to the icon that should be displayed in the button.
* @property {string} ariaLabelAttribute - Internal, map aria-label attribute to the ariaLabel JS property.
* @property {string} hasVisibleLabel - Internal, tracks whether or not the button has a visible label.
* @property {HTMLButtonElement} buttonEl - The internal button element in the shadow DOM.
* @property {HTMLButtonElement} slotEl - The internal slot element in the shadow DOM.
* @slot default - The button's content, overrides label property.
* @fires click - The click event.
*/
export default class MozButton extends MozLitElement {
static shadowRootOptions = {
...MozLitElement.shadowRootOptions,
delegatesFocus: true,
};
static properties = {
label: { type: String, reflect: true },
type: { type: String, reflect: true },
size: { type: String, reflect: true },
disabled: { type: Boolean, reflect: true },
title: { type: String, state: true },
titleAttribute: { type: String, attribute: "title", reflect: true },
tooltipText: { type: String },
ariaLabelAttribute: {
type: String,
attribute: "aria-label",
reflect: true,
},
ariaLabel: { type: String, state: true },
iconSrc: { type: String },
hasVisibleLabel: { type: Boolean, state: true },
};
static queries = {
buttonEl: "button",
slotEl: "slot",
};
constructor() {
super();
this.type = "default";
this.size = "default";
this.disabled = false;
this.hasVisibleLabel = !!this.label;
}
willUpdate(changes) {
if (changes.has("titleAttribute")) {
this.title = this.titleAttribute;
this.titleAttribute = null;
}
if (changes.has("ariaLabelAttribute")) {
this.ariaLabel = this.ariaLabelAttribute;
this.ariaLabelAttribute = null;
}
}
// Delegate clicks on host to the button element.
click() {
this.buttonEl.click();
}
checkForLabelText() {
this.hasVisibleLabel = this.slotEl
.assignedNodes()
.some(node => node.textContent.trim());
}
render() {
return html`
<link
rel="stylesheet"
/>
<button
type=${this.type}
size=${this.size}
?disabled=${this.disabled}
title=${ifDefined(this.title || this.tooltipText)}
aria-label=${ifDefined(this.ariaLabel)}
part="button"
class=${classMap({ labelled: this.label || this.hasVisibleLabel })}
>
${this.iconSrc
? html`<img src=${this.iconSrc} role="presentation" />`
: ""}
<slot @slotchange=${this.checkForLabelText}>${this.label}</slot>
</button>
`;
}
}
customElements.define("moz-button", MozButton);