chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,380 @@
|
||||
# Schema Form
|
||||
|
||||
## Introduction
|
||||
|
||||
A React component capable of building HTML forms out of a [JSON schema](https://json-schema.org/understanding-json-schema/index.html).
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
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
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```ts
|
||||
export interface UISchema {
|
||||
[key: string]: {
|
||||
'ui:widget'?: UIWidget;
|
||||
'ui:options'?: UIOptions;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### UIWidget
|
||||
|
||||
```ts
|
||||
export type UIWidget =
|
||||
| 'textarea'
|
||||
| 'input'
|
||||
| 'checkbox'
|
||||
| 'radio'
|
||||
| 'select'
|
||||
| 'upload'
|
||||
| 'timezone'
|
||||
| 'switch'
|
||||
| 'legend'
|
||||
| 'button';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### UIOptions
|
||||
|
||||
```ts
|
||||
export type UIOptions =
|
||||
| InputOptions
|
||||
| SelectOptions
|
||||
| UploadOptions
|
||||
| SwitchOptions
|
||||
| TimezoneOptions
|
||||
| CheckboxOptions
|
||||
| RadioOptions
|
||||
| TextareaOptions
|
||||
| ButtonOptions;
|
||||
```
|
||||
|
||||
#### BaseUIOptions
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```ts
|
||||
export interface InputOptions extends BaseUIOptions {
|
||||
placeholder?: string;
|
||||
inputType?:
|
||||
| 'color'
|
||||
| 'date'
|
||||
| 'datetime-local'
|
||||
| 'email'
|
||||
| 'month'
|
||||
| 'number'
|
||||
| 'password'
|
||||
| 'range'
|
||||
| 'search'
|
||||
| 'tel'
|
||||
| 'text'
|
||||
| 'time'
|
||||
| 'url'
|
||||
| 'week';
|
||||
}
|
||||
```
|
||||
|
||||
#### SelectOptions
|
||||
|
||||
```ts
|
||||
export interface SelectOptions extends UIOptions {}
|
||||
```
|
||||
|
||||
#### UploadOptions
|
||||
|
||||
```ts
|
||||
export interface UploadOptions extends BaseUIOptions {
|
||||
acceptType?: string;
|
||||
imageType?: Type.UploadType;
|
||||
}
|
||||
```
|
||||
|
||||
#### SwitchOptions
|
||||
|
||||
```ts
|
||||
export interface SwitchOptions extends BaseUIOptions {
|
||||
label?: string;
|
||||
}
|
||||
```
|
||||
|
||||
#### TimezoneOptions
|
||||
|
||||
```ts
|
||||
export interface TimezoneOptions extends UIOptions {
|
||||
placeholder?: string;
|
||||
}
|
||||
```
|
||||
|
||||
#### CheckboxOptions
|
||||
|
||||
```ts
|
||||
export interface CheckboxOptions extends UIOptions {}
|
||||
```
|
||||
|
||||
#### RadioOptions
|
||||
|
||||
```ts
|
||||
export interface RadioOptions extends UIOptions {}
|
||||
```
|
||||
|
||||
#### TextareaOptions
|
||||
|
||||
```ts
|
||||
export interface TextareaOptions extends UIOptions {
|
||||
placeholder?: string;
|
||||
rows?: number;
|
||||
}
|
||||
```
|
||||
|
||||
#### ButtonOptions
|
||||
|
||||
```ts
|
||||
export interface ButtonOptions extends BaseUIOptions {
|
||||
text: string;
|
||||
icon?: string;
|
||||
action?: UIAction;
|
||||
variant?: ButtonProps['variant'];
|
||||
size?: ButtonProps['size'];
|
||||
}
|
||||
```
|
||||
|
||||
#### UIAction
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```ts
|
||||
export interface FormKit {
|
||||
refreshConfig(): void;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### FormData
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
- [json schema](https://json-schema.org/understanding-json-schema/index.html)
|
||||
- [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form)
|
||||
- [vue-json-schema-form](https://github.com/lljj-x/vue-json-schema-form/)
|
||||
Reference in New Issue
Block a user