0.33.8 • Published 26 days ago

@sagold/react-json-editor v0.33.8

Weekly downloads
-
License
MIT
Repository
-
Last release
26 days ago

Simple and extensible React component capable of using JSON Schema to declaratively build and customize user forms.

install

yarn add @sagold/react-json-editor

Npm package version Types

import { useEditor } from '@sagold/react-json-editor';
import defaultWidgets from '@sagold/rje-widgets';
import '@sagold/rje-widgets/dist/styles.css';

function MyForm({ schema, data }) {
  const [root, editor] = useEditor({
    schema,
    data,
    widgets: defaultWidgets,
    onChange: (data, state) => {
      console.log('data', data, 'root', state);
    }
  });
  const Widget = editor.getWidget(root);
  return (
    <div className="rje rje-form rje-theme rje-theme--light">
      <Widget node={root} editor={editor} />
    </div>
  );
}

useEditor Props

Only required property is a valid json-schema passed to schema.

NameTypeDescription
schemaJsonSchemajson schema describing data
cacheKeystringoptionally change key to completely recreate form
dataanyinitial data matching json schema
draftDraftConfigjson schema draft config (json-schema-library)
liveUpdatebooleanomit changes for each keystroke instead of on blur
disabledbooleantrue to disabled whole form
onChange(data, node, editor): voidchange listener for data updates
optionsextends DefaultNodeOptionsoptions to override for root widget
pluginsPlugin[]list of plugins for json editor
validatebooleanset to true to validate and show errors on create
widgetsWidgetPlugin[]list of widgets used to create user form

overview

react implementation of headless-json-editor using react-aria

widgets

A user form built with json-editor solely consists of a tree of widgets. Each widget is responsible to render a part of a json-schema.

In many cases a sub schema is completely rendered by a widget, in others they render other widgets (an object rendering properties) and sometimes a widget is used to wrap another widget (seen in oneOfSelectWidget).

So any point in data can be customized with a specific widget, improving usability, adding json-schema features or adding a fitting preview of the value, e.g. showing a url as image.

widget options

For individual widget options please refer to the storybook widget section

Each widget registers to a sub schema on which an options object can be passed directly to a widget instance. e.g.

{
  "type": "string",
  "options": {
    "title": "Unique Id",
    "disabled": true
  }
}

What follows are options that are supported by each default widget and should be supported by a custom widget:

type DefaultNodeOptions = {
  /**
   * Pass in a list of _css classes_ that should be added on the root
   * element of this widget. Use this to easily identify or style a specific
   * widget instance.
   */
  classNames?: string[];

  /**
   * description of this data point, overwrites description on sub schema
   */
  description?: string;

  /**
   * If the form at this data point should be disabled.
   * Defaults to `false`.
   */
  disabled?: boolean;

  /**
   * If the form at this data point is required. Will display a required icon.
   * Defaults to `false`.
   */
  required?: boolean;

  /**
   * Set to `true` if this form should be hidden from rendering. Usually
   * helpful to hide static variables.
   * Defaults to `false`.
   */
  hidden: boolean;

  /**
   * title of this data point, overwrites title on this sub schema
   */
  title?: string;

  /**
   * If set to false, will not render a title for this widget.
   * Defaults to `true`
   */
  showTitle: boolean;

  /**
   * If set to false, will not render a description for this widget.
   * Defaults to `true`
   */
  showDescription: boolean;
};

In addition, each widget exposes its own options. For more details refer to the storybook widget section

Options passed through component

Note that when rendering a widget using the widget decorator, options can be overriden within the rendering cycle. Thus, it is recommended to access the options from props instead of node.options.

widget registry

list of widgets that test a schema json-editor works on a list of widgets that are used to render each json sub-schema. Thus, to fully support a user form for any json-schema we will need to have a widget for any of those types, be it for a simple string { "type": "string" } or a complex object { "type": "object", "properties": { ... } }. You can also have specialized widgets for compound sub schemas, e.g. an array of strings { "type": "array", "items": { "type": "string" }}. To make this work, json-editor scans the list until of widgets until one widgets registers for the given schema.

return first matching schema With this, very general widgets (string, number, etc) are on the bottom of this list, specialized schemas (image, coordinates, etc) are on top. The first widget returning true on widget.use will be instantiated with the corresponding schema. Note that, very specialized schemas can encompass multiple subschemas and generic schemas only describe the object or array but pass actual children back to the list of widgets for rendering.

can modify test of a widget json-editor comes with a set of widgets exposed as defaultWidgets. These can completely build a user form for any possible json-data. In addtion, some more specialized widgets are exposed and some complex widgets can be added to this list. Just remember that the order is important: first to test true will be used to render the user form.

can modify list of widgets Assembling the list of widgets on your own, you can select the widgets available, the order they should be taken and also modify the actual test-function for when to use a widget:

default widgets

react-json-editor comes with a list of default widgets that cover inputs for all possible json-data as well as catching possible data errors and rendering to them into the form. Note that in some cases a specialized widget is required for a better user experience. For this you can add a any editor into the list of default widgets or replace them completely with your own widgets.

