diff --git a/packages/payload/src/fields/config/types.ts b/packages/payload/src/fields/config/types.ts index 2f6b36ac53c..f6a534c5ec2 100644 --- a/packages/payload/src/fields/config/types.ts +++ b/packages/payload/src/fields/config/types.ts @@ -619,6 +619,8 @@ export type DateFieldClient = { export type GroupField = { admin?: { components?: { + afterInput?: CustomComponent[] + beforeInput?: CustomComponent[] Label?: CustomComponent } & Admin['components'] hideGutter?: boolean @@ -660,6 +662,8 @@ export type CollapsibleField = { | { admin: { components: { + afterInput?: CustomComponent[] + beforeInput?: CustomComponent[] Label: CustomComponent< CollapsibleFieldLabelClientComponent | CollapsibleFieldLabelServerComponent > @@ -671,6 +675,8 @@ export type CollapsibleField = { | { admin?: { components?: { + afterInput?: CustomComponent[] + beforeInput?: CustomComponent[] Label?: CustomComponent< CollapsibleFieldLabelClientComponent | CollapsibleFieldLabelServerComponent > @@ -1029,6 +1035,8 @@ type RelationshipAdmin = { allowCreate?: boolean allowEdit?: boolean components?: { + afterInput?: CustomComponent[] + beforeInput?: CustomComponent[] Error?: CustomComponent< RelationshipFieldErrorClientComponent | RelationshipFieldErrorServerComponent > @@ -1124,6 +1132,8 @@ export type RichTextFieldClient< export type ArrayField = { admin?: { components?: { + afterInput?: CustomComponent[] + beforeInput?: CustomComponent[] Error?: CustomComponent Label?: CustomComponent RowLabel?: RowLabelComponent @@ -1163,6 +1173,8 @@ export type ArrayFieldClient = { export type RadioField = { admin?: { components?: { + afterInput?: CustomComponent[] + beforeInput?: CustomComponent[] Error?: CustomComponent Label?: CustomComponent } & Admin['components'] @@ -1302,6 +1314,8 @@ export type ClientBlock = { export type BlocksField = { admin?: { components?: { + afterInput?: CustomComponent[] + beforeInput?: CustomComponent[] Error?: CustomComponent } & Admin['components'] initCollapsed?: boolean diff --git a/packages/ui/src/fields/Array/index.tsx b/packages/ui/src/fields/Array/index.tsx index 882d0c1e78b..2a6c894f79a 100644 --- a/packages/ui/src/fields/Array/index.tsx +++ b/packages/ui/src/fields/Array/index.tsx @@ -110,7 +110,7 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => { ) const { - customComponents: { Description, Error, Label, RowLabels } = {}, + customComponents: { AfterInput, BeforeInput, Description, Error, Label, RowLabels } = {}, errorPaths, rows: rowsData = [], showError, @@ -268,6 +268,7 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => { /> + {BeforeInput} {(rowsData?.length > 0 || (!valid && (showRequired || showMinRows))) && ( { {t('fields:addLabel', { label: getTranslation(labels.singular, i18n) })} )} + {AfterInput} ) } diff --git a/packages/ui/src/fields/Blocks/index.tsx b/packages/ui/src/fields/Blocks/index.tsx index f18fa109e34..2049fde90f3 100644 --- a/packages/ui/src/fields/Blocks/index.tsx +++ b/packages/ui/src/fields/Blocks/index.tsx @@ -95,7 +95,7 @@ const BlocksFieldComponent: BlocksFieldClientComponent = (props) => { ) const { - customComponents: { Description, Error, Label } = {}, + customComponents: { AfterInput, BeforeInput, Description, Error, Label } = {}, errorPaths, rows = [], showError, @@ -250,6 +250,7 @@ const BlocksFieldComponent: BlocksFieldClientComponent = (props) => { Fallback={} /> + {BeforeInput} {(rows.length > 0 || (!valid && (showRequired || showMinRows))) && ( { /> )} + {AfterInput} ) } diff --git a/packages/ui/src/fields/Collapsible/index.tsx b/packages/ui/src/fields/Collapsible/index.tsx index adfd70ec53a..b4a307fda1a 100644 --- a/packages/ui/src/fields/Collapsible/index.tsx +++ b/packages/ui/src/fields/Collapsible/index.tsx @@ -42,7 +42,7 @@ const CollapsibleFieldComponent: CollapsibleFieldClientComponent = (props) => { const [errorCount, setErrorCount] = useState(0) const fieldHasErrors = errorCount > 0 - const { customComponents: { Description, Label } = {} } = useField({ + const { customComponents: { AfterInput, BeforeInput, Description, Label } = {} } = useField({ path, }) @@ -120,6 +120,7 @@ const CollapsibleFieldComponent: CollapsibleFieldClientComponent = (props) => { id={`field-${fieldPreferencesKey}`} style={styles} > + {BeforeInput} { readOnly={readOnly} /> + {AfterInput} } diff --git a/packages/ui/src/fields/Group/index.tsx b/packages/ui/src/fields/Group/index.tsx index 9a618395587..bc8333b9d89 100644 --- a/packages/ui/src/fields/Group/index.tsx +++ b/packages/ui/src/fields/Group/index.tsx @@ -40,7 +40,8 @@ export const GroupFieldComponent: GroupFieldClientComponent = (props) => { const isWithinGroup = useGroup() const isWithinRow = useRow() const isWithinTab = useTabs() - const { customComponents: { Description, Label } = {}, errorPaths } = useField({ path }) + const { customComponents: { AfterInput, BeforeInput, Description, Label } = {}, errorPaths } = + useField({ path }) const submitted = useFormSubmitted() const errorCount = errorPaths.length const fieldHasErrors = submitted && errorCount > 0 @@ -94,6 +95,7 @@ export const GroupFieldComponent: GroupFieldClientComponent = (props) => { )} {fieldHasErrors && } + {BeforeInput} { /> + {AfterInput} ) } diff --git a/packages/ui/src/fields/Number/index.tsx b/packages/ui/src/fields/Number/index.tsx index 6e320a83ba5..c0ae6a9c0a9 100644 --- a/packages/ui/src/fields/Number/index.tsx +++ b/packages/ui/src/fields/Number/index.tsx @@ -149,6 +149,7 @@ const NumberFieldComponent: NumberFieldClientComponent = (props) => { CustomComponent={Error} Fallback={} /> + {BeforeInput} {hasMany ? ( { /> ) : (
- {BeforeInput} { type="number" value={typeof value === 'number' ? value : ''} /> - {AfterInput}
)} + {AfterInput} } diff --git a/packages/ui/src/fields/RadioGroup/index.tsx b/packages/ui/src/fields/RadioGroup/index.tsx index 66b8cddc751..db989cb6c0b 100644 --- a/packages/ui/src/fields/RadioGroup/index.tsx +++ b/packages/ui/src/fields/RadioGroup/index.tsx @@ -52,7 +52,7 @@ const RadioGroupFieldComponent: RadioFieldClientComponent = (props) => { ) const { - customComponents: { Description, Error, Label } = {}, + customComponents: { AfterInput, BeforeInput, Description, Error, Label } = {}, setValue, showError, value: valueFromContext, @@ -90,6 +90,7 @@ const RadioGroupFieldComponent: RadioFieldClientComponent = (props) => { } />
+ {BeforeInput}
    {options.map((option) => { let optionValue = '' @@ -127,6 +128,7 @@ const RadioGroupFieldComponent: RadioFieldClientComponent = (props) => { ) })}
+ {AfterInput} } diff --git a/packages/ui/src/fields/Relationship/index.tsx b/packages/ui/src/fields/Relationship/index.tsx index 7c346dc5a26..bbfa1dece3c 100644 --- a/packages/ui/src/fields/Relationship/index.tsx +++ b/packages/ui/src/fields/Relationship/index.tsx @@ -100,7 +100,7 @@ const RelationshipFieldComponent: RelationshipFieldClientComponent = (props) => ) const { - customComponents: { Description, Error, Label } = {}, + customComponents: { AfterInput, BeforeInput, Description, Error, Label } = {}, filterOptions, initialValue, setValue, @@ -603,6 +603,7 @@ const RelationshipFieldComponent: RelationshipFieldClientComponent = (props) => CustomComponent={Error} Fallback={} /> + {BeforeInput} {!errorLoading && (
)} {errorLoading &&
{errorLoading}
} + {AfterInput} } diff --git a/test/admin/collections/CustomFields/index.ts b/test/admin/collections/CustomFields/index.ts index 09562839a9a..122a39941df 100644 --- a/test/admin/collections/CustomFields/index.ts +++ b/test/admin/collections/CustomFields/index.ts @@ -73,5 +73,119 @@ export const CustomFields: CollectionConfig = { }, }, }, + { + name: 'relationshipFieldWithBeforeAfterInputs', + type: 'relationship', + admin: { + components: { + afterInput: ['/collections/CustomFields/AfterInput.js#AfterInput'], + beforeInput: ['/collections/CustomFields/BeforeInput.js#BeforeInput'], + }, + }, + relationTo: 'posts', + }, + { + name: 'arrayFieldWithBeforeAfterInputs', + type: 'array', + admin: { + components: { + afterInput: ['/collections/CustomFields/AfterInput.js#AfterInput'], + beforeInput: ['/collections/CustomFields/BeforeInput.js#BeforeInput'], + }, + }, + fields: [ + { + name: 'someTextField', + type: 'text', + }, + ], + }, + { + name: 'blocksFieldWithBeforeAfterInputs', + type: 'blocks', + admin: { + components: { + afterInput: ['/collections/CustomFields/AfterInput.js#AfterInput'], + beforeInput: ['/collections/CustomFields/BeforeInput.js#BeforeInput'], + }, + }, + blocks: [ + { + slug: 'blockFields', + fields: [ + { + name: 'textField', + type: 'text', + }, + ], + }, + ], + }, + { + label: 'Collapsible Field With Before & After Inputs', + type: 'collapsible', + admin: { + components: { + afterInput: ['/collections/CustomFields/AfterInput.js#AfterInput'], + beforeInput: ['/collections/CustomFields/BeforeInput.js#BeforeInput'], + }, + description: 'This is a collapsible field.', + initCollapsed: false, + }, + fields: [ + { + name: 'text', + type: 'text', + }, + ], + }, + { + name: 'groupFieldWithBeforeAfterInputs', + type: 'group', + admin: { + components: { + afterInput: ['/collections/CustomFields/AfterInput.js#AfterInput'], + beforeInput: ['/collections/CustomFields/BeforeInput.js#BeforeInput'], + }, + }, + fields: [ + { + name: 'textOne', + type: 'text', + }, + { + name: 'textTwo', + type: 'text', + }, + ], + }, + { + name: 'radioFieldWithBeforeAfterInputs', + label: { + en: 'Radio en', + es: 'Radio es', + }, + type: 'radio', + admin: { + components: { + afterInput: ['/collections/CustomFields/AfterInput.js#AfterInput'], + beforeInput: ['/collections/CustomFields/BeforeInput.js#BeforeInput'], + }, + }, + options: [ + { + label: { en: 'Value One', es: 'Value Uno' }, + value: 'one', + }, + { + label: 'Value Two', + value: 'two', + }, + { + label: 'Value Three', + value: 'three', + }, + ], + }, ], }