@vuetify/v0 1.0.5 → 1.2.0

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 +8 -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-hq9YlPOF.d.mts → adapter-CqS8xexO.d.mts} +2 -2
  6. package/dist/adapter-CrRJuxRk.mjs +21 -0
  7. package/dist/{adapter-_srNCBEi.d.mts → adapter-PDTe5nFT.d.mts} +6 -7
  8. package/dist/{adapter-lS_VpRow.mjs → adapter-TiGrumDi.mjs} +3 -1
  9. package/dist/browser/index.d.ts +17953 -15766
  10. package/dist/browser/index.js +16633 -14006
  11. package/dist/components/index.d.mts +2 -2
  12. package/dist/components/index.mjs +2 -2
  13. package/dist/{components-OCsY4P1f.mjs → components-DBhVg-t1.mjs} +4253 -2247
  14. package/dist/composables/index.d.mts +22 -20
  15. package/dist/composables/index.mjs +37 -34
  16. package/dist/{composables-xhcxXjuE.mjs → composables-ZGhVN2EJ.mjs} +47 -1066
  17. package/dist/{consola-BPGkJp_q.d.mts → consola-CdMU53rU.d.mts} +1 -1
  18. package/dist/constants/index.d.mts +1 -1
  19. package/dist/constants/index.mjs +1 -1
  20. package/dist/{createDataTable-D38H0Zbp.mjs → createDataTable-VmQEDn-7.mjs} +23 -7
  21. package/dist/{createGroup-CjUHFae5.mjs → createGroup-B_LL7xRr.mjs} +2 -2
  22. package/dist/createPlugin-Oo6t-vBw.mjs +157 -0
  23. package/dist/{createRegistry-B8VqA-QF.mjs → createRegistry-DVdvep0v.mjs} +1 -1
  24. package/dist/{createSelection-BXd5clS0.mjs → createSelection-BNdDz8oY.mjs} +1 -1
  25. package/dist/{createSingle-Bdkfht_B.mjs → createSingle-DHyIQ9Cj.mjs} +1 -1
  26. package/dist/{createTokens-vgyk_0vA.mjs → createTokens-DoISbwd7.mjs} +2 -2
  27. package/dist/data-table/adapters/client/index.d.mts +1 -1
  28. package/dist/data-table/adapters/client/index.mjs +1 -1
  29. package/dist/data-table/adapters/index.d.mts +4 -4
  30. package/dist/data-table/adapters/index.mjs +4 -4
  31. package/dist/data-table/adapters/server/index.d.mts +1 -1
  32. package/dist/data-table/adapters/server/index.mjs +1 -1
  33. package/dist/data-table/adapters/virtual/index.d.mts +1 -1
  34. package/dist/data-table/adapters/virtual/index.mjs +1 -1
  35. package/dist/data-table/index.d.mts +5 -5
  36. package/dist/data-table/index.mjs +5 -5
  37. package/dist/date/index.d.mts +1 -1
  38. package/dist/date/index.mjs +2 -2
  39. package/dist/features/adapters/flagsmith/index.d.mts +1 -1
  40. package/dist/features/adapters/flagsmith/index.mjs +1 -1
  41. package/dist/features/adapters/launchdarkly/index.d.mts +1 -1
  42. package/dist/features/adapters/launchdarkly/index.mjs +1 -1
  43. package/dist/features/adapters/posthog/index.d.mts +1 -1
  44. package/dist/features/adapters/posthog/index.mjs +2 -2
  45. package/dist/features/index.d.mts +2 -2
  46. package/dist/features/index.mjs +2 -2
  47. package/dist/{flagsmith-DA2GCyGv.d.mts → flagsmith-DcIDrI7_.d.mts} +1 -1
  48. package/dist/{globals-B7ejLnrz.mjs → globals-DaoKtIGF.mjs} +1 -1
  49. package/dist/{index-DY81ptHb.d.mts → index-Cm6CbqI6.d.mts} +7494 -5834
  50. package/dist/{index-CrAgM2EJ.d.mts → index-Cx0cWGlx.d.mts} +493 -132
  51. package/dist/{index-QnpcDsV7.d.mts → index-D0ub61GV.d.mts} +2 -2
  52. package/dist/{index-RGiSdjYt.d.mts → index-DSPkZ0ql.d.mts} +2 -2
  53. package/dist/{index-DCtHbY0a.d.mts → index-Di9e8sOm.d.mts} +24 -19
  54. package/dist/{index-DF0tMI2_.d.mts → index-DjRE4lLl.d.mts} +108 -2
  55. package/dist/index.d.mts +25 -24
  56. package/dist/index.mjs +40 -37
  57. package/dist/json/attributes.json +488 -0
  58. package/dist/json/importMap.json +92 -0
  59. package/dist/json/tags.json +234 -0
  60. package/dist/json/web-types.json +1540 -113
  61. package/dist/{launchdarkly-Bp8p9PMD.d.mts → launchdarkly-CUzunYol.d.mts} +1 -1
  62. package/dist/locale/adapters/index.d.mts +2 -2
  63. package/dist/locale/adapters/index.mjs +2 -2
  64. package/dist/locale/adapters/v0/index.d.mts +1 -1
  65. package/dist/locale/adapters/v0/index.mjs +1 -1
  66. package/dist/locale/adapters/vue-i18n/index.d.mts +1 -1
  67. package/dist/locale/adapters/vue-i18n/index.mjs +1 -1
  68. package/dist/locale/index.d.mts +3 -3
  69. package/dist/locale/index.mjs +3 -3
  70. package/dist/locale/messages/en/index.d.mts +5 -0
  71. package/dist/locale/messages/en/index.mjs +6 -1
  72. package/dist/logger/adapters/consola/index.d.mts +1 -1
  73. package/dist/logger/adapters/index.d.mts +4 -4
  74. package/dist/logger/adapters/index.mjs +1 -1
  75. package/dist/logger/adapters/pino/index.d.mts +1 -1
  76. package/dist/logger/adapters/v0/index.d.mts +1 -1
  77. package/dist/logger/adapters/v0/index.mjs +1 -1
  78. package/dist/logger/index.d.mts +5 -5
  79. package/dist/logger/index.mjs +2 -2
  80. package/dist/notifications/index.d.mts +1 -1
  81. package/dist/notifications/index.mjs +2 -2
  82. package/dist/palettes/ant/index.d.mts +1 -1
  83. package/dist/palettes/index.d.mts +3 -3
  84. package/dist/palettes/material/index.d.mts +1 -1
  85. package/dist/palettes/md1/index.d.mts +1 -1
  86. package/dist/palettes/md2/index.d.mts +1 -1
  87. package/dist/palettes/radix/index.d.mts +1 -1
  88. package/dist/palettes/tailwind/index.d.mts +1 -1
  89. package/dist/permissions/adapters/index.d.mts +1 -1
  90. package/dist/permissions/adapters/index.mjs +1 -1
  91. package/dist/permissions/adapters/v0/index.d.mts +1 -1
  92. package/dist/permissions/adapters/v0/index.mjs +1 -1
  93. package/dist/permissions/index.d.mts +1 -1
  94. package/dist/permissions/index.mjs +2 -2
  95. package/dist/{pino-B6BI1AOK.d.mts → pino-DjeWBFnj.d.mts} +1 -1
  96. package/dist/popover/adapters/floating-ui/index.d.mts +25 -0
  97. package/dist/popover/adapters/floating-ui/index.mjs +98 -0
  98. package/dist/popover/index.d.mts +3 -0
  99. package/dist/popover/index.mjs +3 -0
  100. package/dist/{posthog-sFqk0bGy.d.mts → posthog-CJAYssdr.d.mts} +1 -1
  101. package/dist/rules/index.d.mts +1 -1
  102. package/dist/rules/index.mjs +1 -1
  103. package/dist/{server-DbtTGb67.d.mts → server-5vbJ7GGs.d.mts} +2 -2
  104. package/dist/{server-D5BJBjB0.mjs → server-m7iD1vOr.mjs} +1 -2
  105. package/dist/storage/adapters/index.d.mts +2 -2
  106. package/dist/storage/adapters/index.mjs +1 -1
  107. package/dist/storage/adapters/memory/index.d.mts +1 -1
  108. package/dist/storage/adapters/memory/index.mjs +1 -1
  109. package/dist/storage/index.d.mts +3 -3
  110. package/dist/storage/index.mjs +2 -2
  111. package/dist/theme/adapters/index.d.mts +1 -1
  112. package/dist/theme/adapters/index.mjs +3 -3
  113. package/dist/theme/adapters/unhead/index.d.mts +1 -1
  114. package/dist/theme/adapters/unhead/index.mjs +1 -1
  115. package/dist/theme/adapters/v0/index.d.mts +1 -1
  116. package/dist/theme/adapters/v0/index.mjs +1 -1
  117. package/dist/theme/index.d.mts +2 -2
  118. package/dist/theme/index.mjs +4 -4
  119. package/dist/types/index.d.mts +1 -1
  120. package/dist/{unhead-DxiB3P5p.mjs → unhead-C8zbWr45.mjs} +2 -2
  121. package/dist/{useEventListener-BjWJPfYS.mjs → useEventListener-2eAMwUdw.mjs} +2 -2
  122. package/dist/useFeatures-DLafCOWt.mjs +221 -0
  123. package/dist/{useLocale-B2BAEieU.mjs → useLocale-K_45ulPt.mjs} +4 -4
  124. package/dist/{useLogger-CXKIZhks.mjs → useLogger-YyWuYvrH.mjs} +5 -159
  125. package/dist/{useNotifications-Czgbh8Ns.mjs → useNotifications-Kh_KvM7j.mjs} +57 -154
  126. package/dist/{usePermissions-BkndJNpk.mjs → usePermissions-BCGwsOES.mjs} +4 -4
  127. package/dist/usePopover-BTo0AGIQ.mjs +420 -0
  128. package/dist/{useRovingFocus-Cn96TXRw.mjs → useRovingFocus-CkRnVmJ1.mjs} +1122 -531
  129. package/dist/{useRules-NzJChxfk.mjs → useRules-BuE5ffOJ.mjs} +3 -2
  130. package/dist/{useStorage-D6xihSHv.mjs → useStorage-BT8-mjVs.mjs} +5 -4
  131. package/dist/useTheme-DkK6tPqY.mjs +445 -0
  132. package/dist/useTimer-CGVXk397.mjs +151 -0
  133. package/dist/utilities/index.d.mts +2 -2
  134. package/dist/utilities/index.mjs +181 -2
  135. package/dist/{v0-BFMaRqAx.mjs → v0-B_53w7Fu.mjs} +2 -2
  136. package/dist/{v0-BnUwMaOv.d.mts → v0-CDW1Ktk-.d.mts} +1 -1
  137. package/dist/{v0-gU93DxmF.mjs → v0-D0Exc2bO.mjs} +2 -2
  138. package/dist/{v0-rSxMW8FJ.d.mts → v0-DfFK-p4X.d.mts} +1 -1
  139. package/dist/{v0-DotXXGXU.d.mts → v0-GI9U-rPA.d.mts} +2 -2
  140. package/dist/{v0-eZcJPyii.mjs → v0-SuxTihEe.mjs} +1 -1
  141. package/dist/{v0-A4GLojAr.mjs → v0-yZ2ZUtVF.mjs} +1 -2
  142. package/dist/{virtual-DFvOoeG6.mjs → virtual-Bbu26O_h.mjs} +1 -2
  143. package/dist/{virtual-C-NsLue0.d.mts → virtual-JIdFLpTQ.d.mts} +2 -2
  144. package/package.json +8 -1
  145. package/dist/adapter-CVoWg0sw.mjs +0 -99
  146. package/dist/useFeatures-DcgU66KC.mjs +0 -124
  147. package/dist/useTheme-BuXEQdPz.mjs +0 -162
  148. /package/dist/{adapter-CTsckKAR.mjs → adapter-8UADsA3-.mjs} +0 -0
  149. /package/dist/{adapter-BCtceV3b.mjs → adapter-BuSfpxur.mjs} +0 -0
  150. /package/dist/{adapter-Bc0yPSfo.d.mts → adapter-D5nT3bLw.d.mts} +0 -0
  151. /package/dist/{adapter-bwZo7b5p.mjs → adapter-D8zizQVP.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,17 +1,16 @@
1
- import { i as SUPPORTS_MUTATION_OBSERVER, r as SUPPORTS_MATCH_MEDIA, t as IN_BROWSER } from "./globals-B7ejLnrz.mjs";
2
- import { V0Error, clamp, instanceExists, isArray, isBoolean, isElement, isFunction, isNaN, isNull, isNullOrUndefined, isNumber, isString, isThenable, isUndefined, mergeDeep, 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 { a as createPlugin, i as useLogger, o as createPluginContext } from "./useLogger-CXKIZhks.mjs";
5
- import { t as createRegistry } from "./createRegistry-B8VqA-QF.mjs";
6
- import { i as createModel } from "./createSelection-BXd5clS0.mjs";
7
- import { a as useLocale } from "./useLocale-B2BAEieU.mjs";
8
- import { t as toArray } from "./toArray-C89ZaEuF.mjs";
9
- import { n as useEventListener, r as useWindowEventListener } from "./useEventListener-BjWJPfYS.mjs";
10
- import { J as useResizeObserver, M as ComboboxAdapter, Y as createObserver, b as createInput, et as useHydration, tt as useToggleScope } from "./useRovingFocus-Cn96TXRw.mjs";
11
- import { i as useProxyRegistry, t as createGroup } from "./createGroup-CjUHFae5.mjs";
12
- import { a as extractLeaves, t as createDataTable } from "./createDataTable-D38H0Zbp.mjs";
13
- import { n as deriveWeekInfo } from "./adapter-BCtceV3b.mjs";
14
- import { computed, effectScope, isRef, onScopeDispose, onWatcherCleanup, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRef, toValue, unref, watch, watchEffect } from "vue";
1
+ import { i as SUPPORTS_MUTATION_OBSERVER, r as SUPPORTS_MATCH_MEDIA, t as IN_BROWSER } from "./globals-DaoKtIGF.mjs";
2
+ import { V0Error, clamp, findMatchRanges, getActiveElement, instanceExists, isArray, isBoolean, isElement, isFunction, isNaN, isNull, isNullOrUndefined, isNumber, isString, isThenable, isUndefined, mergeDeep, useId as useId$1 } from "./utilities/index.mjs";
3
+ import { i as useContext, 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-YyWuYvrH.mjs";
6
+ import { t as createRegistry } from "./createRegistry-DVdvep0v.mjs";
7
+ import { a as useLocale } from "./useLocale-K_45ulPt.mjs";
8
+ import { t as toArray } from "./toArray-MY9Kb1Qy.mjs";
9
+ import { n as useEventListener, r as useWindowEventListener } from "./useEventListener-2eAMwUdw.mjs";
10
+ import { A as createSortable, I as ComboboxAdapter, X as useResizeObserver, Z as createObserver, y as createInput } from "./useRovingFocus-CkRnVmJ1.mjs";
11
+ import { c as usePrefersReducedMotion, p as useHydration } from "./useTheme-DkK6tPqY.mjs";
12
+ import { n as deriveWeekInfo } from "./adapter-BuSfpxur.mjs";
13
+ import { computed, effectScope, hasInjectionContext, isRef, onScopeDispose, onWatcherCleanup, reactive, readonly, ref, shallowReadonly, shallowRef, toRef, toValue, unref, watch, watchEffect } from "vue";
15
14
  //#region src/composables/createCombobox/adapters/server.ts
16
15
  /**
17
16
  * @module createCombobox/adapters/server
@@ -37,897 +36,6 @@ var ServerComboboxAdapter = class extends ComboboxAdapter {
37
36
  }
38
37
  };
39
38
  //#endregion
40
- //#region src/composables/createSortable/index.ts
41
- /**
42
- * @module createSortable
43
- *
44
- * @see https://0.vuetifyjs.com/composables/data/create-sortable
45
- *
46
- * @remarks
47
- * Headless ordered-list primitive. Extends `createModel` with mutation primitives
48
- * (`swap`, `reorder`) and an enriched `move:ticket` event on the registry event
49
- * bus. Honors `disabled` as a real mutation gate at both root and per-ticket scope.
50
- *
51
- * Pure logical composable — no DnD, no DOM, no keyboard. Drag-and-drop integration
52
- * composes with `useDragDrop`; keyboard reorder composes with `useVirtualFocus`.
53
- *
54
- * @example
55
- * ```ts
56
- * import { createSortable } from '@vuetify/v0'
57
- * import type { SortableTicketInput } from '@vuetify/v0'
58
- *
59
- * interface TaskTicket extends SortableTicketInput {
60
- * value: { id: number; label: string }
61
- * }
62
- *
63
- * const sortable = createSortable<TaskTicket>()
64
- * const a = sortable.register({ value: { id: 1, label: 'A' } })
65
- * const b = sortable.register({ value: { id: 2, label: 'B' } })
66
- *
67
- * sortable.move(a.id, 1)
68
- * sortable.on('move:ticket', ({ ticket, from, to }) => {
69
- * console.log(`${ticket.value.label} moved ${from} → ${to}`)
70
- * })
71
- * ```
72
- */
73
- /**
74
- * Create an ordered-list state primitive.
75
- *
76
- * @param options Sortable options.
77
- * @returns A {@link SortableContext} that extends {@link ModelContext}.
78
- *
79
- * @example
80
- * ```ts
81
- * const sortable = createSortable<Todo>()
82
- * sortable.onboard(todos.value.map(value => ({ value })))
83
- * ```
84
- */
85
- function createSortable(_options = {}) {
86
- const { disabled, ...options } = _options;
87
- const model = createModel({
88
- ...options,
89
- events: true,
90
- disabled
91
- });
92
- const logger = useLogger();
93
- function move(id, toIndex) {
94
- if (toValue(disabled)) return void 0;
95
- const ticket = model.get(id);
96
- if (!ticket) return void 0;
97
- if (toValue(ticket.disabled)) return void 0;
98
- const from = ticket.index;
99
- const result = model.move(id, toIndex);
100
- if (result && result.index !== from) model.emit("move:ticket", {
101
- ticket: result,
102
- from,
103
- to: result.index
104
- });
105
- return result;
106
- }
107
- function swap(a, b) {
108
- if (toValue(disabled)) return;
109
- if (a === b) return;
110
- const ta = model.get(a);
111
- const tb = model.get(b);
112
- if (!ta || !tb) return;
113
- if (toValue(ta.disabled) || toValue(tb.disabled)) return;
114
- const indexA = ta.index;
115
- const indexB = tb.index;
116
- model.batch(() => {
117
- const ra = model.move(a, indexB);
118
- if (ra && ra.index !== indexA) model.emit("move:ticket", {
119
- ticket: ra,
120
- from: indexA,
121
- to: ra.index
122
- });
123
- const rb = model.move(b, indexA);
124
- if (rb && rb.index !== indexB) model.emit("move:ticket", {
125
- ticket: rb,
126
- from: indexB,
127
- to: rb.index
128
- });
129
- });
130
- }
131
- function reorder(ids) {
132
- if (toValue(disabled)) return;
133
- const currentSize = model.size;
134
- if (ids.length !== currentSize) {
135
- logger.warn(`Reorder expected ${currentSize} ids, got ${ids.length}.`);
136
- return;
137
- }
138
- const known = new Set(model.keys());
139
- const seen = /* @__PURE__ */ new Set();
140
- for (const id of ids) {
141
- if (!known.has(id)) {
142
- logger.warn(`Reorder contains unknown id "${String(id)}".`);
143
- return;
144
- }
145
- if (seen.has(id)) {
146
- logger.warn(`Reorder contains duplicate id "${String(id)}".`);
147
- return;
148
- }
149
- seen.add(id);
150
- }
151
- const froms = /* @__PURE__ */ new Map();
152
- for (const id of ids) {
153
- const ticket = model.get(id);
154
- if (ticket) froms.set(id, ticket.index);
155
- }
156
- model.batch(() => {
157
- model.reorder(ids);
158
- for (const [index, id] of ids.entries()) {
159
- const from = froms.get(id);
160
- if (from === index) continue;
161
- const ticket = model.get(id);
162
- if (ticket) model.emit("move:ticket", {
163
- ticket,
164
- from,
165
- to: index
166
- });
167
- }
168
- });
169
- }
170
- return {
171
- ...model,
172
- move,
173
- swap,
174
- reorder,
175
- get size() {
176
- return model.size;
177
- }
178
- };
179
- }
180
- //#endregion
181
- //#region src/composables/createDataGrid/editing.ts
182
- /**
183
- * @module createDataGrid/editing
184
- *
185
- * @remarks
186
- * Cell editing state management. Tracks active cell, validation errors,
187
- * and dirty (staged but uncommitted) edits. Does not mutate source data —
188
- * commit fires a callback for the consumer to handle.
189
- *
190
- * When a `registry` is provided, editing state for rows that get
191
- * unregistered (or wiped via `clear`) is pruned automatically so consumers
192
- * can never observe `active` pointing at a phantom row or stale entries
193
- * lingering in `dirty`.
194
- *
195
- * @internal Consumed only by `createDataGrid`. This is a fully decoupled 2D
196
- * cell-edit primitive — it imports nothing from `createDataGrid` /
197
- * `createDataTable` (only `#v0/utilities`, `#v0/types`, and Vue), so it is a
198
- * latent composable. It is parameterized over a row type `T` (defaulting to
199
- * `unknown`), but a type parameter is not an import — the primitive stays
200
- * fully decoupled from the grid's concrete ticket types and deliberately
201
- * row-agnostic: `T` is intentionally unconstrained, so do not narrow it to
202
- * the grid's `Record<string, unknown>` when promoting. Promote it to a
203
- * standalone `createCellEditing/`
204
- * composable the moment a second consumer appears (e.g. an editable
205
- * `createDataTable`). See `.claude/rules/composables.md` §"Sub-modules:
206
- * inline, private sibling, or promote".
207
- */
208
- /**
209
- * Creates cell editing state for a data grid.
210
- *
211
- * @param options Cell editing configuration including columns and commit callback
212
- * @returns Cell editing state and controls
213
- *
214
- * @example
215
- * ```ts
216
- * const editing = createCellEditing({
217
- * columns: [{ id: 'name', editable: true }],
218
- * registry: table,
219
- * onEdit (row, column, value) { ... },
220
- * })
221
- *
222
- * editing.edit(1, 'name')
223
- * editing.commit('Alice')
224
- * ```
225
- */
226
- function createCellEditing(options) {
227
- const { columns, onEdit, lookup, registry } = options;
228
- function resolveColumn(column) {
229
- for (const col of toValue(columns)) if (col.id === column) return col;
230
- }
231
- const active = shallowRef(null);
232
- const error = shallowRef(null);
233
- const dirty = shallowReactive(/* @__PURE__ */ new Map());
234
- function edit(row, column) {
235
- const col = resolveColumn(column);
236
- if (!col) return;
237
- if (/* @__PURE__ */ isFunction(col.editable)) {
238
- const item = lookup?.(row);
239
- if (/* @__PURE__ */ isUndefined(item) || !col.editable(item)) return;
240
- } else if (col.editable !== true) return;
241
- error.value = null;
242
- active.value = {
243
- row,
244
- column
245
- };
246
- }
247
- function commit(value) {
248
- const cell = active.value;
249
- if (!cell) return;
250
- const col = resolveColumn(cell.column);
251
- if (col?.validate) {
252
- const result = col.validate(value, lookup?.(cell.row));
253
- if (result !== true && /* @__PURE__ */ isString(result) && result.length > 0) {
254
- error.value = result;
255
- return;
256
- }
257
- }
258
- const entry = dirty.get(cell.row);
259
- if (entry) {
260
- entry.delete(cell.column);
261
- if (entry.size === 0) dirty.delete(cell.row);
262
- }
263
- error.value = null;
264
- active.value = null;
265
- onEdit?.(cell.row, cell.column, value);
266
- }
267
- function cancel() {
268
- const cell = active.value;
269
- if (cell) {
270
- const entry = dirty.get(cell.row);
271
- if (entry) {
272
- entry.delete(cell.column);
273
- if (entry.size === 0) dirty.delete(cell.row);
274
- }
275
- }
276
- error.value = null;
277
- active.value = null;
278
- }
279
- function onUnregister(data) {
280
- const ticket = data;
281
- if (active.value?.row === ticket.id) {
282
- active.value = null;
283
- error.value = null;
284
- }
285
- dirty.delete(ticket.id);
286
- }
287
- function onClear() {
288
- active.value = null;
289
- error.value = null;
290
- dirty.clear();
291
- }
292
- if (registry) {
293
- registry.on("unregister:ticket", onUnregister);
294
- registry.on("clear:registry", onClear);
295
- onScopeDispose(() => {
296
- registry.off("unregister:ticket", onUnregister);
297
- registry.off("clear:registry", onClear);
298
- }, true);
299
- }
300
- return {
301
- active,
302
- edit,
303
- commit,
304
- cancel,
305
- error,
306
- dirty
307
- };
308
- }
309
- //#endregion
310
- //#region src/composables/createDataGrid/layout.ts
311
- /**
312
- * @module createDataGrid/layout
313
- *
314
- * @remarks
315
- * Manages column layout state for data grids: sizing (percentages 0-100),
316
- * pinning (left/right/scrollable regions), delta-based resizing compatible
317
- * with the Splitter two-panel model, column reordering, and visibility.
318
- *
319
- * Column existence, display order, AND grid layout config (size, pin,
320
- * min/max, resizable, reorderable) all live on the table's columns registry
321
- * (passed in as the only argument). `createRegistry` preserves the extra
322
- * grid fields on each ticket, so layout reads its config straight off the
323
- * registered ticket — there is no separate defs array. Columns onboarded
324
- * before OR after the layout is built are picked up identically: an initial
325
- * loop seeds the already-registered set and a `register:ticket` handler seeds
326
- * the rest. Removed columns have their pin/size/visibility state pruned via
327
- * unregister events.
328
- *
329
- * Sizing uses percentages so it is compatible with the Splitter component.
330
- * Offsets are computed per-region (left, scrollable, right) independently
331
- * and over visible columns only — hidden columns are excluded from the
332
- * render set without auto-redistribution (headless: the consumer rebalances
333
- * via `distribute()` or CSS).
334
- *
335
- * @internal Private sibling of `createDataGrid`, and intentionally NOT a
336
- * promotion candidate: it is bound to the table's `DataTableColumnTicket`
337
- * types, so it is parent-specific glue rather than a reusable primitive. See
338
- * `.claude/rules/composables.md` §"Sub-modules: inline, private sibling, or
339
- * promote".
340
- */
341
- const DEFAULT_EXTRAS = {
342
- minSize: 2,
343
- maxSize: 100,
344
- resizable: true,
345
- reorderable: true
346
- };
347
- function offsets(cols, reverse = false) {
348
- let offset = 0;
349
- const start = reverse ? cols.length - 1 : 0;
350
- const step = reverse ? -1 : 1;
351
- const end = reverse ? -1 : cols.length;
352
- for (let i = start; i !== end; i += step) {
353
- cols[i].offset = offset;
354
- offset += cols[i].size;
355
- }
356
- }
357
- /**
358
- * Creates a column layout manager for a data grid.
359
- *
360
- * Reads column existence, display order, AND grid layout config (size, pin,
361
- * min/max, resizable, reorderable) from the table's columns registry. The
362
- * grid fields ride on each ticket — `createRegistry` preserves them — so
363
- * there is no separate defs array. Visibility is layout-local view state
364
- * (not a ticket field) kept here and reconciled via register / unregister /
365
- * clear events.
366
- *
367
- * Generic over the registry's input/output ticket types so the caller's
368
- * concrete grid column ticket (`DataGridColumnTicket`) flows through. Layout
369
- * only ever reads from the registry (`values`, `keys`, `on`, `reorder`,
370
- * `move`, `lookup`) — it never registers — so the output ticket need only be
371
- * readable as a {@link GridColumnDef}.
372
- *
373
- * @param cols The table's columns registry — source of truth for which
374
- * columns exist, in what order, and their layout config
375
- * @returns Column layout state and mutation methods
376
- */
377
- function createColumnLayout(cols) {
378
- const logger = useLogger();
379
- const configs = /* @__PURE__ */ new Map();
380
- const group = createGroup({ multiple: true });
381
- const sizes = shallowReactive(/* @__PURE__ */ new Map());
382
- const hidden = shallowReactive(/* @__PURE__ */ new Set());
383
- const order = [];
384
- function record(id) {
385
- if (!order.includes(id)) order.push(id);
386
- }
387
- /** Even share over the currently-registered leaves: explicit sizes are
388
- * honored, unsized columns split the remaining percentage. */
389
- function share(id) {
390
- const leaves = /* @__PURE__ */ extractLeaves(cols.values());
391
- let used = 0;
392
- let unsized = 0;
393
- for (const leaf of leaves) {
394
- const size = configs.get(String(leaf.id))?.size;
395
- if (/* @__PURE__ */ isUndefined(size)) unsized++;
396
- else used += size;
397
- }
398
- const own = configs.get(id)?.size;
399
- if (!/* @__PURE__ */ isUndefined(own)) return own;
400
- const remainder = Math.max(0, 100 - used);
401
- return unsized > 0 ? remainder / unsized : 0;
402
- }
403
- function seedLeaf(leaf) {
404
- const id = String(leaf.id);
405
- if (!configs.has(id)) configs.set(id, {
406
- size: leaf.size,
407
- minSize: leaf.minSize ?? DEFAULT_EXTRAS.minSize,
408
- maxSize: leaf.maxSize ?? DEFAULT_EXTRAS.maxSize,
409
- resizable: leaf.resizable ?? DEFAULT_EXTRAS.resizable,
410
- reorderable: leaf.reorderable ?? DEFAULT_EXTRAS.reorderable,
411
- pinned: leaf.pinned ?? false
412
- });
413
- if (!group.has(id)) group.register({
414
- id,
415
- value: id
416
- });
417
- if (!sizes.has(id)) sizes.set(id, share(id));
418
- for (const other of /* @__PURE__ */ extractLeaves(cols.values())) {
419
- const otherId = String(other.id);
420
- if (configs.has(otherId) && /* @__PURE__ */ isUndefined(configs.get(otherId)?.size)) sizes.set(otherId, share(otherId));
421
- }
422
- const config = configs.get(id);
423
- if (config.pinned === "left") group.select(id);
424
- else if (config.pinned === "right") group.mix(id);
425
- }
426
- function dropLeaf(id) {
427
- group.unregister(id);
428
- configs.delete(id);
429
- sizes.delete(id);
430
- hidden.delete(id);
431
- }
432
- function leavesOf(ticket) {
433
- return /* @__PURE__ */ extractLeaves([ticket]);
434
- }
435
- for (const ticket of cols.values()) {
436
- record(String(ticket.id));
437
- for (const leaf of leavesOf(ticket)) seedLeaf(leaf);
438
- }
439
- cols.on("register:ticket", (ticket) => {
440
- record(String(ticket.id));
441
- for (const leaf of leavesOf(ticket)) seedLeaf(leaf);
442
- });
443
- cols.on("unregister:ticket", (ticket) => {
444
- const top = order.indexOf(String(ticket.id));
445
- if (top !== -1) order.splice(top, 1);
446
- for (const leaf of leavesOf(ticket)) dropLeaf(String(leaf.id));
447
- });
448
- cols.on("clear:registry", () => {
449
- group.clear();
450
- configs.clear();
451
- sizes.clear();
452
- hidden.clear();
453
- order.length = 0;
454
- });
455
- function position(id) {
456
- if (group.selectedIds.has(id)) return "left";
457
- if (group.mixed(id)) return "right";
458
- return false;
459
- }
460
- function resolve(includeHidden) {
461
- const resolved = [];
462
- let index = 0;
463
- for (const ticket of /* @__PURE__ */ extractLeaves(cols.values())) {
464
- const id = String(ticket.id);
465
- const visible = !hidden.has(id);
466
- if (!includeHidden && !visible) continue;
467
- const meta = configs.get(id) ?? DEFAULT_EXTRAS;
468
- resolved.push({
469
- id,
470
- index: index++,
471
- size: sizes.get(id) ?? 0,
472
- offset: 0,
473
- pinned: position(id),
474
- resizable: meta.resizable,
475
- reorderable: meta.reorderable,
476
- minSize: meta.minSize,
477
- maxSize: meta.maxSize,
478
- visible
479
- });
480
- }
481
- return resolved;
482
- }
483
- function split(resolved) {
484
- const left = [];
485
- const scrollable = [];
486
- const right = [];
487
- for (const col of resolved) if (col.pinned === "left") left.push(col);
488
- else if (col.pinned === "right") right.push(col);
489
- else scrollable.push(col);
490
- offsets(left);
491
- offsets(scrollable);
492
- offsets(right, true);
493
- return {
494
- left,
495
- scrollable,
496
- right
497
- };
498
- }
499
- const pinned = computed(() => split(resolve(false)));
500
- const columns = computed(() => {
501
- const { left, scrollable, right } = pinned.value;
502
- return [
503
- ...left,
504
- ...scrollable,
505
- ...right
506
- ];
507
- });
508
- const allColumns = computed(() => resolve(true));
509
- function pin(id, pos) {
510
- if (!group.has(id)) return;
511
- group.unselect(id);
512
- group.unmix(id);
513
- if (pos === "left") group.select(id);
514
- else if (pos === "right") group.mix(id);
515
- }
516
- function resize(id, delta) {
517
- const { left, scrollable, right } = pinned.value;
518
- const all = [
519
- ...left,
520
- ...scrollable,
521
- ...right
522
- ];
523
- const target = all.find((c) => c.id === id);
524
- if (!target || !target.resizable) return;
525
- const allIndex = all.findIndex((c) => c.id === id);
526
- if (allIndex === -1 || allIndex === all.length - 1) return;
527
- const neighbor = all[allIndex + 1];
528
- const total = target.size + neighbor.size;
529
- const lower = Math.max(target.minSize, total - neighbor.maxSize);
530
- const upper = Math.min(target.maxSize, total - neighbor.minSize);
531
- const clamped = /* @__PURE__ */ clamp(target.size + delta, lower, upper);
532
- sizes.set(id, clamped);
533
- sizes.set(neighbor.id, total - clamped);
534
- }
535
- function reorder(from, to) {
536
- if (from === to) return;
537
- const tops = [...cols.values()];
538
- const ids = [];
539
- const leafToTop = [];
540
- for (const [top, ticket] of tops.entries()) for (const leaf of /* @__PURE__ */ extractLeaves([ticket])) {
541
- ids.push(String(leaf.id));
542
- leafToTop.push(top);
543
- }
544
- const visible = ids.filter((id) => !hidden.has(id));
545
- const fromId = visible[from];
546
- const toId = visible[to];
547
- if (/* @__PURE__ */ isUndefined(fromId) || /* @__PURE__ */ isUndefined(toId)) return;
548
- const fromTop = leafToTop[ids.indexOf(fromId)];
549
- const toTop = leafToTop[ids.indexOf(toId)];
550
- if (/* @__PURE__ */ isUndefined(fromTop) || /* @__PURE__ */ isUndefined(toTop) || fromTop === toTop) return;
551
- if (tops[fromTop]?.reorderable === false) return;
552
- const id = cols.lookup(fromTop);
553
- if (/* @__PURE__ */ isUndefined(id)) return;
554
- cols.move(id, toTop);
555
- }
556
- function distribute(incoming) {
557
- const tickets = /* @__PURE__ */ extractLeaves(cols.values());
558
- if (incoming.length !== tickets.length) {
559
- logger.warn(`createDataGrid: distribute() expected ${tickets.length} sizes but received ${incoming.length}; ignoring.`);
560
- return;
561
- }
562
- const sum = incoming.reduce((acc, value) => acc + value, 0);
563
- if (sum <= 0) {
564
- logger.warn(`createDataGrid: distribute() received sizes summing to ${sum}; expected a positive total.`);
565
- return;
566
- }
567
- const metas = tickets.map((ticket) => configs.get(String(ticket.id)) ?? DEFAULT_EXTRAS);
568
- let current = incoming.map((value, i) => /* @__PURE__ */ clamp(value / sum * 100, metas[i].minSize, metas[i].maxSize));
569
- let residual = 100 - current.reduce((acc, value) => acc + value, 0);
570
- const max = tickets.length * 2;
571
- for (let pass = 0; pass < max && Math.abs(residual) >= 1e-6; pass++) {
572
- const room = current.map((value, i) => residual > 0 ? metas[i].maxSize - value : value - metas[i].minSize);
573
- const available = room.reduce((acc, value) => acc + Math.max(0, value), 0);
574
- if (available <= 0) break;
575
- current = current.map((value, i) => room[i] <= 0 ? value : value + residual * (room[i] / available));
576
- residual = 100 - current.reduce((acc, value) => acc + value, 0);
577
- }
578
- if (Math.abs(residual) >= 1e-6) logger.warn(`createDataGrid: distribute() could not reach 100 within min/max constraints (off by ${residual.toFixed(2)})`);
579
- for (const [i, ticket] of tickets.entries()) sizes.set(String(ticket.id), current[i]);
580
- }
581
- function show(id) {
582
- hidden.delete(id);
583
- }
584
- function hide(id) {
585
- hidden.add(id);
586
- }
587
- function toggle(id) {
588
- if (hidden.has(id)) hidden.delete(id);
589
- else hidden.add(id);
590
- }
591
- function reset() {
592
- for (const ticket of /* @__PURE__ */ extractLeaves(cols.values())) {
593
- const id = String(ticket.id);
594
- sizes.set(id, share(id));
595
- }
596
- cols.reorder([...order]);
597
- hidden.clear();
598
- for (const ticket of /* @__PURE__ */ extractLeaves(cols.values())) {
599
- const id = String(ticket.id);
600
- group.unselect(id);
601
- group.unmix(id);
602
- }
603
- for (const [id, config] of configs) if (config.pinned === "left") group.select(id);
604
- else if (config.pinned === "right") group.mix(id);
605
- }
606
- return {
607
- pinned,
608
- columns,
609
- all: allColumns,
610
- pin,
611
- resize,
612
- reorder,
613
- distribute,
614
- show,
615
- hide,
616
- toggle,
617
- reset
618
- };
619
- }
620
- //#endregion
621
- //#region src/composables/createDataGrid/spanning.ts
622
- /**
623
- * @module createDataGrid/spanning
624
- *
625
- * @remarks
626
- * Computes a row span map from visible items. For each cell, determines
627
- * rowSpan and whether it's hidden (covered by a span from a previous row).
628
- * Spans do not cross page boundaries. Each row is addressed by a key: either a
629
- * `key(item, index)` projection (the grid passes the registry ticket id) or,
630
- * absent that, the row's `itemKey` value. Rows whose resolved key is
631
- * `undefined` cannot be addressed in the resulting map and are skipped.
632
- *
633
- * @internal Consumed only by `createDataGrid`. Fully decoupled (items ref +
634
- * columns + key + span fn — no grid/table types), so it is a latent composable.
635
- * Promote it to a standalone `createRowSpanning/` composable on a second
636
- * consumer. See `.claude/rules/composables.md` §"Sub-modules: inline, private
637
- * sibling, or promote".
638
- */
639
- /**
640
- * Computes a row span map from visible items.
641
- *
642
- * @param options Row spanning configuration
643
- * @returns A computed map of item ID to column to SpanEntry
644
- *
645
- * @example
646
- * ```ts
647
- * const spans = createRowSpanning({
648
- * items: computed(() => grid.items.value),
649
- * columns: ['group', 'ticker', 'value'],
650
- * span: (item, column) => column === 'group' ? 3 : 1,
651
- * })
652
- *
653
- * spans.value.get(id)?.get('group') // { rowSpan: 3, hidden: false }
654
- * ```
655
- */
656
- function createRowSpanning(options) {
657
- const { items, columns, key, itemKey = "id", span } = options;
658
- return computed(() => {
659
- const result = /* @__PURE__ */ new Map();
660
- if (!span) return result;
661
- const list = items.value;
662
- const resolved = toValue(columns);
663
- const covered = Array.from({ length: resolved.length }).fill(0);
664
- for (let row = 0; row < list.length; row++) {
665
- const item = list[row];
666
- const id = key ? key(item, row) : item[itemKey];
667
- if (/* @__PURE__ */ isUndefined(id)) continue;
668
- const cells = /* @__PURE__ */ new Map();
669
- for (const [col, column] of resolved.entries()) if (covered[col] > 0) {
670
- cells.set(column, {
671
- rowSpan: 1,
672
- hidden: true
673
- });
674
- covered[col]--;
675
- } else {
676
- const raw = span(item, column);
677
- const rowSpan = Math.min(Math.max(1, /* @__PURE__ */ isNaN(raw) ? 1 : raw), list.length - row);
678
- cells.set(column, {
679
- rowSpan,
680
- hidden: false
681
- });
682
- if (rowSpan > 1) covered[col] = rowSpan - 1;
683
- }
684
- result.set(id, cells);
685
- }
686
- return result;
687
- });
688
- }
689
- //#endregion
690
- //#region src/composables/createDataGrid/index.ts
691
- /**
692
- * @module createDataGrid
693
- *
694
- * @see https://0.vuetifyjs.com/composables/data/create-data-grid
695
- *
696
- * @remarks
697
- * Main factory that wires together column layout, cell editing, row ordering,
698
- * and row spanning on top of a createDataTable pipeline. Row ordering is
699
- * provided by a createSortable instance synced to the table's row registry
700
- * via register / unregister events; the ordered ids are applied post-sort,
701
- * pre-pagination by overriding the `items` projection.
702
- *
703
- * Rows are registered through the inherited registry surface (`register`,
704
- * `onboard`, `unregister`, `clear`) — they are not passed as an `items`
705
- * option to the factory.
706
- *
707
- * Follows the trinity pattern for dependency injection.
708
- *
709
- * @example
710
- * ```ts
711
- * const grid = createDataGrid()
712
- *
713
- * grid.columns.onboard([
714
- * { id: 'name', sortable: true },
715
- * { id: 'progress', editable: true },
716
- * ])
717
- *
718
- * grid.onboard(rows.map(value => ({ id: value.id, value })))
719
- * grid.layout.pin('name', 'left')
720
- * grid.editing.edit(row.id, 'progress')
721
- * ```
722
- */
723
- /**
724
- * Creates a data grid instance with layout, editing, row ordering, and spanning
725
- * layered on top of the createDataTable pipeline.
726
- *
727
- * Rows live on the inherited registry surface — register them with
728
- * `grid.onboard(rows.map(value => ({ id: value.id, value })))` or
729
- * `grid.register({ id, value })`.
730
- *
731
- * @param options Data grid options
732
- * @returns Data grid context
733
- *
734
- * @example
735
- * ```ts
736
- * const grid = createDataGrid({ pagination: { initial: 1 } })
737
- *
738
- * grid.columns.onboard([
739
- * { id: 'name', sortable: true },
740
- * { id: 'progress', editable: true, validate: v => Number(v) >= 0 || 'must be positive' },
741
- * ])
742
- *
743
- * grid.onboard(rows.map(value => ({ id: value.id, value })))
744
- * grid.layout.pin('name', 'left')
745
- * grid.rows.move(rowId, 0)
746
- * grid.editing.edit(row.id, 'progress')
747
- * ```
748
- */
749
- function createDataGrid(_options = {}) {
750
- const { editing: editingOptions, preserveRowOrder = false, rowSpanning, ...options } = _options;
751
- const table = createDataTable(options);
752
- const sortable = createSortable();
753
- const sortableProxy = useProxyRegistry(sortable);
754
- const dirty = shallowRef(false);
755
- table.on("register:ticket", (ticket) => {
756
- sortable.register({
757
- id: ticket.id,
758
- value: ticket.id
759
- });
760
- });
761
- table.on("unregister:ticket", (ticket) => {
762
- sortable.unregister(ticket.id);
763
- });
764
- table.on("clear:registry", () => {
765
- sortable.clear();
766
- dirty.value = false;
767
- });
768
- const order = toRef(() => sortableProxy.keys);
769
- const sortedIds = computed(() => {
770
- const buckets = /* @__PURE__ */ new Map();
771
- for (const ticket of table.values()) {
772
- const value = ticket.value;
773
- const queue = buckets.get(value);
774
- if (queue) queue.push(ticket.id);
775
- else buckets.set(value, [ticket.id]);
776
- }
777
- const ids = [];
778
- for (const value of table.sortedItems.value) {
779
- const id = buckets.get(value)?.shift();
780
- if (!/* @__PURE__ */ isUndefined(id)) ids.push(id);
781
- }
782
- return ids;
783
- });
784
- function move(id, toIndex) {
785
- if (!dirty.value) {
786
- const sorted = sortedIds.value;
787
- const seen = new Set(sorted);
788
- const rest = sortable.keys().filter((key) => !seen.has(key));
789
- sortable.reorder([...sorted, ...rest]);
790
- }
791
- sortable.move(id, toIndex);
792
- dirty.value = true;
793
- }
794
- function reset() {
795
- if (!dirty.value) return;
796
- if (sortable.size > 0) sortable.reorder(table.keys());
797
- dirty.value = false;
798
- }
799
- useToggleScope(() => !toValue(preserveRowOrder), () => {
800
- watch(table.sort.columns, reset, { flush: "sync" });
801
- });
802
- const page = computed(() => {
803
- if (!dirty.value) {
804
- const start = table.pagination.pageStart.value;
805
- return {
806
- items: table.items.value,
807
- ids: table.total.value > table.sortedItems.value.length ? sortedIds.value : sortedIds.value.slice(start, start + table.items.value.length)
808
- };
809
- }
810
- const sorted = table.sortedItems.value;
811
- const ids = sortedIds.value;
812
- const byId = /* @__PURE__ */ new Map();
813
- for (let i = 0; i < sorted.length; i++) byId.set(ids[i], sorted[i]);
814
- const seen = new Set(order.value);
815
- const items = [];
816
- const ordered = [];
817
- for (const id of order.value) {
818
- const value = byId.get(id);
819
- if (!/* @__PURE__ */ isUndefined(value)) {
820
- items.push(value);
821
- ordered.push(id);
822
- }
823
- }
824
- for (const [i, element] of sorted.entries()) {
825
- const id = ids[i];
826
- if (!seen.has(id)) {
827
- items.push(element);
828
- ordered.push(id);
829
- }
830
- }
831
- if (table.total.value > sorted.length) return {
832
- items,
833
- ids: ordered
834
- };
835
- const start = table.pagination.pageStart.value;
836
- const stop = table.pagination.pageStop.value;
837
- return {
838
- items: items.slice(start, stop),
839
- ids: ordered.slice(start, stop)
840
- };
841
- });
842
- const pageOrderedItems = toRef(() => page.value.items);
843
- const layout = createColumnLayout(table.columns);
844
- function lookup(row) {
845
- return table.get(row)?.value;
846
- }
847
- const editing = createCellEditing({
848
- columns: () => table.leaves.value.filter((col) => col.editable === true || /* @__PURE__ */ isFunction(col.editable)).map((col) => ({
849
- id: String(col.id),
850
- editable: col.editable,
851
- validate: col.validate
852
- })),
853
- lookup,
854
- registry: table,
855
- onEdit: editingOptions?.onEdit ? (row, column, value) => {
856
- const item = lookup(row);
857
- if (!/* @__PURE__ */ isUndefined(item)) editingOptions.onEdit(row, column, value, item);
858
- } : void 0
859
- });
860
- const spans = createRowSpanning({
861
- items: pageOrderedItems,
862
- columns: () => table.leaves.value.map((col) => col.id),
863
- key: (_item, index) => page.value.ids[index],
864
- span(item, column) {
865
- const col = table.leaves.value.find((leaf) => String(leaf.id) === column);
866
- if (col && /* @__PURE__ */ isFunction(col.span)) return col.span(item);
867
- return rowSpanning?.(item, column) ?? 1;
868
- }
869
- });
870
- return {
871
- ...table,
872
- items: pageOrderedItems,
873
- layout,
874
- rows: {
875
- order,
876
- move,
877
- reset
878
- },
879
- editing,
880
- spans,
881
- get size() {
882
- return table.size;
883
- }
884
- };
885
- }
886
- /**
887
- * Creates a data grid context with dependency injection support.
888
- *
889
- * @param options Data grid context options including namespace
890
- * @returns A trinity tuple: [useDataGridContext, provideDataGridContext, defaultContext]
891
- *
892
- * @example
893
- * ```ts
894
- * const [useDataGrid, provideDataGrid, grid] = createDataGridContext({
895
- * namespace: 'v0:projects',
896
- * })
897
- *
898
- * grid.columns.onboard(columns)
899
- * grid.onboard(rows.map(value => ({ id: value.id, value })))
900
- * provideDataGrid()
901
- * const ctx = useDataGrid()
902
- * ```
903
- */
904
- function createDataGridContext(_options = {}) {
905
- const { namespace = "v0:data-grid", ...options } = _options;
906
- const [useDataGridContext, _provideDataGridContext] = createContext(namespace);
907
- const context = createDataGrid(options);
908
- function provideDataGridContext(_context = context, app) {
909
- return _provideDataGridContext(_context, app);
910
- }
911
- return createTrinity(useDataGridContext, provideDataGridContext, context);
912
- }
913
- /**
914
- * Returns the current data grid context from dependency injection.
915
- *
916
- * @param namespace The namespace for the data grid context. @default 'v0:data-grid'
917
- * @returns The current data grid context
918
- *
919
- * @example
920
- * ```ts
921
- * const grid = useDataGrid<Project>()
922
- *
923
- * grid.layout.pin('id', 'left')
924
- * grid.rows.reset()
925
- * ```
926
- */
927
- function useDataGrid(namespace = "v0:data-grid") {
928
- return useContext(namespace);
929
- }
930
- //#endregion
931
39
  //#region src/composables/createKanban/index.ts
932
40
  /**
933
41
  * @module createKanban
@@ -1035,6 +143,19 @@ function createKanban(_options = {}) {
1035
143
  return _columns.size;
1036
144
  }
1037
145
  };
146
+ function onColumnUnregister(column) {
147
+ column.items.dispose();
148
+ for (const t of lookup.values()) if (t.value === column.id) t.unregister();
149
+ }
150
+ function dispose() {
151
+ for (const column of _columns.values()) column.items.dispose();
152
+ lookup.dispose();
153
+ bus.dispose();
154
+ _columns.dispose();
155
+ columns.on("unregister:ticket", onColumnUnregister);
156
+ }
157
+ columns.dispose = dispose;
158
+ columns.on("unregister:ticket", onColumnUnregister);
1038
159
  function isAccepted(accept, ticket, from, toIndex) {
1039
160
  if (/* @__PURE__ */ isUndefined(accept)) return true;
1040
161
  try {
@@ -1049,10 +170,6 @@ function createKanban(_options = {}) {
1049
170
  return false;
1050
171
  }
1051
172
  }
1052
- columns.on("unregister:ticket", (column) => {
1053
- column.items.dispose();
1054
- for (const t of lookup.values()) if (t.value === column.id) t.unregister();
1055
- });
1056
173
  function transfer(id, toColumnId, toIndex) {
1057
174
  const fromColumnId = lookup.get(id)?.value;
1058
175
  if (/* @__PURE__ */ isUndefined(fromColumnId)) {
@@ -1107,7 +224,8 @@ function createKanban(_options = {}) {
1107
224
  columns,
1108
225
  transfer,
1109
226
  on,
1110
- off
227
+ off,
228
+ dispose
1111
229
  };
1112
230
  }
1113
231
  //#endregion
@@ -1877,24 +995,9 @@ function chunk(text, ranges) {
1877
995
  });
1878
996
  return chunks;
1879
997
  }
1880
- function find(text, query, matchAll, ignoreCase) {
1881
- const terms = (/* @__PURE__ */ toArray(query)).filter(Boolean);
1882
- const haystack = ignoreCase ? text.toLocaleLowerCase() : text;
998
+ function find(text, query, options) {
1883
999
  const spans = [];
1884
- for (const term of terms) {
1885
- const needle = ignoreCase ? term.toLocaleLowerCase() : term;
1886
- let index = haystack.indexOf(needle);
1887
- if (index !== -1) {
1888
- spans.push([index, index + term.length]);
1889
- if (matchAll) {
1890
- index = haystack.indexOf(needle, index + term.length);
1891
- while (index !== -1) {
1892
- spans.push([index, index + term.length]);
1893
- index = haystack.indexOf(needle, index + term.length);
1894
- }
1895
- }
1896
- }
1897
- }
1000
+ for (const term of (/* @__PURE__ */ toArray(query)).filter(Boolean)) spans.push(.../* @__PURE__ */ findMatchRanges(text, term, options));
1898
1001
  return merge(spans);
1899
1002
  }
1900
1003
  /**
@@ -1907,7 +1010,7 @@ function find(text, query, matchAll, ignoreCase) {
1907
1010
  *
1908
1011
  * @param text The source string to split.
1909
1012
  * @param query One or more search terms. Empty strings are ignored. Case sensitivity controlled by `options.ignoreCase`.
1910
- * @param options Optional `matches`, `matchAll`, `ignoreCase`.
1013
+ * @param options Optional `matches`, `matchAll`, `ignoreCase`, `ignoreAccents`.
1911
1014
  * @returns A `HighlightChunk[]` array.
1912
1015
  *
1913
1016
  * @see https://0.vuetifyjs.com/composables/transformers/to-highlight
@@ -1931,9 +1034,14 @@ function toHighlight(text, query, options = {}) {
1931
1034
  const _matches = toValue(options.matches);
1932
1035
  const matchAll = toValue(options.matchAll) ?? false;
1933
1036
  const ignoreCase = toValue(options.ignoreCase) ?? false;
1037
+ const ignoreAccents = toValue(options.ignoreAccents) ?? false;
1934
1038
  if (_matches?.length) return chunk(_text, merge(_matches));
1935
1039
  if (_query) {
1936
- const ranges = find(_text, _query, matchAll, ignoreCase);
1040
+ const ranges = find(_text, _query, {
1041
+ matchAll,
1042
+ ignoreCase,
1043
+ ignoreAccents
1044
+ });
1937
1045
  return ranges.length > 0 ? chunk(_text, ranges) : [{
1938
1046
  text: _text,
1939
1047
  match: false
@@ -2414,7 +1522,7 @@ function createDate(options) {
2414
1522
  const { locales = defaultLocales, adapter, locale: initialLocale, firstDayOfWeek: explicitFirstDay } = options;
2415
1523
  let selectedId;
2416
1524
  try {
2417
- if (/* @__PURE__ */ instanceExists()) selectedId = useLocale().selectedId;
1525
+ if (hasInjectionContext()) selectedId = useLocale().selectedId;
2418
1526
  } catch {}
