@vuetify/nightly 3.8.4-master.2025-05-12 → 3.8.5-dev.2025-05-14

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 (101) hide show
  1. package/CHANGELOG.md +20 -12
  2. package/dist/_component-variables-labs.sass +1 -0
  3. package/dist/json/attributes.json +2152 -1792
  4. package/dist/json/importMap-labs.json +40 -36
  5. package/dist/json/importMap.json +106 -106
  6. package/dist/json/tags.json +95 -0
  7. package/dist/json/web-types.json +5016 -3760
  8. package/dist/vuetify-labs.cjs +429 -61
  9. package/dist/vuetify-labs.css +4205 -4149
  10. package/dist/vuetify-labs.d.ts +2274 -1142
  11. package/dist/vuetify-labs.esm.js +430 -62
  12. package/dist/vuetify-labs.esm.js.map +1 -1
  13. package/dist/vuetify-labs.js +429 -61
  14. package/dist/vuetify-labs.min.css +2 -2
  15. package/dist/vuetify.cjs +151 -41
  16. package/dist/vuetify.cjs.map +1 -1
  17. package/dist/vuetify.css +4725 -4672
  18. package/dist/vuetify.d.ts +544 -487
  19. package/dist/vuetify.esm.js +152 -42
  20. package/dist/vuetify.esm.js.map +1 -1
  21. package/dist/vuetify.js +151 -41
  22. package/dist/vuetify.js.map +1 -1
  23. package/dist/vuetify.min.css +2 -2
  24. package/dist/vuetify.min.js +1181 -1173
  25. package/dist/vuetify.min.js.map +1 -1
  26. package/lib/components/VAlert/VAlert.css +6 -1
  27. package/lib/components/VAlert/VAlert.d.ts +35 -0
  28. package/lib/components/VAlert/VAlert.js +14 -9
  29. package/lib/components/VAlert/VAlert.js.map +1 -1
  30. package/lib/components/VAlert/VAlert.sass +7 -1
  31. package/lib/components/VAutocomplete/VAutocomplete.d.ts +94 -94
  32. package/lib/components/VBottomSheet/VBottomSheet.css +1 -1
  33. package/lib/components/VBottomSheet/VBottomSheet.sass +1 -1
  34. package/lib/components/VBtn/VBtn.css +25 -0
  35. package/lib/components/VBtn/VBtn.sass +9 -0
  36. package/lib/components/VBtn/_variables.scss +1 -0
  37. package/lib/components/VBtnGroup/VBtnGroup.css +30 -7
  38. package/lib/components/VBtnGroup/VBtnGroup.d.ts +58 -32
  39. package/lib/components/VBtnGroup/VBtnGroup.js +7 -3
  40. package/lib/components/VBtnGroup/VBtnGroup.js.map +1 -1
  41. package/lib/components/VBtnGroup/VBtnGroup.sass +44 -17
  42. package/lib/components/VBtnToggle/VBtnToggle.d.ts +25 -0
  43. package/lib/components/VCheckbox/VCheckbox.d.ts +3 -3
  44. package/lib/components/VCombobox/VCombobox.d.ts +94 -94
  45. package/lib/components/VField/VField.d.ts +3 -3
  46. package/lib/components/VFileInput/VFileInput.d.ts +15 -15
  47. package/lib/components/VInput/VInput.d.ts +4 -4
  48. package/lib/components/VNumberInput/VNumberInput.d.ts +89 -89
  49. package/lib/components/VOverlay/VOverlay.css +1 -1
  50. package/lib/components/VOverlay/_variables.scss +1 -1
  51. package/lib/components/VRadioGroup/VRadioGroup.d.ts +3 -3
  52. package/lib/components/VRangeSlider/VRangeSlider.d.ts +3 -3
  53. package/lib/components/VSelect/VSelect.d.ts +94 -94
  54. package/lib/components/VSlider/VSlider.d.ts +3 -3
  55. package/lib/components/VSnackbarQueue/VSnackbarQueue.d.ts +3 -1
  56. package/lib/components/VSnackbarQueue/VSnackbarQueue.js.map +1 -1
  57. package/lib/components/VSwitch/VSwitch.d.ts +3 -3
  58. package/lib/components/VTextField/VTextField.d.ts +27 -27
  59. package/lib/components/VTextarea/VTextarea.d.ts +15 -15
  60. package/lib/composables/calendar.d.ts +1 -0
  61. package/lib/composables/calendar.js.map +1 -1
  62. package/lib/composables/dateFormat.d.ts +24 -0
  63. package/lib/composables/dateFormat.js +112 -0
  64. package/lib/composables/dateFormat.js.map +1 -0
  65. package/lib/composables/iconSizes.d.ts +28 -0
  66. package/lib/composables/iconSizes.js +23 -0
  67. package/lib/composables/iconSizes.js.map +1 -0
  68. package/lib/composables/theme.d.ts +6 -1
  69. package/lib/composables/theme.js +94 -26
  70. package/lib/composables/theme.js.map +1 -1
  71. package/lib/composables/virtual.js +6 -1
  72. package/lib/composables/virtual.js.map +1 -1
  73. package/lib/entry-bundler.js +1 -1
  74. package/lib/entry-bundler.js.map +1 -1
  75. package/lib/framework.d.ts +51 -43
  76. package/lib/framework.js +1 -1
  77. package/lib/framework.js.map +1 -1
  78. package/lib/iconsets/mdi.js +2 -1
  79. package/lib/iconsets/mdi.js.map +1 -1
  80. package/lib/labs/VColorInput/VColorInput.css +4 -0
  81. package/lib/labs/VColorInput/VColorInput.d.ts +1767 -0
  82. package/lib/labs/VColorInput/VColorInput.js +129 -0
  83. package/lib/labs/VColorInput/VColorInput.js.map +1 -0
  84. package/lib/labs/VColorInput/VColorInput.sass +7 -0
  85. package/lib/labs/VColorInput/_variables.scss +2 -0
  86. package/lib/labs/VColorInput/index.d.ts +1 -0
  87. package/lib/labs/VColorInput/index.js +2 -0
  88. package/lib/labs/VColorInput/index.js.map +1 -0
  89. package/lib/labs/VDateInput/VDateInput.d.ts +133 -108
  90. package/lib/labs/VDateInput/VDateInput.js +43 -10
  91. package/lib/labs/VDateInput/VDateInput.js.map +1 -1
  92. package/lib/labs/VIconBtn/VIconBtn.d.ts +29 -29
  93. package/lib/labs/VIconBtn/VIconBtn.js +7 -11
  94. package/lib/labs/VIconBtn/VIconBtn.js.map +1 -1
  95. package/lib/labs/components.d.ts +1 -0
  96. package/lib/labs/components.js +1 -0
  97. package/lib/labs/components.js.map +1 -1
  98. package/lib/util/globals.d.ts +1 -0
  99. package/lib/util/globals.js +1 -0
  100. package/lib/util/globals.js.map +1 -1
  101. package/package.json +2 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Vuetify v3.8.4-master.2025-05-12
