@vuetify/v0 0.1.3 → 0.1.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.
Files changed (130) hide show
  1. package/dist/adapter-CJIj5ySf.d.mts +11 -0
  2. package/dist/adapter-Cmeg49W9.mjs +229 -0
  3. package/dist/adapter-D2JoR-4d.d.mts +344 -0
  4. package/dist/adapters-BQ-Lr3PW.mjs +1 -0
  5. package/dist/adapters-DEXpW9If.mjs +1 -0
  6. package/dist/adapters-Q9WaOsJp.mjs +1 -0
  7. package/dist/adapters-SSDVth5e.mjs +1 -0
  8. package/dist/browser/index.js +953 -1026
  9. package/dist/components/index.d.mts +20 -7
  10. package/dist/components/index.mjs +38 -6
  11. package/dist/{components-C0zEvP7w.mjs → components-BbbGkTcN.mjs} +579 -107
  12. package/dist/composables/index.d.mts +17 -4
  13. package/dist/composables/index.mjs +36 -4
  14. package/dist/consola-DiUk9j3y.d.mts +15 -0
  15. package/dist/consola-GBy8XRuL.mjs +31 -0
  16. package/dist/constants/index.d.mts +1 -1
  17. package/dist/constants/index.mjs +3 -3
  18. package/dist/constants-B8pMSkcW.mjs +1 -0
  19. package/dist/createDataTable-cNf6DdHz.mjs +387 -0
  20. package/dist/createGroup-BrZPZudL.mjs +363 -0
  21. package/dist/createPagination-Wc_vRGNQ.mjs +234 -0
  22. package/dist/createSelection-BURpoE3p.mjs +261 -0
  23. package/dist/createSingle-BE1vHaZy.mjs +179 -0
  24. package/dist/createTokens-jwf8-iGn.mjs +682 -0
  25. package/dist/createTrinity-DkwPrPRS.mjs +149 -0
  26. package/dist/data-table/adapters/client/index.d.mts +3 -0
  27. package/dist/data-table/adapters/client/index.mjs +9 -0
  28. package/dist/data-table/adapters/index.d.mts +5 -0
  29. package/dist/data-table/adapters/index.mjs +12 -0
  30. package/dist/data-table/adapters/server/index.d.mts +3 -0
  31. package/dist/data-table/adapters/server/index.mjs +7 -0
  32. package/dist/data-table/adapters/virtual/index.d.mts +3 -0
  33. package/dist/data-table/adapters/virtual/index.mjs +9 -0
  34. package/dist/data-table/index.d.mts +7 -0
  35. package/dist/data-table/index.mjs +25 -0
  36. package/dist/date/index.d.mts +1 -1
  37. package/dist/date/index.mjs +2 -2
  38. package/dist/features/adapters/flagsmith/index.d.mts +16 -0
  39. package/dist/features/adapters/flagsmith/index.mjs +3 -0
  40. package/dist/features/adapters/launchdarkly/index.d.mts +15 -0
  41. package/dist/features/adapters/launchdarkly/index.mjs +3 -0
  42. package/dist/features/adapters/posthog/index.d.mts +15 -0
  43. package/dist/features/adapters/posthog/index.mjs +4 -0
  44. package/dist/features/index.d.mts +17 -0
  45. package/dist/features/index.mjs +18 -0
  46. package/dist/flagsmith-CHmpPGR7.mjs +40 -0
  47. package/dist/{globals-BwYsH-rt.mjs → globals-vN-O052q.mjs} +2 -2
  48. package/dist/index-BDTbJClL.d.mts +11 -0
  49. package/dist/{index-2wh69fk5.d.mts → index-BTMzRHep.d.mts} +187 -1417
  50. package/dist/index-BuOz3Rgm.d.mts +32 -0
  51. package/dist/{index-Bmem4l8m.d.mts → index-Bv1VN_j5.d.mts} +1 -1
  52. package/dist/{index-DFM5iBqh.d.mts → index-DRax9EgT.d.mts} +1044 -437
  53. package/dist/index-DdWxDPX3.d.mts +251 -0
  54. package/dist/{index-DBZTizq2.d.mts → index-UNwEBkQT.d.mts} +16 -2
  55. package/dist/index.d.mts +20 -7
  56. package/dist/index.mjs +39 -7
  57. package/dist/json/attributes.json +172 -0
  58. package/dist/json/importMap.json +28 -0
  59. package/dist/json/tags.json +73 -0
  60. package/dist/json/web-types.json +475 -1
  61. package/dist/launchdarkly-W8t8ZANX.mjs +28 -0
  62. package/dist/locale/adapters/index.d.mts +3 -0
  63. package/dist/locale/adapters/index.mjs +6 -0
  64. package/dist/locale/adapters/v0/index.d.mts +3 -0
  65. package/dist/locale/adapters/v0/index.mjs +5 -0
  66. package/dist/locale/index.d.mts +17 -0
  67. package/dist/locale/index.mjs +17 -0
  68. package/dist/logger/adapters/consola/index.d.mts +3 -0
  69. package/dist/logger/adapters/consola/index.mjs +3 -0
  70. package/dist/logger/adapters/index.d.mts +5 -0
  71. package/dist/logger/adapters/index.mjs +8 -0
  72. package/dist/logger/adapters/pino/index.d.mts +3 -0
  73. package/dist/logger/adapters/pino/index.mjs +5 -0
  74. package/dist/logger/adapters/v0/index.d.mts +3 -0
  75. package/dist/logger/adapters/v0/index.mjs +5 -0
  76. package/dist/logger/index.d.mts +17 -0
  77. package/dist/logger/index.mjs +10 -0
  78. package/dist/memory-BsZGbGnG.mjs +27 -0
  79. package/dist/memory-DVjquu_v.d.mts +25 -0
  80. package/dist/permissions/adapters/index.d.mts +18 -0
  81. package/dist/permissions/adapters/index.mjs +6 -0
  82. package/dist/permissions/adapters/v0/index.d.mts +18 -0
  83. package/dist/permissions/adapters/v0/index.mjs +5 -0
  84. package/dist/permissions/index.d.mts +17 -0
  85. package/dist/permissions/index.mjs +15 -0
  86. package/dist/pino-DFxkZLiu.mjs +49 -0
  87. package/dist/pino-p-jDkNQd.d.mts +24 -0
  88. package/dist/posthog-BOUoZTTf.mjs +50 -0
  89. package/dist/server-B-HWxaTQ.d.mts +20 -0
  90. package/dist/server-C2R2POGE.mjs +45 -0
  91. package/dist/storage/adapters/index.d.mts +3 -0
  92. package/dist/storage/adapters/index.mjs +3 -0
  93. package/dist/storage/adapters/memory/index.d.mts +2 -0
  94. package/dist/storage/adapters/memory/index.mjs +3 -0
  95. package/dist/storage/index.d.mts +17 -0
  96. package/dist/storage/index.mjs +37 -0
  97. package/dist/theme/adapters/index.d.mts +17 -0
  98. package/dist/theme/adapters/index.mjs +6 -0
  99. package/dist/theme/adapters/v0/index.d.mts +17 -0
  100. package/dist/theme/adapters/v0/index.mjs +5 -0
  101. package/dist/theme/index.d.mts +17 -0
  102. package/dist/theme/index.mjs +16 -0
  103. package/dist/toArray-VIn8vYt3.mjs +38 -0
  104. package/dist/types/index.d.mts +1 -1
  105. package/dist/useClickOutside-DIi0kjN5.mjs +4716 -0
  106. package/dist/useFeatures-6O7EPJUS.mjs +122 -0
  107. package/dist/useLocale-DHjbekzS.mjs +85 -0
  108. package/dist/useLogger-BXqiUvt2.mjs +283 -0
  109. package/dist/usePermissions-DFacFVqO.mjs +128 -0
  110. package/dist/useTheme-D0_1mjTw.mjs +135 -0
  111. package/dist/utilities/index.d.mts +3 -3
  112. package/dist/utilities/index.mjs +3 -3
  113. package/dist/{utilities-BbKjbXTx.mjs → utilities-Dx8wzGa5.mjs} +20 -3
  114. package/dist/v0-BNXo1ecc.d.mts +10 -0
  115. package/dist/v0-BOxb3nD1.d.mts +33 -0
  116. package/dist/v0-BPzPP8C5.d.mts +9 -0
  117. package/dist/v0-BYqmw3qM.mjs +21 -0
  118. package/dist/v0-C8DBv9mh.mjs +73 -0
  119. package/dist/v0-CfSj99gF.mjs +37 -0
  120. package/dist/v0-DHMoZ7dS.d.mts +22 -0
  121. package/dist/v0-Dc5mcpQs.mjs +41 -0
  122. package/dist/v0-Dwufx8ae.mjs +83 -0
  123. package/dist/virtual-A4e1yrdn.d.mts +9 -0
  124. package/dist/virtual-BoTGK6HT.mjs +44 -0
  125. package/package.json +34 -2
  126. package/dist/useClickOutside-DrkNYxDe.mjs +0 -8871
  127. /package/dist/{adapter-D95FHAtt.d.mts → adapter-DcwxFryd.d.mts} +0 -0
  128. /package/dist/{constants-DHKqjdjH.mjs → adapters-BGJKsBrw.mjs} +0 -0
  129. /package/dist/{htmlElements-DO9n35bD.mjs → htmlElements-d8iBCGpO.mjs} +0 -0
  130. /package/dist/{index-BLK67J_-.d.mts → index-BFBN5Zl3.d.mts} +0 -0
