@vuetify/nightly 3.9.1-master.2025-07-17 → 3.9.2-dev.2025-07-18

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 (61) hide show
  1. package/CHANGELOG.md +11 -5
  2. package/dist/json/attributes.json +3550 -3530
  3. package/dist/json/importMap-labs.json +12 -12
  4. package/dist/json/importMap.json +180 -180
  5. package/dist/json/tags.json +5 -0
  6. package/dist/json/web-types.json +20050 -6602
  7. package/dist/vuetify-labs.cjs +277 -89
  8. package/dist/vuetify-labs.css +4411 -4409
  9. package/dist/vuetify-labs.d.ts +124 -62
  10. package/dist/vuetify-labs.esm.js +277 -89
  11. package/dist/vuetify-labs.esm.js.map +1 -1
  12. package/dist/vuetify-labs.js +277 -89
  13. package/dist/vuetify-labs.min.css +2 -2
  14. package/dist/vuetify.cjs +239 -80
  15. package/dist/vuetify.cjs.map +1 -1
  16. package/dist/vuetify.css +2666 -2664
  17. package/dist/vuetify.d.ts +114 -62
  18. package/dist/vuetify.esm.js +239 -80
  19. package/dist/vuetify.esm.js.map +1 -1
  20. package/dist/vuetify.js +239 -80
  21. package/dist/vuetify.js.map +1 -1
  22. package/dist/vuetify.min.css +2 -2
  23. package/dist/vuetify.min.js +724 -702
  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/components/VTreeview/VTreeview.js +2 -3
  47. package/lib/components/VTreeview/VTreeview.js.map +1 -1
  48. package/lib/components/VTreeview/VTreeviewChildren.js +59 -59
  49. package/lib/components/VTreeview/VTreeviewChildren.js.map +1 -1
  50. package/lib/composables/fileFilter.d.ts +18 -0
  51. package/lib/composables/fileFilter.js +38 -0
  52. package/lib/composables/fileFilter.js.map +1 -0
  53. package/lib/entry-bundler.js +1 -1
  54. package/lib/entry-bundler.js.map +1 -1
  55. package/lib/framework.d.ts +62 -62
  56. package/lib/framework.js +1 -1
  57. package/lib/framework.js.map +1 -1
  58. package/lib/labs/VFileUpload/VFileUpload.d.ts +15 -0
  59. package/lib/labs/VFileUpload/VFileUpload.js +39 -9
  60. package/lib/labs/VFileUpload/VFileUpload.js.map +1 -1
  61. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Vuetify v3.9.1-master.2025-07-17
2
+ * Vuetify v3.9.2-dev.2025-07-18
3
3
  * Forged by John Leider
4
4
  * Released under the MIT License.
5
5
  */
@@ -5169,6 +5169,69 @@
5169
5169
  };
5170
5170
  }
5171
5171
 
