Test codes will be added in the future.
pnpm add @mm1995tk/simple-form @mm1995tk/immutable-record-updater jotai
re-export "SimpleFormJotaiBound"
'use client';
export { SimpleFormJotaiBound } from '@mm1995tk/simple-form';
Enclose the application root with "SimpleFormJotaiBound".
init simple-form by passing validation variants
export const createSimpleForm = initSimpleForm('danger', 'warning', 'info');
define form types, its empty data and rules. then, create hooks of simple-form by passing empty data.
export type UserForm = {
name: string;
age: number | null;
note: string;
};
export const emptyUser: UserForm = {
name: '',
age: null,
note: '',
};
export const isAgeNumber: ValidateUserForm = ({ age }) => {
const ageNumber = Number(age);
return (
!age ||
(!isNaN(ageNumber) && ageNumber > 0) || {
variant: 'danger',
name: 'invalid-format',
properties: ['age'],
}
);
};
export const isAgeValid: ValidateUserForm = ({ age }) => {
const ageNumber = Number(age);
return (
isNaN(ageNumber) ||
ageNumber < 200 || {
variant: 'warning',
name: 'too-old',
properties: ['age'],
}
);
};
export const { useSimpleForm, useHydrateForm, useControlledAlert } = createSimpleForm(emptyUser);
setup validation.
export const useAlert = () => {
const [, { isDirty }] = useSimpleForm();
const isAgeNotDirtyOr = addORConditionToUserFormValidator(!isDirty('age'));
const alert = useControlledAlert<UserFormAlertDef>(
isAgeNotDirtyOr(isAgeNumber),
isAgeValid
);
return alert(console.log);
};
const addORConditionToUserFormValidator: AddORCondition<UserForm, UserFormAlertDef> = addORCondition;
create form component.
export const UserFormComponent = ({ initialData }: { initialData: UserForm }) => {
// feed initial-value to form
useHydrateForm(initialData);
const [data, { reset }] = useSimpleForm();
return (
<form
onSubmit={e => {
e.preventDefault();
console.log(data);
}}
style={{ display: 'flex', gap: 8, flexDirection: 'column' }}
>
<FieldInput field='name' />
<FieldInput field='age' />
<FieldInput field='note' />
<div>
<button
type='button'
onClick={() => {
reset();
}}
>
reset all fields
</button>
{' '}
<button type='submit'>submit</button>
</div>
</form>
);
};
const FieldInput = ({ field }: { field: keyof UserForm }) => {
const [data, { mutateData, reset }] = useSimpleForm();
const id = `user-form-${field}`;
const value = data[field];
const alert = useAlert();
return (
<div>
<label htmlFor={id}>{field}: </label>
<div style={{ color: 'red' }}>{alert[field].danger.has('required') && <>required</>}</div>
<div style={{ color: 'red' }}>
{field === 'age' && alert.age.danger.has('invalid-format') && <>age muet be a natural number.</>}
</div>
<div style={{ color: 'orange' }}>{field === 'age' && alert.age.warning.has('too-old') && <>are you an elf?</>}</div>
<input
value={value}
onChange={e => {
mutateData(field, e.target.value);
}}
id={id}
/>
<button
type='button'
onClick={() => {
reset(field);
}}
>
reset {field}
</button>
</div>
);
"SimpleFormJotaiBound" is jotai's "Provider". you can control a range that form-state is retained by using "SimpleFormJotaiBound".
as like jotai, when you across over "SimpleFormJotaiBound", form-state is cleared.
If you want to display the same form repeatedly, array-simple-form is useful.
Additional documentation will be added in the future.
import { initArraySimpleForm } from '@mm1995tk/simple-form';