├── .babelrc ├── .eslintrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── UPGRADE.md ├── doc-engine ├── README.md ├── package.json ├── scripts │ └── start.js ├── src │ ├── App.css │ ├── App.js │ ├── client.js │ ├── comps │ │ ├── default-theme.js │ │ ├── layouts │ │ │ ├── github.svg │ │ │ └── layouts.js │ │ ├── recipes │ │ │ ├── custom-button-text.js │ │ │ ├── dynamic-fields.js │ │ │ ├── form-controlled.js │ │ │ ├── form-uncontrolled.js │ │ │ ├── multiple-submit-inline.js │ │ │ ├── multiple-submit-theme.js │ │ │ ├── required-with-stars.js │ │ │ ├── submit-on-blur.js │ │ │ ├── wrapinput-custom-datepicker.js │ │ │ ├── wrapinput-react-belle-date-picker.js │ │ │ ├── wrapinput-react-bootstrap-daterangepicker.js │ │ │ ├── wrapinput-react-date-picker.js │ │ │ └── wrapinput-react-datepicker.js │ │ ├── style-rules.js │ │ └── styles.js │ ├── favicon.ico │ ├── generate-html.js │ ├── index.html │ ├── lib │ │ ├── polyfill.js │ │ └── scroll.js │ ├── pages │ │ ├── 404.js │ │ ├── Docs.js │ │ ├── GettingStarted.js │ │ ├── Home.js │ │ ├── Recipes.js │ │ └── docs │ │ │ ├── Form.js │ │ │ ├── Optional.js │ │ │ ├── ReformContext.js │ │ │ ├── Themes.js │ │ │ ├── Validations.js │ │ │ └── WrapInput.js │ ├── reta.css │ └── routes.js ├── web_loaders │ ├── md-loader.js │ └── routes-loader.js ├── webpack.config.base.js ├── webpack.config.dev.js ├── webpack.config.prod-client.js └── webpack.config.prod-server.js ├── docs ├── 404 │ └── index.html ├── 1-54941.chunk.js ├── 1-54941.chunk.js.map ├── 10-1087e.chunk.js ├── 10-1087e.chunk.js.map ├── 11-773bf.chunk.js ├── 11-773bf.chunk.js.map ├── 2-c3661.chunk.js ├── 2-c3661.chunk.js.map ├── 3-81f00.chunk.js ├── 3-81f00.chunk.js.map ├── 4-2c9da.chunk.js ├── 4-2c9da.chunk.js.map ├── 5-e67b0.chunk.js ├── 5-e67b0.chunk.js.map ├── 6-19c86.chunk.js ├── 6-19c86.chunk.js.map ├── 7-7e1c9.chunk.js ├── 7-7e1c9.chunk.js.map ├── 8-efa67.chunk.js ├── 8-efa67.chunk.js.map ├── 9-0c3df.chunk.js ├── 9-0c3df.chunk.js.map ├── CNAME ├── docs │ ├── form │ │ └── index.html │ ├── index.html │ ├── optional │ │ └── index.html │ ├── reform-context │ │ └── index.html │ ├── themes │ │ └── index.html │ ├── validations │ │ └── index.html │ └── wrap-input │ │ └── index.html ├── favicon.ico ├── getting-started │ └── index.html ├── index.html ├── main-c7aa6340fa99b23562d9228eb3a22f82.css ├── main-c7aa6340fa99b23562d9228eb3a22f82.css.map ├── main-d8084.js ├── main-d8084.js.map └── recipes │ └── index.html ├── package.json ├── samples ├── index.html.ejs ├── index.js ├── package.json └── webpack.config.js └── src ├── Form.js ├── ReformContext.js ├── WrapInput.js ├── __tests__ ├── __snapshots__ │ └── basic_test.js.snap ├── basic_test.js └── ssr_test.js ├── createTheme.js ├── index.js └── opt ├── inputs.js └── validations.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react-app" 4 | ], 5 | "plugins": [ 6 | "babel-plugin-dev-expression" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "react-app", 3 | "rules": { 4 | "semi": ["warn", "never"], 5 | "quotes": ["warn", "single"], 6 | "no-cond-assign": ["error", "except-parens"], 7 | "import/no-webpack-loader-syntax": 0 8 | }, 9 | "globals": { 10 | "__DEV__": true, 11 | "__SERVERRENDER__": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | node_modules/ 3 | *.sublime-* 4 | /core/ 5 | /opt/ 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .eslintrc 3 | .babelrc 4 | src/ 5 | samples/ 6 | docs/ 7 | doc-engine/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" 4 | - "4" 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.1.1 4 | 5 | - adding test suite 6 | - fix [#17](https://github.com/codecks-io/react-reform/issues/13): SSR now works without throwing errors. 7 | - ensure unmounted fields properly de-register from their form 8 | 9 | ## 1.1.0 10 | 11 | Validations within wrapped inputs now support camelCase. This is also the recommended way of doing things and the docs have been changed accordingly. See [#13](https://github.com/codecks-io/react-reform/issues/13). 12 | 13 | **old** 14 | ``` 15 | 16 | ``` 17 | 18 | **new** 19 | ``` 20 | 21 | ``` 22 | 23 | The old way is still supported but might get deprecated at some point. 24 | 25 | ## 1.0.0 26 | 27 | Too much to list here. Make sure to check out [the docs](http://react-reform.codecks.io/docs/) and the [UPGRADE.md](./UPGRADE.md) 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > **Deprecated** 2 | > 3 | > This library is no longer maintained and used within Codecks. We recommend taking a look at [formik](https://github.com/jaredpalmer/formik) as a very capable alternative. 4 | 5 | # React Reform 6 | 7 | Helps you create powerful themes for pleasant to use forms 8 | 9 | ## Why? 10 | 11 | Read [this post](https://www.codecks.io/blog/2017/introducing-react-reform/) to get behind some of the reasoning. 12 | 13 | ## Getting Started/Docs 14 | 15 | **[http://react-reform.codecks.io](http://react-reform.codecks.io)** 16 | 17 | ### What's the status of this project? 18 | 19 | This library is being used and actively developed alongside [www.codecks.io](https://www.codecks.io/). There's been quite some API changes before v1.0 but we arrived at a very happy place right now. 20 | 21 | ## Contribute 22 | 23 | - clone the repo 24 | - `npm install && cd samples && npm install` 25 | - for running the sample project: `cd samples && npm run dev` and open `http://localhost:8080/` 26 | - run `npm test` or `npm run test-watch` for test 27 | 28 | The docs are generated via the [doc-engine](./doc-engine). So please look here if you would like to update the docs. 29 | 30 | ## License 31 | 32 | ISC 33 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | # 0.5 -> 1.0 2 | 3 | First off the good news: The whole React Reform experiences is now much more rounded. Also: existing your `
`'s don't need to be updated. But probably everything else. 4 | 5 | Let's have a look at the details: 6 | 7 | ## ReformContext 8 | 9 | Rather than registering themes and validations in some global module, you now need to use ReformContext. [Check out the docs](http://react-reform.codecks.io/docs/reform-context/) for more details. 10 | 11 | ## Creating themes 12 | 13 | For creating themes you now have to use the `createTheme(themeObj)` method. You probably don't have to change too much. You need to replace the old `[fieldDescription]` component by `children` and the `fieldDescription` now gets its place under the `renderField` key within the `themeObj`. The docs explain all [the details](http://react-reform.codecks.io/docs/themes/). 14 | 15 | ## Wrapping inputs 16 | 17 | Got a lot more powerful and explicit. There's a [`simpleInputWrapper`](./src/opt/inputs.js) that almost looks like the old `wrapInput`. Have a look at this and [the docs](http://react-reform.codecks.io/docs/wrap-input/) to see how to migrate your code 18 | 19 | ## Validations vs validators 20 | 21 | Instead of `validators` we're now more consistently using `validations` everywhere. This also means that you need to do `import defaultValidations from 'react-reform/opt/validations'` to import the default validations. 22 | 23 | ## Form methods 24 | 25 | If you were calling `validate()` on the ``'s reference. You now need to call `checkForErrors()`. 26 | -------------------------------------------------------------------------------- /doc-engine/README.md: -------------------------------------------------------------------------------- 1 | # Doc Engine 2 | 3 | Custom-made and quite powerful static site generator based on the very helpful [static-site-generator-webpack-plugin](https://github.com/markdalgleish/static-site-generator-webpack-plugin). 4 | 5 | ## Features 6 | 7 | - inlining minimal necessary css for each page 8 | - very meaningful first paint after downloading the html (page would works without downloading any js) 9 | - after loading the js file, [react-router](https://github.com/ReactTraining/react-router) takes over the routing 10 | - automatic code splitting for all the routes 11 | - to create a new page, just add a new file inside the `src/pages` folder 12 | - nice dev experience: auto reload page when file changed 13 | 14 | At some point this engine probably will be setup as a separate repo. 15 | 16 | ## Start hacking on the docs 17 | 18 | ``` 19 | npm install 20 | npm start 21 | ``` 22 | 23 | ## Generate docs 24 | 25 | ``` 26 | npm run build 27 | ``` 28 | -------------------------------------------------------------------------------- /doc-engine/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-reform-doc-engine", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node scripts/start.js", 7 | "build": "rm -rf ../docs && webpack --config webpack.config.prod-client.js && webpack --config webpack.config.prod-server.js && rm ../docs/generate-html-* ../docs/webpack-assets.json && echo \"react-reform.codecks.io\\n\" > ../docs/CNAME" 8 | }, 9 | "devDependencies": { 10 | "assets-webpack-plugin": "^3.5.0", 11 | "babel-loader": "^6.2.5", 12 | "chalk": "^1.1.3", 13 | "commonmark": "^0.26.0", 14 | "connect-history-api-fallback": "^1.3.0", 15 | "css-loader": "^0.25.0", 16 | "extract-text-webpack-plugin": "^1.0.1", 17 | "file-loader": "^0.9.0", 18 | "front-matter": "^2.1.0", 19 | "glob": "^7.1.0", 20 | "html-loader": "^0.4.4", 21 | "html-webpack-plugin": "^2.22.0", 22 | "loader-utils": "^0.2.16", 23 | "purify-css": "^1.1.9", 24 | "raw-loader": "^0.5.1", 25 | "react-dev-utils": "^0.2.1", 26 | "static-site-generator-webpack-plugin": "^3.0.0", 27 | "style-loader": "^0.13.1", 28 | "svg-inline-loader": "^0.7.1", 29 | "webpack": "^1.13.2", 30 | "webpack-dev-server": "^1.16.1", 31 | "webpack-directory-name-as-main": "^1.0.0" 32 | }, 33 | "dependencies": { 34 | "belle": "^3.0.0", 35 | "normalize.css": "^5.0.0", 36 | "prismjs": "^1.6.0", 37 | "react": "^15.3.2", 38 | "react-bootstrap-daterangepicker": "^3.2.2", 39 | "react-date-picker": "^5.3.28", 40 | "react-datepicker": "^0.39.0", 41 | "react-dom": "^15.3.2", 42 | "react-router": "^3.0.0", 43 | "react-router-scroll": "^0.3.3", 44 | "reta": "^0.3.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /doc-engine/scripts/start.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'development' 2 | 3 | var chalk = require('chalk') 4 | var webpack = require('webpack') 5 | var WebpackDevServer = require('webpack-dev-server') 6 | 7 | var clearConsole = require('react-dev-utils/clearConsole') 8 | var formatWebpackMessages = require('react-dev-utils/formatWebpackMessages') 9 | var openBrowser = require('react-dev-utils/openBrowser') 10 | var historyApiFallback = require('connect-history-api-fallback') 11 | 12 | var config = require('../webpack.config.dev') 13 | 14 | var compiler 15 | var handleCompile 16 | 17 | function setupCompiler(host, port, protocol) { 18 | compiler = webpack(config, handleCompile) 19 | 20 | compiler.plugin('invalid', function() { 21 | clearConsole() 22 | console.log('Compiling...') 23 | }) 24 | 25 | compiler.plugin('done', function(stats) { 26 | clearConsole() 27 | 28 | // We have switched off the default Webpack output in WebpackDevServer 29 | // options so we are going to "massage" the warnings and errors and present 30 | // them in a readable focused way. 31 | var messages = formatWebpackMessages(stats.toJson({}, true)) 32 | if (!messages.errors.length && !messages.warnings.length) { 33 | console.log(chalk.green('Compiled successfully!')) 34 | console.log() 35 | console.log('The app is running at:') 36 | console.log() 37 | console.log(' ' + chalk.cyan(protocol + '://' + host + ':' + port + '/')) 38 | console.log() 39 | console.log('Note that the development build is not optimized.') 40 | console.log('To create a production build, use ' + chalk.cyan('npm run build') + '.') 41 | console.log() 42 | } 43 | 44 | // If errors exist, only show errors. 45 | if (messages.errors.length) { 46 | console.log(chalk.red('Failed to compile.')) 47 | console.log() 48 | messages.errors.forEach(message => { 49 | console.log(message) 50 | console.log() 51 | }) 52 | return 53 | } 54 | 55 | // Show warnings if no errors were found. 56 | if (messages.warnings.length) { 57 | console.log(chalk.yellow('Compiled with warnings.')) 58 | console.log() 59 | messages.warnings.forEach(message => { 60 | console.log(message) 61 | console.log() 62 | }) 63 | // Teach some ESLint tricks. 64 | console.log('You may use special comments to disable some warnings.') 65 | console.log('Use ' + chalk.yellow('// eslint-disable-next-line') + ' to ignore the next line.') 66 | console.log('Use ' + chalk.yellow('/* eslint-disable */') + ' to ignore all warnings in a file.') 67 | } 68 | }) 69 | } 70 | 71 | function addMiddleware(devServer) { 72 | devServer.use(historyApiFallback({disableDotRule: true})) 73 | devServer.use(devServer.middleware) 74 | } 75 | 76 | function runDevServer(host, port, protocol) { 77 | var devServer = new WebpackDevServer(compiler, { 78 | clientLogLevel: 'none', 79 | hot: true, 80 | publicPath: config.output.publicPath, 81 | quiet: true, 82 | watchOptions: { 83 | ignored: /node_modules/ 84 | }, 85 | // Enable HTTPS if the HTTPS environment variable is set to "true" 86 | https: protocol === 'https', 87 | host: host 88 | }) 89 | 90 | // Our custom middleware proxies requests to /index.html or a remote API. 91 | addMiddleware(devServer) 92 | 93 | // Launch WebpackDevServer. 94 | devServer.listen(port, (err, result) => { 95 | if (err) { 96 | return console.log(err) 97 | } 98 | 99 | clearConsole() 100 | console.log(chalk.cyan('Starting the development server...')) 101 | console.log() 102 | openBrowser(protocol + '://' + host + ':' + port + '/') 103 | }) 104 | } 105 | 106 | function run(port) { 107 | var protocol = process.env.HTTPS === 'true' ? 'https' : 'http' 108 | var host = process.env.HOST || 'localhost' 109 | setupCompiler(host, port, protocol) 110 | runDevServer(host, port, protocol) 111 | } 112 | 113 | // Tools like Cloud9 rely on this. 114 | var DEFAULT_PORT = process.env.PORT || 3000 115 | run(DEFAULT_PORT) 116 | -------------------------------------------------------------------------------- /doc-engine/src/App.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | transition-duration: .15s; 4 | transition-timing-function: ease-out; 5 | } 6 | 7 | *, *:before, *:after { 8 | box-sizing: inherit; 9 | transition-duration: inherit; 10 | transition-timing-function: inherit; 11 | transition-property: none; 12 | } 13 | 14 | body { 15 | font-family: -apple-system, BlinkMacSystemFont, 16 | "Segoe UI", "Roboto", "Oxygen", 17 | "Ubuntu", "Cantarell", "Fira Sans", 18 | "Droid Sans", "Helvetica Neue", sans-serif; 19 | } 20 | 21 | a { 22 | color: inherit; 23 | text-decoration: none; 24 | } 25 | 26 | h1, h2, h3, h4, h5, h6, p, ul, ol, pre { 27 | margin: 0; padding: 0; 28 | } 29 | 30 | .github-icon svg { 31 | width: 18px; 32 | height: 18px; 33 | fill: currentColor; 34 | position: relative; 35 | top: 3px; 36 | } 37 | 38 | /* fixing bootstrap dependency of react-bootstrap-daterangepicker */ 39 | 40 | .dropdown-menu { 41 | display: none; 42 | } -------------------------------------------------------------------------------- /doc-engine/src/App.js: -------------------------------------------------------------------------------- 1 | import 'lib/polyfill' 2 | import React from 'react' 3 | import {StyleProvider} from 'reta' 4 | import PropTypes from 'prop-types' 5 | 6 | import 'normalize.css/normalize.css' 7 | import './App.css' 8 | 9 | export default class App extends React.Component { 10 | 11 | static childContextTypes = { 12 | appInfo: PropTypes.object 13 | } 14 | 15 | getChildContext() { 16 | return { 17 | appInfo: { 18 | routes: this.props.allRoutes, 19 | isServerRender: this.props.isServerRender 20 | } 21 | } 22 | } 23 | 24 | render() { 25 | return ( 26 | 27 | {this.props.children} 28 | 29 | ) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /doc-engine/src/client.js: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom' 2 | import getRoutes from './routes' 3 | import 'reta.css' 4 | 5 | const appEl = window.document.getElementById('app') 6 | 7 | ReactDOM.render(getRoutes(false, require('routes!pages/Home')), appEl) 8 | -------------------------------------------------------------------------------- /doc-engine/src/comps/default-theme.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {createTheme} from 'react-reform' 3 | 4 | export default createTheme({ 5 | renderForm: (FormContainer, children, {directProps}) => ( 6 | 7 |
{children}
8 | 9 |
10 | ), 11 | renderField: (Field, {directProps: {label, ...remainingDirectProps}, name, validations, id}) => { 12 | const errors = validations 13 | .filter(({isValid}) => isValid === false) 14 | .map(({errorMessage, name}) => {errorMessage} ) 15 | return ( 16 |
17 | 18 | 19 | {errors.length > 0 && {errors}} 20 |
21 | ) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /doc-engine/src/comps/layouts/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc-engine/src/comps/layouts/layouts.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import B from 'comps/styles' 4 | import {Link as RRLink} from 'react-router' 5 | import {scrollToNode} from 'lib/scroll' 6 | import PropTypes from 'prop-types' 7 | 8 | export const md = (num) => `(max-width: ${num}px)` 9 | 10 | export const RawButton = ({onClick, to, href, disabled, type = to || href ? undefined : 'button', props, ...rest}) => ( 11 | 12 | ) 13 | export const PlainLink = ({href, to, target, props, nofollow, ...rest}) => ( 14 | 15 | ) 16 | export const Link = (props) => ( 17 | 18 | ) 19 | 20 | export const BigButton = (props) => ( 21 | 22 | ) 23 | 24 | export const Input = (props) => ( 25 | 26 | ) 27 | 28 | export const Scaffold = ({children}) => ( 29 | 30 | 35 |