Skip to content

Feat/new pan view with reanimated 2 #1404

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Aug 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b222458
New PanView - somewhat working
M-i-k-e-l Jul 1, 2021
12ea702
Small refactor
M-i-k-e-l Jul 1, 2021
0978cd6
Add worklet
M-i-k-e-l Jul 1, 2021
193fc80
Merge branch 'master' into feat/new-pan-view-with-reanimated-2
M-i-k-e-l Jul 13, 2021
faa0207
Fix typings
M-i-k-e-l Jul 13, 2021
700cb59
Do not add GestureHandlerRootView by default
M-i-k-e-l Jul 13, 2021
a24f4cf
Move to Incubator
M-i-k-e-l Jul 13, 2021
35d4d54
Move to Incubator (2)
M-i-k-e-l Jul 14, 2021
b7a7dbf
Merge branch 'master' into feat/new-pan-view-with-reanimated-2
M-i-k-e-l Aug 3, 2021
03701d8
Add chevronDown to assets and use it from there
M-i-k-e-l Aug 3, 2021
7253810
Rename to PanView...
M-i-k-e-l Aug 3, 2021
fa96364
Improve docs
M-i-k-e-l Aug 3, 2021
db21282
Add TODO
M-i-k-e-l Aug 3, 2021
d1fdd06
Increase damping
M-i-k-e-l Aug 3, 2021
2f3ea15
Reorder imports
M-i-k-e-l Aug 3, 2021
dfcfc46
Use Object.assign
M-i-k-e-l Aug 4, 2021
8c4f61e
Move GestureHandlerRootView to the screen
M-i-k-e-l Aug 4, 2021
626044a
Fix tests (import)
M-i-k-e-l Aug 4, 2021
b902c33
Remove translationLock
M-i-k-e-l Aug 5, 2021
d385d81
Use typeof instead of static types
M-i-k-e-l Aug 5, 2021
9914d42
Remove unused and unecessary styles
M-i-k-e-l Aug 5, 2021
a107126
Move default value of directions
M-i-k-e-l Aug 5, 2021
3e49d9e
Add springBack
M-i-k-e-l Aug 5, 2021
82c2c62
Allow returning to the original location
M-i-k-e-l Aug 5, 2021
2af6234
Rename const
M-i-k-e-l Aug 5, 2021
13e7a43
Merge branch 'master' into feat/new-pan-view-with-reanimated-2
M-i-k-e-l Aug 9, 2021
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
1 change: 1 addition & 0 deletions demo/src/configurations.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Assets, Colors, Typography, Spacings, Incubator} from 'react-native-ui-lib'; // eslint-disable-line

