1.3.6 ā€¢ Published 22 hours ago

@bright-lab/tw-form v1.3.6

Weekly downloads
-
License
MIT
Repository
github
Last release
22 hours ago

npm downloads minizipped size npm latest package

ā€‹

Installation

@bright-lab/tw-form

@bright-lab/tw-form is available as an npm package

// 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}
        defaultValues={values}
        handleChange={(val: values) => console.log(val)} // returns new values on change
        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}
      defaultValues={values}
      handleChange={handleChange}
      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

PropertyTypeInitial StateExample
isErrorCallback function returns booleannull(error) => setIsError(error)
gapobjectnullrowGap: '10px', columnGap: '10px'
useCheckboxAsBooleanbooleantruefalse
darkModebooleanfalsetrue

Keys in fields

KeyTypeExampleRequiredFor
labelString or JSX ElementNameNoAll
typeStringtextYesAll
nameStringusernameYesAll
placeholderStringwrite here..NoAll
requiredBooleantrueNoAll
disabledBooleanfalseNoAll
gridObject{xs: 12, md: 6, lg: 3, xl: 2}NoAll
groupGridObject{xs: 12, md: 6, lg: 3, xl: 2}NoRadioGroup, checkboxGroup
minLengthNumber5NoText/Email/Password/Textarea
maxLengthNumber20NoText/Email/Password/Textarea
minNumber1NoNumber
maxNumber100NoNumber
rowsNumber5NoTextarea
colsNumber5NoTextarea
generatePasswordBooleantrueNoPassword
dataArray of Objects[{label: 'Cream', value:'cream'}]YesSelect, RadioGroup, checkboxGroup
contentStringbetween, around, center, endNoRadioGroup, checkboxGroup
groupColsbooleantrueNoRadioGroup, checkboxGroup
styleObject{marginBottom: '5px'}NoAll

Changelog

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

1.3.6

22 hours ago

1.3.5

8 days ago

1.3.4

11 days ago

1.3.3

11 days ago

1.3.2

12 days ago

1.3.1

12 days ago

1.3.0

13 days ago

1.2.0

1 year ago

1.1.1

1 year ago

1.1.0

1 year ago

1.1.9

1 year ago

1.1.8

1 year ago

1.0.9

1 year ago

1.1.7

1 year ago

1.0.8

1 year ago

1.1.6

1 year ago

1.0.7

1 year ago

1.1.5

1 year ago

1.1.4

1 year ago

1.1.3

1 year ago

1.1.2

1 year ago

1.0.6

1 year ago

1.0.5

1 year ago

1.0.4

1 year ago

1.0.3

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago