@vuetify/nightly 3.9.2-master.2025-07-22 → 3.9.2-master.2025-07-24

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 (237) hide show
  1. package/CHANGELOG.md +32 -3
  2. package/dist/_component-variables-labs.sass +2 -1
  3. package/dist/json/attributes.json +3014 -2750
  4. package/dist/json/importMap-labs.json +34 -22
  5. package/dist/json/importMap.json +168 -168
  6. package/dist/json/tags.json +81 -0
  7. package/dist/json/web-types.json +6647 -5536
  8. package/dist/vuetify-labs.cjs +765 -23
  9. package/dist/vuetify-labs.css +4300 -3958
  10. package/dist/vuetify-labs.d.ts +6519 -844
  11. package/dist/vuetify-labs.esm.js +766 -24
  12. package/dist/vuetify-labs.esm.js.map +1 -1
  13. package/dist/vuetify-labs.js +765 -23
  14. package/dist/vuetify-labs.min.css +2 -2
  15. package/dist/vuetify.cjs +50 -16
  16. package/dist/vuetify.cjs.map +1 -1
  17. package/dist/vuetify.css +5769 -5762
  18. package/dist/vuetify.d.ts +96 -82
  19. package/dist/vuetify.esm.js +50 -16
  20. package/dist/vuetify.esm.js.map +1 -1
  21. package/dist/vuetify.js +50 -16
  22. package/dist/vuetify.js.map +1 -1
  23. package/dist/vuetify.min.css +2 -2
  24. package/dist/vuetify.min.js +276 -274
  25. package/dist/vuetify.min.js.map +1 -1
  26. package/lib/components/VBottomSheet/VBottomSheet.d.ts +6 -6
  27. package/lib/components/VCarousel/VCarousel.d.ts +7 -13
  28. package/lib/components/VCarousel/VCarousel.js.map +1 -1
  29. package/lib/components/VColorPicker/VColorPicker.css +1 -0
  30. package/lib/components/VColorPicker/VColorPicker.sass +1 -0
  31. package/lib/components/VDataTable/VDataTableHeaders.js +0 -1
  32. package/lib/components/VDataTable/VDataTableHeaders.js.map +1 -1
  33. package/lib/components/VDialog/VDialog.d.ts +6 -6
  34. package/lib/components/VFileInput/VFileInput.css +3 -0
  35. package/lib/components/VFileInput/VFileInput.sass +3 -0
  36. package/lib/components/VOverlay/VOverlay.js +1 -0
  37. package/lib/components/VOverlay/VOverlay.js.map +1 -1
  38. package/lib/components/VOverlay/scrollStrategies.d.ts +1 -0
  39. package/lib/components/VOverlay/scrollStrategies.js +6 -4
  40. package/lib/components/VOverlay/scrollStrategies.js.map +1 -1
  41. package/lib/components/VProgressLinear/VProgressLinear.css +4 -1
  42. package/lib/components/VProgressLinear/VProgressLinear.js +2 -1
  43. package/lib/components/VProgressLinear/VProgressLinear.js.map +1 -1
  44. package/lib/components/VProgressLinear/VProgressLinear.sass +5 -2
  45. package/lib/components/VRangeSlider/VRangeSlider.d.ts +13 -0
  46. package/lib/components/VSlider/VSlider.d.ts +13 -0
  47. package/lib/components/VSlider/VSlider.js +3 -1
  48. package/lib/components/VSlider/VSlider.js.map +1 -1
  49. package/lib/components/VSlider/VSliderThumb.d.ts +13 -0
  50. package/lib/components/VSlider/VSliderThumb.js +2 -0
  51. package/lib/components/VSlider/VSliderThumb.js.map +1 -1
  52. package/lib/components/VSlider/slider.d.ts +6 -0
  53. package/lib/components/VSlider/slider.js +2 -0
  54. package/lib/components/VSlider/slider.js.map +1 -1
  55. package/lib/components/VTextField/VTextField.js +2 -2
  56. package/lib/components/VTextField/VTextField.js.map +1 -1
  57. package/lib/components/VTreeview/VTreeview.d.ts +7 -7
  58. package/lib/components/VTreeview/VTreeview.js +0 -1
  59. package/lib/components/VTreeview/VTreeview.js.map +1 -1
  60. package/lib/components/VTreeview/VTreeviewChildren.d.ts +13 -0
  61. package/lib/components/VTreeview/VTreeviewChildren.js +2 -1
  62. package/lib/components/VTreeview/VTreeviewChildren.js.map +1 -1
  63. package/lib/components/index.js +1 -1
  64. package/lib/components/index.js.map +1 -1
  65. package/lib/composables/date/adapters/vuetify.js +8 -2
  66. package/lib/composables/date/adapters/vuetify.js.map +1 -1
  67. package/lib/entry-bundler.js +1 -1
  68. package/lib/framework.d.ts +59 -55
  69. package/lib/framework.js +1 -1
  70. package/lib/iconsets/fa.js +9 -1
  71. package/lib/iconsets/fa.js.map +1 -1
  72. package/lib/iconsets/fa4.js +9 -1
  73. package/lib/iconsets/fa4.js.map +1 -1
  74. package/lib/iconsets/md.js +9 -1
  75. package/lib/iconsets/md.js.map +1 -1
  76. package/lib/iconsets/mdi-svg.js +9 -1
  77. package/lib/iconsets/mdi-svg.js.map +1 -1
  78. package/lib/iconsets/mdi.js +9 -1
  79. package/lib/iconsets/mdi.js.map +1 -1
  80. package/lib/labs/VFileUpload/VFileUploadItem.js +1 -1
  81. package/lib/labs/VFileUpload/VFileUploadItem.js.map +1 -1
  82. package/lib/labs/VStepperVertical/VStepperVerticalItem.css +1 -0
  83. package/lib/labs/VStepperVertical/VStepperVerticalItem.sass +1 -0
  84. package/lib/labs/VVideo/VVideo.css +319 -0
  85. package/lib/labs/VVideo/VVideo.d.ts +6932 -0
  86. package/lib/labs/VVideo/VVideo.js +424 -0
  87. package/lib/labs/VVideo/VVideo.js.map +1 -0
  88. package/lib/labs/VVideo/VVideo.sass +301 -0
  89. package/lib/labs/VVideo/VVideoControls.d.ts +3524 -0
  90. package/lib/labs/VVideo/VVideoControls.js +232 -0
  91. package/lib/labs/VVideo/VVideoControls.js.map +1 -0
  92. package/lib/labs/VVideo/VVideoVolume.d.ts +3088 -0
  93. package/lib/labs/VVideo/VVideoVolume.js +90 -0
  94. package/lib/labs/VVideo/VVideoVolume.js.map +1 -0
  95. package/lib/labs/VVideo/_variables.scss +58 -0
  96. package/lib/labs/VVideo/index.d.ts +3 -0
  97. package/lib/labs/VVideo/index.js +4 -0
  98. package/lib/labs/VVideo/index.js.map +1 -0
  99. package/lib/labs/components.d.ts +1 -0
  100. package/lib/labs/components.js +1 -0
  101. package/lib/labs/components.js.map +1 -1
  102. package/lib/locale/af.d.ts +11 -0
  103. package/lib/locale/af.js +11 -0
  104. package/lib/locale/af.js.map +1 -1
  105. package/lib/locale/ar.d.ts +11 -0
  106. package/lib/locale/ar.js +11 -0
  107. package/lib/locale/ar.js.map +1 -1
  108. package/lib/locale/az.d.ts +11 -0
  109. package/lib/locale/az.js +11 -0
  110. package/lib/locale/az.js.map +1 -1
  111. package/lib/locale/bg.d.ts +11 -0
  112. package/lib/locale/bg.js +11 -0
  113. package/lib/locale/bg.js.map +1 -1
  114. package/lib/locale/ca.d.ts +11 -0
  115. package/lib/locale/ca.js +11 -0
  116. package/lib/locale/ca.js.map +1 -1
  117. package/lib/locale/ckb.d.ts +11 -0
  118. package/lib/locale/ckb.js +11 -0
  119. package/lib/locale/ckb.js.map +1 -1
  120. package/lib/locale/cs.d.ts +11 -0
  121. package/lib/locale/cs.js +11 -0
  122. package/lib/locale/cs.js.map +1 -1
  123. package/lib/locale/da.d.ts +11 -0
  124. package/lib/locale/da.js +11 -0
  125. package/lib/locale/da.js.map +1 -1
  126. package/lib/locale/de.d.ts +11 -0
  127. package/lib/locale/de.js +11 -0
  128. package/lib/locale/de.js.map +1 -1
  129. package/lib/locale/el.d.ts +11 -0
  130. package/lib/locale/el.js +11 -0
  131. package/lib/locale/el.js.map +1 -1
  132. package/lib/locale/en.d.ts +11 -0
  133. package/lib/locale/en.js +11 -0
  134. package/lib/locale/en.js.map +1 -1
  135. package/lib/locale/es.d.ts +11 -0
  136. package/lib/locale/es.js +11 -0
  137. package/lib/locale/es.js.map +1 -1
  138. package/lib/locale/et.d.ts +11 -0
  139. package/lib/locale/et.js +11 -0
  140. package/lib/locale/et.js.map +1 -1
  141. package/lib/locale/fa.d.ts +11 -0
  142. package/lib/locale/fa.js +11 -0
  143. package/lib/locale/fa.js.map +1 -1
  144. package/lib/locale/fi.d.ts +11 -0
  145. package/lib/locale/fi.js +11 -0
  146. package/lib/locale/fi.js.map +1 -1
  147. package/lib/locale/fr.d.ts +11 -0
  148. package/lib/locale/fr.js +11 -0
  149. package/lib/locale/fr.js.map +1 -1
  150. package/lib/locale/he.d.ts +11 -0
  151. package/lib/locale/he.js +11 -0
  152. package/lib/locale/he.js.map +1 -1
  153. package/lib/locale/hr.d.ts +11 -0
  154. package/lib/locale/hr.js +11 -0
  155. package/lib/locale/hr.js.map +1 -1
  156. package/lib/locale/hu.d.ts +11 -0
  157. package/lib/locale/hu.js +11 -0
  158. package/lib/locale/hu.js.map +1 -1
  159. package/lib/locale/id.d.ts +11 -0
  160. package/lib/locale/id.js +11 -0
  161. package/lib/locale/id.js.map +1 -1
  162. package/lib/locale/it.d.ts +11 -0
  163. package/lib/locale/it.js +11 -0
  164. package/lib/locale/it.js.map +1 -1
  165. package/lib/locale/ja.d.ts +11 -0
  166. package/lib/locale/ja.js +11 -0
  167. package/lib/locale/ja.js.map +1 -1
  168. package/lib/locale/km.d.ts +11 -0
  169. package/lib/locale/km.js +11 -0
  170. package/lib/locale/km.js.map +1 -1
  171. package/lib/locale/ko.d.ts +11 -0
  172. package/lib/locale/ko.js +11 -0
  173. package/lib/locale/ko.js.map +1 -1
  174. package/lib/locale/lt.d.ts +11 -0
  175. package/lib/locale/lt.js +11 -0
  176. package/lib/locale/lt.js.map +1 -1
  177. package/lib/locale/lv.d.ts +11 -0
  178. package/lib/locale/lv.js +11 -0
  179. package/lib/locale/lv.js.map +1 -1
  180. package/lib/locale/nl.d.ts +11 -0
  181. package/lib/locale/nl.js +11 -0
  182. package/lib/locale/nl.js.map +1 -1
  183. package/lib/locale/no.d.ts +11 -0
  184. package/lib/locale/no.js +11 -0
  185. package/lib/locale/no.js.map +1 -1
  186. package/lib/locale/pl.d.ts +11 -0
  187. package/lib/locale/pl.js +11 -0
  188. package/lib/locale/pl.js.map +1 -1
  189. package/lib/locale/pt.d.ts +11 -0
  190. package/lib/locale/pt.js +11 -0
  191. package/lib/locale/pt.js.map +1 -1
  192. package/lib/locale/ro.d.ts +11 -0
  193. package/lib/locale/ro.js +11 -0
  194. package/lib/locale/ro.js.map +1 -1
  195. package/lib/locale/ru.d.ts +11 -0
  196. package/lib/locale/ru.js +11 -0
  197. package/lib/locale/ru.js.map +1 -1
  198. package/lib/locale/sk.d.ts +11 -0
  199. package/lib/locale/sk.js +11 -0
  200. package/lib/locale/sk.js.map +1 -1
  201. package/lib/locale/sl.d.ts +11 -0
  202. package/lib/locale/sl.js +11 -0
  203. package/lib/locale/sl.js.map +1 -1
  204. package/lib/locale/sr-Cyrl.d.ts +11 -0
  205. package/lib/locale/sr-Cyrl.js +11 -0
  206. package/lib/locale/sr-Cyrl.js.map +1 -1
  207. package/lib/locale/sr-Latn.d.ts +11 -0
  208. package/lib/locale/sr-Latn.js +11 -0
  209. package/lib/locale/sr-Latn.js.map +1 -1
  210. package/lib/locale/sv.d.ts +11 -0
  211. package/lib/locale/sv.js +11 -0
  212. package/lib/locale/sv.js.map +1 -1
  213. package/lib/locale/th.d.ts +11 -0
  214. package/lib/locale/th.js +11 -0
  215. package/lib/locale/th.js.map +1 -1
  216. package/lib/locale/tr.d.ts +11 -0
  217. package/lib/locale/tr.js +11 -0
  218. package/lib/locale/tr.js.map +1 -1
  219. package/lib/locale/uk.d.ts +11 -0
  220. package/lib/locale/uk.js +11 -0
  221. package/lib/locale/uk.js.map +1 -1
  222. package/lib/locale/vi.d.ts +11 -0
  223. package/lib/locale/vi.js +11 -0
  224. package/lib/locale/vi.js.map +1 -1
  225. package/lib/locale/zh-Hans.d.ts +11 -0
  226. package/lib/locale/zh-Hans.js +11 -0
  227. package/lib/locale/zh-Hans.js.map +1 -1
  228. package/lib/locale/zh-Hant.d.ts +11 -0
  229. package/lib/locale/zh-Hant.js +11 -0
  230. package/lib/locale/zh-Hant.js.map +1 -1
  231. package/lib/util/index.d.ts +1 -0
  232. package/lib/util/index.js +1 -0
  233. package/lib/util/index.js.map +1 -1
  234. package/lib/util/timeUtils.d.ts +1 -0
  235. package/lib/util/timeUtils.js +4 -0
  236. package/lib/util/timeUtils.js.map +1 -0
  237. package/package.json +1 -1
