@microsoft/fast-form-generator-react
TypeScript icon, indicating that this package has built-in type declarations

3.8.0 • Public • Published

FAST Form generator React

FAST Form generator React has been deprecated. Use FAST Tooling React instead.

A self generating UI based on JSON Schemas.

Dynamically generates a form user interface based on incoming JSON Schemas to change data values of a React component.

Installing

npm i --save @microsoft/fast-form-generator-react

Basic usage


The required properties are the data, schema, and onChange function. The data should be tied to your state as the data will change when editing the form.

import Form from "@microsoft/fast-form-generator-react";

/**
 * Add to your render function
 */
<Form
    data={this.state.currentComponentData}
    schema={currentComponentSchema}
    onChange={handleChange}
/>

onChange

The onChange is used as a callback, it should take one argument that is the data that should be updated when any data has been changed from within the generated form.

Data and data mapping

Component data passed to the form generator as plain data, there is a mapDataToComponent export from the package which converts any children data to executable React components. It is required that any component that would be mapped from data should be supplied in the childOptions prop.

Example onChange:

import { mapDataToComponent } from "@microsoft/fast-form-generator-react";

/**
 * The app on change event
 */
onChange = (data) => {
    this.setState({
        currentComponentData: mapDataToComponent(data)
    });
}

Simple data

Where the component is a button and the data being passed to the onChange is:

{
    "disabled": true,
    "children": "Button text"
}

Data with component children

Where the component contains a button and the data being passed to the onChange is:

Example data:

{
    "children": {
        "id": "button",
        "props": {
            "disabled": true
        }
    }
}

The id corresponds to the components' JSON schema id and the props corresponds to the data being passed to the component.

Advanced usage


Outside of the basic use case you can provide some additional functionality through optional properties.

plugins and onSchemaChange

Plugins may be created to determine if a form should change based on data. You can identify a piece of schema that should be updated by adding a unique key to your JSON schema formPluginId. When you initialize a custom plugin you will need to pass that same id to the plugin as part of its configuration.

Example schema:

{
    "$schema": "http://json-schema.org/schema#",
    "id": "my-component",
    "title": "My component",
    "type": "object",
    "properties": {
        "text": {
            "title": "Text",
            "type": "string",
            "example": "Hello world",
            "formPluginId": "my-custom-plugin-identifier"
        },
        "weight": {
            "title": "Weight",
            "type": "string",
            "enum": [
                "heavy",
                "medium",
                "light"
            ]
        }
    },
    "required": [
        "text"
    ]
}

Example plugin which returns an unmodified schema, unless the weight property has been specified, then the options become specific to the data:

import { FormPlugin, FormPluginProps } from "@microsoft/fast-form-generator-react";

export class MyCustomSchemaPlugin extends FormPlugin {
    resolver(schema, data) {
        switch (data.weight) {
            case "heavy":
                return Object.assign({}, schema, { enum: ["heavy text 1", "heavy text 2"] });
            case "medium":
                return Object.assign({}, schema, { enum: ["medium text 1", "medium text 2"] });
            case "light":
                return Object.assign({}, schema, { enum: ["light text 1", "light text 2"] });
        }

        return schema;
    }
}

Example implementation with the Form:

Note: When the plugins are used the schema tied to the Form should be set to a state so that it can be kept up-to-date, you will need to use the onSchemaChange callback which will return the newly updated schema.

import Form from "@microsoft/fast-form-generator-react";
import { Button, ButtonSchema } from "@microsoft/fast-components-react-msft";
import { MyCustomSchemaPlugin } from "./my-custom-schema-plugin";

<Form
    data={this.state.currentComponentData}
    schema={this.state.currentComponentSchema}
    onChange={handleChange}
    onSchemaChange={handleSchemaChange}
    plugins={[
        new MyCustomSchemaPlugin({
            id: ["my-custom-plugin-identifier"]
        })
    ]}
/>

childOptions

