@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.
- package/README.md +8 -0
- package/dist/{adapter-Butx_2UU.d.mts → adapter-BXunW_mw.d.mts} +1 -1
- package/dist/{createPagination-B5dfqY-a.mjs → adapter-BiQV5j8B.mjs} +98 -3
- package/dist/adapter-ClB-53_F.d.mts +62 -0
- package/dist/{adapter-hq9YlPOF.d.mts → adapter-CqS8xexO.d.mts} +2 -2
- package/dist/adapter-CrRJuxRk.mjs +21 -0
- package/dist/{adapter-_srNCBEi.d.mts → adapter-PDTe5nFT.d.mts} +6 -7
- package/dist/{adapter-lS_VpRow.mjs → adapter-TiGrumDi.mjs} +3 -1
- package/dist/browser/index.d.ts +17953 -15766
- package/dist/browser/index.js +16633 -14006
- package/dist/components/index.d.mts +2 -2
- package/dist/components/index.mjs +2 -2
- package/dist/{components-OCsY4P1f.mjs → components-DBhVg-t1.mjs} +4253 -2247
- package/dist/composables/index.d.mts +22 -20
- package/dist/composables/index.mjs +37 -34
- package/dist/{composables-xhcxXjuE.mjs → composables-ZGhVN2EJ.mjs} +47 -1066
- package/dist/{consola-BPGkJp_q.d.mts → consola-CdMU53rU.d.mts} +1 -1
- package/dist/constants/index.d.mts +1 -1
- package/dist/constants/index.mjs +1 -1
- package/dist/{createDataTable-D38H0Zbp.mjs → createDataTable-VmQEDn-7.mjs} +23 -7
- package/dist/{createGroup-CjUHFae5.mjs → createGroup-B_LL7xRr.mjs} +2 -2
- package/dist/createPlugin-Oo6t-vBw.mjs +157 -0
- package/dist/{createRegistry-B8VqA-QF.mjs → createRegistry-DVdvep0v.mjs} +1 -1
- package/dist/{createSelection-BXd5clS0.mjs → createSelection-BNdDz8oY.mjs} +1 -1
- package/dist/{createSingle-Bdkfht_B.mjs → createSingle-DHyIQ9Cj.mjs} +1 -1
- package/dist/{createTokens-vgyk_0vA.mjs → createTokens-DoISbwd7.mjs} +2 -2
- package/dist/data-table/adapters/client/index.d.mts +1 -1
- package/dist/data-table/adapters/client/index.mjs +1 -1
- package/dist/data-table/adapters/index.d.mts +4 -4
- package/dist/data-table/adapters/index.mjs +4 -4
- package/dist/data-table/adapters/server/index.d.mts +1 -1
- package/dist/data-table/adapters/server/index.mjs +1 -1
- package/dist/data-table/adapters/virtual/index.d.mts +1 -1
- package/dist/data-table/adapters/virtual/index.mjs +1 -1
- package/dist/data-table/index.d.mts +5 -5
- package/dist/data-table/index.mjs +5 -5
- package/dist/date/index.d.mts +1 -1
- package/dist/date/index.mjs +2 -2
- package/dist/features/adapters/flagsmith/index.d.mts +1 -1
- package/dist/features/adapters/flagsmith/index.mjs +1 -1
- package/dist/features/adapters/launchdarkly/index.d.mts +1 -1
- package/dist/features/adapters/launchdarkly/index.mjs +1 -1
- package/dist/features/adapters/posthog/index.d.mts +1 -1
- package/dist/features/adapters/posthog/index.mjs +2 -2
- package/dist/features/index.d.mts +2 -2
- package/dist/features/index.mjs +2 -2
- package/dist/{flagsmith-DA2GCyGv.d.mts → flagsmith-DcIDrI7_.d.mts} +1 -1
- package/dist/{globals-B7ejLnrz.mjs → globals-DaoKtIGF.mjs} +1 -1
- package/dist/{index-DY81ptHb.d.mts → index-Cm6CbqI6.d.mts} +7494 -5834
- package/dist/{index-CrAgM2EJ.d.mts → index-Cx0cWGlx.d.mts} +493 -132
- package/dist/{index-QnpcDsV7.d.mts → index-D0ub61GV.d.mts} +2 -2
- package/dist/{index-RGiSdjYt.d.mts → index-DSPkZ0ql.d.mts} +2 -2
- package/dist/{index-DCtHbY0a.d.mts → index-Di9e8sOm.d.mts} +24 -19
- package/dist/{index-DF0tMI2_.d.mts → index-DjRE4lLl.d.mts} +108 -2
- package/dist/index.d.mts +25 -24
- package/dist/index.mjs +40 -37
- package/dist/json/attributes.json +488 -0
- package/dist/json/importMap.json +92 -0
- package/dist/json/tags.json +234 -0
- package/dist/json/web-types.json +1540 -113
- package/dist/{launchdarkly-Bp8p9PMD.d.mts → launchdarkly-CUzunYol.d.mts} +1 -1
- package/dist/locale/adapters/index.d.mts +2 -2
- package/dist/locale/adapters/index.mjs +2 -2
- package/dist/locale/adapters/v0/index.d.mts +1 -1
- package/dist/locale/adapters/v0/index.mjs +1 -1
- package/dist/locale/adapters/vue-i18n/index.d.mts +1 -1
- package/dist/locale/adapters/vue-i18n/index.mjs +1 -1
- package/dist/locale/index.d.mts +3 -3
- package/dist/locale/index.mjs +3 -3
- package/dist/locale/messages/en/index.d.mts +5 -0
- package/dist/locale/messages/en/index.mjs +6 -1
- package/dist/logger/adapters/consola/index.d.mts +1 -1
- package/dist/logger/adapters/index.d.mts +4 -4
- package/dist/logger/adapters/index.mjs +1 -1
- package/dist/logger/adapters/pino/index.d.mts +1 -1
- package/dist/logger/adapters/v0/index.d.mts +1 -1
- package/dist/logger/adapters/v0/index.mjs +1 -1
- package/dist/logger/index.d.mts +5 -5
- package/dist/logger/index.mjs +2 -2
- package/dist/notifications/index.d.mts +1 -1
- package/dist/notifications/index.mjs +2 -2
- package/dist/palettes/ant/index.d.mts +1 -1
- package/dist/palettes/index.d.mts +3 -3
- package/dist/palettes/material/index.d.mts +1 -1
- package/dist/palettes/md1/index.d.mts +1 -1
- package/dist/palettes/md2/index.d.mts +1 -1
- package/dist/palettes/radix/index.d.mts +1 -1
- package/dist/palettes/tailwind/index.d.mts +1 -1
- package/dist/permissions/adapters/index.d.mts +1 -1
- package/dist/permissions/adapters/index.mjs +1 -1
- package/dist/permissions/adapters/v0/index.d.mts +1 -1
- package/dist/permissions/adapters/v0/index.mjs +1 -1
- package/dist/permissions/index.d.mts +1 -1
- package/dist/permissions/index.mjs +2 -2
- package/dist/{pino-B6BI1AOK.d.mts → pino-DjeWBFnj.d.mts} +1 -1
- package/dist/popover/adapters/floating-ui/index.d.mts +25 -0
- package/dist/popover/adapters/floating-ui/index.mjs +98 -0
- package/dist/popover/index.d.mts +3 -0
- package/dist/popover/index.mjs +3 -0
- package/dist/{posthog-sFqk0bGy.d.mts → posthog-CJAYssdr.d.mts} +1 -1
- package/dist/rules/index.d.mts +1 -1
- package/dist/rules/index.mjs +1 -1
- package/dist/{server-DbtTGb67.d.mts → server-5vbJ7GGs.d.mts} +2 -2
- package/dist/{server-D5BJBjB0.mjs → server-m7iD1vOr.mjs} +1 -2
- package/dist/storage/adapters/index.d.mts +2 -2
- package/dist/storage/adapters/index.mjs +1 -1
- package/dist/storage/adapters/memory/index.d.mts +1 -1
- package/dist/storage/adapters/memory/index.mjs +1 -1
- package/dist/storage/index.d.mts +3 -3
- package/dist/storage/index.mjs +2 -2
- package/dist/theme/adapters/index.d.mts +1 -1
- package/dist/theme/adapters/index.mjs +3 -3
- package/dist/theme/adapters/unhead/index.d.mts +1 -1
- package/dist/theme/adapters/unhead/index.mjs +1 -1
- package/dist/theme/adapters/v0/index.d.mts +1 -1
- package/dist/theme/adapters/v0/index.mjs +1 -1
- package/dist/theme/index.d.mts +2 -2
- package/dist/theme/index.mjs +4 -4
- package/dist/types/index.d.mts +1 -1
- package/dist/{unhead-DxiB3P5p.mjs → unhead-C8zbWr45.mjs} +2 -2
- package/dist/{useEventListener-BjWJPfYS.mjs → useEventListener-2eAMwUdw.mjs} +2 -2
- package/dist/useFeatures-DLafCOWt.mjs +221 -0
- package/dist/{useLocale-B2BAEieU.mjs → useLocale-K_45ulPt.mjs} +4 -4
- package/dist/{useLogger-CXKIZhks.mjs → useLogger-YyWuYvrH.mjs} +5 -159
- package/dist/{useNotifications-Czgbh8Ns.mjs → useNotifications-Kh_KvM7j.mjs} +57 -154
- package/dist/{usePermissions-BkndJNpk.mjs → usePermissions-BCGwsOES.mjs} +4 -4
- package/dist/usePopover-BTo0AGIQ.mjs +420 -0
- package/dist/{useRovingFocus-Cn96TXRw.mjs → useRovingFocus-CkRnVmJ1.mjs} +1122 -531
- package/dist/{useRules-NzJChxfk.mjs → useRules-BuE5ffOJ.mjs} +3 -2
- package/dist/{useStorage-D6xihSHv.mjs → useStorage-BT8-mjVs.mjs} +5 -4
- package/dist/useTheme-DkK6tPqY.mjs +445 -0
- package/dist/useTimer-CGVXk397.mjs +151 -0
- package/dist/utilities/index.d.mts +2 -2
- package/dist/utilities/index.mjs +181 -2
- package/dist/{v0-BFMaRqAx.mjs → v0-B_53w7Fu.mjs} +2 -2
- package/dist/{v0-BnUwMaOv.d.mts → v0-CDW1Ktk-.d.mts} +1 -1
- package/dist/{v0-gU93DxmF.mjs → v0-D0Exc2bO.mjs} +2 -2
- package/dist/{v0-rSxMW8FJ.d.mts → v0-DfFK-p4X.d.mts} +1 -1
- package/dist/{v0-DotXXGXU.d.mts → v0-GI9U-rPA.d.mts} +2 -2
- package/dist/{v0-eZcJPyii.mjs → v0-SuxTihEe.mjs} +1 -1
- package/dist/{v0-A4GLojAr.mjs → v0-yZ2ZUtVF.mjs} +1 -2
- package/dist/{virtual-DFvOoeG6.mjs → virtual-Bbu26O_h.mjs} +1 -2
- package/dist/{virtual-C-NsLue0.d.mts → virtual-JIdFLpTQ.d.mts} +2 -2
- package/package.json +8 -1
- package/dist/adapter-CVoWg0sw.mjs +0 -99
- package/dist/useFeatures-DcgU66KC.mjs +0 -124
- package/dist/useTheme-BuXEQdPz.mjs +0 -162
- /package/dist/{adapter-CTsckKAR.mjs → adapter-8UADsA3-.mjs} +0 -0
- /package/dist/{adapter-BCtceV3b.mjs → adapter-BuSfpxur.mjs} +0 -0
- /package/dist/{adapter-Bc0yPSfo.d.mts → adapter-D5nT3bLw.d.mts} +0 -0
- /package/dist/{adapter-bwZo7b5p.mjs → adapter-D8zizQVP.mjs} +0 -0
- /package/dist/{adapter-BYzU4Ey5.d.mts → adapter-ryk5H6YZ.d.mts} +0 -0
- /package/dist/{index-CROz1VSV.d.mts → index-CX869wwk.d.mts} +0 -0
- /package/dist/{index-FtE8MXJ_.d.mts → index-CsuikFeJ.d.mts} +0 -0
- /package/dist/{index-DidZKN6S.d.mts → index-Djhiy3nS.d.mts} +0 -0
- /package/dist/{index-CyNk9FpR.d.mts → index-DtiaWx5U.d.mts} +0 -0
- /package/dist/{index-DXMlYoiQ.d.mts → index-H_hl6-4b.d.mts} +0 -0
- /package/dist/{index-BgCkepP_.d.mts → index-u_qSc2xS.d.mts} +0 -0
- /package/dist/{memory-DbyZeNjg.d.mts → memory-B7z1RR9r.d.mts} +0 -0
- /package/dist/{memory-BJjkQzxs.mjs → memory-CR6zvuaP.mjs} +0 -0
- /package/dist/{toArray-C89ZaEuF.mjs → toArray-MY9Kb1Qy.mjs} +0 -0
- /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-
|
|
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,
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { a as useLocale } from "./useLocale-
|
|
8
|
-
import { t as toArray } from "./toArray-
|
|
9
|
-
import { n as useEventListener, r as useWindowEventListener } from "./useEventListener-
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
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,
|
|
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
|
|
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,
|
|
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 (
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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 {
|
|
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 };
|