import { LitElement } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { html, literal } from 'lit/static-html.js'; import '~/components/spinner/spinner'; import { emit } from '~/internal/event'; import { FormSubmitController } from '~/internal/form'; import { HasSlotController } from '~/internal/slot'; import styles from './button.styles'; /** * @since 2.0 * @status stable * * @dependency sl-spinner * * @event sl-blur - Emitted when the button loses focus. * @event sl-focus - Emitted when the button gains focus. * * @slot - The button's label. * @slot prefix - Used to prepend an icon or similar element to the button. * @slot suffix - Used to append an icon or similar element to the button. * * @csspart base - The component's internal wrapper. * @csspart prefix - The prefix slot's container. * @csspart label - The button's label. * @csspart suffix - The suffix slot's container. * @csspart caret - The button's caret. */ @customElement('sl-button') export default class SlButton extends LitElement { static styles = styles; @query('.button') button: HTMLButtonElement | HTMLLinkElement; private readonly formSubmitController = new FormSubmitController(this, { form: (input: HTMLInputElement) => { // Buttons support a form attribute that points to an arbitrary form, so if this attribute it set we need to query // the form from the same root using its id if (input.hasAttribute('form')) { const doc = input.getRootNode() as Document | ShadowRoot; const formId = input.getAttribute('form')!; return doc.getElementById(formId) as HTMLFormElement; } // Fall back to the closest containing form return input.closest('form'); } }); private readonly hasSlotController = new HasSlotController(this, '[default]', 'prefix', 'suffix'); @state() private hasFocus = false; /** The button's variant. */ @property({ reflect: true }) variant: 'default' | 'primary' | 'success' | 'neutral' | 'warning' | 'danger' | 'text' = 'default'; /** The button's size. */ @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; /** Draws the button with a caret for use with dropdowns, popovers, etc. */ @property({ type: Boolean, reflect: true }) caret = false; /** Disables the button. */ @property({ type: Boolean, reflect: true }) disabled = false; /** Draws the button in a loading state. */ @property({ type: Boolean, reflect: true }) loading = false; /** Draws an outlined button. */ @property({ type: Boolean, reflect: true }) outline = false; /** Draws a pill-style button with rounded edges. */ @property({ type: Boolean, reflect: true }) pill = false; /** Draws a circle button. */ @property({ type: Boolean, reflect: true }) circle = false; /** * The type of button. When the type is `submit`, the button will submit the surrounding form. Note that the default * value is `button` instead of `submit`, which is opposite of how native `