Children by default only include text elements. If you want to add some child components you are providing, you can do this through the childOptions.

import Form from "@microsoft/fast-form-generator-react";
import { Button, ButtonSchema } from "@microsoft/fast-components-react-msft";

<Form
    data={this.state.currentComponentData}
    schema={currentComponentSchema}
    onChange={handleChange}
    childOptions={[
        {
            name: "Button",
            component: Button,
            schema: ButtonSchema
        }
    ]}
/>

location

The location prop allows the user to control which piece of JSON schema the form is pointing to and has two required properties. It takes dataLocation which is the location of the data to be edited, and onChange which will fire an update when the user performs an action on the form that would change the visible data to be edited. An example of this would be clicking on an array item to edit that item.

import Form from "@microsoft/fast-form-generator-react";

<Form
    data={this.state.currentComponentData}
    schema={currentComponentSchema}
    onChange={handleChange}
    location={{
        dataLocation: this.state.dataLocation,
        onChange: this.handleChange
    }}
/>

// example method to use for the location onChange
handleChange = (dataLocation) => {
    this.setState({
        dataLocation: dataLocation
    });
}

componentMappingToPropertyNames - There are special components that can be mapped to property names so that they are used. An example would be alignHorizontal which when mapped will show alignment controls instead of a select dropdown. You can map them to one or more different property names so if your component has a property alignHorizontalSpacingForTitle and alignHorizontalSpacingForImage:

import Form from "@microsoft/fast-form-generator-react";

<Form
    data={this.state.currentComponentData}
    schema={currentComponentSchema}
    onChange={handleChange}
    componentMappingToPropertyNames={{
        alignHorizontal: [
            "alignHorizontalSpacingForTitle",
            "alignHorizontalSpacingForImage"
        ]
    }}
/>

attributeSettingsMappingToPropertyNames - The attributes of a form item can be mapped to by this prop. An example of updating the textarea row to be 1 when the property name is text:

import Form from "@microsoft/fast-form-generator-react";

