npm package: @sgrsoft/vpe-react-ui
Description: React 기반 비디오 플레이어 UI 컴포넌트 모음입니다. 스트리밍 엔진(HLS/DASH)은 외부에서 주입하고, UI는 이 패키지에서 제공합니다. 여러 플레이어를 동시에 렌더링할 수 있도록 스토어 스코프를 지원합니다.
Latest version: 0.2.17

# vpe-react-ui

React 기반 비디오 플레이어 UI 컴포넌트 모음입니다. 스트리밍 엔진(HLS/DASH)은 외부에서 주입하고, UI는 이 패키지에서 제공합니다. 여러 플레이어를 동시에 렌더링할 수 있도록 스토어 스코프를 지원합니다.

## 주요 특징

- HLS/DASH/MP4/Native(HLS) 재생 UI 제공
- hls.js, dash.js는 선택적 주입(옵셔널 peer dependency)
- 자막 트랙(VTT) 지원 및 자막 선택/토글 UI 제공
- 품질 선택, 재생 속도, PiP, 전체화면, 음량, 공유 등 UI 컴포넌트 제공
- 모바일 더블탭 탐색 오버레이, 워터마크, 시작 시간 표시 등 부가 UI 제공
- `PlayerStoreProvider`로 플레이어별 상태 스코프 분리 가능

## 설치

```bash
pnpm add @sgrsoft/vpe-react-ui
```

필수 peer dependency:

- `react`
- `react-dom`

선택적 주입:

- `hls.js`
- `dashjs`

## 기본 사용 예시

```tsx
import {
  BaseStyle,
  PlayerStoreProvider,
  HlsVideo,
  SeekBar,
  PlayBtn,
  CurrentTimeBtn,
  DurationBtn,
  VolumeBtn,
  FullscreenBtn,
  SettingBtn,
  SettingModal,
} from "@sgrsoft/vpe-react-ui";

import Hls from "hls.js";

export default function Player() {
  const src = {
    file: "https://example.com/stream.m3u8",
    poster: "https://example.com/poster.jpg",
    vtt: [
      { label: "KOR", id: "ko", default: true, src: "https://example.com/ko.vtt" },
    ],
  };

  const options = {
    autostart: false,
    autoPause: true,
    objectFit: "contain",
    playbackRate: 1,
    lowLatencyMode: false,
  };

  return (
    <PlayerStoreProvider>
      <BaseStyle />
      <div className="vpe-root-wrap">
        <HlsVideo src={src} hlsLib={Hls} options={options} />

        <div className="controls">
          <SeekBar src={src} hlsLib={Hls} />
          <PlayBtn />
          <CurrentTimeBtn />
          <DurationBtn />
          <VolumeBtn />
          <FullscreenBtn />
          <SettingBtn />
        </div>

        <SettingModal
          text={{
            setting: "설정",
            quality: "화질",
            autoplay: "자동 재생",
            playbackRate: "재생 속도",
            captions: "자막",
            auto: "자동",
            notUse: "사용 안 함",
          }}
          src={src}
          options={{ playRateSetting: [0.5, 1, 1.5, 2] }}
        />
      </div>
    </PlayerStoreProvider>
  );
}
```

## 공통 레이아웃 규칙

- 루트 컨테이너에 `vpe-root-wrap` 클래스를 권장합니다.
- 전체화면 대상 엘리먼트를 지정하려면 `vpe-fullscreen-target` 클래스를 사용합니다.
- `BaseStyle` 컴포넌트는 필수는 아니지만 기본 스타일(폰트, 버튼, 모달, 오버레이 등)을 제공합니다.

## 비디오 컴포넌트

### `HlsVideo`

- hls.js가 주입되면 MSE 기반 HLS 재생을 사용합니다.
- hls.js 미지원 환경에서는 네이티브 HLS로 폴백합니다.
- `options.retry`로 재시도 횟수/간격을 설정할 수 있습니다.
- `options.lowLatencyMode` 사용 시 저지연 모드 설정을 시도합니다.

### `DashVideo`

- dash.js가 주입되면 DASH 재생을 사용합니다.
- dash.js 미주입 시 네이티브 재생으로 폴백합니다.

### `Mp4Video`

- 일반 MP4 재생용 컴포넌트입니다.

### `NativeVideo`

- 네이티브 HLS 재생 전용 컴포넌트입니다.
- FairPlay DRM 지원을 위한 `src.drm` 설정을 제공합니다.

#### 비디오 컴포넌트 공통 Props

```ts
src?: {
  file?: string;
  poster?: string;
  vtt?: Array<{
    label?: string;
    id?: string;
    default?: boolean;
    src?: string;
  }>;
  drm?: Record<string, {
    licenseUri?: string;
    licenseRequestHeader?: Record<string, string | number>;
    certificateUri?: string;
    certificateRequestHeader?: Record<string, string | number>;
  }>;
};
options?: {
  autostart?: boolean;
  autoPause?: boolean;
  muted?: boolean;
  objectFit?: string;
  playbackRate?: number;
  lowLatencyMode?: boolean;
  retry?: { maxRetry?: number; interval?: number };
  fairplayContentId?: string;
};
onError?: (err: unknown) => void;
emitEvent?: (type: string, data?: Record<string, unknown>) => void;
```

