@v-c/virtual-list 0.0.1 → 1.0.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.
Files changed (69) hide show
  1. package/dist/Filler.cjs +51 -1
  2. package/dist/Filler.js +47 -56
  3. package/dist/Item.cjs +26 -1
  4. package/dist/Item.js +23 -26
  5. package/dist/List.cjs +412 -1
  6. package/dist/List.d.ts +45 -9
  7. package/dist/List.js +407 -274
  8. package/dist/ScrollBar.cjs +259 -1
  9. package/dist/ScrollBar.d.ts +3 -97
  10. package/dist/ScrollBar.js +254 -191
  11. package/dist/_virtual/rolldown_runtime.cjs +21 -0
  12. package/dist/hooks/useDiffItem.cjs +19 -1
  13. package/dist/hooks/useDiffItem.js +16 -20
  14. package/dist/hooks/useFrameWheel.cjs +63 -1
  15. package/dist/hooks/useFrameWheel.js +60 -51
  16. package/dist/hooks/useGetSize.cjs +29 -1
  17. package/dist/hooks/useGetSize.d.ts +2 -2
  18. package/dist/hooks/useGetSize.js +27 -23
  19. package/dist/hooks/useHeights.cjs +66 -1
  20. package/dist/hooks/useHeights.d.ts +1 -1
  21. package/dist/hooks/useHeights.js +62 -41
  22. package/dist/hooks/useMobileTouchMove.cjs +82 -1
  23. package/dist/hooks/useMobileTouchMove.js +79 -43
  24. package/dist/hooks/useOriginScroll.cjs +23 -1
  25. package/dist/hooks/useOriginScroll.js +20 -16
  26. package/dist/hooks/useScrollDrag.cjs +83 -1
  27. package/dist/hooks/useScrollDrag.js +77 -48
  28. package/dist/hooks/useScrollTo.cjs +97 -0
  29. package/dist/hooks/useScrollTo.d.ts +19 -0
  30. package/dist/hooks/useScrollTo.js +94 -0
  31. package/dist/index.cjs +4 -1
  32. package/dist/index.d.ts +1 -1
  33. package/dist/index.js +3 -4
  34. package/dist/interface.cjs +0 -1
  35. package/dist/interface.d.ts +1 -1
  36. package/dist/interface.js +0 -1
  37. package/dist/utils/CacheMap.cjs +25 -1
  38. package/dist/utils/CacheMap.d.ts +1 -1
  39. package/dist/utils/CacheMap.js +23 -28
  40. package/dist/utils/isFirefox.cjs +4 -1
  41. package/dist/utils/isFirefox.js +2 -4
  42. package/dist/utils/scrollbarUtil.cjs +8 -1
  43. package/dist/utils/scrollbarUtil.js +7 -6
  44. package/package.json +19 -13
  45. package/docs/basic.vue +0 -175
  46. package/docs/height.vue +0 -48
  47. package/docs/nest.vue +0 -60
  48. package/docs/no-virtual.vue +0 -127
  49. package/docs/switch.vue +0 -101
  50. package/docs/virtual-list.stories.vue +0 -31
  51. package/src/Filler.tsx +0 -72
  52. package/src/Item.tsx +0 -34
  53. package/src/List.tsx +0 -577
  54. package/src/ScrollBar.tsx +0 -298
  55. package/src/__tests__/List.test.ts +0 -59
  56. package/src/hooks/useDiffItem.ts +0 -27
  57. package/src/hooks/useFrameWheel.ts +0 -141
  58. package/src/hooks/useGetSize.ts +0 -44
  59. package/src/hooks/useHeights.ts +0 -106
  60. package/src/hooks/useMobileTouchMove.ts +0 -131
  61. package/src/hooks/useOriginScroll.ts +0 -47
  62. package/src/hooks/useScrollDrag.ts +0 -123
  63. package/src/index.ts +0 -5
  64. package/src/interface.ts +0 -32
  65. package/src/utils/CacheMap.ts +0 -42
  66. package/src/utils/isFirefox.ts +0 -3
  67. package/src/utils/scrollbarUtil.ts +0 -10
  68. package/vite.config.ts +0 -18
  69. package/vitest.config.ts +0 -11
