npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

material-ui-hook-form

v0.1.20

Published

A set of wrapper components to facilitate using Material-UI with React Hook Form

Downloads

33

Readme

Material UI Hook Form

A set of wrapper components to facilitate using Material-UI with React Hook Form

Storebook

Storebook src

TODO

  • Website
  • Improve Docs
  • Add more examples
  • FormRender, Maybe we can build a tool that can generate fields from config file or GraphQL query/mutation

Field ( Text, Select, TextArea )

This component can use inside <Fields>

You can pass any props from TextField to Field.

Additional props from React Hook Form:

  • name: string - name is required and unique. Input name also supports dot and bracket syntax, which allows you to easily create nested form fields. Read more
  • control?: Control - control object is from invoking useForm. it's optional if you are using FormContext.
  • required?: string | ValidationOptionObject<boolean>
  • min?: ValidationOptionObject<number | string>
  • max?: ValidationOptionObject<number | string>
  • maxLength?: ValidationOptionObject<number | string>
  • minLength?: ValidationOptionObject<number | string>
  • pattern: ValidationOptionObject<RegExp>
  • validate?: Validate | Record<string, Validate>

Addtional props:

  • disableErrorMessage?: boolean - Hide error message when true
  • disableLabel?:boolean - Hide label when true
// Text
<Field name="firstName" />
<Field name="firstName" required maxLength={5} minLength={3} />
<Field name="phone" pattern={/^\d+$/} />

// TextArea
<Field name="note" multiline rows={4} />
<Field
  name="note"
  multiline
  rows={4}
  validate={v =>
    v
      ? String(v)
          .toLowerCase()
          .includes('mui') || 'note must include word `mui`'
      : undefined
  }
/>;



// Select
<Field name="department" options={['HR', 'accounting', 'shipping']} />

// Select with render props
<Field name="department">
    {DEPARTMENTS.map(option=> {
        <MenuItem key={option} value={option}>{option}</MenuItem>
    })}
</Field>

FieldNumber ( Currency, Number, FormatNumber, MaskInput, Phone Number, etc )

This component can use inside <Fields>

You can pass any props from TextField to FieldNumber except select, SelectProps.

You can pass any props from React Number Format

Additional props from React Hook Form:

  • name: string - name is required and unique. Input name also supports dot and bracket syntax, which allows you to easily create nested form fields. Read more
  • control?: Control - control object is from invoking useForm. it's optional if you are using FormContext.
  • required?: string | ValidationOptionObject<boolean>
  • min?: ValidationOptionObject<number | string>
  • max?: ValidationOptionObject<number | string>
  • validate?: Validate | Record<string, Validate>

Addtional props:

  • disableErrorMessage?: boolean - Hide error message when true
  • disableLabel?:boolean - Hide label when true
// Number
<FieldNumber name="age" />

// Currency,  $ 150,000
<FieldNumber name="salary" min={150000} thousandSeparator prefix="$ " md={4} />

If you need to build advanced Number Format, you can leaveage <FieldNumberFormat />

// A Money Format that will store user input as smallest currency unit and display as regular format.

// e.g. $100  => 100000

function CurrencyFormat({ value, onChange, currency = 'USD', ...other }: any) {
  const [maskValue, setMaskValue] = React.useState(value / 100);
  React.useEffect(() => setMaskValue(value / 100), [value]);

  return (
    <NumberFormat
      value={maskValue}
      isNumericString
      thousandSeparator
      onValueChange={target => {
        if (target.floatValue) {
          setMaskValue(target.floatValue);
          onChange(target.floatValue * 100);
        }
      }}
      customInput={TextField}
      prefix={getCurrencyPrefix(currency)}
      decimalScale={getCurrencyDecimalScale(currency)}
      {...other}
    />
  );
}

interface FieldMoney extends Except<FieldNumberFormat, 'as'> {
  currency?: CurrencyEnum;
}

function FieldMoney({ className, ...other }: FieldMoney) {
  return <FieldNumberFormat {...other} as={CurrencyFormat} className={clsx(className)} />;
}

export default FieldMoney;

FieldAutocomplete ( Autocomplete )

This component can use inside <Fields>

You can pass any props from Autocomplete to FieldAutocomplete.

You can pass any props from TextField to FieldAutocomplete except onChange, select, SelectProps.

