Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ transition={{ type: 'spring', damping: 10 }} → transitionType="spring", tran
- `README.md` (props table + usage section)
- `docs/docs/usage.mdx` (usage guide)
- `docs/docs/api-reference.mdx` (API reference table)
- `skills/react-native-ease-refactor/SKILL.md` (supported properties list, transition category keys, decision tree)

## Development Commands

Expand Down
56 changes: 53 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ Available category keys:
| `opacity` | opacity |
| `borderRadius` | borderRadius |
| `backgroundColor` | backgroundColor |
| `border` | borderWidth, borderColor |
| `shadow` | shadowOpacity, shadowRadius, shadowColor, shadowOffset, elevation |

Use `default` as a fallback for categories not explicitly listed:

Expand All @@ -267,7 +269,7 @@ When no `default` key is provided, the library default (timing 300ms easeInOut)

### Border Radius

`borderRadius` can be animated just like other properties. It uses hardware-accelerated platform APIs — `ViewOutlineProvider` + `clipToOutline` on Android and `layer.cornerRadius` + `layer.masksToBounds` on iOS. Unlike RN's style-based `borderRadius` (which uses a Canvas drawable on Android), this clips children properly and is GPU-accelerated.
`borderRadius` can be animated just like other properties. It uses hardware-accelerated platform APIs — `ViewOutlineProvider` + `clipToOutline` on Android and `layer.cornerRadius` on iOS.

```tsx
<EaseView
Expand Down Expand Up @@ -302,6 +304,38 @@ On Android, background color uses `ValueAnimator.ofArgb()` (timing only — spri

When `backgroundColor` is in `animate`, any `backgroundColor` in `style` is automatically stripped to avoid conflicts.

### Border

`borderWidth` and `borderColor` can be animated. On iOS, these use Core Animation on the `CALayer` border properties. On Android, they use `BackgroundStyleApplicator` which updates the `BorderDrawable` each frame.

```tsx
<EaseView
animate={{
borderWidth: selected ? 3 : 0,
borderColor: selected ? '#3B82F6' : '#E5E7EB',
}}
transition={{ border: { type: 'spring', damping: 15, stiffness: 120 } }}
style={styles.card}
/>
```

### Shadow / Elevation

Shadow properties are iOS-only (`shadowOpacity`, `shadowRadius`, `shadowColor`, `shadowOffset`). On Android, use `elevation` for material shadows.

```tsx
<EaseView
animate={{
shadowOpacity: active ? 0.4 : 0,
shadowRadius: active ? 16 : 0,
shadowOffset: active ? { width: 0, height: 8 } : { width: 0, height: 0 },
elevation: active ? 12 : 0,
}}
transition={{ shadow: { type: 'spring', damping: 15, stiffness: 120 } }}
style={{ shadowColor: '#000', backgroundColor: '#fff', borderRadius: 16 }}
/>
```

### Animatable Properties

All properties are set in the `animate` prop as flat values (no transform array).
Expand All @@ -318,8 +352,15 @@ All properties are set in the `animate` prop as flat values (no transform array)
rotate: 0, // Z-axis rotation in degrees
rotateX: 0, // X-axis rotation in degrees (3D)
rotateY: 0, // Y-axis rotation in degrees (3D)
borderRadius: 0, // pixels (hardware-accelerated, clips children)
borderRadius: 0, // pixels (hardware-accelerated)
backgroundColor: 'transparent', // any RN color value
borderWidth: 0, // pixels
borderColor: 'black', // any RN color value
shadowOpacity: 0, // 0–1 (iOS only)
shadowRadius: 0, // pixels (iOS only)
shadowColor: 'black', // any RN color value (iOS only)
shadowOffset: { width: 0, height: 0 }, // iOS only
elevation: 0, // Android material shadow
}}
/>
```
Expand Down Expand Up @@ -502,8 +543,15 @@ A `View` that animates property changes using native platform APIs.
| `rotate` | `number` | `0` | Z-axis rotation in degrees |
| `rotateX` | `number` | `0` | X-axis rotation in degrees (3D) |
| `rotateY` | `number` | `0` | Y-axis rotation in degrees (3D) |
| `borderRadius` | `number` | `0` | Border radius in pixels (hardware-accelerated, clips children) |
| `borderRadius` | `number` | `0` | Border radius in pixels (hardware-accelerated) |
| `backgroundColor` | `ColorValue` | `'transparent'` | Background color (any RN color value). Timing-only on Android, spring+timing on iOS. |
| `borderWidth` | `number` | `0` | Border width in pixels |
| `borderColor` | `ColorValue` | `'black'` | Border color |
| `shadowOpacity` | `number` | `0` | Shadow opacity 0–1 (iOS only) |
| `shadowRadius` | `number` | `0` | Shadow blur radius (iOS only) |
| `shadowColor` | `ColorValue` | `'black'` | Shadow color (iOS only) |
| `shadowOffset` | `object` | `{width:0,height:0}` | Shadow offset `{ width, height }` (iOS only) |
| `elevation` | `number` | `0` | Material shadow elevation (Android only) |

