@bright-lab/tw-form
TypeScript icon, indicating that this package has built-in type declarations

1.4.6 • Public • Published

Bright Lab logo


Bright Lab TW Form

npm downloads minizipped size npm latest package

Installation

@bright-lab/tw-form

@bright-lab/tw-form is available as an [npm package] (https://www.npmjs.org/package/@bright-lab/tw-form)

// with npm
npm install @bright-lab/tw-form

// with yarn
yarn add @bright-lab/tw-form

What is so powerful about the TW-Form ?

This Form is so smart that it will handle everything for you, as well as you can style your own inputs, custom components, error validation and responsiveness!

Getting started with @bright-lab/tw-form

Here is an example of a basic app using @bright-lab/tw-form:

in App.tsx, Import the required css file.

import '@bright-lab/tw-form/css';

in Form.tsx for example, we will import useState, DynamicForm and start adding the required fields.

import React, { useState } from 'react';
import { DynamicForm, DynamicFields } from '@bright-lab/tw-form';

const fields: DynamicFields = [
  {
    label: 'Email',
    type: 'email',
    name: 'email',
    required: true,
    grid: {
      xs: 12,
      md: 6,
    },
  },
  {
    label: 'Password',
    type: 'password',
    name: 'password',
    required: true,
    grid: {
      xs: 12,
      md: 6,
    },
  },
  {
    label: 'Nationality',
    type: 'select',
    name: 'nationality',
    data: [
      {
        title: 'Lebanon',
        value: 'Lebanon',
      },
      {
        title: 'Spain',
        value: 'Spain',
      },
    ],
    grid: {
      xs: 12,
    },
  },
  {
    label: 'seperator',
    type: 'seperator',
    name: 'seperator',
  },
  {
    label: 'Gender',
    type: 'radioGroup',
    name: 'gender',
    content: 'between',
    data: [
      {
        label: 'Male',
        value: 'male',
      },
      {
        label: 'Female',
        value: 'female',
      },
    ],
    grid: {
      xs: 12,
      md: 6,
    },
  },
  {
    label: 'Software',
    type: 'checkboxGroup',
    name: 'software',
    content: 'between',
    data: [
      {
        label: 'Adobe',
        value: 'Adobe',
      },
      {
        label: 'VSCode',
        value: 'VSCode',
      },
    ],
    grid: {
      xs: 12,
      md: 6,
    },
  },
  {
    label: 'Married?',
    type: 'checkbox',
    name: 'married',
    grid: {
      xs: 12,
      md: 6,
    },
  },
  {
    label: 'Kids',
    type: 'number',
    name: 'kids',
    min: 0,
    required: true,
    grid: {
      xs: 12,
      md: 6,
    },
  },
  {
    label: 'Hobbies',
    type: 'chips',
    name: 'hobbies',
    grid: {
      xs: 12,
      md: 6,
    },
  },
];

Now Let's validate the form.

const validation = {
  email: (value: string) => {
    if (value?.trim()?.length === 0) {
      return 'Email is required';
    }
    if (!/\S+@\S+\.\S+/.test(value)) {
      return 'Email is invalid';
    }
    return '';
  },
  password: (value: string) => {
    if (value?.length < 8) {
      return 'Password is shorter than the minimum length (8)';
    }

    return '';
  },
};

Finally, Let's add the default values and return the Dynamic Form.

type values = {
  name: string,
  email: string,
  password: string,
  married: boolean,
  gender: string,
  nationality: string,
  kids: number,
  hobbies: string[],
};

const [values, setValues] = useState({
  name: '',
  email: '',
  password: '',
  married: false,
  gender: 'male',
  nationality: 'Lebanon',
  kids: 0,
  hobbies: ['basketball', 'football'],
});

const [isError, setIsError] = useState(false);

return (
  <div>
    <h1>Dynamic Form</h1>
    <div className="max-w-[800px] mx-auto bg-slate-50 p-5">
      <DynamicForm
        fields={fields}
        values={values}
        setValues={setValues}
        validation={validation}
        isError={(error) => setIsError(error)} //returns boolean
      />
      <button disabled={isError}>Submit</button>
    </div>
  </div>
);

Here's an example on how to add Custom Fields.

  {
    label: 'file',
    type: 'custom',
    name: 'image',
    Component: (customValue: File, customOnChange: () => void,  errors: Record<string, string>, expectedErrors: Record<string, string>) => {
      return <File value={customValue} onChange={customOnChange} errors={errors} expectedErrors={expectedErrors} />;
    },
    grid: {
      xs: 12,
      md: 6,
    },
  },


  const [values, setValues] = useState({
  name: '',
  email: '',
  drink: ''
});

File Component would look like this for example:

interface Props {
  onChange: (value: string) => void;
  value: string;
  errors: Record<string, string>;
  expectedErrors: Record<string, string>;
  handleBlur: (e: React.ChangeEvent<HTMLInputElement>) => void;
}

const Drink: React.FC<Props> = ({
  onChange,
  value,
  errors,
  expectedErrors,
}) => {
  return (
    <>
      <input
        type="text"
        name="drink"
        value={value}
        onChange={(e) => {
          onChange(e.target.value);
        }}
        onBlur={handleBlur} // error validation on blur
      />
      {errors?.drink && 'error in drinks'}
    </>
  );
};

export default File;

Show errors when submitting the form.

Import useRef and DynamicRef Type

import { useRef } from 'react';
import { DynamicForm, DynamicRef } from '@bright-lab/tw-form';

Add the reference to the DynamicForm component, a submit button, and let's handle the functionality.

 const dynamicFormRef = useRef<DynamicRef>();

const handleSubmit = () => {
  if (isError) {
    return dynamicFormRef.current?.onSubmit();
  }
 console.log('no errors')
};

return (
  <>
    <DynamicForm
      ref={dynamicFormRef}
      fields={fields}
      values={values}
      setValues={setValues}
      validation={validation}
      isError={(error) => setIsError(error)}
      gap={{ rowGap: '3px', columnGap: '3px' }}
    />

    <button
      onClick={handleSubmit}
    >
      Submit
    </button>
  </>
);

CSS Styling

:root {
  --tw-label-text-color: #000;
  --tw-label-text-size: 1rem;
  --tw-input-bg-color: #fefefe;
  --tw-input-text-color: #4b5563;
  --tw-input-text-size: 1rem;
  --tw-input-border-color: #d1d5db;
  --tw-input-border-focus-color: #475569;
  --tw-input-border-radius: 0.5rem;
  --tw-input-padding: 0.5rem 0.7rem;
  --tw-input-error-border-color: #ef4444;
  --tw-input-error-text-color: #ef4444;
  --tw-input-radio-checked-color: dodgerblue;
  --tw-input-checkbox-checked-color: dodgerblue;
  --tw-input-select-arrow-color: #999;
  --tw-chips-add-btn-color: dodgerblue;
  --tw-chips-dlt-btn-color: #475569;
  --tw-chips-selected-bg-color: #e2e8f0;
}

Additional Props

Property Type Initial State Example
isError Callback function returns boolean null (error) => setIsError(error)
gap object null rowGap: '10px', columnGap: '10px'
useCheckboxAsBoolean boolean true false
darkMode boolean false true

Keys in fields

Key Type Example Required For
label String or JSX Element Name No All
type String text Yes All
name String username Yes All
placeholder String write here.. No All
required Boolean true No All
disabled Boolean false No All
grid Object {xs: 12, md: 6, lg: 3, xl: 2} No All
groupGrid Object {xs: 12, md: 6, lg: 3, xl: 2} No RadioGroup, checkboxGroup
minLength Number 5 No Text/Email/Password/Textarea
maxLength Number 20 No Text/Email/Password/Textarea
min Number 1 No Number
max Number 100 No Number
rows Number 5 No Textarea
cols Number 5 No Textarea
generatePassword Boolean true No Password
data Array of Objects [{label: 'Cream', value:'cream'}] Yes Select, RadioGroup, checkboxGroup
content String between, around, center, end No RadioGroup, checkboxGroup
groupCols boolean true No RadioGroup, checkboxGroup
style Object {marginBottom: '5px'} No All

Changelog

The changelog is regularly updated to reflect what's changed in each new release.

Package Sidebar

Install

npm i @bright-lab/tw-form

Weekly Downloads

59

Version

1.4.6

License

MIT

Unpacked Size

121 kB

Total Files

19

Last publish

Collaborators

  • chrissakiki
  • sergemassaad
  • charlesdaccache