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

react-formatge

v0.1.37

Published

The declarative library for creating quick and full-featured react forms.

Downloads

162

Readme

React Formatge

NPM version Build npm-typescript License

The declarative library for creating quick and full-featured react forms based on Chakra UI components.

Live demo:

React Formatge Live Demo

Installation:

npm install react-formatge --save

or

yarn add react-formatge

Important notes:

This package will only work in a ChakraUI project, and it will also need date-fns and react-date-range

npm install @chakra-ui/react @emotion/react @emotion/styled framer-motion react-date-range date-fns

After installing these dependencies, wrap your main app with ChakraProvider

Wrap with the provider

Complete instructions in ChakraUI Getting Started

import * as React from 'react'

// 1. import `ChakraProvider` component
import { ChakraProvider } from '@chakra-ui/react'


function App() {
  // 2. Wrap ChakraProvider at the root of your app
  return (
    <ChakraProvider>
      <TheRestOfYourApplication/>
    </ChakraProvider>
  )
}

Usage :

Form encapsulation in a single component will return the form data on submit.

// App.ts
const App: FC = () => {
  const [ data, setData ] = useState<Partial<ExampleFormFields> | null>( null )

  return (
    <ExampleForm onFormSubmit={ setData } />
  )
}

export default App

Basic example on how we declare the fields of a form.

// ExampleForm.ts
export type ExampleFormFields = {
  name: string
  email: string
}

interface ExampleFormComponentProps extends StackProps {
  data?: ExampleFormFields
  onFormSubmit: OnFormSubmit<ExampleFormFields>
}

const ExampleFormComponent: FC<ExampleFormComponentProps> = ( { data, onFormSubmit, ...props } ) => {
  const inputFields: FormFieldType<ExampleFormFields>[] = [
    {
      componentType: 'input',
      name: 'name',
      label: 'name',
      initialValue: '',
    },
    {
      componentType: 'input',
      name: 'email',
      label: 'email',
      initialValue: '',
    },
  ]

  const buttonProps = {
    children: 'Save',
  }

  const handleOnFormSubmit = async ( updatedData: ExampleFormFields ) => await onFormSubmit( updatedData )

  return (
    <FormWrapper<ExampleFormFields>
      onSubmitCb={ handleOnFormSubmit }
      { ...{ inputFields, buttonProps } }
      { ...props }
    />
  )
}

export default ExampleFormComponent

Pass additional props to the input fields

const inputFields = [
  {
    componentType: 'input',
    name: 'password',
    label: 'password',
    // pass additional props to the field to customize it
    placeholder: 'type the password',
    type: 'password',
    // The optional "helperText" let us pass tips or explanations to the user
    helperText: 'This password let the user log in securely',
    // the initialState is mandatory.
    initialValue: '',
  },
]

Validate fields and mark them as required

The form won't enable the button until all the fields marked as required are correctly set

const inputFields = [
  {
    componentType: 'input',
    name: 'email',
    label: 'email',
    initialValue: '',
    validation: {
      // We can set the field as required
      required: true,
      // We can pass an optional validator with a custom error message
      validator: {
        regEx: formValidationRgx.email,
        error: 'Invalid email format',
      },
    },
  },
]

Create textarea components

const inputFields = [
  {
    componentType: 'input',
    name: 'description',
    label: 'description',
    // we can set fields as texareas
    textarea: true,
    noOfLines: 4,
    placeholder: 'type an optional description',
    initialValue: '',
  },
]

Match fields

const inputFields = [
  {
    componentType: 'input',
    name: 'password',
    label: 'password',
    type: 'password',
    initialValue: '',
  },

  {
    name: 'repeatPassword',
    componentType: 'input',
    label: 'new password',
    helperText: 'this field should match password',
    type: 'password',
    initialValue: null,
    validation: {
      required: true,
      equalsField: {
        field: 'password',
        error: 'No match',
      },
    },
  },
]

Affect the value of other fields

Passing an onValueChange prop to modify another field or the same field by passing the value prop again

