@praxisjs/composables 1.0.6 → 1.1.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/CHANGELOG.md +74 -9
- package/dist/__tests__/dom.test.js +106 -22
- package/dist/__tests__/dom.test.js.map +1 -1
- package/dist/__tests__/list.test.d.ts +2 -0
- package/dist/__tests__/list.test.d.ts.map +1 -0
- package/dist/__tests__/list.test.js +156 -0
- package/dist/__tests__/list.test.js.map +1 -0
- package/dist/dom.d.ts +28 -6
- package/dist/dom.d.ts.map +1 -1
- package/dist/dom.js +69 -53
- package/dist/dom.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/list.d.ts +30 -0
- package/dist/list.d.ts.map +1 -0
- package/dist/list.js +47 -0
- package/dist/list.js.map +1 -0
- package/package.json +3 -3
- package/src/__tests__/dom.test.ts +114 -23
- package/src/__tests__/list.test.ts +210 -0
- package/src/dom.ts +78 -53
- package/src/index.ts +1 -0
- package/src/list.ts +77 -0
package/src/list.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Composable } from "@praxisjs/core";
|
|
2
|
+
import { computed, signal } from "@praxisjs/core/internal";
|
|
3
|
+
|
|
4
|
+
export interface VirtualItem<T> {
|
|
5
|
+
item: T;
|
|
6
|
+
index: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class VirtualList<T = unknown> extends Composable {
|
|
10
|
+
declare visibleItems: Array<VirtualItem<T>>;
|
|
11
|
+
declare totalHeight: number;
|
|
12
|
+
declare offsetTop: number;
|
|
13
|
+
declare offsetBottom: number;
|
|
14
|
+
|
|
15
|
+
private readonly _scrollTop = signal(0);
|
|
16
|
+
private readonly _viewHeight = signal(600);
|
|
17
|
+
private _scrollCleanup?: () => void;
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
private readonly containerRef: { current: HTMLElement | null },
|
|
21
|
+
private readonly getItems: () => T[],
|
|
22
|
+
private readonly itemHeight: number,
|
|
23
|
+
private readonly buffer = 3,
|
|
24
|
+
) {
|
|
25
|
+
super();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setup() {
|
|
29
|
+
const { _scrollTop, _viewHeight, itemHeight, buffer, getItems } = this;
|
|
30
|
+
|
|
31
|
+
const items = computed(getItems);
|
|
32
|
+
const total = computed(() => items().length);
|
|
33
|
+
|
|
34
|
+
const startIdx = computed(() =>
|
|
35
|
+
Math.max(0, Math.floor(_scrollTop() / itemHeight) - buffer),
|
|
36
|
+
);
|
|
37
|
+
const endIdx = computed(() =>
|
|
38
|
+
Math.min(
|
|
39
|
+
total() - 1,
|
|
40
|
+
Math.ceil((_scrollTop() + _viewHeight()) / itemHeight) + buffer,
|
|
41
|
+
),
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const visibleItems = computed<Array<VirtualItem<T>>>(() => {
|
|
45
|
+
const arr = items();
|
|
46
|
+
const result: Array<VirtualItem<T>> = [];
|
|
47
|
+
for (let i = startIdx(); i <= endIdx(); i++) {
|
|
48
|
+
result.push({ item: arr[i], index: i });
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const totalHeight = computed(() => total() * itemHeight);
|
|
54
|
+
const offsetTop = computed(() => startIdx() * itemHeight);
|
|
55
|
+
const offsetBottom = computed(() =>
|
|
56
|
+
Math.max(0, total() - 1 - endIdx()) * itemHeight,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return { visibleItems, totalHeight, offsetTop, offsetBottom };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
onMount() {
|
|
63
|
+
const el = this.containerRef.current;
|
|
64
|
+
if (!el) return;
|
|
65
|
+
|
|
66
|
+
const h = el.clientHeight;
|
|
67
|
+
if (h > 0) this._viewHeight.set(h);
|
|
68
|
+
|
|
69
|
+
const handler = () => { this._scrollTop.set(el.scrollTop); };
|
|
70
|
+
el.addEventListener("scroll", handler);
|
|
71
|
+
this._scrollCleanup = () => { el.removeEventListener("scroll", handler); };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
onUnmount() {
|
|
75
|
+
this._scrollCleanup?.();
|
|
76
|
+
}
|
|
77
|
+
}
|