Update animated components to use TypeScript
This commit is contained in:
parent
f43dc55735
commit
140bcf3675
3 changed files with 84 additions and 70 deletions
|
@ -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}
|
|
@ -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 (
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue