@kalxjs/core
Version: 
A modern JavaScript framework for building user interfaces with reactive state, composition API, and built-in performance optimizations
1,519 lines (1,338 loc) • 482 kB
JavaScript
/**
 * KalxJS Core - Development Build
 * WARNING: This is a development build with extra debugging.
 * Do not use in production.
 * 
 * Version: 2.2.20
 * Build date: 2025-10-20T01:41:05.244Z
 */
import * as fs from 'fs';
import * as path from 'path';
import { Readable } from 'stream';
// packages/core/src/reactivity/reactive.js
// Current active effect
let activeEffect = null;
/**
 * Creates a reactive object
 * @param {Object} target - Object to make reactive
 * @returns {Proxy} Reactive object
 */
function reactive$1(target) {
    const handlers = {
        get(target, key, receiver) {
            const result = Reflect.get(target, key, receiver);
            track(target, key);
            return result;
        },
        set(target, key, value, receiver) {
            const oldValue = target[key];
            const result = Reflect.set(target, key, value, receiver);
            if (oldValue !== value) {
                trigger(target, key);
            }
            return result;
        }
    };
    return new Proxy(target, handlers);
}
/**
 * Creates a reactive reference
 * @param {any} value - Initial value
 * @returns {Object} Reactive reference
 */
function ref$1(value) {
    const r = {
        _value: value,
        get value() {
            track(r, 'value');
            return this._value;
        },
        set value(newValue) {
            if (this._value !== newValue) {
                this._value = newValue;
                trigger(r, 'value');
            }
        }
    };
    return r;
}
/**
 * Creates a computed property
 * @param {Function} getter - Getter function
 * @returns {Object} Computed property
 */
function computed$2(getter) {
    let value;
    let dirty = true;
    const runner = effect$2(getter, {
        lazy: true,
        scheduler: () => {
            if (!dirty) {
                dirty = true;
                trigger(computedRef, 'value');
            }
        }
    });
    const computedRef = {
        get value() {
            if (dirty) {
                value = runner();
                dirty = false;
            }
            track(computedRef, 'value');
            return value;
        }
    };
    return computedRef;
}
/**
 * Creates a reactive effect
 * @param {Function} fn - Effect function
 * @param {Object} options - Effect options
 * @returns {Function} Effect runner
 */
function effect$2(fn, options = {}) {
    const effect = createReactiveEffect(fn, options);
    if (!options.lazy) {
        effect();
    }
    return effect;
}
// Internal helpers
const targetMap = new WeakMap();
function track(target, key) {
    // Only track if we have an active effect and a valid target
    if (activeEffect && target) {
        let depsMap = targetMap.get(target);
        if (!depsMap) {
            targetMap.set(target, (depsMap = new Map()));
        }
        let dep = depsMap.get(key);
        if (!dep) {
            depsMap.set(key, (dep = new Set()));
        }
        dep.add(activeEffect);
    }
}
function trigger(target, key) {
    // Check if target is valid
    if (!target) return;
    const depsMap = targetMap.get(target);
    if (!depsMap) return;
    const effects = depsMap.get(key);
    if (effects) {
        // Create a new set to avoid infinite loops if an effect triggers itself
        const effectsToRun = new Set(effects);
        effectsToRun.forEach(effect => {
            if (effect.scheduler) {
                effect.scheduler();
            } else {
                effect();
            }
        });
    }
}
function createReactiveEffect(fn, options) {
    const effect = function reactiveEffect() {
        if (!effect.active) return fn();
        if (!effectStack.includes(effect)) {
            cleanup(effect);
            try {
                effectStack.push(effect);
                activeEffect = effect;
                return fn();
            } finally {
                effectStack.pop();
                // Set activeEffect to the previous effect in the stack or null if empty
                activeEffect = effectStack.length > 0 ? effectStack[effectStack.length - 1] : null;
            }
        }
    };
    effect.active = true;
    effect.deps = [];
    effect.options = options;
    return effect;
}
const effectStack = [];
function cleanup(effect) {
    const { deps } = effect;
    if (deps.length) {
        for (let i = 0; i < deps.length; i++) {
            deps[i].delete(effect);
        }
        deps.length = 0;
    }
}
// @kalxjs/core - Virtual DOM diffing algorithm
/**
 * Patches a DOM node to match a new virtual DOM node
 * @param {HTMLElement} domNode - DOM node to patch
 * @param {Object} oldVNode - Old virtual DOM node
 * @param {Object} newVNode - New virtual DOM node
 * @returns {HTMLElement} Updated DOM node
 */
function patch(domNode, oldVNode, newVNode) {
    // Check if domNode is valid
    if (!domNode) {
        console.warn('Cannot patch: domNode is undefined or null');
        return createDOMNode(newVNode); // Return a new node but don't attach it
    }
    // Check if domNode has a parent
    if (!domNode.parentNode) {
        console.warn('Cannot patch: domNode has no parent');
        return createDOMNode(newVNode); // Return a new node but don't attach it
    }
    // If the old vnode is the same as the new vnode, do nothing
    if (oldVNode === newVNode) {
        return domNode;
    }
    // If the new vnode is null or undefined, remove the node
    if (!newVNode) {
        domNode.parentNode.removeChild(domNode);
        return null;
    }
    // If the old vnode is null or undefined, create a new node
    if (!oldVNode) {
        const newNode = createDOMNode(newVNode);
        domNode.parentNode.appendChild(newNode);
        return newNode;
    }
    // If the nodes are of different types, replace the node
    if (nodeTypesAreDifferent(oldVNode, newVNode)) {
        const newNode = createDOMNode(newVNode);
        domNode.parentNode.replaceChild(newNode, domNode);
        return newNode;
    }
    // If the nodes are of the same type, update the node
    return updateDOMNode(domNode, oldVNode, newVNode);
}
/**
 * Checks if two nodes are of different types
 * @private
 * @param {Object} oldVNode - Old virtual DOM node
 * @param {Object} newVNode - New virtual DOM node
 * @returns {boolean} Whether the nodes are of different types
 */
