├── .npmignore
├── LICENSE
├── README.md
├── examples
└── FormView.js
├── index.js
├── package.json
├── src
├── Form.js
├── KeyboardAwareScrollView.js
├── fields
│ ├── CountDownField.ios.js
│ ├── DatePickerField.android.js
│ ├── DatePickerField.ios.js
│ ├── InputField.android.js
│ ├── InputField.ios.js
│ ├── LinkField.android.js
│ ├── LinkField.ios.js
│ ├── PickerField.android.js
│ ├── PickerField.ios.js
│ ├── Separator.js
│ ├── SwitchField.android.js
│ ├── SwitchField.ios.js
│ ├── TimePickerField.android.js
│ └── TimePickerField.ios.js
├── index.js
└── lib
│ ├── DatePickerComponent.android.js
│ ├── DatePickerComponent.ios.js
│ ├── Field.js
│ ├── HelpText.js
│ ├── InputComponent.js
│ ├── LinkComponent.js
│ ├── PickerComponent.android.js
│ ├── PickerComponent.ios.js
│ ├── SwitchComponent.js
│ └── TimePickerComponent.android.js
└── yarn.lock
/.npmignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18 | .grunt
19 |
20 | # node-waf configuration
21 | .lock-wscript
22 |
23 | # Compiled binary addons (http://nodejs.org/api/addons.html)
24 | build/Release
25 |
26 | # Dependency directory
27 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
28 | node_modules
29 |
30 | # Optional npm cache directory
31 | .npm
32 |
33 | # Optional REPL history
34 | .node_repl_history
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Michael Cereda
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | React Native Form Generator
2 | ================
3 |
4 | Generate forms with native look and feel in a breeze
5 |
6 | [](https://nodei.co/npm/react-native-form-generator/)
7 |
8 |
9 | 
10 |
11 | 
12 |
13 | ## Components
14 | * Picker
15 | * DatePicker
16 | * TimePicker
17 | * Input
18 | * Link
19 | * Separator
20 | * Switch
21 |
22 | ## Features
23 | * Android and IOS support, Yeah Baby!
24 | * Pleasant Defaults, totally overridable
25 | * Doesn't have dependencies
26 | * Use your own icon pack
27 | * Easy to use and clean, react style syntax
28 | * Automatic events handling
29 | * Supports custom fields and styles without adding any weird syntax (just create a react component)
30 | * Applies by default the current OS style
31 | * Inspired by tcomb, the good parts
32 | * Performances: just the field changed gets a setState
33 | * You don't need to create a 'Model' or a 'Struct' that contains your data, just create a form component (the React's way)
34 | * Validate InputFields based on keyboardType (can be overridden using validationFunction)
35 | * Multiple validators
36 | * Reset/Set Fields programmatically (setValue, setDate, setTime, focus)
37 | * Custom Wrapper for Picker & DatePicker Components (iOS Only)
38 |
39 | [My blogpost about React Native Form Generator](https://medium.com/@michaelcereda/react-native-forms-the-right-way-315802f989d6#.p9oj79vt3)
40 |
41 | ## Installation
42 | ```
43 | npm install --save react-native-form-generator
44 | ```
45 | ## I'm actively working on this project
46 |
47 | * Pull requests are very very welcome. They make my day ;).
48 | * Master should be considered 'unstable' even if I do my best to keep it nice and safe.
49 | * Every release has its own branch.
50 | * Slider hasn't been created.
51 | * I have to document the code properly and do some housekeeping, i apologize in advance.
52 |
53 | ## Example
54 |
55 | Please check the folder _examples_ for an always up to date use case.
56 |
57 | the example below generates the form you see in the animation
58 | ```javascript
59 |
60 | /*
61 | This is a view i use in a test app,
62 | very useful to list all the use cases
63 | */
64 |
65 | import React from 'react';
66 |
67 | import {
68 | AppRegistry,
69 | StyleSheet,
70 | Text,
71 | View,ScrollView,
72 | } from 'react-native';
73 |
74 |
75 | import { Form,
76 | Separator,InputField, LinkField,
77 | SwitchField, PickerField,DatePickerField,TimePickerField
78 | } from 'react-native-form-generator';
79 |
80 | export class FormView extends React.Component{
81 | constructor(props){
82 | super(props);
83 | this.state = {
84 | formData:{}
85 | }
86 | }
87 | handleFormChange(formData){
88 | /*
89 | formData will contain all the values of the form,
90 | in this example.
91 |
92 | formData = {
93 | first_name:"",
94 | last_name:"",
95 | gender: '',
96 | birthday: Date,
97 | has_accepted_conditions: bool
98 | }
99 | */
100 |
101 | this.setState({formData:formData})
102 | this.props.onFormChange && this.props.onFormChange(formData);
103 | }
104 | handleFormFocus(e, component){
105 | //console.log(e, component);
106 | }
107 | openTermsAndConditionsURL(){
108 |
109 | }
110 | render(){
111 | return (
112 |
185 | {JSON.stringify(this.state.formData)}
186 |
187 | );
188 | }
189 | }
190 |
191 | ```
192 |
193 | ## Form
194 | Form automatically attaches on change events so you just have to attach an handle to the onFocus attibute of Form to monitor all the changes.
195 |
196 | It's just a wrapper that allows you to attach onFocus (used to track focus events and keyboard events) and onChange (used to track changes in every field)
197 |
198 | ## Fields
199 | #### Common Rules
200 | * __Every__ field that has to propagate its value in the form __MUST__ have a ref attribute. (Separator and LinkField don't have a ref).
201 | Check the example to understand the use of the ref attribute.
202 | * All the components provided use _Field_ as wrapper in order to have the following props.
203 |
204 | | Prop (parameters) | Description |
205 | | --- | --- |
206 | | helpText | String shown as text under the component |
207 | | helpTextComponent | Custom component that replaces the one provided |
208 | | onPress | onPress method |
209 |
210 |
211 | ### Separator
212 | ```javascript
213 |
216 | ```
217 |
218 | ### InputField
219 | Input fields can be used to receive text, you can add icons (a react component) to the left and the right side of the field.
220 |
221 | InputField can validate values based on keyboardType property, validation is not "aggressive", just changes a value inside the class, you can access the value using the ref (ex. this.ref.example_input_field.valid).
222 | InputField automatically provides the attibutes _valid_ and _validationErrors_ to guarantee full control to the developer.
223 |
224 | you can customize your validation function by adding a _validationFunction_ prop to the component. _validationFunction_ supports also an array of validators.
225 |
226 | #### Creating a validator
227 | Validators are simple functions have one paramenter (value) and that return true or a string containing an error.
228 |
229 | ```javascript
230 | let workingValidator = (value)=>{
231 | if(value == '') return "Required";
232 | //Initial state is null/undefined
233 | if(!value) return true;
234 | var matches = value.match(/\d+/g);
235 | if (matches != null) {
236 | return "First Name can't contain numbers";
237 | }
238 |
239 | return true;
240 | }
241 | ```
242 |
243 | _react-native-form-generator_ doesn't depend on any icon library, that gives you freedom of adding any icon or react component you want.
244 |
245 | look at the example here.
246 |
247 | 
248 |
249 | ```javascript
250 | {return true;}}
256 | iconRight={
257 | {
262 | //i can change the style of the component related to the attibute of example_input_field
263 | if(!!(self.refs && self.refs.example_input_field)){
264 | if(!self.refs.example_input_field.valid) return {color:'#d52222'}
265 | }
266 | }
267 | )(this)]}
268 | />
269 | } //React Component
270 | />
271 | ```
272 | All the props are passed down to the underlying TextInput Component
273 |
274 | | Prop (parameters) | Description |
275 | | --- | --- |
276 | | label | Text to show in the field, if exists will move the textinput on the right, providing also the right alignment |
277 | | iconLeft | React component, shown on the left of the field, the component needs to have a prop size to allow the inputText to resize properly |
278 | | iconRight | React component, shown on the right of the field, the component needs to have a prop size to allow the inputText to resize properly |
279 | | validationFunction | Function or array of functions, used to pass custom validators to the component|
280 | | keyboardType | possible values: __undefined__, __email-address__|
281 |
282 | | ref methods | Description |
283 | | --- | --- |
284 | | setValue | Sets the value programmatically |
285 | | focus | Focus the textinput component |
286 |
287 |
288 | ### SwitchField
289 |
290 | | Prop (parameters) | Description |
291 | | --- | --- |
292 | | onValueChange(value) | triggered at every value change, returns the new value of the field|
293 | | value | Initial value of the component (Boolean)|
294 |
295 |
296 | ### PickerField
297 | | Prop (parameters) | Description |
298 | | --- | --- |
299 | | onValueChange(value) | triggered at every value change, returns the new value of the field|
300 | | value | Initial value of the component|
301 | | options=[{label:"test",value="Test"},...] | All the possible options, array of objects|
302 | | iconRight | React component, shown on the left of the text field (i suggest Ionicons 'ios-arrow-right' for a nice iOS effect) |
303 | | pickerWrapper | Optional, Custom wrapper of the picker, check the example |
304 |
305 | ### DatePickerField
306 | Every prop is passed down to the underlying DatePickerIOS/DatePickerAndroid component.
307 |
308 | | Prop (parameters) | Description |
309 | | --- | --- |
310 | | onValueChange(date) | triggered at every value change, returns the new value of the field|
311 | | date | Initial date of the component, defaults to (new Date()) |
312 | | iconRight | React component, shown on the left of the text field (i suggest Ionicons 'ios-arrow-right' for a nice iOS effect) |
313 | | dateTimeFormat | Optional, Custom date formatter |
314 | | pickerWrapper | Optional, Custom wrapper of the picker, check the example |
315 | | prettyPrint | Boolean, if true the component returns a string formatted using dateTimeFormat, if false a Date object is returned |
316 | | placeholderComponent | Substitutes the component used to render the placeholder |
317 | | placeholderStyle | Used to style the placeholder |
318 | | valueStyle | Used to style the field's value |
319 |
320 | ### TimePickerField
321 | Every prop is passed down to the underlying DatePickerIOS/DatePickerAndroid component.
322 | Mode is set to 'time'
323 |
324 | | Prop (parameters) | Description |
325 | | --- | --- |
326 | | onValueChange(date) | triggered at every value change, returns the new value of the field|
327 | | date | Initial date of the component, defaults to (new Date()) |
328 | | iconRight | React component, shown on the left of the text field (i suggest Ionicons 'ios-arrow-right' for a nice iOS effect) |
329 | | dateTimeFormat | Optional, Custom date formatter |
330 | | pickerWrapper | Optional, Custom wrapper of the picker, check the example |
331 | | prettyPrint | Boolean, if true the component returns a string formatted using dateTimeFormat, if false a Date object is returned |
332 | | placeholderComponent | Substitutes the component used to render the placeholder |
333 | | placeholderStyle | Used to style the placeholder |
334 | | valueStyle | Used to style the field's value |
335 |
336 | ### LinkField
337 | Every prop is passed down to the underlying DatePickerIOS component.
338 |
339 | | Prop (parameters) | Description |
340 | | --- | --- |
341 | | label | Text to show in the field |
342 | | iconLeft | React component, shown on the left of the text field |
343 | | iconRight | React component, shown on the left of the text field (i suggest Ionicons 'ios-arrow-right' for a nice iOS effect) |
344 |
345 | ### KeyboardEvents
346 | react-native-form-generator ships with an implementation ok KeyboardAwareScrollView that make handling keyboard events a breeze.
347 | check here https://medium.com/@michaelcereda/react-native-forms-the-right-way-315802f989d6#.p9oj79vt3
348 |
349 | 
350 |
351 | ### Custom Fields
352 | With react-native-form-generator is extremely easy to create your own custom fields.
353 | You just need to know that:
354 | 1. Every field is a react component
355 | 2. Evey field will receive 3 props from the Form object:
356 | - fieldRef: contains the reference of the field (workaround on a react-native bug).
357 | - onChange: must be called every time i want to update the values inside the form component. (required)
358 | - onValueChange: can be used whenever you prefer to pass the values to another component.
359 |
360 | Example
361 | ```javascript
362 | 'use strict';
363 | import {Field} from '../lib/Field';
364 |
365 | export class SimpleInputField extends React.Component{
366 | constructor(props){
367 | super();
368 | }
369 | }
370 |
371 | handleChange(event){
372 | var value = event.nativeEvent.text;
373 |
374 | this.setState({value:value});
375 |
376 | // This updates values in form everytime i update
377 | if(this.props.onChange) this.props.onChange(this.props.fieldRef, value);
378 | if(this.props.onValueChange) this.props.onValueChange(value);
379 | }
380 |
381 | render(){
382 | return(
383 |
392 |
393 | )
394 | }
395 |
396 | }
397 | ```
398 | ### Wrapping fields
399 | You can decide to wrap every field in a component to mantain design uniformity and avoid repetitions (ex. Icons ?!).
400 |
401 | Battle tested example
402 | ```javascript
403 | import {PickerField, LinkField} from 'react-native-form-generator';
404 | import Icon from 'react-native-vector-icons/Ionicons';
405 |
406 | let {
407 | StyleSheet
408 | } = React;
409 |
410 | export class WrappedLinkField extends React.Component{
411 | render(){
412 |
413 | return
419 | }
420 | }
421 |
422 | export class WrappedPickerField extends React.Component{
423 | render(){
424 |
425 | return
439 | }
440 | />
441 | }
442 | }
443 |
444 | let formStyles = StyleSheet.create({
445 | alignRight:{
446 | marginTop: 7, position:'absolute', right: 10
447 | }
448 | });
449 | ```
450 |
--------------------------------------------------------------------------------
/examples/FormView.js:
--------------------------------------------------------------------------------
1 | /*
2 | This is a view i use in a test app,
3 | very useful to list all the use cases
4 | */
5 |
6 | import React from 'react';
7 |
8 | import {
9 | AppRegistry,
10 | StyleSheet,
11 | Text,
12 | View,ScrollView,TouchableHighlight, Modal
13 | } from 'react-native';
14 | import Icon from 'react-native-vector-icons/Ionicons';
15 |
16 |
17 |
18 | import { Form,
19 | Separator,InputField, LinkField,
20 | SwitchField, PickerField, DatePickerField,
21 | TimePickerField, CountDownField
22 | } from 'react-native-form-generator';
23 |
24 | class CustomModal extends React.Component{
25 | handleClose(){
26 | this.props.onHidePicker && this.props.onHidePicker();
27 | }
28 | render(){
29 | return
30 |
31 |
39 | A Custom Wrapper for your picker
46 | {this.props.children}
47 |
48 |
51 | Close
54 |
55 |
56 |
57 | }
58 | }
59 |
60 | class WrappedIcon extends React.Component {
61 | render() {
62 | return (
63 |
64 | );
65 | }
66 | }
67 |
68 | export class FormView extends React.Component{
69 | constructor(props){
70 | super(props);
71 | this.state = {
72 | formData:{}
73 | }
74 | }
75 | handleFormChange(formData){
76 | /*
77 | formData will contain all the values of the form,
78 | in this example.
79 |
80 | formData = {
81 | first_name:"",
82 | last_name:"",
83 | gender: '',
84 | birthday: Date,
85 | has_accepted_conditions: bool
86 | }
87 | */
88 |
89 | this.setState({formData:formData})
90 | this.props.onFormChange && this.props.onFormChange(formData);
91 | }
92 | handleFormFocus(e, component){
93 | //console.log(e, component);
94 | }
95 | openTermsAndConditionsURL(){
96 |
97 | }
98 | resetForm(){
99 |
100 | this.refs.registrationForm.refs.first_name.setValue("");
101 | this.refs.registrationForm.refs.last_name.setValue("");
102 | this.refs.registrationForm.refs.other_input.setValue("");
103 | this.refs.registrationForm.refs.meeting.setDate(new Date());
104 | this.refs.registrationForm.refs.has_accepted_conditions.setValue(false);
105 | }
106 | render(){
107 |
108 |
109 |
110 | return (
111 |
210 | {JSON.stringify(this.state.formData)}
211 |
214 | Reset
218 | this.refs.registrationForm.refs.other_input.focus()}
221 | underlayColor='#78ac05'>
222 | Focus First Name
228 | );
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import {Form} from './src/Form';
4 | import {Separator} from './src/fields/Separator';
5 | import {InputField} from './src/fields/InputField';
6 | import {LinkField} from './src/fields/LinkField';
7 | import {SwitchField} from './src/fields/SwitchField';
8 | import {PickerField} from './src/fields/PickerField';
9 | import {DatePickerField} from './src/fields/DatePickerField';
10 | import {TimePickerField} from './src/fields/TimePickerField';
11 | import {CountDownField} from './src/fields/CountDownField';
12 |
13 |
14 | //import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
15 | export {
16 | Form,
17 | Separator, InputField, LinkField,
18 | SwitchField, PickerField, DatePickerField,
19 | CountDownField, TimePickerField
20 | }
21 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "_args": [
3 | [
4 | "https://github.com/MichaelCereda/react-native-form-generator.git",
5 | "/Users/michael/Projects/OpenSource/TestApp"
6 | ]
7 | ],
8 | "_from": "git+https://github.com/MichaelCereda/react-native-form-generator.git",
9 | "_id": "react-native-form-generator@0.7.2",
10 | "_inCache": true,
11 | "_installable": true,
12 | "_location": "/react-native-form-generator",
13 | "_phantomChildren": {},
14 | "_requested": {
15 | "hosted": {
16 | "directUrl": "https://raw.githubusercontent.com/MichaelCereda/react-native-form-generator/master/package.json",
17 | "gitUrl": "git://github.com/MichaelCereda/react-native-form-generator.git",
18 | "httpsUrl": "git+https://github.com/MichaelCereda/react-native-form-generator.git",
19 | "shortcut": "github:MichaelCereda/react-native-form-generator",
20 | "ssh": "git@github.com:MichaelCereda/react-native-form-generator.git",
21 | "sshUrl": "git+ssh://git@github.com/MichaelCereda/react-native-form-generator.git",
22 | "type": "github"
23 | },
24 | "name": null,
25 | "raw": "https://github.com/MichaelCereda/react-native-form-generator.git",
26 | "rawSpec": "https://github.com/MichaelCereda/react-native-form-generator.git",
27 | "scope": null,
28 | "spec": "git+https://github.com/MichaelCereda/react-native-form-generator.git",
29 | "type": "hosted"
30 | },
31 | "_requiredBy": [
32 | "/"
33 | ],
34 | "_resolved": "git+https://github.com/MichaelCereda/react-native-form-generator.git#f67d26986f3916668d0c3e9e74b66d0ed6165cba",
35 | "_shasum": "cca28fd48d65a98a0a502b5cf84c3b02462ac1c9",
36 | "_shrinkwrap": null,
37 | "_spec": "https://github.com/MichaelCereda/react-native-form-generator.git",
38 | "_where": "/Users/michael/Projects/OpenSource/TestApp",
39 | "author": {
40 | "name": "Michael Cereda",
41 | "url": "info@michaelcereda.com"
42 | },
43 | "bugs": {
44 | "url": "https://github.com/MichaelCereda/react-native-form-generator/issues"
45 | },
46 | "dependencies": {
47 | "prop-types": "^15.5.10"
48 | },
49 | "description": "Generate amazing React Native forms in a breeze",
50 | "gitHead": "f67d26986f3916668d0c3e9e74b66d0ed6165cba",
51 | "homepage": "https://github.com/MichaelCereda/react-native-form-generator#readme",
52 | "keywords": [
53 | "react",
54 | "native",
55 | "forms",
56 | "input",
57 | "react",
58 | "native"
59 | ],
60 | "license": "MIT",
61 | "main": "index.js",
62 | "name": "react-native-form-generator",
63 | "optionalDependencies": {},
64 | "readme": "React Native Form Generator\n================\nGenerate forms with native look and feel in a breeze\n\n[](https://nodei.co/npm/react-native-form-generator/)\n\n\n\n\n\n\n## Features\n* Doesn't have dependencies\n* Use your own icon pack\n* Easy to use and clean, react style syntax\n* Automatic events handling\n* Supports custom fields and styles without adding any weird syntax (just create a react component)\n* Applies by default the current OS style\n* Inspired by tcomb, the good parts\n* Performances: just the field changed gets a setState\n* You don't need to create a 'Model' or a 'Struct' that contains your data, just create a form component (the React's way)\n* Validate InputFields based on keyboardType (can be overridden using validationFunction)\n\n[My blogpost about React Native Form Generator](https://medium.com/@michaelcereda/react-native-forms-the-right-way-315802f989d6#.p9oj79vt3)\n\n## Installation\n```\n npm install --save react-native-form-generator\n```\n## Warning: I'm actively working on this project\n\n* Pull requests are very very welcome\n* All the elements are tested and stable against normal use cases (but i expect to do a lot of changes here and there)\n* Slider hasn't been created\n* I have to document the code properly and do some housekeeping, i apologize in advance.\n* Android support is coming.\n\n* This project requires (for some fields) react-native-vector-icons to show icons in some fields (i will remove this dependency soon)\n\n## Example\nthe example below generates the form you see in the animation\n```javascript\n\nimport { Form, InputField,\n Separator, SwitchField, LinkField ,\n PickerField, DatePickerField\n } from 'react-native-form-generator';\n\n export class MyCoolComponent extends React.Component{\n handleFormChange(formData){\n /*\n formData will contain all the values of the form,\n in this example.\n\n formData = {\n first_name:\"\",\n last_name:\"\",\n gender: '',\n birthday: Date,\n has_accepted_conditions: bool\n }\n */\n\n }\n render(){\n );\n }\n}\n```\n\n## Form\nForm automatically attaches on change events so you just have to attach an handle to the onFocus attibute of Form to monitor all the changes.\n\nIt's just a wrapper that allows you to attach onFocus (used to track focus events and keyboard events) and onChange (used to track changes in every field)\n\n## Fields\n#### Common Rules\n* Every field that has to propagate its value in the form needs to have a ref attribute. (Separator and LinkField don't have a ref).\nCheck the example to understand the use of the ref attribute.\n\n\n### Separator\n```javascript\n \n```\n\n### InputField\nInput fields can be used to receive text, you can add icons (a react component) to the left and the right side of the field.\n\nInputField can validate values based on keyboardType property, validation is not \"aggressive\", just changes a value inside the class, you can access the value using the ref (ex. this.ref.example_input_field.valid).\n\nyou can customize your validation function by adding a validationFunction property to the component\n\nreact-native-form-generator doesn't depend on any icon library, that gives you freedom of adding any icon or react component you want.\n\nlook at the example here.\n\n\n\n```javascript\n {return true;}}\n iconRight={\n {\n //i can change the style of the component related to the attibute of example_input_field\n if(!!(self.refs && self.refs.example_input_field)){\n if(!self.refs.example_input_field.valid) return {color:'#d52222'}\n }\n }\n )(this)]}\n />\n } //React Component\n />\n```\nAll the props are passed down to the underlying TextInput Component\n\n| Prop (parameters) | Description |\n| --- | --- |\n| label | Text to show in the field, if exists will move the textinput on the right, providing also the right alignment |\n| iconLeft | React component, shown on the left of the field, the component needs to have a prop size to allow the inputText to resize properly |\n| iconRight | React component, shown on the right of the field, the component needs to have a prop size to allow the inputText to resize properly |\n\n### SwitchField\n\n| Prop (parameters) | Description |\n| --- | --- |\n| onValueChange(value) | triggered at every value change, returns the new value of the field|\n| value | Initial value of the component (Boolean)|\n\n\n### PickerField\n| Prop (parameters) | Description |\n| --- | --- |\n| onValueChange(value) | triggered at every value change, returns the new value of the field|\n| value | Initial value of the component|\n| options=[{label:\"test\",value=\"Test\"},...] | All the possible options, array of objects|\n| iconRight | React component, shown on the left of the text field (i suggest Ionicons 'ios-arrow-right' for a nice iOS effect) |\n\n### DatePickerField\nEvery prop is passed down to the underlying DatePickerIOS component.\n\n| Prop (parameters) | Description |\n| --- | --- |\n| onValueChange(date) | triggered at every value change, returns the new value of the field|\n| date | Initial date of the component, defaults to (new Date()) |\n| iconRight | React component, shown on the left of the text field (i suggest Ionicons 'ios-arrow-right' for a nice iOS effect) |\n\n### LinkField\nEvery prop is passed down to the underlying DatePickerIOS component.\n\n| Prop (parameters) | Description |\n| --- | --- |\n| label | Text to show in the field |\n| iconLeft | React component, shown on the left of the text field |\n| iconRight | React component, shown on the left of the text field (i suggest Ionicons 'ios-arrow-right' for a nice iOS effect) |\n\n### KeyboardEvents\nreact-native-form-generator ships with an implementation ok KeyboardAwareScrollView that make handling keyboard events a breeze.\ncheck here https://medium.com/@michaelcereda/react-native-forms-the-right-way-315802f989d6#.p9oj79vt3\n\n\n\n### Custom Fields\nWith react-native-form-generator is extremely easy to create your own custom fields.\nYou just need to know that:\n1. Every field is a react component\n2. Evey field will receive 3 props from the Form object:\n - fieldRef: contains the reference of the field (workaround on a react-native bug).\n - onChange: must be called every time i want to update the values inside the form component. (required)\n - onValueChange: can be used whenever you prefer to pass the values to another component.\n\nExample\n```javascript\n'use strict';\nimport {Field} from '../lib/Field';\n\nexport class SimpleInputField extends React.Component{\n constructor(props){\n super();\n }\n }\n\n handleChange(event){\n var value = event.nativeEvent.text;\n\n this.setState({value:value});\n\n // This updates values in form everytime i update\n if(this.props.onChange) this.props.onChange(this.props.fieldRef, value);\n if(this.props.onValueChange) this.props.onValueChange(value);\n }\n\n render(){\n return(\n \n \n )\n}\n\n}\n```\n### Wrapping fields\nYou can decide to wrap every field in a component to mantain design uniformity and avoid repetitions (ex. Icons ?!).\n\nBattle tested example\n```javascript\nimport {PickerField, LinkField} from 'react-native-form-generator';\nimport Icon from 'react-native-vector-icons/Ionicons';\n\nlet {\n StyleSheet\n} = React;\n\nexport class WrappedLinkField extends React.Component{\n render(){\n\n return \n }\n}\n\nexport class WrappedPickerField extends React.Component{\n render(){\n\n return \n }\n />\n }\n}\n\nlet formStyles = StyleSheet.create({\n alignRight:{\n marginTop: 7, position:'absolute', right: 10\n }\n });\n```\n",
65 | "readmeFilename": "README.md",
66 | "repository": {
67 | "type": "git",
68 | "url": "git+https://github.com/MichaelCereda/react-native-form-generator.git"
69 | },
70 | "scripts": {
71 | "test": "echo \"Error: no test specified\" && exit 1"
72 | },
73 | "version": "0.9.10"
74 | }
75 |
--------------------------------------------------------------------------------
/src/Form.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | let { View, TextInput,
3 | StyleSheet,
4 | ScrollView,
5 | Text,
6 | SliderIOS,
7 | TouchableWithoutFeedback
8 | } = require('react-native');
9 |
10 | // import {Separator} from './fields/Separator';
11 |
12 | export class Form extends React.Component{
13 | constructor(props){
14 | super();
15 |
16 | this.values = {};
17 |
18 | }
19 |
20 | handleFieldFocused(event, inputHandle){
21 | this.props.onFocus && this.props.onFocus(event, inputHandle);
22 | }
23 | handleFieldChange(field_ref, value){
24 | this.values[field_ref] = value;
25 | this.props.onChange && this.props.onChange(this.values);
26 | }
27 | getValues(){
28 | return this.values;
29 | }
30 |
31 | underscoreToSpaced(str){
32 | var words = str.split('_');
33 | var res=[];
34 | words.map(function(word, i){
35 | res.push(word.charAt(0).toUpperCase() + word.slice(1));
36 | })
37 |
38 | return res.join(' ');
39 | }
40 |
41 | render(){
42 | let wrappedChildren = [];
43 |
44 | React.Children.map(this.props.children, (child, i)=> {
45 | if (!child) {
46 | return;
47 | }
48 | wrappedChildren.push(React.cloneElement(child, {
49 | key: child.ref || child.type+i,
50 | fieldRef : child.ref,
51 | ref: child.ref,
52 | onFocus:this.handleFieldFocused.bind(this),
53 | onChange:this.handleFieldChange.bind(this, child.ref)
54 | }
55 | ));
56 | }, this);
57 |
58 | return (
59 |
60 | {wrappedChildren}
61 |
62 | );
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/KeyboardAwareScrollView.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { ScrollView, DeviceEventEmitter } from 'react-native'
4 | import StyleSheetPropType from 'react-native/Libraries/StyleSheet/StyleSheetPropType'
5 | import ViewStylePropTypes from 'react-native/Libraries/Components/View/ViewStylePropTypes'
6 |
7 | export class KeyboardAwareScrollView extends React.Component {
8 | constructor (props) {
9 | super(props)
10 | this.state = {
11 | keyboardSpace: 0,
12 | }
13 | this.updateKeyboardSpace = this.updateKeyboardSpace.bind(this)
14 | this.resetKeyboardSpace = this.resetKeyboardSpace.bind(this)
15 | }
16 |
17 | // Keyboard actions
18 | // TODO: automatically handle TabBar height instead of using props
19 | updateKeyboardSpace (frames) {
20 | // let coordinatesHeight = (frames.endCoordinates)? frames.endCoordinates.height : frames.end.height;
21 | let coordinatesHeight = frames.endCoordinates.height;
22 | const keyboardSpace = (this.props.viewIsInsideTabBar) ? coordinatesHeight - 49 : coordinatesHeight
23 | this.setState({
24 | keyboardSpace: keyboardSpace,
25 | })
26 | return {
27 |
28 | }
29 | }
30 |
31 | resetKeyboardSpace () {
32 | this.setState({
33 | keyboardSpace: 0,
34 | })
35 | }
36 |
37 | componentDidMount () {
38 | // Keyboard events
39 | DeviceEventEmitter.addListener('keyboardWillShow', this.updateKeyboardSpace)
40 | DeviceEventEmitter.addListener('keyboardWillHide', this.resetKeyboardSpace)
41 | }
42 |
43 | componentWillUnmount () {
44 | // TODO: figure out if removeAllListeners is the right thing to do
45 | DeviceEventEmitter.removeAllListeners('keyboardWillShow')
46 | DeviceEventEmitter.removeAllListeners('keyboardWillHide')
47 | }
48 |
49 | /**
50 | * @param extraHeight: takes an extra height in consideration.
51 | */
52 | scrollToFocusedInput (event, reactNode, extraHeight = 69) {
53 | const scrollView = this.refs.keyboardScrollView.getScrollResponder();
54 | setTimeout(() => {
55 | scrollView.scrollResponderScrollNativeHandleToKeyboard(
56 | reactNode, extraHeight, true
57 | )
58 | }, 220)
59 | }
60 |
61 | render () {
62 | return (
63 |
70 | {this.props.children}
71 |
72 | )
73 | }
74 | }
75 |
76 | KeyboardAwareScrollView.propTypes = {
77 | style: StyleSheetPropType(ViewStylePropTypes),
78 | children: PropTypes.node,
79 | viewIsInsideTabBar: PropTypes.bool,
80 | }
81 |
--------------------------------------------------------------------------------
/src/fields/CountDownField.ios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import ReactNative from 'react-native';
5 | let { View, StyleSheet, TextInput, Text, PickerIOS} = ReactNative;
6 |
7 |
8 | import {DatePickerComponent} from '../lib/DatePickerComponent';
9 |
10 | export class CountDownField extends React.Component{
11 | setTime(date){
12 | this.refs.datePickerComponent.setDate(date);
13 | }
14 | render(){
15 | /*
16 |
17 | */
18 | return()
31 | }
32 |
33 | }
34 |
35 |
36 |
37 | let formStyles = StyleSheet.create({
38 | form:{
39 |
40 | },
41 | alignRight:{
42 | marginTop: 7, position:'absolute', right: 10
43 | },
44 | noBorder:{
45 | borderTopWidth: 0,
46 | borderBottomWidth: 0
47 | },
48 | separatorContainer:{
49 | // borderTopColor: '#C8C7CC',
50 | // borderTopWidth: 1,
51 | paddingTop: 35,
52 | borderBottomColor: '#C8C7CC',
53 | borderBottomWidth: 1,
54 |
55 | },
56 | separator:{
57 |
58 | paddingLeft: 10,
59 | paddingRight: 10,
60 | color: '#6D6D72',
61 | paddingBottom: 7
62 |
63 | },
64 | fieldsWrapper:{
65 | // borderTopColor: '#afafaf',
66 | // borderTopWidth: 1,
67 | },
68 | horizontalContainer:{
69 | flexDirection: 'row',
70 |
71 | justifyContent: 'flex-start'
72 | },
73 | fieldContainer:{
74 | borderBottomWidth: 1,
75 | borderBottomColor: '#C8C7CC',
76 | backgroundColor: 'white',
77 | justifyContent: 'center',
78 | height: 45
79 | },
80 | fieldValue:{
81 | fontSize: 34/2,
82 | paddingLeft: 10,
83 | paddingRight: 10,
84 | marginRight:10,
85 | paddingTop: 4,
86 | justifyContent: 'center',
87 |
88 | color: '#C7C7CC'
89 | },
90 | fieldText:{
91 | fontSize: 34/2,
92 | paddingLeft: 10,
93 | paddingRight: 10,
94 | justifyContent: 'center',
95 | lineHeight: 32
96 | },
97 | input:{
98 | paddingLeft: 10,
99 | paddingRight: 10,
100 |
101 | },
102 | helpTextContainer:{
103 | marginTop:9,
104 | marginBottom: 25,
105 | paddingLeft: 20,
106 | paddingRight: 20,
107 |
108 | },
109 | helpText:{
110 | color: '#7a7a7a'
111 | }
112 | });
113 |
--------------------------------------------------------------------------------
/src/fields/DatePickerField.android.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import ReactNative from 'react-native';
5 | let { View, StyleSheet, TextInput, Text, PickerIOS} = ReactNative;
6 |
7 |
8 | import {DatePickerComponent} from '../lib/DatePickerComponent';
9 |
10 | export class DatePickerField extends React.Component{
11 | setDate(date){
12 | this.refs.datePickerComponent.setDate(date);
13 | }
14 | render(){
15 |
16 | return()
29 | }
30 |
31 | }
32 |
33 |
34 |
35 | let formStyles = StyleSheet.create({
36 | form:{
37 |
38 | },
39 | alignRight:{
40 | marginTop: 7, position:'absolute', right: 10
41 | },
42 | noBorder:{
43 | borderTopWidth: 0,
44 | borderBottomWidth: 0
45 | },
46 | separatorContainer:{
47 | // borderTopColor: '#C8C7CC',
48 | // borderTopWidth: 1,
49 | paddingTop: 35,
50 | borderBottomColor: '#C8C7CC',
51 | borderBottomWidth: 1,
52 |
53 | },
54 | separator:{
55 |
56 | paddingLeft: 10,
57 | paddingRight: 10,
58 | color: '#6D6D72',
59 | paddingBottom: 7
60 |
61 | },
62 | fieldsWrapper:{
63 | // borderTopColor: '#afafaf',
64 | // borderTopWidth: 1,
65 | },
66 | horizontalContainer:{
67 | flexDirection: 'row',
68 |
69 | justifyContent: 'flex-start'
70 | },
71 | fieldContainer:{
72 | borderBottomWidth: 1,
73 | borderBottomColor: '#C8C7CC',
74 | backgroundColor: 'white',
75 | justifyContent: 'center',
76 | height: 45
77 | },
78 | fieldValue:{
79 | fontSize: 34/2,
80 | paddingLeft: 10,
81 | paddingRight: 10,
82 | marginRight:10,
83 | paddingTop: 4,
84 | justifyContent: 'center',
85 |
86 | color: '#C7C7CC'
87 | },
88 | fieldText:{
89 | fontSize: 34/2,
90 | paddingLeft: 10,
91 | paddingRight: 10,
92 | justifyContent: 'center',
93 | lineHeight: 32
94 | },
95 | input:{
96 | paddingLeft: 10,
97 | paddingRight: 10,
98 |
99 | },
100 | helpTextContainer:{
101 | marginTop:9,
102 | marginBottom: 25,
103 | paddingLeft: 20,
104 | paddingRight: 20,
105 |
106 | },
107 | helpText:{
108 | color: '#7a7a7a'
109 | }
110 | });
111 |
--------------------------------------------------------------------------------
/src/fields/DatePickerField.ios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import ReactNative from 'react-native';
5 | let { View, StyleSheet, TextInput, Text, PickerIOS} = ReactNative;
6 |
7 |
8 | import {DatePickerComponent} from '../lib/DatePickerComponent';
9 |
10 | export class DatePickerField extends React.Component{
11 | setDate(date){
12 | this.refs.datePickerComponent.setDate(date);
13 | }
14 | render(){
15 | return()
29 | }
30 |
31 | }
32 |
33 | let formStyles = StyleSheet.create({
34 | form:{
35 |
36 | },
37 | alignRight:{
38 | marginTop: 7, position:'absolute', right: 10
39 | },
40 | noBorder:{
41 | borderTopWidth: 0,
42 | borderBottomWidth: 0
43 | },
44 | separatorContainer:{
45 | // borderTopColor: '#C8C7CC',
46 | // borderTopWidth: 1,
47 | paddingTop: 35,
48 | borderBottomColor: '#C8C7CC',
49 | borderBottomWidth: 1,
50 |
51 | },
52 | separator:{
53 |
54 | paddingLeft: 10,
55 | paddingRight: 10,
56 | color: '#6D6D72',
57 | paddingBottom: 7
58 |
59 | },
60 | fieldsWrapper:{
61 | // borderTopColor: '#afafaf',
62 | // borderTopWidth: 1,
63 | },
64 | horizontalContainer:{
65 | flexDirection: 'row',
66 |
67 | justifyContent: 'flex-start'
68 | },
69 | fieldContainer:{
70 | borderBottomWidth: 1,
71 | borderBottomColor: '#C8C7CC',
72 | backgroundColor: 'white',
73 | justifyContent: 'center',
74 | height: 45
75 | },
76 | fieldValue:{
77 | fontSize: 34/2,
78 | paddingLeft: 10,
79 | paddingRight: 10,
80 | marginRight:10,
81 | paddingTop: 4,
82 | justifyContent: 'center',
83 |
84 | color: '#C7C7CC'
85 | },
86 | fieldText:{
87 | fontSize: 34/2,
88 | paddingLeft: 10,
89 | paddingRight: 10,
90 | justifyContent: 'center',
91 | lineHeight: 32
92 | },
93 | input:{
94 | paddingLeft: 10,
95 | paddingRight: 10,
96 |
97 | },
98 | helpTextContainer:{
99 | marginTop:9,
100 | marginBottom: 25,
101 | paddingLeft: 20,
102 | paddingRight: 20,
103 |
104 | },
105 | helpText:{
106 | color: '#7a7a7a'
107 | }
108 | });
109 |
--------------------------------------------------------------------------------
/src/fields/InputField.android.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import ReactNative from 'react-native';
5 | import {InputComponent} from '../lib/InputComponent';
6 |
7 | const {StyleSheet} = ReactNative;
8 |
9 | export class InputField extends React.Component{
10 |
11 | handleValidation(isValid, validationErrors){
12 | this.valid = isValid;
13 | this.validationErrors = validationErrors;
14 | }
15 | setValue(value){
16 | this.refs.fieldComponent.setValue(value)
17 | }
18 | focus(){
19 | this.refs.fieldComponent.focus()
20 | }
21 | render(){
22 | return(
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/fields/InputField.ios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import PropTypes from 'prop-types';
5 | import ReactNative from 'react-native';
6 | import {InputComponent} from '../lib/InputComponent';
7 |
8 | const {StyleSheet} = ReactNative;
9 |
10 | export class InputField extends React.Component{
11 | handleValidation(isValid, validationErrors){
12 | this.valid = isValid;
13 | this.validationErrors = validationErrors;
14 | }
15 | setValue(value){
16 | this.refs.fieldComponent.setValue(value)
17 | }
18 | focus(){
19 | this.refs.fieldComponent.focus()
20 | }
21 | render(){
22 | return(
39 | )
40 | }
41 |
42 | }
43 |
44 | InputField.propTypes = {
45 | multiline: PropTypes.bool,
46 | placeholder:PropTypes.string,
47 | }
48 |
49 |
50 | let fieldStyles =StyleSheet.create({
51 | input:{
52 | paddingLeft: 10,
53 | paddingRight: 10,
54 | },
55 | });
56 |
57 | let formStyles = StyleSheet.create({
58 | form:{
59 |
60 | },
61 | alignRight:{
62 | marginTop: 7, position:'absolute', right: 10
63 | },
64 | textRight:{
65 | textAlign: 'right'
66 | },
67 | multiline:{
68 | lineHeight: 32,
69 | fontSize: 34/2,
70 | paddingBottom:10
71 | },
72 | separatorContainer:{
73 | // borderTopColor: '#C8C7CC',
74 | // borderTopWidth: 1,
75 | paddingTop: 35,
76 | borderBottomColor: '#C8C7CC',
77 | borderBottomWidth: 1,
78 |
79 | },
80 |
81 | fieldsWrapper:{
82 | // borderTopColor: '#afafaf',
83 | // borderTopWidth: 1,
84 | },
85 | horizontalContainer:{
86 | flexDirection: 'row',
87 |
88 | justifyContent: 'flex-start'
89 | },
90 | fieldContainer:{
91 | borderBottomWidth: 1,
92 | borderBottomColor: '#C8C7CC',
93 | backgroundColor: 'white',
94 | justifyContent: 'center',
95 | },
96 | fieldText:{
97 | fontSize: 34/2,
98 | paddingLeft: 10,
99 | paddingRight: 10,
100 | justifyContent: 'center',
101 | lineHeight: 32,
102 |
103 | },
104 | input:{
105 | paddingLeft: 10,
106 | paddingRight: 10,
107 |
108 | },
109 | helpTextContainer:{
110 | marginTop:9,
111 | marginBottom: 25,
112 | paddingLeft: 20,
113 | paddingRight: 20,
114 |
115 | },
116 | helpText:{
117 | color: '#7a7a7a'
118 | }
119 | });
120 |
121 |
122 | {/*
124 | {(this.props.iconLeft)
125 | ? this.props.iconLeft
126 | : null
127 | }
128 | {(this.props.label)
129 | ?
130 | {this.props.label}
134 | : null
135 | }
136 |
157 | {(this.props.iconRight)
158 | ? this.props.iconRight
159 | : null
160 | }
161 | */}
162 |
--------------------------------------------------------------------------------
/src/fields/LinkField.android.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | let { View, StyleSheet, TextInput, Text} = require('react-native');
5 | import {LinkComponent} from '../lib/LinkComponent';
6 |
7 |
8 | export class LinkField extends React.Component{
9 | render(){
10 | return(
18 | )
19 | }
20 |
21 | }
22 |
23 | let formStyles = StyleSheet.create({
24 | fieldContainer:{
25 | borderBottomWidth: 1,
26 | borderBottomColor: '#C8C7CC',
27 | backgroundColor: 'white',
28 | justifyContent: 'center',
29 | height: 45
30 | },
31 | horizontalContainer:{
32 | flexDirection: 'row',
33 |
34 | justifyContent: 'flex-start'
35 | },
36 | fieldText:{
37 | fontSize: 34/2,
38 | paddingLeft: 10,
39 | paddingRight: 10,
40 | justifyContent: 'center',
41 | lineHeight: 32
42 | },
43 | });
44 |
--------------------------------------------------------------------------------
/src/fields/LinkField.ios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | let { View, StyleSheet, TextInput, Text} = require('react-native');
5 | import {LinkComponent} from '../lib/LinkComponent';
6 |
7 |
8 | export class LinkField extends React.Component{
9 | render(){
10 | return(
19 | )
20 | }
21 |
22 | }
23 |
24 | let formStyles = StyleSheet.create({
25 | fieldContainer:{
26 | borderBottomWidth: 1,
27 | borderBottomColor: '#C8C7CC',
28 | backgroundColor: 'white',
29 | justifyContent: 'center',
30 | height: 45
31 | },
32 | horizontalContainer:{
33 | flexDirection: 'row',
34 |
35 | justifyContent: 'flex-start'
36 | },
37 | fieldText:{
38 | fontSize: 34/2,
39 | paddingLeft: 10,
40 | paddingRight: 10,
41 | justifyContent: 'center',
42 | lineHeight: 32,
43 | flex:2
44 | },
45 | });
46 |
--------------------------------------------------------------------------------
/src/fields/PickerField.android.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import ReactNative from 'react-native';
5 | let { View, StyleSheet, TextInput, Text, PickerIOS} = ReactNative;
6 |
7 |
8 | import {PickerComponent} from '../lib/PickerComponent';
9 |
10 | export class PickerField extends React.Component{
11 | setValue(value){
12 | this.refs.fieldComponent.setValue(value)
13 | }
14 | render(){
15 | return()
29 | }
30 |
31 | }
32 |
33 |
34 |
35 | let formStyles = StyleSheet.create({
36 | fieldContainer:{
37 | borderBottomWidth: 1,
38 | borderBottomColor: '#C8C7CC',
39 | backgroundColor: 'white',
40 | justifyContent: 'center',
41 | height: 45
42 | },
43 | form:{
44 |
45 | },
46 | alignRight:{
47 | marginTop: 7, position:'absolute', right: 10
48 | },
49 | noBorder:{
50 | borderTopWidth: 0,
51 | borderBottomWidth: 0
52 | },
53 | separatorContainer:{
54 | // borderTopColor: '#C8C7CC',
55 | // borderTopWidth: 1,
56 | paddingTop: 35,
57 | borderBottomColor: '#C8C7CC',
58 | borderBottomWidth: 1,
59 |
60 | },
61 | separator:{
62 |
63 | paddingLeft: 10,
64 | paddingRight: 10,
65 | color: '#6D6D72',
66 | paddingBottom: 7
67 |
68 | },
69 | fieldsWrapper:{
70 | // borderTopColor: '#afafaf',
71 | // borderTopWidth: 1,
72 | },
73 | horizontalContainer:{
74 | flexDirection: 'row',
75 |
76 | justifyContent: 'flex-start'
77 | },
78 |
79 | fieldValue:{
80 | fontSize: 34/2,
81 | paddingLeft: 10,
82 | paddingRight: 10,
83 | marginRight:10,
84 | paddingTop: 4,
85 | justifyContent: 'center',
86 |
87 | color: '#C7C7CC'
88 | },
89 | fieldText:{
90 | fontSize: 34/2,
91 | paddingLeft: 10,
92 | paddingRight: 10,
93 | justifyContent: 'center',
94 | lineHeight: 32
95 | },
96 | input:{
97 | paddingLeft: 10,
98 | paddingRight: 10,
99 |
100 | },
101 | helpTextContainer:{
102 | marginTop:9,
103 | marginBottom: 25,
104 | paddingLeft: 20,
105 | paddingRight: 20,
106 |
107 | },
108 | helpText:{
109 | color: '#7a7a7a'
110 | }
111 | });
112 |
--------------------------------------------------------------------------------
/src/fields/PickerField.ios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import ReactNative from 'react-native';
5 | let { View, StyleSheet, TextInput, Text, PickerIOS} = ReactNative;
6 |
7 |
8 | import {PickerComponent} from '../lib/PickerComponent';
9 |
10 | export class PickerField extends React.Component{
11 | setValue(value){
12 | this.refs.fieldComponent.setValue(value)
13 | }
14 | render(){
15 | return()
28 | }
29 |
30 | }
31 |
32 |
33 |
34 | let formStyles = StyleSheet.create({
35 | form:{
36 |
37 | },
38 | alignRight:{
39 | marginTop: 7, position:'absolute', right: 10
40 | },
41 | noBorder:{
42 | borderTopWidth: 0,
43 | borderBottomWidth: 0
44 | },
45 | separatorContainer:{
46 | // borderTopColor: '#C8C7CC',
47 | // borderTopWidth: 1,
48 | paddingTop: 35,
49 | borderBottomColor: '#C8C7CC',
50 | borderBottomWidth: 1,
51 |
52 | },
53 | separator:{
54 |
55 | paddingLeft: 10,
56 | paddingRight: 10,
57 | color: '#6D6D72',
58 | paddingBottom: 7
59 |
60 | },
61 | fieldsWrapper:{
62 | // borderTopColor: '#afafaf',
63 | // borderTopWidth: 1,
64 | },
65 | horizontalContainer:{
66 | flexDirection: 'row',
67 |
68 | justifyContent: 'flex-start'
69 | },
70 | fieldContainer:{
71 | borderBottomWidth: 1,
72 | borderBottomColor: '#C8C7CC',
73 | backgroundColor: 'white',
74 | justifyContent: 'center',
75 | height: 45
76 | },
77 | fieldValue:{
78 | fontSize: 34/2,
79 | paddingLeft: 10,
80 | paddingRight: 10,
81 | marginRight:10,
82 | paddingTop: 4,
83 | justifyContent: 'center',
84 |
85 | color: '#C7C7CC'
86 | },
87 | fieldText:{
88 | fontSize: 34/2,
89 | paddingLeft: 10,
90 | paddingRight: 10,
91 | justifyContent: 'center',
92 | lineHeight: 32
93 | },
94 | input:{
95 | paddingLeft: 10,
96 | paddingRight: 10,
97 |
98 | },
99 | helpTextContainer:{
100 | marginTop:9,
101 | marginBottom: 25,
102 | paddingLeft: 20,
103 | paddingRight: 20,
104 |
105 | },
106 | helpText:{
107 | color: '#7a7a7a'
108 | }
109 | });
110 |
--------------------------------------------------------------------------------
/src/fields/Separator.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | let { View, StyleSheet, Text} = require('react-native');
5 |
6 | export class Separator extends React.Component{
7 | render(){
8 | return(
9 | {
10 | (this.props.label)?
11 | {this.props.label.toUpperCase()}
12 | : null
13 | }
14 |
15 | )
16 | }
17 | }
18 |
19 | Separator.propTypes = {
20 | labelStyle: Text.propTypes.style,
21 | containerStyle: View.propTypes.style
22 | }
23 |
24 |
25 | let formStyles = StyleSheet.create({
26 | form:{
27 |
28 | },
29 | alignRight:{
30 | marginTop: 7, position:'absolute', right: 10
31 | },
32 | separatorContainer:{
33 | // borderTopColor: '#C8C7CC',
34 | // borderTopWidth: 1,
35 | paddingTop: 35,
36 | borderBottomColor: '#C8C7CC',
37 | borderBottomWidth: 1,
38 |
39 | },
40 | separator:{
41 |
42 | paddingLeft: 10,
43 | paddingRight: 10,
44 | color: '#6D6D72',
45 | paddingBottom: 7
46 |
47 | },
48 | fieldContainer:{
49 | borderBottomWidth: 1,
50 | borderBottomColor: '#C8C7CC',
51 | backgroundColor: 'white',
52 | justifyContent: 'center',
53 | height: 45
54 | },
55 | });
56 |
--------------------------------------------------------------------------------
/src/fields/SwitchField.android.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | let { View, StyleSheet, Text, Switch} = require('react-native');
5 |
6 | import {SwitchComponent} from '../lib/SwitchComponent';
7 |
8 | export class SwitchField extends React.Component{
9 | setValue(value){
10 | this.refs.fieldComponent.setValue(value)
11 | }
12 | render(){
13 |
14 | return(
32 |
33 | )
34 | }
35 |
36 | }
37 |
38 |
39 |
40 | let formStyles = StyleSheet.create({
41 | fieldContainer:{
42 | borderBottomWidth: 1,
43 | borderBottomColor: '#C8C7CC',
44 | backgroundColor: 'white',
45 | justifyContent: 'center',
46 | height: 45
47 | },
48 | horizontalContainer:{
49 | flexDirection: 'row',
50 |
51 | justifyContent: 'flex-start'
52 | },
53 |
54 | });
55 |
--------------------------------------------------------------------------------
/src/fields/SwitchField.ios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | let { View, StyleSheet, Text, Switch} = require('react-native');
5 |
6 | import {SwitchComponent} from '../lib/SwitchComponent';
7 |
8 | export class SwitchField extends React.Component{
9 | setValue(value){
10 | this.refs.fieldComponent.setValue(value)
11 | }
12 | render(){
13 |
14 | return(
32 |
33 | )
34 | }
35 |
36 | }
37 |
38 |
39 |
40 | let formStyles = StyleSheet.create({
41 | fieldContainer:{
42 | borderBottomWidth: 1,
43 | borderBottomColor: '#C8C7CC',
44 | backgroundColor: 'white',
45 | justifyContent: 'center',
46 | height: 45
47 | },
48 | horizontalContainer:{
49 | flexDirection: 'row',
50 |
51 | justifyContent: 'flex-start'
52 | },
53 | fieldText:{
54 | fontSize: 34/2,
55 | paddingLeft: 10,
56 | paddingRight: 10,
57 | justifyContent: 'center',
58 | lineHeight: 32
59 | },
60 |
61 | });
62 |
--------------------------------------------------------------------------------
/src/fields/TimePickerField.android.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import ReactNative from 'react-native';
5 | let { View, StyleSheet, TextInput, Text} = ReactNative;
6 |
7 |
8 | import {TimePickerComponent} from '../lib/TimePickerComponent';
9 |
10 | export class TimePickerField extends React.Component{
11 | setTime(date){
12 | this.refs.datePickerComponent.setTime(date);
13 | }
14 | render(){
15 | /*
16 |
17 | */
18 | return()
31 | }
32 |
33 | }
34 |
35 |
36 |
37 | let formStyles = StyleSheet.create({
38 | form:{
39 |
40 | },
41 | alignRight:{
42 | marginTop: 7, position:'absolute', right: 10
43 | },
44 | noBorder:{
45 | borderTopWidth: 0,
46 | borderBottomWidth: 0
47 | },
48 | separatorContainer:{
49 | // borderTopColor: '#C8C7CC',
50 | // borderTopWidth: 1,
51 | paddingTop: 35,
52 | borderBottomColor: '#C8C7CC',
53 | borderBottomWidth: 1,
54 |
55 | },
56 | separator:{
57 |
58 | paddingLeft: 10,
59 | paddingRight: 10,
60 | color: '#6D6D72',
61 | paddingBottom: 7
62 |
63 | },
64 | fieldsWrapper:{
65 | // borderTopColor: '#afafaf',
66 | // borderTopWidth: 1,
67 | },
68 | horizontalContainer:{
69 | flexDirection: 'row',
70 |
71 | justifyContent: 'flex-start'
72 | },
73 | fieldContainer:{
74 | borderBottomWidth: 1,
75 | borderBottomColor: '#C8C7CC',
76 | backgroundColor: 'white',
77 | justifyContent: 'center',
78 | height: 45
79 | },
80 | fieldValue:{
81 | fontSize: 34/2,
82 | paddingLeft: 10,
83 | paddingRight: 10,
84 | marginRight:10,
85 | paddingTop: 4,
86 | justifyContent: 'center',
87 |
88 | color: '#C7C7CC'
89 | },
90 | fieldText:{
91 | fontSize: 34/2,
92 | paddingLeft: 10,
93 | paddingRight: 10,
94 | justifyContent: 'center',
95 | lineHeight: 32
96 | },
97 | input:{
98 | paddingLeft: 10,
99 | paddingRight: 10,
100 |
101 | },
102 | helpTextContainer:{
103 | marginTop:9,
104 | marginBottom: 25,
105 | paddingLeft: 20,
106 | paddingRight: 20,
107 |
108 | },
109 | helpText:{
110 | color: '#7a7a7a'
111 | }
112 | });
113 |
--------------------------------------------------------------------------------
/src/fields/TimePickerField.ios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import ReactNative from 'react-native';
5 | let { View, StyleSheet, TextInput, Text, PickerIOS} = ReactNative;
6 |
7 |
8 | import {DatePickerComponent} from '../lib/DatePickerComponent';
9 |
10 | export class TimePickerField extends React.Component{
11 | setTime(date){
12 | this.refs.datePickerComponent.setDate(date);
13 | }
14 | render(){
15 | /*
16 |
17 | */
18 | return()
31 | }
32 |
33 | }
34 |
35 |
36 |
37 | let formStyles = StyleSheet.create({
38 | form:{
39 |
40 | },
41 | alignRight:{
42 | marginTop: 7, position:'absolute', right: 10
43 | },
44 | noBorder:{
45 | borderTopWidth: 0,
46 | borderBottomWidth: 0
47 | },
48 | separatorContainer:{
49 | // borderTopColor: '#C8C7CC',
50 | // borderTopWidth: 1,
51 | paddingTop: 35,
52 | borderBottomColor: '#C8C7CC',
53 | borderBottomWidth: 1,
54 |
55 | },
56 | separator:{
57 |
58 | paddingLeft: 10,
59 | paddingRight: 10,
60 | color: '#6D6D72',
61 | paddingBottom: 7
62 |
63 | },
64 | fieldsWrapper:{
65 | // borderTopColor: '#afafaf',
66 | // borderTopWidth: 1,
67 | },
68 | horizontalContainer:{
69 | flexDirection: 'row',
70 |
71 | justifyContent: 'flex-start'
72 | },
73 | fieldContainer:{
74 | borderBottomWidth: 1,
75 | borderBottomColor: '#C8C7CC',
76 | backgroundColor: 'white',
77 | justifyContent: 'center',
78 | height: 45
79 | },
80 | fieldValue:{
81 | fontSize: 34/2,
82 | paddingLeft: 10,
83 | paddingRight: 10,
84 | marginRight:10,
85 | paddingTop: 4,
86 | justifyContent: 'center',
87 |
88 | color: '#C7C7CC'
89 | },
90 | fieldText:{
91 | fontSize: 34/2,
92 | paddingLeft: 10,
93 | paddingRight: 10,
94 | justifyContent: 'center',
95 | lineHeight: 32
96 | },
97 | input:{
98 | paddingLeft: 10,
99 | paddingRight: 10,
100 |
101 | },
102 | helpTextContainer:{
103 | marginTop:9,
104 | marginBottom: 25,
105 | paddingLeft: 20,
106 | paddingRight: 20,
107 |
108 | },
109 | helpText:{
110 | color: '#7a7a7a'
111 | }
112 | });
113 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | import {InputField} from './src/fields/InputField';
4 | import {SwitchField} from './src/fields/SwitchField';
5 | import {Separator} from './src/fields/Separator';
6 | import {LinkField} from './src/fields/LinkField';
7 |
8 | import {DatePickerField} from './src/fields/DatePickerField';
9 | import {Form} from './src/Form';
10 |
11 | import {KeyboardAwareScrollView} from './src/KeyboardAwareScrollView';
12 | //import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
13 | export {InputField, SwitchField,
14 | Separator, LinkField,
15 | KeyboardAwareScrollView,
16 | Form
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/DatePickerComponent.android.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | import React from 'react';
5 | import PropTypes from 'prop-types';
6 | let { View, StyleSheet, TextInput, Text, DatePickerAndroid} = require('react-native');
7 | import {Field} from './Field';
8 |
9 |
10 | export class DatePickerComponent extends React.Component{
11 | constructor(props){
12 | super(props);
13 | this.state = {
14 | date: props.date? new Date(props.date) :'',
15 | isPickerVisible: false
16 | }
17 |
18 | }
19 |
20 | handleLayoutChange(e){
21 | let {x, y, width, height} = {... e.nativeEvent.layout};
22 |
23 | this.setState(e.nativeEvent.layout);
24 | //e.nativeEvent.layout: {x, y, width, height}}}.
25 | }
26 |
27 | handleValueChange(date){
28 |
29 | this.setState({date:date});
30 |
31 | if(this.props.onChange) this.props.onChange((this.props.prettyPrint)?this.props.dateTimeFormat(date):date);
32 | if(this.props.onValueChange) this.props.onValueChange(date);
33 | }
34 | setDate(date){
35 | this.setState({date:date});
36 | if(this.props.onChange) this.props.onChange((this.props.prettyPrint)?this.props.dateTimeFormat(date):date);
37 | if(this.props.onValueChange) this.props.onValueChange(date);
38 | }
39 |
40 |
41 | // this.refs.picker.measure(this.getPickerLayout.bind(this));
42 |
43 |
44 | async _togglePicker(event){
45 | try {
46 |
47 | const {action, year, month, day} = await DatePickerAndroid.open({
48 | date: this.props.date || new Date(),
49 | minDate:this.props.minimumDate,
50 |
51 | maxDate:this.props.maximumDate
52 | });
53 | if (action !== DatePickerAndroid.dismissedAction) {
54 | this.handleValueChange(new Date(year,month,day));
55 | // Selected year, month (0-11), day
56 | }
57 | } catch ({code, message}) {
58 | console.warn('Cannot open time picker', message);
59 | }
60 | this.props.onPress && this.props.onPress(event);
61 | }
62 |
63 | render(){
64 | let placeholderComponent = (this.props.placeholderComponent)
65 | ? this.props.placeholderComponent
66 | : {this.props.placeholder}
67 | return(
71 |
75 | {(this.props.iconLeft)
76 | ? this.props.iconLeft
77 | : null
78 | }
79 | {placeholderComponent}
80 |
81 | {
82 | (this.state.date)?this.state.date.toLocaleDateString():""
83 | }
84 |
85 |
86 |
87 | {(this.props.iconRight)
88 | ? this.props.iconRight
89 | : null
90 | }
91 |
92 |
93 | {(this.state.isPickerVisible)?
94 |
100 |
101 | : null
102 | }
103 |
104 |
105 | )
106 | }
107 |
108 | }
109 |
110 | DatePickerComponent.propTypes = {
111 | dateTimeFormat: PropTypes.func
112 | }
113 |
114 | DatePickerComponent.defaultProps = {
115 | dateTimeFormat: (date)=>{
116 | if(!date) return "";
117 | return date.toLocaleDateString()
118 | }
119 | };
120 |
121 | let formStyles = StyleSheet.create({
122 | form:{
123 |
124 | },
125 | alignRight:{
126 | marginTop: 7, position:'absolute', right: 10
127 | },
128 | noBorder:{
129 | borderTopWidth: 0,
130 | borderBottomWidth: 0
131 | },
132 | separatorContainer:{
133 | // borderTopColor: '#C8C7CC',
134 | // borderTopWidth: 1,
135 | paddingTop: 35,
136 | borderBottomColor: '#C8C7CC',
137 | borderBottomWidth: 1,
138 |
139 | },
140 | separator:{
141 |
142 | paddingLeft: 10,
143 | paddingRight: 10,
144 | color: '#6D6D72',
145 | paddingBottom: 7
146 |
147 | },
148 | fieldsWrapper:{
149 | // borderTopColor: '#afafaf',
150 | // borderTopWidth: 1,
151 | },
152 | horizontalContainer:{
153 | flexDirection: 'row',
154 |
155 | justifyContent: 'flex-start'
156 | },
157 | fieldContainer:{
158 | borderBottomWidth: 1,
159 | borderBottomColor: '#C8C7CC',
160 | backgroundColor: 'white',
161 | justifyContent: 'center',
162 | height: 45
163 | },
164 | fieldValue:{
165 | fontSize: 34/2,
166 | paddingLeft: 10,
167 | paddingRight: 10,
168 | marginRight:10,
169 | paddingTop: 4,
170 | justifyContent: 'center',
171 |
172 | color: '#C7C7CC'
173 | },
174 | fieldText:{
175 | fontSize: 34/2,
176 | paddingLeft: 10,
177 | paddingRight: 10,
178 | justifyContent: 'center',
179 | lineHeight: 32
180 | },
181 | input:{
182 | paddingLeft: 10,
183 | paddingRight: 10,
184 |
185 | },
186 | helpTextContainer:{
187 | marginTop:9,
188 | marginBottom: 25,
189 | paddingLeft: 20,
190 | paddingRight: 20,
191 |
192 | },
193 | helpText:{
194 | color: '#7a7a7a'
195 | }
196 | });
197 |
--------------------------------------------------------------------------------
/src/lib/DatePickerComponent.ios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | import React from 'react';
5 | import PropTypes from 'prop-types';
6 | let { View, StyleSheet, TextInput, Text, DatePickerIOS} = require('react-native');
7 | import {Field} from './Field';
8 |
9 |
10 | export class DatePickerComponent extends React.Component{
11 | constructor(props){
12 | super(props);
13 | this.state = {
14 | date: props.date? new Date(props.date) : '',
15 | isPickerVisible: false
16 | }
17 |
18 | }
19 | setDate(date){
20 | this.setState({date:date});
21 | if(this.props.onChange) this.props.onChange((this.props.prettyPrint)?this.props.dateTimeFormat(date):date);
22 | if(this.props.onValueChange) this.props.onValueChange(date);
23 | }
24 | handleLayoutChange(e){
25 | let {x, y, width, height} = {... e.nativeEvent.layout};
26 |
27 | this.setState(e.nativeEvent.layout);
28 | //e.nativeEvent.layout: {x, y, width, height}}}.
29 | }
30 |
31 | handleValueChange(date){
32 |
33 | this.setState({date:date});
34 |
35 | this.props.onChange && this.props.onChange((this.props.prettyPrint)?this.props.dateTimeFormat(date, this.props.mode):date);
36 | this.props.onValueChange && this.props.onValueChange(date);
37 |
38 | }
39 |
40 |
41 |
42 | // this.refs.picker.measure(this.getPickerLayout.bind(this));
43 |
44 |
45 | _togglePicker(event){
46 | this.setState({isPickerVisible:!this.state.isPickerVisible});
47 | //this._scrollToInput(event);
48 | this.props.onPress && this.props.onPress(event);
49 | }
50 |
51 | render(){
52 | let { maximumDate, minimumDate,
53 | minuteInterval, mode,
54 | onDateChange, timeZoneOffsetInMinutes } = this.props;
55 |
56 | let valueString = this.props.dateTimeFormat(this.state.date, this.props.mode);
57 |
58 | let datePicker=
67 |
68 | let pickerWrapper = React.cloneElement(this.props.pickerWrapper,{onHidePicker:()=>{this.setState({isPickerVisible:false})}},datePicker);
69 |
70 | let iconLeft = this.props.iconLeft,
71 | iconRight = this.props.iconRight;
72 |
73 | if(iconLeft && iconLeft.constructor === Array){
74 | iconLeft = (!this.state.isPickerVisible)
75 | ? iconLeft[0]
76 | : iconLeft[1]
77 | }
78 | if(iconRight && iconRight.constructor === Array){
79 | iconRight = (!this.state.isPickerVisible)
80 | ? iconRight[0]
81 | : iconRight[1]
82 | }
83 | let placeholderComponent = (this.props.placeholderComponent)
84 | ? this.props.placeholderComponent
85 | : {this.props.placeholder}
86 | return(
90 |
94 | {(iconLeft)
95 | ? iconLeft
96 | : null
97 | }
98 | {placeholderComponent}
99 |
100 | { valueString }
101 |
102 | {(iconRight)
103 | ? iconRight
104 | : null
105 | }
106 |
107 |
108 |
109 |
110 | {(this.state.isPickerVisible)?
111 | pickerWrapper : null
112 | }
113 |
114 |
115 | )
116 | }
117 |
118 | }
119 |
120 | DatePickerComponent.propTypes = {
121 | dateTimeFormat: PropTypes.func,
122 | pickerWrapper: PropTypes.element,
123 | prettyPrint: PropTypes.bool
124 | }
125 |
126 | DatePickerComponent.defaultProps = {
127 | pickerWrapper: ,
128 | dateTimeFormat: (date, mode)=>{
129 | if(!date) return "";
130 | let value='';
131 | switch(mode){
132 | case 'datetime':
133 | value = date.toLocaleDateString()
134 | + ' '
135 | + date.toLocaleTimeString()
136 | break;
137 | case 'time':
138 | value = date.toLocaleTimeString()
139 | break;
140 | case 'countdown':
141 | value = date.getHours() + ":" + date.getMinutes();
142 | break;
143 | default:
144 | value = date.toLocaleDateString()
145 | }
146 | return value;
147 | }
148 | };
149 |
150 | let formStyles = StyleSheet.create({
151 | form:{
152 |
153 | },
154 | alignRight:{
155 | marginTop: 7, position:'absolute', right: 10
156 | },
157 | noBorder:{
158 | borderTopWidth: 0,
159 | borderBottomWidth: 0
160 | },
161 | separatorContainer:{
162 | // borderTopColor: '#C8C7CC',
163 | // borderTopWidth: 1,
164 | paddingTop: 35,
165 | borderBottomColor: '#C8C7CC',
166 | borderBottomWidth: 1,
167 |
168 | },
169 | separator:{
170 |
171 | paddingLeft: 10,
172 | paddingRight: 10,
173 | color: '#6D6D72',
174 | paddingBottom: 7
175 |
176 | },
177 | fieldsWrapper:{
178 | // borderTopColor: '#afafaf',
179 | // borderTopWidth: 1,
180 | },
181 | horizontalContainer:{
182 | flexDirection: 'row',
183 | justifyContent: 'flex-start'
184 | },
185 | fieldContainer:{
186 | borderBottomWidth: 1,
187 | borderBottomColor: '#C8C7CC',
188 | backgroundColor: 'white',
189 | justifyContent: 'center',
190 | height: 45
191 | },
192 | fieldValue:{
193 | fontSize: 34/2,
194 | paddingLeft: 10,
195 | paddingRight: 10,
196 | marginRight:10,
197 | paddingTop: 4,
198 | justifyContent: 'center',
199 |
200 | color: '#C7C7CC'
201 | },
202 | fieldText:{
203 | fontSize: 34/2,
204 | paddingLeft: 10,
205 | paddingRight: 10,
206 | justifyContent: 'center',
207 | lineHeight: 32
208 | },
209 | input:{
210 | paddingLeft: 10,
211 | paddingRight: 10,
212 |
213 | },
214 | helpTextContainer:{
215 | marginTop:9,
216 | marginBottom: 25,
217 | paddingLeft: 20,
218 | paddingRight: 20,
219 |
220 | },
221 | helpText:{
222 | color: '#7a7a7a'
223 | }
224 | });
225 |
--------------------------------------------------------------------------------
/src/lib/Field.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import PropTypes from 'prop-types';
5 | import {HelpText} from './HelpText';
6 | let { View, StyleSheet, Text, TouchableHighlight} = require('react-native');
7 |
8 | export class Field extends React.Component{
9 | render(){
10 | let fieldHelpText =
11 | this.props.helpTextComponent
12 | || ((this.props.helpText)
13 | ?
14 | : null);
15 |
16 | if(this.props.onPress){
17 | return
18 |
19 | {this.props.children}
20 | {fieldHelpText}
21 |
22 |
23 | }
24 | return
25 | {this.props.children}
26 | {fieldHelpText}
27 | ;
28 |
29 |
30 | }
31 | }
32 | Field.propTypes = {
33 | helpTextComponent: PropTypes.element,
34 | helpText: PropTypes.string
35 | }
36 |
37 |
38 | let formStyles = StyleSheet.create({
39 |
40 | helpTextContainer:{
41 | marginTop:9,
42 | marginBottom: 25,
43 | paddingLeft: 20,
44 | paddingRight: 20,
45 |
46 | },
47 | helpText:{
48 | color: '#7a7a7a'
49 | }
50 | });
51 |
--------------------------------------------------------------------------------
/src/lib/HelpText.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | 'use strict';
4 |
5 | import React from 'react';
6 | import PropTypes from 'prop-types';
7 |
8 | import { View, StyleSheet, Text} from 'react-native';
9 |
10 | export class HelpText extends React.Component{
11 | render(){
12 | if(!this.props.text) return null;
13 | return (
14 |
15 | {this.props.text}
16 | );
17 | }
18 | }
19 |
20 | HelpText.propTypes = {
21 | text: PropTypes.string
22 | }
23 |
24 |
25 | let formStyles = StyleSheet.create({
26 |
27 | helpTextContainer:{
28 | marginTop:9,
29 | marginBottom: 25,
30 | paddingLeft: 20,
31 | paddingRight: 20,
32 |
33 | },
34 | helpText:{
35 | color: '#7a7a7a'
36 | }
37 | });
38 |
--------------------------------------------------------------------------------
/src/lib/InputComponent.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import PropTypes from 'prop-types';
5 | import ReactNative, { Platform } from 'react-native';
6 | import {Field} from './Field.js';
7 |
8 | const {View, StyleSheet, TextInput, Text} = ReactNative;
9 |
10 | function validateEmail(email) {
11 | var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
12 | if(re.test(email)) return true;
13 | return 'Invalid email';
14 | }
15 |
16 | export class InputComponent extends React.Component{
17 | constructor(props){
18 | super(props);
19 |
20 | this.triggerValidation = this.triggerValidation.bind(this);
21 | // this.validate = this.validate.bind(this)
22 | this.validate(props.value);
23 | this.validationErrors = [];
24 | this.state = {
25 | labelWidth: 0,
26 | value: props.value,
27 | minFieldHeight: props.height || 44,
28 | inputHeight: Math.max(props.height || 44),
29 | // isValid:
30 | };
31 | this.setValue = this.setValue.bind(this)
32 | this.focus = this.focus.bind(this)
33 | this.triggerValidation = this.triggerValidation.bind(this)
34 | this.validate = this.validate.bind(this)
35 | this.handleLayoutChange = this.handleLayoutChange.bind(this)
36 | this.handleLabelLayoutChange = this.handleLabelLayoutChange.bind(this)
37 | this.handleChange = this.handleChange.bind(this)
38 | this.handleFieldPress = this.handleFieldPress.bind(this)
39 | this._scrollToInput = this._scrollToInput.bind(this)
40 | }
41 |
42 | setValue(value){
43 | this.setState({value:value});
44 | if(this.props.onChange) this.props.onChange(value);
45 | if(this.props.onValueChange) this.props.onValueChange(value);
46 | }
47 | focus(){
48 | this.refs.inputBox.focus()
49 | }
50 | triggerValidation() {
51 | this.setState({isValid:this.validate(this.state.value)});
52 | }
53 | validate(value){
54 | let validationResult;
55 | this.validationErrors = [];
56 |
57 | if(!!this.props.validationFunction) {
58 | if(this.props.validationFunction.constructor === Array){
59 | /*
60 | validationFunction has to return an object in case of error,
61 | true in case of successful validation
62 | */
63 | this.props.validationFunction.map((valFn, i)=>{
64 |
65 | let validationResult = valFn(value, this);
66 | if(validationResult === true){
67 | this.valid = (this.valid !== false)? validationResult : this.valid;
68 | } else{
69 | this.validationErrors.push(validationResult);
70 | this.valid = false;
71 | }
72 |
73 | })
74 | } else {
75 | let validationResult = this.props.validationFunction(value, this);
76 | if(validationResult === true){
77 | this.valid = true;
78 | } else{
79 | this.validationErrors.push(validationResult);
80 | this.valid = false;
81 | }
82 | }
83 |
84 | } else
85 | if(this.props.keyboardType){
86 | switch (this.props.keyboardType) {
87 | case 'email-address':
88 | validationResult = validateEmail(value);
89 | break;
90 | }
91 | if(validationResult === true){
92 | this.valid = true;
93 | } else{
94 | this.validationErrors.push(validationResult);
95 | this.valid = false;
96 | }
97 | }
98 | this.props.onValidation(this.valid, this.validationErrors);
99 | return this.valid;
100 | }
101 | handleLayoutChange(e){
102 | if (Platform.OS === 'ios') {
103 | let {x, y, width, height} = {... e.nativeEvent.layout};
104 |
105 | this.setState(e.nativeEvent.layout);
106 | }
107 | // //e.nativeEvent.layout: {x, y, width, height}}}.
108 | }
109 |
110 | handleLabelLayoutChange(e){
111 | if (Platform.OS === 'ios') {
112 | let {x, y, width, height} = {... e.nativeEvent.layout};
113 |
114 | this.setState({labelWidth:width});
115 | }
116 | // //e.nativeEvent.layout: {x, y, width, height}}}.
117 | }
118 | handleChange(event){
119 | const value = event.nativeEvent.text;
120 |
121 | this.validate(value);
122 |
123 | this.setState({value,
124 | inputHeight: Math.max(this.state.minFieldHeight,
125 | (event.nativeEvent.contentSize && this.props.multiline)
126 | ? event.nativeEvent.contentSize.height
127 | : 0)
128 | });
129 | //this.props.onChange(this.props.fieldRef, value);
130 | if(this.props.onChange) this.props.onChange(value, this.valid);
131 | if(this.props.onValueChange) this.props.onValueChange(value,this.valid);
132 | }
133 |
134 | _scrollToInput (event) {
135 | //debugger;
136 | if (this.props.onFocus) {
137 | let handle = ReactNative.findNodeHandle(this.refs.inputBox);
138 | this.props.onFocus(
139 | event,
140 | handle
141 | )
142 | }
143 | }
144 | handleFieldPress(event){
145 | this.refs.inputBox.focus();
146 | }
147 | render(){
148 | // style={[formStyles.fieldContainer,
149 | // formStyles.horizontalContainer,
150 | // this.props.containerStyle,
151 | // {height: this.state.inputHeight+1}
152 | // ]}
153 | return(
154 |
160 | {(this.props.iconLeft)
161 | ? this.props.iconLeft
162 | : null
163 | }
164 | {(this.props.label)
165 | ?
166 | {this.props.label}
171 | : null
172 | }
173 |
192 | {(this.props.iconRight)
193 | ? this.props.iconRight
194 | : null
195 | }
196 |
197 |
198 | )
199 | }
200 |
201 | }
202 |
203 | // InputComponent.propTypes = {
204 | // multiline: PropTypes.bool,
205 | // placeholder:PropTypes.string,
206 | // }
207 |
208 | InputComponent.propTypes = {
209 | labelStyle: Text.propTypes.style,
210 | inputStyle: TextInput.propTypes.style,
211 | containerStyle: View.propTypes.style
212 | }
213 |
--------------------------------------------------------------------------------
/src/lib/LinkComponent.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | let { View, StyleSheet, Text} = require('react-native');
5 | import {Field} from './Field';
6 |
7 |
8 | export class LinkComponent extends React.Component{
9 | constructor(props){
10 | super(props);
11 | this.state = {
12 | }
13 | }
14 | handleLayoutChange(e){
15 | let {x, y, width, height} = {... e.nativeEvent.layout};
16 |
17 | this.setState(e.nativeEvent.layout);
18 | //e.nativeEvent.layout: {x, y, width, height}}}.
19 | }
20 |
21 |
22 | render(){
23 | return(
24 |
27 |
28 | {(this.props.iconLeft)
29 | ? this.props.iconLeft
30 | : null
31 | }
32 |
34 | {this.props.label}
35 |
36 |
37 | {(this.props.iconRight)
38 | ? this.props.iconRight
39 | : null
40 | }
41 |
42 |
43 |
44 | )
45 | }
46 |
47 | }
48 |
49 | LinkComponent.propTypes = {
50 | labelStyle: Text.propTypes.style,
51 | containerStyle: View.propTypes.style
52 | }
53 |
--------------------------------------------------------------------------------
/src/lib/PickerComponent.android.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import ReactNative from 'react-native';
5 | let { View, StyleSheet, TextInput, Text, Picker} = ReactNative;
6 | import {Field} from '../lib/Field';
7 |
8 | var PickerItem = Picker.Item;
9 |
10 | export class PickerComponent extends React.Component{
11 | constructor(props){
12 | super(props);
13 | this.state = {
14 | value: props.value || props.label,
15 | }
16 | this.pickerMeasures = {};
17 | }
18 | setValue(value){
19 | this.setState({value:value});
20 | if(this.props.onChange) this.props.onChange(value);
21 | if(this.props.onValueChange) this.props.onValueChange(value);
22 | }
23 | handleLayoutChange(e){
24 | let {x, y, width, height} = {... e.nativeEvent.layout};
25 |
26 | this.setState(e.nativeEvent.layout);
27 | //e.nativeEvent.layout: {x, y, width, height}}}.
28 | }
29 |
30 | handleValueChange(value){
31 |
32 | this.setState({value:(value && value!='')?value:this.props.label});
33 |
34 | if(this.props.onChange) this.props.onChange(value);
35 | if(this.props.onValueChange) this.props.onValueChange(value);
36 | }
37 |
38 | _scrollToInput (event) {
39 |
40 | if (this.props.onFocus) {
41 | let handle = ReactNative.findNodeHandle(this.refs.inputBox);
42 |
43 | this.props.onFocus(
44 | event,
45 | handle
46 | )
47 | }
48 |
49 | // this.refs.picker.measure(this.getPickerLayout.bind(this));
50 |
51 | }
52 | _togglePicker(event){
53 | //this.setState({isPickerVisible:!this.state.isPickerVisible});
54 | //this._scrollToInput(event);
55 | }
56 | render(){
57 |
58 | return(
63 |
66 |
67 | {this.props.label}
68 |
73 | {Object.keys(this.props.options).map((value) => (
74 |
79 | ), this)}
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | )
90 | }
91 |
92 | }
93 |
94 |
95 |
96 | let formStyles = StyleSheet.create({
97 | form:{
98 |
99 | },
100 | alignRight:{
101 | marginTop: 7, position:'absolute', right: 10
102 | },
103 | noBorder:{
104 | borderTopWidth: 0,
105 | borderBottomWidth: 0
106 | },
107 | separatorContainer:{
108 | // borderTopColor: '#C8C7CC',
109 | // borderTopWidth: 1,
110 | paddingTop: 35,
111 | borderBottomColor: '#C8C7CC',
112 | borderBottomWidth: 1,
113 |
114 | },
115 | separator:{
116 |
117 | paddingLeft: 10,
118 | paddingRight: 10,
119 | color: '#6D6D72',
120 | paddingBottom: 7
121 |
122 | },
123 | fieldsWrapper:{
124 | // borderTopColor: '#afafaf',
125 | // borderTopWidth: 1,
126 | },
127 | horizontalContainer:{
128 | flexDirection: 'row',
129 |
130 | justifyContent: 'flex-start'
131 | },
132 | fieldContainer:{
133 | borderBottomWidth: 1,
134 | borderBottomColor: '#C8C7CC',
135 | backgroundColor: 'white',
136 | justifyContent: 'center',
137 | height: 45
138 | },
139 | fieldValue:{
140 | fontSize: 34/2,
141 | paddingLeft: 10,
142 | paddingRight: 10,
143 | marginRight:10,
144 | paddingTop: 4,
145 | justifyContent: 'center',
146 |
147 | color: '#C7C7CC'
148 | },
149 | fieldText:{
150 | fontSize: 34/2,
151 | paddingLeft: 10,
152 | paddingRight: 10,
153 | justifyContent: 'center',
154 | lineHeight: 32
155 | },
156 | input:{
157 | paddingLeft: 10,
158 | paddingRight: 10,
159 |
160 | },
161 | helpTextContainer:{
162 | marginTop:9,
163 | marginBottom: 25,
164 | paddingLeft: 20,
165 | paddingRight: 20,
166 |
167 | },
168 | helpText:{
169 | color: '#7a7a7a'
170 | }
171 | });
172 |
--------------------------------------------------------------------------------
/src/lib/PickerComponent.ios.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import PropTypes from 'prop-types';
5 | import ReactNative from 'react-native';
6 | let { View, StyleSheet, TextInput, Text, Picker} = ReactNative;
7 | import {Field} from '../lib/Field';
8 |
9 | var PickerItem = Picker.Item;
10 |
11 | export class PickerComponent extends React.Component{
12 | constructor(props){
13 | super(props);
14 | this.state = {
15 | value: props.value,
16 | isPickerVisible: false
17 | }
18 | this.pickerMeasures = {};
19 | }
20 | setValue(value){
21 | this.setState({value:value});
22 | if(this.props.onChange) this.props.onChange(value);
23 | if(this.props.onValueChange) this.props.onValueChange(value);
24 | }
25 | handleLayoutChange(e){
26 | let {x, y, width, height} = {... e.nativeEvent.layout};
27 |
28 | this.setState(e.nativeEvent.layout);
29 | //e.nativeEvent.layout: {x, y, width, height}}}.
30 | }
31 |
32 | handleValueChange(value){
33 |
34 | this.setState({value:value});
35 |
36 | if(this.props.onChange) this.props.onChange(value);
37 | if(this.props.onValueChange) this.props.onValueChange(value);
38 | if(this.props.autoclose) this._togglePicker();
39 | }
40 |
41 | _scrollToInput (event) {
42 |
43 | if (this.props.onFocus) {
44 | let handle = ReactNative.findNodeHandle(this.refs.inputBox);
45 |
46 | this.props.onFocus(
47 | event,
48 | handle
49 | )
50 | }
51 |
52 | // this.refs.picker.measure(this.getPickerLayout.bind(this));
53 |
54 | }
55 | _togglePicker(event){
56 | this.setState({isPickerVisible:!this.state.isPickerVisible});
57 | this.props.onPress && this.props.onPress(event);
58 | //this._scrollToInput(event);
59 | }
60 | render(){
61 | //
62 | // if (this.state.isMultipleSelect){
63 | // let iconName = 'ios-circle-outline';
64 | // let iconColor = {};
65 | // if (this.state.multipleSelectValue[name]) {
66 | // iconName = 'ios-checkmark-outline';
67 | // iconColor = {color:'red'};
68 | // }
69 | // return (
70 | // {this.checkStateChange(name)}}>
72 | //
73 | //
74 | // );
75 | // }else {
76 | // return (
77 | //
78 | // );
79 | // }
80 |
81 | // this.setState({falseSwitchIsOn: value})}
83 | //
84 | // value={this.state.falseSwitchIsOn} />
85 |
86 | // this.props.options.map((option, i) => {
87 | // pickerOptions.push();
92 | // });
93 | let picker =
99 | {Object.keys(this.props.options).map((value) => (
100 |
105 | ), this)}
106 |
107 | ;
108 | let pickerWrapper = React.cloneElement(this.props.pickerWrapper,{ onHidePicker:()=>{this.setState({isPickerVisible:false})}}, picker);
109 | let iconLeft = this.props.iconLeft,
110 | iconRight = this.props.iconRight;
111 |
112 | if(iconLeft && iconLeft.constructor === Array){
113 | iconLeft = (!this.state.isPickerVisible)
114 | ? iconLeft[0]
115 | : iconLeft[1]
116 | }
117 | if(iconRight && iconRight.constructor === Array){
118 | iconRight = (!this.state.isPickerVisible)
119 | ? iconRight[0]
120 | : iconRight[1]
121 | }
122 | return(
126 |
129 | {(iconLeft)
130 | ? iconLeft
131 | : null
132 | }
133 | {this.props.label}
134 |
135 |
136 | {(this.state.value)?this.props.options[this.state.value]:''}
137 |
138 |
139 |
140 | {(this.props.iconRight)
141 | ? this.props.iconRight
142 | : null
143 | }
144 |
145 |
146 |
147 | {(this.state.isPickerVisible)?
148 | pickerWrapper : null
149 | }
150 |
151 |
152 | )
153 | }
154 |
155 | }
156 |
157 | PickerComponent.propTypes = {
158 | pickerWrapper: PropTypes.element,
159 | }
160 |
161 | PickerComponent.defaultProps = {
162 | pickerWrapper:
163 | }
164 |
165 | let formStyles = StyleSheet.create({
166 | form:{
167 |
168 | },
169 | alignRight:{
170 | marginTop: 7, position:'absolute', right: 10
171 | },
172 | noBorder:{
173 | borderTopWidth: 0,
174 | borderBottomWidth: 0
175 | },
176 | separatorContainer:{
177 | // borderTopColor: '#C8C7CC',
178 | // borderTopWidth: 1,
179 | paddingTop: 35,
180 | borderBottomColor: '#C8C7CC',
181 | borderBottomWidth: 1,
182 |
183 | },
184 | separator:{
185 |
186 | paddingLeft: 10,
187 | paddingRight: 10,
188 | color: '#6D6D72',
189 | paddingBottom: 7
190 |
191 | },
192 | fieldsWrapper:{
193 | // borderTopColor: '#afafaf',
194 | // borderTopWidth: 1,
195 | },
196 | horizontalContainer:{
197 | flexDirection: 'row',
198 |
199 | justifyContent: 'flex-start'
200 | },
201 | fieldContainer:{
202 | borderBottomWidth: 1,
203 | borderBottomColor: '#C8C7CC',
204 | backgroundColor: 'white',
205 | justifyContent: 'center',
206 | height: 45
207 | },
208 | fieldValue:{
209 | fontSize: 34/2,
210 | paddingLeft: 10,
211 | paddingRight: 10,
212 | marginRight:10,
213 | paddingTop: 4,
214 | justifyContent: 'center',
215 |
216 | color: '#C7C7CC'
217 | },
218 | fieldText:{
219 | fontSize: 34/2,
220 | paddingLeft: 10,
221 | paddingRight: 10,
222 | justifyContent: 'center',
223 | lineHeight: 32
224 | },
225 | input:{
226 | paddingLeft: 10,
227 | paddingRight: 10,
228 |
229 | },
230 | helpTextContainer:{
231 | marginTop:9,
232 | marginBottom: 25,
233 | paddingLeft: 20,
234 | paddingRight: 20,
235 |
236 | },
237 | helpText:{
238 | color: '#7a7a7a'
239 | }
240 | });
241 |
--------------------------------------------------------------------------------
/src/lib/SwitchComponent.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | let { View, StyleSheet, Text, Switch} = require('react-native');
5 |
6 | import {Field} from './Field';
7 |
8 | export class SwitchComponent extends React.Component{
9 | constructor(props){
10 | super(props);
11 | this.state = {
12 | value: props.value,
13 | }
14 | }
15 | handleLayoutChange(e){
16 | let {x, y, width, height} = {... e.nativeEvent.layout};
17 |
18 | this.setState(e.nativeEvent.layout);
19 | //e.nativeEvent.layout: {x, y, width, height}}}.
20 | }
21 | setValue(value){
22 | this.setState({value:value});
23 | if(this.props.onChange) this.props.onChange(value);
24 | if(this.props.onValueChange) this.props.onValueChange(value);
25 | }
26 |
27 | handleValueChange(value){
28 | // debugger;
29 | this.setState({value:value});
30 | if(this.props.onChange) this.props.onChange(value);
31 | if(this.props.onValueChange) this.props.onValueChange(value);
32 | }
33 |
34 |
35 | render(){
36 |
37 | return(
38 |
40 |
41 | {this.props.label}
42 |
46 |
47 |
48 |
49 | )
50 | }
51 |
52 | }
53 |
54 | SwitchComponent.propTypes = {
55 | labelStyle: Text.propTypes.style,
56 | containerStyle: View.propTypes.style,
57 | switchStyle: Switch.propTypes.style
58 | }
59 |
60 |
61 | let formStyles = StyleSheet.create({
62 | form:{
63 |
64 | },
65 | alignRight:{
66 | marginTop: 7, position:'absolute', right: 10
67 | },
68 | noBorder:{
69 | borderTopWidth: 0,
70 | borderBottomWidth: 0
71 | },
72 | separatorContainer:{
73 | // borderTopColor: '#C8C7CC',
74 | // borderTopWidth: 1,
75 | paddingTop: 35,
76 | borderBottomColor: '#C8C7CC',
77 | borderBottomWidth: 1,
78 |
79 | },
80 | separator:{
81 |
82 | paddingLeft: 10,
83 | paddingRight: 10,
84 | color: '#6D6D72',
85 | paddingBottom: 7
86 |
87 | },
88 | fieldsWrapper:{
89 | // borderTopColor: '#afafaf',
90 | // borderTopWidth: 1,
91 | },
92 | horizontalContainer:{
93 | flexDirection: 'row',
94 |
95 | justifyContent: 'flex-start'
96 | },
97 | fieldContainer:{
98 | borderBottomWidth: 1,
99 | borderBottomColor: '#C8C7CC',
100 | backgroundColor: 'white',
101 | justifyContent: 'center',
102 | height: 45
103 | },
104 | fieldText:{
105 | fontSize: 34/2,
106 | paddingLeft: 10,
107 | paddingRight: 10,
108 | justifyContent: 'center',
109 | lineHeight: 32
110 | },
111 | input:{
112 | paddingLeft: 10,
113 | paddingRight: 10,
114 |
115 | },
116 | helpTextContainer:{
117 | marginTop:9,
118 | marginBottom: 25,
119 | paddingLeft: 20,
120 | paddingRight: 20,
121 |
122 | },
123 | helpText:{
124 | color: '#7a7a7a'
125 | }
126 | });
127 |
--------------------------------------------------------------------------------
/src/lib/TimePickerComponent.android.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | import React from 'react';
5 | import PropTypes from 'prop-types';
6 | let { View, StyleSheet, TextInput, Text, TimePickerAndroid} = require('react-native');
7 | import {Field} from './Field';
8 |
9 |
10 | export class TimePickerComponent extends React.Component{
11 | constructor(props){
12 | super(props);
13 | this.state = {
14 | date: props.date? new Date(props.date) :'',
15 | isPickerVisible: false
16 | }
17 |
18 | }
19 |
20 | handleLayoutChange(e){
21 | let {x, y, width, height} = {... e.nativeEvent.layout};
22 |
23 | this.setState(e.nativeEvent.layout);
24 | //e.nativeEvent.layout: {x, y, width, height}}}.
25 | }
26 |
27 | handleValueChange(date){
28 |
29 | this.setState({date:date});
30 |
31 | if(this.props.onChange) this.props.onChange(date);
32 | if(this.props.onValueChange) this.props.onValueChange(date);
33 | }
34 |
35 | setTime(date){
36 | this.setState({date:date});
37 | if(this.props.onChange) this.props.onChange((this.props.prettyPrint)?this.props.dateTimeFormat(date):date);
38 | if(this.props.onValueChange) this.props.onValueChange(date);
39 | }
40 |
41 | async _togglePicker(event){
42 | try {
43 | const {action, hour, minute} = await TimePickerAndroid.open({...this.props.options});
44 | if (action !== TimePickerAndroid.dismissedAction) {
45 | let date = new Date(0,0,0,hour, minute);
46 |
47 | this.handleValueChange(date);
48 | // Selected year, month (0-11), day
49 | }
50 | } catch ({code, message}) {
51 | console.warn('Cannot open time picker', message);
52 | }
53 |
54 |
55 | }
56 | render(){
57 | let placeholderComponent = (this.props.placeholderComponent)
58 | ? this.props.placeholderComponent
59 | : {this.props.placeholder}
60 | return(
64 |
68 |
69 | {placeholderComponent}
70 |
71 | {
72 | this.props.dateTimeFormat(this.state.date)
73 | }
74 |
75 |
76 |
77 | {(this.props.iconRight)
78 | ? this.props.iconRight
79 | : null
80 | }
81 |
82 |
83 | {(this.state.isPickerVisible)?
84 |
90 |
91 | : null
92 | }
93 |
94 |
95 | )
96 | }
97 |
98 | }
99 | TimePickerComponent.propTypes = {
100 | dateTimeFormat: PropTypes.func,
101 | prettyPrint: PropTypes.bool
102 | }
103 |
104 | TimePickerComponent.defaultProps = {
105 | dateTimeFormat: (date)=>{
106 | if(!date) return "";
107 | return date.toLocaleTimeString();
108 | }
109 | };
110 |
111 |
112 | let formStyles = StyleSheet.create({
113 | form:{
114 |
115 | },
116 | alignRight:{
117 | marginTop: 7, position:'absolute', right: 10
118 | },
119 | noBorder:{
120 | borderTopWidth: 0,
121 | borderBottomWidth: 0
122 | },
123 | separatorContainer:{
124 | // borderTopColor: '#C8C7CC',
125 | // borderTopWidth: 1,
126 | paddingTop: 35,
127 | borderBottomColor: '#C8C7CC',
128 | borderBottomWidth: 1,
129 |
130 | },
131 | separator:{
132 |
133 | paddingLeft: 10,
134 | paddingRight: 10,
135 | color: '#6D6D72',
136 | paddingBottom: 7
137 |
138 | },
139 | fieldsWrapper:{
140 | // borderTopColor: '#afafaf',
141 | // borderTopWidth: 1,
142 | },
143 | horizontalContainer:{
144 | flexDirection: 'row',
145 |
146 | justifyContent: 'flex-start'
147 | },
148 | fieldContainer:{
149 | borderBottomWidth: 1,
150 | borderBottomColor: '#C8C7CC',
151 | backgroundColor: 'white',
152 | justifyContent: 'center',
153 | height: 45
154 | },
155 | fieldValue:{
156 | fontSize: 34/2,
157 | paddingLeft: 10,
158 | paddingRight: 10,
159 | marginRight:10,
160 | paddingTop: 4,
161 | justifyContent: 'center',
162 |
163 | color: '#C7C7CC'
164 | },
165 | fieldText:{
166 | fontSize: 34/2,
167 | paddingLeft: 10,
168 | paddingRight: 10,
169 | justifyContent: 'center',
170 | lineHeight: 32
171 | },
172 | input:{
173 | paddingLeft: 10,
174 | paddingRight: 10,
175 |
176 | },
177 | helpTextContainer:{
178 | marginTop:9,
179 | marginBottom: 25,
180 | paddingLeft: 20,
181 | paddingRight: 20,
182 |
183 | },
184 | helpText:{
185 | color: '#7a7a7a'
186 | }
187 | });
188 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | asap@~2.0.3:
6 | version "2.0.6"
7 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
8 |
9 | core-js@^1.0.0:
10 | version "1.2.7"
11 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
12 |
13 | encoding@^0.1.11:
14 | version "0.1.12"
15 | resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
16 | dependencies:
17 | iconv-lite "~0.4.13"
18 |
19 | fbjs@^0.8.9:
20 | version "0.8.14"
21 | resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.14.tgz#d1dbe2be254c35a91e09f31f9cd50a40b2a0ed1c"
22 | dependencies:
23 | core-js "^1.0.0"
24 | isomorphic-fetch "^2.1.1"
25 | loose-envify "^1.0.0"
26 | object-assign "^4.1.0"
27 | promise "^7.1.1"
28 | setimmediate "^1.0.5"
29 | ua-parser-js "^0.7.9"
30 |
31 | iconv-lite@~0.4.13:
32 | version "0.4.18"
33 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2"
34 |
35 | is-stream@^1.0.1:
36 | version "1.1.0"
37 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
38 |
39 | isomorphic-fetch@^2.1.1:
40 | version "2.2.1"
41 | resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
42 | dependencies:
43 | node-fetch "^1.0.1"
44 | whatwg-fetch ">=0.10.0"
45 |
46 | js-tokens@^3.0.0:
47 | version "3.0.2"
48 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
49 |
50 | loose-envify@^1.0.0, loose-envify@^1.3.1:
51 | version "1.3.1"
52 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
53 | dependencies:
54 | js-tokens "^3.0.0"
55 |
56 | node-fetch@^1.0.1:
57 | version "1.7.1"
58 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.1.tgz#899cb3d0a3c92f952c47f1b876f4c8aeabd400d5"
59 | dependencies:
60 | encoding "^0.1.11"
61 | is-stream "^1.0.1"
62 |
63 | object-assign@^4.1.0:
64 | version "4.1.1"
65 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
66 |
67 | promise@^7.1.1:
68 | version "7.3.1"
69 | resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
70 | dependencies:
71 | asap "~2.0.3"
72 |
73 | prop-types@^15.5.10:
74 | version "15.5.10"
75 | resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
76 | dependencies:
77 | fbjs "^0.8.9"
78 | loose-envify "^1.3.1"
79 |
80 | setimmediate@^1.0.5:
81 | version "1.0.5"
82 | resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
83 |
84 | ua-parser-js@^0.7.9:
85 | version "0.7.14"
86 | resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.14.tgz#110d53fa4c3f326c121292bbeac904d2e03387ca"
87 |
88 | whatwg-fetch@>=0.10.0:
89 | version "2.0.3"
90 | resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
91 |
--------------------------------------------------------------------------------