@vuetify/v0 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/browser/index.js +1705 -458
  2. package/dist/components/index.d.mts +2 -2
  3. package/dist/components/index.mjs +19 -19
  4. package/dist/{components-CACff-Lt.mjs → components-BbxKYAXs.mjs} +1203 -312
  5. package/dist/composables/index.d.mts +3 -3
  6. package/dist/composables/index.mjs +18 -18
  7. package/dist/constants/index.mjs +1 -1
  8. package/dist/{createDataTable-CLI4TALE.mjs → createDataTable-DZouEhvH.mjs} +2 -2
  9. package/dist/{createGroup-Cf6lK9BR.mjs → createGroup-BpJFi41X.mjs} +1 -1
  10. package/dist/{createSelection-DvOR2tKk.mjs → createSelection-8MX0OHXR.mjs} +1 -1
  11. package/dist/{createSingle-Bbcwcq4R.mjs → createSingle-CbuOBb-E.mjs} +1 -1
  12. package/dist/{createTokens-CMRBDlzN.mjs → createTokens-CXlT0Vc6.mjs} +3 -2
  13. package/dist/data-table/adapters/client/index.mjs +1 -1
  14. package/dist/data-table/adapters/index.mjs +1 -1
  15. package/dist/data-table/adapters/server/index.mjs +1 -1
  16. package/dist/data-table/adapters/virtual/index.mjs +1 -1
  17. package/dist/data-table/index.mjs +10 -10
  18. package/dist/date/index.mjs +1 -1
  19. package/dist/features/adapters/posthog/index.mjs +2 -2
  20. package/dist/features/index.d.mts +1 -1
  21. package/dist/features/index.mjs +8 -8
  22. package/dist/{globals-BqRH_jdr.mjs → globals-ClSU6mqC.mjs} +1 -1
  23. package/dist/{index-BE848tZ2.d.mts → index-63-0oJS8.d.mts} +155 -53
  24. package/dist/{index-CKbxWC4t.d.mts → index-B5NU2uB7.d.mts} +2362 -1314
  25. package/dist/{index-8sflFIN8.d.mts → index-CxW4itj1.d.mts} +2 -0
  26. package/dist/index.d.mts +4 -4
  27. package/dist/index.mjs +19 -19
  28. package/dist/json/attributes.json +252 -0
  29. package/dist/json/importMap.json +60 -0
  30. package/dist/json/tags.json +128 -0
  31. package/dist/json/web-types.json +1023 -228
  32. package/dist/locale/adapters/index.mjs +2 -2
  33. package/dist/locale/adapters/v0/index.mjs +2 -2
  34. package/dist/locale/index.d.mts +1 -1
  35. package/dist/locale/index.mjs +8 -8
  36. package/dist/logger/adapters/index.mjs +2 -2
  37. package/dist/logger/adapters/pino/index.mjs +1 -1
  38. package/dist/logger/adapters/v0/index.mjs +2 -2
  39. package/dist/logger/index.d.mts +1 -1
  40. package/dist/logger/index.mjs +3 -3
  41. package/dist/palettes/ant/index.d.mts +1 -1
  42. package/dist/palettes/index.d.mts +2 -2
  43. package/dist/palettes/material/index.d.mts +1 -1
  44. package/dist/palettes/md1/index.d.mts +1 -1
  45. package/dist/palettes/md2/index.d.mts +1 -1
  46. package/dist/palettes/radix/index.d.mts +1 -1
  47. package/dist/palettes/tailwind/index.d.mts +1 -1
  48. package/dist/permissions/adapters/index.d.mts +2 -2
  49. package/dist/permissions/adapters/index.mjs +1 -1
  50. package/dist/permissions/adapters/v0/index.d.mts +1 -1
  51. package/dist/permissions/adapters/v0/index.mjs +1 -1
  52. package/dist/permissions/index.d.mts +1 -1
  53. package/dist/permissions/index.mjs +5 -5
  54. package/dist/{posthog-DbPqmaAp.mjs → posthog-BE7-t7cV.mjs} +1 -1
  55. package/dist/rules/index.d.mts +1 -1
  56. package/dist/rules/index.mjs +9 -9
  57. package/dist/storage/index.d.mts +1 -1
  58. package/dist/storage/index.mjs +17 -17
  59. package/dist/theme/adapters/index.d.mts +1 -1
  60. package/dist/theme/adapters/index.mjs +2 -2
  61. package/dist/theme/adapters/v0/index.d.mts +1 -1
  62. package/dist/theme/adapters/v0/index.mjs +2 -2
  63. package/dist/theme/index.d.mts +1 -1
  64. package/dist/theme/index.mjs +8 -8
  65. package/dist/{useClickOutside-YOGwKo7v.mjs → useClickOutside-W0Sur1rC.mjs} +477 -125
  66. package/dist/{useFeatures-BGDgUrdr.mjs → useFeatures-CUicSI-E.mjs} +3 -3
  67. package/dist/{useLocale-C8I_fNAS.mjs → useLocale-cQlPxbpV.mjs} +11 -7
  68. package/dist/{useLogger-B70T4SgK.mjs → useLogger-DY1Hbcy1.mjs} +2 -2
  69. package/dist/{usePermissions-afVt2qR7.mjs → usePermissions-BSW59R4q.mjs} +2 -2
  70. package/dist/{useRules-7C92Xzyt.mjs → useRules-BbA6_gvs.mjs} +3 -3
  71. package/dist/{useTheme-jp2wL2FJ.mjs → useTheme-Bdx2Lj5c.mjs} +4 -4
  72. package/dist/utilities/index.mjs +1 -1
  73. package/dist/{v0-CGlkn5u7.mjs → v0-2G2476h-.mjs} +1 -1
  74. package/dist/{v0-V-cQsuZD.mjs → v0-BFseIsBi.mjs} +1 -1
  75. package/dist/{v0-1bfmyZ5_.d.mts → v0-BZINNGoC.d.mts} +1 -1
  76. package/dist/{v0-CHvU3jQE.mjs → v0-CHBrvw49.mjs} +1 -1
  77. package/package.json +2 -1