Properties not specified in `animate` default to their identity values.

Expand Down Expand Up @@ -552,6 +600,8 @@ A per-property map that applies different transition configs to different proper
| `opacity` | opacity |
| `borderRadius` | borderRadius |
| `backgroundColor` | backgroundColor |
| `border` | borderWidth, borderColor |
| `shadow` | shadowOpacity, shadowRadius, shadowColor, shadowOffset, elevation |

## Hardware Layers (Android)

Expand Down
9 changes: 9 additions & 0 deletions docs/docs/api-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ A `View` that animates property changes using native platform APIs.
| `rotateY` | `number` | `0` | Y-axis rotation in degrees |
| `borderRadius` | `number` | `0` | Border radius in pixels |
| `backgroundColor` | `ColorValue` | `'transparent'` | Background color |
| `borderWidth` | `number` | `0` | Border width in pixels |
| `borderColor` | `ColorValue` | `'black'` | Border color |
| `shadowOpacity` | `number` | `0` | Shadow opacity 0–1 (iOS only) |
| `shadowRadius` | `number` | `0` | Shadow blur radius (iOS only) |
| `shadowColor` | `ColorValue` | `'black'` | Shadow color (iOS only) |
| `shadowOffset` | `object` | `{width:0,height:0}` | Shadow offset `{ width, height }` (iOS only) |
| `elevation` | `number` | `0` | Material shadow elevation (Android only) |

## `TimingTransition`

Expand Down Expand Up @@ -82,6 +89,8 @@ A per-property map that applies different transition configs to different proper
| `opacity` | opacity |
| `borderRadius` | borderRadius |
| `backgroundColor` | backgroundColor |
| `border` | borderWidth, borderColor |
| `shadow` | shadowOpacity, shadowRadius, shadowColor, shadowOffset, elevation |

## Hardware layers (Android)

Expand Down
39 changes: 39 additions & 0 deletions docs/docs/usage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ Available category keys:
| `opacity` | opacity |
| `borderRadius` | borderRadius |
| `backgroundColor` | backgroundColor |
| `border` | borderWidth, borderColor |
| `shadow` | shadowOpacity, shadowRadius, shadowColor, shadowOffset, elevation |

When no `default` key is provided, the library default (timing 300ms easeInOut) applies to all categories.

Expand Down Expand Up @@ -125,6 +127,36 @@ When `borderRadius` is in `animate`, any `borderRadius` in `style` is automatica

On Android, background color uses timing animation only. On iOS, it supports both timing and spring transitions.

## Border

```tsx
<EaseView
animate={{
borderWidth: selected ? 3 : 0,
borderColor: selected ? '#3B82F6' : '#E5E7EB',
}}
transition={{ border: { type: 'spring', damping: 15, stiffness: 120 } }}
style={styles.card}
/>
```

## Shadow / Elevation

Shadow properties are iOS-only. On Android, use `elevation` for material shadows.

```tsx
<EaseView
animate={{
shadowOpacity: active ? 0.4 : 0,
shadowRadius: active ? 16 : 0,
shadowOffset: active ? { width: 0, height: 8 } : { width: 0, height: 0 },
elevation: active ? 12 : 0,
}}
transition={{ shadow: { type: 'spring', damping: 15, stiffness: 120 } }}
style={{ shadowColor: '#000', backgroundColor: '#fff', borderRadius: 16 }}
/>
```

## Animatable properties

