tree: ac70c8ea91691982b045b329e2730d1a69d50c5a [path history] [tgz]
  1. components/
  2. index.tsx
  3. README.md
  4. types.ts
ui/src/components/SchemaForm/README.md

Schema Form

Introduction

A React component capable of building HTML forms out of a JSON schema.

Usage

import React, { useState } from 'react';

import {
  SchemaForm,
  initFormData,
  JSONSchema,
  UISchema,
  FormKit,
} from '@/components';

const schema: JSONSchema = {
  title: 'General',
  properties: {
    name: {
      type: 'string',
      title: 'Name',
    },
    age: {
      type: 'number',
      title: 'Age',
    },
    sex: {
      type: 'string',
      title: 'sex',
      enum: [1, 2],
      enumNames: ['male', 'female'],
    },
  },
};

const uiSchema: UISchema = {
  name: {
    'ui:widget': 'input',
  },
  age: {
    'ui:widget': 'input',
    'ui:options': {
      type: 'number',
    },
  },
  sex: {
    'ui:widget': 'radio',
  },
};

const Form = () => {
  const [formData, setFormData] = useState(initFormData(schema));

  const formRef = useRef<{
    validator: () => Promise<boolean>;
  }>(null);

  const refreshConfig: FormKit['refreshConfig'] = async () => {
    // refreshFormConfig();
  };

  const handleChange = (data) => {
    setFormData(data);
  };

  return (
    <SchemaForm
      ref={formRef}
      schema={schema}
      uiSchema={uiSchema}
      formData={formData}
      onChange={handleChange}
      refreshConfig={refreshConfig}
    />
  );
};

export default Form;

Form Props

interface FormProps {
  // Describe the form structure with schema
  schema: JSONSchema | null;
  // Describe the properties of the field
  uiSchema?: UISchema;
  // Describe form data
  formData: Type.FormDataType | null;
  // Callback function when form data changes
  onChange?: (data: Type.FormDataType) => void;
  // Handler for when a form fires a `submit` event
  onSubmit?: (e: React.FormEvent) => void;
  /**
   * Callback method for updating form configuration
   * information (schema/uiSchema) in UIAction
   */
  refreshConfig?: FormKit['refreshConfig'];
}

Form Ref

export interface FormRef {
  validator: () => Promise<boolean>;
}

When you need to validate a form and get the result outside the form, you can create a FormRef with useRef and pass it to the form using the ref property.

This allows you to validate the form and get the result outside the form using formRef.current.validator().


Types Definition

JSONSchema

export interface JSONSchema {
  title: string;
  description?: string;
  required?: string[];
  properties: {
    [key: string]: {
      type: 'string' | 'boolean' | 'number';
      title: string;
      label?: string;
      description?: string;
      enum?: Array<string | boolean | number>;
      enumNames?: string[];
      default?: string | boolean | number;
    };
  };
}

UISchema

export interface UISchema {
  [key: string]: {
    'ui:widget'?: UIWidget;
    'ui:options'?: UIOptions;
  };
}

UIWidget

export type UIWidget =
  | 'textarea'
  | 'input'
  | 'checkbox'
  | 'radio'
  | 'select'
  | 'upload'
  | 'timezone'
  | 'switch'
  | 'legend'
  | 'button';

UIOptions

export type UIOptions =
  | InputOptions
  | SelectOptions
  | UploadOptions
  | SwitchOptions
  | TimezoneOptions
  | CheckboxOptions
  | RadioOptions
  | TextareaOptions
  | ButtonOptions;

BaseUIOptions

export interface BaseUIOptions {
  empty?: string;
  // Will be appended to the className of the form component itself
  className?: classnames.Argument;
  class_name?: classnames.Argument;
  // The className that will be attached to a form field container
  field_class_name?: classnames.Argument;
  // Make a form component render into simplified mode
  readOnly?: boolean;
  simplify?: boolean;
  validator?: (
    value,
    formData?,
  ) => Promise<string | true | void> | true | string;
}

InputOptions

export interface InputOptions extends BaseUIOptions {
  placeholder?: string;
  inputType?:
    | 'color'
    | 'date'
    | 'datetime-local'
    | 'email'
    | 'month'
    | 'number'
    | 'password'
    | 'range'
    | 'search'
    | 'tel'
    | 'text'
    | 'time'
    | 'url'
    | 'week';
}

SelectOptions

export interface SelectOptions extends UIOptions {}

UploadOptions

export interface UploadOptions extends BaseUIOptions {
  acceptType?: string;
  imageType?: Type.UploadType;
}

SwitchOptions

export interface SwitchOptions extends BaseUIOptions {
  label?: string;
}

TimezoneOptions

export interface TimezoneOptions extends UIOptions {
  placeholder?: string;
}

CheckboxOptions

export interface CheckboxOptions extends UIOptions {}

RadioOptions

export interface RadioOptions extends UIOptions {}

TextareaOptions

export interface TextareaOptions extends UIOptions {
  placeholder?: string;
  rows?: number;
}

ButtonOptions

export interface ButtonOptions extends BaseUIOptions {
  text: string;
  icon?: string;
  action?: UIAction;
  variant?: ButtonProps['variant'];
  size?: ButtonProps['size'];
}

UIAction

export interface UIAction {
  url: string;
  method?: 'get' | 'post' | 'put' | 'delete';
  loading?: {
    text: string;
    state?: 'none' | 'pending' | 'completed';
  };
  on_complete?: {
    toast_return_message?: boolean;
    refresh_form_config?: boolean;
  };
}

FormKit

export interface FormKit {
  refreshConfig(): void;
}

FormData

export interface FormValue<T = any> {
  value: T;
  isInvalid: boolean;
  errorMsg: string;
  [prop: string]: any;
}

export interface FormDataType {
  [prop: string]: FormValue;
}

Backend API

For backend generating modal form you can return json like this.

Response

{
  "name": "string",
  "slug_name": "string",
  "description": "string",
  "version": "string",
  "config_fields": [
    {
      "name": "string",
      "type": "textarea",
      "title": "string",
      "description": "string",
      "required": true,
      "value": "string",
      "ui_options": {
        "placeholder": "placeholder",
        "rows": 4
      },
      "options": [
        {
          "value": "string",
          "label": "string"
        }
      ]
    }
  ]
}

reference