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.
This commit is contained in:
@@ -19,6 +19,7 @@ export const LocaleSelector: React.FC<{
|
||||
options: localeOptions,
|
||||
}}
|
||||
onChange={(value: string) => onChange(value)}
|
||||
path="locale"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -159,6 +159,7 @@ export const APIViewClient: React.FC = () => {
|
||||
label: t('version:draft'),
|
||||
}}
|
||||
onChange={() => setDraft(!draft)}
|
||||
path="draft"
|
||||
/>
|
||||
)}
|
||||
<CheckboxField
|
||||
@@ -167,6 +168,7 @@ export const APIViewClient: React.FC = () => {
|
||||
label: t('authentication:authenticated'),
|
||||
}}
|
||||
onChange={() => setAuthenticated(!authenticated)}
|
||||
path="authenticated"
|
||||
/>
|
||||
</div>
|
||||
{localeOptions && <LocaleSelector localeOptions={localeOptions} onChange={setLocale} />}
|
||||
@@ -181,6 +183,7 @@ export const APIViewClient: React.FC = () => {
|
||||
min: 0,
|
||||
}}
|
||||
onChange={(value) => setDepth(value?.toString())}
|
||||
path="depth"
|
||||
/>
|
||||
</div>
|
||||
</Form>
|
||||
|
||||
@@ -36,6 +36,7 @@ export const ToggleTheme: React.FC = () => {
|
||||
],
|
||||
}}
|
||||
onChange={onChange}
|
||||
path="theme"
|
||||
value={autoMode ? 'auto' : theme}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -105,6 +105,7 @@ export const CreateFirstUserClient: React.FC<{
|
||||
label: t('authentication:newPassword'),
|
||||
required: true,
|
||||
}}
|
||||
path="password"
|
||||
/>
|
||||
<ConfirmPasswordField />
|
||||
<RenderFields
|
||||
|
||||
@@ -86,6 +86,7 @@ export const ForgotPasswordForm: React.FC = () => {
|
||||
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',
|
||||
|
||||
@@ -25,6 +25,7 @@ export const LoginField: React.FC<LoginFieldProps> = ({ type, required = true })
|
||||
label: t('general:email'),
|
||||
required,
|
||||
}}
|
||||
path="email"
|
||||
validate={email}
|
||||
/>
|
||||
)
|
||||
@@ -38,6 +39,7 @@ export const LoginField: React.FC<LoginFieldProps> = ({ type, required = true })
|
||||
label: t('authentication:username'),
|
||||
required,
|
||||
}}
|
||||
path="username"
|
||||
validate={username}
|
||||
/>
|
||||
)
|
||||
@@ -51,6 +53,7 @@ export const LoginField: React.FC<LoginFieldProps> = ({ type, required = true })
|
||||
label: t('authentication:emailOrUsername'),
|
||||
required,
|
||||
}}
|
||||
path="username"
|
||||
validate={(value, options) => {
|
||||
const passesUsername = username(value, options)
|
||||
const passesEmail = email(
|
||||
|
||||
@@ -98,6 +98,7 @@ export const LoginForm: React.FC<{
|
||||
label: t('general:password'),
|
||||
required: true,
|
||||
}}
|
||||
path="password"
|
||||
/>
|
||||
</div>
|
||||
<Link
|
||||
|
||||
@@ -75,9 +75,6 @@ export const ResetPasswordForm: React.FC<Args> = ({ 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<Args> = ({ token }) => {
|
||||
hidden: true,
|
||||
},
|
||||
}}
|
||||
indexPath=""
|
||||
parentPath={userSlug}
|
||||
parentSchemaPath={userSlug}
|
||||
path="token"
|
||||
schemaPath={`${userSlug}.token`}
|
||||
value={token}
|
||||
|
||||
@@ -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<ArrayFieldClient, 'type'>
|
||||
|
||||
type ArrayFieldBaseClientProps = {
|
||||
readonly path?: string
|
||||
readonly validate?: ArrayFieldValidation
|
||||
} & Pick<ServerFieldBase, 'permissions'>
|
||||
} & FieldPaths &
|
||||
Pick<ServerFieldBase, 'permissions'>
|
||||
|
||||
export type ArrayFieldClientProps = ArrayFieldBaseClientProps &
|
||||
ClientFieldBase<ArrayFieldClientWithoutType>
|
||||
|
||||
@@ -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<BlocksFieldClient, 'type'>
|
||||
|
||||
type BlocksFieldBaseClientProps = {
|
||||
readonly path?: string
|
||||
readonly validate?: BlocksFieldValidation
|
||||
} & Pick<ServerFieldBase, 'permissions'>
|
||||
} & FieldPaths &
|
||||
Pick<ServerFieldBase, 'permissions'>
|
||||
|
||||
export type BlocksFieldClientProps = BlocksFieldBaseClientProps &
|
||||
ClientFieldBase<BlocksFieldClientWithoutType>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ type CodeFieldClientWithoutType = MarkOptional<CodeFieldClient, 'type'>
|
||||
|
||||
type CodeFieldBaseClientProps = {
|
||||
readonly autoComplete?: string
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
readonly validate?: CodeFieldValidation
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ServerFieldBase, 'permissions'>
|
||||
type CollapsibleFieldBaseClientProps = FieldPaths & Pick<ServerFieldBase, 'permissions'>
|
||||
|
||||
type CollapsibleFieldClientWithoutType = MarkOptional<CollapsibleFieldClient, 'type'>
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import type {
|
||||
type DateFieldClientWithoutType = MarkOptional<DateFieldClient, 'type'>
|
||||
|
||||
type DateFieldBaseClientProps = {
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
readonly validate?: DateFieldValidation
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import type {
|
||||
type EmailFieldClientWithoutType = MarkOptional<EmailFieldClient, 'type'>
|
||||
|
||||
type EmailFieldBaseClientProps = {
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
readonly validate?: EmailFieldValidation
|
||||
}
|
||||
|
||||
|
||||
@@ -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<GroupFieldClient, 'type'>
|
||||
|
||||
export type GroupFieldBaseClientProps = {
|
||||
readonly path?: string
|
||||
} & Pick<ServerFieldBase, 'permissions'>
|
||||
export type GroupFieldBaseClientProps = FieldPaths & Pick<ServerFieldBase, 'permissions'>
|
||||
|
||||
export type GroupFieldClientProps = ClientFieldBase<GroupFieldClientWithoutType> &
|
||||
GroupFieldBaseClientProps
|
||||
|
||||
@@ -6,6 +6,7 @@ type HiddenFieldBaseClientProps = {
|
||||
readonly field?: {
|
||||
readonly name?: string
|
||||
} & ClientField
|
||||
readonly path: string
|
||||
readonly value?: unknown
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import type {
|
||||
type JSONFieldClientWithoutType = MarkOptional<JSONFieldClient, 'type'>
|
||||
|
||||
type JSONFieldBaseClientProps = {
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
readonly validate?: JSONFieldValidation
|
||||
}
|
||||
|
||||
|
||||
@@ -17,15 +17,21 @@ import type {
|
||||
|
||||
type JoinFieldClientWithoutType = MarkOptional<JoinFieldClient, 'type'>
|
||||
|
||||
export type JoinFieldClientProps = {
|
||||
path?: string
|
||||
} & ClientFieldBase<JoinFieldClientWithoutType>
|
||||
type JoinFieldBaseClientProps = {
|
||||
readonly path: string
|
||||
}
|
||||
|
||||
export type JoinFieldClientProps = ClientFieldBase<JoinFieldClientWithoutType> &
|
||||
JoinFieldBaseClientProps
|
||||
|
||||
export type JoinFieldServerProps = ServerFieldBase<JoinField>
|
||||
|
||||
export type JoinFieldServerComponent = FieldServerComponent<JoinField>
|
||||
|
||||
export type JoinFieldClientComponent = FieldClientComponent<JoinFieldClientWithoutType>
|
||||
export type JoinFieldClientComponent = FieldClientComponent<
|
||||
JoinFieldClientWithoutType,
|
||||
JoinFieldBaseClientProps
|
||||
>
|
||||
|
||||
export type JoinFieldLabelServerComponent = FieldLabelServerComponent<JoinField>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ type NumberFieldClientWithoutType = MarkOptional<NumberFieldClient, 'type'>
|
||||
|
||||
type NumberFieldBaseClientProps = {
|
||||
readonly onChange?: (e: number) => void
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
readonly validate?: NumberFieldValidation
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import type {
|
||||
type PointFieldClientWithoutType = MarkOptional<PointFieldClient, 'type'>
|
||||
|
||||
type PointFieldBaseClientProps = {
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
readonly validate?: PointFieldValidation
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ type RadioFieldBaseClientProps = {
|
||||
*/
|
||||
readonly disableModifyingForm?: boolean
|
||||
readonly onChange?: OnChange
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
readonly validate?: RadioFieldValidation
|
||||
readonly value?: string
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import type {
|
||||
type RelationshipFieldClientWithoutType = MarkOptional<RelationshipFieldClient, 'type'>
|
||||
|
||||
type RelationshipFieldBaseClientProps = {
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
readonly validate?: RelationshipFieldValidation
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ type RichTextFieldBaseClientProps<
|
||||
TAdapterProps = any,
|
||||
TExtraProperties = object,
|
||||
> = {
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
readonly validate?: RichTextFieldValidation
|
||||
}
|
||||
|
||||
|
||||
@@ -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<RowFieldClient, 'type'>
|
||||
|
||||
type RowFieldBaseClientProps = {
|
||||
readonly forceRender?: boolean
|
||||
} & Pick<ServerFieldBase, 'permissions'>
|
||||
} & Omit<FieldPaths, 'path'> &
|
||||
Pick<ServerFieldBase, 'permissions'>
|
||||
|
||||
export type RowFieldClientProps = ClientFieldBase<RowFieldClientWithoutType> &
|
||||
export type RowFieldClientProps = Omit<ClientFieldBase<RowFieldClientWithoutType>, 'path'> &
|
||||
RowFieldBaseClientProps
|
||||
|
||||
export type RowFieldServerProps = ServerFieldBase<RowField, RowFieldClientWithoutType>
|
||||
|
||||
@@ -20,7 +20,7 @@ type SelectFieldClientWithoutType = MarkOptional<SelectFieldClient, 'type'>
|
||||
|
||||
type SelectFieldBaseClientProps = {
|
||||
readonly onChange?: (e: string | string[]) => void
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
readonly validate?: SelectFieldValidation
|
||||
readonly value?: string
|
||||
}
|
||||
|
||||
@@ -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<NamedTab, 'fields'>)
|
||||
| ({ fields: ClientField[] } & Omit<UnnamedTab, 'fields'>)
|
||||
|
||||
type TabsFieldBaseClientProps = {} & Pick<ServerFieldBase, 'permissions'>
|
||||
type TabsFieldBaseClientProps = FieldPaths & Pick<ServerFieldBase, 'permissions'>
|
||||
|
||||
type TabsFieldClientWithoutType = MarkOptional<TabsFieldClient, 'type'>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ type TextFieldClientWithoutType = MarkOptional<TextFieldClient, 'type'>
|
||||
type TextFieldBaseClientProps = {
|
||||
readonly inputRef?: React.RefObject<HTMLInputElement>
|
||||
readonly onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
readonly validate?: TextFieldValidation
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ type TextareaFieldClientWithoutType = MarkOptional<TextareaFieldClient, 'type'>
|
||||
type TextareaFieldBaseClientProps = {
|
||||
readonly inputRef?: React.Ref<HTMLInputElement>
|
||||
readonly onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
readonly validate?: TextareaFieldValidation
|
||||
}
|
||||
|
||||
|
||||
@@ -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<UIFieldClient, 'type'>
|
||||
export type UIFieldClientComponent = FieldClientComponent<UIFieldClientWithoutType>
|
||||
|
||||
type UIFieldBaseClientProps = {
|
||||
readonly path: string
|
||||
}
|
||||
|
||||
export type UIFieldClientProps = ClientFieldBase<UIFieldClientWithoutType> & UIFieldBaseClientProps
|
||||
|
||||
export type UIFieldServerProps = ServerFieldBase<UIField, UIFieldClientWithoutType>
|
||||
|
||||
export type UIFieldClientComponent = FieldClientComponent<
|
||||
UIFieldClientWithoutType,
|
||||
UIFieldBaseClientProps
|
||||
>
|
||||
|
||||
export type UIFieldServerComponent = FieldServerComponent<UIField, UIFieldClientWithoutType>
|
||||
|
||||
@@ -19,7 +19,7 @@ import type {
|
||||
type UploadFieldClientWithoutType = MarkOptional<UploadFieldClient, 'type'>
|
||||
|
||||
type UploadFieldBaseClientProps = {
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
readonly validate?: UploadFieldValidation
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<FieldPaths, 'path'> &
|
||||
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}
|
||||
|
||||
@@ -23,10 +23,7 @@ export interface EditorConfigContextType {
|
||||
editorConfig: SanitizedClientEditorConfig
|
||||
editorContainerRef: React.RefObject<HTMLDivElement>
|
||||
|
||||
fieldProps: MarkRequired<
|
||||
LexicalRichTextFieldProps,
|
||||
'indexPath' | 'parentPath' | 'parentSchemaPath' | 'path' | 'schemaPath'
|
||||
>
|
||||
fieldProps: MarkRequired<LexicalRichTextFieldProps, 'path' | 'schemaPath'>
|
||||
focusedEditor: EditorConfigContextType | null
|
||||
// Editor focus handling
|
||||
focusEditor: (editorContext: EditorConfigContextType) => void
|
||||
|
||||
@@ -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<FieldPaths, 'path'> &
|
||||
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}
|
||||
|
||||
@@ -29,7 +29,7 @@ export function EmailAndUsernameFields(props: RenderEmailAndUsernameFieldsProps)
|
||||
const showUsernameField = Boolean(loginWithUsername)
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={className}>
|
||||
{showEmailField ? (
|
||||
<EmailField
|
||||
field={{
|
||||
@@ -40,9 +40,6 @@ export function EmailAndUsernameFields(props: RenderEmailAndUsernameFieldsProps)
|
||||
label: t('general:email'),
|
||||
required: !loginWithUsername || (loginWithUsername && loginWithUsername.requireEmail),
|
||||
}}
|
||||
indexPath=""
|
||||
parentPath=""
|
||||
parentSchemaPath=""
|
||||
path="email"
|
||||
schemaPath="email"
|
||||
validate={email}
|
||||
@@ -55,14 +52,11 @@ export function EmailAndUsernameFields(props: RenderEmailAndUsernameFieldsProps)
|
||||
label: t('authentication:username'),
|
||||
required: loginWithUsername && loginWithUsername.requireUsername,
|
||||
}}
|
||||
indexPath=""
|
||||
parentPath=""
|
||||
parentSchemaPath=""
|
||||
path="username"
|
||||
schemaPath="username"
|
||||
validate={username}
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -26,11 +26,10 @@ const DateTimeFieldComponent: DateFieldClientComponent = (props) => {
|
||||
localized,
|
||||
required,
|
||||
},
|
||||
path: pathFromProps,
|
||||
path,
|
||||
readOnly,
|
||||
validate,
|
||||
} = props
|
||||
const path = pathFromProps ?? name
|
||||
|
||||
const { i18n } = useTranslation()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -25,11 +25,10 @@ const JSONFieldComponent: JSONFieldClientComponent = (props) => {
|
||||
localized,
|
||||
required,
|
||||
},
|
||||
path: pathFromProps,
|
||||
path,
|
||||
readOnly,
|
||||
validate,
|
||||
} = props
|
||||
const path = pathFromProps ?? name
|
||||
|
||||
const [stringValue, setStringValue] = useState<string>()
|
||||
const [jsonError, setJsonError] = useState<string>()
|
||||
|
||||
@@ -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 } =
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -33,10 +33,9 @@ const PasswordFieldComponent: React.FC<PasswordFieldProps> = (props) => {
|
||||
required,
|
||||
} = {} as PasswordFieldProps['field'],
|
||||
inputRef,
|
||||
path: pathFromProps,
|
||||
path,
|
||||
validate,
|
||||
} = props
|
||||
const path = pathFromProps ?? name
|
||||
|
||||
const { t } = useTranslation()
|
||||
const locale = useLocale()
|
||||
|
||||
@@ -27,7 +27,7 @@ export type PasswordFieldProps = {
|
||||
/**
|
||||
* @default field.name
|
||||
*/
|
||||
readonly path?: string
|
||||
readonly path: string
|
||||
/**
|
||||
* @default field.name
|
||||
*/
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -56,11 +56,10 @@ const RelationshipFieldComponent: RelationshipFieldClientComponent = (props) =>
|
||||
relationTo,
|
||||
required,
|
||||
},
|
||||
path: pathFromProps,
|
||||
path,
|
||||
readOnly,
|
||||
validate,
|
||||
} = props
|
||||
const path = pathFromProps ?? name
|
||||
|
||||
const { config } = useConfig()
|
||||
|
||||
|
||||
@@ -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])
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -28,11 +28,10 @@ const TextareaFieldComponent: TextareaFieldClientComponent = (props) => {
|
||||
minLength,
|
||||
required,
|
||||
},
|
||||
path: pathFromProps,
|
||||
path,
|
||||
readOnly,
|
||||
validate,
|
||||
} = props
|
||||
const path = pathFromProps ?? name
|
||||
|
||||
const { i18n } = useTranslation()
|
||||
|
||||
|
||||
@@ -27,11 +27,10 @@ export function UploadComponent(props: UploadFieldClientProps) {
|
||||
relationTo,
|
||||
required,
|
||||
},
|
||||
path: pathFromProps,
|
||||
path,
|
||||
readOnly,
|
||||
validate,
|
||||
} = props
|
||||
const path = pathFromProps ?? name
|
||||
|
||||
const { config } = useConfig()
|
||||
|
||||
|
||||
@@ -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<ClientFieldBase>
|
||||
[K in 'hidden' | 'password' | FieldTypes]: React.FC<ClientFieldBase>
|
||||
} & {
|
||||
confirmPassword: React.FC<ConfirmPasswordFieldProps>
|
||||
}
|
||||
|
||||
export const fieldComponents: FieldTypesComponents = {
|
||||
|
||||
@@ -59,9 +59,6 @@ export const NullifyLocaleField: React.FC<NullifyLocaleFieldProps> = ({
|
||||
label: t('general:fallbackToDefaultLocale'),
|
||||
}}
|
||||
id={`field-${path.replace(/\./g, '__')}`}
|
||||
indexPath=""
|
||||
parentPath=""
|
||||
parentSchemaPath=""
|
||||
path={path}
|
||||
schemaPath=""
|
||||
// onToggle={onChange}
|
||||
|
||||
@@ -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<ClientComponentProps, 'forceRender' | 'readOnly' | 'schemaPath'>
|
||||
|
||||
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<ClientComponentProps, 'forceRender' | 'readOnly' | 'schemaPath'> = {
|
||||
forceRender,
|
||||
indexPath,
|
||||
parentPath,
|
||||
parentSchemaPath,
|
||||
path,
|
||||
readOnly,
|
||||
schemaPath,
|
||||
}
|
||||
|
||||
if (clientFieldConfig.admin?.hidden) {
|
||||
return <HiddenField field={clientFieldConfig} {...sharedProps} />
|
||||
const iterableFieldProps = {
|
||||
...baseFieldProps,
|
||||
indexPath,
|
||||
parentPath,
|
||||
parentSchemaPath,
|
||||
permissions,
|
||||
}
|
||||
|
||||
const DefaultField = fieldComponents?.[clientFieldConfig?.type]
|
||||
if (clientFieldConfig.admin?.hidden) {
|
||||
return <HiddenField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
}
|
||||
|
||||
switch (clientFieldConfig.type) {
|
||||
// named fields with subfields
|
||||
case 'array':
|
||||
return <ArrayField {...sharedProps} field={clientFieldConfig} permissions={permissions} />
|
||||
return <ArrayField {...iterableFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'blocks':
|
||||
return <BlocksField {...sharedProps} field={clientFieldConfig} permissions={permissions} />
|
||||
return <BlocksField {...iterableFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'checkbox':
|
||||
return <CheckboxField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'code':
|
||||
return <CodeField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'collapsible':
|
||||
return (
|
||||
<CollapsibleField {...sharedProps} field={clientFieldConfig} permissions={permissions} />
|
||||
)
|
||||
return <CollapsibleField {...iterableFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'date':
|
||||
return <DateTimeField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'email':
|
||||
return <EmailField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'group':
|
||||
return <GroupField {...sharedProps} field={clientFieldConfig} permissions={permissions} />
|
||||
return <GroupField {...iterableFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'join':
|
||||
return <JoinField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'json':
|
||||
return <JSONField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'number':
|
||||
return <NumberField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'point':
|
||||
return <PointField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'radio':
|
||||
return <RadioGroupField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'relationship':
|
||||
return <RelationshipField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'richText':
|
||||
return <RichTextField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
// unnamed fields with subfields
|
||||
case 'row':
|
||||
return <RowField {...sharedProps} field={clientFieldConfig} permissions={permissions} />
|
||||
case 'tabs':
|
||||
return <TabsField {...sharedProps} field={clientFieldConfig} permissions={permissions} />
|
||||
return <RowField {...iterableFieldProps} field={clientFieldConfig} />
|
||||
|
||||
default:
|
||||
return DefaultField ? <DefaultField field={clientFieldConfig} {...sharedProps} /> : null
|
||||
case 'select':
|
||||
return <SelectField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'tabs':
|
||||
return <TabsField {...iterableFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'text':
|
||||
return <TextField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'textarea':
|
||||
return <TextareaField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
|
||||
case 'ui':
|
||||
return <UIField />
|
||||
|
||||
case 'upload':
|
||||
return <UploadField {...baseFieldProps} field={clientFieldConfig} path={path} />
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<FieldPaths> = {
|
||||
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,
|
||||
|
||||
@@ -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<ClientFieldProps, 'field' | 'indexPath' | 'path'>,
|
||||
'indexPath' | 'path'
|
||||
>,
|
||||
P extends MarkOptional<FieldPaths & Pick<ClientFieldProps, 'field'>, 'indexPath' | 'path'>,
|
||||
>(
|
||||
Field: React.ComponentType<P>,
|
||||
): React.FC<P> => {
|
||||
|
||||
@@ -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<IFieldComponentsContext>(null)
|
||||
|
||||
export const FieldComponentsProvider: React.FC<{
|
||||
readonly children: React.ReactNode
|
||||
readonly fieldComponents: FieldTypesComponents
|
||||
}> = ({ children, fieldComponents }) => {
|
||||
return (
|
||||
<FieldComponentsContext.Provider value={fieldComponents}>
|
||||
{children}
|
||||
</FieldComponentsContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export const useFieldComponents = (): IFieldComponentsContext => useContext(FieldComponentsContext)
|
||||
@@ -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<Props> = ({
|
||||
<ServerFunctionsProvider serverFunction={serverFunction}>
|
||||
<RouteCacheComponent>
|
||||
<ConfigProvider config={config}>
|
||||
<FieldComponentsProvider fieldComponents={fieldComponents}>
|
||||
<ClientFunctionProvider>
|
||||
<TranslationProvider
|
||||
dateFNSKey={dateFNSKey}
|
||||
fallbackLang={fallbackLang}
|
||||
language={languageCode}
|
||||
languageOptions={languageOptions}
|
||||
switchLanguageServerAction={switchLanguageServerAction}
|
||||
translations={translations}
|
||||
<ClientFunctionProvider>
|
||||
<TranslationProvider
|
||||
dateFNSKey={dateFNSKey}
|
||||
fallbackLang={fallbackLang}
|
||||
language={languageCode}
|
||||
languageOptions={languageOptions}
|
||||
switchLanguageServerAction={switchLanguageServerAction}
|
||||
translations={translations}
|
||||
>
|
||||
<WindowInfoProvider
|
||||
breakpoints={{
|
||||
l: '(max-width: 1440px)',
|
||||
m: '(max-width: 1024px)',
|
||||
s: '(max-width: 768px)',
|
||||
xs: '(max-width: 400px)',
|
||||
}}
|
||||
>
|
||||
<WindowInfoProvider
|
||||
breakpoints={{
|
||||
l: '(max-width: 1440px)',
|
||||
m: '(max-width: 1024px)',
|
||||
s: '(max-width: 768px)',
|
||||
xs: '(max-width: 400px)',
|
||||
}}
|
||||
>
|
||||
<ScrollInfoProvider>
|
||||
<SearchParamsProvider>
|
||||
<ModalProvider classPrefix="payload" transTime={0} zIndex="var(--z-modal)">
|
||||
<AuthProvider permissions={permissions} user={user}>
|
||||
<PreferencesProvider>
|
||||
<ThemeProvider theme={theme}>
|
||||
<ParamsProvider>
|
||||
<LocaleProvider>
|
||||
<StepNavProvider>
|
||||
<LoadingOverlayProvider>
|
||||
<DocumentEventsProvider>
|
||||
<NavProvider initialIsOpen={isNavOpen}>
|
||||
{children}
|
||||
</NavProvider>
|
||||
</DocumentEventsProvider>
|
||||
</LoadingOverlayProvider>
|
||||
</StepNavProvider>
|
||||
</LocaleProvider>
|
||||
</ParamsProvider>
|
||||
</ThemeProvider>
|
||||
</PreferencesProvider>
|
||||
<ModalContainer />
|
||||
<StayLoggedInModal />
|
||||
</AuthProvider>
|
||||
</ModalProvider>
|
||||
</SearchParamsProvider>
|
||||
</ScrollInfoProvider>
|
||||
</WindowInfoProvider>
|
||||
</TranslationProvider>
|
||||
</ClientFunctionProvider>
|
||||
</FieldComponentsProvider>
|
||||
<ScrollInfoProvider>
|
||||
<SearchParamsProvider>
|
||||
<ModalProvider classPrefix="payload" transTime={0} zIndex="var(--z-modal)">
|
||||
<AuthProvider permissions={permissions} user={user}>
|
||||
<PreferencesProvider>
|
||||
<ThemeProvider theme={theme}>
|
||||
<ParamsProvider>
|
||||
<LocaleProvider>
|
||||
<StepNavProvider>
|
||||
<LoadingOverlayProvider>
|
||||
<DocumentEventsProvider>
|
||||
<NavProvider initialIsOpen={isNavOpen}>
|
||||
{children}
|
||||
</NavProvider>
|
||||
</DocumentEventsProvider>
|
||||
</LoadingOverlayProvider>
|
||||
</StepNavProvider>
|
||||
</LocaleProvider>
|
||||
</ParamsProvider>
|
||||
</ThemeProvider>
|
||||
</PreferencesProvider>
|
||||
<ModalContainer />
|
||||
<StayLoggedInModal />
|
||||
</AuthProvider>
|
||||
</ModalProvider>
|
||||
</SearchParamsProvider>
|
||||
</ScrollInfoProvider>
|
||||
</WindowInfoProvider>
|
||||
</TranslationProvider>
|
||||
</ClientFunctionProvider>
|
||||
</ConfigProvider>
|
||||
</RouteCacheComponent>
|
||||
</ServerFunctionsProvider>
|
||||
|
||||
@@ -215,9 +215,6 @@ export const Auth: React.FC<Props> = (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> = (props) => {
|
||||
admin: { disabled, readOnly },
|
||||
label: t('authentication:verified'),
|
||||
}}
|
||||
indexPath=""
|
||||
parentPath=""
|
||||
parentSchemaPath=""
|
||||
path="_verified"
|
||||
schemaPath={`${collectionSlug}._verified`}
|
||||
/>
|
||||
|
||||
@@ -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 (
|
||||
<TextField
|
||||
field={field}
|
||||
indexPath={indexPath}
|
||||
parentPath={parentPath}
|
||||
parentSchemaPath={parentSchemaPath}
|
||||
path={path}
|
||||
schemaPath={schemaPath}
|
||||
/>
|
||||
)
|
||||
export const MyClientFieldComponent: TextFieldClientComponent = (props) => {
|
||||
return <TextField {...props} />
|
||||
}
|
||||
|
||||
@@ -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!!!!'
|
||||
|
||||
Reference in New Issue
Block a user