168 lines
3.9 KiB
TypeScript
168 lines
3.9 KiB
TypeScript
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<string, IViewDefinition> = new Map();
|
|
private instances: Map<string, HTMLElement> = 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;
|
|
}
|
|
}
|