Gathering detailed insights and metrics for bottoms-up-react-form
Gathering detailed insights and metrics for bottoms-up-react-form
Gathering detailed insights and metrics for bottoms-up-react-form
Gathering detailed insights and metrics for bottoms-up-react-form
npm install bottoms-up-react-form
Typescript
Module System
Node Version
NPM Version
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
1
This package helps with building simple to complex forms in React.
Packages like Formik keep all form logic at a central place and prefer to keep input fields as stateless "dumb" presentational components.
Inspired by HTML inputs, Bottoms-Up-React-Forms shares the responsibility between the input fields and form.
The input components take care of validations and visualization, group components maintain the data structure and
logic that involves multiple input and group components. This allows for easy extendable and readable code as your forms
approach a plug and play structure.
The name Bottoms-Up-React-Forms emphasises on a bottom-up forms architecture that starts from complete standalone input components.
Each of these input components can be plugged into any group component, creating a new standalone system. If the need is there then each of these
input and group component can be grouped into another even bigger group and so on. All of this without any need to change or copy-paste the existing
components' logic. At the end of the day you'll get that feeling that you created something great and really deserve a nice drink :beer: :tropical_drink:
npm i -s bottoms-up-react-forms
Please clone the project and execute this in the command line:
npm install
npm run storybook
Just a form with first name/last name/array of emails/array of addresses (street, city, country)
class InputText extends PureComponent {
render() {
return <InputManager {...{...this.props}}>
{(input) => {
const {error, touched, focus, value, onChange, onFocus, onBlur, label, type} = input;
const showError = error && touched && !focus;
return <div {...{className: styles.input}}>
<label {...{className: styles.label}}>{label}
<input {...{
type,
value: value || '',
onChange: (event) => onChange(event.target.value),
onFocus,
onBlur
}}/>
{showError ? <label {...{className: styles.error}}>{error}</label> : null}
</label>
</div>
}}
</InputManager>;
}
}
class UserProfile extends Component {
state = {
value: initialValue(),
initialValue: initialValue()
};
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
}
onChange(newFormState) {
this.setState(newFormState);
}
render() {
const {onChange, state} = this;
const {value, initialValue} = state;
return <InputGroupManager {...{onChange, value, initialValue}}>
{(form) => {
return <Fragment>
<InputText {...{label: "First name", ...form.helpers.buildProps({name: "firstName"})}}/>
<InputText {...{label: "Last name", ...form.helpers.buildProps({name: "lastName"})}}/>
<InputGroupManager {...{valueType: "array", ...form.helpers.buildProps({name: "emailAddresses"})}}>
{(emails) => <Fragment>
{emails.value.map((email, index) => {
return <InputText {...{label: "Email", ...emails.helpers.buildProps({index})}}/>;
})}
<Button {...{label: "Add Email", onClick: emails.helpers.array.add}}/>
</Fragment>}
</InputGroupManager>
<InputGroupManager {...{valueType: "array", ...form.helpers.buildProps({name: "addresses"})}}>
{(addresses) => <Fragment>
<h5>My addresses</h5>
{addresses.value.map((address, index) => {
return <InputGroupManager {...{...addresses.helpers.buildProps({index})}}>
{(address) => <Fragment>
<InputText {...{label: "Street", ...address.helpers.buildProps({name: "street"})}}/>
<InputText {...{label: "City", ...address.helpers.buildProps({name: "city"})}}/>
<InputText {...{label: "Country", ...address.helpers.buildProps({name: "country"})}}/>
</Fragment>}
</InputGroupManager>;
})}
<Button {...{label: "Add address", onClick: addresses.helpers.array.add}}/>
</Fragment>}
</InputGroupManager>
</Fragment>;
}}
</InputGroupManager>;
}
}
Bottoms-Up-React-Forms exposes 2 components: a InputGroupManager that takes care of the group responsibilities, and a InputManager assists with the input logic. The InputManager is designed to only act as a child of a group, whereas the InputGroupManager can act as a child and as a parent of other input/group components.
To get to this plug and play structure, both the group and input components support the following props:
Combines and manages inputs. Wraps around InputManager components or other InputGroupManager.
Keeps the state of a single input value. Listens to value changes of children and parents and notifies the other if a change happened. Handles validations. Handles dirty, focus, touched logic.
= !isEqual(this.props.initialValue, newValue)
Helps with resetting everything in the form by unmounting and remounting the whole form using the React property "key".
Add this to the constructor of your top form component:
this.formResetter = new FormResetter(this);
Spread the results of this.formResetter.toProps()
to the props of the top <InputGroupManager>:
<InputGroupManager {...{...this.formResetter.toProps()}}>
Provides some functions that help with building the "validator" property for the InputManager
.
Note that the order matters sometimes. E.g. required() should be added before minimum(x) because minimum
Common example: validator = validatorBuilder(minimum(3), maximum(50))
.
Note that the example chains multiple validators, keep in mind that the order is important when you do this (e.g. when combining required and minimum).
Uses the error variable to decide if the value is valid as follows: valid = !error
.
Given a value, the response will be the string "required" if !value
else false
.
Given a value, the response will be the string "minimum" if value.length >= minLength
else false
.
Given a value, the response will be the string "maximum" if value.length <= maxLength
else false
.
Given a value, the response will be the string "password" if pattern.test(value)
else false
.
Given a value, the response will be false
if patternStrong.test(value)
else mediumPassword
if patternMedium.test(value)
else weakPassword
.
No vulnerabilities found.
No security vulnerabilities found.