@hoci/components 0.7.1 → 0.8.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/dist/index.cjs +1345 -174
- package/dist/index.d.cts +149 -58
- package/dist/index.d.mts +149 -58
- package/dist/index.d.ts +149 -58
- package/dist/index.mjs +1347 -177
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -5,20 +5,6 @@ const vue = require('vue');
|
|
|
5
5
|
const tslx = require('tslx');
|
|
6
6
|
const core = require('@hoci/core');
|
|
7
7
|
|
|
8
|
-
var _a;
|
|
9
|
-
const isClient = typeof window !== "undefined";
|
|
10
|
-
const isString = (val) => typeof val === "string";
|
|
11
|
-
const noop = () => {
|
|
12
|
-
};
|
|
13
|
-
isClient && ((_a = window == null ? void 0 : window.navigator) == null ? void 0 : _a.userAgent) && /iP(ad|hone|od)/.test(window.navigator.userAgent);
|
|
14
|
-
|
|
15
|
-
function resolveUnref(r) {
|
|
16
|
-
return typeof r === "function" ? r() : vue.unref(r);
|
|
17
|
-
}
|
|
18
|
-
function identity(arg) {
|
|
19
|
-
return arg;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
8
|
function tryOnScopeDispose(fn) {
|
|
23
9
|
if (vue.getCurrentScope()) {
|
|
24
10
|
vue.onScopeDispose(fn);
|
|
@@ -31,119 +17,275 @@ function isDefined(v) {
|
|
|
31
17
|
return vue.unref(v) != null;
|
|
32
18
|
}
|
|
33
19
|
|
|
34
|
-
|
|
35
|
-
|
|
20
|
+
const isClient = typeof window !== "undefined" && typeof document !== "undefined";
|
|
21
|
+
typeof WorkerGlobalScope !== "undefined" && globalThis instanceof WorkerGlobalScope;
|
|
22
|
+
const notNullish = (val) => val != null;
|
|
23
|
+
const toString = Object.prototype.toString;
|
|
24
|
+
const isObject = (val) => toString.call(val) === "[object Object]";
|
|
25
|
+
const noop = () => {
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
function createFilterWrapper(filter, fn) {
|
|
29
|
+
function wrapper(...args) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
Promise.resolve(filter(() => fn.apply(this, args), { fn, thisArg: this, args })).then(resolve).catch(reject);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return wrapper;
|
|
35
|
+
}
|
|
36
|
+
const bypassFilter = (invoke) => {
|
|
37
|
+
return invoke();
|
|
38
|
+
};
|
|
39
|
+
function pausableFilter(extendFilter = bypassFilter, options = {}) {
|
|
40
|
+
const {
|
|
41
|
+
initialState = "active"
|
|
42
|
+
} = options;
|
|
43
|
+
const isActive = toRef(initialState === "active");
|
|
44
|
+
function pause() {
|
|
45
|
+
isActive.value = false;
|
|
46
|
+
}
|
|
47
|
+
function resume() {
|
|
48
|
+
isActive.value = true;
|
|
49
|
+
}
|
|
50
|
+
const eventFilter = (...args) => {
|
|
51
|
+
if (isActive.value)
|
|
52
|
+
extendFilter(...args);
|
|
53
|
+
};
|
|
54
|
+
return { isActive: vue.readonly(isActive), pause, resume, eventFilter };
|
|
55
|
+
}
|
|
56
|
+
function getLifeCycleTarget(target) {
|
|
57
|
+
return vue.getCurrentInstance();
|
|
58
|
+
}
|
|
59
|
+
function toArray(value) {
|
|
60
|
+
return Array.isArray(value) ? value : [value];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function toRef(...args) {
|
|
64
|
+
if (args.length !== 1)
|
|
65
|
+
return vue.toRef(...args);
|
|
66
|
+
const r = args[0];
|
|
67
|
+
return typeof r === "function" ? vue.readonly(vue.customRef(() => ({ get: r, set: noop }))) : vue.ref(r);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function watchWithFilter(source, cb, options = {}) {
|
|
71
|
+
const {
|
|
72
|
+
eventFilter = bypassFilter,
|
|
73
|
+
...watchOptions
|
|
74
|
+
} = options;
|
|
75
|
+
return vue.watch(
|
|
76
|
+
source,
|
|
77
|
+
createFilterWrapper(
|
|
78
|
+
eventFilter,
|
|
79
|
+
cb
|
|
80
|
+
),
|
|
81
|
+
watchOptions
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function watchPausable(source, cb, options = {}) {
|
|
86
|
+
const {
|
|
87
|
+
eventFilter: filter,
|
|
88
|
+
initialState = "active",
|
|
89
|
+
...watchOptions
|
|
90
|
+
} = options;
|
|
91
|
+
const { eventFilter, pause, resume, isActive } = pausableFilter(filter, { initialState });
|
|
92
|
+
const stop = watchWithFilter(
|
|
93
|
+
source,
|
|
94
|
+
cb,
|
|
95
|
+
{
|
|
96
|
+
...watchOptions,
|
|
97
|
+
eventFilter
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
return { stop, pause, resume, isActive };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function syncRef(left, right, ...[options]) {
|
|
36
104
|
const {
|
|
37
105
|
flush = "sync",
|
|
38
106
|
deep = false,
|
|
39
107
|
immediate = true,
|
|
40
108
|
direction = "both",
|
|
41
109
|
transform = {}
|
|
42
|
-
} = options;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
const transformRTL = (_b = transform.rtl) != null ? _b : (v) => v;
|
|
110
|
+
} = options || {};
|
|
111
|
+
const watchers = [];
|
|
112
|
+
const transformLTR = "ltr" in transform && transform.ltr || ((v) => v);
|
|
113
|
+
const transformRTL = "rtl" in transform && transform.rtl || ((v) => v);
|
|
47
114
|
if (direction === "both" || direction === "ltr") {
|
|
48
|
-
|
|
115
|
+
watchers.push(watchPausable(
|
|
116
|
+
left,
|
|
117
|
+
(newValue) => {
|
|
118
|
+
watchers.forEach((w) => w.pause());
|
|
119
|
+
right.value = transformLTR(newValue);
|
|
120
|
+
watchers.forEach((w) => w.resume());
|
|
121
|
+
},
|
|
122
|
+
{ flush, deep, immediate }
|
|
123
|
+
));
|
|
49
124
|
}
|
|
50
125
|
if (direction === "both" || direction === "rtl") {
|
|
51
|
-
|
|
126
|
+
watchers.push(watchPausable(
|
|
127
|
+
right,
|
|
128
|
+
(newValue) => {
|
|
129
|
+
watchers.forEach((w) => w.pause());
|
|
130
|
+
left.value = transformRTL(newValue);
|
|
131
|
+
watchers.forEach((w) => w.resume());
|
|
132
|
+
},
|
|
133
|
+
{ flush, deep, immediate }
|
|
134
|
+
));
|
|
52
135
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
watchRight == null ? void 0 : watchRight();
|
|
136
|
+
const stop = () => {
|
|
137
|
+
watchers.forEach((w) => w.stop());
|
|
56
138
|
};
|
|
139
|
+
return stop;
|
|
57
140
|
}
|
|
58
141
|
|
|
59
|
-
function tryOnMounted(fn, sync = true) {
|
|
60
|
-
|
|
61
|
-
|
|
142
|
+
function tryOnMounted(fn, sync = true, target) {
|
|
143
|
+
const instance = getLifeCycleTarget();
|
|
144
|
+
if (instance)
|
|
145
|
+
vue.onMounted(fn, target);
|
|
62
146
|
else if (sync)
|
|
63
147
|
fn();
|
|
64
148
|
else
|
|
65
149
|
vue.nextTick(fn);
|
|
66
150
|
}
|
|
67
151
|
|
|
152
|
+
function watchImmediate(source, cb, options) {
|
|
153
|
+
return vue.watch(
|
|
154
|
+
source,
|
|
155
|
+
cb,
|
|
156
|
+
{
|
|
157
|
+
...options,
|
|
158
|
+
immediate: true
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function watchOnce(source, cb, options) {
|
|
164
|
+
const stop = vue.watch(source, (...args) => {
|
|
165
|
+
vue.nextTick(() => stop());
|
|
166
|
+
return cb(...args);
|
|
167
|
+
}, options);
|
|
168
|
+
return stop;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const defaultWindow = isClient ? window : void 0;
|
|
172
|
+
|
|
68
173
|
function unrefElement(elRef) {
|
|
69
174
|
var _a;
|
|
70
|
-
const plain =
|
|
175
|
+
const plain = vue.toValue(elRef);
|
|
71
176
|
return (_a = plain == null ? void 0 : plain.$el) != null ? _a : plain;
|
|
72
177
|
}
|
|
73
178
|
|
|
74
|
-
const defaultWindow = isClient ? window : void 0;
|
|
75
|
-
|
|
76
179
|
function useEventListener(...args) {
|
|
77
|
-
let target;
|
|
78
|
-
let events;
|
|
79
|
-
let listeners;
|
|
80
|
-
let options;
|
|
81
|
-
if (isString(args[0]) || Array.isArray(args[0])) {
|
|
82
|
-
[events, listeners, options] = args;
|
|
83
|
-
target = defaultWindow;
|
|
84
|
-
} else {
|
|
85
|
-
[target, events, listeners, options] = args;
|
|
86
|
-
}
|
|
87
|
-
if (!target)
|
|
88
|
-
return noop;
|
|
89
|
-
if (!Array.isArray(events))
|
|
90
|
-
events = [events];
|
|
91
|
-
if (!Array.isArray(listeners))
|
|
92
|
-
listeners = [listeners];
|
|
93
180
|
const cleanups = [];
|
|
94
181
|
const cleanup = () => {
|
|
95
182
|
cleanups.forEach((fn) => fn());
|
|
96
183
|
cleanups.length = 0;
|
|
97
184
|
};
|
|
98
|
-
const register = (el, event, listener) => {
|
|
185
|
+
const register = (el, event, listener, options) => {
|
|
99
186
|
el.addEventListener(event, listener, options);
|
|
100
187
|
return () => el.removeEventListener(event, listener, options);
|
|
101
188
|
};
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
189
|
+
const firstParamTargets = vue.computed(() => {
|
|
190
|
+
const test = toArray(vue.toValue(args[0])).filter((e) => e != null);
|
|
191
|
+
return test.every((e) => typeof e !== "string") ? test : void 0;
|
|
192
|
+
});
|
|
193
|
+
const stopWatch = watchImmediate(
|
|
194
|
+
() => {
|
|
195
|
+
var _a, _b;
|
|
196
|
+
return [
|
|
197
|
+
(_b = (_a = firstParamTargets.value) == null ? void 0 : _a.map((e) => unrefElement(e))) != null ? _b : [defaultWindow].filter((e) => e != null),
|
|
198
|
+
toArray(vue.toValue(firstParamTargets.value ? args[1] : args[0])),
|
|
199
|
+
toArray(vue.unref(firstParamTargets.value ? args[2] : args[1])),
|
|
200
|
+
// @ts-expect-error - TypeScript gets the correct types, but somehow still complains
|
|
201
|
+
vue.toValue(firstParamTargets.value ? args[3] : args[2])
|
|
202
|
+
];
|
|
203
|
+
},
|
|
204
|
+
([raw_targets, raw_events, raw_listeners, raw_options]) => {
|
|
205
|
+
cleanup();
|
|
206
|
+
if (!(raw_targets == null ? void 0 : raw_targets.length) || !(raw_events == null ? void 0 : raw_events.length) || !(raw_listeners == null ? void 0 : raw_listeners.length))
|
|
207
|
+
return;
|
|
208
|
+
const optionsClone = isObject(raw_options) ? { ...raw_options } : raw_options;
|
|
209
|
+
cleanups.push(
|
|
210
|
+
...raw_targets.flatMap(
|
|
211
|
+
(el) => raw_events.flatMap(
|
|
212
|
+
(event) => raw_listeners.map((listener) => register(el, event, listener, optionsClone))
|
|
213
|
+
)
|
|
214
|
+
)
|
|
215
|
+
);
|
|
216
|
+
},
|
|
217
|
+
{ flush: "post" }
|
|
218
|
+
);
|
|
110
219
|
const stop = () => {
|
|
111
220
|
stopWatch();
|
|
112
221
|
cleanup();
|
|
113
222
|
};
|
|
114
|
-
tryOnScopeDispose(
|
|
223
|
+
tryOnScopeDispose(cleanup);
|
|
115
224
|
return stop;
|
|
116
225
|
}
|
|
117
226
|
|
|
118
|
-
function
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
227
|
+
function useMounted() {
|
|
228
|
+
const isMounted = vue.shallowRef(false);
|
|
229
|
+
const instance = vue.getCurrentInstance();
|
|
230
|
+
if (instance) {
|
|
231
|
+
vue.onMounted(() => {
|
|
232
|
+
isMounted.value = true;
|
|
233
|
+
}, instance);
|
|
234
|
+
}
|
|
235
|
+
return isMounted;
|
|
124
236
|
}
|
|
125
237
|
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
238
|
+
function useSupported(callback) {
|
|
239
|
+
const isMounted = useMounted();
|
|
240
|
+
return vue.computed(() => {
|
|
241
|
+
isMounted.value;
|
|
242
|
+
return Boolean(callback());
|
|
243
|
+
});
|
|
244
|
+
}
|
|
129
245
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (source != null && __getOwnPropSymbols$f)
|
|
139
|
-
for (var prop of __getOwnPropSymbols$f(source)) {
|
|
140
|
-
if (exclude.indexOf(prop) < 0 && __propIsEnum$f.call(source, prop))
|
|
141
|
-
target[prop] = source[prop];
|
|
246
|
+
function useMutationObserver(target, callback, options = {}) {
|
|
247
|
+
const { window = defaultWindow, ...mutationOptions } = options;
|
|
248
|
+
let observer;
|
|
249
|
+
const isSupported = useSupported(() => window && "MutationObserver" in window);
|
|
250
|
+
const cleanup = () => {
|
|
251
|
+
if (observer) {
|
|
252
|
+
observer.disconnect();
|
|
253
|
+
observer = void 0;
|
|
142
254
|
}
|
|
143
|
-
|
|
144
|
-
|
|
255
|
+
};
|
|
256
|
+
const targets = vue.computed(() => {
|
|
257
|
+
const value = vue.toValue(target);
|
|
258
|
+
const items = toArray(value).map(unrefElement).filter(notNullish);
|
|
259
|
+
return new Set(items);
|
|
260
|
+
});
|
|
261
|
+
const stopWatch = vue.watch(
|
|
262
|
+
() => targets.value,
|
|
263
|
+
(targets2) => {
|
|
264
|
+
cleanup();
|
|
265
|
+
if (isSupported.value && targets2.size) {
|
|
266
|
+
observer = new MutationObserver(callback);
|
|
267
|
+
targets2.forEach((el) => observer.observe(el, mutationOptions));
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
{ immediate: true, flush: "post" }
|
|
271
|
+
);
|
|
272
|
+
const takeRecords = () => {
|
|
273
|
+
return observer == null ? void 0 : observer.takeRecords();
|
|
274
|
+
};
|
|
275
|
+
const stop = () => {
|
|
276
|
+
stopWatch();
|
|
277
|
+
cleanup();
|
|
278
|
+
};
|
|
279
|
+
tryOnScopeDispose(stop);
|
|
280
|
+
return {
|
|
281
|
+
isSupported,
|
|
282
|
+
stop,
|
|
283
|
+
takeRecords
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
145
287
|
function useResizeObserver(target, callback, options = {}) {
|
|
146
|
-
const
|
|
288
|
+
const { window = defaultWindow, ...observerOptions } = options;
|
|
147
289
|
let observer;
|
|
148
290
|
const isSupported = useSupported(() => window && "ResizeObserver" in window);
|
|
149
291
|
const cleanup = () => {
|
|
@@ -152,13 +294,24 @@ function useResizeObserver(target, callback, options = {}) {
|
|
|
152
294
|
observer = void 0;
|
|
153
295
|
}
|
|
154
296
|
};
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
297
|
+
const targets = vue.computed(() => {
|
|
298
|
+
const _targets = vue.toValue(target);
|
|
299
|
+
return Array.isArray(_targets) ? _targets.map((el) => unrefElement(el)) : [unrefElement(_targets)];
|
|
300
|
+
});
|
|
301
|
+
const stopWatch = vue.watch(
|
|
302
|
+
targets,
|
|
303
|
+
(els) => {
|
|
304
|
+
cleanup();
|
|
305
|
+
if (isSupported.value && window) {
|
|
306
|
+
observer = new ResizeObserver(callback);
|
|
307
|
+
for (const _el of els) {
|
|
308
|
+
if (_el)
|
|
309
|
+
observer.observe(_el, observerOptions);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
{ immediate: true, flush: "post" }
|
|
314
|
+
);
|
|
162
315
|
const stop = () => {
|
|
163
316
|
cleanup();
|
|
164
317
|
stopWatch();
|
|
@@ -175,17 +328,18 @@ function useElementBounding(target, options = {}) {
|
|
|
175
328
|
reset = true,
|
|
176
329
|
windowResize = true,
|
|
177
330
|
windowScroll = true,
|
|
178
|
-
immediate = true
|
|
331
|
+
immediate = true,
|
|
332
|
+
updateTiming = "sync"
|
|
179
333
|
} = options;
|
|
180
|
-
const height = vue.
|
|
181
|
-
const bottom = vue.
|
|
182
|
-
const left = vue.
|
|
183
|
-
const right = vue.
|
|
184
|
-
const top = vue.
|
|
185
|
-
const width = vue.
|
|
186
|
-
const x = vue.
|
|
187
|
-
const y = vue.
|
|
188
|
-
function
|
|
334
|
+
const height = vue.shallowRef(0);
|
|
335
|
+
const bottom = vue.shallowRef(0);
|
|
336
|
+
const left = vue.shallowRef(0);
|
|
337
|
+
const right = vue.shallowRef(0);
|
|
338
|
+
const top = vue.shallowRef(0);
|
|
339
|
+
const width = vue.shallowRef(0);
|
|
340
|
+
const x = vue.shallowRef(0);
|
|
341
|
+
const y = vue.shallowRef(0);
|
|
342
|
+
function recalculate() {
|
|
189
343
|
const el = unrefElement(target);
|
|
190
344
|
if (!el) {
|
|
191
345
|
if (reset) {
|
|
@@ -210,8 +364,17 @@ function useElementBounding(target, options = {}) {
|
|
|
210
364
|
x.value = rect.x;
|
|
211
365
|
y.value = rect.y;
|
|
212
366
|
}
|
|
367
|
+
function update() {
|
|
368
|
+
if (updateTiming === "sync")
|
|
369
|
+
recalculate();
|
|
370
|
+
else if (updateTiming === "next-frame")
|
|
371
|
+
requestAnimationFrame(() => recalculate());
|
|
372
|
+
}
|
|
213
373
|
useResizeObserver(target, update);
|
|
214
374
|
vue.watch(() => unrefElement(target), (ele) => !ele && update());
|
|
375
|
+
useMutationObserver(target, update, {
|
|
376
|
+
attributeFilter: ["style", "class"]
|
|
377
|
+
});
|
|
215
378
|
if (windowScroll)
|
|
216
379
|
useEventListener("scroll", update, { capture: true, passive: true });
|
|
217
380
|
if (windowResize)
|
|
@@ -233,84 +396,101 @@ function useElementBounding(target, options = {}) {
|
|
|
233
396
|
};
|
|
234
397
|
}
|
|
235
398
|
|
|
236
|
-
function
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
399
|
+
function useIntersectionObserver(target, callback, options = {}) {
|
|
400
|
+
const {
|
|
401
|
+
root,
|
|
402
|
+
rootMargin = "0px",
|
|
403
|
+
threshold = 0,
|
|
404
|
+
window = defaultWindow,
|
|
405
|
+
immediate = true
|
|
406
|
+
} = options;
|
|
407
|
+
const isSupported = useSupported(() => window && "IntersectionObserver" in window);
|
|
408
|
+
const targets = vue.computed(() => {
|
|
409
|
+
const _target = vue.toValue(target);
|
|
410
|
+
return toArray(_target).map(unrefElement).filter(notNullish);
|
|
411
|
+
});
|
|
412
|
+
let cleanup = noop;
|
|
413
|
+
const isActive = vue.shallowRef(immediate);
|
|
414
|
+
const stopWatch = isSupported.value ? vue.watch(
|
|
415
|
+
() => [targets.value, unrefElement(root), isActive.value],
|
|
416
|
+
([targets2, root2]) => {
|
|
417
|
+
cleanup();
|
|
418
|
+
if (!isActive.value)
|
|
419
|
+
return;
|
|
420
|
+
if (!targets2.length)
|
|
421
|
+
return;
|
|
422
|
+
const observer = new IntersectionObserver(
|
|
423
|
+
callback,
|
|
424
|
+
{
|
|
425
|
+
root: unrefElement(root2),
|
|
426
|
+
rootMargin,
|
|
427
|
+
threshold
|
|
428
|
+
}
|
|
429
|
+
);
|
|
430
|
+
targets2.forEach((el) => el && observer.observe(el));
|
|
431
|
+
cleanup = () => {
|
|
432
|
+
observer.disconnect();
|
|
433
|
+
cleanup = noop;
|
|
434
|
+
};
|
|
435
|
+
},
|
|
436
|
+
{ immediate, flush: "post" }
|
|
437
|
+
) : noop;
|
|
438
|
+
const stop = () => {
|
|
439
|
+
cleanup();
|
|
440
|
+
stopWatch();
|
|
441
|
+
isActive.value = false;
|
|
442
|
+
};
|
|
443
|
+
tryOnScopeDispose(stop);
|
|
444
|
+
return {
|
|
445
|
+
isSupported,
|
|
446
|
+
isActive,
|
|
447
|
+
pause() {
|
|
448
|
+
cleanup();
|
|
449
|
+
isActive.value = false;
|
|
450
|
+
},
|
|
451
|
+
resume() {
|
|
452
|
+
isActive.value = true;
|
|
453
|
+
},
|
|
454
|
+
stop
|
|
249
455
|
};
|
|
250
|
-
vue.watch(() => unrefElement(element), () => testBounding(), { immediate: true, flush: "post" });
|
|
251
|
-
if (window) {
|
|
252
|
-
useEventListener(scrollTarget || window, "scroll", testBounding, {
|
|
253
|
-
capture: false,
|
|
254
|
-
passive: true
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
return elementIsVisible;
|
|
258
456
|
}
|
|
259
457
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
458
|
+
function useElementVisibility(element, options = {}) {
|
|
459
|
+
const {
|
|
460
|
+
window = defaultWindow,
|
|
461
|
+
scrollTarget,
|
|
462
|
+
threshold = 0,
|
|
463
|
+
rootMargin,
|
|
464
|
+
once = false
|
|
465
|
+
} = options;
|
|
466
|
+
const elementIsVisible = vue.shallowRef(false);
|
|
467
|
+
const { stop } = useIntersectionObserver(
|
|
468
|
+
element,
|
|
469
|
+
(intersectionObserverEntries) => {
|
|
470
|
+
let isIntersecting = elementIsVisible.value;
|
|
471
|
+
let latestTime = 0;
|
|
472
|
+
for (const entry of intersectionObserverEntries) {
|
|
473
|
+
if (entry.time >= latestTime) {
|
|
474
|
+
latestTime = entry.time;
|
|
475
|
+
isIntersecting = entry.isIntersecting;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
elementIsVisible.value = isIntersecting;
|
|
479
|
+
if (once) {
|
|
480
|
+
watchOnce(elementIsVisible, () => {
|
|
481
|
+
stop();
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
root: scrollTarget,
|
|
487
|
+
window,
|
|
488
|
+
threshold,
|
|
489
|
+
rootMargin: vue.toValue(rootMargin)
|
|
282
490
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
easeInSine: [0.12, 0, 0.39, 0],
|
|
287
|
-
easeOutSine: [0.61, 1, 0.88, 1],
|
|
288
|
-
easeInOutSine: [0.37, 0, 0.63, 1],
|
|
289
|
-
easeInQuad: [0.11, 0, 0.5, 0],
|
|
290
|
-
easeOutQuad: [0.5, 1, 0.89, 1],
|
|
291
|
-
easeInOutQuad: [0.45, 0, 0.55, 1],
|
|
292
|
-
easeInCubic: [0.32, 0, 0.67, 0],
|
|
293
|
-
easeOutCubic: [0.33, 1, 0.68, 1],
|
|
294
|
-
easeInOutCubic: [0.65, 0, 0.35, 1],
|
|
295
|
-
easeInQuart: [0.5, 0, 0.75, 0],
|
|
296
|
-
easeOutQuart: [0.25, 1, 0.5, 1],
|
|
297
|
-
easeInOutQuart: [0.76, 0, 0.24, 1],
|
|
298
|
-
easeInQuint: [0.64, 0, 0.78, 0],
|
|
299
|
-
easeOutQuint: [0.22, 1, 0.36, 1],
|
|
300
|
-
easeInOutQuint: [0.83, 0, 0.17, 1],
|
|
301
|
-
easeInExpo: [0.7, 0, 0.84, 0],
|
|
302
|
-
easeOutExpo: [0.16, 1, 0.3, 1],
|
|
303
|
-
easeInOutExpo: [0.87, 0, 0.13, 1],
|
|
304
|
-
easeInCirc: [0.55, 0, 1, 0.45],
|
|
305
|
-
easeOutCirc: [0, 0.55, 0.45, 1],
|
|
306
|
-
easeInOutCirc: [0.85, 0, 0.15, 1],
|
|
307
|
-
easeInBack: [0.36, 0, 0.66, -0.56],
|
|
308
|
-
easeOutBack: [0.34, 1.56, 0.64, 1],
|
|
309
|
-
easeInOutBack: [0.68, -0.6, 0.32, 1.6]
|
|
310
|
-
};
|
|
311
|
-
__spreadValues({
|
|
312
|
-
linear: identity
|
|
313
|
-
}, _TransitionPresets);
|
|
491
|
+
);
|
|
492
|
+
return elementIsVisible;
|
|
493
|
+
}
|
|
314
494
|
|
|
315
495
|
const affixProps = shared.defineHookProps(
|
|
316
496
|
{
|
|
@@ -1032,6 +1212,995 @@ const HiTabs = vue.defineComponent({
|
|
|
1032
1212
|
}
|
|
1033
1213
|
});
|
|
1034
1214
|
|
|
1215
|
+
function memo(getDeps, fn, opts) {
|
|
1216
|
+
let deps = opts.initialDeps ?? [];
|
|
1217
|
+
let result;
|
|
1218
|
+
function memoizedFunction() {
|
|
1219
|
+
var _a, _b, _c, _d;
|
|
1220
|
+
let depTime;
|
|
1221
|
+
if (opts.key && ((_a = opts.debug) == null ? void 0 : _a.call(opts))) depTime = Date.now();
|
|
1222
|
+
const newDeps = getDeps();
|
|
1223
|
+
const depsChanged = newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep);
|
|
1224
|
+
if (!depsChanged) {
|
|
1225
|
+
return result;
|
|
1226
|
+
}
|
|
1227
|
+
deps = newDeps;
|
|
1228
|
+
let resultTime;
|
|
1229
|
+
if (opts.key && ((_b = opts.debug) == null ? void 0 : _b.call(opts))) resultTime = Date.now();
|
|
1230
|
+
result = fn(...newDeps);
|
|
1231
|
+
if (opts.key && ((_c = opts.debug) == null ? void 0 : _c.call(opts))) {
|
|
1232
|
+
const depEndTime = Math.round((Date.now() - depTime) * 100) / 100;
|
|
1233
|
+
const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100;
|
|
1234
|
+
const resultFpsPercentage = resultEndTime / 16;
|
|
1235
|
+
const pad = (str, num) => {
|
|
1236
|
+
str = String(str);
|
|
1237
|
+
while (str.length < num) {
|
|
1238
|
+
str = " " + str;
|
|
1239
|
+
}
|
|
1240
|
+
return str;
|
|
1241
|
+
};
|
|
1242
|
+
console.info(
|
|
1243
|
+
`%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,
|
|
1244
|
+
`
|
|
1245
|
+
font-size: .6rem;
|
|
1246
|
+
font-weight: bold;
|
|
1247
|
+
color: hsl(${Math.max(
|
|
1248
|
+
0,
|
|
1249
|
+
Math.min(120 - 120 * resultFpsPercentage, 120)
|
|
1250
|
+
)}deg 100% 31%);`,
|
|
1251
|
+
opts == null ? void 0 : opts.key
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
(_d = opts == null ? void 0 : opts.onChange) == null ? void 0 : _d.call(opts, result);
|
|
1255
|
+
return result;
|
|
1256
|
+
}
|
|
1257
|
+
memoizedFunction.updateDeps = (newDeps) => {
|
|
1258
|
+
deps = newDeps;
|
|
1259
|
+
};
|
|
1260
|
+
return memoizedFunction;
|
|
1261
|
+
}
|
|
1262
|
+
function notUndefined(value, msg) {
|
|
1263
|
+
if (value === void 0) {
|
|
1264
|
+
throw new Error(`Unexpected undefined${""}`);
|
|
1265
|
+
} else {
|
|
1266
|
+
return value;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
const approxEqual = (a, b) => Math.abs(a - b) <= 1;
|
|
1270
|
+
const debounce = (targetWindow, fn, ms) => {
|
|
1271
|
+
let timeoutId;
|
|
1272
|
+
return function(...args) {
|
|
1273
|
+
targetWindow.clearTimeout(timeoutId);
|
|
1274
|
+
timeoutId = targetWindow.setTimeout(() => fn.apply(this, args), ms);
|
|
1275
|
+
};
|
|
1276
|
+
};
|
|
1277
|
+
|
|
1278
|
+
const getRect = (element) => {
|
|
1279
|
+
const { offsetWidth, offsetHeight } = element;
|
|
1280
|
+
return { width: offsetWidth, height: offsetHeight };
|
|
1281
|
+
};
|
|
1282
|
+
const defaultKeyExtractor = (index) => index;
|
|
1283
|
+
const defaultRangeExtractor = (range) => {
|
|
1284
|
+
const start = Math.max(range.startIndex - range.overscan, 0);
|
|
1285
|
+
const end = Math.min(range.endIndex + range.overscan, range.count - 1);
|
|
1286
|
+
const arr = [];
|
|
1287
|
+
for (let i = start; i <= end; i++) {
|
|
1288
|
+
arr.push(i);
|
|
1289
|
+
}
|
|
1290
|
+
return arr;
|
|
1291
|
+
};
|
|
1292
|
+
const observeElementRect = (instance, cb) => {
|
|
1293
|
+
const element = instance.scrollElement;
|
|
1294
|
+
if (!element) {
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
const targetWindow = instance.targetWindow;
|
|
1298
|
+
if (!targetWindow) {
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
const handler = (rect) => {
|
|
1302
|
+
const { width, height } = rect;
|
|
1303
|
+
cb({ width: Math.round(width), height: Math.round(height) });
|
|
1304
|
+
};
|
|
1305
|
+
handler(getRect(element));
|
|
1306
|
+
if (!targetWindow.ResizeObserver) {
|
|
1307
|
+
return () => {
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
const observer = new targetWindow.ResizeObserver((entries) => {
|
|
1311
|
+
const run = () => {
|
|
1312
|
+
const entry = entries[0];
|
|
1313
|
+
if (entry == null ? void 0 : entry.borderBoxSize) {
|
|
1314
|
+
const box = entry.borderBoxSize[0];
|
|
1315
|
+
if (box) {
|
|
1316
|
+
handler({ width: box.inlineSize, height: box.blockSize });
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
handler(getRect(element));
|
|
1321
|
+
};
|
|
1322
|
+
instance.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
|
|
1323
|
+
});
|
|
1324
|
+
observer.observe(element, { box: "border-box" });
|
|
1325
|
+
return () => {
|
|
1326
|
+
observer.unobserve(element);
|
|
1327
|
+
};
|
|
1328
|
+
};
|
|
1329
|
+
const addEventListenerOptions = {
|
|
1330
|
+
passive: true
|
|
1331
|
+
};
|
|
1332
|
+
const supportsScrollend = typeof window == "undefined" ? true : "onscrollend" in window;
|
|
1333
|
+
const observeElementOffset = (instance, cb) => {
|
|
1334
|
+
const element = instance.scrollElement;
|
|
1335
|
+
if (!element) {
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1338
|
+
const targetWindow = instance.targetWindow;
|
|
1339
|
+
if (!targetWindow) {
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
let offset = 0;
|
|
1343
|
+
const fallback = instance.options.useScrollendEvent && supportsScrollend ? () => void 0 : debounce(
|
|
1344
|
+
targetWindow,
|
|
1345
|
+
() => {
|
|
1346
|
+
cb(offset, false);
|
|
1347
|
+
},
|
|
1348
|
+
instance.options.isScrollingResetDelay
|
|
1349
|
+
);
|
|
1350
|
+
const createHandler = (isScrolling) => () => {
|
|
1351
|
+
const { horizontal, isRtl } = instance.options;
|
|
1352
|
+
offset = horizontal ? element["scrollLeft"] * (isRtl && -1 || 1) : element["scrollTop"];
|
|
1353
|
+
fallback();
|
|
1354
|
+
cb(offset, isScrolling);
|
|
1355
|
+
};
|
|
1356
|
+
const handler = createHandler(true);
|
|
1357
|
+
const endHandler = createHandler(false);
|
|
1358
|
+
endHandler();
|
|
1359
|
+
element.addEventListener("scroll", handler, addEventListenerOptions);
|
|
1360
|
+
const registerScrollendEvent = instance.options.useScrollendEvent && supportsScrollend;
|
|
1361
|
+
if (registerScrollendEvent) {
|
|
1362
|
+
element.addEventListener("scrollend", endHandler, addEventListenerOptions);
|
|
1363
|
+
}
|
|
1364
|
+
return () => {
|
|
1365
|
+
element.removeEventListener("scroll", handler);
|
|
1366
|
+
if (registerScrollendEvent) {
|
|
1367
|
+
element.removeEventListener("scrollend", endHandler);
|
|
1368
|
+
}
|
|
1369
|
+
};
|
|
1370
|
+
};
|
|
1371
|
+
const measureElement = (element, entry, instance) => {
|
|
1372
|
+
if (entry == null ? void 0 : entry.borderBoxSize) {
|
|
1373
|
+
const box = entry.borderBoxSize[0];
|
|
1374
|
+
if (box) {
|
|
1375
|
+
const size = Math.round(
|
|
1376
|
+
box[instance.options.horizontal ? "inlineSize" : "blockSize"]
|
|
1377
|
+
);
|
|
1378
|
+
return size;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
return element[instance.options.horizontal ? "offsetWidth" : "offsetHeight"];
|
|
1382
|
+
};
|
|
1383
|
+
const elementScroll = (offset, {
|
|
1384
|
+
adjustments = 0,
|
|
1385
|
+
behavior
|
|
1386
|
+
}, instance) => {
|
|
1387
|
+
var _a, _b;
|
|
1388
|
+
const toOffset = offset + adjustments;
|
|
1389
|
+
(_b = (_a = instance.scrollElement) == null ? void 0 : _a.scrollTo) == null ? void 0 : _b.call(_a, {
|
|
1390
|
+
[instance.options.horizontal ? "left" : "top"]: toOffset,
|
|
1391
|
+
behavior
|
|
1392
|
+
});
|
|
1393
|
+
};
|
|
1394
|
+
class Virtualizer {
|
|
1395
|
+
constructor(opts) {
|
|
1396
|
+
this.unsubs = [];
|
|
1397
|
+
this.scrollElement = null;
|
|
1398
|
+
this.targetWindow = null;
|
|
1399
|
+
this.isScrolling = false;
|
|
1400
|
+
this.scrollToIndexTimeoutId = null;
|
|
1401
|
+
this.measurementsCache = [];
|
|
1402
|
+
this.itemSizeCache = /* @__PURE__ */ new Map();
|
|
1403
|
+
this.pendingMeasuredCacheIndexes = [];
|
|
1404
|
+
this.scrollRect = null;
|
|
1405
|
+
this.scrollOffset = null;
|
|
1406
|
+
this.scrollDirection = null;
|
|
1407
|
+
this.scrollAdjustments = 0;
|
|
1408
|
+
this.elementsCache = /* @__PURE__ */ new Map();
|
|
1409
|
+
this.observer = /* @__PURE__ */ (() => {
|
|
1410
|
+
let _ro = null;
|
|
1411
|
+
const get = () => {
|
|
1412
|
+
if (_ro) {
|
|
1413
|
+
return _ro;
|
|
1414
|
+
}
|
|
1415
|
+
if (!this.targetWindow || !this.targetWindow.ResizeObserver) {
|
|
1416
|
+
return null;
|
|
1417
|
+
}
|
|
1418
|
+
return _ro = new this.targetWindow.ResizeObserver((entries) => {
|
|
1419
|
+
entries.forEach((entry) => {
|
|
1420
|
+
const run = () => {
|
|
1421
|
+
this._measureElement(entry.target, entry);
|
|
1422
|
+
};
|
|
1423
|
+
this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
|
|
1424
|
+
});
|
|
1425
|
+
});
|
|
1426
|
+
};
|
|
1427
|
+
return {
|
|
1428
|
+
disconnect: () => {
|
|
1429
|
+
var _a;
|
|
1430
|
+
(_a = get()) == null ? void 0 : _a.disconnect();
|
|
1431
|
+
_ro = null;
|
|
1432
|
+
},
|
|
1433
|
+
observe: (target) => {
|
|
1434
|
+
var _a;
|
|
1435
|
+
return (_a = get()) == null ? void 0 : _a.observe(target, { box: "border-box" });
|
|
1436
|
+
},
|
|
1437
|
+
unobserve: (target) => {
|
|
1438
|
+
var _a;
|
|
1439
|
+
return (_a = get()) == null ? void 0 : _a.unobserve(target);
|
|
1440
|
+
}
|
|
1441
|
+
};
|
|
1442
|
+
})();
|
|
1443
|
+
this.range = null;
|
|
1444
|
+
this.setOptions = (opts2) => {
|
|
1445
|
+
Object.entries(opts2).forEach(([key, value]) => {
|
|
1446
|
+
if (typeof value === "undefined") delete opts2[key];
|
|
1447
|
+
});
|
|
1448
|
+
this.options = {
|
|
1449
|
+
debug: false,
|
|
1450
|
+
initialOffset: 0,
|
|
1451
|
+
overscan: 1,
|
|
1452
|
+
paddingStart: 0,
|
|
1453
|
+
paddingEnd: 0,
|
|
1454
|
+
scrollPaddingStart: 0,
|
|
1455
|
+
scrollPaddingEnd: 0,
|
|
1456
|
+
horizontal: false,
|
|
1457
|
+
getItemKey: defaultKeyExtractor,
|
|
1458
|
+
rangeExtractor: defaultRangeExtractor,
|
|
1459
|
+
onChange: () => {
|
|
1460
|
+
},
|
|
1461
|
+
measureElement,
|
|
1462
|
+
initialRect: { width: 0, height: 0 },
|
|
1463
|
+
scrollMargin: 0,
|
|
1464
|
+
gap: 0,
|
|
1465
|
+
indexAttribute: "data-index",
|
|
1466
|
+
initialMeasurementsCache: [],
|
|
1467
|
+
lanes: 1,
|
|
1468
|
+
isScrollingResetDelay: 150,
|
|
1469
|
+
enabled: true,
|
|
1470
|
+
isRtl: false,
|
|
1471
|
+
useScrollendEvent: false,
|
|
1472
|
+
useAnimationFrameWithResizeObserver: false,
|
|
1473
|
+
...opts2
|
|
1474
|
+
};
|
|
1475
|
+
};
|
|
1476
|
+
this.notify = (sync) => {
|
|
1477
|
+
var _a, _b;
|
|
1478
|
+
(_b = (_a = this.options).onChange) == null ? void 0 : _b.call(_a, this, sync);
|
|
1479
|
+
};
|
|
1480
|
+
this.maybeNotify = memo(
|
|
1481
|
+
() => {
|
|
1482
|
+
this.calculateRange();
|
|
1483
|
+
return [
|
|
1484
|
+
this.isScrolling,
|
|
1485
|
+
this.range ? this.range.startIndex : null,
|
|
1486
|
+
this.range ? this.range.endIndex : null
|
|
1487
|
+
];
|
|
1488
|
+
},
|
|
1489
|
+
(isScrolling) => {
|
|
1490
|
+
this.notify(isScrolling);
|
|
1491
|
+
},
|
|
1492
|
+
{
|
|
1493
|
+
key: process.env.NODE_ENV !== "production" && "maybeNotify",
|
|
1494
|
+
debug: () => this.options.debug,
|
|
1495
|
+
initialDeps: [
|
|
1496
|
+
this.isScrolling,
|
|
1497
|
+
this.range ? this.range.startIndex : null,
|
|
1498
|
+
this.range ? this.range.endIndex : null
|
|
1499
|
+
]
|
|
1500
|
+
}
|
|
1501
|
+
);
|
|
1502
|
+
this.cleanup = () => {
|
|
1503
|
+
this.unsubs.filter(Boolean).forEach((d) => d());
|
|
1504
|
+
this.unsubs = [];
|
|
1505
|
+
this.observer.disconnect();
|
|
1506
|
+
this.scrollElement = null;
|
|
1507
|
+
this.targetWindow = null;
|
|
1508
|
+
};
|
|
1509
|
+
this._didMount = () => {
|
|
1510
|
+
return () => {
|
|
1511
|
+
this.cleanup();
|
|
1512
|
+
};
|
|
1513
|
+
};
|
|
1514
|
+
this._willUpdate = () => {
|
|
1515
|
+
var _a;
|
|
1516
|
+
const scrollElement = this.options.enabled ? this.options.getScrollElement() : null;
|
|
1517
|
+
if (this.scrollElement !== scrollElement) {
|
|
1518
|
+
this.cleanup();
|
|
1519
|
+
if (!scrollElement) {
|
|
1520
|
+
this.maybeNotify();
|
|
1521
|
+
return;
|
|
1522
|
+
}
|
|
1523
|
+
this.scrollElement = scrollElement;
|
|
1524
|
+
if (this.scrollElement && "ownerDocument" in this.scrollElement) {
|
|
1525
|
+
this.targetWindow = this.scrollElement.ownerDocument.defaultView;
|
|
1526
|
+
} else {
|
|
1527
|
+
this.targetWindow = ((_a = this.scrollElement) == null ? void 0 : _a.window) ?? null;
|
|
1528
|
+
}
|
|
1529
|
+
this.elementsCache.forEach((cached) => {
|
|
1530
|
+
this.observer.observe(cached);
|
|
1531
|
+
});
|
|
1532
|
+
this._scrollToOffset(this.getScrollOffset(), {
|
|
1533
|
+
adjustments: void 0,
|
|
1534
|
+
behavior: void 0
|
|
1535
|
+
});
|
|
1536
|
+
this.unsubs.push(
|
|
1537
|
+
this.options.observeElementRect(this, (rect) => {
|
|
1538
|
+
this.scrollRect = rect;
|
|
1539
|
+
this.maybeNotify();
|
|
1540
|
+
})
|
|
1541
|
+
);
|
|
1542
|
+
this.unsubs.push(
|
|
1543
|
+
this.options.observeElementOffset(this, (offset, isScrolling) => {
|
|
1544
|
+
this.scrollAdjustments = 0;
|
|
1545
|
+
this.scrollDirection = isScrolling ? this.getScrollOffset() < offset ? "forward" : "backward" : null;
|
|
1546
|
+
this.scrollOffset = offset;
|
|
1547
|
+
this.isScrolling = isScrolling;
|
|
1548
|
+
this.maybeNotify();
|
|
1549
|
+
})
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
1553
|
+
this.getSize = () => {
|
|
1554
|
+
if (!this.options.enabled) {
|
|
1555
|
+
this.scrollRect = null;
|
|
1556
|
+
return 0;
|
|
1557
|
+
}
|
|
1558
|
+
this.scrollRect = this.scrollRect ?? this.options.initialRect;
|
|
1559
|
+
return this.scrollRect[this.options.horizontal ? "width" : "height"];
|
|
1560
|
+
};
|
|
1561
|
+
this.getScrollOffset = () => {
|
|
1562
|
+
if (!this.options.enabled) {
|
|
1563
|
+
this.scrollOffset = null;
|
|
1564
|
+
return 0;
|
|
1565
|
+
}
|
|
1566
|
+
this.scrollOffset = this.scrollOffset ?? (typeof this.options.initialOffset === "function" ? this.options.initialOffset() : this.options.initialOffset);
|
|
1567
|
+
return this.scrollOffset;
|
|
1568
|
+
};
|
|
1569
|
+
this.getFurthestMeasurement = (measurements, index) => {
|
|
1570
|
+
const furthestMeasurementsFound = /* @__PURE__ */ new Map();
|
|
1571
|
+
const furthestMeasurements = /* @__PURE__ */ new Map();
|
|
1572
|
+
for (let m = index - 1; m >= 0; m--) {
|
|
1573
|
+
const measurement = measurements[m];
|
|
1574
|
+
if (furthestMeasurementsFound.has(measurement.lane)) {
|
|
1575
|
+
continue;
|
|
1576
|
+
}
|
|
1577
|
+
const previousFurthestMeasurement = furthestMeasurements.get(
|
|
1578
|
+
measurement.lane
|
|
1579
|
+
);
|
|
1580
|
+
if (previousFurthestMeasurement == null || measurement.end > previousFurthestMeasurement.end) {
|
|
1581
|
+
furthestMeasurements.set(measurement.lane, measurement);
|
|
1582
|
+
} else if (measurement.end < previousFurthestMeasurement.end) {
|
|
1583
|
+
furthestMeasurementsFound.set(measurement.lane, true);
|
|
1584
|
+
}
|
|
1585
|
+
if (furthestMeasurementsFound.size === this.options.lanes) {
|
|
1586
|
+
break;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
return furthestMeasurements.size === this.options.lanes ? Array.from(furthestMeasurements.values()).sort((a, b) => {
|
|
1590
|
+
if (a.end === b.end) {
|
|
1591
|
+
return a.index - b.index;
|
|
1592
|
+
}
|
|
1593
|
+
return a.end - b.end;
|
|
1594
|
+
})[0] : void 0;
|
|
1595
|
+
};
|
|
1596
|
+
this.getMeasurementOptions = memo(
|
|
1597
|
+
() => [
|
|
1598
|
+
this.options.count,
|
|
1599
|
+
this.options.paddingStart,
|
|
1600
|
+
this.options.scrollMargin,
|
|
1601
|
+
this.options.getItemKey,
|
|
1602
|
+
this.options.enabled
|
|
1603
|
+
],
|
|
1604
|
+
(count, paddingStart, scrollMargin, getItemKey, enabled) => {
|
|
1605
|
+
this.pendingMeasuredCacheIndexes = [];
|
|
1606
|
+
return {
|
|
1607
|
+
count,
|
|
1608
|
+
paddingStart,
|
|
1609
|
+
scrollMargin,
|
|
1610
|
+
getItemKey,
|
|
1611
|
+
enabled
|
|
1612
|
+
};
|
|
1613
|
+
},
|
|
1614
|
+
{
|
|
1615
|
+
key: false
|
|
1616
|
+
}
|
|
1617
|
+
);
|
|
1618
|
+
this.getMeasurements = memo(
|
|
1619
|
+
() => [this.getMeasurementOptions(), this.itemSizeCache],
|
|
1620
|
+
({ count, paddingStart, scrollMargin, getItemKey, enabled }, itemSizeCache) => {
|
|
1621
|
+
if (!enabled) {
|
|
1622
|
+
this.measurementsCache = [];
|
|
1623
|
+
this.itemSizeCache.clear();
|
|
1624
|
+
return [];
|
|
1625
|
+
}
|
|
1626
|
+
if (this.measurementsCache.length === 0) {
|
|
1627
|
+
this.measurementsCache = this.options.initialMeasurementsCache;
|
|
1628
|
+
this.measurementsCache.forEach((item) => {
|
|
1629
|
+
this.itemSizeCache.set(item.key, item.size);
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1632
|
+
const min = this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0;
|
|
1633
|
+
this.pendingMeasuredCacheIndexes = [];
|
|
1634
|
+
const measurements = this.measurementsCache.slice(0, min);
|
|
1635
|
+
for (let i = min; i < count; i++) {
|
|
1636
|
+
const key = getItemKey(i);
|
|
1637
|
+
const furthestMeasurement = this.options.lanes === 1 ? measurements[i - 1] : this.getFurthestMeasurement(measurements, i);
|
|
1638
|
+
const start = furthestMeasurement ? furthestMeasurement.end + this.options.gap : paddingStart + scrollMargin;
|
|
1639
|
+
const measuredSize = itemSizeCache.get(key);
|
|
1640
|
+
const size = typeof measuredSize === "number" ? measuredSize : this.options.estimateSize(i);
|
|
1641
|
+
const end = start + size;
|
|
1642
|
+
const lane = furthestMeasurement ? furthestMeasurement.lane : i % this.options.lanes;
|
|
1643
|
+
measurements[i] = {
|
|
1644
|
+
index: i,
|
|
1645
|
+
start,
|
|
1646
|
+
size,
|
|
1647
|
+
end,
|
|
1648
|
+
key,
|
|
1649
|
+
lane
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
this.measurementsCache = measurements;
|
|
1653
|
+
return measurements;
|
|
1654
|
+
},
|
|
1655
|
+
{
|
|
1656
|
+
key: process.env.NODE_ENV !== "production" && "getMeasurements",
|
|
1657
|
+
debug: () => this.options.debug
|
|
1658
|
+
}
|
|
1659
|
+
);
|
|
1660
|
+
this.calculateRange = memo(
|
|
1661
|
+
() => [
|
|
1662
|
+
this.getMeasurements(),
|
|
1663
|
+
this.getSize(),
|
|
1664
|
+
this.getScrollOffset(),
|
|
1665
|
+
this.options.lanes
|
|
1666
|
+
],
|
|
1667
|
+
(measurements, outerSize, scrollOffset, lanes) => {
|
|
1668
|
+
return this.range = measurements.length > 0 && outerSize > 0 ? calculateRange({
|
|
1669
|
+
measurements,
|
|
1670
|
+
outerSize,
|
|
1671
|
+
scrollOffset,
|
|
1672
|
+
lanes
|
|
1673
|
+
}) : null;
|
|
1674
|
+
},
|
|
1675
|
+
{
|
|
1676
|
+
key: process.env.NODE_ENV !== "production" && "calculateRange",
|
|
1677
|
+
debug: () => this.options.debug
|
|
1678
|
+
}
|
|
1679
|
+
);
|
|
1680
|
+
this.getVirtualIndexes = memo(
|
|
1681
|
+
() => {
|
|
1682
|
+
let startIndex = null;
|
|
1683
|
+
let endIndex = null;
|
|
1684
|
+
const range = this.calculateRange();
|
|
1685
|
+
if (range) {
|
|
1686
|
+
startIndex = range.startIndex;
|
|
1687
|
+
endIndex = range.endIndex;
|
|
1688
|
+
}
|
|
1689
|
+
this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex]);
|
|
1690
|
+
return [
|
|
1691
|
+
this.options.rangeExtractor,
|
|
1692
|
+
this.options.overscan,
|
|
1693
|
+
this.options.count,
|
|
1694
|
+
startIndex,
|
|
1695
|
+
endIndex
|
|
1696
|
+
];
|
|
1697
|
+
},
|
|
1698
|
+
(rangeExtractor, overscan, count, startIndex, endIndex) => {
|
|
1699
|
+
return startIndex === null || endIndex === null ? [] : rangeExtractor({
|
|
1700
|
+
startIndex,
|
|
1701
|
+
endIndex,
|
|
1702
|
+
overscan,
|
|
1703
|
+
count
|
|
1704
|
+
});
|
|
1705
|
+
},
|
|
1706
|
+
{
|
|
1707
|
+
key: process.env.NODE_ENV !== "production" && "getVirtualIndexes",
|
|
1708
|
+
debug: () => this.options.debug
|
|
1709
|
+
}
|
|
1710
|
+
);
|
|
1711
|
+
this.indexFromElement = (node) => {
|
|
1712
|
+
const attributeName = this.options.indexAttribute;
|
|
1713
|
+
const indexStr = node.getAttribute(attributeName);
|
|
1714
|
+
if (!indexStr) {
|
|
1715
|
+
console.warn(
|
|
1716
|
+
`Missing attribute name '${attributeName}={index}' on measured element.`
|
|
1717
|
+
);
|
|
1718
|
+
return -1;
|
|
1719
|
+
}
|
|
1720
|
+
return parseInt(indexStr, 10);
|
|
1721
|
+
};
|
|
1722
|
+
this._measureElement = (node, entry) => {
|
|
1723
|
+
const index = this.indexFromElement(node);
|
|
1724
|
+
const item = this.measurementsCache[index];
|
|
1725
|
+
if (!item) {
|
|
1726
|
+
return;
|
|
1727
|
+
}
|
|
1728
|
+
const key = item.key;
|
|
1729
|
+
const prevNode = this.elementsCache.get(key);
|
|
1730
|
+
if (prevNode !== node) {
|
|
1731
|
+
if (prevNode) {
|
|
1732
|
+
this.observer.unobserve(prevNode);
|
|
1733
|
+
}
|
|
1734
|
+
this.observer.observe(node);
|
|
1735
|
+
this.elementsCache.set(key, node);
|
|
1736
|
+
}
|
|
1737
|
+
if (node.isConnected) {
|
|
1738
|
+
this.resizeItem(index, this.options.measureElement(node, entry, this));
|
|
1739
|
+
}
|
|
1740
|
+
};
|
|
1741
|
+
this.resizeItem = (index, size) => {
|
|
1742
|
+
const item = this.measurementsCache[index];
|
|
1743
|
+
if (!item) {
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1746
|
+
const itemSize = this.itemSizeCache.get(item.key) ?? item.size;
|
|
1747
|
+
const delta = size - itemSize;
|
|
1748
|
+
if (delta !== 0) {
|
|
1749
|
+
if (this.shouldAdjustScrollPositionOnItemSizeChange !== void 0 ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this) : item.start < this.getScrollOffset() + this.scrollAdjustments) {
|
|
1750
|
+
if (process.env.NODE_ENV !== "production" && this.options.debug) {
|
|
1751
|
+
console.info("correction", delta);
|
|
1752
|
+
}
|
|
1753
|
+
this._scrollToOffset(this.getScrollOffset(), {
|
|
1754
|
+
adjustments: this.scrollAdjustments += delta,
|
|
1755
|
+
behavior: void 0
|
|
1756
|
+
});
|
|
1757
|
+
}
|
|
1758
|
+
this.pendingMeasuredCacheIndexes.push(item.index);
|
|
1759
|
+
this.itemSizeCache = new Map(this.itemSizeCache.set(item.key, size));
|
|
1760
|
+
this.notify(false);
|
|
1761
|
+
}
|
|
1762
|
+
};
|
|
1763
|
+
this.measureElement = (node) => {
|
|
1764
|
+
if (!node) {
|
|
1765
|
+
this.elementsCache.forEach((cached, key) => {
|
|
1766
|
+
if (!cached.isConnected) {
|
|
1767
|
+
this.observer.unobserve(cached);
|
|
1768
|
+
this.elementsCache.delete(key);
|
|
1769
|
+
}
|
|
1770
|
+
});
|
|
1771
|
+
return;
|
|
1772
|
+
}
|
|
1773
|
+
this._measureElement(node, void 0);
|
|
1774
|
+
};
|
|
1775
|
+
this.getVirtualItems = memo(
|
|
1776
|
+
() => [this.getVirtualIndexes(), this.getMeasurements()],
|
|
1777
|
+
(indexes, measurements) => {
|
|
1778
|
+
const virtualItems = [];
|
|
1779
|
+
for (let k = 0, len = indexes.length; k < len; k++) {
|
|
1780
|
+
const i = indexes[k];
|
|
1781
|
+
const measurement = measurements[i];
|
|
1782
|
+
virtualItems.push(measurement);
|
|
1783
|
+
}
|
|
1784
|
+
return virtualItems;
|
|
1785
|
+
},
|
|
1786
|
+
{
|
|
1787
|
+
key: process.env.NODE_ENV !== "production" && "getVirtualItems",
|
|
1788
|
+
debug: () => this.options.debug
|
|
1789
|
+
}
|
|
1790
|
+
);
|
|
1791
|
+
this.getVirtualItemForOffset = (offset) => {
|
|
1792
|
+
const measurements = this.getMeasurements();
|
|
1793
|
+
if (measurements.length === 0) {
|
|
1794
|
+
return void 0;
|
|
1795
|
+
}
|
|
1796
|
+
return notUndefined(
|
|
1797
|
+
measurements[findNearestBinarySearch(
|
|
1798
|
+
0,
|
|
1799
|
+
measurements.length - 1,
|
|
1800
|
+
(index) => notUndefined(measurements[index]).start,
|
|
1801
|
+
offset
|
|
1802
|
+
)]
|
|
1803
|
+
);
|
|
1804
|
+
};
|
|
1805
|
+
this.getOffsetForAlignment = (toOffset, align, itemSize = 0) => {
|
|
1806
|
+
const size = this.getSize();
|
|
1807
|
+
const scrollOffset = this.getScrollOffset();
|
|
1808
|
+
if (align === "auto") {
|
|
1809
|
+
align = toOffset >= scrollOffset + size ? "end" : "start";
|
|
1810
|
+
}
|
|
1811
|
+
if (align === "center") {
|
|
1812
|
+
toOffset += (itemSize - size) / 2;
|
|
1813
|
+
} else if (align === "end") {
|
|
1814
|
+
toOffset -= size;
|
|
1815
|
+
}
|
|
1816
|
+
const maxOffset = this.getTotalSize() - size;
|
|
1817
|
+
return Math.max(Math.min(maxOffset, toOffset), 0);
|
|
1818
|
+
};
|
|
1819
|
+
this.getOffsetForIndex = (index, align = "auto") => {
|
|
1820
|
+
index = Math.max(0, Math.min(index, this.options.count - 1));
|
|
1821
|
+
const item = this.measurementsCache[index];
|
|
1822
|
+
if (!item) {
|
|
1823
|
+
return void 0;
|
|
1824
|
+
}
|
|
1825
|
+
const size = this.getSize();
|
|
1826
|
+
const scrollOffset = this.getScrollOffset();
|
|
1827
|
+
if (align === "auto") {
|
|
1828
|
+
if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) {
|
|
1829
|
+
align = "end";
|
|
1830
|
+
} else if (item.start <= scrollOffset + this.options.scrollPaddingStart) {
|
|
1831
|
+
align = "start";
|
|
1832
|
+
} else {
|
|
1833
|
+
return [scrollOffset, align];
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
const toOffset = align === "end" ? item.end + this.options.scrollPaddingEnd : item.start - this.options.scrollPaddingStart;
|
|
1837
|
+
return [
|
|
1838
|
+
this.getOffsetForAlignment(toOffset, align, item.size),
|
|
1839
|
+
align
|
|
1840
|
+
];
|
|
1841
|
+
};
|
|
1842
|
+
this.isDynamicMode = () => this.elementsCache.size > 0;
|
|
1843
|
+
this.cancelScrollToIndex = () => {
|
|
1844
|
+
if (this.scrollToIndexTimeoutId !== null && this.targetWindow) {
|
|
1845
|
+
this.targetWindow.clearTimeout(this.scrollToIndexTimeoutId);
|
|
1846
|
+
this.scrollToIndexTimeoutId = null;
|
|
1847
|
+
}
|
|
1848
|
+
};
|
|
1849
|
+
this.scrollToOffset = (toOffset, { align = "start", behavior } = {}) => {
|
|
1850
|
+
this.cancelScrollToIndex();
|
|
1851
|
+
if (behavior === "smooth" && this.isDynamicMode()) {
|
|
1852
|
+
console.warn(
|
|
1853
|
+
"The `smooth` scroll behavior is not fully supported with dynamic size."
|
|
1854
|
+
);
|
|
1855
|
+
}
|
|
1856
|
+
this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {
|
|
1857
|
+
adjustments: void 0,
|
|
1858
|
+
behavior
|
|
1859
|
+
});
|
|
1860
|
+
};
|
|
1861
|
+
this.scrollToIndex = (index, { align: initialAlign = "auto", behavior } = {}) => {
|
|
1862
|
+
index = Math.max(0, Math.min(index, this.options.count - 1));
|
|
1863
|
+
this.cancelScrollToIndex();
|
|
1864
|
+
if (behavior === "smooth" && this.isDynamicMode()) {
|
|
1865
|
+
console.warn(
|
|
1866
|
+
"The `smooth` scroll behavior is not fully supported with dynamic size."
|
|
1867
|
+
);
|
|
1868
|
+
}
|
|
1869
|
+
const offsetAndAlign = this.getOffsetForIndex(index, initialAlign);
|
|
1870
|
+
if (!offsetAndAlign) return;
|
|
1871
|
+
const [offset, align] = offsetAndAlign;
|
|
1872
|
+
this._scrollToOffset(offset, { adjustments: void 0, behavior });
|
|
1873
|
+
if (behavior !== "smooth" && this.isDynamicMode() && this.targetWindow) {
|
|
1874
|
+
this.scrollToIndexTimeoutId = this.targetWindow.setTimeout(() => {
|
|
1875
|
+
this.scrollToIndexTimeoutId = null;
|
|
1876
|
+
const elementInDOM = this.elementsCache.has(
|
|
1877
|
+
this.options.getItemKey(index)
|
|
1878
|
+
);
|
|
1879
|
+
if (elementInDOM) {
|
|
1880
|
+
const [latestOffset] = notUndefined(
|
|
1881
|
+
this.getOffsetForIndex(index, align)
|
|
1882
|
+
);
|
|
1883
|
+
const currentScrollOffset = this.getScrollOffset();
|
|
1884
|
+
if (!approxEqual(latestOffset, currentScrollOffset)) {
|
|
1885
|
+
this.scrollToIndex(index, { align, behavior });
|
|
1886
|
+
}
|
|
1887
|
+
} else {
|
|
1888
|
+
this.scrollToIndex(index, { align, behavior });
|
|
1889
|
+
}
|
|
1890
|
+
});
|
|
1891
|
+
}
|
|
1892
|
+
};
|
|
1893
|
+
this.scrollBy = (delta, { behavior } = {}) => {
|
|
1894
|
+
this.cancelScrollToIndex();
|
|
1895
|
+
if (behavior === "smooth" && this.isDynamicMode()) {
|
|
1896
|
+
console.warn(
|
|
1897
|
+
"The `smooth` scroll behavior is not fully supported with dynamic size."
|
|
1898
|
+
);
|
|
1899
|
+
}
|
|
1900
|
+
this._scrollToOffset(this.getScrollOffset() + delta, {
|
|
1901
|
+
adjustments: void 0,
|
|
1902
|
+
behavior
|
|
1903
|
+
});
|
|
1904
|
+
};
|
|
1905
|
+
this.getTotalSize = () => {
|
|
1906
|
+
var _a;
|
|
1907
|
+
const measurements = this.getMeasurements();
|
|
1908
|
+
let end;
|
|
1909
|
+
if (measurements.length === 0) {
|
|
1910
|
+
end = this.options.paddingStart;
|
|
1911
|
+
} else if (this.options.lanes === 1) {
|
|
1912
|
+
end = ((_a = measurements[measurements.length - 1]) == null ? void 0 : _a.end) ?? 0;
|
|
1913
|
+
} else {
|
|
1914
|
+
const endByLane = Array(this.options.lanes).fill(null);
|
|
1915
|
+
let endIndex = measurements.length - 1;
|
|
1916
|
+
while (endIndex >= 0 && endByLane.some((val) => val === null)) {
|
|
1917
|
+
const item = measurements[endIndex];
|
|
1918
|
+
if (endByLane[item.lane] === null) {
|
|
1919
|
+
endByLane[item.lane] = item.end;
|
|
1920
|
+
}
|
|
1921
|
+
endIndex--;
|
|
1922
|
+
}
|
|
1923
|
+
end = Math.max(...endByLane.filter((val) => val !== null));
|
|
1924
|
+
}
|
|
1925
|
+
return Math.max(
|
|
1926
|
+
end - this.options.scrollMargin + this.options.paddingEnd,
|
|
1927
|
+
0
|
|
1928
|
+
);
|
|
1929
|
+
};
|
|
1930
|
+
this._scrollToOffset = (offset, {
|
|
1931
|
+
adjustments,
|
|
1932
|
+
behavior
|
|
1933
|
+
}) => {
|
|
1934
|
+
this.options.scrollToFn(offset, { behavior, adjustments }, this);
|
|
1935
|
+
};
|
|
1936
|
+
this.measure = () => {
|
|
1937
|
+
this.itemSizeCache = /* @__PURE__ */ new Map();
|
|
1938
|
+
this.notify(false);
|
|
1939
|
+
};
|
|
1940
|
+
this.setOptions(opts);
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
|
|
1944
|
+
while (low <= high) {
|
|
1945
|
+
const middle = (low + high) / 2 | 0;
|
|
1946
|
+
const currentValue = getCurrentValue(middle);
|
|
1947
|
+
if (currentValue < value) {
|
|
1948
|
+
low = middle + 1;
|
|
1949
|
+
} else if (currentValue > value) {
|
|
1950
|
+
high = middle - 1;
|
|
1951
|
+
} else {
|
|
1952
|
+
return middle;
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
if (low > 0) {
|
|
1956
|
+
return low - 1;
|
|
1957
|
+
} else {
|
|
1958
|
+
return 0;
|
|
1959
|
+
}
|
|
1960
|
+
};
|
|
1961
|
+
function calculateRange({
|
|
1962
|
+
measurements,
|
|
1963
|
+
outerSize,
|
|
1964
|
+
scrollOffset,
|
|
1965
|
+
lanes
|
|
1966
|
+
}) {
|
|
1967
|
+
const lastIndex = measurements.length - 1;
|
|
1968
|
+
const getOffset = (index) => measurements[index].start;
|
|
1969
|
+
if (measurements.length <= lanes) {
|
|
1970
|
+
return {
|
|
1971
|
+
startIndex: 0,
|
|
1972
|
+
endIndex: lastIndex
|
|
1973
|
+
};
|
|
1974
|
+
}
|
|
1975
|
+
let startIndex = findNearestBinarySearch(
|
|
1976
|
+
0,
|
|
1977
|
+
lastIndex,
|
|
1978
|
+
getOffset,
|
|
1979
|
+
scrollOffset
|
|
1980
|
+
);
|
|
1981
|
+
let endIndex = startIndex;
|
|
1982
|
+
if (lanes === 1) {
|
|
1983
|
+
while (endIndex < lastIndex && measurements[endIndex].end < scrollOffset + outerSize) {
|
|
1984
|
+
endIndex++;
|
|
1985
|
+
}
|
|
1986
|
+
} else if (lanes > 1) {
|
|
1987
|
+
const endPerLane = Array(lanes).fill(0);
|
|
1988
|
+
while (endIndex < lastIndex && endPerLane.some((pos) => pos < scrollOffset + outerSize)) {
|
|
1989
|
+
const item = measurements[endIndex];
|
|
1990
|
+
endPerLane[item.lane] = item.end;
|
|
1991
|
+
endIndex++;
|
|
1992
|
+
}
|
|
1993
|
+
const startPerLane = Array(lanes).fill(scrollOffset + outerSize);
|
|
1994
|
+
while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {
|
|
1995
|
+
const item = measurements[startIndex];
|
|
1996
|
+
startPerLane[item.lane] = item.start;
|
|
1997
|
+
startIndex--;
|
|
1998
|
+
}
|
|
1999
|
+
startIndex = Math.max(0, startIndex - startIndex % lanes);
|
|
2000
|
+
endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - endIndex % lanes));
|
|
2001
|
+
}
|
|
2002
|
+
return { startIndex, endIndex };
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
const virtualListProps = shared.defineHookProps({
|
|
2006
|
+
options: {
|
|
2007
|
+
type: Object,
|
|
2008
|
+
default: () => ({})
|
|
2009
|
+
},
|
|
2010
|
+
count: {
|
|
2011
|
+
type: Number,
|
|
2012
|
+
default: () => 0
|
|
2013
|
+
},
|
|
2014
|
+
estimateSize: {
|
|
2015
|
+
type: [Function, Number],
|
|
2016
|
+
default: () => 50
|
|
2017
|
+
},
|
|
2018
|
+
horizontal: {
|
|
2019
|
+
type: Boolean,
|
|
2020
|
+
default: () => false
|
|
2021
|
+
}
|
|
2022
|
+
});
|
|
2023
|
+
const virtualListEmits = shared.defineHookEmits({
|
|
2024
|
+
scrollEnd: () => true,
|
|
2025
|
+
scrollStart: () => true,
|
|
2026
|
+
scroll: (_) => true
|
|
2027
|
+
});
|
|
2028
|
+
const useVirtualList = shared.defineHookComponent({
|
|
2029
|
+
props: virtualListProps,
|
|
2030
|
+
emits: virtualListEmits,
|
|
2031
|
+
setup(props, context) {
|
|
2032
|
+
const { emit } = context;
|
|
2033
|
+
const scrollElementRef = shared.elementRef();
|
|
2034
|
+
const propsEstimateSize = props.estimateSize;
|
|
2035
|
+
const estimateSize = typeof propsEstimateSize === "function" ? propsEstimateSize : () => propsEstimateSize;
|
|
2036
|
+
const options = vue.computed(() => {
|
|
2037
|
+
const opts = { ...props.options || {} };
|
|
2038
|
+
return {
|
|
2039
|
+
...opts,
|
|
2040
|
+
count: props.count,
|
|
2041
|
+
estimateSize,
|
|
2042
|
+
horizontal: props.horizontal,
|
|
2043
|
+
getScrollElement: () => scrollElementRef.value,
|
|
2044
|
+
observeElementRect,
|
|
2045
|
+
observeElementOffset,
|
|
2046
|
+
scrollToFn: elementScroll
|
|
2047
|
+
};
|
|
2048
|
+
});
|
|
2049
|
+
const virtualizer = new Virtualizer(options.value);
|
|
2050
|
+
const state = vue.shallowRef(virtualizer);
|
|
2051
|
+
const virtualItems = vue.computed(() => state.value.getVirtualItems());
|
|
2052
|
+
const virtualIndexes = vue.computed(() => state.value.getVirtualIndexes());
|
|
2053
|
+
const totalSize = vue.computed(() => state.value.getTotalSize());
|
|
2054
|
+
vue.watch(
|
|
2055
|
+
virtualIndexes,
|
|
2056
|
+
(indexes) => {
|
|
2057
|
+
if (indexes.length === 0) {
|
|
2058
|
+
return;
|
|
2059
|
+
}
|
|
2060
|
+
if (indexes[indexes.length - 1] === props.count - 1) {
|
|
2061
|
+
emit("scrollEnd");
|
|
2062
|
+
} else if (indexes[0] === 0) {
|
|
2063
|
+
emit("scrollStart");
|
|
2064
|
+
}
|
|
2065
|
+
emit("scroll", indexes);
|
|
2066
|
+
},
|
|
2067
|
+
{ immediate: true }
|
|
2068
|
+
);
|
|
2069
|
+
vue.watch(
|
|
2070
|
+
options,
|
|
2071
|
+
(opts) => {
|
|
2072
|
+
virtualizer.setOptions({
|
|
2073
|
+
...opts,
|
|
2074
|
+
onChange: (instance, sync) => {
|
|
2075
|
+
opts.onChange?.(instance, sync);
|
|
2076
|
+
vue.triggerRef(state);
|
|
2077
|
+
}
|
|
2078
|
+
});
|
|
2079
|
+
virtualizer._willUpdate();
|
|
2080
|
+
vue.triggerRef(state);
|
|
2081
|
+
},
|
|
2082
|
+
{ immediate: true }
|
|
2083
|
+
);
|
|
2084
|
+
vue.watch(
|
|
2085
|
+
scrollElementRef,
|
|
2086
|
+
(el) => {
|
|
2087
|
+
if (el) {
|
|
2088
|
+
virtualizer._willUpdate();
|
|
2089
|
+
vue.triggerRef(state);
|
|
2090
|
+
}
|
|
2091
|
+
},
|
|
2092
|
+
{ immediate: true }
|
|
2093
|
+
);
|
|
2094
|
+
tryOnScopeDispose(virtualizer._didMount());
|
|
2095
|
+
const measureElement = (el) => {
|
|
2096
|
+
virtualizer.measureElement(el);
|
|
2097
|
+
};
|
|
2098
|
+
const scrollToIndex = (index, options2 = {
|
|
2099
|
+
behavior: "smooth"
|
|
2100
|
+
}) => {
|
|
2101
|
+
virtualizer.scrollToIndex(index, options2);
|
|
2102
|
+
};
|
|
2103
|
+
const scrollToStart = (options2 = {
|
|
2104
|
+
behavior: "smooth"
|
|
2105
|
+
}) => {
|
|
2106
|
+
scrollToIndex(0, options2);
|
|
2107
|
+
};
|
|
2108
|
+
const scrollToEnd = (options2 = {
|
|
2109
|
+
behavior: "smooth"
|
|
2110
|
+
}) => {
|
|
2111
|
+
scrollToIndex(props.count - 1, options2);
|
|
2112
|
+
};
|
|
2113
|
+
return {
|
|
2114
|
+
virtualizer,
|
|
2115
|
+
virtualItems,
|
|
2116
|
+
virtualIndexes,
|
|
2117
|
+
totalSize,
|
|
2118
|
+
scrollElementRef,
|
|
2119
|
+
measureElement,
|
|
2120
|
+
scrollToIndex,
|
|
2121
|
+
scrollToStart,
|
|
2122
|
+
scrollToEnd
|
|
2123
|
+
};
|
|
2124
|
+
}
|
|
2125
|
+
});
|
|
2126
|
+
|
|
2127
|
+
const HiVirtualList = vue.defineComponent({
|
|
2128
|
+
name: "HiVirtualList",
|
|
2129
|
+
inheritAttrs: true,
|
|
2130
|
+
props: {
|
|
2131
|
+
...virtualListProps,
|
|
2132
|
+
as: {
|
|
2133
|
+
type: String,
|
|
2134
|
+
default: () => "div"
|
|
2135
|
+
},
|
|
2136
|
+
wrapperAs: {
|
|
2137
|
+
type: String,
|
|
2138
|
+
default: () => "div"
|
|
2139
|
+
},
|
|
2140
|
+
wrapperStyle: {
|
|
2141
|
+
type: Object,
|
|
2142
|
+
default: () => ({})
|
|
2143
|
+
},
|
|
2144
|
+
wrapperClass: {
|
|
2145
|
+
type: shared.classPropType,
|
|
2146
|
+
default: () => ""
|
|
2147
|
+
}
|
|
2148
|
+
},
|
|
2149
|
+
emits: virtualListEmits,
|
|
2150
|
+
setup(props, context) {
|
|
2151
|
+
const { slots, expose } = context;
|
|
2152
|
+
const {
|
|
2153
|
+
totalSize,
|
|
2154
|
+
scrollElementRef,
|
|
2155
|
+
virtualItems,
|
|
2156
|
+
scrollToIndex,
|
|
2157
|
+
scrollToStart,
|
|
2158
|
+
scrollToEnd
|
|
2159
|
+
} = useVirtualList(props, context);
|
|
2160
|
+
expose({
|
|
2161
|
+
scrollToIndex,
|
|
2162
|
+
scrollToStart,
|
|
2163
|
+
scrollToEnd
|
|
2164
|
+
});
|
|
2165
|
+
const wrapperStyle = vue.computed(() => {
|
|
2166
|
+
return {
|
|
2167
|
+
position: "relative",
|
|
2168
|
+
[props.horizontal ? "width" : "height"]: `${totalSize.value}px`,
|
|
2169
|
+
...props.wrapperStyle
|
|
2170
|
+
};
|
|
2171
|
+
});
|
|
2172
|
+
return () => vue.h(
|
|
2173
|
+
props.as,
|
|
2174
|
+
{
|
|
2175
|
+
ref: scrollElementRef,
|
|
2176
|
+
style: {
|
|
2177
|
+
[props.horizontal ? "overflowX" : "overflowY"]: "auto"
|
|
2178
|
+
}
|
|
2179
|
+
},
|
|
2180
|
+
[
|
|
2181
|
+
vue.h(
|
|
2182
|
+
props.wrapperAs,
|
|
2183
|
+
{
|
|
2184
|
+
style: wrapperStyle.value,
|
|
2185
|
+
class: props.wrapperClass
|
|
2186
|
+
},
|
|
2187
|
+
tslx.each(virtualItems.value, (item) => {
|
|
2188
|
+
const slotData = {
|
|
2189
|
+
...item,
|
|
2190
|
+
style: {
|
|
2191
|
+
position: "absolute",
|
|
2192
|
+
[props.horizontal ? "left" : "top"]: `${item.start}px`,
|
|
2193
|
+
[props.horizontal ? "width" : "height"]: `${item.size}px`
|
|
2194
|
+
}
|
|
2195
|
+
};
|
|
2196
|
+
return vue.renderSlot(slots, "item", slotData);
|
|
2197
|
+
})
|
|
2198
|
+
)
|
|
2199
|
+
]
|
|
2200
|
+
);
|
|
2201
|
+
}
|
|
2202
|
+
});
|
|
2203
|
+
|
|
1035
2204
|
const components = {
|
|
1036
2205
|
__proto__: null,
|
|
1037
2206
|
HiAffix: HiAffix,
|
|
@@ -1044,7 +2213,8 @@ const components = {
|
|
|
1044
2213
|
HiSelection: HiSelection,
|
|
1045
2214
|
HiSwitch: HiSwitch,
|
|
1046
2215
|
HiTabPane: HiTabPane,
|
|
1047
|
-
HiTabs: HiTabs
|
|
2216
|
+
HiTabs: HiTabs,
|
|
2217
|
+
HiVirtualList: HiVirtualList
|
|
1048
2218
|
};
|
|
1049
2219
|
|
|
1050
2220
|
function install(app) {
|
|
@@ -1064,4 +2234,5 @@ exports.HiSelection = HiSelection;
|
|
|
1064
2234
|
exports.HiSwitch = HiSwitch;
|
|
1065
2235
|
exports.HiTabPane = HiTabPane;
|
|
1066
2236
|
exports.HiTabs = HiTabs;
|
|
2237
|
+
exports.HiVirtualList = HiVirtualList;
|
|
1067
2238
|
exports.install = install;
|