feat(client): improve the form component and add more examples
This commit is contained in:
parent
dfa28983d7
commit
5acac725f9
@ -1,17 +1,18 @@
|
||||
import React, { useContext, useMemo } from 'react';
|
||||
import { toJS } from '@formily/reactive';
|
||||
import { createForm, FormPath } from '@formily/core';
|
||||
import {
|
||||
FieldContext,
|
||||
FormContext,
|
||||
FormProvider,
|
||||
observer,
|
||||
SchemaContext,
|
||||
SchemaOptionsContext,
|
||||
useField,
|
||||
useFieldSchema,
|
||||
useFieldSchema
|
||||
} from '@formily/react';
|
||||
import { toJS } from '@formily/reactive';
|
||||
import { Spin } from 'antd';
|
||||
import React, { useContext, useMemo } from 'react';
|
||||
import { SchemaComponent, useAttach } from '../..';
|
||||
import { useRequest } from '../../../api-client';
|
||||
|
||||
type ComposedForm = React.FC<any> & {
|
||||
__NOCOBASE_FORM?: boolean;
|
||||
@ -42,17 +43,47 @@ const FormDecorator: React.FC<any> = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const Form: ComposedForm = observer((props) => {
|
||||
const form = useMemo(() => createForm(), []);
|
||||
const FormComponent: React.FC<any> = (props) => {
|
||||
const { form } = props;
|
||||
const fieldSchema = useFieldSchema();
|
||||
const decorator = useFormDecorator();
|
||||
return decorator ? (
|
||||
<FormDecorator form={form} />
|
||||
) : (
|
||||
<FormContext.Provider value={form}>
|
||||
<SchemaComponent schema={fieldSchema} />
|
||||
</FormContext.Provider>
|
||||
return (
|
||||
<FieldContext.Provider value={undefined}>
|
||||
<FormContext.Provider value={form}>
|
||||
<SchemaComponent schema={fieldSchema} />
|
||||
</FormContext.Provider>
|
||||
</FieldContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const useRequestProps = (props: any) => {
|
||||
const { request, initialValue } = props;
|
||||
if (request) {
|
||||
return request;
|
||||
}
|
||||
return () => {
|
||||
return Promise.resolve({
|
||||
data: initialValue,
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const useDefaultValues = (props: any = {}, opts: any = {}) => {
|
||||
return useRequest(useRequestProps(props), opts);
|
||||
};
|
||||
|
||||
export const Form: ComposedForm = observer((props) => {
|
||||
const { useValues = useDefaultValues } = props;
|
||||
const decorator = useFormDecorator();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const form = useMemo(() => createForm(), []);
|
||||
const { loading } = useValues(props, {
|
||||
uid: fieldSchema['x-uid'],
|
||||
async onSuccess(data) {
|
||||
await form.reset();
|
||||
form.setValues(data?.data);
|
||||
},
|
||||
});
|
||||
return <Spin spinning={loading}>{decorator ? <FormDecorator form={form} /> : <FormComponent form={form} />}</Spin>;
|
||||
});
|
||||
|
||||
Form.__NOCOBASE_FORM = true;
|
||||
|
@ -0,0 +1,21 @@
|
||||
import { uid } from '@formily/shared';
|
||||
import { APIClient } from '@nocobase/client';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
|
||||
export const apiClient = new APIClient();
|
||||
|
||||
const mock = new MockAdapter(apiClient.axios);
|
||||
|
||||
const sleep = (value: number) => new Promise((resolve) => setTimeout(resolve, value));
|
||||
|
||||
mock.onGet('/posts:get').reply(async (config) => {
|
||||
await sleep(1000);
|
||||
return [
|
||||
200,
|
||||
{
|
||||
data: {
|
||||
field1: uid(),
|
||||
},
|
||||
},
|
||||
];
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { observer, ISchema } from '@formily/react';
|
||||
import { SchemaComponent, SchemaComponentProvider, Form, Action, useCloseAction } from '@nocobase/client';
|
||||
import { FormItem, Input } from '@formily/antd';
|
||||
import { ISchema, observer, useForm } from '@formily/react';
|
||||
import { Action, Form, SchemaComponent, SchemaComponentProvider, useCloseAction } from '@nocobase/client';
|
||||
import React from 'react';
|
||||
|
||||
export default observer(() => {
|
||||
const schema: ISchema = {
|
||||
@ -26,6 +26,9 @@ export default observer(() => {
|
||||
'x-decorator': 'FormItem',
|
||||
title: 'T1',
|
||||
},
|
||||
out: {
|
||||
'x-component': 'Output',
|
||||
},
|
||||
f1: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer.Footer',
|
||||
@ -45,8 +48,14 @@ export default observer(() => {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const Output = observer(() => {
|
||||
const form = useForm();
|
||||
return <pre>{JSON.stringify(form.values, null, 2)}</pre>;
|
||||
});
|
||||
|
||||
return (
|
||||
<SchemaComponentProvider scope={{ useCloseAction }} components={{ Form, Action, Input, FormItem }}>
|
||||
<SchemaComponentProvider scope={{ useCloseAction }} components={{ Output, Form, Action, Input, FormItem }}>
|
||||
<SchemaComponent schema={schema} />
|
||||
</SchemaComponentProvider>
|
||||
);
|
||||
|
@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import { observer, ISchema, useForm } from '@formily/react';
|
||||
import { SchemaComponent, SchemaComponentProvider, Form, Action } from '@nocobase/client';
|
||||
import { FormItem, Input } from '@formily/antd';
|
||||
import { ISchema, observer, useForm } from '@formily/react';
|
||||
import { Action, Form, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
|
||||
import { Card } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
export default observer(() => {
|
||||
const schema: ISchema = {
|
||||
@ -9,6 +10,10 @@ export default observer(() => {
|
||||
properties: {
|
||||
form1: {
|
||||
type: 'void',
|
||||
'x-decorator': 'Card',
|
||||
"x-decorator-props": {
|
||||
title: 'Form Title',
|
||||
},
|
||||
'x-component': 'Form',
|
||||
properties: {
|
||||
field1: {
|
||||
@ -16,6 +21,9 @@ export default observer(() => {
|
||||
'x-decorator': 'FormItem',
|
||||
title: 'T1',
|
||||
},
|
||||
out: {
|
||||
'x-component': 'Output',
|
||||
},
|
||||
action1: {
|
||||
// type: 'void',
|
||||
'x-component': 'Action',
|
||||
@ -29,6 +37,11 @@ export default observer(() => {
|
||||
},
|
||||
};
|
||||
|
||||
const Output = observer(() => {
|
||||
const form = useForm();
|
||||
return <pre>{JSON.stringify(form.values, null, 2)}</pre>;
|
||||
});
|
||||
|
||||
const useSubmit = () => {
|
||||
const form = useForm();
|
||||
return {
|
||||
@ -39,7 +52,7 @@ export default observer(() => {
|
||||
};
|
||||
|
||||
return (
|
||||
<SchemaComponentProvider scope={{ useSubmit }} components={{ Action, Form, Input, FormItem }}>
|
||||
<SchemaComponentProvider scope={{ useSubmit }} components={{ Card, Output, Action, Form, Input, FormItem }}>
|
||||
<SchemaComponent schema={schema} />
|
||||
</SchemaComponentProvider>
|
||||
);
|
||||
|
@ -0,0 +1,60 @@
|
||||
import { FormItem, Input } from '@formily/antd';
|
||||
import { ISchema, observer, useForm } from '@formily/react';
|
||||
import { Action, Form, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
|
||||
import { Card } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
export default observer(() => {
|
||||
const schema: ISchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
form1: {
|
||||
type: 'void',
|
||||
'x-component': 'Form',
|
||||
'x-component-props': {
|
||||
initialValue: {
|
||||
field1: 'aaa',
|
||||
},
|
||||
},
|
||||
properties: {
|
||||
field1: {
|
||||
'x-component': 'Input',
|
||||
'x-decorator': 'FormItem',
|
||||
title: 'T1',
|
||||
},
|
||||
out: {
|
||||
'x-component': 'Output',
|
||||
},
|
||||
action1: {
|
||||
// type: 'void',
|
||||
'x-component': 'Action',
|
||||
title: 'Submit',
|
||||
'x-component-props': {
|
||||
useAction: '{{ useSubmit }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const Output = observer(() => {
|
||||
const form = useForm();
|
||||
return <pre>{JSON.stringify(form.values, null, 2)}</pre>;
|
||||
});
|
||||
|
||||
const useSubmit = () => {
|
||||
const form = useForm();
|
||||
return {
|
||||
async run() {
|
||||
console.log(form.values);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<SchemaComponentProvider scope={{ useSubmit }} components={{ Card, Output, Action, Form, Input, FormItem }}>
|
||||
<SchemaComponent schema={schema} />
|
||||
</SchemaComponentProvider>
|
||||
);
|
||||
});
|
@ -0,0 +1,67 @@
|
||||
import { FormItem, Input } from '@formily/antd';
|
||||
import { ISchema, observer, useForm } from '@formily/react';
|
||||
import { Action, Form, SchemaComponent, SchemaComponentProvider, useCloseAction } from '@nocobase/client';
|
||||
import React from 'react';
|
||||
|
||||
export default observer(() => {
|
||||
const schema: ISchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a1: {
|
||||
type: 'void',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
},
|
||||
title: 'Open',
|
||||
properties: {
|
||||
d1: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer',
|
||||
'x-decorator': 'Form',
|
||||
'x-decorator-props': {
|
||||
initialValue: {
|
||||
field1: 'aaa',
|
||||
},
|
||||
},
|
||||
title: 'Drawer Title',
|
||||
properties: {
|
||||
field1: {
|
||||
title: 'T1',
|
||||
'x-component': 'Input',
|
||||
'x-decorator': 'FormItem',
|
||||
},
|
||||
out: {
|
||||
'x-component': 'Output',
|
||||
},
|
||||
f1: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer.Footer',
|
||||
properties: {
|
||||
a1: {
|
||||
'x-component': 'Action',
|
||||
title: 'Close',
|
||||
'x-component-props': {
|
||||
useAction: '{{ useCloseAction }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const Output = observer(() => {
|
||||
const form = useForm();
|
||||
return <pre>{JSON.stringify(form.values, null, 2)}</pre>;
|
||||
});
|
||||
|
||||
return (
|
||||
<SchemaComponentProvider scope={{ useCloseAction }} components={{ Output, Form, Action, Input, FormItem }}>
|
||||
<SchemaComponent schema={schema} />
|
||||
</SchemaComponentProvider>
|
||||
);
|
||||
});
|
106
packages/client/src/schema-component/antd/form/demos/demo5.tsx
Normal file
106
packages/client/src/schema-component/antd/form/demos/demo5.tsx
Normal file
@ -0,0 +1,106 @@
|
||||
import { FormItem, Input } from '@formily/antd';
|
||||
import { ISchema, observer, useForm } from '@formily/react';
|
||||
import {
|
||||
Action,
|
||||
APIClientProvider,
|
||||
Form,
|
||||
SchemaComponent,
|
||||
SchemaComponentProvider,
|
||||
useAPIClient
|
||||
} from '@nocobase/client';
|
||||
import { Card, Space } from 'antd';
|
||||
import React from 'react';
|
||||
import { apiClient } from './apiClient';
|
||||
|
||||
export default observer(() => {
|
||||
const schema: ISchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
form1: {
|
||||
type: 'void',
|
||||
'x-uid': 'form1',
|
||||
'x-component': 'Form',
|
||||
'x-component-props': {
|
||||
request: {
|
||||
resource: 'posts',
|
||||
action: 'get',
|
||||
},
|
||||
},
|
||||
properties: {
|
||||
field1: {
|
||||
title: 'T1',
|
||||
'x-component': 'Input',
|
||||
'x-decorator': 'FormItem',
|
||||
},
|
||||
field2: {
|
||||
title: 'T2',
|
||||
'x-component': 'Input',
|
||||
'x-decorator': 'FormItem',
|
||||
required: true,
|
||||
default: 'default value',
|
||||
},
|
||||
out: {
|
||||
'x-component': 'Output',
|
||||
},
|
||||
Space: {
|
||||
type: 'void',
|
||||
'x-component': 'Space',
|
||||
properties: {
|
||||
action2: {
|
||||
// type: 'void',
|
||||
'x-component': 'Action',
|
||||
title: 'Submit',
|
||||
'x-component-props': {
|
||||
useAction: '{{ useSubmit }}',
|
||||
},
|
||||
},
|
||||
action1: {
|
||||
// type: 'void',
|
||||
title: 'Refresh',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction: '{{ useRefresh }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const Output = observer(() => {
|
||||
const form = useForm();
|
||||
return <pre>{JSON.stringify(form.values, null, 2)}</pre>;
|
||||
});
|
||||
|
||||
const useSubmit = () => {
|
||||
const form = useForm();
|
||||
return {
|
||||
async run() {
|
||||
await form.submit();
|
||||
console.log(form.values);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const useRefresh = () => {
|
||||
const apiClient = useAPIClient();
|
||||
return {
|
||||
async run() {
|
||||
apiClient.service('form1')?.refresh();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<APIClientProvider apiClient={apiClient}>
|
||||
<SchemaComponentProvider
|
||||
scope={{ useSubmit, useRefresh }}
|
||||
components={{ Space, Card, Output, Action, Form, Input, FormItem }}
|
||||
>
|
||||
<SchemaComponent schema={schema} />
|
||||
</SchemaComponentProvider>
|
||||
</APIClientProvider>
|
||||
);
|
||||
});
|
@ -7,8 +7,26 @@ group:
|
||||
|
||||
# Form
|
||||
|
||||
## Examples
|
||||
|
||||
### 基础用法
|
||||
|
||||
<code src="./demos/demo2.tsx"/>
|
||||
|
||||
### Form Decorator
|
||||
|
||||
Form 也可以作 decorator 存在,和 Action.Drawer 结合就是 DrawerForm 了。
|
||||
|
||||
<code src="./demos/demo1.tsx"/>
|
||||
|
||||
### initialValue 初始化
|
||||
|
||||
<code src="./demos/demo3.tsx"/>
|
||||
|
||||
### decorator 的 initialValue
|
||||
|
||||
<code src="./demos/demo4.tsx"/>
|
||||
|
||||
### 远程初始化数据
|
||||
|
||||
<code src="./demos/demo5.tsx"/>
|
||||
|
Loading…
Reference in New Issue
Block a user