-
Notifications
You must be signed in to change notification settings - Fork 3k
/
Copy pathtodayButton.tsx
155 lines (127 loc) Β· 4.07 KB
/
todayButton.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import XDate from 'xdate';
import React, {forwardRef, useImperativeHandle, useEffect, useRef, useState, useContext, useCallback} from 'react';
import {Animated, TouchableOpacity, ViewStyle, ViewProps, StyleProp} from 'react-native';
import {Theme} from '../../types';
import {getDefaultLocale} from '../../services';
import {toMarkingFormat} from '../../interface';
import {isToday, isPastDate} from '../../dateutils';
import {UpdateSources, todayString} from '../commons';
import styleConstructor from '../style';
import Context from './index';
const TOP_POSITION = 65;
const DOWN_ICON = require('../../img/down.png');
const UP_ICON = require('../../img/up.png');
export interface TodayButtonProps extends ViewProps {
/** The opacity for the disabled button (0-1) */
disabledOpacity?: number;
/** The button's top position */
margin?: number;
/** Specify theme properties to override specific styles for calendar parts */
theme?: Theme;
style?: StyleProp<ViewStyle>;
}
export interface TodayButtonImperativeMethods {
disable: (shouldDisable: boolean) => void;
}
const TodayButton = (props: TodayButtonProps, ref: any) => {
useImperativeHandle(ref, () => ({
disable: (shouldDisable: boolean) => {
disable(shouldDisable);
}
}));
const {
margin = 0,
disabledOpacity = 0.3,
theme,
style: propsStyle,
} = props;
const {date, setDate} = useContext(Context);
const [disabled, setDisabled] = useState(false);
const style = useRef(styleConstructor(theme));
const state = isToday(date) ? 0 : isPastDate(date) ? -1 : 1;
const shouldShow = state !== 0;
/** Effects */
useEffect(() => {
if (shouldShow) {
setButtonIcon(getButtonIcon());
}
animatePosition();
}, [state]);
useEffect(() => {
if (!shouldShow) {
return;
}
animateOpacity();
}, [disabled]);
const disable = (shouldDisable: boolean) => {
if (shouldDisable !== disabled) {
setDisabled(shouldDisable);
}
};
/** Label */
const getFormattedLabel = () => {
const todayStr = getDefaultLocale().today || todayString;
const today = todayStr.charAt(0).toUpperCase() + todayStr.slice(1);
return today;
};
const today = useRef(getFormattedLabel());
/** Icon */
const getButtonIcon = () => {
if (shouldShow) {
return state === 1 ? UP_ICON : DOWN_ICON;
}
};
const [buttonIcon, setButtonIcon] = useState(getButtonIcon());
/** Animations */
const buttonY = useRef(new Animated.Value(margin ? -margin : -TOP_POSITION));
const opacity = useRef(new Animated.Value(1));
const getPositionAnimation = () => {
const toValue = state === 0 ? TOP_POSITION : -margin || -TOP_POSITION;
return {
toValue,
tension: 30,
friction: 8,
useNativeDriver: true
};
};
const getOpacityAnimation = () => {
return {
toValue: disabled ? disabledOpacity : 1,
duration: 500,
useNativeDriver: true
};
};
const animatePosition = () => {
const animationData = getPositionAnimation();
Animated.spring(buttonY.current, {
...animationData
}).start();
};
const animateOpacity = () => {
const animationData = getOpacityAnimation();
Animated.timing(opacity.current, {
...animationData
}).start();
};
const getTodayDate = () => {
return toMarkingFormat(new XDate());
};
const onPress = useCallback(() => {
setDate(getTodayDate(), UpdateSources.TODAY_PRESS);
}, [setDate]);
return (
<Animated.View style={[style.current.todayButtonContainer, {transform: [{translateY: buttonY.current}]}]}>
<TouchableOpacity
style={[style.current.todayButton, propsStyle]}
onPress={onPress}
disabled={disabled}
>
{buttonIcon ? (<Animated.Image style={[style.current.todayButtonImage, {opacity: opacity.current}]} source={buttonIcon}/>) : null}
<Animated.Text allowFontScaling={false} style={[style.current.todayButtonText, {opacity: opacity.current}]}>
{today.current}
</Animated.Text>
</TouchableOpacity>
</Animated.View>
);
};
export default forwardRef(TodayButton);