3.8 KiB
3.8 KiB
Tasks: enterprise-react-image
Change ID: enterprise-react-image
Package: @suaveplan/react-image
Target path: react/media/react-image
Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/react-translate
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, exports map. - Dependencies:
@suaveplan/error workspace:^,@suaveplan/react-translate workspace:^,zod catalog:forms,@opentelemetry/api catalog:observability,tslib catalog:build. - Write
tsconfig.json,vitest.config.ts, scripts.
2. Error codes and types
- Define
ImageErrorextendingSuaveplanError; codes:IMAGE_LOAD_FAILED,IMAGE_DECODE_FAILED,IMAGE_CROP_INVALID. - Define all component prop types in
src/types/.
3. Utils
src/utils/blurhash/—decodeBlurhash(hash, width, height): Uint8ClampedArray,blurhashToDataURL(hash, width, height): string. Write test + md.src/utils/filter-presets/—getFilterCSS(preset: FilterPreset): string(grayscale, sepia, blur, brightness, contrast, invert). Write test + md.
4. Hooks
For each hook (useImageLoader, useImagePreloader, useImageDimensions, useImageColor, useLightbox):
- Implement hook.
useImageLoaderemits OTelimage.loadspan. ThrowsImageErroron failure. - Write test (≤500 lines) + stories (playground) + md.
{ timeout: 10000 }.
5. Components
For each component:
- Implement with i18n via
useTranslation, forward ref, a11y attributes. - Image — lazy loading via
IntersectionObserver, blurhash placeholder, skeleton fallback,srcSet. - Avatar/AvatarGroup — initials fallback, status indicator (online/offline/busy/away), group overlap.
- ImageComparison — draggable split slider; keyboard adjustable.
- ImageCropper — drag-handle crop selection; validates bounds (throws
ImageError(IMAGE_CROP_INVALID)on invalid). - ImageFilter — CSS filter presets via
getFilterCSS; preview toggle. - ImageGallery — masonry layout via CSS columns or absolute positioning.
- ImageMagnifier — hover-activated lens at configurable zoom level.
- ImageOverlay — gradient/reveal overlay wrapper.
- ImagePlaceholder — SVG with
aria-label. - Lightbox — portal-rendered; keyboard nav (Left/Right/Esc); thumbnails; close on backdrop.
- ZoomImage — pinch-to-zoom (touch) + wheel-zoom; pan when zoomed.
- Write test + stories (default, loading, error, interactive, playground) + md for each.
6. E2E
e2e/image.spec.ts— Playwright:Imagewith lazy-load: scroll into view →imgsrc set.ImageCropperdrag: drag handle, verify crop rect changes.Lightbox: click image → lightbox opens; press Right → next image; press Esc → closes.
7. Verify and publish
bunx turbo lint typecheck test --filter=@suaveplan/react-image— green.bunx turbo test:coverage --filter=@suaveplan/react-image— 100%.bun scripts/publish.ts --package @suaveplan/react-image.- Archive change folder.