UNPKG

@extralam/microui

Version:

A lightweight, modern JavaScript utility library that makes DOM manipulation and event handling simple and efficient.

1,679 lines (1,568 loc) 49.8 kB
/*! MicroUI v1.0.3 | MIT License | https://github.com/lam0819/microui */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.MicroUI = factory()); })(this, (function () { 'use strict'; function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } /** * DOM Utilities * Provides core DOM manipulation functions */ // Element cache for performance var elementCache = new Map(); /** * Query single element with caching * @param {string} selector - CSS selector * @returns {Element|null} - Found element or null */ function $(selector) { if (elementCache.has(selector)) { var cached = elementCache.get(selector); if (document.contains(cached)) { return cached; } elementCache.delete(selector); } var element = document.querySelector(selector); if (element) { elementCache.set(selector, element); } return element; } /** * Query multiple elements * @param {string} selector - CSS selector * @returns {NodeList} - List of found elements */ function $$(selector) { return document.querySelectorAll(selector); } /** * Add classes to element * @param {Element|string} element - Element or selector * @param {string} classes - Space-separated class names */ function addClass(element, classes) { var _el$classList; var el = typeof element === 'string' ? $(element) : element; if (!el) return; var classArray = classes.split(' ').filter(function (cls) { return cls.trim(); }); (_el$classList = el.classList).add.apply(_el$classList, _toConsumableArray(classArray)); } /** * Remove classes from element * @param {Element|string} element - Element or selector * @param {string} classes - Space-separated class names */ function removeClass(element, classes) { var _el$classList2; var el = typeof element === 'string' ? $(element) : element; if (!el) return; var classArray = classes.split(' ').filter(function (cls) { return cls.trim(); }); (_el$classList2 = el.classList).remove.apply(_el$classList2, _toConsumableArray(classArray)); } /** * Toggle class on element * @param {Element|string} element - Element or selector * @param {string} className - Class name to toggle * @param {boolean} force - Force add/remove */ function toggleClass(element, className, force) { var el = typeof element === 'string' ? $(element) : element; if (!el) return; return el.classList.toggle(className, force); } /** * Check if element has class * @param {Element|string} element - Element or selector * @param {string} className - Class name to check * @returns {boolean} - True if element has class */ function hasClass(element, className) { var el = typeof element === 'string' ? $(element) : element; if (!el) return false; return el.classList.contains(className); } /** * Set or get attribute * @param {Element|string} element - Element or selector * @param {string} name - Attribute name * @param {string} value - Attribute value (optional) * @returns {string|void} - Attribute value if getting */ function attr(element, name, value) { var el = typeof element === 'string' ? $(element) : element; if (!el) return; if (value === undefined) { return el.getAttribute(name); } if (value === null) { el.removeAttribute(name); } else { el.setAttribute(name, value); } } /** * Set or get data attribute * @param {Element|string} element - Element or selector * @param {string} key - Data key * @param {any} value - Data value (optional) * @returns {any} - Data value if getting */ function data(element, key, value) { var el = typeof element === 'string' ? $(element) : element; if (!el) return; if (value === undefined) { var dataValue = el.dataset[key]; try { return JSON.parse(dataValue); } catch (_unused) { return dataValue; } } el.dataset[key] = _typeof(value) === 'object' ? JSON.stringify(value) : value; } /** * Set HTML content * @param {Element|string} element - Element or selector * @param {string} html - HTML content */ function html(element, html) { var el = typeof element === 'string' ? $(element) : element; if (!el) return; el.innerHTML = html; } /** * Append HTML content * @param {Element|string} element - Element or selector * @param {string} html - HTML content to append */ function append(element, html) { var el = typeof element === 'string' ? $(element) : element; if (!el) return; el.insertAdjacentHTML('beforeend', html); } /** * Prepend HTML content * @param {Element|string} element - Element or selector * @param {string} html - HTML content to prepend */ function prepend(element, html) { var el = typeof element === 'string' ? $(element) : element; if (!el) return; el.insertAdjacentHTML('afterbegin', html); } /** * Remove element * @param {Element|string} element - Element or selector */ function remove(element) { var el = typeof element === 'string' ? $(element) : element; if (!el) return; el.remove(); } /** * Find closest ancestor matching selector * @param {Element} element - Starting element * @param {string} selector - CSS selector * @returns {Element|null} - Closest matching element */ function closest(element, selector) { return element.closest(selector); } /** * Event System * Provides event delegation and handling */ // Store delegated event handlers var eventHandlers = new Map(); /** * Add event listener with delegation * @param {string} event - Event type * @param {string} selector - CSS selector for delegation * @param {Function} handler - Event handler function */ function on(event, selector, handler) { var events = event.split(' '); events.forEach(function (eventType) { var key = "".concat(eventType, ":").concat(selector); if (!eventHandlers.has(key)) { eventHandlers.set(key, new Set()); // Add delegated event listener to document document.addEventListener(eventType, function (e) { var target = e.target.closest(selector); if (target) { var handlers = eventHandlers.get(key); if (handlers) { handlers.forEach(function (h) { return h.call(target, e); }); } } }); } eventHandlers.get(key).add(handler); }); } /** * Remove event listeners * @param {string} event - Event type * @param {string} selector - CSS selector * @param {Function} handler - Specific handler to remove (optional) */ function off(event, selector, handler) { var events = event.split(' '); events.forEach(function (eventType) { var key = "".concat(eventType, ":").concat(selector); var handlers = eventHandlers.get(key); if (handlers) { if (handler) { handlers.delete(handler); } else { handlers.clear(); } if (handlers.size === 0) { eventHandlers.delete(key); } } }); } /** * Add one-time event listener * @param {string} event - Event type * @param {string} selector - CSS selector * @param {Function} handler - Event handler function */ function once(event, selector, handler) { var _onceHandler = function onceHandler(e) { handler.call(this, e); off(event, selector, _onceHandler); }; on(event, selector, _onceHandler); } /** * Trigger custom event * @param {Element|string} element - Element or selector * @param {string} eventType - Event type * @param {any} data - Event data */ function trigger(element, eventType, data) { var el = typeof element === 'string' ? document.querySelector(element) : element; if (!el) return; var event = new CustomEvent(eventType, { detail: data, bubbles: true, cancelable: true }); el.dispatchEvent(event); } /** * DOM ready handler * @param {Function} callback - Callback function */ function ready(callback) { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', callback); } else { callback(); } } /** * AJAX Utilities * Provides Promise-based HTTP requests */ /** * Default options for AJAX requests */ var defaultOptions = { method: 'GET', headers: { 'Content-Type': 'application/json' }, timeout: 5000 }; /** * Generic AJAX request * @param {Object} options - Request options * @returns {Promise} - Promise resolving to response data */ function ajax(options) { var config = _objectSpread2(_objectSpread2({}, defaultOptions), options); return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest(); var isTimedOut = false; var timeoutId = setTimeout(function () { isTimedOut = true; xhr.abort(); reject(new Error('Request timeout')); }, config.timeout); xhr.open(config.method, config.url); // Set headers if (config.headers) { Object.entries(config.headers).forEach(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), key = _ref2[0], value = _ref2[1]; xhr.setRequestHeader(key, value); }); } xhr.onload = function () { clearTimeout(timeoutId); if (xhr.status >= 200 && xhr.status < 300) { try { var contentType = xhr.getResponseHeader('Content-Type'); var response = xhr.responseText; if (contentType && contentType.includes('application/json')) { response = JSON.parse(xhr.responseText); } resolve(response); } catch (e) { reject(new Error('Invalid JSON response')); } } else { reject(new Error("HTTP ".concat(xhr.status, ": ").concat(xhr.statusText))); } }; xhr.onerror = function () { clearTimeout(timeoutId); reject(new Error('Network error')); }; xhr.onabort = function () { clearTimeout(timeoutId); if (!isTimedOut) { reject(new Error('Request aborted')); } }; // Send request if (config.data) { if (config.method === 'GET') { // Append data as query string for GET requests var params = new URLSearchParams(config.data).toString(); xhr.open(config.method, "".concat(config.url, "?").concat(params)); xhr.send(); } else { // Send data as JSON for other methods var payload = typeof config.data === 'string' ? config.data : JSON.stringify(config.data); xhr.send(payload); } } else { xhr.send(); } }); } /** * GET request * @param {string} url - Request URL * @param {Object} options - Additional options * @returns {Promise} - Promise resolving to response data */ function get(url) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return ajax(_objectSpread2(_objectSpread2({}, options), {}, { method: 'GET', url: url })); } /** * POST request * @param {string} url - Request URL * @param {any} data - Request data * @param {Object} options - Additional options * @returns {Promise} - Promise resolving to response data */ function post(url, data) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; return ajax(_objectSpread2(_objectSpread2({}, options), {}, { method: 'POST', url: url, data: data })); } /** * PUT request * @param {string} url - Request URL * @param {any} data - Request data * @param {Object} options - Additional options * @returns {Promise} - Promise resolving to response data */ function put(url, data) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; return ajax(_objectSpread2(_objectSpread2({}, options), {}, { method: 'PUT', url: url, data: data })); } /** * DELETE request * @param {string} url - Request URL * @param {Object} options - Additional options * @returns {Promise} - Promise resolving to response data */ function del(url) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return ajax(_objectSpread2(_objectSpread2({}, options), {}, { method: 'DELETE', url: url })); } /** * Load HTML content into element * @param {Element|string} element - Target element or selector * @param {string} url - URL to load content from * @returns {Promise} - Promise resolving when content is loaded */ function load(element, url) { return get(url).then(function (html) { var el = typeof element === 'string' ? document.querySelector(element) : element; if (el) { el.innerHTML = html; } return html; }); } /** * Utility Functions * Provides helper functions for common tasks */ /** * Debounce function * @param {Function} func - Function to debounce * @param {number} wait - Wait time in milliseconds * @returns {Function} - Debounced function */ function debounce(func, wait) { var timeout; return function executedFunction() { var _this = this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } var later = function later() { clearTimeout(timeout); func.apply(_this, args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } /** * Throttle function * @param {Function} func - Function to throttle * @param {number} limit - Time limit in milliseconds * @returns {Function} - Throttled function */ function throttle(func, limit) { var inThrottle; return function executedFunction() { if (!inThrottle) { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } func.apply(this, args); inThrottle = true; setTimeout(function () { return inThrottle = false; }, limit); } }; } /** * Merge objects * @param {Object} target - Target object * @param {...Object} sources - Source objects * @returns {Object} - Merged object */ function extend(target) { for (var _len3 = arguments.length, sources = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { sources[_key3 - 1] = arguments[_key3]; } if (!sources.length) return target; var source = sources.shift(); if (isObject(target) && isObject(source)) { for (var key in source) { if (isObject(source[key])) { if (!target[key]) Object.assign(target, _defineProperty({}, key, {})); extend(target[key], source[key]); } else { Object.assign(target, _defineProperty({}, key, source[key])); } } } return extend.apply(void 0, [target].concat(sources)); } /** * Check if value is an object * @param {any} item - Value to check * @returns {boolean} - True if value is an object */ function isObject(item) { return item && _typeof(item) === 'object' && !Array.isArray(item); } /** * Generate unique ID * @param {string} prefix - ID prefix * @returns {string} - Unique ID */ function uniqueId() { var prefix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'id'; return "".concat(prefix, "_").concat(Math.random().toString(36).substr(2, 9)); } /** * Check if element is visible * @param {Element} element - Element to check * @returns {boolean} - True if element is visible */ function isVisible(element) { return !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length); } /** * Get element offset * @param {Element} element - Element to get offset for * @returns {Object} - Object with top and left properties */ function offset(element) { var rect = element.getBoundingClientRect(); return { top: rect.top + window.pageYOffset, left: rect.left + window.pageXOffset }; } /** * Animation Module * Provides animation utilities using Web Animations API */ /** * Fade in animation * @param {Element|string} element - Element or selector * @param {number} duration - Animation duration in milliseconds * @param {Function} callback - Callback function when animation completes */ function fadeIn(element) { var duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300; var callback = arguments.length > 2 ? arguments[2] : undefined; var el = typeof element === 'string' ? document.querySelector(element) : element; if (!el) return; el.style.display = el.style.display === 'none' ? '' : el.style.display; var animation = el.animate([{ opacity: 0 }, { opacity: 1 }], { duration: duration, easing: 'ease-in-out', fill: 'forwards' }); if (callback) { animation.addEventListener('finish', callback); } return animation; } /** * Fade out animation * @param {Element|string} element - Element or selector * @param {number} duration - Animation duration in milliseconds * @param {Function} callback - Callback function when animation completes */ function fadeOut(element) { var duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300; var callback = arguments.length > 2 ? arguments[2] : undefined; var el = typeof element === 'string' ? document.querySelector(element) : element; if (!el) return; var animation = el.animate([{ opacity: 1 }, { opacity: 0 }], { duration: duration, easing: 'ease-in-out', fill: 'forwards' }); animation.addEventListener('finish', function () { el.style.display = 'none'; if (callback) callback(); }); return animation; } /** * Slide down animation * @param {Element|string} element - Element or selector * @param {number} duration - Animation duration in milliseconds * @param {Function} callback - Callback function when animation completes */ function slideDown(element) { var duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 400; var callback = arguments.length > 2 ? arguments[2] : undefined; var el = typeof element === 'string' ? document.querySelector(element) : element; if (!el) return; var startHeight = el.offsetHeight; el.style.overflow = 'hidden'; el.style.display = el.style.display === 'none' ? 'block' : el.style.display; var endHeight = el.scrollHeight; var animation = el.animate([{ height: "".concat(startHeight, "px") }, { height: "".concat(endHeight, "px") }], { duration: duration, easing: 'ease-in-out', fill: 'forwards' }); animation.addEventListener('finish', function () { el.style.height = ''; el.style.overflow = ''; if (callback) callback(); }); return animation; } /** * Slide up animation * @param {Element|string} element - Element or selector * @param {number} duration - Animation duration in milliseconds * @param {Function} callback - Callback function when animation completes */ function slideUp(element) { var duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 400; var callback = arguments.length > 2 ? arguments[2] : undefined; var el = typeof element === 'string' ? document.querySelector(element) : element; if (!el) return; var startHeight = el.offsetHeight; el.style.overflow = 'hidden'; var animation = el.animate([{ height: "".concat(startHeight, "px") }, { height: '0px' }], { duration: duration, easing: 'ease-in-out', fill: 'forwards' }); animation.addEventListener('finish', function () { el.style.display = 'none'; el.style.height = ''; el.style.overflow = ''; if (callback) callback(); }); return animation; } /** * Custom animation using Web Animations API * @param {Element|string} element - Element or selector * @param {Object|Array} keyframes - Animation keyframes * @param {Object} options - Animation options */ function animate(element, keyframes) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var el = typeof element === 'string' ? document.querySelector(element) : element; if (!el) return; var defaultOptions = { duration: 1000, easing: 'ease', fill: 'both' }; var config = _objectSpread2(_objectSpread2({}, defaultOptions), options); return el.animate(keyframes, config); } /** * Storage Module * Provides localStorage and sessionStorage wrappers */ /** * LocalStorage wrapper */ var store = { /** * Set item in localStorage * @param {string} key - Storage key * @param {any} value - Value to store */ set: function set(key, value) { try { var serializedValue = JSON.stringify(value); localStorage.setItem(key, serializedValue); } catch (e) { console.warn('Failed to save to localStorage:', e); } }, /** * Get item from localStorage * @param {string} key - Storage key * @param {any} defaultValue - Default value if key doesn't exist * @returns {any} - Retrieved value */ get: function get(key) { var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; try { var item = localStorage.getItem(key); return item ? JSON.parse(item) : defaultValue; } catch (e) { console.warn('Failed to retrieve from localStorage:', e); return defaultValue; } }, /** * Remove item from localStorage * @param {string} key - Storage key */ remove: function remove(key) { try { localStorage.removeItem(key); } catch (e) { console.warn('Failed to remove from localStorage:', e); } }, /** * Clear all items from localStorage */ clear: function clear() { try { localStorage.clear(); } catch (e) { console.warn('Failed to clear localStorage:', e); } }, /** * Get all keys from localStorage * @returns {string[]} - Array of storage keys */ keys: function keys() { try { return Object.keys(localStorage); } catch (e) { console.warn('Failed to get localStorage keys:', e); return []; } } }; /** * SessionStorage wrapper */ var session = { /** * Set item in sessionStorage * @param {string} key - Storage key * @param {any} value - Value to store */ set: function set(key, value) { try { var serializedValue = JSON.stringify(value); sessionStorage.setItem(key, serializedValue); } catch (e) { console.warn('Failed to save to sessionStorage:', e); } }, /** * Get item from sessionStorage * @param {string} key - Storage key * @param {any} defaultValue - Default value if key doesn't exist * @returns {any} - Retrieved value */ get: function get(key) { var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; try { var item = sessionStorage.getItem(key); return item ? JSON.parse(item) : defaultValue; } catch (e) { console.warn('Failed to retrieve from sessionStorage:', e); return defaultValue; } }, /** * Remove item from sessionStorage * @param {string} key - Storage key */ remove: function remove(key) { try { sessionStorage.removeItem(key); } catch (e) { console.warn('Failed to remove from sessionStorage:', e); } }, /** * Clear all items from sessionStorage */ clear: function clear() { try { sessionStorage.clear(); } catch (e) { console.warn('Failed to clear sessionStorage:', e); } }, /** * Get all keys from sessionStorage * @returns {string[]} - Array of storage keys */ keys: function keys() { try { return Object.keys(sessionStorage); } catch (e) { console.warn('Failed to get sessionStorage keys:', e); return []; } } }; /** * Component System * Simple component-based architecture for reusable UI elements */ var Component = /*#__PURE__*/function () { function Component(name, definition) { var _this = this; _classCallCheck(this, Component); this.name = name; this.template = definition.template || ''; this.props = definition.props || {}; this.state = _objectSpread2({}, definition.state) || {}; this.methods = definition.methods || {}; this.events = definition.events || {}; this.lifecycle = definition.lifecycle || {}; this.element = null; this.mounted = false; // Bind methods to component instance Object.keys(this.methods).forEach(function (methodName) { _this.methods[methodName] = _this.methods[methodName].bind(_this); }); } /** * Render template with state and props */ return _createClass(Component, [{ key: "render", value: function render() { var html = this.template; // Replace template variables with state/props var data = _objectSpread2(_objectSpread2({}, this.props), this.state); Object.keys(data).forEach(function (key) { var regex = new RegExp("{{".concat(key, "}}"), 'g'); html = html.replace(regex, data[key]); }); return html; } /** * Update component DOM */ }, { key: "update", value: function update() { var _this2 = this; if (!this.element) return; // Clean up existing event handlers if (this._eventHandlers) { this._eventHandlers.forEach(function (_ref) { var eventType = _ref.eventType, handler = _ref.handler; _this2.element.removeEventListener(eventType, handler, true); }); this._eventHandlers = []; } var newHTML = this.render(); this.element.innerHTML = newHTML; this.bindEvents(); } /** * Bind component events */ }, { key: "bindEvents", value: function bindEvents() { var _this3 = this; if (!this.element) return; Object.keys(this.events).forEach(function (eventKey) { var parts = eventKey.trim().split(/\s+/); var eventType = parts[0]; var selector = parts.slice(1).join(' '); var methodName = _this3.events[eventKey]; var method = _this3.methods[methodName]; if (method && selector && eventType) { // Create bound handler for this specific event var boundHandler = function boundHandler(e) { var target = e.target.closest(selector); if (target && _this3.element.contains(target)) { method.call(_this3, e); } }; // Store handler for potential cleanup _this3._eventHandlers = _this3._eventHandlers || []; _this3._eventHandlers.push({ eventType: eventType, handler: boundHandler }); // Add event listener to the component element _this3.element.addEventListener(eventType, boundHandler, true); } }); } /** * Mount component to DOM element */ }, { key: "mount", value: function mount(container) { var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; // Merge props this.props = _objectSpread2(_objectSpread2({}, this.props), props); // Call lifecycle hook if (this.lifecycle.created) { this.lifecycle.created.call(this); } // Create element var wrapper = document.createElement('div'); wrapper.innerHTML = this.render(); this.element = wrapper.firstElementChild; // Append to container if (typeof container === 'string') { container = document.querySelector(container); } container.appendChild(this.element); // Bind events this.bindEvents(); this.mounted = true; // Call lifecycle hook if (this.lifecycle.mounted) { this.lifecycle.mounted.call(this); } return this; } /** * Unmount component */ }, { key: "unmount", value: function unmount() { var _this4 = this; if (this.lifecycle.beforeDestroy) { this.lifecycle.beforeDestroy.call(this); } // Clean up event listeners if (this._eventHandlers && this.element) { this._eventHandlers.forEach(function (_ref2) { var eventType = _ref2.eventType, handler = _ref2.handler; _this4.element.removeEventListener(eventType, handler, true); }); this._eventHandlers = []; } if (this.element && this.element.parentNode) { this.element.parentNode.removeChild(this.element); } this.element = null; this.mounted = false; if (this.lifecycle.destroyed) { this.lifecycle.destroyed.call(this); } } /** * Set state and trigger update */ }, { key: "setState", value: function setState(newState) { this.state = _objectSpread2(_objectSpread2({}, this.state), newState); this.update(); } /** * Set props and trigger update */ }, { key: "setProps", value: function setProps(newProps) { this.props = _objectSpread2(_objectSpread2({}, this.props), newProps); this.update(); } }]); }(); // Global component registry var components = new Map(); /** * Register a component */ function component(name, definition) { components.set(name, definition); return definition; } /** * Mount a component instance */ function mount(container, componentName) { var props = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var definition = components.get(componentName); if (!definition) { throw new Error("Component \"".concat(componentName, "\" not found")); } var instance = new Component(componentName, definition); return instance.mount(container, props); } /** * Create component instance without mounting */ function create(componentName) { var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var definition = components.get(componentName); if (!definition) { throw new Error("Component \"".concat(componentName, "\" not found")); } var instance = new Component(componentName, definition); // Set initial props instance.props = _objectSpread2(_objectSpread2({}, instance.props), props); return instance; } /** * Get registered component */ function getComponent(name) { return components.get(name); } /** * List all registered components */ function listComponents() { return Array.from(components.keys()); } /** * Event Delegation System * Advanced event delegation with namespaces and scoped handlers */ var DelegationNamespace = /*#__PURE__*/function () { function DelegationNamespace(name) { var container = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document; _classCallCheck(this, DelegationNamespace); this.name = name; this.container = container; this.handlers = new Map(); this.active = true; } /** * Add event handler to namespace */ return _createClass(DelegationNamespace, [{ key: "on", value: function on(event, selector, handler) { var key = "".concat(event, ":").concat(selector); if (!this.handlers.has(key)) { this.handlers.set(key, new Set()); } this.handlers.get(key).add(handler); // Add actual event listener if this is the first handler for this event/selector combo if (this.handlers.get(key).size === 1) { this.attachListener(event, selector); } return this; } /** * Remove event handler from namespace */ }, { key: "off", value: function off(event, selector) { var handler = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; var key = "".concat(event, ":").concat(selector); if (!this.handlers.has(key)) { return this; } if (handler) { // Remove specific handler this.handlers.get(key).delete(handler); // If no handlers left, remove the event listener if (this.handlers.get(key).size === 0) { this.detachListener(event, selector); this.handlers.delete(key); } } else { // Remove all handlers for this event/selector this.detachListener(event, selector); this.handlers.delete(key); } return this; } /** * Add one-time event handler */ }, { key: "once", value: function once(event, selector, handler) { var _this = this; var _onceHandler = function onceHandler(e) { handler.call(e.target, e); _this.off(event, selector, _onceHandler); }; return this.on(event, selector, _onceHandler); } /** * Trigger custom event on matching elements */ }, { key: "trigger", value: function trigger(selector, eventType) { var data = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var elements = this.container.querySelectorAll(selector); elements.forEach(function (element) { var event = new CustomEvent(eventType, { detail: data, bubbles: true, cancelable: true }); element.dispatchEvent(event); }); return this; } /** * Attach actual DOM event listener */ }, { key: "attachListener", value: function attachListener(event, selector) { var _this2 = this; var key = "".concat(event, ":").concat(selector); var delegatedHandler = function delegatedHandler(e) { if (!_this2.active) return; var target = e.target.closest(selector); if (target && _this2.container.contains(target)) { var handlers = _this2.handlers.get(key); if (handlers) { handlers.forEach(function (handler) { try { handler.call(target, e); } catch (error) { // Re-throw error to be handled by global error handlers setTimeout(function () { throw new Error("Delegation handler error in ".concat(_this2.name, ": ").concat(error.message)); }, 0); } }); } } }; // Store the actual handler for later removal this._actualHandlers = this._actualHandlers || new Map(); this._actualHandlers.set(key, delegatedHandler); this.container.addEventListener(event, delegatedHandler, true); } /** * Detach DOM event listener */ }, { key: "detachListener", value: function detachListener(event, selector) { var key = "".concat(event, ":").concat(selector); if (this._actualHandlers && this._actualHandlers.has(key)) { var handler = this._actualHandlers.get(key); this.container.removeEventListener(event, handler, true); this._actualHandlers.delete(key); } } /** * Pause all event handling for this namespace */ }, { key: "pause", value: function pause() { this.active = false; return this; } /** * Resume event handling for this namespace */ }, { key: "resume", value: function resume() { this.active = true; return this; } /** * Check if namespace is active */ }, { key: "isActive", value: function isActive() { return this.active; } /** * Get all handlers for debugging */ }, { key: "getHandlers", value: function getHandlers() { var result = {}; this.handlers.forEach(function (handlers, key) { result[key] = Array.from(handlers); }); return result; } /** * Destroy namespace and remove all handlers */ }, { key: "destroy", value: function destroy() { var _this3 = this; // Remove all event listeners this.handlers.forEach(function (handlers, key) { var _key$split = key.split(':'), _key$split2 = _slicedToArray(_key$split, 2), event = _key$split2[0], selector = _key$split2[1]; _this3.detachListener(event, selector); }); // Clear maps this.handlers.clear(); if (this._actualHandlers) { this._actualHandlers.clear(); } this.active = false; // Remove from global registry if (namespaces.has(this.name)) { namespaces.delete(this.name); } } }]); }(); // Global namespace registry var namespaces = new Map(); /** * Create or get event delegation namespace */ function delegate(name) { var handlers = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var container = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : document; var namespace; if (namespaces.has(name)) { namespace = namespaces.get(name); } else { namespace = new DelegationNamespace(name, container); namespaces.set(name, namespace); } // Add handlers if provided Object.keys(handlers).forEach(function (eventSelector) { var _eventSelector$split = eventSelector.split(' '), _eventSelector$split2 = _slicedToArray(_eventSelector$split, 2), event = _eventSelector$split2[0], selector = _eventSelector$split2[1]; var handler = handlers[eventSelector]; if (event && selector && typeof handler === 'function') { namespace.on(event, selector, handler); } }); return namespace; } /** * Get existing namespace */ function getNamespace(name) { return namespaces.get(name); } /** * Destroy namespace */ function destroyNamespace(name) { var namespace = namespaces.get(name); if (namespace) { namespace.destroy(); } return !namespaces.has(name); } /** * List all active namespaces */ function listNamespaces() { return Array.from(namespaces.keys()); } /** * Pause all namespaces */ function pauseAll() { namespaces.forEach(function (namespace) { return namespace.pause(); }); } /** * Resume all namespaces */ function resumeAll() { namespaces.forEach(function (namespace) { return namespace.resume(); }); } /** * Destroy all namespaces */ function destroyAll() { var names = Array.from(namespaces.keys()); names.forEach(function (name) { return destroyNamespace(name); }); namespaces.clear(); } /** * Create scoped delegation for a specific container */ function scope(container) { var name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "scope_".concat(Date.now()); if (typeof container === 'string') { container = document.querySelector(container); } if (!container) { throw new Error('Container element not found'); } return delegate(name, {}, container); } /** * Advanced delegation with middleware support */ function advanced(name) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var _options$container = options.container, container = _options$container === void 0 ? document : _options$container, _options$middleware = options.middleware, middleware = _options$middleware === void 0 ? [] : _options$middleware, _options$errorHandler = options.errorHandler, errorHandler = _options$errorHandler === void 0 ? null : _options$errorHandler; var namespace = delegate(name, {}, container); // Override the on method to support middleware var originalOn = namespace.on; namespace.on = function (event, selector, handler) { var _this4 = this; var wrappedHandler = function wrappedHandler(e) { // Run middleware chain var index = 0; var _next = function next() { if (index < middleware.length) { var middleware_fn = middleware[index++]; try { middleware_fn(e, _next); } catch (error) { if (errorHandler) { errorHandler(error, e); } else { // Re-throw error to be handled by global error handlers setTimeout(function () { throw new Error("Middleware error: ".concat(error.message)); }, 0); } } } else { // All middleware passed, run original handler try { handler.call(_this4, e); } catch (error) { if (errorHandler) { errorHandler(error, e); } else { // Re-throw error to be handled by global error handlers setTimeout(function () { throw new Error("Handler error: ".concat(error.message)); }, 0); } } } }; _next(); }; return originalOn.call(this, event, selector, wrappedHandler); }; return namespace; } /** * MicroUI - Main Entry Point * Exports all library functionality */ /** * MicroUI Library * Main library object containing all functionality */ var MicroUI = { // DOM utilities $: $, $$: $$, addClass: addClass, removeClass: removeClass, toggleClass: toggleClass, hasClass: hasClass, attr: attr, data: data, html: html, append: append, prepend: prepend, remove: remove, closest: closest, // Event system on: on, off: off, once: once, trigger: trigger, ready: ready, // AJAX utilities ajax: ajax, get: get, post: post, put: put, delete: del, // 'delete' is a reserved word load: load, // Animation fadeIn: fadeIn, fadeOut: fadeOut, slideDown: slideDown, slideUp: slideUp, animate: animate, // Storage store: store, session: session, // Component system component: component, mount: mount, create: create, getComponent: getComponent, listComponents: listComponents, // Delegation system delegate: delegate, getNamespace: getNamespace, destroyNamespace: destroyNamespace, listNamespaces: listNamespaces, pauseAll: pauseAll, resumeAll: resumeAll, destroyAll: destroyAll, scope: scope, advanced: advanced, // Utilities debounce: debounce, throttle: throttle, extend: extend, uniqueId: uniqueId, isVisible: isVisible, offset: offset, // Version version: '1.0.3' }; // For UMD build if (typeof window !== 'undefined') { window.MicroUI = MicroUI; } return MicroUI; }));