Skip to content

Commit

Permalink
Allow custom style props
Browse files Browse the repository at this point in the history
  • Loading branch information
sonaye committed Aug 8, 2018
1 parent c35aa59 commit 9af045d
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 57 deletions.
31 changes: 29 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
# 0.0.27

- Allow dropping unused style props to enhance performance through `skipStyleProps`.
- Allow adding any type of style props manually through `styleProps`.
- Allow removing all default style props on mount and utilize whatever in `styleProps` only through `clearStyleProps` prop.

```js
const defaultStyleProps = [
// nativeDriver
{ prop: 'opacity', default: 1, native: true },
{ prop: 'rotate', default: '0deg', native: true, transform: true },
{ prop: 'scale', default: 1, native: true, transform: true },
{ prop: 'translateX', default: 0, native: true, transform: true },
{ prop: 'translateY', default: 0, native: true, transform: true },

// driver (non-native)
{ prop: 'backgroundColor', default: 'transparent' },
{ prop: 'height', default: null },
{ prop: 'width', default: null },

...styleProps // add yours, or overwrite defaults
];

// if any of these props exist in `skipStyleProps` they will not be used
// and no interpolation values would be created, slightly boosting perf.
```

# 0.0.26

- Support filtering props from being included in styles, when using additional props as style overrides, through `skipProps` prop.
- Support filtering passed props from being included in styles, when using additional props as style overrides, through `skipProps` prop.

# 0.0.25

Expand All @@ -14,7 +41,7 @@

# 0.0.21

