fix(web): size uploaded videos from their own frame
Uploaded videos carry no dimensions, so a vertical clip sat letterboxed in a 16:9 frame. The player now takes the frame size from the file's metadata when the block has none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
This commit is contained in:
parent
d67a6275a4
commit
17d285f87e
@ -66,6 +66,21 @@ describe("MediaPlayer", () => {
|
|||||||
expect(video.hasAttribute("controls")).toBe(true);
|
expect(video.hasAttribute("controls")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("sizes the frame from the file when the block has no dimensions", async () => {
|
||||||
|
await act(async () =>
|
||||||
|
root.render(<MediaPlayer artifactId="art-4" kind="video" name="up.mp4" />),
|
||||||
|
);
|
||||||
|
const frame = container.querySelector<HTMLDivElement>('[data-testid="media-video"]')!;
|
||||||
|
expect(frame.style.width).toBe("420px");
|
||||||
|
const video = container.querySelector("video")!;
|
||||||
|
Object.defineProperty(video, "videoWidth", { value: 1080 });
|
||||||
|
Object.defineProperty(video, "videoHeight", { value: 1920 });
|
||||||
|
await act(async () => {
|
||||||
|
video.dispatchEvent(new Event("loadedmetadata"));
|
||||||
|
});
|
||||||
|
expect(frame.style.width).toBe("270px");
|
||||||
|
});
|
||||||
|
|
||||||
it("falls back to a download link when the browser cannot play the file", async () => {
|
it("falls back to a download link when the browser cannot play the file", async () => {
|
||||||
await act(async () =>
|
await act(async () =>
|
||||||
root.render(<MediaPlayer artifactId="art-3" kind="audio" name="memo.ogg" />),
|
root.render(<MediaPlayer artifactId="art-3" kind="audio" name="memo.ogg" />),
|
||||||
|
|||||||
@ -28,6 +28,7 @@ export function MediaPlayer({
|
|||||||
const container = useRef<HTMLDivElement>(null);
|
const container = useRef<HTMLDivElement>(null);
|
||||||
const near = useNearViewport(container);
|
const near = useNearViewport(container);
|
||||||
const [failed, setFailed] = useState(false);
|
const [failed, setFailed] = useState(false);
|
||||||
|
const [frame, setFrame] = useState<{ width: number; height: number } | null>(null);
|
||||||
const src = near ? artifactUrl(artifactId) : undefined;
|
const src = near ? artifactUrl(artifactId) : undefined;
|
||||||
|
|
||||||
if (failed) return <MediaFallback artifactId={artifactId} name={name} />;
|
if (failed) return <MediaFallback artifactId={artifactId} name={name} />;
|
||||||
@ -48,7 +49,8 @@ export function MediaPlayer({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const box = videoBox(width, height);
|
// Uploads carry no dimensions; size the frame from the file once its metadata loads.
|
||||||
|
const box = videoBox(width ?? frame?.width, height ?? frame?.height);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={container}
|
ref={container}
|
||||||
@ -66,6 +68,12 @@ export function MediaPlayer({
|
|||||||
aria-label={name}
|
aria-label={name}
|
||||||
className="block size-full object-contain"
|
className="block size-full object-contain"
|
||||||
onError={() => setFailed(true)}
|
onError={() => setFailed(true)}
|
||||||
|
onLoadedMetadata={(event) => {
|
||||||
|
const { videoWidth, videoHeight } = event.currentTarget;
|
||||||
|
if (videoWidth > 0 && videoHeight > 0) {
|
||||||
|
setFrame({ width: videoWidth, height: videoHeight });
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user