@vuetify/v0 0.0.2 → 0.0.6
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 +12 -13
- package/dist/browser/index.js +3347 -2056
- package/dist/components/index.d.ts +4 -7
- package/dist/components/index.js +6 -8
- package/dist/{components-Cc48kKWf.js → components-B5k361i-.js} +173 -190
- package/dist/composables/index.d.ts +3 -7
- package/dist/composables/index.js +4 -7
- package/dist/composables-CAbYjAkR.js +3746 -0
- package/dist/constants/index.d.ts +1 -1
- package/dist/constants/index.js +3 -3
- package/dist/{globals--2b7sF4-.js → globals-CHVv7nNV.js} +2 -2
- package/dist/{htmlElements-SjqYu0am.js → htmlElements-lF7PGahL.js} +1 -1
- package/dist/{index-z_zwVNP8.d.ts → index-BKc0YiL1.d.ts} +1 -1
- package/dist/index-BQfe0WBZ.d.ts +410 -0
- package/dist/index-BhPlroXd.d.ts +2764 -0
- package/dist/{index-LBy5OPMu.d.ts → index-C_lAPFXS.d.ts} +1 -1
- package/dist/{index-BozA2pze.d.ts → index-DIX3zaZG.d.ts} +3 -10
- package/dist/index.d.ts +6 -7
- package/dist/index.js +7 -10
- package/dist/types/index.d.ts +1 -1
- package/dist/utilities/index.d.ts +3 -3
- package/dist/utilities/index.js +2 -2
- package/dist/{utilities-D9rWEgQK.js → utilities-rsKHgU2m.js} +5 -32
- package/package.json +10 -38
- package/dist/composables-7Cbs2sdO.js +0 -1003
- package/dist/factories/index.d.ts +0 -2
- package/dist/factories/index.js +0 -3
- package/dist/factories-CPq2yMlr.js +0 -79
- package/dist/index-BnsMFYhs.d.ts +0 -1407
- package/dist/index-BqrLvboW.d.ts +0 -61
- package/dist/index-tUyghL98.d.ts +0 -19
- package/dist/transformers/index.d.ts +0 -2
- package/dist/transformers/index.js +0 -4
- package/dist/transformers-BAeg3QJF.js +0 -122
- package/dist/useTheme-DSYiiz0R.js +0 -1244
- /package/dist/{constants-DiTCgvMU.js → constants-De5c3_aB.js} +0 -0
|
@@ -1,1003 +0,0 @@
|
|
|
1
|
-
import { createContext, createPlugin, createTrinity, useContext } from "./factories-CPq2yMlr.js";
|
|
2
|
-
import { createTokensContext, useGroup, useHydration, useLogger, useRegistry, useSingle } from "./useTheme-DSYiiz0R.js";
|
|
3
|
-
import { isArray, isFunction } from "./utilities-D9rWEgQK.js";
|
|
4
|
-
import { IN_BROWSER, SUPPORTS_INTERSECTION_OBSERVER, SUPPORTS_MUTATION_OBSERVER, SUPPORTS_OBSERVER } from "./globals--2b7sF4-.js";
|
|
5
|
-
import { toArray } from "./transformers-BAeg3QJF.js";
|
|
6
|
-
import { computed, getCurrentInstance, getCurrentScope, isRef, onMounted, onScopeDispose, onUnmounted, readonly, ref, shallowReactive, shallowRef, toRaw, toRef, toValue, unref, watch } from "vue";
|
|
7
|
-
|
|
8
|
-
//#region src/composables/useEventListener/index.ts
|
|
9
|
-
function useEventListener(target, event, listener, options) {
|
|
10
|
-
const cleanups = [];
|
|
11
|
-
function cleanup() {
|
|
12
|
-
for (const fn of cleanups) fn();
|
|
13
|
-
cleanups.length = 0;
|
|
14
|
-
}
|
|
15
|
-
const register = (el, event$1, listener$1, options$1) => {
|
|
16
|
-
el.addEventListener(event$1, listener$1, options$1);
|
|
17
|
-
return () => el.removeEventListener(event$1, listener$1, options$1);
|
|
18
|
-
};
|
|
19
|
-
const stopWatcher = watch(() => [
|
|
20
|
-
toValue(target),
|
|
21
|
-
toValue(event),
|
|
22
|
-
unref(listener),
|
|
23
|
-
toValue(options)
|
|
24
|
-
], ([el, events, listeners, opts]) => {
|
|
25
|
-
cleanup();
|
|
26
|
-
if (!el) return;
|
|
27
|
-
const eventList = toArray(events);
|
|
28
|
-
const listenerList = toArray(listeners);
|
|
29
|
-
for (const event$1 of eventList) for (const listenerFn of listenerList) cleanups.push(register(el, event$1, listenerFn, opts));
|
|
30
|
-
}, {
|
|
31
|
-
immediate: true,
|
|
32
|
-
flush: "post"
|
|
33
|
-
});
|
|
34
|
-
function stop() {
|
|
35
|
-
stopWatcher();
|
|
36
|
-
cleanup();
|
|
37
|
-
}
|
|
38
|
-
onScopeDispose(stop, true);
|
|
39
|
-
return stop;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Convenience function for attaching event listeners to the window object.
|
|
43
|
-
* This function provides a simplified API by pre-binding the window target,
|
|
44
|
-
* making it easier to handle window-specific events with automatic cleanup.
|
|
45
|
-
*
|
|
46
|
-
* @param event Event name(s) to listen for from WindowEventMap.
|
|
47
|
-
* @param listener Event handler function(s) with proper window event typing.
|
|
48
|
-
* @param options Optional event listener configuration.
|
|
49
|
-
* @returns Function to manually remove all attached listeners.
|
|
50
|
-
*/
|
|
51
|
-
function useWindowEventListener(event, listener, options) {
|
|
52
|
-
return useEventListener(window, event, listener, options);
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Convenience function for attaching event listeners to the document object.
|
|
56
|
-
* This function provides a simplified API by pre-binding the document target,
|
|
57
|
-
* making it easier to handle document-specific events with automatic cleanup.
|
|
58
|
-
*
|
|
59
|
-
* @param event Event name(s) to listen for from DocumentEventMap.
|
|
60
|
-
* @param listener Event handler function(s) with proper document event typing.
|
|
61
|
-
* @param options Optional event listener configuration.
|
|
62
|
-
* @returns Function to manually remove all attached listeners.
|
|
63
|
-
*/
|
|
64
|
-
function useDocumentEventListener(event, listener, options) {
|
|
65
|
-
return useEventListener(document, event, listener, options);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
//#endregion
|
|
69
|
-
//#region src/composables/useFilter/index.ts
|
|
70
|
-
function defaultFilter(query, item, keys, mode = "some") {
|
|
71
|
-
const queries = Array.isArray(query) ? query.map((q) => String(q).toLowerCase()) : [String(query).toLowerCase()];
|
|
72
|
-
function match(value, q) {
|
|
73
|
-
return String(value).toLowerCase().includes(q);
|
|
74
|
-
}
|
|
75
|
-
const values = typeof item === "object" && item !== null ? keys?.length ? keys.map((k) => item[k]) : Object.values(item) : [item];
|
|
76
|
-
const stringValues = values.map((v) => String(v).toLowerCase());
|
|
77
|
-
if (mode === "some") return stringValues.some((val) => match(val, queries[0]));
|
|
78
|
-
if (mode === "every") return stringValues.every((val) => match(val, queries[0]));
|
|
79
|
-
if (mode === "union") return queries.some((q) => stringValues.some((val) => match(val, q)));
|
|
80
|
-
if (mode === "intersection") return queries.every((q) => stringValues.some((val) => match(val, q)));
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
function toRefOrGetter(value) {
|
|
84
|
-
return isRef(value) ? value : typeof value === "function" ? toRef(value) : toRef(() => value);
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Creates a reactive filter for arrays based on query matching with configurable search modes.
|
|
88
|
-
* Supports 'some' (any field matches), 'every' (all fields match), 'union' (any query matches),
|
|
89
|
-
* and 'intersection' (all queries match) filtering strategies.
|
|
90
|
-
*
|
|
91
|
-
* @param query Filter query to match against items.
|
|
92
|
-
* @param items Collection of items to filter.
|
|
93
|
-
* @param options Optional configuration for the filter behavior.
|
|
94
|
-
* @template Z The type of the items being filtered.
|
|
95
|
-
* @returns A computed reference to the filtered items based on the query and options.
|
|
96
|
-
*/
|
|
97
|
-
function useFilter(query, items, options = {}) {
|
|
98
|
-
const { customFilter, keys, mode = "some" } = options;
|
|
99
|
-
const filterFunction = customFilter ?? ((q, i) => defaultFilter(q, i, keys, mode));
|
|
100
|
-
const itemsRef = isRef(items) ? items : toRef(() => items);
|
|
101
|
-
const queryRef = toRefOrGetter(query);
|
|
102
|
-
const filteredItems = computed(() => {
|
|
103
|
-
const q = toValue(queryRef);
|
|
104
|
-
const queries = (Array.isArray(q) ? q : [q]).filter((q$1) => String(q$1).trim());
|
|
105
|
-
if (queries.length === 0) return itemsRef.value;
|
|
106
|
-
const queryParam = queries.length === 1 ? queries[0] : queries;
|
|
107
|
-
return itemsRef.value.filter((item) => filterFunction(queryParam, item));
|
|
108
|
-
});
|
|
109
|
-
return { items: filteredItems };
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
//#endregion
|
|
113
|
-
//#region src/composables/useForm/index.ts
|
|
114
|
-
function useForm(options) {
|
|
115
|
-
const registry = useRegistry(options);
|
|
116
|
-
const validateOn = options?.validateOn || "submit";
|
|
117
|
-
function parse(value) {
|
|
118
|
-
return value.toLowerCase().split(/\s+/);
|
|
119
|
-
}
|
|
120
|
-
function validatesOn(event) {
|
|
121
|
-
return parse(validateOn).includes(event);
|
|
122
|
-
}
|
|
123
|
-
const isValidating = computed(() => {
|
|
124
|
-
for (const ticket of registry.collection.values()) if (ticket.isValidating.value) return true;
|
|
125
|
-
return false;
|
|
126
|
-
});
|
|
127
|
-
const isValid = computed(() => {
|
|
128
|
-
let hasFields = false;
|
|
129
|
-
for (const ticket of registry.values()) {
|
|
130
|
-
hasFields = true;
|
|
131
|
-
if (ticket.isValid.value === false) return false;
|
|
132
|
-
if (ticket.isValid.value === null) return null;
|
|
133
|
-
}
|
|
134
|
-
return hasFields ? true : null;
|
|
135
|
-
});
|
|
136
|
-
function reset() {
|
|
137
|
-
for (const ticket of registry.values()) ticket.reset();
|
|
138
|
-
}
|
|
139
|
-
async function submit() {
|
|
140
|
-
return validate(registry.keys());
|
|
141
|
-
}
|
|
142
|
-
async function validate(id) {
|
|
143
|
-
const validating = toArray(id);
|
|
144
|
-
if (validatesOn("submit")) {
|
|
145
|
-
const results = await Promise.all(validating.map(async (id$1) => await registry.get(id$1)?.validate() ?? true));
|
|
146
|
-
return results.every(Boolean);
|
|
147
|
-
}
|
|
148
|
-
const tickets = validating.map((id$1) => registry.get(id$1)).filter(Boolean);
|
|
149
|
-
return tickets.every((ticket) => ticket.isValid.value === true);
|
|
150
|
-
}
|
|
151
|
-
function register(registration) {
|
|
152
|
-
const model = shallowRef(registration.value == null ? "" : toValue(registration.value));
|
|
153
|
-
const rules = registration.rules || [];
|
|
154
|
-
const errors = shallowRef([]);
|
|
155
|
-
const isValidating$1 = shallowRef(false);
|
|
156
|
-
const initialValue = model.value;
|
|
157
|
-
const triggers = registration.validateOn || validateOn;
|
|
158
|
-
const isPristine = shallowRef(true);
|
|
159
|
-
const isValid$1 = shallowRef(null);
|
|
160
|
-
function _validatesOn(event) {
|
|
161
|
-
return parse(triggers).includes(event);
|
|
162
|
-
}
|
|
163
|
-
function _reset() {
|
|
164
|
-
model.value = initialValue;
|
|
165
|
-
errors.value = [];
|
|
166
|
-
isPristine.value = true;
|
|
167
|
-
isValid$1.value = null;
|
|
168
|
-
}
|
|
169
|
-
async function validate$1(silent = false) {
|
|
170
|
-
if (rules.length === 0) return true;
|
|
171
|
-
isValidating$1.value = true;
|
|
172
|
-
try {
|
|
173
|
-
const results = await Promise.all(rules.map((rule) => rule(model.value)));
|
|
174
|
-
const errorMessages = results.filter((result) => typeof result === "string");
|
|
175
|
-
if (!silent) {
|
|
176
|
-
errors.value = errorMessages;
|
|
177
|
-
isValid$1.value = errorMessages.length === 0;
|
|
178
|
-
isPristine.value = toValue(model) === initialValue;
|
|
179
|
-
}
|
|
180
|
-
return errorMessages.length === 0;
|
|
181
|
-
} finally {
|
|
182
|
-
isValidating$1.value = false;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
const item = {
|
|
186
|
-
...registration,
|
|
187
|
-
rules,
|
|
188
|
-
errors,
|
|
189
|
-
disabled: registration.disabled || false,
|
|
190
|
-
validateOn: triggers,
|
|
191
|
-
isValidating: isValidating$1,
|
|
192
|
-
isPristine,
|
|
193
|
-
isValid: isValid$1,
|
|
194
|
-
reset: _reset,
|
|
195
|
-
validate: validate$1
|
|
196
|
-
};
|
|
197
|
-
const ticket = registry.register(item);
|
|
198
|
-
Object.defineProperty(ticket, "value", {
|
|
199
|
-
get() {
|
|
200
|
-
return model.value;
|
|
201
|
-
},
|
|
202
|
-
set(val) {
|
|
203
|
-
model.value = val;
|
|
204
|
-
isPristine.value = val === initialValue;
|
|
205
|
-
isValid$1.value = null;
|
|
206
|
-
if (_validatesOn("change")) validate$1();
|
|
207
|
-
},
|
|
208
|
-
enumerable: true,
|
|
209
|
-
configurable: true
|
|
210
|
-
});
|
|
211
|
-
return ticket;
|
|
212
|
-
}
|
|
213
|
-
return {
|
|
214
|
-
...registry,
|
|
215
|
-
register,
|
|
216
|
-
reset,
|
|
217
|
-
submit,
|
|
218
|
-
validateOn,
|
|
219
|
-
isValid,
|
|
220
|
-
isValidating
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
//#endregion
|
|
225
|
-
//#region src/composables/useIntersectionObserver/index.ts
|
|
226
|
-
/**
|
|
227
|
-
* Composable for observing element intersection with viewport or ancestor
|
|
228
|
-
*
|
|
229
|
-
* @param target - Element ref to observe
|
|
230
|
-
* @param callback - Callback fired on intersection change
|
|
231
|
-
* @param options - Observer options
|
|
232
|
-
* @returns Observer controls and intersection state
|
|
233
|
-
*
|
|
234
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver
|
|
235
|
-
*/
|
|
236
|
-
function useIntersectionObserver(target, callback, options = {}) {
|
|
237
|
-
const { isHydrated } = useHydration();
|
|
238
|
-
const observer = shallowRef();
|
|
239
|
-
const isPaused = shallowRef(false);
|
|
240
|
-
const isIntersecting = shallowRef(false);
|
|
241
|
-
watch([isHydrated, target], ([hydrated, el]) => {
|
|
242
|
-
cleanup();
|
|
243
|
-
if (!hydrated || !SUPPORTS_INTERSECTION_OBSERVER || !el) return;
|
|
244
|
-
observer.value = new IntersectionObserver((entries) => {
|
|
245
|
-
const transformedEntries = entries.map((entry) => ({
|
|
246
|
-
boundingClientRect: entry.boundingClientRect,
|
|
247
|
-
intersectionRatio: entry.intersectionRatio,
|
|
248
|
-
intersectionRect: entry.intersectionRect,
|
|
249
|
-
isIntersecting: entry.isIntersecting,
|
|
250
|
-
rootBounds: entry.rootBounds,
|
|
251
|
-
target: entry.target,
|
|
252
|
-
time: entry.time
|
|
253
|
-
}));
|
|
254
|
-
const latestEntry = transformedEntries.at(-1);
|
|
255
|
-
if (latestEntry) isIntersecting.value = latestEntry.isIntersecting;
|
|
256
|
-
callback(transformedEntries);
|
|
257
|
-
}, {
|
|
258
|
-
root: options.root || null,
|
|
259
|
-
rootMargin: options.rootMargin || "0px",
|
|
260
|
-
threshold: options.threshold || 0
|
|
261
|
-
});
|
|
262
|
-
observer.value.observe(el);
|
|
263
|
-
if (options.immediate) {
|
|
264
|
-
const rect = el.getBoundingClientRect();
|
|
265
|
-
const syntheticEntry = {
|
|
266
|
-
boundingClientRect: rect,
|
|
267
|
-
intersectionRatio: 0,
|
|
268
|
-
intersectionRect: new DOMRect(0, 0, 0, 0),
|
|
269
|
-
isIntersecting: false,
|
|
270
|
-
rootBounds: null,
|
|
271
|
-
target: el,
|
|
272
|
-
time: performance.now()
|
|
273
|
-
};
|
|
274
|
-
callback([syntheticEntry]);
|
|
275
|
-
}
|
|
276
|
-
});
|
|
277
|
-
function setup() {
|
|
278
|
-
if (!isHydrated.value || !SUPPORTS_INTERSECTION_OBSERVER || !target.value || isPaused.value) return;
|
|
279
|
-
observer.value = new IntersectionObserver((entries) => {
|
|
280
|
-
const transformedEntries = entries.map((entry) => ({
|
|
281
|
-
boundingClientRect: entry.boundingClientRect,
|
|
282
|
-
intersectionRatio: entry.intersectionRatio,
|
|
283
|
-
intersectionRect: entry.intersectionRect,
|
|
284
|
-
isIntersecting: entry.isIntersecting,
|
|
285
|
-
rootBounds: entry.rootBounds,
|
|
286
|
-
target: entry.target,
|
|
287
|
-
time: entry.time
|
|
288
|
-
}));
|
|
289
|
-
const latestEntry = transformedEntries.at(-1);
|
|
290
|
-
if (latestEntry) isIntersecting.value = latestEntry.isIntersecting;
|
|
291
|
-
callback(transformedEntries);
|
|
292
|
-
}, {
|
|
293
|
-
root: options.root || null,
|
|
294
|
-
rootMargin: options.rootMargin || "0px",
|
|
295
|
-
threshold: options.threshold || 0
|
|
296
|
-
});
|
|
297
|
-
observer.value.observe(target.value);
|
|
298
|
-
if (options.immediate) {
|
|
299
|
-
const rect = target.value.getBoundingClientRect();
|
|
300
|
-
const syntheticEntry = {
|
|
301
|
-
boundingClientRect: rect,
|
|
302
|
-
intersectionRatio: 0,
|
|
303
|
-
intersectionRect: new DOMRect(0, 0, 0, 0),
|
|
304
|
-
isIntersecting: false,
|
|
305
|
-
rootBounds: null,
|
|
306
|
-
target: target.value,
|
|
307
|
-
time: performance.now()
|
|
308
|
-
};
|
|
309
|
-
callback([syntheticEntry]);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
function cleanup() {
|
|
313
|
-
if (observer.value) {
|
|
314
|
-
observer.value.disconnect();
|
|
315
|
-
observer.value = void 0;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
function pause() {
|
|
319
|
-
isPaused.value = true;
|
|
320
|
-
observer.value?.disconnect();
|
|
321
|
-
}
|
|
322
|
-
function resume() {
|
|
323
|
-
isPaused.value = false;
|
|
324
|
-
setup();
|
|
325
|
-
}
|
|
326
|
-
function stop() {
|
|
327
|
-
cleanup();
|
|
328
|
-
}
|
|
329
|
-
onUnmounted(stop);
|
|
330
|
-
return {
|
|
331
|
-
isIntersecting: readonly(isIntersecting),
|
|
332
|
-
isPaused: readonly(isPaused),
|
|
333
|
-
pause,
|
|
334
|
-
resume,
|
|
335
|
-
stop
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* Convenience composable for simple intersection detection
|
|
340
|
-
*
|
|
341
|
-
* @param target - Element ref to observe
|
|
342
|
-
* @param options - Observer options
|
|
343
|
-
* @returns Reactive intersection state
|
|
344
|
-
*/
|
|
345
|
-
function useElementIntersection(target, options = {}) {
|
|
346
|
-
const isIntersecting = shallowRef(false);
|
|
347
|
-
const intersectionRatio = shallowRef(0);
|
|
348
|
-
useIntersectionObserver(target, (entries) => {
|
|
349
|
-
const entry = entries.at(-1);
|
|
350
|
-
if (entry) {
|
|
351
|
-
isIntersecting.value = entry.isIntersecting;
|
|
352
|
-
intersectionRatio.value = entry.intersectionRatio;
|
|
353
|
-
}
|
|
354
|
-
}, {
|
|
355
|
-
immediate: true,
|
|
356
|
-
...options
|
|
357
|
-
});
|
|
358
|
-
return {
|
|
359
|
-
isIntersecting: readonly(isIntersecting),
|
|
360
|
-
intersectionRatio: readonly(intersectionRatio)
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
//#endregion
|
|
365
|
-
//#region src/composables/useKeydown/index.ts
|
|
366
|
-
/**
|
|
367
|
-
* Sets up global keyboard event listeners for specified key handlers with automatic cleanup.
|
|
368
|
-
* This composable automatically starts listening when mounted and cleans up when the scope
|
|
369
|
-
* is disposed, providing a clean way to handle global keyboard interactions.
|
|
370
|
-
*
|
|
371
|
-
* @param handlers A single handler or array of handlers to register for keydown events.
|
|
372
|
-
* @returns Object with methods to manually start and stop listening for keydown events.
|
|
373
|
-
*/
|
|
374
|
-
function useKeydown(handlers) {
|
|
375
|
-
const keyHandlers = Array.isArray(handlers) ? handlers : [handlers];
|
|
376
|
-
function onKeydown(event) {
|
|
377
|
-
const handler = keyHandlers.find((h$1) => h$1.key === event.key);
|
|
378
|
-
if (handler) {
|
|
379
|
-
if (handler.preventDefault) event.preventDefault();
|
|
380
|
-
if (handler.stopPropagation) event.stopPropagation();
|
|
381
|
-
handler.handler(event);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
function startListening() {
|
|
385
|
-
document.addEventListener("keydown", onKeydown);
|
|
386
|
-
}
|
|
387
|
-
function stopListening() {
|
|
388
|
-
document.removeEventListener("keydown", onKeydown);
|
|
389
|
-
}
|
|
390
|
-
if (getCurrentScope()) onMounted(startListening);
|
|
391
|
-
onScopeDispose(stopListening, true);
|
|
392
|
-
return {
|
|
393
|
-
startListening,
|
|
394
|
-
stopListening
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
//#endregion
|
|
399
|
-
//#region src/composables/useLayout/index.ts
|
|
400
|
-
function useLayout(_options = {}) {
|
|
401
|
-
const { enroll = true, events = true,...options } = _options;
|
|
402
|
-
const registry = useGroup({
|
|
403
|
-
enroll,
|
|
404
|
-
events,
|
|
405
|
-
...options
|
|
406
|
-
});
|
|
407
|
-
const sizes = shallowReactive(/* @__PURE__ */ new Map());
|
|
408
|
-
const height = shallowRef(0);
|
|
409
|
-
const width = shallowRef(0);
|
|
410
|
-
const bounds = {
|
|
411
|
-
top: computed(() => sum("top")),
|
|
412
|
-
bottom: computed(() => sum("bottom")),
|
|
413
|
-
left: computed(() => sum("left")),
|
|
414
|
-
right: computed(() => sum("right"))
|
|
415
|
-
};
|
|
416
|
-
const main = {
|
|
417
|
-
x: computed(() => bounds.left.value),
|
|
418
|
-
y: computed(() => bounds.top.value),
|
|
419
|
-
width: computed(() => width.value - bounds.left.value - bounds.right.value),
|
|
420
|
-
height: computed(() => height.value - bounds.top.value - bounds.bottom.value)
|
|
421
|
-
};
|
|
422
|
-
function sum(position) {
|
|
423
|
-
let total = 0;
|
|
424
|
-
for (const item of registry.values()) if (item.position === position && item.isActive.value) total += sizes.get(item.id) ?? item.value ?? 0;
|
|
425
|
-
return total;
|
|
426
|
-
}
|
|
427
|
-
function register(registration) {
|
|
428
|
-
const item = {
|
|
429
|
-
position: registration.position,
|
|
430
|
-
order: registration.order ?? 0,
|
|
431
|
-
...registration
|
|
432
|
-
};
|
|
433
|
-
const ticket = registry.register(item);
|
|
434
|
-
sizes.set(ticket.id, ticket.value);
|
|
435
|
-
return ticket;
|
|
436
|
-
}
|
|
437
|
-
if (IN_BROWSER && getCurrentInstance()) {
|
|
438
|
-
function resize() {
|
|
439
|
-
height.value = window.innerHeight;
|
|
440
|
-
width.value = window.innerWidth;
|
|
441
|
-
}
|
|
442
|
-
onMounted(() => {
|
|
443
|
-
resize();
|
|
444
|
-
window.addEventListener("resize", resize);
|
|
445
|
-
});
|
|
446
|
-
onUnmounted(() => {
|
|
447
|
-
window.removeEventListener("resize", resize);
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
registry.on("unregister", (item) => {
|
|
451
|
-
sizes.delete(item.id);
|
|
452
|
-
});
|
|
453
|
-
return {
|
|
454
|
-
...registry,
|
|
455
|
-
register,
|
|
456
|
-
bounds,
|
|
457
|
-
main,
|
|
458
|
-
sizes,
|
|
459
|
-
height,
|
|
460
|
-
width
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
//#endregion
|
|
465
|
-
//#region src/composables/useLocale/adapters/v0.ts
|
|
466
|
-
/**
|
|
467
|
-
* Vuetify0.x locale adapter implementation
|
|
468
|
-
*
|
|
469
|
-
* This adapter provides translation and number formatting
|
|
470
|
-
* capabilities using the Intl API and supports both
|
|
471
|
-
* numbered and named variables in translation strings.
|
|
472
|
-
*/
|
|
473
|
-
var Vuetify0LocaleAdapter = class {
|
|
474
|
-
t(message, ...params) {
|
|
475
|
-
let resolvedMessage = message;
|
|
476
|
-
if (params.length > 0 && typeof params[0] === "object" && params[0] !== null && !Array.isArray(params[0])) {
|
|
477
|
-
const variables = params[0];
|
|
478
|
-
resolvedMessage = resolvedMessage.replace(/{([a-zA-Z][a-zA-Z0-9_]*)}/g, (match, name) => {
|
|
479
|
-
return variables[name] === void 0 ? match : String(variables[name]);
|
|
480
|
-
});
|
|
481
|
-
params = params.slice(1);
|
|
482
|
-
}
|
|
483
|
-
resolvedMessage = resolvedMessage.replace(/\{(\d+)\}/g, (match, index) => {
|
|
484
|
-
const idx = Number.parseInt(index, 10);
|
|
485
|
-
if (params[idx] !== void 0) return String(params[idx]);
|
|
486
|
-
return match;
|
|
487
|
-
});
|
|
488
|
-
return resolvedMessage;
|
|
489
|
-
}
|
|
490
|
-
n(value, locale, ...params) {
|
|
491
|
-
if (!IN_BROWSER || !locale) return value.toString();
|
|
492
|
-
const options = params[0];
|
|
493
|
-
return new Intl.NumberFormat(String(locale), options).format(value);
|
|
494
|
-
}
|
|
495
|
-
};
|
|
496
|
-
|
|
497
|
-
//#endregion
|
|
498
|
-
//#region src/composables/useLocale/index.ts
|
|
499
|
-
/**
|
|
500
|
-
* Creates a locale registry for managing internationalization with translations and number formatting.
|
|
501
|
-
* Supports message resolution with token references and locale-specific number formatting.
|
|
502
|
-
*
|
|
503
|
-
* @param namespace The namespace for the locale context.
|
|
504
|
-
* @param options Configuration including adapter and messages.
|
|
505
|
-
* @template Z The type of the locale context.
|
|
506
|
-
* @template E The type of the locale items managed by the registry.
|
|
507
|
-
* @returns An array containing the inject function, provide function, and the locale context.
|
|
508
|
-
*/
|
|
509
|
-
function createLocale(namespace = "v0:locale", options = {}) {
|
|
510
|
-
const { adapter = new Vuetify0LocaleAdapter(), messages = {} } = options;
|
|
511
|
-
const [useLocaleContext, _provideLocaleContext] = createContext(namespace);
|
|
512
|
-
const registry = useSingle();
|
|
513
|
-
for (const id in messages) {
|
|
514
|
-
registry.register({
|
|
515
|
-
value: messages[id],
|
|
516
|
-
id
|
|
517
|
-
});
|
|
518
|
-
if (id === options.default && !registry.selectedId.value) registry.select(id);
|
|
519
|
-
}
|
|
520
|
-
function t(key, ...params) {
|
|
521
|
-
const locale = registry.selectedId.value;
|
|
522
|
-
if (!locale) return key;
|
|
523
|
-
const message = messages[locale]?.[key];
|
|
524
|
-
const template = typeof message === "string" ? resolve(locale, message) : key;
|
|
525
|
-
return adapter.t(template, ...params);
|
|
526
|
-
}
|
|
527
|
-
function n(value, ...params) {
|
|
528
|
-
return adapter.n(value, registry.selectedId.value, ...params);
|
|
529
|
-
}
|
|
530
|
-
function resolve(locale, str) {
|
|
531
|
-
return str.replace(/{([a-zA-Z0-9.-_]+)}/g, (match, linkedKey) => {
|
|
532
|
-
const [linkedLocale, ...rest] = linkedKey.split(".");
|
|
533
|
-
const keyPath = rest.join(".");
|
|
534
|
-
const targetLocale = messages[linkedLocale] ? linkedLocale : locale;
|
|
535
|
-
const targetKey = messages[linkedLocale] ? keyPath : linkedKey;
|
|
536
|
-
const resolved = messages[targetLocale]?.[targetKey];
|
|
537
|
-
return typeof resolved === "string" ? resolve(targetLocale, resolved) : match;
|
|
538
|
-
});
|
|
539
|
-
}
|
|
540
|
-
const context = {
|
|
541
|
-
...registry,
|
|
542
|
-
t,
|
|
543
|
-
n
|
|
544
|
-
};
|
|
545
|
-
function provideLocaleContext(_context = context, app) {
|
|
546
|
-
return _provideLocaleContext(_context, app);
|
|
547
|
-
}
|
|
548
|
-
return createTrinity(useLocaleContext, provideLocaleContext, context);
|
|
549
|
-
}
|
|
550
|
-
/**
|
|
551
|
-
* Simple hook to access the locale context.
|
|
552
|
-
*
|
|
553
|
-
* @returns The locale context containing translation and formatting functions.
|
|
554
|
-
*/
|
|
555
|
-
function useLocale() {
|
|
556
|
-
return useContext("v0:locale")();
|
|
557
|
-
}
|
|
558
|
-
/**
|
|
559
|
-
* Creates a Vue plugin for internationalization with locale management and translation support.
|
|
560
|
-
* Integrates with token system for message resolution and provides app-wide locale context.
|
|
561
|
-
*
|
|
562
|
-
* @param options Configuration for adapter, default locale, and messages.
|
|
563
|
-
* @template Z The type of the locale context.
|
|
564
|
-
* @template E The type of the locale items managed by the registry.
|
|
565
|
-
* @template R The type of the token context.
|
|
566
|
-
* @template O The type of the token items managed by the registry.
|
|
567
|
-
* @returns Vue install function for the plugin
|
|
568
|
-
*/
|
|
569
|
-
function createLocalePlugin(options = {}) {
|
|
570
|
-
const { adapter = new Vuetify0LocaleAdapter(), messages = {} } = options;
|
|
571
|
-
const [, provideLocaleTokenContext, tokensContext] = createTokensContext("v0:locale:tokens", messages);
|
|
572
|
-
const [, provideLocaleContext, localeContext] = createLocale("v0:locale", {
|
|
573
|
-
adapter,
|
|
574
|
-
messages
|
|
575
|
-
});
|
|
576
|
-
return createPlugin({
|
|
577
|
-
namespace: "v0:locale",
|
|
578
|
-
provide: (app) => {
|
|
579
|
-
provideLocaleContext(localeContext, app);
|
|
580
|
-
provideLocaleTokenContext(tokensContext, app);
|
|
581
|
-
}
|
|
582
|
-
});
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
//#endregion
|
|
586
|
-
//#region src/composables/useMutationObserver/index.ts
|
|
587
|
-
/**
|
|
588
|
-
* Composable for observing DOM mutations
|
|
589
|
-
*
|
|
590
|
-
* @param target - Element ref to observe
|
|
591
|
-
* @param callback - Callback fired on mutation
|
|
592
|
-
* @param options - Observer options
|
|
593
|
-
* @returns Observer controls
|
|
594
|
-
*
|
|
595
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
|
|
596
|
-
*/
|
|
597
|
-
function useMutationObserver(target, callback, options = {}) {
|
|
598
|
-
const { isHydrated } = useHydration();
|
|
599
|
-
const observer = shallowRef();
|
|
600
|
-
const isPaused = shallowRef(false);
|
|
601
|
-
const observerOptions = {
|
|
602
|
-
childList: options.childList ?? true,
|
|
603
|
-
attributes: options.attributes ?? false,
|
|
604
|
-
characterData: options.characterData ?? false,
|
|
605
|
-
subtree: options.subtree ?? false,
|
|
606
|
-
attributeOldValue: options.attributeOldValue ?? false,
|
|
607
|
-
characterDataOldValue: options.characterDataOldValue ?? false,
|
|
608
|
-
attributeFilter: options.attributeFilter
|
|
609
|
-
};
|
|
610
|
-
watch([isHydrated, target], ([hydrated, el]) => {
|
|
611
|
-
cleanup();
|
|
612
|
-
if (!hydrated || !SUPPORTS_MUTATION_OBSERVER || !el) return;
|
|
613
|
-
observer.value = new MutationObserver((mutations) => {
|
|
614
|
-
const transformedEntries = mutations.map((mutation) => ({
|
|
615
|
-
type: mutation.type,
|
|
616
|
-
target: mutation.target,
|
|
617
|
-
addedNodes: mutation.addedNodes,
|
|
618
|
-
removedNodes: mutation.removedNodes,
|
|
619
|
-
previousSibling: mutation.previousSibling,
|
|
620
|
-
nextSibling: mutation.nextSibling,
|
|
621
|
-
attributeName: mutation.attributeName,
|
|
622
|
-
attributeNamespace: mutation.attributeNamespace,
|
|
623
|
-
oldValue: mutation.oldValue
|
|
624
|
-
}));
|
|
625
|
-
callback(transformedEntries);
|
|
626
|
-
});
|
|
627
|
-
observer.value.observe(el, observerOptions);
|
|
628
|
-
if (options.immediate) {
|
|
629
|
-
const emptyNodeList = {
|
|
630
|
-
length: 0,
|
|
631
|
-
item: () => null,
|
|
632
|
-
forEach: () => {},
|
|
633
|
-
*[Symbol.iterator]() {}
|
|
634
|
-
};
|
|
635
|
-
const syntheticEntry = {
|
|
636
|
-
type: "childList",
|
|
637
|
-
target: el,
|
|
638
|
-
addedNodes: emptyNodeList,
|
|
639
|
-
removedNodes: emptyNodeList,
|
|
640
|
-
previousSibling: null,
|
|
641
|
-
nextSibling: null,
|
|
642
|
-
attributeName: null,
|
|
643
|
-
attributeNamespace: null,
|
|
644
|
-
oldValue: null
|
|
645
|
-
};
|
|
646
|
-
callback([syntheticEntry]);
|
|
647
|
-
}
|
|
648
|
-
}, { immediate: true });
|
|
649
|
-
function setup() {
|
|
650
|
-
if (!isHydrated.value || !SUPPORTS_MUTATION_OBSERVER || !target.value || isPaused.value) return;
|
|
651
|
-
observer.value = new MutationObserver((mutations) => {
|
|
652
|
-
const transformedEntries = mutations.map((mutation) => ({
|
|
653
|
-
type: mutation.type,
|
|
654
|
-
target: mutation.target,
|
|
655
|
-
addedNodes: mutation.addedNodes,
|
|
656
|
-
removedNodes: mutation.removedNodes,
|
|
657
|
-
previousSibling: mutation.previousSibling,
|
|
658
|
-
nextSibling: mutation.nextSibling,
|
|
659
|
-
attributeName: mutation.attributeName,
|
|
660
|
-
attributeNamespace: mutation.attributeNamespace,
|
|
661
|
-
oldValue: mutation.oldValue
|
|
662
|
-
}));
|
|
663
|
-
callback(transformedEntries);
|
|
664
|
-
});
|
|
665
|
-
observer.value.observe(target.value, observerOptions);
|
|
666
|
-
if (options.immediate) {
|
|
667
|
-
const emptyNodeList = {
|
|
668
|
-
length: 0,
|
|
669
|
-
item: () => null,
|
|
670
|
-
forEach: () => {},
|
|
671
|
-
*[Symbol.iterator]() {}
|
|
672
|
-
};
|
|
673
|
-
const syntheticEntry = {
|
|
674
|
-
type: "childList",
|
|
675
|
-
target: target.value,
|
|
676
|
-
addedNodes: emptyNodeList,
|
|
677
|
-
removedNodes: emptyNodeList,
|
|
678
|
-
previousSibling: null,
|
|
679
|
-
nextSibling: null,
|
|
680
|
-
attributeName: null,
|
|
681
|
-
attributeNamespace: null,
|
|
682
|
-
oldValue: null
|
|
683
|
-
};
|
|
684
|
-
callback([syntheticEntry]);
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
function cleanup() {
|
|
688
|
-
if (observer.value) {
|
|
689
|
-
observer.value.disconnect();
|
|
690
|
-
observer.value = void 0;
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
function pause() {
|
|
694
|
-
isPaused.value = true;
|
|
695
|
-
observer.value?.disconnect();
|
|
696
|
-
}
|
|
697
|
-
function resume() {
|
|
698
|
-
isPaused.value = false;
|
|
699
|
-
setup();
|
|
700
|
-
}
|
|
701
|
-
function stop() {
|
|
702
|
-
cleanup();
|
|
703
|
-
}
|
|
704
|
-
onUnmounted(stop);
|
|
705
|
-
return {
|
|
706
|
-
isPaused: readonly(isPaused),
|
|
707
|
-
pause,
|
|
708
|
-
resume,
|
|
709
|
-
stop
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
//#endregion
|
|
714
|
-
//#region src/composables/useProxyModel/index.ts
|
|
715
|
-
/**
|
|
716
|
-
* Creates a proxy model for two-way binding with a selection context.
|
|
717
|
-
*
|
|
718
|
-
* @param registry SelectionContext | GroupContext | SingleContext | StepContext
|
|
719
|
-
* @template Z The type of items managed by the selection.
|
|
720
|
-
* @template E The type of the selection context.
|
|
721
|
-
* @returns The proxy model for two-way binding with the selection context.
|
|
722
|
-
*/
|
|
723
|
-
function useProxyModel(registry, initial, options, _transformIn, _transformOut) {
|
|
724
|
-
const logger = useLogger();
|
|
725
|
-
const reactivity = options?.deep ? ref : shallowRef;
|
|
726
|
-
const internal = reactivity(initial ? toArray(initial) : []);
|
|
727
|
-
const isModelArray = isArray(initial);
|
|
728
|
-
function transformIn(val) {
|
|
729
|
-
if (isFunction(_transformIn)) return _transformIn(val);
|
|
730
|
-
return toArray(val);
|
|
731
|
-
}
|
|
732
|
-
function transformOut(val) {
|
|
733
|
-
if (isFunction(_transformOut)) return _transformOut(val);
|
|
734
|
-
return isModelArray ? val : val[0];
|
|
735
|
-
}
|
|
736
|
-
const model = computed({
|
|
737
|
-
get() {
|
|
738
|
-
return transformOut(internal.value);
|
|
739
|
-
},
|
|
740
|
-
set(val) {
|
|
741
|
-
internal.value = transformIn(val);
|
|
742
|
-
}
|
|
743
|
-
});
|
|
744
|
-
const watcher = watch(registry.selectedIds, (val, oldVal) => {
|
|
745
|
-
if (toRaw(val).symmetricDifference(toRaw(oldVal)).size === 0) return;
|
|
746
|
-
if (val.size === 0) {
|
|
747
|
-
model.value = [];
|
|
748
|
-
return;
|
|
749
|
-
}
|
|
750
|
-
model.value = Array.from(registry.selectedValues.value);
|
|
751
|
-
});
|
|
752
|
-
watch(model, (val) => {
|
|
753
|
-
const currentIds = new Set(toValue(registry.selectedIds));
|
|
754
|
-
const targetIds = /* @__PURE__ */ new Set();
|
|
755
|
-
for (const value of toArray(val)) {
|
|
756
|
-
const id = registry.browse(value);
|
|
757
|
-
if (id) targetIds.add(id);
|
|
758
|
-
else logger.warn("Unable to find id for value", value);
|
|
759
|
-
}
|
|
760
|
-
watcher.pause();
|
|
761
|
-
if (isModelArray) {
|
|
762
|
-
for (const id of currentIds.difference(targetIds)) registry.selectedIds.delete(id);
|
|
763
|
-
for (const id of targetIds.difference(currentIds)) registry.selectedIds.add(id);
|
|
764
|
-
} else {
|
|
765
|
-
const next = targetIds.values().next().value;
|
|
766
|
-
const last = currentIds.values().next().value;
|
|
767
|
-
registry.selectedIds.delete(last);
|
|
768
|
-
registry.selectedIds.add(next);
|
|
769
|
-
}
|
|
770
|
-
watcher.resume();
|
|
771
|
-
});
|
|
772
|
-
return model;
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
//#endregion
|
|
776
|
-
//#region src/composables/useResizeObserver/index.ts
|
|
777
|
-
/**
|
|
778
|
-
* Composable for observing element resize events
|
|
779
|
-
*
|
|
780
|
-
* @param target - Element ref to observe
|
|
781
|
-
* @param callback - Callback fired on resize
|
|
782
|
-
* @param options - Observer options
|
|
783
|
-
* @returns Observer controls
|
|
784
|
-
*
|
|
785
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
|
|
786
|
-
*/
|
|
787
|
-
function useResizeObserver(target, callback, options = {}) {
|
|
788
|
-
const { isHydrated } = useHydration();
|
|
789
|
-
const observer = shallowRef();
|
|
790
|
-
const isPaused = shallowRef(false);
|
|
791
|
-
watch([isHydrated, target], ([hydrated, el]) => {
|
|
792
|
-
cleanup();
|
|
793
|
-
if (!hydrated || !SUPPORTS_OBSERVER || !el) return;
|
|
794
|
-
observer.value = new ResizeObserver((entries) => {
|
|
795
|
-
const transformedEntries = entries.map((entry) => ({
|
|
796
|
-
contentRect: {
|
|
797
|
-
width: entry.contentRect.width,
|
|
798
|
-
height: entry.contentRect.height,
|
|
799
|
-
top: entry.contentRect.top,
|
|
800
|
-
left: entry.contentRect.left
|
|
801
|
-
},
|
|
802
|
-
target: entry.target
|
|
803
|
-
}));
|
|
804
|
-
callback(transformedEntries);
|
|
805
|
-
});
|
|
806
|
-
observer.value.observe(el, { box: options.box || "content-box" });
|
|
807
|
-
if (options.immediate) {
|
|
808
|
-
const rect = el.getBoundingClientRect();
|
|
809
|
-
callback([{
|
|
810
|
-
contentRect: {
|
|
811
|
-
width: rect.width,
|
|
812
|
-
height: rect.height,
|
|
813
|
-
top: rect.top,
|
|
814
|
-
left: rect.left
|
|
815
|
-
},
|
|
816
|
-
target: el
|
|
817
|
-
}]);
|
|
818
|
-
}
|
|
819
|
-
});
|
|
820
|
-
function setup() {
|
|
821
|
-
if (!isHydrated.value || !SUPPORTS_OBSERVER || !target.value || isPaused.value) return;
|
|
822
|
-
observer.value = new ResizeObserver((entries) => {
|
|
823
|
-
const transformedEntries = entries.map((entry) => ({
|
|
824
|
-
contentRect: {
|
|
825
|
-
width: entry.contentRect.width,
|
|
826
|
-
height: entry.contentRect.height,
|
|
827
|
-
top: entry.contentRect.top,
|
|
828
|
-
left: entry.contentRect.left
|
|
829
|
-
},
|
|
830
|
-
target: entry.target
|
|
831
|
-
}));
|
|
832
|
-
callback(transformedEntries);
|
|
833
|
-
});
|
|
834
|
-
observer.value.observe(target.value, { box: options.box || "content-box" });
|
|
835
|
-
if (options.immediate) {
|
|
836
|
-
const rect = target.value.getBoundingClientRect();
|
|
837
|
-
callback([{
|
|
838
|
-
contentRect: {
|
|
839
|
-
width: rect.width,
|
|
840
|
-
height: rect.height,
|
|
841
|
-
top: rect.top,
|
|
842
|
-
left: rect.left
|
|
843
|
-
},
|
|
844
|
-
target: target.value
|
|
845
|
-
}]);
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
function cleanup() {
|
|
849
|
-
if (observer.value) {
|
|
850
|
-
observer.value.disconnect();
|
|
851
|
-
observer.value = void 0;
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
function pause() {
|
|
855
|
-
isPaused.value = true;
|
|
856
|
-
observer.value?.disconnect();
|
|
857
|
-
}
|
|
858
|
-
function resume() {
|
|
859
|
-
isPaused.value = false;
|
|
860
|
-
setup();
|
|
861
|
-
}
|
|
862
|
-
function stop() {
|
|
863
|
-
cleanup();
|
|
864
|
-
}
|
|
865
|
-
onUnmounted(stop);
|
|
866
|
-
return {
|
|
867
|
-
isPaused: readonly(isPaused),
|
|
868
|
-
pause,
|
|
869
|
-
resume,
|
|
870
|
-
stop
|
|
871
|
-
};
|
|
872
|
-
}
|
|
873
|
-
/**
|
|
874
|
-
* Convenience composable for tracking element dimensions
|
|
875
|
-
*
|
|
876
|
-
* @param target - Element ref to observe
|
|
877
|
-
* @returns Reactive width and height
|
|
878
|
-
*/
|
|
879
|
-
function useElementSize(target) {
|
|
880
|
-
const width = shallowRef(0);
|
|
881
|
-
const height = shallowRef(0);
|
|
882
|
-
useResizeObserver(target, (entries) => {
|
|
883
|
-
const entry = entries[0];
|
|
884
|
-
if (entry) {
|
|
885
|
-
width.value = entry.contentRect.width;
|
|
886
|
-
height.value = entry.contentRect.height;
|
|
887
|
-
}
|
|
888
|
-
}, { immediate: true });
|
|
889
|
-
return {
|
|
890
|
-
width,
|
|
891
|
-
height
|
|
892
|
-
};
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
//#endregion
|
|
896
|
-
//#region src/composables/useStorage/adapters/memory.ts
|
|
897
|
-
/**
|
|
898
|
-
* In-memory storage adapter that implements the StorageAdapter interface.
|
|
899
|
-
* This adapter provides temporary storage that persists only for the current
|
|
900
|
-
* session and is useful for testing or when persistent storage is not available.
|
|
901
|
-
*/
|
|
902
|
-
var MemoryAdapter = class {
|
|
903
|
-
store = /* @__PURE__ */ new Map();
|
|
904
|
-
get length() {
|
|
905
|
-
return this.store.size;
|
|
906
|
-
}
|
|
907
|
-
getItem(key) {
|
|
908
|
-
return this.store.get(key) ?? null;
|
|
909
|
-
}
|
|
910
|
-
setItem(key, value) {
|
|
911
|
-
this.store.set(key, value);
|
|
912
|
-
}
|
|
913
|
-
removeItem(key) {
|
|
914
|
-
this.store.delete(key);
|
|
915
|
-
}
|
|
916
|
-
key(index) {
|
|
917
|
-
return Array.from(this.store.keys())[index];
|
|
918
|
-
}
|
|
919
|
-
};
|
|
920
|
-
|
|
921
|
-
//#endregion
|
|
922
|
-
//#region src/composables/useStorage/index.ts
|
|
923
|
-
const [useStorageContext, provideStorageContext] = createContext("v0:storage");
|
|
924
|
-
/**
|
|
925
|
-
* Creates a reactive storage system with automatic persistence and cross-adapter support.
|
|
926
|
-
* This function provides a consistent interface for storing and retrieving reactive values
|
|
927
|
-
* that automatically sync with the underlying storage adapter (localStorage, memory, etc.).
|
|
928
|
-
*
|
|
929
|
-
* @param options Optional configuration for storage adapter, prefix, and serialization.
|
|
930
|
-
* @template E The type of the storage context.
|
|
931
|
-
* @returns A storage context object with get, set, remove, and clear methods.
|
|
932
|
-
*/
|
|
933
|
-
function createStorage(options = {}) {
|
|
934
|
-
const { adapter = IN_BROWSER ? window.localStorage : new MemoryAdapter(), prefix = "v0:", serializer = {
|
|
935
|
-
read: JSON.parse,
|
|
936
|
-
write: JSON.stringify
|
|
937
|
-
} } = options;
|
|
938
|
-
const cache = /* @__PURE__ */ new Map();
|
|
939
|
-
function get(key, defaultValue) {
|
|
940
|
-
const prefixedKey = `${prefix}${key}`;
|
|
941
|
-
if (cache.has(prefixedKey)) return cache.get(prefixedKey);
|
|
942
|
-
const storedValue = adapter?.getItem(prefixedKey);
|
|
943
|
-
let initialValue = defaultValue;
|
|
944
|
-
if (storedValue) try {
|
|
945
|
-
initialValue = serializer.read(storedValue);
|
|
946
|
-
} catch (error) {
|
|
947
|
-
console.error(`[v0:storage] Failed to parse stored value for key "${prefixedKey}":`, error);
|
|
948
|
-
}
|
|
949
|
-
const valueRef = ref(initialValue);
|
|
950
|
-
watch(valueRef, (newValue) => {
|
|
951
|
-
if (newValue === void 0 || newValue === null) adapter?.removeItem(prefixedKey);
|
|
952
|
-
else adapter?.setItem(prefixedKey, serializer.write(newValue));
|
|
953
|
-
}, { deep: true });
|
|
954
|
-
cache.set(prefixedKey, valueRef);
|
|
955
|
-
return valueRef;
|
|
956
|
-
}
|
|
957
|
-
function set(key, value) {
|
|
958
|
-
const valueRef = get(key);
|
|
959
|
-
valueRef.value = value;
|
|
960
|
-
}
|
|
961
|
-
function remove(key) {
|
|
962
|
-
const prefixedKey = `${prefix}${key}`;
|
|
963
|
-
adapter?.removeItem(prefixedKey);
|
|
964
|
-
cache.delete(prefixedKey);
|
|
965
|
-
}
|
|
966
|
-
function clear() {
|
|
967
|
-
for (const key of cache.keys()) adapter?.removeItem(key);
|
|
968
|
-
cache.clear();
|
|
969
|
-
}
|
|
970
|
-
return {
|
|
971
|
-
get,
|
|
972
|
-
set,
|
|
973
|
-
remove,
|
|
974
|
-
clear
|
|
975
|
-
};
|
|
976
|
-
}
|
|
977
|
-
/**
|
|
978
|
-
* Simple hook to access the storage context.
|
|
979
|
-
*
|
|
980
|
-
* @returns The storage context containing reactive storage methods.
|
|
981
|
-
*/
|
|
982
|
-
function useStorage() {
|
|
983
|
-
return useStorageContext();
|
|
984
|
-
}
|
|
985
|
-
/**
|
|
986
|
-
* Creates a Vue plugin for reactive storage capabilities with automatic persistence.
|
|
987
|
-
* Provides app-wide access to reactive storage that syncs with the configured adapter.
|
|
988
|
-
*
|
|
989
|
-
* @param options Optional configuration for the storage system.
|
|
990
|
-
* @returns A Vue plugin object with install method.
|
|
991
|
-
*/
|
|
992
|
-
function createStoragePlugin(options = {}) {
|
|
993
|
-
const context = createStorage(options);
|
|
994
|
-
return createPlugin({
|
|
995
|
-
namespace: "v0:storage",
|
|
996
|
-
provide: (app) => {
|
|
997
|
-
provideStorageContext(context, app);
|
|
998
|
-
}
|
|
999
|
-
});
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
//#endregion
|
|
1003
|
-
export { createLocale, createLocalePlugin, createStorage, createStoragePlugin, provideStorageContext, useDocumentEventListener, useElementIntersection, useElementSize, useEventListener, useFilter, useForm, useIntersectionObserver, useKeydown, useLayout, useLocale, useMutationObserver, useProxyModel, useResizeObserver, useStorage, useStorageContext, useWindowEventListener };
|