@vuetify/v0 0.1.12 → 0.2.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/{adapter-DvT8lTup.d.mts → adapter-DIZk5xrU.d.mts} +1 -1
- package/dist/adapter-Drq1v5wV.mjs +27 -0
- package/dist/{adapter-D3dUnE__.d.mts → adapter-MT5TiIjj.d.mts} +2 -2
- package/dist/browser/index.js +3912 -2932
- package/dist/components/index.d.mts +3 -2
- package/dist/components/index.mjs +22 -20
- package/dist/{components-CrZmJSH3.mjs → components-lme-T9bN.mjs} +771 -177
- package/dist/composables/index.d.mts +19 -19
- package/dist/composables/index.mjs +22 -20
- package/dist/{consola-C1OjyZVf.d.mts → consola-bPHDMwrK.d.mts} +1 -1
- package/dist/constants/index.d.mts +1 -1
- package/dist/constants/index.mjs +1 -1
- package/dist/{useClickOutside-hbi0BOL-.mjs → createCombobox-DgFUWLKw.mjs} +1091 -790
- package/dist/{createDataTable-DKCm5-7f.mjs → createDataTable-DGG3Kgau.mjs} +2 -2
- package/dist/{createGroup-CFMocwej.mjs → createGroup-C38Mc-se.mjs} +1 -1
- package/dist/{createSelection-Cl1nX0he.mjs → createSelection-GS1yfwki.mjs} +1 -1
- package/dist/{createSingle-BxOPkL3l.mjs → createSingle-Dh2gp4kv.mjs} +1 -1
- package/dist/{createTokens-C67MMcZJ.mjs → createTokens-Ckczb95n.mjs} +1 -1
- package/dist/data-table/adapters/client/index.d.mts +1 -1
- package/dist/data-table/adapters/client/index.mjs +1 -1
- package/dist/data-table/adapters/index.d.mts +4 -4
- package/dist/data-table/adapters/index.mjs +1 -1
- package/dist/data-table/adapters/server/index.d.mts +1 -1
- package/dist/data-table/adapters/server/index.mjs +1 -1
- package/dist/data-table/adapters/virtual/index.d.mts +1 -1
- package/dist/data-table/adapters/virtual/index.mjs +1 -1
- package/dist/data-table/index.d.mts +5 -5
- package/dist/data-table/index.mjs +10 -10
- package/dist/date/index.d.mts +2 -1
- package/dist/date/index.mjs +34 -10
- package/dist/features/adapters/flagsmith/index.d.mts +1 -1
- package/dist/features/adapters/launchdarkly/index.d.mts +1 -1
- package/dist/features/adapters/posthog/index.d.mts +1 -1
- package/dist/features/adapters/posthog/index.mjs +2 -2
- package/dist/features/index.d.mts +2 -2
- package/dist/features/index.mjs +8 -8
- package/dist/{globals-uLTsqsl2.mjs → globals-B6VQTLVM.mjs} +1 -1
- package/dist/{index-B_pScNDG.d.mts → index-A6Vo3pb6.d.mts} +28 -1
- package/dist/{index-CBER-Sxt.d.mts → index-BAix61Ke.d.mts} +275 -98
- package/dist/{index-BN-lmMJM.d.mts → index-CuUuJj3-.d.mts} +878 -199
- package/dist/{index-CdUIc68E.d.mts → index-D5ehwqoP.d.mts} +3 -3
- package/dist/{index-YyqYAay2.d.mts → index-Y0Bo7jx-.d.mts} +2 -2
- package/dist/{index-dJKXAO5D.d.mts → index-pwVD-IDb.d.mts} +1 -1
- package/dist/index.d.mts +23 -23
- package/dist/index.mjs +23 -21
- package/dist/json/attributes.json +199 -7
- package/dist/json/importMap.json +44 -0
- package/dist/json/tags.json +100 -2
- package/dist/json/web-types.json +592 -10
- package/dist/locale/adapters/index.d.mts +2 -2
- package/dist/locale/adapters/index.mjs +2 -2
- package/dist/locale/adapters/v0/index.d.mts +1 -1
- package/dist/locale/adapters/v0/index.mjs +2 -2
- package/dist/locale/adapters/vue-i18n/index.d.mts +1 -1
- package/dist/locale/adapters/vue-i18n/index.mjs +1 -1
- package/dist/locale/index.d.mts +3 -3
- package/dist/locale/index.mjs +8 -8
- package/dist/logger/adapters/consola/index.d.mts +1 -1
- package/dist/logger/adapters/index.d.mts +4 -4
- package/dist/logger/adapters/index.mjs +2 -2
- package/dist/logger/adapters/pino/index.d.mts +1 -1
- package/dist/logger/adapters/pino/index.mjs +1 -1
- package/dist/logger/adapters/v0/index.d.mts +1 -1
- package/dist/logger/adapters/v0/index.mjs +2 -2
- package/dist/logger/index.d.mts +5 -5
- package/dist/logger/index.mjs +3 -3
- package/dist/notifications/index.d.mts +1 -1
- package/dist/notifications/index.mjs +1 -1
- package/dist/palettes/ant/index.d.mts +1 -1
- package/dist/palettes/index.d.mts +3 -3
- package/dist/palettes/material/index.d.mts +1 -1
- package/dist/palettes/md1/index.d.mts +1 -1
- package/dist/palettes/md2/index.d.mts +1 -1
- package/dist/palettes/radix/index.d.mts +1 -1
- package/dist/palettes/tailwind/index.d.mts +1 -1
- package/dist/permissions/adapters/index.d.mts +2 -2
- package/dist/permissions/adapters/index.mjs +1 -1
- package/dist/permissions/adapters/v0/index.d.mts +1 -1
- package/dist/permissions/adapters/v0/index.mjs +1 -1
- package/dist/permissions/index.d.mts +1 -1
- package/dist/permissions/index.mjs +5 -5
- package/dist/{pino-CM1iLXmi.d.mts → pino-BUGULcfS.d.mts} +1 -1
- package/dist/{posthog-DSkHSLCw.mjs → posthog-BUVv9Rky.mjs} +1 -1
- package/dist/rules/index.d.mts +1 -1
- package/dist/rules/index.mjs +9 -9
- package/dist/{server-CSLVeyyI.d.mts → server-Ciw0ZhhL.d.mts} +1 -1
- package/dist/storage/adapters/index.d.mts +2 -2
- package/dist/storage/adapters/memory/index.d.mts +1 -1
- package/dist/storage/index.d.mts +3 -3
- package/dist/storage/index.mjs +20 -18
- package/dist/theme/adapters/index.d.mts +2 -2
- package/dist/theme/adapters/index.mjs +6 -4
- package/dist/theme/adapters/unhead/index.d.mts +2 -0
- package/dist/theme/adapters/unhead/index.mjs +4 -0
- package/dist/theme/adapters/v0/index.d.mts +2 -2
- package/dist/theme/adapters/v0/index.mjs +4 -3
- package/dist/theme/index.d.mts +2 -2
- package/dist/theme/index.mjs +12 -10
- package/dist/types/index.d.mts +1 -1
- package/dist/unhead-CMUN7pv4.mjs +63 -0
- package/dist/{useFeatures-DNQ8V1So.mjs → useFeatures-_uwRwuBy.mjs} +3 -3
- package/dist/{useLocale-BpjMU7hm.mjs → useLocale-BNecStw9.mjs} +9 -5
- package/dist/{useLogger-jmvgVE6N.mjs → useLogger-B3ijAgn0.mjs} +29 -7
- package/dist/{usePermissions-TIV4dGj1.mjs → usePermissions-5g7JSb3-.mjs} +2 -2
- package/dist/{useRules-sRYyyrvM.mjs → useRules-BnQZP8n2.mjs} +2 -2
- package/dist/{useTheme-vAXldHit.mjs → useTheme-CKcE6z3t.mjs} +10 -7
- package/dist/utilities/index.d.mts +1 -1
- package/dist/utilities/index.mjs +11 -11
- package/dist/{v0-vIA3663g.mjs → v0-3e8B6fd8.mjs} +7 -32
- package/dist/{v0-B6ILFiMN.d.mts → v0-BRnEUnx1.d.mts} +2 -2
- package/dist/{v0-CQ2qHo5-.d.mts → v0-B_8xEDpf.d.mts} +1 -1
- package/dist/{v0-JPf99NKg.d.mts → v0-C3cGdshz.d.mts} +1 -1
- package/dist/{v0-Dem6wjKF.mjs → v0-C64RQgkl.mjs} +1 -1
- package/dist/{v0-JMByI2xs.mjs → v0-Dab-mQua.mjs} +1 -1
- package/dist/{v0-3zDdS4II.d.mts → v0-WOPq3YTM.d.mts} +1 -1
- package/dist/{virtual-Dg0Cm5Hn.d.mts → virtual-By1prSSj.d.mts} +1 -1
- package/package.json +2 -1
- /package/dist/{adapter-CJQav2JB.d.mts → adapter-CST7kApg.d.mts} +0 -0
- /package/dist/{adapter-BWMm0JAQ.d.mts → adapter-cc0r4Pfu.d.mts} +0 -0
- /package/dist/{adapters-C66XaKkw.mjs → adapters-BvwLemDt.mjs} +0 -0
- /package/dist/{index-CeNfBYuo.d.mts → index-BsNeOyXe.d.mts} +0 -0
- /package/dist/{index-BvTD7kU8.d.mts → index-BvlxDVXg.d.mts} +0 -0
- /package/dist/{index-DSao7i57.d.mts → index-C9Wj_it8.d.mts} +0 -0
- /package/dist/{index-Dor6eAEc.d.mts → index-D7Yh-7yN.d.mts} +0 -0
- /package/dist/{memory-DyBabFV1.d.mts → memory-CC5pKIAp.d.mts} +0 -0
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { a as SUPPORTS_OBSERVER, i as SUPPORTS_MUTATION_OBSERVER, n as SUPPORTS_INTERSECTION_OBSERVER, r as SUPPORTS_MATCH_MEDIA, t as IN_BROWSER } from "./globals-
|
|
1
|
+
import { a as SUPPORTS_OBSERVER, i as SUPPORTS_MUTATION_OBSERVER, n as SUPPORTS_INTERSECTION_OBSERVER, r as SUPPORTS_MATCH_MEDIA, t as IN_BROWSER } from "./globals-B6VQTLVM.mjs";
|
|
2
2
|
import { clamp, instanceExists, isElement, isFunction, isNull, isNullOrUndefined, isNumber, isObject, isString, isUndefined, mergeDeep, useId as useId$1 } from "./utilities/index.mjs";
|
|
3
3
|
import { i as useContext, n as createContext, t as createTrinity } from "./createTrinity-C_c8eedz.mjs";
|
|
4
|
-
import { a as createPlugin, i as useLogger, o as createPluginContext } from "./useLogger-
|
|
5
|
-
import { a as createRegistry } from "./createTokens-
|
|
6
|
-
import { i as createModel, t as createSelection } from "./createSelection-
|
|
7
|
-
import { t as createSingle } from "./createSingle-
|
|
8
|
-
import { t as createGroup } from "./createGroup-
|
|
4
|
+
import { a as createPlugin, i as useLogger, o as createPluginContext } from "./useLogger-B3ijAgn0.mjs";
|
|
5
|
+
import { a as createRegistry } from "./createTokens-Ckczb95n.mjs";
|
|
6
|
+
import { i as createModel, t as createSelection } from "./createSelection-GS1yfwki.mjs";
|
|
7
|
+
import { t as createSingle } from "./createSingle-Dh2gp4kv.mjs";
|
|
8
|
+
import { t as createGroup } from "./createGroup-C38Mc-se.mjs";
|
|
9
9
|
import { t as toArray } from "./toArray-VdROPpy-.mjs";
|
|
10
|
-
import { a as useLocale } from "./useLocale-
|
|
11
|
-
import {
|
|
10
|
+
import { a as useLocale } from "./useLocale-BNecStw9.mjs";
|
|
11
|
+
import { n as createFilter } from "./adapter-DXRKF27V.mjs";
|
|
12
|
+
import { a as useRules, o as isStandardSchema } from "./useRules-BnQZP8n2.mjs";
|
|
12
13
|
import { t as MemoryAdapter } from "./memory-XCMtkld1.mjs";
|
|
13
14
|
import { computed, effectScope, isRef, nextTick, onMounted, onScopeDispose, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRef, toValue, unref, watch, watchEffect } from "vue";
|
|
14
15
|
//#region src/composables/createBreadcrumbs/index.ts
|
|
@@ -692,222 +693,6 @@ function useOverflow(namespace = "v0:overflow") {
|
|
|
692
693
|
return useContext(namespace);
|
|
693
694
|
}
|
|
694
695
|
//#endregion
|
|
695
|
-
//#region src/composables/useProxyModel/index.ts
|
|
696
|
-
/**
|
|
697
|
-
* @module useProxyModel
|
|
698
|
-
*
|
|
699
|
-
* @remarks
|
|
700
|
-
* Proxy composable for bidirectional sync between a model context and v-model.
|
|
701
|
-
*
|
|
702
|
-
* Key features:
|
|
703
|
-
* - Bidirectional synchronization
|
|
704
|
-
* - Array and single-value modes
|
|
705
|
-
* - Automatic cleanup on scope disposal
|
|
706
|
-
* - Works with any ModelContext (Selection, Slider, etc.)
|
|
707
|
-
*
|
|
708
|
-
* Bridges the gap between model composables and Vue's v-model.
|
|
709
|
-
*/
|
|
710
|
-
/**
|
|
711
|
-
* Syncs a ref with a model context bidirectionally.
|
|
712
|
-
*
|
|
713
|
-
* @param context The model context to bind to.
|
|
714
|
-
* @param model The ref to sync.
|
|
715
|
-
* @param options The options for the proxy model.
|
|
716
|
-
* @returns A function to stop the sync.
|
|
717
|
-
*
|
|
718
|
-
* @see https://0.vuetifyjs.com/composables/forms/use-proxy-model
|
|
719
|
-
*
|
|
720
|
-
* @example
|
|
721
|
-
* ```ts
|
|
722
|
-
* import { createSelection, useProxyModel } from '@vuetify/v0'
|
|
723
|
-
*
|
|
724
|
-
* const model = ref()
|
|
725
|
-
* const registry = createSelection({ events: true })
|
|
726
|
-
* registry.onboard([
|
|
727
|
-
* { id: 'item-1', value: 'Item 1' },
|
|
728
|
-
* { id: 'item-2', value: 'Item 2' },
|
|
729
|
-
* ])
|
|
730
|
-
*
|
|
731
|
-
* const stop = useProxyModel(registry, model)
|
|
732
|
-
* ```
|
|
733
|
-
*/
|
|
734
|
-
function useProxyModel(context, model, options) {
|
|
735
|
-
const multiple = options?.multiple ?? context.multiple ?? false;
|
|
736
|
-
const _transformIn = options?.transformIn;
|
|
737
|
-
const _transformOut = options?.transformOut;
|
|
738
|
-
function transformIn(val) {
|
|
739
|
-
const value = toValue(val);
|
|
740
|
-
return toArray(/* @__PURE__ */ isFunction(_transformIn) ? _transformIn(value) : value);
|
|
741
|
-
}
|
|
742
|
-
function transformOut(val) {
|
|
743
|
-
if (/* @__PURE__ */ isFunction(_transformOut)) return _transformOut(val);
|
|
744
|
-
return toValue(multiple) ? val : val[0];
|
|
745
|
-
}
|
|
746
|
-
const applyOptions = toValue(multiple) === toValue(context.multiple ?? false) ? void 0 : { multiple: toValue(multiple) };
|
|
747
|
-
const modelAsArray = transformIn(model);
|
|
748
|
-
const pending = new Set(modelAsArray);
|
|
749
|
-
context.apply(modelAsArray, applyOptions);
|
|
750
|
-
const selected = new Set(context.selectedValues.value);
|
|
751
|
-
for (const value of modelAsArray) if (selected.has(value)) pending.delete(value);
|
|
752
|
-
const contextWatch = watch(context.selectedValues, (val) => {
|
|
753
|
-
modelWatch.pause();
|
|
754
|
-
model.value = transformOut(Array.from(toValue(val)));
|
|
755
|
-
modelWatch.resume();
|
|
756
|
-
}, { flush: "sync" });
|
|
757
|
-
const modelWatch = watch(model, (val) => {
|
|
758
|
-
contextWatch.pause();
|
|
759
|
-
context.apply(transformIn(val), applyOptions);
|
|
760
|
-
contextWatch.resume();
|
|
761
|
-
}, {
|
|
762
|
-
flush: "sync",
|
|
763
|
-
deep: toValue(multiple)
|
|
764
|
-
});
|
|
765
|
-
function onRegister(data) {
|
|
766
|
-
const ticket = data;
|
|
767
|
-
if (!pending.has(ticket.value) || toValue(ticket.disabled)) return;
|
|
768
|
-
contextWatch.pause();
|
|
769
|
-
modelWatch.pause();
|
|
770
|
-
context.select?.(ticket.id);
|
|
771
|
-
pending.delete(ticket.value);
|
|
772
|
-
modelWatch.resume();
|
|
773
|
-
contextWatch.resume();
|
|
774
|
-
}
|
|
775
|
-
context.on?.("register:ticket", onRegister);
|
|
776
|
-
function stop() {
|
|
777
|
-
contextWatch();
|
|
778
|
-
modelWatch();
|
|
779
|
-
context.off?.("register:ticket", onRegister);
|
|
780
|
-
}
|
|
781
|
-
onScopeDispose(stop, true);
|
|
782
|
-
return stop;
|
|
783
|
-
}
|
|
784
|
-
//#endregion
|
|
785
|
-
//#region src/composables/useTimer/index.ts
|
|
786
|
-
/**
|
|
787
|
-
* @module useTimer
|
|
788
|
-
*
|
|
789
|
-
* @remarks
|
|
790
|
-
* A reactive timer composable with pause/resume support.
|
|
791
|
-
*
|
|
792
|
-
* Key features:
|
|
793
|
-
* - Start/stop/pause/resume controls
|
|
794
|
-
* - Reactive remaining time tracking
|
|
795
|
-
* - One-shot (default) or repeating mode
|
|
796
|
-
* - Automatic cleanup on scope disposal
|
|
797
|
-
* - SSR-safe
|
|
798
|
-
*/
|
|
799
|
-
/**
|
|
800
|
-
* Creates a reactive timer with pause/resume support.
|
|
801
|
-
*
|
|
802
|
-
* @param handler Callback invoked when the timer fires.
|
|
803
|
-
* @param options Timer configuration.
|
|
804
|
-
* @returns Timer controls and reactive state.
|
|
805
|
-
*
|
|
806
|
-
* @see https://0.vuetifyjs.com/composables/system/use-timer
|
|
807
|
-
*
|
|
808
|
-
* @example
|
|
809
|
-
* ```ts
|
|
810
|
-
* const timer = useTimer(() => console.log('fired'), { duration: 5000 })
|
|
811
|
-
*
|
|
812
|
-
* timer.start()
|
|
813
|
-
* timer.pause()
|
|
814
|
-
* timer.resume()
|
|
815
|
-
* timer.stop()
|
|
816
|
-
* ```
|
|
817
|
-
*/
|
|
818
|
-
function useTimer(handler, options = {}) {
|
|
819
|
-
const { duration = 1e3, repeat = false } = options;
|
|
820
|
-
const remaining = shallowRef(duration);
|
|
821
|
-
const isActive = shallowRef(false);
|
|
822
|
-
const isPaused = shallowRef(false);
|
|
823
|
-
let timeoutId;
|
|
824
|
-
let trackingId;
|
|
825
|
-
let startedAt = 0;
|
|
826
|
-
let budget = duration;
|
|
827
|
-
function clearTimer() {
|
|
828
|
-
if (!/* @__PURE__ */ isUndefined(timeoutId)) {
|
|
829
|
-
globalThis.clearTimeout(timeoutId);
|
|
830
|
-
timeoutId = void 0;
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
function startTracking() {
|
|
834
|
-
stopTracking();
|
|
835
|
-
if (!IN_BROWSER) return;
|
|
836
|
-
trackingId = globalThis.setInterval(() => {
|
|
837
|
-
if (!isActive.value || isPaused.value) return;
|
|
838
|
-
const elapsed = Date.now() - startedAt;
|
|
839
|
-
remaining.value = Math.max(0, budget - elapsed);
|
|
840
|
-
}, 100);
|
|
841
|
-
}
|
|
842
|
-
function stopTracking() {
|
|
843
|
-
if (!/* @__PURE__ */ isUndefined(trackingId)) {
|
|
844
|
-
globalThis.clearInterval(trackingId);
|
|
845
|
-
trackingId = void 0;
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
function fire() {
|
|
849
|
-
clearTimer();
|
|
850
|
-
stopTracking();
|
|
851
|
-
handler();
|
|
852
|
-
if (repeat) begin(duration);
|
|
853
|
-
else {
|
|
854
|
-
isActive.value = false;
|
|
855
|
-
remaining.value = 0;
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
function begin(ms) {
|
|
859
|
-
clearTimer();
|
|
860
|
-
stopTracking();
|
|
861
|
-
budget = ms;
|
|
862
|
-
startedAt = Date.now();
|
|
863
|
-
remaining.value = ms;
|
|
864
|
-
isActive.value = true;
|
|
865
|
-
isPaused.value = false;
|
|
866
|
-
timeoutId = globalThis.setTimeout(fire, ms);
|
|
867
|
-
startTracking();
|
|
868
|
-
}
|
|
869
|
-
function start() {
|
|
870
|
-
if (duration < 0) return;
|
|
871
|
-
begin(duration);
|
|
872
|
-
}
|
|
873
|
-
function stop() {
|
|
874
|
-
clearTimer();
|
|
875
|
-
stopTracking();
|
|
876
|
-
isActive.value = false;
|
|
877
|
-
isPaused.value = false;
|
|
878
|
-
remaining.value = duration;
|
|
879
|
-
}
|
|
880
|
-
function pause() {
|
|
881
|
-
if (!isActive.value || isPaused.value) return;
|
|
882
|
-
const elapsed = Date.now() - startedAt;
|
|
883
|
-
budget = Math.max(0, budget - elapsed);
|
|
884
|
-
remaining.value = budget;
|
|
885
|
-
clearTimer();
|
|
886
|
-
stopTracking();
|
|
887
|
-
isPaused.value = true;
|
|
888
|
-
}
|
|
889
|
-
function resume() {
|
|
890
|
-
if (!isPaused.value) return;
|
|
891
|
-
isPaused.value = false;
|
|
892
|
-
startedAt = Date.now();
|
|
893
|
-
timeoutId = globalThis.setTimeout(fire, budget);
|
|
894
|
-
startTracking();
|
|
895
|
-
}
|
|
896
|
-
onScopeDispose(() => {
|
|
897
|
-
clearTimer();
|
|
898
|
-
stopTracking();
|
|
899
|
-
}, true);
|
|
900
|
-
return {
|
|
901
|
-
start,
|
|
902
|
-
stop,
|
|
903
|
-
pause,
|
|
904
|
-
resume,
|
|
905
|
-
remaining,
|
|
906
|
-
isActive,
|
|
907
|
-
isPaused
|
|
908
|
-
};
|
|
909
|
-
}
|
|
910
|
-
//#endregion
|
|
911
696
|
//#region src/composables/toReactive/index.ts
|
|
912
697
|
/**
|
|
913
698
|
* @module toReactive
|
|
@@ -924,6 +709,115 @@ function useTimer(handler, options = {}) {
|
|
|
924
709
|
*
|
|
925
710
|
* Perfect for creating reactive versions of plain objects while automatically unwrapping refs.
|
|
926
711
|
*/
|
|
712
|
+
function createMapProxy(refObject) {
|
|
713
|
+
let mapProxy;
|
|
714
|
+
const mapHandlers = {
|
|
715
|
+
get: (key) => unref(refObject.value.get(key)),
|
|
716
|
+
set: (key, value) => {
|
|
717
|
+
const map = refObject.value;
|
|
718
|
+
const existingValue = map.get(key);
|
|
719
|
+
if (isRef(existingValue)) existingValue.value = unref(value);
|
|
720
|
+
else map.set(key, value);
|
|
721
|
+
return mapProxy;
|
|
722
|
+
},
|
|
723
|
+
has: (key) => refObject.value.has(key),
|
|
724
|
+
delete: (key) => refObject.value.delete(key),
|
|
725
|
+
clear: () => refObject.value.clear(),
|
|
726
|
+
keys: () => refObject.value.keys(),
|
|
727
|
+
*values() {
|
|
728
|
+
for (const value of refObject.value.values()) yield unref(value);
|
|
729
|
+
},
|
|
730
|
+
*entries() {
|
|
731
|
+
for (const [key, value] of refObject.value.entries()) yield [key, unref(value)];
|
|
732
|
+
},
|
|
733
|
+
forEach: (callback, thisArg) => {
|
|
734
|
+
for (const [key, value] of refObject.value.entries()) callback.call(thisArg, unref(value), key, mapProxy);
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
mapHandlers[Symbol.iterator] = mapHandlers.entries;
|
|
738
|
+
mapProxy = new Proxy(/* @__PURE__ */ new Map(), { get(_, p) {
|
|
739
|
+
if (p === "size") return refObject.value.size;
|
|
740
|
+
if (Object.prototype.hasOwnProperty.call(mapHandlers, p)) return mapHandlers[p];
|
|
741
|
+
const map = refObject.value;
|
|
742
|
+
const value = Reflect.get(map, p);
|
|
743
|
+
return typeof value === "function" ? value.bind(map) : value;
|
|
744
|
+
} });
|
|
745
|
+
return reactive(mapProxy);
|
|
746
|
+
}
|
|
747
|
+
function createSetProxy(refObject) {
|
|
748
|
+
let setProxy;
|
|
749
|
+
const setHandlers = {
|
|
750
|
+
add: (value) => {
|
|
751
|
+
refObject.value.add(value);
|
|
752
|
+
return setProxy;
|
|
753
|
+
},
|
|
754
|
+
has: (value) => refObject.value.has(value),
|
|
755
|
+
delete: (value) => refObject.value.delete(value),
|
|
756
|
+
clear: () => refObject.value.clear(),
|
|
757
|
+
*keys() {
|
|
758
|
+
for (const value of refObject.value.values()) yield unref(value);
|
|
759
|
+
},
|
|
760
|
+
*values() {
|
|
761
|
+
for (const value of refObject.value.values()) yield unref(value);
|
|
762
|
+
},
|
|
763
|
+
*entries() {
|
|
764
|
+
for (const value of refObject.value.values()) {
|
|
765
|
+
const unreffedValue = unref(value);
|
|
766
|
+
yield [unreffedValue, unreffedValue];
|
|
767
|
+
}
|
|
768
|
+
},
|
|
769
|
+
forEach: (callback, thisArg) => {
|
|
770
|
+
for (const value of refObject.value) {
|
|
771
|
+
const unreffedValue = unref(value);
|
|
772
|
+
callback.call(thisArg, unreffedValue, unreffedValue, setProxy);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
setHandlers[Symbol.iterator] = setHandlers.values;
|
|
777
|
+
setProxy = new Proxy(/* @__PURE__ */ new Set(), { get(_, p) {
|
|
778
|
+
if (p === "size") return refObject.value.size;
|
|
779
|
+
if (Object.prototype.hasOwnProperty.call(setHandlers, p)) return setHandlers[p];
|
|
780
|
+
const set = refObject.value;
|
|
781
|
+
const value = Reflect.get(set, p);
|
|
782
|
+
return typeof value === "function" ? value.bind(set) : value;
|
|
783
|
+
} });
|
|
784
|
+
return reactive(setProxy);
|
|
785
|
+
}
|
|
786
|
+
function createObjectProxy(refObject) {
|
|
787
|
+
return reactive(new Proxy({}, {
|
|
788
|
+
get(_, p, receiver) {
|
|
789
|
+
return unref(Reflect.get(refObject.value, p, receiver));
|
|
790
|
+
},
|
|
791
|
+
set(_, p, value) {
|
|
792
|
+
return Reflect.set(refObject.value, p, value);
|
|
793
|
+
},
|
|
794
|
+
deleteProperty(_, p) {
|
|
795
|
+
return Reflect.deleteProperty(refObject.value, p);
|
|
796
|
+
},
|
|
797
|
+
has(_, p) {
|
|
798
|
+
return Reflect.has(refObject.value, p);
|
|
799
|
+
},
|
|
800
|
+
ownKeys() {
|
|
801
|
+
return Reflect.ownKeys(refObject.value);
|
|
802
|
+
},
|
|
803
|
+
getOwnPropertyDescriptor(_, p) {
|
|
804
|
+
const desc = Reflect.getOwnPropertyDescriptor(refObject.value, p);
|
|
805
|
+
if (!desc) return;
|
|
806
|
+
const newDesc = {
|
|
807
|
+
configurable: true,
|
|
808
|
+
enumerable: desc.enumerable
|
|
809
|
+
};
|
|
810
|
+
if ("value" in desc) {
|
|
811
|
+
newDesc.value = unref(desc.value);
|
|
812
|
+
newDesc.writable = desc.writable;
|
|
813
|
+
} else {
|
|
814
|
+
newDesc.get = desc.get;
|
|
815
|
+
newDesc.set = desc.set;
|
|
816
|
+
}
|
|
817
|
+
return newDesc;
|
|
818
|
+
}
|
|
819
|
+
}));
|
|
820
|
+
}
|
|
927
821
|
/**
|
|
928
822
|
* Converts a `MaybeRef` to a `UnwrapNestedRefs`.
|
|
929
823
|
*
|
|
@@ -946,100 +840,11 @@ function useTimer(handler, options = {}) {
|
|
|
946
840
|
*/
|
|
947
841
|
function toReactive(objectRef) {
|
|
948
842
|
if (!isRef(objectRef)) return reactive(objectRef);
|
|
949
|
-
const
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
if (p === "set") return (key, value) => {
|
|
955
|
-
const existingValue = map.get(key);
|
|
956
|
-
if (isRef(existingValue)) existingValue.value = unref(value);
|
|
957
|
-
else map.set(key, value);
|
|
958
|
-
return mapProxy;
|
|
959
|
-
};
|
|
960
|
-
if (p === "has") return (key) => map.has(key);
|
|
961
|
-
if (p === "delete") return (key) => map.delete(key);
|
|
962
|
-
if (p === "clear") return () => map.clear();
|
|
963
|
-
if (p === "size") return map.size;
|
|
964
|
-
if (p === "keys") return () => map.keys();
|
|
965
|
-
if (p === "values") return function* () {
|
|
966
|
-
for (const value of map.values()) yield unref(value);
|
|
967
|
-
};
|
|
968
|
-
if (p === "entries") return function* () {
|
|
969
|
-
for (const [key, value] of map.entries()) yield [key, unref(value)];
|
|
970
|
-
};
|
|
971
|
-
if (p === "forEach") return (callback, thisArg) => {
|
|
972
|
-
for (const [key, value] of map.entries()) callback.call(thisArg, unref(value), key, mapProxy);
|
|
973
|
-
};
|
|
974
|
-
if (p === Symbol.iterator) return function* () {
|
|
975
|
-
for (const [key, value] of map.entries()) yield [key, unref(value)];
|
|
976
|
-
};
|
|
977
|
-
return Reflect.get(map, p);
|
|
978
|
-
} });
|
|
979
|
-
return reactive(mapProxy);
|
|
980
|
-
}
|
|
981
|
-
if (target instanceof Set) {
|
|
982
|
-
const setProxy = new Proxy(/* @__PURE__ */ new Set(), { get(_, p) {
|
|
983
|
-
const set = objectRef.value;
|
|
984
|
-
if (p === "add") return (value) => {
|
|
985
|
-
set.add(value);
|
|
986
|
-
return setProxy;
|
|
987
|
-
};
|
|
988
|
-
if (p === "has") return (value) => set.has(value);
|
|
989
|
-
if (p === "delete") return (value) => set.delete(value);
|
|
990
|
-
if (p === "clear") return () => set.clear();
|
|
991
|
-
if (p === "size") return set.size;
|
|
992
|
-
if (p === "keys" || p === "values") return function* () {
|
|
993
|
-
for (const value of set.values()) yield unref(value);
|
|
994
|
-
};
|
|
995
|
-
if (p === "entries") return function* () {
|
|
996
|
-
for (const value of set.values()) {
|
|
997
|
-
const unreffedValue = unref(value);
|
|
998
|
-
yield [unreffedValue, unreffedValue];
|
|
999
|
-
}
|
|
1000
|
-
};
|
|
1001
|
-
if (p === "forEach") return (callback, thisArg) => {
|
|
1002
|
-
for (const value of set) {
|
|
1003
|
-
const unreffedValue = unref(value);
|
|
1004
|
-
callback.call(thisArg, unreffedValue, unreffedValue, setProxy);
|
|
1005
|
-
}
|
|
1006
|
-
};
|
|
1007
|
-
if (p === Symbol.iterator) return function* () {
|
|
1008
|
-
for (const value of set.values()) yield unref(value);
|
|
1009
|
-
};
|
|
1010
|
-
return Reflect.get(set, p);
|
|
1011
|
-
} });
|
|
1012
|
-
return reactive(setProxy);
|
|
1013
|
-
}
|
|
1014
|
-
return reactive(new Proxy({}, {
|
|
1015
|
-
get(_, p, receiver) {
|
|
1016
|
-
return unref(Reflect.get(objectRef.value, p, receiver));
|
|
1017
|
-
},
|
|
1018
|
-
set(_, p, value) {
|
|
1019
|
-
const currentTarget = objectRef.value;
|
|
1020
|
-
currentTarget[p] = value;
|
|
1021
|
-
return true;
|
|
1022
|
-
},
|
|
1023
|
-
deleteProperty(_, p) {
|
|
1024
|
-
return Reflect.deleteProperty(objectRef.value, p);
|
|
1025
|
-
},
|
|
1026
|
-
has(_, p) {
|
|
1027
|
-
return Reflect.has(objectRef.value, p);
|
|
1028
|
-
},
|
|
1029
|
-
ownKeys() {
|
|
1030
|
-
return Object.keys(objectRef.value);
|
|
1031
|
-
},
|
|
1032
|
-
getOwnPropertyDescriptor(_, p) {
|
|
1033
|
-
const desc = Reflect.getOwnPropertyDescriptor(objectRef.value, p);
|
|
1034
|
-
if (!desc) return;
|
|
1035
|
-
const newDesc = {
|
|
1036
|
-
...desc,
|
|
1037
|
-
configurable: true
|
|
1038
|
-
};
|
|
1039
|
-
if ("value" in newDesc) newDesc.value = unref(newDesc.value);
|
|
1040
|
-
return newDesc;
|
|
1041
|
-
}
|
|
1042
|
-
}));
|
|
843
|
+
const refObject = objectRef;
|
|
844
|
+
const target = refObject.value;
|
|
845
|
+
if (target instanceof Map) return createMapProxy(refObject);
|
|
846
|
+
if (target instanceof Set) return createSetProxy(refObject);
|
|
847
|
+
return createObjectProxy(refObject);
|
|
1043
848
|
}
|
|
1044
849
|
//#endregion
|
|
1045
850
|
//#region src/composables/useBreakpoints/index.ts
|
|
@@ -1243,202 +1048,459 @@ const [createBreakpointsContext, createBreakpointsPlugin, useBreakpoints] = crea
|
|
|
1243
1048
|
}
|
|
1244
1049
|
});
|
|
1245
1050
|
//#endregion
|
|
1246
|
-
//#region src/composables/
|
|
1051
|
+
//#region src/composables/useClickOutside/index.ts
|
|
1247
1052
|
/**
|
|
1248
|
-
* @module
|
|
1053
|
+
* @module useClickOutside
|
|
1249
1054
|
*
|
|
1250
1055
|
* @remarks
|
|
1251
|
-
*
|
|
1056
|
+
* Detects clicks outside of specified element(s) with automatic cleanup.
|
|
1252
1057
|
*
|
|
1253
1058
|
* Key features:
|
|
1254
|
-
* -
|
|
1255
|
-
* -
|
|
1256
|
-
* -
|
|
1257
|
-
*
|
|
1258
|
-
*
|
|
1259
|
-
*
|
|
1260
|
-
* import { Vuetify0DateAdapter } from '@vuetify/v0/date'
|
|
1261
|
-
* import { createDatePlugin } from '@vuetify/v0'
|
|
1262
|
-
*
|
|
1263
|
-
* const app = createApp(App)
|
|
1264
|
-
* app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))
|
|
1265
|
-
*
|
|
1266
|
-
* // In a component:
|
|
1267
|
-
* const { adapter } = useDate()
|
|
1268
|
-
* const today = adapter.date()
|
|
1269
|
-
* const formatted = adapter.format(today, 'fullDate')
|
|
1270
|
-
* ```
|
|
1271
|
-
*
|
|
1272
|
-
* @example Custom adapter
|
|
1273
|
-
* ```ts
|
|
1274
|
-
* import type { DateAdapter } from '@vuetify/v0'
|
|
1059
|
+
* - Two-phase detection (pointerdown → pointerup) prevents drag-out false positives
|
|
1060
|
+
* - Touch scroll threshold ignores swipes/scrolls on mobile
|
|
1061
|
+
* - Capture phase listeners work with stopPropagation
|
|
1062
|
+
* - Pause/resume/stop functionality
|
|
1063
|
+
* - Optional iframe focus detection
|
|
1064
|
+
* - SSR-safe (no-op when not in browser)
|
|
1275
1065
|
*
|
|
1276
|
-
*
|
|
1277
|
-
* // ... implementation
|
|
1278
|
-
* }
|
|
1066
|
+
* Common use cases: closing popovers, dropdowns, modals, and menus.
|
|
1279
1067
|
*
|
|
1280
|
-
*
|
|
1281
|
-
*
|
|
1282
|
-
|
|
1283
|
-
/**
|
|
1284
|
-
* Default short locale codes mapped to full Intl locale strings.
|
|
1285
|
-
* Used when useLocale provides a short code without region (e.g., 'en' instead of 'en-US').
|
|
1286
|
-
*/
|
|
1287
|
-
const defaultLocales = {
|
|
1288
|
-
en: "en-US",
|
|
1289
|
-
es: "es-ES",
|
|
1290
|
-
fr: "fr-FR",
|
|
1291
|
-
de: "de-DE",
|
|
1292
|
-
it: "it-IT",
|
|
1293
|
-
pt: "pt-BR",
|
|
1294
|
-
ja: "ja-JP",
|
|
1295
|
-
ko: "ko-KR",
|
|
1296
|
-
zh: "zh-CN",
|
|
1297
|
-
ru: "ru-RU",
|
|
1298
|
-
ar: "ar-SA"
|
|
1299
|
-
};
|
|
1300
|
-
/**
|
|
1301
|
-
* Derive firstDayOfWeek from an Intl locale string.
|
|
1302
|
-
* Returns 0-6 (0=Sun) or 0 as fallback.
|
|
1068
|
+
* Accessibility: This composable handles pointer interactions only. For accessible
|
|
1069
|
+
* components (dialogs, popovers, menus), pair with `useHotkey` for Escape key
|
|
1070
|
+
* dismissal per WCAG/APG requirements.
|
|
1303
1071
|
*/
|
|
1304
|
-
function deriveFirstDayOfWeek(locale) {
|
|
1305
|
-
try {
|
|
1306
|
-
const info = new Intl.Locale(locale).getWeekInfo?.();
|
|
1307
|
-
return info ? info.firstDay % 7 : 0;
|
|
1308
|
-
} catch {
|
|
1309
|
-
return 0;
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
1072
|
/**
|
|
1313
|
-
*
|
|
1073
|
+
* Detects clicks outside of the specified element(s).
|
|
1314
1074
|
*
|
|
1315
|
-
*
|
|
1316
|
-
*
|
|
1317
|
-
* @template E The date context type.
|
|
1318
|
-
* @returns A date context.
|
|
1075
|
+
* Uses two-phase detection (pointerdown → pointerup) to prevent false positives
|
|
1076
|
+
* when users drag from inside to outside an element.
|
|
1319
1077
|
*
|
|
1320
|
-
* @
|
|
1078
|
+
* @param target Element ref(s) to detect clicks outside of. Accepts a single ref/getter or array of refs/getters.
|
|
1079
|
+
* @param handler Callback invoked when a click outside is detected.
|
|
1080
|
+
* @param options Configuration options.
|
|
1081
|
+
* @returns An object with methods to control the listener.
|
|
1321
1082
|
*
|
|
1322
|
-
* @
|
|
1323
|
-
* ```ts
|
|
1324
|
-
* import { Vuetify0DateAdapter } from '@vuetify/v0/date'
|
|
1083
|
+
* @see https://0.vuetifyjs.com/composables/system/use-click-outside
|
|
1325
1084
|
*
|
|
1326
|
-
*
|
|
1327
|
-
*
|
|
1085
|
+
* @example Native element ref
|
|
1086
|
+
* ```ts
|
|
1087
|
+
* const menuRef = useTemplateRef<HTMLElement>('menu')
|
|
1328
1088
|
*
|
|
1329
|
-
*
|
|
1330
|
-
* const { adapter } = createDate({
|
|
1331
|
-
* adapter: new Vuetify0DateAdapter(),
|
|
1332
|
-
* locale: 'de-DE',
|
|
1333
|
-
* })
|
|
1089
|
+
* useClickOutside(menuRef, () => { isOpen.value = false })
|
|
1334
1090
|
* ```
|
|
1335
|
-
*/
|
|
1336
|
-
function createDate(options) {
|
|
1337
|
-
const { locales = defaultLocales, adapter, locale: initialLocale, firstDayOfWeek: explicitFirstDay } = options;
|
|
1338
|
-
let selectedId;
|
|
1339
|
-
try {
|
|
1340
|
-
if (instanceExists()) selectedId = useLocale().selectedId;
|
|
1341
|
-
} catch {}
|
|
1342
|
-
const locale = computed(() => {
|
|
1343
|
-
const selected = selectedId?.value;
|
|
1344
|
-
if (!/* @__PURE__ */ isNullOrUndefined(selected)) {
|
|
1345
|
-
const str = String(selected);
|
|
1346
|
-
return str.includes("-") ? str : locales[str] ?? str;
|
|
1347
|
-
}
|
|
1348
|
-
const fallback = initialLocale ?? adapter.locale ?? "en-US";
|
|
1349
|
-
return fallback.includes("-") ? fallback : locales[fallback] ?? fallback;
|
|
1350
|
-
});
|
|
1351
|
-
const firstDayOfWeek = computed(() => {
|
|
1352
|
-
if (!/* @__PURE__ */ isUndefined(explicitFirstDay)) return explicitFirstDay;
|
|
1353
|
-
const loc = locale.value;
|
|
1354
|
-
return loc ? deriveFirstDayOfWeek(loc) : 0;
|
|
1355
|
-
});
|
|
1356
|
-
if (instanceExists()) onScopeDispose(watchEffect(() => {
|
|
1357
|
-
const loc = locale.value;
|
|
1358
|
-
if (loc && adapter.locale !== loc) adapter.locale = loc;
|
|
1359
|
-
const fdow = firstDayOfWeek.value;
|
|
1360
|
-
if (adapter.firstDayOfWeek !== fdow) adapter.firstDayOfWeek = fdow;
|
|
1361
|
-
}));
|
|
1362
|
-
else {
|
|
1363
|
-
const loc = locale.value;
|
|
1364
|
-
if (loc && adapter.locale !== loc) adapter.locale = loc;
|
|
1365
|
-
const fdow = firstDayOfWeek.value;
|
|
1366
|
-
if (adapter.firstDayOfWeek !== fdow) adapter.firstDayOfWeek = fdow;
|
|
1367
|
-
}
|
|
1368
|
-
return {
|
|
1369
|
-
adapter,
|
|
1370
|
-
locale,
|
|
1371
|
-
firstDayOfWeek
|
|
1372
|
-
};
|
|
1373
|
-
}
|
|
1374
|
-
/**
|
|
1375
|
-
* Creates a new date context trinity.
|
|
1376
|
-
*
|
|
1377
|
-
* @param options Adapter, locale, and namespace configuration.
|
|
1378
|
-
* @template Z The date type used by the adapter.
|
|
1379
|
-
* @template E The date context type.
|
|
1380
|
-
* @returns A trinity [useContext, provideContext, defaultContext].
|
|
1381
|
-
*
|
|
1382
|
-
* @see https://0.vuetifyjs.com/composables/plugins/use-date
|
|
1383
1091
|
*
|
|
1384
|
-
* @example
|
|
1092
|
+
* @example Component ref (e.g., Atom)
|
|
1385
1093
|
* ```ts
|
|
1386
|
-
*
|
|
1094
|
+
* const atomRef = useTemplateRef<AtomExpose>('atom')
|
|
1387
1095
|
*
|
|
1388
|
-
*
|
|
1389
|
-
*
|
|
1390
|
-
*
|
|
1391
|
-
* }
|
|
1096
|
+
* // Pass the exposed element TemplateRef via getter
|
|
1097
|
+
* useClickOutside(
|
|
1098
|
+
* () => atomRef.value?.element,
|
|
1099
|
+
* () => { isOpen.value = false }
|
|
1100
|
+
* )
|
|
1392
1101
|
* ```
|
|
1393
|
-
*/
|
|
1394
|
-
function createDateContext(options) {
|
|
1395
|
-
const { namespace = "v0:date", ...dateOptions } = options;
|
|
1396
|
-
const [useDateContext, _provideDateContext] = createContext(namespace);
|
|
1397
|
-
const context = createDate(dateOptions);
|
|
1398
|
-
function provideDateContext(_context = context, app) {
|
|
1399
|
-
return _provideDateContext(_context, app);
|
|
1400
|
-
}
|
|
1401
|
-
return createTrinity(useDateContext, provideDateContext, context);
|
|
1402
|
-
}
|
|
1403
|
-
/**
|
|
1404
|
-
* Creates a new date plugin.
|
|
1405
1102
|
*
|
|
1406
|
-
* @
|
|
1407
|
-
*
|
|
1408
|
-
*
|
|
1409
|
-
*
|
|
1103
|
+
* @example Multiple targets
|
|
1104
|
+
* ```ts
|
|
1105
|
+
* const popoverRef = useTemplateRef<AtomExpose>('popover')
|
|
1106
|
+
* const anchorRef = useTemplateRef<HTMLElement>('anchor')
|
|
1410
1107
|
*
|
|
1411
|
-
*
|
|
1108
|
+
* useClickOutside(
|
|
1109
|
+
* [() => popoverRef.value?.element, anchorRef],
|
|
1110
|
+
* () => { isOpen.value = false }
|
|
1111
|
+
* )
|
|
1112
|
+
* ```
|
|
1412
1113
|
*
|
|
1413
|
-
* @example
|
|
1114
|
+
* @example Ignoring elements (CSS selectors or refs)
|
|
1414
1115
|
* ```ts
|
|
1415
|
-
*
|
|
1116
|
+
* useClickOutside(
|
|
1117
|
+
* () => navRef.value?.element,
|
|
1118
|
+
* () => { isOpen.value = false },
|
|
1119
|
+
* { ignore: ['[data-app-bar]'] }
|
|
1120
|
+
* )
|
|
1121
|
+
* ```
|
|
1416
1122
|
*
|
|
1417
|
-
*
|
|
1418
|
-
*
|
|
1123
|
+
* @example Native dialog with bounds detection
|
|
1124
|
+
* ```ts
|
|
1125
|
+
* // For native <dialog> elements, use bounds mode to detect backdrop clicks
|
|
1126
|
+
* const dialogRef = useTemplateRef<HTMLDialogElement>('dialog')
|
|
1419
1127
|
*
|
|
1420
|
-
*
|
|
1421
|
-
*
|
|
1422
|
-
*
|
|
1423
|
-
*
|
|
1424
|
-
*
|
|
1128
|
+
* useClickOutside(
|
|
1129
|
+
* dialogRef,
|
|
1130
|
+
* () => { dialogRef.value?.close() },
|
|
1131
|
+
* { bounds: true }
|
|
1132
|
+
* )
|
|
1425
1133
|
* ```
|
|
1426
1134
|
*/
|
|
1427
|
-
function
|
|
1428
|
-
const {
|
|
1429
|
-
const
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1135
|
+
function useClickOutside(target, handler, options = {}) {
|
|
1136
|
+
const { capture = true, touchScrollThreshold = 30, detectIframe = false, ignore = [], bounds = false } = options;
|
|
1137
|
+
const isPaused = shallowRef(false);
|
|
1138
|
+
const isActive = toRef(() => !isPaused.value);
|
|
1139
|
+
let initialTarget = null;
|
|
1140
|
+
let startPosition = {
|
|
1141
|
+
x: 0,
|
|
1142
|
+
y: 0
|
|
1143
|
+
};
|
|
1144
|
+
let cleanupPointerDown;
|
|
1145
|
+
let cleanupPointerUp;
|
|
1146
|
+
let cleanupBlur;
|
|
1147
|
+
/**
|
|
1148
|
+
* Resolve target(s) to an array of HTMLElements.
|
|
1149
|
+
*/
|
|
1150
|
+
function getTargets() {
|
|
1151
|
+
return toArray(target).map((source) => toValue(source)).filter((el) => !!el && /* @__PURE__ */ isFunction(el.contains));
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Resolve ignore targets to a tuple of [selectors, elements].
|
|
1155
|
+
* Called once per event to avoid repeated toValue() calls in hot path.
|
|
1156
|
+
*/
|
|
1157
|
+
function resolveIgnoreTargets() {
|
|
1158
|
+
const ignoreTargets = toValue(ignore);
|
|
1159
|
+
if (ignoreTargets.length === 0) return [[], []];
|
|
1160
|
+
const selectors = [];
|
|
1161
|
+
const elements = [];
|
|
1162
|
+
for (const ignoreTarget of ignoreTargets) if (/* @__PURE__ */ isString(ignoreTarget)) selectors.push(ignoreTarget);
|
|
1163
|
+
else {
|
|
1164
|
+
const ignoreEl = toValue(ignoreTarget);
|
|
1165
|
+
if (ignoreEl) elements.push(ignoreEl);
|
|
1166
|
+
}
|
|
1167
|
+
return [selectors, elements];
|
|
1168
|
+
}
|
|
1169
|
+
/**
|
|
1170
|
+
* Check if an element matches resolved ignore targets.
|
|
1171
|
+
*/
|
|
1172
|
+
function isIgnored(el, selectors, elements) {
|
|
1173
|
+
if (!el) return false;
|
|
1174
|
+
for (const selector of selectors) try {
|
|
1175
|
+
if (el.matches(selector) || !/* @__PURE__ */ isNull(el.closest(selector))) return true;
|
|
1176
|
+
} catch {}
|
|
1177
|
+
for (const ignoreEl of elements) if (ignoreEl === el || ignoreEl.contains(el)) return true;
|
|
1178
|
+
return false;
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Check if any element in the event path should be ignored.
|
|
1182
|
+
*/
|
|
1183
|
+
function shouldIgnore(path) {
|
|
1184
|
+
const [selectors, elements] = resolveIgnoreTargets();
|
|
1185
|
+
if (selectors.length === 0 && elements.length === 0) return false;
|
|
1186
|
+
return path.some((node) => node instanceof Element && isIgnored(node, selectors, elements));
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Check if the event target is outside all target elements (DOM containment).
|
|
1190
|
+
*/
|
|
1191
|
+
function isOutside(eventTarget) {
|
|
1192
|
+
/* v8 ignore start -- defensive guards */
|
|
1193
|
+
if (!eventTarget) return false;
|
|
1194
|
+
if (!(eventTarget instanceof Node)) return false;
|
|
1195
|
+
/* v8 ignore stop */
|
|
1196
|
+
const targets = getTargets();
|
|
1197
|
+
if (targets.length === 0) return false;
|
|
1198
|
+
return targets.every((el) => {
|
|
1199
|
+
if (/* @__PURE__ */ isNullOrUndefined(el) || !/* @__PURE__ */ isFunction(el.contains)) return false;
|
|
1200
|
+
return el !== eventTarget && !el.contains(eventTarget);
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* Check if coordinates are outside all target elements' bounding rects.
|
|
1205
|
+
*/
|
|
1206
|
+
function isOutsideBounds(x, y) {
|
|
1207
|
+
const targets = getTargets();
|
|
1208
|
+
if (targets.length === 0) return false;
|
|
1209
|
+
return targets.every((el) => {
|
|
1210
|
+
const { left, right, top, bottom } = el.getBoundingClientRect();
|
|
1211
|
+
return x < left || x > right || y < top || y > bottom;
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Validate that the target is still in the DOM.
|
|
1216
|
+
*/
|
|
1217
|
+
function isValidTarget(eventTarget) {
|
|
1218
|
+
if (!(eventTarget instanceof Element)) return false;
|
|
1219
|
+
if (!eventTarget.isConnected) return false;
|
|
1220
|
+
return true;
|
|
1221
|
+
}
|
|
1222
|
+
/* v8 ignore start -- event handlers tested via integration, not unit */
|
|
1223
|
+
/**
|
|
1224
|
+
* Handle pointerdown - store initial target and position.
|
|
1225
|
+
*/
|
|
1226
|
+
function onPointerDown(event) {
|
|
1227
|
+
if (isPaused.value) return;
|
|
1228
|
+
if (event.defaultPrevented) return;
|
|
1229
|
+
initialTarget = event.composedPath()[0] ?? event.target;
|
|
1230
|
+
startPosition = {
|
|
1231
|
+
x: event.clientX,
|
|
1232
|
+
y: event.clientY
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Handle pointerup - check if it's an outside click.
|
|
1237
|
+
*/
|
|
1238
|
+
function onPointerUp(event) {
|
|
1239
|
+
if (isPaused.value) return;
|
|
1240
|
+
if (event.defaultPrevented) return;
|
|
1241
|
+
if (!initialTarget) return;
|
|
1242
|
+
const pointerdownTarget = initialTarget;
|
|
1243
|
+
initialTarget = null;
|
|
1244
|
+
if (!isValidTarget(pointerdownTarget)) return;
|
|
1245
|
+
const path = event.composedPath();
|
|
1246
|
+
const pointerupTarget = path[0] ?? event.target;
|
|
1247
|
+
if (event.pointerType === "touch") {
|
|
1248
|
+
const dx = Math.abs(event.clientX - startPosition.x);
|
|
1249
|
+
const dy = Math.abs(event.clientY - startPosition.y);
|
|
1250
|
+
if (dx >= touchScrollThreshold || dy >= touchScrollThreshold) return;
|
|
1251
|
+
}
|
|
1252
|
+
if ((bounds ? isOutsideBounds(startPosition.x, startPosition.y) && isOutsideBounds(event.clientX, event.clientY) : isOutside(pointerdownTarget) && isOutside(pointerupTarget)) && !shouldIgnore(path)) handler(event);
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* Handle window blur - detect focus moving to iframe.
|
|
1256
|
+
*/
|
|
1257
|
+
function onBlur(event) {
|
|
1258
|
+
if (isPaused.value) return;
|
|
1259
|
+
if (event.defaultPrevented) return;
|
|
1260
|
+
if (document.activeElement instanceof HTMLIFrameElement) {
|
|
1261
|
+
const iframeIsOutside = getTargets().every((el) => !el.contains(document.activeElement));
|
|
1262
|
+
const [selectors, elements] = resolveIgnoreTargets();
|
|
1263
|
+
if (iframeIsOutside && !isIgnored(document.activeElement, selectors, elements)) handler(event);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
/* v8 ignore stop */
|
|
1267
|
+
function setup() {
|
|
1268
|
+
cleanupPointerDown = useDocumentEventListener("pointerdown", onPointerDown, capture);
|
|
1269
|
+
cleanupPointerUp = useDocumentEventListener("pointerup", onPointerUp, capture);
|
|
1270
|
+
if (!detectIframe) return;
|
|
1271
|
+
cleanupBlur = useWindowEventListener("blur", onBlur, capture);
|
|
1272
|
+
}
|
|
1273
|
+
function cleanup() {
|
|
1274
|
+
cleanupPointerDown?.();
|
|
1275
|
+
cleanupPointerUp?.();
|
|
1276
|
+
cleanupBlur?.();
|
|
1277
|
+
cleanupPointerDown = void 0;
|
|
1278
|
+
cleanupPointerUp = void 0;
|
|
1279
|
+
cleanupBlur = void 0;
|
|
1280
|
+
}
|
|
1281
|
+
function pause() {
|
|
1282
|
+
if (isPaused.value) return;
|
|
1283
|
+
isPaused.value = true;
|
|
1284
|
+
initialTarget = null;
|
|
1285
|
+
cleanup();
|
|
1286
|
+
}
|
|
1287
|
+
function resume() {
|
|
1288
|
+
if (!isPaused.value) return;
|
|
1289
|
+
isPaused.value = false;
|
|
1290
|
+
setup();
|
|
1291
|
+
}
|
|
1292
|
+
function stop() {
|
|
1293
|
+
isPaused.value = true;
|
|
1294
|
+
initialTarget = null;
|
|
1295
|
+
cleanup();
|
|
1296
|
+
}
|
|
1297
|
+
setup();
|
|
1298
|
+
onScopeDispose(stop, true);
|
|
1299
|
+
return {
|
|
1300
|
+
isActive: shallowReadonly(isActive),
|
|
1301
|
+
isPaused: shallowReadonly(isPaused),
|
|
1302
|
+
pause,
|
|
1303
|
+
resume,
|
|
1304
|
+
stop
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
//#endregion
|
|
1308
|
+
//#region src/composables/useDate/index.ts
|
|
1309
|
+
/**
|
|
1310
|
+
* @module useDate
|
|
1311
|
+
*
|
|
1312
|
+
* @remarks
|
|
1313
|
+
* Date manipulation composable with adapter pattern for date operations.
|
|
1314
|
+
*
|
|
1315
|
+
* Key features:
|
|
1316
|
+
* - Adapter pattern for date library abstraction
|
|
1317
|
+
* - Locale-aware formatting via Intl.DateTimeFormat
|
|
1318
|
+
* - Integration with useLocale for automatic locale sync
|
|
1319
|
+
*
|
|
1320
|
+
* @example Using the built-in Temporal adapter
|
|
1321
|
+
* ```ts
|
|
1322
|
+
* import { Vuetify0DateAdapter } from '@vuetify/v0/date'
|
|
1323
|
+
* import { createDatePlugin } from '@vuetify/v0'
|
|
1324
|
+
*
|
|
1325
|
+
* const app = createApp(App)
|
|
1326
|
+
* app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))
|
|
1327
|
+
*
|
|
1328
|
+
* // In a component:
|
|
1329
|
+
* const { adapter } = useDate()
|
|
1330
|
+
* const today = adapter.date()
|
|
1331
|
+
* const formatted = adapter.format(today, 'fullDate')
|
|
1332
|
+
* ```
|
|
1333
|
+
*
|
|
1334
|
+
* @example Custom adapter
|
|
1335
|
+
* ```ts
|
|
1336
|
+
* import type { DateAdapter } from '@vuetify/v0'
|
|
1337
|
+
*
|
|
1338
|
+
* class DateFnsAdapter implements DateAdapter<Date> {
|
|
1339
|
+
* // ... implementation
|
|
1340
|
+
* }
|
|
1341
|
+
*
|
|
1342
|
+
* app.use(createDatePlugin({ adapter: new DateFnsAdapter() }))
|
|
1343
|
+
* ```
|
|
1344
|
+
*/
|
|
1345
|
+
/**
|
|
1346
|
+
* Default short locale codes mapped to full Intl locale strings.
|
|
1347
|
+
* Used when useLocale provides a short code without region (e.g., 'en' instead of 'en-US').
|
|
1348
|
+
*/
|
|
1349
|
+
const defaultLocales = {
|
|
1350
|
+
en: "en-US",
|
|
1351
|
+
es: "es-ES",
|
|
1352
|
+
fr: "fr-FR",
|
|
1353
|
+
de: "de-DE",
|
|
1354
|
+
it: "it-IT",
|
|
1355
|
+
pt: "pt-BR",
|
|
1356
|
+
ja: "ja-JP",
|
|
1357
|
+
ko: "ko-KR",
|
|
1358
|
+
zh: "zh-CN",
|
|
1359
|
+
ru: "ru-RU",
|
|
1360
|
+
ar: "ar-SA"
|
|
1361
|
+
};
|
|
1362
|
+
/**
|
|
1363
|
+
* Derive firstDayOfWeek from an Intl locale string.
|
|
1364
|
+
* Returns 0-6 (0=Sun) or 0 as fallback.
|
|
1365
|
+
*/
|
|
1366
|
+
function deriveFirstDayOfWeek(locale) {
|
|
1367
|
+
try {
|
|
1368
|
+
const info = new Intl.Locale(locale).getWeekInfo?.();
|
|
1369
|
+
return info ? info.firstDay % 7 : 0;
|
|
1370
|
+
} catch {
|
|
1371
|
+
return 0;
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* Creates a new date context.
|
|
1376
|
+
*
|
|
1377
|
+
* @param options Adapter and locale configuration.
|
|
1378
|
+
* @template Z The date type used by the adapter.
|
|
1379
|
+
* @template E The date context type.
|
|
1380
|
+
* @returns A date context.
|
|
1381
|
+
*
|
|
1382
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-date
|
|
1383
|
+
*
|
|
1384
|
+
* @example
|
|
1385
|
+
* ```ts
|
|
1386
|
+
* import { Vuetify0DateAdapter } from '@vuetify/v0/date'
|
|
1387
|
+
*
|
|
1388
|
+
* const { adapter } = createDate({ adapter: new Vuetify0DateAdapter() })
|
|
1389
|
+
* const today = adapter.date()
|
|
1390
|
+
*
|
|
1391
|
+
* // With locale options
|
|
1392
|
+
* const { adapter } = createDate({
|
|
1393
|
+
* adapter: new Vuetify0DateAdapter(),
|
|
1394
|
+
* locale: 'de-DE',
|
|
1395
|
+
* })
|
|
1396
|
+
* ```
|
|
1397
|
+
*/
|
|
1398
|
+
function createDate(options) {
|
|
1399
|
+
const { locales = defaultLocales, adapter, locale: initialLocale, firstDayOfWeek: explicitFirstDay } = options;
|
|
1400
|
+
let selectedId;
|
|
1401
|
+
try {
|
|
1402
|
+
if (instanceExists()) selectedId = useLocale().selectedId;
|
|
1403
|
+
} catch {}
|
|
1404
|
+
const locale = computed(() => {
|
|
1405
|
+
const selected = selectedId?.value;
|
|
1406
|
+
if (!/* @__PURE__ */ isNullOrUndefined(selected)) {
|
|
1407
|
+
const str = String(selected);
|
|
1408
|
+
return str.includes("-") ? str : locales[str] ?? str;
|
|
1409
|
+
}
|
|
1410
|
+
const fallback = initialLocale ?? adapter.locale ?? "en-US";
|
|
1411
|
+
return fallback.includes("-") ? fallback : locales[fallback] ?? fallback;
|
|
1412
|
+
});
|
|
1413
|
+
const firstDayOfWeek = computed(() => {
|
|
1414
|
+
if (!/* @__PURE__ */ isUndefined(explicitFirstDay)) return explicitFirstDay;
|
|
1415
|
+
const loc = locale.value;
|
|
1416
|
+
return loc ? deriveFirstDayOfWeek(loc) : 0;
|
|
1417
|
+
});
|
|
1418
|
+
if (instanceExists()) onScopeDispose(watchEffect(() => {
|
|
1419
|
+
const loc = locale.value;
|
|
1420
|
+
if (loc && adapter.locale !== loc) adapter.locale = loc;
|
|
1421
|
+
const fdow = firstDayOfWeek.value;
|
|
1422
|
+
if (adapter.firstDayOfWeek !== fdow) adapter.firstDayOfWeek = fdow;
|
|
1423
|
+
}));
|
|
1424
|
+
else {
|
|
1425
|
+
const loc = locale.value;
|
|
1426
|
+
if (loc && adapter.locale !== loc) adapter.locale = loc;
|
|
1427
|
+
const fdow = firstDayOfWeek.value;
|
|
1428
|
+
if (adapter.firstDayOfWeek !== fdow) adapter.firstDayOfWeek = fdow;
|
|
1429
|
+
}
|
|
1430
|
+
return {
|
|
1431
|
+
adapter,
|
|
1432
|
+
locale,
|
|
1433
|
+
firstDayOfWeek
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
/**
|
|
1437
|
+
* Creates a new date context trinity.
|
|
1438
|
+
*
|
|
1439
|
+
* @param options Adapter, locale, and namespace configuration.
|
|
1440
|
+
* @template Z The date type used by the adapter.
|
|
1441
|
+
* @template E The date context type.
|
|
1442
|
+
* @returns A trinity [useContext, provideContext, defaultContext].
|
|
1443
|
+
*
|
|
1444
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-date
|
|
1445
|
+
*
|
|
1446
|
+
* @example
|
|
1447
|
+
* ```ts
|
|
1448
|
+
* import { Vuetify0DateAdapter } from '@vuetify/v0/date'
|
|
1449
|
+
*
|
|
1450
|
+
* const [useAppDate, provideAppDate] = createDateContext({
|
|
1451
|
+
* adapter: new Vuetify0DateAdapter(),
|
|
1452
|
+
* namespace: 'app:date',
|
|
1453
|
+
* })
|
|
1454
|
+
* ```
|
|
1455
|
+
*/
|
|
1456
|
+
function createDateContext(options) {
|
|
1457
|
+
const { namespace = "v0:date", ...dateOptions } = options;
|
|
1458
|
+
const [useDateContext, _provideDateContext] = createContext(namespace);
|
|
1459
|
+
const context = createDate(dateOptions);
|
|
1460
|
+
function provideDateContext(_context = context, app) {
|
|
1461
|
+
return _provideDateContext(_context, app);
|
|
1462
|
+
}
|
|
1463
|
+
return createTrinity(useDateContext, provideDateContext, context);
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* Creates a new date plugin.
|
|
1467
|
+
*
|
|
1468
|
+
* @param options Adapter, locale, and namespace configuration.
|
|
1469
|
+
* @template Z The date type used by the adapter.
|
|
1470
|
+
* @template E The date context type.
|
|
1471
|
+
* @returns A Vue plugin.
|
|
1472
|
+
*
|
|
1473
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-date
|
|
1474
|
+
*
|
|
1475
|
+
* @example
|
|
1476
|
+
* ```ts
|
|
1477
|
+
* import { Vuetify0DateAdapter } from '@vuetify/v0/date'
|
|
1478
|
+
*
|
|
1479
|
+
* const app = createApp(App)
|
|
1480
|
+
* app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))
|
|
1481
|
+
*
|
|
1482
|
+
* // With locale options
|
|
1483
|
+
* app.use(createDatePlugin({
|
|
1484
|
+
* adapter: new Vuetify0DateAdapter(),
|
|
1485
|
+
* locale: 'de-DE',
|
|
1486
|
+
* }))
|
|
1487
|
+
* ```
|
|
1488
|
+
*/
|
|
1489
|
+
function createDatePlugin(options) {
|
|
1490
|
+
const { namespace = "v0:date", ...dateOptions } = options;
|
|
1491
|
+
const [, provideDateContext, context] = createDateContext({
|
|
1492
|
+
namespace,
|
|
1493
|
+
...dateOptions
|
|
1494
|
+
});
|
|
1495
|
+
return createPlugin({
|
|
1496
|
+
namespace,
|
|
1497
|
+
provide: (app) => {
|
|
1498
|
+
provideDateContext(context, app);
|
|
1499
|
+
}
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Returns the current date context.
|
|
1442
1504
|
*
|
|
1443
1505
|
* Requires `createDatePlugin` to be installed with an adapter.
|
|
1444
1506
|
*
|
|
@@ -2156,6 +2218,132 @@ function useElementIntersection(target, options = {}) {
|
|
|
2156
2218
|
};
|
|
2157
2219
|
}
|
|
2158
2220
|
//#endregion
|
|
2221
|
+
//#region src/composables/useTimer/index.ts
|
|
2222
|
+
/**
|
|
2223
|
+
* @module useTimer
|
|
2224
|
+
*
|
|
2225
|
+
* @remarks
|
|
2226
|
+
* A reactive timer composable with pause/resume support.
|
|
2227
|
+
*
|
|
2228
|
+
* Key features:
|
|
2229
|
+
* - Start/stop/pause/resume controls
|
|
2230
|
+
* - Reactive remaining time tracking
|
|
2231
|
+
* - One-shot (default) or repeating mode
|
|
2232
|
+
* - Automatic cleanup on scope disposal
|
|
2233
|
+
* - SSR-safe
|
|
2234
|
+
*/
|
|
2235
|
+
/**
|
|
2236
|
+
* Creates a reactive timer with pause/resume support.
|
|
2237
|
+
*
|
|
2238
|
+
* @param handler Callback invoked when the timer fires.
|
|
2239
|
+
* @param options Timer configuration.
|
|
2240
|
+
* @returns Timer controls and reactive state.
|
|
2241
|
+
*
|
|
2242
|
+
* @see https://0.vuetifyjs.com/composables/system/use-timer
|
|
2243
|
+
*
|
|
2244
|
+
* @example
|
|
2245
|
+
* ```ts
|
|
2246
|
+
* const timer = useTimer(() => console.log('fired'), { duration: 5000 })
|
|
2247
|
+
*
|
|
2248
|
+
* timer.start()
|
|
2249
|
+
* timer.pause()
|
|
2250
|
+
* timer.resume()
|
|
2251
|
+
* timer.stop()
|
|
2252
|
+
* ```
|
|
2253
|
+
*/
|
|
2254
|
+
function useTimer(handler, options = {}) {
|
|
2255
|
+
const { duration = 1e3, repeat = false } = options;
|
|
2256
|
+
const remaining = shallowRef(duration);
|
|
2257
|
+
const isActive = shallowRef(false);
|
|
2258
|
+
const isPaused = shallowRef(false);
|
|
2259
|
+
let timeoutId;
|
|
2260
|
+
let trackingId;
|
|
2261
|
+
let startedAt = 0;
|
|
2262
|
+
let budget = duration;
|
|
2263
|
+
function clearTimer() {
|
|
2264
|
+
if (!/* @__PURE__ */ isUndefined(timeoutId)) {
|
|
2265
|
+
globalThis.clearTimeout(timeoutId);
|
|
2266
|
+
timeoutId = void 0;
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
function startTracking() {
|
|
2270
|
+
stopTracking();
|
|
2271
|
+
if (!IN_BROWSER) return;
|
|
2272
|
+
trackingId = globalThis.setInterval(() => {
|
|
2273
|
+
if (!isActive.value || isPaused.value) return;
|
|
2274
|
+
const elapsed = Date.now() - startedAt;
|
|
2275
|
+
remaining.value = Math.max(0, budget - elapsed);
|
|
2276
|
+
}, 100);
|
|
2277
|
+
}
|
|
2278
|
+
function stopTracking() {
|
|
2279
|
+
if (!/* @__PURE__ */ isUndefined(trackingId)) {
|
|
2280
|
+
globalThis.clearInterval(trackingId);
|
|
2281
|
+
trackingId = void 0;
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
function fire() {
|
|
2285
|
+
clearTimer();
|
|
2286
|
+
stopTracking();
|
|
2287
|
+
handler();
|
|
2288
|
+
if (repeat) begin(duration);
|
|
2289
|
+
else {
|
|
2290
|
+
isActive.value = false;
|
|
2291
|
+
remaining.value = 0;
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
function begin(ms) {
|
|
2295
|
+
clearTimer();
|
|
2296
|
+
stopTracking();
|
|
2297
|
+
budget = ms;
|
|
2298
|
+
startedAt = Date.now();
|
|
2299
|
+
remaining.value = ms;
|
|
2300
|
+
isActive.value = true;
|
|
2301
|
+
isPaused.value = false;
|
|
2302
|
+
timeoutId = globalThis.setTimeout(fire, ms);
|
|
2303
|
+
startTracking();
|
|
2304
|
+
}
|
|
2305
|
+
function start() {
|
|
2306
|
+
if (duration < 0) return;
|
|
2307
|
+
begin(duration);
|
|
2308
|
+
}
|
|
2309
|
+
function stop() {
|
|
2310
|
+
clearTimer();
|
|
2311
|
+
stopTracking();
|
|
2312
|
+
isActive.value = false;
|
|
2313
|
+
isPaused.value = false;
|
|
2314
|
+
remaining.value = duration;
|
|
2315
|
+
}
|
|
2316
|
+
function pause() {
|
|
2317
|
+
if (!isActive.value || isPaused.value) return;
|
|
2318
|
+
const elapsed = Date.now() - startedAt;
|
|
2319
|
+
budget = Math.max(0, budget - elapsed);
|
|
2320
|
+
remaining.value = budget;
|
|
2321
|
+
clearTimer();
|
|
2322
|
+
stopTracking();
|
|
2323
|
+
isPaused.value = true;
|
|
2324
|
+
}
|
|
2325
|
+
function resume() {
|
|
2326
|
+
if (!isPaused.value) return;
|
|
2327
|
+
isPaused.value = false;
|
|
2328
|
+
startedAt = Date.now();
|
|
2329
|
+
timeoutId = globalThis.setTimeout(fire, budget);
|
|
2330
|
+
startTracking();
|
|
2331
|
+
}
|
|
2332
|
+
onScopeDispose(() => {
|
|
2333
|
+
clearTimer();
|
|
2334
|
+
stopTracking();
|
|
2335
|
+
}, true);
|
|
2336
|
+
return {
|
|
2337
|
+
start,
|
|
2338
|
+
stop,
|
|
2339
|
+
pause,
|
|
2340
|
+
resume,
|
|
2341
|
+
remaining,
|
|
2342
|
+
isActive,
|
|
2343
|
+
isPaused
|
|
2344
|
+
};
|
|
2345
|
+
}
|
|
2346
|
+
//#endregion
|
|
2159
2347
|
//#region src/composables/useLazy/index.ts
|
|
2160
2348
|
/**
|
|
2161
2349
|
* @module useLazy
|
|
@@ -3886,92 +4074,94 @@ const [createNotificationsContext, createNotificationsPlugin, useNotifications]
|
|
|
3886
4074
|
}
|
|
3887
4075
|
});
|
|
3888
4076
|
//#endregion
|
|
3889
|
-
//#region src/composables/
|
|
4077
|
+
//#region src/composables/useProxyModel/index.ts
|
|
3890
4078
|
/**
|
|
3891
|
-
* @module
|
|
4079
|
+
* @module useProxyModel
|
|
3892
4080
|
*
|
|
3893
4081
|
* @remarks
|
|
3894
|
-
*
|
|
3895
|
-
* Manages open/close state, anchor styles, content attributes, and
|
|
3896
|
-
* bidirectional sync between reactive state and native popover events.
|
|
4082
|
+
* Proxy composable for bidirectional sync between a model context and v-model.
|
|
3897
4083
|
*
|
|
3898
4084
|
* Key features:
|
|
3899
|
-
* -
|
|
3900
|
-
* -
|
|
3901
|
-
* -
|
|
3902
|
-
* -
|
|
3903
|
-
*
|
|
4085
|
+
* - Bidirectional synchronization
|
|
4086
|
+
* - Array and single-value modes
|
|
4087
|
+
* - Automatic cleanup on scope disposal
|
|
4088
|
+
* - Works with any ModelContext (Selection, Slider, etc.)
|
|
4089
|
+
*
|
|
4090
|
+
* Bridges the gap between model composables and Vue's v-model.
|
|
4091
|
+
*/
|
|
4092
|
+
/**
|
|
4093
|
+
* Syncs a ref with a model context bidirectionally.
|
|
4094
|
+
*
|
|
4095
|
+
* @param context The model context to bind to.
|
|
4096
|
+
* @param model The ref to sync.
|
|
4097
|
+
* @param options The options for the proxy model.
|
|
4098
|
+
* @returns A function to stop the sync.
|
|
4099
|
+
*
|
|
4100
|
+
* @see https://0.vuetifyjs.com/composables/forms/use-proxy-model
|
|
3904
4101
|
*
|
|
3905
|
-
*
|
|
3906
|
-
*
|
|
4102
|
+
* @example
|
|
4103
|
+
* ```ts
|
|
4104
|
+
* import { createSelection, useProxyModel } from '@vuetify/v0'
|
|
4105
|
+
*
|
|
4106
|
+
* const model = ref()
|
|
4107
|
+
* const registry = createSelection({ events: true })
|
|
4108
|
+
* registry.onboard([
|
|
4109
|
+
* { id: 'item-1', value: 'Item 1' },
|
|
4110
|
+
* { id: 'item-2', value: 'Item 2' },
|
|
4111
|
+
* ])
|
|
4112
|
+
*
|
|
4113
|
+
* const stop = useProxyModel(registry, model)
|
|
4114
|
+
* ```
|
|
3907
4115
|
*/
|
|
3908
|
-
function
|
|
3909
|
-
const
|
|
3910
|
-
const
|
|
3911
|
-
const
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
const hideTimer = hideDelay > 0 ? useTimer(() => {
|
|
3916
|
-
isOpen.value = false;
|
|
3917
|
-
}, { duration: hideDelay }) : void 0;
|
|
3918
|
-
function open() {
|
|
3919
|
-
hideTimer?.stop();
|
|
3920
|
-
if (showTimer) showTimer.start();
|
|
3921
|
-
else isOpen.value = true;
|
|
4116
|
+
function useProxyModel(context, model, options) {
|
|
4117
|
+
const multiple = options?.multiple ?? context.multiple ?? false;
|
|
4118
|
+
const _transformIn = options?.transformIn;
|
|
4119
|
+
const _transformOut = options?.transformOut;
|
|
4120
|
+
function transformIn(val) {
|
|
4121
|
+
const value = toValue(val);
|
|
4122
|
+
return toArray(/* @__PURE__ */ isFunction(_transformIn) ? _transformIn(value) : value);
|
|
3922
4123
|
}
|
|
3923
|
-
function
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
else isOpen.value = false;
|
|
4124
|
+
function transformOut(val) {
|
|
4125
|
+
if (/* @__PURE__ */ isFunction(_transformOut)) return _transformOut(val);
|
|
4126
|
+
return toValue(multiple) ? val : val[0];
|
|
3927
4127
|
}
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
4128
|
+
const applyOptions = toValue(multiple) === toValue(context.multiple ?? false) ? void 0 : { multiple: toValue(multiple) };
|
|
4129
|
+
const modelAsArray = transformIn(model);
|
|
4130
|
+
const pending = new Set(modelAsArray);
|
|
4131
|
+
context.apply(modelAsArray, applyOptions);
|
|
4132
|
+
const selected = new Set(context.selectedValues.value);
|
|
4133
|
+
for (const value of modelAsArray) if (selected.has(value)) pending.delete(value);
|
|
4134
|
+
const contextWatch = watch(context.selectedValues, (val) => {
|
|
4135
|
+
modelWatch.pause();
|
|
4136
|
+
model.value = transformOut(Array.from(toValue(val)));
|
|
4137
|
+
modelWatch.resume();
|
|
4138
|
+
}, { flush: "sync" });
|
|
4139
|
+
const modelWatch = watch(model, (val) => {
|
|
4140
|
+
contextWatch.pause();
|
|
4141
|
+
context.apply(transformIn(val), applyOptions);
|
|
4142
|
+
contextWatch.resume();
|
|
4143
|
+
}, {
|
|
4144
|
+
flush: "sync",
|
|
4145
|
+
deep: toValue(multiple)
|
|
4146
|
+
});
|
|
4147
|
+
function onRegister(data) {
|
|
4148
|
+
const ticket = data;
|
|
4149
|
+
if (!pending.has(ticket.value) || toValue(ticket.disabled)) return;
|
|
4150
|
+
contextWatch.pause();
|
|
4151
|
+
modelWatch.pause();
|
|
4152
|
+
context.select?.(ticket.id);
|
|
4153
|
+
pending.delete(ticket.value);
|
|
4154
|
+
modelWatch.resume();
|
|
4155
|
+
contextWatch.resume();
|
|
3931
4156
|
}
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
const contentStyles = toRef(() => ({
|
|
3938
|
-
"position": "fixed",
|
|
3939
|
-
"margin": "unset",
|
|
3940
|
-
"inset-area": positionArea,
|
|
3941
|
-
"position-area": positionArea,
|
|
3942
|
-
"position-anchor": `--${id}`,
|
|
3943
|
-
"position-try-fallbacks": positionTry
|
|
3944
|
-
}));
|
|
3945
|
-
/* v8 ignore start -- browser popover API */
|
|
3946
|
-
function attach(el) {
|
|
3947
|
-
onMounted(() => {
|
|
3948
|
-
const element = toValue(el);
|
|
3949
|
-
if (isOpen.value) element?.showPopover();
|
|
3950
|
-
});
|
|
3951
|
-
watch(isOpen, (value) => {
|
|
3952
|
-
const element = toValue(el);
|
|
3953
|
-
if (!element?.isConnected) return;
|
|
3954
|
-
if (value === element.matches?.(":popover-open")) return;
|
|
3955
|
-
if (value) element.showPopover?.();
|
|
3956
|
-
else element.hidePopover?.();
|
|
3957
|
-
});
|
|
3958
|
-
useEventListener(el, "toggle", (e) => {
|
|
3959
|
-
if (!toValue(el)?.isConnected) return;
|
|
3960
|
-
isOpen.value = e.newState === "open";
|
|
3961
|
-
});
|
|
4157
|
+
context.on?.("register:ticket", onRegister);
|
|
4158
|
+
function stop() {
|
|
4159
|
+
contextWatch();
|
|
4160
|
+
modelWatch();
|
|
4161
|
+
context.off?.("register:ticket", onRegister);
|
|
3962
4162
|
}
|
|
3963
|
-
|
|
3964
|
-
return
|
|
3965
|
-
isOpen,
|
|
3966
|
-
id,
|
|
3967
|
-
open,
|
|
3968
|
-
close,
|
|
3969
|
-
toggle,
|
|
3970
|
-
anchorStyles,
|
|
3971
|
-
contentAttrs,
|
|
3972
|
-
contentStyles,
|
|
3973
|
-
attach
|
|
3974
|
-
};
|
|
4163
|
+
onScopeDispose(stop, true);
|
|
4164
|
+
return stop;
|
|
3975
4165
|
}
|
|
3976
4166
|
//#endregion
|
|
3977
4167
|
//#region src/composables/useRaf/index.ts
|
|
@@ -4331,6 +4521,10 @@ const [createRtlContext, createRtlPlugin, useRtl] = createPluginContext("v0:rtl"
|
|
|
4331
4521
|
fallback: () => createRtlFallback(),
|
|
4332
4522
|
setup: (context, app, { adapter = new Vuetify0RtlAdapter(), target }) => {
|
|
4333
4523
|
adapter.setup(app, context, target);
|
|
4524
|
+
},
|
|
4525
|
+
persist: (ctx) => ctx.isRtl.value,
|
|
4526
|
+
restore: (ctx, saved) => {
|
|
4527
|
+
ctx.isRtl.value = saved;
|
|
4334
4528
|
}
|
|
4335
4529
|
});
|
|
4336
4530
|
//#endregion
|
|
@@ -5976,261 +6170,368 @@ function useDocumentEventListener(event, listener, options) {
|
|
|
5976
6170
|
return IN_BROWSER ? useEventListener(document, event, listener, options) : () => {};
|
|
5977
6171
|
}
|
|
5978
6172
|
//#endregion
|
|
5979
|
-
//#region src/composables/
|
|
6173
|
+
//#region src/composables/usePopover/index.ts
|
|
5980
6174
|
/**
|
|
5981
|
-
* @module
|
|
6175
|
+
* @module usePopover
|
|
5982
6176
|
*
|
|
5983
6177
|
* @remarks
|
|
5984
|
-
*
|
|
6178
|
+
* Composable for native popover API behavior with CSS anchor positioning.
|
|
6179
|
+
* Manages open/close state, anchor styles, content attributes, and
|
|
6180
|
+
* bidirectional sync between reactive state and native popover events.
|
|
5985
6181
|
*
|
|
5986
6182
|
* Key features:
|
|
5987
|
-
* -
|
|
5988
|
-
* -
|
|
5989
|
-
* -
|
|
5990
|
-
* -
|
|
5991
|
-
* - Optional
|
|
5992
|
-
* - SSR-safe (no-op when not in browser)
|
|
5993
|
-
*
|
|
5994
|
-
* Common use cases: closing popovers, dropdowns, modals, and menus.
|
|
6183
|
+
* - Native popover API (showPopover/hidePopover)
|
|
6184
|
+
* - CSS anchor positioning (position-area, position-try-fallbacks)
|
|
6185
|
+
* - Toggle event sync for native state changes
|
|
6186
|
+
* - SSR-safe (no DOM ops outside browser)
|
|
6187
|
+
* - Optional external isOpen ref for v-model integration
|
|
5995
6188
|
*
|
|
5996
|
-
*
|
|
5997
|
-
*
|
|
5998
|
-
* dismissal per WCAG/APG requirements.
|
|
6189
|
+
* Perfect for building select, combobox, tooltip, and menu components
|
|
6190
|
+
* without wrapping the Popover compound component.
|
|
5999
6191
|
*/
|
|
6192
|
+
function usePopover(options = {}) {
|
|
6193
|
+
const { id: _id, positionArea = "bottom", positionTry = "most-width bottom", showDelay = 0, hideDelay = 0 } = options;
|
|
6194
|
+
const id = _id ?? /* @__PURE__ */ useId$1();
|
|
6195
|
+
const isOpen = options.isOpen ?? shallowRef(false);
|
|
6196
|
+
const showTimer = showDelay > 0 ? useTimer(() => {
|
|
6197
|
+
isOpen.value = true;
|
|
6198
|
+
}, { duration: showDelay }) : void 0;
|
|
6199
|
+
const hideTimer = hideDelay > 0 ? useTimer(() => {
|
|
6200
|
+
isOpen.value = false;
|
|
6201
|
+
}, { duration: hideDelay }) : void 0;
|
|
6202
|
+
function open() {
|
|
6203
|
+
hideTimer?.stop();
|
|
6204
|
+
if (showTimer) showTimer.start();
|
|
6205
|
+
else isOpen.value = true;
|
|
6206
|
+
}
|
|
6207
|
+
function close() {
|
|
6208
|
+
showTimer?.stop();
|
|
6209
|
+
if (hideTimer) hideTimer.start();
|
|
6210
|
+
else isOpen.value = false;
|
|
6211
|
+
}
|
|
6212
|
+
function toggle() {
|
|
6213
|
+
if (isOpen.value) close();
|
|
6214
|
+
else open();
|
|
6215
|
+
}
|
|
6216
|
+
const anchorStyles = toRef(() => ({ anchorName: `--${id}` }));
|
|
6217
|
+
const contentAttrs = toRef(() => ({
|
|
6218
|
+
id,
|
|
6219
|
+
popover: ""
|
|
6220
|
+
}));
|
|
6221
|
+
const contentStyles = toRef(() => ({
|
|
6222
|
+
"position": "fixed",
|
|
6223
|
+
"margin": "unset",
|
|
6224
|
+
"inset-area": positionArea,
|
|
6225
|
+
"position-area": positionArea,
|
|
6226
|
+
"position-anchor": `--${id}`,
|
|
6227
|
+
"position-try-fallbacks": positionTry
|
|
6228
|
+
}));
|
|
6229
|
+
/* v8 ignore start -- browser popover API */
|
|
6230
|
+
function attach(el) {
|
|
6231
|
+
onMounted(() => {
|
|
6232
|
+
const element = toValue(el);
|
|
6233
|
+
if (isOpen.value) element?.showPopover();
|
|
6234
|
+
});
|
|
6235
|
+
watch(isOpen, (value) => {
|
|
6236
|
+
const element = toValue(el);
|
|
6237
|
+
if (!element?.isConnected) return;
|
|
6238
|
+
if (value === element.matches?.(":popover-open")) return;
|
|
6239
|
+
if (value) element.showPopover?.();
|
|
6240
|
+
else element.hidePopover?.();
|
|
6241
|
+
});
|
|
6242
|
+
useEventListener(el, "toggle", (e) => {
|
|
6243
|
+
if (!toValue(el)?.isConnected) return;
|
|
6244
|
+
isOpen.value = e.newState === "open";
|
|
6245
|
+
});
|
|
6246
|
+
}
|
|
6247
|
+
/* v8 ignore stop */
|
|
6248
|
+
return {
|
|
6249
|
+
isOpen,
|
|
6250
|
+
id,
|
|
6251
|
+
open,
|
|
6252
|
+
close,
|
|
6253
|
+
toggle,
|
|
6254
|
+
anchorStyles,
|
|
6255
|
+
contentAttrs,
|
|
6256
|
+
contentStyles,
|
|
6257
|
+
attach
|
|
6258
|
+
};
|
|
6259
|
+
}
|
|
6260
|
+
//#endregion
|
|
6261
|
+
//#region src/composables/createCombobox/adapters/client.ts
|
|
6000
6262
|
/**
|
|
6001
|
-
*
|
|
6002
|
-
*
|
|
6003
|
-
* Uses two-phase detection (pointerdown → pointerup) to prevent false positives
|
|
6004
|
-
* when users drag from inside to outside an element.
|
|
6005
|
-
*
|
|
6006
|
-
* @param target Element ref(s) to detect clicks outside of. Accepts a single ref/getter or array of refs/getters.
|
|
6007
|
-
* @param handler Callback invoked when a click outside is detected.
|
|
6008
|
-
* @param options Configuration options.
|
|
6009
|
-
* @returns An object with methods to control the listener.
|
|
6263
|
+
* @module createCombobox/adapters/client
|
|
6010
6264
|
*
|
|
6011
|
-
* @
|
|
6012
|
-
*
|
|
6013
|
-
*
|
|
6014
|
-
|
|
6015
|
-
|
|
6265
|
+
* @remarks
|
|
6266
|
+
* Default combobox adapter. Filters items client-side using createFilter.
|
|
6267
|
+
* Synchronous, zero debounce — items update immediately as the user types.
|
|
6268
|
+
*/
|
|
6269
|
+
var ClientAdapter = class {
|
|
6270
|
+
options;
|
|
6271
|
+
constructor(options = {}) {
|
|
6272
|
+
this.options = options;
|
|
6273
|
+
}
|
|
6274
|
+
setup(context) {
|
|
6275
|
+
const { mode, keys, filter: customFilter } = this.options;
|
|
6276
|
+
const filter = createFilter({
|
|
6277
|
+
mode,
|
|
6278
|
+
keys,
|
|
6279
|
+
customFilter: customFilter ? (query, item) => customFilter(String(query), item) : void 0
|
|
6280
|
+
});
|
|
6281
|
+
const values = toRef(() => context.items.value.map((t) => t.value));
|
|
6282
|
+
const { items: filteredValues } = filter.apply(context.query, values);
|
|
6283
|
+
const filtered = computed(() => {
|
|
6284
|
+
if (!String(context.query.value).trim()) return new Set(context.items.value.map((t) => t.id));
|
|
6285
|
+
const matchedValues = new Set(filteredValues.value);
|
|
6286
|
+
const ids = /* @__PURE__ */ new Set();
|
|
6287
|
+
for (const ticket of context.items.value) if (matchedValues.has(ticket.value)) ids.add(ticket.id);
|
|
6288
|
+
return ids;
|
|
6289
|
+
});
|
|
6290
|
+
const isEmpty = toRef(() => filtered.value.size === 0);
|
|
6291
|
+
return {
|
|
6292
|
+
filtered,
|
|
6293
|
+
isLoading: shallowRef(false),
|
|
6294
|
+
isEmpty
|
|
6295
|
+
};
|
|
6296
|
+
}
|
|
6297
|
+
};
|
|
6298
|
+
//#endregion
|
|
6299
|
+
//#region src/composables/createCombobox/adapters/server.ts
|
|
6300
|
+
/**
|
|
6301
|
+
* @module createCombobox/adapters/server
|
|
6016
6302
|
*
|
|
6017
|
-
*
|
|
6018
|
-
*
|
|
6303
|
+
* @remarks
|
|
6304
|
+
* Server-side combobox adapter. All filtering is performed externally.
|
|
6305
|
+
* The adapter is a pass-through — it shows all registered items and
|
|
6306
|
+
* exposes loading state for the consumer to control.
|
|
6019
6307
|
*
|
|
6020
|
-
*
|
|
6021
|
-
*
|
|
6022
|
-
|
|
6308
|
+
* The consumer watches `query` via useComboboxContext() or slot props
|
|
6309
|
+
* and provides filtered items reactively.
|
|
6310
|
+
*/
|
|
6311
|
+
var ServerAdapter = class {
|
|
6312
|
+
setup(context) {
|
|
6313
|
+
const isLoading = shallowRef(false);
|
|
6314
|
+
return {
|
|
6315
|
+
filtered: toRef(() => {
|
|
6316
|
+
return new Set(context.items.value.map((t) => t.id));
|
|
6317
|
+
}),
|
|
6318
|
+
isLoading,
|
|
6319
|
+
isEmpty: toRef(() => context.items.value.length === 0)
|
|
6320
|
+
};
|
|
6321
|
+
}
|
|
6322
|
+
};
|
|
6323
|
+
//#endregion
|
|
6324
|
+
//#region src/composables/createCombobox/index.ts
|
|
6325
|
+
/**
|
|
6326
|
+
* @module createCombobox
|
|
6023
6327
|
*
|
|
6024
|
-
*
|
|
6025
|
-
*
|
|
6026
|
-
*
|
|
6027
|
-
*
|
|
6028
|
-
* )
|
|
6029
|
-
* ```
|
|
6328
|
+
* @remarks
|
|
6329
|
+
* Orchestrator composable that coordinates selection, popover, and virtual focus
|
|
6330
|
+
* for a combobox (autocomplete/typeahead) pattern. Does not extend the selection
|
|
6331
|
+
* chain — it composes existing primitives instead.
|
|
6030
6332
|
*
|
|
6031
|
-
*
|
|
6032
|
-
*
|
|
6033
|
-
*
|
|
6034
|
-
*
|
|
6333
|
+
* Key features:
|
|
6334
|
+
* - Adapter-based filtering (client-side or server-side via ClientAdapter/ServerAdapter)
|
|
6335
|
+
* - Single or multi-select mode
|
|
6336
|
+
* - Virtual focus keyboard navigation (aria-activedescendant pattern)
|
|
6337
|
+
* - Strict mode: reverts query to selected value on close if no match
|
|
6338
|
+
* - Popover-based dropdown positioning
|
|
6339
|
+
* - Context DI via createComboboxContext / useCombobox
|
|
6340
|
+
*/
|
|
6341
|
+
/**
|
|
6342
|
+
* Creates a combobox context that orchestrates selection, popover, virtual
|
|
6343
|
+
* focus, and adapter-based filtering into a single coordinated state.
|
|
6035
6344
|
*
|
|
6036
|
-
*
|
|
6037
|
-
*
|
|
6038
|
-
* () => { isOpen.value = false }
|
|
6039
|
-
* )
|
|
6040
|
-
* ```
|
|
6345
|
+
* @param options - Configuration for selection mode, filtering adapter, and behavior.
|
|
6346
|
+
* @returns A combobox context with all composed systems and action methods.
|
|
6041
6347
|
*
|
|
6042
|
-
* @
|
|
6043
|
-
* ```ts
|
|
6044
|
-
* useClickOutside(
|
|
6045
|
-
* () => navRef.value?.element,
|
|
6046
|
-
* () => { isOpen.value = false },
|
|
6047
|
-
* { ignore: ['[data-app-bar]'] }
|
|
6048
|
-
* )
|
|
6049
|
-
* ```
|
|
6348
|
+
* @see https://0.vuetifyjs.com/composables/combobox/create-combobox
|
|
6050
6349
|
*
|
|
6051
|
-
* @example
|
|
6350
|
+
* @example
|
|
6052
6351
|
* ```ts
|
|
6053
|
-
*
|
|
6054
|
-
* const dialogRef = useTemplateRef<HTMLDialogElement>('dialog')
|
|
6352
|
+
* import { createCombobox } from '@vuetify/v0'
|
|
6055
6353
|
*
|
|
6056
|
-
*
|
|
6057
|
-
*
|
|
6058
|
-
*
|
|
6059
|
-
*
|
|
6060
|
-
*
|
|
6354
|
+
* const combobox = createCombobox({ strict: true })
|
|
6355
|
+
*
|
|
6356
|
+
* combobox.selection.register({ id: 'a', value: 'Apple' })
|
|
6357
|
+
* combobox.selection.register({ id: 'b', value: 'Banana' })
|
|
6358
|
+
*
|
|
6359
|
+
* combobox.open()
|
|
6360
|
+
* combobox.select('a') // query → 'Apple', dropdown closes
|
|
6061
6361
|
* ```
|
|
6062
6362
|
*/
|
|
6063
|
-
function
|
|
6064
|
-
const {
|
|
6065
|
-
const
|
|
6066
|
-
const
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
return
|
|
6080
|
-
}
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
}
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
}
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
/*
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
if (targets.length === 0) return false;
|
|
6126
|
-
return targets.every((el) => {
|
|
6127
|
-
if (/* @__PURE__ */ isNullOrUndefined(el) || !/* @__PURE__ */ isFunction(el.contains)) return false;
|
|
6128
|
-
return el !== eventTarget && !el.contains(eventTarget);
|
|
6129
|
-
});
|
|
6130
|
-
}
|
|
6131
|
-
/**
|
|
6132
|
-
* Check if coordinates are outside all target elements' bounding rects.
|
|
6133
|
-
*/
|
|
6134
|
-
function isOutsideBounds(x, y) {
|
|
6135
|
-
const targets = getTargets();
|
|
6136
|
-
if (targets.length === 0) return false;
|
|
6137
|
-
return targets.every((el) => {
|
|
6138
|
-
const { left, right, top, bottom } = el.getBoundingClientRect();
|
|
6139
|
-
return x < left || x > right || y < top || y > bottom;
|
|
6140
|
-
});
|
|
6141
|
-
}
|
|
6142
|
-
/**
|
|
6143
|
-
* Validate that the target is still in the DOM.
|
|
6144
|
-
*/
|
|
6145
|
-
function isValidTarget(eventTarget) {
|
|
6146
|
-
if (!(eventTarget instanceof Element)) return false;
|
|
6147
|
-
if (!eventTarget.isConnected) return false;
|
|
6148
|
-
return true;
|
|
6363
|
+
function createCombobox(options = {}) {
|
|
6364
|
+
const { multiple = false, mandatory = false, disabled = false, strict = false, error = false, errorMessages, adapter, displayValue = (v) => String(v ?? ""), id: _id, name, form } = options;
|
|
6365
|
+
const id = _id ?? /* @__PURE__ */ useId$1();
|
|
6366
|
+
const inputId = `${id}-input`;
|
|
6367
|
+
const listboxId = `${id}-listbox`;
|
|
6368
|
+
const descriptionId = `${id}-description`;
|
|
6369
|
+
const errorId = `${id}-error`;
|
|
6370
|
+
const hasDescription = shallowRef(false);
|
|
6371
|
+
const hasError = shallowRef(false);
|
|
6372
|
+
const errors = computed(() => {
|
|
6373
|
+
const messages = toValue(errorMessages);
|
|
6374
|
+
return messages ? toArray(messages) : [];
|
|
6375
|
+
});
|
|
6376
|
+
const isValid = toRef(() => {
|
|
6377
|
+
if (toValue(error)) return false;
|
|
6378
|
+
if (errors.value.length > 0) return false;
|
|
6379
|
+
return null;
|
|
6380
|
+
});
|
|
6381
|
+
const selection = createSelection({
|
|
6382
|
+
multiple,
|
|
6383
|
+
mandatory,
|
|
6384
|
+
disabled: toRef(() => toValue(disabled)),
|
|
6385
|
+
events: true
|
|
6386
|
+
});
|
|
6387
|
+
const query = shallowRef("");
|
|
6388
|
+
const pristine = shallowRef(true);
|
|
6389
|
+
const inputEl = shallowRef(null);
|
|
6390
|
+
const version = shallowRef(0);
|
|
6391
|
+
selection.on("register:ticket", () => {
|
|
6392
|
+
version.value++;
|
|
6393
|
+
});
|
|
6394
|
+
selection.on("unregister:ticket", () => {
|
|
6395
|
+
version.value++;
|
|
6396
|
+
});
|
|
6397
|
+
const items = computed(() => {
|
|
6398
|
+
version.value;
|
|
6399
|
+
return [...selection.values()];
|
|
6400
|
+
});
|
|
6401
|
+
const { filtered, isLoading, isEmpty } = (adapter ?? new ClientAdapter()).setup({
|
|
6402
|
+
query,
|
|
6403
|
+
items
|
|
6404
|
+
});
|
|
6405
|
+
const popover = usePopover({ id });
|
|
6406
|
+
const isOpen = popover.isOpen;
|
|
6407
|
+
const cursor = useVirtualFocus(() => selection.values().filter((ticket) => filtered.value.has(ticket.id) && !toValue(ticket.disabled)).map((ticket) => ({
|
|
6408
|
+
id: ticket.id,
|
|
6409
|
+
el: () => document.querySelector(`#${CSS.escape(`${id}-option-${ticket.id}`)}`),
|
|
6410
|
+
disabled: ticket.disabled
|
|
6411
|
+
})), {
|
|
6412
|
+
control: inputEl,
|
|
6413
|
+
target: () => null,
|
|
6414
|
+
orientation: "vertical"
|
|
6415
|
+
});
|
|
6416
|
+
const selectedId = toRef(() => selection.selectedIds.values().next().value);
|
|
6417
|
+
const display = toRef(() => {
|
|
6418
|
+
if (!pristine.value) return query.value;
|
|
6419
|
+
if (toValue(multiple)) return query.value;
|
|
6420
|
+
const ticket = /* @__PURE__ */ isUndefined(selectedId.value) ? void 0 : selection.get(selectedId.value);
|
|
6421
|
+
return ticket ? displayValue(ticket.value) : "";
|
|
6422
|
+
});
|
|
6423
|
+
function open() {
|
|
6424
|
+
if (!isOpen.value && !toValue(disabled)) isOpen.value = true;
|
|
6149
6425
|
}
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
function onPointerDown(event) {
|
|
6155
|
-
if (isPaused.value) return;
|
|
6156
|
-
if (event.defaultPrevented) return;
|
|
6157
|
-
initialTarget = event.composedPath()[0] ?? event.target;
|
|
6158
|
-
startPosition = {
|
|
6159
|
-
x: event.clientX,
|
|
6160
|
-
y: event.clientY
|
|
6161
|
-
};
|
|
6426
|
+
function close() {
|
|
6427
|
+
query.value = "";
|
|
6428
|
+
pristine.value = true;
|
|
6429
|
+
isOpen.value = false;
|
|
6162
6430
|
}
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
function onPointerUp(event) {
|
|
6167
|
-
if (isPaused.value) return;
|
|
6168
|
-
if (event.defaultPrevented) return;
|
|
6169
|
-
if (!initialTarget) return;
|
|
6170
|
-
const pointerdownTarget = initialTarget;
|
|
6171
|
-
initialTarget = null;
|
|
6172
|
-
if (!isValidTarget(pointerdownTarget)) return;
|
|
6173
|
-
const path = event.composedPath();
|
|
6174
|
-
const pointerupTarget = path[0] ?? event.target;
|
|
6175
|
-
if (event.pointerType === "touch") {
|
|
6176
|
-
const dx = Math.abs(event.clientX - startPosition.x);
|
|
6177
|
-
const dy = Math.abs(event.clientY - startPosition.y);
|
|
6178
|
-
if (dx >= touchScrollThreshold || dy >= touchScrollThreshold) return;
|
|
6179
|
-
}
|
|
6180
|
-
if ((bounds ? isOutsideBounds(startPosition.x, startPosition.y) && isOutsideBounds(event.clientX, event.clientY) : isOutside(pointerdownTarget) && isOutside(pointerupTarget)) && !shouldIgnore(path)) handler(event);
|
|
6431
|
+
function toggle() {
|
|
6432
|
+
if (isOpen.value) close();
|
|
6433
|
+
else open();
|
|
6181
6434
|
}
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6435
|
+
function select(itemId) {
|
|
6436
|
+
if (toValue(multiple)) {
|
|
6437
|
+
selection.toggle(itemId);
|
|
6438
|
+
query.value = "";
|
|
6439
|
+
pristine.value = true;
|
|
6440
|
+
cursor.highlight(itemId);
|
|
6441
|
+
inputEl.value?.focus();
|
|
6442
|
+
} else {
|
|
6443
|
+
selection.select(itemId);
|
|
6444
|
+
query.value = "";
|
|
6445
|
+
pristine.value = true;
|
|
6446
|
+
close();
|
|
6192
6447
|
}
|
|
6193
6448
|
}
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
if (!detectIframe) return;
|
|
6199
|
-
cleanupBlur = useWindowEventListener("blur", onBlur, capture);
|
|
6200
|
-
}
|
|
6201
|
-
function cleanup() {
|
|
6202
|
-
cleanupPointerDown?.();
|
|
6203
|
-
cleanupPointerUp?.();
|
|
6204
|
-
cleanupBlur?.();
|
|
6205
|
-
cleanupPointerDown = void 0;
|
|
6206
|
-
cleanupPointerUp = void 0;
|
|
6207
|
-
cleanupBlur = void 0;
|
|
6208
|
-
}
|
|
6209
|
-
function pause() {
|
|
6210
|
-
if (isPaused.value) return;
|
|
6211
|
-
isPaused.value = true;
|
|
6212
|
-
initialTarget = null;
|
|
6213
|
-
cleanup();
|
|
6214
|
-
}
|
|
6215
|
-
function resume() {
|
|
6216
|
-
if (!isPaused.value) return;
|
|
6217
|
-
isPaused.value = false;
|
|
6218
|
-
setup();
|
|
6219
|
-
}
|
|
6220
|
-
function stop() {
|
|
6221
|
-
isPaused.value = true;
|
|
6222
|
-
initialTarget = null;
|
|
6223
|
-
cleanup();
|
|
6449
|
+
function clear() {
|
|
6450
|
+
query.value = "";
|
|
6451
|
+
pristine.value = true;
|
|
6452
|
+
for (const id of Array.from(selection.selectedIds)) selection.unselect(id);
|
|
6224
6453
|
}
|
|
6225
|
-
|
|
6226
|
-
|
|
6454
|
+
watch(isOpen, (open) => {
|
|
6455
|
+
if (!open) cursor.clear();
|
|
6456
|
+
});
|
|
6227
6457
|
return {
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6458
|
+
selection,
|
|
6459
|
+
popover,
|
|
6460
|
+
cursor,
|
|
6461
|
+
query,
|
|
6462
|
+
display,
|
|
6463
|
+
pristine,
|
|
6464
|
+
filtered,
|
|
6465
|
+
isEmpty,
|
|
6466
|
+
isLoading,
|
|
6467
|
+
isOpen,
|
|
6468
|
+
id,
|
|
6469
|
+
inputId,
|
|
6470
|
+
listboxId,
|
|
6471
|
+
descriptionId,
|
|
6472
|
+
errorId,
|
|
6473
|
+
hasDescription,
|
|
6474
|
+
hasError,
|
|
6475
|
+
errors,
|
|
6476
|
+
isValid,
|
|
6477
|
+
inputEl,
|
|
6478
|
+
multiple: toValue(multiple),
|
|
6479
|
+
strict,
|
|
6480
|
+
disabled,
|
|
6481
|
+
name,
|
|
6482
|
+
form,
|
|
6483
|
+
open,
|
|
6484
|
+
close,
|
|
6485
|
+
toggle,
|
|
6486
|
+
select,
|
|
6487
|
+
clear
|
|
6233
6488
|
};
|
|
6234
6489
|
}
|
|
6490
|
+
/**
|
|
6491
|
+
* Creates a combobox context with dependency injection support.
|
|
6492
|
+
*
|
|
6493
|
+
* @param options - Combobox options plus an optional namespace for DI.
|
|
6494
|
+
* @returns A context trinity: `[useCombobox, provideCombobox, defaultCombobox]`.
|
|
6495
|
+
*
|
|
6496
|
+
* @see https://0.vuetifyjs.com/composables/combobox/create-combobox
|
|
6497
|
+
*
|
|
6498
|
+
* @example
|
|
6499
|
+
* ```ts
|
|
6500
|
+
* import { createComboboxContext } from '@vuetify/v0'
|
|
6501
|
+
*
|
|
6502
|
+
* const [useCombobox, provideCombobox, combobox] = createComboboxContext({
|
|
6503
|
+
* namespace: 'my-combobox',
|
|
6504
|
+
* strict: true,
|
|
6505
|
+
* })
|
|
6506
|
+
* ```
|
|
6507
|
+
*/
|
|
6508
|
+
function createComboboxContext(options = {}) {
|
|
6509
|
+
const { namespace = "v0:combobox", ...rest } = options;
|
|
6510
|
+
const [useCombobox, _provideCombobox] = createContext(namespace);
|
|
6511
|
+
const context = createCombobox(rest);
|
|
6512
|
+
function provideCombobox(_context = context, app) {
|
|
6513
|
+
return _provideCombobox(_context, app);
|
|
6514
|
+
}
|
|
6515
|
+
return createTrinity(useCombobox, provideCombobox, context);
|
|
6516
|
+
}
|
|
6517
|
+
/**
|
|
6518
|
+
* Injects the current combobox context from a parent provider.
|
|
6519
|
+
*
|
|
6520
|
+
* @param namespace - DI namespace. Defaults to `'v0:combobox'`.
|
|
6521
|
+
* @returns The combobox context from the nearest provider.
|
|
6522
|
+
*
|
|
6523
|
+
* @see https://0.vuetifyjs.com/composables/combobox/create-combobox
|
|
6524
|
+
*
|
|
6525
|
+
* @example
|
|
6526
|
+
* ```ts
|
|
6527
|
+
* import { useCombobox } from '@vuetify/v0'
|
|
6528
|
+
*
|
|
6529
|
+
* const combobox = useCombobox()
|
|
6530
|
+
* combobox.query.value = 'search term'
|
|
6531
|
+
* ```
|
|
6532
|
+
*/
|
|
6533
|
+
function useCombobox(namespace = "v0:combobox") {
|
|
6534
|
+
return useContext(namespace);
|
|
6535
|
+
}
|
|
6235
6536
|
//#endregion
|
|
6236
|
-
export {
|
|
6537
|
+
export { useMediaQuery as $, createSlider as A, createHydrationPlugin as At, createNotifications as B, createStep as C, useOverflow as Ct, createStackContext as D, createFallbackHydration as Dt, createStack as E, toElement as Et, useRtl as F, createQueueContext as G, createNotificationsPlugin as H, Vuetify0RtlAdapter as I, createNestedContext as J, useQueue as K, useRovingFocus as L, createRtlContext as M, createBreadcrumbs as Mt, createRtlFallback as N, createBreadcrumbsContext as Nt, createStackPlugin as O, createHydration as Ot, createRtlPlugin as P, useBreadcrumbs as Pt, useMutationObserver as Q, useRaf as R, useStorage as S, createOverflowContext as St, useStep as T, useResizeObserver as Tt, useNotifications as U, createNotificationsContext as V, createQueue as W, multipleOpenStrategy as X, useNested as Y, singleOpenStrategy as Z, createTimelineContext as _, createBreakpointsContext as _t, ClientAdapter as a, useElementIntersection as at, createStorageContext as b, toReactive as bt, useEventListener as c, createForm as ct, createVirtual as d, createDate as dt, usePrefersContrast as et, createVirtualContext as f, createDateContext as ft, createTimeline as g, createBreakpoints as gt, createValidation as h, useClickOutside as ht, ServerAdapter as i, useTimer as it, createRtl as j, useHydration as jt, useStack as k, createHydrationContext as kt, useWindowEventListener as l, createFormContext as lt, useToggleScope as m, useDate as mt, createComboboxContext as n, usePrefersReducedMotion as nt, usePopover as o, useIntersectionObserver as ot, useVirtual as p, createDatePlugin as pt, createNested as q, useCombobox as r, useLazy as rt, useDocumentEventListener as s, useHotkey as st, createCombobox as t, usePrefersDark as tt, useVirtualFocus as u, useForm as ut, useTimeline as v, createBreakpointsPlugin as vt, createStepContext as w, useElementSize as wt, createStoragePlugin as x, createOverflow as xt, createStorage as y, useBreakpoints as yt, useProxyModel as z };
|