UNPKG

payload

Version:

Node, React, Headless CMS and Application Framework built on Next.js

1,140 lines • 61.3 kB
import type { EditorProps } from '@monaco-editor/react'; import type { JSONSchema4 } from 'json-schema'; import type { CSSProperties } from 'react'; import type React from 'react'; import type { DeepUndefinable, MarkRequired } from 'ts-essentials'; import type { JoinFieldClientProps, JoinFieldErrorClientComponent, JoinFieldErrorServerComponent, JoinFieldLabelClientComponent, JoinFieldLabelServerComponent } from '../../admin/fields/Join.js'; import type { FieldClientComponent, FieldServerComponent } from '../../admin/forms/Field.js'; import type { RichTextAdapter, RichTextAdapterProvider } from '../../admin/RichText.js'; import type { ArrayFieldClientProps, ArrayFieldErrorClientComponent, ArrayFieldErrorServerComponent, ArrayFieldLabelClientComponent, ArrayFieldLabelServerComponent, BlocksFieldClientProps, BlocksFieldErrorClientComponent, BlocksFieldErrorServerComponent, BlocksFieldLabelClientComponent, BlocksFieldLabelServerComponent, CheckboxFieldClientProps, CheckboxFieldErrorClientComponent, CheckboxFieldErrorServerComponent, CheckboxFieldLabelClientComponent, CheckboxFieldLabelServerComponent, ClientTab, CodeFieldClientProps, CodeFieldErrorClientComponent, CodeFieldErrorServerComponent, CodeFieldLabelClientComponent, CodeFieldLabelServerComponent, CollapsibleFieldClientProps, CollapsibleFieldLabelClientComponent, CollapsibleFieldLabelServerComponent, ConditionalDateProps, DateFieldClientProps, DateFieldErrorClientComponent, DateFieldErrorServerComponent, DateFieldLabelClientComponent, DateFieldLabelServerComponent, DefaultCellComponentProps, DefaultServerCellComponentProps, Description, EmailFieldClientProps, EmailFieldErrorClientComponent, EmailFieldErrorServerComponent, EmailFieldLabelClientComponent, EmailFieldLabelServerComponent, FieldDescriptionClientProps, FieldDescriptionServerProps, FieldDiffClientProps, FieldDiffServerProps, GroupFieldClientProps, GroupFieldLabelClientComponent, GroupFieldLabelServerComponent, HiddenFieldProps, JSONFieldClientProps, JSONFieldErrorClientComponent, JSONFieldErrorServerComponent, JSONFieldLabelClientComponent, JSONFieldLabelServerComponent, NumberFieldClientProps, NumberFieldErrorClientComponent, NumberFieldErrorServerComponent, NumberFieldLabelClientComponent, NumberFieldLabelServerComponent, PointFieldClientProps, PointFieldErrorClientComponent, PointFieldErrorServerComponent, PointFieldLabelClientComponent, PointFieldLabelServerComponent, RadioFieldClientProps, RadioFieldErrorClientComponent, RadioFieldErrorServerComponent, RadioFieldLabelClientComponent, RadioFieldLabelServerComponent, RelationshipFieldClientProps, RelationshipFieldErrorClientComponent, RelationshipFieldErrorServerComponent, RelationshipFieldLabelClientComponent, RelationshipFieldLabelServerComponent, RichTextFieldClientProps, RowFieldClientProps, RowLabelComponent, SelectFieldClientProps, SelectFieldErrorClientComponent, SelectFieldErrorServerComponent, SelectFieldLabelClientComponent, SelectFieldLabelServerComponent, StaticDescription, TabsFieldClientProps, TextareaFieldClientProps, TextareaFieldErrorClientComponent, TextareaFieldErrorServerComponent, TextareaFieldLabelClientComponent, TextareaFieldLabelServerComponent, TextFieldClientProps, TextFieldErrorClientComponent, TextFieldErrorServerComponent, TextFieldLabelClientComponent, TextFieldLabelServerComponent, UploadFieldClientProps } from '../../admin/types.js'; import type { SanitizedCollectionConfig, TypeWithID } from '../../collections/config/types.js'; import type { CustomComponent, LabelFunction, PayloadComponent, StaticLabel } from '../../config/types.js'; import type { DBIdentifierName } from '../../database/types.js'; import type { SanitizedGlobalConfig } from '../../globals/config/types.js'; import type { ArrayFieldValidation, BlocksFieldValidation, BlockSlug, CheckboxFieldValidation, CodeFieldValidation, CollectionSlug, DateFieldValidation, EmailFieldValidation, JSONFieldValidation, PointFieldValidation, RadioFieldValidation, RequestContext, Sort, TextareaFieldValidation } from '../../index.js'; import type { DocumentPreferences } from '../../preferences/types.js'; import type { DefaultValue, JsonObject, Operation, PayloadRequest, Where } from '../../types/index.js'; import type { NumberFieldManyValidation, NumberFieldSingleValidation, RelationshipFieldManyValidation, RelationshipFieldSingleValidation, SelectFieldManyValidation, SelectFieldSingleValidation, TextFieldManyValidation, TextFieldSingleValidation, UploadFieldManyValidation, UploadFieldSingleValidation } from '../validations.js'; export type FieldHookArgs<TData extends TypeWithID = any, TValue = any, TSiblingData = any> = { /** * The data of the nearest parent block. If the field is not within a block, `blockData` will be equal to `undefined`. */ blockData: JsonObject | undefined; /** The collection which the field belongs to. If the field belongs to a global, this will be null. */ collection: null | SanitizedCollectionConfig; context: RequestContext; /** * Only available in `afterRead` hooks */ currentDepth?: number; /** * Only available in `afterRead` hooks */ /** The data passed to update the document within create and update operations, and the full document itself in the afterRead hook. */ data?: Partial<TData>; /** * Only available in the `afterRead` hook. */ depth?: number; draft?: boolean; /** The field which the hook is running against. */ field: FieldAffectingData; /** Boolean to denote if this hook is running against finding one, or finding many within the afterRead hook. */ findMany?: boolean; /** The global which the field belongs to. If the field belongs to a collection, this will be null. */ global: null | SanitizedGlobalConfig; indexPath: number[]; /** A string relating to which operation the field type is currently executing within. Useful within beforeValidate, beforeChange, and afterChange hooks to differentiate between create and update operations. */ operation?: 'create' | 'delete' | 'read' | 'update'; /** The full original document in `update` operations. In the `afterChange` hook, this is the resulting document of the operation. */ originalDoc?: TData; overrideAccess?: boolean; /** * The path of the field, e.g. ["group", "myArray", 1, "textField"]. The path is the schemaPath but with indexes and would be used in the context of field data, not field schemas. */ path: (number | string)[]; /** The document before changes were applied, only in `afterChange` hooks. */ previousDoc?: TData; /** The sibling data of the document before changes being applied, only in `beforeChange`, `beforeValidate`, `beforeDuplicate` and `afterChange` field hooks. */ previousSiblingDoc?: TData; /** The previous value of the field, before changes, only in `beforeChange`, `afterChange`, `beforeDuplicate` and `beforeValidate` field hooks. */ previousValue?: TValue; /** The Express request object. It is mocked for Local API operations. */ req: PayloadRequest; /** * The schemaPath of the field, e.g. ["group", "myArray", "textField"]. The schemaPath is the path but without indexes and would be used in the context of field schemas, not field data. */ schemaPath: string[]; /** * Only available in the `afterRead` hook. */ showHiddenFields?: boolean; /** The sibling data passed to a field that the hook is running against. */ siblingData: Partial<TSiblingData>; /** * The original siblingData with locales (not modified by any hooks). Only available in `beforeChange` and `beforeDuplicate` field hooks. */ siblingDocWithLocales?: Record<string, unknown>; /** * The sibling fields of the field which the hook is running against. */ siblingFields: (Field | TabAsField)[]; /** The value of the field. */ value?: TValue; }; export type FieldHook<TData extends TypeWithID = any, TValue = any, TSiblingData = any> = (args: FieldHookArgs<TData, TValue, TSiblingData>) => Promise<TValue> | TValue; export type FieldAccessArgs<TData extends TypeWithID = any, TSiblingData = any> = { /** * The data of the nearest parent block. If the field is not within a block, `blockData` will be equal to `undefined`. */ blockData?: JsonObject | undefined; /** * The incoming, top-level document data used to `create` or `update` the document with. */ data?: Partial<TData>; /** * The original data of the document before the `update` is applied. `doc` is undefined during the `create` operation. */ doc?: TData; /** * The `id` of the current document being read or updated. `id` is undefined during the `create` operation. */ id?: number | string; /** The `payload` object to interface with the payload API */ req: PayloadRequest; /** * Immediately adjacent data to this field. For example, if this is a `group` field, then `siblingData` will be the other fields within the group. */ siblingData?: Partial<TSiblingData>; }; export type FieldAccess<TData extends TypeWithID = any, TSiblingData = any> = (args: FieldAccessArgs<TData, TSiblingData>) => boolean | Promise<boolean>; export type Condition<TData extends TypeWithID = any, TSiblingData = any> = ( /** * The top-level document data */ data: Partial<TData>, /** * Immediately adjacent data to this field. For example, if this is a `group` field, then `siblingData` will be the other fields within the group. */ siblingData: Partial<TSiblingData>, { blockData, operation, path, user, }: { /** * The data of the nearest parent block. If the field is not within a block, `blockData` will be equal to `undefined`. */ blockData: Partial<TData>; /** * A string relating to which operation the field type is currently executing within. */ operation: Operation; /** * The path of the field, e.g. ["group", "myArray", 1, "textField"]. The path is the schemaPath but with indexes and would be used in the context of field data, not field schemas. */ path: (number | string)[]; user: PayloadRequest['user']; }) => boolean; export type FilterOptionsProps<TData = any> = { /** * The data of the nearest parent block. Will be `undefined` if the field is not within a block or when called on a `Filter` component within the list view. */ blockData: TData; /** * An object containing the full collection or global document currently being edited. Will be an empty object when called on a `Filter` component within the list view. */ data: TData; /** * The `id` of the current document being edited. Will be undefined during the `create` operation or when called on a `Filter` component within the list view. */ id: number | string; /** * The collection `slug` to filter against, limited to this field's `relationTo` property. */ relationTo: CollectionSlug; req: PayloadRequest; /** * An object containing document data that is scoped to only fields within the same parent of this field. Will be an empty object when called on a `Filter` component within the list view. */ siblingData: unknown; /** * An object containing the currently authenticated user. */ user: Partial<PayloadRequest['user']>; }; export type FilterOptionsFunc<TData = any> = (options: FilterOptionsProps<TData>) => boolean | Promise<boolean | Where> | Where; export type FilterOptions<TData = any> = ((options: FilterOptionsProps<TData>) => boolean | Promise<boolean | Where> | Where) | null | Where; type Admin = { className?: string; components?: { Cell?: PayloadComponent<DefaultServerCellComponentProps, DefaultCellComponentProps>; Description?: PayloadComponent<FieldDescriptionServerProps, FieldDescriptionClientProps>; Diff?: PayloadComponent<FieldDiffServerProps, FieldDiffClientProps>; Field?: PayloadComponent<FieldClientComponent | FieldServerComponent>; /** * The Filter component has to be a client component */ Filter?: PayloadComponent; }; /** * You can programmatically show / hide fields based on what other fields are doing. * This is also run on the server, to determine if the field should be validated. */ condition?: Condition; /** Extension point to add your custom data. Available in server and client. */ custom?: Record<string, any>; /** * The field description will be displayed next to the field in the admin UI. Additionally, * we use the field description to generate JSDoc comments for the generated TypeScript types. */ description?: Description; disableBulkEdit?: boolean; disabled?: boolean; /** * Shows / hides fields from appearing in the list view column selector. * @type boolean */ disableListColumn?: boolean; /** * Shows / hides fields from appearing in the list view filter options. * @type boolean */ disableListFilter?: boolean; hidden?: boolean; position?: 'sidebar'; readOnly?: boolean; style?: CSSProperties; width?: CSSProperties['width']; }; export type AdminClient = { className?: string; /** Extension point to add your custom data. Available in server and client. */ custom?: Record<string, any>; description?: StaticDescription; disableBulkEdit?: boolean; disabled?: boolean; /** * Shows / hides fields from appearing in the list view column selector. * @type boolean */ disableListColumn?: boolean; /** * Shows / hides fields from appearing in the list view filter options. * @type boolean */ disableListFilter?: boolean; hidden?: boolean; position?: 'sidebar'; readOnly?: boolean; style?: { '--field-width'?: CSSProperties['width']; } & CSSProperties; width?: CSSProperties['width']; }; export type Labels = { plural: LabelFunction | StaticLabel; singular: LabelFunction | StaticLabel; }; export type LabelsClient = { plural: StaticLabel; singular: StaticLabel; }; export type BaseValidateOptions<TData, TSiblingData, TValue> = { /** /** * The data of the nearest parent block. If the field is not within a block, `blockData` will be equal to `undefined`. */ blockData: Partial<TData>; collectionSlug?: string; data: Partial<TData>; event?: 'onChange' | 'submit'; id?: number | string; operation?: Operation; /** * The path of the field, e.g. ["group", "myArray", 1, "textField"]. The path is the schemaPath but with indexes and would be used in the context of field data, not field schemas. */ path: (number | string)[]; preferences: DocumentPreferences; previousValue?: TValue; req: PayloadRequest; required?: boolean; siblingData: Partial<TSiblingData>; }; export type ValidateOptions<TData, TSiblingData, TFieldConfig extends object, TValue> = BaseValidateOptions<TData, TSiblingData, TValue> & TFieldConfig; export type Validate<TValue = any, TData = any, TSiblingData = any, TFieldConfig extends object = object> = (value: null | TValue | undefined, options: ValidateOptions<TData, TSiblingData, TFieldConfig, TValue>) => Promise<string | true> | string | true; export type OptionLabel = (() => React.JSX.Element) | LabelFunction | React.JSX.Element | StaticLabel; export type OptionObject = { label: OptionLabel; value: string; }; export type Option = OptionObject | string; export type FieldGraphQLType = { graphQL?: { /** * Complexity for the query. This is used to limit the complexity of the join query. * * @default 10 */ complexity?: number; }; }; export interface FieldBase { /** * Do not set this property manually. This is set to true during sanitization, to avoid * sanitizing the same field multiple times. */ _sanitized?: boolean; access?: { create?: FieldAccess; read?: FieldAccess; update?: FieldAccess; }; admin?: Admin; /** Extension point to add your custom data. Server only. */ custom?: Record<string, any>; defaultValue?: DefaultValue; hidden?: boolean; hooks?: { afterChange?: FieldHook[]; afterRead?: FieldHook[]; beforeChange?: FieldHook[]; /** * Runs before a document is duplicated to prevent errors in unique fields or return null to use defaultValue. */ beforeDuplicate?: FieldHook[]; beforeValidate?: FieldHook[]; }; index?: boolean; label?: false | LabelFunction | StaticLabel; localized?: boolean; /** * The name of the field. Must be alphanumeric and cannot contain ' . ' * * Must not be one of reserved field names: ['__v', 'salt', 'hash', 'file'] * @link https://payloadcms.com/docs/fields/overview#field-names */ name: string; required?: boolean; saveToJWT?: boolean | string; /** * Allows you to modify the base JSON schema that is generated during generate:types for this field. * This JSON schema will be used to generate the TypeScript interface of this field. */ typescriptSchema?: Array<(args: { jsonSchema: JSONSchema4; }) => JSONSchema4>; unique?: boolean; validate?: Validate; /** * Pass `true` to disable field in the DB * for [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges): * A virtual field can be used in `admin.useAsTitle` only when linked to a relationship. */ virtual?: boolean | string; } export interface FieldBaseClient { admin?: AdminClient; hidden?: boolean; index?: boolean; label?: StaticLabel; localized?: boolean; /** * The name of the field. Must be alphanumeric and cannot contain ' . ' * * Must not be one of reserved field names: ['__v', 'salt', 'hash', 'file'] * @link https://payloadcms.com/docs/fields/overview#field-names */ name: string; required?: boolean; saveToJWT?: boolean | string; /** * Allows you to modify the base JSON schema that is generated during generate:types for this field. * This JSON schema will be used to generate the TypeScript interface of this field. */ typescriptSchema?: Array<(args: { jsonSchema: JSONSchema4; }) => JSONSchema4>; unique?: boolean; } export type NumberField = { admin?: { /** Set this property to a string that will be used for browser autocomplete. */ autoComplete?: string; components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<NumberFieldErrorClientComponent | NumberFieldErrorServerComponent>; Label?: CustomComponent<NumberFieldLabelClientComponent | NumberFieldLabelServerComponent>; } & Admin['components']; /** Set this property to define a placeholder string for the field. */ placeholder?: Record<string, string> | string; /** Set a value for the number field to increment / decrement using browser controls. */ step?: number; } & Admin; /** Maximum value accepted. Used in the default `validate` function. */ max?: number; /** Minimum value accepted. Used in the default `validate` function. */ min?: number; type: 'number'; } & ({ /** Makes this field an ordered array of numbers instead of just a single number. */ hasMany: true; /** Maximum number of numbers in the numbers array, if `hasMany` is set to true. */ maxRows?: number; /** Minimum number of numbers in the numbers array, if `hasMany` is set to true. */ minRows?: number; validate?: NumberFieldManyValidation; } | { /** Makes this field an ordered array of numbers instead of just a single number. */ hasMany?: false | undefined; /** Maximum number of numbers in the numbers array, if `hasMany` is set to true. */ maxRows?: undefined; /** Minimum number of numbers in the numbers array, if `hasMany` is set to true. */ minRows?: undefined; validate?: NumberFieldSingleValidation; }) & Omit<FieldBase, 'validate'>; export type NumberFieldClient = { admin?: AdminClient & Pick<NumberField['admin'], 'autoComplete' | 'placeholder' | 'step'>; } & FieldBaseClient & Pick<NumberField, 'hasMany' | 'max' | 'maxRows' | 'min' | 'minRows' | 'type'>; export type TextField = { admin?: { autoComplete?: string; components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<TextFieldErrorClientComponent | TextFieldErrorServerComponent>; Label?: CustomComponent<TextFieldLabelClientComponent | TextFieldLabelServerComponent>; } & Admin['components']; placeholder?: Record<string, string> | string; rtl?: boolean; } & Admin; maxLength?: number; minLength?: number; type: 'text'; } & ({ /** Makes this field an ordered array of strings instead of just a single string. */ hasMany: true; /** Maximum number of strings in the strings array, if `hasMany` is set to true. */ maxRows?: number; /** Minimum number of strings in the strings array, if `hasMany` is set to true. */ minRows?: number; validate?: TextFieldManyValidation; } | { /** Makes this field an ordered array of strings instead of just a single string. */ hasMany?: false | undefined; /** Maximum number of strings in the strings array, if `hasMany` is set to true. */ maxRows?: undefined; /** Minimum number of strings in the strings array, if `hasMany` is set to true. */ minRows?: undefined; validate?: TextFieldSingleValidation; }) & Omit<FieldBase, 'validate'>; export type TextFieldClient = { admin?: AdminClient & Pick<TextField['admin'], 'autoComplete' | 'placeholder' | 'rtl'>; } & FieldBaseClient & Pick<TextField, 'hasMany' | 'maxLength' | 'maxRows' | 'minLength' | 'minRows' | 'type'>; export type EmailField = { admin?: { autoComplete?: string; components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<EmailFieldErrorClientComponent | EmailFieldErrorServerComponent>; Label?: CustomComponent<EmailFieldLabelClientComponent | EmailFieldLabelServerComponent>; } & Admin['components']; placeholder?: Record<string, string> | string; } & Admin; type: 'email'; validate?: EmailFieldValidation; } & Omit<FieldBase, 'validate'>; export type EmailFieldClient = { admin?: AdminClient & Pick<EmailField['admin'], 'autoComplete' | 'placeholder'>; } & FieldBaseClient & Pick<EmailField, 'type'>; export type TextareaField = { admin?: { components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<TextareaFieldErrorClientComponent | TextareaFieldErrorServerComponent>; Label?: CustomComponent<TextareaFieldLabelClientComponent | TextareaFieldLabelServerComponent>; } & Admin['components']; placeholder?: Record<string, string> | string; rows?: number; rtl?: boolean; } & Admin; maxLength?: number; minLength?: number; type: 'textarea'; validate?: TextareaFieldValidation; } & Omit<FieldBase, 'validate'>; export type TextareaFieldClient = { admin?: AdminClient & Pick<TextareaField['admin'], 'placeholder' | 'rows' | 'rtl'>; } & FieldBaseClient & Pick<TextareaField, 'maxLength' | 'minLength' | 'type'>; export type CheckboxField = { admin?: { components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<CheckboxFieldErrorClientComponent | CheckboxFieldErrorServerComponent>; Label?: CustomComponent<CheckboxFieldLabelClientComponent | CheckboxFieldLabelServerComponent>; } & Admin['components']; } & Admin; type: 'checkbox'; validate?: CheckboxFieldValidation; } & Omit<FieldBase, 'validate'>; export type CheckboxFieldClient = { admin?: AdminClient; } & FieldBaseClient & Pick<CheckboxField, 'type'>; export type DateField = { admin?: { components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<DateFieldErrorClientComponent | DateFieldErrorServerComponent>; Label?: CustomComponent<DateFieldLabelClientComponent | DateFieldLabelServerComponent>; } & Admin['components']; date?: ConditionalDateProps; placeholder?: Record<string, string> | string; } & Admin; /** * Enable timezone selection in the admin interface. */ timezone?: true; type: 'date'; validate?: DateFieldValidation; } & Omit<FieldBase, 'validate'>; export type DateFieldClient = { admin?: AdminClient & Pick<DateField['admin'], 'date' | 'placeholder'>; } & FieldBaseClient & Pick<DateField, 'timezone' | 'type'>; export type GroupField = { admin?: { components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Label?: CustomComponent<GroupFieldLabelClientComponent | GroupFieldLabelServerComponent>; } & Admin['components']; hideGutter?: boolean; } & Admin; fields: Field[]; /** Customize generated GraphQL and Typescript schema names. * By default, it is bound to the collection. * * This is useful if you would like to generate a top level type to share amongst collections/fields. * **Note**: Top level types can collide, ensure they are unique amongst collections, arrays, groups, blocks, tabs. */ interfaceName?: string; type: 'group'; validate?: Validate<unknown, unknown, unknown, GroupField>; } & Omit<FieldBase, 'required' | 'validate'>; export type GroupFieldClient = { admin?: AdminClient & Pick<GroupField['admin'], 'hideGutter'>; fields: ClientField[]; } & Omit<FieldBaseClient, 'required'> & Pick<GroupField, 'interfaceName' | 'type'>; export type RowField = { admin?: Omit<Admin, 'description'>; fields: Field[]; type: 'row'; } & Omit<FieldBase, 'admin' | 'label' | 'localized' | 'name' | 'validate' | 'virtual'>; export type RowFieldClient = { admin?: Omit<AdminClient, 'description'>; fields: ClientField[]; } & Omit<FieldBaseClient, 'admin' | 'label' | 'name'> & Pick<RowField, 'type'>; export type CollapsibleField = { fields: Field[]; type: 'collapsible'; } & ({ admin: { components: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Label: CustomComponent<CollapsibleFieldLabelClientComponent | CollapsibleFieldLabelServerComponent>; } & Admin['components']; initCollapsed?: boolean; } & Admin; label?: Required<FieldBase['label']>; } | { admin?: { components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Label?: CustomComponent<CollapsibleFieldLabelClientComponent | CollapsibleFieldLabelServerComponent>; } & Admin['components']; initCollapsed?: boolean; } & Admin; label: Required<FieldBase['label']>; }) & Omit<FieldBase, 'label' | 'localized' | 'name' | 'validate' | 'virtual'>; export type CollapsibleFieldClient = { admin?: { initCollapsed?: boolean; } & AdminClient; fields: ClientField[]; label: StaticLabel; } & Omit<FieldBaseClient, 'label' | 'name' | 'validate'> & Pick<CollapsibleField, 'type'>; type TabBase = { /** * @deprecated * Use `admin.description` instead. This will be removed in a future major version. */ description?: LabelFunction | StaticDescription; fields: Field[]; id?: string; interfaceName?: string; saveToJWT?: boolean | string; } & Omit<FieldBase, 'required' | 'validate'>; export type NamedTab = { /** Customize generated GraphQL and Typescript schema names. * The slug is used by default. * * This is useful if you would like to generate a top level type to share amongst collections/fields. * **Note**: Top level types can collide, ensure they are unique amongst collections, arrays, groups, blocks, tabs. */ interfaceName?: string; } & TabBase; export type UnnamedTab = { interfaceName?: never; /** * Can be either: * - A string, which will be used as the tab's label. * - An object, where the key is the language code and the value is the label. */ label: { [selectedLanguage: string]: string; } | LabelFunction | string; localized?: never; } & Omit<TabBase, 'name' | 'virtual'>; export type Tab = NamedTab | UnnamedTab; export type TabsField = { admin?: Omit<Admin, 'description'>; type: 'tabs'; } & { tabs: Tab[]; } & Omit<FieldBase, 'admin' | 'localized' | 'name' | 'saveToJWT' | 'virtual'>; export type TabsFieldClient = { admin?: Omit<AdminClient, 'description'>; tabs: ClientTab[]; } & Omit<FieldBaseClient, 'admin' | 'localized' | 'name' | 'saveToJWT'> & Pick<TabsField, 'type'>; export type TabAsField = { name?: string; type: 'tab'; } & Tab; export type TabAsFieldClient = ClientTab & Pick<TabAsField, 'name' | 'type'>; export type UIField = { admin: { components?: { /** * Allow any custom components to be added to the UI field. This allows * the UI field to be used as a vessel for getting components rendered. */ [key: string]: PayloadComponent | undefined; Cell?: CustomComponent; Field?: CustomComponent; /** * The Filter component has to be a client component */ Filter?: PayloadComponent; } & Admin['components']; condition?: Condition; /** Extension point to add your custom data. Available in server and client. */ custom?: Record<string, any>; /** * Set `false` make the UI field appear in the list view column selector. `true` by default for UI fields. * @default true */ disableBulkEdit?: boolean; /** * Shows / hides fields from appearing in the list view column selector. * @type boolean */ disableListColumn?: boolean; position?: string; width?: CSSProperties['width']; }; /** Extension point to add your custom data. Server only. */ custom?: Record<string, any>; label?: Record<string, string> | string; name: string; type: 'ui'; }; export type UIFieldClient = { admin: DeepUndefinable<FieldBaseClient['admin']> & Pick<UIField['admin'], 'custom' | 'disableBulkEdit' | 'disableListColumn' | 'position' | 'width'>; } & Omit<DeepUndefinable<FieldBaseClient>, 'admin'> & // still include FieldBaseClient (even if it's undefinable) so that we don't need constant type checks (e.g. if('xy' in field)) Pick<UIField, 'label' | 'name' | 'type'>; type SharedUploadProperties = { /** * Toggle the preview in the admin interface. */ displayPreview?: boolean; filterOptions?: FilterOptions; /** * Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. * * {@link https://payloadcms.com/docs/getting-started/concepts#field-level-max-depth} */ maxDepth?: number; type: 'upload'; } & ({ hasMany: true; /** * @deprecated Use 'maxRows' instead */ max?: number; maxRows?: number; /** * @deprecated Use 'minRows' instead */ min?: number; minRows?: number; validate?: UploadFieldManyValidation; } | { hasMany?: false | undefined; /** * @deprecated Use 'maxRows' instead */ max?: undefined; maxRows?: undefined; /** * @deprecated Use 'minRows' instead */ min?: undefined; minRows?: undefined; validate?: UploadFieldSingleValidation; }) & FieldGraphQLType & Omit<FieldBase, 'validate'>; type SharedUploadPropertiesClient = FieldBaseClient & Pick<SharedUploadProperties, 'hasMany' | 'max' | 'maxDepth' | 'maxRows' | 'min' | 'minRows' | 'type'>; type UploadAdmin = { allowCreate?: boolean; components?: { Error?: CustomComponent<RelationshipFieldErrorClientComponent | RelationshipFieldErrorServerComponent>; Label?: CustomComponent<RelationshipFieldLabelClientComponent | RelationshipFieldLabelServerComponent>; } & Admin['components']; isSortable?: boolean; } & Admin; type UploadAdminClient = AdminClient & Pick<UploadAdmin, 'allowCreate' | 'isSortable'>; export type PolymorphicUploadField = { admin?: { sortOptions?: Partial<Record<CollectionSlug, string>>; } & UploadAdmin; relationTo: CollectionSlug[]; } & SharedUploadProperties; export type PolymorphicUploadFieldClient = { admin?: { sortOptions?: Pick<PolymorphicUploadField['admin'], 'sortOptions'>; } & UploadAdminClient; } & Pick<PolymorphicUploadField, 'displayPreview' | 'maxDepth' | 'relationTo' | 'type'> & SharedUploadPropertiesClient; export type SingleUploadField = { admin?: { sortOptions?: string; } & UploadAdmin; relationTo: CollectionSlug; } & SharedUploadProperties; export type SingleUploadFieldClient = { admin?: Pick<SingleUploadField['admin'], 'sortOptions'> & UploadAdminClient; } & Pick<SingleUploadField, 'displayPreview' | 'maxDepth' | 'relationTo' | 'type'> & SharedUploadPropertiesClient; export type UploadField = SingleUploadField; export type UploadFieldClient = SingleUploadFieldClient; export type CodeField = { admin?: { components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<CodeFieldErrorClientComponent | CodeFieldErrorServerComponent>; Label?: CustomComponent<CodeFieldLabelClientComponent | CodeFieldLabelServerComponent>; } & Admin['components']; editorOptions?: EditorProps['options']; language?: string; } & Admin; maxLength?: number; minLength?: number; type: 'code'; validate?: CodeFieldValidation; } & Omit<FieldBase, 'admin' | 'validate'>; export type CodeFieldClient = { admin?: AdminClient & Pick<CodeField['admin'], 'editorOptions' | 'language'>; } & Omit<FieldBaseClient, 'admin'> & Pick<CodeField, 'maxLength' | 'minLength' | 'type'>; export type JSONField = { admin?: { components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<JSONFieldErrorClientComponent | JSONFieldErrorServerComponent>; Label?: CustomComponent<JSONFieldLabelClientComponent | JSONFieldLabelServerComponent>; } & Admin['components']; editorOptions?: EditorProps['options']; maxHeight?: number; } & Admin; jsonSchema?: { fileMatch: string[]; schema: JSONSchema4; uri: string; }; type: 'json'; validate?: JSONFieldValidation; } & Omit<FieldBase, 'admin' | 'validate'>; export type JSONFieldClient = { admin?: AdminClient & Pick<JSONField['admin'], 'editorOptions' | 'maxHeight'>; } & Omit<FieldBaseClient, 'admin'> & Pick<JSONField, 'jsonSchema' | 'type'>; export type SelectField = { admin?: { components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<SelectFieldErrorClientComponent | SelectFieldErrorServerComponent>; Label?: CustomComponent<SelectFieldLabelClientComponent | SelectFieldLabelServerComponent>; } & Admin['components']; isClearable?: boolean; isSortable?: boolean; } & Admin; /** * Customize the SQL table name */ dbName?: DBIdentifierName; /** * Customize the DB enum name */ enumName?: DBIdentifierName; hasMany?: boolean; /** Customize generated GraphQL and Typescript schema names. * By default, it is bound to the collection. * * This is useful if you would like to generate a top level type to share amongst collections/fields. * **Note**: Top level types can collide, ensure they are unique amongst collections, arrays, groups, blocks, tabs. */ interfaceName?: string; options: Option[]; type: 'select'; } & ({ hasMany: true; validate?: SelectFieldManyValidation; } | { hasMany?: false | undefined; validate?: SelectFieldSingleValidation; }) & Omit<FieldBase, 'validate'>; export type SelectFieldClient = { admin?: AdminClient & Pick<SelectField['admin'], 'isClearable' | 'isSortable'>; } & FieldBaseClient & Pick<SelectField, 'hasMany' | 'interfaceName' | 'options' | 'type'>; type SharedRelationshipProperties = { filterOptions?: FilterOptions; /** * Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. * * {@link https://payloadcms.com/docs/getting-started/concepts#field-level-max-depth} */ maxDepth?: number; type: 'relationship'; } & ({ hasMany: true; /** * @deprecated Use 'maxRows' instead */ max?: number; maxRows?: number; /** * @deprecated Use 'minRows' instead */ min?: number; minRows?: number; validate?: RelationshipFieldManyValidation; } | { hasMany?: false | undefined; /** * @deprecated Use 'maxRows' instead */ max?: undefined; maxRows?: undefined; /** * @deprecated Use 'minRows' instead */ min?: undefined; minRows?: undefined; validate?: RelationshipFieldSingleValidation; }) & FieldGraphQLType & Omit<FieldBase, 'validate'>; type SharedRelationshipPropertiesClient = FieldBaseClient & Pick<SharedRelationshipProperties, 'hasMany' | 'max' | 'maxDepth' | 'maxRows' | 'min' | 'minRows' | 'type'>; type RelationshipAdmin = { allowCreate?: boolean; allowEdit?: boolean; appearance?: 'drawer' | 'select'; components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<RelationshipFieldErrorClientComponent | RelationshipFieldErrorServerComponent>; Label?: CustomComponent<RelationshipFieldLabelClientComponent | RelationshipFieldLabelServerComponent>; } & Admin['components']; isSortable?: boolean; } & Admin; type RelationshipAdminClient = AdminClient & Pick<RelationshipAdmin, 'allowCreate' | 'allowEdit' | 'appearance' | 'isSortable'>; export type PolymorphicRelationshipField = { admin?: { sortOptions?: Partial<Record<CollectionSlug, string>>; } & RelationshipAdmin; relationTo: CollectionSlug[]; } & SharedRelationshipProperties; export type PolymorphicRelationshipFieldClient = { admin?: { sortOptions?: Pick<PolymorphicRelationshipField['admin'], 'sortOptions'>; } & RelationshipAdminClient; } & Pick<PolymorphicRelationshipField, 'relationTo'> & SharedRelationshipPropertiesClient; export type SingleRelationshipField = { admin?: { sortOptions?: string; } & RelationshipAdmin; relationTo: CollectionSlug; } & SharedRelationshipProperties; export type SingleRelationshipFieldClient = { admin?: Partial<Pick<SingleRelationshipField['admin'], 'sortOptions'>> & RelationshipAdminClient; } & Pick<SingleRelationshipField, 'relationTo'> & SharedRelationshipPropertiesClient; export type RelationshipField = PolymorphicRelationshipField | SingleRelationshipField; export type RelationshipFieldClient = PolymorphicRelationshipFieldClient | SingleRelationshipFieldClient; export type ValueWithRelation = { relationTo: CollectionSlug; value: number | string; }; export declare function valueIsValueWithRelation(value: unknown): value is ValueWithRelation; export type RelationshipValue = RelationshipValueMany | RelationshipValueSingle; export type RelationshipValueMany = (number | string)[] | ValueWithRelation[]; export type RelationshipValueSingle = number | string | ValueWithRelation; export type RichTextField<TValue extends object = any, TAdapterProps = any, TExtraProperties = object> = { admin?: { components?: { Error?: CustomComponent; Label?: CustomComponent; } & Admin['components']; } & Admin; editor?: RichTextAdapter<TValue, TAdapterProps, TExtraProperties> | RichTextAdapterProvider<TValue, TAdapterProps, TExtraProperties>; /** * Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. * * {@link https://payloadcms.com/docs/getting-started/concepts#field-level-max-depth} */ maxDepth?: number; type: 'richText'; } & FieldBase & TExtraProperties; export type RichTextFieldClient<TValue extends object = any, TAdapterProps = any, TExtraProperties = object> = FieldBaseClient & Pick<RichTextField<TValue, TAdapterProps, TExtraProperties>, 'maxDepth' | 'type'> & TExtraProperties; export type ArrayField = { admin?: { components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<ArrayFieldErrorClientComponent | ArrayFieldErrorServerComponent>; Label?: CustomComponent<ArrayFieldLabelClientComponent | ArrayFieldLabelServerComponent>; RowLabel?: RowLabelComponent; } & Admin['components']; initCollapsed?: boolean; /** * Disable drag and drop sorting */ isSortable?: boolean; } & Admin; /** * Customize the SQL table name */ dbName?: DBIdentifierName; fields: Field[]; /** Customize generated GraphQL and Typescript schema names. * By default, it is bound to the collection. * * This is useful if you would like to generate a top level type to share amongst collections/fields. * **Note**: Top level types can collide, ensure they are unique amongst collections, arrays, groups, blocks, tabs. */ interfaceName?: string; labels?: Labels; maxRows?: number; minRows?: number; type: 'array'; validate?: ArrayFieldValidation; } & Omit<FieldBase, 'validate'>; export type ArrayFieldClient = { admin?: AdminClient & Pick<ArrayField['admin'], 'initCollapsed' | 'isSortable'>; fields: ClientField[]; labels?: LabelsClient; } & FieldBaseClient & Pick<ArrayField, 'interfaceName' | 'maxRows' | 'minRows' | 'type'>; export type RadioField = { admin?: { components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<RadioFieldErrorClientComponent | RadioFieldErrorServerComponent>; Label?: CustomComponent<RadioFieldLabelClientComponent | RadioFieldLabelServerComponent>; } & Admin['components']; layout?: 'horizontal' | 'vertical'; } & Admin; /** * Customize the SQL table name */ dbName?: DBIdentifierName; /** * Customize the DB enum name */ enumName?: DBIdentifierName; /** Customize generated GraphQL and Typescript schema names. * By default, it is bound to the collection. * * This is useful if you would like to generate a top level type to share amongst collections/fields. * **Note**: Top level types can collide, ensure they are unique amongst collections, arrays, groups, blocks, tabs. */ interfaceName?: string; options: Option[]; type: 'radio'; validate?: RadioFieldValidation; } & Omit<FieldBase, 'validate'>; export type RadioFieldClient = { admin?: AdminClient & Pick<RadioField['admin'], 'layout'>; } & FieldBaseClient & Pick<RadioField, 'interfaceName' | 'options' | 'type'>; type BlockFields = { [key: string]: any; blockName?: string; blockType?: string; }; export type BlockJSX = { /** * Override the default regex used to search for the start of the block in the JSX. * By default, it's <BlockSlugHere */ customEndRegex?: { /** * Whether the end match is optional. If true, the end match is * not required to match for the transformer to be triggered. * The entire text from regexpStart to the end of the document will then be matched. */ optional?: true; regExp: RegExp; } | RegExp; /** * Override the default regex used to search for the start of the block in the JSX. * By default, it's <BlockSlugHere/> */ customStartRegex?: RegExp; /** * By default, all spaces at the beginning and end of every line of the * children (text between the open and close match) are removed. * Set this to true to disable this behavior. */ doNotTrimChildren?: boolean; /** * Function that receives the data for a given block and returns a JSX representation of it. * * This is used to convert Lexical => JSX */ export: (props: { fields: BlockFields; lexicalToMarkdown: (props: { editorState: Record<string, any>; }) => string; }) => { children?: string; props?: object; } | false | string; /** * Function that receives the markdown string and parsed * JSX props for a given matched block and returns a Lexical representation of it. * * This is used to convert JSX => Lexical */ import: (props: { children: string; closeMatch: null | RegExpMatchArray; htmlToLexical?: ((props: { html: string; }) => any) | null; markdownToLexical: (props: { markdown: string; }) => Record<string, any>; openMatch?: RegExpMatchArray; props: Record<string, any>; }) => BlockFields | false; }; export type Block = { /** * Do not set this property manually. This is set to true during sanitization, to avoid * sanitizing the same block multiple times. */ _sanitized?: boolean; admin?: { components?: { /** * This will replace the entire block component, including the block header / collapsible. */ Block?: PayloadComponent<any, any>; Label?: PayloadComponent<any, any>; }; /** Extension point to add your custom data. Available in server and client. */ custom?: Record<string, any>; /** * Hides the block name field from the Block's header * * @default false */ disableBlockName?: boolean; group?: Record<string, string> | string; jsx?: PayloadComponent; }; /** Extension point to add your custom data. Server only. */ custom?: Record<string, any>; /** * Customize the SQL table name */ dbName?: DBIdentifierName; fields: Field[]; /** @deprecated - please migrate to the interfaceName property instead. */ graphQL?: { singularName?: string; }; imageAltText?: string; /** * Preferred aspect ratio of the image is 3 : 2 */ imageURL?: string; /** Customize generated GraphQL and Typescript schema names. * The slug is used by default. * * This is useful if you would like to generate a top level type to share amongst collections/fields. * **Note**: Top level types can collide, ensure they are unique amongst collections, arrays, groups, blocks, tabs. */ interfaceName?: string; jsx?: BlockJSX; labels?: Labels; slug: string; }; export type ClientBlock = { admin?: Pick<Block['admin'], 'custom' | 'disableBlockName' | 'group'>; fields: ClientField[]; labels?: LabelsClient; } & Pick<Block, 'imageAltText' | 'imageURL' | 'jsx' | 'slug'>; export type BlocksField = { admin?: { components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<BlocksFieldErrorClientComponent | BlocksFieldErrorServerComponent>; Label?: CustomComponent<BlocksFieldLabelClientComponent | BlocksFieldLabelServerComponent>; } & Admin['components']; initCollapsed?: boolean; /** * Disable drag and drop sorting */ isSortable?: boolean; } & Admin; /** * Like `blocks`, but allows you to also pass strings that are slugs of blocks defined in `config.blocks`. * * @todo `blockReferences` will be merged with `blocks` in 4.0 */ blockReferences?: (Block | BlockSlug)[]; blocks: Block[]; defaultValue?: DefaultValue; labels?: Labels; maxRows?: number; minRows?: number; type: 'blocks'; validate?: BlocksFieldValidation; } & Omit<FieldBase, 'validate'>; export type BlocksFieldClient = { admin?: AdminClient & Pick<BlocksField['admin'], 'initCollapsed' | 'isSortable'>; /** * Like `blocks`, but allows you to also pass strings that are slugs of blocks defined in `config.blocks`. * * @todo `blockReferences` will be merged with `blocks` in 4.0 */ blockReferences?: (ClientBlock | string)[]; blocks: ClientBlock[]; labels?: LabelsClient; } & FieldBaseClient & Pick<BlocksField, 'maxRows' | 'minRows' | 'type'>; export type PointField = { admin?: { components?: { afterInput?: CustomComponent[]; beforeInput?: CustomComponent[]; Error?: CustomComponent<PointFieldErrorClientComponent | PointFieldErrorServerComponent>; Label?: CustomComponent<PointFieldLabelClie