├── .babelrc ├── .eslintrc ├── .flowconfig ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── example ├── .buckconfig ├── .eslintrc.js ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .prettierrc.js ├── .watchmanconfig ├── App.js ├── __tests__ │ └── App-test.js ├── android │ ├── app │ │ ├── BUCK │ │ ├── build.gradle │ │ ├── build_defs.bzl │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.json ├── babel.config.js ├── form.js ├── index.js ├── ios │ ├── Podfile │ ├── example-tvOS │ │ └── Info.plist │ ├── example-tvOSTests │ │ └── Info.plist │ ├── example.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── example-tvOS.xcscheme │ │ │ └── example.xcscheme │ ├── example │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Base.lproj │ │ │ └── LaunchScreen.xib │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ └── main.m │ └── exampleTests │ │ ├── Info.plist │ │ └── exampleTests.m ├── metro.config.js ├── package-lock.json └── package.json ├── flow-typed └── npm │ ├── @babel │ ├── cli_vx.x.x.js │ ├── core_vx.x.x.js │ ├── node_vx.x.x.js │ ├── preset-env_vx.x.x.js │ ├── preset-flow_vx.x.x.js │ └── register_v7.x.x.js │ ├── babel-eslint_vx.x.x.js │ ├── eslint-plugin-flowtype_vx.x.x.js │ ├── eslint-plugin-react_vx.x.x.js │ ├── eslint_vx.x.x.js │ ├── flow-bin_v0.x.x.js │ ├── flow-typed_vx.x.x.js │ ├── flow_vx.x.x.js │ ├── metro-react-native-babel-preset_vx.x.x.js │ ├── prettier-eslint-cli_vx.x.x.js │ ├── prettier-eslint_vx.x.x.js │ ├── react-native-modal-selector_vx.x.x.js │ ├── react-native-svg-icon_vx.x.x.js │ ├── react-native-svg_vx.x.x.js │ └── uuid_v3.x.x.js ├── index.js ├── package.json ├── src ├── components │ ├── Form.js │ ├── FormAnswerSwitch.js │ ├── FormAnswers.js │ ├── FormComponents │ │ ├── ButtonComponent.js │ │ ├── Component.js │ │ ├── Connected │ │ │ ├── ConnectedSelect.js │ │ │ ├── ConnectedSetSwitch.js │ │ │ ├── ConnectedSliderSet.js │ │ │ ├── ConnectedSliderSetContainer.js │ │ │ ├── ConnectedText.js │ │ │ ├── Select.js │ │ │ └── TextInput.js │ │ ├── ConnectedComponent.js │ │ ├── ConnectedComponentContainer.js │ │ ├── DummyComponent.js │ │ ├── FormElementHeader.js │ │ ├── FormElementsComponent.js │ │ ├── FormPicker.js │ │ ├── Label.js │ │ ├── ListComponent.js │ │ ├── MultipleSelectComponent.js │ │ ├── SelectComponent.js │ │ ├── SetComponent.js │ │ ├── Sets │ │ │ ├── SetSwitch.js │ │ │ └── SliderSet.js │ │ ├── SingleSlider.js │ │ ├── SliderComponent.js │ │ ├── SwitchComponent.js │ │ ├── TextInput.js │ │ └── common │ │ │ └── ListTextElement.js │ ├── components │ │ ├── FormButton.js │ │ ├── SvgIcon.js │ │ └── TextFormButton.js │ └── debug │ │ └── DisplayComponent.js ├── forms │ ├── constants.js │ ├── index.js │ └── types.js ├── resources │ └── images │ │ └── svgicons.js ├── styles │ └── index.js ├── types │ └── formTypes.js ├── utils │ ├── colorTransform.js │ ├── formHelpers.js │ ├── stripKeys.js │ ├── utils.js │ └── viewportCalculation.js └── validation │ └── Form.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "module:metro-react-native-babel-preset", 4 | "@babel/preset-flow" 5 | ] 6 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true 5 | }, 6 | "plugins": ["react", "flowtype"], 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:react/recommended", 10 | "plugin:flowtype/recommended" 11 | ], 12 | "parser": "babel-eslint", 13 | "rules": { 14 | "comma-dangle": ["error", "always-multiline"], 15 | "no-console": 0, 16 | "semi": ["error", "never"], 17 | "rules": { 18 | "quotes": ["error", "single"] 19 | }, 20 | "eqeqeq": ["error", "always"], 21 | "no-trailing-spaces": "error", 22 | "no-multi-spaces": [ 23 | "error", 24 | { "exceptions": { "ImportDeclaration": true } } 25 | ], 26 | "no-loop-func": "error", 27 | "no-case-declarations": "error", 28 | "template-curly-spacing": "off", 29 | "indent": "off" 30 | }, 31 | "globals": { 32 | "__DEV__": true 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/node_modules/* 3 | 4 | [include] 5 | ./src/* 6 | 7 | [libs] 8 | node_modules/react-native/flow 9 | node_modules/react-native/flow-github/ 10 | flow/ 11 | flow-typed 12 | react-native 13 | 14 | [lints] 15 | 16 | [options] 17 | module.system=haste 18 | module.file_ext=.js 19 | module.file_ext=.jsx 20 | module.file_ext=.json 21 | module.file_ext=.native.js 22 | 23 | [strict] 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | *.log 3 | *.tgz 4 | npm-debug.log 5 | 6 | # Runtime data 7 | tmp 8 | build 9 | dist 10 | 11 | # Dependency directory 12 | node_modules -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | *.log 3 | npm-debug.log 4 | 5 | # Dependency directory 6 | node_modules 7 | 8 | # Example directory 9 | example 10 | 11 | # Types 12 | flow-typed -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Oscar Colmenares 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## React native typed forms 2 | 3 | An UI forms library to make it easy to build forms with custom development behavior in react native 4 | 5 | ### Installation 6 | 7 | First you need to install 8 | 9 | - [react-native-svg](https://github.com/react-native-community/react-native-svg) 10 | - [react-native-svg-icon](https://github.com/stowball/react-native-svg-icon) 11 | - [react-native-vector-icons](https://github.com/oblador/react-native-vector-icons) 12 | 13 | Then 14 | 15 | `npm install --save react-native-typed-forms` 16 | 17 | Or if using yarn 18 | 19 | `yarn add react-native-typed-forms` 20 | 21 | ### Usage 22 | 23 | The main component of the library is the Form component, this component handles everything from displaying the form to handling the inner data of the form. 24 | 25 | ``` 26 | import { Form } from 'react-native-typed-form` 27 | 28 | . 29 | . 30 | . 31 |
37 | . 38 | . 39 | . 40 | ``` 41 | 42 | #### Properties 43 | 44 | | Property | Required | default | type | 45 | | :------------- | :------- | :------ | :--------------- | 46 | | model | yes | - | Object | 47 | | value | no | null | Object - null\* | 48 | | onFinish | yes | - | Function(Object) | 49 | | disableAnswers | no | false | Boolean\*\* | 50 | 51 | On finish will provide a data value that can be provided AS IS to the value prop of the form, and the form itself will handle the data to preload the components. 52 | 53 | \*If you do not provide a value (that is, the value produced by the onFinish method after completing a form) it will always create a new blank form. Providing a value preloads with data from previous iterations. 54 | 55 | \*\*Extremely recommended to set as true always, this was an old mechanic that needs to be changed 56 | 57 | #### Model 58 | 59 | The model is the spec the lib will use to build the form, see the example for a more convoluted use, but basically it's the following: 60 | 61 | ``` 62 | { 63 | type: formTypes.form, // always 64 | answer: answerTypes.single, // answer types, multiple not docummented 65 | fields: { 66 | 0: { // for now, indexes are required 67 | type: formTypes.string, // any of the form component types 68 | key: 'text_identifier', // key is required, has to be unique inside the form 69 | content: { 70 | text: 'This is a text field you can fill', 71 | }, 72 | options: { 73 | placeHolder: 'Filler text', 74 | multiline: true, 75 | default: '', 76 | }, 77 | }, 78 | }, 79 | } 80 | ``` 81 | 82 | Each component has it's own unique content/options spec, which are due for documentation. 83 | 84 | # Example app 85 | 86 | To run the example app 87 | ``` 88 | - git clone this repo 89 | - cd example 90 | - npm install 91 | - react-native run-android 92 | ``` 93 | 94 | Windows users may need to run npx react-native run-android or similar commands to use the inner react-native cli instead of the proxy cli. Due to new issues with react-native 0.60.x unexpected behavior unrelated to the lib may happen, please inform me of those issues 95 | 96 | # Contributing 97 | No particular rules enforced for now, open issues and make PRs to be reviewed 98 | 99 | 100 | # Special thanks 101 | - @EdoAPP 102 | - Dan Kurfirst -------------------------------------------------------------------------------- /example/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /example/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native-community', 4 | }; 5 | -------------------------------------------------------------------------------- /example/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | {
31 | state: BaseState = {
32 | value: null,
33 | }
34 |
35 | componentDidMount() {
36 | const {
37 | value = null,
38 | baseValue = null,
39 | field: { options },
40 | } = this.props
41 | // If the component has no value, we have to report the initial value, either the default or the base value provided
42 | if (isValueUnset(value)) {
43 | if (baseValue && !isValueUnset(baseValue.value)) this.onBaseChange(baseValue.value)
44 | else if (options && !isValueUnset(options.default)) this.onBaseChange(options.default)
45 | }
46 | }
47 |
48 | componentDidUpdate(prevProps: BaseProps) {
49 | const {
50 | value = null,
51 | baseValue = null,
52 | field: { options },
53 | } = this.props
54 | const { previousBase = null } = prevProps
55 | // If the component has no value, we have to report the initial value, either the default or the base value provided
56 | if (isValueUnset(value)) {
57 | if (baseValue && !isValueUnset(baseValue.value)) this.onBaseChange(baseValue.value)
58 | else if (options && !isValueUnset(options.default)) this.onBaseChange(options.default)
59 | } else if (
60 | value &&
61 | baseValue &&
62 | !isValueUnset(baseValue.value) &&
63 | previousBase &&
64 | !isValueUnset(previousBase.value)
65 | ) {
66 | // If the component does have a value but a base value has been inserted, update with the new base
67 | this.onBaseChange(baseValue.value)
68 | }
69 | }
70 |
71 | onBaseChange = (value) => {
72 | const { onChange } = this.props
73 | if (onChange) onChange(value)
74 | }
75 |
76 | render() {
77 | return null
78 | }
79 | }
80 |
81 | export default Component
82 |
--------------------------------------------------------------------------------
/src/components/FormComponents/Connected/ConnectedSelect.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { View, Text } from 'react-native'
3 | import uuid from 'uuid/v4'
4 | import { connectedComponentStyles } from '../../../styles'
5 | import Select from './Select'
6 |
7 | type Props = {
8 | onChange: () => any,
9 | value: any,
10 | field: any,
11 | buttonHandler: () => any,
12 | currentFormValue: any,
13 | allFields: any,
14 | component: any,
15 | header: string,
16 | dataElement: {
17 | text: string,
18 | value: Array
37 | case types.multipleSelect:
38 | return