npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@microsoft/fast-form-generator-react

v3.8.0

Published

A self generating user interface based on JSON Schemas.

Downloads

105

Readme

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.