diff --git a/cspell.json b/cspell.json index bb4511bf..16b5b73f 100644 --- a/cspell.json +++ b/cspell.json @@ -15,6 +15,7 @@ "rahim", "segoe", "shiki", + "squircle", "videojs", "vitesse", "wouter" diff --git a/packages/core/src/dom/media/types.ts b/packages/core/src/dom/media/types.ts index e3cbde0e..0946156d 100644 --- a/packages/core/src/dom/media/types.ts +++ b/packages/core/src/dom/media/types.ts @@ -66,6 +66,7 @@ export type AudioFeatures = [ PlayerFeature, PlayerFeature, PlayerFeature, + PlayerFeature, ]; // TODO: Define background video features (e.g., playback, source, buffer) diff --git a/packages/core/src/dom/store/features/presets.ts b/packages/core/src/dom/store/features/presets.ts index ef1e77d4..c1e110d2 100644 --- a/packages/core/src/dom/store/features/presets.ts +++ b/packages/core/src/dom/store/features/presets.ts @@ -32,6 +32,7 @@ export const audioFeatures: AudioFeatures = [ timeFeature, sourceFeature, bufferFeature, + errorFeature, ]; // TODO: Add background video features (e.g., playback, source, buffer) diff --git a/packages/html/src/define/audio/minimal-skin.tailwind.ts b/packages/html/src/define/audio/minimal-skin.tailwind.ts index 4e20d097..94fddbb0 100644 --- a/packages/html/src/define/audio/minimal-skin.tailwind.ts +++ b/packages/html/src/define/audio/minimal-skin.tailwind.ts @@ -45,7 +45,7 @@ function getTemplateHTML() {
- + ${renderIcon('restart', { class: cn(icon, iconState.play.restart) })} ${renderIcon('play', { class: cn(icon, iconState.play.play) })} ${renderIcon('pause', { class: cn(icon, iconState.play.pause) })} @@ -57,7 +57,7 @@ function getTemplateHTML() { - + ${renderIcon('seek', { class: cn(icon, iconFlipped) })} ${SEEK_TIME} @@ -67,7 +67,7 @@ function getTemplateHTML() { Seek backward ${SEEK_TIME} seconds - + ${renderIcon('seek', { class: icon })} ${SEEK_TIME} @@ -95,13 +95,13 @@ function getTemplateHTML() {
- + Toggle playback rate - + ${renderIcon('volume-off', { class: cn(icon, iconState.mute.volumeOff) })} ${renderIcon('volume-low', { class: cn(icon, iconState.mute.volumeLow) })} ${renderIcon('volume-high', { class: cn(icon, iconState.mute.volumeHigh) })} diff --git a/packages/html/src/define/audio/minimal-skin.ts b/packages/html/src/define/audio/minimal-skin.ts index 75895a64..c2760e8a 100644 --- a/packages/html/src/define/audio/minimal-skin.ts +++ b/packages/html/src/define/audio/minimal-skin.ts @@ -28,7 +28,7 @@ function getTemplateHTML() {
- + ${renderIcon('restart', { class: 'media-icon media-icon--restart' })} ${renderIcon('play', { class: 'media-icon media-icon--play' })} ${renderIcon('pause', { class: 'media-icon media-icon--pause' })} @@ -39,7 +39,7 @@ function getTemplateHTML() { Pause - + ${renderIcon('seek', { class: 'media-icon media-icon--seek media-icon--flipped' })} ${SEEK_TIME} @@ -49,7 +49,7 @@ function getTemplateHTML() { Seek backward ${SEEK_TIME} seconds - + ${renderIcon('seek', { class: 'media-icon media-icon--seek' })} ${SEEK_TIME} @@ -77,13 +77,13 @@ function getTemplateHTML() {
- + Toggle playback rate - + ${renderIcon('volume-off', { class: 'media-icon media-icon--volume-off' })} ${renderIcon('volume-low', { class: 'media-icon media-icon--volume-low' })} ${renderIcon('volume-high', { class: 'media-icon media-icon--volume-high' })} diff --git a/packages/html/src/define/audio/skin.tailwind.ts b/packages/html/src/define/audio/skin.tailwind.ts index 26bc5654..69377ca7 100644 --- a/packages/html/src/define/audio/skin.tailwind.ts +++ b/packages/html/src/define/audio/skin.tailwind.ts @@ -43,7 +43,7 @@ function getTemplateHTML() {
- + ${renderIcon('restart', { class: cn(icon, iconState.play.restart) })} ${renderIcon('play', { class: cn(icon, iconState.play.play) })} ${renderIcon('pause', { class: cn(icon, iconState.play.pause) })} @@ -55,7 +55,7 @@ function getTemplateHTML() { - + ${renderIcon('seek', { class: cn(icon, iconFlipped) })} ${SEEK_TIME} @@ -65,7 +65,7 @@ function getTemplateHTML() { Seek backward ${SEEK_TIME} seconds - + ${renderIcon('seek', { class: icon })} ${SEEK_TIME} @@ -87,12 +87,12 @@ function getTemplateHTML() { - + Toggle playback rate - + ${renderIcon('volume-off', { class: cn(icon, iconState.mute.volumeOff) })} ${renderIcon('volume-low', { class: cn(icon, iconState.mute.volumeLow) })} ${renderIcon('volume-high', { class: cn(icon, iconState.mute.volumeHigh) })} diff --git a/packages/html/src/define/audio/skin.ts b/packages/html/src/define/audio/skin.ts index 9d62d7cd..658d5c67 100644 --- a/packages/html/src/define/audio/skin.ts +++ b/packages/html/src/define/audio/skin.ts @@ -27,7 +27,7 @@ function getTemplateHTML() {
- + ${renderIcon('restart', { class: 'media-icon media-icon--restart' })} ${renderIcon('play', { class: 'media-icon media-icon--play' })} ${renderIcon('pause', { class: 'media-icon media-icon--pause' })} @@ -38,7 +38,7 @@ function getTemplateHTML() { Pause - + ${renderIcon('seek', { class: 'media-icon media-icon--seek media-icon--flipped' })} ${SEEK_TIME} @@ -48,7 +48,7 @@ function getTemplateHTML() { Seek backward ${SEEK_TIME} seconds - + ${renderIcon('seek', { class: 'media-icon media-icon--seek' })} ${SEEK_TIME} @@ -70,12 +70,12 @@ function getTemplateHTML() { - + Toggle playback rate - + ${renderIcon('volume-off', { class: 'media-icon media-icon--volume-off' })} ${renderIcon('volume-low', { class: 'media-icon media-icon--volume-low' })} ${renderIcon('volume-high', { class: 'media-icon media-icon--volume-high' })} diff --git a/packages/html/src/define/video/minimal-skin.tailwind.ts b/packages/html/src/define/video/minimal-skin.tailwind.ts index 50a38bca..1c8dc81c 100644 --- a/packages/html/src/define/video/minimal-skin.tailwind.ts +++ b/packages/html/src/define/video/minimal-skin.tailwind.ts @@ -63,7 +63,7 @@ function getTemplateHTML() {
- + ${renderIcon('restart', { class: cn(icon, iconState.play.restart) })} ${renderIcon('play', { class: cn(icon, iconState.play.play) })} ${renderIcon('pause', { class: cn(icon, iconState.play.pause) })} @@ -75,7 +75,7 @@ function getTemplateHTML() { - + ${renderIcon('seek', { class: cn(icon, iconFlipped) })} ${SEEK_TIME} @@ -85,7 +85,7 @@ function getTemplateHTML() { Seek backward ${SEEK_TIME} seconds - + ${renderIcon('seek', { class: icon })} ${SEEK_TIME} @@ -121,13 +121,13 @@ function getTemplateHTML() {
- + Toggle playback rate - + ${renderIcon('volume-off', { class: cn(icon, iconState.mute.volumeOff) })} ${renderIcon('volume-low', { class: cn(icon, iconState.mute.volumeLow) })} ${renderIcon('volume-high', { class: cn(icon, iconState.mute.volumeHigh) })} @@ -143,7 +143,7 @@ function getTemplateHTML() { - + ${renderIcon('captions-off', { class: cn(icon, iconState.captions.off) })} ${renderIcon('captions-on', { class: cn(icon, iconState.captions.on) })} @@ -154,7 +154,7 @@ function getTemplateHTML() { - + ${renderIcon('pip-enter', { class: cn(icon, iconState.pip.off) })} ${renderIcon('pip-exit', { class: cn(icon, iconState.pip.on) })} @@ -165,7 +165,7 @@ function getTemplateHTML() { - + ${renderIcon('fullscreen-enter', { class: cn(icon, iconState.fullscreen.enter) })} ${renderIcon('fullscreen-exit', { class: cn(icon, iconState.fullscreen.exit) })} diff --git a/packages/html/src/define/video/minimal-skin.ts b/packages/html/src/define/video/minimal-skin.ts index 5de7b8a6..5bfd7a96 100644 --- a/packages/html/src/define/video/minimal-skin.ts +++ b/packages/html/src/define/video/minimal-skin.ts @@ -41,7 +41,7 @@ function getTemplateHTML() {
- + ${renderIcon('restart', { class: 'media-icon media-icon--restart' })} ${renderIcon('play', { class: 'media-icon media-icon--play' })} ${renderIcon('pause', { class: 'media-icon media-icon--pause' })} @@ -52,7 +52,7 @@ function getTemplateHTML() { Pause - + ${renderIcon('seek', { class: 'media-icon media-icon--flipped' })} ${SEEK_TIME} @@ -62,7 +62,7 @@ function getTemplateHTML() { Seek backward ${SEEK_TIME} seconds - + ${renderIcon('seek', { class: 'media-icon' })} ${SEEK_TIME} @@ -98,12 +98,12 @@ function getTemplateHTML() {
- + Toggle playback rate - + ${renderIcon('volume-off', { class: 'media-icon media-icon--volume-off' })} ${renderIcon('volume-low', { class: 'media-icon media-icon--volume-low' })} ${renderIcon('volume-high', { class: 'media-icon media-icon--volume-high' })} @@ -118,7 +118,7 @@ function getTemplateHTML() { - + ${renderIcon('captions-off', { class: 'media-icon media-icon--captions-off' })} ${renderIcon('captions-on', { class: 'media-icon media-icon--captions-on' })} @@ -126,7 +126,7 @@ function getTemplateHTML() { Toggle captions - + ${renderIcon('pip-enter', { class: 'media-icon media-icon--pip-enter' })} ${renderIcon('pip-exit', { class: 'media-icon media-icon--pip-exit' })} @@ -135,7 +135,7 @@ function getTemplateHTML() { Exit picture-in-picture - + ${renderIcon('fullscreen-enter', { class: 'media-icon media-icon--fullscreen-enter' })} ${renderIcon('fullscreen-exit', { class: 'media-icon media-icon--fullscreen-exit' })} diff --git a/packages/html/src/define/video/skin.tailwind.ts b/packages/html/src/define/video/skin.tailwind.ts index 33941f35..074332ef 100644 --- a/packages/html/src/define/video/skin.tailwind.ts +++ b/packages/html/src/define/video/skin.tailwind.ts @@ -63,7 +63,7 @@ function getTemplateHTML() { - + ${renderIcon('restart', { class: cn(icon, iconState.play.restart) })} ${renderIcon('play', { class: cn(icon, iconState.play.play) })} ${renderIcon('pause', { class: cn(icon, iconState.play.pause) })} @@ -75,7 +75,7 @@ function getTemplateHTML() { - + ${renderIcon('seek', { class: cn(icon, iconFlipped) })} ${SEEK_TIME} @@ -85,7 +85,7 @@ function getTemplateHTML() { Seek backward ${SEEK_TIME} seconds - + ${renderIcon('seek', { class: icon })} ${SEEK_TIME} @@ -113,12 +113,12 @@ function getTemplateHTML() { - + Toggle playback rate - + ${renderIcon('volume-off', { class: cn(icon, iconState.mute.volumeOff) })} ${renderIcon('volume-low', { class: cn(icon, iconState.mute.volumeLow) })} ${renderIcon('volume-high', { class: cn(icon, iconState.mute.volumeHigh) })} @@ -134,7 +134,7 @@ function getTemplateHTML() { - + ${renderIcon('captions-off', { class: cn(icon, iconState.captions.off) })} ${renderIcon('captions-on', { class: cn(icon, iconState.captions.on) })} @@ -145,7 +145,7 @@ function getTemplateHTML() { - + ${renderIcon('pip-enter', { class: cn(icon, iconState.pip.off) })} ${renderIcon('pip-exit', { class: cn(icon, iconState.pip.on) })} @@ -156,7 +156,7 @@ function getTemplateHTML() { - + ${renderIcon('fullscreen-enter', { class: cn(icon, iconState.fullscreen.enter) })} ${renderIcon('fullscreen-exit', { class: cn(icon, iconState.fullscreen.exit) })} diff --git a/packages/html/src/define/video/skin.ts b/packages/html/src/define/video/skin.ts index 18e00283..380d4a46 100644 --- a/packages/html/src/define/video/skin.ts +++ b/packages/html/src/define/video/skin.ts @@ -43,7 +43,7 @@ function getTemplateHTML() { - + ${renderIcon('restart', { class: 'media-icon media-icon--restart' })} ${renderIcon('play', { class: 'media-icon media-icon--play' })} ${renderIcon('pause', { class: 'media-icon media-icon--pause' })} @@ -54,7 +54,7 @@ function getTemplateHTML() { Pause - + ${renderIcon('seek', { class: 'media-icon media-icon--flipped' })} ${SEEK_TIME} @@ -64,7 +64,7 @@ function getTemplateHTML() { Seek backward ${SEEK_TIME} seconds - + ${renderIcon('seek', { class: 'media-icon' })} ${SEEK_TIME} @@ -92,12 +92,12 @@ function getTemplateHTML() { - + Toggle playback rate - + ${renderIcon('volume-off', { class: 'media-icon media-icon--volume-off' })} ${renderIcon('volume-low', { class: 'media-icon media-icon--volume-low' })} ${renderIcon('volume-high', { class: 'media-icon media-icon--volume-high' })} @@ -112,7 +112,7 @@ function getTemplateHTML() { - + ${renderIcon('captions-off', { class: 'media-icon media-icon--captions-off' })} ${renderIcon('captions-on', { class: 'media-icon media-icon--captions-on' })} @@ -121,7 +121,7 @@ function getTemplateHTML() { Disable captions - + ${renderIcon('pip-enter', { class: 'media-icon media-icon--pip-enter' })} ${renderIcon('pip-exit', { class: 'media-icon media-icon--pip-exit' })} @@ -130,7 +130,7 @@ function getTemplateHTML() { Exit picture-in-picture - + ${renderIcon('fullscreen-enter', { class: 'media-icon media-icon--fullscreen-enter' })} ${renderIcon('fullscreen-exit', { class: 'media-icon media-icon--fullscreen-exit' })} diff --git a/packages/html/src/player/tests/create-player.test-d.ts b/packages/html/src/player/tests/create-player.test-d.ts index 29c94a85..27818b5a 100644 --- a/packages/html/src/player/tests/create-player.test-d.ts +++ b/packages/html/src/player/tests/create-player.test-d.ts @@ -16,6 +16,12 @@ describe('createPlayer', () => { const result = createPlayer({ features: audioFeatures }); assertType>(result); + + const store = result.create(); + + assertType(store.error?.code); + assertType(store.error?.message); + assertType<() => void>(store.dismissError); }); it('resolves spread video features to VideoPlayerStore', () => { diff --git a/packages/react/src/presets/audio/minimal-skin.tailwind.tsx b/packages/react/src/presets/audio/minimal-skin.tailwind.tsx index a74e1f19..198e4f9c 100644 --- a/packages/react/src/presets/audio/minimal-skin.tailwind.tsx +++ b/packages/react/src/presets/audio/minimal-skin.tailwind.tsx @@ -12,6 +12,7 @@ import { button, buttonGroup, controls, + error, icon, iconContainer, iconFlipped, @@ -34,23 +35,26 @@ import { Time } from '@/ui/time'; import { TimeSlider } from '@/ui/time-slider'; import { Tooltip } from '@/ui/tooltip'; import { VolumeSlider } from '@/ui/volume-slider'; +import { ErrorDialog } from '../error-dialog'; import type { MinimalAudioSkinProps } from './minimal-skin'; const SEEK_TIME = 10; +const ERROR_CLASSNAMES = { + root: error.root, + dialog: error.dialog, + content: error.content, + title: error.title, + description: error.description, + actions: error.actions, + close: cn(button.base, button.subtle), +}; + /* --------------------------------------- Components ---------------------------------------- */ -const Button = forwardRef & { variant?: 'icon' }>(function Button( - { className, variant, ...props }, - ref -) { +const Button = forwardRef>(function Button({ className, ...props }, ref) { return ( -