function nodeTypesAreDifferent(oldVNode, newVNode) {
    // Handle primitive values
    if (typeof oldVNode !== 'object' || typeof newVNode !== 'object') {
        return typeof oldVNode !== typeof newVNode;
    }
    // Handle component nodes
    if (oldVNode.isComponent || newVNode.isComponent) {
        return oldVNode.tag !== newVNode.tag;
    }
    // Handle regular nodes
    return oldVNode.tag !== newVNode.tag;
}
/**
 * Creates a DOM node from a virtual DOM node
 * @private
 * @param {Object} vnode - Virtual DOM node
 * @returns {HTMLElement} DOM node
 */
function createDOMNode(vnode) {
    // Handle primitive values
    if (typeof vnode === 'string' || typeof vnode === 'number') {
        return document.createTextNode(vnode);
    }
    // Handle null or undefined
    if (!vnode) {
        // Create a fallback element instead of a comment node
        const fallbackElement = document.createElement('div');
        fallbackElement.className = 'kalxjs-fallback-element';
        fallbackElement.innerHTML = `
            <div style="padding: 10px; border: 1px solid #f0ad4e; background-color: #fcf8e3; color: #8a6d3b; border-radius: 4px;">
                <h4 style="margin-top: 0;">KalxJS Rendering Notice</h4>
                <p>The framework attempted to render a component but received empty content.</p>
                <p>This is a fallback element to ensure something is displayed.</p>
            </div>
        `;
        return fallbackElement;
    }
    // Handle component nodes
    if (vnode.isComponent) {
        // This would be handled by the component system
        return document.createComment('component node');
    }
    // Handle regular nodes
    const element = document.createElement(vnode.tag);
    // Set attributes
    updateAttributes(element, {}, vnode.props || {});
    // Create and append children
    (vnode.children || []).forEach(child => {
        if (child !== null && child !== undefined) {
            element.appendChild(createDOMNode(child));
        }
    });
    return element;
}
/**
 * Updates a DOM node to match a new virtual DOM node
 * @private
 * @param {HTMLElement} domNode - DOM node to update
 * @param {Object} oldVNode - Old virtual DOM node
 * @param {Object} newVNode - New virtual DOM node
 * @returns {HTMLElement} Updated DOM node
 */
function updateDOMNode(domNode, oldVNode, newVNode) {
    // Check if domNode is valid
    if (!domNode) {
        console.warn('Cannot update DOM node: domNode is undefined or null');
        return createDOMNode(newVNode);
    }
    // Check if domNode has a parent
    if (!domNode.parentNode) {
        console.warn('Cannot update DOM node: domNode has no parent');
        return createDOMNode(newVNode);
    }
    // Handle text nodes
    if (typeof oldVNode === 'string' || typeof newVNode === 'string' ||
        typeof oldVNode === 'number' || typeof newVNode === 'number') {
        if (oldVNode !== newVNode) {
            const newNode = document.createTextNode(newVNode);
            domNode.parentNode.replaceChild(newNode, domNode);
            return newNode;
        }
        return domNode;
    }
    // Update attributes
    updateAttributes(domNode, oldVNode.props || {}, newVNode.props || {});
    // Update children
    updateChildren$1(domNode, oldVNode.children || [], newVNode.children || []);
    return domNode;
}
/**
 * Updates the attributes of a DOM node
 * @private
 * @param {HTMLElement} domNode - DOM node to update
 * @param {Object} oldAttrs - Old attributes
 * @param {Object} newAttrs - New attributes
 */
function updateAttributes(domNode, oldAttrs, newAttrs) {
    // Remove old attributes
    for (const key in oldAttrs) {
        if (!(key in newAttrs)) {
            if (key.startsWith('on')) {
                const eventName = key.slice(2).toLowerCase();
                domNode.removeEventListener(eventName, oldAttrs[key]);
            } else {
                domNode.removeAttribute(key);
            }
        }
    }
    // Set new attributes
    for (const key in newAttrs) {
        if (oldAttrs[key] !== newAttrs[key]) {
            if (key.startsWith('on')) {
                // Handle both camelCase (onClick) and lowercase (onclick) event handlers
                const eventName = key.slice(2).toLowerCase();
                if (oldAttrs[key]) {
                    domNode.removeEventListener(eventName, oldAttrs[key]);
                }
                domNode.addEventListener(eventName, newAttrs[key]);
            } else if (key === 'style' && typeof newAttrs[key] === 'object') {
                // Handle style objects
                const styleObj = newAttrs[key];
                for (const styleKey in styleObj) {
                    domNode.style[styleKey] = styleObj[styleKey];
                }
            } else if (key === 'class' || key === 'className') {
                // Handle class names
                domNode.className = newAttrs[key];
            } else if (key === 'dangerouslySetInnerHTML') {
                // Handle innerHTML
                domNode.innerHTML = newAttrs[key].__html;
            } else {
                // Handle regular attributes
                domNode.setAttribute(key, newAttrs[key]);
            }
        }
    }
}
/**
 * Updates the children of a DOM node
 * @private
 * @param {HTMLElement} domNode - DOM node to update
 * @param {Array} oldChildren - Old children
 * @param {Array} newChildren - New children
 */
