const targetMap = new WeakMap(); let activeEffect = null; const root = document.getElementById("root"); function createElement(tagName, props = {}, children = []) { const el = document.createElement(tagName); for (const [key, value] of Object.entries(props || {})) { if (key.startsWith("on") && typeof value === "function") { el.addEventListener(key.substring(2).toLowerCase(), value); } else if (key === "style" && typeof value === "object") { Object.assign(el.style, value); } else { el.setAttribute(key, value); } } const appendChild = (child) => { if (Array.isArray(child)) { child.forEach(appendChild); } else if (typeof child === "function") { const placeholder = document.createTextNode(""); el.appendChild(placeholder); e(() => { placeholder.textContent = child() ?? ""; }); } else if (child instanceof Node) { el.appendChild(child); } else if (child != null) { el.appendChild(document.createTextNode(String(child))); } }; children.forEach(appendChild); return el; } function track(target, key) { if (!activeEffect) { return; } let depsMap = targetMap.get(target); if (!depsMap) { depsMap = new Map(); targetMap.set(target, depsMap); } let dep = depsMap.get(key); if (!dep) { dep = new Set(); depsMap.set(key, dep); } dep.add(activeEffect); } function trigger(target, key) { const depsMap = targetMap.get(target); if (!depsMap) { return; } const dep = depsMap.get(key); if (dep) { dep.forEach((effect) => effect()); } } //** // Create a reactive value, the value is at .value. // To use this in element props you need to supply the .value read as a function. // */ export function r(target) { target = { value: target }; return new Proxy(target, { get(obj, key, receiver) { track(obj, key); return Reflect.get(obj, key, receiver); }, set(obj, key, value, receiver) { const result = Reflect.set(obj, key, value, receiver); trigger(obj, key); return result; }, }); } //** // Run code when value changes // */ export function e(fn) { let active = true; const runner = () => { if (active) { activeEffect = runner; fn(); activeEffect = null; } }; runner(); runner.stop = () => { active = false; }; return runner; } export function gqp(key) { return new URLSearchParams(location.search).get(key) } export function sqp(query) { console.log(query); if ('URLSearchParams' in window) { const url = new URL(window.location) for (const key of Object.keys(query)) { const value = encodeURIComponent(query[key]) if (!value || value === "") url.searchParams.delete(key) else url.searchParams.set(key, value) } history.pushState(null, '', url); } } //** // Combine elements // */ export function c(a, b) { const normalize = (x) => (x == null ? [] : Array.isArray(x) ? x : [x]); return [...normalize(a), ...normalize(b)]; } //** // Mount element to a target (target is #root by default) // */ export async function m(component, target = root) { if (typeof component === "function") { component = await component(); } if (Array.isArray(component)) { target.append(...component); } else { target.appendChild(component); } } export function css(styleObject) { return Object.entries(styleObject).map(([key, value]) => { const kebabKey = key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); return `${kebabKey}: ${value}`; }).join("; "); } //** // Create element // */ export function t(name, props, ...children) { if (typeof name === "function") { return name({ ...props, children }); } return createElement(name, props, children); }