angular-layout-virtual 0.0.7 → 0.2.0

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.
@@ -4,14 +4,18 @@
4
4
  * @author Alexandr Kalabin
5
5
  */
6
6
  import { TemplateRef } from '@angular/core';
7
- import type { AfterViewInit } from '@angular/core';
8
- import { type ListItemProps } from './AngularRenderer';
7
+ import type { AfterViewInit, ElementRef } from '@angular/core';
8
+ import type { AngularClassAttribute, ListItemProps } from './types';
9
9
  export type VirtualizedListItemContext<T> = ListItemProps<T> & {
10
10
  $implicit: T;
11
11
  };
12
12
  export default class VirtualizedListAngular<T> implements AfterViewInit {
13
13
  data: T[];
14
14
  overscanHeight: number;
15
+ scrollerRef?: ElementRef<HTMLElement>;
16
+ scrollerClass?: AngularClassAttribute;
17
+ viewportClass?: AngularClassAttribute;
18
+ contentLayerClass?: AngularClassAttribute;
15
19
  renderItemTemplate: TemplateRef<VirtualizedListItemContext<T>>;
16
20
  private containerRef;
17
21
  private scrollHeightFillerRef;
@@ -4,19 +4,8 @@
4
4
  * @author Alexandr Kalabin
5
5
  */
6
6
  import { BaseRenderer } from 'layout-virtual/core';
7
- import type { IRangeRenderer, ScrollDirection, VirtualScrollStructure } from 'layout-virtual/types';
8
- export interface ListItemProps<T = unknown> {
9
- data: T;
10
- index: number;
11
- }
12
- type AngularRendererOptions<T> = {
13
- itemsSetter: (items: ListItemProps<T>[]) => void;
14
- itemsFlusher: () => void;
15
- } & VirtualScrollStructure;
16
- export type AngularListItem<T = unknown> = {
17
- data: T;
18
- render?: unknown;
19
- };
7
+ import type { IRangeRenderer, ScrollDirection } from 'layout-virtual/types';
8
+ import type { AngularRendererOptions } from './types';
20
9
  export default class AngularRenderer<DataType = unknown> extends BaseRenderer implements IRangeRenderer<DataType> {
21
10
  private _store;
22
11
  private _itemsSetter;
@@ -35,4 +24,3 @@ export default class AngularRenderer<DataType = unknown> extends BaseRenderer im
35
24
  commit(renderedRefs: Map<number, Element>): void;
36
25
  get dataSize(): number;
37
26
  }
38
- export {};
package/dist/index.d.ts CHANGED
@@ -4,3 +4,4 @@
4
4
  * @author Alexandr Kalabin
5
5
  */
6
6
  export { default } from './AngularLayoutVirtual';
7
+ export type { ListItemProps, VirtualizedListAngularProps, VirtualizedListAngularClasses } from './types';
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{CommonModule as t}from"@angular/common";import{Input as e,ContentChild as i,TemplateRef as r,ViewChild as n,Component as s,inject as o,ChangeDetectorRef as a}from"@angular/core";import{BaseRenderer as c,DynamicListLayout as l,LayoutVirtual as h}from"layout-virtual/core";class m extends c{t=[];i;o;l=[];constructor(t){super(t),this.i=t.itemsSetter,this.o=t.itemsFlusher}renderRange(t,e,i){const r=this.t,n=this.l,s=[];for(let o=t;o<=e;o++){const t=r[o];t&&s.push({data:t,index:o})}this.l="down"===i?n.concat(s):"up"===i?s.concat(n):this.l}removeRange(t,e,i){const r=super.removeRange(t,e),n=r.itemsToRemove.length;return n&&(this.l="down"===i?this.l.slice(n):"up"===i?this.l.slice(0,-n):this.l),r}clear(){super.clear(),this.l=[],this.i(this.l)}setData(t){this.t=t}setRenderItem(){}flush(){return this.i(this.l),this.o(),Promise.resolve()}commit(t){for(const[e,i]of t.entries())this.registerElement(e,i);t.clear()}get dataSize(){return this.t.length}}var d=Object.defineProperty,p=Object.getOwnPropertyDescriptor,v=(t,e,i,r)=>{for(var n,s=r>1?void 0:r?p(e,i):e,o=t.length-1;o>=0;o--)(n=t[o])&&(s=(r?n(e,i,s):n(s))||s);return r&&s&&d(e,i,s),s};let f=class{data=[];overscanHeight=200;renderItemTemplate;containerRef;scrollHeightFillerRef;viewportContainerRef;scrollCanvasRef;topSpacerRef;contentLayerRef;bottomSpacerRef;visibleItems=[];renderer;changeDetectorRef=o(a);ngAfterViewInit(){this.renderer=new m({container:this.containerRef.nativeElement,scrollHeightFiller:this.scrollHeightFillerRef.nativeElement,viewportContainer:this.viewportContainerRef.nativeElement,scrollCanvas:this.scrollCanvasRef.nativeElement,topSpacer:this.topSpacerRef.nativeElement,contentLayer:this.contentLayerRef.nativeElement,bottomSpacer:this.bottomSpacerRef.nativeElement,itemsSetter:this.setVisibleItems,itemsFlusher:this.flushVisibleItems});const t=new l({overscanHeight:this.overscanHeight,renderer:this.renderer});new h({layout:t}).setData(this.data)}trackByIndex(t,e){return e.index}getItemContext(t){return{$implicit:t.data,data:t.data,index:t.index}}setVisibleItems=t=>{this.visibleItems=t};flushVisibleItems=()=>{this.changeDetectorRef.detectChanges(),this.commit()};commit(){const t=/* @__PURE__ */new Map;Array.from(this.contentLayerRef.nativeElement.children).forEach((e,i)=>{const r=this.visibleItems[i];r&&t.set(r.index,e)}),this.renderer?.commit(t)}};v([e({required:!0})],f.prototype,"data",2),v([e()],f.prototype,"overscanHeight",2),v([i("renderItem",{read:r})],f.prototype,"renderItemTemplate",2),v([n("container",{static:!0})],f.prototype,"containerRef",2),v([n("scrollHeightFiller",{static:!0})],f.prototype,"scrollHeightFillerRef",2),v([n("viewportContainer",{static:!0})],f.prototype,"viewportContainerRef",2),v([n("scrollCanvas",{static:!0})],f.prototype,"scrollCanvasRef",2),v([n("topSpacer",{static:!0})],f.prototype,"topSpacerRef",2),v([n("contentLayer",{static:!0})],f.prototype,"contentLayerRef",2),v([n("bottomSpacer",{static:!0})],f.prototype,"bottomSpacerRef",2),f=v([s({selector:"angular-layout-virtual",standalone:!0,imports:[t],host:{style:"display: contents;"},template:'\n <div #container>\n <div #scrollHeightFiller></div>\n <div #viewportContainer>\n <div #scrollCanvas>\n <div #topSpacer></div>\n <div #contentLayer>\n <ng-container\n *ngFor="let item of visibleItems; trackBy: trackByIndex"\n >\n <ng-container\n *ngTemplateOutlet="\n renderItemTemplate;\n context: getItemContext(item)\n "\n ></ng-container>\n </ng-container>\n </div>\n <div #bottomSpacer></div>\n </div>\n </div>\n </div>\n '})],f);export{f as default};
1
+ import{CommonModule as t}from"@angular/common";import{Input as e,ContentChild as r,TemplateRef as s,ViewChild as i,Component as n,inject as a,ChangeDetectorRef as o}from"@angular/core";import{BaseRenderer as l,DynamicListLayout as c,LayoutVirtual as h}from"layout-virtual/core";class m extends l{t=[];i;o;l=[];constructor(t){super(t),this.i=t.itemsSetter,this.o=t.itemsFlusher}renderRange(t,e,r){const s=this.t,i=this.l,n=[];for(let a=t;a<=e;a++){const t=s[a];t&&n.push({data:t,index:a})}this.l="down"===r?i.concat(n):"up"===r?n.concat(i):this.l}removeRange(t,e,r){const s=super.removeRange(t,e),i=s.itemsToRemove.length;return i&&(this.l="down"===r?this.l.slice(i):"up"===r?this.l.slice(0,-i):this.l),s}clear(){super.clear(),this.l=[],this.i(this.l)}setData(t){this.t=t}setRenderItem(){}flush(){return this.i(this.l),this.o(),Promise.resolve()}commit(t){for(const[e,r]of t.entries())this.registerElement(e,r);t.clear()}get dataSize(){return this.t.length}}var p=Object.defineProperty,d=Object.getOwnPropertyDescriptor,v=(t,e,r,s)=>{for(var i,n=s>1?void 0:s?d(e,r):e,a=t.length-1;a>=0;a--)(i=t[a])&&(n=(s?i(e,r,n):i(n))||n);return s&&n&&p(e,r,n),n};let f=class{data=[];overscanHeight=200;scrollerRef;scrollerClass;viewportClass;contentLayerClass;renderItemTemplate;containerRef;scrollHeightFillerRef;viewportContainerRef;scrollCanvasRef;topSpacerRef;contentLayerRef;bottomSpacerRef;visibleItems=[];renderer;changeDetectorRef=a(o);ngAfterViewInit(){this.renderer=new m({container:this.scrollerRef?.nativeElement||this.containerRef.nativeElement,scrollHeightFiller:this.scrollHeightFillerRef.nativeElement,viewportContainer:this.viewportContainerRef.nativeElement,scrollCanvas:this.scrollCanvasRef.nativeElement,topSpacer:this.topSpacerRef.nativeElement,contentLayer:this.contentLayerRef.nativeElement,bottomSpacer:this.bottomSpacerRef.nativeElement,itemsSetter:this.setVisibleItems,itemsFlusher:this.flushVisibleItems});const t=new c({overscanHeight:this.overscanHeight,renderer:this.renderer});new h({layout:t}).setData(this.data)}trackByIndex(t,e){return e.index}getItemContext(t){return{$implicit:t.data,data:t.data,index:t.index}}setVisibleItems=t=>{this.visibleItems=t};flushVisibleItems=()=>{this.changeDetectorRef.detectChanges(),this.commit()};commit(){const t=/* @__PURE__ */new Map;Array.from(this.contentLayerRef.nativeElement.children).forEach((e,r)=>{const s=this.visibleItems[r];s&&t.set(s.index,e)}),this.renderer?.commit(t)}};v([e({required:!0})],f.prototype,"data",2),v([e()],f.prototype,"overscanHeight",2),v([e()],f.prototype,"scrollerRef",2),v([e()],f.prototype,"scrollerClass",2),v([e()],f.prototype,"viewportClass",2),v([e()],f.prototype,"contentLayerClass",2),v([r("renderItem",{read:s})],f.prototype,"renderItemTemplate",2),v([i("container",{static:!0})],f.prototype,"containerRef",2),v([i("scrollHeightFiller",{static:!0})],f.prototype,"scrollHeightFillerRef",2),v([i("viewportContainer",{static:!0})],f.prototype,"viewportContainerRef",2),v([i("scrollCanvas",{static:!0})],f.prototype,"scrollCanvasRef",2),v([i("topSpacer",{static:!0})],f.prototype,"topSpacerRef",2),v([i("contentLayer",{static:!0})],f.prototype,"contentLayerRef",2),v([i("bottomSpacer",{static:!0})],f.prototype,"bottomSpacerRef",2),f=v([n({selector:"angular-layout-virtual",standalone:!0,imports:[t],template:'\n <div #container [class]="scrollerClass">\n <div #scrollHeightFiller></div>\n <div #viewportContainer [class]="viewportClass">\n <div #scrollCanvas>\n <div #topSpacer></div>\n <div #contentLayer [class]="contentLayerClass">\n <ng-container\n *ngFor="let item of visibleItems; trackBy: trackByIndex"\n >\n <ng-container\n *ngTemplateOutlet="\n renderItemTemplate;\n context: getItemContext(item)\n "\n ></ng-container>\n </ng-container>\n </div>\n <div #bottomSpacer></div>\n </div>\n </div>\n </div>\n '})],f);export{f as default};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/AngularRenderer.ts","../src/AngularLayoutVirtual.ts"],"sourcesContent":["/**\n * @fileoverview AngularRenderer.\n * @license MIT\n * @author Alexandr Kalabin\n */\n\nimport { BaseRenderer } from 'layout-virtual/core';\nimport type {\n IRangeRenderer,\n ScrollDirection,\n VirtualScrollStructure,\n} from 'layout-virtual/types';\n\nexport interface ListItemProps<T = unknown> {\n data: T;\n index: number;\n}\n\ntype AngularRendererOptions<T> = {\n itemsSetter: (items: ListItemProps<T>[]) => void;\n itemsFlusher: () => void;\n} & VirtualScrollStructure;\n\nexport type AngularListItem<T = unknown> = {\n data: T;\n render?: unknown;\n};\n\nexport default class AngularRenderer<DataType = unknown> extends BaseRenderer implements IRangeRenderer<DataType> {\n private _store: DataType[] = [];\n private _itemsSetter: (items: ListItemProps<DataType>[]) => void;\n private _itemsFlusher: () => void;\n private _listItems: ListItemProps<DataType>[] = [];\n\n constructor(opts: AngularRendererOptions<DataType>) {\n super(opts);\n this._itemsSetter = opts.itemsSetter;\n this._itemsFlusher = opts.itemsFlusher;\n }\n\n renderRange(startIndex: number, endIndex: number, direction: ScrollDirection) {\n const store = this._store;\n const listItems = this._listItems;\n const itemsToAdd: ListItemProps<DataType>[] = [];\n\n for (let index = startIndex; index <= endIndex; index++) {\n const data = store[index];\n\n if (data) {\n itemsToAdd.push({ data, index });\n }\n }\n\n this._listItems =\n direction === 'down'\n ? listItems.concat(itemsToAdd)\n : direction === 'up'\n ? itemsToAdd.concat(listItems)\n : this._listItems;\n }\n\n removeRange(startIndex: number, endIndex: number, direction?: ScrollDirection) {\n const removal = super.removeRange(startIndex, endIndex);\n const removedItemsCount = removal.itemsToRemove.length;\n\n if (removedItemsCount) {\n this._listItems =\n direction === 'down'\n ? this._listItems.slice(removedItemsCount)\n : direction === 'up'\n ? this._listItems.slice(0, -removedItemsCount)\n : this._listItems;\n }\n\n return removal;\n }\n\n clear() {\n super.clear();\n this._listItems = [];\n this._itemsSetter(this._listItems);\n }\n\n setData(store: DataType[]) {\n this._store = store;\n }\n\n setRenderItem() {\n /* not needed for Angular renderer */\n }\n\n flush() {\n this._itemsSetter(this._listItems);\n this._itemsFlusher();\n return Promise.resolve();\n }\n\n commit(renderedRefs: Map<number, Element>) {\n for (const [idx, element] of renderedRefs.entries()) {\n this.registerElement(idx, element);\n }\n\n renderedRefs.clear();\n }\n\n get dataSize() {\n return this._store.length;\n }\n}\n","/**\n * @fileoverview VirtualizedList Angular component.\n * @license MIT\n * @author Alexandr Kalabin\n */\n\nimport { CommonModule } from '@angular/common';\nimport {\n ChangeDetectorRef,\n Component,\n ContentChild,\n Input,\n TemplateRef,\n ViewChild,\n inject,\n} from '@angular/core';\nimport type { AfterViewInit, ElementRef } from '@angular/core';\nimport type { IRangeRenderer } from 'layout-virtual/types';\nimport { LayoutVirtual, DynamicListLayout } from 'layout-virtual/core';\nimport AngularRenderer, { type ListItemProps } from './AngularRenderer';\n\nexport type VirtualizedListItemContext<T> = ListItemProps<T> & {\n $implicit: T;\n};\n\n@Component({\n selector: 'angular-layout-virtual',\n standalone: true,\n imports: [CommonModule],\n host: {\n style: 'display: contents;',\n },\n template: `\n <div #container>\n <div #scrollHeightFiller></div>\n <div #viewportContainer>\n <div #scrollCanvas>\n <div #topSpacer></div>\n <div #contentLayer>\n <ng-container\n *ngFor=\"let item of visibleItems; trackBy: trackByIndex\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n renderItemTemplate;\n context: getItemContext(item)\n \"\n ></ng-container>\n </ng-container>\n </div>\n <div #bottomSpacer></div>\n </div>\n </div>\n </div>\n `,\n})\nexport default class VirtualizedListAngular<T> implements AfterViewInit {\n @Input({ required: true }) data: T[] = [];\n @Input() overscanHeight = 200;\n\n @ContentChild('renderItem', { read: TemplateRef })\n renderItemTemplate!: TemplateRef<VirtualizedListItemContext<T>>;\n\n @ViewChild('container', { static: true })\n private containerRef!: ElementRef<HTMLDivElement>;\n @ViewChild('scrollHeightFiller', { static: true })\n private scrollHeightFillerRef!: ElementRef<HTMLDivElement>;\n @ViewChild('viewportContainer', { static: true })\n private viewportContainerRef!: ElementRef<HTMLDivElement>;\n @ViewChild('scrollCanvas', { static: true })\n private scrollCanvasRef!: ElementRef<HTMLDivElement>;\n @ViewChild('topSpacer', { static: true })\n private topSpacerRef!: ElementRef<HTMLDivElement>;\n @ViewChild('contentLayer', { static: true })\n private contentLayerRef!: ElementRef<HTMLDivElement>;\n @ViewChild('bottomSpacer', { static: true })\n private bottomSpacerRef!: ElementRef<HTMLDivElement>;\n\n visibleItems: ListItemProps<T>[] = [];\n private renderer: AngularRenderer<T> | undefined;\n private readonly changeDetectorRef = inject(ChangeDetectorRef);\n\n ngAfterViewInit() {\n this.renderer = new AngularRenderer<T>({\n container: this.containerRef.nativeElement,\n scrollHeightFiller: this.scrollHeightFillerRef.nativeElement,\n viewportContainer: this.viewportContainerRef.nativeElement,\n scrollCanvas: this.scrollCanvasRef.nativeElement,\n topSpacer: this.topSpacerRef.nativeElement,\n contentLayer: this.contentLayerRef.nativeElement,\n bottomSpacer: this.bottomSpacerRef.nativeElement,\n itemsSetter: this.setVisibleItems,\n itemsFlusher: this.flushVisibleItems,\n });\n\n const layout = new DynamicListLayout({\n overscanHeight: this.overscanHeight,\n renderer: this.renderer as unknown as IRangeRenderer,\n });\n\n const list = new LayoutVirtual({\n layout,\n } as unknown as ConstructorParameters<typeof LayoutVirtual>[0]);\n \n list.setData(this.data);\n }\n\n trackByIndex(_position: number, item: ListItemProps<T>) {\n return item.index;\n }\n\n getItemContext(item: ListItemProps<T>): VirtualizedListItemContext<T> {\n return {\n $implicit: item.data,\n data: item.data,\n index: item.index,\n };\n }\n\n private setVisibleItems = (items: ListItemProps<T>[]) => {\n this.visibleItems = items;\n };\n\n private flushVisibleItems = () => {\n this.changeDetectorRef.detectChanges();\n this.commit();\n };\n\n private commit() {\n const renderedRefs = new Map<number, Element>();\n const itemElements = Array.from(\n this.contentLayerRef.nativeElement.children,\n );\n\n itemElements.forEach((element, position) => {\n const item = this.visibleItems[position];\n\n if (item) {\n renderedRefs.set(item.index, element);\n }\n });\n\n this.renderer?.commit(renderedRefs);\n }\n}\n"],"names":["AngularRenderer","BaseRenderer","_store","_itemsSetter","_itemsFlusher","_listItems","constructor","opts","super","this","itemsSetter","itemsFlusher","renderRange","startIndex","endIndex","direction","store","listItems","itemsToAdd","index","data","push","concat","removeRange","removal","removedItemsCount","itemsToRemove","length","slice","clear","setData","setRenderItem","flush","Promise","resolve","commit","renderedRefs","idx","element","entries","registerElement","dataSize","VirtualizedListAngular","overscanHeight","renderItemTemplate","containerRef","scrollHeightFillerRef","viewportContainerRef","scrollCanvasRef","topSpacerRef","contentLayerRef","bottomSpacerRef","visibleItems","renderer","changeDetectorRef","inject","ChangeDetectorRef","ngAfterViewInit","container","nativeElement","scrollHeightFiller","viewportContainer","scrollCanvas","topSpacer","contentLayer","bottomSpacer","setVisibleItems","flushVisibleItems","layout","DynamicListLayout","LayoutVirtual","trackByIndex","_position","item","getItemContext","$implicit","items","detectChanges","Map","Array","from","children","forEach","position","set","__decorateClass","Input","required","prototype","ContentChild","read","TemplateRef","ViewChild","static","Component","selector","standalone","imports","CommonModule","host","style","template"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/AngularRenderer.ts","../src/AngularLayoutVirtual.ts"],"sourcesContent":["/**\n * @fileoverview AngularRenderer.\n * @license MIT\n * @author Alexandr Kalabin\n */\n\nimport { BaseRenderer } from 'layout-virtual/core';\nimport type { IRangeRenderer, ScrollDirection } from 'layout-virtual/types';\nimport type { ListItemProps, AngularRendererOptions } from './types';\n\nexport default class AngularRenderer<DataType = unknown> extends BaseRenderer implements IRangeRenderer<DataType> {\n private _store: DataType[] = [];\n private _itemsSetter: (items: ListItemProps<DataType>[]) => void;\n private _itemsFlusher: () => void;\n private _listItems: ListItemProps<DataType>[] = [];\n\n constructor(opts: AngularRendererOptions<DataType>) {\n super(opts);\n this._itemsSetter = opts.itemsSetter;\n this._itemsFlusher = opts.itemsFlusher;\n }\n\n renderRange(startIndex: number, endIndex: number, direction: ScrollDirection) {\n const store = this._store;\n const listItems = this._listItems;\n const itemsToAdd: ListItemProps<DataType>[] = [];\n\n for (let index = startIndex; index <= endIndex; index++) {\n const data = store[index];\n\n if (data) {\n itemsToAdd.push({ data, index });\n }\n }\n\n this._listItems =\n direction === 'down'\n ? listItems.concat(itemsToAdd)\n : direction === 'up'\n ? itemsToAdd.concat(listItems)\n : this._listItems;\n }\n\n removeRange(startIndex: number, endIndex: number, direction?: ScrollDirection) {\n const removal = super.removeRange(startIndex, endIndex);\n const removedItemsCount = removal.itemsToRemove.length;\n\n if (removedItemsCount) {\n this._listItems =\n direction === 'down'\n ? this._listItems.slice(removedItemsCount)\n : direction === 'up'\n ? this._listItems.slice(0, -removedItemsCount)\n : this._listItems;\n }\n\n return removal;\n }\n\n clear() {\n super.clear();\n this._listItems = [];\n this._itemsSetter(this._listItems);\n }\n\n setData(store: DataType[]) {\n this._store = store;\n }\n\n setRenderItem() {\n /* not needed for Angular renderer */\n }\n\n flush() {\n this._itemsSetter(this._listItems);\n this._itemsFlusher();\n return Promise.resolve();\n }\n\n commit(renderedRefs: Map<number, Element>) {\n for (const [idx, element] of renderedRefs.entries()) {\n this.registerElement(idx, element);\n }\n\n renderedRefs.clear();\n }\n\n get dataSize() {\n return this._store.length;\n }\n}\n","/**\n * @fileoverview VirtualizedList Angular component.\n * @license MIT\n * @author Alexandr Kalabin\n */\n\nimport { CommonModule } from '@angular/common';\nimport {\n ChangeDetectorRef,\n Component,\n ContentChild,\n Input,\n TemplateRef,\n ViewChild,\n inject,\n} from '@angular/core';\nimport type { AfterViewInit, ElementRef } from '@angular/core';\nimport type { IRangeRenderer } from 'layout-virtual/types';\nimport { LayoutVirtual, DynamicListLayout } from 'layout-virtual/core';\nimport AngularRenderer from './AngularRenderer';\nimport type { AngularClassAttribute, ListItemProps } from './types';\n\nexport type VirtualizedListItemContext<T> = ListItemProps<T> & {\n $implicit: T;\n};\n\n@Component({\n selector: 'angular-layout-virtual',\n standalone: true,\n imports: [CommonModule],\n template: `\n <div #container [class]=\"scrollerClass\">\n <div #scrollHeightFiller></div>\n <div #viewportContainer [class]=\"viewportClass\">\n <div #scrollCanvas>\n <div #topSpacer></div>\n <div #contentLayer [class]=\"contentLayerClass\">\n <ng-container\n *ngFor=\"let item of visibleItems; trackBy: trackByIndex\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n renderItemTemplate;\n context: getItemContext(item)\n \"\n ></ng-container>\n </ng-container>\n </div>\n <div #bottomSpacer></div>\n </div>\n </div>\n </div>\n `,\n})\nexport default class VirtualizedListAngular<T> implements AfterViewInit {\n @Input({ required: true }) data: T[] = [];\n @Input() overscanHeight = 200;\n @Input() scrollerRef?: ElementRef<HTMLElement>;\n @Input() scrollerClass?: AngularClassAttribute;\n @Input() viewportClass?: AngularClassAttribute;\n @Input() contentLayerClass?: AngularClassAttribute;\n\n @ContentChild('renderItem', { read: TemplateRef })\n renderItemTemplate!: TemplateRef<VirtualizedListItemContext<T>>;\n\n @ViewChild('container', { static: true })\n private containerRef!: ElementRef<HTMLDivElement>;\n @ViewChild('scrollHeightFiller', { static: true })\n private scrollHeightFillerRef!: ElementRef<HTMLDivElement>;\n @ViewChild('viewportContainer', { static: true })\n private viewportContainerRef!: ElementRef<HTMLDivElement>;\n @ViewChild('scrollCanvas', { static: true })\n private scrollCanvasRef!: ElementRef<HTMLDivElement>;\n @ViewChild('topSpacer', { static: true })\n private topSpacerRef!: ElementRef<HTMLDivElement>;\n @ViewChild('contentLayer', { static: true })\n private contentLayerRef!: ElementRef<HTMLDivElement>;\n @ViewChild('bottomSpacer', { static: true })\n private bottomSpacerRef!: ElementRef<HTMLDivElement>;\n\n visibleItems: ListItemProps<T>[] = [];\n private renderer: AngularRenderer<T> | undefined;\n private readonly changeDetectorRef = inject(ChangeDetectorRef);\n\n ngAfterViewInit() {\n this.renderer = new AngularRenderer<T>({\n container: this.scrollerRef?.nativeElement || this.containerRef.nativeElement,\n scrollHeightFiller: this.scrollHeightFillerRef.nativeElement,\n viewportContainer: this.viewportContainerRef.nativeElement,\n scrollCanvas: this.scrollCanvasRef.nativeElement,\n topSpacer: this.topSpacerRef.nativeElement,\n contentLayer: this.contentLayerRef.nativeElement,\n bottomSpacer: this.bottomSpacerRef.nativeElement,\n itemsSetter: this.setVisibleItems,\n itemsFlusher: this.flushVisibleItems,\n });\n\n const layout = new DynamicListLayout({\n overscanHeight: this.overscanHeight,\n renderer: this.renderer as unknown as IRangeRenderer,\n });\n\n const list = new LayoutVirtual({\n layout,\n } as unknown as ConstructorParameters<typeof LayoutVirtual>[0]);\n \n list.setData(this.data);\n }\n\n trackByIndex(_position: number, item: ListItemProps<T>) {\n return item.index;\n }\n\n getItemContext(item: ListItemProps<T>): VirtualizedListItemContext<T> {\n return {\n $implicit: item.data,\n data: item.data,\n index: item.index,\n };\n }\n\n private setVisibleItems = (items: ListItemProps<T>[]) => {\n this.visibleItems = items;\n };\n\n private flushVisibleItems = () => {\n this.changeDetectorRef.detectChanges();\n this.commit();\n };\n\n private commit() {\n const renderedRefs = new Map<number, Element>();\n const itemElements = Array.from(\n this.contentLayerRef.nativeElement.children,\n );\n\n itemElements.forEach((element, position) => {\n const item = this.visibleItems[position];\n\n if (item) {\n renderedRefs.set(item.index, element);\n }\n });\n\n this.renderer?.commit(renderedRefs);\n }\n}\n"],"names":["AngularRenderer","BaseRenderer","_store","_itemsSetter","_itemsFlusher","_listItems","constructor","opts","super","this","itemsSetter","itemsFlusher","renderRange","startIndex","endIndex","direction","store","listItems","itemsToAdd","index","data","push","concat","removeRange","removal","removedItemsCount","itemsToRemove","length","slice","clear","setData","setRenderItem","flush","Promise","resolve","commit","renderedRefs","idx","element","entries","registerElement","dataSize","VirtualizedListAngular","overscanHeight","scrollerRef","scrollerClass","viewportClass","contentLayerClass","renderItemTemplate","containerRef","scrollHeightFillerRef","viewportContainerRef","scrollCanvasRef","topSpacerRef","contentLayerRef","bottomSpacerRef","visibleItems","renderer","changeDetectorRef","inject","ChangeDetectorRef","ngAfterViewInit","container","nativeElement","scrollHeightFiller","viewportContainer","scrollCanvas","topSpacer","contentLayer","bottomSpacer","setVisibleItems","flushVisibleItems","layout","DynamicListLayout","LayoutVirtual","trackByIndex","_position","item","getItemContext","$implicit","items","detectChanges","Map","Array","from","children","forEach","position","set","__decorateClass","Input","required","prototype","ContentChild","read","TemplateRef","ViewChild","static","Component","selector","standalone","imports","CommonModule","template"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @fileoverview Types for VirtualizedList Angular renderer and component.
3
+ * @license MIT
4
+ * @author Alexandr Kalabin
5
+ */
6
+ import type { ElementRef } from '@angular/core';
7
+ import type { VirtualScrollStructure } from 'layout-virtual/types';
8
+ export interface ListItemProps<T = unknown> {
9
+ data: T;
10
+ index: number;
11
+ }
12
+ export type AngularRendererOptions<T> = {
13
+ itemsSetter: (items: ListItemProps<T>[]) => void;
14
+ itemsFlusher: () => void;
15
+ } & VirtualScrollStructure;
16
+ export type AngularClassAttribute = string | string[] | Set<string> | Record<string, boolean>;
17
+ export interface VirtualizedListAngularClasses {
18
+ scrollerClass?: AngularClassAttribute;
19
+ viewportClass?: AngularClassAttribute;
20
+ contentLayerClass?: AngularClassAttribute;
21
+ }
22
+ export interface VirtualizedListAngularProps<T> extends VirtualizedListAngularClasses {
23
+ scrollerRef?: ElementRef<HTMLElement>;
24
+ overscanHeight?: number;
25
+ data: T[];
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "angular-layout-virtual",
3
- "version": "0.0.7",
3
+ "version": "0.2.0",
4
4
  "description": "Angular virtual scrolling component for responsive lists and grids with dynamic item sizes.",
5
5
  "keywords": [
6
6
  "virtual",
@@ -43,7 +43,7 @@
43
43
  "prepublishOnly": "npm run build"
44
44
  },
45
45
  "dependencies": {
46
- "layout-virtual": "^0.1.2"
46
+ "layout-virtual": "^0.3.0"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "@angular/common": "^21.0.0",