@maxima/a-form
v0.0.27
Published
Form library to use in React form components based on fields schema and react hooks.
Downloads
121
Readme
AForm
Build statically-typed forms using React and TypeScript based on form schemas.
How to install
yarn install a-form
How to use
For creating a form with a-form
follow steps described below.
Define form schema
import { Input, InputArray, InputGroup } from 'a-form';
const aSchema = new InputGroup({
name: new Input<string>(), // <- string input
age: new Input<number>(), // <- number input
address: new InputGroup({ // <- nested inputs
city: new Input<string>(),
zip: new Input<number>()
}),
phoneNumbers: new InputArray(new Input<string>()), // <- array of string inputs
ids: new InputArray(new Input<number>()), // <- array of number inputs
guests: new InputArray( // <- array of nested inputs
new InputGroup({
name: new Input<string>(),
age: new Input<number>()
})
)
});
You can also use helper functions for denining form schemas:
import { input, inputArray, inputGroup } from 'a-form';
const aSchema = inputGroup({
name: input<string>(), // <- string input
age: input<number>(), // <- number input
address: inputGroup({ // <- nested inputs
city: input<string>(),
zip: input<number>()
}),
phoneNumbers: inputArray(input<string>()), // <- array of string inputs
ids: inputArray(input<number>()), // <- array of number inputs
guests: inputArray( // <- array of nested inputs
inputGroup({
name: input<string>(),
age: input<number>()
})
)
});
Using useForm React hook
import { useForm } from 'a-form';
const AForm: React.SFC<{}> = (props) => {
const validate = (values: typeof initialValues) => ({}); // form always valid
const submit = (values: typeof initialValues) => console.log(values);
const form = useForm({ aSchema, initialValues, validate, submit });
// use form to access properties for rendering form
return (
<form onSubmit={form.handleSubmit}>
{ // ... }
</form>
)
};
Using Form component to render your form with render props
const AForm: React.SFC<{}> = (props) => {
const validate = (values: typeof initialValues) => ({}); // form always valid
const submit = (values: typeof initialValues) => console.log(values);
return (
<Form schema={aSchema} validate={validate} submit={submit} initialValues={}>
{
(formProps) =>
(
<form onSubmit={formProps.handleSubmit}>
<div>
<label htmlFor="input-name">Name</label>
<input id="input-name" {...formProps.name} />
{
formProps.name.touched && formProps.name.invalid &&
<span className="error">{formProps.name.error}</span>
}
</div>
<div>
<label htmlFor="input-age">Age</label>
<input id="input-age" {...formProps.age} />
{
formProps.age.touched && formProps.age.invalid &&
<span className="error">{formProps.age.error}</span>
}
</div>
<div>
<label htmlFor="input-address-city">City</label>
<input id="input-address-city" {...formProps.address.city} />
</div>
<div>
<label htmlFor="input-address-zip">Postal code</label>
<input id="input-address-zip" {...formProps.address.zip} />
</div>
{
formProps.phoneNumbers.items.map((phoneNumberProps, index) => {
<div>
<label htmlFor={`input-phone-number-${index}`}>Phone {index}</label>
<input id={`input-phone-number-${index}`} {...phoneNumberProps} />
<button type="button" onClick={() => formProps.phoneNumbers.remove(index)}>×</button>
</div>
})
}
<button type="button" onClick={() => formProps.phoneNumbers.push('')}>Add phone number</button>
<button type="submit">Submit form</button>
</form>
)
}
</Form>
);
}
API
Form props / useForm hook config
schema: InputGroup
- form schema, which defines available form inputs, for which later field-level props will be availablevalidate(values)
- validation function which returns an object with validation errors for each field.submit(values)
- function which handles data submissioninitialValues
- values of the form, with which the form will be initialized
Form state
values: Values<T>
- form valueserrors: Errors<T>
- per-input validation errorsactive: Flags<T>
- per-input active flags, indicating whether input is focused or nottouched: Flags<T>
- per-input touched flags, indicating whether input is touched or notinvalid: boolean
- indicates that form has validation errorsvalidating: boolean
- indicates that form is currently running validationssubmitting: boolean
- indicates that form is currently submittingsubmitted: boolean
- indicates that the form was submittedsubmitResult: boolean | undefined
- indicates whether the form submission was successfull or failederror: string | undefined
- global form-level errordirty: boolean
- global dirty flag, indicates that current form values are not deeply equal to initialValues
Form handlers
handleSubmit(event: React.FormEvent): void;
- form submit handler, which internally marks all fields as touched, validates and submits form valuesreset(): void;
- reset form values to form's initialValuessetValues(values: Values<T>): void;
- set form valuessetErrors(errors: Errors<T>): void;
- set form errors
Input props
value: T
- field valuename: string
- field nameerror: string | undefined
- validation erroractive: boolean
- active flag (indicates that field is currently focused)touched: boolean
- touched flag (indicates that field is touched)dirty: boolean
- field value was changed and is different from value, specified ininitialValues
prop of the form componentinvalid: boolean
- field has validation errorsonBlur(event: React.FocusEvent<HTMLElement>): void
- blur event handleronChange(eventOrValue: React.ChangeEvent<HTMLInputElement> | T): void
- change event handleronFocus(event: React.FocusEvent<HTMLElement>): void
- focus event handler
InputArray props
items
: array of field props for each value in the listtouched
: booleanpop(): void
- remove last value from the listpush(value: T): void
- add value specified as agrument to the end of the listshift(): void
- remove first value from the listunshift(value: T): void
- add value specified as agrument to the beginning of the listinsert(index: number, value: T): void
- insert value specified as agrument at a given index into the listreplace(index: number, value: T): void
- replace value by existing index with a new valueremove(index: number): void
- remove value from the list at index specified as an argumentmove(from: number, to: number): void
- move value from one index to anotherswap(indexA: number, indexB: number): void
- swap positions of two values in the list, specified by arguments
InputGroup props
touched
: booleanchange(values: T)
- change form group values
For each of the input defined in particular input group, it's props are available by the name of the input.
Example:
const groupSchema = new InputGroup({
name: new Input<string>(),
tags: new InputArray(Input<string>)
});
// ...
// usage later in form component
formProps.name // <= Input props for name input
formProps.tags // <= InputArray props for tags input
Licence
GPLv3
Copyright hck, 2019