ng-virtual-list 17.0.21 → 17.0.22

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.
Files changed (87) hide show
  1. package/ng-package.json +7 -0
  2. package/package.json +29 -42
  3. package/src/lib/components/ng-virtual-list-item.component.html +9 -0
  4. package/src/lib/components/ng-virtual-list-item.component.scss +17 -0
  5. package/src/lib/components/ng-virtual-list-item.component.spec.ts +23 -0
  6. package/src/lib/components/ng-virtual-list-item.component.ts +111 -0
  7. package/src/lib/const/index.ts +67 -0
  8. package/{lib/enums/direction.d.ts → src/lib/enums/direction.ts} +9 -8
  9. package/{lib/enums/directions.d.ts → src/lib/enums/directions.ts} +16 -16
  10. package/{lib/enums/index.d.ts → src/lib/enums/index.ts} +7 -4
  11. package/{lib/models/collection.model.d.ts → src/lib/models/collection.model.ts} +9 -9
  12. package/{lib/models/index.d.ts → src/lib/models/index.ts} +13 -6
  13. package/{lib/models/item.model.d.ts → src/lib/models/item.model.ts} +15 -14
  14. package/{lib/models/render-collection.model.d.ts → src/lib/models/render-collection.model.ts} +9 -9
  15. package/{lib/models/render-item-config.model.d.ts → src/lib/models/render-item-config.model.ts} +33 -33
  16. package/{lib/models/render-item.model.d.ts → src/lib/models/render-item.model.ts} +29 -28
  17. package/{lib/models/scroll-direction.model.d.ts → src/lib/models/scroll-direction.model.ts} +5 -5
  18. package/{lib/models/scroll-event.model.d.ts → src/lib/models/scroll-event.model.ts} +51 -50
  19. package/{lib/models/sticky-map.model.d.ts → src/lib/models/sticky-map.model.ts} +12 -12
  20. package/src/lib/ng-virtual-list.component.html +5 -0
  21. package/src/lib/ng-virtual-list.component.scss +28 -0
  22. package/src/lib/ng-virtual-list.component.spec.ts +23 -0
  23. package/src/lib/ng-virtual-list.component.ts +543 -0
  24. package/src/lib/ng-virtual-list.module.ts +12 -0
  25. package/{lib/types/id.d.ts → src/lib/types/id.ts} +7 -7
  26. package/{lib/types/index.d.ts → src/lib/types/index.ts} +9 -4
  27. package/{lib/types/rect.d.ts → src/lib/types/rect.ts} +18 -17
  28. package/{lib/types/size.d.ts → src/lib/types/size.ts} +16 -16
  29. package/src/lib/utils/cacheMap.ts +224 -0
  30. package/src/lib/utils/debounce.ts +31 -0
  31. package/src/lib/utils/eventEmitter.ts +119 -0
  32. package/{lib/utils/index.d.ts → src/lib/utils/index.ts} +15 -7
  33. package/src/lib/utils/isDirection.ts +17 -0
  34. package/src/lib/utils/scrollEvent.ts +62 -0
  35. package/src/lib/utils/toggleClassName.ts +14 -0
  36. package/src/lib/utils/trackBox.ts +839 -0
  37. package/src/lib/utils/tracker.ts +126 -0
  38. package/{public-api.d.ts → src/public-api.ts} +8 -4
  39. package/tsconfig.lib.json +16 -0
  40. package/tsconfig.lib.prod.json +11 -0
  41. package/tsconfig.spec.json +15 -0
  42. package/esm2022/lib/components/ng-virtual-list-item.component.mjs +0 -88
  43. package/esm2022/lib/const/index.mjs +0 -35
  44. package/esm2022/lib/enums/direction.mjs +0 -2
  45. package/esm2022/lib/enums/directions.mjs +0 -18
  46. package/esm2022/lib/enums/index.mjs +0 -3
  47. package/esm2022/lib/models/collection.model.mjs +0 -3
  48. package/esm2022/lib/models/index.mjs +0 -2
  49. package/esm2022/lib/models/item.model.mjs +0 -3
  50. package/esm2022/lib/models/render-collection.model.mjs +0 -3
  51. package/esm2022/lib/models/render-item-config.model.mjs +0 -2
  52. package/esm2022/lib/models/render-item.model.mjs +0 -3
  53. package/esm2022/lib/models/scroll-direction.model.mjs +0 -2
  54. package/esm2022/lib/models/scroll-event.model.mjs +0 -2
  55. package/esm2022/lib/models/sticky-map.model.mjs +0 -2
  56. package/esm2022/lib/ng-virtual-list.component.mjs +0 -390
  57. package/esm2022/lib/ng-virtual-list.module.mjs +0 -20
  58. package/esm2022/lib/types/id.mjs +0 -2
  59. package/esm2022/lib/types/index.mjs +0 -2
  60. package/esm2022/lib/types/rect.mjs +0 -2
  61. package/esm2022/lib/types/size.mjs +0 -2
  62. package/esm2022/lib/utils/cacheMap.mjs +0 -168
  63. package/esm2022/lib/utils/debounce.mjs +0 -31
  64. package/esm2022/lib/utils/eventEmitter.mjs +0 -105
  65. package/esm2022/lib/utils/index.mjs +0 -8
  66. package/esm2022/lib/utils/isDirection.mjs +0 -15
  67. package/esm2022/lib/utils/scrollEvent.mjs +0 -42
  68. package/esm2022/lib/utils/toggleClassName.mjs +0 -15
  69. package/esm2022/lib/utils/trackBox.mjs +0 -627
  70. package/esm2022/lib/utils/tracker.mjs +0 -93
  71. package/esm2022/ng-virtual-list.mjs +0 -5
  72. package/esm2022/public-api.mjs +0 -8
  73. package/fesm2022/ng-virtual-list.mjs +0 -1639
  74. package/fesm2022/ng-virtual-list.mjs.map +0 -1
  75. package/index.d.ts +0 -5
  76. package/lib/components/ng-virtual-list-item.component.d.ts +0 -31
  77. package/lib/const/index.d.ts +0 -33
  78. package/lib/ng-virtual-list.component.d.ts +0 -130
  79. package/lib/ng-virtual-list.module.d.ts +0 -9
  80. package/lib/utils/cacheMap.d.ts +0 -60
  81. package/lib/utils/debounce.d.ts +0 -16
  82. package/lib/utils/eventEmitter.d.ts +0 -40
  83. package/lib/utils/isDirection.d.ts +0 -8
  84. package/lib/utils/scrollEvent.d.ts +0 -39
  85. package/lib/utils/toggleClassName.d.ts +0 -7
  86. package/lib/utils/trackBox.d.ts +0 -176
  87. package/lib/utils/tracker.d.ts +0 -44
