diff --git a/CHANGELOG.md b/CHANGELOG.md index a554a6725b..21060d991b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,14 @@ it according to semantic versioning. For example, if your PR adds a breaking cha should change the heading of the (upcoming) version to include a major version bump. --> +# 5.14.0 + +## @rjsf/utils +- Updated `getTemplate()` to allow per-field customization using string key from `Registry`. + +## Dev / docs / playground +- Updated `advanced-customization/custom-templates` with the new feature. + # 5.13.0 ## @rjsf/antd diff --git a/packages/docs/docs/advanced-customization/custom-templates.md b/packages/docs/docs/advanced-customization/custom-templates.md index 3ed505b1dc..f1c0802f96 100644 --- a/packages/docs/docs/advanced-customization/custom-templates.md +++ b/packages/docs/docs/advanced-customization/custom-templates.md @@ -76,7 +76,7 @@ render( ); ``` -You also can provide your own field template to a uiSchema by specifying a `ui:ArrayFieldTemplate` property. +You also can provide your own field template to a uiSchema by specifying a `ui:ArrayFieldTemplate` property with your Component or a string value from the `Registry`. ```tsx import { UiSchema } from '@rjsf/utils'; @@ -162,7 +162,7 @@ render( ); ``` -You also can provide your own template to a uiSchema by specifying a `ui:ArrayFieldDescriptionTemplate` property. +You also can provide your own template to a uiSchema by specifying a `ui:ArrayFieldDescriptionTemplate` property with your Component or a string value from the `Registry`. ```tsx import { UiSchema } from '@rjsf/utils'; @@ -260,7 +260,7 @@ render( ); ``` -You also can provide your own template to a uiSchema by specifying a `ui:ArrayFieldDescriptionTemplate` property. +You also can provide your own template to a uiSchema by specifying a `ui:ArrayFieldDescriptionTemplate` property with your Component or a string value from the `Registry`. ```tsx import { UiSchema } from '@rjsf/utils'; @@ -612,7 +612,7 @@ render( ); ``` -You also can provide your own field template to a uiSchema by specifying a `ui:FieldTemplate` property. +You also can provide your own field template to a uiSchema by specifying a `ui:FieldTemplate` property with your Component or a string value from the `Registry`. ```tsx import { UiSchema } from '@rjsf/utils'; @@ -691,7 +691,7 @@ render( ); ``` -You also can provide your own field template to a uiSchema by specifying a `ui:ObjectFieldTemplate` property. +You also can provide your own field template to a uiSchema by specifying a `ui:ObjectFieldTemplate` property with your Component or a string value from the `Registry`. ```tsx import { UiSchema } from '@rjsf/utils'; diff --git a/packages/utils/src/getTemplate.ts b/packages/utils/src/getTemplate.ts index 8863df65d5..ca9733d53f 100644 --- a/packages/utils/src/getTemplate.ts +++ b/packages/utils/src/getTemplate.ts @@ -18,6 +18,17 @@ export default function getTemplate< if (name === 'ButtonTemplates') { return templates[name]; } + // Allow templates to be customized per-field by using string keys from the registry + if ( + Object.hasOwn(uiOptions, name) && + typeof uiOptions[name] === 'string' && + Object.hasOwn(templates, uiOptions[name] as string) + ) { + const key = uiOptions[name]; + // Evaluating templates[key] results in TS2590: Expression produces a union type that is too complex to represent + // To avoid that, we cast templates to `any` before accessing the key field + return (templates as any)[key]; + } return ( // Evaluating uiOptions[name] results in TS2590: Expression produces a union type that is too complex to represent // To avoid that, we cast uiOptions to `any` before accessing the name field diff --git a/packages/utils/test/getTemplate.test.ts b/packages/utils/test/getTemplate.test.ts index 7b9300475f..6d0fbedacb 100644 --- a/packages/utils/test/getTemplate.test.ts +++ b/packages/utils/test/getTemplate.test.ts @@ -86,4 +86,19 @@ describe('getTemplate', () => { expect(getTemplate(name, registry, uiOptions)).toBe(CustomTemplate); }); }); + it('returns the template from registry using uiOptions key when available', () => { + KEYS.forEach(key => { + const name = key as keyof TemplatesType; + expect( + getTemplate( + name, + registry, + Object.keys(uiOptions).reduce((uiOptions, key) => { + uiOptions[key] = key; + return uiOptions; + }, {}) + ) + ).toBe(FakeTemplate); + }); + }); });