Additional props from React Hook Form:

  • name: string - name is required and unique. Input name also supports dot and bracket syntax, which allows you to easily create nested form fields. Read more
  • control?: Control - control object is from invoking useForm. it's optional if you are using FormContext.
  • required?: string | ValidationOptionObject<boolean>
  • validate?: Validate | Record<string, Validate>

Addtional props:

  • disableErrorMessage?: boolean - Hide error message when true
  • disableLabel?:boolean - Hide label when true

FieldAutocomplete has a default renderInput implementation, which just a TextField with error message, All TextField props will forwarded to TextField. You can override renderInput if needed.

(params: RenderInputParams) => (
  <TextField
    fullWidth
    required={!!required}
    label={!naked ? label ?? getInputLabelFromName(name) : undefined}
    helperText={!naked ? error?.message ?? helperText : undefined}
    error={!!error}
    variant={variant as any}
    {...params}
    {...other}
  />
);
// Autocomplete
<FieldAutocomplete name="gender" options={['male', 'female']} />
<FieldAutocomplete name="gender" options={['male', 'female']} required />
<FieldAutocomplete
    name="gender"
    options={['male', 'female', 'other']}
    validate={v=> v === 'other' || 'Only other is allowed'}
/>

FieldRadioGroup ( RadioGroup )

You can pass any props from RadioGroup to FieldRadioGroup.

Additional props from React Hook Form:

  • name: string - name is required and unique. Input name also supports dot and bracket syntax, which allows you to easily create nested form fields. Read more
  • control?: Control - control object is from invoking useForm. it's optional if you are using FormContext.
  • required?: string | ValidationOptionObject<boolean>

Addtional props:

  • label?: string - Form Label
  • disableErrorMessage?: boolean - Hide error message when true
  • options: (string | { value: string; label?: string })[] - self described
  • helperText?: string - @see TextField#helperText
  • disabled?: boolean - @see TextField#disabled
// TODO

Form

You can pass any props from <form />.

Additional props:

  • form?: FormContextValues - If you pass the form object got from invoking useForm(). It will wrap a FormContext for you
  • debug?: boolean - TODO

Implementation

interface Form extends React.FormHTMLAttributes<HTMLFormElement> {
  form?: FormContextValues;
  debug?: boolean;
}

function Form({ form, ...other }: Form) {
  const component = <form noValidate {...other} />;
  return form ? <FormContext {...form}>{component}</FormContext> : component;
}

Fields

You can pass any props from Grid to Fields except container and item.

  • Fields have spacing=2 default value
  • All Grid item have xs=12 default value.
// All field now wrapped with <Grid item xs={12} md={6}/> You can override this by pass breakpoints to individual `Field`

<Fields md={6}>
  <Field name="department" md={12} />
  <Field name="firstName" />
  <Field name="lastName" />
  <FieldNumber name="age" md={4} />
  <FieldNumber name="salary" md={4} />
  <Field name="phone" md={4} />
  <Field name="note" />
</Fields>

Submit

A button with loading indicator and disabled while submitting

You can pass any props from Button to Submit

Additional props from React Hook Form:

  • control?: Control - control object is from invoking useForm. it's optional if you are using FormContext.

Addtional props:

  • loading?: boolean - Disable button and show loading indicator when true, it's optional if you are using FormContext
const form = useForm();
<Form
  form={form}
  onSubmit={form.handleSubmit(async () => {
    // sleep
    await new Promise(resolve => setTimeout(resolve, 2000));
  })}
>
  <Submit />
</Form>;

Styling

In order to make your form looks good, you should customize material-ui with your theme.

Here is the default theme we used in storybook example

createMuiTheme({
  props: {
    MuiFilledInput: {
      disableUnderline: true,
    },
    MuiTextField: {
      margin: 'none',
      size: 'small',
      variant: 'filled',
    },
    MuiFormHelperText: {
      variant: 'filled',
    },
    MuiInputLabel: {
      shrink: true,
      variant: 'filled',
    },
    MuiFormControl: {
      margin: 'none',
      variant: 'filled',
    },
  },
  overrides: {
    MuiInputBase: {
      input: {
        '&$disabled': {
          cursor: 'not-allowed',
        },
      },
    },
    MuiFilledInput: {
      root: {
        borderRadius: 4,
      },
    },
  },
});

All thanks goes to:

Other Solutions