# @wasable/react-form

> form for beable use

Latest version **1.0.0-rc.2** (published 2023-04-14) · ISC license · 0 weekly downloads

## Install

```sh
npm install @wasable/react-form
pnpm add @wasable/react-form
yarn add @wasable/react-form
bun add @wasable/react-form
```

## Health

**Score 25/100 (F)** — status: abandoned.

Positive: has types; no vulnerabilities; high quality score.

Warnings: low downloads; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.0.0-rc.2 |
| Published | 2023-04-14 |
| First published | 2023-04-14 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | bundled |
| Module format | CommonJS |
| Dependencies | 1 |
| Unpacked size | 104.7 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Beable |
| Maintainers | oyokoon |

## Links

- npm: https://www.npmjs.com/package/@wasable/react-form
- npm.io page: https://npm.io/package/@wasable/react-form

## Dependencies (1)

- [ramda](https://npm.io/package/ramda.md) ^0.27.1

## Recent versions

- 1.0.0-rc.2 (latest) — 2023-04-14

## README

# Form Usage

To use an HOC form with innerState, errors handlings and validation, an helper is available like as follows:

```js
import { classicForm } from "@wasable/react-form";
```

you need to provide it some required properties:

`initialData` : is the item to edit OR the initialData in a create Action  
`actionForm` : is the action triggered on submit, if the validation is correct

you can also provide it with an optional property:

`load` : a function that is triggered in the constructor of the form  
`returnCompleteData` : if set to true, the first parameter of the actionform function will be the full formdata, not only the modified one  
`onSubmitError` : function triggered when submit is triggered but the validation is NOK (WARNING: this is not triggered on API error ATM)

finally, an example:

```js
import { connect } from "react-redux";
import { classicForm } from "@wasable/react-form";

// Your components to wrap
import ExampleComponent from "path/to/component";

const mapStateToProps = (state) => {
  initialData: {
  } // here you store your selector or your initialData file
  returnCompleteData: false;
};

const mapDispatchToProps = () => {
  return {
    actionForm: (data) => {
      // data: is either the full data of the form or only the modified data
      // here is the main action of your form, usually an Api call for creation/update
    },
    onSubmitError: (errorList) => {
      // errorList : an array of all the text errors in your form
      // you can dispatch here an action to display a toaster, for example.
    },
    load: () => {
      // you can dispatch here an action to retrieve necessary data for your form, such as civilityList, cityList... etc.
    },
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(classicForm(ExampleComponent));
```

```js
import { HOCErrorLabel } from "@wasable/react-form";
import ComponentLabel from "./some_path_to_component";

// Utils
import { fieldDefaultPropTypes } from "./const/propTypes";
import { fieldDefaultProps } from "./const/defaultProps";

export default class ExampleComponent extends Component {
  constructor(props) {
    super(props);
    props.setValidator(/* some rules, some custom rules func */);
  }

  render() {
    const ErrorMessage = HOCErrorLabel(ComponentLabel);

    const { getValidationStatus, handleChange, formData, submit } = this.props;

    const { property_name, second_property_name } = formData;

    return (
      <>
        <div>
          <div>
            <span>Some Label</span>
            <Input
              // some props...
              value={property_name}
              onChange={(e) => handleChange("property_name", e.value)}
            />
            <ErrorMessage
              getKeysStatus={() =>
                getValidationStatus(["some_rule_name", "some_rule_name_again"])
              }
              isMulti={true}
            />
          </div>
          <div>
            <span>Some Label Again</span>
            <Input
              // some props...
              value={second_property_name}
              onChange={(e) => handleChange("second_property_name", e.value)}
            />
            <ErrorMessage
              getKeysStatus={() =>
                getValidationStatus([
                  "some_rule_name",
                  "some_rule_name_again",
                  "some_rule_name_the_prequel",
                ])
              }
              isMulti={false}
            />
          </div>
        </div>
        /* will triger the validation according to rule set in constructor after
        that, will triger actionForm (if validation OK) or (onSubmitError) */
        <button onClick={submit}>Valider</button>
      </>
    );
  }
}
```

# Validation

## Validator

The validator is a javascript class who can handle rules and validate a javascript object accordingly

_Example_

```js
import { Validator } from "@wasable/beable-form";

// some code
const rules = {
  my_strict_rules_name: {
    // the key corresponding to a given rules (default or custom)
    rule: "stricktlySameValue",
    // the property of the object to Test given to the ruleFunction in the order
    fields: ["bar", "foo"],
    // error message given if invalid
    message: "you striclty f***** something, mate !",
  },

  my_rules_name: {
    // the key corresponding to a given rules (default or custom)
    rule: "sameValue",
    // the property of the object to Test given to the ruleFunction in the order
    fields: ["foo", "bar"],
    // error message given if invalid
    message: "you f***** something, mate !",
  },
};

const rulesFunc = {
  // here we are defining a custom rules (for defaut rules given see Rules -> Native Rules
  stricktlySameValue: isStrictlySameValue,
  sameValue: isSameValue,
};

// here is the definition of the function to use in our custom rules
// note that in this exemple props1 = objectToTest.bar's value and props2 = objectToTest.foo's value
function isStrictlySameValue(props1, props2) {
  return props1 === props2;
}

// here is the definition of the function to use in our custom rules
// note that in this exemple props1 = objectToTest.foo's value and props2 = objectToTest.bar's value
function isSameValue(props1, props2) {
  return props1 == props2;
}

// create our validator with our rules and custome validation function
const exampleValidator = new Validator(rules, rulesFunc);

// --- validate Zone ---
// firstTest will be : { my_strict_rules_name: true, my_rules_name: true }
const firstTest = exampleValidator.validate({
  foo: "1",
  bar: "2",
});

// secondTest will be : { my_strict_rules_name: true }
const secondTest = exampleValidator.validate({
  foo: "1",
  bar: 1,
});

// thindTest will be : {}  because all rules are valid
const thirdTest = exampleValidator.validate({
  foo: "1",
  bar: "1",
});

// --- hasError Zone ---

// will return true
exampleValidator.hasError(
  ["my_strict_rules_name", "my_rules_name"],
  secondTest
);

// will return true
exampleValidator.hasError(["my_strict_rules_name"], secondTest);

// will return false
exampleValidator.hasError(["my_rules_name"], secondTest);

// --- getStatus Zone ---
// ---- firstTest Zone ----

// will be : ['you striclty f***** something, mate !', 'you f***** something, mate !']
exampleValidator.getStatus(
  ["my_strict_rules_name", "my_rules_name"],
  firstTest
);

// will be : ['you striclty f***** something, mate !']
exampleValidator.getStatus(["my_strict_rules_name"], firstTest);

// will be : ['you f***** something, mate !']
exampleValidator.getStatus(["my_rules_name"], firstTest);

// will be : []
exampleValidator.getStatus(["another_rule_name"], firstTest);

// ---- secondTest Zone ----

// will be : ['you striclty f***** something, mate !']
exampleValidator.getStatus(
  ["my_strict_rules_name", "my_rules_name"],
  secondTest
);

// will be : ['you striclty f***** something, mate !']
exampleValidator.getStatus(["my_strict_rules_name"], secondTest);

// errorMessages will be : []
exampleValidator.getStatus(["my_rules_name"], secondTest);

// ---- thirdTest Zone ----

// will be : []
exampleValidator.getStatus(
  ["my_strict_rules_name", "my_rules_name"],
  thirdTest
);

// will be : []
exampleValidator.getStatus(["my_strict_rules_name"], thirdTest);

// will be : []
exampleValidator.getStatus(["my_rules_name"], thirdTest);

// some code
```

## Rules

### Syntaxe

```js
const rulesList = {
  my_rules_name_1: {
    // the key corresponding to a given rules (default or custom)
    rule: "someRule",
    // the property of the object to Test given to the ruleFunction in the order
    fields: ["props1", "props2", "propsX"],
    // error message given if invalid
    message: "a message",
  },
  my_rules_name_X: {
    rule: "someRule",
    fields: ["props7", "propsX"],
    message: "a message",
  },
};
```

### Native Rules

`email` : The field under validation must be formatted as an e-mail address  
`siret` : The field under validation must be a FRENCH siret number  
`phone` : The field under validation must be a FRENCH phone number (ten numeric)  
`password` : The field under validation casted in string must contain uppercase, lowercase, number and at least eight character  
`required` : The field under validation musn't be null, undefined or empty string  
`isSame` : The fields under validation must be strictly identical (===)  
`password_repeat` : same as previous, here for backward compatibility  
`isTrue` : The field under validation must be true  
`isFalse` : The field under validation must be true

### Helpers

#### Generators

To ease the writing of rules, some helpers (called 'rulesGenerators') are available:

**generateRequiredRules**

_Description_  
will return an object containing required rules for multiple properties in your form

_Syntaxe_

```js
generateRequiredRules(fields, message);
```

_Parameters_

`fields`: Array[string] -> contain all the properties which required rule will be generated  
`message`: string -> an error message (CAUTION: this will be applied to all the rule generated in this manner), if not specified this will return '${property_name}.required'

_Return value_

a Javascript object with pair key/value -> ruleName/ruleValue (formatted defined in 'RULES')

```js
import { generateRequiredRules } from "@wasable/beable-form";

// some code

const exampleRulesJSON = generateRequiredRules([
  "my_property_1",
  "my_property_2",
  /*... */ "my_property_X",
]);

// some code
```

## HOCErrorLabel

Will give to the wrapped component an array of error message depending on the rules to watch

Property Needed:
`getKeysStatus` : a function who will return the list of message to handle (usually the return of getValidationStatus from the validationHOC)
`isMulti` : if multiple message can be returned at once

Property given to Wrapped Component:
`errorToDisplay` : an array of message to display

```js
import { HOCErrorLabel } from "@wasable/react-form";
import ComponentLabel from "./some_path_to_component";

// Utils
import { fieldDefaultPropTypes } from "./const/propTypes";
import { fieldDefaultProps } from "./const/defaultProps";

export const TextField = (props) => {
  const ErrorMessage = HOCErrorLabel(ComponentLabel);

  const { getValidationStatus } = props;

  return (
    <div>
      <ErrorMessage
        getKeysStatus={() => getValidationStatus(validationErrors)}
        isMulti={true}
      />
    </div>
  );
};
```

In this exemple, the component 'ComponentLabel', will receive an array of string (who are the corresponding message of all the rules 'watched')

---
_Source: https://npm.io/package/@wasable/react-form · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
