@vuetify/v0 0.1.3 → 0.1.4

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