@vuetify/nightly 3.9.0-dev.2025-07-15 → 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 (45) hide show
  1. package/CHANGELOG.md +9 -3
  2. package/dist/json/attributes.json +3261 -3241
  3. package/dist/json/importMap-labs.json +24 -24
  4. package/dist/json/importMap.json +202 -202
  5. package/dist/json/tags.json +5 -0
  6. package/dist/json/web-types.json +6129 -6059
  7. package/dist/vuetify-labs.cjs +204 -25
  8. package/dist/vuetify-labs.css +4800 -4798
  9. package/dist/vuetify-labs.d.ts +129 -67
  10. package/dist/vuetify-labs.esm.js +204 -25
  11. package/dist/vuetify-labs.esm.js.map +1 -1
  12. package/dist/vuetify-labs.js +204 -25
  13. package/dist/vuetify-labs.min.css +2 -2
  14. package/dist/vuetify.cjs +166 -16
  15. package/dist/vuetify.cjs.map +1 -1
  16. package/dist/vuetify.css +3987 -3985
  17. package/dist/vuetify.d.ts +119 -67
  18. package/dist/vuetify.esm.js +166 -16
  19. package/dist/vuetify.esm.js.map +1 -1
  20. package/dist/vuetify.js +166 -16
  21. package/dist/vuetify.js.map +1 -1
  22. package/dist/vuetify.min.css +2 -2
  23. package/dist/vuetify.min.js +710 -688
  24. package/dist/vuetify.min.js.map +1 -1
  25. package/lib/components/VFileInput/VFileInput.d.ts +15 -0
  26. package/lib/components/VFileInput/VFileInput.js +38 -9
  27. package/lib/components/VFileInput/VFileInput.js.map +1 -1
  28. package/lib/components/VProgressLinear/VProgressLinear.css +1 -1
  29. package/lib/components/VProgressLinear/VProgressLinear.d.ts +75 -0
  30. package/lib/components/VProgressLinear/VProgressLinear.js +32 -6
  31. package/lib/components/VProgressLinear/VProgressLinear.js.map +1 -1
  32. package/lib/components/VProgressLinear/VProgressLinear.sass +2 -2
  33. package/lib/components/VProgressLinear/chunks.d.ts +55 -0
  34. package/lib/components/VProgressLinear/chunks.js +62 -0
  35. package/lib/components/VProgressLinear/chunks.js.map +1 -0
  36. package/lib/composables/fileFilter.d.ts +18 -0
  37. package/lib/composables/fileFilter.js +38 -0
  38. package/lib/composables/fileFilter.js.map +1 -0
  39. package/lib/entry-bundler.js +1 -1
  40. package/lib/framework.d.ts +67 -67
  41. package/lib/framework.js +1 -1
  42. package/lib/labs/VFileUpload/VFileUpload.d.ts +15 -0
  43. package/lib/labs/VFileUpload/VFileUpload.js +39 -9
  44. package/lib/labs/VFileUpload/VFileUpload.js.map +1 -1
  45. package/package.json +1 -1
package/dist/vuetify.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Vuetify v3.9.0-dev.2025-07-15
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"
@@ -24383,6 +24469,42 @@
24383
24469
  return item.isDirectory ? `${path}/${item.name}` : path;
24384
24470
  }
24385
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
+
24386
24508
  // Types
24387
24509
 
24388
24510
  const makeVFileInputProps = propsFactory({
@@ -24415,6 +24537,7 @@
24415
24537
  return wrapInArray(val).every(v => v != null && typeof v === 'object');
24416
24538
  }
24417
24539
  },
24540
+ ...makeFileFilterProps(),
24418
24541
  ...makeVFieldProps({
24419
24542
  clearable: true
24420
24543
  })
@@ -24427,7 +24550,8 @@
24427
24550
  'click:control': e => true,
24428
24551
  'mousedown:control': e => true,
24429
24552
  'update:focused': focused => true,
24430
- 'update:modelValue': files => true
24553
+ 'update:modelValue': files => true,
24554
+ rejected: files => true
24431
24555
  },
24432
24556
  setup(props, _ref) {
24433
24557
  let {
@@ -24438,6 +24562,9 @@
24438
24562
  const {
24439
24563
  t
24440
24564
  } = useLocale();
24565
+ const {
24566
+ filterAccepted
24567
+ } = useFileFilter(props);
24441
24568
  const model = useProxiedModel(props, 'modelValue', props.modelValue, val => wrapInArray(val), val => !props.multiple && Array.isArray(val) ? val[0] : val);
24442
24569
  const {
24443
24570
  isFocused,
@@ -24511,14 +24638,38 @@
24511
24638
  e.stopImmediatePropagation();
24512
24639
  isDragging.value = false;
24513
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) {
24514
24655
  const dataTransfer = new DataTransfer();
24515
- 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) {
24516
24664
  dataTransfer.items.add(file);
24517
24665
  }
24518
24666
  inputRef.value.files = dataTransfer.files;
24519
- inputRef.value.dispatchEvent(new Event('change', {
24667
+ model.value = [...dataTransfer.files];
24668
+ const event = new Event('change', {
24520
24669
  bubbles: true
24521
- }));
24670
+ });
24671
+ event.repack = true;
24672
+ inputRef.value.dispatchEvent(event);
24522
24673
  }
24523
24674
  vue.watch(model, newValue => {
24524
24675
  const hasModelReset = !Array.isArray(newValue) || !newValue.length;
@@ -24535,6 +24686,8 @@
24535
24686
  ...inputProps
24536
24687
  } = VInput.filterProps(props);
24537
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);
24538
24691
  return vue.createVNode(VInput, vue.mergeProps({
24539
24692
  "ref": vInputRef,
24540
24693
  "modelValue": props.multiple ? model.value : model.value[0],
@@ -24588,6 +24741,7 @@
24588
24741
  return vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("input", vue.mergeProps({
24589
24742
  "ref": inputRef,
24590
24743
  "type": "file",
24744
+ "accept": inputAccept,
24591
24745
  "readonly": isReadonly.value,
24592
24746
  "disabled": isDisabled.value,
24593
24747
  "multiple": props.multiple,
@@ -24597,11 +24751,7 @@
24597
24751
  if (isReadonly.value) e.preventDefault();
24598
24752
  onFocus();
24599
24753
  },
24600
- "onChange": e => {
24601
- if (!e.target) return;
24602
- const target = e.target;
24603
- model.value = [...(target.files ?? [])];
24604
- },
24754
+ "onChange": onFileSelection,
24605
24755
  "onDragleave": onDragleave,
24606
24756
  "onFocus": onFocus,
24607
24757
  "onBlur": blur
@@ -31396,7 +31546,7 @@
31396
31546
  };
31397
31547
  });
31398
31548
  }
31399
- const version$1 = "3.9.0-dev.2025-07-15";
31549
+ const version$1 = "3.9.0-dev.2025-07-16";
31400
31550
  createVuetify$1.version = version$1;
31401
31551
 
31402
31552
  // Vue's inject() can only be used in setup
@@ -31421,7 +31571,7 @@
31421
31571
  ...options
31422
31572
  });
31423
31573
  };
31424
- const version = "3.9.0-dev.2025-07-15";
31574
+ const version = "3.9.0-dev.2025-07-16";
31425
31575
  createVuetify.version = version;
31426
31576
 
31427
31577
  exports.blueprints = index;