@hoci/core 0.7.0 → 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,23 +1,8 @@
1
- import { defineHookProps, defineHookEmits, defineHookComponent, elementRef, toReactive, useElement, throttleByRaf, isWindow, useSharedConfig, valuePropType, labelPropType, classPropType, getFirstChilld } from '@hoci/shared';
1
+ import { defineHookProps, defineHookEmits, defineHookComponent, elementRef, toReactive, useElement, throttleByRaf, isWindow, toArray as toArray$1, useSharedConfig, valuePropType, labelPropType, classPropType, getFirstChilld } from '@hoci/shared';
2
2
  export * from '@hoci/shared';
3
- import { getCurrentInstance, onMounted, nextTick, getCurrentScope, onScopeDispose, unref, watch, ref, computed, inject, watchPostEffect, provide, reactive, renderSlot } from 'vue';
3
+ import { onMounted, nextTick, watch, getCurrentScope, onScopeDispose, getCurrentInstance, unref, readonly, toRef as toRef$1, ref, customRef, shallowRef, toValue, computed, inject, watchPostEffect, provide, reactive, renderSlot, triggerRef } from 'vue';
4
4
  import { px, createUnitFormat, cls } from 'tslx';
5
-
6
- var _a;
7
- const isClient = typeof window !== "undefined";
8
- const isDef = (val) => typeof val !== "undefined";
9
- const isFunction = (val) => typeof val === "function";
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() : unref(r);
17
- }
18
- function identity(arg) {
19
- return arg;
20
- }
5
+ import { elementScroll, observeElementOffset, observeElementRect, Virtualizer } from '@tanstack/virtual-core';
21
6
 
