@vuetify/v0 1.1.0 → 1.2.1

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 (162) hide show
  1. package/README.md +13 -0
  2. package/dist/{adapter-Butx_2UU.d.mts → adapter-BXunW_mw.d.mts} +1 -1
  3. package/dist/{createPagination-B5dfqY-a.mjs → adapter-BiQV5j8B.mjs} +98 -3
  4. package/dist/adapter-ClB-53_F.d.mts +62 -0
  5. package/dist/adapter-CrRJuxRk.mjs +21 -0
  6. package/dist/{adapter-hq9YlPOF.d.mts → adapter-FckJSz_o.d.mts} +2 -2
  7. package/dist/{adapter-_srNCBEi.d.mts → adapter-PDTe5nFT.d.mts} +6 -7
  8. package/dist/browser/index.d.ts +15918 -13714
  9. package/dist/browser/index.js +16708 -14105
  10. package/dist/components/index.d.mts +2 -2
  11. package/dist/components/index.mjs +2 -2
  12. package/dist/{components-B2BZ1B3K.mjs → components-MCFhfNlt.mjs} +8234 -6307
  13. package/dist/composables/index.d.mts +22 -20
  14. package/dist/composables/index.mjs +37 -34
  15. package/dist/{composables-DONBl_c9.mjs → composables-8xtFVviy.mjs} +32 -1061
  16. package/dist/{consola-BPGkJp_q.d.mts → consola-CdMU53rU.d.mts} +1 -1
  17. package/dist/constants/index.d.mts +1 -1
  18. package/dist/constants/index.mjs +1 -1
  19. package/dist/{createDataTable-DgyHBfAr.mjs → createDataTable-OCGnpy-N.mjs} +24 -8
  20. package/dist/{createGroup-BXKKcb9-.mjs → createGroup-DtVYu-VY.mjs} +14 -3
  21. package/dist/createPlugin-Oo6t-vBw.mjs +157 -0
  22. package/dist/{createRegistry-B9cOWny2.mjs → createRegistry-DSQiALGi.mjs} +3 -3
  23. package/dist/{createSelection-CWE554_g.mjs → createSelection-TB5oK1FG.mjs} +2 -1
  24. package/dist/{createSingle-Dz-1Iv7u.mjs → createSingle-CV1qigP2.mjs} +1 -1
  25. package/dist/{createTokens-C4qcW2Kv.mjs → createTokens-B0CqJEL6.mjs} +2 -2
  26. package/dist/data-table/adapters/client/index.d.mts +1 -1
  27. package/dist/data-table/adapters/client/index.mjs +1 -1
  28. package/dist/data-table/adapters/index.d.mts +4 -4
  29. package/dist/data-table/adapters/index.mjs +4 -4
  30. package/dist/data-table/adapters/server/index.d.mts +1 -1
  31. package/dist/data-table/adapters/server/index.mjs +1 -1
  32. package/dist/data-table/adapters/virtual/index.d.mts +1 -1
  33. package/dist/data-table/adapters/virtual/index.mjs +1 -1
  34. package/dist/data-table/index.d.mts +5 -5
  35. package/dist/data-table/index.mjs +5 -5
  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 +1 -1
  39. package/dist/features/adapters/flagsmith/index.mjs +1 -1
  40. package/dist/features/adapters/launchdarkly/index.d.mts +1 -1
  41. package/dist/features/adapters/launchdarkly/index.mjs +1 -1
  42. package/dist/features/adapters/posthog/index.d.mts +1 -1
  43. package/dist/features/adapters/posthog/index.mjs +2 -2
  44. package/dist/features/index.d.mts +2 -2
  45. package/dist/features/index.mjs +2 -2
  46. package/dist/{flagsmith-DA2GCyGv.d.mts → flagsmith-DcIDrI7_.d.mts} +1 -1
  47. package/dist/{globals-CtaXlEOI.mjs → globals-wvVdMRFF.mjs} +1 -1
  48. package/dist/{index-DCtHbY0a.d.mts → index-3bThcqCN.d.mts} +25 -20
  49. package/dist/{index-QnpcDsV7.d.mts → index-3vvA76pZ.d.mts} +2 -2
  50. package/dist/{index-RGiSdjYt.d.mts → index-4Z38WhA9.d.mts} +9 -3
  51. package/dist/{index-CTl0cGH6.d.mts → index-BTdCsSz0.d.mts} +7264 -5608
  52. package/dist/{index-DF0tMI2_.d.mts → index-CORslci7.d.mts} +121 -2
  53. package/dist/{index-Dc7lKT6q.d.mts → index-Dgkt7Ve9.d.mts} +494 -131
  54. package/dist/index.d.mts +25 -24
  55. package/dist/index.mjs +40 -37
  56. package/dist/json/attributes.json +500 -0
  57. package/dist/json/importMap.json +92 -0
  58. package/dist/json/tags.json +237 -0
  59. package/dist/json/web-types.json +1553 -97
  60. package/dist/{launchdarkly-Bp8p9PMD.d.mts → launchdarkly-CUzunYol.d.mts} +1 -1
  61. package/dist/locale/adapters/index.d.mts +2 -2
  62. package/dist/locale/adapters/index.mjs +2 -2
  63. package/dist/locale/adapters/v0/index.d.mts +1 -1
  64. package/dist/locale/adapters/v0/index.mjs +1 -1
  65. package/dist/locale/adapters/vue-i18n/index.d.mts +1 -1
  66. package/dist/locale/adapters/vue-i18n/index.mjs +1 -1
  67. package/dist/locale/index.d.mts +3 -3
  68. package/dist/locale/index.mjs +3 -3
  69. package/dist/locale/messages/en/index.d.mts +6 -0
  70. package/dist/locale/messages/en/index.mjs +2 -0
  71. package/dist/logger/adapters/consola/index.d.mts +1 -1
  72. package/dist/logger/adapters/index.d.mts +4 -4
  73. package/dist/logger/adapters/index.mjs +1 -1
  74. package/dist/logger/adapters/pino/index.d.mts +1 -1
  75. package/dist/logger/adapters/v0/index.d.mts +1 -1
  76. package/dist/logger/adapters/v0/index.mjs +1 -1
  77. package/dist/logger/index.d.mts +5 -5
  78. package/dist/logger/index.mjs +2 -2
  79. package/dist/notifications/index.d.mts +1 -1
  80. package/dist/notifications/index.mjs +2 -2
  81. package/dist/palettes/ant/index.d.mts +1 -1
  82. package/dist/palettes/index.d.mts +3 -3
  83. package/dist/palettes/material/index.d.mts +1 -1
  84. package/dist/palettes/md1/index.d.mts +1 -1
  85. package/dist/palettes/md2/index.d.mts +1 -1
  86. package/dist/palettes/radix/index.d.mts +1 -1
  87. package/dist/palettes/tailwind/index.d.mts +1 -1
  88. package/dist/permissions/adapters/index.d.mts +1 -1
  89. package/dist/permissions/adapters/index.mjs +1 -1
  90. package/dist/permissions/adapters/v0/index.d.mts +1 -1
  91. package/dist/permissions/adapters/v0/index.mjs +1 -1
  92. package/dist/permissions/index.d.mts +1 -1
  93. package/dist/permissions/index.mjs +2 -2
  94. package/dist/{pino-B6BI1AOK.d.mts → pino-DjeWBFnj.d.mts} +1 -1
  95. package/dist/popover/adapters/floating-ui/index.d.mts +25 -0
  96. package/dist/popover/adapters/floating-ui/index.mjs +98 -0
  97. package/dist/popover/index.d.mts +3 -0
  98. package/dist/popover/index.mjs +3 -0
  99. package/dist/{posthog-sFqk0bGy.d.mts → posthog-CJAYssdr.d.mts} +1 -1
  100. package/dist/rules/index.d.mts +1 -1
  101. package/dist/rules/index.mjs +1 -1
  102. package/dist/{server-DbtTGb67.d.mts → server-5vbJ7GGs.d.mts} +2 -2
  103. package/dist/{server-D5BJBjB0.mjs → server-m7iD1vOr.mjs} +1 -2
  104. package/dist/storage/adapters/index.d.mts +2 -2
  105. package/dist/storage/adapters/index.mjs +1 -1
  106. package/dist/storage/adapters/memory/index.d.mts +1 -1
  107. package/dist/storage/adapters/memory/index.mjs +1 -1
  108. package/dist/storage/index.d.mts +3 -3
  109. package/dist/storage/index.mjs +2 -2
  110. package/dist/theme/adapters/index.d.mts +1 -1
  111. package/dist/theme/adapters/index.mjs +3 -3
  112. package/dist/theme/adapters/unhead/index.d.mts +1 -1
  113. package/dist/theme/adapters/unhead/index.mjs +1 -1
  114. package/dist/theme/adapters/v0/index.d.mts +1 -1
  115. package/dist/theme/adapters/v0/index.mjs +1 -1
  116. package/dist/theme/index.d.mts +2 -2
  117. package/dist/theme/index.mjs +4 -4
  118. package/dist/types/index.d.mts +1 -1
  119. package/dist/{unhead-BAWCwNOF.mjs → unhead-SyU953Pt.mjs} +2 -2
  120. package/dist/{useEventListener-DSOeDtC-.mjs → useEventListener-hF6R2p6X.mjs} +2 -2
  121. package/dist/useFeatures-CTpkM6hV.mjs +221 -0
  122. package/dist/{useLocale-D-V0DENN.mjs → useLocale-D-iWu08b.mjs} +4 -4
  123. package/dist/{useLogger-CbvzXCWb.mjs → useLogger-CDsgHbzO.mjs} +5 -159
  124. package/dist/{useNotifications-Cqg3uDz0.mjs → useNotifications-DhNjvRt1.mjs} +57 -154
  125. package/dist/{usePermissions-BTdUVyQe.mjs → usePermissions-CKe8xcvz.mjs} +4 -4
  126. package/dist/usePopover-DyAdne_S.mjs +421 -0
  127. package/dist/{useRovingFocus-g6ifibLg.mjs → useRovingFocus-D0OOozbe.mjs} +1169 -553
  128. package/dist/{useRules-DEiHd_eY.mjs → useRules-DA8bNhNq.mjs} +3 -2
  129. package/dist/{useStorage-BSfQfDbg.mjs → useStorage-D9c6xx4N.mjs} +5 -4
  130. package/dist/useTheme-BrXA5VBp.mjs +445 -0
  131. package/dist/useTimer-DLtkRCHw.mjs +151 -0
  132. package/dist/utilities/index.d.mts +2 -2
  133. package/dist/utilities/index.mjs +204 -2
  134. package/dist/{v0-BnUwMaOv.d.mts → v0-C09lR5fc.d.mts} +1 -1
  135. package/dist/{v0-CveVV6On.mjs → v0-CaTmC7C4.mjs} +2 -2
  136. package/dist/{v0-rSxMW8FJ.d.mts → v0-DfFK-p4X.d.mts} +1 -1
  137. package/dist/{v0-CCWHeKJM.mjs → v0-DpFVF6pD.mjs} +1 -1
  138. package/dist/{v0-DotXXGXU.d.mts → v0-GI9U-rPA.d.mts} +2 -2
  139. package/dist/{v0-CZBkpQjr.mjs → v0-cC-WxCLd.mjs} +2 -2
  140. package/dist/{v0-A4GLojAr.mjs → v0-yZ2ZUtVF.mjs} +1 -2
  141. package/dist/{virtual-DFvOoeG6.mjs → virtual-Bbu26O_h.mjs} +1 -2
  142. package/dist/{virtual-C-NsLue0.d.mts → virtual-JIdFLpTQ.d.mts} +2 -2
  143. package/package.json +8 -1
  144. package/dist/adapter-CVoWg0sw.mjs +0 -99
  145. package/dist/useFeatures-YJmONiU7.mjs +0 -124
  146. package/dist/useTheme-C0_i__N6.mjs +0 -162
  147. /package/dist/{adapter-CTsckKAR.mjs → adapter-8UADsA3-.mjs} +0 -0
  148. /package/dist/{adapter-BCtceV3b.mjs → adapter-BuSfpxur.mjs} +0 -0
  149. /package/dist/{adapter-Bc0yPSfo.d.mts → adapter-D5nT3bLw.d.mts} +0 -0
  150. /package/dist/{adapter-bwZo7b5p.mjs → adapter-D8zizQVP.mjs} +0 -0
  151. /package/dist/{adapter-q1sRACUc.mjs → adapter-TiGrumDi.mjs} +0 -0
  152. /package/dist/{adapter-BYzU4Ey5.d.mts → adapter-ryk5H6YZ.d.mts} +0 -0
  153. /package/dist/{index-CROz1VSV.d.mts → index-CX869wwk.d.mts} +0 -0
  154. /package/dist/{index-FtE8MXJ_.d.mts → index-CsuikFeJ.d.mts} +0 -0
  155. /package/dist/{index-DidZKN6S.d.mts → index-Djhiy3nS.d.mts} +0 -0
  156. /package/dist/{index-CyNk9FpR.d.mts → index-DtiaWx5U.d.mts} +0 -0
  157. /package/dist/{index-DXMlYoiQ.d.mts → index-H_hl6-4b.d.mts} +0 -0
  158. /package/dist/{index-BgCkepP_.d.mts → index-u_qSc2xS.d.mts} +0 -0
  159. /package/dist/{memory-DbyZeNjg.d.mts → memory-B7z1RR9r.d.mts} +0 -0
  160. /package/dist/{memory-BJjkQzxs.mjs → memory-CR6zvuaP.mjs} +0 -0
  161. /package/dist/{toArray-C89ZaEuF.mjs → toArray-MY9Kb1Qy.mjs} +0 -0
  162. /package/dist/{v0-UNyykD27.mjs → v0-Ch0yBKEj.mjs} +0 -0
