{"version":3,"file":"listine.mjs","sources":["../../../projects/listine/src/lib/listtine-virtual/variable-virtual-scroll/listine-virtual-scroll.component.ts","../../../projects/listine/src/lib/listtine-virtual/variable-virtual-scroll/listine-virtual-scroll.component.html","../../../projects/listine/src/public-api.ts","../../../projects/listine/src/listine.ts"],"sourcesContent":["import {\n  Component,\n  Input,\n  TemplateRef,\n  ViewChild,\n  ElementRef,\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  ViewChildren,\n  QueryList,\n  EventEmitter,\n  Output,\n  OnChanges,\n  SimpleChanges,\n  OnInit,\n  OnDestroy,\n  NgZone,\n} from \"@angular/core\";\nimport { CommonModule } from \"@angular/common\";\n\n/**\n * `s73-variable-virtual-scroll`\n *\n * A lightweight, customizable virtual scroll component that supports variable item heights.\n * Efficiently renders only visible items to improve performance for large lists.\n *\n * ## Inputs:\n * - `items`: List of data items to display\n * - `viewportHeight`: Height of the scrollable container (default: 400px)\n * - `buffer`: Number of extra items rendered above and below the viewport for smooth scrolling (default: 5)\n * - `itemTemplate`: Angular template for rendering each item\n * - `initialItemHeight`: Default item height before measurement (default: 50px)\n *\n * ## Outputs:\n * - `scrollEmitter`: Emits scroll position on every scroll event\n */\n@Component({\n  selector: \"listine-variable-virtual-scroll\",\n  standalone: true,\n  imports: [CommonModule],\n  templateUrl: \"./listine-virtual-scroll.component.html\",\n  styleUrls: [\"./listine-virtual-scroll.component.scss\"],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ListineVirtualScrollModule\n  implements OnInit, AfterViewInit, OnChanges, OnDestroy\n{\n  /** List of all items to render */\n  @Input() items: any[] = [];\n\n  /** Height of the scrollable viewport in pixels */\n  @Input() viewportHeight = 400;\n\n  /** Number of extra items to render above and below the viewport */\n  @Input() buffer = 5;\n\n  /** Template reference for rendering each item */\n  @Input() itemTemplate: TemplateRef<any>;\n\n  /** Flag to track if panel is open */\n  @Input() panelOpen: boolean = false;\n\n  /** Initial estimated height of each item before actual measurement */\n  @Input() initialItemHeight = 50;\n\n  /** Emits scroll position whenever user scrolls */\n  @Output() scrollEmitter = new EventEmitter<any>();\n\n  /** Emits when user scrolls to the end of the list */\n  @Output() scrollToEnd = new EventEmitter<void>();\n\n  /** Reference to the scrolling container */\n  @ViewChild(\"scroller\", { static: true }) scrollerRef!: ElementRef;\n\n  /** QueryList of rendered item elements (used for height measurement) */\n  @ViewChildren(\"itemElement\", { read: ElementRef })\n  itemElements!: QueryList<ElementRef>;\n\n  /** Stores measured heights of items */\n  itemHeights: number[] = [];\n\n  /** Stores calculated top offset for each item */\n  itemTops: number[] = [];\n\n  /** Total height of all items (used to simulate full scrollable area) */\n  totalContentHeight = 0;\n\n  /** Index of the first visible item (including buffer) */\n  visibleStart = 0;\n\n  /** Index of the last visible item (including buffer) */\n  visibleEnd = 0;\n\n  /** Items currently visible in the viewport */\n  visibleItems: any[] = [];\n\n  /** ResizeObserver to watch for item height changes */\n  private resizeObserver = new ResizeObserver(() => {\n    this.ngZone.run(() => {\n      this.measureItemHeights();\n    });\n  });\n\n  /** Previous scroll position to detect actual scrolling */\n  private previousScrollTop = 0;\n\n  constructor(private cdr: ChangeDetectorRef, private ngZone: NgZone) {}\n\n  /** Initialize item heights on component initialization */\n  ngOnInit(): void {\n    this.initializeHeights();\n  }\n\n  /**\n   * Respond to changes in input bindings (mainly the `items` array)\n   * @param changes - input property changes\n   */\n  ngOnChanges(changes: SimpleChanges): void {\n    if (changes[\"items\"]) {\n      this.items = changes[\"items\"].currentValue;\n      this.initializeHeights();\n\n      setTimeout(() => {\n        this.calculateHeights();\n        this.onScroll();\n      });\n    }\n    if (changes[\"panelOpen\"] && changes[\"panelOpen\"]?.currentValue) {\n      this.panelOpen = changes[\"panelOpen\"]?.currentValue;\n      this.onScroll();\n    }\n  }\n\n  /**\n   * Called after view initialization. Triggers initial height calculation.\n   */\n  ngAfterViewInit() {\n    setTimeout(() => {\n      this.calculateHeights();\n      this.onScroll();\n    });\n  }\n\n  /**\n   * Disconnects ResizeObserver on component destroy\n   */\n  ngOnDestroy(): void {\n    this.resizeObserver.disconnect();\n  }\n\n  /** Initializes item height and position tracking arrays */\n  initializeHeights() {\n    this.itemHeights = this.items.map(() => this.initialItemHeight);\n    this.updateItemTops();\n  }\n\n  /** Recalculates item top positions and content height */\n  calculateHeights() {\n    this.updateItemTops();\n  }\n\n  /** Updates top positions of all items based on their current heights */\n  updateItemTops() {\n    this.itemTops = [];\n    let top = 0;\n    for (const height of this.itemHeights) {\n      this.itemTops.push(top);\n      top += height;\n    }\n    this.totalContentHeight = top;\n  }\n\n  /**\n   * Returns the top position of an item by index\n   * @param index - index of the item\n   */\n  getItemTop(index: number): number {\n    return this.itemTops[index] || 0;\n  }\n\n  /** Scroll event handler: calculates which items should be visible */\n  onScroll() {\n    const scrollTop = this.scrollerRef.nativeElement.scrollTop;\n    const viewportBottom = scrollTop + this.viewportHeight;\n\n    let start = 0;\n    while (\n      start < this.items.length &&\n      this.getItemTop(start + 1) < scrollTop\n    ) {\n      start++;\n    }\n\n    let end = start;\n    while (end < this.items.length && this.getItemTop(end) < viewportBottom) {\n      end++;\n    }\n    this.visibleStart = Math.max(0, start - this.buffer);\n    this.visibleEnd = Math.min(this.items.length, end + this.buffer);\n    this.updateVisibleItems();\n    this.scrollEmitter.emit(scrollTop);\n\n    // Check if scrolled to the end\n    const scrollHeight = this.scrollerRef.nativeElement.scrollHeight;\n    const clientHeight = this.scrollerRef.nativeElement.clientHeight;\n    const isAtEnd = scrollTop + clientHeight >= scrollHeight - 1;\n\n    if (isAtEnd && scrollTop > this.previousScrollTop && scrollTop > 0) {\n      this.scrollToEnd.emit();\n    }\n\n    this.previousScrollTop = scrollTop;\n  }\n\n  /** Updates the list of items to be rendered based on scroll position */\n  updateVisibleItems() {\n    this.visibleItems = this.items.slice(this.visibleStart, this.visibleEnd);\n\n    // Wait for DOM render before measuring heights\n    setTimeout(() => {\n      this.measureItemHeights();\n    });\n  }\n\n  /** Measures actual heights of rendered DOM elements and updates tracking */\n  measureItemHeights() {\n    this.itemElements.forEach((el, idx) => {\n      const index = this.visibleStart + idx;\n      const height = el.nativeElement.offsetHeight;\n      if (this.itemHeights[index] !== height) {\n        this.itemHeights[index] = height;\n        this.resizeObserver.observe(el.nativeElement);\n      }\n    });\n    this.updateItemTops();\n    this.cdr.markForCheck();\n  }\n}\n","<div\n  #scroller\n  class=\"scroll-container\"\n  (scroll)=\"onScroll()\"\n  [style.height.px]=\"viewportHeight\"\n>\n  <div\n    class=\"total-height\"\n    [style.height.px]=\"totalContentHeight - viewportHeight\"\n  >\n    <ng-container *ngFor=\"let item of visibleItems; let i = index\">\n      <div\n        #itemElement\n        class=\"item\"\n        [style.transform]=\"'translateY(' + getItemTop(visibleStart + i) + 'px)'\"\n      >\n        <ng-container\n          *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"\n        ></ng-container>\n      </div>\n    </ng-container>\n  </div>\n</div>\n","/*\n * Public API Surface of Listine\n */\n\nexport * from \"./lib/listtine-virtual/variable-virtual-scroll/listine-virtual-scroll.component\";\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}