fix: collection field support x-use-component-props (#4264)

* fix: collection field support x-use-component-props

* fix: bug

* fix: bug
This commit is contained in:
jack zhang 2024-05-09 09:21:58 +08:00 committed by GitHub
parent 1e5e015b73
commit 2014729e01
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 80 additions and 36 deletions

View File

@ -12,7 +12,47 @@ import React, { ComponentType, useMemo } from 'react';
import { useDesignable } from '../../schema-component';
import _ from 'lodash';
const useDefaultSchemaProps = () => undefined;
const useDefaultDynamicComponentProps = () => undefined;
const getHook = (str: string, scope: Record<string, any>, allText: string) => {
let res = undefined;
if (_.isFunction(str)) {
res = str;
} else {
res = scope[str];
if (!res) {
console.error(`${allText} is not registered`);
}
}
return res || useDefaultDynamicComponentProps;
};
export function useDynamicComponentProps(useComponentPropsStr?: string, props?: any) {
const scope = useExpressionScope();
const useDynamicProps = useMemo(() => {
if (!useComponentPropsStr) {
return useDefaultDynamicComponentProps;
}
if (_.isFunction(useComponentPropsStr)) {
return useComponentPropsStr;
}
const pathList = useComponentPropsStr.split('.');
let result;
for (const item of pathList) {
result = getHook(item, result || scope, useComponentPropsStr);
}
return result;
}, [useComponentPropsStr]);
const res = useDynamicProps(props);
return res;
}
interface WithSchemaHookOptions {
displayName?: string;
@ -25,7 +65,6 @@ export function withDynamicSchemaProps<T = any>(
const displayName = options.displayName || Component.displayName || Component.name;
const ComponentWithProps: ComponentType<T> = (props) => {
const { dn, findComponent } = useDesignable();
const scope = useExpressionScope();
const useComponentPropsStr = useMemo(() => {
const xComponent = dn.getSchemaAttribute('x-component');
const xDecorator = dn.getSchemaAttribute('x-decorator');
@ -40,38 +79,7 @@ export function withDynamicSchemaProps<T = any>(
return xUseDecoratorProps;
}
}, [dn]);
const useSchemaProps = useMemo(() => {
const getHook = (str: string, scope: Record<string, any>, allText: string) => {
let res = undefined;
if (_.isFunction(str)) {
res = str;
} else {
res = scope[str];
if (!res) {
console.error(`${allText} is not registered`);
}
}
return res || useDefaultSchemaProps;
};
if (!useComponentPropsStr) {
return useDefaultSchemaProps;
}
if (_.isFunction(useComponentPropsStr)) {
return useComponentPropsStr;
}
const pathList = useComponentPropsStr.split('.');
let result;
for (const item of pathList) {
result = getHook(item, result || scope, useComponentPropsStr);
}
return result;
}, [scope, useComponentPropsStr]);
const schemaProps = useSchemaProps(props);
const schemaProps = useDynamicComponentProps(useComponentPropsStr, props);
const memoProps = useMemo(() => {
return { ...props, ...schemaProps };

View File

@ -34,8 +34,34 @@ function renderApp(fieldName: string, components = {}) {
reverseKey: null,
};
const useCustomDynamicProps = () => {
return {
addonBefore: 'addonBefore',
};
};
const dynamicPropsSchema = {
key: 'dynamic-props',
name: 'dynamic-props',
type: 'string',
interface: 'select',
description: null,
collectionName: 't_vwpds9fs4xs',
parentKey: null,
reverseKey: null,
uiSchema: {
type: 'string',
'x-component': 'Input',
'x-component-props': {
placeholder: 'placeholder',
},
'x-use-component-props': 'useCustomDynamicProps',
},
};
const usersCollection: any = collections[0];
usersCollection.fields.push(noUiSchema);
usersCollection.fields.push(dynamicPropsSchema);
const app = new Application({
dataSourceManager: {
@ -61,6 +87,7 @@ function renderApp(fieldName: string, components = {}) {
<CollectionProvider name="users">
<SchemaComponent
schema={schema}
scope={{ useCustomDynamicProps }}
components={{ CollectionField: CollectionField, FormItem, Input, ...components }}
/>
</CollectionProvider>
@ -86,6 +113,12 @@ describe('CollectionField', () => {
expect(document.querySelector('.input-test-1')).toHaveTextContent('nickname');
});
it('useComponentProps', () => {
renderApp('dynamic-props');
expect(document.querySelector('.ant-input')).toHaveAttribute('placeholder', 'placeholder');
expect(screen.queryByText('addonBefore')).toBeInTheDocument();
});
it('no schema', () => {
renderApp('no-ui-schema');
expect(document.querySelector('.ant-formily-item-control-content-component')).toHaveTextContent('');

View File

@ -16,6 +16,7 @@ import { useFormBlockContext } from '../../block-provider/FormBlockProvider';
import { useCompile, useComponent } from '../../schema-component';
import { useIsAllowToSetDefaultValue } from '../../schema-settings/hooks/useIsAllowToSetDefaultValue';
import { CollectionFieldProvider, useCollectionField } from './CollectionFieldProvider';
import { useDynamicComponentProps } from '../../application/hoc';
type Props = {
component: any;
@ -49,6 +50,8 @@ export const CollectionFieldInternalField: React.FC = (props: Props) => {
}, [fieldSchema, uiSchema]);
const ctx = useFormBlockContext();
const dynamicProps = useDynamicComponentProps(uiSchema?.['x-use-component-props'], props);
useEffect(() => {
if (ctx?.field) {
ctx.field.added = ctx.field.added || new Set();
@ -82,12 +85,12 @@ export const CollectionFieldInternalField: React.FC = (props: Props) => {
// @ts-ignore
field.dataSource = uiSchema.enum;
const originalProps = compile(uiSchema['x-component-props']) || {};
field.componentProps = merge(originalProps, field.componentProps || {});
field.componentProps = merge(originalProps, field.componentProps || {}, dynamicProps || {});
}, [uiSchema]);
if (!uiSchema) return null;
return <Component {...props} />;
return <Component {...props} {...dynamicProps} />;
};
export const CollectionField = connect((props) => {