5172
+ // Utilities
5173
+
5174
+ // Types
5175
+
5176
+ // Composables
5177
+ const makeChunksProps = propsFactory({
5178
+ chunkCount: {
5179
+ type: [Number, String],
5180
+ default: null
5181
+ },
5182
+ chunkWidth: {
5183
+ type: [Number, String],
5184
+ default: null
5185
+ },
5186
+ chunkGap: {
5187
+ type: [Number, String],
5188
+ default: 4
5189
+ }
5190
+ }, 'chunks');
5191
+ function useChunks(props, containerWidth) {
5192
+ const hasChunks = vue.toRef(() => !!props.chunkCount || !!props.chunkWidth);
5193
+ const chunkWidth = vue.computed(() => {
5194
+ const containerSize = vue.toValue(containerWidth);
5195
+ if (!containerSize) {
5196
+ return 0;
5197
+ }
5198
+ if (!props.chunkCount) {
5199
+ return Number(props.chunkWidth);
5200
+ }
5201
+ const count = Number(props.chunkCount);
5202
+ const availableWidth = containerSize - Number(props.chunkGap) * (count - 1);
5203
+ return availableWidth / count;
5204
+ });
5205
+ const chunkGap = vue.toRef(() => Number(props.chunkGap));
5206
+ const chunksMaskStyles = vue.computed(() => {
5207
+ if (!hasChunks.value) {
5208
+ return {};
5209
+ }
5210
+ const chunkGapPx = convertToUnit(chunkGap.value);
5211
+ const chunkWidthPx = convertToUnit(chunkWidth.value);
5212
+ return {
5213
+ maskRepeat: 'repeat-x',
5214
+ maskImage: `linear-gradient(90deg, #000, #000 ${chunkWidthPx}, transparent ${chunkWidthPx}, transparent)`,
5215
+ maskSize: `calc(${chunkWidthPx} + ${chunkGapPx}) 100%`
5216
+ };
5217
+ });
5218
+ function snapValueToChunk(val) {
5219
+ const containerSize = vue.toValue(containerWidth);
5220
+ if (!containerSize) {
5221
+ return val;
5222
+ }
5223
+ const gapRelativeSize = 100 * chunkGap.value / containerSize;
5224
+ const chunkRelativeSize = 100 * (chunkWidth.value + chunkGap.value) / containerSize;
5225
+ const filledChunks = Math.floor((val + gapRelativeSize) / chunkRelativeSize);
5226
+ return clamp(0, filledChunks * chunkRelativeSize - gapRelativeSize / 2, 100);
5227
+ }
5228
+ return {
5229
+ hasChunks,
5230
+ chunksMaskStyles,
5231
+ snapValueToChunk
5232
+ };
5233
+ }
5234
+
5172
5235
  const makeVProgressLinearProps = propsFactory({
5173
5236
  absolute: Boolean,
5174
5237
  active: {
@@ -5203,6 +5266,7 @@
5203
5266
  stream: Boolean,
5204
5267
  striped: Boolean,
5205
5268
  roundedBar: Boolean,
5269
+ ...makeChunksProps(),
5206
5270
  ...makeComponentProps(),
5207
5271
  ...makeLocationProps({
5208
5272
  location: 'top'
@@ -5221,6 +5285,7 @@
5221
5285
  let {
5222
5286
  slots
5223
5287
  } = _ref;
5288
+ const root = vue.ref();
5224
5289
  const progress = useProxiedModel(props, 'modelValue');
5225
5290
  const {
5226
5291
  isRtl,
@@ -5262,6 +5327,24 @@
5262
5327
  const isReversed = vue.computed(() => isRtl.value !== props.reverse);
5263
5328
  const transition = vue.computed(() => props.indeterminate ? 'fade-transition' : 'slide-x-transition');
5264
5329
  const isForcedColorsModeActive = IN_BROWSER && window.matchMedia?.('(forced-colors: active)').matches;
5330
+ const containerWidth = vue.shallowRef(0);
5331
+ const {
5332
+ hasChunks,
5333
+ chunksMaskStyles,
5334
+ snapValueToChunk
5335
+ } = useChunks(props, containerWidth);
5336
+ useToggleScope(hasChunks, () => {
5337
+ const {
5338
+ resizeRef
5339
+ } = useResizeObserver(entries => containerWidth.value = entries[0].contentRect.width);
5340
+ vue.watchEffect(() => resizeRef.value = root.value);
5341
+ });
5342
+ const bufferWidth = vue.computed(() => {
5343
+ return hasChunks.value ? snapValueToChunk(normalizedBuffer.value) : normalizedBuffer.value;
5344
+ });
5345
+ const barWidth = vue.computed(() => {
5346
+ return hasChunks.value ? snapValueToChunk(normalizedValue.value) : normalizedValue.value;
5347
+ });
5265
5348
  function handleClick(e) {
5266
5349
  if (!intersectionRef.value) return;
5267
5350
  const {
@@ -5272,8 +5355,11 @@
5272
5355
  const value = isReversed.value ? width - e.clientX + (right - width) : e.clientX - left;
5273
5356
  progress.value = Math.round(value / width * max.value);
5274
5357
  }
5358
+ vue.watchEffect(() => {
5359
+ intersectionRef.value = root.value;
5360
+ });
5275
5361
  useRender(() => vue.createVNode(props.tag, {
5276
- "ref": intersectionRef,
5362
+ "ref": root,
5277
5363
  "class": vue.normalizeClass(['v-progress-linear', {
5278
5364
  'v-progress-linear--absolute': props.absolute,
5279
5365
  'v-progress-linear--active': props.active && isIntersecting.value,
@@ -5288,7 +5374,7 @@
5288
5374
  height: props.active ? convertToUnit(height.value) : 0,
5289
5375
  '--v-progress-linear-height': convertToUnit(height.value),
5290
5376
  ...(props.absolute ? locationStyles.value : {})
5291
- }, props.style]),
5377
+ }, chunksMaskStyles.value, props.style]),
5292
5378
  "role": "progressbar",
5293
5379
  "aria-hidden": props.active ? 'false' : 'true',
5294
5380
  "aria-valuemin": "0",
@@ -5318,7 +5404,7 @@
5318
5404
  "class": vue.normalizeClass(['v-progress-linear__buffer', !isForcedColorsModeActive ? bufferColorClasses.value : undefined]),
5319
5405
  "style": vue.normalizeStyle([bufferColorStyles.value, {
5320
5406
  opacity: parseFloat(props.bufferOpacity),
5321
- width: convertToUnit(normalizedBuffer.value, '%')
5407
+ width: convertToUnit(bufferWidth.value, '%')
5322
5408
  }])
5323
5409
  }, null), vue.createVNode(vue.Transition, {
5324
5410
  "name": transition.value
@@ -5326,7 +5412,7 @@
5326
5412
  default: () => [!props.indeterminate ? vue.createElementVNode("div", {
5327
5413
  "class": vue.normalizeClass(['v-progress-linear__determinate', !isForcedColorsModeActive ? barColorClasses.value : undefined]),
5328
5414
  "style": vue.normalizeStyle([barColorStyles.value, {
5329
- width: convertToUnit(normalizedValue.value, '%')
5415
+ width: convertToUnit(barWidth.value, '%')
5330
5416
  }])
5331
5417
  }, null) : vue.createElementVNode("div", {
5332
5418
  "class": "v-progress-linear__indeterminate"
@@ -9544,6 +9630,11 @@
9544
9630
  const isLink = vue.toRef(() => props.link !== false && link.isLink.value);
9545
9631
  const isSelectable = vue.computed(() => !!list && (root.selectable.value || root.activatable.value || props.value != null));
9546
9632
  const isClickable = vue.computed(() => !props.disabled && props.link !== false && (props.link || link.isClickable.value || isSelectable.value));
9633
+ const role = vue.computed(() => list ? isSelectable.value ? 'option' : 'listitem' : undefined);
9634
+ const ariaSelected = vue.computed(() => {
9635
+ if (!isSelectable.value) return undefined;
9636
+ return root.activatable.value ? isActivated.value : root.selectable.value ? isSelected.value : isActive.value;
9637
+ });
9547
9638
  const roundedProps = vue.toRef(() => props.rounded || props.nav);
9548
9639
  const color = vue.toRef(() => props.color ?? props.activeColor);
9549
9640
  const variantProps = vue.toRef(() => ({
@@ -9647,7 +9738,8 @@
9647
9738
  }, themeClasses.value, borderClasses.value, colorClasses.value, densityClasses.value, elevationClasses.value, lineClasses.value, roundedClasses.value, variantClasses.value, props.class],
9648
9739
  "style": [colorStyles.value, dimensionStyles.value, props.style],
9649
9740
  "tabindex": isClickable.value ? list ? -2 : 0 : undefined,
9650
- "aria-selected": isSelectable.value ? root.activatable.value ? isActivated.value : root.selectable.value ? isSelected.value : isActive.value : undefined,
9741
+ "aria-selected": ariaSelected.value,
9742
+ "role": role.value,
9651
9743
  "onClick": onClick,
9652
9744
  "onKeydown": isClickable.value && !isLink.value && onKeyDown
9653
9745
  }, link.linkProps), {
@@ -10149,6 +10241,7 @@
10149
10241
  const activeColor = vue.toRef(() => props.activeColor);
10150
10242
  const baseColor = vue.toRef(() => props.baseColor);
10151
10243
  const color = vue.toRef(() => props.color);
10244
+ const isSelectable = vue.toRef(() => props.selectable || props.activatable);
10152
10245
  createList({
10153
10246
  filterable: props.filterable
10154
10247
  });
@@ -10220,7 +10313,7 @@
10220
10313
  }, themeClasses.value, backgroundColorClasses.value, borderClasses.value, densityClasses.value, elevationClasses.value, lineClasses.value, roundedClasses.value, props.class]),
10221
10314
  "style": vue.normalizeStyle([backgroundColorStyles.value, dimensionStyles.value, props.style]),
10222
10315
  "tabindex": props.disabled ? -1 : 0,
10223
- "role": "listbox",
10316
+ "role": isSelectable.value ? 'listbox' : 'list',
10224
10317
  "aria-activedescendant": undefined,
10225
10318
  "onFocusin": onFocusin,
10226
10319
  "onFocusout": onFocusout,
@@ -13290,6 +13383,7 @@
13290
13383
  "onKeydown": onListKeydown,
13291
13384
  "onFocusin": onFocusin,
13292
13385
  "tabindex": "-1",
13386
+ "selectable": true,
13293
13387
  "aria-live": "polite",
13294
13388
  "aria-label": `${props.label}-list`,
13295
13389
  "color": props.itemColor ?? props.color
@@ -13909,6 +14003,7 @@
13909
14003
  "onFocusin": onFocusin,
13910
14004
  "onFocusout": onFocusout,
13911
14005
  "tabindex": "-1",
14006
+ "selectable": true,
13912
14007
  "aria-live": "polite",
13913
14008
  "color": props.itemColor ?? props.color
13914
14009
  }, listEvents, props.listProps), {
@@ -18996,6 +19091,7 @@
18996
19091
  "selected": selectedValues.value,
18997
19092
  "selectStrategy": props.multiple ? 'independent' : 'single-independent',
18998
19093
  "onMousedown": e => e.preventDefault(),
19094
+ "selectable": true,
18999
19095
  "onKeydown": onListKeydown,
19000
19096
  "onFocusin": onFocusin,
19001
19097
  "onFocusout": onFocusout,
@@ -24094,6 +24190,42 @@
24094
24190
  return item.isDirectory ? `${path}/${item.name}` : path;
24095
24191
  }
24096
24192
 
24193
+ // Utilities
24194
+ // Composables
24195
+ const makeFileFilterProps = propsFactory({
24196
+ filterByType: String
24197
+ }, 'file-accept');
24198
+ function useFileFilter(props) {
24199
+ const fileFilter = vue.computed(() => props.filterByType ? createFilter(props.filterByType) : null);
24200
+ function filterAccepted(files) {
24201
+ if (fileFilter.value) {
24202
+ const accepted = files.filter(fileFilter.value);
24203
+ return {
24204
+ accepted,
24205
+ rejected: files.filter(f => !accepted.includes(f))
24206
+ };
24207
+ }
24208
+ return {
24209
+ accepted: files,
24210
+ rejected: []
24211
+ };
24212
+ }
24213
+ return {
24214
+ filterAccepted
24215
+ };
24216
+ }
24217
+ function createFilter(v) {
24218
+ const types = v.split(',').map(x => x.trim().toLowerCase());
24219
+ const extensionsToMatch = types.filter(x => x.startsWith('.'));
24220
+ const wildcards = types.filter(x => x.endsWith('/*'));
24221
+ const typesToMatch = types.filter(x => !extensionsToMatch.includes(x) && !wildcards.includes(x));
24222
+ return file => {
24223
+ const extension = file.name.split('.').at(-1)?.toLowerCase() ?? '';
24224
+ const typeGroup = file.type.split('/').at(0)?.toLowerCase() ?? '';
24225
+ return typesToMatch.includes(file.type) || extensionsToMatch.includes(`.${extension}`) || wildcards.includes(`${typeGroup}/*`);
24226
+ };
24227
+ }
24228
+
24097
24229
  // Types
24098
24230
 
24099
24231
  const makeVFileInputProps = propsFactory({
@@ -24126,6 +24258,7 @@
24126
24258
  return wrapInArray(val).every(v => v != null && typeof v === 'object');
24127
24259
  }
24128
24260
  },
24261
+ ...makeFileFilterProps(),
24129
24262
  ...makeVFieldProps({
24130
24263
  clearable: true
24131
24264
  })
@@ -24138,7 +24271,8 @@
24138
24271
  'click:control': e => true,
24139
24272
  'mousedown:control': e => true,
24140
24273
  'update:focused': focused => true,
24141
- 'update:modelValue': files => true
24274
+ 'update:modelValue': files => true,
24275
+ rejected: files => true
24142
24276
  },
24143
24277
  setup(props, _ref) {
24144
24278
  let {
@@ -24149,6 +24283,9 @@
24149
24283
  const {
24150
24284
  t
24151
24285
  } = useLocale();
24286
+ const {
24287
+ filterAccepted
24288
+ } = useFileFilter(props);
24152
24289
  const model = useProxiedModel(props, 'modelValue', props.modelValue, val => wrapInArray(val), val => !props.multiple && Array.isArray(val) ? val[0] : val);
24153
24290
  const {
24154
24291
  isFocused,
@@ -24222,14 +24359,38 @@
24222
24359
  e.stopImmediatePropagation();
24223
24360
  isDragging.value = false;
24224
24361
  if (!inputRef.value || !hasFilesOrFolders(e)) return;
24362
+ const allDroppedFiles = await handleDrop(e);
24363
+ selectAccepted(allDroppedFiles);
24364
+ }
24365
+ function onFileSelection(e) {
24366
+ if (!e.target || e.repack) return; // prevent loop
24367
+
24368
+ if (!props.filterByType) {
24369
+ const target = e.target;
24370
+ model.value = [...(target.files ?? [])];
24371
+ } else {
24372
+ selectAccepted([...e.target.files]);
24373
+ }
24374
+ }
24375
+ function selectAccepted(files) {
24225
24376
  const dataTransfer = new DataTransfer();
24226
- for (const file of await handleDrop(e)) {
24377
+ const {
24378
+ accepted,
24379
+ rejected
24380
+ } = filterAccepted(files);
24381
+ if (rejected.length) {
24382
+ emit('rejected', rejected);
24383
+ }
24384
+ for (const file of accepted) {
24227
24385
  dataTransfer.items.add(file);
24228
24386
  }
24229
24387
  inputRef.value.files = dataTransfer.files;
24230
- inputRef.value.dispatchEvent(new Event('change', {
24388
+ model.value = [...dataTransfer.files];
24389
+ const event = new Event('change', {
24231
24390
  bubbles: true
24232
- }));
24391
+ });
24392
+ event.repack = true;
24393
+ inputRef.value.dispatchEvent(event);
24233
24394
  }
24234
24395
  vue.watch(model, newValue => {
24235
24396
  const hasModelReset = !Array.isArray(newValue) || !newValue.length;
@@ -24246,6 +24407,8 @@
24246
24407
  ...inputProps
24247
24408
  } = VInput.filterProps(props);
24248
24409
  const fieldProps = VField.filterProps(props);
24410
+ const expectsDirectory = attrs.webkitdirectory !== undefined && attrs.webkitdirectory !== false;
24411
+ const inputAccept = expectsDirectory ? undefined : props.filterByType ?? String(attrs.accept);
24249
24412
  return vue.createVNode(VInput, vue.mergeProps({
24250
24413
  "ref": vInputRef,
24251
24414
  "modelValue": props.multiple ? model.value : model.value[0],
@@ -24301,6 +24464,7 @@
24301
24464
  return vue.createElementVNode(vue.Fragment, null, [vue.createElementVNode("input", vue.mergeProps({
24302
24465
  "ref": inputRef,
24303
24466
  "type": "file",
24467
+ "accept": inputAccept,
24304
24468
  "readonly": isReadonly.value,
24305
24469
  "disabled": isDisabled.value,
24306
24470
  "multiple": props.multiple,
@@ -24310,11 +24474,7 @@
24310
24474
  if (isReadonly.value) e.preventDefault();
24311
24475
  onFocus();
24312
24476
  },
24313
- "onChange": e => {
24314
- if (!e.target) return;
24315
- const target = e.target;
24316
- model.value = [...(target.files ?? [])];
24317
- },
24477
+ "onChange": onFileSelection,
24318
24478
  "onDragleave": onDragleave,
24319
24479
  "onFocus": onFocus,
24320
24480
  "onBlur": blur
@@ -30349,51 +30509,48 @@
30349
30509
  parentIndentLines: props.parentIndentLines,
30350
30510
  variant: props.indentLinesVariant
30351
30511
  });
30352
- function renderItem(itemProps) {
30353
- return vue.createVNode(VTreeviewItem, itemProps, {
30354
- prepend: slotProps => vue.createElementVNode(vue.Fragment, null, [props.selectable && (!children || children && !['leaf', 'single-leaf'].includes(props.selectStrategy)) && vue.createElementVNode("div", null, [vue.createVNode(VCheckboxBtn, {
30355
- "key": item.value,
30356
- "modelValue": slotProps.isSelected,
30357
- "disabled": props.disabled,
30358
- "loading": loading,
30359
- "color": props.selectedColor,
30360
- "density": props.density,
30361
- "indeterminate": slotProps.isIndeterminate,
30362
- "indeterminateIcon": props.indeterminateIcon,
30363
- "falseIcon": props.falseIcon,
30364
- "trueIcon": props.trueIcon,
30365
- "onUpdate:modelValue": v => selectItem(slotProps.select, v),
30366
- "onClick": e => e.stopPropagation(),
30367
- "onKeydown": e => {
30368
- if (!['Enter', 'Space'].includes(e.key)) return;
30369
- e.stopPropagation();
30370
- selectItem(slotProps.select, slotProps.isSelected);
30371
- }
30372
- }, null)]), slots.prepend?.({
30373
- ...slotProps,
30374
- ...treeItemProps,
30375
- item: item.raw,
30376
- internalItem: item
30377
- })]),
30378
- append: slots.append ? slotProps => slots.append?.({
30379
- ...slotProps,
30380
- ...treeItemProps,
30381
- item: item.raw,
30382
- internalItem: item
30383
- }) : undefined,
30384
- title: slots.title ? slotProps => slots.title?.({
30385
- ...slotProps,
30386
- item: item.raw,
30387
- internalItem: item
30388
- }) : undefined,
30389
- subtitle: slots.subtitle ? slotProps => slots.subtitle?.({
30390
- ...slotProps,
30391
- item: item.raw,
30392
- internalItem: item
30393
- }) : undefined,
30394
- $stable: true
30395
- });
30396
- }
30512
+ const slotsWithItem = {
30513
+ prepend: slotProps => vue.createElementVNode(vue.Fragment, null, [props.selectable && (!children || children && !['leaf', 'single-leaf'].includes(props.selectStrategy)) && vue.createElementVNode("div", null, [vue.createVNode(VCheckboxBtn, {
30514
+ "key": item.value,
30515
+ "modelValue": slotProps.isSelected,
30516
+ "disabled": props.disabled,
30517
+ "loading": loading,
30518
+ "color": props.selectedColor,
30519
+ "density": props.density,
30520
+ "indeterminate": slotProps.isIndeterminate,
30521
+ "indeterminateIcon": props.indeterminateIcon,
30522
+ "falseIcon": props.falseIcon,
30523
+ "trueIcon": props.trueIcon,
30524
+ "onUpdate:modelValue": v => selectItem(slotProps.select, v),
30525
+ "onClick": e => e.stopPropagation(),
30526
+ "onKeydown": e => {
30527
+ if (!['Enter', 'Space'].includes(e.key)) return;
30528
+ e.stopPropagation();
30529
+ selectItem(slotProps.select, slotProps.isSelected);
30530
+ }
30531
+ }, null)]), slots.prepend?.({
30532
+ ...slotProps,
30533
+ ...treeItemProps,
30534
+ item: item.raw,
30535
+ internalItem: item
30536
+ })]),
30537
+ append: slots.append ? slotProps => slots.append?.({
30538
+ ...slotProps,
30539
+ ...treeItemProps,
30540
+ item: item.raw,
30541
+ internalItem: item
30542
+ }) : undefined,
30543
+ title: slots.title ? slotProps => slots.title?.({
30544
+ ...slotProps,
30545
+ item: item.raw,
30546
+ internalItem: item
30547
+ }) : undefined,
30548
+ subtitle: slots.subtitle ? slotProps => slots.subtitle?.({
30549
+ ...slotProps,
30550
+ item: item.raw,
30551
+ internalItem: item
30552
+ }) : undefined
30553
+ };
30397
30554
  const treeviewGroupProps = VTreeviewGroup.filterProps(itemProps);
30398
30555
  const treeviewChildrenProps = VTreeviewChildren.filterProps({
30399
30556
  ...props,
@@ -30407,16 +30564,21 @@
30407
30564
  let {
30408
30565
  props: activatorProps
30409
30566
  } = _ref2;
30410
- return renderItem({
30567
+ const listItemProps = {
30411
30568
  ...itemProps,
30412
30569
  ...activatorProps,
30413
- loading,
30414
- hideActions: props.hideActions,
30415
- indentLines: indentLines.node,
30416
- value: props.returnObject ? item.raw : itemProps.value,
30570
+ value: itemProps?.value,
30417
30571
  onToggleExpand: [() => checkChildren(item), activatorProps.onClick],
30418
30572
  onClick: isClickOnOpen.value ? [() => checkChildren(item), activatorProps.onClick] : () => selectItem(activatorItems.value[index]?.select, !activatorItems.value[index]?.isSelected)
30419
- });
30573
+ };
30574
+ return vue.createVNode(VTreeviewItem, vue.mergeProps({
30575
+ "ref": el => activatorItems.value[index] = el
30576
+ }, listItemProps, {
30577
+ "hideActions": props.hideActions,
30578
+ "indentLines": indentLines.node,
30579
+ "value": props.returnObject ? item.raw : itemProps.value,
30580
+ "loading": loading
30581
+ }), slotsWithItem);
30420
30582
  },
30421
30583
  default: () => vue.createVNode(VTreeviewChildren, vue.mergeProps(treeviewChildrenProps, {
30422
30584
  "items": children,
@@ -30424,8 +30586,7 @@
30424
30586
  "parentIndentLines": indentLines.children,
30425
30587
  "isLastGroup": nextItemHasChildren,
30426
30588
  "returnObject": props.returnObject
30427
- }), slots),
30428
- $stable: true
30589
+ }), slots)
30429
30590
  }) : renderSlot(slots.item, {
30430
30591
  props: itemProps,
30431
30592
  item: item.raw,
@@ -30441,12 +30602,11 @@
30441
30602
  props: item.raw
30442
30603
  }, () => vue.createVNode(VListSubheader, item.props, null));
30443
30604
  }
30444
- return renderItem({
30445
- ...itemProps,
30446
- hideActions: props.hideActions,
30447
- indentLines: indentLines.leaf,
30448
- value: props.returnObject ? vue.toRaw(item.raw) : itemProps.value
30449
- });
30605
+ return vue.createVNode(VTreeviewItem, vue.mergeProps(itemProps, {
30606
+ "hideActions": props.hideActions,
30607
+ "indentLines": indentLines.leaf,
30608
+ "value": props.returnObject ? vue.toRaw(item.raw) : itemProps.value
30609
+ }), slotsWithItem);
30450
30610
  });
30451
30611
  });
30452
30612
  }
@@ -30585,14 +30745,13 @@
30585
30745
  "selected": selected.value,
30586
30746
  "onUpdate:selected": $event => selected.value = $event
30587
30747
  }), {
30588
- default: () => vue.createVNode(VTreeviewChildren, vue.mergeProps(treeviewChildrenProps, {
30748
+ default: () => [vue.createVNode(VTreeviewChildren, vue.mergeProps(treeviewChildrenProps, {
30589
30749
  "density": props.density,
30590
30750
  "returnObject": props.returnObject,
30591
30751
  "items": items.value,
30592
30752
  "parentIndentLines": props.indentLines ? [] : undefined,
30593
30753
  "indentLinesVariant": indentLinesVariant
30594
- }), slots),
30595
- $stable: true
30754
+ }), slots)]
30596
30755
  });
