@vuetify/v0 1.0.0-alpha.3 → 1.0.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/README.md +5 -0
  2. package/dist/adapter-B6IrPwib.d.mts +98 -0
  3. package/dist/adapter-BEJXp-ie.d.mts +11 -0
  4. package/dist/adapter-BFSJsyv7.mjs +481 -0
  5. package/dist/{adapter-DlX3FA3A.d.mts → adapter-BO75n0Cn.d.mts} +10 -14
  6. package/dist/adapter-BSKx9WQ7.mjs +4 -0
  7. package/dist/adapter-Chznb9Ju.mjs +4 -0
  8. package/dist/{index-CT5SCLzW.d.mts → adapter-CspReV3g.d.mts} +6 -9
  9. package/dist/adapter-D8zizQVP.mjs +4 -0
  10. package/dist/adapter-DDJHLC8K.d.mts +17 -0
  11. package/dist/adapters-4t-NhR11.mjs +5 -0
  12. package/dist/adapters-BcoA0zCS.mjs +4 -0
  13. package/dist/adapters-BjaPK635.mjs +2 -0
  14. package/dist/adapters-D64TORDu.mjs +2 -0
  15. package/dist/adapters-DvG-9z9q.mjs +3 -0
  16. package/dist/browser/index.js +2074 -561
  17. package/dist/components/index.d.mts +2 -2
  18. package/dist/components/index.mjs +1 -1
  19. package/dist/{components-C4jI-78d.mjs → components-Dn4Kbi0i.mjs} +149 -101
  20. package/dist/composables/index.d.mts +20 -19
  21. package/dist/composables/index.mjs +31 -29
  22. package/dist/{consola-BdgyPEfx.d.mts → consola-CUNHyu8J.d.mts} +2 -2
  23. package/dist/{consola-Ceox8BWi.mjs → consola-DYvbPNbF.mjs} +3 -1
  24. package/dist/constants/index.d.mts +1 -1
  25. package/dist/constants/index.mjs +2 -2
  26. package/dist/{createDataTable-iODP6aKB.mjs → createDataTable-H-PuVigU.mjs} +216 -124
  27. package/dist/{createGroup-CGk6hY_Y.mjs → createGroup-aHt_kvtU.mjs} +3 -3
  28. package/dist/{createRegistry-BXzdXAjq.mjs → createRegistry-CWpvSbCe.mjs} +78 -41
  29. package/dist/{createSelection-B3HJEPNg.mjs → createSelection-MRyUZyW2.mjs} +3 -3
  30. package/dist/{createSingle-Dql8mRi-.mjs → createSingle-BSciC9EJ.mjs} +1 -1
  31. package/dist/{createTokens-DgFYsOrv.mjs → createTokens-CQ9C7GTV.mjs} +2 -2
  32. package/dist/data-table/adapters/client/index.d.mts +2 -2
  33. package/dist/data-table/adapters/client/index.mjs +2 -2
  34. package/dist/data-table/adapters/index.d.mts +5 -5
  35. package/dist/data-table/adapters/index.mjs +6 -6
  36. package/dist/data-table/adapters/server/index.d.mts +2 -2
  37. package/dist/data-table/adapters/server/index.mjs +2 -2
  38. package/dist/data-table/adapters/virtual/index.d.mts +2 -2
  39. package/dist/data-table/adapters/virtual/index.mjs +2 -2
  40. package/dist/data-table/index.d.mts +6 -6
  41. package/dist/data-table/index.mjs +6 -6
  42. package/dist/date/index.d.mts +3 -3
  43. package/dist/date/index.mjs +12 -5
  44. package/dist/features/adapters/flagsmith/index.d.mts +2 -2
  45. package/dist/features/adapters/flagsmith/index.mjs +2 -2
  46. package/dist/features/adapters/launchdarkly/index.d.mts +2 -2
  47. package/dist/features/adapters/launchdarkly/index.mjs +2 -2
  48. package/dist/features/adapters/posthog/index.d.mts +2 -2
  49. package/dist/features/adapters/posthog/index.mjs +2 -2
  50. package/dist/features/index.d.mts +3 -3
  51. package/dist/features/index.mjs +2 -1
  52. package/dist/{index-BzFHTW59.d.mts → flagsmith-Cd44vxff.d.mts} +4 -4
  53. package/dist/{flagsmith-Dbh1h8WF.mjs → flagsmith-Cu93hUIF.mjs} +6 -4
  54. package/dist/{globals-zEjWBKCr.mjs → globals-BRdxsC2M.mjs} +1 -1
  55. package/dist/{index-GOpjKzaJ.d.mts → index-BLaKZq0Y.d.mts} +25 -2
  56. package/dist/{index-BJGcVy7e.d.mts → index-BmEu85PI.d.mts} +126 -65
  57. package/dist/{index-DE3bWw11.d.mts → index-C0ewabdY.d.mts} +93 -215
  58. package/dist/index-C6NnIuDv.d.mts +4 -0
  59. package/dist/{index-DNDuacmH.d.mts → index-CJdG9yY1.d.mts} +116 -106
  60. package/dist/index-C_t6t0Z-.d.mts +170 -0
  61. package/dist/{index-B76iGRE3.d.mts → index-CyUCELZC.d.mts} +1149 -61
  62. package/dist/index.d.mts +24 -23
  63. package/dist/index.mjs +35 -33
  64. package/dist/json/attributes.json +1 -1
  65. package/dist/json/web-types.json +2 -2
  66. package/dist/{launchdarkly-BKtW-idu.mjs → launchdarkly-CLGtJCsI.mjs} +6 -4
  67. package/dist/launchdarkly-De701hkf.d.mts +13 -0
  68. package/dist/locale/adapters/index.d.mts +3 -3
  69. package/dist/locale/adapters/index.mjs +4 -3
  70. package/dist/locale/adapters/v0/index.d.mts +2 -2
  71. package/dist/locale/adapters/v0/index.mjs +2 -2
  72. package/dist/locale/adapters/vue-i18n/index.d.mts +3 -3
  73. package/dist/locale/adapters/vue-i18n/index.mjs +4 -2
  74. package/dist/locale/index.d.mts +4 -4
  75. package/dist/locale/index.mjs +4 -3
  76. package/dist/logger/adapters/consola/index.d.mts +1 -1
  77. package/dist/logger/adapters/consola/index.mjs +1 -1
  78. package/dist/logger/adapters/index.d.mts +5 -5
  79. package/dist/logger/adapters/index.mjs +6 -5
  80. package/dist/logger/adapters/pino/index.d.mts +1 -1
  81. package/dist/logger/adapters/pino/index.mjs +1 -1
  82. package/dist/logger/adapters/v0/index.d.mts +2 -2
  83. package/dist/logger/adapters/v0/index.mjs +2 -2
  84. package/dist/logger/index.d.mts +6 -6
  85. package/dist/logger/index.mjs +6 -5
  86. package/dist/{memory-oYBvtkgx.mjs → memory-BMpJcQjQ.mjs} +13 -3
  87. package/dist/{memory-CeSQE-QV.d.mts → memory-D-JbdKXg.d.mts} +9 -9
  88. package/dist/notifications/index.d.mts +30 -4
  89. package/dist/notifications/index.mjs +187 -126
  90. package/dist/palettes/ant/index.d.mts +1 -1
  91. package/dist/palettes/index.d.mts +3 -3
  92. package/dist/palettes/leonardo/generate/index.mjs +3 -0
  93. package/dist/palettes/material/index.d.mts +1 -1
  94. package/dist/palettes/md1/index.d.mts +1 -1
  95. package/dist/palettes/md2/index.d.mts +1 -1
  96. package/dist/palettes/radix/index.d.mts +1 -1
  97. package/dist/palettes/tailwind/index.d.mts +1 -1
  98. package/dist/permissions/adapters/index.d.mts +2 -2
  99. package/dist/permissions/adapters/index.mjs +3 -3
  100. package/dist/permissions/adapters/v0/index.d.mts +2 -2
  101. package/dist/permissions/adapters/v0/index.mjs +2 -2
  102. package/dist/permissions/index.d.mts +2 -2
  103. package/dist/permissions/index.mjs +3 -3
  104. package/dist/{pino-DNfCEb0p.d.mts → pino-BaYY_KIN.d.mts} +2 -2
  105. package/dist/{pino-9L79n6y6.mjs → pino-CIcYlW3u.mjs} +3 -1
  106. package/dist/{posthog-DmuyycaR.mjs → posthog-0umvvA48.mjs} +7 -5
  107. package/dist/posthog-CIrmvke4.d.mts +13 -0
  108. package/dist/rules/index.d.mts +1 -1
  109. package/dist/rules/index.mjs +1 -1
  110. package/dist/{server-3ilWFwqe.d.mts → server-7vjHxjNc.d.mts} +5 -5
  111. package/dist/{server-y7zLSCSx.mjs → server-BNSiVoMe.mjs} +4 -3
  112. package/dist/storage/adapters/index.d.mts +3 -3
  113. package/dist/storage/adapters/index.mjs +2 -2
  114. package/dist/storage/adapters/memory/index.d.mts +2 -2
  115. package/dist/storage/adapters/memory/index.mjs +2 -2
  116. package/dist/storage/index.d.mts +4 -4
  117. package/dist/storage/index.mjs +3 -3
  118. package/dist/theme/adapters/index.d.mts +2 -2
  119. package/dist/theme/adapters/index.mjs +4 -4
  120. package/dist/theme/adapters/unhead/index.d.mts +1 -1
  121. package/dist/theme/adapters/unhead/index.mjs +1 -1
  122. package/dist/theme/adapters/v0/index.d.mts +1 -1
  123. package/dist/theme/adapters/v0/index.mjs +1 -1
  124. package/dist/theme/index.d.mts +1 -1
  125. package/dist/theme/index.mjs +3 -3
  126. package/dist/types/index.d.mts +1 -1
  127. package/dist/{unhead-B-I2OS6i.mjs → unhead-_cXZcx0j.mjs} +2 -2
  128. package/dist/{useClickOutside-CY4U2J9W.mjs → useClickOutside-DbOLg1uw.mjs} +1483 -182
  129. package/dist/{useFeatures-BPOke6iP.mjs → useFeatures-Dhnr-Lg2.mjs} +7 -10
  130. package/dist/{useLocale-BV8e3imF.mjs → useLocale-Sh-2sNiG.mjs} +6 -6
  131. package/dist/{useLogger-DvdRTrqC.mjs → useLogger-1_ZeBY12.mjs} +5 -5
  132. package/dist/{useNotifications-vSJE6z6t.mjs → useNotifications-CAVQ7hK6.mjs} +6 -6
  133. package/dist/{usePermissions-D3zPwKQc.mjs → usePermissions-D9Oituwy.mjs} +6 -6
  134. package/dist/{useRules-BT6cgoTj.mjs → useRules-DK4AeNeC.mjs} +4 -3
  135. package/dist/{useTheme-cUZb2A9O.mjs → useTheme-FMDQC81h.mjs} +5 -5
  136. package/dist/utilities/index.d.mts +2 -2
  137. package/dist/utilities/index.mjs +26 -2
  138. package/dist/{v0-CHZpnMeP.mjs → v0-C42ssNIy.mjs} +6 -4
  139. package/dist/{v0-Dq3zhexO.mjs → v0-CEfbyyp2.mjs} +3 -4
  140. package/dist/{v0-C49OI_wc.mjs → v0-Ch-O6YVd.mjs} +5 -3
  141. package/dist/{v0-gpExNexS.mjs → v0-D0imQlSD.mjs} +2 -2
  142. package/dist/{v0-DrOub-e1.d.mts → v0-DWZ_N2GG.d.mts} +4 -4
  143. package/dist/{v0-Bmow1q_x.mjs → v0-Dvu8fMl3.mjs} +3 -3
  144. package/dist/v0-QIjffi4E.d.mts +8 -0
  145. package/dist/{v0-D7Fm2C3Y.d.mts → v0-aYLq6qmT.d.mts} +3 -3
  146. package/dist/{virtual-C0yHf1DC.mjs → virtual-Cq5aRp7m.mjs} +3 -4
  147. package/dist/virtual-CrgGA-o6.d.mts +8 -0
  148. package/package.json +1 -1
  149. package/dist/adapter-58IvIfAZ.d.mts +0 -96
  150. package/dist/adapter-BvWEd9w-.d.mts +0 -17
  151. package/dist/adapter-Dhq68tz0.d.mts +0 -11
  152. package/dist/adapter-gQ2SNKZq.mjs +0 -238
  153. package/dist/adapters-BSiqsTZN.mjs +0 -3
  154. package/dist/adapters-C3QXhf4I.mjs +0 -2
  155. package/dist/adapters-CMJGA1k7.mjs +0 -2
  156. package/dist/adapters-Dse4bPxk.mjs +0 -5
  157. package/dist/adapters-_ZqxCD8f.mjs +0 -4
  158. package/dist/createPagination-CHF7SmmK.mjs +0 -247
  159. package/dist/index-1XdASTjp.d.mts +0 -13
  160. package/dist/index-C6rdXZ7j.d.mts +0 -11
  161. package/dist/index-Dp1HjBxJ.d.mts +0 -13
  162. package/dist/v0-CdusXjY_.d.mts +0 -8
  163. package/dist/virtual-D4fckewC.d.mts +0 -8
  164. /package/dist/{adapter-Be9zUc-n.mjs → adapter-oM18AdUc.mjs} +0 -0
  165. /package/dist/{htmlElements-D4oMQZPJ.mjs → htmlElements-CHXZfsZu.mjs} +0 -0
  166. /package/dist/{index-CFhUdAHM.d.mts → index-BOn0AAue.d.mts} +0 -0
  167. /package/dist/{index-CROz1VSV.d.mts → index-CKKoxA9V.d.mts} +0 -0
  168. /package/dist/{index-DuddF-NR.d.mts → index-CLR1QMM3.d.mts} +0 -0
  169. /package/dist/{index-DTvqw22G.d.mts → index-H_hl6-4b.d.mts} +0 -0
  170. /package/dist/{index-BgCkepP_.d.mts → index-PvkxPev3.d.mts} +0 -0
  171. /package/dist/{toArray-as9BWxBK.mjs → toArray-CD2-OxAz.mjs} +0 -0