```tsx
Expand All @@ -141,6 +173,13 @@ On Android, background color uses timing animation only. On iOS, it supports bot
rotateY: 0,
borderRadius: 0,
backgroundColor: 'transparent',
borderWidth: 0,
borderColor: 'black',
shadowOpacity: 0, // iOS only
shadowRadius: 0, // iOS only
shadowColor: 'black', // iOS only
shadowOffset: { width: 0, height: 0 }, // iOS only
elevation: 0, // Android only
}}
/>
```
Expand Down
15 changes: 11 additions & 4 deletions skills/react-native-ease-refactor/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ Apply these checks in order. The first match determines the result:
5c. **Uses `withDelay` wrapping `withSequence` or nested `withDelay`?** → NOT migratable — "Complex delay/sequencing not supported"
6. **Uses complex `interpolate()`?** (more than 2 input/output values) → NOT migratable — "Complex interpolation"
7. **Uses `layout={...}` prop?** → NOT migratable — "Layout animation"
8. **Animates unsupported properties?** (anything besides: opacity, translateX, translateY, scale, scaleX, scaleY, rotate, rotateX, rotateY, borderRadius, backgroundColor) → NOT migratable — "Animates unsupported property: `<prop>`"
9. **Uses different transition configs per property?** (e.g., opacity uses 200ms timing, scale uses spring) → MIGRATABLE — map to `TransitionMap` with category keys (`transform`, `opacity`, `borderRadius`, `backgroundColor`, `default`)
8. **Animates unsupported properties?** (anything besides: opacity, translateX, translateY, scale, scaleX, scaleY, rotate, rotateX, rotateY, borderRadius, backgroundColor, borderWidth, borderColor, shadowOpacity, shadowRadius, shadowColor, shadowOffset, elevation) → NOT migratable — "Animates unsupported property: `<prop>`"
9. **Uses different transition configs per property?** (e.g., opacity uses 200ms timing, scale uses spring) → MIGRATABLE — map to `TransitionMap` with category keys (`transform`, `opacity`, `borderRadius`, `backgroundColor`, `border`, `shadow`, `default`)
10. **Not driven by state?** (animation triggered by gesture/scroll value, not React state) → NOT migratable — "Not state-driven"
11. **Otherwise** → MIGRATABLE

Expand Down Expand Up @@ -363,6 +363,13 @@ All properties in the `animate` prop:
| `rotateY` | `number` | `0` | Y-axis rotation in degrees (3D) |
| `borderRadius` | `number` | `0` | In pixels |
| `backgroundColor` | `ColorValue` | `'transparent'` | Any RN color value |
| `borderWidth` | `number` | `0` | In pixels |
| `borderColor` | `ColorValue` | `'black'` | Any RN color value |
| `shadowOpacity` | `number` | `0` | 0–1 (iOS only) |
| `shadowRadius` | `number` | `0` | In pixels (iOS only) |
| `shadowColor` | `ColorValue` | `'black'` | Any RN color value (iOS only) |
| `shadowOffset` | `object` | `{width:0,height:0}` | `{ width, height }` (iOS only) |
| `elevation` | `number` | `0` | Android material shadow |

### Transition Types

Expand Down Expand Up @@ -400,7 +407,7 @@ transition={{ type: 'none' }}

- `animate` — target values for animated properties
- `initialAnimate` — starting values (animates to `animate` on mount)
- `transition` — animation config: a single `SingleTransition` (timing/spring/none) OR a `TransitionMap` with category keys (`default`, `transform`, `opacity`, `borderRadius`, `backgroundColor`)
- `transition` — animation config: a single `SingleTransition` (timing/spring/none) OR a `TransitionMap` with category keys (`default`, `transform`, `opacity`, `borderRadius`, `backgroundColor`, `border`, `shadow`)
- `onTransitionEnd` — callback with `{ finished: boolean }`
- `transformOrigin` — pivot point as `{ x: 0-1, y: 0-1 }`, default center
- `useHardwareLayer` — Android GPU optimization (boolean, default false)
Expand All @@ -409,7 +416,7 @@ transition={{ type: 'none' }}
### Important Constraints

- **Loop requires timing** (not spring) and `initialAnimate` must define the start value
- **Per-property transitions supported** — pass a `TransitionMap` with category keys (`default`, `transform`, `opacity`, `borderRadius`, `backgroundColor`) to use different configs per property group
- **Per-property transitions supported** — pass a `TransitionMap` with category keys (`default`, `transform`, `opacity`, `borderRadius`, `backgroundColor`, `border`, `shadow`) to use different configs per property group
- **No animation sequencing** — no equivalent to `withSequence`. Simple `withDelay` IS supported via the `delay` transition prop
- **No gesture/scroll-driven animations** — EaseView is state-driven only
- **Style/animate conflict** — if a property appears in both `style` and `animate`, the animated value wins
Loading