import { DeesElement, html, property, customElement, cssManager, css, unsafeCSS, type TemplateResult, } from '@design.estate/dees-element'; // Import design tokens import { colors, bdTheme } from './00colors.js'; import { spacing, radius, shadows, transitions } from './00tokens.js'; import { fontFamilies, typography } from './00fonts.js'; declare global { interface HTMLElementTagNameMap { 'sio-button': SioButton; } } @customElement('sio-button') export class SioButton extends DeesElement { public static demo = () => html`
Default Primary Delete Outline Ghost Small Large Disabled
`; @property({ type: String }) public text: string = ''; @property({ type: String }) public type: 'default' | 'primary' | 'destructive' | 'outline' | 'ghost' = 'default'; @property({ type: String }) public size: 'sm' | 'default' | 'lg' = 'default'; @property({ type: Boolean, reflect: true }) public disabled: boolean = false; @property({ type: String }) public status: 'normal' | 'pending' | 'success' | 'error' = 'normal'; public static styles = [ cssManager.defaultStyles, css` :host { display: inline-block; font-family: ${unsafeCSS(fontFamilies.sans)}; } :host([disabled]) { pointer-events: none; } .button { position: relative; display: inline-flex; align-items: center; justify-content: center; white-space: nowrap; border-radius: ${unsafeCSS(radius.md)}; font-weight: 500; transition: ${unsafeCSS(transitions.all)}; cursor: pointer; user-select: none; outline: none; border: 1px solid transparent; gap: ${unsafeCSS(spacing["2"])}; font-size: 0.875rem; line-height: 1.5; } /* Size variants */ .button.size-sm { height: 32px; padding: 0 ${unsafeCSS(spacing["3"])}; font-size: 13px; } .button.size-default { height: 36px; padding: 0 ${unsafeCSS(spacing["4"])}; font-size: 14px; } .button.size-lg { height: 44px; padding: 0 ${unsafeCSS(spacing["6"])}; font-size: 16px; } /* Type variants */ .button.default { background: ${bdTheme('background')}; color: ${bdTheme('foreground')}; border-color: ${bdTheme('border')}; box-shadow: ${unsafeCSS(shadows.sm)}; } .button.default:hover:not(.disabled) { background: ${bdTheme('accent')}; border-color: ${bdTheme('accent')}; transform: translateY(-1px); box-shadow: ${unsafeCSS(shadows.md)}; } .button.default:active:not(.disabled) { transform: translateY(0); box-shadow: ${unsafeCSS(shadows.sm)}; } .button.primary { background: ${bdTheme('primary')}; color: ${bdTheme('primaryForeground')}; box-shadow: ${unsafeCSS(shadows.sm)}; } .button.primary:hover:not(.disabled) { opacity: 0.9; transform: translateY(-1px); box-shadow: ${unsafeCSS(shadows.md)}; } .button.primary:active:not(.disabled) { transform: translateY(0); box-shadow: ${unsafeCSS(shadows.sm)}; } .button.destructive { background: ${bdTheme('destructive')}; color: ${bdTheme('destructiveForeground')}; } .button.destructive:hover:not(.disabled) { opacity: 0.9; } .button.destructive:active:not(.disabled) { transform: translateY(1px); } .button.outline { background: transparent; color: ${bdTheme('foreground')}; border-color: ${bdTheme('border')}; } .button.outline:hover:not(.disabled) { background: ${bdTheme('accent')}; color: ${bdTheme('accentForeground')}; } .button.outline:active:not(.disabled) { transform: translateY(1px); } .button.ghost { background: transparent; color: ${bdTheme('foreground')}; border-color: transparent; } .button.ghost:hover:not(.disabled) { background: ${bdTheme('accent')}; color: ${bdTheme('accentForeground')}; border-color: transparent; } .button.ghost:active:not(.disabled) { background: ${bdTheme('accent')}; opacity: 0.8; } /* Status states */ .button.pending { pointer-events: none; opacity: 0.7; } .spinner { position: absolute; left: ${unsafeCSS(spacing["3"])}; animation: spin 1s linear infinite; } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .button.success { background: ${bdTheme('success')}; color: ${bdTheme('successForeground')}; pointer-events: none; } .button.error { background: ${bdTheme('destructive')}; color: ${bdTheme('destructiveForeground')}; pointer-events: none; } /* Disabled state */ .button.disabled { opacity: 0.5; cursor: not-allowed; } /* Focus state */ .button:focus-visible { outline: 2px solid ${bdTheme('ring')}; outline-offset: 2px; } `, ]; public render(): TemplateResult { const buttonClasses = [ 'button', this.type === 'primary' ? 'primary' : this.type, `size-${this.size}`, this.disabled ? 'disabled' : '', this.status, ].filter(Boolean).join(' '); return html` `; } private handleClick(event: MouseEvent) { if (this.disabled || this.status !== 'normal') { event.preventDefault(); event.stopPropagation(); return; } // Dispatch a custom event with any data this.dispatchEvent(new CustomEvent('click', { detail: { originalEvent: event }, bubbles: true, composed: true })); } }