/* eslint-disable lit/binding-positions */ /* eslint-disable lit/no-invalid-html */ import { type PropertyValueMap, css } from "lit"; import { html, literal } from "lit/static-html.js"; import { customElement, property } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { TailwindElement } from "@/classes/TailwindElement"; import { tw } from "@/utils/tailwind"; /** * Custom styled button * * Usage example: * ```ts * Click me * ``` */ @customElement("btrix-navigation-button") export class Button extends TailwindElement { @property({ type: Boolean }) active = false; @property({ type: String }) type: "submit" | "button" = "button"; @property({ type: String }) label?: string; @property({ type: String }) href?: string; @property({ type: Boolean }) disabled = false; @property({ type: Boolean }) icon = false; @property({ type: String, reflect: true }) role: ARIAMixin["role"] = "tab"; @property({ type: String }) size: "small" | "medium" | "large" = "medium"; @property({ type: String }) align: "left" | "center" | "right" = "left"; protected willUpdate(changedProperties: PropertyValueMap) { if (changedProperties.has("active")) { this.ariaSelected = this.active ? "true" : null; } } static styles = css` :host { display: inline-block; } ::slotted(sl-icon) { display: block; font-size: 1rem; } `; render() { const tag = this.href ? literal`a` : literal`button`; return html`<${tag} type=${this.type === "submit" ? "submit" : "button"} class=${[ tw`flex w-full cursor-pointer items-center gap-2 rounded font-medium leading-[16px] outline-primary-600 transition hover:transition-none focus-visible:outline focus-visible:outline-3 focus-visible:outline-offset-1 disabled:cursor-not-allowed disabled:bg-transparent disabled:opacity-50`, this.icon ? tw`min-h-6 min-w-6` : tw``, { small: this.icon ? tw`min-h-6 p-0` : tw`min-h-6 px-2 py-0`, medium: tw`p-2`, large: tw`px-2 py-4`, }[this.size], { left: "justify-start", center: "justify-center", right: "justify-end", }[this.align], this.active ? tw`bg-blue-100 text-blue-600 shadow-sm shadow-blue-900/20 hover:bg-blue-100` : tw`text-neutral-600 hover:bg-blue-50`, ] .filter(Boolean) .join(" ")} ?disabled=${this.disabled} href=${ifDefined(this.href)} aria-label=${ifDefined(this.label)} @click=${this.handleClick} > `; } private handleClick(e: MouseEvent) { if (this.disabled) { e.preventDefault(); e.stopPropagation(); return; } if (this.type === "submit") { this.submit(); } } private submit() { const form = (this.closest("form") || this.closest("form"))!; if (form) { form.submit(); } } }