From bcbca0e44a2dd7f6bfea9598cb3b37578a89d584 Mon Sep 17 00:00:00 2001 From: Jarrod Flesch <30633324+JarrodMFlesch@users.noreply.github.com> Date: Wed, 13 Nov 2024 13:53:47 -0500 Subject: [PATCH] chore: improves field types (#9172) ### What? Ensures `path` is required and only present on the fields that expect it (all fields except row). Deprecates `useFieldComponents` and `FieldComponentsProvider` and instead extends the RenderField component to account for all field types. This also improves type safety within `RenderField`. ### Why? `path` being optional just adds DX overhead and annoyance. ### How? Added `FieldPaths` type which is added to iterable field types. Placed `path` back onto the ClientFieldBase type. --- .../src/views/API/LocaleSelector/index.tsx | 1 + packages/next/src/views/API/index.client.tsx | 3 + .../src/views/Account/ToggleTheme/index.tsx | 1 + .../views/CreateFirstUser/index.client.tsx | 1 + .../ForgotPasswordForm/index.tsx | 2 + .../next/src/views/Login/LoginField/index.tsx | 3 + .../next/src/views/Login/LoginForm/index.tsx | 1 + .../ResetPassword/ResetPasswordForm/index.tsx | 6 - packages/payload/src/admin/fields/Array.ts | 5 +- packages/payload/src/admin/fields/Blocks.ts | 7 +- packages/payload/src/admin/fields/Checkbox.ts | 2 +- packages/payload/src/admin/fields/Code.ts | 2 +- .../payload/src/admin/fields/Collapsible.ts | 5 +- packages/payload/src/admin/fields/Date.ts | 2 +- packages/payload/src/admin/fields/Email.ts | 2 +- packages/payload/src/admin/fields/Group.ts | 5 +- packages/payload/src/admin/fields/Hidden.ts | 1 + packages/payload/src/admin/fields/JSON.ts | 2 +- packages/payload/src/admin/fields/Join.ts | 14 +- packages/payload/src/admin/fields/Number.ts | 2 +- packages/payload/src/admin/fields/Point.ts | 2 +- packages/payload/src/admin/fields/Radio.ts | 2 +- .../payload/src/admin/fields/Relationship.ts | 2 +- packages/payload/src/admin/fields/RichText.ts | 2 +- packages/payload/src/admin/fields/Row.ts | 6 +- packages/payload/src/admin/fields/Select.ts | 2 +- packages/payload/src/admin/fields/Tabs.ts | 3 +- packages/payload/src/admin/fields/Text.ts | 2 +- packages/payload/src/admin/fields/Textarea.ts | 2 +- packages/payload/src/admin/fields/UI.ts | 21 ++- packages/payload/src/admin/fields/Upload.ts | 2 +- packages/payload/src/admin/forms/Field.ts | 37 +++-- packages/payload/src/admin/types.ts | 8 +- .../richtext-lexical/src/field/rscEntry.tsx | 11 +- .../config/client/EditorConfigProvider.tsx | 5 +- .../richtext-slate/src/field/rscEntry.tsx | 25 ++-- .../src/elements/EmailAndUsername/index.tsx | 10 +- packages/ui/src/exports/client/index.ts | 4 - packages/ui/src/fields/Array/index.tsx | 3 +- packages/ui/src/fields/Blocks/index.tsx | 3 +- packages/ui/src/fields/Checkbox/index.tsx | 3 +- packages/ui/src/fields/Code/index.tsx | 3 +- packages/ui/src/fields/Collapsible/index.tsx | 8 +- packages/ui/src/fields/DateTime/index.tsx | 3 +- packages/ui/src/fields/Email/index.tsx | 3 +- packages/ui/src/fields/Group/index.tsx | 3 +- packages/ui/src/fields/JSON/index.tsx | 3 +- packages/ui/src/fields/Join/index.tsx | 4 +- packages/ui/src/fields/Number/index.tsx | 3 +- packages/ui/src/fields/Password/index.tsx | 3 +- packages/ui/src/fields/Password/types.ts | 2 +- packages/ui/src/fields/Point/index.tsx | 3 +- packages/ui/src/fields/RadioGroup/index.tsx | 4 +- packages/ui/src/fields/Relationship/index.tsx | 3 +- packages/ui/src/fields/Select/index.tsx | 3 +- packages/ui/src/fields/Text/index.tsx | 5 +- packages/ui/src/fields/Textarea/index.tsx | 3 +- packages/ui/src/fields/Upload/index.tsx | 3 +- packages/ui/src/fields/index.tsx | 6 +- packages/ui/src/forms/NullifyField/index.tsx | 3 - .../ui/src/forms/RenderFields/RenderField.tsx | 131 ++++++++++++------ .../fieldSchemasToFormState/renderField.tsx | 13 +- packages/ui/src/forms/withCondition/index.tsx | 7 +- .../src/providers/FieldComponents/index.tsx | 22 --- packages/ui/src/providers/Root/index.tsx | 96 ++++++------- packages/ui/src/views/Edit/Auth/index.tsx | 6 - .../collections/Posts/MyClientField.tsx | 20 +-- .../views/CustomView/index.client.tsx | 1 + 68 files changed, 305 insertions(+), 281 deletions(-) delete mode 100644 packages/ui/src/providers/FieldComponents/index.tsx diff --git a/packages/next/src/views/API/LocaleSelector/index.tsx b/packages/next/src/views/API/LocaleSelector/index.tsx index 99e8c442c..dd9056bc1 100644 --- a/packages/next/src/views/API/LocaleSelector/index.tsx +++ b/packages/next/src/views/API/LocaleSelector/index.tsx @@ -19,6 +19,7 @@ export const LocaleSelector: React.FC<{ options: localeOptions, }} onChange={(value: string) => onChange(value)} + path="locale" /> ) } diff --git a/packages/next/src/views/API/index.client.tsx b/packages/next/src/views/API/index.client.tsx index 8babd6fa5..c7657d236 100644 --- a/packages/next/src/views/API/index.client.tsx +++ b/packages/next/src/views/API/index.client.tsx @@ -159,6 +159,7 @@ export const APIViewClient: React.FC = () => { label: t('version:draft'), }} onChange={() => setDraft(!draft)} + path="draft" /> )} { label: t('authentication:authenticated'), }} onChange={() => setAuthenticated(!authenticated)} + path="authenticated" /> {localeOptions && } @@ -181,6 +183,7 @@ export const APIViewClient: React.FC = () => { min: 0, }} onChange={(value) => setDepth(value?.toString())} + path="depth" /> diff --git a/packages/next/src/views/Account/ToggleTheme/index.tsx b/packages/next/src/views/Account/ToggleTheme/index.tsx index cdadbdd0d..3fd6a13a8 100644 --- a/packages/next/src/views/Account/ToggleTheme/index.tsx +++ b/packages/next/src/views/Account/ToggleTheme/index.tsx @@ -36,6 +36,7 @@ export const ToggleTheme: React.FC = () => { ], }} onChange={onChange} + path="theme" value={autoMode ? 'auto' : theme} /> ) diff --git a/packages/next/src/views/CreateFirstUser/index.client.tsx b/packages/next/src/views/CreateFirstUser/index.client.tsx index 2070d72e2..156d134a8 100644 --- a/packages/next/src/views/CreateFirstUser/index.client.tsx +++ b/packages/next/src/views/CreateFirstUser/index.client.tsx @@ -105,6 +105,7 @@ export const CreateFirstUserClient: React.FC<{ label: t('authentication:newPassword'), required: true, }} + path="password" /> { label: t('authentication:username'), required: true, }} + path="username" validate={(value) => text(value, { name: 'username', @@ -113,6 +114,7 @@ export const ForgotPasswordForm: React.FC = () => { label: t('general:email'), required: true, }} + path="email" validate={(value) => email(value, { name: 'email', diff --git a/packages/next/src/views/Login/LoginField/index.tsx b/packages/next/src/views/Login/LoginField/index.tsx index 9af450a15..2102cea1e 100644 --- a/packages/next/src/views/Login/LoginField/index.tsx +++ b/packages/next/src/views/Login/LoginField/index.tsx @@ -25,6 +25,7 @@ export const LoginField: React.FC = ({ type, required = true }) label: t('general:email'), required, }} + path="email" validate={email} /> ) @@ -38,6 +39,7 @@ export const LoginField: React.FC = ({ type, required = true }) label: t('authentication:username'), required, }} + path="username" validate={username} /> ) @@ -51,6 +53,7 @@ export const LoginField: React.FC = ({ type, required = true }) label: t('authentication:emailOrUsername'), required, }} + path="username" validate={(value, options) => { const passesUsername = username(value, options) const passesEmail = email( diff --git a/packages/next/src/views/Login/LoginForm/index.tsx b/packages/next/src/views/Login/LoginForm/index.tsx index 85d24947a..a1193e0dd 100644 --- a/packages/next/src/views/Login/LoginForm/index.tsx +++ b/packages/next/src/views/Login/LoginForm/index.tsx @@ -98,6 +98,7 @@ export const LoginForm: React.FC<{ label: t('general:password'), required: true, }} + path="password" /> = ({ token }) => { label: i18n.t('authentication:newPassword'), required: true, }} - indexPath="" - parentPath="" - parentSchemaPath="" path="password" schemaPath={`${userSlug}.password`} /> @@ -90,9 +87,6 @@ export const ResetPasswordForm: React.FC = ({ token }) => { hidden: true, }, }} - indexPath="" - parentPath={userSlug} - parentSchemaPath={userSlug} path="token" schemaPath={`${userSlug}.token`} value={token} diff --git a/packages/payload/src/admin/fields/Array.ts b/packages/payload/src/admin/fields/Array.ts index 3d7b8df04..d67c0c315 100644 --- a/packages/payload/src/admin/fields/Array.ts +++ b/packages/payload/src/admin/fields/Array.ts @@ -6,6 +6,7 @@ import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../fo import type { ClientFieldBase, FieldClientComponent, + FieldPaths, FieldServerComponent, ServerFieldBase, } from '../forms/Field.js' @@ -19,9 +20,9 @@ import type { type ArrayFieldClientWithoutType = MarkOptional type ArrayFieldBaseClientProps = { - readonly path?: string readonly validate?: ArrayFieldValidation -} & Pick +} & FieldPaths & + Pick export type ArrayFieldClientProps = ArrayFieldBaseClientProps & ClientFieldBase diff --git a/packages/payload/src/admin/fields/Blocks.ts b/packages/payload/src/admin/fields/Blocks.ts index 0183a89a5..921005a03 100644 --- a/packages/payload/src/admin/fields/Blocks.ts +++ b/packages/payload/src/admin/fields/Blocks.ts @@ -1,11 +1,12 @@ import type { MarkOptional } from 'ts-essentials' -import type { BlocksField, BlocksFieldClient, ClientField } from '../../fields/config/types.js' +import type { BlocksField, BlocksFieldClient } from '../../fields/config/types.js' import type { BlocksFieldValidation } from '../../fields/validations.js' import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js' import type { ClientFieldBase, FieldClientComponent, + FieldPaths, FieldServerComponent, ServerFieldBase, } from '../forms/Field.js' @@ -19,9 +20,9 @@ import type { type BlocksFieldClientWithoutType = MarkOptional type BlocksFieldBaseClientProps = { - readonly path?: string readonly validate?: BlocksFieldValidation -} & Pick +} & FieldPaths & + Pick export type BlocksFieldClientProps = BlocksFieldBaseClientProps & ClientFieldBase diff --git a/packages/payload/src/admin/fields/Checkbox.ts b/packages/payload/src/admin/fields/Checkbox.ts index b82f7a8c9..37196dfd8 100644 --- a/packages/payload/src/admin/fields/Checkbox.ts +++ b/packages/payload/src/admin/fields/Checkbox.ts @@ -24,7 +24,7 @@ type CheckboxFieldBaseClientProps = { readonly id?: string readonly onChange?: (value: boolean) => void readonly partialChecked?: boolean - readonly path?: string + readonly path: string readonly validate?: CheckboxFieldValidation } diff --git a/packages/payload/src/admin/fields/Code.ts b/packages/payload/src/admin/fields/Code.ts index dcc158465..c58d3fd71 100644 --- a/packages/payload/src/admin/fields/Code.ts +++ b/packages/payload/src/admin/fields/Code.ts @@ -20,7 +20,7 @@ type CodeFieldClientWithoutType = MarkOptional type CodeFieldBaseClientProps = { readonly autoComplete?: string - readonly path?: string + readonly path: string readonly validate?: CodeFieldValidation } diff --git a/packages/payload/src/admin/fields/Collapsible.ts b/packages/payload/src/admin/fields/Collapsible.ts index 1000d28c8..01b90fa4c 100644 --- a/packages/payload/src/admin/fields/Collapsible.ts +++ b/packages/payload/src/admin/fields/Collapsible.ts @@ -5,6 +5,7 @@ import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../fo import type { ClientFieldBase, FieldClientComponent, + FieldPaths, FieldServerComponent, ServerFieldBase, } from '../forms/Field.js' @@ -15,9 +16,7 @@ import type { FieldLabelServerComponent, } from '../types.js' -type CollapsibleFieldBaseClientProps = { - readonly path?: string -} & Pick +type CollapsibleFieldBaseClientProps = FieldPaths & Pick type CollapsibleFieldClientWithoutType = MarkOptional diff --git a/packages/payload/src/admin/fields/Date.ts b/packages/payload/src/admin/fields/Date.ts index 10c43ab2f..ddcb82f81 100644 --- a/packages/payload/src/admin/fields/Date.ts +++ b/packages/payload/src/admin/fields/Date.ts @@ -19,7 +19,7 @@ import type { type DateFieldClientWithoutType = MarkOptional type DateFieldBaseClientProps = { - readonly path?: string + readonly path: string readonly validate?: DateFieldValidation } diff --git a/packages/payload/src/admin/fields/Email.ts b/packages/payload/src/admin/fields/Email.ts index 498097994..309759cba 100644 --- a/packages/payload/src/admin/fields/Email.ts +++ b/packages/payload/src/admin/fields/Email.ts @@ -19,7 +19,7 @@ import type { type EmailFieldClientWithoutType = MarkOptional type EmailFieldBaseClientProps = { - readonly path?: string + readonly path: string readonly validate?: EmailFieldValidation } diff --git a/packages/payload/src/admin/fields/Group.ts b/packages/payload/src/admin/fields/Group.ts index 2087539b2..deda3081d 100644 --- a/packages/payload/src/admin/fields/Group.ts +++ b/packages/payload/src/admin/fields/Group.ts @@ -5,6 +5,7 @@ import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../fo import type { ClientFieldBase, FieldClientComponent, + FieldPaths, FieldServerComponent, ServerFieldBase, } from '../forms/Field.js' @@ -17,9 +18,7 @@ import type { type GroupFieldClientWithoutType = MarkOptional -export type GroupFieldBaseClientProps = { - readonly path?: string -} & Pick +export type GroupFieldBaseClientProps = FieldPaths & Pick export type GroupFieldClientProps = ClientFieldBase & GroupFieldBaseClientProps diff --git a/packages/payload/src/admin/fields/Hidden.ts b/packages/payload/src/admin/fields/Hidden.ts index ebc4d5dff..630d42a09 100644 --- a/packages/payload/src/admin/fields/Hidden.ts +++ b/packages/payload/src/admin/fields/Hidden.ts @@ -6,6 +6,7 @@ type HiddenFieldBaseClientProps = { readonly field?: { readonly name?: string } & ClientField + readonly path: string readonly value?: unknown } diff --git a/packages/payload/src/admin/fields/JSON.ts b/packages/payload/src/admin/fields/JSON.ts index 226f990e5..7ab7a9ae0 100644 --- a/packages/payload/src/admin/fields/JSON.ts +++ b/packages/payload/src/admin/fields/JSON.ts @@ -19,7 +19,7 @@ import type { type JSONFieldClientWithoutType = MarkOptional type JSONFieldBaseClientProps = { - readonly path?: string + readonly path: string readonly validate?: JSONFieldValidation } diff --git a/packages/payload/src/admin/fields/Join.ts b/packages/payload/src/admin/fields/Join.ts index 7854eba00..980da78d8 100644 --- a/packages/payload/src/admin/fields/Join.ts +++ b/packages/payload/src/admin/fields/Join.ts @@ -17,15 +17,21 @@ import type { type JoinFieldClientWithoutType = MarkOptional -export type JoinFieldClientProps = { - path?: string -} & ClientFieldBase +type JoinFieldBaseClientProps = { + readonly path: string +} + +export type JoinFieldClientProps = ClientFieldBase & + JoinFieldBaseClientProps export type JoinFieldServerProps = ServerFieldBase export type JoinFieldServerComponent = FieldServerComponent -export type JoinFieldClientComponent = FieldClientComponent +export type JoinFieldClientComponent = FieldClientComponent< + JoinFieldClientWithoutType, + JoinFieldBaseClientProps +> export type JoinFieldLabelServerComponent = FieldLabelServerComponent diff --git a/packages/payload/src/admin/fields/Number.ts b/packages/payload/src/admin/fields/Number.ts index a420e3a7a..36ff5f987 100644 --- a/packages/payload/src/admin/fields/Number.ts +++ b/packages/payload/src/admin/fields/Number.ts @@ -20,7 +20,7 @@ type NumberFieldClientWithoutType = MarkOptional type NumberFieldBaseClientProps = { readonly onChange?: (e: number) => void - readonly path?: string + readonly path: string readonly validate?: NumberFieldValidation } diff --git a/packages/payload/src/admin/fields/Point.ts b/packages/payload/src/admin/fields/Point.ts index a57011d61..b1f425935 100644 --- a/packages/payload/src/admin/fields/Point.ts +++ b/packages/payload/src/admin/fields/Point.ts @@ -19,7 +19,7 @@ import type { type PointFieldClientWithoutType = MarkOptional type PointFieldBaseClientProps = { - readonly path?: string + readonly path: string readonly validate?: PointFieldValidation } diff --git a/packages/payload/src/admin/fields/Radio.ts b/packages/payload/src/admin/fields/Radio.ts index 25266660b..518c2af67 100644 --- a/packages/payload/src/admin/fields/Radio.ts +++ b/packages/payload/src/admin/fields/Radio.ts @@ -24,7 +24,7 @@ type RadioFieldBaseClientProps = { */ readonly disableModifyingForm?: boolean readonly onChange?: OnChange - readonly path?: string + readonly path: string readonly validate?: RadioFieldValidation readonly value?: string } diff --git a/packages/payload/src/admin/fields/Relationship.ts b/packages/payload/src/admin/fields/Relationship.ts index 42a905133..79fdc6181 100644 --- a/packages/payload/src/admin/fields/Relationship.ts +++ b/packages/payload/src/admin/fields/Relationship.ts @@ -19,7 +19,7 @@ import type { type RelationshipFieldClientWithoutType = MarkOptional type RelationshipFieldBaseClientProps = { - readonly path?: string + readonly path: string readonly validate?: RelationshipFieldValidation } diff --git a/packages/payload/src/admin/fields/RichText.ts b/packages/payload/src/admin/fields/RichText.ts index e548ac0cd..5b2256668 100644 --- a/packages/payload/src/admin/fields/RichText.ts +++ b/packages/payload/src/admin/fields/RichText.ts @@ -27,7 +27,7 @@ type RichTextFieldBaseClientProps< TAdapterProps = any, TExtraProperties = object, > = { - readonly path?: string + readonly path: string readonly validate?: RichTextFieldValidation } diff --git a/packages/payload/src/admin/fields/Row.ts b/packages/payload/src/admin/fields/Row.ts index da9228a84..9a179b3e7 100644 --- a/packages/payload/src/admin/fields/Row.ts +++ b/packages/payload/src/admin/fields/Row.ts @@ -4,6 +4,7 @@ import type { RowField, RowFieldClient } from '../../fields/config/types.js' import type { ClientFieldBase, FieldClientComponent, + FieldPaths, FieldServerComponent, ServerFieldBase, } from '../forms/Field.js' @@ -20,9 +21,10 @@ type RowFieldClientWithoutType = MarkOptional type RowFieldBaseClientProps = { readonly forceRender?: boolean -} & Pick +} & Omit & + Pick -export type RowFieldClientProps = ClientFieldBase & +export type RowFieldClientProps = Omit, 'path'> & RowFieldBaseClientProps export type RowFieldServerProps = ServerFieldBase diff --git a/packages/payload/src/admin/fields/Select.ts b/packages/payload/src/admin/fields/Select.ts index d5466ffc0..51952115b 100644 --- a/packages/payload/src/admin/fields/Select.ts +++ b/packages/payload/src/admin/fields/Select.ts @@ -20,7 +20,7 @@ type SelectFieldClientWithoutType = MarkOptional type SelectFieldBaseClientProps = { readonly onChange?: (e: string | string[]) => void - readonly path?: string + readonly path: string readonly validate?: SelectFieldValidation readonly value?: string } diff --git a/packages/payload/src/admin/fields/Tabs.ts b/packages/payload/src/admin/fields/Tabs.ts index 7a8c38adb..2cbb4bbd9 100644 --- a/packages/payload/src/admin/fields/Tabs.ts +++ b/packages/payload/src/admin/fields/Tabs.ts @@ -11,6 +11,7 @@ import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../fo import type { ClientFieldBase, FieldClientComponent, + FieldPaths, FieldServerComponent, ServerFieldBase, } from '../forms/Field.js' @@ -25,7 +26,7 @@ export type ClientTab = | ({ fields: ClientField[]; readonly path?: string } & Omit) | ({ fields: ClientField[] } & Omit) -type TabsFieldBaseClientProps = {} & Pick +type TabsFieldBaseClientProps = FieldPaths & Pick type TabsFieldClientWithoutType = MarkOptional diff --git a/packages/payload/src/admin/fields/Text.ts b/packages/payload/src/admin/fields/Text.ts index 484c02afb..755e512a9 100644 --- a/packages/payload/src/admin/fields/Text.ts +++ b/packages/payload/src/admin/fields/Text.ts @@ -22,7 +22,7 @@ type TextFieldClientWithoutType = MarkOptional type TextFieldBaseClientProps = { readonly inputRef?: React.RefObject readonly onKeyDown?: React.KeyboardEventHandler - readonly path?: string + readonly path: string readonly validate?: TextFieldValidation } diff --git a/packages/payload/src/admin/fields/Textarea.ts b/packages/payload/src/admin/fields/Textarea.ts index 800458a43..390ec049e 100644 --- a/packages/payload/src/admin/fields/Textarea.ts +++ b/packages/payload/src/admin/fields/Textarea.ts @@ -22,7 +22,7 @@ type TextareaFieldClientWithoutType = MarkOptional type TextareaFieldBaseClientProps = { readonly inputRef?: React.Ref readonly onKeyDown?: React.KeyboardEventHandler - readonly path?: string + readonly path: string readonly validate?: TextareaFieldValidation } diff --git a/packages/payload/src/admin/fields/UI.ts b/packages/payload/src/admin/fields/UI.ts index c903a37be..4c8901d4d 100644 --- a/packages/payload/src/admin/fields/UI.ts +++ b/packages/payload/src/admin/fields/UI.ts @@ -1,9 +1,26 @@ import type { MarkOptional } from 'ts-essentials' import type { UIField, UIFieldClient } from '../../fields/config/types.js' -import type { FieldClientComponent, FieldServerComponent } from '../types.js' +import type { + ClientFieldBase, + FieldClientComponent, + FieldServerComponent, + ServerFieldBase, +} from '../types.js' type UIFieldClientWithoutType = MarkOptional -export type UIFieldClientComponent = FieldClientComponent + +type UIFieldBaseClientProps = { + readonly path: string +} + +export type UIFieldClientProps = ClientFieldBase & UIFieldBaseClientProps + +export type UIFieldServerProps = ServerFieldBase + +export type UIFieldClientComponent = FieldClientComponent< + UIFieldClientWithoutType, + UIFieldBaseClientProps +> export type UIFieldServerComponent = FieldServerComponent diff --git a/packages/payload/src/admin/fields/Upload.ts b/packages/payload/src/admin/fields/Upload.ts index e40d25708..72f86d81b 100644 --- a/packages/payload/src/admin/fields/Upload.ts +++ b/packages/payload/src/admin/fields/Upload.ts @@ -19,7 +19,7 @@ import type { type UploadFieldClientWithoutType = MarkOptional type UploadFieldBaseClientProps = { - readonly path?: string + readonly path: string readonly validate?: UploadFieldValidation } diff --git a/packages/payload/src/admin/forms/Field.ts b/packages/payload/src/admin/forms/Field.ts index cde779d0d..795ed991c 100644 --- a/packages/payload/src/admin/forms/Field.ts +++ b/packages/payload/src/admin/forms/Field.ts @@ -19,6 +19,19 @@ export type ClientComponentProps = { customComponents: FormField['customComponents'] field: ClientBlock | ClientField | ClientTab forceRender?: boolean + readOnly?: boolean + renderedBlocks?: RenderedField[] + /** + * Used to extract field configs from a schemaMap. + * Does not include indexes. + * + * @default field.name + **/ + schemaPath?: string +} + +// TODO: maybe we can come up with a better name? +export type FieldPaths = { /** * @default '' */ @@ -28,19 +41,27 @@ export type ClientComponentProps = { */ parentPath?: string /** - * @default ''' + * The path built up to the point of the field + * excluding the field name. + * + * @default '' */ parentSchemaPath?: string /** + * A built up path to access FieldState in the form state. + * Nested fields will have a path that includes the parent field names + * if they are nested within a group, array, block or named tab. + * + * Collapsibles and unnamed tabs will have arbitrary paths + * that look like _index-0, _index-1, etc. + * + * Row fields will not have a path. + * + * @example 'parentGroupField.childTextField' + * * @default field.name */ - path?: string - readOnly?: boolean - renderedBlocks?: RenderedField[] - /** - * @default field.name - **/ - schemaPath?: string + path: string } export type ServerComponentProps = { diff --git a/packages/payload/src/admin/types.ts b/packages/payload/src/admin/types.ts index 81182a7a0..46627a352 100644 --- a/packages/payload/src/admin/types.ts +++ b/packages/payload/src/admin/types.ts @@ -301,7 +301,12 @@ export type { TextareaFieldServerProps, } from './fields/Textarea.js' -export type { UIFieldClientComponent, UIFieldServerComponent } from './fields/UI.js' +export type { + UIFieldClientComponent, + UIFieldClientProps, + UIFieldServerComponent, + UIFieldServerProps, +} from './fields/UI.js' export type { UploadFieldClientComponent, @@ -351,6 +356,7 @@ export type { ClientFieldBase, ClientFieldWithOptionalType, FieldClientComponent, + FieldPaths, FieldServerComponent, ServerComponentProps, ServerFieldBase, diff --git a/packages/richtext-lexical/src/field/rscEntry.tsx b/packages/richtext-lexical/src/field/rscEntry.tsx index bda24d64d..2560a7524 100644 --- a/packages/richtext-lexical/src/field/rscEntry.tsx +++ b/packages/richtext-lexical/src/field/rscEntry.tsx @@ -1,4 +1,9 @@ -import type { ClientComponentProps, RichTextFieldClient, ServerComponentProps } from 'payload' +import type { + ClientComponentProps, + FieldPaths, + RichTextFieldClient, + ServerComponentProps, +} from 'payload' import React from 'react' @@ -13,6 +18,7 @@ export const RscEntryLexicalField: React.FC< admin: LexicalFieldAdminProps sanitizedEditorConfig: SanitizedServerEditorConfig } & ClientComponentProps & + Pick & ServerComponentProps > = (args) => { const path = args.path ?? (args.clientField as RichTextFieldClient).name @@ -32,10 +38,7 @@ export const RscEntryLexicalField: React.FC< featureClientSchemaMap={featureClientSchemaMap} field={args.clientField as RichTextFieldClient} forceRender={args.forceRender} - indexPath={args.indexPath} lexicalEditorConfig={args.sanitizedEditorConfig.lexical} - parentPath={args.parentPath} - parentSchemaPath={args.parentSchemaPath} path={path} permissions={args.permissions} readOnly={args.readOnly} diff --git a/packages/richtext-lexical/src/lexical/config/client/EditorConfigProvider.tsx b/packages/richtext-lexical/src/lexical/config/client/EditorConfigProvider.tsx index ec52db743..b7ea109de 100644 --- a/packages/richtext-lexical/src/lexical/config/client/EditorConfigProvider.tsx +++ b/packages/richtext-lexical/src/lexical/config/client/EditorConfigProvider.tsx @@ -23,10 +23,7 @@ export interface EditorConfigContextType { editorConfig: SanitizedClientEditorConfig editorContainerRef: React.RefObject - fieldProps: MarkRequired< - LexicalRichTextFieldProps, - 'indexPath' | 'parentPath' | 'parentSchemaPath' | 'path' | 'schemaPath' - > + fieldProps: MarkRequired focusedEditor: EditorConfigContextType | null // Editor focus handling focusEditor: (editorContext: EditorConfigContextType) => void diff --git a/packages/richtext-slate/src/field/rscEntry.tsx b/packages/richtext-slate/src/field/rscEntry.tsx index c68c14cab..850d97311 100644 --- a/packages/richtext-slate/src/field/rscEntry.tsx +++ b/packages/richtext-slate/src/field/rscEntry.tsx @@ -1,13 +1,13 @@ +import type { + ClientComponentProps, + ClientField, + Field, + FieldPaths, + RichTextFieldClient, + ServerComponentProps } from 'payload' + import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' -import { - type ClientComponentProps, - type ClientField, - createClientFields, - deepCopyObjectSimple, - type Field, - type RichTextFieldClient, - type ServerComponentProps, -} from 'payload' +import { createClientFields, deepCopyObjectSimple } from 'payload' import React from 'react' import type { AdapterArguments, RichTextCustomElement, RichTextCustomLeaf } from '../types.js' @@ -22,15 +22,13 @@ export const RscEntrySlateField: React.FC< { args: AdapterArguments } & ClientComponentProps & + Pick & ServerComponentProps > = ({ args, clientField, forceRender, i18n, - indexPath, - parentPath, - parentSchemaPath, path, payload, readOnly, @@ -191,9 +189,6 @@ export const RscEntrySlateField: React.FC< componentMap={Object.fromEntries(componentMap)} field={clientField as RichTextFieldClient} forceRender={forceRender} - indexPath={indexPath} - parentPath={parentPath} - parentSchemaPath={parentSchemaPath} path={path} readOnly={readOnly} renderedBlocks={renderedBlocks} diff --git a/packages/ui/src/elements/EmailAndUsername/index.tsx b/packages/ui/src/elements/EmailAndUsername/index.tsx index afc136dc0..57e8148d7 100644 --- a/packages/ui/src/elements/EmailAndUsername/index.tsx +++ b/packages/ui/src/elements/EmailAndUsername/index.tsx @@ -29,7 +29,7 @@ export function EmailAndUsernameFields(props: RenderEmailAndUsernameFieldsProps) const showUsernameField = Boolean(loginWithUsername) return ( - +
{showEmailField ? ( )} - +
) } diff --git a/packages/ui/src/exports/client/index.ts b/packages/ui/src/exports/client/index.ts index 680a7d698..5a62675b3 100644 --- a/packages/ui/src/exports/client/index.ts +++ b/packages/ui/src/exports/client/index.ts @@ -233,10 +233,6 @@ export { EntityVisibilityProvider, useEntityVisibility, } from '../../providers/EntityVisibility/index.js' -export { - FieldComponentsProvider, - useFieldComponents, -} from '../../providers/FieldComponents/index.js' export { UploadEditsProvider, useUploadEdits } from '../../providers/UploadEdits/index.js' export { ListDrawerContextProvider, diff --git a/packages/ui/src/fields/Array/index.tsx b/packages/ui/src/fields/Array/index.tsx index 31440fee5..ff8b9901e 100644 --- a/packages/ui/src/fields/Array/index.tsx +++ b/packages/ui/src/fields/Array/index.tsx @@ -46,13 +46,12 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => { required, }, forceRender = false, - path: pathFromProps, + path, permissions, readOnly, schemaPath: schemaPathFromProps, validate, } = props - const path = pathFromProps ?? name const schemaPath = schemaPathFromProps ?? name const minRows = (minRowsProp ?? required) ? 1 : 0 diff --git a/packages/ui/src/fields/Blocks/index.tsx b/packages/ui/src/fields/Blocks/index.tsx index 392ab9ef8..7073cdd83 100644 --- a/packages/ui/src/fields/Blocks/index.tsx +++ b/packages/ui/src/fields/Blocks/index.tsx @@ -47,13 +47,12 @@ const BlocksFieldComponent: BlocksFieldClientComponent = (props) => { minRows: minRowsProp, required, }, - path: pathFromProps, + path, permissions, readOnly, schemaPath: schemaPathFromProps, validate, } = props - const path = pathFromProps ?? name const schemaPath = schemaPathFromProps ?? name const minRows = (minRowsProp ?? required) ? 1 : 0 diff --git a/packages/ui/src/fields/Checkbox/index.tsx b/packages/ui/src/fields/Checkbox/index.tsx index 496af6bee..ca6421775 100644 --- a/packages/ui/src/fields/Checkbox/index.tsx +++ b/packages/ui/src/fields/Checkbox/index.tsx @@ -43,11 +43,10 @@ const CheckboxFieldComponent: CheckboxFieldClientComponent = (props) => { } = {} as CheckboxFieldClientProps['field'], onChange: onChangeFromProps, partialChecked, - path: pathFromProps, + path, readOnly, validate, } = props - const path = pathFromProps ?? name const { uuid } = useForm() diff --git a/packages/ui/src/fields/Code/index.tsx b/packages/ui/src/fields/Code/index.tsx index 66f8d5bd3..d3729ade0 100644 --- a/packages/ui/src/fields/Code/index.tsx +++ b/packages/ui/src/fields/Code/index.tsx @@ -36,11 +36,10 @@ const CodeFieldComponent: CodeFieldClientComponent = (props) => { localized, required, }, - path: pathFromProps, + path, readOnly, validate, } = props - const path = pathFromProps ?? name const memoizedValidate = useCallback( (value, options) => { diff --git a/packages/ui/src/fields/Collapsible/index.tsx b/packages/ui/src/fields/Collapsible/index.tsx index ad73871b1..1e5ded28b 100644 --- a/packages/ui/src/fields/Collapsible/index.tsx +++ b/packages/ui/src/fields/Collapsible/index.tsx @@ -25,10 +25,10 @@ const CollapsibleFieldComponent: CollapsibleFieldClientComponent = (props) => { const { field, field: { admin: { className, description, initCollapsed = false } = {}, fields, label } = {}, - indexPath = '', - parentPath = '', - parentSchemaPath = '', - path = '', + indexPath, + parentPath, + parentSchemaPath, + path, permissions, readOnly, } = props diff --git a/packages/ui/src/fields/DateTime/index.tsx b/packages/ui/src/fields/DateTime/index.tsx index 1d5152588..bc6b7da42 100644 --- a/packages/ui/src/fields/DateTime/index.tsx +++ b/packages/ui/src/fields/DateTime/index.tsx @@ -26,11 +26,10 @@ const DateTimeFieldComponent: DateFieldClientComponent = (props) => { localized, required, }, - path: pathFromProps, + path, readOnly, validate, } = props - const path = pathFromProps ?? name const { i18n } = useTranslation() diff --git a/packages/ui/src/fields/Email/index.tsx b/packages/ui/src/fields/Email/index.tsx index fa00c043e..d3c6bcc49 100644 --- a/packages/ui/src/fields/Email/index.tsx +++ b/packages/ui/src/fields/Email/index.tsx @@ -34,11 +34,10 @@ const EmailFieldComponent: EmailFieldClientComponent = (props) => { localized, required, } = {} as EmailFieldClientProps['field'], - path: pathFromProps, + path, readOnly, validate, } = props - const path = pathFromProps ?? name const { i18n } = useTranslation() diff --git a/packages/ui/src/fields/Group/index.tsx b/packages/ui/src/fields/Group/index.tsx index 4411a5695..8a84ae6ca 100644 --- a/packages/ui/src/fields/Group/index.tsx +++ b/packages/ui/src/fields/Group/index.tsx @@ -31,12 +31,11 @@ export const GroupFieldComponent: GroupFieldClientComponent = (props) => { fields, label, }, - path: pathFromProps, + path, permissions, readOnly, schemaPath: schemaPathFromProps, } = props - const path = pathFromProps ?? name const schemaPath = schemaPathFromProps ?? name const { i18n } = useTranslation() diff --git a/packages/ui/src/fields/JSON/index.tsx b/packages/ui/src/fields/JSON/index.tsx index 9e97dff30..235d48e40 100644 --- a/packages/ui/src/fields/JSON/index.tsx +++ b/packages/ui/src/fields/JSON/index.tsx @@ -25,11 +25,10 @@ const JSONFieldComponent: JSONFieldClientComponent = (props) => { localized, required, }, - path: pathFromProps, + path, readOnly, validate, } = props - const path = pathFromProps ?? name const [stringValue, setStringValue] = useState() const [jsonError, setJsonError] = useState() diff --git a/packages/ui/src/fields/Join/index.tsx b/packages/ui/src/fields/Join/index.tsx index f371ae217..d508998e5 100644 --- a/packages/ui/src/fields/Join/index.tsx +++ b/packages/ui/src/fields/Join/index.tsx @@ -23,11 +23,9 @@ const JoinFieldComponent: JoinFieldClientComponent = (props) => { on, required, }, - path: pathFromProps, + path, } = props - const path = pathFromProps ?? name - const { id: docID } = useDocumentInfo() const { customComponents: { AfterInput, BeforeInput, Label } = {}, value } = diff --git a/packages/ui/src/fields/Number/index.tsx b/packages/ui/src/fields/Number/index.tsx index 981ef44c2..18a8d5cbd 100644 --- a/packages/ui/src/fields/Number/index.tsx +++ b/packages/ui/src/fields/Number/index.tsx @@ -39,11 +39,10 @@ const NumberFieldComponent: NumberFieldClientComponent = (props) => { required, }, onChange: onChangeFromProps, - path: pathFromProps, + path, readOnly, validate, } = props - const path = pathFromProps ?? name const { i18n, t } = useTranslation() diff --git a/packages/ui/src/fields/Password/index.tsx b/packages/ui/src/fields/Password/index.tsx index 8438ea66f..da99d734c 100644 --- a/packages/ui/src/fields/Password/index.tsx +++ b/packages/ui/src/fields/Password/index.tsx @@ -33,10 +33,9 @@ const PasswordFieldComponent: React.FC = (props) => { required, } = {} as PasswordFieldProps['field'], inputRef, - path: pathFromProps, + path, validate, } = props - const path = pathFromProps ?? name const { t } = useTranslation() const locale = useLocale() diff --git a/packages/ui/src/fields/Password/types.ts b/packages/ui/src/fields/Password/types.ts index b555d141e..03fd3d43f 100644 --- a/packages/ui/src/fields/Password/types.ts +++ b/packages/ui/src/fields/Password/types.ts @@ -27,7 +27,7 @@ export type PasswordFieldProps = { /** * @default field.name */ - readonly path?: string + readonly path: string /** * @default field.name */ diff --git a/packages/ui/src/fields/Point/index.tsx b/packages/ui/src/fields/Point/index.tsx index e83989de8..3d75a3857 100644 --- a/packages/ui/src/fields/Point/index.tsx +++ b/packages/ui/src/fields/Point/index.tsx @@ -25,11 +25,10 @@ export const PointFieldComponent: PointFieldClientComponent = (props) => { localized, required, }, - path: pathFromProps, + path, readOnly, validate, } = props - const path = pathFromProps ?? name const { i18n, t } = useTranslation() diff --git a/packages/ui/src/fields/RadioGroup/index.tsx b/packages/ui/src/fields/RadioGroup/index.tsx index 8033e6639..c4a2db185 100644 --- a/packages/ui/src/fields/RadioGroup/index.tsx +++ b/packages/ui/src/fields/RadioGroup/index.tsx @@ -21,7 +21,6 @@ const RadioGroupFieldComponent: RadioFieldClientComponent = (props) => { const { disableModifyingForm: disableModifyingFormFromProps, field: { - name, admin: { className, description, @@ -35,12 +34,11 @@ const RadioGroupFieldComponent: RadioFieldClientComponent = (props) => { required, } = {} as RadioFieldClientProps['field'], onChange: onChangeFromProps, - path: pathFromProps, + path, readOnly, validate, value: valueFromProps, } = props - const path = pathFromProps ?? name const { uuid } = useForm() diff --git a/packages/ui/src/fields/Relationship/index.tsx b/packages/ui/src/fields/Relationship/index.tsx index 961afb02d..ebd539b04 100644 --- a/packages/ui/src/fields/Relationship/index.tsx +++ b/packages/ui/src/fields/Relationship/index.tsx @@ -56,11 +56,10 @@ const RelationshipFieldComponent: RelationshipFieldClientComponent = (props) => relationTo, required, }, - path: pathFromProps, + path, readOnly, validate, } = props - const path = pathFromProps ?? name const { config } = useConfig() diff --git a/packages/ui/src/fields/Select/index.tsx b/packages/ui/src/fields/Select/index.tsx index 55259053e..98e7584e2 100644 --- a/packages/ui/src/fields/Select/index.tsx +++ b/packages/ui/src/fields/Select/index.tsx @@ -46,11 +46,10 @@ const SelectFieldComponent: SelectFieldClientComponent = (props) => { required, }, onChange: onChangeFromProps, - path: pathFromProps, + path, readOnly, validate, } = props - const path = pathFromProps ?? name const options = React.useMemo(() => formatOptions(optionsFromProps), [optionsFromProps]) diff --git a/packages/ui/src/fields/Text/index.tsx b/packages/ui/src/fields/Text/index.tsx index 05aa80b1e..0bc349858 100644 --- a/packages/ui/src/fields/Text/index.tsx +++ b/packages/ui/src/fields/Text/index.tsx @@ -11,8 +11,8 @@ import { withCondition } from '../../forms/withCondition/index.js' import { useConfig } from '../../providers/Config/index.js' import { useLocale } from '../../providers/Locale/index.js' import { isFieldRTL } from '../shared/index.js' -import './index.scss' import { TextInput } from './Input.js' +import './index.scss' export { TextInput, TextInputProps } @@ -31,11 +31,10 @@ const TextFieldComponent: TextFieldClientComponent = (props) => { required, }, inputRef, - path: pathFromProps, + path, readOnly, validate, } = props - const path = pathFromProps ?? name const locale = useLocale() diff --git a/packages/ui/src/fields/Textarea/index.tsx b/packages/ui/src/fields/Textarea/index.tsx index 696c1a1dd..566ef44d0 100644 --- a/packages/ui/src/fields/Textarea/index.tsx +++ b/packages/ui/src/fields/Textarea/index.tsx @@ -28,11 +28,10 @@ const TextareaFieldComponent: TextareaFieldClientComponent = (props) => { minLength, required, }, - path: pathFromProps, + path, readOnly, validate, } = props - const path = pathFromProps ?? name const { i18n } = useTranslation() diff --git a/packages/ui/src/fields/Upload/index.tsx b/packages/ui/src/fields/Upload/index.tsx index 069021a47..0bbae5c8d 100644 --- a/packages/ui/src/fields/Upload/index.tsx +++ b/packages/ui/src/fields/Upload/index.tsx @@ -27,11 +27,10 @@ export function UploadComponent(props: UploadFieldClientProps) { relationTo, required, }, - path: pathFromProps, + path, readOnly, validate, } = props - const path = pathFromProps ?? name const { config } = useConfig() diff --git a/packages/ui/src/fields/index.tsx b/packages/ui/src/fields/index.tsx index 8aa3be1f8..838022574 100644 --- a/packages/ui/src/fields/index.tsx +++ b/packages/ui/src/fields/index.tsx @@ -8,6 +8,8 @@ import type { } from 'payload' import type React from 'react' +import type { ConfirmPasswordFieldProps } from './ConfirmPassword/index.js' + import { RowLabel } from '../forms/RowLabel/index.js' import { ArrayField } from './Array/index.js' import { BlocksField } from './Blocks/index.js' @@ -41,7 +43,9 @@ import { UploadField } from './Upload/index.js' export * from './shared/index.js' export type FieldTypesComponents = { - [K in 'confirmPassword' | 'hidden' | 'password' | FieldTypes]: React.FC + [K in 'hidden' | 'password' | FieldTypes]: React.FC +} & { + confirmPassword: React.FC } export const fieldComponents: FieldTypesComponents = { diff --git a/packages/ui/src/forms/NullifyField/index.tsx b/packages/ui/src/forms/NullifyField/index.tsx index 754f648e4..7fa03aa66 100644 --- a/packages/ui/src/forms/NullifyField/index.tsx +++ b/packages/ui/src/forms/NullifyField/index.tsx @@ -59,9 +59,6 @@ export const NullifyLocaleField: React.FC = ({ label: t('general:fallbackToDefaultLocale'), }} id={`field-${path.replace(/\./g, '__')}`} - indexPath="" - parentPath="" - parentSchemaPath="" path={path} schemaPath="" // onToggle={onChange} diff --git a/packages/ui/src/forms/RenderFields/RenderField.tsx b/packages/ui/src/forms/RenderFields/RenderField.tsx index 2b397d85f..5b1790533 100644 --- a/packages/ui/src/forms/RenderFields/RenderField.tsx +++ b/packages/ui/src/forms/RenderFields/RenderField.tsx @@ -1,32 +1,39 @@ 'use client' -import type { ClientComponentProps, ClientField, FieldPermissions } from 'payload' +import type { ClientComponentProps, ClientField, FieldPaths, FieldPermissions } from 'payload' import React from 'react' import { ArrayField } from '../../fields/Array/index.js' import { BlocksField } from '../../fields/Blocks/index.js' +import { CheckboxField } from '../../fields/Checkbox/index.js' +import { CodeField } from '../../fields/Code/index.js' import { CollapsibleField } from '../../fields/Collapsible/index.js' +import { DateTimeField } from '../../fields/DateTime/index.js' +import { EmailField } from '../../fields/Email/index.js' import { GroupField } from '../../fields/Group/index.js' import { HiddenField } from '../../fields/Hidden/index.js' +import { JoinField } from '../../fields/Join/index.js' +import { JSONField } from '../../fields/JSON/index.js' +import { NumberField } from '../../fields/Number/index.js' +import { PointField } from '../../fields/Point/index.js' +import { RadioGroupField } from '../../fields/RadioGroup/index.js' +import { RelationshipField } from '../../fields/Relationship/index.js' +import { RichTextField } from '../../fields/RichText/index.js' import { RowField } from '../../fields/Row/index.js' +import { SelectField } from '../../fields/Select/index.js' import { TabsField } from '../../fields/Tabs/index.js' +import { TextField } from '../../fields/Text/index.js' +import { TextareaField } from '../../fields/Textarea/index.js' +import { UIField } from '../../fields/UI/index.js' +import { UploadField } from '../../fields/Upload/index.js' import { useFormFields } from '../../forms/Form/index.js' -import { useFieldComponents } from '../../providers/FieldComponents/index.js' type RenderFieldProps = { clientFieldConfig: ClientField permissions: FieldPermissions -} & Pick< - ClientComponentProps, - | 'forceRender' - | 'indexPath' - | 'parentPath' - | 'parentSchemaPath' - | 'path' - | 'readOnly' - | 'schemaPath' -> +} & FieldPaths & + Pick export function RenderField({ clientFieldConfig, @@ -39,59 +46,95 @@ export function RenderField({ readOnly, schemaPath, }: RenderFieldProps) { - const fieldComponents = useFieldComponents() - const Field = useFormFields(([fields]) => fields && fields?.[path]?.customComponents?.Field) if (Field !== undefined) { return Field || null } - const sharedProps: Pick< - ClientComponentProps, - | 'forceRender' - | 'indexPath' - | 'parentPath' - | 'parentSchemaPath' - | 'path' - | 'readOnly' - | 'schemaPath' - > = { + const baseFieldProps: Pick = { forceRender, - indexPath, - parentPath, - parentSchemaPath, - path, readOnly, schemaPath, } - if (clientFieldConfig.admin?.hidden) { - return + const iterableFieldProps = { + ...baseFieldProps, + indexPath, + parentPath, + parentSchemaPath, + permissions, } - const DefaultField = fieldComponents?.[clientFieldConfig?.type] + if (clientFieldConfig.admin?.hidden) { + return + } switch (clientFieldConfig.type) { - // named fields with subfields case 'array': - return + return + case 'blocks': - return + return + + case 'checkbox': + return + + case 'code': + return + case 'collapsible': - return ( - - ) + return + + case 'date': + return + + case 'email': + return + case 'group': - return + return + + case 'join': + return + + case 'json': + return + + case 'number': + return + + case 'point': + return + + case 'radio': + return + + case 'relationship': + return + + case 'richText': + return - // unnamed fields with subfields case 'row': - return - case 'tabs': - return + return - default: - return DefaultField ? : null + case 'select': + return + + case 'tabs': + return + + case 'text': + return + + case 'textarea': + return + + case 'ui': + return + + case 'upload': + return } } diff --git a/packages/ui/src/forms/fieldSchemasToFormState/renderField.tsx b/packages/ui/src/forms/fieldSchemasToFormState/renderField.tsx index 22aaafeb0..cb6c04d7f 100644 --- a/packages/ui/src/forms/fieldSchemasToFormState/renderField.tsx +++ b/packages/ui/src/forms/fieldSchemasToFormState/renderField.tsx @@ -1,6 +1,7 @@ import type { ClientComponentProps, ClientField, + FieldPaths, FieldPermissions, PayloadComponent, ServerComponentProps, @@ -45,17 +46,21 @@ export const renderField: RenderFieldMethod = ({ ? incomingPermissions?.[fieldConfig.name] : ({} as FieldPermissions) - const clientProps: ClientComponentProps = { + const clientProps: ClientComponentProps & Partial = { customComponents: fieldState?.customComponents || {}, field: clientField, - indexPath, - parentPath, - parentSchemaPath, path, readOnly: permissions?.[operation]?.permission === false, schemaPath, } + // fields with subfields + if (['array', 'blocks', 'collapsible', 'group', 'row', 'tabs'].includes(fieldConfig.type)) { + clientProps.indexPath = indexPath + clientProps.parentPath = parentPath + clientProps.parentSchemaPath = parentSchemaPath + } + const serverProps: ServerComponentProps = { clientField, data, diff --git a/packages/ui/src/forms/withCondition/index.tsx b/packages/ui/src/forms/withCondition/index.tsx index ead9b49f8..3b548c299 100644 --- a/packages/ui/src/forms/withCondition/index.tsx +++ b/packages/ui/src/forms/withCondition/index.tsx @@ -1,5 +1,5 @@ 'use client' -import type { ClientFieldProps } from 'payload' +import type { ClientFieldProps, FieldPaths } from 'payload' import type { MarkOptional } from 'ts-essentials' import React from 'react' @@ -7,10 +7,7 @@ import React from 'react' import { WatchCondition } from './WatchCondition.js' export const withCondition = < - P extends MarkOptional< - Pick, - 'indexPath' | 'path' - >, + P extends MarkOptional, 'indexPath' | 'path'>, >( Field: React.ComponentType

, ): React.FC

