@sigx/runtime-dom 0.1.8 → 0.1.9

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"src-DblUVEtM.js","names":[],"sources":["../src/Portal.tsx","../src/directives/show.ts","../src/index.ts"],"sourcesContent":["/**\r\n * Portal component for rendering children to a different DOM location.\r\n * \r\n * Uses the `moveBefore` API (Chrome 133+) when available for state-preserving\r\n * DOM moves. Falls back to `insertBefore` for older browsers.\r\n * \r\n * @example\r\n * ```tsx\r\n * import { Portal } from '@sigx/runtime-dom';\r\n * \r\n * // Render to document.body (default)\r\n * <Portal>\r\n * <div class=\"modal\">Modal content</div>\r\n * </Portal>\r\n * \r\n * // Render to a specific container\r\n * <Portal to={document.getElementById('modal-root')}>\r\n * <div class=\"modal\">Modal content</div>\r\n * </Portal>\r\n * \r\n * // Render to a container by selector\r\n * <Portal to=\"#modal-root\">\r\n * <div class=\"modal\">Modal content</div>\r\n * </Portal>\r\n * ```\r\n */\r\n\r\nimport { component, DefineProp, Fragment, VNode, jsx } from '@sigx/runtime-core';\r\nimport { normalizeSubTree } from '@sigx/runtime-core/internals';\r\nimport { effect } from '@sigx/reactivity';\r\nimport { mount, unmount, patch } from './index.js';\r\n\r\n/**\r\n * Check if the browser supports the moveBefore API.\r\n * moveBefore allows moving DOM nodes without losing state (iframes, videos, focus, etc.)\r\n */\r\nexport function supportsMoveBefore(): boolean {\r\n return typeof Node !== 'undefined' && 'moveBefore' in Node.prototype;\r\n}\r\n\r\n/**\r\n * Move or insert a node into a parent, using moveBefore when available\r\n * for state-preserving moves.\r\n * \r\n * @param parent - The target parent element\r\n * @param node - The node to move/insert\r\n * @param anchor - Optional reference node to insert before\r\n */\r\nexport function moveNode(\r\n parent: Element,\r\n node: Node,\r\n anchor: Node | null = null\r\n): void {\r\n if (supportsMoveBefore()) {\r\n // Use moveBefore for state-preserving move (Chrome 133+)\r\n (parent as any).moveBefore(node, anchor);\r\n } else {\r\n // Fallback to insertBefore (causes state reset for iframes, etc.)\r\n parent.insertBefore(node, anchor);\r\n }\r\n}\r\n\r\n/**\r\n * Resolve a portal target from a string selector or Element.\r\n * Returns document.body as fallback.\r\n */\r\nfunction resolveTarget(target: string | Element | undefined): Element {\r\n if (target === undefined) {\r\n return document.body;\r\n }\r\n \r\n if (typeof target === 'string') {\r\n const resolved = document.querySelector(target);\r\n if (!resolved) {\r\n console.warn(`Portal: Target \"${target}\" not found, falling back to document.body`);\r\n return document.body;\r\n }\r\n return resolved;\r\n }\r\n \r\n return target;\r\n}\r\n\r\ntype PortalProps = DefineProp<'to', string | Element> & DefineProp<'disabled', boolean>;\r\n\r\n/**\r\n * Portal component - renders children to a different DOM location.\r\n * \r\n * Props:\r\n * - `to` - Target container (Element or CSS selector string). Defaults to document.body.\r\n * - `disabled` - When true, renders children in place instead of portaling\r\n * - `children` - Content to render in the portal\r\n * \r\n * Features:\r\n * - Uses `moveBefore` API (Chrome 133+) for state-preserving DOM moves\r\n * - Preserves iframe content, video playback, focus, and CSS animations\r\n * - Falls back to `insertBefore` for older browsers\r\n */\r\nexport const Portal = component<PortalProps>(({ props, slots, onMounted, onUnmounted }) => {\r\n // Container element for portal content\r\n let portalContainer: HTMLDivElement | null = null;\r\n let mountedVNode: VNode | null = null;\r\n let cleanupEffect: (() => void) | null = null;\r\n\r\n onMounted(() => {\r\n if (props.disabled) {\r\n return;\r\n }\r\n\r\n // Resolve target container\r\n const targetContainer = resolveTarget(props.to);\r\n\r\n // Create a container div for the portal content\r\n portalContainer = document.createElement('div');\r\n portalContainer.setAttribute('data-sigx-portal', '');\r\n\r\n // Use moveBefore when available for state-preserving move\r\n moveNode(targetContainer, portalContainer);\r\n\r\n // Set up reactive effect to render children into portal container\r\n const stopEffect = effect(() => {\r\n const children = slots.default();\r\n \r\n if (!portalContainer) return;\r\n \r\n // Normalize children to a proper VNode using the shared utility\r\n const vnode = normalizeSubTree(children);\r\n\r\n if (mountedVNode) {\r\n // Patch existing content\r\n patch(mountedVNode, vnode, portalContainer);\r\n } else {\r\n // Initial mount\r\n mount(vnode, portalContainer);\r\n }\r\n \r\n mountedVNode = vnode;\r\n });\r\n\r\n cleanupEffect = stopEffect;\r\n });\r\n\r\n onUnmounted(() => {\r\n // Stop the reactive effect\r\n if (cleanupEffect) {\r\n cleanupEffect();\r\n cleanupEffect = null;\r\n }\r\n\r\n // Unmount the portal content\r\n if (mountedVNode && portalContainer) {\r\n unmount(mountedVNode, portalContainer);\r\n mountedVNode = null;\r\n }\r\n\r\n // Remove the portal container from the DOM\r\n if (portalContainer && portalContainer.parentNode) {\r\n portalContainer.parentNode.removeChild(portalContainer);\r\n }\r\n portalContainer = null;\r\n });\r\n\r\n return () => {\r\n // When disabled, render children in place using jsx function\r\n if (props.disabled) {\r\n const children = slots.default();\r\n return jsx(Fragment, { children });\r\n }\r\n\r\n // When portal is active, render nothing in place\r\n // Children are rendered into the portal container via the effect\r\n return null;\r\n };\r\n}, { name: 'Portal' });\r\n","/**\r\n * Built-in `show` directive — toggles element visibility via `display` CSS property.\r\n *\r\n * Unlike conditional rendering (ternary in JSX), `use:show` keeps the element in the DOM\r\n * and only toggles its `display` style. This is useful when toggling is frequent and you\r\n * want to preserve element state (e.g., scroll position, input focus).\r\n *\r\n * @example\r\n * ```tsx\r\n * // Shorthand — directive resolved automatically:\r\n * <div use:show={isVisible}>Content</div>\r\n *\r\n * // Explicit tuple form:\r\n * import { show } from 'sigx';\r\n * <div use:show={[show, isVisible]}>Content</div>\r\n * ```\r\n */\r\n\r\nimport { defineDirective } from '@sigx/runtime-core';\r\n\r\n/** Symbol key for storing the original display value on elements. */\r\nconst ORIGINAL_DISPLAY = Symbol('sigx.show.originalDisplay');\r\n\r\n/** HTMLElement with the show directive's original display property. */\r\ninterface ShowElement extends HTMLElement {\r\n [ORIGINAL_DISPLAY]?: string;\r\n}\r\n\r\nexport const show = defineDirective<boolean, HTMLElement>({\r\n mounted(el, { value }) {\r\n const showEl = el as ShowElement;\r\n // Save the original display value now that all props have been applied\r\n const saved = showEl.style.display === 'none' ? '' : showEl.style.display;\r\n showEl[ORIGINAL_DISPLAY] = saved;\r\n showEl.style.display = value ? saved : 'none';\r\n },\r\n\r\n updated(el, { value, oldValue }) {\r\n if (value !== oldValue) {\r\n const showEl = el as ShowElement;\r\n showEl.style.display = value ? showEl[ORIGINAL_DISPLAY] ?? '' : 'none';\r\n }\r\n },\r\n\r\n unmounted(el) {\r\n const showEl = el as ShowElement;\r\n // Restore original display on cleanup\r\n const original = showEl[ORIGINAL_DISPLAY];\r\n if (original !== undefined) {\r\n showEl.style.display = original;\r\n }\r\n }\r\n});\r\n","// Import JSX types (global augmentation)\r\nimport './jsx';\r\n// Import type augmentation for @sigx/runtime-core\r\nimport './types';\r\n// Import JSX type augmentation for built-in directives (IntelliSense for use:show, etc.)\r\nimport './directives/show-jsx-types';\r\nimport { setPlatformModelProcessor, createRenderer, setDefaultMount } from '@sigx/runtime-core/internals';\r\nimport type { RendererOptions } from '@sigx/runtime-core/internals';\r\nimport { isDirective, type DirectiveDefinition, type JSXElement } from '@sigx/runtime-core';\r\nimport type { AppContext } from '@sigx/runtime-core';\r\n\r\n/**\r\n * A directive definition narrowed to DOM elements.\r\n * Use this type when defining directives for the DOM renderer.\r\n *\r\n * @example\r\n * ```ts\r\n * import { defineDirective, type DOMDirective } from 'sigx';\r\n *\r\n * const tooltip = defineDirective<string, HTMLElement>({\r\n * mounted(el, { value }) {\r\n * el.title = value; // el is HTMLElement, fully typed\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport type DOMDirective<T = any> = DirectiveDefinition<T, HTMLElement>;\r\n\r\n// ============================================================================\r\n// Directive Runtime for DOM (element-level use:* directives)\r\n// ============================================================================\r\n\r\n/**\r\n * Registry of built-in directives by name.\r\n * When a `use:<name>` prop receives a plain value (not a DirectiveDefinition),\r\n * the runtime looks up the directive by name here.\r\n * @internal\r\n */\r\nconst builtInDirectives = new Map<string, DirectiveDefinition>();\r\n\r\n/**\r\n * Register a built-in directive so it can be used with the shorthand syntax:\r\n * `<div use:show={value}>` instead of `<div use:show={[show, value]}>`.\r\n * @internal\r\n */\r\nexport function registerBuiltInDirective(name: string, def: DirectiveDefinition): void {\r\n builtInDirectives.set(name, def);\r\n}\r\n\r\n/**\r\n * Look up a registered built-in directive by name.\r\n * Used by SSR renderer to resolve `use:<name>={value}` shorthand.\r\n * @internal\r\n */\r\nexport function resolveBuiltInDirective(name: string): DirectiveDefinition | undefined {\r\n return builtInDirectives.get(name);\r\n}\r\n\r\n/**\r\n * Symbol key to store directive state on DOM elements.\r\n * @internal\r\n */\r\nconst DIRECTIVE_STATE = Symbol.for('sigx.directives');\r\n\r\n/**\r\n * Per-directive state stored on a DOM element.\r\n * @internal\r\n */\r\ninterface DirectiveState {\r\n def: DirectiveDefinition;\r\n value: any;\r\n cleanup?: () => void;\r\n}\r\n\r\n/**\r\n * Get or create the directive state map on a DOM element.\r\n * @internal\r\n */\r\nfunction getDirectiveMap(el: Element): Map<string, DirectiveState> {\r\n let map = (el as any)[DIRECTIVE_STATE] as Map<string, DirectiveState> | undefined;\r\n if (!map) {\r\n map = new Map();\r\n (el as any)[DIRECTIVE_STATE] = map;\r\n }\r\n return map;\r\n}\r\n\r\n/**\r\n * Process a `use:*` prop in patchProp.\r\n * Handles directive created and updated lifecycle hooks.\r\n * @internal\r\n */\r\nfunction patchDirective(el: Element, name: string, prevValue: any, nextValue: any, appContext: AppContext | null): void {\r\n const dirMap = getDirectiveMap(el);\r\n\r\n if (nextValue == null) {\r\n // Directive removed — unmounted will be called via onElementUnmounted\r\n dirMap.delete(name);\r\n return;\r\n }\r\n\r\n // Extract directive definition and binding value from the prop value:\r\n // - use:name={directiveDef} → def=directiveDef, value=undefined\r\n // - use:name={[directiveDef, value]} → def=directiveDef[0], value=directiveDef[1]\r\n let def: DirectiveDefinition;\r\n let value: any;\r\n\r\n if (isDirective(nextValue)) {\r\n def = nextValue;\r\n value = undefined;\r\n } else if (\r\n Array.isArray(nextValue) &&\r\n nextValue.length >= 1 &&\r\n isDirective(nextValue[0])\r\n ) {\r\n def = nextValue[0];\r\n value = nextValue[1];\r\n } else {\r\n // Not an explicit directive — try to resolve by name:\r\n // 1. Built-in directives (always available, e.g., 'show')\r\n // 2. App-registered custom directives (via app.directive())\r\n const builtIn = builtInDirectives.get(name);\r\n if (builtIn) {\r\n def = builtIn;\r\n value = nextValue;\r\n } else {\r\n const custom = appContext?.directives.get(name);\r\n if (custom) {\r\n def = custom;\r\n value = nextValue;\r\n } else {\r\n console.warn(\r\n `[sigx] Directive \"use:${name}\" could not be resolved. ` +\r\n `Make sure to register it via app.directive('${name}', definition) or pass a directive definition directly.`\r\n );\r\n return;\r\n }\r\n }\r\n }\r\n\r\n const existing = dirMap.get(name);\r\n\r\n if (!existing) {\r\n // First time — call created hook\r\n const state: DirectiveState = { def, value };\r\n dirMap.set(name, state);\r\n\r\n if (def.created) {\r\n def.created(el, { value });\r\n }\r\n } else {\r\n // Update — call updated hook\r\n const oldValue = existing.value;\r\n existing.def = def;\r\n existing.value = value;\r\n\r\n if (def.updated && value !== oldValue) {\r\n def.updated(el, { value, oldValue });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Called after an element is inserted into the DOM.\r\n * Invokes `mounted` hooks for all directives on the element.\r\n * @internal\r\n */\r\nfunction onElementMounted(el: Element): void {\r\n const map = (el as any)[DIRECTIVE_STATE] as Map<string, DirectiveState> | undefined;\r\n if (!map) return;\r\n\r\n for (const [, state] of map) {\r\n if (state.def.mounted) {\r\n state.def.mounted(el, { value: state.value });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Called before an element is removed from the DOM.\r\n * Invokes `unmounted` hooks for all directives on the element.\r\n * @internal\r\n */\r\nfunction onElementUnmounted(el: Element): void {\r\n const map = (el as any)[DIRECTIVE_STATE] as Map<string, DirectiveState> | undefined;\r\n if (!map) return;\r\n\r\n for (const [, state] of map) {\r\n if (state.def.unmounted) {\r\n state.def.unmounted(el, { value: state.value });\r\n }\r\n if (state.cleanup) {\r\n state.cleanup();\r\n }\r\n }\r\n\r\n // Clean up the map\r\n map.clear();\r\n delete (el as any)[DIRECTIVE_STATE];\r\n}\r\n\r\n// SVG namespace for createElementNS\r\nconst svgNS = 'http://www.w3.org/2000/svg';\r\n\r\n// SVG elements that should be created with createElementNS\r\n// Based on https://developer.mozilla.org/en-US/docs/Web/SVG/Element\r\nconst svgElements = new Set([\r\n 'svg', 'animate', 'animateMotion', 'animateTransform', 'circle', 'clipPath',\r\n 'defs', 'desc', 'ellipse', 'feBlend', 'feColorMatrix', 'feComponentTransfer',\r\n 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap',\r\n 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG',\r\n 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology',\r\n 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile',\r\n 'feTurbulence', 'filter', 'foreignObject', 'g', 'image', 'line', 'linearGradient',\r\n 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline',\r\n 'radialGradient', 'rect', 'set', 'stop', 'switch', 'symbol', 'text', 'textPath',\r\n 'title', 'tspan', 'use', 'view'\r\n]);\r\n\r\n/**\r\n * Check if a tag is an SVG element\r\n */\r\nfunction _isSvgTag(tag: string): boolean {\r\n return svgElements.has(tag);\r\n}\r\n\r\n// Register DOM-specific model processor for intrinsic elements (checkbox, radio, etc.)\r\nsetPlatformModelProcessor((type, props, [stateObj, key], originalProps) => {\r\n // Helper to set value - uses onUpdate handler if available (for props model forwarding)\r\n const setValue = (v: any) => {\r\n const updateHandler = stateObj[`onUpdate:${key}`];\r\n if (typeof updateHandler === 'function') {\r\n updateHandler(v);\r\n } else {\r\n stateObj[key] = v;\r\n }\r\n };\r\n\r\n // Smart mapping for checkbox\r\n if (type === 'input' && originalProps.type === 'checkbox') {\r\n const val = stateObj[key];\r\n\r\n if (Array.isArray(val)) {\r\n // Array Checkbox (Multi-select)\r\n props.checked = val.includes(originalProps.value);\r\n\r\n const existingHandler = props['onUpdate:modelValue'];\r\n props['onUpdate:modelValue'] = (checked: boolean) => {\r\n const currentVal = originalProps.value;\r\n const currentArr = stateObj[key] as any[];\r\n if (checked) {\r\n if (!currentArr.includes(currentVal)) {\r\n setValue([...currentArr, currentVal]);\r\n }\r\n } else {\r\n setValue(currentArr.filter((i: any) => i !== currentVal));\r\n }\r\n if (existingHandler) existingHandler(checked);\r\n };\r\n } else {\r\n // Boolean Checkbox\r\n props.checked = val;\r\n const existingHandler = props['onUpdate:modelValue'];\r\n props['onUpdate:modelValue'] = (v: any) => {\r\n setValue(v);\r\n if (existingHandler) existingHandler(v);\r\n };\r\n }\r\n return true; // Handled\r\n }\r\n\r\n // Radio Button\r\n if (type === 'input' && originalProps.type === 'radio') {\r\n props.checked = stateObj[key] === originalProps.value;\r\n const existingHandler = props['onUpdate:modelValue'];\r\n props['onUpdate:modelValue'] = (checked: boolean) => {\r\n if (checked) setValue(originalProps.value);\r\n if (existingHandler) existingHandler(checked);\r\n };\r\n return true; // Handled\r\n }\r\n\r\n // Text input (default input type)\r\n if (type === 'input') {\r\n props.value = stateObj[key] ?? '';\r\n const existingHandler = props['onUpdate:modelValue'];\r\n props['onUpdate:modelValue'] = (v: any) => {\r\n setValue(v);\r\n if (existingHandler) existingHandler(v);\r\n };\r\n return true; // Handled\r\n }\r\n\r\n // Textarea\r\n if (type === 'textarea') {\r\n props.value = stateObj[key] ?? '';\r\n const existingHandler = props['onUpdate:modelValue'];\r\n props['onUpdate:modelValue'] = (v: any) => {\r\n setValue(v);\r\n if (existingHandler) existingHandler(v);\r\n };\r\n return true; // Handled\r\n }\r\n\r\n // Select\r\n if (type === 'select') {\r\n props.value = stateObj[key] ?? '';\r\n const existingHandler = props['onUpdate:modelValue'];\r\n props['onUpdate:modelValue'] = (v: any) => {\r\n setValue(v);\r\n if (existingHandler) existingHandler(v);\r\n };\r\n return true; // Handled\r\n }\r\n\r\n // Not handled - use generic fallback\r\n return false;\r\n});\r\n\r\nfunction patchProp(dom: Element, key: string, prevValue: any, nextValue: any, isSVG?: boolean) {\r\n // Guard: skip if dom is null (shouldn't happen but protects against edge cases)\r\n if (!dom) return;\r\n const tagName = dom.tagName.toLowerCase();\r\n \r\n // Detect SVG context: either passed explicitly or detect from element type\r\n // This ensures SVG attributes are handled correctly even if renderer doesn't pass isSVG\r\n const isSvgElement = isSVG ?? (dom instanceof SVGElement);\r\n \r\n const _oldProps = prevValue ? { [key]: prevValue } : {};\r\n const _newProps = nextValue ? { [key]: nextValue } : {};\r\n\r\n // This is a simplified version of updateProps that handles a single prop\r\n // But the original updateProps handled all props at once.\r\n // The renderer calls patchProp for each key.\r\n\r\n // Logic adapted from original updateProps\r\n const oldValue = prevValue;\r\n const newValue = nextValue;\r\n\r\n if (key === 'children' || key === 'key' || key === 'ref') return;\r\n\r\n if (key === 'style') {\r\n const el = dom as HTMLElement;\r\n if (typeof newValue === 'object' && newValue !== null) {\r\n const styleObj = newValue as Record<string, string | number>;\r\n // We might need to unset old styles if they are not in new styles\r\n // But here we only get the new value for the key.\r\n // Ideally patchProp should handle diffing inside style object if it's an object.\r\n // For now, let's assume full replacement or simple update.\r\n for (const styleKey in styleObj) {\r\n if (styleKey.startsWith('--')) {\r\n el.style.setProperty(styleKey, String(styleObj[styleKey]));\r\n } else {\r\n (el.style as any)[styleKey] = styleObj[styleKey];\r\n }\r\n }\r\n } else {\r\n el.style.cssText = String(newValue);\r\n }\r\n } else if (key.startsWith('on')) {\r\n if (key === 'onUpdate:modelValue' && (tagName === 'input' || tagName === 'textarea' || tagName === 'select')) {\r\n const el = dom as HTMLElement;\r\n if (oldValue) {\r\n const wrapper = (oldValue as any).__sigx_model_handler;\r\n if (wrapper) {\r\n el.removeEventListener('input', wrapper);\r\n el.removeEventListener('change', wrapper);\r\n }\r\n }\r\n\r\n if (newValue) {\r\n const handler = (e: Event) => {\r\n const target = e.target as HTMLInputElement;\r\n let val: any;\r\n\r\n if (target.type === 'checkbox' || target.type === 'radio') {\r\n val = target.checked;\r\n } else if (target.type === 'number') {\r\n val = target.valueAsNumber;\r\n } else if (tagName === 'select' && (dom as HTMLSelectElement).multiple) {\r\n val = Array.from((dom as HTMLSelectElement).selectedOptions).map(o => o.value);\r\n } else {\r\n val = target.value;\r\n }\r\n\r\n (newValue as Function)(val);\r\n };\r\n (newValue as any).__sigx_model_handler = handler;\r\n\r\n const inputType = (dom as HTMLInputElement).type;\r\n if (tagName === 'select' || (tagName === 'input' && (inputType === 'checkbox' || inputType === 'radio'))) {\r\n el.addEventListener('change', handler);\r\n } else {\r\n el.addEventListener('input', handler);\r\n }\r\n }\r\n return;\r\n }\r\n\r\n const eventName = key.slice(2).toLowerCase();\r\n // Store handlers on the DOM element to properly track them across re-renders\r\n // Using a Map keyed by event name to ensure we remove the correct wrapper\r\n const handlersKey = '__sigx_event_handlers';\r\n let handlers = (dom as any)[handlersKey] as Map<string, EventListener> | undefined;\r\n if (!handlers) {\r\n handlers = new Map();\r\n (dom as any)[handlersKey] = handlers;\r\n }\r\n\r\n // Remove old handler if exists\r\n const oldHandler = handlers.get(eventName);\r\n if (oldHandler) {\r\n dom.removeEventListener(eventName, oldHandler);\r\n handlers.delete(eventName);\r\n }\r\n\r\n // Add new handler\r\n if (newValue) {\r\n const handler = (e: Event) => {\r\n if (e instanceof CustomEvent) {\r\n (newValue as Function)(e.detail);\r\n } else {\r\n (newValue as Function)(e);\r\n }\r\n };\r\n handlers.set(eventName, handler);\r\n dom.addEventListener(eventName, handler as EventListener);\r\n }\r\n } else if (key === 'className') {\r\n // For SVG, use setAttribute to preserve case (class works on both)\r\n dom.setAttribute('class', String(newValue));\r\n } else if (key.startsWith('.')) {\r\n const propName = key.slice(1);\r\n (dom as any)[propName] = newValue;\r\n } else if (key.startsWith('prop:')) {\r\n const propName = key.slice(5);\r\n (dom as any)[propName] = newValue;\r\n } else if (isSvgElement) {\r\n // SVG elements: use setAttribute to preserve case-sensitive attribute names\r\n // SVG attributes like viewBox, preserveAspectRatio, etc. are case-sensitive\r\n if (key === 'innerHTML' || key === 'textContent') {\r\n // These can be set as properties even on SVG\r\n (dom as any)[key] = newValue ?? '';\r\n } else if (key.startsWith('xlink:')) {\r\n // xlink: attributes need special namespace handling\r\n const xlinkNS = 'http://www.w3.org/1999/xlink';\r\n if (newValue == null) {\r\n dom.removeAttributeNS(xlinkNS, key.slice(6));\r\n } else {\r\n dom.setAttributeNS(xlinkNS, key, String(newValue));\r\n }\r\n } else {\r\n // Standard SVG attribute - use setAttribute to preserve case\r\n if (newValue === true) dom.setAttribute(key, '');\r\n else if (newValue === false || newValue == null) dom.removeAttribute(key);\r\n else dom.setAttribute(key, String(newValue));\r\n }\r\n } else {\r\n if ((tagName === 'input' || tagName === 'textarea' || tagName === 'select') &&\r\n (key === 'value' || key === 'checked')) {\r\n if (tagName === 'select' && key === 'value') {\r\n // Defer setting select value until options are mounted\r\n queueMicrotask(() => {\r\n (dom as HTMLSelectElement).value = String(newValue ?? '');\r\n });\r\n return;\r\n }\r\n\r\n if (key === 'checked' && tagName === 'input') {\r\n (dom as HTMLInputElement).checked = Boolean(newValue);\r\n } else if (key === 'value') {\r\n (dom as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement).value = String(newValue ?? '');\r\n }\r\n } else if (key in dom) {\r\n // Skip undefined/null to avoid DOM coercing to 0 for numeric props like maxLength\r\n if (newValue == null) {\r\n // Remove attribute if it exists\r\n if (dom.hasAttribute?.(key)) {\r\n dom.removeAttribute(key);\r\n }\r\n } else {\r\n try {\r\n (dom as Record<string, any>)[key] = newValue;\r\n } catch {\r\n dom.setAttribute(key, String(newValue));\r\n }\r\n }\r\n } else if (tagName.includes('-') && !key.includes('-')) {\r\n (dom as Record<string, any>)[key] = newValue;\r\n } else {\r\n if (newValue === true) dom.setAttribute(key, '');\r\n else if (newValue === false || newValue == null) dom.removeAttribute(key);\r\n else dom.setAttribute(key, String(newValue));\r\n }\r\n }\r\n}\r\n\r\nconst nodeOps: RendererOptions<Node, Element> = {\r\n insert: (child, parent, anchor) => {\r\n if (anchor && anchor.parentNode !== parent) anchor = null;\r\n parent.insertBefore(child, anchor || null);\r\n },\r\n remove: (child) => {\r\n const parent = child.parentNode;\r\n if (parent) {\r\n parent.removeChild(child);\r\n }\r\n },\r\n createElement: (tag, isSVG, isCustomizedBuiltIn) => {\r\n if (isSVG) {\r\n return document.createElementNS(svgNS, tag);\r\n }\r\n const is = isCustomizedBuiltIn ? { is: isCustomizedBuiltIn } : undefined;\r\n return document.createElement(tag, is);\r\n },\r\n createText: (text) => document.createTextNode(text),\r\n createComment: (text) => document.createComment(text),\r\n setText: (node, text) => {\r\n node.nodeValue = text;\r\n },\r\n setElementText: (el, text) => {\r\n el.textContent = text;\r\n },\r\n parentNode: (node) => node.parentNode as Element,\r\n nextSibling: (node) => node.nextSibling,\r\n querySelector: (selector) => document.querySelector(selector),\r\n setScopeId: (el, id) => el.setAttribute(id, ''),\r\n cloneNode: (node) => node.cloneNode(true),\r\n getActiveElement: () => document.activeElement as Element | null,\r\n restoreFocus: (el) => {\r\n if (el instanceof HTMLElement || el instanceof SVGElement) {\r\n // Use preventScroll to avoid layout thrashing.\r\n // Suppress focus/blur events to prevent re-triggering reactive updates.\r\n const suppressEvent = (e: Event) => { e.stopImmediatePropagation(); };\r\n el.addEventListener('focus', suppressEvent, { capture: true, once: true });\r\n el.addEventListener('focusin', suppressEvent, { capture: true, once: true });\r\n // Also suppress blur on the element that will lose focus\r\n const current = document.activeElement;\r\n if (current instanceof HTMLElement) {\r\n current.addEventListener('blur', suppressEvent, { capture: true, once: true });\r\n current.addEventListener('focusout', suppressEvent, { capture: true, once: true });\r\n }\r\n el.focus({ preventScroll: true });\r\n }\r\n },\r\n patchProp,\r\n patchDirective,\r\n onElementMounted,\r\n onElementUnmounted\r\n};\r\n\r\nconst renderer = createRenderer(nodeOps);\r\n\r\n/**\r\n * Render a SignalX element to a DOM container.\r\n * Supports both Element references and CSS selectors.\r\n * \r\n * @example\r\n * ```tsx\r\n * import { render } from 'sigx';\r\n * \r\n * // Using CSS selector\r\n * render(<App />, \"#app\");\r\n * \r\n * // Using element reference\r\n * render(<App />, document.getElementById('app')!);\r\n * ```\r\n */\r\nexport const render = (element: JSXElement, container: Element | string, appContext?: AppContext): void => {\r\n const target = typeof container === 'string'\r\n ? document.querySelector(container)\r\n : container;\r\n\r\n if (!target) {\r\n throw new Error(`Render target \"${container}\" not found.`);\r\n }\r\n\r\n return renderer.render(element, target as Element, appContext);\r\n};\r\n\r\n// Export primitives for SSR plugins and hydration\r\nexport const { patch, mount, unmount, mountComponent } = renderer;\r\nexport { patchProp, patchDirective, onElementMounted, nodeOps };\r\n\r\n// Set up the default mount function for this platform\r\nsetDefaultMount((component: any, container: HTMLElement | Element | ShadowRoot | string, appContext?: AppContext): (() => void) => {\r\n const target = typeof container === 'string'\r\n ? document.querySelector(container)\r\n : container;\r\n\r\n if (!target) {\r\n throw new Error(`Mount target \"${container}\" not found.`);\r\n }\r\n\r\n render(component, target as Element, appContext);\r\n\r\n return () => {\r\n render(null, target as Element);\r\n };\r\n});\r\n\r\n// Export Portal component and moveBefore utilities\r\nexport { Portal, supportsMoveBefore, moveNode } from './Portal.js';\r\n\r\n// Export built-in directives\r\nexport { show } from './directives/show.js';\r\n\r\n// Register built-in directives so use:show={value} works without importing\r\nimport { show as _showDirective } from './directives/show.js';\r\nregisterBuiltInDirective('show', _showDirective);\r\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigx/runtime-dom",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "DOM runtime for SignalX",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -9,6 +9,10 @@
9
9
  ".": {
10
10
  "import": "./dist/index.js",
11
11
  "types": "./dist/index.d.ts"
12
+ },
13
+ "./internals": {
14
+ "import": "./dist/internals.js",
15
+ "types": "./dist/internals.d.ts"
12
16
  }
13
17
  },
