48 lines
2.3 KiB
JavaScript
48 lines
2.3 KiB
JavaScript
class UiButton extends HTMLElement {
|
|
static get observedAttributes() { return ['variant', 'size', 'loading', 'disabled']; }
|
|
connectedCallback() { this.#render(); }
|
|
attributeChangedCallback() { this.#render(); }
|
|
|
|
#render() {
|
|
const variant = this.getAttribute('variant') || 'primary';
|
|
const size = this.getAttribute('size') || 'md';
|
|
const loading = this.hasAttribute('loading');
|
|
const disabled = this.hasAttribute('disabled') || loading;
|
|
const pad = { sm: '.35rem .75rem', md: '.5rem 1rem', lg: '.65rem 1.25rem' }[size] || '.5rem 1rem';
|
|
const fs = { sm: '.813rem', md: '.875rem', lg: '1rem' }[size] || '.875rem';
|
|
|
|
if (!this.shadowRoot) this.attachShadow({ mode: 'open' });
|
|
this.shadowRoot.innerHTML = `
|
|
<style>
|
|
:host { display: inline-flex; }
|
|
button {
|
|
display: inline-flex; align-items: center; gap: .4rem;
|
|
padding: ${pad}; border: none; border-radius: var(--radius);
|
|
font-size: ${fs}; font-weight: 600; cursor: pointer;
|
|
transition: opacity .15s, background .15s;
|
|
white-space: nowrap;
|
|
}
|
|
button:disabled { opacity: .5; cursor: not-allowed; }
|
|
.primary { background: var(--teal); color: #fff; }
|
|
.primary:hover:not(:disabled) { background: var(--teal-dk); }
|
|
.ghost { background: transparent; border: 1px solid var(--border); color: var(--text); }
|
|
.ghost:hover:not(:disabled) { background: var(--surface-2); }
|
|
.danger { background: var(--danger); color: #fff; }
|
|
.danger:hover:not(:disabled) { opacity: .88; }
|
|
.icon { background: transparent; border: none; color: var(--text-muted); padding: .4rem; border-radius: var(--radius-sm); }
|
|
.icon:hover:not(:disabled) { background: var(--surface-2); color: var(--text); }
|
|
.ring {
|
|
width: 14px; height: 14px; border: 2px solid rgba(255,255,255,.4);
|
|
border-top-color: #fff; border-radius: 50%;
|
|
animation: spin .6s linear infinite; flex-shrink: 0;
|
|
}
|
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
</style>
|
|
<button class="${variant}" ${disabled ? 'disabled' : ''}>
|
|
${loading ? '<div class="ring"></div>' : ''}
|
|
<slot></slot>
|
|
</button>`;
|
|
}
|
|
}
|
|
customElements.define('ui-button', UiButton);
|