Skip to content

Commit

Permalink
Merge pull request #2 from Almouro/features
Browse files Browse the repository at this point in the history
Features
  • Loading branch information
Almouro authored Mar 25, 2017
2 parents b8f7810 + ac92520 commit 421cc02
Show file tree
Hide file tree
Showing 11 changed files with 3,347 additions and 148 deletions.
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["react-native"]
}
45 changes: 45 additions & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -1,7 +1,52 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js

; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/

; Ignore unexpected extra "@providesModule"
.*/node_modules/.*/node_modules/fbjs/.*
.*/node_modules/@exponent/ex-navigation

; Ignore duplicate module providers
; For RN Apps installed via npm, "Libraries" folder is inside
; "node_modules/react-native" but in the source repo it is in the root
.*/Libraries/react-native/React.js
.*/Libraries/react-native/ReactNative.js
.*/Libraries/Components/StaticContainer.js
.*/node_modules/react-native/Libraries/EventEmitter/EventSubscriptionVendor.js
.*/node_modules/react-native/Libraries/EventEmitter/EmitterSubscription.js
.*/node_modules/react-native/Libraries/EventEmitter/EventSubscription.js
.*/node_modules/react-native-form-idable/src/Form.js
.*/node_modules/victory-native/*
.*/node_modules/victory-pie-native/*

[include]

[libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/flow

[options]
emoji=true

module.system=haste
experimental.strict_type_args=true
esproposal.decorators=ignore
munge_underscores=true

module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'

suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FixMe

suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-8]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-8]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy

unsafe.enable_getters_and_setters=true

[version]
^0.38.0
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules
jest
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
language: node_js
cache:
directories:
- jest/tmp
- node_modules
notifications:
email: false
Expand Down
42 changes: 17 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,45 +10,36 @@ npm install --save react-native-form-idable

```javascript
import React, { Component } from 'react';
import { StyleSheet, View } from 'react-native';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { Form, TextInput } from 'react-native-form-idable';
import { Button } from 'homefriend/src/components';
import appStyle from 'homefriend/src/appStyle';

const styles = StyleSheet.create({
container: {
backgroundColor: appStyle.colors.primary,
backgroundColor: 'blue',
flex: 1,
padding: appStyle.margins.l,
padding: 24,
},
});

const fieldStyle = StyleSheet.create({
const formStyles = {
fieldContainer: {
alignSelf: 'stretch',
flexDirection: 'row',
backgroundColor: appStyle.input.backgroundColor,
alignItems: 'center',
height: appStyle.dimensions.touchableHeight,
backgroundColor: 'rgba(255, 255, 255, 0.21)',
},
fieldText: {
color: appStyle.colors.secondary,
flex: 1,
fontSize: appStyle.font.sizes.small,
color: 'white',
fontSize: 14,
fontWeight: '600',
paddingHorizontal: appStyle.input.paddingHorizontal,
paddingHorizontal: 10,
},
errorTextContainer: {
height: 17,
flex: 1,
alignItems: 'flex-end',
marginBottom: appStyle.margins.m,
marginBottom: 10,
},
error: {
color: appStyle.font.colors.white,
fontSize: appStyle.font.sizes.xxs,
color: 'white',
fontSize: 10,
},
});
};

class MyAwesomeForm extends Component {
props: PropsType;
Expand All @@ -57,8 +48,9 @@ class MyAwesomeForm extends Component {
return (
<View style={styles.container}>
<Form
fieldStyle={fieldStyle}
formStyles={formStyles}
onSubmit={formData => console.log(formData)}
onValidationError={errors => console.log(errors)}
>
<TextInput
name="email"
Expand All @@ -72,9 +64,9 @@ class MyAwesomeForm extends Component {
type="password"
required
/>
<Button type="submit">
Submit
</Button>
<TouchableOpacity type="submit">
<Text>Submit</Text>
</TouchableOpacity>
</Form>
</View>
);
Expand Down
24 changes: 22 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,36 @@
"description": "",
"main": "src/index.js",
"scripts": {
"test": "flow",
"test": "jest",
"semantic-release": "semantic-release pre && npm publish && semantic-release post",
"commitmsg": "validate-commit-msg",
"commit": "git-cz"
},
"author": "Almouro <[email protected]> (almouro.com)",
"license": "MIT",
"devDependencies": {
"babel-core": "^6.22.1",
"babel-eslint": "^7.1.1",
"babel-jest": "18.0.0",
"babel-preset-react-native": "^1.9.1",
"commitizen": "^2.9.6",
"cz-conventional-changelog": "^2.0.0",
"enzyme": "^2.7.1",
"enzyme-to-json": "^1.5.0",
"flow-bin": "^0.38.0",
"husky": "^0.13.2",
"jest": "18.1.0",
"jsdom": "^9.12.0",
"react": "^15.4.2",
"react-addons-test-utils": "^15.4.2",
"react-dom": "^15.4.2",
"react-native": "^0.42.3",
"semantic-release": "^6.3.2",
"validate-commit-msg": "^2.11.2"
},
"dependencies": {
"@remobile/react-native-toast": "^1.0.5",
"lodash": "^4.17.4",
"react-native-root-toast": "^1.0.3",
"validator": "^6.2.1"
},
"config": {
Expand All @@ -32,5 +44,13 @@
"repository": {
"type": "git",
"url": "https://github.com/almouro/react-native-form-idable"
},
"jest": {
"preset": "react-native",
"transformIgnorePatterns": [
"node_modules/(?!@exponent/ex-navigation",
")"
],
"cacheDirectory": "<rootDir>/jest/tmp"
}
}
77 changes: 51 additions & 26 deletions src/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,29 @@

import React, { Component } from 'react';
import {
ActivityIndicator,
Keyboard,
ScrollView,
StyleSheet,
View,
} from 'react-native';
import { isArray } from 'lodash';
import Toast from '@remobile/react-native-toast';
import { isArray, merge } from 'lodash';
import Toast from 'react-native-root-toast';
import defaultStyles from './defaultStyles';

type _ValidationError = {
input: any,
message: string,
}

type _Props = {
children: any,
submitText: string,
onSubmit: () => void,
scrollable: boolean,
showErrorsInToast: boolean,
toastErrors: boolean,
isLoading: boolean,
fieldStyle: any,
formStyles: any,
onValidationError: () => _ValidationError[],
}

const styles = StyleSheet.create({
Expand All @@ -27,63 +33,91 @@ const styles = StyleSheet.create({
},
});

const SUBMIT_TYPE = 'submit';

class Form extends Component {
inputs: Array<Object>;
state: Object;
submitButton: Object;
formStyles: Object;

static defaultProps = {
submitText: 'validate',
onSubmit: () => {},
};

constructor(props: _Props) {
super(props);
this.inputs = isArray(this.props.children) ? this.props.children : [this.props.children];

this.setFormInputs();
this.setSubmitButton(props);
this.setInitialState();
this.formStyles = merge({}, defaultStyles, props.formStyles);
}

setFormInputs() {
this.inputs = isArray(this.props.children) ?
this.props.children.filter(child => child.props.type !== SUBMIT_TYPE) :
[this.props.children]
;
}

setInitialState() {
this.state = this.inputs.reduce((formState, input) => ({
...formState,
[input.props.name]: input.props.defaultValue,
}), {});
}

setSubmitButton(props) {
this.submitButton = React.cloneElement(props.children[props.children.length - 1], {
setSubmitButton(props: _Props) {
const submitButton = props.children.find(child => child.props.type === SUBMIT_TYPE);
this.submitButton = React.cloneElement(submitButton, {
onPress: () => this.onSubmit(),
});
}

componentWillReceiveProps(nextProps) {
componentWillReceiveProps(nextProps: _Props) {
this.setSubmitButton(nextProps);
}

onSubmit() {
const errorMessages = [];
const errorMessages: _ValidationError[] = [];

this.inputs.forEach((child) => {
if (!child.props.name) return;
const inputErrorMessage = this.refs[child.props.name].getValidationError();

if (inputErrorMessage) {
errorMessages.push({
inputPlaceholder: child.props.placeholder,
input: child,
message: inputErrorMessage,
});
}
});

if (errorMessages.length === 0) {
Keyboard.dismiss();
return this.props.onSubmit(this.state);
}

if (this.props.showErrorsInToast) {
Toast.showLongTop(`${errorMessages[0].inputPlaceholder}: ${errorMessages[0].message}`);
if (this.props.toastErrors) {
Toast.show(`${errorMessages[0].input.props.placeholder}: ${errorMessages[0].message}`, {
duration: Toast.durations.LONG,
position: Toast.positions.TOP,
});
}

if (this.props.onValidationError) {
this.props.onValidationError(errorMessages);
}
}

renderTextInputClone(input: any) {
return React.cloneElement(input, {
ref: input.props.name,
showError: !this.props.showErrorsInToast,
fieldStyle: this.props.fieldStyle,
key: input.props.name,
showError: !this.props.toastErrors,
formStyles: this.formStyles,
onChangeValue: (value) => {
this.setState({
...this.state,
Expand All @@ -93,20 +127,11 @@ class Form extends Component {
});
}

renderButtonClone(button: any) {
return this.submitButton;
}

renderForm() {
return (
<ScrollView ref="scrollView" scrollEnabled={false} keyboardShouldPersistTaps="always">
{this.inputs.map((child, index) => {
return (
<View key={index}>
{ index === this.inputs.length - 1 ? this.renderButtonClone(child) : this.renderTextInputClone(child)}
</View>
);
})}
{this.inputs.map(child => this.renderTextInputClone(child))}
{ this.submitButton }
</ScrollView>
);
}
Expand Down
Loading

0 comments on commit 421cc02

Please sign in to comment.