=> { diff --git a/packages/ui/src/providers/FieldComponents/index.tsx b/packages/ui/src/providers/FieldComponents/index.tsx deleted file mode 100644 index ef26bac01..000000000 --- a/packages/ui/src/providers/FieldComponents/index.tsx +++ /dev/null @@ -1,22 +0,0 @@ -'use client' - -import React, { createContext, useContext } from 'react' - -import type { FieldTypesComponents } from '../../fields/index.js' - -export type IFieldComponentsContext = FieldTypesComponents - -const FieldComponentsContext = createContext(null) - -export const FieldComponentsProvider: React.FC<{ - readonly children: React.ReactNode - readonly fieldComponents: FieldTypesComponents -}> = ({ children, fieldComponents }) => { - return ( - - {children} - - ) -} - -export const useFieldComponents = (): IFieldComponentsContext => useContext(FieldComponentsContext) diff --git a/packages/ui/src/providers/Root/index.tsx b/packages/ui/src/providers/Root/index.tsx index 779a06842..0a6e56d54 100644 --- a/packages/ui/src/providers/Root/index.tsx +++ b/packages/ui/src/providers/Root/index.tsx @@ -18,13 +18,11 @@ import { LoadingOverlayProvider } from '../../elements/LoadingOverlay/index.js' import { NavProvider } from '../../elements/Nav/context.js' import { StayLoggedInModal } from '../../elements/StayLoggedIn/index.js' import { StepNavProvider } from '../../elements/StepNav/index.js' -import { fieldComponents } from '../../fields/index.js' import { WindowInfoProvider } from '../../providers/WindowInfo/index.js' import { AuthProvider } from '../Auth/index.js' import { ClientFunctionProvider } from '../ClientFunction/index.js' import { ConfigProvider } from '../Config/index.js' import { DocumentEventsProvider } from '../DocumentEvents/index.js' -import { FieldComponentsProvider } from '../FieldComponents/index.js' import { LocaleProvider } from '../Locale/index.js' import { ParamsProvider } from '../Params/index.js' import { PreferencesProvider } from '../Preferences/index.js' @@ -74,55 +72,53 @@ export const RootProvider: React.FC = ({ - - - + + - - - - - - - - - - - - - - {children} - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + {children} + + + + + + + + + + + + + + + + + diff --git a/packages/ui/src/views/Edit/Auth/index.tsx b/packages/ui/src/views/Edit/Auth/index.tsx index f82fc2c70..befa160d3 100644 --- a/packages/ui/src/views/Edit/Auth/index.tsx +++ b/packages/ui/src/views/Edit/Auth/index.tsx @@ -215,9 +215,6 @@ export const Auth: React.FC = (props) => { admin: { disabled, readOnly: enableAPIKeyReadOnly }, label: t('authentication:enableAPIKey'), }} - indexPath="" - parentPath="" - parentSchemaPath="" path="enableAPIKey" schemaPath={`${collectionSlug}.enableAPIKey`} /> @@ -232,9 +229,6 @@ export const Auth: React.FC = (props) => { admin: { disabled, readOnly }, label: t('authentication:verified'), }} - indexPath="" - parentPath="" - parentSchemaPath="" path="_verified" schemaPath={`${collectionSlug}._verified`} /> diff --git a/test/_community/collections/Posts/MyClientField.tsx b/test/_community/collections/Posts/MyClientField.tsx index 30f208ed4..b6c13f534 100644 --- a/test/_community/collections/Posts/MyClientField.tsx +++ b/test/_community/collections/Posts/MyClientField.tsx @@ -4,22 +4,6 @@ import type { TextFieldClientComponent } from 'payload' import { TextField } from '@payloadcms/ui' import React from 'react' -export const MyClientFieldComponent: TextFieldClientComponent = ({ - field, - indexPath, - parentPath, - parentSchemaPath, - path, - schemaPath, -}) => { - return ( - - ) +export const MyClientFieldComponent: TextFieldClientComponent = (props) => { + return } diff --git a/test/admin/components/views/CustomView/index.client.tsx b/test/admin/components/views/CustomView/index.client.tsx index ec58facc6..e80ac05b7 100644 --- a/test/admin/components/views/CustomView/index.client.tsx +++ b/test/admin/components/views/CustomView/index.client.tsx @@ -47,6 +47,7 @@ const CustomPassword: React.FC = () => { label: 'Password', required: true, }} + path="password" validate={(value) => { if (value && confirmValue) { return confirmValue === value ? true : 'Passwords must match!!!!'