import { html, render, type TemplateResult } from '@design.estate/dees-element'; import type { IViewDefinition } from '../../interfaces/appconfig.js'; /** * Registry for managing views and their lifecycle */ export class ViewRegistry { private views: Map = new Map(); private instances: Map = new Map(); private currentViewId: string | null = null; /** * Register a single view */ public register(view: IViewDefinition): void { if (this.views.has(view.id)) { console.warn(`View with id "${view.id}" already registered. Overwriting.`); } this.views.set(view.id, view); } /** * Register multiple views */ public registerAll(views: IViewDefinition[]): void { views.forEach((view) => this.register(view)); } /** * Get a view definition by ID */ public get(viewId: string): IViewDefinition | undefined { return this.views.get(viewId); } /** * Get all registered view IDs */ public getViewIds(): string[] { return Array.from(this.views.keys()); } /** * Get all views */ public getAll(): IViewDefinition[] { return Array.from(this.views.values()); } /** * Get route for a view */ public getRoute(viewId: string): string { const view = this.views.get(viewId); return view?.route || view?.id || ''; } /** * Find view by route */ public findByRoute(route: string): IViewDefinition | undefined { for (const view of this.views.values()) { const viewRoute = view.route || view.id; if (viewRoute === route) { return view; } } return undefined; } /** * Render a view's content into a container */ public renderView(viewId: string, container: HTMLElement): HTMLElement | null { const view = this.views.get(viewId); if (!view) { console.error(`View "${viewId}" not found in registry`); return null; } // Clear container container.innerHTML = ''; let element: HTMLElement; if (typeof view.content === 'string') { // Tag name string element = document.createElement(view.content); } else if (typeof view.content === 'function') { // Check if it's a class constructor or template function if (view.content.prototype instanceof HTMLElement) { // Element class constructor element = new (view.content as new () => HTMLElement)(); } else { // Template function - wrap in a container and use Lit's render const wrapper = document.createElement('div'); wrapper.className = 'view-content-wrapper'; wrapper.style.cssText = 'display: contents;'; const template = (view.content as () => TemplateResult)(); render(template, wrapper); element = wrapper; } } else { console.error(`Invalid content type for view "${viewId}"`); return null; } container.appendChild(element); this.instances.set(viewId, element); this.currentViewId = viewId; return element; } /** * Get currently active view ID */ public getCurrentViewId(): string | null { return this.currentViewId; } /** * Get cached instance of a view */ public getInstance(viewId: string): HTMLElement | undefined { return this.instances.get(viewId); } /** * Clear all instances */ public clearInstances(): void { this.instances.clear(); this.currentViewId = null; } /** * Unregister a view */ public unregister(viewId: string): boolean { this.instances.delete(viewId); return this.views.delete(viewId); } /** * Clear the registry */ public clear(): void { this.views.clear(); this.instances.clear(); this.currentViewId = null; } /** * Check if a view is registered */ public has(viewId: string): boolean { return this.views.has(viewId); } /** * Get the number of registered views */ public get size(): number { return this.views.size; } }