@gleb.askerko/componentkit-js
Version:
Lightweight, framework-agnostic JavaScript component library with progress gift components
182 lines (145 loc) • 4.36 kB
JavaScript
export class Card {
constructor(options = {}) {
this.options = {
title: '',
content: '',
variant: 'default',
actions: [],
className: '',
...options
};
this.element = null;
this.container = null;
this.actionButtons = [];
}
render(selector) {
this.container = typeof selector === 'string'
? document.querySelector(selector)
: selector;
if (!this.container) {
throw new Error(`Container not found: ${selector}`);
}
this.element = this.createElement();
this.container.appendChild(this.element);
this.bindEvents();
return this;
}
createElement() {
const card = document.createElement('div');
card.className = this.getCardClasses();
if (this.options.title) {
const header = this.createHeader();
card.appendChild(header);
}
if (this.options.content) {
const body = this.createBody();
card.appendChild(body);
}
if (this.options.actions && this.options.actions.length > 0) {
const footer = this.createFooter();
card.appendChild(footer);
}
return card;
}
createHeader() {
const header = document.createElement('div');
header.className = 'ck-card-header';
const title = document.createElement('h3');
title.className = 'ck-card-title';
title.textContent = this.options.title;
header.appendChild(title);
return header;
}
createBody() {
const body = document.createElement('div');
body.className = 'ck-card-body';
if (typeof this.options.content === 'string') {
const content = document.createElement('p');
content.className = 'ck-card-content';
content.textContent = this.options.content;
body.appendChild(content);
} else if (this.options.content instanceof HTMLElement) {
body.appendChild(this.options.content);
}
return body;
}
createFooter() {
const footer = document.createElement('div');
footer.className = 'ck-card-footer';
this.options.actions.forEach((action, index) => {
const button = this.createActionButton(action, index);
footer.appendChild(button);
this.actionButtons.push(button);
});
return footer;
}
createActionButton(action, index) {
const button = document.createElement('button');
button.className = `ck-button ck-card-action ${action.variant ? `ck-button--${action.variant}` : 'ck-button--primary'}`;
button.textContent = action.text || 'Action';
button.disabled = action.disabled || false;
if (action.onClick) {
button.addEventListener('click', (e) => {
action.onClick(e, index);
});
}
return button;
}
getCardClasses() {
const baseClasses = 'ck-card';
const variantClasses = {
default: 'ck-card--default',
elevated: 'ck-card--elevated',
outlined: 'ck-card--outlined'
};
return [
baseClasses,
variantClasses[this.options.variant] || variantClasses.default,
this.options.className
].filter(Boolean).join(' ');
}
bindEvents() {
// Card-level events can be added here
}
update(newOptions) {
this.options = { ...this.options, ...newOptions };
if (this.element) {
// Remove old element and create new one
const parent = this.element.parentNode;
parent.removeChild(this.element);
this.actionButtons = [];
this.element = this.createElement();
parent.appendChild(this.element);
this.bindEvents();
}
return this;
}
setTitle(title) {
return this.update({ title });
}
setContent(content) {
return this.update({ content });
}
addAction(action) {
const actions = [...this.options.actions, action];
return this.update({ actions });
}
removeAction(index) {
const actions = this.options.actions.filter((_, i) => i !== index);
return this.update({ actions });
}
destroy() {
// Clean up action button event listeners
this.actionButtons.forEach(button => {
if (button.parentNode) {
button.parentNode.removeChild(button);
}
});
if (this.element && this.element.parentNode) {
this.element.parentNode.removeChild(this.element);
}
this.element = null;
this.container = null;
this.actionButtons = [];
}
}