Update animated components to use TypeScript

This commit is contained in:
Arnaud Vergnet 2020-09-22 17:43:40 +02:00
parent f43dc55735
commit 140bcf3675
3 changed files with 84 additions and 70 deletions

View file

@ -17,42 +17,37 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import {View} from 'react-native';
import {View, ViewStyle} from 'react-native';
import {List, withTheme} from 'react-native-paper';
import Collapsible from 'react-native-collapsible';
import * as Animatable from 'react-native-animatable';
import type {CustomThemeType} from '../../managers/ThemeManager';
import type {ListIconPropsType} from '../../constants/PaperStyles';
type PropsType = {
theme: CustomThemeType,
title: string,
subtitle?: string,
left?: () => React.Node,
opened?: boolean,
unmountWhenCollapsed?: boolean,
children?: React.Node,
theme: ReactNativePaper.Theme;
title: string;
subtitle?: string;
style: ViewStyle;
left?: (props: {
color: string;
style?: {
marginRight: number;
marginVertical?: number;
};
}) => React.ReactNode;
opened?: boolean;
unmountWhenCollapsed?: boolean;
children?: React.ReactNode;
};
type StateType = {
expanded: boolean,
expanded: boolean;
};
const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon);
class AnimatedAccordion extends React.Component<PropsType, StateType> {
static defaultProps = {
subtitle: '',
left: null,
opened: null,
unmountWhenCollapsed: false,
children: null,
};
chevronRef: {current: null | AnimatedListIcon};
chevronRef: {current: null | (typeof AnimatedListIcon & List.Icon)};
chevronIcon: string;
@ -62,6 +57,9 @@ class AnimatedAccordion extends React.Component<PropsType, StateType> {
constructor(props: PropsType) {
super(props);
this.chevronIcon = '';
this.animStart = '';
this.animEnd = '';
this.state = {
expanded: props.opened != null ? props.opened : false,
};
@ -71,8 +69,9 @@ class AnimatedAccordion extends React.Component<PropsType, StateType> {
shouldComponentUpdate(nextProps: PropsType): boolean {
const {state, props} = this;
if (nextProps.opened != null && nextProps.opened !== props.opened)
if (nextProps.opened != null && nextProps.opened !== props.opened) {
state.expanded = nextProps.opened;
}
return true;
}
@ -101,17 +100,17 @@ class AnimatedAccordion extends React.Component<PropsType, StateType> {
}
};
render(): React.Node {
render() {
const {props, state} = this;
const {colors} = props.theme;
return (
<View>
<View style={props.style}>
<List.Item
title={props.title}
subtitle={props.subtitle}
description={props.subtitle}
titleStyle={state.expanded ? {color: colors.primary} : null}
onPress={this.toggleAccordion}
right={(iconProps: ListIconPropsType): React.Node => (
right={(iconProps) => (
<AnimatedListIcon
ref={this.chevronRef}
style={iconProps.style}

View file

@ -17,29 +17,30 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import {StyleSheet, View} from 'react-native';
import {
NativeScrollEvent,
NativeSyntheticEvent,
StyleSheet,
View,
} from 'react-native';
import {FAB, IconButton, Surface, withTheme} from 'react-native-paper';
import * as Animatable from 'react-native-animatable';
import {StackNavigationProp} from '@react-navigation/stack';
import AutoHideHandler from '../../utils/AutoHideHandler';
import CustomTabBar from '../Tabbar/CustomTabBar';
import type {CustomThemeType} from '../../managers/ThemeManager';
import type {OnScrollType} from '../../utils/AutoHideHandler';
const AnimatedFAB = Animatable.createAnimatableComponent(FAB);
type PropsType = {
navigation: StackNavigationProp,
theme: CustomThemeType,
onPress: (action: string, data?: string) => void,
seekAttention: boolean,
navigation: StackNavigationProp<any>;
theme: ReactNativePaper.Theme;
onPress: (action: string, data?: string) => void;
seekAttention: boolean;
};
type StateType = {
currentMode: string,
currentMode: string;
};
const DISPLAY_MODES = {
@ -78,14 +79,14 @@ const styles = StyleSheet.create({
});
class AnimatedBottomBar extends React.Component<PropsType, StateType> {
ref: {current: null | Animatable.View};
ref: {current: null | (Animatable.View & View)};
hideHandler: AutoHideHandler;
displayModeIcons: {[key: string]: string};
constructor() {
super();
constructor(props: PropsType) {
super(props);
this.state = {
currentMode: DISPLAY_MODES.WEEK,
};
@ -108,13 +109,17 @@ class AnimatedBottomBar extends React.Component<PropsType, StateType> {
}
onHideChange = (shouldHide: boolean) => {
if (this.ref.current != null) {
if (shouldHide) this.ref.current.fadeOutDown(500);
else this.ref.current.fadeInUp(500);
const ref = this.ref;
if (ref && ref.current && ref.current.fadeOutDown && ref.current.fadeInUp) {
if (shouldHide) {
ref.current.fadeOutDown(500);
} else {
ref.current.fadeInUp(500);
}
}
};
onScroll = (event: OnScrollType) => {
onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
this.hideHandler.onScroll(event);
};
@ -139,7 +144,7 @@ class AnimatedBottomBar extends React.Component<PropsType, StateType> {
props.onPress('changeView', newMode);
};
render(): React.Node {
render() {
const {props, state} = this;
const buttonColor = props.theme.colors.primary;
return (

View file

@ -17,22 +17,23 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import {StyleSheet} from 'react-native';
import {
NativeScrollEvent,
NativeSyntheticEvent,
StyleSheet,
View,
} from 'react-native';
import {FAB} from 'react-native-paper';
import * as Animatable from 'react-native-animatable';
import AutoHideHandler from '../../utils/AutoHideHandler';
import CustomTabBar from '../Tabbar/CustomTabBar';
type PropsType = {
icon: string,
onPress: () => void,
icon: string;
onPress: () => void;
};
const AnimatedFab = Animatable.createAnimatableComponent(FAB);
const styles = StyleSheet.create({
fab: {
position: 'absolute',
@ -42,41 +43,50 @@ const styles = StyleSheet.create({
});
export default class AnimatedFAB extends React.Component<PropsType> {
ref: {current: null | Animatable.View};
ref: {current: null | (Animatable.View & View)};
hideHandler: AutoHideHandler;
constructor() {
super();
constructor(props: PropsType) {
super(props);
this.ref = React.createRef();
this.hideHandler = new AutoHideHandler(false);
this.hideHandler.addListener(this.onHideChange);
}
onScroll = (event: SyntheticEvent<EventTarget>) => {
onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
this.hideHandler.onScroll(event);
};
onHideChange = (shouldHide: boolean) => {
if (this.ref.current != null) {
if (shouldHide) this.ref.current.bounceOutDown(1000);
else this.ref.current.bounceInUp(1000);
const ref = this.ref;
if (
ref &&
ref.current &&
ref.current.bounceOutDown &&
ref.current.bounceInUp
) {
if (shouldHide) {
ref.current.bounceOutDown(1000);
} else {
ref.current.bounceInUp(1000);
}
}
};
render(): React.Node {
render() {
const {props} = this;
return (
<AnimatedFab
ref={this.ref}
useNativeDriver
icon={props.icon}
onPress={props.onPress}
style={{
...styles.fab,
bottom: CustomTabBar.TAB_BAR_HEIGHT,
}}
/>
<Animatable.View ref={this.ref} useNativeDriver={true}>
<FAB
icon={props.icon}
onPress={props.onPress}
style={{
...styles.fab,
bottom: CustomTabBar.TAB_BAR_HEIGHT,
}}
/>
</Animatable.View>
);
}
}