From 4fef1cb0782e68a21a94859e34a9322be9ce558b Mon Sep 17 00:00:00 2001 From: Alberto Miconi Date: Fri, 28 Aug 2026 11:08:27 +0200 Subject: [PATCH 1/3] feat(VAudio): add audio player component --- .../api-generator/src/locale/en/VAudio.json | 52 ++ .../src/locale/en/VAudioControls.json | 56 ++ .../src/locale/en/VAudioWaveform.json | 32 + packages/docs/src/data/nav.json | 4 + .../src/examples/v-audio/misc-waveform.vue | 51 ++ .../src/examples/v-audio/prop-density.vue | 60 ++ .../docs/src/examples/v-audio/prop-peaks.vue | 52 ++ .../src/examples/v-audio/prop-seek-target.vue | 47 ++ .../docs/src/examples/v-audio/slot-error.vue | 45 ++ packages/docs/src/examples/v-audio/usage.vue | 61 ++ .../src/pages/en/components/audio-players.md | 109 +++ .../docs/src/pages/en/labs/introduction.md | 1 + packages/vuetify/src/iconsets/bx.ts | 4 + packages/vuetify/src/iconsets/carbon.ts | 4 + packages/vuetify/src/iconsets/fa.ts | 4 + packages/vuetify/src/iconsets/fa4.ts | 4 + packages/vuetify/src/iconsets/fa6.ts | 4 + packages/vuetify/src/iconsets/lucide.ts | 4 + packages/vuetify/src/iconsets/md.ts | 4 + packages/vuetify/src/iconsets/mdi-svg.ts | 4 + packages/vuetify/src/iconsets/mdi-unocss.ts | 4 + packages/vuetify/src/iconsets/mdi.ts | 4 + packages/vuetify/src/iconsets/ms.ts | 4 + packages/vuetify/src/iconsets/ph.ts | 4 + packages/vuetify/src/iconsets/ri.ts | 4 + packages/vuetify/src/iconsets/tabler.ts | 4 + packages/vuetify/src/labs/VAudio/VAudio.sass | 98 +++ packages/vuetify/src/labs/VAudio/VAudio.tsx | 633 ++++++++++++++++++ .../src/labs/VAudio/VAudioControls.sass | 68 ++ .../src/labs/VAudio/VAudioControls.tsx | 515 ++++++++++++++ .../src/labs/VAudio/VAudioWaveform.sass | 75 +++ .../src/labs/VAudio/VAudioWaveform.tsx | 402 +++++++++++ .../VAudio/__tests__/VAudio.spec.browser.tsx | 213 ++++++ .../__tests__/VAudioWaveform.spec.browser.tsx | 126 ++++ .../src/labs/VAudio/__tests__/api.spec.ts | 24 + .../src/labs/VAudio/__tests__/peaks.spec.ts | 51 ++ .../src/labs/VAudio/__tests__/time.spec.ts | 31 + .../vuetify/src/labs/VAudio/_variables.scss | 52 ++ packages/vuetify/src/labs/VAudio/decode.ts | 51 ++ packages/vuetify/src/labs/VAudio/index.ts | 3 + packages/vuetify/src/labs/VAudio/peaks.ts | 52 ++ packages/vuetify/src/labs/VAudio/time.ts | 15 + packages/vuetify/src/labs/components.ts | 1 + packages/vuetify/src/locale/af.ts | 14 + packages/vuetify/src/locale/ar.ts | 14 + packages/vuetify/src/locale/az.ts | 14 + packages/vuetify/src/locale/bg.ts | 14 + packages/vuetify/src/locale/ca.ts | 14 + packages/vuetify/src/locale/ckb.ts | 14 + packages/vuetify/src/locale/cs.ts | 14 + packages/vuetify/src/locale/da.ts | 14 + packages/vuetify/src/locale/de.ts | 14 + packages/vuetify/src/locale/el.ts | 14 + packages/vuetify/src/locale/en.ts | 14 + packages/vuetify/src/locale/es.ts | 14 + packages/vuetify/src/locale/et.ts | 14 + packages/vuetify/src/locale/fa.ts | 14 + packages/vuetify/src/locale/fi.ts | 14 + packages/vuetify/src/locale/fr.ts | 14 + packages/vuetify/src/locale/he.ts | 14 + packages/vuetify/src/locale/hr.ts | 14 + packages/vuetify/src/locale/hu.ts | 14 + packages/vuetify/src/locale/id.ts | 14 + packages/vuetify/src/locale/it.ts | 14 + packages/vuetify/src/locale/ja.ts | 14 + packages/vuetify/src/locale/km.ts | 14 + packages/vuetify/src/locale/ko.ts | 14 + packages/vuetify/src/locale/lt.ts | 14 + packages/vuetify/src/locale/lv.ts | 14 + packages/vuetify/src/locale/nl.ts | 14 + packages/vuetify/src/locale/no.ts | 14 + packages/vuetify/src/locale/pl.ts | 14 + packages/vuetify/src/locale/pt.ts | 14 + packages/vuetify/src/locale/ro.ts | 14 + packages/vuetify/src/locale/ru.ts | 14 + packages/vuetify/src/locale/sk.ts | 14 + packages/vuetify/src/locale/sl.ts | 14 + packages/vuetify/src/locale/sr-Cyrl.ts | 14 + packages/vuetify/src/locale/sr-Latn.ts | 14 + packages/vuetify/src/locale/sv.ts | 14 + packages/vuetify/src/locale/th.ts | 14 + packages/vuetify/src/locale/tr.ts | 14 + packages/vuetify/src/locale/uk.ts | 14 + packages/vuetify/src/locale/vi.ts | 14 + packages/vuetify/src/locale/zh-Hans.ts | 14 + packages/vuetify/src/locale/zh-Hant.ts | 14 + 86 files changed, 3638 insertions(+) create mode 100644 packages/api-generator/src/locale/en/VAudio.json create mode 100644 packages/api-generator/src/locale/en/VAudioControls.json create mode 100644 packages/api-generator/src/locale/en/VAudioWaveform.json create mode 100644 packages/docs/src/examples/v-audio/misc-waveform.vue create mode 100644 packages/docs/src/examples/v-audio/prop-density.vue create mode 100644 packages/docs/src/examples/v-audio/prop-peaks.vue create mode 100644 packages/docs/src/examples/v-audio/prop-seek-target.vue create mode 100644 packages/docs/src/examples/v-audio/slot-error.vue create mode 100644 packages/docs/src/examples/v-audio/usage.vue create mode 100644 packages/docs/src/pages/en/components/audio-players.md create mode 100644 packages/vuetify/src/labs/VAudio/VAudio.sass create mode 100644 packages/vuetify/src/labs/VAudio/VAudio.tsx create mode 100644 packages/vuetify/src/labs/VAudio/VAudioControls.sass create mode 100644 packages/vuetify/src/labs/VAudio/VAudioControls.tsx create mode 100644 packages/vuetify/src/labs/VAudio/VAudioWaveform.sass create mode 100644 packages/vuetify/src/labs/VAudio/VAudioWaveform.tsx create mode 100644 packages/vuetify/src/labs/VAudio/__tests__/VAudio.spec.browser.tsx create mode 100644 packages/vuetify/src/labs/VAudio/__tests__/VAudioWaveform.spec.browser.tsx create mode 100644 packages/vuetify/src/labs/VAudio/__tests__/api.spec.ts create mode 100644 packages/vuetify/src/labs/VAudio/__tests__/peaks.spec.ts create mode 100644 packages/vuetify/src/labs/VAudio/__tests__/time.spec.ts create mode 100644 packages/vuetify/src/labs/VAudio/_variables.scss create mode 100644 packages/vuetify/src/labs/VAudio/decode.ts create mode 100644 packages/vuetify/src/labs/VAudio/index.ts create mode 100644 packages/vuetify/src/labs/VAudio/peaks.ts create mode 100644 packages/vuetify/src/labs/VAudio/time.ts diff --git a/packages/api-generator/src/locale/en/VAudio.json b/packages/api-generator/src/locale/en/VAudio.json new file mode 100644 index 00000000000..d6439ce2e40 --- /dev/null +++ b/packages/api-generator/src/locale/en/VAudio.json @@ -0,0 +1,52 @@ +{ + "description": "A player for self-hosted audio files, with a seekable waveform and a configurable transport bar.", + "props": { + "src": "Media file URL", + "srcObject": "Sets the source to a MediaStream, MediaSource, or Blob object. Live streams report an infinite duration, so the time display shows elapsed only and the waveform falls back to a placeholder track.", + "type": "Media file type (optional). When set, the source is rendered as a nested `` element so the hint is honoured.", + "crossorigin": "Forwarded to the native audio element. Required, together with CORS response headers from the media host, before peaks can be decoded from a cross-origin file.", + "preload": "Forwarded to the native audio element. The default `metadata` obtains the duration without downloading the whole file.", + "currentTime": "Playback position in seconds. Writing to it seeks; it stays in sync with `progress`, which expresses the same position as a percentage.", + "error": "Puts the component in the manual error state.", + "autoplay": "Starts loading the media file without waiting for the user to click. Playback begins once enough data is loaded.", + "loop": "Restarts playback when the end is reached. The `ended` event is not emitted while looping.", + "muted": "Hides the volume control and disables the playback sound.", + "startAt": "Moves progress to the specified time (in seconds) once the media file is loaded.", + "eager": "Silently loads the media file without waiting for the user to click.", + "disabled": "Removes all interaction and dims the component.", + "seekTarget": "Which surface responds to a click when no waveform is shown. A visible waveform is always the seek surface, so `container` takes effect together with `hide-waveform` — that combination makes the whole component click-to-seek. `none` disables seeking entirely.", + "rounded": "Applies a border radius to the container and the controls. Accepts an array of two values to customize the elements separately.", + "controlsProps": "Pass props through to the `v-audio-controls` component. Accepts an object with anything from [v-audio-controls](/api/v-audio-controls/#props) props, camelCase keys are recommended." + }, + "events": { + "loaded": "Emitted when the audio has loaded its metadata and is ready to be played.", + "ended": "Emitted when playback reaches the end. Not emitted while `loop` is set.", + "error": "Emits the native MediaError when the audio fails to load, or `false` when the user triggers a retry.", + "update:playing": "Emitted when the playing state changes.", + "update:progress": "Emitted when the playback position changes, as a percentage (0-100).", + "update:currentTime": "Emitted when the playback position changes, in seconds.", + "update:volume": "Emitted when the volume changes.", + "update:playbackRate": "Emitted when the playback rate changes.", + "update:error": "Emitted when the error state changes." + }, + "slots": { + "controls": "Replaces the control bar with custom content.", + "prepend": "Additional content on the left within the control bar.", + "append": "Additional content on the right within the control bar.", + "waveform": "Replaces the waveform between the controls and the time display.", + "time": "Replaces the time display. Receives the elapsed, remaining and total time already formatted.", + "loader": "Slot used to replace the loader displayed while the audio is being loaded.", + "error": "Slot used to replace the default error state. Receives the MediaError and a `retry` function.", + "sources": "Slot for content placed within the native `