UNPKG

4.53 kBJavaScriptView Raw
1import React from "react";
2import PropTypes from "prop-types";
3import {
4 Animated,
5 Easing,
6 Text,
7 TextInput,
8 TouchableWithoutFeedback,
9 View,
10 StyleSheet,
11} from "react-native";
12
13import BaseInput from "./BaseInput";
14
15export default class Jiro extends BaseInput {
16 static propTypes = {
17 borderColor: PropTypes.string,
18 inputPadding: PropTypes.number,
19 height: PropTypes.number,
20 };
21
22 static defaultProps = {
23 borderColor: "red",
24 inputPadding: 16,
25 height: 48,
26 };
27
28 constructor(props, context) {
29 super(props, context);
30
31 const animationValue = props.value ? 1 : 0;
32 this.state = {
33 value: props.value,
34 borderPositionAnim: new Animated.Value(animationValue),
35 borderHeightAnim: new Animated.Value(animationValue),
36 labelPositionAnim: new Animated.Value(animationValue),
37 };
38 }
39
40 _toggle(isActive) {
41 const animationValue = isActive ? 1 : 0;
42 const borderPositionAnimation = Animated.timing(
43 this.state.borderPositionAnim,
44 {
45 toValue: animationValue,
46 eaasing: Easing.bezier(0.2, 1, 0.3, 1),
47 duration: 200,
48 useNativeDriver: false,
49 }
50 );
51 const borderHeightAnimation = Animated.timing(this.state.borderHeightAnim, {
52 toValue: animationValue,
53 eaasing: Easing.ease,
54 duration: 200,
55 useNativeDriver: false,
56 });
57 const labelPositionAnimation = Animated.timing(
58 this.state.labelPositionAnim,
59 {
60 toValue: animationValue,
61 eaasing: Easing.ease,
62 duration: 200,
63 useNativeDriver: false,
64 }
65 );
66
67 if (isActive) {
68 Animated.sequence([
69 borderPositionAnimation,
70 Animated.parallel([labelPositionAnimation, borderHeightAnimation]),
71 ]).start();
72 } else {
73 Animated.sequence([
74 borderHeightAnimation,
75 Animated.parallel([borderPositionAnimation, labelPositionAnimation]),
76 ]).start();
77 }
78 }
79
80 render() {
81 const {
82 label,
83 style: containerStyle,
84 inputStyle,
85 labelStyle,
86 borderColor,
87 height: inputHeight,
88 inputPadding,
89 } = this.props;
90 const {
91 width,
92 borderPositionAnim,
93 borderHeightAnim,
94 labelPositionAnim,
95 value,
96 } = this.state;
97 const totalHeight = inputHeight + 2 * inputPadding;
98
99 return (
100 <View
101 style={[
102 containerStyle,
103 {
104 height: totalHeight,
105 },
106 ]}
107 onLayout={this._onLayout}
108 >
109 <Animated.View
110 style={[
111 styles.border,
112 {
113 height: borderHeightAnim.interpolate({
114 inputRange: [0, 1],
115 outputRange: [3, inputHeight],
116 }),
117 top: borderPositionAnim.interpolate({
118 inputRange: [0, 1],
119 outputRange: [totalHeight - 3, 2 * inputPadding],
120 }),
121 backgroundColor: borderColor,
122 },
123 ]}
124 />
125 <TextInput
126 ref={this.input}
127 {...this.props}
128 style={[
129 styles.textInput,
130 inputStyle,
131 {
132 width,
133 height: inputHeight,
134 left: inputPadding,
135 },
136 ]}
137 value={value}
138 onBlur={this._onBlur}
139 onChange={this._onChange}
140 onFocus={this._onFocus}
141 underlineColorAndroid={"transparent"}
142 />
143 <TouchableWithoutFeedback onPress={this.focus}>
144 <Animated.View
145 style={[
146 styles.labelContainer,
147 {
148 bottom: labelPositionAnim.interpolate({
149 inputRange: [0, 1],
150 outputRange: [
151 inputPadding / 2,
152 inputHeight + inputPadding / 4,
153 ],
154 }),
155 left: inputPadding,
156 },
157 ]}
158 >
159 <Text style={[styles.label, labelStyle]}>{label}</Text>
160 </Animated.View>
161 </TouchableWithoutFeedback>
162 </View>
163 );
164 }
165}
166
167const styles = StyleSheet.create({
168 labelContainer: {
169 position: "absolute",
170 backgroundColor: "transparent",
171 },
172 label: {
173 fontSize: 13,
174 fontWeight: "bold",
175 color: "#6a7989",
176 },
177 textInput: {
178 position: "absolute",
179 bottom: 0,
180 padding: 0,
181 color: "black",
182 fontSize: 18,
183 fontWeight: "bold",
184 },
185 border: {
186 position: "absolute",
187 bottom: 0,
188 left: 0,
189 right: 0,
190 },
191});