function updateChildren$1(domNode, oldChildren, newChildren) {
    // Check if domNode is valid
    if (!domNode) {
        console.warn('Cannot update children: domNode is undefined or null');
        return;
    }
    // Optimize for common cases
    if (oldChildren.length === 0) {
        // If there were no old children, append all new children
        newChildren.forEach(child => {
            domNode.appendChild(createDOMNode(child));
        });
        return;
    }
    if (newChildren.length === 0) {
        // If there are no new children, remove all old children
        domNode.innerHTML = '';
        return;
    }
    // Use key-based reconciliation if keys are present
    const oldKeyedChildren = {};
    const newKeyedChildren = {};
    let hasKeys = false;
    // Check if keys are present
    for (let i = 0; i < oldChildren.length; i++) {
        const child = oldChildren[i];
        if (child && child.props && child.props.key != null) {
            hasKeys = true;
            oldKeyedChildren[child.props.key] = { vnode: child, index: i };
        }
    }
    for (let i = 0; i < newChildren.length; i++) {
        const child = newChildren[i];
        if (child && child.props && child.props.key != null) {
            hasKeys = true;
            newKeyedChildren[child.props.key] = { vnode: child, index: i };
        }
    }
    if (hasKeys) {
        // Use key-based reconciliation
        const domChildren = Array.from(domNode.childNodes);
        const keysToRemove = Object.keys(oldKeyedChildren).filter(key => !(key in newKeyedChildren));
        // Remove nodes that are no longer needed
        keysToRemove.forEach(key => {
            const { index } = oldKeyedChildren[key];
            if (index < domChildren.length && domChildren[index]) {
                domNode.removeChild(domChildren[index]);
            }
        });
        // Update or insert nodes
        let lastIndex = 0;
        Object.keys(newKeyedChildren).forEach(key => {
            const { vnode: newChild, index: newIndex } = newKeyedChildren[key];
            const oldChild = oldKeyedChildren[key];
            if (oldChild) {
                // Update existing node
                const oldIndex = oldChild.index;
                const oldVNode = oldChild.vnode;
                // Make sure the DOM node exists before patching
                if (oldIndex < domChildren.length && domChildren[oldIndex]) {
                    patch(domChildren[oldIndex], oldVNode, newChild);
                    // Move node if needed
                    if (oldIndex < lastIndex) {
                        const node = domChildren[oldIndex];
                        if (lastIndex < domChildren.length) {
                            domNode.insertBefore(node, domChildren[lastIndex]);
                        } else {
                            domNode.appendChild(node);
                        }
                    }
                    lastIndex = Math.max(oldIndex, lastIndex);
                } else {
                    // DOM node doesn't exist, create a new one
                    const newNode = createDOMNode(newChild);
                    if (newIndex < domChildren.length) {
                        domNode.insertBefore(newNode, domChildren[newIndex]);
                    } else {
                        domNode.appendChild(newNode);
                    }
                }
            } else {
                // Insert new node
                const newNode = createDOMNode(newChild);
                if (newIndex < domChildren.length) {
                    domNode.insertBefore(newNode, domChildren[newIndex]);
                } else {
                    domNode.appendChild(newNode);
                }
            }
        });
    } else {
        // Use simple reconciliation
        const maxLength = Math.max(oldChildren.length, newChildren.length);
        for (let i = 0; i < maxLength; i++) {
            const oldChild = oldChildren[i];
            const newChild = newChildren[i];
            // Check if the DOM child exists
            const domChild = i < domNode.childNodes.length ? domNode.childNodes[i] : null;
            if (!oldChild && newChild) {
                // Insert new node
                domNode.appendChild(createDOMNode(newChild));
            } else if (oldChild && !newChild) {
                // Remove old node if it exists in the DOM
                if (domChild) {
                    domNode.removeChild(domChild);
                } else {
                    console.warn('Attempted to remove a child node that does not exist in the DOM');
                }
            } else if (oldChild && newChild) {
                if (domChild) {
                    // Update existing node
                    patch(domChild, oldChild, newChild);
                } else {
                    // DOM node doesn't exist, create a new one
                    domNode.appendChild(createDOMNode(newChild));
                }
            }
        }
    }
}
// packages/core/src/vdom/vdom.js
/**
 * Creates a DOM element with the given tag
 * @param {string} tag - HTML tag name
 * @returns {HTMLElement} The created DOM element
 */
function createDOMElement$1(tag) {
    // Ensure tag is a string
    if (typeof tag !== 'string') {
        console.warn(`createDOMElement: Invalid tag type: ${typeof tag}. Using 'div' instead.`);
        tag = 'div';
    }
    // Ensure tag is not empty
    if (!tag) {
        console.warn('createDOMElement: Empty tag provided. Using div instead.');
        tag = 'div';
    }
    try {
        return document.createElement(tag);
    } catch (error) {
        console.error(`createDOMElement: Error creating element with tag "${tag}":`, error);
        return document.createElement('div');
    }
}
/**
 * Flattens an array (polyfill for Array.prototype.flat)
 * @private
 * @param {Array} arr - Array to flatten
 * @param {number} depth - Maximum recursion depth
 * @returns {Array} Flattened array
 */