- **Breaking**: Project has been renamed to `haraka`. You can continue to use [`react-native-behavior`](https://www.npmjs.com/package/react-native-behavior) if you are already using it in a project (has been stable for over a year), it will not reacive any future updates however and has been deprecated.
- **Breaking**: Project has been renamed to `haraka`. You can continue to use [`react-native-behavior`](https://www.npmjs.com/package/react-native-behavior) if you are already using it in a project (has been stable for over a year), it will not receive any future updates however and has been deprecated.
- **Breaking**: `animatedNativeValue` prop is now `nativeDriver`.
- **Breaking**: `animatedValue` prop is now `driver`.
- **Breaking**: `states` prop is now just `state` (without the s).
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,16 @@ type State = {
width?: number // no percentages, default = null
};

type StyleProp = {
prop: string,
default: string | number | null,
native?: bool,
transform: bool
};

type Behavior = {
config?: DefaultConfig,
clearStyleProps?: bool, // removes all default style props on mount and utilizes whatever in `styleProps` only
state?: State[], // default value is [{}, {}], [{}] can be used for a static behavior
nativeDriver?: AnimatedValue, // default = new Animated.Value(0), you can use a custom native driver
driver?: AnimatedValue, // default = new Animated.Value(0), you can use a custom driver
Expand All @@ -76,8 +84,10 @@ type Behavior = {
clamp?: bool, // default = false, prevent animations from exceeding their ranges
keys?: number[], // can be used with custom drivers to define custom state keys/indices
initialState?: number, // default = 0
skipProps?: string[], // default = []
skipProps?: string[], // default = [], allows filtering passed props from being included in styles
skipStyleProps?: string[], // default = [], allows dropping unused style props
style?: object, // style of the behavior view, default = {}, AnimatedViewStyle (see React Native docs)
styleProps?: StyleProp[], // default = [], allows adding any type of style props manually
unmounted?: bool, // default = false, start behavior in the unmounted state
// animation presets (they populate `state` prop which will be ignored):
faded?: bool, // default = false, see below for available presets
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"license": "MIT",
"name": "haraka",
"description": "Stateful animations in React Native.",
"version": "0.0.26",
"version": "0.0.27",
"main": "lib/index.js",
"repository": {
"type": "git",
Expand All @@ -13,8 +13,8 @@
"react-native": "*"
},
"devDependencies": {
"@types/react": "16.4.7",
"@types/react-native": "0.56.4",
"@types/react": "16.4.8",
"@types/react-native": "0.56.6",
"babel-core": "6.26.3",
"babel-eslint": "8.2.6",
"babel-plugin-external-helpers": "6.22.0",
Expand All @@ -26,7 +26,7 @@
"eslint-plugin-import": "2.13.0",
"eslint-plugin-jsx-a11y": "6.1.1",
"eslint-plugin-react": "7.10.0",
"rollup": "0.63.5",
"rollup": "0.64.1",
"rollup-plugin-babel": "3.0.7"
},
"scripts": {
Expand Down
119 changes: 69 additions & 50 deletions src/behavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ import { Animated } from 'react-native';
export default class Behavior extends React.PureComponent {
static defaultProps = {
clamp: false,
clearStyleProps: false,
config: { type: 'spring' },
initialState: 0,
skipProps: [],
skipStyleProps: [],
state: [{}, {}],
style: {},
styleProps: [],
unmounted: false
};

Expand Down Expand Up @@ -85,18 +88,6 @@ export default class Behavior extends React.PureComponent {
});
};

presets = {
faded: [{ opacity: 0 }, { opacity: 1 }]
};

layoutPresets = {
absolute: { bottom: 0, left: 0, position: 'absolute', right: 0, top: 0 },
centered: { alignSelf: 'center' },
fixed: { position: 'absolute' },
full: { flex: 1 },
landing: { alignItems: 'center', flex: 1, justifyContent: 'center' }
};

render() {
const { mounted } = this.state;

Expand All @@ -107,6 +98,7 @@ export default class Behavior extends React.PureComponent {
centered,
children,
clamp,
clearStyleProps,
config,
driver,
faded,
Expand All @@ -118,15 +110,43 @@ export default class Behavior extends React.PureComponent {
nativeDriver,
pointerEvents,
skipProps,
skipStyleProps,
state: _state,
style,
styleProps,
unmounted,
...rest
} = this.props;

let { state } = this.props;

if (faded) state = this.presets.faded;
const presets = {
faded: [{ opacity: 0 }, { opacity: 1 }]
};

if (faded) state = presets.faded;

const layoutPresets = {
absolute: { bottom: 0, left: 0, position: 'absolute', right: 0, top: 0 },
centered: { alignSelf: 'center' },
fixed: { position: 'absolute' },
full: { flex: 1 },
landing: { alignItems: 'center', flex: 1, justifyContent: 'center' }
};

const viewStyles = {
...layoutPresets[absolute && 'absolute'],
...layoutPresets[centered && 'centered'],
...layoutPresets[fixed && 'fixed'],
...layoutPresets[full && 'full'],
...layoutPresets[landing && 'landing']
};

const propStyles = Object.keys(rest).reduce((obj, key) => {
if (skipProps.includes(key)) return obj;

return { ...obj, [key]: rest[key] };
}, {});

const inputRange =
keys ||
Expand Down Expand Up @@ -156,50 +176,49 @@ export default class Behavior extends React.PureComponent {
return range;
}, []);

const addNativeProp = (prop, defaultValue) =>
this.nativeDriver.interpolate({
inputRange,
outputRange: getRange(prop, defaultValue),
extrapolate: clamp ? 'clamp' : undefined
});
const addProp = (prop, defaultValue, native) => {
const propDriver = native ? this.nativeDriver : this.driver;

const addProp = (prop, defaultValue) =>
this.driver.interpolate({
return propDriver.interpolate({
inputRange,
outputRange: getRange(prop, defaultValue),
extrapolate: clamp ? 'clamp' : undefined
});

const opacity = addNativeProp('opacity', 1);
const rotate = addNativeProp('rotate', '0deg');
const scale = addNativeProp('scale', 1);
const translateX = addNativeProp('translateX', 0);
const translateY = addNativeProp('translateY', 0);

const backgroundColor = addProp('backgroundColor', 'transparent');
const height = addProp('height', null);
const width = addProp('width', null);

const viewStyles = {
...this.layoutPresets[absolute && 'absolute'],
...this.layoutPresets[centered && 'centered'],
...this.layoutPresets[fixed && 'fixed'],
...this.layoutPresets[full && 'full'],
...this.layoutPresets[landing && 'landing']
};

const propStyles = Object.keys(rest).reduce((obj, key) => {
if (skipProps.includes(key)) return obj;

return { ...obj, [key]: rest[key] };
}, {});

const nativeStyles = {
opacity,
transform: [{ rotate }, { scale }, { translateX }, { translateY }]
};

const styles = { backgroundColor, height, width };
const defaultStyleProps = !clearStyleProps
? [
{ prop: 'opacity', default: 1, native: true },
{ prop: 'rotate', default: '0deg', native: true, transform: true },
{ prop: 'scale', default: 1, native: true, transform: true },
{ prop: 'translateX', default: 0, native: true, transform: true },
{ prop: 'translateY', default: 0, native: true, transform: true },

{ prop: 'backgroundColor', default: 'transparent' },
{ prop: 'height', default: null },
{ prop: 'width', default: null }
]
: [];

const nativeStyles = {};
const styles = {};

[...defaultStyleProps, ...styleProps].forEach(
({ prop, default: defaultValue, native, transform }) => {
if (!skipStyleProps.includes(prop)) {
const stylesRef = native ? nativeStyles : styles;

if (transform) {
stylesRef.transform = [
...(stylesRef.transform || []),
{ [prop]: addProp(prop, defaultValue, native) }
];
} else {
stylesRef[prop] = addProp(prop, defaultValue, native);
}
}
}
);

return (
<Animated.View
Expand Down

0 comments on commit 9af045d

Please sign in to comment.