fix(client): improve form schema component

This commit is contained in:
chenos 2022-02-08 13:43:40 +08:00
parent 01d172e5c4
commit dd783f6554
5 changed files with 84 additions and 56 deletions

View File

@ -1,56 +1,22 @@
import { FormLayout } from '@formily/antd'; import { FormLayout } from '@formily/antd';
import { createForm, FormPath } from '@formily/core'; import { createForm } from '@formily/core';
import { import { FieldContext, FormContext, observer, useField, useFieldSchema } from '@formily/react';
FieldContext,
FormContext,
observer,
SchemaContext,
SchemaOptionsContext,
useField,
useFieldSchema
} from '@formily/react';
import { toJS } from '@formily/reactive';
import { Spin } from 'antd'; import { Spin } from 'antd';
import React, { useContext, useMemo } from 'react'; import React, { useMemo } from 'react';
import { SchemaComponent, useAttach } from '../..'; import { useAttach } from '../..';
import { useRequest } from '../../../api-client'; import { useRequest } from '../../../api-client';
type ComposedForm = React.FC<any> & {
__NOCOBASE_FORM?: boolean;
};
const useFormDecorator = () => {
const field = useField();
const options = useContext(SchemaOptionsContext);
const decorator = field.decoratorType ? FormPath.getIn(options?.components, field.decoratorType) : null;
return decorator?.__NOCOBASE_FORM ? decorator : null;
};
const FormDecorator: React.FC<any> = (props) => {
const { form } = props;
const options = useContext(SchemaOptionsContext);
const field = useField();
const fieldSchema = useFieldSchema();
const f = useAttach(form.createVoidField({ ...field.props, basePath: '' }));
const finalComponent = FormPath.getIn(options?.components, field.componentType) ?? field.componentType;
return (
<FormContext.Provider value={form}>
<SchemaContext.Provider value={fieldSchema}>
<FieldContext.Provider value={f}>
{React.createElement(finalComponent, toJS(field.componentProps))}
</FieldContext.Provider>
</SchemaContext.Provider>
</FormContext.Provider>
);
};
const FormComponent: React.FC<any> = (props) => { const FormComponent: React.FC<any> = (props) => {
const { form } = props; const { form, children, ...others } = props;
const fieldSchema = useFieldSchema(); const field = useField();
// TODO: component 里 useField 会与当前 field 存在偏差
const f = useAttach(form.createVoidField({ ...field.props, basePath: '' }));
return ( return (
<FieldContext.Provider value={undefined}> <FieldContext.Provider value={undefined}>
<FormContext.Provider value={form}> <FormContext.Provider value={form}>
<SchemaComponent schema={fieldSchema} /> <FormLayout layout={'vertical'} {...others}>
<FieldContext.Provider value={f}>{children}</FieldContext.Provider>
</FormLayout>
</FormContext.Provider> </FormContext.Provider>
</FieldContext.Provider> </FieldContext.Provider>
); );
@ -72,9 +38,8 @@ const useDefaultValues = (props: any = {}, opts: any = {}) => {
return useRequest(useRequestProps(props), opts); return useRequest(useRequestProps(props), opts);
}; };
export const Form: ComposedForm = observer((props) => { export const Form: React.FC<any> = observer((props) => {
const { request, initialValue, useValues = useDefaultValues, ...others } = props; const { request, initialValue, useValues = useDefaultValues, ...others } = props;
const decorator = useFormDecorator();
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const form = useMemo(() => createForm(), []); const form = useMemo(() => createForm(), []);
const { loading } = useValues(props, { const { loading } = useValues(props, {
@ -86,11 +51,7 @@ export const Form: ComposedForm = observer((props) => {
}); });
return ( return (
<Spin spinning={loading}> <Spin spinning={loading}>
<FormLayout layout={'vertical'} {...others}> <FormComponent form={form} {...others} />
{decorator ? <FormDecorator form={form} /> : <FormComponent form={form} />}
</FormLayout>
</Spin> </Spin>
); );
}); });
Form.__NOCOBASE_FORM = true;

View File

@ -11,7 +11,7 @@ export default observer(() => {
form1: { form1: {
type: 'void', type: 'void',
'x-decorator': 'Card', 'x-decorator': 'Card',
"x-decorator-props": { 'x-decorator-props': {
title: 'Form Title', title: 'Form Title',
}, },
'x-component': 'Form', 'x-component': 'Form',
@ -20,6 +20,7 @@ export default observer(() => {
'x-component': 'Input', 'x-component': 'Input',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
title: 'T1', title: 'T1',
required: true,
}, },
out: { out: {
'x-component': 'Output', 'x-component': 'Output',
@ -46,6 +47,7 @@ export default observer(() => {
const form = useForm(); const form = useForm();
return { return {
async run() { async run() {
await form.submit();
console.log(form.values); console.log(form.values);
}, },
}; };

View File

@ -0,0 +1,61 @@
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-decorator': 'Form',
'x-decorator-props': {
initialValue: {
field1: 'aaa',
},
},
'x-component': 'Card',
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>
);
});

View File

@ -15,7 +15,11 @@ group:
### Form Decorator ### Form Decorator
Form 也可以作 decorator 存在,和 Action.Drawer 结合就是 DrawerForm 了。 Form 也可以作 decorator 存在
<code src="./demos/demo6.tsx"/>
和 Action.Drawer 结合就是 DrawerForm 了
<code src="./demos/demo1.tsx"/> <code src="./demos/demo1.tsx"/>

View File

@ -146,8 +146,8 @@ export default function App() {
schema={{ schema={{
type: 'void', type: 'void',
name: 'page', name: 'page',
'x-decorator': 'Page', 'x-decorator': 'Form',
'x-component': 'Form', 'x-component': 'Page',
properties: { properties: {
title: { title: {
type: 'string', type: 'string',