const inputFields = [
  {
    componentType: 'input',
    name: 'name',
    label: 'name',
    placeholder: 'type the name',
    // a field can affect the value of another component field
    onValueChange: ( payload ) => setSlug( slugify( payload.value ) ),
    initialValue: '',
  },

  {
    componentType: 'input',
    name: 'slug',
    label: 'slug',
    placeholder: 'type the slug',
    // a field can affect its own value
    onValueChange: ( payload ) => setSlug( slugify( payload.value ) ),
    // And then passing the custom value again as "value"
    value: slug,
  },
]

Additional built-in components


const inputFields = [
  {
    name: 'isEnabled',
    componentType: 'component',
    label: 'simple checkbox',
    helperText: 'This checkboxes can enable or disable functionality',
    initialValue: false,
    // We can use onChange to use the value outside the form
    component: (
      <CheckboxComponent onChange={ ( e ) => console.log( 'The component can still return the event ->', e ) }>
        is enabled
      </CheckboxComponent>
    ),
  },

  {
    componentType: 'component',
    name: 'date',
    initialValue: new Date(),
    label: 'date',
    helperText: 'Single date selector',
    component: <DatePickerComponent title={ 'Pick a date' } />,
    validation: {
      required: true,
    },
  },

  {
    componentType: 'component',
    name: 'rangeDate',
    initialValue: [ new Date(), new Date() ],
    label: 'start and end date',
    helperText: 'Range date selector',
    // We can handle data outside the form
    component: (
      <DateRangePickerComponent
        title={ 'pick the start and end date' }
        onChange={ ( range: [ Date, Date ] ) => console.log( 'This component returns the value ->', range ) }
      />
    ),
    validation: {
      required: true,
    },
  },
]

Creating your own React-Formatge extension components

You can create your own extension components with custom logic, it's simple! You just have to implement the CustomComponentImplementation type on your custom component like so:


import React, { FC } from 'react'
import { Checkbox, CheckboxProps } from '@chakra-ui/react'
import { CustomComponentImplementation } from '../types'

type CheckboxComponentProps = CheckboxProps & CustomComponentImplementation<boolean>

const CheckboxComponent: FC<CheckboxComponentProps> = (
  {
    value,
    onUpdateValue,
    onChange,
    defaultValue,
    ...props
  } ) => {
  
  return (
    <Checkbox
      defaultChecked={ defaultValue }
      isChecked={ value }
      onChange={ ( e ) => {
        onUpdateValue && onUpdateValue( e.target.checked )
        // preserve the default onChange events
        onChange && onChange( e )
      } }
      { ...props }
    />
  )
}

export default CheckboxComponent

Affect the button behaviour

Passing "isDisabled" to the props will let you handle and extend the conditions to disable the submit button.

  const buttonProps = {
  isDisabled: true, // any boolean logic
  children: 'Save'  // The children of the buttons can be a component or a label string
}

Overwrite default buttons

  1. Passing updating the buttonProps to hide the default component.
  2. Pass a callback to "onUpdate" to FormWrapper component to set your state
  3. Use the button state or the updated form data with custom logic

const [ formUpdate, setFormUpdate ] = useState<FormUpdatePayload<DevFormFields> | null>( null )

const buttonProps = {
  display: 'none', // 1.
}

return (
  <VStack { ...props }>
    <FormWrapper<DevFormFields>
      onSubmitCb={ handleOnFormSubmit }
      onUpdate={ setFormUpdate } // 2.
      { ...{ inputFields, buttonProps } }
    />
    <HStack w={ 'full' } justify={ 'flex-end' }>
      <Button
        colorScheme={ 'red' }
        variant={ 'ghost' }>
        Cancel
      </Button>
      <Button
        isDisabled={ !formUpdate?.isEnabled } // 3.
        onClick={ () => formUpdate && handleOnFormSubmit( formUpdate.updatedData ) } // 3.
      >
        Accept
      </Button>
    </HStack>
  </VStack>
)