@@ -1,16 +1,21 @@
1
- import { a as SUPPORTS_OBSERVER, n as SUPPORTS_INTERSECTION_OBSERVER, t as IN_BROWSER } from "./globals-CtaXlEOI.mjs";
2
- import { clamp, instanceExists, isArray, isElement, isFunction, isNaN, isNull, isNullOrUndefined, isObject, isString, isUndefined, range, resolveIds, resolveIndexes, useId as useId$1 } from "./utilities/index.mjs";
3
- import { i as useContext, t as createTrinity } from "./createTrinity-z-3q9QWR.mjs";
4
- import { a as createPlugin, i as useLogger, o as createPluginContext } from "./useLogger-CbvzXCWb.mjs";
5
- import { t as createRegistry } from "./createRegistry-B9cOWny2.mjs";
6
- import { i as createModel, t as createSelection } from "./createSelection-CWE554_g.mjs";
7
- import { t as createSingle } from "./createSingle-Dz-1Iv7u.mjs";
8
- import { t as toArray } from "./toArray-C89ZaEuF.mjs";
9
- import { n as useEventListener, r as useWindowEventListener, t as useDocumentEventListener } from "./useEventListener-DSOeDtC-.mjs";
10
- import { t as createGroup } from "./createGroup-BXKKcb9-.mjs";
11
- import { c as useTimer } from "./useNotifications-Cqg3uDz0.mjs";
12
- import { i as createFilter } from "./createPagination-B5dfqY-a.mjs";
13
- import { a as useRules, o as isStandardSchema } from "./useRules-DEiHd_eY.mjs";
1
+ import { a as SUPPORTS_OBSERVER, n as SUPPORTS_INTERSECTION_OBSERVER, t as IN_BROWSER } from "./globals-wvVdMRFF.mjs";
2
+ import { clamp, getActiveElement, instanceExists, isArray, isElement, isFunction, isNaN, isNull, isNullOrUndefined, isObject, isString, isUndefined, pxToNumber, range, resolveIds, resolveIndexes, useId as useId$1 } from "./utilities/index.mjs";
3
+ import { i as useContext, n as createContext, t as createTrinity } from "./createTrinity-z-3q9QWR.mjs";
4
+ import { n as createPluginContext, t as createPlugin } from "./createPlugin-Oo6t-vBw.mjs";
5
+ import { i as useLogger } from "./useLogger-CDsgHbzO.mjs";
6
+ import { t as createRegistry } from "./createRegistry-DSQiALGi.mjs";
7
+ import { i as createModel, t as createSelection } from "./createSelection-TB5oK1FG.mjs";
8
+ import { t as createSingle } from "./createSingle-CV1qigP2.mjs";
9
+ import { a as useLocale } from "./useLocale-D-iWu08b.mjs";
10
+ import { t as toArray } from "./toArray-MY9Kb1Qy.mjs";
11
+ import { n as useEventListener, r as useWindowEventListener, t as useDocumentEventListener } from "./useEventListener-hF6R2p6X.mjs";
12
+ import { p as useHydration } from "./useTheme-BrXA5VBp.mjs";
13
+ import { i as useProxyRegistry, t as createGroup } from "./createGroup-DtVYu-VY.mjs";
14
+ import { t as useTimer } from "./useTimer-DLtkRCHw.mjs";
15
+ import { i as usePopover } from "./usePopover-DyAdne_S.mjs";
16
+ import { a as createFilter } from "./adapter-BiQV5j8B.mjs";
17
+ import { a as extractLeaves, t as createDataTable } from "./createDataTable-OCGnpy-N.mjs";
18
+ import { a as useRules, o as isStandardSchema } from "./useRules-DA8bNhNq.mjs";
14
19
  import { computed, effectScope, hasInjectionContext, isReadonly, isRef, nextTick, onScopeDispose, ref, shallowReactive, shallowReadonly, shallowRef, toRef, toValue, watch } from "vue";
15
20
  //#region src/composables/useClickOutside/index.ts
16
21
  /**
@@ -254,7 +259,7 @@ function useClickOutside(target, handler, options = {}) {
254
259
  if (isPaused.value) return;
255
260
  if (event.defaultPrevented) return;
256
261
  if (document.activeElement instanceof HTMLIFrameElement) {
257
- const iframeIsOutside = getTargets().every((el) => !el.contains(document.activeElement));
262
+ const iframeIsOutside = getTargets().every((el) => !el.contains(/* @__PURE__ */ getActiveElement()));
258
263
  const [selectors, elements] = resolveIgnoreTargets();
259
264
  if (iframeIsOutside && !isIgnored(document.activeElement, selectors, elements)) handler(event);
260
265
  }
