Files
dees-catalog-mobile/ts_web/elements/00group-ui/dees-mobile-button/dees-mobile-button.ts

225 lines
5.3 KiB
TypeScript
Raw Normal View History

2025-12-22 10:53:15 +00:00
import {
DeesElement,
css,
cssManager,
customElement,
html,
property,
type TemplateResult,
} from '@design.estate/dees-element';
import { mobileComponentStyles } from '../../00componentstyles.js';
import { demoFunc } from './dees-mobile-button.demo.js';
export type ButtonVariant = 'default' | 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'link';
export type ButtonSize = 'sm' | 'md' | 'lg';
declare global {
interface HTMLElementTagNameMap {
'dees-mobile-button': DeesMobileButton;
}
}
@customElement('dees-mobile-button')
export class DeesMobileButton extends DeesElement {
public static demo = demoFunc;
@property({ type: String })
accessor variant: ButtonVariant = 'default';
@property({ type: String })
accessor size: ButtonSize = 'md';
@property({ type: Boolean })
accessor disabled: boolean = false;
@property({ type: Boolean })
accessor loading: boolean = false;
@property({ type: Boolean, reflect: true })
accessor icon: boolean = false;
@property({ type: String })
accessor type: 'button' | 'submit' | 'reset' = 'button';
public static styles = [
cssManager.defaultStyles,
mobileComponentStyles,
css`
:host {
display: inline-block;
}
button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
font-family: inherit;
font-weight: 500;
border: none;
border-radius: calc(var(--dees-radius, 0.5rem) - 2px);
cursor: pointer;
transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1);
outline: none;
position: relative;
white-space: nowrap;
text-decoration: none;
}
button:focus-visible {
outline: 2px solid var(--dees-primary);
outline-offset: 2px;
}
button:active:not(:disabled) {
transform: scale(0.98);
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
/* Sizes */
button.sm {
height: 2rem;
padding: 0 0.75rem;
font-size: 0.75rem;
border-radius: calc(var(--dees-radius, 0.5rem) - 4px);
}
button.md {
height: 2.25rem;
padding: 0 1rem;
font-size: 0.875rem;
}
button.lg {
height: 2.75rem;
padding: 0 2rem;
font-size: 0.875rem;
}
/* Variants - using bdTheme for bright/dark support */
button.default,
button.primary {
background: #3b82f6;
color: #ffffff;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
}
button.default:not(:disabled):hover,
button.primary:not(:disabled):hover {
background: #2563eb;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
button.secondary {
background: ${cssManager.bdTheme('#f4f4f5', '#27272a')};
color: ${cssManager.bdTheme('#18181b', '#fafafa')};
}
button.secondary:not(:disabled):hover {
background: ${cssManager.bdTheme('#e4e4e7', '#3f3f46')};
}
button.outline {
background: transparent;
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#3f3f46')};
}
button.outline:not(:disabled):hover {
background: ${cssManager.bdTheme('#f4f4f5', '#27272a')};
border-color: ${cssManager.bdTheme('#d4d4d8', '#52525b')};
}
button.ghost {
background-color: transparent;
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
}
button.ghost:not(:disabled):hover {
background: ${cssManager.bdTheme('#f4f4f5', '#27272a')};
}
button.destructive {
background: #dc2626;
color: #ffffff;
}
button.destructive:not(:disabled):hover {
background: #b91c1c;
}
button.link {
background: transparent;
color: #3b82f6;
text-decoration: underline;
text-underline-offset: 4px;
padding: 0;
height: auto;
}
button.link:not(:disabled):hover {
text-decoration: underline;
}
/* Loading state */
.spinner {
width: 1em;
height: 1em;
border: 2px solid transparent;
border-top-color: currentColor;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Icon-only button */
:host([icon]) button {
width: 2.25rem;
height: 2.25rem;
padding: 0;
}
:host([icon]) button.sm {
width: 2rem;
height: 2rem;
}
:host([icon]) button.lg {
width: 2.75rem;
height: 2.75rem;
}
`,
];
private handleClick(e: MouseEvent) {
if (this.disabled || this.loading) {
e.preventDefault();
e.stopPropagation();
return;
}
}
public render(): TemplateResult {
return html`
<button
type=${this.type}
class=${`${this.variant} ${this.size}`}
?disabled=${this.disabled || this.loading}
@click=${this.handleClick}
>
${this.loading ? html`<span class="spinner"></span>` : ''}
<slot></slot>
</button>
`;
}
}