Compare commits

..

32 Commits

Author SHA1 Message Date
Elliot DeNolf
dbf2301a61 chore(release): v3.0.0-beta.104 [skip ci] 2024-09-12 09:05:20 -04:00
Dan Ribbens
c34401dc4b test: uploads return correct content type headers (#8182) 2024-09-12 11:21:10 +00:00
Patrik
6e94884d18 fix(ui): properly retrieves singular labels for array field rows (#8171)
## Description

`singular` labels were not being used for array rows - this PR updates
the array field to properly retrieve the correct label

- [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
2024-09-11 15:58:05 -04:00
Jacob Fletcher
8b307012f3 feat: passes client field config to server components (#8166)
## 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
2024-09-11 15:47:56 -04:00
Paul
9561aa3f79 fix(templates): website media staticDir to public folder (#8175) 2024-09-11 18:37:55 +00:00
Jacob Fletcher
51bc8b4416 feat: document drawer controls (#7679)
## 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
2024-09-11 14:34:03 -04:00
Paul
ec3730722b feat(drizzle): add support for in and not_in operators on json field (#8148)
Closes https://github.com/payloadcms/payload/issues/7952

Adds support for `in` and `not_in` operator against JSON field filters.

The following queries are now valid in postgres as well, previously it
only worked in mongo

```ts
await payload.find({
  collection: 'posts',
  where: {
    'data.value': {
      in: ['12', '13', '14'],
    },
  },
  context: {
    disable: true,
  },
})


await payload.find({
  collection: 'posts',
  where: {
    'data.value': {
      not_in: ['12', '13', '14'],
    },
  },
  context: {
    disable: true,
  },
})
```
2024-09-11 11:11:13 -06:00
Jacob Fletcher
465e47a219 fix!: properly names BlocksField and related types (#8174)
The `BlockField` type is not representative of the underlying "blocks"
field type, which is plural, i.e. `BlocksField`. This is a semantic
change that will better align the type with the field.

## Breaking Changes

Types related to the `blocks` field have change names. If you were using
the `BlockField` or related types in your own applications, simply
change the import name to be plural and instead of singular.

Old (singular):

```ts
import type {
  BlockField,
  BlockFieldClient,
  BlockFieldValidation,
  BlockFieldDescriptionClientComponent,
  BlockFieldDescriptionServerComponent,
  BlockFieldErrorClientComponent,
  BlocksFieldErrorServerComponent,
  BlockFieldLabelClientComponent,
  BlockFieldLabelServerComponent,
} from 'payload'
```

New (plural):

```ts
import type {
  BlocksField,
  BlocksFieldClient,
  BlocksFieldValidation,
  BlocksFieldDescriptionClientComponent,
  BlocksFieldDescriptionServerComponent,
  BlocksFieldErrorClientComponent,
  BlocksFieldErrorServerComponent,
  BlocksFieldLabelClientComponent,
  BlocksFieldLabelServerComponent,
} from 'payload'
```
2024-09-11 16:05:03 +00:00
Hampus Wallentin Olsen
043bf95a70 fix(cpa): match vercel postgres db type with package name (#8141)
## Description

Fixes the bug I reported in
https://github.com/payloadcms/payload/issues/8139 where the casing of
the defined value (camelCase) of Vercel's Postgres database adapter does
not match the casing of the package (kebab-case).
2024-09-11 09:47:09 -06:00
Germán Jabloñski
cd734b0f98 fix(ui): fix row width bug (#7940)
Closes https://github.com/payloadcms/payload/issues/7867

Problem: currently, setting an 

```ts
admin: {
   width: '30%'
}
```

does not work for fields inside a row or similar (group, array etc.)

Solution: when we render the field, we set a CSS variable
`--field-width` with the value of `admin.width`. This allows us to
calculate the correct width for a field in CSS by doing `flex: 0 1
var(--field-width);`

It also allows us to properly handle `gap` with `flex-wrap: wrap;`

Notes: added playwright tests to ensure widths are correctly rendered


![image](https://github.com/user-attachments/assets/0c0f11fc-2387-4f01-9298-a2613fceee22)
2024-09-11 12:36:54 -03:00
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
Bruno Crosier
82a684138a Merge branch 'beta' of https://github.com/payloadcms/payload into fix-row-field-width 2024-09-09 23:32:25 +01: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
Bruno Crosier
3a61d8d656 fix 2024-09-09 20:01:49 +01:00
Bruno Crosier
d04f6ab2bf fix test 2024-09-09 19:42:23 +01:00
Bruno Crosier
552239b637 fix type errors 2024-09-09 18:53:14 +01:00
Bruno Crosier
37e181a38d pr comments 2024-09-09 18:42:19 +01:00
Bruno Crosier
ef6fe9ca9a review comments 2024-09-02 23:52:04 +01:00
Bruno Crosier
053256d5ce more tests and better implementation 2024-08-31 23:58:20 +01:00
Bruno Crosier
efe17ff5e4 fix(row): set max-width for row 2024-08-29 02:23:54 +01:00
263 changed files with 11072 additions and 637 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,8 @@ 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`** | In Server Components, this is the original Field Config. In Client Components, this is the sanitized Client Field Config. [More details](#the-field-prop). |
| **`clientField`** | Server components receive the Client Field Config through this prop. [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,51 +176,50 @@ 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 Server Components, this is the original Field Config as written within your Payload Config. Within Client Components, however, this is a "Client Config", which is a sanitized, client-friendly version of the Field Config. This is because the original Field Config is [non-serializable](https://react.dev/reference/rsc/use-client#serializable-types), meaning it cannot be passed into Client Components without first being transformed.
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.
The Client Field Config is an exact copy of the original Field Config, minus all non-serializable properties, plus all evaluated functions such as field labels, [Custom Components](../components), etc.
Server Component:
```tsx
import React from 'react'
import type { TextFieldServerComponent } from 'payload'
import { TextField } from '@payloadcms/ui'
export const MyServerField: TextFieldServerComponent = ({ clientField }) => {
return <TextField field={clientField} />
}
```
<Banner type="info">
<strong>Tip:</strong>
Server Components can still access the original Field Config through the `field` prop.
</Banner>
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 } }) => {
return (
<p>
{`This field's name is ${name}`}
</p>
)
export const MyTextField: TextFieldClientComponent = ({ field }) => {
return <TextField field={field} />
}
```
@@ -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.
@@ -298,7 +276,8 @@ All Cell Components receive the following props:
| Property | Description |
| ---------------- | ----------------------------------------------------------------- |
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
| **`field`** | In Server Components, this is the original Field Config. In Client Components, this is the sanitized Client Field Config. [More details](#the-field-prop). |
| **`clientField`** | Server components receive the Client Field Config through this prop. [More details](#the-field-prop). |
| **`link`** | A boolean representing whether this cell should be wrapped in a link. |
| **`onClick`** | A function that is called when the cell is clicked. |
@@ -338,7 +317,8 @@ Custom Label Components receive all [Field Component](#the-field-component) prop
| Property | Description |
| -------------- | ---------------------------------------------------------------- |
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
| **`field`** | In Server Components, this is the original Field Config. In Client Components, this is the sanitized Client Field Config. [More details](#the-field-prop). |
| **`clientField`** | Server components receive the Client Field Config through this prop. [More details](#the-field-prop). |
<Banner type="success">
<strong>Reminder:</strong>
@@ -353,7 +333,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'
```
@@ -383,7 +363,8 @@ Custom Error Components receive all [Field Component](#the-field-component) prop
| Property | Description |
| --------------- | ------------------------------------------------------------- |
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
| **`field`** | In Server Components, this is the original Field Config. In Client Components, this is the sanitized Client Field Config. [More details](#the-field-prop). |
| **`clientField`** | Server components receive the Client Field Config through this prop. [More details](#the-field-prop). |
<Banner type="success">
<strong>Reminder:</strong>
@@ -499,7 +480,8 @@ Custom Description Components receive all [Field Component](#the-field-component
| Property | Description |
| -------------- | ---------------------------------------------------------------- |
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
| **`field`** | In Server Components, this is the original Field Config. In Client Components, this is the sanitized Client Field Config. [More details](#the-field-prop). |
| **`clientField`** | Server components receive the Client Field Config through this prop. [More details](#the-field-prop). |
<Banner type="success">
<strong>Reminder:</strong>

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

@@ -1,6 +1,6 @@
{
"name": "payload-monorepo",
"version": "3.0.0-beta.101",
"version": "3.0.0-beta.104",
"private": true,
"type": "module",
"scripts": {
@@ -87,6 +87,7 @@
"test:e2e:prod:ci": "rm -rf test/node_modules && rm -f test/pnpm-lock.yaml && pnpm run script:pack --all --no-build --dest test/packed && pnpm runts test/setupProd.ts && cd test && pnpm i --ignore-workspace && cd .. && pnpm runts ./test/runE2E.ts --prod",
"test:int": "cross-env NODE_OPTIONS=\"--no-deprecation\" NODE_NO_WARNINGS=1 DISABLE_LOGGING=true jest --forceExit --detectOpenHandles --config=test/jest.config.js --runInBand",
"test:int:postgres": "cross-env NODE_OPTIONS=\"--no-deprecation\" NODE_NO_WARNINGS=1 PAYLOAD_DATABASE=postgres DISABLE_LOGGING=true jest --forceExit --detectOpenHandles --config=test/jest.config.js --runInBand",
"test:int:sqlite": "cross-env NODE_OPTIONS=\"--no-deprecation\" NODE_NO_WARNINGS=1 PAYLOAD_DATABASE=sqlite DISABLE_LOGGING=true jest --forceExit --detectOpenHandles --config=test/jest.config.js --runInBand",
"test:unit": "cross-env NODE_OPTIONS=\"--no-deprecation\" NODE_NO_WARNINGS=1 DISABLE_LOGGING=true jest --forceExit --detectOpenHandles --config=jest.config.js --runInBand",
"translateNewKeys": "pnpm --filter payload run translateNewKeys"
},

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