From a6f13f73308b84af7d380ee390eac9561f587fb5 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Thu, 12 Sep 2024 14:45:17 -0400 Subject: [PATCH] fix(ui): properly extracts label from field in FieldLabel component (#8190) Although the `` component receives a `field` prop, it does not use this prop to extract the `label` from the field. This is currently only an issue when rendering this component directly, such as within `admin.components.Label`. The label simply won't appear unless explicitly provided, despite it being passed as `field.label`. This is not an issue when rendering field components themselves, because they properly thread this value through as a top-level prop. Here's an example of the issue: ```tsx import type { TextFieldLabelServerComponent } from 'payload' import { FieldLabel } from '@payloadcms/ui' import React from 'react' export const MyCustomLabelComponent: TextFieldLabelServerComponent = ({ clientField }) => { return ( ) } ``` Here is the end result: ```tsx import type { TextFieldLabelServerComponent } from 'payload' import { FieldLabel } from '@payloadcms/ui' import React from 'react' export const MyCustomLabelComponent: TextFieldLabelServerComponent = ({ clientField }) => { return } ``` --- packages/payload/src/admin/forms/Label.ts | 4 ++-- packages/richtext-lexical/src/field/Field.tsx | 9 +-------- .../richtext-slate/src/field/RichText.tsx | 9 +-------- .../TableColumns/buildColumnState.tsx | 9 +-------- packages/ui/src/fields/Array/index.tsx | 2 -- packages/ui/src/fields/Blocks/index.tsx | 2 -- packages/ui/src/fields/Code/index.tsx | 8 +------- packages/ui/src/fields/DateTime/index.tsx | 8 +------- packages/ui/src/fields/Email/index.tsx | 8 +------- packages/ui/src/fields/FieldLabel/index.tsx | 20 +++++++++++++++++-- packages/ui/src/fields/JSON/index.tsx | 8 +------- packages/ui/src/fields/Number/index.tsx | 8 +------- packages/ui/src/fields/Point/index.tsx | 1 + packages/ui/src/fields/RadioGroup/index.tsx | 8 +------- packages/ui/src/fields/Relationship/index.tsx | 9 +-------- packages/ui/src/fields/Select/Input.tsx | 2 +- packages/ui/src/fields/Select/index.tsx | 2 -- packages/ui/src/fields/Text/index.tsx | 2 -- packages/ui/src/fields/Text/types.ts | 2 +- packages/ui/src/fields/Textarea/index.tsx | 2 -- packages/ui/src/fields/Textarea/types.ts | 2 +- packages/ui/src/fields/Upload/Input.tsx | 2 +- packages/ui/src/fields/Upload/index.tsx | 2 -- test/fields/collections/Email/CustomLabel.tsx | 6 ++++-- 24 files changed, 39 insertions(+), 96 deletions(-) diff --git a/packages/payload/src/admin/forms/Label.ts b/packages/payload/src/admin/forms/Label.ts index d7c35d583..6c5d7ddd1 100644 --- a/packages/payload/src/admin/forms/Label.ts +++ b/packages/payload/src/admin/forms/Label.ts @@ -1,5 +1,5 @@ import type { ServerProps, StaticLabel } from '../../config/types.js' -import type { ClientField, Field } from '../../fields/config/types.js' +import type { Field } from '../../fields/config/types.js' import type { MappedComponent } from '../types.js' import type { ClientFieldWithOptionalType } from './Field.js' @@ -27,7 +27,7 @@ export type FieldLabelServerProps< } & GenericLabelProps & Partial -export type SanitizedLabelProps = Omit< +export type SanitizedLabelProps = Omit< FieldLabelClientProps, 'label' | 'required' > diff --git a/packages/richtext-lexical/src/field/Field.tsx b/packages/richtext-lexical/src/field/Field.tsx index cdbfc4bb8..c209e5aee 100644 --- a/packages/richtext-lexical/src/field/Field.tsx +++ b/packages/richtext-lexical/src/field/Field.tsx @@ -41,7 +41,6 @@ const RichTextComponent: React.FC< style, width, } = {}, - label, required, }, field, @@ -101,13 +100,7 @@ const RichTextComponent: React.FC< {...(errorProps || {})} alignCaret="left" /> - +
{}}> = (props) => { style, width, } = {}, - label, required, }, labelProps, @@ -321,13 +320,7 @@ const RichTextField: React.FC = (props) => { width, }} > - +
{ ? field.admin.components.Label : undefined - const Label = ( - - ) + const Label = const fieldAffectsDataSubFields = field && diff --git a/packages/ui/src/fields/Array/index.tsx b/packages/ui/src/fields/Array/index.tsx index be1f4eada..ec10fef05 100644 --- a/packages/ui/src/fields/Array/index.tsx +++ b/packages/ui/src/fields/Array/index.tsx @@ -239,8 +239,6 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => { as="span" field={field} Label={field?.admin?.components?.Label} - label={label} - required={required} unstyled {...(labelProps || {})} /> diff --git a/packages/ui/src/fields/Blocks/index.tsx b/packages/ui/src/fields/Blocks/index.tsx index 5c0fdb784..8d63de676 100644 --- a/packages/ui/src/fields/Blocks/index.tsx +++ b/packages/ui/src/fields/Blocks/index.tsx @@ -231,8 +231,6 @@ const BlocksFieldComponent: BlocksFieldClientComponent = (props) => { as="span" field={field} Label={field?.admin?.components?.Description} - label={label} - required={required} unstyled {...(labelProps || {})} /> diff --git a/packages/ui/src/fields/Code/index.tsx b/packages/ui/src/fields/Code/index.tsx index 8a4f2074f..02b59ef96 100644 --- a/packages/ui/src/fields/Code/index.tsx +++ b/packages/ui/src/fields/Code/index.tsx @@ -83,13 +83,7 @@ const CodeFieldComponent: CodeFieldClientComponent = (props) => { width, }} > - +
{ width, }} > - +
{ width, }} > - +
= (props) => { export const FieldLabel: FieldLabelClientComponent = (props) => { const { Label, ...rest } = props + // Don't get `Label` from `field.admin.components.Label` here because + // this will cause an infinite loop when threading field through custom usages of `FieldLabel` if (Label) { return } - return + return ( + + ) } diff --git a/packages/ui/src/fields/JSON/index.tsx b/packages/ui/src/fields/JSON/index.tsx index e04b95fa7..5dbbf31de 100644 --- a/packages/ui/src/fields/JSON/index.tsx +++ b/packages/ui/src/fields/JSON/index.tsx @@ -133,13 +133,7 @@ const JSONFieldComponent: JSONFieldClientComponent = (props) => { width, }} > - +
{ width, }} > - +
{
  • diff --git a/packages/ui/src/fields/RadioGroup/index.tsx b/packages/ui/src/fields/RadioGroup/index.tsx index 876061b57..ac7278052 100644 --- a/packages/ui/src/fields/RadioGroup/index.tsx +++ b/packages/ui/src/fields/RadioGroup/index.tsx @@ -99,13 +99,7 @@ const RadioGroupFieldComponent: RadioFieldClientComponent = (props) => { {...(errorProps || {})} alignCaret="left" /> - +
      {options.map((option) => { diff --git a/packages/ui/src/fields/Relationship/index.tsx b/packages/ui/src/fields/Relationship/index.tsx index 68360b50b..0853a9fdf 100644 --- a/packages/ui/src/fields/Relationship/index.tsx +++ b/packages/ui/src/fields/Relationship/index.tsx @@ -55,7 +55,6 @@ const RelationshipFieldComponent: RelationshipFieldClientComponent = (props) => width, } = {}, hasMany, - label, relationTo, required, }, @@ -602,13 +601,7 @@ const RelationshipFieldComponent: RelationshipFieldClientComponent = (props) => width, }} > - +
      readonly name: string readonly onChange?: ReactSelectAdapterProps['onChange'] diff --git a/packages/ui/src/fields/Select/index.tsx b/packages/ui/src/fields/Select/index.tsx index 5866d7cea..d6e4d7fc6 100644 --- a/packages/ui/src/fields/Select/index.tsx +++ b/packages/ui/src/fields/Select/index.tsx @@ -44,7 +44,6 @@ const SelectFieldComponent: SelectFieldClientComponent = (props) => { width, } = {} as SelectFieldClientProps['field']['admin'], hasMany = false, - label, options: optionsFromProps = [], required, }, @@ -111,7 +110,6 @@ const SelectFieldComponent: SelectFieldClientComponent = (props) => { isClearable={isClearable} isSortable={isSortable} Label={field?.admin?.components?.Label} - label={label} name={name} onChange={onChange} options={options} diff --git a/packages/ui/src/fields/Text/index.tsx b/packages/ui/src/fields/Text/index.tsx index 42a0bbc20..5c4b16f5b 100644 --- a/packages/ui/src/fields/Text/index.tsx +++ b/packages/ui/src/fields/Text/index.tsx @@ -33,7 +33,6 @@ const TextFieldComponent: TextFieldClientComponent = (props) => { width, } = {}, hasMany, - label, localized, maxLength, maxRows, @@ -131,7 +130,6 @@ const TextFieldComponent: TextFieldClientComponent = (props) => { hasMany={hasMany} inputRef={inputRef} Label={field?.admin?.components?.Label} - label={label} maxRows={maxRows} minRows={minRows} onChange={ diff --git a/packages/ui/src/fields/Text/types.ts b/packages/ui/src/fields/Text/types.ts index b25672a34..009ae9c20 100644 --- a/packages/ui/src/fields/Text/types.ts +++ b/packages/ui/src/fields/Text/types.ts @@ -27,7 +27,7 @@ export type TextInputProps = { readonly field?: MarkOptional readonly inputRef?: React.RefObject readonly Label?: MappedComponent - readonly label: StaticLabel + readonly label?: StaticLabel readonly labelProps?: Record readonly maxRows?: number readonly minRows?: number diff --git a/packages/ui/src/fields/Textarea/index.tsx b/packages/ui/src/fields/Textarea/index.tsx index 5a941fe0a..e2640399c 100644 --- a/packages/ui/src/fields/Textarea/index.tsx +++ b/packages/ui/src/fields/Textarea/index.tsx @@ -35,7 +35,6 @@ const TextareaFieldComponent: TextareaFieldClientComponent = (props) => { style, width, } = {}, - label, localized, maxLength, minLength, @@ -91,7 +90,6 @@ const TextareaFieldComponent: TextareaFieldClientComponent = (props) => { Error={field?.admin?.components?.Error} errorProps={errorProps} Label={field?.admin?.components?.Label} - label={label} labelProps={labelProps} onChange={(e) => { setValue(e.target.value) diff --git a/packages/ui/src/fields/Textarea/types.ts b/packages/ui/src/fields/Textarea/types.ts index a764f058b..b135b35c4 100644 --- a/packages/ui/src/fields/Textarea/types.ts +++ b/packages/ui/src/fields/Textarea/types.ts @@ -24,7 +24,7 @@ export type TextAreaInputProps = { readonly field?: MarkOptional readonly inputRef?: React.RefObject readonly Label?: MappedComponent - readonly label: StaticLabel + readonly label?: StaticLabel readonly labelProps?: FieldLabelClientProps> readonly onChange?: (e: ChangeEvent) => void readonly onKeyDown?: React.KeyboardEventHandler diff --git a/packages/ui/src/fields/Upload/Input.tsx b/packages/ui/src/fields/Upload/Input.tsx index 843a48c64..7f6315c50 100644 --- a/packages/ui/src/fields/Upload/Input.tsx +++ b/packages/ui/src/fields/Upload/Input.tsx @@ -63,7 +63,7 @@ export type UploadInputProps = { readonly hasMany?: boolean readonly isSortable?: boolean readonly Label?: MappedComponent - readonly label: StaticLabel + readonly label?: StaticLabel readonly labelProps?: FieldLabelClientProps> readonly maxRows?: number readonly onChange?: (e) => void diff --git a/packages/ui/src/fields/Upload/index.tsx b/packages/ui/src/fields/Upload/index.tsx index 219ac5354..7189b3bf3 100644 --- a/packages/ui/src/fields/Upload/index.tsx +++ b/packages/ui/src/fields/Upload/index.tsx @@ -21,7 +21,6 @@ export function UploadComponent(props: UploadFieldClientProps) { _path, admin: { className, isSortable, readOnly: readOnlyFromAdmin, style, width } = {}, hasMany, - label, maxRows, relationTo, required, @@ -70,7 +69,6 @@ export function UploadComponent(props: UploadFieldClientProps) { hasMany={hasMany} isSortable={isSortable} Label={field?.admin?.components?.Label} - label={label} maxRows={maxRows} onChange={setValue} path={path} diff --git a/test/fields/collections/Email/CustomLabel.tsx b/test/fields/collections/Email/CustomLabel.tsx index 630bf4ac1..e0e2af4aa 100644 --- a/test/fields/collections/Email/CustomLabel.tsx +++ b/test/fields/collections/Email/CustomLabel.tsx @@ -1,12 +1,14 @@ 'use client' +import type { EmailFieldClientComponent } from 'payload' + import { useFieldProps } from '@payloadcms/ui' import React from 'react' -export const CustomLabel = ({ schemaPath }) => { +export const CustomLabel: EmailFieldClientComponent = ({ field }) => { const { path: pathFromContext } = useFieldProps() - const path = pathFromContext ?? schemaPath // pathFromContext will be undefined in list view + const path = pathFromContext ?? field?._schemaPath // pathFromContext will be undefined in list view return (