package/package.json CHANGED
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "name": "@v-c/virtual-list",
3
3
  "type": "module",
4
- "version": "0.0.1",
4
+ "version": "1.0.1",
5
+ "description": "Vue Virtual List Component",
6
+ "author": "",
7
+ "license": "MIT",
8
+ "keywords": [
9
+ "vue",
10
+ "virtual-list",
11
+ "vue-component"
12
+ ],
5
13
  "exports": {
6
14
  ".": {
7
15
  "types": "./dist/index.d.ts",
@@ -11,15 +19,11 @@
11
19
  "./dist/*": "./dist/*",
12
20
  "./package.json": "./package.json"
13
21
  },
14
- "description": "Vue Virtual List Component",
15
- "author": "",
16
- "license": "MIT",
17
- "keywords": [
18
- "vue",
19
- "virtual-list",
20
- "vue-component"
22
+ "main": "./dist/index.js",
23
+ "files": [
24
+ "dist",
25
+ "package.json"
21
26
  ],
22
- "main": "index.js",
23
27
  "publishConfig": {
24
28
  "access": "public"
25
29
  },
@@ -27,12 +31,14 @@
27
31
  "vue": "^3.0.0"
28
32
  },
29
33
  "dependencies": {
30
- "@v-c/resize-observer": "0.0.2",
31
- "@v-c/util": "0.0.7"
34
+ "@v-c/resize-observer": "^1.0.0",
35
+ "@v-c/util": "^1.0.2"
32
36
  },
33
37
  "scripts": {
34
38
  "build": "vite build",
35
- "test": "vitest",
36
- "prepublish": "pnpm build"
39
+ "test": "vitest run",
40
+ "prepublish": "pnpm build",
41
+ "bump": "bumpp",
42
+ "patch": "bumpp --release patch"
37
43
  }
38
44
  }