@@ -1,10 +1,10 @@
1
1
  /*!
2
- * Vuetify v3.9.2-master.2025-07-22
2
+ * Vuetify v3.9.2-master.2025-07-24
3
3
  * Forged by John Leider
4
4
  * Released under the MIT License.
5
5
  */
6
6
 
7
- import { shallowRef, reactive, watchEffect, toRef, capitalize, unref, Fragment, camelize, isVNode, Comment, warn, getCurrentInstance as getCurrentInstance$1, ref, computed, provide, inject as inject$1, defineComponent as defineComponent$1, h, onBeforeUnmount, watch, readonly, onMounted, useId, onDeactivated, onActivated, onScopeDispose, effectScope, toRaw, getCurrentScope, createElementVNode, normalizeStyle, normalizeClass, createVNode, TransitionGroup, Transition, mergeProps, toRefs, toValue, isRef, onBeforeMount, nextTick, withDirectives, vShow, onUpdated, Text, resolveDynamicComponent, toDisplayString, markRaw, Teleport, cloneVNode, createTextVNode, normalizeProps, guardReactiveProps, onUnmounted, onBeforeUpdate, withModifiers, vModelText, resolveComponent, render } from 'vue';
7
+ import { shallowRef, reactive, watchEffect, toRef, capitalize, unref, Fragment, camelize, isVNode, Comment, warn, getCurrentInstance as getCurrentInstance$1, ref, computed, provide, inject as inject$1, defineComponent as defineComponent$1, h, onBeforeUnmount, watch, readonly, onMounted, useId, onDeactivated, onActivated, onScopeDispose, effectScope, toRaw, getCurrentScope, createElementVNode, normalizeStyle, normalizeClass, createVNode, TransitionGroup, Transition, mergeProps, toRefs, toValue, isRef, onBeforeMount, nextTick, withDirectives, vShow, onUpdated, Text, resolveDynamicComponent, toDisplayString, markRaw, Teleport, cloneVNode, createTextVNode, normalizeProps, guardReactiveProps, onUnmounted, onBeforeUpdate, withModifiers, vModelText, resolveDirective, resolveComponent, render } from 'vue';
8
8
 
