diff --git a/docs/admin/fields.mdx b/docs/admin/fields.mdx index 0af47f73f..c330f6569 100644 --- a/docs/admin/fields.mdx +++ b/docs/admin/fields.mdx @@ -347,31 +347,13 @@ Custom Label Components receive all [Field Component](#the-field-component) prop #### TypeScript -When building Custom Label Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Label Component, one for every [Field Type](../fields/overview). The convention is to append `LabelComponent` to the type of field, i.e. `TextFieldLabelComponent`. +When building Custom Label Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Label Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `LabelServerComponent` or `LabelClientComponent` to the type of field, i.e. `TextFieldLabelClientComponent`. ```tsx import type { - ArrayFieldLabelComponent, - BlocksFieldLabelComponent, - CheckboxFieldLabelComponent, - CodeFieldLabelComponent, - CollapsibleFieldLabelComponent, - DateFieldLabelComponent, - EmailFieldLabelComponent, - GroupFieldLabelComponent, - HiddenFieldLabelComponent, - JSONFieldLabelComponent, - NumberFieldLabelComponent, - PointFieldLabelComponent, - RadioFieldLabelComponent, - RelationshipFieldLabelComponent, - RichTextFieldLabelComponent, - RowFieldLabelComponent, - SelectFieldLabelComponent, - TabsFieldLabelComponent, - TextFieldLabelComponent, - TextareaFieldLabelComponent, - UploadFieldLabelComponent + TextFieldLabelServerComponent, + TextFieldLabelClientComponent, + // And so on for each Field Type } from 'payload' ``` @@ -410,31 +392,13 @@ Custom Error Components receive all [Field Component](#the-field-component) prop #### TypeScript -When building Custom Error Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Error Component, one for every [Field Type](../fields/overview). The convention is to append `ErrorComponent` to the type of field, i.e. `TextFieldErrorComponent`. +When building Custom Error Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Error Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `ErrorServerComponent` or `ErrorClientComponent` to the type of field, i.e. `TextFieldErrorClientComponent`. ```tsx import type { - ArrayFieldErrorComponent, - BlocksFieldErrorComponent, - CheckboxFieldErrorComponent, - CodeFieldErrorComponent, - CollapsibleFieldErrorComponent, - DateFieldErrorComponent, - EmailFieldErrorComponent, - GroupFieldErrorComponent, - HiddenFieldErrorComponent, - JSONFieldErrorComponent, - NumberFieldErrorComponent, - PointFieldErrorComponent, - RadioFieldErrorComponent, - RelationshipFieldErrorComponent, - RichTextFieldErrorComponent, - RowFieldErrorComponent, - SelectFieldErrorComponent, - TabsFieldErrorComponent, - TextFieldErrorComponent, - TextareaFieldErrorComponent, - UploadFieldErrorComponent + TextFieldErrorServerComponent, + TextFieldErrorClientComponent, + // And so on for each Field Type } from 'payload' ``` @@ -544,31 +508,13 @@ Custom Description Components receive all [Field Component](#the-field-component #### TypeScript -When building Custom Description Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Description Component, one for every [Field Type](../fields/overview). The convention is to append `DescriptionComponent` to the type of field, i.e. `TextFieldDescriptionComponent`. +When building Custom Description Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Description Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `DescriptionServerComponent` or `DescriptionClientComponent` to the type of field, i.e. `TextFieldDescriptionClientComponent`. ```tsx import type { - ArrayFieldDescriptionComponent, - BlocksFieldDescriptionComponent, - CheckboxFieldDescriptionComponent, - CodeFieldDescriptionComponent, - CollapsibleFieldDescriptionComponent, - DateFieldDescriptionComponent, - EmailFieldDescriptionComponent, - GroupFieldDescriptionComponent, - HiddenFieldDescriptionComponent, - JSONFieldDescriptionComponent, - NumberFieldDescriptionComponent, - PointFieldDescriptionComponent, - RadioFieldDescriptionComponent, - RelationshipFieldDescriptionComponent, - RichTextFieldDescriptionComponent, - RowFieldDescriptionComponent, - SelectFieldDescriptionComponent, - TabsFieldDescriptionComponent, - TextFieldDescriptionComponent, - TextareaFieldDescriptionComponent, - UploadFieldDescriptionComponent + TextFieldDescriptionServerComponent, + TextFieldDescriptionClientComponent, + // And so on for each Field Type } from 'payload' ``` diff --git a/docs/migration-guide/overview.mdx b/docs/migration-guide/overview.mdx index de376d1f0..fd2e0db7c 100644 --- a/docs/migration-guide/overview.mdx +++ b/docs/migration-guide/overview.mdx @@ -467,10 +467,10 @@ export const ServerRenderedDescription = () => // file: components/ClientRenderedDescription.tsx 'use client' import React from 'react' -import type { DescriptionComponent } from 'payload' +import type { TextFieldDescriptionClientComponent } from 'payload' import { useFieldProps, useFormFields } from '@payloadcms/ui' -export const ClientRenderedDescription: DescriptionComponent = () ={ +export const ClientRenderedDescription: TextFieldDescriptionClientComponent = () ={ const { path } = useFieldProps() const { value } = useFormFields(([fields]) => fields[path]) const customDescription = `Component description: ${path} - ${value}` diff --git a/packages/next/src/elements/DocumentHeader/Tabs/index.tsx b/packages/next/src/elements/DocumentHeader/Tabs/index.tsx index 966d15cec..67252a2f4 100644 --- a/packages/next/src/elements/DocumentHeader/Tabs/index.tsx +++ b/packages/next/src/elements/DocumentHeader/Tabs/index.tsx @@ -7,7 +7,6 @@ import type { } from 'payload' import { RenderComponent, getCreateMappedComponent } from '@payloadcms/ui/shared' -import { isPlainObject } from 'payload' import React from 'react' import { ShouldRenderTabs } from './ShouldRenderTabs.js' diff --git a/packages/next/src/views/Account/Settings/index.tsx b/packages/next/src/views/Account/Settings/index.tsx index ffce5ff15..013793951 100644 --- a/packages/next/src/views/Account/Settings/index.tsx +++ b/packages/next/src/views/Account/Settings/index.tsx @@ -11,9 +11,9 @@ import './index.scss' const baseClass = 'payload-settings' export const Settings: React.FC<{ - className?: string - i18n: I18n - languageOptions: LanguageOptions + readonly className?: string + readonly i18n: I18n + readonly languageOptions: LanguageOptions }> = (props) => { const { className, i18n, languageOptions } = props @@ -21,7 +21,7 @@ export const Settings: React.FC<{

{i18n.t('general:payloadSettings')}

- +
diff --git a/packages/next/src/views/Document/getViewsFromConfig.tsx b/packages/next/src/views/Document/getViewsFromConfig.tsx index 5f41d2398..ee6d512c6 100644 --- a/packages/next/src/views/Document/getViewsFromConfig.tsx +++ b/packages/next/src/views/Document/getViewsFromConfig.tsx @@ -128,8 +128,6 @@ export const getViewsFromConfig = ({ views, }) - console.log('CustomViewComponent', customViewKey) - if (customViewKey) { viewKey = customViewKey diff --git a/packages/next/src/views/Edit/Default/Auth/APIKey.tsx b/packages/next/src/views/Edit/Default/Auth/APIKey.tsx index 9ac99de73..5d233240a 100644 --- a/packages/next/src/views/Edit/Default/Auth/APIKey.tsx +++ b/packages/next/src/views/Edit/Default/Auth/APIKey.tsx @@ -129,6 +129,7 @@ export const APIKey: React.FC<{ readonly enabled: boolean; readonly readOnly?: b Component: null, RenderedComponent: APIKeyLabel, }} + field={null} htmlFor={path} /> + export type ArrayFieldProps = { readonly CustomRowLabel?: MappedComponent - readonly field: MarkOptional readonly validate?: ArrayFieldValidation -} & Omit +} & Omit, 'validate'> -export type ArrayFieldLabelComponent = LabelComponent<'array'> +export type ArrayFieldLabelServerComponent = FieldLabelServerComponent -export type ArrayFieldDescriptionComponent = DescriptionComponent<'array'> +export type ArrayFieldLabelClientComponent = FieldLabelClientComponent -export type ArrayFieldErrorComponent = ErrorComponent<'array'> +export type ArrayFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type ArrayFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type ArrayFieldErrorServerComponent = FieldErrorServerComponent + +export type ArrayFieldErrorClientComponent = FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Blocks.ts b/packages/payload/src/admin/fields/Blocks.ts index 723beef88..c81d03b7d 100644 --- a/packages/payload/src/admin/fields/Blocks.ts +++ b/packages/payload/src/admin/fields/Blocks.ts @@ -1,17 +1,31 @@ import type { MarkOptional } from 'ts-essentials' -import type { BlockFieldClient } from '../../fields/config/types.js' +import type { BlockField, BlockFieldClient } from '../../fields/config/types.js' import type { BlockFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type BlocksFieldClientWithoutType = MarkOptional export type BlockFieldProps = { - readonly field: MarkOptional readonly validate?: BlockFieldValidation -} & Omit +} & Omit, 'validate'> -export type BlockFieldLabelComponent = LabelComponent<'blocks'> +export type BlockFieldLabelServerComponent = FieldLabelServerComponent -export type BlockFieldDescriptionComponent = DescriptionComponent<'blocks'> +export type BlockFieldLabelClientComponent = FieldLabelClientComponent -export type BlockFieldErrorComponent = ErrorComponent<'blocks'> +export type BlockFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type BlockFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type BlockFieldErrorServerComponent = FieldErrorServerComponent + +export type BlockFieldErrorClientComponent = FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Checkbox.ts b/packages/payload/src/admin/fields/Checkbox.ts index 4b1dc2a2f..59d8de2dc 100644 --- a/packages/payload/src/admin/fields/Checkbox.ts +++ b/packages/payload/src/admin/fields/Checkbox.ts @@ -1,22 +1,38 @@ import type { MarkOptional } from 'ts-essentials' -import type { CheckboxFieldClient } from '../../fields/config/types.js' +import type { CheckboxField, CheckboxFieldClient } from '../../fields/config/types.js' import type { CheckboxFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type CheckboxFieldClientWithoutType = MarkOptional export type CheckboxFieldProps = { readonly checked?: boolean readonly disableFormData?: boolean - readonly field: MarkOptional readonly id?: string readonly onChange?: (value: boolean) => void readonly partialChecked?: boolean readonly validate?: CheckboxFieldValidation -} & Omit +} & Omit, 'validate'> -export type CheckboxFieldLabelComponent = LabelComponent<'checkbox'> +export type CheckboxFieldLabelServerComponent = FieldLabelServerComponent -export type CheckboxFieldDescriptionComponent = DescriptionComponent<'checkbox'> +export type CheckboxFieldLabelClientComponent = + FieldLabelClientComponent -export type CheckboxFieldErrorComponent = ErrorComponent<'checkbox'> +export type CheckboxFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type CheckboxFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type CheckboxFieldErrorServerComponent = FieldErrorServerComponent + +export type CheckboxFieldErrorClientComponent = + FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Code.ts b/packages/payload/src/admin/fields/Code.ts index 7154d369a..ddf29e04c 100644 --- a/packages/payload/src/admin/fields/Code.ts +++ b/packages/payload/src/admin/fields/Code.ts @@ -1,18 +1,32 @@ import type { MarkOptional } from 'ts-essentials' -import type { CodeFieldClient } from '../../fields/config/types.js' +import type { CodeField, CodeFieldClient } from '../../fields/config/types.js' import type { CodeFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type CodeFieldClientWithoutType = MarkOptional export type CodeFieldProps = { readonly autoComplete?: string - readonly field: MarkOptional readonly validate?: CodeFieldValidation -} & Omit +} & Omit, 'validate'> -export type CodeFieldLabelComponent = LabelComponent<'code'> +export type CodeFieldLabelServerComponent = FieldLabelServerComponent -export type CodeFieldDescriptionComponent = DescriptionComponent<'code'> +export type CodeFieldLabelClientComponent = FieldLabelClientComponent -export type CodeFieldErrorComponent = ErrorComponent<'code'> +export type CodeFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type CodeFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type CodeFieldErrorServerComponent = FieldErrorServerComponent + +export type CodeFieldErrorClientComponent = FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Collapsible.ts b/packages/payload/src/admin/fields/Collapsible.ts index ad941ed83..360e19a42 100644 --- a/packages/payload/src/admin/fields/Collapsible.ts +++ b/packages/payload/src/admin/fields/Collapsible.ts @@ -1,15 +1,31 @@ import type { MarkOptional } from 'ts-essentials' -import type { CollapsibleFieldClient } from '../../fields/config/types.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { CollapsibleField, CollapsibleFieldClient } from '../../fields/config/types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' -export type CollapsibleFieldProps = { - readonly field: MarkOptional -} & FormFieldBase +type CollapsibleFieldClientWithoutType = MarkOptional -export type CollapsibleFieldLabelComponent = LabelComponent<'collapsible'> +export type CollapsibleFieldProps = FormFieldBase -export type CollapsibleFieldDescriptionComponent = DescriptionComponent<'collapsible'> +export type CollapsibleFieldLabelServerComponent = FieldLabelServerComponent -export type CollapsibleFieldErrorComponent = ErrorComponent<'collapsible'> +export type CollapsibleFieldLabelClientComponent = + FieldLabelClientComponent + +export type CollapsibleFieldDescriptionServerComponent = + FieldDescriptionServerComponent + +export type CollapsibleFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type CollapsibleFieldErrorServerComponent = FieldErrorServerComponent + +export type CollapsibleFieldErrorClientComponent = + FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Date.ts b/packages/payload/src/admin/fields/Date.ts index 3a43eb057..9c6a30bc8 100644 --- a/packages/payload/src/admin/fields/Date.ts +++ b/packages/payload/src/admin/fields/Date.ts @@ -1,17 +1,31 @@ import type { MarkOptional } from 'ts-essentials' -import type { DateFieldClient } from '../../fields/config/types.js' +import type { DateField, DateFieldClient } from '../../fields/config/types.js' import type { DateFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type DateFieldClientWithoutType = MarkOptional export type DateFieldProps = { - readonly field: MarkOptional readonly validate?: DateFieldValidation -} & Omit +} & Omit, 'validate'> -export type DateFieldLabelComponent = LabelComponent<'date'> +export type DateFieldLabelServerComponent = FieldLabelServerComponent -export type DateFieldDescriptionComponent = DescriptionComponent<'date'> +export type DateFieldLabelClientComponent = FieldLabelClientComponent -export type DateFieldErrorComponent = ErrorComponent<'date'> +export type DateFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type DateFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type DateFieldErrorServerComponent = FieldErrorServerComponent + +export type DateFieldErrorClientComponent = FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Email.ts b/packages/payload/src/admin/fields/Email.ts index 4f7330dd3..2648177f2 100644 --- a/packages/payload/src/admin/fields/Email.ts +++ b/packages/payload/src/admin/fields/Email.ts @@ -1,18 +1,32 @@ import type { MarkOptional } from 'ts-essentials' -import type { EmailFieldClient } from '../../fields/config/types.js' +import type { EmailField, EmailFieldClient } from '../../fields/config/types.js' import type { EmailFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type EmailFieldClientWithoutType = MarkOptional export type EmailFieldProps = { readonly autoComplete?: string - readonly field: MarkOptional readonly validate?: EmailFieldValidation -} & Omit +} & Omit, 'validate'> -export type EmailFieldLabelComponent = LabelComponent<'email'> +export type EmailFieldLabelServerComponent = FieldLabelServerComponent -export type EmailFieldDescriptionComponent = DescriptionComponent<'email'> +export type EmailFieldLabelClientComponent = FieldLabelClientComponent -export type EmailFieldErrorComponent = ErrorComponent<'email'> +export type EmailFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type EmailFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type EmailFieldErrorServerComponent = FieldErrorServerComponent + +export type EmailFieldErrorClientComponent = FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Group.ts b/packages/payload/src/admin/fields/Group.ts index c5fe2f340..ed360d0f5 100644 --- a/packages/payload/src/admin/fields/Group.ts +++ b/packages/payload/src/admin/fields/Group.ts @@ -1,15 +1,28 @@ import type { MarkOptional } from 'ts-essentials' -import type { GroupFieldClient } from '../../fields/config/types.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { GroupField, GroupFieldClient } from '../../fields/config/types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' -export type GroupFieldProps = { - readonly field: MarkOptional -} & FormFieldBase +type GroupFieldClientWithoutType = MarkOptional -export type GroupFieldLabelComponent = LabelComponent<'group'> +export type GroupFieldProps = FormFieldBase -export type GroupFieldDescriptionComponent = DescriptionComponent<'group'> +export type GroupFieldLabelServerComponent = FieldLabelServerComponent -export type GroupFieldErrorComponent = ErrorComponent<'group'> +export type GroupFieldLabelClientComponent = FieldLabelClientComponent + +export type GroupFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type GroupFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type GroupFieldErrorServerComponent = FieldErrorServerComponent + +export type GroupFieldErrorClientComponent = FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Hidden.ts b/packages/payload/src/admin/fields/Hidden.ts index b1e0b481f..959cbb0e9 100644 --- a/packages/payload/src/admin/fields/Hidden.ts +++ b/packages/payload/src/admin/fields/Hidden.ts @@ -1,6 +1,5 @@ import type { ClientField } from '../../fields/config/client.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FormFieldBase } from '../types.js' export type HiddenFieldProps = { readonly disableModifyingForm?: false @@ -10,9 +9,3 @@ export type HiddenFieldProps = { readonly forceUsePathFromProps?: boolean readonly value?: unknown } & FormFieldBase - -export type HiddenFieldLabelComponent = LabelComponent<'hidden'> - -export type HiddenFieldDescriptionComponent = DescriptionComponent<'hidden'> - -export type HiddenFieldErrorComponent = ErrorComponent<'hidden'> diff --git a/packages/payload/src/admin/fields/JSON.ts b/packages/payload/src/admin/fields/JSON.ts index f20151226..373498b51 100644 --- a/packages/payload/src/admin/fields/JSON.ts +++ b/packages/payload/src/admin/fields/JSON.ts @@ -1,17 +1,31 @@ import type { MarkOptional } from 'ts-essentials' -import type { JSONFieldClient } from '../../fields/config/types.js' +import type { JSONField, JSONFieldClient } from '../../fields/config/types.js' import type { JSONFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type JSONFieldClientWithoutType = MarkOptional export type JSONFieldProps = { - readonly field: MarkOptional readonly validate?: JSONFieldValidation -} & Omit +} & Omit, 'validate'> -export type JSONFieldLabelComponent = LabelComponent<'json'> +export type JSONFieldLabelServerComponent = FieldLabelServerComponent -export type JSONFieldDescriptionComponent = DescriptionComponent<'json'> +export type JSONFieldLabelClientComponent = FieldLabelClientComponent -export type JSONFieldErrorComponent = ErrorComponent<'json'> +export type JSONFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type JSONFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type JSONFieldErrorServerComponent = FieldErrorServerComponent + +export type JSONFieldErrorClientComponent = FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Number.ts b/packages/payload/src/admin/fields/Number.ts index a936605e2..eed165380 100644 --- a/packages/payload/src/admin/fields/Number.ts +++ b/packages/payload/src/admin/fields/Number.ts @@ -1,18 +1,34 @@ import type { MarkOptional } from 'ts-essentials' -import type { NumberFieldClient } from '../../fields/config/types.js' +import type { NumberField, NumberFieldClient } from '../../fields/config/types.js' import type { NumberFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type NumberFieldClientWithoutType = MarkOptional export type NumberFieldProps = { - readonly field: MarkOptional readonly onChange?: (e: number) => void readonly validate?: NumberFieldValidation -} & Omit +} & Omit, 'validate'> -export type NumberFieldLabelComponent = LabelComponent<'number'> +export type NumberFieldLabelServerComponent = FieldLabelServerComponent -export type NumberFieldDescriptionComponent = DescriptionComponent<'number'> +export type NumberFieldLabelClientComponent = + FieldLabelClientComponent -export type NumberFieldErrorComponent = ErrorComponent<'number'> +export type NumberFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type NumberFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type NumberFieldErrorServerComponent = FieldErrorServerComponent + +export type NumberFieldErrorClientComponent = + FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Point.ts b/packages/payload/src/admin/fields/Point.ts index 4a8302861..8033bb063 100644 --- a/packages/payload/src/admin/fields/Point.ts +++ b/packages/payload/src/admin/fields/Point.ts @@ -1,17 +1,31 @@ import type { MarkOptional } from 'ts-essentials' -import type { PointFieldClient } from '../../fields/config/types.js' +import type { PointField, PointFieldClient } from '../../fields/config/types.js' import type { PointFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type PointFieldClientWithoutType = MarkOptional export type PointFieldProps = { - readonly field: MarkOptional readonly validate?: PointFieldValidation -} & Omit +} & Omit, 'validate'> -export type PointFieldLabelComponent = LabelComponent<'point'> +export type PointFieldLabelServerComponent = FieldLabelServerComponent -export type PointFieldDescriptionComponent = DescriptionComponent<'point'> +export type PointFieldLabelClientComponent = FieldLabelClientComponent -export type PointFieldErrorComponent = ErrorComponent<'point'> +export type PointFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type PointFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type PointFieldErrorServerComponent = FieldErrorServerComponent + +export type PointFieldErrorClientComponent = FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Radio.ts b/packages/payload/src/admin/fields/Radio.ts index 06ebe1141..9095dd064 100644 --- a/packages/payload/src/admin/fields/Radio.ts +++ b/packages/payload/src/admin/fields/Radio.ts @@ -1,21 +1,35 @@ import type { MarkOptional } from 'ts-essentials' -import type { RadioFieldClient } from '../../fields/config/types.js' +import type { RadioField, RadioFieldClient } from '../../fields/config/types.js' import type { RadioFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type RadioFieldClientWithoutType = MarkOptional export type RadioFieldProps = { - readonly field: MarkOptional readonly onChange?: OnChange readonly validate?: RadioFieldValidation readonly value?: string -} & Omit +} & Omit, 'validate'> export type OnChange = (value: T) => void -export type RadioFieldLabelComponent = LabelComponent<'radio'> +export type RadioFieldLabelServerComponent = FieldLabelServerComponent -export type RadioFieldDescriptionComponent = DescriptionComponent<'radio'> +export type RadioFieldLabelClientComponent = FieldLabelClientComponent -export type RadioFieldErrorComponent = ErrorComponent<'radio'> +export type RadioFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type RadioFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type RadioFieldErrorServerComponent = FieldErrorServerComponent + +export type RadioFieldErrorClientComponent = FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Relationship.ts b/packages/payload/src/admin/fields/Relationship.ts index bdba09ede..03b342c92 100644 --- a/packages/payload/src/admin/fields/Relationship.ts +++ b/packages/payload/src/admin/fields/Relationship.ts @@ -1,17 +1,34 @@ import type { MarkOptional } from 'ts-essentials' -import type { RelationshipFieldClient } from '../../fields/config/types.js' +import type { RelationshipField, RelationshipFieldClient } from '../../fields/config/types.js' import type { RelationshipFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type RelationshipFieldClientWithoutType = MarkOptional export type RelationshipFieldProps = { - readonly field: MarkOptional readonly validate?: RelationshipFieldValidation -} & Omit +} & Omit, 'validate'> -export type RelationshipFieldLabelComponent = LabelComponent<'relationship'> +export type RelationshipFieldLabelServerComponent = FieldLabelServerComponent -export type RelationshipFieldDescriptionComponent = DescriptionComponent<'relationship'> +export type RelationshipFieldLabelClientComponent = + FieldLabelClientComponent -export type RelationshipFieldErrorComponent = ErrorComponent<'relationship'> +export type RelationshipFieldDescriptionServerComponent = + FieldDescriptionServerComponent + +export type RelationshipFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type RelationshipFieldErrorServerComponent = FieldErrorServerComponent + +export type RelationshipFieldErrorClientComponent = + FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/RichText.ts b/packages/payload/src/admin/fields/RichText.ts index eeb56b240..285c882ec 100644 --- a/packages/payload/src/admin/fields/RichText.ts +++ b/packages/payload/src/admin/fields/RichText.ts @@ -1,21 +1,37 @@ import type { MarkOptional } from 'ts-essentials' -import type { RichTextFieldClient } from '../../fields/config/types.js' +import type { RichTextField, RichTextFieldClient } from '../../fields/config/types.js' import type { RichTextFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type RichTextFieldClientWithoutType = MarkOptional export type RichTextFieldProps< TValue extends object = any, TAdapterProps = any, TExtraProperties = object, > = { - readonly field: MarkOptional, 'type'> readonly validate?: RichTextFieldValidation -} & Omit +} & Omit, 'validate'> -export type RichTextFieldLabelComponent = LabelComponent<'richText'> +export type RichTextFieldLabelServerComponent = FieldLabelServerComponent -export type RichTextFieldDescriptionComponent = DescriptionComponent<'richText'> +export type RichTextFieldLabelClientComponent = + FieldLabelClientComponent -export type RichTextFieldErrorComponent = ErrorComponent<'richText'> +export type RichTextFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type RichTextFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type RichTextFieldErrorServerComponent = FieldErrorServerComponent + +export type RichTextFieldErrorClientComponent = + FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Row.ts b/packages/payload/src/admin/fields/Row.ts index 01aabe4f5..6b915e293 100644 --- a/packages/payload/src/admin/fields/Row.ts +++ b/packages/payload/src/admin/fields/Row.ts @@ -1,17 +1,32 @@ -import type { DescriptionComponent, FormFieldBase, LabelComponent } from 'payload' import type { MarkOptional } from 'ts-essentials' -import type { RowFieldClient } from '../../fields/config/types.js' -import type { ErrorComponent } from '../forms/Error.js' +import type { RowField, RowFieldClient } from '../../fields/config/types.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldErrorClientComponent, + FieldErrorServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type RowFieldClientWithoutType = MarkOptional export type RowFieldProps = { - field: MarkOptional - forceRender?: boolean - indexPath: string -} & FormFieldBase + readonly forceRender?: boolean + readonly indexPath: string +} & FormFieldBase -export type RowFieldLabelComponent = LabelComponent<'row'> +export type RowFieldLabelServerComponent = FieldLabelServerComponent -export type RowFieldDescriptionComponent = DescriptionComponent<'row'> +export type RowFieldLabelClientComponent = FieldLabelClientComponent -export type RowFieldErrorComponent = ErrorComponent<'row'> +export type RowFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type RowFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type RowFieldErrorServerComponent = FieldErrorServerComponent + +export type RowFieldErrorClientComponent = FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Select.ts b/packages/payload/src/admin/fields/Select.ts index aa6389dcc..be84f87ae 100644 --- a/packages/payload/src/admin/fields/Select.ts +++ b/packages/payload/src/admin/fields/Select.ts @@ -1,19 +1,35 @@ import type { MarkOptional } from 'ts-essentials' -import type { SelectFieldClient } from '../../fields/config/types.js' +import type { SelectField, SelectFieldClient } from '../../fields/config/types.js' import type { SelectFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type SelectFieldClientWithoutType = MarkOptional export type SelectFieldProps = { - readonly field: MarkOptional readonly onChange?: (e: string | string[]) => void readonly validate?: SelectFieldValidation readonly value?: string -} & Omit +} & Omit, 'validate'> -export type SelectFieldLabelComponent = LabelComponent<'select'> +export type SelectFieldLabelServerComponent = FieldLabelServerComponent -export type SelectFieldDescriptionComponent = DescriptionComponent<'select'> +export type SelectFieldLabelClientComponent = + FieldLabelClientComponent -export type SelectFieldErrorComponent = ErrorComponent<'select'> +export type SelectFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type SelectFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type SelectFieldErrorServerComponent = FieldErrorServerComponent + +export type SelectFieldErrorClientComponent = + FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Tabs.ts b/packages/payload/src/admin/fields/Tabs.ts index 938cdf0e9..817621c3e 100644 --- a/packages/payload/src/admin/fields/Tabs.ts +++ b/packages/payload/src/admin/fields/Tabs.ts @@ -3,22 +3,36 @@ import type { MarkOptional } from 'ts-essentials' import type { ClientField, NamedTab, + TabsField, TabsFieldClient, UnnamedTab, } from '../../fields/config/types.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' export type ClientTab = | ({ fields: ClientField[] } & Omit) | ({ fields: ClientField[] } & Omit) -export type TabsFieldProps = { - readonly field: MarkOptional -} & FormFieldBase +export type TabsFieldClientWithoutType = MarkOptional -export type TabsFieldLabelComponent = LabelComponent<'tabs'> +export type TabsFieldProps = FormFieldBase -export type TabsFieldDescriptionComponent = DescriptionComponent<'tabs'> +export type TabsFieldLabelServerComponent = FieldLabelServerComponent -export type TabsFieldErrorComponent = ErrorComponent<'tabs'> +export type TabsFieldLabelClientComponent = FieldLabelClientComponent + +export type TabsFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type TabsFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type TabsFieldErrorServerComponent = FieldErrorServerComponent + +export type TabsFieldErrorClientComponent = FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Text.ts b/packages/payload/src/admin/fields/Text.ts index 3b8887667..c8f2f846f 100644 --- a/packages/payload/src/admin/fields/Text.ts +++ b/packages/payload/src/admin/fields/Text.ts @@ -1,20 +1,34 @@ import type React from 'react' import type { MarkOptional } from 'ts-essentials' -import type { TextFieldClient } from '../../fields/config/types.js' +import type { TextField, TextFieldClient } from '../../fields/config/types.js' import type { TextFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type TextFieldClientWithoutType = MarkOptional export type TextFieldProps = { - readonly field: MarkOptional readonly inputRef?: React.RefObject readonly onKeyDown?: React.KeyboardEventHandler readonly validate?: TextFieldValidation -} & Omit +} & Omit, 'validate'> -export type TextFieldLabelComponent = LabelComponent<'text'> +export type TextFieldLabelServerComponent = FieldLabelServerComponent -export type TextFieldDescriptionComponent = DescriptionComponent<'text'> +export type TextFieldLabelClientComponent = FieldLabelClientComponent -export type TextFieldErrorComponent = ErrorComponent<'text'> +export type TextFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type TextFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type TextFieldErrorServerComponent = FieldErrorServerComponent + +export type TextFieldErrorClientComponent = FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Textarea.ts b/packages/payload/src/admin/fields/Textarea.ts index 3f1467c7a..a9b74edd5 100644 --- a/packages/payload/src/admin/fields/Textarea.ts +++ b/packages/payload/src/admin/fields/Textarea.ts @@ -1,20 +1,36 @@ import type React from 'react' import type { MarkOptional } from 'ts-essentials' -import type { TextareaFieldClient } from '../../fields/config/types.js' +import type { TextareaField, TextareaFieldClient } from '../../fields/config/types.js' import type { TextareaFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type TextareaFieldClientWithoutType = MarkOptional export type TextareaFieldProps = { - readonly field: MarkOptional readonly inputRef?: React.Ref readonly onKeyDown?: React.KeyboardEventHandler readonly validate?: TextareaFieldValidation -} & Omit +} & Omit, 'validate'> -export type TextareaFieldLabelComponent = LabelComponent<'textarea'> +export type TextareaFieldLabelServerComponent = FieldLabelServerComponent -export type TextareaFieldDescriptionComponent = DescriptionComponent<'textarea'> +export type TextareaFieldLabelClientComponent = + FieldLabelClientComponent -export type TextareaFieldErrorComponent = ErrorComponent<'textarea'> +export type TextareaFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type TextareaFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type TextareaFieldErrorServerComponent = FieldErrorServerComponent + +export type TextareaFieldErrorClientComponent = + FieldErrorClientComponent diff --git a/packages/payload/src/admin/fields/Upload.ts b/packages/payload/src/admin/fields/Upload.ts index b9e989c0d..ccd36cc71 100644 --- a/packages/payload/src/admin/fields/Upload.ts +++ b/packages/payload/src/admin/fields/Upload.ts @@ -1,17 +1,33 @@ import type { MarkOptional } from 'ts-essentials' -import type { UploadFieldClient } from '../../fields/config/types.js' +import type { UploadField, UploadFieldClient } from '../../fields/config/types.js' import type { UploadFieldValidation } from '../../fields/validations.js' -import type { ErrorComponent } from '../forms/Error.js' -import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js' +import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' +import type { + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + FieldLabelClientComponent, + FieldLabelServerComponent, + FormFieldBase, +} from '../types.js' + +type UploadFieldClientWithoutType = MarkOptional export type UploadFieldProps = { - readonly field: MarkOptional readonly validate?: UploadFieldValidation -} & Omit +} & Omit, 'validate'> -export type UploadFieldLabelComponent = LabelComponent<'upload'> +export type UploadFieldLabelServerComponent = FieldLabelServerComponent -export type UploadFieldDescriptionComponent = DescriptionComponent<'upload'> +export type UploadFieldLabelClientComponent = + FieldLabelClientComponent -export type UploadFieldErrorComponent = ErrorComponent<'upload'> +export type UploadFieldDescriptionServerComponent = FieldDescriptionServerComponent + +export type UploadFieldDescriptionClientComponent = + FieldDescriptionClientComponent + +export type UploadFieldErrorServerComponent = FieldErrorServerComponent + +export type UploadFieldErrorClientComponent = + FieldErrorClientComponent diff --git a/packages/payload/src/admin/forms/Description.ts b/packages/payload/src/admin/forms/Description.ts new file mode 100644 index 000000000..30fde7f6d --- /dev/null +++ b/packages/payload/src/admin/forms/Description.ts @@ -0,0 +1,38 @@ +import type { MarkOptional } from 'ts-essentials' + +import type { LabelFunction, ServerProps } from '../../config/types.js' +import type { ClientField, Field } from '../../fields/config/types.js' +import type { MappedComponent } from '../types.js' + +export type DescriptionFunction = LabelFunction + +type ClientFieldWithOptionalType = MarkOptional + +export type FieldDescriptionClientComponent< + TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType, +> = React.ComponentType> + +export type FieldDescriptionServerComponent = + React.ComponentType> + +export type StaticDescription = Record | string + +export type Description = DescriptionFunction | StaticDescription + +export type GenericDescriptionProps = { + readonly Description?: MappedComponent + readonly className?: string + readonly description?: StaticDescription + readonly marginPlacement?: 'bottom' | 'top' +} + +export type FieldDescriptionServerProps = { + field: TFieldServer +} & GenericDescriptionProps & + Partial + +export type FieldDescriptionClientProps< + TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType, +> = { + field: TFieldClient +} & GenericDescriptionProps diff --git a/packages/payload/src/admin/forms/Error.ts b/packages/payload/src/admin/forms/Error.ts index a3a405951..487966ba4 100644 --- a/packages/payload/src/admin/forms/Error.ts +++ b/packages/payload/src/admin/forms/Error.ts @@ -1,5 +1,7 @@ -import type { CustomComponent, ServerProps } from '../../config/types.js' -import type { FieldTypes } from '../../fields/config/types.js' +import type { MarkOptional } from 'ts-essentials' + +import type { ServerProps } from '../../config/types.js' +import type { ClientField, Field } from '../../fields/config/types.js' import type { MappedComponent } from '../types.js' export type GenericErrorProps = { @@ -10,9 +12,23 @@ export type GenericErrorProps = { readonly showError?: boolean } -export type ErrorProps = { - type: T +type ClientFieldWithOptionalType = MarkOptional + +export type FieldErrorClientProps< + TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType, +> = { + field: TFieldClient +} & GenericErrorProps + +export type FieldErrorServerProps = { + field: TFieldServer } & GenericErrorProps & Partial -export type ErrorComponent = CustomComponent> +export type FieldErrorClientComponent< + TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType, +> = React.ComponentType> + +export type FieldErrorServerComponent = React.ComponentType< + FieldErrorServerProps +> diff --git a/packages/payload/src/admin/forms/Field.ts b/packages/payload/src/admin/forms/Field.ts index 91d6d91c6..c80b32006 100644 --- a/packages/payload/src/admin/forms/Field.ts +++ b/packages/payload/src/admin/forms/Field.ts @@ -1,24 +1,28 @@ +import type { MarkOptional } from 'ts-essentials' + import type { User } from '../../auth/types.js' import type { Locale } from '../../config/types.js' -import type { Validate } from '../../fields/config/types.js' +import type { ClientField, Validate } from '../../fields/config/types.js' import type { DocumentPreferences } from '../../preferences/types.js' -import type { ErrorProps } from './Error.js' -import type { FieldDescriptionProps } from './FieldDescription.js' -import type { LabelProps } from './Label.js' +import type { FieldDescriptionClientProps } from './Description.js' +import type { FieldErrorClientProps } from './Error.js' +import type { FieldLabelClientProps } from './Label.js' -// TODO: Check if we still need this. Shouldnt most of it be present in the field type? -export type FormFieldBase = { - readonly descriptionProps?: FieldDescriptionProps +export type FormFieldBase< + TFieldClient extends MarkOptional = MarkOptional, +> = { + readonly descriptionProps?: FieldDescriptionClientProps readonly docPreferences?: DocumentPreferences - readonly errorProps?: ErrorProps + readonly errorProps?: FieldErrorClientProps + readonly field: TFieldClient /** - * forceRender is added by RenderField automatically + * `forceRender` is added by RenderField automatically. */ readonly forceRender?: boolean - readonly labelProps?: LabelProps + readonly labelProps?: FieldLabelClientProps readonly locale?: Locale /** - * forceRender is added by RenderField automatically. This should be used instead of field.admin.readOnly + * `readOnly` is added by RenderField automatically. This should be used instead of `field.admin.readOnly`. */ readonly readOnly?: boolean readonly user?: User diff --git a/packages/payload/src/admin/forms/FieldDescription.ts b/packages/payload/src/admin/forms/FieldDescription.ts deleted file mode 100644 index 9ed831886..000000000 --- a/packages/payload/src/admin/forms/FieldDescription.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { CustomComponent, LabelFunction, ServerProps } from '../../config/types.js' -import type { FieldTypes } from '../../fields/config/types.js' -import type { MappedComponent } from '../types.js' - -export type DescriptionFunction = LabelFunction - -export type DescriptionComponent = CustomComponent< - FieldDescriptionProps -> - -export type StaticDescription = Record | string - -export type Description = DescriptionFunction | StaticDescription -export type GenericDescriptionProps = { - readonly Description?: MappedComponent - readonly className?: string - readonly description?: StaticDescription - readonly marginPlacement?: 'bottom' | 'top' -} -export type FieldDescriptionProps = { - type: T -} & GenericDescriptionProps & - Partial diff --git a/packages/payload/src/admin/forms/Label.ts b/packages/payload/src/admin/forms/Label.ts index f3839d09c..c4fa71bea 100644 --- a/packages/payload/src/admin/forms/Label.ts +++ b/packages/payload/src/admin/forms/Label.ts @@ -1,5 +1,7 @@ -import type { CustomComponent, ServerProps, StaticLabel } from '../../config/types.js' -import type { FieldTypes } from '../../fields/config/types.js' +import type { MarkOptional } from 'ts-essentials' + +import type { ServerProps, StaticLabel } from '../../config/types.js' +import type { ClientField, Field } from '../../fields/config/types.js' import type { MappedComponent } from '../types.js' export type GenericLabelProps = { @@ -11,14 +13,28 @@ export type GenericLabelProps = { readonly unstyled?: boolean } -export type LabelProps = { - type: T +type ClientFieldWithOptionalType = MarkOptional + +export type FieldLabelClientProps< + TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType, +> = { + field: TFieldClient +} & GenericLabelProps + +export type FieldLabelServerProps = { + field: TFieldServer } & GenericLabelProps & Partial -export type SanitizedLabelProps = Omit< - LabelProps, +export type SanitizedLabelProps = Omit< + FieldLabelClientProps, 'label' | 'required' > -export type LabelComponent = CustomComponent> +export type FieldLabelClientComponent< + TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType, +> = React.ComponentType> + +export type FieldLabelServerComponent = React.ComponentType< + FieldLabelServerProps +> diff --git a/packages/payload/src/admin/types.ts b/packages/payload/src/admin/types.ts index a86e121ec..dad3c7dd6 100644 --- a/packages/payload/src/admin/types.ts +++ b/packages/payload/src/admin/types.ts @@ -33,172 +33,237 @@ export type { } from './elements/WithServerSideProps.js' export type { - ArrayFieldDescriptionComponent, - ArrayFieldErrorComponent, - ArrayFieldLabelComponent, + ArrayFieldDescriptionClientComponent, + ArrayFieldDescriptionServerComponent, + ArrayFieldErrorClientComponent, + ArrayFieldErrorServerComponent, + ArrayFieldLabelClientComponent, + ArrayFieldLabelServerComponent, ArrayFieldProps, } from './fields/Array.js' export type { - BlockFieldDescriptionComponent, - BlockFieldErrorComponent, - BlockFieldLabelComponent, + BlockFieldDescriptionClientComponent, + BlockFieldDescriptionServerComponent, + BlockFieldErrorClientComponent, + BlockFieldErrorServerComponent, + BlockFieldLabelClientComponent, + BlockFieldLabelServerComponent, BlockFieldProps, } from './fields/Blocks.js' export type { - CheckboxFieldDescriptionComponent, - CheckboxFieldErrorComponent, - CheckboxFieldLabelComponent, + CheckboxFieldDescriptionClientComponent, + CheckboxFieldDescriptionServerComponent, + CheckboxFieldErrorClientComponent, + CheckboxFieldErrorServerComponent, + CheckboxFieldLabelClientComponent, + CheckboxFieldLabelServerComponent, CheckboxFieldProps, } from './fields/Checkbox.js' export type { - CodeFieldDescriptionComponent, - CodeFieldErrorComponent, - CodeFieldLabelComponent, + CodeFieldDescriptionClientComponent, + CodeFieldDescriptionServerComponent, + CodeFieldErrorClientComponent, + CodeFieldErrorServerComponent, + CodeFieldLabelClientComponent, + CodeFieldLabelServerComponent, CodeFieldProps, } from './fields/Code.js' export type { - CollapsibleFieldDescriptionComponent, - CollapsibleFieldErrorComponent, - CollapsibleFieldLabelComponent, + CollapsibleFieldDescriptionClientComponent, + CollapsibleFieldDescriptionServerComponent, + CollapsibleFieldErrorClientComponent, + CollapsibleFieldErrorServerComponent, + CollapsibleFieldLabelClientComponent, + CollapsibleFieldLabelServerComponent, CollapsibleFieldProps, } from './fields/Collapsible.js' export type { - DateFieldDescriptionComponent, - DateFieldErrorComponent, - DateFieldLabelComponent, + DateFieldDescriptionClientComponent, + DateFieldDescriptionServerComponent, + DateFieldErrorClientComponent, + DateFieldErrorServerComponent, + DateFieldLabelClientComponent, + DateFieldLabelServerComponent, DateFieldProps, } from './fields/Date.js' export type { - EmailFieldDescriptionComponent, - EmailFieldErrorComponent, - EmailFieldLabelComponent, + EmailFieldDescriptionClientComponent, + EmailFieldDescriptionServerComponent, + EmailFieldErrorClientComponent, + EmailFieldErrorServerComponent, + EmailFieldLabelClientComponent, + EmailFieldLabelServerComponent, EmailFieldProps, } from './fields/Email.js' export type { - GroupFieldDescriptionComponent, - GroupFieldErrorComponent, - GroupFieldLabelComponent, + GroupFieldDescriptionClientComponent, + GroupFieldDescriptionServerComponent, + GroupFieldErrorClientComponent, + GroupFieldErrorServerComponent, + GroupFieldLabelClientComponent, + GroupFieldLabelServerComponent, GroupFieldProps, } from './fields/Group.js' -export type { - HiddenFieldDescriptionComponent, - HiddenFieldErrorComponent, - HiddenFieldLabelComponent, - HiddenFieldProps, -} from './fields/Hidden.js' +export type { HiddenFieldProps } from './fields/Hidden.js' export type { - JSONFieldDescriptionComponent, - JSONFieldErrorComponent, - JSONFieldLabelComponent, + JSONFieldDescriptionClientComponent, + JSONFieldDescriptionServerComponent, + JSONFieldErrorClientComponent, + JSONFieldErrorServerComponent, + JSONFieldLabelClientComponent, + JSONFieldLabelServerComponent, JSONFieldProps, } from './fields/JSON.js' export type { - NumberFieldDescriptionComponent, - NumberFieldErrorComponent, - NumberFieldLabelComponent, + NumberFieldDescriptionClientComponent, + NumberFieldDescriptionServerComponent, + NumberFieldErrorClientComponent, + NumberFieldErrorServerComponent, + NumberFieldLabelClientComponent, + NumberFieldLabelServerComponent, NumberFieldProps, } from './fields/Number.js' export type { - PointFieldDescriptionComponent, - PointFieldErrorComponent, - PointFieldLabelComponent, + PointFieldDescriptionClientComponent, + PointFieldDescriptionServerComponent, + PointFieldErrorClientComponent, + PointFieldErrorServerComponent, + PointFieldLabelClientComponent, + PointFieldLabelServerComponent, PointFieldProps, } from './fields/Point.js' export type { - RadioFieldDescriptionComponent, - RadioFieldErrorComponent, - RadioFieldLabelComponent, + RadioFieldDescriptionClientComponent, + RadioFieldDescriptionServerComponent, + RadioFieldErrorClientComponent, + RadioFieldErrorServerComponent, + RadioFieldLabelClientComponent, + RadioFieldLabelServerComponent, RadioFieldProps, } from './fields/Radio.js' export type { - RelationshipFieldDescriptionComponent, - RelationshipFieldErrorComponent, - RelationshipFieldLabelComponent, + RelationshipFieldDescriptionClientComponent, + RelationshipFieldDescriptionServerComponent, + RelationshipFieldErrorClientComponent, + RelationshipFieldErrorServerComponent, + RelationshipFieldLabelClientComponent, + RelationshipFieldLabelServerComponent, RelationshipFieldProps, } from './fields/Relationship.js' export type { - RichTextFieldDescriptionComponent, - RichTextFieldErrorComponent, - RichTextFieldLabelComponent, + RichTextFieldDescriptionClientComponent, + RichTextFieldDescriptionServerComponent, + RichTextFieldErrorClientComponent, + RichTextFieldErrorServerComponent, + RichTextFieldLabelClientComponent, + RichTextFieldLabelServerComponent, RichTextFieldProps, } from './fields/RichText.js' export type { - RowFieldDescriptionComponent, - RowFieldErrorComponent, - RowFieldLabelComponent, + RowFieldDescriptionClientComponent, + RowFieldDescriptionServerComponent, + RowFieldErrorClientComponent, + RowFieldErrorServerComponent, + RowFieldLabelClientComponent, + RowFieldLabelServerComponent, RowFieldProps, } from './fields/Row.js' export type { - SelectFieldDescriptionComponent, - SelectFieldErrorComponent, - SelectFieldLabelComponent, + SelectFieldDescriptionClientComponent, + SelectFieldDescriptionServerComponent, + SelectFieldErrorClientComponent, + SelectFieldErrorServerComponent, + SelectFieldLabelClientComponent, + SelectFieldLabelServerComponent, SelectFieldProps, } from './fields/Select.js' export type { ClientTab, - TabsFieldDescriptionComponent, - TabsFieldErrorComponent, - TabsFieldLabelComponent, + TabsFieldDescriptionClientComponent, + TabsFieldDescriptionServerComponent, + TabsFieldErrorClientComponent, + TabsFieldErrorServerComponent, + TabsFieldLabelClientComponent, + TabsFieldLabelServerComponent, TabsFieldProps, } from './fields/Tabs.js' export type { - TextFieldDescriptionComponent, - TextFieldErrorComponent, - TextFieldLabelComponent, + TextFieldDescriptionClientComponent, + TextFieldDescriptionServerComponent, + TextFieldErrorClientComponent, + TextFieldErrorServerComponent, + TextFieldLabelClientComponent, + TextFieldLabelServerComponent, TextFieldProps, } from './fields/Text.js' export type { - TextareaFieldDescriptionComponent, - TextareaFieldErrorComponent, - TextareaFieldLabelComponent, + TextareaFieldDescriptionClientComponent, + TextareaFieldDescriptionServerComponent, + TextareaFieldErrorClientComponent, + TextareaFieldErrorServerComponent, + TextareaFieldLabelClientComponent, + TextareaFieldLabelServerComponent, TextareaFieldProps, } from './fields/Textarea.js' export type { - UploadFieldDescriptionComponent, - UploadFieldErrorComponent, - UploadFieldLabelComponent, + UploadFieldDescriptionClientComponent, + UploadFieldDescriptionServerComponent, + UploadFieldErrorClientComponent, + UploadFieldErrorServerComponent, + UploadFieldLabelClientComponent, + UploadFieldLabelServerComponent, UploadFieldProps, } from './fields/Upload.js' -export type { ErrorComponent, ErrorProps, GenericErrorProps } from './forms/Error.js' - -export type { FormFieldBase } from './forms/Field.js' - export type { Description, - DescriptionComponent, DescriptionFunction, - FieldDescriptionProps, + FieldDescriptionClientComponent, + FieldDescriptionClientProps, + FieldDescriptionServerComponent, + FieldDescriptionServerProps, GenericDescriptionProps, StaticDescription, -} from './forms/FieldDescription.js' +} from './forms/Description.js' + +export type { + FieldErrorClientComponent, + FieldErrorClientProps, + FieldErrorServerComponent, + FieldErrorServerProps, + GenericErrorProps, +} from './forms/Error.js' + +export type { FormFieldBase } from './forms/Field.js' export type { Data, FilterOptionsResult, FormField, FormState, Row } from './forms/Form.js' export type { + FieldLabelClientComponent, + FieldLabelClientProps, + FieldLabelServerComponent, + FieldLabelServerProps, GenericLabelProps, - LabelComponent, - LabelProps, SanitizedLabelProps, } from './forms/Label.js' @@ -241,14 +306,20 @@ export type MappedComponent( component: { Component: React.FC } | PayloadComponent | null, - props: object, + props: { + clientProps?: JsonObject + serverProps?: object + }, fallback: React.FC, identifier: string, ): MappedComponent ( components: ({ Component: React.FC } | PayloadComponent)[], - props: object, + props: { + clientProps?: JsonObject + serverProps?: object + }, fallback: React.FC, identifier: string, ): MappedComponent[] diff --git a/packages/payload/src/collections/config/client.ts b/packages/payload/src/collections/config/client.ts index 78ca51648..b19a9b20e 100644 --- a/packages/payload/src/collections/config/client.ts +++ b/packages/payload/src/collections/config/client.ts @@ -1,4 +1,4 @@ -import type { MappedComponent } from '../../admin/types.js' +import type { MappedComponent, StaticDescription } from '../../admin/types.js' import type { MappedView } from '../../admin/views/types.js' import type { LivePreviewConfig, ServerOnlyLivePreviewProperties } from '../../config/types.js' import type { ClientField } from '../../fields/config/client.js' @@ -46,7 +46,7 @@ export type ClientCollectionConfig = { } } } - description?: Record | string + description?: StaticDescription livePreview?: Omit } & Omit< SanitizedCollectionConfig['admin'], diff --git a/packages/payload/src/config/types.ts b/packages/payload/src/config/types.ts index cbc4eed99..a6c9e7b0d 100644 --- a/packages/payload/src/config/types.ts +++ b/packages/payload/src/config/types.ts @@ -398,14 +398,14 @@ export type EditViewConfig = { ) export type ServerProps = { - [key: string]: unknown - i18n: I18nClient - locale?: Locale - params?: { [key: string]: string | string[] | undefined } - payload: Payload - permissions?: Permissions - searchParams?: { [key: string]: string | string[] | undefined } - user?: TypedUser + readonly i18n: I18nClient + readonly locale?: Locale + readonly params?: { [key: string]: string | string[] | undefined } + readonly payload: Payload + readonly permissions?: Permissions + readonly [key: string]: unknown + readonly searchParams?: { [key: string]: string | string[] | undefined } + readonly user?: TypedUser } export const serverProps: (keyof ServerProps)[] = [ diff --git a/packages/payload/src/fields/config/types.ts b/packages/payload/src/fields/config/types.ts index 7b651f14e..fe80667b3 100644 --- a/packages/payload/src/fields/config/types.ts +++ b/packages/payload/src/fields/config/types.ts @@ -6,16 +6,97 @@ import type { CSSProperties } from 'react' import type { DeepUndefinable } from 'ts-essentials' import type { RichTextAdapter, RichTextAdapterProvider } from '../../admin/RichText.js' -import type { ErrorComponent } from '../../admin/forms/Error.js' import type { + ArrayFieldErrorClientComponent, + ArrayFieldErrorServerComponent, + ArrayFieldLabelClientComponent, + ArrayFieldLabelServerComponent, + ArrayFieldProps, + BlockFieldErrorClientComponent, + BlockFieldErrorServerComponent, + BlockFieldProps, + CheckboxFieldErrorClientComponent, + CheckboxFieldErrorServerComponent, + CheckboxFieldLabelClientComponent, + CheckboxFieldLabelServerComponent, + CheckboxFieldProps, ClientTab, + CodeFieldErrorClientComponent, + CodeFieldErrorServerComponent, + CodeFieldLabelClientComponent, + CodeFieldLabelServerComponent, + CodeFieldProps, + CollapsibleFieldLabelClientComponent, + CollapsibleFieldLabelServerComponent, + CollapsibleFieldProps, ConditionalDateProps, + DateFieldErrorClientComponent, + DateFieldErrorServerComponent, + DateFieldLabelClientComponent, + DateFieldLabelServerComponent, + DateFieldProps, Description, - DescriptionComponent, - LabelComponent, + EmailFieldErrorClientComponent, + EmailFieldErrorServerComponent, + EmailFieldLabelClientComponent, + EmailFieldLabelServerComponent, + EmailFieldProps, + FieldDescriptionClientComponent, + FieldDescriptionServerComponent, + GroupFieldLabelClientComponent, + GroupFieldLabelServerComponent, + GroupFieldProps, + HiddenFieldProps, + JSONFieldErrorClientComponent, + JSONFieldErrorServerComponent, + JSONFieldLabelClientComponent, + JSONFieldLabelServerComponent, + JSONFieldProps, MappedComponent, + NumberFieldErrorClientComponent, + NumberFieldErrorServerComponent, + NumberFieldLabelClientComponent, + NumberFieldLabelServerComponent, + NumberFieldProps, + PointFieldErrorClientComponent, + PointFieldErrorServerComponent, + PointFieldLabelClientComponent, + PointFieldLabelServerComponent, + PointFieldProps, + RadioFieldErrorClientComponent, + RadioFieldErrorServerComponent, + RadioFieldLabelClientComponent, + RadioFieldLabelServerComponent, + RadioFieldProps, + RelationshipFieldErrorClientComponent, + RelationshipFieldErrorServerComponent, + RelationshipFieldLabelClientComponent, + RelationshipFieldLabelServerComponent, + RelationshipFieldProps, + RichTextFieldProps, + RowFieldProps, RowLabelComponent, + SelectFieldErrorClientComponent, + SelectFieldErrorServerComponent, + SelectFieldLabelClientComponent, + SelectFieldLabelServerComponent, + SelectFieldProps, StaticDescription, + TabsFieldProps, + TextFieldErrorClientComponent, + TextFieldErrorServerComponent, + TextFieldLabelClientComponent, + TextFieldLabelServerComponent, + TextareaFieldErrorClientComponent, + TextareaFieldErrorServerComponent, + TextareaFieldLabelClientComponent, + TextareaFieldLabelServerComponent, + TextareaFieldProps, + UploadFieldErrorClientComponent, + UploadFieldErrorServerComponent, + UploadFieldLabelClientComponent, + UploadFieldLabelServerComponent, + UploadFieldProps, } from '../../admin/types.js' import type { SanitizedCollectionConfig, TypeWithID } from '../../collections/config/types.js' import type { @@ -148,7 +229,7 @@ type Admin = { className?: string components?: { Cell?: CustomComponent - Description?: DescriptionComponent + Description?: CustomComponent Field?: CustomComponent /** * The Filter component has to be a client component @@ -339,8 +420,8 @@ export type NumberField = { /** Set this property to a string that will be used for browser autocomplete. */ autoComplete?: string components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent afterInput?: CustomComponent[] beforeInput?: CustomComponent[] } & Admin['components'] @@ -392,8 +473,8 @@ export type TextField = { admin?: { autoComplete?: string components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent afterInput?: CustomComponent[] beforeInput?: CustomComponent[] } & Admin['components'] @@ -441,8 +522,8 @@ export type EmailField = { admin?: { autoComplete?: string components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent afterInput?: CustomComponent[] beforeInput?: CustomComponent[] } & Admin['components'] @@ -468,8 +549,8 @@ export type EmailFieldClient = { export type TextareaField = { admin?: { components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent afterInput?: CustomComponent[] beforeInput?: CustomComponent[] } & Admin['components'] @@ -499,8 +580,8 @@ export type TextareaFieldClient = { export type CheckboxField = { admin?: { components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent afterInput?: CustomComponent[] beforeInput?: CustomComponent[] } & Admin['components'] @@ -524,8 +605,8 @@ export type CheckboxFieldClient = { export type DateField = { admin?: { components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent afterInput?: CustomComponent[] beforeInput?: CustomComponent[] } & Admin['components'] @@ -552,7 +633,7 @@ export type DateFieldClient = { export type GroupField = { admin?: { components?: { - Label?: LabelComponent + Label?: CustomComponent } & Admin['components'] hideGutter?: boolean } & Admin @@ -598,7 +679,9 @@ export type CollapsibleField = { | { admin: { components: { - Label?: LabelComponent + Label?: CustomComponent< + CollapsibleFieldLabelClientComponent | CollapsibleFieldLabelServerComponent + > RowLabel: RowLabelComponent } & Admin['components'] initCollapsed?: boolean @@ -608,7 +691,9 @@ export type CollapsibleField = { | { admin?: { components?: { - Label?: LabelComponent + Label?: CustomComponent< + CollapsibleFieldLabelClientComponent | CollapsibleFieldLabelServerComponent + > } & Admin['components'] initCollapsed?: boolean } & Admin @@ -742,8 +827,8 @@ export type UIFieldClient = { export type UploadField = { admin?: { components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent } & Admin['components'] } displayPreview?: boolean @@ -772,8 +857,8 @@ export type UploadFieldClient = { export type CodeField = { admin?: { components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent afterInput?: CustomComponent[] beforeInput?: CustomComponent[] } & Admin['components'] @@ -802,8 +887,8 @@ export type CodeFieldClient = { export type JSONField = { admin?: { components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent afterInput?: CustomComponent[] beforeInput?: CustomComponent[] } & Admin['components'] @@ -835,8 +920,8 @@ export type JSONFieldClient = { export type SelectField = { admin?: { components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent afterInput?: CustomComponent[] beforeInput?: CustomComponent[] } & Admin['components'] @@ -920,8 +1005,12 @@ type SharedRelationshipPropertiesClient = FieldBaseClient & type RelationshipAdmin = { allowCreate?: boolean components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent< + RelationshipFieldErrorClientComponent | RelationshipFieldErrorServerComponent + > + Label?: CustomComponent< + RelationshipFieldLabelClientComponent | RelationshipFieldLabelServerComponent + > } & Admin['components'] isSortable?: boolean } & Admin @@ -988,8 +1077,8 @@ export type RichTextField< > = { admin?: { components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent } & Admin['components'] } & Admin editor?: @@ -1015,6 +1104,7 @@ export type RichTextFieldClient< Error?: MappedComponent Label?: MappedComponent } & AdminClient['components'] + placeholder?: Record | string } & AdminClient richTextComponentMap?: Map } & FieldBaseClient & @@ -1024,8 +1114,8 @@ export type RichTextFieldClient< export type ArrayField = { admin?: { components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent RowLabel?: RowLabelComponent } & Admin['components'] initCollapsed?: boolean @@ -1070,8 +1160,8 @@ export type ArrayFieldClient = { export type RadioField = { admin?: { components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent } & Admin['components'] layout?: 'horizontal' | 'vertical' } & Admin @@ -1157,7 +1247,7 @@ export type ClientBlock = { export type BlockField = { admin?: { components?: { - Error?: ErrorComponent + Error?: CustomComponent } & Admin['components'] initCollapsed?: boolean /** @@ -1189,8 +1279,8 @@ export type BlockFieldClient = { export type PointField = { admin?: { components?: { - Error?: ErrorComponent - Label?: LabelComponent + Error?: CustomComponent + Label?: CustomComponent afterInput?: CustomComponent[] beforeInput?: CustomComponent[] } & Admin['components'] @@ -1260,6 +1350,28 @@ export type ClientField = | UIFieldClient | UploadFieldClient +export type ClientFieldProps = + | ArrayFieldProps + | BlockFieldProps + | CheckboxFieldProps + | CodeFieldProps + | CollapsibleFieldProps + | DateFieldProps + | EmailFieldProps + | GroupFieldProps + | HiddenFieldProps + | JSONFieldProps + | NumberFieldProps + | PointFieldProps + | RadioFieldProps + | RelationshipFieldProps + | RichTextFieldProps + | RowFieldProps + | SelectFieldProps + | TabsFieldProps + | TextareaFieldProps + | UploadFieldProps + type ExtractFieldTypes = T extends { type: infer U } ? U : never export type FieldTypes = ExtractFieldTypes @@ -1373,9 +1485,9 @@ export type FieldWithManyClient = RelationshipFieldClient | SelectFieldClient export type FieldWithMaxDepth = RelationshipField | UploadField export type FieldWithMaxDepthClient = RelationshipFieldClient | UploadFieldClient -export function fieldHasSubFields( - field: T, -): field is T & (T extends ClientField ? FieldWithSubFieldsClient : FieldWithSubFields) { +export function fieldHasSubFields( + field: TField, +): field is TField & (TField extends ClientField ? FieldWithSubFieldsClient : FieldWithSubFields) { return ( field.type === 'group' || field.type === 'array' || @@ -1384,21 +1496,21 @@ export function fieldHasSubFields( ) } -export function fieldIsArrayType( - field: T, -): field is T & (T extends ClientField ? ArrayFieldClient : ArrayField) { +export function fieldIsArrayType( + field: TField, +): field is TField & (TField extends ClientField ? ArrayFieldClient : ArrayField) { return field.type === 'array' } -export function fieldIsBlockType( - field: T, -): field is T & (T extends ClientField ? BlockFieldClient : BlockField) { +export function fieldIsBlockType( + field: TField, +): field is TField & (TField extends ClientField ? BlockFieldClient : BlockField) { return field.type === 'blocks' } -export function fieldIsGroupType( - field: T, -): field is T & (T extends ClientField ? GroupFieldClient : GroupField) { +export function fieldIsGroupType( + field: TField, +): field is TField & (TField extends ClientField ? GroupFieldClient : GroupField) { return field.type === 'group' } @@ -1414,40 +1526,44 @@ export function optionIsValue(option: Option): option is string { return typeof option === 'string' } -export function fieldSupportsMany( - field: T, -): field is T & (T extends ClientField ? FieldWithManyClient : FieldWithMany) { +export function fieldSupportsMany( + field: TField, +): field is TField & (TField extends ClientField ? FieldWithManyClient : FieldWithMany) { return field.type === 'select' || field.type === 'relationship' } -export function fieldHasMaxDepth( - field: T, -): field is T & (T extends ClientField ? FieldWithMaxDepthClient : FieldWithMaxDepth) { +export function fieldHasMaxDepth( + field: TField, +): field is TField & (TField extends ClientField ? FieldWithMaxDepthClient : FieldWithMaxDepth) { return ( (field.type === 'upload' || field.type === 'relationship') && typeof field.maxDepth === 'number' ) } export function fieldIsPresentationalOnly< - T extends ClientField | Field | TabAsField | TabAsFieldClient, ->(field: T): field is T & (T extends ClientField | TabAsFieldClient ? UIFieldClient : UIField) { + TField extends ClientField | Field | TabAsField | TabAsFieldClient, +>( + field: TField, +): field is TField & (TField extends ClientField | TabAsFieldClient ? UIFieldClient : UIField) { return field.type === 'ui' } -export function fieldIsSidebar( - field: T, -): field is { admin: { position: 'sidebar' } } & T { +export function fieldIsSidebar( + field: TField, +): field is { admin: { position: 'sidebar' } } & TField { return 'admin' in field && 'position' in field.admin && field.admin.position === 'sidebar' } -export function fieldAffectsData( - field: T, -): field is T & - (T extends ClientField | TabAsFieldClient ? FieldAffectingDataClient : FieldAffectingData) { +export function fieldAffectsData< + TField extends ClientField | Field | TabAsField | TabAsFieldClient, +>( + field: TField, +): field is TField & + (TField extends ClientField | TabAsFieldClient ? FieldAffectingDataClient : FieldAffectingData) { return 'name' in field && !fieldIsPresentationalOnly(field) } -export function tabHasName(tab: T): tab is NamedTab & T { +export function tabHasName(tab: TField): tab is NamedTab & TField { return 'name' in tab } diff --git a/packages/payload/src/utilities/flattenTopLevelFields.ts b/packages/payload/src/utilities/flattenTopLevelFields.ts index cb5118b8a..5537c54ef 100644 --- a/packages/payload/src/utilities/flattenTopLevelFields.ts +++ b/packages/payload/src/utilities/flattenTopLevelFields.ts @@ -1,3 +1,4 @@ +import type { ClientTab } from '../admin/fields/Tabs.js' import type { ClientField } from '../fields/config/client.js' import type { Field, @@ -14,13 +15,12 @@ import { fieldIsPresentationalOnly, tabHasName, } from '../fields/config/types.js' -import { ClientTab } from '../admin/fields/Tabs.js' -type FlattenedField = T extends ClientField +type FlattenedField = TField extends ClientField ? FieldAffectingDataClient | FieldPresentationalOnlyClient : FieldAffectingData | FieldPresentationalOnly -type TabType = T extends ClientField ? ClientTab : Tab +type TabType = TField extends ClientField ? ClientTab : Tab /** * Flattens a collection's fields into a single array of fields, as long @@ -29,27 +29,30 @@ type TabType = T extends ClientField ? ClientTab : Tab * @param fields * @param keepPresentationalFields if true, will skip flattening fields that are presentational only */ -function flattenFields( - fields: T[], +function flattenFields( + fields: TField[], keepPresentationalFields?: boolean, -): FlattenedField[] { - return fields.reduce[]>((fieldsToUse, field) => { +): FlattenedField[] { + return fields.reduce[]>((fieldsToUse, field) => { if (fieldAffectsData(field) || (keepPresentationalFields && fieldIsPresentationalOnly(field))) { - return [...fieldsToUse, field as FlattenedField] + return [...fieldsToUse, field as FlattenedField] } if (fieldHasSubFields(field)) { - return [...fieldsToUse, ...flattenFields(field.fields as T[], keepPresentationalFields)] + return [...fieldsToUse, ...flattenFields(field.fields as TField[], keepPresentationalFields)] } if (field.type === 'tabs' && 'tabs' in field) { return [ ...fieldsToUse, - ...field.tabs.reduce[]>((tabFields, tab: TabType) => { + ...field.tabs.reduce[]>((tabFields, tab: TabType) => { if (tabHasName(tab)) { - return [...tabFields, { ...tab, type: 'tab' } as unknown as FlattenedField] + return [...tabFields, { ...tab, type: 'tab' } as unknown as FlattenedField] } else { - return [...tabFields, ...flattenFields(tab.fields as T[], keepPresentationalFields)] + return [ + ...tabFields, + ...flattenFields(tab.fields as TField[], keepPresentationalFields), + ] } }, []), ] diff --git a/packages/plugin-cloud-storage/src/admin/fields/getFields.ts b/packages/plugin-cloud-storage/src/admin/fields/getFields.ts index 8696654b1..edc7fcc43 100644 --- a/packages/plugin-cloud-storage/src/admin/fields/getFields.ts +++ b/packages/plugin-cloud-storage/src/admin/fields/getFields.ts @@ -88,7 +88,7 @@ export const getFields = ({ collection, prefix }: Args): Field[] => { type: 'group', fields: [ { - ...(existingSizeURLField || {}), + ...(existingSizeURLField || ({} as any)), ...baseURLField, }, ], diff --git a/packages/plugin-cloud-storage/src/fields/getFields.ts b/packages/plugin-cloud-storage/src/fields/getFields.ts index 39b2d54a8..7600f3598 100644 --- a/packages/plugin-cloud-storage/src/fields/getFields.ts +++ b/packages/plugin-cloud-storage/src/fields/getFields.ts @@ -108,7 +108,7 @@ export const getFields = ({ fields: [ ...(adapter.fields || []), { - ...(existingSizeURLField || {}), + ...(existingSizeURLField || ({} as any)), ...baseURLField, hooks: { afterRead: [ diff --git a/packages/plugin-seo/src/fields/MetaDescription/MetaDescriptionComponent.tsx b/packages/plugin-seo/src/fields/MetaDescription/MetaDescriptionComponent.tsx index 917d6bb61..bda292f97 100644 --- a/packages/plugin-seo/src/fields/MetaDescription/MetaDescriptionComponent.tsx +++ b/packages/plugin-seo/src/fields/MetaDescription/MetaDescriptionComponent.tsx @@ -24,7 +24,7 @@ import { LengthIndicator } from '../../ui/LengthIndicator.js' const { maxLength, minLength } = defaults.description type MetaDescriptionProps = { - hasGenerateDescriptionFn: boolean + readonly hasGenerateDescriptionFn: boolean } & TextareaFieldProps export const MetaDescriptionComponent: React.FC = (props) => { @@ -58,9 +58,16 @@ export const MetaDescriptionComponent: React.FC = (props) const genDescriptionResponse = await fetch('/api/plugin-seo/generate-description', { body: JSON.stringify({ - ...docInfo, - doc: { ...getData() }, + id: docInfo.id, + slug: docInfo.slug, + doc: getData(), + docPermissions: docInfo.docPermissions, + hasPublishPermission: docInfo.hasPublishPermission, + hasSavePermission: docInfo.hasSavePermission, + initialData: docInfo.initialData, + initialState: docInfo.initialState, locale: typeof locale === 'object' ? locale?.code : locale, + title: docInfo.title, } satisfies Omit[0], 'req'>), credentials: 'include', headers: { @@ -87,7 +94,7 @@ export const MetaDescriptionComponent: React.FC = (props) }} >
- + {hasGenerateDescriptionFn && (   —   diff --git a/packages/plugin-seo/src/fields/MetaImage/MetaImageComponent.tsx b/packages/plugin-seo/src/fields/MetaImage/MetaImageComponent.tsx index ee78c3399..b8dd9a666 100644 --- a/packages/plugin-seo/src/fields/MetaImage/MetaImageComponent.tsx +++ b/packages/plugin-seo/src/fields/MetaImage/MetaImageComponent.tsx @@ -21,7 +21,7 @@ import type { GenerateImage } from '../../types.js' import { Pill } from '../../ui/Pill.js' type MetaImageProps = { - hasGenerateImageFn: boolean + readonly hasGenerateImageFn: boolean } & UploadFieldProps export const MetaImageComponent: React.FC = (props) => { @@ -54,9 +54,16 @@ export const MetaImageComponent: React.FC = (props) => { const genImageResponse = await fetch('/api/plugin-seo/generate-image', { body: JSON.stringify({ - ...docInfo, - doc: { ...getData() }, + id: docInfo.id, + slug: docInfo.slug, + doc: getData(), + docPermissions: docInfo.docPermissions, + hasPublishPermission: docInfo.hasPublishPermission, + hasSavePermission: docInfo.hasSavePermission, + initialData: docInfo.initialData, + initialState: docInfo.initialState, locale: typeof locale === 'object' ? locale?.code : locale, + title: docInfo.title, } satisfies Omit[0], 'req'>), credentials: 'include', headers: { @@ -91,7 +98,7 @@ export const MetaImageComponent: React.FC = (props) => { }} >
- + {hasGenerateImageFn && (   —   diff --git a/packages/plugin-seo/src/fields/MetaTitle/MetaTitleComponent.tsx b/packages/plugin-seo/src/fields/MetaTitle/MetaTitleComponent.tsx index 795baa59c..79aa480e7 100644 --- a/packages/plugin-seo/src/fields/MetaTitle/MetaTitleComponent.tsx +++ b/packages/plugin-seo/src/fields/MetaTitle/MetaTitleComponent.tsx @@ -25,7 +25,7 @@ import '../index.scss' const { maxLength, minLength } = defaults.title type MetaTitleProps = { - hasGenerateTitleFn: boolean + readonly hasGenerateTitleFn: boolean } & TextFieldProps export const MetaTitleComponent: React.FC = (props) => { @@ -59,9 +59,16 @@ export const MetaTitleComponent: React.FC = (props) => { const genTitleResponse = await fetch('/api/plugin-seo/generate-title', { body: JSON.stringify({ - ...docInfo, - doc: { ...getData() }, + id: docInfo.id, + slug: docInfo.slug, + doc: getData(), + docPermissions: docInfo.docPermissions, + hasPublishPermission: docInfo.hasPublishPermission, + hasSavePermission: docInfo.hasSavePermission, + initialData: docInfo.initialData, + initialState: docInfo.initialState, locale: typeof locale === 'object' ? locale?.code : locale, + title: docInfo.title, } satisfies Omit[0], 'req'>), credentials: 'include', headers: { @@ -88,7 +95,7 @@ export const MetaTitleComponent: React.FC = (props) => { }} >
- + {hasGenerateTitleFn && (   —   diff --git a/packages/plugin-seo/src/fields/Preview/PreviewComponent.tsx b/packages/plugin-seo/src/fields/Preview/PreviewComponent.tsx index b6d195757..62afc9de3 100644 --- a/packages/plugin-seo/src/fields/Preview/PreviewComponent.tsx +++ b/packages/plugin-seo/src/fields/Preview/PreviewComponent.tsx @@ -15,16 +15,18 @@ import type { PluginSEOTranslationKeys, PluginSEOTranslations } from '../../tran import type { GenerateURL } from '../../types.js' type PreviewProps = { - descriptionPath?: string - hasGenerateURLFn: boolean - titlePath?: string + readonly descriptionPath?: string + readonly hasGenerateURLFn: boolean + readonly titlePath?: string } & UIField -export const PreviewComponent: React.FC = ({ - descriptionPath: descriptionPathFromContext, - hasGenerateURLFn, - titlePath: titlePathFromContext, -}) => { +export const PreviewComponent: React.FC = (props) => { + const { + descriptionPath: descriptionPathFromContext, + hasGenerateURLFn, + titlePath: titlePathFromContext, + } = props + const { t } = useTranslation() const locale = useLocale() @@ -46,9 +48,15 @@ export const PreviewComponent: React.FC = ({ const getHref = async () => { const genURLResponse = await fetch('/api/plugin-seo/generate-url', { body: JSON.stringify({ - ...docInfo, - doc: { ...getData() }, + id: docInfo.id, + doc: getData(), + docPermissions: docInfo.docPermissions, + hasPublishPermission: docInfo.hasPublishPermission, + hasSavePermission: docInfo.hasSavePermission, + initialData: docInfo.initialData, + initialState: docInfo.initialState, locale: typeof locale === 'object' ? locale?.code : locale, + title: docInfo.title, } satisfies Omit[0], 'req'>), credentials: 'include', headers: { diff --git a/packages/plugin-seo/src/types.ts b/packages/plugin-seo/src/types.ts index ed0078bea..ab1fe0654 100644 --- a/packages/plugin-seo/src/types.ts +++ b/packages/plugin-seo/src/types.ts @@ -1,8 +1,23 @@ import type { DocumentInfoContext } from '@payloadcms/ui' import type { Field, PayloadRequest, TextField, TextareaField, UploadField } from 'payload' +export type PartialDocumentInfoContext = Pick< + DocumentInfoContext, + | 'docPermissions' + | 'hasPublishPermission' + | 'hasSavePermission' + | 'id' + | 'initialData' + | 'initialState' + | 'preferencesKey' + | 'publishedDoc' + | 'slug' + | 'title' + | 'versionsCount' +> + export type GenerateTitle = ( - args: { doc: T; locale?: string; req: PayloadRequest } & DocumentInfoContext, + args: { doc: T; locale?: string; req: PayloadRequest } & PartialDocumentInfoContext, ) => Promise | string export type GenerateDescription = ( @@ -10,15 +25,15 @@ export type GenerateDescription = ( doc: T locale?: string req: PayloadRequest - } & DocumentInfoContext, + } & PartialDocumentInfoContext, ) => Promise | string export type GenerateImage = ( - args: { doc: T; locale?: string; req: PayloadRequest } & DocumentInfoContext, + args: { doc: T; locale?: string; req: PayloadRequest } & PartialDocumentInfoContext, ) => Promise | string export type GenerateURL = ( - args: { doc: T; locale?: string; req: PayloadRequest } & DocumentInfoContext, + args: { doc: T; locale?: string; req: PayloadRequest } & PartialDocumentInfoContext, ) => Promise | string export type SEOPluginConfig = { diff --git a/packages/richtext-lexical/src/cell/index.tsx b/packages/richtext-lexical/src/cell/index.tsx index bca069f35..b00520bc2 100644 --- a/packages/richtext-lexical/src/cell/index.tsx +++ b/packages/richtext-lexical/src/cell/index.tsx @@ -18,8 +18,8 @@ import { getEnabledNodes } from '../lexical/nodes/index.js' export const RichTextCell: React.FC< { - admin?: LexicalFieldAdminProps - lexicalEditorConfig: LexicalEditorConfig + readonly admin?: LexicalFieldAdminProps + readonly lexicalEditorConfig: LexicalEditorConfig } & CellComponentProps > = (props) => { const { diff --git a/packages/richtext-lexical/src/field/Field.tsx b/packages/richtext-lexical/src/field/Field.tsx index 22110e439..afc698677 100644 --- a/packages/richtext-lexical/src/field/Field.tsx +++ b/packages/richtext-lexical/src/field/Field.tsx @@ -94,8 +94,20 @@ const RichTextComponent: React.FC< width, }} > - - + +
{}}> - +
) diff --git a/packages/richtext-lexical/src/utilities/generateComponentMap.tsx b/packages/richtext-lexical/src/utilities/generateComponentMap.tsx index ec04ecdd2..92247e47d 100644 --- a/packages/richtext-lexical/src/utilities/generateComponentMap.tsx +++ b/packages/richtext-lexical/src/utilities/generateComponentMap.tsx @@ -44,9 +44,11 @@ export const getGenerateComponentMap = const mappedComponent: MappedComponent = createMappedComponent( payloadComponent, { - componentKey, - featureKey: resolvedFeature.key, - key: `${resolvedFeature.key}-${componentKey}`, + clientProps: { + componentKey, + featureKey: resolvedFeature.key, + key: `${resolvedFeature.key}-${componentKey}`, + }, }, undefined, 'lexical-from-resolvedFeature', diff --git a/packages/richtext-slate/src/field/RichText.tsx b/packages/richtext-slate/src/field/RichText.tsx index d86a2d98a..f2acf6cea 100644 --- a/packages/richtext-slate/src/field/RichText.tsx +++ b/packages/richtext-slate/src/field/RichText.tsx @@ -54,6 +54,7 @@ const RichTextField: React.FC = (props) => { descriptionProps, elements, errorProps, + field, field: { name, _path: pathFromProps, @@ -316,9 +317,15 @@ const RichTextField: React.FC = (props) => { width, }} > - +
- + = (props) => {
- +
) diff --git a/packages/ui/src/elements/FieldSelect/index.tsx b/packages/ui/src/elements/FieldSelect/index.tsx index c117319db..417f41f1b 100644 --- a/packages/ui/src/elements/FieldSelect/index.tsx +++ b/packages/ui/src/elements/FieldSelect/index.tsx @@ -175,7 +175,7 @@ export const FieldSelect: React.FC = ({ fields, setSelected }) return (
- + { if (typeof option.value === 'object' && 'path' in option.value) { diff --git a/packages/ui/src/elements/ListDrawer/DrawerContent.tsx b/packages/ui/src/elements/ListDrawer/DrawerContent.tsx index 2bf92f7a9..62e4f5f97 100644 --- a/packages/ui/src/elements/ListDrawer/DrawerContent.tsx +++ b/packages/ui/src/elements/ListDrawer/DrawerContent.tsx @@ -258,7 +258,7 @@ export const ListDrawerContent: React.FC = ({ )} {moreThanOneAvailableCollection && (
- + { const Label = ( diff --git a/packages/ui/src/elements/Upload/index.tsx b/packages/ui/src/elements/Upload/index.tsx index 9123d6176..b48135154 100644 --- a/packages/ui/src/elements/Upload/index.tsx +++ b/packages/ui/src/elements/Upload/index.tsx @@ -222,7 +222,7 @@ export const Upload: React.FC = (props) => { return (
- + {doc.filename && !replacingFile && ( string +export type ViewDescriptionComponent = React.ComponentType -export type DescriptionComponent = React.ComponentType - -type Description = DescriptionComponent | DescriptionFunction | Record | string +type Description = DescriptionFunction | StaticDescription | ViewDescriptionComponent | string export type ViewDescriptionProps = { - description?: Description + readonly description?: Description } -export function isComponent(description: Description): description is DescriptionComponent { +export function isComponent(description: Description): description is ViewDescriptionComponent { return React.isValidElement(description) } @@ -29,11 +29,7 @@ export const ViewDescription: React.FC = (props) => { } if (description) { - return ( -
- {typeof description === 'function' ? description() : getTranslation(description, i18n)} -
- ) + return
{getTranslation(description, i18n)}
} return null diff --git a/packages/ui/src/fields/Array/index.tsx b/packages/ui/src/fields/Array/index.tsx index 491862bf1..36e4ab565 100644 --- a/packages/ui/src/fields/Array/index.tsx +++ b/packages/ui/src/fields/Array/index.tsx @@ -215,6 +215,7 @@ export const ArrayFieldComponent: React.FC = (props) => { {showError && ( @@ -226,6 +227,7 @@ export const ArrayFieldComponent: React.FC = (props) => { = (props) => { diff --git a/packages/ui/src/fields/Blocks/index.tsx b/packages/ui/src/fields/Blocks/index.tsx index 674312cce..c2595364d 100644 --- a/packages/ui/src/fields/Blocks/index.tsx +++ b/packages/ui/src/fields/Blocks/index.tsx @@ -56,6 +56,7 @@ const BlocksFieldComponent: React.FC = (props) => { readOnly: readOnlyFromTopLevelProps, validate, } = props + const readOnlyFromProps = readOnlyFromTopLevelProps || readOnlyFromAdmin const { indexPath, readOnly: readOnlyFromContext } = useFieldProps() @@ -217,6 +218,7 @@ const BlocksFieldComponent: React.FC = (props) => { {showError && ( @@ -228,6 +230,7 @@ const BlocksFieldComponent: React.FC = (props) => { = (props) => { diff --git a/packages/ui/src/fields/Checkbox/Input.tsx b/packages/ui/src/fields/Checkbox/Input.tsx index 3115b410a..94bc93e74 100644 --- a/packages/ui/src/fields/Checkbox/Input.tsx +++ b/packages/ui/src/fields/Checkbox/Input.tsx @@ -1,5 +1,11 @@ 'use client' -import type { LabelProps, MappedComponent, SanitizedLabelProps } from 'payload' +import type { + CheckboxFieldClient, + FieldLabelClientProps, + MappedComponent, + StaticLabel, +} from 'payload' +import type { MarkOptional } from 'ts-essentials' import React from 'react' @@ -14,10 +20,11 @@ export type CheckboxInputProps = { readonly beforeInput?: MappedComponent[] readonly checked?: boolean readonly className?: string + readonly field?: MarkOptional readonly id?: string readonly inputRef?: React.RefObject - readonly label?: LabelProps<'checkbox'>['label'] - readonly labelProps?: SanitizedLabelProps + readonly label?: StaticLabel + readonly labelProps?: FieldLabelClientProps> readonly name?: string readonly onToggle: (event: React.ChangeEvent) => void readonly partialChecked?: boolean @@ -35,6 +42,7 @@ export const CheckboxInput: React.FC = ({ beforeInput, checked, className, + field, inputRef, label, labelProps, @@ -79,6 +87,7 @@ export const CheckboxInput: React.FC = ({
= (props) => { > = (props) => {
diff --git a/packages/ui/src/fields/Code/index.tsx b/packages/ui/src/fields/Code/index.tsx index 2f199d189..09aba0fee 100644 --- a/packages/ui/src/fields/Code/index.tsx +++ b/packages/ui/src/fields/Code/index.tsx @@ -85,6 +85,7 @@ const CodeFieldComponent: React.FC = (props) => { > = (props) => {
@@ -108,6 +110,7 @@ const CodeFieldComponent: React.FC = (props) => {
diff --git a/packages/ui/src/fields/Collapsible/index.tsx b/packages/ui/src/fields/Collapsible/index.tsx index 47f19f76c..2b2a9fa66 100644 --- a/packages/ui/src/fields/Collapsible/index.tsx +++ b/packages/ui/src/fields/Collapsible/index.tsx @@ -163,6 +163,7 @@ const CollapsibleFieldComponent: React.FC = (props) => {
diff --git a/packages/ui/src/fields/ConfirmPassword/index.tsx b/packages/ui/src/fields/ConfirmPassword/index.tsx index 1e22f0971..968c33bc9 100644 --- a/packages/ui/src/fields/ConfirmPassword/index.tsx +++ b/packages/ui/src/fields/ConfirmPassword/index.tsx @@ -38,12 +38,13 @@ export const ConfirmPasswordField: React.FC = (props) .join(' ')} >
- + {/* disable eslint here because the label is dynamic */} {} = (props) => { > = (props) => {
@@ -108,6 +110,7 @@ const DateTimeFieldComponent: React.FC = (props) => {
diff --git a/packages/ui/src/fields/Email/index.tsx b/packages/ui/src/fields/Email/index.tsx index 562f061c8..87f0f1d1a 100644 --- a/packages/ui/src/fields/Email/index.tsx +++ b/packages/ui/src/fields/Email/index.tsx @@ -20,7 +20,6 @@ const EmailFieldComponent: React.FC = (props) => { autoComplete, descriptionProps, errorProps, - field, field: { name, _path: pathFromProps, @@ -36,10 +35,12 @@ const EmailFieldComponent: React.FC = (props) => { label, required, } = {} as EmailFieldProps['field'], + field, labelProps, readOnly: readOnlyFromTopLevelProps, validate, } = props + const readOnlyFromProps = readOnlyFromTopLevelProps || readOnlyFromAdmin const { i18n } = useTranslation() @@ -74,6 +75,7 @@ const EmailFieldComponent: React.FC = (props) => { > = (props) => {
@@ -103,6 +106,7 @@ const EmailFieldComponent: React.FC = (props) => {
diff --git a/packages/ui/src/fields/FieldDescription/index.tsx b/packages/ui/src/fields/FieldDescription/index.tsx index a997e2a80..48d93c26d 100644 --- a/packages/ui/src/fields/FieldDescription/index.tsx +++ b/packages/ui/src/fields/FieldDescription/index.tsx @@ -1,5 +1,5 @@ 'use client' -import type { GenericDescriptionProps } from 'payload' +import type { FieldDescriptionClientComponent, GenericDescriptionProps } from 'payload' import { getTranslation } from '@payloadcms/translations' import React from 'react' @@ -38,7 +38,7 @@ const DefaultFieldDescription: React.FC = (props) => { return null } -export const FieldDescription: React.FC = (props) => { +export const FieldDescription: FieldDescriptionClientComponent = (props) => { const { Description, ...rest } = props if (Description) { diff --git a/packages/ui/src/fields/FieldError/index.tsx b/packages/ui/src/fields/FieldError/index.tsx index bd392ae88..07e8555b7 100644 --- a/packages/ui/src/fields/FieldError/index.tsx +++ b/packages/ui/src/fields/FieldError/index.tsx @@ -1,6 +1,6 @@ 'use client' -import type { GenericErrorProps } from 'payload' +import type { FieldErrorClientComponent, GenericErrorProps } from 'payload' import React from 'react' @@ -42,7 +42,7 @@ const DefaultFieldError: React.FC = (props) => { return null } -export const FieldError: React.FC = (props) => { +export const FieldError: FieldErrorClientComponent = (props) => { const { CustomError, ...rest } = props if (CustomError) { diff --git a/packages/ui/src/fields/FieldLabel/index.tsx b/packages/ui/src/fields/FieldLabel/index.tsx index 8a0918628..6ee0b13e2 100644 --- a/packages/ui/src/fields/FieldLabel/index.tsx +++ b/packages/ui/src/fields/FieldLabel/index.tsx @@ -1,6 +1,6 @@ 'use client' -import type { GenericLabelProps } from 'payload' +import type { FieldLabelClientComponent, GenericLabelProps } from 'payload' import { getTranslation } from '@payloadcms/translations' import React from 'react' @@ -41,7 +41,7 @@ const DefaultFieldLabel: React.FC = (props) => { return null } -export const FieldLabel: React.FC = (props) => { +export const FieldLabel: FieldLabelClientComponent = (props) => { const { Label, ...rest } = props if (Label) { diff --git a/packages/ui/src/fields/Group/index.tsx b/packages/ui/src/fields/Group/index.tsx index 293441497..83ec3df04 100644 --- a/packages/ui/src/fields/Group/index.tsx +++ b/packages/ui/src/fields/Group/index.tsx @@ -96,6 +96,7 @@ export const GroupFieldComponent: React.FC = (props) => { diff --git a/packages/ui/src/fields/JSON/index.tsx b/packages/ui/src/fields/JSON/index.tsx index 260171bb6..7d2fe98f6 100644 --- a/packages/ui/src/fields/JSON/index.tsx +++ b/packages/ui/src/fields/JSON/index.tsx @@ -128,6 +128,7 @@ const JSONFieldComponent: React.FC = (props) => { > = (props) => {
@@ -152,6 +154,7 @@ const JSONFieldComponent: React.FC = (props) => {
diff --git a/packages/ui/src/fields/Number/index.tsx b/packages/ui/src/fields/Number/index.tsx index 0005f7d42..8fb6fd6c6 100644 --- a/packages/ui/src/fields/Number/index.tsx +++ b/packages/ui/src/fields/Number/index.tsx @@ -149,6 +149,7 @@ const NumberFieldComponent: React.FC = (props) => { > = (props) => {
@@ -210,6 +212,7 @@ const NumberFieldComponent: React.FC = (props) => {
diff --git a/packages/ui/src/fields/Password/input.tsx b/packages/ui/src/fields/Password/input.tsx index d2bf996cb..5b9fcdde2 100644 --- a/packages/ui/src/fields/Password/input.tsx +++ b/packages/ui/src/fields/Password/input.tsx @@ -23,6 +23,7 @@ export const PasswordInput: React.FC = (props) => { beforeInput, className, errorProps, + field, inputRef, label, labelProps, @@ -59,13 +60,14 @@ export const PasswordInput: React.FC = (props) => { >
- +
> + readonly errorProps?: FieldErrorClientProps> readonly field: MarkOptional readonly inputRef?: React.RefObject + readonly labelProps?: FieldLabelClientProps> readonly validate?: PasswordFieldValidation } & FormFieldBase @@ -28,10 +32,11 @@ export type PasswordInputProps = { readonly beforeInput?: MappedComponent[] readonly className?: string readonly description?: StaticDescription - readonly errorProps: ErrorProps + readonly errorProps: FieldErrorClientProps> + readonly field?: MarkOptional readonly inputRef?: React.RefObject readonly label: FieldBaseClient['label'] - readonly labelProps: LabelProps + readonly labelProps: FieldLabelClientProps> readonly onChange?: (e: ChangeEvent) => void readonly onKeyDown?: React.KeyboardEventHandler readonly path: string diff --git a/packages/ui/src/fields/Point/index.tsx b/packages/ui/src/fields/Point/index.tsx index cd0851955..7b5da32f3 100644 --- a/packages/ui/src/fields/Point/index.tsx +++ b/packages/ui/src/fields/Point/index.tsx @@ -133,11 +133,13 @@ export const PointFieldComponent: React.FC = (props) => {
  • @@ -161,6 +163,7 @@ export const PointFieldComponent: React.FC = (props) => {
    diff --git a/packages/ui/src/fields/RadioGroup/index.tsx b/packages/ui/src/fields/RadioGroup/index.tsx index baf1c4169..54ec13058 100644 --- a/packages/ui/src/fields/RadioGroup/index.tsx +++ b/packages/ui/src/fields/RadioGroup/index.tsx @@ -93,12 +93,14 @@ const RadioGroupFieldComponent: React.FC = (props) => { > = (props) => {
  • diff --git a/packages/ui/src/fields/Relationship/index.tsx b/packages/ui/src/fields/Relationship/index.tsx index bc3f6d509..ae34fc693 100644 --- a/packages/ui/src/fields/Relationship/index.tsx +++ b/packages/ui/src/fields/Relationship/index.tsx @@ -489,6 +489,7 @@ const RelationshipFieldComponent: React.FC = (props) => > = (props) =>
    @@ -606,6 +608,7 @@ const RelationshipFieldComponent: React.FC = (props) =>
    diff --git a/packages/ui/src/fields/Select/Input.tsx b/packages/ui/src/fields/Select/Input.tsx index c8e78fc1f..ccccbc1a7 100644 --- a/packages/ui/src/fields/Select/Input.tsx +++ b/packages/ui/src/fields/Select/Input.tsx @@ -1,5 +1,12 @@ 'use client' -import type { MappedComponent, OptionObject, StaticDescription, StaticLabel } from 'payload' +import type { + MappedComponent, + OptionObject, + SelectFieldClient, + StaticDescription, + StaticLabel, +} from 'payload' +import type { MarkOptional } from 'ts-essentials' import { getTranslation } from '@payloadcms/translations' import React from 'react' @@ -25,6 +32,7 @@ export type SelectInputProps = { readonly description?: StaticDescription readonly descriptionProps?: Record readonly errorProps?: Record + readonly field?: MarkOptional readonly hasMany?: boolean readonly isClearable?: boolean readonly isSortable?: boolean @@ -53,6 +61,7 @@ export const SelectInput: React.FC = (props) => { description, descriptionProps, errorProps, + field, hasMany = false, isClearable = true, isSortable = true, @@ -106,9 +115,15 @@ export const SelectInput: React.FC = (props) => { width, }} > - +
    - + = (props) => {
    diff --git a/packages/ui/src/fields/Select/index.tsx b/packages/ui/src/fields/Select/index.tsx index 06fd943e1..ec11ae166 100644 --- a/packages/ui/src/fields/Select/index.tsx +++ b/packages/ui/src/fields/Select/index.tsx @@ -101,6 +101,7 @@ const SelectFieldComponent: React.FC = (props) => { beforeInput={field?.admin?.components?.beforeInput} className={className} description={description} + field={field} hasMany={hasMany} isClearable={isClearable} isSortable={isSortable} diff --git a/packages/ui/src/fields/Tabs/index.tsx b/packages/ui/src/fields/Tabs/index.tsx index afd8c76a7..b474ee249 100644 --- a/packages/ui/src/fields/Tabs/index.tsx +++ b/packages/ui/src/fields/Tabs/index.tsx @@ -154,7 +154,7 @@ const TabsFieldComponent: React.FC = (props) => { .filter(Boolean) .join(' ')} > - + = (props) => { description, descriptionProps, errorProps, + field, hasMany, inputRef, label, @@ -64,9 +65,15 @@ export const TextInput: React.FC = (props) => { width, }} > - +
    - + {hasMany ? ( = (props) => {
    diff --git a/packages/ui/src/fields/Text/index.tsx b/packages/ui/src/fields/Text/index.tsx index bcefd7c56..c7325c18f 100644 --- a/packages/ui/src/fields/Text/index.tsx +++ b/packages/ui/src/fields/Text/index.tsx @@ -127,6 +127,7 @@ const TextFieldComponent: React.FC = (props) => { beforeInput={field?.admin?.components?.beforeInput} className={className} description={description} + field={field} hasMany={hasMany} inputRef={inputRef} label={label} diff --git a/packages/ui/src/fields/Text/types.ts b/packages/ui/src/fields/Text/types.ts index 9248ac7fe..fb852cf78 100644 --- a/packages/ui/src/fields/Text/types.ts +++ b/packages/ui/src/fields/Text/types.ts @@ -1,6 +1,7 @@ -import type { MappedComponent, StaticDescription, StaticLabel } from 'payload' +import type { MappedComponent, StaticDescription, StaticLabel, TextFieldClient } from 'payload' import type { ChangeEvent } from 'react' import type React from 'react' +import type { MarkOptional } from 'ts-essentials' import type { Option, ReactSelectAdapterProps } from '../../elements/ReactSelect/types.js' @@ -24,6 +25,7 @@ export type TextInputProps = { readonly description?: StaticDescription readonly descriptionProps?: Record readonly errorProps?: Record + readonly field?: MarkOptional readonly inputRef?: React.RefObject readonly label: StaticLabel readonly labelProps?: Record diff --git a/packages/ui/src/fields/Textarea/Input.tsx b/packages/ui/src/fields/Textarea/Input.tsx index 28e563953..7efc8936d 100644 --- a/packages/ui/src/fields/Textarea/Input.tsx +++ b/packages/ui/src/fields/Textarea/Input.tsx @@ -23,6 +23,7 @@ export const TextareaInput: React.FC = (props) => { description, descriptionProps, errorProps, + field, label, labelProps, onChange, @@ -56,9 +57,15 @@ export const TextareaInput: React.FC = (props) => { width, }} > - +
    - +
    )} - + )} {!readOnly && } diff --git a/packages/ui/src/fields/Upload/index.tsx b/packages/ui/src/fields/Upload/index.tsx index 1e735087b..7b46b41fa 100644 --- a/packages/ui/src/fields/Upload/index.tsx +++ b/packages/ui/src/fields/Upload/index.tsx @@ -19,6 +19,8 @@ export type { UploadInputProps } const UploadComponent: React.FC = (props) => { const { + descriptionProps, + errorProps, field, field: { _path: pathFromProps, @@ -27,9 +29,11 @@ const UploadComponent: React.FC = (props) => { relationTo, required, }, + labelProps, readOnly: readOnlyFromTopLevelProps, validate, } = props + const readOnlyFromProps = readOnlyFromTopLevelProps || readOnlyFromAdmin const { @@ -92,8 +96,11 @@ const UploadComponent: React.FC = (props) => { api={apiRoute} className={className} collection={collection} + descriptionProps={descriptionProps} + errorProps={errorProps} filterOptions={filterOptions} label={label} + labelProps={labelProps} onChange={onChange} readOnly={disabled} relationTo={relationTo} diff --git a/packages/ui/src/forms/RowLabel/types.ts b/packages/ui/src/forms/RowLabel/types.ts index 84150e0be..b5da11ad5 100644 --- a/packages/ui/src/forms/RowLabel/types.ts +++ b/packages/ui/src/forms/RowLabel/types.ts @@ -1,11 +1,11 @@ import type { I18nClient } from '@payloadcms/translations' -import type { LabelProps, MappedComponent } from 'payload' +import type { MappedComponent, StaticLabel } from 'payload' export type RowLabelProps = { readonly RowLabel?: MappedComponent readonly className?: string readonly i18n: I18nClient readonly path: string - readonly rowLabel?: LabelProps['label'] + readonly rowLabel?: StaticLabel readonly rowNumber?: number } diff --git a/packages/ui/src/providers/Config/createClientConfig/collections.tsx b/packages/ui/src/providers/Config/createClientConfig/collections.tsx index 25f802223..13163dd09 100644 --- a/packages/ui/src/providers/Config/createClientConfig/collections.tsx +++ b/packages/ui/src/providers/Config/createClientConfig/collections.tsx @@ -210,6 +210,7 @@ export const createClientCollectionConfig = ({ } let description = undefined + if (collection.admin?.description) { if ( typeof collection.admin?.description === 'string' || @@ -220,13 +221,16 @@ export const createClientCollectionConfig = ({ description = collection.admin?.description({ t: i18n.t }) } } + clientCollection.admin.description = description if (collection.admin.components.edit?.Description) { clientCollection.admin.components.edit.Description = createMappedComponent( collection.admin.components.edit.Description, { - description, + clientProps: { + description, + }, }, undefined, 'collection.admin.components.edit.Description', @@ -261,7 +265,9 @@ export const createClientCollectionConfig = ({ ? collection.admin.components.views.edit.default.Component : null, { - collectionSlug: collection.slug, + clientProps: { + collectionSlug: collection.slug, + }, }, DefaultEditView, 'collection.admin.components.views.edit.default', @@ -280,7 +286,9 @@ export const createClientCollectionConfig = ({ clientCollection.admin.components.views.edit[key].Component = createMappedComponent( view.Component, { - collectionSlug: collection.slug, + clientProps: { + collectionSlug: collection.slug, + }, }, undefined, 'collection.admin.components.views.edit.key.Component', @@ -318,7 +326,9 @@ export const createClientCollectionConfig = ({ ? collection.admin.components.views.list.Component : null, { - collectionSlug: collection.slug, + clientProps: { + collectionSlug: collection.slug, + }, }, DefaultListView, 'collection.admin.components.views.list', diff --git a/packages/ui/src/providers/Config/createClientConfig/fields.tsx b/packages/ui/src/providers/Config/createClientConfig/fields.tsx index d1a8afa09..41ca91ccf 100644 --- a/packages/ui/src/providers/Config/createClientConfig/fields.tsx +++ b/packages/ui/src/providers/Config/createClientConfig/fields.tsx @@ -7,8 +7,9 @@ import type { ClientField, CreateMappedComponent, Field, + FieldLabelClientComponent, + FieldLabelServerComponent, ImportMap, - LabelComponent, LabelsClient, MappedComponent, Payload, @@ -106,12 +107,14 @@ export const createClientField = ({ clientField.label = incomingField.label({ t: i18n.t }) } - const CustomLabel: LabelComponent | RowLabelComponent = + const CustomLabel: FieldLabelClientComponent | FieldLabelServerComponent | RowLabelComponent = 'admin' in incomingField && 'components' in incomingField.admin && 'Label' in incomingField.admin.components && incomingField.admin.components.Label + const serverProps = { serverProps: { field: incomingField } } + switch (incomingField.type) { case 'array': case 'group': @@ -133,7 +136,7 @@ export const createClientField = ({ if (incomingField?.admin?.components && 'RowLabel' in incomingField.admin.components) { ;(field as unknown as ArrayFieldClient).admin.components.RowLabel = createMappedComponent( incomingField.admin.components.RowLabel, - undefined, + serverProps, undefined, 'incomingField.admin.components.RowLabel', ) @@ -178,7 +181,7 @@ export const createClientField = ({ if (block.admin?.components?.Label) { clientBlock.admin.components.Label = createMappedComponent( block.admin.components.Label, - undefined, + serverProps, undefined, 'block.admin.components.Label', ) @@ -202,36 +205,40 @@ export const createClientField = ({ } case 'richText': { - const field = clientField as RichTextFieldClient + const field = clientField if (!incomingField?.editor) { throw new MissingEditorProp(incomingField) // while we allow disabling editor functionality, you should not have any richText fields defined if you do not have an editor } + if (typeof incomingField?.editor === 'function') { throw new Error('Attempted to access unsanitized rich text editor.') } + if (!field.admin) { field.admin = {} } + if (!field.admin.components) { field.admin.components = {} } field.admin.components.Field = createMappedComponent( incomingField.editor.FieldComponent, - undefined, + serverProps, undefined, 'incomingField.editor.FieldComponent', ) + field.admin.components.Cell = createMappedComponent( incomingField.editor.CellComponent, - undefined, + serverProps, undefined, 'incomingField.editor.CellComponent', ) if (incomingField.editor.generateComponentMap) { - const { Component: generateComponentMap, serverProps } = getComponent({ + const { Component: generateComponentMap, serverProps: richTextServerProps } = getComponent({ identifier: 'richText-generateComponentMap', importMap, payloadComponent: incomingField.editor.generateComponentMap, @@ -241,10 +248,10 @@ export const createClientField = ({ if (generateComponentMap) { const actualGenerateComponentMap: RichTextGenerateComponentMap = ( generateComponentMap as any - )(serverProps) + )(richTextServerProps) const result = actualGenerateComponentMap({ - clientField: field, + clientField: field as RichTextFieldClient, createMappedComponent, field: incomingField, i18n, @@ -253,7 +260,7 @@ export const createClientField = ({ schemaPath: field._schemaPath, }) - field.richTextComponentMap = result + ;(field as RichTextFieldClient).richTextComponentMap = result } } break @@ -349,7 +356,7 @@ export const createClientField = ({ if (incomingField?.admin?.components?.Cell !== undefined) { clientField.admin.components.Cell = createMappedComponent( incomingField.admin.components.Cell, - undefined, + serverProps, undefined, 'incomingField.admin.components.Cell', ) @@ -367,7 +374,7 @@ export const createClientField = ({ ;(clientField as FieldWithDescriptionComponent).admin.components.Description = createMappedComponent( incomingField.admin.components.Description, - undefined, + serverProps, undefined, 'incomingField.admin.components.Description', ) @@ -387,7 +394,7 @@ export const createClientField = ({ ) { ;(clientField as FieldWithErrorComponent).admin.components.Error = createMappedComponent( incomingField.admin.components.Error, - undefined, + serverProps, undefined, 'incomingField.admin.components.Error', ) @@ -396,7 +403,7 @@ export const createClientField = ({ if (incomingField?.admin?.components?.Field !== undefined) { clientField.admin.components.Field = createMappedComponent( incomingField.admin.components.Field, - undefined, + serverProps, undefined, 'incomingField.admin.components.Field', ) @@ -409,7 +416,7 @@ export const createClientField = ({ ) { clientField.admin.components.Filter = createMappedComponent( incomingField.admin.components.Filter, - undefined, + serverProps, undefined, 'incomingField.admin.components.Filter', ) @@ -429,7 +436,7 @@ export const createClientField = ({ ) { ;(clientField as FieldWithLabelComponent).admin.components.Label = createMappedComponent( CustomLabel, - undefined, + serverProps, undefined, 'incomingField.admin.components.Label', ) @@ -450,7 +457,7 @@ export const createClientField = ({ ;(clientField as FieldWithBeforeInputComponent).admin.components.beforeInput = createMappedComponent( incomingField.admin?.components?.beforeInput, - undefined, + serverProps, undefined, 'incomingField.admin.components.beforeInput', ) @@ -471,7 +478,7 @@ export const createClientField = ({ ;(clientField as FieldWithAfterInputComponent).admin.components.afterInput = createMappedComponent( incomingField.admin?.components?.afterInput, - undefined, + serverProps, undefined, 'incomingField.admin.components.afterInput', ) @@ -512,10 +519,12 @@ export const createClientFields = ({ parentPath, payload, }) + if (newField) { newClientFields.push({ ...newField }) } } + const hasID = newClientFields.findIndex((f) => fieldAffectsData(f) && f.name === 'id') > -1 if (!disableAddingID && !hasID) { diff --git a/packages/ui/src/providers/Config/createClientConfig/getCreateMappedComponent.tsx b/packages/ui/src/providers/Config/createClientConfig/getCreateMappedComponent.tsx index decff2fb2..0de9df994 100644 --- a/packages/ui/src/providers/Config/createClientConfig/getCreateMappedComponent.tsx +++ b/packages/ui/src/providers/Config/createClientConfig/getCreateMappedComponent.tsx @@ -27,10 +27,15 @@ export function getCreateMappedComponent({ const createSingleMappedComponent = ( payloadComponent: { ReactComponent: React.FC } | PayloadComponent, key: number | string, - props: JsonObject, + props: { + clientProps: JsonObject + serverProps: object + }, Fallback: React.FC, identifier: string, ): MappedComponent => { + const { clientProps, serverProps: componentServerProps } = props || {} + if (payloadComponent === undefined || payloadComponent === null) { if (!Fallback) { return undefined @@ -40,7 +45,9 @@ export function getCreateMappedComponent({ return { type: 'server', Component: null, - RenderedComponent: , + RenderedComponent: ( + + ), } } else { const toReturn: MappedComponent = { @@ -49,7 +56,7 @@ export function getCreateMappedComponent({ } // conditionally set props here to avoid bloating the HTML with `$undefined` props - if (props) toReturn.props = props + if (clientProps) toReturn.props = clientProps return toReturn } @@ -88,7 +95,13 @@ export function getCreateMappedComponent({ type: 'server', Component: null, RenderedComponent: ( - + ), } } else { @@ -101,7 +114,7 @@ export function getCreateMappedComponent({ Component: resolvedComponent.Component, props: { ...(resolvedComponent.clientProps || {}), - ...props, + ...clientProps, }, } } diff --git a/packages/ui/src/providers/Config/createClientConfig/globals.tsx b/packages/ui/src/providers/Config/createClientConfig/globals.tsx index 6ad7b3e8e..ad20355cd 100644 --- a/packages/ui/src/providers/Config/createClientConfig/globals.tsx +++ b/packages/ui/src/providers/Config/createClientConfig/globals.tsx @@ -142,7 +142,9 @@ export const createClientGlobalConfig = ({ ? global.admin.components.views.edit.default.Component : null, { - globalSlug: global.slug, + clientProps: { + globalSlug: global.slug, + }, }, DefaultEditView, 'global.admin.components.views.edit.default', @@ -160,7 +162,9 @@ export const createClientGlobalConfig = ({ clientGlobal.admin.components.views.edit[key].Component = createMappedComponent( view.Component, { - globalSlug: global.slug, + clientProps: { + globalSlug: global.slug, + }, }, undefined, 'global.admin.components.views.edit.key.Component', diff --git a/test/admin/collections/CustomFields/FieldDescription/index.tsx b/test/admin/collections/CustomFields/FieldDescription/index.tsx index 3377f1ee9..5e326b484 100644 --- a/test/admin/collections/CustomFields/FieldDescription/index.tsx +++ b/test/admin/collections/CustomFields/FieldDescription/index.tsx @@ -1,12 +1,10 @@ 'use client' -import type { DescriptionComponent, PayloadClientReactComponent } from 'payload' +import type { FieldDescriptionClientComponent } from 'payload' import { useFieldProps, useFormFields } from '@payloadcms/ui' import React from 'react' -export const FieldDescriptionComponent: PayloadClientReactComponent< - DescriptionComponent<'text'> -> = () => { +export const FieldDescriptionComponent: FieldDescriptionClientComponent = () => { const { path } = useFieldProps() const field = useFormFields(([fields]) => (fields && fields?.[path]) || null) const { value } = field || {} diff --git a/test/admin/collections/CustomFields/fields/Text/Description.tsx b/test/admin/collections/CustomFields/fields/Text/Description.tsx deleted file mode 100644 index 1f7c87418..000000000 --- a/test/admin/collections/CustomFields/fields/Text/Description.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import type { TextFieldDescriptionComponent } from 'payload' - -import React from 'react' - -export const CustomDescription: TextFieldDescriptionComponent = (props) => { - return ( -
    {`Description: the max length of this field is: ${props?.maxLength}`}
    - ) -} diff --git a/test/admin/collections/CustomFields/fields/Text/DescriptionClient.tsx b/test/admin/collections/CustomFields/fields/Text/DescriptionClient.tsx new file mode 100644 index 000000000..d88459651 --- /dev/null +++ b/test/admin/collections/CustomFields/fields/Text/DescriptionClient.tsx @@ -0,0 +1,10 @@ +'use client' +import type { TextFieldDescriptionClientComponent } from 'payload' + +import React from 'react' + +export const CustomClientDescription: TextFieldDescriptionClientComponent = (props) => { + return ( +
    {`Description: the max length of this field is: ${props?.field?.maxLength}`}
    + ) +} diff --git a/test/admin/collections/CustomFields/fields/Text/DescriptionServer.tsx b/test/admin/collections/CustomFields/fields/Text/DescriptionServer.tsx new file mode 100644 index 000000000..9c88afc72 --- /dev/null +++ b/test/admin/collections/CustomFields/fields/Text/DescriptionServer.tsx @@ -0,0 +1,9 @@ +import type { TextFieldDescriptionServerComponent } from 'payload' + +import React from 'react' + +export const CustomServerDescription: TextFieldDescriptionServerComponent = (props) => { + return ( +
    {`Description: the max length of this field is: ${props?.field?.maxLength}`}
    + ) +} diff --git a/test/admin/collections/CustomFields/fields/Text/Label.tsx b/test/admin/collections/CustomFields/fields/Text/Label.tsx deleted file mode 100644 index a670a7126..000000000 --- a/test/admin/collections/CustomFields/fields/Text/Label.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import type { TextFieldLabelComponent } from 'payload' - -import React from 'react' - -export const CustomLabel: TextFieldLabelComponent = (props) => { - return ( -
    {`Label: the max length of this field is: ${props?.maxLength}`}
    - ) -} diff --git a/test/admin/collections/CustomFields/fields/Text/LabelClient.tsx b/test/admin/collections/CustomFields/fields/Text/LabelClient.tsx new file mode 100644 index 000000000..0e1754117 --- /dev/null +++ b/test/admin/collections/CustomFields/fields/Text/LabelClient.tsx @@ -0,0 +1,10 @@ +'use client' +import type { TextFieldLabelClientComponent } from 'payload' + +import React from 'react' + +export const CustomClientLabel: TextFieldLabelClientComponent = (props) => { + return ( +
    {`Label: the max length of this field is: ${props?.field?.maxLength}`}
    + ) +} diff --git a/test/admin/collections/CustomFields/fields/Text/LabelServer.tsx b/test/admin/collections/CustomFields/fields/Text/LabelServer.tsx new file mode 100644 index 000000000..8a358a371 --- /dev/null +++ b/test/admin/collections/CustomFields/fields/Text/LabelServer.tsx @@ -0,0 +1,9 @@ +import type { TextFieldLabelServerComponent } from 'payload' + +import React from 'react' + +export const CustomServerLabel: TextFieldLabelServerComponent = (props) => { + return ( +
    {`Label: the max length of this field is: ${props?.field?.maxLength}`}
    + ) +} diff --git a/test/admin/collections/CustomFields/index.ts b/test/admin/collections/CustomFields/index.ts index 67f5a5fe6..da42f8f64 100644 --- a/test/admin/collections/CustomFields/index.ts +++ b/test/admin/collections/CustomFields/index.ts @@ -6,7 +6,7 @@ export const CustomFields: CollectionConfig = { slug: customFieldsSlug, fields: [ { - name: 'customTextField', + name: 'customTextServerField', type: 'text', maxLength: 100, admin: { @@ -14,8 +14,26 @@ export const CustomFields: CollectionConfig = { components: { afterInput: ['/collections/CustomFields/AfterInput.js#AfterInput'], beforeInput: ['/collections/CustomFields/BeforeInput.js#BeforeInput'], - Label: '/collections/CustomFields/fields/Text/Label.js#CustomLabel', - Description: '/collections/CustomFields/fields/Text/Description.js#CustomDescription', + Label: '/collections/CustomFields/fields/Text/LabelServer.js#CustomServerLabel', + Description: + '/collections/CustomFields/fields/Text/DescriptionServer.js#CustomServerDescription', + Error: '/collections/CustomFields/CustomError.js#CustomError', + }, + }, + minLength: 3, + }, + { + name: 'customTextClientField', + type: 'text', + maxLength: 100, + admin: { + placeholder: 'This is a placeholder', + components: { + afterInput: ['/collections/CustomFields/AfterInput.js#AfterInput'], + beforeInput: ['/collections/CustomFields/BeforeInput.js#BeforeInput'], + Label: '/collections/CustomFields/fields/Text/LabelClient.js#CustomClientLabel', + Description: + '/collections/CustomFields/fields/Text/DescriptionClient.js#CustomClientDescription', Error: '/collections/CustomFields/CustomError.js#CustomError', }, }, diff --git a/test/admin/e2e/1/e2e.spec.ts b/test/admin/e2e/1/e2e.spec.ts index 36dddb5fb..553379a16 100644 --- a/test/admin/e2e/1/e2e.spec.ts +++ b/test/admin/e2e/1/e2e.spec.ts @@ -555,25 +555,47 @@ describe('admin1', () => { test('renders custom label component', async () => { await page.goto(customFieldsURL.create) await page.waitForURL(customFieldsURL.create) - await expect(page.locator('#custom-field-label')).toBeVisible() + await expect(page.locator('#custom-client-field-label')).toBeVisible() + await expect(page.locator('#custom-server-field-label')).toBeVisible() }) test('renders custom description component', async () => { await page.goto(customFieldsURL.create) await page.waitForURL(customFieldsURL.create) - await expect(page.locator('#custom-field-description')).toBeVisible() + await expect(page.locator('#custom-client-field-description')).toBeVisible() + await expect(page.locator('#custom-server-field-description')).toBeVisible() }) - // test('ensure custom components receive field props', async () => { - // await page.goto(customFieldsURL.create) - // await page.waitForURL(customFieldsURL.create) - // await expect(page.locator('#custom-field-label')).toContainText( - // 'The max length of this field is: 100', - // ) - // await expect(page.locator('#custom-field-description')).toContainText( - // 'The max length of this field is: 100', - // ) - // }) + test('custom server components should receive field props', async () => { + await page.goto(customFieldsURL.create) + await page.waitForURL(customFieldsURL.create) + await expect( + page.locator('#custom-server-field-label', { + hasText: exactText('Label: the max length of this field is: 100'), + }), + ).toBeVisible() + + await expect( + page.locator('#custom-server-field-description', { + hasText: exactText('Description: the max length of this field is: 100'), + }), + ).toBeVisible() + }) + + test('custom client components should receive field props', async () => { + await page.goto(customFieldsURL.create) + await page.waitForURL(customFieldsURL.create) + await expect( + page.locator('#custom-client-field-label', { + hasText: exactText('Label: the max length of this field is: 100'), + }), + ).toBeVisible() + await expect( + page.locator('#custom-client-field-description', { + hasText: exactText('Description: the max length of this field is: 100'), + }), + ).toBeVisible() + }) describe('field descriptions', () => { test('should render static field description', async () => { @@ -606,10 +628,10 @@ describe('admin1', () => { test('should render custom error component', async () => { await page.goto(customFieldsURL.create) await page.waitForURL(customFieldsURL.create) - const input = page.locator('input[id="field-customTextField"]') + const input = page.locator('input[id="field-customTextClientField"]') await input.fill('ab') await expect(input).toHaveValue('ab') - const error = page.locator('.custom-error:near(input[id="field-customTextField"])') + const error = page.locator('.custom-error:near(input[id="field-customTextClientField"])') const submit = page.locator('button[type="button"][id="action-save"]') await submit.click() await expect(error).toHaveText('#custom-error') @@ -617,17 +639,19 @@ describe('admin1', () => { test('should render beforeInput and afterInput', async () => { await page.goto(customFieldsURL.create) - const input = page.locator('input[id="field-customTextField"]') + const input = page.locator('input[id="field-customTextClientField"]') const prevSibling = await input.evaluateHandle((el) => { return el.previousElementSibling }) + const prevSiblingText = await page.evaluate((el) => el?.textContent, prevSibling) expect(prevSiblingText).toEqual('#before-input') const nextSibling = await input.evaluateHandle((el) => { return el.nextElementSibling }) + const nextSiblingText = await page.evaluate((el) => el?.textContent, nextSibling) expect(nextSiblingText).toEqual('#after-input') }) diff --git a/test/admin/payload-types.ts b/test/admin/payload-types.ts index e5734c3b0..b155ab5a6 100644 --- a/test/admin/payload-types.ts +++ b/test/admin/payload-types.ts @@ -172,7 +172,8 @@ export interface CustomViewsTwo { */ export interface CustomField { id: string; - customTextField?: string | null; + customTextServerField?: string | null; + customTextClientField?: string | null; descriptionAsString?: string | null; descriptionAsFunction?: string | null; descriptionAsComponent?: string | null;