···246246 this.#options = options
247247 }
248248249249- // Find longest increasing subsequence to minimize moves during reordering
250250- // Returns the indices in the sequence that form the LIS
251251- #longestIncreasingSubsequence(sequence: Array<number | undefined>): Array<number> {
252252- const n = sequence.length
253253- if (n === 0) return []
254254-255255- // smallestEnding[i] = smallest ending value of any increasing subsequence of length i+1
256256- const smallestEnding: Array<number> = []
257257- // indices[i] = index in sequence where smallestEnding[i] occurs
258258- const indices: Array<number> = []
259259- // prev[i] = previous index in the LIS ending at sequence[i]
260260- const prev: Array<number> = new Array(n)
261261-262262- // Build the LIS by processing each value
263263- for (let i = 0; i < n; i++) {
264264- const val = sequence[i]
265265- if (val === undefined) continue // Skip new nodes (not in original sequence)
266266-267267- // Binary search: find where this value fits in smallestEnding
268268- let left = 0
269269- let right = smallestEnding.length
270270-271271- while (left < right) {
272272- const mid = Math.floor((left + right) / 2)
273273- if (smallestEnding[mid]! < val) left = mid + 1
274274- else right = mid
275275- }
276276-277277- // Link this element to the previous one in the subsequence
278278- prev[i] = left > 0 ? indices[left - 1]! : -1
279279-280280- // Either extend the sequence or update an existing position
281281- if (left === smallestEnding.length) {
282282- // Extend: this value is larger than all previous endings
283283- smallestEnding.push(val)
284284- indices.push(i)
285285- } else {
286286- // Update: found a better (smaller) ending for this length
287287- smallestEnding[left] = val
288288- indices[left] = i
289289- }
290290- }
291291-292292- // Reconstruct the actual indices that form the LIS
293293- const result: Array<number> = []
294294- if (indices.length === 0) return result
295295-296296- // Walk backwards through prev links to build the LIS
297297- let curr: number | undefined = indices[indices.length - 1]
298298- while (curr !== undefined && curr !== -1) {
299299- result.unshift(curr)
300300- curr = prev[curr]
301301- }
302302-303303- return result
304304- }
305305-306249 morph(from: ChildNode, to: ChildNode | NodeListOf<ChildNode>): void {
307250 if (isParentNode(from)) {
308251 this.#mapIdSets(from)
···678621679622 // Find LIS - these nodes don't need to move
680623 // matches already contains the fromChildNodes indices, so we can use it directly
681681- const lisIndices = this.#longestIncreasingSubsequence(matches)
624624+ const lisIndices = longestIncreasingSubsequence(matches)
682625683626 const shouldNotMove: Array<boolean> = new Array(fromChildNodes.length)
684627 for (let i = 0; i < lisIndices.length; i++) {
···808751function isParentNode(node: Node): node is ParentNode {
809752 return !!IS_PARENT_NODE_TYPE[node.nodeType]
810753}
754754+755755+// Find longest increasing subsequence to minimize moves during reordering
756756+// Returns the indices in the sequence that form the LIS
757757+function longestIncreasingSubsequence(sequence: Array<number | undefined>): Array<number> {
758758+ const n = sequence.length
759759+ if (n === 0) return []
760760+761761+ // smallestEnding[i] = smallest ending value of any increasing subsequence of length i+1
762762+ const smallestEnding: Array<number> = []
763763+ // indices[i] = index in sequence where smallestEnding[i] occurs
764764+ const indices: Array<number> = []
765765+ // prev[i] = previous index in the LIS ending at sequence[i]
766766+ const prev: Array<number> = new Array(n)
767767+768768+ // Build the LIS by processing each value
769769+ for (let i = 0; i < n; i++) {
770770+ const val = sequence[i]
771771+ if (val === undefined) continue // Skip new nodes (not in original sequence)
772772+773773+ // Binary search: find where this value fits in smallestEnding
774774+ let left = 0
775775+ let right = smallestEnding.length
776776+777777+ while (left < right) {
778778+ const mid = Math.floor((left + right) / 2)
779779+ if (smallestEnding[mid]! < val) left = mid + 1
780780+ else right = mid
781781+ }
782782+783783+ // Link this element to the previous one in the subsequence
784784+ prev[i] = left > 0 ? indices[left - 1]! : -1
785785+786786+ // Either extend the sequence or update an existing position
787787+ if (left === smallestEnding.length) {
788788+ // Extend: this value is larger than all previous endings
789789+ smallestEnding.push(val)
790790+ indices.push(i)
791791+ } else {
792792+ // Update: found a better (smaller) ending for this length
793793+ smallestEnding[left] = val
794794+ indices[left] = i
795795+ }
796796+ }
797797+798798+ // Reconstruct the actual indices that form the LIS
799799+ const result: Array<number> = []
800800+ if (indices.length === 0) return result
801801+802802+ // Walk backwards through prev links to build the LIS
803803+ let curr: number | undefined = indices[indices.length - 1]
804804+ while (curr !== undefined && curr !== -1) {
805805+ result.unshift(curr)
806806+ curr = prev[curr]
807807+ }
808808+809809+ return result
810810+}