2
+ * Vuetify v3.8.5-dev.2025-05-14
3
3
  * Forged by John Leider
4
4
  * Released under the MIT License.
5
5
  */
@@ -85,6 +85,7 @@
85
85
  const SUPPORTS_INTERSECTION = IN_BROWSER && 'IntersectionObserver' in window;
86
86
  const SUPPORTS_TOUCH = IN_BROWSER && ('ontouchstart' in window || window.navigator.maxTouchPoints > 0);
87
87
  const SUPPORTS_EYE_DROPPER = IN_BROWSER && 'EyeDropper' in window;
88
+ const SUPPORTS_MATCH_MEDIA = IN_BROWSER && 'matchMedia' in window && typeof window.matchMedia === 'function';
88
89
 
89
90
  function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
90
91
  function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
@@ -2299,6 +2300,7 @@
2299
2300
  function genDefaults$2() {
2300
2301
  return {
2301
2302
  defaultTheme: 'light',
2303
+ prefix: 'v-',
2302
2304
  variations: {
2303
2305
  colors: [],
2304
2306
  lighten: 0,
@@ -2380,7 +2382,10 @@
2380
2382
  }
2381
2383
  }
2382
2384
  },
2383
- stylesheetId: 'vuetify-theme-stylesheet'
2385
+ stylesheetId: 'vuetify-theme-stylesheet',
2386
+ scoped: false,
2387
+ unimportant: false,
2388
+ utilities: true
2384
2389
  };
2385
2390
  }
