+
} />} />
Toggle playback rate
diff --git a/packages/react/src/presets/video/minimal-skin.tsx b/packages/react/src/presets/video/minimal-skin.tsx
index 99086ac2..896612ef 100644
--- a/packages/react/src/presets/video/minimal-skin.tsx
+++ b/packages/react/src/presets/video/minimal-skin.tsx
@@ -182,10 +182,10 @@ export function MinimalVideoSkin(props: MinimalVideoSkinProps): ReactNode {
-
-
-
-
+
+
+
+
@@ -199,7 +199,7 @@ export function MinimalVideoSkin(props: MinimalVideoSkinProps): ReactNode {
-
+
diff --git a/packages/react/src/presets/video/skin.tailwind.tsx b/packages/react/src/presets/video/skin.tailwind.tsx
index 6794af1e..6e07c633 100644
--- a/packages/react/src/presets/video/skin.tailwind.tsx
+++ b/packages/react/src/presets/video/skin.tailwind.tsx
@@ -17,6 +17,8 @@ import {
import {
bufferingIndicator,
button,
+ buttonGroupEnd,
+ buttonGroupStart,
controls,
error,
icon,
@@ -202,50 +204,52 @@ export function VideoSkinTailwind(props: VideoSkinProps): ReactNode {
className={controls}
>
-
- }>
-
-
-
-
- }
- />
-
-
-
-
+
+
+ }>
+
+
+
+
+ }
+ />
+
+
+
+
-
- }>
-
-
- {SEEK_TIME}
-
-
- }
- />
- Seek backward {SEEK_TIME} seconds
-
+
+ }>
+
+
+ {SEEK_TIME}
+
+
+ }
+ />
+ Seek backward {SEEK_TIME} seconds
+
-
- }>
-
-
- {SEEK_TIME}
-
-
- }
- />
- Seek forward {SEEK_TIME} seconds
-
+
+ }>
+
+
+ {SEEK_TIME}
+
+
+ }
+ />
+ Seek forward {SEEK_TIME} seconds
+
+
-
+
}>
}>
@@ -255,61 +259,63 @@ export function VideoSkinTailwind(props: VideoSkinProps): ReactNode {
} />
-
+
-
+
-
- } />} />
- Toggle playback rate
-
+
+
+ } />} />
+ Toggle playback rate
+
-
+
-
- }>
-
-
-
- }
- />
-
-
-
-
+
+ }>
+
+
+
+ }
+ />
+
+
+
+
-
- }>
-
-
-
- }
- />
-
-
-
-
+
+ }>
+
+
+
+ }
+ />
+
+
+
+
-
- }>
-
-
-
- }
- />
-
-
-
-
+
+ }>
+
+
+
+ }
+ />
+
+
+
+
+
diff --git a/packages/react/src/presets/video/skin.tsx b/packages/react/src/presets/video/skin.tsx
index 5741edf0..fdb3e8a6 100644
--- a/packages/react/src/presets/video/skin.tsx
+++ b/packages/react/src/presets/video/skin.tsx
@@ -138,51 +138,53 @@ export function VideoSkin(props: VideoSkinProps): ReactNode {
-
- }>
-
-
-
-
- }
- />
-
-
-
-
+
+
+ }>
+
+
+
+
+ }
+ />
+
+
+
+
-
- }>
-
-
- {SEEK_TIME}
-
-
- }
- />
- Seek backward {SEEK_TIME} seconds
-
+
+ }>
+
+
+ {SEEK_TIME}
+
+
+ }
+ />
+ Seek backward {SEEK_TIME} seconds
+
-
- }>
-
-
- {SEEK_TIME}
-
-
- }
- />
- Seek forward {SEEK_TIME} seconds
-
+
+ }>
+
+
+ {SEEK_TIME}
+
+
+ }
+ />
+ Seek forward {SEEK_TIME} seconds
+
+
-
-
+
+
@@ -192,63 +194,65 @@ export function VideoSkin(props: VideoSkinProps): ReactNode {
-
+
-
-
+
+
-
- } />}
- />
- Toggle playback rate
-
+
+
+ } />}
+ />
+ Toggle playback rate
+
-
+
-
- }>
-
-
-
- }
- />
-
-
-
-
+
+ }>
+
+
+
+ }
+ />
+
+
+
+
-
- }>
-
-
-
- }
- />
-
-
-
-
+
+ }>
+
+
+
+ }
+ />
+
+
+
+
-
- }>
-
-
-
- }
- />
-
-
-
-
+
+ }>
+
+
+
+ }
+ />
+
+
+
+
+
diff --git a/packages/sandbox/templates/cdn/index.html b/packages/sandbox/templates/cdn/index.html
index 1db8639e..a3fa9a95 100644
--- a/packages/sandbox/templates/cdn/index.html
+++ b/packages/sandbox/templates/cdn/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/html-audio/index.html b/packages/sandbox/templates/html-audio/index.html
index 73b10839..222f41fb 100644
--- a/packages/sandbox/templates/html-audio/index.html
+++ b/packages/sandbox/templates/html-audio/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/html-background-video/index.html b/packages/sandbox/templates/html-background-video/index.html
index 39951d8f..bd2a9bcf 100644
--- a/packages/sandbox/templates/html-background-video/index.html
+++ b/packages/sandbox/templates/html-background-video/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/html-dash-video/index.html b/packages/sandbox/templates/html-dash-video/index.html
index 35793c23..03e61484 100644
--- a/packages/sandbox/templates/html-dash-video/index.html
+++ b/packages/sandbox/templates/html-dash-video/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/html-hls-video/index.html b/packages/sandbox/templates/html-hls-video/index.html
index a081ee0e..669273ca 100644
--- a/packages/sandbox/templates/html-hls-video/index.html
+++ b/packages/sandbox/templates/html-hls-video/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/html-mux-video/index.html b/packages/sandbox/templates/html-mux-video/index.html
index f8a7fdc8..201dfde5 100644
--- a/packages/sandbox/templates/html-mux-video/index.html
+++ b/packages/sandbox/templates/html-mux-video/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/html-simple-hls-video/index.html b/packages/sandbox/templates/html-simple-hls-video/index.html
index a081ee0e..669273ca 100644
--- a/packages/sandbox/templates/html-simple-hls-video/index.html
+++ b/packages/sandbox/templates/html-simple-hls-video/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/html-video/index.html b/packages/sandbox/templates/html-video/index.html
index a081ee0e..669273ca 100644
--- a/packages/sandbox/templates/html-video/index.html
+++ b/packages/sandbox/templates/html-video/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/react-audio/index.html b/packages/sandbox/templates/react-audio/index.html
index 1f2d2633..301b1dc2 100644
--- a/packages/sandbox/templates/react-audio/index.html
+++ b/packages/sandbox/templates/react-audio/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/react-background-video/index.html b/packages/sandbox/templates/react-background-video/index.html
index 44567c35..3fa99ab0 100644
--- a/packages/sandbox/templates/react-background-video/index.html
+++ b/packages/sandbox/templates/react-background-video/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/react-dash-video/index.html b/packages/sandbox/templates/react-dash-video/index.html
index ae4ecb9c..63967ead 100644
--- a/packages/sandbox/templates/react-dash-video/index.html
+++ b/packages/sandbox/templates/react-dash-video/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/react-hls-video/index.html b/packages/sandbox/templates/react-hls-video/index.html
index 77317e25..11c035c7 100644
--- a/packages/sandbox/templates/react-hls-video/index.html
+++ b/packages/sandbox/templates/react-hls-video/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/react-mux-video/index.html b/packages/sandbox/templates/react-mux-video/index.html
index 2596b060..4e909677 100644
--- a/packages/sandbox/templates/react-mux-video/index.html
+++ b/packages/sandbox/templates/react-mux-video/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/react-simple-hls-video/index.html b/packages/sandbox/templates/react-simple-hls-video/index.html
index 77317e25..11c035c7 100644
--- a/packages/sandbox/templates/react-simple-hls-video/index.html
+++ b/packages/sandbox/templates/react-simple-hls-video/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/sandbox/templates/react-video/index.html b/packages/sandbox/templates/react-video/index.html
index 77317e25..11c035c7 100644
--- a/packages/sandbox/templates/react-video/index.html
+++ b/packages/sandbox/templates/react-video/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/packages/skins/src/default/css/audio.css b/packages/skins/src/default/css/audio.css
index 66d634ef..dd30b596 100644
--- a/packages/skins/src/default/css/audio.css
+++ b/packages/skins/src/default/css/audio.css
@@ -5,7 +5,8 @@
@import "./components/error.css";
@import "./components/controls.css";
@import "./components/time.css";
-@import "./components/buttons.css";
+@import "./components/button.css";
+@import "./components/button-group.css";
@import "./components/icons.css";
@import "./components/slider.css";
@import "./components/popup.css";
@@ -17,7 +18,6 @@
========================================================================== */
.media-default-skin--audio {
- --media-border-color: oklch(0 0 0 / 0.1);
--media-surface-background-color: oklch(1 0 0 / 0.5);
--media-surface-inner-border-color: oklch(1 0 0 / 0.1);
--media-surface-outer-border-color: oklch(0 0 0 / 0.05);
@@ -28,6 +28,8 @@
--media-error-dialog-transition-delay: 100ms;
--media-popup-transition-duration: 100ms;
--media-popup-transition-timing-function: ease-out;
+ --media-tooltip-side-offset: 0.75rem;
+ --media-popover-side-offset: 0.75rem;
@media (prefers-reduced-motion: reduce) {
--media-error-dialog-transition-duration: 50ms;
@@ -36,10 +38,20 @@
}
@media (prefers-color-scheme: dark) {
- --media-border-color: oklch(1 0 0 / 0.1);
--media-surface-background-color: oklch(0 0 0 / 0.4);
--media-text-color: var(--media-color-primary, oklch(1 0 0));
}
+
+ @media (prefers-reduced-transparency: reduce) or (prefers-contrast: more) {
+ --media-surface-background-color: oklch(1 0 0);
+ --media-surface-outer-border-color: oklch(0 0 0 / 0.05);
+ }
+
+ @media (prefers-color-scheme: dark) and ((prefers-reduced-transparency: reduce) or (prefers-contrast: more)) {
+ --media-surface-background-color: oklch(0 0 0);
+ --media-surface-inner-border-color: oklch(1 0 0 / 0.2);
+ --media-surface-outer-border-color: transparent;
+ }
}
/* ==========================================================================
diff --git a/packages/skins/src/default/css/components/button-group.css b/packages/skins/src/default/css/components/button-group.css
new file mode 100644
index 00000000..db840f7c
--- /dev/null
+++ b/packages/skins/src/default/css/components/button-group.css
@@ -0,0 +1,13 @@
+/* ==========================================================================
+ Button Groups
+ ========================================================================== */
+
+.media-default-skin .media-button-group {
+ display: flex;
+ align-items: center;
+ gap: 0.075rem;
+
+ @container media-root (width > 42rem) {
+ gap: 0.125rem;
+ }
+}
diff --git a/packages/skins/src/default/css/components/buttons.css b/packages/skins/src/default/css/components/button.css
similarity index 95%
rename from packages/skins/src/default/css/components/buttons.css
rename to packages/skins/src/default/css/components/button.css
index a55e8d07..06cfd69b 100644
--- a/packages/skins/src/default/css/components/buttons.css
+++ b/packages/skins/src/default/css/components/button.css
@@ -14,6 +14,8 @@
outline: 2px solid transparent;
outline-offset: -2px;
transition-property: background-color, outline-offset, scale;
+ /* Fix weird jumping when clicking on the buttons in Safari. */
+ will-change: scale;
transition-duration: 150ms;
transition-timing-function: ease-out;
cursor: pointer;
@@ -66,7 +68,7 @@
/* Icon button variant */
.media-default-skin .media-button--icon {
display: grid;
- width: 2.125rem;
+ width: 2.25rem;
padding: 0;
aspect-ratio: 1;
@@ -94,10 +96,6 @@
right: unset;
left: -1px;
}
-
- @container media-controls (width < 28rem) {
- display: none;
- }
}
/* Playback rate button */
diff --git a/packages/skins/src/default/css/components/captions.css b/packages/skins/src/default/css/components/captions.css
index 4b5dfa59..6976c469 100644
--- a/packages/skins/src/default/css/components/captions.css
+++ b/packages/skins/src/default/css/components/captions.css
@@ -4,11 +4,17 @@
.media-default-skin {
--media-caption-track-duration: var(--media-controls-transition-duration);
- --media-caption-track-delay: calc(var(--media-controls-transition-delay) + 25ms);
+ --media-caption-track-delay: 25ms;
--media-caption-track-y: -0.5rem;
&:has(.media-controls[data-visible]) {
- --media-caption-track-y: -3.5rem;
+ --media-caption-track-y: -5.5rem;
+ }
+
+ @container media-root (width > 42rem) {
+ &:has(.media-controls[data-visible]) > * {
+ --media-caption-track-y: -3.5rem;
+ }
}
}
diff --git a/packages/skins/src/default/css/components/controls.css b/packages/skins/src/default/css/components/controls.css
index 13cb7ef2..7c2f9447 100644
--- a/packages/skins/src/default/css/components/controls.css
+++ b/packages/skins/src/default/css/components/controls.css
@@ -6,18 +6,13 @@
container: media-controls / inline-size;
display: flex;
align-items: center;
- gap: 0.075rem;
- padding: 0.175rem;
- border-radius: calc(infinity * 1px);
+ column-gap: 0.075rem;
+ padding: 0.375rem;
+ border-radius: 1.5rem;
--media-controls-current-shadow-color: oklch(from currentColor 0 0 0 / clamp(0, calc((l - 0.5) * 0.5), 0.15));
--media-controls-current-shadow-color-subtle: oklch(
from var(--media-controls-current-shadow-color) l c h /
calc(alpha * 0.4)
);
text-shadow: 0 1px 0 var(--media-controls-current-shadow-color);
-
- @container media-root (width > 40rem) {
- gap: 0.125rem;
- padding: 0.25rem;
- }
}
diff --git a/packages/skins/src/default/css/components/overlay.css b/packages/skins/src/default/css/components/overlay.css
index 2a19f1b1..1fe0cf4d 100644
--- a/packages/skins/src/default/css/components/overlay.css
+++ b/packages/skins/src/default/css/components/overlay.css
@@ -7,12 +7,11 @@
inset: 0;
border-radius: inherit;
background-image: linear-gradient(to top, oklch(0 0 0 / 0.5), oklch(0 0 0 / 0.3), oklch(0 0 0 / 0));
- backdrop-filter: blur(0) saturate(1.5);
+ backdrop-filter: blur(0) saturate(1);
opacity: 0;
pointer-events: none;
transition-property: opacity, backdrop-filter;
transition-duration: var(--media-controls-transition-duration);
- transition-delay: var(--media-controls-transition-delay);
transition-timing-function: ease-out;
}
diff --git a/packages/skins/src/default/css/components/popup.css b/packages/skins/src/default/css/components/popup.css
index 5a6fa5ce..78d277c3 100644
--- a/packages/skins/src/default/css/components/popup.css
+++ b/packages/skins/src/default/css/components/popup.css
@@ -69,8 +69,6 @@
}
.media-default-skin .media-popover {
- --media-popover-side-offset: 0.5rem;
-
&[data-side="top"]::before,
&[data-side="bottom"]::before {
height: var(--media-popover-side-offset);
@@ -81,7 +79,7 @@
}
}
.media-default-skin .media-popover--volume {
- padding: 0.625rem 0.25rem;
+ padding: 0.75rem 0;
border-radius: calc(infinity * 1px);
&:has(media-volume-slider[data-availability="unsupported"]) {
@@ -94,7 +92,6 @@
border-radius: calc(infinity * 1px);
font-size: 0.75rem;
white-space: nowrap;
- --media-tooltip-side-offset: 0.75rem;
&[data-side="top"]::before,
&[data-side="bottom"]::before {
diff --git a/packages/skins/src/default/css/components/preview.css b/packages/skins/src/default/css/components/preview.css
index e2f141ec..03bfafc8 100644
--- a/packages/skins/src/default/css/components/preview.css
+++ b/packages/skins/src/default/css/components/preview.css
@@ -4,6 +4,7 @@
.media-default-skin .media-preview {
background-color: oklch(0 0 0 / 0.9);
border-radius: 0.75rem;
+ pointer-events: none;
& .media-preview__thumbnail {
display: block;
@@ -20,12 +21,11 @@
}
}
- & .media-preview__timestamp {
+ & .media-preview__time {
position: absolute;
bottom: 0.5rem;
inset-inline: 0;
text-align: center;
- font-variant-numeric: tabular-nums;
}
& .media-overlay {
diff --git a/packages/skins/src/default/css/components/root.css b/packages/skins/src/default/css/components/root.css
index 1d81f526..e8844311 100644
--- a/packages/skins/src/default/css/components/root.css
+++ b/packages/skins/src/default/css/components/root.css
@@ -3,12 +3,12 @@
========================================================================== */
.media-default-skin {
+ container: media-root / inline-size;
position: relative;
isolation: isolate;
display: block;
height: 100%;
width: 100%;
- container: media-root / inline-size;
border-radius: var(--media-border-radius, 2rem);
font-family:
Inter Variable,
@@ -16,9 +16,18 @@
ui-sans-serif,
system-ui,
sans-serif;
- font-size: 0.8125rem;
line-height: 1.5;
letter-spacing: normal;
-webkit-font-smoothing: auto;
-moz-osx-font-smoothing: auto;
+
+ & > * {
+ font-size: 0.75rem; /* 12px at 100% font size */
+ }
+
+ @container media-root (width > 48rem) {
+ & > * {
+ font-size: 0.875rem; /* 14px at 100% font size */
+ }
+ }
}
diff --git a/packages/skins/src/default/css/components/slider.css b/packages/skins/src/default/css/components/slider.css
index e639aba9..a23d85ac 100644
--- a/packages/skins/src/default/css/components/slider.css
+++ b/packages/skins/src/default/css/components/slider.css
@@ -15,11 +15,11 @@
&[data-orientation="horizontal"] {
min-width: 5rem;
width: 100%;
- height: 1.25rem;
+ height: 2rem;
}
&[data-orientation="vertical"] {
- width: 1.25rem;
+ width: 2rem;
height: 5rem;
}
}
diff --git a/packages/skins/src/default/css/components/surface.css b/packages/skins/src/default/css/components/surface.css
index 1c8c1b0b..2e2ae90b 100644
--- a/packages/skins/src/default/css/components/surface.css
+++ b/packages/skins/src/default/css/components/surface.css
@@ -20,12 +20,4 @@
box-shadow: inset 0 0 0 1px var(--media-surface-inner-border-color);
pointer-events: none;
}
-
- @media (prefers-reduced-transparency: reduce) {
- background-color: oklch(from var(--media-surface-background-color) l c h / 0.7);
- }
-
- @media (prefers-contrast: more) {
- background-color: oklch(from var(--media-surface-background-color) l c h / 0.9);
- }
}
diff --git a/packages/skins/src/default/css/components/time.css b/packages/skins/src/default/css/components/time.css
index 941f6f48..c205c34b 100644
--- a/packages/skins/src/default/css/components/time.css
+++ b/packages/skins/src/default/css/components/time.css
@@ -2,23 +2,15 @@
Time Display
========================================================================== */
-.media-default-skin .media-time {
- container: media-time / inline-size;
+.media-default-skin .media-time-controls {
+ container: media-time-controls / inline-size;
display: flex;
align-items: center;
flex: 1;
gap: 0.75rem;
padding-inline: 0.5rem;
-
- & .media-time__value:first-child {
- display: none;
-
- @container media-time (width > 18rem) {
- display: block;
- }
- }
}
-.media-default-skin .media-time__value {
+.media-default-skin .media-time {
font-variant-numeric: tabular-nums;
}
diff --git a/packages/skins/src/default/css/video.css b/packages/skins/src/default/css/video.css
index 7e1c9744..7a1e7893 100644
--- a/packages/skins/src/default/css/video.css
+++ b/packages/skins/src/default/css/video.css
@@ -7,7 +7,8 @@
@import "./components/error.css";
@import "./components/controls.css";
@import "./components/time.css";
-@import "./components/buttons.css";
+@import "./components/button.css";
+@import "./components/button-group.css";
@import "./components/icons.css";
@import "./components/poster.css";
@import "./components/preview.css";
@@ -42,13 +43,14 @@
--media-surface-backdrop-filter: blur(16px) saturate(1.5);
--media-video-border-radius: var(--media-border-radius, 2rem);
--media-controls-transition-duration: 100ms;
- --media-controls-transition-delay: 0ms;
--media-controls-transition-timing-function: ease-out;
--media-error-dialog-transition-duration: 350ms;
--media-error-dialog-transition-delay: 100ms;
--media-error-dialog-transition-timing-function: var(--media-spring-transition);
--media-popup-transition-duration: 100ms;
--media-popup-transition-timing-function: ease-out;
+ --media-tooltip-side-offset: 0.75rem;
+ --media-popover-side-offset: 0.5rem;
@media (prefers-reduced-motion: reduce) {
--media-error-dialog-transition-duration: 50ms;
@@ -61,10 +63,15 @@
--media-border-color: oklch(1 0 0 / 0.15);
}
+ @media (prefers-reduced-transparency: reduce) or (prefers-contrast: more) {
+ --media-surface-background-color: oklch(0 0 0);
+ --media-surface-inner-border-color: oklch(1 0 0 / 0.25);
+ --media-surface-outer-border-color: transparent;
+ }
+
&:has(.media-controls:not([data-visible])) {
/* Slight delay to hide controls on non-touch devices after interaction */
@media (pointer: fine) {
- --media-controls-transition-delay: 500ms;
--media-controls-transition-duration: 300ms;
}
@media (pointer: coarse) {
@@ -145,13 +152,13 @@
========================================================================== */
.media-default-skin--video .media-controls {
+ flex-wrap: wrap;
position: absolute;
- bottom: 0.75rem;
- inset-inline: 0.75rem;
+ bottom: 0.5rem;
+ inset-inline: 0.5rem;
z-index: 10;
color: var(--media-color-primary, oklch(1 0 0));
transition-duration: var(--media-controls-transition-duration);
- transition-delay: var(--media-controls-transition-delay);
transition-timing-function: var(--media-controls-transition-timing-function);
transform-origin: bottom;
@@ -178,17 +185,49 @@
scale: 1;
}
}
+
+ & .media-time-controls {
+ order: -1;
+ flex: 0 0 100%;
+ padding-inline: 0.625rem;
+ }
+
+ & .media-button-group:first-child {
+ flex: 1;
+ text-align: left;
+ }
+
+ & .media-button-group:last-child {
+ flex: 1;
+ justify-content: end;
+ }
+
+ @container media-root (width > 42rem) {
+ bottom: 0.75rem;
+ inset-inline: 0.75rem;
+ flex-wrap: nowrap;
+ column-gap: 0.125rem;
+ padding: 0.25rem;
+
+ & .media-time-controls {
+ order: unset;
+ flex: 1;
+ }
+
+ & .media-button-group:first-child,
+ & .media-button-group:last-child {
+ flex: 0 0 auto;
+ }
+ }
}
.media-default-skin--video .media-error[data-open] ~ .media-controls {
display: none;
}
-/* Hide cursor when controls are hidden in fullscreen */
-@media (pointer: fine) {
- .media-default-skin--video:fullscreen:has(.media-controls:not([data-visible])) {
- cursor: none;
- }
+/* Hide cursor when controls are hidden */
+.media-default-skin--video:has(.media-controls:not([data-visible])) {
+ cursor: none;
}
/* ==========================================================================
@@ -201,8 +240,20 @@
}
.media-default-skin--video .media-slider__preview {
+ --media-preview-max-width: 11rem;
+ --media-preview-padding: -1.125rem;
+ /**
+ Inset is the difference between the container width and the slider (100%) width.
+ Divided by 2 as we render the time on both sides.
+ */
+ --media-preview-inset: calc((100cqi - 100%) / 2);
+
position: absolute;
- left: var(--media-slider-pointer);
+ left: clamp(
+ calc(var(--media-preview-max-width) / 2 + var(--media-preview-padding) - var(--media-preview-inset)),
+ var(--media-slider-pointer),
+ calc(100% - var(--media-preview-max-width) / 2 - var(--media-preview-padding) + var(--media-preview-inset))
+ );
bottom: calc(100% + 1.2rem);
translate: -50%;
opacity: 0;
@@ -215,7 +266,7 @@
pointer-events: none;
& .media-preview__thumbnail {
- max-width: 11rem;
+ max-width: var(--media-preview-max-width);
}
&:has(.media-preview__thumbnail[data-loading]) {
diff --git a/packages/skins/src/default/tailwind/audio.tailwind.ts b/packages/skins/src/default/tailwind/audio.tailwind.ts
index 250c4c29..ae577b04 100644
--- a/packages/skins/src/default/tailwind/audio.tailwind.ts
+++ b/packages/skins/src/default/tailwind/audio.tailwind.ts
@@ -5,7 +5,7 @@ import { error as baseError } from './components/error';
import { popup as basePopup } from './components/popup';
import { root as baseRoot } from './components/root';
import { slider as baseSlider } from './components/slider';
-import { surface as baseSurface } from './components/surface';
+import { surface } from './components/surface';
/* ==========================================================================
Root
@@ -14,32 +14,32 @@ import { surface as baseSurface } from './components/surface';
export const root = cn(
baseRoot,
'[--media-text-color:var(--media-color-primary,oklch(0_0_0))]',
+ '[--media-surface-background-color:oklch(1_0_0/0.5)]',
+ '[--media-surface-inner-border-color:oklch(1_0_0/0.1)]',
+ '[--media-surface-outer-border-color:oklch(0_0_0/0.05)]',
+ '[--media-surface-shadow-color:oklch(0_0_0/0.15)]',
+ '[--media-surface-backdrop-filter:blur(16px)_saturate(1.5)]',
'[--media-error-dialog-transition-duration:250ms]',
'[--media-error-dialog-transition-delay:100ms]',
'[--media-popup-transition-duration:100ms]',
'[--media-popup-transition-timing-function:ease-out]',
+ '[--media-tooltip-side-offset:0.75rem]',
+ '[--media-popover-side-offset:0.75rem]',
'motion-reduce:[--media-error-dialog-transition-duration:50ms]',
'motion-reduce:[--media-error-dialog-transition-delay:0ms]',
'motion-reduce:[--media-popup-transition-duration:0ms]',
- 'dark:[--media-text-color:var(--media-color-primary,oklch(1_0_0))]'
-);
-
-/* ==========================================================================
- Surface (shared glass effect for tooltips, popovers, controls)
- ========================================================================== */
-
-export const surface = cn(
- baseSurface,
- 'bg-white/50 dark:bg-black/40',
- 'backdrop-blur-lg backdrop-saturate-150',
- // Border and shadow
- 'ring-black/5 shadow-sm shadow-black/15',
- // Border to enhance contrast on lighter pages
- 'after:ring-white/10',
- // Reduced transparency for users with preference
- '[@media(prefers-reduced-transparency:reduce)]:bg-white/70 dark:[@media(prefers-reduced-transparency:reduce)]:bg-black/70',
- // High contrast mode
- 'contrast-more:bg-white/90 dark:contrast-more:bg-black/90'
+ 'dark:[--media-surface-background-color:oklch(0_0_0/0.4)]',
+ 'dark:[--media-text-color:var(--media-color-primary,oklch(1_0_0))]',
+ '[@media(prefers-reduced-transparency:reduce)]:[--media-surface-background-color:oklch(1_0_0)]',
+ 'contrast-more:[--media-surface-background-color:oklch(1_0_0)]',
+ '[@media(prefers-reduced-transparency:reduce)]:[--media-surface-outer-border-color:oklch(0_0_0/0.05)]',
+ 'contrast-more:[--media-surface-outer-border-color:oklch(0_0_0/0.05)]',
+ 'dark:[@media(prefers-reduced-transparency:reduce)]:[--media-surface-background-color:oklch(0_0_0)]',
+ 'dark:contrast-more:[--media-surface-background-color:oklch(0_0_0)]',
+ 'dark:[@media(prefers-reduced-transparency:reduce)]:[--media-surface-inner-border-color:oklch(1_0_0/0.2)]',
+ 'dark:contrast-more:[--media-surface-inner-border-color:oklch(1_0_0/0.2)]',
+ 'dark:[@media(prefers-reduced-transparency:reduce)]:[--media-surface-outer-border-color:transparent]',
+ 'dark:contrast-more:[--media-surface-outer-border-color:transparent]'
);
/* ==========================================================================
@@ -89,8 +89,8 @@ export const error = {
'transition-[opacity,filter] ease-out',
'duration-(--media-error-dialog-transition-duration)',
'delay-(--media-error-dialog-transition-delay)',
- 'group-data-starting-style/error:opacity-0 group-data-starting-style/error:blur-[4px]',
- 'group-data-ending-style/error:opacity-0 group-data-ending-style/error:blur-[4px]',
+ 'group-data-starting-style/error:opacity-0 group-data-starting-style/error:blur-xs',
+ 'group-data-ending-style/error:opacity-0 group-data-ending-style/error:blur-xs',
'group-data-ending-style/error:delay-0'
),
content: 'flex flex-1 items-center gap-2',
@@ -103,6 +103,7 @@ export const error = {
export { iconState } from '../../shared/tailwind/icon-state';
export { tooltipState } from '../../shared/tailwind/tooltip-state';
export { button } from './components/button';
+export { buttonGroup } from './components/button-group';
export { icon, iconContainer, iconFlipped, iconHidden } from './components/icon';
export { playbackRate } from './components/playback-rate';
export { seek } from './components/seek';
diff --git a/packages/skins/src/default/tailwind/components/button-group.ts b/packages/skins/src/default/tailwind/components/button-group.ts
new file mode 100644
index 00000000..143d2b02
--- /dev/null
+++ b/packages/skins/src/default/tailwind/components/button-group.ts
@@ -0,0 +1,3 @@
+import { cn } from '@videojs/utils/style';
+
+export const buttonGroup = cn('flex items-center gap-[0.075rem]', '@2xl/media-root:gap-0.5');
diff --git a/packages/skins/src/default/tailwind/components/button.ts b/packages/skins/src/default/tailwind/components/button.ts
index 5dfc07f2..813d6978 100644
--- a/packages/skins/src/default/tailwind/components/button.ts
+++ b/packages/skins/src/default/tailwind/components/button.ts
@@ -5,7 +5,7 @@ export const button = {
'flex items-center justify-center shrink-0 border-none cursor-pointer select-none text-center touch-manipulation',
'py-2 px-4 rounded-full',
'outline-2 outline-transparent -outline-offset-2',
- 'transition-[background-color,outline-offset,scale] duration-150 ease-out',
+ 'transition-[background-color,outline-offset,scale] will-change-[scale] duration-150 ease-out',
'active:scale-[0.98]',
'disabled:cursor-not-allowed disabled:opacity-50 disabled:grayscale',
'focus-visible:outline-current focus-visible:outline-offset-2',
@@ -18,5 +18,5 @@ export const button = {
'focus-visible:bg-current/10',
'aria-expanded:bg-current/10'
),
- icon: cn('grid w-[2.125rem] aspect-square p-0', 'active:scale-90'),
+ icon: cn('grid w-9 aspect-square p-0', 'active:scale-90'),
};
diff --git a/packages/skins/src/default/tailwind/components/controls.ts b/packages/skins/src/default/tailwind/components/controls.ts
index 9f718e5d..25092f12 100644
--- a/packages/skins/src/default/tailwind/components/controls.ts
+++ b/packages/skins/src/default/tailwind/components/controls.ts
@@ -5,13 +5,11 @@ export const controls = cn(
'peer/controls',
// Layout
'@container/media-controls',
- 'p-[0.175rem] flex items-center gap-[0.075rem]',
- 'rounded-full',
+ 'p-[0.375rem] flex items-center gap-x-[0.075rem]',
+ 'rounded-3xl',
// Shadow color variables (derived from currentColor lightness)
'[--media-controls-current-shadow-color:oklch(from_currentColor_0_0_0/clamp(0,calc((l-0.5)*0.5),0.15))]',
'[--media-controls-current-shadow-color-subtle:oklch(from_var(--media-controls-current-shadow-color)_l_c_h/calc(alpha*0.4))]',
// Text shadow
- 'text-shadow-[0_1px_0_var(--media-controls-current-shadow-color)]',
- // Wider container
- '@2xl/media-root:p-1 @2xl/media-root:gap-0.5'
+ 'text-shadow-2xs text-shadow-(color:--media-controls-current-shadow-color)'
);
diff --git a/packages/skins/src/default/tailwind/components/overlay.ts b/packages/skins/src/default/tailwind/components/overlay.ts
index 5630f020..f079574f 100644
--- a/packages/skins/src/default/tailwind/components/overlay.ts
+++ b/packages/skins/src/default/tailwind/components/overlay.ts
@@ -7,11 +7,10 @@ export const overlay = cn(
// Default: hidden
'opacity-0',
'bg-linear-to-t from-black/50 via-black/30 to-transparent',
- 'backdrop-blur-none backdrop-saturate-150',
+ 'backdrop-blur-none backdrop-saturate-100',
// Transitions
'transition-[opacity,backdrop-filter]',
'duration-(--media-controls-transition-duration)',
- 'delay-(--media-controls-transition-delay)',
'ease-out',
// Shown when controls visible
'peer-data-visible/controls:opacity-100',
@@ -19,5 +18,5 @@ export const overlay = cn(
'peer-data-open/error:opacity-100',
'peer-data-open/error:duration-(--media-error-dialog-transition-duration)',
'peer-data-open/error:delay-(--media-error-dialog-transition-delay)',
- 'peer-data-open/error:backdrop-blur-lg'
+ 'peer-data-open/error:backdrop-blur-lg peer-data-open/error:backdrop-saturate-150'
);
diff --git a/packages/skins/src/default/tailwind/components/popup.ts b/packages/skins/src/default/tailwind/components/popup.ts
index c693d167..a18bf244 100644
--- a/packages/skins/src/default/tailwind/components/popup.ts
+++ b/packages/skins/src/default/tailwind/components/popup.ts
@@ -23,16 +23,14 @@ const base = cn(
export const popup = {
popover: cn(
base,
- '[--media-popover-side-offset:0.5rem]',
'data-[side=top]:before:h-(--media-popover-side-offset) data-[side=bottom]:before:h-(--media-popover-side-offset)',
'data-[side=left]:before:w-(--media-popover-side-offset) data-[side=right]:before:w-(--media-popover-side-offset)'
),
tooltip: cn(
base,
'py-1 px-2.5 rounded-full text-[0.75rem] whitespace-nowrap',
- '[--media-tooltip-side-offset:0.75rem]',
'data-[side=top]:before:h-(--media-tooltip-side-offset) data-[side=bottom]:before:h-(--media-tooltip-side-offset)',
'data-[side=left]:before:w-(--media-tooltip-side-offset) data-[side=right]:before:w-(--media-tooltip-side-offset)'
),
- volume: 'py-2.5 px-1 rounded-full',
+ volume: 'py-3 px-0 rounded-full',
};
diff --git a/packages/skins/src/default/tailwind/components/preview.ts b/packages/skins/src/default/tailwind/components/preview.ts
index 58ed996e..66713fcd 100644
--- a/packages/skins/src/default/tailwind/components/preview.ts
+++ b/packages/skins/src/default/tailwind/components/preview.ts
@@ -9,7 +9,7 @@ export const preview = {
'after:bg-linear-to-t after:from-black/80 after:via-black/30 after:to-black/0',
'data-loading:opacity-0'
),
- timestamp: 'absolute bottom-2 inset-x-0 text-center tabular-nums',
+ time: 'absolute bottom-2 inset-x-0 text-center tabular-nums',
spinner: cn(
'absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-0',
'transition-opacity duration-150 ease-out',
diff --git a/packages/skins/src/default/tailwind/components/root.ts b/packages/skins/src/default/tailwind/components/root.ts
index ffcaa973..bc354004 100644
--- a/packages/skins/src/default/tailwind/components/root.ts
+++ b/packages/skins/src/default/tailwind/components/root.ts
@@ -5,7 +5,8 @@ export const root = cn(
'block relative isolate h-full w-full @container/media-root',
// Appearance
'rounded-(--media-border-radius,2rem)',
- 'font-[Inter_Variable,Inter,ui-sans-serif,system-ui,sans-serif] text-[0.8125rem] leading-normal subpixel-antialiased',
+ 'font-[Inter_Variable,Inter,ui-sans-serif,system-ui,sans-serif] leading-normal subpixel-antialiased',
+ '[&>*]:text-xs @3xl/media-root:[&>*]:text-sm',
// Resets
'**:box-border',
'[&_button]:font-[inherit]',
diff --git a/packages/skins/src/default/tailwind/components/seek.ts b/packages/skins/src/default/tailwind/components/seek.ts
index 03c2b51f..2b319821 100644
--- a/packages/skins/src/default/tailwind/components/seek.ts
+++ b/packages/skins/src/default/tailwind/components/seek.ts
@@ -1,5 +1,4 @@
export const seek = {
- button: '@max-md/media-controls:hidden',
label: 'text-[10px] font-[480] tabular-nums',
labelForward: 'absolute -right-px -bottom-0.75',
labelBackward: 'absolute -left-px -bottom-0.75',
diff --git a/packages/skins/src/default/tailwind/components/slider.ts b/packages/skins/src/default/tailwind/components/slider.ts
index 9fc72188..a72eef39 100644
--- a/packages/skins/src/default/tailwind/components/slider.ts
+++ b/packages/skins/src/default/tailwind/components/slider.ts
@@ -4,9 +4,9 @@ export const slider = {
root: cn(
'group/slider relative flex flex-1 items-center justify-center rounded-full outline-none cursor-pointer',
// Horizontal
- 'data-[orientation=horizontal]:min-w-20 data-[orientation=horizontal]:w-full data-[orientation=horizontal]:h-5',
+ 'data-[orientation=horizontal]:min-w-20 data-[orientation=horizontal]:w-full data-[orientation=horizontal]:h-8',
// Vertical
- 'data-[orientation=vertical]:w-5 data-[orientation=vertical]:h-20'
+ 'data-[orientation=vertical]:w-8 data-[orientation=vertical]:h-20'
),
track: cn(
'relative isolate overflow-hidden rounded-[inherit] select-none',
diff --git a/packages/skins/src/default/tailwind/components/surface.ts b/packages/skins/src/default/tailwind/components/surface.ts
index 9639ef35..97b61e96 100644
--- a/packages/skins/src/default/tailwind/components/surface.ts
+++ b/packages/skins/src/default/tailwind/components/surface.ts
@@ -1,8 +1,8 @@
import { cn } from '@videojs/utils/style';
export const surface = cn(
- // Border and shadow
- 'ring shadow-sm',
- // Border to enhance contrast on lighter videos
- 'after:absolute after:inset-0 after:ring after:ring-inset after:rounded-[inherit] after:pointer-events-none after:z-10'
+ 'bg-(--media-surface-background-color)',
+ '[backdrop-filter:var(--media-surface-backdrop-filter)]',
+ '[box-shadow:0_0_0_1px_var(--media-surface-outer-border-color),0_1px_3px_0_var(--media-surface-shadow-color),0_1px_2px_-1px_var(--media-surface-shadow-color)]',
+ 'after:absolute after:inset-0 after:[box-shadow:inset_0_0_0_1px_var(--media-surface-inner-border-color)] after:rounded-[inherit] after:pointer-events-none after:z-10'
);
diff --git a/packages/skins/src/default/tailwind/video.tailwind.ts b/packages/skins/src/default/tailwind/video.tailwind.ts
index bb7d0f13..7f357da6 100644
--- a/packages/skins/src/default/tailwind/video.tailwind.ts
+++ b/packages/skins/src/default/tailwind/video.tailwind.ts
@@ -1,12 +1,14 @@
import { cn } from '@videojs/utils/style';
import { bufferingIndicator as baseBufferingIndicator } from './components/buffering';
+import { buttonGroup as baseButtonGroup } from './components/button-group';
import { controls as baseControls } from './components/controls';
import { error as baseError } from './components/error';
import { popup as basePopup } from './components/popup';
import { preview as basePreview } from './components/preview';
import { root as baseRoot } from './components/root';
import { slider as baseSlider } from './components/slider';
-import { surface as baseSurface } from './components/surface';
+import { surface } from './components/surface';
+import { time as baseTime } from './components/time';
/* ==========================================================================
Root
@@ -29,26 +31,38 @@ export const root = (isShadowDOM: boolean) =>
'[--media-spring-transition:linear(0,0.034_1.5%,0.763_9.7%,1.066_13.9%,1.198_19.9%,1.184_21.8%,0.963_37.5%,0.997_50.9%,1)]',
'[--media-video-border-radius:var(--media-border-radius,2rem)]',
'[--media-controls-transition-duration:100ms]',
- '[--media-controls-transition-delay:0ms]',
'[--media-controls-transition-timing-function:ease-out]',
'[--media-error-dialog-transition-duration:350ms]',
'[--media-error-dialog-transition-delay:100ms]',
'[--media-error-dialog-transition-timing-function:var(--media-spring-transition)]',
'[--media-popup-transition-duration:100ms]',
'[--media-popup-transition-timing-function:ease-out]',
+ '[--media-surface-background-color:oklch(1_0_0/0.1)]',
+ '[--media-surface-inner-border-color:oklch(1_0_0/0.05)]',
+ '[--media-surface-outer-border-color:oklch(0_0_0/0.1)]',
+ '[--media-surface-shadow-color:oklch(0_0_0/0.15)]',
+ '[--media-surface-backdrop-filter:blur(16px)_saturate(1.5)]',
'motion-reduce:[--media-error-dialog-transition-duration:50ms]',
'motion-reduce:[--media-error-dialog-transition-delay:0ms]',
'motion-reduce:[--media-error-dialog-transition-timing-function:ease-out]',
+ '[--media-tooltip-side-offset:0.75rem]',
+ '[--media-popover-side-offset:0.5rem]',
'motion-reduce:[--media-popup-transition-duration:0ms]',
- '[@media(pointer:fine)]:has-[[data-controls]:not([data-visible])]:[--media-controls-transition-delay:500ms]',
+ '[@media(prefers-reduced-transparency:reduce)]:[--media-surface-background-color:oklch(0_0_0)]',
+ 'contrast-more:[--media-surface-background-color:oklch(0_0_0)]',
+ '[@media(prefers-reduced-transparency:reduce)]:[--media-surface-inner-border-color:oklch(1_0_0/0.25)]',
+ 'contrast-more:[--media-surface-inner-border-color:oklch(1_0_0/0.25)]',
+ '[@media(prefers-reduced-transparency:reduce)]:[--media-surface-outer-border-color:transparent]',
+ 'contrast-more:[--media-surface-outer-border-color:transparent]',
'[@media(pointer:fine)]:has-[[data-controls]:not([data-visible])]:[--media-controls-transition-duration:300ms]',
'[@media(pointer:coarse)]:has-[[data-controls]:not([data-visible])]:[--media-controls-transition-duration:150ms]',
'motion-reduce:has-[[data-controls]:not([data-visible])]:[--media-controls-transition-duration:50ms]',
// Caption track CSS variables (consumed by the native caption bridge in light DOM)
'[--media-caption-track-y:-0.5rem]',
- '[--media-caption-track-delay:calc(var(--media-controls-transition-delay)_+_25ms)]',
+ '[--media-caption-track-delay:25ms]',
'[--media-caption-track-duration:var(--media-controls-transition-duration)]',
- 'has-[[data-controls][data-visible]]:[--media-caption-track-y:-3.5rem]',
+ 'has-[[data-controls][data-visible]]:[--media-caption-track-y:-5.5rem]',
+ '@2xl/media-root:has-[[data-controls][data-visible]]:[&>*]:[--media-caption-track-y:-3.5rem]',
// Native caption track container
!isShadowDOM
? [
@@ -70,24 +84,6 @@ export const root = (isShadowDOM: boolean) =>
}
);
-/* ==========================================================================
- Surface (shared glass effect for tooltips, popovers, controls)
- ========================================================================== */
-
-export const surface = cn(
- baseSurface,
- 'bg-white/10',
- 'backdrop-saturate-150 backdrop-blur-lg',
- // Border and shadow
- 'ring-black/15 shadow-black/10',
- // Border to enhance contrast on lighter videos
- 'after:ring-white/5',
- // Reduced transparency for users with preference
- '[@media(prefers-reduced-transparency:reduce)]:bg-black/70',
- // High contrast mode
- 'contrast-more:bg-black/90'
-);
-
/* ==========================================================================
Controls (hide/show behavior)
========================================================================== */
@@ -95,13 +91,12 @@ export const surface = cn(
export const controls = cn(
baseControls,
surface,
- // Position
- 'absolute bottom-3 inset-x-3',
+ // Position & wrapping layout (small)
+ 'absolute bottom-2 inset-x-2 flex-wrap',
'[color:var(--media-color-primary,oklch(1_0_0))] z-10',
'peer-data-open/error:hidden',
'ease-(--media-controls-transition-timing-function) origin-bottom',
'duration-(--media-controls-transition-duration)',
- 'delay-(--media-controls-transition-delay)',
'[@media(pointer:fine)]:will-change-[scale,filter,opacity]',
'[@media(pointer:fine)]:transition-[scale,filter,opacity]',
'[@media(pointer:coarse)]:will-change-[scale,opacity]',
@@ -109,9 +104,31 @@ export const controls = cn(
// Hidden state
'not-data-visible:pointer-events-none not-data-visible:opacity-0',
'motion-safe:not-data-visible:scale-90',
- '[@media(pointer:fine)]:motion-safe:not-data-visible:blur-sm'
+ '[@media(pointer:fine)]:motion-safe:not-data-visible:blur-sm',
+ // Single-row layout (large)
+ '@2xl/media-root:bottom-3 @2xl/media-root:inset-x-3 @2xl/media-root:flex-nowrap @2xl/media-root:gap-x-0.5 @2xl/media-root:p-1'
);
+/* ==========================================================================
+ Button groups
+ ========================================================================== */
+
+export const buttonGroupStart = cn(baseButtonGroup, 'flex-1 @2xl/media-root:flex-none');
+export const buttonGroupEnd = cn(baseButtonGroup, 'flex-1 justify-end @2xl/media-root:flex-none');
+
+/* ==========================================================================
+ Time
+ ========================================================================== */
+
+export const time = {
+ ...baseTime,
+ group: cn(
+ baseTime.group,
+ 'grow-0 shrink-0 basis-full order-[-1] px-2.5',
+ '@2xl/media-root:grow @2xl/media-root:shrink @2xl/media-root:basis-0 @2xl/media-root:order-[unset]'
+ ),
+};
+
/* ==========================================================================
Preview (with video surface)
========================================================================== */
@@ -119,7 +136,8 @@ export const controls = cn(
export const preview = {
...basePreview,
root: cn(
- 'absolute left-(--media-slider-pointer) bottom-[calc(100%+1.2rem)] -translate-x-1/2',
+ '[--media-preview-max-width:11rem] [--media-preview-padding:-1.125rem] [--media-preview-inset:calc((100cqi-100%)/2)]',
+ 'absolute [left:clamp(calc(var(--media-preview-max-width)/2+var(--media-preview-padding)-var(--media-preview-inset)),var(--media-slider-pointer),calc(100%-var(--media-preview-max-width)/2-var(--media-preview-padding)+var(--media-preview-inset)))] bottom-[calc(100%+1.2rem)] -translate-x-1/2',
'opacity-0 scale-80 blur-sm origin-bottom',
'transition-[scale,opacity,filter] duration-150',
'group-data-pointing/slider:opacity-100 group-data-pointing/slider:scale-100 group-data-pointing/slider:blur-none',
@@ -128,7 +146,7 @@ export const preview = {
surface,
basePreview.root
),
- thumbnail: cn(basePreview.thumbnail, 'max-w-44'),
+ thumbnail: cn(basePreview.thumbnail, 'max-w-(--media-preview-max-width)'),
};
/* ==========================================================================
@@ -137,7 +155,7 @@ export const preview = {
export const slider = {
...baseSlider,
- track: cn(baseSlider.track, 'bg-white/20 shadow-[0_0_0_1px_oklch(0_0_0/0.05)]'),
+ track: cn(baseSlider.track, 'bg-white/20 ring-1 ring-black/5'),
};
/* ==========================================================================
@@ -165,7 +183,7 @@ export const bufferingIndicator = {
export const error = {
...baseError,
- dialog: cn(baseError.dialog, surface, 'text-shadow-[0_1px_0_oklch(0_0_0/0.25)]'),
+ dialog: cn(baseError.dialog, surface, 'text-shadow-2xs text-shadow-black/25'),
content: cn(baseError.content, 'text-shadow-inherit'),
title: cn(baseError.title, 'text-base'),
};
@@ -177,9 +195,9 @@ export const error = {
export { iconState } from '../../shared/tailwind/icon-state';
export { tooltipState } from '../../shared/tailwind/tooltip-state';
export { button } from './components/button';
+export { buttonGroup } from './components/button-group';
export { icon, iconContainer, iconFlipped, iconHidden } from './components/icon';
export { overlay } from './components/overlay';
export { playbackRate } from './components/playback-rate';
export { poster } from './components/poster';
export { seek } from './components/seek';
-export { time } from './components/time';
diff --git a/packages/skins/src/minimal/css/audio.css b/packages/skins/src/minimal/css/audio.css
index 498e4c90..04ab4d93 100644
--- a/packages/skins/src/minimal/css/audio.css
+++ b/packages/skins/src/minimal/css/audio.css
@@ -4,7 +4,8 @@
@import "./components/error.css";
@import "./components/controls.css";
@import "./components/time.css";
-@import "./components/buttons.css";
+@import "./components/button.css";
+@import "./components/button-group.css";
@import "./components/icons.css";
@import "./components/slider.css";
@import "./components/popup.css";
@@ -17,13 +18,19 @@
.media-minimal-skin--audio {
--media-controls-background-color: oklch(1 0 0);
- --media-controls-border-color: oklch(0 0 0 / 0.1);
- --media-controls-padding: 0.375rem;
- --media-text-color: var(--media-color-primary, oklch(0 0 0));
+ --media-controls-backdrop-filter: blur(16px) saturate(1.5);
+ --media-controls-border-color: oklch(0 0 0 / 0.05);
+ --media-controls-text-color: var(--media-color-primary, oklch(0 0 0));
--media-error-dialog-transition-duration: 250ms;
--media-error-dialog-transition-delay: 100ms;
--media-popup-transition-duration: 100ms;
--media-popup-transition-timing-function: ease-out;
+ --media-tooltip-background-color: oklch(1 0 0 / 0.1);
+ --media-tooltip-border-color: oklch(0 0 0 / 0.05);
+ --media-tooltip-backdrop-filter: blur(16px) saturate(1.5);
+ --media-tooltip-text-color: currentColor;
+ --media-tooltip-side-offset: 0.75rem;
+ --media-popover-side-offset: 0.75rem;
@media (prefers-reduced-motion: reduce) {
--media-error-dialog-transition-duration: 50ms;
@@ -34,7 +41,15 @@
@media (prefers-color-scheme: dark) {
--media-controls-background-color: oklch(0 0 0);
--media-controls-border-color: oklch(1 0 0 / 0.1);
- --media-text-color: var(--media-color-primary, oklch(1 0 0));
+ --media-controls-text-color: var(--media-color-primary, oklch(1 0 0));
+ }
+
+ @media (prefers-reduced-transparency: reduce) or (prefers-contrast: more) {
+ --media-tooltip-background-color: oklch(1 0 0);
+ }
+
+ @media (prefers-color-scheme: dark) and ((prefers-reduced-transparency: reduce) or (prefers-contrast: more)) {
+ --media-tooltip-background-color: oklch(0 0 0);
}
}
@@ -80,13 +95,11 @@
========================================================================== */
.media-minimal-skin--audio .media-controls {
+ padding: 0.375rem;
gap: 0.5rem;
- padding: var(--media-controls-padding);
- background-color: var(--media-controls-background-color);
- backdrop-filter: blur(16px) saturate(1.5);
- border-radius: var(--media-controls-radius);
- color: var(--media-text-color);
+ color: var(--media-controls-text-color);
box-shadow: 0 0 0 1px var(--media-controls-border-color);
+ border-radius: var(--media-border-radius, 1rem);
}
/* ==========================================================================
@@ -95,6 +108,5 @@
.media-minimal-skin--audio .media-popover--volume {
background: linear-gradient(to left, var(--media-controls-background-color) 80%, transparent 100%);
- padding: 0.5rem 0 0.5rem 4rem;
- --media-popover-side-offset: 0.75rem;
+ padding: 0 0 0 4rem;
}
diff --git a/packages/skins/src/minimal/css/components/button-group.css b/packages/skins/src/minimal/css/components/button-group.css
new file mode 100644
index 00000000..54131548
--- /dev/null
+++ b/packages/skins/src/minimal/css/components/button-group.css
@@ -0,0 +1,13 @@
+/* ==========================================================================
+ Button Groups
+ ========================================================================== */
+
+.media-minimal-skin .media-button-group {
+ display: flex;
+ align-items: center;
+ gap: 0.075rem;
+
+ @container media-root (width > 42rem) {
+ gap: 0.125rem;
+ }
+}
diff --git a/packages/skins/src/minimal/css/components/buttons.css b/packages/skins/src/minimal/css/components/button.css
similarity index 81%
rename from packages/skins/src/minimal/css/components/buttons.css
rename to packages/skins/src/minimal/css/components/button.css
index 9c33a293..cdf75e9b 100644
--- a/packages/skins/src/minimal/css/components/buttons.css
+++ b/packages/skins/src/minimal/css/components/button.css
@@ -1,17 +1,3 @@
-/* ==========================================================================
- Button Groups
- ========================================================================== */
-
-.media-minimal-skin .media-button-group {
- display: flex;
- align-items: center;
- gap: 0.075rem;
-
- @container media-root (width > 40rem) {
- gap: 0.125rem;
- }
-}
-
/* ==========================================================================
Buttons
========================================================================== */
@@ -24,10 +10,12 @@
flex-shrink: 0;
padding: 0.5rem 1rem;
border: none;
- border-radius: calc(var(--media-controls-radius) - var(--media-controls-padding));
+ border-radius: 0.5rem;
outline: 2px solid transparent;
outline-offset: -2px;
transition-property: background-color, outline-offset, scale;
+ /* Fix weird jumping when clicking on the buttons in Safari. */
+ will-change: scale;
transition-duration: 150ms;
transition-timing-function: ease-out;
cursor: pointer;
@@ -58,7 +46,7 @@
/* biome-ignore lint/correctness/noUnknownProperty: corner-shape is an emerging CSS spec */
@supports (corner-shape: squircle) {
.media-minimal-skin .media-button {
- border-radius: var(--media-controls-radius);
+ border-radius: 1rem;
/* biome-ignore lint/correctness/noUnknownProperty: corner-shape is an emerging CSS spec */
corner-shape: squircle;
}
@@ -107,7 +95,7 @@
position: absolute;
right: -1px;
bottom: -3px;
- font-size: 10px;
+ font-size: 10px; /* Hard coded due to size limitations. */
font-weight: 480;
font-variant-numeric: tabular-nums;
}
@@ -116,10 +104,6 @@
right: unset;
left: -1px;
}
-
- @container media-controls (width < 28rem) {
- display: none;
- }
}
/* Playback rate button */
diff --git a/packages/skins/src/minimal/css/components/captions.css b/packages/skins/src/minimal/css/components/captions.css
index a092ac7c..32ffdcb8 100644
--- a/packages/skins/src/minimal/css/components/captions.css
+++ b/packages/skins/src/minimal/css/components/captions.css
@@ -4,11 +4,17 @@
.media-minimal-skin {
--media-caption-track-duration: var(--media-controls-transition-duration);
- --media-caption-track-delay: calc(var(--media-controls-transition-delay) + 25ms);
+ --media-caption-track-delay: 25ms;
--media-caption-track-y: -0.5rem;
&:has(.media-controls[data-visible]) {
- --media-caption-track-y: -3rem;
+ --media-caption-track-y: -5rem;
+ }
+
+ @container media-root (width > 42rem) {
+ &:has(.media-controls[data-visible]) > * {
+ --media-caption-track-y: -3rem;
+ }
}
}
diff --git a/packages/skins/src/minimal/css/components/controls.css b/packages/skins/src/minimal/css/components/controls.css
index 97a0b87d..be025e6f 100644
--- a/packages/skins/src/minimal/css/components/controls.css
+++ b/packages/skins/src/minimal/css/components/controls.css
@@ -11,5 +11,7 @@
from var(--media-controls-current-shadow-color) l c h /
calc(alpha * 0.4)
);
+ background-color: var(--media-controls-background-color);
+ backdrop-filter: var(--media-controls-backdrop-filter);
text-shadow: 0 1px 0 var(--media-controls-current-shadow-color);
}
diff --git a/packages/skins/src/minimal/css/components/overlay.css b/packages/skins/src/minimal/css/components/overlay.css
index 32d498c9..555465b2 100644
--- a/packages/skins/src/minimal/css/components/overlay.css
+++ b/packages/skins/src/minimal/css/components/overlay.css
@@ -7,12 +7,11 @@
inset: 0;
border-radius: inherit;
background-image: linear-gradient(to top, oklch(0 0 0 / 0.7), oklch(0 0 0 / 0.5) 7.5rem, oklch(0 0 0 / 0));
- backdrop-filter: blur(0) saturate(1.5);
+ backdrop-filter: blur(0) saturate(1);
opacity: 0;
pointer-events: none;
transition-property: opacity, backdrop-filter;
transition-duration: var(--media-controls-transition-duration);
- transition-delay: var(--media-controls-transition-delay);
transition-timing-function: ease-out;
}
@@ -27,5 +26,5 @@
}
.media-minimal-skin .media-error[data-open] ~ .media-overlay {
- backdrop-filter: blur(16px) saturate(1.5);
+ backdrop-filter: blur(16px) saturate(1.2);
}
diff --git a/packages/skins/src/minimal/css/components/popup.css b/packages/skins/src/minimal/css/components/popup.css
index af4350e1..4ec16cfa 100644
--- a/packages/skins/src/minimal/css/components/popup.css
+++ b/packages/skins/src/minimal/css/components/popup.css
@@ -81,15 +81,16 @@
.media-minimal-skin .media-tooltip {
padding: 0.25rem 0.5rem;
- border-radius: 0.25rem;
- background-color: oklch(1 0 0 / 0.1);
- backdrop-filter: blur(16px) saturate(1.5);
+ border-radius: 0.5rem;
+ background-color: var(--media-tooltip-background-color);
+ backdrop-filter: var(--media-tooltip-backdrop-filter);
box-shadow:
+ 0 0 0 1px var(--media-tooltip-border-color),
0 4px 6px -1px oklch(0 0 0 / 0.1),
0 2px 4px -2px oklch(0 0 0 / 0.1);
- font-size: 0.75rem;
+ color: var(--media-tooltip-text-color);
+ font-size: 0.75rem; /* 12px at 100% font size */
white-space: nowrap;
- --media-tooltip-side-offset: 0.75rem;
&[data-side="top"]::before,
&[data-side="bottom"]::before {
@@ -99,14 +100,6 @@
&[data-side="right"]::before {
width: var(--media-tooltip-side-offset);
}
-
- @media (prefers-reduced-transparency: reduce) {
- background-color: oklch(0 0 0 / 0.7);
- }
-
- @media (prefers-contrast: more) {
- background-color: oklch(0 0 0 / 0.9);
- }
}
.media-minimal-skin .media-popover--volume:has(media-volume-slider[data-availability="unsupported"]) {
diff --git a/packages/skins/src/minimal/css/components/preview.css b/packages/skins/src/minimal/css/components/preview.css
index 7c21e59e..c326f342 100644
--- a/packages/skins/src/minimal/css/components/preview.css
+++ b/packages/skins/src/minimal/css/components/preview.css
@@ -2,6 +2,8 @@
Media preview
========================================================================== */
.media-minimal-skin .media-preview {
+ pointer-events: none;
+
& .media-preview__thumbnail-wrapper {
position: relative;
border-radius: 0.5rem;
@@ -12,9 +14,8 @@
border-radius: inherit;
}
- & .media-preview__timestamp {
+ & .media-preview__time {
display: block;
- font-variant-numeric: tabular-nums;
text-align: center;
margin-top: 0.5rem;
}
diff --git a/packages/skins/src/minimal/css/components/root.css b/packages/skins/src/minimal/css/components/root.css
index 863ea0eb..03e03af6 100644
--- a/packages/skins/src/minimal/css/components/root.css
+++ b/packages/skins/src/minimal/css/components/root.css
@@ -3,12 +3,12 @@
========================================================================== */
.media-minimal-skin {
+ container: media-root / inline-size;
position: relative;
isolation: isolate;
display: block;
height: 100%;
width: 100%;
- container: media-root / inline-size;
border-radius: var(--media-border-radius, 0.75rem);
font-family:
Inter Variable,
@@ -16,11 +16,18 @@
ui-sans-serif,
system-ui,
sans-serif;
- font-size: 0.8125rem;
line-height: 1.5;
letter-spacing: normal;
-webkit-font-smoothing: auto;
-moz-osx-font-smoothing: auto;
- --media-controls-radius: var(--media-border-radius, 1rem);
+ & > * {
+ font-size: 0.75rem; /* 12px at 100% font size */
+ }
+
+ @container media-root (width > 48rem) {
+ & > * {
+ font-size: 0.875rem; /* 14px at 100% font size */
+ }
+ }
}
diff --git a/packages/skins/src/minimal/css/components/slider.css b/packages/skins/src/minimal/css/components/slider.css
index 37e8c284..f94b61d5 100644
--- a/packages/skins/src/minimal/css/components/slider.css
+++ b/packages/skins/src/minimal/css/components/slider.css
@@ -15,11 +15,11 @@
&[data-orientation="horizontal"] {
min-width: 5rem;
width: 100%;
- height: 1.25rem;
+ height: 2rem;
}
&[data-orientation="vertical"] {
- width: 1.25rem;
+ width: 2rem;
height: 4.5rem;
}
}
diff --git a/packages/skins/src/minimal/css/components/time.css b/packages/skins/src/minimal/css/components/time.css
index f5444463..650cb6b6 100644
--- a/packages/skins/src/minimal/css/components/time.css
+++ b/packages/skins/src/minimal/css/components/time.css
@@ -3,34 +3,41 @@
========================================================================== */
.media-minimal-skin .media-time-controls {
+ container: media-time-controls / inline-size;
display: flex;
flex-direction: row-reverse;
align-items: center;
flex: 1;
gap: 0.75rem;
}
-.media-minimal-skin .media-time {
+
+.media-minimal-skin .media-time-group {
display: flex;
align-items: center;
gap: 0.25rem;
}
-.media-minimal-skin .media-time__value {
+
+.media-minimal-skin .media-time {
font-variant-numeric: tabular-nums;
}
-.media-minimal-skin .media-time__value--current,
-.media-minimal-skin .media-time__separator {
+
+.media-minimal-skin .media-time--current,
+.media-minimal-skin .media-time-separator {
display: none;
}
-@container media-controls (width > 28rem) {
+
+@container media-root (width > 42rem) {
.media-minimal-skin .media-time-controls {
flex-direction: row;
}
- .media-minimal-skin .media-time__value--duration,
- .media-minimal-skin .media-time__separator {
+
+ .media-minimal-skin .media-time--duration,
+ .media-minimal-skin .media-time-separator {
color: oklch(from currentColor l c h / 0.6);
}
- .media-minimal-skin .media-time__value--current,
- .media-minimal-skin .media-time__separator {
+
+ .media-minimal-skin .media-time--current,
+ .media-minimal-skin .media-time-separator {
display: inline;
}
}
diff --git a/packages/skins/src/minimal/css/video.css b/packages/skins/src/minimal/css/video.css
index 904f2449..ad3fadf0 100644
--- a/packages/skins/src/minimal/css/video.css
+++ b/packages/skins/src/minimal/css/video.css
@@ -6,7 +6,8 @@
@import "./components/error.css";
@import "./components/controls.css";
@import "./components/time.css";
-@import "./components/buttons.css";
+@import "./components/button.css";
+@import "./components/button-group.css";
@import "./components/icons.css";
@import "./components/poster.css";
@import "./components/preview.css";
@@ -25,15 +26,20 @@
background: oklch(0 0 0);
--media-border-color: oklch(0 0 0 / 0.15);
--media-video-border-radius: var(--media-border-radius, 0.75rem);
- --media-controls-padding: 0.375rem;
+ --media-controls-background-color: transparent;
--media-controls-transition-duration: 100ms;
- --media-controls-transition-delay: 0ms;
--media-controls-transition-timing-function: ease-out;
--media-error-dialog-transition-duration: 250ms;
--media-error-dialog-transition-delay: 100ms;
--media-error-dialog-transition-timing-function: ease-out;
--media-popup-transition-duration: 100ms;
--media-popup-transition-timing-function: ease-out;
+ --media-tooltip-background-color: oklch(1 0 0 / 0.1);
+ --media-tooltip-border-color: transparent;
+ --media-tooltip-backdrop-filter: blur(16px) saturate(1.5);
+ --media-tooltip-text-color: currentColor;
+ --media-tooltip-side-offset: 0.5rem;
+ --media-popover-side-offset: 1.5rem;
@media (prefers-reduced-motion: reduce) {
--media-error-dialog-transition-duration: 50ms;
@@ -45,10 +51,20 @@
--media-border-color: oklch(1 0 0 / 0.15);
}
+ @media (prefers-reduced-transparency: reduce) or (prefers-contrast: more) {
+ --media-controls-background-color: oklch(0 0 0);
+ --media-tooltip-background-color: oklch(0 0 0);
+ }
+
+ @container media-root (width > 42rem) {
+ & > * {
+ --media-popover-side-offset: 0rem;
+ }
+ }
+
&:has(.media-controls:not([data-visible])) {
/* Slight delay to hide controls on non-touch devices after interaction */
@media (pointer: fine) {
- --media-controls-transition-delay: 500ms;
--media-controls-transition-duration: 300ms;
}
@media (pointer: coarse) {
@@ -135,15 +151,16 @@
========================================================================== */
.media-minimal-skin--video .media-controls {
+ padding: 0.25rem;
+ column-gap: 0.5rem;
+ flex-wrap: wrap;
position: absolute;
- bottom: 0;
- inset-inline: 0;
+ bottom: 0.25rem;
+ inset-inline: 0.25rem;
z-index: 10;
- gap: 0.5rem;
- padding: 2rem var(--media-controls-padding) var(--media-controls-padding) var(--media-controls-padding);
- color: var(--media-color-primary, oklch(1 0 0));
+ color: oklch(1 0 0);
+ border-radius: 0.75rem;
transition-duration: var(--media-controls-transition-duration);
- transition-delay: var(--media-controls-transition-delay);
transition-timing-function: var(--media-controls-transition-timing-function);
@media (pointer: fine) {
@@ -171,14 +188,41 @@
}
}
- @container media-root (width > 40rem) {
- gap: 0.875rem;
- padding: 2.5rem 0.75rem 0.75rem 0.75rem;
+ & .media-time-controls {
+ order: -1;
+ flex: 0 0 100%;
+ padding-inline: 0.625rem;
+ }
+
+ & .media-button-group:first-child {
+ flex: 1;
+ text-align: left;
+ }
+
+ & .media-button-group:last-child {
+ flex: 1;
+ justify-content: end;
+ }
+
+ @container media-root (width > 42rem) {
+ flex-wrap: nowrap;
+ bottom: 0.5rem;
+ inset-inline: 0.5rem;
+
+ & .media-time-controls {
+ order: unset;
+ flex: 1;
+ }
+
+ & .media-button-group:first-child,
+ & .media-button-group:last-child {
+ flex: 0 0 auto;
+ }
}
}
-/* Hide cursor when controls are hidden in fullscreen */
-.media-minimal-skin--video:fullscreen:has(.media-controls:not([data-visible])) {
+/* Hide cursor when controls are hidden */
+.media-minimal-skin--video:has(.media-controls:not([data-visible])) {
cursor: none;
}
@@ -195,9 +239,13 @@
========================================================================== */
.media-minimal-skin--video .media-popover--volume {
- --media-popover-side-offset: 0.5rem;
background: transparent;
- padding: 0.25rem;
+ padding-block: 0.75rem;
+ border-radius: 0.75rem;
+
+ @media (prefers-reduced-transparency: reduce) or (prefers-contrast: more) {
+ background: var(--media-controls-background-color);
+ }
}
/* ==========================================================================
@@ -205,9 +253,21 @@
========================================================================== */
.media-minimal-skin--video .media-slider__preview {
+ --media-preview-max-width: 11rem;
+ --media-preview-padding: -0.5rem;
+ /**
+ Inset is the difference between the container width and the slider (100%) width.
+ We only add to the end as we render the time there.
+ */
+ --media-preview-inset: calc(100cqi - 100%);
+
position: absolute;
- left: var(--media-slider-pointer);
- bottom: calc(100% + 0.5rem);
+ left: clamp(
+ calc(var(--media-preview-max-width) / 2 + var(--media-preview-padding)),
+ var(--media-slider-pointer),
+ calc(100% - var(--media-preview-max-width) / 2 - var(--media-preview-padding) + var(--media-preview-inset))
+ );
+ bottom: 100%;
translate: -50%;
opacity: 0;
scale: 0.8;
@@ -217,6 +277,11 @@
transition-timing-function: ease-out;
transform-origin: bottom;
+ @container media-root (width > 42rem) {
+ bottom: calc(100% + 0.25rem);
+ left: var(--media-slider-pointer);
+ }
+
& .media-preview__thumbnail-wrapper {
position: relative;
@@ -233,7 +298,7 @@
}
& .media-preview__thumbnail {
- max-width: 11rem;
+ max-width: var(--media-preview-max-width);
}
&:has(.media-preview__thumbnail[data-loading]) {
diff --git a/packages/skins/src/minimal/tailwind/audio.tailwind.ts b/packages/skins/src/minimal/tailwind/audio.tailwind.ts
index 23260346..d57bdd94 100644
--- a/packages/skins/src/minimal/tailwind/audio.tailwind.ts
+++ b/packages/skins/src/minimal/tailwind/audio.tailwind.ts
@@ -11,19 +11,29 @@ import { root as baseRoot } from './components/root';
export const root = cn(
baseRoot,
'[--media-controls-background-color:oklch(1_0_0)]',
- '[--media-controls-border-color:oklch(0_0_0/0.1)]',
- '[--media-controls-padding:0.375rem]',
- '[--media-text-color:var(--media-color-primary,oklch(0_0_0))]',
+ '[--media-controls-backdrop-filter:blur(16px)_saturate(1.5)]',
+ '[--media-controls-border-color:oklch(0_0_0/0.05)]',
+ '[--media-controls-text-color:var(--media-color-primary,oklch(0_0_0))]',
'[--media-error-dialog-transition-duration:250ms]',
'[--media-error-dialog-transition-delay:100ms]',
'[--media-popup-transition-duration:100ms]',
'[--media-popup-transition-timing-function:ease-out]',
+ '[--media-tooltip-background-color:oklch(1_0_0/0.1)]',
+ '[--media-tooltip-border-color:oklch(0_0_0/0.05)]',
+ '[--media-tooltip-backdrop-filter:blur(16px)_saturate(1.5)]',
+ '[--media-tooltip-text-color:currentColor]',
+ '[--media-tooltip-side-offset:0.75rem]',
+ '[--media-popover-side-offset:0.75rem]',
'motion-reduce:[--media-error-dialog-transition-duration:50ms]',
'motion-reduce:[--media-error-dialog-transition-delay:0ms]',
'motion-reduce:[--media-popup-transition-duration:0ms]',
'dark:[--media-controls-background-color:oklch(0_0_0)]',
'dark:[--media-controls-border-color:oklch(1_0_0/0.1)]',
- 'dark:[--media-text-color:var(--media-color-primary,oklch(1_0_0))]'
+ 'dark:[--media-controls-text-color:var(--media-color-primary,oklch(1_0_0))]',
+ '[@media(prefers-reduced-transparency:reduce)]:[--media-tooltip-background-color:oklch(1_0_0)]',
+ 'contrast-more:[--media-tooltip-background-color:oklch(1_0_0)]',
+ 'dark:[@media(prefers-reduced-transparency:reduce)]:[--media-tooltip-background-color:oklch(0_0_0)]',
+ 'dark:contrast-more:[--media-tooltip-background-color:oklch(0_0_0)]'
);
/* ==========================================================================
@@ -33,14 +43,11 @@ export const root = cn(
export const controls = cn(
baseControls,
// Layout
- 'gap-2 p-1.5',
+ 'p-1.5 gap-2',
+ 'rounded-(--media-border-radius,1rem)',
'peer-data-open/error:[&_*]:invisible',
// Appearance
- 'rounded-(--media-border-radius,0.75rem)',
- 'bg-(--media-controls-background-color)',
- 'text-(--media-text-color)',
- // Backdrop filter
- 'backdrop-blur backdrop-brightness-[0.98] backdrop-saturate-[1.2]',
+ 'text-(--media-controls-text-color)',
// Border
'ring-1 ring-(color:--media-controls-border-color)'
);
@@ -53,9 +60,8 @@ export const popup = {
...basePopup,
volume: cn(
basePopup.popover,
- 'py-2 pr-0 pl-16',
- 'bg-transparent bg-gradient-to-l from-(--media-controls-background-color) from-80% to-transparent',
- '[--media-popover-side-offset:0.75rem]'
+ 'p-0 pl-16',
+ 'bg-transparent bg-gradient-to-l from-(--media-controls-background-color) from-80% to-transparent'
),
};
@@ -71,8 +77,8 @@ export const error = {
'transition-[opacity,filter,scale] ease-out',
'duration-(--media-error-dialog-transition-duration)',
'delay-(--media-error-dialog-transition-delay)',
- 'group-data-starting-style/error:opacity-0 group-data-starting-style/error:blur-[4px] group-data-starting-style/error:scale-95',
- 'group-data-ending-style/error:opacity-0 group-data-ending-style/error:blur-[4px] group-data-ending-style/error:scale-95',
+ 'group-data-starting-style/error:opacity-0 group-data-starting-style/error:blur-xs group-data-starting-style/error:scale-95',
+ 'group-data-ending-style/error:opacity-0 group-data-ending-style/error:blur-xs group-data-ending-style/error:scale-95',
'group-data-ending-style/error:delay-0'
),
content: 'flex flex-1 items-center gap-2',
diff --git a/packages/skins/src/minimal/tailwind/components/button.ts b/packages/skins/src/minimal/tailwind/components/button.ts
index 3c6c4c3e..e17d6e5b 100644
--- a/packages/skins/src/minimal/tailwind/components/button.ts
+++ b/packages/skins/src/minimal/tailwind/components/button.ts
@@ -3,13 +3,13 @@ import { cn } from '@videojs/utils/style';
export const button = {
base: cn(
'flex items-center justify-center shrink-0 border-none cursor-pointer select-none text-center touch-manipulation',
- 'py-2 px-4 rounded-[calc(var(--media-controls-radius)-var(--media-controls-padding))]',
+ 'py-2 px-4 rounded-lg',
'outline-2 outline-transparent -outline-offset-2',
- 'transition-[background-color,outline-offset,scale] duration-150 ease-out',
+ 'transition-[background-color,outline-offset,scale] will-change-[scale] duration-150 ease-out',
'focus-visible:outline-current focus-visible:outline-offset-2',
'active:scale-[0.98]',
'disabled:cursor-not-allowed disabled:opacity-50 disabled:grayscale',
- 'supports-[corner-shape:squircle]:rounded-(--media-controls-radius)',
+ 'supports-[corner-shape:squircle]:rounded-[1rem]',
'supports-[corner-shape:squircle]:[corner-shape:squircle]',
'data-[availability=unavailable]:hidden'
),
diff --git a/packages/skins/src/minimal/tailwind/components/controls.ts b/packages/skins/src/minimal/tailwind/components/controls.ts
index 670443b6..7e96b293 100644
--- a/packages/skins/src/minimal/tailwind/components/controls.ts
+++ b/packages/skins/src/minimal/tailwind/components/controls.ts
@@ -9,6 +9,9 @@ export const controls = cn(
// Shadow color variables (derived from currentColor lightness)
'[--media-controls-current-shadow-color:oklch(from_currentColor_0_0_0/clamp(0,calc((l-0.5)*0.5),0.15))]',
'[--media-controls-current-shadow-color-subtle:oklch(from_var(--media-controls-current-shadow-color)_l_c_h/calc(alpha*0.4))]',
+ // Appearance (driven by CSS variables set on the root)
+ 'bg-(--media-controls-background-color)',
+ '[backdrop-filter:var(--media-controls-backdrop-filter)]',
// Text shadow
- 'text-shadow-[0_1px_0_var(--media-controls-current-shadow-color)]'
+ 'text-shadow-2xs text-shadow-(color:--media-controls-current-shadow-color)'
);
diff --git a/packages/skins/src/minimal/tailwind/components/overlay.ts b/packages/skins/src/minimal/tailwind/components/overlay.ts
index 0a283d71..56575e07 100644
--- a/packages/skins/src/minimal/tailwind/components/overlay.ts
+++ b/packages/skins/src/minimal/tailwind/components/overlay.ts
@@ -7,11 +7,10 @@ export const overlay = cn(
// Default: hidden
'opacity-0',
'bg-linear-to-t from-black/70 via-black/50 via-[7.5rem] to-transparent',
- 'backdrop-blur-none backdrop-saturate-150',
+ 'backdrop-blur-none backdrop-saturate-100',
// Transitions
'transition-[opacity,backdrop-filter]',
'duration-(--media-controls-transition-duration)',
- 'delay-(--media-controls-transition-delay)',
'ease-out',
// Shown when controls visible
'peer-data-visible/controls:opacity-100',
@@ -19,5 +18,5 @@ export const overlay = cn(
'peer-data-open/error:opacity-100',
'peer-data-open/error:duration-(--media-error-dialog-transition-duration)',
'peer-data-open/error:delay-(--media-error-dialog-transition-delay)',
- 'peer-data-open/error:backdrop-blur-lg'
+ 'peer-data-open/error:backdrop-blur-lg peer-data-open/error:backdrop-saturate-120'
);
diff --git a/packages/skins/src/minimal/tailwind/components/popup.ts b/packages/skins/src/minimal/tailwind/components/popup.ts
index e4fc0431..869a4a21 100644
--- a/packages/skins/src/minimal/tailwind/components/popup.ts
+++ b/packages/skins/src/minimal/tailwind/components/popup.ts
@@ -29,11 +29,11 @@ export const popup = {
),
tooltip: cn(
base,
- 'px-2 py-1 rounded-sm shadow-md shadow-black/10 bg-white/10 backdrop-blur-lg backdrop-saturate-150 text-[0.75rem] whitespace-nowrap',
- '[--media-tooltip-side-offset:0.75rem]',
+ 'px-2 py-1 rounded-lg text-[0.75rem] whitespace-nowrap',
+ 'bg-(--media-tooltip-background-color) [backdrop-filter:var(--media-tooltip-backdrop-filter)]',
+ 'ring-1 ring-(color:--media-tooltip-border-color) shadow-md shadow-black/10',
+ 'text-(--media-tooltip-text-color)',
'data-[side=top]:before:h-(--media-tooltip-side-offset) data-[side=bottom]:before:h-(--media-tooltip-side-offset)',
- 'data-[side=left]:before:w-(--media-tooltip-side-offset) data-[side=right]:before:w-(--media-tooltip-side-offset)',
- '[@media(prefers-reduced-transparency:reduce)]:bg-black/70',
- 'contrast-more:bg-black/90'
+ 'data-[side=left]:before:w-(--media-tooltip-side-offset) data-[side=right]:before:w-(--media-tooltip-side-offset)'
),
};
diff --git a/packages/skins/src/minimal/tailwind/components/preview.ts b/packages/skins/src/minimal/tailwind/components/preview.ts
index 60937d01..3f841a63 100644
--- a/packages/skins/src/minimal/tailwind/components/preview.ts
+++ b/packages/skins/src/minimal/tailwind/components/preview.ts
@@ -4,7 +4,7 @@ export const preview = {
root: 'group/preview pointer-events-none',
thumbnailWrapper: 'relative rounded-lg bg-black/90',
thumbnail: cn('block rounded-[inherit] transition-opacity duration-150 ease-out', 'data-loading:opacity-0'),
- timestamp: 'mt-2 block text-center tabular-nums',
+ time: 'mt-2 block text-center tabular-nums',
spinner: cn(
'absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-0',
'transition-opacity duration-150 ease-out',
diff --git a/packages/skins/src/minimal/tailwind/components/root.ts b/packages/skins/src/minimal/tailwind/components/root.ts
index 142e5a4a..8b456a51 100644
--- a/packages/skins/src/minimal/tailwind/components/root.ts
+++ b/packages/skins/src/minimal/tailwind/components/root.ts
@@ -5,8 +5,8 @@ export const root = cn(
'block relative isolate @container/media-root',
// Appearance
'rounded-(--media-border-radius,0.75rem)',
- '[--media-controls-radius:var(--media-border-radius,1rem)]',
- 'font-[Inter_Variable,Inter,ui-sans-serif,system-ui,sans-serif] text-[0.8125rem] leading-normal subpixel-antialiased',
+ 'font-[Inter_Variable,Inter,ui-sans-serif,system-ui,sans-serif] leading-normal subpixel-antialiased',
+ '[&>*]:text-xs @3xl/media-root:[&>*]:text-sm',
// Resets
'**:box-border',
'[&_button]:font-[inherit]',
diff --git a/packages/skins/src/minimal/tailwind/components/seek.ts b/packages/skins/src/minimal/tailwind/components/seek.ts
index 03c2b51f..2b319821 100644
--- a/packages/skins/src/minimal/tailwind/components/seek.ts
+++ b/packages/skins/src/minimal/tailwind/components/seek.ts
@@ -1,5 +1,4 @@
export const seek = {
- button: '@max-md/media-controls:hidden',
label: 'text-[10px] font-[480] tabular-nums',
labelForward: 'absolute -right-px -bottom-0.75',
labelBackward: 'absolute -left-px -bottom-0.75',
diff --git a/packages/skins/src/minimal/tailwind/components/slider.ts b/packages/skins/src/minimal/tailwind/components/slider.ts
index c0cb7c0b..5b223168 100644
--- a/packages/skins/src/minimal/tailwind/components/slider.ts
+++ b/packages/skins/src/minimal/tailwind/components/slider.ts
@@ -4,9 +4,9 @@ export const slider = {
root: cn(
'group/slider relative flex flex-1 items-center justify-center rounded-full outline-none cursor-pointer',
// Horizontal
- 'data-[orientation=horizontal]:min-w-20 data-[orientation=horizontal]:w-full data-[orientation=horizontal]:h-5',
+ 'data-[orientation=horizontal]:min-w-20 data-[orientation=horizontal]:w-full data-[orientation=horizontal]:h-8',
// Vertical
- 'data-[orientation=vertical]:w-5 data-[orientation=vertical]:h-[4.5rem]'
+ 'data-[orientation=vertical]:w-8 data-[orientation=vertical]:h-[4.5rem]'
),
track: cn(
'relative isolate overflow-hidden bg-current/20 rounded-[inherit] select-none',
diff --git a/packages/skins/src/minimal/tailwind/components/time.ts b/packages/skins/src/minimal/tailwind/components/time.ts
index e3617687..d1af4fc6 100644
--- a/packages/skins/src/minimal/tailwind/components/time.ts
+++ b/packages/skins/src/minimal/tailwind/components/time.ts
@@ -2,8 +2,8 @@ import { cn } from '@videojs/utils/style';
export const time = {
group: 'flex items-center gap-1',
- current: cn('hidden tabular-nums', '@md/media-controls:inline'),
- separator: cn('hidden', '@md/media-controls:inline @md/media-controls:text-current/60'),
- duration: cn('tabular-nums', '@md/media-controls:text-current/60'),
- controls: cn('flex flex-row-reverse items-center flex-1 gap-3', '@md/media-controls:flex-row'),
+ current: cn('hidden tabular-nums', '@2xl/media-root:inline'),
+ separator: cn('hidden', '@2xl/media-root:inline @2xl/media-root:text-current/60'),
+ duration: cn('tabular-nums', '@2xl/media-root:text-current/60'),
+ controls: cn('@container flex flex-row-reverse items-center flex-1 gap-3', '@2xl/media-root:flex-row'),
};
diff --git a/packages/skins/src/minimal/tailwind/video.tailwind.ts b/packages/skins/src/minimal/tailwind/video.tailwind.ts
index 6e359428..b5fb2f3d 100644
--- a/packages/skins/src/minimal/tailwind/video.tailwind.ts
+++ b/packages/skins/src/minimal/tailwind/video.tailwind.ts
@@ -1,10 +1,12 @@
import { cn } from '@videojs/utils/style';
+import { buttonGroup as baseButtonGroup } from './components/button-group';
import { controls as baseControls } from './components/controls';
import { error as baseError } from './components/error';
import { popup as basePopup } from './components/popup';
import { preview as basePreview } from './components/preview';
import { root as baseRoot } from './components/root';
import { slider as baseSlider } from './components/slider';
+import { time as baseTime } from './components/time';
/* ==========================================================================
Root
@@ -25,27 +27,37 @@ export const root = (isShadowDOM: boolean) =>
!isShadowDOM,
},
'[--media-video-border-radius:var(--media-border-radius,0.75rem)]',
- '[--media-controls-padding:0.375rem]',
+ '[--media-controls-background-color:transparent]',
'[--media-controls-transition-duration:100ms]',
- '[--media-controls-transition-delay:0ms]',
'[--media-controls-transition-timing-function:ease-out]',
'[--media-error-dialog-transition-duration:250ms]',
'[--media-error-dialog-transition-delay:100ms]',
'[--media-error-dialog-transition-timing-function:ease-out]',
'[--media-popup-transition-duration:100ms]',
'[--media-popup-transition-timing-function:ease-out]',
+ '[--media-tooltip-background-color:oklch(1_0_0/0.1)]',
+ '[--media-tooltip-border-color:transparent]',
+ '[--media-tooltip-backdrop-filter:blur(16px)_saturate(1.5)]',
+ '[--media-tooltip-text-color:currentColor]',
+ '[--media-tooltip-side-offset:0.5rem]',
+ '[--media-popover-side-offset:1.5rem]',
'motion-reduce:[--media-error-dialog-transition-duration:50ms]',
'motion-reduce:[--media-error-dialog-transition-delay:0ms]',
'motion-reduce:[--media-popup-transition-duration:0ms]',
- '[@media(pointer:fine)]:has-[[data-controls]:not([data-visible])]:[--media-controls-transition-delay:500ms]',
+ '[@media(prefers-reduced-transparency:reduce)]:[--media-controls-background-color:oklch(0_0_0)]',
+ 'contrast-more:[--media-controls-background-color:oklch(0_0_0)]',
+ '[@media(prefers-reduced-transparency:reduce)]:[--media-tooltip-background-color:oklch(0_0_0)]',
+ 'contrast-more:[--media-tooltip-background-color:oklch(0_0_0)]',
+ '@2xl/media-root:[&>*]:[--media-popover-side-offset:0rem]',
'[@media(pointer:fine)]:has-[[data-controls]:not([data-visible])]:[--media-controls-transition-duration:300ms]',
'[@media(pointer:coarse)]:has-[[data-controls]:not([data-visible])]:[--media-controls-transition-duration:150ms]',
'motion-reduce:has-[[data-controls]:not([data-visible])]:[--media-controls-transition-duration:50ms]',
// Caption track CSS variables (consumed by the native caption bridge in light DOM)
'[--media-caption-track-y:-0.5rem]',
- '[--media-caption-track-delay:calc(var(--media-controls-transition-delay)_+_25ms)]',
+ '[--media-caption-track-delay:25ms]',
'[--media-caption-track-duration:var(--media-controls-transition-duration)]',
- 'has-[[data-controls][data-visible]]:[--media-caption-track-y:-3rem]',
+ 'has-[[data-controls][data-visible]]:[--media-caption-track-y:-5rem]',
+ '@2xl/media-root:has-[[data-controls][data-visible]]:[&>*]:[--media-caption-track-y:-3rem]',
// Native caption track container
!isShadowDOM
? [
@@ -73,14 +85,13 @@ export const root = (isShadowDOM: boolean) =>
export const controls = cn(
baseControls,
- // Position
- 'absolute bottom-0 inset-x-0',
- 'pt-8 px-(--media-controls-padding) pb-(--media-controls-padding) gap-2',
- '[color:var(--media-color-primary,oklch(1_0_0))] z-10',
+ // Position & wrapping layout (small)
+ 'absolute bottom-1 inset-x-1',
+ 'p-1 gap-x-2 flex-wrap rounded-xl',
+ 'text-white z-10',
'peer-data-open/error:hidden',
'ease-(--media-controls-transition-timing-function)',
'duration-(--media-controls-transition-duration)',
- 'delay-(--media-controls-transition-delay)',
'[@media(pointer:fine)]:will-change-[translate,filter,opacity]',
'[@media(pointer:fine)]:transition-[translate,filter,opacity]',
'[@media(pointer:coarse)]:will-change-[translate,opacity]',
@@ -89,11 +100,30 @@ export const controls = cn(
'not-data-visible:opacity-0 not-data-visible:pointer-events-none',
'motion-safe:not-data-visible:translate-y-full',
'[@media(pointer:fine)]:motion-safe:not-data-visible:blur-sm',
- // Wider container
- '@sm/media-root:pt-10 @sm/media-root:px-3 @sm/media-root:pb-3',
- '@sm/media-root:gap-3.5'
+ // Single-row layout (large)
+ '@2xl/media-root:flex-nowrap @2xl/media-root:bottom-2 @2xl/media-root:inset-x-2'
);
+/* ==========================================================================
+ Button groups
+ ========================================================================== */
+
+export const buttonGroupStart = cn(baseButtonGroup, 'flex-1 @2xl/media-root:flex-none');
+export const buttonGroupEnd = cn(baseButtonGroup, 'flex-1 justify-end @2xl/media-root:flex-none');
+
+/* ==========================================================================
+ Time
+ ========================================================================== */
+
+export const time = {
+ ...baseTime,
+ controls: cn(
+ baseTime.controls,
+ 'grow-0 shrink-0 basis-full order-[-1] px-2.5',
+ '@2xl/media-root:grow @2xl/media-root:shrink @2xl/media-root:basis-0 @2xl/media-root:order-[unset]'
+ ),
+};
+
/* ==========================================================================
Error
========================================================================== */
@@ -112,7 +142,9 @@ export const error = {
export const preview = {
...basePreview,
root: cn(
- 'absolute left-(--media-slider-pointer) bottom-[calc(100%+0.5rem)] -translate-x-1/2',
+ '[--media-preview-max-width:11rem] [--media-preview-padding:-0.5rem] [--media-preview-inset:calc(100cqi-100%)]',
+ 'absolute [left:clamp(calc(var(--media-preview-max-width)/2+var(--media-preview-padding)),var(--media-slider-pointer),calc(100%-var(--media-preview-max-width)/2-var(--media-preview-padding)+var(--media-preview-inset)))] bottom-full -translate-x-1/2',
+ '@2xl/media-root:bottom-[calc(100%+0.25rem)] @2xl/media-root:[left:var(--media-slider-pointer)]',
'opacity-0 scale-80 blur-sm origin-bottom',
'transition-[scale,opacity,filter] duration-150',
'group-data-pointing/slider:opacity-100 group-data-pointing/slider:scale-100 group-data-pointing/slider:blur-none',
@@ -125,7 +157,7 @@ export const preview = {
'after:absolute after:inset-0 after:rounded-[inherit]',
'after:ring-1 after:ring-black/5 after:shadow-sm after:shadow-black/20'
),
- thumbnail: cn(basePreview.thumbnail, 'max-w-44'),
+ thumbnail: cn(basePreview.thumbnail, 'max-w-(--media-preview-max-width)'),
};
/* ==========================================================================
@@ -143,7 +175,12 @@ export const slider = {
export const popup = {
...basePopup,
- volume: cn(basePopup.popover, '[--media-popover-side-offset:0.5rem] p-1 bg-transparent'),
+ volume: cn(
+ basePopup.popover,
+ 'py-3 px-0 bg-transparent rounded-xl',
+ '[@media(prefers-reduced-transparency:reduce)]:bg-(--media-controls-background-color)',
+ 'contrast-more:bg-(--media-controls-background-color)'
+ ),
};
/* ==========================================================================
@@ -160,4 +197,3 @@ export { overlay } from './components/overlay';
export { playbackRate } from './components/playback-rate';
export { poster } from './components/poster';
export { seek } from './components/seek';
-export { time } from './components/time';