@@ -1,16 +1,16 @@
1
- import { a as SUPPORTS_OBSERVER, i as SUPPORTS_MUTATION_OBSERVER, n as SUPPORTS_INTERSECTION_OBSERVER, r as SUPPORTS_MATCH_MEDIA, t as IN_BROWSER } from "./globals-BqRH_jdr.mjs";
1
+ import { a as SUPPORTS_OBSERVER, i as SUPPORTS_MUTATION_OBSERVER, n as SUPPORTS_INTERSECTION_OBSERVER, r as SUPPORTS_MATCH_MEDIA, t as IN_BROWSER } from "./globals-ClSU6mqC.mjs";
2
2
  import { clamp, instanceExists, isElement, isFunction, isNull, isNullOrUndefined, isNumber, isObject, isString, isUndefined, mergeDeep, useId as useId$1 } from "./utilities/index.mjs";
3
3
  import { i as useContext, n as createContext, t as createTrinity } from "./createTrinity-C_c8eedz.mjs";
4
- import { a as createPlugin, i as useLogger, o as createPluginContext } from "./useLogger-B70T4SgK.mjs";
5
- import { i as createRegistry } from "./createTokens-CMRBDlzN.mjs";
6
- import { i as createModel, t as createSelection } from "./createSelection-DvOR2tKk.mjs";
7
- import { t as createSingle } from "./createSingle-Bbcwcq4R.mjs";
8
- import { t as createGroup } from "./createGroup-Cf6lK9BR.mjs";
4
+ import { a as createPlugin, i as useLogger, o as createPluginContext } from "./useLogger-DY1Hbcy1.mjs";
5
+ import { i as createRegistry } from "./createTokens-CXlT0Vc6.mjs";
6
+ import { i as createModel, t as createSelection } from "./createSelection-8MX0OHXR.mjs";
7
+ import { t as createSingle } from "./createSingle-CbuOBb-E.mjs";
8
+ import { t as createGroup } from "./createGroup-BpJFi41X.mjs";
9
9
  import { t as toArray } from "./toArray-VdROPpy-.mjs";
10
- import { a as useLocale } from "./useLocale-C8I_fNAS.mjs";
11
- import { a as useRules, o as isStandardSchema, s as toRule } from "./useRules-7C92Xzyt.mjs";
10
+ import { a as useLocale } from "./useLocale-cQlPxbpV.mjs";
11
+ import { a as useRules, o as isStandardSchema } from "./useRules-BbA6_gvs.mjs";
12
12
  import { t as MemoryAdapter } from "./memory-XCMtkld1.mjs";
13
- import { computed, effectScope, isRef, nextTick, onScopeDispose, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRef, toValue, unref, watch, watchEffect } from "vue";
13
+ import { computed, effectScope, isRef, nextTick, onMounted, onScopeDispose, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRef, toValue, unref, watch, watchEffect } from "vue";
14
14
  //#region src/composables/createBreadcrumbs/index.ts
15
15
  /**
16
16
  * @module createBreadcrumbs
@@ -1047,6 +1047,7 @@ function createBreakpoints(_options = {}) {
1047
1047
  }
1048
1048
  return {
1049
1049
  breakpoints,
1050
+ mobileBreakpoint,
1050
1051
  name: readonly(name),
1051
1052
  width: readonly(width),
1052
1053
  height: readonly(height),
@@ -1073,8 +1074,10 @@ function createBreakpoints(_options = {}) {
1073
1074
  }
1074
1075
  function createBreakpointsFallback(options = {}) {
1075
1076
  if (options.ssr) return createBreakpoints(options);
1077
+ const defaults = createDefaultBreakpoints();
1076
1078
  return {
1077
- breakpoints: createDefaultBreakpoints().breakpoints,
1079
+ breakpoints: defaults.breakpoints,
1080
+ mobileBreakpoint: defaults.mobileBreakpoint,
1078
1081
  name: readonly(shallowRef("xs")),
1079
1082
  width: readonly(shallowRef(0)),
1080
1083
  height: readonly(shallowRef(0)),
@@ -1362,14 +1365,14 @@ function useDate(namespace = "v0:date") {
1362
1365
  * @example
1363
1366
  * ```ts
1364
1367
  * import { createForm, createValidation } from '@vuetify/v0'
1368
+ * import { shallowRef } from 'vue'
1365
1369
  *
1366
1370
  * const form = createForm()
1367
1371
  *
1368
- * // Validations register themselves — form is just the coordinator
1369
- * const validation = createValidation()
1370
- * const email = validation.register({
1371
- * id: 'email',
1372
- * value: '',
1372
+ * // Each validation is one input — form is just the coordinator
1373
+ * const email = shallowRef('')
1374
+ * const validation = createValidation({
1375
+ * value: email,
1373
1376
  * rules: ['required', 'email'],
1374
1377
  * })
1375
1378
  *
@@ -1379,12 +1382,12 @@ function useDate(namespace = "v0:date") {
1379
1382
  * form.reset()
1380
1383
  * ```
1381
1384
  */
