@bquery/bquery 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -6
- package/dist/full.d.ts +6 -0
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +58 -35
- package/dist/full.es.mjs.map +1 -1
- package/dist/full.iife.js +6 -1
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +6 -1
- package/dist/full.umd.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.mjs +58 -35
- package/dist/index.es.mjs.map +1 -1
- package/dist/reactive/signal.d.ts +7 -0
- package/dist/reactive/signal.d.ts.map +1 -1
- package/dist/reactive.es.mjs +34 -25
- package/dist/reactive.es.mjs.map +1 -1
- package/dist/router/index.d.ts +287 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router.es.mjs +166 -0
- package/dist/router.es.mjs.map +1 -0
- package/dist/store/index.d.ts +288 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store.es.mjs +229 -0
- package/dist/store.es.mjs.map +1 -0
- package/dist/view/index.d.ts +201 -0
- package/dist/view/index.d.ts.map +1 -0
- package/dist/view.es.mjs +325 -0
- package/dist/view.es.mjs.map +1 -0
- package/package.json +132 -120
- package/src/full.ts +44 -0
- package/src/index.ts +9 -0
- package/src/reactive/signal.ts +14 -0
- package/src/router/index.ts +718 -0
- package/src/store/index.ts +848 -0
- package/src/view/index.ts +1041 -0
package/dist/full.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"full.umd.js","sources":["../src/security/sanitize.ts","../src/core/shared.ts","../src/core/element.ts","../src/core/collection.ts","../src/core/selector.ts","../src/core/utils.ts","../src/reactive/signal.ts","../src/component/index.ts","../src/motion/index.ts","../src/platform/buckets.ts","../src/platform/cache.ts","../src/platform/notifications.ts","../src/platform/storage.ts"],"sourcesContent":["/**\r\n * Security utilities for HTML sanitization, CSP compatibility, and Trusted Types.\r\n * All DOM writes are sanitized by default to prevent XSS attacks.\r\n *\r\n * @module bquery/security\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Sanitizer configuration options.\r\n */\r\nexport interface SanitizeOptions {\r\n /** Allow these additional tags (default: none) */\r\n allowTags?: string[];\r\n /** Allow these additional attributes (default: none) */\r\n allowAttributes?: string[];\r\n /** Allow data-* attributes (default: true) */\r\n allowDataAttributes?: boolean;\r\n /** Strip all tags and return plain text (default: false) */\r\n stripAllTags?: boolean;\r\n}\r\n\r\n/**\r\n * Trusted Types policy name.\r\n */\r\nconst POLICY_NAME = 'bquery-sanitizer';\r\n\r\n// ============================================================================\r\n// Trusted Types Support\r\n// ============================================================================\r\n\r\n/** Window interface extended with Trusted Types */\r\ninterface TrustedTypesWindow extends Window {\r\n trustedTypes?: {\r\n createPolicy: (\r\n name: string,\r\n rules: { createHTML?: (input: string) => string }\r\n ) => TrustedTypePolicy;\r\n isHTML?: (value: unknown) => boolean;\r\n };\r\n}\r\n\r\n/** Trusted Types policy interface */\r\ninterface TrustedTypePolicy {\r\n createHTML: (input: string) => TrustedHTML;\r\n}\r\n\r\n/** Trusted HTML type placeholder for environments without Trusted Types */\r\ninterface TrustedHTML {\r\n toString(): string;\r\n}\r\n\r\n/** Cached Trusted Types policy */\r\nlet cachedPolicy: TrustedTypePolicy | null = null;\r\n\r\n/**\r\n * Check if Trusted Types API is available.\r\n * @returns True if Trusted Types are supported\r\n */\r\nexport const isTrustedTypesSupported = (): boolean => {\r\n return typeof (window as TrustedTypesWindow).trustedTypes !== 'undefined';\r\n};\r\n\r\n/**\r\n * Get or create the bQuery Trusted Types policy.\r\n * @returns The Trusted Types policy or null if unsupported\r\n */\r\nexport const getTrustedTypesPolicy = (): TrustedTypePolicy | null => {\r\n if (cachedPolicy) return cachedPolicy;\r\n\r\n const win = window as TrustedTypesWindow;\r\n if (!win.trustedTypes) return null;\r\n\r\n try {\r\n cachedPolicy = win.trustedTypes.createPolicy(POLICY_NAME, {\r\n createHTML: (input: string) => sanitizeHtmlCore(input),\r\n });\r\n return cachedPolicy;\r\n } catch {\r\n // Policy may already exist or be blocked by CSP\r\n console.warn(`bQuery: Could not create Trusted Types policy \"${POLICY_NAME}\"`);\r\n return null;\r\n }\r\n};\r\n\r\n// ============================================================================\r\n// Default Safe Lists\r\n// ============================================================================\r\n\r\n/**\r\n * Default allowed HTML tags considered safe.\r\n */\r\nconst DEFAULT_ALLOWED_TAGS = new Set([\r\n 'a',\r\n 'abbr',\r\n 'address',\r\n 'article',\r\n 'aside',\r\n 'b',\r\n 'bdi',\r\n 'bdo',\r\n 'blockquote',\r\n 'br',\r\n 'button',\r\n 'caption',\r\n 'cite',\r\n 'code',\r\n 'col',\r\n 'colgroup',\r\n 'data',\r\n 'dd',\r\n 'del',\r\n 'details',\r\n 'dfn',\r\n 'div',\r\n 'dl',\r\n 'dt',\r\n 'em',\r\n 'figcaption',\r\n 'figure',\r\n 'footer',\r\n 'form',\r\n 'h1',\r\n 'h2',\r\n 'h3',\r\n 'h4',\r\n 'h5',\r\n 'h6',\r\n 'header',\r\n 'hgroup',\r\n 'hr',\r\n 'i',\r\n 'img',\r\n 'input',\r\n 'ins',\r\n 'kbd',\r\n 'label',\r\n 'legend',\r\n 'li',\r\n 'main',\r\n 'mark',\r\n 'nav',\r\n 'ol',\r\n 'optgroup',\r\n 'option',\r\n 'p',\r\n 'picture',\r\n 'pre',\r\n 'progress',\r\n 'q',\r\n 'rp',\r\n 'rt',\r\n 'ruby',\r\n 's',\r\n 'samp',\r\n 'section',\r\n 'select',\r\n 'small',\r\n 'source',\r\n 'span',\r\n 'strong',\r\n 'sub',\r\n 'summary',\r\n 'sup',\r\n 'table',\r\n 'tbody',\r\n 'td',\r\n 'textarea',\r\n 'tfoot',\r\n 'th',\r\n 'thead',\r\n 'time',\r\n 'tr',\r\n 'u',\r\n 'ul',\r\n 'var',\r\n 'wbr',\r\n]);\r\n\r\n/**\r\n * Explicitly dangerous tags that should never be allowed.\r\n * These are checked even if somehow added to allowTags.\r\n */\r\nconst DANGEROUS_TAGS = new Set([\r\n 'script',\r\n 'iframe',\r\n 'frame',\r\n 'frameset',\r\n 'object',\r\n 'embed',\r\n 'applet',\r\n 'link',\r\n 'meta',\r\n 'style',\r\n 'base',\r\n 'template',\r\n 'slot',\r\n 'math',\r\n 'svg',\r\n 'foreignobject',\r\n 'noscript',\r\n]);\r\n\r\n/**\r\n * Reserved IDs that could cause DOM clobbering attacks.\r\n * These are prevented to avoid overwriting global browser objects.\r\n */\r\nconst RESERVED_IDS = new Set([\r\n // Global objects\r\n 'document',\r\n 'window',\r\n 'location',\r\n 'top',\r\n 'self',\r\n 'parent',\r\n 'frames',\r\n 'history',\r\n 'navigator',\r\n 'screen',\r\n // Dangerous functions\r\n 'alert',\r\n 'confirm',\r\n 'prompt',\r\n 'eval',\r\n 'Function',\r\n // Document properties\r\n 'cookie',\r\n 'domain',\r\n 'referrer',\r\n 'body',\r\n 'head',\r\n 'forms',\r\n 'images',\r\n 'links',\r\n 'scripts',\r\n // DOM traversal properties\r\n 'children',\r\n 'parentNode',\r\n 'firstChild',\r\n 'lastChild',\r\n // Content manipulation\r\n 'innerHTML',\r\n 'outerHTML',\r\n 'textContent',\r\n]);\r\n\r\n/**\r\n * Default allowed attributes considered safe.\r\n */\r\nconst DEFAULT_ALLOWED_ATTRIBUTES = new Set([\r\n 'alt',\r\n 'class',\r\n 'dir',\r\n 'height',\r\n 'hidden',\r\n 'href',\r\n 'id',\r\n 'lang',\r\n 'loading',\r\n 'name',\r\n 'rel',\r\n 'role',\r\n 'src',\r\n 'srcset',\r\n 'style',\r\n 'tabindex',\r\n 'target',\r\n 'title',\r\n 'type',\r\n 'width',\r\n 'aria-*',\r\n]);\r\n\r\n/**\r\n * Dangerous attribute prefixes to always remove.\r\n */\r\nconst DANGEROUS_ATTR_PREFIXES = ['on', 'formaction', 'xlink:', 'xmlns:'];\r\n\r\n/**\r\n * Dangerous URL protocols to block.\r\n */\r\nconst DANGEROUS_PROTOCOLS = ['javascript:', 'data:', 'vbscript:', 'file:'];\r\n\r\n// ============================================================================\r\n// Core Sanitization\r\n// ============================================================================\r\n\r\n/**\r\n * Check if an attribute name is allowed.\r\n * @internal\r\n */\r\nconst isAllowedAttribute = (\r\n name: string,\r\n allowedSet: Set<string>,\r\n allowDataAttrs: boolean\r\n): boolean => {\r\n const lowerName = name.toLowerCase();\r\n\r\n // Check dangerous prefixes\r\n for (const prefix of DANGEROUS_ATTR_PREFIXES) {\r\n if (lowerName.startsWith(prefix)) return false;\r\n }\r\n\r\n // Check data attributes\r\n if (allowDataAttrs && lowerName.startsWith('data-')) return true;\r\n\r\n // Check aria attributes (allowed by default)\r\n if (lowerName.startsWith('aria-')) return true;\r\n\r\n // Check explicit allow list\r\n return allowedSet.has(lowerName);\r\n};\r\n\r\n/**\r\n * Check if an ID/name value could cause DOM clobbering.\r\n * @internal\r\n */\r\nconst isSafeIdOrName = (value: string): boolean => {\r\n const lowerValue = value.toLowerCase().trim();\r\n return !RESERVED_IDS.has(lowerValue);\r\n};\r\n\r\n/**\r\n * Normalize URL by removing control characters, whitespace, and Unicode tricks.\r\n * Enhanced to prevent various bypass techniques.\r\n * @internal\r\n */\r\nconst normalizeUrl = (value: string): string =>\r\n value\r\n // Remove null bytes and control characters\r\n .replace(/[\\u0000-\\u001F\\u007F]+/g, '')\r\n // Remove zero-width characters that could hide malicious content\r\n .replace(/[\\u200B-\\u200D\\uFEFF\\u2028\\u2029]+/g, '')\r\n // Remove escaped Unicode sequences\r\n .replace(/\\\\u[\\da-fA-F]{4}/g, '')\r\n // Remove whitespace\r\n .replace(/\\s+/g, '')\r\n // Normalize case\r\n .toLowerCase();\r\n\r\n/**\r\n * Check if a URL value is safe.\r\n * @internal\r\n */\r\nconst isSafeUrl = (value: string): boolean => {\r\n const normalized = normalizeUrl(value);\r\n for (const protocol of DANGEROUS_PROTOCOLS) {\r\n if (normalized.startsWith(protocol)) return false;\r\n }\r\n return true;\r\n};\r\n\r\n/**\r\n * Check if a URL is external (different origin).\r\n * @internal\r\n */\r\nconst isExternalUrl = (url: string): boolean => {\r\n try {\r\n // Normalize URL by trimming whitespace\r\n const trimmedUrl = url.trim();\r\n \r\n // Protocol-relative URLs (//example.com) are always external.\r\n // CRITICAL: This check must run before the relative-URL check below;\r\n // otherwise, a protocol-relative URL like \"//evil.com\" would be treated\r\n // as a non-http(s) relative URL and incorrectly classified as same-origin.\r\n // Handling them up front guarantees correct security classification.\r\n if (trimmedUrl.startsWith('//')) {\r\n return true;\r\n }\r\n \r\n // Normalize URL for case-insensitive protocol checks\r\n const lowerUrl = trimmedUrl.toLowerCase();\r\n \r\n // Check for non-http(s) protocols which are considered external/special\r\n // (mailto:, tel:, ftp:, etc.)\r\n const hasProtocol = /^[a-z][a-z0-9+.-]*:/i.test(trimmedUrl);\r\n if (hasProtocol && !lowerUrl.startsWith('http://') && !lowerUrl.startsWith('https://')) {\r\n // These are special protocols, not traditional \"external\" links\r\n // but we treat them as external for security consistency\r\n return true;\r\n }\r\n \r\n // Relative URLs are not external\r\n if (!lowerUrl.startsWith('http://') && !lowerUrl.startsWith('https://')) {\r\n return false;\r\n }\r\n \r\n // In non-browser environments (e.g., Node.js), treat all absolute URLs as external\r\n if (typeof window === 'undefined' || !window.location) {\r\n return true;\r\n }\r\n \r\n const urlObj = new URL(trimmedUrl, window.location.href);\r\n return urlObj.origin !== window.location.origin;\r\n } catch {\r\n // If URL parsing fails, treat as potentially external for safety\r\n return true;\r\n }\r\n};\r\n\r\n/**\r\n * Core sanitization logic (without Trusted Types wrapper).\r\n * @internal\r\n */\r\nconst sanitizeHtmlCore = (html: string, options: SanitizeOptions = {}): string => {\r\n const {\r\n allowTags = [],\r\n allowAttributes = [],\r\n allowDataAttributes = true,\r\n stripAllTags = false,\r\n } = options;\r\n\r\n // Build combined allow sets (excluding dangerous tags even if specified)\r\n const allowedTags = new Set(\r\n [...DEFAULT_ALLOWED_TAGS, ...allowTags.map((t) => t.toLowerCase())].filter(\r\n (tag) => !DANGEROUS_TAGS.has(tag)\r\n )\r\n );\r\n const allowedAttrs = new Set([\r\n ...DEFAULT_ALLOWED_ATTRIBUTES,\r\n ...allowAttributes.map((a) => a.toLowerCase()),\r\n ]);\r\n\r\n // Use template for parsing\r\n const template = document.createElement('template');\r\n template.innerHTML = html;\r\n\r\n if (stripAllTags) {\r\n return template.content.textContent ?? '';\r\n }\r\n\r\n // Walk the DOM tree\r\n const walker = document.createTreeWalker(template.content, NodeFilter.SHOW_ELEMENT);\r\n\r\n const toRemove: Element[] = [];\r\n\r\n while (walker.nextNode()) {\r\n const el = walker.currentNode as Element;\r\n const tagName = el.tagName.toLowerCase();\r\n\r\n // Remove explicitly dangerous tags even if in allow list\r\n if (DANGEROUS_TAGS.has(tagName)) {\r\n toRemove.push(el);\r\n continue;\r\n }\r\n\r\n // Remove disallowed tags entirely\r\n if (!allowedTags.has(tagName)) {\r\n toRemove.push(el);\r\n continue;\r\n }\r\n\r\n // Process attributes\r\n const attrsToRemove: string[] = [];\r\n for (const attr of Array.from(el.attributes)) {\r\n const attrName = attr.name.toLowerCase();\r\n\r\n // Check if attribute is allowed\r\n if (!isAllowedAttribute(attrName, allowedAttrs, allowDataAttributes)) {\r\n attrsToRemove.push(attr.name);\r\n continue;\r\n }\r\n\r\n // Check for DOM clobbering on id and name attributes\r\n if ((attrName === 'id' || attrName === 'name') && !isSafeIdOrName(attr.value)) {\r\n attrsToRemove.push(attr.name);\r\n continue;\r\n }\r\n\r\n // Validate URL attributes\r\n if (\r\n (attrName === 'href' || attrName === 'src' || attrName === 'srcset') &&\r\n !isSafeUrl(attr.value)\r\n ) {\r\n attrsToRemove.push(attr.name);\r\n }\r\n }\r\n\r\n // Remove disallowed attributes\r\n for (const attrName of attrsToRemove) {\r\n el.removeAttribute(attrName);\r\n }\r\n\r\n // Add rel=\"noopener noreferrer\" to external links for security\r\n if (tagName === 'a') {\r\n const href = el.getAttribute('href');\r\n const target = el.getAttribute('target');\r\n const hasTargetBlank = target?.toLowerCase() === '_blank';\r\n const isExternal = href && isExternalUrl(href);\r\n\r\n // Add security attributes to links opening in new window or external links\r\n if (hasTargetBlank || isExternal) {\r\n const existingRel = el.getAttribute('rel');\r\n const relValues = new Set(\r\n existingRel ? existingRel.split(/\\s+/).filter(Boolean) : []\r\n );\r\n \r\n // Add noopener and noreferrer\r\n relValues.add('noopener');\r\n relValues.add('noreferrer');\r\n \r\n el.setAttribute('rel', Array.from(relValues).join(' '));\r\n }\r\n }\r\n }\r\n\r\n // Remove disallowed elements\r\n for (const el of toRemove) {\r\n el.remove();\r\n }\r\n\r\n return template.innerHTML;\r\n};\r\n\r\n// ============================================================================\r\n// Public API\r\n// ============================================================================\r\n\r\n/**\r\n * Sanitize HTML string, removing dangerous elements and attributes.\r\n * Uses Trusted Types when available for CSP compliance.\r\n *\r\n * @param html - The HTML string to sanitize\r\n * @param options - Sanitization options\r\n * @returns Sanitized HTML string\r\n *\r\n * @example\r\n * ```ts\r\n * const safe = sanitizeHtml('<div onclick=\"alert(1)\">Hello</div>');\r\n * // Returns: '<div>Hello</div>'\r\n * ```\r\n */\r\nexport const sanitizeHtml = (html: string, options: SanitizeOptions = {}): string => {\r\n return sanitizeHtmlCore(html, options);\r\n};\r\n\r\n/**\r\n * Create a Trusted HTML value for use with Trusted Types-enabled sites.\r\n * Falls back to regular string when Trusted Types are unavailable.\r\n *\r\n * @param html - The HTML string to wrap\r\n * @returns Trusted HTML value or sanitized string\r\n */\r\nexport const createTrustedHtml = (html: string): TrustedHTML | string => {\r\n const policy = getTrustedTypesPolicy();\r\n if (policy) {\r\n return policy.createHTML(html);\r\n }\r\n return sanitizeHtml(html);\r\n};\r\n\r\n/**\r\n * Escape HTML entities to prevent XSS.\r\n * Use this for displaying user content as text.\r\n *\r\n * @param text - The text to escape\r\n * @returns Escaped HTML string\r\n *\r\n * @example\r\n * ```ts\r\n * escapeHtml('<script>alert(1)</script>');\r\n * // Returns: '<script>alert(1)</script>'\r\n * ```\r\n */\r\nexport const escapeHtml = (text: string): string => {\r\n const escapeMap: Record<string, string> = {\r\n '&': '&',\r\n '<': '<',\r\n '>': '>',\r\n '\"': '"',\r\n \"'\": ''',\r\n '`': '`',\r\n };\r\n return text.replace(/[&<>\"'`]/g, (char) => escapeMap[char]);\r\n};\r\n\r\n/**\r\n * Strip all HTML tags and return plain text.\r\n *\r\n * @param html - The HTML string to strip\r\n * @returns Plain text content\r\n */\r\nexport const stripTags = (html: string): string => {\r\n return sanitizeHtmlCore(html, { stripAllTags: true });\r\n};\r\n\r\n// ============================================================================\r\n// CSP Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Generate a nonce for inline scripts/styles.\r\n * Use with Content-Security-Policy nonce directives.\r\n *\r\n * @param length - Nonce length (default: 16)\r\n * @returns Cryptographically random nonce string\r\n */\r\nexport const generateNonce = (length: number = 16): string => {\r\n const array = new Uint8Array(length);\r\n crypto.getRandomValues(array);\r\n return btoa(String.fromCharCode(...array))\r\n .replace(/\\+/g, '-')\r\n .replace(/\\//g, '_')\r\n .replace(/=/g, '');\r\n};\r\n\r\n/**\r\n * Check if a CSP header is present with specific directive.\r\n * Useful for feature detection and fallback strategies.\r\n *\r\n * @param directive - The CSP directive to check (e.g., 'script-src')\r\n * @returns True if the directive appears to be enforced\r\n */\r\nexport const hasCSPDirective = (directive: string): boolean => {\r\n // Check meta tag\r\n const meta = document.querySelector('meta[http-equiv=\"Content-Security-Policy\"]');\r\n if (meta) {\r\n const content = meta.getAttribute('content') ?? '';\r\n return content.includes(directive);\r\n }\r\n return false;\r\n};\r\n","/**\n * Shared helpers for element wrappers.\n */\nexport type ElementList = Element[];\n\nexport const toElementList = (input: Element | ElementList): ElementList =>\n Array.isArray(input) ? input : [input];\n\nexport const applyAll = (elements: ElementList, action: (el: Element) => void) => {\n for (const el of elements) {\n action(el);\n }\n};\n","import { sanitizeHtml } from '../security/sanitize';\r\nimport { applyAll, toElementList } from './shared';\r\n\r\n/**\r\n * Wrapper for a single DOM element.\r\n * Provides a chainable, jQuery-like API for DOM manipulation.\r\n *\r\n * This class encapsulates a DOM element and provides methods for:\r\n * - Class manipulation (addClass, removeClass, toggleClass)\r\n * - Attribute and property access (attr, prop, data)\r\n * - Content manipulation (text, html, append, prepend)\r\n * - Style manipulation (css)\r\n * - Event handling (on, off, once, trigger)\r\n * - DOM traversal (find, closest, parent, children, siblings)\r\n *\r\n * All mutating methods return `this` for method chaining.\r\n *\r\n * @example\r\n * ```ts\r\n * $('#button')\r\n * .addClass('active')\r\n * .css({ color: 'blue' })\r\n * .on('click', () => console.log('clicked'));\r\n * ```\r\n */\r\n/** Handler signature for delegated events */\r\ntype DelegatedHandler = (event: Event, target: Element) => void;\r\n\r\nexport class BQueryElement {\r\n /**\r\n * Stores delegated event handlers for cleanup via undelegate().\r\n * Key format: `${event}:${selector}`\r\n * @internal\r\n */\r\n private readonly delegatedHandlers = new Map<string, Map<DelegatedHandler, EventListener>>();\r\n\r\n /**\r\n * Creates a new BQueryElement wrapper.\r\n * @param element - The DOM element to wrap\r\n */\r\n constructor(private readonly element: Element) {}\r\n\r\n /**\r\n * Exposes the raw DOM element when direct access is needed.\r\n * Use sparingly; prefer the wrapper methods for consistency.\r\n */\r\n get raw(): Element {\r\n return this.element;\r\n }\r\n\r\n /**\r\n * Exposes the underlying DOM element.\r\n * Provided for spec compatibility and read-only access.\r\n */\r\n get node(): Element {\r\n return this.element;\r\n }\r\n\r\n /** Add one or more classes. */\r\n addClass(...classNames: string[]): this {\r\n this.element.classList.add(...classNames);\r\n return this;\r\n }\r\n\r\n /** Remove one or more classes. */\r\n removeClass(...classNames: string[]): this {\r\n this.element.classList.remove(...classNames);\r\n return this;\r\n }\r\n\r\n /** Toggle a class by name. */\r\n toggleClass(className: string, force?: boolean): this {\r\n this.element.classList.toggle(className, force);\r\n return this;\r\n }\r\n\r\n /** Get or set an attribute. */\r\n attr(name: string, value?: string): string | this {\r\n if (value === undefined) {\r\n return this.element.getAttribute(name) ?? '';\r\n }\r\n this.element.setAttribute(name, value);\r\n return this;\r\n }\r\n\r\n /** Get or set a property. */\r\n prop<T extends keyof Element>(name: T, value?: Element[T]): Element[T] | this {\r\n if (value === undefined) {\r\n return this.element[name];\r\n }\r\n this.element[name] = value;\r\n return this;\r\n }\r\n\r\n /** Read or write data attributes in camelCase. */\r\n data(name: string, value?: string): string | this {\r\n const key = name.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);\r\n if (value === undefined) {\r\n return this.element.getAttribute(`data-${key}`) ?? '';\r\n }\r\n this.element.setAttribute(`data-${key}`, value);\r\n return this;\r\n }\r\n\r\n /** Get or set text content. */\r\n text(value?: string): string | this {\r\n if (value === undefined) {\r\n return this.element.textContent ?? '';\r\n }\r\n this.element.textContent = value;\r\n return this;\r\n }\r\n\r\n /** Set HTML content using a sanitized string. */\r\n /**\r\n * Sets sanitized HTML content on the element.\r\n * Uses the security module to sanitize input and prevent XSS attacks.\r\n *\r\n * @param value - The HTML string to set (will be sanitized)\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * $('#content').html('<strong>Hello</strong>');\r\n * ```\r\n */\r\n html(value: string): this {\r\n this.element.innerHTML = sanitizeHtml(value);\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets HTML content without sanitization.\r\n * Use only when you trust the HTML source completely.\r\n *\r\n * @param value - The raw HTML string to set\r\n * @returns The instance for method chaining\r\n *\r\n * @warning This method bypasses XSS protection. Use with caution.\r\n */\r\n htmlUnsafe(value: string): this {\r\n this.element.innerHTML = value;\r\n return this;\r\n }\r\n\r\n /**\r\n * Gets or sets CSS styles on the element.\r\n *\r\n * @param property - A CSS property name or an object of property-value pairs\r\n * @param value - The value when setting a single property\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * // Single property\r\n * $('#box').css('color', 'red');\r\n *\r\n * // Multiple properties\r\n * $('#box').css({ color: 'red', 'font-size': '16px' });\r\n * ```\r\n */\r\n css(property: string | Record<string, string>, value?: string): this {\r\n if (typeof property === 'string') {\r\n if (value !== undefined) {\r\n (this.element as HTMLElement).style.setProperty(property, value);\r\n }\r\n return this;\r\n }\r\n\r\n for (const [key, val] of Object.entries(property)) {\r\n (this.element as HTMLElement).style.setProperty(key, val);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Appends HTML or elements to the end of the element.\r\n *\r\n * @param content - HTML string or element(s) to append\r\n * @returns The instance for method chaining\r\n */\r\n append(content: string | Element | Element[]): this {\r\n this.insertContent(content, 'beforeend');\r\n return this;\r\n }\r\n\r\n /**\r\n * Prepends HTML or elements to the beginning of the element.\r\n *\r\n * @param content - HTML string or element(s) to prepend\r\n * @returns The instance for method chaining\r\n */\r\n prepend(content: string | Element | Element[]): this {\r\n this.insertContent(content, 'afterbegin');\r\n return this;\r\n }\r\n\r\n /**\r\n * Inserts content before this element.\r\n *\r\n * @param content - HTML string or element(s) to insert\r\n * @returns The instance for method chaining\r\n */\r\n before(content: string | Element | Element[]): this {\r\n this.insertContent(content, 'beforebegin');\r\n return this;\r\n }\r\n\r\n /**\r\n * Inserts content after this element.\r\n *\r\n * @param content - HTML string or element(s) to insert\r\n * @returns The instance for method chaining\r\n */\r\n after(content: string | Element | Element[]): this {\r\n this.insertContent(content, 'afterend');\r\n return this;\r\n }\r\n\r\n /**\r\n * Wraps the element with the specified wrapper element or tag.\r\n *\r\n * @param wrapper - Tag name string or Element to wrap with\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * $('#content').wrap('div'); // Wraps with <div>\r\n * $('#content').wrap(document.createElement('section'));\r\n * ```\r\n */\r\n wrap(wrapper: string | Element): this {\r\n const wrapperEl = typeof wrapper === 'string' ? document.createElement(wrapper) : wrapper;\r\n this.element.parentNode?.insertBefore(wrapperEl, this.element);\r\n wrapperEl.appendChild(this.element);\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes the parent element, keeping this element in its place.\r\n * Essentially the opposite of wrap().\r\n *\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * // Before: <div><span id=\"text\">Hello</span></div>\r\n * $('#text').unwrap();\r\n * // After: <span id=\"text\">Hello</span>\r\n * ```\r\n */\r\n unwrap(): this {\r\n const parent = this.element.parentElement;\r\n if (parent && parent.parentNode) {\r\n parent.parentNode.insertBefore(this.element, parent);\r\n parent.remove();\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Replaces this element with new content.\r\n *\r\n * @param content - HTML string (sanitized) or Element to replace with\r\n * @returns A new BQueryElement wrapping the replacement element\r\n *\r\n * @example\r\n * ```ts\r\n * const newEl = $('#old').replaceWith('<div id=\"new\">Replaced</div>');\r\n * ```\r\n */\r\n replaceWith(content: string | Element): BQueryElement {\r\n let newEl: Element;\r\n if (typeof content === 'string') {\r\n const template = document.createElement('template');\r\n template.innerHTML = sanitizeHtml(content);\r\n newEl = template.content.firstElementChild ?? document.createElement('div');\r\n } else {\r\n newEl = content;\r\n }\r\n this.element.replaceWith(newEl);\r\n return new BQueryElement(newEl);\r\n }\r\n\r\n /**\r\n * Scrolls the element into view with configurable behavior.\r\n *\r\n * @param options - ScrollIntoView options or boolean for legacy behavior\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * $('#section').scrollTo(); // Smooth scroll\r\n * $('#section').scrollTo({ behavior: 'instant', block: 'start' });\r\n * ```\r\n */\r\n scrollTo(options: ScrollIntoViewOptions | boolean = { behavior: 'smooth' }): this {\r\n this.element.scrollIntoView(options);\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes the element from the DOM.\r\n *\r\n * @returns The instance for method chaining (though element is now detached)\r\n */\r\n remove(): this {\r\n this.element.remove();\r\n return this;\r\n }\r\n\r\n /**\r\n * Clears all child nodes from the element.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n empty(): this {\r\n this.element.innerHTML = '';\r\n return this;\r\n }\r\n\r\n /**\r\n * Clones the element, optionally with all descendants.\r\n *\r\n * @param deep - If true, clone all descendants (default: true)\r\n * @returns A new BQueryElement wrapping the cloned element\r\n */\r\n clone(deep: boolean = true): BQueryElement {\r\n return new BQueryElement(this.element.cloneNode(deep) as Element);\r\n }\r\n\r\n /**\r\n * Finds all descendant elements matching the selector.\r\n *\r\n * @param selector - CSS selector to match\r\n * @returns Array of matching elements\r\n */\r\n find(selector: string): Element[] {\r\n return Array.from(this.element.querySelectorAll(selector));\r\n }\r\n\r\n /**\r\n * Finds the first descendant element matching the selector.\r\n *\r\n * @param selector - CSS selector to match\r\n * @returns The first matching element or null\r\n */\r\n findOne(selector: string): Element | null {\r\n return this.element.querySelector(selector);\r\n }\r\n\r\n /**\r\n * Finds the closest ancestor matching the selector.\r\n *\r\n * @param selector - CSS selector to match\r\n * @returns The matching ancestor or null\r\n */\r\n closest(selector: string): Element | null {\r\n return this.element.closest(selector);\r\n }\r\n\r\n /**\r\n * Gets the parent element.\r\n *\r\n * @returns The parent element or null\r\n */\r\n parent(): Element | null {\r\n return this.element.parentElement;\r\n }\r\n\r\n /**\r\n * Gets all child elements.\r\n *\r\n * @returns Array of child elements\r\n */\r\n children(): Element[] {\r\n return Array.from(this.element.children);\r\n }\r\n\r\n /**\r\n * Gets all sibling elements.\r\n *\r\n * @returns Array of sibling elements (excluding this element)\r\n */\r\n siblings(): Element[] {\r\n const parent = this.element.parentElement;\r\n if (!parent) return [];\r\n return Array.from(parent.children).filter((child) => child !== this.element);\r\n }\r\n\r\n /**\r\n * Gets the next sibling element.\r\n *\r\n * @returns The next sibling element or null\r\n */\r\n next(): Element | null {\r\n return this.element.nextElementSibling;\r\n }\r\n\r\n /**\r\n * Gets the previous sibling element.\r\n *\r\n * @returns The previous sibling element or null\r\n */\r\n prev(): Element | null {\r\n return this.element.previousElementSibling;\r\n }\r\n\r\n /**\r\n * Adds an event listener.\r\n *\r\n * @param event - Event type to listen for\r\n * @param handler - Event handler function\r\n * @returns The instance for method chaining\r\n */\r\n on(event: string, handler: EventListenerOrEventListenerObject): this {\r\n this.element.addEventListener(event, handler);\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a one-time event listener that removes itself after firing.\r\n *\r\n * @param event - Event type to listen for\r\n * @param handler - Event handler function\r\n * @returns The instance for method chaining\r\n */\r\n once(event: string, handler: EventListener): this {\r\n this.element.addEventListener(event, handler, { once: true });\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes an event listener.\r\n *\r\n * @param event - Event type\r\n * @param handler - The handler to remove\r\n * @returns The instance for method chaining\r\n */\r\n off(event: string, handler: EventListenerOrEventListenerObject): this {\r\n this.element.removeEventListener(event, handler);\r\n return this;\r\n }\r\n\r\n /**\r\n * Triggers a custom event on the element.\r\n *\r\n * @param event - Event type to trigger\r\n * @param detail - Optional detail data to include with the event\r\n * @returns The instance for method chaining\r\n */\r\n trigger(event: string, detail?: unknown): this {\r\n this.element.dispatchEvent(new CustomEvent(event, { detail, bubbles: true, cancelable: true }));\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a delegated event listener that only triggers for matching descendants.\r\n * More efficient than adding listeners to many elements individually.\r\n *\r\n * Use `undelegate()` to remove the listener later.\r\n *\r\n * @param event - Event type to listen for\r\n * @param selector - CSS selector to match against event targets\r\n * @param handler - Event handler function, receives the matched element as context\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * // Instead of adding listeners to each button:\r\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\r\n * $('#list').delegate('click', '.item', handler);\r\n *\r\n * // Later, remove the delegated listener:\r\n * $('#list').undelegate('click', '.item', handler);\r\n * ```\r\n */\r\n delegate(\r\n event: string,\r\n selector: string,\r\n handler: (event: Event, target: Element) => void\r\n ): this {\r\n const key = `${event}:${selector}`;\r\n const wrapper: EventListener = (e: Event) => {\r\n const target = (e.target as Element).closest(selector);\r\n if (target && this.element.contains(target)) {\r\n handler(e, target);\r\n }\r\n };\r\n\r\n // Store the wrapper so it can be removed later\r\n if (!this.delegatedHandlers.has(key)) {\r\n this.delegatedHandlers.set(key, new Map());\r\n }\r\n this.delegatedHandlers.get(key)!.set(handler, wrapper);\r\n\r\n this.element.addEventListener(event, wrapper);\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes a delegated event listener previously added with `delegate()`.\r\n *\r\n * @param event - Event type that was registered\r\n * @param selector - CSS selector that was used\r\n * @param handler - The original handler function passed to delegate()\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\r\n * $('#list').delegate('click', '.item', handler);\r\n *\r\n * // Remove the delegated listener:\r\n * $('#list').undelegate('click', '.item', handler);\r\n * ```\r\n */\r\n undelegate(\r\n event: string,\r\n selector: string,\r\n handler: (event: Event, target: Element) => void\r\n ): this {\r\n const key = `${event}:${selector}`;\r\n const handlers = this.delegatedHandlers.get(key);\r\n\r\n if (handlers) {\r\n const wrapper = handlers.get(handler);\r\n if (wrapper) {\r\n this.element.removeEventListener(event, wrapper);\r\n handlers.delete(handler);\r\n\r\n // Clean up empty maps\r\n if (handlers.size === 0) {\r\n this.delegatedHandlers.delete(key);\r\n }\r\n }\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Checks if the element matches a CSS selector.\r\n *\r\n * @param selector - CSS selector to match against\r\n * @returns True if the element matches the selector\r\n */\r\n matches(selector: string): boolean {\r\n return this.element.matches(selector);\r\n }\r\n\r\n /**\r\n * Checks if the element has a specific class.\r\n *\r\n * @param className - Class name to check\r\n * @returns True if the element has the class\r\n */\r\n hasClass(className: string): boolean {\r\n return this.element.classList.contains(className);\r\n }\r\n\r\n /**\r\n * Shows the element by removing the hidden attribute and setting display.\r\n *\r\n * @param display - Optional display value (default: '')\r\n * @returns The instance for method chaining\r\n */\r\n show(display: string = ''): this {\r\n this.element.removeAttribute('hidden');\r\n (this.element as HTMLElement).style.display = display;\r\n return this;\r\n }\r\n\r\n /**\r\n * Hides the element by setting display to 'none'.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n hide(): this {\r\n (this.element as HTMLElement).style.display = 'none';\r\n return this;\r\n }\r\n\r\n /**\r\n * Toggles the visibility of the element.\r\n *\r\n * @param force - Optional force show (true) or hide (false)\r\n * @returns The instance for method chaining\r\n */\r\n toggle(force?: boolean): this {\r\n const isHidden = (this.element as HTMLElement).style.display === 'none';\r\n const shouldShow = force ?? isHidden;\r\n return shouldShow ? this.show() : this.hide();\r\n }\r\n\r\n /**\r\n * Focuses the element.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n focus(): this {\r\n (this.element as HTMLElement).focus();\r\n return this;\r\n }\r\n\r\n /**\r\n * Blurs (unfocuses) the element.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n blur(): this {\r\n (this.element as HTMLElement).blur();\r\n return this;\r\n }\r\n\r\n /**\r\n * Gets or sets the value of form elements.\r\n *\r\n * @param newValue - Optional value to set\r\n * @returns The current value when getting, or the instance when setting\r\n */\r\n val(newValue?: string): string | this {\r\n const input = this.element as HTMLInputElement;\r\n if (newValue === undefined) {\r\n return input.value ?? '';\r\n }\r\n input.value = newValue;\r\n return this;\r\n }\r\n\r\n /**\r\n * Serializes form data to a plain object.\r\n * Only works on form elements; returns empty object for non-forms.\r\n *\r\n * @returns Object with form field names as keys and values\r\n *\r\n * @example\r\n * ```ts\r\n * // For a form with <input name=\"email\" value=\"test@example.com\">\r\n * const data = $('#myForm').serialize();\r\n * // { email: 'test@example.com' }\r\n * ```\r\n */\r\n serialize(): Record<string, string | string[]> {\r\n const form = this.element as HTMLFormElement;\r\n if (form.tagName.toLowerCase() !== 'form') {\r\n return {};\r\n }\r\n\r\n const result: Record<string, string | string[]> = {};\r\n const formData = new FormData(form);\r\n\r\n for (const [key, value] of formData.entries()) {\r\n if (typeof value !== 'string') continue; // Skip File objects\r\n\r\n if (key in result) {\r\n // Handle multiple values (e.g., checkboxes)\r\n const existing = result[key];\r\n if (Array.isArray(existing)) {\r\n existing.push(value);\r\n } else {\r\n result[key] = [existing, value];\r\n }\r\n } else {\r\n result[key] = value;\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Serializes form data to a URL-encoded query string.\r\n *\r\n * @returns URL-encoded string suitable for form submission\r\n *\r\n * @example\r\n * ```ts\r\n * const queryString = $('#myForm').serializeString();\r\n * // 'email=test%40example.com&name=John'\r\n * ```\r\n */\r\n serializeString(): string {\r\n const form = this.element as HTMLFormElement;\r\n if (form.tagName.toLowerCase() !== 'form') {\r\n return '';\r\n }\r\n\r\n const formData = new FormData(form);\r\n const params = new URLSearchParams();\r\n\r\n for (const [key, value] of formData.entries()) {\r\n if (typeof value === 'string') {\r\n params.append(key, value);\r\n }\r\n }\r\n\r\n return params.toString();\r\n }\r\n\r\n /**\r\n * Gets the bounding client rectangle of the element.\r\n *\r\n * @returns The element's bounding rectangle\r\n */\r\n rect(): DOMRect {\r\n return this.element.getBoundingClientRect();\r\n }\r\n\r\n /**\r\n * Gets the offset dimensions (width, height, top, left).\r\n *\r\n * @returns Object with offset dimensions\r\n */\r\n offset(): { width: number; height: number; top: number; left: number } {\r\n const el = this.element as HTMLElement;\r\n return {\r\n width: el.offsetWidth,\r\n height: el.offsetHeight,\r\n top: el.offsetTop,\r\n left: el.offsetLeft,\r\n };\r\n }\r\n\r\n /**\r\n * Internal method to insert content at a specified position.\r\n * @internal\r\n */\r\n private insertContent(content: string | Element | Element[], position: InsertPosition) {\r\n if (typeof content === 'string') {\r\n this.element.insertAdjacentHTML(position, sanitizeHtml(content));\r\n return;\r\n }\r\n\r\n const elements = toElementList(content);\r\n applyAll(elements, (el) => {\r\n this.element.insertAdjacentElement(position, el);\r\n });\r\n }\r\n}\r\n","import { sanitizeHtml } from '../security/sanitize';\r\nimport { BQueryElement } from './element';\r\nimport { applyAll } from './shared';\r\n\r\n/** Handler signature for delegated events */\r\ntype DelegatedHandler = (event: Event, target: Element) => void;\r\n\r\n/**\r\n * Wrapper for multiple DOM elements.\r\n * Provides batch operations on a collection of elements with chainable API.\r\n *\r\n * This class enables jQuery-like operations across multiple elements:\r\n * - All mutating methods apply to every element in the collection\r\n * - Getter methods return data from the first element\r\n * - Supports iteration via forEach, map, filter, and reduce\r\n *\r\n * @example\r\n * ```ts\r\n * $$('.items')\r\n * .addClass('highlight')\r\n * .css({ opacity: '0.8' })\r\n * .on('click', () => console.log('clicked'));\r\n * ```\r\n */\r\nexport class BQueryCollection {\r\n /**\r\n * Stores delegated event handlers for cleanup via undelegate().\r\n * Outer map: element -> (key -> (handler -> wrapper))\r\n * Key format: `${event}:${selector}`\r\n * @internal\r\n */\r\n private readonly delegatedHandlers = new WeakMap<\r\n Element,\r\n Map<string, Map<DelegatedHandler, EventListener>>\r\n >();\r\n\r\n /**\r\n * Creates a new collection wrapper.\r\n * @param elements - Array of DOM elements to wrap\r\n */\r\n constructor(public readonly elements: Element[]) {}\r\n\r\n /**\r\n * Gets the number of elements in the collection.\r\n */\r\n get length(): number {\r\n return this.elements.length;\r\n }\r\n\r\n /**\r\n * Gets the first element in the collection, if any.\r\n * @internal\r\n */\r\n private first(): Element | undefined {\r\n return this.elements[0];\r\n }\r\n\r\n /**\r\n * Gets a single element as a BQueryElement wrapper.\r\n *\r\n * @param index - Zero-based index of the element\r\n * @returns BQueryElement wrapper or undefined if out of range\r\n */\r\n eq(index: number): BQueryElement | undefined {\r\n const el = this.elements[index];\r\n return el ? new BQueryElement(el) : undefined;\r\n }\r\n\r\n /**\r\n * Gets the first element as a BQueryElement wrapper.\r\n *\r\n * @returns BQueryElement wrapper or undefined if empty\r\n */\r\n firstEl(): BQueryElement | undefined {\r\n return this.eq(0);\r\n }\r\n\r\n /**\r\n * Gets the last element as a BQueryElement wrapper.\r\n *\r\n * @returns BQueryElement wrapper or undefined if empty\r\n */\r\n lastEl(): BQueryElement | undefined {\r\n return this.eq(this.elements.length - 1);\r\n }\r\n\r\n /**\r\n * Iterates over each element in the collection.\r\n *\r\n * @param callback - Function to call for each wrapped element\r\n * @returns The instance for method chaining\r\n */\r\n each(callback: (element: BQueryElement, index: number) => void): this {\r\n this.elements.forEach((element, index) => {\r\n callback(new BQueryElement(element), index);\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Maps each element to a new value.\r\n *\r\n * @param callback - Function to transform each element\r\n * @returns Array of transformed values\r\n */\r\n map<T>(callback: (element: Element, index: number) => T): T[] {\r\n return this.elements.map(callback);\r\n }\r\n\r\n /**\r\n * Filters elements based on a predicate.\r\n *\r\n * @param predicate - Function to test each element\r\n * @returns New BQueryCollection with matching elements\r\n */\r\n filter(predicate: (element: Element, index: number) => boolean): BQueryCollection {\r\n return new BQueryCollection(this.elements.filter(predicate));\r\n }\r\n\r\n /**\r\n * Reduces the collection to a single value.\r\n *\r\n * @param callback - Reducer function\r\n * @param initialValue - Initial accumulator value\r\n * @returns Accumulated result\r\n */\r\n reduce<T>(callback: (accumulator: T, element: Element, index: number) => T, initialValue: T): T {\r\n return this.elements.reduce(callback, initialValue);\r\n }\r\n\r\n /**\r\n * Converts the collection to an array of BQueryElement wrappers.\r\n *\r\n * @returns Array of BQueryElement instances\r\n */\r\n toArray(): BQueryElement[] {\r\n return this.elements.map((el) => new BQueryElement(el));\r\n }\r\n\r\n /** Add one or more classes to all elements. */\r\n addClass(...classNames: string[]): this {\r\n applyAll(this.elements, (el) => el.classList.add(...classNames));\r\n return this;\r\n }\r\n\r\n /** Remove one or more classes from all elements. */\r\n removeClass(...classNames: string[]): this {\r\n applyAll(this.elements, (el) => el.classList.remove(...classNames));\r\n return this;\r\n }\r\n\r\n /** Toggle a class on all elements. */\r\n toggleClass(className: string, force?: boolean): this {\r\n applyAll(this.elements, (el) => el.classList.toggle(className, force));\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets an attribute on all elements or gets from first.\r\n *\r\n * @param name - Attribute name\r\n * @param value - Value to set (optional)\r\n * @returns Attribute value when getting, instance when setting\r\n */\r\n attr(name: string, value?: string): string | this {\r\n if (value === undefined) {\r\n return this.first()?.getAttribute(name) ?? '';\r\n }\r\n applyAll(this.elements, (el) => el.setAttribute(name, value));\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes an attribute from all elements.\r\n *\r\n * @param name - Attribute name to remove\r\n * @returns The instance for method chaining\r\n */\r\n removeAttr(name: string): this {\r\n applyAll(this.elements, (el) => el.removeAttribute(name));\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets text content on all elements or gets from first.\r\n *\r\n * @param value - Text to set (optional)\r\n * @returns Text content when getting, instance when setting\r\n */\r\n text(value?: string): string | this {\r\n if (value === undefined) {\r\n return this.first()?.textContent ?? '';\r\n }\r\n applyAll(this.elements, (el) => {\r\n el.textContent = value;\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets sanitized HTML on all elements or gets from first.\r\n *\r\n * @param value - HTML to set (optional, will be sanitized)\r\n * @returns HTML content when getting, instance when setting\r\n */\r\n html(value?: string): string | this {\r\n if (value === undefined) {\r\n return this.first()?.innerHTML ?? '';\r\n }\r\n const sanitized = sanitizeHtml(value);\r\n applyAll(this.elements, (el) => {\r\n el.innerHTML = sanitized;\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets HTML on all elements without sanitization.\r\n *\r\n * @param value - Raw HTML to set\r\n * @returns The instance for method chaining\r\n * @warning Bypasses XSS protection\r\n */\r\n htmlUnsafe(value: string): this {\r\n applyAll(this.elements, (el) => {\r\n el.innerHTML = value;\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Applies CSS styles to all elements.\r\n *\r\n * @param property - Property name or object of properties\r\n * @param value - Value when setting single property\r\n * @returns The instance for method chaining\r\n */\r\n css(property: string | Record<string, string>, value?: string): this {\r\n if (typeof property === 'string') {\r\n if (value !== undefined) {\r\n applyAll(this.elements, (el) => {\r\n (el as HTMLElement).style.setProperty(property, value);\r\n });\r\n }\r\n return this;\r\n }\r\n\r\n applyAll(this.elements, (el) => {\r\n for (const [key, val] of Object.entries(property)) {\r\n (el as HTMLElement).style.setProperty(key, val);\r\n }\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Shows all elements.\r\n *\r\n * @param display - Optional display value (default: '')\r\n * @returns The instance for method chaining\r\n */\r\n show(display: string = ''): this {\r\n applyAll(this.elements, (el) => {\r\n el.removeAttribute('hidden');\r\n (el as HTMLElement).style.display = display;\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Hides all elements.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n hide(): this {\r\n applyAll(this.elements, (el) => {\r\n (el as HTMLElement).style.display = 'none';\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds an event listener to all elements.\r\n *\r\n * @param event - Event type\r\n * @param handler - Event handler\r\n * @returns The instance for method chaining\r\n */\r\n on(event: string, handler: EventListenerOrEventListenerObject): this {\r\n applyAll(this.elements, (el) => el.addEventListener(event, handler));\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a one-time event listener to all elements.\r\n *\r\n * @param event - Event type\r\n * @param handler - Event handler\r\n * @returns The instance for method chaining\r\n */\r\n once(event: string, handler: EventListener): this {\r\n applyAll(this.elements, (el) => el.addEventListener(event, handler, { once: true }));\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes an event listener from all elements.\r\n *\r\n * @param event - Event type\r\n * @param handler - The handler to remove\r\n * @returns The instance for method chaining\r\n */\r\n off(event: string, handler: EventListenerOrEventListenerObject): this {\r\n applyAll(this.elements, (el) => el.removeEventListener(event, handler));\r\n return this;\r\n }\r\n\r\n /**\r\n * Triggers a custom event on all elements.\r\n *\r\n * @param event - Event type\r\n * @param detail - Optional event detail\r\n * @returns The instance for method chaining\r\n */\r\n trigger(event: string, detail?: unknown): this {\r\n applyAll(this.elements, (el) => {\r\n el.dispatchEvent(new CustomEvent(event, { detail, bubbles: true, cancelable: true }));\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a delegated event listener to all elements.\r\n * Events are delegated to matching descendants.\r\n *\r\n * Use `undelegate()` to remove the listener later.\r\n *\r\n * @param event - Event type to listen for\r\n * @param selector - CSS selector to match against event targets\r\n * @param handler - Event handler function\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\r\n * $$('.container').delegate('click', '.item', handler);\r\n *\r\n * // Later, remove the delegated listener:\r\n * $$('.container').undelegate('click', '.item', handler);\r\n * ```\r\n */\r\n delegate(\r\n event: string,\r\n selector: string,\r\n handler: (event: Event, target: Element) => void\r\n ): this {\r\n const key = `${event}:${selector}`;\r\n\r\n applyAll(this.elements, (el) => {\r\n const wrapper: EventListener = (e: Event) => {\r\n const target = (e.target as Element).closest(selector);\r\n if (target && el.contains(target)) {\r\n handler(e, target);\r\n }\r\n };\r\n\r\n // Get or create the handler maps for this element\r\n if (!this.delegatedHandlers.has(el)) {\r\n this.delegatedHandlers.set(el, new Map());\r\n }\r\n const elementHandlers = this.delegatedHandlers.get(el)!;\r\n\r\n if (!elementHandlers.has(key)) {\r\n elementHandlers.set(key, new Map());\r\n }\r\n elementHandlers.get(key)!.set(handler, wrapper);\r\n\r\n el.addEventListener(event, wrapper);\r\n });\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes a delegated event listener previously added with `delegate()`.\r\n *\r\n * @param event - Event type that was registered\r\n * @param selector - CSS selector that was used\r\n * @param handler - The original handler function passed to delegate()\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\r\n * $$('.container').delegate('click', '.item', handler);\r\n *\r\n * // Remove the delegated listener:\r\n * $$('.container').undelegate('click', '.item', handler);\r\n * ```\r\n */\r\n undelegate(\r\n event: string,\r\n selector: string,\r\n handler: (event: Event, target: Element) => void\r\n ): this {\r\n const key = `${event}:${selector}`;\r\n\r\n applyAll(this.elements, (el) => {\r\n const elementHandlers = this.delegatedHandlers.get(el);\r\n if (!elementHandlers) return;\r\n\r\n const handlers = elementHandlers.get(key);\r\n if (!handlers) return;\r\n\r\n const wrapper = handlers.get(handler);\r\n if (wrapper) {\r\n el.removeEventListener(event, wrapper);\r\n handlers.delete(handler);\r\n\r\n // Clean up empty maps\r\n if (handlers.size === 0) {\r\n elementHandlers.delete(key);\r\n }\r\n if (elementHandlers.size === 0) {\r\n this.delegatedHandlers.delete(el);\r\n }\r\n }\r\n });\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes all elements from the DOM.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n remove(): this {\r\n applyAll(this.elements, (el) => el.remove());\r\n return this;\r\n }\r\n\r\n /**\r\n * Clears all child nodes from all elements.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n empty(): this {\r\n applyAll(this.elements, (el) => {\r\n el.innerHTML = '';\r\n });\r\n return this;\r\n }\r\n}\r\n","import { BQueryCollection } from './collection';\nimport { BQueryElement } from './element';\n\n/**\n * Select a single element. Returns a wrapper for chainable operations.\n */\nexport const $ = (selector: string | Element): BQueryElement => {\n if (typeof selector !== 'string') {\n return new BQueryElement(selector);\n }\n const element = document.querySelector(selector);\n if (!element) {\n throw new Error(`bQuery: element not found for selector \"${selector}\"`);\n }\n return new BQueryElement(element);\n};\n\n/**\n * Select multiple elements. Returns a collection wrapper.\n */\nexport const $$ = (selector: string | Element[] | NodeListOf<Element>): BQueryCollection => {\n if (Array.isArray(selector)) {\n return new BQueryCollection(selector);\n }\n if (selector instanceof NodeList) {\n return new BQueryCollection(Array.from(selector));\n }\n return new BQueryCollection(Array.from(document.querySelectorAll(selector)));\n};\n","/**\r\n * Utility helpers used across the framework.\r\n * These are intentionally small and framework-agnostic to keep the core tiny.\r\n *\r\n * @module bquery/core/utils\r\n */\r\n\r\n/**\r\n * Utility object containing common helper functions.\r\n * All utilities are designed to be tree-shakeable and have zero dependencies.\r\n */\r\nexport const utils = {\r\n /**\r\n * Creates a deep clone using structuredClone if available, otherwise fallback to JSON.\r\n *\r\n * @template T - The type of value being cloned\r\n * @param value - The value to clone\r\n * @returns A deep copy of the value\r\n *\r\n * @example\r\n * ```ts\r\n * const original = { nested: { value: 1 } };\r\n * const copy = utils.clone(original);\r\n * copy.nested.value = 2;\r\n * console.log(original.nested.value); // 1\r\n * ```\r\n */\r\n clone<T>(value: T): T {\r\n if (typeof structuredClone === 'function') {\r\n return structuredClone(value);\r\n }\r\n return JSON.parse(JSON.stringify(value)) as T;\r\n },\r\n\r\n /**\r\n * Deep-merges plain objects into a new object.\r\n * Later sources override earlier ones for primitive values.\r\n * Objects are recursively merged.\r\n *\r\n * @template T - The type of the merged object\r\n * @param sources - Objects to merge\r\n * @returns A new object with all sources merged\r\n *\r\n * @example\r\n * ```ts\r\n * const result = utils.merge(\r\n * { a: 1, nested: { x: 1 } },\r\n * { b: 2, nested: { y: 2 } }\r\n * );\r\n * // Result: { a: 1, b: 2, nested: { x: 1, y: 2 } }\r\n * ```\r\n *\r\n * @security This method is protected against prototype pollution attacks.\r\n * Keys like `__proto__`, `constructor`, and `prototype` are ignored.\r\n */\r\n merge<T extends Record<string, unknown>>(...sources: T[]): T {\r\n const result: Record<string, unknown> = {};\r\n for (const source of sources) {\r\n for (const [key, value] of Object.entries(source)) {\r\n // Prevent prototype pollution attacks\r\n if (utils.isPrototypePollutionKey(key)) continue;\r\n\r\n if (utils.isPlainObject(value) && utils.isPlainObject(result[key])) {\r\n result[key] = utils.merge(\r\n result[key] as Record<string, unknown>,\r\n value as Record<string, unknown>\r\n );\r\n } else {\r\n result[key] = value;\r\n }\r\n }\r\n }\r\n return result as T;\r\n },\r\n\r\n /**\r\n * Checks if a key could cause prototype pollution.\r\n * These keys are dangerous when used in object merging operations.\r\n *\r\n * @param key - The key to check\r\n * @returns True if the key is a prototype pollution vector\r\n *\r\n * @internal\r\n */\r\n isPrototypePollutionKey(key: string): boolean {\r\n return key === '__proto__' || key === 'constructor' || key === 'prototype';\r\n },\r\n\r\n /**\r\n * Creates a debounced function that delays execution until after\r\n * the specified delay has elapsed since the last call.\r\n *\r\n * @template TArgs - The argument types of the function\r\n * @param fn - The function to debounce\r\n * @param delayMs - Delay in milliseconds\r\n * @returns A debounced version of the function\r\n *\r\n * @example\r\n * ```ts\r\n * const search = utils.debounce((query: string) => {\r\n * console.log('Searching:', query);\r\n * }, 300);\r\n *\r\n * search('h');\r\n * search('he');\r\n * search('hello'); // Only this call executes after 300ms\r\n * ```\r\n */\r\n debounce<TArgs extends unknown[]>(\r\n fn: (...args: TArgs) => void,\r\n delayMs: number\r\n ): (...args: TArgs) => void {\r\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\r\n return (...args: TArgs) => {\r\n if (timeoutId) {\r\n clearTimeout(timeoutId);\r\n }\r\n timeoutId = setTimeout(() => fn(...args), delayMs);\r\n };\r\n },\r\n\r\n /**\r\n * Creates a throttled function that runs at most once per interval.\r\n *\r\n * @template TArgs - The argument types of the function\r\n * @param fn - The function to throttle\r\n * @param intervalMs - Minimum interval between calls in milliseconds\r\n * @returns A throttled version of the function\r\n *\r\n * @example\r\n * ```ts\r\n * const handleScroll = utils.throttle(() => {\r\n * console.log('Scroll position:', window.scrollY);\r\n * }, 100);\r\n *\r\n * window.addEventListener('scroll', handleScroll);\r\n * ```\r\n */\r\n throttle<TArgs extends unknown[]>(\r\n fn: (...args: TArgs) => void,\r\n intervalMs: number\r\n ): (...args: TArgs) => void {\r\n let lastRun = 0;\r\n return (...args: TArgs) => {\r\n const now = Date.now();\r\n if (now - lastRun >= intervalMs) {\r\n lastRun = now;\r\n fn(...args);\r\n }\r\n };\r\n },\r\n\r\n /**\r\n * Creates a stable unique ID for DOM usage.\r\n *\r\n * @param prefix - Optional prefix for the ID (default: 'bQuery')\r\n * @returns A unique identifier string\r\n *\r\n * @example\r\n * ```ts\r\n * const id = utils.uid('modal'); // 'modal_x7k2m9p'\r\n * ```\r\n */\r\n uid(prefix = 'bQuery'): string {\r\n return `${prefix}_${Math.random().toString(36).slice(2, 9)}`;\r\n },\r\n\r\n /**\r\n * Checks if a value is a DOM Element.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is an Element\r\n */\r\n isElement(value: unknown): value is Element {\r\n return value instanceof Element;\r\n },\r\n\r\n /**\r\n * Checks if a value is a BQueryCollection-like object.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value has an elements array property\r\n */\r\n isCollection(value: unknown): value is { elements: Element[] } {\r\n return Boolean(value && typeof value === 'object' && 'elements' in (value as object));\r\n },\r\n\r\n /**\r\n * Checks for emptiness across common value types.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is empty (null, undefined, empty string, empty array, or empty object)\r\n *\r\n * @example\r\n * ```ts\r\n * utils.isEmpty(''); // true\r\n * utils.isEmpty([]); // true\r\n * utils.isEmpty({}); // true\r\n * utils.isEmpty(null); // true\r\n * utils.isEmpty('hello'); // false\r\n * utils.isEmpty([1, 2]); // false\r\n * ```\r\n */\r\n isEmpty(value: unknown): boolean {\r\n if (value == null) return true;\r\n if (typeof value === 'string') return value.trim().length === 0;\r\n if (Array.isArray(value)) return value.length === 0;\r\n if (typeof value === 'object') return Object.keys(value as object).length === 0;\r\n return false;\r\n },\r\n\r\n /**\r\n * Checks if a value is a plain object (not null, array, or class instance).\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a plain object\r\n */\r\n isPlainObject(value: unknown): value is Record<string, unknown> {\r\n return Object.prototype.toString.call(value) === '[object Object]';\r\n },\r\n\r\n /**\r\n * Checks if a value is a function.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a function\r\n */\r\n isFunction(value: unknown): value is (...args: unknown[]) => unknown {\r\n return typeof value === 'function';\r\n },\r\n\r\n /**\r\n * Checks if a value is a string.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a string\r\n */\r\n isString(value: unknown): value is string {\r\n return typeof value === 'string';\r\n },\r\n\r\n /**\r\n * Checks if a value is a number (excluding NaN).\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a valid number\r\n */\r\n isNumber(value: unknown): value is number {\r\n return typeof value === 'number' && !Number.isNaN(value);\r\n },\r\n\r\n /**\r\n * Checks if a value is a boolean.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a boolean\r\n */\r\n isBoolean(value: unknown): value is boolean {\r\n return typeof value === 'boolean';\r\n },\r\n\r\n /**\r\n * Checks if a value is an array.\r\n *\r\n * @template T - The type of array elements\r\n * @param value - The value to check\r\n * @returns True if the value is an array\r\n */\r\n isArray<T = unknown>(value: unknown): value is T[] {\r\n return Array.isArray(value);\r\n },\r\n\r\n /**\r\n * Safely parses a JSON string, returning a default value on error.\r\n *\r\n * @template T - The expected type of the parsed value\r\n * @param json - The JSON string to parse\r\n * @param fallback - The default value if parsing fails\r\n * @returns The parsed value or the fallback\r\n *\r\n * @example\r\n * ```ts\r\n * utils.parseJson('{\"name\":\"bQuery\"}', {}); // { name: 'bQuery' }\r\n * utils.parseJson('invalid', {}); // {}\r\n * ```\r\n */\r\n parseJson<T>(json: string, fallback: T): T {\r\n try {\r\n return JSON.parse(json) as T;\r\n } catch {\r\n return fallback;\r\n }\r\n },\r\n\r\n /**\r\n * Picks specified keys from an object.\r\n *\r\n * @template T - The object type\r\n * @template K - The key type\r\n * @param obj - The source object\r\n * @param keys - Keys to pick\r\n * @returns A new object with only the specified keys\r\n *\r\n * @example\r\n * ```ts\r\n * const user = { name: 'John', age: 30, email: 'john@example.com' };\r\n * utils.pick(user, ['name', 'email']); // { name: 'John', email: 'john@example.com' }\r\n * ```\r\n */\r\n pick<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {\r\n const result = {} as Pick<T, K>;\r\n for (const key of keys) {\r\n if (key in obj) {\r\n result[key] = obj[key];\r\n }\r\n }\r\n return result;\r\n },\r\n\r\n /**\r\n * Omits specified keys from an object.\r\n *\r\n * @template T - The object type\r\n * @template K - The key type\r\n * @param obj - The source object\r\n * @param keys - Keys to omit\r\n * @returns A new object without the specified keys\r\n *\r\n * @example\r\n * ```ts\r\n * const user = { name: 'John', age: 30, password: 'secret' };\r\n * utils.omit(user, ['password']); // { name: 'John', age: 30 }\r\n * ```\r\n */\r\n omit<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {\r\n const result = { ...obj };\r\n for (const key of keys) {\r\n delete result[key];\r\n }\r\n return result as Omit<T, K>;\r\n },\r\n\r\n /**\r\n * Delays execution for a specified number of milliseconds.\r\n *\r\n * @param ms - Milliseconds to delay\r\n * @returns A promise that resolves after the delay\r\n *\r\n * @example\r\n * ```ts\r\n * await utils.sleep(1000); // Wait 1 second\r\n * console.log('Done!');\r\n * ```\r\n */\r\n sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n },\r\n\r\n /**\r\n * Generates a random integer between min and max (inclusive).\r\n *\r\n * @param min - Minimum value\r\n * @param max - Maximum value\r\n * @returns A random integer in the range [min, max]\r\n *\r\n * @example\r\n * ```ts\r\n * const roll = utils.randomInt(1, 6); // Random dice roll\r\n * ```\r\n */\r\n randomInt(min: number, max: number): number {\r\n return Math.floor(Math.random() * (max - min + 1)) + min;\r\n },\r\n\r\n /**\r\n * Clamps a number between a minimum and maximum value.\r\n *\r\n * @param value - The value to clamp\r\n * @param min - Minimum value\r\n * @param max - Maximum value\r\n * @returns The clamped value\r\n *\r\n * @example\r\n * ```ts\r\n * utils.clamp(150, 0, 100); // 100\r\n * utils.clamp(-10, 0, 100); // 0\r\n * utils.clamp(50, 0, 100); // 50\r\n * ```\r\n */\r\n clamp(value: number, min: number, max: number): number {\r\n return Math.min(Math.max(value, min), max);\r\n },\r\n\r\n /**\r\n * Capitalizes the first letter of a string.\r\n *\r\n * @param str - The string to capitalize\r\n * @returns The capitalized string\r\n *\r\n * @example\r\n * ```ts\r\n * utils.capitalize('hello'); // 'Hello'\r\n * ```\r\n */\r\n capitalize(str: string): string {\r\n if (!str) return str;\r\n return str.charAt(0).toUpperCase() + str.slice(1);\r\n },\r\n\r\n /**\r\n * Converts a string to kebab-case.\r\n *\r\n * @param str - The string to convert\r\n * @returns The kebab-cased string\r\n *\r\n * @example\r\n * ```ts\r\n * utils.toKebabCase('myVariableName'); // 'my-variable-name'\r\n * ```\r\n */\r\n toKebabCase(str: string): string {\r\n return str\r\n .replace(/([a-z])([A-Z])/g, '$1-$2')\r\n .replace(/[\\s_]+/g, '-')\r\n .toLowerCase();\r\n },\r\n\r\n /**\r\n * Converts a string to camelCase.\r\n *\r\n * @param str - The string to convert\r\n * @returns The camelCased string\r\n *\r\n * @example\r\n * ```ts\r\n * utils.toCamelCase('my-variable-name'); // 'myVariableName'\r\n * ```\r\n */\r\n toCamelCase(str: string): string {\r\n return str\r\n .replace(/[-_\\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))\r\n .replace(/^[A-Z]/, (char) => char.toLowerCase());\r\n },\r\n};\r\n","/**\r\n * Reactive primitives inspired by fine-grained reactivity.\r\n *\r\n * This module provides a minimal but powerful reactive system:\r\n * - Signal: A reactive value that notifies subscribers when changed\r\n * - Computed: A derived value that automatically updates when dependencies change\r\n * - Effect: A side effect that re-runs when its dependencies change\r\n * - Batch: Group multiple updates to prevent intermediate re-renders\r\n *\r\n * @module bquery/reactive\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n * const doubled = computed(() => count.value * 2);\r\n *\r\n * effect(() => {\r\n * console.log(`Count: ${count.value}, Doubled: ${doubled.value}`);\r\n * });\r\n *\r\n * batch(() => {\r\n * count.value = 1;\r\n * count.value = 2;\r\n * });\r\n * // Logs: \"Count: 2, Doubled: 4\" (only once due to batching)\r\n * ```\r\n */\r\n\r\n/**\r\n * Observer function type used internally for tracking reactivity.\r\n */\r\nexport type Observer = () => void;\r\n\r\n/**\r\n * Cleanup function returned by effects for disposal.\r\n */\r\nexport type CleanupFn = () => void;\r\n\r\n// Internal state for tracking the current observer context\r\nconst observerStack: Observer[] = [];\r\nlet batchDepth = 0;\r\nconst pendingObservers = new Set<Observer>();\r\n\r\n// Flag to disable tracking temporarily (for untrack)\r\nlet trackingEnabled = true;\r\n\r\n/**\r\n * Tracks dependencies during a function execution.\r\n * Uses direct push/pop for O(1) operations instead of array copying.\r\n * @internal\r\n */\r\nconst track = <T>(observer: Observer, fn: () => T): T => {\r\n observerStack.push(observer);\r\n try {\r\n return fn();\r\n } finally {\r\n observerStack.pop();\r\n }\r\n};\r\n\r\n/**\r\n * Schedules an observer to run, respecting batch mode.\r\n * @internal\r\n */\r\nconst scheduleObserver = (observer: Observer) => {\r\n if (batchDepth > 0) {\r\n pendingObservers.add(observer);\r\n return;\r\n }\r\n observer();\r\n};\r\n\r\n/**\r\n * Flushes all pending observers after a batch completes.\r\n * @internal\r\n */\r\nconst flushObservers = () => {\r\n for (const observer of Array.from(pendingObservers)) {\r\n pendingObservers.delete(observer);\r\n observer();\r\n }\r\n};\r\n\r\n/**\r\n * A reactive value container that notifies subscribers on change.\r\n *\r\n * Signals are the foundational primitive of the reactive system.\r\n * Reading a signal's value inside an effect or computed automatically\r\n * establishes a reactive dependency.\r\n *\r\n * @template T - The type of the stored value\r\n *\r\n * @example\r\n * ```ts\r\n * const name = signal('World');\r\n * console.log(name.value); // 'World'\r\n *\r\n * name.value = 'bQuery';\r\n * console.log(name.value); // 'bQuery'\r\n * ```\r\n */\r\nexport class Signal<T> {\r\n private subscribers = new Set<Observer>();\r\n\r\n /**\r\n * Creates a new signal with an initial value.\r\n * @param _value - The initial value\r\n */\r\n constructor(private _value: T) {}\r\n\r\n /**\r\n * Gets the current value and tracks the read if inside an observer.\r\n * Respects the global tracking state (disabled during untrack calls).\r\n */\r\n get value(): T {\r\n if (trackingEnabled) {\r\n const current = observerStack[observerStack.length - 1];\r\n if (current) {\r\n this.subscribers.add(current);\r\n }\r\n }\r\n return this._value;\r\n }\r\n\r\n /**\r\n * Sets a new value and notifies all subscribers if the value changed.\r\n * Uses Object.is for equality comparison.\r\n */\r\n set value(next: T) {\r\n if (Object.is(this._value, next)) return;\r\n this._value = next;\r\n for (const subscriber of this.subscribers) {\r\n scheduleObserver(subscriber);\r\n }\r\n }\r\n\r\n /**\r\n * Reads the current value without tracking.\r\n * Useful when you need the value but don't want to create a dependency.\r\n *\r\n * @returns The current value\r\n */\r\n peek(): T {\r\n return this._value;\r\n }\r\n\r\n /**\r\n * Updates the value using a function.\r\n * Useful for updates based on the current value.\r\n *\r\n * @param updater - Function that receives current value and returns new value\r\n */\r\n update(updater: (current: T) => T): void {\r\n this.value = updater(this._value);\r\n }\r\n}\r\n\r\n/**\r\n * A computed value that derives from other reactive sources.\r\n *\r\n * Computed values are lazily evaluated and cached. They only\r\n * recompute when their dependencies change.\r\n *\r\n * @template T - The type of the computed value\r\n *\r\n * @example\r\n * ```ts\r\n * const price = signal(100);\r\n * const quantity = signal(2);\r\n * const total = computed(() => price.value * quantity.value);\r\n *\r\n * console.log(total.value); // 200\r\n * price.value = 150;\r\n * console.log(total.value); // 300\r\n * ```\r\n */\r\nexport class Computed<T> {\r\n private cachedValue!: T;\r\n private dirty = true;\r\n private subscribers = new Set<Observer>();\r\n private readonly markDirty = () => {\r\n this.dirty = true;\r\n for (const subscriber of this.subscribers) {\r\n scheduleObserver(subscriber);\r\n }\r\n };\r\n\r\n /**\r\n * Creates a new computed value.\r\n * @param compute - Function that computes the value\r\n */\r\n constructor(private readonly compute: () => T) {}\r\n\r\n /**\r\n * Gets the computed value, recomputing if dependencies changed.\r\n */\r\n get value(): T {\r\n const current = observerStack[observerStack.length - 1];\r\n if (current) {\r\n this.subscribers.add(current);\r\n }\r\n if (this.dirty) {\r\n this.dirty = false;\r\n this.cachedValue = track(this.markDirty, this.compute);\r\n }\r\n return this.cachedValue;\r\n }\r\n}\r\n\r\n/**\r\n * Creates a new reactive signal.\r\n *\r\n * @template T - The type of the signal value\r\n * @param value - The initial value\r\n * @returns A new Signal instance\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n * count.value++; // Triggers subscribers\r\n * ```\r\n */\r\nexport const signal = <T>(value: T): Signal<T> => new Signal(value);\r\n\r\n/**\r\n * Creates a new computed value.\r\n *\r\n * @template T - The type of the computed value\r\n * @param fn - Function that computes the value from reactive sources\r\n * @returns A new Computed instance\r\n *\r\n * @example\r\n * ```ts\r\n * const doubled = computed(() => count.value * 2);\r\n * ```\r\n */\r\nexport const computed = <T>(fn: () => T): Computed<T> => new Computed(fn);\r\n\r\n/**\r\n * Creates a side effect that automatically re-runs when dependencies change.\r\n *\r\n * The effect runs immediately upon creation and then re-runs whenever\r\n * any signal or computed value read inside it changes.\r\n *\r\n * @param fn - The effect function to run\r\n * @returns A cleanup function to stop the effect\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n *\r\n * const cleanup = effect(() => {\r\n * document.title = `Count: ${count.value}`;\r\n * });\r\n *\r\n * // Later, to stop the effect:\r\n * cleanup();\r\n * ```\r\n */\r\nexport const effect = (fn: () => void | CleanupFn): CleanupFn => {\r\n let cleanupFn: CleanupFn | void;\r\n let isDisposed = false;\r\n\r\n const observer: Observer = () => {\r\n if (isDisposed) return;\r\n\r\n // Run previous cleanup if exists\r\n if (cleanupFn) {\r\n cleanupFn();\r\n }\r\n\r\n // Run effect and capture cleanup\r\n cleanupFn = track(observer, fn);\r\n };\r\n\r\n observer();\r\n\r\n return () => {\r\n isDisposed = true;\r\n if (cleanupFn) {\r\n cleanupFn();\r\n }\r\n };\r\n};\r\n\r\n/**\r\n * Batches multiple signal updates into a single notification cycle.\r\n *\r\n * Updates made inside the batch function are deferred until the batch\r\n * completes, preventing intermediate re-renders and improving performance.\r\n *\r\n * @param fn - Function containing multiple signal updates\r\n *\r\n * @example\r\n * ```ts\r\n * batch(() => {\r\n * firstName.value = 'John';\r\n * lastName.value = 'Doe';\r\n * age.value = 30;\r\n * });\r\n * // Effects only run once with all three updates\r\n * ```\r\n */\r\nexport const batch = (fn: () => void): void => {\r\n batchDepth += 1;\r\n try {\r\n fn();\r\n } finally {\r\n batchDepth -= 1;\r\n if (batchDepth === 0) {\r\n flushObservers();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Creates a signal that persists to localStorage.\r\n *\r\n * @template T - The type of the signal value\r\n * @param key - The localStorage key\r\n * @param initialValue - The initial value if not found in storage\r\n * @returns A Signal that syncs with localStorage\r\n *\r\n * @example\r\n * ```ts\r\n * const theme = persistedSignal('theme', 'light');\r\n * theme.value = 'dark'; // Automatically saved to localStorage\r\n * ```\r\n */\r\nexport const persistedSignal = <T>(key: string, initialValue: T): Signal<T> => {\r\n let stored: T = initialValue;\r\n\r\n try {\r\n const raw = localStorage.getItem(key);\r\n if (raw !== null) {\r\n stored = JSON.parse(raw) as T;\r\n }\r\n } catch {\r\n // Use initial value on parse error\r\n }\r\n\r\n const sig = signal(stored);\r\n\r\n // Create an effect to persist changes\r\n effect(() => {\r\n try {\r\n localStorage.setItem(key, JSON.stringify(sig.value));\r\n } catch {\r\n // Ignore storage errors\r\n }\r\n });\r\n\r\n return sig;\r\n};\r\n\r\n// ============================================================================\r\n// Extended Reactive Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * A readonly wrapper around a signal that prevents writes.\r\n * Provides read-only access to a signal's value while maintaining reactivity.\r\n *\r\n * @template T - The type of the wrapped value\r\n */\r\nexport interface ReadonlySignal<T> {\r\n /** Gets the current value with dependency tracking. */\r\n readonly value: T;\r\n /** Gets the current value without dependency tracking. */\r\n peek(): T;\r\n}\r\n\r\n/**\r\n * Creates a read-only view of a signal.\r\n * Useful for exposing reactive state without allowing modifications.\r\n *\r\n * @template T - The type of the signal value\r\n * @param sig - The signal to wrap\r\n * @returns A readonly signal wrapper\r\n *\r\n * @example\r\n * ```ts\r\n * const _count = signal(0);\r\n * const count = readonly(_count); // Expose read-only version\r\n *\r\n * console.log(count.value); // 0\r\n * count.value = 1; // TypeScript error: Cannot assign to 'value'\r\n * ```\r\n */\r\nexport const readonly = <T>(sig: Signal<T>): ReadonlySignal<T> => ({\r\n get value(): T {\r\n return sig.value;\r\n },\r\n peek(): T {\r\n return sig.peek();\r\n },\r\n});\r\n\r\n/**\r\n * Watches a signal or computed value and calls a callback with old and new values.\r\n * Unlike effect, watch provides access to the previous value.\r\n *\r\n * @template T - The type of the watched value\r\n * @param source - The signal or computed to watch\r\n * @param callback - Function called with (newValue, oldValue) on changes\r\n * @param options - Watch options\r\n * @returns A cleanup function to stop watching\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n *\r\n * const cleanup = watch(count, (newVal, oldVal) => {\r\n * console.log(`Changed from ${oldVal} to ${newVal}`);\r\n * });\r\n *\r\n * count.value = 5; // Logs: \"Changed from 0 to 5\"\r\n * cleanup();\r\n * ```\r\n */\r\nexport const watch = <T>(\r\n source: Signal<T> | Computed<T>,\r\n callback: (newValue: T, oldValue: T | undefined) => void,\r\n options: { immediate?: boolean } = {}\r\n): CleanupFn => {\r\n let oldValue: T | undefined;\r\n let isFirst = true;\r\n\r\n return effect(() => {\r\n const newValue = source.value;\r\n\r\n if (isFirst) {\r\n isFirst = false;\r\n oldValue = newValue;\r\n if (options.immediate) {\r\n callback(newValue, undefined);\r\n }\r\n return;\r\n }\r\n\r\n callback(newValue, oldValue);\r\n oldValue = newValue;\r\n });\r\n};\r\n\r\n/**\r\n * Executes a function without tracking any signal dependencies.\r\n * Useful when reading a signal value without creating a reactive dependency.\r\n *\r\n * @template T - The return type of the function\r\n * @param fn - The function to execute without tracking\r\n * @returns The result of the function\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n *\r\n * effect(() => {\r\n * // This creates a dependency\r\n * console.log('Tracked:', count.value);\r\n *\r\n * // This does NOT create a dependency\r\n * const untracked = untrack(() => otherSignal.value);\r\n * });\r\n * ```\r\n */\r\nexport const untrack = <T>(fn: () => T): T => {\r\n const prevTracking = trackingEnabled;\r\n trackingEnabled = false;\r\n try {\r\n return fn();\r\n } finally {\r\n trackingEnabled = prevTracking;\r\n }\r\n};\r\n\r\n/**\r\n * Type guard to check if a value is a Signal instance.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a Signal\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n * const num = 42;\r\n *\r\n * isSignal(count); // true\r\n * isSignal(num); // false\r\n * ```\r\n */\r\nexport const isSignal = (value: unknown): value is Signal<unknown> => value instanceof Signal;\r\n\r\n/**\r\n * Type guard to check if a value is a Computed instance.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a Computed\r\n *\r\n * @example\r\n * ```ts\r\n * const doubled = computed(() => count.value * 2);\r\n * isComputed(doubled); // true\r\n * ```\r\n */\r\nexport const isComputed = (value: unknown): value is Computed<unknown> => value instanceof Computed;\r\n","/**\r\n * Minimal Web Component helper for building custom elements.\r\n *\r\n * This module provides a declarative API for defining Web Components\r\n * without complex build steps. Features include:\r\n * - Type-safe props with automatic attribute coercion\r\n * - Reactive state management\r\n * - Shadow DOM encapsulation with scoped styles\r\n * - Lifecycle hooks (connected, disconnected)\r\n * - Event emission helpers\r\n *\r\n * @module bquery/component\r\n *\r\n * @example\r\n * ```ts\r\n * import { component, html } from 'bquery/component';\r\n *\r\n * component('user-card', {\r\n * props: {\r\n * username: { type: String, required: true },\r\n * avatar: { type: String, default: '/default-avatar.png' },\r\n * },\r\n * styles: `\r\n * .card { padding: 1rem; border: 1px solid #ccc; }\r\n * `,\r\n * render({ props }) {\r\n * return html`\r\n * <div class=\"card\">\r\n * <img src=\"${props.avatar}\" alt=\"${props.username}\" />\r\n * <h3>${props.username}</h3>\r\n * </div>\r\n * `;\r\n * },\r\n * });\r\n * ```\r\n */\r\n\r\n/**\r\n * Defines a single prop's type and configuration.\r\n *\r\n * @template T - The TypeScript type of the prop value\r\n *\r\n * @example\r\n * ```ts\r\n * const myProp: PropDefinition<number> = {\r\n * type: Number,\r\n * required: false,\r\n * default: 0,\r\n * };\r\n * ```\r\n */\r\nexport type PropDefinition<T = unknown> = {\r\n /** Constructor or converter function for the prop type */\r\n type:\r\n | StringConstructor\r\n | NumberConstructor\r\n | BooleanConstructor\r\n | ObjectConstructor\r\n | ArrayConstructor\r\n | { new (value: unknown): T }\r\n | ((value: unknown) => T);\r\n /** Whether the prop must be provided */\r\n required?: boolean;\r\n /** Default value when prop is not provided */\r\n default?: T;\r\n /** Optional validator function to validate prop values */\r\n validator?: (value: T) => boolean;\r\n};\r\n\r\n/**\r\n * Complete component definition including props, state, styles, and lifecycle.\r\n *\r\n * @template TProps - Type of the component's props\r\n */\r\nexport type ComponentDefinition<TProps extends Record<string, unknown> = Record<string, unknown>> =\r\n {\r\n /** Prop definitions with types and defaults */\r\n props?: Record<keyof TProps, PropDefinition>;\r\n /** Initial internal state */\r\n state?: Record<string, unknown>;\r\n /** CSS styles scoped to the component's shadow DOM */\r\n styles?: string;\r\n /** Lifecycle hook called before the component mounts (before first render) */\r\n beforeMount?: () => void;\r\n /** Lifecycle hook called when component is added to DOM */\r\n connected?: () => void;\r\n /** Lifecycle hook called when component is removed from DOM */\r\n disconnected?: () => void;\r\n /** Lifecycle hook called before an update render; return false to prevent */\r\n beforeUpdate?: (props: TProps) => boolean | void;\r\n /** Lifecycle hook called after reactive updates trigger a render */\r\n updated?: () => void;\r\n /** Error handler for errors during rendering or lifecycle */\r\n onError?: (error: Error) => void;\r\n /** Render function returning HTML string */\r\n render: (context: {\r\n props: TProps;\r\n state: Record<string, unknown>;\r\n emit: (event: string, detail?: unknown) => void;\r\n }) => string;\r\n };\r\n\r\n/**\r\n * Coerces a string attribute value into a typed prop value.\r\n * Supports String, Number, Boolean, Object, Array, and custom converters.\r\n *\r\n * @internal\r\n * @template T - The target type\r\n * @param rawValue - The raw string value from the attribute\r\n * @param config - The prop definition with type information\r\n * @returns The coerced value of type T\r\n */\r\nconst coercePropValue = <T>(rawValue: string, config: PropDefinition<T>): T => {\r\n const { type } = config;\r\n\r\n if (type === String) return rawValue as T;\r\n\r\n if (type === Number) {\r\n const parsed = Number(rawValue);\r\n return (Number.isNaN(parsed) ? rawValue : parsed) as T;\r\n }\r\n\r\n if (type === Boolean) {\r\n const normalized = rawValue.trim().toLowerCase();\r\n if (normalized === '' || normalized === 'true' || normalized === '1') {\r\n return true as T;\r\n }\r\n if (normalized === 'false' || normalized === '0') {\r\n return false as T;\r\n }\r\n return Boolean(rawValue) as T;\r\n }\r\n\r\n if (type === Object || type === Array) {\r\n try {\r\n return JSON.parse(rawValue) as T;\r\n } catch {\r\n return rawValue as T;\r\n }\r\n }\r\n\r\n if (typeof type === 'function') {\r\n const callable = type as (value: unknown) => T;\r\n const constructable = type as new (value: unknown) => T;\r\n try {\r\n return callable(rawValue);\r\n } catch {\r\n return new constructable(rawValue);\r\n }\r\n }\r\n\r\n return rawValue as T;\r\n};\r\n\r\n/**\r\n * Tagged template literal for creating HTML strings.\r\n *\r\n * This function handles interpolation of values into HTML templates,\r\n * converting null/undefined to empty strings.\r\n *\r\n * @param strings - Template literal string parts\r\n * @param values - Interpolated values\r\n * @returns Combined HTML string\r\n *\r\n * @example\r\n * ```ts\r\n * const name = 'World';\r\n * const greeting = html`<h1>Hello, ${name}!</h1>`;\r\n * // Result: '<h1>Hello, World!</h1>'\r\n * ```\r\n */\r\nexport const html = (strings: TemplateStringsArray, ...values: unknown[]): string => {\r\n return strings.reduce((acc, part, index) => `${acc}${part}${values[index] ?? ''}`, '');\r\n};\r\n\r\n/**\r\n * Escapes HTML entities in interpolated values for XSS prevention.\r\n * Use this when you need to safely embed user content in templates.\r\n *\r\n * @param strings - Template literal string parts\r\n * @param values - Interpolated values to escape\r\n * @returns Combined HTML string with escaped values\r\n *\r\n * @example\r\n * ```ts\r\n * const userInput = '<script>alert(\"xss\")</script>';\r\n * const safe = safeHtml`<div>${userInput}</div>`;\r\n * // Result: '<div><script>alert(\"xss\")</script></div>'\r\n * ```\r\n */\r\nexport const safeHtml = (strings: TemplateStringsArray, ...values: unknown[]): string => {\r\n const escapeMap: Record<string, string> = {\r\n '&': '&',\r\n '<': '<',\r\n '>': '>',\r\n '\"': '"',\r\n \"'\": ''',\r\n '`': '`',\r\n };\r\n\r\n const escape = (value: unknown): string => {\r\n const str = String(value ?? '');\r\n return str.replace(/[&<>\"'`]/g, (char) => escapeMap[char]);\r\n };\r\n\r\n return strings.reduce((acc, part, index) => `${acc}${part}${escape(values[index])}`, '');\r\n};\r\n\r\n/**\r\n * Defines and registers a custom Web Component.\r\n *\r\n * This function creates a new custom element with the given tag name\r\n * and configuration. The component uses Shadow DOM for encapsulation\r\n * and automatically re-renders when observed attributes change.\r\n *\r\n * @template TProps - Type of the component's props\r\n * @param tagName - The custom element tag name (must contain a hyphen)\r\n * @param definition - The component configuration\r\n *\r\n * @example\r\n * ```ts\r\n * component('counter-button', {\r\n * props: {\r\n * start: { type: Number, default: 0 },\r\n * },\r\n * state: { count: 0 },\r\n * styles: `\r\n * button { padding: 0.5rem 1rem; }\r\n * `,\r\n * connected() {\r\n * console.log('Counter mounted');\r\n * },\r\n * render({ props, state, emit }) {\r\n * return html`\r\n * <button onclick=\"this.getRootNode().host.increment()\">\r\n * Count: ${state.count}\r\n * </button>\r\n * `;\r\n * },\r\n * });\r\n * ```\r\n */\r\nexport const component = <TProps extends Record<string, unknown>>(\r\n tagName: string,\r\n definition: ComponentDefinition<TProps>\r\n): void => {\r\n /**\r\n * Internal Web Component class created for each component definition.\r\n * @internal\r\n */\r\n class BQueryComponent extends HTMLElement {\r\n /** Internal state object for the component */\r\n private readonly state = { ...(definition.state ?? {}) };\r\n /** Typed props object populated from attributes */\r\n private props = {} as TProps;\r\n\r\n constructor() {\r\n super();\r\n this.attachShadow({ mode: 'open' });\r\n this.syncProps();\r\n }\r\n\r\n /**\r\n * Returns the list of attributes to observe for changes.\r\n */\r\n static get observedAttributes(): string[] {\r\n return Object.keys(definition.props ?? {});\r\n }\r\n\r\n /**\r\n * Called when the element is added to the DOM.\r\n */\r\n connectedCallback(): void {\r\n try {\r\n definition.beforeMount?.call(this);\r\n definition.connected?.call(this);\r\n this.render();\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Called when the element is removed from the DOM.\r\n */\r\n disconnectedCallback(): void {\r\n try {\r\n definition.disconnected?.call(this);\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Called when an observed attribute changes.\r\n */\r\n attributeChangedCallback(): void {\r\n try {\r\n this.syncProps();\r\n this.render(true);\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Handles errors during component lifecycle.\r\n * @internal\r\n */\r\n private handleError(error: Error): void {\r\n if (definition.onError) {\r\n definition.onError.call(this, error);\r\n } else {\r\n console.error(`bQuery component error in <${tagName}>:`, error);\r\n }\r\n }\r\n\r\n /**\r\n * Updates a state property and triggers a re-render.\r\n *\r\n * @param key - The state property key\r\n * @param value - The new value\r\n */\r\n setState(key: string, value: unknown): void {\r\n this.state[key] = value;\r\n this.render(true);\r\n }\r\n\r\n /**\r\n * Gets a state property value.\r\n *\r\n * @param key - The state property key\r\n * @returns The current value\r\n */\r\n getState<T = unknown>(key: string): T {\r\n return this.state[key] as T;\r\n }\r\n\r\n /**\r\n * Synchronizes props from attributes.\r\n * @internal\r\n */\r\n private syncProps(): void {\r\n const props = definition.props ?? {};\r\n for (const [key, config] of Object.entries(props) as [string, PropDefinition][]) {\r\n const attrValue = this.getAttribute(key);\r\n let value: unknown;\r\n\r\n if (attrValue == null) {\r\n if (config.required && config.default === undefined) {\r\n throw new Error(`bQuery component: missing required prop \"${key}\"`);\r\n }\r\n value = config.default ?? undefined;\r\n } else {\r\n value = coercePropValue(attrValue, config);\r\n }\r\n\r\n // Validate the prop value if a validator is provided\r\n if (config.validator && value !== undefined) {\r\n const isValid = config.validator(value);\r\n if (!isValid) {\r\n throw new Error(\r\n `bQuery component: validation failed for prop \"${key}\" with value ${JSON.stringify(value)}`\r\n );\r\n }\r\n }\r\n\r\n (this.props as Record<string, unknown>)[key] = value;\r\n }\r\n }\r\n\r\n /**\r\n * Renders the component to its shadow root.\r\n * @internal\r\n */\r\n private render(triggerUpdated = false): void {\r\n try {\r\n // Check beforeUpdate hook if this is an update\r\n if (triggerUpdated && definition.beforeUpdate) {\r\n const shouldUpdate = definition.beforeUpdate.call(this, this.props);\r\n if (shouldUpdate === false) return;\r\n }\r\n\r\n /**\r\n * Emits a custom event from the component.\r\n */\r\n const emit = (event: string, detail?: unknown): void => {\r\n this.dispatchEvent(new CustomEvent(event, { detail, bubbles: true, composed: true }));\r\n };\r\n\r\n if (!this.shadowRoot) return;\r\n\r\n const markup = definition.render({\r\n props: this.props,\r\n state: this.state,\r\n emit,\r\n });\r\n\r\n const styles = definition.styles ? `<style>${definition.styles}</style>` : '';\r\n this.shadowRoot.innerHTML = `${styles}${markup}`;\r\n\r\n if (triggerUpdated) {\r\n definition.updated?.call(this);\r\n }\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n }\r\n }\r\n }\r\n\r\n if (!customElements.get(tagName)) {\r\n customElements.define(tagName, BQueryComponent);\r\n }\r\n};\r\n","/**\n * Motion module providing view transitions, FLIP animations, and spring physics.\n * Designed to work with modern browser APIs while providing smooth fallbacks.\n *\n * @module bquery/motion\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Options for view transitions.\n */\nexport interface TransitionOptions {\n /** The DOM update function to execute during transition */\n update: () => void;\n}\n\n/**\n * Captured element bounds for FLIP animations.\n */\nexport interface ElementBounds {\n top: number;\n left: number;\n width: number;\n height: number;\n}\n\n/**\n * FLIP animation configuration options.\n */\nexport interface FlipOptions {\n /** Animation duration in milliseconds */\n duration?: number;\n /** CSS easing function */\n easing?: string;\n /** Callback when animation completes */\n onComplete?: () => void;\n}\n\n/**\n * Spring physics configuration.\n */\nexport interface SpringConfig {\n /** Spring stiffness (default: 100) */\n stiffness?: number;\n /** Damping coefficient (default: 10) */\n damping?: number;\n /** Mass of the object (default: 1) */\n mass?: number;\n /** Velocity threshold for completion (default: 0.01) */\n precision?: number;\n}\n\n/**\n * Spring instance for animating values.\n */\nexport interface Spring {\n /** Start animating to target value */\n to(target: number): Promise<void>;\n /** Get current animated value */\n current(): number;\n /** Stop the animation */\n stop(): void;\n /** Subscribe to value changes */\n onChange(callback: (value: number) => void): () => void;\n}\n\n// ============================================================================\n// View Transitions\n// ============================================================================\n\n/** Extended document type with View Transitions API */\ntype DocumentWithTransition = Document & {\n startViewTransition?: (callback: () => void) => {\n finished: Promise<void>;\n ready: Promise<void>;\n updateCallbackDone: Promise<void>;\n };\n};\n\n/**\n * Execute a DOM update with view transition animation.\n * Falls back to immediate update when View Transitions API is unavailable.\n *\n * @param updateOrOptions - Update function or options object\n * @returns Promise that resolves when transition completes\n *\n * @example\n * ```ts\n * await transition(() => {\n * $('#content').text('Updated');\n * });\n * ```\n */\nexport const transition = async (\n updateOrOptions: (() => void) | TransitionOptions\n): Promise<void> => {\n const update = typeof updateOrOptions === 'function' ? updateOrOptions : updateOrOptions.update;\n\n const doc = document as DocumentWithTransition;\n\n if (doc.startViewTransition) {\n await doc.startViewTransition(() => update()).finished;\n return;\n }\n\n update();\n};\n\n// ============================================================================\n// FLIP Animations\n// ============================================================================\n\n/**\n * Capture the current bounds of an element for FLIP animation.\n *\n * @param element - The DOM element to measure\n * @returns The element's current position and size\n */\nexport const capturePosition = (element: Element): ElementBounds => {\n const rect = element.getBoundingClientRect();\n return {\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n };\n};\n\n/**\n * Perform a FLIP (First, Last, Invert, Play) animation.\n * Animates an element from its captured position to its current position.\n *\n * @param element - The element to animate\n * @param firstBounds - The previously captured bounds\n * @param options - Animation configuration\n * @returns Promise that resolves when animation completes\n *\n * @example\n * ```ts\n * const first = capturePosition(element);\n * // ... DOM changes that move the element ...\n * await flip(element, first, { duration: 300 });\n * ```\n */\nexport const flip = (\n element: Element,\n firstBounds: ElementBounds,\n options: FlipOptions = {}\n): Promise<void> => {\n const { duration = 300, easing = 'ease-out', onComplete } = options;\n\n // Last: Get current position\n const lastBounds = capturePosition(element);\n\n // Skip animation if element has zero dimensions (avoid division by zero)\n if (lastBounds.width === 0 || lastBounds.height === 0) {\n return Promise.resolve();\n }\n\n // Invert: Calculate the delta\n const deltaX = firstBounds.left - lastBounds.left;\n const deltaY = firstBounds.top - lastBounds.top;\n const deltaW = firstBounds.width / lastBounds.width;\n const deltaH = firstBounds.height / lastBounds.height;\n\n // Skip animation if no change\n if (deltaX === 0 && deltaY === 0 && deltaW === 1 && deltaH === 1) {\n return Promise.resolve();\n }\n\n const htmlElement = element as HTMLElement;\n\n // Apply inverted transform\n htmlElement.style.transform = `translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`;\n htmlElement.style.transformOrigin = 'top left';\n\n // Force reflow\n void htmlElement.offsetHeight;\n\n // Play: Animate back to current position\n return new Promise((resolve) => {\n const animation = htmlElement.animate(\n [\n {\n transform: `translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`,\n },\n { transform: 'translate(0, 0) scale(1, 1)' },\n ],\n { duration, easing, fill: 'forwards' }\n );\n\n animation.onfinish = () => {\n htmlElement.style.transform = '';\n htmlElement.style.transformOrigin = '';\n onComplete?.();\n resolve();\n };\n });\n};\n\n/**\n * FLIP helper for animating a list of elements.\n * Useful for reordering lists with smooth animations.\n *\n * @param elements - Array of elements to animate\n * @param performUpdate - Function that performs the DOM update\n * @param options - Animation configuration\n *\n * @example\n * ```ts\n * await flipList(listItems, () => {\n * container.appendChild(container.firstChild); // Move first to last\n * });\n * ```\n */\nexport const flipList = async (\n elements: Element[],\n performUpdate: () => void,\n options: FlipOptions = {}\n): Promise<void> => {\n // First: Capture all positions\n const positions = new Map<Element, ElementBounds>();\n for (const el of elements) {\n positions.set(el, capturePosition(el));\n }\n\n // Perform DOM update\n performUpdate();\n\n // Animate each element\n const animations = elements.map((el) => {\n const first = positions.get(el);\n if (!first) return Promise.resolve();\n return flip(el, first, options);\n });\n\n await Promise.all(animations);\n};\n\n// ============================================================================\n// Spring Physics\n// ============================================================================\n\n/**\n * Default spring configuration values.\n */\nconst DEFAULT_SPRING_CONFIG: Required<SpringConfig> = {\n stiffness: 100,\n damping: 10,\n mass: 1,\n precision: 0.01,\n};\n\n/**\n * Create a spring-based animation for smooth, physics-based motion.\n *\n * @param initialValue - Starting value for the spring\n * @param config - Spring physics configuration\n * @returns Spring instance for controlling the animation\n *\n * @example\n * ```ts\n * const x = spring(0, { stiffness: 120, damping: 14 });\n * x.onChange((value) => {\n * element.style.transform = `translateX(${value}px)`;\n * });\n * await x.to(100);\n * ```\n */\nexport const spring = (initialValue: number, config: SpringConfig = {}): Spring => {\n const { stiffness, damping, mass, precision } = {\n ...DEFAULT_SPRING_CONFIG,\n ...config,\n };\n\n let current = initialValue;\n let velocity = 0;\n let target = initialValue;\n let animationFrame: number | null = null;\n let resolvePromise: (() => void) | null = null;\n const listeners = new Set<(value: number) => void>();\n\n const notifyListeners = () => {\n for (const listener of listeners) {\n listener(current);\n }\n };\n\n const step = () => {\n // Spring physics calculation\n const displacement = current - target;\n const springForce = -stiffness * displacement;\n const dampingForce = -damping * velocity;\n const acceleration = (springForce + dampingForce) / mass;\n\n velocity += acceleration * (1 / 60); // Assuming 60fps\n current += velocity * (1 / 60);\n\n notifyListeners();\n\n // Check if spring has settled\n if (Math.abs(velocity) < precision && Math.abs(displacement) < precision) {\n current = target;\n velocity = 0;\n animationFrame = null;\n notifyListeners();\n resolvePromise?.();\n resolvePromise = null;\n return;\n }\n\n animationFrame = requestAnimationFrame(step);\n };\n\n return {\n to(newTarget: number): Promise<void> {\n target = newTarget;\n\n if (animationFrame !== null) {\n cancelAnimationFrame(animationFrame);\n }\n\n return new Promise((resolve) => {\n resolvePromise = resolve;\n animationFrame = requestAnimationFrame(step);\n });\n },\n\n current(): number {\n return current;\n },\n\n stop(): void {\n if (animationFrame !== null) {\n cancelAnimationFrame(animationFrame);\n animationFrame = null;\n }\n velocity = 0;\n resolvePromise?.();\n resolvePromise = null;\n },\n\n onChange(callback: (value: number) => void): () => void {\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n };\n};\n\n/**\n * Preset spring configurations for common use cases.\n */\nexport const springPresets = {\n /** Gentle, slow-settling spring */\n gentle: { stiffness: 80, damping: 15 } as SpringConfig,\n /** Responsive, snappy spring */\n snappy: { stiffness: 200, damping: 20 } as SpringConfig,\n /** Bouncy, playful spring */\n bouncy: { stiffness: 300, damping: 8 } as SpringConfig,\n /** Stiff, quick spring with minimal overshoot */\n stiff: { stiffness: 400, damping: 30 } as SpringConfig,\n};\n","/**\n * Storage Buckets API wrapper.\n * Provides a simplified interface for storing blobs and binary data.\n * Falls back to IndexedDB when Storage Buckets API is not available.\n */\n\n/**\n * Bucket interface for blob storage operations.\n */\nexport interface Bucket {\n /**\n * Store a blob in the bucket.\n * @param key - Unique identifier for the blob\n * @param data - Blob data to store\n */\n put(key: string, data: Blob): Promise<void>;\n\n /**\n * Retrieve a blob from the bucket.\n * @param key - Blob identifier\n * @returns The stored blob or null if not found\n */\n get(key: string): Promise<Blob | null>;\n\n /**\n * Remove a blob from the bucket.\n * @param key - Blob identifier\n */\n remove(key: string): Promise<void>;\n\n /**\n * List all keys in the bucket.\n * @returns Array of blob keys\n */\n keys(): Promise<string[]>;\n}\n\n/**\n * IndexedDB-based bucket implementation.\n * Used as fallback when Storage Buckets API is unavailable.\n */\nclass IndexedDBBucket implements Bucket {\n private dbPromise: Promise<IDBDatabase> | null = null;\n private readonly storeName = 'blobs';\n\n constructor(private readonly bucketName: string) {}\n\n private openDB(): Promise<IDBDatabase> {\n if (this.dbPromise) return this.dbPromise;\n\n const dbName = `bquery-bucket-${this.bucketName}`;\n this.dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(dbName, 1);\n\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(this.storeName)) {\n db.createObjectStore(this.storeName);\n }\n };\n\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n\n return this.dbPromise;\n }\n\n private async withStore<T>(\n mode: IDBTransactionMode,\n operation: (store: IDBObjectStore) => IDBRequest<T>\n ): Promise<T> {\n const db = await this.openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.storeName, mode);\n const store = tx.objectStore(this.storeName);\n const request = operation(store);\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n\n async put(key: string, data: Blob): Promise<void> {\n await this.withStore('readwrite', (store) => store.put(data, key));\n }\n\n async get(key: string): Promise<Blob | null> {\n const result = await this.withStore<Blob | undefined>('readonly', (store) => store.get(key));\n return result ?? null;\n }\n\n async remove(key: string): Promise<void> {\n await this.withStore('readwrite', (store) => store.delete(key));\n }\n\n async keys(): Promise<string[]> {\n const result = await this.withStore<IDBValidKey[]>('readonly', (store) => store.getAllKeys());\n return result.map((key) => String(key));\n }\n}\n\n/**\n * Bucket manager for creating and accessing storage buckets.\n */\nexport const buckets = {\n /**\n * Open or create a storage bucket.\n * @param name - Bucket name\n * @returns Bucket instance for blob operations\n */\n async open(name: string): Promise<Bucket> {\n // Storage Buckets API is experimental; use IndexedDB fallback\n return new IndexedDBBucket(name);\n },\n};\n","/**\n * Cache Storage API wrapper.\n * Provides a simplified interface for caching responses and assets.\n */\n\n/**\n * Cache handle interface for managing cached resources.\n */\nexport interface CacheHandle {\n /**\n * Add a resource to the cache by URL.\n * Fetches the resource and stores the response.\n * @param url - URL to fetch and cache\n */\n add(url: string): Promise<void>;\n\n /**\n * Add multiple resources to the cache.\n * @param urls - Array of URLs to fetch and cache\n */\n addAll(urls: string[]): Promise<void>;\n\n /**\n * Store a custom response in the cache.\n * @param url - URL key for the cached response\n * @param response - Response object to cache\n */\n put(url: string, response: Response): Promise<void>;\n\n /**\n * Retrieve a cached response.\n * @param url - URL to look up\n * @returns Cached Response or undefined if not found\n */\n match(url: string): Promise<Response | undefined>;\n\n /**\n * Remove a cached response.\n * @param url - URL to remove from cache\n * @returns True if the entry was deleted\n */\n remove(url: string): Promise<boolean>;\n\n /**\n * Get all cached request URLs.\n * @returns Array of cached URLs\n */\n keys(): Promise<string[]>;\n}\n\n/**\n * Internal cache handle implementation.\n */\nclass CacheHandleImpl implements CacheHandle {\n constructor(private readonly cache: Cache) {}\n\n async add(url: string): Promise<void> {\n await this.cache.add(url);\n }\n\n async addAll(urls: string[]): Promise<void> {\n await this.cache.addAll(urls);\n }\n\n async put(url: string, response: Response): Promise<void> {\n await this.cache.put(url, response);\n }\n\n async match(url: string): Promise<Response | undefined> {\n return this.cache.match(url);\n }\n\n async remove(url: string): Promise<boolean> {\n return this.cache.delete(url);\n }\n\n async keys(): Promise<string[]> {\n const requests = await this.cache.keys();\n return requests.map((req) => req.url);\n }\n}\n\n/**\n * Cache manager for accessing the Cache Storage API.\n */\nexport const cache = {\n /**\n * Check if Cache Storage API is supported.\n * @returns True if caches API is available\n */\n isSupported(): boolean {\n return 'caches' in window;\n },\n\n /**\n * Open or create a named cache.\n * @param name - Cache name\n * @returns CacheHandle for cache operations\n */\n async open(name: string): Promise<CacheHandle> {\n if (!this.isSupported()) {\n throw new Error('bQuery: Cache Storage API not supported');\n }\n const c = await caches.open(name);\n return new CacheHandleImpl(c);\n },\n\n /**\n * Delete a named cache.\n * @param name - Cache name to delete\n * @returns True if the cache was deleted\n */\n async delete(name: string): Promise<boolean> {\n if (!this.isSupported()) {\n return false;\n }\n return caches.delete(name);\n },\n\n /**\n * List all cache names.\n * @returns Array of cache names\n */\n async keys(): Promise<string[]> {\n if (!this.isSupported()) {\n return [];\n }\n return caches.keys();\n },\n};\n","/**\n * Web Notifications API wrapper.\n * Provides a simplified interface for browser notifications.\n */\n\n/**\n * Notification options matching the standard NotificationOptions interface.\n */\nexport interface NotificationOptions {\n /** Body text of the notification */\n body?: string;\n /** Icon URL for the notification */\n icon?: string;\n /** Badge icon for mobile devices */\n badge?: string;\n /** Tag for grouping notifications */\n tag?: string;\n /** Whether to require user interaction */\n requireInteraction?: boolean;\n /** Vibration pattern for mobile devices */\n vibrate?: number[];\n /** Additional data attached to the notification */\n data?: unknown;\n}\n\n/**\n * Notifications manager providing a clean interface for web notifications.\n */\nexport const notifications = {\n /**\n * Check if notifications are supported.\n * @returns True if Notification API is available\n */\n isSupported(): boolean {\n return 'Notification' in window;\n },\n\n /**\n * Get current permission status.\n * @returns Current permission state\n */\n getPermission(): NotificationPermission {\n if (!this.isSupported()) return 'denied';\n return Notification.permission;\n },\n\n /**\n * Request notification permission from the user.\n * @returns Promise resolving to the permission result\n */\n async requestPermission(): Promise<NotificationPermission> {\n if (!this.isSupported()) {\n return 'denied';\n }\n\n if (Notification.permission === 'granted') {\n return 'granted';\n }\n\n if (Notification.permission === 'denied') {\n return 'denied';\n }\n\n return Notification.requestPermission();\n },\n\n /**\n * Send a notification.\n * Requires 'granted' permission.\n * @param title - Notification title\n * @param options - Optional notification settings\n * @returns The Notification instance or null if not permitted\n */\n send(title: string, options?: NotificationOptions): Notification | null {\n if (!this.isSupported()) {\n console.warn('bQuery: Notifications not supported in this browser');\n return null;\n }\n\n if (Notification.permission !== 'granted') {\n console.warn('bQuery: Notification permission not granted');\n return null;\n }\n\n return new Notification(title, options);\n },\n};\n","/**\n * Unified storage adapters for web platform storage APIs.\n * Provides a consistent, promise-based interface with predictable errors.\n */\n\n/**\n * Common interface for all storage adapters.\n * All methods return promises for a unified async API.\n */\nexport interface StorageAdapter {\n /**\n * Retrieve a value by key.\n * @param key - The storage key\n * @returns The stored value or null if not found\n */\n get<T>(key: string): Promise<T | null>;\n\n /**\n * Store a value by key.\n * @param key - The storage key\n * @param value - The value to store\n */\n set<T>(key: string, value: T): Promise<void>;\n\n /**\n * Remove a value by key.\n * @param key - The storage key\n */\n remove(key: string): Promise<void>;\n\n /**\n * Clear all stored values.\n */\n clear(): Promise<void>;\n\n /**\n * Get all storage keys.\n * @returns Array of all keys\n */\n keys(): Promise<string[]>;\n}\n\n/**\n * Abstract base class for web storage adapters (localStorage/sessionStorage).\n * Implements DRY principle by sharing common logic.\n */\nabstract class WebStorageAdapter implements StorageAdapter {\n constructor(protected readonly storage: Storage) {}\n\n async get<T>(key: string): Promise<T | null> {\n const raw = this.storage.getItem(key);\n if (raw === null) return null;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return raw as unknown as T;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n const serialized = typeof value === 'string' ? value : JSON.stringify(value);\n this.storage.setItem(key, serialized);\n }\n\n async remove(key: string): Promise<void> {\n this.storage.removeItem(key);\n }\n\n async clear(): Promise<void> {\n this.storage.clear();\n }\n\n async keys(): Promise<string[]> {\n return Object.keys(this.storage);\n }\n}\n\n/**\n * localStorage adapter with async interface.\n */\nclass LocalStorageAdapter extends WebStorageAdapter {\n constructor() {\n super(localStorage);\n }\n}\n\n/**\n * sessionStorage adapter with async interface.\n */\nclass SessionStorageAdapter extends WebStorageAdapter {\n constructor() {\n super(sessionStorage);\n }\n}\n\n/**\n * IndexedDB configuration options.\n */\nexport interface IndexedDBOptions {\n /** Database name */\n name: string;\n /** Object store name */\n store: string;\n /** Database version (optional) */\n version?: number;\n}\n\n/**\n * IndexedDB key-value adapter.\n * Wraps IndexedDB with a simple key-value interface.\n */\nclass IndexedDBAdapter implements StorageAdapter {\n private dbPromise: Promise<IDBDatabase> | null = null;\n\n constructor(private readonly options: IndexedDBOptions) {}\n\n /**\n * Opens or creates the IndexedDB database.\n */\n private openDB(): Promise<IDBDatabase> {\n if (this.dbPromise) return this.dbPromise;\n\n this.dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(this.options.name, this.options.version ?? 1);\n\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(this.options.store)) {\n db.createObjectStore(this.options.store);\n }\n };\n\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n\n return this.dbPromise;\n }\n\n /**\n * Executes a transaction on the object store.\n */\n private async withStore<T>(\n mode: IDBTransactionMode,\n operation: (store: IDBObjectStore) => IDBRequest<T>\n ): Promise<T> {\n const db = await this.openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.options.store, mode);\n const store = tx.objectStore(this.options.store);\n const request = operation(store);\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n\n async get<T>(key: string): Promise<T | null> {\n const result = await this.withStore<T | undefined>('readonly', (store) => store.get(key));\n return result ?? null;\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n await this.withStore('readwrite', (store) => store.put(value, key));\n }\n\n async remove(key: string): Promise<void> {\n await this.withStore('readwrite', (store) => store.delete(key));\n }\n\n async clear(): Promise<void> {\n await this.withStore('readwrite', (store) => store.clear());\n }\n\n async keys(): Promise<string[]> {\n const result = await this.withStore<IDBValidKey[]>('readonly', (store) => store.getAllKeys());\n return result.map((key) => String(key));\n }\n}\n\n/**\n * Storage factory providing access to different storage adapters.\n */\nexport const storage = {\n /**\n * Create a localStorage adapter.\n * @returns StorageAdapter wrapping localStorage\n */\n local(): StorageAdapter {\n return new LocalStorageAdapter();\n },\n\n /**\n * Create a sessionStorage adapter.\n * @returns StorageAdapter wrapping sessionStorage\n */\n session(): StorageAdapter {\n return new SessionStorageAdapter();\n },\n\n /**\n * Create an IndexedDB adapter with key-value interface.\n * @param options - Database and store configuration\n * @returns StorageAdapter wrapping IndexedDB\n */\n indexedDB(options: IndexedDBOptions): StorageAdapter {\n return new IndexedDBAdapter(options);\n },\n};\n"],"names":["POLICY_NAME","cachedPolicy","isTrustedTypesSupported","getTrustedTypesPolicy","win","input","sanitizeHtmlCore","DEFAULT_ALLOWED_TAGS","DANGEROUS_TAGS","RESERVED_IDS","DEFAULT_ALLOWED_ATTRIBUTES","DANGEROUS_ATTR_PREFIXES","DANGEROUS_PROTOCOLS","isAllowedAttribute","name","allowedSet","allowDataAttrs","lowerName","prefix","isSafeIdOrName","value","lowerValue","normalizeUrl","isSafeUrl","normalized","protocol","isExternalUrl","url","trimmedUrl","lowerUrl","html","options","allowTags","allowAttributes","allowDataAttributes","stripAllTags","allowedTags","t","tag","allowedAttrs","a","template","walker","toRemove","el","tagName","attrsToRemove","attr","attrName","href","hasTargetBlank","isExternal","existingRel","relValues","sanitizeHtml","createTrustedHtml","policy","escapeHtml","text","escapeMap","char","stripTags","generateNonce","length","array","hasCSPDirective","directive","meta","toElementList","applyAll","elements","action","BQueryElement","element","classNames","className","force","key","match","property","val","content","wrapper","wrapperEl","parent","newEl","deep","selector","child","event","handler","detail","e","target","handlers","display","isHidden","newValue","form","result","formData","existing","params","position","BQueryCollection","index","callback","predicate","initialValue","sanitized","elementHandlers","$","$$","utils","sources","source","fn","delayMs","timeoutId","args","intervalMs","lastRun","now","json","fallback","obj","keys","ms","resolve","min","max","str","_","observerStack","batchDepth","pendingObservers","trackingEnabled","track","observer","scheduleObserver","flushObservers","Signal","_value","current","next","subscriber","updater","Computed","compute","signal","computed","effect","cleanupFn","isDisposed","batch","persistedSignal","stored","raw","sig","readonly","watch","oldValue","isFirst","untrack","prevTracking","isSignal","isComputed","coercePropValue","rawValue","config","type","parsed","callable","constructable","strings","values","acc","part","safeHtml","escape","component","definition","BQueryComponent","error","props","attrValue","triggerUpdated","emit","markup","styles","transition","updateOrOptions","update","doc","capturePosition","rect","flip","firstBounds","duration","easing","onComplete","lastBounds","deltaX","deltaY","deltaW","deltaH","htmlElement","animation","flipList","performUpdate","positions","animations","first","DEFAULT_SPRING_CONFIG","spring","stiffness","damping","mass","precision","velocity","animationFrame","resolvePromise","listeners","notifyListeners","listener","step","displacement","springForce","dampingForce","acceleration","newTarget","springPresets","IndexedDBBucket","bucketName","dbName","reject","request","db","mode","operation","store","data","buckets","CacheHandleImpl","cache","urls","response","req","c","notifications","title","WebStorageAdapter","storage","serialized","LocalStorageAdapter","SessionStorageAdapter","IndexedDBAdapter"],"mappings":"8NA4BA,MAAMA,EAAc,mBA4BpB,IAAIC,EAAyC,KAMtC,MAAMC,EAA0B,IAC9B,OAAQ,OAA8B,aAAiB,IAOnDC,EAAwB,IAAgC,CACnE,GAAIF,EAAc,OAAOA,EAEzB,MAAMG,EAAM,OACZ,GAAI,CAACA,EAAI,aAAc,OAAO,KAE9B,GAAI,CACF,OAAAH,EAAeG,EAAI,aAAa,aAAaJ,EAAa,CACxD,WAAaK,GAAkBC,EAAiBD,CAAK,CAAA,CACtD,EACMJ,CACT,MAAQ,CAEN,eAAQ,KAAK,kDAAkDD,CAAW,GAAG,EACtE,IACT,CACF,EASMO,MAA2B,IAAI,CACnC,IACA,OACA,UACA,UACA,QACA,IACA,MACA,MACA,aACA,KACA,SACA,UACA,OACA,OACA,MACA,WACA,OACA,KACA,MACA,UACA,MACA,MACA,KACA,KACA,KACA,aACA,SACA,SACA,OACA,KACA,KACA,KACA,KACA,KACA,KACA,SACA,SACA,KACA,IACA,MACA,QACA,MACA,MACA,QACA,SACA,KACA,OACA,OACA,MACA,KACA,WACA,SACA,IACA,UACA,MACA,WACA,IACA,KACA,KACA,OACA,IACA,OACA,UACA,SACA,QACA,SACA,OACA,SACA,MACA,UACA,MACA,QACA,QACA,KACA,WACA,QACA,KACA,QACA,OACA,KACA,IACA,KACA,MACA,KACF,CAAC,EAMKC,MAAqB,IAAI,CAC7B,SACA,SACA,QACA,WACA,SACA,QACA,SACA,OACA,OACA,QACA,OACA,WACA,OACA,OACA,MACA,gBACA,UACF,CAAC,EAMKC,MAAmB,IAAI,CAE3B,WACA,SACA,WACA,MACA,OACA,SACA,SACA,UACA,YACA,SAEA,QACA,UACA,SACA,OACA,WAEA,SACA,SACA,WACA,OACA,OACA,QACA,SACA,QACA,UAEA,WACA,aACA,aACA,YAEA,YACA,YACA,aACF,CAAC,EAKKC,MAAiC,IAAI,CACzC,MACA,QACA,MACA,SACA,SACA,OACA,KACA,OACA,UACA,OACA,MACA,OACA,MACA,SACA,QACA,WACA,SACA,QACA,OACA,QACA,QACF,CA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"}
|
|
1
|
+
{"version":3,"file":"full.umd.js","sources":["../src/security/sanitize.ts","../src/core/shared.ts","../src/core/element.ts","../src/core/collection.ts","../src/core/selector.ts","../src/core/utils.ts","../src/reactive/signal.ts","../src/component/index.ts","../src/motion/index.ts","../src/platform/buckets.ts","../src/platform/cache.ts","../src/platform/notifications.ts","../src/platform/storage.ts","../src/router/index.ts","../src/store/index.ts","../src/view/index.ts"],"sourcesContent":["/**\r\n * Security utilities for HTML sanitization, CSP compatibility, and Trusted Types.\r\n * All DOM writes are sanitized by default to prevent XSS attacks.\r\n *\r\n * @module bquery/security\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Sanitizer configuration options.\r\n */\r\nexport interface SanitizeOptions {\r\n /** Allow these additional tags (default: none) */\r\n allowTags?: string[];\r\n /** Allow these additional attributes (default: none) */\r\n allowAttributes?: string[];\r\n /** Allow data-* attributes (default: true) */\r\n allowDataAttributes?: boolean;\r\n /** Strip all tags and return plain text (default: false) */\r\n stripAllTags?: boolean;\r\n}\r\n\r\n/**\r\n * Trusted Types policy name.\r\n */\r\nconst POLICY_NAME = 'bquery-sanitizer';\r\n\r\n// ============================================================================\r\n// Trusted Types Support\r\n// ============================================================================\r\n\r\n/** Window interface extended with Trusted Types */\r\ninterface TrustedTypesWindow extends Window {\r\n trustedTypes?: {\r\n createPolicy: (\r\n name: string,\r\n rules: { createHTML?: (input: string) => string }\r\n ) => TrustedTypePolicy;\r\n isHTML?: (value: unknown) => boolean;\r\n };\r\n}\r\n\r\n/** Trusted Types policy interface */\r\ninterface TrustedTypePolicy {\r\n createHTML: (input: string) => TrustedHTML;\r\n}\r\n\r\n/** Trusted HTML type placeholder for environments without Trusted Types */\r\ninterface TrustedHTML {\r\n toString(): string;\r\n}\r\n\r\n/** Cached Trusted Types policy */\r\nlet cachedPolicy: TrustedTypePolicy | null = null;\r\n\r\n/**\r\n * Check if Trusted Types API is available.\r\n * @returns True if Trusted Types are supported\r\n */\r\nexport const isTrustedTypesSupported = (): boolean => {\r\n return typeof (window as TrustedTypesWindow).trustedTypes !== 'undefined';\r\n};\r\n\r\n/**\r\n * Get or create the bQuery Trusted Types policy.\r\n * @returns The Trusted Types policy or null if unsupported\r\n */\r\nexport const getTrustedTypesPolicy = (): TrustedTypePolicy | null => {\r\n if (cachedPolicy) return cachedPolicy;\r\n\r\n const win = window as TrustedTypesWindow;\r\n if (!win.trustedTypes) return null;\r\n\r\n try {\r\n cachedPolicy = win.trustedTypes.createPolicy(POLICY_NAME, {\r\n createHTML: (input: string) => sanitizeHtmlCore(input),\r\n });\r\n return cachedPolicy;\r\n } catch {\r\n // Policy may already exist or be blocked by CSP\r\n console.warn(`bQuery: Could not create Trusted Types policy \"${POLICY_NAME}\"`);\r\n return null;\r\n }\r\n};\r\n\r\n// ============================================================================\r\n// Default Safe Lists\r\n// ============================================================================\r\n\r\n/**\r\n * Default allowed HTML tags considered safe.\r\n */\r\nconst DEFAULT_ALLOWED_TAGS = new Set([\r\n 'a',\r\n 'abbr',\r\n 'address',\r\n 'article',\r\n 'aside',\r\n 'b',\r\n 'bdi',\r\n 'bdo',\r\n 'blockquote',\r\n 'br',\r\n 'button',\r\n 'caption',\r\n 'cite',\r\n 'code',\r\n 'col',\r\n 'colgroup',\r\n 'data',\r\n 'dd',\r\n 'del',\r\n 'details',\r\n 'dfn',\r\n 'div',\r\n 'dl',\r\n 'dt',\r\n 'em',\r\n 'figcaption',\r\n 'figure',\r\n 'footer',\r\n 'form',\r\n 'h1',\r\n 'h2',\r\n 'h3',\r\n 'h4',\r\n 'h5',\r\n 'h6',\r\n 'header',\r\n 'hgroup',\r\n 'hr',\r\n 'i',\r\n 'img',\r\n 'input',\r\n 'ins',\r\n 'kbd',\r\n 'label',\r\n 'legend',\r\n 'li',\r\n 'main',\r\n 'mark',\r\n 'nav',\r\n 'ol',\r\n 'optgroup',\r\n 'option',\r\n 'p',\r\n 'picture',\r\n 'pre',\r\n 'progress',\r\n 'q',\r\n 'rp',\r\n 'rt',\r\n 'ruby',\r\n 's',\r\n 'samp',\r\n 'section',\r\n 'select',\r\n 'small',\r\n 'source',\r\n 'span',\r\n 'strong',\r\n 'sub',\r\n 'summary',\r\n 'sup',\r\n 'table',\r\n 'tbody',\r\n 'td',\r\n 'textarea',\r\n 'tfoot',\r\n 'th',\r\n 'thead',\r\n 'time',\r\n 'tr',\r\n 'u',\r\n 'ul',\r\n 'var',\r\n 'wbr',\r\n]);\r\n\r\n/**\r\n * Explicitly dangerous tags that should never be allowed.\r\n * These are checked even if somehow added to allowTags.\r\n */\r\nconst DANGEROUS_TAGS = new Set([\r\n 'script',\r\n 'iframe',\r\n 'frame',\r\n 'frameset',\r\n 'object',\r\n 'embed',\r\n 'applet',\r\n 'link',\r\n 'meta',\r\n 'style',\r\n 'base',\r\n 'template',\r\n 'slot',\r\n 'math',\r\n 'svg',\r\n 'foreignobject',\r\n 'noscript',\r\n]);\r\n\r\n/**\r\n * Reserved IDs that could cause DOM clobbering attacks.\r\n * These are prevented to avoid overwriting global browser objects.\r\n */\r\nconst RESERVED_IDS = new Set([\r\n // Global objects\r\n 'document',\r\n 'window',\r\n 'location',\r\n 'top',\r\n 'self',\r\n 'parent',\r\n 'frames',\r\n 'history',\r\n 'navigator',\r\n 'screen',\r\n // Dangerous functions\r\n 'alert',\r\n 'confirm',\r\n 'prompt',\r\n 'eval',\r\n 'Function',\r\n // Document properties\r\n 'cookie',\r\n 'domain',\r\n 'referrer',\r\n 'body',\r\n 'head',\r\n 'forms',\r\n 'images',\r\n 'links',\r\n 'scripts',\r\n // DOM traversal properties\r\n 'children',\r\n 'parentNode',\r\n 'firstChild',\r\n 'lastChild',\r\n // Content manipulation\r\n 'innerHTML',\r\n 'outerHTML',\r\n 'textContent',\r\n]);\r\n\r\n/**\r\n * Default allowed attributes considered safe.\r\n */\r\nconst DEFAULT_ALLOWED_ATTRIBUTES = new Set([\r\n 'alt',\r\n 'class',\r\n 'dir',\r\n 'height',\r\n 'hidden',\r\n 'href',\r\n 'id',\r\n 'lang',\r\n 'loading',\r\n 'name',\r\n 'rel',\r\n 'role',\r\n 'src',\r\n 'srcset',\r\n 'style',\r\n 'tabindex',\r\n 'target',\r\n 'title',\r\n 'type',\r\n 'width',\r\n 'aria-*',\r\n]);\r\n\r\n/**\r\n * Dangerous attribute prefixes to always remove.\r\n */\r\nconst DANGEROUS_ATTR_PREFIXES = ['on', 'formaction', 'xlink:', 'xmlns:'];\r\n\r\n/**\r\n * Dangerous URL protocols to block.\r\n */\r\nconst DANGEROUS_PROTOCOLS = ['javascript:', 'data:', 'vbscript:', 'file:'];\r\n\r\n// ============================================================================\r\n// Core Sanitization\r\n// ============================================================================\r\n\r\n/**\r\n * Check if an attribute name is allowed.\r\n * @internal\r\n */\r\nconst isAllowedAttribute = (\r\n name: string,\r\n allowedSet: Set<string>,\r\n allowDataAttrs: boolean\r\n): boolean => {\r\n const lowerName = name.toLowerCase();\r\n\r\n // Check dangerous prefixes\r\n for (const prefix of DANGEROUS_ATTR_PREFIXES) {\r\n if (lowerName.startsWith(prefix)) return false;\r\n }\r\n\r\n // Check data attributes\r\n if (allowDataAttrs && lowerName.startsWith('data-')) return true;\r\n\r\n // Check aria attributes (allowed by default)\r\n if (lowerName.startsWith('aria-')) return true;\r\n\r\n // Check explicit allow list\r\n return allowedSet.has(lowerName);\r\n};\r\n\r\n/**\r\n * Check if an ID/name value could cause DOM clobbering.\r\n * @internal\r\n */\r\nconst isSafeIdOrName = (value: string): boolean => {\r\n const lowerValue = value.toLowerCase().trim();\r\n return !RESERVED_IDS.has(lowerValue);\r\n};\r\n\r\n/**\r\n * Normalize URL by removing control characters, whitespace, and Unicode tricks.\r\n * Enhanced to prevent various bypass techniques.\r\n * @internal\r\n */\r\nconst normalizeUrl = (value: string): string =>\r\n value\r\n // Remove null bytes and control characters\r\n .replace(/[\\u0000-\\u001F\\u007F]+/g, '')\r\n // Remove zero-width characters that could hide malicious content\r\n .replace(/[\\u200B-\\u200D\\uFEFF\\u2028\\u2029]+/g, '')\r\n // Remove escaped Unicode sequences\r\n .replace(/\\\\u[\\da-fA-F]{4}/g, '')\r\n // Remove whitespace\r\n .replace(/\\s+/g, '')\r\n // Normalize case\r\n .toLowerCase();\r\n\r\n/**\r\n * Check if a URL value is safe.\r\n * @internal\r\n */\r\nconst isSafeUrl = (value: string): boolean => {\r\n const normalized = normalizeUrl(value);\r\n for (const protocol of DANGEROUS_PROTOCOLS) {\r\n if (normalized.startsWith(protocol)) return false;\r\n }\r\n return true;\r\n};\r\n\r\n/**\r\n * Check if a URL is external (different origin).\r\n * @internal\r\n */\r\nconst isExternalUrl = (url: string): boolean => {\r\n try {\r\n // Normalize URL by trimming whitespace\r\n const trimmedUrl = url.trim();\r\n \r\n // Protocol-relative URLs (//example.com) are always external.\r\n // CRITICAL: This check must run before the relative-URL check below;\r\n // otherwise, a protocol-relative URL like \"//evil.com\" would be treated\r\n // as a non-http(s) relative URL and incorrectly classified as same-origin.\r\n // Handling them up front guarantees correct security classification.\r\n if (trimmedUrl.startsWith('//')) {\r\n return true;\r\n }\r\n \r\n // Normalize URL for case-insensitive protocol checks\r\n const lowerUrl = trimmedUrl.toLowerCase();\r\n \r\n // Check for non-http(s) protocols which are considered external/special\r\n // (mailto:, tel:, ftp:, etc.)\r\n const hasProtocol = /^[a-z][a-z0-9+.-]*:/i.test(trimmedUrl);\r\n if (hasProtocol && !lowerUrl.startsWith('http://') && !lowerUrl.startsWith('https://')) {\r\n // These are special protocols, not traditional \"external\" links\r\n // but we treat them as external for security consistency\r\n return true;\r\n }\r\n \r\n // Relative URLs are not external\r\n if (!lowerUrl.startsWith('http://') && !lowerUrl.startsWith('https://')) {\r\n return false;\r\n }\r\n \r\n // In non-browser environments (e.g., Node.js), treat all absolute URLs as external\r\n if (typeof window === 'undefined' || !window.location) {\r\n return true;\r\n }\r\n \r\n const urlObj = new URL(trimmedUrl, window.location.href);\r\n return urlObj.origin !== window.location.origin;\r\n } catch {\r\n // If URL parsing fails, treat as potentially external for safety\r\n return true;\r\n }\r\n};\r\n\r\n/**\r\n * Core sanitization logic (without Trusted Types wrapper).\r\n * @internal\r\n */\r\nconst sanitizeHtmlCore = (html: string, options: SanitizeOptions = {}): string => {\r\n const {\r\n allowTags = [],\r\n allowAttributes = [],\r\n allowDataAttributes = true,\r\n stripAllTags = false,\r\n } = options;\r\n\r\n // Build combined allow sets (excluding dangerous tags even if specified)\r\n const allowedTags = new Set(\r\n [...DEFAULT_ALLOWED_TAGS, ...allowTags.map((t) => t.toLowerCase())].filter(\r\n (tag) => !DANGEROUS_TAGS.has(tag)\r\n )\r\n );\r\n const allowedAttrs = new Set([\r\n ...DEFAULT_ALLOWED_ATTRIBUTES,\r\n ...allowAttributes.map((a) => a.toLowerCase()),\r\n ]);\r\n\r\n // Use template for parsing\r\n const template = document.createElement('template');\r\n template.innerHTML = html;\r\n\r\n if (stripAllTags) {\r\n return template.content.textContent ?? '';\r\n }\r\n\r\n // Walk the DOM tree\r\n const walker = document.createTreeWalker(template.content, NodeFilter.SHOW_ELEMENT);\r\n\r\n const toRemove: Element[] = [];\r\n\r\n while (walker.nextNode()) {\r\n const el = walker.currentNode as Element;\r\n const tagName = el.tagName.toLowerCase();\r\n\r\n // Remove explicitly dangerous tags even if in allow list\r\n if (DANGEROUS_TAGS.has(tagName)) {\r\n toRemove.push(el);\r\n continue;\r\n }\r\n\r\n // Remove disallowed tags entirely\r\n if (!allowedTags.has(tagName)) {\r\n toRemove.push(el);\r\n continue;\r\n }\r\n\r\n // Process attributes\r\n const attrsToRemove: string[] = [];\r\n for (const attr of Array.from(el.attributes)) {\r\n const attrName = attr.name.toLowerCase();\r\n\r\n // Check if attribute is allowed\r\n if (!isAllowedAttribute(attrName, allowedAttrs, allowDataAttributes)) {\r\n attrsToRemove.push(attr.name);\r\n continue;\r\n }\r\n\r\n // Check for DOM clobbering on id and name attributes\r\n if ((attrName === 'id' || attrName === 'name') && !isSafeIdOrName(attr.value)) {\r\n attrsToRemove.push(attr.name);\r\n continue;\r\n }\r\n\r\n // Validate URL attributes\r\n if (\r\n (attrName === 'href' || attrName === 'src' || attrName === 'srcset') &&\r\n !isSafeUrl(attr.value)\r\n ) {\r\n attrsToRemove.push(attr.name);\r\n }\r\n }\r\n\r\n // Remove disallowed attributes\r\n for (const attrName of attrsToRemove) {\r\n el.removeAttribute(attrName);\r\n }\r\n\r\n // Add rel=\"noopener noreferrer\" to external links for security\r\n if (tagName === 'a') {\r\n const href = el.getAttribute('href');\r\n const target = el.getAttribute('target');\r\n const hasTargetBlank = target?.toLowerCase() === '_blank';\r\n const isExternal = href && isExternalUrl(href);\r\n\r\n // Add security attributes to links opening in new window or external links\r\n if (hasTargetBlank || isExternal) {\r\n const existingRel = el.getAttribute('rel');\r\n const relValues = new Set(\r\n existingRel ? existingRel.split(/\\s+/).filter(Boolean) : []\r\n );\r\n \r\n // Add noopener and noreferrer\r\n relValues.add('noopener');\r\n relValues.add('noreferrer');\r\n \r\n el.setAttribute('rel', Array.from(relValues).join(' '));\r\n }\r\n }\r\n }\r\n\r\n // Remove disallowed elements\r\n for (const el of toRemove) {\r\n el.remove();\r\n }\r\n\r\n return template.innerHTML;\r\n};\r\n\r\n// ============================================================================\r\n// Public API\r\n// ============================================================================\r\n\r\n/**\r\n * Sanitize HTML string, removing dangerous elements and attributes.\r\n * Uses Trusted Types when available for CSP compliance.\r\n *\r\n * @param html - The HTML string to sanitize\r\n * @param options - Sanitization options\r\n * @returns Sanitized HTML string\r\n *\r\n * @example\r\n * ```ts\r\n * const safe = sanitizeHtml('<div onclick=\"alert(1)\">Hello</div>');\r\n * // Returns: '<div>Hello</div>'\r\n * ```\r\n */\r\nexport const sanitizeHtml = (html: string, options: SanitizeOptions = {}): string => {\r\n return sanitizeHtmlCore(html, options);\r\n};\r\n\r\n/**\r\n * Create a Trusted HTML value for use with Trusted Types-enabled sites.\r\n * Falls back to regular string when Trusted Types are unavailable.\r\n *\r\n * @param html - The HTML string to wrap\r\n * @returns Trusted HTML value or sanitized string\r\n */\r\nexport const createTrustedHtml = (html: string): TrustedHTML | string => {\r\n const policy = getTrustedTypesPolicy();\r\n if (policy) {\r\n return policy.createHTML(html);\r\n }\r\n return sanitizeHtml(html);\r\n};\r\n\r\n/**\r\n * Escape HTML entities to prevent XSS.\r\n * Use this for displaying user content as text.\r\n *\r\n * @param text - The text to escape\r\n * @returns Escaped HTML string\r\n *\r\n * @example\r\n * ```ts\r\n * escapeHtml('<script>alert(1)</script>');\r\n * // Returns: '<script>alert(1)</script>'\r\n * ```\r\n */\r\nexport const escapeHtml = (text: string): string => {\r\n const escapeMap: Record<string, string> = {\r\n '&': '&',\r\n '<': '<',\r\n '>': '>',\r\n '\"': '"',\r\n \"'\": ''',\r\n '`': '`',\r\n };\r\n return text.replace(/[&<>\"'`]/g, (char) => escapeMap[char]);\r\n};\r\n\r\n/**\r\n * Strip all HTML tags and return plain text.\r\n *\r\n * @param html - The HTML string to strip\r\n * @returns Plain text content\r\n */\r\nexport const stripTags = (html: string): string => {\r\n return sanitizeHtmlCore(html, { stripAllTags: true });\r\n};\r\n\r\n// ============================================================================\r\n// CSP Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Generate a nonce for inline scripts/styles.\r\n * Use with Content-Security-Policy nonce directives.\r\n *\r\n * @param length - Nonce length (default: 16)\r\n * @returns Cryptographically random nonce string\r\n */\r\nexport const generateNonce = (length: number = 16): string => {\r\n const array = new Uint8Array(length);\r\n crypto.getRandomValues(array);\r\n return btoa(String.fromCharCode(...array))\r\n .replace(/\\+/g, '-')\r\n .replace(/\\//g, '_')\r\n .replace(/=/g, '');\r\n};\r\n\r\n/**\r\n * Check if a CSP header is present with specific directive.\r\n * Useful for feature detection and fallback strategies.\r\n *\r\n * @param directive - The CSP directive to check (e.g., 'script-src')\r\n * @returns True if the directive appears to be enforced\r\n */\r\nexport const hasCSPDirective = (directive: string): boolean => {\r\n // Check meta tag\r\n const meta = document.querySelector('meta[http-equiv=\"Content-Security-Policy\"]');\r\n if (meta) {\r\n const content = meta.getAttribute('content') ?? '';\r\n return content.includes(directive);\r\n }\r\n return false;\r\n};\r\n","/**\n * Shared helpers for element wrappers.\n */\nexport type ElementList = Element[];\n\nexport const toElementList = (input: Element | ElementList): ElementList =>\n Array.isArray(input) ? input : [input];\n\nexport const applyAll = (elements: ElementList, action: (el: Element) => void) => {\n for (const el of elements) {\n action(el);\n }\n};\n","import { sanitizeHtml } from '../security/sanitize';\r\nimport { applyAll, toElementList } from './shared';\r\n\r\n/**\r\n * Wrapper for a single DOM element.\r\n * Provides a chainable, jQuery-like API for DOM manipulation.\r\n *\r\n * This class encapsulates a DOM element and provides methods for:\r\n * - Class manipulation (addClass, removeClass, toggleClass)\r\n * - Attribute and property access (attr, prop, data)\r\n * - Content manipulation (text, html, append, prepend)\r\n * - Style manipulation (css)\r\n * - Event handling (on, off, once, trigger)\r\n * - DOM traversal (find, closest, parent, children, siblings)\r\n *\r\n * All mutating methods return `this` for method chaining.\r\n *\r\n * @example\r\n * ```ts\r\n * $('#button')\r\n * .addClass('active')\r\n * .css({ color: 'blue' })\r\n * .on('click', () => console.log('clicked'));\r\n * ```\r\n */\r\n/** Handler signature for delegated events */\r\ntype DelegatedHandler = (event: Event, target: Element) => void;\r\n\r\nexport class BQueryElement {\r\n /**\r\n * Stores delegated event handlers for cleanup via undelegate().\r\n * Key format: `${event}:${selector}`\r\n * @internal\r\n */\r\n private readonly delegatedHandlers = new Map<string, Map<DelegatedHandler, EventListener>>();\r\n\r\n /**\r\n * Creates a new BQueryElement wrapper.\r\n * @param element - The DOM element to wrap\r\n */\r\n constructor(private readonly element: Element) {}\r\n\r\n /**\r\n * Exposes the raw DOM element when direct access is needed.\r\n * Use sparingly; prefer the wrapper methods for consistency.\r\n */\r\n get raw(): Element {\r\n return this.element;\r\n }\r\n\r\n /**\r\n * Exposes the underlying DOM element.\r\n * Provided for spec compatibility and read-only access.\r\n */\r\n get node(): Element {\r\n return this.element;\r\n }\r\n\r\n /** Add one or more classes. */\r\n addClass(...classNames: string[]): this {\r\n this.element.classList.add(...classNames);\r\n return this;\r\n }\r\n\r\n /** Remove one or more classes. */\r\n removeClass(...classNames: string[]): this {\r\n this.element.classList.remove(...classNames);\r\n return this;\r\n }\r\n\r\n /** Toggle a class by name. */\r\n toggleClass(className: string, force?: boolean): this {\r\n this.element.classList.toggle(className, force);\r\n return this;\r\n }\r\n\r\n /** Get or set an attribute. */\r\n attr(name: string, value?: string): string | this {\r\n if (value === undefined) {\r\n return this.element.getAttribute(name) ?? '';\r\n }\r\n this.element.setAttribute(name, value);\r\n return this;\r\n }\r\n\r\n /** Get or set a property. */\r\n prop<T extends keyof Element>(name: T, value?: Element[T]): Element[T] | this {\r\n if (value === undefined) {\r\n return this.element[name];\r\n }\r\n this.element[name] = value;\r\n return this;\r\n }\r\n\r\n /** Read or write data attributes in camelCase. */\r\n data(name: string, value?: string): string | this {\r\n const key = name.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);\r\n if (value === undefined) {\r\n return this.element.getAttribute(`data-${key}`) ?? '';\r\n }\r\n this.element.setAttribute(`data-${key}`, value);\r\n return this;\r\n }\r\n\r\n /** Get or set text content. */\r\n text(value?: string): string | this {\r\n if (value === undefined) {\r\n return this.element.textContent ?? '';\r\n }\r\n this.element.textContent = value;\r\n return this;\r\n }\r\n\r\n /** Set HTML content using a sanitized string. */\r\n /**\r\n * Sets sanitized HTML content on the element.\r\n * Uses the security module to sanitize input and prevent XSS attacks.\r\n *\r\n * @param value - The HTML string to set (will be sanitized)\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * $('#content').html('<strong>Hello</strong>');\r\n * ```\r\n */\r\n html(value: string): this {\r\n this.element.innerHTML = sanitizeHtml(value);\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets HTML content without sanitization.\r\n * Use only when you trust the HTML source completely.\r\n *\r\n * @param value - The raw HTML string to set\r\n * @returns The instance for method chaining\r\n *\r\n * @warning This method bypasses XSS protection. Use with caution.\r\n */\r\n htmlUnsafe(value: string): this {\r\n this.element.innerHTML = value;\r\n return this;\r\n }\r\n\r\n /**\r\n * Gets or sets CSS styles on the element.\r\n *\r\n * @param property - A CSS property name or an object of property-value pairs\r\n * @param value - The value when setting a single property\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * // Single property\r\n * $('#box').css('color', 'red');\r\n *\r\n * // Multiple properties\r\n * $('#box').css({ color: 'red', 'font-size': '16px' });\r\n * ```\r\n */\r\n css(property: string | Record<string, string>, value?: string): this {\r\n if (typeof property === 'string') {\r\n if (value !== undefined) {\r\n (this.element as HTMLElement).style.setProperty(property, value);\r\n }\r\n return this;\r\n }\r\n\r\n for (const [key, val] of Object.entries(property)) {\r\n (this.element as HTMLElement).style.setProperty(key, val);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Appends HTML or elements to the end of the element.\r\n *\r\n * @param content - HTML string or element(s) to append\r\n * @returns The instance for method chaining\r\n */\r\n append(content: string | Element | Element[]): this {\r\n this.insertContent(content, 'beforeend');\r\n return this;\r\n }\r\n\r\n /**\r\n * Prepends HTML or elements to the beginning of the element.\r\n *\r\n * @param content - HTML string or element(s) to prepend\r\n * @returns The instance for method chaining\r\n */\r\n prepend(content: string | Element | Element[]): this {\r\n this.insertContent(content, 'afterbegin');\r\n return this;\r\n }\r\n\r\n /**\r\n * Inserts content before this element.\r\n *\r\n * @param content - HTML string or element(s) to insert\r\n * @returns The instance for method chaining\r\n */\r\n before(content: string | Element | Element[]): this {\r\n this.insertContent(content, 'beforebegin');\r\n return this;\r\n }\r\n\r\n /**\r\n * Inserts content after this element.\r\n *\r\n * @param content - HTML string or element(s) to insert\r\n * @returns The instance for method chaining\r\n */\r\n after(content: string | Element | Element[]): this {\r\n this.insertContent(content, 'afterend');\r\n return this;\r\n }\r\n\r\n /**\r\n * Wraps the element with the specified wrapper element or tag.\r\n *\r\n * @param wrapper - Tag name string or Element to wrap with\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * $('#content').wrap('div'); // Wraps with <div>\r\n * $('#content').wrap(document.createElement('section'));\r\n * ```\r\n */\r\n wrap(wrapper: string | Element): this {\r\n const wrapperEl = typeof wrapper === 'string' ? document.createElement(wrapper) : wrapper;\r\n this.element.parentNode?.insertBefore(wrapperEl, this.element);\r\n wrapperEl.appendChild(this.element);\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes the parent element, keeping this element in its place.\r\n * Essentially the opposite of wrap().\r\n *\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * // Before: <div><span id=\"text\">Hello</span></div>\r\n * $('#text').unwrap();\r\n * // After: <span id=\"text\">Hello</span>\r\n * ```\r\n */\r\n unwrap(): this {\r\n const parent = this.element.parentElement;\r\n if (parent && parent.parentNode) {\r\n parent.parentNode.insertBefore(this.element, parent);\r\n parent.remove();\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Replaces this element with new content.\r\n *\r\n * @param content - HTML string (sanitized) or Element to replace with\r\n * @returns A new BQueryElement wrapping the replacement element\r\n *\r\n * @example\r\n * ```ts\r\n * const newEl = $('#old').replaceWith('<div id=\"new\">Replaced</div>');\r\n * ```\r\n */\r\n replaceWith(content: string | Element): BQueryElement {\r\n let newEl: Element;\r\n if (typeof content === 'string') {\r\n const template = document.createElement('template');\r\n template.innerHTML = sanitizeHtml(content);\r\n newEl = template.content.firstElementChild ?? document.createElement('div');\r\n } else {\r\n newEl = content;\r\n }\r\n this.element.replaceWith(newEl);\r\n return new BQueryElement(newEl);\r\n }\r\n\r\n /**\r\n * Scrolls the element into view with configurable behavior.\r\n *\r\n * @param options - ScrollIntoView options or boolean for legacy behavior\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * $('#section').scrollTo(); // Smooth scroll\r\n * $('#section').scrollTo({ behavior: 'instant', block: 'start' });\r\n * ```\r\n */\r\n scrollTo(options: ScrollIntoViewOptions | boolean = { behavior: 'smooth' }): this {\r\n this.element.scrollIntoView(options);\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes the element from the DOM.\r\n *\r\n * @returns The instance for method chaining (though element is now detached)\r\n */\r\n remove(): this {\r\n this.element.remove();\r\n return this;\r\n }\r\n\r\n /**\r\n * Clears all child nodes from the element.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n empty(): this {\r\n this.element.innerHTML = '';\r\n return this;\r\n }\r\n\r\n /**\r\n * Clones the element, optionally with all descendants.\r\n *\r\n * @param deep - If true, clone all descendants (default: true)\r\n * @returns A new BQueryElement wrapping the cloned element\r\n */\r\n clone(deep: boolean = true): BQueryElement {\r\n return new BQueryElement(this.element.cloneNode(deep) as Element);\r\n }\r\n\r\n /**\r\n * Finds all descendant elements matching the selector.\r\n *\r\n * @param selector - CSS selector to match\r\n * @returns Array of matching elements\r\n */\r\n find(selector: string): Element[] {\r\n return Array.from(this.element.querySelectorAll(selector));\r\n }\r\n\r\n /**\r\n * Finds the first descendant element matching the selector.\r\n *\r\n * @param selector - CSS selector to match\r\n * @returns The first matching element or null\r\n */\r\n findOne(selector: string): Element | null {\r\n return this.element.querySelector(selector);\r\n }\r\n\r\n /**\r\n * Finds the closest ancestor matching the selector.\r\n *\r\n * @param selector - CSS selector to match\r\n * @returns The matching ancestor or null\r\n */\r\n closest(selector: string): Element | null {\r\n return this.element.closest(selector);\r\n }\r\n\r\n /**\r\n * Gets the parent element.\r\n *\r\n * @returns The parent element or null\r\n */\r\n parent(): Element | null {\r\n return this.element.parentElement;\r\n }\r\n\r\n /**\r\n * Gets all child elements.\r\n *\r\n * @returns Array of child elements\r\n */\r\n children(): Element[] {\r\n return Array.from(this.element.children);\r\n }\r\n\r\n /**\r\n * Gets all sibling elements.\r\n *\r\n * @returns Array of sibling elements (excluding this element)\r\n */\r\n siblings(): Element[] {\r\n const parent = this.element.parentElement;\r\n if (!parent) return [];\r\n return Array.from(parent.children).filter((child) => child !== this.element);\r\n }\r\n\r\n /**\r\n * Gets the next sibling element.\r\n *\r\n * @returns The next sibling element or null\r\n */\r\n next(): Element | null {\r\n return this.element.nextElementSibling;\r\n }\r\n\r\n /**\r\n * Gets the previous sibling element.\r\n *\r\n * @returns The previous sibling element or null\r\n */\r\n prev(): Element | null {\r\n return this.element.previousElementSibling;\r\n }\r\n\r\n /**\r\n * Adds an event listener.\r\n *\r\n * @param event - Event type to listen for\r\n * @param handler - Event handler function\r\n * @returns The instance for method chaining\r\n */\r\n on(event: string, handler: EventListenerOrEventListenerObject): this {\r\n this.element.addEventListener(event, handler);\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a one-time event listener that removes itself after firing.\r\n *\r\n * @param event - Event type to listen for\r\n * @param handler - Event handler function\r\n * @returns The instance for method chaining\r\n */\r\n once(event: string, handler: EventListener): this {\r\n this.element.addEventListener(event, handler, { once: true });\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes an event listener.\r\n *\r\n * @param event - Event type\r\n * @param handler - The handler to remove\r\n * @returns The instance for method chaining\r\n */\r\n off(event: string, handler: EventListenerOrEventListenerObject): this {\r\n this.element.removeEventListener(event, handler);\r\n return this;\r\n }\r\n\r\n /**\r\n * Triggers a custom event on the element.\r\n *\r\n * @param event - Event type to trigger\r\n * @param detail - Optional detail data to include with the event\r\n * @returns The instance for method chaining\r\n */\r\n trigger(event: string, detail?: unknown): this {\r\n this.element.dispatchEvent(new CustomEvent(event, { detail, bubbles: true, cancelable: true }));\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a delegated event listener that only triggers for matching descendants.\r\n * More efficient than adding listeners to many elements individually.\r\n *\r\n * Use `undelegate()` to remove the listener later.\r\n *\r\n * @param event - Event type to listen for\r\n * @param selector - CSS selector to match against event targets\r\n * @param handler - Event handler function, receives the matched element as context\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * // Instead of adding listeners to each button:\r\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\r\n * $('#list').delegate('click', '.item', handler);\r\n *\r\n * // Later, remove the delegated listener:\r\n * $('#list').undelegate('click', '.item', handler);\r\n * ```\r\n */\r\n delegate(\r\n event: string,\r\n selector: string,\r\n handler: (event: Event, target: Element) => void\r\n ): this {\r\n const key = `${event}:${selector}`;\r\n const wrapper: EventListener = (e: Event) => {\r\n const target = (e.target as Element).closest(selector);\r\n if (target && this.element.contains(target)) {\r\n handler(e, target);\r\n }\r\n };\r\n\r\n // Store the wrapper so it can be removed later\r\n if (!this.delegatedHandlers.has(key)) {\r\n this.delegatedHandlers.set(key, new Map());\r\n }\r\n this.delegatedHandlers.get(key)!.set(handler, wrapper);\r\n\r\n this.element.addEventListener(event, wrapper);\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes a delegated event listener previously added with `delegate()`.\r\n *\r\n * @param event - Event type that was registered\r\n * @param selector - CSS selector that was used\r\n * @param handler - The original handler function passed to delegate()\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\r\n * $('#list').delegate('click', '.item', handler);\r\n *\r\n * // Remove the delegated listener:\r\n * $('#list').undelegate('click', '.item', handler);\r\n * ```\r\n */\r\n undelegate(\r\n event: string,\r\n selector: string,\r\n handler: (event: Event, target: Element) => void\r\n ): this {\r\n const key = `${event}:${selector}`;\r\n const handlers = this.delegatedHandlers.get(key);\r\n\r\n if (handlers) {\r\n const wrapper = handlers.get(handler);\r\n if (wrapper) {\r\n this.element.removeEventListener(event, wrapper);\r\n handlers.delete(handler);\r\n\r\n // Clean up empty maps\r\n if (handlers.size === 0) {\r\n this.delegatedHandlers.delete(key);\r\n }\r\n }\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Checks if the element matches a CSS selector.\r\n *\r\n * @param selector - CSS selector to match against\r\n * @returns True if the element matches the selector\r\n */\r\n matches(selector: string): boolean {\r\n return this.element.matches(selector);\r\n }\r\n\r\n /**\r\n * Checks if the element has a specific class.\r\n *\r\n * @param className - Class name to check\r\n * @returns True if the element has the class\r\n */\r\n hasClass(className: string): boolean {\r\n return this.element.classList.contains(className);\r\n }\r\n\r\n /**\r\n * Shows the element by removing the hidden attribute and setting display.\r\n *\r\n * @param display - Optional display value (default: '')\r\n * @returns The instance for method chaining\r\n */\r\n show(display: string = ''): this {\r\n this.element.removeAttribute('hidden');\r\n (this.element as HTMLElement).style.display = display;\r\n return this;\r\n }\r\n\r\n /**\r\n * Hides the element by setting display to 'none'.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n hide(): this {\r\n (this.element as HTMLElement).style.display = 'none';\r\n return this;\r\n }\r\n\r\n /**\r\n * Toggles the visibility of the element.\r\n *\r\n * @param force - Optional force show (true) or hide (false)\r\n * @returns The instance for method chaining\r\n */\r\n toggle(force?: boolean): this {\r\n const isHidden = (this.element as HTMLElement).style.display === 'none';\r\n const shouldShow = force ?? isHidden;\r\n return shouldShow ? this.show() : this.hide();\r\n }\r\n\r\n /**\r\n * Focuses the element.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n focus(): this {\r\n (this.element as HTMLElement).focus();\r\n return this;\r\n }\r\n\r\n /**\r\n * Blurs (unfocuses) the element.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n blur(): this {\r\n (this.element as HTMLElement).blur();\r\n return this;\r\n }\r\n\r\n /**\r\n * Gets or sets the value of form elements.\r\n *\r\n * @param newValue - Optional value to set\r\n * @returns The current value when getting, or the instance when setting\r\n */\r\n val(newValue?: string): string | this {\r\n const input = this.element as HTMLInputElement;\r\n if (newValue === undefined) {\r\n return input.value ?? '';\r\n }\r\n input.value = newValue;\r\n return this;\r\n }\r\n\r\n /**\r\n * Serializes form data to a plain object.\r\n * Only works on form elements; returns empty object for non-forms.\r\n *\r\n * @returns Object with form field names as keys and values\r\n *\r\n * @example\r\n * ```ts\r\n * // For a form with <input name=\"email\" value=\"test@example.com\">\r\n * const data = $('#myForm').serialize();\r\n * // { email: 'test@example.com' }\r\n * ```\r\n */\r\n serialize(): Record<string, string | string[]> {\r\n const form = this.element as HTMLFormElement;\r\n if (form.tagName.toLowerCase() !== 'form') {\r\n return {};\r\n }\r\n\r\n const result: Record<string, string | string[]> = {};\r\n const formData = new FormData(form);\r\n\r\n for (const [key, value] of formData.entries()) {\r\n if (typeof value !== 'string') continue; // Skip File objects\r\n\r\n if (key in result) {\r\n // Handle multiple values (e.g., checkboxes)\r\n const existing = result[key];\r\n if (Array.isArray(existing)) {\r\n existing.push(value);\r\n } else {\r\n result[key] = [existing, value];\r\n }\r\n } else {\r\n result[key] = value;\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Serializes form data to a URL-encoded query string.\r\n *\r\n * @returns URL-encoded string suitable for form submission\r\n *\r\n * @example\r\n * ```ts\r\n * const queryString = $('#myForm').serializeString();\r\n * // 'email=test%40example.com&name=John'\r\n * ```\r\n */\r\n serializeString(): string {\r\n const form = this.element as HTMLFormElement;\r\n if (form.tagName.toLowerCase() !== 'form') {\r\n return '';\r\n }\r\n\r\n const formData = new FormData(form);\r\n const params = new URLSearchParams();\r\n\r\n for (const [key, value] of formData.entries()) {\r\n if (typeof value === 'string') {\r\n params.append(key, value);\r\n }\r\n }\r\n\r\n return params.toString();\r\n }\r\n\r\n /**\r\n * Gets the bounding client rectangle of the element.\r\n *\r\n * @returns The element's bounding rectangle\r\n */\r\n rect(): DOMRect {\r\n return this.element.getBoundingClientRect();\r\n }\r\n\r\n /**\r\n * Gets the offset dimensions (width, height, top, left).\r\n *\r\n * @returns Object with offset dimensions\r\n */\r\n offset(): { width: number; height: number; top: number; left: number } {\r\n const el = this.element as HTMLElement;\r\n return {\r\n width: el.offsetWidth,\r\n height: el.offsetHeight,\r\n top: el.offsetTop,\r\n left: el.offsetLeft,\r\n };\r\n }\r\n\r\n /**\r\n * Internal method to insert content at a specified position.\r\n * @internal\r\n */\r\n private insertContent(content: string | Element | Element[], position: InsertPosition) {\r\n if (typeof content === 'string') {\r\n this.element.insertAdjacentHTML(position, sanitizeHtml(content));\r\n return;\r\n }\r\n\r\n const elements = toElementList(content);\r\n applyAll(elements, (el) => {\r\n this.element.insertAdjacentElement(position, el);\r\n });\r\n }\r\n}\r\n","import { sanitizeHtml } from '../security/sanitize';\r\nimport { BQueryElement } from './element';\r\nimport { applyAll } from './shared';\r\n\r\n/** Handler signature for delegated events */\r\ntype DelegatedHandler = (event: Event, target: Element) => void;\r\n\r\n/**\r\n * Wrapper for multiple DOM elements.\r\n * Provides batch operations on a collection of elements with chainable API.\r\n *\r\n * This class enables jQuery-like operations across multiple elements:\r\n * - All mutating methods apply to every element in the collection\r\n * - Getter methods return data from the first element\r\n * - Supports iteration via forEach, map, filter, and reduce\r\n *\r\n * @example\r\n * ```ts\r\n * $$('.items')\r\n * .addClass('highlight')\r\n * .css({ opacity: '0.8' })\r\n * .on('click', () => console.log('clicked'));\r\n * ```\r\n */\r\nexport class BQueryCollection {\r\n /**\r\n * Stores delegated event handlers for cleanup via undelegate().\r\n * Outer map: element -> (key -> (handler -> wrapper))\r\n * Key format: `${event}:${selector}`\r\n * @internal\r\n */\r\n private readonly delegatedHandlers = new WeakMap<\r\n Element,\r\n Map<string, Map<DelegatedHandler, EventListener>>\r\n >();\r\n\r\n /**\r\n * Creates a new collection wrapper.\r\n * @param elements - Array of DOM elements to wrap\r\n */\r\n constructor(public readonly elements: Element[]) {}\r\n\r\n /**\r\n * Gets the number of elements in the collection.\r\n */\r\n get length(): number {\r\n return this.elements.length;\r\n }\r\n\r\n /**\r\n * Gets the first element in the collection, if any.\r\n * @internal\r\n */\r\n private first(): Element | undefined {\r\n return this.elements[0];\r\n }\r\n\r\n /**\r\n * Gets a single element as a BQueryElement wrapper.\r\n *\r\n * @param index - Zero-based index of the element\r\n * @returns BQueryElement wrapper or undefined if out of range\r\n */\r\n eq(index: number): BQueryElement | undefined {\r\n const el = this.elements[index];\r\n return el ? new BQueryElement(el) : undefined;\r\n }\r\n\r\n /**\r\n * Gets the first element as a BQueryElement wrapper.\r\n *\r\n * @returns BQueryElement wrapper or undefined if empty\r\n */\r\n firstEl(): BQueryElement | undefined {\r\n return this.eq(0);\r\n }\r\n\r\n /**\r\n * Gets the last element as a BQueryElement wrapper.\r\n *\r\n * @returns BQueryElement wrapper or undefined if empty\r\n */\r\n lastEl(): BQueryElement | undefined {\r\n return this.eq(this.elements.length - 1);\r\n }\r\n\r\n /**\r\n * Iterates over each element in the collection.\r\n *\r\n * @param callback - Function to call for each wrapped element\r\n * @returns The instance for method chaining\r\n */\r\n each(callback: (element: BQueryElement, index: number) => void): this {\r\n this.elements.forEach((element, index) => {\r\n callback(new BQueryElement(element), index);\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Maps each element to a new value.\r\n *\r\n * @param callback - Function to transform each element\r\n * @returns Array of transformed values\r\n */\r\n map<T>(callback: (element: Element, index: number) => T): T[] {\r\n return this.elements.map(callback);\r\n }\r\n\r\n /**\r\n * Filters elements based on a predicate.\r\n *\r\n * @param predicate - Function to test each element\r\n * @returns New BQueryCollection with matching elements\r\n */\r\n filter(predicate: (element: Element, index: number) => boolean): BQueryCollection {\r\n return new BQueryCollection(this.elements.filter(predicate));\r\n }\r\n\r\n /**\r\n * Reduces the collection to a single value.\r\n *\r\n * @param callback - Reducer function\r\n * @param initialValue - Initial accumulator value\r\n * @returns Accumulated result\r\n */\r\n reduce<T>(callback: (accumulator: T, element: Element, index: number) => T, initialValue: T): T {\r\n return this.elements.reduce(callback, initialValue);\r\n }\r\n\r\n /**\r\n * Converts the collection to an array of BQueryElement wrappers.\r\n *\r\n * @returns Array of BQueryElement instances\r\n */\r\n toArray(): BQueryElement[] {\r\n return this.elements.map((el) => new BQueryElement(el));\r\n }\r\n\r\n /** Add one or more classes to all elements. */\r\n addClass(...classNames: string[]): this {\r\n applyAll(this.elements, (el) => el.classList.add(...classNames));\r\n return this;\r\n }\r\n\r\n /** Remove one or more classes from all elements. */\r\n removeClass(...classNames: string[]): this {\r\n applyAll(this.elements, (el) => el.classList.remove(...classNames));\r\n return this;\r\n }\r\n\r\n /** Toggle a class on all elements. */\r\n toggleClass(className: string, force?: boolean): this {\r\n applyAll(this.elements, (el) => el.classList.toggle(className, force));\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets an attribute on all elements or gets from first.\r\n *\r\n * @param name - Attribute name\r\n * @param value - Value to set (optional)\r\n * @returns Attribute value when getting, instance when setting\r\n */\r\n attr(name: string, value?: string): string | this {\r\n if (value === undefined) {\r\n return this.first()?.getAttribute(name) ?? '';\r\n }\r\n applyAll(this.elements, (el) => el.setAttribute(name, value));\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes an attribute from all elements.\r\n *\r\n * @param name - Attribute name to remove\r\n * @returns The instance for method chaining\r\n */\r\n removeAttr(name: string): this {\r\n applyAll(this.elements, (el) => el.removeAttribute(name));\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets text content on all elements or gets from first.\r\n *\r\n * @param value - Text to set (optional)\r\n * @returns Text content when getting, instance when setting\r\n */\r\n text(value?: string): string | this {\r\n if (value === undefined) {\r\n return this.first()?.textContent ?? '';\r\n }\r\n applyAll(this.elements, (el) => {\r\n el.textContent = value;\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets sanitized HTML on all elements or gets from first.\r\n *\r\n * @param value - HTML to set (optional, will be sanitized)\r\n * @returns HTML content when getting, instance when setting\r\n */\r\n html(value?: string): string | this {\r\n if (value === undefined) {\r\n return this.first()?.innerHTML ?? '';\r\n }\r\n const sanitized = sanitizeHtml(value);\r\n applyAll(this.elements, (el) => {\r\n el.innerHTML = sanitized;\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets HTML on all elements without sanitization.\r\n *\r\n * @param value - Raw HTML to set\r\n * @returns The instance for method chaining\r\n * @warning Bypasses XSS protection\r\n */\r\n htmlUnsafe(value: string): this {\r\n applyAll(this.elements, (el) => {\r\n el.innerHTML = value;\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Applies CSS styles to all elements.\r\n *\r\n * @param property - Property name or object of properties\r\n * @param value - Value when setting single property\r\n * @returns The instance for method chaining\r\n */\r\n css(property: string | Record<string, string>, value?: string): this {\r\n if (typeof property === 'string') {\r\n if (value !== undefined) {\r\n applyAll(this.elements, (el) => {\r\n (el as HTMLElement).style.setProperty(property, value);\r\n });\r\n }\r\n return this;\r\n }\r\n\r\n applyAll(this.elements, (el) => {\r\n for (const [key, val] of Object.entries(property)) {\r\n (el as HTMLElement).style.setProperty(key, val);\r\n }\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Shows all elements.\r\n *\r\n * @param display - Optional display value (default: '')\r\n * @returns The instance for method chaining\r\n */\r\n show(display: string = ''): this {\r\n applyAll(this.elements, (el) => {\r\n el.removeAttribute('hidden');\r\n (el as HTMLElement).style.display = display;\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Hides all elements.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n hide(): this {\r\n applyAll(this.elements, (el) => {\r\n (el as HTMLElement).style.display = 'none';\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds an event listener to all elements.\r\n *\r\n * @param event - Event type\r\n * @param handler - Event handler\r\n * @returns The instance for method chaining\r\n */\r\n on(event: string, handler: EventListenerOrEventListenerObject): this {\r\n applyAll(this.elements, (el) => el.addEventListener(event, handler));\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a one-time event listener to all elements.\r\n *\r\n * @param event - Event type\r\n * @param handler - Event handler\r\n * @returns The instance for method chaining\r\n */\r\n once(event: string, handler: EventListener): this {\r\n applyAll(this.elements, (el) => el.addEventListener(event, handler, { once: true }));\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes an event listener from all elements.\r\n *\r\n * @param event - Event type\r\n * @param handler - The handler to remove\r\n * @returns The instance for method chaining\r\n */\r\n off(event: string, handler: EventListenerOrEventListenerObject): this {\r\n applyAll(this.elements, (el) => el.removeEventListener(event, handler));\r\n return this;\r\n }\r\n\r\n /**\r\n * Triggers a custom event on all elements.\r\n *\r\n * @param event - Event type\r\n * @param detail - Optional event detail\r\n * @returns The instance for method chaining\r\n */\r\n trigger(event: string, detail?: unknown): this {\r\n applyAll(this.elements, (el) => {\r\n el.dispatchEvent(new CustomEvent(event, { detail, bubbles: true, cancelable: true }));\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a delegated event listener to all elements.\r\n * Events are delegated to matching descendants.\r\n *\r\n * Use `undelegate()` to remove the listener later.\r\n *\r\n * @param event - Event type to listen for\r\n * @param selector - CSS selector to match against event targets\r\n * @param handler - Event handler function\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\r\n * $$('.container').delegate('click', '.item', handler);\r\n *\r\n * // Later, remove the delegated listener:\r\n * $$('.container').undelegate('click', '.item', handler);\r\n * ```\r\n */\r\n delegate(\r\n event: string,\r\n selector: string,\r\n handler: (event: Event, target: Element) => void\r\n ): this {\r\n const key = `${event}:${selector}`;\r\n\r\n applyAll(this.elements, (el) => {\r\n const wrapper: EventListener = (e: Event) => {\r\n const target = (e.target as Element).closest(selector);\r\n if (target && el.contains(target)) {\r\n handler(e, target);\r\n }\r\n };\r\n\r\n // Get or create the handler maps for this element\r\n if (!this.delegatedHandlers.has(el)) {\r\n this.delegatedHandlers.set(el, new Map());\r\n }\r\n const elementHandlers = this.delegatedHandlers.get(el)!;\r\n\r\n if (!elementHandlers.has(key)) {\r\n elementHandlers.set(key, new Map());\r\n }\r\n elementHandlers.get(key)!.set(handler, wrapper);\r\n\r\n el.addEventListener(event, wrapper);\r\n });\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes a delegated event listener previously added with `delegate()`.\r\n *\r\n * @param event - Event type that was registered\r\n * @param selector - CSS selector that was used\r\n * @param handler - The original handler function passed to delegate()\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\r\n * $$('.container').delegate('click', '.item', handler);\r\n *\r\n * // Remove the delegated listener:\r\n * $$('.container').undelegate('click', '.item', handler);\r\n * ```\r\n */\r\n undelegate(\r\n event: string,\r\n selector: string,\r\n handler: (event: Event, target: Element) => void\r\n ): this {\r\n const key = `${event}:${selector}`;\r\n\r\n applyAll(this.elements, (el) => {\r\n const elementHandlers = this.delegatedHandlers.get(el);\r\n if (!elementHandlers) return;\r\n\r\n const handlers = elementHandlers.get(key);\r\n if (!handlers) return;\r\n\r\n const wrapper = handlers.get(handler);\r\n if (wrapper) {\r\n el.removeEventListener(event, wrapper);\r\n handlers.delete(handler);\r\n\r\n // Clean up empty maps\r\n if (handlers.size === 0) {\r\n elementHandlers.delete(key);\r\n }\r\n if (elementHandlers.size === 0) {\r\n this.delegatedHandlers.delete(el);\r\n }\r\n }\r\n });\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes all elements from the DOM.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n remove(): this {\r\n applyAll(this.elements, (el) => el.remove());\r\n return this;\r\n }\r\n\r\n /**\r\n * Clears all child nodes from all elements.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n empty(): this {\r\n applyAll(this.elements, (el) => {\r\n el.innerHTML = '';\r\n });\r\n return this;\r\n }\r\n}\r\n","import { BQueryCollection } from './collection';\nimport { BQueryElement } from './element';\n\n/**\n * Select a single element. Returns a wrapper for chainable operations.\n */\nexport const $ = (selector: string | Element): BQueryElement => {\n if (typeof selector !== 'string') {\n return new BQueryElement(selector);\n }\n const element = document.querySelector(selector);\n if (!element) {\n throw new Error(`bQuery: element not found for selector \"${selector}\"`);\n }\n return new BQueryElement(element);\n};\n\n/**\n * Select multiple elements. Returns a collection wrapper.\n */\nexport const $$ = (selector: string | Element[] | NodeListOf<Element>): BQueryCollection => {\n if (Array.isArray(selector)) {\n return new BQueryCollection(selector);\n }\n if (selector instanceof NodeList) {\n return new BQueryCollection(Array.from(selector));\n }\n return new BQueryCollection(Array.from(document.querySelectorAll(selector)));\n};\n","/**\r\n * Utility helpers used across the framework.\r\n * These are intentionally small and framework-agnostic to keep the core tiny.\r\n *\r\n * @module bquery/core/utils\r\n */\r\n\r\n/**\r\n * Utility object containing common helper functions.\r\n * All utilities are designed to be tree-shakeable and have zero dependencies.\r\n */\r\nexport const utils = {\r\n /**\r\n * Creates a deep clone using structuredClone if available, otherwise fallback to JSON.\r\n *\r\n * @template T - The type of value being cloned\r\n * @param value - The value to clone\r\n * @returns A deep copy of the value\r\n *\r\n * @example\r\n * ```ts\r\n * const original = { nested: { value: 1 } };\r\n * const copy = utils.clone(original);\r\n * copy.nested.value = 2;\r\n * console.log(original.nested.value); // 1\r\n * ```\r\n */\r\n clone<T>(value: T): T {\r\n if (typeof structuredClone === 'function') {\r\n return structuredClone(value);\r\n }\r\n return JSON.parse(JSON.stringify(value)) as T;\r\n },\r\n\r\n /**\r\n * Deep-merges plain objects into a new object.\r\n * Later sources override earlier ones for primitive values.\r\n * Objects are recursively merged.\r\n *\r\n * @template T - The type of the merged object\r\n * @param sources - Objects to merge\r\n * @returns A new object with all sources merged\r\n *\r\n * @example\r\n * ```ts\r\n * const result = utils.merge(\r\n * { a: 1, nested: { x: 1 } },\r\n * { b: 2, nested: { y: 2 } }\r\n * );\r\n * // Result: { a: 1, b: 2, nested: { x: 1, y: 2 } }\r\n * ```\r\n *\r\n * @security This method is protected against prototype pollution attacks.\r\n * Keys like `__proto__`, `constructor`, and `prototype` are ignored.\r\n */\r\n merge<T extends Record<string, unknown>>(...sources: T[]): T {\r\n const result: Record<string, unknown> = {};\r\n for (const source of sources) {\r\n for (const [key, value] of Object.entries(source)) {\r\n // Prevent prototype pollution attacks\r\n if (utils.isPrototypePollutionKey(key)) continue;\r\n\r\n if (utils.isPlainObject(value) && utils.isPlainObject(result[key])) {\r\n result[key] = utils.merge(\r\n result[key] as Record<string, unknown>,\r\n value as Record<string, unknown>\r\n );\r\n } else {\r\n result[key] = value;\r\n }\r\n }\r\n }\r\n return result as T;\r\n },\r\n\r\n /**\r\n * Checks if a key could cause prototype pollution.\r\n * These keys are dangerous when used in object merging operations.\r\n *\r\n * @param key - The key to check\r\n * @returns True if the key is a prototype pollution vector\r\n *\r\n * @internal\r\n */\r\n isPrototypePollutionKey(key: string): boolean {\r\n return key === '__proto__' || key === 'constructor' || key === 'prototype';\r\n },\r\n\r\n /**\r\n * Creates a debounced function that delays execution until after\r\n * the specified delay has elapsed since the last call.\r\n *\r\n * @template TArgs - The argument types of the function\r\n * @param fn - The function to debounce\r\n * @param delayMs - Delay in milliseconds\r\n * @returns A debounced version of the function\r\n *\r\n * @example\r\n * ```ts\r\n * const search = utils.debounce((query: string) => {\r\n * console.log('Searching:', query);\r\n * }, 300);\r\n *\r\n * search('h');\r\n * search('he');\r\n * search('hello'); // Only this call executes after 300ms\r\n * ```\r\n */\r\n debounce<TArgs extends unknown[]>(\r\n fn: (...args: TArgs) => void,\r\n delayMs: number\r\n ): (...args: TArgs) => void {\r\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\r\n return (...args: TArgs) => {\r\n if (timeoutId) {\r\n clearTimeout(timeoutId);\r\n }\r\n timeoutId = setTimeout(() => fn(...args), delayMs);\r\n };\r\n },\r\n\r\n /**\r\n * Creates a throttled function that runs at most once per interval.\r\n *\r\n * @template TArgs - The argument types of the function\r\n * @param fn - The function to throttle\r\n * @param intervalMs - Minimum interval between calls in milliseconds\r\n * @returns A throttled version of the function\r\n *\r\n * @example\r\n * ```ts\r\n * const handleScroll = utils.throttle(() => {\r\n * console.log('Scroll position:', window.scrollY);\r\n * }, 100);\r\n *\r\n * window.addEventListener('scroll', handleScroll);\r\n * ```\r\n */\r\n throttle<TArgs extends unknown[]>(\r\n fn: (...args: TArgs) => void,\r\n intervalMs: number\r\n ): (...args: TArgs) => void {\r\n let lastRun = 0;\r\n return (...args: TArgs) => {\r\n const now = Date.now();\r\n if (now - lastRun >= intervalMs) {\r\n lastRun = now;\r\n fn(...args);\r\n }\r\n };\r\n },\r\n\r\n /**\r\n * Creates a stable unique ID for DOM usage.\r\n *\r\n * @param prefix - Optional prefix for the ID (default: 'bQuery')\r\n * @returns A unique identifier string\r\n *\r\n * @example\r\n * ```ts\r\n * const id = utils.uid('modal'); // 'modal_x7k2m9p'\r\n * ```\r\n */\r\n uid(prefix = 'bQuery'): string {\r\n return `${prefix}_${Math.random().toString(36).slice(2, 9)}`;\r\n },\r\n\r\n /**\r\n * Checks if a value is a DOM Element.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is an Element\r\n */\r\n isElement(value: unknown): value is Element {\r\n return value instanceof Element;\r\n },\r\n\r\n /**\r\n * Checks if a value is a BQueryCollection-like object.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value has an elements array property\r\n */\r\n isCollection(value: unknown): value is { elements: Element[] } {\r\n return Boolean(value && typeof value === 'object' && 'elements' in (value as object));\r\n },\r\n\r\n /**\r\n * Checks for emptiness across common value types.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is empty (null, undefined, empty string, empty array, or empty object)\r\n *\r\n * @example\r\n * ```ts\r\n * utils.isEmpty(''); // true\r\n * utils.isEmpty([]); // true\r\n * utils.isEmpty({}); // true\r\n * utils.isEmpty(null); // true\r\n * utils.isEmpty('hello'); // false\r\n * utils.isEmpty([1, 2]); // false\r\n * ```\r\n */\r\n isEmpty(value: unknown): boolean {\r\n if (value == null) return true;\r\n if (typeof value === 'string') return value.trim().length === 0;\r\n if (Array.isArray(value)) return value.length === 0;\r\n if (typeof value === 'object') return Object.keys(value as object).length === 0;\r\n return false;\r\n },\r\n\r\n /**\r\n * Checks if a value is a plain object (not null, array, or class instance).\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a plain object\r\n */\r\n isPlainObject(value: unknown): value is Record<string, unknown> {\r\n return Object.prototype.toString.call(value) === '[object Object]';\r\n },\r\n\r\n /**\r\n * Checks if a value is a function.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a function\r\n */\r\n isFunction(value: unknown): value is (...args: unknown[]) => unknown {\r\n return typeof value === 'function';\r\n },\r\n\r\n /**\r\n * Checks if a value is a string.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a string\r\n */\r\n isString(value: unknown): value is string {\r\n return typeof value === 'string';\r\n },\r\n\r\n /**\r\n * Checks if a value is a number (excluding NaN).\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a valid number\r\n */\r\n isNumber(value: unknown): value is number {\r\n return typeof value === 'number' && !Number.isNaN(value);\r\n },\r\n\r\n /**\r\n * Checks if a value is a boolean.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a boolean\r\n */\r\n isBoolean(value: unknown): value is boolean {\r\n return typeof value === 'boolean';\r\n },\r\n\r\n /**\r\n * Checks if a value is an array.\r\n *\r\n * @template T - The type of array elements\r\n * @param value - The value to check\r\n * @returns True if the value is an array\r\n */\r\n isArray<T = unknown>(value: unknown): value is T[] {\r\n return Array.isArray(value);\r\n },\r\n\r\n /**\r\n * Safely parses a JSON string, returning a default value on error.\r\n *\r\n * @template T - The expected type of the parsed value\r\n * @param json - The JSON string to parse\r\n * @param fallback - The default value if parsing fails\r\n * @returns The parsed value or the fallback\r\n *\r\n * @example\r\n * ```ts\r\n * utils.parseJson('{\"name\":\"bQuery\"}', {}); // { name: 'bQuery' }\r\n * utils.parseJson('invalid', {}); // {}\r\n * ```\r\n */\r\n parseJson<T>(json: string, fallback: T): T {\r\n try {\r\n return JSON.parse(json) as T;\r\n } catch {\r\n return fallback;\r\n }\r\n },\r\n\r\n /**\r\n * Picks specified keys from an object.\r\n *\r\n * @template T - The object type\r\n * @template K - The key type\r\n * @param obj - The source object\r\n * @param keys - Keys to pick\r\n * @returns A new object with only the specified keys\r\n *\r\n * @example\r\n * ```ts\r\n * const user = { name: 'John', age: 30, email: 'john@example.com' };\r\n * utils.pick(user, ['name', 'email']); // { name: 'John', email: 'john@example.com' }\r\n * ```\r\n */\r\n pick<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {\r\n const result = {} as Pick<T, K>;\r\n for (const key of keys) {\r\n if (key in obj) {\r\n result[key] = obj[key];\r\n }\r\n }\r\n return result;\r\n },\r\n\r\n /**\r\n * Omits specified keys from an object.\r\n *\r\n * @template T - The object type\r\n * @template K - The key type\r\n * @param obj - The source object\r\n * @param keys - Keys to omit\r\n * @returns A new object without the specified keys\r\n *\r\n * @example\r\n * ```ts\r\n * const user = { name: 'John', age: 30, password: 'secret' };\r\n * utils.omit(user, ['password']); // { name: 'John', age: 30 }\r\n * ```\r\n */\r\n omit<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {\r\n const result = { ...obj };\r\n for (const key of keys) {\r\n delete result[key];\r\n }\r\n return result as Omit<T, K>;\r\n },\r\n\r\n /**\r\n * Delays execution for a specified number of milliseconds.\r\n *\r\n * @param ms - Milliseconds to delay\r\n * @returns A promise that resolves after the delay\r\n *\r\n * @example\r\n * ```ts\r\n * await utils.sleep(1000); // Wait 1 second\r\n * console.log('Done!');\r\n * ```\r\n */\r\n sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n },\r\n\r\n /**\r\n * Generates a random integer between min and max (inclusive).\r\n *\r\n * @param min - Minimum value\r\n * @param max - Maximum value\r\n * @returns A random integer in the range [min, max]\r\n *\r\n * @example\r\n * ```ts\r\n * const roll = utils.randomInt(1, 6); // Random dice roll\r\n * ```\r\n */\r\n randomInt(min: number, max: number): number {\r\n return Math.floor(Math.random() * (max - min + 1)) + min;\r\n },\r\n\r\n /**\r\n * Clamps a number between a minimum and maximum value.\r\n *\r\n * @param value - The value to clamp\r\n * @param min - Minimum value\r\n * @param max - Maximum value\r\n * @returns The clamped value\r\n *\r\n * @example\r\n * ```ts\r\n * utils.clamp(150, 0, 100); // 100\r\n * utils.clamp(-10, 0, 100); // 0\r\n * utils.clamp(50, 0, 100); // 50\r\n * ```\r\n */\r\n clamp(value: number, min: number, max: number): number {\r\n return Math.min(Math.max(value, min), max);\r\n },\r\n\r\n /**\r\n * Capitalizes the first letter of a string.\r\n *\r\n * @param str - The string to capitalize\r\n * @returns The capitalized string\r\n *\r\n * @example\r\n * ```ts\r\n * utils.capitalize('hello'); // 'Hello'\r\n * ```\r\n */\r\n capitalize(str: string): string {\r\n if (!str) return str;\r\n return str.charAt(0).toUpperCase() + str.slice(1);\r\n },\r\n\r\n /**\r\n * Converts a string to kebab-case.\r\n *\r\n * @param str - The string to convert\r\n * @returns The kebab-cased string\r\n *\r\n * @example\r\n * ```ts\r\n * utils.toKebabCase('myVariableName'); // 'my-variable-name'\r\n * ```\r\n */\r\n toKebabCase(str: string): string {\r\n return str\r\n .replace(/([a-z])([A-Z])/g, '$1-$2')\r\n .replace(/[\\s_]+/g, '-')\r\n .toLowerCase();\r\n },\r\n\r\n /**\r\n * Converts a string to camelCase.\r\n *\r\n * @param str - The string to convert\r\n * @returns The camelCased string\r\n *\r\n * @example\r\n * ```ts\r\n * utils.toCamelCase('my-variable-name'); // 'myVariableName'\r\n * ```\r\n */\r\n toCamelCase(str: string): string {\r\n return str\r\n .replace(/[-_\\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))\r\n .replace(/^[A-Z]/, (char) => char.toLowerCase());\r\n },\r\n};\r\n","/**\r\n * Reactive primitives inspired by fine-grained reactivity.\r\n *\r\n * This module provides a minimal but powerful reactive system:\r\n * - Signal: A reactive value that notifies subscribers when changed\r\n * - Computed: A derived value that automatically updates when dependencies change\r\n * - Effect: A side effect that re-runs when its dependencies change\r\n * - Batch: Group multiple updates to prevent intermediate re-renders\r\n *\r\n * @module bquery/reactive\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n * const doubled = computed(() => count.value * 2);\r\n *\r\n * effect(() => {\r\n * console.log(`Count: ${count.value}, Doubled: ${doubled.value}`);\r\n * });\r\n *\r\n * batch(() => {\r\n * count.value = 1;\r\n * count.value = 2;\r\n * });\r\n * // Logs: \"Count: 2, Doubled: 4\" (only once due to batching)\r\n * ```\r\n */\r\n\r\n/**\r\n * Observer function type used internally for tracking reactivity.\r\n */\r\nexport type Observer = () => void;\r\n\r\n/**\r\n * Cleanup function returned by effects for disposal.\r\n */\r\nexport type CleanupFn = () => void;\r\n\r\n// Internal state for tracking the current observer context\r\nconst observerStack: Observer[] = [];\r\nlet batchDepth = 0;\r\nconst pendingObservers = new Set<Observer>();\r\n\r\n// Flag to disable tracking temporarily (for untrack)\r\nlet trackingEnabled = true;\r\n\r\n/**\r\n * Tracks dependencies during a function execution.\r\n * Uses direct push/pop for O(1) operations instead of array copying.\r\n * @internal\r\n */\r\nconst track = <T>(observer: Observer, fn: () => T): T => {\r\n observerStack.push(observer);\r\n try {\r\n return fn();\r\n } finally {\r\n observerStack.pop();\r\n }\r\n};\r\n\r\n/**\r\n * Schedules an observer to run, respecting batch mode.\r\n * @internal\r\n */\r\nconst scheduleObserver = (observer: Observer) => {\r\n if (batchDepth > 0) {\r\n pendingObservers.add(observer);\r\n return;\r\n }\r\n observer();\r\n};\r\n\r\n/**\r\n * Flushes all pending observers after a batch completes.\r\n * @internal\r\n */\r\nconst flushObservers = () => {\r\n for (const observer of Array.from(pendingObservers)) {\r\n pendingObservers.delete(observer);\r\n observer();\r\n }\r\n};\r\n\r\n/**\r\n * A reactive value container that notifies subscribers on change.\r\n *\r\n * Signals are the foundational primitive of the reactive system.\r\n * Reading a signal's value inside an effect or computed automatically\r\n * establishes a reactive dependency.\r\n *\r\n * @template T - The type of the stored value\r\n *\r\n * @example\r\n * ```ts\r\n * const name = signal('World');\r\n * console.log(name.value); // 'World'\r\n *\r\n * name.value = 'bQuery';\r\n * console.log(name.value); // 'bQuery'\r\n * ```\r\n */\r\nexport class Signal<T> {\r\n private subscribers = new Set<Observer>();\r\n\r\n /**\r\n * Creates a new signal with an initial value.\r\n * @param _value - The initial value\r\n */\r\n constructor(private _value: T) {}\r\n\r\n /**\r\n * Gets the current value and tracks the read if inside an observer.\r\n * Respects the global tracking state (disabled during untrack calls).\r\n */\r\n get value(): T {\r\n if (trackingEnabled) {\r\n const current = observerStack[observerStack.length - 1];\r\n if (current) {\r\n this.subscribers.add(current);\r\n }\r\n }\r\n return this._value;\r\n }\r\n\r\n /**\r\n * Sets a new value and notifies all subscribers if the value changed.\r\n * Uses Object.is for equality comparison.\r\n */\r\n set value(next: T) {\r\n if (Object.is(this._value, next)) return;\r\n this._value = next;\r\n for (const subscriber of this.subscribers) {\r\n scheduleObserver(subscriber);\r\n }\r\n }\r\n\r\n /**\r\n * Reads the current value without tracking.\r\n * Useful when you need the value but don't want to create a dependency.\r\n *\r\n * @returns The current value\r\n */\r\n peek(): T {\r\n return this._value;\r\n }\r\n\r\n /**\r\n * Updates the value using a function.\r\n * Useful for updates based on the current value.\r\n *\r\n * @param updater - Function that receives current value and returns new value\r\n */\r\n update(updater: (current: T) => T): void {\r\n this.value = updater(this._value);\r\n }\r\n}\r\n\r\n/**\r\n * A computed value that derives from other reactive sources.\r\n *\r\n * Computed values are lazily evaluated and cached. They only\r\n * recompute when their dependencies change.\r\n *\r\n * @template T - The type of the computed value\r\n *\r\n * @example\r\n * ```ts\r\n * const price = signal(100);\r\n * const quantity = signal(2);\r\n * const total = computed(() => price.value * quantity.value);\r\n *\r\n * console.log(total.value); // 200\r\n * price.value = 150;\r\n * console.log(total.value); // 300\r\n * ```\r\n */\r\nexport class Computed<T> {\r\n private cachedValue!: T;\r\n private dirty = true;\r\n private subscribers = new Set<Observer>();\r\n private readonly markDirty = () => {\r\n this.dirty = true;\r\n for (const subscriber of this.subscribers) {\r\n scheduleObserver(subscriber);\r\n }\r\n };\r\n\r\n /**\r\n * Creates a new computed value.\r\n * @param compute - Function that computes the value\r\n */\r\n constructor(private readonly compute: () => T) {}\r\n\r\n /**\r\n * Gets the computed value, recomputing if dependencies changed.\r\n */\r\n get value(): T {\r\n const current = observerStack[observerStack.length - 1];\r\n if (current) {\r\n this.subscribers.add(current);\r\n }\r\n if (this.dirty) {\r\n this.dirty = false;\r\n this.cachedValue = track(this.markDirty, this.compute);\r\n }\r\n return this.cachedValue;\r\n }\r\n\r\n /**\r\n * Reads the current computed value without tracking.\r\n * Useful when you need the value but don't want to create a dependency.\r\n *\r\n * @returns The current cached value (recomputes if dirty)\r\n */\r\n peek(): T {\r\n if (this.dirty) {\r\n this.dirty = false;\r\n this.cachedValue = track(this.markDirty, this.compute);\r\n }\r\n return this.cachedValue;\r\n }\r\n}\r\n\r\n/**\r\n * Creates a new reactive signal.\r\n *\r\n * @template T - The type of the signal value\r\n * @param value - The initial value\r\n * @returns A new Signal instance\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n * count.value++; // Triggers subscribers\r\n * ```\r\n */\r\nexport const signal = <T>(value: T): Signal<T> => new Signal(value);\r\n\r\n/**\r\n * Creates a new computed value.\r\n *\r\n * @template T - The type of the computed value\r\n * @param fn - Function that computes the value from reactive sources\r\n * @returns A new Computed instance\r\n *\r\n * @example\r\n * ```ts\r\n * const doubled = computed(() => count.value * 2);\r\n * ```\r\n */\r\nexport const computed = <T>(fn: () => T): Computed<T> => new Computed(fn);\r\n\r\n/**\r\n * Creates a side effect that automatically re-runs when dependencies change.\r\n *\r\n * The effect runs immediately upon creation and then re-runs whenever\r\n * any signal or computed value read inside it changes.\r\n *\r\n * @param fn - The effect function to run\r\n * @returns A cleanup function to stop the effect\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n *\r\n * const cleanup = effect(() => {\r\n * document.title = `Count: ${count.value}`;\r\n * });\r\n *\r\n * // Later, to stop the effect:\r\n * cleanup();\r\n * ```\r\n */\r\nexport const effect = (fn: () => void | CleanupFn): CleanupFn => {\r\n let cleanupFn: CleanupFn | void;\r\n let isDisposed = false;\r\n\r\n const observer: Observer = () => {\r\n if (isDisposed) return;\r\n\r\n // Run previous cleanup if exists\r\n if (cleanupFn) {\r\n cleanupFn();\r\n }\r\n\r\n // Run effect and capture cleanup\r\n cleanupFn = track(observer, fn);\r\n };\r\n\r\n observer();\r\n\r\n return () => {\r\n isDisposed = true;\r\n if (cleanupFn) {\r\n cleanupFn();\r\n }\r\n };\r\n};\r\n\r\n/**\r\n * Batches multiple signal updates into a single notification cycle.\r\n *\r\n * Updates made inside the batch function are deferred until the batch\r\n * completes, preventing intermediate re-renders and improving performance.\r\n *\r\n * @param fn - Function containing multiple signal updates\r\n *\r\n * @example\r\n * ```ts\r\n * batch(() => {\r\n * firstName.value = 'John';\r\n * lastName.value = 'Doe';\r\n * age.value = 30;\r\n * });\r\n * // Effects only run once with all three updates\r\n * ```\r\n */\r\nexport const batch = (fn: () => void): void => {\r\n batchDepth += 1;\r\n try {\r\n fn();\r\n } finally {\r\n batchDepth -= 1;\r\n if (batchDepth === 0) {\r\n flushObservers();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Creates a signal that persists to localStorage.\r\n *\r\n * @template T - The type of the signal value\r\n * @param key - The localStorage key\r\n * @param initialValue - The initial value if not found in storage\r\n * @returns A Signal that syncs with localStorage\r\n *\r\n * @example\r\n * ```ts\r\n * const theme = persistedSignal('theme', 'light');\r\n * theme.value = 'dark'; // Automatically saved to localStorage\r\n * ```\r\n */\r\nexport const persistedSignal = <T>(key: string, initialValue: T): Signal<T> => {\r\n let stored: T = initialValue;\r\n\r\n try {\r\n const raw = localStorage.getItem(key);\r\n if (raw !== null) {\r\n stored = JSON.parse(raw) as T;\r\n }\r\n } catch {\r\n // Use initial value on parse error\r\n }\r\n\r\n const sig = signal(stored);\r\n\r\n // Create an effect to persist changes\r\n effect(() => {\r\n try {\r\n localStorage.setItem(key, JSON.stringify(sig.value));\r\n } catch {\r\n // Ignore storage errors\r\n }\r\n });\r\n\r\n return sig;\r\n};\r\n\r\n// ============================================================================\r\n// Extended Reactive Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * A readonly wrapper around a signal that prevents writes.\r\n * Provides read-only access to a signal's value while maintaining reactivity.\r\n *\r\n * @template T - The type of the wrapped value\r\n */\r\nexport interface ReadonlySignal<T> {\r\n /** Gets the current value with dependency tracking. */\r\n readonly value: T;\r\n /** Gets the current value without dependency tracking. */\r\n peek(): T;\r\n}\r\n\r\n/**\r\n * Creates a read-only view of a signal.\r\n * Useful for exposing reactive state without allowing modifications.\r\n *\r\n * @template T - The type of the signal value\r\n * @param sig - The signal to wrap\r\n * @returns A readonly signal wrapper\r\n *\r\n * @example\r\n * ```ts\r\n * const _count = signal(0);\r\n * const count = readonly(_count); // Expose read-only version\r\n *\r\n * console.log(count.value); // 0\r\n * count.value = 1; // TypeScript error: Cannot assign to 'value'\r\n * ```\r\n */\r\nexport const readonly = <T>(sig: Signal<T>): ReadonlySignal<T> => ({\r\n get value(): T {\r\n return sig.value;\r\n },\r\n peek(): T {\r\n return sig.peek();\r\n },\r\n});\r\n\r\n/**\r\n * Watches a signal or computed value and calls a callback with old and new values.\r\n * Unlike effect, watch provides access to the previous value.\r\n *\r\n * @template T - The type of the watched value\r\n * @param source - The signal or computed to watch\r\n * @param callback - Function called with (newValue, oldValue) on changes\r\n * @param options - Watch options\r\n * @returns A cleanup function to stop watching\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n *\r\n * const cleanup = watch(count, (newVal, oldVal) => {\r\n * console.log(`Changed from ${oldVal} to ${newVal}`);\r\n * });\r\n *\r\n * count.value = 5; // Logs: \"Changed from 0 to 5\"\r\n * cleanup();\r\n * ```\r\n */\r\nexport const watch = <T>(\r\n source: Signal<T> | Computed<T>,\r\n callback: (newValue: T, oldValue: T | undefined) => void,\r\n options: { immediate?: boolean } = {}\r\n): CleanupFn => {\r\n let oldValue: T | undefined;\r\n let isFirst = true;\r\n\r\n return effect(() => {\r\n const newValue = source.value;\r\n\r\n if (isFirst) {\r\n isFirst = false;\r\n oldValue = newValue;\r\n if (options.immediate) {\r\n callback(newValue, undefined);\r\n }\r\n return;\r\n }\r\n\r\n callback(newValue, oldValue);\r\n oldValue = newValue;\r\n });\r\n};\r\n\r\n/**\r\n * Executes a function without tracking any signal dependencies.\r\n * Useful when reading a signal value without creating a reactive dependency.\r\n *\r\n * @template T - The return type of the function\r\n * @param fn - The function to execute without tracking\r\n * @returns The result of the function\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n *\r\n * effect(() => {\r\n * // This creates a dependency\r\n * console.log('Tracked:', count.value);\r\n *\r\n * // This does NOT create a dependency\r\n * const untracked = untrack(() => otherSignal.value);\r\n * });\r\n * ```\r\n */\r\nexport const untrack = <T>(fn: () => T): T => {\r\n const prevTracking = trackingEnabled;\r\n trackingEnabled = false;\r\n try {\r\n return fn();\r\n } finally {\r\n trackingEnabled = prevTracking;\r\n }\r\n};\r\n\r\n/**\r\n * Type guard to check if a value is a Signal instance.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a Signal\r\n *\r\n * @example\r\n * ```ts\r\n * const count = signal(0);\r\n * const num = 42;\r\n *\r\n * isSignal(count); // true\r\n * isSignal(num); // false\r\n * ```\r\n */\r\nexport const isSignal = (value: unknown): value is Signal<unknown> => value instanceof Signal;\r\n\r\n/**\r\n * Type guard to check if a value is a Computed instance.\r\n *\r\n * @param value - The value to check\r\n * @returns True if the value is a Computed\r\n *\r\n * @example\r\n * ```ts\r\n * const doubled = computed(() => count.value * 2);\r\n * isComputed(doubled); // true\r\n * ```\r\n */\r\nexport const isComputed = (value: unknown): value is Computed<unknown> => value instanceof Computed;\r\n","/**\r\n * Minimal Web Component helper for building custom elements.\r\n *\r\n * This module provides a declarative API for defining Web Components\r\n * without complex build steps. Features include:\r\n * - Type-safe props with automatic attribute coercion\r\n * - Reactive state management\r\n * - Shadow DOM encapsulation with scoped styles\r\n * - Lifecycle hooks (connected, disconnected)\r\n * - Event emission helpers\r\n *\r\n * @module bquery/component\r\n *\r\n * @example\r\n * ```ts\r\n * import { component, html } from 'bquery/component';\r\n *\r\n * component('user-card', {\r\n * props: {\r\n * username: { type: String, required: true },\r\n * avatar: { type: String, default: '/default-avatar.png' },\r\n * },\r\n * styles: `\r\n * .card { padding: 1rem; border: 1px solid #ccc; }\r\n * `,\r\n * render({ props }) {\r\n * return html`\r\n * <div class=\"card\">\r\n * <img src=\"${props.avatar}\" alt=\"${props.username}\" />\r\n * <h3>${props.username}</h3>\r\n * </div>\r\n * `;\r\n * },\r\n * });\r\n * ```\r\n */\r\n\r\n/**\r\n * Defines a single prop's type and configuration.\r\n *\r\n * @template T - The TypeScript type of the prop value\r\n *\r\n * @example\r\n * ```ts\r\n * const myProp: PropDefinition<number> = {\r\n * type: Number,\r\n * required: false,\r\n * default: 0,\r\n * };\r\n * ```\r\n */\r\nexport type PropDefinition<T = unknown> = {\r\n /** Constructor or converter function for the prop type */\r\n type:\r\n | StringConstructor\r\n | NumberConstructor\r\n | BooleanConstructor\r\n | ObjectConstructor\r\n | ArrayConstructor\r\n | { new (value: unknown): T }\r\n | ((value: unknown) => T);\r\n /** Whether the prop must be provided */\r\n required?: boolean;\r\n /** Default value when prop is not provided */\r\n default?: T;\r\n /** Optional validator function to validate prop values */\r\n validator?: (value: T) => boolean;\r\n};\r\n\r\n/**\r\n * Complete component definition including props, state, styles, and lifecycle.\r\n *\r\n * @template TProps - Type of the component's props\r\n */\r\nexport type ComponentDefinition<TProps extends Record<string, unknown> = Record<string, unknown>> =\r\n {\r\n /** Prop definitions with types and defaults */\r\n props?: Record<keyof TProps, PropDefinition>;\r\n /** Initial internal state */\r\n state?: Record<string, unknown>;\r\n /** CSS styles scoped to the component's shadow DOM */\r\n styles?: string;\r\n /** Lifecycle hook called before the component mounts (before first render) */\r\n beforeMount?: () => void;\r\n /** Lifecycle hook called when component is added to DOM */\r\n connected?: () => void;\r\n /** Lifecycle hook called when component is removed from DOM */\r\n disconnected?: () => void;\r\n /** Lifecycle hook called before an update render; return false to prevent */\r\n beforeUpdate?: (props: TProps) => boolean | void;\r\n /** Lifecycle hook called after reactive updates trigger a render */\r\n updated?: () => void;\r\n /** Error handler for errors during rendering or lifecycle */\r\n onError?: (error: Error) => void;\r\n /** Render function returning HTML string */\r\n render: (context: {\r\n props: TProps;\r\n state: Record<string, unknown>;\r\n emit: (event: string, detail?: unknown) => void;\r\n }) => string;\r\n };\r\n\r\n/**\r\n * Coerces a string attribute value into a typed prop value.\r\n * Supports String, Number, Boolean, Object, Array, and custom converters.\r\n *\r\n * @internal\r\n * @template T - The target type\r\n * @param rawValue - The raw string value from the attribute\r\n * @param config - The prop definition with type information\r\n * @returns The coerced value of type T\r\n */\r\nconst coercePropValue = <T>(rawValue: string, config: PropDefinition<T>): T => {\r\n const { type } = config;\r\n\r\n if (type === String) return rawValue as T;\r\n\r\n if (type === Number) {\r\n const parsed = Number(rawValue);\r\n return (Number.isNaN(parsed) ? rawValue : parsed) as T;\r\n }\r\n\r\n if (type === Boolean) {\r\n const normalized = rawValue.trim().toLowerCase();\r\n if (normalized === '' || normalized === 'true' || normalized === '1') {\r\n return true as T;\r\n }\r\n if (normalized === 'false' || normalized === '0') {\r\n return false as T;\r\n }\r\n return Boolean(rawValue) as T;\r\n }\r\n\r\n if (type === Object || type === Array) {\r\n try {\r\n return JSON.parse(rawValue) as T;\r\n } catch {\r\n return rawValue as T;\r\n }\r\n }\r\n\r\n if (typeof type === 'function') {\r\n const callable = type as (value: unknown) => T;\r\n const constructable = type as new (value: unknown) => T;\r\n try {\r\n return callable(rawValue);\r\n } catch {\r\n return new constructable(rawValue);\r\n }\r\n }\r\n\r\n return rawValue as T;\r\n};\r\n\r\n/**\r\n * Tagged template literal for creating HTML strings.\r\n *\r\n * This function handles interpolation of values into HTML templates,\r\n * converting null/undefined to empty strings.\r\n *\r\n * @param strings - Template literal string parts\r\n * @param values - Interpolated values\r\n * @returns Combined HTML string\r\n *\r\n * @example\r\n * ```ts\r\n * const name = 'World';\r\n * const greeting = html`<h1>Hello, ${name}!</h1>`;\r\n * // Result: '<h1>Hello, World!</h1>'\r\n * ```\r\n */\r\nexport const html = (strings: TemplateStringsArray, ...values: unknown[]): string => {\r\n return strings.reduce((acc, part, index) => `${acc}${part}${values[index] ?? ''}`, '');\r\n};\r\n\r\n/**\r\n * Escapes HTML entities in interpolated values for XSS prevention.\r\n * Use this when you need to safely embed user content in templates.\r\n *\r\n * @param strings - Template literal string parts\r\n * @param values - Interpolated values to escape\r\n * @returns Combined HTML string with escaped values\r\n *\r\n * @example\r\n * ```ts\r\n * const userInput = '<script>alert(\"xss\")</script>';\r\n * const safe = safeHtml`<div>${userInput}</div>`;\r\n * // Result: '<div><script>alert(\"xss\")</script></div>'\r\n * ```\r\n */\r\nexport const safeHtml = (strings: TemplateStringsArray, ...values: unknown[]): string => {\r\n const escapeMap: Record<string, string> = {\r\n '&': '&',\r\n '<': '<',\r\n '>': '>',\r\n '\"': '"',\r\n \"'\": ''',\r\n '`': '`',\r\n };\r\n\r\n const escape = (value: unknown): string => {\r\n const str = String(value ?? '');\r\n return str.replace(/[&<>\"'`]/g, (char) => escapeMap[char]);\r\n };\r\n\r\n return strings.reduce((acc, part, index) => `${acc}${part}${escape(values[index])}`, '');\r\n};\r\n\r\n/**\r\n * Defines and registers a custom Web Component.\r\n *\r\n * This function creates a new custom element with the given tag name\r\n * and configuration. The component uses Shadow DOM for encapsulation\r\n * and automatically re-renders when observed attributes change.\r\n *\r\n * @template TProps - Type of the component's props\r\n * @param tagName - The custom element tag name (must contain a hyphen)\r\n * @param definition - The component configuration\r\n *\r\n * @example\r\n * ```ts\r\n * component('counter-button', {\r\n * props: {\r\n * start: { type: Number, default: 0 },\r\n * },\r\n * state: { count: 0 },\r\n * styles: `\r\n * button { padding: 0.5rem 1rem; }\r\n * `,\r\n * connected() {\r\n * console.log('Counter mounted');\r\n * },\r\n * render({ props, state, emit }) {\r\n * return html`\r\n * <button onclick=\"this.getRootNode().host.increment()\">\r\n * Count: ${state.count}\r\n * </button>\r\n * `;\r\n * },\r\n * });\r\n * ```\r\n */\r\nexport const component = <TProps extends Record<string, unknown>>(\r\n tagName: string,\r\n definition: ComponentDefinition<TProps>\r\n): void => {\r\n /**\r\n * Internal Web Component class created for each component definition.\r\n * @internal\r\n */\r\n class BQueryComponent extends HTMLElement {\r\n /** Internal state object for the component */\r\n private readonly state = { ...(definition.state ?? {}) };\r\n /** Typed props object populated from attributes */\r\n private props = {} as TProps;\r\n\r\n constructor() {\r\n super();\r\n this.attachShadow({ mode: 'open' });\r\n this.syncProps();\r\n }\r\n\r\n /**\r\n * Returns the list of attributes to observe for changes.\r\n */\r\n static get observedAttributes(): string[] {\r\n return Object.keys(definition.props ?? {});\r\n }\r\n\r\n /**\r\n * Called when the element is added to the DOM.\r\n */\r\n connectedCallback(): void {\r\n try {\r\n definition.beforeMount?.call(this);\r\n definition.connected?.call(this);\r\n this.render();\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Called when the element is removed from the DOM.\r\n */\r\n disconnectedCallback(): void {\r\n try {\r\n definition.disconnected?.call(this);\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Called when an observed attribute changes.\r\n */\r\n attributeChangedCallback(): void {\r\n try {\r\n this.syncProps();\r\n this.render(true);\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Handles errors during component lifecycle.\r\n * @internal\r\n */\r\n private handleError(error: Error): void {\r\n if (definition.onError) {\r\n definition.onError.call(this, error);\r\n } else {\r\n console.error(`bQuery component error in <${tagName}>:`, error);\r\n }\r\n }\r\n\r\n /**\r\n * Updates a state property and triggers a re-render.\r\n *\r\n * @param key - The state property key\r\n * @param value - The new value\r\n */\r\n setState(key: string, value: unknown): void {\r\n this.state[key] = value;\r\n this.render(true);\r\n }\r\n\r\n /**\r\n * Gets a state property value.\r\n *\r\n * @param key - The state property key\r\n * @returns The current value\r\n */\r\n getState<T = unknown>(key: string): T {\r\n return this.state[key] as T;\r\n }\r\n\r\n /**\r\n * Synchronizes props from attributes.\r\n * @internal\r\n */\r\n private syncProps(): void {\r\n const props = definition.props ?? {};\r\n for (const [key, config] of Object.entries(props) as [string, PropDefinition][]) {\r\n const attrValue = this.getAttribute(key);\r\n let value: unknown;\r\n\r\n if (attrValue == null) {\r\n if (config.required && config.default === undefined) {\r\n throw new Error(`bQuery component: missing required prop \"${key}\"`);\r\n }\r\n value = config.default ?? undefined;\r\n } else {\r\n value = coercePropValue(attrValue, config);\r\n }\r\n\r\n // Validate the prop value if a validator is provided\r\n if (config.validator && value !== undefined) {\r\n const isValid = config.validator(value);\r\n if (!isValid) {\r\n throw new Error(\r\n `bQuery component: validation failed for prop \"${key}\" with value ${JSON.stringify(value)}`\r\n );\r\n }\r\n }\r\n\r\n (this.props as Record<string, unknown>)[key] = value;\r\n }\r\n }\r\n\r\n /**\r\n * Renders the component to its shadow root.\r\n * @internal\r\n */\r\n private render(triggerUpdated = false): void {\r\n try {\r\n // Check beforeUpdate hook if this is an update\r\n if (triggerUpdated && definition.beforeUpdate) {\r\n const shouldUpdate = definition.beforeUpdate.call(this, this.props);\r\n if (shouldUpdate === false) return;\r\n }\r\n\r\n /**\r\n * Emits a custom event from the component.\r\n */\r\n const emit = (event: string, detail?: unknown): void => {\r\n this.dispatchEvent(new CustomEvent(event, { detail, bubbles: true, composed: true }));\r\n };\r\n\r\n if (!this.shadowRoot) return;\r\n\r\n const markup = definition.render({\r\n props: this.props,\r\n state: this.state,\r\n emit,\r\n });\r\n\r\n const styles = definition.styles ? `<style>${definition.styles}</style>` : '';\r\n this.shadowRoot.innerHTML = `${styles}${markup}`;\r\n\r\n if (triggerUpdated) {\r\n definition.updated?.call(this);\r\n }\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n }\r\n }\r\n }\r\n\r\n if (!customElements.get(tagName)) {\r\n customElements.define(tagName, BQueryComponent);\r\n }\r\n};\r\n","/**\n * Motion module providing view transitions, FLIP animations, and spring physics.\n * Designed to work with modern browser APIs while providing smooth fallbacks.\n *\n * @module bquery/motion\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Options for view transitions.\n */\nexport interface TransitionOptions {\n /** The DOM update function to execute during transition */\n update: () => void;\n}\n\n/**\n * Captured element bounds for FLIP animations.\n */\nexport interface ElementBounds {\n top: number;\n left: number;\n width: number;\n height: number;\n}\n\n/**\n * FLIP animation configuration options.\n */\nexport interface FlipOptions {\n /** Animation duration in milliseconds */\n duration?: number;\n /** CSS easing function */\n easing?: string;\n /** Callback when animation completes */\n onComplete?: () => void;\n}\n\n/**\n * Spring physics configuration.\n */\nexport interface SpringConfig {\n /** Spring stiffness (default: 100) */\n stiffness?: number;\n /** Damping coefficient (default: 10) */\n damping?: number;\n /** Mass of the object (default: 1) */\n mass?: number;\n /** Velocity threshold for completion (default: 0.01) */\n precision?: number;\n}\n\n/**\n * Spring instance for animating values.\n */\nexport interface Spring {\n /** Start animating to target value */\n to(target: number): Promise<void>;\n /** Get current animated value */\n current(): number;\n /** Stop the animation */\n stop(): void;\n /** Subscribe to value changes */\n onChange(callback: (value: number) => void): () => void;\n}\n\n// ============================================================================\n// View Transitions\n// ============================================================================\n\n/** Extended document type with View Transitions API */\ntype DocumentWithTransition = Document & {\n startViewTransition?: (callback: () => void) => {\n finished: Promise<void>;\n ready: Promise<void>;\n updateCallbackDone: Promise<void>;\n };\n};\n\n/**\n * Execute a DOM update with view transition animation.\n * Falls back to immediate update when View Transitions API is unavailable.\n *\n * @param updateOrOptions - Update function or options object\n * @returns Promise that resolves when transition completes\n *\n * @example\n * ```ts\n * await transition(() => {\n * $('#content').text('Updated');\n * });\n * ```\n */\nexport const transition = async (\n updateOrOptions: (() => void) | TransitionOptions\n): Promise<void> => {\n const update = typeof updateOrOptions === 'function' ? updateOrOptions : updateOrOptions.update;\n\n const doc = document as DocumentWithTransition;\n\n if (doc.startViewTransition) {\n await doc.startViewTransition(() => update()).finished;\n return;\n }\n\n update();\n};\n\n// ============================================================================\n// FLIP Animations\n// ============================================================================\n\n/**\n * Capture the current bounds of an element for FLIP animation.\n *\n * @param element - The DOM element to measure\n * @returns The element's current position and size\n */\nexport const capturePosition = (element: Element): ElementBounds => {\n const rect = element.getBoundingClientRect();\n return {\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n };\n};\n\n/**\n * Perform a FLIP (First, Last, Invert, Play) animation.\n * Animates an element from its captured position to its current position.\n *\n * @param element - The element to animate\n * @param firstBounds - The previously captured bounds\n * @param options - Animation configuration\n * @returns Promise that resolves when animation completes\n *\n * @example\n * ```ts\n * const first = capturePosition(element);\n * // ... DOM changes that move the element ...\n * await flip(element, first, { duration: 300 });\n * ```\n */\nexport const flip = (\n element: Element,\n firstBounds: ElementBounds,\n options: FlipOptions = {}\n): Promise<void> => {\n const { duration = 300, easing = 'ease-out', onComplete } = options;\n\n // Last: Get current position\n const lastBounds = capturePosition(element);\n\n // Skip animation if element has zero dimensions (avoid division by zero)\n if (lastBounds.width === 0 || lastBounds.height === 0) {\n return Promise.resolve();\n }\n\n // Invert: Calculate the delta\n const deltaX = firstBounds.left - lastBounds.left;\n const deltaY = firstBounds.top - lastBounds.top;\n const deltaW = firstBounds.width / lastBounds.width;\n const deltaH = firstBounds.height / lastBounds.height;\n\n // Skip animation if no change\n if (deltaX === 0 && deltaY === 0 && deltaW === 1 && deltaH === 1) {\n return Promise.resolve();\n }\n\n const htmlElement = element as HTMLElement;\n\n // Apply inverted transform\n htmlElement.style.transform = `translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`;\n htmlElement.style.transformOrigin = 'top left';\n\n // Force reflow\n void htmlElement.offsetHeight;\n\n // Play: Animate back to current position\n return new Promise((resolve) => {\n const animation = htmlElement.animate(\n [\n {\n transform: `translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`,\n },\n { transform: 'translate(0, 0) scale(1, 1)' },\n ],\n { duration, easing, fill: 'forwards' }\n );\n\n animation.onfinish = () => {\n htmlElement.style.transform = '';\n htmlElement.style.transformOrigin = '';\n onComplete?.();\n resolve();\n };\n });\n};\n\n/**\n * FLIP helper for animating a list of elements.\n * Useful for reordering lists with smooth animations.\n *\n * @param elements - Array of elements to animate\n * @param performUpdate - Function that performs the DOM update\n * @param options - Animation configuration\n *\n * @example\n * ```ts\n * await flipList(listItems, () => {\n * container.appendChild(container.firstChild); // Move first to last\n * });\n * ```\n */\nexport const flipList = async (\n elements: Element[],\n performUpdate: () => void,\n options: FlipOptions = {}\n): Promise<void> => {\n // First: Capture all positions\n const positions = new Map<Element, ElementBounds>();\n for (const el of elements) {\n positions.set(el, capturePosition(el));\n }\n\n // Perform DOM update\n performUpdate();\n\n // Animate each element\n const animations = elements.map((el) => {\n const first = positions.get(el);\n if (!first) return Promise.resolve();\n return flip(el, first, options);\n });\n\n await Promise.all(animations);\n};\n\n// ============================================================================\n// Spring Physics\n// ============================================================================\n\n/**\n * Default spring configuration values.\n */\nconst DEFAULT_SPRING_CONFIG: Required<SpringConfig> = {\n stiffness: 100,\n damping: 10,\n mass: 1,\n precision: 0.01,\n};\n\n/**\n * Create a spring-based animation for smooth, physics-based motion.\n *\n * @param initialValue - Starting value for the spring\n * @param config - Spring physics configuration\n * @returns Spring instance for controlling the animation\n *\n * @example\n * ```ts\n * const x = spring(0, { stiffness: 120, damping: 14 });\n * x.onChange((value) => {\n * element.style.transform = `translateX(${value}px)`;\n * });\n * await x.to(100);\n * ```\n */\nexport const spring = (initialValue: number, config: SpringConfig = {}): Spring => {\n const { stiffness, damping, mass, precision } = {\n ...DEFAULT_SPRING_CONFIG,\n ...config,\n };\n\n let current = initialValue;\n let velocity = 0;\n let target = initialValue;\n let animationFrame: number | null = null;\n let resolvePromise: (() => void) | null = null;\n const listeners = new Set<(value: number) => void>();\n\n const notifyListeners = () => {\n for (const listener of listeners) {\n listener(current);\n }\n };\n\n const step = () => {\n // Spring physics calculation\n const displacement = current - target;\n const springForce = -stiffness * displacement;\n const dampingForce = -damping * velocity;\n const acceleration = (springForce + dampingForce) / mass;\n\n velocity += acceleration * (1 / 60); // Assuming 60fps\n current += velocity * (1 / 60);\n\n notifyListeners();\n\n // Check if spring has settled\n if (Math.abs(velocity) < precision && Math.abs(displacement) < precision) {\n current = target;\n velocity = 0;\n animationFrame = null;\n notifyListeners();\n resolvePromise?.();\n resolvePromise = null;\n return;\n }\n\n animationFrame = requestAnimationFrame(step);\n };\n\n return {\n to(newTarget: number): Promise<void> {\n target = newTarget;\n\n if (animationFrame !== null) {\n cancelAnimationFrame(animationFrame);\n }\n\n return new Promise((resolve) => {\n resolvePromise = resolve;\n animationFrame = requestAnimationFrame(step);\n });\n },\n\n current(): number {\n return current;\n },\n\n stop(): void {\n if (animationFrame !== null) {\n cancelAnimationFrame(animationFrame);\n animationFrame = null;\n }\n velocity = 0;\n resolvePromise?.();\n resolvePromise = null;\n },\n\n onChange(callback: (value: number) => void): () => void {\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n };\n};\n\n/**\n * Preset spring configurations for common use cases.\n */\nexport const springPresets = {\n /** Gentle, slow-settling spring */\n gentle: { stiffness: 80, damping: 15 } as SpringConfig,\n /** Responsive, snappy spring */\n snappy: { stiffness: 200, damping: 20 } as SpringConfig,\n /** Bouncy, playful spring */\n bouncy: { stiffness: 300, damping: 8 } as SpringConfig,\n /** Stiff, quick spring with minimal overshoot */\n stiff: { stiffness: 400, damping: 30 } as SpringConfig,\n};\n","/**\n * Storage Buckets API wrapper.\n * Provides a simplified interface for storing blobs and binary data.\n * Falls back to IndexedDB when Storage Buckets API is not available.\n */\n\n/**\n * Bucket interface for blob storage operations.\n */\nexport interface Bucket {\n /**\n * Store a blob in the bucket.\n * @param key - Unique identifier for the blob\n * @param data - Blob data to store\n */\n put(key: string, data: Blob): Promise<void>;\n\n /**\n * Retrieve a blob from the bucket.\n * @param key - Blob identifier\n * @returns The stored blob or null if not found\n */\n get(key: string): Promise<Blob | null>;\n\n /**\n * Remove a blob from the bucket.\n * @param key - Blob identifier\n */\n remove(key: string): Promise<void>;\n\n /**\n * List all keys in the bucket.\n * @returns Array of blob keys\n */\n keys(): Promise<string[]>;\n}\n\n/**\n * IndexedDB-based bucket implementation.\n * Used as fallback when Storage Buckets API is unavailable.\n */\nclass IndexedDBBucket implements Bucket {\n private dbPromise: Promise<IDBDatabase> | null = null;\n private readonly storeName = 'blobs';\n\n constructor(private readonly bucketName: string) {}\n\n private openDB(): Promise<IDBDatabase> {\n if (this.dbPromise) return this.dbPromise;\n\n const dbName = `bquery-bucket-${this.bucketName}`;\n this.dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(dbName, 1);\n\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(this.storeName)) {\n db.createObjectStore(this.storeName);\n }\n };\n\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n\n return this.dbPromise;\n }\n\n private async withStore<T>(\n mode: IDBTransactionMode,\n operation: (store: IDBObjectStore) => IDBRequest<T>\n ): Promise<T> {\n const db = await this.openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.storeName, mode);\n const store = tx.objectStore(this.storeName);\n const request = operation(store);\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n\n async put(key: string, data: Blob): Promise<void> {\n await this.withStore('readwrite', (store) => store.put(data, key));\n }\n\n async get(key: string): Promise<Blob | null> {\n const result = await this.withStore<Blob | undefined>('readonly', (store) => store.get(key));\n return result ?? null;\n }\n\n async remove(key: string): Promise<void> {\n await this.withStore('readwrite', (store) => store.delete(key));\n }\n\n async keys(): Promise<string[]> {\n const result = await this.withStore<IDBValidKey[]>('readonly', (store) => store.getAllKeys());\n return result.map((key) => String(key));\n }\n}\n\n/**\n * Bucket manager for creating and accessing storage buckets.\n */\nexport const buckets = {\n /**\n * Open or create a storage bucket.\n * @param name - Bucket name\n * @returns Bucket instance for blob operations\n */\n async open(name: string): Promise<Bucket> {\n // Storage Buckets API is experimental; use IndexedDB fallback\n return new IndexedDBBucket(name);\n },\n};\n","/**\n * Cache Storage API wrapper.\n * Provides a simplified interface for caching responses and assets.\n */\n\n/**\n * Cache handle interface for managing cached resources.\n */\nexport interface CacheHandle {\n /**\n * Add a resource to the cache by URL.\n * Fetches the resource and stores the response.\n * @param url - URL to fetch and cache\n */\n add(url: string): Promise<void>;\n\n /**\n * Add multiple resources to the cache.\n * @param urls - Array of URLs to fetch and cache\n */\n addAll(urls: string[]): Promise<void>;\n\n /**\n * Store a custom response in the cache.\n * @param url - URL key for the cached response\n * @param response - Response object to cache\n */\n put(url: string, response: Response): Promise<void>;\n\n /**\n * Retrieve a cached response.\n * @param url - URL to look up\n * @returns Cached Response or undefined if not found\n */\n match(url: string): Promise<Response | undefined>;\n\n /**\n * Remove a cached response.\n * @param url - URL to remove from cache\n * @returns True if the entry was deleted\n */\n remove(url: string): Promise<boolean>;\n\n /**\n * Get all cached request URLs.\n * @returns Array of cached URLs\n */\n keys(): Promise<string[]>;\n}\n\n/**\n * Internal cache handle implementation.\n */\nclass CacheHandleImpl implements CacheHandle {\n constructor(private readonly cache: Cache) {}\n\n async add(url: string): Promise<void> {\n await this.cache.add(url);\n }\n\n async addAll(urls: string[]): Promise<void> {\n await this.cache.addAll(urls);\n }\n\n async put(url: string, response: Response): Promise<void> {\n await this.cache.put(url, response);\n }\n\n async match(url: string): Promise<Response | undefined> {\n return this.cache.match(url);\n }\n\n async remove(url: string): Promise<boolean> {\n return this.cache.delete(url);\n }\n\n async keys(): Promise<string[]> {\n const requests = await this.cache.keys();\n return requests.map((req) => req.url);\n }\n}\n\n/**\n * Cache manager for accessing the Cache Storage API.\n */\nexport const cache = {\n /**\n * Check if Cache Storage API is supported.\n * @returns True if caches API is available\n */\n isSupported(): boolean {\n return 'caches' in window;\n },\n\n /**\n * Open or create a named cache.\n * @param name - Cache name\n * @returns CacheHandle for cache operations\n */\n async open(name: string): Promise<CacheHandle> {\n if (!this.isSupported()) {\n throw new Error('bQuery: Cache Storage API not supported');\n }\n const c = await caches.open(name);\n return new CacheHandleImpl(c);\n },\n\n /**\n * Delete a named cache.\n * @param name - Cache name to delete\n * @returns True if the cache was deleted\n */\n async delete(name: string): Promise<boolean> {\n if (!this.isSupported()) {\n return false;\n }\n return caches.delete(name);\n },\n\n /**\n * List all cache names.\n * @returns Array of cache names\n */\n async keys(): Promise<string[]> {\n if (!this.isSupported()) {\n return [];\n }\n return caches.keys();\n },\n};\n","/**\n * Web Notifications API wrapper.\n * Provides a simplified interface for browser notifications.\n */\n\n/**\n * Notification options matching the standard NotificationOptions interface.\n */\nexport interface NotificationOptions {\n /** Body text of the notification */\n body?: string;\n /** Icon URL for the notification */\n icon?: string;\n /** Badge icon for mobile devices */\n badge?: string;\n /** Tag for grouping notifications */\n tag?: string;\n /** Whether to require user interaction */\n requireInteraction?: boolean;\n /** Vibration pattern for mobile devices */\n vibrate?: number[];\n /** Additional data attached to the notification */\n data?: unknown;\n}\n\n/**\n * Notifications manager providing a clean interface for web notifications.\n */\nexport const notifications = {\n /**\n * Check if notifications are supported.\n * @returns True if Notification API is available\n */\n isSupported(): boolean {\n return 'Notification' in window;\n },\n\n /**\n * Get current permission status.\n * @returns Current permission state\n */\n getPermission(): NotificationPermission {\n if (!this.isSupported()) return 'denied';\n return Notification.permission;\n },\n\n /**\n * Request notification permission from the user.\n * @returns Promise resolving to the permission result\n */\n async requestPermission(): Promise<NotificationPermission> {\n if (!this.isSupported()) {\n return 'denied';\n }\n\n if (Notification.permission === 'granted') {\n return 'granted';\n }\n\n if (Notification.permission === 'denied') {\n return 'denied';\n }\n\n return Notification.requestPermission();\n },\n\n /**\n * Send a notification.\n * Requires 'granted' permission.\n * @param title - Notification title\n * @param options - Optional notification settings\n * @returns The Notification instance or null if not permitted\n */\n send(title: string, options?: NotificationOptions): Notification | null {\n if (!this.isSupported()) {\n console.warn('bQuery: Notifications not supported in this browser');\n return null;\n }\n\n if (Notification.permission !== 'granted') {\n console.warn('bQuery: Notification permission not granted');\n return null;\n }\n\n return new Notification(title, options);\n },\n};\n","/**\n * Unified storage adapters for web platform storage APIs.\n * Provides a consistent, promise-based interface with predictable errors.\n */\n\n/**\n * Common interface for all storage adapters.\n * All methods return promises for a unified async API.\n */\nexport interface StorageAdapter {\n /**\n * Retrieve a value by key.\n * @param key - The storage key\n * @returns The stored value or null if not found\n */\n get<T>(key: string): Promise<T | null>;\n\n /**\n * Store a value by key.\n * @param key - The storage key\n * @param value - The value to store\n */\n set<T>(key: string, value: T): Promise<void>;\n\n /**\n * Remove a value by key.\n * @param key - The storage key\n */\n remove(key: string): Promise<void>;\n\n /**\n * Clear all stored values.\n */\n clear(): Promise<void>;\n\n /**\n * Get all storage keys.\n * @returns Array of all keys\n */\n keys(): Promise<string[]>;\n}\n\n/**\n * Abstract base class for web storage adapters (localStorage/sessionStorage).\n * Implements DRY principle by sharing common logic.\n */\nabstract class WebStorageAdapter implements StorageAdapter {\n constructor(protected readonly storage: Storage) {}\n\n async get<T>(key: string): Promise<T | null> {\n const raw = this.storage.getItem(key);\n if (raw === null) return null;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return raw as unknown as T;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n const serialized = typeof value === 'string' ? value : JSON.stringify(value);\n this.storage.setItem(key, serialized);\n }\n\n async remove(key: string): Promise<void> {\n this.storage.removeItem(key);\n }\n\n async clear(): Promise<void> {\n this.storage.clear();\n }\n\n async keys(): Promise<string[]> {\n return Object.keys(this.storage);\n }\n}\n\n/**\n * localStorage adapter with async interface.\n */\nclass LocalStorageAdapter extends WebStorageAdapter {\n constructor() {\n super(localStorage);\n }\n}\n\n/**\n * sessionStorage adapter with async interface.\n */\nclass SessionStorageAdapter extends WebStorageAdapter {\n constructor() {\n super(sessionStorage);\n }\n}\n\n/**\n * IndexedDB configuration options.\n */\nexport interface IndexedDBOptions {\n /** Database name */\n name: string;\n /** Object store name */\n store: string;\n /** Database version (optional) */\n version?: number;\n}\n\n/**\n * IndexedDB key-value adapter.\n * Wraps IndexedDB with a simple key-value interface.\n */\nclass IndexedDBAdapter implements StorageAdapter {\n private dbPromise: Promise<IDBDatabase> | null = null;\n\n constructor(private readonly options: IndexedDBOptions) {}\n\n /**\n * Opens or creates the IndexedDB database.\n */\n private openDB(): Promise<IDBDatabase> {\n if (this.dbPromise) return this.dbPromise;\n\n this.dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(this.options.name, this.options.version ?? 1);\n\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(this.options.store)) {\n db.createObjectStore(this.options.store);\n }\n };\n\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n\n return this.dbPromise;\n }\n\n /**\n * Executes a transaction on the object store.\n */\n private async withStore<T>(\n mode: IDBTransactionMode,\n operation: (store: IDBObjectStore) => IDBRequest<T>\n ): Promise<T> {\n const db = await this.openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.options.store, mode);\n const store = tx.objectStore(this.options.store);\n const request = operation(store);\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n\n async get<T>(key: string): Promise<T | null> {\n const result = await this.withStore<T | undefined>('readonly', (store) => store.get(key));\n return result ?? null;\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n await this.withStore('readwrite', (store) => store.put(value, key));\n }\n\n async remove(key: string): Promise<void> {\n await this.withStore('readwrite', (store) => store.delete(key));\n }\n\n async clear(): Promise<void> {\n await this.withStore('readwrite', (store) => store.clear());\n }\n\n async keys(): Promise<string[]> {\n const result = await this.withStore<IDBValidKey[]>('readonly', (store) => store.getAllKeys());\n return result.map((key) => String(key));\n }\n}\n\n/**\n * Storage factory providing access to different storage adapters.\n */\nexport const storage = {\n /**\n * Create a localStorage adapter.\n * @returns StorageAdapter wrapping localStorage\n */\n local(): StorageAdapter {\n return new LocalStorageAdapter();\n },\n\n /**\n * Create a sessionStorage adapter.\n * @returns StorageAdapter wrapping sessionStorage\n */\n session(): StorageAdapter {\n return new SessionStorageAdapter();\n },\n\n /**\n * Create an IndexedDB adapter with key-value interface.\n * @param options - Database and store configuration\n * @returns StorageAdapter wrapping IndexedDB\n */\n indexedDB(options: IndexedDBOptions): StorageAdapter {\n return new IndexedDBAdapter(options);\n },\n};\n","/**\r\n * Minimal SPA router with History API integration.\r\n *\r\n * This module provides a lightweight, signal-based router for single-page\r\n * applications. Features include:\r\n * - History API navigation\r\n * - Route matching with params and wildcards\r\n * - Lazy route loading\r\n * - Navigation guards (beforeEach, afterEach)\r\n * - Reactive current route via signals\r\n * - Multi-value query params (e.g., `?tag=a&tag=b` → `{ tag: ['a', 'b'] }`)\r\n *\r\n * @module bquery/router\r\n *\r\n * @example\r\n * ```ts\r\n * import { createRouter, navigate, currentRoute } from 'bquery/router';\r\n * import { effect } from 'bquery/reactive';\r\n *\r\n * const router = createRouter({\r\n * routes: [\r\n * { path: '/', component: () => import('./Home') },\r\n * { path: '/user/:id', component: () => import('./User') },\r\n * { path: '*', component: () => import('./NotFound') },\r\n * ],\r\n * });\r\n *\r\n * effect(() => {\r\n * console.log('Route changed:', currentRoute.value);\r\n * });\r\n *\r\n * navigate('/user/42');\r\n * ```\r\n */\r\n\r\nimport { computed, signal, type ReadonlySignal, type Signal } from '../reactive/index';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Represents a parsed route with matched params.\r\n */\r\nexport type Route = {\r\n /** The current path (e.g., '/user/42') */\r\n path: string;\r\n /** Extracted route params (e.g., { id: '42' }) */\r\n params: Record<string, string>;\r\n /**\r\n * Query string params.\r\n * Each key maps to a single string value by default.\r\n * Only keys that appear multiple times in the query string become arrays.\r\n * @example\r\n * // ?foo=1 → { foo: '1' }\r\n * // ?tag=a&tag=b → { tag: ['a', 'b'] }\r\n * // ?x=1&y=2&x=3 → { x: ['1', '3'], y: '2' }\r\n */\r\n query: Record<string, string | string[]>;\r\n /** The matched route definition */\r\n matched: RouteDefinition | null;\r\n /** Hash fragment without # */\r\n hash: string;\r\n};\r\n\r\n/**\r\n * Route definition for configuration.\r\n */\r\nexport type RouteDefinition = {\r\n /** Path pattern (e.g., '/user/:id', '/posts/*') */\r\n path: string;\r\n /** Component loader (sync or async) */\r\n component: () => unknown | Promise<unknown>;\r\n /** Optional route name for programmatic navigation */\r\n name?: string;\r\n /** Optional metadata */\r\n meta?: Record<string, unknown>;\r\n /** Nested child routes */\r\n children?: RouteDefinition[];\r\n};\r\n\r\n/**\r\n * Router configuration options.\r\n */\r\nexport type RouterOptions = {\r\n /** Array of route definitions */\r\n routes: RouteDefinition[];\r\n /** Base path for all routes (default: '') */\r\n base?: string;\r\n /** Use hash-based routing instead of history (default: false) */\r\n hash?: boolean;\r\n};\r\n\r\n/**\r\n * Navigation guard function type.\r\n */\r\nexport type NavigationGuard = (to: Route, from: Route) => boolean | void | Promise<boolean | void>;\r\n\r\n/**\r\n * Router instance returned by createRouter.\r\n */\r\nexport type Router = {\r\n /** Navigate to a path */\r\n push: (path: string) => Promise<void>;\r\n /** Replace current history entry */\r\n replace: (path: string) => Promise<void>;\r\n /** Go back in history */\r\n back: () => void;\r\n /** Go forward in history */\r\n forward: () => void;\r\n /** Go to a specific history entry */\r\n go: (delta: number) => void;\r\n /** Add a beforeEach guard */\r\n beforeEach: (guard: NavigationGuard) => () => void;\r\n /** Add an afterEach hook */\r\n afterEach: (hook: (to: Route, from: Route) => void) => () => void;\r\n /** Current route (reactive) */\r\n currentRoute: ReadonlySignal<Route>;\r\n /** All route definitions */\r\n routes: RouteDefinition[];\r\n /** Destroy the router and cleanup listeners */\r\n destroy: () => void;\r\n};\r\n\r\n// ============================================================================\r\n// Internal State\r\n// ============================================================================\r\n\r\n/** @internal */\r\nlet activeRouter: Router | null = null;\r\n\r\n/** @internal */\r\nconst routeSignal: Signal<Route> = signal<Route>({\r\n path: '',\r\n params: {},\r\n query: {},\r\n matched: null,\r\n hash: '',\r\n});\r\n\r\n/**\r\n * Reactive signal containing the current route.\r\n *\r\n * @example\r\n * ```ts\r\n * import { currentRoute } from 'bquery/router';\r\n * import { effect } from 'bquery/reactive';\r\n *\r\n * effect(() => {\r\n * document.title = `Page: ${currentRoute.value.path}`;\r\n * });\r\n * ```\r\n */\r\nexport const currentRoute: ReadonlySignal<Route> = computed(() => routeSignal.value);\r\n\r\n// ============================================================================\r\n// Route Matching\r\n// ============================================================================\r\n\r\n/**\r\n * Converts a route path pattern to a RegExp for matching.\r\n * Uses placeholder approach to preserve :param and * patterns during escaping.\r\n * @internal\r\n */\r\nconst pathToRegex = (path: string): RegExp => {\r\n // Handle wildcard-only route\r\n if (path === '*') {\r\n return /^.*$/;\r\n }\r\n\r\n // Unique placeholders using null chars (won't appear in normal paths)\r\n const PARAM_MARKER = '\\u0000P\\u0000';\r\n const WILDCARD_MARKER = '\\u0000W\\u0000';\r\n\r\n // Store param names for restoration\r\n const paramNames: string[] = [];\r\n\r\n // Step 1: Extract :param patterns before escaping\r\n let pattern = path.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, (_, name) => {\r\n paramNames.push(name);\r\n return PARAM_MARKER;\r\n });\r\n\r\n // Step 2: Extract * wildcards before escaping\r\n pattern = pattern.replace(/\\*/g, WILDCARD_MARKER);\r\n\r\n // Step 3: Escape ALL regex metacharacters: \\ ^ $ . * + ? ( ) [ ] { } |\r\n pattern = pattern.replace(/[\\\\^$.*+?()[\\]{}|]/g, '\\\\$&');\r\n\r\n // Step 4: Restore param capture groups\r\n let paramIdx = 0;\r\n pattern = pattern.replace(/\\u0000P\\u0000/g, () => `(?<${paramNames[paramIdx++]}>[^/]+)`);\r\n\r\n // Step 5: Restore wildcards as .*\r\n pattern = pattern.replace(/\\u0000W\\u0000/g, '.*');\r\n\r\n return new RegExp(`^${pattern}$`);\r\n};\r\n\r\n/**\r\n * Extracts param names from a route path.\r\n * @internal\r\n */\r\nconst extractParamNames = (path: string): string[] => {\r\n const matches = path.match(/:([a-zA-Z_][a-zA-Z0-9_]*)/g);\r\n return matches ? matches.map((m) => m.slice(1)) : [];\r\n};\r\n\r\n/**\r\n * Matches a path against route definitions and extracts params.\r\n * @internal\r\n */\r\nconst matchRoute = (\r\n path: string,\r\n routes: RouteDefinition[]\r\n): { matched: RouteDefinition; params: Record<string, string> } | null => {\r\n for (const route of routes) {\r\n const regex = pathToRegex(route.path);\r\n const match = path.match(regex);\r\n\r\n if (match) {\r\n const paramNames = extractParamNames(route.path);\r\n const params: Record<string, string> = {};\r\n\r\n // Extract named groups if available\r\n if (match.groups) {\r\n Object.assign(params, match.groups);\r\n } else {\r\n // Fallback for browsers without named groups\r\n paramNames.forEach((name, index) => {\r\n params[name] = match[index + 1] || '';\r\n });\r\n }\r\n\r\n return { matched: route, params };\r\n }\r\n }\r\n\r\n return null;\r\n};\r\n\r\n/**\r\n * Parses query string into an object.\r\n * Single values are stored as strings, duplicate keys become arrays.\r\n * @internal\r\n *\r\n * @example\r\n * parseQuery('?foo=1') // { foo: '1' }\r\n * parseQuery('?tag=a&tag=b') // { tag: ['a', 'b'] }\r\n * parseQuery('?x=1&y=2&x=3') // { x: ['1', '3'], y: '2' }\r\n */\r\nconst parseQuery = (search: string): Record<string, string | string[]> => {\r\n const query: Record<string, string | string[]> = {};\r\n const params = new URLSearchParams(search);\r\n\r\n params.forEach((value, key) => {\r\n const existing = query[key];\r\n if (existing === undefined) {\r\n // First occurrence: store as string\r\n query[key] = value;\r\n } else if (Array.isArray(existing)) {\r\n // Already an array: append\r\n existing.push(value);\r\n } else {\r\n // Second occurrence: convert to array\r\n query[key] = [existing, value];\r\n }\r\n });\r\n\r\n return query;\r\n};\r\n\r\n/**\r\n * Creates a Route object from the current URL.\r\n * @internal\r\n */\r\nconst createRoute = (\r\n pathname: string,\r\n search: string,\r\n hash: string,\r\n routes: RouteDefinition[]\r\n): Route => {\r\n const result = matchRoute(pathname, routes);\r\n\r\n return {\r\n path: pathname,\r\n params: result?.params ?? {},\r\n query: parseQuery(search),\r\n matched: result?.matched ?? null,\r\n hash: hash.replace(/^#/, ''),\r\n };\r\n};\r\n\r\n// ============================================================================\r\n// Navigation\r\n// ============================================================================\r\n\r\n/**\r\n * Navigates to a new path.\r\n *\r\n * @param path - The path to navigate to\r\n * @param options - Navigation options\r\n *\r\n * @example\r\n * ```ts\r\n * import { navigate } from 'bquery/router';\r\n *\r\n * // Push to history\r\n * await navigate('/dashboard');\r\n *\r\n * // Replace current entry\r\n * await navigate('/login', { replace: true });\r\n * ```\r\n */\r\nexport const navigate = async (\r\n path: string,\r\n options: { replace?: boolean } = {}\r\n): Promise<void> => {\r\n if (!activeRouter) {\r\n throw new Error('bQuery router: No router initialized. Call createRouter() first.');\r\n }\r\n\r\n await activeRouter[options.replace ? 'replace' : 'push'](path);\r\n};\r\n\r\n/**\r\n * Programmatically go back in history.\r\n *\r\n * @example\r\n * ```ts\r\n * import { back } from 'bquery/router';\r\n * back();\r\n * ```\r\n */\r\nexport const back = (): void => {\r\n if (activeRouter) {\r\n activeRouter.back();\r\n } else {\r\n history.back();\r\n }\r\n};\r\n\r\n/**\r\n * Programmatically go forward in history.\r\n *\r\n * @example\r\n * ```ts\r\n * import { forward } from 'bquery/router';\r\n * forward();\r\n * ```\r\n */\r\nexport const forward = (): void => {\r\n if (activeRouter) {\r\n activeRouter.forward();\r\n } else {\r\n history.forward();\r\n }\r\n};\r\n\r\n// ============================================================================\r\n// Router Creation\r\n// ============================================================================\r\n\r\n/**\r\n * Creates and initializes a router instance.\r\n *\r\n * @param options - Router configuration\r\n * @returns The router instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { createRouter } from 'bquery/router';\r\n *\r\n * const router = createRouter({\r\n * routes: [\r\n * { path: '/', component: () => import('./pages/Home') },\r\n * { path: '/about', component: () => import('./pages/About') },\r\n * { path: '/user/:id', component: () => import('./pages/User') },\r\n * { path: '*', component: () => import('./pages/NotFound') },\r\n * ],\r\n * base: '/app',\r\n * });\r\n *\r\n * router.beforeEach((to, from) => {\r\n * if (to.path === '/admin' && !isAuthenticated()) {\r\n * return false; // Cancel navigation\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport const createRouter = (options: RouterOptions): Router => {\r\n // Clean up any existing router to prevent guard leakage\r\n if (activeRouter) {\r\n activeRouter.destroy();\r\n }\r\n\r\n const { routes, base = '', hash: useHash = false } = options;\r\n\r\n // Instance-specific guards and hooks (not shared globally)\r\n const beforeGuards: NavigationGuard[] = [];\r\n const afterHooks: Array<(to: Route, from: Route) => void> = [];\r\n\r\n // Flatten nested routes\r\n const flatRoutes = flattenRoutes(routes, base);\r\n\r\n /**\r\n * Gets the current path from the URL.\r\n */\r\n const getCurrentPath = (): { pathname: string; search: string; hash: string } => {\r\n if (useHash) {\r\n const hashPath = window.location.hash.slice(1) || '/';\r\n const [pathname, rest = ''] = hashPath.split('?');\r\n const [search, hashPart = ''] = rest.split('#');\r\n return {\r\n pathname,\r\n search: search ? `?${search}` : '',\r\n hash: hashPart ? `#${hashPart}` : '',\r\n };\r\n }\r\n\r\n let pathname = window.location.pathname;\r\n if (base && pathname.startsWith(base)) {\r\n pathname = pathname.slice(base.length) || '/';\r\n }\r\n\r\n return {\r\n pathname,\r\n search: window.location.search,\r\n hash: window.location.hash,\r\n };\r\n };\r\n\r\n /**\r\n * Updates the route signal with current URL state.\r\n */\r\n const syncRoute = (): void => {\r\n const { pathname, search, hash } = getCurrentPath();\r\n const newRoute = createRoute(pathname, search, hash, flatRoutes);\r\n routeSignal.value = newRoute;\r\n };\r\n\r\n /**\r\n * Performs navigation with guards.\r\n */\r\n const performNavigation = async (\r\n path: string,\r\n method: 'pushState' | 'replaceState'\r\n ): Promise<void> => {\r\n const { pathname, search, hash } = getCurrentPath();\r\n const from = createRoute(pathname, search, hash, flatRoutes);\r\n\r\n // Parse the target path\r\n const url = new URL(path, window.location.origin);\r\n const toPath = useHash ? path : url.pathname;\r\n const to = createRoute(toPath, url.search, url.hash, flatRoutes);\r\n\r\n // Run beforeEach guards\r\n for (const guard of beforeGuards) {\r\n const result = await guard(to, from);\r\n if (result === false) {\r\n return; // Cancel navigation\r\n }\r\n }\r\n\r\n // Update browser history\r\n const fullPath = useHash ? `#${path}` : `${base}${path}`;\r\n history[method]({}, '', fullPath);\r\n\r\n // Update route signal\r\n syncRoute();\r\n\r\n // Run afterEach hooks\r\n for (const hook of afterHooks) {\r\n hook(routeSignal.value, from);\r\n }\r\n };\r\n\r\n /**\r\n * Handle popstate events (back/forward).\r\n */\r\n const handlePopState = async (): Promise<void> => {\r\n const { pathname, search, hash } = getCurrentPath();\r\n const from = routeSignal.value;\r\n const to = createRoute(pathname, search, hash, flatRoutes);\r\n\r\n // Run beforeEach guards (supports async guards)\r\n for (const guard of beforeGuards) {\r\n const result = await guard(to, from);\r\n if (result === false) {\r\n // Restore previous state\r\n const restorePath = useHash ? `#${from.path}` : `${base}${from.path}`;\r\n history.pushState({}, '', restorePath);\r\n return;\r\n }\r\n }\r\n\r\n syncRoute();\r\n\r\n for (const hook of afterHooks) {\r\n hook(routeSignal.value, from);\r\n }\r\n };\r\n\r\n // Attach popstate listener\r\n window.addEventListener('popstate', handlePopState);\r\n\r\n // Initialize route\r\n syncRoute();\r\n\r\n const router: Router = {\r\n push: (path: string) => performNavigation(path, 'pushState'),\r\n replace: (path: string) => performNavigation(path, 'replaceState'),\r\n back: () => history.back(),\r\n forward: () => history.forward(),\r\n go: (delta: number) => history.go(delta),\r\n\r\n beforeEach: (guard: NavigationGuard) => {\r\n beforeGuards.push(guard);\r\n return () => {\r\n const index = beforeGuards.indexOf(guard);\r\n if (index > -1) beforeGuards.splice(index, 1);\r\n };\r\n },\r\n\r\n afterEach: (hook: (to: Route, from: Route) => void) => {\r\n afterHooks.push(hook);\r\n return () => {\r\n const index = afterHooks.indexOf(hook);\r\n if (index > -1) afterHooks.splice(index, 1);\r\n };\r\n },\r\n\r\n currentRoute,\r\n routes: flatRoutes,\r\n\r\n destroy: () => {\r\n window.removeEventListener('popstate', handlePopState);\r\n beforeGuards.length = 0;\r\n afterHooks.length = 0;\r\n activeRouter = null;\r\n },\r\n };\r\n\r\n activeRouter = router;\r\n return router;\r\n};\r\n\r\n// ============================================================================\r\n// Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Flattens nested routes into a single array with full paths.\r\n * @internal\r\n */\r\nconst flattenRoutes = (routes: RouteDefinition[], base = ''): RouteDefinition[] => {\r\n const result: RouteDefinition[] = [];\r\n\r\n for (const route of routes) {\r\n const fullPath = route.path === '*' ? '*' : `${base}${route.path}`.replace(/\\/+/g, '/');\r\n\r\n result.push({\r\n ...route,\r\n path: fullPath,\r\n });\r\n\r\n if (route.children) {\r\n result.push(...flattenRoutes(route.children, fullPath));\r\n }\r\n }\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Resolves a route by name and params.\r\n *\r\n * @param name - The route name\r\n * @param params - Route params to interpolate\r\n * @returns The resolved path\r\n *\r\n * @example\r\n * ```ts\r\n * import { resolve } from 'bquery/router';\r\n *\r\n * const path = resolve('user', { id: '42' });\r\n * // Returns '/user/42' if route is defined as { name: 'user', path: '/user/:id' }\r\n * ```\r\n */\r\nexport const resolve = (name: string, params: Record<string, string> = {}): string => {\r\n if (!activeRouter) {\r\n throw new Error('bQuery router: No router initialized.');\r\n }\r\n\r\n const route = activeRouter.routes.find((r) => r.name === name);\r\n if (!route) {\r\n throw new Error(`bQuery router: Route \"${name}\" not found.`);\r\n }\r\n\r\n let path = route.path;\r\n for (const [key, value] of Object.entries(params)) {\r\n path = path.replace(`:${key}`, encodeURIComponent(value));\r\n }\r\n\r\n return path;\r\n};\r\n\r\n/**\r\n * Checks if a path matches the current route.\r\n *\r\n * @param path - Path to check\r\n * @param exact - Whether to match exactly (default: false)\r\n * @returns True if the path matches\r\n *\r\n * @example\r\n * ```ts\r\n * import { isActive } from 'bquery/router';\r\n *\r\n * if (isActive('/dashboard')) {\r\n * // Highlight nav item\r\n * }\r\n * ```\r\n */\r\nexport const isActive = (path: string, exact = false): boolean => {\r\n const current = routeSignal.value.path;\r\n return exact ? current === path : current.startsWith(path);\r\n};\r\n\r\n/**\r\n * Creates a computed signal that checks if a path is active.\r\n *\r\n * @param path - Path to check\r\n * @param exact - Whether to match exactly\r\n * @returns A reactive signal\r\n *\r\n * @example\r\n * ```ts\r\n * import { isActiveSignal } from 'bquery/router';\r\n * import { effect } from 'bquery/reactive';\r\n *\r\n * const dashboardActive = isActiveSignal('/dashboard');\r\n * effect(() => {\r\n * navItem.classList.toggle('active', dashboardActive.value);\r\n * });\r\n * ```\r\n */\r\nexport const isActiveSignal = (path: string, exact = false): ReadonlySignal<boolean> => {\r\n return computed(() => {\r\n const current = routeSignal.value.path;\r\n return exact ? current === path : current.startsWith(path);\r\n });\r\n};\r\n\r\n// ============================================================================\r\n// Router Link Helper\r\n// ============================================================================\r\n\r\n/**\r\n * Creates click handler for router links.\r\n * Attach to anchor elements to enable client-side navigation.\r\n *\r\n * @param path - Target path\r\n * @param options - Navigation options\r\n * @returns Click event handler\r\n *\r\n * @example\r\n * ```ts\r\n * import { link } from 'bquery/router';\r\n * import { $ } from 'bquery/core';\r\n *\r\n * $('#nav-home').on('click', link('/'));\r\n * $('#nav-about').on('click', link('/about'));\r\n * ```\r\n */\r\nexport const link = (path: string, options: { replace?: boolean } = {}): ((e: Event) => void) => {\r\n return (e: Event) => {\r\n e.preventDefault();\r\n navigate(path, options);\r\n };\r\n};\r\n\r\n/**\r\n * Intercepts all link clicks within a container for client-side routing.\r\n * Only intercepts links with matching origins and no target attribute.\r\n *\r\n * @param container - The container element to intercept links in\r\n * @returns Cleanup function to remove the listener\r\n *\r\n * @example\r\n * ```ts\r\n * import { interceptLinks } from 'bquery/router';\r\n *\r\n * // Intercept all links in the app\r\n * const cleanup = interceptLinks(document.body);\r\n *\r\n * // Later, remove the interceptor\r\n * cleanup();\r\n * ```\r\n */\r\nexport const interceptLinks = (container: Element = document.body): (() => void) => {\r\n const handler = (e: Event) => {\r\n const target = e.target as HTMLElement;\r\n const anchor = target.closest('a');\r\n\r\n if (!anchor) return;\r\n if (anchor.target) return; // Has target attribute\r\n if (anchor.hasAttribute('download')) return;\r\n if (anchor.origin !== window.location.origin) return; // External link\r\n\r\n const path = anchor.pathname + anchor.search + anchor.hash;\r\n\r\n e.preventDefault();\r\n navigate(path);\r\n };\r\n\r\n container.addEventListener('click', handler);\r\n return () => container.removeEventListener('click', handler);\r\n};\r\n","/**\r\n * Minimal state management built on signals.\r\n *\r\n * This module provides a lightweight store pattern inspired by Pinia/Vuex\r\n * but built entirely on bQuery's reactive primitives. Features include:\r\n * - Signal-based reactive state\r\n * - Computed getters\r\n * - Actions with async support\r\n * - Devtools hooks for debugging\r\n * - Plugin system for extensions\r\n *\r\n * @module bquery/store\r\n *\r\n * @example\r\n * ```ts\r\n * import { createStore } from 'bquery/store';\r\n * import { effect } from 'bquery/reactive';\r\n *\r\n * const counterStore = createStore({\r\n * id: 'counter',\r\n * state: () => ({ count: 0 }),\r\n * getters: {\r\n * doubled: (state) => state.count * 2,\r\n * isPositive: (state) => state.count > 0,\r\n * },\r\n * actions: {\r\n * increment() {\r\n * this.count++;\r\n * },\r\n * async fetchAndSet(url: string) {\r\n * const response = await fetch(url);\r\n * const data = await response.json();\r\n * this.count = data.count;\r\n * },\r\n * },\r\n * });\r\n *\r\n * effect(() => {\r\n * console.log('Count:', counterStore.count);\r\n * console.log('Doubled:', counterStore.doubled);\r\n * });\r\n *\r\n * counterStore.increment();\r\n * ```\r\n */\r\n\r\nimport { batch, computed, signal, type ReadonlySignal, type Signal } from '../reactive/index';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Store state factory function.\r\n */\r\nexport type StateFactory<S> = () => S;\r\n\r\n/**\r\n * Getter definition - derives computed values from state.\r\n */\r\nexport type Getters<S, G> = {\r\n [K in keyof G]: (state: S, getters: G) => G[K];\r\n};\r\n\r\n/**\r\n * Action definition - methods that can modify state.\r\n */\r\nexport type Actions<S, A> = {\r\n [K in keyof A]: A[K] extends (...args: infer P) => infer R\r\n ? (this: S & A, ...args: P) => R\r\n : never;\r\n};\r\n\r\n/**\r\n * Store definition for createStore.\r\n */\r\nexport type StoreDefinition<\r\n S extends Record<string, unknown> = Record<string, unknown>,\r\n G extends Record<string, unknown> = Record<string, unknown>,\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n A extends Record<string, (...args: any[]) => any> = Record<string, never>,\r\n> = {\r\n /** Unique store identifier for devtools */\r\n id: string;\r\n /** State factory function */\r\n state: StateFactory<S>;\r\n /** Computed getters */\r\n getters?: Getters<S, G>;\r\n /** Action methods */\r\n actions?: A;\r\n};\r\n\r\n/**\r\n * The returned store instance with state, getters, and actions merged.\r\n */\r\nexport type Store<\r\n S extends Record<string, unknown>,\r\n G extends Record<string, unknown>,\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n A extends Record<string, (...args: any[]) => any>,\r\n> = S &\r\n G &\r\n A & {\r\n /** Store identifier */\r\n $id: string;\r\n /** Reset state to initial values */\r\n $reset: () => void;\r\n /** Subscribe to state changes */\r\n $subscribe: (callback: (state: S) => void) => () => void;\r\n /** Patch multiple state properties at once (shallow) */\r\n $patch: (partial: Partial<S> | ((state: S) => void)) => void;\r\n /**\r\n * Patch with deep reactivity support.\r\n * Unlike $patch, this method deep-clones nested objects before mutation,\r\n * ensuring that all changes trigger reactive updates.\r\n */\r\n $patchDeep: (partial: Partial<S> | ((state: S) => void)) => void;\r\n /** Get raw state object (non-reactive snapshot) */\r\n $state: S;\r\n };\r\n\r\n/**\r\n * Plugin that can extend store functionality.\r\n */\r\nexport type StorePlugin<S = unknown> = (context: {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n store: Store<any, any, any>;\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n options: StoreDefinition<any, any, any>;\r\n}) => Partial<S> | void;\r\n\r\n// ============================================================================\r\n// Internal State\r\n// ============================================================================\r\n\r\n/** @internal Registry of all stores for devtools */\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nconst storeRegistry = new Map<string, Store<any, any, any>>();\r\n\r\n// ============================================================================\r\n// Internal Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Check if a value is a plain object (not array, null, Date, etc.).\r\n * @internal\r\n */\r\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\r\n return (\r\n value !== null && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype\r\n );\r\n};\r\n\r\n/**\r\n * Deep clones an object. Used for deep reactivity support.\r\n * @internal\r\n */\r\nconst deepClone = <T>(obj: T): T => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map(deepClone) as T;\r\n }\r\n\r\n if (obj instanceof Date) {\r\n return new Date(obj.getTime()) as T;\r\n }\r\n\r\n if (obj instanceof Map) {\r\n return new Map(Array.from(obj.entries()).map(([k, v]) => [k, deepClone(v)])) as T;\r\n }\r\n\r\n if (obj instanceof Set) {\r\n return new Set(Array.from(obj).map(deepClone)) as T;\r\n }\r\n\r\n const cloned = {} as T;\r\n for (const key of Object.keys(obj)) {\r\n (cloned as Record<string, unknown>)[key] = deepClone((obj as Record<string, unknown>)[key]);\r\n }\r\n return cloned;\r\n};\r\n\r\n/**\r\n * Compares two values for deep equality.\r\n * @internal\r\n */\r\nconst deepEqual = (a: unknown, b: unknown): boolean => {\r\n if (a === b) return true;\r\n if (a === null || b === null) return false;\r\n if (typeof a !== 'object' || typeof b !== 'object') return false;\r\n\r\n if (Array.isArray(a) && Array.isArray(b)) {\r\n if (a.length !== b.length) return false;\r\n return a.every((item, i) => deepEqual(item, b[i]));\r\n }\r\n\r\n if (Array.isArray(a) !== Array.isArray(b)) return false;\r\n\r\n const keysA = Object.keys(a as object);\r\n const keysB = Object.keys(b as object);\r\n\r\n if (keysA.length !== keysB.length) return false;\r\n\r\n return keysA.every((key) =>\r\n deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])\r\n );\r\n};\r\n\r\n/**\r\n * Detects if nested objects were mutated but the reference stayed the same.\r\n * Returns the keys where nested mutations were detected.\r\n * @internal\r\n */\r\nconst detectNestedMutations = <S extends Record<string, unknown>>(\r\n before: S,\r\n after: S,\r\n signalValues: Map<keyof S, unknown>\r\n): Array<keyof S> => {\r\n const mutatedKeys: Array<keyof S> = [];\r\n\r\n for (const key of Object.keys(after) as Array<keyof S>) {\r\n const beforeValue = before[key];\r\n const afterValue = after[key];\r\n const signalValue = signalValues.get(key);\r\n\r\n // Check if it's the same reference but content changed\r\n if (\r\n signalValue === afterValue && // Same reference as signal\r\n isPlainObject(beforeValue) &&\r\n isPlainObject(afterValue) &&\r\n !deepEqual(beforeValue, afterValue)\r\n ) {\r\n mutatedKeys.push(key);\r\n }\r\n }\r\n\r\n return mutatedKeys;\r\n};\r\n\r\n/** @internal Flag to enable/disable development warnings */\r\nconst __DEV__ = (() => {\r\n try {\r\n // Check for Node.js environment\r\n const globalProcess = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;\r\n return typeof globalProcess !== 'undefined' && globalProcess.env?.NODE_ENV !== 'production';\r\n } catch {\r\n return true; // Default to dev mode if detection fails\r\n }\r\n})();\r\n\r\n/** @internal Registered plugins */\r\nconst plugins: StorePlugin[] = [];\r\n\r\n/** @internal Devtools hook */\r\ndeclare global {\r\n interface Window {\r\n __BQUERY_DEVTOOLS__?: {\r\n stores: Map<string, unknown>;\r\n onStoreCreated?: (id: string, store: unknown) => void;\r\n onStateChange?: (id: string, state: unknown) => void;\r\n };\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Store Creation\r\n// ============================================================================\r\n\r\n/**\r\n * Creates a reactive store with state, getters, and actions.\r\n *\r\n * @template S - State type\r\n * @template G - Getters type\r\n * @template A - Actions type\r\n * @param definition - Store definition\r\n * @returns The reactive store instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { createStore } from 'bquery/store';\r\n *\r\n * // Simple counter store\r\n * const useCounter = createStore({\r\n * id: 'counter',\r\n * state: () => ({ count: 0, step: 1 }),\r\n * getters: {\r\n * doubled: (state) => state.count * 2,\r\n * next: (state) => state.count + state.step,\r\n * },\r\n * actions: {\r\n * increment() {\r\n * this.count += this.step;\r\n * },\r\n * decrement() {\r\n * this.count -= this.step;\r\n * },\r\n * setStep(newStep: number) {\r\n * this.step = newStep;\r\n * },\r\n * async loadFromServer() {\r\n * const res = await fetch('/api/counter');\r\n * const data = await res.json();\r\n * this.count = data.count;\r\n * },\r\n * },\r\n * });\r\n *\r\n * // Use the store\r\n * useCounter.increment();\r\n * console.log(useCounter.count); // 1\r\n * console.log(useCounter.doubled); // 2\r\n * ```\r\n */\r\nexport const createStore = <\r\n S extends Record<string, unknown>,\r\n G extends Record<string, unknown> = Record<string, never>,\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n A extends Record<string, (...args: any[]) => any> = Record<string, never>,\r\n>(\r\n definition: StoreDefinition<S, G, A>\r\n): Store<S, G, A> => {\r\n const { id, state: stateFactory, getters = {} as Getters<S, G>, actions = {} as A } = definition;\r\n\r\n // Check for duplicate store IDs\r\n if (storeRegistry.has(id)) {\r\n console.warn(`bQuery store: Store \"${id}\" already exists. Returning existing instance.`);\r\n return storeRegistry.get(id) as Store<S, G, A>;\r\n }\r\n\r\n // Create initial state\r\n const initialState = stateFactory();\r\n\r\n // Create signals for each state property\r\n const stateSignals = new Map<keyof S, Signal<unknown>>();\r\n for (const key of Object.keys(initialState) as Array<keyof S>) {\r\n stateSignals.set(key, signal(initialState[key]));\r\n }\r\n\r\n // Subscribers for $subscribe\r\n const subscribers: Array<(state: S) => void> = [];\r\n\r\n /**\r\n * Notifies subscribers of state changes.\r\n * @internal\r\n */\r\n const notifySubscribers = (): void => {\r\n const currentState = getCurrentState();\r\n for (const callback of subscribers) {\r\n callback(currentState);\r\n }\r\n\r\n // Notify devtools\r\n if (typeof window !== 'undefined' && window.__BQUERY_DEVTOOLS__?.onStateChange) {\r\n window.__BQUERY_DEVTOOLS__.onStateChange(id, currentState);\r\n }\r\n };\r\n\r\n /**\r\n * Cached state proxy that lazily reads signal values.\r\n * Uses a Proxy to avoid creating new objects on each access.\r\n *\r\n * **Note:** This returns a shallow snapshot of the state. Nested object\r\n * mutations will NOT trigger reactive updates. For nested reactivity,\r\n * replace the entire object or use signals for nested properties.\r\n *\r\n * @internal\r\n */\r\n const stateProxy = new Proxy({} as S, {\r\n get: (_, prop: string | symbol) => {\r\n const key = prop as keyof S;\r\n if (stateSignals.has(key)) {\r\n return stateSignals.get(key)!.value;\r\n }\r\n return undefined;\r\n },\r\n ownKeys: () => Array.from(stateSignals.keys()) as string[],\r\n getOwnPropertyDescriptor: (_, prop) => {\r\n if (stateSignals.has(prop as keyof S)) {\r\n return { enumerable: true, configurable: true };\r\n }\r\n return undefined;\r\n },\r\n has: (_, prop) => stateSignals.has(prop as keyof S),\r\n });\r\n\r\n /**\r\n * Gets the current state.\r\n *\r\n * For subscriber notifications (where a plain object snapshot is needed),\r\n * this creates a shallow copy. For internal reads, use stateProxy directly.\r\n *\r\n * **Note:** Returns a shallow snapshot. Nested object mutations will NOT\r\n * trigger reactive updates. This differs from frameworks like Pinia that\r\n * use deep reactivity. To update nested state, replace the entire object:\r\n *\r\n * @example\r\n * ```ts\r\n * // ❌ Won't trigger updates\r\n * store.user.name = 'New Name';\r\n *\r\n * // ✅ Will trigger updates\r\n * store.user = { ...store.user, name: 'New Name' };\r\n * ```\r\n *\r\n * @internal\r\n */\r\n const getCurrentState = (): S => ({ ...stateProxy });\r\n\r\n // Create computed getters\r\n const getterComputed = new Map<keyof G, ReadonlySignal<unknown>>();\r\n\r\n // Build the store proxy\r\n const store = {} as Store<S, G, A>;\r\n\r\n // Define state properties with getters/setters\r\n for (const key of Object.keys(initialState) as Array<keyof S>) {\r\n Object.defineProperty(store, key, {\r\n get: () => stateSignals.get(key)!.value,\r\n set: (value: unknown) => {\r\n stateSignals.get(key)!.value = value;\r\n notifySubscribers();\r\n },\r\n enumerable: true,\r\n configurable: false,\r\n });\r\n }\r\n\r\n // Define getters as computed properties\r\n for (const key of Object.keys(getters) as Array<keyof G>) {\r\n const getterFn = getters[key];\r\n\r\n // Create computed that reads from state signals via proxy (more efficient)\r\n const computedGetter = computed(() => {\r\n const state = stateProxy;\r\n // For getter dependencies, pass a proxy that reads from computed getters\r\n const getterProxy = new Proxy({} as G, {\r\n get: (_, prop: string | symbol) => {\r\n const propKey = prop as keyof G;\r\n if (getterComputed.has(propKey)) {\r\n return getterComputed.get(propKey)!.value;\r\n }\r\n return undefined;\r\n },\r\n });\r\n return getterFn(state, getterProxy);\r\n });\r\n\r\n getterComputed.set(key, computedGetter as unknown as ReadonlySignal<unknown>);\r\n\r\n Object.defineProperty(store, key, {\r\n get: () => computedGetter.value,\r\n enumerable: true,\r\n configurable: false,\r\n });\r\n }\r\n\r\n // Bind actions to the store context\r\n for (const key of Object.keys(actions) as Array<keyof A>) {\r\n const actionFn = actions[key];\r\n\r\n // Wrap action to enable 'this' binding\r\n (store as Record<string, unknown>)[key as string] = function (...args: unknown[]) {\r\n // Create a context that allows 'this.property' access\r\n const context = new Proxy(store, {\r\n get: (target, prop) => {\r\n if (typeof prop === 'string' && stateSignals.has(prop as keyof S)) {\r\n return stateSignals.get(prop as keyof S)!.value;\r\n }\r\n return (target as Record<string, unknown>)[prop as string];\r\n },\r\n set: (_target, prop, value) => {\r\n if (typeof prop === 'string' && stateSignals.has(prop as keyof S)) {\r\n stateSignals.get(prop as keyof S)!.value = value;\r\n notifySubscribers();\r\n return true;\r\n }\r\n return false;\r\n },\r\n });\r\n\r\n return actionFn.apply(context, args);\r\n };\r\n }\r\n\r\n // Add store utility methods\r\n Object.defineProperties(store, {\r\n $id: {\r\n value: id,\r\n writable: false,\r\n enumerable: false,\r\n },\r\n $reset: {\r\n value: () => {\r\n const fresh = stateFactory();\r\n batch(() => {\r\n for (const [key, sig] of stateSignals) {\r\n sig.value = fresh[key];\r\n }\r\n });\r\n notifySubscribers();\r\n },\r\n writable: false,\r\n enumerable: false,\r\n },\r\n $subscribe: {\r\n value: (callback: (state: S) => void) => {\r\n subscribers.push(callback);\r\n return () => {\r\n const index = subscribers.indexOf(callback);\r\n if (index > -1) subscribers.splice(index, 1);\r\n };\r\n },\r\n writable: false,\r\n enumerable: false,\r\n },\r\n $patch: {\r\n value: (partial: Partial<S> | ((state: S) => void)) => {\r\n batch(() => {\r\n if (typeof partial === 'function') {\r\n // Capture state before mutation for nested mutation detection\r\n const stateBefore = __DEV__ ? deepClone(getCurrentState()) : null;\r\n const signalValuesBefore = __DEV__\r\n ? new Map(Array.from(stateSignals.entries()).map(([k, s]) => [k, s.value]))\r\n : null;\r\n\r\n // Mutation function\r\n const state = getCurrentState();\r\n partial(state);\r\n\r\n // Detect nested mutations in development mode\r\n if (__DEV__ && stateBefore && signalValuesBefore) {\r\n const mutatedKeys = detectNestedMutations(stateBefore, state, signalValuesBefore);\r\n if (mutatedKeys.length > 0) {\r\n console.warn(\r\n `[bQuery store \"${id}\"] Nested mutation detected in $patch() for keys: ${mutatedKeys.map(String).join(', ')}.\\n` +\r\n 'Nested object mutations do not trigger reactive updates because the store uses shallow reactivity.\\n' +\r\n 'To fix this, either:\\n' +\r\n ' 1. Replace the entire object: state.user = { ...state.user, name: \"New\" }\\n' +\r\n ' 2. Use $patchDeep() for automatic deep cloning\\n' +\r\n 'See: https://bquery.dev/guide/store#deep-reactivity'\r\n );\r\n }\r\n }\r\n\r\n for (const [key, value] of Object.entries(state) as Array<[keyof S, unknown]>) {\r\n if (stateSignals.has(key)) {\r\n stateSignals.get(key)!.value = value;\r\n }\r\n }\r\n } else {\r\n // Partial object\r\n for (const [key, value] of Object.entries(partial) as Array<[keyof S, unknown]>) {\r\n if (stateSignals.has(key)) {\r\n stateSignals.get(key)!.value = value;\r\n }\r\n }\r\n }\r\n });\r\n notifySubscribers();\r\n },\r\n writable: false,\r\n enumerable: false,\r\n },\r\n $patchDeep: {\r\n value: (partial: Partial<S> | ((state: S) => void)) => {\r\n batch(() => {\r\n if (typeof partial === 'function') {\r\n // Deep clone state before mutation to ensure new references\r\n const state = deepClone(getCurrentState());\r\n partial(state);\r\n\r\n for (const [key, value] of Object.entries(state) as Array<[keyof S, unknown]>) {\r\n if (stateSignals.has(key)) {\r\n stateSignals.get(key)!.value = value;\r\n }\r\n }\r\n } else {\r\n // Deep clone each value in partial to ensure new references\r\n for (const [key, value] of Object.entries(partial) as Array<[keyof S, unknown]>) {\r\n if (stateSignals.has(key)) {\r\n stateSignals.get(key)!.value = deepClone(value);\r\n }\r\n }\r\n }\r\n });\r\n notifySubscribers();\r\n },\r\n writable: false,\r\n enumerable: false,\r\n },\r\n $state: {\r\n get: () => getCurrentState(),\r\n enumerable: false,\r\n },\r\n });\r\n\r\n // Register store\r\n storeRegistry.set(id, store);\r\n\r\n // Apply plugins\r\n for (const plugin of plugins) {\r\n const extension = plugin({ store, options: definition });\r\n if (extension) {\r\n Object.assign(store, extension);\r\n }\r\n }\r\n\r\n // Notify devtools\r\n if (typeof window !== 'undefined') {\r\n if (!window.__BQUERY_DEVTOOLS__) {\r\n window.__BQUERY_DEVTOOLS__ = { stores: new Map() };\r\n }\r\n window.__BQUERY_DEVTOOLS__.stores.set(id, store);\r\n window.__BQUERY_DEVTOOLS__.onStoreCreated?.(id, store);\r\n }\r\n\r\n return store;\r\n};\r\n\r\n// ============================================================================\r\n// Store Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Retrieves an existing store by its ID.\r\n *\r\n * @param id - The store identifier\r\n * @returns The store instance or undefined if not found\r\n *\r\n * @example\r\n * ```ts\r\n * import { getStore } from 'bquery/store';\r\n *\r\n * const counter = getStore('counter');\r\n * if (counter) {\r\n * counter.increment();\r\n * }\r\n * ```\r\n */\r\nexport const getStore = <T = unknown>(id: string): T | undefined => {\r\n return storeRegistry.get(id) as T | undefined;\r\n};\r\n\r\n/**\r\n * Lists all registered store IDs.\r\n *\r\n * @returns Array of store IDs\r\n *\r\n * @example\r\n * ```ts\r\n * import { listStores } from 'bquery/store';\r\n *\r\n * console.log('Active stores:', listStores());\r\n * ```\r\n */\r\nexport const listStores = (): string[] => {\r\n return Array.from(storeRegistry.keys());\r\n};\r\n\r\n/**\r\n * Removes a store from the registry.\r\n *\r\n * @param id - The store identifier\r\n *\r\n * @example\r\n * ```ts\r\n * import { destroyStore } from 'bquery/store';\r\n *\r\n * destroyStore('counter');\r\n * ```\r\n */\r\nexport const destroyStore = (id: string): void => {\r\n storeRegistry.delete(id);\r\n if (typeof window !== 'undefined' && window.__BQUERY_DEVTOOLS__) {\r\n window.__BQUERY_DEVTOOLS__.stores.delete(id);\r\n }\r\n};\r\n\r\n/**\r\n * Registers a plugin that extends all stores.\r\n *\r\n * @param plugin - The plugin function\r\n *\r\n * @example\r\n * ```ts\r\n * import { registerPlugin } from 'bquery/store';\r\n *\r\n * // Add localStorage persistence\r\n * registerPlugin(({ store, options }) => {\r\n * const key = `bquery-store-${options.id}`;\r\n *\r\n * // Load saved state\r\n * const saved = localStorage.getItem(key);\r\n * if (saved) {\r\n * store.$patch(JSON.parse(saved));\r\n * }\r\n *\r\n * // Save on changes\r\n * store.$subscribe((state) => {\r\n * localStorage.setItem(key, JSON.stringify(state));\r\n * });\r\n * });\r\n * ```\r\n */\r\nexport const registerPlugin = (plugin: StorePlugin): void => {\r\n plugins.push(plugin);\r\n};\r\n\r\n// ============================================================================\r\n// Composition Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Creates a store with automatic persistence to localStorage.\r\n *\r\n * @param definition - Store definition\r\n * @param storageKey - Optional custom storage key\r\n * @returns The reactive store instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { createPersistedStore } from 'bquery/store';\r\n *\r\n * const settings = createPersistedStore({\r\n * id: 'settings',\r\n * state: () => ({\r\n * theme: 'dark',\r\n * language: 'en',\r\n * }),\r\n * });\r\n *\r\n * // State is automatically saved/loaded from localStorage\r\n * settings.theme = 'light';\r\n * ```\r\n */\r\nexport const createPersistedStore = <\r\n S extends Record<string, unknown>,\r\n G extends Record<string, unknown> = Record<string, never>,\r\n A extends Record<string, (...args: unknown[]) => unknown> = Record<string, never>,\r\n>(\r\n definition: StoreDefinition<S, G, A>,\r\n storageKey?: string\r\n): Store<S, G, A> => {\r\n const key = storageKey ?? `bquery-store-${definition.id}`;\r\n\r\n // Wrap state factory to load from storage\r\n const originalStateFactory = definition.state;\r\n definition.state = () => {\r\n const defaultState = originalStateFactory();\r\n\r\n if (typeof window !== 'undefined') {\r\n try {\r\n const saved = localStorage.getItem(key);\r\n if (saved) {\r\n return { ...defaultState, ...JSON.parse(saved) };\r\n }\r\n } catch {\r\n // Ignore parse errors\r\n }\r\n }\r\n\r\n return defaultState;\r\n };\r\n\r\n const store = createStore(definition);\r\n\r\n // Subscribe to save changes\r\n store.$subscribe((state) => {\r\n if (typeof window !== 'undefined') {\r\n try {\r\n localStorage.setItem(key, JSON.stringify(state));\r\n } catch {\r\n // Ignore quota errors\r\n }\r\n }\r\n });\r\n\r\n return store;\r\n};\r\n\r\n/**\r\n * Maps store state properties to a reactive object for use in components.\r\n *\r\n * @param store - The store instance\r\n * @param keys - State keys to map\r\n * @returns Object with mapped properties\r\n *\r\n * @example\r\n * ```ts\r\n * import { mapState } from 'bquery/store';\r\n *\r\n * const counter = useCounter();\r\n * const { count, step } = mapState(counter, ['count', 'step']);\r\n * ```\r\n */\r\nexport const mapState = <S extends Record<string, unknown>, K extends keyof S>(\r\n store: S,\r\n keys: K[]\r\n): Pick<S, K> => {\r\n const mapped = {} as Pick<S, K>;\r\n\r\n for (const key of keys) {\r\n Object.defineProperty(mapped, key, {\r\n get: () => store[key],\r\n enumerable: true,\r\n });\r\n }\r\n\r\n return mapped;\r\n};\r\n\r\n/**\r\n * Maps store actions to an object for easier destructuring.\r\n *\r\n * @param store - The store instance\r\n * @param keys - Action keys to map\r\n * @returns Object with mapped actions\r\n *\r\n * @example\r\n * ```ts\r\n * import { mapActions } from 'bquery/store';\r\n *\r\n * const counter = useCounter();\r\n * const { increment, decrement } = mapActions(counter, ['increment', 'decrement']);\r\n *\r\n * // Use directly\r\n * increment();\r\n * ```\r\n */\r\nexport const mapActions = <\r\n A extends Record<string, (...args: unknown[]) => unknown>,\r\n K extends keyof A,\r\n>(\r\n store: A,\r\n keys: K[]\r\n): Pick<A, K> => {\r\n const mapped = {} as Pick<A, K>;\r\n\r\n for (const key of keys) {\r\n (mapped as Record<string, unknown>)[key as string] = (...args: unknown[]) =>\r\n (store[key] as (...args: unknown[]) => unknown)(...args);\r\n }\r\n\r\n return mapped;\r\n};\r\n","/**\r\n * Declarative DOM bindings via data attributes.\r\n *\r\n * This module provides Vue/Svelte-style template directives without\r\n * requiring a compiler. Bindings are evaluated at runtime using\r\n * bQuery's reactive system. Features include:\r\n * - Conditional rendering (bq-if)\r\n * - List rendering (bq-for)\r\n * - Two-way binding (bq-model)\r\n * - Class binding (bq-class)\r\n * - Text/HTML binding (bq-text, bq-html)\r\n * - Attribute binding (bq-bind)\r\n * - Event binding (bq-on)\r\n *\r\n * ## Security Considerations\r\n *\r\n * **WARNING:** This module uses `new Function()` to evaluate expressions at runtime.\r\n * This is similar to Vue/Alpine's approach but carries inherent security risks:\r\n *\r\n * - **NEVER** use expressions derived from user input or untrusted sources\r\n * - Expressions should only come from developer-controlled templates\r\n * - The context object should not contain sensitive data that could be exfiltrated\r\n * - For user-generated content, use static bindings with sanitized values instead\r\n *\r\n * Since bQuery is runtime-only (no build-time compilation), expressions are evaluated\r\n * dynamically. If your application loads templates from external sources (APIs, databases),\r\n * ensure they are trusted and validated before mounting.\r\n *\r\n * ## Content Security Policy (CSP) Compatibility\r\n *\r\n * **IMPORTANT:** This module requires `'unsafe-eval'` in your CSP `script-src` directive.\r\n * The `new Function()` constructor used for expression evaluation will be blocked by\r\n * strict CSP policies that omit `'unsafe-eval'`.\r\n *\r\n * ### Required CSP Header\r\n * ```\r\n * Content-Security-Policy: script-src 'self' 'unsafe-eval';\r\n * ```\r\n *\r\n * ### CSP-Strict Alternatives\r\n *\r\n * If your application requires a strict CSP without `'unsafe-eval'`, consider these alternatives:\r\n *\r\n * 1. **Use bQuery's core reactive system directly** - Bind signals to DOM elements manually\r\n * using `effect()` without the view module's template directives:\r\n * ```ts\r\n * import { signal, effect } from 'bquery/reactive';\r\n * import { $ } from 'bquery';\r\n *\r\n * const count = signal(0);\r\n * effect(() => {\r\n * $('#counter').text(String(count.value));\r\n * });\r\n * ```\r\n *\r\n * 2. **Use bQuery's component module** - Web Components with typed props don't require\r\n * dynamic expression evaluation:\r\n * ```ts\r\n * import { component } from 'bquery/component';\r\n * component('my-counter', {\r\n * props: { count: { type: Number } },\r\n * render: ({ props }) => `<span>${props.count}</span>`,\r\n * });\r\n * ```\r\n *\r\n * 3. **Pre-compile templates at build time** - Use a build step to transform bq-* attributes\r\n * into static JavaScript (similar to Svelte/Vue SFC compilation). This is outside bQuery's\r\n * scope but can be achieved with custom Vite/Rollup plugins.\r\n *\r\n * The view module is designed for rapid prototyping and applications where CSP flexibility\r\n * is acceptable. For security-critical applications requiring strict CSP, use the alternatives above.\r\n *\r\n * @module bquery/view\r\n *\r\n * @example\r\n * ```html\r\n * <div id=\"app\">\r\n * <input bq-model=\"name\" />\r\n * <p bq-text=\"greeting\"></p>\r\n * <ul>\r\n * <li bq-for=\"item in items\" bq-text=\"item.name\"></li>\r\n * </ul>\r\n * <button bq-on:click=\"handleClick\">Click me</button>\r\n * <div bq-if=\"showDetails\" bq-class=\"{ active: isActive }\">\r\n * Details here\r\n * </div>\r\n * </div>\r\n * ```\r\n *\r\n * ```ts\r\n * import { mount } from 'bquery/view';\r\n * import { signal } from 'bquery/reactive';\r\n *\r\n * mount('#app', {\r\n * name: signal('World'),\r\n * greeting: computed(() => `Hello, ${name.value}!`),\r\n * items: signal([{ name: 'Item 1' }, { name: 'Item 2' }]),\r\n * showDetails: signal(true),\r\n * isActive: signal(false),\r\n * handleClick: () => console.log('Clicked!'),\r\n * });\r\n * ```\r\n */\r\n\r\nimport { effect, isComputed, isSignal, type CleanupFn, type Signal } from '../reactive/index';\r\nimport { sanitizeHtml } from '../security/index';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Context object passed to binding expressions.\r\n */\r\nexport type BindingContext = Record<string, unknown>;\r\n\r\n/**\r\n * Configuration options for mount.\r\n */\r\nexport type MountOptions = {\r\n /** Prefix for directive attributes (default: 'bq') */\r\n prefix?: string;\r\n /** Whether to sanitize bq-html content (default: true) */\r\n sanitize?: boolean;\r\n};\r\n\r\n/**\r\n * Mounted view instance.\r\n */\r\nexport type View = {\r\n /** The root element */\r\n el: Element;\r\n /** The binding context */\r\n context: BindingContext;\r\n /** Update the context and re-render */\r\n update: (newContext: Partial<BindingContext>) => void;\r\n /** Destroy the view and cleanup effects */\r\n destroy: () => void;\r\n};\r\n\r\n/**\r\n * Internal directive handler type.\r\n * @internal\r\n */\r\ntype DirectiveHandler = (\r\n el: Element,\r\n expression: string,\r\n context: BindingContext,\r\n cleanups: CleanupFn[]\r\n) => void;\r\n\r\n// ============================================================================\r\n// Expression Evaluation\r\n// ============================================================================\r\n\r\n/**\r\n * Evaluates an expression in the given context using `new Function()`.\r\n *\r\n * @security **WARNING:** This function uses dynamic code execution via `new Function()`.\r\n * - NEVER pass expressions derived from user input or untrusted sources\r\n * - Expressions should only come from developer-controlled templates\r\n * - Malicious expressions can access and exfiltrate context data\r\n * - Consider this equivalent to `eval()` in terms of security implications\r\n *\r\n * @internal\r\n */\r\nconst evaluate = <T = unknown>(expression: string, context: BindingContext): T => {\r\n try {\r\n // Build context keys for function scope\r\n const keys = Object.keys(context);\r\n const values = keys.map((key) => {\r\n const value = context[key];\r\n // Auto-unwrap signals/computed\r\n if (isSignal(value) || isComputed(value)) {\r\n return (value as Signal<unknown>).value;\r\n }\r\n return value;\r\n });\r\n\r\n // Create function with context variables in scope\r\n const fn = new Function(...keys, `return (${expression})`);\r\n return fn(...values) as T;\r\n } catch (error) {\r\n console.error(`bQuery view: Error evaluating \"${expression}\"`, error);\r\n return undefined as T;\r\n }\r\n};\r\n\r\n/**\r\n * Evaluates an expression and returns the raw value (for signal access).\r\n *\r\n * @security **WARNING:** Uses dynamic code execution. See {@link evaluate} for security notes.\r\n * @internal\r\n */\r\nconst evaluateRaw = <T = unknown>(expression: string, context: BindingContext): T => {\r\n try {\r\n const keys = Object.keys(context);\r\n const values = keys.map((key) => context[key]);\r\n const fn = new Function(...keys, `return (${expression})`);\r\n return fn(...values) as T;\r\n } catch (error) {\r\n console.error(`bQuery view: Error evaluating \"${expression}\"`, error);\r\n return undefined as T;\r\n }\r\n};\r\n\r\n/**\r\n * Parses object expression like \"{ active: isActive, disabled: !enabled }\".\r\n * Handles nested structures like function calls, arrays, and template literals.\r\n * @internal\r\n */\r\nconst parseObjectExpression = (expression: string): Record<string, string> => {\r\n const result: Record<string, string> = {};\r\n\r\n // Remove outer braces and trim\r\n const inner = expression\r\n .trim()\r\n .replace(/^\\{|\\}$/g, '')\r\n .trim();\r\n if (!inner) return result;\r\n\r\n // Split by comma at depth 0, respecting strings and nesting\r\n const parts: string[] = [];\r\n let current = '';\r\n let depth = 0;\r\n let inString: string | null = null;\r\n\r\n for (let i = 0; i < inner.length; i++) {\r\n const char = inner[i];\r\n const prevChar = i > 0 ? inner[i - 1] : '';\r\n\r\n // Handle string literals (including escape sequences)\r\n if ((char === '\"' || char === \"'\" || char === '`') && prevChar !== '\\\\') {\r\n if (inString === null) {\r\n inString = char;\r\n } else if (inString === char) {\r\n inString = null;\r\n }\r\n current += char;\r\n continue;\r\n }\r\n\r\n // Skip if inside string\r\n if (inString !== null) {\r\n current += char;\r\n continue;\r\n }\r\n\r\n // Track nesting depth for parentheses, brackets, and braces\r\n if (char === '(' || char === '[' || char === '{') {\r\n depth++;\r\n current += char;\r\n } else if (char === ')' || char === ']' || char === '}') {\r\n depth--;\r\n current += char;\r\n } else if (char === ',' && depth === 0) {\r\n // Top-level comma - split point\r\n parts.push(current.trim());\r\n current = '';\r\n } else {\r\n current += char;\r\n }\r\n }\r\n\r\n // Add the last part\r\n if (current.trim()) {\r\n parts.push(current.trim());\r\n }\r\n\r\n // Parse each part to extract key and value\r\n for (const part of parts) {\r\n // Find the first colon at depth 0 (to handle ternary operators in values)\r\n let colonIndex = -1;\r\n let partDepth = 0;\r\n let partInString: string | null = null;\r\n\r\n for (let i = 0; i < part.length; i++) {\r\n const char = part[i];\r\n const prevChar = i > 0 ? part[i - 1] : '';\r\n\r\n if ((char === '\"' || char === \"'\" || char === '`') && prevChar !== '\\\\') {\r\n if (partInString === null) {\r\n partInString = char;\r\n } else if (partInString === char) {\r\n partInString = null;\r\n }\r\n continue;\r\n }\r\n\r\n if (partInString !== null) continue;\r\n\r\n if (char === '(' || char === '[' || char === '{') {\r\n partDepth++;\r\n } else if (char === ')' || char === ']' || char === '}') {\r\n partDepth--;\r\n } else if (char === ':' && partDepth === 0) {\r\n colonIndex = i;\r\n break;\r\n }\r\n }\r\n\r\n if (colonIndex > -1) {\r\n const key = part\r\n .slice(0, colonIndex)\r\n .trim()\r\n .replace(/^['\"]|['\"]$/g, '');\r\n const value = part.slice(colonIndex + 1).trim();\r\n result[key] = value;\r\n }\r\n }\r\n\r\n return result;\r\n};\r\n\r\n// ============================================================================\r\n// Directive Handlers\r\n// ============================================================================\r\n\r\n/**\r\n * Handles bq-text directive - sets text content.\r\n * @internal\r\n */\r\nconst handleText: DirectiveHandler = (el, expression, context, cleanups) => {\r\n const cleanup = effect(() => {\r\n const value = evaluate(expression, context);\r\n el.textContent = String(value ?? '');\r\n });\r\n cleanups.push(cleanup);\r\n};\r\n\r\n/**\r\n * Handles bq-html directive - sets innerHTML (sanitized by default).\r\n * @internal\r\n */\r\nconst handleHtml = (sanitize: boolean): DirectiveHandler => {\r\n return (el, expression, context, cleanups) => {\r\n const cleanup = effect(() => {\r\n const value = evaluate<string>(expression, context);\r\n const html = String(value ?? '');\r\n el.innerHTML = sanitize ? sanitizeHtml(html) : html;\r\n });\r\n cleanups.push(cleanup);\r\n };\r\n};\r\n\r\n/**\r\n * Handles bq-if directive - conditional rendering.\r\n * @internal\r\n */\r\nconst handleIf: DirectiveHandler = (el, expression, context, cleanups) => {\r\n const parent = el.parentNode;\r\n const placeholder = document.createComment(`bq-if: ${expression}`);\r\n\r\n // Store original element state\r\n let isInserted = true;\r\n\r\n const cleanup = effect(() => {\r\n const condition = evaluate<boolean>(expression, context);\r\n\r\n if (condition && !isInserted) {\r\n // Insert element\r\n parent?.replaceChild(el, placeholder);\r\n isInserted = true;\r\n } else if (!condition && isInserted) {\r\n // Remove element\r\n parent?.replaceChild(placeholder, el);\r\n isInserted = false;\r\n }\r\n });\r\n\r\n cleanups.push(cleanup);\r\n};\r\n\r\n/**\r\n * Handles bq-show directive - toggle visibility.\r\n * @internal\r\n */\r\nconst handleShow: DirectiveHandler = (el, expression, context, cleanups) => {\r\n const htmlEl = el as HTMLElement;\r\n const originalDisplay = htmlEl.style.display;\r\n\r\n const cleanup = effect(() => {\r\n const condition = evaluate<boolean>(expression, context);\r\n htmlEl.style.display = condition ? originalDisplay : 'none';\r\n });\r\n\r\n cleanups.push(cleanup);\r\n};\r\n\r\n/**\r\n * Handles bq-class directive - dynamic class binding.\r\n * Tracks previously added classes to ensure proper cleanup when expressions change.\r\n * @internal\r\n */\r\nconst handleClass: DirectiveHandler = (el, expression, context, cleanups) => {\r\n // Track classes added by this directive to clean them up on re-evaluation\r\n let previousClasses: Set<string> = new Set();\r\n\r\n const cleanup = effect(() => {\r\n const newClasses: Set<string> = new Set();\r\n\r\n if (expression.startsWith('{')) {\r\n // Object syntax: { active: isActive, disabled: !enabled }\r\n const classMap = parseObjectExpression(expression);\r\n for (const [className, conditionExpr] of Object.entries(classMap)) {\r\n const condition = evaluate<boolean>(conditionExpr, context);\r\n el.classList.toggle(className, Boolean(condition));\r\n // Track class regardless of condition - toggle handles add/remove\r\n newClasses.add(className);\r\n }\r\n } else if (expression.includes('[')) {\r\n // Array syntax: [class1, class2]\r\n const classes = evaluate<string[]>(expression, context);\r\n if (Array.isArray(classes)) {\r\n for (const cls of classes) {\r\n if (cls) {\r\n el.classList.add(cls);\r\n newClasses.add(cls);\r\n }\r\n }\r\n }\r\n } else {\r\n // Single expression returning string or array\r\n const result = evaluate<string | string[]>(expression, context);\r\n if (typeof result === 'string') {\r\n result.split(/\\s+/).forEach((cls) => {\r\n if (cls) {\r\n el.classList.add(cls);\r\n newClasses.add(cls);\r\n }\r\n });\r\n } else if (Array.isArray(result)) {\r\n result.forEach((cls) => {\r\n if (cls) {\r\n el.classList.add(cls);\r\n newClasses.add(cls);\r\n }\r\n });\r\n }\r\n }\r\n\r\n // Remove classes that were previously added but are no longer in the new set\r\n // Skip for object syntax since toggle already handles removal\r\n if (!expression.startsWith('{')) {\r\n for (const cls of previousClasses) {\r\n if (!newClasses.has(cls)) {\r\n el.classList.remove(cls);\r\n }\r\n }\r\n }\r\n\r\n previousClasses = newClasses;\r\n });\r\n\r\n cleanups.push(cleanup);\r\n};\r\n\r\n/**\r\n * Handles bq-style directive - dynamic style binding.\r\n * @internal\r\n */\r\nconst handleStyle: DirectiveHandler = (el, expression, context, cleanups) => {\r\n const htmlEl = el as HTMLElement;\r\n\r\n const cleanup = effect(() => {\r\n if (expression.startsWith('{')) {\r\n const styleMap = parseObjectExpression(expression);\r\n for (const [prop, valueExpr] of Object.entries(styleMap)) {\r\n const value = evaluate<string>(valueExpr, context);\r\n const cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();\r\n htmlEl.style.setProperty(cssProp, String(value ?? ''));\r\n }\r\n } else {\r\n const result = evaluate<Record<string, string>>(expression, context);\r\n if (result && typeof result === 'object') {\r\n for (const [prop, value] of Object.entries(result)) {\r\n const cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();\r\n htmlEl.style.setProperty(cssProp, String(value ?? ''));\r\n }\r\n }\r\n }\r\n });\r\n\r\n cleanups.push(cleanup);\r\n};\r\n\r\n/**\r\n * Handles bq-model directive - two-way binding.\r\n * @internal\r\n */\r\nconst handleModel: DirectiveHandler = (el, expression, context, cleanups) => {\r\n const input = el as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\r\n const rawValue = evaluateRaw<Signal<unknown>>(expression, context);\r\n\r\n if (!isSignal(rawValue)) {\r\n console.warn(`bQuery view: bq-model requires a signal, got \"${expression}\"`);\r\n return;\r\n }\r\n\r\n const sig = rawValue as Signal<unknown>;\r\n\r\n // Initial value sync\r\n const isCheckbox = input.type === 'checkbox';\r\n const isRadio = input.type === 'radio';\r\n\r\n const updateInput = () => {\r\n if (isCheckbox) {\r\n (input as HTMLInputElement).checked = Boolean(sig.value);\r\n } else if (isRadio) {\r\n (input as HTMLInputElement).checked = sig.value === input.value;\r\n } else {\r\n input.value = String(sig.value ?? '');\r\n }\r\n };\r\n\r\n // Effect to sync signal -> input\r\n const cleanup = effect(() => {\r\n updateInput();\r\n });\r\n cleanups.push(cleanup);\r\n\r\n // Event listener to sync input -> signal\r\n const eventType = input.tagName === 'SELECT' ? 'change' : 'input';\r\n const handler = () => {\r\n if (isCheckbox) {\r\n sig.value = (input as HTMLInputElement).checked;\r\n } else if (isRadio) {\r\n if ((input as HTMLInputElement).checked) {\r\n sig.value = input.value;\r\n }\r\n } else {\r\n sig.value = input.value;\r\n }\r\n };\r\n\r\n input.addEventListener(eventType, handler);\r\n cleanups.push(() => input.removeEventListener(eventType, handler));\r\n};\r\n\r\n/**\r\n * Handles bq-bind:attr directive - attribute binding.\r\n * @internal\r\n */\r\nconst handleBind = (attrName: string): DirectiveHandler => {\r\n return (el, expression, context, cleanups) => {\r\n const cleanup = effect(() => {\r\n const value = evaluate(expression, context);\r\n if (value == null || value === false) {\r\n el.removeAttribute(attrName);\r\n } else if (value === true) {\r\n el.setAttribute(attrName, '');\r\n } else {\r\n el.setAttribute(attrName, String(value));\r\n }\r\n });\r\n cleanups.push(cleanup);\r\n };\r\n};\r\n\r\n/**\r\n * Handles bq-on:event directive - event binding.\r\n * @internal\r\n */\r\nconst handleOn = (eventName: string): DirectiveHandler => {\r\n return (el, expression, context, cleanups) => {\r\n const handler = (event: Event) => {\r\n // Add $event to context for expression evaluation\r\n const eventContext = { ...context, $event: event, $el: el };\r\n\r\n // Check if expression is just a function reference (no parentheses)\r\n // In that case, we should call it directly\r\n const isPlainFunctionRef = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(expression.trim());\r\n\r\n if (isPlainFunctionRef) {\r\n // Get the function and call it with the event\r\n const fn = evaluateRaw<unknown>(expression, eventContext);\r\n if (typeof fn === 'function') {\r\n fn(event);\r\n return;\r\n }\r\n }\r\n\r\n // Otherwise evaluate as expression (e.g., \"handleClick($event)\" or \"count++\")\r\n evaluate(expression, eventContext);\r\n };\r\n\r\n el.addEventListener(eventName, handler);\r\n cleanups.push(() => el.removeEventListener(eventName, handler));\r\n };\r\n};\r\n\r\n/**\r\n * Represents a rendered item in bq-for with its DOM element and associated cleanup functions.\r\n * @internal\r\n */\r\ntype RenderedItem = {\r\n key: unknown;\r\n element: Element;\r\n cleanups: CleanupFn[];\r\n item: unknown;\r\n index: number;\r\n};\r\n\r\n/**\r\n * Extracts a key from an item using the key expression or falls back to index.\r\n * @internal\r\n */\r\nconst getItemKey = (\r\n item: unknown,\r\n index: number,\r\n keyExpression: string | null,\r\n itemName: string,\r\n indexName: string | undefined,\r\n context: BindingContext\r\n): unknown => {\r\n if (!keyExpression) {\r\n return index; // Fallback to index-based keying\r\n }\r\n\r\n const keyContext: BindingContext = {\r\n ...context,\r\n [itemName]: item,\r\n };\r\n if (indexName) {\r\n keyContext[indexName] = index;\r\n }\r\n\r\n return evaluate(keyExpression, keyContext);\r\n};\r\n\r\n/**\r\n * Handles bq-for directive - list rendering with keyed reconciliation.\r\n *\r\n * Supports optional `:key` attribute for efficient DOM reuse:\r\n * ```html\r\n * <li bq-for=\"item in items\" :key=\"item.id\">...</li>\r\n * ```\r\n *\r\n * Without a key, falls back to index-based tracking (less efficient for reordering).\r\n *\r\n * @internal\r\n */\r\nconst handleFor = (prefix: string, sanitize: boolean): DirectiveHandler => {\r\n return (el, expression, context, cleanups) => {\r\n const parent = el.parentNode;\r\n if (!parent) return;\r\n\r\n // Parse expression: \"item in items\" or \"(item, index) in items\"\r\n // Use \\S.* instead of .+ to prevent ReDoS by requiring non-whitespace start\r\n const match = expression.match(/^\\(?(\\w+)(?:\\s*,\\s*(\\w+))?\\)?\\s+in\\s+(\\S.*)$/);\r\n if (!match) {\r\n console.error(`bQuery view: Invalid bq-for expression \"${expression}\"`);\r\n return;\r\n }\r\n\r\n const [, itemName, indexName, listExpression] = match;\r\n\r\n // Extract :key attribute if present\r\n const keyExpression = el.getAttribute(':key') || el.getAttribute(`${prefix}-key`);\r\n\r\n const template = el.cloneNode(true) as Element;\r\n template.removeAttribute(`${prefix}-for`);\r\n template.removeAttribute(':key');\r\n template.removeAttribute(`${prefix}-key`);\r\n\r\n // Create placeholder comment\r\n const placeholder = document.createComment(`bq-for: ${expression}`);\r\n parent.replaceChild(placeholder, el);\r\n\r\n // Track rendered items by key for reconciliation\r\n let renderedItemsMap = new Map<unknown, RenderedItem>();\r\n let renderedOrder: unknown[] = [];\r\n\r\n /**\r\n * Creates a new DOM element for an item.\r\n */\r\n const createItemElement = (item: unknown, index: number, key: unknown): RenderedItem => {\r\n const clone = template.cloneNode(true) as Element;\r\n const itemCleanups: CleanupFn[] = [];\r\n\r\n const childContext: BindingContext = {\r\n ...context,\r\n [itemName]: item,\r\n };\r\n if (indexName) {\r\n childContext[indexName] = index;\r\n }\r\n\r\n // Process bindings on the clone\r\n processElement(clone, childContext, prefix, sanitize, itemCleanups);\r\n processChildren(clone, childContext, prefix, sanitize, itemCleanups);\r\n\r\n return {\r\n key,\r\n element: clone,\r\n cleanups: itemCleanups,\r\n item,\r\n index,\r\n };\r\n };\r\n\r\n /**\r\n * Removes a rendered item and cleans up its effects.\r\n */\r\n const removeItem = (rendered: RenderedItem): void => {\r\n for (const cleanup of rendered.cleanups) {\r\n cleanup();\r\n }\r\n rendered.element.remove();\r\n };\r\n\r\n /**\r\n * Updates an existing item's index context if needed.\r\n * Note: For deep reactivity, items should use signals internally.\r\n */\r\n const updateItemIndex = (rendered: RenderedItem, newIndex: number): void => {\r\n if (rendered.index !== newIndex && indexName) {\r\n // Index changed - we need to re-process bindings for index-dependent expressions\r\n // For now, we mark the index as updated (future: could use signals for index)\r\n rendered.index = newIndex;\r\n }\r\n };\r\n\r\n const cleanup = effect(() => {\r\n const list = evaluate<unknown[]>(listExpression, context);\r\n\r\n if (!Array.isArray(list)) {\r\n // Clear all if list is invalid\r\n for (const rendered of renderedItemsMap.values()) {\r\n removeItem(rendered);\r\n }\r\n renderedItemsMap.clear();\r\n renderedOrder = [];\r\n return;\r\n }\r\n\r\n // Build new key order and detect changes\r\n const newKeys: unknown[] = [];\r\n const newItemsByKey = new Map<unknown, { item: unknown; index: number }>();\r\n\r\n list.forEach((item, index) => {\r\n const key = getItemKey(item, index, keyExpression, itemName, indexName, context);\r\n newKeys.push(key);\r\n newItemsByKey.set(key, { item, index });\r\n });\r\n\r\n // Identify items to remove (in old but not in new)\r\n const keysToRemove: unknown[] = [];\r\n for (const key of renderedOrder) {\r\n if (!newItemsByKey.has(key)) {\r\n keysToRemove.push(key);\r\n }\r\n }\r\n\r\n // Remove deleted items\r\n for (const key of keysToRemove) {\r\n const rendered = renderedItemsMap.get(key);\r\n if (rendered) {\r\n removeItem(rendered);\r\n renderedItemsMap.delete(key);\r\n }\r\n }\r\n\r\n // Process new list: create new items, update indices, reorder\r\n const newRenderedMap = new Map<unknown, RenderedItem>();\r\n let lastInsertedElement: Element | Comment = placeholder;\r\n\r\n for (let i = 0; i < newKeys.length; i++) {\r\n const key = newKeys[i];\r\n const { item, index } = newItemsByKey.get(key)!;\r\n let rendered = renderedItemsMap.get(key);\r\n\r\n if (rendered) {\r\n // Reuse existing element\r\n updateItemIndex(rendered, index);\r\n newRenderedMap.set(key, rendered);\r\n\r\n // Check if element needs to be moved\r\n const currentNext: ChildNode | null = lastInsertedElement.nextSibling;\r\n if (currentNext !== rendered.element) {\r\n // Move element to correct position\r\n lastInsertedElement.after(rendered.element);\r\n }\r\n lastInsertedElement = rendered.element;\r\n } else {\r\n // Create new element\r\n rendered = createItemElement(item, index, key);\r\n newRenderedMap.set(key, rendered);\r\n\r\n // Insert at correct position\r\n lastInsertedElement.after(rendered.element);\r\n lastInsertedElement = rendered.element;\r\n }\r\n }\r\n\r\n // Update tracking state\r\n renderedItemsMap = newRenderedMap;\r\n renderedOrder = newKeys;\r\n });\r\n\r\n // When the bq-for itself is cleaned up, also cleanup all rendered items\r\n cleanups.push(() => {\r\n cleanup();\r\n for (const rendered of renderedItemsMap.values()) {\r\n for (const itemCleanup of rendered.cleanups) {\r\n itemCleanup();\r\n }\r\n }\r\n renderedItemsMap.clear();\r\n });\r\n };\r\n};\r\n\r\n/**\r\n * Handles bq-ref directive - element reference.\r\n * @internal\r\n */\r\nconst handleRef: DirectiveHandler = (el, expression, context, cleanups) => {\r\n const rawValue = evaluateRaw<Signal<Element | null>>(expression, context);\r\n\r\n if (isSignal(rawValue)) {\r\n (rawValue as Signal<Element | null>).value = el;\r\n cleanups.push(() => {\r\n (rawValue as Signal<Element | null>).value = null;\r\n });\r\n } else if (typeof context[expression] === 'object' && context[expression] !== null) {\r\n // Object with .value property\r\n (context[expression] as { value: Element | null }).value = el;\r\n }\r\n};\r\n\r\n// ============================================================================\r\n// Core Processing\r\n// ============================================================================\r\n\r\n/**\r\n * Processes a single element for directives.\r\n * @internal\r\n */\r\nconst processElement = (\r\n el: Element,\r\n context: BindingContext,\r\n prefix: string,\r\n sanitize: boolean,\r\n cleanups: CleanupFn[]\r\n): void => {\r\n const attributes = Array.from(el.attributes);\r\n\r\n for (const attr of attributes) {\r\n const { name, value } = attr;\r\n\r\n if (!name.startsWith(prefix)) continue;\r\n\r\n const directive = name.slice(prefix.length + 1); // Remove prefix and dash\r\n\r\n // Handle bq-for specially (creates new scope)\r\n if (directive === 'for') {\r\n handleFor(prefix, sanitize)(el, value, context, cleanups);\r\n return; // Don't process children, bq-for handles it\r\n }\r\n\r\n // Handle other directives\r\n if (directive === 'text') {\r\n handleText(el, value, context, cleanups);\r\n } else if (directive === 'html') {\r\n handleHtml(sanitize)(el, value, context, cleanups);\r\n } else if (directive === 'if') {\r\n handleIf(el, value, context, cleanups);\r\n } else if (directive === 'show') {\r\n handleShow(el, value, context, cleanups);\r\n } else if (directive === 'class') {\r\n handleClass(el, value, context, cleanups);\r\n } else if (directive === 'style') {\r\n handleStyle(el, value, context, cleanups);\r\n } else if (directive === 'model') {\r\n handleModel(el, value, context, cleanups);\r\n } else if (directive === 'ref') {\r\n handleRef(el, value, context, cleanups);\r\n } else if (directive.startsWith('bind:')) {\r\n const attrName = directive.slice(5);\r\n handleBind(attrName)(el, value, context, cleanups);\r\n } else if (directive.startsWith('on:')) {\r\n const eventName = directive.slice(3);\r\n handleOn(eventName)(el, value, context, cleanups);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Recursively processes children of an element.\r\n * @internal\r\n */\r\nconst processChildren = (\r\n el: Element,\r\n context: BindingContext,\r\n prefix: string,\r\n sanitize: boolean,\r\n cleanups: CleanupFn[]\r\n): void => {\r\n const children = Array.from(el.children);\r\n for (const child of children) {\r\n // Skip if element has bq-for (handled separately)\r\n if (!child.hasAttribute(`${prefix}-for`)) {\r\n processElement(child, context, prefix, sanitize, cleanups);\r\n processChildren(child, context, prefix, sanitize, cleanups);\r\n } else {\r\n processElement(child, context, prefix, sanitize, cleanups);\r\n }\r\n }\r\n};\r\n\r\n// ============================================================================\r\n// Public API\r\n// ============================================================================\r\n\r\n/**\r\n * Mounts a reactive view to an element.\r\n *\r\n * @param selector - CSS selector or Element\r\n * @param context - Binding context with signals, computed, and functions\r\n * @param options - Mount options\r\n * @returns The mounted View instance\r\n *\r\n * @security **WARNING:** Directive expressions (bq-text, bq-if, bq-on, etc.) are evaluated\r\n * using `new Function()` at runtime. This means:\r\n * - Template attributes must come from trusted sources only\r\n * - NEVER load templates containing bq-* attributes from user input or untrusted APIs\r\n * - If you must use external templates, validate/sanitize attribute values first\r\n *\r\n * @example\r\n * ```ts\r\n * import { mount } from 'bquery/view';\r\n * import { signal, computed } from 'bquery/reactive';\r\n *\r\n * const name = signal('World');\r\n * const greeting = computed(() => `Hello, ${name.value}!`);\r\n * const items = signal([\r\n * { id: 1, text: 'Item 1' },\r\n * { id: 2, text: 'Item 2' },\r\n * ]);\r\n *\r\n * const view = mount('#app', {\r\n * name,\r\n * greeting,\r\n * items,\r\n * addItem: () => {\r\n * items.value = [...items.value, { id: Date.now(), text: 'New Item' }];\r\n * },\r\n * });\r\n *\r\n * // Later, cleanup\r\n * view.destroy();\r\n * ```\r\n */\r\nexport const mount = (\r\n selector: string | Element,\r\n context: BindingContext,\r\n options: MountOptions = {}\r\n): View => {\r\n const { prefix = 'bq', sanitize = true } = options;\r\n\r\n const el = typeof selector === 'string' ? document.querySelector(selector) : selector;\r\n\r\n if (!el) {\r\n throw new Error(`bQuery view: Element \"${selector}\" not found.`);\r\n }\r\n\r\n const cleanups: CleanupFn[] = [];\r\n\r\n // Process the root element and its children\r\n processElement(el, context, prefix, sanitize, cleanups);\r\n processChildren(el, context, prefix, sanitize, cleanups);\r\n\r\n return {\r\n el,\r\n context,\r\n\r\n update: (newContext: Partial<BindingContext>) => {\r\n Object.assign(context, newContext);\r\n },\r\n\r\n destroy: () => {\r\n for (const cleanup of cleanups) {\r\n cleanup();\r\n }\r\n cleanups.length = 0;\r\n },\r\n };\r\n};\r\n\r\n/**\r\n * Creates a reactive template function.\r\n *\r\n * @param template - HTML template string\r\n * @returns A function that creates a mounted element with the given context\r\n *\r\n * @example\r\n * ```ts\r\n * import { createTemplate } from 'bquery/view';\r\n * import { signal } from 'bquery/reactive';\r\n *\r\n * const TodoItem = createTemplate(`\r\n * <li bq-class=\"{ completed: done }\">\r\n * <input type=\"checkbox\" bq-model=\"done\" />\r\n * <span bq-text=\"text\"></span>\r\n * </li>\r\n * `);\r\n *\r\n * const item = TodoItem({\r\n * done: signal(false),\r\n * text: 'Buy groceries',\r\n * });\r\n *\r\n * document.querySelector('#list').append(item.el);\r\n * ```\r\n */\r\nexport const createTemplate = (\r\n template: string,\r\n options: MountOptions = {}\r\n): ((context: BindingContext) => View) => {\r\n return (context: BindingContext) => {\r\n const container = document.createElement('div');\r\n container.innerHTML = template.trim();\r\n\r\n const el = container.firstElementChild;\r\n if (!el) {\r\n throw new Error('bQuery view: Template must contain a single root element.');\r\n }\r\n\r\n return mount(el, context, options);\r\n };\r\n};\r\n\r\n// ============================================================================\r\n// Utility Exports\r\n// ============================================================================\r\n\r\n/**\r\n * Re-export reactive primitives for convenience.\r\n */\r\nexport { batch, computed, effect, signal } from '../reactive/index';\r\n"],"names":["POLICY_NAME","cachedPolicy","isTrustedTypesSupported","getTrustedTypesPolicy","win","input","sanitizeHtmlCore","DEFAULT_ALLOWED_TAGS","DANGEROUS_TAGS","RESERVED_IDS","DEFAULT_ALLOWED_ATTRIBUTES","DANGEROUS_ATTR_PREFIXES","DANGEROUS_PROTOCOLS","isAllowedAttribute","name","allowedSet","allowDataAttrs","lowerName","prefix","isSafeIdOrName","value","lowerValue","normalizeUrl","isSafeUrl","normalized","protocol","isExternalUrl","url","trimmedUrl","lowerUrl","html","options","allowTags","allowAttributes","allowDataAttributes","stripAllTags","allowedTags","t","tag","allowedAttrs","a","template","walker","toRemove","el","tagName","attrsToRemove","attr","attrName","href","hasTargetBlank","isExternal","existingRel","relValues","sanitizeHtml","createTrustedHtml","policy","escapeHtml","text","escapeMap","char","stripTags","generateNonce","length","array","hasCSPDirective","directive","meta","toElementList","applyAll","elements","action","BQueryElement","element","classNames","className","force","key","match","property","val","content","wrapper","wrapperEl","parent","newEl","deep","selector","child","event","handler","detail","e","target","handlers","display","isHidden","newValue","form","result","formData","existing","params","position","BQueryCollection","index","callback","predicate","initialValue","sanitized","elementHandlers","$","$$","utils","sources","source","fn","delayMs","timeoutId","args","intervalMs","lastRun","now","json","fallback","obj","keys","ms","resolve","min","max","str","_","observerStack","batchDepth","pendingObservers","trackingEnabled","track","observer","scheduleObserver","flushObservers","Signal","_value","current","next","subscriber","updater","Computed","compute","signal","computed","effect","cleanupFn","isDisposed","batch","persistedSignal","stored","raw","sig","readonly","watch","oldValue","isFirst","untrack","prevTracking","isSignal","isComputed","coercePropValue","rawValue","config","type","parsed","callable","constructable","strings","values","acc","part","safeHtml","escape","component","definition","BQueryComponent","error","props","attrValue","triggerUpdated","emit","markup","styles","transition","updateOrOptions","update","doc","capturePosition","rect","flip","firstBounds","duration","easing","onComplete","lastBounds","deltaX","deltaY","deltaW","deltaH","htmlElement","animation","flipList","performUpdate","positions","animations","first","DEFAULT_SPRING_CONFIG","spring","stiffness","damping","mass","precision","velocity","animationFrame","resolvePromise","listeners","notifyListeners","listener","step","displacement","springForce","dampingForce","acceleration","newTarget","springPresets","IndexedDBBucket","bucketName","dbName","reject","request","db","mode","operation","store","data","buckets","CacheHandleImpl","cache","urls","response","req","c","notifications","title","WebStorageAdapter","storage","serialized","LocalStorageAdapter","SessionStorageAdapter","IndexedDBAdapter","activeRouter","routeSignal","currentRoute","pathToRegex","path","PARAM_MARKER","WILDCARD_MARKER","paramNames","pattern","paramIdx","extractParamNames","matches","m","matchRoute","routes","route","regex","parseQuery","search","query","createRoute","pathname","hash","navigate","back","forward","createRouter","base","useHash","beforeGuards","afterHooks","flatRoutes","flattenRoutes","getCurrentPath","hashPath","rest","hashPart","syncRoute","newRoute","performNavigation","method","from","toPath","to","guard","fullPath","hook","handlePopState","restorePath","router","delta","r","isActive","exact","isActiveSignal","link","interceptLinks","container","anchor","storeRegistry","isPlainObject","deepClone","k","v","cloned","deepEqual","b","item","keysA","keysB","detectNestedMutations","before","after","signalValues","mutatedKeys","beforeValue","afterValue","__DEV__","globalProcess","plugins","createStore","id","stateFactory","getters","actions","initialState","stateSignals","subscribers","notifySubscribers","currentState","getCurrentState","stateProxy","prop","getterComputed","getterFn","computedGetter","state","getterProxy","propKey","actionFn","context","_target","fresh","partial","stateBefore","signalValuesBefore","s","plugin","extension","getStore","listStores","destroyStore","registerPlugin","createPersistedStore","storageKey","originalStateFactory","defaultState","saved","mapState","mapped","mapActions","evaluate","expression","evaluateRaw","parseObjectExpression","inner","parts","depth","inString","i","prevChar","colonIndex","partDepth","partInString","handleText","cleanups","cleanup","handleHtml","sanitize","handleIf","placeholder","isInserted","condition","handleShow","htmlEl","originalDisplay","handleClass","previousClasses","newClasses","classMap","conditionExpr","classes","cls","handleStyle","styleMap","valueExpr","cssProp","handleModel","isCheckbox","isRadio","updateInput","eventType","handleBind","handleOn","eventName","eventContext","getItemKey","keyExpression","itemName","indexName","keyContext","handleFor","listExpression","renderedItemsMap","renderedOrder","createItemElement","clone","itemCleanups","childContext","processElement","processChildren","removeItem","rendered","updateItemIndex","newIndex","list","newKeys","newItemsByKey","keysToRemove","newRenderedMap","lastInsertedElement","itemCleanup","handleRef","attributes","children","mount","newContext","createTemplate"],"mappings":"8NA4BA,MAAMA,EAAc,mBA4BpB,IAAIC,EAAyC,KAMtC,MAAMC,GAA0B,IAC9B,OAAQ,OAA8B,aAAiB,IAOnDC,GAAwB,IAAgC,CACnE,GAAIF,EAAc,OAAOA,EAEzB,MAAMG,EAAM,OACZ,GAAI,CAACA,EAAI,aAAc,OAAO,KAE9B,GAAI,CACF,OAAAH,EAAeG,EAAI,aAAa,aAAaJ,EAAa,CACxD,WAAaK,GAAkBC,EAAiBD,CAAK,CAAA,CACtD,EACMJ,CACT,MAAQ,CAEN,eAAQ,KAAK,kDAAkDD,CAAW,GAAG,EACtE,IACT,CACF,EASMO,OAA2B,IAAI,CACnC,IACA,OACA,UACA,UACA,QACA,IACA,MACA,MACA,aACA,KACA,SACA,UACA,OACA,OACA,MACA,WACA,OACA,KACA,MACA,UACA,MACA,MACA,KACA,KACA,KACA,aACA,SACA,SACA,OACA,KACA,KACA,KACA,KACA,KACA,KACA,SACA,SACA,KACA,IACA,MACA,QACA,MACA,MACA,QACA,SACA,KACA,OACA,OACA,MACA,KACA,WACA,SACA,IACA,UACA,MACA,WACA,IACA,KACA,KACA,OACA,IACA,OACA,UACA,SACA,QACA,SACA,OACA,SACA,MACA,UACA,MACA,QACA,QACA,KACA,WACA,QACA,KACA,QACA,OACA,KACA,IACA,KACA,MACA,KACF,CAAC,EAMKC,OAAqB,IAAI,CAC7B,SACA,SACA,QACA,WACA,SACA,QACA,SACA,OACA,OACA,QACA,OACA,WACA,OACA,OACA,MACA,gBACA,UACF,CAAC,EAMKC,OAAmB,IAAI,CAE3B,WACA,SACA,WACA,MACA,OACA,SACA,SACA,UACA,YACA,SAEA,QACA,UACA,SACA,OACA,WAEA,SACA,SACA,WACA,OACA,OACA,QACA,SACA,QACA,UAEA,WACA,aACA,aACA,YAEA,YACA,YACA,aACF,CAAC,EAKKC,OAAiC,IAAI,CACzC,MACA,QACA,MACA,SACA,SACA,OACA,KACA,OACA,UACA,OACA,MACA,OACA,MACA,SACA,QACA,WACA,SACA,QACA,OACA,QACA,QACF,CA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"}
|