1.0.6 • Published 8 months ago

react-dynamic-fields-core v1.0.6

Weekly downloads
-
License
MIT
Repository
-
Last release
8 months ago

react-dynamic-fields-core

react-dynamic-fields-core is a dynamic library for creating flexible, condition-based forms in React. Define field schemas, handle field conditions, and manage form states effortlessly.


Features

  • Dynamic Form Rendering: Build forms based on a JSON schema.
  • Field Conditions: Automatically manage field rules (e.g., disabled, hidden) based on other fields' states.
  • Custom Rendering: Supports custom rendering of field components.
  • Centralized State Management: Manage form states efficiently.
  • TypeScript Support: Fully typed for a robust developer experience.

Installation

Install the package using npm or yarn:

npm install react-dynamic-fields-core

or

yarn add react-dynamic-fields-core

Usage

1. Import the Required Components

import {
  ReactDynamicField,
  ReactDynamicFields,
  ReactDynamicFieldsProvider,
  ReactDynamicFieldsSchema,
} from "react-dynamic-fields-core";

2. Define a Field Schema

A field schema specifies form fields, their rules, and conditional logic.

const fieldsSchema: ReactDynamicFieldsSchema = [
  {
    fieldType: "string",
    fieldName: "title",
    placeholder: "Заголовок",
    defaultValue: "",
    style: { width: "600px" },
    rules: {
      required: false,
      maxLength: undefined,
      hidden: false,
      disabled: false,
      minLength: undefined,
    },
    fieldConditions: [
      {
        otherFieldName: "select-to-disable",
        comparison: "includesInObject",
        value: "title",
        action: {
          rules: {
            disabled: true,
          },
          styles: {
            style: { width: "100px" },
            className: "",
          },
        },
      },
    ],
  },
  {
    fieldType: "string",
    fieldName: "summary",
    placeholder: "Summary",
    rules: {},
    defaultValue: "",
    fieldConditions: [
      {
        otherFieldName: "select-to-disable",
        comparison: "includesInObject",
        value: "summary",
        action: {
          rules: {
            disabled: true,
          },
        },
      },
    ],
  },
  {
    defaultValue: {},
    fieldType: "select",
    fieldName: "cities",
    placeholder: "Города",
    rules: {},
    options: [],
    fetchOptions: async () => {
      const response = await fetch(
        "https://countriesnow.space/api/v0.1/countries/population/cities"
      );
      const data = await response.json();
      return { data: data.data };
    },
    labelFieldName: "country",
    valueFieldName: "city",
    fieldConditions: [
      {
        otherFieldName: "select-to-disable",
        comparison: "includesInObject",
        value: "cities",
        action: {
          rules: {
            disabled: true,
          },
        },
      },
    ],
  },
];

const fieldsSchemaExtended: ReactDynamicFieldsSchema = [
  {
    defaultValue: {},
    fieldType: "select",
    fieldName: "select-to-disable",
    placeholder: "Select field you want to disable",
    rules: {},
    fieldConditions: [],
    options: fieldsSchema as unknown as Record<string, string>[],
    labelFieldName: "placeholder",
    valueFieldName: "fieldName",
  },
  ...fieldsSchema,
];

3. Render the Form

const stateName = "state";

export function ReactDynamicFieldsExample() {
  return (
    <>
      <ReactDynamicFieldsProvider>
        <ReactDynamicFields
          stateName={stateName}
          renderSchema={({ controller }) => {
            return (
              <form
                onSubmit={(e) => {
                  e.preventDefault();
                  controller.submit({ fieldsSchema: fieldsSchemaExtended });
                  console.log(controller.getValues());
                }}
              >
                {fieldsSchemaExtended.map((fieldSchema, index) => {
                  return (
                    <ReactDynamicField
                      key={index}
                      renderFields={({ fieldName }) => {
                        return {
                          input: ({
                            actionProperties: { rules, styles },
                            value,
                            fieldErrorMessage,
                          }) => {
                            return (
                              <>
                                <input
                                  style={styles?.style || fieldSchema.style}
                                  disabled={rules.disabled}
                                  maxLength={rules.maxLength}
                                  minLength={rules.minLength}
                                  defaultValue={value || ""}
                                  className="border"
                                  value={value || ""}
                                  placeholder={fieldSchema.placeholder}
                                  onChange={(e) => {
                                    const value = e.target.value;
                                    controller.updateFieldValue({
                                      fieldName,
                                      value,
                                    });
                                  }}
                                />
                                {fieldErrorMessage}
                              </>
                            );
                          },
                          select: ({
                            loading,
                            value,
                            options,
                            fieldErrorMessage,
                            labelFieldName,
                            valueFieldName,
                            actionProperties: { rules, styles },
                          }) => {
                            if (value == null) return;
                            if (loading) return "fetching...";

                            return (
                              <>
                                <select
                                  style={styles?.style}
                                  disabled={rules.disabled}
                                  defaultValue={value.value}
                                  name={value.value}
                                  id={value.value}
                                  onChange={(e) => {
                                    const value = e.target.value;
                                    const option = options.find(
                                      (option) =>
                                        option?.[valueFieldName] === value
                                    );
                                    if (!option) return;
                                    controller.updateFieldValue({
                                      fieldName,
                                      value: option,
                                    });
                                  }}
                                >
                                  {options.map((option, index) => {
                                    const value = option?.[valueFieldName];
                                    const label = option?.[labelFieldName];
                                    return (
                                      <option
                                        key={index + " " + value}
                                        value={value}
                                      >
                                        {label}
                                      </option>
                                    );
                                  })}
                                </select>
                                {fieldErrorMessage}
                              </>
                            );
                          },
                        };
                      }}
                      fieldSchema={fieldSchema}
                      stateName={stateName}
                    />
                  );
                })}

                <button type="submit">submit</button>
              </form>
            );
          }}
        />
      </ReactDynamicFieldsProvider>
    </>
  );
}

Props

ReactDynamicFields

PropTypeDescription
stateNamestringUnique identifier for form state.
renderSchemafunctionFunction to render the form schema.

ReactDynamicField

PropTypeDescription
fieldSchemaobjectSchema for a single field.
stateNamestringIdentifier for managing field state.
renderFieldsfunctionFunction to render field components.

Schema Structure

A schema object can contain the following properties:

KeyTypeDescription
fieldTypestringType of the field (string, select).
fieldNamestringUnique field name.
placeholderstringPlaceholder text for the field.
defaultValueanyDefault value for the field.
rulesobjectValidation rules (e.g., required).
fieldConditionsarrayConditional logic for field rules.
optionsarray (for select)Options for dropdown fields.

Example fieldConditions:

{
  "otherFieldName": "other-field",
  "comparison": "equals",
  "value": "disabled",
  "action": {
    "rules": {
      "disabled": true
    }
  }
}

License

MIT


Contributions

Contributions are welcome! Open an issue or submit a pull request to improve the library.

1.0.6

8 months ago

1.0.5

8 months ago

1.0.4

8 months ago

1.0.3

8 months ago

1.0.2

8 months ago

1.0.1

8 months ago

1.0.0

8 months ago