Skip to content

Commit

Permalink
feat: New style props support in CSS animations (#6944)
Browse files Browse the repository at this point in the history
## Summary

This PR adds support for new animation properties added in RN `0.77` and
implements respective examples for all of added props.

Support was added for the following props
- `boxSizing`
- `outlineColor`
- `outlineOffset`
- `outlineStyle`
- `outlineWidth`
- `mixBlendMode`

Supported props have been also updated in
[this](https://docs.google.com/spreadsheets/d/1PCYJ8e4Kk1R8rJ4J7-iuywW3hYmTcrBJsXWcgSZ9ZjY/edit?gid=0#gid=0)
spreadsheet.
  • Loading branch information
MatiPl01 authored Jan 29, 2025
1 parent 5784672 commit 0e0cf96
Show file tree
Hide file tree
Showing 16 changed files with 425 additions and 15 deletions.
26 changes: 26 additions & 0 deletions apps/common-app/src/apps/css/examples/animations/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ const layoutAndPositioningRoutes = {
name: 'Aspect Ratio',
Component: animatedProperties.layoutAndPositioning.others.AspectRatio,
},
BoxSizing: {
name: 'Box Sizing',
labelTypes: ['web'],
Component: animatedProperties.layoutAndPositioning.others.BoxSizing,
},
},
},
} satisfies Routes;
Expand Down Expand Up @@ -243,6 +248,23 @@ const appearanceRoutes = {
},
},
},
Outlines: {
name: 'Outlines',
routes: {
OutlineOffset: {
name: 'Outline Offset',
Component: animatedProperties.appearance.outlines.OutlineOffset,
},
OutlineStyle: {
name: 'Outline Style',
Component: animatedProperties.appearance.outlines.OutlineStyle,
},
OutlineWidth: {
name: 'Outline Width',
Component: animatedProperties.appearance.outlines.OutlineWidth,
},
},
},
Transforms: {
name: 'Transforms',
flatten: true,
Expand Down Expand Up @@ -311,6 +333,10 @@ const appearanceRoutes = {
name: 'Backface Visibility',
Component: animatedProperties.appearance.others.BackfaceVisibility,
},
MixBlendMode: {
name: 'Mix Blend Mode',
Component: animatedProperties.appearance.others.MixBlendMode,
},
},
},
} satisfies Routes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,26 @@ function OtherColors() {
shadowRadius: spacing.sm,
}}
/>
<ViewExample
title="outlineColor"
animation={{
animationName: {
from: {
outlineColor: 'red',
},
to: {
outlineColor: 'cyan',
},
},
...sharedConfig,
}}
style={{
backgroundColor: colors.primary,
outlineOffset: spacing.xs,
outlineStyle: 'solid',
outlineWidth: spacing.xs,
}}
/>
<ImageExample
labelTypes={['iOS', 'Android']}
source={splashImage}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import borders from './borders';
import colors from './colors';
import others from './others';
import outlines from './outlines';
import shadows from './shadows';
import transforms from './transforms';

