diff --git a/packages/ui/src/fields/Array/index.tsx b/packages/ui/src/fields/Array/index.tsx index e1a72797fe..41ba5ddb76 100644 --- a/packages/ui/src/fields/Array/index.tsx +++ b/packages/ui/src/fields/Array/index.tsx @@ -32,7 +32,7 @@ import './index.scss' const baseClass = 'array-field' export type ArrayFieldProps = FormFieldBase & { - RowLabel?: React.ReactNode + CustomRowLabel?: React.ReactNode fieldMap: FieldMap forceRender?: boolean indexPath: string @@ -51,7 +51,7 @@ export const ArrayField: React.FC = (props) => { CustomDescription, CustomError, CustomLabel, - RowLabel, + CustomRowLabel, className, descriptionProps, errorProps, @@ -252,7 +252,7 @@ export const ArrayField: React.FC = (props) => { {(draggableSortableItemProps) => ( = (props) => { descriptionProps, errorProps, filterOptions, - label, labelProps, onChange, readOnly, relationTo, - required, serverURL, showError, style, diff --git a/packages/ui/src/providers/ComponentMap/buildComponentMap/mapFields.tsx b/packages/ui/src/providers/ComponentMap/buildComponentMap/mapFields.tsx index 0451a3299e..5cc03162f7 100644 --- a/packages/ui/src/providers/ComponentMap/buildComponentMap/mapFields.tsx +++ b/packages/ui/src/providers/ComponentMap/buildComponentMap/mapFields.tsx @@ -1,5 +1,12 @@ import type { FieldDescriptionProps } from '@payloadcms/ui/forms/FieldDescription' -import type { CellProps, Field, FieldWithPath, LabelProps, SanitizedConfig } from 'payload/types' +import type { + CellProps, + Field, + FieldWithPath, + LabelProps, + RowLabelComponent, + SanitizedConfig, +} from 'payload/types' import { fieldAffectsData, fieldIsPresentationalOnly } from 'payload/types' import { isPlainObject } from 'payload/utilities' @@ -80,8 +87,7 @@ export const mapFields = (args: { }` const labelProps: LabelProps = { - // @ts-expect-error-next-line - label: 'label' in field ? field.label : null, + label: 'label' in field && typeof field.label !== 'function' ? field.label : null, required: 'required' in field ? field.required : undefined, } @@ -204,23 +210,26 @@ export const mapFields = (args: { switch (field.type) { case 'array': { - let RowLabel: React.ReactNode + let CustomRowLabel: React.ReactNode if ( 'admin' in field && field.admin.components && 'RowLabel' in field.admin.components && field.admin.components.RowLabel && - !isPlainObject(field.admin.components.RowLabel) + (typeof field.admin.components.RowLabel === 'function' || + // Do this to test for client components (`use client` directive) bc they import as empty objects + (typeof field.admin.components.RowLabel === 'object' && + !isPlainObject(field.admin.components.RowLabel))) ) { - const CustomRowLabel = field.admin.components.RowLabel as React.ComponentType - RowLabel = + const CustomRowLabelComponent = field.admin.components.RowLabel as RowLabelComponent + CustomRowLabel = } const arrayFieldProps: Omit = { ...baseFieldProps, name: field.name, - RowLabel, + CustomRowLabel, className: field.admin?.className, disabled: field.admin?.disabled, fieldMap: nestedFieldMap, @@ -319,16 +328,20 @@ export const mapFields = (args: { break } case 'collapsible': { - let CollapsibleLabel: React.ReactNode + let CustomCollapsibleLabel: React.ReactNode - if (typeof field.label === 'object' && !isPlainObject(field.label)) { - const LabelToRender = field.label as unknown as React.ComponentType - CollapsibleLabel = + if ( + typeof field.label === 'function' || + // Do this to test for client components (`use client` directive) bc they import as empty objects + (typeof field.label === 'object' && !isPlainObject(field.label)) + ) { + const CustomCollapsibleLabelComponent = field.label as RowLabelComponent + CustomCollapsibleLabel = } const collapsibleField: Omit = { ...baseFieldProps, - CustomLabel: CollapsibleLabel, + CustomLabel: CustomCollapsibleLabel, className: field.admin?.className, disabled: field.admin?.disabled, fieldMap: nestedFieldMap, @@ -338,7 +351,7 @@ export const mapFields = (args: { width: field.admin?.width, } - fieldComponentProps = collapsibleField + fieldComponentProps = collapsibleField as CollapsibleFieldProps // TODO: dunno why this is needed break } case 'date': { diff --git a/test/fields/collections/Collapsible/CustomLabel/getCustomLabel.tsx b/test/fields/collections/Collapsible/CustomLabel/getCustomLabel.tsx new file mode 100644 index 0000000000..92d23f1891 --- /dev/null +++ b/test/fields/collections/Collapsible/CustomLabel/getCustomLabel.tsx @@ -0,0 +1,15 @@ +import React from 'react' + +import { CustomLabelComponent } from './index.js' + +export const getCustomLabel = ({ + fallback, + path, + style, +}: { + fallback?: string + path: string + style: React.CSSProperties +}) => { + return +} diff --git a/test/fields/collections/Collapsible/CustomLabel/index.tsx b/test/fields/collections/Collapsible/CustomLabel/index.tsx new file mode 100644 index 0000000000..cd94797c8e --- /dev/null +++ b/test/fields/collections/Collapsible/CustomLabel/index.tsx @@ -0,0 +1,21 @@ +'use client' + +import { useRowLabel } from '@payloadcms/ui/forms/RowLabel/Context' +import React from 'react' + +export const CustomLabelComponent: React.FC<{ + fallback?: string + path: string + style?: React.CSSProperties +}> = ({ + fallback = 'Untitled', + path, + style = { + color: 'hotpink', + textTransform: 'uppercase', + }, +}) => { + const { data } = useRowLabel() + + return
{data?.[path] || fallback}
+} diff --git a/test/fields/collections/Collapsible/LabelComponent.tsx b/test/fields/collections/Collapsible/LabelComponent.tsx deleted file mode 100644 index 1e7e548aa0..0000000000 --- a/test/fields/collections/Collapsible/LabelComponent.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import type { RowLabelComponent } from 'payload/types' - -import React from 'react' - -export const CollapsibleLabelComponent: RowLabelComponent = ({ data }) => { - return ( -
- {data.innerCollapsible || 'Untitled'} -
- ) -} diff --git a/test/fields/collections/Collapsible/index.ts b/test/fields/collections/Collapsible/index.ts index d65e263046..557b65a21a 100644 --- a/test/fields/collections/Collapsible/index.ts +++ b/test/fields/collections/Collapsible/index.ts @@ -1,7 +1,8 @@ import type { CollectionConfig } from 'payload/types' import { collapsibleFieldsSlug } from '../../slugs.js' -import { CollapsibleLabelComponent } from './LabelComponent.js' +import { getCustomLabel } from './CustomLabel/getCustomLabel.js' +import { CustomLabelComponent } from './CustomLabel/index.js' const CollapsibleFields: CollectionConfig = { slug: collapsibleFieldsSlug, @@ -77,7 +78,12 @@ const CollapsibleFields: CollectionConfig = { ], }, { - label: ({ data }) => data.functionTitleField || 'Custom Collapsible Label', + label: () => + getCustomLabel({ + path: 'functionTitleField', + fallback: 'Custom Collapsible Label', + style: {}, + }), type: 'collapsible', admin: { description: 'Collapsible label rendered from a function.', @@ -91,7 +97,7 @@ const CollapsibleFields: CollectionConfig = { ], }, { - label: ({ data }) => data?.componentTitleField || 'Untitled', + label: () => getCustomLabel({ path: 'componentTitleField', style: {} }), type: 'collapsible', admin: { description: 'Collapsible label rendered as a react component.', @@ -103,7 +109,8 @@ const CollapsibleFields: CollectionConfig = { }, { type: 'collapsible', - label: ({ data }) => data?.nestedTitle || 'Nested Collapsible', + label: () => + getCustomLabel({ path: 'nestedTitle', fallback: 'Nested Collapsible', style: {} }), fields: [ { type: 'text', @@ -118,7 +125,7 @@ const CollapsibleFields: CollectionConfig = { type: 'array', fields: [ { - label: CollapsibleLabelComponent, + label: CustomLabelComponent, type: 'collapsible', fields: [ { diff --git a/tsconfig.json b/tsconfig.json index bbb0643e4f..ae8b02bdd6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -37,7 +37,7 @@ ], "paths": { "@payload-config": [ - "./test/auth/config.ts" + "./test/fields/config.ts" ], "@payloadcms/ui/assets": [ "./packages/ui/src/assets/index.ts" @@ -154,4 +154,4 @@ ".next/types/**/*.ts", "scripts/**/*.ts" ] -} \ No newline at end of file +}