ui-lit
Version:
UI Elements on LIT
286 lines (284 loc) • 10.2 kB
JavaScript
import { __decorate } from "tslib";
import { styleMap } from 'lit/directives/style-map.js';
import { LitElement, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { button } from './styles';
import '../spinner';
import '../icon';
import '../link';
import { focusable } from '../mixins/focusable/index';
/** @tag lit-button */
let LitButton = class LitButton extends focusable(LitElement) {
constructor() {
super(...arguments);
/** @ignore */
this._loading = false;
/** @prop {"button" | "submit"} type */
this.align = 'center';
this.href = null;
this.target = "_self";
/** @prop {"button" | "submit"} type */
this.type = 'button';
this.size = 'medium';
/** @prop {boolean} disabled - Disable element */
this.disabled = false;
/** @prop {boolean} borderless - Borderless element */
this.borderless = false;
///** @prop {boolean} switch - Button can be switch toggle */
//@property({type: Boolean, reflect: true}) switch: boolean = false;
/** @prop {boolean} primary - Primary */
this.primary = false;
/** @prop {boolean} success - Success */
this.success = false;
/** @prop {boolean} danger - Danger */
this.danger = false;
this.between = false;
/** @prop {boolean} switchOn - switch State. true - enabled, false disabled */
this.switchOn = false;
this.accent = false;
this.notifyOnClick = false;
/** @ignore */
this._notifyIcon = false;
this.tabindex = 0;
/** @ignore */
this._notifyTimeout = 0;
/** @ignore */
this._width = 0;
/** @ignore */
this._radiant = 5;
/** @ignore */
this._animationFrame = 0;
/** @ignore */
this._pressed = false;
// ==== Events ====
// +++ Ripple +++
this._startAnimation = () => {
if (this._radiant < 1000 && this._pressed) {
this._radiant += 20;
this.style.setProperty(`--radiant`, this._radiant + "px");
this._animationFrame = requestAnimationFrame(this._startAnimation);
}
};
this._endPress = () => {
this._pressed = false;
this._radiant = 5;
cancelAnimationFrame(this._animationFrame);
this.removeAttribute('pressed');
this.removeAttribute('hover');
document.removeEventListener('mouseup', this._endPress);
document.removeEventListener('touchend', this._endPress);
document.removeEventListener('touchcancel', this._endPress);
};
/** @ignore */
this._onKeyDown = (e) => {
if (e.key === "Enter" || e.key === " ") {
this.submit();
e.preventDefault();
}
};
}
static get properties() {
return {
loading: { type: Boolean }
};
}
get loading() {
return this._loading;
}
set loading(value) {
const oldValue = this._loading;
if (oldValue === value)
return;
this._loading = value;
if (value) {
this.setAttribute('loading', '');
}
else {
this.removeAttribute('loading');
}
this.requestUpdate("loading", oldValue);
}
/** @ignore */
get classes() {
return {
button: true,
wrapper: true,
noselect: true,
checkmark: this._notifyIcon,
accent: this.primary || this.success || this.danger || this.accent
};
}
/** @ignore */
_contentTemplate() {
if (this._notifyIcon) {
return html `<lit-icon icon = "checkmark"></lit-icon>`;
}
return html `${this.loading
? html `<lit-spinner small></lit-spinner>`
: html `<slot name = "icon-before"></slot>`}
<div part = "content" class = "content"><slot></slot></div>
<slot name = "icon-after"></slot>`;
}
wrapperTemplate(content) {
if (this.href) {
return html `<lit-link
type = "button"
target = "${this.target}"
href = "${this.href}">${content}</lit-link>`;
}
return content;
}
/**
* @slot icon-before - You can put some elements before content
* @slot icon-after - You can put some elements after content
*/
render() {
const styles = this._width ? { width: this._width + 'px' } : {};
const template = html `
<button role = "button"
aria-pressed = "${this.type === 'switch' ? this.switchOn : 'undefined'}"
tabindex = "${this.href ? -1 : this.tabindex}"
style = "${styleMap(styles)}"
class = "${classMap(this.classes)}"
= "${this.click}"
= "${this._onFocus}"
= "${this._onBlur}"
= "${this._onMouseOver}"
= "${this._onMouseOut}"
= "${this._onMouseDown}"
= "${this._onTouchstart}"
= "${this._endPress}"
= "${this._endPress}"
>${this._contentTemplate()}</button>`;
return this.wrapperTemplate(template);
}
_onTouchstart(e) {
this._startPress(e.touches[0].clientX, e.touches[0].clientY);
document.addEventListener('touchend', this._endPress);
document.addEventListener('touchcancel', this._endPress);
}
_onMouseOver(e) {
this.setAttribute('hover', '');
}
_onMouseOut(e) {
this.removeAttribute('hover');
}
_onMouseDown(e) {
this._startPress(e.clientX, e.clientY);
document.addEventListener('mouseup', this._endPress);
}
_startPress(x, y) {
const rect = this.getBoundingClientRect();
this._pressed = true;
this.setAttribute('pressed', '');
const _x = x - rect.x;
const _y = y - rect.y;
this.style.setProperty(`--click-x`, _x + "px");
this.style.setProperty(`--click-y`, _y + "px");
this._startAnimation();
}
// --- Ripple ---
/** @ignore */
_onBlur() {
document.removeEventListener('keydown', this._onKeyDown);
}
/** @ignore */
_onFocus() {
document.addEventListener('keydown', this._onKeyDown);
}
// ==== Actions ====
click() {
var _a, _b;
(_b = (_a = window.navigator).vibrate) === null || _b === void 0 ? void 0 : _b.call(_a, 20);
this.submit();
}
/** @event {CustomEvent} switchChanged - for type = 'switch'. Return current switchOn state. */
toggleSwitch() {
this.switchOn = !this.switchOn;
this.dispatchEvent(new CustomEvent("switchChanged", {
detail: this.switchOn,
bubbles: true,
}));
}
/** @event {CustomEvent} submitForm - for type = 'submit'. Submit to lit-form */
submit() {
var _a, _b;
if (this.disabled || this.loading)
return;
if (this.href) {
(_b = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector("lit-link")) === null || _b === void 0 ? void 0 : _b.click();
}
if (this.type === 'switch') {
this.toggleSwitch();
}
if (this.type === "submit") {
this.dispatchEvent(new CustomEvent("submitForm", {
bubbles: true,
composed: true,
}));
}
if (this.notifyOnClick) {
this._notifyIcon = true;
this._width = this.clientWidth;
clearTimeout(this._notifyTimeout);
this._notifyTimeout = window.setTimeout(() => {
this._notifyIcon = false;
this._width = 0;
}, 1000);
}
}
};
LitButton.styles = button;
__decorate([
property({ type: String, attribute: true })
], LitButton.prototype, "align", void 0);
__decorate([
property({ type: String, attribute: true })
], LitButton.prototype, "href", void 0);
__decorate([
property({ type: String })
], LitButton.prototype, "target", void 0);
__decorate([
property({ type: String, attribute: true })
], LitButton.prototype, "type", void 0);
__decorate([
property({ type: String, reflect: true, attribute: true })
], LitButton.prototype, "size", void 0);
__decorate([
property({ type: Boolean, reflect: true })
], LitButton.prototype, "disabled", void 0);
__decorate([
property({ type: Boolean, reflect: true })
], LitButton.prototype, "borderless", void 0);
__decorate([
property({ type: Boolean, reflect: true })
], LitButton.prototype, "primary", void 0);
__decorate([
property({ type: Boolean, reflect: true })
], LitButton.prototype, "success", void 0);
__decorate([
property({ type: Boolean, reflect: true })
], LitButton.prototype, "danger", void 0);
__decorate([
property({ type: Boolean, reflect: true })
], LitButton.prototype, "between", void 0);
__decorate([
property({ type: Boolean, reflect: true })
], LitButton.prototype, "switchOn", void 0);
__decorate([
property({ type: Boolean, reflect: true })
], LitButton.prototype, "accent", void 0);
__decorate([
property({ type: Boolean })
], LitButton.prototype, "notifyOnClick", void 0);
__decorate([
state()
], LitButton.prototype, "_notifyIcon", void 0);
__decorate([
property({ type: Number })
], LitButton.prototype, "tabindex", void 0);
LitButton = __decorate([
customElement("lit-button")
], LitButton);
export { LitButton };