@@ -1,24 +1,23 @@
1
- import { a as SUPPORTS_OBSERVER, i as SUPPORTS_MUTATION_OBSERVER, n as SUPPORTS_INTERSECTION_OBSERVER, r as SUPPORTS_MATCH_MEDIA, t as IN_BROWSER } from "./globals-zEjWBKCr.mjs";
2
- import { clamp, instanceExists, isArray, isElement, isFunction, isNull, isNullOrUndefined, isNumber, isObject, isString, isUndefined, mergeDeep, range, resolveIds, resolveIndexes, useId as useId$1 } from "./utilities/index.mjs";
1
+ import { a as SUPPORTS_OBSERVER, i as SUPPORTS_MUTATION_OBSERVER, n as SUPPORTS_INTERSECTION_OBSERVER, r as SUPPORTS_MATCH_MEDIA, t as IN_BROWSER } from "./globals-BRdxsC2M.mjs";
2
+ import { clamp, instanceExists, isArray, isElement, isFunction, isNull, isNullOrUndefined, isNumber, isObject, isString, isThenable, isUndefined, mergeDeep, range, resolveIds, resolveIndexes, useId as useId$1 } from "./utilities/index.mjs";
3
3
  import { i as useContext, t as createTrinity } from "./createTrinity-BTCs1pYx.mjs";
4
- import { a as createPlugin, i as useLogger, o as createPluginContext } from "./useLogger-DvdRTrqC.mjs";
5
- import { t as createRegistry } from "./createRegistry-BXzdXAjq.mjs";
6
- import { i as createModel, t as createSelection } from "./createSelection-B3HJEPNg.mjs";
7
- import { t as createSingle } from "./createSingle-Dql8mRi-.mjs";
8
- import "./createTokens-DgFYsOrv.mjs";
9
- import { a as useLocale } from "./useLocale-BV8e3imF.mjs";
10
- import { c as useTimer } from "./useNotifications-vSJE6z6t.mjs";
11
- import { t as toArray } from "./toArray-as9BWxBK.mjs";
12
- import { n as createFilter } from "./adapter-gQ2SNKZq.mjs";
13
- import { t as createGroup } from "./createGroup-CGk6hY_Y.mjs";
14
- import "./createPagination-CHF7SmmK.mjs";
15
- import "./createDataTable-iODP6aKB.mjs";
16
- import { a as useRules, o as isStandardSchema } from "./useRules-BT6cgoTj.mjs";
17
- import "./useFeatures-BPOke6iP.mjs";
18
- import "./usePermissions-D3zPwKQc.mjs";
19
- import { t as MemoryAdapter } from "./memory-oYBvtkgx.mjs";
20
- import "./useTheme-cUZb2A9O.mjs";
21
- import { computed, effectScope, hasInjectionContext, isRef, nextTick, onMounted, onScopeDispose, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRef, toValue, unref, watch, watchEffect } from "vue";
4
+ import { a as createPlugin, i as useLogger, o as createPluginContext } from "./useLogger-1_ZeBY12.mjs";
5
+ import { t as createRegistry } from "./createRegistry-CWpvSbCe.mjs";
6
+ import { i as createModel, t as createSelection } from "./createSelection-MRyUZyW2.mjs";
7
+ import { t as createSingle } from "./createSingle-BSciC9EJ.mjs";
8
+ import "./createTokens-CQ9C7GTV.mjs";
9
+ import { a as useLocale } from "./useLocale-Sh-2sNiG.mjs";
10
+ import { c as useTimer } from "./useNotifications-CAVQ7hK6.mjs";
11
+ import { t as toArray } from "./toArray-CD2-OxAz.mjs";
12
+ import { a as createFilter } from "./adapter-BFSJsyv7.mjs";
13
+ import { t as createGroup } from "./createGroup-aHt_kvtU.mjs";
14
+ import "./createDataTable-H-PuVigU.mjs";
15
+ import { a as useRules, o as isStandardSchema } from "./useRules-DK4AeNeC.mjs";
16
+ import "./useFeatures-Dhnr-Lg2.mjs";
17
+ import "./usePermissions-D9Oituwy.mjs";
18
+ import { t as MemoryStorageAdapter } from "./memory-BMpJcQjQ.mjs";
19
+ import "./useTheme-FMDQC81h.mjs";
20
+ import { computed, effectScope, hasInjectionContext, isReadonly, isRef, nextTick, onMounted, onScopeDispose, onWatcherCleanup, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRef, toValue, unref, watch, watchEffect } from "vue";
22
21
  //#region src/composables/createBreadcrumbs/index.ts
23
22
  /**
24
23
  * @module createBreadcrumbs
@@ -351,6 +350,7 @@ function createFocusTraversal(items, activate, options = {}) {
351
350
  }
352
351
  /** Focus first non-disabled item in the current row (grid mode) */
