/** * el-ui — Activation-based frontend framework. * * State is an Engram graph. Reactivity is spreading activation. * * Core exports: * Graph — in-browser Engram graph (nodes, edges, activation) * Renderer — DOM mounting and patching * Router — graph-based routing * Component — base class for el-ui components * mount() — attach a component to the DOM * * @module el-ui */ export { Graph } from './graph.js'; export { Renderer } from './renderer.js'; export { Router } from './router.js'; export { spreadActivation, activationStrength, reachableNodes, PRUNE_THRESHOLD, } from './activation.js'; import { Graph } from './graph.js'; import { Renderer } from './renderer.js'; /** * Base class for all el-ui components. * * Subclasses override: * render() → returns HTML string * onMount() → called after first mount (optional) * * Subclasses call: * setState(name, value) → update state, trigger activation, patch DOM */ export class Component { constructor(props = {}) { /** @type {Graph} */ this._graph = new Graph(); /** @type {Record} state node IDs */ this._stateNodes = {}; /** @type {Record} current state values */ this._state = {}; /** @type {Record} current prop values */ this.props = props; /** @type {Renderer|null} */ this._renderer = null; } /** * Update a named state variable. * Triggers spreading activation in the graph, then patches the DOM. * * @param {string} name * @param {any} value */ setState(name, value) { if (this._stateNodes[name] !== undefined) { this._graph.update(this._stateNodes[name], value); // Graph.update() notifies subscribers, which call _renderer.patch(). // Belt-and-suspenders: also patch directly in case no subscribers yet. if (this._renderer) this._renderer.patch(); } } /** * Render a child component inline, sharing the parent's activation graph. * Used by the compiler to embed child components in template strings. * * @param {typeof Component} ComponentClass * @param {Record} props * @returns {string} */ _child(ComponentClass, props = {}) { try { const instance = new ComponentClass(props); // Share the parent graph so child state participates in the same // activation surface. Child state changes can propagate upward. instance._graph = this._graph; return instance.render(); } catch (e) { console.warn(`el-ui: failed to render child ${ComponentClass?.name}`, e); return ``; } } /** * Override to return the component's HTML string. * All state and props are accessible via this._state / this.props. * @returns {string} */ render() { return ''; } /** * Called once after the component is first mounted to the DOM. * Override for side effects (timers, fetch calls, subscriptions). */ onMount() {} } /** * Mount a component to a DOM element and start the el-ui runtime. * * @param {typeof Component} ComponentClass the component class to mount * @param {string} selector CSS selector for the root element * @param {Record} [props={}] initial props * @returns {Component} the live component instance * * @example * import { mount } from './el-ui.js'; * import { Counter } from './counter.js'; * mount(Counter, '#app'); */ export function mount(ComponentClass, selector, props = {}) { const root = document.querySelector(selector); if (!root) { throw new Error(`el-ui: no element found for selector '${selector}'`); } const component = new ComponentClass(props); const renderer = new Renderer(root, component); component._renderer = renderer; renderer.mount(); return component; } export default { mount, Component, Graph, Renderer };