diff --git a/docs/wrapper.js b/docs/wrapper.js
index 24ad313..11935e2 100644
--- a/docs/wrapper.js
+++ b/docs/wrapper.js
@@ -1,9 +1,21 @@
import React, { Component } from 'react';
+import { createGlobalStyle } from 'styled-components';
import { ThemeProvider } from '../src';
+const GlobalStyle = createGlobalStyle `
+ * {
+ box-sizing: border-box;
+ }
+`
+
class App extends Component {
render() {
- return {this.props.children};
+ return (
+ <>
+
+ {this.props.children}
+ >
+ );
}
}
diff --git a/package-lock.json b/package-lock.json
index 5dbf42e..1cd828b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3463,7 +3463,7 @@
},
"chalk": {
"version": "1.1.3",
- "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
@@ -3504,7 +3504,7 @@
"dependencies": {
"@babel/code-frame": {
"version": "7.0.0-beta.44",
- "resolved": "http://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz",
"integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==",
"dev": true,
"requires": {
@@ -3513,7 +3513,7 @@
},
"@babel/generator": {
"version": "7.0.0-beta.44",
- "resolved": "http://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz",
"integrity": "sha512-5xVb7hlhjGcdkKpMXgicAVgx8syK5VJz193k0i/0sLP6DzE6lRrU1K3B/rFefgdo9LPGMAOOOAWW4jycj07ShQ==",
"dev": true,
"requires": {
@@ -3526,7 +3526,7 @@
},
"@babel/helper-function-name": {
"version": "7.0.0-beta.44",
- "resolved": "http://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz",
"integrity": "sha512-MHRG2qZMKMFaBavX0LWpfZ2e+hLloT++N7rfM3DYOMUOGCD8cVjqZpwiL8a0bOX3IYcQev1ruciT0gdFFRTxzg==",
"dev": true,
"requires": {
@@ -3537,7 +3537,7 @@
},
"@babel/helper-get-function-arity": {
"version": "7.0.0-beta.44",
- "resolved": "http://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz",
"integrity": "sha512-w0YjWVwrM2HwP6/H3sEgrSQdkCaxppqFeJtAnB23pRiJB5E/O9Yp7JAAeWBl+gGEgmBFinnTyOv2RN7rcSmMiw==",
"dev": true,
"requires": {
@@ -3546,7 +3546,7 @@
},
"@babel/helper-split-export-declaration": {
"version": "7.0.0-beta.44",
- "resolved": "http://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz",
"integrity": "sha512-aQ7QowtkgKKzPGf0j6u77kBMdUFVBKNHw2p/3HX/POt5/oz8ec5cs0GwlgM8Hz7ui5EwJnzyfRmkNF1Nx1N7aA==",
"dev": true,
"requires": {
@@ -3555,7 +3555,7 @@
},
"@babel/highlight": {
"version": "7.0.0-beta.44",
- "resolved": "http://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz",
"integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==",
"dev": true,
"requires": {
@@ -3566,7 +3566,7 @@
},
"@babel/template": {
"version": "7.0.0-beta.44",
- "resolved": "http://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz",
"integrity": "sha512-w750Sloq0UNifLx1rUqwfbnC6uSUk0mfwwgGRfdLiaUzfAOiH0tHJE6ILQIUi3KYkjiCDTskoIsnfqZvWLBDng==",
"dev": true,
"requires": {
@@ -3578,7 +3578,7 @@
},
"@babel/traverse": {
"version": "7.0.0-beta.44",
- "resolved": "http://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz",
"integrity": "sha512-UHuDz8ukQkJCDASKHf+oDt3FVUzFd+QYfuBIsiNu/4+/ix6pP/C+uQZJ6K1oEfbCMv/IKWbgDEh7fcsnIE5AtA==",
"dev": true,
"requires": {
@@ -3596,7 +3596,7 @@
},
"@babel/types": {
"version": "7.0.0-beta.44",
- "resolved": "http://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz",
"integrity": "sha512-5eTV4WRmqbaFM3v9gHAIljEQJU4Ssc6fxL61JN+Oe2ga/BwyjzjamwkCVVAQjHGuAX8i0BWo42dshL8eO5KfLQ==",
"dev": true,
"requires": {
@@ -3607,7 +3607,7 @@
},
"babylon": {
"version": "7.0.0-beta.44",
- "resolved": "http://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz",
+ "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz",
"integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==",
"dev": true
},
@@ -8195,7 +8195,7 @@
},
"eslint": {
"version": "4.19.1",
- "resolved": "http://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz",
"integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==",
"dev": true,
"requires": {
@@ -8424,7 +8424,7 @@
},
"load-json-file": {
"version": "2.0.0",
- "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"dev": true,
"requires": {
@@ -8873,7 +8873,7 @@
},
"external-editor": {
"version": "2.2.0",
- "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
"dev": true,
"requires": {
@@ -9549,6 +9549,12 @@
"readable-stream": "^2.0.4"
}
},
+ "fn-name": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz",
+ "integrity": "sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=",
+ "dev": true
+ },
"follow-redirects": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz",
@@ -14822,7 +14828,8 @@
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
- "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+ "dev": true
},
"lodash._getnative": {
"version": "3.9.1",
@@ -16997,6 +17004,12 @@
}
}
},
+ "property-expr": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-1.5.1.tgz",
+ "integrity": "sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==",
+ "dev": true
+ },
"property-information": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/property-information/-/property-information-5.0.1.tgz",
@@ -17337,21 +17350,21 @@
"dev": true
},
"react": {
- "version": "16.8.2",
- "resolved": "https://registry.npmjs.org/react/-/react-16.8.2.tgz",
- "integrity": "sha512-aB2ctx9uQ9vo09HVknqv3DGRpI7OIGJhCx3Bt0QqoRluEjHSaObJl+nG12GDdYH6sTgE7YiPJ6ZUyMx9kICdXw==",
+ "version": "16.8.3",
+ "resolved": "https://registry.npmjs.org/react/-/react-16.8.3.tgz",
+ "integrity": "sha512-3UoSIsEq8yTJuSu0luO1QQWYbgGEILm+eJl2QN/VLDi7hL+EN18M3q3oVZwmVzzBJ3DkM7RMdRwBmZZ+b4IzSA==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
- "scheduler": "^0.13.2"
+ "scheduler": "^0.13.3"
},
"dependencies": {
"scheduler": {
- "version": "0.13.2",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.2.tgz",
- "integrity": "sha512-qK5P8tHS7vdEMCW5IPyt8v9MJOHqTrOUgPXib7tqm9vh834ibBX5BNhwkplX/0iOzHW5sXyluehYfS9yrkz9+w==",
+ "version": "0.13.3",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.3.tgz",
+ "integrity": "sha512-UxN5QRYWtpR1egNWzJcVLk8jlegxAugswQc984lD3kU7NuobsO37/sRfbpTdBjtnD5TBNFA2Q2oLV5+UmPSmEQ==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
@@ -17608,21 +17621,21 @@
}
},
"react-dom": {
- "version": "16.8.2",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.2.tgz",
- "integrity": "sha512-cPGfgFfwi+VCZjk73buu14pYkYBR1b/SRMSYqkLDdhSEHnSwcuYTPu6/Bh6ZphJFIk80XLvbSe2azfcRzNF+Xg==",
+ "version": "16.8.3",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.3.tgz",
+ "integrity": "sha512-ttMem9yJL4/lpItZAQ2NTFAbV7frotHk5DZEHXUOws2rMmrsvh1Na7ThGT0dTzUIl6pqTOi5tYREfL8AEna3lA==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
- "scheduler": "^0.13.2"
+ "scheduler": "^0.13.3"
},
"dependencies": {
"scheduler": {
- "version": "0.13.2",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.2.tgz",
- "integrity": "sha512-qK5P8tHS7vdEMCW5IPyt8v9MJOHqTrOUgPXib7tqm9vh834ibBX5BNhwkplX/0iOzHW5sXyluehYfS9yrkz9+w==",
+ "version": "0.13.3",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.3.tgz",
+ "integrity": "sha512-UxN5QRYWtpR1egNWzJcVLk8jlegxAugswQc984lD3kU7NuobsO37/sRfbpTdBjtnD5TBNFA2Q2oLV5+UmPSmEQ==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
@@ -18388,7 +18401,7 @@
},
"regexpp": {
"version": "1.1.0",
- "resolved": "http://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz",
"integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==",
"dev": true
},
@@ -20489,6 +20502,12 @@
"integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=",
"dev": true
},
+ "synchronous-promise": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.6.tgz",
+ "integrity": "sha512-TyOuWLwkmtPL49LHCX1caIwHjRzcVd62+GF6h8W/jHOeZUFHpnd2XJDVuUlaTaLPH1nuu2M69mfHr5XbQJnf/g==",
+ "dev": true
+ },
"table": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz",
@@ -20808,6 +20827,12 @@
}
}
},
+ "toposort": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
+ "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=",
+ "dev": true
+ },
"tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
@@ -22588,6 +22613,37 @@
"dev": true
}
}
+ },
+ "yup": {
+ "version": "0.26.10",
+ "resolved": "https://registry.npmjs.org/yup/-/yup-0.26.10.tgz",
+ "integrity": "sha512-keuNEbNSnsOTOuGCt3UJW69jDE3O4P+UHAakO7vSeFMnjaitcmlbij/a3oNb9g1Y1KvSKH/7O1R2PQ4m4TRylw==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "7.0.0",
+ "fn-name": "~2.0.1",
+ "lodash": "^4.17.10",
+ "property-expr": "^1.5.0",
+ "synchronous-promise": "^2.0.5",
+ "toposort": "^2.0.2"
+ },
+ "dependencies": {
+ "@babel/runtime": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz",
+ "integrity": "sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==",
+ "dev": true,
+ "requires": {
+ "regenerator-runtime": "^0.12.0"
+ }
+ },
+ "regenerator-runtime": {
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz",
+ "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==",
+ "dev": true
+ }
+ }
}
}
}
diff --git a/package.json b/package.json
index 4a3c100..ca0263a 100644
--- a/package.json
+++ b/package.json
@@ -28,7 +28,6 @@
"release": "standard-version && git push --follow-tags"
},
"dependencies": {
- "lodash": "^4.17.11",
"mitt": "^1.1.3",
"polished": "^2.0.0",
"popper.js": "^1.14.7",
@@ -63,8 +62,8 @@
"jest": "^24.1.0",
"jest-styled-components": "^6.3.1",
"npm-run-all": "^4.1.5",
- "react": "^16.8.2",
- "react-dom": "^16.8.2",
+ "react": "^16.8.3",
+ "react-dom": "^16.8.3",
"react-router-dom": "^4.2.2",
"react-test-renderer": "^16.8.2",
"rimraf": "^2.6.3",
@@ -73,7 +72,8 @@
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-filesize": "^6.0.1",
"standard-version": "^5.0.0",
- "styled-components": "^4.1.3"
+ "styled-components": "^4.1.3",
+ "yup": "^0.26.10"
},
"resolutions": {
"babel-core": "^7.0.0-bridge.0"
diff --git a/src/Form/Checkbox.js b/src/Form/Checkbox.js
index cf3a757..32a3736 100644
--- a/src/Form/Checkbox.js
+++ b/src/Form/Checkbox.js
@@ -4,6 +4,7 @@ import { css } from 'styled-components';
import Icon from '../Icon';
import FormError from '../Form/FormError';
import Flex from '../Flex';
+import { createEasyInput } from './EasyInput';
import { createComponent } from '../utils';
const CheckboxContainer = createComponent({
@@ -44,7 +45,7 @@ const StyledLabel = createComponent({
`,
});
-export default class Checkbox extends React.Component {
+class Checkbox extends React.Component {
static propTypes = {
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
@@ -148,3 +149,5 @@ export default class Checkbox extends React.Component {
);
}
}
+
+export default createEasyInput(Checkbox);
diff --git a/src/Form/CheckboxGroup.js b/src/Form/CheckboxGroup.js
index 3fcbf05..60e03b7 100644
--- a/src/Form/CheckboxGroup.js
+++ b/src/Form/CheckboxGroup.js
@@ -1,11 +1,12 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
+import Flex from '../Flex';
+import Box from '../Box';
import Checkbox from './Checkbox';
import FormError from './FormError';
-import Box from '../Box';
-import Flex from '../Flex';
+import { createEasyInput } from './EasyInput';
-export default class CheckboxGroup extends Component {
+class CheckboxGroup extends Component {
static propTypes = {
name: PropTypes.string.isRequired,
color: PropTypes.string,
@@ -22,6 +23,7 @@ export default class CheckboxGroup extends Component {
};
static defaultProps = {
+ defaultValue: [],
color: 'primary',
horizontal: false,
onChange() {},
@@ -90,3 +92,5 @@ export default class CheckboxGroup extends Component {
);
}
}
+
+export default createEasyInput(CheckboxGroup);
diff --git a/src/Form/EasyInput.js b/src/Form/EasyInput.js
new file mode 100644
index 0000000..582f5bc
--- /dev/null
+++ b/src/Form/EasyInput.js
@@ -0,0 +1,39 @@
+import React, { useContext } from 'react';
+import { Context } from './Formbot';
+
+/**
+ * useContext has some slight performance issues. Every update to context re-renders
+ * each subscribed component and there's currently no way to bail out of renders if the
+ * values we care about haven't changed. Below is a sufficient workaround below and redux maintainers are discussing here: https://github.com/facebook/react/issues/14110
+ */
+const PureInput = React.memo(({ Component, ...props }) => );
+
+function EasyInput({ name, Component, ...props }) {
+ const state = useContext(Context);
+
+ if (!state) {
+ return
+ }
+
+ const value = state.values[name];
+ const defaultValue = Component.defaultProps && Component.defaultProps.defaultValue !== undefined
+ ? Component.defaultProps.defaultValue
+ : '';
+
+ return (
+
+ );
+}
+
+export const createEasyInput = Component => props =>
+
+export default EasyInput;
diff --git a/src/Form/Fieldset.js b/src/Form/Fieldset.js
new file mode 100644
index 0000000..33740f7
--- /dev/null
+++ b/src/Form/Fieldset.js
@@ -0,0 +1,41 @@
+import React from 'react';
+import Box from '../Box';
+import styled, { css } from 'styled-components';
+import { createComponent } from '../utils';
+
+const Legend = createComponent({
+ name: 'Legend',
+ tag: 'legend',
+ style: ({
+ theme,
+ color = theme.colors.primary,
+ }) => css`
+ font-weight: 700;
+ margin-bottom: 1rem;
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.25px;
+ color: ${color};
+ `,
+});
+
+const Container = styled.fieldset`
+ border: 0;
+ padding: 0;
+ margin: 0;
+
+ * + & {
+ margin-top: 1.5rem;
+ }
+`;
+
+const Fieldset = ({ legend, children }) => (
+
+ {legend && }
+
+ {children}
+
+);
+
+export default Fieldset;
+
diff --git a/src/Form/Form.js b/src/Form/Form.js
new file mode 100644
index 0000000..66d728e
--- /dev/null
+++ b/src/Form/Form.js
@@ -0,0 +1,14 @@
+import React, { useContext } from 'react';
+import { Context } from './Formbot';
+
+function Form({ children, ...props }) {
+ const state = useContext(Context);
+
+ return (
+
+ )
+}
+
+export default Form;
diff --git a/src/Form/Formbot.example.js b/src/Form/Formbot.example.js
index 6e232cf..d811184 100644
--- a/src/Form/Formbot.example.js
+++ b/src/Form/Formbot.example.js
@@ -1,9 +1,11 @@
-import React from 'react';
+import React, { useContext } from 'react';
import Input from './Input';
import Select from './Select';
-import Formbot from './Formbot';
+import Formbot, { Context } from './Formbot';
+import Form from './Form';
import Button from '../Button';
import FormGroup from './FormGroup';
+import Fieldset from './Fieldset';
import CheckboxGroup from './CheckboxGroup';
import RadioGroup from './RadioGroup';
import Switch from './Switch';
@@ -38,6 +40,13 @@ const radioValues = [
},
];
+const Values = () => {
+ const state = useContext(Context);
+ return (
+ {JSON.stringify(state.values, null, 2)}
+ )
+}
+
export default function() {
return (
- {({ values, onSubmit, onChange, errors, onBlur }) => (
-
- )}
+
);
}
diff --git a/src/Form/Formbot.js b/src/Form/Formbot.js
index 54d5861..d006bbe 100644
--- a/src/Form/Formbot.js
+++ b/src/Form/Formbot.js
@@ -1,6 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
+export const Context = React.createContext(null);
+
const VALIDATIONS = {
required: (val, isRequired) => {
if (!isRequired) return;
@@ -23,9 +25,8 @@ const VALIDATIONS = {
export default class Formbot extends React.Component {
static propTypes = {
initialValues: PropTypes.shape(),
- validations: PropTypes.shape({
- fieldName: PropTypes.oneOfType([PropTypes.func, PropTypes.shape()]),
- }),
+ validations: PropTypes.object,
+ validationSchema: PropTypes.object,
onFocus: PropTypes.func,
onChange: PropTypes.func,
onBlur: PropTypes.func,
@@ -35,6 +36,7 @@ export default class Formbot extends React.Component {
static defaultProps = {
initialValues: {},
validations: {},
+ validationSchema: null,
onFocus() {},
onChange() {},
onBlur() {},
@@ -47,8 +49,12 @@ export default class Formbot extends React.Component {
errors: {},
};
+ get validatableFields() {
+ return Object.keys(this.props.validationSchema || this.props.validations || {});
+ }
+
get validatable() {
- return Object.keys(this.props.validations);
+ return !!this.validatableFields.length;
}
get isValid() {
@@ -110,15 +116,27 @@ export default class Formbot extends React.Component {
validateField(field) {
return new Promise(resolve => {
- const validation = this.props.validations[field];
+ const fieldState = this.state.fields[field] || {};
+ if (fieldState.validated) {
+ resolve();
+ return;
+ }
+
+ const fromSchema = !!this.props.validationSchema;
+ const validation = (fromSchema ? this.props.validationSchema : this.props.validations)[field];
- if (!validation) return;
+ if (!validation) {
+ resolve();
+ return;
+ }
const fieldValue = this.state.values[field];
let errorMsg;
try {
- if (typeof validation === 'function') {
+ if (fromSchema) {
+ validation.validateSync(fieldValue, { values: this.state.values });
+ } else if (typeof validation === 'function') {
validation(fieldValue);
} else {
Object.keys(validation).forEach(method => {
@@ -132,7 +150,11 @@ export default class Formbot extends React.Component {
});
}
} catch (err) {
- errorMsg = err.message;
+ if (fromSchema) {
+ errorMsg = err.errors.length ? err.errors[0] : undefined;
+ } else {
+ errorMsg = err.message;
+ }
} finally {
this.updateField(field, { validated: true }).then(() => {
this.setState(
@@ -151,7 +173,7 @@ export default class Formbot extends React.Component {
validateAllFields() {
return Promise.all(
- this.validatable.map(field => this.updateField(field, {}).then(() => this.validateField(field)))
+ this.validatableFields.map(field => this.updateField(field, {}).then(() => this.validateField(field)))
);
}
@@ -198,8 +220,8 @@ export default class Formbot extends React.Component {
});
};
- render() {
- return this.props.children({
+ getContext() {
+ return {
...this.props,
values: this.state.values,
errors: this.state.errors,
@@ -208,6 +230,16 @@ export default class Formbot extends React.Component {
onBlur: this.onBlur,
onSubmit: this.onSubmit,
reset: this.reset,
- });
+ }
+ }
+
+ render() {
+ const { children, ...props } = this.props;
+
+ return (
+
+ {typeof children === 'function' ? children(this.getContext()) : children}
+
+ )
}
}
diff --git a/src/Form/Formbot.mdx b/src/Form/Formbot.mdx
index 592ad84..3ab51a8 100644
--- a/src/Form/Formbot.mdx
+++ b/src/Form/Formbot.mdx
@@ -4,8 +4,11 @@ name: Formbot
---
import { Playground, PropsTable } from 'docz'
+import * as yup from 'yup';
import FormExample from './Formbot.example'
import Formbot from './Formbot'
+import Form from './Form';
+import Field from './Field';
import Button from '../Button'
import FormGroup from './FormGroup'
import Input from './Input'
@@ -22,30 +25,21 @@ Quickly build a form using a Formbot and pre-configured form components. Formbot
### Formbot
-
- {({ values, onSubmit, onChange, errors, onBlur }) => (
-
diff --git a/src/Form/Input.js b/src/Form/Input.js
index 5eba758..ab07b49 100644
--- a/src/Form/Input.js
+++ b/src/Form/Input.js
@@ -4,6 +4,7 @@ import { css } from 'styled-components';
import Field from './Field';
import StyledLabel from './Label';
import FormError from './FormError';
+import { createEasyInput } from './EasyInput';
import { createComponent } from '../utils';
const InputContainer = createComponent({
@@ -71,7 +72,7 @@ const validateValueProp = (props, propName, componentName) => {
return null;
};
-export default class Input extends Component {
+class Input extends Component {
static propTypes = {
value: validateValueProp,
type: PropTypes.string,
@@ -277,3 +278,5 @@ export default class Input extends Component {
);
}
}
+
+export default createEasyInput(Input);
diff --git a/src/Form/RadioGroup.js b/src/Form/RadioGroup.js
index a560ddf..70fe646 100644
--- a/src/Form/RadioGroup.js
+++ b/src/Form/RadioGroup.js
@@ -1,10 +1,11 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
+import Flex from '../Flex';
+import Box from '../Box';
import Checkbox from './Checkbox';
import Label from './Label';
import FormError from './FormError';
-import Flex from '../Flex';
-import Box from '../Box';
+import { createEasyInput } from './EasyInput';
import { createComponent } from '../utils';
const StyledRadioGroup = createComponent({
@@ -12,7 +13,7 @@ const StyledRadioGroup = createComponent({
as: Box,
});
-export default class RadioGroup extends Component {
+class RadioGroup extends Component {
static propTypes = {
name: PropTypes.string,
onChange: PropTypes.func,
@@ -53,9 +54,9 @@ export default class RadioGroup extends Component {
// Bail out if value is the same
if (this.state.value === value) return;
- this.setState({ value });
-
- this.props.onChange(this.props.name, value);
+ this.setState({ value }, () => {
+ this.props.onChange(this.props.name, value);
+ });
};
render() {
@@ -83,6 +84,7 @@ export default class RadioGroup extends Component {
label={choiceLabel}
value={this.state.value}
valueTrue={value}
+ valueFalse={value}
iconOn="radiobox-marked"
iconOff="radiobox-blank"
onChange={this.handleChange}
@@ -96,3 +98,5 @@ export default class RadioGroup extends Component {
);
}
}
+
+export default createEasyInput(RadioGroup);
diff --git a/src/Form/Select.js b/src/Form/Select.js
index a22260f..c9a0e05 100644
--- a/src/Form/Select.js
+++ b/src/Form/Select.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { Component } from 'react';
import styled, { css } from 'styled-components';
import PropTypes from 'prop-types';
import Field from './Field';
@@ -6,6 +6,7 @@ import FormError from './FormError';
import Icon from '../Icon';
import Flex from '../Flex';
import Label from './Label';
+import { createEasyInput } from './EasyInput';
import { createComponent } from '../utils';
const SelectContain = createComponent({
@@ -26,7 +27,7 @@ const SelectContain = createComponent({
font-size: ${theme.fontSizes[size]}px;
vertical-align: middle;
- ${value &&
+ ${!value &&
css`
color: ${p => p.theme.colors.grayMid};
select {
@@ -55,48 +56,74 @@ const IconContain = styled(Flex)`
z-index: 1;
`;
-function Select({ id, name = id, options, placeholder, value, error, onChange, onBlur, size = 'md', label }) {
- return (
-
- {label && }
-
-
-
-
-
-
- {error && {error}}
-
- );
-}
+class Select extends Component {
+ static propTypes = {
+ name: PropTypes.string.isRequired,
+ options: PropTypes.array.isRequired,
+ placeholder: PropTypes.string,
+ value: PropTypes.string,
+ error: PropTypes.string,
+ onChange: PropTypes.func,
+ onBlur: PropTypes.func,
+ size: PropTypes.string,
+ label: PropTypes.string,
+ }
+
+ static defaultProps = {
+ onChange() {},
+ onBlur() {},
+ }
+
+ static getDerivedStateFromProps(props, state) {
+ if (props.value !== undefined && props.value !== state.value) {
+ return {
+ value: props.value,
+ };
+ }
+ return null;
+ }
+
+ state = {
+ value: "",
+ };
-Select.propTypes = {
- id: PropTypes.string.isRequired,
- name: PropTypes.string.isRequired,
- options: PropTypes.array.isRequired,
- placeholder: PropTypes.string,
- value: PropTypes.string,
- error: PropTypes.string,
- onChange: PropTypes.func,
- onBlur: PropTypes.func,
- size: PropTypes.string,
- label: PropTypes.string,
-};
+ handleChange = e => {
+ this.setState({ value: e.target.value });
+ this.props.onChange(e.target.name, e.target.value);
+ }
+
+ handleBlur = e => {
+ this.props.onBlur(e.target.name)
+ }
+
+ render() {
+ const { id, name, options, placeholder, error, size = 'md', label, ...props } = this.props;
+ const { value } = this.state;
+
+ return (
+
+ {label && }
+
+
+
+
+
+
+ {error && {error}}
+
+ )
+ }
+}
-export default Select;
+export default createEasyInput(Select);
diff --git a/src/Form/Switch.js b/src/Form/Switch.js
index 9944c5c..5690a12 100644
--- a/src/Form/Switch.js
+++ b/src/Form/Switch.js
@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled, { css } from 'styled-components';
+import { createEasyInput } from './EasyInput';
const SwitchContain = styled.label`
position: relative;
@@ -52,7 +53,6 @@ const SwitchThumb = styled.span`
class Switch extends React.Component {
static propTypes = {
- id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
value: PropTypes.bool,
size: PropTypes.number,
@@ -61,6 +61,7 @@ class Switch extends React.Component {
};
static defaultProps = {
+ defaultValue: false,
variant: 'primary',
size: 16,
inset: 8,
@@ -96,16 +97,16 @@ class Switch extends React.Component {
};
render() {
- const { id, name, size, variant, inset } = this.props;
+ const { name, size, variant, inset, ...props } = this.props;
const { on } = this.state;
return (
-
-
+
+
);
}
}
-export default Switch;
+export default createEasyInput(Switch);
diff --git a/src/index.js b/src/index.js
index 1d067f0..5a91111 100644
--- a/src/index.js
+++ b/src/index.js
@@ -12,6 +12,7 @@ export Column from './Grid/Column';
export Container from './Grid/Container';
export Dropdown from './Dropdown';
export Field from './Form/Field';
+export Fieldset from './Form/Fieldset';
export Flex from './Flex';
export Formbot from './Form/Formbot';
export FormError from './Form/FormError';