UNPKG

stylescape

Version:

Stylescape is a visual identity framework developed by Scape Agency.

247 lines 8.1 kB
import { getComponent } from "./registry.js"; const instanceStore = new WeakMap(); const config = { attributePrefix: "data-ss", autoInitEnabled: true, observerEnabled: true, debug: true, }; let observer = null; function parseConfig(element, componentName, defaults = {}) { const result = { ...defaults }; const prefix = `${config.attributePrefix}-${componentName}-`; const jsonAttr = `${config.attributePrefix}-${componentName}-config`; const jsonConfig = element.getAttribute(jsonAttr); if (jsonConfig) { try { Object.assign(result, JSON.parse(jsonConfig)); } catch (e) { console.warn(`[Stylescape] Invalid JSON config for ${componentName}:`, e); } } Array.from(element.attributes).forEach((attr) => { if (attr.name.startsWith(prefix) && attr.name !== jsonAttr) { const key = attr.name .slice(prefix.length) .replace(/-([a-z])/g, (_, c) => c.toUpperCase()); let value = attr.value; if (value === "true") value = true; else if (value === "false") value = false; else if (!isNaN(Number(value)) && value !== "") value = Number(value); result[key] = value; } }); return result; } function initComponent(element, componentName) { const entry = getComponent(componentName); if (!entry) { if (config.debug) { console.warn(`[Stylescape] Unknown component: ${componentName}`); } return null; } let instances = instanceStore.get(element); if (instances?.has(componentName)) { if (config.debug) { console.log(`[Stylescape] Component "${componentName}" already initialized on element`); } return instances.get(componentName); } const componentConfig = parseConfig(element, componentName, entry.defaults); try { const instance = entry.handler(element, componentConfig); if (!instances) { instances = new Map(); instanceStore.set(element, instances); } instances.set(componentName, instance); element.setAttribute(`${config.attributePrefix}-${componentName}-initialized`, "true"); if (config.debug) { console.log(`[Stylescape] Initialized "${componentName}" on`, element); } return instance; } catch (e) { console.error(`[Stylescape] Error initializing "${componentName}":`, e); return null; } } function initElement(element) { const ssAttr = element.getAttribute(config.attributePrefix); console.log(`[Stylescape] Processing element:`, { element: element.tagName, id: element.id, dataSs: ssAttr, }); if (!ssAttr) return; if (element.hasAttribute(`${config.attributePrefix}-manual`)) { console.log(`[Stylescape] Skipping manual element:`, element); return; } const componentNames = ssAttr.trim().split(/\s+/); console.log(`[Stylescape] Initializing components:`, componentNames); componentNames.forEach((name) => { if (name) { initComponent(element, name.toLowerCase()); } }); } export function init(root = document.body) { console.log("[Stylescape] Auto-init starting...", { root: root.tagName, autoInitEnabled: config.autoInitEnabled, }); if (!config.autoInitEnabled) { if (config.debug) { console.log("[Stylescape] Auto-init disabled, skipping"); } return; } const selector = `[${config.attributePrefix}]`; const elements = root.querySelectorAll(selector); console.log(`[Stylescape] Found ${elements.length} elements with ${selector}`); if (root instanceof HTMLElement && root.hasAttribute(config.attributePrefix)) { initElement(root); } elements.forEach((element) => initElement(element)); console.log(`[Stylescape] Auto-init complete. Initialized ${elements.length} elements`); } export function getInstance(element, componentName) { const instances = instanceStore.get(element); if (!instances) return null; if (componentName) { return instances.get(componentName.toLowerCase()) || null; } const values = instances.values(); const first = values.next(); return first.done ? null : first.value; } export function getAllInstances(element) { return instanceStore.get(element) || null; } export function reinit(element, componentName) { destroy(element, componentName); if (componentName) { initComponent(element, componentName); } else { initElement(element); } } export function destroy(element, componentName) { const instances = instanceStore.get(element); if (!instances) return; const destroyInstance = (name, instance) => { if (instance && typeof instance.destroy === "function") { try { instance.destroy(); } catch (e) { console.warn(`[Stylescape] Error destroying "${name}":`, e); } } instances.delete(name); element.removeAttribute(`${config.attributePrefix}-${name}-initialized`); if (config.debug) { console.log(`[Stylescape] Destroyed "${name}" on`, element); } }; if (componentName) { const instance = instances.get(componentName.toLowerCase()); if (instance) { destroyInstance(componentName.toLowerCase(), instance); } } else { instances.forEach((instance, name) => destroyInstance(name, instance)); instanceStore.delete(element); } } export function observe(root = document.body) { if (!config.observerEnabled) return; if (observer) { observer.disconnect(); } observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node instanceof HTMLElement) { if (node.hasAttribute(config.attributePrefix)) { initElement(node); } const descendants = node.querySelectorAll(`[${config.attributePrefix}]`); descendants.forEach((el) => initElement(el)); } }); mutation.removedNodes.forEach((node) => { if (node instanceof HTMLElement) { if (instanceStore.has(node)) { destroy(node); } const descendants = node.querySelectorAll(`[${config.attributePrefix}]`); descendants.forEach((el) => { if (instanceStore.has(el)) { destroy(el); } }); } }); }); }); observer.observe(root, { childList: true, subtree: true, }); if (config.debug) { console.log("[Stylescape] Observer started"); } } export function stopObserving() { if (observer) { observer.disconnect(); observer = null; if (config.debug) { console.log("[Stylescape] Observer stopped"); } } } export function setAutoInit(enabled) { config.autoInitEnabled = enabled; } export function setObserver(enabled) { config.observerEnabled = enabled; if (!enabled && observer) { stopObserving(); } } export function setDebug(enabled) { config.debug = enabled; } export function setAttributePrefix(prefix) { config.attributePrefix = prefix; } export function autoStart() { if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", () => { init(); observe(); }); } else { init(); observe(); } } //# sourceMappingURL=autoInit.js.map