@@ -409,7 +414,7 @@ function toElement(target) {
409
414
  * ```
410
415
  */
411
416
  function createStack(_options = {}) {
412
- const { baseZIndex = 2e3, increment = 10, ...options } = _options;
417
+ const { baseZIndex = 2e3, increment = 10, default: defaultTeleport, ...options } = _options;
413
418
  const selection = createSelection({
414
419
  ...options,
415
420
  multiple: true
@@ -470,6 +475,7 @@ function createStack(_options = {}) {
470
475
  }, true);
471
476
  return ticket;
472
477
  }
478
+ const defaultRef = toRef(() => defaultTeleport);
473
479
  return {
474
480
  ...selection,
475
481
  register,
@@ -478,6 +484,7 @@ function createStack(_options = {}) {
478
484
  scrimZIndex,
479
485
  isBlocking,
480
486
  topElement,
487
+ default: defaultRef,
481
488
  get size() {
482
489
  return selection.size;
483
490
  }
@@ -708,109 +715,6 @@ function useToggleScope(source, fn) {
708
715
  return controls;
709
716
  }
710
717
  //#endregion
711
- //#region src/composables/useHydration/index.ts
712
- /**
713
- * @module useHydration
714
- *
715
- * @see https://0.vuetifyjs.com/composables/plugins/use-hydration
716
- *
717
- * @remarks
718
- * SSR hydration state management composable.
719
- *
720
- * Key features:
721
- * - Hydration state detection (browser vs SSR)
722
- * - Root component detection
723
- * - Readonly hydration state refs
724
- * - Plugin installation support
725
- * - Perfect for hydration-safe rendering
726
- *
727
- * Essential for composables that need to behave differently during SSR vs client-side.
728
- *
729
- * @example
730
- * ```ts
731
- * import { useHydration } from '@vuetify/v0'
732
- *
733
- * const { isHydrated } = useHydration()
734
- * if (isHydrated.value) {
735
- * // safe for client-only logic
736
- * }
737
- * ```
738
- */
739
- /**
740
- * Creates a new hydration instance.
741
- *
742
- * @returns A new hydration instance.
743
- *
744
- * @see https://0.vuetifyjs.com/composables/plugins/use-hydration
745
- *
746
- * @example
747
- * ```ts
748
- * import { createHydration } from '@vuetify/v0'
749
- *
750
- * const hydration = createHydration()
751
- * console.log(hydration.isHydrated.value) // false
752
- * hydration.hydrate()
753
- * console.log(hydration.isHydrated.value) // true
754
- * ```
755
- */
756
- function createHydration() {
757
- const isHydrated = shallowRef(false);
758
- const isSettled = shallowRef(false);
759
- function hydrate() {
760
- isHydrated.value = true;
761
- }
762
- function settle() {
763
- isSettled.value = true;
764
- }
765
- return {
766
- isHydrated: shallowReadonly(isHydrated),
767
- isSettled: shallowReadonly(isSettled),
768
- hydrate,
769
- settle
770
- };
771
- }
772
- function createFallbackHydration() {
773
- return {
774
- isHydrated: shallowReadonly(shallowRef(true)),
775
- isSettled: shallowReadonly(shallowRef(true)),
776
- hydrate: () => {},
777
- settle: () => {}
778
- };
779
- }
780
- /**
781
- * Creates a new hydration context trinity.
782
- *
783
- * @param options Options for creating the hydration context.
784
- * @template E The type of the hydration context.
785
- * @returns A new hydration context trinity.
786
- *
787
- * @see https://0.vuetifyjs.com/composables/plugins/use-hydration
788
- *
789
- * @example
790
- * ```ts
791
- * import { createHydrationContext } from '@vuetify/v0'
792
- *
793
- * export const [useHydrationContext, provideHydrationContext, context] = createHydrationContext({
794
- * namespace: 'app:hydration',
795
- * })
796
- * ```
797
- */
798
- const [createHydrationContext, createHydrationPlugin, useHydration] = createPluginContext("v0:hydration", () => createHydration(), {
799
- fallback: () => createFallbackHydration(),
800
- setup: (context, app) => {
801
- const { mount } = app;
802
- app.mount = (...args) => {
803
- const vm = mount(...args);
804
- nextTick().then(() => {
805
- context.hydrate();
806
- nextTick().then(() => context.settle());
807
- });
808
- app.mount = mount;
809
- return vm;
810
- };
811
- }
812
- });
813
- //#endregion
814
718
  //#region src/composables/createObserver/index.ts
815
719
  /**
816
720
  * @module createObserver
@@ -942,12 +846,6 @@ function createObserver(target, userCallback, config) {
942
846
  * })
943
847
  * ```
944
848
  */
945
- /* @__NO_SIDE_EFFECTS__ */
946
- function pxToNumber(value, fallback = 0) {
947
- if (!/* @__PURE__ */ isString(value)) return fallback;
948
- const parsed = Number.parseFloat(value);
949
- return /* @__PURE__ */ isNaN(parsed) ? fallback : parsed;
950
- }
951
849
  /**
952
850
  * Synthesize the entry the observer would report for `el`, for the `immediate`
953
851
  * callback that fires before the observer's own first delivery.
@@ -1235,7 +1133,7 @@ function createOverflow(options = {}) {
1235
1133
  /* v8 ignore start -- browser-only measurement code */
1236
1134
  if (!IN_BROWSER) return;
1237
1135
  const style = getComputedStyle(el);
1238
- const marginX = (Number.parseFloat(style.marginLeft) || 0) + (Number.parseFloat(style.marginRight) || 0);
1136
+ const marginX = /* @__PURE__ */ pxToNumber(style.marginLeft) + /* @__PURE__ */ pxToNumber(style.marginRight);
1239
1137
  const w = (el.offsetWidth || 0) + marginX;
1240
1138
  if (widths.value.get(index) !== w) widths.value = new Map(widths.value).set(index, w);
1241
1139
  /* v8 ignore stop */
@@ -1855,6 +1753,7 @@ function createStep(_options = {}) {
1855
1753
  function step(count = 1) {
1856
1754
  const length = registry.size;
1857
1755
  if (!length) return;
1756
+ registry.lookup(0);
1858
1757
  const currentIndex = registry.selectedIndex.value;
1859
1758
  const direction = Math.sign(count || 1);
1860
1759
  let hops = 0;
@@ -1944,238 +1843,6 @@ function useStep(namespace = "v0:step") {
1944
1843
  return useContext(namespace);
1945
1844
  }
1946
1845
  //#endregion
1947
- //#region src/composables/useDelay/index.ts
1948
- /**
1949
- * @module useDelay
1950
- *
1951
- * @see https://0.vuetifyjs.com/composables/system/use-delay
1952
- *
1953
- * @remarks
1954
- * Schedule open and close transitions with configurable delays.
1955
- *
1956
- * Composes `useTimer` for the underlying lifecycle (start / stop / pause / resume,
1957
- * plus reactive `isActive`, `isPaused`, `remaining`) and adds direction tracking
1958
- * (`isOpening`) and promise-based resolution.
1959
- *
1960
- * Key features:
1961
- * - Reactive `openDelay` and `closeDelay` via `MaybeRefOrGetter`
1962
- * - `start(isOpening)` returns a `Promise<boolean>` that resolves once the delay elapses
1963
- * - Per-call `minDelay` floor enforces a minimum delay
1964
- * - Automatic cleanup on scope disposal (timer cleared, pending promise settled with current direction)
1965
- * - SSR-safe
1966
- *
1967
- * @example
1968
- * ```ts
1969
- * import { useDelay } from '@vuetify/v0'
1970
- *
1971
- * const delay = useDelay(isOpening => isVisible.value = isOpening, {
1972
- * openDelay: 300,
1973
- * closeDelay: 200,
1974
- * })
1975
- *
1976
- * delay.start(true)
1977
- * delay.start(false, { minDelay: 500 })
1978
- * ```
1979
- */
1980
- /**
1981
- * Schedule open and close transitions with configurable delays.
1982
- *
1983
- * Composes `useTimer` for the lifecycle (`start` / `stop` / `pause` / `resume` plus
1984
- * reactive `isActive`, `isPaused`, `remaining`) and adds direction tracking
1985
- * (`isOpening`) and promise-based resolution.
1986
- *
1987
- * @param callback Optional callback invoked once a started delay elapses; receives the resolved direction.
1988
- * @param options Reactive delay settings.
1989
- * @returns Lifecycle controls and reactive state.
1990
- *
1991
- * @see https://0.vuetifyjs.com/composables/system/use-delay
1992
- *
1993
- * @example
1994
- * ```ts
1995
- * const delay = useDelay(isOpening => isVisible.value = isOpening, {
1996
- * openDelay: 300,
1997
- * closeDelay: 200,
1998
- * })
1999
- *
2000
- * delay.start(true)
2001
- * delay.start(false, { minDelay: 500 })
2002
- * delay.pause()
2003
- * delay.resume()
2004
- * delay.stop()
2005
- * ```
2006
- */
2007
- function useDelay(callback, options = {}) {
2008
- const { openDelay, closeDelay } = options;
2009
- const isOpening = shallowRef(false);
2010
- let minDelay = 0;
2011
- let resolver;
2012
- function fire() {
2013
- const direction = isOpening.value;
2014
- const resolve = resolver;
2015
- resolver = void 0;
2016
- resolve?.(direction);
2017
- callback?.(direction);
2018
- }
2019
- function duration() {
2020
- const raw = isOpening.value ? toValue(openDelay) : toValue(closeDelay);
2021
- return Math.max(minDelay, raw ?? 0);
2022
- }
2023
- const timer = useTimer(fire, { duration });
2024
- function start(direction, options = {}) {
2025
- const previous = resolver;
2026
- resolver = void 0;
2027
- isOpening.value = direction;
2028
- minDelay = options.minDelay ?? 0;
2029
- previous?.(direction);
2030
- const ms = duration();
2031
- return new Promise((resolve) => {
2032
- resolver = resolve;
2033
- if (ms <= 0) {
2034
- timer.stop();
2035
- fire();
2036
- return;
2037
- }
2038
- timer.start();
2039
- });
2040
- }
2041
- function stop() {
2042
- const resolve = resolver;
2043
- resolver = void 0;
2044
- timer.stop();
2045
- resolve?.(isOpening.value);
2046
- }
2047
- onScopeDispose(() => {
2048
- const resolve = resolver;
2049
- resolver = void 0;
2050
- resolve?.(isOpening.value);
2051
- }, true);
2052
- return {
2053
- start,
2054
- stop,
2055
- pause: timer.pause,
2056
- resume: timer.resume,
2057
- isActive: shallowReadonly(timer.isActive),
2058
- isPaused: shallowReadonly(timer.isPaused),
2059
- remaining: shallowReadonly(timer.remaining),
2060
- isOpening: shallowReadonly(isOpening)
2061
- };
2062
- }
2063
- //#endregion
2064
- //#region src/composables/usePopover/index.ts
2065
- /**
2066
- * @module usePopover
2067
- *
2068
- * @see https://0.vuetifyjs.com/composables/system/use-popover
2069
- *
2070
- * @remarks
2071
- * Composable for native popover API behavior with CSS anchor positioning.
2072
- * Manages open/close state, anchor styles, content attributes, bidirectional
2073
- * sync between reactive state and native popover events, and configurable
2074
- * open / close delays via `useDelay`.
2075
- *
2076
- * Key features:
2077
- * - Native popover API (showPopover/hidePopover)
2078
- * - CSS anchor positioning (position-area, position-try-fallbacks)
2079
- * - Reactive open/close delays via `useDelay`
2080
- * - Toggle event sync for native state changes
2081
- * - SSR-safe (no DOM ops outside browser)
2082
- * - Optional external isOpen ref for v-model integration
2083
- *
2084
- * @example
2085
- * ```ts
2086
- * import { usePopover } from '@vuetify/v0'
2087
- *
2088
- * const popover = usePopover({ openDelay: 200, closeDelay: 100 })
2089
- * popover.open()
2090
- * popover.toggle()
2091
- * ```
2092
- */
2093
- function usePopover(options = {}) {
2094
- const { id: _id, positionArea = "bottom", positionTry = "most-width bottom", openDelay, closeDelay } = options;
2095
- const id = _id ?? /* @__PURE__ */ useId$1();
2096
- const anchor = `--${String(id).replace(/[^a-zA-Z0-9_-]/g, "")}`;
2097
- const isOpen = options.isOpen ?? shallowRef(false);
2098
- const delay = useDelay((direction) => {
2099
- isOpen.value = direction;
2100
- }, {
2101
- openDelay,
2102
- closeDelay
2103
- });
2104
- function open() {
2105
- delay.start(true);
2106
- }
2107
- function close() {
2108
- delay.start(false);
2109
- }
2110
- function toggle() {
2111
- if (isOpen.value) close();
2112
- else open();
2113
- }
2114
- function cancel() {
2115
- delay.stop();
2116
- }
2117
- const anchorStyles = toRef(() => ({ anchorName: anchor }));
2118
- const contentAttrs = toRef(() => ({
2119
- id,
2120
- popover: ""
2121
- }));
2122
- const contentStyles = toRef(() => ({
2123
- "position": "fixed",
2124
- "margin": "unset",
2125
- "inset-area": positionArea,
2126
- "position-area": positionArea,
2127
- "position-anchor": anchor,
2128
- "position-try-fallbacks": positionTry
2129
- }));
2130
- function attach(el) {
2131
- let current;
2132
- function hide(element) {
2133
- if (!IN_BROWSER || /* @__PURE__ */ isNullOrUndefined(element)) return;
2134
- try {
2135
- if (element.matches?.(":popover-open") === false) return;
2136
- element.hidePopover?.();
2137
- } catch {}
2138
- }
2139
- function sync() {
2140
- if (!IN_BROWSER) return;
2141
- const element = toValue(el);
2142
- if (!/* @__PURE__ */ isNullOrUndefined(current) && current !== element) hide(current);
2143
- current = /* @__PURE__ */ isNullOrUndefined(element) ? void 0 : element;
2144
- if (/* @__PURE__ */ isNullOrUndefined(element)) return;
2145
- if (!isOpen.value) {
2146
- hide(element);
2147
- return;
2148
- }
2149
- if (!element.isConnected) return;
2150
- if (element.matches?.(":popover-open")) return;
2151
- element.showPopover?.();
2152
- }
2153
- watch([isOpen, () => toValue(el)], sync, {
2154
- immediate: true,
2155
- flush: "post"
2156
- });
2157
- onScopeDispose(() => {
2158
- hide(toValue(el) ?? current);
2159
- }, true);
2160
- useEventListener(el, "toggle", (e) => {
2161
- if (!toValue(el)?.isConnected) return;
2162
- isOpen.value = e.newState === "open";
2163
- });
2164
- }
2165
- return {
2166
- isOpen,
2167
- id,
2168
- open,
2169
- close,
2170
- toggle,
2171
- cancel,
2172
- anchorStyles,
2173
- contentAttrs,
2174
- contentStyles,
2175
- attach
2176
- };
2177
- }
2178
- //#endregion
2179
1846
  //#region src/composables/createFocusTraversal/index.ts
2180
1847
  /**
2181
1848
  * @module createFocusTraversal
@@ -2541,7 +2208,7 @@ var ClientComboboxAdapter = class extends ComboboxAdapter {
2541
2208
  * ```
2542
2209
  */
2543
2210
  function createCombobox(options = {}) {
2544
- const { multiple = false, mandatory = false, disabled = false, strict = false, error = false, errorMessages, adapter, displayValue = (v) => String(v ?? ""), id: _id, name, form } = options;
2211
+ const { multiple = false, mandatory = false, disabled = false, strict = false, error = false, errorMessages, adapter, positionAdapter, displayValue = (v) => String(v ?? ""), id: _id, name, form } = options;
2545
2212
  const id = _id ?? /* @__PURE__ */ useId$1();
2546
2213
  const inputId = `${id}-input`;
2547
2214
  const listboxId = `${id}-listbox`;
@@ -2582,7 +2249,11 @@ function createCombobox(options = {}) {
2582
2249
  query,
2583
2250
  items
2584
2251
  });
2585
- const popover = usePopover({ id });
2252
+ const popover = usePopover({
2253
+ id,
2254
+ adapter: positionAdapter
2255
+ });
2256
+ popover.attachAnchor(inputEl);
2586
2257
  const isOpen = popover.isOpen;
2587
2258
  const cursor = useVirtualFocus(() => selection.values().filter((ticket) => filtered.value.has(ticket.id) && !toValue(ticket.disabled)).map((ticket) => ({
2588
2259
  id: ticket.id,
@@ -2672,143 +2343,1136 @@ function createCombobox(options = {}) {
2672
2343
  };
2673
2344
  }
2674
2345
  /**
2675
- * Creates a combobox context with dependency injection support.
2676
- *
2677
- * @param options - Combobox options plus an optional namespace for DI.
2678
- * @returns A context trinity: `[useCombobox, provideCombobox, defaultCombobox]`.
2346
+ * Creates a combobox context with dependency injection support.
2347
+ *
2348
+ * @param options - Combobox options plus an optional namespace for DI.
2349
+ * @returns A context trinity: `[useCombobox, provideCombobox, defaultCombobox]`.
2350
+ *
2351
+ * @see https://0.vuetifyjs.com/composables/forms/create-combobox
2352
+ *
2353
+ * @example
2354
+ * ```ts
2355
+ * import { createComboboxContext } from '@vuetify/v0'
2356
+ *
2357
+ * const [useCombobox, provideCombobox, combobox] = createComboboxContext({
2358
+ * namespace: 'my-combobox',
2359
+ * strict: true,
2360
+ * })
2361
+ * ```
2362
+ */
2363
+ function createComboboxContext(_options = {}) {
2364
+ const { namespace = "v0:combobox", ...options } = _options;
2365
+ return createTrinity(namespace, createCombobox(options));
2366
+ }
2367
+ /**
2368
+ * Injects the current combobox context from a parent provider.
2369
+ *
2370
+ * @param namespace - DI namespace. Defaults to `'v0:combobox'`.
2371
+ * @returns The combobox context from the nearest provider.
2372
+ *
2373
+ * @see https://0.vuetifyjs.com/composables/forms/create-combobox
2374
+ *
2375
+ * @example
2376
+ * ```ts
2377
+ * import { useCombobox } from '@vuetify/v0'
2378
+ *
2379
+ * const combobox = useCombobox()
2380
+ * combobox.query.value = 'search term'
2381
+ * ```
2382
+ */
2383
+ function useCombobox(namespace = "v0:combobox") {
2384
+ return useContext(namespace);
2385
+ }
2386
+ //#endregion
2387
+ //#region src/composables/useLazy/index.ts
2388
+ /**
2389
+ * @module useLazy
2390
+ *
2391
+ * @see https://0.vuetifyjs.com/composables/system/use-lazy
2392
+ *
2393
+ * @remarks
2394
+ * Deferred content rendering composable for performance optimization.
2395
+ *
2396
+ * Key features:
2397
+ * - Content only renders after first activation (unless eager)
2398
+ * - Optional reset on deactivation for memory savings
2399
+ * - Readonly state refs for template binding
2400
+ * - Manual reset control
2401
+ * - SSR-safe
2402
+ *
2403
+ * Perfect for dialogs, menus, tooltips, and any component with
2404
+ * conditionally rendered content.
2405
+ *
2406
+ * @example
2407
+ * ```ts
2408
+ * import { shallowRef } from 'vue'
2409
+ * import { useLazy } from '@vuetify/v0'
2410
+ *
2411
+ * const isOpen = shallowRef(false)
2412
+ * const { hasContent, onAfterLeave } = useLazy(isOpen)
2413
+ * ```
2414
+ */
2415
+ /**
2416
+ * Deferred content rendering for performance optimization.
2417
+ *
2418
+ * @param active Reactive boolean controlling activation state
2419
+ * @param options Configuration options
2420
+ * @returns Lazy context with state refs and control functions
2421
+ *
2422
+ * @see https://0.vuetifyjs.com/composables/system/use-lazy
2423
+ *
2424
+ * @example
2425
+ * ```ts
2426
+ * import { ref } from 'vue'
2427
+ * import { useLazy } from '@vuetify/v0'
2428
+ *
2429
+ * const isOpen = ref(false)
2430
+ * const { hasContent, onAfterLeave } = useLazy(isOpen)
2431
+ *
2432
+ * // In template:
2433
+ * // <Transition @after-leave="onAfterLeave">
2434
+ * // <div v-if="isOpen">
2435
+ * // <template v-if="hasContent">
2436
+ * // <!-- Heavy content here -->
2437
+ * // </template>
2438
+ * // </div>
2439
+ * // </Transition>
2440
+ * ```
2441
+ *
2442
+ * @example
2443
+ * Eager mode (render immediately):
2444
+ * ```ts
2445
+ * const { hasContent } = useLazy(isOpen, { eager: true })
2446
+ * // hasContent.value is always true
2447
+ * ```
2448
+ *
2449
+ * @example
2450
+ * With reactive eager prop:
2451
+ * ```ts
2452
+ * const props = defineProps<{ eager: boolean }>()
2453
+ * const { hasContent } = useLazy(isOpen, {
2454
+ * eager: toRef(() => props.eager),
2455
+ * })
2456
+ * ```
2457
+ */
2458
+ function useLazy(active, options = {}) {
2459
+ const { eager = false, delay = 0 } = options;
2460
+ const isBooted = shallowRef(false);
2461
+ const hasContent = toRef(() => isBooted.value || toValue(eager) || toValue(active));
2462
+ const timer = delay > 0 ? useTimer(() => {
2463
+ isBooted.value = true;
2464
+ }, { duration: delay }) : void 0;
2465
+ const stop = watch(() => toValue(active), (value) => {
2466
+ if (value) if (timer) timer.start();
2467
+ else isBooted.value = true;
2468
+ else timer?.stop();
2469
+ }, { immediate: true });
2470
+ function reset() {
2471
+ isBooted.value = false;
2472
+ }
2473
+ function onAfterLeave() {
2474
+ if (!toValue(eager)) reset();
2475
+ }
2476
+ onScopeDispose(stop, true);
2477
+ return {
2478
+ isBooted: shallowReadonly(isBooted),
2479
+ hasContent: shallowReadonly(hasContent),
2480
+ reset,
2481
+ onAfterLeave
2482
+ };
2483
+ }
2484
+ //#endregion
2485
+ //#region src/composables/createSortable/index.ts
2486
+ /**
2487
+ * @module createSortable
2488
+ *
2489
+ * @see https://0.vuetifyjs.com/composables/data/create-sortable
2490
+ *
2491
+ * @remarks
2492
+ * Headless ordered-list primitive. Extends `createModel` with mutation primitives
2493
+ * (`swap`, `reorder`) and an enriched `move:ticket` event on the registry event
2494
+ * bus. Honors `disabled` as a real mutation gate at both root and per-ticket scope.
2495
+ *
2496
+ * Pure logical composable — no DnD, no DOM, no keyboard. Drag-and-drop integration
2497
+ * composes with `useDragDrop`; keyboard reorder composes with `useVirtualFocus`.
2498
+ *
2499
+ * @example
2500
+ * ```ts
2501
+ * import { createSortable } from '@vuetify/v0'
2502
+ * import type { SortableTicketInput } from '@vuetify/v0'
2503
+ *
2504
+ * interface TaskTicket extends SortableTicketInput {
2505
+ * value: { id: number; label: string }
2506
+ * }
2507
+ *
2508
+ * const sortable = createSortable<TaskTicket>()
2509
+ * const a = sortable.register({ value: { id: 1, label: 'A' } })
2510
+ * const b = sortable.register({ value: { id: 2, label: 'B' } })
2511
+ *
2512
+ * sortable.move(a.id, 1)
2513
+ * sortable.on('move:ticket', ({ ticket, from, to }) => {
2514
+ * console.log(`${ticket.value.label} moved ${from} → ${to}`)
2515
+ * })
2516
+ * ```
2517
+ */
2518
+ /**
2519
+ * Create an ordered-list state primitive.
2520
+ *
2521
+ * @param options Sortable options.
2522
+ * @returns A {@link SortableContext} that extends {@link ModelContext}.
2523
+ *
2524
+ * @example
2525
+ * ```ts
2526
+ * const sortable = createSortable<Todo>()
2527
+ * sortable.onboard(todos.value.map(value => ({ value })))
2528
+ * ```
2529
+ */
2530
+ function createSortable(_options = {}) {
2531
+ const { disabled, ...options } = _options;
2532
+ const model = createModel({
2533
+ ...options,
2534
+ events: true,
2535
+ disabled
2536
+ });
2537
+ const logger = useLogger();
2538
+ function move(id, toIndex) {
2539
+ if (toValue(disabled)) return void 0;
2540
+ const ticket = model.get(id);
2541
+ if (!ticket) return void 0;
2542
+ if (toValue(ticket.disabled)) return void 0;
2543
+ const from = ticket.index;
2544
+ const result = model.move(id, toIndex);
2545
+ if (result && result.index !== from) model.emit("move:ticket", {
2546
+ ticket: result,
2547
+ from,
2548
+ to: result.index
2549
+ });
2550
+ return result;
2551
+ }
2552
+ function swap(a, b) {
2553
+ if (toValue(disabled)) return;
2554
+ if (a === b) return;
2555
+ const ta = model.get(a);
2556
+ const tb = model.get(b);
2557
+ if (!ta || !tb) return;
2558
+ if (toValue(ta.disabled) || toValue(tb.disabled)) return;
2559
+ const indexA = ta.index;
2560
+ const indexB = tb.index;
2561
+ model.batch(() => {
2562
+ const ra = model.move(a, indexB);
2563
+ if (ra && ra.index !== indexA) model.emit("move:ticket", {
2564
+ ticket: ra,
2565
+ from: indexA,
2566
+ to: ra.index
2567
+ });
2568
+ const rb = model.move(b, indexA);
2569
+ if (rb && rb.index !== indexB) model.emit("move:ticket", {
2570
+ ticket: rb,
2571
+ from: indexB,
2572
+ to: rb.index
2573
+ });
2574
+ });
2575
+ }
2576
+ function reorder(ids) {
2577
+ if (toValue(disabled)) return;
2578
+ const currentSize = model.size;
2579
+ if (ids.length !== currentSize) {
2580
+ logger.warn(`Reorder expected ${currentSize} ids, got ${ids.length}.`);
2581
+ return;
2582
+ }
2583
+ const known = new Set(model.keys());
2584
+ const seen = /* @__PURE__ */ new Set();
2585
+ for (const id of ids) {
2586
+ if (!known.has(id)) {
2587
+ logger.warn(`Reorder contains unknown id "${String(id)}".`);
2588
+ return;
2589
+ }
2590
+ if (seen.has(id)) {
2591
+ logger.warn(`Reorder contains duplicate id "${String(id)}".`);
2592
+ return;
2593
+ }
2594
+ seen.add(id);
2595
+ }
2596
+ const froms = /* @__PURE__ */ new Map();
2597
+ for (const id of ids) {
2598
+ const ticket = model.get(id);
2599
+ if (ticket) froms.set(id, ticket.index);
2600
+ }
2601
+ model.batch(() => {
2602
+ model.reorder(ids);
2603
+ for (const [index, id] of ids.entries()) {
2604
+ const from = froms.get(id);
2605
+ if (from === index) continue;
2606
+ const ticket = model.get(id);
2607
+ if (ticket) model.emit("move:ticket", {
2608
+ ticket,
2609
+ from,
2610
+ to: index
2611
+ });
2612
+ }
2613
+ });
2614
+ }
2615
+ return {
2616
+ ...model,
2617
+ move,
2618
+ swap,
2619
+ reorder,
2620
+ get size() {
2621
+ return model.size;
2622
+ }
2623
+ };
2624
+ }
2625
+ //#endregion
2626
+ //#region src/composables/createDataGrid/editing.ts
2627
+ /**
2628
+ * @module createDataGrid/editing
2629
+ *
2630
+ * @remarks
2631
+ * Cell editing state management. Tracks active cell, validation errors,
2632
+ * and dirty (staged but uncommitted) edits. Does not mutate source data —
2633
+ * commit fires a callback for the consumer to handle.
2634
+ *
2635
+ * When a `registry` is provided, editing state for rows that get
2636
+ * unregistered (or wiped via `clear`) is pruned automatically so consumers
2637
+ * can never observe `active` pointing at a phantom row or stale entries
2638
+ * lingering in `dirty`.
2639
+ *
2640
+ * @internal Consumed only by `createDataGrid`. This is a fully decoupled 2D
2641
+ * cell-edit primitive — it imports nothing from `createDataGrid` /
2642
+ * `createDataTable` (only `#v0/utilities`, `#v0/types`, and Vue), so it is a
2643
+ * latent composable. It is parameterized over a row type `T` (defaulting to
2644
+ * `unknown`), but a type parameter is not an import — the primitive stays
2645
+ * fully decoupled from the grid's concrete ticket types and deliberately
2646
+ * row-agnostic: `T` is intentionally unconstrained, so do not narrow it to
2647
+ * the grid's `Record<string, unknown>` when promoting. Promote it to a
2648
+ * standalone `createCellEditing/`
2649
+ * composable the moment a second consumer appears (e.g. an editable
2650
+ * `createDataTable`). See `.claude/rules/composables.md` §"Sub-modules:
2651
+ * inline, private sibling, or promote".
2652
+ */
2653
+ /**
2654
+ * Creates cell editing state for a data grid.
2655
+ *
2656
+ * @param options Cell editing configuration including columns and commit callback
2657
+ * @returns Cell editing state and controls
2658
+ *
2659
+ * @example
2660
+ * ```ts
2661
+ * const editing = createCellEditing({
2662
+ * columns: [{ id: 'name', editable: true }],
2663
+ * registry: table,
2664
+ * onEdit (row, column, value) { ... },
2665
+ * })
2666
+ *
2667
+ * editing.edit(1, 'name')
2668
+ * editing.commit('Alice')
2669
+ * ```
2670
+ */
2671
+ function createCellEditing(options) {
2672
+ const { columns, onEdit, lookup, registry } = options;
2673
+ function resolveColumn(column) {
2674
+ for (const col of toValue(columns)) if (col.id === column) return col;
2675
+ }
2676
+ const active = shallowRef(null);
2677
+ const error = shallowRef(null);
2678
+ const dirty = shallowReactive(/* @__PURE__ */ new Map());
2679
+ function edit(row, column) {
2680
+ const col = resolveColumn(column);
2681
+ if (!col) return;
2682
+ if (/* @__PURE__ */ isFunction(col.editable)) {
2683
+ const item = lookup?.(row);
2684
+ if (/* @__PURE__ */ isUndefined(item) || !col.editable(item)) return;
2685
+ } else if (col.editable !== true) return;
2686
+ error.value = null;
2687
+ active.value = {
2688
+ row,
2689
+ column
2690
+ };
2691
+ }
2692
+ function commit(value) {
2693
+ const cell = active.value;
2694
+ if (!cell) return;
2695
+ const col = resolveColumn(cell.column);
2696
+ if (col?.validate) {
2697
+ const result = col.validate(value, lookup?.(cell.row));
2698
+ if (result !== true && /* @__PURE__ */ isString(result) && result.length > 0) {
2699
+ error.value = result;
2700
+ return;
2701
+ }
2702
+ }
2703
+ const entry = dirty.get(cell.row);
2704
+ if (entry) {
2705
+ entry.delete(cell.column);
2706
+ if (entry.size === 0) dirty.delete(cell.row);
2707
+ }
2708
+ error.value = null;
2709
+ active.value = null;
2710
+ onEdit?.(cell.row, cell.column, value);
2711
+ }
2712
+ function cancel() {
2713
+ const cell = active.value;
2714
+ if (cell) {
2715
+ const entry = dirty.get(cell.row);
2716
+ if (entry) {
2717
+ entry.delete(cell.column);
2718
+ if (entry.size === 0) dirty.delete(cell.row);
2719
+ }
2720
+ }
2721
+ error.value = null;
2722
+ active.value = null;
2723
+ }
2724
+ function onUnregister(data) {
2725
+ const ticket = data;
2726
+ if (active.value?.row === ticket.id) {
2727
+ active.value = null;
2728
+ error.value = null;
2729
+ }
2730
+ dirty.delete(ticket.id);
2731
+ }
2732
+ function onClear() {
2733
+ active.value = null;
2734
+ error.value = null;
2735
+ dirty.clear();
2736
+ }
2737
+ if (registry) {
2738
+ registry.on("unregister:ticket", onUnregister);
2739
+ registry.on("clear:registry", onClear);
2740
+ onScopeDispose(() => {
2741
+ registry.off("unregister:ticket", onUnregister);
2742
+ registry.off("clear:registry", onClear);
2743
+ }, true);
2744
+ }
2745
+ return {
2746
+ active,
2747
+ edit,
2748
+ commit,
2749
+ cancel,
2750
+ error,
2751
+ dirty
2752
+ };
2753
+ }
2754
+ //#endregion
2755
+ //#region src/composables/createDataGrid/layout.ts
2756
+ /**
2757
+ * @module createDataGrid/layout
2758
+ *
2759
+ * @remarks
2760
+ * Manages column layout state for data grids: sizing (percentages 0-100),
2761
+ * pinning (left/right/scrollable regions), delta-based resizing compatible
2762
+ * with the Splitter two-panel model, column reordering, and visibility.
2763
+ *
2764
+ * Column existence, display order, AND grid layout config (size, pin,
2765
+ * min/max, resizable, reorderable) all live on the table's columns registry
2766
+ * (passed in as the only argument). `createRegistry` preserves the extra
2767
+ * grid fields on each ticket, so layout reads its config straight off the
2768
+ * registered ticket — there is no separate defs array. Columns onboarded
2769
+ * before OR after the layout is built are picked up identically: an initial
2770
+ * loop seeds the already-registered set and a `register:ticket` handler seeds
2771
+ * the rest. Removed columns have their pin/size/visibility state pruned via
2772
+ * unregister events.
2773
+ *
2774
+ * Sizing uses percentages so it is compatible with the Splitter component.
2775
+ * Offsets are computed per-region (left, scrollable, right) independently
2776
+ * and over visible columns only — hidden columns are excluded from the
2777
+ * render set without auto-redistribution (headless: the consumer rebalances
2778
+ * via `distribute()` or CSS).
2779
+ *
2780
+ * @internal Private sibling of `createDataGrid`, and intentionally NOT a
2781
+ * promotion candidate: it is bound to the table's `DataTableColumnTicket`
2782
+ * types, so it is parent-specific glue rather than a reusable primitive. See
2783
+ * `.claude/rules/composables.md` §"Sub-modules: inline, private sibling, or
2784
+ * promote".
2785
+ */
2786
+ const DEFAULT_EXTRAS = {
2787
+ minSize: 2,
2788
+ maxSize: 100,
2789
+ resizable: true,
2790
+ reorderable: true
2791
+ };
2792
+ function offsets(cols, reverse = false) {
2793
+ let offset = 0;
2794
+ const start = reverse ? cols.length - 1 : 0;
2795
+ const step = reverse ? -1 : 1;
2796
+ const end = reverse ? -1 : cols.length;
2797
+ for (let i = start; i !== end; i += step) {
2798
+ cols[i].offset = offset;
2799
+ offset += cols[i].size;
2800
+ }
2801
+ }
2802
+ /**
2803
+ * Creates a column layout manager for a data grid.
2804
+ *
2805
+ * Reads column existence, display order, AND grid layout config (size, pin,
2806
+ * min/max, resizable, reorderable) from the table's columns registry. The
2807
+ * grid fields ride on each ticket — `createRegistry` preserves them — so
2808
+ * there is no separate defs array. Visibility is layout-local view state
2809
+ * (not a ticket field) kept here and reconciled via register / unregister /
2810
+ * clear events.
2811
+ *
2812
+ * Generic over the registry's input/output ticket types so the caller's
2813
+ * concrete grid column ticket (`DataGridColumnTicket`) flows through. Layout
2814
+ * only ever reads from the registry (`values`, `keys`, `on`, `reorder`,
2815
+ * `move`, `lookup`) — it never registers — so the output ticket need only be
2816
+ * readable as a {@link GridColumnDef}.
2817
+ *
2818
+ * @param cols The table's columns registry — source of truth for which
2819
+ * columns exist, in what order, and their layout config
2820
+ * @returns Column layout state and mutation methods
2821
+ */
2822
+ function createColumnLayout(cols) {
2823
+ const logger = useLogger();
2824
+ const configs = /* @__PURE__ */ new Map();
2825
+ const group = createGroup({ multiple: true });
2826
+ const sizes = shallowReactive(/* @__PURE__ */ new Map());
2827
+ const hidden = shallowReactive(/* @__PURE__ */ new Set());
2828
+ const order = [];
2829
+ function record(id) {
2830
+ if (!order.includes(id)) order.push(id);
2831
+ }
2832
+ /** Even share over the currently-registered leaves: explicit sizes are
2833
+ * honored, unsized columns split the remaining percentage. */
2834
+ function share(id) {
2835
+ const leaves = /* @__PURE__ */ extractLeaves(cols.values());
2836
+ let used = 0;
2837
+ let unsized = 0;
2838
+ for (const leaf of leaves) {
2839
+ const size = configs.get(String(leaf.id))?.size;
2840
+ if (/* @__PURE__ */ isUndefined(size)) unsized++;
2841
+ else used += size;
2842
+ }
2843
+ const own = configs.get(id)?.size;
2844
+ if (!/* @__PURE__ */ isUndefined(own)) return own;
2845
+ const remainder = Math.max(0, 100 - used);
2846
+ return unsized > 0 ? remainder / unsized : 0;
2847
+ }
2848
+ function seedLeaf(leaf) {
2849
+ const id = String(leaf.id);
2850
+ if (!configs.has(id)) configs.set(id, {
2851
+ size: leaf.size,
2852
+ minSize: leaf.minSize ?? DEFAULT_EXTRAS.minSize,
2853
+ maxSize: leaf.maxSize ?? DEFAULT_EXTRAS.maxSize,
2854
+ resizable: leaf.resizable ?? DEFAULT_EXTRAS.resizable,
2855
+ reorderable: leaf.reorderable ?? DEFAULT_EXTRAS.reorderable,
2856
+ pinned: leaf.pinned ?? false
2857
+ });
2858
+ if (!group.has(id)) group.register({
2859
+ id,
2860
+ value: id
2861
+ });
2862
+ if (!sizes.has(id)) sizes.set(id, share(id));
2863
+ for (const other of /* @__PURE__ */ extractLeaves(cols.values())) {
2864
+ const otherId = String(other.id);
2865
+ if (configs.has(otherId) && /* @__PURE__ */ isUndefined(configs.get(otherId)?.size)) sizes.set(otherId, share(otherId));
2866
+ }
2867
+ const config = configs.get(id);
2868
+ if (config.pinned === "left") group.select(id);
2869
+ else if (config.pinned === "right") group.mix(id);
2870
+ }
2871
+ function dropLeaf(id) {
2872
+ group.unregister(id);
2873
+ configs.delete(id);
2874
+ sizes.delete(id);
2875
+ hidden.delete(id);
2876
+ }
2877
+ function leavesOf(ticket) {
2878
+ return /* @__PURE__ */ extractLeaves([ticket]);
2879
+ }
2880
+ for (const ticket of cols.values()) {
2881
+ record(String(ticket.id));
2882
+ for (const leaf of leavesOf(ticket)) seedLeaf(leaf);
2883
+ }
2884
+ cols.on("register:ticket", (ticket) => {
2885
+ record(String(ticket.id));
2886
+ for (const leaf of leavesOf(ticket)) seedLeaf(leaf);
2887
+ });
2888
+ cols.on("unregister:ticket", (ticket) => {
2889
+ const top = order.indexOf(String(ticket.id));
2890
+ if (top !== -1) order.splice(top, 1);
2891
+ for (const leaf of leavesOf(ticket)) dropLeaf(String(leaf.id));
2892
+ });
2893
+ cols.on("clear:registry", () => {
2894
+ group.clear();
2895
+ configs.clear();
2896
+ sizes.clear();
2897
+ hidden.clear();
2898
+ order.length = 0;
2899
+ });
2900
+ function position(id) {
2901
+ if (group.selectedIds.has(id)) return "left";
2902
+ if (group.mixed(id)) return "right";
2903
+ return false;
2904
+ }
2905
+ function resolve(includeHidden) {
2906
+ const resolved = [];
2907
+ let index = 0;
2908
+ for (const ticket of /* @__PURE__ */ extractLeaves(cols.values())) {
2909
+ const id = String(ticket.id);
2910
+ const visible = !hidden.has(id);
2911
+ if (!includeHidden && !visible) continue;
2912
+ const meta = configs.get(id) ?? DEFAULT_EXTRAS;
2913
+ resolved.push({
2914
+ id,
2915
+ index: index++,
2916
+ size: sizes.get(id) ?? 0,
2917
+ offset: 0,
2918
+ pinned: position(id),
2919
+ resizable: meta.resizable,
2920
+ reorderable: meta.reorderable,
2921
+ minSize: meta.minSize,
2922
+ maxSize: meta.maxSize,
2923
+ visible
2924
+ });
2925
+ }
2926
+ return resolved;
2927
+ }
2928
+ function split(resolved) {
2929
+ const left = [];
2930
+ const scrollable = [];
2931
+ const right = [];
2932
+ for (const col of resolved) if (col.pinned === "left") left.push(col);
2933
+ else if (col.pinned === "right") right.push(col);
2934
+ else scrollable.push(col);
2935
+ offsets(left);
2936
+ offsets(scrollable);
2937
+ offsets(right, true);
2938
+ return {
2939
+ left,
2940
+ scrollable,
2941
+ right
2942
+ };
2943
+ }
2944
+ const pinned = computed(() => split(resolve(false)));
2945
+ const columns = computed(() => {
2946
+ const { left, scrollable, right } = pinned.value;
2947
+ return [
2948
+ ...left,
2949
+ ...scrollable,
2950
+ ...right
2951
+ ];
2952
+ });
2953
+ const allColumns = computed(() => resolve(true));
2954
+ function pin(id, pos) {
2955
+ if (!group.has(id)) return;
2956
+ group.unselect(id);
2957
+ group.unmix(id);
2958
+ if (pos === "left") group.select(id);
2959
+ else if (pos === "right") group.mix(id);
2960
+ }
2961
+ function resize(id, delta) {
2962
+ const { left, scrollable, right } = pinned.value;
2963
+ const all = [
2964
+ ...left,
2965
+ ...scrollable,
2966
+ ...right
2967
+ ];
2968
+ const target = all.find((c) => c.id === id);
2969
+ if (!target || !target.resizable) return;
2970
+ const allIndex = all.findIndex((c) => c.id === id);
2971
+ if (allIndex === -1 || allIndex === all.length - 1) return;
2972
+ const neighbor = all[allIndex + 1];
2973
+ const total = target.size + neighbor.size;
2974
+ const lower = Math.max(target.minSize, total - neighbor.maxSize);
2975
+ const upper = Math.min(target.maxSize, total - neighbor.minSize);
2976
+ const clamped = /* @__PURE__ */ clamp(target.size + delta, lower, upper);
2977
+ sizes.set(id, clamped);
2978
+ sizes.set(neighbor.id, total - clamped);
2979
+ }
2980
+ function reorder(from, to) {
2981
+ if (from === to) return;
2982
+ const tops = [...cols.values()];
2983
+ const ids = [];
2984
+ const leafToTop = [];
2985
+ for (const [top, ticket] of tops.entries()) for (const leaf of /* @__PURE__ */ extractLeaves([ticket])) {
2986
+ ids.push(String(leaf.id));
2987
+ leafToTop.push(top);
2988
+ }
2989
+ const visible = ids.filter((id) => !hidden.has(id));
2990
+ const fromId = visible[from];
2991
+ const toId = visible[to];
2992
+ if (/* @__PURE__ */ isUndefined(fromId) || /* @__PURE__ */ isUndefined(toId)) return;
2993
+ const fromTop = leafToTop[ids.indexOf(fromId)];
2994
+ const toTop = leafToTop[ids.indexOf(toId)];
2995
+ if (/* @__PURE__ */ isUndefined(fromTop) || /* @__PURE__ */ isUndefined(toTop) || fromTop === toTop) return;
2996
+ if (tops[fromTop]?.reorderable === false) return;
2997
+ const id = cols.lookup(fromTop);
2998
+ if (/* @__PURE__ */ isUndefined(id)) return;
2999
+ cols.move(id, toTop);
3000
+ }
3001
+ function distribute(incoming) {
3002
+ const visible = (/* @__PURE__ */ extractLeaves(cols.values())).filter((leaf) => !hidden.has(String(leaf.id)));
3003
+ if (incoming.length !== visible.length) {
3004
+ logger.warn(`createDataGrid: distribute() expected ${visible.length} sizes but received ${incoming.length}; ignoring.`);
3005
+ return;
3006
+ }
3007
+ const sum = incoming.reduce((acc, value) => acc + value, 0);
3008
+ if (sum <= 0) {
3009
+ logger.warn(`createDataGrid: distribute() received sizes summing to ${sum}; expected a positive total.`);
3010
+ return;
3011
+ }
3012
+ const metas = visible.map((col) => configs.get(String(col.id)) ?? DEFAULT_EXTRAS);
3013
+ let current = incoming.map((value, i) => /* @__PURE__ */ clamp(value / sum * 100, metas[i].minSize, metas[i].maxSize));
3014
+ let residual = 100 - current.reduce((acc, value) => acc + value, 0);
3015
+ const max = visible.length * 2;
3016
+ for (let pass = 0; pass < max && Math.abs(residual) >= 1e-6; pass++) {
3017
+ const room = current.map((value, i) => residual > 0 ? metas[i].maxSize - value : value - metas[i].minSize);
3018
+ const available = room.reduce((acc, value) => acc + Math.max(0, value), 0);
3019
+ if (available <= 0) break;
3020
+ current = current.map((value, i) => room[i] <= 0 ? value : value + residual * (room[i] / available));
3021
+ residual = 100 - current.reduce((acc, value) => acc + value, 0);
3022
+ }
3023
+ if (Math.abs(residual) >= 1e-6) logger.warn(`createDataGrid: distribute() could not reach 100 within min/max constraints (off by ${residual.toFixed(2)})`);
3024
+ for (const [i, col] of visible.entries()) sizes.set(String(col.id), current[i]);
3025
+ }
3026
+ function show(id) {
3027
+ hidden.delete(id);
3028
+ }
3029
+ function hide(id) {
3030
+ hidden.add(id);
3031
+ }
3032
+ function toggle(id) {
3033
+ if (hidden.has(id)) hidden.delete(id);
3034
+ else hidden.add(id);
3035
+ }
3036
+ function reset() {
3037
+ for (const ticket of /* @__PURE__ */ extractLeaves(cols.values())) {
3038
+ const id = String(ticket.id);
3039
+ sizes.set(id, share(id));
3040
+ }
3041
+ cols.reorder([...order]);
3042
+ hidden.clear();
3043
+ for (const ticket of /* @__PURE__ */ extractLeaves(cols.values())) {
3044
+ const id = String(ticket.id);
3045
+ group.unselect(id);
3046
+ group.unmix(id);
3047
+ }
3048
+ for (const [id, config] of configs) if (config.pinned === "left") group.select(id);
3049
+ else if (config.pinned === "right") group.mix(id);
3050
+ }
3051
+ return {
3052
+ pinned,
3053
+ columns,
3054
+ all: allColumns,
3055
+ pin,
3056
+ resize,
3057
+ reorder,
3058
+ distribute,
3059
+ show,
3060
+ hide,
3061
+ toggle,
3062
+ reset
3063
+ };
3064
+ }
3065
+ //#endregion
3066
+ //#region src/composables/createDataGrid/spanning.ts
3067
+ /**
3068
+ * @module createDataGrid/spanning
3069
+ *
3070
+ * @remarks
3071
+ * Computes a row span map from visible items. For each cell, determines
3072
+ * rowSpan and whether it's hidden (covered by a span from a previous row).
3073
+ * Spans do not cross page boundaries. Each row is addressed by a key: either a
3074
+ * `key(item, index)` projection (the grid passes the registry ticket id) or,
3075
+ * absent that, the row's `itemKey` value. Rows whose resolved key is
3076
+ * `undefined` cannot be addressed in the resulting map and are skipped.
3077
+ *
3078
+ * @internal Consumed only by `createDataGrid`. Fully decoupled (items ref +
3079
+ * columns + key + span fn — no grid/table types), so it is a latent composable.
3080
+ * Promote it to a standalone `createRowSpanning/` composable on a second
3081
+ * consumer. See `.claude/rules/composables.md` §"Sub-modules: inline, private
3082
+ * sibling, or promote".
3083
+ */
3084
+ /**
3085
+ * Computes a row span map from visible items.
3086
+ *
3087
+ * @param options Row spanning configuration
3088
+ * @returns A computed map of item ID to column to SpanEntry
3089
+ *
3090
+ * @example
3091
+ * ```ts
3092
+ * const spans = createRowSpanning({
3093
+ * items: computed(() => grid.items.value),
3094
+ * columns: ['group', 'ticker', 'value'],
3095
+ * span: (item, column) => column === 'group' ? 3 : 1,
3096
+ * })
3097
+ *
3098
+ * spans.value.get(id)?.get('group') // { rowSpan: 3, hidden: false }
3099
+ * ```
3100
+ */
3101
+ function createRowSpanning(options) {
3102
+ const { items, columns, key, itemKey = "id", span } = options;
3103
+ return computed(() => {
3104
+ const result = /* @__PURE__ */ new Map();
3105
+ if (!span) return result;
3106
+ const list = items.value;
3107
+ const resolved = toValue(columns);
3108
+ const covered = Array.from({ length: resolved.length }).fill(0);
3109
+ for (let row = 0; row < list.length; row++) {
3110
+ const item = list[row];
3111
+ const id = key ? key(item, row) : item[itemKey];
3112
+ if (/* @__PURE__ */ isUndefined(id)) continue;
3113
+ const cells = /* @__PURE__ */ new Map();
3114
+ for (const [col, column] of resolved.entries()) if (covered[col] > 0) {
3115
+ cells.set(column, {
3116
+ rowSpan: 1,
3117
+ hidden: true
3118
+ });
3119
+ covered[col]--;
3120
+ } else {
3121
+ const raw = span(item, column);
3122
+ const rowSpan = Math.min(Math.max(1, /* @__PURE__ */ isNaN(raw) ? 1 : raw), list.length - row);
3123
+ cells.set(column, {
3124
+ rowSpan,
3125
+ hidden: false
3126
+ });
3127
+ if (rowSpan > 1) covered[col] = rowSpan - 1;
3128
+ }
3129
+ result.set(id, cells);
3130
+ }
3131
+ return result;
3132
+ });
3133
+ }
3134
+ //#endregion
3135
+ //#region src/composables/createDataGrid/index.ts
3136
+ /**
3137
+ * @module createDataGrid
3138
+ *
3139
+ * @see https://0.vuetifyjs.com/composables/data/create-data-grid
3140
+ *
3141
+ * @remarks
3142
+ * Main factory that wires together column layout, cell editing, row ordering,
3143
+ * and row spanning on top of a createDataTable pipeline. Row ordering is
3144
+ * provided by a createSortable instance synced to the table's row registry
3145
+ * via register / unregister events; the ordered ids are applied post-sort,
3146
+ * pre-pagination by overriding the `items` projection.
3147
+ *
3148
+ * Rows are registered through the inherited registry surface (`register`,
3149
+ * `onboard`, `unregister`, `clear`) — they are not passed as an `items`
3150
+ * option to the factory.
3151
+ *
3152
+ * Follows the trinity pattern for dependency injection.
3153
+ *
3154
+ * @example
3155
+ * ```ts
3156
+ * const grid = createDataGrid()
3157
+ *
3158
+ * grid.columns.onboard([
3159
+ * { id: 'name', sortable: true },
3160
+ * { id: 'progress', editable: true },
3161
+ * ])
3162
+ *
3163
+ * grid.onboard(rows.map(value => ({ id: value.id, value })))
3164
+ * grid.layout.pin('name', 'left')
3165
+ * grid.editing.edit(row.id, 'progress')
3166
+ * ```
3167
+ */
3168
+ function recordId(row) {
3169
+ return row.id;
3170
+ }
3171
+ /**
3172
+ * Creates a data grid instance with layout, editing, row ordering, and spanning
3173
+ * layered on top of the createDataTable pipeline.
3174
+ *
3175
+ * Rows live on the inherited registry surface — register them with
3176
+ * `grid.onboard(rows.map(value => ({ id: value.id, value })))` or
3177
+ * `grid.register({ id, value })`.
3178
+ *
3179
+ * @param options Data grid options
3180
+ * @returns Data grid context
3181
+ *
3182
+ * @example
3183
+ * ```ts
3184
+ * const grid = createDataGrid({ pagination: { page: 1 } })
3185
+ *
3186
+ * grid.columns.onboard([
3187
+ * { id: 'name', sortable: true },
3188
+ * { id: 'progress', editable: true, validate: v => Number(v) >= 0 || 'must be positive' },
3189
+ * ])
3190
+ *
3191
+ * grid.onboard(rows.map(value => ({ id: value.id, value })))
3192
+ * grid.layout.pin('name', 'left')
3193
+ * grid.rows.move(rowId, 0)
3194
+ * grid.editing.edit(row.id, 'progress')
3195
+ * ```
3196
+ */
3197
+ function createDataGrid(_options = {}) {
3198
+ const { editing: editingOptions, preserveRowOrder = false, rowSpanning, ...options } = _options;
3199
+ const table = createDataTable(options);
3200
+ const sortable = createSortable();
3201
+ const sortableProxy = useProxyRegistry(sortable);
3202
+ const dirty = shallowRef(false);
3203
+ table.on("register:ticket", (ticket) => {
3204
+ sortable.register({
3205
+ id: ticket.id,
3206
+ value: ticket.id
3207
+ });
3208
+ });
3209
+ table.on("unregister:ticket", (ticket) => {
3210
+ sortable.unregister(ticket.id);
3211
+ });
3212
+ table.on("clear:registry", () => {
3213
+ sortable.clear();
3214
+ dirty.value = false;
3215
+ });
3216
+ const order = toRef(() => sortableProxy.keys);
3217
+ const sortedIds = computed(() => {
3218
+ const buckets = /* @__PURE__ */ new Map();
3219
+ for (const ticket of table.values()) {
3220
+ const value = ticket.value;
3221
+ const queue = buckets.get(value);
3222
+ if (queue) queue.push(ticket.id);
3223
+ else buckets.set(value, [ticket.id]);
3224
+ }
3225
+ const ids = [];
3226
+ for (const value of table.sortedItems.value) {
3227
+ const id = buckets.get(value)?.shift();
3228
+ if (!/* @__PURE__ */ isUndefined(id)) ids.push(id);
3229
+ }
3230
+ return ids;
3231
+ });
3232
+ function move(id, toIndex) {
3233
+ if (!dirty.value) {
3234
+ const sorted = sortedIds.value;
3235
+ const seen = new Set(sorted);
3236
+ const rest = sortable.keys().filter((key) => !seen.has(key));
3237
+ sortable.reorder([...sorted, ...rest]);
3238
+ }
3239
+ sortable.move(id, toIndex);
3240
+ dirty.value = true;
3241
+ }
3242
+ function reset() {
3243
+ if (!dirty.value) return;
3244
+ if (sortable.size > 0) sortable.reorder(table.keys());
3245
+ dirty.value = false;
3246
+ }
3247
+ useToggleScope(() => !toValue(preserveRowOrder), () => {
3248
+ watch(table.sort.columns, reset, { flush: "sync" });
3249
+ });
3250
+ const ordered = computed(() => {
3251
+ if (!dirty.value) return {
3252
+ items: table.sortedItems.value,
3253
+ ids: sortedIds.value
3254
+ };
3255
+ const sorted = table.sortedItems.value;
3256
+ const ids = sortedIds.value;
3257
+ const byId = /* @__PURE__ */ new Map();
3258
+ for (let i = 0; i < sorted.length; i++) byId.set(ids[i], sorted[i]);
3259
+ const seen = new Set(order.value);
3260
+ const items = [];
3261
+ const orderedIds = [];
3262
+ for (const id of order.value) {
3263
+ const value = byId.get(id);
3264
+ if (!/* @__PURE__ */ isUndefined(value)) {
3265
+ items.push(value);
3266
+ orderedIds.push(id);
3267
+ }
3268
+ }
3269
+ for (const [i, element] of sorted.entries()) {
3270
+ const id = ids[i];
3271
+ if (!seen.has(id)) {
3272
+ items.push(element);
3273
+ orderedIds.push(id);
3274
+ }
3275
+ }
3276
+ return {
3277
+ items,
3278
+ ids: orderedIds
3279
+ };
3280
+ });
3281
+ const page = computed(() => {
3282
+ if (!dirty.value) {
3283
+ const start = table.pagination.pageStart.value;
3284
+ return {
3285
+ items: table.items.value,
3286
+ ids: table.total.value > table.sortedItems.value.length ? sortedIds.value : sortedIds.value.slice(start, start + table.items.value.length)
3287
+ };
3288
+ }
3289
+ const full = ordered.value;
3290
+ if (table.total.value > table.sortedItems.value.length) return full;
3291
+ const start = table.pagination.pageStart.value;
3292
+ const stop = table.pagination.pageStop.value;
3293
+ return {
3294
+ items: full.items.slice(start, stop),
3295
+ ids: full.ids.slice(start, stop)
3296
+ };
3297
+ });
3298
+ const pageOrderedItems = toRef(() => page.value.items);
3299
+ const orderedItems = toRef(() => ordered.value.items);
3300
+ function rank(source) {
3301
+ const ranked = orderedItems.value;
3302
+ const positions = /* @__PURE__ */ new Map();
3303
+ for (const [index, row] of ranked.entries()) {
3304
+ positions.set(row, index);
3305
+ const id = recordId(row);
3306
+ if (!/* @__PURE__ */ isNullOrUndefined(id)) positions.set(id, index);
3307
+ }
3308
+ return [...source].toSorted((a, b) => {
3309
+ return (positions.get(a) ?? positions.get(recordId(a)) ?? Infinity) - (positions.get(b) ?? positions.get(recordId(b)) ?? Infinity);
3310
+ });
3311
+ }
3312
+ const layout = createColumnLayout(table.columns);
3313
+ function lookup(row) {
3314
+ return table.get(row)?.value;
3315
+ }
3316
+ const editing = createCellEditing({
3317
+ columns: () => table.leaves.value.filter((col) => col.editable === true || /* @__PURE__ */ isFunction(col.editable)).map((col) => ({
3318
+ id: String(col.id),
3319
+ editable: col.editable,
3320
+ validate: col.validate
3321
+ })),
3322
+ lookup,
3323
+ registry: table,
3324
+ onEdit: editingOptions?.onEdit ? (row, column, value) => {
3325
+ const item = lookup(row);
3326
+ if (!/* @__PURE__ */ isUndefined(item)) editingOptions.onEdit(row, column, value, item);
3327
+ } : void 0
3328
+ });
3329
+ const spans = createRowSpanning({
3330
+ items: pageOrderedItems,
3331
+ columns: () => table.leaves.value.map((col) => col.id),
3332
+ key: (_item, index) => page.value.ids[index],
3333
+ span(item, column) {
3334
+ const col = table.leaves.value.find((leaf) => String(leaf.id) === column);
3335
+ if (col && /* @__PURE__ */ isFunction(col.span)) return col.span(item);
3336
+ return rowSpanning?.(item, column) ?? 1;
3337
+ }
3338
+ });
3339
+ return {
3340
+ ...table,
3341
+ items: pageOrderedItems,
3342
+ orderedItems,
3343
+ rank,
3344
+ layout,
3345
+ rows: {
3346
+ order,
3347
+ move,
3348
+ reset
3349
+ },
3350
+ editing,
3351
+ spans,
3352
+ get size() {
3353
+ return table.size;
3354
+ }
3355
+ };
3356
+ }
3357
+ /**
3358
+ * Creates a data grid context with dependency injection support.
2679
3359
  *
2680
- * @see https://0.vuetifyjs.com/composables/forms/create-combobox
3360
+ * @param options Data grid context options including namespace
3361
+ * @returns A trinity tuple: [useDataGridContext, provideDataGridContext, defaultContext]
2681
3362
  *
2682
3363
  * @example
2683
3364
  * ```ts
2684
- * import { createComboboxContext } from '@vuetify/v0'
2685
- *
2686
- * const [useCombobox, provideCombobox, combobox] = createComboboxContext({
2687
- * namespace: 'my-combobox',
2688
- * strict: true,
3365
+ * const [useDataGrid, provideDataGrid, grid] = createDataGridContext({
3366
+ * namespace: 'v0:projects',
2689
3367
  * })
3368
+ *
3369
+ * grid.columns.onboard(columns)
3370
+ * grid.onboard(rows.map(value => ({ id: value.id, value })))
3371
+ * provideDataGrid()
3372
+ * const ctx = useDataGrid()
2690
3373
  * ```
2691
3374
  */
2692
- function createComboboxContext(_options = {}) {
2693
- const { namespace = "v0:combobox", ...options } = _options;
2694
- return createTrinity(namespace, createCombobox(options));
3375
+ function createDataGridContext(_options = {}) {
3376
+ const { namespace = "v0:data-grid", ...options } = _options;
3377
+ const [useDataGridContext, _provideDataGridContext] = createContext(namespace);
3378
+ const context = createDataGrid(options);
3379
+ function provideDataGridContext(_context = context, app) {
3380
+ return _provideDataGridContext(_context, app);
3381
+ }
3382
+ return createTrinity(useDataGridContext, provideDataGridContext, context);
2695
3383
  }
2696
3384
  /**
2697
- * Injects the current combobox context from a parent provider.
2698
- *
2699
- * @param namespace - DI namespace. Defaults to `'v0:combobox'`.
2700
- * @returns The combobox context from the nearest provider.
3385
+ * Returns the current data grid context from dependency injection.
2701
3386
  *
2702
- * @see https://0.vuetifyjs.com/composables/forms/create-combobox
3387
+ * @param namespace The namespace for the data grid context. @default 'v0:data-grid'
3388
+ * @returns The current data grid context
2703
3389
  *
2704
3390
  * @example
2705
3391
  * ```ts
2706
- * import { useCombobox } from '@vuetify/v0'
3392
+ * const grid = useDataGrid<Project>()
2707
3393
  *
2708
- * const combobox = useCombobox()
2709
- * combobox.query.value = 'search term'
3394
+ * grid.layout.pin('id', 'left')
3395
+ * grid.rows.reset()
2710
3396
  * ```
2711
3397
  */
2712
- function useCombobox(namespace = "v0:combobox") {
3398
+ function useDataGrid(namespace = "v0:data-grid") {
2713
3399
  return useContext(namespace);
2714
3400
  }
2715
3401
  //#endregion
2716
- //#region src/composables/useLazy/index.ts
3402
+ //#region src/composables/useRaf/index.ts
2717
3403
  /**
2718
- * @module useLazy
3404
+ * @module useRaf
2719
3405
  *
2720
- * @see https://0.vuetifyjs.com/composables/system/use-lazy
3406
+ * @see https://0.vuetifyjs.com/composables/system/use-raf
2721
3407
  *
2722
3408
  * @remarks
2723
- * Deferred content rendering composable for performance optimization.
3409
+ * Scope-disposed safe requestAnimationFrame composable.
2724
3410
  *
2725
3411
  * Key features:
2726
- * - Content only renders after first activation (unless eager)
2727
- * - Optional reset on deactivation for memory savings
2728
- * - Readonly state refs for template binding
2729
- * - Manual reset control
2730
- * - SSR-safe
3412
+ * - Cancel-then-request pattern (deduplicates rapid calls)
3413
+ * - Automatic cleanup on scope disposal
3414
+ * - SSR-safe (no-op in non-browser environments)
3415
+ * - Callable function with cancel method
2731
3416
  *
2732
- * Perfect for dialogs, menus, tooltips, and any component with
2733
- * conditionally rendered content.
3417
+ * Perfect for throttling updates to the next animation frame.
2734
3418
  *
2735
3419
  * @example
2736
3420
  * ```ts
2737
- * import { shallowRef } from 'vue'
2738
- * import { useLazy } from '@vuetify/v0'
3421
+ * import { useRaf } from '@vuetify/v0'
2739
3422
  *
2740
- * const isOpen = shallowRef(false)
2741
- * const { hasContent, onAfterLeave } = useLazy(isOpen)
3423
+ * const update = useRaf(timestamp => {
3424
+ * // runs on next animation frame
3425
+ * })
3426
+ * update()
2742
3427
  * ```
2743
3428
  */
2744
3429
  /**
2745
- * Deferred content rendering for performance optimization.
3430
+ * Scope-disposed safe requestAnimationFrame.
2746
3431
  *
2747
- * @param active Reactive boolean controlling activation state
2748
- * @param options Configuration options
2749
- * @returns Lazy context with state refs and control functions
3432
+ * @param callback Function to call on animation frame.
3433
+ * @returns Callable that requests frame (canceling pending), with cancel method.
2750
3434
  *
2751
- * @see https://0.vuetifyjs.com/composables/system/use-lazy
3435
+ * @see https://0.vuetifyjs.com/composables/system/use-raf
2752
3436
  *
2753
3437
  * @example
2754
3438
  * ```ts
2755
- * import { ref } from 'vue'
2756
- * import { useLazy } from '@vuetify/v0'
2757
- *
2758
- * const isOpen = ref(false)
2759
- * const { hasContent, onAfterLeave } = useLazy(isOpen)
3439
+ * // Basic usage
3440
+ * const update = useRaf((timestamp) => {
3441
+ * // Runs on next animation frame
3442
+ * })
2760
3443
  *
2761
- * // In template:
2762
- * // <Transition @after-leave="onAfterLeave">
2763
- * // <div v-if="isOpen">
2764
- * // <template v-if="hasContent">
2765
- * // <!-- Heavy content here -->
2766
- * // </template>
2767
- * // </div>
2768
- * // </Transition>
2769
- * ```
3444
+ * update() // Request frame
3445
+ * update() // Cancels previous, requests new (deduplicated)
2770
3446
  *
2771
- * @example
2772
- * Eager mode (render immediately):
2773
- * ```ts
2774
- * const { hasContent } = useLazy(isOpen, { eager: true })
2775
- * // hasContent.value is always true
2776
- * ```
3447
+ * // Manual cancel
3448
+ * update.cancel()
2777
3449
  *
2778
- * @example
2779
- * With reactive eager prop:
2780
- * ```ts
2781
- * const props = defineProps<{ eager: boolean }>()
2782
- * const { hasContent } = useLazy(isOpen, {
2783
- * eager: toRef(() => props.eager),
2784
- * })
3450
+ * // Check if pending
3451
+ * if (update.isActive.value) { ... }
2785
3452
  * ```
2786
3453
  */
2787
- function useLazy(active, options = {}) {
2788
- const { eager = false, delay = 0 } = options;
2789
- const isBooted = shallowRef(false);
2790
- const hasContent = toRef(() => isBooted.value || toValue(eager) || toValue(active));
2791
- const timer = delay > 0 ? useTimer(() => {
2792
- isBooted.value = true;
2793
- }, { duration: delay }) : void 0;
2794
- const stop = watch(() => toValue(active), (value) => {
2795
- if (value) if (timer) timer.start();
2796
- else isBooted.value = true;
2797
- else timer?.stop();
2798
- }, { immediate: true });
2799
- function reset() {
2800
- isBooted.value = false;
3454
+ function useRaf(callback) {
3455
+ const id = shallowRef();
3456
+ const isActive = toRef(() => !/* @__PURE__ */ isUndefined(id.value));
3457
+ function cancel() {
3458
+ if (!/* @__PURE__ */ isUndefined(id.value)) {
3459
+ cancelAnimationFrame(id.value);
3460
+ id.value = void 0;
3461
+ }
2801
3462
  }
2802
- function onAfterLeave() {
2803
- if (!toValue(eager)) reset();
3463
+ function request() {
3464
+ if (!IN_BROWSER) return;
3465
+ cancel();
3466
+ id.value = requestAnimationFrame((timestamp) => {
3467
+ id.value = void 0;
3468
+ callback(timestamp);
3469
+ });
2804
3470
  }
2805
- onScopeDispose(stop, true);
2806
- return {
2807
- isBooted: shallowReadonly(isBooted),
2808
- hasContent: shallowReadonly(hasContent),
2809
- reset,
2810
- onAfterLeave
2811
- };
3471
+ onScopeDispose(cancel, true);
3472
+ return Object.assign(request, {
3473
+ cancel,
3474
+ isActive
3475
+ });
2812
3476
  }
2813
3477
  //#endregion
2814
3478
  //#region src/composables/createForm/index.ts
@@ -3202,7 +3866,7 @@ const UNSET = /* @__PURE__ */ Symbol("unset");
3202
3866
  * ```
3203
3867
  */
3204
3868
  function createValidation(_options = {}) {
3205
- const { rules: initialRules = [], value: valueSource, enroll = true, ...options } = _options;
3869
+ const { rules: initialRules = [], value: valueSource, enroll = true, formNamespace = "v0:form", ...options } = _options;
3206
3870
  const group = createGroup({
3207
3871
  ...options,
3208
3872
  enroll,
@@ -3217,8 +3881,8 @@ function createValidation(_options = {}) {
3217
3881
  let latest;
3218
3882
  function register(input) {
3219
3883
  if (/* @__PURE__ */ isFunction(input) || /* @__PURE__ */ isString(input) || /* @__PURE__ */ isStandardSchema(input)) {
3220
- const resolved = rulesContext.resolve([input]);
3221
- return group.register({ value: resolved[0] ?? (() => true) });
3884
+ const rule = rulesContext.resolve([input])[0] ?? (() => /* @__PURE__ */ isString(input) ? `Unknown validation rule "${input}"` : false);
3885
+ return group.register({ value: rule });
3222
3886
  }
3223
3887
  return group.register(input);
3224
3888
  }
@@ -3297,7 +3961,7 @@ function createValidation(_options = {}) {
3297
3961
  return group.size;
3298
3962
  }
3299
3963
  };
3300
- const form = useForm();
3964
+ const form = useForm(formNamespace);
3301
3965
  const ticket = form?.register({ value: context });
3302
3966
  onScopeDispose(() => {
3303
3967
  if (!ticket || !form) return;
@@ -3325,15 +3989,24 @@ function createValidation(_options = {}) {
3325
3989
  * import { createInput } from '@vuetify/v0'
3326
3990
  *
3327
3991
  * const value = shallowRef('')
3328
- * const input = createInput({ value, label: 'Name', rules: ['required'] })
3992
+ * const input = createInput({ value, label: 'Name', required: true })
3329
3993
  * await input.validate()
3330
3994
  * ```
3331
3995
  */
3332
3996
  function createInput(options) {
3333
- const { value, id = /* @__PURE__ */ useId$1(), label, name, form, required, disabled = false, readonly: _readonly = false, rules = [], error = false, errorMessages, dirty: dirtyFn, equals = (a, b) => a === b } = options;
3997
+ const { value, id = /* @__PURE__ */ useId$1(), label, name, form, formNamespace, required, disabled = false, readonly: _readonly = false, rules = [], error = false, errorMessages, dirty: dirtyFn, equals = (a, b) => a === b } = options;
3998
+ function filled(val) {
3999
+ if (dirtyFn) return dirtyFn(val);
4000
+ return /* @__PURE__ */ isString(val) ? val.length > 0 : !/* @__PURE__ */ isNullOrUndefined(val);
4001
+ }
4002
+ const locale = useLocale();
4003
+ function requiredRule(v) {
4004
+ return filled(v) || (locale.ti("Input.required") ?? "Required");
4005
+ }
3334
4006
  const validation = createValidation({
3335
- rules,
3336
- value
4007
+ rules: required ? [requiredRule, ...rules] : rules,
4008
+ value,
4009
+ formNamespace
3337
4010
  });
3338
4011
  const initialValue = value.value;
3339
4012
  const isFocused = shallowRef(false);
@@ -3346,10 +4019,7 @@ function createInput(options) {
3346
4019
  const isReadonly = toRef(() => toValue(_readonly));
3347
4020
  const descriptionId = `${id}-description`;
3348
4021
  const errorId = `${id}-error`;
3349
- const isDirty = toRef(() => {
3350
- if (dirtyFn) return dirtyFn(value.value);
3351
- return /* @__PURE__ */ isString(value.value) ? value.value.length > 0 : !/* @__PURE__ */ isNullOrUndefined(value.value);
3352
- });
4022
+ const isDirty = toRef(() => filled(value.value));
3353
4023
  const isPristine = shallowRef(true);
3354
4024
  watch(value, (val) => {
3355
4025
  isPristine.value = equals(val, initialValue);
@@ -3511,7 +4181,7 @@ function createNumeric(options = {}) {
3511
4181
  * ```
3512
4182
  */
3513
4183
  function createNumberField(options = {}) {
3514
- const { value = ref(null), locale = "en-US", format: formatOptions, clamp: shouldClamp = true, disabled = false, readonly: _readonly = false, min, max, step, leap, wrap, id, label, name, rules, error, errorMessages } = options;
4184
+ const { value = ref(null), locale = "en-US", format: formatOptions, clamp: shouldClamp = true, commitOn = "change", disabled = false, readonly: _readonly = false, min, max, step, leap, wrap, id, label, name, formNamespace, required, rules, error, errorMessages } = options;
3515
4185
  const numeric = createNumeric({
3516
4186
  min,
3517
4187
  max,
@@ -3524,6 +4194,8 @@ function createNumberField(options = {}) {
3524
4194
  id,
3525
4195
  label,
3526
4196
  name,
4197
+ formNamespace,
4198
+ required,
3527
4199
  disabled,
3528
4200
  readonly: _readonly,
3529
4201
  rules,
@@ -3601,6 +4273,10 @@ function createNumberField(options = {}) {
3601
4273
  }
3602
4274
  value.value = numeric.snap(val);
3603
4275
  }
4276
+ function write(text) {
4277
+ if (isLocked()) return;
4278
+ value.value = parse(text);
4279
+ }
3604
4280
  return {
3605
4281
  value,
3606
4282
  display,
@@ -3614,86 +4290,12 @@ function createNumberField(options = {}) {
3614
4290
  ceil,
3615
4291
  formatValue,
3616
4292
  parse,
3617
- commit
4293
+ commit,
4294
+ commitOn,
4295
+ write
3618
4296
  };
3619
4297
  }
3620
4298
  //#endregion
3621
- //#region src/composables/useRaf/index.ts
3622
- /**
3623
- * @module useRaf
3624
- *
3625
- * @see https://0.vuetifyjs.com/composables/system/use-raf
3626
- *
3627
- * @remarks
3628
- * Scope-disposed safe requestAnimationFrame composable.
3629
- *
3630
- * Key features:
3631
- * - Cancel-then-request pattern (deduplicates rapid calls)
3632
- * - Automatic cleanup on scope disposal
3633
- * - SSR-safe (no-op in non-browser environments)
3634
- * - Callable function with cancel method
3635
- *
3636
- * Perfect for throttling updates to the next animation frame.
3637
- *
3638
- * @example
3639
- * ```ts
3640
- * import { useRaf } from '@vuetify/v0'
3641
- *
3642
- * const update = useRaf(timestamp => {
3643
- * // runs on next animation frame
3644
- * })
3645
- * update()
3646
- * ```
3647
- */
3648
- /**
3649
- * Scope-disposed safe requestAnimationFrame.
3650
- *
3651
- * @param callback Function to call on animation frame.
3652
- * @returns Callable that requests frame (canceling pending), with cancel method.
3653
- *
3654
- * @see https://0.vuetifyjs.com/composables/system/use-raf
3655
- *
3656
- * @example
3657
- * ```ts
3658
- * // Basic usage
3659
- * const update = useRaf((timestamp) => {
3660
- * // Runs on next animation frame
3661
- * })
3662
- *
3663
- * update() // Request frame
3664
- * update() // Cancels previous, requests new (deduplicated)
3665
- *
3666
- * // Manual cancel
3667
- * update.cancel()
3668
- *
3669
- * // Check if pending
3670
- * if (update.isActive.value) { ... }
3671
- * ```
3672
- */
3673
- function useRaf(callback) {
3674
- const id = shallowRef();
3675
- const isActive = toRef(() => !/* @__PURE__ */ isUndefined(id.value));
3676
- function cancel() {
3677
- if (!/* @__PURE__ */ isUndefined(id.value)) {
3678
- cancelAnimationFrame(id.value);
3679
- id.value = void 0;
3680
- }
3681
- }
3682
- function request() {
3683
- if (!IN_BROWSER) return;
3684
- cancel();
3685
- id.value = requestAnimationFrame((timestamp) => {
3686
- id.value = void 0;
3687
- callback(timestamp);
3688
- });
3689
- }
3690
- onScopeDispose(cancel, true);
3691
- return Object.assign(request, {
3692
- cancel,
3693
- isActive
3694
- });
3695
- }
3696
- //#endregion
3697
4299
  //#region src/composables/usePresence/index.ts
3698
4300
  /**
3699
4301
  * @module usePresence
@@ -3876,9 +4478,8 @@ function createProgress(options = {}) {
3876
4478
  return (total.value - min) / extent * 100;
3877
4479
  });
3878
4480
  const isIndeterminate = toRef(() => {
3879
- if (_hasInitialValue) return false;
3880
4481
  const segs = segments.value;
3881
- if (segs.length === 0) return true;
4482
+ if (segs.length === 0) return !_hasInitialValue;
3882
4483
  for (const seg of segs) if ((toValue(seg.value) ?? 0) > 0) return false;
3883
4484
  return true;
3884
4485
  });
@@ -3898,16 +4499,18 @@ function createProgress(options = {}) {
3898
4499
  if (pending && segments.value.length >= pending.length) pending = null;
3899
4500
  return ticket;
3900
4501
  }
4502
+ function onboard(registrations) {
4503
+ return model.batch(() => registrations.map((registration) => register(registration)));
4504
+ }
3901
4505
  function apply(incoming, _options) {
3902
4506
  const clamped = incoming.map((v) => /* @__PURE__ */ clamp(Number(v), min, max));
3903
4507
  if (segments.value.length === 0) {
3904
4508
  pending = clamped;
3905
4509
  return;
3906
4510
  }
3907
- for (const [index, element] of clamped.entries()) {
3908
- const ticket = segments.value[index];
3909
- if (!ticket || !isRef(ticket.value) || isReadonly(ticket.value)) continue;
3910
- ticket.value.value = element;
4511
+ for (const [index, ticket] of segments.value.entries()) {
4512
+ if (!isRef(ticket.value) || isReadonly(ticket.value)) continue;
4513
+ ticket.value.value = clamped[index] ?? min;
3911
4514
  }
3912
4515
  }
3913
4516
  return {
@@ -3918,6 +4521,7 @@ function createProgress(options = {}) {
3918
4521
  isIndeterminate,
3919
4522
  fromValue,
3920
4523
  register,
4524
+ onboard,
3921
4525
  apply,
3922
4526
  min,
3923
4527
  max,
@@ -4347,7 +4951,8 @@ function createTooltip(options = {}) {
4347
4951
  isAnyOpen,
4348
4952
  shouldSkipOpenDelay,
4349
4953
  register: registry.register,
4350
- unregister: registry.unregister
4954
+ unregister: registry.unregister,
4955
+ adapter: options.adapter
4351
4956
  };
4352
4957
  }
4353
4958
  /**
@@ -4810,12 +5415,13 @@ function createNested(_options = {}) {
4810
5415
  }
4811
5416
  function unselectAll() {
4812
5417
  if (toValue(group.disabled)) return;
4813
- const first = group.selectedIds.values().next().value;
4814
5418
  group.selectedIds.clear();
4815
5419
  group.mixedIds.clear();
4816
- if (toValue(mandatoryOption) && first) {
4817
- group.selectedIds.add(first);
4818
- updateAncestors(first);
5420
+ if (!toValue(mandatoryOption)) return;
5421
+ const ticket = group.seek("first");
5422
+ if (ticket) {
5423
+ group.selectedIds.add(ticket.id);
5424
+ updateAncestors(ticket.id);
4819
5425
  }
4820
5426
  }
4821
5427
  function toggleAll() {
@@ -4889,6 +5495,7 @@ function createNested(_options = {}) {
4889
5495
  ticket.select = () => select(id);
4890
5496
  ticket.unselect = () => unselect(id);
4891
5497
  ticket.toggle = () => toggle(id);
5498
+ ticket.unregister = () => unregister(id);
4892
5499
  if (registration.active) activate(id);
4893
5500
  if (nested?.length) for (const child of nested) register({
4894
5501
  ...child,
@@ -4972,6 +5579,14 @@ function createNested(_options = {}) {
4972
5579
  rootIds.clear();
4973
5580
  group.reset();
4974
5581
  }
5582
+ function dispose() {
5583
+ children.clear();
5584
+ parents.clear();
5585
+ openedIds.clear();
5586
+ activeIds.clear();
5587
+ rootIds.clear();
5588
+ group.dispose();
5589
+ }
4975
5590
  return {
4976
5591
  ...group,
4977
5592
  children,
@@ -5020,6 +5635,7 @@ function createNested(_options = {}) {
5020
5635
  onboard,
5021
5636
  clear,
5022
5637
  reset,
5638
+ dispose,
5023
5639
  get size() {
5024
5640
  return group.size;
5025
5641
  }
@@ -5129,4 +5745,4 @@ function useRovingFocus(items, options = {}) {
5129
5745
  };
5130
5746
  }
5131
5747
  //#endregion
5132
- export { createHydrationPlugin as $, useCombobox as A, createBreadcrumbs as B, useIntersectionObserver as C, useLazy as D, useForm as E, useDelay as F, createOverflowContext as G, useBreadcrumbs as H, createStep as I, useResizeObserver as J, useOverflow as K, createStepContext as L, ComboboxAdapter as M, useVirtualFocus as N, createCombobox as O, usePopover as P, createHydrationContext as Q, useStep as R, useElementIntersection as S, createFormContext as T, useImage as U, createBreadcrumbsContext as V, createOverflow as W, createFallbackHydration as X, createObserver as Y, createHydration as Z, useRaf as _, createTooltipContext as a, useStack as at, createInput as b, useTooltip as c, createRatingContext as d, useHydration as et, useRating as f, usePresence as g, useProgress as h, useNested as i, createStackPlugin as it, ClientComboboxAdapter as j, createComboboxContext as k, createSlider as l, createProgressContext as m, createNested as n, createStack as nt, createTooltipFallback as o, toElement as ot, createProgress as p, useElementSize as q, createNestedContext as r, createStackContext as rt, createTooltipPlugin as s, useClickOutside as st, useRovingFocus as t, useToggleScope as tt, createRating as u, createNumberField as v, createForm as w, createValidation as x, createNumeric as y, useProxyModel as z };
5748
+ export { createStack as $, createSortable as A, useStep as B, createForm as C, createDataGrid as D, useRaf as E, ClientComboboxAdapter as F, useImage as G, createBreadcrumbs as H, ComboboxAdapter as I, useOverflow as J, createOverflow as K, useVirtualFocus as L, createCombobox as M, createComboboxContext as N, createDataGridContext as O, useCombobox as P, useToggleScope as Q, createStep as R, useIntersectionObserver as S, useForm as T, createBreadcrumbsContext as U, useProxyModel as V, useBreadcrumbs as W, useResizeObserver as X, useElementSize as Y, createObserver as Z, createNumberField as _, createTooltipContext as a, createValidation as b, useTooltip as c, createRatingContext as d, createStackContext as et, useRating as f, usePresence as g, useProgress as h, useNested as i, useClickOutside as it, useLazy as j, useDataGrid as k, createSlider as l, createProgressContext as m, createNested as n, useStack as nt, createTooltipFallback as o, createProgress as p, createOverflowContext as q, createNestedContext as r, toElement as rt, createTooltipPlugin as s, useRovingFocus as t, createStackPlugin as tt, createRating as u, createNumeric as v, createFormContext as w, useElementIntersection as x, createInput as y, createStepContext as z };