9
9
  // Types
10
10
  // eslint-disable-line vue/prefer-import-from-vue
@@ -1656,6 +1656,10 @@ function useRender(render) {
1656
1656
  vm.render = render;
1657
1657
  }
1658
1658
 
1659
+ function formatTime(seconds) {
1660
+ return [Math.floor(seconds % 60), Math.floor(seconds / 60 % 60), Math.floor(seconds / 60 / 60 % 60)].filter((x, i) => i < 2 || x > 0).reverse().map(String).map((x, i) => i > 0 ? x.padStart(2, '0') : x).join(':');
1661
+ }
1662
+
1659
1663
  // Utilities
1660
1664
 
1661
1665
  // Types
@@ -2176,6 +2180,17 @@ var en = {
2176
2180
  option: 'Option',
2177
2181
  plus: 'plus',
2178
2182
  shortcut: 'Keyboard shortcut: {0}'
2183
+ },
2184
+ video: {
2185
+ play: 'Play',
2186
+ pause: 'Pause',
2187
+ seek: 'Seek',
2188
+ volume: 'Volume',
2189
+ showVolume: 'Show volume control',
2190
+ mute: 'Mute',
2191
+ unmute: 'Unmute',
2192
+ enterFullscreen: 'Full screen',
2193
+ exitFullscreen: 'Exit full screen'
2179
2194
  }
2180
2195
  };
2181
2196
 