export default {
borders,
colors,
others,
outlines,
shadows,
transforms,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { StyleSheet, View } from 'react-native';
import type { CSSAnimationKeyframes } from 'react-native-reanimated';
import Animated from 'react-native-reanimated';

import { balloonsImage } from '@/apps/css/assets';
import { ExamplesScreen, VerticalExampleCard } from '@/apps/css/components';
import { colors, radius, sizes } from '@/theme';

export default function MixBlendMode() {
return (
<ExamplesScreen<{ keyframes: CSSAnimationKeyframes }>
CardComponent={VerticalExampleCard}
buildAnimation={({ keyframes }) => ({
animationDirection: 'alternate',
animationDuration: '14s',
animationIterationCount: 'infinite',
animationName: keyframes,
animationTimingFunction: 'linear',
})}
renderExample={({ animation }) => (
<View>
<View style={styles.box} />
<Animated.Image
source={balloonsImage}
style={[styles.image, animation]}
/>
</View>
)}
sections={[
{
examples: [
{
description:
'`mix-blend-mode` is a **continuous** property. That means, it **can be smoothly animated** between values.',
keyframes: {
'0%, 100%': {
mixBlendMode: 'normal',
},
'6.67%': {
mixBlendMode: 'multiply',
},
'13.33%': {
mixBlendMode: 'screen',
},
'20%': {
mixBlendMode: 'overlay',
},
'26.67%': {
mixBlendMode: 'darken',
},
'33.33%': {
mixBlendMode: 'lighten',
},
'40%': {
mixBlendMode: 'color-dodge',
},
'46.67%': {
mixBlendMode: 'color-burn',
},
'53.33%': {
mixBlendMode: 'hard-light',
},
'60%': {
mixBlendMode: 'soft-light',
},
'66.67%': {
mixBlendMode: 'difference',
},
'73.33%': {
mixBlendMode: 'exclusion',
},
'80%': {
mixBlendMode: 'hue',
},
'86.67%': {
mixBlendMode: 'saturation',
},
'93.33%': {
mixBlendMode: 'color',
},
'100%': {
mixBlendMode: 'luminosity',
},
},
minExampleHeight: 1.5 * sizes.xxxl,
title: 'Changing Mix Blend Mode',
},
],
title: 'Mix Blend Mode',
},
]}
/>
);
}

const styles = StyleSheet.create({
box: {
backgroundColor: colors.primary,
borderRadius: radius.md,
height: sizes.xxxl,
position: 'absolute',
transform: [{ translateX: '-15%' }, { translateY: '-15%' }],
width: sizes.xxxl,
},
image: {
borderRadius: radius.md,
height: sizes.xxxl,
width: sizes.xxxl,
},
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import BackfaceVisibility from './BackfaceVisibility';
import MixBlendMode from './MixBlendMode';
import Opacity from './Opacity';

export default {
BackfaceVisibility,
MixBlendMode,
Opacity,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { StyleSheet } from 'react-native';
import type { CSSAnimationKeyframes } from 'react-native-reanimated';
import Animated from 'react-native-reanimated';

import { ExamplesScreen, VerticalExampleCard } from '@/apps/css/components';
import { colors, radius, sizes, spacing } from '@/theme';

export default function OutlineOffset() {
return (
<ExamplesScreen<{ keyframes: CSSAnimationKeyframes }>
CardComponent={VerticalExampleCard}
buildAnimation={({ keyframes }) => ({
animationDirection: 'alternate',
animationDuration: '1s',
animationIterationCount: 'infinite',
animationName: keyframes,
animationTimingFunction: 'linear',
})}
renderExample={({ animation }) => (
<Animated.View style={[styles.box, animation]} />
)}
sections={[
{
examples: [
{
keyframes: {
from: {
outlineOffset: 0,
},
to: {
outlineOffset: spacing.md,
},
},
title: 'Changing Outline Offset',
},
],
title: 'Outline Offset',
},
]}
/>
);
}

const styles = StyleSheet.create({
box: {
backgroundColor: colors.primary,
borderColor: colors.primaryDark,
borderRadius: radius.sm,
height: sizes.xl,
outlineColor: colors.primaryDark,
outlineStyle: 'solid',
outlineWidth: spacing.xxs,
width: sizes.xl,
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { StyleSheet } from 'react-native';
import type { CSSAnimationKeyframes } from 'react-native-reanimated';
import Animated from 'react-native-reanimated';

import { ExamplesScreen, VerticalExampleCard } from '@/apps/css/components';
import { colors, radius, sizes, spacing } from '@/theme';

export default function OutlineStyle() {
return (
<ExamplesScreen<{ keyframes: CSSAnimationKeyframes }>
CardComponent={VerticalExampleCard}
buildAnimation={({ keyframes }) => ({
animationDuration: '3s',
animationIterationCount: 'infinite',
animationName: keyframes,
animationTimingFunction: 'linear',
})}
renderExample={({ animation }) => (
<Animated.View style={[styles.box, animation]} />
)}
sections={[
{
examples: [
{
description:
"`outlineStyle` is a **discrete** property. That means, it **can't be smoothly animated** between values. However, we can still change this property in the animation keyframes but the change will be **abrupt**.",
keyframes: {
'0%, 100%': {
outlineStyle: 'solid',
},
'33.3%': {
outlineStyle: 'dotted',
},
'66.6%': {
outlineStyle: 'dashed',
},
},
title: 'Changing Outline Style',
},
],
title: 'Outline Style',
},
]}
/>
);
}

const styles = StyleSheet.create({
box: {
backgroundColor: colors.primary,
borderColor: colors.primaryDark,
borderRadius: radius.sm,
height: sizes.xl,
outlineColor: colors.primaryDark,
outlineWidth: spacing.xxs,
width: sizes.xl,
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { StyleSheet } from 'react-native';
import type { CSSAnimationKeyframes } from 'react-native-reanimated';
import Animated from 'react-native-reanimated';

import { ExamplesScreen, VerticalExampleCard } from '@/apps/css/components';
import { colors, radius, sizes, spacing } from '@/theme';

export default function OutlineWidth() {
return (
<ExamplesScreen<{ keyframes: CSSAnimationKeyframes }>
CardComponent={VerticalExampleCard}
buildAnimation={({ keyframes }) => ({
animationDirection: 'alternate',
animationDuration: '1s',
animationIterationCount: 'infinite',
animationName: keyframes,
animationTimingFunction: 'linear',
})}
renderExample={({ animation }) => (
<Animated.View style={[styles.box, animation]} />
)}
sections={[
{
examples: [
{
keyframes: {
from: {
outlineWidth: 0,
},
to: {
outlineWidth: spacing.md,
},
},
title: 'Changing Outline Width',
},
],
title: 'Outline Width',
},
]}
/>
);
}

const styles = StyleSheet.create({
box: {
backgroundColor: colors.primary,
borderColor: colors.primaryDark,
borderRadius: radius.sm,
height: sizes.xl,
outlineColor: colors.primaryDark,
outlineStyle: 'solid',
outlineWidth: spacing.xxs,
width: sizes.xl,
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import OutlineOffset from './OutlineOffset';
import OutlineStyle from './OutlineStyle';
import OutlineWidth from './OutlineWidth';

export default { OutlineOffset, OutlineStyle, OutlineWidth };
Loading

0 comments on commit 0e0cf96

Please sign in to comment.