function flattenArray(arr, depth = 1) {
    // Ensure arr is always an array
    if (!Array.isArray(arr)) {
        return arr ? [arr] : [];
    }
    const result = [];
    arr.forEach(item => {
        if (Array.isArray(item) && depth > 0) {
            result.push(...flattenArray(item, depth - 1));
        } else {
            result.push(item);
        }
    });
    return result;
}
/**
 * Creates a virtual DOM node
 * @param {string|function} tag - HTML tag name or component function
 * @param {Object} props - Node properties
 * @param {Array} children - Child nodes
 */
function h$1(tag, props = {}, children = []) {
    // Handle null or undefined tag
    if (!tag) {
        console.warn('Invalid tag provided to h function');
        return null;
    }
    // Ensure children is always an array
    const childArray = Array.isArray(children) ? children : (children ? [children] : []);
    // If tag is a component function, mark it as a component
    if (typeof tag === 'function') {
        return {
            tag: 'component-placeholder', // Use a placeholder tag for the vnode
            props: props || {},
            children: flattenArray(childArray),
            component: tag, // Store the component function
            isComponent: true // Mark as a component
        };
    }
    return {
        tag,
        props: props || {},
        children: flattenArray(childArray)
    };
}
/**
 * Creates a real DOM element from a virtual node
 * @param {Object} vnode - Virtual DOM node
 * @returns {HTMLElement} Real DOM element
 */
