@indielayer/ui 1.8.3 → 1.9.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/docs/pages/component/menu/usage.vue +1 -0
- package/docs/pages/component/select/usage.vue +17 -5
- package/docs/pages/component/table/index.vue +7 -0
- package/docs/pages/component/table/virtual.vue +53 -0
- package/lib/components/menu/MenuItem.vue.d.ts +3 -3
- package/lib/components/menu/MenuItem.vue.js +1 -1
- package/lib/components/menu/MenuItem.vue2.js +16 -16
- package/lib/components/menu/theme/MenuItem.base.theme.js +30 -30
- package/lib/components/select/Select.vue.d.ts +36 -0
- package/lib/components/select/Select.vue.js +224 -201
- package/lib/components/select/theme/Select.base.theme.js +1 -1
- package/lib/components/table/Table.vue.d.ts +91 -4
- package/lib/components/table/Table.vue.js +214 -180
- package/lib/components/table/TableHead.vue.d.ts +10 -2
- package/lib/components/table/TableHead.vue.js +16 -13
- package/lib/components/table/TableHeader.vue.d.ts +0 -4
- package/lib/components/table/TableHeader.vue.js +9 -10
- package/lib/components/table/theme/TableHead.base.theme.js +7 -4
- package/lib/components/table/theme/TableHead.carbon.theme.js +7 -4
- package/lib/components/table/theme/TableHeader.base.theme.js +3 -3
- package/lib/components/table/theme/TableHeader.carbon.theme.js +1 -1
- package/lib/composables/index.d.ts +1 -0
- package/lib/composables/useVirtualList.d.ts +48 -0
- package/lib/composables/useVirtualList.js +123 -0
- package/lib/index.js +35 -33
- package/lib/index.umd.js +4 -4
- package/lib/node_modules/.pnpm/@vueuse_core@10.2.0_vue@3.3.9_typescript@5.2.2_/node_modules/@vueuse/core/index.js +254 -221
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
- package/src/components/menu/MenuItem.vue +1 -1
- package/src/components/menu/theme/MenuItem.base.theme.ts +8 -8
- package/src/components/select/Select.vue +56 -26
- package/src/components/select/theme/Select.base.theme.ts +1 -1
- package/src/components/table/Table.vue +152 -113
- package/src/components/table/TableHead.vue +6 -2
- package/src/components/table/TableHeader.vue +0 -1
- package/src/components/table/theme/TableHead.base.theme.ts +7 -1
- package/src/components/table/theme/TableHead.carbon.theme.ts +7 -1
- package/src/components/table/theme/TableHeader.base.theme.ts +0 -2
- package/src/components/table/theme/TableHeader.carbon.theme.ts +0 -2
- package/src/composables/index.ts +1 -0
- package/src/composables/useVirtualList.ts +286 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file useVirtualList composable adapted from https://github.com/vueuse/vueuse/blob/main/packages/core/useVirtualList/index.ts
|
|
3
|
+
*/
|
|
4
|
+
import { computed, ref, shallowRef, unref, watch } from 'vue'
|
|
5
|
+
import type { Ref, ShallowRef, StyleValue } from 'vue'
|
|
6
|
+
import type { MaybeRef } from '@vueuse/shared'
|
|
7
|
+
import { useElementSize } from '@vueuse/core'
|
|
8
|
+
|
|
9
|
+
type UseVirtualListItemSize = number | ((index: number) => number)
|
|
10
|
+
|
|
11
|
+
export type UseVirtualListOptions = {
|
|
12
|
+
/**
|
|
13
|
+
* item height, accept a pixel value or a function that returns the height
|
|
14
|
+
*
|
|
15
|
+
* @default 0
|
|
16
|
+
*/
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
itemHeight: UseVirtualListItemSize;
|
|
19
|
+
topOffset: number;
|
|
20
|
+
bottomOffset: number;
|
|
21
|
+
/**
|
|
22
|
+
* the extra buffer items outside of the view area
|
|
23
|
+
*
|
|
24
|
+
* @default 5
|
|
25
|
+
*/
|
|
26
|
+
overscan?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface UseVirtualListItem<T> {
|
|
30
|
+
data: T;
|
|
31
|
+
index: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface UseVirtualListReturn<T> {
|
|
35
|
+
list: Ref<UseVirtualListItem<T>[]>;
|
|
36
|
+
scrollTo: (index: number) => void;
|
|
37
|
+
reset: () => void;
|
|
38
|
+
|
|
39
|
+
containerProps: {
|
|
40
|
+
ref: Ref<HTMLElement | null>;
|
|
41
|
+
style: StyleValue;
|
|
42
|
+
onScroll: () => void;
|
|
43
|
+
};
|
|
44
|
+
wrapperProps: MaybeRef<{
|
|
45
|
+
style?: {
|
|
46
|
+
width: string;
|
|
47
|
+
height: string;
|
|
48
|
+
marginTop: string;
|
|
49
|
+
} | {
|
|
50
|
+
width: string;
|
|
51
|
+
height: string;
|
|
52
|
+
marginLeft: string;
|
|
53
|
+
display: string;
|
|
54
|
+
};
|
|
55
|
+
}>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function useVirtualList<T = any>(list: MaybeRef<T[]>, options: UseVirtualListOptions): UseVirtualListReturn<T> {
|
|
59
|
+
if (options.disabled) {
|
|
60
|
+
return {
|
|
61
|
+
list: computed(() => unref(list).map((data, index) => ({ data, index }))),
|
|
62
|
+
scrollTo: () => {},
|
|
63
|
+
reset: () => {},
|
|
64
|
+
containerProps: {
|
|
65
|
+
ref: ref(null),
|
|
66
|
+
style: {},
|
|
67
|
+
onScroll: () => {},
|
|
68
|
+
},
|
|
69
|
+
wrapperProps: {},
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const { containerStyle, wrapperProps, scrollTo, calculateRange, currentList, containerRef } = useVerticalVirtualList(options, list)
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
list: currentList,
|
|
77
|
+
scrollTo,
|
|
78
|
+
reset: calculateRange,
|
|
79
|
+
containerProps: {
|
|
80
|
+
ref: containerRef,
|
|
81
|
+
onScroll: () => {
|
|
82
|
+
calculateRange()
|
|
83
|
+
},
|
|
84
|
+
style: containerStyle,
|
|
85
|
+
},
|
|
86
|
+
wrapperProps,
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
type UseVirtualListContainerRef = Ref<HTMLElement | null>
|
|
91
|
+
|
|
92
|
+
interface UseVirtualElementSizes {
|
|
93
|
+
width: Ref<number>;
|
|
94
|
+
height: Ref<number>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
type UseVirtualListArray<T> = UseVirtualListItem<T>[]
|
|
98
|
+
type UseVirtualListRefArray<T> = Ref<UseVirtualListArray<T>>
|
|
99
|
+
|
|
100
|
+
type UseVirtualListSource<T> = Ref<T[]> | ShallowRef<T[]>
|
|
101
|
+
|
|
102
|
+
interface UseVirtualListState { start: number; end: number; }
|
|
103
|
+
|
|
104
|
+
type RefState = Ref<UseVirtualListState>
|
|
105
|
+
|
|
106
|
+
interface UseVirtualListResources<T> {
|
|
107
|
+
state: RefState;
|
|
108
|
+
source: UseVirtualListSource<T>;
|
|
109
|
+
currentList: UseVirtualListRefArray<T>;
|
|
110
|
+
size: UseVirtualElementSizes;
|
|
111
|
+
containerRef: UseVirtualListContainerRef;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function useVirtualListResources<T>(list: MaybeRef<T[]>): UseVirtualListResources<T> {
|
|
115
|
+
const containerRef = ref<HTMLElement | null>(null)
|
|
116
|
+
const size = useElementSize(containerRef)
|
|
117
|
+
|
|
118
|
+
const currentList: Ref<UseVirtualListItem<T>[]> = ref([])
|
|
119
|
+
const source = shallowRef(list)
|
|
120
|
+
|
|
121
|
+
const state: Ref<{ start: number; end: number; }> = ref({ start: 0, end: 10 })
|
|
122
|
+
|
|
123
|
+
return { state, source, currentList, size, containerRef }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function createGetViewCapacity<T>(state: UseVirtualListResources<T>['state'], source: UseVirtualListResources<T>['source'], itemSize: UseVirtualListItemSize) {
|
|
127
|
+
return (containerSize: number) => {
|
|
128
|
+
if (typeof itemSize === 'number')
|
|
129
|
+
return Math.ceil(containerSize / itemSize)
|
|
130
|
+
|
|
131
|
+
const { start = 0 } = state.value
|
|
132
|
+
let sum = 0
|
|
133
|
+
let capacity = 0
|
|
134
|
+
|
|
135
|
+
for (let i = start; i < source.value.length; i++) {
|
|
136
|
+
const size = itemSize(i)
|
|
137
|
+
|
|
138
|
+
sum += size
|
|
139
|
+
capacity = i
|
|
140
|
+
if (sum > containerSize)
|
|
141
|
+
break
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return capacity - start
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function createGetOffset<T>(source: UseVirtualListResources<T>['source'], itemSize: UseVirtualListItemSize) {
|
|
149
|
+
return (scrollDirection: number) => {
|
|
150
|
+
if (typeof itemSize === 'number')
|
|
151
|
+
return Math.floor(scrollDirection / itemSize) + 1
|
|
152
|
+
|
|
153
|
+
let sum = 0
|
|
154
|
+
let offset = 0
|
|
155
|
+
|
|
156
|
+
for (let i = 0; i < source.value.length; i++) {
|
|
157
|
+
const size = itemSize(i)
|
|
158
|
+
|
|
159
|
+
sum += size
|
|
160
|
+
if (sum >= scrollDirection) {
|
|
161
|
+
offset = i
|
|
162
|
+
break
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return offset + 1
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function createCalculateRange<T>(type: 'horizontal' | 'vertical', overscan: number, getOffset: ReturnType<typeof createGetOffset>, getViewCapacity: ReturnType<typeof createGetViewCapacity>, { containerRef, state, currentList, source }: UseVirtualListResources<T>) {
|
|
171
|
+
return () => {
|
|
172
|
+
const element = containerRef.value
|
|
173
|
+
|
|
174
|
+
if (element) {
|
|
175
|
+
const offset = getOffset(type === 'vertical' ? element.scrollTop : element.scrollLeft)
|
|
176
|
+
const viewCapacity = getViewCapacity(type === 'vertical' ? element.clientHeight : element.clientWidth)
|
|
177
|
+
|
|
178
|
+
const from = offset - overscan
|
|
179
|
+
const to = offset + viewCapacity + overscan
|
|
180
|
+
|
|
181
|
+
state.value = {
|
|
182
|
+
start: from < 0 ? 0 : from,
|
|
183
|
+
end: to > source.value.length
|
|
184
|
+
? source.value.length
|
|
185
|
+
: to,
|
|
186
|
+
}
|
|
187
|
+
currentList.value = source.value
|
|
188
|
+
.slice(state.value.start, state.value.end)
|
|
189
|
+
.map((ele, index) => ({
|
|
190
|
+
data: ele,
|
|
191
|
+
index: index + state.value.start,
|
|
192
|
+
}))
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function createGetDistance<T>(itemSize: UseVirtualListItemSize, source: UseVirtualListResources<T>['source']) {
|
|
198
|
+
return (index: number) => {
|
|
199
|
+
if (typeof itemSize === 'number') {
|
|
200
|
+
const size = index * itemSize
|
|
201
|
+
|
|
202
|
+
return size
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const size = source.value
|
|
206
|
+
.slice(0, index)
|
|
207
|
+
.reduce((sum, _, i) => sum + itemSize(i), 0)
|
|
208
|
+
|
|
209
|
+
return size
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function useWatchForSizes<T>(size: UseVirtualElementSizes, list: MaybeRef<T[]>, containerRef: Ref<HTMLElement | null>, calculateRange: () => void, scrollTo: (index: number) => void) {
|
|
214
|
+
watch([size.width, size.height, list, containerRef], () => {
|
|
215
|
+
calculateRange()
|
|
216
|
+
scrollTo(0)
|
|
217
|
+
})
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function createComputedTotalSize<T>(itemSize: UseVirtualListItemSize, source: UseVirtualListResources<T>['source']) {
|
|
221
|
+
return computed(() => {
|
|
222
|
+
if (typeof itemSize === 'number')
|
|
223
|
+
return source.value.length * itemSize
|
|
224
|
+
|
|
225
|
+
return source.value.reduce((sum, _, index) => sum + itemSize(index), 0)
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const scrollToDictionaryForElementScrollKey = {
|
|
230
|
+
horizontal: 'scrollLeft',
|
|
231
|
+
vertical: 'scrollTop',
|
|
232
|
+
} as const
|
|
233
|
+
|
|
234
|
+
function createScrollTo<T>(type: 'horizontal' | 'vertical', calculateRange: () => void, getDistance: ReturnType<typeof createGetDistance>, containerRef: UseVirtualListResources<T>['containerRef']) {
|
|
235
|
+
return (index: number) => {
|
|
236
|
+
if (containerRef.value) {
|
|
237
|
+
containerRef.value[scrollToDictionaryForElementScrollKey[type]] = getDistance(index)
|
|
238
|
+
calculateRange()
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function useVerticalVirtualList<T>(options: UseVirtualListOptions, list: MaybeRef<T[]>) {
|
|
244
|
+
const resources = useVirtualListResources(list)
|
|
245
|
+
|
|
246
|
+
const { state, source, currentList, size, containerRef } = resources
|
|
247
|
+
|
|
248
|
+
const containerStyle: StyleValue = { overflowY: 'auto' }
|
|
249
|
+
|
|
250
|
+
const { itemHeight, topOffset = 0, bottomOffset = 0, overscan = 5 } = options
|
|
251
|
+
|
|
252
|
+
const getViewCapacity = createGetViewCapacity(state, source, itemHeight)
|
|
253
|
+
|
|
254
|
+
const getOffset = createGetOffset(source, itemHeight)
|
|
255
|
+
|
|
256
|
+
const calculateRange = createCalculateRange('vertical', overscan, getOffset, getViewCapacity, resources)
|
|
257
|
+
|
|
258
|
+
const getDistanceTop = createGetDistance(itemHeight, source)
|
|
259
|
+
|
|
260
|
+
const offsetTop = computed(() => getDistanceTop(state.value.start))
|
|
261
|
+
|
|
262
|
+
const totalHeight = createComputedTotalSize(itemHeight, source)
|
|
263
|
+
|
|
264
|
+
const scrollTo = createScrollTo('vertical', calculateRange, getDistanceTop, containerRef)
|
|
265
|
+
|
|
266
|
+
useWatchForSizes(size, list, containerRef, calculateRange, scrollTo)
|
|
267
|
+
|
|
268
|
+
const wrapperProps = computed(() => {
|
|
269
|
+
return {
|
|
270
|
+
style: {
|
|
271
|
+
width: '100%',
|
|
272
|
+
height: `${totalHeight.value - offsetTop.value + topOffset + bottomOffset}px`,
|
|
273
|
+
marginTop: `${offsetTop.value}px`,
|
|
274
|
+
},
|
|
275
|
+
}
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
calculateRange,
|
|
280
|
+
scrollTo,
|
|
281
|
+
containerStyle,
|
|
282
|
+
wrapperProps,
|
|
283
|
+
currentList,
|
|
284
|
+
containerRef,
|
|
285
|
+
}
|
|
286
|
+
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '1.
|
|
1
|
+
export default '1.9.0'
|