30597
30756
  });
30598
30757
  return {};
@@ -31833,6 +31992,7 @@
31833
31992
  },
31834
31993
  showSize: Boolean,
31835
31994
  name: String,
31995
+ ...makeFileFilterProps(),
31836
31996
  ...makeDelayProps(),
31837
31997
  ...makeDensityProps(),
31838
31998
  ...pick(makeVDividerProps({
@@ -31845,11 +32005,13 @@
31845
32005
  inheritAttrs: false,
31846
32006
  props: makeVFileUploadProps(),
31847
32007
  emits: {
31848
- 'update:modelValue': files => true
32008
+ 'update:modelValue': files => true,
32009
+ rejected: files => true
31849
32010
  },
31850
32011
  setup(props, _ref) {
31851
32012
  let {
31852
32013
  attrs,
32014
+ emit,
31853
32015
  slots
31854
32016
  } = _ref;
31855
32017
  const {
@@ -31858,6 +32020,9 @@
31858
32020
  const {
31859
32021
  densityClasses
31860
32022
  } = useDensity(props);
32023
+ const {
32024
+ filterAccepted
32025
+ } = useFileFilter(props);
31861
32026
  const model = useProxiedModel(props, 'modelValue', props.modelValue, val => wrapInArray(val), val => props.multiple || Array.isArray(props.modelValue) ? val : val[0]);
31862
32027
  const isDragging = vue.shallowRef(false);
31863
32028
  const vSheetRef = vue.ref(null);
@@ -31879,14 +32044,38 @@
31879
32044
  e.stopImmediatePropagation();
31880
32045
  isDragging.value = false;
31881
32046
  if (!inputRef.value) return;
32047
+ const allDroppedFiles = await handleDrop(e);
32048
+ selectAccepted(allDroppedFiles);
32049
+ }
32050
+ function onFileSelection(e) {
32051
+ if (!e.target || e.repack) return; // prevent loop
32052
+
32053
+ if (!props.filterByType) {
32054
+ const target = e.target;
32055
+ model.value = [...(target.files ?? [])];
32056
+ } else {
32057
+ selectAccepted([...e.target.files]);
32058
+ }
32059
+ }
32060
+ function selectAccepted(files) {
31882
32061
  const dataTransfer = new DataTransfer();
31883
- for (const file of await handleDrop(e)) {
32062
+ const {
32063
+ accepted,
32064
+ rejected
32065
+ } = filterAccepted(files);
32066
+ if (rejected.length) {
32067
+ emit('rejected', rejected);
32068
+ }
32069
+ for (const file of accepted) {
31884
32070
  dataTransfer.items.add(file);
31885
32071
  }
31886
32072
  inputRef.value.files = dataTransfer.files;
31887
- inputRef.value.dispatchEvent(new Event('change', {
32073
+ model.value = [...dataTransfer.files];
32074
+ const event = new Event('change', {
31888
32075
  bubbles: true
31889
- }));
32076
+ });
32077
+ event.repack = true;
32078
+ inputRef.value.dispatchEvent(event);
31890
32079
  }
31891
32080
  function onClick() {
31892
32081
  inputRef.value?.click();
@@ -31904,17 +32093,16 @@
31904
32093
  const cardProps = VSheet.filterProps(props);
31905
32094
  const dividerProps = VDivider.filterProps(props);
31906
32095
  const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
32096
+ const expectsDirectory = attrs.webkitdirectory !== undefined && attrs.webkitdirectory !== false;
32097
+ const inputAccept = expectsDirectory ? undefined : props.filterByType ?? String(attrs.accept);
31907
32098
  const inputNode = vue.createElementVNode("input", vue.mergeProps({
31908
32099
  "ref": inputRef,
31909
32100
  "type": "file",
32101
+ "accept": inputAccept,
31910
32102
  "disabled": props.disabled,
31911
32103
  "multiple": props.multiple,
31912
32104
  "name": props.name,
31913
- "onChange": e => {
31914
- if (!e.target) return;
31915
- const target = e.target;
31916
- model.value = [...(target.files ?? [])];
31917
- }
32105
+ "onChange": onFileSelection
31918
32106
  }, inputAttrs), null);
31919
32107
  return vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VSheet, vue.mergeProps({
31920
32108
  "ref": vSheetRef
@@ -33693,7 +33881,7 @@
33693
33881
  };
33694
33882
  });
33695
33883
  }
33696
- const version$1 = "3.9.1-master.2025-07-17";
33884
+ const version$1 = "3.9.2-dev.2025-07-18";
33697
33885
  createVuetify$1.version = version$1;
33698
33886
 
33699
33887
  // Vue's inject() can only be used in setup
@@ -33991,7 +34179,7 @@
33991
34179
 
33992
34180
  /* eslint-disable local-rules/sort-imports */
33993
34181
 
33994
- const version = "3.9.1-master.2025-07-17";
34182
+ const version = "3.9.2-dev.2025-07-18";
33995
34183
 
33996
34184
  /* eslint-disable local-rules/sort-imports */
33997
34185