/** * Dynamic shape registry — replaces the 300-line switch in canvas.html * and the 165-line if-chain in community-sync.ts. * * Each shape class registers itself with `fromData()` and `applyData()`, * so creation and sync are fully data-driven. */ import type { FolkShape } from "./folk-shape"; import type { ShapeData } from "./community-sync"; export interface ShapeRegistration { tagName: string; /** The custom element class (must have fromData/applyData) */ elementClass: typeof HTMLElement & { fromData?(data: ShapeData): HTMLElement; }; } class ShapeRegistry { #registrations = new Map(); /** Register a shape type. */ register(tagName: string, elementClass: ShapeRegistration["elementClass"]): void { this.#registrations.set(tagName, { tagName, elementClass }); } /** Get registration for a tag name. */ getRegistration(tagName: string): ShapeRegistration | undefined { return this.#registrations.get(tagName); } /** Create a new element from ShapeData using the class's static fromData(). */ createElement(data: ShapeData): HTMLElement | null { const reg = this.#registrations.get(data.type); if (!reg) return null; if (typeof reg.elementClass.fromData === "function") { return reg.elementClass.fromData(data); } // Fallback: basic createElement const el = document.createElement(data.type); el.id = data.id; return el; } /** Update an existing element using its instance applyData(). */ updateElement(shape: any, data: ShapeData): void { if (typeof shape.applyData === "function") { shape.applyData(data); } } /** List all registered tag names. */ listAll(): string[] { return Array.from(this.#registrations.keys()); } /** Check if a type is registered. */ has(tagName: string): boolean { return this.#registrations.has(tagName); } } /** Singleton registry instance. */ export const shapeRegistry = new ShapeRegistry();