Fixes#10529. The `req.locale` property within collection and global
access control functions does not reflect the current locale. This was
because we were attaching the locale to the req only _after_ running
`payload.auth`, which attempts to get access control without a
fully-formed req. The fix is to first authenticate the user using the
`executeAuthStrategies` operation directly, then determine the request
locale with that user, and finally get access results with the proper
locale.
Previously, this config:
```ts
import type { CollectionConfig } from 'payload'
export const tabSlug = 'tabs'
export const Tab: CollectionConfig = {
slug: tabSlug,
fields: [
{
type: 'tabs',
tabs: [
{
name: 'tabLocalized',
localized: true,
fields: [
{
name: 'title',
type: 'text',
},
{
name: 'array',
type: 'array',
fields: [
{
name: 'title',
type: 'text',
},
],
},
],
},
],
},
],
}
```
This call
```ts
const result = await payload.create({
collection: tabSlug,
locale: englishLocale,
data: {
tabLocalized: {},
},
})
```
Led to the following crash with the MongoDB adapter
<img width="741" alt="image"
src="https://github.com/user-attachments/assets/8d1d37de-a685-4a30-bd37-58af164108a2"
/>
This is due to how Mongoose, apparently just ignores the `minimize:
false` configuration
a83a430a3a/packages/db-mongodb/src/models/buildSchema.ts (L571)
and we, instead of `tabLocalized: { en: { } }` receive just
`tabLocalized: {}`.
This isn't an issue with group fields because we have fallback for them
a83a430a3a/packages/payload/src/fields/hooks/afterChange/promise.ts (L203)
This PR adds the same for tabs.
Editing fields during a locale change on slow networks can lead to
changes being reset when the new form state is returned. This is because
the fields receive new values from context when the new locale loads in,
which may have occurred _after_ changes were made to the fields. The fix
is to subscribe to a new `localeIsLoading` context which is set
immediately after changing locales, and then reset once the new locale
loads in. This also removes the misleading `@deprecated` flag from the
`useLocale` hook itself.
Currently, unless a locale is present in the URL search params, the
locale context is instantiated using the default locale until prefs load
in client-side. This causes the locale selector to briefly render in
with the incorrect (default) locale before being replaced by the proper
locale of the request. For example, if the default locale is `en`, and
the page is requested in `es`, the locale selector will flash with
English before changing to the correct locale, even though the page data
itself is properly loaded in Spanish. This is especially evident within
slow networks.
The fix is to query the user's locale preference server-side and thread
it into the locale provider to initialize state. Because search params
are not available within server layouts, we cannot pass the locale param
in the same way, so we rely on the provider itself to read them from the
`useSearchParams` hook. If present, this takes precedence over the
user's preference if it exists.
Since the root page also queries the user's locale preference to
determine the proper locale across navigation, we use React's cache
function to dedupe these function calls and ensure only a single query
is made to the db for each request.
The localization e2e test is notorious for flaking, consuming a lot of
time and resources continually retrying. This was because the test was
attempting to click DOM elements using selectors that never resolve, or
attempting to click inaccessible DOM nodes such as those behind a modal.
The fix is to ensure that the dot nav, for example, is disabled while
form state loads, and that modals are properly closed prior to executing
subsequent tests, etc. Tests also needed to explicitly check for
_enabled_ states before performing click actions, rather than simply
awaiting their visibility.
### What?
Adds ability to copy data from one locale to another at a document
level.
### How?
For any localized collection, you will find a new option in the document
controls called `Copy to Locale`.
This option will open a drawer, from here you can select your origin and
destination locales.
If data already exists in the destination locale, you can choose to:
1. Overwrite this data (this will copy any empty fields in your origin
locale)
2. Not overwrite existing data (this will only copy data into empty
fields in the destination locale)
---------
Co-authored-by: Jarrod Flesch <jarrodmflesch@gmail.com>
This PR fixes and improves a few things around localisation and
fallbackLocale:
- For the REST API `fallbackLocale` and `fallback-locale` are treated
the same for consistency with the Local API
- `fallback: false` in config is now respected, by default results will
not fallback to `defaultLocale` unless this config is true, can also be
overridden by providing an explicit `fallbackLocale` in the request
- locale specific fallbacks will now take priority over `defaultLocale`
unless an explicit fallback is provided
- Fixes types on operations to allow `'none'` as a value for
fallbackLocale
- `fallback` is now true by default if unspecified
Closes https://github.com/payloadcms/payload/issues/8443
Currently, Payload renders all custom components on initial compile of
the admin panel. This is problematic for two key reasons:
1. Custom components do not receive contextual data, i.e. fields do not
receive their field data, edit views do not receive their document data,
etc.
2. Components are unnecessarily rendered before they are used
This was initially required to support React Server Components within
the Payload Admin Panel for two key reasons:
1. Fields can be dynamically rendered within arrays, blocks, etc.
2. Documents can be recursively rendered within a "drawer" UI, i.e.
relationship fields
3. Payload supports server/client component composition
In order to achieve this, components need to be rendered on the server
and passed as "slots" to the client. Currently, the pattern for this is
to render custom server components in the "client config". Then when a
view or field is needed to be rendered, we first check the client config
for a "pre-rendered" component, otherwise render our client-side
fallback component.
But for the reasons listed above, this pattern doesn't exactly make
custom server components very useful within the Payload Admin Panel,
which is where this PR comes in. Now, instead of pre-rendering all
components on initial compile, we're able to render custom components
_on demand_, only as they are needed.
To achieve this, we've established [this
pattern](https://github.com/payloadcms/payload/pull/8481) of React
Server Functions in the Payload Admin Panel. With Server Functions, we
can iterate the Payload Config and return JSX through React's
`text/x-component` content-type. This means we're able to pass
contextual props to custom components, such as data for fields and
views.
## Breaking Changes
1. Add the following to your root layout file, typically located at
`(app)/(payload)/layout.tsx`:
```diff
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
+ import type { ServerFunctionClient } from 'payload'
import config from '@payload-config'
import { RootLayout } from '@payloadcms/next/layouts'
import { handleServerFunctions } from '@payloadcms/next/utilities'
import React from 'react'
import { importMap } from './admin/importMap.js'
import './custom.scss'
type Args = {
children: React.ReactNode
}
+ const serverFunctions: ServerFunctionClient = async function (args) {
+ 'use server'
+ return handleServerFunctions({
+ ...args,
+ config,
+ importMap,
+ })
+ }
const Layout = ({ children }: Args) => (
<RootLayout
config={config}
importMap={importMap}
+ serverFunctions={serverFunctions}
>
{children}
</RootLayout>
)
export default Layout
```
2. If you were previously posting to the `/api/form-state` endpoint, it
no longer exists. Instead, you'll need to invoke the `form-state` Server
Function, which can be done through the _new_ `getFormState` utility:
```diff
- import { getFormState } from '@payloadcms/ui'
- const { state } = await getFormState({
- apiRoute: '',
- body: {
- // ...
- },
- serverURL: ''
- })
+ const { getFormState } = useServerFunctions()
+
+ const { state } = await getFormState({
+ // ...
+ })
```
## Breaking Changes
```diff
- useFieldProps()
- useCellProps()
```
More details coming soon.
---------
Co-authored-by: Alessio Gravili <alessio@gravili.de>
Co-authored-by: Jarrod Flesch <jarrodmflesch@gmail.com>
Co-authored-by: James <james@trbl.design>
### What?
Fixes https://github.com/payloadcms/payload/issues/5152 issue related to
sorting by a localized field with SQLite / Postgres database adapters.
### Why?
It was an incorrect behaviour.
### How?
Modifies the `getTableColumnFromPath` file to have correct join
conditions. Previously if you had this structure in the _locales table
_locale title parent
en A 1
es B 1
we sorted by everything that's here, but we need to sort only by the
passed locale.
Additionally fixes a typescript error in `dev.ts` that I added here
https://github.com/payloadcms/payload/pull/8834
Also, removes the condition with `joins.length` in `countDistinct`. It
was there as for this issue
https://github.com/payloadcms/payload/issues/4889 because sorting by a
localized property caused duplication. This can simnifically improve
performance for `.find` with nested querying/sorting on large data sets,
because `count(*)` is faster than `count(DISTINCT id)`
fixes https://github.com/payloadcms/payload/issues/8455 and
https://github.com/payloadcms/payload/issues/8462
- Builds the `_locale` column for the `_rels` when it's inside of a
localized group / tab
- Properly builds `sanitizedPath` for blocks in the transform-read
function when it's inside of a localized field. This fixes with fields
inside that have its own table (like `_rels`, select `hasMany: true`
etc)
Adds _more_ tests!
Previously, this worked with MongoDB but failed with Postgres / SQLite
when the `slug` field has both `localized: true` and `unique: true`.
```ts
await payload.create({
collection: "posts",
locale: "en",
data: {
slug: "my-post"
}
})
await payload.create({
collection: "posts",
locale: "de",
data: {
slug: "my-post"
}
})
```
Now, we build unique constraints and indexes in combination with the
_locale column. This should also improve query performance for fields
with both index: true and localized: true.
### Migration steps (Postgres/SQLite only)
This change updates the database schema and requires a migration (if you
have any localized fields). To apply it, run the following commands:
```sh
pnpm payload migration:create locale_unique_indexes
pnpm payload migrate
```
Note that if you use `db.push: true` which is a default, you don't have
to run `pnpm payload migrate` in the development mode, only in the
production, as Payload automatically pushes the schema to your DB with
it.
Fixes a case where in relational DBs, you can't duplicate documents if
you have localized arrays within unnamed tabs.
The `beforeDuplicate` hooks were not being run for fields within unnamed
tabs.
Fixes an issue where duplicating documents in Postgres / SQLite would
crash because of a foreign key constraint / unique ID issue when you
have nested arrays / blocks within localized arrays / blocks.
We now run `beforeDuplicate` against all locales prior to
`beforeValidate` and `beforeChange` hooks.
This PR also fixes a series of issues in Postgres / SQLite where you
have localized groups / named tabs, and then arrays / blocks within the
localized groups / named tabs.
## Description
### TL;DR:
It's currently not possible to render our field components from a server
component because their `field` prop is the original field config, not
the _client_ config which our components require. Currently, the `field`
prop passed into custom fields changes type depending on whether it's a
server or client component, leaving server components without any access
to the client field config or mechanism to acquire it.
This PR passes the client config to all server field components through
a new `clientField` prop. This allows the following in a server
component, which is very similar to how client field components
currently work:
Server component:
```tsx
import { TextField } from '@payloadcms/ui'
import type { TextFieldServerComponent } from 'payload'
export const MyCustomServerField: TextFieldServerComponent = ({ clientField }) => {
return <TextField field={clientField} />
}
```
Client component:
```tsx
'use client'
import { TextField } from '@payloadcms/ui'
import type { TextFieldClientComponent } from 'payload'
export const MyCustomClientField: TextFieldClientComponent = ({ field }) => {
return <TextField field={field} />
}
```
### Full Background
If you have a custom field component, and it's a server component, there
is currently no way to pass the field prop into Payload's client-side
field components.
Here's an example of the problem:
```tsx
import { TextField } from '@payloadcms/ui'
import type { TextFieldServerComponent } from 'payload'
import React from 'react'
export const MyServerComponent: TextFieldServerComponent = (props) => {
const { field } = props
return (
<TextField field={field} /> // This is not possible
)
}
```
The config needs to be transformed into a client config, however,
because of the sheer number of hard-to-find arguments that the
`createClientField` requires, we cannot use it in its raw form.
Here is another example of the problem:
```tsx
import { TextField } from '@payloadcms/ui'
import { createClientField } from '@payloadcms/ui/utilities/createClientField'
import type { TextFieldServerComponent } from 'payload'
import React from 'react'
export const MyServerComponent: TextFieldServerComponent = ({ createClientField }) => {
const clientField = createClientField({...}) // Not a good option bc it requires many hard-to-find args
return (
<TextField field={clientField} />
)
}
```
Theoretically, we could preformat a `createFieldConfig` function so it
can simply be called without arguments:
```tsx
import { TextField } from '@payloadcms/ui'
import type { TextFieldServerComponent } from 'payload'
import React from 'react'
export const MyServerComponent: TextFieldServerComponent = ({ createClientField }) => {
return <TextField field={createClientField()} />
}
```
But this means the field config would be evaluated twice unnecessarily,
including label functions, etc.
The right way to fix this is to simply pass the client config to server
components through a new `clientField` prop:
```tsx
import { TextField } from '@payloadcms/ui'
import type { TextFieldServerComponent } from 'payload'
import React from 'react'
export const MyServerComponent: TextFieldServerComponent = ({ clientField }) => {
return <TextField field={clientField} />
}
```
- [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] Existing test suite passes locally with my changes
- [x] I have made corresponding changes to the documentation
## Description
Currently, you cannot create, delete, or duplicate documents within the
document drawer directly. To create a document within a relationship
field, for example, you must first navigate to the parent field and open
the "create new" drawer. Similarly (but worse), to duplicate or delete a
document, you must _navigate to the parent document to perform these
actions_ which is incredibly disruptive to the content editing workflow.
This becomes especially apparent within the relationship field where you
can edit documents inline, but cannot duplicate or delete them. This PR
supports all document-level actions within the document drawer so that
these actions can be performed on-the-fly without navigating away.
Inline duplication flow on a polymorphic "hasOne" relationship:
https://github.com/user-attachments/assets/bb80404a-079d-44a1-b9bc-14eb2ab49a46
Inline deletion flow on a polymorphic "hasOne" relationship:
https://github.com/user-attachments/assets/10f3587f-f70a-4cca-83ee-5dbcad32f063
- [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
## 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
In Postgres, localized blocks or arrays that contain other array / block
/ relationship fields were not properly storing locales in the database.
Now they are! Need to check a few things yet:
- Ensure test coverage is sufficient
- Test localized array, with non-localized array inside of it
- Test localized block with relationship field within it
- Ensure `_rels` table gets the `locale` column added if a single
non-localized relationship exists within a localized array / block
Fixes step 6 as identified in #7805
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>
## Description
V2 PR [here](https://github.com/payloadcms/payload/pull/6923)
- [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
**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
- Upgrades eslint from v8 to v9
- Upgrades all other eslint packages. We will have to do a new
full-project lint, as new rules have been added
- Upgrades husky from v8 to v9
- Upgrades lint-staged from v14 to v15
- Moves the old .eslintrc.cjs file format to the new eslint.config.js
flat file format.
Previously, we were very specific regarding which rules are applied to
which files. Now that `extends` is no longer a thing, I have to use
deepMerge & imports instead.
This is rather uncommon and is not a documented pattern - e.g.
typescript-eslint docs want us to add the default typescript-eslint
rules to the top-level & then disable it in files using the
disable-typechecked config.
However, I hate this opt-out approach. The way I did it here adds a lot
of clarity as to which rules are applied to which files, and is pretty
easy to read. Much less black magic
## .eslintignore
These files are no longer supported (see
https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files).
I moved the entries to the ignores property in the eslint config. => one
less file in each package folder!
# Breaking Changes
### New file import locations
Exports from the `payload` package have been _significantly_ cleaned up.
Now, just about everything is able to be imported from `payload`
directly, rather than an assortment of subpath exports. This means that
things like `import { buildConfig } from 'payload/config'` are now just
imported via `import { buildConfig } from 'payload'`. The mental model
is significantly simpler for developers, but you might need to update
some of your imports.
Payload now exposes only three exports:
1. `payload` - all types and server-only Payload code
2. `payload/shared` - utilities that can be used in either the browser
or in Node environments
3. `payload/node` - heavy utilities that should only be imported in Node
scripts and never be imported into bundled code like Next.js
### UI library pre-bundling
With this release, we've dramatically sped up the compile time for
Payload by pre-bundling our entire UI package for use inside of the
Payload admin itself. There are new exports that should be used within
Payload custom components:
1. `@payloadcms/ui/client` - all client components
2. `@payloadcms/ui/server` - all server components
For all of your custom Payload admin UI components, you should be
importing from one of these two pre-compiled barrel files rather than
importing from the more deeply nested exports directly. That will keep
compile times nice and speedy, and will also make sure that the bundled
JS for your admin UI is kept small.
For example, whereas before, if you imported the Payload `Button`, you
would have imported it like this:
```ts
import { Button } from '@payloadcms/ui/elements/Button'
```
Now, you would import it like this:
```ts
import { Button } from '@payloadcms/ui/client'
```
This is a significant DX / performance optimization that we're pretty
pumped about.
However, if you are importing or re-using Payload UI components
_outside_ of the Payload admin UI, for example in your own frontend
apps, you can import from the individual component exports which will
make sure that the bundled JS is kept to a minimum in your frontend
apps. So in your own frontend, you can continue to import directly to
the components that you want to consume rather than importing from the
pre-compiled barrel files.
Individual component exports will now come with their corresponding CSS
and everything will work perfectly as-expected.
### Specific exports have changed
- `'@payloadcms/ui/templates/Default'` and
`'@payloadcms/ui/templates/Minimal`' are now exported from
`'@payloadcms/next/templates'`
- Old: `import { LogOut } from '@payloadcms/ui/icons/LogOut'` new:
`import { LogOutIcon } from '@payloadcms/ui/icons/LogOut'`
## Background info
In effort to make local dev as fast as possible, we need to import as
few files as possible so that the compiler has less to process. One way
we've achieved this in the Admin Panel was to _remove_ all .scss imports
from all components in the `@payloadcms/ui` module using a build
process. This stripped all `import './index.scss'` statements out of
each component before injecting them into `dist`. Instead, it bundles
all of the CSS into a single `main.css` file, and we import _that_ at
the root of the app.
While this concept is _still_ the right solution to the problem, this
particular approach is not viable when using these components outside
the Admin Panel, where not only does this root stylesheet not exist, but
where it would also bloat your app with unused styles. Instead, we need
to _keep_ these .scss imports in place so they are imported directly
alongside your components, as expected. Then, we need create a _new_
build step that _separately_ compiles the components _without_ their
stylesheets—this way your app can consume either as needed from the new
`client` and `server` barrel files within `@payloadcms/ui`, i.e. from
within `@payloadcms/next` and all other admin-specific packages and
plugins.
This way, all other applications will simply import using the direct
file paths, just as they did before. Except now they come with
stylesheets.
And we've gotten a pretty awesome initial compilation performance boost.
---------
Co-authored-by: James <james@trbl.design>
Co-authored-by: Alessio Gravili <alessio@gravili.de>
**BREAKING:** We now export toast from `sonner` instead of
`react-toastify`. If you send out toasts from your own projects, make
sure to use our `toast` export, or install `sonner`. React-toastify
toasts will no longer work anymore. The Toast APIs are mostly similar,
but there are some differences if you provide options to your toast
CSS styles have been changed from Toastify
```css
/* before */
.Toastify
/* current */
.payload-toast-container
.payload-toast-item
.payload-toast-close-button
/* individual toast items will also have these classes depending on the state */
.toast-info
.toast-warning
.toast-success
.toast-error
```
https://github.com/payloadcms/payload/assets/70709113/da3e732e-aafc-4008-9469-b10f4eb06b35
---------
Co-authored-by: Paul Popus <paul@nouance.io>
Types are now auto-generated by default.
You can opt-out of this behavior by setting:
```ts
buildConfig({
// Rest of config
typescript: {
autoGenerate: false
},
})
```