@vuetify/nightly 3.8.4-master.2025-05-13 → 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 +17 -21
  2. package/dist/_component-variables-labs.sass +1 -0
  3. package/dist/json/attributes.json +3625 -3273
  4. package/dist/json/importMap-labs.json +32 -28
  5. package/dist/json/importMap.json +180 -180
  6. package/dist/json/tags.json +93 -0
  7. package/dist/json/web-types.json +7373 -6147
  8. package/dist/vuetify-labs.cjs +424 -130
  9. package/dist/vuetify-labs.css +4754 -4698
  10. package/dist/vuetify-labs.d.ts +2285 -1171
  11. package/dist/vuetify-labs.esm.js +425 -131
  12. package/dist/vuetify-labs.esm.js.map +1 -1
  13. package/dist/vuetify-labs.js +424 -130
  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 +2697 -2644
  18. package/dist/vuetify.d.ts +568 -511
  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 +75 -67
  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 +115 -118
  90. package/lib/labs/VDateInput/VDateInput.js +38 -79
  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-13
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,11 +29186,240 @@
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({
29082
29422
  displayFormat: [Function, String],
29083
- inputFormat: [Function, String],
29084
29423
  location: {
29085
29424
  type: String,
29086
29425
  default: 'bottom start'
@@ -29090,6 +29429,7 @@
29090
29429
  type: Array,
29091
29430
  default: () => ['blur', 'enter']
29092
29431
  },
29432
+ ...makeDateFormatProps(),
29093
29433
  ...makeDisplayProps({
29094
29434
  mobile: null
29095
29435
  }),
@@ -29098,7 +29438,6 @@
29098
29438
  hideActions: true
29099
29439
  }),
29100
29440
  ...makeVTextFieldProps({
29101
- placeholder: 'mm/dd/yyyy',
29102
29441
  prependIcon: '$calendar'
29103
29442
  }),
29104
29443
  ...omit(makeVDatePickerProps({
@@ -29121,9 +29460,16 @@
29121
29460
  slots
29122
29461
  } = _ref;
29123
29462
  const {
29124
- t
29463
+ t,
29464
+ current: currentLocale
29125
29465
  } = useLocale();
29126
29466
  const adapter = useDate();
29467
+ const {
29468
+ isValid,
29469
+ parseDate,
29470
+ formatDate,
29471
+ parserFormat
29472
+ } = useDateFormat(props, currentLocale);
29127
29473
  const {
29128
29474
  mobile
29129
29475
  } = useDisplay(props);
@@ -29142,80 +29488,10 @@
29142
29488
  if (typeof props.displayFormat === 'function') {
29143
29489
  return props.displayFormat(date);
29144
29490
  }
29145
- return adapter.format(date, props.displayFormat ?? 'keyboardDate');
29146
- }
29147
- function parseDateString(dateString, format) {
29148
- function countConsecutiveChars(str, startIndex) {
29149
- const char = str[startIndex];
29150
- let count = 0;
29151
- while (str[startIndex + count] === char) count++;
29152
- return count;
29153
- }
29154
- function parseDateParts(dateString, format) {
29155
- const dateParts = {};
29156
- let stringIndex = 0;
29157
- const upperFormat = format.toUpperCase();
29158
- for (let formatIndex = 0; formatIndex < upperFormat.length;) {
29159
- const formatChar = upperFormat[formatIndex];
29160
- const charCount = countConsecutiveChars(upperFormat, formatIndex);
29161
- const dateValue = dateString.slice(stringIndex, stringIndex + charCount);
29162
- if (['Y', 'M', 'D'].includes(formatChar)) {
29163
- const numValue = parseInt(dateValue);
29164
- if (isNaN(numValue)) return null;
29165
- dateParts[formatChar] = numValue;
29166
- }
29167
- formatIndex += charCount;
29168
- stringIndex += charCount;
29169
- }
29170
- return dateParts;
29171
- }
29172
- function validateDateParts(dateParts) {
29173
- const {
29174
- Y: year,
29175
- M: month,
29176
- D: day
29177
- } = dateParts;
29178
- if (!year || !month || !day) return null;
29179
- if (month < 1 || month > 12) return null;
29180
- if (day < 1 || day > 31) return null;
29181
- return {
29182
- year,
29183
- month,
29184
- day
29185
- };
29491
+ if (props.displayFormat) {
29492
+ return adapter.format(date, props.displayFormat ?? 'keyboardDate');
29186
29493
  }
29187
- const dateParts = parseDateParts(dateString, format);
29188
- if (!dateParts) return null;
29189
- const validatedParts = validateDateParts(dateParts);
29190
- if (!validatedParts) return null;
29191
- const {
29192
- year,
29193
- month,
29194
- day
29195
- } = validatedParts;
29196
- return {
29197
- year,
29198
- month,
29199
- day
29200
- };
29201
- }
29202
- function parseUserInput(value) {
29203
- if (typeof props.inputFormat === 'function') {
29204
- return props.inputFormat(value);
29205
- }
29206
- if (typeof props.inputFormat === 'string') {
29207
- const formattedDate = parseDateString(value, props.inputFormat);
29208
- if (!formattedDate) {
29209
- return model.value;
29210
- }
29211
- const {
29212
- year,
29213
- month,
29214
- day
29215
- } = formattedDate;
29216
- return adapter.parseISO(`${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`);
29217
- }
29218
- return adapter.isValid(value) ? adapter.date(value) : model.value;
29494
+ return formatDate(date);
29219
29495
  }
29220
29496
  const display = vue.computed(() => {
29221
29497
  const value = wrapInArray(model.value);
@@ -29293,12 +29569,32 @@
29293
29569
  let {
29294
29570
  value
29295
29571
  } = _ref2;
29296
- model.value = !value ? emptyModelValue() : parseUserInput(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))];
29297
29593
  }
29298
29594
  useRender(() => {
29299
29595
  const confirmEditProps = VConfirmEdit.filterProps(props);
29300
29596
  const datePickerProps = VDatePicker.filterProps(omit(props, ['active', 'location', 'rounded']));
29301
- const textFieldProps = VTextField.filterProps(props);
29597
+ const textFieldProps = VTextField.filterProps(omit(props, ['placeholder']));
29302
29598
  return vue.createVNode(VTextField, vue.mergeProps({
29303
29599
  "ref": vTextFieldRef
29304
29600
  }, textFieldProps, {
@@ -29306,11 +29602,13 @@
29306
29602
  "style": props.style,
29307
29603
  "modelValue": display.value,
29308
29604
  "inputmode": inputmode.value,
29605
+ "placeholder": props.placeholder ?? parserFormat.value,
29309
29606
  "readonly": isReadonly.value,
29310
29607
  "onKeydown": isInteractive.value ? onKeydown : undefined,
29311
29608
  "focused": menu.value || isFocused.value,
29312
29609
  "onFocus": focus,
29313
29610
  "onBlur": onBlur,
29611
+ "validationValue": model.value,
29314
29612
  "onClick:control": isInteractive.value ? onClick : undefined,
29315
29613
  "onClick:prepend": isInteractive.value ? onClick : undefined,
29316
29614
  "onUpdate:modelValue": onUpdateDisplayModel
@@ -29696,11 +29994,6 @@
29696
29994
  hideOverlay: Boolean,
29697
29995
  icon: [String, Function, Object],
29698
29996
  iconColor: String,
29699
- iconSize: [Number, String],
29700
- iconSizes: {
29701
- type: Array,
29702
- default: () => [['x-small', 10], ['small', 16], ['default', 24], ['large', 28], ['x-large', 32]]
29703
- },
29704
29997
  loading: Boolean,
29705
29998
  opacity: [Number, String],
29706
29999
  readonly: Boolean,
@@ -29720,6 +30013,7 @@
29720
30013
  ...makeBorderProps(),
29721
30014
  ...makeComponentProps(),
29722
30015
  ...makeElevationProps(),
30016
+ ...makeIconSizeProps(),
29723
30017
  ...makeRoundedProps(),
29724
30018
  ...makeTagProps({
29725
30019
  tag: 'button'
@@ -29774,7 +30068,6 @@
29774
30068
  })()
29775
30069
  }));
29776
30070
  const btnSizeMap = new Map(props.sizes);
29777
- const iconSizeMap = new Map(props.iconSizes);
29778
30071
  function onClick() {
29779
30072
  if (props.disabled || props.readonly || isActive.value === undefined || props.tag === 'a' && attrs.href) return;
29780
30073
  isActive.value = !isActive.value;
@@ -29786,12 +30079,12 @@
29786
30079
  const btnSize = hasNamedSize ? btnSizeMap.get(_btnSize) : _btnSize;
29787
30080
  const btnHeight = props.height ?? btnSize;
29788
30081
  const btnWidth = props.width ?? btnSize;
29789
- const _iconSize = props.iconSize;
29790
- const hasNamedIconSize = iconSizeMap.has(_iconSize);
29791
- 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));
29792
30085
  const iconProps = {
29793
30086
  icon,
29794
- size: iconSize,
30087
+ size: iconSize.value,
29795
30088
  iconColor: props.iconColor,
29796
30089
  opacity: props.opacity
29797
30090
  };
@@ -29834,7 +30127,7 @@
29834
30127
  "color": typeof props.loading === 'boolean' ? undefined : props.loading,
29835
30128
  "indeterminate": "disable-shrink",
29836
30129
  "width": "2",
29837
- "size": iconSize
30130
+ "size": iconSize.value
29838
30131
  }, null)])]
29839
30132
  });
29840
30133
  });
@@ -31277,6 +31570,7 @@
31277
31570
  VClassIcon: VClassIcon,
31278
31571
  VCode: VCode,
31279
31572
  VCol: VCol,
31573
+ VColorInput: VColorInput,
31280
31574
  VColorPicker: VColorPicker,
31281
31575
  VCombobox: VCombobox,
31282
31576
  VComponentIcon: VComponentIcon,
@@ -31743,7 +32037,7 @@
31743
32037
  };
31744
32038
  });
31745
32039
  }
31746
- const version$1 = "3.8.4-master.2025-05-13";
32040
+ const version$1 = "3.8.5-dev.2025-05-14";
31747
32041
  createVuetify$1.version = version$1;
31748
32042
 
31749
32043
  // Vue's inject() can only be used in setup
@@ -32041,7 +32335,7 @@
32041
32335
 
32042
32336
  /* eslint-disable local-rules/sort-imports */
32043
32337
 
32044
- const version = "3.8.4-master.2025-05-13";
32338
+ const version = "3.8.5-dev.2025-05-14";
32045
32339
 
32046
32340
  /* eslint-disable local-rules/sort-imports */
32047
32341