Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit dcd98b0

Browse filesBrowse files
committed
feat(template): introduce experimental virtual-scrolling package
1 parent a1b6982 commit dcd98b0
Copy full SHA for dcd98b0

29 files changed

+4034
-1
lines changed

‎libs/template/experimental/virtual-scrolling/README.md

Copy file name to clipboardExpand all lines: libs/template/experimental/virtual-scrolling/README.md
+564Lines changed: 564 additions & 0 deletions
Large diffs are not rendered by default.
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"$schema": "../../../../node_modules/ng-packagr/package.schema.json",
3+
"lib": {
4+
"entryFile": "src/index.ts",
5+
"flatModuleFile": "template-experimental-virtual-scrolling"
6+
}
7+
}
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './lib';
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export {
2+
ListRange,
3+
RxVirtualForViewContext,
4+
RxVirtualScrollStrategy,
5+
RxVirtualViewRepeater,
6+
} from './model';
7+
export * from './scroll-strategies/autosized-virtual-scroll-strategy';
8+
export * from './scroll-strategies/dynamic-size-virtual-scroll-strategy';
9+
export * from './scroll-strategies/fixed-size-virtual-scroll-strategy';
10+
export * from './virtual-for.directive';
11+
export {
12+
RX_VIRTUAL_SCROLL_DEFAULT_OPTIONS,
13+
RX_VIRTUAL_SCROLL_DEFAULT_OPTIONS_FACTORY,
14+
RxVirtualScrollDefaultOptions,
15+
} from './virtual-scroll.config';
16+
export * from './virtual-scroll-viewport.component';
17+
export * from './virtual-scrolling.module';
+179Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import {
2+
ChangeDetectorRef,
3+
Directive,
4+
EmbeddedViewRef,
5+
ErrorHandler,
6+
NgIterable,
7+
NgZone,
8+
Output,
9+
TemplateRef,
10+
TrackByFunction,
11+
ViewContainerRef,
12+
} from '@angular/core';
13+
import { RxStrategies } from '@rx-angular/cdk/render-strategies';
14+
import { RxDefaultListViewContext } from '@rx-angular/cdk/template';
15+
import { Observable, Subject } from 'rxjs';
16+
17+
type CreateViewContext<T, C, U> = (value: T, computedContext: U) => C;
18+
19+
type UpdateViewContext<T, C, U> = (
20+
value: T,
21+
view: EmbeddedViewRef<C>,
22+
computedContext?: U
23+
) => void;
24+
25+
export interface TemplateSettings<T, C, U> {
26+
viewContainerRef: ViewContainerRef;
27+
templateRef: TemplateRef<C>;
28+
createViewContext: CreateViewContext<T, C, U>;
29+
updateViewContext: UpdateViewContext<T, C, U>;
30+
viewCacheSize: number;
31+
}
32+
33+
export interface RenderSettings {
34+
cdRef: ChangeDetectorRef;
35+
parent: boolean;
36+
patchZone?: NgZone;
37+
strategies: RxStrategies<string>;
38+
defaultStrategyName: string;
39+
errorHandler?: ErrorHandler;
40+
}
41+
42+
export const enum ListTemplateChangeType {
43+
insert,
44+
remove,
45+
move,
46+
update,
47+
context,
48+
}
49+
// [value, index, oldIndex?]
50+
export type ListTemplateChangePayload<T> = [T, number?, number?];
51+
export type ListTemplateChange<T = any> = [
52+
ListTemplateChangeType,
53+
ListTemplateChangePayload<T>
54+
];
55+
export type ListTemplateChanges<T = any> = [
56+
ListTemplateChange<T>[], // changes to apply
57+
boolean // notify parent
58+
];
59+
60+
export interface ListRange {
61+
start: number;
62+
end: number;
63+
}
64+
65+
/**
66+
* @Directive RxVirtualScrollStrategy
67+
*
68+
* @description
69+
* Abstract implementation for the actual implementations of the ScrollStrategies
70+
* being consumed by `*rxVirtualFor` and `rx-virtual-scroll-viewport`.
71+
*
72+
* This is one of the core parts for the virtual scrolling implementation. It has
73+
* to determine the `ListRange` being rendered to the DOM as well as managing
74+
* the layouting task for the `*rxVirtualFor` directive.
75+
*
76+
* @docsCategory RxVirtualFor
77+
* @docsPage RxVirtualFor
78+
* @publicApi
79+
*/
80+
@Directive()
81+
export abstract class RxVirtualScrollStrategy<
82+
T,
83+
U extends NgIterable<T> = NgIterable<T>
84+
> {
85+
/** Emits when the index of the first element visible in the viewport changes. */
86+
/** @internal */
87+
abstract scrolledIndex$: Observable<number>;
88+
/** @internal */
89+
abstract renderedRange$: Observable<ListRange>;
90+
/** @internal */
91+
abstract contentSize$: Observable<number>;
92+
93+
/**
94+
* @description
95+
*
96+
* Emits whenever an update to a single view was rendered
97+
*/
98+
@Output() readonly viewRenderCallback = new Subject<{
99+
view: EmbeddedViewRef<RxVirtualForViewContext<T, U>>;
100+
item: T;
101+
index: number;
102+
}>();
103+
104+
/** @internal */
105+
private nodeIndex?: number;
106+
107+
/** @internal */
108+
protected getElement(
109+
view: EmbeddedViewRef<RxVirtualForViewContext<T, U>>
110+
): HTMLElement {
111+
if (this.nodeIndex !== undefined) {
112+
return view.rootNodes[this.nodeIndex];
113+
}
114+
const rootNode = view.rootNodes[0];
115+
this.nodeIndex = rootNode instanceof HTMLElement ? 0 : 1;
116+
return view.rootNodes[this.nodeIndex] as HTMLElement;
117+
}
118+
119+
/**
120+
* Attaches this scroll strategy to a viewport.
121+
* @param viewport The viewport to attach this strategy to.
122+
* @param viewRepeater The viewRepeater attached to the viewport.
123+
*/
124+
abstract attach(
125+
viewport: RxVirtualScrollViewport,
126+
viewRepeater: RxVirtualViewRepeater<any>
127+
): void;
128+
129+
/** Detaches this scroll strategy from the currently attached viewport. */
130+
abstract detach(): void;
131+
132+
/**
133+
* Scroll to the offset for the given index.
134+
* @param index The index of the element to scroll to.
135+
* @param behavior The ScrollBehavior to use when scrolling.
136+
*/
137+
abstract scrollToIndex(index: number, behavior?: ScrollBehavior): void;
138+
}
139+
140+
/** @internal */
141+
@Directive()
142+
export abstract class RxVirtualScrollViewport {
143+
abstract rendered$: Observable<any>;
144+
abstract viewRange: Observable<ListRange>;
145+
abstract elementScrolled$: Observable<void>;
146+
abstract containerRect$: Observable<{ height: number; width: number }>;
147+
abstract getScrollTop(): number;
148+
abstract scrollTo(scrollTo: number, behavior?: ScrollBehavior): void;
149+
}
150+
151+
/** @internal */
152+
@Directive()
153+
export abstract class RxVirtualViewRepeater<
154+
T,
155+
U extends NgIterable<T> = NgIterable<T>
156+
> {
157+
abstract values$: Observable<U | null | undefined>;
158+
abstract rendered$: Observable<any>;
159+
abstract viewsRendered$: Observable<EmbeddedViewRef<any>[]>;
160+
abstract viewRendered$: Observable<{
161+
view: EmbeddedViewRef<RxVirtualForViewContext<T, U>>;
162+
index: number;
163+
item: T;
164+
}>;
165+
abstract renderingStart$: Observable<void>;
166+
_trackBy: TrackByFunction<T> = (i, a) => a;
167+
}
168+
169+
/** @internal */
170+
export class RxVirtualForViewContext<
171+
T,
172+
U extends NgIterable<T> = NgIterable<T>,
173+
C extends { count: number; index: number } = { count: number; index: number },
174+
K = keyof T
175+
> extends RxDefaultListViewContext<T, U, K> {
176+
constructor(item: T, public rxVirtualForOf: U, customProps?: C) {
177+
super(item, customProps);
178+
}
179+
}
+32Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Observable } from 'rxjs';
2+
3+
export function observeElementSize(
4+
element: Element,
5+
config?: {
6+
options?: ResizeObserverOptions;
7+
}
8+
): Observable<DOMRectReadOnly>;
9+
export function observeElementSize<T>(
10+
element: Element,
11+
config?: {
12+
options?: ResizeObserverOptions;
13+
extract: (entries: ResizeObserverEntry[]) => T;
14+
}
15+
): Observable<T>;
16+
export function observeElementSize<T>(
17+
element: Element,
18+
config?: {
19+
options?: ResizeObserverOptions;
20+
extract?: (entries: ResizeObserverEntry[]) => T;
21+
}
22+
): Observable<T | DOMRectReadOnly> {
23+
const extractProp: (entries: ResizeObserverEntry[]) => T | DOMRectReadOnly =
24+
config?.extract ?? ((entries) => entries[0].contentRect);
25+
return new Observable<T | DOMRectReadOnly>((subscriber) => {
26+
const observer = new ResizeObserver((entries) => {
27+
subscriber.next(extractProp(entries));
28+
});
29+
observer.observe(element, config?.options);
30+
return () => observer.disconnect();
31+
});
32+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.