Assets.loadAssetsGroup('icons.demo', {
chevronDown: require('./assets/icons/chevronDown.png'),
add: require('./assets/icons/add.png'),
camera: require('./assets/icons/cameraSelected.png'),
close: require('./assets/icons/close.png'),
Expand Down
3 changes: 3 additions & 0 deletions demo/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ module.exports = {
get IncubatorTextFieldScreen() {
return require('./screens/incubatorScreens/IncubatorTextFieldScreen').default;
},
get PanViewScreen() {
return require('./screens/incubatorScreens/PanViewScreen').default;
},
// realExamples
get AppleMusic() {
return require('./screens/realExamples/AppleMusic').default;
Expand Down
3 changes: 2 additions & 1 deletion demo/src/screens/MenuStructure.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ export const navigationData = {
screens: [
{title: 'Native TouchableOpacity', tags: 'touchable native', screen: 'unicorn.incubator.TouchableOpacityScreen'},
{title: '(New) TextField', tags: 'text field input', screen: 'unicorn.components.IncubatorTextFieldScreen'},
{title: 'WheelPicker (Incubator)', tags: 'wheel picker spinner experimental', screen: 'unicorn.incubator.WheelPickerScreen'}
{title: 'WheelPicker (Incubator)', tags: 'wheel picker spinner experimental', screen: 'unicorn.incubator.WheelPickerScreen'},
{title: 'Pan View', tags: 'pan swipe drag', screen: 'unicorn.incubator.PanViewScreen'}
]
},
Inspirations: {
Expand Down
205 changes: 205 additions & 0 deletions demo/src/screens/incubatorScreens/PanViewScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import React, {Component} from 'react';
import {StyleSheet, ScrollView} from 'react-native';
import {GestureHandlerRootView, FlatList} from 'react-native-gesture-handler';
import {
Assets,
View,
Text,
Colors,
Incubator,
Card,
Constants,
Modal,
BorderRadiuses,
Image,
TouchableOpacity
} from 'react-native-ui-lib';
const {PanView} = Incubator;

interface Item {
value: string;
label: string;
}

const overlayBackgroundColor = Colors.rgba(Colors.black, 0.2);
const colors: Item[] = [
{value: Colors.red10, label: 'Red10'},
{value: Colors.red30, label: 'Red30'},
{value: Colors.red50, label: 'Red50'},
{value: Colors.red70, label: 'Red70'},
{value: Colors.blue10, label: 'Blue10'},
{value: Colors.blue30, label: 'Blue30'},
{value: Colors.blue50, label: 'Blue50'},
{value: Colors.blue70, label: 'Blue70'},
{value: Colors.purple10, label: 'Purple10'},
{value: Colors.purple30, label: 'Purple30'},
{value: Colors.purple50, label: 'Purple50'},
{value: Colors.purple70, label: 'Purple70'},
{value: Colors.green10, label: 'Green10'},
{value: Colors.green30, label: 'Green30'},
{value: Colors.green50, label: 'Green50'},
{value: Colors.green70, label: 'Green70'},
{value: Colors.yellow10, label: 'Yellow10'},
{value: Colors.yellow30, label: 'Yellow30'},
{value: Colors.yellow50, label: 'Yellow50'},
{value: Colors.yellow70, label: 'Yellow70'}
];

class PanViewScreen extends Component {
state = {
showToast: false,
showDialog: false
};

onDialogDismissed = () => {
this.setState({showDialog: false});
};

keyExtractor = (item: Item) => {
return item.value;
};

renderVerticalItem = ({item}: {item: Item}) => {
return (
<Text text50 margin-20 color={item.value}>
{item.label}
</Text>
);
};

renderDialog = () => {
const Container = Constants.isAndroid ? GestureHandlerRootView : React.Fragment;
const containerProps = Constants.isAndroid ? {style: styles.gestureHandler} : {};
return (
<View flex>
<Modal
transparent
onBackgroundPress={this.onDialogDismissed}
overlayBackgroundColor={overlayBackgroundColor}
visible
>
<Container {...containerProps}>
<PanView
directions={[PanView.directions.DOWN]}
dismissible
springBack
// threshold={{y: 10}}
containerStyle={styles.panView}
onDismiss={this.onDialogDismissed}
>
<View style={styles.dialog}>
<Text text60 margin-s2>
Title (swipe here)
</Text>
<View height={1} bg-grey40/>
<FlatList
showsVerticalScrollIndicator={false}
style={styles.verticalScroll}
data={colors}
renderItem={this.renderVerticalItem}
keyExtractor={this.keyExtractor}
/>
</View>
</PanView>
</Container>
</Modal>
</View>
);
};

onToastDismissed = () => {
this.setState({showToast: false});
};

renderToast = () => {
return (
<PanView
directions={[PanView.directions.LEFT, PanView.directions.DOWN, PanView.directions.RIGHT]}
dismissible
springBack
directionLock
threshold={{y: 10}}
containerStyle={styles.panView}
onDismiss={this.onToastDismissed}
>
<TouchableOpacity center style={styles.toast} onPress={this.onToastDismissed}>
<Text>Swipe or click to dismiss</Text>
</TouchableOpacity>
</PanView>
);
};

renderCard = (key: string, name: string) => {
// @ts-expect-error
const value = this.state[key];
const text = value ? `I'm still showing or being dismissed` : `Click me (${name})`;
const onPress = value ? undefined : () => this.setState({[key]: true});
return (
<Card margin-page onPress={onPress}>
<View padding-15>
<Text text30 grey30>
{text}
</Text>
</View>
</Card>
);
};

render() {
const {showToast, showDialog} = this.state;
const Container = showDialog ? View : GestureHandlerRootView;
return (
<Container style={[styles.root, styles.gestureHandler]}>
<View marginL-page height={50} centerV>
<Text text50>New Pan View</Text>
</View>
<ScrollView>
{this.renderCard('showToast', 'toast')}
{this.renderCard('showDialog', 'dialog')}
<View height={Constants.screenHeight} centerH>
<Text text50 marginB-s2>
Scrollable
</Text>
<Image source={Assets.icons.demo.chevronDown}/>
</View>
</ScrollView>
{showToast && this.renderToast()}
{showDialog && this.renderDialog()}
</Container>
);
}
}

export default PanViewScreen;

const styles = StyleSheet.create({
root: {
backgroundColor: Colors.grey80
},
gestureHandler: {
flex: 1
},
panView: {
flex: 1,
position: 'absolute',
bottom: 20,
alignSelf: 'center'
},
toast: {
backgroundColor: Colors.white,
width: 200,
height: 40,
borderRadius: BorderRadiuses.br20,
borderWidth: 0.5,
borderColor: Colors.grey30
},
dialog: {
backgroundColor: Colors.white,
width: 200,
height: 300,
borderRadius: BorderRadiuses.br20
},
verticalScroll: {
marginTop: 20
}
});
1 change: 1 addition & 0 deletions demo/src/screens/incubatorScreens/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export function registerScreens(registrar) {
gestureHandlerRootHOC(require('./TouchableOpacityScreen').default));
registrar('unicorn.components.IncubatorTextFieldScreen', () => require('./IncubatorTextFieldScreen').default);
registrar('unicorn.incubator.WheelPickerScreen', () => gestureHandlerRootHOC(require('./WheelPickerScreen').default));
registrar('unicorn.incubator.PanViewScreen', () => require('./PanViewScreen').default);
}
1 change: 1 addition & 0 deletions generatedTypes/incubator/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export { default as TextField, TextFieldProps, FieldContextType } from './TextFi
export { default as TouchableOpacity, TouchableOpacityProps } from './TouchableOpacity';
export { default as TouchableOpacity2 } from './TouchableOpacity2';
export { default as WheelPicker, WheelPickerProps } from './WheelPicker';
export { default as PanView, PanViewProps, PanViewDirections, PanViewDismissThreshold } from './panView';
50 changes: 50 additions & 0 deletions generatedTypes/incubator/panView/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import { StyleProp, ViewStyle } from 'react-native';
import { ViewProps } from '../../components/view';
import { PanViewDirections, PanViewDismissThreshold } from './panningUtil';
export { PanViewDirections, PanViewDismissThreshold };
export interface PanViewProps extends ViewProps {
/**
* The directions of the allowed pan (default is all)
* Types: UP, DOWN, LEFT and RIGHT (using PanView.directions.###)
*/
directions?: PanViewDirections[];
/**
* Dismiss the view if over the threshold (translation or velocity).
*/
dismissible?: boolean;
/**
* Animate to start if not dismissed.
*/
springBack?: boolean;
/**
* Callback to the dismiss animation end
*/
onDismiss?: () => void;
/**
* Should the direction of dragging be locked once a drag has started.
*/
directionLock?: boolean;
/**
* Object to adjust the dismiss threshold limits (eg {x, y, velocity}).
*/
threshold?: PanViewDismissThreshold;
/**
* Add a style to the container
*/
containerStyle?: StyleProp<ViewStyle>;
}
interface Props extends PanViewProps {
children?: React.ReactNode | React.ReactNode[];
}
declare const _default: React.ComponentClass<PanViewProps & {
useCustomTheme?: boolean | undefined;
}, any> & {
(props: Props): JSX.Element;
displayName: string;
directions: typeof PanViewDirections;
defaultProps: {
threshold: Required<PanViewDismissThreshold>;
};
};
export default _default;
36 changes: 36 additions & 0 deletions generatedTypes/incubator/panView/panningUtil.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { PanGestureHandlerEventPayload } from 'react-native-gesture-handler';
export declare enum PanViewDirections {
UP = "up",
DOWN = "down",
LEFT = "left",
RIGHT = "right"
}
export interface Frame {
x: number;
y: number;
}
export interface TranslationOptions {
directionLock?: boolean;
currentTranslation: Frame;
}
export interface PanViewDismissThreshold {
/**
* The (positive) velocity of a drag\swipe past it the view will be dismissed.
*/
velocity?: number;
/**
* The x translation from the start location past it the view will be dismissed.
*/
x?: number;
/**
* The y translation from the start location past it the view will be dismissed.
*/
y?: number;
}
export declare function getTranslationDirectionClamp(translation: Frame, options: TranslationOptions): Frame;
export declare function getTranslation(event: PanGestureHandlerEventPayload, initialTranslation: Frame, directions: PanViewDirections[], options: TranslationOptions): Frame;
export declare const DEFAULT_THRESHOLD: Required<PanViewDismissThreshold>;
/**
* Will return undefined if should not dismiss
*/
export declare function getDismissVelocity(event: PanGestureHandlerEventPayload, directions: PanViewDirections[], options: TranslationOptions, threshold?: PanViewDismissThreshold): Partial<Frame> | undefined;
1 change: 1 addition & 0 deletions jest-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ jest.spyOn(AccessibilityInfo, 'isScreenReaderEnabled').mockImplementation(() =>
jest.mock('@react-native-community/blur', () => {});
jest.mock('@react-native-community/netinfo', () => {});
jest.mock('react-native-reanimated', () => require('react-native-reanimated/mock'));
global.__reanimatedWorkletInit = jest.fn();
jest.mock('react-native-gesture-handler', () => {});
jest.mock('@react-native-picker/picker', () => ({Picker: {Item: {}}}));
1 change: 1 addition & 0 deletions src/incubator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export {default as TextField, TextFieldProps, FieldContextType} from './TextFiel
export {default as TouchableOpacity, TouchableOpacityProps} from './TouchableOpacity';
export {default as TouchableOpacity2} from './TouchableOpacity2';
export {default as WheelPicker, WheelPickerProps} from './WheelPicker';
export {default as PanView, PanViewProps, PanViewDirections, PanViewDismissThreshold} from './panView';
Loading