3.2.0 • Published 2 years ago

apollo-form v3.2.0

Weekly downloads
232
License
MIT
Repository
github
Last release
2 years ago

npm version downloads size Coverage Status dependencies Status type license Code style

Introduction

Advanced form state, optimized fields rendering, form validation, file picker and more.

Installation

npm i apollo-form
# or
yarn add apollo-form

Demo

Show code of stories

Demo sign in

Demo todo list

Demo with confirm

Examples

Full form

interface CreatePlanFormValues {
   title: string;
   price: number;
   features: Array<{ title: string }>;
}

const validationSchema = Yup.object().shape({
   title: Yup.string().required(),
   price: Yup.number()
      .required()
      .min(0),
   features: Yup.array().of(
      Yup.object().shape({
         title: Yup.string().required(),
      }),
   ),
});

const initialState = {
   title: '',
   price: 0,
   features: [],
};

function CreatePlanForm() {
   return (
      <Form<CreatePlanFormValues>
         name='CreatePlanForm'
         enableReinitialize
         initialState={initialState}
         validationSchema={validationSchema}
         onSubmit={async ({ values }, form) => {
            try {
               await createPlanMutation({ variables: values });

               form.reset();
            } catch (e) {
               form.responseError(e.message);
            }
         }}
      >
         <Field name='title'>{({ field }) => <input {...getFieldProps(field)} />}</Field>
         <Field name='price'>
            {({ field }) => <input type='number' {...getFieldProps(field)} />}
         </Field>

         <FieldArray<{ title: string }> name='features'>
            {({ field }) => {
               return (
                  <>
                     {field.value.map((el, i) => {
                        return (
                           <div key={'plan-feature-' + i}>
                              <input key={'test' + i} name={'features' + '.' + i} />
                           </div>
                        );
                     })}

                     <div>
                        <button onClick={() => field.push({ title: '' })}>Push feature</button>
                        <Button onClick={() => field.pop()}>Pop feature</Button>
                     </div>
                  </>
               );
            }}
         </FieldArray>

         <ResponseMessage>{({ error }) => <span>{error}</span>}</ResponseMessage>
         <FormLoader>
            {({ loading }) => (
               <span style={{ display: loading ? 'block' : 'none' }}>Loading...</span>
            )}
         </FormLoader>

         <Submit>
            {({ disabled }) => (
               <button type='submit' disabled={disabled}>
                  Create plan
               </button>
            )}
         </Submit>
         <Reset>
            {({ disabled }) => (
               <button type='reset' disabled={disabled}>
                  Reset
               </button>
            )}
         </Reset>
      </Form>
   );
}

create field

function FormTextField(props: { name: string; validate?: FieldValidator<string> }) {
   const field = useField(props);

   return <TextField {...getFieldProps(field)} />;
}

// or

function FormTextField(props: { name: string; validate?: FieldValidator<string> }) {
   return (
      <Field<string> name={props.name} validate={props.validate}>
         {({ field }) => {
            const showError = Boolean(!field.focused && field.touched && field.error);

            return (
               <TextField
                  value={field.value}
                  onChange={e => field.setFieldValue(e.target.value)}
                  onFocus={() => field.setFieldFocused()}
                  onBlur={() => field.setFieldTouched(true)}
                  helperText={showError ? field.error : undefined}
                  error={showError}
               />
            );
         }}
      </Field>
   );
}

create array field

function FormTextFieldArray(props: { name: string; validate: FieldValidator<string[]> }) {
   return (
      <FieldArray<string> name={props.name} validate={props.validate}>
         {({ field }) => {
            return (
               <>
                  {field.value.map((el, i) => {
                     return (
                        <Grid item xs={3} key={'arr-field' + i}>
                           <FormTextField
                              key={'test' + i}
                              name={props.name + '.' + i}
                              label={props.name + '.' + i}
                           />
                        </Grid>
                     );
                  })}

                  <Grid item xs={3}>
                     <Box display='flex'>
                        <Button onClick={() => field.push((field.value.length + 1).toString())}>
                           push
                        </Button>
                        <Button onClick={() => field.pop()}>pop</Button>
                     </Box>
                  </Grid>
               </>
            );
         }}
      </FieldArray>
   );
}

create file field

function FieldImage(props: Omit<ImageFieldProps, 'children'>) {
   return (
      <FieldFile accept={['image/jpeg', 'image/png']} maxSize={1024 * 500} {...props}>
         {({ field, onClick }) => {
            const [img, setImg] = React.useState<string | null>(null);

            React.useEffect(() => {
               if (field.value) {
                  fileToBase64(field.value).then(r => setImg(r));
               }
            }, [field.value]);

            return (
               <>
                  {field.value ? (
                     <>
                        {img && (
                           <>
                              <img style={{ width: '100%' }} src={img} alt={field.value.name} />
                              <Button onClick={onClick} variant='contained'>
                                 Upload new image
                              </Button>
                           </>
                        )}
                     </>
                  ) : (
                     <Button variant='contained' onClick={onClick}>
                        Upload image
                     </Button>
                  )}
               </>
            );
         }}
      </FieldFile>
   );
}

create submit button

function FormSubmit() {
   return (
      <Submit>
         {({ isValid, isSubmitted, loading, existsChanges }) => (
            <Button type='submit' disabled={loading || (isSubmitted ? !isValid : false)}>
               Submit
            </Button>
         )}
      </Submit>
   );
}

create reset button

function FormSubmit() {
   return (
      <Reset>
         {({ disabled }) => (
            <Button type='reset' disabled={disabled}>
               Submit
            </Button>
         )}
      </Reset>
   );
}

show error message

function FirstError(props: { name: string; ignoreTouched?: boolean }) {
   return (
      <ErrorMessage
         ignoreTouched={props.ignoreTouched}
         name={props.name}
         children={({ error }) => (
            <span>
               password-err: (<b style={{ color: 'red' }}>{error}</b>)
            </span>
         )}
      />
   );
}

show loader

function CustomLoader() {
   return (
      <FormLoader children={({ loading }) => <span>{loading ? 'loading...' : 'loaded'}</span>} />
   );
}

create query

const myFormQuery = makeApolloFormQuery('my-form');

function useMyFormState() {
    return useQuery(myFormQuery);
}

function Form() {
   return (
      <Form
         name='my-form'
         ...
      >
         ...
      </Form>
   );
}

Api

Form api

NameTypeRequiredDescription
namestringyesgraphql client value name, like this query Form { ${name} @client }
initialStateobjectyesInitial form state
initialErrorsFormErrorsnoInitial errors
initialTouchesFormTouchesnoInitial touched fields
validationSchemaObjectSchemanoYup validation schema
validateFunctionnoCustom form validation, function returned errors state
resetOnSubmitbooleannoReset form with initialState after submit
validateOnMountbooleannoValidate form on mount
enableReinitializebooleannoReset form with new initialState
onInitFunctionnoFunction for save form reference
onSubmitFunctionnoAsync function for handle form submit
onChangeFunctionnoHandle state changes (called only if values changed)
saveOnUnmountbooleannoSave form state in apollo global state
resetOnUnmountbooleannoReset form with initialState after unmount form

Field api

NameTypeRequiredDescription
namestringyeskey of state object
validateFunctionnoFunction for validate value, return err(string) or undefined
childrenFunctionyesFunction for render, return object of "value", "error", "touched", "focused" and change actions

License

MIT

3.2.0

2 years ago

3.1.3

2 years ago

3.1.2

2 years ago

3.0.2

3 years ago

3.1.1

3 years ago

3.1.0

3 years ago

3.0.1

3 years ago

2.4.3

3 years ago

2.4.5

3 years ago

2.4.4

3 years ago

2.4.2

3 years ago

2.4.1

3 years ago

2.4.0

3 years ago

2.3.0

3 years ago

2.2.2

3 years ago

2.2.1

3 years ago

2.2.0

3 years ago

2.1.4

3 years ago

2.1.2

3 years ago

2.1.3

3 years ago

2.1.1

3 years ago

2.1.0

3 years ago

2.0.7

3 years ago

2.0.6

3 years ago

2.0.5

3 years ago

2.0.4

3 years ago

2.0.3

3 years ago

2.0.2

3 years ago

2.0.1

3 years ago

1.12.2

3 years ago

2.0.0-canary.2

3 years ago

2.0.0-canary.1

3 years ago

2.0.0-canary

3 years ago

2.0.0

3 years ago

1.12.1

3 years ago

1.12.0

3 years ago

1.11.0-canary

3 years ago

1.11.0

3 years ago

1.11.0-canary-1

3 years ago

1.11.0-canary-2

3 years ago

1.11.0-canary-5

3 years ago

1.11.0-canary-3

3 years ago

1.11.0-canary-4

3 years ago

1.9.1

3 years ago

1.10.0-beta

3 years ago

1.10.0

3 years ago

1.9.0

3 years ago

1.8.3

3 years ago

1.8.2

3 years ago

1.8.1

3 years ago

1.8.0

3 years ago

1.7.3

3 years ago

1.7.1

3 years ago

1.6.4

3 years ago

1.7.0

3 years ago

1.6.3

4 years ago

1.6.2

4 years ago

1.6.1

4 years ago

1.6.0

4 years ago

1.5.0

4 years ago

1.4.3

4 years ago

1.4.2

4 years ago

1.4.1

4 years ago

1.3.6

4 years ago

1.4.0

4 years ago

1.3.5

4 years ago

1.3.4

4 years ago

1.3.3

4 years ago

1.3.2

4 years ago

1.3.1

4 years ago

1.3.0

4 years ago

1.2.0

4 years ago

1.1.4

4 years ago

1.1.3

4 years ago

1.1.2

4 years ago

1.1.1

4 years ago

1.1.0

4 years ago

1.0.9

4 years ago

1.0.8

4 years ago

1.0.7

4 years ago

1.0.6

4 years ago

1.0.5

4 years ago

1.0.4

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago