├── .babelrc ├── .eslintrc.js ├── .gitignore ├── README.md ├── bower.json ├── dist └── form-for.js ├── example ├── .babelrc ├── index.html ├── package.json ├── server.js ├── src │ └── app.jsx └── webpack.config.js ├── lib ├── checkbox-input.js ├── color-input.js ├── date-input.js ├── datetime-input.js ├── email-input.js ├── form-errors.js ├── form-for.js ├── hidden-input.js ├── input.js ├── label.js ├── number-input.js ├── options-for-select.js ├── password-input.js ├── select-input.js ├── text-input.js ├── textarea-input.js └── time-input.js ├── package.json ├── src ├── checkbox-input.jsx ├── color-input.jsx ├── date-input.jsx ├── datetime-input.jsx ├── email-input.jsx ├── form-errors.jsx ├── form-for.jsx ├── hidden-input.jsx ├── input.jsx ├── label.jsx ├── number-input.jsx ├── options-for-select.jsx ├── password-input.jsx ├── select-input.jsx ├── text-input.jsx ├── textarea-input.jsx └── time-input.jsx ├── test ├── form-for-test.js └── input-test.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-3", "react"], 3 | "plugins": [ 4 | "transform-decorators-legacy" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "parser": "babel-eslint", 3 | "extends": "airbnb", 4 | "plugins": [ 5 | "react", 6 | "mocha" 7 | ], 8 | "rules": { 9 | "mocha/no-exclusive-tests": "error" 10 | }, 11 | "env": { 12 | "jquery": true 13 | }, 14 | "ecmaFeatures": { 15 | "experimentalDecorators": true, 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## React Form For Object 2 | 3 | No-effort, simple ReactJS form builder for Javascript objects. 4 | 5 | Simply pass FormFor a javascript object and it will display the form and handle 6 | data for you. You can always override defaults by passing FormFor options. 7 | 8 | There is a full working example [here](./example) 9 | 10 | ### Install 11 | ```bash 12 | npm install react-form-for-object 13 | ``` 14 | 15 | OR 16 | 17 | ```bash 18 | bower install react-form-for-object 19 | ``` 20 | 21 | ### Usage 22 | FormFor will determine the type of input based on the your object. We do our best 23 | to detect the type of the input you're looking for. However, some things are harder to detect such as textarea. We give you the option to override them in the options by passing a type (see example below). 24 | 25 | Supply a submit handler with onSubmit key in the options. On submit, FormFor will pass all of the form data to the callback you provided. 26 | 27 | Supply a cancel handler with onCancel key in the options. If you don't want a cancel button, 28 | simply don't supply an onCancel handler. 29 | 30 | FormFor will display all errors supplied to it in the errors prop. 31 | 32 | If we can't successfully detect the type of value from an object attribute, we default 33 | to text input. 34 | 35 | By default, id attributes are built as hidden input. 36 | 37 | ```javascript 38 | import FormFor from 'react-form-for-object'; 39 | 40 | const todo = { 41 | name: "Clean my room", 42 | description: "My room needs some serious cleaning", 43 | completed: false, 44 | list: "Home", 45 | }; 46 | 47 | const inputOptions = { 48 | labels: true, // by default we use placeholders, but you can turn on labels and we will use both. 49 | description: { type: 'textarea' }, 50 | list: { type: 'select', values: [{value:"Home", show: "Home"}, {value:"Work", show: "Work"}] }, 51 | }; 52 | 53 | console.log(data) } 57 | onCancel={ (data) => console.log(data) } 58 | /> 59 | 60 | ``` 61 | #### How to use the options 62 | Each attribute on your object can have its own options/overrides. In your option object, 63 | use the name of the attribute as the key (see example above). Currently you can supply the following options: 64 | 65 | - type: 'textarea', 'select' (please see supported inputs below). Please keep in mind that you don't have to supply any options for FormFor to work, only supply them to override what we give you 66 | based on your object attributes. 67 | - className 68 | - value 69 | - labels: turned off by default. 70 | - placeholder: we use the name of the field, you can override that (this also affects label, if labels are turned on). 71 | 72 | ### Labels 73 | You can pass a labels: true attribute in the form options. We will then use 74 | the input placeholder (if you specified it in the options) or input name as the label. 75 | 76 | ### Input support 77 | 78 | - text 79 | - checkbox 80 | - number 81 | - hidden 82 | - select 83 | - password 84 | - textarea 85 | - date 86 | - datetime 87 | - email 88 | - submit 89 | - color 90 | 91 | ## Examples 92 | A working example can be found [here](./example) 93 | 94 | ## TODO 95 | - file 96 | - image 97 | - month 98 | - radio 99 | - range 100 | - reset 101 | - search 102 | - tel 103 | - url 104 | - week 105 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-form-for-object", 3 | "version": "1.1.0", 4 | "authors": [ 5 | "Ed Shadi " 6 | ], 7 | "description": "Rails inspired form builder that makes building forms in React a breeze.", 8 | "main": "dist/form-for.js", 9 | "keywords": [ 10 | "react", 11 | "addon", 12 | "form", 13 | "rails", 14 | "flux" 15 | ], 16 | "license": "MIT", 17 | "private": false, 18 | "ignore": [ 19 | "**/.*", 20 | "node_modules", 21 | "bower_components", 22 | "app/bower_components", 23 | "test", 24 | "tests", 25 | "node_modules" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /dist/form-for.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) 10 | /******/ return installedModules[moduleId].exports; 11 | 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ exports: {}, 15 | /******/ id: moduleId, 16 | /******/ loaded: false 17 | /******/ }; 18 | 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | 22 | /******/ // Flag the module as loaded 23 | /******/ module.loaded = true; 24 | 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | 29 | 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | 36 | /******/ // __webpack_public_path__ 37 | /******/ __webpack_require__.p = ""; 38 | 39 | /******/ // Load entry module and return exports 40 | /******/ return __webpack_require__(0); 41 | /******/ }) 42 | /************************************************************************/ 43 | /******/ ([ 44 | /* 0 */ 45 | /***/ function(module, exports) { 46 | 47 | 'use strict'; 48 | 49 | Object.defineProperty(exports, "__esModule", { 50 | value: true 51 | }); 52 | exports.default = undefined; 53 | 54 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 55 | 56 | var _react = require('react'); 57 | 58 | var _react2 = _interopRequireDefault(_react); 59 | 60 | var _input = require('./input'); 61 | 62 | var _input2 = _interopRequireDefault(_input); 63 | 64 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 65 | 66 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 67 | 68 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 69 | 70 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 71 | 72 | var FormFor = function (_React$Component) { 73 | _inherits(FormFor, _React$Component); 74 | 75 | function FormFor(props) { 76 | _classCallCheck(this, FormFor); 77 | 78 | var _this = _possibleConstructorReturn(this, (FormFor.__proto__ || Object.getPrototypeOf(FormFor)).call(this, props)); 79 | 80 | _this.state = { 81 | inputs: Object.keys(props.object).reduce(function (data, key) { 82 | data[key] = props.object[key]; 83 | return data; 84 | }, {}) 85 | }; 86 | _this.setInput = _this.setInput.bind(_this); 87 | _this.handleSubmit = _this.handleSubmit.bind(_this); 88 | return _this; 89 | } 90 | 91 | _createClass(FormFor, [{ 92 | key: 'setInput', 93 | value: function setInput(e) { 94 | e.preventDefault(); 95 | var inputs = this.state.inputs; 96 | var _e$target = e.target, 97 | type = _e$target.type, 98 | name = _e$target.name, 99 | checked = _e$target.checked, 100 | value = _e$target.value; 101 | 102 | 103 | inputs[name] = type === 'checkbox' ? checked : value; 104 | 105 | this.setState(inputs); 106 | } 107 | }, { 108 | key: 'handleSubmit', 109 | value: function handleSubmit(e) { 110 | if (e) e.preventDefault(); 111 | this.props.onSubmit(this.state.inputs); 112 | } 113 | }, { 114 | key: 'inputs', 115 | value: function inputs() { 116 | var _this2 = this; 117 | 118 | var object = this.props.object; 119 | var inputs = []; 120 | Object.keys(object).forEach(function (key) { 121 | var value = _this2.state.inputs[key]; 122 | var dataForInput = { 123 | value: value === undefined ? '' : _this2.state.inputs[key], 124 | name: key 125 | }; 126 | var options = _this2.props.inputOptions[key] || {}; 127 | inputs.push(_react2.default.createElement(_input2.default, { 128 | key: key, 129 | data: dataForInput, 130 | options: options, 131 | label: _this2.props.inputOptions.labels, 132 | onChange: _this2.setInput 133 | })); 134 | }); 135 | return inputs; 136 | } 137 | }, { 138 | key: 'submitText', 139 | value: function submitText() { 140 | var _props = this.props, 141 | submitValue = _props.submitValue, 142 | objectName = _props.objectName; 143 | 144 | var text = this.props.object.id ? 'Update' : 'Create'; 145 | if (submitValue) text = submitValue; 146 | if (objectName) text = text + ' ' + objectName; 147 | return text; 148 | } 149 | }, { 150 | key: 'renderCancelButton', 151 | value: function renderCancelButton() { 152 | var button = void 0; 153 | if (this.props.onCancel) button = _react2.default.createElement('input', { type: 'button', value: 'Cancel' }); 154 | return button; 155 | } 156 | }, { 157 | key: 'render', 158 | value: function render() { 159 | return _react2.default.createElement( 160 | 'form', 161 | { onSubmit: this.handleSubmit, className: 'form-for' }, 162 | this.inputs(), 163 | _react2.default.createElement('input', { type: 'submit', value: this.submitText() }), 164 | this.renderCancelButton() 165 | ); 166 | } 167 | }]); 168 | 169 | return FormFor; 170 | }(_react2.default.Component); 171 | 172 | exports.default = FormFor; 173 | 174 | 175 | FormFor.propTypes = { 176 | object: _react.PropTypes.object.isRequired, 177 | onCancel: _react.PropTypes.func, 178 | onSubmit: _react.PropTypes.func.isRequired, 179 | submitValue: _react.PropTypes.string, 180 | objectName: _react.PropTypes.string, 181 | inputOptions: _react.PropTypes.object 182 | }; 183 | 184 | FormFor.defaultProps = { 185 | onSubmit: function onSubmit(data) { 186 | return console.log(data); 187 | }, 188 | object: {}, 189 | inputOptions: {} 190 | }; 191 | 192 | /***/ } 193 | /******/ ]); -------------------------------------------------------------------------------- /example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-3", "react"], 3 | "plugins": [ 4 | "transform-decorators-legacy" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-form-for-object-example", 3 | "version": "2.0.0", 4 | "description": "Working example for react-form-for-object package", 5 | "main": "dist/app.js", 6 | "scripts": { 7 | "start": "node server.js" 8 | }, 9 | "devDependencies": { 10 | "babel": "^6.5.2", 11 | "babel-core": "^6.8.0", 12 | "babel-eslint": "^6.0.4", 13 | "babel-loader": "^6.2.4", 14 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 15 | "babel-preset-es2015": "^6.6.0", 16 | "babel-preset-react": "^6.5.0", 17 | "babel-preset-stage-3": "^6.17.0", 18 | "css-loader": "^0.25.0", 19 | "eslint": "^2.10.2", 20 | "eslint-config-airbnb": "^9.0.1", 21 | "eslint-plugin-import": "^1.8.1", 22 | "eslint-plugin-jsx-a11y": "^1.2.2", 23 | "eslint-plugin-react": "^5.1.1", 24 | "file-loader": "^0.9.0", 25 | "node-sass": "^3.10.1", 26 | "path": "^0.11.14", 27 | "react-hot-loader": "^1.2.7", 28 | "reactotron-react-js": "^1.1.3", 29 | "sass-loader": "^4.0.2", 30 | "style-loader": "^0.13.1", 31 | "url-loader": "^0.5.7", 32 | "webpack": "^1.13.2", 33 | "webpack-dashboard": "^0.1.8", 34 | "webpack-dev-server": "^1.16.2", 35 | "webpack-notifier": "^1.2.1" 36 | }, 37 | "author": "Ed Shadi ", 38 | "license": "ISC", 39 | "dependencies": { 40 | "react": "^15.4.2", 41 | "react-dom": "^15.4.2", 42 | "react-form-for-object": "file:///Users/apprentice/Development/Github/opensource/react-form-for-object" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /example/server.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | const webpack = require('webpack'); 3 | const WebpackDevServer = require('webpack-dev-server'); 4 | 5 | const config = require('./webpack.config'); 6 | 7 | new WebpackDevServer(webpack(config), { 8 | publicPath: config.output.publicPath, 9 | hot: true, 10 | stats: { 11 | colors: true, 12 | }, 13 | }).listen(3000, '0.0.0.0', (err) => { 14 | if (err) { 15 | console.error(err); 16 | return; 17 | } 18 | console.log('Listening at 0.0.0.0:3000'); 19 | }); 20 | -------------------------------------------------------------------------------- /example/src/app.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDom from 'react-dom'; 3 | import FormFor from 'react-form-for-object'; 4 | 5 | const TodoStore = { 6 | all() { 7 | return [{ 8 | id: 1, // this will be hidden field by default. 9 | name: 'Clean my room', 10 | description: 'My room needs some serious cleaning', 11 | priority: 3, 12 | createAt: '2014-10-09', 13 | completed: true, 14 | password: 'sweet todo', 15 | list: 'Home', 16 | email: 'myemail@gmail.com', 17 | color: '#fc5803', 18 | }]; 19 | }, 20 | new() { 21 | return { 22 | name: null, 23 | description: null, 24 | priority: null, 25 | createAt: null, 26 | completed: false, 27 | password: null, 28 | list: null, 29 | email: null, 30 | color: null, 31 | }; 32 | }, 33 | 34 | find(index) { 35 | return this.all()[index]; 36 | }, 37 | }; 38 | 39 | class App extends React.Component { 40 | constructor(props) { 41 | super(props); 42 | this.state = { 43 | errors: [], 44 | alert: undefined, 45 | }; 46 | this.handleSubmit = this.handleSubmit.bind(this); 47 | } 48 | 49 | handleSubmit(data) { 50 | // this is where you call an action, e.g. TodoActions.createTodo. For this example 51 | // I will just simulate errors and success here. 52 | if (data.name === "") return this.setState({errors: ["name can't be blank"]}); 53 | console.log(data); 54 | return this.setState({alert: "Success!", errors: []}); 55 | } 56 | 57 | handleCancel() { 58 | console.log('cancelling'); 59 | } 60 | 61 | render() { 62 | const inputOptions = { 63 | // Uncomment that if you want to display labels for the fields, it's off by default 64 | labels: false, 65 | description: { type: 'textarea' }, 66 | createAt: { type: 'date' }, 67 | list: { 68 | type: 'select', values: [ 69 | { value: 'Home', label: 'Home' }, 70 | { value: 'Work', label: 'Work' }, 71 | ], 72 | }, 73 | color: { type: 'color' }, 74 | due: { type: 'datetime' }, 75 | }; 76 | return ( 77 |
78 | {this.state.alert} 79 |

Create

80 | 85 |

Update

86 | 93 |
94 | ); 95 | } 96 | } 97 | 98 | ReactDom.render( 99 | , 100 | document.getElementById('app') 101 | ); 102 | -------------------------------------------------------------------------------- /example/webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var path = require('path'); 3 | var nodeModulesDir = path.join(__dirname, 'node_modules'); 4 | var WebpackNotifierPlugin = require('webpack-notifier'); 5 | 6 | require("babel-preset-es2015") 7 | require("babel-preset-react") 8 | 9 | var config = { 10 | entry: { 11 | app: './src/app.jsx' 12 | }, 13 | output: { 14 | path: path.join(__dirname, 'dist'), 15 | publicPath: '/js/', 16 | filename: '[name].js', 17 | }, 18 | resolve: { 19 | extensions: ['', '.js', '.json', '.jsx'] 20 | }, 21 | plugins: [ 22 | new WebpackNotifierPlugin() 23 | ], 24 | devtool: 'eval', 25 | module: { 26 | noParse: [], 27 | loaders: [ 28 | { 29 | test: /\.jsx$|\.js$/, 30 | loader: 'babel', 31 | exclude: [nodeModulesDir] 32 | }, 33 | { test: /\.css$/, loader: "style-loader!css-loader" }, 34 | { test: /\.png$/, loader: "url-loader?limit=100000" }, 35 | { test: /\.jpg$/, loader: "file-loader" } 36 | ] 37 | } 38 | }; 39 | 40 | module.exports = config; 41 | -------------------------------------------------------------------------------- /lib/checkbox-input.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = CheckboxInput; 7 | 8 | var _react = require("react"); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function CheckboxInput(props) { 15 | var _props$data = props.data, 16 | name = _props$data.name, 17 | value = _props$data.value; 18 | 19 | 20 | return _react2.default.createElement("input", { 21 | name: name, 22 | type: "checkbox", 23 | checked: value, 24 | onChange: props.onChange, 25 | className: props.options.className 26 | }); 27 | } 28 | 29 | CheckboxInput.propTypes = { 30 | data: _react.PropTypes.object.isRequired, 31 | options: _react.PropTypes.object, 32 | onChange: _react.PropTypes.func.isRequired 33 | }; 34 | 35 | CheckboxInput.defaultProps = { 36 | data: {}, 37 | options: {} 38 | }; -------------------------------------------------------------------------------- /lib/color-input.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = ColorInput; 7 | 8 | var _react = require("react"); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function ColorInput(props) { 15 | var _props$data = props.data, 16 | name = _props$data.name, 17 | value = _props$data.value; 18 | 19 | return _react2.default.createElement("input", { 20 | name: name, 21 | type: "color", 22 | value: value, 23 | className: props.options.className, 24 | onChange: props.onChange 25 | }); 26 | } 27 | 28 | ColorInput.propTypes = { 29 | data: _react.PropTypes.object.isRequired, 30 | options: _react.PropTypes.object, 31 | onChange: _react.PropTypes.func.isRequired 32 | }; 33 | 34 | ColorInput.defaultProps = { 35 | data: {}, 36 | options: {} 37 | }; -------------------------------------------------------------------------------- /lib/date-input.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = DateInput; 7 | 8 | var _react = require("react"); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function DateInput(props) { 15 | var _props$options = props.options, 16 | placeholder = _props$options.placeholder, 17 | className = _props$options.className; 18 | var _props$data = props.data, 19 | value = _props$data.value, 20 | name = _props$data.name; 21 | 22 | return _react2.default.createElement("input", { 23 | type: "date", 24 | name: name, 25 | value: value, 26 | placeholder: placeholder, 27 | className: className, 28 | onChange: props.onChange 29 | }); 30 | } 31 | 32 | DateInput.propTypes = { 33 | data: _react.PropTypes.object.isRequired, 34 | options: _react.PropTypes.object, 35 | onChange: _react.PropTypes.func.isRequired 36 | }; 37 | 38 | DateInput.defaultProps = { 39 | data: {}, 40 | options: {} 41 | }; -------------------------------------------------------------------------------- /lib/datetime-input.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = DatetimeInput; 7 | 8 | var _react = require("react"); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function DatetimeInput(props) { 15 | var _props$data = props.data, 16 | name = _props$data.name, 17 | value = _props$data.value; 18 | 19 | return _react2.default.createElement("input", { 20 | type: "datetime-local", 21 | name: name, 22 | value: value, 23 | className: props.options.className, 24 | onChange: props.onChange 25 | }); 26 | } 27 | 28 | DatetimeInput.propTypes = { 29 | data: _react.PropTypes.object.isRequired, 30 | options: _react.PropTypes.object, 31 | onChange: _react.PropTypes.func.isRequired 32 | }; 33 | 34 | DatetimeInput.defaultProps = { 35 | data: {}, 36 | options: {} 37 | }; -------------------------------------------------------------------------------- /lib/email-input.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = EmailInput; 7 | 8 | var _react = require("react"); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function EmailInput(props) { 15 | var _props$options = props.options, 16 | placeholder = _props$options.placeholder, 17 | className = _props$options.className; 18 | var _props$data = props.data, 19 | name = _props$data.name, 20 | value = _props$data.value; 21 | 22 | return _react2.default.createElement("input", { 23 | type: "email", 24 | name: name, 25 | value: value, 26 | placeholder: placeholder, 27 | className: className, 28 | onChange: props.onChange 29 | }); 30 | } 31 | 32 | EmailInput.propTypes = { 33 | data: _react.PropTypes.object.isRequired, 34 | options: _react.PropTypes.object, 35 | onChange: _react.PropTypes.func.isRequired 36 | }; 37 | 38 | EmailInput.defaultProps = { 39 | data: {}, 40 | options: {} 41 | }; -------------------------------------------------------------------------------- /lib/form-errors.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = FormErrors; 7 | 8 | var _react = require("react"); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function FormErrors(props) { 15 | var errors = props.errors.map(function (err) { 16 | return _react2.default.createElement( 17 | "li", 18 | null, 19 | err 20 | ); 21 | }); 22 | return _react2.default.createElement( 23 | "ul", 24 | { className: "form-errors" }, 25 | errors 26 | ); 27 | } 28 | 29 | FormErrors.propTypes = { 30 | errors: _react.PropTypes.array 31 | }; 32 | 33 | FormErrors.defaultProps = { 34 | errors: [] 35 | }; -------------------------------------------------------------------------------- /lib/form-for.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = undefined; 7 | 8 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 9 | 10 | var _react = require('react'); 11 | 12 | var _react2 = _interopRequireDefault(_react); 13 | 14 | var _input = require('./input'); 15 | 16 | var _input2 = _interopRequireDefault(_input); 17 | 18 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 19 | 20 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 21 | 22 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 23 | 24 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 25 | 26 | var FormFor = function (_React$Component) { 27 | _inherits(FormFor, _React$Component); 28 | 29 | function FormFor(props) { 30 | _classCallCheck(this, FormFor); 31 | 32 | var _this = _possibleConstructorReturn(this, (FormFor.__proto__ || Object.getPrototypeOf(FormFor)).call(this, props)); 33 | 34 | _this.state = { 35 | inputs: Object.keys(props.object).reduce(function (data, key) { 36 | data[key] = props.object[key]; 37 | return data; 38 | }, {}) 39 | }; 40 | _this.setInput = _this.setInput.bind(_this); 41 | _this.handleSubmit = _this.handleSubmit.bind(_this); 42 | return _this; 43 | } 44 | 45 | _createClass(FormFor, [{ 46 | key: 'setInput', 47 | value: function setInput(e) { 48 | e.preventDefault(); 49 | var inputs = this.state.inputs; 50 | var _e$target = e.target, 51 | type = _e$target.type, 52 | name = _e$target.name, 53 | checked = _e$target.checked, 54 | value = _e$target.value; 55 | 56 | 57 | inputs[name] = type === 'checkbox' ? checked : value; 58 | 59 | this.setState(inputs); 60 | } 61 | }, { 62 | key: 'handleSubmit', 63 | value: function handleSubmit(e) { 64 | if (e) e.preventDefault(); 65 | this.props.onSubmit(this.state.inputs); 66 | } 67 | }, { 68 | key: 'inputs', 69 | value: function inputs() { 70 | var _this2 = this; 71 | 72 | var object = this.props.object; 73 | var inputs = []; 74 | Object.keys(object).forEach(function (key) { 75 | var value = _this2.state.inputs[key]; 76 | var dataForInput = { 77 | value: value === undefined ? '' : _this2.state.inputs[key], 78 | name: key 79 | }; 80 | var options = _this2.props.inputOptions[key] || {}; 81 | inputs.push(_react2.default.createElement(_input2.default, { 82 | key: key, 83 | data: dataForInput, 84 | options: options, 85 | label: _this2.props.inputOptions.labels, 86 | onChange: _this2.setInput 87 | })); 88 | }); 89 | return inputs; 90 | } 91 | }, { 92 | key: 'submitText', 93 | value: function submitText() { 94 | var _props = this.props, 95 | submitValue = _props.submitValue, 96 | objectName = _props.objectName; 97 | 98 | var text = this.props.object.id ? 'Update' : 'Create'; 99 | if (submitValue) text = submitValue; 100 | if (objectName) text = text + ' ' + objectName; 101 | return text; 102 | } 103 | }, { 104 | key: 'renderCancelButton', 105 | value: function renderCancelButton() { 106 | var button = void 0; 107 | if (this.props.onCancel) button = _react2.default.createElement('input', { type: 'button', value: 'Cancel' }); 108 | return button; 109 | } 110 | }, { 111 | key: 'render', 112 | value: function render() { 113 | return _react2.default.createElement( 114 | 'form', 115 | { onSubmit: this.handleSubmit, className: 'form-for' }, 116 | this.inputs(), 117 | _react2.default.createElement('input', { type: 'submit', value: this.submitText() }), 118 | this.renderCancelButton() 119 | ); 120 | } 121 | }]); 122 | 123 | return FormFor; 124 | }(_react2.default.Component); 125 | 126 | exports.default = FormFor; 127 | 128 | 129 | FormFor.propTypes = { 130 | object: _react.PropTypes.object.isRequired, 131 | onCancel: _react.PropTypes.func, 132 | onSubmit: _react.PropTypes.func.isRequired, 133 | submitValue: _react.PropTypes.string, 134 | objectName: _react.PropTypes.string, 135 | inputOptions: _react.PropTypes.object 136 | }; 137 | 138 | FormFor.defaultProps = { 139 | onSubmit: function onSubmit(data) { 140 | return console.log(data); 141 | }, 142 | object: {}, 143 | inputOptions: {} 144 | }; -------------------------------------------------------------------------------- /lib/hidden-input.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = HiddenInput; 7 | 8 | var _react = require("react"); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function HiddenInput(props) { 15 | var _props$data = props.data, 16 | name = _props$data.name, 17 | value = _props$data.value; 18 | 19 | 20 | return _react2.default.createElement("input", { 21 | type: "hidden", 22 | name: name, 23 | value: value, 24 | className: props.options.className, 25 | onChange: props.onChange 26 | }); 27 | } 28 | 29 | HiddenInput.propTypes = { 30 | data: _react.PropTypes.object.isRequired, 31 | options: _react.PropTypes.object, 32 | onChange: _react.PropTypes.func.isRequired 33 | }; 34 | 35 | HiddenInput.defaultProps = { 36 | data: {}, 37 | options: {} 38 | }; -------------------------------------------------------------------------------- /lib/input.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = undefined; 7 | 8 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 9 | 10 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 11 | 12 | var _react = require('react'); 13 | 14 | var _react2 = _interopRequireDefault(_react); 15 | 16 | var _textInput = require('./text-input'); 17 | 18 | var _textInput2 = _interopRequireDefault(_textInput); 19 | 20 | var _checkboxInput = require('./checkbox-input'); 21 | 22 | var _checkboxInput2 = _interopRequireDefault(_checkboxInput); 23 | 24 | var _numberInput = require('./number-input'); 25 | 26 | var _numberInput2 = _interopRequireDefault(_numberInput); 27 | 28 | var _hiddenInput = require('./hidden-input'); 29 | 30 | var _hiddenInput2 = _interopRequireDefault(_hiddenInput); 31 | 32 | var _selectInput = require('./select-input'); 33 | 34 | var _selectInput2 = _interopRequireDefault(_selectInput); 35 | 36 | var _passwordInput = require('./password-input'); 37 | 38 | var _passwordInput2 = _interopRequireDefault(_passwordInput); 39 | 40 | var _textareaInput = require('./textarea-input'); 41 | 42 | var _textareaInput2 = _interopRequireDefault(_textareaInput); 43 | 44 | var _dateInput = require('./date-input'); 45 | 46 | var _dateInput2 = _interopRequireDefault(_dateInput); 47 | 48 | var _colorInput = require('./color-input'); 49 | 50 | var _colorInput2 = _interopRequireDefault(_colorInput); 51 | 52 | var _datetimeInput = require('./datetime-input'); 53 | 54 | var _datetimeInput2 = _interopRequireDefault(_datetimeInput); 55 | 56 | var _emailInput = require('./email-input'); 57 | 58 | var _emailInput2 = _interopRequireDefault(_emailInput); 59 | 60 | var _timeInput = require('./time-input'); 61 | 62 | var _timeInput2 = _interopRequireDefault(_timeInput); 63 | 64 | var _label = require('./label'); 65 | 66 | var _label2 = _interopRequireDefault(_label); 67 | 68 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 69 | 70 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 71 | 72 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 73 | 74 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 75 | 76 | var Input = function (_React$Component) { 77 | _inherits(Input, _React$Component); 78 | 79 | function Input() { 80 | _classCallCheck(this, Input); 81 | 82 | return _possibleConstructorReturn(this, (Input.__proto__ || Object.getPrototypeOf(Input)).apply(this, arguments)); 83 | } 84 | 85 | _createClass(Input, [{ 86 | key: 'label', 87 | value: function label() { 88 | var label = void 0; 89 | if (this.props.label) label = _react2.default.createElement(_label2.default, { label: this.placeholder() }); 90 | return label; 91 | } 92 | }, { 93 | key: 'input', 94 | value: function input() { 95 | var _props = this.props, 96 | data = _props.data, 97 | options = _props.options; 98 | 99 | options.placeholder = this.placeholder(); 100 | var input = void 0; 101 | switch (this.type()) { 102 | case 'boolean': 103 | input = _react2.default.createElement( 104 | 'span', 105 | null, 106 | _react2.default.createElement(_checkboxInput2.default, { onChange: this.props.onChange, data: data, options: options }), 107 | _react2.default.createElement( 108 | 'span', 109 | null, 110 | this.placeholder() 111 | ) 112 | ); 113 | break; 114 | case 'number': 115 | input = _react2.default.createElement(_numberInput2.default, { onChange: this.props.onChange, data: data, options: options }); 116 | break; 117 | case 'color': 118 | input = _react2.default.createElement(_colorInput2.default, { onChange: this.props.onChange, data: data, options: options }); 119 | break; 120 | case 'email': 121 | input = _react2.default.createElement(_emailInput2.default, { onChange: this.props.onChange, data: data, options: options }); 122 | break; 123 | case 'date': 124 | input = _react2.default.createElement(_dateInput2.default, { onChange: this.props.onChange, data: data, options: options }); 125 | break; 126 | case 'datetime': 127 | input = _react2.default.createElement(_datetimeInput2.default, { onChange: this.props.onChange, data: data, options: options }); 128 | break; 129 | case 'time': 130 | input = _react2.default.createElement(_timeInput2.default, { onChange: this.props.onChange, data: data, options: options }); 131 | break; 132 | case 'hidden': 133 | input = _react2.default.createElement(_hiddenInput2.default, { onChange: this.props.onChange, data: data, options: options }); 134 | break; 135 | case 'select': 136 | input = _react2.default.createElement(_selectInput2.default, { onChange: this.props.onChange, data: data, options: options }); 137 | break; 138 | case 'password': 139 | input = _react2.default.createElement(_passwordInput2.default, { onChange: this.props.onChange, data: data, options: options }); 140 | break; 141 | case 'textarea': 142 | input = _react2.default.createElement(_textareaInput2.default, { onChange: this.props.onChange, data: data, options: options }); 143 | break; 144 | default: 145 | input = _react2.default.createElement(_textInput2.default, { onChange: this.props.onChange, data: data, options: options }); 146 | } 147 | return input; 148 | } 149 | }, { 150 | key: 'type', 151 | value: function type() { 152 | var type = _typeof(this.props.data.value); 153 | if (this.props.options.type) type = this.props.options.type; 154 | if (this.isId()) type = 'hidden'; 155 | if (this.isPassword()) type = 'password'; 156 | if (this.isEmail()) type = 'email'; 157 | // console.log('data', this.props.data.value) 158 | // console.log('type', type) 159 | return type; 160 | } 161 | }, { 162 | key: 'isId', 163 | value: function isId() { 164 | return this.props.data.name === 'id'; 165 | } 166 | }, { 167 | key: 'isPassword', 168 | value: function isPassword() { 169 | return this.props.data.name === 'password' || this.props.data.name === 'password_confirmation'; 170 | } 171 | }, { 172 | key: 'isEmail', 173 | value: function isEmail() { 174 | 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,}))$/; 175 | return this.props.data.name === 'email' || re.test(this.props.data.value); 176 | } 177 | }, { 178 | key: 'placeholder', 179 | value: function placeholder() { 180 | var name = this.props.options.placeholder || this.props.data.name; 181 | return name.charAt(0).toUpperCase() + name.slice(1); 182 | } 183 | }, { 184 | key: 'render', 185 | value: function render() { 186 | return _react2.default.createElement( 187 | 'div', 188 | null, 189 | _react2.default.createElement( 190 | 'div', 191 | { className: 'form-group' }, 192 | this.label(), 193 | this.input() 194 | ) 195 | ); 196 | } 197 | }]); 198 | 199 | return Input; 200 | }(_react2.default.Component); 201 | 202 | exports.default = Input; 203 | 204 | 205 | Input.propTypes = { 206 | data: _react.PropTypes.object.isRequired, 207 | options: _react.PropTypes.object, 208 | label: _react.PropTypes.bool, 209 | onChange: _react.PropTypes.func.isRequired 210 | }; 211 | 212 | Input.defaultProps = { 213 | data: {}, 214 | options: {}, 215 | label: false 216 | }; -------------------------------------------------------------------------------- /lib/label.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = Label; 7 | 8 | var _react = require("react"); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function Label(props) { 15 | return _react2.default.createElement( 16 | "label", 17 | { className: "form-for-label" }, 18 | props.label 19 | ); 20 | } 21 | 22 | Label.propTypes = { 23 | label: _react.PropTypes.string.isRequired, 24 | options: _react.PropTypes.object 25 | }; 26 | 27 | Label.defaultProps = { 28 | options: {} 29 | }; -------------------------------------------------------------------------------- /lib/number-input.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = NumberInput; 7 | 8 | var _react = require("react"); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function NumberInput(props) { 15 | var _props$options = props.options, 16 | placeholder = _props$options.placeholder, 17 | className = _props$options.className; 18 | var _props$data = props.data, 19 | name = _props$data.name, 20 | value = _props$data.value; 21 | 22 | 23 | return _react2.default.createElement("input", { 24 | type: "number", 25 | name: name, 26 | value: value, 27 | placeholder: placeholder, 28 | className: className, 29 | onChange: props.onChange 30 | }); 31 | } 32 | 33 | NumberInput.propTypes = { 34 | data: _react.PropTypes.object.isRequired, 35 | options: _react.PropTypes.object, 36 | onChange: _react.PropTypes.func.isRequired 37 | }; 38 | 39 | NumberInput.defaultProps = { 40 | data: {}, 41 | options: {} 42 | }; -------------------------------------------------------------------------------- /lib/options-for-select.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = OptionForSelect; 7 | 8 | var _react = require('react'); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function OptionForSelect(props) { 15 | return _react2.default.createElement( 16 | 'option', 17 | { value: props.value }, 18 | props.label 19 | ); 20 | } 21 | 22 | OptionForSelect.propTypes = { 23 | label: _react.PropTypes.string.isRequired, 24 | value: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]).isRequired, 25 | options: _react.PropTypes.object 26 | }; 27 | 28 | OptionForSelect.defaultProps = { 29 | options: {} 30 | }; -------------------------------------------------------------------------------- /lib/password-input.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = PasswordInput; 7 | 8 | var _react = require("react"); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function PasswordInput(props) { 15 | var _props$options = props.options, 16 | placeholder = _props$options.placeholder, 17 | className = _props$options.className; 18 | var _props$data = props.data, 19 | name = _props$data.name, 20 | value = _props$data.value; 21 | 22 | 23 | return _react2.default.createElement("input", { 24 | type: "password", 25 | name: name, 26 | value: value, 27 | placeholder: placeholder, 28 | className: className, 29 | onChange: props.onChange 30 | }); 31 | } 32 | 33 | PasswordInput.propTypes = { 34 | data: _react.PropTypes.object.isRequired, 35 | options: _react.PropTypes.object, 36 | onChange: _react.PropTypes.func.isRequired 37 | }; 38 | 39 | PasswordInput.defaultProps = { 40 | data: {}, 41 | options: {} 42 | }; -------------------------------------------------------------------------------- /lib/select-input.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = SelectInput; 7 | 8 | var _react = require('react'); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | var _optionsForSelect = require('./options-for-select'); 13 | 14 | var _optionsForSelect2 = _interopRequireDefault(_optionsForSelect); 15 | 16 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 17 | 18 | function SelectInput(props) { 19 | var _props$data = props.data, 20 | name = _props$data.name, 21 | value = _props$data.value, 22 | id = _props$data.id; 23 | 24 | var options = props.options.values.map(function (v) { 25 | return _react2.default.createElement(_optionsForSelect2.default, { key: v.value, value: v.value, label: v.label }); 26 | }); 27 | return _react2.default.createElement( 28 | 'select', 29 | { 30 | name: name, 31 | value: value, 32 | className: props.options.className, 33 | id: id, 34 | onChange: props.onChange 35 | }, 36 | options 37 | ); 38 | } 39 | 40 | SelectInput.propTypes = { 41 | data: _react.PropTypes.object.isRequired, 42 | options: _react.PropTypes.object, 43 | onChange: _react.PropTypes.func.isRequired 44 | }; 45 | 46 | SelectInput.defaultProps = { 47 | data: {}, 48 | options: { 49 | values: [] 50 | } 51 | }; -------------------------------------------------------------------------------- /lib/text-input.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = TextInput; 7 | 8 | var _react = require("react"); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function TextInput(props) { 15 | var _props$options = props.options, 16 | placeholder = _props$options.placeholder, 17 | className = _props$options.className; 18 | var _props$data = props.data, 19 | name = _props$data.name, 20 | value = _props$data.value; 21 | 22 | return _react2.default.createElement("input", { 23 | type: "text", 24 | name: name, 25 | value: value, 26 | placeholder: placeholder, 27 | className: className, 28 | onChange: props.onChange 29 | }); 30 | } 31 | 32 | TextInput.propTypes = { 33 | data: _react.PropTypes.object.isRequired, 34 | options: _react.PropTypes.object, 35 | onChange: _react.PropTypes.func.isRequired 36 | }; 37 | 38 | TextInput.defaultProps = { 39 | data: {}, 40 | options: {} 41 | }; -------------------------------------------------------------------------------- /lib/textarea-input.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = TextareaInput; 7 | 8 | var _react = require('react'); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function TextareaInput(props) { 15 | var _props$options = props.options, 16 | placeholder = _props$options.placeholder, 17 | className = _props$options.className; 18 | var _props$data = props.data, 19 | name = _props$data.name, 20 | value = _props$data.value; 21 | 22 | 23 | return _react2.default.createElement('textarea', { 24 | name: name, 25 | value: value, 26 | placeholder: placeholder, 27 | className: className, 28 | onChange: props.onChange 29 | }); 30 | } 31 | 32 | TextareaInput.propTypes = { 33 | data: _react.PropTypes.object.isRequired, 34 | options: _react.PropTypes.object, 35 | onChange: _react.PropTypes.func.isRequired 36 | }; 37 | 38 | TextareaInput.defaultProps = { 39 | data: {}, 40 | options: {} 41 | }; -------------------------------------------------------------------------------- /lib/time-input.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = TimeInput; 7 | 8 | var _react = require("react"); 9 | 10 | var _react2 = _interopRequireDefault(_react); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function TimeInput(props) { 15 | var _props$options = props.options, 16 | placeholder = _props$options.placeholder, 17 | className = _props$options.className; 18 | var _props$data = props.data, 19 | name = _props$data.name, 20 | value = _props$data.value; 21 | 22 | 23 | return _react2.default.createElement("input", { 24 | type: "time", 25 | name: name, 26 | value: value, 27 | placeholder: placeholder, 28 | className: className, 29 | onChange: props.onChange 30 | }); 31 | } 32 | 33 | TimeInput.propTypes = { 34 | data: _react.PropTypes.object.isRequired, 35 | options: _react.PropTypes.object, 36 | onChange: _react.PropTypes.func.isRequired 37 | }; 38 | 39 | TimeInput.defaultProps = { 40 | data: {}, 41 | options: {} 42 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-form-for-object", 3 | "description": "Simple ReactJS form builder for Javascript objects", 4 | "repository": { 5 | "type": "git", 6 | "url": "git+https://github.com/edshadi/react-form-for-object.git" 7 | }, 8 | "scripts": { 9 | "build": "babel ./src/ -d ./lib/", 10 | "test": "mocha --require babel-register", 11 | "prepublish": "npm run build && webpack" 12 | }, 13 | "devDependencies": { 14 | "babel": "^6.5.2", 15 | "babel-cli": "^6.23.0", 16 | "babel-core": "^6.8.0", 17 | "babel-eslint": "^6.0.4", 18 | "babel-loader": "^6.2.4", 19 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 20 | "babel-preset-es2015": "^6.6.0", 21 | "babel-preset-react": "^6.5.0", 22 | "babel-preset-stage-3": "^6.17.0", 23 | "babel-register": "^6.23.0", 24 | "chai": "^3.5.0", 25 | "chai-enzyme": "^0.6.1", 26 | "css-loader": "^0.25.0", 27 | "enzyme": "^2.7.1", 28 | "eslint": "^2.10.2", 29 | "eslint-config-airbnb": "^9.0.1", 30 | "eslint-plugin-import": "^1.8.1", 31 | "eslint-plugin-jsx-a11y": "^1.2.2", 32 | "eslint-plugin-mocha": "^4.8.0", 33 | "eslint-plugin-react": "^5.1.1", 34 | "file-loader": "^0.9.0", 35 | "fs": "0.0.1-security", 36 | "mocha": "^3.2.0", 37 | "node-sass": "^3.10.1", 38 | "path": "^0.11.14", 39 | "react-addons-test-utils": "^15.4.2", 40 | "react-hot-loader": "^1.2.7", 41 | "reactotron-react-js": "^1.1.3", 42 | "sass-loader": "^4.0.2", 43 | "sinon": "^1.17.7", 44 | "style-loader": "^0.13.1", 45 | "url-loader": "^0.5.7", 46 | "webpack": "^1.13.2", 47 | "webpack-dashboard": "^0.1.8", 48 | "webpack-dev-server": "^1.9.0", 49 | "webpack-notifier": "^1.2.1" 50 | }, 51 | "bugs": { 52 | "url": "https://github.com/edshadi/react-form-for-object/issues" 53 | }, 54 | "homepage": "https://github.com/edshadi/react-form-for-object#readme", 55 | "version": "2.0.1", 56 | "main": "lib/form-for.js", 57 | "directories": { 58 | "example": "example" 59 | }, 60 | "author": "Ed Shadi ", 61 | "license": "ISC", 62 | "dependencies": { 63 | "react": "^15.4.2", 64 | "react-dom": "^15.4.2" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/checkbox-input.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | 3 | export default function CheckboxInput(props) { 4 | const { name, value } = props.data; 5 | 6 | return ( 7 | 14 | ); 15 | } 16 | 17 | CheckboxInput.propTypes = { 18 | data: PropTypes.object.isRequired, 19 | options: PropTypes.object, 20 | onChange: PropTypes.func.isRequired, 21 | }; 22 | 23 | CheckboxInput.defaultProps = { 24 | data: {}, 25 | options: {}, 26 | }; 27 | -------------------------------------------------------------------------------- /src/color-input.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | 3 | export default function ColorInput(props) { 4 | const { name, value } = props.data; 5 | return ( 6 | 13 | ); 14 | } 15 | 16 | ColorInput.propTypes = { 17 | data: PropTypes.object.isRequired, 18 | options: PropTypes.object, 19 | onChange: PropTypes.func.isRequired, 20 | }; 21 | 22 | ColorInput.defaultProps = { 23 | data: {}, 24 | options: {}, 25 | }; 26 | -------------------------------------------------------------------------------- /src/date-input.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | 3 | export default function DateInput(props) { 4 | const { placeholder, className } = props.options; 5 | const { value, name } = props.data; 6 | return ( 7 | 15 | ); 16 | } 17 | 18 | DateInput.propTypes = { 19 | data: PropTypes.object.isRequired, 20 | options: PropTypes.object, 21 | onChange: PropTypes.func.isRequired, 22 | }; 23 | 24 | DateInput.defaultProps = { 25 | data: {}, 26 | options: {}, 27 | }; 28 | -------------------------------------------------------------------------------- /src/datetime-input.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | 3 | export default function DatetimeInput(props) { 4 | const { name, value } = props.data; 5 | return ( 6 | 13 | ); 14 | } 15 | 16 | DatetimeInput.propTypes = { 17 | data: PropTypes.object.isRequired, 18 | options: PropTypes.object, 19 | onChange: PropTypes.func.isRequired, 20 | }; 21 | 22 | DatetimeInput.defaultProps = { 23 | data: {}, 24 | options: {}, 25 | }; 26 | -------------------------------------------------------------------------------- /src/email-input.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | 3 | export default function EmailInput(props) { 4 | const { placeholder, className } = props.options; 5 | const { name, value } = props.data; 6 | return ( 7 | 15 | ); 16 | } 17 | 18 | EmailInput.propTypes = { 19 | data: PropTypes.object.isRequired, 20 | options: PropTypes.object, 21 | onChange: PropTypes.func.isRequired, 22 | }; 23 | 24 | EmailInput.defaultProps = { 25 | data: {}, 26 | options: {}, 27 | }; 28 | -------------------------------------------------------------------------------- /src/form-errors.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | 3 | export default function FormErrors(props) { 4 | const errors = props.errors.map(err =>
  • {err}
  • ); 5 | return ( 6 |
      {errors}
    7 | ); 8 | } 9 | 10 | FormErrors.propTypes = { 11 | errors: PropTypes.array, 12 | }; 13 | 14 | FormErrors.defaultProps = { 15 | errors: [], 16 | }; 17 | -------------------------------------------------------------------------------- /src/form-for.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import Input from './input'; 3 | 4 | export default class FormFor extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | inputs: Object.keys(props.object).reduce((data, key) => { 9 | data[key] = props.object[key]; 10 | return data; 11 | }, {}), 12 | }; 13 | this.setInput = this.setInput.bind(this); 14 | this.handleSubmit = this.handleSubmit.bind(this); 15 | } 16 | 17 | setInput(e) { 18 | e.preventDefault(); 19 | const inputs = this.state.inputs; 20 | const { type, name, checked, value } = e.target; 21 | 22 | inputs[name] = type === 'checkbox' ? checked : value; 23 | 24 | this.setState(inputs); 25 | } 26 | 27 | handleSubmit(e) { 28 | if (e) e.preventDefault(); 29 | this.props.onSubmit(this.state.inputs); 30 | } 31 | 32 | inputs() { 33 | const object = this.props.object; 34 | const inputs = []; 35 | Object.keys(object).forEach((key) => { 36 | const value = this.state.inputs[key]; 37 | const dataForInput = { 38 | value: value === undefined ? '' : this.state.inputs[key], 39 | name: key, 40 | }; 41 | const options = this.props.inputOptions[key] || {}; 42 | inputs.push( 43 | 50 | ); 51 | }); 52 | return inputs; 53 | } 54 | 55 | submitText() { 56 | const { submitValue, objectName } = this.props; 57 | let text = this.props.object.id ? 'Update' : 'Create'; 58 | if (submitValue) text = submitValue; 59 | if (objectName) text = `${text} ${objectName}`; 60 | return text; 61 | } 62 | 63 | renderCancelButton() { 64 | let button; 65 | if (this.props.onCancel) button = ; 66 | return button; 67 | } 68 | 69 | render() { 70 | return ( 71 |
    72 | {this.inputs()} 73 | 74 | {this.renderCancelButton()} 75 |
    76 | ); 77 | } 78 | 79 | } 80 | 81 | FormFor.propTypes = { 82 | object: PropTypes.object.isRequired, 83 | onCancel: PropTypes.func, 84 | onSubmit: PropTypes.func.isRequired, 85 | submitValue: PropTypes.string, 86 | objectName: PropTypes.string, 87 | inputOptions: PropTypes.object, 88 | }; 89 | 90 | FormFor.defaultProps = { 91 | onSubmit: (data) => console.log(data), 92 | object: {}, 93 | inputOptions: {}, 94 | }; 95 | -------------------------------------------------------------------------------- /src/hidden-input.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | 3 | export default function HiddenInput(props) { 4 | const { name, value } = props.data; 5 | 6 | return ( 7 | 14 | ); 15 | } 16 | 17 | HiddenInput.propTypes = { 18 | data: PropTypes.object.isRequired, 19 | options: PropTypes.object, 20 | onChange: PropTypes.func.isRequired, 21 | }; 22 | 23 | HiddenInput.defaultProps = { 24 | data: {}, 25 | options: {}, 26 | }; 27 | -------------------------------------------------------------------------------- /src/input.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import TextInput from './text-input'; 3 | import CheckboxInput from './checkbox-input'; 4 | import NumberInput from './number-input'; 5 | import HiddenInput from './hidden-input'; 6 | import SelectInput from './select-input'; 7 | import PasswordInput from './password-input'; 8 | import TextareaInput from './textarea-input'; 9 | import DateInput from './date-input'; 10 | import ColorInput from './color-input'; 11 | import DatetimeInput from './datetime-input'; 12 | import EmailInput from './email-input'; 13 | import TimeInput from './time-input'; 14 | import Label from './label'; 15 | 16 | export default class Input extends React.Component { 17 | label() { 18 | let label; 19 | if (this.props.label) label =