Skip to content

Pass through raw numeric and color style values instead of throwing when not found in theme#356

Closed
KAMRONBEK wants to merge 1 commit into
Shopify:masterfrom
KAMRONBEK:fix-raw-style-value-passthrough
Closed

Pass through raw numeric and color style values instead of throwing when not found in theme#356
KAMRONBEK wants to merge 1 commit into
Shopify:masterfrom
KAMRONBEK:fix-raw-style-value-passthrough

Conversation

@KAMRONBEK

Copy link
Copy Markdown

Problem

Animated restyle components crash under react-native-reanimated 4.4+ (issue #355, two independent reports). Reanimated 4.4 ships the default-on FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS flag: when an animation settles, it re-renders the wrapped component with the resolved raw style values spread as top-level props. On an Animated.createAnimatedComponent(Box) those arrive as theme-key props with raw values, and restyle throws:

Value '13' does not exist in theme['borderRadii']            // animated borderRadius
Value 'rgba(255,209,102,1)' does not exist in theme['colors'] // animated backgroundColor

Root cause

In src/utilities/getThemeValue.ts, any truthy value that is not a key in the theme scale throws — regardless of whether it is a legitimate literal style value (a raw pixel number, an rgba/hex color string) or a genuine typo'd theme key. Peer theme-prop libraries (styled-system, dripsy) pass unknown values through, so restyle's strictness turns benign upstream behavior into render crashes.

Fix

getThemeValue now passes a value through as-is when it is not a key in the theme scale but is a valid raw style value:

  • numeric literals (e.g. borderRadius={13}) — valid for the numeric scales (borderRadii, spacing, zIndices, custom scales), and RN also accepts processed-color ints;
  • unambiguous raw color strings#hex (3/4/6/8 digits) and rgb()/rgba()/hsl()/hsla()/hwb() functional notation.

Unresolvable string keys (e.g. backgroundColor="primaryy", borderRadius="xxl") still throw exactly as before, preserving the typo-catching behavior — raw color syntax is never a plausible theme key, so typo detection is not weakened. Named colors ('red', 'transparent') intentionally do NOT pass through, because they could shadow misspelled theme keys; Reanimated settles colors as rgba() strings, which are covered.

The passthrough composes with responsive values for free (getResponsiveValue resolves the breakpoint value and funnels it through getThemeValue), and with the memoization in createRestyleFunction (passthrough results memoize per theme/property/value like any other). It is also consistent with the existing behavior for falsy values (borderRadius={0} already passed through raw). I kept the passthrough silent rather than adding a dev-mode warning since the codebase has no console.warn/__DEV__ convention anywhere in src/ — happy to add one if preferred.

Tests

  • createRestyleFunction.test.ts: raw numeric borderRadius (13) passes through on a borderRadii scale — plain and inside a {phone: 13} responsive object; raw rgba(...) and #hex strings pass through on the colors scale; misspelled string keys ('xxl' on borderRadii, 'primaryy' on colors) still throw; theme-key lookup ('m' → 8) unchanged.
  • createRestyleComponent.test.tsx: component-level repros of both reports — <Component borderRadius={13 as never} /> and <Component backgroundColor={'rgba(255, 209, 102, 1)' as never} /> render with the raw values (the casts mirror Reanimated spreading settled values as props, bypassing TypeScript).

All 6 new passthrough tests fail without the fix (verified by temporarily reverting getThemeValue.ts); full suite is 53/53, and yarn lint (eslint + tsc --noEmit) and yarn build pass.

Fixes #355

When a theme-key prop received a value that is not a key in the theme
scale, getThemeValue threw even for valid raw style values.
react-native-reanimated 4.4+ re-renders settled animations with the
resolved raw values set as top-level props (e.g. borderRadius: 13,
backgroundColor: 'rgba(255, 209, 102, 1)'), crashing animated restyle
components.

Numeric literals and unambiguous raw color strings (hex / rgb / rgba /
hsl / hsla / hwb) now pass through as-is, matching styled-system and
dripsy, while unresolvable string keys (likely typos) still throw.

Fixes Shopify#355
@KAMRONBEK

Copy link
Copy Markdown
Author

@naqvitalha @gvarandas TL;DR for #355: when a Reanimated 4.4+ animation settles it re-renders with the raw settled value as a prop (e.g. borderRadius: 13, backgroundColor: 'rgba(…)'), and getThemeValue throws 'Value X does not exist in theme…' — breaking any AnimatedBox on the current restyle+reanimated pair. Fix: numeric literals and raw color strings pass through when they aren't theme keys (styled-system/dripsy parity), while misspelled string theme keys still throw exactly as before (the typo-catching path is covered by tests). Two independent reporters confirmed the crash in the issue; happy to gate the passthrough behind a flag or add a DEV warning if you'd prefer stricter theming.

@KAMRONBEK

Copy link
Copy Markdown
Author

I have signed the CLA!

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.

Reanimated 4.4.x animated components conflict with Restyle theme

1 participant