@vuetify/nightly 3.9.0-dev.2025-07-08 → 3.9.0-dev.2025-07-16

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 (55) hide show
  1. package/CHANGELOG.md +14 -3
  2. package/dist/json/attributes.json +3826 -3806
  3. package/dist/json/importMap-labs.json +24 -24
  4. package/dist/json/importMap.json +168 -168
  5. package/dist/json/tags.json +5 -0
  6. package/dist/json/web-types.json +6992 -6922
  7. package/dist/vuetify-labs.cjs +216 -27
  8. package/dist/vuetify-labs.css +4659 -4657
  9. package/dist/vuetify-labs.d.ts +119 -57
  10. package/dist/vuetify-labs.esm.js +216 -27
  11. package/dist/vuetify-labs.esm.js.map +1 -1
  12. package/dist/vuetify-labs.js +216 -27
  13. package/dist/vuetify-labs.min.css +2 -2
  14. package/dist/vuetify.cjs +178 -18
  15. package/dist/vuetify.cjs.map +1 -1
  16. package/dist/vuetify.css +4036 -4034
  17. package/dist/vuetify.d.ts +109 -57
  18. package/dist/vuetify.esm.js +178 -18
  19. package/dist/vuetify.esm.js.map +1 -1
  20. package/dist/vuetify.js +178 -18
  21. package/dist/vuetify.js.map +1 -1
  22. package/dist/vuetify.min.css +2 -2
  23. package/dist/vuetify.min.js +718 -696
  24. package/dist/vuetify.min.js.map +1 -1
  25. package/lib/components/VAutocomplete/VAutocomplete.js +1 -0
  26. package/lib/components/VAutocomplete/VAutocomplete.js.map +1 -1
  27. package/lib/components/VCombobox/VCombobox.js +1 -0
  28. package/lib/components/VCombobox/VCombobox.js.map +1 -1
  29. package/lib/components/VFileInput/VFileInput.d.ts +15 -0
  30. package/lib/components/VFileInput/VFileInput.js +38 -9
  31. package/lib/components/VFileInput/VFileInput.js.map +1 -1
  32. package/lib/components/VList/VList.js +2 -1
  33. package/lib/components/VList/VList.js.map +1 -1
  34. package/lib/components/VList/VListItem.js +7 -1
  35. package/lib/components/VList/VListItem.js.map +1 -1
  36. package/lib/components/VProgressLinear/VProgressLinear.css +1 -1
  37. package/lib/components/VProgressLinear/VProgressLinear.d.ts +75 -0
  38. package/lib/components/VProgressLinear/VProgressLinear.js +32 -6
  39. package/lib/components/VProgressLinear/VProgressLinear.js.map +1 -1
  40. package/lib/components/VProgressLinear/VProgressLinear.sass +2 -2
  41. package/lib/components/VProgressLinear/chunks.d.ts +55 -0
  42. package/lib/components/VProgressLinear/chunks.js +62 -0
  43. package/lib/components/VProgressLinear/chunks.js.map +1 -0
  44. package/lib/components/VSelect/VSelect.js +1 -0
  45. package/lib/components/VSelect/VSelect.js.map +1 -1
  46. package/lib/composables/fileFilter.d.ts +18 -0
  47. package/lib/composables/fileFilter.js +38 -0
  48. package/lib/composables/fileFilter.js.map +1 -0
  49. package/lib/entry-bundler.js +1 -1
  50. package/lib/framework.d.ts +57 -57
  51. package/lib/framework.js +1 -1
  52. package/lib/labs/VFileUpload/VFileUpload.d.ts +15 -0
  53. package/lib/labs/VFileUpload/VFileUpload.js +39 -9
  54. package/lib/labs/VFileUpload/VFileUpload.js.map +1 -1
  55. package/package.json +1 -1
package/dist/vuetify.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Vuetify v3.9.0-dev.2025-07-08
2
+ * Vuetify v3.9.0-dev.2025-07-16
3
3
  * Forged by John Leider
4
4
  * Released under the MIT License.
5
5
  */
@@ -5468,6 +5468,69 @@
5468
5468
  };
5469
5469
  }
5470
5470
 