주의:

- `src.vtt`가 제공되면 해당 자막을 우선 사용합니다.
- `emitEvent`는 `timeupdate`, `ended`, `seeking`, `seeked`, `volumechange` 등 이벤트를 전달합니다.
- `NativeVideo`의 FairPlay DRM은 Safari 환경을 기준으로 구성되어 있습니다.

## UI 컨트롤 컴포넌트

### 공통 Props (`PlayBtnProps`)

```ts
size?: string;
weight?: "fill";
color?: string;
text?: any;
pos?: "left" | "right";
options?: any;
next?: () => void;
prev?: () => void;
pidx?: number;
playlistCnt?: number;
isMobile?: boolean;
isPortrait?: boolean;
isAnimationComplete?: boolean;
```

### 재생 관련

- `PlayBtn`: 재생/일시정지 토글 버튼
- `BigPlayBtn`: 중앙 대형 재생 버튼, 모바일에서 이전/다음과 함께 사용 가능
- `SkipBackBtn`: 기본 10초 뒤로, `options.skipSeconds`로 변경 가능
- `SkipForwardBtn`: 기본 10초 앞으로, `options.skipSeconds`로 변경 가능

### 시간 표시

- `TimeBtn`: 라이브 시 LIVE 버튼(라이브 엣지로 이동), VOD는 현재/전체 시간 표시
- `CurrentTimeBtn`: 현재 시간 표시
- `DurationBtn`: 전체 시간 표시

### 음량/자막/화면

- `VolumeBtn`: 음소거 토글 + 볼륨 슬라이더
- `MuteBtn`: 음소거 토글 버튼만 제공
- `MuteIcon`: 음소거 상태 표시용 아이콘
- `SubtitleBtn`: 자막 토글
- `FullscreenBtn`: 전체화면 토글
- `PipBtn`: 브라우저 PiP 또는 `options.override.pip`로 커스텀 PiP

### 재생목록/네비게이션

- `PrevBtn`: 이전 콘텐츠로 이동
- `NextBtn`: 다음 콘텐츠로 이동
- `NextPrevBtn`: 이전/다음 버튼 묶음

### 부가 버튼

- `SettingBtn`: 설정 모달 열기
- `ShareBtn`: Web Share API 또는 클립보드 복사

## 설정 모달

### `SettingModal`

- 화질, 재생 속도, 자막 선택 UI 제공
- `usePlayerController`의 `selectQualityLevel`, `playBackRate`를 내부적으로 사용

```ts
text: {
  setting: string;
  quality: string;
  autoplay: string;
  playbackRate: string;
  captions: string;
  auto?: string;
  notUse?: string;
};
vtt?: SubtitleTrack[];
src?: { vtt?: SubtitleTrack[] };
options?: { playRateSetting?: number[]; autostart?: boolean };
```

## 오버레이/레이아웃 컴포넌트

- `InitPlayerUi`: 초기 플레이 버튼 오버레이
- `LoadingUi`: 로딩 스피너 오버레이
- `StartTimeUi`: 예약/시작 시간 카드 표시
- `WatermarkUi`: 워터마크 텍스트 표시(랜덤/고정 위치 지원)
- `DoubleTapSeekOverlay`: 모바일 더블탭 탐색 오버레이
- `MetaDesc`: 제목/프로필/작성시간 메타 정보 표시
- `Blank`: 레이아웃용 스페이서
- `Group`: 버튼 그룹 래퍼

### `DoubleTapSeekOverlay` Props

```ts
seekSeconds?: number;
doubleTapWindowMs?: number;
executeDelayMs?: number;
onSingleTap?: (side: "left" | "right") => void;
```

## 훅/상태 관리

### `PlayerStoreProvider`

- 동일 페이지에서 여러 플레이어를 분리 관리하려면 반드시 사용합니다.
- `scopeId`를 직접 지정하거나 자동 생성합니다.

### `usePlayerState`

- 플레이어 상태를 읽고 패치합니다.
- 재생 상태, 로딩 상태, 자막/음량 상태, 화질 정보 등을 포함합니다.

### `usePlayerController`

- 재생 제어 API를 제공합니다.
- 주요 메소드: `play`, `pause`, `togglePlay`, `seekTo`, `setVolume`, `toggleMute`, `toggleSubtitle`, `selectQualityLevel`, `togglePictureInPicture`, `toggleFullscreen`, `fullscreenOn`, `fullscreenOff` 등.

### `useDeviceState`

- 미디어쿼리 기반으로 `isMobile`, `isPortrait` 상태를 제공합니다.

### `usePlayerKeyboardControls`

- 키보드 제어를 등록합니다.
- `options.keyboardShortcut`이 `true`일 때만 동작합니다.
- 단축키: Space(재생/일시정지), 좌/우(10초 이동), F(전체화면), M(음소거)

## 유틸

- `$util.formatTime(seconds)` 형태로 시간 문자열을 생성합니다.

## 개발 명령

```bash
pnpm dev
pnpm build
pnpm preview
pnpm lint
```

## 빌드 산출물

- ESM: `dist/vpe-react-ui.es.js`
- UMD: `dist/vpe-react-ui.umd.js`