2386
2391
  function parseThemeOptions() {
@@ -2403,21 +2408,21 @@
2403
2408
  function createCssClass(lines, selector, content, scope) {
2404
2409
  lines.push(`${getScopedSelector(selector, scope)} {\n`, ...content.map(line => ` ${line};\n`), '}\n');
2405
2410
  }
2406
- function genCssVariables(theme) {
2411
+ function genCssVariables(theme, prefix) {
2407
2412
  const lightOverlay = theme.dark ? 2 : 1;
2408
2413
  const darkOverlay = theme.dark ? 1 : 2;
2409
2414
  const variables = [];
2410
2415
  for (const [key, value] of Object.entries(theme.colors)) {
2411
2416
  const rgb = parseColor(value);
2412
- variables.push(`--v-theme-${key}: ${rgb.r},${rgb.g},${rgb.b}`);
2417
+ variables.push(`--${prefix}theme-${key}: ${rgb.r},${rgb.g},${rgb.b}`);
2413
2418
  if (!key.startsWith('on-')) {
2414
- variables.push(`--v-theme-${key}-overlay-multiplier: ${getLuma(value) > 0.18 ? lightOverlay : darkOverlay}`);
2419
+ variables.push(`--${prefix}theme-${key}-overlay-multiplier: ${getLuma(value) > 0.18 ? lightOverlay : darkOverlay}`);
2415
2420
  }
2416
2421
  }
2417
2422
  for (const [key, value] of Object.entries(theme.variables)) {
2418
2423
  const color = typeof value === 'string' && value.startsWith('#') ? parseColor(value) : undefined;
2419
2424
  const rgb = color ? `${color.r}, ${color.g}, ${color.b}` : undefined;
2420
- variables.push(`--v-${key}: ${rgb ?? value}`);
2425
+ variables.push(`--${prefix}${key}: ${rgb ?? value}`);
2421
2426
  }
2422
2427
  return variables;
2423
2428
  }
@@ -2461,7 +2466,8 @@
2461
2466
  const scopeSelector = `:where(${scope})`;
2462
2467
  return selector === ':root' ? scopeSelector : `${scopeSelector} ${selector}`;
2463
2468
  }
2464
- function upsertStyles(styleEl, styles) {
2469
+ function upsertStyles(id, cspNonce, styles) {
2470
+ const styleEl = getOrCreateStyleElement(id, cspNonce);
2465
2471
  if (!styleEl) return;
2466
2472
  styleEl.innerHTML = styles;
2467
2473
  }
@@ -2481,8 +2487,17 @@
2481
2487
  // Composables
2482
2488
  function createTheme(options) {
2483
2489
  const parsedOptions = parseThemeOptions(options);
2484
- const name = vue.shallowRef(parsedOptions.defaultTheme);
2490
+ const _name = vue.shallowRef(parsedOptions.defaultTheme);
2485
2491
  const themes = vue.ref(parsedOptions.themes);
2492
+ const systemName = vue.shallowRef('light');
2493
+ const name = vue.computed({
2494
+ get() {
2495
+ return _name.value === 'system' ? systemName.value : _name.value;
2496
+ },
2497
+ set(val) {
2498
+ _name.value = val;
2499
+ }
2500
+ });
2486
2501
  const computedThemes = vue.computed(() => {
2487
2502
  const acc = {};
2488
2503
  for (const [name, original] of Object.entries(themes.value)) {
@@ -2503,28 +2518,49 @@
2503
2518
  const current = vue.toRef(() => computedThemes.value[name.value]);
2504
2519
  const styles = vue.computed(() => {
2505
2520
  const lines = [];
2521
+ const important = parsedOptions.unimportant ? '' : ' !important';
2522
+ const scoped = parsedOptions.scoped ? parsedOptions.prefix : '';
2506
2523
  if (current.value?.dark) {
2507
2524
  createCssClass(lines, ':root', ['color-scheme: dark'], parsedOptions.scope);
2508
2525
  }
2509
- createCssClass(lines, ':root', genCssVariables(current.value), parsedOptions.scope);
2526
+ createCssClass(lines, ':root', genCssVariables(current.value, parsedOptions.prefix), parsedOptions.scope);
2510
2527
  for (const [themeName, theme] of Object.entries(computedThemes.value)) {
2511
- createCssClass(lines, `.v-theme--${themeName}`, [`color-scheme: ${theme.dark ? 'dark' : 'normal'}`, ...genCssVariables(theme)], parsedOptions.scope);
2512
- }
2513
- const bgLines = [];
2514
- const fgLines = [];
2515
- const colors = new Set(Object.values(computedThemes.value).flatMap(theme => Object.keys(theme.colors)));
2516
- for (const key of colors) {
2517
- if (key.startsWith('on-')) {
2518
- createCssClass(fgLines, `.${key}`, [`color: rgb(var(--v-theme-${key})) !important`], parsedOptions.scope);
2519
- } else {
2520
- createCssClass(bgLines, `.bg-${key}`, [`--v-theme-overlay-multiplier: var(--v-theme-${key}-overlay-multiplier)`, `background-color: rgb(var(--v-theme-${key})) !important`, `color: rgb(var(--v-theme-on-${key})) !important`], parsedOptions.scope);
2521
- createCssClass(fgLines, `.text-${key}`, [`color: rgb(var(--v-theme-${key})) !important`], parsedOptions.scope);
2522
- createCssClass(fgLines, `.border-${key}`, [`--v-border-color: var(--v-theme-${key})`], parsedOptions.scope);
2528
+ createCssClass(lines, `.${parsedOptions.prefix}theme--${themeName}`, [`color-scheme: ${theme.dark ? 'dark' : 'normal'}`, ...genCssVariables(theme, parsedOptions.prefix)], parsedOptions.scope);
2529
+ }
2530
+ if (parsedOptions.utilities) {
2531
+ const bgLines = [];
2532
+ const fgLines = [];
2533
+ const colors = new Set(Object.values(computedThemes.value).flatMap(theme => Object.keys(theme.colors)));
2534
+ for (const key of colors) {
2535
+ if (key.startsWith('on-')) {
2536
+ createCssClass(fgLines, `.${key}`, [`color: rgb(var(--${parsedOptions.prefix}theme-${key}))${important}`], parsedOptions.scope);
2537
+ } else {
2538
+ createCssClass(bgLines, `.${scoped}bg-${key}`, [`--${parsedOptions.prefix}theme-overlay-multiplier: var(--${parsedOptions.prefix}theme-${key}-overlay-multiplier)`, `background-color: rgb(var(--${parsedOptions.prefix}theme-${key}))${important}`, `color: rgb(var(--${parsedOptions.prefix}theme-on-${key}))${important}`], parsedOptions.scope);
2539
+ createCssClass(fgLines, `.${scoped}text-${key}`, [`color: rgb(var(--${parsedOptions.prefix}theme-${key}))${important}`], parsedOptions.scope);
2540
+ createCssClass(fgLines, `.${scoped}border-${key}`, [`--${parsedOptions.prefix}border-color: var(--${parsedOptions.prefix}theme-${key})`], parsedOptions.scope);
2541
+ }
2523
2542
  }
2543
+ lines.push(...bgLines, ...fgLines);
2524
2544
  }
2525
- lines.push(...bgLines, ...fgLines);
2526
2545
  return lines.map((str, i) => i === 0 ? str : ` ${str}`).join('');
2527
2546
  });
2547
+ const themeClasses = vue.toRef(() => parsedOptions.isDisabled ? undefined : `${parsedOptions.prefix}theme--${name.value}`);
2548
+ const themeNames = vue.toRef(() => Object.keys(computedThemes.value));
2549
+ if (SUPPORTS_MATCH_MEDIA) {
2550
+ const media = window.matchMedia('(prefers-color-scheme: dark)');
2551
+ function updateSystemName() {
2552
+ systemName.value = media.matches ? 'dark' : 'light';
2553
+ }
2554
+ updateSystemName();
2555
+ media.addEventListener('change', updateSystemName, {
2556
+ passive: true
2557
+ });
2558
+ if (vue.getCurrentScope()) {
2559
+ vue.onScopeDispose(() => {
2560
+ media.removeEventListener('change', updateSystemName);
2561
+ });
2562
+ }
2563
+ }
2528
2564
  function install(app) {
2529
2565
  if (parsedOptions.isDisabled) return;
2530
2566
  const head = app._context.provides.usehead;
@@ -2562,22 +2598,55 @@
2562
2598
  updateStyles();
2563
2599
  }
2564
2600
  function updateStyles() {
2565
- upsertStyles(getOrCreateStyleElement(parsedOptions.stylesheetId, parsedOptions.cspNonce), styles.value);
2601
+ upsertStyles(parsedOptions.stylesheetId, parsedOptions.cspNonce, styles.value);
2566
2602
  }
2567
2603
  }
2568
2604
  }
2569
- const themeClasses = vue.toRef(() => parsedOptions.isDisabled ? undefined : `v-theme--${name.value}`);
2605
+ function change(themeName) {
2606
+ if (!themeNames.value.includes(themeName)) {
2607
+ consoleWarn(`Theme "${themeName}" not found on the Vuetify theme instance`);
2608
+ return;
2609
+ }
2610
+ name.value = themeName;
2611
+ }
2612
+ function cycle() {
2613
+ let themeArray = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : themeNames.value;
2614
+ const currentIndex = themeArray.indexOf(name.value);
2615
+ const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % themeArray.length;
2616
+ change(themeArray[nextIndex]);
2617
+ }
2618
+ function toggle() {
2619
+ let themeArray = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['light', 'dark'];
2620
+ cycle(themeArray);
2621
+ }
2622
+ const globalName = new Proxy(name, {
2623
+ get(target, prop) {
2624
+ return target[prop];
2625
+ },
2626
+ set(target, prop, val) {
2627
+ if (prop === 'value') {
2628
+ deprecate(`theme.global.name.value = ${val}`, `theme.change('${val}')`);
2629
+ }
2630
+ // @ts-expect-error
2631
+ target[prop] = val;
2632
+ return true;
2633
+ }
2634
+ });
2570
2635
  return {
2571
2636
  install,
2637
+ change,
2638
+ cycle,
2639
+ toggle,
2572
2640
  isDisabled: parsedOptions.isDisabled,
2573
2641
  name,
2574
2642
  themes,
2575
2643
  current,
2576
2644
  computedThemes,
2645
+ prefix: parsedOptions.prefix,
2577
2646
  themeClasses,
2578
2647
  styles,
2579
2648
  global: {
2580
- name,
2649
+ name: globalName,
2581
2650
  current
2582
2651
  }
2583
2652
  };
@@ -2588,7 +2657,7 @@
2588
2657
  if (!theme) throw new Error('Could not find Vuetify theme injection');
2589
2658
  const name = vue.toRef(() => props.theme ?? theme.name.value);
2590
2659
  const current = vue.toRef(() => theme.themes.value[name.value]);
2591
- const themeClasses = vue.toRef(() => theme.isDisabled ? undefined : `v-theme--${name.value}`);
2660
+ const themeClasses = vue.toRef(() => theme.isDisabled ? undefined : `${theme.prefix}theme--${name.value}`);
2592
2661
  const newTheme = {
2593
2662
  ...theme,
2594
2663
  name,
@@ -4135,9 +4204,15 @@
4135
4204
  };
4136
4205
  }
4137
4206
 
4207
+ // Types
4208
+
4138
4209
  const makeVBtnGroupProps = propsFactory({
4139
4210
  baseColor: String,
4140
4211
  divided: Boolean,
4212
+ direction: {
4213
+ type: String,
4214
+ default: 'horizontal'
4215
+ },
4141
4216
  ...makeBorderProps(),
4142
4217
  ...makeComponentProps(),
4143
4218
  ...makeDensityProps(),
@@ -4171,7 +4246,7 @@
4171
4246
  } = useRounded(props);
4172
4247
  provideDefaults({
4173
4248
  VBtn: {
4174
- height: 'auto',
4249
+ height: vue.toRef(() => props.direction === 'horizontal' ? 'auto' : null),
4175
4250
  baseColor: vue.toRef(() => props.baseColor),
4176
4251
  color: vue.toRef(() => props.color),
4177
4252
  density: vue.toRef(() => props.density),
@@ -4181,7 +4256,7 @@
4181
4256
  });
4182
4257
  useRender(() => {
4183
4258
  return vue.createVNode(props.tag, {
4184
- "class": ['v-btn-group', {
4259
+ "class": ['v-btn-group', `v-btn-group--${props.direction}`, {
4185
4260
  'v-btn-group--divided': props.divided
4186
4261
  }, themeClasses.value, borderClasses.value, densityClasses.value, elevationClasses.value, roundedClasses.value, props.class],
4187
4262
  "style": props.style
@@ -4510,7 +4585,8 @@
4510
4585
  treeviewCollapse: 'mdi-menu-down',
4511
4586
  treeviewExpand: 'mdi-menu-right',
4512
4587
  eyeDropper: 'mdi-eyedropper',
4513
- upload: 'mdi-cloud-upload'
4588
+ upload: 'mdi-cloud-upload',
4589
+ color: 'mdi-palette'
4514
4590
  };
4515
4591
  const mdi = {
4516
4592
  // Not using mergeProps here, functional components merge props by default (?)
@@ -5868,6 +5944,31 @@
5868
5944
  // Utilities
5869
5945
  const VAlertTitle = createSimpleFunctional('v-alert-title');
5870
5946
 
5947
+ // Utilities
5948
+
5949
+ // Types
5950
+
5951
+ // Types
5952
+
5953
+ // Composables
5954
+ const makeIconSizeProps = propsFactory({
5955
+ iconSize: [Number, String],
5956
+ iconSizes: {
5957
+ type: Array,
5958
+ default: () => [['x-small', 10], ['small', 16], ['default', 24], ['large', 28], ['x-large', 32]]
5959
+ }
5960
+ }, 'iconSize');
5961
+ function useIconSizes(props, fallback) {
5962
+ const iconSize = vue.computed(() => {
5963
+ const iconSizeMap = new Map(props.iconSizes);
5964
+ const _iconSize = props.iconSize ?? fallback() ?? 'default';
5965
+ return iconSizeMap.has(_iconSize) ? iconSizeMap.get(_iconSize) : _iconSize;
5966
+ });
5967
+ return {
5968
+ iconSize
5969
+ };
5970
+ }
5971
+
5871
5972
  // Types
5872
5973
 
5873
5974
  const allowedTypes = ['success', 'info', 'warning', 'error'];
@@ -5907,6 +6008,7 @@
5907
6008
  ...makeDensityProps(),
5908
6009
  ...makeDimensionProps(),
5909
6010
  ...makeElevationProps(),
6011
+ ...makeIconSizeProps(),
5910
6012
  ...makeLocationProps(),
5911
6013
  ...makePositionProps(),
5912
6014
  ...makeRoundedProps(),
@@ -5934,6 +6036,9 @@
5934
6036
  if (!props.type) return props.icon;
5935
6037
  return props.icon ?? `$${props.type}`;
5936
6038
  });
6039
+ const {
6040
+ iconSize
6041
+ } = useIconSizes(props, () => props.prominent ? 44 : 28);
5937
6042
  const {
5938
6043
  themeClasses
5939
6044
  } = provideTheme(props);
@@ -5981,6 +6086,11 @@
5981
6086
  const hasPrepend = !!(slots.prepend || icon.value);
5982
6087
  const hasTitle = !!(slots.title || props.title);
5983
6088
  const hasClose = !!(slots.close || props.closable);
6089
+ const iconProps = {
6090
+ density: props.density,
6091
+ icon: icon.value,
6092
+ size: iconSize.value
6093
+ };
5984
6094
  return isActive.value && vue.createVNode(props.tag, {
5985
6095
  "class": ['v-alert', props.border && {
5986
6096
  'v-alert--border': !!props.border,
@@ -5998,19 +6108,14 @@
5998
6108
  }, null), hasPrepend && vue.createVNode("div", {
5999
6109
  "key": "prepend",
6000
6110
  "class": "v-alert__prepend"
6001
- }, [!slots.prepend ? vue.createVNode(VIcon, {
6002
- "key": "prepend-icon",
6003
- "density": props.density,
6004
- "icon": icon.value,
6005
- "size": props.prominent ? 44 : 28
6006
- }, null) : vue.createVNode(VDefaultsProvider, {
6111
+ }, [!slots.prepend ? vue.createVNode(VIcon, vue.mergeProps({
6112
+ "key": "prepend-icon"
6113
+ }, iconProps), null) : vue.createVNode(VDefaultsProvider, {
6007
6114
  "key": "prepend-defaults",
6008
6115
  "disabled": !icon.value,
6009
6116
  "defaults": {
6010
6117
  VIcon: {
6011
- density: props.density,
6012
- icon: icon.value,
6013
- size: props.prominent ? 44 : 28
6118
+ ...iconProps
6014
6119
  }
6015
6120
  }
6016
6121
  }, slots.prepend)]), vue.createVNode("div", {
@@ -12356,7 +12461,12 @@
12356
12461
  }
12357
12462
  function calculateOffset(index) {
12358
12463
  index = clamp(index, 0, items.value.length - 1);
12359
- return offsets[index] || 0;
12464
+ const whole = Math.floor(index);
12465
+ const fraction = index % 1;
12466
+ const next = whole + 1;
12467
+ const wholeOffset = offsets[whole] || 0;
12468
+ const nextOffset = offsets[next] || wholeOffset;
12469
+ return wholeOffset + (nextOffset - wholeOffset) * fraction;
12360
12470
  }
12361
12471
  function calculateIndex(scrollTop) {
12362
12472
  return binaryClosest(offsets, scrollTop);
@@ -29076,6 +29186,236 @@
29076
29186
 
29077
29187
  // Types
29078
29188
 
29189
+ const makeVColorInputProps = propsFactory({
29190
+ pip: Boolean,
29191
+ pipIcon: {
29192
+ type: String,
29193
+ default: '$color'
29194
+ },
29195
+ ...makeFocusProps(),
29196
+ ...makeVConfirmEditProps(),
29197
+ ...makeVTextFieldProps(),
29198
+ ...omit(makeVColorPickerProps(), ['width'])
29199
+ }, 'VColorInput');
29200
+ const VColorInput = genericComponent()({
29201
+ name: 'VColorInput',
29202
+ props: makeVColorInputProps(),
29203
+ emits: {
29204
+ 'update:modelValue': val => true
29205
+ },
29206
+ setup(props, _ref) {
29207
+ let {
29208
+ slots
29209
+ } = _ref;
29210
+ const {
29211
+ isFocused,
29212
+ focus,
29213
+ blur
29214
+ } = useFocus(props);
29215
+ const model = useProxiedModel(props, 'modelValue');
29216
+ const menu = vue.shallowRef(false);
29217
+ const isInteractive = vue.computed(() => !props.disabled && !props.readonly);
29218
+ const display = vue.computed(() => model.value || null);
29219
+ function onKeydown(e) {
29220
+ if (e.key !== 'Enter') return;
29221
+ if (!menu.value || !isFocused.value) {
29222
+ menu.value = true;
29223
+ return;
29224
+ }
29225
+ const target = e.target;
29226
+ model.value = target.value;
29227
+ }
29228
+ function onClick(e) {
29229
+ e.preventDefault();
29230
+ e.stopPropagation();
29231
+ menu.value = true;
29232
+ }
29233
+ function onSave() {
29234
+ menu.value = false;
29235
+ }
29236
+ useRender(() => {
29237
+ const confirmEditProps = VConfirmEdit.filterProps(props);
29238
+ const colorPickerProps = VColorPicker.filterProps(omit(props, ['active', 'color']));
29239
+ const textFieldProps = VTextField.filterProps(omit(props, ['prependInnerIcon']));
29240
+ const hasPrepend = !!(slots.prepend || props.pipIcon);
29241
+ return vue.createVNode(VTextField, vue.mergeProps(textFieldProps, {
29242
+ "class": ['v-color-input', props.class],
29243
+ "style": props.style,
29244
+ "modelValue": display.value,
29245
+ "onKeydown": isInteractive.value ? onKeydown : undefined,
29246
+ "focused": menu.value || isFocused.value,
29247
+ "onFocus": focus,
29248
+ "onBlur": blur,
29249
+ "onClick:control": isInteractive.value ? onClick : undefined,
29250
+ "onClick:prependInner": isInteractive.value ? onClick : undefined,
29251
+ "onClick:appendInner": isInteractive.value ? onClick : undefined,
29252
+ "onUpdate:modelValue": val => {
29253
+ model.value = val;
29254
+ }
29255
+ }), {
29256
+ ...slots,
29257
+ prepend: props.pipIcon ? arg => vue.createVNode(vue.Fragment, null, [hasPrepend && vue.createVNode(VIcon, {
29258
+ "color": props.pip ? model.value : undefined,
29259
+ "icon": props.pipIcon
29260
+ }, null), slots.prepend?.(arg)]) : undefined,
29261
+ default: () => vue.createVNode(vue.Fragment, null, [vue.createVNode(VMenu, {
29262
+ "modelValue": menu.value,
29263
+ "onUpdate:modelValue": $event => menu.value = $event,
29264
+ "activator": "parent",
29265
+ "min-width": "0",
29266
+ "closeOnContentClick": false,
29267
+ "openOnClick": false
29268
+ }, {
29269
+ default: () => [vue.createVNode(VConfirmEdit, vue.mergeProps(confirmEditProps, {
29270
+ "modelValue": model.value,
29271
+ "onUpdate:modelValue": $event => model.value = $event,
29272
+ "onSave": onSave
29273
+ }), {
29274
+ default: _ref2 => {
29275
+ let {
29276
+ actions,
29277
+ model: proxyModel,
29278
+ save,
29279
+ cancel,
29280
+ isPristine
29281
+ } = _ref2;
29282
+ return vue.createVNode(VColorPicker, vue.mergeProps(colorPickerProps, {
29283
+ "modelValue": proxyModel.value,
29284
+ "onUpdate:modelValue": val => {
29285
+ proxyModel.value = val;
29286
+ model.value = val;
29287
+ },
29288
+ "onMousedown": e => e.preventDefault()
29289
+ }), {
29290
+ actions: !props.hideActions ? () => slots.actions?.({
29291
+ save,
29292
+ cancel,
29293
+ isPristine
29294
+ }) ?? actions() : undefined
29295
+ });
29296
+ }
29297
+ })]
29298
+ }), slots.default?.()])
29299
+ });
29300
+ });
29301
+ }
29302
+ });
29303
+
29304
+ // Composables
29305
+
29306
+ // Types
29307
+
29308
+ // Types
29309
+
29310
+ class DateFormatSpec {
29311
+ constructor(order,
29312
+ // mdy | dmy | ymd
29313
+ separator // / | - | .
29314
+ ) {
29315
+ this.order = order;
29316
+ this.separator = separator;
29317
+ }
29318
+ get format() {
29319
+ return this.order.split('').map(sign => `${sign}${sign}`).join(this.separator).replace('yy', 'yyyy');
29320
+ }
29321
+ static canBeParsed(v) {
29322
+ if (typeof v !== 'string') return false;
29323
+ const lowercase = v.toLowerCase();
29324
+ return ['y', 'm', 'd'].every(sign => lowercase.includes(sign)) && ['/', '-', '.'].some(sign => v.includes(sign));
29325
+ }
29326
+ static parse(v) {
29327
+ if (!DateFormatSpec.canBeParsed(v)) {
29328
+ throw new Error(`[${v}] cannot be parsed into date format specification`);
29329
+ }
29330
+ const order = v.toLowerCase().split('').filter((c, i, all) => 'dmy'.includes(c) && all.indexOf(c) === i).join('');
29331
+ const separator = ['/', '-', '.'].find(sign => v.includes(sign));
29332
+ return new DateFormatSpec(order, separator);
29333
+ }
29334
+ }
29335
+ const makeDateFormatProps = propsFactory({
29336
+ inputFormat: {
29337
+ type: String,
29338
+ validator: v => !v || DateFormatSpec.canBeParsed(v)
29339
+ }
29340
+ }, 'date-format');
29341
+ function useDateFormat(props, locale) {
29342
+ const adapter = useDate();
29343
+ function inferFromLocale() {
29344
+ const localeForDateFormat = locale.value ?? 'en-US';
29345
+ const formatFromLocale = Intl.DateTimeFormat(localeForDateFormat, {
29346
+ year: 'numeric',
29347
+ month: '2-digit',
29348
+ day: '2-digit'
29349
+ }).format(adapter.toJsDate(adapter.parseISO('1999-12-07'))).replace(/(07)|(٠٧)|(٢٩)|(۱۶)|(০৭)/, 'dd').replace(/(12)|(١٢)|(٠٨)|(۰۹)|(১২)/, 'mm').replace(/(1999)|(2542)|(١٩٩٩)|(١٤٢٠)|(۱۳۷۸)|(১৯৯৯)/, 'yyyy').replace(/[^ymd\-/.]/g, '').replace(/\.$/, '');
29350
+ if (!DateFormatSpec.canBeParsed(formatFromLocale)) {
29351
+ consoleWarn(`Date format inferred from locale [${localeForDateFormat}] is invalid: [${formatFromLocale}]`);
29352
+ return 'mm/dd/yyyy';
29353
+ }
29354
+ return formatFromLocale;
29355
+ }
29356
+ const currentFormat = vue.toRef(() => {
29357
+ return DateFormatSpec.canBeParsed(props.inputFormat) ? DateFormatSpec.parse(props.inputFormat) : DateFormatSpec.parse(inferFromLocale());
29358
+ });
29359
+ function parseDate(dateString) {
29360
+ function parseDateParts(text) {
29361
+ const parts = text.trim().split(currentFormat.value.separator);
29362
+ return {
29363
+ y: Number(parts[currentFormat.value.order.indexOf('y')]),
29364
+ m: Number(parts[currentFormat.value.order.indexOf('m')]),
29365
+ d: Number(parts[currentFormat.value.order.indexOf('d')])
29366
+ };
29367
+ }
29368
+ function validateDateParts(dateParts) {
29369
+ const {
29370
+ y: year,
29371
+ m: month,
29372
+ d: day
29373
+ } = dateParts;
29374
+ if (!year || !month || !day) return null;
29375
+ if (month < 1 || month > 12) return null;
29376
+ if (day < 1 || day > 31) return null;
29377
+ return {
29378
+ year: autoFixYear(year),
29379
+ month,
29380
+ day
29381
+ };
29382
+ }
29383
+ function autoFixYear(year) {
29384
+ const currentYear = adapter.getYear(adapter.date());
29385
+ if (year > 100 || currentYear % 100 >= 50) {
29386
+ return year;
29387
+ }
29388
+ const currentCentury = ~~(currentYear / 100) * 100;
29389
+ return year < 50 ? currentCentury + year : currentCentury - 100 + year;
29390
+ }
29391
+ const dateParts = parseDateParts(dateString);
29392
+ const validatedParts = validateDateParts(dateParts);
29393
+ if (!validatedParts) return null;
29394
+ const {
29395
+ year,
29396
+ month,
29397
+ day
29398
+ } = validatedParts;
29399
+ const pad = v => String(v).padStart(2, '0');
29400
+ return adapter.parseISO(`${year}-${pad(month)}-${pad(day)}`);
29401
+ }
29402
+ function isValid(text) {
29403
+ return !!parseDate(text);
29404
+ }
29405
+ function formatDate(value) {
29406
+ const parts = adapter.toISO(value).split('-');
29407
+ return currentFormat.value.order.split('').map(sign => parts['ymd'.indexOf(sign)]).join(currentFormat.value.separator);
29408
+ }
29409
+ return {
29410
+ isValid,
29411
+ parseDate,
29412
+ formatDate,
29413
+ parserFormat: vue.toRef(() => currentFormat.value.format)
29414
+ };
29415
+ }
29416
+
29417
+ // Types
29418
+
29079
29419
  // Types
29080
29420
 
29081
29421
  const makeVDateInputProps = propsFactory({
@@ -29084,10 +29424,12 @@
29084
29424
  type: String,
29085
29425
  default: 'bottom start'
29086
29426
  },
29427
+ menu: Boolean,
29087
29428
  updateOn: {
29088
29429
  type: Array,
29089
29430
  default: () => ['blur', 'enter']
29090
29431
  },
29432
+ ...makeDateFormatProps(),
29091
29433
  ...makeDisplayProps({
29092
29434
  mobile: null
29093
29435
  }),
@@ -29096,7 +29438,6 @@
29096
29438
  hideActions: true
29097
29439
  }),
29098
29440
  ...makeVTextFieldProps({
29099
- placeholder: 'mm/dd/yyyy',
29100
29441
  prependIcon: '$calendar'
29101
29442
  }),
29102
29443
  ...omit(makeVDatePickerProps({
@@ -29110,7 +29451,8 @@
29110
29451
  emits: {
29111
29452
  save: value => true,
29112
29453
  cancel: () => true,
29113
- 'update:modelValue': val => true
29454
+ 'update:modelValue': val => true,
29455
+ 'update:menu': val => true
29114
29456
  },
29115
29457
  setup(props, _ref) {
29116
29458
  let {
@@ -29118,9 +29460,16 @@
29118
29460
  slots
29119
29461
  } = _ref;
29120
29462
  const {
29121
- t
29463
+ t,
29464
+ current: currentLocale
29122
29465
  } = useLocale();
29123
29466
  const adapter = useDate();
29467
+ const {
29468
+ isValid,
29469
+ parseDate,
29470
+ formatDate,
29471
+ parserFormat
29472
+ } = useDateFormat(props, currentLocale);
29124
29473
  const {
29125
29474
  mobile
29126
29475
  } = useDisplay(props);
@@ -29131,7 +29480,7 @@
29131
29480
  } = useFocus(props);
29132
29481
  const emptyModelValue = () => props.multiple ? [] : null;
29133
29482
  const model = useProxiedModel(props, 'modelValue', emptyModelValue(), val => Array.isArray(val) ? val.map(item => adapter.toJsDate(item)) : val ? adapter.toJsDate(val) : val, val => Array.isArray(val) ? val.map(item => adapter.date(item)) : val ? adapter.date(val) : val);
29134
- const menu = vue.shallowRef(false);
29483
+ const menu = useProxiedModel(props, 'menu');
29135
29484
  const isEditingInput = vue.shallowRef(false);
29136
29485
  const vTextFieldRef = vue.ref();
29137
29486
  const disabledActions = vue.ref(['save']);
@@ -29139,7 +29488,10 @@
29139
29488
  if (typeof props.displayFormat === 'function') {
29140
29489
  return props.displayFormat(date);
29141
29490
  }
29142
- return adapter.format(date, props.displayFormat ?? 'keyboardDate');
29491
+ if (props.displayFormat) {
29492
+ return adapter.format(date, props.displayFormat ?? 'keyboardDate');
29493
+ }
29494
+ return formatDate(date);
29143
29495
  }
29144
29496
  const display = vue.computed(() => {
29145
29497
  const value = wrapInArray(model.value);
@@ -29174,7 +29526,6 @@
29174
29526
  if (e.key !== 'Enter') return;
29175
29527
  if (!menu.value || !isFocused.value) {
29176
29528
  menu.value = true;
29177
- return;
29178
29529
  }
29179
29530
  if (props.updateOn.includes('enter')) {
29180
29531
  onUserInput(e.target);
@@ -29218,13 +29569,32 @@
29218
29569
  let {
29219
29570
  value
29220
29571
  } = _ref2;
29221
- if (value && !adapter.isValid(value)) return;
29222
- model.value = !value ? emptyModelValue() : value;
29572
+ if (!value.trim()) {
29573
+ model.value = emptyModelValue();
29574
+ } else if (!props.multiple) {
29575
+ if (isValid(value)) {
29576
+ model.value = parseDate(value);
29577
+ }
29578
+ } else {
29579
+ const parts = value.trim().split(/\D+-\D+|[^\d\-/.]+/);
29580
+ if (parts.every(isValid)) {
29581
+ if (props.multiple === 'range') {
29582
+ model.value = getRange(parts);
29583
+ } else {
29584
+ model.value = parts.map(parseDate);
29585
+ }
29586
+ }
29587
+ }
29588
+ }
29589
+ function getRange(inputDates) {
29590
+ const [start, stop] = inputDates.map(parseDate).toSorted((a, b) => adapter.isAfter(a, b) ? 1 : -1);
29591
+ const diff = adapter.getDiff(stop ?? start, start, 'days');
29592
+ return [start, ...createRange(diff, 1).map(i => adapter.addDays(start, i))];
29223
29593
  }
29224
29594
  useRender(() => {
29225
29595
  const confirmEditProps = VConfirmEdit.filterProps(props);
29226
29596
  const datePickerProps = VDatePicker.filterProps(omit(props, ['active', 'location', 'rounded']));
29227
- const textFieldProps = VTextField.filterProps(props);
29597
+ const textFieldProps = VTextField.filterProps(omit(props, ['placeholder']));
29228
29598
  return vue.createVNode(VTextField, vue.mergeProps({
29229
29599
  "ref": vTextFieldRef
29230
29600
  }, textFieldProps, {
@@ -29232,11 +29602,13 @@
29232
29602
  "style": props.style,
29233
29603
  "modelValue": display.value,
29234
29604
  "inputmode": inputmode.value,
29605
+ "placeholder": props.placeholder ?? parserFormat.value,
29235
29606
  "readonly": isReadonly.value,
29236
29607
  "onKeydown": isInteractive.value ? onKeydown : undefined,
29237
29608
  "focused": menu.value || isFocused.value,
29238
29609
  "onFocus": focus,
29239
29610
  "onBlur": onBlur,
29611
+ "validationValue": model.value,
29240
29612
  "onClick:control": isInteractive.value ? onClick : undefined,
29241
29613
  "onClick:prepend": isInteractive.value ? onClick : undefined,
29242
29614
  "onUpdate:modelValue": onUpdateDisplayModel
@@ -29622,11 +29994,6 @@
29622
29994
  hideOverlay: Boolean,
29623
29995
  icon: [String, Function, Object],
29624
29996
  iconColor: String,
29625
- iconSize: [Number, String],
29626
- iconSizes: {
29627
- type: Array,
29628
- default: () => [['x-small', 10], ['small', 16], ['default', 24], ['large', 28], ['x-large', 32]]
29629
- },
29630
29997
  loading: Boolean,
29631
29998
  opacity: [Number, String],
29632
29999
  readonly: Boolean,
@@ -29646,6 +30013,7 @@
29646
30013
  ...makeBorderProps(),
29647
30014
  ...makeComponentProps(),
29648
30015
  ...makeElevationProps(),
30016
+ ...makeIconSizeProps(),
29649
30017
  ...makeRoundedProps(),
29650
30018
  ...makeTagProps({
29651
30019
  tag: 'button'
@@ -29700,7 +30068,6 @@
29700
30068
  })()
29701
30069
  }));
29702
30070
  const btnSizeMap = new Map(props.sizes);
29703
- const iconSizeMap = new Map(props.iconSizes);
29704
30071
  function onClick() {
29705
30072
  if (props.disabled || props.readonly || isActive.value === undefined || props.tag === 'a' && attrs.href) return;
29706
30073
  isActive.value = !isActive.value;
@@ -29712,12 +30079,12 @@
29712
30079
  const btnSize = hasNamedSize ? btnSizeMap.get(_btnSize) : _btnSize;
29713
30080
  const btnHeight = props.height ?? btnSize;
29714
30081
  const btnWidth = props.width ?? btnSize;
29715
- const _iconSize = props.iconSize;
29716
- const hasNamedIconSize = iconSizeMap.has(_iconSize);
29717
- const iconSize = !_iconSize ? hasNamedSize ? iconSizeMap.get(_btnSize) : iconSizeMap.get('default') : hasNamedIconSize ? iconSizeMap.get(_iconSize) : _iconSize;
30082
+ const {
30083
+ iconSize
30084
+ } = useIconSizes(props, () => new Map(props.iconSizes).get(_btnSize));
29718
30085
  const iconProps = {
29719
30086
  icon,
29720
- size: iconSize,
30087
+ size: iconSize.value,
29721
30088
  iconColor: props.iconColor,
29722
30089
  opacity: props.opacity
29723
30090
  };
@@ -29760,7 +30127,7 @@
29760
30127
  "color": typeof props.loading === 'boolean' ? undefined : props.loading,
29761
30128
  "indeterminate": "disable-shrink",
29762
30129
  "width": "2",
29763
- "size": iconSize
30130
+ "size": iconSize.value
29764
30131
  }, null)])]
29765
30132
  });
29766
30133
  });
@@ -31203,6 +31570,7 @@
31203
31570
  VClassIcon: VClassIcon,
31204
31571
  VCode: VCode,
31205
31572
  VCol: VCol,
31573
+ VColorInput: VColorInput,
31206
31574
  VColorPicker: VColorPicker,
31207
31575
  VCombobox: VCombobox,
31208
31576
  VComponentIcon: VComponentIcon,
@@ -31669,7 +32037,7 @@
31669
32037
  };
31670
32038
  });
31671
32039
  }
31672
- const version$1 = "3.8.4-master.2025-05-12";
32040
+ const version$1 = "3.8.5-dev.2025-05-14";
31673
32041
  createVuetify$1.version = version$1;
31674
32042
 
31675
32043
  // Vue's inject() can only be used in setup
@@ -31967,7 +32335,7 @@
31967
32335
 
31968
32336
  /* eslint-disable local-rules/sort-imports */
31969
32337
 
31970
- const version = "3.8.4-master.2025-05-12";
32338
+ const version = "3.8.5-dev.2025-05-14";
31971
32339
 
31972
32340
  /* eslint-disable local-rules/sort-imports */
31973
32341