import '../nile-icon'; import { classMap } from 'lit/directives/class-map.js'; import { customElement, property, query, state } from 'lit/decorators.js'; import { FormControlController, validValidityState } from '../internal/form'; import { HasSlotController } from '../internal/slot'; import { html } from 'lit'; import { ifDefined } from 'lit/directives/if-defined.js'; import { watch } from '../internal/watch'; import { styles } from './nile-button.css'; import type { CSSResultGroup, TemplateResult } from 'lit'; import type { NileFormControl } from '../internal/nile-element'; import NileElement from '../internal/nile-element'; import { literal } from 'lit/static-html.js'; /** * @summary Buttons represent actions that are available to the user. * @status stable * @since 2.0 * * @dependency nile-icon * @dependency nile-spinner * * @event nile-blur - Emitted when the button loses focus. * @event nile-focus - Emitted when the button gains focus. * @event nile-invalid - Emitted when the form control has been checked for validity and its constraints aren't satisfied. * * @slot - The button's label. * @slot prefix - A presentational prefix icon or similar element. * @slot suffix - A presentational suffix icon or similar element. * * @csspart base - The component's base wrapper. * @csspart prefix - The container that wraps the prefix. * @csspart label - The button's label. * @csspart suffix - The container that wraps the suffix. * @csspart caret - The button's caret icon, an `` element. */ @customElement('nile-button') export class NileButton extends NileElement implements NileFormControl { static styles: CSSResultGroup = styles; private readonly formControlController = new FormControlController(this, { form: input => { // Buttons support a form attribute that points to an arbitrary form, so if this attribute is 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'); }, assumeInteractionOn: ['click'], }); private readonly hasSlotController = new HasSlotController( this, '[default]', 'prefix', 'suffix' ); @query('.button') button: HTMLButtonElement | HTMLLinkElement; @state() private hasFocus = false; @state() invalid = false; @property() title = ''; // make reactive to pass through /** The button's theme variant. */ @property({ reflect: true }) variant: | 'primary' | 'secondary' | 'tertiary' | 'caution' | 'ghost' | 'destructive' | 'secondary-grey' | 'secondary-blue' = 'primary'; /** The button's size. */ @state() size = 'medium'; /** Draws the button with a caret. Used to indicate that the button triggers a dropdown menu or similar behavior. */ @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 circular icon button. When this attribute is present, the button expects a single `` in the * default slot. */ @property({ type: Boolean, reflect: true }) circle = false; /** * The type of button. Note that the default value is `button` instead of `submit`, which is opposite of how native * ` `; } } } export default NileButton; declare global { interface HTMLElementTagNameMap { 'nile-button': NileButton; } }