feat: release v0.0.1
This commit is contained in:
220
stories/angular-video-player-adapter.stories.tsx
Normal file
220
stories/angular-video-player-adapter.stories.tsx
Normal file
@@ -0,0 +1,220 @@
|
||||
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<HTMLDivElement | null>(null);
|
||||
const adapterRef = useRef<AngularVideoPlayerAdapter | null>(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 (
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
marginBottom: 12,
|
||||
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
||||
fontSize: 12,
|
||||
color: "#4f4f4f",
|
||||
}}
|
||||
>
|
||||
{status}
|
||||
</div>
|
||||
<div style={{ width: "100%", maxWidth: 960, minHeight: 320 }} ref={hostRef} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const meta: Meta<AngularAdapterStoryArgs> = {
|
||||
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 => <AngularAdapterHarness {...args} />,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<AngularAdapterStoryArgs>;
|
||||
|
||||
export const Playground: Story = {};
|
||||
93
stories/react-video-player.stories.tsx
Normal file
93
stories/react-video-player.stories.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import React from "react";
|
||||
|
||||
import VideoPlayer, { type IVideoPlayerProps } from "../src/react";
|
||||
|
||||
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 meta: Meta<IVideoPlayerProps> = {
|
||||
title: "React/VideoPlayer",
|
||||
component: VideoPlayer,
|
||||
tags: ["autodocs"],
|
||||
args: {
|
||||
src: DEMO_HLS_SOURCE,
|
||||
type: "application/x-mpegurl",
|
||||
preload: "auto",
|
||||
muted: true,
|
||||
fluid: true,
|
||||
responsive: true,
|
||||
controls: true,
|
||||
aspectRatio: "16:9",
|
||||
preferHQ: false,
|
||||
width: 1280,
|
||||
height: 720,
|
||||
autoplay: false,
|
||||
lazy: false,
|
||||
debug: false,
|
||||
forceHover: false,
|
||||
full: true,
|
||||
withRewind: true,
|
||||
showErrors: false,
|
||||
showProcessing: false,
|
||||
withLoading: false,
|
||||
withBlur: false,
|
||||
duration: false,
|
||||
cover: "",
|
||||
},
|
||||
argTypes: {
|
||||
src: { control: "text" },
|
||||
type: {
|
||||
control: { type: "select" },
|
||||
options: [
|
||||
"application/x-mpegurl",
|
||||
"application/vnd.apple.mpegurl",
|
||||
"video/mp4",
|
||||
],
|
||||
},
|
||||
preload: {
|
||||
control: { type: "inline-radio" },
|
||||
options: ["auto", "metadata", "none", "visibility"],
|
||||
},
|
||||
aspectRatio: {
|
||||
control: { type: "select" },
|
||||
options: ["16:9", "4:3", "1:1", "none"],
|
||||
},
|
||||
full: { control: "boolean" },
|
||||
withRewind: { control: "boolean" },
|
||||
duration: {
|
||||
control: { type: "select" },
|
||||
options: [false, 30, 120, 1800],
|
||||
},
|
||||
cover: {
|
||||
control: "text",
|
||||
description: "Poster URL (string) or leave empty",
|
||||
},
|
||||
width: { control: { type: "number", min: 0, step: 1 } },
|
||||
height: { control: { type: "number", min: 0, step: 1 } },
|
||||
className: { control: false },
|
||||
},
|
||||
render: args => {
|
||||
const width = typeof args.width === "number" && args.width > 0 ? args.width : null;
|
||||
const height =
|
||||
typeof args.height === "number" && args.height > 0 ? args.height : null;
|
||||
|
||||
return (
|
||||
<div style={{ maxWidth: 960, width: "100%" }}>
|
||||
<VideoPlayer
|
||||
{...args}
|
||||
width={width}
|
||||
height={height}
|
||||
cover={args.cover ? args.cover : DEMO_POSTER}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<IVideoPlayerProps>;
|
||||
|
||||
export const Playground: Story = {};
|
||||
Reference in New Issue
Block a user