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