function createElement$1(vnode) {
    // Handle primitive values (string, number, etc.)
    if (typeof vnode === 'string' || typeof vnode === 'number') {
        return document.createTextNode(String(vnode));
    }
    // Handle null or undefined
    if (!vnode) {
        console.error('Attempted to create element from null/undefined vnode');
        // Instead of returning a comment node, create a fallback element
        const fallbackElement = document.createElement('div');
        fallbackElement.className = 'kalxjs-fallback-element';
        fallbackElement.innerHTML = `
            <div style="padding: 10px; border: 1px solid #f0ad4e; background-color: #fcf8e3; color: #8a6d3b; border-radius: 4px;">
                <h4 style="margin-top: 0;">KalxJS Rendering Notice</h4>
                <p>The framework attempted to render a component but received empty content.</p>
                <p>This is a fallback element to ensure something is displayed.</p>
            </div>
        `;
        // Add a debug property to help with troubleshooting
        fallbackElement._debug = {
            error: 'Null or undefined vnode',
            timestamp: new Date().toISOString()
        };
        return fallbackElement;
    }
    // Handle case where vnode might be a router view component
    if (vnode._isRouterView && vnode._componentRef) {
        try {
            console.log('Rendering router view component:', vnode._componentRef.name || 'anonymous');
            // Create a container element
            const container = document.createElement(vnode.tag || 'div');
            // Apply props to the container
            for (const [key, value] of Object.entries(vnode.props || {})) {
                if (value === undefined || value === null) continue;
                if (key.startsWith('on')) {
                    const eventName = key.slice(2).toLowerCase();
                    if (typeof value === 'function') {
                        container.addEventListener(eventName, value);
                    }
                } else if (key === 'style' && typeof value === 'object') {
                    Object.assign(container.style, value);
                } else if (key === 'class' || key === 'className') {
                    container.className = value;
                } else {
                    container.setAttribute(key, value);
                }
            }
            // Add a data attribute to identify this as a router view container
            container.setAttribute('data-router-view', 'true');
            // Store the component reference for later use
            container._componentRef = vnode._componentRef;
            // Return the container element
            return container;
        } catch (error) {
            console.error('Error preparing router view component:', error);
            const errorElement = document.createElement('div');
            errorElement.style.color = 'red';
            errorElement.style.border = '1px solid red';
            errorElement.style.padding = '10px';
            errorElement.style.margin = '10px 0';
            errorElement.innerHTML = `
                <h4>Router View Error</h4>
                <p>${error.message}</p>
                <pre style="font-size: 12px; overflow: auto; max-height: 200px; background: #f5f5f5; padding: 5px;">${error.stack}</pre>
            `;
            return errorElement;
        }
    }
    // Handle case where vnode might be a component
    if (vnode.isComponent && vnode.component) {
        try {
            console.log('Rendering component:', vnode.component.name || 'anonymous');
            // Check if this is a component factory from defineComponent
            if (vnode.component.options) {
                console.log('Detected component factory with options:', vnode.component.options.name);
            }
            // Call the component function with the props
            const result = vnode.component(vnode.props);
            if (!result) {
                throw new Error('Component function returned null or undefined');
            }
            console.log('Component function result:', result);
            // If the result is a component instance with a render method, call it
            if (result.render && typeof result.render === 'function') {
                const renderResult = result.render();
                console.log('Component render result:', renderResult);
                return createElement$1(renderResult);
            }
            // If the result doesn't have a tag property, add one
            if (typeof result === 'object' && !result.tag) {
                console.warn('Component returned object without tag property, adding div tag');
                result.tag = 'div';
            }
            return createElement$1(result);
        } catch (error) {
            console.error('Error rendering component:', error);
            const errorElement = document.createElement('div');
            errorElement.style.color = 'red';
            errorElement.style.border = '1px solid red';
            errorElement.style.padding = '10px';
            errorElement.style.margin = '10px 0';
            errorElement.innerHTML = `
                <h4>Component Error</h4>
                <p>${error.message}</p>
                <pre style="font-size: 12px; overflow: auto; max-height: 200px; background: #f5f5f5; padding: 5px;">${error.stack}</pre>
            `;
            return errorElement;
        }
    }
    // Handle case where vnode might be a function (legacy support)
    if (typeof vnode === 'function') {
        console.warn('Function passed directly to createElement. This is deprecated, use h(Component, props, children) instead.');
        try {
            // Call the function with empty props
            const result = vnode({});
            return createElement$1(result);
        } catch (error) {
            console.error('Error rendering function component:', error);
            const errorElement = document.createElement('div');
            errorElement.style.color = 'red';
            errorElement.innerHTML = `<p>Error: ${error.message}</p>`;
            return errorElement;
        }
    }
    // Handle case where vnode.tag is a component object with setup function
    if (vnode.tag && typeof vnode.tag === 'object' && typeof vnode.tag.setup === 'function') {
        try {
            console.log('Handling component object with setup function');
            // Call the setup function to get the actual component
            const setupResult = vnode.tag.setup(vnode.props || {});
            // Handle different types of setup results
            if (setupResult) {
                if (typeof setupResult === 'object') {
                    // Case 1: Setup returned an object (hopefully a vnode)
                    if (!setupResult.tag) {
                        console.warn('Component setup returned object without tag, creating a default vnode');
                        // Create a default vnode with the setup result as content
                        const defaultVNode = {
                            tag: 'div',
                            props: { class: 'kal-component-default' },
                            children: [
                                typeof setupResult === 'object' ?
                                    JSON.stringify(setupResult) :
                                    String(setupResult)
                            ]
                        };
                        return createElement$1(defaultVNode);
                    } else if (typeof setupResult.tag !== 'string') {
                        console.warn('Component setup returned object with invalid tag, setting to div');
                        setupResult.tag = 'div';
                    }
                    // Create the element from the setup result
                    return createElement$1(setupResult);
                } else if (typeof setupResult === 'function') {
                    // Case 2: Setup returned a function (render function)
                    console.log('Component setup returned a function, trying to call it');
                    try {
                        const renderResult = setupResult();
                        if (renderResult && typeof renderResult === 'object') {
                            if (!renderResult.tag) {
                                renderResult.tag = 'div';
                            }
                            return createElement$1(renderResult);
                        } else {
                            throw new Error('Render function did not return a valid vnode');
                        }
                    } catch (renderError) {
                        console.error('Error calling render function:', renderError);
                        const errorElement = document.createElement('div');
                        errorElement.style.color = 'red';
                        errorElement.innerHTML = `<p>Error in render function: ${renderError.message}</p>`;
                        return errorElement;
                    }
                } else {
                    // Case 3: Setup returned a primitive value
                    console.warn('Component setup returned a primitive value:', setupResult);
                    const defaultVNode = {
                        tag: 'div',
                        props: { class: 'kal-component-primitive' },
                        children: [String(setupResult)]
                    };
                    return createElement$1(defaultVNode);
                }
            } else {
                // Case 4: Setup returned null or undefined
                console.error('Component setup did not return a valid value', setupResult);
                const errorElement = document.createElement('div');
                errorElement.style.color = 'red';
                errorElement.innerHTML = '<p>Component setup did not return a valid view</p>';
                return errorElement;
            }
        } catch (error) {
            console.error('Error in component setup:', error);
            const errorElement = document.createElement('div');
            errorElement.style.color = 'red';
            errorElement.style.border = '1px solid red';
            errorElement.style.padding = '10px';
            errorElement.innerHTML = `
                <h4>Component Setup Error</h4>
                <p>${error.message}</p>
                <pre style="font-size: 12px; overflow: auto; max-height: 200px; background: #f5f5f5; padding: 5px;">${error.stack}</pre>
            `;
            return errorElement;
        }
    }
    // Handle case where vnode might not be a proper virtual node object
    if (!vnode.tag) {
        console.error('Invalid vnode (missing tag):', vnode);
        // Debug information
        console.log('vnode type:', typeof vnode);
        console.log('vnode keys:', Object.keys(vnode || {}));
        // Create a more informative error element
        const errorElement = document.createElement('div');
        errorElement.style.color = 'red';
        errorElement.style.border = '1px solid red';
        errorElement.style.padding = '10px';
        errorElement.style.margin = '10px 0';
        try {
            errorElement.innerHTML = `
                <h4>Invalid Virtual DOM Node</h4>
                <p>A virtual DOM node is missing the required 'tag' property</p>
                <pre style="font-size: 12px; overflow: auto; max-height: 200px; background: #f5f5f5; padding: 5px;">
${JSON.stringify(vnode, null, 2)}
                </pre>
            `;
        } catch (e) {
            errorElement.textContent = `Invalid vnode: Cannot stringify for display`;
        }
        return errorElement;
    }
    // Create the DOM element
    let element;
    try {
        // Ensure tag is a string
        const tag = typeof vnode.tag === 'string' ? vnode.tag : 'div';
        if (typeof vnode.tag !== 'string') {
            console.warn(`Invalid tag type: ${typeof vnode.tag}. Using 'div' instead.`, vnode);
        }
        element = createDOMElement$1(tag);
    } catch (error) {
        console.error(`Error creating element with tag "${vnode.tag}":`, error);
        const errorElement = document.createElement('div');
        errorElement.style.color = 'red';
        errorElement.style.padding = '5px';
        errorElement.textContent = `Invalid tag: ${vnode.tag}`;
        return errorElement;
    }
    // Set properties - ensure props is a proper object and not an array
    try {
        const props = vnode.props || {};
        // Safety check: if props is an array, it's likely a mistake - ignore it
        if (Array.isArray(props)) {
            console.warn('Props should be an object, not an array. Ignoring props:', props);
        } else {
            for (const [key, value] of Object.entries(props)) {
                if (value === undefined || value === null) {
                    continue; // Skip null/undefined props
                }
                // Skip numeric keys which are likely array indices accidentally passed as props
                if (/^\d+$/.test(key)) {
                    console.warn(`Numeric key "${key}" found in props - this is likely an array passed as props. Skipping.`);
                    continue;
                }
                if (key.startsWith('on')) {
                    // Handle both camelCase (onClick) and lowercase (onclick) event handlers
                    const eventName = key.slice(2).toLowerCase();
                    if (typeof value === 'function') {
                        element.addEventListener(eventName, value);
                    } else {
                        console.warn(`Event handler for ${eventName} is not a function:`, value);
                    }
                } else if (key === 'style') {
                    // Handle style objects and strings
                    if (typeof value === 'object') {
                        Object.assign(element.style, value);
                    } else if (typeof value === 'string') {
                        element.style.cssText = value;
                    }
                } else if (key === 'class' || key === 'className') {
                    // Handle class names
                    element.className = value;
                } else if (key === 'dangerouslySetInnerHTML') {
                    // Handle innerHTML
                    if (value && value.__html !== undefined) {
                        element.innerHTML = value.__html;
                    }
                } else {
                    // Handle regular attributes - validate attribute name and value
                    try {
                        // Validate attribute name (must be valid HTML attribute name)
                        if (typeof key === 'string' && key.length > 0 && /^[a-zA-Z][\w-]*$/.test(key)) {
                            // Convert value to string and ensure it's valid
                            const stringValue = String(value);
                            element.setAttribute(key, stringValue);
                        } else {
                            console.warn(`Invalid attribute name: ${key}`);
                        }
                    } catch (attrError) {
                        console.warn(`Failed to set attribute ${key}=${value}:`, attrError.message);
                    }
                }
            }
        }
    } catch (error) {
        console.error('Error setting properties:', error);
        // Continue despite property errors
    }
    // Create and append children
    const children = Array.isArray(vnode.children) ? vnode.children : (vnode.children ? [vnode.children] : []);
    children.forEach(child => {
        if (child !== null && child !== undefined) {
            try {
                const childElement = createElement$1(child);
                if (childElement) {
                    element.appendChild(childElement);
                }
            } catch (error) {
                console.error('Error creating child element:', error);
                const errorComment = document.createComment(`Error creating child: ${error.message}`);
                element.appendChild(errorComment);
            }
        }
    });
    return element;
}
/**
 * Updates an existing DOM element to match a new virtual DOM node
 * @param {HTMLElement} element - DOM element to update
 * @param {Object} oldVNode - Previous virtual DOM node
 * @param {Object} newVNode - New virtual DOM node
 * @returns {HTMLElement} Updated DOM element
 */
