4.1 KiB
4.1 KiB
Tasks: enterprise-react-media
Change ID: enterprise-react-media
Package: @suaveplan/react-media
Target path: react/media/react-media
Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/types, @suaveplan/react-translate, @suaveplan/timing
0. Pre-flight (non-negotiable)
- 0.1 Confirm clean working tree (
git statusreports nothing) and no in-flight worktrees with uncommitted work (git worktree listthengit statusin 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.mdmatchesfind packages -maxdepth 3 -name package.jsoncount. Drift here means a prior change archived without regenerating the manifest.
1. Scaffold
- Create directory tree per proposal layout.
- Write
package.jsonat0.1.0with"sideEffects": false, explicit exports map. - Dependencies:
@suaveplan/error workspace:^,@suaveplan/types workspace:^,@suaveplan/react-translate workspace:^,@suaveplan/timing workspace:^,@react-three/drei catalog:3d,@react-three/fiber catalog:3d,zod catalog:forms,@opentelemetry/api catalog:observability,tslib catalog:build. - Write
tsconfig.json,vitest.config.ts, scripts.
2. Error codes and types
- Define
MediaErrorextendingSuaveplanError; codes:MEDIA_LOAD_FAILED,MEDIA_FORMAT_UNSUPPORTED,MEDIA_SOURCE_NOT_FOUND. - Define
MediaConfig,MediaVariant,MediaSource,AdaptiveQualityOptions,ServiceWorkerConfig. - Write Zod
MediaConfigSchema.
3. MediaProvider + context
MediaProvider— acceptsconfig: MediaConfig,fetchFn?: typeof fetch(defaultglobalThis.fetch). Provides alluse*hooks.useMediaConfig,useMediaError,useMediaPath,useMediaSource,useMediaVariant— consume context.- Write tests (no
vi.stubGlobal— inject mockfetchFn) + md.
4. Hooks
useLazyLoad(ref)—IntersectionObserver-based; returnsisVisible.useAdaptiveQuality(src)— selects quality tier based on connection type fromconnection-qualityutil.useProgressiveImage(src, placeholder)— loads full image after placeholder; returnscurrentSrc,isLoading.useServiceWorker(options)— registers/unregisters service worker for media caching.- Write tests + md for each. All use real DI, no mocks.
{ timeout: 10000 }.
5. Components
For each (Media, ImageRenderer, VideoRenderer, AudioRenderer, Model3DRenderer, DocumentRenderer, PictureRenderer, ProgressiveImage, MediaErrorBoundary, PerformanceDashboard, PerformanceBadge):
- Implement with OTel
media.loadspan on successful load. MediaErrorBoundary— extends@suaveplan/react-error-boundarywith media-specific fallback.- Write test + stories (default, loading, error, playground) + md.
6. Utils
connection-quality/—getConnectionQuality(): 'low' | 'medium' | 'high'usingnavigator.connection. Write test + md.image-optimization/—generateSrcSet(url, widths[]),getOptimalFormat(accept). Write test + md.media-cache/— LRU cache for media blobs. Write test + md.responsive-images/—buildPictureSourceSet(image). Write test + md.style-helpers/— aspect-ratio, object-fit helpers. Write test + md.
7. E2E
e2e/media.spec.ts— Playwright:ImageRendererwith lazy-load: scroll into view → image loads.VideoRenderer: play button → video plays.ProgressiveImage: placeholder shown immediately, full image loads after.
8. Verify and publish
bunx turbo lint typecheck test --filter=@suaveplan/react-media— green.bunx turbo test:coverage --filter=@suaveplan/react-media— 100%.bun scripts/publish.ts --package @suaveplan/react-media.- Archive change folder.