14
18
  "files": [
@@ -29,13 +33,13 @@
29
33
  "url": "https://github.com/signalxjs/core/issues"
30
34
  },
31
35
  "dependencies": {
32
- "@sigx/reactivity": "^0.1.8",
33
- "@sigx/runtime-core": "^0.1.8"
36
+ "@sigx/reactivity": "^0.1.9",
37
+ "@sigx/runtime-core": "^0.1.9"
34
38
  },
35
39
  "devDependencies": {
36
40
  "typescript": "^5.9.3",
37
41
  "vite": "^8.0.0-beta.9",
38
- "@sigx/vite": "^0.1.8"
42
+ "@sigx/vite": "^0.1.9"
39
43
  },
40
44
  "scripts": {
41
45
  "build": "vite build && tsc --emitDeclarationOnly",
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/Portal.tsx","../src/directives/show.ts","../src/index.ts"],"sourcesContent":["/**\r\n * Portal component for rendering children to a different DOM location.\r\n * \r\n * Uses the `moveBefore` API (Chrome 133+) when available for state-preserving\r\n * DOM moves. Falls back to `insertBefore` for older browsers.\r\n * \r\n * @example\r\n * ```tsx\r\n * import { Portal } from '@sigx/runtime-dom';\r\n * \r\n * // Render to document.body (default)\r\n * <Portal>\r\n * <div class=\"modal\">Modal content</div>\r\n * </Portal>\r\n * \r\n * // Render to a specific container\r\n * <Portal to={document.getElementById('modal-root')}>\r\n * <div class=\"modal\">Modal content</div>\r\n * </Portal>\r\n * \r\n * // Render to a container by selector\r\n * <Portal to=\"#modal-root\">\r\n * <div class=\"modal\">Modal content</div>\r\n * </Portal>\r\n * ```\r\n */\r\n\r\nimport { component, DefineProp, Fragment, VNode, jsx, normalizeSubTree } from '@sigx/runtime-core';\r\nimport { effect } from '@sigx/reactivity';\r\nimport { mount, unmount, patch } from './index.js';\r\n\r\n/**\r\n * Check if the browser supports the moveBefore API.\r\n * moveBefore allows moving DOM nodes without losing state (iframes, videos, focus, etc.)\r\n */\r\nexport function supportsMoveBefore(): boolean {\r\n return typeof Node !== 'undefined' && 'moveBefore' in Node.prototype;\r\n}\r\n\r\n/**\r\n * Move or insert a node into a parent, using moveBefore when available\r\n * for state-preserving moves.\r\n * \r\n * @param parent - The target parent element\r\n * @param node - The node to move/insert\r\n * @param anchor - Optional reference node to insert before\r\n */\r\nexport function moveNode(\r\n parent: Element,\r\n node: Node,\r\n anchor: Node | null = null\r\n): void {\r\n if (supportsMoveBefore()) {\r\n // Use moveBefore for state-preserving move (Chrome 133+)\r\n (parent as any).moveBefore(node, anchor);\r\n } else {\r\n // Fallback to insertBefore (causes state reset for iframes, etc.)\r\n parent.insertBefore(node, anchor);\r\n }\r\n}\r\n\r\n/**\r\n * Resolve a portal target from a string selector or Element.\r\n * Returns document.body as fallback.\r\n */\r\nfunction resolveTarget(target: string | Element | undefined): Element {\r\n if (target === undefined) {\r\n return document.body;\r\n }\r\n \r\n if (typeof target === 'string') {\r\n const resolved = document.querySelector(target);\r\n if (!resolved) {\r\n console.warn(`Portal: Target \"${target}\" not found, falling back to document.body`);\r\n return document.body;\r\n }\r\n return resolved;\r\n }\r\n \r\n return target;\r\n}\r\n\r\ntype PortalProps = DefineProp<'to', string | Element> & DefineProp<'disabled', boolean>;\r\n\r\n/**\r\n * Portal component - renders children to a different DOM location.\r\n * \r\n * Props:\r\n * - `to` - Target container (Element or CSS selector string). Defaults to document.body.\r\n * - `disabled` - When true, renders children in place instead of portaling\r\n * - `children` - Content to render in the portal\r\n * \r\n * Features:\r\n * - Uses `moveBefore` API (Chrome 133+) for state-preserving DOM moves\r\n * - Preserves iframe content, video playback, focus, and CSS animations\r\n * - Falls back to `insertBefore` for older browsers\r\n */\r\nexport const Portal = component<PortalProps>(({ props, slots, onMounted, onUnmounted }) => {\r\n // Container element for portal content\r\n let portalContainer: HTMLDivElement | null = null;\r\n let mountedVNode: VNode | null = null;\r\n let cleanupEffect: (() => void) | null = null;\r\n\r\n onMounted(() => {\r\n if (props.disabled) {\r\n return;\r\n }\r\n\r\n // Resolve target container\r\n const targetContainer = resolveTarget(props.to);\r\n\r\n // Create a container div for the portal content\r\n portalContainer = document.createElement('div');\r\n portalContainer.setAttribute('data-sigx-portal', '');\r\n\r\n // Use moveBefore when available for state-preserving move\r\n moveNode(targetContainer, portalContainer);\r\n\r\n // Set up reactive effect to render children into portal container\r\n const stopEffect = effect(() => {\r\n const children = slots.default();\r\n \r\n if (!portalContainer) return;\r\n \r\n // Normalize children to a proper VNode using the shared utility\r\n const vnode = normalizeSubTree(children);\r\n\r\n if (mountedVNode) {\r\n // Patch existing content\r\n patch(mountedVNode, vnode, portalContainer);\r\n } else {\r\n // Initial mount\r\n mount(vnode, portalContainer);\r\n }\r\n \r\n mountedVNode = vnode;\r\n });\r\n\r\n cleanupEffect = stopEffect;\r\n });\r\n\r\n onUnmounted(() => {\r\n // Stop the reactive effect\r\n if (cleanupEffect) {\r\n cleanupEffect();\r\n cleanupEffect = null;\r\n }\r\n\r\n // Unmount the portal content\r\n if (mountedVNode && portalContainer) {\r\n unmount(mountedVNode, portalContainer);\r\n mountedVNode = null;\r\n }\r\n\r\n // Remove the portal container from the DOM\r\n if (portalContainer && portalContainer.parentNode) {\r\n portalContainer.parentNode.removeChild(portalContainer);\r\n }\r\n portalContainer = null;\r\n });\r\n\r\n return () => {\r\n // When disabled, render children in place using jsx function\r\n if (props.disabled) {\r\n const children = slots.default();\r\n return jsx(Fragment, { children });\r\n }\r\n\r\n // When portal is active, render nothing in place\r\n // Children are rendered into the portal container via the effect\r\n return null;\r\n };\r\n}, { name: 'Portal' });\r\n","/**\r\n * Built-in `show` directive — toggles element visibility via `display` CSS property.\r\n *\r\n * Unlike conditional rendering (ternary in JSX), `use:show` keeps the element in the DOM\r\n * and only toggles its `display` style. This is useful when toggling is frequent and you\r\n * want to preserve element state (e.g., scroll position, input focus).\r\n *\r\n * @example\r\n * ```tsx\r\n * // Shorthand — directive resolved automatically:\r\n * <div use:show={isVisible}>Content</div>\r\n *\r\n * // Explicit tuple form:\r\n * import { show } from 'sigx';\r\n * <div use:show={[show, isVisible]}>Content</div>\r\n * ```\r\n */\r\n\r\nimport { defineDirective } from '@sigx/runtime-core';\r\n\r\n/** Symbol key for storing the original display value on elements. */\r\nconst ORIGINAL_DISPLAY = Symbol('sigx.show.originalDisplay');\r\n\r\n/** HTMLElement with the show directive's original display property. */\r\ninterface ShowElement extends HTMLElement {\r\n [ORIGINAL_DISPLAY]?: string;\r\n}\r\n\r\nexport const show = defineDirective<boolean, HTMLElement>({\r\n mounted(el, { value }) {\r\n const showEl = el as ShowElement;\r\n // Save the original display value now that all props have been applied\r\n const saved = showEl.style.display === 'none' ? '' : showEl.style.display;\r\n showEl[ORIGINAL_DISPLAY] = saved;\r\n showEl.style.display = value ? saved : 'none';\r\n },\r\n\r\n updated(el, { value, oldValue }) {\r\n if (value !== oldValue) {\r\n const showEl = el as ShowElement;\r\n showEl.style.display = value ? showEl[ORIGINAL_DISPLAY] ?? '' : 'none';\r\n }\r\n },\r\n\r\n unmounted(el) {\r\n const showEl = el as ShowElement;\r\n // Restore original display on cleanup\r\n const original = showEl[ORIGINAL_DISPLAY];\r\n if (original !== undefined) {\r\n showEl.style.display = original;\r\n }\r\n }\r\n});\r\n","// Import JSX types (global augmentation)\r\nimport './jsx';\r\n// Import type augmentation for @sigx/runtime-core\r\nimport './types';\r\n// Import JSX type augmentation for built-in directives (IntelliSense for use:show, etc.)\r\nimport './directives/show-jsx-types';\r\nimport { VNode, Fragment, JSXElement, setPlatformModelProcessor, createRenderer, RendererOptions, Text, setDefaultMount } from '@sigx/runtime-core';\r\nimport { isDirective, type DirectiveDefinition, type DirectiveBinding } from '@sigx/runtime-core';\r\nimport type { AppContext } from '@sigx/runtime-core';\r\n\r\n/**\r\n * A directive definition narrowed to DOM elements.\r\n * Use this type when defining directives for the DOM renderer.\r\n *\r\n * @example\r\n * ```ts\r\n * import { defineDirective, type DOMDirective } from 'sigx';\r\n *\r\n * const tooltip = defineDirective<string, HTMLElement>({\r\n * mounted(el, { value }) {\r\n * el.title = value; // el is HTMLElement, fully typed\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport type DOMDirective<T = any> = DirectiveDefinition<T, HTMLElement>;\r\n\r\n// ============================================================================\r\n// Directive Runtime for DOM (element-level use:* directives)\r\n// ============================================================================\r\n\r\n/**\r\n * Registry of built-in directives by name.\r\n * When a `use:<name>` prop receives a plain value (not a DirectiveDefinition),\r\n * the runtime looks up the directive by name here.\r\n * @internal\r\n */\r\nconst builtInDirectives = new Map<string, DirectiveDefinition>();\r\n\r\n/**\r\n * Register a built-in directive so it can be used with the shorthand syntax:\r\n * `<div use:show={value}>` instead of `<div use:show={[show, value]}>`.\r\n * @internal\r\n */\r\nexport function registerBuiltInDirective(name: string, def: DirectiveDefinition): void {\r\n builtInDirectives.set(name, def);\r\n}\r\n\r\n/**\r\n * Look up a registered built-in directive by name.\r\n * Used by SSR renderer to resolve `use:<name>={value}` shorthand.\r\n * @internal\r\n */\r\nexport function resolveBuiltInDirective(name: string): DirectiveDefinition | undefined {\r\n return builtInDirectives.get(name);\r\n}\r\n\r\n/**\r\n * Symbol key to store directive state on DOM elements.\r\n * @internal\r\n */\r\nconst DIRECTIVE_STATE = Symbol.for('sigx.directives');\r\n\r\n/**\r\n * Per-directive state stored on a DOM element.\r\n * @internal\r\n */\r\ninterface DirectiveState {\r\n def: DirectiveDefinition;\r\n value: any;\r\n cleanup?: () => void;\r\n}\r\n\r\n/**\r\n * Get or create the directive state map on a DOM element.\r\n * @internal\r\n */\r\nfunction getDirectiveMap(el: Element): Map<string, DirectiveState> {\r\n let map = (el as any)[DIRECTIVE_STATE] as Map<string, DirectiveState> | undefined;\r\n if (!map) {\r\n map = new Map();\r\n (el as any)[DIRECTIVE_STATE] = map;\r\n }\r\n return map;\r\n}\r\n\r\n/**\r\n * Process a `use:*` prop in patchProp.\r\n * Handles directive created and updated lifecycle hooks.\r\n * @internal\r\n */\r\nfunction patchDirective(el: Element, name: string, prevValue: any, nextValue: any, appContext: AppContext | null): void {\r\n const dirMap = getDirectiveMap(el);\r\n\r\n if (nextValue == null) {\r\n // Directive removed — unmounted will be called via onElementUnmounted\r\n dirMap.delete(name);\r\n return;\r\n }\r\n\r\n // Extract directive definition and binding value from the prop value:\r\n // - use:name={directiveDef} → def=directiveDef, value=undefined\r\n // - use:name={[directiveDef, value]} → def=directiveDef[0], value=directiveDef[1]\r\n let def: DirectiveDefinition;\r\n let value: any;\r\n\r\n if (isDirective(nextValue)) {\r\n def = nextValue;\r\n value = undefined;\r\n } else if (\r\n Array.isArray(nextValue) &&\r\n nextValue.length >= 1 &&\r\n isDirective(nextValue[0])\r\n ) {\r\n def = nextValue[0];\r\n value = nextValue[1];\r\n } else {\r\n // Not an explicit directive — try to resolve by name:\r\n // 1. Built-in directives (always available, e.g., 'show')\r\n // 2. App-registered custom directives (via app.directive())\r\n const builtIn = builtInDirectives.get(name);\r\n if (builtIn) {\r\n def = builtIn;\r\n value = nextValue;\r\n } else {\r\n const custom = appContext?.directives.get(name);\r\n if (custom) {\r\n def = custom;\r\n value = nextValue;\r\n } else {\r\n console.warn(\r\n `[sigx] Directive \"use:${name}\" could not be resolved. ` +\r\n `Make sure to register it via app.directive('${name}', definition) or pass a directive definition directly.`\r\n );\r\n return;\r\n }\r\n }\r\n }\r\n\r\n const existing = dirMap.get(name);\r\n\r\n if (!existing) {\r\n // First time — call created hook\r\n const state: DirectiveState = { def, value };\r\n dirMap.set(name, state);\r\n\r\n if (def.created) {\r\n def.created(el, { value });\r\n }\r\n } else {\r\n // Update — call updated hook\r\n const oldValue = existing.value;\r\n existing.def = def;\r\n existing.value = value;\r\n\r\n if (def.updated && value !== oldValue) {\r\n def.updated(el, { value, oldValue });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Called after an element is inserted into the DOM.\r\n * Invokes `mounted` hooks for all directives on the element.\r\n * @internal\r\n */\r\nfunction onElementMounted(el: Element): void {\r\n const map = (el as any)[DIRECTIVE_STATE] as Map<string, DirectiveState> | undefined;\r\n if (!map) return;\r\n\r\n for (const [, state] of map) {\r\n if (state.def.mounted) {\r\n state.def.mounted(el, { value: state.value });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Called before an element is removed from the DOM.\r\n * Invokes `unmounted` hooks for all directives on the element.\r\n * @internal\r\n */\r\nfunction onElementUnmounted(el: Element): void {\r\n const map = (el as any)[DIRECTIVE_STATE] as Map<string, DirectiveState> | undefined;\r\n if (!map) return;\r\n\r\n for (const [, state] of map) {\r\n if (state.def.unmounted) {\r\n state.def.unmounted(el, { value: state.value });\r\n }\r\n if (state.cleanup) {\r\n state.cleanup();\r\n }\r\n }\r\n\r\n // Clean up the map\r\n map.clear();\r\n delete (el as any)[DIRECTIVE_STATE];\r\n}\r\n\r\n// SVG namespace for createElementNS\r\nconst svgNS = 'http://www.w3.org/2000/svg';\r\n\r\n// SVG elements that should be created with createElementNS\r\n// Based on https://developer.mozilla.org/en-US/docs/Web/SVG/Element\r\nconst svgElements = new Set([\r\n 'svg', 'animate', 'animateMotion', 'animateTransform', 'circle', 'clipPath',\r\n 'defs', 'desc', 'ellipse', 'feBlend', 'feColorMatrix', 'feComponentTransfer',\r\n 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap',\r\n 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG',\r\n 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology',\r\n 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile',\r\n 'feTurbulence', 'filter', 'foreignObject', 'g', 'image', 'line', 'linearGradient',\r\n 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline',\r\n 'radialGradient', 'rect', 'set', 'stop', 'switch', 'symbol', 'text', 'textPath',\r\n 'title', 'tspan', 'use', 'view'\r\n]);\r\n\r\n/**\r\n * Check if a tag is an SVG element\r\n */\r\nfunction isSvgTag(tag: string): boolean {\r\n return svgElements.has(tag);\r\n}\r\n\r\n// Register DOM-specific model processor for intrinsic elements (checkbox, radio, etc.)\r\nsetPlatformModelProcessor((type, props, [stateObj, key], originalProps) => {\r\n // Helper to set value - uses onUpdate handler if available (for props model forwarding)\r\n const setValue = (v: any) => {\r\n const updateHandler = stateObj[`onUpdate:${key}`];\r\n if (typeof updateHandler === 'function') {\r\n updateHandler(v);\r\n } else {\r\n stateObj[key] = v;\r\n }\r\n };\r\n\r\n // Smart mapping for checkbox\r\n if (type === 'input' && originalProps.type === 'checkbox') {\r\n const val = stateObj[key];\r\n\r\n if (Array.isArray(val)) {\r\n // Array Checkbox (Multi-select)\r\n props.checked = val.includes(originalProps.value);\r\n\r\n const existingHandler = props['onUpdate:modelValue'];\r\n props['onUpdate:modelValue'] = (checked: boolean) => {\r\n const currentVal = originalProps.value;\r\n const currentArr = stateObj[key] as any[];\r\n if (checked) {\r\n if (!currentArr.includes(currentVal)) {\r\n setValue([...currentArr, currentVal]);\r\n }\r\n } else {\r\n setValue(currentArr.filter((i: any) => i !== currentVal));\r\n }\r\n if (existingHandler) existingHandler(checked);\r\n };\r\n } else {\r\n // Boolean Checkbox\r\n props.checked = val;\r\n const existingHandler = props['onUpdate:modelValue'];\r\n props['onUpdate:modelValue'] = (v: any) => {\r\n setValue(v);\r\n if (existingHandler) existingHandler(v);\r\n };\r\n }\r\n return true; // Handled\r\n }\r\n\r\n // Radio Button\r\n if (type === 'input' && originalProps.type === 'radio') {\r\n props.checked = stateObj[key] === originalProps.value;\r\n const existingHandler = props['onUpdate:modelValue'];\r\n props['onUpdate:modelValue'] = (checked: boolean) => {\r\n if (checked) setValue(originalProps.value);\r\n if (existingHandler) existingHandler(checked);\r\n };\r\n return true; // Handled\r\n }\r\n\r\n // Text input (default input type)\r\n if (type === 'input') {\r\n props.value = stateObj[key] ?? '';\r\n const existingHandler = props['onUpdate:modelValue'];\r\n props['onUpdate:modelValue'] = (v: any) => {\r\n setValue(v);\r\n if (existingHandler) existingHandler(v);\r\n };\r\n return true; // Handled\r\n }\r\n\r\n // Textarea\r\n if (type === 'textarea') {\r\n props.value = stateObj[key] ?? '';\r\n const existingHandler = props['onUpdate:modelValue'];\r\n props['onUpdate:modelValue'] = (v: any) => {\r\n setValue(v);\r\n if (existingHandler) existingHandler(v);\r\n };\r\n return true; // Handled\r\n }\r\n\r\n // Select\r\n if (type === 'select') {\r\n props.value = stateObj[key] ?? '';\r\n const existingHandler = props['onUpdate:modelValue'];\r\n props['onUpdate:modelValue'] = (v: any) => {\r\n setValue(v);\r\n if (existingHandler) existingHandler(v);\r\n };\r\n return true; // Handled\r\n }\r\n\r\n // Not handled - use generic fallback\r\n return false;\r\n});\r\n\r\nfunction patchProp(dom: Element, key: string, prevValue: any, nextValue: any, isSVG?: boolean) {\r\n // Guard: skip if dom is null (shouldn't happen but protects against edge cases)\r\n if (!dom) return;\r\n const tagName = dom.tagName.toLowerCase();\r\n \r\n // Detect SVG context: either passed explicitly or detect from element type\r\n // This ensures SVG attributes are handled correctly even if renderer doesn't pass isSVG\r\n const isSvgElement = isSVG ?? (dom instanceof SVGElement);\r\n \r\n const oldProps = prevValue ? { [key]: prevValue } : {};\r\n const newProps = nextValue ? { [key]: nextValue } : {};\r\n\r\n // This is a simplified version of updateProps that handles a single prop\r\n // But the original updateProps handled all props at once.\r\n // The renderer calls patchProp for each key.\r\n\r\n // Logic adapted from original updateProps\r\n const oldValue = prevValue;\r\n const newValue = nextValue;\r\n\r\n if (key === 'children' || key === 'key' || key === 'ref') return;\r\n\r\n if (key === 'style') {\r\n const el = dom as HTMLElement;\r\n if (typeof newValue === 'object' && newValue !== null) {\r\n const styleObj = newValue as Record<string, string | number>;\r\n // We might need to unset old styles if they are not in new styles\r\n // But here we only get the new value for the key.\r\n // Ideally patchProp should handle diffing inside style object if it's an object.\r\n // For now, let's assume full replacement or simple update.\r\n for (const styleKey in styleObj) {\r\n if (styleKey.startsWith('--')) {\r\n el.style.setProperty(styleKey, String(styleObj[styleKey]));\r\n } else {\r\n (el.style as any)[styleKey] = styleObj[styleKey];\r\n }\r\n }\r\n } else {\r\n el.style.cssText = String(newValue);\r\n }\r\n } else if (key.startsWith('on')) {\r\n if (key === 'onUpdate:modelValue' && (tagName === 'input' || tagName === 'textarea' || tagName === 'select')) {\r\n const el = dom as HTMLElement;\r\n if (oldValue) {\r\n const wrapper = (oldValue as any).__sigx_model_handler;\r\n if (wrapper) {\r\n el.removeEventListener('input', wrapper);\r\n el.removeEventListener('change', wrapper);\r\n }\r\n }\r\n\r\n if (newValue) {\r\n const handler = (e: Event) => {\r\n const target = e.target as HTMLInputElement;\r\n let val: any;\r\n\r\n if (target.type === 'checkbox' || target.type === 'radio') {\r\n val = target.checked;\r\n } else if (target.type === 'number') {\r\n val = target.valueAsNumber;\r\n } else if (tagName === 'select' && (dom as HTMLSelectElement).multiple) {\r\n val = Array.from((dom as HTMLSelectElement).selectedOptions).map(o => o.value);\r\n } else {\r\n val = target.value;\r\n }\r\n\r\n (newValue as Function)(val);\r\n };\r\n (newValue as any).__sigx_model_handler = handler;\r\n\r\n const inputType = (dom as HTMLInputElement).type;\r\n if (tagName === 'select' || (tagName === 'input' && (inputType === 'checkbox' || inputType === 'radio'))) {\r\n el.addEventListener('change', handler);\r\n } else {\r\n el.addEventListener('input', handler);\r\n }\r\n }\r\n return;\r\n }\r\n\r\n const eventName = key.slice(2).toLowerCase();\r\n // Store handlers on the DOM element to properly track them across re-renders\r\n // Using a Map keyed by event name to ensure we remove the correct wrapper\r\n const handlersKey = '__sigx_event_handlers';\r\n let handlers = (dom as any)[handlersKey] as Map<string, EventListener> | undefined;\r\n if (!handlers) {\r\n handlers = new Map();\r\n (dom as any)[handlersKey] = handlers;\r\n }\r\n\r\n // Remove old handler if exists\r\n const oldHandler = handlers.get(eventName);\r\n if (oldHandler) {\r\n dom.removeEventListener(eventName, oldHandler);\r\n handlers.delete(eventName);\r\n }\r\n\r\n // Add new handler\r\n if (newValue) {\r\n const handler = (e: Event) => {\r\n if (e instanceof CustomEvent) {\r\n (newValue as Function)(e.detail);\r\n } else {\r\n (newValue as Function)(e);\r\n }\r\n };\r\n handlers.set(eventName, handler);\r\n dom.addEventListener(eventName, handler as EventListener);\r\n }\r\n } else if (key === 'className') {\r\n // For SVG, use setAttribute to preserve case (class works on both)\r\n dom.setAttribute('class', String(newValue));\r\n } else if (key.startsWith('.')) {\r\n const propName = key.slice(1);\r\n (dom as any)[propName] = newValue;\r\n } else if (key.startsWith('prop:')) {\r\n const propName = key.slice(5);\r\n (dom as any)[propName] = newValue;\r\n } else if (isSvgElement) {\r\n // SVG elements: use setAttribute to preserve case-sensitive attribute names\r\n // SVG attributes like viewBox, preserveAspectRatio, etc. are case-sensitive\r\n if (key === 'innerHTML' || key === 'textContent') {\r\n // These can be set as properties even on SVG\r\n (dom as any)[key] = newValue ?? '';\r\n } else if (key.startsWith('xlink:')) {\r\n // xlink: attributes need special namespace handling\r\n const xlinkNS = 'http://www.w3.org/1999/xlink';\r\n if (newValue == null) {\r\n dom.removeAttributeNS(xlinkNS, key.slice(6));\r\n } else {\r\n dom.setAttributeNS(xlinkNS, key, String(newValue));\r\n }\r\n } else {\r\n // Standard SVG attribute - use setAttribute to preserve case\r\n if (newValue === true) dom.setAttribute(key, '');\r\n else if (newValue === false || newValue == null) dom.removeAttribute(key);\r\n else dom.setAttribute(key, String(newValue));\r\n }\r\n } else {\r\n if ((tagName === 'input' || tagName === 'textarea' || tagName === 'select') &&\r\n (key === 'value' || key === 'checked')) {\r\n if (tagName === 'select' && key === 'value') {\r\n // Defer setting select value until options are mounted\r\n queueMicrotask(() => {\r\n (dom as HTMLSelectElement).value = String(newValue ?? '');\r\n });\r\n return;\r\n }\r\n\r\n if (key === 'checked' && tagName === 'input') {\r\n (dom as HTMLInputElement).checked = Boolean(newValue);\r\n } else if (key === 'value') {\r\n (dom as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement).value = String(newValue ?? '');\r\n }\r\n } else if (key in dom) {\r\n // Skip undefined/null to avoid DOM coercing to 0 for numeric props like maxLength\r\n if (newValue == null) {\r\n // Remove attribute if it exists\r\n if (dom.hasAttribute?.(key)) {\r\n dom.removeAttribute(key);\r\n }\r\n } else {\r\n try {\r\n (dom as Record<string, any>)[key] = newValue;\r\n } catch (e) {\r\n dom.setAttribute(key, String(newValue));\r\n }\r\n }\r\n } else if (tagName.includes('-') && !key.includes('-')) {\r\n (dom as Record<string, any>)[key] = newValue;\r\n } else {\r\n if (newValue === true) dom.setAttribute(key, '');\r\n else if (newValue === false || newValue == null) dom.removeAttribute(key);\r\n else dom.setAttribute(key, String(newValue));\r\n }\r\n }\r\n}\r\n\r\nconst nodeOps: RendererOptions<Node, Element> = {\r\n insert: (child, parent, anchor) => {\r\n if (anchor && anchor.parentNode !== parent) anchor = null;\r\n parent.insertBefore(child, anchor || null);\r\n },\r\n remove: (child) => {\r\n const parent = child.parentNode;\r\n if (parent) {\r\n parent.removeChild(child);\r\n }\r\n },\r\n createElement: (tag, isSVG, isCustomizedBuiltIn) => {\r\n if (isSVG) {\r\n return document.createElementNS(svgNS, tag);\r\n }\r\n const is = isCustomizedBuiltIn ? { is: isCustomizedBuiltIn } : undefined;\r\n return document.createElement(tag, is);\r\n },\r\n createText: (text) => document.createTextNode(text),\r\n createComment: (text) => document.createComment(text),\r\n setText: (node, text) => {\r\n node.nodeValue = text;\r\n },\r\n setElementText: (el, text) => {\r\n el.textContent = text;\r\n },\r\n parentNode: (node) => node.parentNode as Element,\r\n nextSibling: (node) => node.nextSibling,\r\n querySelector: (selector) => document.querySelector(selector),\r\n setScopeId: (el, id) => el.setAttribute(id, ''),\r\n cloneNode: (node) => node.cloneNode(true),\r\n patchProp,\r\n patchDirective,\r\n onElementMounted,\r\n onElementUnmounted\r\n};\r\n\r\nconst renderer = createRenderer(nodeOps);\r\n\r\n/**\r\n * Render a SignalX element to a DOM container.\r\n * Supports both Element references and CSS selectors.\r\n * \r\n * @example\r\n * ```tsx\r\n * import { render } from 'sigx';\r\n * \r\n * // Using CSS selector\r\n * render(<App />, \"#app\");\r\n * \r\n * // Using element reference\r\n * render(<App />, document.getElementById('app')!);\r\n * ```\r\n */\r\nexport const render = (element: any, container: Element | string, appContext?: any): void => {\r\n const target = typeof container === 'string'\r\n ? document.querySelector(container)\r\n : container;\r\n\r\n if (!target) {\r\n throw new Error(`Render target \"${container}\" not found.`);\r\n }\r\n\r\n return renderer.render(element, target as Element, appContext);\r\n};\r\n\r\n// Export primitives for SSR plugins and hydration\r\nexport const { patch, mount, unmount, mountComponent } = renderer;\r\nexport { patchProp, patchDirective, onElementMounted, nodeOps };\r\n\r\n/**\r\n * Mount function for DOM environments.\r\n * Use this with defineApp().mount() to render to the DOM.\r\n * \r\n * @example\r\n * ```tsx\r\n * import { defineApp } from '@sigx/runtime-core';\r\n * import { domMount } from '@sigx/runtime-dom';\r\n * \r\n * const app = defineApp(<App />);\r\n * app.use(routerPlugin)\r\n * .mount(document.getElementById('app')!, domMount);\r\n * ```\r\n */\r\nexport const domMount = (component: any, container: HTMLElement | Element | ShadowRoot | string, appContext?: any): (() => void) => {\r\n // Resolve string selector to element\r\n const target = typeof container === 'string'\r\n ? document.querySelector(container)\r\n : container;\r\n\r\n if (!target) {\r\n throw new Error(`Mount target \"${container}\" not found.`);\r\n }\r\n\r\n render(component, target as Element, appContext);\r\n\r\n // Return an unmount function\r\n return () => {\r\n // Render null to unmount\r\n render(null as any, target as Element);\r\n };\r\n};\r\n\r\n// Set domMount as the default mount function for this platform\r\nsetDefaultMount(domMount);\r\n\r\n// Export Portal component and moveBefore utilities\r\nexport { Portal, supportsMoveBefore, moveNode } from './Portal.js';\r\n\r\n// Export built-in directives\r\nexport { show } from './directives/show.js';\r\n\r\n// Register built-in directives so use:show={value} works without importing\r\nimport { show as _showDirective } from './directives/show.js';\r\nregisterBuiltInDirective('show', _showDirective);\r\n"],"mappings":"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"}