Skip to content

feat: add shadow properties (iOS) and elevation (Android)#35

Merged
janicduplessis merged 14 commits intomainfrom
@janic/feat-shadow-elevation
Apr 14, 2026
Merged

feat: add shadow properties (iOS) and elevation (Android)#35
janicduplessis merged 14 commits intomainfrom
@janic/feat-shadow-elevation

Conversation

@janicduplessis
Copy link
Copy Markdown
Collaborator

Summary

React Native's shadow API (shadowOpacity, shadowRadius, shadowColor, shadowOffset) is iOS-only and uses CALayer properties, while Android uses elevation for material shadows. Neither is currently animatable through EaseView.

This PR adds native animation support for both platforms following the existing per-property pattern:

  • iOS: shadowOpacity, shadowRadius, shadowColor, shadowOffsetX, shadowOffsetY — animated via Core Animation key-path animations on the corresponding CALayer properties. Shadow offset X/Y are animated together as a single shadowOffset CGSize animation.
  • Android: elevation — animated via ObjectAnimator (timing) with spring falling back to timing, matching the borderRadius pattern.

All six properties get their own bitmask flag so they can coexist with style-managed values. A new shadow transition category allows per-category animation config for all shadow/elevation properties.

Test Plan

  • yarn format:write && yarn lint && yarn test — all 71 tests pass, including 15 new tests covering shadow/elevation prop resolution, bitmask flags, initialAnimate, shadowColor, and style conflict stripping.
  • Native behavior should be verified by running the example app on iOS simulator and Android emulator with shadow/elevation in animate:
<EaseView
  animate={{
    shadowOpacity: 0.5,
    shadowRadius: 10,
    shadowOffsetY: 4,
    elevation: 8,
  }}
  transition={{ shadow: { type: 'spring', damping: 15 } }}
/>

…upport

Adds animatable shadow/elevation properties following the existing
per-property pattern: bitmask flags, codegen props, native change
detection, and platform-specific animation.

iOS: shadowOpacity, shadowRadius, shadowColor, shadowOffset via
Core Animation key-path animations.
Android: elevation via ObjectAnimator.
clang-format introduced a stray 'l' at the beginning of the file,
causing a compilation error.
…emove web elevation

- shadowOffset is now { width, height } matching RN style API (flattened to native props)
- Consolidated MASK_SHADOW_OFFSET into single bit (1 << 15)
- MASK_ELEVATION shifted to 1 << 16
- Removed elevation from web (no-op in react-native-web)
@janicduplessis janicduplessis force-pushed the @janic/feat-shadow-elevation branch from fb7d691 to 11791cb Compare April 14, 2026 02:12
…ius is not animated

When borderRadius is not in the animated bitmask, use
ViewOutlineProvider.BACKGROUND so elevation shadows respect the style
borderRadius from the background drawable. Only switch to the custom
provider when borderRadius is actively animated.
cornerRadius alone rounds the view's background visually. masksToBounds
clips children and shadows, which conflicts with shadow animations and
doesn't match RN's default overflow:visible. Let the style system
control masksToBounds via the overflow prop instead.
When borderRadius is animated via ObjectAnimator, the BorderDrawable
was not updated, causing borders to render with square corners.
Now setAnimateBorderRadius also calls
BackgroundStyleApplicator.setBorderRadius to keep the border drawable
in sync with the animated corner radius.
@janicduplessis janicduplessis merged commit 6ce7d49 into main Apr 14, 2026
5 checks passed
@janicduplessis janicduplessis deleted the @janic/feat-shadow-elevation branch April 14, 2026 02:43
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