function updateElement(element, oldVNode, newVNode) {
    // Use the new diffing algorithm
    return patch(element, oldVNode, newVNode);
}
/**
 * Updates the properties of a DOM element
 * @param {HTMLElement} element - DOM element to update
 * @param {Object} oldProps - Previous properties
 * @param {Object} newProps - New properties
 */
function updateProps(element, oldProps, newProps) {
    // Remove old properties
    for (const [key, value] of Object.entries(oldProps)) {
        if (!(key in newProps)) {
            if (key.startsWith('on')) {
                const eventName = key.slice(2).toLowerCase();
                element.removeEventListener(eventName, value);
            } else {
                element.removeAttribute(key);
            }
        }
    }
    // Set new properties
    for (const [key, value] of Object.entries(newProps)) {
        if (oldProps[key] !== value) {
            if (key.startsWith('on')) {
                const eventName = key.slice(2).toLowerCase();
                if (oldProps[key]) {
                    element.removeEventListener(eventName, oldProps[key]);
                }
                element.addEventListener(eventName, value);
            } else {
                element.setAttribute(key, value);
            }
        }
    }
}
/**
 * Updates a child element
 * @param {HTMLElement} parentElement - Parent DOM element
 * @param {Object} oldChild - Previous virtual DOM node
 * @param {Object} newChild - New virtual DOM node
 * @param {number} index - Child index
 */
