/**
* @class 🎨 Renderer
* @classdesc A high-performance DOM renderer that implements an optimized two-pointer diffing
* algorithm with key-based node reconciliation. The renderer efficiently updates the DOM by
* computing the minimal set of operations needed to transform the current state to the desired state.
*
* Key features:
* - Two-pointer diffing algorithm for efficient DOM updates
* - Key-based node reconciliation for optimal list performance (O(1) lookup)
* - Preserves DOM node identity during reordering (maintains event listeners, focus, animations)
* - Intelligent attribute synchronization (skips Eleva event attributes)
* - Preservation of Eleva-managed component instances and style elements
*
* @example
* // Basic usage
* const renderer = new Renderer();
* renderer.patchDOM(container, '
Updated content
');
*
* @example
* // With keyed elements for optimal list updates
* const html = items.map(item => `${item.name}`).join('');
* renderer.patchDOM(listContainer, ``);
*
* @example
* // Keyed elements preserve DOM identity during reordering
* // Before: [A, B, C] -> After: [C, A, B]
* // The actual DOM nodes are moved, not recreated
* renderer.patchDOM(container, 'C
A
B
');
*
* @implements {RendererLike}
*/
export class Renderer implements RendererLike {
/**
* Temporary container for parsing new HTML content.
* Reused across patch operations to minimize memory allocation.
* @private
* @type {HTMLDivElement}
*/
private _tempContainer;
/**
* Patches the DOM of the given container with the provided HTML string.
* Uses an optimized two-pointer diffing algorithm to minimize DOM operations.
* The algorithm computes the minimal set of insertions, deletions, and updates
* needed to transform the current DOM state to match the new HTML.
*
* @public
* @param {HTMLElement} container - The container element to patch.
* @param {string} newHtml - The new HTML string to render.
* @returns {void}
*
* @example
* // Simple content update
* renderer.patchDOM(container, 'New content
');
*
* @example
* // List with keyed items (optimal for reordering)
* renderer.patchDOM(container, '');
*
* @example
* // Empty the container
* renderer.patchDOM(container, '');
*
* @see _diff - Low-level diffing algorithm.
* @see _patchNode - Individual node patching.
*/
public patchDOM(container: HTMLElement, newHtml: string): void;
/**
* Performs a diff between two DOM nodes and patches the old node to match the new node.
* Uses a two-pointer algorithm with key-based reconciliation for optimal performance.
* This method modifies oldParent in-place - it is not a pure function.
*
* Algorithm details:
* 1. Early exit if both nodes have no children (O(1) leaf node optimization)
* 2. Convert NodeLists to arrays for indexed access
* 3. Initialize two-pointer indices (oldStart/oldEnd, newStart/newEnd)
* 4. While pointers haven't crossed:
* a. Skip null entries (from previous moves)
* b. If nodes match (same key+tag or same type+name): patch and advance
* c. On mismatch: lazily build key→node map for O(1) lookup
* d. If keyed match found: move existing node (preserves DOM identity)
* e. Otherwise: clone and insert new node
* 5. After loop: append remaining new nodes or remove remaining old nodes
*
* Complexity: O(n) for most cases, O(n²) worst case with no keys.
* Non-keyed elements are matched by position and tag name.
*
* @private
* @param {Element} oldParent - The original DOM element to update (modified in-place).
* @param {Element} newParent - The new DOM element with desired state.
* @returns {void}
*/
private _diff;
/**
* Patches a single node, updating its content and attributes to match the new node.
* Handles text nodes (nodeType 3 / Node.TEXT_NODE) by updating nodeValue,
* and element nodes (nodeType 1 / Node.ELEMENT_NODE) by updating attributes
* and recursively diffing children.
*
* Skips nodes that are managed by Eleva component instances to prevent interference
* with nested component state.
*
* @private
* @param {Node} oldNode - The original DOM node to update.
* @param {Node} newNode - The new DOM node with desired state.
* @returns {void}
*/
private _patchNode;
/**
* Removes a node from its parent, with special handling for Eleva-managed elements.
* Style elements with the `data-e-style` attribute are preserved to maintain
* component styles across re-renders. Without this protection, component styles
* would be removed during DOM diffing and lost until the next full re-render.
*
* @note Style tags persist for the component's entire lifecycle. If the template
* conditionally removes elements that the CSS rules target (e.g., `.foo` elements),
* the style rules remain but simply have no matching elements. This is expected
* behavior - styles are cleaned up when the component unmounts, not when individual
* elements are removed.
*
* @private
* @param {HTMLElement} parent - The parent element containing the node.
* @param {Node} node - The node to remove.
* @returns {void}
* @see _injectStyles - Where data-e-style elements are created.
*/
private _removeNode;
/**
* Updates the attributes of an element to match a new element's attributes.
* Adds new attributes, updates changed values, and removes attributes no longer present.
* Also syncs DOM properties that can diverge from attributes after user interaction.
*
* Processing order:
* 1. Iterate new attributes, skip @ prefixed (event) attributes
* 2. Update attribute if value changed
* 3. Sync corresponding DOM property if writable (handles boolean conversion)
* 4. Iterate old attributes in reverse, remove if not in new element
* 5. Sync SYNC_PROPS (value, checked, selected) from new to old element
*
* @private
* @param {Element} oldEl - The original element to update.
* @param {Element} newEl - The new element with target attributes.
* @returns {void}
*/
private _updateAttributes;
/**
* Determines if two nodes are the same for reconciliation purposes.
* Two nodes are considered the same if:
* - Both have keys: keys match AND tag names match
* - Neither has keys: node types match AND node names match
* - One has key, other doesn't: not the same
*
* This ensures keyed elements are only reused when both key and tag match,
* preventing bugs like `` incorrectly matching ``.
*
* @private
* @param {Node} oldNode - The first node to compare.
* @param {Node} newNode - The second node to compare.
* @returns {boolean} True if the nodes are considered the same for reconciliation.
*/
private _isSameNode;
/**
* Extracts the key attribute from a node if it exists.
* Only element nodes (nodeType === 1) can have key attributes.
* Uses optional chaining for null-safe access.
*
* @private
* @param {Node | null | undefined} node - The node to extract the key from.
* @returns {string | null} The key attribute value, or null if not an element or no key.
*/
private _getNodeKey;
/**
* Creates a key map for efficient O(1) lookup of keyed elements during diffing.
* The map is built lazily only when needed (when a mismatch occurs during diffing).
*
* @private
* @param {ChildNode[]} children - The array of child nodes to map.
* @param {number} start - The start index (inclusive) for mapping.
* @param {number} end - The end index (inclusive) for mapping.
* @returns {KeyMap} A Map of key strings to their corresponding DOM nodes.
*/
private _createKeyMap;
}
/**
* Map of key attribute values to their corresponding DOM nodes.
*/
export type KeyMap = Map;
/**
* Interface describing the public API of a Renderer.
*/
export type RendererLike = {
/**
* Patches the DOM with new HTML content.
*/
patchDOM: (arg0: HTMLElement, arg1: string) => void;
};
//# sourceMappingURL=Renderer.d.ts.map