353
352
  function rowFirst() {
353
+ /* v8 ignore next 2 -- defensive: rowFirst is only invoked in grid mode (cols > 0) */
354
354
  const cols = toValue(_columns) ?? 0;
355
355
  if (!cols) return first();
356
356
  const all = items();
@@ -367,6 +367,7 @@ function createFocusTraversal(items, activate, options = {}) {
367
367
  }
368
368
  /** Focus last non-disabled item in the current row (grid mode) */
369
369
  function rowLast() {
370
+ /* v8 ignore next 2 -- defensive: rowLast is only invoked in grid mode (cols > 0) */
370
371
  const cols = toValue(_columns) ?? 0;
371
372
  if (!cols) return last();
372
373
  const all = items();
@@ -538,6 +539,9 @@ function useVirtualFocus(items, options) {
538
539
  };
539
540
  }
540
541
  //#endregion
542
+ //#region src/composables/createCombobox/adapters/adapter.ts
543
+ var ComboboxAdapter = class {};
544
+ //#endregion
541
545
  //#region src/composables/createCombobox/adapters/client.ts
542
546
  /**
543
547
  * @module createCombobox/adapters/client
@@ -546,9 +550,10 @@ function useVirtualFocus(items, options) {
546
550
  * Default combobox adapter. Filters items client-side using createFilter.
547
551
  * Synchronous, zero debounce — items update immediately as the user types.
548
552
  */
549
- var ClientAdapter = class {
553
+ var ClientComboboxAdapter = class extends ComboboxAdapter {
550
554
  options;
551
555
  constructor(options = {}) {
556
+ super();
552
557
  this.options = options;
553
558
  }
554
559
  setup(context) {
@@ -588,7 +593,7 @@ var ClientAdapter = class {
588
593
  * The consumer watches `query` via useComboboxContext() or slot props
589
594
  * and provides filtered items reactively.
590
595
  */
591
- var ServerAdapter = class {
596
+ var ServerComboboxAdapter = class extends ComboboxAdapter {
592
597
  setup(context) {
593
598
  const isLoading = shallowRef(false);
594
599
  return {
@@ -613,7 +618,7 @@ var ServerAdapter = class {
613
618
  * chain — it composes existing primitives instead.
614
619
  *
615
620
  * Key features:
616
- * - Adapter-based filtering (client-side or server-side via ClientAdapter/ServerAdapter)
621
+ * - Adapter-based filtering (client-side or server-side via ClientComboboxAdapter/ServerComboboxAdapter)
617
622
  * - Single or multi-select mode
618
623
  * - Virtual focus keyboard navigation (aria-activedescendant pattern)
619
624
  * - Strict mode: reverts query to selected value on close if no match
@@ -690,7 +695,7 @@ function createCombobox(options = {}) {
690
695
  version.value;
691
696
  return [...selection.values()];
692
697
  });
693
- const { filtered, isLoading, isEmpty } = (adapter ?? new ClientAdapter()).setup({
698
+ const { filtered, isLoading, isEmpty } = (adapter ?? new ClientComboboxAdapter()).setup({
694
699
  query,
695
700
  items
696
701
  });
@@ -1215,6 +1220,327 @@ function createInput(options) {
1215
1220
  };
1216
1221
  }
1217
1222
  //#endregion
1223
+ //#region src/composables/createSortable/index.ts
1224
+ /**
1225
+ * @module createSortable
1226
+ *
1227
+ * @see https://0.vuetifyjs.com/composables/data/create-sortable
1228
+ *
1229
+ * @remarks
1230
+ * Headless ordered-list primitive. Extends `createModel` with mutation primitives
1231
+ * (`swap`, `reorder`) and an enriched `move:ticket` event on the registry event
1232
+ * bus. Honors `disabled` as a real mutation gate at both root and per-ticket scope.
1233
+ *
1234
+ * Pure logical composable — no DnD, no DOM, no keyboard. Drag-and-drop integration
1235
+ * composes with `useDragDrop`; keyboard reorder composes with `useVirtualFocus`.
1236
+ *
1237
+ * @example
1238
+ * ```ts
1239
+ * import { createSortable } from '@vuetify/v0'
1240
+ * import type { SortableTicketInput } from '@vuetify/v0'
1241
+ *
1242
+ * interface TaskTicket extends SortableTicketInput {
1243
+ * value: { id: number; label: string }
1244
+ * }
1245
+ *
1246
+ * const sortable = createSortable<TaskTicket>()
1247
+ * const a = sortable.register({ value: { id: 1, label: 'A' } })
1248
+ * const b = sortable.register({ value: { id: 2, label: 'B' } })
1249
+ *
1250
+ * sortable.move(a.id, 1)
1251
+ * sortable.on('move:ticket', ({ ticket, from, to }) => {
1252
+ * console.log(`${ticket.value.label} moved ${from} → ${to}`)
1253
+ * })
1254
+ * ```
1255
+ */
1256
+ /**
1257
+ * Create an ordered-list state primitive.
1258
+ *
1259
+ * @param options Sortable options.
1260
+ * @returns A {@link SortableContext} that extends {@link ModelContext}.
1261
+ *
1262
+ * @example
1263
+ * ```ts
1264
+ * const sortable = createSortable<Todo>()
1265
+ * sortable.onboard(todos.value.map(value => ({ value })))
1266
+ * ```
1267
+ */
1268
+ function createSortable(_options = {}) {
1269
+ const { disabled, ...options } = _options;
1270
+ const model = createModel({
1271
+ ...options,
1272
+ events: true,
1273
+ disabled
1274
+ });
1275
+ const logger = useLogger();
1276
+ function move(id, toIndex) {
1277
+ if (toValue(disabled)) return void 0;
1278
+ const ticket = model.get(id);
1279
+ if (!ticket) return void 0;
1280
+ if (toValue(ticket.disabled)) return void 0;
1281
+ const from = ticket.index;
1282
+ const result = model.move(id, toIndex);
1283
+ if (result && result.index !== from) model.emit("move:ticket", {
1284
+ ticket: result,
1285
+ from,
1286
+ to: result.index
1287
+ });
1288
+ return result;
1289
+ }
1290
+ function swap(a, b) {
1291
+ if (toValue(disabled)) return;
1292
+ if (a === b) return;
1293
+ const ta = model.get(a);
1294
+ const tb = model.get(b);
1295
+ if (!ta || !tb) return;
1296
+ if (toValue(ta.disabled) || toValue(tb.disabled)) return;
1297
+ const indexA = ta.index;
1298
+ const indexB = tb.index;
1299
+ model.batch(() => {
1300
+ const ra = model.move(a, indexB);
1301
+ if (ra && ra.index !== indexA) model.emit("move:ticket", {
1302
+ ticket: ra,
1303
+ from: indexA,
1304
+ to: ra.index
1305
+ });
1306
+ const rb = model.move(b, indexA);
1307
+ if (rb && rb.index !== indexB) model.emit("move:ticket", {
1308
+ ticket: rb,
1309
+ from: indexB,
1310
+ to: rb.index
1311
+ });
1312
+ });
1313
+ }
1314
+ function reorder(ids) {
1315
+ if (toValue(disabled)) return;
1316
+ const currentSize = model.size;
1317
+ if (ids.length !== currentSize) {
1318
+ logger.warn(`Reorder expected ${currentSize} ids, got ${ids.length}.`);
1319
+ return;
1320
+ }
1321
+ const known = new Set(model.keys());
1322
+ const seen = /* @__PURE__ */ new Set();
1323
+ for (const id of ids) {
1324
+ if (!known.has(id)) {
1325
+ logger.warn(`Reorder contains unknown id "${String(id)}".`);
1326
+ return;
1327
+ }
1328
+ if (seen.has(id)) {
1329
+ logger.warn(`Reorder contains duplicate id "${String(id)}".`);
1330
+ return;
1331
+ }
1332
+ seen.add(id);
1333
+ }
1334
+ const froms = /* @__PURE__ */ new Map();
1335
+ for (const id of ids) {
1336
+ const ticket = model.get(id);
1337
+ if (ticket) froms.set(id, ticket.index);
1338
+ }
1339
+ model.batch(() => {
1340
+ model.reorder(ids);
1341
+ for (const [index, id] of ids.entries()) {
1342
+ const from = froms.get(id);
1343
+ if (from === index) continue;
1344
+ const ticket = model.get(id);
1345
+ if (ticket) model.emit("move:ticket", {
1346
+ ticket,
1347
+ from,
1348
+ to: index
1349
+ });
1350
+ }
1351
+ });
1352
+ }
1353
+ return {
1354
+ ...model,
1355
+ move,
1356
+ swap,
1357
+ reorder,
1358
+ get size() {
1359
+ return model.size;
1360
+ }
1361
+ };
1362
+ }
1363
+ //#endregion
1364
+ //#region src/composables/createKanban/index.ts
1365
+ /**
1366
+ * @module createKanban
1367
+ *
1368
+ * @see https://0.vuetifyjs.com/composables/data/create-kanban
1369
+ *
1370
+ * @remarks
1371
+ * Headless data-flow management for two-level sortable boards. Wraps a column
1372
+ * sortable; each column ticket carries its own inner sortable on `column.items`.
1373
+ * Adds a `transfer` primitive for cross-column moves with reused `disabled`
1374
+ * gating and a destination-side `accept` predicate. Pure logic — no DnD, no DOM.
1375
+ *
1376
+ * @example
1377
+ * ```ts
1378
+ * import { createKanban } from '@vuetify/v0'
1379
+ * import type { SortableTicketInput } from '@vuetify/v0'
1380
+ *
1381
+ * interface CardTicket extends SortableTicketInput {
1382
+ * value: { title: string }
1383
+ * }
1384
+ *
1385
+ * const kanban = createKanban<CardTicket>()
1386
+ *
1387
+ * const todo = kanban.columns.register({ value: { title: 'Todo' } })
1388
+ * const done = kanban.columns.register({ value: { title: 'Done' } })
1389
+ *
1390
+ * const card = todo.items.register({ value: { title: 'Write spec' } })
1391
+ *
1392
+ * kanban.on('transfer:ticket', ({ ticket, from, to }) => {
1393
+ * console.log(ticket.value.title, from, '→', to)
1394
+ * })
1395
+ *
1396
+ * kanban.transfer(card.id, done.id, 0)
1397
+ * ```
1398
+ */
1399
+ /**
1400
+ * Create a headless two-level sortable orchestrator.
1401
+ *
1402
+ * @param options Kanban options (currently only `disabled`).
1403
+ * @returns A {@link KanbanContext}.
1404
+ *
1405
+ * @example
1406
+ * ```ts
1407
+ * import { createKanban } from '@vuetify/v0'
1408
+ * import type { KanbanColumnTicketInput, SortableTicketInput } from '@vuetify/v0'
1409
+ *
1410
+ * interface CardTicket extends SortableTicketInput {
1411
+ * value: { title: string }
1412
+ * }
1413
+ *
1414
+ * interface BoardColumn extends KanbanColumnTicketInput<CardTicket> {
1415
+ * value: { title: string }
1416
+ * }
1417
+ *
1418
+ * const kanban = createKanban<CardTicket, BoardColumn>()
1419
+ *
1420
+ * const todo = kanban.columns.register({ value: { title: 'Todo' } })
1421
+ * const review = kanban.columns.register({
1422
+ * value: { title: 'Review' },
1423
+ * accept: card => card.value.title.length > 0,
1424
+ * })
1425
+ *
1426
+ * const spec = todo.items.register({ value: { title: 'Write spec' } })
1427
+ * kanban.transfer(spec.id, review.id, 0)
1428
+ * ```
1429
+ */
1430
+ function createKanban(_options = {}) {
1431
+ const { disabled, ...options } = _options;
1432
+ const logger = useLogger();
1433
+ const _columns = createSortable({
1434
+ ...options,
1435
+ disabled
1436
+ });
1437
+ const lookup = createRegistry({ events: true });
1438
+ const bus = createRegistry({ events: true });
1439
+ const on = bus.on;
1440
+ const off = bus.off;
1441
+ const columns = {
1442
+ ..._columns,
1443
+ register(registration) {
1444
+ let ticket;
1445
+ const items = createSortable({ disabled: () => !!toValue(disabled) || !!toValue(ticket?.disabled) });
1446
+ items.on("register:ticket", (t) => {
1447
+ lookup.upsert(t.id, { value: ticket.id });
1448
+ });
1449
+ items.on("unregister:ticket", (t) => {
1450
+ lookup.get(t.id)?.unregister();
1451
+ });
1452
+ ticket = _columns.register({
1453
+ ...registration,
1454
+ items
1455
+ });
1456
+ return ticket;
1457
+ },
1458
+ onboard(registrations) {
1459
+ return _columns.batch(() => registrations.map((reg) => columns.register(reg)));
1460
+ },
1461
+ upsert(id, patch = {}, event) {
1462
+ return /* @__PURE__ */ isUndefined(_columns.get(id)) ? columns.register({
1463
+ ...patch,
1464
+ id
1465
+ }) : _columns.upsert(id, patch, event);
1466
+ },
1467
+ get size() {
1468
+ return _columns.size;
1469
+ }
1470
+ };
1471
+ function isAccepted(accept, ticket, from, toIndex) {
1472
+ if (/* @__PURE__ */ isUndefined(accept)) return true;
1473
+ try {
1474
+ const result = accept(ticket, from, toIndex);
1475
+ if (/* @__PURE__ */ isThenable(result)) {
1476
+ logger.warn("accept predicate returned a thenable; async predicates are not supported — treating as reject");
1477
+ return false;
1478
+ }
1479
+ return Boolean(result);
1480
+ } catch (error) {
1481
+ logger.error("accept predicate threw; treating as reject", error);
1482
+ return false;
1483
+ }
1484
+ }
1485
+ columns.on("unregister:ticket", (column) => {
1486
+ column.items.dispose();
1487
+ for (const t of lookup.values()) if (t.value === column.id) t.unregister();
1488
+ });
1489
+ function transfer(id, toColumnId, toIndex) {
1490
+ const fromColumnId = lookup.get(id)?.value;
1491
+ if (/* @__PURE__ */ isUndefined(fromColumnId)) {
1492
+ logger.warn(`unknown ticket id "${String(id)}"`);
1493
+ return;
1494
+ }
1495
+ const source = columns.get(fromColumnId);
1496
+ if (!source) {
1497
+ logger.warn(`unknown source column id "${String(fromColumnId)}"`);
1498
+ return;
1499
+ }
1500
+ const destination = columns.get(toColumnId);
1501
+ if (!destination) {
1502
+ logger.warn(`unknown destination column id "${String(toColumnId)}"`);
1503
+ return;
1504
+ }
1505
+ const ticket = source.items.get(id);
1506
+ if (!ticket) {
1507
+ logger.warn(`ticket "${String(id)}" missing from source column "${String(fromColumnId)}"`);
1508
+ return;
1509
+ }
1510
+ const fromIndex = ticket.index;
1511
+ if (toColumnId === fromColumnId) return source.items.move(id, toIndex);
1512
+ if (toValue(disabled) || toValue(source.disabled) || toValue(destination.disabled) || toValue(ticket.disabled)) return;
1513
+ if (!isAccepted(destination.accept, ticket, fromColumnId, toIndex)) return void 0;
1514
+ if (!/* @__PURE__ */ isUndefined(destination.items.get(id))) {
1515
+ logger.warn(`id "${String(id)}" already exists in destination column "${String(toColumnId)}"`);
1516
+ return;
1517
+ }
1518
+ let registered;
1519
+ let moved;
1520
+ destination.items.batch(() => {
1521
+ const [input] = source.items.offboard([id]);
1522
+ if (/* @__PURE__ */ isUndefined(input)) return;
1523
+ registered = destination.items.register(input);
1524
+ moved = registered.index === toIndex ? registered : destination.items.move(registered.id, toIndex);
1525
+ });
1526
+ const final = moved ?? registered;
1527
+ if (final) bus.emit("transfer:ticket", {
1528
+ ticket: final,
1529
+ from: fromColumnId,
1530
+ to: toColumnId,
1531
+ fromIndex,
1532
+ toIndex: final.index
1533
+ });
1534
+ return final;
1535
+ }
1536
+ return {
1537
+ columns,
1538
+ transfer,
1539
+ on,
1540
+ off
1541
+ };
1542
+ }
1543
+ //#endregion
1218
1544
  //#region src/composables/createNested/index.ts
1219
1545
  /**
1220
1546
  * @module createNested
@@ -2079,6 +2405,193 @@ function createNumberField(options = {}) {
2079
2405
  };
2080
2406
  }
2081
2407
  //#endregion
2408
+ //#region src/composables/createOtp/index.ts
2409
+ /**
2410
+ * @module createOtp
2411
+ *
2412
+ * @see https://0.vuetifyjs.com/composables/forms/create-otp
2413
+ *
2414
+ * @remarks
2415
+ * Headless state for a fixed-length one-time-password / verification-code value.
2416
+ * Owns the joined string, per-character pattern matching, length contract,
2417
+ * completion edge detection with a decisional async `onComplete` hook, and
2418
+ * validation through `createInput`. Rendering, focus, and per-element event
2419
+ * wiring are the consumer's responsibility.
2420
+ *
2421
+ * @example
2422
+ * ```ts
2423
+ * import { createOtp } from '@vuetify/v0'
2424
+ *
2425
+ * const otp = createOtp({
2426
+ * length: 6,
2427
+ * pattern: 'numeric',
2428
+ * onComplete: async value => {
2429
+ * const ok = await verify(value)
2430
+ * return ok
2431
+ * },
2432
+ * })
2433
+ *
2434
+ * otp.write(0, '4')
2435
+ * otp.distribute('12345', 1) // returns 5; value becomes '412345'
2436
+ * otp.isComplete.value // true
2437
+ * ```
2438
+ */
2439
+ const PRESETS = {
2440
+ numeric: /^[0-9]$/,
2441
+ alphanumeric: /^[a-zA-Z0-9]$/,
2442
+ alphabetic: /^[a-zA-Z]$/
2443
+ };
2444
+ const WARNED_PATTERNS = /* @__PURE__ */ new WeakSet();
2445
+ function createOtp(options = {}) {
2446
+ const { value = shallowRef(""), length = 6, pattern = "numeric", disabled = false, readonly: _readonly = false, onComplete, ...inputOptions } = options;
2447
+ const logger = useLogger();
2448
+ const errorRef = shallowRef(false);
2449
+ const errorMessagesRef = shallowRef(void 0);
2450
+ const input = createInput({
2451
+ ...inputOptions,
2452
+ value,
2453
+ disabled,
2454
+ readonly: _readonly,
2455
+ error: errorRef,
2456
+ errorMessages: errorMessagesRef
2457
+ });
2458
+ const lengthRef = toRef(() => toValue(length));
2459
+ let lastCompleted = "";
2460
+ function compile(resolved) {
2461
+ if (/* @__PURE__ */ isString(resolved)) return PRESETS[resolved];
2462
+ if (process.env.NODE_ENV !== "production" && !WARNED_PATTERNS.has(resolved)) {
2463
+ WARNED_PATTERNS.add(resolved);
2464
+ if (resolved.test("aa") || resolved.test("00")) logger.warn("createOtp: pattern matches multi-character input; per-character matching may behave unexpectedly");
2465
+ }
2466
+ return resolved;
2467
+ }
2468
+ function accepts(char) {
2469
+ if (char.length !== 1) return false;
2470
+ return compile(toValue(pattern)).test(char);
2471
+ }
2472
+ function filterAccepted(text) {
2473
+ let out = "";
2474
+ for (const ch of text) if (accepts(ch)) out += ch;
2475
+ return out;
2476
+ }
2477
+ const isPending = shallowRef(false);
2478
+ function isLocked() {
2479
+ return toValue(disabled) || toValue(_readonly) || isPending.value;
2480
+ }
2481
+ function clearRejection() {
2482
+ if (errorRef.value || errorMessagesRef.value) {
2483
+ errorRef.value = false;
2484
+ errorMessagesRef.value = void 0;
2485
+ }
2486
+ }
2487
+ function write(index, char) {
2488
+ if (isLocked()) return;
2489
+ const max = toValue(lengthRef);
2490
+ if (index < 0 || index >= max) return;
2491
+ if (char === "") {
2492
+ clearRejection();
2493
+ value.value = value.value.slice(0, index);
2494
+ return;
2495
+ }
2496
+ const first = char[0];
2497
+ if (!accepts(first)) return;
2498
+ clearRejection();
2499
+ const current = value.value;
2500
+ const head = current.slice(0, index);
2501
+ const tail = current.slice(index + 1);
2502
+ value.value = (head + first + tail).slice(0, max);
2503
+ }
2504
+ function distribute(text, index = 0) {
2505
+ if (isLocked()) return 0;
2506
+ const max = toValue(lengthRef);
2507
+ const start = /* @__PURE__ */ clamp(index, 0, max);
2508
+ const filtered = filterAccepted(text);
2509
+ if (filtered.length === 0) return 0;
2510
+ clearRejection();
2511
+ const head = value.value.slice(0, start);
2512
+ const next = (head + filtered).slice(0, max);
2513
+ value.value = next;
2514
+ return next.length - head.length;
2515
+ }
2516
+ function clear() {
2517
+ if (isLocked()) return;
2518
+ clearRejection();
2519
+ lastCompleted = "";
2520
+ value.value = "";
2521
+ }
2522
+ function fill(text) {
2523
+ if (isLocked()) return;
2524
+ const max = toValue(lengthRef);
2525
+ const filtered = filterAccepted(text).slice(0, max);
2526
+ if (text.length === 0 || filtered.length > 0) clearRejection();
2527
+ value.value = filtered;
2528
+ }
2529
+ function reject() {
2530
+ errorRef.value = true;
2531
+ errorMessagesRef.value = ["Invalid code"];
2532
+ lastCompleted = "";
2533
+ value.value = "";
2534
+ }
2535
+ const isComplete = toRef(() => {
2536
+ const max = toValue(lengthRef);
2537
+ const v = value.value;
2538
+ if (v.length !== max) return false;
2539
+ const re = compile(toValue(pattern));
2540
+ for (const ch of v) if (!re.test(ch)) return false;
2541
+ return true;
2542
+ });
2543
+ watch(value, (next) => {
2544
+ if (!isComplete.value) {
2545
+ lastCompleted = "";
2546
+ return;
2547
+ }
2548
+ if (!onComplete) return;
2549
+ if (isLocked()) return;
2550
+ if (next === lastCompleted) return;
2551
+ lastCompleted = next;
2552
+ let result;
2553
+ try {
2554
+ result = onComplete(next);
2555
+ } catch (error) {
2556
+ logger.warn("createOtp: onComplete threw", error);
2557
+ reject();
2558
+ return;
2559
+ }
2560
+ if (/* @__PURE__ */ isThenable(result)) {
2561
+ isPending.value = true;
2562
+ result.then((ok) => {
2563
+ isPending.value = false;
2564
+ if (ok === false) reject();
2565
+ }, (error) => {
2566
+ isPending.value = false;
2567
+ logger.warn("createOtp: onComplete rejected", error);
2568
+ reject();
2569
+ });
2570
+ return;
2571
+ }
2572
+ if (result === false) reject();
2573
+ });
2574
+ return {
2575
+ value,
2576
+ length: lengthRef,
2577
+ input: {
2578
+ ...input,
2579
+ reset() {
2580
+ clearRejection();
2581
+ lastCompleted = "";
2582
+ input.reset();
2583
+ }
2584
+ },
2585
+ isComplete,
2586
+ isValidating: isPending,
2587
+ write,
2588
+ distribute,
2589
+ clear,
2590
+ fill,
2591
+ accepts
2592
+ };
2593
+ }
2594
+ //#endregion
2082
2595
  //#region src/composables/useHydration/index.ts
2083
2596
  /**
2084
2597
  * @module useHydration
@@ -2468,6 +2981,7 @@ function useElementSize(target) {
2468
2981
  const height = shallowRef(0);
2469
2982
  const { pause: _pause, resume, stop, isActive, isPaused } = useResizeObserver(target, (entries) => {
2470
2983
  const entry = entries[0];
2984
+ /* v8 ignore next 4 -- defensive: ResizeObserver always passes an entry array with at least one entry */
2471
2985
  if (entry) {
2472
2986
  width.value = entry.contentRect.width;
2473
2987
  height.value = entry.contentRect.height;
@@ -2481,7 +2995,7 @@ function useElementSize(target) {
2481
2995
  return {
2482
2996
  width: shallowReadonly(width),
2483
2997
  height: shallowReadonly(height),
2484
- isActive,
2998
+ isActive: shallowReadonly(isActive),
2485
2999
  isPaused: shallowReadonly(isPaused),
2486
3000
  pause,
2487
3001
  resume,
@@ -2626,6 +3140,7 @@ function createOverflow(options = {}) {
2626
3140
  }),
2627
3141
  total,
2628
3142
  isOverflowing: toRef(() => {
3143
+ if (width.value === 0) return false;
2629
3144
  return total.value > width.value - toValue(reserved);
2630
3145
  }),
2631
3146
  measure,
@@ -2778,7 +3293,7 @@ function createProgress(options = {}) {
2778
3293
  }
2779
3294
  for (const [index, element] of clamped.entries()) {
2780
3295
  const ticket = segments.value[index];
2781
- if (!ticket || !isRef(ticket.value)) continue;
3296
+ if (!ticket || !isRef(ticket.value) || isReadonly(ticket.value)) continue;
2782
3297
  ticket.value.value = element;
2783
3298
  }
2784
3299
  }
@@ -3636,6 +4151,7 @@ function createVirtual(items, _options = {}) {
3636
4151
  /* v8 ignore stop */
3637
4152
  });
3638
4153
  useResizeObserver(element, (entries) => {
4154
+ /* v8 ignore next -- defensive: ResizeObserver always emits at least one entry */
3639
4155
  if (!entries[0]) return;
3640
4156
  viewportHeight.value = entries[0].contentRect.height;
3641
4157
  update();
@@ -3648,6 +4164,7 @@ function createVirtual(items, _options = {}) {
3648
4164
  rebuild();
3649
4165
  }, { immediate: true });
3650
4166
  watch(element, () => {
4167
+ /* v8 ignore next -- defensive: watch fires only when element is present */
3651
4168
  if (!element.value) return;
3652
4169
  if (direction === "reverse" && items.value.length > 0) {
3653
4170
  const lastIndex = items.value.length - 1;
@@ -3666,6 +4183,7 @@ function createVirtual(items, _options = {}) {
3666
4183
  anchorOffset = 0;
3667
4184
  } else if (/* @__PURE__ */ isFunction(anchor)) {
3668
4185
  const result = anchor(items.value);
4186
+ /* v8 ignore next 4 -- function-anchor: tested with valid number return; non-number rejection branch is implicit */
3669
4187
  if (/* @__PURE__ */ isNumber(result)) {
3670
4188
  anchorIndex = result;
3671
4189
  anchorOffset = element.value.scrollTop - (offsets.value[result] || 0);
@@ -3749,8 +4267,10 @@ function createVirtual(items, _options = {}) {
3749
4267
  /* v8 ignore stop */
3750
4268
  }
3751
4269
  function resize(index, height) {
4270
+ /* v8 ignore next -- early bail when height is already correct */
3752
4271
  if (heights.value[index] === height) return;
3753
4272
  heights.value[index] = height;
4273
+ /* v8 ignore next -- first-call only: itemHeight bootstrapped from initial measurement */
3754
4274
  if (!itemHeight.value) itemHeight.value = height;
3755
4275
  if (IN_BROWSER) {
3756
4276
  cancelAnimationFrame(rebuildRaf);
@@ -3767,6 +4287,7 @@ function createVirtual(items, _options = {}) {
3767
4287
  /* v8 ignore stop */
3768
4288
  }
3769
4289
  function scrollTo(index, scrollOptions) {
4290
+ /* v8 ignore next -- defensive: scrollTo only invoked after element mounts */
3770
4291
  if (!element.value) return;
3771
4292
  const targetOffset = offsets.value[index] || 0;
3772
4293
  const behavior = scrollOptions?.behavior ?? "auto";
@@ -3892,6 +4413,124 @@ function useVirtual(namespace = "v0:virtual") {
3892
4413
  return useContext(namespace);
3893
4414
  }
3894
4415
  //#endregion
4416
+ //#region src/composables/toHighlight/index.ts
4417
+ /**
4418
+ * @module toHighlight
4419
+ *
4420
+ * @see https://0.vuetifyjs.com/composables/transformers/to-highlight
4421
+ *
4422
+ * @remarks
4423
+ * Pure transformer — no DOM, no state, no registry, no reactivity. Splits text
4424
+ * into matched and unmatched chunks given a query string, an array of query
4425
+ * strings, or pre-computed `[start, end]` match ranges (e.g., from createFilter).
4426
+ * Returns a plain array; wrap the call in `computed()` for reactive recomputation.
4427
+ *
4428
+ * @example
4429
+ * ```ts
4430
+ * import { toHighlight } from '@vuetify/v0'
4431
+ *
4432
+ * const chunks = toHighlight('Hello World', 'World')
4433
+ * // [{ text: 'Hello ', match: false }, { text: 'World', match: true }]
4434
+ * ```
4435
+ */
4436
+ function merge(ranges) {
4437
+ const sorted = ranges.filter((span) => span[0] < span[1]).toSorted((a, b) => a[0] - b[0]);
4438
+ const merged = [];
4439
+ for (const span of sorted) {
4440
+ const last = merged.at(-1);
4441
+ if (last && span[0] <= last[1]) last[1] = Math.max(last[1], span[1]);
4442
+ else merged.push([span[0], span[1]]);
4443
+ }
4444
+ return merged;
4445
+ }
4446
+ function chunk(text, ranges) {
4447
+ const chunks = [];
4448
+ let cursor = 0;
4449
+ for (const [start, end] of ranges) {
4450
+ if (cursor < start) chunks.push({
4451
+ text: text.slice(cursor, start),
4452
+ match: false
4453
+ });
4454
+ chunks.push({
4455
+ text: text.slice(start, end),
4456
+ match: true
4457
+ });
4458
+ cursor = end;
4459
+ }
4460
+ if (cursor < text.length) chunks.push({
4461
+ text: text.slice(cursor),
4462
+ match: false
4463
+ });
4464
+ return chunks;
4465
+ }
4466
+ function find(text, query, matchAll, ignoreCase) {
4467
+ const terms = (/* @__PURE__ */ toArray(query)).filter(Boolean);
4468
+ const haystack = ignoreCase ? text.toLocaleLowerCase() : text;
4469
+ const spans = [];
4470
+ for (const term of terms) {
4471
+ const needle = ignoreCase ? term.toLocaleLowerCase() : term;
4472
+ let index = haystack.indexOf(needle);
4473
+ if (index !== -1) {
4474
+ spans.push([index, index + term.length]);
4475
+ if (matchAll) {
4476
+ index = haystack.indexOf(needle, index + term.length);
4477
+ while (index !== -1) {
4478
+ spans.push([index, index + term.length]);
4479
+ index = haystack.indexOf(needle, index + term.length);
4480
+ }
4481
+ }
4482
+ }
4483
+ }
4484
+ return merge(spans);
4485
+ }
4486
+ /**
4487
+ * Splits text into matched and unmatched chunks.
4488
+ *
4489
+ * Pure transformer — returns a plain array. Wrap the call in `computed()` for
4490
+ * reactive recomputation.
4491
+ *
4492
+ * Priority: `options.matches` (when non-empty) → `query` → no-match fallback.
4493
+ *
4494
+ * @param text The source string to split.
4495
+ * @param query One or more search terms. Empty strings are ignored. Case sensitivity controlled by `options.ignoreCase`.
4496
+ * @param options Optional `matches`, `matchAll`, `ignoreCase`.
4497
+ * @returns A `HighlightChunk[]` array.
4498
+ *
4499
+ * @see https://0.vuetifyjs.com/composables/transformers/to-highlight
4500
+ *
4501
+ * @example
4502
+ * ```ts
4503
+ * import { computed, shallowRef } from 'vue'
4504
+ * import { toHighlight } from '@vuetify/v0'
4505
+ *
4506
+ * const query = shallowRef('World')
4507
+ * const chunks = computed(() => toHighlight('Hello World', query))
4508
+ *
4509
+ * console.log(chunks.value)
4510
+ * // [{ text: 'Hello ', match: false }, { text: 'World', match: true }]
4511
+ * ```
4512
+ */
4513
+ /* @__NO_SIDE_EFFECTS__ */
4514
+ function toHighlight(text, query, options = {}) {
4515
+ const _text = toValue(text);
4516
+ const _query = toValue(query);
4517
+ const _matches = toValue(options.matches);
4518
+ const matchAll = toValue(options.matchAll) ?? false;
4519
+ const ignoreCase = toValue(options.ignoreCase) ?? false;
4520
+ if (_matches?.length) return chunk(_text, merge(_matches));
4521
+ if (_query) {
4522
+ const ranges = find(_text, _query, matchAll, ignoreCase);
4523
+ return ranges.length > 0 ? chunk(_text, ranges) : [{
4524
+ text: _text,
4525
+ match: false
4526
+ }];
4527
+ }
4528
+ return [{
4529
+ text: _text,
4530
+ match: false
4531
+ }];
4532
+ }
4533
+ //#endregion
3895
4534
  //#region src/composables/toReactive/index.ts
3896
4535
  /**
3897
4536
  * @module toReactive
@@ -4286,11 +4925,11 @@ const [createBreakpointsContext, createBreakpointsPlugin, useBreakpoints] = crea
4286
4925
  *
4287
4926
  * @example Using the built-in Temporal adapter
4288
4927
  * ```ts
4289
- * import { Vuetify0DateAdapter } from '@vuetify/v0/date'
4928
+ * import { V0DateAdapter } from '@vuetify/v0/date'
4290
4929
  * import { createDatePlugin } from '@vuetify/v0'
4291
4930
  *
4292
4931
  * const app = createApp(App)
4293
- * app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))
4932
+ * app.use(createDatePlugin({ adapter: new V0DateAdapter() }))
4294
4933
  *
4295
4934
  * // In a component:
4296
4935
  * const { adapter } = useDate()
@@ -4300,9 +4939,9 @@ const [createBreakpointsContext, createBreakpointsPlugin, useBreakpoints] = crea
4300
4939
  *
4301
4940
  * @example Custom adapter
4302
4941
  * ```ts
4303
- * import type { DateAdapter } from '@vuetify/v0'
4942
+ * import { DateAdapter } from '@vuetify/v0'
4304
4943
  *
4305
- * class DateFnsAdapter implements DateAdapter<Date> {
4944
+ * class DateFnsAdapter extends DateAdapter<Date> {
4306
4945
  * // ... implementation
4307
4946
  * }
4308
4947
  *
@@ -4333,6 +4972,7 @@ const defaultLocales = {
4333
4972
  function deriveFirstDayOfWeek(locale) {
4334
4973
  try {
4335
4974
  const info = new Intl.Locale(locale).getWeekInfo?.();
4975
+ /* v8 ignore next -- defensive: getWeekInfo always returns info in Node 22+ */
4336
4976
  return info ? info.firstDay % 7 : 0;
4337
4977
  } catch {
4338
4978
  return 0;
@@ -4350,14 +4990,14 @@ function deriveFirstDayOfWeek(locale) {
4350
4990
  *
4351
4991
  * @example
4352
4992
  * ```ts
4353
- * import { Vuetify0DateAdapter } from '@vuetify/v0/date'
4993
+ * import { V0DateAdapter } from '@vuetify/v0/date'
4354
4994
  *
4355
- * const { adapter } = createDate({ adapter: new Vuetify0DateAdapter() })
4995
+ * const { adapter } = createDate({ adapter: new V0DateAdapter() })
4356
4996
  * const today = adapter.date()
4357
4997
  *
4358
4998
  * // With locale options
4359
4999
  * const { adapter } = createDate({
4360
- * adapter: new Vuetify0DateAdapter(),
5000
+ * adapter: new V0DateAdapter(),
4361
5001
  * locale: 'de-DE',
4362
5002
  * })
4363
5003
  * ```
@@ -4412,10 +5052,10 @@ function createDate(options) {
4412
5052
  *
4413
5053
  * @example
4414
5054
  * ```ts
4415
- * import { Vuetify0DateAdapter } from '@vuetify/v0/date'
5055
+ * import { V0DateAdapter } from '@vuetify/v0/date'
4416
5056
  *
4417
5057
  * const [useAppDate, provideAppDate] = createDateContext({
4418
- * adapter: new Vuetify0DateAdapter(),
5058
+ * adapter: new V0DateAdapter(),
4419
5059
  * namespace: 'app:date',
4420
5060
  * })
4421
5061
  * ```
@@ -4436,14 +5076,14 @@ function createDateContext(options) {
4436
5076
  *
4437
5077
  * @example
4438
5078
  * ```ts
4439
- * import { Vuetify0DateAdapter } from '@vuetify/v0/date'
5079
+ * import { V0DateAdapter } from '@vuetify/v0/date'
4440
5080
  *
4441
5081
  * const app = createApp(App)
4442
- * app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))
5082
+ * app.use(createDatePlugin({ adapter: new V0DateAdapter() }))
4443
5083
  *
4444
5084
  * // With locale options
4445
5085
  * app.use(createDatePlugin({
4446
- * adapter: new Vuetify0DateAdapter(),
5086
+ * adapter: new V0DateAdapter(),
4447
5087
  * locale: 'de-DE',
4448
5088
  * }))
4449
5089
  * ```
@@ -4477,10 +5117,10 @@ function createDatePlugin(options) {
4477
5117
  * @example
4478
5118
  * ```ts
4479
5119
  * // main.ts
4480
- * import { Vuetify0DateAdapter } from '@vuetify/v0/date'
5120
+ * import { V0DateAdapter } from '@vuetify/v0/date'
4481
5121
  * import { createDatePlugin } from '@vuetify/v0'
4482
5122
  *
4483
- * app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))
5123
+ * app.use(createDatePlugin({ adapter: new V0DateAdapter() }))
4484
5124
  * ```
4485
5125
  *
4486
5126
  * @example
@@ -4494,7 +5134,7 @@ function createDatePlugin(options) {
4494
5134
  * ```
4495
5135
  */
4496
5136
  function useDate(namespace = "v0:date") {
4497
- if (!/* @__PURE__ */ instanceExists()) throw new Error("[v0] useDate() must be called inside a Vue component with createDatePlugin installed.\n\nExample:\n import { Vuetify0DateAdapter } from '@vuetify/v0/date'\n import { createDatePlugin } from '@vuetify/v0'\n\n app.use(createDatePlugin({ adapter: new Vuetify0DateAdapter() }))");
5137
+ if (!/* @__PURE__ */ instanceExists()) throw new Error("[v0] useDate() must be called inside a Vue component with createDatePlugin installed.\n\nExample:\n import { V0DateAdapter } from '@vuetify/v0/date'\n import { createDatePlugin } from '@vuetify/v0'\n\n app.use(createDatePlugin({ adapter: new V0DateAdapter() }))");
4498
5138
  return useContext(namespace);
4499
5139
  }
4500
5140
  //#endregion
@@ -4615,18 +5255,790 @@ function useDelay(callback, options = {}) {
4615
5255
  };
4616
5256
  }
4617
5257
  //#endregion
4618
- //#region src/composables/useHotkey/aliases.ts
5258
+ //#region src/composables/useMutationObserver/index.ts
4619
5259
  /**
4620
- * Key alias mapping for consistent key normalization across the hotkey system.
5260
+ * @module useMutationObserver
4621
5261
  *
4622
- * Maps user-friendly aliases to canonical key names that match
4623
- * KeyboardEvent.key values (in lowercase) where possible.
5262
+ * @see https://0.vuetifyjs.com/composables/system/use-mutation-observer
5263
+ *
5264
+ * @remarks
5265
+ * MutationObserver composable with lifecycle management.
5266
+ *
5267
+ * Key features:
5268
+ * - MutationObserver API wrapper
5269
+ * - `isActive` reactive flag
5270
+ * - `once` option for single-fire observation
5271
+ * - Pause/resume/stop functionality
5272
+ * - Automatic cleanup on unmount
5273
+ * - SSR-safe (checks SUPPORTS_MUTATION_OBSERVER)
5274
+ * - Hydration-aware
5275
+ * - Configurable observation options (childList, attributes, characterData, etc.)
5276
+ *
5277
+ * Perfect for detecting DOM changes and responding to mutations.
5278
+ *
5279
+ * @example
5280
+ * ```ts
5281
+ * import { useTemplateRef } from 'vue'
5282
+ * import { useMutationObserver } from '@vuetify/v0'
5283
+ *
5284
+ * const target = useTemplateRef('target')
5285
+ * useMutationObserver(target, records => {
5286
+ * console.log(records)
5287
+ * }, { childList: true })
5288
+ * ```
4624
5289
  */
4625
- const keyAliasMap = {
4626
- control: "ctrl",
4627
- command: "cmd",
4628
- option: "alt",
4629
- up: "arrowup",
5290
+ /**
5291
+ * A composable that uses the Mutation Observer API to detect changes in the DOM.
5292
+ *
5293
+ * @param target The element to observe.
5294
+ * @param callback The callback to execute when a mutation is observed.
5295
+ * @param options The options for the Mutation Observer.
5296
+ * @returns An object with methods to control the observer.
5297
+ *
5298
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
5299
+ * @see https://0.vuetifyjs.com/composables/system/use-mutation-observer
5300
+ *
5301
+ * @example
5302
+ * ```ts
5303
+ * import { ref } from 'vue'
5304
+ * import { useMutationObserver } from '@vuetify/v0'
5305
+ *
5306
+ * const container = ref<HTMLElement>()
5307
+ *
5308
+ * const { pause, resume, isPaused } = useMutationObserver(
5309
+ * container,
5310
+ * (mutations) => {
5311
+ * mutations.forEach((mutation) => {
5312
+ * if (mutation.type === 'childList') {
5313
+ * console.log('Children changed:', mutation.addedNodes, mutation.removedNodes)
5314
+ * } else if (mutation.type === 'attributes') {
5315
+ * console.log('Attribute changed:', mutation.attributeName)
5316
+ * }
5317
+ * })
5318
+ * },
5319
+ * {
5320
+ * childList: true,
5321
+ * attributes: true,
5322
+ * subtree: true
5323
+ * }
5324
+ * )
5325
+ *
5326
+ * // Pause observation
5327
+ * pause()
5328
+ *
5329
+ * // Resume observation
5330
+ * resume()
5331
+ * ```
5332
+ */
5333
+ function useMutationObserver(target, callback, options = {}) {
5334
+ const observerOptions = {
5335
+ childList: options.childList ?? true,
5336
+ attributes: options.attributes ?? false,
5337
+ characterData: options.characterData ?? false,
5338
+ subtree: options.subtree ?? false,
5339
+ attributeOldValue: options.attributeOldValue ?? false,
5340
+ characterDataOldValue: options.characterDataOldValue ?? false,
5341
+ attributeFilter: options.attributeFilter
5342
+ };
5343
+ return createObserver(target, callback, {
5344
+ supports: SUPPORTS_MUTATION_OBSERVER,
5345
+ once: options.once,
5346
+ create: (cb) => new MutationObserver((mutations) => {
5347
+ cb(mutations.map((m) => ({
5348
+ type: m.type,
5349
+ target: m.target,
5350
+ addedNodes: m.addedNodes,
5351
+ removedNodes: m.removedNodes,
5352
+ previousSibling: m.previousSibling,
5353
+ nextSibling: m.nextSibling,
5354
+ attributeName: m.attributeName,
5355
+ attributeNamespace: m.attributeNamespace,
5356
+ oldValue: m.oldValue
5357
+ })));
5358
+ }),
5359
+ observe: (obs, el) => obs.observe(el, observerOptions),
5360
+ immediate: options.immediate ? (el) => {
5361
+ const emptyNodeList = {
5362
+ length: 0,
5363
+ item: () => null,
5364
+ forEach: () => {},
5365
+ *[Symbol.iterator]() {}
5366
+ };
5367
+ return [{
5368
+ type: "childList",
5369
+ target: el,
5370
+ addedNodes: emptyNodeList,
5371
+ removedNodes: emptyNodeList,
5372
+ previousSibling: null,
5373
+ nextSibling: null,
5374
+ attributeName: null,
5375
+ attributeNamespace: null,
5376
+ oldValue: null
5377
+ }];
5378
+ } : void 0,
5379
+ onceIncludesImmediate: true
5380
+ });
5381
+ }
5382
+ //#endregion
5383
+ //#region src/composables/useDragDrop/adapters/adapter.ts
5384
+ /**
5385
+ * @module useDragDrop/adapters/adapter
5386
+ *
5387
+ * @remarks
5388
+ * Adapter contract and abstract base for useDragDrop. Concrete adapters extend
5389
+ * `DragDropAdapter<Z>` to share the `cleanup` field, `dispose()` lifecycle, and
5390
+ * the `locate()` DOM-walk helper.
5391
+ */
5392
+ /**
5393
+ * Abstract base class for useDragDrop adapters. Provides a `cleanup` slot, a
5394
+ * `dispose()` lifecycle, and a `locate()` helper that walks the DOM to find the
5395
+ * draggable ticket whose `el` ancestors a given event target.
5396
+ *
5397
+ * @example
5398
+ * ```ts
5399
+ * import { DragDropAdapter, type DragDropAdapterContext } from '@vuetify/v0'
5400
+ *
5401
+ * class MyAdapter extends DragDropAdapter {
5402
+ * setup (context: DragDropAdapterContext) {
5403
+ * const stop = useEventListener(document, 'mousedown', event => {
5404
+ * const ticket = this.locate(event.target, context)
5405
+ * if (ticket) context.emit.start(ticket, { x: event.clientX, y: event.clientY }, 'pointer')
5406
+ * })
5407
+ * this.cleanup = () => stop()
5408
+ * }
5409
+ * }
5410
+ * ```
5411
+ */
5412
+ var DragDropAdapter = class {
5413
+ cleanup = null;
5414
+ dispose() {
5415
+ this.cleanup?.();
5416
+ this.cleanup = null;
5417
+ }
5418
+ locate(target, context) {
5419
+ let element = /* @__PURE__ */ isElement(target) ? target : null;
5420
+ while (element) {
5421
+ for (const ticket of context.draggables.values()) if (ticket.el.value === element) return ticket;
5422
+ element = element.parentElement;
5423
+ }
5424
+ return null;
5425
+ }
5426
+ };
5427
+ //#endregion
5428
+ //#region src/composables/useDragDrop/adapters/pointer.ts
5429
+ /**
5430
+ * @module useDragDrop/adapters/pointer
5431
+ *
5432
+ * @remarks
5433
+ * Default pointer adapter for useDragDrop. Listens for `pointerdown` /
5434
+ * `pointermove` / `pointerup` / `pointercancel` on the document and emits the
5435
+ * drag lifecycle. Activation distance is configurable via `threshold`.
5436
+ */
5437
+ /**
5438
+ * Default pointer adapter. Wires `pointerdown` / `pointermove` / `pointerup` /
5439
+ * `pointercancel` on the document and converts them into drag lifecycle calls.
5440
+ *
5441
+ * @example
5442
+ * ```ts
5443
+ * import { PointerAdapter, useDragDrop } from '@vuetify/v0'
5444
+ *
5445
+ * useDragDrop({ adapters: [new PointerAdapter({ threshold: 10 })] })
5446
+ * ```
5447
+ */
5448
+ var PointerAdapter = class extends DragDropAdapter {
5449
+ threshold;
5450
+ constructor(options = {}) {
5451
+ super();
5452
+ this.threshold = options.threshold ?? 0;
5453
+ }
5454
+ setup(context) {
5455
+ const logger = useLogger();
5456
+ if (this.cleanup) {
5457
+ logger.warn("PointerAdapter setup called twice; previous registration will be replaced");
5458
+ this.dispose();
5459
+ }
5460
+ if (!IN_BROWSER) return;
5461
+ let downSource = null;
5462
+ let downOrigin = null;
5463
+ let downId = null;
5464
+ let started = false;
5465
+ function reset() {
5466
+ downSource = null;
5467
+ downOrigin = null;
5468
+ downId = null;
5469
+ started = false;
5470
+ }
5471
+ const onDown = (event) => {
5472
+ if (event.button !== 0) return;
5473
+ if (downSource) return;
5474
+ const ticket = this.locate(event.target, context);
5475
+ if (!ticket) return;
5476
+ downSource = ticket;
5477
+ downOrigin = {
5478
+ x: event.clientX,
5479
+ y: event.clientY
5480
+ };
5481
+ downId = event.pointerId;
5482
+ started = false;
5483
+ };
5484
+ const onMove = (event) => {
5485
+ if (!downSource || !downOrigin || event.pointerId !== downId) return;
5486
+ const point = {
5487
+ x: event.clientX,
5488
+ y: event.clientY
5489
+ };
5490
+ if (!started) {
5491
+ const dx = point.x - downOrigin.x;
5492
+ const dy = point.y - downOrigin.y;
5493
+ if (this.threshold > 0 && Math.hypot(dx, dy) < this.threshold) return;
5494
+ context.emit.start(downSource, downOrigin, "pointer");
5495
+ started = true;
5496
+ }
5497
+ context.emit.move(point);
5498
+ };
5499
+ function onUp(event) {
5500
+ if (event.pointerId !== downId) return;
5501
+ if (downSource && started) context.emit.drop();
5502
+ reset();
5503
+ }
5504
+ function onCancel(event) {
5505
+ if (event.pointerId !== downId) return;
5506
+ if (downSource && started) context.emit.cancel();
5507
+ reset();
5508
+ }
5509
+ const stopDown = useEventListener(document, "pointerdown", onDown);
5510
+ const stopMove = useEventListener(document, "pointermove", onMove);
5511
+ const stopUp = useEventListener(document, "pointerup", onUp);
5512
+ const stopCancel = useEventListener(document, "pointercancel", onCancel);
5513
+ this.cleanup = () => {
5514
+ stopDown();
5515
+ stopMove();
5516
+ stopUp();
5517
+ stopCancel();
5518
+ };
5519
+ }
5520
+ };
5521
+ //#endregion
5522
+ //#region src/composables/useDragDrop/adapters/keyboard.ts
5523
+ /**
5524
+ * @module useDragDrop/adapters/keyboard
5525
+ *
5526
+ * @remarks
5527
+ * Default keyboard adapter for useDragDrop. Listens for `keydown` on the
5528
+ * document. Activation keys (default Space and Enter) start and drop drags;
5529
+ * arrow keys nudge the drag point by `step` px; Escape cancels.
5530
+ */
5531
+ function isEditable(element) {
5532
+ if (/* @__PURE__ */ isNull(element)) return false;
5533
+ const tag = element.tagName;
5534
+ if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
5535
+ if (element.isContentEditable) return true;
5536
+ const role = element.getAttribute("role");
5537
+ return role === "textbox" || role === "searchbox" || role === "combobox" || role === "spinbutton";
5538
+ }
5539
+ /**
5540
+ * Default keyboard adapter. Listens for `keydown` on the document; activation
5541
+ * keys start/drop drags, arrow keys nudge the drag point, Escape cancels.
5542
+ *
5543
+ * @example
5544
+ * ```ts
5545
+ * import { KeyboardAdapter, useDragDrop } from '@vuetify/v0'
5546
+ *
5547
+ * useDragDrop({ adapters: [new KeyboardAdapter({ activate: ['x'], step: 32 })] })
5548
+ * ```
5549
+ */
5550
+ var KeyboardAdapter = class extends DragDropAdapter {
5551
+ activate;
5552
+ step;
5553
+ constructor(options = {}) {
5554
+ super();
5555
+ this.activate = options.activate ?? [" ", "Enter"];
5556
+ this.step = options.step ?? 16;
5557
+ }
5558
+ setup(context) {
5559
+ const logger = useLogger();
5560
+ if (this.cleanup) {
5561
+ logger.warn("KeyboardAdapter setup called twice; previous registration will be replaced");
5562
+ this.dispose();
5563
+ }
5564
+ if (!IN_BROWSER) return;
5565
+ const onKeyDown = (event) => {
5566
+ const focused = document.activeElement;
5567
+ if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) return;
5568
+ if (isEditable(focused)) return;
5569
+ const ticket = this.locate(focused, context);
5570
+ const isActive = !/* @__PURE__ */ isNull(context.active.value);
5571
+ if (this.activate.includes(event.key)) {
5572
+ if (isActive) {
5573
+ event.preventDefault();
5574
+ context.emit.drop();
5575
+ } else if (ticket) {
5576
+ const el = ticket.el.value;
5577
+ if (!el) {
5578
+ logger.warn("KeyboardAdapter: cannot start drag — element is not mounted");
5579
+ return;
5580
+ }
5581
+ event.preventDefault();
5582
+ const rect = el.getBoundingClientRect();
5583
+ context.emit.start(ticket, {
5584
+ x: rect.left + rect.width / 2,
5585
+ y: rect.top + rect.height / 2
5586
+ }, "keyboard");
5587
+ }
5588
+ return;
5589
+ }
5590
+ if (event.key === "Escape" && isActive) {
5591
+ event.preventDefault();
5592
+ context.emit.cancel();
5593
+ return;
5594
+ }
5595
+ if (isActive && event.key.startsWith("Arrow")) {
5596
+ const active = context.active.value;
5597
+ if (/* @__PURE__ */ isNull(active)) return;
5598
+ const current = active.current;
5599
+ let point = null;
5600
+ switch (event.key) {
5601
+ case "ArrowUp":
5602
+ point = {
5603
+ x: current.x,
5604
+ y: current.y - this.step
5605
+ };
5606
+ break;
5607
+ case "ArrowDown":
5608
+ point = {
5609
+ x: current.x,
5610
+ y: current.y + this.step
5611
+ };
5612
+ break;
5613
+ case "ArrowLeft":
5614
+ point = {
5615
+ x: current.x - this.step,
5616
+ y: current.y
5617
+ };
5618
+ break;
5619
+ case "ArrowRight":
5620
+ point = {
5621
+ x: current.x + this.step,
5622
+ y: current.y
5623
+ };
5624
+ break;
5625
+ }
5626
+ if (point) {
5627
+ event.preventDefault();
5628
+ context.emit.move(point);
5629
+ }
5630
+ }
5631
+ };
5632
+ const stop = useEventListener(document, "keydown", onKeyDown);
5633
+ this.cleanup = () => stop();
5634
+ }
5635
+ };
5636
+ //#endregion
5637
+ //#region src/composables/useDragDrop/index.ts
5638
+ /**
5639
+ * @module useDragDrop
5640
+ *
5641
+ * @see https://0.vuetifyjs.com/composables/system/use-drag-drop
5642
+ *
5643
+ * @remarks
5644
+ * Headless drag-and-drop primitive. Owns two registries (draggables and zones)
5645
+ * plus the active-drag state. Pointer and keyboard adapters ship by default;
5646
+ * lifecycle hooks and a plugin array provide extension points.
5647
+ *
5648
+ * @example
5649
+ * ```ts
5650
+ * import { useDragDrop } from '@vuetify/v0'
5651
+ *
5652
+ * const dnd = useDragDrop()
5653
+ * ```
5654
+ */
5655
+ /**
5656
+ * Pure math for resolving where in an oriented zone a pointer would drop.
5657
+ * Internal — consumers rely on the `position.index` / `position.indicator`
5658
+ * fields delivered to `onDrop`.
5659
+ */
5660
+ function resolveDropPosition(point, rects, orientation) {
5661
+ if (rects.length === 0) return null;
5662
+ const axis = orientation === "vertical" ? "y" : "x";
5663
+ const start = orientation === "vertical" ? "top" : "left";
5664
+ const end = orientation === "vertical" ? "bottom" : "right";
5665
+ const coord = point[axis];
5666
+ if (coord < rects[0][start]) return {
5667
+ index: 0,
5668
+ edge: "before",
5669
+ rect: rects[0]
5670
+ };
5671
+ const last = rects.at(-1);
5672
+ if (coord > last[end]) return {
5673
+ index: rects.length,
5674
+ edge: "after",
5675
+ rect: last
5676
+ };
5677
+ for (const [index, rect] of rects.entries()) if (coord >= rect[start] && coord <= rect[end]) {
5678
+ if (coord < rect[start] + (rect[end] - rect[start]) / 2) return {
5679
+ index,
5680
+ edge: "before",
5681
+ rect
5682
+ };
5683
+ return {
5684
+ index: index + 1,
5685
+ edge: "after",
5686
+ rect
5687
+ };
5688
+ }
5689
+ for (let index = 0; index < rects.length - 1; index++) {
5690
+ const a = rects[index];
5691
+ const b = rects[index + 1];
5692
+ if (coord > a[end] && coord < b[start]) {
5693
+ if (coord <= (a[end] + b[start]) / 2) return {
5694
+ index: index + 1,
5695
+ edge: "after",
5696
+ rect: a
5697
+ };
5698
+ return {
5699
+ index: index + 1,
5700
+ edge: "before",
5701
+ rect: b
5702
+ };
5703
+ }
5704
+ }
5705
+ return {
5706
+ index: rects.length,
5707
+ edge: "after",
5708
+ rect: last
5709
+ };
5710
+ }
5711
+ /**
5712
+ * Create a headless drag-and-drop context.
5713
+ *
5714
+ * @param options - Adapters, plugins, and lifecycle hooks. All optional.
5715
+ * @returns A `DragDropContext<Z>` exposing `draggables` / `zones` registries,
5716
+ * the `active` drag, the `isDragging` boolean, and a programmatic `cancel()`.
5717
+ *
5718
+ * @see https://0.vuetifyjs.com/composables/system/use-drag-drop
5719
+ *
5720
+ * @example
5721
+ * ```ts
5722
+ * import { useDragDrop } from '@vuetify/v0'
5723
+ * import { useTemplateRef } from 'vue'
5724
+ *
5725
+ * const dnd = useDragDrop<{ type: 'card', value: string }>()
5726
+ *
5727
+ * const draggable = useTemplateRef<HTMLElement>('draggable')
5728
+ * const dropzone = useTemplateRef<HTMLElement>('dropzone')
5729
+ *
5730
+ * dnd.draggables.register({ el: draggable, type: 'card', value: 'card-1' })
5731
+ * dnd.zones.register({
5732
+ * el: dropzone,
5733
+ * accept: ['card'],
5734
+ * onDrop: (drag, position) => console.log(drag.value, position.index),
5735
+ * })
5736
+ * ```
5737
+ */
5738
+ function useDragDrop(options = {}) {
5739
+ const { plugins = [] } = options;
5740
+ const logger = useLogger();
5741
+ const _draggables = createRegistry({ events: true });
5742
+ const _zones = createRegistry({ events: true });
5743
+ const active = shallowRef(null);
5744
+ const isDragging = toRef(() => !/* @__PURE__ */ isNull(active.value));
5745
+ const scopes = /* @__PURE__ */ new Map();
5746
+ const nodes = /* @__PURE__ */ new Map();
5747
+ function next(fn, ...args) {
5748
+ if (/* @__PURE__ */ isUndefined(fn)) return;
5749
+ try {
5750
+ fn(...args);
5751
+ } catch (error) {
5752
+ logger.error("useDragDrop hook threw", error);
5753
+ }
5754
+ }
5755
+ function safeAccept(accept, drag) {
5756
+ try {
5757
+ if (/* @__PURE__ */ isNull(drag)) return false;
5758
+ if (/* @__PURE__ */ isUndefined(accept)) return true;
5759
+ if (/* @__PURE__ */ isArray(accept)) return accept.includes(drag.type);
5760
+ const result = accept(drag);
5761
+ if (/* @__PURE__ */ isThenable(result)) {
5762
+ logger.warn("useDragDrop accept predicate returned a thenable; async predicates are not supported — treating as reject");
5763
+ return false;
5764
+ }
5765
+ return Boolean(result);
5766
+ } catch (error) {
5767
+ logger.error("useDragDrop accept predicate threw; treating as reject", error);
5768
+ return false;
5769
+ }
5770
+ }
5771
+ const draggables = {
5772
+ ..._draggables,
5773
+ register(registration) {
5774
+ const id = registration.id ?? /* @__PURE__ */ useId$1();
5775
+ const el = toRef(() => toValue(registration.el));
5776
+ const dragging = toRef(() => active.value?.id === id);
5777
+ const input = {
5778
+ ...registration,
5779
+ id,
5780
+ el,
5781
+ isDragging: dragging
5782
+ };
5783
+ return _draggables.register(input);
5784
+ }
5785
+ };
5786
+ const zones = {
5787
+ ..._zones,
5788
+ register(registration) {
5789
+ const id = registration.id ?? /* @__PURE__ */ useId$1();
5790
+ const el = toRef(() => toValue(registration.el));
5791
+ const isOver = toRef(() => active.value?.over === id);
5792
+ const willAccept = toRef(() => safeAccept(registration.accept, active.value));
5793
+ const rects = shallowRef([]);
5794
+ function refresh() {
5795
+ const zoneEl = el.value;
5796
+ rects.value = zoneEl ? Array.from(zoneEl.children).map((child) => child.getBoundingClientRect()) : [];
5797
+ }
5798
+ const scope = effectScope();
5799
+ scopes.set(id, scope);
5800
+ scope.run(() => {
5801
+ if (registration.orientation) {
5802
+ watch(el, refresh, {
5803
+ immediate: true,
5804
+ flush: "post"
5805
+ });
5806
+ useResizeObserver(el, refresh);
5807
+ useMutationObserver(el, refresh, { childList: true });
5808
+ watch(() => active.value?.id, (id) => {
5809
+ if (id) refresh();
5810
+ });
5811
+ }
5812
+ watch(el, (current) => {
5813
+ if (/* @__PURE__ */ isNull(current)) return;
5814
+ nodes.set(current, id);
5815
+ onWatcherCleanup(() => nodes.delete(current));
5816
+ }, { immediate: true });
5817
+ });
5818
+ const indicator = computed(() => {
5819
+ if (!registration.orientation || !isOver.value || !active.value) return null;
5820
+ return resolveDropPosition(active.value.current, rects.value, registration.orientation);
5821
+ });
5822
+ const input = {
5823
+ ...registration,
5824
+ id,
5825
+ el,
5826
+ isOver,
5827
+ willAccept,
5828
+ indicator
5829
+ };
5830
+ return _zones.register(input);
5831
+ }
5832
+ };
5833
+ function at(point) {
5834
+ if (!IN_BROWSER) return null;
5835
+ let element = document.elementFromPoint(point.x, point.y);
5836
+ while (element) {
5837
+ const id = nodes.get(element);
5838
+ if (!/* @__PURE__ */ isUndefined(id)) {
5839
+ const zone = _zones.get(id);
5840
+ if (zone && !toValue(zone.disabled)) return id;
5841
+ }
5842
+ element = element.parentElement;
5843
+ }
5844
+ return null;
5845
+ }
5846
+ function position(zoneId, drag) {
5847
+ const zone = _zones.get(zoneId);
5848
+ const out = { pointer: drag.current };
5849
+ if (zone?.orientation) {
5850
+ const resolved = zone.indicator?.value ?? null;
5851
+ if (resolved) {
5852
+ out.index = resolved.index;
5853
+ out.indicator = resolved;
5854
+ } else out.index = 0;
5855
+ }
5856
+ return out;
5857
+ }
5858
+ function bail(drag, reason = "cancel") {
5859
+ active.value = null;
5860
+ if (!/* @__PURE__ */ isNull(drag.over)) next(_zones.get(drag.over)?.onLeave, drag);
5861
+ next(_draggables.get(drag.id)?.onCancel, drag, reason);
5862
+ next(options.onCancel, drag, reason);
5863
+ }
5864
+ function onStart(source, origin, via) {
5865
+ if (toValue(_draggables.get(source.id)?.disabled)) return;
5866
+ const draft = {
5867
+ id: source.id,
5868
+ type: source.type,
5869
+ value: source.value,
5870
+ origin,
5871
+ current: origin,
5872
+ delta: {
5873
+ x: 0,
5874
+ y: 0
5875
+ },
5876
+ over: null,
5877
+ willAccept: false,
5878
+ via
5879
+ };
5880
+ try {
5881
+ if (_draggables.get(source.id)?.onBeforeStart?.(draft) === false) return;
5882
+ } catch (error) {
5883
+ logger.error("useDragDrop onBeforeStart threw; treating as veto", error);
5884
+ return;
5885
+ }
5886
+ try {
5887
+ if (options.onBeforeStart?.(draft) === false) return;
5888
+ } catch (error) {
5889
+ logger.error("useDragDrop onBeforeStart threw; treating as veto", error);
5890
+ return;
5891
+ }
5892
+ active.value = draft;
5893
+ }
5894
+ function onMove(point) {
5895
+ if (!active.value) return;
5896
+ const over = at(point);
5897
+ const draft = {
5898
+ ...active.value,
5899
+ current: point,
5900
+ delta: {
5901
+ x: point.x - active.value.origin.x,
5902
+ y: point.y - active.value.origin.y
5903
+ },
5904
+ over,
5905
+ willAccept: false
5906
+ };
5907
+ draft.willAccept = !/* @__PURE__ */ isNull(over) && safeAccept(_zones.get(over)?.accept, draft);
5908
+ const previous = active.value.over;
5909
+ active.value = draft;
5910
+ if (previous !== over) {
5911
+ if (!/* @__PURE__ */ isNull(previous)) next(_zones.get(previous)?.onLeave, draft);
5912
+ if (!/* @__PURE__ */ isNull(over)) next(_zones.get(over)?.onEnter, draft);
5913
+ }
5914
+ next(_draggables.get(draft.id)?.onMove, draft);
5915
+ next(options.onMove, draft);
5916
+ }
5917
+ function onDrop() {
5918
+ if (!active.value) return;
5919
+ const drag = active.value;
5920
+ const zoneId = drag.over;
5921
+ if (/* @__PURE__ */ isNull(zoneId)) {
5922
+ bail(drag);
5923
+ return;
5924
+ }
5925
+ const dropAt = position(zoneId, drag);
5926
+ const zone = _zones.get(zoneId);
5927
+ function vetoed(fn, label) {
5928
+ if (!fn) return false;
5929
+ try {
5930
+ return fn(drag, dropAt) === false;
5931
+ } catch (error) {
5932
+ logger.error(`useDragDrop ${label} threw; treating as veto`, error);
5933
+ return true;
5934
+ }
5935
+ }
5936
+ if (vetoed(zone?.onBeforeDrop, "zone onBeforeDrop") || vetoed(options.onBeforeDrop, "options onBeforeDrop")) {
5937
+ bail(drag, "reject");
5938
+ return;
5939
+ }
5940
+ active.value = null;
5941
+ next(zone?.onDrop, drag, dropAt);
5942
+ next(options.onDrop, drag, dropAt);
5943
+ }
5944
+ function cancel() {
5945
+ if (!active.value) return;
5946
+ bail(active.value);
5947
+ }
5948
+ const context = {
5949
+ draggables,
5950
+ zones,
5951
+ active: shallowReadonly(active),
5952
+ isDragging,
5953
+ cancel
5954
+ };
5955
+ const disposers = [];
5956
+ const adapters = options.adapters ?? [new PointerAdapter(), new KeyboardAdapter()];
5957
+ const emit = {
5958
+ start: (source, origin, via) => onStart(source, origin, via),
5959
+ move: (point) => onMove(point),
5960
+ drop: () => onDrop(),
5961
+ cancel: () => cancel()
5962
+ };
5963
+ const adapterContext = {
5964
+ ...context,
5965
+ emit
5966
+ };
5967
+ for (const adapter of adapters) try {
5968
+ adapter.setup(adapterContext);
5969
+ disposers.push(() => adapter.dispose());
5970
+ } catch (error) {
5971
+ logger.error("useDragDrop adapter setup threw; skipping adapter", error);
5972
+ try {
5973
+ adapter.dispose();
5974
+ } catch (disposeError) {
5975
+ logger.error("useDragDrop adapter dispose threw after setup failure", disposeError);
5976
+ }
5977
+ }
5978
+ for (const plugin of plugins) try {
5979
+ const dispose = plugin(context);
5980
+ if (/* @__PURE__ */ isFunction(dispose)) disposers.push(dispose);
5981
+ } catch (error) {
5982
+ logger.error("useDragDrop plugin install threw; skipping plugin", error);
5983
+ }
5984
+ _draggables.on("unregister:ticket", (ticket) => {
5985
+ if (active.value?.id === ticket.id) cancel();
5986
+ });
5987
+ _zones.on("unregister:ticket", (ticket) => {
5988
+ const scope = scopes.get(ticket.id);
5989
+ if (scope) {
5990
+ scope.stop();
5991
+ scopes.delete(ticket.id);
5992
+ }
5993
+ if (active.value?.over === ticket.id) {
5994
+ next(ticket.onLeave, active.value);
5995
+ active.value = {
5996
+ ...active.value,
5997
+ over: null,
5998
+ willAccept: false
5999
+ };
6000
+ }
6001
+ });
6002
+ onScopeDispose(() => {
6003
+ if (!/* @__PURE__ */ isNull(active.value)) cancel();
6004
+ for (const dispose of disposers.toReversed()) try {
6005
+ dispose();
6006
+ } catch (error) {
6007
+ logger.error("useDragDrop disposer threw", error);
6008
+ }
6009
+ for (const scope of scopes.values()) try {
6010
+ scope.stop();
6011
+ } catch (error) {
6012
+ logger.error("useDragDrop zone scope dispose threw", error);
6013
+ }
6014
+ scopes.clear();
6015
+ nodes.clear();
6016
+ try {
6017
+ _draggables.dispose();
6018
+ } catch (error) {
6019
+ logger.error("useDragDrop draggables dispose threw", error);
6020
+ }
6021
+ try {
6022
+ _zones.dispose();
6023
+ } catch (error) {
6024
+ logger.error("useDragDrop zones dispose threw", error);
6025
+ }
6026
+ }, true);
6027
+ return context;
6028
+ }
6029
+ //#endregion
6030
+ //#region src/composables/useHotkey/aliases.ts
6031
+ /**
6032
+ * Key alias mapping for consistent key normalization across the hotkey system.
6033
+ *
6034
+ * Maps user-friendly aliases to canonical key names that match
6035
+ * KeyboardEvent.key values (in lowercase) where possible.
6036
+ */
6037
+ const keyAliasMap = {
6038
+ control: "ctrl",
6039
+ command: "cmd",
6040
+ option: "alt",
6041
+ up: "arrowup",
4630
6042
  down: "arrowdown",
4631
6043
  left: "arrowleft",
4632
6044
  right: "arrowright",
@@ -4875,9 +6287,11 @@ function useHotkey(keys, callback, options = {}, _platform) {
4875
6287
  let isSequence = false;
4876
6288
  let groupIndex = 0;
4877
6289
  function isInputFocused() {
6290
+ /* v8 ignore next -- IN_BROWSER always true in happy-dom test env */
4878
6291
  if (!IN_BROWSER) return false;
4879
6292
  if (toValue(inputs)) return false;
4880
6293
  const activeElement = document.activeElement;
6294
+ /* v8 ignore next -- defensive: document.activeElement is always set in happy-dom */
4881
6295
  if (!activeElement) return false;
4882
6296
  const role = activeElement.getAttribute("role");
4883
6297
  if (role === "textbox" || role === "searchbox" || role === "combobox" || role === "spinbutton") return true;
@@ -4931,6 +6345,7 @@ function useHotkey(keys, callback, options = {}, _platform) {
4931
6345
  const currentKeys = toValue(keys);
4932
6346
  if (!currentKeys) return;
4933
6347
  const groups = splitKeySequence(currentKeys.toLowerCase());
6348
+ /* v8 ignore next -- defensive: splitKeySequence rejects empty strings earlier */
4934
6349
  if (groups.length === 0) return;
4935
6350
  isSequence = groups.length > 1;
4936
6351
  keyGroups = groups;
@@ -4983,6 +6398,7 @@ function isModifier(key) {
4983
6398
  function parseKeyGroup(group) {
4984
6399
  const { keys: parts } = splitKeyCombination(group.toLowerCase());
4985
6400
  const modifiers = Object.fromEntries(MODIFIERS.map((m) => [m, false]));
6401
+ /* v8 ignore next 3 -- defensive: parseKeyGroup is not invoked with empty parts */
4986
6402
  if (parts.length === 0) return {
4987
6403
  modifiers,
4988
6404
  actualKey: void 0
@@ -5208,11 +6624,13 @@ function useIntersectionObserver(target, callback, options = {}) {
5208
6624
  observe: (obs, el) => obs.observe(el),
5209
6625
  onEntry: (entries) => {
5210
6626
  const latest = entries.at(-1);
6627
+ /* v8 ignore next -- defensive: IntersectionObserver always emits at least one entry */
5211
6628
  if (latest) isIntersecting.value = latest.isIntersecting;
5212
6629
  },
5213
6630
  onPause: () => {
5214
6631
  isIntersecting.value = false;
5215
6632
  },
6633
+ /* v8 ignore next -- defensive nullish coalesce: entries always populated when shouldStop fires */
5216
6634
  shouldStop: (entries) => entries.at(-1)?.isIntersecting ?? false,
5217
6635
  immediate: options.immediate ? (el) => {
5218
6636
  return [{
@@ -5262,6 +6680,7 @@ function useElementIntersection(target, options = {}) {
5262
6680
  const intersectionRatio = shallowRef(0);
5263
6681
  const { pause: _pause, resume, stop, isActive, isPaused } = useIntersectionObserver(target, (entries) => {
5264
6682
  const entry = entries.at(-1);
6683
+ /* v8 ignore next 4 -- defensive: IntersectionObserver always emits at least one entry */
5265
6684
  if (entry) {
5266
6685
  isIntersecting.value = entry.isIntersecting;
5267
6686
  intersectionRatio.value = entry.intersectionRatio;
@@ -5511,131 +6930,6 @@ function usePrefersContrast() {
5511
6930
  return useMediaQuery("(prefers-contrast: more)");
5512
6931
  }
5513
6932
  //#endregion
5514
- //#region src/composables/useMutationObserver/index.ts
5515
- /**
5516
- * @module useMutationObserver
5517
- *
5518
- * @see https://0.vuetifyjs.com/composables/system/use-mutation-observer
5519
- *
5520
- * @remarks
5521
- * MutationObserver composable with lifecycle management.
5522
- *
5523
- * Key features:
5524
- * - MutationObserver API wrapper
5525
- * - `isActive` reactive flag
5526
- * - `once` option for single-fire observation
5527
- * - Pause/resume/stop functionality
5528
- * - Automatic cleanup on unmount
5529
- * - SSR-safe (checks SUPPORTS_MUTATION_OBSERVER)
5530
- * - Hydration-aware
5531
- * - Configurable observation options (childList, attributes, characterData, etc.)
5532
- *
5533
- * Perfect for detecting DOM changes and responding to mutations.
5534
- *
5535
- * @example
5536
- * ```ts
5537
- * import { useTemplateRef } from 'vue'
5538
- * import { useMutationObserver } from '@vuetify/v0'
5539
- *
5540
- * const target = useTemplateRef('target')
5541
- * useMutationObserver(target, records => {
5542
- * console.log(records)
5543
- * }, { childList: true })
5544
- * ```
5545
- */
5546
- /**
5547
- * A composable that uses the Mutation Observer API to detect changes in the DOM.
5548
- *
5549
- * @param target The element to observe.
5550
- * @param callback The callback to execute when a mutation is observed.
5551
- * @param options The options for the Mutation Observer.
5552
- * @returns An object with methods to control the observer.
5553
- *
5554
- * @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
5555
- * @see https://0.vuetifyjs.com/composables/system/use-mutation-observer
5556
- *
5557
- * @example
5558
- * ```ts
5559
- * import { ref } from 'vue'
5560
- * import { useMutationObserver } from '@vuetify/v0'
5561
- *
5562
- * const container = ref<HTMLElement>()
5563
- *
5564
- * const { pause, resume, isPaused } = useMutationObserver(
5565
- * container,
5566
- * (mutations) => {
5567
- * mutations.forEach((mutation) => {
5568
- * if (mutation.type === 'childList') {
5569
- * console.log('Children changed:', mutation.addedNodes, mutation.removedNodes)
5570
- * } else if (mutation.type === 'attributes') {
5571
- * console.log('Attribute changed:', mutation.attributeName)
5572
- * }
5573
- * })
5574
- * },
5575
- * {
5576
- * childList: true,
5577
- * attributes: true,
5578
- * subtree: true
5579
- * }
5580
- * )
5581
- *
5582
- * // Pause observation
5583
- * pause()
5584
- *
5585
- * // Resume observation
5586
- * resume()
5587
- * ```
5588
- */
5589
- function useMutationObserver(target, callback, options = {}) {
5590
- const observerOptions = {
5591
- childList: options.childList ?? true,
5592
- attributes: options.attributes ?? false,
5593
- characterData: options.characterData ?? false,
5594
- subtree: options.subtree ?? false,
5595
- attributeOldValue: options.attributeOldValue ?? false,
5596
- characterDataOldValue: options.characterDataOldValue ?? false,
5597
- attributeFilter: options.attributeFilter
5598
- };
5599
- return createObserver(target, callback, {
5600
- supports: SUPPORTS_MUTATION_OBSERVER,
5601
- once: options.once,
5602
- create: (cb) => new MutationObserver((mutations) => {
5603
- cb(mutations.map((m) => ({
5604
- type: m.type,
5605
- target: m.target,
5606
- addedNodes: m.addedNodes,
5607
- removedNodes: m.removedNodes,
5608
- previousSibling: m.previousSibling,
5609
- nextSibling: m.nextSibling,
5610
- attributeName: m.attributeName,
5611
- attributeNamespace: m.attributeNamespace,
5612
- oldValue: m.oldValue
5613
- })));
5614
- }),
5615
- observe: (obs, el) => obs.observe(el, observerOptions),
5616
- immediate: options.immediate ? (el) => {
5617
- const emptyNodeList = {
5618
- length: 0,
5619
- item: () => null,
5620
- forEach: () => {},
5621
- *[Symbol.iterator]() {}
5622
- };
5623
- return [{
5624
- type: "childList",
5625
- target: el,
5626
- addedNodes: emptyNodeList,
5627
- removedNodes: emptyNodeList,
5628
- previousSibling: null,
5629
- nextSibling: null,
5630
- attributeName: null,
5631
- attributeNamespace: null,
5632
- oldValue: null
5633
- }];
5634
- } : void 0,
5635
- onceIncludesImmediate: true
5636
- });
5637
- }
5638
- //#endregion
5639
6933
  //#region src/composables/usePresence/index.ts
5640
6934
  /**
5641
6935
  * @module usePresence
@@ -6019,8 +7313,11 @@ function useRovingFocus(items, options = {}) {
6019
7313
  };
6020
7314
  }
6021
7315
  //#endregion
7316
+ //#region src/composables/useRtl/adapters/adapter.ts
7317
+ var RtlAdapter = class {};
7318
+ //#endregion
6022
7319
  //#region src/composables/useRtl/adapters/v0.ts
6023
- var Vuetify0RtlAdapter = class {
7320
+ var V0RtlAdapter = class extends RtlAdapter {
6024
7321
  setup(app, context, target) {
6025
7322
  if (IN_BROWSER) {
6026
7323
  if (/* @__PURE__ */ isNull(target)) return;
@@ -6088,7 +7385,7 @@ function createRtlFallback() {
6088
7385
  }
6089
7386
  const [createRtlContext, createRtlPlugin, useRtl] = createPluginContext("v0:rtl", (options) => createRtl(options), {
6090
7387
  fallback: () => createRtlFallback(),
6091
- setup: (context, app, { adapter = new Vuetify0RtlAdapter(), target }) => {
7388
+ setup: (context, app, { adapter = new V0RtlAdapter(), target }) => {
6092
7389
  adapter.setup(app, context, target);
6093
7390
  },
6094
7391
  persist: (ctx) => ctx.isRtl.value,
@@ -6380,7 +7677,7 @@ function useStack(namespace = "v0:stack") {
6380
7677
  * ```
6381
7678
  */
6382
7679
  function createStorage(options = {}) {
6383
- const { adapter = IN_BROWSER ? window.localStorage : new MemoryAdapter(), prefix = "v0:", serializer = {
7680
+ const { adapter = IN_BROWSER ? window.localStorage : new MemoryStorageAdapter(), prefix = "v0:", serializer = {
6384
7681
  read: JSON.parse,
6385
7682
  write: JSON.stringify
6386
7683
  }, ttl } = options;
@@ -6395,9 +7692,9 @@ function createStorage(options = {}) {
6395
7692
  if (/* @__PURE__ */ isNullOrUndefined(raw)) return void 0;
6396
7693
  try {
6397
7694
  const parsed = serializer.read(raw);
6398
- if (ttl && /* @__PURE__ */ isObject(parsed) && "__v0" in parsed && "__v" in parsed) {
7695
+ if (/* @__PURE__ */ isObject(parsed) && "__v0" in parsed && "__v" in parsed) {
6399
7696
  const envelope = parsed;
6400
- if (Date.now() - envelope.__t > ttl) {
7697
+ if (ttl && Date.now() - envelope.__t > ttl) {
6401
7698
  adapter?.removeItem(prefixedKey);
6402
7699
  return;
6403
7700
  }
@@ -6477,7 +7774,7 @@ function createStorage(options = {}) {
6477
7774
  };
6478
7775
  }
6479
7776
  function createStorageFallback() {
6480
- return createStorage({ adapter: new MemoryAdapter() });
7777
+ return createStorage({ adapter: new MemoryStorageAdapter() });
6481
7778
  }
6482
7779
  const [createStorageContext, createStoragePlugin, useStorage] = createPluginContext("v0:storage", (options) => createStorage(options), { fallback: () => createStorageFallback() });
6483
7780
  //#endregion
@@ -6824,6 +8121,7 @@ function useClickOutside(target, handler, options = {}) {
6824
8121
  * Check if an element matches resolved ignore targets.
6825
8122
  */
6826
8123
  function isIgnored(el, selectors, elements) {
8124
+ /* v8 ignore next -- defensive guard, callers always pass an Element */
6827
8125
  if (!el) return false;
6828
8126
  for (const selector of selectors) try {
6829
8127
  if (el.matches(selector) || !/* @__PURE__ */ isNull(el.closest(selector))) return true;
@@ -6850,6 +8148,7 @@ function useClickOutside(target, handler, options = {}) {
6850
8148
  const targets = getTargets();
6851
8149
  if (targets.length === 0) return false;
6852
8150
  return targets.every((el) => {
8151
+ /* v8 ignore next -- defensive: getTargets filters to Element-typed values */
6853
8152
  if (/* @__PURE__ */ isNullOrUndefined(el) || !/* @__PURE__ */ isFunction(el.contains)) return false;
6854
8153
  return el !== eventTarget && !el.contains(eventTarget);
6855
8154
  });
@@ -6859,6 +8158,7 @@ function useClickOutside(target, handler, options = {}) {
6859
8158
  */
6860
8159
  function isOutsideBounds(x, y) {
6861
8160
  const targets = getTargets();
8161
+ /* v8 ignore next -- edge case: bounds check only invoked when targets exist */
6862
8162
  if (targets.length === 0) return false;
6863
8163
  return targets.every((el) => {
6864
8164
  const { left, right, top, bottom } = el.getBoundingClientRect();
@@ -6869,6 +8169,7 @@ function useClickOutside(target, handler, options = {}) {
6869
8169
  * Validate that the target is still in the DOM.
6870
8170
  */
6871
8171
  function isValidTarget(eventTarget) {
8172
+ /* v8 ignore next -- type guard for non-Element targets (e.g., document, window) */
6872
8173
  if (!/* @__PURE__ */ isElement(eventTarget)) return false;
6873
8174
  if (!eventTarget.isConnected) return false;
6874
8175
  return true;
@@ -6961,4 +8262,4 @@ function useClickOutside(target, handler, options = {}) {
6961
8262
  };
6962
8263
  }
6963
8264
  //#endregion
6964
- export { createSlider as $, useElementIntersection as A, ServerAdapter as At, createBreakpointsContext as B, usePresence as C, createValidation as Ct, usePrefersDark as D, createCombobox as Dt, usePrefersContrast as E, useForm as Et, createDate as F, createBreadcrumbsContext as Ft, createVirtualContext as G, useBreakpoints as H, createDateContext as I, useBreadcrumbs as It, createTimelineContext as J, useVirtual as K, createDatePlugin as L, useImage as M, useVirtualFocus as Mt, useHotkey as N, usePopover as Nt, usePrefersReducedMotion as O, createComboboxContext as Ot, useDelay as P, createBreadcrumbs as Pt, useStep as Q, useDate as R, useProxyModel as S, createInput as St, useMediaQuery as T, createFormContext as Tt, toReactive as U, createBreakpointsPlugin as V, createVirtual as W, createStep as X, useTimeline as Y, createStepContext as Z, createRtlPlugin as _, createNumberField as _t, useToggleScope as a, useProgress as at, useRovingFocus as b, createNestedContext as bt, createStoragePlugin as c, useOverflow as ct, createStackContext as d, toElement as dt, createRating as et, createStackPlugin as f, createFallbackHydration as ft, createRtlFallback as g, useHydration as gt, createRtlContext as h, createHydrationPlugin as ht, useWindowEventListener as i, createProgressContext as it, useIntersectionObserver as j, ClientAdapter as jt, useLazy as k, useCombobox as kt, useStorage as l, useElementSize as lt, createRtl as m, createHydrationContext as mt, useDocumentEventListener as n, useRating as nt, createStorage as o, createOverflow as ot, useStack as p, createHydration as pt, createTimeline as q, useEventListener as r, createProgress as rt, createStorageContext as s, createOverflowContext as st, useClickOutside as t, createRatingContext as tt, createStack as u, useResizeObserver as ut, useRtl as v, createNumeric as vt, useMutationObserver as w, createForm as wt, useRaf as x, useNested as xt, Vuetify0RtlAdapter as y, createNested as yt, createBreakpoints as z };
8265
+ export { createTimelineContext as $, useIntersectionObserver as A, createInput as At, createDateContext as B, ComboboxAdapter as Bt, usePresence as C, createNumberField as Ct, usePrefersReducedMotion as D, useNested as Dt, usePrefersDark as E, createNestedContext as Et, PointerAdapter as F, createCombobox as Ft, createBreakpointsPlugin as G, useBreadcrumbs as Gt, useDate as H, usePopover as Ht, DragDropAdapter as I, createComboboxContext as It, toHighlight as J, useBreakpoints as K, useMutationObserver as L, useCombobox as Lt, useHotkey as M, createForm as Mt, useDragDrop as N, createFormContext as Nt, useLazy as O, createKanban as Ot, KeyboardAdapter as P, useForm as Pt, createTimeline as Q, useDelay as R, ServerComboboxAdapter as Rt, useProxyModel as S, createOtp as St, usePrefersContrast as T, createNested as Tt, createBreakpoints as U, createBreadcrumbs as Ut, createDatePlugin as V, useVirtualFocus as Vt, createBreakpointsContext as W, createBreadcrumbsContext as Wt, createVirtualContext as X, createVirtual as Y, useVirtual as Z, createRtlPlugin as _, createFallbackHydration as _t, useToggleScope as a, createRating as at, useRovingFocus as b, createHydrationPlugin as bt, createStoragePlugin as c, createProgress as ct, createStackContext as d, createOverflow as dt, useTimeline as et, createStackPlugin as f, createOverflowContext as ft, createRtlFallback as g, toElement as gt, createRtlContext as h, useResizeObserver as ht, useWindowEventListener as i, createSlider as it, useImage as j, createValidation as jt, useElementIntersection as k, createSortable as kt, useStorage as l, createProgressContext as lt, createRtl as m, useElementSize as mt, useDocumentEventListener as n, createStepContext as nt, createStorage as o, createRatingContext as ot, useStack as p, useOverflow as pt, toReactive as q, useEventListener as r, useStep as rt, createStorageContext as s, useRating as st, useClickOutside as t, createStep as tt, createStack as u, useProgress as ut, useRtl as v, createHydration as vt, useMediaQuery as w, createNumeric as wt, useRaf as x, useHydration as xt, V0RtlAdapter as y, createHydrationContext as yt, createDate as z, ClientComboboxAdapter as zt };