Skip to content
This repository was archived by the owner on Oct 8, 2021. It is now read-only.
Open
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
2 changes: 2 additions & 0 deletions example/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {StyleSheet, ScrollView, SafeAreaView} from 'react-native';
import Heart from './components/Heart';
import CustomShape from './components/CustomShape';
import CustomText from './components/CustomText';
import AnimatedCircles from './components/AnimatedCircles';

export default function App() {
return (
Expand All @@ -12,6 +13,7 @@ export default function App() {
<CustomText />
<Heart />
<CustomShape />
<AnimatedCircles />
</ScrollView>
</SafeAreaView>
);
Expand Down
75 changes: 75 additions & 0 deletions example/components/AnimatedCircles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// @flow
import React from 'react';
import {Animated, Easing, StyleSheet, Dimensions} from 'react-native';
import {Surface, Shape, Group} from '@react-native-community/art';

/*
An example of Animated Shapes

Animated uses 'setNativeProps' on the AnimatedShape, preventing rerendering
for each step in the animation
*/

const CIRCLE = 'M 25, 50 a 25,25 0 1,1 50,0 a 25,25 0 1,1 -50,0';

export default function AnimatedCircles() {
const surfaceWidth = Dimensions.get('window').width;

const AnimatedShape = Animated.createAnimatedComponent(Shape);

const [animatedOpacity] = React.useState(new Animated.Value(1));

const blink = React.useCallback(
toValue =>
Animated.timing(animatedOpacity, {
duration: 900,
easing: Easing.linear,
toValue,
}).start(() => blink(toValue === 0 ? 1 : 0)),
[animatedOpacity],
);

React.useEffect(() => {
blink(0);
}, [blink]);

return (
<Surface width={surfaceWidth} height={100} style={styles.surface}>
<Group x={25} y={0}>
<AnimatedShape
d={CIRCLE}
fill={'#61DAFB'}
opacity={animatedOpacity.interpolate({
inputRange: [0, 1, 2],
outputRange: [1, 0, 0],
})}
/>
</Group>
<Group x={surfaceWidth / 2 - 50} y={0}>
<AnimatedShape
d={CIRCLE}
fill={'#61DAFB'}
opacity={animatedOpacity.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
})}
/>
</Group>
<Group x={surfaceWidth - 125} y={0}>
<AnimatedShape
d={CIRCLE}
fill={'#61DAFB'}
opacity={animatedOpacity.interpolate({
inputRange: [0, 1],
outputRange: [1, 0],
})}
/>
</Group>
</Surface>
);
}
const styles = StyleSheet.create({
surface: {
backgroundColor: '#000',
},
});
33 changes: 23 additions & 10 deletions lib/Group.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,46 @@ import * as React from 'react';
import PropTypes from 'prop-types';
import invariant from 'invariant';
import {NativeGroup} from './nativeComponents';
import {extractOpacity, extractTransform, extractShadow} from './helpers';
import {translatePropsToNativeProps} from './helpers';
import type {OpacityProps, TransformProps, ShadowProps} from './types';

type GroupProps = OpacityProps &
export type GroupProps = OpacityProps &
ShadowProps &
TransformProps & {
children: React.Node,
};

const nativePropList = ['opacity', 'transform'];

export default class Group extends React.Component<GroupProps> {
static contextTypes = {
isInSurface: PropTypes.bool.isRequired,
};

_rootComponent = null;

setNativeProps(newProps: $Shape<GroupProps>) {
if (this._rootComponent && newProps) {
// newProps will only include what is changed, but we need existing props for some translations:
const nativeProps = translatePropsToNativeProps(
({
...this.props,
...newProps,
}: GroupProps),
nativePropList,
);
// $FlowFixMe
this._rootComponent.setNativeProps(nativeProps);
}
}

render() {
invariant(
this.context.isInSurface,
'ART: <Group /> must be a child of a <Surface />',
);
const nativeProps = translatePropsToNativeProps(this.props, nativePropList);

return (
<NativeGroup
opacity={extractOpacity(this.props)}
transform={extractTransform(this.props)}
shadow={extractShadow(this.props)}>
{this.props.children}
</NativeGroup>
);
return <NativeGroup {...nativeProps}>{this.props.children}</NativeGroup>;
}
}
56 changes: 33 additions & 23 deletions lib/Shape.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,7 @@
import * as React from 'react';
import {NativeShape} from './nativeComponents';
import Path from './ARTSerializablePath';
import {
extractTransform,
extractShadow,
extractOpacity,
childrenAsString,
extractColor,
extractStrokeJoin,
extractStrokeCap,
extractBrush,
} from './helpers';
import {translatePropsToNativeProps} from './helpers';
import type {
TransformProps,
ShadowProps,
Expand All @@ -45,30 +36,49 @@ export type ShapeProps = TransformProps &
height: number,
};

