diff --git a/packages/core/client/src/application/hoc/withDynamicSchemaProps.tsx b/packages/core/client/src/application/hoc/withDynamicSchemaProps.tsx index df68c317b7..635a3e9de9 100644 --- a/packages/core/client/src/application/hoc/withDynamicSchemaProps.tsx +++ b/packages/core/client/src/application/hoc/withDynamicSchemaProps.tsx @@ -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, 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( const displayName = options.displayName || Component.displayName || Component.name; const ComponentWithProps: ComponentType = (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( return xUseDecoratorProps; } }, [dn]); - const useSchemaProps = useMemo(() => { - const getHook = (str: string, scope: Record, 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 }; diff --git a/packages/core/client/src/data-source/__tests__/collection-field/CollectionField.test.tsx b/packages/core/client/src/data-source/__tests__/collection-field/CollectionField.test.tsx index 92aa36fdce..007286ac8c 100644 --- a/packages/core/client/src/data-source/__tests__/collection-field/CollectionField.test.tsx +++ b/packages/core/client/src/data-source/__tests__/collection-field/CollectionField.test.tsx @@ -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 = {}) { @@ -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(''); diff --git a/packages/core/client/src/data-source/collection-field/CollectionField.tsx b/packages/core/client/src/data-source/collection-field/CollectionField.tsx index 0042a432b4..fe42188f22 100644 --- a/packages/core/client/src/data-source/collection-field/CollectionField.tsx +++ b/packages/core/client/src/data-source/collection-field/CollectionField.tsx @@ -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 ; + return ; }; export const CollectionField = connect((props) => {