2419
1527
  const locale = computed(() => {
2420
1528
  const selected = selectedId?.value;
@@ -2430,12 +1538,12 @@ function createDate(options) {
2430
1538
  const loc = locale.value;
2431
1539
  return loc ? (/* @__PURE__ */ deriveWeekInfo(loc)).firstDay : 0;
2432
1540
  });
2433
- if (/* @__PURE__ */ instanceExists()) onScopeDispose(watchEffect(() => {
1541
+ if (hasInjectionContext()) onScopeDispose(watchEffect(() => {
2434
1542
  const loc = locale.value;
2435
1543
  if (loc && adapter.locale !== loc) adapter.locale = loc;
2436
1544
  const fdow = firstDayOfWeek.value;
2437
1545
  if (adapter.firstDayOfWeek !== fdow) adapter.firstDayOfWeek = fdow;
2438
- }));
1546
+ }), true);
2439
1547
  else {
2440
1548
  const loc = locale.value;
2441
1549
  if (loc && adapter.locale !== loc) adapter.locale = loc;
@@ -2498,13 +1606,13 @@ function createDateContext(_options) {
2498
1606
  */
2499
1607
  function createDatePlugin(_options) {
2500
1608
  const { namespace = "v0:date", ...options } = _options;
2501
- const [, provideDateContext, context] = createDateContext({
2502
- namespace,
2503
- ...options
2504
- });
2505
1609
  return createPlugin({
2506
1610
  namespace,
2507
1611
  provide: (app) => {
1612
+ const [, provideDateContext, context] = createDateContext({
1613
+ namespace,
1614
+ ...options
1615
+ });
2508
1616
  provideDateContext(context, app);
2509
1617
  }
2510
1618
  });
@@ -2857,7 +1965,7 @@ var KeyboardAdapter = class extends DragDropAdapter {
2857
1965
  }
2858
1966
  if (!IN_BROWSER) return;
2859
1967
  const onKeydown = (event) => {
2860
- const focused = document.activeElement;
1968
+ const focused = /* @__PURE__ */ getActiveElement();
2861
1969
  if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) return;
2862
1970
  if (isEditable(focused)) return;
2863
1971
  const ticket = this.locate(focused, context);
@@ -3576,7 +2684,7 @@ function useHotkey(keys, callback, options = {}, _platform) {
3576
2684
  /* v8 ignore next -- IN_BROWSER always true in happy-dom test env */
3577
2685
  if (!IN_BROWSER) return false;
3578
2686
  if (toValue(inputs)) return false;
3579
- const activeElement = document.activeElement;
2687
+ const activeElement = /* @__PURE__ */ getActiveElement();
3580
2688
  /* v8 ignore next -- defensive: document.activeElement is always set in happy-dom */
3581
2689
  if (!activeElement) return false;
3582
2690
  const role = activeElement.getAttribute("role");
@@ -3706,133 +2814,6 @@ function matchesKeyGroup(e, group, platformIsMac) {
3706
2814
  return modifiersMatch && e.key.toLowerCase() === actualKey.toLowerCase();
3707
2815
  }
3708
2816
  //#endregion
3709
- //#region src/composables/useMediaQuery/index.ts
3710
- /**
3711
- * @module useMediaQuery
3712
- *
3713
- * @see https://0.vuetifyjs.com/composables/system/use-media-query
3714
- *
3715
- * @remarks
3716
- * Reactive media query composable with automatic cleanup.
3717
- *
3718
- * Key features:
3719
- * - Synchronous matchMedia read on client mount (prevents FOUC)
3720
- * - Window matchMedia integration
3721
- * - Reactive query string support
3722
- * - SSR-safe (returns false on server)
3723
- * - Hydration-aware (defers client updates until hydrated)
3724
- * - Automatic listener cleanup on scope disposal
3725
- * - Supports both static and dynamic queries
3726
- *
3727
- * Perfect for responsive conditionals beyond breakpoint detection.
3728
- *
3729
- * @example
3730
- * ```ts
3731
- * import { useMediaQuery } from '@vuetify/v0'
3732
- *
3733
- * const { matches } = useMediaQuery('(prefers-color-scheme: dark)')
3734
- * console.log(matches.value) // true/false
3735
- * ```
3736
- */
3737
- /**
3738
- * Reactive media query matching.
3739
- *
3740
- * @param query CSS media query string (reactive).
3741
- * @returns The media query context.
3742
- *
3743
- * @see https://0.vuetifyjs.com/composables/system/use-media-query
3744
- *
3745
- * @example
3746
- * ```ts
3747
- * // Static query
3748
- * const { matches } = useMediaQuery('(prefers-color-scheme: dark)')
3749
- *
3750
- * // Dynamic query
3751
- * const minWidth = ref(768)
3752
- * const { matches } = useMediaQuery(() => `(min-width: ${minWidth.value}px)`)
3753
- *
3754
- * // Manual cleanup
3755
- * const { matches, stop } = useMediaQuery('(hover: hover)')
3756
- * stop() // Remove listener early
3757
- * ```
3758
- */
3759
- function useMediaQuery(query) {
3760
- const resolvedQuery = toRef(() => toValue(query));
3761
- const initialQuery = toValue(query);
3762
- const initialMql = IN_BROWSER && SUPPORTS_MATCH_MEDIA ? window.matchMedia(initialQuery) : null;
3763
- const matches = shallowRef(initialMql?.matches ?? false);
3764
- const mediaQueryList = shallowRef(initialMql);
3765
- const hydration = useHydration();
3766
- let cleanup = null;
3767
- function listen() {
3768
- if (!IN_BROWSER || !SUPPORTS_MATCH_MEDIA) return;
3769
- cleanup?.();
3770
- cleanup = null;
3771
- const mql = window.matchMedia(resolvedQuery.value);
3772
- mediaQueryList.value = mql;
3773
- matches.value = mql.matches;
3774
- function handler(e) {
3775
- matches.value = e.matches;
3776
- }
3777
- mql.addEventListener("change", handler);
3778
- cleanup = () => mql.removeEventListener("change", handler);
3779
- }
3780
- const stopWatch = watch([resolvedQuery, () => hydration.isHydrated.value], ([_, hydrated]) => {
3781
- if (hydrated) listen();
3782
- }, { immediate: true });
3783
- function stop() {
3784
- stopWatch();
3785
- cleanup?.();
3786
- cleanup = null;
3787
- }
3788
- onScopeDispose(stop, true);
3789
- return {
3790
- matches: shallowReadonly(matches),
3791
- query: resolvedQuery,
3792
- mediaQueryList: shallowReadonly(mediaQueryList),
3793
- stop
3794
- };
3795
- }
3796
- /**
3797
- * Check if the user prefers dark color scheme.
3798
- *
3799
- * @returns The media query context.
3800
- *
3801
- * @example
3802
- * ```ts
3803
- * const { matches: prefersDark } = usePrefersDark()
3804
- * ```
3805
- */
3806
- function usePrefersDark() {
3807
- return useMediaQuery("(prefers-color-scheme: dark)");
3808
- }
3809
- /**
3810
- * Check if the user prefers reduced motion.
3811
- *
3812
- * @returns The media query context.
3813
- *
3814
- * @example
3815
- * ```ts
3816
- * const { matches: prefersReducedMotion } = usePrefersReducedMotion()
3817
- * ```
3818
- */
3819
- function usePrefersReducedMotion() {
3820
- return useMediaQuery("(prefers-reduced-motion: reduce)");
3821
- }
3822
- /**
3823
- * Check if the user prefers more contrast.
3824
- *
3825
- * @returns The media query context.
3826
- *
3827
- * @example
3828
- * ```ts
3829
- * const { matches: prefersContrast } = usePrefersContrast()
3830
- * ```
3831
- */
3832
- function usePrefersContrast() {
3833
- return useMediaQuery("(prefers-contrast: more)");
3834
- }
3835
- //#endregion
3836
2817
  //#region src/composables/useReducedMotion/adapters/adapter.ts
3837
2818
  var ReducedMotionAdapter = class {
3838
2819
  /**
@@ -4066,4 +3047,4 @@ const [createRtlContext, createRtlPlugin, useRtl] = createPluginContext("v0:rtl"
4066
3047
  }
4067
3048
  });
4068
3049
  //#endregion
4069
- export { createBreakpointsPlugin as A, createOtp as B, useMutationObserver as C, useDate as D, createDatePlugin as E, createVirtualContext as F, createSortable as G, createDataGrid as H, useVirtual as I, ServerComboboxAdapter as K, createTimeline as L, toReactive as M, toHighlight as N, createBreakpoints as O, createVirtual as P, createTimelineContext as R, DragDropAdapter as S, createDateContext as T, createDataGridContext as U, createKanban as V, useDataGrid as W, usePrefersReducedMotion as _, useRtl as a, KeyboardAdapter as b, createReducedMotion as c, useReducedMotion as d, V0ReducedMotionAdapter as f, usePrefersDark as g, usePrefersContrast as h, createRtlPlugin as i, useBreakpoints as j, createBreakpointsContext as k, createReducedMotionContext as l, useMediaQuery as m, createRtlContext as n, V0RtlAdapter as o, ReducedMotionAdapter as p, createRtlFallback as r, RtlAdapter as s, createRtl as t, createReducedMotionPlugin as u, useHotkey as v, createDate as w, PointerAdapter as x, useDragDrop as y, useTimeline as z };
3050
+ export { createVirtual as A, useDate as C, useBreakpoints as D, createBreakpointsPlugin as E, useTimeline as F, createOtp as I, createKanban as L, useVirtual as M, createTimeline as N, toReactive as O, createTimelineContext as P, ServerComboboxAdapter as R, createDatePlugin as S, createBreakpointsContext as T, PointerAdapter as _, useRtl as a, createDate as b, createReducedMotion as c, useReducedMotion as d, V0ReducedMotionAdapter as f, KeyboardAdapter as g, useDragDrop as h, createRtlPlugin as i, createVirtualContext as j, toHighlight as k, createReducedMotionContext as l, useHotkey as m, createRtlContext as n, V0RtlAdapter as o, ReducedMotionAdapter as p, createRtlFallback as r, RtlAdapter as s, createRtl as t, createReducedMotionPlugin as u, DragDropAdapter as v, createBreakpoints as w, createDateContext as x, useMutationObserver as y };