Files
2026-05-27 23:29:53 +01:00

3.4 KiB

Tasks: enterprise-react-video

Change ID: enterprise-react-video Package: @suaveplan/react-video Target path: react/media/react-video Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/react-translate


0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Scaffold

  • Create directory tree. Write package.json at 0.1.0, tsconfig.json, vitest.config.ts, scripts.
  • Dependencies: @suaveplan/error workspace:^, @suaveplan/react-translate workspace:^, zod catalog:forms, @opentelemetry/api catalog:observability, tslib catalog:build.

2. Error codes and types

  • Define VideoError; codes: VIDEO_LOAD_FAILED, VIDEO_PLAYBACK_ERROR.
  • Define VideoSource, VideoTrack, PlaylistItem, PlaylistProps, VideoControlsProps, VideoPlayerProps.
  • Write VideoSourceSchema Zod schema.

3. Utils — formatTime

  • formatTime(seconds: number): string → 'm:ss' or 'h:mm:ss'.
  • Write test + md.

4. Hook — useVideoPlayer

  • Manages videoRef, isPlaying, currentTime, duration, volume, playbackRate, isMuted, isFullscreen.
  • play(), pause(), seek(time), setVolume(vol), setPlaybackRate(rate), mute(), unmute(), enterFullscreen(), exitFullscreen().
  • Keyboard shortcuts (Space, Left/Right, Up/Down, F) via keydown listener on the container ref.
  • OTel video.play / video.pause spans. Throws VideoError(VIDEO_PLAYBACK_ERROR) on error event.
  • Write use-video-player.test.ts (≤500 lines): play/pause/seek/volume/fullscreen/keyboard. { timeout: 10000 }.
  • Write use-video-player.md.

5. Components

VideoControls

  • Play/pause button, scrubber (<input type="range">), volume slider, speed selector, fullscreen button.
  • aria-label on all controls via useTranslation.
  • Write test, stories (default, minimal, playground), md.

VideoPlayer

  • Renders <video> with source elements; wires useVideoPlayer; optionally renders VideoControls; accepts tracks for <track> WebVTT subtitles.
  • Write test, stories (default, with-playlist, with-subtitles, fullscreen, playground), md.

VideoPlaylist

  • Renders playlist items; highlights current; click to switch source.
  • Write test, stories, md.

6. E2E

  • e2e/video.spec.ts — Playwright:
    • Render VideoPlayer with mock src, click play → isPlaying true.
    • Press Space → pause; Left arrow → seek back.
    • Render VideoPlaylist, click second item → source changes.

7. Verify and publish

  • bunx turbo lint typecheck test --filter=@suaveplan/react-video — green.
  • bunx turbo test:coverage --filter=@suaveplan/react-video — 100%.
  • bun scripts/publish.ts --package @suaveplan/react-video.
  • Archive change folder.