diff --git a/AGENTS.md b/AGENTS.md index ddd5a7b..6a8fb5c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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 diff --git a/README.md b/README.md index 856df58..bf48d6e 100644 --- a/README.md +++ b/README.md @@ -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: @@ -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 +``` + +### Shadow / Elevation + +Shadow properties are iOS-only (`shadowOpacity`, `shadowRadius`, `shadowColor`, `shadowOffset`). On Android, use `elevation` for material shadows. + +```tsx + +``` + ### Animatable Properties All properties are set in the `animate` prop as flat values (no transform array). @@ -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 }} /> ``` @@ -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. @@ -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) diff --git a/docs/docs/api-reference.mdx b/docs/docs/api-reference.mdx index 8b9e5a4..85e26bc 100644 --- a/docs/docs/api-reference.mdx +++ b/docs/docs/api-reference.mdx @@ -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` @@ -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) diff --git a/docs/docs/usage.mdx b/docs/docs/usage.mdx index 2b1ceda..9b538d3 100644 --- a/docs/docs/usage.mdx +++ b/docs/docs/usage.mdx @@ -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. @@ -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 + +``` + +## Shadow / Elevation + +Shadow properties are iOS-only. On Android, use `elevation` for material shadows. + +```tsx + +``` + ## Animatable properties ```tsx @@ -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 }} /> ``` diff --git a/skills/react-native-ease-refactor/SKILL.md b/skills/react-native-ease-refactor/SKILL.md index c931533..a8f6d2c 100644 --- a/skills/react-native-ease-refactor/SKILL.md +++ b/skills/react-native-ease-refactor/SKILL.md @@ -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: ``" -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: ``" +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 @@ -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 @@ -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) @@ -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