<Form
    data={this.state.currentComponentData}
    schema={currentComponentSchema}
    onChange={handleChange}
    attributeSettingsMappingToPropertyNames={{
        textarea: {
            rows: [
                {
                    propertyNames: ["text"],
                    value: 1
                }
            ]
        }
    }
/>

orderByPropertyNames - Properties can be assigned a category with titles to give the form more structure. They can also be weighted, an example of displaying properties related to content on top of properties which relate to formatting:

This also tells the form generator to only display categories once there are 4 or more and gives a default category weight

import Form from "@microsoft/fast-form-generator-react";

<Form
    data={this.state.currentComponentData}
    schema={currentComponentSchema}
    onChange={handleChange}
    orderByPropertyNames={{
        showCategoriesAtPropertyCount: 4,
        defaultCategoryWeight: 20,
        categories: [
            {
                title: "Content",
                weight: 50,
                properties: [
                    { weight: 5, propertyName: ["title, text"] },
                    { weight: 0, propertyName: "details" }
                ]
            },
            {
                title: "Formatting",
                weight: 40,
                properties: [
                    { weight: 9, propertyName: "alignVertical" },
                    { weight: 7, propertyName: "alignHorizontal" }
                ]
            }
        ]
    }}
/>

Writing JSON Schemas

The schema form generator can interpret most JSON schemas, however there are some things to note when writing JSON schemas that make for a better UI.

title

Using a title will add a label to the left or top of the corresponding form element. All properties are required to have a title.

Example:

{
    "$schema": "http://json-schema.org/schema#",
    "id": "my-component",
    "title": "My component",
    "type": "object",
    "properties": {
        "text": {
            "title": "Text",
            "type": "string",
            "example": "Hello world"
        },
        "weight": {
            "title": "Weight",
            "type": "string",
            "enum": [
                "heavy"
            ]
        }
    },
    "required": [
        "text"
    ]
}

disabled

Disabled flag is optional and item will be disabled if flag is set to true.

Example:

{
    "$schema": "http://json-schema.org/schema#",
    "id": "my-component",
    "title": "My component",
    "type": "object",
    "properties": {
        "text": {
            "title": "Text",
            "type": "string",
            "example": "Hello world",
            "disabled": true
        }
    },
    "required": [
        "text"
    ]
}

examples & default

Providing an example or default value will replace the placeholder 'example text' or randomly generated number. It is generally better to add this extra information in case the schema form generator needs to create a new set of data.

Example:

{
    "$schema": "http://json-schema.org/schema#",
    "id": "my-component",
    "title": "My component",
    "type": "object",
    "properties": {
        "text": {
            "title": "Text",
            "type": "string",
            "example": "Hello world"
        },
        "style": {
            "title": "Style",
            "type": "object",
            "properties": {
                "color": {
                    "title": "HEX Color",
                    "type": "string",
                    "example": "#FF0000"
                }
            },
            "required": [
                "color"
            ]
        }
    },
    "required": [
        "text"
    ]
}

Because the style is optional, you can toggle to add it. The schema form generator will see that color is a required piece of data and use the example given to fill in.

oneOf & anyOf

The oneOf and anyOf keywords can be used inside a property and at the root level of a schema. This will create a select dropdown so that the user can switch between them. If data has been provided, it will select the first oneOf/anyOf instance it can validate against. The contents of a 'title' property will be used for the contents of the dropdown.

Example:

{
    "$schema": "http://json-schema.org/schema#",
    "id": "my-component",
    "title": "My component",
    "oneOf": [
        {
            "title": "color",
            "type": "object",
            "properties": {
                "color": {
                    "title": "HEX Color",
                    "type": "string",
                    "example": "#FF0000"
                }
            }
        },
        {
            "title": "text",
            "type": "object",
            "properties": {
                "text": {
                    "title": "Text",
                    "type": "string",
                    "example": "Hello world"
                }
            }
        }
    ]
}

Enums

Any enums will be converted to a select dropdown.

{
    "$schema": "http://json-schema.org/schema#",
    "id": "my-component",
    "title": "My component",
    "type": "object",
    "properties": {
        "color": {
            "title": "Color",
            "type": "string",
            "enum" : [
                "red",
                "green",
                "blue",
                "yellow"
            ],
            "default": "red"
        }
    }
}

React children

React children are treated as special objects instead of simple properties and can be defined in an object as reactProperties. They can specify ids from the given childOptions and can be given defaults, currently there is one default text. If no ids are specified all childOptions are considered valid.

Example of an object that includes children with specific ids and the text default:

{
    "$schema": "http://json-schema.org/schema#",
    "id": "my-component",
    "title": "My component",
    "type": "object",
    "properties": {
        "color": {
            "title": "Color",
            "type": "string"
        }
    },
    "reactProperties": {
        "children": {
            "title": "Components",
            "type": "children",
            "ids": [
                "my-component",
                "my-button-component"
            ],
            "defaults": [
                "text"
            ]
        }
    }
}

Type object

The object type will create its own section which can be navigated to via a link that is created on its parent object. Once it has been navigated to, breadcrumbs will appear above allowing the user to navigate back to the parent object.

Keywords that cannot be interpreted

allOf & $ref

The allOf and $ref keywords cannot be interpreted by the schema form generator. To allow for most of the functionality there is a tool inside the @microsoft/fast-permutator which will simplify the schema and merge allOf arrays when it finds them, see simplifySchemas.

Readme

Keywords

none

Package Sidebar

Install

npm i @microsoft/fast-form-generator-react

Weekly Downloads

3

Version

3.8.0

License

MIT

Unpacked Size

234 kB

Total Files

134

Last publish

Collaborators

  • microsoft1es
  • fastsvc
  • chrisdholt
  • awentzel
  • janechu
  • fluentweb
  • nirice