@glhrmoura/vue-virtualize 0.1.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.
- package/LICENSE +21 -0
- package/README.md +112 -0
- package/dist/components/VirtualGrid.vue.d.ts +53 -0
- package/dist/components/VirtualList.vue.d.ts +48 -0
- package/dist/components/VirtualTable.vue.d.ts +49 -0
- package/dist/composables/useVirtualGrid.d.ts +40 -0
- package/dist/composables/useVirtualList.d.ts +31 -0
- package/dist/composables/useVirtualTable.d.ts +39 -0
- package/dist/composables/useVirtualizer.d.ts +31 -0
- package/dist/core/measurements.d.ts +10 -0
- package/dist/core/scrolling.d.ts +11 -0
- package/dist/core/types.d.ts +25 -0
- package/dist/core/virtualizer.d.ts +35 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +974 -0
- package/dist/index.mjs.map +1 -0
- package/dist/utils/clamp.d.ts +1 -0
- package/dist/utils/dom.d.ts +7 -0
- package/dist/utils/layout.d.ts +10 -0
- package/dist/utils/same-items.d.ts +2 -0
- package/package.json +91 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Guilherme Moura
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/public/logo.png" alt="" width="144" height="96" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Vue Virtualize
|
|
6
|
+
|
|
7
|
+
Headless virtualization for Vue 3 lists, grids, and tables.
|
|
8
|
+
|
|
9
|
+
[](https://github.com/glhrmoura/vue-virtualize/blob/main/LICENSE)
|
|
10
|
+
|
|
11
|
+
`@glhrmoura/vue-virtualize` mounts only the items that intersect the viewport. The layout engine is plain TypeScript: it does not import Vue and it does not touch the DOM. Components and composables subscribe to scroll and resize, then render the window the engine returns.
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- Vertical and horizontal lists
|
|
16
|
+
- Two-axis grids
|
|
17
|
+
- Tables with virtualized rows and placed columns
|
|
18
|
+
- Configurable overscan
|
|
19
|
+
- Fixed estimates and measured dynamic sizes
|
|
20
|
+
- Programmatic `scrollToIndex` and `scrollToOffset`
|
|
21
|
+
- Reactive updates when the collection changes
|
|
22
|
+
- Container resize handling and listener cleanup
|
|
23
|
+
- Empty states and stable item keys
|
|
24
|
+
- SSR-safe: no browser APIs at import time
|
|
25
|
+
- TypeScript generics for item types
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
yarn add @glhrmoura/vue-virtualize
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install @glhrmoura/vue-virtualize
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Vue 3.5+ is a peer dependency.
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
```vue
|
|
42
|
+
<script setup lang="ts">
|
|
43
|
+
import { VirtualList } from '@glhrmoura/vue-virtualize'
|
|
44
|
+
import { shallowRef } from 'vue'
|
|
45
|
+
|
|
46
|
+
interface User {
|
|
47
|
+
id: number
|
|
48
|
+
name: string
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const users = shallowRef<User[]>(
|
|
52
|
+
Array.from({ length: 100_000 }, (_, index) => ({
|
|
53
|
+
id: index + 1,
|
|
54
|
+
name: `User ${index + 1}`,
|
|
55
|
+
})),
|
|
56
|
+
)
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<template>
|
|
60
|
+
<VirtualList :items="users" :estimate-size="60" :height="500" :get-item-key="(user) => user.id">
|
|
61
|
+
<template #default="{ item, index }">
|
|
62
|
+
<UserCard :user="item" :index="index" />
|
|
63
|
+
</template>
|
|
64
|
+
</VirtualList>
|
|
65
|
+
</template>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Examples
|
|
69
|
+
|
|
70
|
+
| Component | Use |
|
|
71
|
+
| ---------------- | ------------------------------------------------------ |
|
|
72
|
+
| `VirtualList` | One axis, vertical or `horizontal` |
|
|
73
|
+
| `VirtualGrid` | Flat array, `columnCount`, row and column estimates |
|
|
74
|
+
| `VirtualTable` | `rows`, `columns`, windowed body |
|
|
75
|
+
| `useVirtualizer` | Custom markup driven by `virtualItems` and `totalSize` |
|
|
76
|
+
|
|
77
|
+
The playground (`yarn dev`) includes 1,000, 10,000, and 100,000 row lists, a measured-height list, a grid, and a table.
|
|
78
|
+
|
|
79
|
+
## Documentation
|
|
80
|
+
|
|
81
|
+
Guides and the API reference live in `docs/` and are built with VitePress:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
yarn docs:dev
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Scripts
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
yarn test
|
|
91
|
+
yarn typecheck
|
|
92
|
+
yarn lint
|
|
93
|
+
yarn build
|
|
94
|
+
yarn bench
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`yarn bench` measures the engine locally. This repository does not publish benchmark numbers.
|
|
98
|
+
|
|
99
|
+
## Publishing
|
|
100
|
+
|
|
101
|
+
Changesets tracks versions. CI runs lint, typecheck, tests, and the library build. Publishing to npm is a manual step after `yarn build`. The package name is `@glhrmoura/vue-virtualize`.
|
|
102
|
+
|
|
103
|
+
## Contributing
|
|
104
|
+
|
|
105
|
+
1. Install dependencies with yarn (`packageManager` is pinned in `package.json`).
|
|
106
|
+
2. Branch from the default branch.
|
|
107
|
+
3. Add a changeset when the public API or behavior changes.
|
|
108
|
+
4. Run `yarn lint`, `yarn typecheck`, `yarn test`, and `yarn build`.
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'vue';
|
|
2
|
+
declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
3
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<{
|
|
4
|
+
items: readonly T[];
|
|
5
|
+
columnCount?: number;
|
|
6
|
+
estimateRowSize?: number | ((rowIndex: number) => number);
|
|
7
|
+
estimateColumnSize?: number | ((columnIndex: number) => number);
|
|
8
|
+
height?: number | string;
|
|
9
|
+
width?: number | string;
|
|
10
|
+
overscan?: number;
|
|
11
|
+
overscanRows?: number;
|
|
12
|
+
overscanColumns?: number;
|
|
13
|
+
rowGap?: number;
|
|
14
|
+
columnGap?: number;
|
|
15
|
+
getItemKey?: (item: T, index: number) => string | number;
|
|
16
|
+
tag?: string;
|
|
17
|
+
itemAttrs?: HTMLAttributes;
|
|
18
|
+
revision?: unknown;
|
|
19
|
+
}> & (typeof globalThis extends {
|
|
20
|
+
__VLS_PROPS_FALLBACK: infer P;
|
|
21
|
+
} ? P : {});
|
|
22
|
+
expose: (exposed: import("vue").ShallowUnwrapRef<{
|
|
23
|
+
scrollToIndex: (index: number, scrollOptions?: import("..").ScrollToIndexOptions) => void;
|
|
24
|
+
scrollToOffset: (offset: {
|
|
25
|
+
top?: number;
|
|
26
|
+
left?: number;
|
|
27
|
+
}, behavior?: ScrollBehavior) => void;
|
|
28
|
+
measureRow: (rowIndex: number, size: number) => void;
|
|
29
|
+
}>) => void;
|
|
30
|
+
attrs: any;
|
|
31
|
+
slots: {
|
|
32
|
+
empty?: (props: {}) => any;
|
|
33
|
+
} & {
|
|
34
|
+
default?: (props: {
|
|
35
|
+
item: T;
|
|
36
|
+
index: number;
|
|
37
|
+
rowIndex: number;
|
|
38
|
+
columnIndex: number;
|
|
39
|
+
row: import("..").VirtualItem;
|
|
40
|
+
column: import("..").VirtualItem;
|
|
41
|
+
}) => any;
|
|
42
|
+
};
|
|
43
|
+
emit: {};
|
|
44
|
+
}>) => import("vue").VNode & {
|
|
45
|
+
__ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
|
|
46
|
+
};
|
|
47
|
+
declare const _default: typeof __VLS_export;
|
|
48
|
+
export default _default;
|
|
49
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
50
|
+
[K in keyof T]: T[K];
|
|
51
|
+
} : {
|
|
52
|
+
[K in keyof T as K]: T[K];
|
|
53
|
+
}) & {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'vue';
|
|
2
|
+
declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
3
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<{
|
|
4
|
+
items: readonly T[];
|
|
5
|
+
estimateSize?: number | ((index: number, item: T) => number);
|
|
6
|
+
height?: number | string;
|
|
7
|
+
width?: number | string;
|
|
8
|
+
horizontal?: boolean;
|
|
9
|
+
overscan?: number;
|
|
10
|
+
gap?: number;
|
|
11
|
+
paddingStart?: number;
|
|
12
|
+
paddingEnd?: number;
|
|
13
|
+
getItemKey?: (item: T, index: number) => string | number;
|
|
14
|
+
tag?: string;
|
|
15
|
+
itemTag?: string;
|
|
16
|
+
itemAttrs?: HTMLAttributes;
|
|
17
|
+
revision?: unknown;
|
|
18
|
+
}> & (typeof globalThis extends {
|
|
19
|
+
__VLS_PROPS_FALLBACK: infer P;
|
|
20
|
+
} ? P : {});
|
|
21
|
+
expose: (exposed: import("vue").ShallowUnwrapRef<{
|
|
22
|
+
scrollToIndex: (index: number, scrollOptions?: import("..").ScrollToIndexOptions) => void;
|
|
23
|
+
scrollToOffset: (offset: number, behavior?: ScrollBehavior) => void;
|
|
24
|
+
measure: (index: number, size: number) => void;
|
|
25
|
+
}>) => void;
|
|
26
|
+
attrs: any;
|
|
27
|
+
slots: {
|
|
28
|
+
empty?: (props: {}) => any;
|
|
29
|
+
} & {
|
|
30
|
+
default?: (props: {
|
|
31
|
+
item: T;
|
|
32
|
+
index: number;
|
|
33
|
+
start: number;
|
|
34
|
+
size: number;
|
|
35
|
+
end: number;
|
|
36
|
+
}) => any;
|
|
37
|
+
};
|
|
38
|
+
emit: {};
|
|
39
|
+
}>) => import("vue").VNode & {
|
|
40
|
+
__ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
|
|
41
|
+
};
|
|
42
|
+
declare const _default: typeof __VLS_export;
|
|
43
|
+
export default _default;
|
|
44
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
45
|
+
[K in keyof T]: T[K];
|
|
46
|
+
} : {
|
|
47
|
+
[K in keyof T as K]: T[K];
|
|
48
|
+
}) & {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'vue';
|
|
2
|
+
import { type VirtualTableColumn } from '../composables/useVirtualTable';
|
|
3
|
+
declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
4
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<{
|
|
5
|
+
rows: readonly T[];
|
|
6
|
+
columns: readonly VirtualTableColumn<T>[];
|
|
7
|
+
estimateRowSize?: number | ((index: number, row: T) => number);
|
|
8
|
+
height?: number | string;
|
|
9
|
+
width?: number | string;
|
|
10
|
+
overscan?: number;
|
|
11
|
+
getRowKey?: (row: T, index: number) => string | number;
|
|
12
|
+
stickyHeader?: boolean;
|
|
13
|
+
tag?: string;
|
|
14
|
+
rowAttrs?: HTMLAttributes;
|
|
15
|
+
revision?: unknown;
|
|
16
|
+
}> & (typeof globalThis extends {
|
|
17
|
+
__VLS_PROPS_FALLBACK: infer P;
|
|
18
|
+
} ? P : {});
|
|
19
|
+
expose: (exposed: import("vue").ShallowUnwrapRef<{
|
|
20
|
+
scrollToIndex: (index: number, scrollOptions?: import("..").ScrollToIndexOptions) => void;
|
|
21
|
+
scrollToOffset: (offset: number, behavior?: ScrollBehavior) => void;
|
|
22
|
+
measure: (index: number, size: number) => void;
|
|
23
|
+
}>) => void;
|
|
24
|
+
attrs: any;
|
|
25
|
+
slots: {
|
|
26
|
+
header?: (props: {
|
|
27
|
+
columns: import("..").PlacedVirtualTableColumn<T>[];
|
|
28
|
+
}) => any;
|
|
29
|
+
} & {
|
|
30
|
+
empty?: (props: {}) => any;
|
|
31
|
+
} & {
|
|
32
|
+
cell?: (props: {
|
|
33
|
+
row: T;
|
|
34
|
+
column: import("..").PlacedVirtualTableColumn<T>;
|
|
35
|
+
rowIndex: number;
|
|
36
|
+
value: unknown;
|
|
37
|
+
}) => any;
|
|
38
|
+
};
|
|
39
|
+
emit: {};
|
|
40
|
+
}>) => import("vue").VNode & {
|
|
41
|
+
__ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
|
|
42
|
+
};
|
|
43
|
+
declare const _default: typeof __VLS_export;
|
|
44
|
+
export default _default;
|
|
45
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
46
|
+
[K in keyof T]: T[K];
|
|
47
|
+
} : {
|
|
48
|
+
[K in keyof T as K]: T[K];
|
|
49
|
+
}) & {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type MaybeRefOrGetter } from 'vue';
|
|
2
|
+
import type { ScrollToIndexOptions, VirtualItem } from '../core/types';
|
|
3
|
+
import { type UseVirtualizerOptions } from './useVirtualizer';
|
|
4
|
+
export interface VirtualGridCell<T> {
|
|
5
|
+
index: number;
|
|
6
|
+
key: string | number;
|
|
7
|
+
item: T;
|
|
8
|
+
row: VirtualItem;
|
|
9
|
+
column: VirtualItem;
|
|
10
|
+
}
|
|
11
|
+
export interface UseVirtualGridOptions<T> {
|
|
12
|
+
items: MaybeRefOrGetter<readonly T[]>;
|
|
13
|
+
columnCount: MaybeRefOrGetter<number>;
|
|
14
|
+
estimateRowSize?: MaybeRefOrGetter<number | ((rowIndex: number) => number)>;
|
|
15
|
+
estimateColumnSize?: MaybeRefOrGetter<number | ((columnIndex: number) => number)>;
|
|
16
|
+
container?: UseVirtualizerOptions['container'];
|
|
17
|
+
overscan?: MaybeRefOrGetter<number | undefined>;
|
|
18
|
+
overscanRows?: MaybeRefOrGetter<number | undefined>;
|
|
19
|
+
overscanColumns?: MaybeRefOrGetter<number | undefined>;
|
|
20
|
+
rowGap?: MaybeRefOrGetter<number | undefined>;
|
|
21
|
+
columnGap?: MaybeRefOrGetter<number | undefined>;
|
|
22
|
+
getItemKey?: (item: T, index: number) => string | number;
|
|
23
|
+
initialRect?: UseVirtualizerOptions['initialRect'];
|
|
24
|
+
revision?: UseVirtualizerOptions['revision'];
|
|
25
|
+
}
|
|
26
|
+
export declare function useVirtualGrid<T>(options: UseVirtualGridOptions<T>): {
|
|
27
|
+
virtualRows: import("vue").ComputedRef<VirtualItem[]>;
|
|
28
|
+
virtualColumns: import("vue").ComputedRef<VirtualItem[]>;
|
|
29
|
+
virtualCells: import("vue").ComputedRef<VirtualGridCell<T>[]>;
|
|
30
|
+
totalHeight: import("vue").ComputedRef<number>;
|
|
31
|
+
totalWidth: import("vue").ComputedRef<number>;
|
|
32
|
+
scrollToIndex: (index: number, scrollOptions?: ScrollToIndexOptions) => void;
|
|
33
|
+
scrollToOffset: (offset: {
|
|
34
|
+
top?: number;
|
|
35
|
+
left?: number;
|
|
36
|
+
}, behavior?: ScrollBehavior) => void;
|
|
37
|
+
measureRow: (rowIndex: number, size: number) => void;
|
|
38
|
+
measureRowElement: (target: unknown, rowIndex: number) => void;
|
|
39
|
+
measureColumn: (index: number, size: number) => void;
|
|
40
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type MaybeRefOrGetter } from 'vue';
|
|
2
|
+
import type { VirtualItem } from '../core/types';
|
|
3
|
+
import { type UseVirtualizerOptions } from './useVirtualizer';
|
|
4
|
+
export interface VirtualListItem<T> extends VirtualItem {
|
|
5
|
+
item: T;
|
|
6
|
+
}
|
|
7
|
+
export interface UseVirtualListOptions<T> {
|
|
8
|
+
items: MaybeRefOrGetter<readonly T[]>;
|
|
9
|
+
estimateSize?: number | ((index: number, item: T) => number);
|
|
10
|
+
container?: UseVirtualizerOptions['container'];
|
|
11
|
+
horizontal?: UseVirtualizerOptions['horizontal'];
|
|
12
|
+
overscan?: UseVirtualizerOptions['overscan'];
|
|
13
|
+
gap?: UseVirtualizerOptions['gap'];
|
|
14
|
+
paddingStart?: UseVirtualizerOptions['paddingStart'];
|
|
15
|
+
paddingEnd?: UseVirtualizerOptions['paddingEnd'];
|
|
16
|
+
itemSize?: UseVirtualizerOptions['itemSize'];
|
|
17
|
+
getItemKey?: (item: T, index: number) => string | number;
|
|
18
|
+
initialRect?: UseVirtualizerOptions['initialRect'];
|
|
19
|
+
viewportInset?: UseVirtualizerOptions['viewportInset'];
|
|
20
|
+
revision?: UseVirtualizerOptions['revision'];
|
|
21
|
+
}
|
|
22
|
+
export declare function useVirtualList<T>(options: UseVirtualListOptions<T>): {
|
|
23
|
+
virtualItems: import("vue").ComputedRef<VirtualListItem<T>[]>;
|
|
24
|
+
totalSize: import("vue").ComputedRef<number>;
|
|
25
|
+
scrollOffset: import("vue").ComputedRef<number>;
|
|
26
|
+
isScrolling: import("vue").ComputedRef<boolean>;
|
|
27
|
+
scrollToIndex: (index: number, scrollOptions?: import("..").ScrollToIndexOptions) => void;
|
|
28
|
+
scrollToOffset: (offset: number, behavior?: ScrollBehavior) => void;
|
|
29
|
+
measure: (index: number, size: number) => void;
|
|
30
|
+
measureElement: (target: unknown, index: number) => void;
|
|
31
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type MaybeRefOrGetter } from 'vue';
|
|
2
|
+
import { type UseVirtualListOptions, type VirtualListItem } from './useVirtualList';
|
|
3
|
+
export interface VirtualTableColumn<T> {
|
|
4
|
+
id: string;
|
|
5
|
+
header: string;
|
|
6
|
+
width?: number;
|
|
7
|
+
minWidth?: number;
|
|
8
|
+
align?: 'left' | 'center' | 'right';
|
|
9
|
+
accessor?: (row: T, index: number) => unknown;
|
|
10
|
+
}
|
|
11
|
+
export interface PlacedVirtualTableColumn<T> extends VirtualTableColumn<T> {
|
|
12
|
+
start: number;
|
|
13
|
+
size: number;
|
|
14
|
+
end: number;
|
|
15
|
+
}
|
|
16
|
+
export interface UseVirtualTableOptions<T> {
|
|
17
|
+
rows: MaybeRefOrGetter<readonly T[]>;
|
|
18
|
+
columns: MaybeRefOrGetter<readonly VirtualTableColumn<T>[]>;
|
|
19
|
+
estimateRowSize?: number | ((index: number, row: T) => number);
|
|
20
|
+
container?: UseVirtualListOptions<T>['container'];
|
|
21
|
+
overscan?: UseVirtualListOptions<T>['overscan'];
|
|
22
|
+
getRowKey?: (row: T, index: number) => string | number;
|
|
23
|
+
initialRect?: UseVirtualListOptions<T>['initialRect'];
|
|
24
|
+
viewportInset?: UseVirtualListOptions<T>['viewportInset'];
|
|
25
|
+
revision?: UseVirtualListOptions<T>['revision'];
|
|
26
|
+
itemSize?: UseVirtualListOptions<T>['itemSize'];
|
|
27
|
+
}
|
|
28
|
+
export declare function useVirtualTable<T>(options: UseVirtualTableOptions<T>): {
|
|
29
|
+
virtualRows: import("vue").ComputedRef<VirtualListItem<T>[]>;
|
|
30
|
+
columns: import("vue").ComputedRef<PlacedVirtualTableColumn<T>[]>;
|
|
31
|
+
totalHeight: import("vue").ComputedRef<number>;
|
|
32
|
+
totalWidth: import("vue").ComputedRef<number>;
|
|
33
|
+
scrollOffset: import("vue").ComputedRef<number>;
|
|
34
|
+
isScrolling: import("vue").ComputedRef<boolean>;
|
|
35
|
+
scrollToIndex: (index: number, scrollOptions?: import("..").ScrollToIndexOptions) => void;
|
|
36
|
+
scrollToOffset: (offset: number, behavior?: ScrollBehavior) => void;
|
|
37
|
+
measure: (index: number, size: number) => void;
|
|
38
|
+
measureElement: (target: unknown, index: number) => void;
|
|
39
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type MaybeRefOrGetter } from 'vue';
|
|
2
|
+
import type { ScrollToIndexOptions, VirtualItem } from '../core/types';
|
|
3
|
+
export interface UseVirtualizerOptions {
|
|
4
|
+
count: MaybeRefOrGetter<number>;
|
|
5
|
+
estimateSize: (index: number) => number;
|
|
6
|
+
container?: MaybeRefOrGetter<HTMLElement | null | undefined>;
|
|
7
|
+
horizontal?: MaybeRefOrGetter<boolean>;
|
|
8
|
+
overscan?: MaybeRefOrGetter<number>;
|
|
9
|
+
gap?: MaybeRefOrGetter<number>;
|
|
10
|
+
paddingStart?: MaybeRefOrGetter<number>;
|
|
11
|
+
paddingEnd?: MaybeRefOrGetter<number>;
|
|
12
|
+
lanes?: MaybeRefOrGetter<number>;
|
|
13
|
+
itemSize?: MaybeRefOrGetter<number | null | undefined>;
|
|
14
|
+
getItemKey?: (index: number) => string | number;
|
|
15
|
+
initialRect?: MaybeRefOrGetter<{
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
} | undefined>;
|
|
19
|
+
viewportInset?: MaybeRefOrGetter<number>;
|
|
20
|
+
revision?: MaybeRefOrGetter<unknown>;
|
|
21
|
+
}
|
|
22
|
+
export declare function useVirtualizer(options: UseVirtualizerOptions): {
|
|
23
|
+
virtualItems: import("vue").ComputedRef<VirtualItem[]>;
|
|
24
|
+
totalSize: import("vue").ComputedRef<number>;
|
|
25
|
+
scrollOffset: import("vue").ComputedRef<number>;
|
|
26
|
+
isScrolling: import("vue").ComputedRef<boolean>;
|
|
27
|
+
scrollToIndex: (index: number, scrollOptions?: ScrollToIndexOptions) => void;
|
|
28
|
+
scrollToOffset: (offset: number, behavior?: ScrollBehavior) => void;
|
|
29
|
+
measure: (index: number, size: number) => void;
|
|
30
|
+
measureElement: (target: unknown, index: number) => void;
|
|
31
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function normalizeSize(size: number): number;
|
|
2
|
+
export declare class MeasurementCache {
|
|
3
|
+
private readonly sizes;
|
|
4
|
+
private divergent;
|
|
5
|
+
get(index: number): number | undefined;
|
|
6
|
+
set(index: number, size: number, baseline: number | null): void;
|
|
7
|
+
get hasDivergent(): boolean;
|
|
8
|
+
clear(): void;
|
|
9
|
+
trim(count: number, baseline: number | null): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ScrollAlignment } from './types';
|
|
2
|
+
export declare function clampScrollOffset(offset: number, totalSize: number, viewport: number): number;
|
|
3
|
+
export declare function findFirstIndexPast(count: number, target: number, getEnd: (index: number) => number): number;
|
|
4
|
+
export declare function findLastIndexBefore(count: number, target: number, getStart: (index: number) => number): number;
|
|
5
|
+
export declare function resolveScrollOffset(input: {
|
|
6
|
+
start: number;
|
|
7
|
+
size: number;
|
|
8
|
+
viewport: number;
|
|
9
|
+
current: number;
|
|
10
|
+
align: ScrollAlignment;
|
|
11
|
+
}): number;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type ScrollAlignment = 'start' | 'center' | 'end' | 'auto';
|
|
2
|
+
export interface VirtualItem {
|
|
3
|
+
index: number;
|
|
4
|
+
key: string | number;
|
|
5
|
+
start: number;
|
|
6
|
+
size: number;
|
|
7
|
+
end: number;
|
|
8
|
+
lane: number;
|
|
9
|
+
}
|
|
10
|
+
export interface VirtualizerOptions {
|
|
11
|
+
count: number;
|
|
12
|
+
estimateSize: (index: number) => number;
|
|
13
|
+
overscan?: number;
|
|
14
|
+
gap?: number;
|
|
15
|
+
paddingStart?: number;
|
|
16
|
+
paddingEnd?: number;
|
|
17
|
+
lanes?: number;
|
|
18
|
+
itemSize?: number | null;
|
|
19
|
+
viewportSize?: number;
|
|
20
|
+
getItemKey?: (index: number) => string | number;
|
|
21
|
+
}
|
|
22
|
+
export interface ScrollToIndexOptions {
|
|
23
|
+
align?: ScrollAlignment;
|
|
24
|
+
behavior?: ScrollBehavior;
|
|
25
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ScrollAlignment, VirtualItem, VirtualizerOptions } from './types';
|
|
2
|
+
export declare class Virtualizer {
|
|
3
|
+
private count;
|
|
4
|
+
private estimateSize;
|
|
5
|
+
private overscan;
|
|
6
|
+
private gap;
|
|
7
|
+
private paddingStart;
|
|
8
|
+
private paddingEnd;
|
|
9
|
+
private lanes;
|
|
10
|
+
private itemSize;
|
|
11
|
+
private viewportSize;
|
|
12
|
+
private scrollOffset;
|
|
13
|
+
private getItemKey;
|
|
14
|
+
private readonly measurements;
|
|
15
|
+
private built;
|
|
16
|
+
private offsets;
|
|
17
|
+
private laneCursor;
|
|
18
|
+
private laneEnd;
|
|
19
|
+
setOptions(options: VirtualizerOptions): void;
|
|
20
|
+
setScrollOffset(offset: number): void;
|
|
21
|
+
getScrollOffset(): number;
|
|
22
|
+
getViewportSize(): number;
|
|
23
|
+
measure(index: number, size: number): boolean;
|
|
24
|
+
clearMeasurements(): void;
|
|
25
|
+
getItemSize(index: number): number;
|
|
26
|
+
getItemOffset(index: number): number;
|
|
27
|
+
getTotalSize(): number;
|
|
28
|
+
getVirtualItems(): VirtualItem[];
|
|
29
|
+
getOffsetForIndex(index: number, align?: ScrollAlignment): number;
|
|
30
|
+
private usesFixedPath;
|
|
31
|
+
private ordinalIndex;
|
|
32
|
+
private laneLength;
|
|
33
|
+
private ensure;
|
|
34
|
+
private resetGeometry;
|
|
35
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { Virtualizer } from './core/virtualizer';
|
|
2
|
+
export { MeasurementCache, normalizeSize } from './core/measurements';
|
|
3
|
+
export { clampScrollOffset, resolveScrollOffset } from './core/scrolling';
|
|
4
|
+
export type { ScrollAlignment, ScrollToIndexOptions, VirtualItem, VirtualizerOptions, } from './core/types';
|
|
5
|
+
export { useVirtualizer } from './composables/useVirtualizer';
|
|
6
|
+
export type { UseVirtualizerOptions } from './composables/useVirtualizer';
|
|
7
|
+
export { useVirtualList } from './composables/useVirtualList';
|
|
8
|
+
export type { UseVirtualListOptions, VirtualListItem } from './composables/useVirtualList';
|
|
9
|
+
export { useVirtualGrid } from './composables/useVirtualGrid';
|
|
10
|
+
export type { UseVirtualGridOptions, VirtualGridCell } from './composables/useVirtualGrid';
|
|
11
|
+
export { useVirtualTable } from './composables/useVirtualTable';
|
|
12
|
+
export type { PlacedVirtualTableColumn, UseVirtualTableOptions, VirtualTableColumn, } from './composables/useVirtualTable';
|
|
13
|
+
export { default as VirtualList } from './components/VirtualList.vue';
|
|
14
|
+
export { default as VirtualGrid } from './components/VirtualGrid.vue';
|
|
15
|
+
export { default as VirtualTable } from './components/VirtualTable.vue';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("vue");function K(e){return!Number.isFinite(e)||e<0?0:e}class Z{sizes=new Map;divergent=!1;get(n){return this.sizes.get(n)}set(n,i,r){this.sizes.set(n,i),r!==null&&Math.abs(i-r)>=.5&&(this.divergent=!0)}get hasDivergent(){return this.divergent}clear(){this.sizes.clear(),this.divergent=!1}trim(n,i){let r=!1;for(const s of this.sizes.keys())s>=n&&(this.sizes.delete(s),r=!0);if(r&&(this.divergent=!1,i!==null)){for(const s of this.sizes.values())if(Math.abs(s-i)>=.5){this.divergent=!0;return}}}}function ee(e,n,i){return Math.min(i,Math.max(n,e))}function G(e,n,i){const r=Math.max(0,n-Math.max(0,i));return ee(Number.isFinite(e)?e:0,0,r)}function le(e,n,i){if(e<=0)return 0;let r=0,s=e-1,o=e-1;for(;r<=s;){const d=r+s>>>1;i(d)>n?(o=d,s=d-1):r=d+1}return o}function ue(e,n,i){if(e<=0)return 0;let r=0,s=e-1,o=0;for(;r<=s;){const d=r+s>>>1;i(d)<n?(o=d,r=d+1):s=d-1}return o}function te(e){const n=e.start+e.size;let i=e.align;if(i==="auto"){const r=e.current+e.viewport;if(e.start>=e.current&&n<=r)return e.current;i=e.start<e.current?"start":"end"}return i==="center"?e.start-(e.viewport-e.size)/2:i==="end"?n-e.viewport:e.start}class ne{count=0;estimateSize=()=>0;overscan=0;gap=0;paddingStart=0;paddingEnd=0;lanes=1;itemSize=null;viewportSize=0;scrollOffset=0;getItemKey=n=>n;measurements=new Z;built=0;offsets=[];laneCursor=[];laneEnd=[];setOptions(n){const i=Math.max(1,Math.floor(n.lanes??1)),r=n.gap??0,s=n.paddingStart??0,o=n.paddingEnd??0,d=Math.max(0,Math.floor(n.count)),h=n.itemSize===void 0||n.itemSize===null?null:K(n.itemSize),y=this.itemSize,x=i!==this.lanes||r!==this.gap||s!==this.paddingStart||o!==this.paddingEnd||n.estimateSize!==this.estimateSize||h!==this.itemSize;this.count=d,this.lanes=i,this.gap=r,this.paddingStart=s,this.paddingEnd=o,this.overscan=Math.max(0,Math.floor(n.overscan??0)),this.estimateSize=n.estimateSize,this.itemSize=h,this.getItemKey=n.getItemKey??(v=>v),n.viewportSize!==void 0&&(this.viewportSize=Math.max(0,n.viewportSize)),h!==y&&this.measurements.clear(),this.measurements.trim(this.count,this.itemSize),(x||this.built>this.count)&&this.resetGeometry()}setScrollOffset(n){this.scrollOffset=Number.isFinite(n)?n:0}getScrollOffset(){return this.scrollOffset}getViewportSize(){return this.viewportSize}measure(n,i){if(n<0||n>=this.count)return!1;const r=K(i),s=this.measurements.get(n);if(s!==void 0&&Math.abs(s-r)<.5)return!1;const o=this.getItemSize(n);return this.measurements.set(n,r,this.itemSize),Math.abs(o-r)<.5?!1:(this.resetGeometry(),!0)}clearMeasurements(){this.measurements.clear(),this.resetGeometry()}getItemSize(n){const i=this.measurements.get(n);return i!==void 0?i:this.itemSize!==null?this.itemSize:K(this.estimateSize(n))}getItemOffset(n){if(n<=0||this.count<=0)return this.paddingStart;const i=Math.min(n,this.count-1);if(this.usesFixedPath()){const r=Math.floor(i/this.lanes);return this.paddingStart+r*((this.itemSize??0)+this.gap)}return this.ensure(i),this.offsets[i]??this.paddingStart}getTotalSize(){if(this.count<=0)return this.paddingStart+this.paddingEnd;if(this.usesFixedPath()){let i=this.paddingStart;const r=this.itemSize??0;for(let s=0;s<this.lanes&&s<this.count;s+=1){const o=this.laneLength(s),d=this.paddingStart+o*r+Math.max(0,o-1)*this.gap;d>i&&(i=d)}return i+this.paddingEnd}this.ensure(this.count-1);let n=this.paddingStart;for(let i=0;i<this.lanes&&i<this.count;i+=1){const r=this.laneEnd[i]??this.paddingStart;r>n&&(n=r)}return n+this.paddingEnd}getVirtualItems(){if(this.count<=0||this.viewportSize<=0)return[];const n=G(this.scrollOffset,this.getTotalSize(),this.viewportSize),i=n+this.viewportSize,r=[];for(let s=0;s<this.lanes;s+=1){const o=this.laneLength(s);if(o<=0)continue;const d=le(o,n,v=>{const p=this.ordinalIndex(s,v);return this.getItemOffset(p)+this.getItemSize(p)}),h=ue(o,i,v=>this.getItemOffset(this.ordinalIndex(s,v))),y=Math.max(0,Math.min(d,h)-this.overscan),x=Math.min(o-1,Math.max(d,h)+this.overscan);for(let v=y;v<=x;v+=1){const p=this.ordinalIndex(s,v),I=this.getItemOffset(p),E=this.getItemSize(p);r.push({index:p,key:this.getItemKey(p),start:I,size:E,end:I+E,lane:s})}}return r.sort((s,o)=>s.index-o.index),r}getOffsetForIndex(n,i="auto"){if(this.count<=0)return 0;const r=ee(n,0,this.count-1),s=this.getItemOffset(r),o=this.getItemSize(r),d=te({start:s,size:o,viewport:this.viewportSize,current:this.scrollOffset,align:i});return G(d,this.getTotalSize(),this.viewportSize)}usesFixedPath(){return this.itemSize!==null&&!this.measurements.hasDivergent}ordinalIndex(n,i){return n+i*this.lanes}laneLength(n){return n<0||n>=this.lanes||n>=this.count?0:Math.floor((this.count-n-1)/this.lanes)+1}ensure(n){if(n<this.built)return;const i=Math.min(n,this.count-1);for(;this.built<=i;){const r=this.built%this.lanes,s=this.laneCursor[r]??this.paddingStart;this.offsets[this.built]=s;const o=s+this.getItemSize(this.built);this.laneEnd[r]=o,this.laneCursor[r]=o+this.gap,this.built+=1}}resetGeometry(){this.built=0,this.offsets=[],this.laneCursor=Array.from({length:this.lanes},()=>this.paddingStart),this.laneEnd=Array.from({length:this.lanes},()=>this.paddingStart)}}function F(){return typeof window<"u"&&typeof document<"u"}function ie(e){return typeof Element>"u"?null:e instanceof Element?e:null}function N(e,n,i,r){if(r==="smooth"&&typeof e.scrollTo=="function"){e.scrollTo({top:i?e.scrollTop:n,left:i?n:e.scrollLeft,behavior:r});return}i?e.scrollLeft=n:e.scrollTop=n}function P(e,n){return n?e.scrollLeft:e.scrollTop}function U(e,n){return n?e.clientWidth:e.clientHeight}function Y(e){return typeof requestAnimationFrame=="function"?requestAnimationFrame(e):setTimeout(e,0)}function X(e){e&&(typeof cancelAnimationFrame=="function"?cancelAnimationFrame(e):clearTimeout(e))}function ce(e,n){if(e.length!==n.length)return!1;for(let i=0;i<e.length;i+=1){const r=e[i],s=n[i];if(!r||!s||r.index!==s.index||r.start!==s.start||r.size!==s.size||r.end!==s.end||r.lane!==s.lane||r.key!==s.key)return!1}return!0}function A(e){const n=new ne,i=t.shallowRef([]),r=t.ref(0),s=t.ref(0),o=t.ref(!1),d=c=>e.estimateSize(c);let h=null,y=null,x=null,v=0,p=0,I=0,E=t.toValue(e.revision);const l=new Map,u=new Map,a=[];function f(){const c=t.toValue(e.container);return typeof HTMLElement>"u"?null:c instanceof HTMLElement?c:null}function S(){return t.toValue(e.horizontal)??!1}function C(){const c=t.toValue(e.initialRect);return c?S()?c.width:c.height:0}function O(){const c=t.toValue(e.revision);Object.is(c,E)||(E=c,n.clearMeasurements());const z=f(),w=z?U(z,S()):0,V=t.toValue(e.viewportInset)??0,k=Math.max(0,(w>0?w:C())-V),T=t.toValue(e.itemSize);n.setOptions({count:t.toValue(e.count),estimateSize:d,overscan:t.toValue(e.overscan)??5,gap:t.toValue(e.gap)??0,paddingStart:t.toValue(e.paddingStart)??0,paddingEnd:t.toValue(e.paddingEnd)??0,lanes:t.toValue(e.lanes)??1,itemSize:T??null,getItemKey:e.getItemKey,viewportSize:k});const M=Math.max(0,n.getTotalSize()-k);n.getScrollOffset()>M&&(n.setScrollOffset(M),z&&P(z,S())!==M&&N(z,M,S(),"auto"));const _=n.getVirtualItems();ce(i.value,_)||(i.value=_);const j=n.getTotalSize();r.value!==j&&(r.value=j);const q=n.getScrollOffset();s.value!==q&&(s.value=q)}function $(){if(!F()){O();return}v||(v=Y(()=>{v=0,o.value=!0,O(),typeof window<"u"&&(window.clearTimeout(I),I=window.setTimeout(()=>{o.value=!1},150))}))}function m(){const c=f();c&&(n.setScrollOffset(P(c,S())),$())}function b(){const c=f();if(c===h||(h&&(h.removeEventListener("scroll",m),y?.disconnect(),y=null),h=c,!c||!F()))return;const z=S();n.getScrollOffset()>0?N(c,n.getScrollOffset(),z,"auto"):n.setScrollOffset(P(c,z)),c.addEventListener("scroll",m,{passive:!0}),typeof ResizeObserver<"u"&&(y=new ResizeObserver(()=>O()),y.observe(c))}function g(){return!F()||typeof ResizeObserver>"u"?null:(x||(x=new ResizeObserver(c=>{const z=S();let w=!1;for(const V of c){const k=l.get(V.target);if(k===void 0)continue;const T=V.borderBoxSize?.[0],M=z?T?.inlineSize??V.contentRect.width:T?.blockSize??V.contentRect.height;M>0&&n.measure(k,M)&&(w=!0)}w&&O()})),x)}function R(){p=0;const c=a.splice(0,a.length),z=S();let w=!1;for(const V of c){if(!V.element.isConnected)continue;const k=V.element.getBoundingClientRect(),T=z?k.width:k.height;T>0&&n.measure(V.index,T)&&(w=!0)}w&&O()}function L(c,z){const w=ie(c),V=g(),k=u.get(z);k&&k!==w&&(V?.unobserve(k),l.delete(k),u.delete(z)),w&&(u.set(z,w),l.set(w,z),V?.observe(w),a.push({element:w,index:z}),!p&&(p=Y(R)))}function W(c,z="auto"){const w=f(),V=w?U(w,S()):0,k=V>0?V:n.getViewportSize(),T=G(c,n.getTotalSize(),k);n.setScrollOffset(T),w&&N(w,T,S(),z),O()}function oe(c,z){const w=n.getOffsetForIndex(c,z?.align??"auto");W(w,z?.behavior??"auto")}function ae(c,z){n.measure(c,z)&&O()}return O(),t.watch(()=>[t.toValue(e.count),t.toValue(e.overscan),t.toValue(e.gap),t.toValue(e.paddingStart),t.toValue(e.paddingEnd),t.toValue(e.lanes),t.toValue(e.horizontal),t.toValue(e.itemSize),t.toValue(e.viewportInset),t.toValue(e.revision),t.toValue(e.container),t.toValue(e.initialRect)?.width,t.toValue(e.initialRect)?.height],()=>{b(),O()},{flush:"post"}),t.onBeforeUnmount(()=>{h&&h.removeEventListener("scroll",m),y?.disconnect(),x?.disconnect(),X(v),X(p),typeof window<"u"&&window.clearTimeout(I),l.clear(),u.clear(),a.length=0}),{virtualItems:t.computed(()=>i.value),totalSize:t.computed(()=>r.value),scrollOffset:t.computed(()=>s.value),isScrolling:t.computed(()=>o.value),scrollToIndex:oe,scrollToOffset:W,measure:ae,measureElement:L}}function de(e,n,i){return typeof e=="function"?e(n,i):typeof e=="number"?e:48}function H(e){const n=A({count:()=>t.toValue(e.items).length,estimateSize:r=>{const s=t.toValue(e.items);return de(e.estimateSize,r,s[r])},getItemKey:r=>{const o=t.toValue(e.items)[r];return e.getItemKey?.(o,r)??r},itemSize:()=>e.itemSize!==void 0?t.toValue(e.itemSize):typeof e.estimateSize=="number"?e.estimateSize:void 0,container:e.container,horizontal:e.horizontal,overscan:e.overscan,gap:e.gap,paddingStart:e.paddingStart,paddingEnd:e.paddingEnd,initialRect:e.initialRect,viewportInset:e.viewportInset,revision:e.revision});return{virtualItems:t.computed(()=>{const r=t.toValue(e.items);return n.virtualItems.value.map(s=>{const o=r[s.index];return{...s,item:o,key:e.getItemKey?.(o,s.index)??s.key}})}),totalSize:n.totalSize,scrollOffset:n.scrollOffset,isScrolling:n.isScrolling,scrollToIndex:n.scrollToIndex,scrollToOffset:n.scrollToOffset,measure:n.measure,measureElement:n.measureElement}}function J(e,n,i){return typeof e=="function"?e(n):typeof e=="number"?e:i}function re(e){const n=t.computed(()=>Math.max(1,Math.floor(t.toValue(e.columnCount)||1))),i=t.computed(()=>Math.ceil(t.toValue(e.items).length/n.value)),r=new Map,s=A({count:()=>i.value,estimateSize:l=>J(t.toValue(e.estimateRowSize),l,48),itemSize:()=>{const l=t.toValue(e.estimateRowSize);return typeof l=="number"?l:void 0},overscan:()=>t.toValue(e.overscanRows)??t.toValue(e.overscan)??2,gap:()=>t.toValue(e.rowGap)??0,horizontal:!1,container:e.container,initialRect:e.initialRect,revision:e.revision}),o=A({count:()=>n.value,estimateSize:l=>J(t.toValue(e.estimateColumnSize),l,160),itemSize:()=>{const l=t.toValue(e.estimateColumnSize);return typeof l=="number"?l:void 0},overscan:()=>t.toValue(e.overscanColumns)??t.toValue(e.overscan)??1,gap:()=>t.toValue(e.columnGap)??0,horizontal:!0,container:e.container,initialRect:e.initialRect,revision:e.revision}),d=t.computed(()=>{const l=t.toValue(e.items),u=n.value,a=[];for(const f of s.virtualItems.value)for(const S of o.virtualItems.value){const C=f.index*u+S.index;if(C>=l.length)continue;const O=l[C];a.push({index:C,key:e.getItemKey?.(O,C)??C,item:O,row:f,column:S})}return a});function h(l,u){const a=t.toValue(e.items);if(!a.length)return;const f=Math.min(Math.max(l,0),a.length-1),S=n.value;s.scrollToIndex(Math.floor(f/S),u),o.scrollToIndex(f%S,u)}function y(l,u="auto"){l.top!==void 0&&s.scrollToOffset(l.top,u),l.left!==void 0&&o.scrollToOffset(l.left,u)}function x(l,u){const a=Math.max(r.get(l)??0,u);a<=0||a===r.get(l)||(r.set(l,a),s.measure(l,a))}let v=null;const p=new Map;function I(){return!F()||typeof ResizeObserver>"u"?null:(v||(v=new ResizeObserver(l=>{for(const u of l){const a=p.get(u.target);if(a===void 0)continue;const S=u.borderBoxSize?.[0]?.blockSize??u.contentRect.height;S>0&&x(a,S)}})),v)}function E(l,u){const a=ie(l),f=I();if(!a)return;p.set(a,u),f?.observe(a);const S=a.getBoundingClientRect().height;S>0&&x(u,S)}return t.onBeforeUnmount(()=>{v?.disconnect(),p.clear()}),{virtualRows:s.virtualItems,virtualColumns:o.virtualItems,virtualCells:d,totalHeight:s.totalSize,totalWidth:o.totalSize,scrollToIndex:h,scrollToOffset:y,measureRow:x,measureRowElement:E,measureColumn:o.measure}}function se(e){const n=H({items:e.rows,estimateSize:e.estimateRowSize,container:e.container,overscan:e.overscan,getItemKey:e.getRowKey,initialRect:e.initialRect,viewportInset:e.viewportInset,revision:e.revision,itemSize:e.itemSize}),i=t.computed(()=>{const o=t.toValue(e.columns);let d=0;return o.map(h=>{const y=h.width??h.minWidth??160,x={...h,start:d,size:y,end:d+y};return d+=y,x})}),r=t.computed(()=>{const o=i.value;return o.length?o[o.length-1]?.end??0:0});return{virtualRows:t.computed(()=>n.virtualItems.value),columns:i,totalHeight:n.totalSize,totalWidth:r,scrollOffset:n.scrollOffset,isScrolling:n.isScrolling,scrollToIndex:n.scrollToIndex,scrollToOffset:n.scrollToOffset,measure:n.measure,measureElement:n.measureElement}}function Q(e){if(typeof e=="number"&&Number.isFinite(e))return`${e}px`;if(typeof e=="string"&&e.trim())return e}function B(e){if(typeof e=="number"&&Number.isFinite(e))return e;if(typeof e!="string")return 0;const n=/^(-?\d+(?:\.\d+)?)px$/.exec(e.trim());if(!n?.[1])return 0;const i=Number(n[1]);return Number.isFinite(i)?i:0}function D(e){return{overflow:"auto",position:"relative",height:Q(e.height)??(e.horizontal?"100%":void 0),width:Q(e.width)??(e.horizontal?void 0:"100%"),overflowAnchor:"none"}}function fe(e,n){return{position:"relative",width:n?`${e}px`:"100%",height:n?"100%":`${e}px`}}function me(e,n){return{position:"absolute",top:0,left:0,width:n?void 0:"100%",height:n?"100%":void 0,transform:n?`translateX(${e}px)`:`translateY(${e}px)`}}const he=t.defineComponent({__name:"VirtualList",props:{items:{},estimateSize:{type:[Number,Function],default:48},height:{},width:{},horizontal:{type:Boolean,default:!1},overscan:{default:5},gap:{default:0},paddingStart:{default:0},paddingEnd:{default:0},getItemKey:{},tag:{default:"div"},itemTag:{default:"div"},itemAttrs:{},revision:{}},setup(e,{expose:n}){const i=e,r=t.ref(null),{virtualItems:s,totalSize:o,scrollToIndex:d,scrollToOffset:h,measure:y,measureElement:x}=H({items:()=>i.items,estimateSize:(l,u)=>{const a=i.estimateSize;return typeof a=="number"?a:a(l,u)},itemSize:()=>typeof i.estimateSize=="number"?i.estimateSize:void 0,container:r,horizontal:()=>i.horizontal,overscan:()=>i.overscan,gap:()=>i.gap,paddingStart:()=>i.paddingStart,paddingEnd:()=>i.paddingEnd,getItemKey:(l,u)=>i.getItemKey?.(l,u)??u,initialRect:()=>({width:B(i.width),height:B(i.height)}),revision:()=>i.revision}),v=t.computed(()=>D({height:i.height,width:i.width,horizontal:i.horizontal})),p=t.computed(()=>fe(o.value,i.horizontal));function I(l){return me(l,i.horizontal)}function E(l){return u=>{x(u,l)}}return n({scrollToIndex:d,scrollToOffset:h,measure:y}),(l,u)=>(t.openBlock(),t.createBlock(t.resolveDynamicComponent(e.tag),{ref_key:"container",ref:r,"data-virtual-container":"",role:"list",style:t.normalizeStyle(v.value)},{default:t.withCtx(()=>[e.items.length?(t.openBlock(),t.createElementBlock("div",{key:1,"data-virtual-spacer":"",style:t.normalizeStyle(p.value)},[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(t.unref(s),a=>(t.openBlock(),t.createBlock(t.resolveDynamicComponent(e.itemTag),t.mergeProps({key:a.key,ref_for:!0,ref:E(a.index),role:"listitem","data-index":a.index,"data-key":String(a.key),"aria-setsize":e.items.length,"aria-posinset":a.index+1,style:I(a.start)},{ref_for:!0},e.itemAttrs),{default:t.withCtx(()=>[t.renderSlot(l.$slots,"default",{item:a.item,index:a.index,start:a.start,size:a.size,end:a.end})]),_:2},1040,["data-index","data-key","aria-setsize","aria-posinset","style"]))),128))],4)):t.renderSlot(l.$slots,"empty",{},void 0,void 0,0)]),_:3},8,["style"]))}}),ge=["data-index","data-key"],ve=t.defineComponent({__name:"VirtualGrid",props:{items:{},columnCount:{default:1},estimateRowSize:{type:[Number,Function],default:48},estimateColumnSize:{type:[Number,Function],default:160},height:{},width:{},overscan:{default:2},overscanRows:{},overscanColumns:{},rowGap:{default:0},columnGap:{default:0},getItemKey:{},tag:{default:"div"},itemAttrs:{},revision:{}},setup(e,{expose:n}){const i=e,r=t.ref(null),{virtualCells:s,totalWidth:o,totalHeight:d,scrollToIndex:h,scrollToOffset:y,measureRow:x,measureRowElement:v}=re({items:()=>i.items,columnCount:()=>i.columnCount,estimateRowSize:()=>i.estimateRowSize,estimateColumnSize:()=>i.estimateColumnSize,container:r,overscan:()=>i.overscan,overscanRows:()=>i.overscanRows,overscanColumns:()=>i.overscanColumns,rowGap:()=>i.rowGap,columnGap:()=>i.columnGap,getItemKey:(u,a)=>i.getItemKey?.(u,a)??a,initialRect:()=>({width:B(i.width),height:B(i.height)}),revision:()=>i.revision}),p=t.computed(()=>D({height:i.height,width:i.width,horizontal:!1})),I=t.computed(()=>({position:"relative",width:`${o.value}px`,height:`${d.value}px`}));function E(u){return a=>{v(a,u)}}function l(u,a,f){return{position:"absolute",top:0,left:0,width:`${a}px`,transform:`translate(${u}px, ${f}px)`}}return n({scrollToIndex:h,scrollToOffset:y,measureRow:x}),(u,a)=>(t.openBlock(),t.createBlock(t.resolveDynamicComponent(e.tag),{ref_key:"container",ref:r,"data-virtual-container":"",role:"grid",style:t.normalizeStyle(p.value)},{default:t.withCtx(()=>[e.items.length?(t.openBlock(),t.createElementBlock("div",{key:1,"data-virtual-spacer":"",style:t.normalizeStyle(I.value)},[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(t.unref(s),f=>(t.openBlock(),t.createElementBlock("div",t.mergeProps({key:f.key,ref_for:!0,ref:E(f.row.index),role:"gridcell","data-index":f.index,"data-key":String(f.key),style:l(f.column.start,f.column.size,f.row.start)},{ref_for:!0},e.itemAttrs),[t.renderSlot(u.$slots,"default",{item:f.item,index:f.index,rowIndex:f.row.index,columnIndex:f.column.index,row:f.row,column:f.column})],16,ge))),128))],4)):t.renderSlot(u.$slots,"empty",{},void 0,void 0,0)]),_:3},8,["style"]))}}),Se=["data-index","data-key","aria-rowindex"],ze=t.defineComponent({__name:"VirtualTable",props:{rows:{},columns:{},estimateRowSize:{type:[Number,Function],default:44},height:{},width:{},overscan:{default:5},getRowKey:{},stickyHeader:{type:Boolean,default:!0},tag:{default:"div"},rowAttrs:{},revision:{}},setup(e,{expose:n}){const i=e,r=t.ref(null),s=t.ref(null),o=t.ref(0),{virtualRows:d,columns:h,totalWidth:y,totalHeight:x,scrollToIndex:v,scrollToOffset:p,measure:I,measureElement:E}=se({rows:()=>i.rows,columns:()=>i.columns,estimateRowSize:(m,b)=>{const g=i.estimateRowSize;return typeof g=="number"?g:g(m,b)},container:r,overscan:()=>i.overscan,getRowKey:(m,b)=>i.getRowKey?.(m,b)??b,initialRect:()=>({width:B(i.width),height:B(i.height)}),viewportInset:o,revision:()=>i.revision,itemSize:()=>typeof i.estimateRowSize=="number"?i.estimateRowSize:void 0});t.watch(s,(m,b,g)=>{if(b===m&&!m||!m||!F()||typeof ResizeObserver>"u")return;const R=()=>{o.value=m.getBoundingClientRect().height},L=new ResizeObserver(R);L.observe(m),R(),g(()=>L.disconnect())});const l=t.computed(()=>D({height:i.height,width:i.width,horizontal:!1})),u=t.computed(()=>({minWidth:`${y.value}px`})),a=t.computed(()=>({position:i.stickyHeader?"sticky":"relative",top:i.stickyHeader?"0px":void 0,zIndex:1,display:"flex",width:`${y.value}px`})),f=t.computed(()=>({position:"relative",height:`${x.value}px`,width:`${y.value}px`}));function S(m){return{width:`${m.size}px`,minWidth:`${m.size}px`,flex:"0 0 auto",textAlign:m.align??"left"}}function C(m){return{position:"absolute",top:0,left:0,width:"100%",display:"flex",transform:`translateY(${m}px)`}}function O(m){return b=>{E(b,m)}}function $(m,b,g){return b.accessor?b.accessor(m,g):m&&typeof m=="object"&&b.id in m?m[b.id]:""}return n({scrollToIndex:v,scrollToOffset:p,measure:I}),(m,b)=>(t.openBlock(),t.createBlock(t.resolveDynamicComponent(e.tag),{ref_key:"container",ref:r,"data-virtual-container":"",role:"table",style:t.normalizeStyle(l.value)},{default:t.withCtx(()=>[t.createElementVNode("div",{style:t.normalizeStyle(u.value)},[t.createElementVNode("div",{ref_key:"header",ref:s,role:"row",style:t.normalizeStyle(a.value)},[t.renderSlot(m.$slots,"header",{columns:t.unref(h)},()=>[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(t.unref(h),g=>(t.openBlock(),t.createElementBlock("div",{key:g.id,role:"columnheader",style:t.normalizeStyle(S(g))},t.toDisplayString(g.header),5))),128))])],4),e.rows.length?(t.openBlock(),t.createElementBlock("div",{key:1,"data-virtual-spacer":"",role:"rowgroup",style:t.normalizeStyle(f.value)},[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(t.unref(d),g=>(t.openBlock(),t.createElementBlock("div",t.mergeProps({key:g.key,ref_for:!0,ref:O(g.index),role:"row","data-index":g.index,"data-key":String(g.key),"aria-rowindex":g.index+1,style:C(g.start)},{ref_for:!0},e.rowAttrs),[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(t.unref(h),R=>(t.openBlock(),t.createElementBlock("div",{key:R.id,role:"cell",style:t.normalizeStyle(S(R))},[t.renderSlot(m.$slots,"cell",{row:g.item,column:R,rowIndex:g.index,value:$(g.item,R,g.index)},()=>[t.createTextVNode(t.toDisplayString($(g.item,R,g.index)),1)])],4))),128))],16,Se))),128))],4)):t.renderSlot(m.$slots,"empty",{},void 0,void 0,0)],4)]),_:3},8,["style"]))}});exports.MeasurementCache=Z;exports.VirtualGrid=ve;exports.VirtualList=he;exports.VirtualTable=ze;exports.Virtualizer=ne;exports.clampScrollOffset=G;exports.normalizeSize=K;exports.resolveScrollOffset=te;exports.useVirtualGrid=re;exports.useVirtualList=H;exports.useVirtualTable=se;exports.useVirtualizer=A;
|
|
2
|
+
//# sourceMappingURL=index.js.map
|