()
| 547 | } |
| 548 | |
| 549 | private renderVisibleItems(): void { |
| 550 | const { startIndex, endIndex, offsetY } = this.state; |
| 551 | |
| 552 | // Track which items are currently visible |
| 553 | const visibleKeys = new Set<string>(); |
| 554 | |
| 555 | // Position the content container |
| 556 | this.contentContainer.style.transform = `translateY(${offsetY}px)`; |
| 557 | |
| 558 | // Build map of currently rendered elements by key |
| 559 | const currentElements = new Map<string, HTMLElement>(); |
| 560 | for (const [key, element] of this.renderedElements) { |
| 561 | if (element.parentElement === this.contentContainer) { |
| 562 | currentElements.set(key, element); |
| 563 | } |
| 564 | } |
| 565 | |
| 566 | // Render visible items in order |
| 567 | let previousElement: HTMLElement | null = null; |
| 568 | for (let i = startIndex; i <= endIndex; i++) { |
| 569 | const item = this.items[i]; |
| 570 | const key = this.getItemKey(item, i); |
| 571 | visibleKeys.add(key); |
| 572 | |
| 573 | let element = this.renderedElements.get(key); |
| 574 | |
| 575 | if (element && this.invalidatedKeys.has(key)) { |
| 576 | if (this.resizeObserver) { |
| 577 | this.resizeObserver.unobserve(element); |
| 578 | } |
| 579 | element.remove(); |
| 580 | this.renderedElements.delete(key); |
| 581 | element = undefined; |
| 582 | } |
| 583 | |
| 584 | if (!element) { |
| 585 | // Create new element |
| 586 | element = this.renderItem(item, i); |
| 587 | |
| 588 | // Add data attribute for measurement tracking |
| 589 | element.dataset.virtualIndex = String(i); |
| 590 | |
| 591 | this.renderedElements.set(key, element); |
| 592 | |
| 593 | // Observe for size changes |
| 594 | if (this.resizeObserver) { |
| 595 | this.resizeObserver.observe(element); |
| 596 | } |
| 597 | } else { |
| 598 | // Update index for existing element |
| 599 | element.dataset.virtualIndex = String(i); |
| 600 | } |
| 601 | this.invalidatedKeys.delete(key); |
| 602 | |
| 603 | // Only manipulate DOM if element is not in correct position |
| 604 | if (previousElement) { |
| 605 | // Element should come after previousElement |
| 606 | if (element.previousElementSibling !== previousElement) { |
no test coverage detected