function updateChild(parentElement, oldChild, newChild, index) {
    const childElement = parentElement.childNodes[index];
    // Remove extra children
    if (!newChild) {
        parentElement.removeChild(childElement);
        return;
    }
    // Add missing children
    if (!oldChild) {
        const newElement = createElement$1(newChild);
        parentElement.appendChild(newElement);
        return;
    }
    // Update existing children
    updateElement(childElement, oldChild, newChild);
}
/**
 * Updates all children of a DOM element
 * @param {HTMLElement} parentElement - Parent DOM element
 * @param {Array} oldChildren - Previous virtual DOM nodes
 * @param {Array} newChildren - New virtual DOM nodes
 */
function updateChildren(parentElement, oldChildren, newChildren) {
    const maxLength = Math.max(oldChildren.length, newChildren.length);
    for (let i = 0; i < maxLength; i++) {
        updateChild(
            parentElement,
            oldChildren[i],
            newChildren[i],
            i
        );
    }
}
// @kalxjs/core - Component instance management for Composition API
// Current component instance
let currentInstance = null;
/**
 * Sets the current component instance
 * @param {Object} instance - Component instance
 */
function setCurrentInstance(instance) {
    currentInstance = instance;
}
/**
 * Gets the current component instance
 * @returns {Object} Current component instance
 */
function getCurrentInstance$1() {
    if (!currentInstance) {
        console.warn('getCurrentInstance() can only be used inside setup()');
        return {};
    }
    return currentInstance;
}
// @kalxjs/core - Composition API
/**
 * Creates a reactive object that can be used in the setup function
 * @param {Object} target - Object to make reactive
 * @returns {Proxy} Reactive object
 */
function useReactive(target) {
    return reactive$1(target);
}
/**
 * Creates a reactive reference that can be used in the setup function
 * @param {any} value - Initial value
 * @returns {Object} Reactive reference
 */
function useRef(value) {
    return ref$1(value);
}
/**
 * Creates a computed property that can be used in the setup function
 * @param {Function} getter - Getter function
 * @returns {Object} Computed property
 */
function useComputed(getter) {
    return computed$2(getter);
}
/**
 * Watches for changes in a reactive source and runs a callback
 * @param {Object|Function} source - Reactive object or getter function
 * @param {Function} callback - Callback function
 * @param {Object} options - Watch options
 * @returns {Function} Function to stop watching
 */
function watch$1(source, callback, options = {}) {
    const { immediate = false } = options;
    // Handle ref or reactive objects
    const getter = typeof source === 'function'
        ? source
        : () => {
            // Handle ref
            if (source && 'value' in source) {
                return source.value;
            }
            // Handle reactive object
            return source;
        };
    let oldValue;
    const runner = effect$2(() => getter(), {
        lazy: true,
        scheduler: () => {
            const newValue = runner();
            callback(newValue, oldValue);
            oldValue = newValue;
        }
    });
    if (immediate) {
        oldValue = runner();
        callback(oldValue, undefined);
    } else {
        oldValue = runner();
    }
    return () => {
        // Cleanup effect
        runner.active = false;
    };
}
/**
 * Runs a callback once when the component is mounted
 * @param {Function} callback - Callback function
 */
function onMounted$1(callback) {
    getCurrentInstance$1().mounted.push(callback);
}
/**
 * Runs a callback before the component is unmounted
 * @param {Function} callback - Callback function
 */
function onUnmounted$1(callback) {
    getCurrentInstance$1().unmounted.push(callback);
}
/**
 * Runs a callback before the component is updated
 * @param {Function} callback - Callback function
 */
function onBeforeUpdate(callback) {
    getCurrentInstance$1().beforeUpdate.push(callback);
}
/**
 * Runs a callback after the component is updated
 * @param {Function} callback - Callback function
 */
function onUpdated(callback) {
    getCurrentInstance$1().updated.push(callback);
}
// @kalxjs/core - Lifecycle hooks for Composition API
/**
 * Runs a callback when the component is created
 * @param {Function} callback - Callback function
 */
function onCreated(callback) {
    const instance = getCurrentInstance$1();
    if (!instance.created) {
        instance.created = [];
    }
    instance.created.push(callback);
}
/**
 * Runs a callback before the component is mounted
 * @param {Function} callback - Callback function
 */
function onBeforeMount(callback) {
    const instance = getCurrentInstance$1();
    if (!instance.beforeMount) {
        instance.beforeMount = [];
    }
    instance.beforeMount.push(callback);
}
/**
 * Runs a callback before the component is unmounted
 * @param {Function} callback - Callback function
 */
function onBeforeUnmount(callback) {
    const instance = getCurrentInstance$1();
    if (!instance.beforeUnmount) {
        instance.beforeUnmount = [];
    }
    instance.beforeUnmount.push(callback);
}
/**
 * Runs a callback when an error occurs in the component
 * @param {Function} callback - Callback function
 */
function onErrorCaptured(callback) {
    const instance = getCurrentInstance$1();
    if (!instance.errorCaptured) {
        instance.errorCaptured = [];
    }
    instance.errorCaptured.push(callback);
}
// @kalxjs/core - Utility functions for Composition API
/**
 * Creates a reactive reference with a getter and setter
 * @param {any} initialValue - Initial value
 * @param {Function} getter - Custom getter function
 * @param {Function} setter - Custom setter function
 * @returns {Object} Reactive reference
 */
function customRef(factory) {
    const track = () => { };
    const trigger = () => { };
    const { get, set } = factory(track, trigger);
    return Object.defineProperty({}, 'value', {
        get,
        set
    });
}
/**
 * Creates a readonly reference
 * @param {Object} source - Source reference
 * @returns {Object} Readonly reference
 */
