## Description
Payload localization works on a field-by-field basis. As you can nest
fields within other fields, you could potentially nest a localized field
within a localized field—but this would be redundant and unnecessary.
There would be no reason to define a localized field within a localized
parent field, given that the entire data structure from the parent field
onward would be localized.
Up until this point, Payload would _allow_ you to nest a localized field
within another localized field, and this might have worked in MongoDB
but it will throw errors in Postgres.
Now, Payload will automatically remove the `localized: true` property
from sub-fields within `sanitizeFields` if a parent field is localized.
This could potentially be a breaking change if you have a configuration
with MongoDB that nests localized fields within localized fields.
## Migrating
You probably only need to migrate if you are using MongoDB, as there,
you may not have noticed any problems. But in Postgres or SQLite, this
would have caused issues so it's unlikely that you've made it too far
without experiencing issues due to a nested localized fields config.
In the event you would like to keep existing data in this fashion, we
have added a `compatibility.allowLocalizedWithinLocalized` flag to the
Payload config, which you can set to `true`, and Payload will then
disable this new sanitization step.
Set this compatibility flag to `true` only if you have an existing
Payload MongoDB database from pre-3.0, and you have nested localized
fields that you would like to maintain without migrating.
## Description
Threads the field config to all "field subcomponents" through props,
i.e. field label, description, error, etc. This way, the field config
that controls any particular component is easily accessible and strongly
typed, i.e. `props.field.maxLength`. This is true for both server and
client components, whose server-side props are now also contextually
typed. This behavior was temporarily removed in #7474 due to bloating
HTML, but has since been resolved in #7620. This PR also makes
significant improvements to component types by exporting explicit types
for _every component of every field_, each with its own client/server
variation. Now, a custom component can look something like this:
```tsx
import type { TextFieldLabelServerComponent } from 'payload'
import React from 'react'
export const CustomLabel: TextFieldLabelServerComponent = (props) => {
return (
<div>{`The max length of this field is: ${props?.field?.maxLength}`}</div>
)
}
```
The following types are now available:
```ts
import type {
TextFieldClientComponent,
TextFieldServerComponent,
TextFieldLabelClientComponent,
TextFieldLabelServerComponent,
TextFieldDescriptionClientComponent,
TextFieldDescriptionServerComponent,
TextFieldErrorClientComponent,
TextFieldErrorServerComponent,
// ...and so one for each field
} from 'payload'
```
BREAKING CHANGES:
In order to strictly type these components, a few breaking changes have
been made _solely to type definitions_. This only effects you if you are
heavily using custom components.
Old
```ts
import type { ErrorComponent, LabelComponent, DescriptionComponent } from 'payload'
```
New:
```ts
import type {
FieldErrorClientComponent,
FieldErrorServerComponent,
FieldLabelClientComponent,
FieldLabelServerComponent,
FieldDescriptionClientComponent,
FieldDescriptionServerComponent,
// Note: these are the generic, underlying types of the more stricter types described above ^
// For example, you should use the type that is explicit for your particular field and environment
// i.e. `TextFieldLabelClientComponent` and not simply `FieldLabelClientComponent`
} from 'payload'
```
- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## Checklist:
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
If it's undefined/null => Fallback Component may be rendered
If it's false => No component should be rendered - as if an empty
component was passed in
This ensures that the user does not have to install `@payloadcms/ui`
anymore, which previously exported an empty component to be used in
component paths
This PR makes three major changes to the codebase:
1. [Component Paths](#component-paths)
Instead of importing custom components into your config directly, they
are now defined as file paths and rendered only when needed. That way
the Payload config will be significantly more lightweight, and ensures
that the Payload config is 100% server-only and Node-safe. Related
discussion: https://github.com/payloadcms/payload/discussions/6938
2. [Client Config](#client-config)
Deprecates the component map by merging its logic into the client
config. The main goal of this change is for performance and
simplification. There was no need to deeply iterate over the Payload
config twice, once for the component map, and another for the client
config. Instead, we can do everything in the client config one time.
This has also dramatically simplified the client side prop drilling
through the UI library. Now, all components can share the same client
config which matches the exact shape of their Payload config (with the
exception of non-serializable props and mapped custom components).
3. [Custom client component are no longer
server-rendered](#custom-client-components-are-no-longer-server-rendered)
Previously, custom components would be server-rendered, no matter if
they are server or client components. Now, only server components are
rendered on the server. Client components are automatically detected,
and simply get passed through as `MappedComponent` to be rendered fully
client-side.
## Component Paths
Instead of importing custom components into your config directly, they
are now defined as file paths and rendered only when needed. That way
the Payload config will be significantly more lightweight, and ensures
that the Payload config is 100% server-only and Node-safe. Related
discussion: https://github.com/payloadcms/payload/discussions/6938
In order to reference any custom components in the Payload config, you
now have to specify a string path to the component instead of importing
it.
Old:
```ts
import { MyComponent2} from './MyComponent2.js'
admin: {
components: {
Label: MyComponent2
},
},
```
New:
```ts
admin: {
components: {
Label: '/collections/Posts/MyComponent2.js#MyComponent2', // <= has to be a relative path based on a baseDir configured in the Payload config - NOT relative based on the importing file
},
},
```
### Local API within Next.js routes
Previously, if you used the Payload Local API within Next.js pages, all
the client-side modules are being added to the bundle for that specific
page, even if you only need server-side functionality.
This `/test` route, which uses the Payload local API, was previously 460
kb. It is now down to 91 kb and does not bundle the Payload client-side
admin panel anymore.
All tests done
[here](https://github.com/payloadcms/payload-3.0-demo/tree/feat/path-test)
with beta.67/PR, db-mongodb and default richtext-lexical:
**dev /admin before:**

**dev /admin after:**

---
**dev /test before:**

**dev /test after:**

---
**build before:**

**build after::**

### Usage of the Payload Local API / config outside of Next.js
This will make it a lot easier to use the Payload config / local API in
other, server-side contexts. Previously, you might encounter errors due
to client files (like .scss files) not being allowed to be imported.
## Client Config
Deprecates the component map by merging its logic into the client
config. The main goal of this change is for performance and
simplification. There was no need to deeply iterate over the Payload
config twice, once for the component map, and another for the client
config. Instead, we can do everything in the client config one time.
This has also dramatically simplified the client side prop drilling
through the UI library. Now, all components can share the same client
config which matches the exact shape of their Payload config (with the
exception of non-serializable props and mapped custom components).
This is breaking change. The `useComponentMap` hook no longer exists,
and most component props have changed (for the better):
```ts
const { componentMap } = useComponentMap() // old
const { config } = useConfig() // new
```
The `useConfig` hook has also changed in shape, `config` is now a
property _within_ the context obj:
```ts
const config = useConfig() // old
const { config } = useConfig() // new
```
## Custom Client Components are no longer server rendered
Previously, custom components would be server-rendered, no matter if
they are server or client components. Now, only server components are
rendered on the server. Client components are automatically detected,
and simply get passed through as `MappedComponent` to be rendered fully
client-side.
The benefit of this change:
Custom client components can now receive props. Previously, the only way
for them to receive dynamic props from a parent client component was to
use hooks, e.g. `useFieldProps()`. Now, we do have the option of passing
in props to the custom components directly, if they are client
components. This will be simpler than having to look for the correct
hook.
This makes rendering them on the client a little bit more complex, as
you now have to check if that component is a server component (=>
already has been rendered) or a client component (=> not rendered yet,
has to be rendered here). However, this added complexity has been
alleviated through the easy-to-use `<RenderMappedComponent />` helper.
This helper now also handles rendering arrays of custom components (e.g.
beforeList, beforeLogin ...), which actually makes rendering custom
components easier in some cases.
## Misc improvements
This PR includes misc, breaking changes. For example, we previously
allowed unions between components and config object for the same
property. E.g. for the custom view property, you were allowed to pass in
a custom component or an object with other properties, alongside a
custom component.
Those union types are now gone. You can now either pass an object, or a
component. The previous `{ View: MyViewComponent}` is now `{ View: {
Component: MyViewComponent} }` or `{ View: { Default: { Component:
MyViewComponent} } }`.
This dramatically simplifies the way we read & process those properties,
especially in buildComponentMap. We can now simply check for the
existence of one specific property, which always has to be a component,
instead of running cursed runtime checks on a shared union property
which could contain a component, but could also contain functions or
objects.


- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.
---------
Co-authored-by: PatrikKozak <patrik@payloadcms.com>
Co-authored-by: Paul <paul@payloadcms.com>
Co-authored-by: Paul Popus <paul@nouance.io>
Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
Co-authored-by: James <james@trbl.design>
Fixes https://github.com/payloadcms/payload/issues/7428
Now email and username fields are rendered with the RenderFields
component, making them behave similarly to other fields. They now appear
and can respect doc permissions, readOnly settings, etc.
## Description
Fixes#7354
Since the `defaultIDType` for IDs in `postgres` are of type `number` -
the `contains` operator should be available in the filter options.
This PR checks the `defaultIDType` of ID and properly outputs the
correct component type for IDs
I.e if ID is of type `number` - the filter operators for ID should
correspond to the the operators of type number as well
The `contains` operator only belongs on fields of type string, aka of
component type `text`
- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## Checklist:
- [x] Existing test suite passes locally with my changes
Allows username to be optional when using the new loginWithUsername
feature. This can be done by the following:
```ts
auth: {
loginWithUsername: {
requireUsername: false, // <-- new property, default true
requireEmail: false, // default: false
allowEmailLogin: true, // default false
},
},
```
## Description
https://github.com/payloadcms/payload/pull/5015 's version for beta
branch. @JessChowdhury
- [X] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.
## Type of change
<!-- Please delete options that are not relevant. -->
- [X] New feature (non-breaking change which adds functionality)
- [X] This change requires a documentation update
## Checklist:
- [X] I have added tests that prove my fix is effective or that my
feature works
- [X] Existing test suite passes locally with my changes
- [X] I have made corresponding changes to the documentation
## Description
Currently, there is no way to read field props from within a custom
field component, i.e. `admin.components.Description`. For example, if
you set `maxLength: 100` on your field, your custom description
component cannot read it from `props.maxLength` or any other methods.
Because these components are rendered on the server, there is also no
way of using `admin.component.Field` to inject custom props yourself,
either. To support this, we can simply pass the base component props
into these components on the server, as expected. This has also led to
custom field component props becoming more strictly typed within the
config.
This change is considered breaking only because the types have changed.
This only affects you if you were previously importing the following
types into your own custom components. To migrate, simply change the
import paths for that type.
Old:
```ts
import type {
ArrayFieldProps,
ReducedBlock,
BlocksFieldProps,
CheckboxFieldProps,
CodeFieldProps,
CollapsibleFieldProps,
DateFieldProps,
EmailFieldProps,
GroupFieldProps,
HiddenFieldProps,
JSONFieldProps,
NumberFieldProps,
PointFieldProps,
RadioFieldProps,
RelationshipFieldProps,
RichTextComponentProps,
RowFieldProps,
SelectFieldProps,
TabsFieldProps,
TextFieldProps,
TextareaFieldProps,
UploadFieldProps,
ErrorProps,
FormFieldBase,
FieldComponentProps,
FieldMap,
MappedField,
MappedTab,
ReducedBlock,
} from '@payloadcms/ui'
```
New:
```ts
import type {
FormFieldBase,
// etc.
} from 'payload'
```
Custom field components are now much more strongly typed. To make this
happen, an explicit type for every custom component has been generated
for every field type. The convention is to append
`DescriptionComponent`, `LabelComponent`, and `ErrorComponent` onto the
end of the field name, i.e. `TextFieldDescriptionComponent`. Here's an
example:
```ts
import type { TextFieldDescriptionComponent } from 'payload'
import React from 'react'
export const CustomDescription: TextFieldDescriptionComponent = (props) => {
return (
<div id="custom-field-description">{`The max length of this field is: ${props?.maxLength}`}</div>
)
}
```
Here's the full list of all new types:
Label Components:
```ts
import type {
ArrayFieldLabelComponent,
BlocksFieldLabelComponent,
CheckboxFieldLabelComponent,
CodeFieldLabelComponent,
CollapsibleFieldLabelComponent,
DateFieldLabelComponent,
EmailFieldLabelComponent,
GroupFieldLabelComponent,
HiddenFieldLabelComponent,
JSONFieldLabelComponent,
NumberFieldLabelComponent,
PointFieldLabelComponent,
RadioFieldLabelComponent,
RelationshipFieldLabelComponent,
RichTextFieldLabelComponent,
RowFieldLabelComponent,
SelectFieldLabelComponent,
TabsFieldLabelComponent,
TextFieldLabelComponent,
TextareaFieldLabelComponent,
UploadFieldLabelComponent
} from 'payload'
```
Error Components:
```tsx
import type {
ArrayFieldErrorComponent,
BlocksFieldErrorComponent,
CheckboxFieldErrorComponent,
CodeFieldErrorComponent,
CollapsibleFieldErrorComponent,
DateFieldErrorComponent,
EmailFieldErrorComponent,
GroupFieldErrorComponent,
HiddenFieldErrorComponent,
JSONFieldErrorComponent,
NumberFieldErrorComponent,
PointFieldErrorComponent,
RadioFieldErrorComponent,
RelationshipFieldErrorComponent,
RichTextFieldErrorComponent,
RowFieldErrorComponent,
SelectFieldErrorComponent,
TabsFieldErrorComponent,
TextFieldErrorComponent,
TextareaFieldErrorComponent,
UploadFieldErrorComponent
} from 'payload'
```
Description Components:
```tsx
import type {
ArrayFieldDescriptionComponent,
BlocksFieldDescriptionComponent,
CheckboxFieldDescriptionComponent,
CodeFieldDescriptionComponent,
CollapsibleFieldDescriptionComponent,
DateFieldDescriptionComponent,
EmailFieldDescriptionComponent,
GroupFieldDescriptionComponent,
HiddenFieldDescriptionComponent,
JSONFieldDescriptionComponent,
NumberFieldDescriptionComponent,
PointFieldDescriptionComponent,
RadioFieldDescriptionComponent,
RelationshipFieldDescriptionComponent,
RichTextFieldDescriptionComponent,
RowFieldDescriptionComponent,
SelectFieldDescriptionComponent,
TabsFieldDescriptionComponent,
TextFieldDescriptionComponent,
TextareaFieldDescriptionComponent,
UploadFieldDescriptionComponent
} from 'payload'
```
This PR also:
- Standardizes the `FieldBase['label']` type with a new `LabelStatic`
type. This makes type usage much more consistent across components.
- Simplifies some of the typings in the field component map, removes
unneeded `<Omit>`, etc.
- Fixes misc. linting issues around voiding promises
- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.
## Type of change
- [x] New feature (non-breaking change which adds functionality)
## Checklist:
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [x] I have made corresponding changes to the documentation
**BREAKING:**
- The `deepMerge` exported from payload now handles more complex data and
is slower. The old, simple deepMerge is now exported as `deepMergeSimple`
- `combineMerge` is no longer exported. You can use
`deepMergeWithCombinedArrays` instead
- The behavior of the exported `deepCopyObject` and `isPlainObject` may
be different and more reliable, as the underlying algorithm has changed
Removes PayloadRequestWithData in favour of just PayloadRequest with
optional types for `data` and `locale`
`addDataAndFileToRequest` and `addLocalesToRequestFromData` now takes in
a single argument instead of an object
```ts
// before
await addDataAndFileToRequest({ request: req })
addLocalesToRequestFromData({ request: req })
// current
await addDataAndFileToRequest(req)
addLocalesToRequestFromData(req)
```
---------
Co-authored-by: Paul Popus <paul@nouance.io>
## BREAKING
- Our internal field hook methods now have new required `schemaPath` and
path `props`. This affects the following functions, if you are using
those: `afterChangeTraverseFields`, `afterReadTraverseFields`,
`beforeChangeTraverseFields`, `beforeValidateTraverseFields`,
`afterReadPromise`
- The afterChange field hook's `value` is now the value AFTER the
previous hooks were run. Previously, this was the original value, which
I believe is a bug
- Only relevant if you have built your own richText adapter: the
richText adapter `populationPromises` property has been renamed to
`graphQLPopulationPromises` and is now only run for graphQL. Previously,
it was run for graphQL AND the rest API. To migrate, use
`hooks.afterRead` to run population for the rest API
- Only relevant if you have built your own lexical features: The
`populationPromises` server feature property has been renamed to
`graphQLPopulationPromises` and is now only run for graphQL. Previously,
it was run for graphQL AND the rest API. To migrate, use
`hooks.afterRead` to run population for the rest API
- Serialized lexical link and upload nodes now have a new `id` property.
While not breaking, localization / hooks will not work for their fields
until you have migrated to that. Re-saving the old document on the new
version will automatically add the `id` property for you. You will also
get a bunch of console logs for every lexical node which is not migrated
Breaking Changes:
- Globals config: `admin.description` no longer accepts a custom component. You will have to move it to `admin.components.elements.Description`
- Collections config: `admin.description` no longer accepts a custom component. You will have to move it to `admin.components.edit.Description`
- All Fields: `field.admin.description` no longer accepts a custom component. You will have to move it to `field.admin.components.Description`
- Collapsible Field: `field.label` no longer accepts a custom component. You will have to move it to `field.admin.components.RowLabel`
- Array Field: `field.admin.components.RowLabel` no longer accepts strings or records
- If you are using our exported field components in your own app, their `labelProps` property has been stripped down and no longer contains the `label` and `required` prop. Those can now only be configured at the top-level
**BREAKING:**
- Narrows the type of the `plugins` prop of lexical features. Client props are now also automatically provided to the plugin components. To migrate, type your plugin as either `PluginComponent` or PluginComponentWithAnchor.
- `BlockQuoteFeature` has been renamed to `BlockquoteFeature`
- `createClientComponent` is now exported only from /components
- The `LexicalBlocks` and `FieldWithRichTextRequiredEditor` types have been removed in favor of just `Blocks` & `Fields`, as well as improved validation.
* moved refresh permissions test suite to access control
* support for custom Save, SaveDraft and Publish buttons in admin config for collections and globals
* moved navigation content to client side so that permissions can be refreshed from active state