besper-frontend-site-dev-main
Version:
Professional B-esper Frontend Site - Site-wide integration toolkit for full website bot deployment
105 lines (88 loc) • 2.93 kB
text/typescript
// Button component for consistent UI interactions
import { Component } from './Component.js';
import { ButtonProps } from '../../types/components.types.js';
import { createElement } from '../../utils/dom.js';
export class Button extends Component {
private props: ButtonProps;
constructor(props: ButtonProps) {
super(props);
this.props = props;
}
protected createElement(): HTMLElement {
const button = createElement(
'button',
this.getButtonClasses()
) as HTMLButtonElement;
button.id = this.id;
button.innerHTML = this.render();
button.disabled = this.props.disabled || false;
this.setupEventListeners(button);
return button;
}
protected render(): string {
if (this.props.loading) {
return `
<span class="button-spinner">
<svg class="animate-spin" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 12a9 9 0 11-6.219-8.56"/>
</svg>
</span>
<span>Loading...</span>
`;
}
return '<span><!-- Button content will be set via setText() --></span>';
}
private getButtonClasses(): string {
const baseClass = 'besper-button';
const variantClass = `button-${this.props.variant || 'primary'}`;
const sizeClass = `button-${this.props.size || 'md'}`;
const stateClasses = [
this.props.disabled ? 'button-disabled' : '',
this.props.loading ? 'button-loading' : '',
].filter(Boolean);
return [baseClass, variantClass, sizeClass, ...stateClasses, this.className]
.filter(Boolean)
.join(' ');
}
private setupEventListeners(button: HTMLButtonElement): void {
if (this.props.onClick) {
this.addEventListener(button, 'click', e => {
e.preventDefault();
if (!this.props.disabled && !this.props.loading && this.props.onClick) {
this.props.onClick();
}
});
}
}
public setText(text: string): void {
if (!this.props.loading) {
const span = this.element.querySelector('span') as HTMLElement;
if (span) {
span.textContent = text;
}
}
}
public setDisabled(disabled: boolean): void {
this.props.disabled = disabled;
(this.element as HTMLButtonElement).disabled = disabled;
this.updateClasses();
}
public setLoading(loading: boolean): void {
this.props.loading = loading;
(this.element as HTMLButtonElement).disabled =
loading || this.props.disabled || false;
this.element.innerHTML = this.render();
this.updateClasses();
}
public setVariant(variant: ButtonProps['variant']): void {
this.props.variant = variant;
this.updateClasses();
}
public setSize(size: ButtonProps['size']): void {
this.props.size = size;
this.updateClasses();
}
private updateClasses(): void {
this.element.className = this.getButtonClasses();
}
}