@kalxjs/core
Version: 
A modern JavaScript framework for building user interfaces with reactive state, composition API, and built-in performance optimizations
1,340 lines (1,184 loc) • 541 kB
JavaScript
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('fs'), require('path'), require('stream')) :
    typeof define === 'function' && define.amd ? define(['exports', 'fs', 'path', 'stream'], factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.kalxjs = {}, global.fs, global.path, global.stream));
})(this, (function (exports, fs, path, stream) { 'use strict';
    function _interopNamespace(e) {
        if (e && e.__esModule) return e;
        var n = Object.create(null);
        if (e) {
            Object.keys(e).forEach(function (k) {
                if (k !== 'default') {
                    var d = Object.getOwnPropertyDescriptor(e, k);
                    Object.defineProperty(n, k, d.get ? d : {
                        enumerable: true,
                        get: function () { return e[k]; }
                    });
                }
            });
        }
        n["default"] = e;
        return Object.freeze(n);
    }
    var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
    var path__namespace = /*#__PURE__*/_interopNamespace(path);
    // 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;
            },
            del