@vuetify/v0 1.0.0-alpha.3 → 1.0.0-alpha.5
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 +5 -0
- package/dist/adapter-B6IrPwib.d.mts +98 -0
- package/dist/adapter-BEJXp-ie.d.mts +11 -0
- package/dist/adapter-BFSJsyv7.mjs +481 -0
- package/dist/{adapter-DlX3FA3A.d.mts → adapter-BO75n0Cn.d.mts} +10 -14
- package/dist/adapter-BSKx9WQ7.mjs +4 -0
- package/dist/adapter-Chznb9Ju.mjs +4 -0
- package/dist/{index-CT5SCLzW.d.mts → adapter-CspReV3g.d.mts} +6 -9
- package/dist/adapter-D8zizQVP.mjs +4 -0
- package/dist/adapter-DDJHLC8K.d.mts +17 -0
- package/dist/adapters-4t-NhR11.mjs +5 -0
- package/dist/adapters-BcoA0zCS.mjs +4 -0
- package/dist/adapters-BjaPK635.mjs +2 -0
- package/dist/adapters-D64TORDu.mjs +2 -0
- package/dist/adapters-DvG-9z9q.mjs +3 -0
- package/dist/browser/index.js +2074 -561
- package/dist/components/index.d.mts +2 -2
- package/dist/components/index.mjs +1 -1
- package/dist/{components-C4jI-78d.mjs → components-Dn4Kbi0i.mjs} +149 -101
- package/dist/composables/index.d.mts +20 -19
- package/dist/composables/index.mjs +31 -29
- package/dist/{consola-BdgyPEfx.d.mts → consola-CUNHyu8J.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-iODP6aKB.mjs → createDataTable-H-PuVigU.mjs} +216 -124
- package/dist/{createGroup-CGk6hY_Y.mjs → createGroup-aHt_kvtU.mjs} +3 -3
- package/dist/{createRegistry-BXzdXAjq.mjs → createRegistry-CWpvSbCe.mjs} +78 -41
- package/dist/{createSelection-B3HJEPNg.mjs → createSelection-MRyUZyW2.mjs} +3 -3
- package/dist/{createSingle-Dql8mRi-.mjs → createSingle-BSciC9EJ.mjs} +1 -1
- package/dist/{createTokens-DgFYsOrv.mjs → createTokens-CQ9C7GTV.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 +12 -5
- 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/{index-BzFHTW59.d.mts → flagsmith-Cd44vxff.d.mts} +4 -4
- package/dist/{flagsmith-Dbh1h8WF.mjs → flagsmith-Cu93hUIF.mjs} +6 -4
- package/dist/{globals-zEjWBKCr.mjs → globals-BRdxsC2M.mjs} +1 -1
- package/dist/{index-GOpjKzaJ.d.mts → index-BLaKZq0Y.d.mts} +25 -2
- package/dist/{index-BJGcVy7e.d.mts → index-BmEu85PI.d.mts} +126 -65
- package/dist/{index-DE3bWw11.d.mts → index-C0ewabdY.d.mts} +93 -215
- package/dist/index-C6NnIuDv.d.mts +4 -0
- package/dist/{index-DNDuacmH.d.mts → index-CJdG9yY1.d.mts} +116 -106
- package/dist/index-C_t6t0Z-.d.mts +170 -0
- package/dist/{index-B76iGRE3.d.mts → index-CyUCELZC.d.mts} +1149 -61
- package/dist/index.d.mts +24 -23
- package/dist/index.mjs +35 -33
- package/dist/json/attributes.json +1 -1
- package/dist/json/web-types.json +2 -2
- package/dist/{launchdarkly-BKtW-idu.mjs → launchdarkly-CLGtJCsI.mjs} +6 -4
- package/dist/launchdarkly-De701hkf.d.mts +13 -0
- 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-oYBvtkgx.mjs → memory-BMpJcQjQ.mjs} +13 -3
- package/dist/{memory-CeSQE-QV.d.mts → memory-D-JbdKXg.d.mts} +9 -9
- 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 +3 -0
- 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-DNfCEb0p.d.mts → pino-BaYY_KIN.d.mts} +2 -2
- package/dist/{pino-9L79n6y6.mjs → pino-CIcYlW3u.mjs} +3 -1
- package/dist/{posthog-DmuyycaR.mjs → posthog-0umvvA48.mjs} +7 -5
- package/dist/posthog-CIrmvke4.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-7vjHxjNc.d.mts} +5 -5
- package/dist/{server-y7zLSCSx.mjs → server-BNSiVoMe.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-B-I2OS6i.mjs → unhead-_cXZcx0j.mjs} +2 -2
- package/dist/{useClickOutside-CY4U2J9W.mjs → useClickOutside-DbOLg1uw.mjs} +1483 -182
- package/dist/{useFeatures-BPOke6iP.mjs → useFeatures-Dhnr-Lg2.mjs} +7 -10
- package/dist/{useLocale-BV8e3imF.mjs → useLocale-Sh-2sNiG.mjs} +6 -6
- package/dist/{useLogger-DvdRTrqC.mjs → useLogger-1_ZeBY12.mjs} +5 -5
- package/dist/{useNotifications-vSJE6z6t.mjs → useNotifications-CAVQ7hK6.mjs} +6 -6
- package/dist/{usePermissions-D3zPwKQc.mjs → usePermissions-D9Oituwy.mjs} +6 -6
- package/dist/{useRules-BT6cgoTj.mjs → useRules-DK4AeNeC.mjs} +4 -3
- package/dist/{useTheme-cUZb2A9O.mjs → useTheme-FMDQC81h.mjs} +5 -5
- package/dist/utilities/index.d.mts +2 -2
- package/dist/utilities/index.mjs +26 -2
- package/dist/{v0-CHZpnMeP.mjs → v0-C42ssNIy.mjs} +6 -4
- package/dist/{v0-Dq3zhexO.mjs → v0-CEfbyyp2.mjs} +3 -4
- package/dist/{v0-C49OI_wc.mjs → v0-Ch-O6YVd.mjs} +5 -3
- package/dist/{v0-gpExNexS.mjs → v0-D0imQlSD.mjs} +2 -2
- package/dist/{v0-DrOub-e1.d.mts → v0-DWZ_N2GG.d.mts} +4 -4
- package/dist/{v0-Bmow1q_x.mjs → v0-Dvu8fMl3.mjs} +3 -3
- package/dist/v0-QIjffi4E.d.mts +8 -0
- package/dist/{v0-D7Fm2C3Y.d.mts → v0-aYLq6qmT.d.mts} +3 -3
- package/dist/{virtual-C0yHf1DC.mjs → virtual-Cq5aRp7m.mjs} +3 -4
- package/dist/virtual-CrgGA-o6.d.mts +8 -0
- package/package.json +1 -1
- 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/adapter-gQ2SNKZq.mjs +0 -238
- package/dist/adapters-BSiqsTZN.mjs +0 -3
- package/dist/adapters-C3QXhf4I.mjs +0 -2
- package/dist/adapters-CMJGA1k7.mjs +0 -2
- package/dist/adapters-Dse4bPxk.mjs +0 -5
- package/dist/adapters-_ZqxCD8f.mjs +0 -4
- 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-BOn0AAue.d.mts} +0 -0
- /package/dist/{index-CROz1VSV.d.mts → index-CKKoxA9V.d.mts} +0 -0
- /package/dist/{index-DuddF-NR.d.mts → index-CLR1QMM3.d.mts} +0 -0
- /package/dist/{index-DTvqw22G.d.mts → index-H_hl6-4b.d.mts} +0 -0
- /package/dist/{index-BgCkepP_.d.mts → index-PvkxPev3.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-BRdxsC2M.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-1_ZeBY12.mjs";
|
|
5
|
+
import { t as createRegistry } from "./createRegistry-CWpvSbCe.mjs";
|
|
6
|
+
import { i as createModel, t as createSelection } from "./createSelection-MRyUZyW2.mjs";
|
|
7
|
+
import { t as createSingle } from "./createSingle-BSciC9EJ.mjs";
|
|
8
|
+
import "./createTokens-CQ9C7GTV.mjs";
|
|
9
|
+
import { a as useLocale } from "./useLocale-Sh-2sNiG.mjs";
|
|
10
|
+
import { c as useTimer } from "./useNotifications-CAVQ7hK6.mjs";
|
|
11
|
+
import { t as toArray } from "./toArray-CD2-OxAz.mjs";
|
|
12
|
+
import { a as createFilter } from "./adapter-BFSJsyv7.mjs";
|
|
13
|
+
import { t as createGroup } from "./createGroup-aHt_kvtU.mjs";
|
|
14
|
+
import "./createDataTable-H-PuVigU.mjs";
|
|
15
|
+
import { a as useRules, o as isStandardSchema } from "./useRules-DK4AeNeC.mjs";
|
|
16
|
+
import "./useFeatures-Dhnr-Lg2.mjs";
|
|
17
|
+
import "./usePermissions-D9Oituwy.mjs";
|
|
18
|
+
import { t as MemoryStorageAdapter } from "./memory-BMpJcQjQ.mjs";
|
|
19
|
+
import "./useTheme-FMDQC81h.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
|
});
|
|
@@ -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
|
|
@@ -2079,6 +2405,193 @@ function createNumberField(options = {}) {
|
|
|
2079
2405
|
};
|
|
2080
2406
|
}
|
|
2081
2407
|
//#endregion
|
|
2408
|
+
//#region src/composables/createOtp/index.ts
|
|
2409
|
+
/**
|
|
2410
|
+
* @module createOtp
|
|
2411
|
+
*
|
|
2412
|
+
* @see https://0.vuetifyjs.com/composables/forms/create-otp
|
|
2413
|
+
*
|
|
2414
|
+
* @remarks
|
|
2415
|
+
* Headless state for a fixed-length one-time-password / verification-code value.
|
|
2416
|
+
* Owns the joined string, per-character pattern matching, length contract,
|
|
2417
|
+
* completion edge detection with a decisional async `onComplete` hook, and
|
|
2418
|
+
* validation through `createInput`. Rendering, focus, and per-element event
|
|
2419
|
+
* wiring are the consumer's responsibility.
|
|
2420
|
+
*
|
|
2421
|
+
* @example
|
|
2422
|
+
* ```ts
|
|
2423
|
+
* import { createOtp } from '@vuetify/v0'
|
|
2424
|
+
*
|
|
2425
|
+
* const otp = createOtp({
|
|
2426
|
+
* length: 6,
|
|
2427
|
+
* pattern: 'numeric',
|
|
2428
|
+
* onComplete: async value => {
|
|
2429
|
+
* const ok = await verify(value)
|
|
2430
|
+
* return ok
|
|
2431
|
+
* },
|
|
2432
|
+
* })
|
|
2433
|
+
*
|
|
2434
|
+
* otp.write(0, '4')
|
|
2435
|
+
* otp.distribute('12345', 1) // returns 5; value becomes '412345'
|
|
2436
|
+
* otp.isComplete.value // true
|
|
2437
|
+
* ```
|
|
2438
|
+
*/
|
|
2439
|
+
const PRESETS = {
|
|
2440
|
+
numeric: /^[0-9]$/,
|
|
2441
|
+
alphanumeric: /^[a-zA-Z0-9]$/,
|
|
2442
|
+
alphabetic: /^[a-zA-Z]$/
|
|
2443
|
+
};
|
|
2444
|
+
const WARNED_PATTERNS = /* @__PURE__ */ new WeakSet();
|
|
2445
|
+
function createOtp(options = {}) {
|
|
2446
|
+
const { value = shallowRef(""), length = 6, pattern = "numeric", disabled = false, readonly: _readonly = false, onComplete, ...inputOptions } = options;
|
|
2447
|
+
const logger = useLogger();
|
|
2448
|
+
const errorRef = shallowRef(false);
|
|
2449
|
+
const errorMessagesRef = shallowRef(void 0);
|
|
2450
|
+
const input = createInput({
|
|
2451
|
+
...inputOptions,
|
|
2452
|
+
value,
|
|
2453
|
+
disabled,
|
|
2454
|
+
readonly: _readonly,
|
|
2455
|
+
error: errorRef,
|
|
2456
|
+
errorMessages: errorMessagesRef
|
|
2457
|
+
});
|
|
2458
|
+
const lengthRef = toRef(() => toValue(length));
|
|
2459
|
+
let lastCompleted = "";
|
|
2460
|
+
function compile(resolved) {
|
|
2461
|
+
if (/* @__PURE__ */ isString(resolved)) return PRESETS[resolved];
|
|
2462
|
+
if (process.env.NODE_ENV !== "production" && !WARNED_PATTERNS.has(resolved)) {
|
|
2463
|
+
WARNED_PATTERNS.add(resolved);
|
|
2464
|
+
if (resolved.test("aa") || resolved.test("00")) logger.warn("createOtp: pattern matches multi-character input; per-character matching may behave unexpectedly");
|
|
2465
|
+
}
|
|
2466
|
+
return resolved;
|
|
2467
|
+
}
|
|
2468
|
+
function accepts(char) {
|
|
2469
|
+
if (char.length !== 1) return false;
|
|
2470
|
+
return compile(toValue(pattern)).test(char);
|
|
2471
|
+
}
|
|
2472
|
+
function filterAccepted(text) {
|
|
2473
|
+
let out = "";
|
|
2474
|
+
for (const ch of text) if (accepts(ch)) out += ch;
|
|
2475
|
+
return out;
|
|
2476
|
+
}
|
|
2477
|
+
const isPending = shallowRef(false);
|
|
2478
|
+
function isLocked() {
|
|
2479
|
+
return toValue(disabled) || toValue(_readonly) || isPending.value;
|
|
2480
|
+
}
|
|
2481
|
+
function clearRejection() {
|
|
2482
|
+
if (errorRef.value || errorMessagesRef.value) {
|
|
2483
|
+
errorRef.value = false;
|
|
2484
|
+
errorMessagesRef.value = void 0;
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
function write(index, char) {
|
|
2488
|
+
if (isLocked()) return;
|
|
2489
|
+
const max = toValue(lengthRef);
|
|
2490
|
+
if (index < 0 || index >= max) return;
|
|
2491
|
+
if (char === "") {
|
|
2492
|
+
clearRejection();
|
|
2493
|
+
value.value = value.value.slice(0, index);
|
|
2494
|
+
return;
|
|
2495
|
+
}
|
|
2496
|
+
const first = char[0];
|
|
2497
|
+
if (!accepts(first)) return;
|
|
2498
|
+
clearRejection();
|
|
2499
|
+
const current = value.value;
|
|
2500
|
+
const head = current.slice(0, index);
|
|
2501
|
+
const tail = current.slice(index + 1);
|
|
2502
|
+
value.value = (head + first + tail).slice(0, max);
|
|
2503
|
+
}
|
|
2504
|
+
function distribute(text, index = 0) {
|
|
2505
|
+
if (isLocked()) return 0;
|
|
2506
|
+
const max = toValue(lengthRef);
|
|
2507
|
+
const start = /* @__PURE__ */ clamp(index, 0, max);
|
|
2508
|
+
const filtered = filterAccepted(text);
|
|
2509
|
+
if (filtered.length === 0) return 0;
|
|
2510
|
+
clearRejection();
|
|
2511
|
+
const head = value.value.slice(0, start);
|
|
2512
|
+
const next = (head + filtered).slice(0, max);
|
|
2513
|
+
value.value = next;
|
|
2514
|
+
return next.length - head.length;
|
|
2515
|
+
}
|
|
2516
|
+
function clear() {
|
|
2517
|
+
if (isLocked()) return;
|
|
2518
|
+
clearRejection();
|
|
2519
|
+
lastCompleted = "";
|
|
2520
|
+
value.value = "";
|
|
2521
|
+
}
|
|
2522
|
+
function fill(text) {
|
|
2523
|
+
if (isLocked()) return;
|
|
2524
|
+
const max = toValue(lengthRef);
|
|
2525
|
+
const filtered = filterAccepted(text).slice(0, max);
|
|
2526
|
+
if (text.length === 0 || filtered.length > 0) clearRejection();
|
|
2527
|
+
value.value = filtered;
|
|
2528
|
+
}
|
|
2529
|
+
function reject() {
|
|
2530
|
+
errorRef.value = true;
|
|
2531
|
+
errorMessagesRef.value = ["Invalid code"];
|
|
2532
|
+
lastCompleted = "";
|
|
2533
|
+
value.value = "";
|
|
2534
|
+
}
|
|
2535
|
+
const isComplete = toRef(() => {
|
|
2536
|
+
const max = toValue(lengthRef);
|
|
2537
|
+
const v = value.value;
|
|
2538
|
+
if (v.length !== max) return false;
|
|
2539
|
+
const re = compile(toValue(pattern));
|
|
2540
|
+
for (const ch of v) if (!re.test(ch)) return false;
|
|
2541
|
+
return true;
|
|
2542
|
+
});
|
|
2543
|
+
watch(value, (next) => {
|
|
2544
|
+
if (!isComplete.value) {
|
|
2545
|
+
lastCompleted = "";
|
|
2546
|
+
return;
|
|
2547
|
+
}
|
|
2548
|
+
if (!onComplete) return;
|
|
2549
|
+
if (isLocked()) return;
|
|
2550
|
+
if (next === lastCompleted) return;
|
|
2551
|
+
lastCompleted = next;
|
|
2552
|
+
let result;
|
|
2553
|
+
try {
|
|
2554
|
+
result = onComplete(next);
|
|
2555
|
+
} catch (error) {
|
|
2556
|
+
logger.warn("createOtp: onComplete threw", error);
|
|
2557
|
+
reject();
|
|
2558
|
+
return;
|
|
2559
|
+
}
|
|
2560
|
+
if (/* @__PURE__ */ isThenable(result)) {
|
|
2561
|
+
isPending.value = true;
|
|
2562
|
+
result.then((ok) => {
|
|
2563
|
+
isPending.value = false;
|
|
2564
|
+
if (ok === false) reject();
|
|
2565
|
+
}, (error) => {
|
|
2566
|
+
isPending.value = false;
|
|
2567
|
+
logger.warn("createOtp: onComplete rejected", error);
|
|
2568
|
+
reject();
|
|
2569
|
+
});
|
|
2570
|
+
return;
|
|
2571
|
+
}
|
|
2572
|
+
if (result === false) reject();
|
|
2573
|
+
});
|
|
2574
|
+
return {
|
|
2575
|
+
value,
|
|
2576
|
+
length: lengthRef,
|
|
2577
|
+
input: {
|
|
2578
|
+
...input,
|
|
2579
|
+
reset() {
|
|
2580
|
+
clearRejection();
|
|
2581
|
+
lastCompleted = "";
|
|
2582
|
+
input.reset();
|
|
2583
|
+
}
|
|
2584
|
+
},
|
|
2585
|
+
isComplete,
|
|
2586
|
+
isValidating: isPending,
|
|
2587
|
+
write,
|
|
2588
|
+
distribute,
|
|
2589
|
+
clear,
|
|
2590
|
+
fill,
|
|
2591
|
+
accepts
|
|
2592
|
+
};
|
|
2593
|
+
}
|
|
2594
|
+
//#endregion
|
|
2082
2595
|
//#region src/composables/useHydration/index.ts
|
|
2083
2596
|
/**
|
|
2084
2597
|
* @module useHydration
|
|
@@ -2468,6 +2981,7 @@ function useElementSize(target) {
|
|
|
2468
2981
|
const height = shallowRef(0);
|
|
2469
2982
|
const { pause: _pause, resume, stop, isActive, isPaused } = useResizeObserver(target, (entries) => {
|
|
2470
2983
|
const entry = entries[0];
|
|
2984
|
+
/* v8 ignore next 4 -- defensive: ResizeObserver always passes an entry array with at least one entry */
|
|
2471
2985
|
if (entry) {
|
|
2472
2986
|
width.value = entry.contentRect.width;
|
|
2473
2987
|
height.value = entry.contentRect.height;
|
|
@@ -2481,7 +2995,7 @@ function useElementSize(target) {
|
|
|
2481
2995
|
return {
|
|
2482
2996
|
width: shallowReadonly(width),
|
|
2483
2997
|
height: shallowReadonly(height),
|
|
2484
|
-
isActive,
|
|
2998
|
+
isActive: shallowReadonly(isActive),
|
|
2485
2999
|
isPaused: shallowReadonly(isPaused),
|
|
2486
3000
|
pause,
|
|
2487
3001
|
resume,
|
|
@@ -2626,6 +3140,7 @@ function createOverflow(options = {}) {
|
|
|
2626
3140
|
}),
|
|
2627
3141
|
total,
|
|
2628
3142
|
isOverflowing: toRef(() => {
|
|
3143
|
+
if (width.value === 0) return false;
|
|
2629
3144
|
return total.value > width.value - toValue(reserved);
|
|
2630
3145
|
}),
|
|
2631
3146
|
measure,
|
|
@@ -2778,7 +3293,7 @@ function createProgress(options = {}) {
|
|
|
2778
3293
|
}
|
|
2779
3294
|
for (const [index, element] of clamped.entries()) {
|
|
2780
3295
|
const ticket = segments.value[index];
|
|
2781
|
-
if (!ticket || !isRef(ticket.value)) continue;
|
|
3296
|
+
if (!ticket || !isRef(ticket.value) || isReadonly(ticket.value)) continue;
|
|
2782
3297
|
ticket.value.value = element;
|
|
2783
3298
|
}
|
|
2784
3299
|
}
|
|
@@ -3636,6 +4151,7 @@ function createVirtual(items, _options = {}) {
|
|
|
3636
4151
|
/* v8 ignore stop */
|
|
3637
4152
|
});
|
|
3638
4153
|
useResizeObserver(element, (entries) => {
|
|
4154
|
+
/* v8 ignore next -- defensive: ResizeObserver always emits at least one entry */
|
|
3639
4155
|
if (!entries[0]) return;
|
|
3640
4156
|
viewportHeight.value = entries[0].contentRect.height;
|
|
3641
4157
|
update();
|
|
@@ -3648,6 +4164,7 @@ function createVirtual(items, _options = {}) {
|
|
|
3648
4164
|
rebuild();
|
|
3649
4165
|
}, { immediate: true });
|
|
3650
4166
|
watch(element, () => {
|
|
4167
|
+
/* v8 ignore next -- defensive: watch fires only when element is present */
|
|
3651
4168
|
if (!element.value) return;
|
|
3652
4169
|
if (direction === "reverse" && items.value.length > 0) {
|
|
3653
4170
|
const lastIndex = items.value.length - 1;
|
|
@@ -3666,6 +4183,7 @@ function createVirtual(items, _options = {}) {
|
|
|
3666
4183
|
anchorOffset = 0;
|
|
3667
4184
|
} else if (/* @__PURE__ */ isFunction(anchor)) {
|
|
3668
4185
|
const result = anchor(items.value);
|
|
4186
|
+
/* v8 ignore next 4 -- function-anchor: tested with valid number return; non-number rejection branch is implicit */
|
|
3669
4187
|
if (/* @__PURE__ */ isNumber(result)) {
|
|
3670
4188
|
anchorIndex = result;
|
|
3671
4189
|
anchorOffset = element.value.scrollTop - (offsets.value[result] || 0);
|
|
@@ -3749,8 +4267,10 @@ function createVirtual(items, _options = {}) {
|
|
|
3749
4267
|
/* v8 ignore stop */
|
|
3750
4268
|
}
|
|
3751
4269
|
function resize(index, height) {
|
|
4270
|
+
/* v8 ignore next -- early bail when height is already correct */
|
|
3752
4271
|
if (heights.value[index] === height) return;
|
|
3753
4272
|
heights.value[index] = height;
|
|
4273
|
+
/* v8 ignore next -- first-call only: itemHeight bootstrapped from initial measurement */
|
|
3754
4274
|
if (!itemHeight.value) itemHeight.value = height;
|
|
3755
4275
|
if (IN_BROWSER) {
|
|
3756
4276
|
cancelAnimationFrame(rebuildRaf);
|
|
@@ -3767,6 +4287,7 @@ function createVirtual(items, _options = {}) {
|
|
|
3767
4287
|
/* v8 ignore stop */
|
|
3768
4288
|
}
|
|
3769
4289
|
function scrollTo(index, scrollOptions) {
|
|
4290
|
+
/* v8 ignore next -- defensive: scrollTo only invoked after element mounts */
|
|
3770
4291
|
if (!element.value) return;
|
|
3771
4292
|
const targetOffset = offsets.value[index] || 0;
|
|
3772
4293
|
const behavior = scrollOptions?.behavior ?? "auto";
|
|
@@ -3892,6 +4413,124 @@ function useVirtual(namespace = "v0:virtual") {
|
|
|
3892
4413
|
return useContext(namespace);
|
|
3893
4414
|
}
|
|
3894
4415
|
//#endregion
|
|
4416
|
+
//#region src/composables/toHighlight/index.ts
|
|
4417
|
+
/**
|
|
4418
|
+
* @module toHighlight
|
|
4419
|
+
*
|
|
4420
|
+
* @see https://0.vuetifyjs.com/composables/transformers/to-highlight
|
|
4421
|
+
*
|
|
4422
|
+
* @remarks
|
|
4423
|
+
* Pure transformer — no DOM, no state, no registry, no reactivity. Splits text
|
|
4424
|
+
* into matched and unmatched chunks given a query string, an array of query
|
|
4425
|
+
* strings, or pre-computed `[start, end]` match ranges (e.g., from createFilter).
|
|
4426
|
+
* Returns a plain array; wrap the call in `computed()` for reactive recomputation.
|
|
4427
|
+
*
|
|
4428
|
+
* @example
|
|
4429
|
+
* ```ts
|
|
4430
|
+
* import { toHighlight } from '@vuetify/v0'
|
|
4431
|
+
*
|
|
4432
|
+
* const chunks = toHighlight('Hello World', 'World')
|
|
4433
|
+
* // [{ text: 'Hello ', match: false }, { text: 'World', match: true }]
|
|
4434
|
+
* ```
|
|
4435
|
+
*/
|
|
4436
|
+
function merge(ranges) {
|
|
4437
|
+
const sorted = ranges.filter((span) => span[0] < span[1]).toSorted((a, b) => a[0] - b[0]);
|
|
4438
|
+
const merged = [];
|
|
4439
|
+
for (const span of sorted) {
|
|
4440
|
+
const last = merged.at(-1);
|
|
4441
|
+
if (last && span[0] <= last[1]) last[1] = Math.max(last[1], span[1]);
|
|
4442
|
+
else merged.push([span[0], span[1]]);
|
|
4443
|
+
}
|
|
4444
|
+
return merged;
|
|
4445
|
+
}
|
|
4446
|
+
function chunk(text, ranges) {
|
|
4447
|
+
const chunks = [];
|
|
4448
|
+
let cursor = 0;
|
|
4449
|
+
for (const [start, end] of ranges) {
|
|
4450
|
+
if (cursor < start) chunks.push({
|
|
4451
|
+
text: text.slice(cursor, start),
|
|
4452
|
+
match: false
|
|
4453
|
+
});
|
|
4454
|
+
chunks.push({
|
|
4455
|
+
text: text.slice(start, end),
|
|
4456
|
+
match: true
|
|
4457
|
+
});
|
|
4458
|
+
cursor = end;
|
|
4459
|
+
}
|
|
4460
|
+
if (cursor < text.length) chunks.push({
|
|
4461
|
+
text: text.slice(cursor),
|
|
4462
|
+
match: false
|
|
4463
|
+
});
|
|
4464
|
+
return chunks;
|
|
4465
|
+
}
|
|
4466
|
+
function find(text, query, matchAll, ignoreCase) {
|
|
4467
|
+
const terms = (/* @__PURE__ */ toArray(query)).filter(Boolean);
|
|
4468
|
+
const haystack = ignoreCase ? text.toLocaleLowerCase() : text;
|
|
4469
|
+
const spans = [];
|
|
4470
|
+
for (const term of terms) {
|
|
4471
|
+
const needle = ignoreCase ? term.toLocaleLowerCase() : term;
|
|
4472
|
+
let index = haystack.indexOf(needle);
|
|
4473
|
+
if (index !== -1) {
|
|
4474
|
+
spans.push([index, index + term.length]);
|
|
4475
|
+
if (matchAll) {
|
|
4476
|
+
index = haystack.indexOf(needle, index + term.length);
|
|
4477
|
+
while (index !== -1) {
|
|
4478
|
+
spans.push([index, index + term.length]);
|
|
4479
|
+
index = haystack.indexOf(needle, index + term.length);
|
|
4480
|
+
}
|
|
4481
|
+
}
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4484
|
+
return merge(spans);
|
|
4485
|
+
}
|
|
4486
|
+
/**
|
|
4487
|
+
* Splits text into matched and unmatched chunks.
|
|
4488
|
+
*
|
|
4489
|
+
* Pure transformer — returns a plain array. Wrap the call in `computed()` for
|
|
4490
|
+
* reactive recomputation.
|
|
4491
|
+
*
|
|
4492
|
+
* Priority: `options.matches` (when non-empty) → `query` → no-match fallback.
|
|
4493
|
+
*
|
|
4494
|
+
* @param text The source string to split.
|
|
4495
|
+
* @param query One or more search terms. Empty strings are ignored. Case sensitivity controlled by `options.ignoreCase`.
|
|
4496
|
+
* @param options Optional `matches`, `matchAll`, `ignoreCase`.
|
|
4497
|
+
* @returns A `HighlightChunk[]` array.
|
|
4498
|
+
*
|
|
4499
|
+
* @see https://0.vuetifyjs.com/composables/transformers/to-highlight
|
|
4500
|
+
*
|
|
4501
|
+
* @example
|
|
4502
|
+
* ```ts
|
|
4503
|
+
* import { computed, shallowRef } from 'vue'
|
|
4504
|
+
* import { toHighlight } from '@vuetify/v0'
|
|
4505
|
+
*
|
|
4506
|
+
* const query = shallowRef('World')
|
|
4507
|
+
* const chunks = computed(() => toHighlight('Hello World', query))
|
|
4508
|
+
*
|
|
4509
|
+
* console.log(chunks.value)
|
|
4510
|
+
* // [{ text: 'Hello ', match: false }, { text: 'World', match: true }]
|
|
4511
|
+
* ```
|
|
4512
|
+
*/
|
|
4513
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
4514
|
+
function toHighlight(text, query, options = {}) {
|
|
4515
|
+
const _text = toValue(text);
|
|
4516
|
+
const _query = toValue(query);
|
|
4517
|
+
const _matches = toValue(options.matches);
|
|
4518
|
+
const matchAll = toValue(options.matchAll) ?? false;
|
|
4519
|
+
const ignoreCase = toValue(options.ignoreCase) ?? false;
|
|
4520
|
+
if (_matches?.length) return chunk(_text, merge(_matches));
|
|
4521
|
+
if (_query) {
|
|
4522
|
+
const ranges = find(_text, _query, matchAll, ignoreCase);
|
|
4523
|
+
return ranges.length > 0 ? chunk(_text, ranges) : [{
|
|
4524
|
+
text: _text,
|
|
4525
|
+
match: false
|
|
4526
|
+
}];
|
|
4527
|
+
}
|
|
4528
|
+
return [{
|
|
4529
|
+
text: _text,
|
|
4530
|
+
match: false
|
|
4531
|
+
}];
|
|
4532
|
+
}
|
|
4533
|
+
//#endregion
|
|
3895
4534
|
//#region src/composables/toReactive/index.ts
|
|
3896
4535
|
/**
|
|
3897
4536
|
* @module toReactive
|
|
@@ -4286,11 +4925,11 @@ const [createBreakpointsContext, createBreakpointsPlugin, useBreakpoints] = crea
|
|
|
4286
4925
|
*
|
|
4287
4926
|
* @example Using the built-in Temporal adapter
|
|
4288
4927
|
* ```ts
|
|
4289
|
-
* import {
|
|
4928
|
+
* import { V0DateAdapter } from '@vuetify/v0/date'
|
|
4290
4929
|
* import { createDatePlugin } from '@vuetify/v0'
|
|
4291
4930
|
*
|
|
4292
4931
|
* const app = createApp(App)
|
|
4293
|
-
* app.use(createDatePlugin({ adapter: new
|
|
4932
|
+
* app.use(createDatePlugin({ adapter: new V0DateAdapter() }))
|
|
4294
4933
|
*
|
|
4295
4934
|
* // In a component:
|
|
4296
4935
|
* const { adapter } = useDate()
|
|
@@ -4300,9 +4939,9 @@ const [createBreakpointsContext, createBreakpointsPlugin, useBreakpoints] = crea
|
|
|
4300
4939
|
*
|
|
4301
4940
|
* @example Custom adapter
|
|
4302
4941
|
* ```ts
|
|
4303
|
-
* import
|
|
4942
|
+
* import { DateAdapter } from '@vuetify/v0'
|
|
4304
4943
|
*
|
|
4305
|
-
* class DateFnsAdapter
|
|
4944
|
+
* class DateFnsAdapter extends DateAdapter<Date> {
|
|
4306
4945
|
* // ... implementation
|
|
4307
4946
|
* }
|
|
4308
4947
|
*
|
|
@@ -4333,6 +4972,7 @@ const defaultLocales = {
|
|
|
4333
4972
|
function deriveFirstDayOfWeek(locale) {
|
|
4334
4973
|
try {
|
|
4335
4974
|
const info = new Intl.Locale(locale).getWeekInfo?.();
|
|
4975
|
+
/* v8 ignore next -- defensive: getWeekInfo always returns info in Node 22+ */
|
|
4336
4976
|
return info ? info.firstDay % 7 : 0;
|
|
4337
4977
|
} catch {
|
|
4338
4978
|
return 0;
|
|
@@ -4350,14 +4990,14 @@ function deriveFirstDayOfWeek(locale) {
|
|
|
4350
4990
|
*
|
|
4351
4991
|
* @example
|
|
4352
4992
|
* ```ts
|
|
4353
|
-
* import {
|
|
4993
|
+
* import { V0DateAdapter } from '@vuetify/v0/date'
|
|
4354
4994
|
*
|
|
4355
|
-
* const { adapter } = createDate({ adapter: new
|
|
4995
|
+
* const { adapter } = createDate({ adapter: new V0DateAdapter() })
|
|
4356
4996
|
* const today = adapter.date()
|
|
4357
4997
|
*
|
|
4358
4998
|
* // With locale options
|
|
4359
4999
|
* const { adapter } = createDate({
|
|
4360
|
-
* adapter: new
|
|
5000
|
+
* adapter: new V0DateAdapter(),
|
|
4361
5001
|
* locale: 'de-DE',
|
|
4362
5002
|
* })
|
|
4363
5003
|
* ```
|
|
@@ -4412,10 +5052,10 @@ function createDate(options) {
|
|
|
4412
5052
|
*
|
|
4413
5053
|
* @example
|
|
4414
5054
|
* ```ts
|
|
4415
|
-
* import {
|
|
5055
|
+
* import { V0DateAdapter } from '@vuetify/v0/date'
|
|
4416
5056
|
*
|
|
4417
5057
|
* const [useAppDate, provideAppDate] = createDateContext({
|
|
4418
|
-
* adapter: new
|
|
5058
|
+
* adapter: new V0DateAdapter(),
|
|
4419
5059
|
* namespace: 'app:date',
|
|
4420
5060
|
* })
|
|
4421
5061
|
* ```
|
|
@@ -4436,14 +5076,14 @@ function createDateContext(options) {
|
|
|
4436
5076
|
*
|
|
4437
5077
|
* @example
|
|
4438
5078
|
* ```ts
|
|
4439
|
-
* import {
|
|
5079
|
+
* import { V0DateAdapter } from '@vuetify/v0/date'
|
|
4440
5080
|
*
|
|
4441
5081
|
* const app = createApp(App)
|
|
4442
|
-
* app.use(createDatePlugin({ adapter: new
|
|
5082
|
+
* app.use(createDatePlugin({ adapter: new V0DateAdapter() }))
|
|
4443
5083
|
*
|
|
4444
5084
|
* // With locale options
|
|
4445
5085
|
* app.use(createDatePlugin({
|
|
4446
|
-
* adapter: new
|
|
5086
|
+
* adapter: new V0DateAdapter(),
|
|
4447
5087
|
* locale: 'de-DE',
|
|
4448
5088
|
* }))
|
|
4449
5089
|
* ```
|
|
@@ -4477,10 +5117,10 @@ function createDatePlugin(options) {
|
|
|
4477
5117
|
* @example
|
|
4478
5118
|
* ```ts
|
|
4479
5119
|
* // main.ts
|
|
4480
|
-
* import {
|
|
5120
|
+
* import { V0DateAdapter } from '@vuetify/v0/date'
|
|
4481
5121
|
* import { createDatePlugin } from '@vuetify/v0'
|
|
4482
5122
|
*
|
|
4483
|
-
* app.use(createDatePlugin({ adapter: new
|
|
5123
|
+
* app.use(createDatePlugin({ adapter: new V0DateAdapter() }))
|
|
4484
5124
|
* ```
|
|
4485
5125
|
*
|
|
4486
5126
|
* @example
|
|
@@ -4494,7 +5134,7 @@ function createDatePlugin(options) {
|
|
|
4494
5134
|
* ```
|
|
4495
5135
|
*/
|
|
4496
5136
|
function useDate(namespace = "v0:date") {
|
|
4497
|
-
if (!/* @__PURE__ */ instanceExists()) throw new Error("[v0] useDate() must be called inside a Vue component with createDatePlugin installed.\n\nExample:\n import {
|
|
5137
|
+
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() }))");
|
|
4498
5138
|
return useContext(namespace);
|
|
4499
5139
|
}
|
|
4500
5140
|
//#endregion
|
|
@@ -4615,18 +5255,790 @@ function useDelay(callback, options = {}) {
|
|
|
4615
5255
|
};
|
|
4616
5256
|
}
|
|
4617
5257
|
//#endregion
|
|
4618
|
-
//#region src/composables/
|
|
5258
|
+
//#region src/composables/useMutationObserver/index.ts
|
|
4619
5259
|
/**
|
|
4620
|
-
*
|
|
5260
|
+
* @module useMutationObserver
|
|
4621
5261
|
*
|
|
4622
|
-
*
|
|
4623
|
-
*
|
|
5262
|
+
* @see https://0.vuetifyjs.com/composables/system/use-mutation-observer
|
|
5263
|
+
*
|
|
5264
|
+
* @remarks
|
|
5265
|
+
* MutationObserver composable with lifecycle management.
|
|
5266
|
+
*
|
|
5267
|
+
* Key features:
|
|
5268
|
+
* - MutationObserver API wrapper
|
|
5269
|
+
* - `isActive` reactive flag
|
|
5270
|
+
* - `once` option for single-fire observation
|
|
5271
|
+
* - Pause/resume/stop functionality
|
|
5272
|
+
* - Automatic cleanup on unmount
|
|
5273
|
+
* - SSR-safe (checks SUPPORTS_MUTATION_OBSERVER)
|
|
5274
|
+
* - Hydration-aware
|
|
5275
|
+
* - Configurable observation options (childList, attributes, characterData, etc.)
|
|
5276
|
+
*
|
|
5277
|
+
* Perfect for detecting DOM changes and responding to mutations.
|
|
5278
|
+
*
|
|
5279
|
+
* @example
|
|
5280
|
+
* ```ts
|
|
5281
|
+
* import { useTemplateRef } from 'vue'
|
|
5282
|
+
* import { useMutationObserver } from '@vuetify/v0'
|
|
5283
|
+
*
|
|
5284
|
+
* const target = useTemplateRef('target')
|
|
5285
|
+
* useMutationObserver(target, records => {
|
|
5286
|
+
* console.log(records)
|
|
5287
|
+
* }, { childList: true })
|
|
5288
|
+
* ```
|
|
4624
5289
|
*/
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
5290
|
+
/**
|
|
5291
|
+
* A composable that uses the Mutation Observer API to detect changes in the DOM.
|
|
5292
|
+
*
|
|
5293
|
+
* @param target The element to observe.
|
|
5294
|
+
* @param callback The callback to execute when a mutation is observed.
|
|
5295
|
+
* @param options The options for the Mutation Observer.
|
|
5296
|
+
* @returns An object with methods to control the observer.
|
|
5297
|
+
*
|
|
5298
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
|
|
5299
|
+
* @see https://0.vuetifyjs.com/composables/system/use-mutation-observer
|
|
5300
|
+
*
|
|
5301
|
+
* @example
|
|
5302
|
+
* ```ts
|
|
5303
|
+
* import { ref } from 'vue'
|
|
5304
|
+
* import { useMutationObserver } from '@vuetify/v0'
|
|
5305
|
+
*
|
|
5306
|
+
* const container = ref<HTMLElement>()
|
|
5307
|
+
*
|
|
5308
|
+
* const { pause, resume, isPaused } = useMutationObserver(
|
|
5309
|
+
* container,
|
|
5310
|
+
* (mutations) => {
|
|
5311
|
+
* mutations.forEach((mutation) => {
|
|
5312
|
+
* if (mutation.type === 'childList') {
|
|
5313
|
+
* console.log('Children changed:', mutation.addedNodes, mutation.removedNodes)
|
|
5314
|
+
* } else if (mutation.type === 'attributes') {
|
|
5315
|
+
* console.log('Attribute changed:', mutation.attributeName)
|
|
5316
|
+
* }
|
|
5317
|
+
* })
|
|
5318
|
+
* },
|
|
5319
|
+
* {
|
|
5320
|
+
* childList: true,
|
|
5321
|
+
* attributes: true,
|
|
5322
|
+
* subtree: true
|
|
5323
|
+
* }
|
|
5324
|
+
* )
|
|
5325
|
+
*
|
|
5326
|
+
* // Pause observation
|
|
5327
|
+
* pause()
|
|
5328
|
+
*
|
|
5329
|
+
* // Resume observation
|
|
5330
|
+
* resume()
|
|
5331
|
+
* ```
|
|
5332
|
+
*/
|
|
5333
|
+
function useMutationObserver(target, callback, options = {}) {
|
|
5334
|
+
const observerOptions = {
|
|
5335
|
+
childList: options.childList ?? true,
|
|
5336
|
+
attributes: options.attributes ?? false,
|
|
5337
|
+
characterData: options.characterData ?? false,
|
|
5338
|
+
subtree: options.subtree ?? false,
|
|
5339
|
+
attributeOldValue: options.attributeOldValue ?? false,
|
|
5340
|
+
characterDataOldValue: options.characterDataOldValue ?? false,
|
|
5341
|
+
attributeFilter: options.attributeFilter
|
|
5342
|
+
};
|
|
5343
|
+
return createObserver(target, callback, {
|
|
5344
|
+
supports: SUPPORTS_MUTATION_OBSERVER,
|
|
5345
|
+
once: options.once,
|
|
5346
|
+
create: (cb) => new MutationObserver((mutations) => {
|
|
5347
|
+
cb(mutations.map((m) => ({
|
|
5348
|
+
type: m.type,
|
|
5349
|
+
target: m.target,
|
|
5350
|
+
addedNodes: m.addedNodes,
|
|
5351
|
+
removedNodes: m.removedNodes,
|
|
5352
|
+
previousSibling: m.previousSibling,
|
|
5353
|
+
nextSibling: m.nextSibling,
|
|
5354
|
+
attributeName: m.attributeName,
|
|
5355
|
+
attributeNamespace: m.attributeNamespace,
|
|
5356
|
+
oldValue: m.oldValue
|
|
5357
|
+
})));
|
|
5358
|
+
}),
|
|
5359
|
+
observe: (obs, el) => obs.observe(el, observerOptions),
|
|
5360
|
+
immediate: options.immediate ? (el) => {
|
|
5361
|
+
const emptyNodeList = {
|
|
5362
|
+
length: 0,
|
|
5363
|
+
item: () => null,
|
|
5364
|
+
forEach: () => {},
|
|
5365
|
+
*[Symbol.iterator]() {}
|
|
5366
|
+
};
|
|
5367
|
+
return [{
|
|
5368
|
+
type: "childList",
|
|
5369
|
+
target: el,
|
|
5370
|
+
addedNodes: emptyNodeList,
|
|
5371
|
+
removedNodes: emptyNodeList,
|
|
5372
|
+
previousSibling: null,
|
|
5373
|
+
nextSibling: null,
|
|
5374
|
+
attributeName: null,
|
|
5375
|
+
attributeNamespace: null,
|
|
5376
|
+
oldValue: null
|
|
5377
|
+
}];
|
|
5378
|
+
} : void 0,
|
|
5379
|
+
onceIncludesImmediate: true
|
|
5380
|
+
});
|
|
5381
|
+
}
|
|
5382
|
+
//#endregion
|
|
5383
|
+
//#region src/composables/useDragDrop/adapters/adapter.ts
|
|
5384
|
+
/**
|
|
5385
|
+
* @module useDragDrop/adapters/adapter
|
|
5386
|
+
*
|
|
5387
|
+
* @remarks
|
|
5388
|
+
* Adapter contract and abstract base for useDragDrop. Concrete adapters extend
|
|
5389
|
+
* `DragDropAdapter<Z>` to share the `cleanup` field, `dispose()` lifecycle, and
|
|
5390
|
+
* the `locate()` DOM-walk helper.
|
|
5391
|
+
*/
|
|
5392
|
+
/**
|
|
5393
|
+
* Abstract base class for useDragDrop adapters. Provides a `cleanup` slot, a
|
|
5394
|
+
* `dispose()` lifecycle, and a `locate()` helper that walks the DOM to find the
|
|
5395
|
+
* draggable ticket whose `el` ancestors a given event target.
|
|
5396
|
+
*
|
|
5397
|
+
* @example
|
|
5398
|
+
* ```ts
|
|
5399
|
+
* import { DragDropAdapter, type DragDropAdapterContext } from '@vuetify/v0'
|
|
5400
|
+
*
|
|
5401
|
+
* class MyAdapter extends DragDropAdapter {
|
|
5402
|
+
* setup (context: DragDropAdapterContext) {
|
|
5403
|
+
* const stop = useEventListener(document, 'mousedown', event => {
|
|
5404
|
+
* const ticket = this.locate(event.target, context)
|
|
5405
|
+
* if (ticket) context.emit.start(ticket, { x: event.clientX, y: event.clientY }, 'pointer')
|
|
5406
|
+
* })
|
|
5407
|
+
* this.cleanup = () => stop()
|
|
5408
|
+
* }
|
|
5409
|
+
* }
|
|
5410
|
+
* ```
|
|
5411
|
+
*/
|
|
5412
|
+
var DragDropAdapter = class {
|
|
5413
|
+
cleanup = null;
|
|
5414
|
+
dispose() {
|
|
5415
|
+
this.cleanup?.();
|
|
5416
|
+
this.cleanup = null;
|
|
5417
|
+
}
|
|
5418
|
+
locate(target, context) {
|
|
5419
|
+
let element = /* @__PURE__ */ isElement(target) ? target : null;
|
|
5420
|
+
while (element) {
|
|
5421
|
+
for (const ticket of context.draggables.values()) if (ticket.el.value === element) return ticket;
|
|
5422
|
+
element = element.parentElement;
|
|
5423
|
+
}
|
|
5424
|
+
return null;
|
|
5425
|
+
}
|
|
5426
|
+
};
|
|
5427
|
+
//#endregion
|
|
5428
|
+
//#region src/composables/useDragDrop/adapters/pointer.ts
|
|
5429
|
+
/**
|
|
5430
|
+
* @module useDragDrop/adapters/pointer
|
|
5431
|
+
*
|
|
5432
|
+
* @remarks
|
|
5433
|
+
* Default pointer adapter for useDragDrop. Listens for `pointerdown` /
|
|
5434
|
+
* `pointermove` / `pointerup` / `pointercancel` on the document and emits the
|
|
5435
|
+
* drag lifecycle. Activation distance is configurable via `threshold`.
|
|
5436
|
+
*/
|
|
5437
|
+
/**
|
|
5438
|
+
* Default pointer adapter. Wires `pointerdown` / `pointermove` / `pointerup` /
|
|
5439
|
+
* `pointercancel` on the document and converts them into drag lifecycle calls.
|
|
5440
|
+
*
|
|
5441
|
+
* @example
|
|
5442
|
+
* ```ts
|
|
5443
|
+
* import { PointerAdapter, useDragDrop } from '@vuetify/v0'
|
|
5444
|
+
*
|
|
5445
|
+
* useDragDrop({ adapters: [new PointerAdapter({ threshold: 10 })] })
|
|
5446
|
+
* ```
|
|
5447
|
+
*/
|
|
5448
|
+
var PointerAdapter = class extends DragDropAdapter {
|
|
5449
|
+
threshold;
|
|
5450
|
+
constructor(options = {}) {
|
|
5451
|
+
super();
|
|
5452
|
+
this.threshold = options.threshold ?? 0;
|
|
5453
|
+
}
|
|
5454
|
+
setup(context) {
|
|
5455
|
+
const logger = useLogger();
|
|
5456
|
+
if (this.cleanup) {
|
|
5457
|
+
logger.warn("PointerAdapter setup called twice; previous registration will be replaced");
|
|
5458
|
+
this.dispose();
|
|
5459
|
+
}
|
|
5460
|
+
if (!IN_BROWSER) return;
|
|
5461
|
+
let downSource = null;
|
|
5462
|
+
let downOrigin = null;
|
|
5463
|
+
let downId = null;
|
|
5464
|
+
let started = false;
|
|
5465
|
+
function reset() {
|
|
5466
|
+
downSource = null;
|
|
5467
|
+
downOrigin = null;
|
|
5468
|
+
downId = null;
|
|
5469
|
+
started = false;
|
|
5470
|
+
}
|
|
5471
|
+
const onDown = (event) => {
|
|
5472
|
+
if (event.button !== 0) return;
|
|
5473
|
+
if (downSource) return;
|
|
5474
|
+
const ticket = this.locate(event.target, context);
|
|
5475
|
+
if (!ticket) return;
|
|
5476
|
+
downSource = ticket;
|
|
5477
|
+
downOrigin = {
|
|
5478
|
+
x: event.clientX,
|
|
5479
|
+
y: event.clientY
|
|
5480
|
+
};
|
|
5481
|
+
downId = event.pointerId;
|
|
5482
|
+
started = false;
|
|
5483
|
+
};
|
|
5484
|
+
const onMove = (event) => {
|
|
5485
|
+
if (!downSource || !downOrigin || event.pointerId !== downId) return;
|
|
5486
|
+
const point = {
|
|
5487
|
+
x: event.clientX,
|
|
5488
|
+
y: event.clientY
|
|
5489
|
+
};
|
|
5490
|
+
if (!started) {
|
|
5491
|
+
const dx = point.x - downOrigin.x;
|
|
5492
|
+
const dy = point.y - downOrigin.y;
|
|
5493
|
+
if (this.threshold > 0 && Math.hypot(dx, dy) < this.threshold) return;
|
|
5494
|
+
context.emit.start(downSource, downOrigin, "pointer");
|
|
5495
|
+
started = true;
|
|
5496
|
+
}
|
|
5497
|
+
context.emit.move(point);
|
|
5498
|
+
};
|
|
5499
|
+
function onUp(event) {
|
|
5500
|
+
if (event.pointerId !== downId) return;
|
|
5501
|
+
if (downSource && started) context.emit.drop();
|
|
5502
|
+
reset();
|
|
5503
|
+
}
|
|
5504
|
+
function onCancel(event) {
|
|
5505
|
+
if (event.pointerId !== downId) return;
|
|
5506
|
+
if (downSource && started) context.emit.cancel();
|
|
5507
|
+
reset();
|
|
5508
|
+
}
|
|
5509
|
+
const stopDown = useEventListener(document, "pointerdown", onDown);
|
|
5510
|
+
const stopMove = useEventListener(document, "pointermove", onMove);
|
|
5511
|
+
const stopUp = useEventListener(document, "pointerup", onUp);
|
|
5512
|
+
const stopCancel = useEventListener(document, "pointercancel", onCancel);
|
|
5513
|
+
this.cleanup = () => {
|
|
5514
|
+
stopDown();
|
|
5515
|
+
stopMove();
|
|
5516
|
+
stopUp();
|
|
5517
|
+
stopCancel();
|
|
5518
|
+
};
|
|
5519
|
+
}
|
|
5520
|
+
};
|
|
5521
|
+
//#endregion
|
|
5522
|
+
//#region src/composables/useDragDrop/adapters/keyboard.ts
|
|
5523
|
+
/**
|
|
5524
|
+
* @module useDragDrop/adapters/keyboard
|
|
5525
|
+
*
|
|
5526
|
+
* @remarks
|
|
5527
|
+
* Default keyboard adapter for useDragDrop. Listens for `keydown` on the
|
|
5528
|
+
* document. Activation keys (default Space and Enter) start and drop drags;
|
|
5529
|
+
* arrow keys nudge the drag point by `step` px; Escape cancels.
|
|
5530
|
+
*/
|
|
5531
|
+
function isEditable(element) {
|
|
5532
|
+
if (/* @__PURE__ */ isNull(element)) return false;
|
|
5533
|
+
const tag = element.tagName;
|
|
5534
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
5535
|
+
if (element.isContentEditable) return true;
|
|
5536
|
+
const role = element.getAttribute("role");
|
|
5537
|
+
return role === "textbox" || role === "searchbox" || role === "combobox" || role === "spinbutton";
|
|
5538
|
+
}
|
|
5539
|
+
/**
|
|
5540
|
+
* Default keyboard adapter. Listens for `keydown` on the document; activation
|
|
5541
|
+
* keys start/drop drags, arrow keys nudge the drag point, Escape cancels.
|
|
5542
|
+
*
|
|
5543
|
+
* @example
|
|
5544
|
+
* ```ts
|
|
5545
|
+
* import { KeyboardAdapter, useDragDrop } from '@vuetify/v0'
|
|
5546
|
+
*
|
|
5547
|
+
* useDragDrop({ adapters: [new KeyboardAdapter({ activate: ['x'], step: 32 })] })
|
|
5548
|
+
* ```
|
|
5549
|
+
*/
|
|
5550
|
+
var KeyboardAdapter = class extends DragDropAdapter {
|
|
5551
|
+
activate;
|
|
5552
|
+
step;
|
|
5553
|
+
constructor(options = {}) {
|
|
5554
|
+
super();
|
|
5555
|
+
this.activate = options.activate ?? [" ", "Enter"];
|
|
5556
|
+
this.step = options.step ?? 16;
|
|
5557
|
+
}
|
|
5558
|
+
setup(context) {
|
|
5559
|
+
const logger = useLogger();
|
|
5560
|
+
if (this.cleanup) {
|
|
5561
|
+
logger.warn("KeyboardAdapter setup called twice; previous registration will be replaced");
|
|
5562
|
+
this.dispose();
|
|
5563
|
+
}
|
|
5564
|
+
if (!IN_BROWSER) return;
|
|
5565
|
+
const onKeyDown = (event) => {
|
|
5566
|
+
const focused = document.activeElement;
|
|
5567
|
+
if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) return;
|
|
5568
|
+
if (isEditable(focused)) return;
|
|
5569
|
+
const ticket = this.locate(focused, context);
|
|
5570
|
+
const isActive = !/* @__PURE__ */ isNull(context.active.value);
|
|
5571
|
+
if (this.activate.includes(event.key)) {
|
|
5572
|
+
if (isActive) {
|
|
5573
|
+
event.preventDefault();
|
|
5574
|
+
context.emit.drop();
|
|
5575
|
+
} else if (ticket) {
|
|
5576
|
+
const el = ticket.el.value;
|
|
5577
|
+
if (!el) {
|
|
5578
|
+
logger.warn("KeyboardAdapter: cannot start drag — element is not mounted");
|
|
5579
|
+
return;
|
|
5580
|
+
}
|
|
5581
|
+
event.preventDefault();
|
|
5582
|
+
const rect = el.getBoundingClientRect();
|
|
5583
|
+
context.emit.start(ticket, {
|
|
5584
|
+
x: rect.left + rect.width / 2,
|
|
5585
|
+
y: rect.top + rect.height / 2
|
|
5586
|
+
}, "keyboard");
|
|
5587
|
+
}
|
|
5588
|
+
return;
|
|
5589
|
+
}
|
|
5590
|
+
if (event.key === "Escape" && isActive) {
|
|
5591
|
+
event.preventDefault();
|
|
5592
|
+
context.emit.cancel();
|
|
5593
|
+
return;
|
|
5594
|
+
}
|
|
5595
|
+
if (isActive && event.key.startsWith("Arrow")) {
|
|
5596
|
+
const active = context.active.value;
|
|
5597
|
+
if (/* @__PURE__ */ isNull(active)) return;
|
|
5598
|
+
const current = active.current;
|
|
5599
|
+
let point = null;
|
|
5600
|
+
switch (event.key) {
|
|
5601
|
+
case "ArrowUp":
|
|
5602
|
+
point = {
|
|
5603
|
+
x: current.x,
|
|
5604
|
+
y: current.y - this.step
|
|
5605
|
+
};
|
|
5606
|
+
break;
|
|
5607
|
+
case "ArrowDown":
|
|
5608
|
+
point = {
|
|
5609
|
+
x: current.x,
|
|
5610
|
+
y: current.y + this.step
|
|
5611
|
+
};
|
|
5612
|
+
break;
|
|
5613
|
+
case "ArrowLeft":
|
|
5614
|
+
point = {
|
|
5615
|
+
x: current.x - this.step,
|
|
5616
|
+
y: current.y
|
|
5617
|
+
};
|
|
5618
|
+
break;
|
|
5619
|
+
case "ArrowRight":
|
|
5620
|
+
point = {
|
|
5621
|
+
x: current.x + this.step,
|
|
5622
|
+
y: current.y
|
|
5623
|
+
};
|
|
5624
|
+
break;
|
|
5625
|
+
}
|
|
5626
|
+
if (point) {
|
|
5627
|
+
event.preventDefault();
|
|
5628
|
+
context.emit.move(point);
|
|
5629
|
+
}
|
|
5630
|
+
}
|
|
5631
|
+
};
|
|
5632
|
+
const stop = useEventListener(document, "keydown", onKeyDown);
|
|
5633
|
+
this.cleanup = () => stop();
|
|
5634
|
+
}
|
|
5635
|
+
};
|
|
5636
|
+
//#endregion
|
|
5637
|
+
//#region src/composables/useDragDrop/index.ts
|
|
5638
|
+
/**
|
|
5639
|
+
* @module useDragDrop
|
|
5640
|
+
*
|
|
5641
|
+
* @see https://0.vuetifyjs.com/composables/system/use-drag-drop
|
|
5642
|
+
*
|
|
5643
|
+
* @remarks
|
|
5644
|
+
* Headless drag-and-drop primitive. Owns two registries (draggables and zones)
|
|
5645
|
+
* plus the active-drag state. Pointer and keyboard adapters ship by default;
|
|
5646
|
+
* lifecycle hooks and a plugin array provide extension points.
|
|
5647
|
+
*
|
|
5648
|
+
* @example
|
|
5649
|
+
* ```ts
|
|
5650
|
+
* import { useDragDrop } from '@vuetify/v0'
|
|
5651
|
+
*
|
|
5652
|
+
* const dnd = useDragDrop()
|
|
5653
|
+
* ```
|
|
5654
|
+
*/
|
|
5655
|
+
/**
|
|
5656
|
+
* Pure math for resolving where in an oriented zone a pointer would drop.
|
|
5657
|
+
* Internal — consumers rely on the `position.index` / `position.indicator`
|
|
5658
|
+
* fields delivered to `onDrop`.
|
|
5659
|
+
*/
|
|
5660
|
+
function resolveDropPosition(point, rects, orientation) {
|
|
5661
|
+
if (rects.length === 0) return null;
|
|
5662
|
+
const axis = orientation === "vertical" ? "y" : "x";
|
|
5663
|
+
const start = orientation === "vertical" ? "top" : "left";
|
|
5664
|
+
const end = orientation === "vertical" ? "bottom" : "right";
|
|
5665
|
+
const coord = point[axis];
|
|
5666
|
+
if (coord < rects[0][start]) return {
|
|
5667
|
+
index: 0,
|
|
5668
|
+
edge: "before",
|
|
5669
|
+
rect: rects[0]
|
|
5670
|
+
};
|
|
5671
|
+
const last = rects.at(-1);
|
|
5672
|
+
if (coord > last[end]) return {
|
|
5673
|
+
index: rects.length,
|
|
5674
|
+
edge: "after",
|
|
5675
|
+
rect: last
|
|
5676
|
+
};
|
|
5677
|
+
for (const [index, rect] of rects.entries()) if (coord >= rect[start] && coord <= rect[end]) {
|
|
5678
|
+
if (coord < rect[start] + (rect[end] - rect[start]) / 2) return {
|
|
5679
|
+
index,
|
|
5680
|
+
edge: "before",
|
|
5681
|
+
rect
|
|
5682
|
+
};
|
|
5683
|
+
return {
|
|
5684
|
+
index: index + 1,
|
|
5685
|
+
edge: "after",
|
|
5686
|
+
rect
|
|
5687
|
+
};
|
|
5688
|
+
}
|
|
5689
|
+
for (let index = 0; index < rects.length - 1; index++) {
|
|
5690
|
+
const a = rects[index];
|
|
5691
|
+
const b = rects[index + 1];
|
|
5692
|
+
if (coord > a[end] && coord < b[start]) {
|
|
5693
|
+
if (coord <= (a[end] + b[start]) / 2) return {
|
|
5694
|
+
index: index + 1,
|
|
5695
|
+
edge: "after",
|
|
5696
|
+
rect: a
|
|
5697
|
+
};
|
|
5698
|
+
return {
|
|
5699
|
+
index: index + 1,
|
|
5700
|
+
edge: "before",
|
|
5701
|
+
rect: b
|
|
5702
|
+
};
|
|
5703
|
+
}
|
|
5704
|
+
}
|
|
5705
|
+
return {
|
|
5706
|
+
index: rects.length,
|
|
5707
|
+
edge: "after",
|
|
5708
|
+
rect: last
|
|
5709
|
+
};
|
|
5710
|
+
}
|
|
5711
|
+
/**
|
|
5712
|
+
* Create a headless drag-and-drop context.
|
|
5713
|
+
*
|
|
5714
|
+
* @param options - Adapters, plugins, and lifecycle hooks. All optional.
|
|
5715
|
+
* @returns A `DragDropContext<Z>` exposing `draggables` / `zones` registries,
|
|
5716
|
+
* the `active` drag, the `isDragging` boolean, and a programmatic `cancel()`.
|
|
5717
|
+
*
|
|
5718
|
+
* @see https://0.vuetifyjs.com/composables/system/use-drag-drop
|
|
5719
|
+
*
|
|
5720
|
+
* @example
|
|
5721
|
+
* ```ts
|
|
5722
|
+
* import { useDragDrop } from '@vuetify/v0'
|
|
5723
|
+
* import { useTemplateRef } from 'vue'
|
|
5724
|
+
*
|
|
5725
|
+
* const dnd = useDragDrop<{ type: 'card', value: string }>()
|
|
5726
|
+
*
|
|
5727
|
+
* const draggable = useTemplateRef<HTMLElement>('draggable')
|
|
5728
|
+
* const dropzone = useTemplateRef<HTMLElement>('dropzone')
|
|
5729
|
+
*
|
|
5730
|
+
* dnd.draggables.register({ el: draggable, type: 'card', value: 'card-1' })
|
|
5731
|
+
* dnd.zones.register({
|
|
5732
|
+
* el: dropzone,
|
|
5733
|
+
* accept: ['card'],
|
|
5734
|
+
* onDrop: (drag, position) => console.log(drag.value, position.index),
|
|
5735
|
+
* })
|
|
5736
|
+
* ```
|
|
5737
|
+
*/
|
|
5738
|
+
function useDragDrop(options = {}) {
|
|
5739
|
+
const { plugins = [] } = options;
|
|
5740
|
+
const logger = useLogger();
|
|
5741
|
+
const _draggables = createRegistry({ events: true });
|
|
5742
|
+
const _zones = createRegistry({ events: true });
|
|
5743
|
+
const active = shallowRef(null);
|
|
5744
|
+
const isDragging = toRef(() => !/* @__PURE__ */ isNull(active.value));
|
|
5745
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
5746
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
5747
|
+
function next(fn, ...args) {
|
|
5748
|
+
if (/* @__PURE__ */ isUndefined(fn)) return;
|
|
5749
|
+
try {
|
|
5750
|
+
fn(...args);
|
|
5751
|
+
} catch (error) {
|
|
5752
|
+
logger.error("useDragDrop hook threw", error);
|
|
5753
|
+
}
|
|
5754
|
+
}
|
|
5755
|
+
function safeAccept(accept, drag) {
|
|
5756
|
+
try {
|
|
5757
|
+
if (/* @__PURE__ */ isNull(drag)) return false;
|
|
5758
|
+
if (/* @__PURE__ */ isUndefined(accept)) return true;
|
|
5759
|
+
if (/* @__PURE__ */ isArray(accept)) return accept.includes(drag.type);
|
|
5760
|
+
const result = accept(drag);
|
|
5761
|
+
if (/* @__PURE__ */ isThenable(result)) {
|
|
5762
|
+
logger.warn("useDragDrop accept predicate returned a thenable; async predicates are not supported — treating as reject");
|
|
5763
|
+
return false;
|
|
5764
|
+
}
|
|
5765
|
+
return Boolean(result);
|
|
5766
|
+
} catch (error) {
|
|
5767
|
+
logger.error("useDragDrop accept predicate threw; treating as reject", error);
|
|
5768
|
+
return false;
|
|
5769
|
+
}
|
|
5770
|
+
}
|
|
5771
|
+
const draggables = {
|
|
5772
|
+
..._draggables,
|
|
5773
|
+
register(registration) {
|
|
5774
|
+
const id = registration.id ?? /* @__PURE__ */ useId$1();
|
|
5775
|
+
const el = toRef(() => toValue(registration.el));
|
|
5776
|
+
const dragging = toRef(() => active.value?.id === id);
|
|
5777
|
+
const input = {
|
|
5778
|
+
...registration,
|
|
5779
|
+
id,
|
|
5780
|
+
el,
|
|
5781
|
+
isDragging: dragging
|
|
5782
|
+
};
|
|
5783
|
+
return _draggables.register(input);
|
|
5784
|
+
}
|
|
5785
|
+
};
|
|
5786
|
+
const zones = {
|
|
5787
|
+
..._zones,
|
|
5788
|
+
register(registration) {
|
|
5789
|
+
const id = registration.id ?? /* @__PURE__ */ useId$1();
|
|
5790
|
+
const el = toRef(() => toValue(registration.el));
|
|
5791
|
+
const isOver = toRef(() => active.value?.over === id);
|
|
5792
|
+
const willAccept = toRef(() => safeAccept(registration.accept, active.value));
|
|
5793
|
+
const rects = shallowRef([]);
|
|
5794
|
+
function refresh() {
|
|
5795
|
+
const zoneEl = el.value;
|
|
5796
|
+
rects.value = zoneEl ? Array.from(zoneEl.children).map((child) => child.getBoundingClientRect()) : [];
|
|
5797
|
+
}
|
|
5798
|
+
const scope = effectScope();
|
|
5799
|
+
scopes.set(id, scope);
|
|
5800
|
+
scope.run(() => {
|
|
5801
|
+
if (registration.orientation) {
|
|
5802
|
+
watch(el, refresh, {
|
|
5803
|
+
immediate: true,
|
|
5804
|
+
flush: "post"
|
|
5805
|
+
});
|
|
5806
|
+
useResizeObserver(el, refresh);
|
|
5807
|
+
useMutationObserver(el, refresh, { childList: true });
|
|
5808
|
+
watch(() => active.value?.id, (id) => {
|
|
5809
|
+
if (id) refresh();
|
|
5810
|
+
});
|
|
5811
|
+
}
|
|
5812
|
+
watch(el, (current) => {
|
|
5813
|
+
if (/* @__PURE__ */ isNull(current)) return;
|
|
5814
|
+
nodes.set(current, id);
|
|
5815
|
+
onWatcherCleanup(() => nodes.delete(current));
|
|
5816
|
+
}, { immediate: true });
|
|
5817
|
+
});
|
|
5818
|
+
const indicator = computed(() => {
|
|
5819
|
+
if (!registration.orientation || !isOver.value || !active.value) return null;
|
|
5820
|
+
return resolveDropPosition(active.value.current, rects.value, registration.orientation);
|
|
5821
|
+
});
|
|
5822
|
+
const input = {
|
|
5823
|
+
...registration,
|
|
5824
|
+
id,
|
|
5825
|
+
el,
|
|
5826
|
+
isOver,
|
|
5827
|
+
willAccept,
|
|
5828
|
+
indicator
|
|
5829
|
+
};
|
|
5830
|
+
return _zones.register(input);
|
|
5831
|
+
}
|
|
5832
|
+
};
|
|
5833
|
+
function at(point) {
|
|
5834
|
+
if (!IN_BROWSER) return null;
|
|
5835
|
+
let element = document.elementFromPoint(point.x, point.y);
|
|
5836
|
+
while (element) {
|
|
5837
|
+
const id = nodes.get(element);
|
|
5838
|
+
if (!/* @__PURE__ */ isUndefined(id)) {
|
|
5839
|
+
const zone = _zones.get(id);
|
|
5840
|
+
if (zone && !toValue(zone.disabled)) return id;
|
|
5841
|
+
}
|
|
5842
|
+
element = element.parentElement;
|
|
5843
|
+
}
|
|
5844
|
+
return null;
|
|
5845
|
+
}
|
|
5846
|
+
function position(zoneId, drag) {
|
|
5847
|
+
const zone = _zones.get(zoneId);
|
|
5848
|
+
const out = { pointer: drag.current };
|
|
5849
|
+
if (zone?.orientation) {
|
|
5850
|
+
const resolved = zone.indicator?.value ?? null;
|
|
5851
|
+
if (resolved) {
|
|
5852
|
+
out.index = resolved.index;
|
|
5853
|
+
out.indicator = resolved;
|
|
5854
|
+
} else out.index = 0;
|
|
5855
|
+
}
|
|
5856
|
+
return out;
|
|
5857
|
+
}
|
|
5858
|
+
function bail(drag, reason = "cancel") {
|
|
5859
|
+
active.value = null;
|
|
5860
|
+
if (!/* @__PURE__ */ isNull(drag.over)) next(_zones.get(drag.over)?.onLeave, drag);
|
|
5861
|
+
next(_draggables.get(drag.id)?.onCancel, drag, reason);
|
|
5862
|
+
next(options.onCancel, drag, reason);
|
|
5863
|
+
}
|
|
5864
|
+
function onStart(source, origin, via) {
|
|
5865
|
+
if (toValue(_draggables.get(source.id)?.disabled)) return;
|
|
5866
|
+
const draft = {
|
|
5867
|
+
id: source.id,
|
|
5868
|
+
type: source.type,
|
|
5869
|
+
value: source.value,
|
|
5870
|
+
origin,
|
|
5871
|
+
current: origin,
|
|
5872
|
+
delta: {
|
|
5873
|
+
x: 0,
|
|
5874
|
+
y: 0
|
|
5875
|
+
},
|
|
5876
|
+
over: null,
|
|
5877
|
+
willAccept: false,
|
|
5878
|
+
via
|
|
5879
|
+
};
|
|
5880
|
+
try {
|
|
5881
|
+
if (_draggables.get(source.id)?.onBeforeStart?.(draft) === false) return;
|
|
5882
|
+
} catch (error) {
|
|
5883
|
+
logger.error("useDragDrop onBeforeStart threw; treating as veto", error);
|
|
5884
|
+
return;
|
|
5885
|
+
}
|
|
5886
|
+
try {
|
|
5887
|
+
if (options.onBeforeStart?.(draft) === false) return;
|
|
5888
|
+
} catch (error) {
|
|
5889
|
+
logger.error("useDragDrop onBeforeStart threw; treating as veto", error);
|
|
5890
|
+
return;
|
|
5891
|
+
}
|
|
5892
|
+
active.value = draft;
|
|
5893
|
+
}
|
|
5894
|
+
function onMove(point) {
|
|
5895
|
+
if (!active.value) return;
|
|
5896
|
+
const over = at(point);
|
|
5897
|
+
const draft = {
|
|
5898
|
+
...active.value,
|
|
5899
|
+
current: point,
|
|
5900
|
+
delta: {
|
|
5901
|
+
x: point.x - active.value.origin.x,
|
|
5902
|
+
y: point.y - active.value.origin.y
|
|
5903
|
+
},
|
|
5904
|
+
over,
|
|
5905
|
+
willAccept: false
|
|
5906
|
+
};
|
|
5907
|
+
draft.willAccept = !/* @__PURE__ */ isNull(over) && safeAccept(_zones.get(over)?.accept, draft);
|
|
5908
|
+
const previous = active.value.over;
|
|
5909
|
+
active.value = draft;
|
|
5910
|
+
if (previous !== over) {
|
|
5911
|
+
if (!/* @__PURE__ */ isNull(previous)) next(_zones.get(previous)?.onLeave, draft);
|
|
5912
|
+
if (!/* @__PURE__ */ isNull(over)) next(_zones.get(over)?.onEnter, draft);
|
|
5913
|
+
}
|
|
5914
|
+
next(_draggables.get(draft.id)?.onMove, draft);
|
|
5915
|
+
next(options.onMove, draft);
|
|
5916
|
+
}
|
|
5917
|
+
function onDrop() {
|
|
5918
|
+
if (!active.value) return;
|
|
5919
|
+
const drag = active.value;
|
|
5920
|
+
const zoneId = drag.over;
|
|
5921
|
+
if (/* @__PURE__ */ isNull(zoneId)) {
|
|
5922
|
+
bail(drag);
|
|
5923
|
+
return;
|
|
5924
|
+
}
|
|
5925
|
+
const dropAt = position(zoneId, drag);
|
|
5926
|
+
const zone = _zones.get(zoneId);
|
|
5927
|
+
function vetoed(fn, label) {
|
|
5928
|
+
if (!fn) return false;
|
|
5929
|
+
try {
|
|
5930
|
+
return fn(drag, dropAt) === false;
|
|
5931
|
+
} catch (error) {
|
|
5932
|
+
logger.error(`useDragDrop ${label} threw; treating as veto`, error);
|
|
5933
|
+
return true;
|
|
5934
|
+
}
|
|
5935
|
+
}
|
|
5936
|
+
if (vetoed(zone?.onBeforeDrop, "zone onBeforeDrop") || vetoed(options.onBeforeDrop, "options onBeforeDrop")) {
|
|
5937
|
+
bail(drag, "reject");
|
|
5938
|
+
return;
|
|
5939
|
+
}
|
|
5940
|
+
active.value = null;
|
|
5941
|
+
next(zone?.onDrop, drag, dropAt);
|
|
5942
|
+
next(options.onDrop, drag, dropAt);
|
|
5943
|
+
}
|
|
5944
|
+
function cancel() {
|
|
5945
|
+
if (!active.value) return;
|
|
5946
|
+
bail(active.value);
|
|
5947
|
+
}
|
|
5948
|
+
const context = {
|
|
5949
|
+
draggables,
|
|
5950
|
+
zones,
|
|
5951
|
+
active: shallowReadonly(active),
|
|
5952
|
+
isDragging,
|
|
5953
|
+
cancel
|
|
5954
|
+
};
|
|
5955
|
+
const disposers = [];
|
|
5956
|
+
const adapters = options.adapters ?? [new PointerAdapter(), new KeyboardAdapter()];
|
|
5957
|
+
const emit = {
|
|
5958
|
+
start: (source, origin, via) => onStart(source, origin, via),
|
|
5959
|
+
move: (point) => onMove(point),
|
|
5960
|
+
drop: () => onDrop(),
|
|
5961
|
+
cancel: () => cancel()
|
|
5962
|
+
};
|
|
5963
|
+
const adapterContext = {
|
|
5964
|
+
...context,
|
|
5965
|
+
emit
|
|
5966
|
+
};
|
|
5967
|
+
for (const adapter of adapters) try {
|
|
5968
|
+
adapter.setup(adapterContext);
|
|
5969
|
+
disposers.push(() => adapter.dispose());
|
|
5970
|
+
} catch (error) {
|
|
5971
|
+
logger.error("useDragDrop adapter setup threw; skipping adapter", error);
|
|
5972
|
+
try {
|
|
5973
|
+
adapter.dispose();
|
|
5974
|
+
} catch (disposeError) {
|
|
5975
|
+
logger.error("useDragDrop adapter dispose threw after setup failure", disposeError);
|
|
5976
|
+
}
|
|
5977
|
+
}
|
|
5978
|
+
for (const plugin of plugins) try {
|
|
5979
|
+
const dispose = plugin(context);
|
|
5980
|
+
if (/* @__PURE__ */ isFunction(dispose)) disposers.push(dispose);
|
|
5981
|
+
} catch (error) {
|
|
5982
|
+
logger.error("useDragDrop plugin install threw; skipping plugin", error);
|
|
5983
|
+
}
|
|
5984
|
+
_draggables.on("unregister:ticket", (ticket) => {
|
|
5985
|
+
if (active.value?.id === ticket.id) cancel();
|
|
5986
|
+
});
|
|
5987
|
+
_zones.on("unregister:ticket", (ticket) => {
|
|
5988
|
+
const scope = scopes.get(ticket.id);
|
|
5989
|
+
if (scope) {
|
|
5990
|
+
scope.stop();
|
|
5991
|
+
scopes.delete(ticket.id);
|
|
5992
|
+
}
|
|
5993
|
+
if (active.value?.over === ticket.id) {
|
|
5994
|
+
next(ticket.onLeave, active.value);
|
|
5995
|
+
active.value = {
|
|
5996
|
+
...active.value,
|
|
5997
|
+
over: null,
|
|
5998
|
+
willAccept: false
|
|
5999
|
+
};
|
|
6000
|
+
}
|
|
6001
|
+
});
|
|
6002
|
+
onScopeDispose(() => {
|
|
6003
|
+
if (!/* @__PURE__ */ isNull(active.value)) cancel();
|
|
6004
|
+
for (const dispose of disposers.toReversed()) try {
|
|
6005
|
+
dispose();
|
|
6006
|
+
} catch (error) {
|
|
6007
|
+
logger.error("useDragDrop disposer threw", error);
|
|
6008
|
+
}
|
|
6009
|
+
for (const scope of scopes.values()) try {
|
|
6010
|
+
scope.stop();
|
|
6011
|
+
} catch (error) {
|
|
6012
|
+
logger.error("useDragDrop zone scope dispose threw", error);
|
|
6013
|
+
}
|
|
6014
|
+
scopes.clear();
|
|
6015
|
+
nodes.clear();
|
|
6016
|
+
try {
|
|
6017
|
+
_draggables.dispose();
|
|
6018
|
+
} catch (error) {
|
|
6019
|
+
logger.error("useDragDrop draggables dispose threw", error);
|
|
6020
|
+
}
|
|
6021
|
+
try {
|
|
6022
|
+
_zones.dispose();
|
|
6023
|
+
} catch (error) {
|
|
6024
|
+
logger.error("useDragDrop zones dispose threw", error);
|
|
6025
|
+
}
|
|
6026
|
+
}, true);
|
|
6027
|
+
return context;
|
|
6028
|
+
}
|
|
6029
|
+
//#endregion
|
|
6030
|
+
//#region src/composables/useHotkey/aliases.ts
|
|
6031
|
+
/**
|
|
6032
|
+
* Key alias mapping for consistent key normalization across the hotkey system.
|
|
6033
|
+
*
|
|
6034
|
+
* Maps user-friendly aliases to canonical key names that match
|
|
6035
|
+
* KeyboardEvent.key values (in lowercase) where possible.
|
|
6036
|
+
*/
|
|
6037
|
+
const keyAliasMap = {
|
|
6038
|
+
control: "ctrl",
|
|
6039
|
+
command: "cmd",
|
|
6040
|
+
option: "alt",
|
|
6041
|
+
up: "arrowup",
|
|
4630
6042
|
down: "arrowdown",
|
|
4631
6043
|
left: "arrowleft",
|
|
4632
6044
|
right: "arrowright",
|
|
@@ -4875,9 +6287,11 @@ function useHotkey(keys, callback, options = {}, _platform) {
|
|
|
4875
6287
|
let isSequence = false;
|
|
4876
6288
|
let groupIndex = 0;
|
|
4877
6289
|
function isInputFocused() {
|
|
6290
|
+
/* v8 ignore next -- IN_BROWSER always true in happy-dom test env */
|
|
4878
6291
|
if (!IN_BROWSER) return false;
|
|
4879
6292
|
if (toValue(inputs)) return false;
|
|
4880
6293
|
const activeElement = document.activeElement;
|
|
6294
|
+
/* v8 ignore next -- defensive: document.activeElement is always set in happy-dom */
|
|
4881
6295
|
if (!activeElement) return false;
|
|
4882
6296
|
const role = activeElement.getAttribute("role");
|
|
4883
6297
|
if (role === "textbox" || role === "searchbox" || role === "combobox" || role === "spinbutton") return true;
|
|
@@ -4931,6 +6345,7 @@ function useHotkey(keys, callback, options = {}, _platform) {
|
|
|
4931
6345
|
const currentKeys = toValue(keys);
|
|
4932
6346
|
if (!currentKeys) return;
|
|
4933
6347
|
const groups = splitKeySequence(currentKeys.toLowerCase());
|
|
6348
|
+
/* v8 ignore next -- defensive: splitKeySequence rejects empty strings earlier */
|
|
4934
6349
|
if (groups.length === 0) return;
|
|
4935
6350
|
isSequence = groups.length > 1;
|
|
4936
6351
|
keyGroups = groups;
|
|
@@ -4983,6 +6398,7 @@ function isModifier(key) {
|
|
|
4983
6398
|
function parseKeyGroup(group) {
|
|
4984
6399
|
const { keys: parts } = splitKeyCombination(group.toLowerCase());
|
|
4985
6400
|
const modifiers = Object.fromEntries(MODIFIERS.map((m) => [m, false]));
|
|
6401
|
+
/* v8 ignore next 3 -- defensive: parseKeyGroup is not invoked with empty parts */
|
|
4986
6402
|
if (parts.length === 0) return {
|
|
4987
6403
|
modifiers,
|
|
4988
6404
|
actualKey: void 0
|
|
@@ -5208,11 +6624,13 @@ function useIntersectionObserver(target, callback, options = {}) {
|
|
|
5208
6624
|
observe: (obs, el) => obs.observe(el),
|
|
5209
6625
|
onEntry: (entries) => {
|
|
5210
6626
|
const latest = entries.at(-1);
|
|
6627
|
+
/* v8 ignore next -- defensive: IntersectionObserver always emits at least one entry */
|
|
5211
6628
|
if (latest) isIntersecting.value = latest.isIntersecting;
|
|
5212
6629
|
},
|
|
5213
6630
|
onPause: () => {
|
|
5214
6631
|
isIntersecting.value = false;
|
|
5215
6632
|
},
|
|
6633
|
+
/* v8 ignore next -- defensive nullish coalesce: entries always populated when shouldStop fires */
|
|
5216
6634
|
shouldStop: (entries) => entries.at(-1)?.isIntersecting ?? false,
|
|
5217
6635
|
immediate: options.immediate ? (el) => {
|
|
5218
6636
|
return [{
|
|
@@ -5262,6 +6680,7 @@ function useElementIntersection(target, options = {}) {
|
|
|
5262
6680
|
const intersectionRatio = shallowRef(0);
|
|
5263
6681
|
const { pause: _pause, resume, stop, isActive, isPaused } = useIntersectionObserver(target, (entries) => {
|
|
5264
6682
|
const entry = entries.at(-1);
|
|
6683
|
+
/* v8 ignore next 4 -- defensive: IntersectionObserver always emits at least one entry */
|
|
5265
6684
|
if (entry) {
|
|
5266
6685
|
isIntersecting.value = entry.isIntersecting;
|
|
5267
6686
|
intersectionRatio.value = entry.intersectionRatio;
|
|
@@ -5511,131 +6930,6 @@ function usePrefersContrast() {
|
|
|
5511
6930
|
return useMediaQuery("(prefers-contrast: more)");
|
|
5512
6931
|
}
|
|
5513
6932
|
//#endregion
|
|
5514
|
-
//#region src/composables/useMutationObserver/index.ts
|
|
5515
|
-
/**
|
|
5516
|
-
* @module useMutationObserver
|
|
5517
|
-
*
|
|
5518
|
-
* @see https://0.vuetifyjs.com/composables/system/use-mutation-observer
|
|
5519
|
-
*
|
|
5520
|
-
* @remarks
|
|
5521
|
-
* MutationObserver composable with lifecycle management.
|
|
5522
|
-
*
|
|
5523
|
-
* Key features:
|
|
5524
|
-
* - MutationObserver API wrapper
|
|
5525
|
-
* - `isActive` reactive flag
|
|
5526
|
-
* - `once` option for single-fire observation
|
|
5527
|
-
* - Pause/resume/stop functionality
|
|
5528
|
-
* - Automatic cleanup on unmount
|
|
5529
|
-
* - SSR-safe (checks SUPPORTS_MUTATION_OBSERVER)
|
|
5530
|
-
* - Hydration-aware
|
|
5531
|
-
* - Configurable observation options (childList, attributes, characterData, etc.)
|
|
5532
|
-
*
|
|
5533
|
-
* Perfect for detecting DOM changes and responding to mutations.
|
|
5534
|
-
*
|
|
5535
|
-
* @example
|
|
5536
|
-
* ```ts
|
|
5537
|
-
* import { useTemplateRef } from 'vue'
|
|
5538
|
-
* import { useMutationObserver } from '@vuetify/v0'
|
|
5539
|
-
*
|
|
5540
|
-
* const target = useTemplateRef('target')
|
|
5541
|
-
* useMutationObserver(target, records => {
|
|
5542
|
-
* console.log(records)
|
|
5543
|
-
* }, { childList: true })
|
|
5544
|
-
* ```
|
|
5545
|
-
*/
|
|
5546
|
-
/**
|
|
5547
|
-
* A composable that uses the Mutation Observer API to detect changes in the DOM.
|
|
5548
|
-
*
|
|
5549
|
-
* @param target The element to observe.
|
|
5550
|
-
* @param callback The callback to execute when a mutation is observed.
|
|
5551
|
-
* @param options The options for the Mutation Observer.
|
|
5552
|
-
* @returns An object with methods to control the observer.
|
|
5553
|
-
*
|
|
5554
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
|
|
5555
|
-
* @see https://0.vuetifyjs.com/composables/system/use-mutation-observer
|
|
5556
|
-
*
|
|
5557
|
-
* @example
|
|
5558
|
-
* ```ts
|
|
5559
|
-
* import { ref } from 'vue'
|
|
5560
|
-
* import { useMutationObserver } from '@vuetify/v0'
|
|
5561
|
-
*
|
|
5562
|
-
* const container = ref<HTMLElement>()
|
|
5563
|
-
*
|
|
5564
|
-
* const { pause, resume, isPaused } = useMutationObserver(
|
|
5565
|
-
* container,
|
|
5566
|
-
* (mutations) => {
|
|
5567
|
-
* mutations.forEach((mutation) => {
|
|
5568
|
-
* if (mutation.type === 'childList') {
|
|
5569
|
-
* console.log('Children changed:', mutation.addedNodes, mutation.removedNodes)
|
|
5570
|
-
* } else if (mutation.type === 'attributes') {
|
|
5571
|
-
* console.log('Attribute changed:', mutation.attributeName)
|
|
5572
|
-
* }
|
|
5573
|
-
* })
|
|
5574
|
-
* },
|
|
5575
|
-
* {
|
|
5576
|
-
* childList: true,
|
|
5577
|
-
* attributes: true,
|
|
5578
|
-
* subtree: true
|
|
5579
|
-
* }
|
|
5580
|
-
* )
|
|
5581
|
-
*
|
|
5582
|
-
* // Pause observation
|
|
5583
|
-
* pause()
|
|
5584
|
-
*
|
|
5585
|
-
* // Resume observation
|
|
5586
|
-
* resume()
|
|
5587
|
-
* ```
|
|
5588
|
-
*/
|
|
5589
|
-
function useMutationObserver(target, callback, options = {}) {
|
|
5590
|
-
const observerOptions = {
|
|
5591
|
-
childList: options.childList ?? true,
|
|
5592
|
-
attributes: options.attributes ?? false,
|
|
5593
|
-
characterData: options.characterData ?? false,
|
|
5594
|
-
subtree: options.subtree ?? false,
|
|
5595
|
-
attributeOldValue: options.attributeOldValue ?? false,
|
|
5596
|
-
characterDataOldValue: options.characterDataOldValue ?? false,
|
|
5597
|
-
attributeFilter: options.attributeFilter
|
|
5598
|
-
};
|
|
5599
|
-
return createObserver(target, callback, {
|
|
5600
|
-
supports: SUPPORTS_MUTATION_OBSERVER,
|
|
5601
|
-
once: options.once,
|
|
5602
|
-
create: (cb) => new MutationObserver((mutations) => {
|
|
5603
|
-
cb(mutations.map((m) => ({
|
|
5604
|
-
type: m.type,
|
|
5605
|
-
target: m.target,
|
|
5606
|
-
addedNodes: m.addedNodes,
|
|
5607
|
-
removedNodes: m.removedNodes,
|
|
5608
|
-
previousSibling: m.previousSibling,
|
|
5609
|
-
nextSibling: m.nextSibling,
|
|
5610
|
-
attributeName: m.attributeName,
|
|
5611
|
-
attributeNamespace: m.attributeNamespace,
|
|
5612
|
-
oldValue: m.oldValue
|
|
5613
|
-
})));
|
|
5614
|
-
}),
|
|
5615
|
-
observe: (obs, el) => obs.observe(el, observerOptions),
|
|
5616
|
-
immediate: options.immediate ? (el) => {
|
|
5617
|
-
const emptyNodeList = {
|
|
5618
|
-
length: 0,
|
|
5619
|
-
item: () => null,
|
|
5620
|
-
forEach: () => {},
|
|
5621
|
-
*[Symbol.iterator]() {}
|
|
5622
|
-
};
|
|
5623
|
-
return [{
|
|
5624
|
-
type: "childList",
|
|
5625
|
-
target: el,
|
|
5626
|
-
addedNodes: emptyNodeList,
|
|
5627
|
-
removedNodes: emptyNodeList,
|
|
5628
|
-
previousSibling: null,
|
|
5629
|
-
nextSibling: null,
|
|
5630
|
-
attributeName: null,
|
|
5631
|
-
attributeNamespace: null,
|
|
5632
|
-
oldValue: null
|
|
5633
|
-
}];
|
|
5634
|
-
} : void 0,
|
|
5635
|
-
onceIncludesImmediate: true
|
|
5636
|
-
});
|
|
5637
|
-
}
|
|
5638
|
-
//#endregion
|
|
5639
6933
|
//#region src/composables/usePresence/index.ts
|
|
5640
6934
|
/**
|
|
5641
6935
|
* @module usePresence
|
|
@@ -6019,8 +7313,11 @@ function useRovingFocus(items, options = {}) {
|
|
|
6019
7313
|
};
|
|
6020
7314
|
}
|
|
6021
7315
|
//#endregion
|
|
7316
|
+
//#region src/composables/useRtl/adapters/adapter.ts
|
|
7317
|
+
var RtlAdapter = class {};
|
|
7318
|
+
//#endregion
|
|
6022
7319
|
//#region src/composables/useRtl/adapters/v0.ts
|
|
6023
|
-
var
|
|
7320
|
+
var V0RtlAdapter = class extends RtlAdapter {
|
|
6024
7321
|
setup(app, context, target) {
|
|
6025
7322
|
if (IN_BROWSER) {
|
|
6026
7323
|
if (/* @__PURE__ */ isNull(target)) return;
|
|
@@ -6088,7 +7385,7 @@ function createRtlFallback() {
|
|
|
6088
7385
|
}
|
|
6089
7386
|
const [createRtlContext, createRtlPlugin, useRtl] = createPluginContext("v0:rtl", (options) => createRtl(options), {
|
|
6090
7387
|
fallback: () => createRtlFallback(),
|
|
6091
|
-
setup: (context, app, { adapter = new
|
|
7388
|
+
setup: (context, app, { adapter = new V0RtlAdapter(), target }) => {
|
|
6092
7389
|
adapter.setup(app, context, target);
|
|
6093
7390
|
},
|
|
6094
7391
|
persist: (ctx) => ctx.isRtl.value,
|
|
@@ -6380,7 +7677,7 @@ function useStack(namespace = "v0:stack") {
|
|
|
6380
7677
|
* ```
|
|
6381
7678
|
*/
|
|
6382
7679
|
function createStorage(options = {}) {
|
|
6383
|
-
const { adapter = IN_BROWSER ? window.localStorage : new
|
|
7680
|
+
const { adapter = IN_BROWSER ? window.localStorage : new MemoryStorageAdapter(), prefix = "v0:", serializer = {
|
|
6384
7681
|
read: JSON.parse,
|
|
6385
7682
|
write: JSON.stringify
|
|
6386
7683
|
}, ttl } = options;
|
|
@@ -6395,9 +7692,9 @@ function createStorage(options = {}) {
|
|
|
6395
7692
|
if (/* @__PURE__ */ isNullOrUndefined(raw)) return void 0;
|
|
6396
7693
|
try {
|
|
6397
7694
|
const parsed = serializer.read(raw);
|
|
6398
|
-
if (
|
|
7695
|
+
if (/* @__PURE__ */ isObject(parsed) && "__v0" in parsed && "__v" in parsed) {
|
|
6399
7696
|
const envelope = parsed;
|
|
6400
|
-
if (Date.now() - envelope.__t > ttl) {
|
|
7697
|
+
if (ttl && Date.now() - envelope.__t > ttl) {
|
|
6401
7698
|
adapter?.removeItem(prefixedKey);
|
|
6402
7699
|
return;
|
|
6403
7700
|
}
|
|
@@ -6477,7 +7774,7 @@ function createStorage(options = {}) {
|
|
|
6477
7774
|
};
|
|
6478
7775
|
}
|
|
6479
7776
|
function createStorageFallback() {
|
|
6480
|
-
return createStorage({ adapter: new
|
|
7777
|
+
return createStorage({ adapter: new MemoryStorageAdapter() });
|
|
6481
7778
|
}
|
|
6482
7779
|
const [createStorageContext, createStoragePlugin, useStorage] = createPluginContext("v0:storage", (options) => createStorage(options), { fallback: () => createStorageFallback() });
|
|
6483
7780
|
//#endregion
|
|
@@ -6824,6 +8121,7 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
6824
8121
|
* Check if an element matches resolved ignore targets.
|
|
6825
8122
|
*/
|
|
6826
8123
|
function isIgnored(el, selectors, elements) {
|
|
8124
|
+
/* v8 ignore next -- defensive guard, callers always pass an Element */
|
|
6827
8125
|
if (!el) return false;
|
|
6828
8126
|
for (const selector of selectors) try {
|
|
6829
8127
|
if (el.matches(selector) || !/* @__PURE__ */ isNull(el.closest(selector))) return true;
|
|
@@ -6850,6 +8148,7 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
6850
8148
|
const targets = getTargets();
|
|
6851
8149
|
if (targets.length === 0) return false;
|
|
6852
8150
|
return targets.every((el) => {
|
|
8151
|
+
/* v8 ignore next -- defensive: getTargets filters to Element-typed values */
|
|
6853
8152
|
if (/* @__PURE__ */ isNullOrUndefined(el) || !/* @__PURE__ */ isFunction(el.contains)) return false;
|
|
6854
8153
|
return el !== eventTarget && !el.contains(eventTarget);
|
|
6855
8154
|
});
|
|
@@ -6859,6 +8158,7 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
6859
8158
|
*/
|
|
6860
8159
|
function isOutsideBounds(x, y) {
|
|
6861
8160
|
const targets = getTargets();
|
|
8161
|
+
/* v8 ignore next -- edge case: bounds check only invoked when targets exist */
|
|
6862
8162
|
if (targets.length === 0) return false;
|
|
6863
8163
|
return targets.every((el) => {
|
|
6864
8164
|
const { left, right, top, bottom } = el.getBoundingClientRect();
|
|
@@ -6869,6 +8169,7 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
6869
8169
|
* Validate that the target is still in the DOM.
|
|
6870
8170
|
*/
|
|
6871
8171
|
function isValidTarget(eventTarget) {
|
|
8172
|
+
/* v8 ignore next -- type guard for non-Element targets (e.g., document, window) */
|
|
6872
8173
|
if (!/* @__PURE__ */ isElement(eventTarget)) return false;
|
|
6873
8174
|
if (!eventTarget.isConnected) return false;
|
|
6874
8175
|
return true;
|
|
@@ -6961,4 +8262,4 @@ function useClickOutside(target, handler, options = {}) {
|
|
|
6961
8262
|
};
|
|
6962
8263
|
}
|
|
6963
8264
|
//#endregion
|
|
6964
|
-
export {
|
|
8265
|
+
export { createTimelineContext as $, useIntersectionObserver as A, createInput as At, createDateContext as B, ComboboxAdapter as Bt, usePresence as C, createNumberField as Ct, usePrefersReducedMotion as D, useNested as Dt, usePrefersDark as E, createNestedContext as Et, PointerAdapter as F, createCombobox as Ft, createBreakpointsPlugin as G, useBreadcrumbs as Gt, useDate as H, usePopover as Ht, DragDropAdapter as I, createComboboxContext as It, toHighlight as J, useBreakpoints as K, useMutationObserver as L, useCombobox as Lt, useHotkey as M, createForm as Mt, useDragDrop as N, createFormContext as Nt, useLazy as O, createKanban as Ot, KeyboardAdapter as P, useForm as Pt, createTimeline as Q, useDelay as R, ServerComboboxAdapter as Rt, useProxyModel as S, createOtp as St, usePrefersContrast as T, createNested as Tt, createBreakpoints as U, createBreadcrumbs as Ut, createDatePlugin as V, useVirtualFocus as Vt, createBreakpointsContext as W, createBreadcrumbsContext as Wt, createVirtualContext as X, createVirtual as Y, useVirtual as Z, createRtlPlugin as _, createFallbackHydration as _t, useToggleScope as a, createRating as at, useRovingFocus as b, createHydrationPlugin as bt, createStoragePlugin as c, createProgress as ct, createStackContext as d, createOverflow as dt, useTimeline as et, createStackPlugin as f, createOverflowContext as ft, createRtlFallback as g, toElement as gt, createRtlContext as h, useResizeObserver as ht, useWindowEventListener as i, createSlider as it, useImage as j, createValidation as jt, useElementIntersection as k, createSortable as kt, useStorage as l, createProgressContext as lt, createRtl as m, useElementSize as mt, useDocumentEventListener as n, createStepContext as nt, createStorage as o, createRatingContext as ot, useStack as p, useOverflow as pt, toReactive as q, useEventListener as r, useStep as rt, createStorageContext as s, useRating as st, useClickOutside as t, createStep as tt, createStack as u, useProgress as ut, useRtl as v, createHydration as vt, useMediaQuery as w, createNumeric as wt, useRaf as x, useHydration as xt, V0RtlAdapter as y, createHydrationContext as yt, createDate as z, ClientComboboxAdapter as zt };
|