commits
Introduce preserveActiveElement to protect the focused element from moves, replacement, and removal so typing state can stay stable when requested without changing default behavior.
Elements with IDs can only match by their ID - they are semantically
distinct entities. Previously, if an element with an ID failed to match
in the ID matching phase, it could still incorrectly match in the
heuristics or tagName phases.
This change separates elements with IDs into a dedicated `idElements`
pool at build time, so they:
1. Skip the expensive `isEqualNode` check entirely
2. Only participate in ID matching
3. Get removed if no ID match is found
The idSet matching phase (for elements matched by descendant IDs) now
correctly iterates over `candidateElements` since elements with idSets
may not have IDs themselves.
This is both a correctness fix and a performance optimization.
* Only flag dirty inputs if preserveChanges is disabled
* Use idSets for one side
* Simplify attribute loops
* Bump deps
Elements with IDs can only match by their ID - they are semantically
distinct entities. Previously, if an element with an ID failed to match
in the ID matching phase, it could still incorrectly match in the
heuristics or tagName phases.
This change separates elements with IDs into a dedicated `idElements`
pool at build time, so they:
1. Skip the expensive `isEqualNode` check entirely
2. Only participate in ID matching
3. Get removed if no ID match is found
The idSet matching phase (for elements matched by descendant IDs) now
correctly iterates over `candidateElements` since elements with idSets
may not have IDs themselves.
This is both a correctness fix and a performance optimization.