@vuetify/v0 0.0.2-beta.4 → 0.0.3
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 +251 -0
- package/dist/browser/index.js +3199 -0
- package/dist/components/index.d.ts +7 -0
- package/dist/components/index.js +8 -0
- package/dist/{components-B5iiovK7.mjs → components-DVuB4lnH.js} +16 -217
- package/dist/composables/index.d.ts +7 -0
- package/dist/composables/index.js +8 -0
- package/dist/composables-yeVk-ULz.js +1270 -0
- package/dist/constants/index.d.ts +2 -0
- package/dist/constants/index.js +5 -0
- package/dist/constants-DiTCgvMU.js +1 -0
- package/dist/factories/index.d.ts +2 -0
- package/dist/factories/index.js +3 -0
- package/dist/{createTrinity-CwGvQ2ng.mjs → factories-BEpawPUw.js} +32 -15
- package/dist/globals-DZvNEOB4.js +12 -0
- package/dist/htmlElements-SjqYu0am.js +78 -0
- package/dist/{index-D4Grk5x1.d.mts → index-BozA2pze.d.ts} +1 -1
- package/dist/index-Ckt12ON6.d.ts +75 -0
- package/dist/index-D0L_ydyW.d.ts +1396 -0
- package/dist/index-DVKeyWc5.d.ts +79 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +11 -0
- package/dist/transformers/index.d.ts +2 -0
- package/dist/transformers/index.js +4 -0
- package/dist/{transformers-BTjuwbOV.mjs → transformers-CWrxLIkw.js} +2 -2
- package/dist/types/{index.d.mts → index.d.ts} +1 -1
- package/dist/types/index.js +1 -0
- package/dist/{useTheme-tY7MoBKr.mjs → useTheme-DCXkw_kv.js} +214 -204
- package/dist/utilities/{index.d.mts → index.d.ts} +2 -2
- package/dist/utilities/{index.mjs → index.js} +1 -1
- package/package.json +20 -35
- package/dist/components/index.d.mts +0 -5
- package/dist/components/index.mjs +0 -7
- package/dist/composables/index.d.mts +0 -5
- package/dist/composables/index.mjs +0 -7
- package/dist/composables-C6dl5kjP.mjs +0 -614
- package/dist/factories/index.d.mts +0 -3
- package/dist/factories/index.mjs +0 -4
- package/dist/factories-DOLmqhVS.mjs +0 -0
- package/dist/index-ChaaTPKp.d.mts +0 -421
- package/dist/index-Cya5Y9pB.d.mts +0 -412
- package/dist/index-DfahEz6s.d.mts +0 -18
- package/dist/index-jG0yrC1F.d.mts +0 -467
- package/dist/index-oCBJwhpG.d.mts +0 -43
- package/dist/index.d.mts +0 -9
- package/dist/index.mjs +0 -9
- package/dist/transformers/index.d.mts +0 -2
- package/dist/transformers/index.mjs +0 -4
- package/dist/types/index.mjs +0 -0
- /package/dist/{index-BA3ZFBnL.d.mts → index-LBy5OPMu.d.ts} +0 -0
- /package/dist/{index-CZRh0I2w.d.mts → index-tUyghL98.d.ts} +0 -0
- /package/dist/{utilities-lZSfrXgw.mjs → utilities-D9rWEgQK.js} +0 -0
|
@@ -0,0 +1,3199 @@
|
|
|
1
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createPropsRestProxy, defineComponent, getCurrentInstance, getCurrentScope, guardReactiveProps, inject, isRef, mergeModels, mergeProps, normalizeProps, normalizeStyle, onMounted, onScopeDispose, onUnmounted, openBlock, provide, reactive, readonly, ref, renderSlot, resolveDynamicComponent, shallowReactive, shallowReadonly, shallowRef, toRaw, toRef, toValue, unref, useAttrs, useId, useModel, useTemplateRef, watch, withCtx } from "vue";
|
|
2
|
+
|
|
3
|
+
//#region src/constants/htmlElements.ts
|
|
4
|
+
const selfClosingTags = [
|
|
5
|
+
"area",
|
|
6
|
+
"base",
|
|
7
|
+
"br",
|
|
8
|
+
"col",
|
|
9
|
+
"embed",
|
|
10
|
+
"hr",
|
|
11
|
+
"img",
|
|
12
|
+
"input",
|
|
13
|
+
"link",
|
|
14
|
+
"meta",
|
|
15
|
+
"source",
|
|
16
|
+
"track",
|
|
17
|
+
"wbr"
|
|
18
|
+
];
|
|
19
|
+
/**
|
|
20
|
+
* Set of HTML elements that are self-closing (void elements)
|
|
21
|
+
* These elements cannot have children and don't need closing tags
|
|
22
|
+
*/
|
|
23
|
+
const SELF_CLOSING_TAGS = new Set(selfClosingTags);
|
|
24
|
+
/**
|
|
25
|
+
* Common HTML element types for polymorphic components
|
|
26
|
+
*/
|
|
27
|
+
const COMMON_ELEMENTS = {
|
|
28
|
+
DIV: "div",
|
|
29
|
+
SPAN: "span",
|
|
30
|
+
SECTION: "section",
|
|
31
|
+
ARTICLE: "article",
|
|
32
|
+
ASIDE: "aside",
|
|
33
|
+
HEADER: "header",
|
|
34
|
+
FOOTER: "footer",
|
|
35
|
+
MAIN: "main",
|
|
36
|
+
NAV: "nav",
|
|
37
|
+
P: "p",
|
|
38
|
+
H1: "h1",
|
|
39
|
+
H2: "h2",
|
|
40
|
+
H3: "h3",
|
|
41
|
+
H4: "h4",
|
|
42
|
+
H5: "h5",
|
|
43
|
+
H6: "h6",
|
|
44
|
+
BUTTON: "button",
|
|
45
|
+
A: "a",
|
|
46
|
+
INPUT: "input",
|
|
47
|
+
TEXTAREA: "textarea",
|
|
48
|
+
SELECT: "select",
|
|
49
|
+
LABEL: "label",
|
|
50
|
+
UL: "ul",
|
|
51
|
+
OL: "ol",
|
|
52
|
+
LI: "li",
|
|
53
|
+
DL: "dl",
|
|
54
|
+
DT: "dt",
|
|
55
|
+
DD: "dd",
|
|
56
|
+
IMG: "img",
|
|
57
|
+
VIDEO: "video",
|
|
58
|
+
AUDIO: "audio",
|
|
59
|
+
CANVAS: "canvas",
|
|
60
|
+
SVG: "svg",
|
|
61
|
+
TABLE: "table",
|
|
62
|
+
THEAD: "thead",
|
|
63
|
+
TBODY: "tbody",
|
|
64
|
+
TFOOT: "tfoot",
|
|
65
|
+
TR: "tr",
|
|
66
|
+
TH: "th",
|
|
67
|
+
TD: "td",
|
|
68
|
+
FORM: "form",
|
|
69
|
+
FIELDSET: "fieldset",
|
|
70
|
+
LEGEND: "legend"
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Check if an element is self-closing
|
|
74
|
+
*/
|
|
75
|
+
function isSelfClosingTag(tag) {
|
|
76
|
+
return SELF_CLOSING_TAGS.has(tag.toLowerCase());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/components/Atom/Atom.vue?vue&type=script&setup=true&lang.ts
|
|
81
|
+
var Atom_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
82
|
+
name: "Atom",
|
|
83
|
+
__name: "Atom",
|
|
84
|
+
props: {
|
|
85
|
+
as: { default: "div" },
|
|
86
|
+
renderless: {
|
|
87
|
+
type: Boolean,
|
|
88
|
+
default: false
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
setup(__props, { expose: __expose }) {
|
|
92
|
+
const element = useTemplateRef("element");
|
|
93
|
+
__expose({ element });
|
|
94
|
+
const attrs = useAttrs();
|
|
95
|
+
const isSelfClosing = toRef(() => typeof __props.as === "string" && isSelfClosingTag(__props.as));
|
|
96
|
+
const slotProps = toRef(() => attrs);
|
|
97
|
+
return (_ctx, _cache) => {
|
|
98
|
+
return _ctx.renderless || _ctx.as === null ? renderSlot(_ctx.$slots, "default", normalizeProps(mergeProps({ key: 0 }, slotProps.value))) : !isSelfClosing.value ? (openBlock(), createBlock(resolveDynamicComponent(_ctx.as), mergeProps({ key: 1 }, slotProps.value, {
|
|
99
|
+
ref_key: "element",
|
|
100
|
+
ref: element
|
|
101
|
+
}), {
|
|
102
|
+
default: withCtx(() => [!isSelfClosing.value ? renderSlot(_ctx.$slots, "default", normalizeProps(mergeProps({ key: 0 }, slotProps.value))) : createCommentVNode("v-if", true)]),
|
|
103
|
+
_: 3
|
|
104
|
+
}, 16)) : (openBlock(), createBlock(resolveDynamicComponent(_ctx.as), mergeProps({
|
|
105
|
+
key: 2,
|
|
106
|
+
ref_key: "element",
|
|
107
|
+
ref: element
|
|
108
|
+
}, slotProps.value), null, 16));
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/components/Atom/Atom.vue
|
|
115
|
+
var Atom_default = Atom_vue_vue_type_script_setup_true_lang_default;
|
|
116
|
+
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region src/factories/createContext/index.ts
|
|
119
|
+
/**
|
|
120
|
+
* A simple wrapper for tapping into a v0 namespace
|
|
121
|
+
* @param key The provided string or InjectionKey
|
|
122
|
+
* @template Z The type values for the context.
|
|
123
|
+
* @returns The injected context
|
|
124
|
+
* @throws Error if namespace is not found.
|
|
125
|
+
*
|
|
126
|
+
* @see https://vuejs.org/api/composition-api-dependency-injection.html#inject
|
|
127
|
+
* @see https://0.vuetifyjs.com/composables/foundation/create-context
|
|
128
|
+
*/
|
|
129
|
+
function useContext(key) {
|
|
130
|
+
const context = inject(key, void 0);
|
|
131
|
+
if (context === void 0) throw new Error(`Context "${String(key)}" not found. Ensure it's provided by an ancestor.`);
|
|
132
|
+
return context;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* A simple wrapper for providing Vue context.
|
|
136
|
+
*
|
|
137
|
+
* @param key The provided string or InjectionKey
|
|
138
|
+
* @param context The context value to provide
|
|
139
|
+
* @param app Optional Vue app instance for global provide
|
|
140
|
+
* @returns The provided context
|
|
141
|
+
*
|
|
142
|
+
* @see https://vuejs.org/api/composition-api-dependency-injection.html#provide
|
|
143
|
+
* @see https://0.vuetifyjs.com/composables/foundation/create-context
|
|
144
|
+
*/
|
|
145
|
+
function provideContext(key, context, app) {
|
|
146
|
+
app?.provide(key, context) ?? provide(key, context);
|
|
147
|
+
return context;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* A simple wrapper for Vues provide & inject systems
|
|
151
|
+
*
|
|
152
|
+
* @param key The provided string or InjectionKey
|
|
153
|
+
* @template Z The type values for the context.
|
|
154
|
+
* @returns A tuple containing provide/inject
|
|
155
|
+
*
|
|
156
|
+
* @see https://vuejs.org/api/composition-api-dependency-injection.html#provide
|
|
157
|
+
* @see https://0.vuetifyjs.com/composables/foundation/create-context
|
|
158
|
+
*/
|
|
159
|
+
function createContext(_key) {
|
|
160
|
+
function _provideContext(context, app) {
|
|
161
|
+
return provideContext(_key, context, app);
|
|
162
|
+
}
|
|
163
|
+
function _useContext(key = _key) {
|
|
164
|
+
return useContext(key);
|
|
165
|
+
}
|
|
166
|
+
return [_useContext, _provideContext];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region src/factories/createPlugin/index.ts
|
|
171
|
+
/**
|
|
172
|
+
* A universal plugin factory to reduce boilerplate code for Vue plugin creation
|
|
173
|
+
* @param options Configurable object with namespace and provide/setup methods
|
|
174
|
+
* @returns A Vue plugin object with install method that runs app w/ context
|
|
175
|
+
*
|
|
176
|
+
* @see https://vuejs.org/guide/reusability/plugins
|
|
177
|
+
* @see https://vuejs.org/api/application.html#app-runwithcontext
|
|
178
|
+
* @see https://0.vuetifyjs.com/factories/create-plugin
|
|
179
|
+
*/
|
|
180
|
+
function createPlugin(options) {
|
|
181
|
+
return { install(app) {
|
|
182
|
+
app.runWithContext(() => {
|
|
183
|
+
options.provide(app);
|
|
184
|
+
options.setup?.(app);
|
|
185
|
+
});
|
|
186
|
+
} };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/composables/useHydration/index.ts
|
|
191
|
+
const [useHydrationContext, provideHydrationContext] = createContext("v0:hydration");
|
|
192
|
+
/**
|
|
193
|
+
* Creates a hydration context for tracking client-side hydration state in SSR applications.
|
|
194
|
+
* This function provides a way to determine when the application has been fully hydrated
|
|
195
|
+
* on the client side, which is essential for SSR/SSG compatibility.
|
|
196
|
+
*
|
|
197
|
+
* @returns A hydration context object with reactive state and hydration control.
|
|
198
|
+
*/
|
|
199
|
+
function createHydration() {
|
|
200
|
+
const isHydrated = shallowRef(false);
|
|
201
|
+
function hydrate() {
|
|
202
|
+
isHydrated.value = true;
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
isHydrated: shallowReadonly(isHydrated),
|
|
206
|
+
hydrate
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Simple hook to access the hydration context.
|
|
211
|
+
*
|
|
212
|
+
* @returns The hydration context containing hydration state and controls.
|
|
213
|
+
*/
|
|
214
|
+
function useHydration() {
|
|
215
|
+
return useHydrationContext();
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Creates a Vue plugin for hydration state management in SSR/SSG applications.
|
|
219
|
+
* This plugin automatically detects when the root component is mounted and
|
|
220
|
+
* triggers the hydration process, ensuring proper client-side hydration timing.
|
|
221
|
+
*
|
|
222
|
+
* @returns A Vue plugin object with install method.
|
|
223
|
+
*/
|
|
224
|
+
function createHydrationPlugin() {
|
|
225
|
+
const context = createHydration();
|
|
226
|
+
return createPlugin({
|
|
227
|
+
namespace: "v0:hydration",
|
|
228
|
+
provide: (app) => {
|
|
229
|
+
provideHydrationContext(context, app);
|
|
230
|
+
},
|
|
231
|
+
setup: (app) => {
|
|
232
|
+
app.mixin({ mounted() {
|
|
233
|
+
if (this.$parent !== null) return;
|
|
234
|
+
context.hydrate();
|
|
235
|
+
} });
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region src/utilities/helpers.ts
|
|
242
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
243
|
+
function isFunction(item) {
|
|
244
|
+
return typeof item === "function";
|
|
245
|
+
}
|
|
246
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
247
|
+
function isString(item) {
|
|
248
|
+
return typeof item === "string";
|
|
249
|
+
}
|
|
250
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
251
|
+
function isNumber(item) {
|
|
252
|
+
return typeof item === "number";
|
|
253
|
+
}
|
|
254
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
255
|
+
function isBoolean(item) {
|
|
256
|
+
return typeof item === "boolean";
|
|
257
|
+
}
|
|
258
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
259
|
+
function isObject(item) {
|
|
260
|
+
return typeof item === "object" && item !== null && !Array.isArray(item);
|
|
261
|
+
}
|
|
262
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
263
|
+
function isArray(item) {
|
|
264
|
+
return Array.isArray(item);
|
|
265
|
+
}
|
|
266
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
267
|
+
function isNullOrUndefined(item) {
|
|
268
|
+
return item == null;
|
|
269
|
+
}
|
|
270
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
271
|
+
function isPrimitive(item) {
|
|
272
|
+
return typeof item === "string" || typeof item === "number" || typeof item === "boolean";
|
|
273
|
+
}
|
|
274
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
275
|
+
function mergeDeep(target, ...sources) {
|
|
276
|
+
if (sources.length === 0) return target;
|
|
277
|
+
const source = sources.shift();
|
|
278
|
+
if (/* @__PURE__ */ isObject(target) && /* @__PURE__ */ isObject(source)) {
|
|
279
|
+
for (const key in source) if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
280
|
+
const sourceValue = source[key];
|
|
281
|
+
const targetValue = target[key];
|
|
282
|
+
if (/* @__PURE__ */ isObject(sourceValue)) {
|
|
283
|
+
if (!/* @__PURE__ */ isObject(targetValue)) Object.assign(target, { [key]: {} });
|
|
284
|
+
} else Object.assign(target, { [key]: sourceValue });
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return /* @__PURE__ */ mergeDeep(target, ...sources);
|
|
288
|
+
}
|
|
289
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
290
|
+
function genId() {
|
|
291
|
+
return Math.random().toString(36).slice(2, 9);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
//#endregion
|
|
295
|
+
//#region src/constants/globals.ts
|
|
296
|
+
const IN_BROWSER = typeof window !== "undefined";
|
|
297
|
+
const SUPPORTS_TOUCH = IN_BROWSER && ("ontouchstart" in window || window.navigator.maxTouchPoints > 0);
|
|
298
|
+
const SUPPORTS_MATCH_MEDIA = IN_BROWSER && "matchMedia" in window && typeof window.matchMedia === "function";
|
|
299
|
+
const SUPPORTS_OBSERVER = IN_BROWSER && "ResizeObserver" in window;
|
|
300
|
+
const SUPPORTS_INTERSECTION_OBSERVER = IN_BROWSER && "IntersectionObserver" in window;
|
|
301
|
+
const SUPPORTS_MUTATION_OBSERVER = IN_BROWSER && "MutationObserver" in window;
|
|
302
|
+
const version = "0.0.3";
|
|
303
|
+
const __LOGGER_ENABLED__ = false;
|
|
304
|
+
|
|
305
|
+
//#endregion
|
|
306
|
+
//#region src/composables/useBreakpoints/index.ts
|
|
307
|
+
const [useBreakpointsContext, provideBreakpointsContext] = createContext("v0:breakpoints");
|
|
308
|
+
/**
|
|
309
|
+
* Simple hook to access the breakpoints context.
|
|
310
|
+
*
|
|
311
|
+
* @returns The breakpoints context containing current breakpoint information.
|
|
312
|
+
*/
|
|
313
|
+
function useBreakpoints() {
|
|
314
|
+
return useBreakpointsContext();
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Creates default breakpoint configuration.
|
|
318
|
+
*
|
|
319
|
+
* @returns The default breakpoint configuration object.
|
|
320
|
+
*/
|
|
321
|
+
function createDefaultBreakpoints() {
|
|
322
|
+
return {
|
|
323
|
+
mobileBreakpoint: "md",
|
|
324
|
+
breakpoints: {
|
|
325
|
+
xs: 0,
|
|
326
|
+
sm: 600,
|
|
327
|
+
md: 960,
|
|
328
|
+
lg: 1280,
|
|
329
|
+
xl: 1920,
|
|
330
|
+
xxl: 2560
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Creates a reactive breakpoints system for responsive behavior management.
|
|
336
|
+
* This function provides access to viewport dimensions, breakpoint detection, and helper flags
|
|
337
|
+
* for determining current screen size and implementing responsive logic.
|
|
338
|
+
*
|
|
339
|
+
* @param options Optional configuration for breakpoint thresholds and mobile breakpoint.
|
|
340
|
+
* @returns A breakpoints context object with reactive state and utility methods.
|
|
341
|
+
*/
|
|
342
|
+
function createBreakpoints(options = {}) {
|
|
343
|
+
const defaults = createDefaultBreakpoints();
|
|
344
|
+
const { mobileBreakpoint, breakpoints } = mergeDeep(defaults, options);
|
|
345
|
+
const sorted = Object.entries(breakpoints).sort((a, b) => a[1] - b[1]);
|
|
346
|
+
const names = sorted.map(([n]) => n);
|
|
347
|
+
const mb = typeof mobileBreakpoint === "number" ? mobileBreakpoint : breakpoints[mobileBreakpoint] ?? breakpoints.md;
|
|
348
|
+
const name = shallowRef("xs");
|
|
349
|
+
const width = shallowRef(0);
|
|
350
|
+
const height = shallowRef(0);
|
|
351
|
+
const isMobile = shallowRef(true);
|
|
352
|
+
const xs = shallowRef(true);
|
|
353
|
+
const sm = shallowRef(false);
|
|
354
|
+
const md = shallowRef(false);
|
|
355
|
+
const lg = shallowRef(false);
|
|
356
|
+
const xl = shallowRef(false);
|
|
357
|
+
const xxl = shallowRef(false);
|
|
358
|
+
const smAndUp = shallowRef(false);
|
|
359
|
+
const mdAndUp = shallowRef(false);
|
|
360
|
+
const lgAndUp = shallowRef(false);
|
|
361
|
+
const xlAndUp = shallowRef(false);
|
|
362
|
+
const xxlAndUp = shallowRef(false);
|
|
363
|
+
const smAndDown = shallowRef(true);
|
|
364
|
+
const mdAndDown = shallowRef(true);
|
|
365
|
+
const lgAndDown = shallowRef(true);
|
|
366
|
+
const xlAndDown = shallowRef(true);
|
|
367
|
+
const xxlAndDown = shallowRef(true);
|
|
368
|
+
function update() {
|
|
369
|
+
if (!IN_BROWSER) return;
|
|
370
|
+
width.value = window.innerWidth;
|
|
371
|
+
height.value = window.innerHeight;
|
|
372
|
+
let current = "xs";
|
|
373
|
+
for (let i = sorted.length - 1; i >= 0; i--) if (width.value >= sorted[i][1]) {
|
|
374
|
+
current = sorted[i][0];
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
name.value = current;
|
|
378
|
+
const index = names.indexOf(current);
|
|
379
|
+
isMobile.value = width.value < mb;
|
|
380
|
+
xs.value = index === 0;
|
|
381
|
+
sm.value = index === 1;
|
|
382
|
+
md.value = index === 2;
|
|
383
|
+
lg.value = index === 3;
|
|
384
|
+
xl.value = index === 4;
|
|
385
|
+
xxl.value = index === 5;
|
|
386
|
+
smAndUp.value = index >= 1;
|
|
387
|
+
mdAndUp.value = index >= 2;
|
|
388
|
+
lgAndUp.value = index >= 3;
|
|
389
|
+
xlAndUp.value = index >= 4;
|
|
390
|
+
xxlAndUp.value = index >= 5;
|
|
391
|
+
smAndDown.value = index <= 1;
|
|
392
|
+
mdAndDown.value = index <= 2;
|
|
393
|
+
lgAndDown.value = index <= 3;
|
|
394
|
+
xlAndDown.value = index <= 4;
|
|
395
|
+
xxlAndDown.value = index <= 5;
|
|
396
|
+
}
|
|
397
|
+
if (getCurrentInstance()) onMounted(() => {
|
|
398
|
+
const { isHydrated } = useHydration();
|
|
399
|
+
if (isHydrated.value) update();
|
|
400
|
+
watch(isHydrated, (hydrated) => {
|
|
401
|
+
if (hydrated) update();
|
|
402
|
+
}, { immediate: true });
|
|
403
|
+
});
|
|
404
|
+
if (IN_BROWSER) {
|
|
405
|
+
function listener() {
|
|
406
|
+
update();
|
|
407
|
+
}
|
|
408
|
+
window.addEventListener("resize", listener, { passive: true });
|
|
409
|
+
if (getCurrentInstance()) onScopeDispose(() => window.removeEventListener("resize", listener));
|
|
410
|
+
}
|
|
411
|
+
return {
|
|
412
|
+
breakpoints,
|
|
413
|
+
name: readonly(name),
|
|
414
|
+
width: readonly(width),
|
|
415
|
+
height: readonly(height),
|
|
416
|
+
isMobile: readonly(isMobile),
|
|
417
|
+
xs: readonly(xs),
|
|
418
|
+
sm: readonly(sm),
|
|
419
|
+
md: readonly(md),
|
|
420
|
+
lg: readonly(lg),
|
|
421
|
+
xl: readonly(xl),
|
|
422
|
+
xxl: readonly(xxl),
|
|
423
|
+
smAndUp: readonly(smAndUp),
|
|
424
|
+
mdAndUp: readonly(mdAndUp),
|
|
425
|
+
lgAndUp: readonly(lgAndUp),
|
|
426
|
+
xlAndUp: readonly(xlAndUp),
|
|
427
|
+
xxlAndUp: readonly(xxlAndUp),
|
|
428
|
+
smAndDown: readonly(smAndDown),
|
|
429
|
+
mdAndDown: readonly(mdAndDown),
|
|
430
|
+
lgAndDown: readonly(lgAndDown),
|
|
431
|
+
xlAndDown: readonly(xlAndDown),
|
|
432
|
+
xxlAndDown: readonly(xxlAndDown),
|
|
433
|
+
update
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Creates a Vue plugin for managing responsive breakpoints with automatic updates.
|
|
438
|
+
* This plugin sets up breakpoint tracking and updates the context when the window
|
|
439
|
+
* is resized, providing reactive breakpoint state throughout the application.
|
|
440
|
+
*
|
|
441
|
+
* @param options Optional configuration for breakpoint thresholds and mobile breakpoint.
|
|
442
|
+
* @returns A Vue plugin object with install method.
|
|
443
|
+
*/
|
|
444
|
+
function createBreakpointsPlugin(options = {}) {
|
|
445
|
+
const context = createBreakpoints(options);
|
|
446
|
+
return createPlugin({
|
|
447
|
+
namespace: "v0:breakpoints",
|
|
448
|
+
provide: (app) => {
|
|
449
|
+
provideBreakpointsContext(context, app);
|
|
450
|
+
},
|
|
451
|
+
setup: (app) => {
|
|
452
|
+
app.mixin({ mounted() {
|
|
453
|
+
context.update();
|
|
454
|
+
} });
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
//#endregion
|
|
460
|
+
//#region src/components/Breakpoints/BreakpointsItem.vue?vue&type=script&setup=true&lang.ts
|
|
461
|
+
var BreakpointsItem_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
462
|
+
name: "BreakpointsItem",
|
|
463
|
+
__name: "BreakpointsItem",
|
|
464
|
+
setup(__props) {
|
|
465
|
+
const breakpointsContext = useBreakpoints();
|
|
466
|
+
return (_ctx, _cache) => {
|
|
467
|
+
return openBlock(), createElementBlock(Fragment, null, [_ctx.$slots.xs && unref(breakpointsContext).xs ? renderSlot(_ctx.$slots, "xs", normalizeProps(mergeProps({ key: 0 }, unref(breakpointsContext)))) : _ctx.$slots.sm && unref(breakpointsContext).sm ? renderSlot(_ctx.$slots, "sm", normalizeProps(mergeProps({ key: 1 }, unref(breakpointsContext)))) : _ctx.$slots.md && unref(breakpointsContext).md ? renderSlot(_ctx.$slots, "md", normalizeProps(mergeProps({ key: 2 }, unref(breakpointsContext)))) : _ctx.$slots.lg && unref(breakpointsContext).lg ? renderSlot(_ctx.$slots, "lg", normalizeProps(mergeProps({ key: 3 }, unref(breakpointsContext)))) : _ctx.$slots.xl && unref(breakpointsContext).xl ? renderSlot(_ctx.$slots, "xl", normalizeProps(mergeProps({ key: 4 }, unref(breakpointsContext)))) : _ctx.$slots.xxl && unref(breakpointsContext).xxl ? renderSlot(_ctx.$slots, "xxl", normalizeProps(mergeProps({ key: 5 }, unref(breakpointsContext)))) : createCommentVNode("v-if", true), renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps(unref(breakpointsContext))))], 64);
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
//#endregion
|
|
473
|
+
//#region src/components/Breakpoints/BreakpointsItem.vue
|
|
474
|
+
var BreakpointsItem_default = BreakpointsItem_vue_vue_type_script_setup_true_lang_default;
|
|
475
|
+
|
|
476
|
+
//#endregion
|
|
477
|
+
//#region src/components/Breakpoints/BreakpointsRoot.vue?vue&type=script&setup=true&lang.ts
|
|
478
|
+
var BreakpointsRoot_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
479
|
+
name: "BreakpointsRoot",
|
|
480
|
+
__name: "BreakpointsRoot",
|
|
481
|
+
props: {
|
|
482
|
+
mobileBreakpoint: {},
|
|
483
|
+
breakpoints: {}
|
|
484
|
+
},
|
|
485
|
+
setup(__props) {
|
|
486
|
+
const breakpointsContext = createBreakpoints(__props);
|
|
487
|
+
provideBreakpointsContext(breakpointsContext);
|
|
488
|
+
return (_ctx, _cache) => {
|
|
489
|
+
return renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps(unref(breakpointsContext))));
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
//#endregion
|
|
495
|
+
//#region src/components/Breakpoints/BreakpointsRoot.vue
|
|
496
|
+
var BreakpointsRoot_default = BreakpointsRoot_vue_vue_type_script_setup_true_lang_default;
|
|
497
|
+
|
|
498
|
+
//#endregion
|
|
499
|
+
//#region src/components/Breakpoints/index.ts
|
|
500
|
+
const Breakpoints = {
|
|
501
|
+
Item: BreakpointsItem_default,
|
|
502
|
+
Root: BreakpointsRoot_default
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
//#endregion
|
|
506
|
+
//#region src/components/Context/ContextItem.vue?vue&type=script&setup=true&lang.ts
|
|
507
|
+
var ContextItem_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
508
|
+
name: "ContextItem",
|
|
509
|
+
__name: "ContextItem",
|
|
510
|
+
props: {
|
|
511
|
+
contextKey: {},
|
|
512
|
+
value: {}
|
|
513
|
+
},
|
|
514
|
+
setup(__props) {
|
|
515
|
+
let contextValue;
|
|
516
|
+
if (__props.value !== void 0) contextValue = __props.value;
|
|
517
|
+
else if (__props.contextKey) {
|
|
518
|
+
const [injectContext] = createContext(__props.contextKey);
|
|
519
|
+
contextValue = injectContext();
|
|
520
|
+
} else throw new Error("Context component requires either a \"value\" prop or a \"contextKey\" prop");
|
|
521
|
+
const bindableProps = toRef(() => ({ value: contextValue }));
|
|
522
|
+
return (_ctx, _cache) => {
|
|
523
|
+
return renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps(bindableProps.value)));
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
//#endregion
|
|
529
|
+
//#region src/components/Context/ContextItem.vue
|
|
530
|
+
var ContextItem_default = ContextItem_vue_vue_type_script_setup_true_lang_default;
|
|
531
|
+
|
|
532
|
+
//#endregion
|
|
533
|
+
//#region src/components/Context/ContextRoot.vue?vue&type=script&setup=true&lang.ts
|
|
534
|
+
var ContextRoot_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
535
|
+
name: "ContextRoot",
|
|
536
|
+
__name: "ContextRoot",
|
|
537
|
+
props: {
|
|
538
|
+
contextKey: {},
|
|
539
|
+
value: {}
|
|
540
|
+
},
|
|
541
|
+
setup(__props) {
|
|
542
|
+
const [, provideContext$1] = createContext(__props.contextKey);
|
|
543
|
+
provideContext$1(__props.value);
|
|
544
|
+
return (_ctx, _cache) => {
|
|
545
|
+
return renderSlot(_ctx.$slots, "default");
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
//#endregion
|
|
551
|
+
//#region src/components/Context/ContextRoot.vue
|
|
552
|
+
var ContextRoot_default = ContextRoot_vue_vue_type_script_setup_true_lang_default;
|
|
553
|
+
|
|
554
|
+
//#endregion
|
|
555
|
+
//#region src/components/Context/index.ts
|
|
556
|
+
const Context = {
|
|
557
|
+
Item: ContextItem_default,
|
|
558
|
+
Root: ContextRoot_default
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
//#endregion
|
|
562
|
+
//#region src/components/Hydration/Hydration.vue?vue&type=script&setup=true&lang.ts
|
|
563
|
+
var Hydration_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
564
|
+
name: "Hydration",
|
|
565
|
+
__name: "Hydration",
|
|
566
|
+
setup(__props) {
|
|
567
|
+
const hydrationContext = useHydration();
|
|
568
|
+
return (_ctx, _cache) => {
|
|
569
|
+
return renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps(unref(hydrationContext))));
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
//#endregion
|
|
575
|
+
//#region src/components/Hydration/Hydration.vue
|
|
576
|
+
var Hydration_default = Hydration_vue_vue_type_script_setup_true_lang_default;
|
|
577
|
+
|
|
578
|
+
//#endregion
|
|
579
|
+
//#region src/components/Hydration/HydrationRoot.vue?vue&type=script&setup=true&lang.ts
|
|
580
|
+
var HydrationRoot_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
581
|
+
name: "HydrationRoot",
|
|
582
|
+
__name: "HydrationRoot",
|
|
583
|
+
setup(__props) {
|
|
584
|
+
const hydrationContext = createHydration();
|
|
585
|
+
provideHydrationContext(hydrationContext);
|
|
586
|
+
return (_ctx, _cache) => {
|
|
587
|
+
return renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps(unref(hydrationContext))));
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
//#endregion
|
|
593
|
+
//#region src/components/Hydration/HydrationRoot.vue
|
|
594
|
+
var HydrationRoot_default = HydrationRoot_vue_vue_type_script_setup_true_lang_default;
|
|
595
|
+
|
|
596
|
+
//#endregion
|
|
597
|
+
//#region src/components/Popover/PopoverRoot.vue?vue&type=script&setup=true&lang.ts
|
|
598
|
+
const [usePopoverContext, providePopoverContext] = createContext("Popover");
|
|
599
|
+
var PopoverRoot_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
600
|
+
name: "PopoverRoot",
|
|
601
|
+
__name: "PopoverRoot",
|
|
602
|
+
props: /* @__PURE__ */ mergeModels({
|
|
603
|
+
id: {},
|
|
604
|
+
as: { default: null },
|
|
605
|
+
renderless: { type: Boolean }
|
|
606
|
+
}, {
|
|
607
|
+
"modelValue": {
|
|
608
|
+
type: Boolean,
|
|
609
|
+
default: false
|
|
610
|
+
},
|
|
611
|
+
"modelModifiers": {}
|
|
612
|
+
}),
|
|
613
|
+
emits: ["update:modelValue"],
|
|
614
|
+
setup(__props) {
|
|
615
|
+
const props = createPropsRestProxy(__props, ["as"]);
|
|
616
|
+
const isSelected = useModel(__props, "modelValue");
|
|
617
|
+
const id = toRef(() => props.id ?? useId());
|
|
618
|
+
function toggle() {
|
|
619
|
+
isSelected.value = !isSelected.value;
|
|
620
|
+
}
|
|
621
|
+
const bindableProps = toRef(() => ({
|
|
622
|
+
id,
|
|
623
|
+
isSelected,
|
|
624
|
+
toggle
|
|
625
|
+
}));
|
|
626
|
+
providePopoverContext({
|
|
627
|
+
isSelected,
|
|
628
|
+
toggle,
|
|
629
|
+
id: id.value
|
|
630
|
+
});
|
|
631
|
+
return (_ctx, _cache) => {
|
|
632
|
+
return openBlock(), createBlock(unref(Atom_default), mergeProps({
|
|
633
|
+
as: _ctx.as,
|
|
634
|
+
renderless: _ctx.renderless
|
|
635
|
+
}, bindableProps.value), {
|
|
636
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps(bindableProps.value)))]),
|
|
637
|
+
_: 3
|
|
638
|
+
}, 16, ["as", "renderless"]);
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
//#endregion
|
|
644
|
+
//#region src/components/Popover/PopoverRoot.vue
|
|
645
|
+
var PopoverRoot_default = PopoverRoot_vue_vue_type_script_setup_true_lang_default;
|
|
646
|
+
|
|
647
|
+
//#endregion
|
|
648
|
+
//#region src/components/Popover/PopoverAnchor.vue?vue&type=script&setup=true&lang.ts
|
|
649
|
+
var PopoverAnchor_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
650
|
+
name: "PopoverAnchor",
|
|
651
|
+
__name: "PopoverAnchor",
|
|
652
|
+
props: {
|
|
653
|
+
target: {},
|
|
654
|
+
as: { default: "button" },
|
|
655
|
+
renderless: { type: Boolean }
|
|
656
|
+
},
|
|
657
|
+
setup(__props) {
|
|
658
|
+
const props = createPropsRestProxy(__props, ["as"]);
|
|
659
|
+
const context = usePopoverContext();
|
|
660
|
+
const popovertarget = toRef(() => props.target ?? context.id);
|
|
661
|
+
const style = toRef(() => ({ anchorName: `--${popovertarget.value}` }));
|
|
662
|
+
return (_ctx, _cache) => {
|
|
663
|
+
return openBlock(), createBlock(unref(Atom_default), {
|
|
664
|
+
as: _ctx.as,
|
|
665
|
+
"data-popover-open": unref(context).isSelected.value ? "" : void 0,
|
|
666
|
+
popovertarget: popovertarget.value,
|
|
667
|
+
style: normalizeStyle(style.value),
|
|
668
|
+
type: _ctx.as === "button" ? "button" : void 0
|
|
669
|
+
}, {
|
|
670
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
|
|
671
|
+
_: 3
|
|
672
|
+
}, 8, [
|
|
673
|
+
"as",
|
|
674
|
+
"data-popover-open",
|
|
675
|
+
"popovertarget",
|
|
676
|
+
"style",
|
|
677
|
+
"type"
|
|
678
|
+
]);
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
//#endregion
|
|
684
|
+
//#region src/components/Popover/PopoverAnchor.vue
|
|
685
|
+
var PopoverAnchor_default = PopoverAnchor_vue_vue_type_script_setup_true_lang_default;
|
|
686
|
+
|
|
687
|
+
//#endregion
|
|
688
|
+
//#region src/components/Popover/PopoverContent.vue?vue&type=script&setup=true&lang.ts
|
|
689
|
+
var PopoverContent_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
690
|
+
name: "PopoverContent",
|
|
691
|
+
__name: "PopoverContent",
|
|
692
|
+
props: {
|
|
693
|
+
id: {},
|
|
694
|
+
positionArea: { default: "bottom" },
|
|
695
|
+
positionTry: { default: "most-width bottom" },
|
|
696
|
+
as: {},
|
|
697
|
+
renderless: { type: Boolean }
|
|
698
|
+
},
|
|
699
|
+
emits: ["beforetoggle"],
|
|
700
|
+
setup(__props, { emit: __emit }) {
|
|
701
|
+
const props = createPropsRestProxy(__props, ["positionArea", "positionTry"]);
|
|
702
|
+
const emit = __emit;
|
|
703
|
+
const context = usePopoverContext();
|
|
704
|
+
const ref$1 = useTemplateRef("ref");
|
|
705
|
+
const id = toRef(() => props.id ?? context.id);
|
|
706
|
+
const style = toRef(() => ({
|
|
707
|
+
positionArea: __props.positionArea,
|
|
708
|
+
positionAnchor: `--${id.value}`,
|
|
709
|
+
positionTry: __props.positionTry
|
|
710
|
+
}));
|
|
711
|
+
onMounted(() => {
|
|
712
|
+
if (context.isSelected.value) ref$1.value?.element?.showPopover();
|
|
713
|
+
});
|
|
714
|
+
function onBeforeToggle(e) {
|
|
715
|
+
context.isSelected.value = e.newState === "open";
|
|
716
|
+
emit("beforetoggle", e);
|
|
717
|
+
}
|
|
718
|
+
return (_ctx, _cache) => {
|
|
719
|
+
return openBlock(), createBlock(unref(Atom_default), {
|
|
720
|
+
id: id.value,
|
|
721
|
+
ref_key: "ref",
|
|
722
|
+
ref: ref$1,
|
|
723
|
+
popover: "",
|
|
724
|
+
style: normalizeStyle(style.value),
|
|
725
|
+
onBeforetoggle: onBeforeToggle
|
|
726
|
+
}, {
|
|
727
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
|
|
728
|
+
_: 3
|
|
729
|
+
}, 8, ["id", "style"]);
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
//#endregion
|
|
735
|
+
//#region src/components/Popover/PopoverContent.vue
|
|
736
|
+
var PopoverContent_default = PopoverContent_vue_vue_type_script_setup_true_lang_default;
|
|
737
|
+
|
|
738
|
+
//#endregion
|
|
739
|
+
//#region src/components/Popover/index.ts
|
|
740
|
+
const Popover = {
|
|
741
|
+
Root: PopoverRoot_default,
|
|
742
|
+
Anchor: PopoverAnchor_default,
|
|
743
|
+
Content: PopoverContent_default
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
//#endregion
|
|
747
|
+
//#region src/factories/createTrinity/index.ts
|
|
748
|
+
/**
|
|
749
|
+
* A tuple containing Vue's provide/inject and a context object
|
|
750
|
+
* @param createContext The function that creates the context
|
|
751
|
+
* @param provideContext The function that provides context
|
|
752
|
+
* @param context The underlying context object singleton
|
|
753
|
+
* @template Z The type parameter for the context value
|
|
754
|
+
* @template E The vmodel type for the context state.
|
|
755
|
+
* @returns [createContext, provideContext, context]
|
|
756
|
+
*
|
|
757
|
+
* @see https://0.vuetifyjs.com/composables/foundation/create-trinity
|
|
758
|
+
*/
|
|
759
|
+
function createTrinity(createContext$1, provideContext$1, context) {
|
|
760
|
+
return [
|
|
761
|
+
createContext$1,
|
|
762
|
+
(_context = context, app) => provideContext$1(_context, app),
|
|
763
|
+
context
|
|
764
|
+
];
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
//#endregion
|
|
768
|
+
//#region src/composables/useLogger/adapters/consola.ts
|
|
769
|
+
var ConsolaLoggerAdapter = class {
|
|
770
|
+
consola;
|
|
771
|
+
constructor(consolaInstance) {
|
|
772
|
+
if (!consolaInstance) throw new Error("Consola instance is required for ConsolaLoggerAdapter");
|
|
773
|
+
this.consola = consolaInstance;
|
|
774
|
+
}
|
|
775
|
+
debug(message, ...args) {
|
|
776
|
+
this.consola.debug(message, ...args);
|
|
777
|
+
}
|
|
778
|
+
info(message, ...args) {
|
|
779
|
+
this.consola.info(message, ...args);
|
|
780
|
+
}
|
|
781
|
+
warn(message, ...args) {
|
|
782
|
+
this.consola.warn(message, ...args);
|
|
783
|
+
}
|
|
784
|
+
error(message, ...args) {
|
|
785
|
+
this.consola.error(message, ...args);
|
|
786
|
+
}
|
|
787
|
+
trace(message, ...args) {
|
|
788
|
+
if (this.consola.trace) this.consola.trace(message, ...args);
|
|
789
|
+
else this.consola.debug(message, ...args);
|
|
790
|
+
}
|
|
791
|
+
fatal(message, ...args) {
|
|
792
|
+
if (this.consola.fatal) this.consola.fatal(message, ...args);
|
|
793
|
+
else this.consola.error("[FATAL]", message, ...args);
|
|
794
|
+
}
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
//#endregion
|
|
798
|
+
//#region src/composables/useLogger/adapters/pino.ts
|
|
799
|
+
/**
|
|
800
|
+
* Pino logger adapter implementation
|
|
801
|
+
*
|
|
802
|
+
* This adapter integrates with the Pino logging library,
|
|
803
|
+
* providing high-performance structured logging optimized
|
|
804
|
+
* for Node.js applications with minimal overhead.
|
|
805
|
+
*/
|
|
806
|
+
var PinoLoggerAdapter = class {
|
|
807
|
+
pino;
|
|
808
|
+
constructor(pinoInstance) {
|
|
809
|
+
if (!pinoInstance) throw new Error("Pino instance is required for PinoLoggerAdapter");
|
|
810
|
+
this.pino = pinoInstance;
|
|
811
|
+
}
|
|
812
|
+
debug(message, ...args) {
|
|
813
|
+
this.pino.debug(this.format(message, ...args));
|
|
814
|
+
}
|
|
815
|
+
info(message, ...args) {
|
|
816
|
+
this.pino.info(this.format(message, ...args));
|
|
817
|
+
}
|
|
818
|
+
warn(message, ...args) {
|
|
819
|
+
this.pino.warn(this.format(message, ...args));
|
|
820
|
+
}
|
|
821
|
+
error(message, ...args) {
|
|
822
|
+
this.pino.error(this.format(message, ...args));
|
|
823
|
+
}
|
|
824
|
+
trace(message, ...args) {
|
|
825
|
+
this.pino.trace(this.format(message, ...args));
|
|
826
|
+
}
|
|
827
|
+
fatal(message, ...args) {
|
|
828
|
+
this.pino.fatal(this.format(message, ...args));
|
|
829
|
+
}
|
|
830
|
+
format(message, ...args) {
|
|
831
|
+
if (args.length === 0) return { msg: message };
|
|
832
|
+
if (args.length === 1 && typeof args[0] === "object" && args[0] !== null) return {
|
|
833
|
+
...args[0],
|
|
834
|
+
msg: message
|
|
835
|
+
};
|
|
836
|
+
return {
|
|
837
|
+
msg: message,
|
|
838
|
+
args
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
//#endregion
|
|
844
|
+
//#region src/composables/useLogger/adapters/v0.ts
|
|
845
|
+
/**
|
|
846
|
+
* Vuetify0.x logger adapter implementation
|
|
847
|
+
*
|
|
848
|
+
* This adapter provides console-based logging with proper formatting,
|
|
849
|
+
* color coding, timestamps, and log level filtering for development
|
|
850
|
+
* and production environments.
|
|
851
|
+
*/
|
|
852
|
+
var Vuetify0LoggerAdapter = class {
|
|
853
|
+
prefix;
|
|
854
|
+
colors;
|
|
855
|
+
timestamps;
|
|
856
|
+
constructor(options = {}) {
|
|
857
|
+
this.prefix = options.prefix || "v0";
|
|
858
|
+
this.colors = options.colors !== false;
|
|
859
|
+
this.timestamps = options.timestamps !== false;
|
|
860
|
+
}
|
|
861
|
+
debug(message, ...args) {
|
|
862
|
+
this.log("debug", "debug", message, ...args);
|
|
863
|
+
}
|
|
864
|
+
info(message, ...args) {
|
|
865
|
+
this.log("info", "info", message, ...args);
|
|
866
|
+
}
|
|
867
|
+
warn(message, ...args) {
|
|
868
|
+
this.log("warn", "warn", message, ...args);
|
|
869
|
+
}
|
|
870
|
+
error(message, ...args) {
|
|
871
|
+
this.log("error", "error", message, ...args);
|
|
872
|
+
}
|
|
873
|
+
trace(message, ...args) {
|
|
874
|
+
this.log("trace", "trace", message, ...args);
|
|
875
|
+
}
|
|
876
|
+
fatal(message, ...args) {
|
|
877
|
+
this.log("fatal", "error", message, ...args);
|
|
878
|
+
}
|
|
879
|
+
format(level, message, ...args) {
|
|
880
|
+
const timestamp = this.timestamps ? this.timestamp() : "";
|
|
881
|
+
const prefixTag = `[${this.prefix} ${level.toLowerCase()}]`;
|
|
882
|
+
return [[
|
|
883
|
+
timestamp,
|
|
884
|
+
prefixTag,
|
|
885
|
+
message
|
|
886
|
+
].filter(Boolean).join(" "), ...args];
|
|
887
|
+
}
|
|
888
|
+
timestamp() {
|
|
889
|
+
if (!IN_BROWSER) return (/* @__PURE__ */ new Date()).toISOString();
|
|
890
|
+
return (/* @__PURE__ */ new Date()).toTimeString().split(" ")[0] ?? "";
|
|
891
|
+
}
|
|
892
|
+
style(level) {
|
|
893
|
+
if (!this.colors || !IN_BROWSER) return "";
|
|
894
|
+
return {
|
|
895
|
+
trace: "color: #64748b",
|
|
896
|
+
debug: "color: #3b82f6",
|
|
897
|
+
info: "color: #10b981",
|
|
898
|
+
warn: "color: #f59e0b",
|
|
899
|
+
error: "color: #ef4444",
|
|
900
|
+
fatal: "color: #dc2626; font-weight: bold",
|
|
901
|
+
silent: ""
|
|
902
|
+
}[level] || "";
|
|
903
|
+
}
|
|
904
|
+
log(level, method, message, ...args) {
|
|
905
|
+
const [formattedMessage, ...restArgs] = this.format(level, message, ...args);
|
|
906
|
+
const style = this.style(level);
|
|
907
|
+
if (IN_BROWSER && style && typeof console[method] === "function") console[method](`%c${formattedMessage}`, style, ...restArgs);
|
|
908
|
+
else if (typeof console[method] === "function") console[method](formattedMessage, ...restArgs);
|
|
909
|
+
}
|
|
910
|
+
};
|
|
911
|
+
|
|
912
|
+
//#endregion
|
|
913
|
+
//#region src/composables/useLogger/index.ts
|
|
914
|
+
const [useLoggerContext, provideLoggerContext] = createContext("v0:logger");
|
|
915
|
+
/**
|
|
916
|
+
* Creates a logger context for application logging with configurable adapters and levels.
|
|
917
|
+
* This function provides a consistent logging interface that can be configured with
|
|
918
|
+
* different adapters and optimized for production builds with conditional compilation.
|
|
919
|
+
*
|
|
920
|
+
* @param options Configuration for the logger adapter, level, and behavior.
|
|
921
|
+
* @returns A logger context object with logging methods and controls.
|
|
922
|
+
*/
|
|
923
|
+
function createLogger(options = {}) {
|
|
924
|
+
const { adapter = new Vuetify0LoggerAdapter({ prefix: options.prefix }), level: initialLevel = "info", enabled: initialEnabled = __LOGGER_ENABLED__ } = options;
|
|
925
|
+
const currentLevel = shallowRef(initialLevel);
|
|
926
|
+
const isEnabled = shallowRef(initialEnabled);
|
|
927
|
+
function value(level$1) {
|
|
928
|
+
return {
|
|
929
|
+
trace: 0,
|
|
930
|
+
debug: 1,
|
|
931
|
+
info: 2,
|
|
932
|
+
warn: 3,
|
|
933
|
+
error: 4,
|
|
934
|
+
fatal: 5,
|
|
935
|
+
silent: 6
|
|
936
|
+
}[level$1] ?? 2;
|
|
937
|
+
}
|
|
938
|
+
function can(level$1) {
|
|
939
|
+
if (!isEnabled.value) return false;
|
|
940
|
+
return value(level$1) >= value(currentLevel.value);
|
|
941
|
+
}
|
|
942
|
+
function format(message) {
|
|
943
|
+
return message;
|
|
944
|
+
}
|
|
945
|
+
function debug(message, ...args) {
|
|
946
|
+
if (can("debug")) adapter.debug(format(message), ...args);
|
|
947
|
+
}
|
|
948
|
+
function info(message, ...args) {
|
|
949
|
+
if (can("info")) adapter.info(format(message), ...args);
|
|
950
|
+
}
|
|
951
|
+
function warn(message, ...args) {
|
|
952
|
+
if (can("warn")) adapter.warn(format(message), ...args);
|
|
953
|
+
}
|
|
954
|
+
function error(message, ...args) {
|
|
955
|
+
if (can("error")) adapter.error(format(message), ...args);
|
|
956
|
+
}
|
|
957
|
+
function trace(message, ...args) {
|
|
958
|
+
if (can("trace")) adapter.trace?.(format(message), ...args);
|
|
959
|
+
}
|
|
960
|
+
function fatal(message, ...args) {
|
|
961
|
+
if (can("fatal")) adapter.fatal?.(format(message), ...args);
|
|
962
|
+
}
|
|
963
|
+
function level(newLevel) {
|
|
964
|
+
currentLevel.value = newLevel;
|
|
965
|
+
}
|
|
966
|
+
function current() {
|
|
967
|
+
return currentLevel.value;
|
|
968
|
+
}
|
|
969
|
+
function enabled() {
|
|
970
|
+
return isEnabled.value;
|
|
971
|
+
}
|
|
972
|
+
function enable() {
|
|
973
|
+
isEnabled.value = true;
|
|
974
|
+
}
|
|
975
|
+
function disable() {
|
|
976
|
+
isEnabled.value = false;
|
|
977
|
+
}
|
|
978
|
+
return {
|
|
979
|
+
debug,
|
|
980
|
+
info,
|
|
981
|
+
warn,
|
|
982
|
+
error,
|
|
983
|
+
trace,
|
|
984
|
+
fatal,
|
|
985
|
+
level,
|
|
986
|
+
current,
|
|
987
|
+
enabled,
|
|
988
|
+
enable,
|
|
989
|
+
disable
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
function createFallbackLogger(namespace = "v0:logger") {
|
|
993
|
+
function format(message, type) {
|
|
994
|
+
return `[${namespace} ${type}] ${message}`;
|
|
995
|
+
}
|
|
996
|
+
return {
|
|
997
|
+
debug: (message, ...args) => console.log(format(message, "debug"), ...args),
|
|
998
|
+
info: (message, ...args) => console.log(format(message, "info"), ...args),
|
|
999
|
+
warn: (message, ...args) => console.log(format(message, "warn"), ...args),
|
|
1000
|
+
error: (message, ...args) => console.log(format(message, "error"), ...args),
|
|
1001
|
+
trace: (message, ...args) => console.log(format(message, "trace"), ...args),
|
|
1002
|
+
fatal: (message, ...args) => console.log(format(message, "fatal"), ...args),
|
|
1003
|
+
level: () => {},
|
|
1004
|
+
current: () => "info",
|
|
1005
|
+
enabled: () => true,
|
|
1006
|
+
enable: () => {},
|
|
1007
|
+
disable: () => {}
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
function useLogger(namespace) {
|
|
1011
|
+
if (getCurrentInstance()) try {
|
|
1012
|
+
return useLoggerContext(namespace);
|
|
1013
|
+
} catch (error) {}
|
|
1014
|
+
return createFallbackLogger(namespace);
|
|
1015
|
+
}
|
|
1016
|
+
function createLoggerPlugin(options = {}) {
|
|
1017
|
+
const context = createLogger(options);
|
|
1018
|
+
return createPlugin({
|
|
1019
|
+
namespace: "v0:logger",
|
|
1020
|
+
provide: (app) => {
|
|
1021
|
+
provideLoggerContext(context, app);
|
|
1022
|
+
},
|
|
1023
|
+
setup: (_app) => {}
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
//#endregion
|
|
1028
|
+
//#region src/composables/useRegistry/index.ts
|
|
1029
|
+
/**
|
|
1030
|
+
* Creates a registry for managing collections of items with registration and lookup capabilities.
|
|
1031
|
+
* This function provides the foundation for item management systems with ID-based, value-based,
|
|
1032
|
+
* and index-based access patterns.
|
|
1033
|
+
*
|
|
1034
|
+
* @param options Optional configuration for enabling events.
|
|
1035
|
+
* @template Z The type of items managed by the registry.
|
|
1036
|
+
* @template E The type of the registry context.
|
|
1037
|
+
* @returns The registry context object.
|
|
1038
|
+
*
|
|
1039
|
+
* @see https://0.vuetifyjs.com/composables/registration/use-registry
|
|
1040
|
+
*/
|
|
1041
|
+
function useRegistry(options) {
|
|
1042
|
+
const logger = useLogger();
|
|
1043
|
+
const collection = /* @__PURE__ */ new Map();
|
|
1044
|
+
const catalog = /* @__PURE__ */ new Map();
|
|
1045
|
+
const directory = /* @__PURE__ */ new Map();
|
|
1046
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1047
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
1048
|
+
function emit(event, data) {
|
|
1049
|
+
if (!options?.events) return;
|
|
1050
|
+
const cbs = listeners.get(event);
|
|
1051
|
+
if (!cbs) return;
|
|
1052
|
+
for (const cb of cbs) cb(data);
|
|
1053
|
+
}
|
|
1054
|
+
function on(event, cb) {
|
|
1055
|
+
if (!listeners.has(event)) listeners.set(event, /* @__PURE__ */ new Set());
|
|
1056
|
+
listeners.get(event).add(cb);
|
|
1057
|
+
}
|
|
1058
|
+
function off(event, cb) {
|
|
1059
|
+
listeners.get(event)?.delete(cb);
|
|
1060
|
+
}
|
|
1061
|
+
function dispose() {
|
|
1062
|
+
if (listeners.size > 0) listeners.clear();
|
|
1063
|
+
clear();
|
|
1064
|
+
}
|
|
1065
|
+
function get(id) {
|
|
1066
|
+
return collection.get(id);
|
|
1067
|
+
}
|
|
1068
|
+
function upsert(id, patch = {}) {
|
|
1069
|
+
const existing = get(id);
|
|
1070
|
+
if (!existing) return register({
|
|
1071
|
+
...patch,
|
|
1072
|
+
id
|
|
1073
|
+
});
|
|
1074
|
+
const hasValue = Object.prototype.hasOwnProperty.call(patch, "value");
|
|
1075
|
+
let value = existing.value;
|
|
1076
|
+
let valueIsIndex = existing.valueIsIndex;
|
|
1077
|
+
if (hasValue) {
|
|
1078
|
+
if (patch.value === void 0) {
|
|
1079
|
+
value = existing.index;
|
|
1080
|
+
valueIsIndex = true;
|
|
1081
|
+
} else {
|
|
1082
|
+
value = patch.value;
|
|
1083
|
+
valueIsIndex = false;
|
|
1084
|
+
}
|
|
1085
|
+
if (!Object.is(value, existing.value)) {
|
|
1086
|
+
unassign(existing.value, id);
|
|
1087
|
+
assign(value, id);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
const updated = {
|
|
1091
|
+
...existing,
|
|
1092
|
+
...patch,
|
|
1093
|
+
id,
|
|
1094
|
+
index: existing.index,
|
|
1095
|
+
value,
|
|
1096
|
+
valueIsIndex
|
|
1097
|
+
};
|
|
1098
|
+
collection.set(id, updated);
|
|
1099
|
+
invalidate();
|
|
1100
|
+
return updated;
|
|
1101
|
+
}
|
|
1102
|
+
function browse(value) {
|
|
1103
|
+
return catalog.get(value);
|
|
1104
|
+
}
|
|
1105
|
+
function lookup(index) {
|
|
1106
|
+
return directory.get(index);
|
|
1107
|
+
}
|
|
1108
|
+
function has(id) {
|
|
1109
|
+
return collection.has(id);
|
|
1110
|
+
}
|
|
1111
|
+
function assign(value, id) {
|
|
1112
|
+
const bucket = catalog.get(value);
|
|
1113
|
+
if (bucket) {
|
|
1114
|
+
if (isArray(bucket)) {
|
|
1115
|
+
if (!bucket.includes(id)) bucket.push(id);
|
|
1116
|
+
} else if (bucket !== id) catalog.set(value, [bucket, id]);
|
|
1117
|
+
} else catalog.set(value, id);
|
|
1118
|
+
}
|
|
1119
|
+
function unassign(value, id) {
|
|
1120
|
+
const bucket = catalog.get(value);
|
|
1121
|
+
if (!bucket) return;
|
|
1122
|
+
if (isArray(bucket)) {
|
|
1123
|
+
const next = bucket.filter((v) => v !== id);
|
|
1124
|
+
if (next.length === 0) catalog.delete(value);
|
|
1125
|
+
else if (next.length === 1) catalog.set(value, next[0]);
|
|
1126
|
+
else catalog.set(value, next);
|
|
1127
|
+
} else if (bucket === id) catalog.delete(value);
|
|
1128
|
+
}
|
|
1129
|
+
function keys() {
|
|
1130
|
+
const cached = cache.get("keys");
|
|
1131
|
+
if (cached != void 0) return cached;
|
|
1132
|
+
const keys$1 = Array.from(collection.keys());
|
|
1133
|
+
cache.set("keys", keys$1);
|
|
1134
|
+
return keys$1;
|
|
1135
|
+
}
|
|
1136
|
+
function values() {
|
|
1137
|
+
const cached = cache.get("values");
|
|
1138
|
+
if (cached != void 0) return cached;
|
|
1139
|
+
const values$1 = Array.from(collection.values());
|
|
1140
|
+
cache.set("values", values$1);
|
|
1141
|
+
return values$1;
|
|
1142
|
+
}
|
|
1143
|
+
function entries() {
|
|
1144
|
+
const cached = cache.get("entries");
|
|
1145
|
+
if (cached != void 0) return cached;
|
|
1146
|
+
const entries$1 = Array.from(collection.entries());
|
|
1147
|
+
cache.set("entries", entries$1);
|
|
1148
|
+
return entries$1;
|
|
1149
|
+
}
|
|
1150
|
+
function clear() {
|
|
1151
|
+
if (collection.size > 0) collection.clear();
|
|
1152
|
+
if (catalog.size > 0) catalog.clear();
|
|
1153
|
+
if (directory.size > 0) directory.clear();
|
|
1154
|
+
invalidate();
|
|
1155
|
+
}
|
|
1156
|
+
function invalidate() {
|
|
1157
|
+
if (cache.size > 0) cache.clear();
|
|
1158
|
+
}
|
|
1159
|
+
function reindex() {
|
|
1160
|
+
if (catalog.size > 0) catalog.clear();
|
|
1161
|
+
if (directory.size > 0) directory.clear();
|
|
1162
|
+
let index = 0;
|
|
1163
|
+
for (const item of values()) {
|
|
1164
|
+
if (item.index !== index) {
|
|
1165
|
+
item.index = index;
|
|
1166
|
+
if (item.valueIsIndex) item.value = index;
|
|
1167
|
+
}
|
|
1168
|
+
directory.set(index, item.id);
|
|
1169
|
+
assign(item.value, item.id);
|
|
1170
|
+
index++;
|
|
1171
|
+
}
|
|
1172
|
+
invalidate();
|
|
1173
|
+
}
|
|
1174
|
+
function register(registration = {}) {
|
|
1175
|
+
const size = collection.size;
|
|
1176
|
+
const id = registration.id ?? genId();
|
|
1177
|
+
if (has(id)) {
|
|
1178
|
+
logger.warn(`Item with id "${id}" already exists in the registry. Skipping registration.`);
|
|
1179
|
+
return get(id);
|
|
1180
|
+
}
|
|
1181
|
+
const index = registration.index ?? size;
|
|
1182
|
+
const value = registration.value === void 0 ? index : registration.value;
|
|
1183
|
+
const valueIsIndex = registration.value === void 0;
|
|
1184
|
+
const item = {
|
|
1185
|
+
...registration,
|
|
1186
|
+
id,
|
|
1187
|
+
index,
|
|
1188
|
+
value,
|
|
1189
|
+
valueIsIndex
|
|
1190
|
+
};
|
|
1191
|
+
collection.set(item.id, item);
|
|
1192
|
+
directory.set(item.index, item.id);
|
|
1193
|
+
assign(item.value, item.id);
|
|
1194
|
+
invalidate();
|
|
1195
|
+
emit("register", item);
|
|
1196
|
+
return item;
|
|
1197
|
+
}
|
|
1198
|
+
function unregister(id) {
|
|
1199
|
+
const item = collection.get(id);
|
|
1200
|
+
if (!item) return;
|
|
1201
|
+
collection.delete(item.id);
|
|
1202
|
+
directory.delete(item.index);
|
|
1203
|
+
unassign(item.value, item.id);
|
|
1204
|
+
emit("unregister", item);
|
|
1205
|
+
reindex();
|
|
1206
|
+
}
|
|
1207
|
+
return {
|
|
1208
|
+
collection,
|
|
1209
|
+
emit,
|
|
1210
|
+
on,
|
|
1211
|
+
off,
|
|
1212
|
+
dispose,
|
|
1213
|
+
has,
|
|
1214
|
+
keys,
|
|
1215
|
+
clear,
|
|
1216
|
+
browse,
|
|
1217
|
+
entries,
|
|
1218
|
+
values,
|
|
1219
|
+
lookup,
|
|
1220
|
+
get,
|
|
1221
|
+
upsert,
|
|
1222
|
+
register,
|
|
1223
|
+
unregister,
|
|
1224
|
+
reindex,
|
|
1225
|
+
onboard(registrations) {
|
|
1226
|
+
return registrations.map((registration) => this.register(registration));
|
|
1227
|
+
},
|
|
1228
|
+
get size() {
|
|
1229
|
+
return collection.size;
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Creates a registry context with full injection/provision control.
|
|
1235
|
+
* Returns the complete trinity for advanced usage scenarios.
|
|
1236
|
+
*
|
|
1237
|
+
* @param namespace The namespace for the registry context.
|
|
1238
|
+
* @param options Optional configuration for reactivity behavior.
|
|
1239
|
+
* @template Z The type of tickets managed by the registry.
|
|
1240
|
+
* @template E The type of the registry context.
|
|
1241
|
+
* @returns A tuple containing the inject function, provide function, and the registry context.
|
|
1242
|
+
*/
|
|
1243
|
+
function createRegistryContext(namespace, options) {
|
|
1244
|
+
const [useRegistryContext, _provideRegistryContext] = createContext(namespace);
|
|
1245
|
+
const context = useRegistry(options);
|
|
1246
|
+
function provideRegistryContext(_context = context, app) {
|
|
1247
|
+
return _provideRegistryContext(_context, app);
|
|
1248
|
+
}
|
|
1249
|
+
return createTrinity(useRegistryContext, provideRegistryContext, context);
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
//#endregion
|
|
1253
|
+
//#region src/composables/useSelection/index.ts
|
|
1254
|
+
/**
|
|
1255
|
+
* Creates a selection context for managing collections of selectable items.
|
|
1256
|
+
* This function extends the registry functionality with selection state management.
|
|
1257
|
+
*
|
|
1258
|
+
* @param options Optional configuration for selection behavior.
|
|
1259
|
+
* @template Z The type of items managed by the selection.
|
|
1260
|
+
* @template E The type of the selection context.
|
|
1261
|
+
* @returns The selection context object.
|
|
1262
|
+
*/
|
|
1263
|
+
function useSelection(options) {
|
|
1264
|
+
const registry = useRegistry(options);
|
|
1265
|
+
const selectedIds = shallowReactive(/* @__PURE__ */ new Set());
|
|
1266
|
+
const enroll = options?.enroll ?? false;
|
|
1267
|
+
const mandatory = options?.mandatory ?? false;
|
|
1268
|
+
const selectedItems = computed(() => {
|
|
1269
|
+
return new Set(Array.from(selectedIds).map((id) => registry.get(id)));
|
|
1270
|
+
});
|
|
1271
|
+
const selectedValues = computed(() => {
|
|
1272
|
+
return new Set(Array.from(selectedItems.value).map((item) => item?.value));
|
|
1273
|
+
});
|
|
1274
|
+
function mandate() {
|
|
1275
|
+
if (!mandatory || registry.selectedIds.size > 0 || registry.size === 0) return;
|
|
1276
|
+
select(registry.lookup(0));
|
|
1277
|
+
}
|
|
1278
|
+
function select(id) {
|
|
1279
|
+
const item = registry.get(id);
|
|
1280
|
+
if (!item || item.disabled) return;
|
|
1281
|
+
selectedIds.add(id);
|
|
1282
|
+
}
|
|
1283
|
+
function unselect(id) {
|
|
1284
|
+
if (mandatory && selectedIds.size === 1) return;
|
|
1285
|
+
selectedIds.delete(id);
|
|
1286
|
+
}
|
|
1287
|
+
function toggle(id) {
|
|
1288
|
+
if (selectedIds.has(id)) unselect(id);
|
|
1289
|
+
else select(id);
|
|
1290
|
+
}
|
|
1291
|
+
function selected(id) {
|
|
1292
|
+
return selectedIds.has(id);
|
|
1293
|
+
}
|
|
1294
|
+
function register(registration = {}) {
|
|
1295
|
+
const id = registration.id ?? genId();
|
|
1296
|
+
const item = {
|
|
1297
|
+
disabled: false,
|
|
1298
|
+
...registration,
|
|
1299
|
+
id,
|
|
1300
|
+
isSelected: toRef(() => selectedIds.has(id)),
|
|
1301
|
+
select: () => select(id),
|
|
1302
|
+
unselect: () => unselect(id),
|
|
1303
|
+
toggle: () => toggle(id)
|
|
1304
|
+
};
|
|
1305
|
+
const ticket = registry.register(item);
|
|
1306
|
+
if (enroll && !item.disabled) selectedIds.add(ticket.id);
|
|
1307
|
+
if (mandatory === "force") mandate();
|
|
1308
|
+
return ticket;
|
|
1309
|
+
}
|
|
1310
|
+
function unregister(id) {
|
|
1311
|
+
selectedIds.delete(id);
|
|
1312
|
+
registry.unregister(id);
|
|
1313
|
+
}
|
|
1314
|
+
function reset() {
|
|
1315
|
+
registry.clear();
|
|
1316
|
+
registry.reindex();
|
|
1317
|
+
registry.mandate();
|
|
1318
|
+
}
|
|
1319
|
+
return {
|
|
1320
|
+
...registry,
|
|
1321
|
+
selectedIds,
|
|
1322
|
+
selectedItems,
|
|
1323
|
+
selectedValues,
|
|
1324
|
+
register,
|
|
1325
|
+
unregister,
|
|
1326
|
+
reset,
|
|
1327
|
+
mandate,
|
|
1328
|
+
select,
|
|
1329
|
+
unselect,
|
|
1330
|
+
toggle,
|
|
1331
|
+
selected
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* Creates a selection registry context with full injection/provision control.
|
|
1336
|
+
* Returns the complete trinity for advanced usage scenarios.
|
|
1337
|
+
*
|
|
1338
|
+
* @param namespace The namespace for the selection registry context
|
|
1339
|
+
* @param options Optional configuration for selection behavior.
|
|
1340
|
+
* @template Z The structure of the registry selection items.
|
|
1341
|
+
* @template E The available methods for the selection's context.
|
|
1342
|
+
* @returns A tuple containing the inject function, provide function, and the selection context.
|
|
1343
|
+
*/
|
|
1344
|
+
function createSelectionContext(namespace, options) {
|
|
1345
|
+
const [useSelectionContext, _provideSelectionContext] = createContext(namespace);
|
|
1346
|
+
const context = useSelection(options);
|
|
1347
|
+
function provideSelectionContext(_context = context, app) {
|
|
1348
|
+
return _provideSelectionContext(_context, app);
|
|
1349
|
+
}
|
|
1350
|
+
return createTrinity(useSelectionContext, provideSelectionContext, context);
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
//#endregion
|
|
1354
|
+
//#region src/composables/useSingle/index.ts
|
|
1355
|
+
/**
|
|
1356
|
+
* Creates a single selection context for managing collections where only one item can be selected.
|
|
1357
|
+
* This function extends the selection functionality with single-selection constraints.
|
|
1358
|
+
*
|
|
1359
|
+
* @param options Optional configuration for single selection behavior.
|
|
1360
|
+
* @template Z The type of items managed by the single selection.
|
|
1361
|
+
* @template E The type of the single selection context.
|
|
1362
|
+
* @returns The single selection context object.
|
|
1363
|
+
*/
|
|
1364
|
+
function useSingle(options) {
|
|
1365
|
+
const registry = useSelection(options);
|
|
1366
|
+
const mandatory = options?.mandatory ?? false;
|
|
1367
|
+
const selectedId = computed(() => registry.selectedIds.values().next().value);
|
|
1368
|
+
const selectedItem = computed(() => registry.selectedItems.value.values().next().value);
|
|
1369
|
+
const selectedIndex = computed(() => selectedItem.value?.index ?? -1);
|
|
1370
|
+
const selectedValue = computed(() => selectedItem.value?.value);
|
|
1371
|
+
function select(id) {
|
|
1372
|
+
const item = registry.get(id);
|
|
1373
|
+
if (!item || item.disabled) return;
|
|
1374
|
+
registry.selectedIds.clear();
|
|
1375
|
+
registry.select(id);
|
|
1376
|
+
}
|
|
1377
|
+
function unselect(id) {
|
|
1378
|
+
if (mandatory && registry.selectedIds.size === 1) return;
|
|
1379
|
+
registry.selectedIds.delete(id);
|
|
1380
|
+
}
|
|
1381
|
+
function toggle(id) {
|
|
1382
|
+
if (registry.selectedIds.has(id)) unselect(id);
|
|
1383
|
+
else select(id);
|
|
1384
|
+
}
|
|
1385
|
+
return {
|
|
1386
|
+
...registry,
|
|
1387
|
+
selectedId,
|
|
1388
|
+
selectedItem,
|
|
1389
|
+
selectedIndex,
|
|
1390
|
+
selectedValue,
|
|
1391
|
+
select,
|
|
1392
|
+
unselect,
|
|
1393
|
+
toggle
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Creates a single selection registry context with full injection/provision control.
|
|
1398
|
+
* Returns the complete trinity for advanced usage scenarios.
|
|
1399
|
+
*
|
|
1400
|
+
* @param namespace The namespace for the single selection registry context
|
|
1401
|
+
* @param options Optional configuration for single selection behavior.
|
|
1402
|
+
* @template Z The structure of the registry single selection items.
|
|
1403
|
+
* @template E The available methods for the single's context.
|
|
1404
|
+
* @returns A tuple containing the inject function, provide function, and the single selection context.
|
|
1405
|
+
*/
|
|
1406
|
+
function createSingleContext(namespace, options) {
|
|
1407
|
+
const [useSingleContext, _provideSingleContext] = createContext(namespace);
|
|
1408
|
+
const context = useSingle(options);
|
|
1409
|
+
function provideSingleContext(_context = context, app) {
|
|
1410
|
+
return _provideSingleContext(_context, app);
|
|
1411
|
+
}
|
|
1412
|
+
return createTrinity(useSingleContext, provideSingleContext, context);
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
//#endregion
|
|
1416
|
+
//#region src/utilities/benchmark.ts
|
|
1417
|
+
async function run(name, fn, samples = 100) {
|
|
1418
|
+
fn();
|
|
1419
|
+
return {
|
|
1420
|
+
name,
|
|
1421
|
+
duration: 0,
|
|
1422
|
+
ops: Infinity
|
|
1423
|
+
};
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
//#endregion
|
|
1427
|
+
//#region src/composables/useTokens/index.ts
|
|
1428
|
+
/**
|
|
1429
|
+
* Creates a token registry for managing design token collections with alias resolution.
|
|
1430
|
+
* Returns the token context directly for simple usage.
|
|
1431
|
+
*
|
|
1432
|
+
* @param tokens A collection of tokens to initialize with
|
|
1433
|
+
* @template Z The structure of the registry token items.
|
|
1434
|
+
* @template E The available methods for the token's context.
|
|
1435
|
+
* @returns The token context object.
|
|
1436
|
+
*
|
|
1437
|
+
* @see https://0.vuetifyjs.com/composables/registration/use-tokens
|
|
1438
|
+
* @see https://www.designtokens.org/tr/drafts/format/
|
|
1439
|
+
*/
|
|
1440
|
+
function useTokens(tokens = {}, options = {}) {
|
|
1441
|
+
const logger = useLogger();
|
|
1442
|
+
const registry = useRegistry();
|
|
1443
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1444
|
+
registry.onboard(flatten(tokens, options.prefix, !!options.flat));
|
|
1445
|
+
function isAlias(token) {
|
|
1446
|
+
return isString(token) && token.length > 2 && token[0] === "{" && token.at(-1) === "}";
|
|
1447
|
+
}
|
|
1448
|
+
function isTokenAlias(value) {
|
|
1449
|
+
return isObject(value) && "$value" in value;
|
|
1450
|
+
}
|
|
1451
|
+
function resolve(token) {
|
|
1452
|
+
const cacheKey = isString(token) ? token : JSON.stringify(token);
|
|
1453
|
+
const cached = cache.get(cacheKey);
|
|
1454
|
+
if (cached !== void 0) return cached;
|
|
1455
|
+
const reference = isTokenAlias(token) ? token.$value : token;
|
|
1456
|
+
const clean = isString(reference) && isAlias(reference) ? reference.slice(1, -1) : String(reference);
|
|
1457
|
+
let found = registry.get(clean);
|
|
1458
|
+
let segments = [];
|
|
1459
|
+
if (!found && clean.includes(".")) {
|
|
1460
|
+
const parts = clean.split(".");
|
|
1461
|
+
for (let i = parts.length - 1; i > 0; i--) {
|
|
1462
|
+
const prefix = parts.slice(0, i).join(".");
|
|
1463
|
+
const suffix = parts.slice(i);
|
|
1464
|
+
const candidate = registry.get(prefix);
|
|
1465
|
+
if (candidate?.value !== void 0) {
|
|
1466
|
+
found = candidate;
|
|
1467
|
+
segments = suffix;
|
|
1468
|
+
break;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
if (found?.value === void 0) {
|
|
1473
|
+
logger.warn(`Alias not found for "${String(reference)}"`);
|
|
1474
|
+
cache.set(cacheKey, void 0);
|
|
1475
|
+
return;
|
|
1476
|
+
}
|
|
1477
|
+
let result;
|
|
1478
|
+
let current = found.value;
|
|
1479
|
+
if (segments.length > 0) {
|
|
1480
|
+
if (isTokenAlias(current)) current = current.$value;
|
|
1481
|
+
for (const segment of segments) {
|
|
1482
|
+
if (!isObject(current) || !(segment in current)) {
|
|
1483
|
+
current = void 0;
|
|
1484
|
+
break;
|
|
1485
|
+
}
|
|
1486
|
+
current = current[segment];
|
|
1487
|
+
if (isTokenAlias(current)) current = current.$value;
|
|
1488
|
+
}
|
|
1489
|
+
if (current === void 0) {
|
|
1490
|
+
logger.warn(`Path not found inside "${clean}": ${segments.join(".")}`);
|
|
1491
|
+
cache.set(cacheKey, void 0);
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
result = current;
|
|
1495
|
+
} else if (isTokenAlias(current)) {
|
|
1496
|
+
const inner = current.$value;
|
|
1497
|
+
if (isString(inner) && isAlias(inner)) return resolve(inner);
|
|
1498
|
+
result = inner;
|
|
1499
|
+
} else if (isString(current) && isAlias(current)) return resolve(current);
|
|
1500
|
+
else result = current;
|
|
1501
|
+
cache.set(cacheKey, result);
|
|
1502
|
+
return result;
|
|
1503
|
+
}
|
|
1504
|
+
return {
|
|
1505
|
+
...registry,
|
|
1506
|
+
resolve,
|
|
1507
|
+
isAlias
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
/**
|
|
1511
|
+
* Creates a token registry context with full injection/provision control.
|
|
1512
|
+
* Returns the complete trinity for advanced usage scenarios.
|
|
1513
|
+
*
|
|
1514
|
+
* @param namespace The namespace for the token registry context
|
|
1515
|
+
* @param tokens An optional collection of tokens to initialize
|
|
1516
|
+
* @template Z The structure of the registry token items.
|
|
1517
|
+
* @template E The available methods for the token's context.
|
|
1518
|
+
* @returns A tuple containing the inject function, provide function, and the token context.
|
|
1519
|
+
*/
|
|
1520
|
+
function createTokensContext(namespace, tokens = {}) {
|
|
1521
|
+
const [useTokensContext, _provideTokensContext] = createContext(namespace);
|
|
1522
|
+
const context = useTokens(tokens);
|
|
1523
|
+
function provideTokensContext(_context = context, app) {
|
|
1524
|
+
return _provideTokensContext(_context, app);
|
|
1525
|
+
}
|
|
1526
|
+
return createTrinity(useTokensContext, provideTokensContext, context);
|
|
1527
|
+
}
|
|
1528
|
+
/**
|
|
1529
|
+
* Flattens a nested collection of tokens into a flat array of tokens.
|
|
1530
|
+
* Each token is represented by an object containing its ID & value.
|
|
1531
|
+
* @param tokens The collection of tokens to flatten.
|
|
1532
|
+
* @param prefix An optional prefix to prepend to each token ID.
|
|
1533
|
+
* @returns An array of flattened tokens, each with an ID and value.
|
|
1534
|
+
*/
|
|
1535
|
+
function flatten(tokens, prefix = "", flat = false) {
|
|
1536
|
+
const flattened = [];
|
|
1537
|
+
const stack = [{
|
|
1538
|
+
tokens,
|
|
1539
|
+
prefix,
|
|
1540
|
+
flat
|
|
1541
|
+
}];
|
|
1542
|
+
while (stack.length > 0) {
|
|
1543
|
+
const { tokens: currentTokens, prefix: currentPrefix, flat: flat$1 } = stack.pop();
|
|
1544
|
+
const meta = {};
|
|
1545
|
+
for (const k in currentTokens) if (k.startsWith("$")) meta[k] = currentTokens[k];
|
|
1546
|
+
if (Object.keys(meta).length > 0 && currentPrefix) flattened.push({
|
|
1547
|
+
id: currentPrefix,
|
|
1548
|
+
value: meta
|
|
1549
|
+
});
|
|
1550
|
+
for (const key in currentTokens) {
|
|
1551
|
+
if (key.startsWith("$")) continue;
|
|
1552
|
+
const value = currentTokens[key];
|
|
1553
|
+
const id = currentPrefix ? `${currentPrefix}.${key}` : key;
|
|
1554
|
+
if (!isObject(value)) {
|
|
1555
|
+
flattened.push({
|
|
1556
|
+
id,
|
|
1557
|
+
value
|
|
1558
|
+
});
|
|
1559
|
+
continue;
|
|
1560
|
+
}
|
|
1561
|
+
if ("$value" in value) {
|
|
1562
|
+
flattened.push({
|
|
1563
|
+
id,
|
|
1564
|
+
value
|
|
1565
|
+
});
|
|
1566
|
+
const inner = value.$value;
|
|
1567
|
+
if (isObject(inner) && !flat$1) for (const innerKey in inner) {
|
|
1568
|
+
if (innerKey.startsWith("$")) continue;
|
|
1569
|
+
const child = inner[innerKey];
|
|
1570
|
+
const childId = `${id}.${innerKey}`;
|
|
1571
|
+
if (!isObject(child)) flattened.push({
|
|
1572
|
+
id: childId,
|
|
1573
|
+
value: child
|
|
1574
|
+
});
|
|
1575
|
+
else if ("$value" in child) flattened.push({
|
|
1576
|
+
id: childId,
|
|
1577
|
+
value: child
|
|
1578
|
+
});
|
|
1579
|
+
else stack.push({
|
|
1580
|
+
tokens: child,
|
|
1581
|
+
prefix: childId,
|
|
1582
|
+
flat: flat$1
|
|
1583
|
+
});
|
|
1584
|
+
}
|
|
1585
|
+
continue;
|
|
1586
|
+
}
|
|
1587
|
+
if (flat$1) {
|
|
1588
|
+
flattened.push({
|
|
1589
|
+
id,
|
|
1590
|
+
value
|
|
1591
|
+
});
|
|
1592
|
+
continue;
|
|
1593
|
+
}
|
|
1594
|
+
stack.push({
|
|
1595
|
+
tokens: value,
|
|
1596
|
+
prefix: id,
|
|
1597
|
+
flat: flat$1
|
|
1598
|
+
});
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
return flattened;
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
//#endregion
|
|
1605
|
+
//#region src/composables/useTheme/adapters/adapter.ts
|
|
1606
|
+
var ThemeAdapter = class {
|
|
1607
|
+
prefix;
|
|
1608
|
+
constructor(prefix) {
|
|
1609
|
+
this.prefix = prefix;
|
|
1610
|
+
}
|
|
1611
|
+
generate(colors) {
|
|
1612
|
+
let css = "";
|
|
1613
|
+
for (const theme in colors) {
|
|
1614
|
+
const themeColors = colors[theme];
|
|
1615
|
+
if (!themeColors) continue;
|
|
1616
|
+
const vars = Object.entries(themeColors).map(([key, val]) => ` --${this.prefix}-${key}: ${val};`).join("\n");
|
|
1617
|
+
css += `.${this.prefix}-theme--${theme} {\n${vars}\n}\n`;
|
|
1618
|
+
}
|
|
1619
|
+
return css;
|
|
1620
|
+
}
|
|
1621
|
+
};
|
|
1622
|
+
|
|
1623
|
+
//#endregion
|
|
1624
|
+
//#region src/composables/useTheme/adapters/v0.ts
|
|
1625
|
+
/**
|
|
1626
|
+
* Theme adapter implementation for Vuetify v0 design system.
|
|
1627
|
+
* This adapter generates CSS custom properties and injects them into the DOM
|
|
1628
|
+
* as a stylesheet, allowing themes to be applied globally.
|
|
1629
|
+
*/
|
|
1630
|
+
var Vuetify0ThemeAdapter = class extends ThemeAdapter {
|
|
1631
|
+
cspNonce;
|
|
1632
|
+
stylesheetId = "v0-theme-stylesheet";
|
|
1633
|
+
constructor(options = {}) {
|
|
1634
|
+
super(options.prefix ?? "v0");
|
|
1635
|
+
this.cspNonce = options.cspNonce;
|
|
1636
|
+
this.stylesheetId = options.stylesheetId ?? this.stylesheetId;
|
|
1637
|
+
}
|
|
1638
|
+
update(colors) {
|
|
1639
|
+
if (!IN_BROWSER) return;
|
|
1640
|
+
this.upsert(this.generate(colors));
|
|
1641
|
+
}
|
|
1642
|
+
upsert(styles) {
|
|
1643
|
+
if (!IN_BROWSER) return;
|
|
1644
|
+
let styleEl = document.querySelector(`#${this.stylesheetId}`);
|
|
1645
|
+
if (!styleEl) {
|
|
1646
|
+
styleEl = document.createElement("style");
|
|
1647
|
+
styleEl.id = this.stylesheetId.startsWith("#") ? this.stylesheetId.slice(1) : this.stylesheetId;
|
|
1648
|
+
if (this.cspNonce) styleEl.setAttribute("nonce", this.cspNonce);
|
|
1649
|
+
document.head.append(styleEl);
|
|
1650
|
+
}
|
|
1651
|
+
styleEl.textContent = styles;
|
|
1652
|
+
}
|
|
1653
|
+
};
|
|
1654
|
+
|
|
1655
|
+
//#endregion
|
|
1656
|
+
//#region src/composables/useTheme/index.ts
|
|
1657
|
+
/**
|
|
1658
|
+
* Creates a theme registry for managing theme selections with dynamic color resolution.
|
|
1659
|
+
* Supports token-based color systems and lazy theme loading for optimal performance.
|
|
1660
|
+
*
|
|
1661
|
+
* @param namespace The namespace for the theme context.
|
|
1662
|
+
* @param options Configuration including adapter and themes.
|
|
1663
|
+
* @template Z The type of theme context.
|
|
1664
|
+
* @template E The type of theme items managed by the registry.
|
|
1665
|
+
* @returns A tuple containing inject, provide functions and the theme context.
|
|
1666
|
+
*
|
|
1667
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-theme
|
|
1668
|
+
*/
|
|
1669
|
+
function createTheme(namespace = "v0:theme", options = {}) {
|
|
1670
|
+
const { themes = {}, palette = {} } = options;
|
|
1671
|
+
const [useThemeContext, _provideThemeContext] = createContext(namespace);
|
|
1672
|
+
const tokens = useTokens({
|
|
1673
|
+
palette,
|
|
1674
|
+
...themes
|
|
1675
|
+
}, { flat: true });
|
|
1676
|
+
const registry = useSingle();
|
|
1677
|
+
for (const id in themes) {
|
|
1678
|
+
const { colors: value,...theme } = themes[id];
|
|
1679
|
+
register({
|
|
1680
|
+
id,
|
|
1681
|
+
value,
|
|
1682
|
+
...theme
|
|
1683
|
+
});
|
|
1684
|
+
if (id === options.default && !registry.selectedId.value) registry.select(id);
|
|
1685
|
+
}
|
|
1686
|
+
const names = computed(() => registry.keys());
|
|
1687
|
+
const colors = computed(() => {
|
|
1688
|
+
const resolved = {};
|
|
1689
|
+
for (const theme of registry.values()) {
|
|
1690
|
+
if (theme.lazy && theme.id !== registry.selectedId.value) continue;
|
|
1691
|
+
resolved[theme.id] = resolve(theme.value);
|
|
1692
|
+
}
|
|
1693
|
+
return resolved;
|
|
1694
|
+
});
|
|
1695
|
+
function cycle(themes$1 = names.value) {
|
|
1696
|
+
const current = themes$1.indexOf(registry.selectedId.value ?? "");
|
|
1697
|
+
const next = current === -1 ? 0 : (current + 1) % themes$1.length;
|
|
1698
|
+
registry.select(themes$1[next]);
|
|
1699
|
+
}
|
|
1700
|
+
function resolve(colors$1) {
|
|
1701
|
+
const resolved = {};
|
|
1702
|
+
for (const [key, value] of Object.entries(colors$1)) resolved[key] = tokens.isAlias(value) ? tokens.resolve(value) : value;
|
|
1703
|
+
return resolved;
|
|
1704
|
+
}
|
|
1705
|
+
function register(registration = {}) {
|
|
1706
|
+
const item = {
|
|
1707
|
+
lazy: false,
|
|
1708
|
+
dark: false,
|
|
1709
|
+
...registration
|
|
1710
|
+
};
|
|
1711
|
+
return registry.register(item);
|
|
1712
|
+
}
|
|
1713
|
+
const context = {
|
|
1714
|
+
...registry,
|
|
1715
|
+
colors,
|
|
1716
|
+
register,
|
|
1717
|
+
cycle
|
|
1718
|
+
};
|
|
1719
|
+
function provideThemeContext(_context = context, app) {
|
|
1720
|
+
return _provideThemeContext(_context, app);
|
|
1721
|
+
}
|
|
1722
|
+
return createTrinity(useThemeContext, provideThemeContext, context);
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1725
|
+
* Simple hook to access the theme context.
|
|
1726
|
+
*
|
|
1727
|
+
* @returns The theme context containing current theme state and utilities.
|
|
1728
|
+
*
|
|
1729
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-theme
|
|
1730
|
+
*/
|
|
1731
|
+
function useTheme() {
|
|
1732
|
+
return useContext("v0:theme");
|
|
1733
|
+
}
|
|
1734
|
+
/**
|
|
1735
|
+
* Creates a Vue plugin for theme management with automatic color system updates.
|
|
1736
|
+
* Integrates with token system for dynamic color resolution and provides reactive
|
|
1737
|
+
* theme switching capabilities throughout the application.
|
|
1738
|
+
*
|
|
1739
|
+
* @param options Configuration for themes, palette, and adapter.
|
|
1740
|
+
* @template Z The type of theme context.
|
|
1741
|
+
* @template E The type of theme items.
|
|
1742
|
+
* @returns A Vue plugin object with install method.
|
|
1743
|
+
*
|
|
1744
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-theme
|
|
1745
|
+
*/
|
|
1746
|
+
function createThemePlugin(_options = {}) {
|
|
1747
|
+
const { adapter = new Vuetify0ThemeAdapter(), palette = {}, themes = {},...options } = _options;
|
|
1748
|
+
const [, provideThemeContext, themeContext] = createTheme("v0:theme", {
|
|
1749
|
+
...options,
|
|
1750
|
+
themes,
|
|
1751
|
+
palette
|
|
1752
|
+
});
|
|
1753
|
+
function update(colors) {
|
|
1754
|
+
adapter.update(colors);
|
|
1755
|
+
}
|
|
1756
|
+
return createPlugin({
|
|
1757
|
+
namespace: "v0:theme",
|
|
1758
|
+
provide: (app) => {
|
|
1759
|
+
provideThemeContext(themeContext, app);
|
|
1760
|
+
},
|
|
1761
|
+
setup: () => {
|
|
1762
|
+
if (IN_BROWSER) watch(themeContext.colors, update, {
|
|
1763
|
+
immediate: true,
|
|
1764
|
+
deep: true
|
|
1765
|
+
});
|
|
1766
|
+
else update(themeContext.colors.value);
|
|
1767
|
+
}
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
//#endregion
|
|
1772
|
+
//#region src/components/Theme/ThemeItem.vue?vue&type=script&setup=true&lang.ts
|
|
1773
|
+
var ThemeItem_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
1774
|
+
name: "ThemeItem",
|
|
1775
|
+
__name: "ThemeItem",
|
|
1776
|
+
setup(__props) {
|
|
1777
|
+
const themeContext = useTheme();
|
|
1778
|
+
return (_ctx, _cache) => {
|
|
1779
|
+
return renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps(unref(themeContext))));
|
|
1780
|
+
};
|
|
1781
|
+
}
|
|
1782
|
+
});
|
|
1783
|
+
|
|
1784
|
+
//#endregion
|
|
1785
|
+
//#region src/components/Theme/ThemeItem.vue
|
|
1786
|
+
var ThemeItem_default = ThemeItem_vue_vue_type_script_setup_true_lang_default;
|
|
1787
|
+
|
|
1788
|
+
//#endregion
|
|
1789
|
+
//#region src/components/Theme/ThemeRoot.vue?vue&type=script&setup=true&lang.ts
|
|
1790
|
+
var ThemeRoot_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
1791
|
+
name: "ThemeRoot",
|
|
1792
|
+
__name: "ThemeRoot",
|
|
1793
|
+
props: {
|
|
1794
|
+
namespace: { default: "v0:theme" },
|
|
1795
|
+
themes: { default: () => [] }
|
|
1796
|
+
},
|
|
1797
|
+
setup(__props) {
|
|
1798
|
+
const [provideThemeContext] = createTheme(__props.namespace);
|
|
1799
|
+
const themeContext = provideThemeContext();
|
|
1800
|
+
for (const theme of __props.themes) themeContext.register(theme);
|
|
1801
|
+
return (_ctx, _cache) => {
|
|
1802
|
+
return renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps(unref(themeContext))));
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
});
|
|
1806
|
+
|
|
1807
|
+
//#endregion
|
|
1808
|
+
//#region src/components/Theme/ThemeRoot.vue
|
|
1809
|
+
var ThemeRoot_default = ThemeRoot_vue_vue_type_script_setup_true_lang_default;
|
|
1810
|
+
|
|
1811
|
+
//#endregion
|
|
1812
|
+
//#region src/components/Theme/index.ts
|
|
1813
|
+
const Theme = {
|
|
1814
|
+
Item: ThemeItem_default,
|
|
1815
|
+
Root: ThemeRoot_default
|
|
1816
|
+
};
|
|
1817
|
+
|
|
1818
|
+
//#endregion
|
|
1819
|
+
//#region src/transformers/toArray/index.ts
|
|
1820
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
1821
|
+
function toArray(value) {
|
|
1822
|
+
return isNullOrUndefined(value) ? [] : Array.isArray(value) ? value : [value];
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
//#endregion
|
|
1826
|
+
//#region src/transformers/toReactive/index.ts
|
|
1827
|
+
/**
|
|
1828
|
+
* Converts an object to a reactive reference using Vue's reactivity system.
|
|
1829
|
+
* This function creates a reactive version of the provided object,
|
|
1830
|
+
* making its properties automatically track dependencies and trigger re-renders
|
|
1831
|
+
* when they change.
|
|
1832
|
+
*
|
|
1833
|
+
* @param objectRef - A reference to an object that should be made reactive.
|
|
1834
|
+
* @template Z The type of the object that extends object.
|
|
1835
|
+
* @returns A reactive reference to the object.
|
|
1836
|
+
*/
|
|
1837
|
+
function toReactive(objectRef) {
|
|
1838
|
+
if (!isRef(objectRef)) return reactive(objectRef);
|
|
1839
|
+
const target = objectRef.value;
|
|
1840
|
+
if (target instanceof Map) {
|
|
1841
|
+
const mapProxy = new Proxy(/* @__PURE__ */ new Map(), { get(_, p) {
|
|
1842
|
+
const map = objectRef.value;
|
|
1843
|
+
if (p === "get") return (key) => unref(map.get(key));
|
|
1844
|
+
if (p === "set") return (key, value) => {
|
|
1845
|
+
const existingValue = map.get(key);
|
|
1846
|
+
if (isRef(existingValue)) existingValue.value = unref(value);
|
|
1847
|
+
else map.set(key, value);
|
|
1848
|
+
return mapProxy;
|
|
1849
|
+
};
|
|
1850
|
+
if (p === "has") return (key) => map.has(key);
|
|
1851
|
+
if (p === "delete") return (key) => map.delete(key);
|
|
1852
|
+
if (p === "clear") return () => map.clear();
|
|
1853
|
+
if (p === "size") return map.size;
|
|
1854
|
+
if (p === "keys") return () => map.keys();
|
|
1855
|
+
if (p === "values") return function* () {
|
|
1856
|
+
for (const value of map.values()) yield unref(value);
|
|
1857
|
+
};
|
|
1858
|
+
if (p === "entries") return function* () {
|
|
1859
|
+
for (const [key, value] of map.entries()) yield [key, unref(value)];
|
|
1860
|
+
};
|
|
1861
|
+
if (p === "forEach") return (callback, thisArg) => {
|
|
1862
|
+
for (const [key, value] of map.entries()) callback.call(thisArg, unref(value), key, mapProxy);
|
|
1863
|
+
};
|
|
1864
|
+
if (p === Symbol.iterator) return function* () {
|
|
1865
|
+
for (const [key, value] of map.entries()) yield [key, unref(value)];
|
|
1866
|
+
};
|
|
1867
|
+
return Reflect.get(map, p);
|
|
1868
|
+
} });
|
|
1869
|
+
return reactive(mapProxy);
|
|
1870
|
+
}
|
|
1871
|
+
if (target instanceof Set) {
|
|
1872
|
+
const setProxy = new Proxy(/* @__PURE__ */ new Set(), { get(_, p) {
|
|
1873
|
+
const set = objectRef.value;
|
|
1874
|
+
if (p === "add") return (value) => {
|
|
1875
|
+
set.add(value);
|
|
1876
|
+
return setProxy;
|
|
1877
|
+
};
|
|
1878
|
+
if (p === "has") return (value) => set.has(value);
|
|
1879
|
+
if (p === "delete") return (value) => set.delete(value);
|
|
1880
|
+
if (p === "clear") return () => set.clear();
|
|
1881
|
+
if (p === "size") return set.size;
|
|
1882
|
+
if (p === "keys" || p === "values") return function* () {
|
|
1883
|
+
for (const value of set.values()) yield unref(value);
|
|
1884
|
+
};
|
|
1885
|
+
if (p === "entries") return function* () {
|
|
1886
|
+
for (const value of set.values()) {
|
|
1887
|
+
const unreffedValue = unref(value);
|
|
1888
|
+
yield [unreffedValue, unreffedValue];
|
|
1889
|
+
}
|
|
1890
|
+
};
|
|
1891
|
+
if (p === "forEach") return (callback, thisArg) => {
|
|
1892
|
+
for (const value of set) {
|
|
1893
|
+
const unreffedValue = unref(value);
|
|
1894
|
+
callback.call(thisArg, unreffedValue, unreffedValue, setProxy);
|
|
1895
|
+
}
|
|
1896
|
+
};
|
|
1897
|
+
if (p === Symbol.iterator) return function* () {
|
|
1898
|
+
for (const value of set.values()) yield unref(value);
|
|
1899
|
+
};
|
|
1900
|
+
return Reflect.get(set, p);
|
|
1901
|
+
} });
|
|
1902
|
+
return reactive(setProxy);
|
|
1903
|
+
}
|
|
1904
|
+
const proxy = new Proxy({}, {
|
|
1905
|
+
get(_, p, receiver) {
|
|
1906
|
+
return unref(Reflect.get(objectRef.value, p, receiver));
|
|
1907
|
+
},
|
|
1908
|
+
set(_, p, value) {
|
|
1909
|
+
const currentTarget = objectRef.value;
|
|
1910
|
+
currentTarget[p] = value;
|
|
1911
|
+
return true;
|
|
1912
|
+
},
|
|
1913
|
+
deleteProperty(_, p) {
|
|
1914
|
+
return Reflect.deleteProperty(objectRef.value, p);
|
|
1915
|
+
},
|
|
1916
|
+
has(_, p) {
|
|
1917
|
+
return Reflect.has(objectRef.value, p);
|
|
1918
|
+
},
|
|
1919
|
+
ownKeys() {
|
|
1920
|
+
return Object.keys(objectRef.value);
|
|
1921
|
+
},
|
|
1922
|
+
getOwnPropertyDescriptor(_, p) {
|
|
1923
|
+
const desc = Reflect.getOwnPropertyDescriptor(objectRef.value, p);
|
|
1924
|
+
if (!desc) return;
|
|
1925
|
+
const newDesc = {
|
|
1926
|
+
...desc,
|
|
1927
|
+
configurable: true
|
|
1928
|
+
};
|
|
1929
|
+
if ("value" in newDesc) newDesc.value = unref(newDesc.value);
|
|
1930
|
+
return newDesc;
|
|
1931
|
+
}
|
|
1932
|
+
});
|
|
1933
|
+
return reactive(proxy);
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
//#endregion
|
|
1937
|
+
//#region src/composables/useEventListener/index.ts
|
|
1938
|
+
function useEventListener(target, event, listener, options) {
|
|
1939
|
+
const cleanups = [];
|
|
1940
|
+
function cleanup() {
|
|
1941
|
+
for (const fn of cleanups) fn();
|
|
1942
|
+
cleanups.length = 0;
|
|
1943
|
+
}
|
|
1944
|
+
function register(el, event$1, listener$1, options$1) {
|
|
1945
|
+
el.addEventListener(event$1, listener$1, options$1);
|
|
1946
|
+
return () => el.removeEventListener(event$1, listener$1, options$1);
|
|
1947
|
+
}
|
|
1948
|
+
const stopWatcher = watch(() => [
|
|
1949
|
+
toValue(target),
|
|
1950
|
+
toValue(event),
|
|
1951
|
+
unref(listener),
|
|
1952
|
+
toValue(options)
|
|
1953
|
+
], ([el, events, listeners, opts]) => {
|
|
1954
|
+
cleanup();
|
|
1955
|
+
if (!el) return;
|
|
1956
|
+
const eventList = toArray(events);
|
|
1957
|
+
const listenerList = toArray(listeners);
|
|
1958
|
+
for (const event$1 of eventList) for (const listenerFn of listenerList) cleanups.push(register(el, event$1, listenerFn, opts));
|
|
1959
|
+
}, {
|
|
1960
|
+
immediate: true,
|
|
1961
|
+
flush: "post"
|
|
1962
|
+
});
|
|
1963
|
+
function stop() {
|
|
1964
|
+
stopWatcher();
|
|
1965
|
+
cleanup();
|
|
1966
|
+
}
|
|
1967
|
+
onScopeDispose(stop, true);
|
|
1968
|
+
return stop;
|
|
1969
|
+
}
|
|
1970
|
+
/**
|
|
1971
|
+
* Convenience function for attaching event listeners to the window object.
|
|
1972
|
+
* This function provides a simplified API by pre-binding the window target,
|
|
1973
|
+
* making it easier to handle window-specific events with automatic cleanup.
|
|
1974
|
+
*
|
|
1975
|
+
* @param event Event name(s) to listen for from WindowEventMap.
|
|
1976
|
+
* @param listener Event handler function(s) with proper window event typing.
|
|
1977
|
+
* @param options Optional event listener configuration.
|
|
1978
|
+
* @returns Function to manually remove all attached listeners.
|
|
1979
|
+
*/
|
|
1980
|
+
function useWindowEventListener(event, listener, options) {
|
|
1981
|
+
return useEventListener(window, event, listener, options);
|
|
1982
|
+
}
|
|
1983
|
+
/**
|
|
1984
|
+
* Convenience function for attaching event listeners to the document object.
|
|
1985
|
+
* This function provides a simplified API by pre-binding the document target,
|
|
1986
|
+
* making it easier to handle document-specific events with automatic cleanup.
|
|
1987
|
+
*
|
|
1988
|
+
* @param event Event name(s) to listen for from DocumentEventMap.
|
|
1989
|
+
* @param listener Event handler function(s) with proper document event typing.
|
|
1990
|
+
* @param options Optional event listener configuration.
|
|
1991
|
+
* @returns Function to manually remove all attached listeners.
|
|
1992
|
+
*/
|
|
1993
|
+
function useDocumentEventListener(event, listener, options) {
|
|
1994
|
+
return useEventListener(document, event, listener, options);
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
//#endregion
|
|
1998
|
+
//#region src/composables/useGroup/index.ts
|
|
1999
|
+
/**
|
|
2000
|
+
* Creates a group selection context for managing collections of items where multiple selections can be made.
|
|
2001
|
+
* This function extends the selection functionality with group selection capabilities.
|
|
2002
|
+
*
|
|
2003
|
+
* @param options Optional configuration for group selection behavior.
|
|
2004
|
+
* @template Z The type of items managed by the group selection.
|
|
2005
|
+
* @template E The type of the group selection context.
|
|
2006
|
+
* @returns The group selection context object.
|
|
2007
|
+
*/
|
|
2008
|
+
function useGroup(options) {
|
|
2009
|
+
const registry = useSelection(options);
|
|
2010
|
+
const selectedIndexes = computed(() => {
|
|
2011
|
+
return new Set(Array.from(registry.selectedItems.value).map((item) => item?.index));
|
|
2012
|
+
});
|
|
2013
|
+
function select(ids) {
|
|
2014
|
+
for (const id of toArray(ids)) registry.select(id);
|
|
2015
|
+
}
|
|
2016
|
+
function unselect(ids) {
|
|
2017
|
+
for (const id of toArray(ids)) registry.unselect(id);
|
|
2018
|
+
}
|
|
2019
|
+
function toggle(ids) {
|
|
2020
|
+
for (const id of toArray(ids)) registry.toggle(id);
|
|
2021
|
+
}
|
|
2022
|
+
return {
|
|
2023
|
+
...registry,
|
|
2024
|
+
select,
|
|
2025
|
+
unselect,
|
|
2026
|
+
toggle,
|
|
2027
|
+
selectedIndexes
|
|
2028
|
+
};
|
|
2029
|
+
}
|
|
2030
|
+
/**
|
|
2031
|
+
* Creates a group selection registry context with full injection/provision control.
|
|
2032
|
+
* Returns the complete trinity for advanced usage scenarios.
|
|
2033
|
+
*
|
|
2034
|
+
* @param namespace The namespace for the group selection registry context
|
|
2035
|
+
* @param options Optional configuration for group selection behavior.
|
|
2036
|
+
* @template Z The structure of the registry group selection items.
|
|
2037
|
+
* @template E The available methods for the group's context.
|
|
2038
|
+
* @returns A tuple containing the inject function, provide function, and the group selection context.
|
|
2039
|
+
*/
|
|
2040
|
+
function createGroupContext(namespace, options) {
|
|
2041
|
+
const [useGroupContext, _provideGroupContext] = createContext(namespace);
|
|
2042
|
+
const context = useGroup(options);
|
|
2043
|
+
function provideGroupContext(_context = context, app) {
|
|
2044
|
+
return _provideGroupContext(_context, app);
|
|
2045
|
+
}
|
|
2046
|
+
return createTrinity(useGroupContext, provideGroupContext, context);
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
//#endregion
|
|
2050
|
+
//#region src/composables/useFeatures/index.ts
|
|
2051
|
+
/**
|
|
2052
|
+
*
|
|
2053
|
+
* @param namespace The namespace for the feature context
|
|
2054
|
+
* @param options Configure initial features to register
|
|
2055
|
+
* @template Z The type of feature ticket
|
|
2056
|
+
* @template E The type of feature context
|
|
2057
|
+
* @returns A context trinity for the features context
|
|
2058
|
+
*
|
|
2059
|
+
* @see https://0.vuetifyjs.com/composables/plugins/create-features
|
|
2060
|
+
*/
|
|
2061
|
+
function createFeatures(namespace = "v0:features", options = {}) {
|
|
2062
|
+
const [useFeaturesContext, _provideFeaturesContext] = createContext(namespace);
|
|
2063
|
+
const tokens = useTokens(options.features, { flat: true });
|
|
2064
|
+
const registry = useGroup();
|
|
2065
|
+
for (const [id, { value }] of tokens.entries()) register({
|
|
2066
|
+
id,
|
|
2067
|
+
value
|
|
2068
|
+
});
|
|
2069
|
+
function variation(id, fallback = null) {
|
|
2070
|
+
const ticket = registry.get(id);
|
|
2071
|
+
if (!ticket) return fallback;
|
|
2072
|
+
return isObject(ticket.value) ? ticket.value.$variation ?? fallback : fallback;
|
|
2073
|
+
}
|
|
2074
|
+
function register(registration = {}) {
|
|
2075
|
+
const item = {
|
|
2076
|
+
value: false,
|
|
2077
|
+
...registration
|
|
2078
|
+
};
|
|
2079
|
+
const ticket = registry.register(item);
|
|
2080
|
+
if (isBoolean(ticket.value) || isObject(ticket.value) && isBoolean(ticket.value.$value) && ticket.value.$value === true) registry.select(ticket.id);
|
|
2081
|
+
return ticket;
|
|
2082
|
+
}
|
|
2083
|
+
const context = {
|
|
2084
|
+
...registry,
|
|
2085
|
+
variation,
|
|
2086
|
+
register
|
|
2087
|
+
};
|
|
2088
|
+
function provideFeaturesContext(_context = context, app) {
|
|
2089
|
+
return _provideFeaturesContext(_context, app);
|
|
2090
|
+
}
|
|
2091
|
+
return createTrinity(useFeaturesContext, provideFeaturesContext, context);
|
|
2092
|
+
}
|
|
2093
|
+
/**
|
|
2094
|
+
* Simple hook to access the theme context.
|
|
2095
|
+
*
|
|
2096
|
+
* @returns The features context containing current theme state and utilities.
|
|
2097
|
+
*
|
|
2098
|
+
* @see https://0.vuetifyjs.com/composables/plugins/create-features
|
|
2099
|
+
*/
|
|
2100
|
+
function useFeatures() {
|
|
2101
|
+
return useContext("v0:features");
|
|
2102
|
+
}
|
|
2103
|
+
/**
|
|
2104
|
+
* Creates a Vue plugin for feature management with variation support.
|
|
2105
|
+
*
|
|
2106
|
+
* @param options Configuration for initial features to register.
|
|
2107
|
+
* @template Z The type of feature ticket.
|
|
2108
|
+
* @template E The type of feature context.
|
|
2109
|
+
* @returns A Vue plugin object with install method.
|
|
2110
|
+
*
|
|
2111
|
+
* @see https://0.vuetifyjs.com/composables/plugins/create-features
|
|
2112
|
+
*/
|
|
2113
|
+
function createFeaturesPlugin(options = {}) {
|
|
2114
|
+
const [, provideFeaturesContext, context] = createFeatures("v0:features", options);
|
|
2115
|
+
return createPlugin({
|
|
2116
|
+
namespace: "v0:features",
|
|
2117
|
+
provide: (app) => {
|
|
2118
|
+
provideFeaturesContext(context, app);
|
|
2119
|
+
}
|
|
2120
|
+
});
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
//#endregion
|
|
2124
|
+
//#region src/composables/useFilter/index.ts
|
|
2125
|
+
function defaultFilter(query, item, keys, mode = "some") {
|
|
2126
|
+
const queries = Array.isArray(query) ? query.map((q) => String(q).toLowerCase()) : [String(query).toLowerCase()];
|
|
2127
|
+
function match(value, q) {
|
|
2128
|
+
return String(value).toLowerCase().includes(q);
|
|
2129
|
+
}
|
|
2130
|
+
const stringValues = (typeof item === "object" && item !== null ? keys?.length ? keys.map((k) => item[k]) : Object.values(item) : [item]).map((v) => String(v).toLowerCase());
|
|
2131
|
+
if (mode === "some") return stringValues.some((val) => match(val, queries[0]));
|
|
2132
|
+
if (mode === "every") return stringValues.every((val) => match(val, queries[0]));
|
|
2133
|
+
if (mode === "union") return queries.some((q) => stringValues.some((val) => match(val, q)));
|
|
2134
|
+
if (mode === "intersection") return queries.every((q) => stringValues.some((val) => match(val, q)));
|
|
2135
|
+
return false;
|
|
2136
|
+
}
|
|
2137
|
+
function toRefOrGetter(value) {
|
|
2138
|
+
return isRef(value) ? value : typeof value === "function" ? toRef(value) : toRef(() => value);
|
|
2139
|
+
}
|
|
2140
|
+
/**
|
|
2141
|
+
* Creates a reactive filter for arrays based on query matching with configurable search modes.
|
|
2142
|
+
* Supports 'some' (any field matches), 'every' (all fields match), 'union' (any query matches),
|
|
2143
|
+
* and 'intersection' (all queries match) filtering strategies.
|
|
2144
|
+
*
|
|
2145
|
+
* @param query Filter query to match against items.
|
|
2146
|
+
* @param items Collection of items to filter.
|
|
2147
|
+
* @param options Optional configuration for the filter behavior.
|
|
2148
|
+
* @template Z The type of the items being filtered.
|
|
2149
|
+
* @returns A computed reference to the filtered items based on the query and options.
|
|
2150
|
+
*/
|
|
2151
|
+
function useFilter(query, items, options = {}) {
|
|
2152
|
+
const { customFilter, keys, mode = "some" } = options;
|
|
2153
|
+
const filterFunction = customFilter ?? ((q, i) => defaultFilter(q, i, keys, mode));
|
|
2154
|
+
const itemsRef = isRef(items) ? items : toRef(() => items);
|
|
2155
|
+
const queryRef = toRefOrGetter(query);
|
|
2156
|
+
return { items: computed(() => {
|
|
2157
|
+
const q = toValue(queryRef);
|
|
2158
|
+
const queries = (Array.isArray(q) ? q : [q]).filter((q$1) => String(q$1).trim());
|
|
2159
|
+
if (queries.length === 0) return itemsRef.value;
|
|
2160
|
+
const queryParam = queries.length === 1 ? queries[0] : queries;
|
|
2161
|
+
return itemsRef.value.filter((item) => filterFunction(queryParam, item));
|
|
2162
|
+
}) };
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
//#endregion
|
|
2166
|
+
//#region src/composables/useForm/index.ts
|
|
2167
|
+
function useForm(options) {
|
|
2168
|
+
const registry = useRegistry(options);
|
|
2169
|
+
const validateOn = options?.validateOn || "submit";
|
|
2170
|
+
function parse(value) {
|
|
2171
|
+
return value.toLowerCase().split(/\s+/);
|
|
2172
|
+
}
|
|
2173
|
+
function validatesOn(event) {
|
|
2174
|
+
return parse(validateOn).includes(event);
|
|
2175
|
+
}
|
|
2176
|
+
const isValidating = computed(() => {
|
|
2177
|
+
for (const ticket of registry.collection.values()) if (ticket.isValidating.value) return true;
|
|
2178
|
+
return false;
|
|
2179
|
+
});
|
|
2180
|
+
const isValid = computed(() => {
|
|
2181
|
+
let hasFields = false;
|
|
2182
|
+
for (const ticket of registry.values()) {
|
|
2183
|
+
hasFields = true;
|
|
2184
|
+
if (ticket.isValid.value === false) return false;
|
|
2185
|
+
if (ticket.isValid.value === null) return null;
|
|
2186
|
+
}
|
|
2187
|
+
return hasFields ? true : null;
|
|
2188
|
+
});
|
|
2189
|
+
function reset() {
|
|
2190
|
+
for (const ticket of registry.values()) ticket.reset();
|
|
2191
|
+
}
|
|
2192
|
+
async function submit() {
|
|
2193
|
+
return validate(registry.keys());
|
|
2194
|
+
}
|
|
2195
|
+
async function validate(id) {
|
|
2196
|
+
const validating = toArray(id);
|
|
2197
|
+
if (validatesOn("submit")) return (await Promise.all(validating.map(async (id$1) => await registry.get(id$1)?.validate() ?? true))).every(Boolean);
|
|
2198
|
+
return validating.map((id$1) => registry.get(id$1)).filter(Boolean).every((ticket) => ticket.isValid.value === true);
|
|
2199
|
+
}
|
|
2200
|
+
function register(registration) {
|
|
2201
|
+
const model = shallowRef(registration.value == null ? "" : toValue(registration.value));
|
|
2202
|
+
const rules = registration.rules || [];
|
|
2203
|
+
const errors = shallowRef([]);
|
|
2204
|
+
const isValidating$1 = shallowRef(false);
|
|
2205
|
+
const initialValue = model.value;
|
|
2206
|
+
const triggers = registration.validateOn || validateOn;
|
|
2207
|
+
const isPristine = shallowRef(true);
|
|
2208
|
+
const isValid$1 = shallowRef(null);
|
|
2209
|
+
function _validatesOn(event) {
|
|
2210
|
+
return parse(triggers).includes(event);
|
|
2211
|
+
}
|
|
2212
|
+
function _reset() {
|
|
2213
|
+
model.value = initialValue;
|
|
2214
|
+
errors.value = [];
|
|
2215
|
+
isPristine.value = true;
|
|
2216
|
+
isValid$1.value = null;
|
|
2217
|
+
}
|
|
2218
|
+
async function validate$1(silent = false) {
|
|
2219
|
+
if (rules.length === 0) return true;
|
|
2220
|
+
isValidating$1.value = true;
|
|
2221
|
+
try {
|
|
2222
|
+
const errorMessages = (await Promise.all(rules.map((rule) => rule(model.value)))).filter((result) => typeof result === "string");
|
|
2223
|
+
if (!silent) {
|
|
2224
|
+
errors.value = errorMessages;
|
|
2225
|
+
isValid$1.value = errorMessages.length === 0;
|
|
2226
|
+
isPristine.value = toValue(model) === initialValue;
|
|
2227
|
+
}
|
|
2228
|
+
return errorMessages.length === 0;
|
|
2229
|
+
} finally {
|
|
2230
|
+
isValidating$1.value = false;
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
const item = {
|
|
2234
|
+
...registration,
|
|
2235
|
+
rules,
|
|
2236
|
+
errors,
|
|
2237
|
+
disabled: registration.disabled || false,
|
|
2238
|
+
validateOn: triggers,
|
|
2239
|
+
isValidating: isValidating$1,
|
|
2240
|
+
isPristine,
|
|
2241
|
+
isValid: isValid$1,
|
|
2242
|
+
reset: _reset,
|
|
2243
|
+
validate: validate$1
|
|
2244
|
+
};
|
|
2245
|
+
const ticket = registry.register(item);
|
|
2246
|
+
Object.defineProperty(ticket, "value", {
|
|
2247
|
+
get() {
|
|
2248
|
+
return model.value;
|
|
2249
|
+
},
|
|
2250
|
+
set(val) {
|
|
2251
|
+
model.value = val;
|
|
2252
|
+
isPristine.value = val === initialValue;
|
|
2253
|
+
isValid$1.value = null;
|
|
2254
|
+
if (_validatesOn("change")) validate$1();
|
|
2255
|
+
},
|
|
2256
|
+
enumerable: true,
|
|
2257
|
+
configurable: true
|
|
2258
|
+
});
|
|
2259
|
+
return ticket;
|
|
2260
|
+
}
|
|
2261
|
+
return {
|
|
2262
|
+
...registry,
|
|
2263
|
+
register,
|
|
2264
|
+
reset,
|
|
2265
|
+
submit,
|
|
2266
|
+
validateOn,
|
|
2267
|
+
isValid,
|
|
2268
|
+
isValidating
|
|
2269
|
+
};
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2272
|
+
//#endregion
|
|
2273
|
+
//#region src/composables/useIntersectionObserver/index.ts
|
|
2274
|
+
/**
|
|
2275
|
+
* Composable for observing element intersection with viewport or ancestor
|
|
2276
|
+
*
|
|
2277
|
+
* @param target - Element ref to observe
|
|
2278
|
+
* @param callback - Callback fired on intersection change
|
|
2279
|
+
* @param options - Observer options
|
|
2280
|
+
* @returns Observer controls and intersection state
|
|
2281
|
+
*
|
|
2282
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver
|
|
2283
|
+
*/
|
|
2284
|
+
function useIntersectionObserver(target, callback, options = {}) {
|
|
2285
|
+
const { isHydrated } = useHydration();
|
|
2286
|
+
const observer = shallowRef();
|
|
2287
|
+
const isPaused = shallowRef(false);
|
|
2288
|
+
const isIntersecting = shallowRef(false);
|
|
2289
|
+
watch([isHydrated, target], ([hydrated, el]) => {
|
|
2290
|
+
cleanup();
|
|
2291
|
+
if (!hydrated || !SUPPORTS_INTERSECTION_OBSERVER || !el) return;
|
|
2292
|
+
observer.value = new IntersectionObserver((entries) => {
|
|
2293
|
+
const transformedEntries = entries.map((entry) => ({
|
|
2294
|
+
boundingClientRect: entry.boundingClientRect,
|
|
2295
|
+
intersectionRatio: entry.intersectionRatio,
|
|
2296
|
+
intersectionRect: entry.intersectionRect,
|
|
2297
|
+
isIntersecting: entry.isIntersecting,
|
|
2298
|
+
rootBounds: entry.rootBounds,
|
|
2299
|
+
target: entry.target,
|
|
2300
|
+
time: entry.time
|
|
2301
|
+
}));
|
|
2302
|
+
const latestEntry = transformedEntries.at(-1);
|
|
2303
|
+
if (latestEntry) isIntersecting.value = latestEntry.isIntersecting;
|
|
2304
|
+
callback(transformedEntries);
|
|
2305
|
+
}, {
|
|
2306
|
+
root: options.root || null,
|
|
2307
|
+
rootMargin: options.rootMargin || "0px",
|
|
2308
|
+
threshold: options.threshold || 0
|
|
2309
|
+
});
|
|
2310
|
+
observer.value.observe(el);
|
|
2311
|
+
if (options.immediate) {
|
|
2312
|
+
const syntheticEntry = {
|
|
2313
|
+
boundingClientRect: el.getBoundingClientRect(),
|
|
2314
|
+
intersectionRatio: 0,
|
|
2315
|
+
intersectionRect: new DOMRect(0, 0, 0, 0),
|
|
2316
|
+
isIntersecting: false,
|
|
2317
|
+
rootBounds: null,
|
|
2318
|
+
target: el,
|
|
2319
|
+
time: performance.now()
|
|
2320
|
+
};
|
|
2321
|
+
callback([syntheticEntry]);
|
|
2322
|
+
}
|
|
2323
|
+
});
|
|
2324
|
+
function setup() {
|
|
2325
|
+
if (!isHydrated.value || !SUPPORTS_INTERSECTION_OBSERVER || !target.value || isPaused.value) return;
|
|
2326
|
+
observer.value = new IntersectionObserver((entries) => {
|
|
2327
|
+
const transformedEntries = entries.map((entry) => ({
|
|
2328
|
+
boundingClientRect: entry.boundingClientRect,
|
|
2329
|
+
intersectionRatio: entry.intersectionRatio,
|
|
2330
|
+
intersectionRect: entry.intersectionRect,
|
|
2331
|
+
isIntersecting: entry.isIntersecting,
|
|
2332
|
+
rootBounds: entry.rootBounds,
|
|
2333
|
+
target: entry.target,
|
|
2334
|
+
time: entry.time
|
|
2335
|
+
}));
|
|
2336
|
+
const latestEntry = transformedEntries.at(-1);
|
|
2337
|
+
if (latestEntry) isIntersecting.value = latestEntry.isIntersecting;
|
|
2338
|
+
callback(transformedEntries);
|
|
2339
|
+
}, {
|
|
2340
|
+
root: options.root || null,
|
|
2341
|
+
rootMargin: options.rootMargin || "0px",
|
|
2342
|
+
threshold: options.threshold || 0
|
|
2343
|
+
});
|
|
2344
|
+
observer.value.observe(target.value);
|
|
2345
|
+
if (options.immediate) {
|
|
2346
|
+
const syntheticEntry = {
|
|
2347
|
+
boundingClientRect: target.value.getBoundingClientRect(),
|
|
2348
|
+
intersectionRatio: 0,
|
|
2349
|
+
intersectionRect: new DOMRect(0, 0, 0, 0),
|
|
2350
|
+
isIntersecting: false,
|
|
2351
|
+
rootBounds: null,
|
|
2352
|
+
target: target.value,
|
|
2353
|
+
time: performance.now()
|
|
2354
|
+
};
|
|
2355
|
+
callback([syntheticEntry]);
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
function cleanup() {
|
|
2359
|
+
if (observer.value) {
|
|
2360
|
+
observer.value.disconnect();
|
|
2361
|
+
observer.value = void 0;
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
function pause() {
|
|
2365
|
+
isPaused.value = true;
|
|
2366
|
+
observer.value?.disconnect();
|
|
2367
|
+
}
|
|
2368
|
+
function resume() {
|
|
2369
|
+
isPaused.value = false;
|
|
2370
|
+
setup();
|
|
2371
|
+
}
|
|
2372
|
+
function stop() {
|
|
2373
|
+
cleanup();
|
|
2374
|
+
}
|
|
2375
|
+
onUnmounted(stop);
|
|
2376
|
+
return {
|
|
2377
|
+
isIntersecting: readonly(isIntersecting),
|
|
2378
|
+
isPaused: readonly(isPaused),
|
|
2379
|
+
pause,
|
|
2380
|
+
resume,
|
|
2381
|
+
stop
|
|
2382
|
+
};
|
|
2383
|
+
}
|
|
2384
|
+
/**
|
|
2385
|
+
* Convenience composable for simple intersection detection
|
|
2386
|
+
*
|
|
2387
|
+
* @param target - Element ref to observe
|
|
2388
|
+
* @param options - Observer options
|
|
2389
|
+
* @returns Reactive intersection state
|
|
2390
|
+
*/
|
|
2391
|
+
function useElementIntersection(target, options = {}) {
|
|
2392
|
+
const isIntersecting = shallowRef(false);
|
|
2393
|
+
const intersectionRatio = shallowRef(0);
|
|
2394
|
+
useIntersectionObserver(target, (entries) => {
|
|
2395
|
+
const entry = entries.at(-1);
|
|
2396
|
+
if (entry) {
|
|
2397
|
+
isIntersecting.value = entry.isIntersecting;
|
|
2398
|
+
intersectionRatio.value = entry.intersectionRatio;
|
|
2399
|
+
}
|
|
2400
|
+
}, {
|
|
2401
|
+
immediate: true,
|
|
2402
|
+
...options
|
|
2403
|
+
});
|
|
2404
|
+
return {
|
|
2405
|
+
isIntersecting: readonly(isIntersecting),
|
|
2406
|
+
intersectionRatio: readonly(intersectionRatio)
|
|
2407
|
+
};
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
//#endregion
|
|
2411
|
+
//#region src/composables/useKeydown/index.ts
|
|
2412
|
+
/**
|
|
2413
|
+
* Sets up global keyboard event listeners for specified key handlers with automatic cleanup.
|
|
2414
|
+
* This composable automatically starts listening when mounted and cleans up when the scope
|
|
2415
|
+
* is disposed, providing a clean way to handle global keyboard interactions.
|
|
2416
|
+
*
|
|
2417
|
+
* @param handlers A single handler or array of handlers to register for keydown events.
|
|
2418
|
+
* @returns Object with methods to manually start and stop listening for keydown events.
|
|
2419
|
+
*/
|
|
2420
|
+
function useKeydown(handlers) {
|
|
2421
|
+
const keyHandlers = Array.isArray(handlers) ? handlers : [handlers];
|
|
2422
|
+
function onKeydown(event) {
|
|
2423
|
+
const handler = keyHandlers.find((h) => h.key === event.key);
|
|
2424
|
+
if (handler) {
|
|
2425
|
+
if (handler.preventDefault) event.preventDefault();
|
|
2426
|
+
if (handler.stopPropagation) event.stopPropagation();
|
|
2427
|
+
handler.handler(event);
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
function startListening() {
|
|
2431
|
+
document.addEventListener("keydown", onKeydown);
|
|
2432
|
+
}
|
|
2433
|
+
function stopListening() {
|
|
2434
|
+
document.removeEventListener("keydown", onKeydown);
|
|
2435
|
+
}
|
|
2436
|
+
if (getCurrentScope()) onMounted(startListening);
|
|
2437
|
+
onScopeDispose(stopListening, true);
|
|
2438
|
+
return {
|
|
2439
|
+
startListening,
|
|
2440
|
+
stopListening
|
|
2441
|
+
};
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
//#endregion
|
|
2445
|
+
//#region src/composables/useLocale/adapters/v0.ts
|
|
2446
|
+
/**
|
|
2447
|
+
* Vuetify0.x locale adapter implementation
|
|
2448
|
+
*
|
|
2449
|
+
* This adapter provides translation and number formatting
|
|
2450
|
+
* capabilities using the Intl API and supports both
|
|
2451
|
+
* numbered and named variables in translation strings.
|
|
2452
|
+
*/
|
|
2453
|
+
var Vuetify0LocaleAdapter = class {
|
|
2454
|
+
t(message, ...params) {
|
|
2455
|
+
let resolvedMessage = message;
|
|
2456
|
+
if (params.length > 0 && typeof params[0] === "object" && params[0] !== null && !Array.isArray(params[0])) {
|
|
2457
|
+
const variables = params[0];
|
|
2458
|
+
resolvedMessage = resolvedMessage.replace(/{([a-zA-Z][a-zA-Z0-9_]*)}/g, (match, name) => {
|
|
2459
|
+
return variables[name] === void 0 ? match : String(variables[name]);
|
|
2460
|
+
});
|
|
2461
|
+
params = params.slice(1);
|
|
2462
|
+
}
|
|
2463
|
+
resolvedMessage = resolvedMessage.replace(/\{(\d+)\}/g, (match, index) => {
|
|
2464
|
+
const idx = Number.parseInt(index, 10);
|
|
2465
|
+
if (params[idx] !== void 0) return String(params[idx]);
|
|
2466
|
+
return match;
|
|
2467
|
+
});
|
|
2468
|
+
return resolvedMessage;
|
|
2469
|
+
}
|
|
2470
|
+
n(value, locale, ...params) {
|
|
2471
|
+
if (!IN_BROWSER || !locale) return value.toString();
|
|
2472
|
+
const options = params[0];
|
|
2473
|
+
return new Intl.NumberFormat(String(locale), options).format(value);
|
|
2474
|
+
}
|
|
2475
|
+
};
|
|
2476
|
+
|
|
2477
|
+
//#endregion
|
|
2478
|
+
//#region src/composables/useLocale/index.ts
|
|
2479
|
+
/**
|
|
2480
|
+
* Creates a locale registry for managing internationalization with translations and number formatting.
|
|
2481
|
+
* Supports message resolution with token references and locale-specific number formatting.
|
|
2482
|
+
*
|
|
2483
|
+
* @param namespace The namespace for the locale context.
|
|
2484
|
+
* @param options Configuration including adapter and messages.
|
|
2485
|
+
* @template Z The type of the locale context.
|
|
2486
|
+
* @template E The type of the locale items managed by the registry.
|
|
2487
|
+
* @returns An array containing the inject function, provide function, and the locale context.
|
|
2488
|
+
*/
|
|
2489
|
+
function createLocale(namespace = "v0:locale", options = {}) {
|
|
2490
|
+
const { adapter = new Vuetify0LocaleAdapter(), messages = {} } = options;
|
|
2491
|
+
const [useLocaleContext, _provideLocaleContext] = createContext(namespace);
|
|
2492
|
+
const registry = useSingle();
|
|
2493
|
+
for (const id in messages) {
|
|
2494
|
+
registry.register({
|
|
2495
|
+
value: messages[id],
|
|
2496
|
+
id
|
|
2497
|
+
});
|
|
2498
|
+
if (id === options.default && !registry.selectedId.value) registry.select(id);
|
|
2499
|
+
}
|
|
2500
|
+
function t(key, ...params) {
|
|
2501
|
+
const locale = registry.selectedId.value;
|
|
2502
|
+
if (!locale) return key;
|
|
2503
|
+
const message = messages[locale]?.[key];
|
|
2504
|
+
const template = typeof message === "string" ? resolve(locale, message) : key;
|
|
2505
|
+
return adapter.t(template, ...params);
|
|
2506
|
+
}
|
|
2507
|
+
function n(value, ...params) {
|
|
2508
|
+
return adapter.n(value, registry.selectedId.value, ...params);
|
|
2509
|
+
}
|
|
2510
|
+
function resolve(locale, str) {
|
|
2511
|
+
return str.replace(/{([a-zA-Z0-9.-_]+)}/g, (match, linkedKey) => {
|
|
2512
|
+
const [linkedLocale, ...rest] = linkedKey.split(".");
|
|
2513
|
+
const keyPath = rest.join(".");
|
|
2514
|
+
const targetLocale = messages[linkedLocale] ? linkedLocale : locale;
|
|
2515
|
+
const targetKey = messages[linkedLocale] ? keyPath : linkedKey;
|
|
2516
|
+
const resolved = messages[targetLocale]?.[targetKey];
|
|
2517
|
+
return typeof resolved === "string" ? resolve(targetLocale, resolved) : match;
|
|
2518
|
+
});
|
|
2519
|
+
}
|
|
2520
|
+
const context = {
|
|
2521
|
+
...registry,
|
|
2522
|
+
t,
|
|
2523
|
+
n
|
|
2524
|
+
};
|
|
2525
|
+
function provideLocaleContext(_context = context, app) {
|
|
2526
|
+
return _provideLocaleContext(_context, app);
|
|
2527
|
+
}
|
|
2528
|
+
return createTrinity(useLocaleContext, provideLocaleContext, context);
|
|
2529
|
+
}
|
|
2530
|
+
/**
|
|
2531
|
+
* Simple hook to access the locale context.
|
|
2532
|
+
*
|
|
2533
|
+
* @returns The locale context containing translation and formatting functions.
|
|
2534
|
+
*/
|
|
2535
|
+
function useLocale() {
|
|
2536
|
+
return useContext("v0:locale");
|
|
2537
|
+
}
|
|
2538
|
+
/**
|
|
2539
|
+
* Creates a Vue plugin for internationalization with locale management and translation support.
|
|
2540
|
+
* Integrates with token system for message resolution and provides app-wide locale context.
|
|
2541
|
+
*
|
|
2542
|
+
* @param options Configuration for adapter, default locale, and messages.
|
|
2543
|
+
* @template Z The type of the locale context.
|
|
2544
|
+
* @template E The type of the locale items managed by the registry.
|
|
2545
|
+
* @template R The type of the token context.
|
|
2546
|
+
* @template O The type of the token items managed by the registry.
|
|
2547
|
+
* @returns Vue install function for the plugin
|
|
2548
|
+
*/
|
|
2549
|
+
function createLocalePlugin(options = {}) {
|
|
2550
|
+
const { adapter = new Vuetify0LocaleAdapter(), messages = {} } = options;
|
|
2551
|
+
const [, provideLocaleTokenContext, tokensContext] = createTokensContext("v0:locale:tokens", messages);
|
|
2552
|
+
const [, provideLocaleContext, localeContext] = createLocale("v0:locale", {
|
|
2553
|
+
adapter,
|
|
2554
|
+
messages
|
|
2555
|
+
});
|
|
2556
|
+
return createPlugin({
|
|
2557
|
+
namespace: "v0:locale",
|
|
2558
|
+
provide: (app) => {
|
|
2559
|
+
provideLocaleContext(localeContext, app);
|
|
2560
|
+
provideLocaleTokenContext(tokensContext, app);
|
|
2561
|
+
}
|
|
2562
|
+
});
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
//#endregion
|
|
2566
|
+
//#region src/composables/useMutationObserver/index.ts
|
|
2567
|
+
/**
|
|
2568
|
+
* Composable for observing DOM mutations
|
|
2569
|
+
*
|
|
2570
|
+
* @param target - Element ref to observe
|
|
2571
|
+
* @param callback - Callback fired on mutation
|
|
2572
|
+
* @param options - Observer options
|
|
2573
|
+
* @returns Observer controls
|
|
2574
|
+
*
|
|
2575
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
|
|
2576
|
+
*/
|
|
2577
|
+
function useMutationObserver(target, callback, options = {}) {
|
|
2578
|
+
const { isHydrated } = useHydration();
|
|
2579
|
+
const observer = shallowRef();
|
|
2580
|
+
const isPaused = shallowRef(false);
|
|
2581
|
+
const observerOptions = {
|
|
2582
|
+
childList: options.childList ?? true,
|
|
2583
|
+
attributes: options.attributes ?? false,
|
|
2584
|
+
characterData: options.characterData ?? false,
|
|
2585
|
+
subtree: options.subtree ?? false,
|
|
2586
|
+
attributeOldValue: options.attributeOldValue ?? false,
|
|
2587
|
+
characterDataOldValue: options.characterDataOldValue ?? false,
|
|
2588
|
+
attributeFilter: options.attributeFilter
|
|
2589
|
+
};
|
|
2590
|
+
watch([isHydrated, target], ([hydrated, el]) => {
|
|
2591
|
+
cleanup();
|
|
2592
|
+
if (!hydrated || !SUPPORTS_MUTATION_OBSERVER || !el) return;
|
|
2593
|
+
observer.value = new MutationObserver((mutations) => {
|
|
2594
|
+
const transformedEntries = mutations.map((mutation) => ({
|
|
2595
|
+
type: mutation.type,
|
|
2596
|
+
target: mutation.target,
|
|
2597
|
+
addedNodes: mutation.addedNodes,
|
|
2598
|
+
removedNodes: mutation.removedNodes,
|
|
2599
|
+
previousSibling: mutation.previousSibling,
|
|
2600
|
+
nextSibling: mutation.nextSibling,
|
|
2601
|
+
attributeName: mutation.attributeName,
|
|
2602
|
+
attributeNamespace: mutation.attributeNamespace,
|
|
2603
|
+
oldValue: mutation.oldValue
|
|
2604
|
+
}));
|
|
2605
|
+
callback(transformedEntries);
|
|
2606
|
+
});
|
|
2607
|
+
observer.value.observe(el, observerOptions);
|
|
2608
|
+
if (options.immediate) {
|
|
2609
|
+
const emptyNodeList = {
|
|
2610
|
+
length: 0,
|
|
2611
|
+
item: () => null,
|
|
2612
|
+
forEach: () => {},
|
|
2613
|
+
*[Symbol.iterator]() {}
|
|
2614
|
+
};
|
|
2615
|
+
callback([{
|
|
2616
|
+
type: "childList",
|
|
2617
|
+
target: el,
|
|
2618
|
+
addedNodes: emptyNodeList,
|
|
2619
|
+
removedNodes: emptyNodeList,
|
|
2620
|
+
previousSibling: null,
|
|
2621
|
+
nextSibling: null,
|
|
2622
|
+
attributeName: null,
|
|
2623
|
+
attributeNamespace: null,
|
|
2624
|
+
oldValue: null
|
|
2625
|
+
}]);
|
|
2626
|
+
}
|
|
2627
|
+
}, { immediate: true });
|
|
2628
|
+
function setup() {
|
|
2629
|
+
if (!isHydrated.value || !SUPPORTS_MUTATION_OBSERVER || !target.value || isPaused.value) return;
|
|
2630
|
+
observer.value = new MutationObserver((mutations) => {
|
|
2631
|
+
const transformedEntries = mutations.map((mutation) => ({
|
|
2632
|
+
type: mutation.type,
|
|
2633
|
+
target: mutation.target,
|
|
2634
|
+
addedNodes: mutation.addedNodes,
|
|
2635
|
+
removedNodes: mutation.removedNodes,
|
|
2636
|
+
previousSibling: mutation.previousSibling,
|
|
2637
|
+
nextSibling: mutation.nextSibling,
|
|
2638
|
+
attributeName: mutation.attributeName,
|
|
2639
|
+
attributeNamespace: mutation.attributeNamespace,
|
|
2640
|
+
oldValue: mutation.oldValue
|
|
2641
|
+
}));
|
|
2642
|
+
callback(transformedEntries);
|
|
2643
|
+
});
|
|
2644
|
+
observer.value.observe(target.value, observerOptions);
|
|
2645
|
+
if (options.immediate) {
|
|
2646
|
+
const emptyNodeList = {
|
|
2647
|
+
length: 0,
|
|
2648
|
+
item: () => null,
|
|
2649
|
+
forEach: () => {},
|
|
2650
|
+
*[Symbol.iterator]() {}
|
|
2651
|
+
};
|
|
2652
|
+
const syntheticEntry = {
|
|
2653
|
+
type: "childList",
|
|
2654
|
+
target: target.value,
|
|
2655
|
+
addedNodes: emptyNodeList,
|
|
2656
|
+
removedNodes: emptyNodeList,
|
|
2657
|
+
previousSibling: null,
|
|
2658
|
+
nextSibling: null,
|
|
2659
|
+
attributeName: null,
|
|
2660
|
+
attributeNamespace: null,
|
|
2661
|
+
oldValue: null
|
|
2662
|
+
};
|
|
2663
|
+
callback([syntheticEntry]);
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
function cleanup() {
|
|
2667
|
+
if (observer.value) {
|
|
2668
|
+
observer.value.disconnect();
|
|
2669
|
+
observer.value = void 0;
|
|
2670
|
+
}
|
|
2671
|
+
}
|
|
2672
|
+
function pause() {
|
|
2673
|
+
isPaused.value = true;
|
|
2674
|
+
observer.value?.disconnect();
|
|
2675
|
+
}
|
|
2676
|
+
function resume() {
|
|
2677
|
+
isPaused.value = false;
|
|
2678
|
+
setup();
|
|
2679
|
+
}
|
|
2680
|
+
function stop() {
|
|
2681
|
+
cleanup();
|
|
2682
|
+
}
|
|
2683
|
+
onUnmounted(stop);
|
|
2684
|
+
return {
|
|
2685
|
+
isPaused: readonly(isPaused),
|
|
2686
|
+
pause,
|
|
2687
|
+
resume,
|
|
2688
|
+
stop
|
|
2689
|
+
};
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
//#endregion
|
|
2693
|
+
//#region src/composables/usePermissions/adapters/adapter.ts
|
|
2694
|
+
var PermissionAdapter = class {};
|
|
2695
|
+
|
|
2696
|
+
//#endregion
|
|
2697
|
+
//#region src/composables/usePermissions/adapters/v0.ts
|
|
2698
|
+
var Vuetify0PermissionAdapter = class extends PermissionAdapter {
|
|
2699
|
+
constructor() {
|
|
2700
|
+
super();
|
|
2701
|
+
}
|
|
2702
|
+
can(role, action, subject, context, permissions) {
|
|
2703
|
+
const access = `${role}.${action}.${subject}`;
|
|
2704
|
+
const ticket = permissions.get(access);
|
|
2705
|
+
if (!ticket || !ticket.value) return false;
|
|
2706
|
+
return isFunction(ticket.value) ? ticket.value(context) : ticket.value;
|
|
2707
|
+
}
|
|
2708
|
+
};
|
|
2709
|
+
|
|
2710
|
+
//#endregion
|
|
2711
|
+
//#region src/composables/usePermissions/index.ts
|
|
2712
|
+
/**
|
|
2713
|
+
*
|
|
2714
|
+
* @param namespace The namespace for the permissions context
|
|
2715
|
+
* @param options Configure initial permissions and adapter
|
|
2716
|
+
* @template Z The type of permission ticket
|
|
2717
|
+
* @template E The type of permission context
|
|
2718
|
+
* @returns A context trinity for the permissions context
|
|
2719
|
+
*
|
|
2720
|
+
* @see https://0.vuetifyjs.com/composables/plugins/create-permissions
|
|
2721
|
+
*/
|
|
2722
|
+
function createPermissions(namespace = "v0:permissions", options = {}) {
|
|
2723
|
+
const { adapter = new Vuetify0PermissionAdapter(), permissions = {} } = options;
|
|
2724
|
+
const [usePermissionsContext, _providePermissionsContext] = createContext(namespace);
|
|
2725
|
+
const record = {};
|
|
2726
|
+
for (const role in permissions) {
|
|
2727
|
+
if (!record[role]) record[role] = {};
|
|
2728
|
+
for (const [actions, subjects, condition = true] of permissions[role]) for (const action of toArray(actions)) for (const subject of toArray(subjects)) {
|
|
2729
|
+
if (!record[role][action]) record[role][action] = {};
|
|
2730
|
+
record[role][action][subject] = condition;
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
const tokens = useTokens(record);
|
|
2734
|
+
function can(id, action, subject, context$1 = {}) {
|
|
2735
|
+
return adapter.can(id, action, subject, context$1, tokens);
|
|
2736
|
+
}
|
|
2737
|
+
const context = {
|
|
2738
|
+
...tokens,
|
|
2739
|
+
can
|
|
2740
|
+
};
|
|
2741
|
+
function providePermissionsContext(_context = context, app) {
|
|
2742
|
+
return _providePermissionsContext(_context, app);
|
|
2743
|
+
}
|
|
2744
|
+
return createTrinity(usePermissionsContext, providePermissionsContext, context);
|
|
2745
|
+
}
|
|
2746
|
+
/**
|
|
2747
|
+
* Simple hook to access the permissions context
|
|
2748
|
+
*
|
|
2749
|
+
* @returns The permissions context
|
|
2750
|
+
* @template Z The type of permission ticket
|
|
2751
|
+
*
|
|
2752
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-permissions
|
|
2753
|
+
*/
|
|
2754
|
+
function usePermissions() {
|
|
2755
|
+
return useContext("v0:permissions");
|
|
2756
|
+
}
|
|
2757
|
+
/**
|
|
2758
|
+
* Factory function to create a permissions plugin
|
|
2759
|
+
*
|
|
2760
|
+
* @param options Configuration options for the permissions plugin
|
|
2761
|
+
* @template Z The type of permission ticket
|
|
2762
|
+
* @template E The type of permission context
|
|
2763
|
+
* @returns A Vue plugin object for permissions management
|
|
2764
|
+
*
|
|
2765
|
+
* @see https://0.vuetifyjs.com/composables/plugins/use-permissions
|
|
2766
|
+
*/
|
|
2767
|
+
function createPermissionsPlugin(options = {}) {
|
|
2768
|
+
const [, providePermissionContext, context] = createPermissions("v0:permissions", options);
|
|
2769
|
+
return createPlugin({
|
|
2770
|
+
namespace: "v0:permissions",
|
|
2771
|
+
provide: (app) => {
|
|
2772
|
+
providePermissionContext(context, app);
|
|
2773
|
+
}
|
|
2774
|
+
});
|
|
2775
|
+
}
|
|
2776
|
+
|
|
2777
|
+
//#endregion
|
|
2778
|
+
//#region src/composables/useProxyModel/index.ts
|
|
2779
|
+
/**
|
|
2780
|
+
* Creates a proxy model for two-way binding with a selection context.
|
|
2781
|
+
*
|
|
2782
|
+
* @param registry SelectionContext | GroupContext | SingleContext | StepContext
|
|
2783
|
+
* @template Z The type of items managed by the selection.
|
|
2784
|
+
* @template E The type of the selection context.
|
|
2785
|
+
* @returns The proxy model for two-way binding with the selection context.
|
|
2786
|
+
*/
|
|
2787
|
+
function useProxyModel(registry, initial, options, _transformIn, _transformOut) {
|
|
2788
|
+
const logger = useLogger();
|
|
2789
|
+
const internal = (options?.deep ? ref : shallowRef)(initial ? toArray(initial) : []);
|
|
2790
|
+
const isModelArray = isArray(initial);
|
|
2791
|
+
function transformIn(val) {
|
|
2792
|
+
if (isFunction(_transformIn)) return _transformIn(val);
|
|
2793
|
+
return toArray(val);
|
|
2794
|
+
}
|
|
2795
|
+
function transformOut(val) {
|
|
2796
|
+
if (isFunction(_transformOut)) return _transformOut(val);
|
|
2797
|
+
return isModelArray ? val : val[0];
|
|
2798
|
+
}
|
|
2799
|
+
const model = computed({
|
|
2800
|
+
get() {
|
|
2801
|
+
return transformOut(internal.value);
|
|
2802
|
+
},
|
|
2803
|
+
set(val) {
|
|
2804
|
+
internal.value = transformIn(val);
|
|
2805
|
+
}
|
|
2806
|
+
});
|
|
2807
|
+
const watcher = watch(registry.selectedIds, (val, oldVal) => {
|
|
2808
|
+
if (toRaw(val).symmetricDifference(toRaw(oldVal)).size === 0) return;
|
|
2809
|
+
if (val.size === 0) {
|
|
2810
|
+
model.value = [];
|
|
2811
|
+
return;
|
|
2812
|
+
}
|
|
2813
|
+
model.value = Array.from(registry.selectedValues.value);
|
|
2814
|
+
});
|
|
2815
|
+
watch(model, (val) => {
|
|
2816
|
+
const currentIds = new Set(toValue(registry.selectedIds));
|
|
2817
|
+
const targetIds = /* @__PURE__ */ new Set();
|
|
2818
|
+
for (const value of toArray(val)) {
|
|
2819
|
+
const ids = registry.browse(value);
|
|
2820
|
+
if (isArray(ids)) for (const single of ids) targetIds.add(single);
|
|
2821
|
+
else if (ids) targetIds.add(ids);
|
|
2822
|
+
else logger.warn("Unable to find id for value", value);
|
|
2823
|
+
}
|
|
2824
|
+
watcher.pause();
|
|
2825
|
+
if (isModelArray) {
|
|
2826
|
+
for (const id of currentIds.difference(targetIds)) registry.selectedIds.delete(id);
|
|
2827
|
+
for (const id of targetIds.difference(currentIds)) registry.selectedIds.add(id);
|
|
2828
|
+
} else {
|
|
2829
|
+
const next = targetIds.values().next().value;
|
|
2830
|
+
const last = currentIds.values().next().value;
|
|
2831
|
+
registry.selectedIds.delete(last);
|
|
2832
|
+
registry.selectedIds.add(next);
|
|
2833
|
+
}
|
|
2834
|
+
watcher.resume();
|
|
2835
|
+
});
|
|
2836
|
+
return model;
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
//#endregion
|
|
2840
|
+
//#region src/composables/useResizeObserver/index.ts
|
|
2841
|
+
/**
|
|
2842
|
+
* Composable for observing element resize events
|
|
2843
|
+
*
|
|
2844
|
+
* @param target - Element ref to observe
|
|
2845
|
+
* @param callback - Callback fired on resize
|
|
2846
|
+
* @param options - Observer options
|
|
2847
|
+
* @returns Observer controls
|
|
2848
|
+
*
|
|
2849
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
|
|
2850
|
+
*/
|
|
2851
|
+
function useResizeObserver(target, callback, options = {}) {
|
|
2852
|
+
const { isHydrated } = useHydration();
|
|
2853
|
+
const observer = shallowRef();
|
|
2854
|
+
const isPaused = shallowRef(false);
|
|
2855
|
+
watch([isHydrated, target], ([hydrated, el]) => {
|
|
2856
|
+
cleanup();
|
|
2857
|
+
if (!hydrated || !SUPPORTS_OBSERVER || !el) return;
|
|
2858
|
+
observer.value = new ResizeObserver((entries) => {
|
|
2859
|
+
const transformedEntries = entries.map((entry) => ({
|
|
2860
|
+
contentRect: {
|
|
2861
|
+
width: entry.contentRect.width,
|
|
2862
|
+
height: entry.contentRect.height,
|
|
2863
|
+
top: entry.contentRect.top,
|
|
2864
|
+
left: entry.contentRect.left
|
|
2865
|
+
},
|
|
2866
|
+
target: entry.target
|
|
2867
|
+
}));
|
|
2868
|
+
callback(transformedEntries);
|
|
2869
|
+
});
|
|
2870
|
+
observer.value.observe(el, { box: options.box || "content-box" });
|
|
2871
|
+
if (options.immediate) {
|
|
2872
|
+
const rect = el.getBoundingClientRect();
|
|
2873
|
+
callback([{
|
|
2874
|
+
contentRect: {
|
|
2875
|
+
width: rect.width,
|
|
2876
|
+
height: rect.height,
|
|
2877
|
+
top: rect.top,
|
|
2878
|
+
left: rect.left
|
|
2879
|
+
},
|
|
2880
|
+
target: el
|
|
2881
|
+
}]);
|
|
2882
|
+
}
|
|
2883
|
+
});
|
|
2884
|
+
function setup() {
|
|
2885
|
+
if (!isHydrated.value || !SUPPORTS_OBSERVER || !target.value || isPaused.value) return;
|
|
2886
|
+
observer.value = new ResizeObserver((entries) => {
|
|
2887
|
+
const transformedEntries = entries.map((entry) => ({
|
|
2888
|
+
contentRect: {
|
|
2889
|
+
width: entry.contentRect.width,
|
|
2890
|
+
height: entry.contentRect.height,
|
|
2891
|
+
top: entry.contentRect.top,
|
|
2892
|
+
left: entry.contentRect.left
|
|
2893
|
+
},
|
|
2894
|
+
target: entry.target
|
|
2895
|
+
}));
|
|
2896
|
+
callback(transformedEntries);
|
|
2897
|
+
});
|
|
2898
|
+
observer.value.observe(target.value, { box: options.box || "content-box" });
|
|
2899
|
+
if (options.immediate) {
|
|
2900
|
+
const rect = target.value.getBoundingClientRect();
|
|
2901
|
+
callback([{
|
|
2902
|
+
contentRect: {
|
|
2903
|
+
width: rect.width,
|
|
2904
|
+
height: rect.height,
|
|
2905
|
+
top: rect.top,
|
|
2906
|
+
left: rect.left
|
|
2907
|
+
},
|
|
2908
|
+
target: target.value
|
|
2909
|
+
}]);
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
function cleanup() {
|
|
2913
|
+
if (observer.value) {
|
|
2914
|
+
observer.value.disconnect();
|
|
2915
|
+
observer.value = void 0;
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
function pause() {
|
|
2919
|
+
isPaused.value = true;
|
|
2920
|
+
observer.value?.disconnect();
|
|
2921
|
+
}
|
|
2922
|
+
function resume() {
|
|
2923
|
+
isPaused.value = false;
|
|
2924
|
+
setup();
|
|
2925
|
+
}
|
|
2926
|
+
function stop() {
|
|
2927
|
+
cleanup();
|
|
2928
|
+
}
|
|
2929
|
+
onUnmounted(stop);
|
|
2930
|
+
return {
|
|
2931
|
+
isPaused: readonly(isPaused),
|
|
2932
|
+
pause,
|
|
2933
|
+
resume,
|
|
2934
|
+
stop
|
|
2935
|
+
};
|
|
2936
|
+
}
|
|
2937
|
+
/**
|
|
2938
|
+
* Convenience composable for tracking element dimensions
|
|
2939
|
+
*
|
|
2940
|
+
* @param target - Element ref to observe
|
|
2941
|
+
* @returns Reactive width and height
|
|
2942
|
+
*/
|
|
2943
|
+
function useElementSize(target) {
|
|
2944
|
+
const width = shallowRef(0);
|
|
2945
|
+
const height = shallowRef(0);
|
|
2946
|
+
useResizeObserver(target, (entries) => {
|
|
2947
|
+
const entry = entries[0];
|
|
2948
|
+
if (entry) {
|
|
2949
|
+
width.value = entry.contentRect.width;
|
|
2950
|
+
height.value = entry.contentRect.height;
|
|
2951
|
+
}
|
|
2952
|
+
}, { immediate: true });
|
|
2953
|
+
return {
|
|
2954
|
+
width,
|
|
2955
|
+
height
|
|
2956
|
+
};
|
|
2957
|
+
}
|
|
2958
|
+
|
|
2959
|
+
//#endregion
|
|
2960
|
+
//#region src/composables/useStep/index.ts
|
|
2961
|
+
/**
|
|
2962
|
+
* Creates a step selection context for managing collections where users can navigate through items sequentially.
|
|
2963
|
+
* This function extends the single selection functionality with stepping navigation.
|
|
2964
|
+
*
|
|
2965
|
+
* @param options Optional configuration for step behavior.
|
|
2966
|
+
* @template Z The type of items managed by the step selection.
|
|
2967
|
+
* @template E The type of the step selection context.
|
|
2968
|
+
* @returns The step selection context object.
|
|
2969
|
+
*/
|
|
2970
|
+
function useStep(options) {
|
|
2971
|
+
const registry = useSingle(options);
|
|
2972
|
+
function first() {
|
|
2973
|
+
if (registry.size === 0) return;
|
|
2974
|
+
registry.selectedIds.clear();
|
|
2975
|
+
registry.select(registry.lookup(0));
|
|
2976
|
+
}
|
|
2977
|
+
function last() {
|
|
2978
|
+
const size = registry.size;
|
|
2979
|
+
if (size === 0) return;
|
|
2980
|
+
registry.selectedIds.clear();
|
|
2981
|
+
registry.select(registry.lookup(size - 1));
|
|
2982
|
+
}
|
|
2983
|
+
function next() {
|
|
2984
|
+
step(1);
|
|
2985
|
+
}
|
|
2986
|
+
function prev() {
|
|
2987
|
+
step(-1);
|
|
2988
|
+
}
|
|
2989
|
+
function wrapped(length, index) {
|
|
2990
|
+
return (index + length) % length;
|
|
2991
|
+
}
|
|
2992
|
+
function step(count = 1) {
|
|
2993
|
+
const length = registry.size;
|
|
2994
|
+
if (!length) return;
|
|
2995
|
+
const direction = Math.sign(count || 1);
|
|
2996
|
+
let hops = 0;
|
|
2997
|
+
let index = wrapped(length, registry.selectedIndex.value + count);
|
|
2998
|
+
let id = registry.lookup(index);
|
|
2999
|
+
while (id !== void 0 && registry.get(id)?.disabled && hops < length) {
|
|
3000
|
+
index = wrapped(length, index + direction);
|
|
3001
|
+
id = registry.lookup(index);
|
|
3002
|
+
hops++;
|
|
3003
|
+
}
|
|
3004
|
+
if (id === void 0 || hops === length) return;
|
|
3005
|
+
registry.selectedIds.clear();
|
|
3006
|
+
registry.select(id);
|
|
3007
|
+
}
|
|
3008
|
+
return {
|
|
3009
|
+
...registry,
|
|
3010
|
+
first,
|
|
3011
|
+
last,
|
|
3012
|
+
next,
|
|
3013
|
+
prev,
|
|
3014
|
+
step
|
|
3015
|
+
};
|
|
3016
|
+
}
|
|
3017
|
+
/**
|
|
3018
|
+
* Creates a step selection registry context with full injection/provision control.
|
|
3019
|
+
* Returns the complete trinity for advanced usage scenarios.
|
|
3020
|
+
*
|
|
3021
|
+
* @param namespace The namespace for the step selection registry context
|
|
3022
|
+
* @param options Optional configuration for step selection behavior.
|
|
3023
|
+
* @template Z The structure of the registry step selection items.
|
|
3024
|
+
* @template E The available methods for the step's context.
|
|
3025
|
+
* @returns A tuple containing the inject function, provide function, and the step selection context.
|
|
3026
|
+
*/
|
|
3027
|
+
function createStepContext(namespace, options) {
|
|
3028
|
+
const [useStepContext, _provideStepContext] = createContext(namespace);
|
|
3029
|
+
const context = useStep(options);
|
|
3030
|
+
function provideStepContext(_context = context, app) {
|
|
3031
|
+
return _provideStepContext(_context, app);
|
|
3032
|
+
}
|
|
3033
|
+
return createTrinity(useStepContext, provideStepContext, context);
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
//#endregion
|
|
3037
|
+
//#region src/composables/useStorage/adapters/memory.ts
|
|
3038
|
+
/**
|
|
3039
|
+
* In-memory storage adapter that implements the StorageAdapter interface.
|
|
3040
|
+
* This adapter provides temporary storage that persists only for the current
|
|
3041
|
+
* session and is useful for testing or when persistent storage is not available.
|
|
3042
|
+
*/
|
|
3043
|
+
var MemoryAdapter = class {
|
|
3044
|
+
store = /* @__PURE__ */ new Map();
|
|
3045
|
+
get length() {
|
|
3046
|
+
return this.store.size;
|
|
3047
|
+
}
|
|
3048
|
+
getItem(key) {
|
|
3049
|
+
return this.store.get(key) ?? null;
|
|
3050
|
+
}
|
|
3051
|
+
setItem(key, value) {
|
|
3052
|
+
this.store.set(key, value);
|
|
3053
|
+
}
|
|
3054
|
+
removeItem(key) {
|
|
3055
|
+
this.store.delete(key);
|
|
3056
|
+
}
|
|
3057
|
+
key(index) {
|
|
3058
|
+
return String(Array.from(this.store.keys())[index] ?? "");
|
|
3059
|
+
}
|
|
3060
|
+
};
|
|
3061
|
+
|
|
3062
|
+
//#endregion
|
|
3063
|
+
//#region src/composables/useStorage/index.ts
|
|
3064
|
+
const [useStorageContext, provideStorageContext] = createContext("v0:storage");
|
|
3065
|
+
/**
|
|
3066
|
+
* Creates a reactive storage system with automatic persistence and cross-adapter support.
|
|
3067
|
+
* This function provides a consistent interface for storing and retrieving reactive values
|
|
3068
|
+
* that automatically sync with the underlying storage adapter (localStorage, memory, etc.).
|
|
3069
|
+
*
|
|
3070
|
+
* @param options Optional configuration for storage adapter, prefix, and serialization.
|
|
3071
|
+
* @template E The type of the storage context.
|
|
3072
|
+
* @returns A storage context object with get, set, remove, and clear methods.
|
|
3073
|
+
*/
|
|
3074
|
+
function createStorage(options = {}) {
|
|
3075
|
+
const { adapter = IN_BROWSER ? window.localStorage : new MemoryAdapter(), prefix = "v0:", serializer = {
|
|
3076
|
+
read: JSON.parse,
|
|
3077
|
+
write: JSON.stringify
|
|
3078
|
+
} } = options;
|
|
3079
|
+
const cache = /* @__PURE__ */ new Map();
|
|
3080
|
+
function get(key, defaultValue) {
|
|
3081
|
+
const prefixedKey = `${prefix}${key}`;
|
|
3082
|
+
if (cache.has(prefixedKey)) return cache.get(prefixedKey);
|
|
3083
|
+
const storedValue = adapter?.getItem(prefixedKey);
|
|
3084
|
+
let initialValue = defaultValue;
|
|
3085
|
+
if (storedValue) try {
|
|
3086
|
+
initialValue = serializer.read(storedValue);
|
|
3087
|
+
} catch (error) {
|
|
3088
|
+
console.error(`[v0:storage] Failed to parse stored value for key "${prefixedKey}":`, error);
|
|
3089
|
+
}
|
|
3090
|
+
const valueRef = ref(initialValue);
|
|
3091
|
+
watch(valueRef, (newValue) => {
|
|
3092
|
+
if (newValue === void 0 || newValue === null) adapter?.removeItem(prefixedKey);
|
|
3093
|
+
else adapter?.setItem(prefixedKey, serializer.write(newValue));
|
|
3094
|
+
}, { deep: true });
|
|
3095
|
+
cache.set(prefixedKey, valueRef);
|
|
3096
|
+
return valueRef;
|
|
3097
|
+
}
|
|
3098
|
+
function set(key, value) {
|
|
3099
|
+
const valueRef = get(key);
|
|
3100
|
+
valueRef.value = value;
|
|
3101
|
+
}
|
|
3102
|
+
function remove(key) {
|
|
3103
|
+
const prefixedKey = `${prefix}${key}`;
|
|
3104
|
+
adapter?.removeItem(prefixedKey);
|
|
3105
|
+
cache.delete(prefixedKey);
|
|
3106
|
+
}
|
|
3107
|
+
function clear() {
|
|
3108
|
+
for (const key of cache.keys()) adapter?.removeItem(key);
|
|
3109
|
+
cache.clear();
|
|
3110
|
+
}
|
|
3111
|
+
return {
|
|
3112
|
+
get,
|
|
3113
|
+
set,
|
|
3114
|
+
remove,
|
|
3115
|
+
clear
|
|
3116
|
+
};
|
|
3117
|
+
}
|
|
3118
|
+
/**
|
|
3119
|
+
* Simple hook to access the storage context.
|
|
3120
|
+
*
|
|
3121
|
+
* @returns The storage context containing reactive storage methods.
|
|
3122
|
+
*/
|
|
3123
|
+
function useStorage() {
|
|
3124
|
+
return useStorageContext();
|
|
3125
|
+
}
|
|
3126
|
+
/**
|
|
3127
|
+
* Creates a Vue plugin for reactive storage capabilities with automatic persistence.
|
|
3128
|
+
* Provides app-wide access to reactive storage that syncs with the configured adapter.
|
|
3129
|
+
*
|
|
3130
|
+
* @param options Optional configuration for the storage system.
|
|
3131
|
+
* @returns A Vue plugin object with install method.
|
|
3132
|
+
*/
|
|
3133
|
+
function createStoragePlugin(options = {}) {
|
|
3134
|
+
const context = createStorage(options);
|
|
3135
|
+
return createPlugin({
|
|
3136
|
+
namespace: "v0:storage",
|
|
3137
|
+
provide: (app) => {
|
|
3138
|
+
provideStorageContext(context, app);
|
|
3139
|
+
}
|
|
3140
|
+
});
|
|
3141
|
+
}
|
|
3142
|
+
|
|
3143
|
+
//#endregion
|
|
3144
|
+
//#region src/composables/useTimeline/index.ts
|
|
3145
|
+
/**
|
|
3146
|
+
* Creates a registry with timeline capabilities (undo/redo)
|
|
3147
|
+
*
|
|
3148
|
+
* @param _options Optional configuration for timeline
|
|
3149
|
+
* @template Z The type of ticket to be stored in the timeline
|
|
3150
|
+
* @template E The type of the timeline context
|
|
3151
|
+
* @returns The timeline context object
|
|
3152
|
+
*
|
|
3153
|
+
* @see https://0.vuetifyjs.com/composables/registration/use-timeline
|
|
3154
|
+
*/
|
|
3155
|
+
function useTimeline(_options = {}) {
|
|
3156
|
+
const { size = 10,...options } = _options;
|
|
3157
|
+
const registry = useRegistry(options);
|
|
3158
|
+
const undoTimeline = [];
|
|
3159
|
+
const redoTimeline = [];
|
|
3160
|
+
function register(item) {
|
|
3161
|
+
if (registry.size < size) return registry.register({ ...item });
|
|
3162
|
+
const id = registry.lookup(0);
|
|
3163
|
+
const removing = registry.get(id);
|
|
3164
|
+
if (redoTimeline.length === size) redoTimeline.shift();
|
|
3165
|
+
redoTimeline.push(removing);
|
|
3166
|
+
registry.unregister(id);
|
|
3167
|
+
const ticket = registry.register({ ...item });
|
|
3168
|
+
registry.reindex();
|
|
3169
|
+
return ticket;
|
|
3170
|
+
}
|
|
3171
|
+
function redo() {
|
|
3172
|
+
if (undoTimeline.length === 0) return;
|
|
3173
|
+
registry.register(undoTimeline.pop());
|
|
3174
|
+
registry.reindex();
|
|
3175
|
+
}
|
|
3176
|
+
function undo() {
|
|
3177
|
+
const id = registry.lookup(registry.size - 1);
|
|
3178
|
+
if (!id) return;
|
|
3179
|
+
undoTimeline.push(registry.get(id));
|
|
3180
|
+
registry.unregister(id);
|
|
3181
|
+
restore();
|
|
3182
|
+
}
|
|
3183
|
+
function restore() {
|
|
3184
|
+
const value = redoTimeline.pop();
|
|
3185
|
+
const restored = value ? [value, ...registry.values()] : [...registry.values()];
|
|
3186
|
+
registry.clear();
|
|
3187
|
+
registry.onboard(restored);
|
|
3188
|
+
registry.reindex();
|
|
3189
|
+
}
|
|
3190
|
+
return {
|
|
3191
|
+
...registry,
|
|
3192
|
+
register,
|
|
3193
|
+
undo,
|
|
3194
|
+
redo
|
|
3195
|
+
};
|
|
3196
|
+
}
|
|
3197
|
+
|
|
3198
|
+
//#endregion
|
|
3199
|
+
export { Atom_default as Atom, Breakpoints, COMMON_ELEMENTS, ConsolaLoggerAdapter, Context, Hydration_default as Hydration, HydrationRoot_default as HydrationRoot, IN_BROWSER, PinoLoggerAdapter, Popover, SELF_CLOSING_TAGS, SUPPORTS_INTERSECTION_OBSERVER, SUPPORTS_MATCH_MEDIA, SUPPORTS_MUTATION_OBSERVER, SUPPORTS_OBSERVER, SUPPORTS_TOUCH, Theme, Vuetify0LoggerAdapter, __LOGGER_ENABLED__, createBreakpoints, createBreakpointsPlugin, createContext, createFeatures, createFeaturesPlugin, createGroupContext, createHydration, createHydrationPlugin, createLocale, createLocalePlugin, createLogger, createLoggerPlugin, createPermissions, createPermissionsPlugin, createPlugin, createRegistryContext, createSelectionContext, createSingleContext, createStepContext, createStorage, createStoragePlugin, createTheme, createThemePlugin, createTokensContext, createTrinity, genId, isArray, isBoolean, isFunction, isNullOrUndefined, isNumber, isObject, isPrimitive, isSelfClosingTag, isString, mergeDeep, provideBreakpointsContext, provideContext, provideHydrationContext, providePopoverContext, provideStorageContext, run, toArray, toReactive, useBreakpoints, useBreakpointsContext, useContext, useDocumentEventListener, useElementIntersection, useElementSize, useEventListener, useFeatures, useFilter, useForm, useGroup, useHydration, useHydrationContext, useIntersectionObserver, useKeydown, useLocale, useLogger, useMutationObserver, usePermissions, usePopoverContext, useProxyModel, useRegistry, useResizeObserver, useSelection, useSingle, useStep, useStorage, useStorageContext, useTheme, useTimeline, useTokens, useWindowEventListener, version };
|