const nativePropList = [
'd',
'fill',
'opacity',
'stroke',
'strokeCap',
'strokeDash',
'strokeJoin',
'strokeWidth',
'transform',
];

export default class Shape extends React.Component<ShapeProps> {
static defaultProps = {
strokeWidth: 1,
width: 0,
height: 0,
};

_rootComponent = null;

setNativeProps(newProps: $Shape<ShapeProps>) {
if (this._rootComponent && newProps) {
// newProps will only include what is changed, but we need existing props for some translations:
const nativeProps = translatePropsToNativeProps(
({
...this.props,
...newProps,
}: ShapeProps),
nativePropList,
);
// $FlowFixMe
this._rootComponent.setNativeProps(nativeProps);
}
}

render() {
const props = this.props;
const path = props.d || childrenAsString(props.children);
const d = (path instanceof Path ? path : new Path(path)).toJSON();
const nativeProps = translatePropsToNativeProps(this.props, nativePropList);

return (
<NativeShape
fill={extractBrush(props.fill, props)}
opacity={extractOpacity(props)}
stroke={extractColor(props.stroke)}
strokeCap={extractStrokeCap(props.strokeCap)}
strokeDash={props.strokeDash || null}
strokeJoin={extractStrokeJoin(props.strokeJoin)}
strokeWidth={props.strokeWidth}
transform={extractTransform(props)}
shadow={extractShadow(this.props)}
d={d}
ref={component => (this._rootComponent = component)}
{...nativeProps}
/>
);
}
Expand Down
69 changes: 36 additions & 33 deletions lib/Text.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,7 @@
import * as React from 'react';
import Path from './ARTSerializablePath';
import {NativeText} from './nativeComponents';
import {
extractBrush,
extractOpacity,
extractColor,
extractStrokeCap,
extractStrokeJoin,
extractTransform,
extractShadow,
extractAlignment,
childrenAsString,
extractFontAndLines,
} from './helpers';
import {translatePropsToNativeProps} from './helpers';
import type {
TransformProps,
ShadowProps,
Expand Down Expand Up @@ -50,37 +39,51 @@ export type TextProps = TransformProps &
path?: string | Path,
};

const nativePropList = [
'alignment',
'frame',
'fill',
'opacity',
'path',
'stroke',
'strokeCap',
'strokeDash',
'strokeJoin',
'strokeWidth',
'transform',
];

export default class Text extends React.Component<TextProps> {
static defaultProps = {
strokeWidth: 1,
width: 0,
height: 0,
};

_rootComponent = null;

setNativeProps(newProps: $Shape<TextProps>) {
if (this._rootComponent && newProps) {
// newProps will only include what is changed, but we need existing props for some translations:
const nativeProps = translatePropsToNativeProps(
({
...this.props,
...newProps,
}: TextProps),
nativePropList,
);
// $FlowFixMe
this._rootComponent.setNativeProps(nativeProps);
}
}

render() {
const props = this.props;
const path = props.path;
const textPath = path
? (path instanceof Path ? path : new Path(path)).toJSON()
: null;
const textFrame = extractFontAndLines(
props.font,
childrenAsString(props.children),
);
const nativeProps = translatePropsToNativeProps(this.props, nativePropList);

return (
<NativeText
fill={extractBrush(props.fill, props)}
opacity={extractOpacity(props)}
stroke={extractColor(props.stroke)}
strokeCap={extractStrokeCap(props.strokeCap)}
strokeDash={props.strokeDash || null}
strokeJoin={extractStrokeJoin(props.strokeJoin)}
strokeWidth={props.strokeWidth}
transform={extractTransform(props)}
alignment={extractAlignment(props.alignment)}
shadow={extractShadow(this.props)}
frame={textFrame}
path={textPath}
ref={component => (this._rootComponent = component)}
{...nativeProps}
/>
);
}
Expand Down
Loading