The Jsonform component add the defaultWidgets per default. If you are using useEditor hook you have to pass the defaultWidgets on your own, e.g.

import { defaultWidgets, useEditor, Widget } from '@sagold/react-json-editor';

function MyForm({ schema }) {
  const [rootNode, editor] = useEditor({ schema, widgets: defaultWidgets });
  return <Widget node={rootNode} editor={editor} />;
}

custom widgets

You can create a custom widget for any input data and add a specific function to register for a specific json-schema.

create your widget

import { widget, WidgetPlugin, StringNode } from '@sagold/react-json-editor';

const MyStringWidget = widget<StringNode, string>(({ node, options, setValue }) => (
  <input
    type="text"
    defaultValue={node.value}
    disabled={options.disabled === true}
    onChange={(e) => {
    setValue(e.target.value);
  }} />
));

In order to register the widget in react-json-editor and hook into specific json-schema a plugin wrapper is required

create a plugin wrapper for your widget

export const MyStringWidgetPlugin = {
  // a unique id is required for each widget plugin
  id: 'my-widget-plugin',
  // return true to register to this node/schema
  use: (node, options) => node.schema.type === 'string',
  // expose the widget to be rendered with this node
  Widget: MyStringWidget
};

For more details check any default widget or take a look at the additional widget packages like rje-code-widgets

validation

  • schema validations
  • custom validators

plugins

adding plugins

import { useEditor, HistoryPlugin } from '@sagold/react-json-editor';

export function Myform({ schema }) {
  const [root, editor] = useEditor({
    schema,
    plugins: [HistoryPlugin]
  });
  const Widget = editor.getWidget(root);
  return <Widget node={root} editor={editor} />;
}

or with useEditorPlugin hook

import { useEditor, useEditorPlugin, HistoryPlugin } from '@sagold/react-json-editor';

export function Myform({ schema }) {
  const [root, editor] = useEditor({ schema });
  const history = useEditorPlugin(editor, HistoryPlugin);
  const Widget = editor.getWidget(root);
  return <Widget node={root} editor={editor} />;
}

existing plugins

EventLoggerPlugin

logs every event

HistoryPlugin

undo, redo support

import { useEditor, useEditorPlugin, HistoryPlugin } from '@sagold/react-json-editor';

export function Myform({ schema }) {
  const [root, editor] = useEditor({ schema });
  const history = useEditorPlugin(editor, HistoryPlugin);
  // history?.undo();
  // history?.redo();
  // history?.history.getUndoCount();
  // history?.history.getRedoCount();
  const Widget = editor.getWidget(root);
  return <Widget node={root} editor={editor} />;
}

OnChangePlugin

callback for data changes

import { useEditorPlugin, OnChangePlugin } from '@sagold/react-json-editor';

function MyForm({ schema }) {
  const [root, editor] = useEditor({ schema });
  useEditorPlugin(editor, OnChangePlugin, {
    onChange(ast, event, editor) {
      // do something
    }
  });
  const Widget = editor.getWidget(root);
  return <Widget node={root} editor={editor} />;
}

Note that an onChangePlugin is added per default.

create custom plugin

0.33.8

26 days ago

0.33.7

1 month ago

0.33.6

2 months ago

0.33.4

2 months ago

0.33.3

2 months ago

0.33.2

2 months ago

0.33.1

2 months ago

0.33.0

2 months ago

0.32.5

2 months ago

0.32.4

2 months ago

0.32.3

2 months ago

0.32.2

2 months ago

0.32.1

2 months ago

0.32.0

2 months ago

0.31.2

2 months ago

0.31.1

2 months ago

0.31.0

2 months ago

0.30.5

2 months ago

0.30.4

2 months ago

0.30.3

2 months ago

0.30.2

2 months ago

0.30.1

7 months ago

0.30.0

8 months ago

0.29.0

9 months ago

0.27.2

10 months ago

0.28.0

9 months ago

0.27.1

10 months ago

0.27.0

10 months ago

0.29.2

9 months ago

0.26.2

1 year ago

0.26.1

1 year ago

0.26.0

1 year ago

0.25.1

1 year ago

0.25.0

1 year ago

0.21.0

1 year ago

0.20.0

1 year ago

0.24.0

1 year ago

0.23.0

1 year ago

0.21.2

1 year ago

0.22.0

1 year ago

0.21.1

1 year ago

0.10.0

2 years ago

0.19.0

1 year ago

0.19.1

1 year ago

0.19.2

1 year ago

0.11.0

2 years ago

0.9.0

2 years ago

0.8.1

2 years ago

0.12.0

2 years ago

0.8.0

2 years ago

0.7.1

2 years ago

0.13.0

2 years ago

0.12.1

2 years ago

0.14.0

2 years ago

0.15.0

2 years ago

0.16.0

2 years ago

0.15.1

2 years ago

0.17.0

2 years ago

0.15.2

2 years ago

0.7.0

2 years ago

0.18.0

1 year ago

0.6.0

2 years ago