// src/util.ts function stringToElement(template) { const parser = new DOMParser(); const doc = parser.parseFromString(template, "text/html"); return doc.body.firstChild; } var isText = (node) => { return node.nodeType === Node.TEXT_NODE; }; var isTemplate = (node) => { return node.nodeName === "TEMPLATE"; }; var isElement = (node) => { return node.nodeType === Node.ELEMENT_NODE; }; function isObject(value) { return value !== null && typeof value === "object"; } function isArray(value) { return Array.isArray(value); } function checkAndRemoveAttribute(el, attrName) { const attributeValue = el.getAttribute(attrName); if (attributeValue !== null) { el.removeAttribute(attrName); } return attributeValue; } function findSlotNodes(element) { const slots = []; const findSlots = (node) => { Array.from(node.childNodes).forEach((node2) => { if (isElement(node2)) { if (node2.nodeName === "SLOT") { slots.push({ node: node2, name: node2.getAttribute("name") || "default" }); } if (node2.hasChildNodes()) { findSlots(node2); } } }); }; findSlots(element); return slots; } function findTemplateNodes(element) { const templates = []; const findTemplates = (element2) => { let defaultContentNodes = []; Array.from(element2.childNodes).forEach((node) => { if (isElement(node) || isText(node)) { if (isElement(node) && node.nodeName === "TEMPLATE" && isTemplate(node)) { templates.push({ targetSlotName: node.getAttribute("slot") || "", node }); } else { defaultContentNodes.push(node); } } }); if (defaultContentNodes.length > 0) { const defaultTemplate = document.createElement("template"); defaultTemplate.setAttribute("slot", "default"); defaultContentNodes.forEach((node) => { defaultTemplate.content.appendChild(node); }); templates.push({ targetSlotName: "default", node: defaultTemplate }); } }; findTemplates(element); return templates; } var nextTick = async (f) => { await new Promise( (r) => setTimeout( (_) => requestAnimationFrame((_2) => { f && f(); r(); }) ) ); }; function html(strings, ...values) { const selfClosingTags = ["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"]; let result = strings.reduce((acc, str, i) => acc + str + (values[i] || ""), ""); result = result.replace(/<([a-zA-Z][^\s/>]*)\s*([^>]*?)\/>/g, (match, tagName, attributes) => { if (selfClosingTags.includes(tagName.toLowerCase())) { return match; } return `<${tagName} ${attributes}>`; }); return result; } function toDisplayString(value) { return value == null ? "" : isObject(value) ? JSON.stringify(value, null, 2) : String(value); } function insertAfter(newNode, existingNode) { if (existingNode.nextSibling) { existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling); } else { existingNode?.parentNode?.appendChild(newNode); } } function isPropAttribute(attrName) { if (attrName.startsWith(".")) { return true; } if (attrName.startsWith("{") && attrName.endsWith("}")) { return true; } return false; } function isSpreadProp(attr) { return attr.startsWith("..."); } function isMirrorProp(attr) { return attr.startsWith("{") && attr.endsWith("}"); } function isRegularProp(attr) { return attr.startsWith("."); } function isEventAttribute(attrName) { return attrName.startsWith("@"); } function componentHasPropByName(name, component) { return Object.keys(component?.props ?? {}).some((prop) => prop === name); } function extractAttributeName(attrName) { return attrName.replace(/^\.\.\./, "").replace(/^\./, "").replace(/^{/, "").replace(/}$/, "").replace(/:bind$/, ""); } function dashToCamel(str) { return str.toLowerCase().replace(/-([a-z])/g, (g) => g[1].toUpperCase()); } function extractPropName(attrName) { return dashToCamel(extractAttributeName(attrName)); } function classNames(_) { const classes = []; for (let i = 0; i < arguments.length; i++) { const arg = arguments[i]; if (!arg) continue; const argType = typeof arg; if (argType === "string" || argType === "number") { classes.push(arg); } else if (Array.isArray(arg)) { if (arg.length) { const inner = classNames.apply(null, arg); if (inner) { classes.push(inner); } } } else if (argType === "object") { if (arg.toString === Object.prototype.toString) { for (let key in arg) { if (Object.hasOwnProperty.call(arg, key) && arg[key]) { classes.push(key); } } } else { classes.push(arg.toString()); } } } return classes.join(" "); } // src/directives/attribute.ts var AttributeDirective = class { element; context; expression; attr; extractedAttributeName; previousClasses = []; previousStyles = {}; is = { sameNameProperty: false, bound: false, spread: false, componentProp: false }; constructor({ element, context, attr }) { this.element = element; this.context = context; this.expression = attr.value; this.attr = attr; this.extractedAttributeName = extractAttributeName(attr.name); this.is = { sameNameProperty: attr.name.startsWith("{") && attr.name.endsWith("}"), bound: attr.name.includes(":bind"), spread: attr.name.startsWith("..."), componentProp: false }; if (this.is.sameNameProperty) { this.expression = this.extractedAttributeName; } if (this.is.spread) { this.expression = this.extractedAttributeName; } element.removeAttribute(attr.name); if (this.is.bound) { context.effect(this.update.bind(this)); } else { this.update(); } } update() { let value = evalGet(this.context.scope, this.expression); if (this.is.spread && typeof value === "object") { for (const [key, val] of Object.entries(value)) { this.element.setAttribute(key, String(val)); } } else if ((typeof value === "object" || Array.isArray(value)) && this.extractedAttributeName === "class") { value = classNames(value); const next = value.split(" "); const diff = next.filter((c) => !this.previousClasses.includes(c)).filter(Boolean); const rm = this.previousClasses.filter((c) => !next.includes(c)); diff.forEach((c) => { this.previousClasses.push(c); this.element.classList.add(c); }); rm.forEach((c) => { this.previousClasses = this.previousClasses.filter((addedClass) => addedClass !== c); this.element.classList.remove(c); }); } else if (typeof value === "object" && this.extractedAttributeName === "style") { const next = Object.keys(value); const rm = Object.keys(this.previousStyles).filter((style) => !next.includes(style)); next.forEach((style) => { this.previousStyles[style] = value[style]; this.element.style[style] = value[style]; }); rm.forEach((style) => { this.previousStyles[style] = ""; this.element.style[style] = ""; }); this.previousStyles = value; } else { this.element.setAttribute(this.extractedAttributeName, value); } } }; // src/directives/event.ts var EventDirective = class { element; context; expression; attr; eventCount = 0; constructor({ element, context, attr }) { this.element = element; this.context = context; this.expression = attr.value; this.attr = attr; const eventName = attr.name.replace(/^@/, ""); const parts = eventName.split("."); this.element.addEventListener(parts[0], (event) => { if (parts.includes("prevent")) event.preventDefault(); if (parts.includes("stop")) event.stopPropagation(); if (parts.includes("once") && this.eventCount > 0) return; this.eventCount++; const handler = evalGet(context.scope, attr.value); if (typeof handler === "function") { handler(event); } }); element.removeAttribute(attr.name); } }; // src/directives/for.ts var forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/; var forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/; var stripParensRE = /^\(|\)$/g; var destructureRE = /^[{[]\s*((?:[\w_$]+\s*,?\s*)+)[\]}]$/; var _for = (el, exp, ctx, component, componentProps, allProps) => { const inMatch = exp.match(forAliasRE); if (!inMatch) { console.warn(`invalid :for expression: ${exp}`); return; } const nextNode = el.nextSibling; const parent2 = el.parentElement; const anchor = new Text(""); parent2.insertBefore(anchor, el); parent2.removeChild(el); const sourceExp = inMatch[2].trim(); let valueExp = inMatch[1].trim().replace(stripParensRE, "").trim(); let destructureBindings; let isArrayDestructure = false; let indexExp; let objIndexExp; let keyAttr = "key"; let keyExp = el.getAttribute(keyAttr) || el.getAttribute(keyAttr = ":key") || el.getAttribute(keyAttr = ":key:bind"); if (keyExp) { el.removeAttribute(keyAttr); if (keyAttr === "key") keyExp = JSON.stringify(keyExp); } let match; if (match = valueExp.match(forIteratorRE)) { valueExp = valueExp.replace(forIteratorRE, "").trim(); indexExp = match[1].trim(); if (match[2]) { objIndexExp = match[2].trim(); } } if (match = valueExp.match(destructureRE)) { destructureBindings = match[1].split(",").map((s) => s.trim()); isArrayDestructure = valueExp[0] === "["; } let mounted = false; let blocks; let childCtxs; let keyToIndexMap; const createChildContexts = (source) => { const map = /* @__PURE__ */ new Map(); const ctxs = []; if (isArray(source)) { for (let i = 0; i < source.length; i++) { ctxs.push(createChildContext(map, source[i], i)); } } else if (typeof source === "number") { for (let i = 0; i < source; i++) { ctxs.push(createChildContext(map, i + 1, i)); } } else if (isObject(source)) { let i = 0; for (const key in source) { ctxs.push(createChildContext(map, source[key], i++, key)); } } return [ctxs, map]; }; const createChildContext = (map, value, index, objKey) => { const data = {}; if (destructureBindings) { destructureBindings.forEach((b, i) => data[b] = value[isArrayDestructure ? i : b]); } else { data[valueExp] = value; } if (objKey) { indexExp && (data[indexExp] = objKey); objIndexExp && (data[objIndexExp] = index); } else { indexExp && (data[indexExp] = index); } const childCtx = createScopedContext(ctx, data); const key = keyExp ? evalGet(childCtx.scope, keyExp) : index; map.set(key, index); childCtx.key = key; return childCtx; }; const mountBlock = (ctx2, ref2) => { const block = new Block({ element: el, parentContext: ctx2, replacementType: "replace", component, componentProps, allProps }); block.key = ctx2.key; block.insert(parent2, ref2); return block; }; ctx.effect(() => { const source = evalGet(ctx.scope, sourceExp); const prevKeyToIndexMap = keyToIndexMap; [childCtxs, keyToIndexMap] = createChildContexts(source); if (!mounted) { blocks = childCtxs.map((s) => mountBlock(s, anchor)); mounted = true; } else { for (let i2 = 0; i2 < blocks.length; i2++) { if (!keyToIndexMap.has(blocks[i2].key)) { blocks[i2].remove(); } } const nextBlocks = []; let i = childCtxs.length; let nextBlock; let prevMovedBlock; while (i--) { const childCtx = childCtxs[i]; const oldIndex = prevKeyToIndexMap.get(childCtx.key); let block; if (oldIndex == null) { block = mountBlock(childCtx, nextBlock ? nextBlock.element : anchor); } else { block = blocks[oldIndex]; Object.assign(block.context.scope, childCtx.scope); if (oldIndex !== i) { if (blocks[oldIndex + 1] !== nextBlock || // If the next has moved, it must move too prevMovedBlock === nextBlock) { prevMovedBlock = block; block.insert(parent2, nextBlock ? nextBlock.element : anchor); } } } nextBlocks.unshift(nextBlock = block); } blocks = nextBlocks; } }); return nextNode; }; // src/directives/if.ts function _if(el, exp, ctx, component, componentProps, allProps) { const parent2 = el.parentElement; const anchor = new Comment(":if"); parent2.insertBefore(anchor, el); const branches = [{ exp, el }]; let elseEl; let elseExp; while (elseEl = el.nextElementSibling) { elseExp = null; if (checkAndRemoveAttribute(elseEl, ":else") === "" || (elseExp = checkAndRemoveAttribute(elseEl, ":else-if"))) { parent2.removeChild(elseEl); branches.push({ exp: elseExp, el: elseEl }); } else { break; } } const nextNode = el.nextSibling; parent2.removeChild(el); let block; let activeBranchIndex = -1; const removeActiveBlock = () => { if (block) { parent2.insertBefore(anchor, block.element); block.remove(); block = void 0; } }; ctx.effect(() => { for (let i = 0; i < branches.length; i++) { const { exp: exp2, el: el2 } = branches[i]; if (!exp2 || evalGet(ctx.scope, exp2)) { if (i !== activeBranchIndex) { removeActiveBlock(); block = new Block({ element: el2, parentContext: ctx, replacementType: "replace", component, componentProps, allProps }); block.insert(parent2, anchor); parent2.removeChild(anchor); activeBranchIndex = i; } return; } } activeBranchIndex = -1; removeActiveBlock(); }); return nextNode; } // src/directives/interpolation.ts var delims = /{{\s?(.*?)\s?}}/g; var InterpolationDirective = class { element; context; textNodes = /* @__PURE__ */ new Map(); constructor({ element, context }) { this.element = element; this.context = context; this.findNodes(); this.textNodes.forEach((nodes, expression) => { const trimmedExpression = expression.slice(2, -2).trim(); nodes.forEach((node) => { const getter = (exp = trimmedExpression) => evalGet(this.context.scope, exp, node); context.effect(() => { node.textContent = toDisplayString(getter()); }); }); }); } findNodes() { const textContent = this.element.textContent.trim(); if (textContent?.match(delims)) { const textNodes = textContent.split(/(\{\{\s?[^}]+\s?\}\})/g).filter(Boolean); if (textNodes) { let previousNode = this.element; for (let i = 0; i < textNodes.length; i++) { const textNode = textNodes[i]; if (textNode.match(/\{\{\s?.+\s?\}\}/)) { const newNode = document.createTextNode(textNode); if (i === 0) { this.element.replaceWith(newNode); } else { insertAfter(newNode, previousNode); } previousNode = newNode; if (this.textNodes.has(textNode)) { this.textNodes.get(textNode).push(newNode); } else { this.textNodes.set(textNode, [newNode]); } } else { const newNode = document.createTextNode(textNodes[i]); if (i === 0) { this.element.replaceWith(newNode); } else { insertAfter(newNode, previousNode); } previousNode = newNode; } } } } } update() { } }; // src/directives/show.ts var ShowDirective = class { element; context; expression; originalDisplay; constructor({ element, context, expression }) { this.element = element; this.context = context; this.expression = expression; this.originalDisplay = getComputedStyle(this.element).display; context.effect(this.update.bind(this)); } update() { const shouldShow = Boolean(evalGet(this.context.scope, this.expression)); this.element.style.display = shouldShow ? this.originalDisplay : "none"; } }; // src/directives/teleport.ts function _teleport(el, exp, ctx) { const anchor = new Comment(":teleport"); el.replaceWith(anchor); const target = document.querySelector(exp); if (!target) { console.warn(`teleport target not found: ${exp}`); return; } nextTick(() => { target.appendChild(el); const observer = new MutationObserver((mutationsList) => { mutationsList.forEach((mutation) => { mutation.removedNodes.forEach((removedNode) => { if (removedNode.contains(anchor)) { el.remove(); observer.disconnect(); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); new Block({ element: el, parentContext: ctx }); }); return anchor; } // src/directives/value.ts function isInput(element) { return element instanceof HTMLInputElement; } function isTextarea(element) { return element instanceof HTMLTextAreaElement; } function isSelect(element) { return element instanceof HTMLSelectElement; } var ValueDirective = class { element; context; expression; inputType; constructor({ element, context, expression }) { this.element = element; this.context = context; this.expression = expression; this.inputType = element.getAttribute("type"); if (isInput(element)) { switch (this.inputType) { case "text": case "password": case "number": case "color": element.addEventListener("input", () => { const value = this.inputType === "number" ? element.value ? parseFloat(element.value) : 0 : element.value; evalSet(this.context.scope, expression, value); }); break; case "checkbox": element.addEventListener("change", (e) => { evalSet(this.context.scope, expression, !!e.currentTarget.checked); }); break; case "radio": element.addEventListener("change", (e) => { if (e.currentTarget.checked) { evalSet(this.context.scope, expression, element.getAttribute("value")); } }); break; default: break; } } if (isTextarea(element)) { element.addEventListener("input", () => { evalSet(this.context.scope, expression, element.value); }); } if (isSelect(element)) { element.addEventListener("change", () => { evalSet(this.context.scope, expression, element.value); }); } context.effect(this.updateElementValue.bind(this)); } updateElementValue() { const value = evalGet(this.context.scope, this.expression, this.element); if (isInput(this.element)) { switch (this.inputType) { case "text": case "password": case "number": case "color": this.element.value = value; break; case "checkbox": this.element.checked = !!value; break; case "radio": this.element.checked = this.element.value === value; break; default: break; } } if (isTextarea(this.element)) { this.element.value = value; } if (isSelect(this.element)) { this.element.value = value; } } }; // src/reactivity/effect.ts var targetMap = /* @__PURE__ */ new WeakMap(); var effectStack = []; function track(target, key) { const activeEffect = effectStack[effectStack.length - 1]; if (!activeEffect) return; let effectsMap = targetMap.get(target); if (!effectsMap) targetMap.set(target, effectsMap = /* @__PURE__ */ new Map()); let effects = effectsMap.get(key); if (!effects) effectsMap.set(key, effects = /* @__PURE__ */ new Set()); if (!effects.has(activeEffect)) { effects.add(activeEffect); activeEffect.refs.push(effects); } } function trigger(target, key) { const effectsMap = targetMap.get(target); if (!effectsMap) return; const scheduled = /* @__PURE__ */ new Set(); effectsMap.get(key)?.forEach((effect2) => { scheduled.add(effect2); }); scheduled.forEach(run); } function stop2(effect2) { if (effect2.active) cleanup(effect2); effect2.active = false; } function start(effect2) { if (!effect2.active) { effect2.active = true; run(effect2); } } function run(effect2) { if (!effect2.active) return; if (effectStack.includes(effect2)) return; cleanup(effect2); let val; try { effectStack.push(effect2); val = effect2.handler(); } finally { effectStack.pop(); } return val; } function cleanup(effect2) { const { refs } = effect2; if (refs.length) { for (const ref2 of refs) { ref2.delete(effect2); } } refs.length = 0; } function effect(handler, opts = {}) { const { lazy } = opts; const newEffect = { active: !lazy, handler, refs: [] }; run(newEffect); return { start: () => { start(newEffect); }, stop: () => { stop2(newEffect); }, toggle: () => { if (newEffect.active) { stop2(newEffect); } else { start(newEffect); } return newEffect.active; } }; } // src/reactivity/computed.ts var $computed = Symbol("computed"); function isComputed(value) { return isObject(value) && value[$computed]; } // src/reactivity/ref.ts var $ref = Symbol("ref"); function isRef(value) { return isObject(value) && !!value[$ref]; } function ref(value = null) { if (isObject(value)) { return isRef(value) ? value : reactive(value); } const result = { value, [$ref]: true }; return new Proxy(result, { get(target, key, receiver) { const val = Reflect.get(target, key, receiver); track(result, "value"); return val; }, set(target, key, value2) { const oldValue = target[key]; if (oldValue !== value2) { const success = Reflect.set(target, key, value2); if (success) { trigger(result, "value"); } } return true; } }); } // src/reactivity/reactive.ts var $reactive = Symbol("reactive"); function reactive(value) { if (!isObject(value)) return ref(value); if (value[$reactive]) return value; value[$reactive] = true; Object.keys(value).forEach((key) => { if (isObject(value[key])) { value[key] = reactive(value[key]); } }); return new Proxy(value, reactiveProxyHandler()); } function reactiveProxyHandler() { return { deleteProperty(target, key) { const had = Reflect.has(target, key); const result = Reflect.deleteProperty(target, key); if (had) trigger(target, key); return result; }, get(target, key) { track(target, key); return Reflect.get(target, key); }, set(target, key, value) { if (target[key] === value) return true; let newObj = false; if (isObject(value) && !isObject(target[key])) { newObj = true; } if (Reflect.set(target, key, value)) { trigger(target, key); } if (newObj) { target[key] = reactive(target[key]); } return true; } }; } // src/index.ts function provide(key, value) { if (!current.componentBlock) { console.warn("Can't provide: no current component block"); } current.componentBlock.provides.set(key, value); } function inject(key) { if (!current.componentBlock) { console.warn("Can't inject: no current component block"); } let c = current.componentBlock; while (c) { if (c.provides.has(key)) { return c.provides.get(key); } c = c.parentComponentBlock; } return void 0; } var App = class { rootBlock; registry = /* @__PURE__ */ new Map(); plugins = /* @__PURE__ */ new Set(); register(name, component) { this.registry.set(name, component); } use(plugin, ...config) { this.plugins.add(plugin); plugin.use(this, ...config); } getComponent(tag) { return this.registry.get(tag); } mount(component, target = "body", props = {}) { const root = typeof target === "string" ? document.querySelector(target) : target; const display = root.style.display; root.style.display = "none"; this.rootBlock = this._mount(component, root, props, true); root.style.display = display; return this.rootBlock; } _mount(component, target, props, isRoot = false) { const parentContext = createContext({ app: this }); if (props) { parentContext.scope = reactive(props); bindContextMethods(parentContext.scope); } parentContext.scope.$isRef = isRef; parentContext.scope.$isComputed = isComputed; const block = new Block({ element: target, parentContext, component, isRoot, componentProps: props, replacementType: "replaceChildren" }); return block; } unmount() { this.rootBlock.teardown(); } }; function createContext({ parentContext, app: app2 }) { const context = { app: app2 ? app2 : parentContext && parentContext.app ? parentContext.app : null, scope: parentContext ? parentContext.scope : reactive({}), blocks: [], effects: [], slots: [], templates: parentContext ? parentContext.templates : [], effect: (handler) => { const e = effect(handler); context.effects.push(e); return e; } }; return context; } var createScopedContext = (ctx, data = {}) => { const parentScope = ctx.scope; const mergedScope = Object.create(parentScope); Object.defineProperties(mergedScope, Object.getOwnPropertyDescriptors(data)); let proxy; proxy = reactive( new Proxy(mergedScope, { set(target, key, val, receiver) { if (receiver === proxy && !target.hasOwnProperty(key)) { return Reflect.set(parentScope, key, val); } return Reflect.set(target, key, val, receiver); } }) ); bindContextMethods(proxy); const out = { ...ctx, scope: { ...ctx.scope, ...proxy } }; return out; }; function bindContextMethods(scope) { for (const key of Object.keys(scope)) { if (typeof scope[key] === "function") { scope[key] = scope[key].bind(scope); } } } function mergeProps(props, defaultProps) { const merged = {}; Object.keys(defaultProps).forEach((defaultProp) => { const propValue = props.hasOwnProperty(defaultProp) ? props[defaultProp] : defaultProps[defaultProp]?.default; merged[defaultProp] = reactive(typeof propValue === "function" ? propValue() : propValue); }); return merged; } var current = { componentBlock: void 0 }; var Block = class { element; context; parentContext; component; provides = /* @__PURE__ */ new Map(); parentComponentBlock; componentProps; allProps; isFragment; start; end; key; constructor(opts) { this.isFragment = opts.element instanceof HTMLTemplateElement; this.parentComponentBlock = opts.parentComponentBlock; if (opts.component) { current.componentBlock = this; this.element = stringToElement(opts.component.template); } else { if (this.isFragment) { this.element = opts.element.content.cloneNode(true); } else if (typeof opts.element === "string") { this.element = stringToElement(opts.element); } else { this.element = opts.element.cloneNode(true); opts.element.replaceWith(this.element); } } if (opts.isRoot) { this.context = opts.parentContext; } else { this.parentContext = opts.parentContext ? opts.parentContext : createContext({}); this.parentContext.blocks.push(this); this.context = createContext({ parentContext: opts.parentContext }); } if (opts.component) { this.componentProps = mergeProps(opts.componentProps ?? {}, opts.component.props ?? {}); if (opts.component.main) { this.context.scope = { ...opts.component.main(this.componentProps) || {} }; } } opts.allProps?.forEach((prop) => { if (prop.isBind) { this.context.effect(() => { let newValue; if (prop.isSpread) { const spreadProps = evalGet(this.parentContext.scope, prop.extractedName); if (isObject(spreadProps)) { Object.keys(spreadProps).forEach((key) => { newValue = spreadProps[key]; this.setProp(key, newValue); }); } } else { newValue = prop.isMirror ? evalGet(this.parentContext.scope, prop.extractedName) : evalGet(this.parentContext.scope, prop.exp); this.setProp(prop.extractedName, newValue); } }); } }); this.context.slots = findSlotNodes(this.element); this.context.templates = opts.templates ?? []; this.context.slots.forEach((slot) => { const template = this.context.templates.find((t) => t.targetSlotName === slot.name); if (template) { const templateContents = template.node.content.cloneNode(true); slot.node.replaceWith(templateContents); } }); this.context.scope.$isRef = isRef; this.context.scope.$isComputed = isComputed; walk(this.element, this.context); if (opts.component) { if (opts.replacementType === "replace") { if (opts.element instanceof HTMLElement) { opts.element.replaceWith(this.element); } } else { if (opts.element instanceof HTMLElement) { opts.element.replaceChildren(this.element); } } } } setProp(name, value) { if (isRef(this.componentProps[name])) { this.componentProps[name].value = value; } else { this.componentProps[name] = value; } } insert(parent2, anchor = null) { if (this.isFragment) { if (this.start) { let node = this.start; let next; while (node) { next = node.nextSibling; parent2.insertBefore(node, anchor); if (node === this.end) { break; } node = next; } } else { this.start = new Text(""); this.end = new Text(""); parent2.insertBefore(this.end, anchor); parent2.insertBefore(this.start, this.end); parent2.insertBefore(this.element, this.end); } } else { parent2.insertBefore(this.element, anchor); } } remove() { if (this.parentContext) { const i = this.parentContext.blocks.indexOf(this); if (i > -1) { this.parentContext.blocks.splice(i, 1); } } if (this.start) { const parent2 = this.start.parentNode; let node = this.start; let next; while (node) { next = node.nextSibling; parent2.removeChild(node); if (node === this.end) { break; } node = next; } } else { this.element.remove(); } this.teardown(); } teardown() { this.context.blocks.forEach((block) => { block.teardown(); }); this.context.effects.forEach(stop); } }; function isComponent(element, context) { return !!context.app.getComponent(element.tagName.toLowerCase()); } function walk(node, context) { if (isText(node)) { new InterpolationDirective({ element: node, context }); return; } if (isElement(node)) { let exp; const handleDirectives = (node2, context2, component, componentProps, allProps) => { if (exp = checkAndRemoveAttribute(node2, ":teleport")) { return _teleport(node2, exp, context2); } if (exp = checkAndRemoveAttribute(node2, ":if")) { return _if(node2, exp, context2, component, componentProps, allProps); } if (exp = checkAndRemoveAttribute(node2, ":for")) { return _for(node2, exp, context2, component, componentProps, allProps); } if (exp = checkAndRemoveAttribute(node2, ":show")) { new ShowDirective({ element: node2, context: context2, expression: exp }); } if (exp = checkAndRemoveAttribute(node2, ":ref")) { context2.scope[exp].value = node2; } if (exp = checkAndRemoveAttribute(node2, ":value")) { new ValueDirective({ element: node2, context: context2, expression: exp }); } if (exp = checkAndRemoveAttribute(node2, ":html")) { context2.effect(() => { const result = evalGet(context2.scope, exp); if (result instanceof Element) { node2.replaceChildren(); node2.append(result); } else { node2.innerHTML = result; } }); } }; const processAttributes = (node2, component) => { return Array.from(node2.attributes).filter((attr) => isSpreadProp(attr.name) || isMirrorProp(attr.name) || isRegularProp(attr.name) && componentHasPropByName(extractPropName(attr.name), component)).map((attr) => ({ isMirror: isMirrorProp(attr.name), isSpread: isSpreadProp(attr.name), isBind: attr.name.includes("bind"), originalName: attr.name, extractedName: extractPropName(attr.name), exp: attr.value, value: isMirrorProp(attr.name) ? evalGet(context.scope, extractPropName(attr.name)) : attr.value ? evalGet(context.scope, attr.value) : void 0 })); }; if (isComponent(node, context)) { const component = context.app.getComponent(node.tagName.toLowerCase()); const allProps = processAttributes(node, component); const componentProps = allProps.reduce((acc, { isSpread, isMirror, extractedName, value }) => { if (isSpread) { const spread = evalGet(context.scope, extractedName); if (isObject(spread)) Object.assign(acc, spread); } else if (isMirror) { acc[extractedName] = evalGet(context.scope, extractedName); } else { acc[extractedName] = value; } return acc; }, {}); const next2 = handleDirectives(node, context, component, componentProps, allProps); if (next2) return next2; const templates = findTemplateNodes(node); return new Block({ element: node, parentContext: context, component, replacementType: "replace", parentComponentBlock: current.componentBlock, templates, componentProps, allProps }).element; } const next = handleDirectives(node, context); if (next) return next; Array.from(node.attributes).forEach((attr) => { if (isPropAttribute(attr.name)) { new AttributeDirective({ element: node, context, attr }); } if (isEventAttribute(attr.name)) { new EventDirective({ element: node, context, attr }); } }); walkChildren(node, context); } } function walkChildren(node, context) { let child2 = node.firstChild; while (child2) { child2 = walk(child2, context) || child2.nextSibling; } } var evalFuncCache = {}; function evalGet(scope, exp, el) { if (!exp.trim()) return void 0; return execute(scope, `const ___value = (${exp.trim()}); return ___value;`, el); } function evalSet(scope, exp, value) { value = typeof value === "string" ? `"${value}"` : value; return execute(scope, `const ___target = (${exp.trim()}); return $isRef(___target) ? ___target.value = ${value} : ___target = ${value};`, null, false); } function execute(scope, exp, el, flatRefs = true) { const newScope = flatRefs ? flattenRefs(scope) : scope; const fn = evalFuncCache[exp] || (evalFuncCache[exp] = toFunction(exp)); try { return fn(newScope, el); } catch (e) { console.warn(`Error evaluating expression: "${exp}":`); console.error(e); } } function toFunction(exp) { try { return new Function("$data", "$el", `with($data){${exp}}`); } catch (e) { console.error(`${e.message} in expression: ${exp}`); return () => { }; } } function flattenRefs(scope) { const mapped = {}; for (const key in scope) { if (scope.hasOwnProperty(key)) { if (isRef(scope[key])) { mapped[key] = scope[key].value; } else { mapped[key] = scope[key]; } } } return mapped; } var child = { template: html`
Animal: {{animal}} {{index}}
`, props: { animal: { default: "cat" }, index: { default: 0 } }, main({ animal, index }) { return { animal, index }; } }; var parent = { template: html`
mirror, no bind:
mirror, bind:
spread, no bind:
spread, bind:
regular prop:
regular prop, bind:
div has "id" set to animal.value

div has "id" set and bound to animal.value

div has "animal" set to animal.value

div has "animal" set and bound to animal.value

div has "animal" spread

div has "animal" spread and bound




if bool, mirror, no bind: if bool, mirror, bind:
for list, mirror, no bind:
for list, mirror, bind: if bool, for list, mirror, no bind: these have the value "DOG!" because by the time for :for directive is evaluated, animal.value is "DOG!", and no longer "dog".
`, main() { const bool = ref(false); const animal = ref("dog"); const spread = reactive({ animal: "panther" }); const list = reactive([1, 2, 3]); setTimeout(() => { spread.animal = "PANTHER!"; animal.value = "DOG!"; bool.value = true; }, 500); setTimeout(() => { animal.value = "DOG!!!!!"; }, 1e3); return { animal, spread, bool, list }; } }; var app = new App(); app.register("child", child); app.mount(parent, "#app"); export { App, Block, createContext, createScopedContext, current, evalGet, evalSet, inject, provide }; //# sourceMappingURL=index.js.map