@@ -4258,7 +4273,7 @@ function useDensity(props) {
4258
4273
 
4259
4274
  // Types
4260
4275
 
4261
- const allowedVariants$2 = ['elevated', 'flat', 'tonal', 'outlined', 'text', 'plain'];
4276
+ const allowedVariants$4 = ['elevated', 'flat', 'tonal', 'outlined', 'text', 'plain'];
4262
4277
  function genOverlays(isClickable, name) {
4263
4278
  return createElementVNode(Fragment, null, [isClickable && createElementVNode("span", {
4264
4279
  "key": "overlay",
@@ -4273,7 +4288,7 @@ const makeVariantProps = propsFactory({
4273
4288
  variant: {
4274
4289
  type: String,
4275
4290
  default: 'elevated',
4276
- validator: v => allowedVariants$2.includes(v)
4291
+ validator: v => allowedVariants$4.includes(v)
4277
4292
  }
4278
4293
  }, 'variant');
4279
4294
  function useVariant(props) {
@@ -4697,7 +4712,15 @@ const aliases = {
4697
4712
  arrowdown: 'mdi-arrow-down',
4698
4713
  arrowleft: 'mdi-arrow-left',
4699
4714
  arrowright: 'mdi-arrow-right',
4700
- backspace: 'mdi-backspace'
4715
+ backspace: 'mdi-backspace',
4716
+ play: 'mdi-play',
4717
+ pause: 'mdi-pause',
4718
+ fullscreen: 'mdi-fullscreen',
4719
+ fullscreenExit: 'mdi-fullscreen-exit',
4720
+ volumeHigh: 'mdi-volume-high',
4721
+ volumeMedium: 'mdi-volume-medium',
4722
+ volumeLow: 'mdi-volume-low',
4723
+ volumeOff: 'mdi-volume-variant-off'
4701
4724
  };
4702
4725
  const mdi = {
4703
4726
  // Not using mergeProps here, functional components merge props by default (?)
@@ -5276,7 +5299,8 @@ const VProgressLinear = genericComponent()({
5276
5299
  'v-progress-linear--reverse': isReversed.value,
5277
5300
  'v-progress-linear--rounded': props.rounded,
5278
5301
  'v-progress-linear--rounded-bar': props.roundedBar,
5279
- 'v-progress-linear--striped': props.striped
5302
+ 'v-progress-linear--striped': props.striped,
5303
+ 'v-progress-linear--clickable': props.clickable
5280
5304
  }, roundedClasses.value, themeClasses.value, rtlClasses.value, props.class]),
5281
5305
  "style": normalizeStyle([{
5282
5306
  bottom: props.location === 'bottom' ? 0 : undefined,
@@ -10826,11 +10850,12 @@ function closeScrollStrategy(data) {
10826
10850
  function onScroll(e) {
10827
10851
  data.isActive.value = false;
10828
10852
  }
10829
- bindScroll(data.targetEl.value ?? data.contentEl.value, onScroll);
10853
+ bindScroll(data.target.value ?? data.contentEl.value, onScroll);
10830
10854
  }
10831
10855
  function blockScrollStrategy(data, props) {
10832
10856
  const offsetParent = data.root.value?.offsetParent;
10833
- const scrollElements = [...new Set([...getScrollParents(data.targetEl.value, props.contained ? offsetParent : undefined), ...getScrollParents(data.contentEl.value, props.contained ? offsetParent : undefined)])].filter(el => !el.classList.contains('v-overlay-scroll-blocked'));
10857
+ const target = Array.isArray(data.target.value) ? document.elementFromPoint(...data.target.value) : data.target.value;
10858
+ const scrollElements = [...new Set([...getScrollParents(target, props.contained ? offsetParent : undefined), ...getScrollParents(data.contentEl.value, props.contained ? offsetParent : undefined)])].filter(el => !el.classList.contains('v-overlay-scroll-blocked'));
10834
10859
  const scrollbarWidth = window.innerWidth - document.documentElement.offsetWidth;
10835
10860
  const scrollableParent = (el => hasScrollbar(el) && el)(offsetParent || document.documentElement);
10836
10861
  if (scrollableParent) {
@@ -10877,7 +10902,7 @@ function repositionScrollStrategy(data, props, scope) {
10877
10902
  }
10878
10903
  ric = (typeof requestIdleCallback === 'undefined' ? cb => cb() : requestIdleCallback)(() => {
10879
10904
  scope.run(() => {
10880
- bindScroll(data.targetEl.value ?? data.contentEl.value, e => {
10905
+ bindScroll(data.target.value ?? data.contentEl.value, e => {
10881
10906
  if (slow) {
10882
10907
  // If the position calculation is slow,
10883
10908
  // defer updates until scrolling is finished.
@@ -10902,7 +10927,8 @@ function repositionScrollStrategy(data, props, scope) {
10902
10927
  }
10903
10928
 
10904
10929
  /** @private */
10905
- function bindScroll(el, onScroll) {
10930
+ function bindScroll(target, onScroll) {
10931
+ const el = Array.isArray(target) ? document.elementFromPoint(...target) : target;
10906
10932
  const scrollElements = [document, ...getScrollParents(el)];
10907
10933
  scrollElements.forEach(el => {
10908
10934
  el.addEventListener('scroll', onScroll, {
@@ -11584,6 +11610,7 @@ const VOverlay = genericComponent()({
11584
11610
  root,
11585
11611
  contentEl,
11586
11612
  targetEl,
11613
+ target,
11587
11614
  isActive,
11588
11615
  updateLocation
11589
11616
  });
@@ -11979,7 +12006,7 @@ const VFieldLabel = genericComponent()({
11979
12006
 
11980
12007
  // Types
11981
12008
 
11982
- const allowedVariants$1 = ['underlined', 'outlined', 'filled', 'solo', 'solo-inverted', 'solo-filled', 'plain'];
12009
+ const allowedVariants$3 = ['underlined', 'outlined', 'filled', 'solo', 'solo-inverted', 'solo-filled', 'plain'];
11983
12010
  const makeVFieldProps = propsFactory({
11984
12011
  appendInnerIcon: IconValue,
11985
12012
  bgColor: String,
@@ -12013,7 +12040,7 @@ const makeVFieldProps = propsFactory({
12013
12040
  variant: {
12014
12041
  type: String,
12015
12042
  default: 'filled',
12016
- validator: v => allowedVariants$1.includes(v)
12043
+ validator: v => allowedVariants$3.includes(v)
12017
12044
  },
12018
12045
  'onClick:clear': EventProp(),
12019
12046
  'onClick:appendInner': EventProp(),
@@ -12361,7 +12388,7 @@ const VTextField = genericComponent()({
12361
12388
  if (!isFocused.value) focus();
12362
12389
  nextTick(() => {
12363
12390
  if (inputRef.value !== document.activeElement) {
12364
- nextTick(() => inputRef.value?.focus());
12391
+ inputRef.value?.focus();
12365
12392
  }
12366
12393
  });
12367
12394
  }
@@ -12464,7 +12491,7 @@ const VTextField = genericComponent()({
12464
12491
  "placeholder": props.placeholder,
12465
12492
  "size": 1,
12466
12493
  "type": props.type,
12467
- "onFocus": onFocus,
12494
+ "onFocus": focus,
12468
12495
  "onBlur": blur
12469
12496
  }, slotProps, inputAttrs), null), [[Intersect, {
12470
12497
  handler: onIntersect
@@ -16175,6 +16202,7 @@ const makeSliderProps = propsFactory({
16175
16202
  validator: v => ['vertical', 'horizontal'].includes(v)
16176
16203
  },
16177
16204
  reverse: Boolean,
16205
+ noKeyboard: Boolean,
16178
16206
  ...makeRoundedProps(),
16179
16207
  ...makeElevationProps({
16180
16208
  elevation: 2
@@ -16378,6 +16406,7 @@ const useSlider = _ref => {
16378
16406
  min,
16379
16407
  max,
16380
16408
  mousePressed,
16409
+ noKeyboard: toRef(() => props.noKeyboard),
16381
16410
  numTicks,
16382
16411
  onSliderMousedown,
16383
16412
  onSliderTouchstart,
@@ -16430,6 +16459,7 @@ const makeVSliderThumbProps = propsFactory({
16430
16459
  default: true
16431
16460
  },
16432
16461
  name: String,
16462
+ noKeyboard: Boolean,
16433
16463
  ...makeComponentProps()
16434
16464
  }, 'VSliderThumb');
16435
16465
  const VSliderThumb = genericComponent()({
@@ -16492,6 +16522,7 @@ const VSliderThumb = genericComponent()({
16492
16522
  if (step.value) return [1, 2, 3];else return [1, 5, 10];
16493
16523
  });
16494
16524
  function parseKeydown(e, value) {
16525
+ if (props.noKeyboard) return;
16495
16526
  if (!relevantKeys.includes(e.key)) return;
16496
16527
  e.preventDefault();
16497
16528
  const _step = step.value || 0.1;
@@ -16727,7 +16758,8 @@ const VSlider = genericComponent()({
16727
16758
  trackContainerRef,
16728
16759
  position,
16729
16760
  hasLabels,
16730
- readonly
16761
+ readonly,
16762
+ noKeyboard
16731
16763
  } = useSlider({
16732
16764
  props,
16733
16765
  steps,
@@ -16803,6 +16835,7 @@ const VSlider = genericComponent()({
16803
16835
  "ref": thumbContainerRef,
16804
16836
  "aria-describedby": messagesId.value,
16805
16837
  "focused": isFocused.value,
16838
+ "noKeyboard": noKeyboard.value,
16806
16839
  "min": min.value,
16807
16840
  "max": max.value,
16808
16841
  "modelValue": model.value,
@@ -17521,7 +17554,13 @@ function getWeekArray(date, locale, firstDayOfWeek) {
17521
17554
  return weeks;
17522
17555
  }
17523
17556
  function startOfWeek(date, locale, firstDayOfWeek) {
17524
- const day = firstDayOfWeek ?? weekInfo(locale)?.firstDay ?? 0;
17557
+ let day = (firstDayOfWeek ?? weekInfo(locale)?.firstDay ?? 0) % 7;
17558
+
17559
+ // prevent infinite loop
17560
+ if (![0, 1, 2, 3, 4, 5, 6].includes(day)) {
17561
+ consoleWarn('Invalid firstDayOfWeek, expected discrete number in range [0-6]');
17562
+ day = 0;
17563
+ }
17525
17564
  const d = new Date(date);
17526
17565
  while (d.getDay() !== day) {
17527
17566
  d.setDate(d.getDate() - 1);
@@ -21139,7 +21178,6 @@ const VDataTableHeaders = genericComponent()({
21139
21178
  "appendIcon": appendIcon.value,
21140
21179
  "onClick:append": () => selectAll(!allSelected.value)
21141
21180
  }, {
21142
- ...slots,
21143
21181
  chip: props => createVNode(VChip, {
21144
21182
  "onClick": props.item.raw?.sortable ? () => toggleSort(props.item.raw) : undefined,
21145
21183
  "onMousedown": e => {
@@ -23874,7 +23912,7 @@ const VExpansionPanel = genericComponent()({
23874
23912
 
23875
23913
  // Types
23876
23914
 
23877
- const allowedVariants = ['default', 'accordion', 'inset', 'popout'];
23915
+ const allowedVariants$2 = ['default', 'accordion', 'inset', 'popout'];
23878
23916
  const makeVExpansionPanelsProps = propsFactory({
23879
23917
  flat: Boolean,
23880
23918
  ...makeGroupProps(),
@@ -23885,7 +23923,7 @@ const makeVExpansionPanelsProps = propsFactory({
23885
23923
  variant: {
23886
23924
  type: String,
23887
23925
  default: 'default',
23888
- validator: v => allowedVariants.includes(v)
23926
+ validator: v => allowedVariants$2.includes(v)
23889
23927
  }
23890
23928
  }, 'VExpansionPanels');
23891
23929
  const VExpansionPanels = genericComponent()({
@@ -30259,6 +30297,7 @@ const VTreeviewItem = genericComponent()({
30259
30297
  // Types
30260
30298
 
30261
30299
  const makeVTreeviewChildrenProps = propsFactory({
30300
+ fluid: Boolean,
30262
30301
  disabled: Boolean,
30263
30302
  loadChildren: Function,
30264
30303
  loadingIcon: {
@@ -30340,7 +30379,7 @@ const VTreeviewChildren = genericComponent()({
30340
30379
  depth,
30341
30380
  isLast,
30342
30381
  isLastGroup: props.isLastGroup,
30343
- leafLinks: !props.hideActions,
30382
+ leafLinks: !props.hideActions && !props.fluid,
30344
30383
  separateRoots: props.separateRoots,
30345
30384
  parentIndentLines: props.parentIndentLines,
30346
30385
  variant: props.indentLinesVariant
@@ -30457,7 +30496,6 @@ function flatten(items) {
30457
30496
  return flat;
30458
30497
  }
30459
30498
  const makeVTreeviewProps = propsFactory({
30460
- fluid: Boolean,
30461
30499
  openAll: Boolean,
30462
30500
  indentLines: [Boolean, String],
30463
30501
  search: String,
@@ -31749,7 +31787,7 @@ const VFileUploadItem = genericComponent()({
31749
31787
  "style": props.style
31750
31788
  }), {
31751
31789
  ...slots,
31752
- title: () => props?.title ?? props.file?.name,
31790
+ title: slots.title ?? (() => props?.title ?? props.file?.name),
31753
31791
  prepend: slotProps => createElementVNode(Fragment, null, [!slots.prepend ? createVNode(VAvatar, {
31754
31792
  "icon": props.fileIcon,
31755
31793
  "image": preview.value,
@@ -33176,6 +33214,707 @@ const VHotkey = genericComponent()({
33176
33214
  }
33177
33215
  });
33178
33216
 
33217
+ // Types
33218
+
33219
+ const makeVVideoVolumeProps = propsFactory({
33220
+ inline: Boolean,
33221
+ label: String,
33222
+ direction: {
33223
+ type: String,
33224
+ default: 'vertical'
33225
+ },
33226
+ modelValue: {
33227
+ type: Number,
33228
+ default: 0
33229
+ },
33230
+ menuProps: Object,
33231
+ sliderProps: Object,
33232
+ onClick: EventProp(),
33233
+ ...makeComponentProps()
33234
+ }, 'VVideoVolume');
33235
+ const VVideoVolume = genericComponent()({
33236
+ name: 'VVideoVolume',
33237
+ props: makeVVideoVolumeProps(),
33238
+ emits: {
33239
+ 'update:modelValue': val => true
33240
+ },
33241
+ setup(props, _ref) {
33242
+ let {
33243
+ attrs
33244
+ } = _ref;
33245
+ const {
33246
+ t
33247
+ } = useLocale();
33248
+ const volume = useProxiedModel(props, 'modelValue');
33249
+ const volumeIcon = toRef(() => volume.value > 70 ? '$volumeHigh' : volume.value > 40 ? '$volumeMedium' : volume.value > 10 ? '$volumeLow' : '$volumeOff');
33250
+ const containerRef = ref();
33251
+ useRender(() => {
33252
+ const sliderDefaults = {
33253
+ hideDetails: true,
33254
+ step: 5,
33255
+ thumbSize: 16
33256
+ };
33257
+ return createElementVNode("div", {
33258
+ "class": normalizeClass(['v-video-volume', {
33259
+ 'v-video-volume--inline': props.inline
33260
+ }, props.class]),
33261
+ "style": normalizeStyle(props.style),
33262
+ "ref": containerRef
33263
+ }, [withDirectives(createVNode(VIconBtn, mergeProps({
33264
+ "icon": volumeIcon.value,
33265
+ "aria-label": props.label,
33266
+ "onClick": props.onClick
33267
+ }, attrs), {
33268
+ default: () => [createVNode(VIcon, null, null), !props.inline && createVNode(VMenu, {
33269
+ "offset": "8",
33270
+ "activator": "parent",
33271
+ "attach": containerRef.value,
33272
+ "location": props.menuProps?.location ?? 'top center',
33273
+ "closeOnContentClick": false
33274
+ }, {
33275
+ default: () => [createElementVNode("div", {
33276
+ "class": normalizeClass(['v-video-volume__menu', `v-video-volume__menu--${props.direction}`])
33277
+ }, [createVNode(VSlider, mergeProps({
33278
+ "direction": props.direction,
33279
+ "aria-label": t('$vuetify.video.volume'),
33280
+ "modelValue": volume.value,
33281
+ "onUpdate:modelValue": v => volume.value = v
33282
+ }, sliderDefaults, props.sliderProps), null)])]
33283
+ })]
33284
+ }), [[resolveDirective("tooltip"), props.label, 'top']]), props.inline && createVNode(VSlider, mergeProps({
33285
+ "class": "v-video-volume-inline__slider",
33286
+ "minWidth": "50",
33287
+ "aria-label": t('$vuetify.video.volume'),
33288
+ "modelValue": volume.value,
33289
+ "onUpdate:modelValue": v => volume.value = v,
33290
+ "onKeydown": e => {
33291
+ e.stopPropagation();
33292
+ }
33293
+ }, sliderDefaults, props.sliderProps), null)]);
33294
+ });
33295
+ }
33296
+ });
33297
+
33298
+ // Types
33299
+
33300
+ const allowedVariants$1 = ['hidden', 'default', 'tube', 'mini'];
33301
+ const makeVVideoControlsProps = propsFactory({
33302
+ color: String,
33303
+ backgroundColor: String,
33304
+ trackColor: String,
33305
+ playing: Boolean,
33306
+ hidePlay: Boolean,
33307
+ hideVolume: Boolean,
33308
+ hideFullscreen: Boolean,
33309
+ fullscreen: Boolean,
33310
+ floating: Boolean,
33311
+ splitTime: Boolean,
33312
+ pills: Boolean,
33313
+ detached: Boolean,
33314
+ progress: {
33315
+ type: Number,
33316
+ default: 0
33317
+ },
33318
+ duration: {
33319
+ type: Number,
33320
+ default: 0
33321
+ },
33322
+ volume: [Number, String],
33323
+ variant: {
33324
+ type: String,
33325
+ default: 'default',
33326
+ validator: v => allowedVariants$1.includes(v)
33327
+ },
33328
+ volumeProps: Object,
33329
+ ...makeDensityProps(),
33330
+ ...makeElevationProps(),
33331
+ ...makeThemeProps()
33332
+ }, 'VVideoControls');
33333
+ const VVideoControls = genericComponent()({
33334
+ name: 'VVideoControls',
33335
+ props: makeVVideoControlsProps(),
33336
+ emits: {
33337
+ 'update:playing': val => true,
33338
+ 'update:progress': val => true,
33339
+ 'update:volume': val => true,
33340
+ skip: val => true,
33341
+ 'click:fullscreen': () => true
33342
+ },
33343
+ setup(props, _ref) {
33344
+ let {
33345
+ emit,
33346
+ slots
33347
+ } = _ref;
33348
+ const {
33349
+ t
33350
+ } = useLocale();
33351
+ const {
33352
+ themeClasses
33353
+ } = provideTheme(props);
33354
+ const {
33355
+ densityClasses
33356
+ } = useDensity(props);
33357
+ const {
33358
+ elevationClasses
33359
+ } = useElevation(props);
33360
+ const {
33361
+ backgroundColorClasses,
33362
+ backgroundColorStyles
33363
+ } = useBackgroundColor(() => {
33364
+ const fallbackBackground = props.detached ? 'surface' : undefined;
33365
+ return props.backgroundColor ?? fallbackBackground;
33366
+ });
33367
+ const playing = useProxiedModel(props, 'playing');
33368
+ const progress = useProxiedModel(props, 'progress');
33369
+ const volume = useProxiedModel(props, 'volume', 0, v => Number(v ?? 0));
33370
+ const lastVolume = shallowRef();
33371
+ const currentTime = computed(() => {
33372
+ const secondsElapsed = Math.round(props.progress / 100 * props.duration);
33373
+ return {
33374
+ elapsed: formatTime(secondsElapsed),
33375
+ remaining: formatTime(props.duration - secondsElapsed),
33376
+ total: formatTime(props.duration)
33377
+ };
33378
+ });
33379
+ const labels = computed(() => {
33380
+ const playIconLocaleKey = playing.value ? 'pause' : 'play';
33381
+ const volumeIconLocaleKey = props.volumeProps?.inline ? volume.value ? 'mute' : 'unmute' : 'showVolume';
33382
+ const fullscreenIconLocaleKey = props.fullscreen ? 'exitFullscreen' : 'enterFullscreen';
33383
+ return {
33384
+ seek: t('$vuetify.video.seek'),
33385
+ volume: t('$vuetify.video.volume'),
33386
+ playAction: t(`$vuetify.video.${playIconLocaleKey}`),
33387
+ volumeAction: t(`$vuetify.video.${volumeIconLocaleKey}`),
33388
+ fullscreenAction: t(`$vuetify.video.${fullscreenIconLocaleKey}`)
33389
+ };
33390
+ });
33391
+ function play() {
33392
+ playing.value = true;
33393
+ }
33394
+ function pause() {
33395
+ playing.value = false;
33396
+ }
33397
+ function skipTo(v) {
33398
+ progress.value = v;
33399
+ }
33400
+ function toggleMuted() {
33401
+ if (volume.value) {
33402
+ lastVolume.value = volume.value;
33403
+ volume.value = 0;
33404
+ } else {
33405
+ volume.value = lastVolume.value ?? 100;
33406
+ }
33407
+ }
33408
+ function toggleFullscreen() {
33409
+ emit('click:fullscreen');
33410
+ }
33411
+ useRender(() => {
33412
+ const sizes = props.pills ? [42, 36, 30] : [32, 28, 24];
33413
+ const innerDefaults = {
33414
+ VIconBtn: {
33415
+ size: props.density === 'compact' ? sizes[2] : props.density === 'comfortable' ? sizes[1] : sizes[0],
33416
+ iconSize: props.density === 'compact' ? 20 : props.density === 'comfortable' ? 24 : 26,
33417
+ variant: 'text',
33418
+ color: props.color
33419
+ },
33420
+ VSlider: {
33421
+ thumbSize: props.variant === 'tube' ? 10 : 16,
33422
+ hideDetails: true
33423
+ }
33424
+ };
33425
+ const regularBtnSize = innerDefaults.VIconBtn.size;
33426
+ const playBtnSize = props.pills ? regularBtnSize + 8 : regularBtnSize;
33427
+ const pillClasses = ['v-video-control__pill', props.pills ? elevationClasses.value : []];
33428
+ const slotProps = {
33429
+ play,
33430
+ pause,
33431
+ playing: playing.value,
33432
+ progress: progress.value,
33433
+ currentTime: currentTime.value,
33434
+ skipTo,
33435
+ volume,
33436
+ toggleMuted,
33437
+ fullscreen: props.fullscreen,
33438
+ toggleFullscreen,
33439
+ labels: labels.value
33440
+ };
33441
+ return createElementVNode("div", {
33442
+ "class": normalizeClass(['v-video-controls', `v-video-controls--variant-${props.variant}`, {
33443
+ 'v-video-controls--pills': props.pills
33444
+ }, {
33445
+ 'v-video-controls--detached': props.detached
33446
+ }, {
33447
+ 'v-video-controls--floating': props.floating
33448
+ }, {
33449
+ 'v-video-controls--split-time': props.splitTime
33450
+ }, backgroundColorClasses.value, props.detached && !props.pills ? elevationClasses.value : [], densityClasses.value, themeClasses.value]),
33451
+ "style": normalizeStyle([backgroundColorStyles.value, {
33452
+ '--v-video-controls-pill-height': `${regularBtnSize}px`
33453
+ }])
33454
+ }, [createVNode(VDefaultsProvider, {
33455
+ "defaults": innerDefaults
33456
+ }, {
33457
+ default: () => [slots.default?.(slotProps) ?? createElementVNode(Fragment, null, [props.variant !== 'mini' && createElementVNode(Fragment, null, [!props.hidePlay && createElementVNode("div", {
33458
+ "class": normalizeClass([pillClasses, 'v-video__action-play'])
33459
+ }, [withDirectives(createVNode(VIconBtn, {
33460
+ "icon": playing.value ? '$pause' : '$play',
33461
+ "size": playBtnSize,
33462
+ "aria-label": labels.value.playAction,
33463
+ "onClick": () => playing.value = !playing.value
33464
+ }, null), [[resolveDirective("tooltip"), labels.value.playAction, 'top']])]), slots.prepend && createElementVNode("div", {
33465
+ "class": normalizeClass(pillClasses)
33466
+ }, [slots.prepend(slotProps)]), props.splitTime ? createElementVNode("span", {
33467
+ "class": normalizeClass([pillClasses, 'v-video__time'])
33468
+ }, [currentTime.value.elapsed]) : props.variant !== 'default' ? createElementVNode("span", {
33469
+ "class": normalizeClass([pillClasses, 'v-video__time'])
33470
+ }, [currentTime.value.elapsed, createTextVNode(" / "), currentTime.value.total]) : '', createVNode(VSlider, {
33471
+ "modelValue": props.progress,
33472
+ "noKeyboard": true,
33473
+ "color": props.trackColor ?? props.color,
33474
+ "trackColor": props.variant === 'tube' ? 'white' : undefined,
33475
+ "class": "v-video__track",
33476
+ "thumbLabel": "always",
33477
+ "aria-label": labels.value.seek,
33478
+ "onUpdate:modelValue": skipTo
33479
+ }, {
33480
+ 'thumb-label': () => currentTime.value.elapsed
33481
+ }), props.variant === 'tube' && createVNode(VSpacer, null, null), props.splitTime ? createElementVNode("span", {
33482
+ "class": normalizeClass([pillClasses, 'v-video__time'])
33483
+ }, [currentTime.value.remaining]) : '']), props.variant === 'mini' && createElementVNode(Fragment, null, [createVNode(VSpacer, null, null), slots.prepend && createElementVNode("div", {
33484
+ "class": normalizeClass(pillClasses)
33485
+ }, [slots.prepend(slotProps)]), !props.hidePlay && createElementVNode("div", {
33486
+ "class": normalizeClass([pillClasses, 'v-video__action-play'])
33487
+ }, [withDirectives(createVNode(VIconBtn, {
33488
+ "icon": playing.value ? '$pause' : '$play',
33489
+ "size": playBtnSize,
33490
+ "aria-label": labels.value.playAction,
33491
+ "onClick": () => playing.value = !playing.value
33492
+ }, null), [[resolveDirective("tooltip"), labels.value.playAction, 'top']])])]), (!props.hideVolume || !props.hideFullscreen || slots.append) && createElementVNode("div", {
33493
+ "class": normalizeClass(pillClasses)
33494
+ }, [!props.hideVolume && createVNode(VVideoVolume, mergeProps({
33495
+ "key": "volume-control",
33496
+ "sliderProps": {
33497
+ color: props.color
33498
+ },
33499
+ "modelValue": volume.value,
33500
+ "label": labels.value.volumeAction,
33501
+ "onUpdate:modelValue": v => volume.value = v,
33502
+ "onClick": () => props.volumeProps?.inline && toggleMuted()
33503
+ }, props.volumeProps), null), slots.append?.(slotProps), !props.hideFullscreen && withDirectives(createVNode(VIconBtn, {
33504
+ "icon": props.fullscreen ? '$fullscreenExit' : '$fullscreen',
33505
+ "aria-label": labels.value.fullscreenAction,
33506
+ "onClick": toggleFullscreen
33507
+ }, null), [[resolveDirective("tooltip"), labels.value.fullscreenAction, 'top']])]), props.variant === 'mini' && createVNode(VSpacer, null, null)])]
33508
+ })]);
33509
+ });
33510
+ return {
33511
+ toggleMuted
33512
+ };
33513
+ }
33514
+ });
33515
+
33516
+ // Types
33517
+
33518
+ const allowedVariants = ['background', 'player'];
33519
+ const makeVVideoProps = propsFactory({
33520
+ autoplay: Boolean,
33521
+ muted: Boolean,
33522
+ eager: Boolean,
33523
+ src: String,
33524
+ type: String,
33525
+ // e.g. video/mp4
33526
+ image: String,
33527
+ hideOverlay: Boolean,
33528
+ noFullscreen: Boolean,
33529
+ startAt: [Number, String],
33530
+ variant: {
33531
+ type: String,
33532
+ default: 'player',
33533
+ validator: v => allowedVariants.includes(v)
33534
+ },
33535
+ controlsTransition: {
33536
+ type: [Boolean, String, Object],
33537
+ component: VFadeTransition
33538
+ },
33539
+ controlsVariant: {
33540
+ type: String,
33541
+ default: 'default'
33542
+ },
33543
+ controlsProps: {
33544
+ type: Object
33545
+ },
33546
+ rounded: [Boolean, Number, String, Array],
33547
+ ...makeComponentProps(),
33548
+ ...makeDensityProps(),
33549
+ ...makeDimensionProps(),
33550
+ ...makeThemeProps(),
33551
+ ...omit(makeVVideoControlsProps(), ['fullscreen', 'variant'])
33552
+ }, 'VVideo');
33553
+ const VVideo = genericComponent()({
33554
+ name: 'VVideo',
33555
+ inheritAttrs: false,
33556
+ props: makeVVideoProps(),
33557
+ emits: {
33558
+ loaded: element => true,
33559
+ 'update:playing': val => true,
33560
+ 'update:progress': val => true,
33561
+ 'update:volume': val => true
33562
+ },
33563
+ setup(props, _ref) {
33564
+ let {
33565
+ attrs,
33566
+ emit,
33567
+ slots
33568
+ } = _ref;
33569
+ const {
33570
+ themeClasses
33571
+ } = provideTheme(props);
33572
+ const {
33573
+ densityClasses
33574
+ } = useDensity(props);
33575
+ const {
33576
+ dimensionStyles
33577
+ } = useDimension(props);
33578
+ const {
33579
+ elevationClasses
33580
+ } = useElevation(props);
33581
+ const {
33582
+ ssr
33583
+ } = useDisplay();
33584
+ const roundedForContainer = toRef(() => Array.isArray(props.rounded) ? props.rounded[0] : props.rounded);
33585
+ const roundedForControls = toRef(() => Array.isArray(props.rounded) ? props.rounded.at(-1) : props.rounded ?? false);
33586
+ const {
33587
+ roundedClasses: roundedContainerClasses
33588
+ } = useRounded(roundedForContainer);
33589
+ const {
33590
+ roundedClasses: roundedControlsClasses
33591
+ } = useRounded(roundedForControls);
33592
+ const containerRef = ref();
33593
+ const videoRef = ref();
33594
+ const controlsRef = ref();
33595
+ const playing = useProxiedModel(props, 'playing');
33596
+ const progress = useProxiedModel(props, 'progress');
33597
+ const volume = useProxiedModel(props, 'volume', 0, v => Number(v ?? 0));
33598
+ const fullscreen = shallowRef(false);
33599
+ const waiting = shallowRef(false);
33600
+ const triggered = shallowRef(false);
33601
+ const startAfterLoad = shallowRef(false);
33602
+ const state = shallowRef(props.autoplay ? 'loading' : 'idle');
33603
+ const duration = shallowRef(0);
33604
+ const fullscreenEnabled = toRef(() => !props.noFullscreen && !String(attrs.controlsList ?? '').includes('nofullscreen'));
33605
+ function onTimeupdate() {
33606
+ const {
33607
+ currentTime,
33608
+ duration
33609
+ } = videoRef.value;
33610
+ progress.value = duration === 0 ? 0 : 100 * currentTime / duration;
33611
+ }
33612
+ async function onTriggered() {
33613
+ await nextTick();
33614
+ if (!videoRef.value) return;
33615
+ videoRef.value.addEventListener('timeupdate', onTimeupdate);
33616
+ videoRef.value.volume = volume.value / 100;
33617
+ if (state.value !== 'loaded') {
33618
+ state.value = 'loading';
33619
+ }
33620
+ }
33621
+ function onVideoLoaded() {
33622
+ state.value = 'loaded';
33623
+ duration.value = videoRef.value.duration;
33624
+ const startTime = Number(props.startAt ?? 0);
33625
+ if (startTime && startTime <= duration.value) {
33626
+ videoRef.value.currentTime = startTime;
33627
+ progress.value = duration.value === 0 ? 0 : 100 * startTime / duration.value;
33628
+ }
33629
+ if (startAfterLoad.value) {
33630
+ setTimeout(() => playing.value = true, 100);
33631
+ }
33632
+ emit('loaded', videoRef.value);
33633
+ }
33634
+ function onClick() {
33635
+ if (state.value !== 'loaded') {
33636
+ triggered.value = true;
33637
+ startAfterLoad.value = !startAfterLoad.value;
33638
+ }
33639
+ }
33640
+ function onKeydown(e) {
33641
+ if (!videoRef.value || e.ctrlKey) return;
33642
+ if (e.key.startsWith('Arrow')) {
33643
+ e.preventDefault();
33644
+ }
33645
+ switch (true) {
33646
+ case e.key === ' ':
33647
+ {
33648
+ if (!['A', 'BUTTON'].includes(e.target?.tagName)) {
33649
+ e.preventDefault();
33650
+ playing.value = !playing.value;
33651
+ }
33652
+ break;
33653
+ }
33654
+ case e.key === 'ArrowRight':
33655
+ {
33656
+ const step = 10 * (e.shiftKey ? 6 : 1);
33657
+ videoRef.value.currentTime = Math.min(videoRef.value.currentTime + step, duration.value);
33658
+ // TODO: show skip indicator
33659
+ break;
33660
+ }
33661
+ case e.key === 'ArrowLeft':
33662
+ {
33663
+ const step = 10 * (e.shiftKey ? 6 : 1);
33664
+ videoRef.value.currentTime = Math.max(videoRef.value.currentTime - step, 0);
33665
+ // TODO: show skip indicator
33666
+ break;
33667
+ }
33668
+ case createRange(10).map(String).includes(e.key):
33669
+ {
33670
+ skipTo(Number(e.key) * 10);
33671
+ break;
33672
+ }
33673
+ case e.key === 'ArrowUp':
33674
+ {
33675
+ volume.value = Math.min(volume.value + 10, 100);
33676
+ // TODO: show volume change indicator
33677
+ break;
33678
+ }
33679
+ case e.key === 'ArrowDown':
33680
+ {
33681
+ volume.value = Math.max(volume.value - 10, 0);
33682
+ // TODO: show volume change indicator
33683
+ break;
33684
+ }
33685
+ case e.key === 'm':
33686
+ {
33687
+ controlsRef.value?.toggleMuted();
33688
+ break;
33689
+ }
33690
+ case e.key === 'f':
33691
+ {
33692
+ toggleFullscreen();
33693
+ break;
33694
+ }
33695
+ }
33696
+ }
33697
+ function skipTo(v) {
33698
+ if (!videoRef.value) return;
33699
+ progress.value = v;
33700
+ videoRef.value.currentTime = duration.value * v / 100;
33701
+ }
33702
+ watch(() => props.src, v => {
33703
+ progress.value = 0;
33704
+ });
33705
+ watch(playing, v => {
33706
+ if (!videoRef.value) return;
33707
+ if (v) {
33708
+ videoRef.value.play();
33709
+ } else {
33710
+ videoRef.value.pause();
33711
+ }
33712
+ });
33713
+ watch(volume, v => {
33714
+ if (!videoRef.value) return;
33715
+ videoRef.value.volume = v / 100;
33716
+ });
33717
+ watch(triggered, () => onTriggered(), {
33718
+ once: true
33719
+ });
33720
+ watch(() => props.eager, v => v && (triggered.value = true), {
33721
+ immediate: true
33722
+ });
33723
+ onMounted(() => {
33724
+ if (props.autoplay && !ssr) {
33725
+ triggered.value = true;
33726
+ startAfterLoad.value = true;
33727
+ }
33728
+ });
33729
+ onBeforeUnmount(() => {
33730
+ videoRef.value?.removeEventListener('timeupdate', onTimeupdate);
33731
+ });
33732
+ function focusSlider() {
33733
+ const container = videoRef.value?.closest('.v-video');
33734
+ const innerSlider = container?.querySelector('[role="slider"]');
33735
+ innerSlider?.focus();
33736
+ }
33737
+ function fullscreenExitShortcut(e) {
33738
+ if (['ESC', 'f'].includes(e.key)) {
33739
+ toggleFullscreen();
33740
+ document.body.removeEventListener('keydown', fullscreenExitShortcut);
33741
+ }
33742
+ }
33743
+ async function toggleFullscreen() {
33744
+ if (!fullscreenEnabled.value || !document.fullscreenEnabled) {
33745
+ return;
33746
+ }
33747
+ if (document.fullscreenElement) {
33748
+ document.exitFullscreen();
33749
+ onFullscreenExit();
33750
+ } else {
33751
+ await containerRef.value?.requestFullscreen();
33752
+ document.body.addEventListener('keydown', fullscreenExitShortcut);
33753
+ document.addEventListener('fullscreenchange', onFullscreenExit);
33754
+ fullscreen.value = true;
33755
+ }
33756
+ }
33757
+ function onFullscreenExit() {
33758
+ // event fires with a delay after requestFullscreen(), ignore first run
33759
+ if (document.fullscreenElement) return;
33760
+ focusSlider();
33761
+ fullscreen.value = false;
33762
+ document.body.removeEventListener('keydown', fullscreenExitShortcut);
33763
+ document.removeEventListener('fullscreenchange', onFullscreenExit);
33764
+ }
33765
+ function onVideoClick(e) {
33766
+ e.preventDefault();
33767
+ if (state.value === 'loaded') {
33768
+ playing.value = !playing.value;
33769
+ focusSlider();
33770
+ }
33771
+ }
33772
+ function onDoubleClick(e) {
33773
+ e.preventDefault();
33774
+ toggleFullscreen();
33775
+ }
33776
+ let lastTap = 0;
33777
+ function onTouchend(e) {
33778
+ const now = performance.now();
33779
+ if (now - lastTap < 500) {
33780
+ e.preventDefault();
33781
+ toggleFullscreen();
33782
+ } else {
33783
+ lastTap = now;
33784
+ }
33785
+ }
33786
+ useRender(() => {
33787
+ const showControls = state.value === 'loaded' && props.variant === 'player' && props.controlsVariant !== 'hidden';
33788
+ const posterTransition = props.variant === 'background' ? 'poster-fade-out' : 'fade-transition';
33789
+ const overlayProps = {
33790
+ contained: true,
33791
+ persistent: true,
33792
+ contentClass: 'v-video__overlay-fill'
33793
+ };
33794
+ const controlsProps = {
33795
+ ...VVideoControls.filterProps(omit(props, ['variant', 'rounded', 'hideVolume'])),
33796
+ rounded: Array.isArray(props.rounded) ? props.rounded.at(-1) : props.rounded,
33797
+ fullscreen: fullscreen.value,
33798
+ hideVolume: props.hideVolume || props.muted,
33799
+ hideFullscreen: props.hideFullscreen || !fullscreenEnabled.value,
33800
+ density: props.density,
33801
+ variant: props.controlsVariant,
33802
+ playing: playing.value,
33803
+ progress: progress.value,
33804
+ duration: duration.value,
33805
+ volume: volume.value,
33806
+ ...props.controlsProps
33807
+ };
33808
+ const controlsEventHandlers = {
33809
+ onSkip: v => skipTo(v),
33810
+ 'onClick:fullscreen': () => toggleFullscreen(),
33811
+ 'onUpdate:playing': v => playing.value = v,
33812
+ 'onUpdate:progress': v => skipTo(v),
33813
+ 'onUpdate:volume': v => volume.value = v,
33814
+ onClick: e => e.stopPropagation()
33815
+ };
33816
+ const controlslist = [attrs.controlslist, props.noFullscreen ? 'nofullscreen' : ''].filter(Boolean).join(' ');
33817
+ const loadingIndicator = createVNode(VProgressCircular, {
33818
+ "indeterminate": true,
33819
+ "color": props.color,
33820
+ "width": "3",
33821
+ "size": Math.min(100, Number(props.height) / 2 || 50)
33822
+ }, null);
33823
+ const overlayPlayIcon = createVNode(VIconBtn, {
33824
+ "icon": "$play",
33825
+ "size": "80",
33826
+ "color": "#fff",
33827
+ "variant": "outlined",
33828
+ "iconSize": "50",
33829
+ "class": "v-video__center-icon"
33830
+ }, null);
33831
+ return createElementVNode("div", {
33832
+ "ref": containerRef,
33833
+ "class": normalizeClass(['v-video', `v-video--variant-${props.variant}`, `v-video--${state.value}`, {
33834
+ 'v-video--playing': playing.value
33835
+ }, themeClasses.value, densityClasses.value, roundedContainerClasses.value, props.class]),
33836
+ "style": normalizeStyle([props.variant === 'background' ? [] : pick(dimensionStyles.value, ['width', 'min-width', 'max-width']), props.style]),
33837
+ "onKeydown": onKeydown,
33838
+ "onClick": onClick
33839
+ }, [createElementVNode("div", {
33840
+ "class": normalizeClass(['v-video__content', elevationClasses.value]),
33841
+ "style": normalizeStyle([props.variant === 'background' ? [] : dimensionStyles.value])
33842
+ }, [(props.eager || triggered.value) && createElementVNode("video", mergeProps({
33843
+ "key": "video-element",
33844
+ "class": ['v-video__video', roundedContainerClasses.value]
33845
+ }, omit(attrs, ['controlslist', 'class', 'style']), {
33846
+ "controlslist": controlslist,
33847
+ "autoplay": props.autoplay,
33848
+ "muted": props.muted,
33849
+ "playsinline": true,
33850
+ "ref": videoRef,
33851
+ "onLoadeddata": onVideoLoaded,
33852
+ "onPlay": () => playing.value = true,
33853
+ "onPause": () => playing.value = false,
33854
+ "onWaiting": () => waiting.value = true,
33855
+ "onPlaying": () => waiting.value = false,
33856
+ "onClick": onVideoClick,
33857
+ "onDblclick": onDoubleClick,
33858
+ "onTouchend": onTouchend
33859
+ }), [slots.sources?.() ?? createElementVNode("source", {
33860
+ "src": props.src,
33861
+ "type": props.type
33862
+ }, null)]), props.variant === 'player' && !props.hideOverlay && createVNode(VOverlay, mergeProps({
33863
+ "key": "pause-overlay",
33864
+ "modelValue": state.value === 'loaded',
33865
+ "opacity": "0"
33866
+ }, overlayProps), {
33867
+ default: () => [createVNode(VSpacer, null, null), createVNode(MaybeTransition, {
33868
+ "name": "fade-transition"
33869
+ }, {
33870
+ default: () => [!playing.value && overlayPlayIcon]
33871
+ }), createVNode(VSpacer, null, null)]
33872
+ }), props.variant === 'player' && !!slots.header ? createElementVNode("div", {
33873
+ "key": "header",
33874
+ "class": "v-video__header"
33875
+ }, [slots.header()]) : '', createVNode(VOverlay, mergeProps({
33876
+ "key": "poster-overlay",
33877
+ "modelValue": state.value !== 'loaded',
33878
+ "transition": posterTransition
33879
+ }, overlayProps), {
33880
+ default: () => [createVNode(VImg, {
33881
+ "cover": true,
33882
+ "src": props.image
33883
+ }, {
33884
+ default: () => [createElementVNode("div", {
33885
+ "class": normalizeClass(['v-video__overlay-fill', ...roundedContainerClasses.value])
33886
+ }, [overlayPlayIcon])]
33887
+ })]
33888
+ }), createVNode(VOverlay, mergeProps({
33889
+ "key": "loading-overlay",
33890
+ "modelValue": state.value === 'loading' || waiting.value,
33891
+ "opacity": ".1"
33892
+ }, overlayProps), {
33893
+ default: () => [loadingIndicator]
33894
+ })]), createVNode(MaybeTransition, {
33895
+ "key": "actions",
33896
+ "transition": props.controlsTransition
33897
+ }, {
33898
+ default: () => [showControls && createVNode(VVideoControls, mergeProps({
33899
+ "ref": controlsRef,
33900
+ "class": roundedControlsClasses.value
33901
+ }, controlsProps, controlsEventHandlers), {
33902
+ default: slots.controls,
33903
+ prepend: slots.prepend,
33904
+ append: slots.append
33905
+ })]
33906
+ })]);
33907
+ });
33908
+ return {
33909
+ video: videoRef,
33910
+ ...forwardRefs({
33911
+ skipTo,
33912
+ toggleFullscreen
33913
+ }, controlsRef)
33914
+ };
33915
+ }
33916
+ });
33917
+
33179
33918
  var components = /*#__PURE__*/Object.freeze({
33180
33919
  __proto__: null,
33181
33920
  VAlert: VAlert,
@@ -33366,6 +34105,9 @@ var components = /*#__PURE__*/Object.freeze({
33366
34105
  VTreeviewGroup: VTreeviewGroup,
33367
34106
  VTreeviewItem: VTreeviewItem,
33368
34107
  VValidation: VValidation,
34108
+ VVideo: VVideo,
34109
+ VVideoControls: VVideoControls,
34110
+ VVideoVolume: VVideoVolume,
33369
34111
  VVirtualScroll: VVirtualScroll,
33370
34112
  VWindow: VWindow,
33371
34113
  VWindowItem: VWindowItem
@@ -33688,7 +34430,7 @@ function createVuetify$1() {
33688
34430
  };
33689
34431
  });
33690
34432
  }
33691
- const version$1 = "3.9.2-master.2025-07-22";
34433
+ const version$1 = "3.9.2-master.2025-07-24";
33692
34434
  createVuetify$1.version = version$1;
33693
34435
 
33694
34436
  // Vue's inject() can only be used in setup
@@ -33986,7 +34728,7 @@ var index = /*#__PURE__*/Object.freeze({
33986
34728
 
33987
34729
  /* eslint-disable local-rules/sort-imports */
33988
34730
 
33989
- const version = "3.9.2-master.2025-07-22";
34731
+ const version = "3.9.2-master.2025-07-24";
33990
34732
 
33991
34733
  /* eslint-disable local-rules/sort-imports */
33992
34734