diff --git a/packages/react/src/presets/video/minimal-skin.css b/packages/react/src/presets/video/minimal-skin.css
index e90d8b31..40840be8 100644
--- a/packages/react/src/presets/video/minimal-skin.css
+++ b/packages/react/src/presets/video/minimal-skin.css
@@ -1,7 +1,3 @@
-.media-minimal-skin * {
- box-sizing: border-box;
-}
-
.media-minimal-skin {
position: relative;
isolation: isolate;
@@ -15,6 +11,9 @@
-webkit-font-smoothing: auto;
-moz-osx-font-smoothing: auto;
}
+.media-minimal-skin * {
+ box-sizing: border-box;
+}
.media-minimal-skin::after {
content: "";
position: absolute;
@@ -155,7 +154,7 @@
text-shadow: 0 1px 0 oklab(0 0 0 / 0.2);
font-variant-numeric: tabular-nums;
}
-@container media-controls (width > 480px) {
+@container media-controls (width > 28rem) {
.media-minimal-skin .media-time-controls {
flex-direction: row;
}
@@ -175,7 +174,7 @@
align-items: center;
gap: 0.075rem;
}
-@container media-root (width > 640px) {
+@container media-root (width > 42rem) {
.media-minimal-skin .media-button-group {
gap: 0.125rem;
}
@@ -213,7 +212,7 @@
opacity: 0.5;
filter: grayscale(1);
}
-@container media-controls (width < 480px) {
+@container media-controls (width < 28rem) {
.media-minimal-skin .media-button--seek {
display: none;
}
@@ -375,6 +374,9 @@
}
/* Tooltip Component Styles */
+.media-minimal-skin .media-tooltip {
+ white-space: nowrap;
+}
.media-minimal-skin .media-tooltip-popup {
color: oklab(1 0 0);
padding: 0.25rem 0.5rem;
@@ -397,6 +399,68 @@
}
}
-.media-minimal-skin .media-tooltip {
- white-space: nowrap;
+/* Captions */
+.media-minimal-skin .media-captions {
+ position: absolute;
+ inset: auto 1rem 1.5rem 1rem;
+ z-index: 20;
+ transition: transform 150ms ease-out;
+ /* The delay must account for the controls delay/duration */
+ transition-delay: 600ms;
+ pointer-events: none;
+ text-wrap: balance;
+ font-size: 1rem;
+}
+@media (prefers-reduced-motion: reduce) {
+ .media-minimal-skin .media-captions {
+ transition-duration: 50ms;
+ }
+}
+.media-minimal-skin .media-captions__container {
+ max-width: 42ch;
+ margin: 0 auto;
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+.media-minimal-skin .media-captions__text {
+ display: block;
+ padding: 0.125rem 0.5rem;
+ text-shadow:
+ 0 0 1px oklab(0 0 0 / 0.7),
+ 0 0 8px oklab(0 0 0 / 0.7);
+ color: #fff;
+ text-align: center;
+ white-space: pre-wrap;
+ line-height: 1.2;
+}
+@media (prefers-contrast: more) {
+ .media-minimal-skin .media-captions__text {
+ text-shadow: none;
+ box-decoration-break: clone;
+ background: oklab(0 0 0 / 0.7);
+ }
+}
+.media-minimal-skin .media-captions__text > * {
+ display: inline;
+}
+@container media-root (width > 20rem) {
+ .media-minimal-skin .media-captions {
+ font-size: 1.5rem;
+ }
+}
+@container media-root (width > 48rem) {
+ .media-minimal-skin .media-captions {
+ font-size: 2rem;
+ }
+}
+@container media-root (width > 80rem) {
+ .media-minimal-skin .media-captions {
+ font-size: 2.5rem;
+ }
+}
+.media-minimal-skin .media-controls[data-visible] ~ .media-captions {
+ transform: translateY(-2.5rem);
+ transition-delay: 25ms;
}
diff --git a/packages/react/src/presets/video/minimal-skin.tsx b/packages/react/src/presets/video/minimal-skin.tsx
index 6cdb4ad1..5305fcbc 100644
--- a/packages/react/src/presets/video/minimal-skin.tsx
+++ b/packages/react/src/presets/video/minimal-skin.tsx
@@ -155,6 +155,15 @@ export function MinimalVideoSkin(props: MinimalVideoSkinProps): ReactNode {
+ {/*
+
+
An example cue
+
+ Another example cue with HTML
+
+
+
*/}
+
);
diff --git a/packages/react/src/presets/video/skin.css b/packages/react/src/presets/video/skin.css
index c23e90fe..d80290b4 100644
--- a/packages/react/src/presets/video/skin.css
+++ b/packages/react/src/presets/video/skin.css
@@ -1,7 +1,3 @@
-.media-default-skin * {
- box-sizing: border-box;
-}
-
.media-default-skin {
position: relative;
isolation: isolate;
@@ -15,6 +11,9 @@
-webkit-font-smoothing: auto;
-moz-osx-font-smoothing: auto;
}
+.media-default-skin * {
+ box-sizing: border-box;
+}
.media-default-skin::before,
.media-default-skin::after {
content: "";
@@ -156,12 +155,13 @@
}
@media (prefers-reduced-motion: reduce) {
.media-default-skin .media-controls:not([data-visible]) {
+ /* FIXME: Make this a custom property that we can share */
transition-duration: 100ms;
filter: blur(0);
scale: 1;
}
}
-@container media-root (width > 640px) {
+@container media-root (width > 42rem) {
.media-default-skin .media-controls {
padding: 0.25rem;
gap: 0.125rem;
@@ -184,7 +184,7 @@
.media-default-skin .media-time .media-time__value:first-child {
display: none;
}
-@container media-time (width > 240px) {
+@container media-time (width > 18rem) {
.media-default-skin .media-time .media-time__value:first-child {
display: block;
}
@@ -224,7 +224,7 @@
opacity: 0.5;
filter: grayscale(1);
}
-@container media-controls (width < 480px) {
+@container media-controls (width < 28rem) {
.media-default-skin .media-button--seek {
display: none;
}
@@ -388,6 +388,9 @@
}
/* Tooltip Component Styles */
+.media-default-skin .media-tooltip {
+ white-space: nowrap;
+}
.media-default-skin .media-tooltip-popup {
color: oklab(1 0 0);
padding: 0.25rem 0.625rem;
@@ -395,6 +398,68 @@
font-size: 0.75rem;
}
-.media-default-skin .media-tooltip {
- white-space: nowrap;
+/* Captions */
+.media-default-skin .media-captions {
+ position: absolute;
+ inset: auto 1rem 1.5rem 1rem;
+ z-index: 20;
+ transition: transform 150ms ease-out;
+ /* The delay must account for the controls delay/duration */
+ transition-delay: 600ms;
+ pointer-events: none;
+ text-wrap: balance;
+ font-size: 1rem;
+}
+@media (prefers-reduced-motion: reduce) {
+ .media-default-skin .media-captions {
+ transition-duration: 50ms;
+ }
+}
+.media-default-skin .media-captions__container {
+ max-width: 42ch;
+ margin: 0 auto;
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+.media-default-skin .media-captions__text {
+ display: block;
+ padding: 0.125rem 0.5rem;
+ text-shadow:
+ 0 0 1px oklab(0 0 0 / 0.7),
+ 0 0 8px oklab(0 0 0 / 0.7);
+ color: #fff;
+ text-align: center;
+ white-space: pre-wrap;
+ line-height: 1.2;
+}
+@media (prefers-contrast: more) {
+ .media-default-skin .media-captions__text {
+ text-shadow: none;
+ box-decoration-break: clone;
+ background: oklab(0 0 0 / 0.7);
+ }
+}
+.media-default-skin .media-captions__text > * {
+ display: inline;
+}
+@container media-root (width > 20rem) {
+ .media-default-skin .media-captions {
+ font-size: 1.5rem;
+ }
+}
+@container media-root (width > 48rem) {
+ .media-default-skin .media-captions {
+ font-size: 2rem;
+ }
+}
+@container media-root (width > 80rem) {
+ .media-default-skin .media-captions {
+ font-size: 2.5rem;
+ }
+}
+.media-default-skin .media-controls[data-visible] ~ .media-captions {
+ transform: translateY(-3rem);
+ transition-delay: 25ms;
}
diff --git a/packages/react/src/presets/video/skin.tsx b/packages/react/src/presets/video/skin.tsx
index 78f3da68..7e14fec0 100644
--- a/packages/react/src/presets/video/skin.tsx
+++ b/packages/react/src/presets/video/skin.tsx
@@ -149,6 +149,15 @@ export function VideoSkin(props: VideoSkinProps): ReactNode {
/>
+ {/*
+
+
An example cue
+
+ Another example cue with HTML
+
+
+
*/}
+
);