ng-virtual-list 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # NgVirtualList
2
+
3
+ Angular version 19.X.X.
4
+
5
+ ## Example
6
+ ![VirtualList-GoogleChrome2025-06-1321-18-21-ezgif com-crop](https://github.com/user-attachments/assets/7a364774-77d1-4ee6-8db0-4338a02d2357)
7
+
8
+ ```bash
9
+ npm i ng-virtual-list
10
+ ```
11
+
12
+ ```html
13
+ <ng-virtual-list class="list simple" [items]="items()" [itemRenderer]="itemRenderer"></ng-virtual-list>
14
+
15
+ <ng-template #itemRenderer let-data="data">
16
+ <div class="list__container">
17
+ <p>{{data?.name}}</p>
18
+ </div>
19
+ </ng-template>
20
+ ```
21
+
22
+ ```ts
23
+ const ITEMS: IVirtualListCollection = [];
24
+
25
+ for (let i = 0, l = 1000; i < l; i++) {
26
+ ITEMS.push({ id: i, name: `Item: ${i}` });
27
+ }
28
+
29
+ @Component({
30
+ selector: 'app-root',
31
+ imports: [NgVirtualListComponent],
32
+ templateUrl: './app.component.html',
33
+ styleUrl: './app.component.scss'
34
+ })
35
+ export class AppComponent {
36
+ items = signal(ITEMS);
37
+ }
38
+ ```
39
+
40
+
@@ -0,0 +1,163 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, signal, Component, viewChild, input, ViewContainerRef, ViewChild, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core';
3
+ import * as i1 from '@angular/common';
4
+ import { CommonModule } from '@angular/common';
5
+ import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
6
+ import { filter, map, combineLatest, switchMap, of, tap } from 'rxjs';
7
+
8
+ class NgVirtualListService {
9
+ constructor() { }
10
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgVirtualListService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
11
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgVirtualListService, providedIn: 'root' });
12
+ }
13
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgVirtualListService, decorators: [{
14
+ type: Injectable,
15
+ args: [{
16
+ providedIn: 'root'
17
+ }]
18
+ }], ctorParameters: () => [] });
19
+
20
+ class NgVirtualListItemComponent {
21
+ data = signal(undefined);
22
+ set item(v) {
23
+ this.data.set(v);
24
+ }
25
+ itemRenderer = signal(undefined);
26
+ set renderer(v) {
27
+ this.itemRenderer.set(v);
28
+ }
29
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgVirtualListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
30
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: NgVirtualListItemComponent, isStandalone: true, selector: "ng-virtual-list-item", ngImport: i0, template: "@let item = data();\r\n@let renderer = itemRenderer();\r\n\r\n@if (item) {\r\n@let translate3d = \"translate3d(0, \" + item.measures.y + \"px , 0)\";\r\n<li #listItem class=\"ngvl-item__container\" [style]=\"{'transform': translate3d}\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\" [ngTemplateOutletContext]=\"{data: item.data || {}}\" />\r\n }\r\n</li>\r\n}", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
31
+ }
32
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgVirtualListItemComponent, decorators: [{
33
+ type: Component,
34
+ args: [{ selector: 'ng-virtual-list-item', imports: [CommonModule], template: "@let item = data();\r\n@let renderer = itemRenderer();\r\n\r\n@if (item) {\r\n@let translate3d = \"translate3d(0, \" + item.measures.y + \"px , 0)\";\r\n<li #listItem class=\"ngvl-item__container\" [style]=\"{'transform': translate3d}\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\" [ngTemplateOutletContext]=\"{data: item.data || {}}\" />\r\n }\r\n</li>\r\n}" }]
35
+ }] });
36
+
37
+ const DEFAULT_ITEM_HEIGHT = 24;
38
+
39
+ class NgVirtualListComponent {
40
+ listContainerRef;
41
+ container = viewChild('container');
42
+ list = viewChild('list');
43
+ items = input.required();
44
+ itemRenderer = input.required();
45
+ itemHeight = input(DEFAULT_ITEM_HEIGHT);
46
+ _displayItems = signal(null);
47
+ _displayComponents = [];
48
+ _bounds = signal(null);
49
+ _scrollSize = signal(0);
50
+ _resizeObserver = null;
51
+ _onResizeHandler = () => {
52
+ this._bounds.set(this.container()?.nativeElement?.getBoundingClientRect() ?? null);
53
+ };
54
+ _onScrollHandler = (e) => {
55
+ const target = e.target;
56
+ this._scrollSize.set(target.scrollTop);
57
+ };
58
+ _sizeCacheMap = new Map();
59
+ constructor() {
60
+ const $bounds = toObservable(this._bounds).pipe(filter(b => !!b)), $items = toObservable(this.items).pipe(map(i => !i ? [] : i)), $scrollSize = toObservable(this._scrollSize), $itemHeight = toObservable(this.itemHeight);
61
+ combineLatest([$bounds, $items, $scrollSize, $itemHeight]).pipe(takeUntilDestroyed(), switchMap(([bounds, items, scrollSize, itemHeight]) => {
62
+ const { width, height } = bounds;
63
+ const itemsFromStartToScrollEnd = Math.floor(scrollSize / itemHeight), itemsFromStartToDisplayEnd = Math.ceil((scrollSize + height) / itemHeight), leftHiddenItemsWeight = itemsFromStartToScrollEnd * itemHeight, totalItemsToDisplayEndWeight = itemsFromStartToDisplayEnd * itemHeight, totalItems = items.length, totalSize = totalItems * itemHeight, itemsOnDisplay = totalItemsToDisplayEndWeight - leftHiddenItemsWeight;
64
+ return of({ items, width, itemsFromStartToScrollEnd, itemsOnDisplay, leftHiddenItemsWeight, itemHeight, totalSize });
65
+ }), tap(({ items, width, itemsFromStartToScrollEnd, itemsOnDisplay, leftHiddenItemsWeight, itemHeight, totalSize }) => {
66
+ const displayItems = [], totalItems = items.length;
67
+ let i = itemsFromStartToScrollEnd, y = leftHiddenItemsWeight, renderWeight = itemsOnDisplay;
68
+ while (renderWeight > 0) {
69
+ if (i >= totalItems) {
70
+ break;
71
+ }
72
+ renderWeight -= itemHeight;
73
+ y += itemHeight;
74
+ const id = items[i].id, measures = {
75
+ x: 0,
76
+ y,
77
+ width,
78
+ height: itemHeight,
79
+ };
80
+ const itemData = { ...items[i] };
81
+ delete itemData.id;
82
+ displayItems.push({ id, measures, data: itemData });
83
+ this._sizeCacheMap.set(id, measures);
84
+ i++;
85
+ }
86
+ this._displayItems.set(displayItems);
87
+ const l = this.list();
88
+ if (l) {
89
+ l.nativeElement.style.height = `${totalSize}px`;
90
+ }
91
+ })).subscribe();
92
+ toObservable(this._displayItems).pipe(takeUntilDestroyed(), tap(displayItems => {
93
+ this.createdisplayComponentsIfNeed(displayItems);
94
+ this.refresh(displayItems);
95
+ })).subscribe();
96
+ }
97
+ createdisplayComponentsIfNeed(displayItems) {
98
+ if (!displayItems || !this.listContainerRef) {
99
+ return;
100
+ }
101
+ const listContainerRef = this.listContainerRef;
102
+ while (this._displayComponents.length < displayItems.length) {
103
+ if (listContainerRef) {
104
+ const comp = listContainerRef.createComponent(NgVirtualListItemComponent);
105
+ this._displayComponents.push(comp);
106
+ }
107
+ }
108
+ if (this._displayComponents.length > displayItems.length) {
109
+ while (this._displayComponents.length > displayItems.length) {
110
+ const comp = this._displayComponents.pop();
111
+ comp?.destroy();
112
+ }
113
+ }
114
+ }
115
+ refresh(displayItems) {
116
+ if (!displayItems) {
117
+ return;
118
+ }
119
+ for (let i = 0, l = displayItems.length; i < l; i++) {
120
+ const el = this._displayComponents[i];
121
+ el.instance.item = displayItems[i];
122
+ el.instance.renderer = this.itemRenderer();
123
+ }
124
+ }
125
+ ngAfterViewInit() {
126
+ const containerEl = this.container();
127
+ if (containerEl) {
128
+ containerEl.nativeElement.addEventListener('scroll', this._onScrollHandler);
129
+ this._resizeObserver = new ResizeObserver(this._onResizeHandler);
130
+ this._resizeObserver.observe(containerEl.nativeElement);
131
+ this._onResizeHandler();
132
+ }
133
+ }
134
+ ngOnDestroy() {
135
+ const containerEl = this.container();
136
+ if (containerEl) {
137
+ containerEl.nativeElement.removeEventListener('scroll', this._onScrollHandler);
138
+ if (this._resizeObserver) {
139
+ this._resizeObserver.unobserve(containerEl.nativeElement);
140
+ }
141
+ }
142
+ }
143
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgVirtualListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
144
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.14", type: NgVirtualListComponent, isStandalone: true, selector: "ng-virtual-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, itemRenderer: { classPropertyName: "itemRenderer", publicName: "itemRenderer", isSignal: true, isRequired: true, transformFunction: null }, itemHeight: { classPropertyName: "itemHeight", publicName: "itemHeight", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, isSignal: true }, { propertyName: "list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "listContainerRef", first: true, predicate: ["renderersContainer"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "<div #container class=\"ngvl__container\">\r\n <ul #list class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </ul>\r\n</div>", styles: [":host{display:block;height:100%;width:100%;max-height:100%;overflow:hidden}.ngvl__container{overflow:auto;width:100%;height:100%}.ngvl__list{list-style:none;padding:0;margin:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
145
+ }
146
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgVirtualListComponent, decorators: [{
147
+ type: Component,
148
+ args: [{ selector: 'ng-virtual-list', imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.ShadowDom, template: "<div #container class=\"ngvl__container\">\r\n <ul #list class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </ul>\r\n</div>", styles: [":host{display:block;height:100%;width:100%;max-height:100%;overflow:hidden}.ngvl__container{overflow:auto;width:100%;height:100%}.ngvl__list{list-style:none;padding:0;margin:0}\n"] }]
149
+ }], ctorParameters: () => [], propDecorators: { listContainerRef: [{
150
+ type: ViewChild,
151
+ args: ['renderersContainer', { read: ViewContainerRef }]
152
+ }] } });
153
+
154
+ /*
155
+ * Public API Surface of ng-virtual-list
156
+ */
157
+
158
+ /**
159
+ * Generated bundle index. Do not edit.
160
+ */
161
+
162
+ export { NgVirtualListComponent, NgVirtualListService };
163
+ //# sourceMappingURL=ng-virtual-list.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ng-virtual-list.mjs","sources":["../../../projects/ng-virtual-list/src/lib/ng-virtual-list.service.ts","../../../projects/ng-virtual-list/src/lib/components/ng-virtual-list-item.component.ts","../../../projects/ng-virtual-list/src/lib/components/ng-virtual-list-item.component.html","../../../projects/ng-virtual-list/src/lib/const/index.ts","../../../projects/ng-virtual-list/src/lib/ng-virtual-list.component.ts","../../../projects/ng-virtual-list/src/lib/ng-virtual-list.component.html","../../../projects/ng-virtual-list/src/public-api.ts","../../../projects/ng-virtual-list/src/ng-virtual-list.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class NgVirtualListService {\r\n\r\n constructor() { }\r\n}\r\n","import { CommonModule } from '@angular/common';\r\nimport { Component, signal, TemplateRef } from '@angular/core';\r\nimport { IRenderVirtualListItem } from '../models';\r\n\r\n@Component({\r\n selector: 'ng-virtual-list-item',\r\n imports: [CommonModule],\r\n templateUrl: './ng-virtual-list-item.component.html',\r\n styleUrl: './ng-virtual-list-item.component.scss'\r\n})\r\nexport class NgVirtualListItemComponent {\r\n data = signal<IRenderVirtualListItem | undefined>(undefined);\r\n\r\n set item(v: IRenderVirtualListItem | undefined) {\r\n this.data.set(v);\r\n }\r\n\r\n itemRenderer = signal<TemplateRef<any> | undefined>(undefined);\r\n\r\n set renderer(v: TemplateRef<any> | undefined) {\r\n this.itemRenderer.set(v);\r\n }\r\n}\r\n","@let item = data();\r\n@let renderer = itemRenderer();\r\n\r\n@if (item) {\r\n@let translate3d = \"translate3d(0, \" + item.measures.y + \"px , 0)\";\r\n<li #listItem class=\"ngvl-item__container\" [style]=\"{'transform': translate3d}\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\" [ngTemplateOutletContext]=\"{data: item.data || {}}\" />\r\n }\r\n</li>\r\n}","export const DEFAULT_ITEM_HEIGHT = 24;","import {\r\n AfterViewInit, ChangeDetectionStrategy, Component, ComponentRef, ElementRef, input,\r\n OnDestroy, signal, TemplateRef, ViewChild, viewChild, ViewContainerRef, ViewEncapsulation,\r\n} from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';\r\nimport { combineLatest, filter, map, of, switchMap, tap } from 'rxjs';\r\nimport { NgVirtualListItemComponent } from './components/ng-virtual-list-item.component';\r\nimport { DEFAULT_ITEM_HEIGHT } from './const';\r\nimport { IRenderVirtualListCollection, IVirtualListCollection } from './models';\r\nimport { Id, IRect } from './types';\r\n\r\n@Component({\r\n selector: 'ng-virtual-list',\r\n imports: [CommonModule],\r\n templateUrl: './ng-virtual-list.component.html',\r\n styleUrl: './ng-virtual-list.component.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.ShadowDom,\r\n})\r\nexport class NgVirtualListComponent implements AfterViewInit, OnDestroy {\r\n @ViewChild('renderersContainer', { read: ViewContainerRef })\r\n protected listContainerRef: ViewContainerRef | undefined;\r\n\r\n protected container = viewChild<ElementRef<HTMLDivElement>>('container');\r\n\r\n protected list = viewChild<ElementRef<HTMLUListElement>>('list');\r\n\r\n items = input.required<IVirtualListCollection>();\r\n\r\n itemRenderer = input.required<TemplateRef<any>>();\r\n\r\n itemHeight = input(DEFAULT_ITEM_HEIGHT);\r\n\r\n protected _displayItems = signal<IRenderVirtualListCollection | null>(null);\r\n\r\n protected _displayComponents: Array<ComponentRef<NgVirtualListItemComponent>> = [];\r\n\r\n protected _bounds = signal<DOMRect | null>(null);\r\n\r\n protected _scrollSize = signal<number>(0);\r\n\r\n private _resizeObserver: ResizeObserver | null = null;\r\n\r\n private _onResizeHandler = () => {\r\n this._bounds.set(this.container()?.nativeElement?.getBoundingClientRect() ?? null);\r\n }\r\n\r\n private _onScrollHandler = (e: Event) => {\r\n const target = e.target as HTMLDivElement;\r\n this._scrollSize.set(target.scrollTop);\r\n }\r\n\r\n private _sizeCacheMap = new Map<Id, IRect>();\r\n\r\n constructor() {\r\n const $bounds = toObservable(this._bounds).pipe(\r\n filter(b => !!b),\r\n ), $items = toObservable(this.items).pipe(\r\n map(i => !i ? [] : i),\r\n ), $scrollSize = toObservable(this._scrollSize),\r\n $itemHeight = toObservable(this.itemHeight);\r\n\r\n combineLatest([$bounds, $items, $scrollSize, $itemHeight]).pipe(\r\n takeUntilDestroyed(),\r\n switchMap(([bounds, items, scrollSize, itemHeight]) => {\r\n const { width, height } = bounds;\r\n const itemsFromStartToScrollEnd = Math.floor(scrollSize / itemHeight),\r\n itemsFromStartToDisplayEnd = Math.ceil((scrollSize + height) / itemHeight),\r\n leftHiddenItemsWeight = itemsFromStartToScrollEnd * itemHeight,\r\n totalItemsToDisplayEndWeight = itemsFromStartToDisplayEnd * itemHeight,\r\n totalItems = items.length,\r\n totalSize = totalItems * itemHeight,\r\n itemsOnDisplay = totalItemsToDisplayEndWeight - leftHiddenItemsWeight;\r\n return of({ items, width, itemsFromStartToScrollEnd, itemsOnDisplay, leftHiddenItemsWeight, itemHeight, totalSize });\r\n }),\r\n tap(({ items, width, itemsFromStartToScrollEnd, itemsOnDisplay, leftHiddenItemsWeight, itemHeight, totalSize }) => {\r\n const displayItems: IRenderVirtualListCollection = [], totalItems = items.length;\r\n let i = itemsFromStartToScrollEnd, y = leftHiddenItemsWeight, renderWeight = itemsOnDisplay;\r\n\r\n\r\n while (renderWeight > 0) {\r\n if (i >= totalItems) {\r\n break;\r\n }\r\n\r\n renderWeight -= itemHeight;\r\n y += itemHeight;\r\n\r\n const id = items[i].id, measures = {\r\n x: 0,\r\n y,\r\n width,\r\n height: itemHeight,\r\n };\r\n\r\n const itemData: any = { ...items[i] };\r\n delete itemData.id;\r\n\r\n displayItems.push({ id, measures, data: itemData });\r\n\r\n this._sizeCacheMap.set(id, measures);\r\n\r\n i++;\r\n }\r\n\r\n this._displayItems.set(displayItems);\r\n\r\n const l = this.list();\r\n if (l) {\r\n l.nativeElement.style.height = `${totalSize}px`;\r\n }\r\n\r\n })\r\n ).subscribe();\r\n\r\n toObservable(this._displayItems).pipe(\r\n takeUntilDestroyed(),\r\n tap(displayItems => {\r\n this.createdisplayComponentsIfNeed(displayItems);\r\n this.refresh(displayItems);\r\n }),\r\n ).subscribe();\r\n }\r\n\r\n private createdisplayComponentsIfNeed(displayItems: IRenderVirtualListCollection | null) {\r\n if (!displayItems || !this.listContainerRef) {\r\n return;\r\n }\r\n const listContainerRef = this.listContainerRef;\r\n\r\n while (this._displayComponents.length < displayItems.length) {\r\n if (listContainerRef) {\r\n const comp = listContainerRef.createComponent(NgVirtualListItemComponent);\r\n this._displayComponents.push(comp);\r\n }\r\n }\r\n\r\n if (this._displayComponents.length > displayItems.length) {\r\n while (this._displayComponents.length > displayItems.length) {\r\n const comp = this._displayComponents.pop();\r\n comp?.destroy();\r\n }\r\n }\r\n }\r\n\r\n protected refresh(displayItems: IRenderVirtualListCollection | null) {\r\n if (!displayItems) {\r\n return;\r\n }\r\n\r\n for (let i = 0, l = displayItems.length; i < l; i++) {\r\n const el = this._displayComponents[i];\r\n el.instance.item = displayItems[i];\r\n el.instance.renderer = this.itemRenderer();\r\n }\r\n }\r\n\r\n ngAfterViewInit(): void {\r\n const containerEl = this.container();\r\n if (containerEl) {\r\n containerEl.nativeElement.addEventListener('scroll', this._onScrollHandler);\r\n\r\n this._resizeObserver = new ResizeObserver(this._onResizeHandler);\r\n this._resizeObserver.observe(containerEl.nativeElement);\r\n\r\n this._onResizeHandler();\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n const containerEl = this.container();\r\n if (containerEl) {\r\n containerEl.nativeElement.removeEventListener('scroll', this._onScrollHandler);\r\n\r\n if (this._resizeObserver) {\r\n this._resizeObserver.unobserve(containerEl.nativeElement);\r\n }\r\n }\r\n }\r\n}\r\n","<div #container class=\"ngvl__container\">\r\n <ul #list class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </ul>\r\n</div>","/*\r\n * Public API Surface of ng-virtual-list\r\n */\r\n\r\nexport * from './lib/ng-virtual-list.service';\r\nexport * from './lib/ng-virtual-list.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="ng-virtual-list" />
5
+ export * from './public-api';
@@ -0,0 +1,11 @@
1
+ import { TemplateRef } from '@angular/core';
2
+ import { IRenderVirtualListItem } from '../models';
3
+ import * as i0 from "@angular/core";
4
+ export declare class NgVirtualListItemComponent {
5
+ data: import("@angular/core").WritableSignal<IRenderVirtualListItem | undefined>;
6
+ set item(v: IRenderVirtualListItem | undefined);
7
+ itemRenderer: import("@angular/core").WritableSignal<TemplateRef<any> | undefined>;
8
+ set renderer(v: TemplateRef<any> | undefined);
9
+ static ɵfac: i0.ɵɵFactoryDeclaration<NgVirtualListItemComponent, never>;
10
+ static ɵcmp: i0.ɵɵComponentDeclaration<NgVirtualListItemComponent, "ng-virtual-list-item", never, {}, {}, never, never, true, never>;
11
+ }
@@ -0,0 +1 @@
1
+ export declare const DEFAULT_ITEM_HEIGHT = 24;
@@ -0,0 +1,3 @@
1
+ import { IVirtualListItem } from "./item.model";
2
+ export interface IVirtualListCollection extends Array<IVirtualListItem> {
3
+ }
@@ -0,0 +1,5 @@
1
+ import { IVirtualListItem } from './item.model';
2
+ import { IVirtualListCollection } from './collection.model';
3
+ import { IRenderVirtualListItem } from './render-item.model';
4
+ import { IRenderVirtualListCollection } from './render-collection.model';
5
+ export type { IVirtualListItem, IVirtualListCollection, IRenderVirtualListItem, IRenderVirtualListCollection, };
@@ -0,0 +1,5 @@
1
+ import { Id } from "../types/id";
2
+ export interface IVirtualListItem {
3
+ id: Id;
4
+ [x: string]: any;
5
+ }
@@ -0,0 +1,3 @@
1
+ import { IRenderVirtualListItem } from "./render-item.model";
2
+ export interface IRenderVirtualListCollection extends Array<IRenderVirtualListItem> {
3
+ }
@@ -0,0 +1,8 @@
1
+ import { IRect } from "../types";
2
+ import { Id } from "../types/id";
3
+ import { IVirtualListItem } from "./item.model";
4
+ export interface IRenderVirtualListItem {
5
+ id: Id;
6
+ measures: IRect;
7
+ data: Omit<IVirtualListItem, 'id'>;
8
+ }
@@ -0,0 +1,27 @@
1
+ import { AfterViewInit, ComponentRef, ElementRef, OnDestroy, TemplateRef, ViewContainerRef } from '@angular/core';
2
+ import { NgVirtualListItemComponent } from './components/ng-virtual-list-item.component';
3
+ import { IRenderVirtualListCollection, IVirtualListCollection } from './models';
4
+ import * as i0 from "@angular/core";
5
+ export declare class NgVirtualListComponent implements AfterViewInit, OnDestroy {
6
+ protected listContainerRef: ViewContainerRef | undefined;
7
+ protected container: import("@angular/core").Signal<ElementRef<HTMLDivElement> | undefined>;
8
+ protected list: import("@angular/core").Signal<ElementRef<HTMLUListElement> | undefined>;
9
+ items: import("@angular/core").InputSignal<IVirtualListCollection>;
10
+ itemRenderer: import("@angular/core").InputSignal<TemplateRef<any>>;
11
+ itemHeight: import("@angular/core").InputSignal<number>;
12
+ protected _displayItems: import("@angular/core").WritableSignal<IRenderVirtualListCollection | null>;
13
+ protected _displayComponents: Array<ComponentRef<NgVirtualListItemComponent>>;
14
+ protected _bounds: import("@angular/core").WritableSignal<DOMRect | null>;
15
+ protected _scrollSize: import("@angular/core").WritableSignal<number>;
16
+ private _resizeObserver;
17
+ private _onResizeHandler;
18
+ private _onScrollHandler;
19
+ private _sizeCacheMap;
20
+ constructor();
21
+ private createdisplayComponentsIfNeed;
22
+ protected refresh(displayItems: IRenderVirtualListCollection | null): void;
23
+ ngAfterViewInit(): void;
24
+ ngOnDestroy(): void;
25
+ static ɵfac: i0.ɵɵFactoryDeclaration<NgVirtualListComponent, never>;
26
+ static ɵcmp: i0.ɵɵComponentDeclaration<NgVirtualListComponent, "ng-virtual-list", never, { "items": { "alias": "items"; "required": true; "isSignal": true; }; "itemRenderer": { "alias": "itemRenderer"; "required": true; "isSignal": true; }; "itemHeight": { "alias": "itemHeight"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
27
+ }
@@ -0,0 +1,6 @@
1
+ import * as i0 from "@angular/core";
2
+ export declare class NgVirtualListService {
3
+ constructor();
4
+ static ɵfac: i0.ɵɵFactoryDeclaration<NgVirtualListService, never>;
5
+ static ɵprov: i0.ɵɵInjectableDeclaration<NgVirtualListService>;
6
+ }
@@ -0,0 +1 @@
1
+ export type Id = string | number;
@@ -0,0 +1,4 @@
1
+ import { Id } from './id';
2
+ import { ISize } from './size';
3
+ import { IRect } from './rect';
4
+ export type { Id, ISize, IRect, };
@@ -0,0 +1,5 @@
1
+ import { ISize } from "./size";
2
+ export interface IRect extends ISize {
3
+ x: number;
4
+ y: number;
5
+ }
@@ -0,0 +1,4 @@
1
+ export interface ISize {
2
+ width: number;
3
+ height: number;
4
+ }
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "ng-virtual-list",
3
+ "version": "0.0.1",
4
+ "author": {
5
+ "name": "Evgenii Grebennikov",
6
+ "email": "djonnyx@gmail.com"
7
+ },
8
+ "peerDependencies": {
9
+ "@angular/common": "^19.2.0",
10
+ "@angular/core": "^19.2.0"
11
+ },
12
+ "dependencies": {
13
+ "tslib": "^2.3.0"
14
+ },
15
+ "sideEffects": false,
16
+ "module": "fesm2022/ng-virtual-list.mjs",
17
+ "typings": "index.d.ts",
18
+ "exports": {
19
+ "./package.json": {
20
+ "default": "./package.json"
21
+ },
22
+ ".": {
23
+ "types": "./index.d.ts",
24
+ "default": "./fesm2022/ng-virtual-list.mjs"
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,2 @@
1
+ export * from './lib/ng-virtual-list.service';
2
+ export * from './lib/ng-virtual-list.component';