function readonly(source) {
    // Handle ref
    if (source && typeof source === 'object' && 'value' in source) {
        return Object.defineProperty({}, 'value', {
            get: () => source.value,
            set: () => {
                console.warn('Cannot set a readonly ref');
            }
        });
    }
    // Handle reactive object
    const handler = {
        get(target, key, receiver) {
            const result = Reflect.get(target, key, receiver);
            return result;
        },
        set() {
            console.warn('Cannot set a readonly reactive object');
            return true;
        },
        deleteProperty() {
            console.warn('Cannot delete from a readonly reactive object');
            return true;
        }
    };
    return new Proxy(source, handler);
}
/**
 * Creates a computed reference that can be both read and written
 * @param {Object} options - Options with get and set functions
 * @returns {Object} Computed reference
 */
function writableComputed(options) {
    const { get, set } = options;
    const computedRef = {
        get value() {
            return get();
        },
        set value(newValue) {
            set(newValue);
        }
    };
    return computedRef;
}
/**
 * Creates a reactive reference that is synchronized with localStorage
 * @param {string} key - localStorage key
 * @param {any} defaultValue - Default value if key doesn't exist
 * @returns {Object} Reactive reference
 */
function useLocalStorage(key, defaultValue) {
    // Get initial value from localStorage or use default
    const initialValue = (() => {
        if (typeof window === 'undefined') return defaultValue;
        try {
            const item = window.localStorage.getItem(key);
            return item ? JSON.parse(item) : defaultValue;
        } catch (error) {
            console.warn(`Error reading localStorage key "${key}":`, error);
            return defaultValue;
        }
    })();
    // Create a ref with the initial value
    const valueRef = ref$1(initialValue);
    // Watch for changes and update localStorage
    if (typeof window !== 'undefined') {
        effect$2(() => {
            try {
                window.localStorage.setItem(key, JSON.stringify(valueRef.value));
            } catch (error) {
                console.warn(`Error setting localStorage key "${key}":`, error);
            }
        });
    }
    return valueRef;
}
/**
 * Creates a debounced version of a function
 * @param {Function} fn - Function to debounce
 * @param {number} delay - Delay in milliseconds
 * @returns {Function} Debounced function
 */
function useDebounce(fn, delay) {
    let timeout;
    return (...args) => {
        clearTimeout(timeout);
        timeout = setTimeout(() => {
            fn(...args);
        }, delay);
    };
}
/**
 * Creates a throttled version of a function
 * @param {Function} fn - Function to throttle
 * @param {number} limit - Limit in milliseconds
 * @returns {Function} Throttled function
 */
function useThrottle(fn, limit) {
    let inThrottle;
    return (...args) => {
        if (!inThrottle) {
            fn(...args);
            inThrottle = true;
            setTimeout(() => {
                inThrottle = false;
            }, limit);
        }
    };
}
/**
 * Creates a reactive reference that tracks mouse position
 * @returns {Object} Reactive mouse position
 */
function useMouse() {
    const position = reactive$1({
        x: 0,
        y: 0
    });
    const update = (event) => {
        position.x = event.clientX;
        position.y = event.clientY;
    };
    if (typeof window !== 'undefined') {
        window.addEventListener('mousemove', update);
        // Clean up event listener when component is unmounted
        const instance = getCurrentInstance$1();
        if (instance) {
            if (!instance.unmounted) {
                instance.unmounted = [];
            }
            instance.unmounted.push(() => {
                window.removeEventListener('mousemove', update);
            });
        }
    }
    return position;
}
// Symbol for internal provide/inject
const PROVIDE_KEY = Symbol('provide');
/**
 * Provide a value that can be injected by descendant components
 * @param {string|symbol} key - The key to provide the value under
 * @param {*} value - The value to provide
 */
function provide(key, value) {
    const instance = getCurrentInstance$1();
    if (!instance) {
        if (process.env.NODE_ENV !== 'production') {
            console.warn('provide() can only be used inside a setup function.');
        }
        return;
    }
    // Initialize provides map if it doesn't exist
    if (!instance[PROVIDE_KEY]) {
        instance[PROVIDE_KEY] = {};
    }
    instance[PROVIDE_KEY][key] = value;
}
/**
 * Inject a value provided by an ancestor component
 * @param {string|symbol} key - The key to inject
 * @param {*} defaultValue - Default value if key is not found
 * @param {boolean} treatDefaultAsFactory - Whether to treat defaultValue as a factory function
 * @returns {*} The injected value or default value
 */
function inject(key, defaultValue, treatDefaultAsFactory = false) {
    const instance = getCurrentInstance$1();
    if (!instance) {
        if (process.env.NODE_ENV !== 'production') {
            console.warn('inject() can only be used inside a setup function.');
        }
        return defaultValue;
    }
    // Walk up the component tree to find the provided value
    let current = instance.parent;
    while (current) {
        if (current[PROVIDE_KEY] && key in current[PROVIDE_KEY]) {
            return current[PROVIDE_KEY][key];
        }
        current = current.parent;
    }
    // Check if the app instance has the provided value
    if (instance.appContext && instance.appContext.provides && key in instance.appContext.provides) {
        return instance.appContext.provides[key];
    }
    // Return default value
    if (arguments.length > 1) {
        return treatDefaultAsFactory && typeof defaultValue === 'func