import type { Meta, StoryObj } from "@storybook/react"; import React, { useEffect, useMemo, useRef, useState } from "react"; import { AngularVideoPlayerAdapter } from "../src/angular"; import type { EngineStrategy, VideoPlayerRuntimePreload } from "../src/core"; interface AngularAdapterStoryArgs { src: string; type: string; strategy: EngineStrategy; preload: VideoPlayerRuntimePreload; autoplay: boolean; controls: boolean; responsive: boolean; aspectRatio: string; fluid: boolean; muted: boolean; poster: string; preferHQ: boolean; debug: boolean; initialTime: number; isIOS: boolean; isMobile: boolean; full: boolean; withRewind: boolean; skipSeconds: number; classNames: string; } const DEMO_HLS_SOURCE = "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8"; const DEMO_POSTER = "https://images.unsplash.com/photo-1574267432553-4b4628081c31?auto=format&fit=crop&w=1280&q=80"; const toAdapterInput = (args: AngularAdapterStoryArgs) => ({ source: { src: args.src, type: args.type, }, strategy: args.strategy, preload: args.preload, autoplay: args.autoplay, controls: args.controls, responsive: args.responsive, aspectRatio: args.aspectRatio === "none" ? undefined : args.aspectRatio, fluid: args.fluid, muted: args.muted, poster: args.poster || undefined, preferHQ: args.preferHQ, debug: args.debug, initialTime: args.initialTime, isIOS: args.isIOS, isMobile: args.isMobile, full: args.full, withRewind: args.withRewind, skipSeconds: args.skipSeconds, classNames: args.classNames .split(",") .map(item => item.trim()) .filter(Boolean), }); const statusText = ({ initialized, engine, source, }: { initialized: boolean; engine: string | null; source?: { src: string } | null; }) => { const sourceText = source?.src ? source.src : "none"; return `initialized=${initialized}; engine=${engine ?? "none"}; source=${sourceText}`; }; const AngularAdapterHarness = (args: AngularAdapterStoryArgs) => { const hostRef = useRef(null); const adapterRef = useRef(null); const [status, setStatus] = useState("initializing"); const input = useMemo(() => toAdapterInput(args), [args]); useEffect(() => { const host = hostRef.current; if (!host) { return; } const adapter = new AngularVideoPlayerAdapter(); adapterRef.current = adapter; let active = true; void adapter .attach(host, input) .then(state => { if (!active) { return; } setStatus(statusText(state.runtime)); }) .catch(error => { if (!active) { return; } setStatus(`attach error: ${String(error)}`); }); return () => { active = false; adapter.destroy(); adapterRef.current = null; }; }, []); useEffect(() => { const adapter = adapterRef.current; if (!adapter) { return; } let active = true; void adapter .update(input) .then(state => { if (!active) { return; } setStatus(statusText(state.runtime)); }) .catch(error => { if (!active) { return; } setStatus(`update error: ${String(error)}`); }); return () => { active = false; }; }, [input]); return (
{status}
); }; const meta: Meta = { title: "Angular/VideoPlayerAdapter", component: AngularAdapterHarness, tags: ["autodocs"], args: { src: DEMO_HLS_SOURCE, type: "application/x-mpegurl", strategy: "auto", preload: "auto", autoplay: false, controls: true, responsive: true, aspectRatio: "16:9", fluid: true, muted: true, poster: DEMO_POSTER, preferHQ: false, debug: false, initialTime: 0, isIOS: false, isMobile: false, full: true, withRewind: true, skipSeconds: 10, classNames: "", }, argTypes: { src: { control: "text" }, type: { control: { type: "select" }, options: [ "application/x-mpegurl", "application/vnd.apple.mpegurl", "video/mp4", ], }, strategy: { control: { type: "inline-radio" }, options: ["auto", "force-hls", "force-videojs"], }, preload: { control: { type: "inline-radio" }, options: ["auto", "metadata", "none", "visibility"], }, aspectRatio: { control: { type: "select" }, options: ["16:9", "4:3", "1:1", "none"], }, initialTime: { control: { type: "number", min: 0, step: 1 } }, skipSeconds: { control: { type: "number", min: 1, step: 1 } }, classNames: { control: "text", description: "Comma-separated class names (e.g. test-one,test-two)", }, }, render: args => , }; export default meta; type Story = StoryObj; export const Playground: Story = {};