Skip to content

Commit

Permalink
[web] Fixed lazy exports (software-mansion#619)
Browse files Browse the repository at this point in the history
# Why

Default import was removed from react-native-web. necolas/react-native-web#1277
The use of module.exports and import/export breaks tree-shaking in with babel-preset-expo.

Related: software-mansion#617
Fixes: expo/expo#4339

# How

* Moved the shims to `Gestures(.web).js`
* Moved all modules out of main re-export file. (optional)
  • Loading branch information
EvanBacon authored and janicduplessis committed Feb 16, 2020
1 parent 03aa702 commit 347bfcf
Show file tree
Hide file tree
Showing 10 changed files with 713 additions and 662 deletions.
166 changes: 166 additions & 0 deletions GestureButtons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import PropTypes from 'prop-types';
import React from 'react';
import { Animated, Platform, processColor, StyleSheet } from 'react-native';

import createNativeWrapper from './createNativeWrapper';
import GestureHandlerButton from './GestureHandlerButton';
import State from './State';

export const RawButton = createNativeWrapper(GestureHandlerButton, {
shouldCancelWhenOutside: false,
shouldActivateOnStart: false,
});

/* Buttons */

export class BaseButton extends React.Component {
static propTypes = {
...RawButton.propTypes,
onPress: PropTypes.func,
onActiveStateChange: PropTypes.func,
};

constructor(props) {
super(props);
this._lastActive = false;
}

_handleEvent = ({ nativeEvent }) => {
const { state, oldState, pointerInside } = nativeEvent;
const active = pointerInside && state === State.ACTIVE;

if (active !== this._lastActive && this.props.onActiveStateChange) {
this.props.onActiveStateChange(active);
}

if (
oldState === State.ACTIVE &&
state !== State.CANCELLED &&
this._lastActive &&
this.props.onPress
) {
this.props.onPress(active);
}

this._lastActive = active;
};

// Normally, the parent would execute it's handler first,
// then forward the event to listeners. However, here our handler
// is virtually only forwarding events to listeners, so we reverse the order
// to keep the proper order of the callbacks (from "raw" ones to "processed").
_onHandlerStateChange = e => {
this.props.onHandlerStateChange && this.props.onHandlerStateChange(e);
this._handleEvent(e);
};

_onGestureEvent = e => {
this.props.onGestureEvent && this.props.onGestureEvent(e);
this._handleEvent(e);
};

render() {
const { style, rippleColor, ...rest } = this.props;

return (
<RawButton
style={[{ overflow: 'hidden' }, style]}
rippleColor={processColor(rippleColor)}
{...rest}
onGestureEvent={this._onGestureEvent}
onHandlerStateChange={this._onHandlerStateChange}
/>
);
}
}

const AnimatedBaseButton = Animated.createAnimatedComponent(BaseButton);

const btnStyles = StyleSheet.create({
underlay: {
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
top: 0,
},
});

export class RectButton extends React.Component {
static propTypes = BaseButton.propTypes;

static defaultProps = {
activeOpacity: 0.105,
underlayColor: 'black',
};

constructor(props) {
super(props);
this._opacity = new Animated.Value(0);
}

_onActiveStateChange = active => {
if (Platform.OS !== 'android') {
this._opacity.setValue(active ? this.props.activeOpacity : 0);
}

this.props.onActiveStateChange && this.props.onActiveStateChange(active);
};

render() {
const { children, ...rest } = this.props;

return (
<BaseButton {...rest} onActiveStateChange={this._onActiveStateChange}>
<Animated.View
style={[
btnStyles.underlay,
{ opacity: this._opacity },
{ backgroundColor: this.props.underlayColor },
]}
/>
{children}
</BaseButton>
);
}
}

export class BorderlessButton extends React.Component {
static propTypes = {
...BaseButton.propTypes,
borderless: PropTypes.bool,
};

static defaultProps = {
activeOpacity: 0.3,
borderless: true,
};

constructor(props) {
super(props);
this._opacity = new Animated.Value(1);
}

_onActiveStateChange = active => {
if (Platform.OS !== 'android') {
this._opacity.setValue(active ? this.props.activeOpacity : 1);
}

this.props.onActiveStateChange && this.props.onActiveStateChange(active);
};

render() {
const { children, style, ...rest } = this.props;

return (
<AnimatedBaseButton
{...rest}
onActiveStateChange={this._onActiveStateChange}
style={[style, Platform.OS === 'ios' && { opacity: this._opacity }]}>
{children}
</AnimatedBaseButton>
);
}
}

export { default as PureNativeButton } from './GestureHandlerButton';
59 changes: 59 additions & 0 deletions GestureComponents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';
import ReactNative from 'react-native';

import createNativeWrapper from './createNativeWrapper';

const MEMOIZED = {};

function memoizeWrap(Component, config) {
const memoized = MEMOIZED[Component.displayName];
if (memoized) {
return memoized;
}
return (MEMOIZED[Component.displayName] = createNativeWrapper(
Component,
config
));
}

module.exports = {
/* RN's components */
get ScrollView() {
return memoizeWrap(ReactNative.ScrollView, {
disallowInterruption: true,
});
},
get Switch() {
return memoizeWrap(ReactNative.Switch, {
shouldCancelWhenOutside: false,
shouldActivateOnStart: true,
disallowInterruption: true,
});
},
get TextInput() {
return memoizeWrap(ReactNative.TextInput);
},
get ToolbarAndroid() {
return memoizeWrap(ReactNative.ToolbarAndroid);
},
get DrawerLayoutAndroid() {
const DrawerLayoutAndroid = memoizeWrap(ReactNative.DrawerLayoutAndroid, {
disallowInterruption: true,
});
DrawerLayoutAndroid.positions = ReactNative.DrawerLayoutAndroid.positions;
return DrawerLayoutAndroid;
},
get FlatList() {
if (!MEMOIZED.FlatList) {
const ScrollView = this.ScrollView;
MEMOIZED.FlatList = React.forwardRef((props, ref) => (
<ReactNative.FlatList
ref={ref}
{...props}
renderScrollComponent={scrollProps => <ScrollView {...scrollProps} />}
/>
));
}
return MEMOIZED.FlatList;
},
};
35 changes: 35 additions & 0 deletions GestureComponents.web.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import {
DrawerLayoutAndroid as RNDrawerLayoutAndroid,
FlatList as RNFlatList,
Switch as RNSwitch,
TextInput as RNTextInput,
ToolbarAndroid as RNToolbarAndroid,
ScrollView as RNScrollView,
} from 'react-native';

import createNativeWrapper from './createNativeWrapper';

export const ScrollView = createNativeWrapper(RNScrollView, {
disallowInterruption: true,
});

export const Switch = createNativeWrapper(RNSwitch, {
shouldCancelWhenOutside: false,
shouldActivateOnStart: true,
disallowInterruption: true,
});
export const TextInput = createNativeWrapper(RNTextInput);
export const ToolbarAndroid = createNativeWrapper(RNToolbarAndroid);
export const DrawerLayoutAndroid = createNativeWrapper(RNDrawerLayoutAndroid, {
disallowInterruption: true,
});
DrawerLayoutAndroid.positions = RNDrawerLayoutAndroid.positions;

export const FlatList = React.forwardRef((props, ref) => (
<RNFlatList
ref={ref}
{...props}
renderScrollComponent={scrollProps => <ScrollView {...scrollProps} />}
/>
));
Loading

0 comments on commit 347bfcf

Please sign in to comment.