@razen-core/zenweb
Version:
A minimalist TypeScript framework for building reactive web applications with no virtual DOM
88 lines • 2.97 kB
JavaScript
/**
* ZenWeb Renderer
* Main rendering engine using vanilla JavaScript (no VDOM)
*/
import { mount, unmount, replaceChildren } from './dom.js';
import { subscribe } from './state.js';
import { debugLog } from './debug.js';
const componentInstances = new WeakMap();
let renderCounter = 0;
/**
* Render a component to a container element
* Component should return an HTMLElement
*/
export function render(component, container, props = {}) {
const instance = {
element: null,
container,
update: () => { },
unmount: () => { }
};
const update = () => {
const renderId = ++renderCounter;
debugLog('Renderer', `Render #${renderId} starting`);
try {
// Execute component function to get DOM element
const newElement = component(props);
debugLog('Renderer', `Render #${renderId} component executed`);
if (!instance.element) {
// Initial mount
debugLog('Renderer', `Render #${renderId} initial mount`);
mount(newElement, container);
instance.element = newElement;
}
else {
// Update - replace old element with new one
debugLog('Renderer', `Render #${renderId} updating DOM`);
if (instance.element.parentElement) {
instance.element.parentElement.replaceChild(newElement, instance.element);
}
instance.element = newElement;
}
debugLog('Renderer', `Render #${renderId} complete`);
}
catch (error) {
console.error('Error rendering component:', error);
}
};
const unmountFn = () => {
if (instance.element) {
unmount(instance.element);
instance.element = null;
}
if (instance.unsubscribe) {
instance.unsubscribe();
}
};
instance.update = update;
instance.unmount = unmountFn;
// Initial render
update();
componentInstances.set(component, instance);
return instance;
}
/**
* Create a component that auto-updates when state changes
*/
export function createComponent(component, stateObj, props = {}) {
const element = component(props);
// If state object provided, subscribe to changes and re-render
if (stateObj && stateObj.__listeners) {
const container = document.createElement('div');
container.appendChild(element);
subscribe(stateObj, () => {
const newElement = component(props);
replaceChildren(container, [newElement]);
});
return container;
}
return element;
}
/**
* Mount a component and return cleanup function
*/
export function mountComponent(component, container, props = {}) {
const instance = render(component, container, props);
return () => instance.unmount();
}
//# sourceMappingURL=renderer.js.map