@@ -0,0 +1,4716 @@
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-vN-O052q.mjs";
2
+ import { a as isElement, c as isNull, g as mergeDeep, h as isUndefined, l as isNullOrUndefined, o as isFunction, p as isString, t as clamp, u as isNumber, v as useId$1, y as instanceExists } from "./utilities-Dx8wzGa5.mjs";
3
+ import { i as useContext, n as createContext, t as createTrinity } from "./createTrinity-DkwPrPRS.mjs";
4
+ import { a as createPlugin, i as useLogger, o as createPluginContext } from "./useLogger-BXqiUvt2.mjs";
5
+ import { i as createRegistry } from "./createTokens-jwf8-iGn.mjs";
6
+ import { t as createSelection } from "./createSelection-BURpoE3p.mjs";
7
+ import { t as createSingle } from "./createSingle-BE1vHaZy.mjs";
8
+ import { t as createGroup } from "./createGroup-BrZPZudL.mjs";
9
+ import { t as toArray } from "./toArray-VIn8vYt3.mjs";
10
+ import { a as useLocale } from "./useLocale-DHjbekzS.mjs";
11
+ import { t as MemoryAdapter } from "./memory-BsZGbGnG.mjs";
12
+ import { computed, effectScope, isRef, nextTick, onScopeDispose, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRaw, toRef, toValue, unref, watch, watchEffect } from "vue";
13
+
14
+ //#region src/composables/createBreadcrumbs/index.ts
15
+ /**
16
+ * @module createBreadcrumbs
17
+ *
18
+ * @remarks
19
+ * Breadcrumb navigation composable built on createSingle.
20
+ *
21
+ * Key features:
22
+ * - Extends createSingle for consistent registry patterns
23
+ * - Navigation methods: first, prev, select (with truncation)
24
+ * - Derived state: depth, isRoot, isEmpty
25
+ * - Trinity pattern for dependency injection
26
+ *
27
+ * Inheritance chain: createRegistry → createSelection → createSingle → createBreadcrumbs
28
+ */
29
+ /**
30
+ * Creates a breadcrumbs navigation model.
31
+ *
32
+ * @param options The options for the breadcrumbs instance.
33
+ * @returns A breadcrumbs context with navigation methods.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * import { createBreadcrumbs } from '@vuetify/v0'
38
+ *
39
+ * const breadcrumbs = createBreadcrumbs()
40
+ *
41
+ * breadcrumbs.register({ text: 'Home' })
42
+ * breadcrumbs.register({ text: 'Products' })
43
+ * breadcrumbs.register({ text: 'Electronics' })
44
+ *
45
+ * // Navigate back
46
+ * breadcrumbs.prev() // removes Electronics
47
+ * breadcrumbs.first() // truncates to Home
48
+ *
49
+ * // Derived state
50
+ * breadcrumbs.depth.value // 1
51
+ * breadcrumbs.isRoot.value // true
52
+ * ```
53
+ */
54
+ function createBreadcrumbs(options = {}) {
55
+ const single = createSingle({
56
+ ...options,
57
+ reactive: true,
58
+ enroll: true
59
+ });
60
+ const depth = toRef(() => single.size);
61
+ const isRoot = toRef(() => depth.value <= 1);
62
+ const isEmpty = toRef(() => depth.value === 0);
63
+ /**
64
+ * Select an item and truncate everything after it.
65
+ */
66
+ function select(id) {
67
+ const ticket = single.get(id);
68
+ if (!ticket) return;
69
+ const index = ticket.index;
70
+ const toRemove = single.values().filter((item) => item.index > index).map((item) => item.id);
71
+ if (toRemove.length > 0) single.offboard(toRemove);
72
+ single.select(id);
73
+ }
74
+ /**
75
+ * Navigate to root (first item).
76
+ */
77
+ function first() {
78
+ const root = single.seek("first");
79
+ if (root) select(root.id);
80
+ }
81
+ /**
82
+ * Navigate up one level (select previous item, removing current).
83
+ */
84
+ function prev() {
85
+ if (single.size <= 1) return;
86
+ const currentIndex = single.selectedIndex.value;
87
+ if (currentIndex <= 0) return;
88
+ const prevId = single.lookup(currentIndex - 1);
89
+ if (prevId) select(prevId);
90
+ }
91
+ return {
92
+ ...single,
93
+ select,
94
+ first,
95
+ prev,
96
+ depth,
97
+ isRoot,
98
+ isEmpty,
99
+ get size() {
100
+ return single.size;
101
+ }
102
+ };
103
+ }
104
+ /**
105
+ * Creates a breadcrumbs context for dependency injection.
106
+ *
107
+ * @param options The options including namespace.
108
+ * @returns A trinity: [useBreadcrumbs, provideBreadcrumbs, defaultContext]
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * const [useBreadcrumbs, provideBreadcrumbs] = createBreadcrumbsContext()
113
+ *
114
+ * // Parent component
115
+ * provideBreadcrumbs()
116
+ *
117
+ * // Child component
118
+ * const breadcrumbs = useBreadcrumbs()
119
+ * breadcrumbs.register({ text: 'Details' })
120
+ * ```
121
+ */
122
+ function createBreadcrumbsContext(_options = {}) {
123
+ const { namespace = "v0:breadcrumbs", ...options } = _options;
124
+ const [useBreadcrumbsContext, _provideBreadcrumbsContext] = createContext(namespace);
125
+ const context = createBreadcrumbs(options);
126
+ function provideBreadcrumbsContext(_context = context, app) {
127
+ return _provideBreadcrumbsContext(_context, app);
128
+ }
129
+ return createTrinity(useBreadcrumbsContext, provideBreadcrumbsContext, context);
130
+ }
131
+ /**
132
+ * Returns the current breadcrumbs instance from context.
133
+ *
134
+ * @param namespace The namespace. @default 'v0:breadcrumbs'
135
+ * @returns The breadcrumbs context.
136
+ *
137
+ * @example
138
+ * ```vue
139
+ * <script setup lang="ts">
140
+ * import { useBreadcrumbs } from '@vuetify/v0'
141
+ *
142
+ * const breadcrumbs = useBreadcrumbs()
143
+ * <\/script>
144
+ *
145
+ * <template>
146
+ * <nav>
147
+ * <template v-for="ticket in breadcrumbs.values()" :key="ticket.id">
148
+ * <a @click="breadcrumbs.select(ticket.id)">{{ ticket.text }}</a>
149
+ * </template>
150
+ * </nav>
151
+ * </template>
152
+ * ```
153
+ */
154
+ function useBreadcrumbs(namespace = "v0:breadcrumbs") {
155
+ return useContext(namespace);
156
+ }
157
+
158
+ //#endregion
159
+ //#region src/composables/useHydration/index.ts
160
+ /**
161
+ * @module useHydration
162
+ *
163
+ * @see https://0.vuetifyjs.com/composables/plugins/use-hydration
164
+ *
165
+ * @remarks
166
+ * SSR hydration state management composable.
167
+ *
168
+ * Key features:
169
+ * - Hydration state detection (browser vs SSR)
170
+ * - Root component detection
171
+ * - Readonly hydration state refs
172
+ * - Plugin installation support
173
+ * - Perfect for hydration-safe rendering
174
+ *
175
+ * Essential for composables that need to behave differently during SSR vs client-side.
176
+ */
177
+ /**
178
+ * Creates a new hydration instance.
179
+ *
180
+ * @returns A new hydration instance.
181
+ *
182
+ * @see https://0.vuetifyjs.com/composables/plugins/use-hydration
183
+ *
184
+ * @example
185
+ * ```ts
186
+ * import { createHydration } from '@vuetify/v0'
187
+ *
188
+ * const hydration = createHydration()
189
+ * console.log(hydration.isHydrated.value) // false
190
+ * hydration.hydrate()
191
+ * console.log(hydration.isHydrated.value) // true
192
+ * ```
193
+ */
194
+ function createHydration() {
195
+ const isHydrated = shallowRef(false);
196
+ const isSettled = shallowRef(false);
197
+ function hydrate() {
198
+ isHydrated.value = true;
199
+ }
200
+ function settle() {
201
+ isSettled.value = true;
202
+ }
203
+ return {
204
+ isHydrated: shallowReadonly(isHydrated),
205
+ isSettled: shallowReadonly(isSettled),
206
+ hydrate,
207
+ settle
208
+ };
209
+ }
210
+ function createFallbackHydration() {
211
+ return {
212
+ isHydrated: shallowReadonly(shallowRef(true)),
213
+ isSettled: shallowReadonly(shallowRef(true)),
214
+ hydrate: () => {},
215
+ settle: () => {}
216
+ };
217
+ }
218
+ /**
219
+ * Creates a new hydration context trinity.
220
+ *
221
+ * @param options Options for creating the hydration context.
222
+ * @template E The type of the hydration context.
223
+ * @returns A new hydration context trinity.
224
+ *
225
+ * @see https://0.vuetifyjs.com/composables/plugins/use-hydration
226
+ *
227
+ * @example
228
+ * ```ts
229
+ * import { createHydrationContext } from '@vuetify/v0'
230
+ *
231
+ * export const [useHydrationContext, provideHydrationContext, context] = createHydrationContext({
232
+ * namespace: 'app:hydration',
233
+ * })
234
+ * ```
235
+ */
236
+ const [createHydrationContext, createHydrationPlugin, useHydration] = createPluginContext("v0:hydration", () => createHydration(), {
237
+ fallback: () => createFallbackHydration(),
238
+ setup: (context, app, _options) => {
239
+ app.mixin({ async mounted() {
240
+ if (!/* @__PURE__ */ isNull(this.$parent)) return;
241
+ context.hydrate();
242
+ await nextTick();
243
+ context.settle();
244
+ } });
245
+ }
246
+ });
247
+
248
+ //#endregion
249
+ //#region src/composables/toElement/index.ts
250
+ /**
251
+ * Resolves a {@link MaybeElementRef} to a DOM Element or undefined.
252
+ *
253
+ * Handles:
254
+ * - `Ref<Element>`, `ShallowRef<HTMLElement>`, getter functions
255
+ * - Vue component instances (extracts `$el`)
256
+ * - Raw DOM elements (pass-through)
257
+ * - null/undefined (returns undefined)
258
+ *
259
+ * @param target The element ref, getter, or raw value to resolve
260
+ * @returns The resolved DOM Element, or undefined if not available
261
+ *
262
+ * @see https://0.vuetifyjs.com/composables/transformers/to-element
263
+ *
264
+ * @example
265
+ * ```ts
266
+ * import { toElement } from '@vuetify/v0'
267
+ *
268
+ * const el = shallowRef<HTMLElement | null>(null)
269
+ * toElement(el) // HTMLElement | undefined
270
+ *
271
+ * const component = ref<ComponentPublicInstance>()
272
+ * toElement(component) // Element | undefined (from $el)
273
+ * ```
274
+ */
275
+ /* @__NO_SIDE_EFFECTS__ */
276
+ function toElement(target) {
277
+ const raw = typeof target === "function" ? target() : target && typeof target === "object" && "value" in target ? target.value : target;
278
+ if (!raw) return void 0;
279
+ if (raw instanceof Element) return raw;
280
+ if ("$el" in raw) return raw.$el;
281
+ }
282
+
283
+ //#endregion
284
+ //#region src/composables/createObserver/index.ts
285
+ /**
286
+ * @module createObserver
287
+ *
288
+ * @remarks
289
+ * Internal factory for browser Observer API composables. Encapsulates the
290
+ * shared lifecycle, hydration, pause/resume/stop, and target-watch logic
291
+ * used by useResizeObserver, useIntersectionObserver, and useMutationObserver.
292
+ *
293
+ * The `observer` ref uses a three-state sentinel:
294
+ * - `undefined` — not yet created
295
+ * - `null` — permanently stopped (`stop()` was called; `setup()` is a no-op)
296
+ * - instance — active observer
297
+ */
298
+ function createObserver(target, userCallback, config) {
299
+ const { isHydrated } = useHydration();
300
+ const resolved = toRef(() => /* @__PURE__ */ toElement(target));
301
+ const observer = shallowRef(void 0);
302
+ const isPaused = shallowRef(false);
303
+ const isActive = toRef(() => !!observer.value);
304
+ function invoke(entries) {
305
+ config.onEntry?.(entries);
306
+ userCallback(entries);
307
+ if (config.once) {
308
+ if (config.shouldStop ? config.shouldStop(entries) : true) stop();
309
+ }
310
+ }
311
+ function setup() {
312
+ if (/* @__PURE__ */ isNull(observer.value)) return;
313
+ const el = resolved.value;
314
+ if (!isHydrated.value || !config.supports || !/* @__PURE__ */ isElement(el) || isPaused.value) return;
315
+ observer.value = config.create(invoke);
316
+ config.observe(observer.value, el);
317
+ if (config.immediate) {
318
+ const entries = config.immediate(el);
319
+ if (config.onceIncludesImmediate) invoke(entries);
320
+ else {
321
+ config.onEntry?.(entries);
322
+ userCallback(entries);
323
+ }
324
+ }
325
+ }
326
+ watch(resolved, (el, oldEl) => {
327
+ if (oldEl || observer.value) cleanup();
328
+ if (isHydrated.value && /* @__PURE__ */ isElement(el)) setup();
329
+ }, { immediate: true });
330
+ let stopHydrationWatch;
331
+ if (!isHydrated.value) stopHydrationWatch = watch(() => isHydrated.value, (hydrated) => {
332
+ if (hydrated && /* @__PURE__ */ isElement(resolved.value) && !observer.value) {
333
+ setup();
334
+ stopHydrationWatch?.();
335
+ stopHydrationWatch = void 0;
336
+ }
337
+ });
338
+ function cleanup() {
339
+ if (observer.value) {
340
+ observer.value.disconnect();
341
+ observer.value = void 0;
342
+ }
343
+ }
344
+ function pause() {
345
+ isPaused.value = true;
346
+ config.onPause?.();
347
+ observer.value?.disconnect();
348
+ }
349
+ function resume() {
350
+ isPaused.value = false;
351
+ setup();
352
+ }
353
+ function stop() {
354
+ stopHydrationWatch?.();
355
+ stopHydrationWatch = void 0;
356
+ cleanup();
357
+ observer.value = null;
358
+ }
359
+ onScopeDispose(stop, true);
360
+ return {
361
+ isActive: shallowReadonly(isActive),
362
+ isPaused: shallowReadonly(isPaused),
363
+ pause,
364
+ resume,
365
+ stop
366
+ };
367
+ }
368
+
369
+ //#endregion
370
+ //#region src/composables/useResizeObserver/index.ts
371
+ /**
372
+ * @module useResizeObserver
373
+ *
374
+ * @remarks
375
+ * ResizeObserver composable with lifecycle management.
376
+ *
377
+ * Key features:
378
+ * - ResizeObserver API wrapper
379
+ * - Pause/resume/stop functionality
380
+ * - Automatic cleanup on unmount
381
+ * - SSR-safe (checks SUPPORTS_OBSERVER)
382
+ * - Hydration-aware
383
+ * - Box model options (content-box/border-box)
384
+ *
385
+ * Perfect for responsive components and size-based rendering.
386
+ */
387
+ /**
388
+ * A composable that uses the Resize Observer API to detect when an element's
389
+ * size changes.
390
+ *
391
+ * @param target The element to observe.
392
+ * @param callback The callback to execute when the element's size changes.
393
+ * @param options The options for the Resize Observer.
394
+ * @returns An object with methods to control the observer.
395
+ *
396
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
397
+ * @see https://0.vuetifyjs.com/composables/system/use-resize-observer
398
+ *
399
+ * @example
400
+ * ```ts
401
+ * import { ref } from 'vue'
402
+ * import { useResizeObserver } from '@vuetify/v0'
403
+ *
404
+ * const el = ref<HTMLElement>()
405
+ * const width = ref(0)
406
+ * const height = ref(0)
407
+ *
408
+ * const { pause, resume, isPaused } = useResizeObserver(
409
+ * el,
410
+ * (entries) => {
411
+ * const entry = entries[0]
412
+ * if (entry) {
413
+ * width.value = entry.contentRect.width
414
+ * height.value = entry.contentRect.height
415
+ * console.log('Size changed:', width.value, 'x', height.value)
416
+ * }
417
+ * },
418
+ * { immediate: true }
419
+ * )
420
+ *
421
+ * // Pause observation
422
+ * pause()
423
+ *
424
+ * // Resume observation
425
+ * resume()
426
+ * ```
427
+ */
428
+ function useResizeObserver(target, callback, options = {}) {
429
+ return createObserver(target, callback, {
430
+ supports: SUPPORTS_OBSERVER,
431
+ once: options.once,
432
+ create: (cb) => new ResizeObserver((entries) => {
433
+ cb(entries.map((e) => ({
434
+ contentRect: {
435
+ width: e.contentRect.width,
436
+ height: e.contentRect.height,
437
+ top: e.contentRect.top,
438
+ left: e.contentRect.left
439
+ },
440
+ target: e.target
441
+ })));
442
+ }),
443
+ observe: (obs, el) => obs.observe(el, { box: options.box ?? "content-box" }),
444
+ immediate: options.immediate ? (el) => {
445
+ const rect = el.getBoundingClientRect();
446
+ return [{
447
+ contentRect: {
448
+ width: rect.width,
449
+ height: rect.height,
450
+ top: rect.top,
451
+ left: rect.left
452
+ },
453
+ target: el
454
+ }];
455
+ } : void 0
456
+ });
457
+ }
458
+ /**
459
+ * A convenience composable that uses the Resize Observer API to track an
460
+ * element's size.
461
+ *
462
+ * @param target The element to observe.
463
+ * @returns An object with the element's width and height.
464
+ *
465
+ * @see https://0.vuetifyjs.com/composables/system/use-resize-observer#use-element-size
466
+ *
467
+ * @example
468
+ * ```ts
469
+ * import { ref, watchEffect } from 'vue'
470
+ * import { useElementSize } from '@vuetify/v0'
471
+ *
472
+ * const box = ref<HTMLElement>()
473
+ * const { width, height } = useElementSize(box)
474
+ *
475
+ * // Width and height are reactive refs
476
+ * watchEffect(() => {
477
+ * console.log('Box size:', width.value, 'x', height.value)
478
+ * })
479
+ * ```
480
+ */
481
+ function useElementSize(target) {
482
+ const width = shallowRef(0);
483
+ const height = shallowRef(0);
484
+ const { pause: _pause, resume, stop, isActive, isPaused } = useResizeObserver(target, (entries) => {
485
+ const entry = entries[0];
486
+ if (entry) {
487
+ width.value = entry.contentRect.width;
488
+ height.value = entry.contentRect.height;
489
+ }
490
+ }, { immediate: true });
491
+ function pause() {
492
+ width.value = 0;
493
+ height.value = 0;
494
+ _pause();
495
+ }
496
+ return {
497
+ width,
498
+ height,
499
+ isActive,
500
+ isPaused: shallowReadonly(isPaused),
501
+ pause,
502
+ resume,
503
+ stop
504
+ };
505
+ }
506
+
507
+ //#endregion
508
+ //#region src/composables/createOverflow/index.ts
509
+ /**
510
+ * @module useOverflow
511
+ *
512
+ * @remarks
513
+ * Composable for computing how many items fit in a container based on available width.
514
+ * Enables responsive truncation logic for Pagination, Breadcrumbs, and similar components.
515
+ *
516
+ * Key features:
517
+ * - Container width tracking via ResizeObserver
518
+ * - Two modes: variable-width (per-item) or uniform-width (sample-based)
519
+ * - Computes capacity (how many items fit)
520
+ * - SSR-safe with Infinity fallback
521
+ * - Supports reserved space for nav buttons, ellipsis, etc.
522
+ *
523
+ * Use variable mode (default) for items with different widths like Breadcrumbs.
524
+ * Use uniform mode (itemWidth option) for same-width items like Pagination buttons.
525
+ */
526
+ /**
527
+ * Creates a new overflow context for computing how many items fit in a container.
528
+ *
529
+ * @param options Configuration options
530
+ * @returns Overflow context with container ref, capacity, and measurement functions
531
+ *
532
+ * @example Variable-width mode (Breadcrumbs)
533
+ * ```vue
534
+ * <script lang="ts" setup>
535
+ * import { useTemplateRef } from 'vue'
536
+ * import { createOverflow } from '@vuetify/v0'
537
+ *
538
+ * const containerRef = useTemplateRef('container')
539
+ * const overflow = createOverflow({
540
+ * container: containerRef,
541
+ * gap: 8,
542
+ * reserved: 40,
543
+ * })
544
+ * <\/script>
545
+ *
546
+ * <template>
547
+ * <div ref="container">
548
+ * <span
549
+ * v-for="(item, i) in items.slice(0, overflow.capacity.value)"
550
+ * :key="i"
551
+ * :ref="el => overflow.measure(i, el)"
552
+ * >
553
+ * {{ item }}
554
+ * </span>
555
+ * <span v-if="overflow.isOverflowing.value">...</span>
556
+ * </div>
557
+ * </template>
558
+ * ```
559
+ *
560
+ * @example Uniform-width mode (Pagination)
561
+ * ```ts
562
+ * const overflow = createOverflow({
563
+ * container: () => atom.value?.element,
564
+ * itemWidth: buttonWidth,
565
+ * reserved: () => buttonWidth.value * 4,
566
+ * })
567
+ * ```
568
+ */
569
+ function createOverflow(options = {}) {
570
+ const { container: _container, gap = 0, reserved = 0, itemWidth, reverse } = options;
571
+ const container = /* @__PURE__ */ isUndefined(_container) ? shallowRef() : toRef(_container);
572
+ const widths = shallowRef(/* @__PURE__ */ new Map());
573
+ const { width } = useElementSize(container);
574
+ function measure(index, el) {
575
+ if (!el) {
576
+ if (widths.value.has(index)) {
577
+ const next = new Map(widths.value);
578
+ next.delete(index);
579
+ widths.value = next;
580
+ }
581
+ return;
582
+ }
583
+ /* v8 ignore start -- browser-only measurement code */
584
+ if (!IN_BROWSER) return;
585
+ const style = getComputedStyle(el);
586
+ const marginX = Number.parseFloat(style.marginLeft) + Number.parseFloat(style.marginRight);
587
+ const w = el.offsetWidth + marginX;
588
+ if (widths.value.get(index) !== w) widths.value = new Map(widths.value).set(index, w);
589
+ /* v8 ignore stop */
590
+ }
591
+ function reset() {
592
+ widths.value = /* @__PURE__ */ new Map();
593
+ }
594
+ const total = computed(() => {
595
+ const g = toValue(gap);
596
+ let sum = 0;
597
+ let count = 0;
598
+ for (const w of widths.value.values()) {
599
+ sum += w + (count > 0 ? g : 0);
600
+ count++;
601
+ }
602
+ return sum;
603
+ });
604
+ return {
605
+ container,
606
+ width,
607
+ capacity: computed(() => {
608
+ const available = width.value - toValue(reserved);
609
+ if (width.value === 0) return Infinity;
610
+ if (available <= 0) return 0;
611
+ const g = toValue(gap);
612
+ const uniformWidth = toValue(itemWidth) ?? 0;
613
+ if (itemWidth !== void 0 && uniformWidth <= 0) return Infinity;
614
+ if (uniformWidth > 0) {
615
+ const subsequent = uniformWidth + g;
616
+ if (available < uniformWidth) return 0;
617
+ return Math.max(1, Math.floor((available - uniformWidth) / subsequent) + 1);
618
+ }
619
+ const entries = [...widths.value.entries()].toSorted((a, b) => a[0] - b[0]);
620
+ if (toValue(reverse)) entries.reverse();
621
+ let sum = 0;
622
+ let count = 0;
623
+ for (const [, w] of entries) {
624
+ const next = sum + w + (count > 0 ? g : 0);
625
+ if (next > available) break;
626
+ sum = next;
627
+ count++;
628
+ }
629
+ return count;
630
+ }),
631
+ total,
632
+ isOverflowing: toRef(() => {
633
+ return total.value > width.value - toValue(reserved);
634
+ }),
635
+ measure,
636
+ reset
637
+ };
638
+ }
639
+ /**
640
+ * Creates an overflow context with dependency injection support.
641
+ *
642
+ * @param options Configuration options including namespace
643
+ * @template E The type of the overflow context
644
+ * @returns Trinity tuple: [useOverflow, provideOverflow, defaultOverflow]
645
+ *
646
+ * @example
647
+ * ```ts
648
+ * // Create injectable context
649
+ * const [useOverflow, provideOverflow, overflow] = createOverflowContext({
650
+ * namespace: 'my-overflow',
651
+ * gap: 8,
652
+ * reserved: 160,
653
+ * })
654
+ *
655
+ * // In parent component
656
+ * provideOverflow()
657
+ *
658
+ * // In child component
659
+ * const overflow = useOverflow()
660
+ * ```
661
+ */
662
+ function createOverflowContext(_options = {}) {
663
+ const { namespace = "v0:overflow", ...options } = _options;
664
+ const [useOverflowContext, _provideOverflowContext] = createContext(namespace);
665
+ const context = createOverflow(options);
666
+ function provideOverflowContext(_context = context, app) {
667
+ return _provideOverflowContext(_context, app);
668
+ }
669
+ return createTrinity(useOverflowContext, provideOverflowContext, context);
670
+ }
671
+ /**
672
+ * Returns the current overflow context from dependency injection.
673
+ *
674
+ * @param namespace The namespace for the overflow context. Defaults to `v0:overflow`.
675
+ * @template E The type of the overflow context
676
+ * @returns The current overflow context.
677
+ *
678
+ * @throws An error if the overflow context is not found and no default is provided.
679
+ *
680
+ * @example
681
+ * ```vue
682
+ * <script lang="ts" setup>
683
+ * import { useOverflow } from '@vuetify/v0'
684
+ *
685
+ * // Inject overflow context provided by parent
686
+ * const overflow = useOverflow()
687
+ * <\/script>
688
+ *
689
+ * <template>
690
+ * <div>
691
+ * <p>Capacity: {{ overflow.capacity.value }}</p>
692
+ * </div>
693
+ * </template>
694
+ * ```
695
+ */
696
+ function useOverflow(namespace = "v0:overflow") {
697
+ return useContext(namespace);
698
+ }
699
+
700
+ //#endregion
701
+ //#region src/composables/useProxyModel/index.ts
702
+ /**
703
+ * @module useProxyModel
704
+ *
705
+ * @remarks
706
+ * Proxy composable for bidirectional sync between selection registry and v-model.
707
+ *
708
+ * Key features:
709
+ * - Bidirectional synchronization
710
+ * - Array and single-value modes
711
+ * - Automatic cleanup on scope disposal
712
+ * - Perfect for form controls with selection backing
713
+ *
714
+ * Bridges the gap between selection composables and Vue's v-model.
715
+ */
716
+ /**
717
+ * Syncs a ref with a selection registry bidirectionally.
718
+ *
719
+ * @param registry The selection registry to bind to.
720
+ * @param model The ref to sync.
721
+ * @param options The options for the proxy model.
722
+ * @template Z The type of the selection ticket.
723
+ * @returns A function to stop the sync.
724
+ *
725
+ * @see https://0.vuetifyjs.com/composables/forms/use-proxy-model
726
+ *
727
+ * @example
728
+ * ```ts
729
+ * import { createSelection, useProxyModel } from '@vuetify/v0'
730
+ *
731
+ * const model = ref()
732
+ * const registry = createSelection({ events: true })
733
+ * registry.onboard([
734
+ * { id: 'item-1', value: 'Item 1' },
735
+ * { id: 'item-2', value: 'Item 2' },
736
+ * ])
737
+ *
738
+ * const stop = useProxyModel(registry, model)
739
+ * ```
740
+ */
741
+ function useProxyModel(registry, model, options) {
742
+ const multiple = options?.multiple ?? false;
743
+ const _transformIn = options?.transformIn;
744
+ const _transformOut = options?.transformOut;
745
+ function transformIn(val) {
746
+ const value = toValue(val);
747
+ return toArray(/* @__PURE__ */ isFunction(_transformIn) ? _transformIn(value) : value);
748
+ }
749
+ function transformOut(val) {
750
+ if (/* @__PURE__ */ isFunction(_transformOut)) return _transformOut(val);
751
+ return toValue(multiple) ? val : val[0];
752
+ }
753
+ const modelAsArray = transformIn(model);
754
+ const pending = new Set(modelAsArray);
755
+ for (const value of modelAsArray) {
756
+ const ids = registry.browse(value);
757
+ /* v8 ignore start -- edge case: value exists in registry at init */
758
+ if (ids) {
759
+ for (const id of ids) registry.select(id);
760
+ pending.delete(value);
761
+ }
762
+ }
763
+ const registryWatch = watch(registry.selectedValues, (val) => {
764
+ modelWatch.pause();
765
+ model.value = transformOut(Array.from(toValue(val)));
766
+ modelWatch.resume();
767
+ }, { flush: "sync" });
768
+ const modelWatch = watch(model, (val) => {
769
+ registryWatch.pause();
770
+ const currentIds = new Set(toValue(registry.selectedIds));
771
+ const targetIds = /* @__PURE__ */ new Set();
772
+ for (const value of transformIn(val)) {
773
+ const ids = registry.browse(toRaw(value));
774
+ if (ids) for (const id of ids) targetIds.add(id);
775
+ }
776
+ if (toValue(multiple)) {
777
+ for (const id of currentIds.difference(targetIds)) registry.selectedIds.delete(id);
778
+ for (const id of targetIds.difference(currentIds)) registry.selectedIds.add(id);
779
+ } else {
780
+ const next = targetIds.values().next().value;
781
+ const last = currentIds.values().next().value;
782
+ if (!/* @__PURE__ */ isUndefined(last)) registry.unselect(last);
783
+ if (!/* @__PURE__ */ isUndefined(next)) registry.select(next);
784
+ }
785
+ registryWatch.resume();
786
+ }, {
787
+ flush: "sync",
788
+ deep: toValue(multiple)
789
+ });
790
+ function onRegister(data) {
791
+ const ticket = data;
792
+ if (!pending.has(ticket.value) || toValue(ticket.disabled)) return;
793
+ registryWatch.pause();
794
+ modelWatch.pause();
795
+ registry.select(ticket.id);
796
+ pending.delete(ticket.value);
797
+ modelWatch.resume();
798
+ registryWatch.resume();
799
+ }
800
+ registry.on("register:ticket", onRegister);
801
+ function stop() {
802
+ registryWatch();
803
+ modelWatch();
804
+ registry.off("register:ticket", onRegister);
805
+ }
806
+ onScopeDispose(stop, true);
807
+ return stop;
808
+ }
809
+
810
+ //#endregion
811
+ //#region src/composables/toReactive/index.ts
812
+ /**
813
+ * @module toReactive
814
+ *
815
+ * @remarks
816
+ * Utility function to convert values and refs into reactive proxies with ref unwrapping.
817
+ *
818
+ * Key features:
819
+ * - Automatic ref unwrapping
820
+ * - Deep reactive proxying
821
+ * - Map and Set support with ref unwrapping
822
+ * - Nested object/array reactivity
823
+ * - Type preservation
824
+ *
825
+ * Perfect for creating reactive versions of plain objects while automatically unwrapping refs.
826
+ */
827
+ /**
828
+ * Converts a `MaybeRef` to a `UnwrapNestedRefs`.
829
+ *
830
+ * @param objectRef The object to convert.
831
+ * @template Z The type of the object.
832
+ * @returns The converted object.
833
+ *
834
+ * @see https://0.vuetifyjs.com/composables/transformers/to-reactive
835
+ *
836
+ * @example
837
+ * ```ts
838
+ * import { ref } from 'vue'
839
+ * import { toReactive } from '@vuetify/v0'
840
+ *
841
+ * const state = ref({ name: 'John', age: 30 })
842
+ * const rstate = toReactive(state)
843
+ *
844
+ * console.log(rstate.name) // John
845
+ * ```
846
+ */
847
+ function toReactive(objectRef) {
848
+ if (!isRef(objectRef)) return reactive(objectRef);
849
+ const target = objectRef.value;
850
+ if (target instanceof Map) {
851
+ const mapProxy = new Proxy(/* @__PURE__ */ new Map(), { get(_, p) {
852
+ const map = objectRef.value;
853
+ if (p === "get") return (key) => unref(map.get(key));
854
+ if (p === "set") return (key, value) => {
855
+ const existingValue = map.get(key);
856
+ if (isRef(existingValue)) existingValue.value = unref(value);
857
+ else map.set(key, value);
858
+ return mapProxy;
859
+ };
860
+ if (p === "has") return (key) => map.has(key);
861
+ if (p === "delete") return (key) => map.delete(key);
862
+ if (p === "clear") return () => map.clear();
863
+ if (p === "size") return map.size;
864
+ if (p === "keys") return () => map.keys();
865
+ if (p === "values") return function* () {
866
+ for (const value of map.values()) yield unref(value);
867
+ };
868
+ if (p === "entries") return function* () {
869
+ for (const [key, value] of map.entries()) yield [key, unref(value)];
870
+ };
871
+ if (p === "forEach") return (callback, thisArg) => {
872
+ for (const [key, value] of map.entries()) callback.call(thisArg, unref(value), key, mapProxy);
873
+ };
874
+ if (p === Symbol.iterator) return function* () {
875
+ for (const [key, value] of map.entries()) yield [key, unref(value)];
876
+ };
877
+ return Reflect.get(map, p);
878
+ } });
879
+ return reactive(mapProxy);
880
+ }
881
+ if (target instanceof Set) {
882
+ const setProxy = new Proxy(/* @__PURE__ */ new Set(), { get(_, p) {
883
+ const set = objectRef.value;
884
+ if (p === "add") return (value) => {
885
+ set.add(value);
886
+ return setProxy;
887
+ };
888
+ if (p === "has") return (value) => set.has(value);
889
+ if (p === "delete") return (value) => set.delete(value);
890
+ if (p === "clear") return () => set.clear();
891
+ if (p === "size") return set.size;
892
+ if (p === "keys" || p === "values") return function* () {
893
+ for (const value of set.values()) yield unref(value);
894
+ };
895
+ if (p === "entries") return function* () {
896
+ for (const value of set.values()) {
897
+ const unreffedValue = unref(value);
898
+ yield [unreffedValue, unreffedValue];
899
+ }
900
+ };
901
+ if (p === "forEach") return (callback, thisArg) => {
902
+ for (const value of set) {
903
+ const unreffedValue = unref(value);
904
+ callback.call(thisArg, unreffedValue, unreffedValue, setProxy);
905
+ }
906
+ };
907
+ if (p === Symbol.iterator) return function* () {
908
+ for (const value of set.values()) yield unref(value);
909
+ };
910
+ return Reflect.get(set, p);
911
+ } });
912
+ return reactive(setProxy);
913
+ }
914
+ return reactive(new Proxy({}, {
915
+ get(_, p, receiver) {
916
+ return unref(Reflect.get(objectRef.value, p, receiver));
917
+ },
918
+ set(_, p, value) {
919
+ const currentTarget = objectRef.value;
920
+ currentTarget[p] = value;
921
+ return true;
922
+ },
923
+ deleteProperty(_, p) {
924
+ return Reflect.deleteProperty(objectRef.value, p);
925
+ },
926
+ has(_, p) {
927
+ return Reflect.has(objectRef.value, p);
928
+ },
929
+ ownKeys() {
930
+ return Object.keys(objectRef.value);
931
+ },
932
+ getOwnPropertyDescriptor(_, p) {
933
+ const desc = Reflect.getOwnPropertyDescriptor(objectRef.value, p);
934
+ if (!desc) return;
935
+ const newDesc = {
936
+ ...desc,
937
+ configurable: true
938
+ };
939
+ if ("value" in newDesc) newDesc.value = unref(newDesc.value);
940
+ return newDesc;
941
+ }
942
+ }));
943
+ }
944
+
945
+ //#endregion
946
+ //#region src/composables/useBreakpoints/index.ts
947
+ /**
948
+ * @module useBreakpoints
949
+ *
950
+ * @see https://0.vuetifyjs.com/composables/plugins/use-breakpoints
951
+ *
952
+ * @remarks
953
+ * Responsive breakpoint detection composable with window resize handling.
954
+ *
955
+ * Key features:
956
+ * - Window matchMedia integration
957
+ * - Six built-in breakpoints (xs, sm, md, lg, xl, xxl)
958
+ * - Automatic resize listener with cleanup
959
+ * - SSR-safe (checks IN_BROWSER)
960
+ * - Hydration-aware
961
+ * - Custom breakpoint configuration
962
+ *
963
+ * Perfect for responsive layouts and conditional rendering based on screen size.
964
+ */
965
+ /**
966
+ * Creates default breakpoint configuration.
967
+ *
968
+ * @returns The default breakpoint configuration object.
969
+ */
970
+ function createDefaultBreakpoints() {
971
+ return {
972
+ mobileBreakpoint: "lg",
973
+ breakpoints: {
974
+ xs: 0,
975
+ sm: 600,
976
+ md: 840,
977
+ lg: 1145,
978
+ xl: 1545,
979
+ xxl: 2138
980
+ }
981
+ };
982
+ }
983
+ /**
984
+ * Creates a new breakpoints instance.
985
+ *
986
+ * @param options The options for the breakpoints instance.
987
+ * @template E The type of the breakpoints context.
988
+ * @returns A new breakpoints instance.
989
+ *
990
+ * @see https://0.vuetifyjs.com/composables/plugins/use-breakpoints
991
+ *
992
+ * @example
993
+ * ```ts
994
+ * import { createBreakpoints } from '@vuetify/v0'
995
+ *
996
+ * export const [useBreakpoints, provideBreakpoints] = createBreakpoints({
997
+ * namespace: 'v0:breakpoints',
998
+ * mobileBreakpoint: 'md',
999
+ * breakpoints: {
1000
+ * xs: 0,
1001
+ * sm: 600,
1002
+ * md: 840,
1003
+ * lg: 1145,
1004
+ * xl: 1545,
1005
+ * xxl: 2138,
1006
+ * },
1007
+ * })
1008
+ * ```
1009
+ */
1010
+ function createBreakpoints(_options = {}) {
1011
+ const { mobileBreakpoint, breakpoints } = /* @__PURE__ */ mergeDeep(createDefaultBreakpoints(), _options);
1012
+ const sorted = Object.entries(breakpoints).toSorted((a, b) => a[1] - b[1]);
1013
+ const names = sorted.map(([n]) => n);
1014
+ const mb = /* @__PURE__ */ isNumber(mobileBreakpoint) ? mobileBreakpoint : breakpoints[mobileBreakpoint] ?? breakpoints.md;
1015
+ const name = shallowRef("xs");
1016
+ const width = shallowRef(0);
1017
+ const height = shallowRef(0);
1018
+ const isMobile = shallowRef(true);
1019
+ const xs = shallowRef(true);
1020
+ const sm = shallowRef(false);
1021
+ const md = shallowRef(false);
1022
+ const lg = shallowRef(false);
1023
+ const xl = shallowRef(false);
1024
+ const xxl = shallowRef(false);
1025
+ const smAndUp = shallowRef(false);
1026
+ const mdAndUp = shallowRef(false);
1027
+ const lgAndUp = shallowRef(false);
1028
+ const xlAndUp = shallowRef(false);
1029
+ const xxlAndUp = shallowRef(false);
1030
+ const smAndDown = shallowRef(true);
1031
+ const mdAndDown = shallowRef(true);
1032
+ const lgAndDown = shallowRef(true);
1033
+ const xlAndDown = shallowRef(true);
1034
+ const xxlAndDown = shallowRef(true);
1035
+ function update() {
1036
+ if (!IN_BROWSER) return;
1037
+ width.value = window.innerWidth;
1038
+ height.value = window.innerHeight;
1039
+ let current = "xs";
1040
+ for (let i = sorted.length - 1; i >= 0; i--) if (width.value >= sorted[i][1]) {
1041
+ current = sorted[i][0];
1042
+ break;
1043
+ }
1044
+ name.value = current;
1045
+ const index = names.indexOf(current);
1046
+ isMobile.value = width.value < mb;
1047
+ xs.value = index === 0;
1048
+ sm.value = index === 1;
1049
+ md.value = index === 2;
1050
+ lg.value = index === 3;
1051
+ xl.value = index === 4;
1052
+ xxl.value = index === 5;
1053
+ smAndUp.value = index >= 1;
1054
+ mdAndUp.value = index >= 2;
1055
+ lgAndUp.value = index >= 3;
1056
+ xlAndUp.value = index >= 4;
1057
+ xxlAndUp.value = index >= 5;
1058
+ smAndDown.value = index <= 1;
1059
+ mdAndDown.value = index <= 2;
1060
+ lgAndDown.value = index <= 3;
1061
+ xlAndDown.value = index <= 4;
1062
+ xxlAndDown.value = index <= 5;
1063
+ }
1064
+ return {
1065
+ breakpoints,
1066
+ name: readonly(name),
1067
+ width: readonly(width),
1068
+ height: readonly(height),
1069
+ isMobile: readonly(isMobile),
1070
+ xs: readonly(xs),
1071
+ sm: readonly(sm),
1072
+ md: readonly(md),
1073
+ lg: readonly(lg),
1074
+ xl: readonly(xl),
1075
+ xxl: readonly(xxl),
1076
+ smAndUp: readonly(smAndUp),
1077
+ mdAndUp: readonly(mdAndUp),
1078
+ lgAndUp: readonly(lgAndUp),
1079
+ xlAndUp: readonly(xlAndUp),
1080
+ xxlAndUp: readonly(xxlAndUp),
1081
+ smAndDown: readonly(smAndDown),
1082
+ mdAndDown: readonly(mdAndDown),
1083
+ lgAndDown: readonly(lgAndDown),
1084
+ xlAndDown: readonly(xlAndDown),
1085
+ xxlAndDown: readonly(xxlAndDown),
1086
+ update
1087
+ };
1088
+ }
1089
+ function createBreakpointsFallback() {
1090
+ return {
1091
+ breakpoints: createDefaultBreakpoints().breakpoints,
1092
+ name: readonly(shallowRef("xs")),
1093
+ width: readonly(shallowRef(0)),
1094
+ height: readonly(shallowRef(0)),
1095
+ isMobile: readonly(shallowRef(false)),
1096
+ xs: readonly(shallowRef(false)),
1097
+ sm: readonly(shallowRef(false)),
1098
+ md: readonly(shallowRef(false)),
1099
+ lg: readonly(shallowRef(false)),
1100
+ xl: readonly(shallowRef(false)),
1101
+ xxl: readonly(shallowRef(false)),
1102
+ smAndUp: readonly(shallowRef(false)),
1103
+ mdAndUp: readonly(shallowRef(false)),
1104
+ lgAndUp: readonly(shallowRef(false)),
1105
+ xlAndUp: readonly(shallowRef(false)),
1106
+ xxlAndUp: readonly(shallowRef(false)),
1107
+ smAndDown: readonly(shallowRef(false)),
1108
+ mdAndDown: readonly(shallowRef(false)),
1109
+ lgAndDown: readonly(shallowRef(false)),
1110
+ xlAndDown: readonly(shallowRef(false)),
1111
+ xxlAndDown: readonly(shallowRef(false)),
1112
+ update: () => {}
1113
+ };
1114
+ }
1115
+ const [createBreakpointsContext, createBreakpointsPlugin, useBreakpoints] = createPluginContext("v0:breakpoints", (options) => createBreakpoints(options), {
1116
+ fallback: () => createBreakpointsFallback(),
1117
+ setup: (context, app, _options) => {
1118
+ app.mixin({ mounted() {
1119
+ if (!/* @__PURE__ */ isNull(this.$parent)) return;
1120
+ const hydration = useHydration();
1121
+ function listener() {
1122
+ context.update();
1123
+ }
1124
+ const unwatch = watch(hydration.isHydrated, (hydrated) => {
1125
+ if (hydrated) listener();
1126
+ }, { immediate: true });
1127
+ const cleanup = useWindowEventListener("resize", listener, { passive: true });
1128
+ onScopeDispose(() => {
1129
+ cleanup();
1130
+ unwatch();
1131
+ }, true);
1132
+ } });
1133
+ }
1134
+ });
1135
+
1136
+ //#endregion
1137
+ //#region src/composables/useDate/index.ts
1138
+ /**
1139
+ * @module useDate
1140
+ *
1141
+ * @remarks
1142
+ * Date manipulation composable with adapter pattern for date operations.
1143
+ *
1144
+ * Key features:
1145
+ * - Adapter pattern for date library abstraction
1146
+ * - Locale-aware formatting via Intl.DateTimeFormat
1147
+ * - Integration with useLocale for automatic locale sync
1148
+ *
1149
+ * @example Using the built-in Temporal adapter
1150
+ * ```ts
1151
+ * import { Vuetify0DateAdapter } from '@vuetify/v0/date'
1152
+ * import { createDatePlugin } from '@vuetify/v0'
1153
+ *
1154
+ * const app = createApp(App)
1155
+ * app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))
1156
+ *
1157
+ * // In a component:
1158
+ * const { adapter } = useDate()
1159
+ * const today = adapter.date()
1160
+ * const formatted = adapter.format(today, 'fullDate')
1161
+ * ```
1162
+ *
1163
+ * @example Custom adapter
1164
+ * ```ts
1165
+ * import type { DateAdapter } from '@vuetify/v0'
1166
+ *
1167
+ * class DateFnsAdapter implements DateAdapter<Date> {
1168
+ * // ... implementation
1169
+ * }
1170
+ *
1171
+ * app.use(createDatePlugin({ adapter: new DateFnsAdapter() }))
1172
+ * ```
1173
+ */
1174
+ /**
1175
+ * Default short locale codes mapped to full Intl locale strings.
1176
+ * Used when useLocale provides a short code without region (e.g., 'en' instead of 'en-US').
1177
+ */
1178
+ const defaultLocales = {
1179
+ en: "en-US",
1180
+ es: "es-ES",
1181
+ fr: "fr-FR",
1182
+ de: "de-DE",
1183
+ it: "it-IT",
1184
+ pt: "pt-BR",
1185
+ ja: "ja-JP",
1186
+ ko: "ko-KR",
1187
+ zh: "zh-CN",
1188
+ ru: "ru-RU",
1189
+ ar: "ar-SA"
1190
+ };
1191
+ /**
1192
+ * Creates a new date context.
1193
+ *
1194
+ * @param options Adapter and locale configuration.
1195
+ * @template Z The date type used by the adapter.
1196
+ * @template E The date context type.
1197
+ * @returns A date context.
1198
+ *
1199
+ * @see https://0.vuetifyjs.com/composables/plugins/use-date
1200
+ *
1201
+ * @example
1202
+ * ```ts
1203
+ * import { Vuetify0DateAdapter } from '@vuetify/v0/date'
1204
+ *
1205
+ * const { adapter } = createDate({ adapter: new Vuetify0DateAdapter() })
1206
+ * const today = adapter.date()
1207
+ *
1208
+ * // With locale options
1209
+ * const { adapter } = createDate({
1210
+ * adapter: new Vuetify0DateAdapter(),
1211
+ * locale: 'de-DE',
1212
+ * })
1213
+ * ```
1214
+ */
1215
+ function createDate(options) {
1216
+ const { locales = defaultLocales, adapter, locale: initialLocale } = options;
1217
+ let selectedId;
1218
+ try {
1219
+ if (instanceExists()) selectedId = useLocale().selectedId;
1220
+ } catch {}
1221
+ const locale = computed(() => {
1222
+ const selected = selectedId?.value;
1223
+ if (!/* @__PURE__ */ isNullOrUndefined(selected)) {
1224
+ const str = String(selected);
1225
+ return str.includes("-") ? str : locales[str] ?? str;
1226
+ }
1227
+ const fallback = initialLocale ?? adapter.locale ?? "en-US";
1228
+ return fallback.includes("-") ? fallback : locales[fallback] ?? fallback;
1229
+ });
1230
+ if (instanceExists()) onScopeDispose(watchEffect(() => {
1231
+ const loc = locale.value;
1232
+ if (loc && adapter.locale !== loc) adapter.locale = loc;
1233
+ }));
1234
+ else {
1235
+ const loc = locale.value;
1236
+ if (loc && adapter.locale !== loc) adapter.locale = loc;
1237
+ }
1238
+ return {
1239
+ adapter,
1240
+ locale
1241
+ };
1242
+ }
1243
+ /**
1244
+ * Creates a new date context trinity.
1245
+ *
1246
+ * @param options Adapter, locale, and namespace configuration.
1247
+ * @template Z The date type used by the adapter.
1248
+ * @template E The date context type.
1249
+ * @returns A trinity [useContext, provideContext, defaultContext].
1250
+ *
1251
+ * @see https://0.vuetifyjs.com/composables/plugins/use-date
1252
+ *
1253
+ * @example
1254
+ * ```ts
1255
+ * import { Vuetify0DateAdapter } from '@vuetify/v0/date'
1256
+ *
1257
+ * const [useAppDate, provideAppDate] = createDateContext({
1258
+ * adapter: new Vuetify0DateAdapter(),
1259
+ * namespace: 'app:date',
1260
+ * })
1261
+ * ```
1262
+ */
1263
+ function createDateContext(options) {
1264
+ const { namespace = "v0:date", ...dateOptions } = options;
1265
+ const [useDateContext, _provideDateContext] = createContext(namespace);
1266
+ const context = createDate(dateOptions);
1267
+ function provideDateContext(_context = context, app) {
1268
+ return _provideDateContext(_context, app);
1269
+ }
1270
+ return createTrinity(useDateContext, provideDateContext, context);
1271
+ }
1272
+ /**
1273
+ * Creates a new date plugin.
1274
+ *
1275
+ * @param options Adapter, locale, and namespace configuration.
1276
+ * @template Z The date type used by the adapter.
1277
+ * @template E The date context type.
1278
+ * @returns A Vue plugin.
1279
+ *
1280
+ * @see https://0.vuetifyjs.com/composables/plugins/use-date
1281
+ *
1282
+ * @example
1283
+ * ```ts
1284
+ * import { Vuetify0DateAdapter } from '@vuetify/v0/date'
1285
+ *
1286
+ * const app = createApp(App)
1287
+ * app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))
1288
+ *
1289
+ * // With locale options
1290
+ * app.use(createDatePlugin({
1291
+ * adapter: new Vuetify0DateAdapter(),
1292
+ * locale: 'de-DE',
1293
+ * }))
1294
+ * ```
1295
+ */
1296
+ function createDatePlugin(options) {
1297
+ const { namespace = "v0:date", ...dateOptions } = options;
1298
+ const [, provideDateContext, context] = createDateContext({
1299
+ namespace,
1300
+ ...dateOptions
1301
+ });
1302
+ return createPlugin({
1303
+ namespace,
1304
+ provide: (app) => {
1305
+ provideDateContext(context, app);
1306
+ }
1307
+ });
1308
+ }
1309
+ /**
1310
+ * Returns the current date context.
1311
+ *
1312
+ * Requires `createDatePlugin` to be installed with an adapter.
1313
+ *
1314
+ * @param namespace The namespace to look up (defaults to 'v0:date').
1315
+ * @template Z The date type used by the adapter.
1316
+ * @template E The date context type.
1317
+ * @returns The current date context.
1318
+ * @throws If called outside a component or without a date plugin installed.
1319
+ *
1320
+ * @see https://0.vuetifyjs.com/composables/plugins/use-date
1321
+ *
1322
+ * @example
1323
+ * ```ts
1324
+ * // main.ts
1325
+ * import { Vuetify0DateAdapter } from '@vuetify/v0/date'
1326
+ * import { createDatePlugin } from '@vuetify/v0'
1327
+ *
1328
+ * app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))
1329
+ * ```
1330
+ *
1331
+ * @example
1332
+ * ```vue
1333
+ * <script setup lang="ts">
1334
+ * import { useDate } from '@vuetify/v0'
1335
+ *
1336
+ * const { adapter, locale } = useDate()
1337
+ * const today = adapter.date()
1338
+ * <\/script>
1339
+ * ```
1340
+ */
1341
+ function useDate(namespace = "v0:date") {
1342
+ if (!instanceExists()) throw new Error("[v0] useDate() must be called inside a Vue component with createDatePlugin installed.\n\nExample:\n import { Vuetify0DateAdapter } from '@vuetify/v0/date'\n import { createDatePlugin } from '@vuetify/v0'\n\n app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))");
1343
+ return useContext(namespace);
1344
+ }
1345
+
1346
+ //#endregion
1347
+ //#region src/composables/createForm/index.ts
1348
+ /**
1349
+ * @module createForm
1350
+ *
1351
+ * @remarks
1352
+ * Form validation composable with async rule support and multiple validation modes.
1353
+ *
1354
+ * Key features:
1355
+ * - Sync and async validation rules
1356
+ * - Multiple validation modes (submit, change, combined)
1357
+ * - Tri-state isValid (null/true/false)
1358
+ * - isPristine tracking
1359
+ * - Silent validation mode
1360
+ * - Form-level validation and reset
1361
+ *
1362
+ * Each field is registered with validation rules and tracks its own state independently.
1363
+ */
1364
+ /**
1365
+ * Creates a new form instance.
1366
+ *
1367
+ * @param options The options for the form instance.
1368
+ * @template Z The type of the form ticket.
1369
+ * @template E The type of the form context.
1370
+ * @returns A new form instance.
1371
+ *
1372
+ * @see https://0.vuetifyjs.com/composables/forms/create-form
1373
+ *
1374
+ * @example
1375
+ * ```ts
1376
+ * import { createForm } from '@vuetify/v0'
1377
+ *
1378
+ * const form = createForm()
1379
+ *
1380
+ * const username = form.register({
1381
+ * id: 'username',
1382
+ * value: '',
1383
+ * rules: [(v) => v.length > 0 || 'Username is required'],
1384
+ * })
1385
+ *
1386
+ * await form.submit()
1387
+ *
1388
+ * console.log(username.errors.value) // ['Username is required']
1389
+ *
1390
+ * form.reset()
1391
+ * ```
1392
+ */
1393
+ function createForm(options) {
1394
+ const registry = createRegistry(options);
1395
+ const validateOn = options?.validateOn || "submit";
1396
+ function parse(value) {
1397
+ return value.toLowerCase().split(/\s+/);
1398
+ }
1399
+ const isValidating = computed(() => {
1400
+ for (const ticket of registry.values()) if (ticket.isValidating.value) return true;
1401
+ return false;
1402
+ });
1403
+ const isValid = computed(() => {
1404
+ let hasFields = false;
1405
+ for (const ticket of registry.values()) {
1406
+ hasFields = true;
1407
+ if (ticket.isValid.value === false) return false;
1408
+ if (/* @__PURE__ */ isNull(ticket.isValid.value)) return null;
1409
+ }
1410
+ return hasFields ? true : null;
1411
+ });
1412
+ function reset() {
1413
+ for (const ticket of registry.values()) ticket.reset();
1414
+ }
1415
+ async function submit() {
1416
+ return validate([...registry.keys()]);
1417
+ }
1418
+ async function validate(id) {
1419
+ const validating = toArray(id);
1420
+ return (await Promise.all(validating.map(async (id$1) => await registry.get(id$1)?.validate() ?? true))).every(Boolean);
1421
+ }
1422
+ function register(registration) {
1423
+ const model = shallowRef(/* @__PURE__ */ isNullOrUndefined(registration.value) ? "" : toValue(registration.value));
1424
+ const rules = registration.rules || [];
1425
+ const errors = shallowRef([]);
1426
+ const isValidating$1 = shallowRef(false);
1427
+ const initialValue = model.value;
1428
+ const triggers = registration.validateOn || validateOn;
1429
+ const isPristine = shallowRef(true);
1430
+ const isValid$1 = shallowRef(null);
1431
+ function _validatesOn(event) {
1432
+ return parse(triggers).includes(event);
1433
+ }
1434
+ function _reset() {
1435
+ model.value = initialValue;
1436
+ errors.value = [];
1437
+ isPristine.value = true;
1438
+ isValid$1.value = null;
1439
+ isValidating$1.value = false;
1440
+ validationGeneration++;
1441
+ }
1442
+ let validationGeneration = 0;
1443
+ async function validate$1(silent = false) {
1444
+ if (rules.length === 0) return isValid$1.value = true;
1445
+ const generation = ++validationGeneration;
1446
+ isValidating$1.value = true;
1447
+ try {
1448
+ const results = await Promise.all(rules.map((rule) => rule(model.value)));
1449
+ if (generation !== validationGeneration) return isValid$1.value ?? false;
1450
+ const errorMessages = results.filter((result) => /* @__PURE__ */ isString(result));
1451
+ if (!silent) {
1452
+ errors.value = errorMessages;
1453
+ isValid$1.value = errorMessages.length === 0;
1454
+ isPristine.value = toValue(model) === initialValue;
1455
+ }
1456
+ return errorMessages.length === 0;
1457
+ } finally {
1458
+ if (generation === validationGeneration) isValidating$1.value = false;
1459
+ }
1460
+ }
1461
+ const item = {
1462
+ ...registration,
1463
+ rules,
1464
+ errors,
1465
+ disabled: registration.disabled || false,
1466
+ validateOn: triggers,
1467
+ isValidating: isValidating$1,
1468
+ isPristine,
1469
+ isValid: isValid$1,
1470
+ reset: _reset,
1471
+ validate: validate$1
1472
+ };
1473
+ const ticket = registry.register(item);
1474
+ Object.defineProperty(ticket, "value", {
1475
+ get() {
1476
+ return model.value;
1477
+ },
1478
+ set(val) {
1479
+ model.value = val;
1480
+ isPristine.value = val === initialValue;
1481
+ isValid$1.value = null;
1482
+ if (_validatesOn("change")) validate$1();
1483
+ },
1484
+ enumerable: true,
1485
+ configurable: true
1486
+ });
1487
+ return ticket;
1488
+ }
1489
+ function onboard(registrations) {
1490
+ return registry.batch(() => registrations.map((r) => register(r)));
1491
+ }
1492
+ return {
1493
+ ...registry,
1494
+ register,
1495
+ onboard,
1496
+ reset,
1497
+ submit,
1498
+ validateOn,
1499
+ isValid,
1500
+ isValidating,
1501
+ get size() {
1502
+ return registry.size;
1503
+ }
1504
+ };
1505
+ }
1506
+ /**
1507
+ * Creates a new form context.
1508
+ *
1509
+ * @param options The options for the form context.
1510
+ * @template Z The type of the form ticket.
1511
+ * @template E The type of the form context.
1512
+ * @returns A new form context.
1513
+ *
1514
+ * @see https://0.vuetifyjs.com/composables/forms/create-form
1515
+ *
1516
+ * @example
1517
+ * ```ts
1518
+ * import { createFormContext } from '@vuetify/v0'
1519
+ *
1520
+ * // With default namespace 'v0:form'
1521
+ * export const [useMyForm, provideMyForm, myForm] = createFormContext({ validateOn: 'change' })
1522
+ *
1523
+ * // Or with custom namespace
1524
+ * export const [useMyForm, provideMyForm, myForm] = createFormContext({
1525
+ * namespace: 'my-form',
1526
+ * validateOn: 'change',
1527
+ * })
1528
+ *
1529
+ * // In a parent component:
1530
+ * provideMyForm()
1531
+ *
1532
+ * // In a child component:
1533
+ * const form = useMyForm()
1534
+ * form.register({ id: 'field', value: ref(''), rules: [...] })
1535
+ * ```
1536
+ */
1537
+ function createFormContext(_options = {}) {
1538
+ const { namespace = "v0:form", ...options } = _options;
1539
+ const [useFormContext, _provideFormContext] = createContext(namespace);
1540
+ const context = createForm(options);
1541
+ function provideFormContext(_context = context, app) {
1542
+ return _provideFormContext(_context, app);
1543
+ }
1544
+ return createTrinity(useFormContext, provideFormContext, context);
1545
+ }
1546
+ /**
1547
+ * Returns the current form instance.
1548
+ *
1549
+ * @param namespace The namespace for the form context. Defaults to `'v0:form'`.
1550
+ * @returns The current form instance.
1551
+ *
1552
+ * @see https://0.vuetifyjs.com/composables/forms/create-form
1553
+ *
1554
+ * @example
1555
+ * ```vue
1556
+ * <script setup lang="ts">
1557
+ * import { useForm } from '@vuetify/v0'
1558
+ *
1559
+ * const form = useForm()
1560
+ * <\/script>
1561
+ *
1562
+ * <template>
1563
+ * <div>
1564
+ * <p>Form is {{ form.isValid.value ? 'valid' : 'invalid' }}</p>
1565
+ * </div>
1566
+ * </template>
1567
+ * ```
1568
+ */
1569
+ function useForm(namespace = "v0:form") {
1570
+ return useContext(namespace);
1571
+ }
1572
+
1573
+ //#endregion
1574
+ //#region src/composables/useHotkey/aliases.ts
1575
+ /**
1576
+ * Key alias mapping for consistent key normalization across the hotkey system.
1577
+ *
1578
+ * Maps user-friendly aliases to canonical key names that match
1579
+ * KeyboardEvent.key values (in lowercase) where possible.
1580
+ */
1581
+ const keyAliasMap = {
1582
+ control: "ctrl",
1583
+ command: "cmd",
1584
+ option: "alt",
1585
+ up: "arrowup",
1586
+ down: "arrowdown",
1587
+ left: "arrowleft",
1588
+ right: "arrowright",
1589
+ esc: "escape",
1590
+ spacebar: " ",
1591
+ space: " ",
1592
+ return: "enter",
1593
+ del: "delete",
1594
+ minus: "-",
1595
+ hyphen: "-"
1596
+ };
1597
+ function normalizeKey(key) {
1598
+ const lowerKey = key.toLowerCase();
1599
+ return keyAliasMap[lowerKey] ?? lowerKey;
1600
+ }
1601
+
1602
+ //#endregion
1603
+ //#region src/composables/useHotkey/parsing.ts
1604
+ const logger = useLogger();
1605
+ const MODIFIERS = [
1606
+ "ctrl",
1607
+ "shift",
1608
+ "alt",
1609
+ "meta",
1610
+ "cmd"
1611
+ ];
1612
+ /**
1613
+ * Splits a single combination string into individual key parts.
1614
+ *
1615
+ * A combination is a set of keys that must be pressed simultaneously.
1616
+ * e.g. `ctrl+k`, `shift+-`
1617
+ *
1618
+ * @param combination - The combination string to parse
1619
+ * @param isInternal - Whether this is an internal call (suppresses warnings)
1620
+ * @returns Object with keys array and separators array
1621
+ */
1622
+ function splitKeyCombination(combination, isInternal = false) {
1623
+ const emptyResult = {
1624
+ keys: [],
1625
+ separators: []
1626
+ };
1627
+ if (!combination) {
1628
+ if (!isInternal) logger.warn("Invalid hotkey combination: empty string provided");
1629
+ return emptyResult;
1630
+ }
1631
+ if (combination.length > 1 && [
1632
+ "+",
1633
+ "/",
1634
+ "_"
1635
+ ].some((v) => combination.startsWith(v)) && ![
1636
+ "++",
1637
+ "//",
1638
+ "__"
1639
+ ].some((v) => combination.startsWith(v)) || combination.includes("++") || combination.includes("__") || combination === "+" || combination === "_" || combination.length > 1 && (combination.endsWith("+") || combination.endsWith("_")) && combination.at(-2) !== combination.at(-1) || combination === "++" || combination === "--" || combination === "__") {
1640
+ if (!isInternal) logger.warn(`Invalid hotkey combination: "${combination}" has invalid structure`);
1641
+ return emptyResult;
1642
+ }
1643
+ const keys = [];
1644
+ const separators = [];
1645
+ let buffer = "";
1646
+ function flushBuffer(separator) {
1647
+ if (buffer) {
1648
+ if (separator) separators.push(separator);
1649
+ keys.push(normalizeKey(buffer));
1650
+ buffer = "";
1651
+ }
1652
+ }
1653
+ for (let i = 0; i < combination.length; i++) {
1654
+ const char = combination[i];
1655
+ const nextChar = combination[i + 1];
1656
+ if ([
1657
+ "+",
1658
+ "/",
1659
+ "_",
1660
+ "-"
1661
+ ].includes(char))
1662
+ /* v8 ignore start -- edge case: doubled special chars */
1663
+ if (char === nextChar) {
1664
+ flushBuffer(char);
1665
+ keys.push(char);
1666
+ i++;
1667
+ } else if ([
1668
+ "+",
1669
+ "/",
1670
+ "_"
1671
+ ].includes(char)) flushBuffer(char);
1672
+ else buffer += char;
1673
+ else buffer += char;
1674
+ }
1675
+ flushBuffer();
1676
+ /* v8 ignore start -- edge case: invalid minus in combination */
1677
+ if (keys.some((key) => key.length > 1 && key.includes("-") && key !== "--")) {
1678
+ if (!isInternal) logger.warn(`Invalid hotkey combination: "${combination}" has invalid structure`);
1679
+ return emptyResult;
1680
+ }
1681
+ if (keys.length === 0 && combination) return {
1682
+ keys: [normalizeKey(combination)],
1683
+ separators
1684
+ };
1685
+ /* v8 ignore stop */
1686
+ return {
1687
+ keys,
1688
+ separators
1689
+ };
1690
+ }
1691
+ /**
1692
+ * Splits a hotkey string into its constituent combination groups.
1693
+ *
1694
+ * A sequence is a series of combinations that must be pressed in order.
1695
+ * e.g. `a-b`, `ctrl+k-p`
1696
+ *
1697
+ * @param str - The sequence string to parse
1698
+ * @returns Array of combination strings
1699
+ */
1700
+ function splitKeySequence(str) {
1701
+ if (!str) {
1702
+ logger.warn("Invalid hotkey sequence: empty string provided");
1703
+ return [];
1704
+ }
1705
+ const hasInvalidStart = str.startsWith("-") && !["---", "--+"].includes(str);
1706
+ const hasInvalidEnd = str.endsWith("-") && !str.endsWith("+-") && !str.endsWith("_-") && str !== "-" && str !== "---";
1707
+ if (hasInvalidStart || hasInvalidEnd) {
1708
+ logger.warn(`Invalid hotkey sequence: "${str}" contains invalid combinations`);
1709
+ return [];
1710
+ }
1711
+ const result = [];
1712
+ let buffer = "";
1713
+ let i = 0;
1714
+ while (i < str.length) {
1715
+ const char = str[i];
1716
+ if (char === "-") {
1717
+ const prevChar = str[i - 1] ?? "";
1718
+ const prevPrevChar = i > 1 ? str[i - 2] : void 0;
1719
+ if (["+", "_"].includes(prevChar) && !["+", "/"].includes(prevPrevChar ?? "")) {
1720
+ buffer += char;
1721
+ i++;
1722
+ } else {
1723
+ if (buffer) {
1724
+ result.push(buffer);
1725
+ buffer = "";
1726
+ } else result.push("-");
1727
+ i++;
1728
+ }
1729
+ } else {
1730
+ buffer += char;
1731
+ i++;
1732
+ }
1733
+ }
1734
+ if (buffer) result.push(buffer);
1735
+ const collapsed = [];
1736
+ let minusCount = 0;
1737
+ for (const part of result)
1738
+ /* v8 ignore start -- edge case: minus collapsing */
1739
+ if (part === "-") {
1740
+ if (minusCount % 2 === 0) collapsed.push("-");
1741
+ minusCount++;
1742
+ } else {
1743
+ minusCount = 0;
1744
+ collapsed.push(part);
1745
+ }
1746
+ /* v8 ignore start -- edge case: invalid combination in sequence */
1747
+ if (!collapsed.every((s) => splitKeyCombination(s, true).keys.length > 0)) {
1748
+ logger.warn(`Invalid hotkey sequence: "${str}" contains invalid combinations`);
1749
+ return [];
1750
+ }
1751
+ /* v8 ignore stop */
1752
+ return collapsed;
1753
+ }
1754
+
1755
+ //#endregion
1756
+ //#region src/composables/useHotkey/index.ts
1757
+ /**
1758
+ * @module useHotkey
1759
+ *
1760
+ * @remarks
1761
+ * Hotkey listener composable with key combination and sequence support.
1762
+ *
1763
+ * Key features:
1764
+ * - Key combination support (`ctrl+k`, `shift+enter`)
1765
+ * - Key sequence support (`g-h` for GitHub-style shortcuts)
1766
+ * - Platform-aware modifiers (Mac: cmd→meta, others: cmd→ctrl)
1767
+ * - Input focus detection (skip when typing in inputs)
1768
+ * - Sequence timeout with automatic reset
1769
+ * - Key alias normalization
1770
+ * - Pause/resume/stop functionality
1771
+ * - Automatic cleanup on scope disposal
1772
+ * - SSR-safe (no-op when not in browser)
1773
+ *
1774
+ * Builds on useEventListener for lifecycle-managed keyboard events.
1775
+ */
1776
+ const isMac = IN_BROWSER && /mac|iphone|ipad|ipod/i.test(navigator?.userAgent ?? "");
1777
+ /**
1778
+ * A composable that listens for hotkey combinations and sequences.
1779
+ *
1780
+ * @param keys - The hotkey string (e.g., 'ctrl+k', 'g-h')
1781
+ * @param callback - The function to call when the hotkey is triggered
1782
+ * @param options - Configuration options
1783
+ * @returns An object with state refs and control methods
1784
+ *
1785
+ * @see https://0.vuetifyjs.com/composables/system/use-hotkey
1786
+ *
1787
+ * @example
1788
+ * ```ts
1789
+ * import { useHotkey } from '@vuetify/v0'
1790
+ *
1791
+ * // Simple combination
1792
+ * const { isActive, pause, resume } = useHotkey('ctrl+k', () => {
1793
+ * console.log('Command palette opened')
1794
+ * })
1795
+ *
1796
+ * // Key sequence (GitHub-style)
1797
+ * useHotkey('g-h', () => console.log('Go home'))
1798
+ *
1799
+ * // With options
1800
+ * useHotkey('escape', closeModal, { inputs: true })
1801
+ *
1802
+ * // Pause/resume control
1803
+ * pause() // Temporarily disable
1804
+ * resume() // Re-enable
1805
+ * ```
1806
+ */
1807
+ function useHotkey(keys, callback, options = {}, _platform) {
1808
+ const platformIsMac = _platform?.isMac ?? isMac;
1809
+ const { event = "keydown", inputs = false, preventDefault = true, stopPropagation = false, sequenceTimeout = 1e3 } = options;
1810
+ const isPaused = shallowRef(false);
1811
+ const cleanup = shallowRef(null);
1812
+ const isActive = toRef(() => !/* @__PURE__ */ isNull(cleanup.value));
1813
+ let sequenceTimer;
1814
+ let keyGroups = [];
1815
+ let isSequence = false;
1816
+ let groupIndex = 0;
1817
+ function isInputFocused() {
1818
+ if (toValue(inputs)) return false;
1819
+ const activeElement = document.activeElement;
1820
+ if (!activeElement) return false;
1821
+ const role = activeElement.getAttribute("role");
1822
+ if (role === "textbox" || role === "searchbox" || role === "combobox" || role === "spinbutton") return true;
1823
+ if (activeElement.tagName === "INPUT") {
1824
+ const type = activeElement.type?.toLowerCase();
1825
+ return [
1826
+ "text",
1827
+ "email",
1828
+ "password",
1829
+ "search",
1830
+ "tel",
1831
+ "url",
1832
+ "number",
1833
+ "date",
1834
+ "datetime-local",
1835
+ "time",
1836
+ "month",
1837
+ "week"
1838
+ ].includes(type);
1839
+ }
1840
+ return activeElement.tagName === "TEXTAREA" || activeElement.isContentEditable;
1841
+ }
1842
+ function resetSequence() {
1843
+ groupIndex = 0;
1844
+ clearTimeout(sequenceTimer);
1845
+ }
1846
+ function handler(e) {
1847
+ const group = keyGroups[groupIndex];
1848
+ if (!group || isInputFocused()) return;
1849
+ if (!matchesKeyGroup(e, group, platformIsMac)) {
1850
+ if (isSequence) resetSequence();
1851
+ return;
1852
+ }
1853
+ if (toValue(stopPropagation)) e.stopPropagation();
1854
+ if (toValue(preventDefault)) e.preventDefault();
1855
+ if (!isSequence) {
1856
+ callback(e);
1857
+ return;
1858
+ }
1859
+ clearTimeout(sequenceTimer);
1860
+ groupIndex++;
1861
+ if (groupIndex === keyGroups.length) {
1862
+ callback(e);
1863
+ resetSequence();
1864
+ return;
1865
+ }
1866
+ sequenceTimer = setTimeout(resetSequence, toValue(sequenceTimeout));
1867
+ }
1868
+ function setup() {
1869
+ if (!IN_BROWSER || isPaused.value) return;
1870
+ const currentKeys = toValue(keys);
1871
+ if (!currentKeys) return;
1872
+ const groups = splitKeySequence(currentKeys.toLowerCase());
1873
+ if (groups.length === 0) return;
1874
+ isSequence = groups.length > 1;
1875
+ keyGroups = groups;
1876
+ resetSequence();
1877
+ cleanup.value = useWindowEventListener(toValue(event), handler);
1878
+ }
1879
+ function dispose() {
1880
+ if (cleanup.value) {
1881
+ cleanup.value();
1882
+ cleanup.value = null;
1883
+ }
1884
+ clearTimeout(sequenceTimer);
1885
+ keyGroups = [];
1886
+ isSequence = false;
1887
+ groupIndex = 0;
1888
+ }
1889
+ function pause() {
1890
+ isPaused.value = true;
1891
+ dispose();
1892
+ }
1893
+ function resume() {
1894
+ isPaused.value = false;
1895
+ setup();
1896
+ }
1897
+ function stop() {
1898
+ dispose();
1899
+ }
1900
+ watch(() => toValue(keys), () => {
1901
+ if (isPaused.value) return;
1902
+ dispose();
1903
+ setup();
1904
+ }, { immediate: true });
1905
+ watch(() => toValue(event), () => {
1906
+ if (isPaused.value || !toValue(keys)) return;
1907
+ dispose();
1908
+ setup();
1909
+ });
1910
+ onScopeDispose(stop, true);
1911
+ return {
1912
+ isActive: shallowReadonly(isActive),
1913
+ isPaused: shallowReadonly(isPaused),
1914
+ pause,
1915
+ resume,
1916
+ stop
1917
+ };
1918
+ }
1919
+ function isModifier(key) {
1920
+ return MODIFIERS.includes(key);
1921
+ }
1922
+ function parseKeyGroup(group) {
1923
+ const { keys: parts } = splitKeyCombination(group.toLowerCase());
1924
+ const modifiers = Object.fromEntries(MODIFIERS.map((m) => [m, false]));
1925
+ if (parts.length === 0) return {
1926
+ modifiers,
1927
+ actualKey: void 0
1928
+ };
1929
+ let actualKey;
1930
+ for (const part of parts) if (isModifier(part)) modifiers[part] = true;
1931
+ else actualKey = part;
1932
+ return {
1933
+ modifiers,
1934
+ actualKey
1935
+ };
1936
+ }
1937
+ function matchesKeyGroup(e, group, platformIsMac) {
1938
+ const { modifiers, actualKey } = parseKeyGroup(group);
1939
+ const expectCtrl = modifiers.ctrl || !platformIsMac && (modifiers.cmd || modifiers.meta);
1940
+ const expectMeta = platformIsMac && (modifiers.cmd || modifiers.meta);
1941
+ const modifiersMatch = e.ctrlKey === expectCtrl && e.metaKey === expectMeta && e.shiftKey === modifiers.shift && e.altKey === modifiers.alt;
1942
+ if (/* @__PURE__ */ isUndefined(actualKey)) return modifiersMatch;
1943
+ return modifiersMatch && e.key.toLowerCase() === actualKey.toLowerCase();
1944
+ }
1945
+
1946
+ //#endregion
1947
+ //#region src/composables/useIntersectionObserver/index.ts
1948
+ /**
1949
+ * @module useIntersectionObserver
1950
+ *
1951
+ * @remarks
1952
+ * IntersectionObserver composable with lifecycle management.
1953
+ *
1954
+ * Key features:
1955
+ * - IntersectionObserver API wrapper
1956
+ * - Pause/resume/stop functionality
1957
+ * - Automatic cleanup on unmount
1958
+ * - SSR-safe (checks SUPPORTS_INTERSECTION_OBSERVER)
1959
+ * - Hydration-aware
1960
+ * - Immediate callback option
1961
+ *
1962
+ * Perfect for lazy loading, infinite scroll, and visibility detection.
1963
+ */
1964
+ /**
1965
+ * A composable that uses the Intersection Observer API to detect when an element
1966
+ * is visible in the viewport.
1967
+ *
1968
+ * @param target The element to observe.
1969
+ * @param callback The callback to execute when the element's intersection changes.
1970
+ * @param options The options for the Intersection Observer.
1971
+ * @returns An object with methods to control the observer.
1972
+ *
1973
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver
1974
+ * @see https://0.vuetifyjs.com/composables/system/use-intersection-observer
1975
+ *
1976
+ * @example
1977
+ * ```ts
1978
+ * import { ref } from 'vue'
1979
+ * import { useIntersectionObserver } from '@vuetify/v0'
1980
+ *
1981
+ * const target = ref<HTMLElement>()
1982
+ * const isVisible = ref(false)
1983
+ *
1984
+ * const { isIntersecting, pause, resume } = useIntersectionObserver(
1985
+ * target,
1986
+ * (entries) => {
1987
+ * const entry = entries[0]
1988
+ * if (entry) {
1989
+ * isVisible.value = entry.isIntersecting
1990
+ * console.log('Element is visible:', entry.isIntersecting)
1991
+ * }
1992
+ * },
1993
+ * { threshold: 0.5 }
1994
+ * )
1995
+ *
1996
+ * // Pause observation
1997
+ * pause()
1998
+ *
1999
+ * // Resume observation
2000
+ * resume()
2001
+ * ```
2002
+ */
2003
+ function useIntersectionObserver(target, callback, options = {}) {
2004
+ const isIntersecting = shallowRef(false);
2005
+ return {
2006
+ ...createObserver(target, callback, {
2007
+ supports: SUPPORTS_INTERSECTION_OBSERVER,
2008
+ once: options.once,
2009
+ create: (cb) => new IntersectionObserver((entries) => {
2010
+ cb(entries.map((e) => ({
2011
+ boundingClientRect: e.boundingClientRect,
2012
+ intersectionRatio: e.intersectionRatio,
2013
+ intersectionRect: e.intersectionRect,
2014
+ isIntersecting: e.isIntersecting,
2015
+ rootBounds: e.rootBounds,
2016
+ target: e.target,
2017
+ time: e.time
2018
+ })));
2019
+ }, {
2020
+ root: options.root ?? null,
2021
+ rootMargin: options.rootMargin ?? "0px",
2022
+ threshold: options.threshold ?? 0
2023
+ }),
2024
+ observe: (obs, el) => obs.observe(el),
2025
+ onEntry: (entries) => {
2026
+ const latest = entries.at(-1);
2027
+ if (latest) isIntersecting.value = latest.isIntersecting;
2028
+ },
2029
+ onPause: () => {
2030
+ isIntersecting.value = false;
2031
+ },
2032
+ shouldStop: (entries) => entries.at(-1)?.isIntersecting ?? false,
2033
+ immediate: options.immediate ? (el) => {
2034
+ return [{
2035
+ boundingClientRect: el.getBoundingClientRect(),
2036
+ intersectionRatio: 0,
2037
+ intersectionRect: new DOMRect(0, 0, 0, 0),
2038
+ isIntersecting: false,
2039
+ rootBounds: null,
2040
+ target: el,
2041
+ time: performance.now()
2042
+ }];
2043
+ } : void 0
2044
+ }),
2045
+ isIntersecting: shallowReadonly(isIntersecting)
2046
+ };
2047
+ }
2048
+ /**
2049
+ * A convenience composable that uses the Intersection Observer API to detect
2050
+ * when an element is visible in the viewport.
2051
+ *
2052
+ * @param target The element to observe.
2053
+ * @param options The options for the Intersection Observer.
2054
+ * @returns An object with the intersection state.
2055
+ *
2056
+ * @see https://0.vuetifyjs.com/composables/system/use-intersection-observer
2057
+ *
2058
+ * @example
2059
+ * ```ts
2060
+ * import { ref } from 'vue'
2061
+ * import { useElementIntersection } from '@vuetify/v0'
2062
+ *
2063
+ * const myElement = ref<HTMLElement>()
2064
+ * const { isIntersecting, intersectionRatio } = useElementIntersection(myElement, {
2065
+ * threshold: 0.5
2066
+ * })
2067
+ *
2068
+ * // Use in template to conditionally render or animate
2069
+ * watchEffect(() => {
2070
+ * if (isIntersecting.value) {
2071
+ * console.log('Element is visible!', intersectionRatio.value)
2072
+ * }
2073
+ * })
2074
+ * ```
2075
+ */
2076
+ function useElementIntersection(target, options = {}) {
2077
+ const isIntersecting = shallowRef(false);
2078
+ const intersectionRatio = shallowRef(0);
2079
+ const { pause: _pause, resume, stop, isActive, isPaused } = useIntersectionObserver(target, (entries) => {
2080
+ const entry = entries.at(-1);
2081
+ if (entry) {
2082
+ isIntersecting.value = entry.isIntersecting;
2083
+ intersectionRatio.value = entry.intersectionRatio;
2084
+ }
2085
+ }, {
2086
+ immediate: true,
2087
+ ...options
2088
+ });
2089
+ function pause() {
2090
+ isIntersecting.value = false;
2091
+ intersectionRatio.value = 0;
2092
+ _pause();
2093
+ }
2094
+ return {
2095
+ isIntersecting: shallowReadonly(isIntersecting),
2096
+ intersectionRatio: shallowReadonly(intersectionRatio),
2097
+ isActive,
2098
+ isPaused,
2099
+ pause,
2100
+ resume,
2101
+ stop
2102
+ };
2103
+ }
2104
+
2105
+ //#endregion
2106
+ //#region src/composables/useLazy/index.ts
2107
+ /**
2108
+ * @module useLazy
2109
+ *
2110
+ * @see https://0.vuetifyjs.com/composables/system/use-lazy
2111
+ *
2112
+ * @remarks
2113
+ * Deferred content rendering composable for performance optimization.
2114
+ *
2115
+ * Key features:
2116
+ * - Content only renders after first activation (unless eager)
2117
+ * - Optional reset on deactivation for memory savings
2118
+ * - Readonly state refs for template binding
2119
+ * - Manual reset control
2120
+ * - SSR-safe
2121
+ *
2122
+ * Perfect for dialogs, menus, tooltips, and any component with
2123
+ * conditionally rendered content.
2124
+ */
2125
+ /**
2126
+ * Deferred content rendering for performance optimization.
2127
+ *
2128
+ * @param active Reactive boolean controlling activation state
2129
+ * @param options Configuration options
2130
+ * @returns Lazy context with state refs and control functions
2131
+ *
2132
+ * @see https://0.vuetifyjs.com/composables/system/use-lazy
2133
+ *
2134
+ * @example
2135
+ * ```ts
2136
+ * import { ref } from 'vue'
2137
+ * import { useLazy } from '@vuetify/v0'
2138
+ *
2139
+ * const isOpen = ref(false)
2140
+ * const { hasContent, onAfterLeave } = useLazy(isOpen)
2141
+ *
2142
+ * // In template:
2143
+ * // <Transition @after-leave="onAfterLeave">
2144
+ * // <div v-if="isOpen">
2145
+ * // <template v-if="hasContent">
2146
+ * // <!-- Heavy content here -->
2147
+ * // </template>
2148
+ * // </div>
2149
+ * // </Transition>
2150
+ * ```
2151
+ *
2152
+ * @example
2153
+ * Eager mode (render immediately):
2154
+ * ```ts
2155
+ * const { hasContent } = useLazy(isOpen, { eager: true })
2156
+ * // hasContent.value is always true
2157
+ * ```
2158
+ *
2159
+ * @example
2160
+ * With reactive eager prop:
2161
+ * ```ts
2162
+ * const props = defineProps<{ eager: boolean }>()
2163
+ * const { hasContent } = useLazy(isOpen, {
2164
+ * eager: toRef(() => props.eager),
2165
+ * })
2166
+ * ```
2167
+ */
2168
+ function useLazy(active, options = {}) {
2169
+ const { eager = false } = options;
2170
+ const isBooted = shallowRef(false);
2171
+ const hasContent = toRef(() => isBooted.value || toValue(eager) || toValue(active));
2172
+ const stop = watch(() => toValue(active), (value) => {
2173
+ if (value) isBooted.value = true;
2174
+ }, { immediate: true });
2175
+ function reset() {
2176
+ isBooted.value = false;
2177
+ }
2178
+ function onAfterLeave() {
2179
+ if (!toValue(eager)) reset();
2180
+ }
2181
+ onScopeDispose(stop, true);
2182
+ return {
2183
+ isBooted: shallowReadonly(isBooted),
2184
+ hasContent: shallowReadonly(hasContent),
2185
+ reset,
2186
+ onAfterLeave
2187
+ };
2188
+ }
2189
+
2190
+ //#endregion
2191
+ //#region src/composables/useMediaQuery/index.ts
2192
+ /**
2193
+ * @module useMediaQuery
2194
+ *
2195
+ * @see https://0.vuetifyjs.com/composables/system/use-media-query
2196
+ *
2197
+ * @remarks
2198
+ * Reactive media query composable with automatic cleanup.
2199
+ *
2200
+ * Key features:
2201
+ * - Window matchMedia integration
2202
+ * - Reactive query string support
2203
+ * - SSR-safe (returns false on server)
2204
+ * - Hydration-aware (defers client updates until hydrated)
2205
+ * - Automatic listener cleanup on scope disposal
2206
+ * - Supports both static and dynamic queries
2207
+ *
2208
+ * Perfect for responsive conditionals beyond breakpoint detection.
2209
+ */
2210
+ /**
2211
+ * Reactive media query matching.
2212
+ *
2213
+ * @param query CSS media query string (reactive).
2214
+ * @returns The media query context.
2215
+ *
2216
+ * @see https://0.vuetifyjs.com/composables/system/use-media-query
2217
+ *
2218
+ * @example
2219
+ * ```ts
2220
+ * // Static query
2221
+ * const { matches } = useMediaQuery('(prefers-color-scheme: dark)')
2222
+ *
2223
+ * // Dynamic query
2224
+ * const minWidth = ref(768)
2225
+ * const { matches } = useMediaQuery(() => `(min-width: ${minWidth.value}px)`)
2226
+ *
2227
+ * // Manual cleanup
2228
+ * const { matches, stop } = useMediaQuery('(hover: hover)')
2229
+ * stop() // Remove listener early
2230
+ * ```
2231
+ */
2232
+ function useMediaQuery(query) {
2233
+ const matches = shallowRef(false);
2234
+ const mediaQueryList = shallowRef(null);
2235
+ const resolvedQuery = computed(() => toValue(query));
2236
+ const hydration = useHydration();
2237
+ let cleanup = null;
2238
+ function update() {
2239
+ if (!IN_BROWSER || !SUPPORTS_MATCH_MEDIA) return;
2240
+ cleanup?.();
2241
+ cleanup = null;
2242
+ const mql = window.matchMedia(resolvedQuery.value);
2243
+ mediaQueryList.value = mql;
2244
+ matches.value = mql.matches;
2245
+ function handler(e) {
2246
+ matches.value = e.matches;
2247
+ }
2248
+ mql.addEventListener("change", handler);
2249
+ cleanup = () => mql.removeEventListener("change", handler);
2250
+ }
2251
+ const stopWatch = watch([resolvedQuery, () => hydration.isHydrated.value], ([_, hydrated]) => {
2252
+ if (hydrated) update();
2253
+ }, { immediate: true });
2254
+ function stop() {
2255
+ stopWatch();
2256
+ cleanup?.();
2257
+ cleanup = null;
2258
+ }
2259
+ onScopeDispose(stop, true);
2260
+ return {
2261
+ matches: shallowReadonly(matches),
2262
+ query: resolvedQuery,
2263
+ mediaQueryList: shallowReadonly(mediaQueryList),
2264
+ stop
2265
+ };
2266
+ }
2267
+ /**
2268
+ * Check if the user prefers dark color scheme.
2269
+ *
2270
+ * @returns The media query context.
2271
+ *
2272
+ * @example
2273
+ * ```ts
2274
+ * const { matches: prefersDark } = usePrefersDark()
2275
+ * ```
2276
+ */
2277
+ function usePrefersDark() {
2278
+ return useMediaQuery("(prefers-color-scheme: dark)");
2279
+ }
2280
+ /**
2281
+ * Check if the user prefers reduced motion.
2282
+ *
2283
+ * @returns The media query context.
2284
+ *
2285
+ * @example
2286
+ * ```ts
2287
+ * const { matches: prefersReducedMotion } = usePrefersReducedMotion()
2288
+ * ```
2289
+ */
2290
+ function usePrefersReducedMotion() {
2291
+ return useMediaQuery("(prefers-reduced-motion: reduce)");
2292
+ }
2293
+ /**
2294
+ * Check if the user prefers more contrast.
2295
+ *
2296
+ * @returns The media query context.
2297
+ *
2298
+ * @example
2299
+ * ```ts
2300
+ * const { matches: prefersContrast } = usePrefersContrast()
2301
+ * ```
2302
+ */
2303
+ function usePrefersContrast() {
2304
+ return useMediaQuery("(prefers-contrast: more)");
2305
+ }
2306
+
2307
+ //#endregion
2308
+ //#region src/composables/useMutationObserver/index.ts
2309
+ /**
2310
+ * @module useMutationObserver
2311
+ *
2312
+ * @remarks
2313
+ * MutationObserver composable with lifecycle management.
2314
+ *
2315
+ * Key features:
2316
+ * - MutationObserver API wrapper
2317
+ * - Pause/resume/stop functionality
2318
+ * - Automatic cleanup on unmount
2319
+ * - SSR-safe (checks SUPPORTS_MUTATION_OBSERVER)
2320
+ * - Hydration-aware
2321
+ * - Configurable observation options (childList, attributes, characterData, etc.)
2322
+ *
2323
+ * Perfect for detecting DOM changes and responding to mutations.
2324
+ */
2325
+ /**
2326
+ * A composable that uses the Mutation Observer API to detect changes in the DOM.
2327
+ *
2328
+ * @param target The element to observe.
2329
+ * @param callback The callback to execute when a mutation is observed.
2330
+ * @param options The options for the Mutation Observer.
2331
+ * @returns An object with methods to control the observer.
2332
+ *
2333
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
2334
+ * @see https://0.vuetifyjs.com/composables/system/use-mutation-observer
2335
+ *
2336
+ * @example
2337
+ * ```ts
2338
+ * import { ref } from 'vue'
2339
+ * import { useMutationObserver } from '@vuetify/v0'
2340
+ *
2341
+ * const container = ref<HTMLElement>()
2342
+ *
2343
+ * const { pause, resume, isPaused } = useMutationObserver(
2344
+ * container,
2345
+ * (mutations) => {
2346
+ * mutations.forEach((mutation) => {
2347
+ * if (mutation.type === 'childList') {
2348
+ * console.log('Children changed:', mutation.addedNodes, mutation.removedNodes)
2349
+ * } else if (mutation.type === 'attributes') {
2350
+ * console.log('Attribute changed:', mutation.attributeName)
2351
+ * }
2352
+ * })
2353
+ * },
2354
+ * {
2355
+ * childList: true,
2356
+ * attributes: true,
2357
+ * subtree: true
2358
+ * }
2359
+ * )
2360
+ *
2361
+ * // Pause observation
2362
+ * pause()
2363
+ *
2364
+ * // Resume observation
2365
+ * resume()
2366
+ * ```
2367
+ */
2368
+ function useMutationObserver(target, callback, options = {}) {
2369
+ const observerOptions = {
2370
+ childList: options.childList ?? true,
2371
+ attributes: options.attributes ?? false,
2372
+ characterData: options.characterData ?? false,
2373
+ subtree: options.subtree ?? false,
2374
+ attributeOldValue: options.attributeOldValue ?? false,
2375
+ characterDataOldValue: options.characterDataOldValue ?? false,
2376
+ attributeFilter: options.attributeFilter
2377
+ };
2378
+ return createObserver(target, callback, {
2379
+ supports: SUPPORTS_MUTATION_OBSERVER,
2380
+ once: options.once,
2381
+ create: (cb) => new MutationObserver((mutations) => {
2382
+ cb(mutations.map((m) => ({
2383
+ type: m.type,
2384
+ target: m.target,
2385
+ addedNodes: m.addedNodes,
2386
+ removedNodes: m.removedNodes,
2387
+ previousSibling: m.previousSibling,
2388
+ nextSibling: m.nextSibling,
2389
+ attributeName: m.attributeName,
2390
+ attributeNamespace: m.attributeNamespace,
2391
+ oldValue: m.oldValue
2392
+ })));
2393
+ }),
2394
+ observe: (obs, el) => obs.observe(el, observerOptions),
2395
+ immediate: options.immediate ? (el) => {
2396
+ const emptyNodeList = {
2397
+ length: 0,
2398
+ item: () => null,
2399
+ forEach: () => {},
2400
+ *[Symbol.iterator]() {}
2401
+ };
2402
+ return [{
2403
+ type: "childList",
2404
+ target: el,
2405
+ addedNodes: emptyNodeList,
2406
+ removedNodes: emptyNodeList,
2407
+ previousSibling: null,
2408
+ nextSibling: null,
2409
+ attributeName: null,
2410
+ attributeNamespace: null,
2411
+ oldValue: null
2412
+ }];
2413
+ } : void 0,
2414
+ onceIncludesImmediate: true
2415
+ });
2416
+ }
2417
+
2418
+ //#endregion
2419
+ //#region src/composables/createNested/strategies.ts
2420
+ /**
2421
+ * Multiple open strategy: allows multiple nodes to be open simultaneously.
2422
+ *
2423
+ * @remarks
2424
+ * Perfect for tree views, file explorers, and nested menus where users expect
2425
+ * to keep multiple sections expanded at once.
2426
+ *
2427
+ * @example
2428
+ * ```ts
2429
+ * const tree = createNested({ openStrategy: multipleOpenStrategy })
2430
+ * tree.open('node-1')
2431
+ * tree.open('node-2')
2432
+ * // Both nodes are now open
2433
+ * ```
2434
+ */
2435
+ const multipleOpenStrategy = {
2436
+ onOpen: void 0,
2437
+ onClose: void 0
2438
+ };
2439
+ /**
2440
+ * Single open strategy: only one node can be open at a time (accordion behavior).
2441
+ *
2442
+ * @remarks
2443
+ * Perfect for accordions, single-select navigation, and contexts where only
2444
+ * one section should be visible at a time.
2445
+ *
2446
+ * @example
2447
+ * ```ts
2448
+ * const tree = createNested({ openStrategy: singleOpenStrategy })
2449
+ * tree.open('node-1') // node-1 opens
2450
+ * tree.open('node-2') // node-1 closes, node-2 opens
2451
+ * ```
2452
+ */
2453
+ const singleOpenStrategy = {
2454
+ onOpen: (id, context) => {
2455
+ for (const openedId of context.openedIds) if (openedId !== id) context.openedIds.delete(openedId);
2456
+ },
2457
+ onClose: void 0
2458
+ };
2459
+
2460
+ //#endregion
2461
+ //#region src/composables/createNested/index.ts
2462
+ /**
2463
+ * @module createNested
2464
+ *
2465
+ * @remarks
2466
+ * Hierarchical tree management composable extending createGroup with:
2467
+ * - Parent-child relationship tracking (children/parents Maps)
2468
+ * - Open/close state management
2469
+ * - Tree traversal utilities (getPath, getDescendants, etc.)
2470
+ * - Pluggable open strategies
2471
+ *
2472
+ * Inheritance chain: createSelection → createGroup → createNested
2473
+ */
2474
+ /**
2475
+ * Resolves open mode to an OpenStrategy.
2476
+ */
2477
+ function resolveOpenStrategy(open = "multiple") {
2478
+ return open === "single" ? singleOpenStrategy : multipleOpenStrategy;
2479
+ }
2480
+ /**
2481
+ * Creates a new nested tree instance with hierarchical management.
2482
+ *
2483
+ * Extends `createGroup` to support parent-child relationships, tree traversal,
2484
+ * and open/close state management. Perfect for tree views, nested navigation,
2485
+ * and hierarchical data structures.
2486
+ *
2487
+ * @param options The options for the nested instance.
2488
+ * @template Z The type of the nested ticket.
2489
+ * @template E The type of the nested context.
2490
+ * @returns A new nested instance with tree management capabilities.
2491
+ *
2492
+ * @remarks
2493
+ * **Key Differences from `createGroup`:**
2494
+ * - `register()` accepts `parentId` for establishing parent-child relationships
2495
+ * - `unregister()` accepts optional `cascade` parameter for cascading deletions
2496
+ * - Adds tree traversal methods: `getPath()`, `getAncestors()`, `getDescendants()`
2497
+ * - Adds computed properties: `roots`, `leaves`, `isLeaf()`, `getDepth()`
2498
+ * - Adds open state management: `open()`, `close()`, `flip()`, `opened()`
2499
+ *
2500
+ * @see https://0.vuetifyjs.com/composables/selection/use-nested
2501
+ *
2502
+ * @example
2503
+ * ```ts
2504
+ * import { createNested } from '@vuetify/v0'
2505
+ *
2506
+ * const tree = createNested()
2507
+ *
2508
+ * const root = tree.register({ id: 'root', value: 'Root' })
2509
+ * const child1 = tree.register({ id: 'child-1', value: 'Child 1', parentId: 'root' })
2510
+ * const child2 = tree.register({ id: 'child-2', value: 'Child 2', parentId: 'root' })
2511
+ *
2512
+ * console.log(tree.getPath('child-1')) // ['root', 'child-1']
2513
+ * console.log(tree.getDescendants('root')) // ['child-1', 'child-2']
2514
+ * console.log(tree.isLeaf('child-2')) // true
2515
+ *
2516
+ * tree.open('root')
2517
+ * console.log(tree.opened('root')) // true
2518
+ * ```
2519
+ */
2520
+ function createNested(_options = {}) {
2521
+ const { open: openMode = "multiple", openAll = false, reveal: revealOnOpen = false, selection: selectionMode = "cascade", active: activeMode = "single", openStrategy, ...options } = _options;
2522
+ const mandatoryOption = _options.mandatory ?? false;
2523
+ const multipleOption = _options.multiple ?? true;
2524
+ const resolvedOpenStrategy = openStrategy ?? resolveOpenStrategy(openMode);
2525
+ const group = createGroup(options);
2526
+ const logger$1 = useLogger();
2527
+ const children = shallowReactive(/* @__PURE__ */ new Map());
2528
+ const parents = shallowReactive(/* @__PURE__ */ new Map());
2529
+ const openedIds = shallowReactive(/* @__PURE__ */ new Set());
2530
+ const activeIds = shallowReactive(/* @__PURE__ */ new Set());
2531
+ const rootIds = shallowReactive(/* @__PURE__ */ new Set());
2532
+ let batching = false;
2533
+ let pendingChildren;
2534
+ let pendingParents;
2535
+ let pendingRoots;
2536
+ const activeItems = computed(() => {
2537
+ return new Set(Array.from(activeIds).map((id) => group.get(id)).filter((item) => !/* @__PURE__ */ isUndefined(item)));
2538
+ });
2539
+ const activeIndexes = computed(() => {
2540
+ return new Set(Array.from(activeItems.value).map((item) => item?.index).filter((index) => !/* @__PURE__ */ isUndefined(index)));
2541
+ });
2542
+ const openedItems = computed(() => {
2543
+ return new Set(Array.from(openedIds).map((id) => group.get(id)).filter((item) => !/* @__PURE__ */ isUndefined(item)));
2544
+ });
2545
+ const roots = computed(() => {
2546
+ return Array.from(rootIds).map((id) => group.get(id)).filter((item) => !/* @__PURE__ */ isUndefined(item));
2547
+ });
2548
+ const leaves = computed(() => {
2549
+ return group.values().filter((item) => {
2550
+ const childList = children.get(item.id);
2551
+ return /* @__PURE__ */ isUndefined(childList) || childList.length === 0;
2552
+ });
2553
+ });
2554
+ function opened(id) {
2555
+ return openedIds.has(id);
2556
+ }
2557
+ function open(ids) {
2558
+ for (const id of toArray(ids)) {
2559
+ if (!group.has(id)) continue;
2560
+ if (revealOnOpen) {
2561
+ let parentId = parents.get(id);
2562
+ while (!/* @__PURE__ */ isUndefined(parentId)) {
2563
+ openedIds.add(parentId);
2564
+ parentId = parents.get(parentId);
2565
+ }
2566
+ }
2567
+ openedIds.add(id);
2568
+ resolvedOpenStrategy.onOpen?.(id, context);
2569
+ }
2570
+ }
2571
+ function close(ids) {
2572
+ for (const id of toArray(ids)) {
2573
+ if (!group.has(id)) continue;
2574
+ openedIds.delete(id);
2575
+ resolvedOpenStrategy.onClose?.(id, context);
2576
+ }
2577
+ }
2578
+ function flip(ids) {
2579
+ for (const id of toArray(ids)) {
2580
+ if (!group.has(id)) continue;
2581
+ if (opened(id)) close(id);
2582
+ else open(id);
2583
+ }
2584
+ }
2585
+ /**
2586
+ * Open node(s) and their immediate non-leaf children.
2587
+ * Useful for expanding a section with its immediate subcategories.
2588
+ */
2589
+ function unfold(ids) {
2590
+ for (const id of toArray(ids)) {
2591
+ if (!group.has(id)) continue;
2592
+ open(id);
2593
+ const childIds = children.get(id) ?? [];
2594
+ for (const childId of childIds) if (!isLeaf(childId)) open(childId);
2595
+ }
2596
+ }
2597
+ /**
2598
+ * Reveal a node by opening all its ancestors.
2599
+ * Makes the node visible in a collapsed tree without opening the node itself.
2600
+ */
2601
+ function reveal(ids) {
2602
+ for (const id of toArray(ids)) {
2603
+ if (!group.has(id)) continue;
2604
+ const ancestorIds = getAncestors(id);
2605
+ if (ancestorIds.length > 0) open(ancestorIds);
2606
+ }
2607
+ }
2608
+ /**
2609
+ * Fully expand a node and all its non-leaf descendants.
2610
+ * Opens the entire subtree rooted at the given node.
2611
+ */
2612
+ function expand(ids) {
2613
+ for (const id of toArray(ids)) {
2614
+ if (!group.has(id)) continue;
2615
+ if (!isLeaf(id)) open(id);
2616
+ for (const descendantId of getDescendants(id)) if (!isLeaf(descendantId)) open(descendantId);
2617
+ }
2618
+ }
2619
+ function expandAll() {
2620
+ for (const [id, childList] of children) if (childList.length > 0) openedIds.add(id);
2621
+ }
2622
+ function collapseAll() {
2623
+ openedIds.clear();
2624
+ }
2625
+ function activated(id) {
2626
+ return activeIds.has(id);
2627
+ }
2628
+ function activate(ids) {
2629
+ for (const id of toArray(ids)) {
2630
+ if (!group.has(id)) continue;
2631
+ if (activeMode === "single") {
2632
+ for (const activeId of activeIds) if (activeId !== id) activeIds.delete(activeId);
2633
+ }
2634
+ activeIds.add(id);
2635
+ }
2636
+ }
2637
+ function deactivate(ids) {
2638
+ for (const id of toArray(ids)) activeIds.delete(id);
2639
+ }
2640
+ function deactivateAll() {
2641
+ activeIds.clear();
2642
+ }
2643
+ function getPath(id) {
2644
+ const path = [];
2645
+ let currentId = id;
2646
+ while (!/* @__PURE__ */ isUndefined(currentId)) {
2647
+ path.unshift(currentId);
2648
+ currentId = parents.get(currentId);
2649
+ }
2650
+ return path;
2651
+ }
2652
+ function getAncestors(id) {
2653
+ return getPath(id).slice(0, -1);
2654
+ }
2655
+ function getDescendants(id) {
2656
+ const descendants = [];
2657
+ const initial = children.get(id);
2658
+ if (!initial) return descendants;
2659
+ const queue = initial.slice();
2660
+ let index = 0;
2661
+ while (index < queue.length) {
2662
+ const currentId = queue[index++];
2663
+ descendants.push(currentId);
2664
+ const childIds = children.get(currentId);
2665
+ if (childIds) for (const cid of childIds) queue.push(cid);
2666
+ }
2667
+ return descendants;
2668
+ }
2669
+ function isLeaf(id) {
2670
+ const childList = children.get(id);
2671
+ return /* @__PURE__ */ isUndefined(childList) || childList.length === 0;
2672
+ }
2673
+ function getDepth(id) {
2674
+ return getAncestors(id).length;
2675
+ }
2676
+ /**
2677
+ * Check if `ancestorId` is an ancestor of `descendantId`.
2678
+ * Returns false if either ID doesn't exist in the tree.
2679
+ */
2680
+ function isAncestorOf(ancestorId, descendantId) {
2681
+ if (!group.has(ancestorId) || !group.has(descendantId)) return false;
2682
+ if (ancestorId === descendantId) return false;
2683
+ let currentId = parents.get(descendantId);
2684
+ while (!/* @__PURE__ */ isUndefined(currentId)) {
2685
+ if (currentId === ancestorId) return true;
2686
+ currentId = parents.get(currentId);
2687
+ }
2688
+ return false;
2689
+ }
2690
+ /**
2691
+ * Check if `id` has `ancestorId` as an ancestor.
2692
+ * Semantic alias for isAncestorOf(ancestorId, id).
2693
+ */
2694
+ function hasAncestor(id, ancestorId) {
2695
+ return isAncestorOf(ancestorId, id);
2696
+ }
2697
+ /**
2698
+ * Get siblings of a node (including self).
2699
+ * For root nodes, returns all root IDs.
2700
+ */
2701
+ function siblings(id) {
2702
+ if (!group.has(id)) return [];
2703
+ const parentId = parents.get(id);
2704
+ if (/* @__PURE__ */ isUndefined(parentId)) return group.values().filter((item) => /* @__PURE__ */ isUndefined(parents.get(item.id))).map((item) => item.id);
2705
+ return children.get(parentId) ?? [];
2706
+ }
2707
+ /**
2708
+ * Get 1-indexed position among siblings (for aria-posinset).
2709
+ * Returns 0 if node not found.
2710
+ */
2711
+ function position(id) {
2712
+ const index = siblings(id).indexOf(id);
2713
+ return index === -1 ? 0 : index + 1;
2714
+ }
2715
+ function updateAncestors(id) {
2716
+ const { selectedIds, mixedIds } = group;
2717
+ let parentId = parents.get(id);
2718
+ while (!/* @__PURE__ */ isUndefined(parentId)) {
2719
+ const childIds = children.get(parentId);
2720
+ if (childIds && childIds.length > 0) {
2721
+ const allSelected = childIds.every((cid) => selectedIds.has(cid));
2722
+ const someSelected = !allSelected && childIds.some((cid) => selectedIds.has(cid) || mixedIds.has(cid));
2723
+ if (allSelected) {
2724
+ mixedIds.delete(parentId);
2725
+ selectedIds.add(parentId);
2726
+ } else if (someSelected) {
2727
+ selectedIds.delete(parentId);
2728
+ mixedIds.add(parentId);
2729
+ } else {
2730
+ mixedIds.delete(parentId);
2731
+ selectedIds.delete(parentId);
2732
+ }
2733
+ }
2734
+ parentId = parents.get(parentId);
2735
+ }
2736
+ }
2737
+ function getLeafDescendants(id) {
2738
+ return getDescendants(id).filter((did) => isLeaf(did));
2739
+ }
2740
+ function select(ids) {
2741
+ for (const id of toArray(ids)) {
2742
+ if (!group.has(id)) continue;
2743
+ if (selectionMode === "independent") group.select(id);
2744
+ else if (selectionMode === "leaf") if (isLeaf(id)) group.select(id);
2745
+ else for (const lid of getLeafDescendants(id)) group.select(lid);
2746
+ else {
2747
+ if (!toValue(multipleOption)) {
2748
+ group.select(id);
2749
+ return;
2750
+ }
2751
+ const { selectedIds, mixedIds } = group;
2752
+ mixedIds.delete(id);
2753
+ selectedIds.add(id);
2754
+ for (const did of getDescendants(id)) {
2755
+ mixedIds.delete(did);
2756
+ selectedIds.add(did);
2757
+ }
2758
+ updateAncestors(id);
2759
+ }
2760
+ }
2761
+ }
2762
+ function unselect(ids) {
2763
+ for (const id of toArray(ids)) {
2764
+ if (!group.has(id)) continue;
2765
+ if (selectionMode === "independent") group.unselect(id);
2766
+ else if (selectionMode === "leaf") if (isLeaf(id)) group.unselect(id);
2767
+ else for (const lid of getLeafDescendants(id)) group.unselect(lid);
2768
+ else {
2769
+ const { selectedIds, mixedIds } = group;
2770
+ if (toValue(mandatoryOption)) {
2771
+ const toRemove = new Set([id, ...getDescendants(id)]);
2772
+ if ([...selectedIds].every((sid) => toRemove.has(sid))) return;
2773
+ }
2774
+ mixedIds.delete(id);
2775
+ selectedIds.delete(id);
2776
+ for (const did of getDescendants(id)) {
2777
+ mixedIds.delete(did);
2778
+ selectedIds.delete(did);
2779
+ }
2780
+ updateAncestors(id);
2781
+ }
2782
+ }
2783
+ }
2784
+ function toggle(ids) {
2785
+ for (const id of toArray(ids)) if (selectionMode === "independent") group.toggle(id);
2786
+ else if (selectionMode === "leaf") if (isLeaf(id)) group.toggle(id);
2787
+ else {
2788
+ const leafIds = getLeafDescendants(id);
2789
+ if (leafIds.every((lid) => group.selected(lid))) for (const lid of leafIds) group.unselect(lid);
2790
+ else for (const lid of leafIds) group.select(lid);
2791
+ }
2792
+ else if (group.selected(id) || group.mixed(id)) unselect(id);
2793
+ else select(id);
2794
+ }
2795
+ /**
2796
+ * Converts the tree to a flat array with parentId references.
2797
+ * Useful for serialization or sending to APIs/AI systems.
2798
+ */
2799
+ function toFlat() {
2800
+ return group.values().map((item) => ({
2801
+ id: item.id,
2802
+ parentId: parents.get(item.id),
2803
+ value: item.value
2804
+ }));
2805
+ }
2806
+ function register(registration = {}) {
2807
+ const id = registration.id ?? /* @__PURE__ */ useId$1();
2808
+ const parentId = registration.parentId;
2809
+ const nested = registration.children;
2810
+ if (!/* @__PURE__ */ isUndefined(parentId) && !group.has(parentId)) logger$1.warn(`Parent with id "${parentId}" does not exist. Registering "${id}" without parent.`);
2811
+ if (!/* @__PURE__ */ isUndefined(parentId) && group.has(parentId)) {
2812
+ if (batching) {
2813
+ pendingParents.set(id, parentId);
2814
+ const pending = pendingChildren.get(parentId);
2815
+ if (pending) pending.push(id);
2816
+ else {
2817
+ const existing = children.get(parentId);
2818
+ const list = existing ? [...existing, id] : [id];
2819
+ pendingChildren.set(parentId, list);
2820
+ }
2821
+ } else {
2822
+ parents.set(id, parentId);
2823
+ const list = children.get(parentId);
2824
+ children.set(parentId, list ? [...list, id] : [id]);
2825
+ }
2826
+ if (openAll) openedIds.add(parentId);
2827
+ } else if (batching) {
2828
+ pendingParents.set(id, void 0);
2829
+ pendingRoots.add(id);
2830
+ } else {
2831
+ parents.set(id, void 0);
2832
+ rootIds.add(id);
2833
+ }
2834
+ const { children: _, ...rest } = registration;
2835
+ const item = {
2836
+ ...rest,
2837
+ id,
2838
+ parentId: batching ? pendingParents.get(id) : parents.get(id),
2839
+ isOpen: toRef(() => opened(id)),
2840
+ isActive: toRef(() => activated(id)),
2841
+ isLeaf: toRef(() => isLeaf(id)),
2842
+ depth: toRef(() => getDepth(id)),
2843
+ open: () => open(id),
2844
+ close: () => close(id),
2845
+ flip: () => flip(id),
2846
+ reveal: () => reveal(id),
2847
+ activate: () => activate(id),
2848
+ deactivate: () => deactivate(id),
2849
+ getPath: () => getPath(id),
2850
+ getAncestors: () => getAncestors(id),
2851
+ getDescendants: () => getDescendants(id),
2852
+ isAncestorOf: (descendantId) => isAncestorOf(id, descendantId),
2853
+ hasAncestor: (ancestorId) => hasAncestor(id, ancestorId),
2854
+ siblings: () => siblings(id),
2855
+ position: () => position(id)
2856
+ };
2857
+ const ticket = group.register(item);
2858
+ if (registration.active) activate(id);
2859
+ if (nested?.length) for (const child of nested) register({
2860
+ ...child,
2861
+ parentId: id
2862
+ });
2863
+ return ticket;
2864
+ }
2865
+ function unregister(id, cascade = false) {
2866
+ if (!group.has(id)) return;
2867
+ const parentId = parents.get(id);
2868
+ if (!/* @__PURE__ */ isUndefined(parentId)) {
2869
+ const siblings$1 = children.get(parentId);
2870
+ if (siblings$1) {
2871
+ const filtered = siblings$1.filter((sid) => sid !== id);
2872
+ if (filtered.length === 0) children.delete(parentId);
2873
+ else children.set(parentId, filtered);
2874
+ }
2875
+ }
2876
+ const list = children.get(id);
2877
+ if (list?.length) if (cascade) {
2878
+ const descendantIds = getDescendants(id);
2879
+ for (const did of descendantIds) {
2880
+ parents.delete(did);
2881
+ children.delete(did);
2882
+ openedIds.delete(did);
2883
+ activeIds.delete(did);
2884
+ rootIds.delete(did);
2885
+ }
2886
+ group.offboard(descendantIds);
2887
+ } else {
2888
+ for (const did of getDescendants(id)) {
2889
+ openedIds.delete(did);
2890
+ activeIds.delete(did);
2891
+ }
2892
+ for (const cid of list) {
2893
+ parents.set(cid, void 0);
2894
+ rootIds.add(cid);
2895
+ }
2896
+ }
2897
+ parents.delete(id);
2898
+ children.delete(id);
2899
+ openedIds.delete(id);
2900
+ activeIds.delete(id);
2901
+ rootIds.delete(id);
2902
+ group.unregister(id);
2903
+ }
2904
+ function offboard(ids, cascade = false) {
2905
+ for (const id of ids) unregister(id, cascade);
2906
+ }
2907
+ function onboard(registrations) {
2908
+ batching = true;
2909
+ pendingChildren = /* @__PURE__ */ new Map();
2910
+ pendingParents = /* @__PURE__ */ new Map();
2911
+ pendingRoots = /* @__PURE__ */ new Set();
2912
+ try {
2913
+ const result = group.batch(() => registrations.map((registration) => register(registration)));
2914
+ for (const [id, list] of pendingChildren) children.set(id, list);
2915
+ for (const [id, pid] of pendingParents) parents.set(id, pid);
2916
+ for (const id of pendingRoots) rootIds.add(id);
2917
+ return result;
2918
+ } finally {
2919
+ batching = false;
2920
+ pendingChildren = void 0;
2921
+ pendingParents = void 0;
2922
+ pendingRoots = void 0;
2923
+ }
2924
+ }
2925
+ function clear() {
2926
+ children.clear();
2927
+ parents.clear();
2928
+ openedIds.clear();
2929
+ activeIds.clear();
2930
+ rootIds.clear();
2931
+ group.reset();
2932
+ }
2933
+ function reset() {
2934
+ clear();
2935
+ }
2936
+ const context = {
2937
+ ...group,
2938
+ children,
2939
+ parents,
2940
+ openedIds,
2941
+ openedItems,
2942
+ activeIds,
2943
+ activeItems,
2944
+ activeIndexes,
2945
+ roots,
2946
+ leaves,
2947
+ getPath,
2948
+ getAncestors,
2949
+ getDescendants,
2950
+ isLeaf,
2951
+ getDepth,
2952
+ isAncestorOf,
2953
+ hasAncestor,
2954
+ siblings,
2955
+ position,
2956
+ open,
2957
+ close,
2958
+ flip,
2959
+ opened,
2960
+ unfold,
2961
+ reveal,
2962
+ expand,
2963
+ expandAll,
2964
+ collapseAll,
2965
+ activate,
2966
+ deactivate,
2967
+ activated,
2968
+ deactivateAll,
2969
+ toFlat,
2970
+ openStrategy: resolvedOpenStrategy,
2971
+ select,
2972
+ unselect,
2973
+ toggle,
2974
+ register,
2975
+ unregister,
2976
+ offboard,
2977
+ onboard,
2978
+ clear,
2979
+ reset,
2980
+ get size() {
2981
+ return group.size;
2982
+ }
2983
+ };
2984
+ return context;
2985
+ }
2986
+ /**
2987
+ * Creates a new nested context with provide/inject pattern.
2988
+ *
2989
+ * @param options The options for the nested context.
2990
+ * @returns A trinity tuple [useNested, provideNested, defaultNested]
2991
+ *
2992
+ * @see https://0.vuetifyjs.com/composables/selection/use-nested
2993
+ *
2994
+ * @example
2995
+ * ```ts
2996
+ * import { createNestedContext } from '@vuetify/v0'
2997
+ *
2998
+ * export const [useTree, provideTree, tree] = createNestedContext()
2999
+ *
3000
+ * // In parent: provideTree()
3001
+ * // In child: const tree = useTree()
3002
+ * ```
3003
+ */
3004
+ function createNestedContext(_options = {}) {
3005
+ const { namespace = "v0:nested", ...options } = _options;
3006
+ const [useNestedContext, _provideNestedContext] = createContext(namespace);
3007
+ const context = createNested(options);
3008
+ function provideNestedContext(_context = context, app) {
3009
+ return _provideNestedContext(_context, app);
3010
+ }
3011
+ return createTrinity(useNestedContext, provideNestedContext, context);
3012
+ }
3013
+ /**
3014
+ * Returns the current nested instance from context.
3015
+ *
3016
+ * @param namespace The namespace for the nested context. Defaults to `'v0:nested'`.
3017
+ * @returns The current nested instance.
3018
+ *
3019
+ * @see https://0.vuetifyjs.com/composables/selection/use-nested
3020
+ */
3021
+ function useNested(namespace = "v0:nested") {
3022
+ return useContext(namespace);
3023
+ }
3024
+
3025
+ //#endregion
3026
+ //#region src/composables/createQueue/index.ts
3027
+ /**
3028
+ * @module createQueue
3029
+ *
3030
+ * @remarks
3031
+ * A queue composable for managing time-based collections with:
3032
+ * - Automatic timeout-based removal
3033
+ * - Pause/resume functionality
3034
+ * - FIFO (First In, First Out) ordering
3035
+ * - Manual dismissal support
3036
+ * - Queue progression management
3037
+ *
3038
+ * Built on top of createRegistry, the queue automatically manages timeouts for tickets,
3039
+ * ensuring only the first ticket in the queue is active at any time. When a ticket
3040
+ * expires or is removed, the next ticket in the queue automatically becomes active.
3041
+ */
3042
+ /**
3043
+ * Creates a new queue instance
3044
+ *
3045
+ * @param options The options for the queue instance
3046
+ * @template Z The type of queue ticket that extends QueueTicket. Use this to add custom properties to tickets.
3047
+ * @template E The type of queue context that extends QueueContext<Z>. Use this when extending the queue with additional methods.
3048
+ * @returns A new queue instance
3049
+ *
3050
+ * @see https://0.vuetifyjs.com/composables/registration/create-queue
3051
+ *
3052
+ * @example
3053
+ * ```ts
3054
+ * import { useQueue } from '@vuetify/v0'
3055
+ *
3056
+ * const queue = useQueue()
3057
+ *
3058
+ * // Register an ticket with default timeout (3000ms)
3059
+ * const ticket1 = queue.register({ value: 'Ticket 1' })
3060
+ *
3061
+ * // Register an ticket with custom timeout
3062
+ * const ticket2 = queue.register({ value: 'Ticket 2', timeout: 5000 })
3063
+ *
3064
+ * // Register a persistent ticket that must be manually dismissed
3065
+ * const ticket3 = queue.register({ value: 'Ticket 3', timeout: -1 })
3066
+ *
3067
+ * // Dismiss an ticket using the convenience method
3068
+ * ticket3.dismiss()
3069
+ *
3070
+ * console.log(queue.size) // 2
3071
+ * ```
3072
+ */
3073
+ function createQueue(_options = {}) {
3074
+ const { timeout: _timeout = 3e3, ...options } = _options;
3075
+ const registry = createRegistry({
3076
+ ...options,
3077
+ events: true
3078
+ });
3079
+ const timeouts = /* @__PURE__ */ new Map();
3080
+ function startTimeout(ticket) {
3081
+ if (/* @__PURE__ */ isUndefined(ticket.timeout) || ticket.timeout < 0 || ticket.isPaused) return;
3082
+ const timeout = setTimeout(() => {
3083
+ timeouts.delete(ticket.id);
3084
+ registry.unregister(ticket.id);
3085
+ resume();
3086
+ }, ticket.timeout);
3087
+ timeouts.set(ticket.id, timeout);
3088
+ }
3089
+ function clearTimeout$1(id) {
3090
+ const timeout = timeouts.get(id);
3091
+ if (timeout) {
3092
+ globalThis.clearTimeout(timeout);
3093
+ timeouts.delete(id);
3094
+ }
3095
+ }
3096
+ function register(registration = {}) {
3097
+ const id = registration.id ?? /* @__PURE__ */ useId$1();
3098
+ const timeout = Object.prototype.hasOwnProperty.call(registration, "timeout") ? registration.timeout : _timeout;
3099
+ const ticket = {
3100
+ ...registration,
3101
+ id,
3102
+ timeout,
3103
+ isPaused: registry.size > 0,
3104
+ dismiss: () => unregister(id)
3105
+ };
3106
+ const registered = registry.register(ticket);
3107
+ startTimeout(registered);
3108
+ return registered;
3109
+ }
3110
+ function unregister(id) {
3111
+ const ticket = /* @__PURE__ */ isUndefined(id) ? registry.seek("first") : registry.get(id);
3112
+ if (!ticket) return void 0;
3113
+ const wasFirst = ticket.index === 0;
3114
+ clearTimeout$1(ticket.id);
3115
+ registry.unregister(ticket.id);
3116
+ if (wasFirst) resume();
3117
+ return ticket;
3118
+ }
3119
+ function offboard(ids) {
3120
+ let hadFirst = false;
3121
+ for (const id of ids) {
3122
+ const ticket = registry.get(id);
3123
+ if (!ticket) continue;
3124
+ if (ticket.index === 0) hadFirst = true;
3125
+ clearTimeout$1(ticket.id);
3126
+ }
3127
+ registry.offboard(ids);
3128
+ if (hadFirst) resume();
3129
+ }
3130
+ function pause() {
3131
+ const ticket = registry.seek("first");
3132
+ if (!ticket || ticket.isPaused) return void 0;
3133
+ clearTimeout$1(ticket.id);
3134
+ return registry.upsert(ticket.id, { isPaused: true });
3135
+ }
3136
+ function resume() {
3137
+ const ticket = registry.seek("first");
3138
+ if (!ticket || ticket.index !== 0 || !ticket.isPaused) return void 0;
3139
+ const updated = registry.upsert(ticket.id, { isPaused: false });
3140
+ startTimeout(updated);
3141
+ return updated;
3142
+ }
3143
+ function clear() {
3144
+ for (const id of timeouts.keys()) clearTimeout$1(id);
3145
+ registry.clear();
3146
+ }
3147
+ function dispose() {
3148
+ clear();
3149
+ registry.dispose();
3150
+ }
3151
+ onScopeDispose(dispose, true);
3152
+ function onboard(registrations) {
3153
+ return registry.batch(() => registrations.map((registration) => register(registration)));
3154
+ }
3155
+ return {
3156
+ ...registry,
3157
+ register,
3158
+ unregister,
3159
+ onboard,
3160
+ offboard,
3161
+ pause,
3162
+ resume,
3163
+ clear,
3164
+ dispose,
3165
+ get size() {
3166
+ return registry.size;
3167
+ }
3168
+ };
3169
+ }
3170
+ /**
3171
+ * Creates a new queue context.
3172
+ *
3173
+ * @param options The options for the queue context.
3174
+ * @template Z The type of the queue ticket.
3175
+ * @template E The type of the queue context.
3176
+ * @returns A new queue context.
3177
+ *
3178
+ * @see https://0.vuetifyjs.com/composables/registration/create-queue
3179
+ *
3180
+ * @example
3181
+ * ```ts
3182
+ * import { createQueueContext } from '@vuetify/v0'
3183
+ *
3184
+ * export const [useQueue, provideQueue, context] = createQueueContext({
3185
+ * timeout: 5000,
3186
+ * })
3187
+ * ```
3188
+ */
3189
+ function createQueueContext(_options = {}) {
3190
+ const { namespace = "v0:queue", ...options } = _options;
3191
+ const [useQueueContext, _provideQueueContext] = createContext(namespace);
3192
+ const context = createQueue(options);
3193
+ function provideQueueContext(_context = context, app) {
3194
+ return _provideQueueContext(_context, app);
3195
+ }
3196
+ return createTrinity(useQueueContext, provideQueueContext, context);
3197
+ }
3198
+ /**
3199
+ * Returns the current queue instance.
3200
+ *
3201
+ * @param namespace The namespace for the queue context. Defaults to `'v0:queue'`.
3202
+ * @returns The current queue instance.
3203
+ *
3204
+ * @see https://0.vuetifyjs.com/composables/registration/create-queue
3205
+ *
3206
+ * @example
3207
+ * ```vue
3208
+ * <script setup lang="ts">
3209
+ * import { useQueue } from '@vuetify/v0'
3210
+ *
3211
+ * const queue = useQueue()
3212
+ * <\/script>
3213
+ * ```
3214
+ */
3215
+ function useQueue(namespace = "v0:queue") {
3216
+ return useContext(namespace);
3217
+ }
3218
+
3219
+ //#endregion
3220
+ //#region src/composables/useStack/index.ts
3221
+ /**
3222
+ * @module useStack
3223
+ *
3224
+ * @see https://0.vuetifyjs.com/composables/plugins/use-stack
3225
+ *
3226
+ * @remarks
3227
+ * Overlay z-index stacking composable with:
3228
+ * - Global reactive registry of active overlays
3229
+ * - Automatic z-index calculation based on selection order
3230
+ * - `globalTop` tracking - is this ticket topmost globally?
3231
+ * - Manual select/unselect for explicit control
3232
+ * - Auto-cleanup when registered within component setup
3233
+ *
3234
+ * Built on createSelection for consistent ticket-based management.
3235
+ */
3236
+ /**
3237
+ * Creates a new stack instance for managing overlay z-indexes.
3238
+ *
3239
+ * @param options Configuration options
3240
+ * @returns Stack context with registry methods and scrim helpers
3241
+ *
3242
+ * @see https://0.vuetifyjs.com/composables/plugins/use-stack
3243
+ *
3244
+ * @example
3245
+ * ```ts
3246
+ * import { createStack } from '@vuetify/v0'
3247
+ *
3248
+ * const stack = createStack({ baseZIndex: 1000 })
3249
+ *
3250
+ * const ticket = stack.register({
3251
+ * onDismiss: () => console.log('dismissed'),
3252
+ * blocking: false,
3253
+ * })
3254
+ *
3255
+ * ticket.select() // Activate overlay
3256
+ * console.log(ticket.zIndex.value) // 1000
3257
+ *
3258
+ * ticket.unselect() // Deactivate overlay
3259
+ * ```
3260
+ */
3261
+ function createStack(_options = {}) {
3262
+ const { baseZIndex = 2e3, increment = 10, ...options } = _options;
3263
+ const selection = createSelection({
3264
+ ...options,
3265
+ multiple: true
3266
+ });
3267
+ const isActive = toRef(() => selection.selectedIds.size > 0);
3268
+ const top = toRef(() => {
3269
+ const ids$1 = Array.from(selection.selectedIds);
3270
+ if (ids$1.length === 0) return void 0;
3271
+ return selection.get(ids$1.at(-1));
3272
+ });
3273
+ const scrimZIndex = toRef(() => {
3274
+ const ticket = top.value;
3275
+ return ticket ? ticket.zIndex.value - 1 : 0;
3276
+ });
3277
+ const isBlocking = toRef(() => top.value?.blocking ?? false);
3278
+ function ids() {
3279
+ return Array.from(selection.selectedIds);
3280
+ }
3281
+ function register(input = {}) {
3282
+ const id = input.id ?? /* @__PURE__ */ useId$1();
3283
+ const blocking = input.blocking ?? false;
3284
+ const onDismiss = input.onDismiss;
3285
+ const zIndex = computed(() => {
3286
+ const position = ids().indexOf(id);
3287
+ if (position === -1) return baseZIndex;
3288
+ return baseZIndex + position * increment;
3289
+ });
3290
+ const globalTop = computed(() => {
3291
+ const list = ids();
3292
+ if (list.length === 0) return false;
3293
+ return list.at(-1) === id;
3294
+ });
3295
+ function dismiss() {
3296
+ if (blocking) return;
3297
+ onDismiss?.();
3298
+ selection.unselect(id);
3299
+ }
3300
+ const ticket = selection.register({
3301
+ blocking,
3302
+ onDismiss,
3303
+ zIndex,
3304
+ globalTop,
3305
+ dismiss,
3306
+ ...input,
3307
+ id
3308
+ });
3309
+ if (instanceExists()) onScopeDispose(() => {
3310
+ selection.unregister(id);
3311
+ }, true);
3312
+ return ticket;
3313
+ }
3314
+ return {
3315
+ ...selection,
3316
+ register,
3317
+ isActive,
3318
+ top,
3319
+ scrimZIndex,
3320
+ isBlocking,
3321
+ get size() {
3322
+ return selection.size;
3323
+ }
3324
+ };
3325
+ }
3326
+ /**
3327
+ * Creates a stack context trinity for provide/inject usage.
3328
+ *
3329
+ * @param options Configuration options including namespace
3330
+ * @returns Trinity of [useStackContext, provideStackContext, context]
3331
+ *
3332
+ * @see https://0.vuetifyjs.com/composables/plugins/use-stack
3333
+ *
3334
+ * @example
3335
+ * ```ts
3336
+ * import { createStackContext } from '@vuetify/v0'
3337
+ *
3338
+ * const [useMyStack, provideMyStack, myStack] = createStackContext({
3339
+ * namespace: 'my:stack',
3340
+ * baseZIndex: 3000,
3341
+ * })
3342
+ *
3343
+ * // In parent component:
3344
+ * provideMyStack()
3345
+ *
3346
+ * // In child component:
3347
+ * const stack = useMyStack()
3348
+ * ```
3349
+ */
3350
+ function createStackContext(_options = {}) {
3351
+ const { namespace = "v0:stack", ...options } = _options;
3352
+ const [useStackContext, _provideStackContext] = createContext(namespace);
3353
+ const context = createStack(options);
3354
+ function provideStackContext(_context = context, app) {
3355
+ return _provideStackContext(_context, app);
3356
+ }
3357
+ return createTrinity(useStackContext, provideStackContext, context);
3358
+ }
3359
+ /**
3360
+ * Creates a Vue plugin to provide stack context at app level.
3361
+ *
3362
+ * @param options Configuration options
3363
+ * @returns Vue plugin instance
3364
+ *
3365
+ * @see https://0.vuetifyjs.com/composables/plugins/use-stack
3366
+ *
3367
+ * @example
3368
+ * ```ts
3369
+ * import { createApp } from 'vue'
3370
+ * import { createStackPlugin } from '@vuetify/v0'
3371
+ *
3372
+ * const app = createApp(App)
3373
+ * app.use(createStackPlugin({ baseZIndex: 2000 }))
3374
+ * app.mount('#app')
3375
+ * ```
3376
+ */
3377
+ function createStackPlugin(_options = {}) {
3378
+ const { namespace = "v0:stack", ...options } = _options;
3379
+ const [, provideStackContext, context] = createStackContext({
3380
+ ...options,
3381
+ namespace
3382
+ });
3383
+ return createPlugin({
3384
+ namespace,
3385
+ provide: (app) => {
3386
+ provideStackContext(context, app);
3387
+ }
3388
+ });
3389
+ }
3390
+ let fallbackStack;
3391
+ function getStackFallback() {
3392
+ if (!fallbackStack) fallbackStack = createStack();
3393
+ return fallbackStack;
3394
+ }
3395
+ /**
3396
+ * Returns the current stack context.
3397
+ *
3398
+ * @param namespace The namespace for the stack context. Defaults to 'v0:stack'.
3399
+ * @returns The stack context instance
3400
+ *
3401
+ * @remarks Falls back to an internal shared instance if no provider exists.
3402
+ * For SSR safety, use createStackPlugin to provide isolated context per app.
3403
+ *
3404
+ * Tickets registered within component setup are automatically unregistered
3405
+ * when the component is unmounted.
3406
+ *
3407
+ * @see https://0.vuetifyjs.com/composables/plugins/use-stack
3408
+ *
3409
+ * @example
3410
+ * ```vue
3411
+ * <script setup lang="ts">
3412
+ * import { shallowRef, watch } from 'vue'
3413
+ * import { useStack } from '@vuetify/v0'
3414
+ *
3415
+ * const stack = useStack()
3416
+ * const isOpen = shallowRef(false)
3417
+ *
3418
+ * // Ticket is auto-cleaned up when component unmounts
3419
+ * const ticket = stack.register({
3420
+ * onDismiss: () => { isOpen.value = false },
3421
+ * })
3422
+ *
3423
+ * // Sync selection state with isOpen
3424
+ * watch(isOpen, v => v ? ticket.select() : ticket.unselect())
3425
+ * <\/script>
3426
+ *
3427
+ * <template>
3428
+ * <button @click="isOpen = true">Open</button>
3429
+ * <div v-if="isOpen" :style="{ zIndex: ticket.zIndex.value }">
3430
+ * <p>Dialog content</p>
3431
+ * <button @click="ticket.dismiss()">Close</button>
3432
+ * </div>
3433
+ * </template>
3434
+ * ```
3435
+ */
3436
+ function useStack(namespace = "v0:stack") {
3437
+ const fallback = getStackFallback();
3438
+ if (!instanceExists()) return fallback;
3439
+ try {
3440
+ return useContext(namespace);
3441
+ } catch {
3442
+ return fallback;
3443
+ }
3444
+ }
3445
+
3446
+ //#endregion
3447
+ //#region src/composables/createStep/index.ts
3448
+ /**
3449
+ * @module useStep
3450
+ *
3451
+ * @remarks
3452
+ * Navigation composable that extends useSingle with first/last/next/prev/step methods.
3453
+ *
3454
+ * Key features:
3455
+ * - Configurable circular or bounded navigation
3456
+ * - Automatic disabled item skipping
3457
+ * - Arbitrary step counts (positive/negative)
3458
+ * - Perfect for wizards, carousels, pagination, onboarding flows
3459
+ *
3460
+ * Inheritance chain: useRegistry → useSelection → useSingle → useStep
3461
+ */
3462
+ /**
3463
+ * Creates a new step instance with navigation through items.
3464
+ *
3465
+ * Extends `createSingle` with `first()`, `last()`, `next()`, `prev()`, and `step(count)` methods
3466
+ * for sequential navigation. Supports both circular (wrapping) and bounded (stopping at edges) modes.
3467
+ *
3468
+ * @param options The options for the step instance.
3469
+ * @template Z The type of the step ticket.
3470
+ * @template E The type of the step context.
3471
+ * @returns A new step instance with navigation methods.
3472
+ *
3473
+ * @remarks
3474
+ * **Key Features:**
3475
+ * - **Configurable Navigation**: `circular: true` for wrapping, `false` for bounded (default: false)
3476
+ * - **Disabled Item Skipping**: Automatically skips disabled items during navigation
3477
+ * - **Bidirectional**: Forward (`next`, positive `step`) and backward (`prev`, negative `step`)
3478
+ * - **Safe Edge Cases**: Handles empty registries and all-disabled scenarios gracefully
3479
+ *
3480
+ * **Navigation Methods:**
3481
+ * - `first()`: Select first non-disabled item
3482
+ * - `last()`: Select last non-disabled item
3483
+ * - `next()`: Move to next item (wraps if circular, stops at end if bounded)
3484
+ * - `prev()`: Move to previous item (wraps if circular, stops at start if bounded)
3485
+ * - `step(count)`: Move by `count` positions (negative for backward)
3486
+ *
3487
+ * **Circular Mode (`circular: true`):**
3488
+ * - Uses modulo arithmetic for wrapping: `((index % length) + length) % length`
3489
+ * - Works correctly with negative indexes and large step counts
3490
+ * - Perfect for carousels, theme switchers, infinite scrolling
3491
+ *
3492
+ * **Bounded Mode (`circular: false`, default):**
3493
+ * - Navigation stops at boundaries (no wrapping)
3494
+ * - `next()` on last item does nothing
3495
+ * - `prev()` on first item does nothing
3496
+ * - Perfect for pagination, wizards with explicit completion, forms
3497
+ *
3498
+ * **Inheritance Chain:**
3499
+ * `useRegistry` → `createSelection` → `createSingle` → `createStep`
3500
+ *
3501
+ * @see https://0.vuetifyjs.com/composables/selection/use-step
3502
+ *
3503
+ * @example
3504
+ * ```ts
3505
+ * import { createStep } from '@vuetify/v0'
3506
+ *
3507
+ * // Bounded navigation (default) - for pagination
3508
+ * const pagination = createStep({ circular: false })
3509
+ * pagination.onboard([
3510
+ * { id: 'page-1', value: 1 },
3511
+ * { id: 'page-2', value: 2 },
3512
+ * { id: 'page-3', value: 3 },
3513
+ * ])
3514
+ * pagination.first() // Select page 1
3515
+ * pagination.prev() // Does nothing (already at first)
3516
+ * pagination.next() // Select page 2
3517
+ *
3518
+ * // Circular navigation - for carousels
3519
+ * const carousel = createStep({ circular: true })
3520
+ * carousel.onboard([
3521
+ * { id: 'slide-1', value: 'First' },
3522
+ * { id: 'slide-2', value: 'Second' },
3523
+ * { id: 'slide-3', value: 'Third' },
3524
+ * ])
3525
+ * carousel.first()
3526
+ * carousel.prev() // Wraps to 'slide-3'
3527
+ * carousel.next() // Wraps to 'slide-1'
3528
+ * ```
3529
+ */
3530
+ function createStep(_options = {}) {
3531
+ const { circular = false, ...options } = _options;
3532
+ const registry = createSingle(options);
3533
+ function first() {
3534
+ const ticket = registry.seek("first");
3535
+ if (ticket) registry.select(ticket.id);
3536
+ }
3537
+ function last() {
3538
+ const ticket = registry.seek("last");
3539
+ if (ticket) registry.select(ticket.id);
3540
+ }
3541
+ function next() {
3542
+ step(1);
3543
+ }
3544
+ function prev() {
3545
+ step(-1);
3546
+ }
3547
+ function wrapped(length, index) {
3548
+ return (index % length + length) % length;
3549
+ }
3550
+ function step(count = 1) {
3551
+ const length = registry.size;
3552
+ if (!length) return;
3553
+ const currentIndex = registry.selectedIndex.value;
3554
+ const direction = Math.sign(count || 1);
3555
+ let hops = 0;
3556
+ let index = circular ? wrapped(length, currentIndex + count) : currentIndex + count;
3557
+ if (!circular && (index < 0 || index >= length)) return;
3558
+ let id = registry.lookup(index);
3559
+ while (!/* @__PURE__ */ isUndefined(id) && toValue(registry.get(id)?.disabled) && hops < length) {
3560
+ index = circular ? wrapped(length, index + direction) : index + direction;
3561
+ if (!circular && (index < 0 || index >= length)) return;
3562
+ id = registry.lookup(index);
3563
+ hops++;
3564
+ }
3565
+ if (/* @__PURE__ */ isUndefined(id) || hops === length) return;
3566
+ registry.selectedIds.clear();
3567
+ registry.select(id);
3568
+ }
3569
+ return {
3570
+ ...registry,
3571
+ first,
3572
+ last,
3573
+ next,
3574
+ prev,
3575
+ step,
3576
+ get size() {
3577
+ return registry.size;
3578
+ }
3579
+ };
3580
+ }
3581
+ /**
3582
+ * Creates a new step context.
3583
+ *
3584
+ * @param options The options for the step context.
3585
+ * @template Z The input ticket type.
3586
+ * @template E The output ticket type.
3587
+ * @template R The context type.
3588
+ * @returns A new step context.
3589
+ *
3590
+ * @see https://0.vuetifyjs.com/composables/selection/use-step
3591
+ *
3592
+ * @example
3593
+ * ```ts
3594
+ * import { createStepContext } from '@vuetify/v0'
3595
+ *
3596
+ * // With default namespace 'v0:step'
3597
+ * export const [useStep, provideStep, context] = createStepContext()
3598
+ *
3599
+ * // In a parent component:
3600
+ * provideStep()
3601
+ *
3602
+ * // In a child component:
3603
+ * const context = useStep()
3604
+ * context.next() // Progress to next step
3605
+ * ```
3606
+ */
3607
+ function createStepContext(_options = {}) {
3608
+ const { namespace = "v0:step", ...options } = _options;
3609
+ const [useStepContext, _provideStepContext] = createContext(namespace);
3610
+ const context = createStep(options);
3611
+ function provideStepContext(_context = context, app) {
3612
+ return _provideStepContext(_context, app);
3613
+ }
3614
+ return createTrinity(useStepContext, provideStepContext, context);
3615
+ }
3616
+ /**
3617
+ * Returns the current step instance.
3618
+ *
3619
+ * @param namespace The namespace for the step context. Defaults to `'v0:step'`.
3620
+ * @template Z The input ticket type.
3621
+ * @template E The output ticket type.
3622
+ * @template R The context type.
3623
+ * @returns The current step instance.
3624
+ *
3625
+ * @see https://0.vuetifyjs.com/composables/selection/use-step
3626
+ *
3627
+ * @example
3628
+ * ```vue
3629
+ * <script setup lang="ts">
3630
+ * import { useStep } from '@vuetify/v0'
3631
+ *
3632
+ * const wizard = useStep()
3633
+ * <\/script>
3634
+ *
3635
+ * <template>
3636
+ * <div>
3637
+ * <p>Current step: {{ wizard.selectedIndex }}</p>
3638
+ * <button @click="wizard.next()">Next</button>
3639
+ * </div>
3640
+ * </template>
3641
+ * ```
3642
+ */
3643
+ function useStep(namespace = "v0:step") {
3644
+ return useContext(namespace);
3645
+ }
3646
+
3647
+ //#endregion
3648
+ //#region src/composables/useStorage/index.ts
3649
+ /**
3650
+ * @module useStorage
3651
+ *
3652
+ * @remarks
3653
+ * Reactive storage composable with adapter pattern for localStorage, sessionStorage, or memory.
3654
+ *
3655
+ * Key features:
3656
+ * - Reactive refs that sync with storage
3657
+ * - localStorage, sessionStorage, and memory adapters
3658
+ * - Custom serialization support
3659
+ * - SSR fallback to memory adapter
3660
+ * - Automatic cleanup on remove/clear
3661
+ *
3662
+ * Uses adapter pattern to abstract storage implementation details.
3663
+ */
3664
+ /**
3665
+ * Creates a new storage instance.
3666
+ *
3667
+ * @param options The options for the storage instance.
3668
+ * @template E The type of the storage context.
3669
+ * @returns A new storage instance.
3670
+ *
3671
+ * @see https://0.vuetifyjs.com/composables/plugins/use-storage
3672
+ *
3673
+ * @example
3674
+ * ```ts
3675
+ * import { createStorage } from '@vuetify/v0'
3676
+ *
3677
+ * const storage = createStorage()
3678
+ *
3679
+ * storage.set('username', 'MyUsername')
3680
+ *
3681
+ * const username = storage.get('username')
3682
+ *
3683
+ * console.log(username.value) // MyUsername
3684
+ *
3685
+ * storage.clear()
3686
+ * ```
3687
+ */
3688
+ function createStorage(options = {}) {
3689
+ const { adapter = IN_BROWSER ? window.localStorage : new MemoryAdapter(), prefix = "v0:", serializer = {
3690
+ read: JSON.parse,
3691
+ write: JSON.stringify
3692
+ } } = options;
3693
+ const cache = /* @__PURE__ */ new Map();
3694
+ const watchers = /* @__PURE__ */ new Map();
3695
+ function has(key) {
3696
+ const prefixedKey = `${prefix}${key}`;
3697
+ return cache.has(prefixedKey);
3698
+ }
3699
+ function get(key, defaultValue) {
3700
+ const prefixedKey = `${prefix}${key}`;
3701
+ if (cache.has(prefixedKey)) return cache.get(prefixedKey);
3702
+ const storedValue = adapter?.getItem(prefixedKey);
3703
+ let initialValue = defaultValue;
3704
+ if (storedValue) try {
3705
+ initialValue = serializer.read(storedValue);
3706
+ } catch (error) {
3707
+ console.error(`[v0:storage] Failed to parse stored value for key "${prefixedKey}":`, error);
3708
+ }
3709
+ const valueRef = ref(initialValue);
3710
+ const stop = watch(valueRef, (newValue) => {
3711
+ if (/* @__PURE__ */ isNullOrUndefined(newValue)) adapter?.removeItem(prefixedKey);
3712
+ else try {
3713
+ adapter?.setItem(prefixedKey, serializer.write(newValue));
3714
+ } catch (error) {
3715
+ console.error(`[v0:storage] Failed to write key "${prefixedKey}":`, error);
3716
+ }
3717
+ }, { deep: true });
3718
+ watchers.set(prefixedKey, stop);
3719
+ cache.set(prefixedKey, valueRef);
3720
+ return valueRef;
3721
+ }
3722
+ function set(key, value) {
3723
+ const valueRef = get(key);
3724
+ valueRef.value = value;
3725
+ }
3726
+ function remove(key) {
3727
+ const prefixedKey = `${prefix}${key}`;
3728
+ const stop = watchers.get(prefixedKey);
3729
+ if (!stop) return;
3730
+ stop();
3731
+ watchers.delete(prefixedKey);
3732
+ adapter?.removeItem(prefixedKey);
3733
+ cache.delete(prefixedKey);
3734
+ }
3735
+ function clear() {
3736
+ if (watchers.size > 0) {
3737
+ for (const stop of watchers.values()) stop();
3738
+ watchers.clear();
3739
+ }
3740
+ if (cache.size > 0) {
3741
+ for (const key of cache.keys()) adapter?.removeItem(key);
3742
+ cache.clear();
3743
+ }
3744
+ }
3745
+ if (IN_BROWSER && adapter === window.localStorage) useWindowEventListener("storage", (e) => {
3746
+ if (!e.key?.startsWith(prefix)) return;
3747
+ const valueRef = cache.get(e.key);
3748
+ if (!valueRef) return;
3749
+ watchers.get(e.key)?.();
3750
+ valueRef.value = e.newValue == null ? void 0 : serializer.read(e.newValue);
3751
+ const stop = watch(valueRef, (newValue) => {
3752
+ if (/* @__PURE__ */ isNullOrUndefined(newValue)) adapter?.removeItem(e.key);
3753
+ else try {
3754
+ adapter?.setItem(e.key, serializer.write(newValue));
3755
+ } catch (error) {
3756
+ console.error(`[v0:storage] Failed to write key "${e.key}":`, error);
3757
+ }
3758
+ }, { deep: true });
3759
+ watchers.set(e.key, stop);
3760
+ });
3761
+ return {
3762
+ has,
3763
+ get,
3764
+ set,
3765
+ remove,
3766
+ clear
3767
+ };
3768
+ }
3769
+ function createStorageFallback() {
3770
+ return createStorage({ adapter: new MemoryAdapter() });
3771
+ }
3772
+ const [createStorageContext, createStoragePlugin, useStorage] = createPluginContext("v0:storage", (options) => createStorage(options), { fallback: () => createStorageFallback() });
3773
+
3774
+ //#endregion
3775
+ //#region src/composables/createTimeline/index.ts
3776
+ /**
3777
+ * @module createTimeline
3778
+ *
3779
+ * @remarks
3780
+ * Bounded undo/redo system with overflow management.
3781
+ *
3782
+ * Key features:
3783
+ * - Fixed-size history (default: 10 items)
3784
+ * - Undo/redo stack management
3785
+ * - Overflow queue (preserves oldest items)
3786
+ * - Automatic reindexing after operations
3787
+ * - Perfect for command pattern, history tracking
3788
+ *
3789
+ * Extends createRegistry with temporal navigation capabilities.
3790
+ */
3791
+ /**
3792
+ * Creates a new timeline instance.
3793
+ *
3794
+ * @param _options The options for the timeline instance.
3795
+ * @template Z The type of the timeline ticket.
3796
+ * @template E The type of the timeline context.
3797
+ * @returns A new timeline instance.
3798
+ *
3799
+ * @see https://0.vuetifyjs.com/composables/registration/create-timeline
3800
+ *
3801
+ * @example
3802
+ * ```ts
3803
+ * import { useTimeline } from '@vuetify/v0'
3804
+ *
3805
+ * const timeline = useTimeline({ size: 3 })
3806
+ *
3807
+ * timeline.onboard([{ id: 'one' }, { id: 'two' }, { id: 'three' }])
3808
+ *
3809
+ * console.log(timeline.values()) // [{ id: 'one' }, { id: 'two' }, { id: 'three' }]
3810
+ *
3811
+ * timeline.undo()
3812
+ * console.log(timeline.values()) // [{ id: 'one' }, { id: 'two' }]
3813
+ *
3814
+ * timeline.redo()
3815
+ * console.log(timeline.values()) // [{ id: 'one' }, { id: 'two' }, { id: 'three' }]
3816
+ * ```
3817
+ */
3818
+ function createTimeline(_options = {}) {
3819
+ const { size = 10, ...options } = _options;
3820
+ const registry = createRegistry(options);
3821
+ const stack = [];
3822
+ const overflow = [];
3823
+ function register(item) {
3824
+ stack.length = 0;
3825
+ if (registry.size < size) return registry.register({ ...item });
3826
+ const removing = registry.seek("first");
3827
+ if (overflow.length === size) overflow.shift();
3828
+ overflow.push(removing);
3829
+ registry.unregister(removing.id);
3830
+ const ticket = registry.register({ ...item });
3831
+ registry.reindex();
3832
+ return ticket;
3833
+ }
3834
+ function undo() {
3835
+ const item = registry.seek("last");
3836
+ if (!item) return void 0;
3837
+ stack.push(item);
3838
+ registry.unregister(item.id);
3839
+ const restored = overflow.pop();
3840
+ if (restored) {
3841
+ const remaining = registry.values();
3842
+ registry.clear();
3843
+ registry.onboard([restored, ...remaining]);
3844
+ registry.reindex();
3845
+ }
3846
+ return item;
3847
+ }
3848
+ function redo() {
3849
+ if (stack.length === 0) return void 0;
3850
+ const item = stack.pop();
3851
+ const ticket = registry.register(item);
3852
+ registry.reindex();
3853
+ return ticket;
3854
+ }
3855
+ return {
3856
+ ...registry,
3857
+ register,
3858
+ undo,
3859
+ redo,
3860
+ get size() {
3861
+ return registry.size;
3862
+ }
3863
+ };
3864
+ }
3865
+ /**
3866
+ * Creates a new timeline context.
3867
+ *
3868
+ * @param options The options for the timeline context.
3869
+ * @template Z The type of the timeline ticket.
3870
+ * @template E The type of the timeline context.
3871
+ * @returns A new timeline context.
3872
+ *
3873
+ * @see https://0.vuetifyjs.com/composables/registration/create-timeline
3874
+ *
3875
+ * @example
3876
+ * ```ts
3877
+ * import { createTimelineContext } from '@vuetify/v0'
3878
+ *
3879
+ * // With default namespace 'v0:timeline'
3880
+ * export const [useTimeline, provideTimeline, context] = createTimelineContext({ size: 5 })
3881
+ *
3882
+ * context.register({ id: 'example' })
3883
+ *
3884
+ * // In a parent component
3885
+ * provideTimeline()
3886
+ *
3887
+ * // In a child component
3888
+ * const timeline = useTimeline()
3889
+ *
3890
+ * console.log(timeline.values()) // [{ id: 'example' }]
3891
+ * ```
3892
+ */
3893
+ function createTimelineContext(_options = {}) {
3894
+ const { namespace = "v0:timeline", ...options } = _options;
3895
+ const [useTimelineContext, _provideTimelineContext] = createContext(namespace);
3896
+ const context = createTimeline(options);
3897
+ function provideTimelineContext(_context = context, app) {
3898
+ return _provideTimelineContext(_context, app);
3899
+ }
3900
+ return createTrinity(useTimelineContext, provideTimelineContext, context);
3901
+ }
3902
+ /**
3903
+ * Returns the current timeline instance.
3904
+ *
3905
+ * @param namespace The namespace for the timeline context. Defaults to `'v0:timeline'`.
3906
+ * @returns The current timeline instance.
3907
+ *
3908
+ * @see https://0.vuetifyjs.com/composables/registration/create-timeline
3909
+ *
3910
+ * @example
3911
+ * ```vue
3912
+ * <script setup lang="ts">
3913
+ * import { useTimeline } from '@vuetify/v0'
3914
+ *
3915
+ * const timeline = useTimeline()
3916
+ * <\/script>
3917
+ * ```
3918
+ */
3919
+ function useTimeline(namespace = "v0:timeline") {
3920
+ return useContext(namespace);
3921
+ }
3922
+
3923
+ //#endregion
3924
+ //#region src/composables/useToggleScope/index.ts
3925
+ /**
3926
+ * @module useToggleScope
3927
+ *
3928
+ * @remarks
3929
+ * Conditionally manages an effect scope based on a reactive boolean condition.
3930
+ * When the source becomes true, creates and runs an effect scope. When false, stops the scope.
3931
+ * All reactive effects created within the scoped function are automatically cleaned up on deactivation.
3932
+ *
3933
+ * Key features:
3934
+ * - Uses Vue's effectScope for efficient reactive effect lifecycle management
3935
+ * - Automatic cleanup when condition becomes false
3936
+ * - Supports optional reset callback for scope restart capability
3937
+ * - Handles rapid toggling and parent scope disposal safely
3938
+ * - SSR-safe (effectScope is part of Vue core)
3939
+ *
3940
+ * Perfect for conditional side effects, feature flags, and performance optimization
3941
+ * by only running reactive effects when needed.
3942
+ */
3943
+ /**
3944
+ * Conditionally manages an effect scope based on a reactive boolean source.
3945
+ *
3946
+ * @param source A reactive boolean value or getter that controls the scope lifecycle
3947
+ * @param fn The function to run within the effect scope. Can optionally receive controls for manual scope management.
3948
+ * @returns Controls object with isActive state and start/stop/reset methods
3949
+ *
3950
+ * @see https://vuejs.org/api/reactivity-advanced.html#effectscope
3951
+ * @see https://0.vuetifyjs.com/composables/system/use-toggle-scope
3952
+ *
3953
+ * @example
3954
+ * ```ts
3955
+ * import { ref } from 'vue'
3956
+ * import { useToggleScope } from '@vuetify/v0'
3957
+ *
3958
+ * const isEnabled = ref(false)
3959
+ *
3960
+ * const { isActive } = useToggleScope(isEnabled, () => {
3961
+ * // This code runs when isEnabled becomes true
3962
+ * const unwatch = watch(someRef, () => {
3963
+ * console.log('Watching...')
3964
+ * })
3965
+ *
3966
+ * // Cleanup happens automatically when isEnabled becomes false
3967
+ * })
3968
+ *
3969
+ * // Toggle the scope on/off
3970
+ * isEnabled.value = true // Starts the scope
3971
+ * console.log(isActive.value) // true
3972
+ * isEnabled.value = false // Stops and cleans up
3973
+ * console.log(isActive.value) // false
3974
+ * ```
3975
+ *
3976
+ * @example
3977
+ * With manual controls:
3978
+ * ```ts
3979
+ * const isEnabled = ref(true)
3980
+ *
3981
+ * useToggleScope(isEnabled, (controls) => {
3982
+ * // Access controls inside the scope
3983
+ * console.log('Active:', controls.isActive.value)
3984
+ *
3985
+ * // Manually reset the scope if needed
3986
+ * someEvent.on('reset', () => controls.reset())
3987
+ * })
3988
+ * ```
3989
+ */
3990
+ function useToggleScope(source, fn) {
3991
+ const scope = shallowRef();
3992
+ const isActive = toRef(() => !!scope.value);
3993
+ function start() {
3994
+ if (scope.value) return;
3995
+ scope.value = effectScope();
3996
+ scope.value.run(() => fn.length > 0 ? fn(controls) : fn());
3997
+ }
3998
+ function stop() {
3999
+ scope.value?.stop();
4000
+ scope.value = void 0;
4001
+ }
4002
+ function reset() {
4003
+ stop();
4004
+ start();
4005
+ }
4006
+ const controls = {
4007
+ isActive: shallowReadonly(isActive),
4008
+ start,
4009
+ stop,
4010
+ reset
4011
+ };
4012
+ watch(source, (active) => {
4013
+ if (active && !scope.value) start();
4014
+ else if (!active) stop();
4015
+ }, { immediate: true });
4016
+ onScopeDispose(stop, true);
4017
+ return controls;
4018
+ }
4019
+
4020
+ //#endregion
4021
+ //#region src/composables/createVirtual/index.ts
4022
+ /**
4023
+ * @module createVirtual
4024
+ *
4025
+ * @remarks
4026
+ * Virtual scrolling composable for efficiently rendering large lists.
4027
+ *
4028
+ * Key features:
4029
+ * - Renders only visible items (viewport + overscan)
4030
+ * - Dynamic or fixed item heights
4031
+ * - SSR-safe (checks IN_BROWSER)
4032
+ * - Bidirectional scrolling (forward/reverse for chat apps)
4033
+ * - Scroll anchoring (maintains position across data changes)
4034
+ * - Edge detection for infinite scroll
4035
+ * - iOS momentum and elastic scrolling
4036
+ * - Configurable overscan (extra items rendered for smooth scrolling)
4037
+ *
4038
+ * Perfect for large data sets, chat apps, and infinite scroll implementations.
4039
+ */
4040
+ /**
4041
+ * Virtual scrolling composable for efficiently rendering large lists
4042
+ *
4043
+ * @param items Reactive array of items to virtualize
4044
+ * @param options Configuration options
4045
+ * @returns Virtual scrolling context
4046
+ *
4047
+ * @see https://0.vuetifyjs.com/composables/utilities/create-virtual
4048
+ *
4049
+ * @example
4050
+ * ```vue
4051
+ * <script setup lang="ts">
4052
+ * import { createVirtual } from '@vuetify/v0'
4053
+ *
4054
+ * const items = ref(Array.from({ length: 10000 }, (_, i) => ({ id: i, name: `Item ${i}` })))
4055
+ * const virtual = createVirtual(items)
4056
+ * <\/script>
4057
+ *
4058
+ * <template>
4059
+ * <div
4060
+ * ref="virtual.element"
4061
+ * style="height: 600px; overflow-y: auto;"
4062
+ * @scroll="virtual.scroll"
4063
+ * >
4064
+ * <div :style="{ height: `${virtual.offset.value}px` }" />
4065
+ *
4066
+ * <div v-for="item in virtual.items.value" :key="item.index">
4067
+ * {{ item.raw.name }}
4068
+ * </div>
4069
+ *
4070
+ * <div :style="{ height: `${virtual.size.value}px` }" />
4071
+ * </div>
4072
+ * </template>
4073
+ * ```
4074
+ */
4075
+ function createVirtual(items, _options = {}) {
4076
+ const { itemHeight: _itemHeight, height, overscan = 5, direction = "forward", anchor = "auto", anchorSmooth = true, onStartReached, onEndReached, startThreshold = 0, endThreshold = 0, momentum: momentumOption, elastic: elasticOption } = _options;
4077
+ const element = ref();
4078
+ const itemHeight = shallowRef(Number.parseFloat(String(_itemHeight || 0)));
4079
+ const heights = shallowRef([]);
4080
+ const offsets = shallowRef([]);
4081
+ const first = shallowRef(0);
4082
+ const last = shallowRef(0);
4083
+ const offset = shallowRef(0);
4084
+ const size = shallowRef(0);
4085
+ const viewportHeight = shallowRef(0);
4086
+ const state = shallowRef("ok");
4087
+ const isIOS = IN_BROWSER && /iPad|iPhone|iPod/.test(navigator.userAgent);
4088
+ const momentum = momentumOption ?? isIOS;
4089
+ const elastic = elasticOption ?? isIOS;
4090
+ let raf = -1;
4091
+ let rebuildRaf = -1;
4092
+ let edgeRaf = -1;
4093
+ const cachedViewport = Number.parseInt(String(height)) || 0;
4094
+ let anchorIndex = -1;
4095
+ let anchorOffset = 0;
4096
+ const computedItems = computed(() => items.value.slice(first.value, last.value).map((item, i) => ({
4097
+ raw: item,
4098
+ index: i + first.value
4099
+ })));
4100
+ watch(element, (el) => {
4101
+ if (!IN_BROWSER || !el?.style) return;
4102
+ /* v8 ignore start -- browser-only style assignments */
4103
+ if (momentum) el.style.webkitOverflowScrolling = "touch";
4104
+ if (!elastic) el.style.overscrollBehavior = "none";
4105
+ /* v8 ignore stop */
4106
+ });
4107
+ useResizeObserver(element, (entries) => {
4108
+ if (!entries[0]) return;
4109
+ viewportHeight.value = entries[0].contentRect.height;
4110
+ update();
4111
+ });
4112
+ watch(items, (newItems) => {
4113
+ captureAnchor();
4114
+ const length = newItems.length;
4115
+ const newHeights = heights.value.length === length ? heights.value : Array.from({ length }, () => null);
4116
+ if (heights.value !== newHeights) heights.value = newHeights;
4117
+ rebuild();
4118
+ }, { immediate: true });
4119
+ watch(element, () => {
4120
+ if (!element.value) return;
4121
+ if (direction === "reverse" && items.value.length > 0) {
4122
+ const lastIndex = items.value.length - 1;
4123
+ const totalHeight = (offsets.value[lastIndex] || 0) + (heights.value[lastIndex] || itemHeight.value);
4124
+ element.value.scrollTop = totalHeight;
4125
+ }
4126
+ update();
4127
+ });
4128
+ function captureAnchor() {
4129
+ if (!element.value || anchor === "auto") return;
4130
+ if (anchor === "start") {
4131
+ anchorIndex = 0;
4132
+ anchorOffset = 0;
4133
+ } else if (anchor === "end") {
4134
+ anchorIndex = items.value.length - 1;
4135
+ anchorOffset = 0;
4136
+ } else if (/* @__PURE__ */ isFunction(anchor)) {
4137
+ const result = anchor(items.value);
4138
+ if (/* @__PURE__ */ isNumber(result)) {
4139
+ anchorIndex = result;
4140
+ anchorOffset = element.value.scrollTop - (offsets.value[result] || 0);
4141
+ }
4142
+ } else {
4143
+ /* v8 ignore start -- default anchor capture */
4144
+ anchorIndex = first.value;
4145
+ anchorOffset = element.value.scrollTop - (offsets.value[first.value] || 0);
4146
+ }
4147
+ }
4148
+ function restoreAnchor() {
4149
+ if (!element.value || anchorIndex < 0) return;
4150
+ const newScrollTop = (offsets.value[anchorIndex] || 0) + anchorOffset;
4151
+ if (anchorSmooth && direction === "forward") element.value.scrollTo({
4152
+ top: newScrollTop,
4153
+ behavior: "smooth"
4154
+ });
4155
+ else element.value.scrollTop = newScrollTop;
4156
+ /* v8 ignore stop */
4157
+ anchorIndex = -1;
4158
+ anchorOffset = 0;
4159
+ }
4160
+ function rebuild() {
4161
+ const length = items.value.length;
4162
+ const newOffsets = offsets.value.length === length ? offsets.value : Array.from({ length });
4163
+ let offset$1 = 0;
4164
+ for (let i = 0; i < length; i++) {
4165
+ newOffsets[i] = offset$1;
4166
+ offset$1 += heights.value[i] || itemHeight.value;
4167
+ }
4168
+ if (offsets.value !== newOffsets) offsets.value = newOffsets;
4169
+ update();
4170
+ restoreAnchor();
4171
+ }
4172
+ function findIndex(scrollTop) {
4173
+ const arr = offsets.value;
4174
+ if (arr.length === 0) return 0;
4175
+ let low = 0;
4176
+ let high = arr.length - 1;
4177
+ while (low <= high) {
4178
+ const mid = low + high >> 1;
4179
+ if (arr[mid] <= scrollTop) low = mid + 1;
4180
+ else high = mid - 1;
4181
+ }
4182
+ return Math.max(0, high);
4183
+ }
4184
+ function update() {
4185
+ if (!element.value) return;
4186
+ const viewport = viewportHeight.value || cachedViewport;
4187
+ if (!viewport || !itemHeight.value) return;
4188
+ const scrollTop = element.value.scrollTop || 0;
4189
+ const length = items.value.length;
4190
+ const visibleStart = findIndex(scrollTop);
4191
+ const visibleEnd = findIndex(scrollTop + viewport) + 1;
4192
+ const start = /* @__PURE__ */ clamp(visibleStart - overscan, 0, length);
4193
+ const end = /* @__PURE__ */ clamp(visibleEnd + overscan, start, length);
4194
+ first.value = start;
4195
+ last.value = end;
4196
+ offset.value = offsets.value[start] || 0;
4197
+ const lastIndex = length - 1;
4198
+ const totalHeight = (offsets.value[lastIndex] || 0) + (heights.value[lastIndex] || itemHeight.value);
4199
+ size.value = totalHeight - (offsets.value[end] || totalHeight);
4200
+ }
4201
+ function checkEdges() {
4202
+ if (!element.value) return;
4203
+ const scrollTop = element.value.scrollTop;
4204
+ const scrollHeight = element.value.scrollHeight;
4205
+ const clientHeight = element.value.clientHeight;
4206
+ const distanceFromStart = scrollTop;
4207
+ const distanceFromEnd = scrollHeight - (scrollTop + clientHeight);
4208
+ if (IN_BROWSER) {
4209
+ cancelAnimationFrame(edgeRaf);
4210
+ edgeRaf = requestAnimationFrame(() => {
4211
+ if (onStartReached && distanceFromStart <= startThreshold) onStartReached(distanceFromStart);
4212
+ if (onEndReached && distanceFromEnd <= endThreshold) onEndReached(distanceFromEnd);
4213
+ });
4214
+ } else {
4215
+ if (onStartReached && distanceFromStart <= startThreshold) onStartReached(distanceFromStart);
4216
+ if (onEndReached && distanceFromEnd <= endThreshold) onEndReached(distanceFromEnd);
4217
+ }
4218
+ /* v8 ignore stop */
4219
+ }
4220
+ function resize(index, height$1) {
4221
+ if (heights.value[index] === height$1) return;
4222
+ heights.value[index] = height$1;
4223
+ if (!itemHeight.value) itemHeight.value = height$1;
4224
+ if (IN_BROWSER) {
4225
+ cancelAnimationFrame(rebuildRaf);
4226
+ rebuildRaf = requestAnimationFrame(rebuild);
4227
+ } else rebuild();
4228
+ /* v8 ignore stop */
4229
+ }
4230
+ function scroll() {
4231
+ if (IN_BROWSER) {
4232
+ cancelAnimationFrame(raf);
4233
+ raf = requestAnimationFrame(update);
4234
+ checkEdges();
4235
+ } else update();
4236
+ /* v8 ignore stop */
4237
+ }
4238
+ function scrollTo(index, scrollOptions) {
4239
+ if (!element.value) return;
4240
+ const targetOffset = offsets.value[index] || 0;
4241
+ const behavior = scrollOptions?.behavior ?? "auto";
4242
+ const block = scrollOptions?.block ?? "start";
4243
+ const extraOffset = scrollOptions?.offset ?? 0;
4244
+ let scrollTop = targetOffset + extraOffset;
4245
+ switch (block) {
4246
+ case "center": {
4247
+ const viewport = viewportHeight.value || cachedViewport;
4248
+ const itemH = heights.value[index] || itemHeight.value;
4249
+ scrollTop = targetOffset - viewport / 2 + itemH / 2 + extraOffset;
4250
+ break;
4251
+ }
4252
+ case "end": {
4253
+ const viewport = viewportHeight.value || cachedViewport;
4254
+ const itemH = heights.value[index] || itemHeight.value;
4255
+ scrollTop = targetOffset - viewport + itemH + extraOffset;
4256
+ break;
4257
+ }
4258
+ case "nearest": {
4259
+ const viewport = viewportHeight.value || cachedViewport;
4260
+ const currentScroll = element.value.scrollTop;
4261
+ const itemH = heights.value[index] || itemHeight.value;
4262
+ if (targetOffset < currentScroll) scrollTop = targetOffset + extraOffset;
4263
+ else if (targetOffset + itemH > currentScroll + viewport) scrollTop = targetOffset - viewport + itemH + extraOffset;
4264
+ else return;
4265
+ break;
4266
+ }
4267
+ }
4268
+ if (behavior === "smooth") element.value.scrollTo({
4269
+ top: scrollTop,
4270
+ behavior: "smooth"
4271
+ });
4272
+ else element.value.scrollTop = scrollTop;
4273
+ update();
4274
+ }
4275
+ function reset() {
4276
+ state.value = "ok";
4277
+ anchorIndex = -1;
4278
+ anchorOffset = 0;
4279
+ if (element.value && direction === "reverse" && items.value.length > 0) {
4280
+ const lastIndex = items.value.length - 1;
4281
+ const totalHeight = (offsets.value[lastIndex] || 0) + (heights.value[lastIndex] || itemHeight.value);
4282
+ element.value.scrollTop = totalHeight;
4283
+ }
4284
+ }
4285
+ onScopeDispose(() => {
4286
+ cancelAnimationFrame(raf);
4287
+ cancelAnimationFrame(rebuildRaf);
4288
+ cancelAnimationFrame(edgeRaf);
4289
+ }, true);
4290
+ return {
4291
+ element,
4292
+ items: computedItems,
4293
+ offset: readonly(offset),
4294
+ size: readonly(size),
4295
+ state,
4296
+ scrollTo,
4297
+ scroll,
4298
+ scrollend: scroll,
4299
+ resize,
4300
+ reset
4301
+ };
4302
+ }
4303
+ /**
4304
+ * Creates a virtual scrolling context with dependency injection support.
4305
+ *
4306
+ * @param items Reactive array of items to virtualize
4307
+ * @param options Configuration options including namespace
4308
+ * @template T The type of the items
4309
+ * @returns Trinity tuple: [useVirtual, provideVirtual, defaultVirtual]
4310
+ *
4311
+ * @see https://0.vuetifyjs.com/composables/utilities/create-virtual
4312
+ *
4313
+ * @example
4314
+ * ```ts
4315
+ * // Create injectable context
4316
+ * const [useVirtual, provideVirtual, virtual] = createVirtualContext(items, {
4317
+ * namespace: 'my-virtual',
4318
+ * overscan: 10,
4319
+ * })
4320
+ *
4321
+ * // In parent component
4322
+ * provideVirtual()
4323
+ *
4324
+ * // In child component
4325
+ * const virtual = useVirtual()
4326
+ * ```
4327
+ */
4328
+ function createVirtualContext(items, _options = {}) {
4329
+ const { namespace = "v0:virtual", ...options } = _options;
4330
+ const [useVirtualContext, _provideVirtualContext] = createContext(namespace);
4331
+ const context = createVirtual(items, options);
4332
+ function provideVirtualContext(_context = context, app) {
4333
+ return _provideVirtualContext(_context, app);
4334
+ }
4335
+ return createTrinity(useVirtualContext, provideVirtualContext, context);
4336
+ }
4337
+ /**
4338
+ * Returns the current virtual context from dependency injection.
4339
+ *
4340
+ * @param namespace The namespace for the virtual context. Defaults to `v0:virtual`.
4341
+ * @template T The type of the items
4342
+ * @returns The current virtual context.
4343
+ *
4344
+ * @throws An error if the virtual context is not found and no default is provided.
4345
+ *
4346
+ * @see https://0.vuetifyjs.com/composables/utilities/create-virtual
4347
+ *
4348
+ * @example
4349
+ * ```vue
4350
+ * <script lang="ts" setup>
4351
+ * import { createVirtual } from '@vuetify/v0'
4352
+ *
4353
+ * // Inject virtual context provided by parent
4354
+ * const virtual = useVirtual()
4355
+ * <\/script>
4356
+ *
4357
+ * <template>
4358
+ * <div>
4359
+ * <p>Visible items: {{ virtual.items.value.length }}</p>
4360
+ * </div>
4361
+ * </template>
4362
+ * ```
4363
+ */
4364
+ function useVirtual(namespace = "v0:virtual") {
4365
+ return useContext(namespace);
4366
+ }
4367
+
4368
+ //#endregion
4369
+ //#region src/composables/useEventListener/index.ts
4370
+ /**
4371
+ * @module useEventListener
4372
+ *
4373
+ * @remarks
4374
+ * Event listener composable with automatic cleanup on scope disposal.
4375
+ *
4376
+ * Key features:
4377
+ * - Supports Window, Document, and HTMLElement targets
4378
+ * - Reactive targets, events, and listeners
4379
+ * - Event options support (capture, passive, once)
4380
+ * - Automatic removeEventListener on unmount
4381
+ * - Multiple overloads for type safety
4382
+ *
4383
+ * Perfect for safely managing event listeners in Vue components.
4384
+ */
4385
+ /**
4386
+ * Attaches an event listener to a target.
4387
+ *
4388
+ * @param target The target to attach the event listener to.
4389
+ * @param event The event to listen for.
4390
+ * @param listener The event listener.
4391
+ * @param options The event listener options.
4392
+ * @returns A function to remove the event listener.
4393
+ *
4394
+ * @see https://0.vuetifyjs.com/composables/system/use-event-listener
4395
+ */
4396
+ function useEventListener(target, event, listener, options) {
4397
+ const cleanups = [];
4398
+ function cleanup() {
4399
+ for (const fn of cleanups) fn();
4400
+ cleanups.length = 0;
4401
+ }
4402
+ function register(el, event$1, listener$1, options$1) {
4403
+ el.addEventListener(event$1, listener$1, options$1);
4404
+ return () => el.removeEventListener(event$1, listener$1, options$1);
4405
+ }
4406
+ const stopWatcher = watch(() => [
4407
+ toValue(target),
4408
+ toValue(event),
4409
+ unref(listener),
4410
+ toValue(options)
4411
+ ], ([el, events, listeners, opts]) => {
4412
+ cleanup();
4413
+ if (!el) return;
4414
+ const eventList = toArray(events);
4415
+ const listenerList = toArray(listeners);
4416
+ for (const event$1 of eventList) for (const listenerFn of listenerList) cleanups.push(register(el, event$1, listenerFn, opts));
4417
+ }, {
4418
+ immediate: true,
4419
+ flush: "post"
4420
+ });
4421
+ function stop() {
4422
+ stopWatcher();
4423
+ cleanup();
4424
+ }
4425
+ onScopeDispose(stop, true);
4426
+ return stop;
4427
+ }
4428
+ /**
4429
+ * Attaches an event listener to the window.
4430
+ *
4431
+ * @param event The event to listen for.
4432
+ * @param listener The event listener.
4433
+ * @param options The event listener options.
4434
+ * @template E The event type.
4435
+ * @returns A function to remove the event listener.
4436
+ *
4437
+ * @see https://0.vuetifyjs.com/composables/system/use-event-listener
4438
+ */
4439
+ function useWindowEventListener(event, listener, options) {
4440
+ return IN_BROWSER ? useEventListener(window, event, listener, options) : () => {};
4441
+ }
4442
+ /**
4443
+ * Attaches an event listener to the document.
4444
+ *
4445
+ * @param event The event to listen for.
4446
+ * @param listener The event listener.
4447
+ * @param options The event listener options.
4448
+ * @template E The event type.
4449
+ * @returns A function to remove the event listener.
4450
+ *
4451
+ * @see https://0.vuetifyjs.com/composables/system/use-event-listener
4452
+ */
4453
+ function useDocumentEventListener(event, listener, options) {
4454
+ return IN_BROWSER ? useEventListener(document, event, listener, options) : () => {};
4455
+ }
4456
+
4457
+ //#endregion
4458
+ //#region src/composables/useClickOutside/index.ts
4459
+ /**
4460
+ * @module useClickOutside
4461
+ *
4462
+ * @remarks
4463
+ * Detects clicks outside of specified element(s) with automatic cleanup.
4464
+ *
4465
+ * Key features:
4466
+ * - Two-phase detection (pointerdown → pointerup) prevents drag-out false positives
4467
+ * - Touch scroll threshold ignores swipes/scrolls on mobile
4468
+ * - Capture phase listeners work with stopPropagation
4469
+ * - Pause/resume/stop functionality
4470
+ * - Optional iframe focus detection
4471
+ * - SSR-safe (no-op when not in browser)
4472
+ *
4473
+ * Common use cases: closing popovers, dropdowns, modals, and menus.
4474
+ *
4475
+ * Accessibility: This composable handles pointer interactions only. For accessible
4476
+ * components (dialogs, popovers, menus), pair with `useHotkey` for Escape key
4477
+ * dismissal per WCAG/APG requirements.
4478
+ */
4479
+ /**
4480
+ * Detects clicks outside of the specified element(s).
4481
+ *
4482
+ * Uses two-phase detection (pointerdown → pointerup) to prevent false positives
4483
+ * when users drag from inside to outside an element.
4484
+ *
4485
+ * @param target Element ref(s) to detect clicks outside of. Accepts a single ref/getter or array of refs/getters.
4486
+ * @param handler Callback invoked when a click outside is detected.
4487
+ * @param options Configuration options.
4488
+ * @returns An object with methods to control the listener.
4489
+ *
4490
+ * @see https://0.vuetifyjs.com/composables/system/use-click-outside
4491
+ *
4492
+ * @example Native element ref
4493
+ * ```ts
4494
+ * const menuRef = useTemplateRef<HTMLElement>('menu')
4495
+ *
4496
+ * useClickOutside(menuRef, () => { isOpen.value = false })
4497
+ * ```
4498
+ *
4499
+ * @example Component ref (e.g., Atom)
4500
+ * ```ts
4501
+ * const atomRef = useTemplateRef<AtomExpose>('atom')
4502
+ *
4503
+ * // Pass the exposed element TemplateRef via getter
4504
+ * useClickOutside(
4505
+ * () => atomRef.value?.element,
4506
+ * () => { isOpen.value = false }
4507
+ * )
4508
+ * ```
4509
+ *
4510
+ * @example Multiple targets
4511
+ * ```ts
4512
+ * const popoverRef = useTemplateRef<AtomExpose>('popover')
4513
+ * const anchorRef = useTemplateRef<HTMLElement>('anchor')
4514
+ *
4515
+ * useClickOutside(
4516
+ * [() => popoverRef.value?.element, anchorRef],
4517
+ * () => { isOpen.value = false }
4518
+ * )
4519
+ * ```
4520
+ *
4521
+ * @example Ignoring elements (CSS selectors or refs)
4522
+ * ```ts
4523
+ * useClickOutside(
4524
+ * () => navRef.value?.element,
4525
+ * () => { isOpen.value = false },
4526
+ * { ignore: ['[data-app-bar]'] }
4527
+ * )
4528
+ * ```
4529
+ *
4530
+ * @example Native dialog with bounds detection
4531
+ * ```ts
4532
+ * // For native <dialog> elements, use bounds mode to detect backdrop clicks
4533
+ * const dialogRef = useTemplateRef<HTMLDialogElement>('dialog')
4534
+ *
4535
+ * useClickOutside(
4536
+ * dialogRef,
4537
+ * () => { dialogRef.value?.close() },
4538
+ * { bounds: true }
4539
+ * )
4540
+ * ```
4541
+ */
4542
+ function useClickOutside(target, handler, options = {}) {
4543
+ const { capture = true, touchScrollThreshold = 30, detectIframe = false, ignore = [], bounds = false } = options;
4544
+ const isPaused = shallowRef(false);
4545
+ const isActive = toRef(() => !isPaused.value);
4546
+ let initialTarget = null;
4547
+ let startPosition = {
4548
+ x: 0,
4549
+ y: 0
4550
+ };
4551
+ let cleanupPointerDown;
4552
+ let cleanupPointerUp;
4553
+ let cleanupBlur;
4554
+ /**
4555
+ * Resolve target(s) to an array of HTMLElements.
4556
+ */
4557
+ function getTargets() {
4558
+ return toArray(target).map((source) => toValue(source)).filter((el) => !!el && /* @__PURE__ */ isFunction(el.contains));
4559
+ }
4560
+ /**
4561
+ * Resolve ignore targets to a tuple of [selectors, elements].
4562
+ * Called once per event to avoid repeated toValue() calls in hot path.
4563
+ */
4564
+ function resolveIgnoreTargets() {
4565
+ const ignoreTargets = toValue(ignore);
4566
+ if (ignoreTargets.length === 0) return [[], []];
4567
+ const selectors = [];
4568
+ const elements = [];
4569
+ for (const ignoreTarget of ignoreTargets) if (/* @__PURE__ */ isString(ignoreTarget)) selectors.push(ignoreTarget);
4570
+ else {
4571
+ const ignoreEl = toValue(ignoreTarget);
4572
+ if (ignoreEl) elements.push(ignoreEl);
4573
+ }
4574
+ return [selectors, elements];
4575
+ }
4576
+ /**
4577
+ * Check if an element matches resolved ignore targets.
4578
+ */
4579
+ function isIgnored(el, selectors, elements) {
4580
+ if (!el) return false;
4581
+ for (const selector of selectors) try {
4582
+ if (el.matches(selector) || !/* @__PURE__ */ isNull(el.closest(selector))) return true;
4583
+ } catch {}
4584
+ for (const ignoreEl of elements) if (ignoreEl === el || ignoreEl.contains(el)) return true;
4585
+ return false;
4586
+ }
4587
+ /**
4588
+ * Check if any element in the event path should be ignored.
4589
+ */
4590
+ function shouldIgnore(path) {
4591
+ const [selectors, elements] = resolveIgnoreTargets();
4592
+ if (selectors.length === 0 && elements.length === 0) return false;
4593
+ return path.some((node) => node instanceof Element && isIgnored(node, selectors, elements));
4594
+ }
4595
+ /**
4596
+ * Check if the event target is outside all target elements (DOM containment).
4597
+ */
4598
+ function isOutside(eventTarget) {
4599
+ /* v8 ignore start -- defensive guards */
4600
+ if (!eventTarget) return false;
4601
+ if (!(eventTarget instanceof Node)) return false;
4602
+ /* v8 ignore stop */
4603
+ const targets = getTargets();
4604
+ if (targets.length === 0) return false;
4605
+ return targets.every((el) => {
4606
+ if (/* @__PURE__ */ isNullOrUndefined(el) || !/* @__PURE__ */ isFunction(el.contains)) return false;
4607
+ return el !== eventTarget && !el.contains(eventTarget);
4608
+ });
4609
+ }
4610
+ /**
4611
+ * Check if coordinates are outside all target elements' bounding rects.
4612
+ */
4613
+ function isOutsideBounds(x, y) {
4614
+ const targets = getTargets();
4615
+ if (targets.length === 0) return false;
4616
+ return targets.every((el) => {
4617
+ const { left, right, top, bottom } = el.getBoundingClientRect();
4618
+ return x < left || x > right || y < top || y > bottom;
4619
+ });
4620
+ }
4621
+ /**
4622
+ * Validate that the target is still in the DOM.
4623
+ */
4624
+ function isValidTarget(eventTarget) {
4625
+ if (!(eventTarget instanceof Element)) return false;
4626
+ if (!eventTarget.isConnected) return false;
4627
+ return true;
4628
+ }
4629
+ /* v8 ignore start -- event handlers tested via integration, not unit */
4630
+ /**
4631
+ * Handle pointerdown - store initial target and position.
4632
+ */
4633
+ function onPointerDown(event) {
4634
+ if (isPaused.value) return;
4635
+ if (event.defaultPrevented) return;
4636
+ initialTarget = event.composedPath()[0] ?? event.target;
4637
+ startPosition = {
4638
+ x: event.clientX,
4639
+ y: event.clientY
4640
+ };
4641
+ }
4642
+ /**
4643
+ * Handle pointerup - check if it's an outside click.
4644
+ */
4645
+ function onPointerUp(event) {
4646
+ if (isPaused.value) return;
4647
+ if (event.defaultPrevented) return;
4648
+ if (!initialTarget) return;
4649
+ const pointerdownTarget = initialTarget;
4650
+ initialTarget = null;
4651
+ if (!isValidTarget(pointerdownTarget)) return;
4652
+ const path = event.composedPath();
4653
+ const pointerupTarget = path[0] ?? event.target;
4654
+ if (event.pointerType === "touch") {
4655
+ const dx = Math.abs(event.clientX - startPosition.x);
4656
+ const dy = Math.abs(event.clientY - startPosition.y);
4657
+ if (dx >= touchScrollThreshold || dy >= touchScrollThreshold) return;
4658
+ }
4659
+ if ((bounds ? isOutsideBounds(startPosition.x, startPosition.y) && isOutsideBounds(event.clientX, event.clientY) : isOutside(pointerdownTarget) && isOutside(pointerupTarget)) && !shouldIgnore(path)) handler(event);
4660
+ }
4661
+ /**
4662
+ * Handle window blur - detect focus moving to iframe.
4663
+ */
4664
+ function onBlur(event) {
4665
+ if (isPaused.value) return;
4666
+ if (event.defaultPrevented) return;
4667
+ if (document.activeElement instanceof HTMLIFrameElement) {
4668
+ const iframeIsOutside = getTargets().every((el) => !el.contains(document.activeElement));
4669
+ const [selectors, elements] = resolveIgnoreTargets();
4670
+ if (iframeIsOutside && !isIgnored(document.activeElement, selectors, elements)) handler(event);
4671
+ }
4672
+ }
4673
+ /* v8 ignore stop */
4674
+ function setup() {
4675
+ cleanupPointerDown = useDocumentEventListener("pointerdown", onPointerDown, capture);
4676
+ cleanupPointerUp = useDocumentEventListener("pointerup", onPointerUp, capture);
4677
+ if (!detectIframe) return;
4678
+ cleanupBlur = useWindowEventListener("blur", onBlur, capture);
4679
+ }
4680
+ function cleanup() {
4681
+ cleanupPointerDown?.();
4682
+ cleanupPointerUp?.();
4683
+ cleanupBlur?.();
4684
+ cleanupPointerDown = void 0;
4685
+ cleanupPointerUp = void 0;
4686
+ cleanupBlur = void 0;
4687
+ }
4688
+ function pause() {
4689
+ if (isPaused.value) return;
4690
+ isPaused.value = true;
4691
+ initialTarget = null;
4692
+ cleanup();
4693
+ }
4694
+ function resume() {
4695
+ if (!isPaused.value) return;
4696
+ isPaused.value = false;
4697
+ setup();
4698
+ }
4699
+ function stop() {
4700
+ isPaused.value = true;
4701
+ initialTarget = null;
4702
+ cleanup();
4703
+ }
4704
+ setup();
4705
+ onScopeDispose(stop, true);
4706
+ return {
4707
+ isActive: shallowReadonly(isActive),
4708
+ isPaused: shallowReadonly(isPaused),
4709
+ pause,
4710
+ resume,
4711
+ stop
4712
+ };
4713
+ }
4714
+
4715
+ //#endregion
4716
+ export { createOverflow as $, singleOpenStrategy as A, createForm as B, createQueue as C, createNestedContext as D, createNested as E, usePrefersReducedMotion as F, createDatePlugin as G, useForm as H, useLazy as I, createBreakpointsContext as J, useDate as K, useElementIntersection as L, useMediaQuery as M, usePrefersContrast as N, useNested as O, usePrefersDark as P, useProxyModel as Q, useIntersectionObserver as R, useStack as S, useQueue as T, createDate as U, createFormContext as V, createDateContext as W, useBreakpoints as X, createBreakpointsPlugin as Y, toReactive as Z, createStepContext as _, createVirtual as a, createFallbackHydration as at, createStackContext as b, useToggleScope as c, createHydrationPlugin as ct, useTimeline as d, createBreadcrumbsContext as dt, createOverflowContext as et, createStorage as f, useBreadcrumbs as ft, createStep as g, useStorage as h, useWindowEventListener as i, toElement as it, useMutationObserver as j, multipleOpenStrategy as k, createTimeline as l, useHydration as lt, createStoragePlugin as m, useDocumentEventListener as n, useElementSize as nt, createVirtualContext as o, createHydration as ot, createStorageContext as p, createBreakpoints as q, useEventListener as r, useResizeObserver as rt, useVirtual as s, createHydrationContext as st, useClickOutside as t, useOverflow as tt, createTimelineContext as u, createBreadcrumbs as ut, useStep as v, createQueueContext as w, createStackPlugin as x, createStack as y, useHotkey as z };