Compare commits

..

26 Commits

Author SHA1 Message Date
Elliot DeNolf
6e61431ca1 chore(release): v3.0.0-beta.103 [skip ci] 2024-09-11 09:04:49 -04:00
Paul
663e5119b2 fix: useAsTitle validation now accounts for default and base fields (#8165) 2024-09-11 03:52:52 +00:00
Jacob Fletcher
8fe6ffd39b feat(examples): adds custom components example (#8162) 2024-09-10 22:48:52 -04:00
Sasha
0118bce582 fix(next): set the user data before redirect after login (#8135)
## Description

Fixes https://github.com/payloadcms/payload/issues/8134

- [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] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [x] Existing test suite passes locally with my changes
2024-09-10 19:04:42 +00:00
Jarrod Flesch
46707e4c5e chore: update lexical docs links 2024-09-10 14:11:11 -04:00
Sasha
a234092b34 fix: upload.defParamCharset: utf8 by default (#8157)
## Description

Fixes https://github.com/payloadcms/payload/issues/8107

This has been confusing for people from countries where characters
aren't latin, for example the Japanese file name:
フェニックス.png
Turns into:
 ãã§ããã¯ã¹.png  

Additionally, ensures type-safety for `DEFAULT_OPTIONS` and removes
unused `fileHandler` property from there, which isn't defined in the
`FetchAPIFileUploadOptions` type.

## Type of change

<!-- Please delete options that are not relevant. -->

- [x] Bug fix (non-breaking change which fixes an issue)
## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-09-10 17:40:44 +00:00
Germán Jabloñski
281c80d2c7 fix(richtext-lexical): hover style of the button to remove blocks (#8154)
## Description

Fix #8045

Before: hover with same color as background, as in the issue
description.

After (light):
![Screenshot 2024-09-10 at 9 36
21 AM](https://github.com/user-attachments/assets/260dbc69-a583-42f6-9b25-a81b8d8d4f70)

After (dark):
![Screenshot 2024-09-10 at 9 35
34 AM](https://github.com/user-attachments/assets/3606ee3c-24d6-43dd-8a0e-11d12e1fe779)


- [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
- [x] I have made corresponding changes to the documentation
2024-09-10 11:47:05 -03:00
Jacob Fletcher
12a30a0585 fix: extends server props onto field component types (#8155) 2024-09-10 10:42:22 -04:00
Sasha
0c563ebd73 fix(db-postgres): querying on array wtihin a relationship field (#8152)
## Description

Fixes https://github.com/payloadcms/payload/issues/6037

- [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] 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
2024-09-10 08:44:38 -04:00
Elliot DeNolf
df023a52fd chore(release): v3.0.0-beta.102 [skip ci] 2024-09-09 17:07:31 -04:00
Dan Ribbens
d267cad482 fix: beforeDuplicate localized blocks and arrays (#8144)
fixes #7988
2024-09-09 21:02:56 +00:00
Germán Jabloñski
fa38dfc16c fix(richtext-lexical): indent regression (#8138)
## Description

Fixes #8038, which was broken in #7817

I'm not entirely sure if this change violates the original intent of the
"base" utility, which from what I understand was introduced for
scalability reasons. Either way, I think it's a good idea to keep the
indent at 40px all the time.

The reason for this is that browsers use 40px as the indentation setting
for lists, and using that setting the indented paragraphs and headings
match the lists. See https://github.com/facebook/lexical/pull/4025

- [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
- [x] I have made corresponding changes to the documentation
2024-09-09 20:48:05 +00:00
Jacob Fletcher
8e1a5c8dba feat!: explicitly types field components (#8136)
## Description

Currently, there is no way of typing custom server field components.
This is because internally, all field components are client components,
and so these were never fully typed. For example, the docs currently
indicate for all custom fields to be typed in this way:

Old:
    
```tsx
export const MyClientTextFieldComponent: React.FC<TextFieldProps>
```

But if your component is a server component, you will never receive the
fully typed `field` prop, `payload` prop, etc. unless you've typed that
yourself using some of the underlying utilities. So to fix this, every
field now explicitly exports a type for each environment:

New:

- Client component:
    ```tsx
    'use client'
    export const MyClientTextFieldComponent: TextFieldClientComponent
    ```

- Server component:
    ```tsx
    export const MyServerTextFieldComponent: TextFieldServerComponent
    ```

This pattern applies to every field type, where the field name is
prepended onto the component type.

```ts
import type {
  TextFieldClientComponent,
  TextFieldServerComponent,
  TextFieldClientProps,
  TextFieldServerProps,
  TextareaFieldClientComponent,
  TextareaFieldServerComponent,
  TextareaFieldClientProps,
  TextareaFieldServerProps,
  // ...and so on for each field type
} from 'payload'
```

## BREAKING CHANGES

We are no longer exporting `TextFieldProps` etc. for each field type.
Instead, we now export props for each client/server environment
explicitly. If you were previously importing one of these types into
your custom component, simply change the import name to reflect your
environment.

Old:

```tsx
import type { TextFieldProps } from 'payload'
``` 

New:

```tsx
import type { TextFieldClientProps, TextFieldServerProps } from 'payload'
``` 

Related: #7754. 

- [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)
- [x] This change requires a documentation update

## Checklist:

- [x] Existing test suite passes locally with my changes
- [x] I have made corresponding changes to the documentation
2024-09-09 20:15:10 +00:00
Germán Jabloñski
67e1d6abc5 fix hover block remove button 2024-09-09 17:07:30 -03:00
Elliot DeNolf
a8c60c1c02 chore(release): v3.0.0-beta.101 [skip ci] 2024-09-09 16:04:45 -04:00
James Mikrut
d44fb2db37 fix: #6800, graphql parallel queries with different fallback locales (#8140)
## Description

Fixes #6800 where parallel GraphQL queries with different locales /
fallbackLocales do not return their data properly.
2024-09-09 16:01:58 -04:00
Dan Ribbens
852f9fc1fd fix!: multiple preferences for the same user and entry (#8100)
fixes #7762

This change mitigates having multiple preferences for one user but not
awaiting the change to a preference and reduces querying by skipping the
access control. In the event that a user has multiple preferences with
the same key, only the one with the latest updatedAt will be returned.

BREAKING CHANGES:
- payload/preferences/operations are no longer default exports

## Description

<!-- Please include a summary of the pull request and any related issues
it fixes. Please also include relevant motivation and context. -->

- [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. -->

- [ ] Chore (non-breaking change which does not add functionality)
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] Change to the
[templates](https://github.com/payloadcms/payload/tree/main/templates)
directory (does not affect core functionality)
- [ ] Change to the
[examples](https://github.com/payloadcms/payload/tree/main/examples)
directory (does not affect core functionality)
- [ ] This change requires a documentation update

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation

---------

Co-authored-by: Paul Popus <paul@nouance.io>
2024-09-09 14:00:51 -04:00
Dan Ribbens
e2d803800d fix: removes transactions wrapping auth strategies and login (#8137)
## Description

By default all api requests are creating transactions due to the
authentication stategy. This change removes transactions for auth and
login requests. This should only happen when the database needs to make
changes in which case the auth strategy or login lockout updates will
invoke their own transactions still.

This should improve performance without any sacrifice to database
consistency.

Fixes #8092 

- [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. -->

- [ ] Chore (non-breaking change which does not add functionality)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] Change to the
[templates](https://github.com/payloadcms/payload/tree/main/templates)
directory (does not affect core functionality)
- [ ] Change to the
[examples](https://github.com/payloadcms/payload/tree/main/examples)
directory (does not affect core functionality)
- [ ] This change requires a documentation update

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-09-09 13:27:21 -04:00
Germán Jabloñski
7fa68d17f5 fix(ui): wrong block indication when an error occurred (#7963) 2024-09-09 10:20:03 -04:00
Paul
9ec431a5bd fix(ui): bulk select checkbox being selected by default when in drawer (#8126) 2024-09-09 06:47:35 +00:00
Paul
cadf815ef6 fix(ui): thumbnails when serverURL config is provided (#8124) 2024-09-09 06:16:43 +00:00
Paul
638382e7fd feat: add validation for useAsTitle to throw an error if it's an invalid or nested field (#8122) 2024-09-08 18:53:12 -06:00
Elliot DeNolf
08fdbcacc0 chore: proper error log format (#8105)
Fix some error log formatting to use `{ msg, err }` properly
2024-09-07 02:48:59 +00:00
Paul
b27e42c484 fix(ui): various issues around documents lists, listQuery provider and search params (#8081)
This PR fixes and improves:
- ListQuery provider is now the source of truth for searchParams instead
of having components use the `useSearchParams` hook
- Various issues with search params and filters sticking around when
navigating between collections
- Pagination and limits not working inside DocumentDrawer
- Searching and filtering causing a flash of overlay in DocumentDrawer,
this now only shows for the first load and on slow networks
- Preferences are now respected in DocumentDrawer
- Changing the limit now resets your page back to 1 in case the current
page no longer exists

Fixes https://github.com/payloadcms/payload/issues/7085
Fixes https://github.com/payloadcms/payload/pull/8081
Fixes https://github.com/payloadcms/payload/issues/8086
2024-09-06 15:51:09 -06:00
Tylan Davis
32cc1a5761 fix(ui): missing thumbnail for non-image files in bulk upload sidebar (#8102)
## Description

Uses the `Thumbnail` component used in other places for the bulk upload
file rows. Closes #8099

In the future, we should consider adding different thumbnail icons based
on the `mimeType` to better describe the files being uploaded.

Before:
![Screenshot 2024-09-06 at 4 51
56 PM](https://github.com/user-attachments/assets/35cd528c-5086-465e-8d3c-7bb66d7c35da)


After:
![Screenshot 2024-09-06 at 4 50
12 PM](https://github.com/user-attachments/assets/54d2b98d-ac11-481e-abe5-4be071c3c8f2)


- [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:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-09-06 21:28:50 +00:00
Tylan Davis
38be69b7d3 fix(ui): better responsiveness for upload fields in sidebar (#8101)
## Description

Adjusts the styling for the Dropzone component for upload fields with
`admin.position: sidebar`.

Before:
![Screenshot 2024-09-06 at 4 10
28 PM](https://github.com/user-attachments/assets/221d43f9-f426-4a44-ba58-29123050c775)

After:
![Screenshot 2024-09-06 at 4 09
32 PM](https://github.com/user-attachments/assets/c4369a65-d842-4e65-9153-19244fcf5600)


- [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:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-09-06 20:37:38 +00:00
242 changed files with 10387 additions and 593 deletions

View File

@@ -783,7 +783,7 @@ Here are the breaking changes and how to migrate:
- New "Views" API added, which allows for custom sub-views on List and Edit views within Admin UI
- New [bundler adapter pattern](https://payloadcms.com/docs/admin/bundlers) released
- Official [Vite bundler](https://payloadcms.com/docs/admin/vite) released
- Offical [Lexical rich text adapter](https://payloadcms.com/docs/rich-text/lexical) released
- Offical [Lexical rich text adapter](https://payloadcms.com/docs/lexical/overview) released
- Lexical rich text editor now supports drag and drop of rich text elements
- Lexical rich text now supports Payload blocks directly within rich text editor
- Upload image cropping added

View File

@@ -431,14 +431,14 @@ export const MyClientComponent: React.FC = () => {
See [Using Hooks](#using-hooks) for more details.
</Banner>
All [Field Components](./fields) automatically receive their respective Client Field Config through a common [`field`](./fields#the-field-prop) prop:
All [Field Components](./fields) automatically receive their respective Field Config through a common [`field`](./fields#the-field-prop) prop:
```tsx
'use client'
import React from 'react'
import type { TextFieldProps } from 'payload'
import type { TextFieldClientComponent } from 'payload'
export const MyClientFieldComponent = ({ field: { name } }: TextFieldProps) => {
export const MyClientFieldComponent: TextFieldClientComponent = ({ field: { name } }) => {
return (
<p>
{`This field's name is ${name}`}

View File

@@ -136,7 +136,7 @@ All Field Components receive the following props:
| Property | Description |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`docPreferences`** | An object that contains the [Preferences](./preferences) for the document.
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
| **`field`** | The field's config. [More details](#the-field-prop) |
| **`locale`** | The locale of the field. [More details](../configuration/localization). |
| **`readOnly`** | A boolean value that represents if the field is read-only or not. |
| **`user`** | The currently authenticated user. [More details](../authentication/overview). |
@@ -175,46 +175,46 @@ export const CustomTextField: React.FC = () => {
#### TypeScript
When building Custom Field Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview). The convention is to append `Props` to the type of field, i.e. `TextFieldProps`.
When building Custom Field Components, you can import the component type to ensure type safety. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview) and for every client/server environment. The convention is to prepend the field type onto the target type, i.e. `TextFieldClientComponent`:
```tsx
import type {
ArrayFieldProps,
BlocksFieldProps,
CheckboxFieldProps,
CodeFieldProps,
CollapsibleFieldProps,
DateFieldProps,
EmailFieldProps,
GroupFieldProps,
HiddenFieldProps,
JSONFieldProps,
NumberFieldProps,
PointFieldProps,
RadioFieldProps,
RelationshipFieldProps,
RichTextFieldProps,
RowFieldProps,
SelectFieldProps,
TabsFieldProps,
TextFieldProps,
TextareaFieldProps,
UploadFieldProps
TextFieldClientComponent,
TextFieldServerComponent,
TextFieldClientProps,
TextFieldServerProps,
// ...and so on for each Field Type
} from 'payload'
```
### The `field` Prop
All Field Components are passed a client-friendly version of their Field Config through a common `field` prop. Since the raw Field Config is [non-serializable](https://react.dev/reference/rsc/use-client#serializable-types), Payload sanitized it into a [Client Config](./components#accessing-the-payload-config) that is safe to pass into Client Components.
All Field Components are passed their own Field Config through a common `field` prop. Within a Server Component, this is the raw Field Config. Within Client Components, however, the raw Field Config is [non-serializable](https://react.dev/reference/rsc/use-client#serializable-types). Instead, Client Components receives a [Client Config](./components#accessing-the-payload-config), which is a sanitizes version of the Field Config that is safe to pass into Client Components.
The exact shape of this prop is unique to the specific [Field Type](../fields/overview) being rendered, minus all non-serializable properties. Any [Custom Components](../components) are also resolved into a "mapped component" that is safe to pass.
```tsx
import React from 'react'
import type { TextFieldServerComponent } from 'payload'
export const MyServerTextField: TextFieldServerComponent = ({ payload, field: { name } }) => {
const result = await payload.find({
collection: 'myCollection',
depth: 1,
})
// ...
}
```
Client Component:
```tsx
'use client'
import React from 'react'
import type { TextFieldProps } from 'payload'
import type { TextFieldClientComponent } from 'payload'
export const MyClientFieldComponent: React.FC<TextFieldProps> = ({ field: { name } }) => {
export const MyClientTextField: TextFieldClientComponent = ({ field: { name } }) => {
return (
<p>
{`This field's name is ${name}`}
@@ -238,40 +238,18 @@ The following additional properties are also provided to the `field` prop:
#### TypeScript
When building Custom Field Components, you can import the client field props to ensure type safety in your component. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview). The convention is to append `Client` to the type of field, i.e. `TextFieldClient`.
When building Custom Field Components, you can import the client field props to ensure type safety in your component. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to prepend the field type onto the target type, i.e. `TextFieldClientComponent`:
```tsx
import type {
ArrayFieldClient,
BlocksFieldClient,
CheckboxFieldClient,
CodeFieldClient,
CollapsibleFieldClient,
DateFieldClient,
EmailFieldClient,
GroupFieldClient,
HiddenFieldClient,
JSONFieldClient,
NumberFieldClient,
PointFieldClient,
RadioFieldClient,
RelationshipFieldClient,
RichTextFieldClient,
RowFieldClient,
SelectFieldClient,
TabsFieldClient,
TextFieldClient,
TextareaFieldClient,
UploadFieldClient
TextFieldClientComponent,
TextFieldServerComponent,
TextFieldClientProps,
TextFieldServerProps,
// ...and so on for each Field Type
} from 'payload'
```
When working on the client, you will never have access to objects of type `Field`. This is reserved for the server-side. Instead, you can use `ClientField` which is a union type of all the client fields:
```tsx
import type { ClientField } from 'payload'
```
### The Cell Component
The Cell Component is rendered in the table of the List View. It represents the value of the field when displayed in a table cell.
@@ -353,7 +331,7 @@ When building Custom Label Components, you can import the component props to ens
import type {
TextFieldLabelServerComponent,
TextFieldLabelClientComponent,
// And so on for each Field Type
// ...and so on for each Field Type
} from 'payload'
```

View File

@@ -31,8 +31,9 @@ const config = buildConfig({
admin: {
components: {
views: {
dashboard: {
Component: '/path/to/MyCustomDashboardView#MyCustomDashboardViewComponent', // highlight-line
customView: {
Component: '/path/to/MyCustomView#MyCustomView', // highlight-line
path: '/my-custom-view',
}
},
},
@@ -40,7 +41,42 @@ const config = buildConfig({
})
```
_For details on how to build Custom Views, see [Building Custom Views](#building-custom-views)._
Your Custom Root Views can optionally use one of the templates that Payload provides. The most common of these is the Default Template which provides the basic layout and navigation. Here is an example of what that might look like:
```tsx
import type { AdminViewProps } from 'payload'
import { DefaultTemplate } from '@payloadcms/next/templates'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export const MyCustomView: React.FC<AdminViewProps> = ({
initPageResult,
params,
searchParams,
}) => {
return (
<DefaultTemplate
i18n={initPageResult.req.i18n}
locale={initPageResult.locale}
params={params}
payload={initPageResult.req.payload}
permissions={initPageResult.permissions}
searchParams={searchParams}
user={initPageResult.req.user || undefined}
visibleEntities={initPageResult.visibleEntities}
>
<Gutter>
<h1>Custom Default Root View</h1>
<br />
<p>This view uses the Default Template.</p>
</Gutter>
</DefaultTemplate>
)
}
```
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
The following options are available:
@@ -133,7 +169,7 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
}
```
_For details on how to build Custom Views, see [Building Custom Views](#building-custom-views)._
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
<Banner type="warning">
<strong>Note:</strong>
@@ -184,7 +220,7 @@ export const MyGlobalConfig: SanitizedGlobalConfig = {
}
```
_For details on how to build Custom Views, see [Building Custom Views](#building-custom-views)._
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
<Banner type="warning">
<strong>Note:</strong>
@@ -227,7 +263,7 @@ export const MyCollectionOrGlobalConfig: SanitizedCollectionConfig = {
}
```
_For details on how to build Custom Views, see [Building Custom Views](#building-custom-views)._
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
<Banner type="warning">
<strong>Note:</strong>
@@ -312,13 +348,11 @@ Your Custom Views will be provided with the following props:
| Prop | Description |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **`user`** | The currently logged in user. |
| **`locale`** | The current [Locale](../configuration/localization) of the [Admin Panel](./overview). |
| **`navGroups`** | The grouped navigation items according to `admin.group` in your [Collection Config](../collections/overview) or [Global Config](../globals/overview). |
| **`params`** | An object containing the [Dynamic Route Parameters](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes). |
| **`permissions`** | The permissions of the currently logged in user. |
| **`searchParams`** | An object containing the [Search Parameters](https://developer.mozilla.org/docs/Learn/Common_questions/What_is_a_URL#parameters). |
| **`visibleEntities`** | The current user's visible entities according to your [Access Control](../access-control/overview). |
| **`initPageResult`** | An object containing `req`, `payload`, `permissions`, etc. |
| **`clientConfig`** | The Client Config object. [More details](../components#accessing-the-payload-config). |
| **`importMap`** | The import map object. |
| **`params`** | An object containing the [Dynamic Route Parameters](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes). |
| **`searchParams`** | An object containing the [Search Parameters](https://developer.mozilla.org/docs/Learn/Common_questions/What_is_a_URL#parameters). |
<Banner type="success">
<strong>Reminder:</strong>

View File

@@ -11,6 +11,7 @@ Payload provides a vast array of examples to help you get started with your proj
Examples are changing every day, so be sure to check back often to see what new examples have been added. If you have a specific example you would like to see, please feel free to start a new [Discussion](https://github.com/payloadcms/payload/discussions) or open a new [PR](https://github.com/payloadcms/payload/pulls) to add it yourself.
- [Auth](https://github.com/payloadcms/payload/tree/main/examples/auth)
- [Custom Components](https://github.com/payloadcms/payload/tree/main/examples/custom-components)
- [Custom Server](https://github.com/payloadcms/payload/tree/main/examples/custom-server)
- [Draft Preview](https://github.com/payloadcms/payload/tree/main/examples/draft-preview)
- [Email](https://github.com/payloadcms/payload/tree/main/examples/email)

View File

@@ -20,7 +20,7 @@ Payload's rich text field is built on an "adapter pattern" which lets you specif
Right now, Payload is officially supporting two rich text editors:
1. [SlateJS](/docs/rich-text/slate) - stable, backwards-compatible with 1.0
2. [Lexical](/docs/rich-text/lexical) - beta, where things will be moving
2. [Lexical](/docs/lexical/overview) - beta, where things will be moving
<Banner type="success">
<strong>
@@ -82,4 +82,4 @@ The Rich Text Field inherits all of the default options from the base [Field Adm
## Editor-specific Options
For a ton more editor-specific options, including how to build custom rich text elements directly into your editor, take a look at either the [Slate docs](/docs/rich-text/slate) or the [Lexical docs](/docs/rich-text/lexical) depending on which editor you're using.
For a ton more editor-specific options, including how to build custom rich text elements directly into your editor, take a look at either the [Slate docs](/docs/rich-text/slate) or the [Lexical docs](/docs/lexical/overview) depending on which editor you're using.

View File

@@ -0,0 +1,3 @@
DATABASE_URI=mongodb://127.0.0.1/payload-example-custom-fields
PAYLOAD_SECRET=PAYLOAD_CUSTOM_FIELDS_EXAMPLE_SECRET_KEY
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000

View File

@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['@payloadcms'],
}

5
examples/custom-components/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
build
dist
node_modules
package-lock.json
.env

View File

@@ -0,0 +1,24 @@
{
"$schema": "https://json.schemastore.org/swcrc",
"sourceMaps": true,
"jsc": {
"target": "esnext",
"parser": {
"syntax": "typescript",
"tsx": true,
"dts": true
},
"transform": {
"react": {
"runtime": "automatic",
"pragmaFrag": "React.Fragment",
"throwIfNamespace": true,
"development": false,
"useBuiltins": true
}
}
},
"module": {
"type": "es6"
}
}

View File

@@ -0,0 +1,46 @@
# Payload Custom Components Example
This example demonstrates how to use Custom Components in [Payload](https://github.com/payloadcms/payload) Admin Panel. This example includes custom components for every field type available in Payload, including both server and client components. It also includes custom views, custom nav links, and more.
## Quick Start
To spin up this example locally, follow these steps:
1. Clone this repo
1. `cd` into this directory and run `pnpm i --ignore-workspace`\*, `yarn`, or `npm install`
> \*If you are running using pnpm within the Payload Monorepo, the `--ignore-workspace` flag is needed so that pnpm generates a lockfile in this example's directory despite the fact that one exists in root.
1. `pnpm dev`, `yarn dev` or `npm run dev` to start the server
- Press `y` when prompted to seed the database
1. `open http://localhost:3000` to access the home page
1. `open http://localhost:3000/admin` to access the admin panel
- Login with email `demo@payloadcms.com` and password `demo`
## How it works
### Collections
See the [Collections](https://payloadcms.com/docs/configuration/collections) docs for details on how to extend any of this functionality.
- #### Users
The `users` collection is auth-enabled which provides access to the admin panel.
For additional help with authentication, see the official [Auth Example](https://github.com/payloadcms/payload/tree/main/examples/auth/cms#readme) or the [Authentication](https://payloadcms.com/docs/authentication/overview#authentication-overview) docs.
- #### Fields
The `fields` collection contains every field type available in Payload, each with custom components filled in every available "slot", i.e. `admin.components.Field`, `admin.components.Label`, etc. There are two of every field, one for server components, and the other for client components. This pattern shows how to use custom components in both environments, no matter which field type you are using.
- #### Views
The `views` collection demonstrates how to add collection-level views, including the default view and custom tabs.
- #### Root Views
The `root-views` collection demonstrates how to add a root document-level view to the admin panel.
## Questions
If you have any issues or questions, reach out to us on [Discord](https://discord.com/invite/payload) or start a [GitHub discussion](https://github.com/payloadcms/payload/discussions).

View File

@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@@ -0,0 +1,8 @@
import { withPayload } from '@payloadcms/next/withPayload'
/** @type {import('next').NextConfig} */
const nextConfig = {
// Your Next.js config here
}
export default withPayload(nextConfig)

View File

@@ -0,0 +1,43 @@
{
"name": "payload-example-custom-fields",
"version": "1.0.0",
"description": "An example of custom fields in Payload.",
"license": "MIT",
"type": "module",
"scripts": {
"_dev": "cross-env NODE_OPTIONS=--no-deprecation && pnpm generate:importmap && next dev",
"build": "cross-env NODE_OPTIONS=--no-deprecation next build",
"dev": "cross-env NODE_OPTIONS=--no-deprecation && pnpm generate:importmap && pnpm seed && next dev --turbo",
"generate:importmap": "payload generate:importmap",
"generate:schema": "payload-graphql generate:schema",
"generate:types": "payload generate:types",
"payload": "cross-env NODE_OPTIONS=--no-deprecation payload",
"seed": "npm run payload migrate:fresh",
"start": "cross-env NODE_OPTIONS=--no-deprecation next start"
},
"dependencies": {
"@payloadcms/db-mongodb": "3.0.0-beta.102",
"@payloadcms/next": "3.0.0-beta.102",
"@payloadcms/richtext-lexical": "3.0.0-beta.102",
"@payloadcms/ui": "3.0.0-beta.102",
"cross-env": "^7.0.3",
"dotenv": "^8.2.0",
"graphql": "^16.9.0",
"next": "15.0.0-canary.104",
"payload": "3.0.0-beta.102",
"react": "19.0.0-rc-06d0b89e-20240801",
"react-dom": "19.0.0-rc-06d0b89e-20240801"
},
"devDependencies": {
"@payloadcms/graphql": "3.0.0-beta.102",
"@types/react": "npm:types-react@19.0.0-beta.2",
"@types/react-dom": "npm:types-react-dom@19.0.0-beta.2",
"eslint": "^8.57.0",
"eslint-config-next": "15.0.0-canary.146",
"tsx": "^4.7.1",
"typescript": "5.5.2"
},
"engines": {
"node": "^18.20.2 || >=20.9.0"
}
}

6848
examples/custom-components/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
import type { Metadata } from 'next'
import config from '@payload-config'
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import { generatePageMetadata, NotFoundPage } from '@payloadcms/next/views'
import { importMap } from '../importMap.js'
type Args = {
params: {
segments: string[]
}
searchParams: {
[key: string]: string | string[]
}
}
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
generatePageMetadata({ config, params, searchParams })
const NotFound = ({ params, searchParams }: Args) =>
NotFoundPage({ config, importMap, params, searchParams })
export default NotFound

View File

@@ -0,0 +1,25 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
import type { Metadata } from 'next'
import config from '@payload-config'
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import { generatePageMetadata, RootPage } from '@payloadcms/next/views'
import { importMap } from '../importMap.js'
type Args = {
params: {
segments: string[]
}
searchParams: {
[key: string]: string | string[]
}
}
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
generatePageMetadata({ config, params, searchParams })
const Page = ({ params, searchParams }: Args) =>
RootPage({ config, importMap, params, searchParams })
export default Page

View File

@@ -0,0 +1,162 @@
import { CustomArrayFieldLabelServer as CustomArrayFieldLabelServer_0 } from '@/collections/Fields/array/components/server/Label'
import { CustomArrayFieldServer as CustomArrayFieldServer_1 } from '@/collections/Fields/array/components/server/Field'
import { CustomArrayFieldLabelClient as CustomArrayFieldLabelClient_2 } from '@/collections/Fields/array/components/client/Label'
import { CustomArrayFieldClient as CustomArrayFieldClient_3 } from '@/collections/Fields/array/components/client/Field'
import { CustomBlocksFieldServer as CustomBlocksFieldServer_4 } from '@/collections/Fields/blocks/components/server/Field'
import { CustomBlocksFieldClient as CustomBlocksFieldClient_5 } from '@/collections/Fields/blocks/components/client/Field'
import { CustomCheckboxFieldLabelServer as CustomCheckboxFieldLabelServer_6 } from '@/collections/Fields/checkbox/components/server/Label'
import { CustomCheckboxFieldServer as CustomCheckboxFieldServer_7 } from '@/collections/Fields/checkbox/components/server/Field'
import { CustomCheckboxFieldLabelClient as CustomCheckboxFieldLabelClient_8 } from '@/collections/Fields/checkbox/components/client/Label'
import { CustomCheckboxFieldClient as CustomCheckboxFieldClient_9 } from '@/collections/Fields/checkbox/components/client/Field'
import { CustomDateFieldLabelServer as CustomDateFieldLabelServer_10 } from '@/collections/Fields/date/components/server/Label'
import { CustomDateFieldServer as CustomDateFieldServer_11 } from '@/collections/Fields/date/components/server/Field'
import { CustomDateFieldLabelClient as CustomDateFieldLabelClient_12 } from '@/collections/Fields/date/components/client/Label'
import { CustomDateFieldClient as CustomDateFieldClient_13 } from '@/collections/Fields/date/components/client/Field'
import { CustomEmailFieldLabelServer as CustomEmailFieldLabelServer_14 } from '@/collections/Fields/email/components/server/Label'
import { CustomEmailFieldServer as CustomEmailFieldServer_15 } from '@/collections/Fields/email/components/server/Field'
import { CustomEmailFieldLabelClient as CustomEmailFieldLabelClient_16 } from '@/collections/Fields/email/components/client/Label'
import { CustomEmailFieldClient as CustomEmailFieldClient_17 } from '@/collections/Fields/email/components/client/Field'
import { CustomNumberFieldLabelServer as CustomNumberFieldLabelServer_18 } from '@/collections/Fields/number/components/server/Label'
import { CustomNumberFieldServer as CustomNumberFieldServer_19 } from '@/collections/Fields/number/components/server/Field'
import { CustomNumberFieldLabelClient as CustomNumberFieldLabelClient_20 } from '@/collections/Fields/number/components/client/Label'
import { CustomNumberFieldClient as CustomNumberFieldClient_21 } from '@/collections/Fields/number/components/client/Field'
import { CustomPointFieldLabelServer as CustomPointFieldLabelServer_22 } from '@/collections/Fields/point/components/server/Label'
import { CustomPointFieldServer as CustomPointFieldServer_23 } from '@/collections/Fields/point/components/server/Field'
import { CustomPointFieldLabelClient as CustomPointFieldLabelClient_24 } from '@/collections/Fields/point/components/client/Label'
import { CustomPointFieldClient as CustomPointFieldClient_25 } from '@/collections/Fields/point/components/client/Field'
import { CustomRadioFieldLabelServer as CustomRadioFieldLabelServer_26 } from '@/collections/Fields/radio/components/server/Label'
import { CustomRadioFieldServer as CustomRadioFieldServer_27 } from '@/collections/Fields/radio/components/server/Field'
import { CustomRadioFieldLabelClient as CustomRadioFieldLabelClient_28 } from '@/collections/Fields/radio/components/client/Label'
import { CustomRadioFieldClient as CustomRadioFieldClient_29 } from '@/collections/Fields/radio/components/client/Field'
import { CustomRelationshipFieldLabelServer as CustomRelationshipFieldLabelServer_30 } from '@/collections/Fields/relationship/components/server/Label'
import { CustomRelationshipFieldServer as CustomRelationshipFieldServer_31 } from '@/collections/Fields/relationship/components/server/Field'
import { CustomRelationshipFieldLabelClient as CustomRelationshipFieldLabelClient_32 } from '@/collections/Fields/relationship/components/client/Label'
import { CustomRelationshipFieldClient as CustomRelationshipFieldClient_33 } from '@/collections/Fields/relationship/components/client/Field'
import { CustomSelectFieldLabelServer as CustomSelectFieldLabelServer_34 } from '@/collections/Fields/select/components/server/Label'
import { CustomSelectFieldServer as CustomSelectFieldServer_35 } from '@/collections/Fields/select/components/server/Field'
import { CustomSelectFieldLabelClient as CustomSelectFieldLabelClient_36 } from '@/collections/Fields/select/components/client/Label'
import { CustomSelectFieldClient as CustomSelectFieldClient_37 } from '@/collections/Fields/select/components/client/Field'
import { CustomTextFieldLabelServer as CustomTextFieldLabelServer_38 } from '@/collections/Fields/text/components/server/Label'
import { CustomTextFieldServer as CustomTextFieldServer_39 } from '@/collections/Fields/text/components/server/Field'
import { CustomTextFieldLabelClient as CustomTextFieldLabelClient_40 } from '@/collections/Fields/text/components/client/Label'
import { CustomTextFieldClient as CustomTextFieldClient_41 } from '@/collections/Fields/text/components/client/Field'
import { CustomTextareaFieldLabelServer as CustomTextareaFieldLabelServer_42 } from '@/collections/Fields/textarea/components/server/Label'
import { CustomTextareaFieldServer as CustomTextareaFieldServer_43 } from '@/collections/Fields/textarea/components/server/Field'
import { CustomTextareaFieldLabelClient as CustomTextareaFieldLabelClient_44 } from '@/collections/Fields/textarea/components/client/Label'
import { CustomTextareaFieldClient as CustomTextareaFieldClient_45 } from '@/collections/Fields/textarea/components/client/Field'
import { CustomTabEditView as CustomTabEditView_46 } from '@/collections/Views/components/CustomTabEditView'
import { CustomDefaultEditView as CustomDefaultEditView_47 } from '@/collections/Views/components/CustomDefaultEditView'
import { CustomRootEditView as CustomRootEditView_48 } from '@/collections/RootViews/components/CustomRootEditView'
import { LinkToCustomView as LinkToCustomView_49 } from '@/components/afterNavLinks/LinkToCustomView'
import { LinkToCustomMinimalView as LinkToCustomMinimalView_50 } from '@/components/afterNavLinks/LinkToCustomMinimalView'
import { LinkToCustomDefaultView as LinkToCustomDefaultView_51 } from '@/components/afterNavLinks/LinkToCustomDefaultView'
import { CustomRootView as CustomRootView_52 } from '@/components/views/CustomRootView'
import { CustomDefaultRootView as CustomDefaultRootView_53 } from '@/components/views/CustomDefaultRootView'
import { CustomMinimalRootView as CustomMinimalRootView_54 } from '@/components/views/CustomMinimalRootView'
export const importMap = {
'@/collections/Fields/array/components/server/Label#CustomArrayFieldLabelServer':
CustomArrayFieldLabelServer_0,
'@/collections/Fields/array/components/server/Field#CustomArrayFieldServer':
CustomArrayFieldServer_1,
'@/collections/Fields/array/components/client/Label#CustomArrayFieldLabelClient':
CustomArrayFieldLabelClient_2,
'@/collections/Fields/array/components/client/Field#CustomArrayFieldClient':
CustomArrayFieldClient_3,
'@/collections/Fields/blocks/components/server/Field#CustomBlocksFieldServer':
CustomBlocksFieldServer_4,
'@/collections/Fields/blocks/components/client/Field#CustomBlocksFieldClient':
CustomBlocksFieldClient_5,
'@/collections/Fields/checkbox/components/server/Label#CustomCheckboxFieldLabelServer':
CustomCheckboxFieldLabelServer_6,
'@/collections/Fields/checkbox/components/server/Field#CustomCheckboxFieldServer':
CustomCheckboxFieldServer_7,
'@/collections/Fields/checkbox/components/client/Label#CustomCheckboxFieldLabelClient':
CustomCheckboxFieldLabelClient_8,
'@/collections/Fields/checkbox/components/client/Field#CustomCheckboxFieldClient':
CustomCheckboxFieldClient_9,
'@/collections/Fields/date/components/server/Label#CustomDateFieldLabelServer':
CustomDateFieldLabelServer_10,
'@/collections/Fields/date/components/server/Field#CustomDateFieldServer':
CustomDateFieldServer_11,
'@/collections/Fields/date/components/client/Label#CustomDateFieldLabelClient':
CustomDateFieldLabelClient_12,
'@/collections/Fields/date/components/client/Field#CustomDateFieldClient':
CustomDateFieldClient_13,
'@/collections/Fields/email/components/server/Label#CustomEmailFieldLabelServer':
CustomEmailFieldLabelServer_14,
'@/collections/Fields/email/components/server/Field#CustomEmailFieldServer':
CustomEmailFieldServer_15,
'@/collections/Fields/email/components/client/Label#CustomEmailFieldLabelClient':
CustomEmailFieldLabelClient_16,
'@/collections/Fields/email/components/client/Field#CustomEmailFieldClient':
CustomEmailFieldClient_17,
'@/collections/Fields/number/components/server/Label#CustomNumberFieldLabelServer':
CustomNumberFieldLabelServer_18,
'@/collections/Fields/number/components/server/Field#CustomNumberFieldServer':
CustomNumberFieldServer_19,
'@/collections/Fields/number/components/client/Label#CustomNumberFieldLabelClient':
CustomNumberFieldLabelClient_20,
'@/collections/Fields/number/components/client/Field#CustomNumberFieldClient':
CustomNumberFieldClient_21,
'@/collections/Fields/point/components/server/Label#CustomPointFieldLabelServer':
CustomPointFieldLabelServer_22,
'@/collections/Fields/point/components/server/Field#CustomPointFieldServer':
CustomPointFieldServer_23,
'@/collections/Fields/point/components/client/Label#CustomPointFieldLabelClient':
CustomPointFieldLabelClient_24,
'@/collections/Fields/point/components/client/Field#CustomPointFieldClient':
CustomPointFieldClient_25,
'@/collections/Fields/radio/components/server/Label#CustomRadioFieldLabelServer':
CustomRadioFieldLabelServer_26,
'@/collections/Fields/radio/components/server/Field#CustomRadioFieldServer':
CustomRadioFieldServer_27,
'@/collections/Fields/radio/components/client/Label#CustomRadioFieldLabelClient':
CustomRadioFieldLabelClient_28,
'@/collections/Fields/radio/components/client/Field#CustomRadioFieldClient':
CustomRadioFieldClient_29,
'@/collections/Fields/relationship/components/server/Label#CustomRelationshipFieldLabelServer':
CustomRelationshipFieldLabelServer_30,
'@/collections/Fields/relationship/components/server/Field#CustomRelationshipFieldServer':
CustomRelationshipFieldServer_31,
'@/collections/Fields/relationship/components/client/Label#CustomRelationshipFieldLabelClient':
CustomRelationshipFieldLabelClient_32,
'@/collections/Fields/relationship/components/client/Field#CustomRelationshipFieldClient':
CustomRelationshipFieldClient_33,
'@/collections/Fields/select/components/server/Label#CustomSelectFieldLabelServer':
CustomSelectFieldLabelServer_34,
'@/collections/Fields/select/components/server/Field#CustomSelectFieldServer':
CustomSelectFieldServer_35,
'@/collections/Fields/select/components/client/Label#CustomSelectFieldLabelClient':
CustomSelectFieldLabelClient_36,
'@/collections/Fields/select/components/client/Field#CustomSelectFieldClient':
CustomSelectFieldClient_37,
'@/collections/Fields/text/components/server/Label#CustomTextFieldLabelServer':
CustomTextFieldLabelServer_38,
'@/collections/Fields/text/components/server/Field#CustomTextFieldServer':
CustomTextFieldServer_39,
'@/collections/Fields/text/components/client/Label#CustomTextFieldLabelClient':
CustomTextFieldLabelClient_40,
'@/collections/Fields/text/components/client/Field#CustomTextFieldClient':
CustomTextFieldClient_41,
'@/collections/Fields/textarea/components/server/Label#CustomTextareaFieldLabelServer':
CustomTextareaFieldLabelServer_42,
'@/collections/Fields/textarea/components/server/Field#CustomTextareaFieldServer':
CustomTextareaFieldServer_43,
'@/collections/Fields/textarea/components/client/Label#CustomTextareaFieldLabelClient':
CustomTextareaFieldLabelClient_44,
'@/collections/Fields/textarea/components/client/Field#CustomTextareaFieldClient':
CustomTextareaFieldClient_45,
'@/collections/Views/components/CustomTabEditView#CustomTabEditView': CustomTabEditView_46,
'@/collections/Views/components/CustomDefaultEditView#CustomDefaultEditView':
CustomDefaultEditView_47,
'@/collections/RootViews/components/CustomRootEditView#CustomRootEditView': CustomRootEditView_48,
'@/components/afterNavLinks/LinkToCustomView#LinkToCustomView': LinkToCustomView_49,
'@/components/afterNavLinks/LinkToCustomMinimalView#LinkToCustomMinimalView':
LinkToCustomMinimalView_50,
'@/components/afterNavLinks/LinkToCustomDefaultView#LinkToCustomDefaultView':
LinkToCustomDefaultView_51,
'@/components/views/CustomRootView#CustomRootView': CustomRootView_52,
'@/components/views/CustomDefaultRootView#CustomDefaultRootView': CustomDefaultRootView_53,
'@/components/views/CustomMinimalRootView#CustomMinimalRootView': CustomMinimalRootView_54,
}

View File

@@ -0,0 +1,10 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
import config from '@payload-config'
import { REST_DELETE, REST_GET, REST_OPTIONS, REST_PATCH, REST_POST } from '@payloadcms/next/routes'
export const GET = REST_GET(config)
export const POST = REST_POST(config)
export const DELETE = REST_DELETE(config)
export const PATCH = REST_PATCH(config)
export const OPTIONS = REST_OPTIONS(config)

View File

@@ -0,0 +1,6 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
import config from '@payload-config'
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes'
export const GET = GRAPHQL_PLAYGROUND_GET(config)

View File

@@ -0,0 +1,6 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
import config from '@payload-config'
import { GRAPHQL_POST } from '@payloadcms/next/routes'
export const POST = GRAPHQL_POST(config)

View File

@@ -0,0 +1,21 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
import configPromise from '@payload-config'
import '@payloadcms/next/css'
import { RootLayout } from '@payloadcms/next/layouts'
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import React from 'react'
import { importMap } from './admin/importMap.js'
import './custom.scss'
type Args = {
children: React.ReactNode
}
const Layout = ({ children }: Args) => (
<RootLayout config={configPromise} importMap={importMap}>
{children}
</RootLayout>
)
export default Layout

View File

@@ -0,0 +1,11 @@
'use client'
import type { TextFieldClientComponent } from 'payload'
import { TextField } from '@payloadcms/ui'
import React from 'react'
export const CustomTextFieldClient: TextFieldClientComponent = (props) => {
const { field } = props
return <TextField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { TextFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomTextFieldLabelClient: TextFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { TextFieldServerComponent } from 'payload'
// import { TextField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomTextFieldServer: TextFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <TextField field={clientField} />
return 'This is a server component for the text field.'
}

View File

@@ -0,0 +1,12 @@
import type { TextFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomTextFieldLabelServer: TextFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the text field label.'
}

View File

@@ -0,0 +1,24 @@
import type { CollectionConfig } from 'payload'
export const textFields: CollectionConfig['fields'] = [
{
name: 'textFieldServerComponent',
type: 'text',
admin: {
components: {
Field: '@/collections/Fields/text/components/server/Field#CustomTextFieldServer',
Label: '@/collections/Fields/text/components/server/Label#CustomTextFieldLabelServer',
},
},
},
{
name: 'textFieldClientComponent',
type: 'text',
admin: {
components: {
Field: '@/collections/Fields/text/components/client/Field#CustomTextFieldClient',
Label: '@/collections/Fields/text/components/client/Label#CustomTextFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { TextareaFieldClientComponent } from 'payload'
import { TextareaField } from '@payloadcms/ui'
import React from 'react'
export const CustomTextareaFieldClient: TextareaFieldClientComponent = (props) => {
const { field } = props
return <TextareaField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { TextareaFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomTextareaFieldLabelClient: TextareaFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { TextareaFieldServerComponent } from 'payload'
// import { TextareaField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomTextareaFieldServer: TextareaFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <TextareaField field={clientField} />
return 'This is a server component for the textarea field.'
}

View File

@@ -0,0 +1,12 @@
import type { TextareaFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomTextareaFieldLabelServer: TextareaFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the textarea field label.'
}

View File

@@ -0,0 +1,26 @@
import type { CollectionConfig } from 'payload'
export const textareaFields: CollectionConfig['fields'] = [
{
name: 'textareaFieldServerComponent',
type: 'textarea',
admin: {
components: {
Field: '@/collections/Fields/textarea/components/server/Field#CustomTextareaFieldServer',
Label:
'@/collections/Fields/textarea/components/server/Label#CustomTextareaFieldLabelServer',
},
},
},
{
name: 'textareaFieldClientComponent',
type: 'textarea',
admin: {
components: {
Field: '@/collections/Fields/textarea/components/client/Field#CustomTextareaFieldClient',
Label:
'@/collections/Fields/textarea/components/client/Label#CustomTextareaFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { ArrayFieldClientComponent } from 'payload'
import { ArrayField } from '@payloadcms/ui'
import React from 'react'
export const CustomArrayFieldClient: ArrayFieldClientComponent = (props) => {
const { field } = props
return <ArrayField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { ArrayFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomArrayFieldLabelClient: ArrayFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { ArrayFieldServerComponent } from 'payload'
// import { ArrayField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomArrayFieldServer: ArrayFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <ArrayField field={clientField} />
return 'This is a server component for the array field.'
}

View File

@@ -0,0 +1,12 @@
import type { ArrayFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomArrayFieldLabelServer: ArrayFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the array field label.'
}

View File

@@ -0,0 +1,38 @@
import type { CollectionConfig } from 'payload'
export const arrayFields: CollectionConfig['fields'] = [
{
name: 'arrayFieldServerComponent',
type: 'array',
admin: {
components: {
Field: '@/collections/Fields/array/components/server/Field#CustomArrayFieldServer',
Label: '@/collections/Fields/array/components/server/Label#CustomArrayFieldLabelServer',
},
},
fields: [
{
name: 'title',
type: 'text',
label: 'Title',
},
],
},
{
name: 'arrayFieldClientComponent',
type: 'array',
admin: {
components: {
Field: '@/collections/Fields/array/components/client/Field#CustomArrayFieldClient',
Label: '@/collections/Fields/array/components/client/Label#CustomArrayFieldLabelClient',
},
},
fields: [
{
name: 'title',
type: 'text',
label: 'Title',
},
],
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { BlocksFieldClientComponent } from 'payload'
import { BlocksField } from '@payloadcms/ui'
import React from 'react'
export const CustomBlocksFieldClient: BlocksFieldClientComponent = (props) => {
const { field } = props
return <BlocksField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { BlocksFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomBlocksFieldLabelClient: BlocksFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { BlocksFieldServerComponent } from 'payload'
// import { BlocksField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomBlocksFieldServer: BlocksFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <BlocksField field={clientField} />
return 'This is a server component for the blocks field.'
}

View File

@@ -0,0 +1,12 @@
import type { BlockFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomBlocksFieldLabelServer: BlockFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the blocks field label.'
}

View File

@@ -0,0 +1,54 @@
import type { CollectionConfig } from 'payload'
export const blocksFields: CollectionConfig['fields'] = [
{
name: 'blocksFieldServerComponent',
type: 'blocks',
admin: {
components: {
Field: '@/collections/Fields/blocks/components/server/Field#CustomBlocksFieldServer',
},
},
blocks: [
{
slug: 'text',
fields: [
{
name: 'content',
type: 'textarea',
label: 'Content',
},
],
labels: {
plural: 'Text Blocks',
singular: 'Text Block',
},
},
],
},
{
name: 'blocksFieldClientComponent',
type: 'blocks',
admin: {
components: {
Field: '@/collections/Fields/blocks/components/client/Field#CustomBlocksFieldClient',
},
},
blocks: [
{
slug: 'text',
fields: [
{
name: 'content',
type: 'textarea',
label: 'Content',
},
],
labels: {
plural: 'Text Blocks',
singular: 'Text Block',
},
},
],
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { CheckboxFieldClientComponent } from 'payload'
import { CheckboxField } from '@payloadcms/ui'
import React from 'react'
export const CustomCheckboxFieldClient: CheckboxFieldClientComponent = (props) => {
const { field } = props
return <CheckboxField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { CheckboxFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomCheckboxFieldLabelClient: CheckboxFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { CheckboxFieldServerComponent } from 'payload'
// import { CheckboxField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomCheckboxFieldServer: CheckboxFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <CheckboxField field={clientField} />
return 'This is a server component for the checkbox field.'
}

View File

@@ -0,0 +1,12 @@
import type { CheckboxFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomCheckboxFieldLabelServer: CheckboxFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the checkbox field label.'
}

View File

@@ -0,0 +1,26 @@
import type { CollectionConfig } from 'payload'
export const checkboxFields: CollectionConfig['fields'] = [
{
name: 'checkboxFieldServerComponent',
type: 'checkbox',
admin: {
components: {
Field: '@/collections/Fields/checkbox/components/server/Field#CustomCheckboxFieldServer',
Label:
'@/collections/Fields/checkbox/components/server/Label#CustomCheckboxFieldLabelServer',
},
},
},
{
name: 'checkboxFieldClientComponent',
type: 'checkbox',
admin: {
components: {
Field: '@/collections/Fields/checkbox/components/client/Field#CustomCheckboxFieldClient',
Label:
'@/collections/Fields/checkbox/components/client/Label#CustomCheckboxFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { DateFieldClientComponent } from 'payload'
import { DateTimeField } from '@payloadcms/ui'
import React from 'react'
export const CustomDateFieldClient: DateFieldClientComponent = (props) => {
const { field } = props
return <DateTimeField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { DateFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomDateFieldLabelClient: DateFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { DateFieldServerComponent } from 'payload'
// import { DateTimeField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomDateFieldServer: DateFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <DateTimeField field={clientField} />
return 'This is a server component for the date field.'
}

View File

@@ -0,0 +1,12 @@
import type { DateFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomDateFieldLabelServer: DateFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the date field label.'
}

View File

@@ -0,0 +1,24 @@
import type { CollectionConfig } from 'payload'
export const dateFields: CollectionConfig['fields'] = [
{
name: 'dateFieldServerComponent',
type: 'date',
admin: {
components: {
Field: '@/collections/Fields/date/components/server/Field#CustomDateFieldServer',
Label: '@/collections/Fields/date/components/server/Label#CustomDateFieldLabelServer',
},
},
},
{
name: 'dateFieldClientComponent',
type: 'date',
admin: {
components: {
Field: '@/collections/Fields/date/components/client/Field#CustomDateFieldClient',
Label: '@/collections/Fields/date/components/client/Label#CustomDateFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { EmailFieldClientComponent } from 'payload'
import { EmailField } from '@payloadcms/ui'
import React from 'react'
export const CustomEmailFieldClient: EmailFieldClientComponent = (props) => {
const { field } = props
return <EmailField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { EmailFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomEmailFieldLabelClient: EmailFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { EmailFieldServerComponent } from 'payload'
// import { EmailField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomEmailFieldServer: EmailFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <EmailField field={clientField} />
return 'This is a server component for the email field.'
}

View File

@@ -0,0 +1,12 @@
import type { EmailFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomEmailFieldLabelServer: EmailFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the email field label.'
}

View File

@@ -0,0 +1,24 @@
import type { CollectionConfig } from 'payload'
export const emailFields: CollectionConfig['fields'] = [
{
name: 'emailFieldServerComponent',
type: 'email',
admin: {
components: {
Field: '@/collections/Fields/email/components/server/Field#CustomEmailFieldServer',
Label: '@/collections/Fields/email/components/server/Label#CustomEmailFieldLabelServer',
},
},
},
{
name: 'emailFieldClientComponent',
type: 'email',
admin: {
components: {
Field: '@/collections/Fields/email/components/client/Field#CustomEmailFieldClient',
Label: '@/collections/Fields/email/components/client/Label#CustomEmailFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,42 @@
import type { CollectionConfig, Field } from 'payload'
import { arrayFields } from './array'
import { blocksFields } from './blocks'
import { checkboxFields } from './checkbox'
import { dateFields } from './date'
import { emailFields } from './email'
import { numberFields } from './number'
import { pointFields } from './point'
import { radioFields } from './radio'
import { relationshipFields } from './relationship'
import { selectFields } from './select'
import { textFields } from './text'
import { textareaFields } from './textarea'
export const CustomFields: CollectionConfig = {
slug: 'custom-fields',
admin: {
useAsTitle: 'title',
},
fields: [
{
name: 'title',
type: 'text',
label: 'Title',
},
...([] as Field[]).concat(
arrayFields,
blocksFields,
checkboxFields,
dateFields,
emailFields,
numberFields,
pointFields,
radioFields,
relationshipFields,
selectFields,
textFields,
textareaFields,
),
],
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { NumberFieldClientComponent } from 'payload'
import { NumberField } from '@payloadcms/ui'
import React from 'react'
export const CustomNumberFieldClient: NumberFieldClientComponent = (props) => {
const { field } = props
return <NumberField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { NumberFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomNumberFieldLabelClient: NumberFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { NumberFieldServerComponent } from 'payload'
// import { NumberField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomNumberFieldServer: NumberFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <NumberField field={clientField} />
return 'This is a server component for the number field.'
}

View File

@@ -0,0 +1,12 @@
import type { NumberFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomNumberFieldLabelServer: NumberFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the number field label.'
}

View File

@@ -0,0 +1,24 @@
import type { CollectionConfig } from 'payload'
export const numberFields: CollectionConfig['fields'] = [
{
name: 'numberFieldServerComponent',
type: 'number',
admin: {
components: {
Field: '@/collections/Fields/number/components/server/Field#CustomNumberFieldServer',
Label: '@/collections/Fields/number/components/server/Label#CustomNumberFieldLabelServer',
},
},
},
{
name: 'numberFieldClientComponent',
type: 'number',
admin: {
components: {
Field: '@/collections/Fields/number/components/client/Field#CustomNumberFieldClient',
Label: '@/collections/Fields/number/components/client/Label#CustomNumberFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { PointFieldClientComponent } from 'payload'
import { PointField } from '@payloadcms/ui'
import React from 'react'
export const CustomPointFieldClient: PointFieldClientComponent = (props) => {
const { field } = props
return <PointField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { PointFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomPointFieldLabelClient: PointFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { PointFieldServerComponent } from 'payload'
// import { PointField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomPointFieldServer: PointFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <PointField field={clientField} />
return 'This is a server component for the point field.'
}

View File

@@ -0,0 +1,12 @@
import type { PointFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomPointFieldLabelServer: PointFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the point field label.'
}

View File

@@ -0,0 +1,24 @@
import type { CollectionConfig } from 'payload'
export const pointFields: CollectionConfig['fields'] = [
{
name: 'pointFieldServerComponent',
type: 'point',
admin: {
components: {
Field: '@/collections/Fields/point/components/server/Field#CustomPointFieldServer',
Label: '@/collections/Fields/point/components/server/Label#CustomPointFieldLabelServer',
},
},
},
{
name: 'pointFieldClientComponent',
type: 'point',
admin: {
components: {
Field: '@/collections/Fields/point/components/client/Field#CustomPointFieldClient',
Label: '@/collections/Fields/point/components/client/Label#CustomPointFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { RadioFieldClientComponent } from 'payload'
import { RadioGroupField } from '@payloadcms/ui'
import React from 'react'
export const CustomRadioFieldClient: RadioFieldClientComponent = (props) => {
const { field } = props
return <RadioGroupField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { RadioFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomRadioFieldLabelClient: RadioFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { RadioFieldServerComponent } from 'payload'
// import { RadioGroupField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomRadioFieldServer: RadioFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <RadioGroupField field={clientField} />
return 'This is a server component for the radio field.'
}

View File

@@ -0,0 +1,12 @@
import type { RadioFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomRadioFieldLabelServer: RadioFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the radio field label.'
}

View File

@@ -0,0 +1,44 @@
import type { CollectionConfig } from 'payload'
export const radioFields: CollectionConfig['fields'] = [
{
name: 'radioFieldServerComponent',
type: 'radio',
admin: {
components: {
Field: '@/collections/Fields/radio/components/server/Field#CustomRadioFieldServer',
Label: '@/collections/Fields/radio/components/server/Label#CustomRadioFieldLabelServer',
},
},
options: [
{
label: 'Option 1',
value: 'option-1',
},
{
label: 'Option 2',
value: 'option-2',
},
],
},
{
name: 'radioFieldClientComponent',
type: 'radio',
admin: {
components: {
Field: '@/collections/Fields/radio/components/client/Field#CustomRadioFieldClient',
Label: '@/collections/Fields/radio/components/client/Label#CustomRadioFieldLabelClient',
},
},
options: [
{
label: 'Option 1',
value: 'option-1',
},
{
label: 'Option 2',
value: 'option-2',
},
],
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { RelationshipFieldClientComponent } from 'payload'
import { RelationshipField } from '@payloadcms/ui'
import React from 'react'
export const CustomRelationshipFieldClient: RelationshipFieldClientComponent = (props) => {
const { field } = props
return <RelationshipField field={field} />
}

View File

@@ -0,0 +1,13 @@
'use client'
import type { RelationshipFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomRelationshipFieldLabelClient: RelationshipFieldLabelClientComponent = (
props,
) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { RelationshipFieldServerComponent } from 'payload'
// import { RelationshipField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomRelationshipFieldServer: RelationshipFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <RelationshipField field={clientField} />
return 'This is a server component for the relationship field.'
}

View File

@@ -0,0 +1,14 @@
import type { RelationshipFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomRelationshipFieldLabelServer: RelationshipFieldLabelServerComponent = (
props,
) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the relationship field label.'
}

View File

@@ -0,0 +1,30 @@
import type { CollectionConfig } from 'payload'
export const relationshipFields: CollectionConfig['fields'] = [
{
name: 'relationshipFieldServerComponent',
type: 'relationship',
admin: {
components: {
Field:
'@/collections/Fields/relationship/components/server/Field#CustomRelationshipFieldServer',
Label:
'@/collections/Fields/relationship/components/server/Label#CustomRelationshipFieldLabelServer',
},
},
relationTo: 'custom-fields',
},
{
name: 'relationshipFieldClientComponent',
type: 'relationship',
admin: {
components: {
Field:
'@/collections/Fields/relationship/components/client/Field#CustomRelationshipFieldClient',
Label:
'@/collections/Fields/relationship/components/client/Label#CustomRelationshipFieldLabelClient',
},
},
relationTo: 'custom-fields',
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { SelectFieldClientComponent } from 'payload'
import { SelectField } from '@payloadcms/ui'
import React from 'react'
export const CustomSelectFieldClient: SelectFieldClientComponent = (props) => {
const { field } = props
return <SelectField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { SelectFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomSelectFieldLabelClient: SelectFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { SelectFieldServerComponent } from 'payload'
// import { SelectField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomSelectFieldServer: SelectFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <SelectField field={clientField} />
return 'This is a server component for the select field.'
}

View File

@@ -0,0 +1,12 @@
import type { SelectFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomSelectFieldLabelServer: SelectFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the select field label.'
}

View File

@@ -0,0 +1,52 @@
import type { CollectionConfig } from 'payload'
export const selectFields: CollectionConfig['fields'] = [
{
name: 'selectFieldServerComponent',
type: 'select',
admin: {
components: {
Field: '@/collections/Fields/select/components/server/Field#CustomSelectFieldServer',
Label: '@/collections/Fields/select/components/server/Label#CustomSelectFieldLabelServer',
},
},
options: [
{
label: 'Option 1',
value: 'option-1',
},
{
label: 'Option 2',
value: 'option-2',
},
{
label: 'Option 3',
value: 'option-3',
},
],
},
{
name: 'selectFieldClientComponent',
type: 'select',
admin: {
components: {
Field: '@/collections/Fields/select/components/client/Field#CustomSelectFieldClient',
Label: '@/collections/Fields/select/components/client/Label#CustomSelectFieldLabelClient',
},
},
options: [
{
label: 'Option 1',
value: 'option-1',
},
{
label: 'Option 2',
value: 'option-2',
},
{
label: 'Option 3',
value: 'option-3',
},
],
},
]

View File

@@ -0,0 +1,12 @@
import type { ServerSideEditViewProps } from 'payload'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export const CustomRootEditView: React.FC<ServerSideEditViewProps> = () => {
return (
<Gutter>
<h1>Custom Root Edit View</h1>
</Gutter>
)
}

View File

@@ -0,0 +1,24 @@
import type { CollectionConfig } from 'payload'
export const CustomRootViews: CollectionConfig = {
slug: 'custom-root-views',
admin: {
components: {
views: {
edit: {
root: {
Component: '@/collections/RootViews/components/CustomRootEditView#CustomRootEditView',
},
},
},
},
useAsTitle: 'title',
},
fields: [
{
name: 'title',
type: 'text',
label: 'Title',
},
],
}

View File

@@ -0,0 +1,12 @@
import type { ServerSideEditViewProps } from 'payload'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export const CustomDefaultEditView: React.FC<ServerSideEditViewProps> = () => {
return (
<Gutter>
<h1>Custom Default Edit View</h1>
</Gutter>
)
}

View File

@@ -0,0 +1,12 @@
import type { ServerSideEditViewProps } from 'payload'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export const CustomTabEditView: React.FC<ServerSideEditViewProps> = () => {
return (
<Gutter>
<h1>Custom Tab Edit View</h1>
</Gutter>
)
}

View File

@@ -0,0 +1,32 @@
import type { CollectionConfig } from 'payload'
export const CustomViews: CollectionConfig = {
slug: 'custom-views',
admin: {
components: {
views: {
edit: {
customView: {
Component: '@/collections/Views/components/CustomTabEditView#CustomTabEditView',
path: '/custom-tab',
tab: {
href: '/custom-tab',
label: 'Custom Tab',
},
},
default: {
Component: '@/collections/Views/components/CustomDefaultEditView#CustomDefaultEditView',
},
},
},
},
useAsTitle: 'title',
},
fields: [
{
name: 'title',
type: 'text',
label: 'Title',
},
],
}

View File

@@ -0,0 +1,6 @@
import Link from 'next/link'
import React from 'react'
export const LinkToCustomDefaultView: React.FC = () => {
return <Link href="/admin/custom-default">Go to Custom Default View</Link>
}

View File

@@ -0,0 +1,6 @@
import Link from 'next/link'
import React from 'react'
export const LinkToCustomMinimalView: React.FC = () => {
return <Link href="/admin/custom-minimal">Go to Custom Minimal View</Link>
}

View File

@@ -0,0 +1,6 @@
import Link from 'next/link'
import React from 'react'
export const LinkToCustomView: React.FC = () => {
return <Link href="/admin/custom">Go to Custom View</Link>
}

View File

@@ -0,0 +1,30 @@
import type { AdminViewProps } from 'payload'
import { DefaultTemplate } from '@payloadcms/next/templates'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export const CustomDefaultRootView: React.FC<AdminViewProps> = ({
initPageResult,
params,
searchParams,
}) => {
return (
<DefaultTemplate
i18n={initPageResult.req.i18n}
locale={initPageResult.locale}
params={params}
payload={initPageResult.req.payload}
permissions={initPageResult.permissions}
searchParams={searchParams}
user={initPageResult.req.user || undefined}
visibleEntities={initPageResult.visibleEntities}
>
<Gutter>
<h1>Custom Default Root View</h1>
<br />
<p>This view uses the Default Template.</p>
</Gutter>
</DefaultTemplate>
)
}

View File

@@ -0,0 +1,17 @@
import type { AdminViewProps } from 'payload'
import { MinimalTemplate } from '@payloadcms/next/templates'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export const CustomMinimalRootView: React.FC<AdminViewProps> = () => {
return (
<MinimalTemplate>
<Gutter>
<h1>Custom Minimal Root View</h1>
<br />
<p>This view uses the Minimal Template.</p>
</Gutter>
</MinimalTemplate>
)
}

View File

@@ -0,0 +1,13 @@
import type { AdminViewProps } from 'payload'
import React from 'react'
export const CustomRootView: React.FC<AdminViewProps> = () => {
return (
<div>
<h1>Custom Root View</h1>
<br />
<p>This is a completely standalone view.</p>
</div>
)
}

View File

@@ -0,0 +1,18 @@
import type { MigrateUpArgs } from '@payloadcms/db-mongodb'
export async function up({ payload }: MigrateUpArgs): Promise<void> {
await payload.create({
collection: 'users',
data: {
email: 'demo@payloadcms.com',
password: 'demo',
},
})
await payload.create({
collection: 'custom-fields',
data: {
title: 'Custom Fields',
},
})
}

View File

@@ -0,0 +1,196 @@
/* tslint:disable */
/* eslint-disable */
/**
* This file was automatically generated by Payload.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
export interface Config {
auth: {
users: UserAuthOperations;
};
collections: {
'custom-fields': CustomField;
'custom-views': CustomView;
'custom-root-views': CustomRootView;
users: User;
'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration;
};
db: {
defaultIDType: string;
};
globals: {};
locale: null;
user: User & {
collection: 'users';
};
}
export interface UserAuthOperations {
forgotPassword: {
email: string;
password: string;
};
login: {
email: string;
password: string;
};
registerFirstUser: {
email: string;
password: string;
};
unlock: {
email: string;
password: string;
};
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "custom-fields".
*/
export interface CustomField {
id: string;
title?: string | null;
arrayFieldServerComponent?:
| {
title?: string | null;
id?: string | null;
}[]
| null;
arrayFieldClientComponent?:
| {
title?: string | null;
id?: string | null;
}[]
| null;
blocksFieldServerComponent?:
| {
content?: string | null;
id?: string | null;
blockName?: string | null;
blockType: 'text';
}[]
| null;
blocksFieldClientComponent?:
| {
content?: string | null;
id?: string | null;
blockName?: string | null;
blockType: 'text';
}[]
| null;
checkboxFieldServerComponent?: boolean | null;
checkboxFieldClientComponent?: boolean | null;
dateFieldServerComponent?: string | null;
dateFieldClientComponent?: string | null;
emailFieldServerComponent?: string | null;
emailFieldClientComponent?: string | null;
numberFieldServerComponent?: number | null;
numberFieldClientComponent?: number | null;
/**
* @minItems 2
* @maxItems 2
*/
pointFieldServerComponent?: [number, number] | null;
/**
* @minItems 2
* @maxItems 2
*/
pointFieldClientComponent?: [number, number] | null;
radioFieldServerComponent?: ('option-1' | 'option-2') | null;
radioFieldClientComponent?: ('option-1' | 'option-2') | null;
relationshipFieldServerComponent?: (string | null) | CustomField;
relationshipFieldClientComponent?: (string | null) | CustomField;
selectFieldServerComponent?: ('option-1' | 'option-2' | 'option-3') | null;
selectFieldClientComponent?: ('option-1' | 'option-2' | 'option-3') | null;
textFieldServerComponent?: string | null;
textFieldClientComponent?: string | null;
textareaFieldServerComponent?: string | null;
textareaFieldClientComponent?: string | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "custom-views".
*/
export interface CustomView {
id: string;
title?: string | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "custom-root-views".
*/
export interface CustomRootView {
id: string;
title?: string | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: string;
updatedAt: string;
createdAt: string;
email: string;
resetPasswordToken?: string | null;
resetPasswordExpiration?: string | null;
salt?: string | null;
hash?: string | null;
loginAttempts?: number | null;
lockUntil?: string | null;
password?: string | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences".
*/
export interface PayloadPreference {
id: string;
user: {
relationTo: 'users';
value: string | User;
};
key?: string | null;
value?:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-migrations".
*/
export interface PayloadMigration {
id: string;
name?: string | null;
batch?: number | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "auth".
*/
export interface Auth {
[k: string]: unknown;
}
declare module 'payload' {
export interface GeneratedTypes extends Config {}
}

View File

@@ -0,0 +1,54 @@
import { mongooseAdapter } from '@payloadcms/db-mongodb'
import { lexicalEditor } from '@payloadcms/richtext-lexical'
import path from 'path'
import { buildConfig } from 'payload'
import { fileURLToPath } from 'url'
import { CustomFields } from './collections/Fields'
import { CustomRootViews } from './collections/RootViews'
import { CustomViews } from './collections/Views'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
// eslint-disable-next-line no-restricted-exports
export default buildConfig({
admin: {
components: {
afterNavLinks: [
'@/components/afterNavLinks/LinkToCustomView#LinkToCustomView',
'@/components/afterNavLinks/LinkToCustomMinimalView#LinkToCustomMinimalView',
'@/components/afterNavLinks/LinkToCustomDefaultView#LinkToCustomDefaultView',
],
views: {
CustomRootView: {
Component: '@/components/views/CustomRootView#CustomRootView',
path: '/custom',
},
DefaultCustomView: {
Component: '@/components/views/CustomDefaultRootView#CustomDefaultRootView',
path: '/custom-default',
},
MinimalCustomView: {
Component: '@/components/views/CustomMinimalRootView#CustomMinimalRootView',
path: '/custom-minimal',
},
},
},
importMap: {
baseDir: path.resolve(dirname),
},
},
collections: [CustomFields, CustomViews, CustomRootViews],
db: mongooseAdapter({
url: process.env.DATABASE_URI as string,
}),
editor: lexicalEditor({}),
graphQL: {
schemaOutputFile: path.resolve(dirname, 'generated-schema.graphql'),
},
secret: process.env.PAYLOAD_SECRET as string,
typescript: {
outputFile: path.resolve(dirname, 'payload-types.ts'),
},
})

View File

@@ -0,0 +1,47 @@
{
"compilerOptions": {
"baseUrl": ".",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./src/*"
],
"@payload-config": [
"src/payload.config.ts"
],
"@payload-types": [
"src/payload-types.ts"
]
},
"target": "ES2017"
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}

View File

@@ -5,13 +5,13 @@ export const recordLastLoggedInTenant: AfterLoginHook = async ({ req, user }) =>
const relatedOrg = await req.payload
.find({
collection: 'tenants',
depth: 0,
limit: 1,
where: {
'domains.domain': {
in: [req.headers.host],
},
},
depth: 0,
limit: 1,
})
?.then((res) => res.docs?.[0])
@@ -24,7 +24,10 @@ export const recordLastLoggedInTenant: AfterLoginHook = async ({ req, user }) =>
req,
})
} catch (err: unknown) {
req.payload.logger.error(`Error recording last logged in tenant for user ${user.id}: ${err}`)
req.payload.logger.error({
err,
msg: `Error recording last logged in tenant for user ${user.id}`,
})
}
return user

Some files were not shown because too many files have changed in this diff Show More