5471
+ // Utilities
5472
+
5473
+ // Types
5474
+
5475
+ // Composables
5476
+ const makeChunksProps = propsFactory({
5477
+ chunkCount: {
5478
+ type: [Number, String],
5479
+ default: null
5480
+ },
5481
+ chunkWidth: {
5482
+ type: [Number, String],
5483
+ default: null
5484
+ },
5485
+ chunkGap: {
5486
+ type: [Number, String],
5487
+ default: 4
5488
+ }
5489
+ }, 'chunks');
5490
+ function useChunks(props, containerWidth) {
5491
+ const hasChunks = vue.toRef(() => !!props.chunkCount || !!props.chunkWidth);
5492
+ const chunkWidth = vue.computed(() => {
5493
+ const containerSize = vue.toValue(containerWidth);
5494
+ if (!containerSize) {
5495
+ return 0;
5496
+ }
5497
+ if (!props.chunkCount) {
5498
+ return Number(props.chunkWidth);
5499
+ }
5500
+ const count = Number(props.chunkCount);
5501
+ const availableWidth = containerSize - Number(props.chunkGap) * (count - 1);
5502
+ return availableWidth / count;
5503
+ });
5504
+ const chunkGap = vue.toRef(() => Number(props.chunkGap));
5505
+ const chunksMaskStyles = vue.computed(() => {
5506
+ if (!hasChunks.value) {
5507
+ return {};
5508
+ }
5509
+ const chunkGapPx = convertToUnit(chunkGap.value);
5510
+ const chunkWidthPx = convertToUnit(chunkWidth.value);
5511
+ return {
5512
+ maskRepeat: 'repeat-x',
5513
+ maskImage: `linear-gradient(90deg, #000, #000 ${chunkWidthPx}, transparent ${chunkWidthPx}, transparent)`,
5514
+ maskSize: `calc(${chunkWidthPx} + ${chunkGapPx}) 100%`
5515
+ };
5516
+ });
5517
+ function snapValueToChunk(val) {
5518
+ const containerSize = vue.toValue(containerWidth);
5519
+ if (!containerSize) {
5520
+ return val;
5521
+ }
5522
+ const gapRelativeSize = 100 * chunkGap.value / containerSize;
5523
+ const chunkRelativeSize = 100 * (chunkWidth.value + chunkGap.value) / containerSize;
5524
+ const filledChunks = Math.floor((val + gapRelativeSize) / chunkRelativeSize);
5525
+ return clamp(0, filledChunks * chunkRelativeSize - gapRelativeSize / 2, 100);
5526
+ }
5527
+ return {
5528
+ hasChunks,
5529
+ chunksMaskStyles,
5530
+ snapValueToChunk
5531
+ };
5532
+ }
5533
+
5471
5534
  const makeVProgressLinearProps = propsFactory({
5472
5535
  absolute: Boolean,
5473
5536
  active: {
@@ -5502,6 +5565,7 @@
5502
5565
  stream: Boolean,
5503
5566
  striped: Boolean,
5504
5567
  roundedBar: Boolean,
5568
+ ...makeChunksProps(),
5505
5569
  ...makeComponentProps(),
5506
5570
  ...makeLocationProps({
5507
5571
  location: 'top'
@@ -5520,6 +5584,7 @@
5520
5584
  let {
5521
5585
  slots
5522
5586
  } = _ref;
5587
+ const root = vue.ref();
5523
5588
  const progress = useProxiedModel(props, 'modelValue');
5524
5589
  const {
5525
5590
  isRtl,
@@ -5561,6 +5626,24 @@
5561
5626
  const isReversed = vue.computed(() => isRtl.value !== props.reverse);
5562
5627
  const transition = vue.computed(() => props.indeterminate ? 'fade-transition' : 'slide-x-transition');
5563
5628
  const isForcedColorsModeActive = IN_BROWSER && window.matchMedia?.('(forced-colors: active)').matches;
5629
+ const containerWidth = vue.shallowRef(0);
5630
+ const {
5631
+ hasChunks,
5632
+ chunksMaskStyles,
5633
+ snapValueToChunk
5634
+ } = useChunks(props, containerWidth);
5635
+ useToggleScope(hasChunks, () => {
5636
+ const {
5637
+ resizeRef
5638
+ } = useResizeObserver(entries => containerWidth.value = entries[0].contentRect.width);
5639
+ vue.watchEffect(() => resizeRef.value = root.value);
5640
+ });
5641
+ const bufferWidth = vue.computed(() => {
5642
+ return hasChunks.value ? snapValueToChunk(normalizedBuffer.value) : normalizedBuffer.value;
5643
+ });
5644
+ const barWidth = vue.computed(() => {
5645
+ return hasChunks.value ? snapValueToChunk(normalizedValue.value) : normalizedValue.value;
5646
+ });
5564
5647
  function handleClick(e) {
5565
5648
  if (!intersectionRef.value) return;
5566
5649
  const {
@@ -5571,8 +5654,11 @@
5571
5654
  const value = isReversed.value ? width - e.clientX + (right - width) : e.clientX - left;
5572
5655
  progress.value = Math.round(value / width * max.value);
5573
5656
  }
5657
+ vue.watchEffect(() => {
5658
+ intersectionRef.value = root.value;
5659
+ });
5574
5660
  useRender(() => vue.createVNode(props.tag, {
5575
- "ref": intersectionRef,
5661
+ "ref": root,
5576
5662
  "class": vue.normalizeClass(['v-progress-linear', {
5577
5663
  'v-progress-linear--absolute': props.absolute,
5578
5664
  'v-progress-linear--active': props.active && isIntersecting.value,
@@ -5587,7 +5673,7 @@
5587
5673
  height: props.active ? convertToUnit(height.value) : 0,
5588
5674
  '--v-progress-linear-height': convertToUnit(height.value),
5589
5675
  ...(props.absolute ? locationStyles.value : {})
5590
- }, props.style]),
5676
+ }, chunksMaskStyles.value, props.style]),
5591
5677
  "role": "progressbar",
5592
5678
  "aria-hidden": props.active ? 'false' : 'true',
5593
5679
  "aria-valuemin": "0",
@@ -5617,7 +5703,7 @@
5617
5703
  "class": vue.normalizeClass(['v-progress-linear__buffer', !isForcedColorsModeActive ? bufferColorClasses.value : undefined]),
5618
5704
  "style": vue.normalizeStyle([bufferColorStyles.value, {
5619
5705
  opacity: parseFloat(props.bufferOpacity),
5620
- width: convertToUnit(normalizedBuffer.value, '%')
5706
+ width: convertToUnit(bufferWidth.value, '%')
5621
5707
  }])
5622
5708
  }, null), vue.createVNode(vue.Transition, {
5623
5709
  "name": transition.value
@@ -5625,7 +5711,7 @@
5625
5711
  default: () => [!props.indeterminate ? vue.createElementVNode("div", {
5626
5712
  "class": vue.normalizeClass(['v-progress-linear__determinate', !isForcedColorsModeActive ? barColorClasses.value : undefined]),
5627
5713
  "style": vue.normalizeStyle([barColorStyles.value, {
5628
- width: convertToUnit(normalizedValue.value, '%')
5714
+ width: convertToUnit(barWidth.value, '%')
5629
5715
  }])
5630
5716
  }, null) : vue.createElementVNode("div", {
5631
5717
  "class": "v-progress-linear__indeterminate"
@@ -9840,6 +9926,11 @@
9840
9926
  const isLink = vue.toRef(() => props.link !== false && link.isLink.value);
9841
9927
  const isSelectable = vue.computed(() => !!list && (root.selectable.value || root.activatable.value || props.value != null));
9842
9928
  const isClickable = vue.computed(() => !props.disabled && props.link !== false && (props.link || link.isClickable.value || isSelectable.value));
9929
+ const role = vue.computed(() => list ? isSelectable.value ? 'option' : 'listitem' : undefined);
9930
+ const ariaSelected = vue.computed(() => {
9931
+ if (!isSelectable.value) return undefined;
9932
+ return root.activatable.value ? isActivated.value : root.selectable.value ? isSelected.value : isActive.value;
9933
+ });
9843
9934
  const roundedProps = vue.toRef(() => props.rounded || props.nav);
9844
9935
  const color = vue.toRef(() => props.color ?? props.activeColor);
9845
9936
  const variantProps = vue.toRef(() => ({
@@ -9943,7 +10034,8 @@
9943
10034
  }, themeClasses.value, borderClasses.value, colorClasses.value, densityClasses.value, elevationClasses.value, lineClasses.value, roundedClasses.value, variantClasses.value, props.class],
9944
10035
  "style": [colorStyles.value, dimensionStyles.value, props.style],
9945
10036
  "tabindex": isClickable.value ? list ? -2 : 0 : undefined,
9946
- "aria-selected": isSelectable.value ? root.activatable.value ? isActivated.value : root.selectable.value ? isSelected.value : isActive.value : undefined,
10037
+ "aria-selected": ariaSelected.value,
10038
+ "role": role.value,
9947
10039
  "onClick": onClick,
9948
10040
  "onKeydown": isClickable.value && !isLink.value && onKeyDown
9949
10041
  }, link.linkProps), {
@@ -10435,6 +10527,7 @@
10435
10527
  const activeColor = vue.toRef(() => props.activeColor);
10436
10528
  const baseColor = vue.toRef(() => props.baseColor);
10437
10529
  const color = vue.toRef(() => props.color);
10530
+ const isSelectable = vue.toRef(() => props.selectable || props.activatable);
10438
10531
  createList({
10439
10532
  filterable: props.filterable
10440
10533
  });
@@ -10504,7 +10597,7 @@
10504
10597
  }, themeClasses.value, backgroundColorClasses.value, borderClasses.value, densityClasses.value, elevationClasses.value, lineClasses.value, roundedClasses.value, props.class]),
10505
10598
  "style": vue.normalizeStyle([backgroundColorStyles.value, dimensionStyles.value, props.style]),
10506
10599
  "tabindex": props.disabled ? -1 : 0,
10507
- "role": "listbox",
10600
+ "role": isSelectable.value ? 'listbox' : 'list',
10508
10601
  "aria-activedescendant": undefined,
10509
10602
  "onFocusin": onFocusin,
10510
10603
  "onFocusout": onFocusout,
@@ -13569,6 +13662,7 @@
13569
13662
  "onKeydown": onListKeydown,
13570
13663
  "onFocusin": onFocusin,
13571
13664
  "tabindex": "-1",
13665
+ "selectable": true,
13572
13666
  "aria-live": "polite",
13573
13667
  "aria-label": `${props.label}-list`,
13574
13668
  "color": props.itemColor ?? props.color
@@ -14188,6 +14282,7 @@
14188
14282
  "onFocusin": onFocusin,
14189
14283
  "onFocusout": onFocusout,
14190
14284
  "tabindex": "-1",
14285
+ "selectable": true,
14191
14286
  "aria-live": "polite",
14192
14287
  "color": props.itemColor ?? props.color
14193
14288
  }, listEvents, props.listProps), {
@@ -19275,6 +19370,7 @@
19275
19370
  "selected": selectedValues.value,
19276
19371
  "selectStrategy": props.multiple ? 'independent' : 'single-independent',
19277
19372
  "onMousedown": e => e.preventDefault(),
19373
+ "selectable": true,
19278
19374
  "onKeydown": onListKeydown,
19279
19375
  "onFocusin": onFocusin,
19280
19376
  "onFocusout": onFocusout,
@@ -24373,6 +24469,42 @@
24373
24469
  return item.isDirectory ? `${path}/${item.name}` : path;
24374
24470
  }
24375
24471
 
24472
+ // Utilities
24473
+ // Composables
24474
+ const makeFileFilterProps = propsFactory({
24475
+ filterByType: String
24476
+ }, 'file-accept');
24477
+ function useFileFilter(props) {
24478
+ const fileFilter = vue.computed(() => props.filterByType ? createFilter(props.filterByType) : null);
24479
+ function filterAccepted(files) {
24480
+ if (fileFilter.value) {
24481
+ const accepted = files.filter(fileFilter.value);
24482
+ return {
24483
+ accepted,
24484
+ rejected: files.filter(f => !accepted.includes(f))
24485
+ };
24486
+ }
24487
+ return {
24488
+ accepted: files,
24489
+ rejected: []
24490
+ };
24491
+ }
24492
+ return {
24493
+ filterAccepted
24494
+ };
24495
+ }
24496
+ function createFilter(v) {
24497
+ const types = v.split(',').map(x => x.trim().toLowerCase());
24498
+ const extensionsToMatch = types.filter(x => x.startsWith('.'));
24499
+ const wildcards = types.filter(x => x.endsWith('/*'));
24500
+ const typesToMatch = types.filter(x => !extensionsToMatch.includes(x) && !wildcards.includes(x));
24501
+ return file => {
24502
+ const extension = file.name.split('.').at(-1)?.toLowerCase() ?? '';
24503
+ const typeGroup = file.type.split('/').at(0)?.toLowerCase() ?? '';
24504
+ return typesToMatch.includes(file.type) || extensionsToMatch.includes(`.${extension}`) || wildcards.includes(`${typeGroup}/*`);
24505
+ };
24506
+ }
24507
+
24376
24508
  // Types
24377
24509
 
24378
24510
  const makeVFileInputProps = propsFactory({
@@ -24405,6 +24537,7 @@
24405
24537
  return wrapInArray(val).every(v => v != null && typeof v === 'object');
24406
24538
  }
24407
24539
  },
24540
+ ...makeFileFilterProps(),
24408
24541
  ...makeVFieldProps({
24409
24542
  clearable: true
24410
24543
  })
@@ -24417,7 +24550,8 @@
24417
24550
  'click:control': e => true,
24418
24551
  'mousedown:control': e => true,
24419
24552
  'update:focused': focused => true,
24420
- 'update:modelValue': files => true
24553
+ 'update:modelValue': files => true,
24554
+ rejected: files => true
24421
24555
  },
24422
24556
  setup(props, _ref) {
24423
24557
  let {
@@ -24428,6 +24562,9 @@
24428
24562
  const {
24429
24563
  t
24430
24564
  } = useLocale();
24565
+ const {
24566
+ filterAccepted
24567
+ } = useFileFilter(props);
24431
24568
  const model = useProxiedModel(props, 'modelValue', props.modelValue, val => wrapInArray(val), val => !props.multiple && Array.isArray(val) ? val[0] : val);
24432
24569
  const {
24433
24570
  isFocused,
@@ -24501,14 +24638,38 @@
24501
24638
  e.stopImmediatePropagation();
24502
24639
  isDragging.value = false;
24503
24640
  if (!inputRef.value || !hasFilesOrFolders(e)) return;
24641
+ const allDroppedFiles = await handleDrop(e);
24642
+ selectAccepted(allDroppedFiles);
24643
+ }
24644
+ function onFileSelection(e) {
24645
+ if (!e.target || e.repack) return; // prevent loop
24646
+
24647
+ if (!props.filterByType) {
24648
+ const target = e.target;
24649
+ model.value = [...(target.files ?? [])];
24650
+ } else {
24651
+ selectAccepted([...e.target.files]);
24652
+ }
24653
+ }
24654
+ function selectAccepted(files) {
24504
24655
  const dataTransfer = new DataTransfer();
24505
- for (const file of await handleDrop(e)) {
24656
+ const {
24657
+ accepted,
24658
+ rejected
24659
+ } = filterAccepted(files);
24660
+ if (rejected.length) {
24661
+ emit('rejected', rejected);
24662
+ }
24663
+ for (const file of accepted) {
24506
24664
  dataTransfer.items.add(file);
24507
24665
  }
24508
24666
  inputRef.value.files = dataTransfer.files;
24509
- inputRef.value.dispatchEvent(new Event('change', {
24667
+ model.value = [...dataTransfer.files];
24668
+ const event = new Event('change', {
24510
24669
  bubbles: true
24511
- }));
24670
+ });
24671
+ event.repack = true;
24672
+ inputRef.value.dispatchEvent(event);
24512
24673
  }
24513
24674
  vue.watch(model, newValue => {
24514
24675
  const hasModelReset = !Array.isArray(newValue) || !newValue.length;
@@ -24525,6 +24686,8 @@
24525
24686
  ...inputProps
24526
24687
  } = VInput.filterProps(props);
24527
24688
  const fieldProps = VField.filterProps(props);
24689
+ const expectsDirectory = attrs.webkitdirectory !== undefined && attrs.webkitdirectory !== false;
24690
+ const inputAccept = expectsDirectory ? undefined : props.filterByType ?? String(attrs.accept);
24528
24691
  return vue.createVNode(VInput, vue.mergeProps({
24529
24692
  "ref": vInputRef,
24530
24693
  "modelValue": props.multiple ? model.value : model.value[0],
@@ -24578,6 +24741,7 @@
24578
24741
  return vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("input", vue.mergeProps({
24579
24742
  "ref": inputRef,
24580
24743
  "type": "file",
24744
+ "accept": inputAccept,
24581
24745
  "readonly": isReadonly.value,
24582
24746
  "disabled": isDisabled.value,
24583
24747
  "multiple": props.multiple,
@@ -24587,11 +24751,7 @@
24587
24751
  if (isReadonly.value) e.preventDefault();
24588
24752
  onFocus();
24589
24753
  },
24590
- "onChange": e => {
24591
- if (!e.target) return;
24592
- const target = e.target;
24593
- model.value = [...(target.files ?? [])];
24594
- },
24754
+ "onChange": onFileSelection,
24595
24755
  "onDragleave": onDragleave,
24596
24756
  "onFocus": onFocus,
24597
24757
  "onBlur": blur
@@ -31386,7 +31546,7 @@
31386
31546
  };
31387
31547
  });
31388
31548
  }
31389
- const version$1 = "3.9.0-dev.2025-07-08";
31549
+ const version$1 = "3.9.0-dev.2025-07-16";
31390
31550
  createVuetify$1.version = version$1;
31391
31551
 
31392
31552
  // Vue's inject() can only be used in setup
@@ -31411,7 +31571,7 @@
31411
31571
  ...options
31412
31572
  });
31413
31573
  };
31414
- const version = "3.9.0-dev.2025-07-08";
31574
+ const version = "3.9.0-dev.2025-07-16";
31415
31575
  createVuetify.version = version;
31416
31576
 
31417
31577
  exports.blueprints = index;