package/docs/basic.vue DELETED
@@ -1,175 +0,0 @@
1
- <script setup lang="ts">
2
- import { ref } from 'vue'
3
- import VirtualList, { type ListRef } from '../src'
4
-
5
- interface Item {
6
- id: number
7
- }
8
-
9
- const data: Item[] = []
10
- for (let i = 0; i < 1000; i += 1) {
11
- data.push({ id: i })
12
- }
13
-
14
- const listRef = ref<ListRef>()
15
-
16
- function scrollToShowBar() {
17
- listRef.value?.scrollTo(null)
18
- }
19
-
20
- function scrollTo100px() {
21
- listRef.value?.scrollTo(500)
22
- }
23
-
24
- function scrollToLarge() {
25
- listRef.value?.scrollTo({
26
- index: 99999999,
27
- align: 'top',
28
- })
29
- }
30
-
31
- function scrollTo50Top() {
32
- listRef.value?.scrollTo({
33
- index: 50,
34
- align: 'top',
35
- })
36
- }
37
-
38
- function scrollTo50Bottom() {
39
- listRef.value?.scrollTo({
40
- index: 50,
41
- align: 'bottom',
42
- })
43
- }
44
-
45
- function scrollTo50Auto() {
46
- listRef.value?.scrollTo({
47
- index: 50,
48
- align: 'auto',
49
- })
50
- }
51
-
52
- function scrollTo50TopOffset() {
53
- listRef.value?.scrollTo({
54
- index: 50,
55
- align: 'top',
56
- offset: 15,
57
- })
58
- }
59
-
60
- function scrollTo50BottomOffset() {
61
- listRef.value?.scrollTo({
62
- index: 50,
63
- align: 'bottom',
64
- offset: 15,
65
- })
66
- }
67
-
68
- function scrollToKey50() {
69
- listRef.value?.scrollTo({
70
- key: 50,
71
- align: 'auto',
72
- })
73
- }
74
-
75
- function scrollToLast() {
76
- listRef.value?.scrollTo({
77
- index: data.length - 2,
78
- align: 'top',
79
- })
80
- }
81
-
82
- function scrollToFirst() {
83
- listRef.value?.scrollTo({
84
- index: 0,
85
- align: 'bottom',
86
- })
87
- }
88
-
89
- const visible = ref(true)
90
-
91
- function onScroll(e: Event) {
92
- const target = e.currentTarget as HTMLElement
93
- console.log('scroll:', target.scrollTop)
94
- }
95
- </script>
96
-
97
- <template>
98
- <div style="height: 200vh">
99
- <h2>Basic</h2>
100
- <div style="margin-bottom: 16px">
101
- <button type="button" style="margin: 4px" @click="scrollToShowBar">
102
- Show scroll bar
103
- </button>
104
- <button type="button" style="margin: 4px" @click="scrollTo100px">
105
- Scroll To 100px
106
- </button>
107
- <button type="button" style="margin: 4px" @click="scrollToLarge">
108
- Scroll To 99999999 (top)
109
- </button>
110
- <button type="button" style="margin: 4px" @click="scrollTo50Top">
111
- Scroll To 50 (top)
112
- </button>
113
- <button type="button" style="margin: 4px" @click="scrollTo50Bottom">
114
- Scroll To 50 (bottom)
115
- </button>
116
- <button type="button" style="margin: 4px" @click="scrollTo50Auto">
117
- Scroll To 50 (auto)
118
- </button>
119
- <br>
120
- <button type="button" style="margin: 4px" @click="scrollTo50TopOffset">
121
- Scroll To 50 (top) + 15 offset
122
- </button>
123
- <button type="button" style="margin: 4px" @click="scrollTo50BottomOffset">
124
- Scroll To 50 (bottom) + 15 offset
125
- </button>
126
- <button type="button" style="margin: 4px" @click="scrollToKey50">
127
- Scroll To key 50 (auto)
128
- </button>
129
- <button type="button" style="margin: 4px" @click="scrollToLast">
130
- Scroll To Last (top)
131
- </button>
132
- <button type="button" style="margin: 4px" @click="scrollToFirst">
133
- Scroll To First (bottom)
134
- </button>
135
- <button type="button" style="margin: 4px" @click="visible = !visible">
136
- Toggle visible
137
- </button>
138
- </div>
139
-
140
- <VirtualList
141
- ref="listRef"
142
- :data="data"
143
- :height="200"
144
- :item-height="20"
145
- item-key="id"
146
- :style="{
147
- border: '1px solid red',
148
- boxSizing: 'border-box',
149
- display: visible ? '' : 'none',
150
- }"
151
- @scroll="onScroll"
152
- >
153
- <template #default="{ item }">
154
- <span
155
- :style="{
156
- height: `${30 + (item.id % 2 ? 0 : 10)}px`,
157
- lineHeight: '30px',
158
- display: 'inline-block',
159
- padding: '0 8px',
160
- }"
161
- @click="() => console.log('Click:', item.id)"
162
- >
163
- {{ item.id }}
164
- </span>
165
- </template>
166
- </VirtualList>
167
- </div>
168
- </template>
169
-
170
- <style scoped>
171
- button {
172
- padding: 4px 8px;
173
- cursor: pointer;
174
- }
175
- </style>
package/docs/height.vue DELETED
@@ -1,48 +0,0 @@
1
- <script setup lang="ts">
2
- import VirtualList from '../src'
3
-
4
- interface Item {
5
- id: number
6
- height: number
7
- }
8
-
9
- const data: Item[] = []
10
- for (let i = 0; i < 100; i += 1) {
11
- data.push({
12
- id: i,
13
- height: 30 + (i % 2 ? 70 : 0),
14
- })
15
- }
16
- </script>
17
-
18
- <template>
19
- <div>
20
- <h2>Dynamic Height</h2>
21
-
22
- <VirtualList
23
- :data="data"
24
- :height="500"
25
- :item-height="30"
26
- item-key="id"
27
- :style="{
28
- border: '1px solid red',
29
- boxSizing: 'border-box',
30
- }"
31
- >
32
- <template #default="{ item }">
33
- <span
34
- :style="{
35
- border: '1px solid gray',
36
- padding: '0 16px',
37
- height: `${item.height}px`,
38
- lineHeight: '30px',
39
- boxSizing: 'border-box',
40
- display: 'inline-block',
41
- }"
42
- >
43
- {{ item.id }}
44
- </span>
45
- </template>
46
- </VirtualList>
47
- </div>
48
- </template>
package/docs/nest.vue DELETED
@@ -1,60 +0,0 @@
1
- <script setup lang="ts">
2
- import VirtualList from '../src'
3
-
4
- interface Item {
5
- id: number
6
- }
7
-
8
- const data: Item[] = []
9
- for (let i = 0; i < 100; i += 1) {
10
- data.push({ id: i })
11
- }
12
-
13
- function onScroll(e: Event) {
14
- // console.log('scroll:', (e.currentTarget as HTMLElement).scrollTop)
15
- }
16
- </script>
17
-
18
- <template>
19
- <div>
20
- <h2>Nested List</h2>
21
- <VirtualList
22
- :data="data"
23
- :height="800"
24
- :item-height="20"
25
- item-key="id"
26
- :style="{
27
- border: '1px solid red',
28
- boxSizing: 'border-box',
29
- }"
30
- @scroll="onScroll"
31
- >
32
- <template #default="{ item }">
33
- <div :style="{ padding: '20px', background: 'yellow' }">
34
- <VirtualList
35
- :data="data"
36
- :height="200"
37
- :item-height="20"
38
- item-key="id"
39
- :style="{
40
- border: '1px solid blue',
41
- boxSizing: 'border-box',
42
- background: 'white',
43
- }"
44
- >
45
- <template #default="{ item: innerItem, index }">
46
- <div
47
- :style="{
48
- height: '20px',
49
- border: '1px solid cyan',
50
- }"
51
- >
52
- {{ item.id }}-{{ index }}
53
- </div>
54
- </template>
55
- </VirtualList>
56
- </div>
57
- </template>
58
- </VirtualList>
59
- </div>
60
- </template>
@@ -1,127 +0,0 @@
1
- <script setup lang="ts">
2
- import VirtualList from '../src'
3
-
4
- interface Item {
5
- id: number
6
- height: number
7
- }
8
-
9
- const data: Item[] = []
10
- for (let i = 0; i < 100; i += 1) {
11
- data.push({
12
- id: i,
13
- height: 30 + (i % 2 ? 20 : 0),
14
- })
15
- }
16
- </script>
17
-
18
- <template>
19
- <div>
20
- <h2>Not Data</h2>
21
- <VirtualList
22
- :data="null"
23
- :item-height="30"
24
- :height="100"
25
- item-key="id"
26
- :style="{
27
- border: '1px solid red',
28
- boxSizing: 'border-box',
29
- }"
30
- >
31
- <template #default="{ item }">
32
- <span
33
- :style="{
34
- border: '1px solid gray',
35
- padding: '0 16px',
36
- height: `${item.height}px`,
37
- lineHeight: '30px',
38
- boxSizing: 'border-box',
39
- display: 'inline-block',
40
- }"
41
- >
42
- {{ item.id }}
43
- </span>
44
- </template>
45
- </VirtualList>
46
-
47
- <h2>Less Count</h2>
48
- <VirtualList
49
- :data="data.slice(0, 1)"
50
- :item-height="30"
51
- :height="100"
52
- item-key="id"
53
- :style="{
54
- border: '1px solid red',
55
- boxSizing: 'border-box',
56
- }"
57
- >
58
- <template #default="{ item }">
59
- <span
60
- :style="{
61
- border: '1px solid gray',
62
- padding: '0 16px',
63
- height: `${item.height}px`,
64
- lineHeight: '30px',
65
- boxSizing: 'border-box',
66
- display: 'inline-block',
67
- }"
68
- >
69
- {{ item.id }}
70
- </span>
71
- </template>
72
- </VirtualList>
73
-
74
- <h2>Less Item Height</h2>
75
- <VirtualList
76
- :data="data.slice(0, 10)"
77
- :item-height="1"
78
- :height="100"
79
- item-key="id"
80
- :style="{
81
- border: '1px solid red',
82
- boxSizing: 'border-box',
83
- }"
84
- >
85
- <template #default="{ item }">
86
- <span
87
- :style="{
88
- border: '1px solid gray',
89
- padding: '0 16px',
90
- height: `${item.height}px`,
91
- lineHeight: '30px',
92
- boxSizing: 'border-box',
93
- display: 'inline-block',
94
- }"
95
- >
96
- {{ item.id }}
97
- </span>
98
- </template>
99
- </VirtualList>
100
-
101
- <h2>Without Height</h2>
102
- <VirtualList
103
- :data="data"
104
- :item-height="30"
105
- item-key="id"
106
- :style="{
107
- border: '1px solid red',
108
- boxSizing: 'border-box',
109
- }"
110
- >
111
- <template #default="{ item }">
112
- <span
113
- :style="{
114
- border: '1px solid gray',
115
- padding: '0 16px',
116
- height: `${item.height}px`,
117
- lineHeight: '30px',
118
- boxSizing: 'border-box',
119
- display: 'inline-block',
120
- }"
121
- >
122
- {{ item.id }}
123
- </span>
124
- </template>
125
- </VirtualList>
126
- </div>
127
- </template>
package/docs/switch.vue DELETED
@@ -1,101 +0,0 @@
1
- <script setup lang="ts">
2
- import { ref } from 'vue'
3
- import VirtualList, { type ListRef } from '../src'
4
-
5
- interface Item {
6
- id: number
7
- }
8
-
9
- function getData(count: number): Item[] {
10
- const result: Item[] = []
11
- for (let i = 0; i < count; i += 1) {
12
- result.push({ id: i })
13
- }
14
- return result
15
- }
16
-
17
- const height = ref(200)
18
- const data = ref(getData(20))
19
- const fullHeight = ref(true)
20
- const listRef = ref<ListRef>()
21
-
22
- function setDataCount(count: number) {
23
- data.value = getData(count)
24
- }
25
-
26
- function showScrollbar() {
27
- listRef.value?.scrollTo(null)
28
- }
29
- </script>
30
-
31
- <template>
32
- <div style="height: 150vh">
33
- <h2>Switch</h2>
34
- <div style="margin-bottom: 16px">
35
- <span>
36
- Data:
37
- <label><input type="radio" name="data" value="0" @change="() => setDataCount(0)"> 0</label>
38
- <label><input type="radio" name="data" value="2" @change="() => setDataCount(2)"> 2</label>
39
- <label><input type="radio" name="data" value="20" checked @change="() => setDataCount(20)"> 20</label>
40
- <label><input type="radio" name="data" value="100" @change="() => setDataCount(100)"> 100</label>
41
- <label><input type="radio" name="data" value="200" @change="() => setDataCount(200)"> 200</label>
42
- <label><input type="radio" name="data" value="1000" @change="() => setDataCount(1000)"> 1000</label>
43
- <button type="button" @click="showScrollbar">
44
- Show scrollbar
45
- </button>
46
- </span>
47
- <br>
48
- <span>
49
- Height:
50
- <label><input type="radio" name="height" value="0" @change="() => height = 0"> 0</label>
51
- <label><input type="radio" name="height" value="100" @change="() => height = 100"> 100</label>
52
- <label><input type="radio" name="height" value="200" checked @change="() => height = 200"> 200</label>
53
- </span>
54
- <span style="margin-left: 16px">
55
- <button @click="fullHeight = !fullHeight">
56
- Full Height: {{ fullHeight }}
57
- </button>
58
- </span>
59
- </div>
60
-
61
- <VirtualList
62
- ref="listRef"
63
- :data="data"
64
- :height="height"
65
- :item-height="10"
66
- item-key="id"
67
- :full-height="fullHeight"
68
- :style="{
69
- border: '1px solid red',
70
- boxSizing: 'border-box',
71
- }"
72
- >
73
- <template #default="{ item }">
74
- <span
75
- :style="{
76
- border: '1px solid gray',
77
- padding: '0 16px',
78
- height: '30px',
79
- lineHeight: '30px',
80
- boxSizing: 'border-box',
81
- display: 'inline-block',
82
- }"
83
- >
84
- {{ item.id }}
85
- </span>
86
- </template>
87
- </VirtualList>
88
- </div>
89
- </template>
90
-
91
- <style scoped>
92
- label {
93
- margin-left: 8px;
94
- }
95
-
96
- button {
97
- margin-left: 8px;
98
- padding: 4px 8px;
99
- cursor: pointer;
100
- }
101
- </style>
@@ -1,31 +0,0 @@
1
- <script setup lang="ts">
2
- import Basic from './basic.vue'
3
- import Height from './height.vue'
4
- import Nest from './nest.vue'
5
- import NoVirtual from './no-virtual.vue'
6
- import Switch from './switch.vue'
7
- </script>
8
-
9
- <template>
10
- <Story title="Virtual List">
11
- <Variant title="Basic">
12
- <Basic />
13
- </Variant>
14
-
15
- <Variant title="Dynamic Height">
16
- <Height />
17
- </Variant>
18
-
19
- <Variant title="No Virtual">
20
- <NoVirtual />
21
- </Variant>
22
-
23
- <Variant title="Switch Data">
24
- <Switch />
25
- </Variant>
26
-
27
- <Variant title="Nested">
28
- <Nest />
29
- </Variant>
30
- </Story>
31
- </template>
package/src/Filler.tsx DELETED
@@ -1,72 +0,0 @@
1
- import ResizeObserver from '@v-c/resize-observer'
2
- import { type CSSProperties, defineComponent, type PropType, type VNode } from 'vue'
3
-
4
- export interface InnerProps {
5
- role?: string
6
- id?: string
7
- }
8
-
9
- export default defineComponent({
10
- name: 'Filler',
11
- props: {
12
- prefixCls: String,
13
- /** Virtual filler height. Should be `count * itemMinHeight` */
14
- height: Number,
15
- /** Set offset of visible items. Should be the top of start item position */
16
- offsetY: Number,
17
- offsetX: Number,
18
- scrollWidth: Number,
19
- onInnerResize: Function as PropType<() => void>,
20
- innerProps: Object as PropType<InnerProps>,
21
- rtl: Boolean,
22
- extra: Object as PropType<VNode>,
23
- },
24
- setup(props, { slots }) {
25
- return () => {
26
- let outerStyle: CSSProperties = {}
27
- let innerStyle: CSSProperties = {
28
- display: 'flex',
29
- flexDirection: 'column',
30
- }
31
-
32
- if (props.offsetY !== undefined) {
33
- outerStyle = {
34
- height: `${props.height}px`,
35
- position: 'relative',
36
- overflow: 'hidden',
37
- }
38
-
39
- innerStyle = {
40
- ...innerStyle,
41
- transform: `translateY(${props.offsetY}px)`,
42
- [props.rtl ? 'marginRight' : 'marginLeft']: `-${props.offsetX || 0}px`,
43
- position: 'absolute',
44
- left: 0,
45
- right: 0,
46
- top: 0,
47
- }
48
- }
49
-
50
- return (
51
- <div style={outerStyle}>
52
- <ResizeObserver
53
- onResize={({ offsetHeight }) => {
54
- if (offsetHeight && props.onInnerResize) {
55
- props.onInnerResize()
56
- }
57
- }}
58
- >
59
- <div
60
- style={innerStyle}
61
- class={props.prefixCls ? `${props.prefixCls}-holder-inner` : undefined}
62
- {...props.innerProps}
63
- >
64
- {slots.default?.()}
65
- {props.extra}
66
- </div>
67
- </ResizeObserver>
68
- </div>
69
- )
70
- }
71
- },
72
- })
package/src/Item.tsx DELETED
@@ -1,34 +0,0 @@
1
- import { filterEmpty } from '@v-c/util/dist/props-util'
2
- import { cloneVNode, defineComponent, type PropType, shallowRef } from 'vue'
3
-
4
- export interface ItemProps {
5
- setRef: (element: HTMLElement | null) => void
6
- }
7
-
8
- export default defineComponent({
9
- name: 'Item',
10
- props: {
11
- setRef: {
12
- type: Function as PropType<(element: HTMLElement | null) => void>,
13
- required: true,
14
- },
15
- },
16
- setup(props, { slots }) {
17
- // Store the ref callback to avoid recreating it on each render
18
- const currentElement = shallowRef<HTMLElement | null>(null)
19
- const refFunc = (node: any) => {
20
- if (currentElement.value !== node) {
21
- currentElement.value = node
22
- props.setRef(node)
23
- }
24
- }
25
-
26
- return () => {
27
- const child = filterEmpty(slots.default?.() ?? [])[0]
28
- if (!child)
29
- return null
30
-
31
- return cloneVNode(child, { ref: refFunc })
32
- }
33
- },
34
- })