├── .gitignore
├── README.md
├── lib
├── index.d.ts
└── index.js
├── package.json
├── src
└── index.tsx
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | yarn.lock
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # react-native-outline-input
3 |
4 | This repository is react-native animated input component
5 |
6 | |  |
7 | |----|
8 |
9 |
10 |
11 |
12 | ## Installation
13 |
14 | > npm install react-native-outline-input
15 |
16 | or
17 | > yarn add react-native-outline-input
18 |
19 | ## Usage
20 |
21 | ```js
22 | import React, { useState } from 'react';
23 | import { SafeAreaView } from 'react-native';
24 | import OutlineInput from 'react-native-outline-input';
25 |
26 | const App = () => {
27 | const [email, setEmail] = useState('');
28 | const [password, setPassword] = useState('');
29 |
30 | return (
31 |
32 | setEmail(e)}
35 | label="Username"
36 | activeValueColor="#6c63fe"
37 | activeBorderColor="#6c63fe"
38 | activeLabelColor="#6c63fe"
39 | passiveBorderColor="#bbb7ff"
40 | passiveLabelColor="#bbb7ff"
41 | passiveValueColor="#bbb7ff"
42 | />
43 | setPassword(e)}
46 | label="Username"
47 | activeValueColor="#6c63fe"
48 | activeBorderColor="#6c63fe"
49 | activeLabelColor="#6c63fe"
50 | passiveBorderColor="#bbb7ff"
51 | passiveLabelColor="#bbb7ff"
52 | passiveValueColor="#bbb7ff"
53 | />
54 |
55 | );
56 | };
57 |
58 | export default App;
59 | ```
60 |
61 | ## Props
62 |
63 | |Prop|Type|Default|Description|
64 | |----|----|----|--------|
65 | | label | string | any | The label that will display giving information about your input field
66 | | onChangeText | function | any |Function that works when there is a change
67 | | value | string | any | Value of input
68 | | secureTextEntry | boolean | false | If true, the text input obscures the text entered
69 | | autoCapitalize | string | none | Can tell to automatically capitalize certain characters
70 | | fontSize | number | 16 |Determines the font size
71 | | height | number | 56 | The label that will display giving information about your input field.
72 | | duration | number | 300 | Determines the animation time
73 | | easing | EasingFunction | Easing.inOut(Easing.ease) | Determines the animation type
74 | | activeValueColor | string | #51AD56 | Determines active value color
75 | | passiveValueColor | string | #757575 | Determines passive value color
76 | | activeLabelColor | string | #51AD56 | Determines active label color
77 | | passiveLabelColor | string | #757575 | Determines passive label color
78 | | activeBorderColor | string | #51AD56 | Determines active border color
79 | | passiveBorderColor | string | #EFEFEF | Determines passive border color
80 | | fontFamily | string | System | Determines value and label font family
81 |
82 | Thank you for your contribution to Burhan Yılmaz ([@burhanyilmaz](https://github.com/burhanyilmaz))
83 |
--------------------------------------------------------------------------------
/lib/index.d.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { EasingFunction } from 'react-native';
3 | declare type secureTextEntryType = true | false;
4 | declare type autoCapitalizeType = 'characters' | 'words' | 'sentences' | 'none';
5 | interface PropTypes {
6 | label: string;
7 | onChangeText?: any;
8 | value?: string;
9 | secureTextEntry?: secureTextEntryType;
10 | autoCapitalize?: autoCapitalizeType;
11 | fontSize?: number;
12 | height?: number;
13 | duration?: number;
14 | easing?: EasingFunction;
15 | activeValueColor?: string;
16 | passiveValueColor?: string;
17 | activeLabelColor?: string;
18 | passiveLabelColor?: string;
19 | activeBorderColor?: string;
20 | passiveBorderColor?: string;
21 | fontFamily?: string;
22 | }
23 | declare const _default: React.MemoExoticComponent<({ label, onChangeText, value, secureTextEntry, autoCapitalize, fontSize, height, duration, easing, activeValueColor, passiveValueColor, activeLabelColor, passiveLabelColor, activeBorderColor, passiveBorderColor, fontFamily, }: PropTypes) => JSX.Element>;
24 | export default _default;
25 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const React = require('react');
4 |
5 | var __assign = (this && this.__assign) || function () {
6 | __assign = Object.assign || function(t) {
7 | for (var s, i = 1, n = arguments.length; i < n; i++) {
8 | s = arguments[i];
9 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
10 | t[p] = s[p];
11 | }
12 | return t;
13 | };
14 | return __assign.apply(this, arguments);
15 | };
16 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17 | if (k2 === undefined) k2 = k;
18 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
19 | }) : (function(o, m, k, k2) {
20 | if (k2 === undefined) k2 = k;
21 | o[k2] = m[k];
22 | }));
23 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24 | Object.defineProperty(o, "default", { enumerable: true, value: v });
25 | }) : function(o, v) {
26 | o["default"] = v;
27 | });
28 | var __importStar = (this && this.__importStar) || function (mod) {
29 | if (mod && mod.__esModule) return mod;
30 | var result = {};
31 | if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
32 | __setModuleDefault(result, mod);
33 | return result;
34 | };
35 | Object.defineProperty(exports, "__esModule", { value: true });
36 | var react_1 = __importStar(require("react"));
37 | var react_native_1 = require("react-native");
38 | var OutlineInput = function (_a) {
39 | var label = _a.label, onChangeText = _a.onChangeText, value = _a.value, _b = _a.secureTextEntry, secureTextEntry = _b === void 0 ? false : _b, _c = _a.autoCapitalize, autoCapitalize = _c === void 0 ? 'none' : _c, _d = _a.fontSize, fontSize = _d === void 0 ? 16 : _d, _e = _a.height, height = _e === void 0 ? 56 : _e, _f = _a.duration, duration = _f === void 0 ? 300 : _f, _g = _a.easing, easing = _g === void 0 ? react_native_1.Easing.inOut(react_native_1.Easing.ease) : _g, _h = _a.activeValueColor, activeValueColor = _h === void 0 ? '#51AD56' : _h, _j = _a.passiveValueColor, passiveValueColor = _j === void 0 ? '#757575' : _j, _k = _a.activeLabelColor, activeLabelColor = _k === void 0 ? '#51AD56' : _k, _l = _a.passiveLabelColor, passiveLabelColor = _l === void 0 ? '#757575' : _l, _m = _a.activeBorderColor, activeBorderColor = _m === void 0 ? '#51AD56' : _m, _o = _a.passiveBorderColor, passiveBorderColor = _o === void 0 ? '#EFEFEF' : _o, _p = _a.fontFamily, fontFamily = _p === void 0 ? 'System' : _p;
40 | var _q = react_1.useState(false), isFocused = _q[0], setIsFocused = _q[1];
41 | var lineHeightValue = fontSize + 2;
42 | var initialTopValue = (height - lineHeightValue) / 2;
43 | var labelPositionEmptyValue = 0;
44 | var inputValueFontSize = fontSize;
45 | var padding = 8;
46 | var labelPositionFillValue = lineHeightValue / 2 + initialTopValue;
47 | var inputHeight = height;
48 | var labelPositionRef = react_1.useRef(new react_native_1.Animated.Value(value ? labelPositionFillValue : labelPositionEmptyValue)).current;
49 | var fontSizeRef = react_1.useRef(new react_native_1.Animated.Value(value ? fontSize - 2 : fontSize)).current;
50 | var lineHeightRef = react_1.useRef(new react_native_1.Animated.Value(value ? lineHeightValue - 2 : lineHeightValue)).current;
51 | var zIndexRef = react_1.useRef(new react_native_1.Animated.Value(value ? 2 : -1)).current;
52 | var commonAnimatedProps = {
53 | duration: duration,
54 | useNativeDriver: false,
55 | easing: easing,
56 | };
57 | var onBlur = react_1.useCallback(function () {
58 | setIsFocused(false);
59 | if (!value) {
60 | react_native_1.Animated.parallel([
61 | react_native_1.Animated.timing(labelPositionRef, __assign({ toValue: labelPositionEmptyValue }, commonAnimatedProps)),
62 | react_native_1.Animated.timing(fontSizeRef, __assign({ toValue: fontSize }, commonAnimatedProps)),
63 | react_native_1.Animated.timing(lineHeightRef, __assign({ toValue: lineHeightValue }, commonAnimatedProps)),
64 | react_native_1.Animated.timing(zIndexRef, __assign({ toValue: -1 }, commonAnimatedProps)),
65 | ]).start();
66 | }
67 | }, [!!value]);
68 | var onFocus = react_1.useCallback(function () {
69 | setIsFocused(true);
70 | react_native_1.Animated.parallel([
71 | react_native_1.Animated.timing(labelPositionRef, __assign({ toValue: labelPositionFillValue }, commonAnimatedProps)),
72 | react_native_1.Animated.timing(fontSizeRef, __assign({ toValue: fontSize - 2 }, commonAnimatedProps)),
73 | react_native_1.Animated.timing(lineHeightRef, __assign({ toValue: lineHeightValue - 2 }, commonAnimatedProps)),
74 | react_native_1.Animated.timing(zIndexRef, __assign({ toValue: 2 }, commonAnimatedProps)),
75 | ]).start();
76 | }, [!!value]);
77 | var animatedViewProps = {
78 | style: {
79 | position: 'absolute',
80 | bottom: labelPositionRef,
81 | left: 10,
82 | zIndex: zIndexRef,
83 | height: height,
84 | },
85 | };
86 | var animatedTextProps = {
87 | style: [
88 | LabelStyle({
89 | isFocused: isFocused,
90 | initialTopValue: initialTopValue,
91 | activeLabelColor: activeLabelColor,
92 | passiveLabelColor: passiveLabelColor,
93 | }),
94 | { fontSize: fontSizeRef, lineHeight: lineHeightRef, fontFamily: fontFamily },
95 | ],
96 | };
97 | var inputProps = {
98 | secureTextEntry: secureTextEntry,
99 | value: value,
100 | onChangeText: onChangeText,
101 | onFocus: onFocus,
102 | onBlur: onBlur,
103 | autoCapitalize: autoCapitalize,
104 | isFocused: isFocused,
105 | height: inputHeight,
106 | padding: padding,
107 | fontSize: inputValueFontSize,
108 | activeBorderColor: activeBorderColor,
109 | passiveBorderColor: passiveBorderColor,
110 | style: [
111 | { fontFamily: fontFamily },
112 | InputStyle({
113 | padding: padding,
114 | height: height,
115 | fontSize: fontSize,
116 | isFocused: isFocused,
117 | activeBorderColor: activeBorderColor,
118 | passiveBorderColor: passiveBorderColor,
119 | activeValueColor: activeValueColor,
120 | passiveValueColor: passiveValueColor,
121 | }),
122 | ],
123 | };
124 | return (
125 |
126 | {label}
127 |
128 |
129 | );
130 | };
131 | var LabelStyle = function (_a) {
132 | var isFocused = _a.isFocused, initialTopValue = _a.initialTopValue, activeLabelColor = _a.activeLabelColor, passiveLabelColor = _a.passiveLabelColor;
133 | return ({
134 | fontStyle: 'normal',
135 | fontWeight: 'normal',
136 | color: isFocused ? activeLabelColor : passiveLabelColor,
137 | backgroundColor: '#FFFFFF',
138 | paddingRight: 5,
139 | paddingLeft: 5,
140 | top: initialTopValue,
141 | });
142 | };
143 | var styles = react_native_1.StyleSheet.create({
144 | container: {
145 | flexDirection: 'column',
146 | marginRight: 5,
147 | backgroundColor: '#ffffff',
148 | },
149 | });
150 | var InputStyle = function (_a) {
151 | var padding = _a.padding, height = _a.height, fontSize = _a.fontSize, isFocused = _a.isFocused, activeBorderColor = _a.activeBorderColor, passiveBorderColor = _a.passiveBorderColor, activeValueColor = _a.activeValueColor, passiveValueColor = _a.passiveValueColor;
152 | return ({
153 | padding: padding,
154 | height: height,
155 | fontSize: fontSize,
156 | borderWidth: 1,
157 | borderColor: isFocused ? activeBorderColor : passiveBorderColor,
158 | borderRadius: 6,
159 | color: isFocused ? activeValueColor : passiveValueColor,
160 | });
161 | };
162 | exports.default = react_1.memo(OutlineInput);
163 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-outline-input",
3 | "version": "1.0.7",
4 | "description": "",
5 | "main": "lib/index.js",
6 | "types": "lib/index.d.ts",
7 | "scripts": {
8 | "p-patch": "npm version patch && npm publish",
9 | "p-major": "npm version major && npm publish",
10 | "p-minor": "npm version minor && npm publish",
11 | "build": "tsc"
12 | },
13 | "peerDependencies": {
14 | "react":"^16.8.0"
15 | },
16 | "devDependencies": {
17 | "@types/node": "^14.0.27",
18 | "react": "^16.8.6",
19 | "react-native": "^0.60.0",
20 | "@types/react": "^16.9.43",
21 | "@types/react-native": "^0.63.2",
22 | "typescript": "^3.8.3"
23 | },
24 | "repository": {
25 | "type": "git",
26 | "url": "git+https://github.com/acerezci/react-native-outline-input"
27 | },
28 | "keywords": [
29 | "outlineinput",
30 | "react-native-outline-input"
31 | ],
32 | "author": "Alperen Çerezci",
33 | "license": "ISC"
34 | }
35 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React, {
2 | memo, useRef, useState, useCallback,
3 | } from 'react';
4 | import {
5 | Animated,
6 | Easing,
7 | EasingFunction,
8 | StyleSheet,
9 | View,
10 | TextInput,
11 | } from 'react-native';
12 |
13 | type secureTextEntryType = true | false;
14 | type autoCapitalizeType = 'characters' | 'words' | 'sentences' | 'none';
15 |
16 | interface PropTypes {
17 | label: string;
18 | onChangeText?: any;
19 | value?: string;
20 | secureTextEntry?: secureTextEntryType;
21 | autoCapitalize?: autoCapitalizeType;
22 | fontSize?: number;
23 | height?: number;
24 | duration?: number;
25 | easing?: EasingFunction;
26 | activeValueColor?:string;
27 | passiveValueColor?:string;
28 | activeLabelColor?: string;
29 | passiveLabelColor?: string;
30 | activeBorderColor?: string;
31 | passiveBorderColor?: string;
32 | fontFamily?: string;
33 | }
34 |
35 | interface CommonAnimatedPropsTypes {
36 | duration: number;
37 | useNativeDriver: boolean;
38 | easing: EasingFunction;
39 | }
40 |
41 | interface LabelStylePropTypes {
42 | isFocused: boolean;
43 | initialTopValue: number;
44 | activeLabelColor: string;
45 | passiveLabelColor: string;
46 | }
47 |
48 | interface InputStyleProps {
49 | padding: number;
50 | height: number;
51 | fontSize: number;
52 | isFocused: boolean;
53 | activeBorderColor: string;
54 | passiveBorderColor: string;
55 | activeValueColor:string;
56 | passiveValueColor:string;
57 | }
58 |
59 | const OutlineInput = ({
60 | label,
61 | onChangeText,
62 | value,
63 | secureTextEntry = false,
64 | autoCapitalize = 'none',
65 | fontSize = 16,
66 | height = 56,
67 | duration = 300,
68 | easing = Easing.inOut(Easing.ease),
69 | activeValueColor = '#51AD56',
70 | passiveValueColor = '#757575',
71 | activeLabelColor = '#51AD56',
72 | passiveLabelColor = '#757575',
73 | activeBorderColor = '#51AD56',
74 | passiveBorderColor = '#EFEFEF',
75 | fontFamily = 'System',
76 | }: PropTypes) => {
77 | const [isFocused, setIsFocused] = useState(false);
78 | const lineHeightValue: number = fontSize + 2;
79 | const initialTopValue: number = (height - lineHeightValue) / 2;
80 | const labelPositionEmptyValue: number = 0;
81 | const inputValueFontSize: number = fontSize;
82 | const padding: number = 8;
83 | const labelPositionFillValue: number = lineHeightValue / 2 + initialTopValue;
84 | const inputHeight: number = height;
85 |
86 | const labelPositionRef = useRef(
87 | new Animated.Value(
88 | value ? labelPositionFillValue : labelPositionEmptyValue,
89 | ),
90 | ).current;
91 | const fontSizeRef = useRef(
92 | new Animated.Value(value ? fontSize - 2 : fontSize),
93 | ).current;
94 | const lineHeightRef = useRef(
95 | new Animated.Value(value ? lineHeightValue - 2 : lineHeightValue),
96 | ).current;
97 | const zIndexRef = useRef(new Animated.Value(value ? 2 : -1)).current;
98 |
99 | const commonAnimatedProps: CommonAnimatedPropsTypes = {
100 | duration,
101 | useNativeDriver: false,
102 | easing,
103 | };
104 |
105 | const onBlur: () => void = useCallback(() => {
106 | setIsFocused(false);
107 | if (!value) {
108 | Animated.parallel([
109 | Animated.timing(labelPositionRef, {
110 | toValue: labelPositionEmptyValue,
111 | ...commonAnimatedProps,
112 | }),
113 | Animated.timing(fontSizeRef, {
114 | toValue: fontSize,
115 | ...commonAnimatedProps,
116 | }),
117 | Animated.timing(lineHeightRef, {
118 | toValue: lineHeightValue,
119 | ...commonAnimatedProps,
120 | }),
121 | Animated.timing(zIndexRef, {
122 | toValue: -1,
123 | ...commonAnimatedProps,
124 | }),
125 | ]).start();
126 | }
127 | }, [!!value]);
128 |
129 | const onFocus: () => void = useCallback(() => {
130 | setIsFocused(true);
131 | Animated.parallel([
132 | Animated.timing(labelPositionRef, {
133 | toValue: labelPositionFillValue,
134 | ...commonAnimatedProps,
135 | }),
136 | Animated.timing(fontSizeRef, {
137 | toValue: fontSize - 2,
138 | ...commonAnimatedProps,
139 | }),
140 | Animated.timing(lineHeightRef, {
141 | toValue: lineHeightValue - 2,
142 | ...commonAnimatedProps,
143 | }),
144 | Animated.timing(zIndexRef, {
145 | toValue: 2,
146 | ...commonAnimatedProps,
147 | }),
148 | ]).start();
149 | }, [!!value]);
150 |
151 | const animatedViewProps = {
152 | style: {
153 | position: 'absolute',
154 | bottom: labelPositionRef,
155 | left: 10,
156 | zIndex: zIndexRef,
157 | height,
158 | },
159 | };
160 |
161 | const animatedTextProps = {
162 | style: [
163 | LabelStyle({
164 | isFocused,
165 | initialTopValue,
166 | activeLabelColor,
167 | passiveLabelColor,
168 | }),
169 | { fontSize: fontSizeRef, lineHeight: lineHeightRef, fontFamily },
170 | ],
171 | };
172 |
173 | const inputProps = {
174 | secureTextEntry,
175 | value,
176 | onChangeText,
177 | onFocus,
178 | onBlur,
179 | autoCapitalize,
180 | isFocused,
181 | height: inputHeight,
182 | padding,
183 | fontSize: inputValueFontSize,
184 | activeBorderColor,
185 | passiveBorderColor,
186 | style: [
187 | { fontFamily },
188 | InputStyle({
189 | padding,
190 | height,
191 | fontSize,
192 | isFocused,
193 | activeBorderColor,
194 | passiveBorderColor,
195 | activeValueColor,
196 | passiveValueColor,
197 | }),
198 | ],
199 | };
200 |
201 | return (
202 |
203 |
204 | {label}
205 |
206 |
207 |
208 | );
209 | };
210 |
211 | const LabelStyle = ({
212 | isFocused,
213 | initialTopValue,
214 | activeLabelColor,
215 | passiveLabelColor,
216 | }: LabelStylePropTypes) => ({
217 | fontStyle: 'normal',
218 | fontWeight: 'normal',
219 | color: isFocused ? activeLabelColor : passiveLabelColor,
220 | backgroundColor: '#FFFFFF',
221 | paddingRight: 5,
222 | paddingLeft: 5,
223 | top: initialTopValue,
224 | });
225 |
226 | const styles = StyleSheet.create({
227 | container: {
228 | flexDirection: 'column',
229 | marginRight: 5,
230 | backgroundColor: '#ffffff',
231 | },
232 | });
233 |
234 | const InputStyle = ({
235 | padding,
236 | height,
237 | fontSize,
238 | isFocused,
239 | activeBorderColor,
240 | passiveBorderColor,
241 | activeValueColor,
242 | passiveValueColor,
243 | }: InputStyleProps) => ({
244 | padding,
245 | height,
246 | fontSize,
247 | borderWidth: 1,
248 | borderColor: isFocused ? activeBorderColor : passiveBorderColor,
249 | borderRadius: 6,
250 | color: isFocused ? activeValueColor : passiveValueColor,
251 | });
252 |
253 | export default memo(OutlineInput);
254 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "declaration": true,
6 | "outDir": "./lib",
7 | "rootDir": "src",
8 | "strict": true,
9 | "jsx": "react-native",
10 | "esModuleInterop": true,
11 | "skipLibCheck": true
12 | },
13 | "include": ["src"],
14 | "exclude": ["node_modules"]
15 | }
--------------------------------------------------------------------------------