diff --git a/package-lock.json b/package-lock.json index b01e18d..081c0c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "foris", - "version": "1.0.0", + "version": "1.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8da249a..88f307d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "foris", - "version": "1.0.0", + "version": "1.1.0", "description": "Set of components and utils for Foris and its plugins.", "author": "CZ.NIC, z.s.p.o.", "repository": { diff --git a/src/api/post.js b/src/api/post.js index 705356e..6a3933a 100644 --- a/src/api/post.js +++ b/src/api/post.js @@ -12,7 +12,7 @@ import { API_ACTIONS, TIMEOUT, HEADERS, APIReducer, getErrorMessage, } from "./utils"; -export function useAPIPost(url) { +export function useAPIPost(url, contentType) { const [state, dispatch] = useReducer(APIReducer, { isSending: false, isError: false, @@ -20,12 +20,17 @@ export function useAPIPost(url) { data: null, }); + const headers = { ...HEADERS }; + if (contentType) { + headers["Content-Type"] = contentType; + } + const post = async (data) => { dispatch({ type: API_ACTIONS.INIT }); try { const result = await axios.post(url, data, { timeout: TIMEOUT, - headers: HEADERS, + headers, }); dispatch({ type: API_ACTIONS.SUCCESS, payload: result.data }); } catch (error) { diff --git a/src/bootstrap/CheckBox.js b/src/bootstrap/CheckBox.js index 8cc4658..02f336c 100644 --- a/src/bootstrap/CheckBox.js +++ b/src/bootstrap/CheckBox.js @@ -7,7 +7,7 @@ import React from "react"; import PropTypes from "prop-types"; -import { useUID } from "react-uid/dist/es5/index"; +import { useUID } from "react-uid"; import { formFieldsSize } from "./constants"; diff --git a/src/bootstrap/FileInput.js b/src/bootstrap/FileInput.js new file mode 100644 index 0000000..b66fcba --- /dev/null +++ b/src/bootstrap/FileInput.js @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 CZ.NIC z.s.p.o. (http://www.nic.cz/) + * + * This is free software, licensed under the GNU General Public License v3. + * See /LICENSE for more information. + */ + +import React from "react"; + +import PropTypes from "prop-types"; +import { Input } from "./Input"; + +FileInput.propTypes = { + /** Field label. */ + label: PropTypes.string.isRequired, + /** Error message. */ + error: PropTypes.string, + /** Help text message. */ + helpText: PropTypes.string, + /** Email value. */ + value: PropTypes.string, +}; + +export function FileInput({ ...props }) { + return ( + + ); +} diff --git a/src/bootstrap/FileInput.md b/src/bootstrap/FileInput.md new file mode 100644 index 0000000..75d76df --- /dev/null +++ b/src/bootstrap/FileInput.md @@ -0,0 +1,15 @@ +Bootstrap component for file input. Includes label and has predefined sizes and structure for using in foris forms. + +All additional `props` are passed to the `` HTML component. + +```js +import {useState} from 'react'; +const [files, setFiles] = useState([]); + +setFiles(event.target.files)} +/> +``` diff --git a/src/bootstrap/Input.js b/src/bootstrap/Input.js index 6784503..d5715ba 100644 --- a/src/bootstrap/Input.js +++ b/src/bootstrap/Input.js @@ -6,7 +6,7 @@ */ import React from "react"; -import { useUID } from "react-uid/dist/es5/index"; +import { useUID } from "react-uid"; import PropTypes from "prop-types"; import { formFieldsSize } from "./constants"; @@ -21,31 +21,31 @@ Input.propTypes = { PropTypes.arrayOf(PropTypes.node), PropTypes.node, ]), + labelClassName: PropTypes.string, + groupClassName: PropTypes.string, }; /** Base bootstrap input component. */ export function Input({ - type, label, helpText, error, className, children, ...props + type, label, helpText, error, className, children, labelClassName, groupClassName, ...props }) { const uid = useUID(); const inputClassName = `form-control ${className || ""} ${(error ? "is-invalid" : "")}`.trim(); return ( -
-
- -
- + +
+ - {children} -
- {error ?
{error}
: null} - {helpText ? {helpText} : null} + {...props} + /> + {children}
+ {error ?
{error}
: null} + {helpText ? {helpText} : null}
); } diff --git a/src/bootstrap/RadioSet.js b/src/bootstrap/RadioSet.js index 9dae6a6..7125cb6 100644 --- a/src/bootstrap/RadioSet.js +++ b/src/bootstrap/RadioSet.js @@ -7,7 +7,7 @@ import React from "react"; import PropTypes from "prop-types"; -import { useUID } from "react-uid/dist/es5/index"; +import { useUID } from "react-uid"; import { formFieldsSize } from "./constants"; diff --git a/src/bootstrap/Select.js b/src/bootstrap/Select.js index cc89ca7..bc524c4 100644 --- a/src/bootstrap/Select.js +++ b/src/bootstrap/Select.js @@ -7,7 +7,7 @@ import React from "react"; import PropTypes from "prop-types"; -import { useUID } from "react-uid/dist/es5/index"; +import { useUID } from "react-uid"; Select.propTypes = { diff --git a/src/bootstrap/__tests__/__snapshots__/NumberInput.test.js.snap b/src/bootstrap/__tests__/__snapshots__/NumberInput.test.js.snap index 67cf590..9729a53 100644 --- a/src/bootstrap/__tests__/__snapshots__/NumberInput.test.js.snap +++ b/src/bootstrap/__tests__/__snapshots__/NumberInput.test.js.snap @@ -2,53 +2,49 @@ exports[` Render number input 1`] = `
-
- + Test label + +
+
- -
- - -
+ + +
- - Some help text -
+ + Some help text +
`; diff --git a/src/bootstrap/__tests__/__snapshots__/PasswordInput.test.js.snap b/src/bootstrap/__tests__/__snapshots__/PasswordInput.test.js.snap index 95f4fe1..3e1f0b7 100644 --- a/src/bootstrap/__tests__/__snapshots__/PasswordInput.test.js.snap +++ b/src/bootstrap/__tests__/__snapshots__/PasswordInput.test.js.snap @@ -2,32 +2,28 @@ exports[` Render password input 1`] = `
-
- -
- -
- - Some help text - + Test label + +
+
+ + Some help text +
`; diff --git a/src/bootstrap/__tests__/__snapshots__/TextInput.test.js.snap b/src/bootstrap/__tests__/__snapshots__/TextInput.test.js.snap index a248d52..e77509f 100644 --- a/src/bootstrap/__tests__/__snapshots__/TextInput.test.js.snap +++ b/src/bootstrap/__tests__/__snapshots__/TextInput.test.js.snap @@ -2,31 +2,27 @@ exports[` Render text input 1`] = `
-
- -
- -
- - Some help text - + Test label + +
+
+ + Some help text +
`; diff --git a/src/form/hooks.js b/src/form/hooks.js index 8bbbd66..3b14499 100644 --- a/src/form/hooks.js +++ b/src/form/hooks.js @@ -17,7 +17,7 @@ const FORM_ACTIONS = { resetData: 2, }; -export function useForm(validator, prepData) { +export function useForm(validator, dataPreprocessor) { const [state, dispatch] = useReducer(formReducer, { data: null, initialData: null, @@ -28,10 +28,10 @@ export function useForm(validator, prepData) { dispatch({ type: FORM_ACTIONS.resetData, data, - prepData, + dataPreprocessor, validator, }); - }, [prepData, validator]); + }, [dataPreprocessor, validator]); const onFormChangeHandler = useCallback((updateRule) => (event) => { dispatch({ @@ -41,6 +41,7 @@ export function useForm(validator, prepData) { validator, }); }, [validator]); + return [ state, onFormChangeHandler, @@ -61,12 +62,15 @@ function formReducer(state, action) { }; } case FORM_ACTIONS.resetData: { - if (!action.data) return { ...state, initialData: state.data }; - const prepData = action.prepData ? action.prepData(action.data) : action.data; + if (!action.data) { + return { ...state, initialData: state.data }; + } + + const data = action.dataPreprocessor ? action.dataPreprocessor(action.data) : action.data; return { - data: prepData, - initialData: prepData, - errors: action.data ? action.validator(prepData) : undefined, + data, + initialData: data, + errors: action.data ? action.validator(data) : undefined, }; } default: { @@ -82,6 +86,9 @@ function getChangedValue(target) { } else if (target.type === "number") { const parsedValue = parseInt(value); value = Number.isNaN(parsedValue) ? value : parsedValue; + } else if (target.type === "file") { + // Return first file (we don't need multiple yet) + [value] = target.files; } return value; } diff --git a/src/index.js b/src/index.js index 7288d3c..ab4987c 100644 --- a/src/index.js +++ b/src/index.js @@ -15,15 +15,16 @@ export { useAPIPatch } from "api/patch"; export { Alert } from "bootstrap/Alert"; export { Button } from "bootstrap/Button"; export { CheckBox } from "bootstrap/CheckBox"; -export { formFieldsSize } from "bootstrap/constants"; export { DataTimeInput } from "bootstrap/DataTimeInput"; export { EmailInput } from "bootstrap/EmailInput"; +export { FileInput } from "bootstrap/FileInput"; export { Input } from "bootstrap/Input"; export { NumberInput } from "bootstrap/NumberInput"; export { PasswordInput } from "bootstrap/PasswordInput"; export { RadioSet } from "bootstrap/RadioSet"; export { Select } from "bootstrap/Select"; export { TextInput } from "bootstrap/TextInput"; +export { formFieldsSize } from "bootstrap/constants"; export { Spinner,