1382
- function createForm(options) {
1383
- const registry = createRegistry(options);
1384
- const disabled = shallowRef(false);
1385
- const readonly = shallowRef(false);
1386
- if (!/* @__PURE__ */ isNullOrUndefined(options?.disabled)) disabled.value = toValue(options.disabled) ?? false;
1387
- if (!/* @__PURE__ */ isNullOrUndefined(options?.readonly)) readonly.value = toValue(options.readonly) ?? false;
1385
+ function createForm(options = {}) {
1386
+ const { disabled = false, readonly = false, ..._options } = options;
1387
+ const registry = createRegistry({
1388
+ ..._options,
1389
+ reactive: true
1390
+ });
1388
1391
  const isValidating = computed(() => {
1389
1392
  for (const ticket of registry.values()) if (ticket.value.isValidating.value) return true;
1390
1393
  return false;
@@ -1404,14 +1407,14 @@ function createForm(options) {
1404
1407
  return registry.register(registration);
1405
1408
  }
1406
1409
  function reset() {
1407
- for (const ticket of registry.values()) for (const field of ticket.value.values()) field.reset();
1410
+ for (const ticket of registry.values()) ticket.value.reset();
1408
1411
  }
1409
1412
  async function submit(id) {
1410
1413
  const ids = id ? toArray(id) : [...registry.keys()];
1411
- return (await Promise.all(ids.map(async (id) => {
1412
- const ticket = registry.get(id);
1414
+ return (await Promise.all(ids.map(async (key) => {
1415
+ const ticket = registry.get(key);
1413
1416
  if (!ticket) return true;
1414
- return (await Promise.all([...ticket.value.values()].map((field) => field.validate()))).every(Boolean);
1417
+ return ticket.value.validate();
1415
1418
  }))).every(Boolean);
1416
1419
  }
1417
1420
  return {
@@ -2932,6 +2935,83 @@ function useNested(namespace = "v0:nested") {
2932
2935
  return useContext(namespace);
2933
2936
  }
2934
2937
  //#endregion
2938
+ //#region src/composables/usePopover/index.ts
2939
+ /**
2940
+ * @module usePopover
2941
+ *
2942
+ * @remarks
2943
+ * Composable for native popover API behavior with CSS anchor positioning.
2944
+ * Manages open/close state, anchor styles, content attributes, and
2945
+ * bidirectional sync between reactive state and native popover events.
2946
+ *
2947
+ * Key features:
2948
+ * - Native popover API (showPopover/hidePopover)
2949
+ * - CSS anchor positioning (position-area, position-try-fallbacks)
2950
+ * - Toggle event sync for native state changes
2951
+ * - SSR-safe (no DOM ops outside browser)
2952
+ * - Optional external isOpen ref for v-model integration
2953
+ *
2954
+ * Perfect for building select, combobox, tooltip, and menu components
2955
+ * without wrapping the Popover compound component.
2956
+ */
2957
+ function usePopover(options = {}) {
2958
+ const { id: _id, positionArea = "bottom", positionTry = "most-width bottom" } = options;
2959
+ const id = _id ?? /* @__PURE__ */ useId$1();
2960
+ const isOpen = options.isOpen ?? shallowRef(false);
2961
+ function open() {
2962
+ isOpen.value = true;
2963
+ }
2964
+ function close() {
2965
+ isOpen.value = false;
2966
+ }
2967
+ function toggle() {
2968
+ isOpen.value = !isOpen.value;
2969
+ }
2970
+ const anchorStyles = toRef(() => ({ anchorName: `--${id}` }));
2971
+ const contentAttrs = toRef(() => ({
2972
+ id,
2973
+ popover: ""
2974
+ }));
2975
+ const contentStyles = toRef(() => ({
2976
+ "position": "fixed",
2977
+ "margin": "unset",
2978
+ "inset-area": positionArea,
2979
+ "position-area": positionArea,
2980
+ "position-anchor": `--${id}`,
2981
+ "position-try-fallbacks": positionTry
2982
+ }));
2983
+ /* v8 ignore start -- browser popover API */
2984
+ function attach(el) {
2985
+ onMounted(() => {
2986
+ const element = toValue(el);
2987
+ if (isOpen.value) element?.showPopover();
2988
+ });
2989
+ watch(isOpen, (value) => {
2990
+ const element = toValue(el);
2991
+ if (!element?.isConnected) return;
2992
+ if (value === element.matches?.(":popover-open")) return;
2993
+ if (value) element.showPopover?.();
2994
+ else element.hidePopover?.();
2995
+ });
2996
+ useEventListener(el, "toggle", (e) => {
2997
+ if (!toValue(el)?.isConnected) return;
2998
+ isOpen.value = e.newState === "open";
2999
+ });
3000
+ }
3001
+ /* v8 ignore stop */
3002
+ return {
3003
+ isOpen,
3004
+ id,
3005
+ open,
3006
+ close,
3007
+ toggle,
3008
+ anchorStyles,
3009
+ contentAttrs,
3010
+ contentStyles,
3011
+ attach
3012
+ };
3013
+ }
3014
+ //#endregion
2935
3015
  //#region src/composables/createQueue/index.ts
2936
3016
  /**
2937
3017
  * @module createQueue
@@ -3125,6 +3205,236 @@ function useQueue(namespace = "v0:queue") {
3125
3205
  return useContext(namespace);
3126
3206
  }
3127
3207
  //#endregion
3208
+ //#region src/composables/createFocusTraversal/index.ts
3209
+ /**
3210
+ * @module createFocusTraversal
3211
+ *
3212
+ * @remarks
3213
+ * Internal factory for keyboard-driven traversal of ordered item lists.
3214
+ * Encapsulates stride-based navigation, disabled-item skipping, circular/bounded
3215
+ * movement, grid row scoping, and key-to-action mapping shared by
3216
+ * useRovingFocus and useVirtualFocus.
3217
+ *
3218
+ * Not exported from the package barrel — consumed only by sibling composables.
3219
+ */
3220
+ function mod(length, index) {
3221
+ return (index % length + length) % length;
3222
+ }
3223
+ function isRtl(e) {
3224
+ if (!IN_BROWSER) return false;
3225
+ const el = e.currentTarget;
3226
+ return el ? getComputedStyle(el).direction === "rtl" : false;
3227
+ }
3228
+ function createFocusTraversal(items, activate, options = {}) {
3229
+ const { orientation = "vertical", circular = false, columns: _columns } = options;
3230
+ const activeId = shallowRef();
3231
+ function enabled() {
3232
+ return items().filter((item) => !toValue(item.disabled));
3233
+ }
3234
+ function indexOf(id) {
3235
+ return items().findIndex((item) => item.id === id);
3236
+ }
3237
+ function go(id) {
3238
+ activeId.value = id;
3239
+ activate(id);
3240
+ }
3241
+ function step(stride) {
3242
+ const all = items();
3243
+ const length = all.length;
3244
+ if (!length) return;
3245
+ const current = /* @__PURE__ */ isUndefined(activeId.value) ? -1 : indexOf(activeId.value);
3246
+ const direction = stride > 0 ? 1 : -1;
3247
+ const absStride = Math.abs(stride);
3248
+ let index = current + stride;
3249
+ const maxHops = Math.ceil(length / absStride);
3250
+ let hops = 0;
3251
+ if (circular) index = mod(length, index);
3252
+ else if (index < 0 || index >= length) return;
3253
+ while (hops < maxHops) {
3254
+ const item = all[index];
3255
+ if (item && !toValue(item.disabled)) {
3256
+ go(item.id);
3257
+ return;
3258
+ }
3259
+ hops++;
3260
+ index = circular ? mod(length, index + stride) : index + direction * absStride;
3261
+ if (!circular && (index < 0 || index >= length)) return;
3262
+ }
3263
+ }
3264
+ function next() {
3265
+ step(1);
3266
+ }
3267
+ function prev() {
3268
+ step(-1);
3269
+ }
3270
+ function first() {
3271
+ const list = enabled();
3272
+ if (list.length > 0) go(list[0].id);
3273
+ }
3274
+ function last() {
3275
+ const list = enabled();
3276
+ if (list.length > 0) go(list.at(-1).id);
3277
+ }
3278
+ /** Focus first non-disabled item in the current row (grid mode) */
3279
+ function rowFirst() {
3280
+ const cols = toValue(_columns) ?? 0;
3281
+ if (!cols) return first();
3282
+ const all = items();
3283
+ const current = /* @__PURE__ */ isUndefined(activeId.value) ? 0 : indexOf(activeId.value);
3284
+ const rowStart = current - current % cols;
3285
+ const rowEnd = Math.min(rowStart + cols, all.length);
3286
+ for (let i = rowStart; i < rowEnd; i++) {
3287
+ const item = all[i];
3288
+ if (item && !toValue(item.disabled)) {
3289
+ go(item.id);
3290
+ return;
3291
+ }
3292
+ }
3293
+ }
3294
+ /** Focus last non-disabled item in the current row (grid mode) */
3295
+ function rowLast() {
3296
+ const cols = toValue(_columns) ?? 0;
3297
+ if (!cols) return last();
3298
+ const all = items();
3299
+ const current = /* @__PURE__ */ isUndefined(activeId.value) ? 0 : indexOf(activeId.value);
3300
+ const rowStart = current - current % cols;
3301
+ const rowEnd = Math.min(rowStart + cols, all.length);
3302
+ for (let i = rowEnd - 1; i >= rowStart; i--) {
3303
+ const item = all[i];
3304
+ if (item && !toValue(item.disabled)) {
3305
+ go(item.id);
3306
+ return;
3307
+ }
3308
+ }
3309
+ }
3310
+ function onKeydown(e) {
3311
+ const cols = toValue(_columns);
3312
+ const rtl = isRtl(e);
3313
+ if (cols) {
3314
+ switch (e.key) {
3315
+ case "ArrowRight":
3316
+ e.preventDefault();
3317
+ step(rtl ? -1 : 1);
3318
+ break;
3319
+ case "ArrowLeft":
3320
+ e.preventDefault();
3321
+ step(rtl ? 1 : -1);
3322
+ break;
3323
+ case "ArrowDown":
3324
+ e.preventDefault();
3325
+ step(cols);
3326
+ break;
3327
+ case "ArrowUp":
3328
+ e.preventDefault();
3329
+ step(-cols);
3330
+ break;
3331
+ case "Home":
3332
+ e.preventDefault();
3333
+ if (e.ctrlKey) first();
3334
+ else rowFirst();
3335
+ break;
3336
+ case "End":
3337
+ e.preventDefault();
3338
+ if (e.ctrlKey) last();
3339
+ else rowLast();
3340
+ break;
3341
+ }
3342
+ return;
3343
+ }
3344
+ const prevKeys = [];
3345
+ const nextKeys = [];
3346
+ if (orientation === "vertical" || orientation === "both") {
3347
+ prevKeys.push("ArrowUp");
3348
+ nextKeys.push("ArrowDown");
3349
+ }
3350
+ if (orientation === "horizontal" || orientation === "both") {
3351
+ prevKeys.push(rtl ? "ArrowRight" : "ArrowLeft");
3352
+ nextKeys.push(rtl ? "ArrowLeft" : "ArrowRight");
3353
+ }
3354
+ if (prevKeys.includes(e.key)) {
3355
+ e.preventDefault();
3356
+ prev();
3357
+ } else if (nextKeys.includes(e.key)) {
3358
+ e.preventDefault();
3359
+ next();
3360
+ } else if (e.key === "Home") {
3361
+ e.preventDefault();
3362
+ first();
3363
+ } else if (e.key === "End") {
3364
+ e.preventDefault();
3365
+ last();
3366
+ }
3367
+ }
3368
+ return {
3369
+ activeId,
3370
+ step,
3371
+ next,
3372
+ prev,
3373
+ first,
3374
+ last,
3375
+ onKeydown
3376
+ };
3377
+ }
3378
+ //#endregion
3379
+ //#region src/composables/useRovingFocus/index.ts
3380
+ /**
3381
+ * @module useRovingFocus
3382
+ *
3383
+ * @remarks
3384
+ * Roving tabindex composable for keyboard navigation within composite widgets.
3385
+ *
3386
+ * Key features:
3387
+ * - Arrow key navigation with orientation support
3388
+ * - Grid mode for 2D navigation (data tables, calendars)
3389
+ * - Automatic disabled item skipping
3390
+ * - Optional circular navigation
3391
+ * - Home/End key support (row-scoped in grid mode)
3392
+ * - Auto-attaches keydown listener when target is provided
3393
+ *
3394
+ * Perfect for toolbars, menus, tree items, grids, and other composite widgets.
3395
+ */
3396
+ function useRovingFocus(items, options = {}) {
3397
+ const { orientation, circular, columns, onFocus, target } = options;
3398
+ function applyFocus(id) {
3399
+ const item = items().find((i) => i.id === id);
3400
+ if (!item?.el) return false;
3401
+ onFocus?.(id);
3402
+ nextTick(() => {
3403
+ toValue(item.el)?.focus();
3404
+ });
3405
+ return true;
3406
+ }
3407
+ const traversal = createFocusTraversal(items, (id) => applyFocus(id), {
3408
+ orientation,
3409
+ circular,
3410
+ columns
3411
+ });
3412
+ function focus(id) {
3413
+ const prev = traversal.activeId.value;
3414
+ traversal.activeId.value = id;
3415
+ if (!applyFocus(id)) traversal.activeId.value = prev;
3416
+ }
3417
+ function enabled() {
3418
+ return items().filter((item) => !toValue(item.disabled));
3419
+ }
3420
+ function isTabbable(id) {
3421
+ if (!/* @__PURE__ */ isUndefined(traversal.activeId.value)) return traversal.activeId.value === id;
3422
+ const list = enabled();
3423
+ return list.length > 0 && list[0]?.id === id;
3424
+ }
3425
+ if (target) useEventListener(target, "keydown", traversal.onKeydown);
3426
+ return {
3427
+ focusedId: traversal.activeId,
3428
+ isTabbable,
3429
+ focus,
3430
+ next: traversal.next,
3431
+ prev: traversal.prev,
3432
+ first: traversal.first,
3433
+ last: traversal.last,
3434
+ onKeydown: traversal.onKeydown
3435
+ };
3436
+ }
3437
+ //#endregion
3128
3438
  //#region src/composables/useRtl/adapters/v0.ts
3129
3439
  var Vuetify0RtlAdapter = class {
3130
3440
  setup(app, context, target) {
@@ -4093,31 +4403,27 @@ function useTimeline(namespace = "v0:timeline") {
4093
4403
  * @module createValidation
4094
4404
  *
4095
4405
  * @remarks
4096
- * Per-field validation lifecycle composable.
4406
+ * Per-input validation composable built on createGroup.
4097
4407
  *
4098
4408
  * Key features:
4409
+ * - Each ticket is a rule — enable/disable via select/unselect
4099
4410
  * - Auto-register with parent form via useForm() injection
4100
4411
  * - Async rule support with generation-based race safety
4101
4412
  * - Silent validation mode
4102
4413
  * - Tri-state isValid (null/true/false)
4103
- * - isPristine tracking
4104
4414
  *
4105
4415
  * Uses useRules() to resolve alias strings via shared context.
4106
4416
  */
4417
+ const UNSET = Symbol("unset");
4107
4418
  /**
4108
- * Resolves raw rule inputs to FormValidationRule[].
4109
- * Uses the provided RulesContext if available, otherwise handles
4110
- * functions and Standard Schema objects directly.
4111
- */
4112
- function resolveRules(raw, context) {
4113
- if (context) return context.resolve(raw);
4114
- return raw.filter((r) => /* @__PURE__ */ isFunction(r) || isStandardSchema(r)).map((r) => isStandardSchema(r) ? toRule(r) : r);
4115
- }
4116
- /**
4117
- * Creates a new validation instance.
4419
+ * Creates a per-input validation instance.
4420
+ *
4421
+ * Built on `createGroup` each registered rule becomes a ticket that can be
4422
+ * enabled/disabled via selection methods (`select`, `unselect`, `toggle`).
4423
+ * Only selected (active) rules run during validation.
4118
4424
  *
4119
4425
  * @param options The options for the validation instance.
4120
- * @returns A new validation context with register(), aggregate state, etc.
4426
+ * @returns A new validation context.
4121
4427
  *
4122
4428
  * @see https://0.vuetifyjs.com/composables/forms/create-validation
4123
4429
  *
@@ -4125,111 +4431,83 @@ function resolveRules(raw, context) {
4125
4431
  * ```ts
4126
4432
  * import { createValidation } from '@vuetify/v0'
4127
4433
  *
4128
- * const validation = createValidation()
4129
- *
4130
- * const field = validation.register({
4131
- * id: 'email',
4132
- * value: '',
4133
- * rules: [(v) => !!v || 'Required'],
4434
+ * const validation = createValidation({
4435
+ * rules: [
4436
+ * v => !!v || 'Required',
4437
+ * v => /^.+@\S+\.\S+$/.test(String(v)) || 'Invalid email',
4438
+ * ],
4134
4439
  * })
4135
4440
  *
4136
- * await field.validate()
4441
+ * await validation.validate('')
4137
4442
  *
4138
- * console.log(field.errors.value) // ['Required']
4443
+ * console.log(validation.errors.value) // ['Required', 'Invalid email']
4139
4444
  *
4140
- * field.reset()
4445
+ * validation.reset()
4141
4446
  * ```
4142
4447
  */
4143
- function createValidation(options = {}) {
4144
- const registry = createRegistry(options);
4145
- const rules = useRules();
4146
- const isValidating = computed(() => {
4147
- for (const ticket of registry.values()) if (ticket.isValidating.value) return true;
4148
- return false;
4448
+ function createValidation(_options = {}) {
4449
+ const { rules: initialRules = [], value: valueSource, enroll = true, ...options } = _options;
4450
+ const group = createGroup({
4451
+ ...options,
4452
+ enroll,
4453
+ multiple: true
4149
4454
  });
4150
- const isValid = computed(() => {
4151
- let hasNull = false;
4152
- let hasFields = false;
4153
- for (const ticket of registry.values()) {
4154
- hasFields = true;
4155
- if (ticket.isValid.value === false) return false;
4156
- if (/* @__PURE__ */ isNull(ticket.isValid.value)) hasNull = true;
4455
+ const rulesContext = useRules();
4456
+ const errors = shallowRef([]);
4457
+ const isValid = shallowRef(null);
4458
+ const isValidating = shallowRef(false);
4459
+ let generation = 0;
4460
+ function register(input) {
4461
+ if (/* @__PURE__ */ isFunction(input) || /* @__PURE__ */ isString(input) || isStandardSchema(input)) {
4462
+ const resolved = rulesContext.resolve([input]);
4463
+ return group.register({ value: resolved[0] ?? (() => true) });
4157
4464
  }
4158
- if (!hasFields) return null;
4159
- return hasNull ? null : true;
4160
- });
4161
- function register(registration = {}) {
4162
- const model = shallowRef(/* @__PURE__ */ isNullOrUndefined(registration.value) ? "" : toValue(registration.value));
4163
- const resolved = resolveRules(registration.rules || [], rules);
4164
- const errors = shallowRef([]);
4165
- const isFieldValidating = shallowRef(false);
4166
- const initialValue = model.value;
4167
- const isPristine = shallowRef(true);
4168
- const isFieldValid = shallowRef(null);
4169
- function reset() {
4170
- model.value = initialValue;
4171
- errors.value = [];
4172
- isPristine.value = true;
4173
- isFieldValid.value = null;
4174
- isFieldValidating.value = false;
4175
- validationGeneration++;
4465
+ return group.register(input);
4466
+ }
4467
+ function onboard(rules) {
4468
+ return group.batch(() => rules.map((r) => register(r)));
4469
+ }
4470
+ async function validate(_value = UNSET, silent = false) {
4471
+ const val = _value === UNSET ? toValue(valueSource) : _value;
4472
+ const activeRules = [];
4473
+ for (const ticket of group.selectedItems.value) activeRules.push(ticket.value);
4474
+ if (activeRules.length === 0) {
4475
+ if (!silent) isValid.value = true;
4476
+ return true;
4176
4477
  }
4177
- let validationGeneration = 0;
4178
- async function validate(silent = false) {
4179
- if (resolved.length === 0) return isFieldValid.value = true;
4180
- const generation = ++validationGeneration;
4181
- isFieldValidating.value = true;
4182
- try {
4183
- const results = await Promise.all(resolved.map((rule) => rule(model.value)));
4184
- if (generation !== validationGeneration) return isFieldValid.value ?? false;
4185
- const errorMessages = results.filter((result) => /* @__PURE__ */ isString(result) || result === false).map((result) => result === false ? "Validation failed" : result);
4186
- if (!silent) {
4187
- errors.value = errorMessages;
4188
- isFieldValid.value = errorMessages.length === 0;
4189
- isPristine.value = model.value === initialValue;
4190
- }
4191
- return errorMessages.length === 0;
4192
- } finally {
4193
- if (generation === validationGeneration) isFieldValidating.value = false;
4478
+ const gen = ++generation;
4479
+ if (!silent) isValidating.value = true;
4480
+ try {
4481
+ const results = await Promise.all(activeRules.map((rule) => rule(val)));
4482
+ if (gen !== generation) return isValid.value ?? false;
4483
+ const errorMessages = results.filter((result) => /* @__PURE__ */ isString(result) || result === false).map((result) => result === false ? "Validation failed" : result);
4484
+ if (!silent) {
4485
+ errors.value = errorMessages;
4486
+ isValid.value = errorMessages.length === 0;
4194
4487
  }
4488
+ return errorMessages.length === 0;
4489
+ } finally {
4490
+ if (gen === generation && !silent) isValidating.value = false;
4195
4491
  }
4196
- const item = {
4197
- ...registration,
4198
- rules: resolved,
4199
- errors,
4200
- disabled: registration.disabled || false,
4201
- isValidating: isFieldValidating,
4202
- isPristine,
4203
- isValid: isFieldValid,
4204
- reset,
4205
- validate
4206
- };
4207
- const ticket = registry.register(item);
4208
- Object.defineProperty(ticket, "value", {
4209
- get() {
4210
- return model.value;
4211
- },
4212
- set(val) {
4213
- model.value = val;
4214
- isPristine.value = val === initialValue;
4215
- isFieldValid.value = null;
4216
- },
4217
- enumerable: true,
4218
- configurable: true
4219
- });
4220
- return ticket;
4221
4492
  }
4222
- function onboard(registrations) {
4223
- return registry.batch(() => registrations.map((r) => register(r)));
4493
+ function reset() {
4494
+ errors.value = [];
4495
+ isValid.value = null;
4496
+ isValidating.value = false;
4497
+ generation++;
4224
4498
  }
4499
+ if (initialRules.length > 0) onboard(initialRules);
4225
4500
  const context = {
4226
- ...registry,
4501
+ ...group,
4227
4502
  register,
4228
4503
  onboard,
4504
+ validate,
4505
+ reset,
4506
+ errors,
4229
4507
  isValid,
4230
4508
  isValidating,
4231
4509
  get size() {
4232
- return registry.size;
4510
+ return group.size;
4233
4511
  }
4234
4512
  };
4235
4513
  const form = useForm();
@@ -4684,6 +4962,80 @@ function useVirtual(namespace = "v0:virtual") {
4684
4962
  return useContext(namespace);
4685
4963
  }
4686
4964
  //#endregion
4965
+ //#region src/composables/useVirtualFocus/index.ts
4966
+ /**
4967
+ * @module useVirtualFocus
4968
+ *
4969
+ * @remarks
4970
+ * Virtual focus composable for aria-activedescendant keyboard navigation.
4971
+ * DOM focus stays on a control element while a virtual cursor highlights
4972
+ * items in a list.
4973
+ *
4974
+ * Key features:
4975
+ * - Arrow key navigation with orientation support
4976
+ * - Grid mode for 2D navigation
4977
+ * - Automatic disabled item skipping
4978
+ * - Optional circular navigation
4979
+ * - Home/End key support (row-scoped in grid mode)
4980
+ * - Auto-attaches keydown listener when target is provided
4981
+ * - Sets aria-activedescendant and data-highlighted attributes
4982
+ *
4983
+ * Perfect for comboboxes, autocompletes, listboxes, and other widgets
4984
+ * where DOM focus must remain on the control element.
4985
+ */
4986
+ function useVirtualFocus(items, options) {
4987
+ const { control, target, orientation, circular, columns, onHighlight } = options;
4988
+ let previousEl = null;
4989
+ function applyHighlight(id) {
4990
+ const item = items().find((i) => i.id === id);
4991
+ if (!item?.el) return false;
4992
+ const el = toValue(item.el);
4993
+ if (!el) return false;
4994
+ const controlEl = toValue(control);
4995
+ if (controlEl) {
4996
+ const itemId = el.getAttribute("id");
4997
+ if (itemId) controlEl.setAttribute("aria-activedescendant", itemId);
4998
+ }
4999
+ if (previousEl) delete previousEl.dataset.highlighted;
5000
+ el.dataset.highlighted = "";
5001
+ previousEl = el;
5002
+ el.scrollIntoView({ block: "nearest" });
5003
+ onHighlight?.(id);
5004
+ return true;
5005
+ }
5006
+ const traversal = createFocusTraversal(items, (id) => applyHighlight(id), {
5007
+ orientation,
5008
+ circular,
5009
+ columns
5010
+ });
5011
+ function highlight(id) {
5012
+ const prev = traversal.activeId.value;
5013
+ traversal.activeId.value = id;
5014
+ if (!applyHighlight(id)) traversal.activeId.value = prev;
5015
+ }
5016
+ function clear() {
5017
+ traversal.activeId.value = void 0;
5018
+ const controlEl = toValue(control);
5019
+ if (controlEl) controlEl.removeAttribute("aria-activedescendant");
5020
+ if (previousEl) {
5021
+ delete previousEl.dataset.highlighted;
5022
+ previousEl = null;
5023
+ }
5024
+ }
5025
+ const listener = target ?? control;
5026
+ if (listener) useEventListener(listener, "keydown", traversal.onKeydown);
5027
+ return {
5028
+ highlightedId: traversal.activeId,
5029
+ highlight,
5030
+ clear,
5031
+ next: traversal.next,
5032
+ prev: traversal.prev,
5033
+ first: traversal.first,
5034
+ last: traversal.last,
5035
+ onKeydown: traversal.onKeydown
5036
+ };
5037
+ }
5038
+ //#endregion
4687
5039
  //#region src/composables/useEventListener/index.ts
4688
5040
  /**
4689
5041
  * @module useEventListener
@@ -5029,4 +5381,4 @@ function useClickOutside(target, handler, options = {}) {
5029
5381
  };
5030
5382
  }
5031
5383
  //#endregion
5032
- export { createDatePlugin as $, Vuetify0RtlAdapter as A, useMediaQuery as B, useStack as C, createRtlFallback as D, createRtlContext as E, createNestedContext as F, useElementIntersection as G, usePrefersDark as H, useNested as I, createForm as J, useIntersectionObserver as K, multipleOpenStrategy as L, createQueueContext as M, useQueue as N, createRtlPlugin as O, createNested as P, createDateContext as Q, singleOpenStrategy as R, createStackPlugin as S, createRtl as T, usePrefersReducedMotion as U, usePrefersContrast as V, useLazy as W, useForm as X, createFormContext as Y, createDate as Z, createStep as _, useHydration as _t, createVirtual as a, toReactive as at, createStack as b, useBreadcrumbs as bt, useToggleScope as c, createOverflowContext as ct, createTimelineContext as d, useResizeObserver as dt, useDate as et, useTimeline as f, toElement as ft, useStorage as g, createHydrationPlugin as gt, createStoragePlugin as h, createHydrationContext as ht, useWindowEventListener as i, useBreakpoints as it, createQueue as j, useRtl as k, createValidation as l, useOverflow as lt, createStorageContext as m, createHydration as mt, useDocumentEventListener as n, createBreakpointsContext as nt, createVirtualContext as o, useProxyModel as ot, createStorage as p, createFallbackHydration as pt, useHotkey as q, useEventListener as r, createBreakpointsPlugin as rt, useVirtual as s, createOverflow as st, useClickOutside as t, createBreakpoints as tt, createTimeline as u, useElementSize as ut, createStepContext as v, createBreadcrumbs as vt, createSlider as w, createStackContext as x, useStep as y, createBreadcrumbsContext as yt, useMutationObserver as z };
5384
+ export { useForm as $, useRtl as A, multipleOpenStrategy as B, createStackPlugin as C, useBreadcrumbs as Ct, createRtlContext as D, createRtl as E, useQueue as F, usePrefersDark as G, useMutationObserver as H, usePopover as I, useElementIntersection as J, usePrefersReducedMotion as K, createNested as L, useRovingFocus as M, createQueue as N, createRtlFallback as O, createQueueContext as P, createFormContext as Q, createNestedContext as R, createStackContext as S, createBreadcrumbsContext as St, createSlider as T, useMediaQuery as U, singleOpenStrategy as V, usePrefersContrast as W, useHotkey as X, useIntersectionObserver as Y, createForm as Z, useStorage as _, createHydration as _t, useVirtualFocus as a, createBreakpointsContext as at, useStep as b, useHydration as bt, useVirtual as c, toReactive as ct, createTimeline as d, createOverflowContext as dt, createDate as et, createTimelineContext as f, useOverflow as ft, createStoragePlugin as g, createFallbackHydration as gt, createStorageContext as h, toElement as ht, useWindowEventListener as i, createBreakpoints as it, Vuetify0RtlAdapter as j, createRtlPlugin as k, useToggleScope as l, useProxyModel as lt, createStorage as m, useResizeObserver as mt, useDocumentEventListener as n, createDatePlugin as nt, createVirtual as o, createBreakpointsPlugin as ot, useTimeline as p, useElementSize as pt, useLazy as q, useEventListener as r, useDate as rt, createVirtualContext as s, useBreakpoints as st, useClickOutside as t, createDateContext as tt, createValidation as u, createOverflow as ut, createStep as v, createHydrationContext as vt, useStack as w, createStack as x, createBreadcrumbs as xt, createStepContext as y, createHydrationPlugin as yt, useNested as z };