Skip to content

fix(mobile): forward image props to Expo Image - #86

Merged
GSTJ merged 1 commit into
mainfrom
GSTJ/fix-mobile-image-props
Jul 27, 2026
Merged

fix(mobile): forward image props to Expo Image#86
GSTJ merged 1 commit into
mainfrom
GSTJ/fix-mobile-image-props

Conversation

@GSTJ

@GSTJ GSTJ commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

Image options and callbacks were landing on the layout wrapper instead of the native image, so contentFit, contentPosition, transition, recyclingKey and the load callbacks were dropped at every call site. Rendering one Expo Image fixes it.

Details

  • Renders a single Expo Image, so whatever a caller passes reaches the component that owns it. Keeping the wrapper would mean hand-separating every current and future Image prop from View props, which is how these got lost in the first place.
  • The API's blurhash moves onto placeholder, where expo-image expects it: one source can't carry both uri and blurhash. Caller-provided placeholders, placeholderContentFit and cache policies still win, and memory-and-disk stays the default.
  • The blurhash placeholder inherits the image's own contentFit so it doesn't crop differently from the photo that replaces it.
  • Every call site is a styled(Image) with width, height and border-radius, all of which expo-image applies itself, so the overflow: hidden wrapper wasn't buying anything.
  • Rebased onto main. The old branch also had a verify:image-props tsx script that ran nowhere in CI; that's now three jest suites, which pnpm test picks up on every branch push.

Proof

720x240 image in a 150x150 box on an iPhone 17 Pro Max simulator, Release build. contain keeps all four colour bands, cover crops to the middle two. Top row is main with contentFit="contain" then "cover", identical because both were dropped. Middle row is this branch, same two props, honoured. Bottom row is contentPosition left then right.

contentFit old vs new

Testing steps

  1. pnpm --filter @pegada/mobile test (12 tests). Image.test.tsx renders the component with expo-image mocked and asserts the props arrive on it; drop the {...props} spread and both of its cases fail.
  2. Open the swipe screen, Messages, a chat, Profile and Edit profile, and confirm every dog photo renders with the expected crop and rounded corners.
  3. Switch between light and dark mode and confirm the photos stay visible.

@GSTJ

GSTJ commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

Verification for e8f83ca:

  • corepack pnpm --version: 9.6.0
  • corepack pnpm --filter @pegada/mobile verify:image-props: passed
  • corepack pnpm --filter @pegada/mobile typecheck: passed
  • Scoped Oxlint, Oxfmt, and git diff --check: passed
  • Release iOS simulator build: passed
  • Simulator: 8C6F98B8-C89E-4FD8-91CC-2CA518E7F44C (isolated from the main test simulator)
  • Final app process: PID 11042, still alive after 1m05s
  • Light screenshot: /private/tmp/pegada-image-props-evidence/final/light/current.png
  • Dark screenshot: /private/tmp/pegada-image-props-evidence/final/dark/swipe-retry.png

The full workspace test command is still blocked before the test phase because Turbo does not pass DIRECT_URL to the API Prisma pretest. The mobile checks above are green, and that workspace issue is unchanged from main.

@GSTJ
GSTJ marked this pull request as ready for review July 22, 2026 13:26
@GSTJ
GSTJ marked this pull request as draft July 22, 2026 13:35
Image options and callbacks were landing on the layout wrapper instead of
the native image, so contentFit, contentPosition, transition, recyclingKey
and the load callbacks were silently dropped at every call site.

Renders a single Expo Image so anything the caller passes reaches the
component that owns it. The API blurhash moves onto `placeholder`, which
is where expo-image expects it, since one source can't carry both `uri`
and `blurhash`. Caller-provided placeholders, placeholderContentFit and
cache policies still win, and memory-and-disk stays the default.

Claude-Session: https://claude.ai/code/session_01VfiCAFzqYFLkBWfQuQWCvK
@GSTJ
GSTJ force-pushed the GSTJ/fix-mobile-image-props branch from 0c75d63 to 60f0f1f Compare July 26, 2026 23:14
@GSTJ

GSTJ commented Jul 27, 2026

Copy link
Copy Markdown
Owner Author

Rebased onto main (the old merge commit left a duplicated babel-jest key in apps/mobile/package.json, which is what Format was failing on) and replaced the verify:image-props tsx script with jest suites, since that script ran nowhere in CI and pnpm test now runs on branch pushes.

pnpm --filter @pegada/mobile test:

PASS src/components/Image.test.tsx
  ✓ hands every image prop to Expo Image, on a single node
  ✓ keeps the style on the image itself instead of a wrapper

PASS src/views/(auth)/SignIn/components/HeroText/index.test.jsx
  ✓ renders en-US without React key warnings
  ✓ renders pt-BR without React key warnings

PASS src/components/imageProps.test.ts
  ✓ moves an API blurhash onto the placeholder and keeps the source clean
  ✓ defaults the blurhash fit to cover when the caller sets no contentFit
  ✓ leaves a caller-provided placeholder and cache policy alone
  ✓ treats an explicit null placeholder and cache policy as opting out
  ✓ passes a 42 source straight through
  ✓ passes a "https://images.pegada.app/static.webp" source straight through
  ✓ passes a null source straight through
  ✓ passes a responsive source array straight through

Test Suites: 3 passed, 3 total
Tests:       12 passed, 12 total

With {...props} removed from the ExpoImage element, both cases in Image.test.tsx fail on the missing contentPosition / recyclingKey / transition, and the style assertion catches props landing anywhere other than the image.

Also pnpm typecheck (5 packages), oxlint (0 errors), oxfmt --check and pnpm dedupe --check, all clean, plus the Release simulator build behind the screenshot in the description.

@GSTJ
GSTJ marked this pull request as ready for review July 27, 2026 00:11
@GSTJ
GSTJ merged commit 1a7ec86 into main Jul 27, 2026
17 checks passed
@GSTJ
GSTJ deleted the GSTJ/fix-mobile-image-props branch July 27, 2026 00:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant