@vuetify/v0 1.0.0-alpha.2 → 1.0.0-alpha.4
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/README.md +6 -1
- package/dist/adapter-BSKx9WQ7.mjs +4 -0
- package/dist/{index-CT5SCLzW.d.mts → adapter-C6JmOyYo.d.mts} +6 -9
- package/dist/{adapter-gQ2SNKZq.mjs → adapter-C9cR4AcY.mjs} +248 -5
- package/dist/adapter-Chznb9Ju.mjs +4 -0
- package/dist/{adapter-DlX3FA3A.d.mts → adapter-Cr7Bl4la.d.mts} +3 -7
- package/dist/adapter-D8zizQVP.mjs +4 -0
- package/dist/adapter-DgBBe_BW.d.mts +17 -0
- package/dist/adapter-Dzyrlbz7.d.mts +98 -0
- package/dist/adapter-o8r-2vUn.d.mts +11 -0
- package/dist/adapters-B25KaYU4.mjs +2 -0
- package/dist/adapters-BcddLSNs.mjs +4 -0
- package/dist/adapters-D64TORDu.mjs +2 -0
- package/dist/adapters-Dv74Jk6A.mjs +5 -0
- package/dist/adapters-t6QC-zE8.mjs +3 -0
- package/dist/browser/index.js +5167 -597
- package/dist/components/index.d.mts +3 -3
- package/dist/components/index.mjs +2 -2
- package/dist/{components-CqDewYTU.mjs → components-BWxMSWr7.mjs} +3780 -417
- package/dist/composables/index.d.mts +19 -19
- package/dist/composables/index.mjs +31 -29
- package/dist/{consola-BdgyPEfx.d.mts → consola-Crr4qbeI.d.mts} +2 -2
- package/dist/{consola-Ceox8BWi.mjs → consola-DYvbPNbF.mjs} +3 -1
- package/dist/constants/index.d.mts +1 -1
- package/dist/constants/index.mjs +2 -2
- package/dist/{createDataTable-rXBqGglI.mjs → createDataTable-DDr2yY-A.mjs} +30 -29
- package/dist/{createGroup-BU4olYtB.mjs → createGroup-BSGtfBUE.mjs} +3 -3
- package/dist/{createRegistry-Dl-bSSTr.mjs → createRegistry-Db_juawd.mjs} +78 -41
- package/dist/{createSelection-Csaa-C8p.mjs → createSelection-BeKZMxha.mjs} +3 -3
- package/dist/{createSingle-8xbHAIpY.mjs → createSingle-Dms2efxr.mjs} +1 -1
- package/dist/{createTokens-lNg2M_P_.mjs → createTokens-B1lwHZvO.mjs} +2 -2
- package/dist/data-table/adapters/client/index.d.mts +2 -2
- package/dist/data-table/adapters/client/index.mjs +2 -2
- package/dist/data-table/adapters/index.d.mts +5 -5
- package/dist/data-table/adapters/index.mjs +6 -6
- package/dist/data-table/adapters/server/index.d.mts +2 -2
- package/dist/data-table/adapters/server/index.mjs +2 -2
- package/dist/data-table/adapters/virtual/index.d.mts +2 -2
- package/dist/data-table/adapters/virtual/index.mjs +2 -2
- package/dist/data-table/index.d.mts +6 -6
- package/dist/data-table/index.mjs +6 -6
- package/dist/date/index.d.mts +3 -3
- package/dist/date/index.mjs +11 -4
- package/dist/features/adapters/flagsmith/index.d.mts +2 -2
- package/dist/features/adapters/flagsmith/index.mjs +2 -2
- package/dist/features/adapters/launchdarkly/index.d.mts +2 -2
- package/dist/features/adapters/launchdarkly/index.mjs +2 -2
- package/dist/features/adapters/posthog/index.d.mts +2 -2
- package/dist/features/adapters/posthog/index.mjs +2 -2
- package/dist/features/index.d.mts +3 -3
- package/dist/features/index.mjs +2 -1
- package/dist/{flagsmith-Dbh1h8WF.mjs → flagsmith-Cu93hUIF.mjs} +6 -4
- package/dist/{index-BzFHTW59.d.mts → flagsmith-ygKMImos.d.mts} +4 -4
- package/dist/{globals-CKdzjeLe.mjs → globals-BAe6tA_x.mjs} +1 -1
- package/dist/{index-GOpjKzaJ.d.mts → index-B3-FstpY.d.mts} +25 -2
- package/dist/{index-BJGcVy7e.d.mts → index-BA7YU2xY.d.mts} +5 -5
- package/dist/{index-BxKMMWnQ.d.mts → index-BfpLkDR_.d.mts} +1113 -74
- package/dist/{index-DE3bWw11.d.mts → index-Cw04PFVO.d.mts} +92 -48
- package/dist/index-DewYtDsc.d.mts +4 -0
- package/dist/{index-B7cqgTBL.d.mts → index-jQPkwo3G.d.mts} +598 -363
- package/dist/index.d.mts +23 -23
- package/dist/index.mjs +35 -33
- package/dist/json/attributes.json +57 -1
- package/dist/json/importMap.json +16 -0
- package/dist/json/tags.json +29 -0
- package/dist/json/web-types.json +181 -3
- package/dist/launchdarkly-BJR4vbbV.d.mts +13 -0
- package/dist/{launchdarkly-BKtW-idu.mjs → launchdarkly-CLGtJCsI.mjs} +6 -4
- package/dist/locale/adapters/index.d.mts +3 -3
- package/dist/locale/adapters/index.mjs +4 -3
- package/dist/locale/adapters/v0/index.d.mts +2 -2
- package/dist/locale/adapters/v0/index.mjs +2 -2
- package/dist/locale/adapters/vue-i18n/index.d.mts +3 -3
- package/dist/locale/adapters/vue-i18n/index.mjs +4 -2
- package/dist/locale/index.d.mts +4 -4
- package/dist/locale/index.mjs +4 -3
- package/dist/logger/adapters/consola/index.d.mts +1 -1
- package/dist/logger/adapters/consola/index.mjs +1 -1
- package/dist/logger/adapters/index.d.mts +5 -5
- package/dist/logger/adapters/index.mjs +6 -5
- 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 +2 -2
- package/dist/logger/adapters/v0/index.mjs +2 -2
- package/dist/logger/index.d.mts +6 -6
- package/dist/logger/index.mjs +6 -5
- package/dist/{memory-CeSQE-QV.d.mts → memory-B0w39kno.d.mts} +9 -9
- package/dist/{memory-oYBvtkgx.mjs → memory-BMpJcQjQ.mjs} +13 -3
- package/dist/notifications/index.d.mts +30 -4
- package/dist/notifications/index.mjs +187 -126
- package/dist/palettes/ant/index.d.mts +1 -1
- package/dist/palettes/index.d.mts +3 -3
- package/dist/palettes/leonardo/generate/index.mjs +5 -1
- 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 +3 -3
- package/dist/permissions/adapters/v0/index.d.mts +2 -2
- package/dist/permissions/adapters/v0/index.mjs +2 -2
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +3 -3
- package/dist/{pino-9L79n6y6.mjs → pino-CIcYlW3u.mjs} +3 -1
- package/dist/{pino-DNfCEb0p.d.mts → pino-NmR7X0s4.d.mts} +2 -2
- package/dist/{posthog-DZNnPXxS.mjs → posthog-B3go2aCh.mjs} +7 -5
- package/dist/posthog-CQntUXFO.d.mts +13 -0
- package/dist/rules/index.d.mts +1 -1
- package/dist/rules/index.mjs +1 -1
- package/dist/{server-3ilWFwqe.d.mts → server-DQK305lc.d.mts} +5 -5
- package/dist/{server-y7zLSCSx.mjs → server-ZFXbgQoY.mjs} +4 -3
- package/dist/storage/adapters/index.d.mts +3 -3
- package/dist/storage/adapters/index.mjs +2 -2
- package/dist/storage/adapters/memory/index.d.mts +2 -2
- package/dist/storage/adapters/memory/index.mjs +2 -2
- package/dist/storage/index.d.mts +4 -4
- package/dist/storage/index.mjs +3 -3
- package/dist/theme/adapters/index.d.mts +2 -2
- package/dist/theme/adapters/index.mjs +4 -4
- package/dist/theme/adapters/unhead/index.d.mts +1 -1
- package/dist/theme/adapters/unhead/index.mjs +1 -1
- package/dist/theme/adapters/v0/index.d.mts +1 -1
- package/dist/theme/adapters/v0/index.mjs +1 -1
- package/dist/theme/index.d.mts +1 -1
- package/dist/theme/index.mjs +3 -3
- package/dist/types/index.d.mts +1 -1
- package/dist/{unhead-DZiD-4Tx.mjs → unhead-dPyVkgiJ.mjs} +2 -2
- package/dist/{useClickOutside-CmCUD_Pf.mjs → useClickOutside-B8naChaQ.mjs} +1405 -288
- package/dist/{useFeatures-ZIvzzuEV.mjs → useFeatures-x2iKp0C8.mjs} +7 -10
- package/dist/{useLocale-DTJx3aKR.mjs → useLocale-BUms59Bw.mjs} +6 -6
- package/dist/{useLogger-BBTcMN61.mjs → useLogger-DPSSa-YR.mjs} +4 -4
- package/dist/{useNotifications-H4knpvNw.mjs → useNotifications-BPTmZWQy.mjs} +22 -11
- package/dist/{usePermissions-B_G12Dwd.mjs → usePermissions-CTi-3pBk.mjs} +6 -6
- package/dist/{useRules--7Qoo60I.mjs → useRules-DNhljkyO.mjs} +2 -2
- package/dist/{useTheme-Co05TEeD.mjs → useTheme-3vW3kFNg.mjs} +5 -5
- package/dist/utilities/index.d.mts +2 -2
- package/dist/utilities/index.mjs +27 -2
- package/dist/{v0-DrOub-e1.d.mts → v0-CRGArJim.d.mts} +4 -4
- package/dist/{v0-D0Mh3EVG.mjs → v0-CotC1PiS.mjs} +5 -3
- package/dist/{v0-Dq3zhexO.mjs → v0-DAlKpCR8.mjs} +3 -4
- package/dist/{v0-D7Fm2C3Y.d.mts → v0-DDELiSI6.d.mts} +3 -3
- package/dist/v0-DYsCJPIu.d.mts +8 -0
- package/dist/{v0-BrTEO5sv.mjs → v0-DadOcxFI.mjs} +2 -2
- package/dist/{v0-Bmow1q_x.mjs → v0-Dvu8fMl3.mjs} +3 -3
- package/dist/{v0-DeiZuexg.mjs → v0-YJQoTLsp.mjs} +6 -4
- package/dist/virtual-BqCRw0ly.d.mts +8 -0
- package/dist/{virtual-C0yHf1DC.mjs → virtual-Dnno49F8.mjs} +3 -4
- package/package.json +10 -10
- package/dist/adapter-58IvIfAZ.d.mts +0 -96
- package/dist/adapter-BvWEd9w-.d.mts +0 -17
- package/dist/adapter-Dhq68tz0.d.mts +0 -11
- package/dist/adapters-BJ5n7rgh.mjs +0 -3
- package/dist/adapters-BnKW0BF_.mjs +0 -2
- package/dist/adapters-CBrvizWb.mjs +0 -4
- package/dist/adapters-CMJGA1k7.mjs +0 -2
- package/dist/adapters-Dse4bPxk.mjs +0 -5
- package/dist/createPagination-CHF7SmmK.mjs +0 -247
- package/dist/index-1XdASTjp.d.mts +0 -13
- package/dist/index-C6rdXZ7j.d.mts +0 -11
- package/dist/index-Dp1HjBxJ.d.mts +0 -13
- package/dist/v0-CdusXjY_.d.mts +0 -8
- package/dist/virtual-D4fckewC.d.mts +0 -8
- /package/dist/{adapter-Be9zUc-n.mjs → adapter-oM18AdUc.mjs} +0 -0
- /package/dist/{htmlElements-D4oMQZPJ.mjs → htmlElements-CHXZfsZu.mjs} +0 -0
- /package/dist/{index-CFhUdAHM.d.mts → index-CKKoxA9V.d.mts} +0 -0
- /package/dist/{index-DuddF-NR.d.mts → index-CLR1QMM3.d.mts} +0 -0
- /package/dist/{index-BgCkepP_.d.mts → index-DJQwYeyx.d.mts} +0 -0
- /package/dist/{index-CROz1VSV.d.mts → index-DWfPppPU.d.mts} +0 -0
- /package/dist/{index-DTvqw22G.d.mts → index-H_hl6-4b.d.mts} +0 -0
- /package/dist/{toArray-as9BWxBK.mjs → toArray-CD2-OxAz.mjs} +0 -0
|
@@ -1,24 +1,23 @@
|
|
|
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-
|
|
2
|
-
import { clamp, instanceExists, isArray, isElement, isFunction, isNull, isNullOrUndefined, isNumber, isObject, isString, isUndefined, mergeDeep, range, resolveIds, resolveIndexes, useId as useId$1 } from "./utilities/index.mjs";
|
|
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-BAe6tA_x.mjs";
|
|
2
|
+
import { clamp, instanceExists, isArray, isElement, isFunction, isNull, isNullOrUndefined, isNumber, isObject, isString, isThenable, isUndefined, mergeDeep, range, resolveIds, resolveIndexes, useId as useId$1 } from "./utilities/index.mjs";
|
|
3
3
|
import { i as useContext, t as createTrinity } from "./createTrinity-BTCs1pYx.mjs";
|
|
4
|
-
import { a as createPlugin, i as useLogger, o as createPluginContext } from "./useLogger-
|
|
5
|
-
import { t as createRegistry } from "./createRegistry-
|
|
6
|
-
import { i as createModel, t as createSelection } from "./createSelection-
|
|
7
|
-
import { t as createSingle } from "./createSingle-
|
|
8
|
-
import "./createTokens-
|
|
9
|
-
import { a as useLocale } from "./useLocale-
|
|
10
|
-
import { c as useTimer } from "./useNotifications-
|
|
11
|
-
import { t as toArray } from "./toArray-
|
|
12
|
-
import {
|
|
13
|
-
import { t as createGroup } from "./createGroup-
|
|
14
|
-
import "./
|
|
15
|
-
import "./
|
|
16
|
-
import
|
|
17
|
-
import "./
|
|
18
|
-
import "./
|
|
19
|
-
import
|
|
20
|
-
import "
|
|
21
|
-
import { computed, effectScope, hasInjectionContext, isRef, nextTick, onMounted, onScopeDispose, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRef, toValue, unref, watch, watchEffect } from "vue";
|
|
4
|
+
import { a as createPlugin, i as useLogger, o as createPluginContext } from "./useLogger-DPSSa-YR.mjs";
|
|
5
|
+
import { t as createRegistry } from "./createRegistry-Db_juawd.mjs";
|
|
6
|
+
import { i as createModel, t as createSelection } from "./createSelection-BeKZMxha.mjs";
|
|
7
|
+
import { t as createSingle } from "./createSingle-Dms2efxr.mjs";
|
|
8
|
+
import "./createTokens-B1lwHZvO.mjs";
|
|
9
|
+
import { a as useLocale } from "./useLocale-BUms59Bw.mjs";
|
|
10
|
+
import { c as useTimer } from "./useNotifications-BPTmZWQy.mjs";
|
|
11
|
+
import { t as toArray } from "./toArray-CD2-OxAz.mjs";
|
|
12
|
+
import { a as createFilter } from "./adapter-C9cR4AcY.mjs";
|
|
13
|
+
import { t as createGroup } from "./createGroup-BSGtfBUE.mjs";
|
|
14
|
+
import "./createDataTable-DDr2yY-A.mjs";
|
|
15
|
+
import { a as useRules, o as isStandardSchema } from "./useRules-DNhljkyO.mjs";
|
|
16
|
+
import "./useFeatures-x2iKp0C8.mjs";
|
|
17
|
+
import "./usePermissions-CTi-3pBk.mjs";
|
|
18
|
+
import { t as MemoryStorageAdapter } from "./memory-BMpJcQjQ.mjs";
|
|
19
|
+
import "./useTheme-3vW3kFNg.mjs";
|
|
20
|
+
import { computed, effectScope, hasInjectionContext, isReadonly, isRef, nextTick, onMounted, onScopeDispose, onWatcherCleanup, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRef, toValue, unref, watch, watchEffect } from "vue";
|
|
22
21
|
//#region src/composables/createBreadcrumbs/index.ts
|
|
23
22
|
/**
|
|
24
23
|
* @module createBreadcrumbs
|
|
@@ -351,6 +350,7 @@ function createFocusTraversal(items, activate, options = {}) {
|
|
|
351
350
|
}
|
|
352
351
|
/** Focus first non-disabled item in the current row (grid mode) */
|
|
353
352
|
function rowFirst() {
|
|
353
|
+
/* v8 ignore next 2 -- defensive: rowFirst is only invoked in grid mode (cols > 0) */
|
|
354
354
|
const cols = toValue(_columns) ?? 0;
|
|
355
355
|
if (!cols) return first();
|
|
356
356
|
const all = items();
|
|
@@ -367,6 +367,7 @@ function createFocusTraversal(items, activate, options = {}) {
|
|
|
367
367
|
}
|
|
368
368
|
/** Focus last non-disabled item in the current row (grid mode) */
|
|
369
369
|
function rowLast() {
|
|
370
|
+
/* v8 ignore next 2 -- defensive: rowLast is only invoked in grid mode (cols > 0) */
|
|
370
371
|
const cols = toValue(_columns) ?? 0;
|
|
371
372
|
if (!cols) return last();
|
|
372
373
|
const all = items();
|
|
@@ -538,6 +539,9 @@ function useVirtualFocus(items, options) {
|
|
|
538
539
|
};
|
|
539
540
|
}
|
|
540
541
|
//#endregion
|
|
542
|
+
//#region src/composables/createCombobox/adapters/adapter.ts
|
|
543
|
+
var ComboboxAdapter = class {};
|
|
544
|
+
//#endregion
|
|
541
545
|
//#region src/composables/createCombobox/adapters/client.ts
|
|
542
546
|
/**
|
|
543
547
|
* @module createCombobox/adapters/client
|
|
@@ -546,9 +550,10 @@ function useVirtualFocus(items, options) {
|
|
|
546
550
|
* Default combobox adapter. Filters items client-side using createFilter.
|
|
547
551
|
* Synchronous, zero debounce — items update immediately as the user types.
|
|
548
552
|
*/
|
|
549
|
-
var
|
|
553
|
+
var ClientComboboxAdapter = class extends ComboboxAdapter {
|
|
550
554
|
options;
|
|
551
555
|
constructor(options = {}) {
|
|
556
|
+
super();
|
|
552
557
|
this.options = options;
|
|
553
558
|
}
|
|
554
559
|
setup(context) {
|
|
@@ -588,7 +593,7 @@ var ClientAdapter = class {
|
|
|
588
593
|
* The consumer watches `query` via useComboboxContext() or slot props
|
|
589
594
|
* and provides filtered items reactively.
|
|
590
595
|
*/
|
|
591
|
-
var
|
|
596
|
+
var ServerComboboxAdapter = class extends ComboboxAdapter {
|
|
592
597
|
setup(context) {
|
|
593
598
|
const isLoading = shallowRef(false);
|
|
594
599
|
return {
|
|
@@ -613,7 +618,7 @@ var ServerAdapter = class {
|
|
|
613
618
|
* chain — it composes existing primitives instead.
|
|
614
619
|
*
|
|
615
620
|
* Key features:
|
|
616
|
-
* - Adapter-based filtering (client-side or server-side via
|
|
621
|
+
* - Adapter-based filtering (client-side or server-side via ClientComboboxAdapter/ServerComboboxAdapter)
|
|
617
622
|
* - Single or multi-select mode
|
|
618
623
|
* - Virtual focus keyboard navigation (aria-activedescendant pattern)
|
|
619
624
|
* - Strict mode: reverts query to selected value on close if no match
|
|
@@ -690,7 +695,7 @@ function createCombobox(options = {}) {
|
|
|
690
695
|
version.value;
|
|
691
696
|
return [...selection.values()];
|
|
692
697
|
});
|
|
693
|
-
const { filtered, isLoading, isEmpty } = (adapter ?? new
|
|
698
|
+
const { filtered, isLoading, isEmpty } = (adapter ?? new ClientComboboxAdapter()).setup({
|
|
694
699
|
query,
|
|
695
700
|
items
|
|
696
701
|
});
|
|
@@ -1069,7 +1074,7 @@ function createValidation(_options = {}) {
|
|
|
1069
1074
|
if (!silent) isValidating.value = true;
|
|
1070
1075
|
try {
|
|
1071
1076
|
const results = await Promise.all(activeRules.map((rule) => rule(val)));
|
|
1072
|
-
if (gen !== generation) return
|
|
1077
|
+
if (gen !== generation) return false;
|
|
1073
1078
|
const errorMessages = results.filter((result) => /* @__PURE__ */ isString(result) || result === false).map((result) => result === false ? "Validation failed" : result);
|
|
1074
1079
|
if (!silent) {
|
|
1075
1080
|
errors.value = errorMessages;
|
|
@@ -1077,7 +1082,7 @@ function createValidation(_options = {}) {
|
|
|
1077
1082
|
}
|
|
1078
1083
|
return errorMessages.length === 0;
|
|
1079
1084
|
} catch (error) {
|
|
1080
|
-
if (gen !== generation) return
|
|
1085
|
+
if (gen !== generation) return false;
|
|
1081
1086
|
if (!silent) {
|
|
1082
1087
|
errors.value = [error instanceof Error ? error.message : "Validation error"];
|
|
1083
1088
|
isValid.value = false;
|
|
@@ -1215,6 +1220,327 @@ function createInput(options) {
|
|
|
1215
1220
|
};
|
|
1216
1221
|
}
|
|
1217
1222
|
//#endregion
|
|
1223
|
+
//#region src/composables/createSortable/index.ts
|
|
1224
|
+
/**
|
|
1225
|
+
* @module createSortable
|
|
1226
|
+
*
|
|
1227
|
+
* @see https://0.vuetifyjs.com/composables/data/create-sortable
|
|
1228
|
+
*
|
|
1229
|
+
* @remarks
|
|
1230
|
+
* Headless ordered-list primitive. Extends `createModel` with mutation primitives
|
|
1231
|
+
* (`swap`, `reorder`) and an enriched `move:ticket` event on the registry event
|
|
1232
|
+
* bus. Honors `disabled` as a real mutation gate at both root and per-ticket scope.
|
|
1233
|
+
*
|
|
1234
|
+
* Pure logical composable — no DnD, no DOM, no keyboard. Drag-and-drop integration
|
|
1235
|
+
* composes with `useDragDrop`; keyboard reorder composes with `useVirtualFocus`.
|
|
1236
|
+
*
|
|
1237
|
+
* @example
|
|
1238
|
+
* ```ts
|
|
1239
|
+
* import { createSortable } from '@vuetify/v0'
|
|
1240
|
+
* import type { SortableTicketInput } from '@vuetify/v0'
|
|
1241
|
+
*
|
|
1242
|
+
* interface TaskTicket extends SortableTicketInput {
|
|
1243
|
+
* value: { id: number; label: string }
|
|
1244
|
+
* }
|
|
1245
|
+
*
|
|
1246
|
+
* const sortable = createSortable<TaskTicket>()
|
|
1247
|
+
* const a = sortable.register({ value: { id: 1, label: 'A' } })
|
|
1248
|
+
* const b = sortable.register({ value: { id: 2, label: 'B' } })
|
|
1249
|
+
*
|
|
1250
|
+
* sortable.move(a.id, 1)
|
|
1251
|
+
* sortable.on('move:ticket', ({ ticket, from, to }) => {
|
|
1252
|
+
* console.log(`${ticket.value.label} moved ${from} → ${to}`)
|
|
1253
|
+
* })
|
|
1254
|
+
* ```
|
|
1255
|
+
*/
|
|
1256
|
+
/**
|
|
1257
|
+
* Create an ordered-list state primitive.
|
|
1258
|
+
*
|
|
1259
|
+
* @param options Sortable options.
|
|
1260
|
+
* @returns A {@link SortableContext} that extends {@link ModelContext}.
|
|
1261
|
+
*
|
|
1262
|
+
* @example
|
|
1263
|
+
* ```ts
|
|
1264
|
+
* const sortable = createSortable<Todo>()
|
|
1265
|
+
* sortable.onboard(todos.value.map(value => ({ value })))
|
|
1266
|
+
* ```
|
|
1267
|
+
*/
|
|
1268
|
+
function createSortable(_options = {}) {
|
|
1269
|
+
const { disabled, ...options } = _options;
|
|
1270
|
+
const model = createModel({
|
|
1271
|
+
...options,
|
|
1272
|
+
events: true,
|
|
1273
|
+
disabled
|
|
1274
|
+
});
|
|
1275
|
+
const logger = useLogger();
|
|
1276
|
+
function move(id, toIndex) {
|
|
1277
|
+
if (toValue(disabled)) return void 0;
|
|
1278
|
+
const ticket = model.get(id);
|
|
1279
|
+
if (!ticket) return void 0;
|
|
1280
|
+
if (toValue(ticket.disabled)) return void 0;
|
|
1281
|
+
const from = ticket.index;
|
|
1282
|
+
const result = model.move(id, toIndex);
|
|
1283
|
+
if (result && result.index !== from) model.emit("move:ticket", {
|
|
1284
|
+
ticket: result,
|
|
1285
|
+
from,
|
|
1286
|
+
to: result.index
|
|
1287
|
+
});
|
|
1288
|
+
return result;
|
|
1289
|
+
}
|
|
1290
|
+
function swap(a, b) {
|
|
1291
|
+
if (toValue(disabled)) return;
|
|
1292
|
+
if (a === b) return;
|
|
1293
|
+
const ta = model.get(a);
|
|
1294
|
+
const tb = model.get(b);
|
|
1295
|
+
if (!ta || !tb) return;
|
|
1296
|
+
if (toValue(ta.disabled) || toValue(tb.disabled)) return;
|
|
1297
|
+
const indexA = ta.index;
|
|
1298
|
+
const indexB = tb.index;
|
|
1299
|
+
model.batch(() => {
|
|
1300
|
+
const ra = model.move(a, indexB);
|
|
1301
|
+
if (ra && ra.index !== indexA) model.emit("move:ticket", {
|
|
1302
|
+
ticket: ra,
|
|
1303
|
+
from: indexA,
|
|
1304
|
+
to: ra.index
|
|
1305
|
+
});
|
|
1306
|
+
const rb = model.move(b, indexA);
|
|
1307
|
+
if (rb && rb.index !== indexB) model.emit("move:ticket", {
|
|
1308
|
+
ticket: rb,
|
|
1309
|
+
from: indexB,
|
|
1310
|
+
to: rb.index
|
|
1311
|
+
});
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1314
|
+
function reorder(ids) {
|
|
1315
|
+
if (toValue(disabled)) return;
|
|
1316
|
+
const currentSize = model.size;
|
|
1317
|
+
if (ids.length !== currentSize) {
|
|
1318
|
+
logger.warn(`Reorder expected ${currentSize} ids, got ${ids.length}.`);
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1321
|
+
const known = new Set(model.keys());
|
|
1322
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1323
|
+
for (const id of ids) {
|
|
1324
|
+
if (!known.has(id)) {
|
|
1325
|
+
logger.warn(`Reorder contains unknown id "${String(id)}".`);
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1328
|
+
if (seen.has(id)) {
|
|
1329
|
+
logger.warn(`Reorder contains duplicate id "${String(id)}".`);
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
seen.add(id);
|
|
1333
|
+
}
|
|
1334
|
+
const froms = /* @__PURE__ */ new Map();
|
|
1335
|
+
for (const id of ids) {
|
|
1336
|
+
const ticket = model.get(id);
|
|
1337
|
+
if (ticket) froms.set(id, ticket.index);
|
|
1338
|
+
}
|
|
1339
|
+
model.batch(() => {
|
|
1340
|
+
model.reorder(ids);
|
|
1341
|
+
for (const [index, id] of ids.entries()) {
|
|
1342
|
+
const from = froms.get(id);
|
|
1343
|
+
if (from === index) continue;
|
|
1344
|
+
const ticket = model.get(id);
|
|
1345
|
+
if (ticket) model.emit("move:ticket", {
|
|
1346
|
+
ticket,
|
|
1347
|
+
from,
|
|
1348
|
+
to: index
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
return {
|
|
1354
|
+
...model,
|
|
1355
|
+
move,
|
|
1356
|
+
swap,
|
|
1357
|
+
reorder,
|
|
1358
|
+
get size() {
|
|
1359
|
+
return model.size;
|
|
1360
|
+
}
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
//#endregion
|
|
1364
|
+
//#region src/composables/createKanban/index.ts
|
|
1365
|
+
/**
|
|
1366
|
+
* @module createKanban
|
|
1367
|
+
*
|
|
1368
|
+
* @see https://0.vuetifyjs.com/composables/data/create-kanban
|
|
1369
|
+
*
|
|
1370
|
+
* @remarks
|
|
1371
|
+
* Headless data-flow management for two-level sortable boards. Wraps a column
|
|
1372
|
+
* sortable; each column ticket carries its own inner sortable on `column.items`.
|
|
1373
|
+
* Adds a `transfer` primitive for cross-column moves with reused `disabled`
|
|
1374
|
+
* gating and a destination-side `accept` predicate. Pure logic — no DnD, no DOM.
|
|
1375
|
+
*
|
|
1376
|
+
* @example
|
|
1377
|
+
* ```ts
|
|
1378
|
+
* import { createKanban } from '@vuetify/v0'
|
|
1379
|
+
* import type { SortableTicketInput } from '@vuetify/v0'
|
|
1380
|
+
*
|
|
1381
|
+
* interface CardTicket extends SortableTicketInput {
|
|
1382
|
+
* value: { title: string }
|
|
1383
|
+
* }
|
|
1384
|
+
*
|
|
1385
|
+
* const kanban = createKanban<CardTicket>()
|
|
1386
|
+
*
|
|
1387
|
+
* const todo = kanban.columns.register({ value: { title: 'Todo' } })
|
|
1388
|
+
* const done = kanban.columns.register({ value: { title: 'Done' } })
|
|
1389
|
+
*
|
|
1390
|
+
* const card = todo.items.register({ value: { title: 'Write spec' } })
|
|
1391
|
+
*
|
|
1392
|
+
* kanban.on('transfer:ticket', ({ ticket, from, to }) => {
|
|
1393
|
+
* console.log(ticket.value.title, from, '→', to)
|
|
1394
|
+
* })
|
|
1395
|
+
*
|
|
1396
|
+
* kanban.transfer(card.id, done.id, 0)
|
|
1397
|
+
* ```
|
|
1398
|
+
*/
|
|
1399
|
+
/**
|
|
1400
|
+
* Create a headless two-level sortable orchestrator.
|
|
1401
|
+
*
|
|
1402
|
+
* @param options Kanban options (currently only `disabled`).
|
|
1403
|
+
* @returns A {@link KanbanContext}.
|
|
1404
|
+
*
|
|
1405
|
+
* @example
|
|
1406
|
+
* ```ts
|
|
1407
|
+
* import { createKanban } from '@vuetify/v0'
|
|
1408
|
+
* import type { KanbanColumnTicketInput, SortableTicketInput } from '@vuetify/v0'
|
|
1409
|
+
*
|
|
1410
|
+
* interface CardTicket extends SortableTicketInput {
|
|
1411
|
+
* value: { title: string }
|
|
1412
|
+
* }
|
|
1413
|
+
*
|
|
1414
|
+
* interface BoardColumn extends KanbanColumnTicketInput<CardTicket> {
|
|
1415
|
+
* value: { title: string }
|
|
1416
|
+
* }
|
|
1417
|
+
*
|
|
1418
|
+
* const kanban = createKanban<CardTicket, BoardColumn>()
|
|
1419
|
+
*
|
|
1420
|
+
* const todo = kanban.columns.register({ value: { title: 'Todo' } })
|
|
1421
|
+
* const review = kanban.columns.register({
|
|
1422
|
+
* value: { title: 'Review' },
|
|
1423
|
+
* accept: card => card.value.title.length > 0,
|
|
1424
|
+
* })
|
|
1425
|
+
*
|
|
1426
|
+
* const spec = todo.items.register({ value: { title: 'Write spec' } })
|
|
1427
|
+
* kanban.transfer(spec.id, review.id, 0)
|
|
1428
|
+
* ```
|
|
1429
|
+
*/
|
|
1430
|
+
function createKanban(_options = {}) {
|
|
1431
|
+
const { disabled, ...options } = _options;
|
|
1432
|
+
const logger = useLogger();
|
|
1433
|
+
const _columns = createSortable({
|
|
1434
|
+
...options,
|
|
1435
|
+
disabled
|
|
1436
|
+
});
|
|
1437
|
+
const lookup = createRegistry({ events: true });
|
|
1438
|
+
const bus = createRegistry({ events: true });
|
|
1439
|
+
const on = bus.on;
|
|
1440
|
+
const off = bus.off;
|
|
1441
|
+
const columns = {
|
|
1442
|
+
..._columns,
|
|
1443
|
+
register(registration) {
|
|
1444
|
+
let ticket;
|
|
1445
|
+
const items = createSortable({ disabled: () => !!toValue(disabled) || !!toValue(ticket?.disabled) });
|
|
1446
|
+
items.on("register:ticket", (t) => {
|
|
1447
|
+
lookup.upsert(t.id, { value: ticket.id });
|
|
1448
|
+
});
|
|
1449
|
+
items.on("unregister:ticket", (t) => {
|
|
1450
|
+
lookup.get(t.id)?.unregister();
|
|
1451
|
+
});
|
|
1452
|
+
ticket = _columns.register({
|
|
1453
|
+
...registration,
|
|
1454
|
+
items
|
|
1455
|
+
});
|
|
1456
|
+
return ticket;
|
|
1457
|
+
},
|
|
1458
|
+
onboard(registrations) {
|
|
1459
|
+
return _columns.batch(() => registrations.map((reg) => columns.register(reg)));
|
|
1460
|
+
},
|
|
1461
|
+
upsert(id, patch = {}, event) {
|
|
1462
|
+
return /* @__PURE__ */ isUndefined(_columns.get(id)) ? columns.register({
|
|
1463
|
+
...patch,
|
|
1464
|
+
id
|
|
1465
|
+
}) : _columns.upsert(id, patch, event);
|
|
1466
|
+
},
|
|
1467
|
+
get size() {
|
|
1468
|
+
return _columns.size;
|
|
1469
|
+
}
|
|
1470
|
+
};
|
|
1471
|
+
function isAccepted(accept, ticket, from, toIndex) {
|
|
1472
|
+
if (/* @__PURE__ */ isUndefined(accept)) return true;
|
|
1473
|
+
try {
|
|
1474
|
+
const result = accept(ticket, from, toIndex);
|
|
1475
|
+
if (/* @__PURE__ */ isThenable(result)) {
|
|
1476
|
+
logger.warn("accept predicate returned a thenable; async predicates are not supported — treating as reject");
|
|
1477
|
+
return false;
|
|
1478
|
+
}
|
|
1479
|
+
return Boolean(result);
|
|
1480
|
+
} catch (error) {
|
|
1481
|
+
logger.error("accept predicate threw; treating as reject", error);
|
|
1482
|
+
return false;
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
columns.on("unregister:ticket", (column) => {
|
|
1486
|
+
column.items.dispose();
|
|
1487
|
+
for (const t of lookup.values()) if (t.value === column.id) t.unregister();
|
|
1488
|
+
});
|
|
1489
|
+
function transfer(id, toColumnId, toIndex) {
|
|
1490
|
+
const fromColumnId = lookup.get(id)?.value;
|
|
1491
|
+
if (/* @__PURE__ */ isUndefined(fromColumnId)) {
|
|
1492
|
+
logger.warn(`unknown ticket id "${String(id)}"`);
|
|
1493
|
+
return;
|
|
1494
|
+
}
|
|
1495
|
+
const source = columns.get(fromColumnId);
|
|
1496
|
+
if (!source) {
|
|
1497
|
+
logger.warn(`unknown source column id "${String(fromColumnId)}"`);
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
const destination = columns.get(toColumnId);
|
|
1501
|
+
if (!destination) {
|
|
1502
|
+
logger.warn(`unknown destination column id "${String(toColumnId)}"`);
|
|
1503
|
+
return;
|
|
1504
|
+
}
|
|
1505
|
+
const ticket = source.items.get(id);
|
|
1506
|
+
if (!ticket) {
|
|
1507
|
+
logger.warn(`ticket "${String(id)}" missing from source column "${String(fromColumnId)}"`);
|
|
1508
|
+
return;
|
|
1509
|
+
}
|
|
1510
|
+
const fromIndex = ticket.index;
|
|
1511
|
+
if (toColumnId === fromColumnId) return source.items.move(id, toIndex);
|
|
1512
|
+
if (toValue(disabled) || toValue(source.disabled) || toValue(destination.disabled) || toValue(ticket.disabled)) return;
|
|
1513
|
+
if (!isAccepted(destination.accept, ticket, fromColumnId, toIndex)) return void 0;
|
|
1514
|
+
if (!/* @__PURE__ */ isUndefined(destination.items.get(id))) {
|
|
1515
|
+
logger.warn(`id "${String(id)}" already exists in destination column "${String(toColumnId)}"`);
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
let registered;
|
|
1519
|
+
let moved;
|
|
1520
|
+
destination.items.batch(() => {
|
|
1521
|
+
const [input] = source.items.offboard([id]);
|
|
1522
|
+
if (/* @__PURE__ */ isUndefined(input)) return;
|
|
1523
|
+
registered = destination.items.register(input);
|
|
1524
|
+
moved = registered.index === toIndex ? registered : destination.items.move(registered.id, toIndex);
|
|
1525
|
+
});
|
|
1526
|
+
const final = moved ?? registered;
|
|
1527
|
+
if (final) bus.emit("transfer:ticket", {
|
|
1528
|
+
ticket: final,
|
|
1529
|
+
from: fromColumnId,
|
|
1530
|
+
to: toColumnId,
|
|
1531
|
+
fromIndex,
|
|
1532
|
+
toIndex: final.index
|
|
1533
|
+
});
|
|
1534
|
+
return final;
|
|
1535
|
+
}
|
|
1536
|
+
return {
|
|
1537
|
+
columns,
|
|
1538
|
+
transfer,
|
|
1539
|
+
on,
|
|
1540
|
+
off
|
|
1541
|
+
};
|
|
1542
|
+
}
|
|
1543
|
+
//#endregion
|
|
1218
1544
|
//#region src/composables/createNested/index.ts
|
|
1219
1545
|
/**
|
|
1220
1546
|
* @module createNested
|
|
@@ -2016,7 +2342,7 @@ function createNumberField(options = {}) {
|
|
|
2016
2342
|
}
|
|
2017
2343
|
function increment(multiplier) {
|
|
2018
2344
|
if (isLocked()) return;
|
|
2019
|
-
if (/* @__PURE__ */ isNull(value.value)) {
|
|
2345
|
+
if (/* @__PURE__ */ isNull(value.value) || !Number.isFinite(value.value)) {
|
|
2020
2346
|
value.value = initialize();
|
|
2021
2347
|
return;
|
|
2022
2348
|
}
|
|
@@ -2024,7 +2350,7 @@ function createNumberField(options = {}) {
|
|
|
2024
2350
|
}
|
|
2025
2351
|
function decrement(multiplier) {
|
|
2026
2352
|
if (isLocked()) return;
|
|
2027
|
-
if (/* @__PURE__ */ isNull(value.value)) {
|
|
2353
|
+
if (/* @__PURE__ */ isNull(value.value) || !Number.isFinite(value.value)) {
|
|
2028
2354
|
value.value = initialize();
|
|
2029
2355
|
return;
|
|
2030
2356
|
}
|
|
@@ -2231,10 +2557,12 @@ const [createHydrationContext, createHydrationPlugin, useHydration] = createPlug
|
|
|
2231
2557
|
*/
|
|
2232
2558
|
/* @__NO_SIDE_EFFECTS__ */
|
|
2233
2559
|
function toElement(target) {
|
|
2234
|
-
|
|
2560
|
+
if (!target) return void 0;
|
|
2561
|
+
if (/* @__PURE__ */ isElement(target)) return target;
|
|
2562
|
+
const raw = /* @__PURE__ */ isFunction(target) ? target() : /* @__PURE__ */ isObject(target) && "value" in target ? target.value : target;
|
|
2235
2563
|
if (!raw) return void 0;
|
|
2236
2564
|
if (/* @__PURE__ */ isElement(raw)) return raw;
|
|
2237
|
-
if ("$el" in raw) return raw.$el;
|
|
2565
|
+
if (/* @__PURE__ */ isObject(raw) && "$el" in raw) return raw.$el;
|
|
2238
2566
|
}
|
|
2239
2567
|
//#endregion
|
|
2240
2568
|
//#region src/composables/createObserver/index.ts
|
|
@@ -2466,6 +2794,7 @@ function useElementSize(target) {
|
|
|
2466
2794
|
const height = shallowRef(0);
|
|
2467
2795
|
const { pause: _pause, resume, stop, isActive, isPaused } = useResizeObserver(target, (entries) => {
|
|
2468
2796
|
const entry = entries[0];
|
|
2797
|
+
/* v8 ignore next 4 -- defensive: ResizeObserver always passes an entry array with at least one entry */
|
|
2469
2798
|
if (entry) {
|
|
2470
2799
|
width.value = entry.contentRect.width;
|
|
2471
2800
|
height.value = entry.contentRect.height;
|
|
@@ -2624,6 +2953,7 @@ function createOverflow(options = {}) {
|
|
|
2624
2953
|
}),
|
|
2625
2954
|
total,
|
|
2626
2955
|
isOverflowing: toRef(() => {
|
|
2956
|
+
if (width.value === 0) return false;
|
|
2627
2957
|
return total.value > width.value - toValue(reserved);
|
|
2628
2958
|
}),
|
|
2629
2959
|
measure,
|
|
@@ -2776,7 +3106,7 @@ function createProgress(options = {}) {
|
|
|
2776
3106
|
}
|
|
2777
3107
|
for (const [index, element] of clamped.entries()) {
|
|
2778
3108
|
const ticket = segments.value[index];
|
|
2779
|
-
if (!ticket || !isRef(ticket.value)) continue;
|
|
3109
|
+
if (!ticket || !isRef(ticket.value) || isReadonly(ticket.value)) continue;
|
|
2780
3110
|
ticket.value.value = element;
|
|
2781
3111
|
}
|
|
2782
3112
|
}
|
|
@@ -3071,8 +3401,8 @@ function createSlider(options = {}) {
|
|
|
3071
3401
|
return inverted.value ? 100 - p : p;
|
|
3072
3402
|
}
|
|
3073
3403
|
function fromPercent(p) {
|
|
3074
|
-
const
|
|
3075
|
-
return numeric.
|
|
3404
|
+
const value = numeric.fromPercent(p);
|
|
3405
|
+
return inverted.value ? numeric.max - (value - numeric.min) : value;
|
|
3076
3406
|
}
|
|
3077
3407
|
function register(input) {
|
|
3078
3408
|
const initialValue = /* @__PURE__ */ isObject(input) ? input.value : input;
|
|
@@ -3634,6 +3964,7 @@ function createVirtual(items, _options = {}) {
|
|
|
3634
3964
|
/* v8 ignore stop */
|
|
3635
3965
|
});
|
|
3636
3966
|
useResizeObserver(element, (entries) => {
|
|
3967
|
+
/* v8 ignore next -- defensive: ResizeObserver always emits at least one entry */
|
|
3637
3968
|
if (!entries[0]) return;
|
|
3638
3969
|
viewportHeight.value = entries[0].contentRect.height;
|
|
3639
3970
|
update();
|
|
@@ -3646,6 +3977,7 @@ function createVirtual(items, _options = {}) {
|
|
|
3646
3977
|
rebuild();
|
|
3647
3978
|
}, { immediate: true });
|
|
3648
3979
|
watch(element, () => {
|
|
3980
|
+
/* v8 ignore next -- defensive: watch fires only when element is present */
|
|
3649
3981
|
if (!element.value) return;
|
|
3650
3982
|
if (direction === "reverse" && items.value.length > 0) {
|
|
3651
3983
|
const lastIndex = items.value.length - 1;
|
|
@@ -3664,6 +3996,7 @@ function createVirtual(items, _options = {}) {
|
|
|
3664
3996
|
anchorOffset = 0;
|
|
3665
3997
|
} else if (/* @__PURE__ */ isFunction(anchor)) {
|
|
3666
3998
|
const result = anchor(items.value);
|
|
3999
|
+
/* v8 ignore next 4 -- function-anchor: tested with valid number return; non-number rejection branch is implicit */
|
|
3667
4000
|
if (/* @__PURE__ */ isNumber(result)) {
|
|
3668
4001
|
anchorIndex = result;
|
|
3669
4002
|
anchorOffset = element.value.scrollTop - (offsets.value[result] || 0);
|
|
@@ -3747,8 +4080,10 @@ function createVirtual(items, _options = {}) {
|
|
|
3747
4080
|
/* v8 ignore stop */
|
|
3748
4081
|
}
|
|
3749
4082
|
function resize(index, height) {
|
|
4083
|
+
/* v8 ignore next -- early bail when height is already correct */
|
|
3750
4084
|
if (heights.value[index] === height) return;
|
|
3751
4085
|
heights.value[index] = height;
|
|
4086
|
+
/* v8 ignore next -- first-call only: itemHeight bootstrapped from initial measurement */
|
|
3752
4087
|
if (!itemHeight.value) itemHeight.value = height;
|
|
3753
4088
|
if (IN_BROWSER) {
|
|
3754
4089
|
cancelAnimationFrame(rebuildRaf);
|
|
@@ -3765,6 +4100,7 @@ function createVirtual(items, _options = {}) {
|
|
|
3765
4100
|
/* v8 ignore stop */
|
|
3766
4101
|
}
|
|
3767
4102
|
function scrollTo(index, scrollOptions) {
|
|
4103
|
+
/* v8 ignore next -- defensive: scrollTo only invoked after element mounts */
|
|
3768
4104
|
if (!element.value) return;
|
|
3769
4105
|
const targetOffset = offsets.value[index] || 0;
|
|
3770
4106
|
const behavior = scrollOptions?.behavior ?? "auto";
|
|
@@ -4284,11 +4620,11 @@ const [createBreakpointsContext, createBreakpointsPlugin, useBreakpoints] = crea
|
|
|
4284
4620
|
*
|
|
4285
4621
|
* @example Using the built-in Temporal adapter
|
|
4286
4622
|
* ```ts
|
|
4287
|
-
* import {
|
|
4623
|
+
* import { V0DateAdapter } from '@vuetify/v0/date'
|
|
4288
4624
|
* import { createDatePlugin } from '@vuetify/v0'
|
|
4289
4625
|
*
|
|
4290
4626
|
* const app = createApp(App)
|
|
4291
|
-
* app.use(createDatePlugin({ adapter: new
|
|
4627
|
+
* app.use(createDatePlugin({ adapter: new V0DateAdapter() }))
|
|
4292
4628
|
*
|
|
4293
4629
|
* // In a component:
|
|
4294
4630
|
* const { adapter } = useDate()
|
|
@@ -4298,9 +4634,9 @@ const [createBreakpointsContext, createBreakpointsPlugin, useBreakpoints] = crea
|
|
|
4298
4634
|
*
|
|
4299
4635
|
* @example Custom adapter
|
|
4300
4636
|
* ```ts
|
|
4301
|
-
* import
|
|
4637
|
+
* import { DateAdapter } from '@vuetify/v0'
|
|
4302
4638
|
*
|
|
4303
|
-
* class DateFnsAdapter
|
|
4639
|
+
* class DateFnsAdapter extends DateAdapter<Date> {
|
|
4304
4640
|
* // ... implementation
|
|
4305
4641
|
* }
|
|
4306
4642
|
*
|
|
@@ -4331,6 +4667,7 @@ const defaultLocales = {
|
|
|
4331
4667
|
function deriveFirstDayOfWeek(locale) {
|
|
4332
4668
|
try {
|
|
4333
4669
|
const info = new Intl.Locale(locale).getWeekInfo?.();
|
|
4670
|
+
/* v8 ignore next -- defensive: getWeekInfo always returns info in Node 22+ */
|
|
4334
4671
|
return info ? info.firstDay % 7 : 0;
|
|
4335
4672
|
} catch {
|
|
4336
4673
|
return 0;
|
|
@@ -4348,14 +4685,14 @@ function deriveFirstDayOfWeek(locale) {
|
|
|
4348
4685
|
*
|
|
4349
4686
|
* @example
|
|
4350
4687
|
* ```ts
|
|
4351
|
-
* import {
|
|
4688
|
+
* import { V0DateAdapter } from '@vuetify/v0/date'
|
|
4352
4689
|
*
|
|
4353
|
-
* const { adapter } = createDate({ adapter: new
|
|
4690
|
+
* const { adapter } = createDate({ adapter: new V0DateAdapter() })
|
|
4354
4691
|
* const today = adapter.date()
|
|
4355
4692
|
*
|
|
4356
4693
|
* // With locale options
|
|
4357
4694
|
* const { adapter } = createDate({
|
|
4358
|
-
* adapter: new
|
|
4695
|
+
* adapter: new V0DateAdapter(),
|
|
4359
4696
|
* locale: 'de-DE',
|
|
4360
4697
|
* })
|
|
4361
4698
|
* ```
|
|
@@ -4410,10 +4747,10 @@ function createDate(options) {
|
|
|
4410
4747
|
*
|
|
4411
4748
|
* @example
|
|
4412
4749
|
* ```ts
|
|
4413
|
-
* import {
|
|
4750
|
+
* import { V0DateAdapter } from '@vuetify/v0/date'
|
|
4414
4751
|
*
|
|
4415
4752
|
* const [useAppDate, provideAppDate] = createDateContext({
|
|
4416
|
-
* adapter: new
|
|
4753
|
+
* adapter: new V0DateAdapter(),
|
|
4417
4754
|
* namespace: 'app:date',
|
|
4418
4755
|
* })
|
|
4419
4756
|
* ```
|
|
@@ -4434,14 +4771,14 @@ function createDateContext(options) {
|
|
|
4434
4771
|
*
|
|
4435
4772
|
* @example
|
|
4436
4773
|
* ```ts
|
|
4437
|
-
* import {
|
|
4774
|
+
* import { V0DateAdapter } from '@vuetify/v0/date'
|
|
4438
4775
|
*
|
|
4439
4776
|
* const app = createApp(App)
|
|
4440
|
-
* app.use(createDatePlugin({ adapter: new
|
|
4777
|
+
* app.use(createDatePlugin({ adapter: new V0DateAdapter() }))
|
|
4441
4778
|
*
|
|
4442
4779
|
* // With locale options
|
|
4443
4780
|
* app.use(createDatePlugin({
|
|
4444
|
-
* adapter: new
|
|
4781
|
+
* adapter: new V0DateAdapter(),
|
|
4445
4782
|
* locale: 'de-DE',
|
|
4446
4783
|
* }))
|
|
4447
4784
|
* ```
|
|
@@ -4475,10 +4812,10 @@ function createDatePlugin(options) {
|
|
|
4475
4812
|
* @example
|
|
4476
4813
|
* ```ts
|
|
4477
4814
|
* // main.ts
|
|
4478
|
-
* import {
|
|
4815
|
+
* import { V0DateAdapter } from '@vuetify/v0/date'
|
|
4479
4816
|
* import { createDatePlugin } from '@vuetify/v0'
|
|
4480
4817
|
*
|
|
4481
|
-
* app.use(createDatePlugin({ adapter: new
|
|
4818
|
+
* app.use(createDatePlugin({ adapter: new V0DateAdapter() }))
|
|
4482
4819
|
* ```
|
|
4483
4820
|
*
|
|
4484
4821
|
* @example
|
|
@@ -4492,127 +4829,1016 @@ function createDatePlugin(options) {
|
|
|
4492
4829
|
* ```
|
|
4493
4830
|
*/
|
|
4494
4831
|
function useDate(namespace = "v0:date") {
|
|
4495
|
-
if (!/* @__PURE__ */ instanceExists()) throw new Error("[v0] useDate() must be called inside a Vue component with createDatePlugin installed.\n\nExample:\n import {
|
|
4832
|
+
if (!/* @__PURE__ */ instanceExists()) throw new Error("[v0] useDate() must be called inside a Vue component with createDatePlugin installed.\n\nExample:\n import { V0DateAdapter } from '@vuetify/v0/date'\n import { createDatePlugin } from '@vuetify/v0'\n\n app.use(createDatePlugin({ adapter: new V0DateAdapter() }))");
|
|
4496
4833
|
return useContext(namespace);
|
|
4497
4834
|
}
|
|
4498
4835
|
//#endregion
|
|
4499
|
-
//#region src/composables/
|
|
4836
|
+
//#region src/composables/useDelay/index.ts
|
|
4500
4837
|
/**
|
|
4501
|
-
*
|
|
4838
|
+
* @module useDelay
|
|
4502
4839
|
*
|
|
4503
|
-
*
|
|
4504
|
-
*
|
|
4840
|
+
* @see https://0.vuetifyjs.com/composables/system/use-delay
|
|
4841
|
+
*
|
|
4842
|
+
* @remarks
|
|
4843
|
+
* Schedule open and close transitions with configurable delays.
|
|
4844
|
+
*
|
|
4845
|
+
* Composes `useTimer` for the underlying lifecycle (start / stop / pause / resume,
|
|
4846
|
+
* plus reactive `isActive`, `isPaused`, `remaining`) and adds direction tracking
|
|
4847
|
+
* (`isOpening`) and promise-based resolution.
|
|
4848
|
+
*
|
|
4849
|
+
* Key features:
|
|
4850
|
+
* - Reactive `openDelay` and `closeDelay` via `MaybeRefOrGetter`
|
|
4851
|
+
* - `start(isOpening)` returns a `Promise<boolean>` that resolves once the delay elapses
|
|
4852
|
+
* - Per-call `minDelay` floor enforces a minimum delay
|
|
4853
|
+
* - Automatic cleanup on scope disposal (timer cleared, pending promise settled with current direction)
|
|
4854
|
+
* - SSR-safe
|
|
4855
|
+
*
|
|
4856
|
+
* @example
|
|
4857
|
+
* ```ts
|
|
4858
|
+
* import { useDelay } from '@vuetify/v0'
|
|
4859
|
+
*
|
|
4860
|
+
* const delay = useDelay(isOpening => isVisible.value = isOpening, {
|
|
4861
|
+
* openDelay: 300,
|
|
4862
|
+
* closeDelay: 200,
|
|
4863
|
+
* })
|
|
4864
|
+
*
|
|
4865
|
+
* delay.start(true)
|
|
4866
|
+
* delay.start(false, { minDelay: 500 })
|
|
4867
|
+
* ```
|
|
4505
4868
|
*/
|
|
4506
|
-
const keyAliasMap = {
|
|
4507
|
-
control: "ctrl",
|
|
4508
|
-
command: "cmd",
|
|
4509
|
-
option: "alt",
|
|
4510
|
-
up: "arrowup",
|
|
4511
|
-
down: "arrowdown",
|
|
4512
|
-
left: "arrowleft",
|
|
4513
|
-
right: "arrowright",
|
|
4514
|
-
esc: "escape",
|
|
4515
|
-
spacebar: " ",
|
|
4516
|
-
space: " ",
|
|
4517
|
-
return: "enter",
|
|
4518
|
-
del: "delete",
|
|
4519
|
-
plus: "+",
|
|
4520
|
-
slash: "/",
|
|
4521
|
-
underscore: "_",
|
|
4522
|
-
minus: "-",
|
|
4523
|
-
hyphen: "-"
|
|
4524
|
-
};
|
|
4525
|
-
/* @__NO_SIDE_EFFECTS__ */
|
|
4526
|
-
function normalizeKey(key) {
|
|
4527
|
-
const lowerKey = key.toLowerCase();
|
|
4528
|
-
return keyAliasMap[lowerKey] ?? lowerKey;
|
|
4529
|
-
}
|
|
4530
|
-
//#endregion
|
|
4531
|
-
//#region src/composables/useHotkey/parsing.ts
|
|
4532
|
-
const logger = /* @__PURE__ */ useLogger();
|
|
4533
|
-
const MODIFIERS = [
|
|
4534
|
-
"ctrl",
|
|
4535
|
-
"shift",
|
|
4536
|
-
"alt",
|
|
4537
|
-
"meta",
|
|
4538
|
-
"cmd"
|
|
4539
|
-
];
|
|
4540
4869
|
/**
|
|
4541
|
-
*
|
|
4870
|
+
* Schedule open and close transitions with configurable delays.
|
|
4542
4871
|
*
|
|
4543
|
-
*
|
|
4544
|
-
*
|
|
4872
|
+
* Composes `useTimer` for the lifecycle (`start` / `stop` / `pause` / `resume` plus
|
|
4873
|
+
* reactive `isActive`, `isPaused`, `remaining`) and adds direction tracking
|
|
4874
|
+
* (`isOpening`) and promise-based resolution.
|
|
4545
4875
|
*
|
|
4546
|
-
* @param
|
|
4547
|
-
* @param
|
|
4548
|
-
* @returns
|
|
4876
|
+
* @param callback Optional callback invoked once a started delay elapses; receives the resolved direction.
|
|
4877
|
+
* @param options Reactive delay settings.
|
|
4878
|
+
* @returns Lifecycle controls and reactive state.
|
|
4879
|
+
*
|
|
4880
|
+
* @see https://0.vuetifyjs.com/composables/system/use-delay
|
|
4881
|
+
*
|
|
4882
|
+
* @example
|
|
4883
|
+
* ```ts
|
|
4884
|
+
* const delay = useDelay(isOpening => isVisible.value = isOpening, {
|
|
4885
|
+
* openDelay: 300,
|
|
4886
|
+
* closeDelay: 200,
|
|
4887
|
+
* })
|
|
4888
|
+
*
|
|
4889
|
+
* delay.start(true)
|
|
4890
|
+
* delay.start(false, { minDelay: 500 })
|
|
4891
|
+
* delay.pause()
|
|
4892
|
+
* delay.resume()
|
|
4893
|
+
* delay.stop()
|
|
4894
|
+
* ```
|
|
4549
4895
|
*/
|
|
4550
|
-
function
|
|
4551
|
-
const
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
if (
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
const nextChar = combination[i + 1];
|
|
4584
|
-
if ([
|
|
4585
|
-
"+",
|
|
4586
|
-
"/",
|
|
4587
|
-
"_",
|
|
4588
|
-
"-"
|
|
4589
|
-
].includes(char))
|
|
4590
|
-
/* v8 ignore start -- edge case: doubled special chars */
|
|
4591
|
-
if (char === nextChar) {
|
|
4592
|
-
flushBuffer(char);
|
|
4593
|
-
keys.push(char);
|
|
4594
|
-
i++;
|
|
4595
|
-
} else if ([
|
|
4596
|
-
"+",
|
|
4597
|
-
"/",
|
|
4598
|
-
"_"
|
|
4599
|
-
].includes(char)) flushBuffer(char);
|
|
4600
|
-
else buffer += char;
|
|
4601
|
-
else buffer += char;
|
|
4896
|
+
function useDelay(callback, options = {}) {
|
|
4897
|
+
const { openDelay, closeDelay } = options;
|
|
4898
|
+
const isOpening = shallowRef(false);
|
|
4899
|
+
let minDelay = 0;
|
|
4900
|
+
let resolver;
|
|
4901
|
+
function fire() {
|
|
4902
|
+
const direction = isOpening.value;
|
|
4903
|
+
const resolve = resolver;
|
|
4904
|
+
resolver = void 0;
|
|
4905
|
+
resolve?.(direction);
|
|
4906
|
+
callback?.(direction);
|
|
4907
|
+
}
|
|
4908
|
+
function duration() {
|
|
4909
|
+
const raw = isOpening.value ? toValue(openDelay) : toValue(closeDelay);
|
|
4910
|
+
return Math.max(minDelay, raw ?? 0);
|
|
4911
|
+
}
|
|
4912
|
+
const timer = useTimer(fire, { duration });
|
|
4913
|
+
function start(direction, options = {}) {
|
|
4914
|
+
const previous = resolver;
|
|
4915
|
+
resolver = void 0;
|
|
4916
|
+
isOpening.value = direction;
|
|
4917
|
+
minDelay = options.minDelay ?? 0;
|
|
4918
|
+
previous?.(direction);
|
|
4919
|
+
const ms = duration();
|
|
4920
|
+
return new Promise((resolve) => {
|
|
4921
|
+
resolver = resolve;
|
|
4922
|
+
if (ms <= 0) {
|
|
4923
|
+
timer.stop();
|
|
4924
|
+
fire();
|
|
4925
|
+
return;
|
|
4926
|
+
}
|
|
4927
|
+
timer.start();
|
|
4928
|
+
});
|
|
4602
4929
|
}
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4930
|
+
function stop() {
|
|
4931
|
+
const resolve = resolver;
|
|
4932
|
+
resolver = void 0;
|
|
4933
|
+
timer.stop();
|
|
4934
|
+
resolve?.(isOpening.value);
|
|
4608
4935
|
}
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4936
|
+
onScopeDispose(() => {
|
|
4937
|
+
const resolve = resolver;
|
|
4938
|
+
resolver = void 0;
|
|
4939
|
+
resolve?.(isOpening.value);
|
|
4940
|
+
}, true);
|
|
4614
4941
|
return {
|
|
4615
|
-
|
|
4942
|
+
start,
|
|
4943
|
+
stop,
|
|
4944
|
+
pause: timer.pause,
|
|
4945
|
+
resume: timer.resume,
|
|
4946
|
+
isActive: shallowReadonly(timer.isActive),
|
|
4947
|
+
isPaused: shallowReadonly(timer.isPaused),
|
|
4948
|
+
remaining: shallowReadonly(timer.remaining),
|
|
4949
|
+
isOpening: shallowReadonly(isOpening)
|
|
4950
|
+
};
|
|
4951
|
+
}
|
|
4952
|
+
//#endregion
|
|
4953
|
+
//#region src/composables/useMutationObserver/index.ts
|
|
4954
|
+
/**
|
|
4955
|
+
* @module useMutationObserver
|
|
4956
|
+
*
|
|
4957
|
+
* @see https://0.vuetifyjs.com/composables/system/use-mutation-observer
|
|
4958
|
+
*
|
|
4959
|
+
* @remarks
|
|
4960
|
+
* MutationObserver composable with lifecycle management.
|
|
4961
|
+
*
|
|
4962
|
+
* Key features:
|
|
4963
|
+
* - MutationObserver API wrapper
|
|
4964
|
+
* - `isActive` reactive flag
|
|
4965
|
+
* - `once` option for single-fire observation
|
|
4966
|
+
* - Pause/resume/stop functionality
|
|
4967
|
+
* - Automatic cleanup on unmount
|
|
4968
|
+
* - SSR-safe (checks SUPPORTS_MUTATION_OBSERVER)
|
|
4969
|
+
* - Hydration-aware
|
|
4970
|
+
* - Configurable observation options (childList, attributes, characterData, etc.)
|
|
4971
|
+
*
|
|
4972
|
+
* Perfect for detecting DOM changes and responding to mutations.
|
|
4973
|
+
*
|
|
4974
|
+
* @example
|
|
4975
|
+
* ```ts
|
|
4976
|
+
* import { useTemplateRef } from 'vue'
|
|
4977
|
+
* import { useMutationObserver } from '@vuetify/v0'
|
|
4978
|
+
*
|
|
4979
|
+
* const target = useTemplateRef('target')
|
|
4980
|
+
* useMutationObserver(target, records => {
|
|
4981
|
+
* console.log(records)
|
|
4982
|
+
* }, { childList: true })
|
|
4983
|
+
* ```
|
|
4984
|
+
*/
|
|
4985
|
+
/**
|
|
4986
|
+
* A composable that uses the Mutation Observer API to detect changes in the DOM.
|
|
4987
|
+
*
|
|
4988
|
+
* @param target The element to observe.
|
|
4989
|
+
* @param callback The callback to execute when a mutation is observed.
|
|
4990
|
+
* @param options The options for the Mutation Observer.
|
|
4991
|
+
* @returns An object with methods to control the observer.
|
|
4992
|
+
*
|
|
4993
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
|
|
4994
|
+
* @see https://0.vuetifyjs.com/composables/system/use-mutation-observer
|
|
4995
|
+
*
|
|
4996
|
+
* @example
|
|
4997
|
+
* ```ts
|
|
4998
|
+
* import { ref } from 'vue'
|
|
4999
|
+
* import { useMutationObserver } from '@vuetify/v0'
|
|
5000
|
+
*
|
|
5001
|
+
* const container = ref<HTMLElement>()
|
|
5002
|
+
*
|
|
5003
|
+
* const { pause, resume, isPaused } = useMutationObserver(
|
|
5004
|
+
* container,
|
|
5005
|
+
* (mutations) => {
|
|
5006
|
+
* mutations.forEach((mutation) => {
|
|
5007
|
+
* if (mutation.type === 'childList') {
|
|
5008
|
+
* console.log('Children changed:', mutation.addedNodes, mutation.removedNodes)
|
|
5009
|
+
* } else if (mutation.type === 'attributes') {
|
|
5010
|
+
* console.log('Attribute changed:', mutation.attributeName)
|
|
5011
|
+
* }
|
|
5012
|
+
* })
|
|
5013
|
+
* },
|
|
5014
|
+
* {
|
|
5015
|
+
* childList: true,
|
|
5016
|
+
* attributes: true,
|
|
5017
|
+
* subtree: true
|
|
5018
|
+
* }
|
|
5019
|
+
* )
|
|
5020
|
+
*
|
|
5021
|
+
* // Pause observation
|
|
5022
|
+
* pause()
|
|
5023
|
+
*
|
|
5024
|
+
* // Resume observation
|
|
5025
|
+
* resume()
|
|
5026
|
+
* ```
|
|
5027
|
+
*/
|
|
5028
|
+
function useMutationObserver(target, callback, options = {}) {
|
|
5029
|
+
const observerOptions = {
|
|
5030
|
+
childList: options.childList ?? true,
|
|
5031
|
+
attributes: options.attributes ?? false,
|
|
5032
|
+
characterData: options.characterData ?? false,
|
|
5033
|
+
subtree: options.subtree ?? false,
|
|
5034
|
+
attributeOldValue: options.attributeOldValue ?? false,
|
|
5035
|
+
characterDataOldValue: options.characterDataOldValue ?? false,
|
|
5036
|
+
attributeFilter: options.attributeFilter
|
|
5037
|
+
};
|
|
5038
|
+
return createObserver(target, callback, {
|
|
5039
|
+
supports: SUPPORTS_MUTATION_OBSERVER,
|
|
5040
|
+
once: options.once,
|
|
5041
|
+
create: (cb) => new MutationObserver((mutations) => {
|
|
5042
|
+
cb(mutations.map((m) => ({
|
|
5043
|
+
type: m.type,
|
|
5044
|
+
target: m.target,
|
|
5045
|
+
addedNodes: m.addedNodes,
|
|
5046
|
+
removedNodes: m.removedNodes,
|
|
5047
|
+
previousSibling: m.previousSibling,
|
|
5048
|
+
nextSibling: m.nextSibling,
|
|
5049
|
+
attributeName: m.attributeName,
|
|
5050
|
+
attributeNamespace: m.attributeNamespace,
|
|
5051
|
+
oldValue: m.oldValue
|
|
5052
|
+
})));
|
|
5053
|
+
}),
|
|
5054
|
+
observe: (obs, el) => obs.observe(el, observerOptions),
|
|
5055
|
+
immediate: options.immediate ? (el) => {
|
|
5056
|
+
const emptyNodeList = {
|
|
5057
|
+
length: 0,
|
|
5058
|
+
item: () => null,
|
|
5059
|
+
forEach: () => {},
|
|
5060
|
+
*[Symbol.iterator]() {}
|
|
5061
|
+
};
|
|
5062
|
+
return [{
|
|
5063
|
+
type: "childList",
|
|
5064
|
+
target: el,
|
|
5065
|
+
addedNodes: emptyNodeList,
|
|
5066
|
+
removedNodes: emptyNodeList,
|
|
5067
|
+
previousSibling: null,
|
|
5068
|
+
nextSibling: null,
|
|
5069
|
+
attributeName: null,
|
|
5070
|
+
attributeNamespace: null,
|
|
5071
|
+
oldValue: null
|
|
5072
|
+
}];
|
|
5073
|
+
} : void 0,
|
|
5074
|
+
onceIncludesImmediate: true
|
|
5075
|
+
});
|
|
5076
|
+
}
|
|
5077
|
+
//#endregion
|
|
5078
|
+
//#region src/composables/useDragDrop/adapters/adapter.ts
|
|
5079
|
+
/**
|
|
5080
|
+
* @module useDragDrop/adapters/adapter
|
|
5081
|
+
*
|
|
5082
|
+
* @remarks
|
|
5083
|
+
* Adapter contract and abstract base for useDragDrop. Concrete adapters extend
|
|
5084
|
+
* `DragDropAdapter<Z>` to share the `cleanup` field, `dispose()` lifecycle, and
|
|
5085
|
+
* the `locate()` DOM-walk helper.
|
|
5086
|
+
*/
|
|
5087
|
+
/**
|
|
5088
|
+
* Abstract base class for useDragDrop adapters. Provides a `cleanup` slot, a
|
|
5089
|
+
* `dispose()` lifecycle, and a `locate()` helper that walks the DOM to find the
|
|
5090
|
+
* draggable ticket whose `el` ancestors a given event target.
|
|
5091
|
+
*
|
|
5092
|
+
* @example
|
|
5093
|
+
* ```ts
|
|
5094
|
+
* import { DragDropAdapter, type DragDropAdapterContext } from '@vuetify/v0'
|
|
5095
|
+
*
|
|
5096
|
+
* class MyAdapter extends DragDropAdapter {
|
|
5097
|
+
* setup (context: DragDropAdapterContext) {
|
|
5098
|
+
* const stop = useEventListener(document, 'mousedown', event => {
|
|
5099
|
+
* const ticket = this.locate(event.target, context)
|
|
5100
|
+
* if (ticket) context.emit.start(ticket, { x: event.clientX, y: event.clientY }, 'pointer')
|
|
5101
|
+
* })
|
|
5102
|
+
* this.cleanup = () => stop()
|
|
5103
|
+
* }
|
|
5104
|
+
* }
|
|
5105
|
+
* ```
|
|
5106
|
+
*/
|
|
5107
|
+
var DragDropAdapter = class {
|
|
5108
|
+
cleanup = null;
|
|
5109
|
+
dispose() {
|
|
5110
|
+
this.cleanup?.();
|
|
5111
|
+
this.cleanup = null;
|
|
5112
|
+
}
|
|
5113
|
+
locate(target, context) {
|
|
5114
|
+
let element = /* @__PURE__ */ isElement(target) ? target : null;
|
|
5115
|
+
while (element) {
|
|
5116
|
+
for (const ticket of context.draggables.values()) if (ticket.el.value === element) return ticket;
|
|
5117
|
+
element = element.parentElement;
|
|
5118
|
+
}
|
|
5119
|
+
return null;
|
|
5120
|
+
}
|
|
5121
|
+
};
|
|
5122
|
+
//#endregion
|
|
5123
|
+
//#region src/composables/useDragDrop/adapters/pointer.ts
|
|
5124
|
+
/**
|
|
5125
|
+
* @module useDragDrop/adapters/pointer
|
|
5126
|
+
*
|
|
5127
|
+
* @remarks
|
|
5128
|
+
* Default pointer adapter for useDragDrop. Listens for `pointerdown` /
|
|
5129
|
+
* `pointermove` / `pointerup` / `pointercancel` on the document and emits the
|
|
5130
|
+
* drag lifecycle. Activation distance is configurable via `threshold`.
|
|
5131
|
+
*/
|
|
5132
|
+
/**
|
|
5133
|
+
* Default pointer adapter. Wires `pointerdown` / `pointermove` / `pointerup` /
|
|
5134
|
+
* `pointercancel` on the document and converts them into drag lifecycle calls.
|
|
5135
|
+
*
|
|
5136
|
+
* @example
|
|
5137
|
+
* ```ts
|
|
5138
|
+
* import { PointerAdapter, useDragDrop } from '@vuetify/v0'
|
|
5139
|
+
*
|
|
5140
|
+
* useDragDrop({ adapters: [new PointerAdapter({ threshold: 10 })] })
|
|
5141
|
+
* ```
|
|
5142
|
+
*/
|
|
5143
|
+
var PointerAdapter = class extends DragDropAdapter {
|
|
5144
|
+
threshold;
|
|
5145
|
+
constructor(options = {}) {
|
|
5146
|
+
super();
|
|
5147
|
+
this.threshold = options.threshold ?? 0;
|
|
5148
|
+
}
|
|
5149
|
+
setup(context) {
|
|
5150
|
+
const logger = useLogger();
|
|
5151
|
+
if (this.cleanup) {
|
|
5152
|
+
logger.warn("PointerAdapter setup called twice; previous registration will be replaced");
|
|
5153
|
+
this.dispose();
|
|
5154
|
+
}
|
|
5155
|
+
if (!IN_BROWSER) return;
|
|
5156
|
+
let downSource = null;
|
|
5157
|
+
let downOrigin = null;
|
|
5158
|
+
let downId = null;
|
|
5159
|
+
let started = false;
|
|
5160
|
+
function reset() {
|
|
5161
|
+
downSource = null;
|
|
5162
|
+
downOrigin = null;
|
|
5163
|
+
downId = null;
|
|
5164
|
+
started = false;
|
|
5165
|
+
}
|
|
5166
|
+
const onDown = (event) => {
|
|
5167
|
+
if (event.button !== 0) return;
|
|
5168
|
+
if (downSource) return;
|
|
5169
|
+
const ticket = this.locate(event.target, context);
|
|
5170
|
+
if (!ticket) return;
|
|
5171
|
+
downSource = ticket;
|
|
5172
|
+
downOrigin = {
|
|
5173
|
+
x: event.clientX,
|
|
5174
|
+
y: event.clientY
|
|
5175
|
+
};
|
|
5176
|
+
downId = event.pointerId;
|
|
5177
|
+
started = false;
|
|
5178
|
+
};
|
|
5179
|
+
const onMove = (event) => {
|
|
5180
|
+
if (!downSource || !downOrigin || event.pointerId !== downId) return;
|
|
5181
|
+
const point = {
|
|
5182
|
+
x: event.clientX,
|
|
5183
|
+
y: event.clientY
|
|
5184
|
+
};
|
|
5185
|
+
if (!started) {
|
|
5186
|
+
const dx = point.x - downOrigin.x;
|
|
5187
|
+
const dy = point.y - downOrigin.y;
|
|
5188
|
+
if (this.threshold > 0 && Math.hypot(dx, dy) < this.threshold) return;
|
|
5189
|
+
context.emit.start(downSource, downOrigin, "pointer");
|
|
5190
|
+
started = true;
|
|
5191
|
+
}
|
|
5192
|
+
context.emit.move(point);
|
|
5193
|
+
};
|
|
5194
|
+
function onUp(event) {
|
|
5195
|
+
if (event.pointerId !== downId) return;
|
|
5196
|
+
if (downSource && started) context.emit.drop();
|
|
5197
|
+
reset();
|
|
5198
|
+
}
|
|
5199
|
+
function onCancel(event) {
|
|
5200
|
+
if (event.pointerId !== downId) return;
|
|
5201
|
+
if (downSource && started) context.emit.cancel();
|
|
5202
|
+
reset();
|
|
5203
|
+
}
|
|
5204
|
+
const stopDown = useEventListener(document, "pointerdown", onDown);
|
|
5205
|
+
const stopMove = useEventListener(document, "pointermove", onMove);
|
|
5206
|
+
const stopUp = useEventListener(document, "pointerup", onUp);
|
|
5207
|
+
const stopCancel = useEventListener(document, "pointercancel", onCancel);
|
|
5208
|
+
this.cleanup = () => {
|
|
5209
|
+
stopDown();
|
|
5210
|
+
stopMove();
|
|
5211
|
+
stopUp();
|
|
5212
|
+
stopCancel();
|
|
5213
|
+
};
|
|
5214
|
+
}
|
|
5215
|
+
};
|
|
5216
|
+
//#endregion
|
|
5217
|
+
//#region src/composables/useDragDrop/adapters/keyboard.ts
|
|
5218
|
+
/**
|
|
5219
|
+
* @module useDragDrop/adapters/keyboard
|
|
5220
|
+
*
|
|
5221
|
+
* @remarks
|
|
5222
|
+
* Default keyboard adapter for useDragDrop. Listens for `keydown` on the
|
|
5223
|
+
* document. Activation keys (default Space and Enter) start and drop drags;
|
|
5224
|
+
* arrow keys nudge the drag point by `step` px; Escape cancels.
|
|
5225
|
+
*/
|
|
5226
|
+
function isEditable(element) {
|
|
5227
|
+
if (/* @__PURE__ */ isNull(element)) return false;
|
|
5228
|
+
const tag = element.tagName;
|
|
5229
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
5230
|
+
if (element.isContentEditable) return true;
|
|
5231
|
+
const role = element.getAttribute("role");
|
|
5232
|
+
return role === "textbox" || role === "searchbox" || role === "combobox" || role === "spinbutton";
|
|
5233
|
+
}
|
|
5234
|
+
/**
|
|
5235
|
+
* Default keyboard adapter. Listens for `keydown` on the document; activation
|
|
5236
|
+
* keys start/drop drags, arrow keys nudge the drag point, Escape cancels.
|
|
5237
|
+
*
|
|
5238
|
+
* @example
|
|
5239
|
+
* ```ts
|
|
5240
|
+
* import { KeyboardAdapter, useDragDrop } from '@vuetify/v0'
|
|
5241
|
+
*
|
|
5242
|
+
* useDragDrop({ adapters: [new KeyboardAdapter({ activate: ['x'], step: 32 })] })
|
|
5243
|
+
* ```
|
|
5244
|
+
*/
|
|
5245
|
+
var KeyboardAdapter = class extends DragDropAdapter {
|
|
5246
|
+
activate;
|
|
5247
|
+
step;
|
|
5248
|
+
constructor(options = {}) {
|
|
5249
|
+
super();
|
|
5250
|
+
this.activate = options.activate ?? [" ", "Enter"];
|
|
5251
|
+
this.step = options.step ?? 16;
|
|
5252
|
+
}
|
|
5253
|
+
setup(context) {
|
|
5254
|
+
const logger = useLogger();
|
|
5255
|
+
if (this.cleanup) {
|
|
5256
|
+
logger.warn("KeyboardAdapter setup called twice; previous registration will be replaced");
|
|
5257
|
+
this.dispose();
|
|
5258
|
+
}
|
|
5259
|
+
if (!IN_BROWSER) return;
|
|
5260
|
+
const onKeyDown = (event) => {
|
|
5261
|
+
const focused = document.activeElement;
|
|
5262
|
+
if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) return;
|
|
5263
|
+
if (isEditable(focused)) return;
|
|
5264
|
+
const ticket = this.locate(focused, context);
|
|
5265
|
+
const isActive = !/* @__PURE__ */ isNull(context.active.value);
|
|
5266
|
+
if (this.activate.includes(event.key)) {
|
|
5267
|
+
if (isActive) {
|
|
5268
|
+
event.preventDefault();
|
|
5269
|
+
context.emit.drop();
|
|
5270
|
+
} else if (ticket) {
|
|
5271
|
+
const el = ticket.el.value;
|
|
5272
|
+
if (!el) {
|
|
5273
|
+
logger.warn("KeyboardAdapter: cannot start drag — element is not mounted");
|
|
5274
|
+
return;
|
|
5275
|
+
}
|
|
5276
|
+
event.preventDefault();
|
|
5277
|
+
const rect = el.getBoundingClientRect();
|
|
5278
|
+
context.emit.start(ticket, {
|
|
5279
|
+
x: rect.left + rect.width / 2,
|
|
5280
|
+
y: rect.top + rect.height / 2
|
|
5281
|
+
}, "keyboard");
|
|
5282
|
+
}
|
|
5283
|
+
return;
|
|
5284
|
+
}
|
|
5285
|
+
if (event.key === "Escape" && isActive) {
|
|
5286
|
+
event.preventDefault();
|
|
5287
|
+
context.emit.cancel();
|
|
5288
|
+
return;
|
|
5289
|
+
}
|
|
5290
|
+
if (isActive && event.key.startsWith("Arrow")) {
|
|
5291
|
+
const active = context.active.value;
|
|
5292
|
+
if (/* @__PURE__ */ isNull(active)) return;
|
|
5293
|
+
const current = active.current;
|
|
5294
|
+
let point = null;
|
|
5295
|
+
switch (event.key) {
|
|
5296
|
+
case "ArrowUp":
|
|
5297
|
+
point = {
|
|
5298
|
+
x: current.x,
|
|
5299
|
+
y: current.y - this.step
|
|
5300
|
+
};
|
|
5301
|
+
break;
|
|
5302
|
+
case "ArrowDown":
|
|
5303
|
+
point = {
|
|
5304
|
+
x: current.x,
|
|
5305
|
+
y: current.y + this.step
|
|
5306
|
+
};
|
|
5307
|
+
break;
|
|
5308
|
+
case "ArrowLeft":
|
|
5309
|
+
point = {
|
|
5310
|
+
x: current.x - this.step,
|
|
5311
|
+
y: current.y
|
|
5312
|
+
};
|
|
5313
|
+
break;
|
|
5314
|
+
case "ArrowRight":
|
|
5315
|
+
point = {
|
|
5316
|
+
x: current.x + this.step,
|
|
5317
|
+
y: current.y
|
|
5318
|
+
};
|
|
5319
|
+
break;
|
|
5320
|
+
}
|
|
5321
|
+
if (point) {
|
|
5322
|
+
event.preventDefault();
|
|
5323
|
+
context.emit.move(point);
|
|
5324
|
+
}
|
|
5325
|
+
}
|
|
5326
|
+
};
|
|
5327
|
+
const stop = useEventListener(document, "keydown", onKeyDown);
|
|
5328
|
+
this.cleanup = () => stop();
|
|
5329
|
+
}
|
|
5330
|
+
};
|
|
5331
|
+
//#endregion
|
|
5332
|
+
//#region src/composables/useDragDrop/index.ts
|
|
5333
|
+
/**
|
|
5334
|
+
* @module useDragDrop
|
|
5335
|
+
*
|
|
5336
|
+
* @see https://0.vuetifyjs.com/composables/system/use-drag-drop
|
|
5337
|
+
*
|
|
5338
|
+
* @remarks
|
|
5339
|
+
* Headless drag-and-drop primitive. Owns two registries (draggables and zones)
|
|
5340
|
+
* plus the active-drag state. Pointer and keyboard adapters ship by default;
|
|
5341
|
+
* lifecycle hooks and a plugin array provide extension points.
|
|
5342
|
+
*
|
|
5343
|
+
* @example
|
|
5344
|
+
* ```ts
|
|
5345
|
+
* import { useDragDrop } from '@vuetify/v0'
|
|
5346
|
+
*
|
|
5347
|
+
* const dnd = useDragDrop()
|
|
5348
|
+
* ```
|
|
5349
|
+
*/
|
|
5350
|
+
/**
|
|
5351
|
+
* Pure math for resolving where in an oriented zone a pointer would drop.
|
|
5352
|
+
* Internal — consumers rely on the `position.index` / `position.indicator`
|
|
5353
|
+
* fields delivered to `onDrop`.
|
|
5354
|
+
*/
|
|
5355
|
+
function resolveDropPosition(point, rects, orientation) {
|
|
5356
|
+
if (rects.length === 0) return null;
|
|
5357
|
+
const axis = orientation === "vertical" ? "y" : "x";
|
|
5358
|
+
const start = orientation === "vertical" ? "top" : "left";
|
|
5359
|
+
const end = orientation === "vertical" ? "bottom" : "right";
|
|
5360
|
+
const coord = point[axis];
|
|
5361
|
+
if (coord < rects[0][start]) return {
|
|
5362
|
+
index: 0,
|
|
5363
|
+
edge: "before",
|
|
5364
|
+
rect: rects[0]
|
|
5365
|
+
};
|
|
5366
|
+
const last = rects.at(-1);
|
|
5367
|
+
if (coord > last[end]) return {
|
|
5368
|
+
index: rects.length,
|
|
5369
|
+
edge: "after",
|
|
5370
|
+
rect: last
|
|
5371
|
+
};
|
|
5372
|
+
for (const [index, rect] of rects.entries()) if (coord >= rect[start] && coord <= rect[end]) {
|
|
5373
|
+
if (coord < rect[start] + (rect[end] - rect[start]) / 2) return {
|
|
5374
|
+
index,
|
|
5375
|
+
edge: "before",
|
|
5376
|
+
rect
|
|
5377
|
+
};
|
|
5378
|
+
return {
|
|
5379
|
+
index: index + 1,
|
|
5380
|
+
edge: "after",
|
|
5381
|
+
rect
|
|
5382
|
+
};
|
|
5383
|
+
}
|
|
5384
|
+
for (let index = 0; index < rects.length - 1; index++) {
|
|
5385
|
+
const a = rects[index];
|
|
5386
|
+
const b = rects[index + 1];
|
|
5387
|
+
if (coord > a[end] && coord < b[start]) {
|
|
5388
|
+
if (coord <= (a[end] + b[start]) / 2) return {
|
|
5389
|
+
index: index + 1,
|
|
5390
|
+
edge: "after",
|
|
5391
|
+
rect: a
|
|
5392
|
+
};
|
|
5393
|
+
return {
|
|
5394
|
+
index: index + 1,
|
|
5395
|
+
edge: "before",
|
|
5396
|
+
rect: b
|
|
5397
|
+
};
|
|
5398
|
+
}
|
|
5399
|
+
}
|
|
5400
|
+
return {
|
|
5401
|
+
index: rects.length,
|
|
5402
|
+
edge: "after",
|
|
5403
|
+
rect: last
|
|
5404
|
+
};
|
|
5405
|
+
}
|
|
5406
|
+
/**
|
|
5407
|
+
* Create a headless drag-and-drop context.
|
|
5408
|
+
*
|
|
5409
|
+
* @param options - Adapters, plugins, and lifecycle hooks. All optional.
|
|
5410
|
+
* @returns A `DragDropContext<Z>` exposing `draggables` / `zones` registries,
|
|
5411
|
+
* the `active` drag, the `isDragging` boolean, and a programmatic `cancel()`.
|
|
5412
|
+
*
|
|
5413
|
+
* @see https://0.vuetifyjs.com/composables/system/use-drag-drop
|
|
5414
|
+
*
|
|
5415
|
+
* @example
|
|
5416
|
+
* ```ts
|
|
5417
|
+
* import { useDragDrop } from '@vuetify/v0'
|
|
5418
|
+
* import { useTemplateRef } from 'vue'
|
|
5419
|
+
*
|
|
5420
|
+
* const dnd = useDragDrop<{ type: 'card', value: string }>()
|
|
5421
|
+
*
|
|
5422
|
+
* const draggable = useTemplateRef<HTMLElement>('draggable')
|
|
5423
|
+
* const dropzone = useTemplateRef<HTMLElement>('dropzone')
|
|
5424
|
+
*
|
|
5425
|
+
* dnd.draggables.register({ el: draggable, type: 'card', value: 'card-1' })
|
|
5426
|
+
* dnd.zones.register({
|
|
5427
|
+
* el: dropzone,
|
|
5428
|
+
* accept: ['card'],
|
|
5429
|
+
* onDrop: (drag, position) => console.log(drag.value, position.index),
|
|
5430
|
+
* })
|
|
5431
|
+
* ```
|
|
5432
|
+
*/
|
|
5433
|
+
function useDragDrop(options = {}) {
|
|
5434
|
+
const { plugins = [] } = options;
|
|
5435
|
+
const logger = useLogger();
|
|
5436
|
+
const _draggables = createRegistry({ events: true });
|
|
5437
|
+
const _zones = createRegistry({ events: true });
|
|
5438
|
+
const active = shallowRef(null);
|
|
5439
|
+
const isDragging = toRef(() => !/* @__PURE__ */ isNull(active.value));
|
|
5440
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
5441
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
5442
|
+
function next(fn, ...args) {
|
|
5443
|
+
if (/* @__PURE__ */ isUndefined(fn)) return;
|
|
5444
|
+
try {
|
|
5445
|
+
fn(...args);
|
|
5446
|
+
} catch (error) {
|
|
5447
|
+
logger.error("useDragDrop hook threw", error);
|
|
5448
|
+
}
|
|
5449
|
+
}
|
|
5450
|
+
function safeAccept(accept, drag) {
|
|
5451
|
+
try {
|
|
5452
|
+
if (/* @__PURE__ */ isNull(drag)) return false;
|
|
5453
|
+
if (/* @__PURE__ */ isUndefined(accept)) return true;
|
|
5454
|
+
if (/* @__PURE__ */ isArray(accept)) return accept.includes(drag.type);
|
|
5455
|
+
const result = accept(drag);
|
|
5456
|
+
if (/* @__PURE__ */ isThenable(result)) {
|
|
5457
|
+
logger.warn("useDragDrop accept predicate returned a thenable; async predicates are not supported — treating as reject");
|
|
5458
|
+
return false;
|
|
5459
|
+
}
|
|
5460
|
+
return Boolean(result);
|
|
5461
|
+
} catch (error) {
|
|
5462
|
+
logger.error("useDragDrop accept predicate threw; treating as reject", error);
|
|
5463
|
+
return false;
|
|
5464
|
+
}
|
|
5465
|
+
}
|
|
5466
|
+
const draggables = {
|
|
5467
|
+
..._draggables,
|
|
5468
|
+
register(registration) {
|
|
5469
|
+
const id = registration.id ?? /* @__PURE__ */ useId$1();
|
|
5470
|
+
const el = toRef(() => toValue(registration.el));
|
|
5471
|
+
const dragging = toRef(() => active.value?.id === id);
|
|
5472
|
+
const input = {
|
|
5473
|
+
...registration,
|
|
5474
|
+
id,
|
|
5475
|
+
el,
|
|
5476
|
+
isDragging: dragging
|
|
5477
|
+
};
|
|
5478
|
+
return _draggables.register(input);
|
|
5479
|
+
}
|
|
5480
|
+
};
|
|
5481
|
+
const zones = {
|
|
5482
|
+
..._zones,
|
|
5483
|
+
register(registration) {
|
|
5484
|
+
const id = registration.id ?? /* @__PURE__ */ useId$1();
|
|
5485
|
+
const el = toRef(() => toValue(registration.el));
|
|
5486
|
+
const isOver = toRef(() => active.value?.over === id);
|
|
5487
|
+
const willAccept = toRef(() => safeAccept(registration.accept, active.value));
|
|
5488
|
+
const rects = shallowRef([]);
|
|
5489
|
+
function refresh() {
|
|
5490
|
+
const zoneEl = el.value;
|
|
5491
|
+
rects.value = zoneEl ? Array.from(zoneEl.children).map((child) => child.getBoundingClientRect()) : [];
|
|
5492
|
+
}
|
|
5493
|
+
const scope = effectScope();
|
|
5494
|
+
scopes.set(id, scope);
|
|
5495
|
+
scope.run(() => {
|
|
5496
|
+
if (registration.orientation) {
|
|
5497
|
+
watch(el, refresh, {
|
|
5498
|
+
immediate: true,
|
|
5499
|
+
flush: "post"
|
|
5500
|
+
});
|
|
5501
|
+
useResizeObserver(el, refresh);
|
|
5502
|
+
useMutationObserver(el, refresh, { childList: true });
|
|
5503
|
+
watch(() => active.value?.id, (id) => {
|
|
5504
|
+
if (id) refresh();
|
|
5505
|
+
});
|
|
5506
|
+
}
|
|
5507
|
+
watch(el, (current) => {
|
|
5508
|
+
if (/* @__PURE__ */ isNull(current)) return;
|
|
5509
|
+
nodes.set(current, id);
|
|
5510
|
+
onWatcherCleanup(() => nodes.delete(current));
|
|
5511
|
+
}, { immediate: true });
|
|
5512
|
+
});
|
|
5513
|
+
const indicator = computed(() => {
|
|
5514
|
+
if (!registration.orientation || !isOver.value || !active.value) return null;
|
|
5515
|
+
return resolveDropPosition(active.value.current, rects.value, registration.orientation);
|
|
5516
|
+
});
|
|
5517
|
+
const input = {
|
|
5518
|
+
...registration,
|
|
5519
|
+
id,
|
|
5520
|
+
el,
|
|
5521
|
+
isOver,
|
|
5522
|
+
willAccept,
|
|
5523
|
+
indicator
|
|
5524
|
+
};
|
|
5525
|
+
return _zones.register(input);
|
|
5526
|
+
}
|
|
5527
|
+
};
|
|
5528
|
+
function at(point) {
|
|
5529
|
+
if (!IN_BROWSER) return null;
|
|
5530
|
+
let element = document.elementFromPoint(point.x, point.y);
|
|
5531
|
+
while (element) {
|
|
5532
|
+
const id = nodes.get(element);
|
|
5533
|
+
if (!/* @__PURE__ */ isUndefined(id)) {
|
|
5534
|
+
const zone = _zones.get(id);
|
|
5535
|
+
if (zone && !toValue(zone.disabled)) return id;
|
|
5536
|
+
}
|
|
5537
|
+
element = element.parentElement;
|
|
5538
|
+
}
|
|
5539
|
+
return null;
|
|
5540
|
+
}
|
|
5541
|
+
function position(zoneId, drag) {
|
|
5542
|
+
const zone = _zones.get(zoneId);
|
|
5543
|
+
const out = { pointer: drag.current };
|
|
5544
|
+
if (zone?.orientation) {
|
|
5545
|
+
const resolved = zone.indicator?.value ?? null;
|
|
5546
|
+
if (resolved) {
|
|
5547
|
+
out.index = resolved.index;
|
|
5548
|
+
out.indicator = resolved;
|
|
5549
|
+
} else out.index = 0;
|
|
5550
|
+
}
|
|
5551
|
+
return out;
|
|
5552
|
+
}
|
|
5553
|
+
function bail(drag, reason = "cancel") {
|
|
5554
|
+
active.value = null;
|
|
5555
|
+
if (!/* @__PURE__ */ isNull(drag.over)) next(_zones.get(drag.over)?.onLeave, drag);
|
|
5556
|
+
next(_draggables.get(drag.id)?.onCancel, drag, reason);
|
|
5557
|
+
next(options.onCancel, drag, reason);
|
|
5558
|
+
}
|
|
5559
|
+
function onStart(source, origin, via) {
|
|
5560
|
+
if (toValue(_draggables.get(source.id)?.disabled)) return;
|
|
5561
|
+
const draft = {
|
|
5562
|
+
id: source.id,
|
|
5563
|
+
type: source.type,
|
|
5564
|
+
value: source.value,
|
|
5565
|
+
origin,
|
|
5566
|
+
current: origin,
|
|
5567
|
+
delta: {
|
|
5568
|
+
x: 0,
|
|
5569
|
+
y: 0
|
|
5570
|
+
},
|
|
5571
|
+
over: null,
|
|
5572
|
+
willAccept: false,
|
|
5573
|
+
via
|
|
5574
|
+
};
|
|
5575
|
+
try {
|
|
5576
|
+
if (_draggables.get(source.id)?.onBeforeStart?.(draft) === false) return;
|
|
5577
|
+
} catch (error) {
|
|
5578
|
+
logger.error("useDragDrop onBeforeStart threw; treating as veto", error);
|
|
5579
|
+
return;
|
|
5580
|
+
}
|
|
5581
|
+
try {
|
|
5582
|
+
if (options.onBeforeStart?.(draft) === false) return;
|
|
5583
|
+
} catch (error) {
|
|
5584
|
+
logger.error("useDragDrop onBeforeStart threw; treating as veto", error);
|
|
5585
|
+
return;
|
|
5586
|
+
}
|
|
5587
|
+
active.value = draft;
|
|
5588
|
+
}
|
|
5589
|
+
function onMove(point) {
|
|
5590
|
+
if (!active.value) return;
|
|
5591
|
+
const over = at(point);
|
|
5592
|
+
const draft = {
|
|
5593
|
+
...active.value,
|
|
5594
|
+
current: point,
|
|
5595
|
+
delta: {
|
|
5596
|
+
x: point.x - active.value.origin.x,
|
|
5597
|
+
y: point.y - active.value.origin.y
|
|
5598
|
+
},
|
|
5599
|
+
over,
|
|
5600
|
+
willAccept: false
|
|
5601
|
+
};
|
|
5602
|
+
draft.willAccept = !/* @__PURE__ */ isNull(over) && safeAccept(_zones.get(over)?.accept, draft);
|
|
5603
|
+
const previous = active.value.over;
|
|
5604
|
+
active.value = draft;
|
|
5605
|
+
if (previous !== over) {
|
|
5606
|
+
if (!/* @__PURE__ */ isNull(previous)) next(_zones.get(previous)?.onLeave, draft);
|
|
5607
|
+
if (!/* @__PURE__ */ isNull(over)) next(_zones.get(over)?.onEnter, draft);
|
|
5608
|
+
}
|
|
5609
|
+
next(_draggables.get(draft.id)?.onMove, draft);
|
|
5610
|
+
next(options.onMove, draft);
|
|
5611
|
+
}
|
|
5612
|
+
function onDrop() {
|
|
5613
|
+
if (!active.value) return;
|
|
5614
|
+
const drag = active.value;
|
|
5615
|
+
const zoneId = drag.over;
|
|
5616
|
+
if (/* @__PURE__ */ isNull(zoneId)) {
|
|
5617
|
+
bail(drag);
|
|
5618
|
+
return;
|
|
5619
|
+
}
|
|
5620
|
+
const dropAt = position(zoneId, drag);
|
|
5621
|
+
const zone = _zones.get(zoneId);
|
|
5622
|
+
function vetoed(fn, label) {
|
|
5623
|
+
if (!fn) return false;
|
|
5624
|
+
try {
|
|
5625
|
+
return fn(drag, dropAt) === false;
|
|
5626
|
+
} catch (error) {
|
|
5627
|
+
logger.error(`useDragDrop ${label} threw; treating as veto`, error);
|
|
5628
|
+
return true;
|
|
5629
|
+
}
|
|
5630
|
+
}
|
|
5631
|
+
if (vetoed(zone?.onBeforeDrop, "zone onBeforeDrop") || vetoed(options.onBeforeDrop, "options onBeforeDrop")) {
|
|
5632
|
+
bail(drag, "reject");
|
|
5633
|
+
return;
|
|
5634
|
+
}
|
|
5635
|
+
active.value = null;
|
|
5636
|
+
next(zone?.onDrop, drag, dropAt);
|
|
5637
|
+
next(options.onDrop, drag, dropAt);
|
|
5638
|
+
}
|
|
5639
|
+
function cancel() {
|
|
5640
|
+
if (!active.value) return;
|
|
5641
|
+
bail(active.value);
|
|
5642
|
+
}
|
|
5643
|
+
const context = {
|
|
5644
|
+
draggables,
|
|
5645
|
+
zones,
|
|
5646
|
+
active: shallowReadonly(active),
|
|
5647
|
+
isDragging,
|
|
5648
|
+
cancel
|
|
5649
|
+
};
|
|
5650
|
+
const disposers = [];
|
|
5651
|
+
const adapters = options.adapters ?? [new PointerAdapter(), new KeyboardAdapter()];
|
|
5652
|
+
const emit = {
|
|
5653
|
+
start: (source, origin, via) => onStart(source, origin, via),
|
|
5654
|
+
move: (point) => onMove(point),
|
|
5655
|
+
drop: () => onDrop(),
|
|
5656
|
+
cancel: () => cancel()
|
|
5657
|
+
};
|
|
5658
|
+
const adapterContext = {
|
|
5659
|
+
...context,
|
|
5660
|
+
emit
|
|
5661
|
+
};
|
|
5662
|
+
for (const adapter of adapters) try {
|
|
5663
|
+
adapter.setup(adapterContext);
|
|
5664
|
+
disposers.push(() => adapter.dispose());
|
|
5665
|
+
} catch (error) {
|
|
5666
|
+
logger.error("useDragDrop adapter setup threw; skipping adapter", error);
|
|
5667
|
+
try {
|
|
5668
|
+
adapter.dispose();
|
|
5669
|
+
} catch (disposeError) {
|
|
5670
|
+
logger.error("useDragDrop adapter dispose threw after setup failure", disposeError);
|
|
5671
|
+
}
|
|
5672
|
+
}
|
|
5673
|
+
for (const plugin of plugins) try {
|
|
5674
|
+
const dispose = plugin(context);
|
|
5675
|
+
if (/* @__PURE__ */ isFunction(dispose)) disposers.push(dispose);
|
|
5676
|
+
} catch (error) {
|
|
5677
|
+
logger.error("useDragDrop plugin install threw; skipping plugin", error);
|
|
5678
|
+
}
|
|
5679
|
+
_draggables.on("unregister:ticket", (ticket) => {
|
|
5680
|
+
if (active.value?.id === ticket.id) cancel();
|
|
5681
|
+
});
|
|
5682
|
+
_zones.on("unregister:ticket", (ticket) => {
|
|
5683
|
+
const scope = scopes.get(ticket.id);
|
|
5684
|
+
if (scope) {
|
|
5685
|
+
scope.stop();
|
|
5686
|
+
scopes.delete(ticket.id);
|
|
5687
|
+
}
|
|
5688
|
+
if (active.value?.over === ticket.id) {
|
|
5689
|
+
next(ticket.onLeave, active.value);
|
|
5690
|
+
active.value = {
|
|
5691
|
+
...active.value,
|
|
5692
|
+
over: null,
|
|
5693
|
+
willAccept: false
|
|
5694
|
+
};
|
|
5695
|
+
}
|
|
5696
|
+
});
|
|
5697
|
+
onScopeDispose(() => {
|
|
5698
|
+
if (!/* @__PURE__ */ isNull(active.value)) cancel();
|
|
5699
|
+
for (const dispose of disposers.toReversed()) try {
|
|
5700
|
+
dispose();
|
|
5701
|
+
} catch (error) {
|
|
5702
|
+
logger.error("useDragDrop disposer threw", error);
|
|
5703
|
+
}
|
|
5704
|
+
for (const scope of scopes.values()) try {
|
|
5705
|
+
scope.stop();
|
|
5706
|
+
} catch (error) {
|
|
5707
|
+
logger.error("useDragDrop zone scope dispose threw", error);
|
|
5708
|
+
}
|
|
5709
|
+
scopes.clear();
|
|
5710
|
+
nodes.clear();
|
|
5711
|
+
try {
|
|
5712
|
+
_draggables.dispose();
|
|
5713
|
+
} catch (error) {
|
|
5714
|
+
logger.error("useDragDrop draggables dispose threw", error);
|
|
5715
|
+
}
|
|
5716
|
+
try {
|
|
5717
|
+
_zones.dispose();
|
|
5718
|
+
} catch (error) {
|
|
5719
|
+
logger.error("useDragDrop zones dispose threw", error);
|
|
5720
|
+
}
|
|
5721
|
+
}, true);
|
|
5722
|
+
return context;
|
|
5723
|
+
}
|
|
5724
|
+
//#endregion
|
|
5725
|
+
//#region src/composables/useHotkey/aliases.ts
|
|
5726
|
+
/**
|
|
5727
|
+
* Key alias mapping for consistent key normalization across the hotkey system.
|
|
5728
|
+
*
|
|
5729
|
+
* Maps user-friendly aliases to canonical key names that match
|
|
5730
|
+
* KeyboardEvent.key values (in lowercase) where possible.
|
|
5731
|
+
*/
|
|
5732
|
+
const keyAliasMap = {
|
|
5733
|
+
control: "ctrl",
|
|
5734
|
+
command: "cmd",
|
|
5735
|
+
option: "alt",
|
|
5736
|
+
up: "arrowup",
|
|
5737
|
+
down: "arrowdown",
|
|
5738
|
+
left: "arrowleft",
|
|
5739
|
+
right: "arrowright",
|
|
5740
|
+
esc: "escape",
|
|
5741
|
+
spacebar: " ",
|
|
5742
|
+
space: " ",
|
|
5743
|
+
return: "enter",
|
|
5744
|
+
del: "delete",
|
|
5745
|
+
plus: "+",
|
|
5746
|
+
slash: "/",
|
|
5747
|
+
underscore: "_",
|
|
5748
|
+
minus: "-",
|
|
5749
|
+
hyphen: "-"
|
|
5750
|
+
};
|
|
5751
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
5752
|
+
function normalizeKey(key) {
|
|
5753
|
+
const lowerKey = key.toLowerCase();
|
|
5754
|
+
return keyAliasMap[lowerKey] ?? lowerKey;
|
|
5755
|
+
}
|
|
5756
|
+
//#endregion
|
|
5757
|
+
//#region src/composables/useHotkey/parsing.ts
|
|
5758
|
+
const logger = /* @__PURE__ */ useLogger();
|
|
5759
|
+
const MODIFIERS = [
|
|
5760
|
+
"ctrl",
|
|
5761
|
+
"shift",
|
|
5762
|
+
"alt",
|
|
5763
|
+
"meta",
|
|
5764
|
+
"cmd"
|
|
5765
|
+
];
|
|
5766
|
+
/**
|
|
5767
|
+
* Splits a single combination string into individual key parts.
|
|
5768
|
+
*
|
|
5769
|
+
* A combination is a set of keys that must be pressed simultaneously.
|
|
5770
|
+
* e.g. `ctrl+k`, `shift+-`
|
|
5771
|
+
*
|
|
5772
|
+
* @param combination - The combination string to parse
|
|
5773
|
+
* @param isInternal - Whether this is an internal call (suppresses warnings)
|
|
5774
|
+
* @returns Object with keys array and separators array
|
|
5775
|
+
*/
|
|
5776
|
+
function splitKeyCombination(combination, isInternal = false) {
|
|
5777
|
+
const emptyResult = {
|
|
5778
|
+
keys: [],
|
|
5779
|
+
separators: []
|
|
5780
|
+
};
|
|
5781
|
+
if (!combination) {
|
|
5782
|
+
if (!isInternal) logger.warn("Invalid hotkey combination: empty string provided");
|
|
5783
|
+
return emptyResult;
|
|
5784
|
+
}
|
|
5785
|
+
if (combination.length > 1 && [
|
|
5786
|
+
"+",
|
|
5787
|
+
"/",
|
|
5788
|
+
"_"
|
|
5789
|
+
].some((v) => combination.startsWith(v)) && ![
|
|
5790
|
+
"++",
|
|
5791
|
+
"//",
|
|
5792
|
+
"__"
|
|
5793
|
+
].some((v) => combination.startsWith(v)) || combination.includes("++") || combination.includes("//") || combination.includes("__") || combination === "+" || combination === "/" || combination === "_" || combination.length > 1 && (combination.endsWith("+") || combination.endsWith("/") || combination.endsWith("_")) && combination.at(-2) !== combination.at(-1) || combination === "++" || combination === "--" || combination === "__") {
|
|
5794
|
+
if (!isInternal) logger.warn(`Invalid hotkey combination: "${combination}" has invalid structure`);
|
|
5795
|
+
return emptyResult;
|
|
5796
|
+
}
|
|
5797
|
+
const keys = [];
|
|
5798
|
+
const separators = [];
|
|
5799
|
+
let buffer = "";
|
|
5800
|
+
function flushBuffer(separator) {
|
|
5801
|
+
if (buffer) {
|
|
5802
|
+
if (separator) separators.push(separator);
|
|
5803
|
+
keys.push(/* @__PURE__ */ normalizeKey(buffer));
|
|
5804
|
+
buffer = "";
|
|
5805
|
+
}
|
|
5806
|
+
}
|
|
5807
|
+
for (let i = 0; i < combination.length; i++) {
|
|
5808
|
+
const char = combination[i];
|
|
5809
|
+
const nextChar = combination[i + 1];
|
|
5810
|
+
if ([
|
|
5811
|
+
"+",
|
|
5812
|
+
"/",
|
|
5813
|
+
"_",
|
|
5814
|
+
"-"
|
|
5815
|
+
].includes(char))
|
|
5816
|
+
/* v8 ignore start -- edge case: doubled special chars */
|
|
5817
|
+
if (char === nextChar) {
|
|
5818
|
+
flushBuffer(char);
|
|
5819
|
+
keys.push(char);
|
|
5820
|
+
i++;
|
|
5821
|
+
} else if ([
|
|
5822
|
+
"+",
|
|
5823
|
+
"/",
|
|
5824
|
+
"_"
|
|
5825
|
+
].includes(char)) flushBuffer(char);
|
|
5826
|
+
else buffer += char;
|
|
5827
|
+
else buffer += char;
|
|
5828
|
+
}
|
|
5829
|
+
flushBuffer();
|
|
5830
|
+
/* v8 ignore start -- edge case: invalid minus in combination */
|
|
5831
|
+
if (keys.some((key) => key.length > 1 && key.includes("-") && key !== "--")) {
|
|
5832
|
+
if (!isInternal) logger.warn(`Invalid hotkey combination: "${combination}" has invalid structure`);
|
|
5833
|
+
return emptyResult;
|
|
5834
|
+
}
|
|
5835
|
+
if (keys.length === 0 && combination) return {
|
|
5836
|
+
keys: [/* @__PURE__ */ normalizeKey(combination)],
|
|
5837
|
+
separators
|
|
5838
|
+
};
|
|
5839
|
+
/* v8 ignore stop */
|
|
5840
|
+
return {
|
|
5841
|
+
keys,
|
|
4616
5842
|
separators
|
|
4617
5843
|
};
|
|
4618
5844
|
}
|
|
@@ -4756,9 +5982,11 @@ function useHotkey(keys, callback, options = {}, _platform) {
|
|
|
4756
5982
|
let isSequence = false;
|
|
4757
5983
|
let groupIndex = 0;
|
|
4758
5984
|
function isInputFocused() {
|
|
5985
|
+
/* v8 ignore next -- IN_BROWSER always true in happy-dom test env */
|
|
4759
5986
|
if (!IN_BROWSER) return false;
|
|
4760
5987
|
if (toValue(inputs)) return false;
|
|
4761
5988
|
const activeElement = document.activeElement;
|
|
5989
|
+
/* v8 ignore next -- defensive: document.activeElement is always set in happy-dom */
|
|
4762
5990
|
if (!activeElement) return false;
|
|
4763
5991
|
const role = activeElement.getAttribute("role");
|
|
4764
5992
|
if (role === "textbox" || role === "searchbox" || role === "combobox" || role === "spinbutton") return true;
|
|
@@ -4812,6 +6040,7 @@ function useHotkey(keys, callback, options = {}, _platform) {
|
|
|
4812
6040
|
const currentKeys = toValue(keys);
|
|
4813
6041
|
if (!currentKeys) return;
|
|
4814
6042
|
const groups = splitKeySequence(currentKeys.toLowerCase());
|
|
6043
|
+
/* v8 ignore next -- defensive: splitKeySequence rejects empty strings earlier */
|
|
4815
6044
|
if (groups.length === 0) return;
|
|
4816
6045
|
isSequence = groups.length > 1;
|
|
4817
6046
|
keyGroups = groups;
|
|
@@ -4864,6 +6093,7 @@ function isModifier(key) {
|
|
|
4864
6093
|
function parseKeyGroup(group) {
|
|
4865
6094
|
const { keys: parts } = splitKeyCombination(group.toLowerCase());
|
|
4866
6095
|
const modifiers = Object.fromEntries(MODIFIERS.map((m) => [m, false]));
|
|
6096
|
+
/* v8 ignore next 3 -- defensive: parseKeyGroup is not invoked with empty parts */
|
|
4867
6097
|
if (parts.length === 0) return {
|
|
4868
6098
|
modifiers,
|
|
4869
6099
|
actualKey: void 0
|
|
@@ -5089,11 +6319,13 @@ function useIntersectionObserver(target, callback, options = {}) {
|
|
|
5089
6319
|
observe: (obs, el) => obs.observe(el),
|
|
5090
6320
|
onEntry: (entries) => {
|
|
5091
6321
|
const latest = entries.at(-1);
|
|
6322
|
+
/* v8 ignore next -- defensive: IntersectionObserver always emits at least one entry */
|
|
5092
6323
|
if (latest) isIntersecting.value = latest.isIntersecting;
|
|
5093
6324
|
},
|
|
5094
6325
|
onPause: () => {
|
|
5095
6326
|
isIntersecting.value = false;
|
|
5096
6327
|
},
|
|
6328
|
+
/* v8 ignore next -- defensive nullish coalesce: entries always populated when shouldStop fires */
|
|
5097
6329
|
shouldStop: (entries) => entries.at(-1)?.isIntersecting ?? false,
|
|
5098
6330
|
immediate: options.immediate ? (el) => {
|
|
5099
6331
|
return [{
|
|
@@ -5143,6 +6375,7 @@ function useElementIntersection(target, options = {}) {
|
|
|
5143
6375
|
const intersectionRatio = shallowRef(0);
|
|
5144
6376
|
const { pause: _pause, resume, stop, isActive, isPaused } = useIntersectionObserver(target, (entries) => {
|
|
5145
6377
|
const entry = entries.at(-1);
|
|
6378
|
+
/* v8 ignore next 4 -- defensive: IntersectionObserver always emits at least one entry */
|
|
5146
6379
|
if (entry) {
|
|
5147
6380
|
isIntersecting.value = entry.isIntersecting;
|
|
5148
6381
|
intersectionRatio.value = entry.intersectionRatio;
|
|
@@ -5392,131 +6625,6 @@ function usePrefersContrast() {
|
|
|
5392
6625
|
return useMediaQuery("(prefers-contrast: more)");
|
|
5393
6626
|
}
|
|
5394
6627
|
//#endregion
|
|
5395
|
-
//#region src/composables/useMutationObserver/index.ts
|
|
5396
|
-
/**
|
|
5397
|
-
* @module useMutationObserver
|
|
5398
|
-
*
|
|
5399
|
-
* @see https://0.vuetifyjs.com/composables/system/use-mutation-observer
|
|
5400
|
-
*
|
|
5401
|
-
* @remarks
|
|
5402
|
-
* MutationObserver composable with lifecycle management.
|
|
5403
|
-
*
|
|
5404
|
-
* Key features:
|
|
5405
|
-
* - MutationObserver API wrapper
|
|
5406
|
-
* - `isActive` reactive flag
|
|
5407
|
-
* - `once` option for single-fire observation
|
|
5408
|
-
* - Pause/resume/stop functionality
|
|
5409
|
-
* - Automatic cleanup on unmount
|
|
5410
|
-
* - SSR-safe (checks SUPPORTS_MUTATION_OBSERVER)
|
|
5411
|
-
* - Hydration-aware
|
|
5412
|
-
* - Configurable observation options (childList, attributes, characterData, etc.)
|
|
5413
|
-
*
|
|
5414
|
-
* Perfect for detecting DOM changes and responding to mutations.
|
|
5415
|
-
*
|
|
5416
|
-
* @example
|
|
5417
|
-
* ```ts
|
|
5418
|
-
* import { useTemplateRef } from 'vue'
|
|
5419
|
-
* import { useMutationObserver } from '@vuetify/v0'
|
|
5420
|
-
*
|
|
5421
|
-
* const target = useTemplateRef('target')
|
|
5422
|
-
* useMutationObserver(target, records => {
|
|
5423
|
-
* console.log(records)
|
|
5424
|
-
* }, { childList: true })
|
|
5425
|
-
* ```
|
|
5426
|
-
*/
|
|
5427
|
-
/**
|
|
5428
|
-
* A composable that uses the Mutation Observer API to detect changes in the DOM.
|
|
5429
|
-
*
|
|
5430
|
-
* @param target The element to observe.
|
|
5431
|
-
* @param callback The callback to execute when a mutation is observed.
|
|
5432
|
-
* @param options The options for the Mutation Observer.
|
|
5433
|
-
* @returns An object with methods to control the observer.
|
|
5434
|
-
*
|
|
5435
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
|
|
5436
|
-
* @see https://0.vuetifyjs.com/composables/system/use-mutation-observer
|
|
5437
|
-
*
|
|
5438
|
-
* @example
|
|
5439
|
-
* ```ts
|
|
5440
|
-
* import { ref } from 'vue'
|
|
5441
|
-
* import { useMutationObserver } from '@vuetify/v0'
|
|
5442
|
-
*
|
|
5443
|
-
* const container = ref<HTMLElement>()
|
|
5444
|
-
*
|
|
5445
|
-
* const { pause, resume, isPaused } = useMutationObserver(
|
|
5446
|
-
* container,
|
|
5447
|
-
* (mutations) => {
|
|
5448
|
-
* mutations.forEach((mutation) => {
|
|
5449
|
-
* if (mutation.type === 'childList') {
|
|
5450
|
-
* console.log('Children changed:', mutation.addedNodes, mutation.removedNodes)
|
|
5451
|
-
* } else if (mutation.type === 'attributes') {
|
|
5452
|
-
* console.log('Attribute changed:', mutation.attributeName)
|
|
5453
|
-
* }
|
|
5454
|
-
* })
|
|
5455
|
-
* },
|
|
5456
|
-
* {
|
|
5457
|
-
* childList: true,
|
|
5458
|
-
* attributes: true,
|
|
5459
|
-
* subtree: true
|
|
5460
|
-
* }
|
|
5461
|
-
* )
|
|
5462
|
-
*
|
|
5463
|
-
* // Pause observation
|
|
5464
|
-
* pause()
|
|
5465
|
-
*
|
|
5466
|
-
* // Resume observation
|
|
5467
|
-
* resume()
|
|
5468
|
-
* ```
|
|
5469
|
-
*/
|
|
5470
|
-
function useMutationObserver(target, callback, options = {}) {
|
|
5471
|
-
const observerOptions = {
|
|
5472
|
-
childList: options.childList ?? true,
|
|
5473
|
-
attributes: options.attributes ?? false,
|
|
5474
|
-
characterData: options.characterData ?? false,
|
|
5475
|
-
subtree: options.subtree ?? false,
|
|
5476
|
-
attributeOldValue: options.attributeOldValue ?? false,
|
|
5477
|
-
characterDataOldValue: options.characterDataOldValue ?? false,
|
|
5478
|
-
attributeFilter: options.attributeFilter
|
|
5479
|
-
};
|
|
5480
|
-
return createObserver(target, callback, {
|
|
5481
|
-
supports: SUPPORTS_MUTATION_OBSERVER,
|
|
5482
|
-
once: options.once,
|
|
5483
|
-
create: (cb) => new MutationObserver((mutations) => {
|
|
5484
|
-
cb(mutations.map((m) => ({
|
|
5485
|
-
type: m.type,
|
|
5486
|
-
target: m.target,
|
|
5487
|
-
addedNodes: m.addedNodes,
|
|
5488
|
-
removedNodes: m.removedNodes,
|
|
5489
|
-
previousSibling: m.previousSibling,
|
|
5490
|
-
nextSibling: m.nextSibling,
|
|
5491
|
-
attributeName: m.attributeName,
|
|
5492
|
-
attributeNamespace: m.attributeNamespace,
|
|
5493
|
-
oldValue: m.oldValue
|
|
5494
|
-
})));
|
|
5495
|
-
}),
|
|
5496
|
-
observe: (obs, el) => obs.observe(el, observerOptions),
|
|
5497
|
-
immediate: options.immediate ? (el) => {
|
|
5498
|
-
const emptyNodeList = {
|
|
5499
|
-
length: 0,
|
|
5500
|
-
item: () => null,
|
|
5501
|
-
forEach: () => {},
|
|
5502
|
-
*[Symbol.iterator]() {}
|
|
5503
|
-
};
|
|
5504
|
-
return [{
|
|
5505
|
-
type: "childList",
|
|
5506
|
-
target: el,
|
|
5507
|
-
addedNodes: emptyNodeList,
|
|
5508
|
-
removedNodes: emptyNodeList,
|
|
5509
|
-
previousSibling: null,
|
|
5510
|
-
nextSibling: null,
|
|
5511
|
-
attributeName: null,
|
|
5512
|
-
attributeNamespace: null,
|
|
5513
|
-
oldValue: null
|
|
5514
|
-
}];
|
|
5515
|
-
} : void 0,
|
|
5516
|
-
onceIncludesImmediate: true
|
|
5517
|
-
});
|
|
5518
|
-
}
|
|
5519
|
-
//#endregion
|
|
5520
6628
|
//#region src/composables/usePresence/index.ts
|
|
5521
6629
|
/**
|
|
5522
6630
|
* @module usePresence
|
|
@@ -5900,8 +7008,11 @@ function useRovingFocus(items, options = {}) {
|
|
|
5900
7008
|
};
|
|
5901
7009
|
}
|
|
5902
7010
|
//#endregion
|
|
7011
|
+
//#region src/composables/useRtl/adapters/adapter.ts
|
|
7012
|
+
var RtlAdapter = class {};
|
|
7013
|
+
//#endregion
|
|
5903
7014
|
//#region src/composables/useRtl/adapters/v0.ts
|
|
5904
|
-
var
|
|
7015
|
+
var V0RtlAdapter = class extends RtlAdapter {
|
|
5905
7016
|
setup(app, context, target) {
|
|
5906
7017
|
if (IN_BROWSER) {
|
|
5907
7018
|
if (/* @__PURE__ */ isNull(target)) return;
|
|
@@ -5969,7 +7080,7 @@ function createRtlFallback() {
|
|
|
5969
7080
|
}
|
|
5970
7081
|
const [createRtlContext, createRtlPlugin, useRtl] = createPluginContext("v0:rtl", (options) => createRtl(options), {
|
|
5971
7082
|
fallback: () => createRtlFallback(),
|
|
5972
|
-
setup: (context, app, { adapter = new
|
|
7083
|
+
setup: (context, app, { adapter = new V0RtlAdapter(), target }) => {
|
|
5973
7084
|
adapter.setup(app, context, target);
|
|
5974
7085
|
},
|
|
5975
7086
|
persist: (ctx) => ctx.isRtl.value,
|
|
@@ -6261,7 +7372,7 @@ function useStack(namespace = "v0:stack") {
|
|
|
6261
7372
|
* ```
|
|
6262
7373
|
*/
|
|
6263
7374
|
function createStorage(options = {}) {
|
|
6264
|
-
const { adapter = IN_BROWSER ? window.localStorage : new
|
|
7375
|
+
const { adapter = IN_BROWSER ? window.localStorage : new MemoryStorageAdapter(), prefix = "v0:", serializer = {
|
|
6265
7376
|
read: JSON.parse,
|
|
6266
7377
|
write: JSON.stringify
|
|
6267
7378
|
}, ttl } = options;
|
|
@@ -6276,9 +7387,9 @@ function createStorage(options = {}) {
|
|
|
6276
7387
|
if (/* @__PURE__ */ isNullOrUndefined(raw)) return void 0;
|
|
6277
7388
|
try {
|
|
6278
7389
|
const parsed = serializer.read(raw);
|
|
6279
|
-
if (
|
|
7390
|
+
if (/* @__PURE__ */ isObject(parsed) && "__v0" in parsed && "__v" in parsed) {
|
|
6280
7391
|
const envelope = parsed;
|
|
6281
|
-
if (Date.now() - envelope.__t > ttl) {
|
|
7392
|
+
if (ttl && Date.now() - envelope.__t > ttl) {
|
|
6282
7393
|
adapter?.removeItem(prefixedKey);
|
|
6283
7394
|
return;
|
|
6284
7395
|
}
|
|
@@ -6358,7 +7469,7 @@ function createStorage(options = {}) {
|
|
|
6358
7469
|
};
|
|
6359
7470
|
}
|
|
6360
7471
|
function createStorageFallback() {
|
|
6361
|
-
return createStorage({ adapter: new
|
|
7472
|
+
return createStorage({ adapter: new MemoryStorageAdapter() });
|
|
6362
7473
|
}
|
|
6363
7474
|
const [createStorageContext, createStoragePlugin, useStorage] = createPluginContext("v0:storage", (options) => createStorage(options), { fallback: () => createStorageFallback() });
|
|
6364
7475
|
//#endregion
|
|
@@ -6675,6 +7786,7 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
6675
7786
|
x: 0,
|
|
6676
7787
|
y: 0
|
|
6677
7788
|
};
|
|
7789
|
+
let startedOutsideBounds = false;
|
|
6678
7790
|
let cleanupPointerDown;
|
|
6679
7791
|
let cleanupPointerUp;
|
|
6680
7792
|
let cleanupBlur;
|
|
@@ -6704,6 +7816,7 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
6704
7816
|
* Check if an element matches resolved ignore targets.
|
|
6705
7817
|
*/
|
|
6706
7818
|
function isIgnored(el, selectors, elements) {
|
|
7819
|
+
/* v8 ignore next -- defensive guard, callers always pass an Element */
|
|
6707
7820
|
if (!el) return false;
|
|
6708
7821
|
for (const selector of selectors) try {
|
|
6709
7822
|
if (el.matches(selector) || !/* @__PURE__ */ isNull(el.closest(selector))) return true;
|
|
@@ -6730,6 +7843,7 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
6730
7843
|
const targets = getTargets();
|
|
6731
7844
|
if (targets.length === 0) return false;
|
|
6732
7845
|
return targets.every((el) => {
|
|
7846
|
+
/* v8 ignore next -- defensive: getTargets filters to Element-typed values */
|
|
6733
7847
|
if (/* @__PURE__ */ isNullOrUndefined(el) || !/* @__PURE__ */ isFunction(el.contains)) return false;
|
|
6734
7848
|
return el !== eventTarget && !el.contains(eventTarget);
|
|
6735
7849
|
});
|
|
@@ -6739,6 +7853,7 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
6739
7853
|
*/
|
|
6740
7854
|
function isOutsideBounds(x, y) {
|
|
6741
7855
|
const targets = getTargets();
|
|
7856
|
+
/* v8 ignore next -- edge case: bounds check only invoked when targets exist */
|
|
6742
7857
|
if (targets.length === 0) return false;
|
|
6743
7858
|
return targets.every((el) => {
|
|
6744
7859
|
const { left, right, top, bottom } = el.getBoundingClientRect();
|
|
@@ -6749,6 +7864,7 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
6749
7864
|
* Validate that the target is still in the DOM.
|
|
6750
7865
|
*/
|
|
6751
7866
|
function isValidTarget(eventTarget) {
|
|
7867
|
+
/* v8 ignore next -- type guard for non-Element targets (e.g., document, window) */
|
|
6752
7868
|
if (!/* @__PURE__ */ isElement(eventTarget)) return false;
|
|
6753
7869
|
if (!eventTarget.isConnected) return false;
|
|
6754
7870
|
return true;
|
|
@@ -6765,6 +7881,7 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
6765
7881
|
x: event.clientX,
|
|
6766
7882
|
y: event.clientY
|
|
6767
7883
|
};
|
|
7884
|
+
startedOutsideBounds = bounds ? isOutsideBounds(event.clientX, event.clientY) : false;
|
|
6768
7885
|
}
|
|
6769
7886
|
/**
|
|
6770
7887
|
* Handle pointerup - check if it's an outside click.
|
|
@@ -6783,7 +7900,7 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
6783
7900
|
const dy = Math.abs(event.clientY - startPosition.y);
|
|
6784
7901
|
if (dx >= touchScrollThreshold || dy >= touchScrollThreshold) return;
|
|
6785
7902
|
}
|
|
6786
|
-
if ((bounds ?
|
|
7903
|
+
if ((bounds ? startedOutsideBounds && isOutsideBounds(event.clientX, event.clientY) : isOutside(pointerdownTarget) && isOutside(pointerupTarget)) && !shouldIgnore(path)) handler(event);
|
|
6787
7904
|
}
|
|
6788
7905
|
/**
|
|
6789
7906
|
* Handle window blur - detect focus moving to iframe.
|
|
@@ -6840,4 +7957,4 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
6840
7957
|
};
|
|
6841
7958
|
}
|
|
6842
7959
|
//#endregion
|
|
6843
|
-
export {
|
|
7960
|
+
export { useTimeline as $, useIntersectionObserver as A, createForm as At, createDateContext as B, usePopover as Bt, usePresence as C, createNested as Ct, usePrefersReducedMotion as D, createSortable as Dt, usePrefersDark as E, createKanban as Et, PointerAdapter as F, useCombobox as Ft, createBreakpointsPlugin as G, useDate as H, createBreadcrumbsContext as Ht, DragDropAdapter as I, ServerComboboxAdapter as It, createVirtual as J, useBreakpoints as K, useMutationObserver as L, ClientComboboxAdapter as Lt, useHotkey as M, useForm as Mt, useDragDrop as N, createCombobox as Nt, useLazy as O, createInput as Ot, KeyboardAdapter as P, createComboboxContext as Pt, createTimelineContext as Q, useDelay as R, ComboboxAdapter as Rt, useProxyModel as S, createNumeric as St, usePrefersContrast as T, useNested as Tt, createBreakpoints as U, useBreadcrumbs as Ut, createDatePlugin as V, createBreadcrumbs as Vt, createBreakpointsContext as W, useVirtual as X, createVirtualContext as Y, createTimeline as Z, createRtlPlugin as _, createHydration as _t, useToggleScope as a, createRatingContext as at, useRovingFocus as b, useHydration as bt, createStoragePlugin as c, createProgressContext as ct, createStackContext as d, createOverflowContext as dt, createStep as et, createStackPlugin as f, useOverflow as ft, createRtlFallback as g, createFallbackHydration as gt, createRtlContext as h, toElement as ht, useWindowEventListener as i, createRating as it, useImage as j, createFormContext as jt, useElementIntersection as k, createValidation as kt, useStorage as l, useProgress as lt, createRtl as m, useResizeObserver as mt, useDocumentEventListener as n, useStep as nt, createStorage as o, useRating as ot, useStack as p, useElementSize as pt, toReactive as q, useEventListener as r, createSlider as rt, createStorageContext as s, createProgress as st, useClickOutside as t, createStepContext as tt, createStack as u, createOverflow as ut, useRtl as v, createHydrationContext as vt, useMediaQuery as w, createNestedContext as wt, useRaf as x, createNumberField as xt, V0RtlAdapter as y, createHydrationPlugin as yt, createDate as z, useVirtualFocus as zt };
|