UNPKG

mcp-quiz-server

Version:

🧠 AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.

136 lines (121 loc) • 4.05 kB
/** * @moduleName: Base Component Class - Frontend Architecture Foundation * @version: 2.0.0 * @since: 2025-07-23 * @lastUpdated: 2025-07-24 * @projectSummary: MCP Quiz Server - Base component class providing lifecycle management and event handling for all UI components * @techStack: TypeScript, DOM API, Event System, Component Architecture * @dependency: EventEmitter utility class * @interModuleDependency: All frontend components extend this base class * @requirementsTraceability: * {@link Requirements.REQ_ARCH_001} (Component Integration System) * {@link Requirements.REQ_UI_001} (Component Architecture Foundation) * @briefDescription: Abstract base class that provides common functionality for all UI components including lifecycle management, event handling, DOM manipulation, and cleanup * @methods: mount, unmount, render, bindEvents, onMount, onUnmount, destroy * @contributors: Architecture Team, GitHub Copilot * @examples: class MyComponent extends Component with render method implementation * @vulnerabilitiesAssessment: DOM element validation prevents XSS, proper event cleanup prevents memory leaks */ import { EventEmitter } from '../utils/index'; export abstract class Component extends EventEmitter { protected element: HTMLElement; protected mounted = false; /** * @description Creates a new component instance * @param {HTMLElement | string} element - DOM element or CSS selector * @throws {Error} If element selector is not found in DOM */ constructor(element: HTMLElement | string) { super(); if (typeof element === 'string') { const found = document.querySelector(element); if (!found) { throw new Error(`Element not found: ${element}`); } this.element = found as HTMLElement; } else { this.element = element; } } /** * @description Mounts the component to the DOM, rendering content and binding events * @returns {void} */ mount(): void { if (this.mounted) return; this.mounted = true; this.render(); this.bindEvents(); this.onMount(); } /** * @description Unmounts the component, cleaning up events and resources * @returns {void} */ unmount(): void { if (!this.mounted) return; this.mounted = false; this.unbindEvents(); this.onUnmount(); } /** * @description Abstract method for rendering component content - must be implemented by subclasses * @returns {void} */ protected abstract render(): void; protected bindEvents(): void { // Override in subclasses } protected unbindEvents(): void { // Override in subclasses } protected onMount(): void { // Override in subclasses } protected onUnmount(): void { // Override in subclasses } protected updateElement( updates: Partial<{ innerHTML: string; textContent: string; className: string; hidden: boolean; }> ): void { if (updates.innerHTML !== undefined) { this.element.innerHTML = updates.innerHTML; } if (updates.textContent !== undefined) { this.element.textContent = updates.textContent; } if (updates.className !== undefined) { this.element.className = updates.className; } if (updates.hidden !== undefined) { this.element.hidden = updates.hidden; } } /** * @description Shows the component by removing hidden class * @returns {void} */ show(): void { this.element.classList.remove('hidden'); } /** * @description Hides the component by adding hidden class * @returns {void} */ hide(): void { this.element.classList.add('hidden'); } /** * @description Toggles component visibility * @param {boolean} [force] - Optional force parameter for toggle * @returns {void} */ toggle(force?: boolean): void { this.element.classList.toggle('hidden', force); } }