22
7
  function tryOnScopeDispose(fn) {
23
8
  if (getCurrentScope()) {
@@ -31,98 +16,234 @@ function isDefined(v) {
31
16
  return unref(v) != null;
32
17
  }
33
18
 
34
- function syncRef(left, right, options = {}) {
19
+ const isClient = typeof window !== "undefined" && typeof document !== "undefined";
20
+ typeof WorkerGlobalScope !== "undefined" && globalThis instanceof WorkerGlobalScope;
21
+ const isDef = (val) => typeof val !== "undefined";
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
+ const isIOS = /* @__PURE__ */ getIsIOS();
28
+ function getIsIOS() {
35
29
  var _a, _b;
30
+ return isClient && ((_a = window == null ? void 0 : window.navigator) == null ? void 0 : _a.userAgent) && (/iP(?:ad|hone|od)/.test(window.navigator.userAgent) || ((_b = window == null ? void 0 : window.navigator) == null ? void 0 : _b.maxTouchPoints) > 2 && /iPad|Macintosh/.test(window == null ? void 0 : window.navigator.userAgent));
31
+ }
32
+
33
+ function createFilterWrapper(filter, fn) {
34
+ function wrapper(...args) {
35
+ return new Promise((resolve, reject) => {
36
+ Promise.resolve(filter(() => fn.apply(this, args), { fn, thisArg: this, args })).then(resolve).catch(reject);
37
+ });
38
+ }
39
+ return wrapper;
40
+ }
41
+ const bypassFilter = (invoke) => {
42
+ return invoke();
43
+ };
44
+ function pausableFilter(extendFilter = bypassFilter, options = {}) {
45
+ const {
46
+ initialState = "active"
47
+ } = options;
48
+ const isActive = toRef(initialState === "active");
49
+ function pause() {
50
+ isActive.value = false;
51
+ }
52
+ function resume() {
53
+ isActive.value = true;
54
+ }
55
+ const eventFilter = (...args) => {
56
+ if (isActive.value)
57
+ extendFilter(...args);
58
+ };
59
+ return { isActive: readonly(isActive), pause, resume, eventFilter };
60
+ }
61
+ function getLifeCycleTarget(target) {
62
+ return getCurrentInstance();
63
+ }
64
+ function toArray(value) {
65
+ return Array.isArray(value) ? value : [value];
66
+ }
67
+
68
+ function toRef(...args) {
69
+ if (args.length !== 1)
70
+ return toRef$1(...args);
71
+ const r = args[0];
72
+ return typeof r === "function" ? readonly(customRef(() => ({ get: r, set: noop }))) : ref(r);
73
+ }
74
+
75
+ function watchWithFilter(source, cb, options = {}) {
76
+ const {
77
+ eventFilter = bypassFilter,
78
+ ...watchOptions
79
+ } = options;
80
+ return watch(
81
+ source,
82
+ createFilterWrapper(
83
+ eventFilter,
84
+ cb
85
+ ),
86
+ watchOptions
87
+ );
88
+ }
89
+
90
+ function watchPausable(source, cb, options = {}) {
91
+ const {
92
+ eventFilter: filter,
93
+ initialState = "active",
94
+ ...watchOptions
95
+ } = options;
96
+ const { eventFilter, pause, resume, isActive } = pausableFilter(filter, { initialState });
97
+ const stop = watchWithFilter(
98
+ source,
99
+ cb,
100
+ {
101
+ ...watchOptions,
102
+ eventFilter
103
+ }
104
+ );
105
+ return { stop, pause, resume, isActive };
106
+ }
107
+
108
+ function syncRef(left, right, ...[options]) {
36
109
  const {
37
110
  flush = "sync",
38
111
  deep = false,
39
112
  immediate = true,
40
113
  direction = "both",
41
114
  transform = {}
42
- } = options;
43
- let watchLeft;
44
- let watchRight;
45
- const transformLTR = (_a = transform.ltr) != null ? _a : (v) => v;
46
- const transformRTL = (_b = transform.rtl) != null ? _b : (v) => v;
115
+ } = options || {};
116
+ const watchers = [];
117
+ const transformLTR = "ltr" in transform && transform.ltr || ((v) => v);
118
+ const transformRTL = "rtl" in transform && transform.rtl || ((v) => v);
47
119
  if (direction === "both" || direction === "ltr") {
48
- watchLeft = watch(left, (newValue) => right.value = transformLTR(newValue), { flush, deep, immediate });
120
+ watchers.push(watchPausable(
121
+ left,
122
+ (newValue) => {
123
+ watchers.forEach((w) => w.pause());
124
+ right.value = transformLTR(newValue);
125
+ watchers.forEach((w) => w.resume());
126
+ },
127
+ { flush, deep, immediate }
128
+ ));
49
129
  }
50
130
  if (direction === "both" || direction === "rtl") {
51
- watchRight = watch(right, (newValue) => left.value = transformRTL(newValue), { flush, deep, immediate });
131
+ watchers.push(watchPausable(
132
+ right,
133
+ (newValue) => {
134
+ watchers.forEach((w) => w.pause());
135
+ left.value = transformRTL(newValue);
136
+ watchers.forEach((w) => w.resume());
137
+ },
138
+ { flush, deep, immediate }
139
+ ));
52
140
  }
53
- return () => {
54
- watchLeft == null ? void 0 : watchLeft();
55
- watchRight == null ? void 0 : watchRight();
141
+ const stop = () => {
142
+ watchers.forEach((w) => w.stop());
56
143
  };
144
+ return stop;
57
145
  }
58
146
 
59
- function tryOnMounted(fn, sync = true) {
60
- if (getCurrentInstance())
61
- onMounted(fn);
147
+ function tryOnMounted(fn, sync = true, target) {
148
+ const instance = getLifeCycleTarget();
149
+ if (instance)
150
+ onMounted(fn, target);
62
151
  else if (sync)
63
152
  fn();
64
153
  else
65
154
  nextTick(fn);
66
155
  }
67
156
 
157
+ function watchImmediate(source, cb, options) {
158
+ return watch(
159
+ source,
160
+ cb,
161
+ {
162
+ ...options,
163
+ immediate: true
164
+ }
165
+ );
166
+ }
167
+
168
+ function watchOnce(source, cb, options) {
169
+ const stop = watch(source, (...args) => {
170
+ nextTick(() => stop());
171
+ return cb(...args);
172
+ }, options);
173
+ return stop;
174
+ }
175
+
176
+ const defaultWindow = isClient ? window : void 0;
177
+
68
178
  function unrefElement(elRef) {
69
179
  var _a;
70
- const plain = resolveUnref(elRef);
180
+ const plain = toValue(elRef);
71
181
  return (_a = plain == null ? void 0 : plain.$el) != null ? _a : plain;
72
182
  }
73
183
 
74
- const defaultWindow = isClient ? window : void 0;
75
-
76
184
  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
185
  const cleanups = [];
94
186
  const cleanup = () => {
95
187
  cleanups.forEach((fn) => fn());
96
188
  cleanups.length = 0;
97
189
  };
98
- const register = (el, event, listener) => {
190
+ const register = (el, event, listener, options) => {
99
191
  el.addEventListener(event, listener, options);
100
192
  return () => el.removeEventListener(event, listener, options);
101
193
  };
102
- const stopWatch = watch(() => unrefElement(target), (el) => {
103
- cleanup();
104
- if (!el)
105
- return;
106
- cleanups.push(...events.flatMap((event) => {
107
- return listeners.map((listener) => register(el, event, listener));
108
- }));
109
- }, { immediate: true, flush: "post" });
194
+ const firstParamTargets = computed(() => {
195
+ const test = toArray(toValue(args[0])).filter((e) => e != null);
196
+ return test.every((e) => typeof e !== "string") ? test : void 0;
197
+ });
198
+ const stopWatch = watchImmediate(
199
+ () => {
200
+ var _a, _b;
201
+ return [
202
+ (_b = (_a = firstParamTargets.value) == null ? void 0 : _a.map((e) => unrefElement(e))) != null ? _b : [defaultWindow].filter((e) => e != null),
203
+ toArray(toValue(firstParamTargets.value ? args[1] : args[0])),
204
+ toArray(unref(firstParamTargets.value ? args[2] : args[1])),
205
+ // @ts-expect-error - TypeScript gets the correct types, but somehow still complains
206
+ toValue(firstParamTargets.value ? args[3] : args[2])
207
+ ];
208
+ },
209
+ ([raw_targets, raw_events, raw_listeners, raw_options]) => {
210
+ cleanup();
211
+ 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))
212
+ return;
213
+ const optionsClone = isObject(raw_options) ? { ...raw_options } : raw_options;
214
+ cleanups.push(
215
+ ...raw_targets.flatMap(
216
+ (el) => raw_events.flatMap(
217
+ (event) => raw_listeners.map((listener) => register(el, event, listener, optionsClone))
218
+ )
219
+ )
220
+ );
221
+ },
222
+ { flush: "post" }
223
+ );
110
224
  const stop = () => {
111
225
  stopWatch();
112
226
  cleanup();
113
227
  };
114
- tryOnScopeDispose(stop);
228
+ tryOnScopeDispose(cleanup);
115
229
  return stop;
116
230
  }
117
231
 
232
+ let _iOSWorkaround = false;
118
233
  function onClickOutside(target, handler, options = {}) {
119
- const { window = defaultWindow, ignore = [], capture = true, detectIframe = false } = options;
120
- if (!window)
121
- return;
234
+ const { window = defaultWindow, ignore = [], capture = true, detectIframe = false, controls = false } = options;
235
+ if (!window) {
236
+ return controls ? { stop: noop, cancel: noop, trigger: noop } : noop;
237
+ }
238
+ if (isIOS && !_iOSWorkaround) {
239
+ _iOSWorkaround = true;
240
+ const listenerOptions = { passive: true };
241
+ Array.from(window.document.body.children).forEach((el) => useEventListener(el, "click", noop, listenerOptions));
242
+ useEventListener(window.document.documentElement, "click", noop, listenerOptions);
243
+ }
122
244
  let shouldListen = true;
123
- let fallback;
124
245
  const shouldIgnore = (event) => {
125
- return ignore.some((target2) => {
246
+ return toValue(ignore).some((target2) => {
126
247
  if (typeof target2 === "string") {
127
248
  return Array.from(window.document.querySelectorAll(target2)).some((el) => el === event.target || event.composedPath().includes(el));
128
249
  } else {
@@ -131,12 +252,26 @@ function onClickOutside(target, handler, options = {}) {
131
252
  }
132
253
  });
133
254
  };
255
+ function hasMultipleRoots(target2) {
256
+ const vm = toValue(target2);
257
+ return vm && vm.$.subTree.shapeFlag === 16;
258
+ }
259
+ function checkMultipleRoots(target2, event) {
260
+ const vm = toValue(target2);
261
+ const children = vm.$.subTree && vm.$.subTree.children;
262
+ if (children == null || !Array.isArray(children))
263
+ return false;
264
+ return children.some((child) => child.el === event.target || event.composedPath().includes(child.el));
265
+ }
134
266
  const listener = (event) => {
135
- window.clearTimeout(fallback);
136
267
  const el = unrefElement(target);
268
+ if (event.target == null)
269
+ return;
270
+ if (!(el instanceof Element) && hasMultipleRoots(target) && checkMultipleRoots(target, event))
271
+ return;
137
272
  if (!el || el === event.target || event.composedPath().includes(el))
138
273
  return;
139
- if (event.detail === 0)
274
+ if ("detail" in event && event.detail === 0)
140
275
  shouldListen = !shouldIgnore(event);
141
276
  if (!shouldListen) {
142
277
  shouldListen = true;
@@ -144,63 +279,114 @@ function onClickOutside(target, handler, options = {}) {
144
279
  }
145
280
  handler(event);
146
281
  };
282
+ let isProcessingClick = false;
147
283
  const cleanup = [
148
- useEventListener(window, "click", listener, { passive: true, capture }),
284
+ useEventListener(window, "click", (event) => {
285
+ if (!isProcessingClick) {
286
+ isProcessingClick = true;
287
+ setTimeout(() => {
288
+ isProcessingClick = false;
289
+ }, 0);
290
+ listener(event);
291
+ }
292
+ }, { passive: true, capture }),
149
293
  useEventListener(window, "pointerdown", (e) => {
150
294
  const el = unrefElement(target);
151
- if (el)
152
- shouldListen = !e.composedPath().includes(el) && !shouldIgnore(e);
153
- }, { passive: true }),
154
- useEventListener(window, "pointerup", (e) => {
155
- if (e.button === 0) {
156
- const path = e.composedPath();
157
- e.composedPath = () => path;
158
- fallback = window.setTimeout(() => listener(e), 50);
159
- }
295
+ shouldListen = !shouldIgnore(e) && !!(el && !e.composedPath().includes(el));
160
296
  }, { passive: true }),
161
297
  detectIframe && useEventListener(window, "blur", (event) => {
162
- var _a;
163
- const el = unrefElement(target);
164
- if (((_a = window.document.activeElement) == null ? void 0 : _a.tagName) === "IFRAME" && !(el == null ? void 0 : el.contains(window.document.activeElement)))
165
- handler(event);
166
- })
298
+ setTimeout(() => {
299
+ var _a;
300
+ const el = unrefElement(target);
301
+ if (((_a = window.document.activeElement) == null ? void 0 : _a.tagName) === "IFRAME" && !(el == null ? void 0 : el.contains(window.document.activeElement))) {
302
+ handler(event);
303
+ }
304
+ }, 0);
305
+ }, { passive: true })
167
306
  ].filter(Boolean);
168
307
  const stop = () => cleanup.forEach((fn) => fn());
308
+ if (controls) {
309
+ return {
310
+ stop,
311
+ cancel: () => {
312
+ shouldListen = false;
313
+ },
314
+ trigger: (event) => {
315
+ shouldListen = true;
316
+ listener(event);
317
+ shouldListen = false;
318
+ }
319
+ };
320
+ }
169
321
  return stop;
170
322
  }
171
323
 
172
- function useSupported(callback, sync = false) {
173
- const isSupported = ref();
174
- const update = () => isSupported.value = Boolean(callback());
175
- update();
176
- tryOnMounted(update, sync);
177
- return isSupported;
324
+ function useMounted() {
325
+ const isMounted = shallowRef(false);
326
+ const instance = getCurrentInstance();
327
+ if (instance) {
328
+ onMounted(() => {
329
+ isMounted.value = true;
330
+ }, instance);
331
+ }
332
+ return isMounted;
333
+ }
334
+
335
+ function useSupported(callback) {
336
+ const isMounted = useMounted();
337
+ return computed(() => {
338
+ isMounted.value;
339
+ return Boolean(callback());
340
+ });
341
+ }
342
+
343
+ function useMutationObserver(target, callback, options = {}) {
344
+ const { window = defaultWindow, ...mutationOptions } = options;
345
+ let observer;
346
+ const isSupported = useSupported(() => window && "MutationObserver" in window);
347
+ const cleanup = () => {
348
+ if (observer) {
349
+ observer.disconnect();
350
+ observer = void 0;
351
+ }
352
+ };
353
+ const targets = computed(() => {
354
+ const value = toValue(target);
355
+ const items = toArray(value).map(unrefElement).filter(notNullish);
356
+ return new Set(items);
357
+ });
358
+ const stopWatch = watch(
359
+ () => targets.value,
360
+ (targets2) => {
361
+ cleanup();
362
+ if (isSupported.value && targets2.size) {
363
+ observer = new MutationObserver(callback);
364
+ targets2.forEach((el) => observer.observe(el, mutationOptions));
365
+ }
366
+ },
367
+ { immediate: true, flush: "post" }
368
+ );
369
+ const takeRecords = () => {
370
+ return observer == null ? void 0 : observer.takeRecords();
371
+ };
372
+ const stop = () => {
373
+ stopWatch();
374
+ cleanup();
375
+ };
376
+ tryOnScopeDispose(stop);
377
+ return {
378
+ isSupported,
379
+ stop,
380
+ takeRecords
381
+ };
178
382
  }
383
+
179
384
  function cloneFnJSON(source) {
180
385
  return JSON.parse(JSON.stringify(source));
181
386
  }
182
387
 
183
- const _global = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
184
- const globalKey = "__vueuse_ssr_handlers__";
185
- _global[globalKey] = _global[globalKey] || {};
186
-
187
- var __getOwnPropSymbols$f = Object.getOwnPropertySymbols;
188
- var __hasOwnProp$f = Object.prototype.hasOwnProperty;
189
- var __propIsEnum$f = Object.prototype.propertyIsEnumerable;
190
- var __objRest$2 = (source, exclude) => {
191
- var target = {};
192
- for (var prop in source)
193
- if (__hasOwnProp$f.call(source, prop) && exclude.indexOf(prop) < 0)
194
- target[prop] = source[prop];
195
- if (source != null && __getOwnPropSymbols$f)
196
- for (var prop of __getOwnPropSymbols$f(source)) {
197
- if (exclude.indexOf(prop) < 0 && __propIsEnum$f.call(source, prop))
198
- target[prop] = source[prop];
199
- }
200
- return target;
201
- };
202
388
  function useResizeObserver(target, callback, options = {}) {
203
- const _a = options, { window = defaultWindow } = _a, observerOptions = __objRest$2(_a, ["window"]);
389
+ const { window = defaultWindow, ...observerOptions } = options;
204
390
  let observer;
205
391
  const isSupported = useSupported(() => window && "ResizeObserver" in window);
206
392
  const cleanup = () => {
@@ -209,13 +395,24 @@ function useResizeObserver(target, callback, options = {}) {
209
395
  observer = void 0;
210
396
  }
211
397
  };
212
- const stopWatch = watch(() => unrefElement(target), (el) => {
213
- cleanup();
214
- if (isSupported.value && window && el) {
215
- observer = new ResizeObserver(callback);
216
- observer.observe(el, observerOptions);
217
- }
218
- }, { immediate: true, flush: "post" });
398
+ const targets = computed(() => {
399
+ const _targets = toValue(target);
400
+ return Array.isArray(_targets) ? _targets.map((el) => unrefElement(el)) : [unrefElement(_targets)];
401
+ });
402
+ const stopWatch = watch(
403
+ targets,
404
+ (els) => {
405
+ cleanup();
406
+ if (isSupported.value && window) {
407
+ observer = new ResizeObserver(callback);
408
+ for (const _el of els) {
409
+ if (_el)
410
+ observer.observe(_el, observerOptions);
411
+ }
412
+ }
413
+ },
414
+ { immediate: true, flush: "post" }
415
+ );
219
416
  const stop = () => {
220
417
  cleanup();
221
418
  stopWatch();
@@ -232,17 +429,18 @@ function useElementBounding(target, options = {}) {
232
429
  reset = true,
233
430
  windowResize = true,
234
431
  windowScroll = true,
235
- immediate = true
432
+ immediate = true,
433
+ updateTiming = "sync"
236
434
  } = options;
237
- const height = ref(0);
238
- const bottom = ref(0);
239
- const left = ref(0);
240
- const right = ref(0);
241
- const top = ref(0);
242
- const width = ref(0);
243
- const x = ref(0);
244
- const y = ref(0);
245
- function update() {
435
+ const height = shallowRef(0);
436
+ const bottom = shallowRef(0);
437
+ const left = shallowRef(0);
438
+ const right = shallowRef(0);
439
+ const top = shallowRef(0);
440
+ const width = shallowRef(0);
441
+ const x = shallowRef(0);
442
+ const y = shallowRef(0);
443
+ function recalculate() {
246
444
  const el = unrefElement(target);
247
445
  if (!el) {
248
446
  if (reset) {
@@ -267,8 +465,17 @@ function useElementBounding(target, options = {}) {
267
465
  x.value = rect.x;
268
466
  y.value = rect.y;
269
467
  }
468
+ function update() {
469
+ if (updateTiming === "sync")
470
+ recalculate();
471
+ else if (updateTiming === "next-frame")
472
+ requestAnimationFrame(() => recalculate());
473
+ }
270
474
  useResizeObserver(target, update);
271
475
  watch(() => unrefElement(target), (ele) => !ele && update());
476
+ useMutationObserver(target, update, {
477
+ attributeFilter: ["style", "class"]
478
+ });
272
479
  if (windowScroll)
273
480
  useEventListener("scroll", update, { capture: true, passive: true });
274
481
  if (windowResize)
@@ -290,84 +497,101 @@ function useElementBounding(target, options = {}) {
290
497
  };
291
498
  }
292
499
 
293
- function useElementVisibility(element, { window = defaultWindow, scrollTarget } = {}) {
294
- const elementIsVisible = ref(false);
295
- const testBounding = () => {
296
- if (!window)
297
- return;
298
- const document = window.document;
299
- const el = unrefElement(element);
300
- if (!el) {
301
- elementIsVisible.value = false;
302
- } else {
303
- const rect = el.getBoundingClientRect();
304
- elementIsVisible.value = rect.top <= (window.innerHeight || document.documentElement.clientHeight) && rect.left <= (window.innerWidth || document.documentElement.clientWidth) && rect.bottom >= 0 && rect.right >= 0;
305
- }
500
+ function useIntersectionObserver(target, callback, options = {}) {
501
+ const {
502
+ root,
503
+ rootMargin = "0px",
504
+ threshold = 0,
505
+ window = defaultWindow,
506
+ immediate = true
507
+ } = options;
508
+ const isSupported = useSupported(() => window && "IntersectionObserver" in window);
509
+ const targets = computed(() => {
510
+ const _target = toValue(target);
511
+ return toArray(_target).map(unrefElement).filter(notNullish);
512
+ });
513
+ let cleanup = noop;
514
+ const isActive = shallowRef(immediate);
515
+ const stopWatch = isSupported.value ? watch(
516
+ () => [targets.value, unrefElement(root), isActive.value],
517
+ ([targets2, root2]) => {
518
+ cleanup();
519
+ if (!isActive.value)
520
+ return;
521
+ if (!targets2.length)
522
+ return;
523
+ const observer = new IntersectionObserver(
524
+ callback,
525
+ {
526
+ root: unrefElement(root2),
527
+ rootMargin,
528
+ threshold
529
+ }
530
+ );
531
+ targets2.forEach((el) => el && observer.observe(el));
532
+ cleanup = () => {
533
+ observer.disconnect();
534
+ cleanup = noop;
535
+ };
536
+ },
537
+ { immediate, flush: "post" }
538
+ ) : noop;
539
+ const stop = () => {
540
+ cleanup();
541
+ stopWatch();
542
+ isActive.value = false;
543
+ };
544
+ tryOnScopeDispose(stop);
545
+ return {
546
+ isSupported,
547
+ isActive,
548
+ pause() {
549
+ cleanup();
550
+ isActive.value = false;
551
+ },
552
+ resume() {
553
+ isActive.value = true;
554
+ },
555
+ stop
306
556
  };
307
- watch(() => unrefElement(element), () => testBounding(), { immediate: true, flush: "post" });
308
- if (window) {
309
- useEventListener(scrollTarget || window, "scroll", testBounding, {
310
- capture: false,
311
- passive: true
312
- });
313
- }
314
- return elementIsVisible;
315
557
  }
316
558
 
317
- var SwipeDirection;
318
- (function(SwipeDirection2) {
319
- SwipeDirection2["UP"] = "UP";
320
- SwipeDirection2["RIGHT"] = "RIGHT";
321
- SwipeDirection2["DOWN"] = "DOWN";
322
- SwipeDirection2["LEFT"] = "LEFT";
323
- SwipeDirection2["NONE"] = "NONE";
324
- })(SwipeDirection || (SwipeDirection = {}));
325
-
326
- var __defProp = Object.defineProperty;
327
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
328
- var __hasOwnProp = Object.prototype.hasOwnProperty;
329
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
330
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
331
- var __spreadValues = (a, b) => {
332
- for (var prop in b || (b = {}))
333
- if (__hasOwnProp.call(b, prop))
334
- __defNormalProp(a, prop, b[prop]);
335
- if (__getOwnPropSymbols)
336
- for (var prop of __getOwnPropSymbols(b)) {
337
- if (__propIsEnum.call(b, prop))
338
- __defNormalProp(a, prop, b[prop]);
559
+ function useElementVisibility(element, options = {}) {
560
+ const {
561
+ window = defaultWindow,
562
+ scrollTarget,
563
+ threshold = 0,
564
+ rootMargin,
565
+ once = false
566
+ } = options;
567
+ const elementIsVisible = shallowRef(false);
568
+ const { stop } = useIntersectionObserver(
569
+ element,
570
+ (intersectionObserverEntries) => {
571
+ let isIntersecting = elementIsVisible.value;
572
+ let latestTime = 0;
573
+ for (const entry of intersectionObserverEntries) {
574
+ if (entry.time >= latestTime) {
575
+ latestTime = entry.time;
576
+ isIntersecting = entry.isIntersecting;
577
+ }
578
+ }
579
+ elementIsVisible.value = isIntersecting;
580
+ if (once) {
581
+ watchOnce(elementIsVisible, () => {
582
+ stop();
583
+ });
584
+ }
585
+ },
586
+ {
587
+ root: scrollTarget,
588
+ window,
589
+ threshold,
590
+ rootMargin: toValue(rootMargin)
339
591
  }
340
- return a;
341
- };
342
- const _TransitionPresets = {
343
- easeInSine: [0.12, 0, 0.39, 0],
344
- easeOutSine: [0.61, 1, 0.88, 1],
345
- easeInOutSine: [0.37, 0, 0.63, 1],
346
- easeInQuad: [0.11, 0, 0.5, 0],
347
- easeOutQuad: [0.5, 1, 0.89, 1],
348
- easeInOutQuad: [0.45, 0, 0.55, 1],
349
- easeInCubic: [0.32, 0, 0.67, 0],
350
- easeOutCubic: [0.33, 1, 0.68, 1],
351
- easeInOutCubic: [0.65, 0, 0.35, 1],
352
- easeInQuart: [0.5, 0, 0.75, 0],
353
- easeOutQuart: [0.25, 1, 0.5, 1],
354
- easeInOutQuart: [0.76, 0, 0.24, 1],
355
- easeInQuint: [0.64, 0, 0.78, 0],
356
- easeOutQuint: [0.22, 1, 0.36, 1],
357
- easeInOutQuint: [0.83, 0, 0.17, 1],
358
- easeInExpo: [0.7, 0, 0.84, 0],
359
- easeOutExpo: [0.16, 1, 0.3, 1],
360
- easeInOutExpo: [0.87, 0, 0.13, 1],
361
- easeInCirc: [0.55, 0, 1, 0.45],
362
- easeOutCirc: [0, 0.55, 0.45, 1],
363
- easeInOutCirc: [0.85, 0, 0.15, 1],
364
- easeInBack: [0.36, 0, 0.66, -0.56],
365
- easeOutBack: [0.34, 1.56, 0.64, 1],
366
- easeInOutBack: [0.68, -0.6, 0.32, 1.6]
367
- };
368
- __spreadValues({
369
- linear: identity
370
- }, _TransitionPresets);
592
+ );
593
+ return elementIsVisible;
594
+ }
371
595
 
372
596
  function useVModel(props, key, emit, options = {}) {
373
597
  var _a, _b, _c;
@@ -376,27 +600,48 @@ function useVModel(props, key, emit, options = {}) {
376
600
  passive = false,
377
601
  eventName,
378
602
  deep = false,
379
- defaultValue
603
+ defaultValue,
604
+ shouldEmit
380
605
  } = options;
381
606
  const vm = getCurrentInstance();
382
607
  const _emit = emit || (vm == null ? void 0 : vm.emit) || ((_a = vm == null ? void 0 : vm.$emit) == null ? void 0 : _a.bind(vm)) || ((_c = (_b = vm == null ? void 0 : vm.proxy) == null ? void 0 : _b.$emit) == null ? void 0 : _c.bind(vm == null ? void 0 : vm.proxy));
383
608
  let event = eventName;
384
609
  if (!key) {
385
- {
386
- key = "modelValue";
387
- }
610
+ key = "modelValue";
388
611
  }
389
- event = eventName || event || `update:${key.toString()}`;
390
- const cloneFn = (val) => !clone ? val : isFunction(clone) ? clone(val) : cloneFnJSON(val);
612
+ event = event || `update:${key.toString()}`;
613
+ const cloneFn = (val) => !clone ? val : typeof clone === "function" ? clone(val) : cloneFnJSON(val);
391
614
  const getValue = () => isDef(props[key]) ? cloneFn(props[key]) : defaultValue;
615
+ const triggerEmit = (value) => {
616
+ if (shouldEmit) {
617
+ if (shouldEmit(value))
618
+ _emit(event, value);
619
+ } else {
620
+ _emit(event, value);
621
+ }
622
+ };
392
623
  if (passive) {
393
624
  const initialValue = getValue();
394
625
  const proxy = ref(initialValue);
395
- watch(() => props[key], (v) => proxy.value = cloneFn(v));
396
- watch(proxy, (v) => {
397
- if (v !== props[key] || deep)
398
- _emit(event, v);
399
- }, { deep });
626
+ let isUpdating = false;
627
+ watch(
628
+ () => props[key],
629
+ (v) => {
630
+ if (!isUpdating) {
631
+ isUpdating = true;
632
+ proxy.value = cloneFn(v);
633
+ nextTick(() => isUpdating = false);
634
+ }
635
+ }
636
+ );
637
+ watch(
638
+ proxy,
639
+ (v) => {
640
+ if (!isUpdating && (v !== props[key] || deep))
641
+ triggerEmit(v);
642
+ },
643
+ { deep }
644
+ );
400
645
  return proxy;
401
646
  } else {
402
647
  return computed({
@@ -404,7 +649,7 @@ function useVModel(props, key, emit, options = {}) {
404
649
  return getValue();
405
650
  },
406
651
  set(value) {
407
- _emit(event, value);
652
+ triggerEmit(value);
408
653
  }
409
654
  });
410
655
  }
@@ -566,15 +811,8 @@ const useFileUpload = defineHookComponent({
566
811
  setup(props, { emit }) {
567
812
  const fileInputRef = elementRef();
568
813
  const files = ref([]);
569
- watch(props.modelValue, (value) => {
570
- if (value instanceof File) {
571
- files.value.push(value);
572
- } else if (Array.isArray(value)) {
573
- files.value.push(...value);
574
- }
575
- if (props.multiple) {
576
- files.value.splice(1, files.value.length - 1);
577
- }
814
+ watch(() => toArray$1(props.modelValue), (value) => {
815
+ files.value = value;
578
816
  }, {
579
817
  immediate: true,
580
818
  deep: true
@@ -582,18 +820,25 @@ const useFileUpload = defineHookComponent({
582
820
  const openFileInput = () => {
583
821
  fileInputRef.value?.click();
584
822
  };
823
+ const toModelValue = (files2) => {
824
+ if (props.multiple) {
825
+ return files2;
826
+ }
827
+ if (files2.length) {
828
+ return files2[files2.length - 1];
829
+ }
830
+ return null;
831
+ };
585
832
  useEventListener(fileInputRef, "change", (event) => {
586
- const newFiles = event.target.files;
587
- let value = [];
588
- if (newFiles) {
833
+ const newFiles = Array.from(event.target.files ?? []);
834
+ if (newFiles?.length) {
589
835
  if (props.multiple) {
590
- value = Array.from(newFiles);
591
- files.value.push(...value);
836
+ files.value.push(...newFiles);
592
837
  } else {
593
- value = Array.from(newFiles)[0];
594
- files.value = value ? [value] : [];
838
+ files.value = newFiles.slice(newFiles.length - 1);
595
839
  }
596
840
  }
841
+ const value = toModelValue(files.value);
597
842
  emit("update:modelValue", value);
598
843
  emit("change", value);
599
844
  });
@@ -1281,4 +1526,126 @@ const useSwitch = defineHookComponent({
1281
1526
  }
1282
1527
  });
1283
1528
 
1284
- export { AFFIX_TARGET_KEY, affixEmits, affixProps, configProviderProps, fileUploadEmits, fileUploadProps, iconProps, itemEmits, itemProps, popoverEmits, popoverProps, provideAffixTarget, selectionEmits, selectionProps, switchEmits, switchProps, useAffix, useFileUpload, useIcon, usePopover, useSelectionContext, useSelectionItem, useSelectionList, useSwitch };
1529
+ const virtualListProps = defineHookProps({
1530
+ options: {
1531
+ type: Object,
1532
+ default: () => ({})
1533
+ },
1534
+ count: {
1535
+ type: Number,
1536
+ default: () => 0
1537
+ },
1538
+ estimateSize: {
1539
+ type: [Function, Number],
1540
+ default: () => 50
1541
+ },
1542
+ horizontal: {
1543
+ type: Boolean,
1544
+ default: () => false
1545
+ }
1546
+ });
1547
+ const virtualListEmits = defineHookEmits({
1548
+ scrollEnd: () => true,
1549
+ scrollStart: () => true,
1550
+ scroll: (_) => true
1551
+ });
1552
+ const useVirtualList = defineHookComponent({
1553
+ props: virtualListProps,
1554
+ emits: virtualListEmits,
1555
+ setup(props, context) {
1556
+ const { emit } = context;
1557
+ const scrollElementRef = elementRef();
1558
+ const propsEstimateSize = props.estimateSize;
1559
+ const estimateSize = typeof propsEstimateSize === "function" ? propsEstimateSize : () => propsEstimateSize;
1560
+ const options = computed(() => {
1561
+ const opts = { ...props.options || {} };
1562
+ return {
1563
+ ...opts,
1564
+ count: props.count,
1565
+ estimateSize,
1566
+ horizontal: props.horizontal,
1567
+ getScrollElement: () => scrollElementRef.value,
1568
+ observeElementRect,
1569
+ observeElementOffset,
1570
+ scrollToFn: elementScroll
1571
+ };
1572
+ });
1573
+ const virtualizer = new Virtualizer(options.value);
1574
+ const state = shallowRef(virtualizer);
1575
+ const virtualItems = computed(() => state.value.getVirtualItems());
1576
+ const virtualIndexes = computed(() => state.value.getVirtualIndexes());
1577
+ const totalSize = computed(() => state.value.getTotalSize());
1578
+ watch(
1579
+ virtualIndexes,
1580
+ (indexes) => {
1581
+ if (indexes.length === 0) {
1582
+ return;
1583
+ }
1584
+ if (indexes[indexes.length - 1] === props.count - 1) {
1585
+ emit("scrollEnd");
1586
+ } else if (indexes[0] === 0) {
1587
+ emit("scrollStart");
1588
+ }
1589
+ emit("scroll", indexes);
1590
+ },
1591
+ { immediate: true }
1592
+ );
1593
+ watch(
1594
+ options,
1595
+ (opts) => {
1596
+ virtualizer.setOptions({
1597
+ ...opts,
1598
+ onChange: (instance, sync) => {
1599
+ opts.onChange?.(instance, sync);
1600
+ triggerRef(state);
1601
+ }
1602
+ });
1603
+ virtualizer._willUpdate();
1604
+ triggerRef(state);
1605
+ },
1606
+ { immediate: true }
1607
+ );
1608
+ watch(
1609
+ scrollElementRef,
1610
+ (el) => {
1611
+ if (el) {
1612
+ virtualizer._willUpdate();
1613
+ triggerRef(state);
1614
+ }
1615
+ },
1616
+ { immediate: true }
1617
+ );
1618
+ tryOnScopeDispose(virtualizer._didMount());
1619
+ const measureElement = (el) => {
1620
+ virtualizer.measureElement(el);
1621
+ };
1622
+ const scrollToIndex = (index, options2 = {
1623
+ behavior: "smooth"
1624
+ }) => {
1625
+ virtualizer.scrollToIndex(index, options2);
1626
+ };
1627
+ const scrollToStart = (options2 = {
1628
+ behavior: "smooth"
1629
+ }) => {
1630
+ scrollToIndex(0, options2);
1631
+ };
1632
+ const scrollToEnd = (options2 = {
1633
+ behavior: "smooth"
1634
+ }) => {
1635
+ scrollToIndex(props.count - 1, options2);
1636
+ };
1637
+ return {
1638
+ virtualizer,
1639
+ virtualItems,
1640
+ virtualIndexes,
1641
+ totalSize,
1642
+ scrollElementRef,
1643
+ measureElement,
1644
+ scrollToIndex,
1645
+ scrollToStart,
1646
+ scrollToEnd
1647
+ };
1648
+ }
1649
+ });
1650
+
1651
+ export { AFFIX_TARGET_KEY, affixEmits, affixProps, configProviderProps, fileUploadEmits, fileUploadProps, iconProps, itemEmits, itemProps, popoverEmits, popoverProps, provideAffixTarget, selectionEmits, selectionProps, switchEmits, switchProps, useAffix, useFileUpload, useIcon, usePopover, useSelectionContext, useSelectionItem, useSelectionList, useSwitch, useVirtualList, virtualListEmits, virtualListProps };