import { css, html } from 'lit'; import { property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { styleMap } from 'lit/directives/style-map.js'; import { BootstrapElement, defineElement, type Variant } from '@bootstrap-wc/core'; export type SpinnerType = 'border' | 'grow'; export type SpinnerSize = 'sm' | 'md'; /** * `` — Bootstrap spinner (border or grow variant). * * For a custom size, set the `width` and `height` attributes (any CSS * length, e.g. `width="3rem" height="3rem"`). These are forwarded as * inline styles on the inner spinner element and override the * `spinner-{type}` defaults. */ export class BsSpinner extends BootstrapElement { // The inner `.spinner-*` element is `display: inline-block` with its own // intrinsic size. Without a host display value, the host collapses to a // line-height of the surrounding inline context and the inner spinner // overflows. Match `.spinner-border`'s default layout on the host. static override styles = css` :host { display: inline-block; vertical-align: var(--bs-spinner-vertical-align, -0.125em); } `; @property({ type: String }) type: SpinnerType = 'border'; @property({ type: String }) variant?: Variant; @property({ type: String }) size: SpinnerSize = 'md'; @property({ type: String }) label = 'Loading...'; @property({ type: String }) width?: string; @property({ type: String }) height?: string; override render() { const classes = classMap({ [`spinner-${this.type}`]: true, [`spinner-${this.type}-sm`]: this.size === 'sm', [`text-${this.variant}`]: !!this.variant, }); const styles = styleMap({ ...(this.width ? { width: this.width } : {}), ...(this.height ? { height: this.height } : {}), }); return html`
${this.label}
`; } } defineElement('bs-spinner', BsSpinner); declare global { interface HTMLElementTagNameMap { 'bs-spinner': BsSpinner; } }