@@ -0,0 +1,224 @@
1
+ import { ScrollDirection } from "../models";
2
+ import { debounce } from "./debounce";
3
+ import { EventEmitter, TEventHandler } from "./eventEmitter";
4
+
5
+ export class CMap<K = string, V = any> {
6
+ private _dict: { [k: string | number]: V } = {};
7
+
8
+ constructor(dict?: CMap<K, V>) {
9
+ if (dict) {
10
+ this._dict = { ...dict._dict };
11
+ }
12
+ }
13
+
14
+ get(key: K) {
15
+ const k = String(key);
16
+ return this._dict[k];
17
+ }
18
+ set(key: K, value: V) {
19
+ const k = String(key);
20
+ this._dict[k] = value;
21
+ return this;
22
+ }
23
+ has(key: K) {
24
+ return this._dict.hasOwnProperty(String(key));
25
+ }
26
+ delete(key: K) {
27
+ const k = String(key);
28
+ delete this._dict[k];
29
+ }
30
+ clear() {
31
+ this._dict = {};
32
+ }
33
+ }
34
+
35
+ export interface ICacheMap<I = any, B = any> {
36
+ set: (id: I, bounds: B) => CMap<I, B>;
37
+ has: (id: I) => boolean;
38
+ get: (id: I) => B | undefined;
39
+ }
40
+
41
+ export const CACHE_BOX_CHANGE_EVENT_NAME = 'change';
42
+
43
+ type CacheMapEvents = typeof CACHE_BOX_CHANGE_EVENT_NAME;
44
+
45
+ type OnChangeEventListener = (version: number) => void;
46
+
47
+ type CacheMapListeners = OnChangeEventListener;
48
+
49
+ const MAX_SCROLL_DIRECTION_POOL = 50, CLEAR_SCROLL_DIRECTION_TO = 10,
50
+ DIR_BACK = '-1', DIR_NONE = '0', DIR_FORWARD = '1';
51
+
52
+ /**
53
+ * Cache map.
54
+ * Emits a change event on each mutation.
55
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/cacheMap.ts
56
+ * @author Evgenii Grebennikov
57
+ * @email djonnyx@gmail.com
58
+ */
59
+ export class CacheMap<I = string | number, B = any, E extends string = CacheMapEvents, L extends TEventHandler = CacheMapListeners>
60
+ extends EventEmitter<E, L> implements ICacheMap {
61
+ protected _map = new CMap<I, B>();
62
+
63
+ protected _snapshot = new CMap<I, B>();
64
+
65
+ protected _version: number = 0;
66
+
67
+ protected _previousVersion = this._version;
68
+
69
+ protected _lifeCircleTimeout: any;
70
+
71
+ protected _delta: number = 0;
72
+
73
+ get delta() {
74
+ return this._delta;
75
+ }
76
+
77
+ protected _deltaDirection: ScrollDirection = 0;
78
+ set deltaDirection(v: ScrollDirection) {
79
+ this._deltaDirection = v;
80
+
81
+ this._scrollDirection = this.calcScrollDirection(v);
82
+ }
83
+ get deltaDirection() {
84
+ return this._deltaDirection;
85
+ }
86
+
87
+ private _scrollDirectionCache: Array<ScrollDirection> = [];
88
+ private _scrollDirection: ScrollDirection = 0;
89
+ get scrollDirection() {
90
+ return this._scrollDirection;
91
+ }
92
+
93
+ get version() {
94
+ return this._version;
95
+ }
96
+
97
+ private _clearScrollDirectionDebounce = debounce(() => {
98
+ while (this._scrollDirectionCache.length > CLEAR_SCROLL_DIRECTION_TO) {
99
+ this._scrollDirectionCache.shift();
100
+ }
101
+ }, 10);
102
+
103
+ constructor() {
104
+ super();
105
+ this.lifeCircle();
106
+ }
107
+
108
+ protected changesDetected() {
109
+ return this._version !== this._previousVersion;
110
+ }
111
+
112
+ protected stopLifeCircle() {
113
+ clearTimeout(this._lifeCircleTimeout);
114
+ }
115
+
116
+ protected nextTick(cb: () => void) {
117
+ if (this._disposed) {
118
+ return;
119
+ }
120
+
121
+ this._lifeCircleTimeout = setTimeout(() => {
122
+ cb();
123
+ });
124
+ return this._lifeCircleTimeout;
125
+ }
126
+
127
+ protected lifeCircle() {
128
+ this.fireChangeIfNeed();
129
+
130
+ this.lifeCircleDo();
131
+ }
132
+
133
+ protected lifeCircleDo() {
134
+ this._previousVersion = this._version;
135
+
136
+ this.nextTick(() => {
137
+ this.lifeCircle();
138
+ });
139
+ }
140
+
141
+ clearScrollDirectionCache() {
142
+ this._clearScrollDirectionDebounce.execute();
143
+ }
144
+
145
+ private calcScrollDirection(v: ScrollDirection): ScrollDirection {
146
+ while (this._scrollDirectionCache.length >= MAX_SCROLL_DIRECTION_POOL) {
147
+ this._scrollDirectionCache.shift();
148
+ }
149
+ this._scrollDirectionCache.push(v);
150
+ const dict: { [x: string]: number } = { [DIR_BACK]: 0, [DIR_NONE]: 0, [DIR_FORWARD]: 0 };
151
+ for (let i = 0, l = this._scrollDirectionCache.length, li = l - 1; i < l; i++) {
152
+ const dir = String(this._scrollDirectionCache[i]);
153
+ dict[dir] += 1;
154
+ if (i === li) {
155
+ for (let d in dict) {
156
+ if (d === String(v)) {
157
+ continue;
158
+ }
159
+ dict[d] -= 1;
160
+ }
161
+ }
162
+ }
163
+
164
+ if (dict[DIR_BACK] > dict[DIR_NONE] && dict[DIR_BACK] > dict[DIR_FORWARD]) {
165
+ return -1;
166
+ } else if (dict[DIR_FORWARD] > dict[DIR_BACK] && dict[DIR_FORWARD] > dict[DIR_NONE]) {
167
+ return 1;
168
+ }
169
+
170
+ return 0;
171
+ }
172
+
173
+ protected bumpVersion() {
174
+ if (this.changesDetected()) {
175
+ return;
176
+ }
177
+ const v = this._version === Number.MAX_SAFE_INTEGER ? 0 : this._version + 1;
178
+ this._version = v;
179
+ }
180
+
181
+ protected fireChangeIfNeed() {
182
+ if (this.changesDetected()) {
183
+ this.dispatch(CACHE_BOX_CHANGE_EVENT_NAME as E, this.version);
184
+ }
185
+ }
186
+
187
+ set(id: I, bounds: B): CMap<I, B> {
188
+ if (this._map.has(id)) {
189
+ const b: any = this._map.get(id), bb: any = bounds;
190
+ if (b.width === bb.width && b.height === bb.height) {
191
+ return this._map;
192
+ }
193
+ return this._map;
194
+ }
195
+
196
+ const v = this._map.set(id, bounds);
197
+
198
+ this.bumpVersion();
199
+
200
+ return v;
201
+ }
202
+
203
+ has(id: I): boolean {
204
+ return this._map.has(id);
205
+ }
206
+
207
+ get(id: I): B | undefined {
208
+ return this._map.get(id);
209
+ }
210
+
211
+ snapshot() {
212
+ this._snapshot = new CMap(this._map);
213
+ }
214
+
215
+ override dispose() {
216
+ super.dispose();
217
+
218
+ this.stopLifeCircle();
219
+
220
+ this._snapshot.clear();
221
+
222
+ this._map.clear();
223
+ }
224
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Simple debounce function.
3
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/debounce.ts
4
+ * @author Evgenii Grebennikov
5
+ * @email djonnyx@gmail.com
6
+ */
7
+ export const debounce = (cb: (...args: Array<any>) => void, debounceTime: number = 0) => {
8
+ let timeout: any;
9
+ const dispose = () => {
10
+ if (timeout !== undefined) {
11
+ clearTimeout(timeout);
12
+ }
13
+ }
14
+ const execute = (...args: Array<any>) => {
15
+ dispose();
16
+
17
+ timeout = setTimeout(() => {
18
+ cb(...args);
19
+ }, debounceTime);
20
+ };
21
+ return {
22
+ /**
23
+ * Call handling method
24
+ */
25
+ execute,
26
+ /**
27
+ * Method of destroying handlers
28
+ */
29
+ dispose,
30
+ };
31
+ };
@@ -0,0 +1,119 @@
1
+ export type TEventHandler = (...args: Array<any>) => void;
2
+
3
+ /**
4
+ * Simple event emitter
5
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/eventEmitter.ts
6
+ * @author Evgenii Grebennikov
7
+ * @email djonnyx@gmail.com
8
+ */
9
+ export class EventEmitter<E = string, H = TEventHandler> {
10
+ private _listeners: {
11
+ [eventName: string]: Array<TEventHandler>,
12
+ } = {};
13
+
14
+ protected _disposed: boolean = false;
15
+
16
+ constructor() { }
17
+
18
+ /**
19
+ * Emits the event
20
+ */
21
+ dispatch(event: E, ...args: Array<any>): void {
22
+ const ctx = this;
23
+ const listeners = this._listeners[event as string];
24
+ if (Array.isArray(listeners)) {
25
+ for (let i = 0, l = listeners.length; i < l; i++) {
26
+ const listener = listeners[i];
27
+ if (listener) {
28
+ listener.apply(ctx, args);
29
+ }
30
+ }
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Emits the event async
36
+ */
37
+ dispatchAsync(event: E, ...args: Array<any>): void {
38
+ queueMicrotask(() => {
39
+ if (this._disposed) {
40
+ return;
41
+ }
42
+ this.dispatch(event, ...args);
43
+ });
44
+ }
45
+
46
+ /**
47
+ * Returns true if the event listener is already subscribed.
48
+ */
49
+ hasEventListener(eventName: E, handler: H): boolean {
50
+ const event = eventName as string;
51
+ if (this._listeners.hasOwnProperty(event)) {
52
+ const listeners = this._listeners[event];
53
+ const index = listeners.findIndex(v => v === handler);
54
+ if (index > -1) {
55
+ return true;
56
+ }
57
+ }
58
+ return false
59
+ }
60
+
61
+ /**
62
+ * Add event listener
63
+ */
64
+ addEventListener(eventName: E, handler: H): void {
65
+ const event = eventName as string;
66
+ if (!this._listeners.hasOwnProperty(event)) {
67
+ this._listeners[event] = [];
68
+ }
69
+ this._listeners[event].push(handler as TEventHandler);
70
+ }
71
+
72
+ /**
73
+ * Remove event listener
74
+ */
75
+ removeEventListener(eventName: E, handler: H): void {
76
+ const event = eventName as string;
77
+ if (!this._listeners.hasOwnProperty(event)) {
78
+ return;
79
+ }
80
+ const listeners = this._listeners[event], index = listeners.findIndex(v => v === handler);
81
+ if (index > -1) {
82
+ listeners.splice(index, 1);
83
+
84
+ if (listeners.length === 0) {
85
+ delete this._listeners[event];
86
+ }
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Remove all listeners
92
+ */
93
+ removeAllListeners() {
94
+ const events = Object.keys(this._listeners);
95
+ while (events.length > 0) {
96
+ const event = events.pop();
97
+ if (event) {
98
+ const listeners = this._listeners[event];
99
+ if (Array.isArray(listeners)) {
100
+ while (listeners.length > 0) {
101
+ const listener = listeners.pop();
102
+ if (listener) {
103
+ this.removeEventListener(event as E, listener as H);
104
+ }
105
+ }
106
+ }
107
+ }
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Method of destroying handlers
113
+ */
114
+ dispose() {
115
+ this._disposed = true;
116
+
117
+ this.removeAllListeners();
118
+ }
119
+ }
@@ -1,7 +1,15 @@
1
- import { isDirection } from "./isDirection";
2
- import { debounce } from "./debounce";
3
- import { toggleClassName } from './toggleClassName';
4
- import { Tracker } from "./tracker";
5
- import { TrackBox } from "./trackBox";
6
- import { ScrollEvent } from "./scrollEvent";
7
- export { isDirection, debounce, toggleClassName, ScrollEvent, TrackBox, Tracker, };
1
+ import { isDirection } from "./isDirection";
2
+ import { debounce } from "./debounce";
3
+ import { toggleClassName } from './toggleClassName';
4
+ import { Tracker } from "./tracker";
5
+ import { TrackBox } from "./trackBox";
6
+ import { ScrollEvent } from "./scrollEvent";
7
+
8
+ export {
9
+ isDirection,
10
+ debounce,
11
+ toggleClassName,
12
+ ScrollEvent,
13
+ TrackBox,
14
+ Tracker,
15
+ };
@@ -0,0 +1,17 @@
1
+ import { Direction, Directions } from "../enums";
2
+
3
+ const HORIZONTAL_ALIASES = [Directions.HORIZONTAL, 'horizontal'],
4
+ VERTICAL_ALIASES = [Directions.VERTICAL, 'vertical'];
5
+
6
+ /**
7
+ * Determines the axis membership of a virtual list
8
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/isDirection.ts
9
+ * @author Evgenii Grebennikov
10
+ * @email djonnyx@gmail.com
11
+ */
12
+ export const isDirection = (src: Direction, expected: Direction): boolean => {
13
+ if (HORIZONTAL_ALIASES.includes(expected)) {
14
+ return HORIZONTAL_ALIASES.includes(src);
15
+ }
16
+ return VERTICAL_ALIASES.includes(src);
17
+ }
@@ -0,0 +1,62 @@
1
+ import { IScrollEvent, ScrollDirection } from "../models";
2
+
3
+ interface IScrollEventParams {
4
+ direction: ScrollDirection;
5
+ container: HTMLElement;
6
+ list: HTMLElement;
7
+ delta: number;
8
+ scrollDelta: number;
9
+ isVertical: boolean;
10
+ }
11
+
12
+ /**
13
+ * Scroll event.
14
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/scrollEvent.ts
15
+ * @author Evgenii Grebennikov
16
+ * @email djonnyx@gmail.com
17
+ */
18
+ export class ScrollEvent implements IScrollEvent {
19
+ private _direction: ScrollDirection = 1;
20
+ get direction() { return this._direction; }
21
+
22
+ private _scrollSize: number = 0;
23
+ get scrollSize() { return this._scrollSize; }
24
+
25
+ private _scrollWeight: number = 0;
26
+ get scrollWeight() { return this._scrollWeight; }
27
+
28
+ private _isVertical: boolean = true;
29
+ get isVertical() { return this._isVertical; }
30
+
31
+ private _listSize: number = 0;
32
+ get listSize() { return this._listSize; }
33
+
34
+ private _size: number = 0;
35
+ get size() { return this._size; }
36
+
37
+ private _isStart: boolean = true;
38
+ get isStart() { return this._isStart; }
39
+
40
+ private _isEnd: boolean = false;
41
+ get isEnd() { return this._isEnd; }
42
+
43
+ private _delta: number = 0;
44
+ get delta() { return this._delta; }
45
+
46
+ private _scrollDelta: number = 0;
47
+ get scrollDelta() { return this._scrollDelta; }
48
+
49
+ constructor(params: IScrollEventParams) {
50
+ const { direction, isVertical, container, list, delta, scrollDelta } = params;
51
+ this._direction = direction;
52
+ this._isVertical = isVertical;
53
+ this._scrollSize = isVertical ? container.scrollTop : container.scrollLeft;
54
+ this._scrollWeight = isVertical ? container.scrollHeight : container.scrollWidth;
55
+ this._listSize = isVertical ? list.offsetHeight : list.offsetWidth;
56
+ this._size = isVertical ? container.offsetHeight : container.offsetWidth;
57
+ this._isEnd = (this._scrollSize + this._size) === this._scrollWeight;
58
+ this._delta = delta;
59
+ this._scrollDelta = scrollDelta;
60
+ this._isStart = this._scrollSize === 0;
61
+ }
62
+ }
@@ -0,0 +1,14 @@
1
+
2
+ /**
3
+ * Switch css classes
4
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/17.x/projects/ng-virtual-list/src/lib/utils/toggleClassName.ts
5
+ * @author Evgenii Grebennikov
6
+ * @email djonnyx@gmail.com
7
+ */
8
+ export const toggleClassName = (el: HTMLElement, className: string, remove = false) => {
9
+ if (!el.classList.contains(className)) {
10
+ el.classList.add(className);
11
+ } else if (remove) {
12
+ el.classList.remove(className);
13
+ }
14
+ };